diff -Nru python-cryptography-2.1.4/AUTHORS.rst python-cryptography-2.6.1/AUTHORS.rst --- python-cryptography-2.1.4/AUTHORS.rst 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/AUTHORS.rst 2019-02-27 23:27:53.000000000 +0000 @@ -37,3 +37,8 @@ * Ofek Lev (FFB6 B92B 30B1 7848 546E 9912 972F E913 DAD5 A46E) * Erik Daguerre * Aviv Palivoda +* Chris Wolfe +* Jeremy Lainé +* Denis Gladkikh +* John Pacific (2CF6 0381 B5EF 29B7 D48C 2020 7BB9 71A0 E891 44D9) +* Marti Raudsepp diff -Nru python-cryptography-2.1.4/CHANGELOG.rst python-cryptography-2.6.1/CHANGELOG.rst --- python-cryptography-2.1.4/CHANGELOG.rst 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/CHANGELOG.rst 2019-02-27 23:27:53.000000000 +0000 @@ -1,6 +1,206 @@ Changelog ========= +.. _v2-6-1: + +2.6.1 - 2019-02-27 +~~~~~~~~~~~~~~~~~~ + +* Resolved an error in our build infrastructure that broke our Python3 wheels + for macOS and Linux. + +.. _v2-6: + +2.6 - 2019-02-27 +~~~~~~~~~~~~~~~~ + +* **BACKWARDS INCOMPATIBLE:** Removed + ``cryptography.hazmat.primitives.asymmetric.utils.encode_rfc6979_signature`` + and + ``cryptography.hazmat.primitives.asymmetric.utils.decode_rfc6979_signature``, + which had been deprecated for nearly 4 years. Use + :func:`~cryptography.hazmat.primitives.asymmetric.utils.encode_dss_signature` + and + :func:`~cryptography.hazmat.primitives.asymmetric.utils.decode_dss_signature` + instead. +* **BACKWARDS INCOMPATIBLE**: Removed ``cryptography.x509.Certificate.serial``, + which had been deprecated for nearly 3 years. Use + :attr:`~cryptography.x509.Certificate.serial_number` instead. +* Updated Windows, macOS, and ``manylinux1`` wheels to be compiled with + OpenSSL 1.1.1b. +* Added support for :doc:`/hazmat/primitives/asymmetric/ed448` when using + OpenSSL 1.1.1b or newer. +* Added support for :doc:`/hazmat/primitives/asymmetric/ed25519` when using + OpenSSL 1.1.1b or newer. +* :func:`~cryptography.hazmat.primitives.serialization.load_ssh_public_key` can + now load ``ed25519`` public keys. +* Add support for easily mapping an object identifier to its elliptic curve + class via + :func:`~cryptography.hazmat.primitives.asymmetric.ec.get_curve_for_oid`. +* Add support for OpenSSL when compiled with the ``no-engine`` + (``OPENSSL_NO_ENGINE``) flag. + +.. _v2-5: + +2.5 - 2019-01-22 +~~~~~~~~~~~~~~~~ + +* **BACKWARDS INCOMPATIBLE:** :term:`U-label` strings were deprecated in + version 2.1, but this version removes the default ``idna`` dependency as + well. If you still need this deprecated path please install cryptography + with the ``idna`` extra: ``pip install cryptography[idna]``. +* **BACKWARDS INCOMPATIBLE:** The minimum supported PyPy version is now 5.4. +* Numerous classes and functions have been updated to allow :term:`bytes-like` + types for keying material and passwords, including symmetric algorithms, AEAD + ciphers, KDFs, loading asymmetric keys, and one time password classes. +* Updated Windows, macOS, and ``manylinux1`` wheels to be compiled with + OpenSSL 1.1.1a. +* Added support for :class:`~cryptography.hazmat.primitives.hashes.SHA512_224` + and :class:`~cryptography.hazmat.primitives.hashes.SHA512_256` when using + OpenSSL 1.1.1. +* Added support for :class:`~cryptography.hazmat.primitives.hashes.SHA3_224`, + :class:`~cryptography.hazmat.primitives.hashes.SHA3_256`, + :class:`~cryptography.hazmat.primitives.hashes.SHA3_384`, and + :class:`~cryptography.hazmat.primitives.hashes.SHA3_512` when using OpenSSL + 1.1.1. +* Added support for :doc:`/hazmat/primitives/asymmetric/x448` when using + OpenSSL 1.1.1. +* Added support for :class:`~cryptography.hazmat.primitives.hashes.SHAKE128` + and :class:`~cryptography.hazmat.primitives.hashes.SHAKE256` when using + OpenSSL 1.1.1. +* Added initial support for parsing PKCS12 files with + :func:`~cryptography.hazmat.primitives.serialization.pkcs12.load_key_and_certificates`. +* Added support for :class:`~cryptography.x509.IssuingDistributionPoint`. +* Added ``rfc4514_string()`` method to + :meth:`x509.Name `, + :meth:`x509.RelativeDistinguishedName + `, and + :meth:`x509.NameAttribute ` + to format the name or component an :rfc:`4514` Distinguished Name string. +* Added + :meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey.from_encoded_point`, + which immediately checks if the point is on the curve and supports compressed + points. Deprecated the previous method + :meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicNumbers.from_encoded_point`. +* Added :attr:`~cryptography.x509.ocsp.OCSPResponse.signature_hash_algorithm` + to ``OCSPResponse``. +* Updated :doc:`/hazmat/primitives/asymmetric/x25519` support to allow + additional serialization methods. Calling + :meth:`~cryptography.hazmat.primitives.asymmetric.x25519.X25519PublicKey.public_bytes` + with no arguments has been deprecated. +* Added support for encoding compressed and uncompressed points via + :meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey.public_bytes`. Deprecated the previous method + :meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicNumbers.encode_point`. + + +.. _v2-4-2: + +2.4.2 - 2018-11-21 +~~~~~~~~~~~~~~~~~~ + +* Updated Windows, macOS, and ``manylinux1`` wheels to be compiled with + OpenSSL 1.1.0j. + +.. _v2-4-1: + +2.4.1 - 2018-11-11 +~~~~~~~~~~~~~~~~~~ + +* Fixed a build breakage in our ``manylinux1`` wheels. + +.. _v2-4: + +2.4 - 2018-11-11 +~~~~~~~~~~~~~~~~ + +* **BACKWARDS INCOMPATIBLE:** Dropped support for LibreSSL 2.4.x. +* Deprecated OpenSSL 1.0.1 support. OpenSSL 1.0.1 is no longer supported by + the OpenSSL project. At this time there is no time table for dropping + support, however we strongly encourage all users to upgrade or install + ``cryptography`` from a wheel. +* Added initial :doc:`OCSP ` support. +* Added support for :class:`~cryptography.x509.PrecertPoison`. + +.. _v2-3-1: + +2.3.1 - 2018-08-14 +~~~~~~~~~~~~~~~~~~ + +* Updated Windows, macOS, and ``manylinux1`` wheels to be compiled with + OpenSSL 1.1.0i. + +.. _v2-3: + +2.3 - 2018-07-18 +~~~~~~~~~~~~~~~~ + +* **SECURITY ISSUE:** + :meth:`~cryptography.hazmat.primitives.ciphers.AEADDecryptionContext.finalize_with_tag` + allowed tag truncation by default which can allow tag forgery in some cases. + The method now enforces the ``min_tag_length`` provided to the + :class:`~cryptography.hazmat.primitives.ciphers.modes.GCM` constructor. + *CVE-2018-10903* +* Added support for Python 3.7. +* Added :meth:`~cryptography.fernet.Fernet.extract_timestamp` to get the + authenticated timestamp of a :doc:`Fernet ` token. +* Support for Python 2.7.x without ``hmac.compare_digest`` has been deprecated. + We will require Python 2.7.7 or higher (or 2.7.6 on Ubuntu) in the next + ``cryptography`` release. +* Fixed multiple issues preventing ``cryptography`` from compiling against + LibreSSL 2.7.x. +* Added + :class:`~cryptography.x509.CertificateRevocationList.get_revoked_certificate_by_serial_number` + for quick serial number searches in CRLs. +* The :class:`~cryptography.x509.RelativeDistinguishedName` class now + preserves the order of attributes. Duplicate attributes now raise an error + instead of silently discarding duplicates. +* :func:`~cryptography.hazmat.primitives.keywrap.aes_key_unwrap` and + :func:`~cryptography.hazmat.primitives.keywrap.aes_key_unwrap_with_padding` + now raise :class:`~cryptography.hazmat.primitives.keywrap.InvalidUnwrap` if + the wrapped key is an invalid length, instead of ``ValueError``. + +.. _v2-2-2: + +2.2.2 - 2018-03-27 +~~~~~~~~~~~~~~~~~~ + +* Updated Windows, macOS, and ``manylinux1`` wheels to be compiled with + OpenSSL 1.1.0h. + +.. _v2-2-1: + +2.2.1 - 2018-03-20 +~~~~~~~~~~~~~~~~~~ + +* Reverted a change to ``GeneralNames`` which prohibited having zero elements, + due to breakages. +* Fixed a bug in + :func:`~cryptography.hazmat.primitives.keywrap.aes_key_unwrap_with_padding` + that caused it to raise ``InvalidUnwrap`` when key length modulo 8 was + zero. + + +.. _v2-2: + +2.2 - 2018-03-19 +~~~~~~~~~~~~~~~~ + +* **BACKWARDS INCOMPATIBLE:** Support for Python 2.6 has been dropped. +* Resolved a bug in ``HKDF`` that incorrectly constrained output size. +* Added :class:`~cryptography.hazmat.primitives.asymmetric.ec.BrainpoolP256R1`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.BrainpoolP384R1`, and + :class:`~cryptography.hazmat.primitives.asymmetric.ec.BrainpoolP512R1` to + support inter-operating with systems like German smart meters. +* Added token rotation support to :doc:`Fernet ` with + :meth:`~cryptography.fernet.MultiFernet.rotate`. +* Fixed a memory leak in + :func:`~cryptography.hazmat.primitives.asymmetric.ec.derive_private_key`. +* Added support for AES key wrapping with padding via + :func:`~cryptography.hazmat.primitives.keywrap.aes_key_wrap_with_padding` + and + :func:`~cryptography.hazmat.primitives.keywrap.aes_key_unwrap_with_padding` + . +* Allow loading DSA keys with 224 bit ``q``. .. _v2-1-4: @@ -42,13 +242,15 @@ * **BACKWARDS INCOMPATIBLE:** ``Whirlpool``, ``RIPEMD160``, and ``UnsupportedExtension`` have been removed in accordance with our :doc:`/api-stability` policy. -* **BACKWARDS INCOMPATIBLE:** :attr:`~cryptography.x509.DNSName.value`, - :attr:`~cryptography.x509.RFC822Name.value`, and - :attr:`~cryptography.x509.UniformResourceIdentifier.value` will now return - an :term:`A-label` string when parsing a certificate containing an - internationalized domain name (IDN) or if the caller passed a :term:`U-label` - to the constructor. See below for additional deprecations related to this - change. +* **BACKWARDS INCOMPATIBLE:** + :attr:`DNSName.value `, + :attr:`RFC822Name.value `, and + :attr:`UniformResourceIdentifier.value + ` + will now return an :term:`A-label` string when parsing a certificate + containing an internationalized domain name (IDN) or if the caller passed + a :term:`U-label` to the constructor. See below for additional deprecations + related to this change. * Installing ``cryptography`` now requires ``pip`` 6 or newer. * Deprecated passing :term:`U-label` strings to the :class:`~cryptography.x509.DNSName`, diff -Nru python-cryptography-2.1.4/debian/changelog python-cryptography-2.6.1/debian/changelog --- python-cryptography-2.1.4/debian/changelog 2018-03-08 15:28:34.000000000 +0000 +++ python-cryptography-2.6.1/debian/changelog 2019-10-03 12:14:31.000000000 +0000 @@ -1,27 +1,66 @@ -python-cryptography (2.1.4-1ubuntu1.1) bionic; urgency=medium +python-cryptography (2.6.1-3.1~cloud0) bionic-train; urgency=medium - * d/control: Reverted addition of python-cffi as it is not apparently - necessary. + * New update for the Ubuntu Cloud Archive. - -- Corey Bryant Thu, 08 Mar 2018 10:28:34 -0500 + -- Openstack Ubuntu Testing Bot Thu, 03 Oct 2019 12:14:31 +0000 -python-cryptography (2.1.4-1ubuntu1) bionic; urgency=medium +python-cryptography (2.6.1-3.1) unstable; urgency=medium - * d/control: Add python-cffi to binary package dependencies (LP: #1752660). + * Non-maintainer upload. + * Backport two patches to fix the testsute with newer openssl. + * Ignore test_load_ecdsa_no_named_curve in the testsuite because it known to + break with newer openssl (Closes: #940547). - -- Corey Bryant Mon, 05 Mar 2018 14:37:41 -0500 + -- Sebastian Andrzej Siewior Tue, 24 Sep 2019 21:10:32 +0200 -python-cryptography (2.1.4-1build2) bionic; urgency=high +python-cryptography (2.6.1-3) unstable; urgency=medium - * No change rebuild against openssl1.1. + * Fix autopkgtest dependencies. - -- Dimitri John Ledkov Mon, 05 Feb 2018 16:52:17 +0000 + -- Tristan Seligmann Sat, 09 Mar 2019 13:25:47 +0200 -python-cryptography (2.1.4-1build1) bionic; urgency=medium +python-cryptography (2.6.1-2) unstable; urgency=medium - * No change rebuild for openssl 1.0.2n. + [ Ondřej Nový ] + * Convert git repository from git-dpm to gbp layout + * Use 'python3 -m sphinx' instead of sphinx-build for building docs - -- Dimitri John Ledkov Mon, 29 Jan 2018 14:16:13 +0000 + [ Tristan Seligmann ] + * Fix merge. + + -- Tristan Seligmann Fri, 08 Mar 2019 20:56:58 +0200 + +python-cryptography (2.6.1-1) unstable; urgency=medium + + * New upstream release. + + -- Tristan Seligmann Fri, 08 Mar 2019 13:33:42 +0200 + +python-cryptography (2.3-1) unstable; urgency=medium + + * New upstream release (closes: #904072). + - Fixes CVE-2018-10903. + * Bump Standards-Version to 4.1.5 (no changes). + + -- Tristan Seligmann Sat, 28 Jul 2018 05:50:55 +0200 + +python-cryptography (2.2.2-1) unstable; urgency=medium + + [ Ondřej Nový ] + * d/control: Set Vcs-* to salsa.debian.org + * d/copyright: Use https protocol in Format field + * d/control: Remove ancient X-Python-Version field + * d/control: Remove ancient X-Python3-Version field + + [ Tristan Seligmann ] + * New upstream release (closes: #901076). + - Fixed compatibility with newer Sphinx (closes: #896631). + * Populate debian/upstream/metadata. + * Bump Standards-Version to 4.1.4 (no changes). + * Bump debhelper compat level to 11. + * Tighten vectors dependency for autopkgtests (closes: #884484). + + -- Tristan Seligmann Sat, 09 Jun 2018 16:28:09 +0200 python-cryptography (2.1.4-1) unstable; urgency=medium diff -Nru python-cryptography-2.1.4/debian/compat python-cryptography-2.6.1/debian/compat --- python-cryptography-2.1.4/debian/compat 2017-12-11 11:47:46.000000000 +0000 +++ python-cryptography-2.6.1/debian/compat 2019-03-09 11:25:47.000000000 +0000 @@ -1 +1 @@ -9 +11 diff -Nru python-cryptography-2.1.4/debian/control python-cryptography-2.6.1/debian/control --- python-cryptography-2.1.4/debian/control 2018-03-08 15:28:34.000000000 +0000 +++ python-cryptography-2.6.1/debian/control 2019-03-09 11:25:47.000000000 +0000 @@ -1,19 +1,18 @@ Source: python-cryptography -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Tristan Seligmann +Maintainer: Tristan Seligmann Uploaders: Debian Python Modules Team , Section: python Priority: optional Build-Depends: - debhelper (>= 9.20141010), + debhelper (>= 11), dh-python (>= 2.20151103), dpkg-dev (>= 1.17.14), libssl-dev, python-asn1crypto (>= 0.21.0~), python-cffi (>= 1.7~), - python-cryptography-vectors (<< 2.1.5~) , - python-cryptography-vectors (>= 2.1.4~) , + python-cryptography-vectors (<< 2.6.2~) , + python-cryptography-vectors (>= 2.6.1~) , python-dev, python-enum34, python-hypothesis , @@ -28,8 +27,8 @@ python-tz , python3-asn1crypto (>= 0.21.0~), python3-cffi (>= 1.7~), - python3-cryptography-vectors (<< 2.1.5~) , - python3-cryptography-vectors (>= 2.1.4~) , + python3-cryptography-vectors (<< 2.6.2~) , + python3-cryptography-vectors (>= 2.6.1~) , python3-dev, python3-hypothesis , python3-idna (>= 2.0~), @@ -40,12 +39,10 @@ python3-six (>= 1.4.1~), python3-sphinx , python3-tz , -Standards-Version: 4.1.2 +Standards-Version: 4.1.5 Homepage: https://cryptography.io/ -Vcs-Git: https://anonscm.debian.org/git/python-modules/packages/python-cryptography.git -Vcs-Browser: https://anonscm.debian.org/cgit/python-modules/packages/python-cryptography.git -X-Python-Version: >= 2.6 -X-Python3-Version: >= 3.4 +Vcs-Git: https://salsa.debian.org/python-team/modules/python-cryptography.git +Vcs-Browser: https://salsa.debian.org/python-team/modules/python-cryptography Package: python-cryptography Architecture: any diff -Nru python-cryptography-2.1.4/debian/copyright python-cryptography-2.6.1/debian/copyright --- python-cryptography-2.1.4/debian/copyright 2017-12-11 11:47:46.000000000 +0000 +++ python-cryptography-2.6.1/debian/copyright 2019-03-09 11:25:47.000000000 +0000 @@ -1,4 +1,4 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: cryptography Upstream-Contact: cryptography-dev@python.org Source: http://cryptography.io/ diff -Nru python-cryptography-2.1.4/debian/.git-dpm python-cryptography-2.6.1/debian/.git-dpm --- python-cryptography-2.1.4/debian/.git-dpm 2017-12-11 11:47:46.000000000 +0000 +++ python-cryptography-2.6.1/debian/.git-dpm 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -# see git-dpm(1) from git-dpm package -21713e952d5f46fb6b43f253606e9dd2e99fd2b7 -21713e952d5f46fb6b43f253606e9dd2e99fd2b7 -21713e952d5f46fb6b43f253606e9dd2e99fd2b7 -21713e952d5f46fb6b43f253606e9dd2e99fd2b7 -python-cryptography_2.1.4.orig.tar.gz -0c4d8104c78e6e3e94ca8bdb1d99a365f29673e7 -441557 -debianTag="debian/%e%v" -patchedTag="patched/%e%v" -upstreamTag="upstream/%e%u" diff -Nru python-cryptography-2.1.4/debian/patches/series python-cryptography-2.6.1/debian/patches/series --- python-cryptography-2.1.4/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/debian/patches/series 2019-09-24 18:38:45.000000000 +0000 @@ -0,0 +1,3 @@ +update-our-test-to-be-more-robust-wrt-some-changes-f.patch +use-a-random-key-for-these-tests-4887.patch +tests-Skip-test_load_ecdsa_no_named_curve.patch diff -Nru python-cryptography-2.1.4/debian/patches/tests-Skip-test_load_ecdsa_no_named_curve.patch python-cryptography-2.6.1/debian/patches/tests-Skip-test_load_ecdsa_no_named_curve.patch --- python-cryptography-2.1.4/debian/patches/tests-Skip-test_load_ecdsa_no_named_curve.patch 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/debian/patches/tests-Skip-test_load_ecdsa_no_named_curve.patch 2019-09-24 18:38:23.000000000 +0000 @@ -0,0 +1,31 @@ +From: Sebastian Andrzej Siewior +Date: Tue, 24 Sep 2019 11:18:27 +0200 +Subject: [PATCH] tests: Skip test_load_ecdsa_no_named_curve + +The test_load_ecdsa_no_named_curve breaks with OpenSSL 1.1.1d which is +due to to commit 9a43a733801bd ("[ec] Match built-in curves on +EC_GROUP_new_from_ecparameters"). + +Upstream is aware of the issue and it is tracked at + https://github.com/pyca/cryptography/issues/4998 + +Signed-off-by: Sebastian Andrzej Siewior +--- + tests/x509/test_x509.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py +index 07a6019bd1394..c553636f27efe 100644 +--- a/tests/x509/test_x509.py ++++ b/tests/x509/test_x509.py +@@ -4122,6 +4122,7 @@ ParsedCertificate = collections.namedtuple( + ec.ECDSA(cert.signature_hash_algorithm) + ) + ++ @pytest.mark.skip(reason="Breaks with openssl 1.1.1d, https://github.com/pyca/cryptography/issues/4998") + def test_load_ecdsa_no_named_curve(self, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + cert = _load_cert( +-- +2.23.0 + diff -Nru python-cryptography-2.1.4/debian/patches/update-our-test-to-be-more-robust-wrt-some-changes-f.patch python-cryptography-2.6.1/debian/patches/update-our-test-to-be-more-robust-wrt-some-changes-f.patch --- python-cryptography-2.1.4/debian/patches/update-our-test-to-be-more-robust-wrt-some-changes-f.patch 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/debian/patches/update-our-test-to-be-more-robust-wrt-some-changes-f.patch 2019-09-24 06:34:23.000000000 +0000 @@ -0,0 +1,35 @@ +From e575e3d482f976c4a1f3203d63ea0f5007a49a2a Mon Sep 17 00:00:00 2001 +From: Paul Kehrer +Date: Wed, 11 Sep 2019 12:12:30 +0800 +Subject: [PATCH] update our test to be more robust wrt some changes from + upstream (#4993) + +--- + tests/hazmat/primitives/test_dh.py | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/tests/hazmat/primitives/test_dh.py b/tests/hazmat/primitives/test_dh.py +index c667cd16e1a6b..43f2ce5c0318b 100644 +--- a/tests/hazmat/primitives/test_dh.py ++++ b/tests/hazmat/primitives/test_dh.py +@@ -157,8 +157,15 @@ from ...utils import load_nist_vectors, load_vectors_from_file + dh.generate_parameters(7, 512, backend) + + def test_dh_parameters_supported(self, backend): +- assert backend.dh_parameters_supported(23, 5) +- assert not backend.dh_parameters_supported(23, 18) ++ valid_p = int( ++ b"907c7211ae61aaaba1825ff53b6cb71ac6df9f1a424c033f4a0a41ac42fad3a9" ++ b"bcfc7f938a269710ed69e330523e4039029b7900977c740990d46efed79b9bbe" ++ b"73505ae878808944ce4d9c6c52daecc0a87dc889c53499be93db8551ee685f30" ++ b"349bf1b443d4ebaee0d5e8b441a40d4e8178f8f612f657a5eb91e0a8e" ++ b"107755f", 16 ++ ) ++ assert backend.dh_parameters_supported(valid_p, 5) ++ assert not backend.dh_parameters_supported(23, 22) + + @pytest.mark.parametrize( + "vector", +-- +2.23.0 + diff -Nru python-cryptography-2.1.4/debian/patches/use-a-random-key-for-these-tests-4887.patch python-cryptography-2.6.1/debian/patches/use-a-random-key-for-these-tests-4887.patch --- python-cryptography-2.1.4/debian/patches/use-a-random-key-for-these-tests-4887.patch 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/debian/patches/use-a-random-key-for-these-tests-4887.patch 2019-09-24 06:34:30.000000000 +0000 @@ -0,0 +1,29 @@ +From 97af501780534065739a251dc6bafd74b6bf7f19 Mon Sep 17 00:00:00 2001 +From: Paul Kehrer +Date: Sat, 18 May 2019 09:04:37 -0400 +Subject: [PATCH] use a random key for these tests (#4887) + +Using an all 0 key causes failures in OpenSSL master (and Fedora has +cherry-picked the commit that causes it). The change requires that the +key/tweak for XTS mode not be the same value, so let's just use a random +key. +--- + tests/hazmat/primitives/test_aes.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/hazmat/primitives/test_aes.py b/tests/hazmat/primitives/test_aes.py +index f083f31978ee7..565cc11dd4df5 100644 +--- a/tests/hazmat/primitives/test_aes.py ++++ b/tests/hazmat/primitives/test_aes.py +@@ -490,7 +490,7 @@ from ...utils import load_nist_vectors + def test_buffer_protocol_alternate_modes(mode, backend): + data = bytearray(b"sixteen_byte_msg") + cipher = base.Cipher( +- algorithms.AES(bytearray(b"\x00" * 32)), mode, backend ++ algorithms.AES(bytearray(os.urandom(32))), mode, backend + ) + enc = cipher.encryptor() + ct = enc.update(data) + enc.finalize() +-- +2.23.0 + diff -Nru python-cryptography-2.1.4/debian/rules python-cryptography-2.6.1/debian/rules --- python-cryptography-2.1.4/debian/rules 2018-03-05 19:37:22.000000000 +0000 +++ python-cryptography-2.6.1/debian/rules 2019-03-09 11:25:47.000000000 +0000 @@ -29,7 +29,7 @@ PYTHONPATH=. \ http_proxy='127.0.0.1:9' \ https_proxy='127.0.0.1:9' \ - sphinx-build -N -b html docs/ $(CURDIR)/.pybuild/docs/html/ + python3 -m sphinx -N -b html docs/ $(CURDIR)/.pybuild/docs/html/ endif diff -Nru python-cryptography-2.1.4/debian/tests/control python-cryptography-2.6.1/debian/tests/control --- python-cryptography-2.1.4/debian/tests/control 2017-12-11 11:47:46.000000000 +0000 +++ python-cryptography-2.6.1/debian/tests/control 2019-03-09 11:25:47.000000000 +0000 @@ -1,8 +1,10 @@ Test-Command: for p in $(pyversions -s) $(py3versions -s); do $p -m pytest tests/; done Depends: python-all, + python-cffi, python-cryptography, - python-cryptography-vectors, + python-cryptography-vectors (<< 2.6.2~), + python-cryptography-vectors (>= 2.6.1~), python-hypothesis, python-iso8601, python-pretend, @@ -10,8 +12,10 @@ python-pytest, python-tz, python3-all, + python3-cffi, python3-cryptography, - python3-cryptography-vectors, + python3-cryptography-vectors (<< 2.6.2~), + python3-cryptography-vectors (>= 2.6.1~), python3-hypothesis, python3-iso8601, python3-pretend, diff -Nru python-cryptography-2.1.4/debian/upstream/metadata python-cryptography-2.6.1/debian/upstream/metadata --- python-cryptography-2.1.4/debian/upstream/metadata 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/debian/upstream/metadata 2019-03-09 11:25:47.000000000 +0000 @@ -0,0 +1,16 @@ +--- +Archive: PyPI +Bug-Database: https://github.com/pyca/cryptography/issues +Bug-Submit: https://github.com/pyca/cryptography/issues/new +Changelog: + https://raw.githubusercontent.com/pyca/cryptography/master/CHANGELOG.rst +Contact: https://mail.python.org/mailman/listinfo/cryptography-dev +Documentation: https://cryptography.io/en/latest/ +Name: Cryptography +Registry: + - Name: PyPI + Entry: cryptography_vectors +Repository: https://github.com/pyca/cryptography.git +Repository-Browse: https://github.com/pyca/cryptography +Security-Contact: + https://cryptography.io/en/latest/security/#reporting-a-security-issue diff -Nru python-cryptography-2.1.4/docs/api-stability.rst python-cryptography-2.6.1/docs/api-stability.rst --- python-cryptography-2.1.4/docs/api-stability.rst 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/docs/api-stability.rst 2019-02-27 23:27:53.000000000 +0000 @@ -34,18 +34,34 @@ policy as necessary in order to resolve a security issue or harden ``cryptography`` against a possible attack. +Versioning +---------- + +This project uses a custom versioning scheme as described below. + +Given a version ``cryptography X.Y.Z``, + +* ``X.Y`` is a decimal number that is incremented for + potentially-backwards-incompatible releases. + + * This increases like a standard decimal. + In other words, 0.9 is the ninth release, and 1.0 is the tenth (not 0.10). + The dividing decimal point can effectively be ignored. + +* ``Z`` is an integer that is incremented for backward-compatible releases. + Deprecation ------------ +~~~~~~~~~~~ From time to time we will want to change the behavior of an API or remove it entirely. In that case, here's how the process will work: * In ``cryptography X.Y`` the feature exists. -* In ``cryptography X.Y+1`` using that feature will emit a - ``PendingDeprecationWarning``. -* In ``cryptography X.Y+2`` using that feature will emit a - ``DeprecationWarning``. -* In ``cryptography X.Y+3`` the feature will be removed or changed. +* In ``cryptography X.Y + 0.1`` using that feature will emit a + ``UserWarning``. +* In ``cryptography X.Y + 0.2`` using that feature will emit a + ``UserWarning``. +* In ``cryptography X.Y + 0.3`` the feature will be removed or changed. In short, code that runs without warnings will always continue to work for a period of two releases. diff -Nru python-cryptography-2.1.4/docs/conf.py python-cryptography-2.6.1/docs/conf.py --- python-cryptography-2.1.4/docs/conf.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/conf.py 2019-02-27 23:27:53.000000000 +0000 @@ -176,9 +176,9 @@ # Retry requests in the linkcheck builder so that we're resillient against # transient network errors. -linkcheck_retries = 5 +linkcheck_retries = 10 linkcheck_ignore = [ - # Certificate is issued by a Japanese CA that isn't publicly trusted - "https://www.cryptrec.go.jp", + # Small DH key results in a TLS failure on modern OpenSSL + "https://info.isl.ntt.co.jp/crypt/eng/camellia/", ] diff -Nru python-cryptography-2.1.4/docs/cryptography-docs.py python-cryptography-2.6.1/docs/cryptography-docs.py --- python-cryptography-2.1.4/docs/cryptography-docs.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/cryptography-docs.py 2019-02-27 23:27:53.000000000 +0000 @@ -5,8 +5,7 @@ from __future__ import absolute_import, division, print_function from docutils import nodes - -from sphinx.util.compat import Directive +from docutils.parsers.rst import Directive DANGER_MESSAGE = """ diff -Nru python-cryptography-2.1.4/docs/development/c-bindings.rst python-cryptography-2.6.1/docs/development/c-bindings.rst --- python-cryptography-2.1.4/docs/development/c-bindings.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/development/c-bindings.rst 2019-02-27 23:27:53.000000000 +0000 @@ -191,7 +191,7 @@ one. In that case, it may make sense to either check for a particular version. For example, to check for OpenSSL 1.1.0 or newer:: - #if OPENSSL_VERSION_NUMBER >= 0x10100000L + #if CRYPTOGRAPHY_OPENSSL_110_OR_GREATER Sometimes, the version of a library on a particular platform will have features that you thought it wouldn't, based on its version. diff -Nru python-cryptography-2.1.4/docs/development/custom-vectors/arc4.rst python-cryptography-2.6.1/docs/development/custom-vectors/arc4.rst --- python-cryptography-2.1.4/docs/development/custom-vectors/arc4.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/development/custom-vectors/arc4.rst 2019-02-27 23:27:53.000000000 +0000 @@ -2,14 +2,14 @@ ==================== This page documents the code that was used to generate the ARC4 test -vectors for key lengths not available in RFC 6229. All the vectors +vectors for key lengths not available in :rfc:`6229`. All the vectors were generated using OpenSSL and verified with Go. Creation -------- ``cryptography`` was modified to support ARC4 key lengths not listed -in RFC 6229. Then the following Python script was run to generate the +in :rfc:`6229`. Then the following Python script was run to generate the vector files. .. literalinclude:: /development/custom-vectors/arc4/generate_arc4.py diff -Nru python-cryptography-2.1.4/docs/development/custom-vectors/cast5/verify_cast5.go python-cryptography-2.6.1/docs/development/custom-vectors/cast5/verify_cast5.go --- python-cryptography-2.1.4/docs/development/custom-vectors/cast5/verify_cast5.go 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/development/custom-vectors/cast5/verify_cast5.go 2019-02-27 23:27:53.000000000 +0000 @@ -3,7 +3,7 @@ import ( "bufio" "bytes" - "code.google.com/p/go.crypto/cast5" + "golang.org/x/crypto/cast5" "crypto/cipher" "encoding/hex" "fmt" diff -Nru python-cryptography-2.1.4/docs/development/custom-vectors/hkdf/generate_hkdf.py python-cryptography-2.6.1/docs/development/custom-vectors/hkdf/generate_hkdf.py --- python-cryptography-2.1.4/docs/development/custom-vectors/hkdf/generate_hkdf.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/docs/development/custom-vectors/hkdf/generate_hkdf.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,39 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.kdf.hkdf import HKDF + +IKM = binascii.unhexlify(b"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") +L = 1200 +OKM = HKDF( + algorithm=hashes.SHA256(), length=L, salt=None, info=None, + backend=default_backend() +).derive(IKM) + + +def _build_vectors(): + output = [] + output.append("COUNT = 0") + output.append("Hash = SHA-256") + output.append("IKM = " + binascii.hexlify(IKM).decode("ascii")) + output.append("salt = ") + output.append("info = ") + output.append("L = {}".format(L)) + output.append("OKM = " + binascii.hexlify(OKM).decode("ascii")) + return "\n".join(output) + + +def _write_file(data, filename): + with open(filename, 'w') as f: + f.write(data) + + +if __name__ == '__main__': + _write_file(_build_vectors(), 'hkdf.txt') diff -Nru python-cryptography-2.1.4/docs/development/custom-vectors/hkdf/verify_hkdf.go python-cryptography-2.6.1/docs/development/custom-vectors/hkdf/verify_hkdf.go --- python-cryptography-2.1.4/docs/development/custom-vectors/hkdf/verify_hkdf.go 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/docs/development/custom-vectors/hkdf/verify_hkdf.go 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,69 @@ +package main + +import ( + "bufio" + "bytes" + "crypto/sha256" + "encoding/hex" + "fmt" + "golang.org/x/crypto/hkdf" + "io" + "os" + "strconv" + "strings" +) + +func unhexlify(s string) []byte { + bytes, err := hex.DecodeString(s) + if err != nil { + panic(err) + } + return bytes +} + +func verifier(l uint64, ikm, okm []byte) bool { + hash := sha256.New + hkdf := hkdf.New(hash, ikm, nil, nil) + okmComputed := make([]byte, l) + io.ReadFull(hkdf, okmComputed) + return bytes.Equal(okmComputed, okm) +} + +func validateVectors(filename string) bool { + vectors, err := os.Open(filename) + if err != nil { + panic(err) + } + defer vectors.Close() + + var segments []string + var l uint64 + var ikm, okm string + + scanner := bufio.NewScanner(vectors) + for scanner.Scan() { + segments = strings.Split(scanner.Text(), " = ") + + switch { + case strings.ToUpper(segments[0]) == "L": + l, err = strconv.ParseUint(segments[1], 10, 64) + if err != nil { + panic(err) + } + case strings.ToUpper(segments[0]) == "IKM": + ikm = segments[1] + case strings.ToUpper(segments[0]) == "OKM": + okm = segments[1] + } + } + return verifier(l, unhexlify(ikm), unhexlify(okm)) +} + +func main() { + if validateVectors("vectors/cryptography_vectors/KDF/hkdf-generated.txt") { + fmt.Println("HKDF OK.") + } else { + fmt.Println("HKDF failed.") + os.Exit(1) + } +} diff -Nru python-cryptography-2.1.4/docs/development/custom-vectors/hkdf.rst python-cryptography-2.6.1/docs/development/custom-vectors/hkdf.rst --- python-cryptography-2.1.4/docs/development/custom-vectors/hkdf.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/docs/development/custom-vectors/hkdf.rst 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,28 @@ +HKDF vector creation +==================== + +This page documents the code that was used to generate a longer +HKDF test vector (1200 bytes) than is available in :rfc:`5869`. All +the vectors were generated using OpenSSL and verified with Go. + +Creation +-------- + +The following Python script was run to generate the vector files. + +.. literalinclude:: /development/custom-vectors/hkdf/generate_hkdf.py + +Download link: :download:`generate_hkdf.py +` + + +Verification +------------ + +The following Go code was used to verify the vectors. + +.. literalinclude:: /development/custom-vectors/hkdf/verify_hkdf.go + :language: go + +Download link: :download:`verify_hkdf.go +` diff -Nru python-cryptography-2.1.4/docs/development/custom-vectors/secp256k1.rst python-cryptography-2.6.1/docs/development/custom-vectors/secp256k1.rst --- python-cryptography-2.1.4/docs/development/custom-vectors/secp256k1.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/development/custom-vectors/secp256k1.rst 2019-02-27 23:27:53.000000000 +0000 @@ -29,4 +29,4 @@ Download link: :download:`verify_secp256k1.py ` -.. _`pure Python ecdsa`: https://pypi.python.org/pypi/ecdsa +.. _`pure Python ecdsa`: https://pypi.org/project/ecdsa/ diff -Nru python-cryptography-2.1.4/docs/development/getting-started.rst python-cryptography-2.6.1/docs/development/getting-started.rst --- python-cryptography-2.1.4/docs/development/getting-started.rst 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/docs/development/getting-started.rst 2019-02-27 23:27:53.000000000 +0000 @@ -19,6 +19,10 @@ $ pip install --requirement dev-requirements.txt $ pip install --editable . +Make sure that ``pip install --requirement ...`` has installed the Python +package ``vectors/`` and packages on ``tests/`` . If it didn't, you may +install them manually by using ``pip`` on each directory. + You will also need to install ``enchant`` using your system's package manager to check spelling in the documentation. @@ -61,7 +65,7 @@ .. code-block:: console - $ py.test + $ pytest ... 62746 passed in 220.43 seconds @@ -75,10 +79,9 @@ $ tox ... - ERROR: py26: InterpreterNotFound: python2.6 py27: commands succeeded ERROR: pypy: InterpreterNotFound: pypy - py33: commands succeeded + py34: commands succeeded docs: commands succeeded pep8: commands succeeded @@ -107,10 +110,10 @@ .. _`Homebrew`: https://brew.sh .. _`MacPorts`: https://www.macports.org .. _`OpenSSL`: https://www.openssl.org -.. _`pytest`: https://pypi.python.org/pypi/pytest -.. _`tox`: https://pypi.python.org/pypi/tox -.. _`virtualenv`: https://pypi.python.org/pypi/virtualenv -.. _`pip`: https://pypi.python.org/pypi/pip -.. _`sphinx`: https://pypi.python.org/pypi/Sphinx -.. _`reStructured Text`: http://sphinx-doc.org/rest.html +.. _`pytest`: https://pypi.org/project/pytest/ +.. _`tox`: https://pypi.org/project/tox/ +.. _`virtualenv`: https://pypi.org/project/virtualenv/ +.. _`pip`: https://pypi.org/project/pip/ +.. _`sphinx`: https://pypi.org/project/Sphinx/ +.. _`reStructured Text`: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html .. _`this Github issue`: https://github.com/rfk/pyenchant/issues/42 diff -Nru python-cryptography-2.1.4/docs/development/index.rst python-cryptography-2.6.1/docs/development/index.rst --- python-cryptography-2.1.4/docs/development/index.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/development/index.rst 2019-02-27 23:27:53.000000000 +0000 @@ -17,4 +17,4 @@ c-bindings .. _`GitHub`: https://github.com/pyca/cryptography -.. _`what to put in your bug report`: http://www.contribution-guide.org/#what-to-put-in-your-bug-report +.. _`what to put in your bug report`: https://www.contribution-guide.org/#what-to-put-in-your-bug-report diff -Nru python-cryptography-2.1.4/docs/development/submitting-patches.rst python-cryptography-2.6.1/docs/development/submitting-patches.rst --- python-cryptography-2.1.4/docs/development/submitting-patches.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/development/submitting-patches.rst 2019-02-27 23:27:53.000000000 +0000 @@ -155,7 +155,7 @@ .. _`Write comments as complete sentences.`: https://nedbatchelder.com/blog/201401/comments_should_be_sentences.html -.. _`syntax`: http://sphinx-doc.org/domains.html#info-field-lists +.. _`syntax`: https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#info-field-lists .. _`Studies have shown`: https://smartbear.com/SmartBear/media/pdfs/11_Best_Practices_for_Peer_Code_Review.pdf .. _`our mailing list`: https://mail.python.org/mailman/listinfo/cryptography-dev .. _`doc8`: https://github.com/openstack/doc8 diff -Nru python-cryptography-2.1.4/docs/development/test-vectors.rst python-cryptography-2.6.1/docs/development/test-vectors.rst --- python-cryptography-2.1.4/docs/development/test-vectors.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/development/test-vectors.rst 2019-02-27 23:27:53.000000000 +0000 @@ -8,12 +8,23 @@ using an official vector file as input to verify consistency between implemented backends. -Vectors are kept in the `cryptography_vectors` package rather than within our +Vectors are kept in the ``cryptography_vectors`` package rather than within our main test suite. Sources ------- +Project Wycheproof +~~~~~~~~~~~~~~~~~~ + +We run vectors from `Project Wycheproof`_ -- a collection of known edge-cases +for various cryptographic algorithms. These are not included in the repository +(or ``cryptography_vectors`` package), but rather cloned from Git in our +continuous integration environments. + +We have ensured all test vectors are used as of commit +``c313761979d74b0417230eddd0f87d0cfab2b46b``. + Asymmetric ciphers ~~~~~~~~~~~~~~~~~~ @@ -30,13 +41,16 @@ * PKCS #8 PEM serialization vectors from * GnuTLS: `enc-rsa-pkcs8.pem`_, `enc2-rsa-pkcs8.pem`_, - `unenc-rsa-pkcs8.pem`_, `pkcs12_s2k_pem.c`_. The contents of - `enc2-rsa-pkcs8.pem`_ was re-encrypted using a stronger PKCS#8 cipher. + `unenc-rsa-pkcs8.pem`_, `pkcs12_s2k_pem.c`_. The encoding error in + `unenc-rsa-pkcs8.pem`_ was fixed, and the contents of `enc-rsa-pkcs8.pem`_ + was re-encrypted to include it. The contents of `enc2-rsa-pkcs8.pem`_ + was re-encrypted using a stronger PKCS#8 cipher. * `Botan's ECC private keys`_. * `asymmetric/public/PKCS1/dsa.pub.pem`_ is a PKCS1 DSA public key from the Ruby test suite. -* X25519 test vectors from :rfc:`7748`. +* X25519 and X448 test vectors from :rfc:`7748`. * RSA OAEP with custom label from the `BoringSSL evp tests`_. +* Ed448 test vectors from :rfc:`8032`. Custom asymmetric vectors @@ -85,6 +99,39 @@ * ``asymmetric/public/PKCS1/rsa.pub.pem`` and ``asymmetric/public/PKCS1/rsa.pub.der`` are PKCS1 conversions of the public key from ``asymmetric/PKCS8/unenc-rsa-pkcs8.pem`` using PEM and DER encoding. +* ``x509/custom/ca/ca_key.pem`` - An unencrypted PCKS8 ``secp256r1`` key. It is + the private key for the certificate ``x509/custom/ca/ca.pem``. This key is + encoded in several of the PKCS12 custom vectors. +* ``asymmetric/EC/compressed_points.txt`` - Contains compressed public points + generated using OpenSSL. +* ``asymmetric/X448/x448-pkcs8-enc.pem`` and + ``asymmetric/X448/x448-pkcs8-enc.der`` contain an X448 key encrypted with + AES 256 CBC with the password ``password``. +* ``asymmetric/X448/x448-pkcs8.pem`` and ``asymmetric/X448/x448-pkcs8.der`` + contain an unencrypted X448 key. +* ``asymmetric/X448/x448-pub.pem`` and ``asymmetric/X448/x448-pub.der`` contain + an X448 public key. +* ``asymmetric/Ed25519/ed25519-pkcs8-enc.pem`` and + ``asymmetric/Ed25519/ed25519-pkcs8-enc.der`` contain an Ed25519 key encrypted + with AES 256 CBC with the password ``password``. +* ``asymmetric/Ed25519/ed25519-pkcs8.pem`` and + ``asymmetric/Ed25519/ed25519-pkcs8.der`` contain an unencrypted Ed25519 key. +* ``asymmetric/Ed25519/ed25519-pub.pem`` and + ``asymmetric/Ed25519/ed25519-pub.der`` contain an Ed25519 public key. +* ``asymmetric/X25519/x25519-pkcs8-enc.pem`` and + ``asymmetric/X25519/x25519-pkcs8-enc.der`` contain an X25519 key encrypted + with AES 256 CBC with the password ``password``. +* ``asymmetric/X25519/x25519-pkcs8.pem`` and + ``asymmetric/X25519/x25519-pkcs8.der`` contain an unencrypted X25519 key. +* ``asymmetric/X25519/x25519-pub.pem`` and ``asymmetric/X25519/x25519-pub.der`` + contain an X25519 public key. +* ``asymmetric/Ed448/ed448-pkcs8-enc.pem`` and + ``asymmetric/Ed448/ed448-pkcs8-enc.der`` contain an Ed448 key encrypted + with AES 256 CBC with the password ``password``. +* ``asymmetric/Ed448/ed448-pkcs8.pem`` and + ``asymmetric/Ed448/ed448-pkcs8.der`` contain an unencrypted Ed448 key. +* ``asymmetric/Ed448/ed448-pub.pem`` and ``asymmetric/Ed448/ed448-pub.der`` + contain an Ed448 public key. Key exchange @@ -121,7 +168,7 @@ Diffie-Hellman parameters and key respectively. The keys were generated using OpenSSL following `DHKE`_ guide. When creating the parameters we added the `-pkeyopt dh_rfc5114:2` option to use - RFC5114 2048 bit DH parameters with 224 bit subgroup. + :rfc:`5114` 2048 bit DH parameters with 224 bit subgroup. ``vectors/cryptography_vectors/asymmetric/DH/dhkey_rfc5114_2.txt`` contains all parameter in text. ``vectors/cryptography_vectors/asymmetric/DH/dhp_rfc5114_2.der``, @@ -129,6 +176,8 @@ ``vectors/cryptography_vectors/asymmetric/DH/dhpub_rfc5114_2.der`` contains are the above parameters and keys in DER format. +* ``vectors/cryptoraphy_vectors/asymmetric/ECDH/brainpool.txt`` contains + Brainpool vectors from :rfc:`7027`. X.509 ~~~~~ @@ -144,6 +193,10 @@ cryptography website. * ``rapidssl_sha256_ca_g3.pem`` - The intermediate CA that issued the ``cryptography.io.pem`` certificate. +* ``cryptography.io.precert.pem`` - A pre-certificate with the CT poison + extension for the cryptography website. +* ``cryptography-scts.io.pem`` - A leaf certificate issued by Let's Encrypt for + the cryptography website which contains signed certificate timestamps. * ``wildcard_san.pem`` - A leaf certificate issued by a public CA for ``langui.sh`` that contains wildcard entries in the SAN extension. * ``san_edipartyname.der`` - A DSA certificate from a `Mozilla bug`_ @@ -174,6 +227,10 @@ a distinguished name with an ``x500UniqueIdentifier``. * ``utf8-dnsname.pem`` - A certificate containing non-ASCII characters in the DNS name entries of the SAN extension. +* ``badasn1time.pem`` - A certificate containing an incorrectly specified + UTCTime in its validity->not_after. +* ``letsencryptx3.pem`` - A subordinate certificate used by Let's Encrypt to + issue end entity certificates. Custom X.509 Vectors ~~~~~~~~~~~~~~~~~~~~ @@ -328,6 +385,9 @@ a ``policyConstraints`` extension with a ``requireExplicitPolicy`` value. * ``freshestcrl.pem`` - A self-signed certificate containing a ``freshestCRL`` extension. +* ``ca/ca.pem`` - A self-signed certificate with ``basicConstraints`` set to + true. Its private key is ``ca/ca_key.pem``. This certificate is encoded in + several of the PKCS12 custom vectors. Custom X.509 Request Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -389,11 +449,85 @@ was used to generate it. * ``crl_delta_crl_indicator.pem`` - Contains a CRL with the ``DeltaCRLIndicator`` extension. +* ``crl_idp_fullname_only.pem`` - Contains a CRL with an + ``IssuingDistributionPoints`` extension with only a ``fullname`` for the + distribution point. +* ``crl_idp_only_ca.pem`` - Contains a CRL with an + ``IssuingDistributionPoints`` extension that is only valid for CA certificate + revocation. +* ``crl_idp_fullname_only_aa.pem`` - Contains a CRL with an + ``IssuingDistributionPoints`` extension that sets a ``fullname`` and is only + valid for attribute certificate revocation. +* ``crl_idp_fullname_only_user.pem`` - Contains a CRL with an + ``IssuingDistributionPoints`` extension that sets a ``fullname`` and is only + valid for user certificate revocation. +* ``crl_idp_fullname_indirect_crl.pem`` - Contains a CRL with an + ``IssuingDistributionPoints`` extension that sets a ``fullname`` and the + indirect CRL flag. +* ``crl_idp_reasons_only.pem`` - Contains a CRL with an + ``IssuingDistributionPoints`` extension that is only valid for revocations + with the ``keyCompromise`` reason. +* ``crl_idp_relative_user_all_reasons.pem`` - Contains a CRL with an + ``IssuingDistributionPoints`` extension that sets all revocation reasons as + allowed. +* ``crl_idp_relativename_only.pem`` - Contains a CRL with an + ``IssuingDistributionPoints`` extension with only a ``relativename`` for + the distribution point. + +X.509 OCSP Test Vectors +~~~~~~~~~~~~~~~~~~~~~~~ +* ``x509/ocsp/resp-sha256.der`` - An OCSP response for ``cryptography.io`` with + a SHA256 signature. +* ``x509/ocsp/resp-unauthorized.der`` - An OCSP response with an unauthorized + status. +* ``x509/ocsp/resp-revoked.der`` - An OCSP response for ``revoked.badssl.com`` + with a revoked status. +* ``x509/ocsp/resp-delegate-unknown-cert.der`` - An OCSP response for an + unknown cert from ``AC Camerafirma``. This response also contains a delegate + certificate. +* ``x509/ocsp/resp-responder-key-hash.der`` - An OCSP response from the + ``DigiCert`` OCSP responder that uses a key hash for the responder ID. +* ``x509/ocsp/resp-revoked-reason.der`` - An OCSP response from the + ``QuoVadis`` OCSP responder that contains a revoked certificate with a + revocation reason. +* ``x509/ocsp/resp-revoked-no-next-update.der`` - An OCSP response that + contains a revoked certificate and no ``nextUpdate`` value. +* ``x509/ocsp/resp-invalid-signature-oid.der`` - An OCSP response that was + modified to contain an MD2 signature algorithm object identifier. Custom X.509 OCSP Test Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * ``x509/ocsp/req-sha1.der`` - An OCSP request containing a single request and using SHA1 as the hash algorithm. +* ``x509/ocsp/req-multi-sha1.der`` - An OCSP request containing multiple + requests. +* ``x509/ocsp/req-invalid-hash-alg.der`` - An OCSP request containing an + invalid hash algorithm OID. +* ``x509/ocsp/req-ext-nonce.der`` - An OCSP request containing a nonce + extension. + +Custom PKCS12 Test Vectors +~~~~~~~~~~~~~~~~~~~~~~~~~~ +* ``pkcs12/cert-key-aes256cbc.p12`` - A PKCS12 file containing a cert + (``x509/custom/ca/ca.pem``) and key (``x509/custom/ca/ca_key.pem``) + both encrypted with AES 256 CBC with the password ``cryptography``. +* ``pkcs12/cert-none-key-none.p12`` - A PKCS12 file containing a cert + (``x509/custom/ca/ca.pem``) and key (``x509/custom/ca/ca_key.pem``) + with no encryption. The password (used for integrity checking only) is + ``cryptography``. +* ``pkcs12/cert-rc2-key-3des.p12`` - A PKCS12 file containing a cert + (``x509/custom/ca/ca.pem``) encrypted with RC2 and key + (``x509/custom/ca/ca_key.pem``) encrypted via 3DES with the password + ``cryptography``. +* ``pkcs12/no-password.p12`` - A PKCS12 file containing a cert + (``x509/custom/ca/ca.pem``) and key (``x509/custom/ca/ca_key.pem``) with no + encryption and no password. +* ``pkcs12/no-cert-key-aes256cbc.p12`` - A PKCS12 file containing a key + (``x509/custom/ca/ca_key.pem``) encrypted via AES 256 CBC with the + password ``cryptography`` and no certificate. +* ``pkcs12/cert-aes256cbc-no-key.p12`` - A PKCS12 file containing a cert + (``x509/custom/ca/ca.pem``) encrypted via AES 256 CBC with the + password ``cryptography`` and no private key. Hashes ~~~~~~ @@ -401,8 +535,9 @@ * MD5 from :rfc:`1321`. * RIPEMD160 from the `RIPEMD website`_. * SHA1 from `NIST CAVP`_. -* SHA2 (224, 256, 384, 512) from `NIST CAVP`_. -* Whirlpool from the `Whirlpool website`_. +* SHA2 (224, 256, 384, 512, 512/224, 512/256) from `NIST CAVP`_. +* SHA3 (224, 256, 384, 512) from `NIST CAVP`_. +* SHAKE (128, 256) from `NIST CAVP`_. * Blake2s and Blake2b from OpenSSL `test/evptests.txt`_. HMAC @@ -427,6 +562,7 @@ ~~~~~~~~~~~~ * AES key wrap (AESKW) and 3DES key wrap test vectors from `NIST CAVP`_. +* AES key wrap with padding vectors from `Botan's key wrap vectors`_. Recipes ~~~~~~~ @@ -477,8 +613,8 @@ When official vectors are unavailable ``cryptography`` may choose to build its own using existing vectors as source material. -Custom Symmetric Vectors -~~~~~~~~~~~~~~~~~~~~~~~~ +Created Vectors +~~~~~~~~~~~~~~~ .. toctree:: :maxdepth: 1 @@ -487,6 +623,8 @@ custom-vectors/cast5 custom-vectors/idea custom-vectors/seed + custom-vectors/hkdf + If official test vectors appear in the future the custom generated vectors should be discarded. @@ -503,6 +641,7 @@ .. _`NIST`: https://www.nist.gov/ .. _`IETF`: https://www.ietf.org/ +.. _`Project Wycheproof`: https://github.com/google/wycheproof .. _`NIST CAVP`: https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program .. _`Bruce Schneier's vectors`: https://www.schneier.com/code/vectors.txt .. _`Camellia page`: https://info.isl.ntt.co.jp/crypt/eng/camellia/ @@ -512,7 +651,6 @@ .. _`BoringSSL ChaCha20Poly1305 tests`: https://boringssl.googlesource.com/boringssl/+/2e2a226ac9201ac411a84b5e79ac3a7333d8e1c9/crypto/cipher_extra/test/chacha20_poly1305_tests.txt .. _`BoringSSL evp tests`: https://boringssl.googlesource.com/boringssl/+/ce3773f9fe25c3b54390bc51d72572f251c7d7e6/crypto/evp/evp_tests.txt .. _`RIPEMD website`: https://homes.esat.kuleuven.be/~bosselae/ripemd160.html -.. _`Whirlpool website`: http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html .. _`draft RFC`: https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01 .. _`Specification repository`: https://github.com/fernet/spec .. _`errata`: https://www.rfc-editor.org/errata_search.php?rfc=6238 @@ -539,3 +677,4 @@ .. _`unknown signature OID`: https://bugzilla.mozilla.org/show_bug.cgi?id=405966 .. _`botan`: https://github.com/randombit/botan/blob/57789bdfc55061002b2727d0b32587612829a37c/src/tests/data/pubkey/dh.vec .. _`DHKE`: https://sandilands.info/sgordon/diffie-hellman-secret-key-exchange-with-openssl +.. _`Botan's key wrap vectors`: https://github.com/randombit/botan/blob/737f33c09a18500e044dca3e2ae13bd2c08bafdd/src/tests/data/keywrap/nist_key_wrap.vec diff -Nru python-cryptography-2.1.4/docs/docutils.conf python-cryptography-2.6.1/docs/docutils.conf --- python-cryptography-2.1.4/docs/docutils.conf 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/docs/docutils.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -[parsers] -smart_quotes: no diff -Nru python-cryptography-2.1.4/docs/doing-a-release.rst python-cryptography-2.6.1/docs/doing-a-release.rst --- python-cryptography-2.1.4/docs/doing-a-release.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/doing-a-release.rst 2019-02-27 23:27:53.000000000 +0000 @@ -3,32 +3,33 @@ Doing a release of ``cryptography`` requires a few steps. -Verifying and upgrading OpenSSL version ---------------------------------------- +Security Releases +----------------- + +In addition to the other steps described below, for a release which fixes a +security vulnerability, you should also include the following steps: + +* Request a `CVE from MITRE`_. Once you have received the CVE, it should be + included in the :doc:`changelog`. Ideally you should request the CVE before + starting the release process so that the CVE is available at the time of the + release. +* Ensure that the :doc:`changelog` entry credits whoever reported the issue. +* The release should be announced on the `oss-security`_ mailing list, in + addition to the regular announcement lists. + +Verifying OpenSSL version +------------------------- The release process creates wheels bundling OpenSSL for Windows, macOS, and Linux. Check that the Windows and macOS Jenkins builders have the latest version of OpenSSL installed and verify that the latest version is present in the ``pyca/cryptography-manylinux1`` docker containers. If anything is out -of date: - -Upgrading Windows -~~~~~~~~~~~~~~~~~ - -Run the ``openssl-release-1.1`` Jenkins job, then copy the resulting artifacts -to the Windows builders and unzip them in the root of the file system. - -Upgrading macOS -~~~~~~~~~~~~~~~ - -Run the ``update-brew-openssl`` Jenkins job. +of date follow the instructions for upgrading OpenSSL. -Upgrading ``manylinux1`` docker containers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Upgrading OpenSSL +----------------- -Send a pull request to the ``pyca/infra`` project updating the version and -file hash in ``cryptography-manylinux1/install_openssl.sh``. Once this is -merged the updated image will be available to the wheel builder. +Use the `upgrading OpenSSL issue template`_. Bumping the version number -------------------------- @@ -91,6 +92,9 @@ * Send an email to the `mailing list`_ and `python-announce`_ announcing the release. +.. _`CVE from MITRE`: https://cveform.mitre.org/ +.. _`oss-security`: https://www.openwall.com/lists/oss-security/ +.. _`upgrading OpenSSL issue template`: https://github.com/pyca/cryptography/issues/new?template=openssl-release.md .. _`milestone`: https://github.com/pyca/cryptography/milestones .. _`mailing list`: https://mail.python.org/mailman/listinfo/cryptography-dev .. _`python-announce`: https://mail.python.org/mailman/listinfo/python-announce-list diff -Nru python-cryptography-2.1.4/docs/faq.rst python-cryptography-2.6.1/docs/faq.rst --- python-cryptography-2.1.4/docs/faq.rst 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/docs/faq.rst 2019-02-27 23:27:53.000000000 +0000 @@ -22,7 +22,8 @@ ``cryptography``'s :ref:`recipes ` layer has similar goals to NaCl. -If you prefer NaCl's design, we highly recommend `PyNaCl`_. +If you prefer NaCl's design, we highly recommend `PyNaCl`_, which is also +maintained by the PyCA team. Why use ``cryptography``? ------------------------- @@ -55,11 +56,6 @@ PyPy. You will need to install your own copy of OpenSSL -- we recommend using Homebrew. -Starting ``cryptography`` using ``mod_wsgi`` produces an ``InternalError`` during a call in ``_register_osrandom_engine`` -------------------------------------------------------------------------------------------------------------------------- - -Upgrade to the latest ``cryptography`` and this issue should be resolved. - ``cryptography`` raised an ``InternalError`` and I'm not sure what to do? ------------------------------------------------------------------------- @@ -70,11 +66,6 @@ appear to be at fault, it's possible that this is a bug in ``cryptography``. Please file an `issue`_ with instructions on how to reproduce it. -Installing ``cryptography`` fails with ``ImportError: No module named setuptools_ext`` --------------------------------------------------------------------------------------- - -Your ``cffi`` package is out of date. ``pip install -U cffi`` to update it. - error: ``-Werror=sign-conversion``: No option ``-Wsign-conversion`` during installation --------------------------------------------------------------------------------------- @@ -84,15 +75,74 @@ newer ``gcc`` and then install ``cryptography`` using ``CC=/path/to/newer/gcc pip install cryptography``. +Installing ``cryptography`` fails with ``Invalid environment marker: python_version < '3'`` +------------------------------------------------------------------------------------------- + +Your ``pip`` and/or ``setuptools`` are outdated. Please upgrade to the latest +versions with ``pip install -U pip setuptools`` (or on Windows +``python -m pip install -U pip setuptools``). + Installing cryptography with OpenSSL 0.9.8 or 1.0.0 fails --------------------------------------------------------- The OpenSSL project has dropped support for the 0.9.8 and 1.0.0 release series. Since they are no longer receiving security patches from upstream, ``cryptography`` is also dropping support for them. To fix this issue you -should upgrade to a newer version of OpenSSL (1.0.1 or later). This may require +should upgrade to a newer version of OpenSSL (1.0.2 or later). This may require you to upgrade to a newer operating system. +Why are there no wheels for Python 3.5+ on Linux or macOS? +---------------------------------------------------------- + +Our Python3 wheels, for macOS and Linux, are ``abi3`` wheels. This means they +support multiple versions of Python. The Python 3.4 ``abi3`` wheel can be used +with any version of Python greater than or equal to 3.4. Recent versions of +``pip`` will automatically install ``abi3`` wheels. + +``ImportError``: ``idna`` is not installed +------------------------------------------ + +``cryptography`` deprecated passing :term:`U-label` strings to various X.509 +constructors in version 2.1 and in version 2.5 moved the ``idna`` dependency +to a ``setuptools`` extra. If you see this exception you should upgrade your +software so that it no longer depends on this deprecated feature. If that is +not yet possible you can also install ``cryptography`` with +``pip install cryptography[idna]`` to automatically install the missing +dependency. This workaround will be available until the feature is fully +removed. + +Why can't I import my PEM file? +------------------------------- + +PEM is a format (defined by several RFCs, but originally :rfc:`1421`) for +encoding keys, certificates and others cryptographic data into a regular form. +The data is encoded as base64 and wrapped with a header and footer. + +If you are having trouble importing PEM files, make sure your file fits +the following rules: + +* has a one-line header like this: ``-----BEGIN [FILE TYPE]-----`` + (where ``[FILE TYPE]`` is ``CERTIFICATE``, ``PUBLIC KEY``, ``PRIVATE KEY``, + etc.) + +* has a one-line footer like this: ``-----END [FILE TYPE]-----`` + +* all lines, except for the final one, must consist of exactly 64 + characters. + +For example, this is a PEM file for a RSA Public Key: :: + + -----BEGIN PUBLIC KEY----- + MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7CsKFSzq20NLb2VQDXma + 9DsDXtKADv0ziI5hT1KG6Bex5seE9pUoEcUxNv4uXo2jzAUgyRweRl/DLU8SoN8+ + WWd6YWik4GZvNv7j0z28h9Q5jRySxy4dmElFtIRHGiKhqd1Z06z4AzrmKEzgxkOk + LJjY9cvwD+iXjpK2oJwNNyavvjb5YZq6V60RhpyNtKpMh2+zRLgIk9sROEPQeYfK + 22zj2CnGBMg5Gm2uPOsGDltl/I/Fdh1aO3X4i1GXwCuPf1kSAg6lPJD0batftkSG + v0X0heUaV0j1HSNlBWamT4IR9+iJfKJHekOqvHQBcaCu7Ja4kXzx6GZ3M2j/Ja3A + 2QIDAQAB + -----END PUBLIC KEY----- + + .. _`NaCl`: https://nacl.cr.yp.to/ .. _`PyNaCl`: https://pynacl.readthedocs.io .. _`WSGIApplicationGroup`: https://modwsgi.readthedocs.io/en/develop/configuration-directives/WSGIApplicationGroup.html diff -Nru python-cryptography-2.1.4/docs/fernet.rst python-cryptography-2.6.1/docs/fernet.rst --- python-cryptography-2.1.4/docs/fernet.rst 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/docs/fernet.rst 2019-02-27 23:27:53.000000000 +0000 @@ -19,9 +19,9 @@ >>> f = Fernet(key) >>> token = f.encrypt(b"my deep dark secret") >>> token - '...' + b'...' >>> f.decrypt(token) - 'my deep dark secret' + b'my deep dark secret' :param bytes key: A URL-safe base64-encoded 32-byte key. This **must** be kept secret. Anyone with this key is able to create and @@ -80,13 +80,30 @@ :raises TypeError: This exception is raised if ``token`` is not ``bytes``. + .. method:: extract_timestamp(token) + + .. versionadded:: 2.3 + + Returns the timestamp for the token. The caller can then decide if + the token is about to expire and, for example, issue a new token. + + :param bytes token: The Fernet token. This is the result of calling + :meth:`encrypt`. + :returns int: The UNIX timestamp of the token. + :raises cryptography.fernet.InvalidToken: If the ``token``'s signature + is invalid this exception + is raised. + :raises TypeError: This exception is raised if ``token`` is not + ``bytes``. + .. class:: MultiFernet(fernets) .. versionadded:: 0.7 This class implements key rotation for Fernet. It takes a ``list`` of - :class:`Fernet` instances, and implements the same API: + :class:`Fernet` instances and implements the same API with the exception + of one additional method: :meth:`MultiFernet.rotate`: .. doctest:: @@ -96,9 +113,9 @@ >>> f = MultiFernet([key1, key2]) >>> token = f.encrypt(b"Secret message!") >>> token - '...' + b'...' >>> f.decrypt(token) - 'Secret message!' + b'Secret message!' MultiFernet performs all encryption options using the *first* key in the ``list`` provided. MultiFernet attempts to decrypt tokens with each key in @@ -109,6 +126,50 @@ the front of the list to start encrypting new messages, and remove old keys as they are no longer needed. + Token rotation as offered by :meth:`MultiFernet.rotate` is a best practice + and manner of cryptographic hygiene designed to limit damage in the event of + an undetected event and to increase the difficulty of attacks. For example, + if an employee who had access to your company's fernet keys leaves, you'll + want to generate new fernet key, rotate all of the tokens currently deployed + using that new key, and then retire the old fernet key(s) to which the + employee had access. + + .. method:: rotate(msg) + + .. versionadded:: 2.2 + + Rotates a token by re-encrypting it under the :class:`MultiFernet` + instance's primary key. This preserves the timestamp that was originally + saved with the token. If a token has successfully been rotated then the + rotated token will be returned. If rotation fails this will raise an + exception. + + .. doctest:: + + >>> from cryptography.fernet import Fernet, MultiFernet + >>> key1 = Fernet(Fernet.generate_key()) + >>> key2 = Fernet(Fernet.generate_key()) + >>> f = MultiFernet([key1, key2]) + >>> token = f.encrypt(b"Secret message!") + >>> token + b'...' + >>> f.decrypt(token) + b'Secret message!' + >>> key3 = Fernet(Fernet.generate_key()) + >>> f2 = MultiFernet([key3, key1, key2]) + >>> rotated = f2.rotate(token) + >>> f2.decrypt(rotated) + b'Secret message!' + + :param bytes msg: The token to re-encrypt. + :returns bytes: A secure message that cannot be read or altered without + the key. This is URL-safe base64-encoded. This is referred to as a + "Fernet token". + :raises cryptography.fernet.InvalidToken: If a ``token`` is in any + way invalid this exception is raised. + :raises TypeError: This exception is raised if the ``msg`` is not + ``bytes``. + .. class:: InvalidToken @@ -144,9 +205,9 @@ >>> f = Fernet(key) >>> token = f.encrypt(b"Secret message!") >>> token - '...' + b'...' >>> f.decrypt(token) - 'Secret message!' + b'Secret message!' In this scheme, the salt has to be stored in a retrievable location in order to derive the same key from the password in the future. diff -Nru python-cryptography-2.1.4/docs/glossary.rst python-cryptography-2.6.1/docs/glossary.rst --- python-cryptography-2.1.4/docs/glossary.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/glossary.rst 2019-02-27 23:27:53.000000000 +0000 @@ -94,6 +94,11 @@ bit key, you can calculate the number of bytes by dividing by 8. 128 divided by 8 is 16, so a 128 bit key is a 16 byte key. + bytes-like + A bytes-like object contains binary data and supports the + `buffer protocol`_. This includes ``bytes``, ``bytearray``, and + ``memoryview`` objects. + U-label The presentational unicode form of an internationalized domain name. U-labels use unicode characters outside the ASCII range and @@ -101,3 +106,4 @@ .. _`hardware security module`: https://en.wikipedia.org/wiki/Hardware_security_module .. _`idna`: https://pypi.org/project/idna/ +.. _`buffer protocol`: https://docs.python.org/3/c-api/buffer.html diff -Nru python-cryptography-2.1.4/docs/hazmat/backends/openssl.rst python-cryptography-2.6.1/docs/hazmat/backends/openssl.rst --- python-cryptography-2.1.4/docs/hazmat/backends/openssl.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/backends/openssl.rst 2019-02-27 23:27:53.000000000 +0000 @@ -106,7 +106,7 @@ +------------------------------------------+------------------------------+ | Windows | ``CryptGenRandom()`` | +------------------------------------------+------------------------------+ -| Linux >= 3.4.17 with working | ``getrandom(GRND_NONBLOCK)`` | +| Linux >= 3.17 with working | ``getrandom(GRND_NONBLOCK)`` | | ``SYS_getrandom`` syscall | | +------------------------------------------+------------------------------+ | OpenBSD >= 5.6 | ``getentropy()`` | @@ -123,4 +123,4 @@ .. _`initializing the RNG`: https://en.wikipedia.org/wiki/OpenSSL#Predictable_private_keys_.28Debian-specific.29 .. _`Fortuna`: https://en.wikipedia.org/wiki/Fortuna_(PRNG) .. _`Yarrow`: https://en.wikipedia.org/wiki/Yarrow_algorithm -.. _`Microsoft documentation`: https://msdn.microsoft.com/en-us/library/windows/desktop/aa379942(v=vs.85).aspx +.. _`Microsoft documentation`: https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-cryptgenrandom diff -Nru python-cryptography-2.1.4/docs/hazmat/bindings/openssl.rst python-cryptography-2.6.1/docs/hazmat/bindings/openssl.rst --- python-cryptography-2.1.4/docs/hazmat/bindings/openssl.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/bindings/openssl.rst 2019-02-27 23:27:53.000000000 +0000 @@ -33,16 +33,15 @@ Threading --------- -``cryptography`` enables OpenSSLs `thread safety facilities`_ in two different -ways depending on the configuration of your system. Normally the locking -callbacks provided by your Python implementation specifically for OpenSSL will -be used. However, if you have linked ``cryptography`` to a different version of -OpenSSL than that used by your Python implementation we enable an alternative -locking callback. This version is implemented in Python and so may result in -lower performance in some situations. In particular parallelism is reduced -because it has to acquire the GIL whenever any lock operations occur within -OpenSSL. +``cryptography`` enables OpenSSLs `thread safety facilities`_ in several +different ways depending on the configuration of your system. For users on +OpenSSL 1.1.0 or newer (including anyone who uses a binary wheel) the OpenSSL +internal locking callbacks are automatically used. Otherwise, we first attempt +to use the callbacks provided by your Python implementation specifically for +OpenSSL. This will work in every case except where ``cryptography`` is linked +against a different version of OpenSSL than the one used by your Python +implementation. For this final case we have a C-based locking callback. .. _`CFFI`: https://cffi.readthedocs.io .. _`OpenSSL`: https://www.openssl.org/ -.. _`thread safety facilities`: https://www.openssl.org/docs/man1.0.2/crypto/threads.html +.. _`thread safety facilities`: https://www.openssl.org/docs/man1.0.2/man3/CRYPTO_THREADID_set_callback.html diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/aead.rst python-cryptography-2.6.1/docs/hazmat/primitives/aead.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/aead.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/aead.rst 2019-02-27 23:27:53.000000000 +0000 @@ -18,7 +18,8 @@ It is a stream cipher combined with a MAC that offers strong integrity guarantees. - :param bytes key: A 32-byte key. This **must** be kept secret. + :param key: A 32-byte key. This **must** be kept secret. + :type key: :term:`bytes-like` :raises cryptography.exceptions.UnsupportedAlgorithm: If the version of OpenSSL does not support ChaCha20Poly1305. @@ -34,7 +35,7 @@ >>> nonce = os.urandom(12) >>> ct = chacha.encrypt(nonce, data, aad) >>> chacha.decrypt(nonce, ct, aad) - 'a secret message' + b'a secret message' .. classmethod:: generate_key() @@ -53,13 +54,15 @@ ``associated_data``. The output of this can be passed directly to the ``decrypt`` method. - :param bytes nonce: A 12 byte value. **NEVER REUSE A NONCE** with a - key. + :param nonce: A 12 byte value. **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` :param bytes data: The data to encrypt. :param bytes associated_data: Additional data that should be authenticated with the key, but does not need to be encrypted. Can be ``None``. :returns bytes: The ciphertext bytes with the 16 byte tag appended. + :raises OverflowError: If ``data`` or ``associated_data`` is larger + than 2\ :sup:`32` bytes. .. method:: decrypt(nonce, data, associated_data) @@ -67,8 +70,9 @@ called encrypt with ``associated_data`` you must pass the same ``associated_data`` in decrypt or the integrity check will fail. - :param bytes nonce: A 12 byte value. **NEVER REUSE A NONCE** with a + :param nonce: A 12 byte value. **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` :param bytes data: The data to decrypt (with tag appended). :param bytes associated_data: Additional data to authenticate. Can be ``None`` if none was passed during encryption. @@ -86,7 +90,8 @@ :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES` block cipher utilizing Galois Counter Mode (GCM). - :param bytes key: A 128, 192, or 256-bit key. This **must** be kept secret. + :param key: A 128, 192, or 256-bit key. This **must** be kept secret. + :type key: :term:`bytes-like` .. doctest:: @@ -99,7 +104,7 @@ >>> nonce = os.urandom(12) >>> ct = aesgcm.encrypt(nonce, data, aad) >>> aesgcm.decrypt(nonce, ct, aad) - 'a secret message' + b'a secret message' .. classmethod:: generate_key(bit_length) @@ -121,13 +126,16 @@ authenticating the ``associated_data``. The output of this can be passed directly to the ``decrypt`` method. - :param bytes nonce: NIST `recommends a 96-bit IV length`_ for best + :param nonce: NIST `recommends a 96-bit IV length`_ for best performance but it can be up to 2\ :sup:`64` - 1 :term:`bits`. **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` :param bytes data: The data to encrypt. :param bytes associated_data: Additional data that should be authenticated with the key, but is not encrypted. Can be ``None``. :returns bytes: The ciphertext bytes with the 16 byte tag appended. + :raises OverflowError: If ``data`` or ``associated_data`` is larger + than 2\ :sup:`32` bytes. .. method:: decrypt(nonce, data, associated_data) @@ -135,9 +143,10 @@ called encrypt with ``associated_data`` you must pass the same ``associated_data`` in decrypt or the integrity check will fail. - :param bytes nonce: NIST `recommends a 96-bit IV length`_ for best + :param nonce: NIST `recommends a 96-bit IV length`_ for best performance but it can be up to 2\ :sup:`64` - 1 :term:`bits`. **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` :param bytes data: The data to decrypt (with tag appended). :param bytes associated_data: Additional data to authenticate. Can be ``None`` if none was passed during encryption. @@ -161,11 +170,12 @@ :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES` block cipher utilizing Counter with CBC-MAC (CCM) (specified in :rfc:`3610`). - :param bytes key: A 128, 192, or 256-bit key. This **must** be kept secret. + :param key: A 128, 192, or 256-bit key. This **must** be kept secret. + :type key: :term:`bytes-like` :param int tag_length: The length of the authentication tag. This defaults to 16 bytes and it is **strongly** recommended that you do not make it shorter unless absolutely necessary. Valid tag - lengths are 4, 6, 8, 12, 14, and 16. + lengths are 4, 6, 8, 10, 12, 14, and 16. :raises cryptography.exceptions.UnsupportedAlgorithm: If the version of OpenSSL does not support AES-CCM. @@ -181,7 +191,7 @@ >>> nonce = os.urandom(13) >>> ct = aesccm.encrypt(nonce, data, aad) >>> aesccm.decrypt(nonce, ct, aad) - 'a secret message' + b'a secret message' .. classmethod:: generate_key(bit_length) @@ -203,15 +213,18 @@ authenticating the ``associated_data``. The output of this can be passed directly to the ``decrypt`` method. - :param bytes nonce: A value of between 7 and 13 bytes. The maximum + :param nonce: A value of between 7 and 13 bytes. The maximum length is determined by the length of the ciphertext you are encrypting and must satisfy the condition: ``len(data) < 2 ** (8 * (15 - len(nonce)))`` **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` :param bytes data: The data to encrypt. :param bytes associated_data: Additional data that should be authenticated with the key, but is not encrypted. Can be ``None``. :returns bytes: The ciphertext bytes with the tag appended. + :raises OverflowError: If ``data`` or ``associated_data`` is larger + than 2\ :sup:`32` bytes. .. method:: decrypt(nonce, data, associated_data) @@ -219,9 +232,10 @@ called encrypt with ``associated_data`` you must pass the same ``associated_data`` in decrypt or the integrity check will fail. - :param bytes nonce: A value of between 7 and 13 bytes. This + :param nonce: A value of between 7 and 13 bytes. This is the same value used when you originally called encrypt. **NEVER REUSE A NONCE** with a key. + :type nonce: :term:`bytes-like` :param bytes data: The data to decrypt (with tag appended). :param bytes associated_data: Additional data to authenticate. Can be ``None`` if none was passed during encryption. diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/dh.rst python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/dh.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/dh.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/dh.rst 2019-02-27 23:27:53.000000000 +0000 @@ -19,12 +19,66 @@ ~~~~~~~~~~~~~~~~~~ For most applications the ``shared_key`` should be passed to a key -derivation function. +derivation function. This allows mixing of additional information into the +key, derivation of multiple keys, and destroys any structure that may be +present. + +.. warning:: + + This example does not give `forward secrecy`_ and is only provided as a + demonstration of the basic Diffie-Hellman construction. For real world + applications always use the ephemeral form described after this example. .. code-block:: pycon >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric import dh + >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF + >>> # Generate some parameters. These can be reused. + >>> parameters = dh.generate_parameters(generator=2, key_size=2048, + ... backend=default_backend()) + >>> # Generate a private key for use in the exchange. + >>> server_private_key = parameters.generate_private_key() + >>> # In a real handshake the peer is a remote client. For this + >>> # example we'll generate another local private key though. Note that in + >>> # a DH handshake both peers must agree on a common set of parameters. + >>> peer_private_key = parameters.generate_private_key() + >>> shared_key = server_private_key.exchange(peer_private_key.public_key()) + >>> # Perform key derivation. + >>> derived_key = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).derive(shared_key) + >>> # And now we can demonstrate that the handshake performed in the + >>> # opposite direction gives the same final value + >>> same_shared_key = peer_private_key.exchange( + ... server_private_key.public_key() + ... ) + >>> same_derived_key = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).derive(same_shared_key) + >>> derived_key == same_derived_key + +DHE (or EDH), the ephemeral form of this exchange, is **strongly +preferred** over simple DH and provides `forward secrecy`_ when used. You must +generate a new private key using :func:`~DHParameters.generate_private_key` for +each :meth:`~DHPrivateKey.exchange` when performing an DHE key exchange. An +example of the ephemeral form: + +.. code-block:: pycon + + >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import hashes + >>> from cryptography.hazmat.primitives.asymmetric import dh + >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF >>> # Generate some parameters. These can be reused. >>> parameters = dh.generate_parameters(generator=2, key_size=2048, ... backend=default_backend()) @@ -36,17 +90,26 @@ >>> # must agree on a common set of parameters. >>> peer_public_key = parameters.generate_private_key().public_key() >>> shared_key = private_key.exchange(peer_public_key) + >>> # Perform key derivation. + >>> derived_key = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).derive(shared_key) >>> # For the next handshake we MUST generate another private key, but >>> # we can reuse the parameters. >>> private_key_2 = parameters.generate_private_key() >>> peer_public_key_2 = parameters.generate_private_key().public_key() >>> shared_key_2 = private_key_2.exchange(peer_public_key_2) - -DHE (or EDH), the ephemeral form of this exchange, is **strongly -preferred** over simple DH and provides `forward secrecy`_ when used. You must -generate a new private key using :func:`~DHParameters.generate_private_key` for -each :meth:`~DHPrivateKey.exchange` when performing an DHE key exchange. This -is demonstrated in the previous example. + >>> derived_key_2 = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).derive(shared_key_2) To assemble a :class:`~DHParameters` and a :class:`~DHPublicKey` from primitive integers, you must first create the @@ -68,7 +131,7 @@ .. function:: generate_parameters(generator, key_size, backend) - .. versionadded:: 0.9 + .. versionadded:: 1.7 Generate a new DH parameter group for use with ``backend``. @@ -89,13 +152,11 @@ .. class:: DHParameters - .. versionadded:: 0.9 + .. versionadded:: 1.7 .. method:: generate_private_key() - .. versionadded:: 0.9 - Generate a DH private key. This method can be used to generate many new private keys from a single set of parameters. @@ -130,7 +191,7 @@ .. class:: DHParametersWithSerialization - .. versionadded:: 0.9 + .. versionadded:: 1.7 Alias for :class:`DHParameters`. @@ -140,7 +201,7 @@ .. class:: DHPrivateKey - .. versionadded:: 0.9 + .. versionadded:: 1.7 A DH private key that is not an :term:`opaque key` also implements :class:`DHPrivateKeyWithSerialization` to provide serialization methods. @@ -173,7 +234,7 @@ .. class:: DHPrivateKeyWithSerialization - .. versionadded:: 0.9 + .. versionadded:: 1.7 This interface contains additional methods relating to serialization. Any object with this interface also has all the methods from @@ -215,7 +276,7 @@ .. class:: DHPublicKey - .. versionadded:: 0.9 + .. versionadded:: 1.7 .. attribute:: key_size @@ -254,7 +315,7 @@ .. class:: DHPublicKeyWithSerialization - .. versionadded:: 0.9 + .. versionadded:: 1.7 Alias for :class:`DHPublicKey`. diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/dsa.rst python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/dsa.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/dsa.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/dsa.rst 2019-02-27 23:27:53.000000000 +0000 @@ -444,4 +444,4 @@ .. _`DSA`: https://en.wikipedia.org/wiki/Digital_Signature_Algorithm .. _`public-key`: https://en.wikipedia.org/wiki/Public-key_cryptography .. _`FIPS 186-4`: https://csrc.nist.gov/publications/detail/fips/186/4/final -.. _`at least 2048`: http://www.ecrypt.eu.org/ecrypt2/documents/D.SPA.20.pdf +.. _`at least 2048`: https://www.cosic.esat.kuleuven.be/ecrypt/ecrypt2/documents/D.SPA.20.pdf diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/ec.rst python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/ec.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/ec.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/ec.rst 2019-02-27 23:27:53.000000000 +0000 @@ -152,6 +152,13 @@ .. class:: EllipticCurvePublicNumbers(x, y, curve) + .. warning:: + The point represented by this object is not validated in any way until + :meth:`EllipticCurvePublicNumbers.public_key` is called and may not + represent a valid point on the curve. You should not attempt to perform + any computations using the values from this class until you have either + validated it yourself or called ``public_key()`` successfully. + .. versionadded:: 0.5 The collection of integers that make up an EC public key. @@ -182,10 +189,17 @@ :param backend: An instance of :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`. + :raises ValueError: Raised if the point is invalid for the curve. :returns: A new instance of :class:`EllipticCurvePublicKey`. .. method:: encode_point() + .. warning:: + + This method is deprecated as of version 2.5. Callers should migrate + to using + :meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey.public_bytes`. + .. versionadded:: 1.1 Encodes an elliptic curve point to a byte string as described in @@ -198,6 +212,11 @@ .. versionadded:: 1.1 + .. note:: + + This has been deprecated in favor of + :meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey.from_encoded_point` + Decodes a byte string as described in `SEC 1 v2.0`_ section 2.3.3 and returns an :class:`EllipticCurvePublicNumbers`. This method only supports uncompressed points. @@ -226,12 +245,68 @@ in NIST publication `800-56A`_, and later in `800-56Ar2`_. For most applications the ``shared_key`` should be passed to a key - derivation function. + derivation function. This allows mixing of additional information into the + key, derivation of multiple keys, and destroys any structure that may be + present. + + .. warning:: + + This example does not give `forward secrecy`_ and is only provided as a + demonstration of the basic Diffie-Hellman construction. For real world + applications always use the ephemeral form described after this example. .. doctest:: >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric import ec + >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF + >>> # Generate a private key for use in the exchange. + >>> server_private_key = ec.generate_private_key( + ... ec.SECP384R1(), default_backend() + ... ) + >>> # In a real handshake the peer is a remote client. For this + >>> # example we'll generate another local private key though. + >>> peer_private_key = ec.generate_private_key( + ... ec.SECP384R1(), default_backend() + ... ) + >>> shared_key = server_private_key.exchange( + ... ec.ECDH(), peer_private_key.public_key()) + >>> # Perform key derivation. + >>> derived_key = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).derive(shared_key) + >>> # And now we can demonstrate that the handshake performed in the + >>> # opposite direction gives the same final value + >>> same_shared_key = peer_private_key.exchange( + ... ec.ECDH(), server_private_key.public_key()) + >>> # Perform key derivation. + >>> same_derived_key = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).derive(same_shared_key) + >>> derived_key == same_derived_key + True + + ECDHE (or EECDH), the ephemeral form of this exchange, is **strongly + preferred** over simple ECDH and provides `forward secrecy`_ when used. + You must generate a new private key using :func:`generate_private_key` for + each :meth:`~EllipticCurvePrivateKey.exchange` when performing an ECDHE key + exchange. An example of the ephemeral form: + + .. doctest:: + + >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import hashes + >>> from cryptography.hazmat.primitives.asymmetric import ec + >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF >>> # Generate a private key for use in the exchange. >>> private_key = ec.generate_private_key( ... ec.SECP384R1(), default_backend() @@ -243,6 +318,14 @@ ... ec.SECP384R1(), default_backend() ... ).public_key() >>> shared_key = private_key.exchange(ec.ECDH(), peer_public_key) + >>> # Perform key derivation. + >>> derived_key = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).derive(shared_key) >>> # For the next handshake we MUST generate another private key. >>> private_key_2 = ec.generate_private_key( ... ec.SECP384R1(), default_backend() @@ -251,12 +334,13 @@ ... ec.SECP384R1(), default_backend() ... ).public_key() >>> shared_key_2 = private_key_2.exchange(ec.ECDH(), peer_public_key_2) - - ECDHE (or EECDH), the ephemeral form of this exchange, is **strongly - preferred** over simple ECDH and provides `forward secrecy`_ when used. - You must generate a new private key using :func:`generate_private_key` for - each :meth:`~EllipticCurvePrivateKey.exchange` when performing an ECDHE key - exchange. + >>> derived_key_2 = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).derive(shared_key_2) Elliptic Curves --------------- @@ -283,116 +367,149 @@ All named curves are instances of :class:`EllipticCurve`. -.. class:: SECT571K1 +.. class:: SECP256R1 .. versionadded:: 0.5 - SECG curve ``sect571k1``. Also called NIST K-571. + SECG curve ``secp256r1``. Also called NIST P-256. -.. class:: SECT409K1 +.. class:: SECP384R1 .. versionadded:: 0.5 - SECG curve ``sect409k1``. Also called NIST K-409. + SECG curve ``secp384r1``. Also called NIST P-384. -.. class:: SECT283K1 +.. class:: SECP521R1 .. versionadded:: 0.5 - SECG curve ``sect283k1``. Also called NIST K-283. + SECG curve ``secp521r1``. Also called NIST P-521. -.. class:: SECT233K1 +.. class:: SECP224R1 .. versionadded:: 0.5 - SECG curve ``sect233k1``. Also called NIST K-233. + SECG curve ``secp224r1``. Also called NIST P-224. -.. class:: SECT163K1 +.. class:: SECP192R1 .. versionadded:: 0.5 - SECG curve ``sect163k1``. Also called NIST K-163. + SECG curve ``secp192r1``. Also called NIST P-192. -.. class:: SECT571R1 +.. class:: SECP256K1 - .. versionadded:: 0.5 + .. versionadded:: 0.9 + + SECG curve ``secp256k1``. - SECG curve ``sect571r1``. Also called NIST B-571. +.. class:: BrainpoolP256R1 -.. class:: SECT409R1 + .. versionadded:: 2.2 + + Brainpool curve specified in :rfc:`5639`. These curves are discouraged + for new systems. + +.. class:: BrainpoolP384R1 + + .. versionadded:: 2.2 + + Brainpool curve specified in :rfc:`5639`. These curves are discouraged + for new systems. + +.. class:: BrainpoolP512R1 + + .. versionadded:: 2.2 + + Brainpool curve specified in :rfc:`5639`. These curves are discouraged + for new systems. + +.. class:: SECT571K1 .. versionadded:: 0.5 - SECG curve ``sect409r1``. Also called NIST B-409. + SECG curve ``sect571k1``. Also called NIST K-571. These binary curves are + discouraged for new systems. -.. class:: SECT283R1 +.. class:: SECT409K1 .. versionadded:: 0.5 - SECG curve ``sect283r1``. Also called NIST B-283. + SECG curve ``sect409k1``. Also called NIST K-409. These binary curves are + discouraged for new systems. -.. class:: SECT233R1 +.. class:: SECT283K1 .. versionadded:: 0.5 - SECG curve ``sect233r1``. Also called NIST B-233. + SECG curve ``sect283k1``. Also called NIST K-283. These binary curves are + discouraged for new systems. -.. class:: SECT163R2 +.. class:: SECT233K1 .. versionadded:: 0.5 - SECG curve ``sect163r2``. Also called NIST B-163. + SECG curve ``sect233k1``. Also called NIST K-233. These binary curves are + discouraged for new systems. -.. class:: SECP521R1 +.. class:: SECT163K1 .. versionadded:: 0.5 - SECG curve ``secp521r1``. Also called NIST P-521. + SECG curve ``sect163k1``. Also called NIST K-163. These binary curves are + discouraged for new systems. -.. class:: SECP384R1 +.. class:: SECT571R1 .. versionadded:: 0.5 - SECG curve ``secp384r1``. Also called NIST P-384. + SECG curve ``sect571r1``. Also called NIST B-571. These binary curves are + discouraged for new systems. -.. class:: SECP256R1 +.. class:: SECT409R1 .. versionadded:: 0.5 - SECG curve ``secp256r1``. Also called NIST P-256. + SECG curve ``sect409r1``. Also called NIST B-409. These binary curves are + discouraged for new systems. -.. class:: SECP224R1 +.. class:: SECT283R1 .. versionadded:: 0.5 - SECG curve ``secp224r1``. Also called NIST P-224. + SECG curve ``sect283r1``. Also called NIST B-283. These binary curves are + discouraged for new systems. -.. class:: SECP192R1 +.. class:: SECT233R1 .. versionadded:: 0.5 - SECG curve ``secp192r1``. Also called NIST P-192. + SECG curve ``sect233r1``. Also called NIST B-233. These binary curves are + discouraged for new systems. -.. class:: SECP256K1 +.. class:: SECT163R2 + + .. versionadded:: 0.5 + + SECG curve ``sect163r2``. Also called NIST B-163. These binary curves are + discouraged for new systems. - .. versionadded:: 0.9 - SECG curve ``secp256k1``. Key Interfaces @@ -406,7 +523,7 @@ .. attribute:: name - :type: string + :type: str The name of the curve. Usually the name used for the ASN.1 OID such as ``secp256k1``. @@ -453,8 +570,10 @@ Performs a key exchange operation using the provided algorithm with the peer's public key. - For most applications the result should be passed to a key derivation - function. + For most applications the ``shared_key`` should be passed to a key + derivation function. This allows mixing of additional information into the + key, derivation of multiple keys, and destroys any structure that may be + present. :param algorithm: The key exchange algorithm, currently only :class:`~cryptography.hazmat.primitives.asymmetric.ec.ECDH` is @@ -555,12 +674,20 @@ .. method:: public_bytes(encoding, format) - Allows serialization of the key to bytes. Encoding ( - :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM` or + Allows serialization of the key data to bytes. When encoding the public + key the encodings ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`) and format ( :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`) - are chosen to define the exact serialization. + are chosen to define the exact serialization. When encoding the point + the encoding + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.X962` + should be used with the formats ( + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.UncompressedPoint` + or + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.CompressedPoint` + ). :param encoding: A value from the :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. @@ -568,7 +695,7 @@ :param format: A value from the :class:`~cryptography.hazmat.primitives.serialization.PublicFormat` enum. - :return bytes: Serialized key. + :return bytes: Serialized data. .. method:: verify(signature, data, signature_algorithm) @@ -596,6 +723,27 @@ Size (in :term:`bits`) of a secret scalar for the curve (as generated by :func:`generate_private_key`). + .. classmethod:: from_encoded_point(curve, data) + + .. versionadded:: 2.5 + + Decodes a byte string as described in `SEC 1 v2.0`_ section 2.3.3 and + returns an :class:`EllipticCurvePublicKey`. This class method supports + compressed points. + + :param curve: An + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve` + instance. + + :param bytes data: The serialized point byte string. + + :returns: An :class:`EllipticCurvePublicKey` instance. + + :raises ValueError: Raised when an invalid point is supplied. + + :raises TypeError: Raised when curve is not an + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve`. + .. class:: EllipticCurvePublicKeyWithSerialization @@ -626,7 +774,7 @@ ... encryption_algorithm=serialization.BestAvailableEncryption(b'testpassword') ... ) >>> serialized_private.splitlines()[0] - '-----BEGIN ENCRYPTED PRIVATE KEY-----' + b'-----BEGIN ENCRYPTED PRIVATE KEY-----' You can also serialize the key without a password, by relying on :class:`~cryptography.hazmat.primitives.serialization.NoEncryption`. @@ -642,7 +790,7 @@ ... format=serialization.PublicFormat.SubjectPublicKeyInfo ... ) >>> serialized_public.splitlines()[0] - '-----BEGIN PUBLIC KEY-----' + b'-----BEGIN PUBLIC KEY-----' This is the part that you would normally share with the rest of the world. @@ -669,13 +817,138 @@ ... ) +Elliptic Curve Object Identifiers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. class:: EllipticCurveOID + + .. versionadded:: 2.4 + + .. attribute:: SECP192R1 + + Corresponds to the dotted string ``"1.2.840.10045.3.1.1"``. + + .. attribute:: SECP224R1 + + Corresponds to the dotted string ``"1.3.132.0.33"``. + + .. attribute:: SECP256K1 + + Corresponds to the dotted string ``"1.3.132.0.10"``. + + .. attribute:: SECP256R1 + + Corresponds to the dotted string ``"1.2.840.10045.3.1.7"``. + + .. attribute:: SECP384R1 + + Corresponds to the dotted string ``"1.3.132.0.34"``. + + .. attribute:: SECP521R1 + + Corresponds to the dotted string ``"1.3.132.0.35"``. + + .. attribute:: BRAINPOOLP256R1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.36.3.3.2.8.1.1.7"``. + + .. attribute:: BRAINPOOLP384R1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.36.3.3.2.8.1.1.11"``. + + .. attribute:: BRAINPOOLP512R1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.36.3.3.2.8.1.1.13"``. + + .. attribute:: SECT163K1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.1"``. + + .. attribute:: SECT163R2 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.15"``. + + .. attribute:: SECT233K1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.26"``. + + .. attribute:: SECT233R1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.27"``. + + .. attribute:: SECT283K1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.16"``. + + .. attribute:: SECT283R1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.17"``. + + .. attribute:: SECT409K1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.36"``. + + .. attribute:: SECT409R1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.37"``. + + .. attribute:: SECT571K1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.38"``. + + .. attribute:: SECT571R1 + + .. versionadded:: 2.5 + + Corresponds to the dotted string ``"1.3.132.0.39"``. + +.. function:: get_curve_for_oid(oid) + + .. versionadded:: 2.6 + + A function that takes an :class:`~cryptography.x509.ObjectIdentifier` + and returns the associated elliptic curve class. + + :param oid: An instance of + :class:`~cryptography.x509.ObjectIdentifier`. + + :returns: The matching elliptic curve class. The returned class conforms + to the :class:`EllipticCurve` interface. + + :raises LookupError: Raised if no elliptic curve is found that matches + the provided object identifier. + .. _`FIPS 186-3`: https://csrc.nist.gov/csrc/media/publications/fips/186/3/archive/2009-06-25/documents/fips_186-3.pdf .. _`FIPS 186-4`: https://csrc.nist.gov/publications/detail/fips/186/4/final .. _`800-56A`: https://csrc.nist.gov/publications/detail/sp/800-56a/revised/archive/2007-03-14 .. _`800-56Ar2`: https://csrc.nist.gov/publications/detail/sp/800-56a/rev-2/final .. _`some concern`: https://crypto.stackexchange.com/questions/10263/should-we-trust-the-nist-recommended-ecc-parameters -.. _`less than 224 bits`: http://www.ecrypt.eu.org/ecrypt2/documents/D.SPA.20.pdf -.. _`elliptic curve diffie-hellman is faster than diffie-hellman`: http://digitalcommons.unl.edu/cgi/viewcontent.cgi?article=1100&context=cseconfwork +.. _`less than 224 bits`: https://www.cosic.esat.kuleuven.be/ecrypt/ecrypt2/documents/D.SPA.20.pdf +.. _`elliptic curve diffie-hellman is faster than diffie-hellman`: https://digitalcommons.unl.edu/cgi/viewcontent.cgi?article=1100&context=cseconfwork .. _`minimize the number of security concerns for elliptic-curve cryptography`: https://cr.yp.to/ecdh/curve25519-20060209.pdf .. _`SafeCurves`: https://safecurves.cr.yp.to/ .. _`ECDSA`: https://en.wikipedia.org/wiki/ECDSA diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/ed25519.rst python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/ed25519.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/ed25519.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/ed25519.rst 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,159 @@ +.. hazmat:: + +Ed25519 signing +=============== + +.. currentmodule:: cryptography.hazmat.primitives.asymmetric.ed25519 + + +Ed25519 is an elliptic curve signing algorithm using `EdDSA`_ and +`Curve25519`_. If you do not have legacy interoperability concerns then you +should strongly consider using this signature algorithm. + + +Signing & Verification +~~~~~~~~~~~~~~~~~~~~~~ + +.. doctest:: + + >>> from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey + >>> private_key = Ed25519PrivateKey.generate() + >>> signature = private_key.sign(b"my authenticated message") + >>> public_key = private_key.public_key() + >>> # Raises InvalidSignature if verification fails + >>> public_key.verify(signature, b"my authenticated message") + +Key interfaces +~~~~~~~~~~~~~~ + +.. class:: Ed25519PrivateKey + + .. versionadded:: 2.6 + + .. classmethod:: generate() + + Generate an Ed25519 private key. + + :returns: :class:`Ed25519PrivateKey` + + .. classmethod:: from_private_bytes(data) + + :param data: 32 byte private key. + :type data: :term:`bytes-like` + + :returns: :class:`Ed25519PrivateKey` + + .. doctest:: + + >>> from cryptography.hazmat.primitives import serialization + >>> from cryptography.hazmat.primitives.asymmetric import ed25519 + >>> private_key = ed25519.Ed25519PrivateKey.generate() + >>> private_bytes = private_key.private_bytes( + ... encoding=serialization.Encoding.Raw, + ... format=serialization.PrivateFormat.Raw, + ... encryption_algorithm=serialization.NoEncryption() + ... ) + >>> loaded_private_key = ed25519.Ed25519PrivateKey.from_private_bytes(private_bytes) + + + .. method:: public_key() + + :returns: :class:`Ed25519PublicKey` + + .. method:: sign(data) + + :param bytes data: The data to sign. + + :returns bytes: The 64 byte signature. + + .. method:: private_bytes(encoding, format, encryption_algorithm) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8` + or + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + ) are chosen to define the exact serialization. + + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.PrivateFormat` + enum. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`. + + :param encryption_algorithm: An instance of an object conforming to the + :class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption` + interface. + + :return bytes: Serialized key. + +.. class:: Ed25519PublicKey + + .. versionadded:: 2.6 + + .. classmethod:: from_public_bytes(data) + + :param bytes data: 32 byte public key. + + :returns: :class:`Ed25519PublicKey` + + .. doctest:: + + >>> from cryptography.hazmat.primitives import serialization + >>> from cryptography.hazmat.primitives.asymmetric import ed25519 + >>> private_key = ed25519.Ed25519PrivateKey.generate() + >>> public_key = private_key.public_key() + >>> public_bytes = public_key.public_bytes( + ... encoding=serialization.Encoding.Raw, + ... format=serialization.PublicFormat.Raw + ... ) + >>> loaded_public_key = ed25519.Ed25519PublicKey.from_public_bytes(public_bytes) + + .. method:: public_bytes(encoding, format) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo` + or + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + ) are chosen to define the exact serialization. + + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.PublicFormat` + enum. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`. + + :returns bytes: The public key bytes. + + .. method:: verify(signature, data) + + :param bytes signature: The signature to verify. + + :param bytes data: The data to verify. + + :raises cryptography.exceptions.InvalidSignature: Raised when the + signature cannot be verified. + + + +.. _`EdDSA`: https://en.wikipedia.org/wiki/EdDSA +.. _`Curve25519`: https://en.wikipedia.org/wiki/Curve25519 diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/ed448.rst python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/ed448.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/ed448.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/ed448.rst 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,131 @@ +.. hazmat:: + +Ed448 signing +============= + +.. currentmodule:: cryptography.hazmat.primitives.asymmetric.ed448 + + +Ed448 is an elliptic curve signing algorithm using `EdDSA`_. + + +Signing & Verification +~~~~~~~~~~~~~~~~~~~~~~ + +.. doctest:: + + >>> from cryptography.hazmat.primitives.asymmetric.ed448 import Ed448PrivateKey + >>> private_key = Ed448PrivateKey.generate() + >>> signature = private_key.sign(b"my authenticated message") + >>> public_key = private_key.public_key() + >>> # Raises InvalidSignature if verification fails + >>> public_key.verify(signature, b"my authenticated message") + +Key interfaces +~~~~~~~~~~~~~~ + +.. class:: Ed448PrivateKey + + .. versionadded:: 2.6 + + .. classmethod:: generate() + + Generate an Ed448 private key. + + :returns: :class:`Ed448PrivateKey` + + .. classmethod:: from_private_bytes(data) + + :param data: 57 byte private key. + :type data: :term:`bytes-like` + + :returns: :class:`Ed448PrivateKey` + + .. method:: public_key() + + :returns: :class:`Ed448PublicKey` + + .. method:: sign(data) + + :param bytes data: The data to sign. + + :returns bytes: The 64 byte signature. + + .. method:: private_bytes(encoding, format, encryption_algorithm) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8` + or + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + ) are chosen to define the exact serialization. + + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.PrivateFormat` + enum. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`. + + :param encryption_algorithm: An instance of an object conforming to the + :class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption` + interface. + + :return bytes: Serialized key. + +.. class:: Ed448PublicKey + + .. versionadded:: 2.6 + + .. classmethod:: from_public_bytes(data) + + :param bytes data: 57 byte public key. + + :returns: :class:`Ed448PublicKey` + + .. method:: public_bytes(encoding, format) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo` + or + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + ) are chosen to define the exact serialization. + + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.PublicFormat` + enum. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`. + + :returns bytes: The public key bytes. + + .. method:: verify(signature, data) + + :param bytes signature: The signature to verify. + + :param bytes data: The data to verify. + + :raises cryptography.exceptions.InvalidSignature: Raised when the + signature cannot be verified. + + + +.. _`EdDSA`: https://en.wikipedia.org/wiki/EdDSA diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/index.rst python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/index.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/index.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/index.rst 2019-02-27 23:27:53.000000000 +0000 @@ -23,13 +23,16 @@ .. toctree:: :maxdepth: 1 - dsa + ed25519 + x25519 + ed448 + x448 ec rsa dh + dsa serialization utils - x25519 .. _`proof of identity`: https://en.wikipedia.org/wiki/Public-key_infrastructure diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/rsa.rst python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/rsa.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/rsa.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/rsa.rst 2019-02-27 23:27:53.000000000 +0000 @@ -64,6 +64,7 @@ .. code-block:: pycon + >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import serialization >>> with open("path/to/key.pem", "rb") as key_file: @@ -99,7 +100,7 @@ ... encryption_algorithm=serialization.BestAvailableEncryption(b'mypassword') ... ) >>> pem.splitlines()[0] - '-----BEGIN ENCRYPTED PRIVATE KEY-----' + b'-----BEGIN ENCRYPTED PRIVATE KEY-----' It is also possible to serialize without encryption using :class:`~cryptography.hazmat.primitives.serialization.NoEncryption`. @@ -112,7 +113,7 @@ ... encryption_algorithm=serialization.NoEncryption() ... ) >>> pem.splitlines()[0] - '-----BEGIN RSA PRIVATE KEY-----' + b'-----BEGIN RSA PRIVATE KEY-----' For public keys you can use :meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey.public_bytes` @@ -127,7 +128,7 @@ ... format=serialization.PublicFormat.SubjectPublicKeyInfo ... ) >>> pem.splitlines()[0] - '-----BEGIN PUBLIC KEY-----' + b'-----BEGIN PUBLIC KEY-----' Signing ~~~~~~~ @@ -246,8 +247,8 @@ >>> ciphertext = public_key.encrypt( ... message, ... padding.OAEP( - ... mgf=padding.MGF1(algorithm=hashes.SHA1()), - ... algorithm=hashes.SHA1(), + ... mgf=padding.MGF1(algorithm=hashes.SHA256()), + ... algorithm=hashes.SHA256(), ... label=None ... ) ... ) @@ -269,8 +270,8 @@ >>> plaintext = private_key.decrypt( ... ciphertext, ... padding.OAEP( - ... mgf=padding.MGF1(algorithm=hashes.SHA1()), - ... algorithm=hashes.SHA1(), + ... mgf=padding.MGF1(algorithm=hashes.SHA256()), + ... algorithm=hashes.SHA256(), ... label=None ... ) ... ) @@ -718,10 +719,10 @@ .. _`RSA`: https://en.wikipedia.org/wiki/RSA_(cryptosystem) .. _`public-key`: https://en.wikipedia.org/wiki/Public-key_cryptography .. _`specific mathematical properties`: https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Key_generation -.. _`use 65537`: http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html -.. _`at least 2048`: http://www.ecrypt.eu.org/ecrypt2/documents/D.SPA.20.pdf +.. _`use 65537`: https://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html +.. _`at least 2048`: https://www.cosic.esat.kuleuven.be/ecrypt/ecrypt2/documents/D.SPA.20.pdf .. _`OpenPGP`: https://en.wikipedia.org/wiki/Pretty_Good_Privacy .. _`Chinese Remainder Theorem`: https://en.wikipedia.org/wiki/RSA_%28cryptosystem%29#Using_the_Chinese_remainder_algorithm .. _`security proof`: https://eprint.iacr.org/2001/062.pdf -.. _`recommended padding algorithm`: http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html +.. _`recommended padding algorithm`: https://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html .. _`proven secure`: https://cseweb.ucsd.edu/~mihir/papers/oae.pdf diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/serialization.rst python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/serialization.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/serialization.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/serialization.rst 2019-02-27 23:27:53.000000000 +0000 @@ -133,10 +133,12 @@ Deserialize a private key from PEM encoded data to one of the supported asymmetric private key types. - :param bytes data: The PEM encoded key data. + :param data: The PEM encoded key data. + :type data: :term:`bytes-like` - :param bytes password: The password to use to decrypt the data. Should + :param password: The password to use to decrypt the data. Should be ``None`` if the private key is not encrypted. + :type data: :term:`bytes-like` :param backend: An instance of :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend`. @@ -241,10 +243,12 @@ Deserialize a private key from DER encoded data to one of the supported asymmetric private key types. - :param bytes data: The DER encoded key data. + :param data: The DER encoded key data. + :type data: :term:`bytes-like` - :param bytes password: The password to use to decrypt the data. Should + :param password: The password to use to decrypt the data. Should be ``None`` if the private key is not encrypted. + :type password: :term:`bytes-like` :param backend: An instance of :class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend`. @@ -372,10 +376,6 @@ Deserialize a public key from OpenSSH (:rfc:`4253`) encoded data to an instance of the public key type for the specified backend. - .. note:: - - Currently Ed25519 keys are not supported. - :param bytes data: The OpenSSH encoded key data. :param backend: A backend which implements @@ -387,8 +387,9 @@ :returns: One of :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, - or :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` + , or + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey`, depending on the contents of ``data``. :raises ValueError: If the OpenSSH data could not be properly decoded or @@ -397,9 +398,48 @@ :raises cryptography.exceptions.UnsupportedAlgorithm: If the serialized key is of a type that is not supported. +PKCS12 +~~~~~~ + +.. currentmodule:: cryptography.hazmat.primitives.serialization.pkcs12 + +PKCS12 is a binary format described in :rfc:`7292`. It can contain +certificates, keys, and more. PKCS12 files commonly have a ``pfx`` or ``p12`` +file suffix. + +.. note:: + + ``cryptography`` only supports a single private key and associated + certificates when parsing PKCS12 files at this time. + +.. function:: load_key_and_certificates(data, password, backend) + + .. versionadded:: 2.5 + + Deserialize a PKCS12 blob. + + :param data: The binary data. + :type data: :term:`bytes-like` + + :param password: The password to use to decrypt the data. ``None`` + if the PKCS12 is not encrypted. + :type password: :term:`bytes-like` + + :param backend: A backend instance. + + :returns: A tuple of + ``(private_key, certificate, additional_certificates)``. + ``private_key`` is a private key type or ``None``, ``certificate`` + is either the :class:`~cryptography.x509.Certificate` whose public key + matches the private key in the PKCS 12 object or ``None``, and + ``additional_certificates`` is a list of all other + :class:`~cryptography.x509.Certificate` instances in the PKCS12 object. + Serialization Formats ~~~~~~~~~~~~~~~~~~~~~ +.. currentmodule:: cryptography.hazmat.primitives.serialization + .. class:: PrivateFormat .. versionadded:: 0.8 @@ -418,12 +458,31 @@ Frequently known as PKCS#1 format. Still a widely used format, but generally considered legacy. + A PEM encoded RSA key will look like:: + + -----BEGIN RSA PRIVATE KEY----- + ... + -----END RSA PRIVATE KEY----- + .. attribute:: PKCS8 A more modern format for serializing keys which allows for better encryption. Choose this unless you have explicit legacy compatibility requirements. + A PEM encoded key will look like:: + + -----BEGIN PRIVATE KEY----- + ... + -----END PRIVATE KEY----- + + .. attribute:: Raw + + .. versionadded:: 2.5 + + A raw format used by :doc:`/hazmat/primitives/asymmetric/x448`. It is a + binary format and is invalid for other key types. + .. class:: PublicFormat .. versionadded:: 0.8 @@ -443,11 +502,23 @@ identifier and the public key as a bit string. Choose this unless you have specific needs. + A PEM encoded key will look like:: + + -----BEGIN PUBLIC KEY----- + ... + -----END PUBLIC KEY----- + .. attribute:: PKCS1 Just the public key elements (without the algorithm identifier). This format is RSA only, but is used by some older systems. + A PEM encoded key will look like:: + + -----BEGIN RSA PUBLIC KEY----- + ... + -----END RSA PUBLIC KEY----- + .. attribute:: OpenSSH .. versionadded:: 1.4 @@ -455,6 +526,27 @@ The public key format used by OpenSSH (e.g. as found in ``~/.ssh/id_rsa.pub`` or ``~/.ssh/authorized_keys``). + .. attribute:: Raw + + .. versionadded:: 2.5 + + A raw format used by :doc:`/hazmat/primitives/asymmetric/x448`. It is a + binary format and is invalid for other key types. + + .. attribute:: CompressedPoint + + .. versionadded:: 2.5 + + A compressed elliptic curve public key as defined in ANSI X9.62 section + 4.3.6 (as well as `SEC 1 v2.0`_). + + .. attribute:: UncompressedPoint + + .. versionadded:: 2.5 + + An uncompressed elliptic curve public key as defined in ANSI X9.62 + section 4.3.6 (as well as `SEC 1 v2.0`_). + .. class:: ParameterFormat .. versionadded:: 2.0 @@ -477,14 +569,16 @@ :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization` , :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization` - , :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKeyWithSerialization` + , :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKeyWithSerialization`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization`, and - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization` + :class:`~cryptography.hazmat.primitives.asymmetric.x448.X448PrivateKey` as well as ``public_bytes`` on - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization`, - :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKeyWithSerialization` + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`, and - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization`. + :class:`~cryptography.hazmat.primitives.asymmetric.x448.X448PublicKey`. .. attribute:: PEM @@ -504,6 +598,20 @@ The format used by OpenSSH public keys. This is a text format. + .. attribute:: Raw + + .. versionadded:: 2.5 + + A raw format used by :doc:`/hazmat/primitives/asymmetric/x448`. It is a + binary format and is invalid for other key types. + + .. attribute:: X962 + + .. versionadded:: 2.5 + + The format used by elliptic curve point encodings. This is a binary + format. + Serialization Encryption Types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -535,4 +643,5 @@ Do not encrypt. -.. _`PKCS3`: https://www.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-3-diffie-hellman-key-agreement-standar.htm +.. _`PKCS3`: https://www.teletrust.de/fileadmin/files/oid/oid_pkcs-3v1-4.pdf +.. _`SEC 1 v2.0`: http://www.secg.org/sec1-v2.pdf diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/x25519.rst python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/x25519.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/x25519.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/x25519.rst 2019-02-27 23:27:53.000000000 +0000 @@ -15,12 +15,16 @@ ~~~~~~~~~~~~~~~~~~ For most applications the ``shared_key`` should be passed to a key -derivation function. +derivation function. This allows mixing of additional information into the +key, derivation of multiple keys, and destroys any structure that may be +present. .. doctest:: >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey + >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF >>> # Generate a private key for use in the exchange. >>> private_key = X25519PrivateKey.generate() >>> # In a real handshake the peer_public_key will be received from the @@ -29,10 +33,25 @@ >>> # must agree on a common set of parameters. >>> peer_public_key = X25519PrivateKey.generate().public_key() >>> shared_key = private_key.exchange(peer_public_key) + >>> # Perform key derivation. + >>> derived_key = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).derive(shared_key) >>> # For the next handshake we MUST generate another private key. >>> private_key_2 = X25519PrivateKey.generate() >>> peer_public_key_2 = X25519PrivateKey.generate().public_key() >>> shared_key_2 = private_key_2.exchange(peer_public_key_2) + >>> derived_key_2 = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).derive(shared_key_2) Key interfaces ~~~~~~~~~~~~~~ @@ -47,6 +66,29 @@ :returns: :class:`X25519PrivateKey` + .. classmethod:: from_private_bytes(data) + + .. versionadded:: 2.5 + + A class method for loading an X25519 key encoded as + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`. + + :param bytes data: 32 byte private key. + + :returns: :class:`X25519PrivateKey` + + .. doctest:: + + >>> from cryptography.hazmat.primitives import serialization + >>> from cryptography.hazmat.primitives.asymmetric import x25519 + >>> private_key = x25519.X25519PrivateKey.generate() + >>> private_bytes = private_key.private_bytes( + ... encoding=serialization.Encoding.Raw, + ... format=serialization.PrivateFormat.Raw, + ... encryption_algorithm=serialization.NoEncryption() + ... ) + >>> loaded_private_key = x25519.X25519PrivateKey.from_private_bytes(private_bytes) + .. method:: public_key() :returns: :class:`X25519PublicKey` @@ -58,6 +100,38 @@ :returns bytes: A shared key. + .. method:: private_bytes(encoding, format, encryption_algorithm) + + .. versionadded:: 2.5 + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8` + or + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + ) are chosen to define the exact serialization. + + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.PrivateFormat` + enum. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`. + + :param encryption_algorithm: An instance of an object conforming to the + :class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption` + interface. + + :return bytes: Serialized key. + .. class:: X25519PublicKey .. versionadded:: 2.0 @@ -73,12 +147,37 @@ >>> from cryptography.hazmat.primitives.asymmetric import x25519 >>> private_key = x25519.X25519PrivateKey.generate() >>> public_key = private_key.public_key() - >>> public_bytes = public_key.public_bytes() + >>> public_bytes = public_key.public_bytes( + ... encoding=serialization.Encoding.Raw, + ... format=serialization.PublicFormat.Raw + ... ) >>> loaded_public_key = x25519.X25519PublicKey.from_public_bytes(public_bytes) - .. method:: public_bytes() + .. method:: public_bytes(encoding, format) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo` + or + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + ) are chosen to define the exact serialization. + + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.PublicFormat` + enum. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`. - :returns bytes: The raw bytes of the public key. + :returns bytes: The public key bytes. .. _`Diffie-Hellman key exchange`: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/x448.rst python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/x448.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/asymmetric/x448.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/asymmetric/x448.rst 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,179 @@ +.. hazmat:: + +X448 key exchange +=================== + +.. currentmodule:: cryptography.hazmat.primitives.asymmetric.x448 + + +X448 is an elliptic curve `Diffie-Hellman key exchange`_ using `Curve448`_. +It allows two parties to jointly agree on a shared secret using an insecure +channel. + + +Exchange Algorithm +~~~~~~~~~~~~~~~~~~ + +For most applications the ``shared_key`` should be passed to a key +derivation function. This allows mixing of additional information into the +key, derivation of multiple keys, and destroys any structure that may be +present. + +.. doctest:: + + >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import hashes + >>> from cryptography.hazmat.primitives.asymmetric.x448 import X448PrivateKey + >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF + >>> # Generate a private key for use in the exchange. + >>> private_key = X448PrivateKey.generate() + >>> # In a real handshake the peer_public_key will be received from the + >>> # other party. For this example we'll generate another private key and + >>> # get a public key from that. Note that in a DH handshake both peers + >>> # must agree on a common set of parameters. + >>> peer_public_key = X448PrivateKey.generate().public_key() + >>> shared_key = private_key.exchange(peer_public_key) + >>> # Perform key derivation. + >>> derived_key = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).derive(shared_key) + >>> # For the next handshake we MUST generate another private key. + >>> private_key_2 = X448PrivateKey.generate() + >>> peer_public_key_2 = X448PrivateKey.generate().public_key() + >>> shared_key_2 = private_key_2.exchange(peer_public_key_2) + >>> derived_key_2 = HKDF( + ... algorithm=hashes.SHA256(), + ... length=32, + ... salt=None, + ... info=b'handshake data', + ... backend=default_backend() + ... ).derive(shared_key_2) + +Key interfaces +~~~~~~~~~~~~~~ + +.. class:: X448PrivateKey + + .. versionadded:: 2.5 + + .. classmethod:: generate() + + Generate an X448 private key. + + :returns: :class:`X448PrivateKey` + + .. classmethod:: from_private_bytes(data) + + :param data: 56 byte private key. + :type data: :term:`bytes-like` + + :returns: :class:`X448PrivateKey` + + .. doctest:: + + >>> from cryptography.hazmat.primitives import serialization + >>> from cryptography.hazmat.primitives.asymmetric import x448 + >>> private_key = x448.X448PrivateKey.generate() + >>> private_bytes = private_key.private_bytes( + ... encoding=serialization.Encoding.Raw, + ... format=serialization.PrivateFormat.Raw, + ... encryption_algorithm=serialization.NoEncryption() + ... ) + >>> loaded_private_key = x448.X448PrivateKey.from_private_bytes(private_bytes) + + .. method:: public_key() + + :returns: :class:`X448PublicKey` + + .. method:: exchange(peer_public_key) + + :param X448PublicKey peer_public_key: The public key for the + peer. + + :returns bytes: A shared key. + + .. method:: private_bytes(encoding, format, encryption_algorithm) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8` + or + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + ) are chosen to define the exact serialization. + + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.PrivateFormat` + enum. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`. + + :param encryption_algorithm: An instance of an object conforming to the + :class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption` + interface. + + :return bytes: Serialized key. + +.. class:: X448PublicKey + + .. versionadded:: 2.5 + + .. classmethod:: from_public_bytes(data) + + :param bytes data: 56 byte public key. + + :returns: :class:`X448PublicKey` + + .. doctest:: + + >>> from cryptography.hazmat.primitives import serialization + >>> from cryptography.hazmat.primitives.asymmetric import x448 + >>> private_key = x448.X448PrivateKey.generate() + >>> public_key = private_key.public_key() + >>> public_bytes = public_key.public_bytes( + ... encoding=serialization.Encoding.Raw, + ... format=serialization.PublicFormat.Raw + ... ) + >>> loaded_public_key = x448.X448PublicKey.from_public_bytes(public_bytes) + + .. method:: public_bytes(encoding, format) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo` + or + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + ) are chosen to define the exact serialization. + + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.PublicFormat` + enum. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`. + + :returns bytes: The public key bytes. + + +.. _`Diffie-Hellman key exchange`: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange +.. _`Curve448`: https://en.wikipedia.org/wiki/Curve448 diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/cryptographic-hashes.rst python-cryptography-2.6.1/docs/hazmat/primitives/cryptographic-hashes.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/cryptographic-hashes.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/cryptographic-hashes.rst 2019-02-27 23:27:53.000000000 +0000 @@ -26,7 +26,7 @@ >>> digest.update(b"abc") >>> digest.update(b"123") >>> digest.finalize() - 'l\xa1=R\xcap\xc8\x83\xe0\xf0\xbb\x10\x1eBZ\x89\xe8bM\xe5\x1d\xb2\xd29%\x93\xafj\x84\x11\x80\x90' + b'l\xa1=R\xcap\xc8\x83\xe0\xf0\xbb\x10\x1eBZ\x89\xe8bM\xe5\x1d\xb2\xd29%\x93\xafj\x84\x11\x80\x90' If the backend doesn't support the requested ``algorithm`` an :class:`~cryptography.exceptions.UnsupportedAlgorithm` exception will be @@ -102,6 +102,20 @@ SHA-512 is a cryptographic hash function from the SHA-2 family and is standardized by NIST. It produces a 512-bit message digest. +.. class:: SHA512_224() + + .. versionadded:: 2.5 + + SHA-512/224 is a cryptographic hash function from the SHA-2 family and is + standardized by NIST. It produces a 224-bit message digest. + +.. class:: SHA512_256() + + .. versionadded:: 2.5 + + SHA-512/256 is a cryptographic hash function from the SHA-2 family and is + standardized by NIST. It produces a 256-bit message digest. + BLAKE2 ~~~~~~ @@ -134,6 +148,73 @@ :raises ValueError: If the ``digest_size`` is invalid. +SHA-3 family +~~~~~~~~~~~~ + +SHA-3 is the most recent NIST secure hash algorithm standard. Despite the +larger number SHA-3 is not considered to be better than SHA-2. Instead, it uses +a significantly different internal structure so that **if** an attack appears +against SHA-2 it is unlikely to apply to SHA-3. SHA-3 is significantly slower +than SHA-2 so at this time most users should choose SHA-2. + +.. class:: SHA3_224() + + .. versionadded:: 2.5 + + SHA3/224 is a cryptographic hash function from the SHA-3 family and is + standardized by NIST. It produces a 224-bit message digest. + +.. class:: SHA3_256() + + .. versionadded:: 2.5 + + SHA3/256 is a cryptographic hash function from the SHA-3 family and is + standardized by NIST. It produces a 256-bit message digest. + +.. class:: SHA3_384() + + .. versionadded:: 2.5 + + SHA3/384 is a cryptographic hash function from the SHA-3 family and is + standardized by NIST. It produces a 384-bit message digest. + +.. class:: SHA3_512() + + .. versionadded:: 2.5 + + SHA3/512 is a cryptographic hash function from the SHA-3 family and is + standardized by NIST. It produces a 512-bit message digest. + +.. class:: SHAKE128(digest_size) + + .. versionadded:: 2.5 + + SHAKE128 is an extendable output function (XOF) based on the same core + permutations as SHA3. It allows the caller to obtain an arbitrarily long + digest length. Longer lengths, however, do not increase security or + collision resistance and lengths shorter than 128 bit (16 bytes) will + decrease it. + + :param int digest_size: The length of output desired. Must be greater than + zero. + + :raises ValueError: If the ``digest_size`` is invalid. + +.. class:: SHAKE256(digest_size) + + .. versionadded:: 2.5 + + SHAKE256 is an extendable output function (XOF) based on the same core + permutations as SHA3. It allows the caller to obtain an arbitrarily long + digest length. Longer lengths, however, do not increase security or + collision resistance and lengths shorter than 256 bit (32 bytes) will + decrease it. + + :param int digest_size: The length of output desired. Must be greater than + zero. + + :raises ValueError: If the ``digest_size`` is invalid. + SHA-1 ~~~~~ @@ -175,7 +256,7 @@ :type: str The standard name for the hash algorithm, for example: ``"sha256"`` or - ``"whirlpool"``. + ``"blake2b"``. .. attribute:: digest_size @@ -183,12 +264,6 @@ The size of the resulting digest in bytes. - .. attribute:: block_size - - :type: int - - The internal block size of the hash algorithm in bytes. - .. class:: HashContext diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/key-derivation-functions.rst python-cryptography-2.6.1/docs/hazmat/primitives/key-derivation-functions.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/key-derivation-functions.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/key-derivation-functions.rst 2019-02-27 23:27:53.000000000 +0000 @@ -92,8 +92,9 @@ .. method:: derive(key_material) - :param bytes key_material: The input key material. For PBKDF2 this + :param key_material: The input key material. For PBKDF2 this should be a password. + :type key_material: :term:`bytes-like` :return bytes: the derived key. :raises cryptography.exceptions.AlreadyFinalized: This is raised when :meth:`derive` or @@ -199,7 +200,8 @@ .. method:: derive(key_material) - :param bytes key_material: The input key material. + :param key_material: The input key material. + :type key_material: :term:`bytes-like` :return bytes: The derived key. :raises TypeError: This exception is raised if ``key_material`` is not ``bytes``. @@ -282,7 +284,6 @@ :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the provided ``backend`` does not implement :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` - :raises TypeError: This is raised if the provided ``info`` is a unicode object :raises TypeError: This exception is raised if ``info`` is not ``bytes``. .. method:: derive(key_material) @@ -290,8 +291,6 @@ :param bytes key_material: The input key material. :return bytes: The derived key. - :raises TypeError: This is raised if the provided ``key_material`` is - a unicode object :raises TypeError: This exception is raised if ``key_material`` is not ``bytes``. @@ -314,7 +313,7 @@ called more than once. :raises TypeError: This is raised if the provided ``key_material`` is - a unicode object + a ``unicode`` object This checks whether deriving a new key from the supplied ``key_material`` generates the same key as the ``expected_key``, and @@ -378,7 +377,8 @@ .. method:: derive(key_material) - :param bytes key_material: The input key material. + :param key_material: The input key material. + :type key_material: :term:`bytes-like` :return bytes: The derived key. :raises TypeError: This exception is raised if ``key_material`` is not ``bytes``. @@ -563,7 +563,8 @@ .. method:: derive(key_material) - :param bytes key_material: The input key material. + :param key_material: The input key material. + :type key_material: :term:`bytes-like` :return bytes: The derived key. :raises TypeError: This exception is raised if ``key_material`` is not ``bytes``. @@ -689,7 +690,8 @@ .. method:: derive(key_material) - :param bytes key_material: The input key material. + :param key_material: The input key material. + :type key_material: :term:`bytes-like` :return bytes: The derived key. :raises TypeError: This exception is raised if ``key_material`` is not ``bytes``. @@ -814,7 +816,8 @@ .. method:: derive(key_material) - :param bytes key_material: The input key material. + :param key_material: The input key material. + :type key_material: :term:`bytes-like` :return bytes: the derived key. :raises TypeError: This exception is raised if ``key_material`` is not ``bytes``. diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/keywrap.rst python-cryptography-2.6.1/docs/hazmat/primitives/keywrap.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/keywrap.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/keywrap.rst 2019-02-27 23:27:53.000000000 +0000 @@ -50,6 +50,45 @@ :raises cryptography.hazmat.primitives.keywrap.InvalidUnwrap: This is raised if the key is not successfully unwrapped. +.. function:: aes_key_wrap_with_padding(wrapping_key, key_to_wrap, backend) + + .. versionadded:: 2.2 + + This function performs AES key wrap with padding as specified in + :rfc:`5649`. + + :param bytes wrapping_key: The wrapping key. + + :param bytes key_to_wrap: The key to wrap. + + :param backend: A + :class:`~cryptography.hazmat.backends.interfaces.CipherBackend` + instance that supports + :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES`. + + :return bytes: The wrapped key as bytes. + +.. function:: aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend) + + .. versionadded:: 2.2 + + This function performs AES key unwrap with padding as specified in + :rfc:`5649`. + + :param bytes wrapping_key: The wrapping key. + + :param bytes wrapped_key: The wrapped key. + + :param backend: A + :class:`~cryptography.hazmat.backends.interfaces.CipherBackend` + instance that supports + :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES`. + + :return bytes: The unwrapped key as bytes. + + :raises cryptography.hazmat.primitives.keywrap.InvalidUnwrap: This is + raised if the key is not successfully unwrapped. + Exceptions ~~~~~~~~~~ diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/mac/cmac.rst python-cryptography-2.6.1/docs/hazmat/primitives/mac/cmac.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/mac/cmac.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/mac/cmac.rst 2019-02-27 23:27:53.000000000 +0000 @@ -32,7 +32,7 @@ >>> c = cmac.CMAC(algorithms.AES(key), backend=default_backend()) >>> c.update(b"message to authenticate") >>> c.finalize() - 'CT\x1d\xc8\x0e\x15\xbe4e\xdb\xb6\x84\xca\xd9Xk' + b'CT\x1d\xc8\x0e\x15\xbe4e\xdb\xb6\x84\xca\xd9Xk' If the backend doesn't support the requested ``algorithm`` an :class:`~cryptography.exceptions.UnsupportedAlgorithm` exception will be diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/mac/hmac.rst python-cryptography-2.6.1/docs/hazmat/primitives/mac/hmac.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/mac/hmac.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/mac/hmac.rst 2019-02-27 23:27:53.000000000 +0000 @@ -32,7 +32,7 @@ >>> h = hmac.HMAC(key, hashes.SHA256(), backend=default_backend()) >>> h.update(b"message to hash") >>> h.finalize() - '#F\xdaI\x8b"e\xc4\xf1\xbb\x9a\x8fc\xff\xf5\xdex.\xbc\xcd/+\x8a\x86\x1d\x84\'\xc3\xa6\x1d\xd8J' + b'#F\xdaI\x8b"e\xc4\xf1\xbb\x9a\x8fc\xff\xf5\xdex.\xbc\xcd/+\x8a\x86\x1d\x84\'\xc3\xa6\x1d\xd8J' If the backend doesn't support the requested ``algorithm`` an :class:`~cryptography.exceptions.UnsupportedAlgorithm` exception will be @@ -54,7 +54,8 @@ ... cryptography.exceptions.InvalidSignature: Signature did not match digest. - :param bytes key: Secret key as ``bytes``. + :param key: Secret key as ``bytes``. + :type key: :term:`bytes-like` :param algorithm: An :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` instance such as those described in @@ -69,7 +70,8 @@ .. method:: update(msg) - :param bytes msg: The bytes to hash and authenticate. + :param msg: The bytes to hash and authenticate. + :type msg: :term:`bytes-like` :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize` :raises TypeError: This exception is raised if ``msg`` is not ``bytes``. diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/padding.rst python-cryptography-2.6.1/docs/hazmat/primitives/padding.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/padding.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/padding.rst 2019-02-27 23:27:53.000000000 +0000 @@ -25,16 +25,16 @@ >>> padder = padding.PKCS7(128).padder() >>> padded_data = padder.update(b"11111111111111112222222222") >>> padded_data - '1111111111111111' + b'1111111111111111' >>> padded_data += padder.finalize() >>> padded_data - '11111111111111112222222222\x06\x06\x06\x06\x06\x06' + b'11111111111111112222222222\x06\x06\x06\x06\x06\x06' >>> unpadder = padding.PKCS7(128).unpadder() >>> data = unpadder.update(padded_data) >>> data - '1111111111111111' + b'1111111111111111' >>> data + unpadder.finalize() - '11111111111111112222222222' + b'11111111111111112222222222' :param block_size: The size of the block in :term:`bits` that the data is being padded to. @@ -68,16 +68,16 @@ >>> padder = padding.ANSIX923(128).padder() >>> padded_data = padder.update(b"11111111111111112222222222") >>> padded_data - '1111111111111111' + b'1111111111111111' >>> padded_data += padder.finalize() >>> padded_data - '11111111111111112222222222\x00\x00\x00\x00\x00\x06' + b'11111111111111112222222222\x00\x00\x00\x00\x00\x06' >>> unpadder = padding.ANSIX923(128).unpadder() >>> data = unpadder.update(padded_data) >>> data - '1111111111111111' + b'1111111111111111' >>> data + unpadder.finalize() - '11111111111111112222222222' + b'11111111111111112222222222' :param block_size: The size of the block in :term:`bits` that the data is being padded to. @@ -126,4 +126,4 @@ :raises ValueError: When trying to remove padding from incorrectly padded data. -.. _`ANSI X.923`: https://en.wikipedia.org/wiki/Padding_%28cryptography%29#ANSI_X.923 +.. _`ANSI X.923`: https://en.wikipedia.org/wiki/Padding_%28cryptography%29#ANSI_X9.23 diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/symmetric-encryption.rst python-cryptography-2.6.1/docs/hazmat/primitives/symmetric-encryption.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/symmetric-encryption.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/symmetric-encryption.rst 2019-02-27 23:27:53.000000000 +0000 @@ -42,7 +42,7 @@ >>> ct = encryptor.update(b"a secret message") + encryptor.finalize() >>> decryptor = cipher.decryptor() >>> decryptor.update(ct) + decryptor.finalize() - 'a secret message' + b'a secret message' :param algorithms: A :class:`~cryptography.hazmat.primitives.ciphers.CipherAlgorithm` @@ -92,8 +92,9 @@ AES is both fast, and cryptographically strong. It is a good default choice for encryption. - :param bytes key: The secret key. This must be kept secret. Either ``128``, + :param key: The secret key. This must be kept secret. Either ``128``, ``192``, or ``256`` :term:`bits` long. + :type key: :term:`bytes-like` .. class:: Camellia(key) @@ -101,8 +102,9 @@ It is considered to have comparable security and performance to AES but is not as widely studied or deployed. - :param bytes key: The secret key. This must be kept secret. Either ``128``, + :param key: The secret key. This must be kept secret. Either ``128``, ``192``, or ``256`` :term:`bits` long. + :type key: :term:`bytes-like` .. class:: ChaCha20(key) @@ -120,15 +122,17 @@ ChaCha20 is a stream cipher used in several IETF protocols. It is standardized in :rfc:`7539`. - :param bytes key: The secret key. This must be kept secret. ``256`` + :param key: The secret key. This must be kept secret. ``256`` :term:`bits` (32 bytes) in length. + :type key: :term:`bytes-like` - :param bytes nonce: Should be unique, a :term:`nonce`. It is + :param nonce: Should be unique, a :term:`nonce`. It is critical to never reuse a ``nonce`` with a given key. Any reuse of a nonce with the same key compromises the security of every message encrypted with that key. The nonce does not need to be kept secret and may be included with the ciphertext. This must be ``128`` :term:`bits` in length. + :type nonce: :term:`bytes-like` .. note:: @@ -136,7 +140,7 @@ concatenated with a block counter (encoded as a 32-bit little-endian). If you have a separate nonce and block counter you will need to concatenate it yourself before passing it. For - example if you have an initial block counter of 2 and a 96-bit + example, if you have an initial block counter of 2 and a 96-bit nonce the concatenated nonce would be ``struct.pack(">> ct = encryptor.update(b"a secret message") >>> decryptor = cipher.decryptor() >>> decryptor.update(ct) - 'a secret message' + b'a secret message' .. class:: TripleDES(key) @@ -161,12 +165,13 @@ Nonetheless, Triple DES is not recommended for new applications because it is incredibly slow; old applications should consider moving away from it. - :param bytes key: The secret key. This must be kept secret. Either ``64``, + :param key: The secret key. This must be kept secret. Either ``64``, ``128``, or ``192`` :term:`bits` long. DES only uses ``56``, ``112``, or ``168`` bits of the key as there is a parity byte in each component of the key. Some writing refers to there being up to three separate keys that are each ``56`` bits long, they can simply be concatenated to produce the full key. + :type key: :term:`bytes-like` .. class:: CAST5(key) @@ -177,8 +182,9 @@ a variable key length cipher and supports keys from 40-128 :term:`bits` in length. - :param bytes key: The secret key, This must be kept secret. 40 to 128 + :param key: The secret key, This must be kept secret. 40 to 128 :term:`bits` in length in increments of 8 bits. + :type key: :term:`bytes-like` .. class:: SEED(key) @@ -188,8 +194,9 @@ (KISA). It is defined in :rfc:`4269` and is used broadly throughout South Korean industry, but rarely found elsewhere. - :param bytes key: The secret key. This must be kept secret. ``128`` + :param key: The secret key. This must be kept secret. ``128`` :term:`bits` in length. + :type key: :term:`bytes-like` Weak ciphers ------------ @@ -206,8 +213,9 @@ susceptible to attacks when using weak keys. The author has recommended that users of Blowfish move to newer algorithms such as :class:`AES`. - :param bytes key: The secret key. This must be kept secret. 32 to 448 + :param key: The secret key. This must be kept secret. 32 to 448 :term:`bits` in length in increments of 8 bits. + :type key: :term:`bytes-like` .. class:: ARC4(key) @@ -215,9 +223,10 @@ initial stream output. Its use is strongly discouraged. ARC4 does not use mode constructions. - :param bytes key: The secret key. This must be kept secret. Either ``40``, + :param key: The secret key. This must be kept secret. Either ``40``, ``56``, ``64``, ``80``, ``128``, ``192``, or ``256`` :term:`bits` in length. + :type key: :term:`bytes-like` .. doctest:: @@ -229,7 +238,7 @@ >>> ct = encryptor.update(b"a secret message") >>> decryptor = cipher.decryptor() >>> decryptor.update(ct) - 'a secret message' + b'a secret message' .. class:: IDEA(key) @@ -238,8 +247,9 @@ is susceptible to attacks when using weak keys. It is recommended that you do not use this cipher for new applications. - :param bytes key: The secret key. This must be kept secret. ``128`` + :param key: The secret key. This must be kept secret. ``128`` :term:`bits` in length. + :type key: :term:`bytes-like` .. _symmetric-encryption-modes: @@ -256,13 +266,14 @@ **Padding is required when using this mode.** - :param bytes initialization_vector: Must be :doc:`random bytes + :param initialization_vector: Must be :doc:`random bytes `. They do not need to be kept secret and they can be included in a transmitted message. Must be the same number of bytes as the ``block_size`` of the cipher. Each time something is encrypted a new ``initialization_vector`` should be generated. Do not reuse an ``initialization_vector`` with a given ``key``, and particularly do not use a constant ``initialization_vector``. + :type initialization_vector: :term:`bytes-like` A good construction looks like: @@ -278,7 +289,7 @@ .. doctest:: >>> from cryptography.hazmat.primitives.ciphers.modes import CBC - >>> iv = "a" * 16 + >>> iv = b"a" * 16 >>> mode = CBC(iv) @@ -295,12 +306,13 @@ **This mode does not require padding.** - :param bytes nonce: Should be unique, a :term:`nonce`. It is + :param nonce: Should be unique, a :term:`nonce`. It is critical to never reuse a ``nonce`` with a given key. Any reuse of a nonce with the same key compromises the security of every message encrypted with that key. Must be the same number of bytes as the ``block_size`` of the cipher with a given key. The nonce does not need to be kept secret and may be included with the ciphertext. + :type nonce: :term:`bytes-like` .. class:: OFB(initialization_vector) @@ -309,11 +321,12 @@ **This mode does not require padding.** - :param bytes initialization_vector: Must be :doc:`random bytes + :param initialization_vector: Must be :doc:`random bytes `. They do not need to be kept secret and they can be included in a transmitted message. Must be the same number of bytes as the ``block_size`` of the cipher. Do not reuse an ``initialization_vector`` with a given ``key``. + :type initialization_vector: :term:`bytes-like` .. class:: CFB(initialization_vector) @@ -322,11 +335,12 @@ **This mode does not require padding.** - :param bytes initialization_vector: Must be :doc:`random bytes + :param initialization_vector: Must be :doc:`random bytes `. They do not need to be kept secret and they can be included in a transmitted message. Must be the same number of bytes as the ``block_size`` of the cipher. Do not reuse an ``initialization_vector`` with a given ``key``. + :type initialization_vector: :term:`bytes-like` .. class:: CFB8(initialization_vector) @@ -336,11 +350,12 @@ **This mode does not require padding.** - :param bytes initialization_vector: Must be :doc:`random bytes + :param initialization_vector: Must be :doc:`random bytes `. They do not need to be kept secret and they can be included in a transmitted message. Must be the same number of bytes as the ``block_size`` of the cipher. Do not reuse an ``initialization_vector`` with a given ``key``. + :type initialization_vector: :term:`bytes-like` .. class:: GCM(initialization_vector, tag=None, min_tag_length=16) @@ -368,21 +383,22 @@ **This mode does not require padding.** - :param bytes initialization_vector: Must be unique, a :term:`nonce`. + :param initialization_vector: Must be unique, a :term:`nonce`. They do not need to be kept secret and they can be included in a transmitted message. NIST `recommends a 96-bit IV length`_ for performance critical situations but it can be up to 2\ :sup:`64` - 1 :term:`bits`. Do not reuse an ``initialization_vector`` with a given ``key``. + :type initialization_vector: :term:`bytes-like` .. note:: Cryptography will generate a 128-bit tag when finalizing encryption. You can shorten a tag by truncating it to the desired length but this - is **not recommended** as it lowers the security margins of the - authentication (`NIST SP-800-38D`_ recommends 96-:term:`bits` or - greater). Applications wishing to allow truncation must pass the - ``min_tag_length`` parameter. + is **not recommended** as it makes it easier to forge messages, and + also potentially leaks the key (`NIST SP-800-38D`_ recommends + 96-:term:`bits` or greater). Applications wishing to allow truncation + can pass the ``min_tag_length`` parameter. .. versionchanged:: 0.5 @@ -395,11 +411,12 @@ :meth:`~cryptography.hazmat.primitives.ciphers.AEADDecryptionContext.finalize_with_tag`. Otherwise, the tag is mandatory. - :param bytes min_tag_length: The minimum length ``tag`` must be. By default + :param int min_tag_length: The minimum length ``tag`` must be. By default this is ``16``, meaning tag truncation is not allowed. Allowing tag truncation is strongly discouraged for most applications. - :raises ValueError: This is raised if ``len(tag) < min_tag_length``. + :raises ValueError: This is raised if ``len(tag) < min_tag_length`` or the + ``initialization_vector`` is too short. :raises NotImplementedError: This is raised if the version of the OpenSSL backend used is 1.0.1 or earlier. @@ -471,7 +488,7 @@ .. testoutput:: - a secret message! + b'a secret message!' .. class:: XTS(tweak) @@ -494,11 +511,11 @@ **This mode does not require padding.** - :param bytes tweak: The tweak is a 16 byte value typically derived from + :param tweak: The tweak is a 16 byte value typically derived from something like the disk sector number. A given ``(tweak, key)`` pair should not be reused, although doing so is less catastrophic than in CTR mode. - + :type tweak: :term:`bytes-like` Insecure modes -------------- @@ -543,7 +560,8 @@ .. method:: update(data) - :param bytes data: The data you wish to pass into the context. + :param data: The data you wish to pass into the context. + :type data: :term:`bytes-like` :return bytes: Returns the data that was encrypted or decrypted. :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize` @@ -566,7 +584,8 @@ requirement and you will be making many small calls to ``update_into``. - :param bytes data: The data you wish to pass into the context. + :param data: The data you wish to pass into the context. + :type data: :term:`bytes-like` :param buf: A writable Python buffer that the data will be written into. This buffer should be ``len(data) + n - 1`` bytes where ``n`` is the block size (in bytes) of the cipher and mode combination. @@ -594,7 +613,7 @@ >>> len_decrypted = decryptor.update_into(ct, buf) >>> # get the plaintext from the buffer reading only the bytes written (len_decrypted) >>> bytes(buf[:len_decrypted]) + decryptor.finalize() - 'a secret message' + b'a secret message' .. method:: finalize() @@ -628,7 +647,8 @@ .. method:: authenticate_additional_data(data) - :param bytes data: Any data you wish to authenticate but not encrypt. + :param data: Any data you wish to authenticate but not encrypt. + :type data: :term:`bytes-like` :raises: :class:`~cryptography.exceptions.AlreadyFinalized` .. class:: AEADEncryptionContext @@ -670,6 +690,7 @@ :raises ValueError: This is raised when the data provided isn't a multiple of the algorithm's block size, if ``min_tag_length`` is less than 4, or if ``len(tag) < min_tag_length``. + ``min_tag_length`` is an argument to the ``GCM`` constructor. :raises NotImplementedError: This is raised if the version of the OpenSSL backend used is 1.0.1 or earlier. @@ -745,7 +766,7 @@ .. attribute:: initialization_vector - :type: bytes + :type: :term:`bytes-like` Exact requirements of the initialization are described by the documentation of individual modes. @@ -757,7 +778,7 @@ .. attribute:: nonce - :type: bytes + :type: :term:`bytes-like` Exact requirements of the nonce are described by the documentation of individual modes. @@ -769,7 +790,7 @@ .. attribute:: tag - :type: bytes + :type: :term:`bytes-like` Exact requirements of the tag are described by the documentation of individual modes. @@ -783,7 +804,7 @@ .. attribute:: tweak - :type: bytes + :type: :term:`bytes-like` Exact requirements of the tweak are described by the documentation of individual modes. @@ -801,13 +822,13 @@ -.. _`described by Colin Percival`: http://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html +.. _`described by Colin Percival`: https://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html .. _`recommends a 96-bit IV length`: https://csrc.nist.gov/publications/detail/sp/800-38d/final .. _`NIST SP-800-38D`: https://csrc.nist.gov/publications/detail/sp/800-38d/final .. _`Communications Security Establishment`: https://www.cse-cst.gc.ca -.. _`encrypt`: https://ssd.eff.org/en/module/what-encryption +.. _`encrypt`: https://ssd.eff.org/en/module/what-should-i-know-about-encryption .. _`CRYPTREC`: https://www.cryptrec.go.jp/english/ .. _`significant patterns in the output`: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29 .. _`International Data Encryption Algorithm`: https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm -.. _`OpenPGP`: http://openpgp.org +.. _`OpenPGP`: https://www.openpgp.org/ .. _`disk encryption`: https://en.wikipedia.org/wiki/Disk_encryption_theory#XTS diff -Nru python-cryptography-2.1.4/docs/hazmat/primitives/twofactor.rst python-cryptography-2.6.1/docs/hazmat/primitives/twofactor.rst --- python-cryptography-2.1.4/docs/hazmat/primitives/twofactor.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/hazmat/primitives/twofactor.rst 2019-02-27 23:27:53.000000000 +0000 @@ -41,9 +41,10 @@ >>> hotp_value = hotp.generate(0) >>> hotp.verify(hotp_value, 0) - :param bytes key: Per-user secret key. This value must be kept secret - and be at least 128 :term:`bits`. It is recommended that - the key be 160 bits. + :param key: Per-user secret key. This value must be kept secret + and be at least 128 :term:`bits`. It is recommended that + the key be 160 bits. + :type key: :term:`bytes-like` :param int length: Length of generated one time password as ``int``. :param cryptography.hazmat.primitives.hashes.HashAlgorithm algorithm: A :class:`~cryptography.hazmat.primitives.hashes` @@ -163,9 +164,10 @@ >>> totp_value = totp.generate(time_value) >>> totp.verify(totp_value, time_value) - :param bytes key: Per-user secret key. This value must be kept secret - and be at least 128 :term:`bits`. It is recommended that the - key be 160 bits. + :param key: Per-user secret key. This value must be kept secret + and be at least 128 :term:`bits`. It is recommended that the + key be 160 bits. + :type key: :term:`bytes-like` :param int length: Length of generated one time password as ``int``. :param cryptography.hazmat.primitives.hashes.HashAlgorithm algorithm: A :class:`~cryptography.hazmat.primitives.hashes` @@ -212,7 +214,7 @@ :param account_name: The display name of account, such as ``'Alice Smith'`` or ``'alice@example.com'``. - :type: :term:`text` + :type account_name: :term:`text` :param issuer: The optional display name of issuer. This is typically the provider or service the user wants to access using the OTP token. @@ -222,11 +224,11 @@ Provisioning URI ~~~~~~~~~~~~~~~~ -The provisioning URI of HOTP and TOTP is not actual the part of RFC 4226 and -RFC 6238, but a `spec of Google Authenticator`_. It is widely supported by web -sites and mobile applications which are using Two-Factor authentication. +The provisioning URI of HOTP and TOTP is a `feature of Google Authenticator`_ +and not actually part of the HOTP or TOTP RFCs. However, it is widely supported +by web sites and mobile applications which are using Two-Factor authentication. -For generating a provisioning URI, you could use the ``get_provisioning_uri`` +For generating a provisioning URI you can use the ``get_provisioning_uri`` method of HOTP/TOTP instances. .. code-block:: python @@ -241,5 +243,5 @@ A common usage is encoding the provisioning URI into QR code and guiding users to scan it with Two-Factor authentication applications in their mobile devices. -.. _`spec of Google Authenticator`: https://github.com/google/google-authenticator/wiki/Key-Uri-Format +.. _`feature of Google Authenticator`: https://github.com/google/google-authenticator/wiki/Key-Uri-Format .. _`Issue #2915`: https://github.com/pyca/cryptography/issues/2915 diff -Nru python-cryptography-2.1.4/docs/index.rst python-cryptography-2.6.1/docs/index.rst --- python-cryptography-2.1.4/docs/index.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/index.rst 2019-02-27 23:27:53.000000000 +0000 @@ -19,7 +19,8 @@ 'A really secret message. Not for prying eyes.' If you are interested in learning more about the field of cryptography, we -recommend `Crypto 101, by Laurens Van Houtven`_. +recommend `Crypto 101, by Laurens Van Houtven`_ and `The Cryptopals Crypto +Challenges`_. Installation ------------ @@ -92,3 +93,4 @@ :doc:`get in touch `. .. _`Crypto 101, by Laurens Van Houtven`: https://www.crypto101.io/ +.. _`The Cryptopals Crypto Challenges`: https://cryptopals.com/ diff -Nru python-cryptography-2.1.4/docs/installation.rst python-cryptography-2.6.1/docs/installation.rst --- python-cryptography-2.1.4/docs/installation.rst 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/docs/installation.rst 2019-02-27 23:27:53.000000000 +0000 @@ -10,30 +10,29 @@ Supported platforms ------------------- -Currently we test ``cryptography`` on Python 2.6, 2.7, 3.4, 3.5, 3.6, and -PyPy 5.3+ on these operating systems. +Currently we test ``cryptography`` on Python 2.7, 3.4+, and +PyPy 5.4+ on these operating systems. * x86-64 CentOS 7.x -* x86-64 FreeBSD 11 * macOS 10.12 Sierra, 10.11 El Capitan * x86-64 Ubuntu 14.04, 16.04, and rolling * x86-64 Debian Wheezy (7.x), Jessie (8.x), Stretch (9.x), and Sid (unstable) * x86-64 Alpine (latest) * 32-bit and 64-bit Python on 64-bit Windows Server 2012 -.. warning:: - Python 2.6 is no longer supported by the Python core team. The next release - of ``cryptography`` will drop support for Python 2.6. - We test compiling with ``clang`` as well as ``gcc`` and use the following OpenSSL releases: * ``OpenSSL 1.0.1`` * ``OpenSSL 1.0.1e-fips`` (``RHEL/CentOS 7``) * ``OpenSSL 1.0.1f`` -* ``OpenSSL 1.0.1j-freebsd`` * ``OpenSSL 1.0.2-latest`` * ``OpenSSL 1.1.0-latest`` +* ``OpenSSL 1.1.1-latest`` + +.. warning:: + Cryptography 2.4 has deprecated support for OpenSSL 1.0.1. + Building cryptography on Windows -------------------------------- @@ -49,7 +48,7 @@ If you prefer to compile it yourself you'll need to have OpenSSL installed. You can compile OpenSSL yourself as well or use the binaries we build for our release infrastructure (`openssl-release`_). Be sure to download the proper -version for your architecture and Python (2010 works for Python 2.6, 2.7, 3.3, +version for your architecture and Python (2010 works for Python 2.7, 3.3, and 3.4 while 2015 is required for 3.5 and above). Wherever you place your copy of OpenSSL you'll need to set the ``LIB`` and ``INCLUDE`` environment variables to include the proper locations. For example: @@ -209,7 +208,7 @@ ./config no-shared no-ssl2 no-ssl3 -fPIC --prefix=${CWD}/openssl make && make install cd .. - CFLAGS="-I${CWD}/openssl/include" LDFLAGS="-L${CWD}/openssl/lib" pip wheel --no-use-wheel cryptography + CFLAGS="-I${CWD}/openssl/include" LDFLAGS="-L${CWD}/openssl/lib" pip wheel --no-binary :all: cryptography Building cryptography on macOS ------------------------------ @@ -277,33 +276,10 @@ If you need to rebuild ``cryptography`` for any reason be sure to clear the local `wheel cache`_. -Building cryptography with conda --------------------------------- - -Because of a bug in conda, attempting to install cryptography out of the box -will result in an error. This can be resolved by setting the library path -environment variable for your platform. - -On macOS: - -.. code-block:: console - - $ env DYLD_LIBRARY_PATH="$HOME/anaconda/lib" pip install cryptography - -and on Linux: - -.. code-block:: console - - $ env LD_LIBRARY_PATH="$HOME/anaconda/lib" pip install cryptography - -You will need to set this variable every time you start Python. For more -information, consult `Greg Wilson's blog post`_ on the subject. - .. _`Homebrew`: https://brew.sh .. _`MacPorts`: https://www.macports.org .. _`openssl-release`: https://ci.cryptography.io/job/cryptography-support-jobs/job/openssl-release-1.1/ -.. _`Greg Wilson's blog post`: https://software-carpentry.org/blog/2014/04/mr-biczo-was-right.html .. _virtualenv: https://virtualenv.pypa.io/en/latest/ .. _openssl.org: https://www.openssl.org/source/ .. _`wheel cache`: https://pip.pypa.io/en/stable/reference/pip_install/#caching diff -Nru python-cryptography-2.1.4/docs/security.rst python-cryptography-2.6.1/docs/security.rst --- python-cryptography-2.1.4/docs/security.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/security.rst 2019-02-27 23:27:53.000000000 +0000 @@ -82,42 +82,12 @@ Disclosure Process ------------------ -Our process for taking a security issue from private discussion to public -disclosure involves multiple steps. +When we become aware of a security bug in ``cryptography``, we will endeavor to +fix it and issue a release as quickly as possible. We will generally issue a new +release for any security issue. -Approximately one week before full public disclosure, we will send advance -notification of the issue to a list of people and organizations, primarily -composed of operating-system vendors and other distributors of -``cryptography``. This notification will consist of an email message -containing: +The steps for issuing a security release are described in our +:doc:`/doing-a-release` documentation. -* A full description of the issue and the affected versions of - ``cryptography``. -* The steps we will be taking to remedy the issue. -* The patches, if any, that will be applied to ``cryptography``. -* The date on which the ``cryptography`` team will apply these patches, issue - new releases, and publicly disclose the issue. - -Simultaneously, the reporter of the issue will receive notification of the date -on which we plan to take the issue public. - -On the day of disclosure, we will take the following steps: - -* Apply the relevant patches to the ``cryptography`` repository. The commit - messages for these patches will indicate that they are for security issues, - but will not describe the issue in any detail; instead, they will warn of - upcoming disclosure. -* Issue the relevant releases. -* Post a notice to the cryptography mailing list that describes the issue in - detail, point to the new release and crediting the reporter of the issue. - -If a reported issue is believed to be particularly time-sensitive – due to a -known exploit in the wild, for example – the time between advance notification -and public disclosure may be shortened considerably. - -The list of people and organizations who receives advanced notification of -security issues is not and will not be made public. This list generally -consists of high-profile downstream distributors and is entirely at the -discretion of the ``cryptography`` team. .. _`master`: https://github.com/pyca/cryptography diff -Nru python-cryptography-2.1.4/docs/spelling_wordlist.txt python-cryptography-2.6.1/docs/spelling_wordlist.txt --- python-cryptography-2.1.4/docs/spelling_wordlist.txt 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/docs/spelling_wordlist.txt 2019-02-27 23:27:53.000000000 +0000 @@ -8,7 +8,9 @@ Blowfish boolean Botan +Brainpool Capitan +changelog Changelog ciphertext codebook @@ -21,6 +23,7 @@ cryptographically Debian decrypt +decrypts Decrypts decrypted decrypting @@ -38,6 +41,7 @@ El Encodings endian +extendable fallback Fernet fernet @@ -49,6 +53,7 @@ idna indistinguishability initialisms +interoperability interoperable introspectability invariants @@ -73,6 +78,7 @@ pickleable plaintext pre +precompute preprocessor preprocessors presentational @@ -91,15 +97,19 @@ Tanja testability timestamp +timestamps tunable Ubuntu unencrypted +unicode unpadded unpadding verifier Verifier Verisign +versioning wildcard WoSign +Wycheproof Xcode XEX diff -Nru python-cryptography-2.1.4/docs/x509/index.rst python-cryptography-2.6.1/docs/x509/index.rst --- python-cryptography-2.1.4/docs/x509/index.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/x509/index.rst 2019-02-27 23:27:53.000000000 +0000 @@ -10,6 +10,7 @@ tutorial certificate-transparency + ocsp reference .. _`public key infrastructure`: https://en.wikipedia.org/wiki/Public_key_infrastructure diff -Nru python-cryptography-2.1.4/docs/x509/ocsp.rst python-cryptography-2.6.1/docs/x509/ocsp.rst --- python-cryptography-2.1.4/docs/x509/ocsp.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/docs/x509/ocsp.rst 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,669 @@ +OCSP +==== + +.. currentmodule:: cryptography.x509.ocsp + +.. testsetup:: + + import base64 + pem_cert = b""" + -----BEGIN CERTIFICATE----- + MIIFvTCCBKWgAwIBAgICPyAwDQYJKoZIhvcNAQELBQAwRzELMAkGA1UEBhMCVVMx + FjAUBgNVBAoTDUdlb1RydXN0IEluYy4xIDAeBgNVBAMTF1JhcGlkU1NMIFNIQTI1 + NiBDQSAtIEczMB4XDTE0MTAxNTEyMDkzMloXDTE4MTExNjAxMTUwM1owgZcxEzAR + BgNVBAsTCkdUNDg3NDI5NjUxMTAvBgNVBAsTKFNlZSB3d3cucmFwaWRzc2wuY29t + L3Jlc291cmNlcy9jcHMgKGMpMTQxLzAtBgNVBAsTJkRvbWFpbiBDb250cm9sIFZh + bGlkYXRlZCAtIFJhcGlkU1NMKFIpMRwwGgYDVQQDExN3d3cuY3J5cHRvZ3JhcGh5 + LmlvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAom/FebKJIot7Sp3s + itG1sicpe3thCssjI+g1JDAS7I3GLVNmbms1DOdIIqwf01gZkzzXBN2+9sOnyRaR + PPfCe1jTr3dk2y6rPE559vPa1nZQkhlzlhMhlPyjaT+S7g4Tio4qV2sCBZU01DZJ + CaksfohN+5BNVWoJzTbOcrHOEJ+M8B484KlBCiSxqf9cyNQKru4W3bHaCVNVJ8eu + 6i6KyhzLa0L7yK3LXwwXVs583C0/vwFhccGWsFODqD/9xHUzsBIshE8HKjdjDi7Y + 3BFQzVUQFjBB50NSZfAA/jcdt1blxJouc7z9T8Oklh+V5DDBowgAsrT4b6Z2Fq6/ + r7D1GqivLK/ypUQmxq2WXWAUBb/Q6xHgxASxI4Br+CByIUQJsm8L2jzc7k+mF4hW + ltAIUkbo8fGiVnat0505YJgxWEDKOLc4Gda6d/7GVd5AvKrz242bUqeaWo6e4MTx + diku2Ma3rhdcr044Qvfh9hGyjqNjvhWY/I+VRWgihU7JrYvgwFdJqsQ5eiKT4OHi + gsejvWwkZzDtiQ+aQTrzM1FsY2swJBJsLSX4ofohlVRlIJCn/ME+XErj553431Lu + YQ5SzMd3nXzN78Vj6qzTfMUUY72UoT1/AcFiUMobgIqrrmwuNxfrkbVE2b6Bga74 + FsJX63prvrJ41kuHK/16RQBM7fcCAwEAAaOCAWAwggFcMB8GA1UdIwQYMBaAFMOc + 8/zTRgg0u85Gf6B8W/PiCMtZMFcGCCsGAQUFBwEBBEswSTAfBggrBgEFBQcwAYYT + aHR0cDovL2d2LnN5bWNkLmNvbTAmBggrBgEFBQcwAoYaaHR0cDovL2d2LnN5bWNi + LmNvbS9ndi5jcnQwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB + BggrBgEFBQcDAjAvBgNVHREEKDAmghN3d3cuY3J5cHRvZ3JhcGh5Lmlvgg9jcnlw + dG9ncmFwaHkuaW8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2d2LnN5bWNiLmNv + bS9ndi5jcmwwDAYDVR0TAQH/BAIwADBFBgNVHSAEPjA8MDoGCmCGSAGG+EUBBzYw + LDAqBggrBgEFBQcCARYeaHR0cHM6Ly93d3cucmFwaWRzc2wuY29tL2xlZ2FsMA0G + CSqGSIb3DQEBCwUAA4IBAQAzIYO2jx7h17FBT74tJ2zbV9OKqGb7QF8y3wUtP4xc + dH80vprI/Cfji8s86kr77aAvAqjDjaVjHn7UzebhSUivvRPmfzRgyWBacomnXTSt + Xlt2dp2nDQuwGyK2vB7dMfKnQAkxwq1sYUXznB8i0IhhCAoXp01QGPKq51YoIlnF + 7DRMk6iEaL1SJbkIrLsCQyZFDf0xtfW9DqXugMMLoxeCsBhZJQzNyS2ryirrv9LH + aK3+6IZjrcyy9bkpz/gzJucyhU+75c4My/mnRCrtItRbCQuiI5pd5poDowm+HH9i + GVI9+0lAFwxOUnOnwsoI40iOoxjLMGB+CgFLKCGUcWxP + -----END CERTIFICATE----- + """ + pem_issuer = b""" + -----BEGIN CERTIFICATE----- + MIIEJTCCAw2gAwIBAgIDAjp3MA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNVBAYTAlVT + MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i + YWwgQ0EwHhcNMTQwODI5MjEzOTMyWhcNMjIwNTIwMjEzOTMyWjBHMQswCQYDVQQG + EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXUmFwaWRTU0wg + U0hBMjU2IENBIC0gRzMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCv + VJvZWF0eLFbG1eh/9H0WA//Qi1rkjqfdVC7UBMBdmJyNkA+8EGVf2prWRHzAn7Xp + SowLBkMEu/SW4ib2YQGRZjEiwzQ0Xz8/kS9EX9zHFLYDn4ZLDqP/oIACg8PTH2lS + 1p1kD8mD5xvEcKyU58Okaiy9uJ5p2L4KjxZjWmhxgHsw3hUEv8zTvz5IBVV6s9cQ + DAP8m/0Ip4yM26eO8R5j3LMBL3+vV8M8SKeDaCGnL+enP/C1DPz1hNFTvA5yT2AM + QriYrRmIV9cE7Ie/fodOoyH5U/02mEiN1vi7SPIpyGTRzFRIU4uvt2UevykzKdkp + YEj4/5G8V1jlNS67abZZAgMBAAGjggEdMIIBGTAfBgNVHSMEGDAWgBTAephojYn7 + qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUw5zz/NNGCDS7zkZ/oHxb8+IIy1kwEgYD + VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwNQYDVR0fBC4wLDAqoCig + JoYkaHR0cDovL2cuc3ltY2IuY29tL2NybHMvZ3RnbG9iYWwuY3JsMC4GCCsGAQUF + BwEBBCIwIDAeBggrBgEFBQcwAYYSaHR0cDovL2cuc3ltY2QuY29tMEwGA1UdIARF + MEMwQQYKYIZIAYb4RQEHNjAzMDEGCCsGAQUFBwIBFiVodHRwOi8vd3d3Lmdlb3Ry + dXN0LmNvbS9yZXNvdXJjZXMvY3BzMA0GCSqGSIb3DQEBCwUAA4IBAQCjWB7GQzKs + rC+TeLfqrlRARy1+eI1Q9vhmrNZPc9ZE768LzFvB9E+aj0l+YK/CJ8cW8fuTgZCp + fO9vfm5FlBaEvexJ8cQO9K8EWYOHDyw7l8NaEpt7BDV7o5UzCHuTcSJCs6nZb0+B + kvwHtnm8hEqddwnxxYny8LScVKoSew26T++TGezvfU5ho452nFnPjJSxhJf3GrkH + uLLGTxN5279PURt/aQ1RKsHWFf83UTRlUfQevjhq7A6rvz17OQV79PP7GqHQyH5O + ZI3NjGFVkP46yl0lD/gdo0p0Vk8aVUBwdSWmMy66S6VdU5oNMOGNX2Esr8zvsJmh + gP8L8mJMcCaY + -----END CERTIFICATE----- + """ + pem_responder_cert = b""" + -----BEGIN CERTIFICATE----- + MIIBPjCB5KADAgECAgQHW80VMAoGCCqGSM49BAMCMCcxCzAJBgNVBAYTAlVTMRgw + FgYDVQQDDA9DcnlwdG9ncmFwaHkgQ0EwHhcNMTgxMDA3MTIzNTEwWhcNMjgxMDA0 + MTIzNTEwWjAnMQswCQYDVQQGEwJVUzEYMBYGA1UEAwwPQ3J5cHRvZ3JhcGh5IENB + MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbQ2E0N/E3R0zEG+qa+yAFXBY6Fte + QzyvFdq7EZHDktlyUllaVJBrbX1ItV0MlayFwwQPhZmuLPpQBzuVKyrUfTAKBggq + hkjOPQQDAgNJADBGAiEAo0NQRmfPvhWQpSvJzV+2Ag441Zeckk+bib7swduQIjIC + IQCqYD9pArB2SWfmhQCSZkNEATlsPIML8lvlSkbNcrmrqQ== + -----END CERTIFICATE----- + """ + pem_responder_key = b""" + -----BEGIN PRIVATE KEY----- + MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgO+vsRu8xDIVZE+xh + s8ESqJqcpJlwmj8CtF8HPHxrDSGhRANCAARtDYTQ38TdHTMQb6pr7IAVcFjoW15D + PK8V2rsRkcOS2XJSWVpUkGttfUi1XQyVrIXDBA+Fma4s+lAHO5UrKtR9 + -----END PRIVATE KEY----- + """ + der_ocsp_req = ( + b"0V0T0R0P0N0\t\x06\x05+\x0e\x03\x02\x1a\x05\x00\x04\x148\xcaF\x8c" + b"\x07D\x8d\xf4\x81\x96\xc7mmLpQ\x9e`\xa7\xbd\x04\x14yu\xbb\x84:\xcb" + b",\xdez\t\xbe1\x1bC\xbc\x1c*MSX\x02\x15\x00\x98\xd9\xe5\xc0\xb4\xc3" + b"sU-\xf7|]\x0f\x1e\xb5\x12\x8eIE\xf9" + ) + der_ocsp_resp_unauth = b"0\x03\n\x01\x06" + +OCSP (Online Certificate Status Protocol) is a method of checking the +revocation status of certificates. It is specified in :rfc:`6960`, as well +as other obsoleted RFCs. + + +Loading Requests +~~~~~~~~~~~~~~~~ + +.. function:: load_der_ocsp_request(data) + + .. versionadded:: 2.4 + + Deserialize an OCSP request from DER encoded data. + + :param bytes data: The DER encoded OCSP request data. + + :returns: An instance of :class:`~cryptography.x509.ocsp.OCSPRequest`. + + .. doctest:: + + >>> from cryptography.x509 import ocsp + >>> ocsp_req = ocsp.load_der_ocsp_request(der_ocsp_req) + >>> print(ocsp_req.serial_number) + 872625873161273451176241581705670534707360122361 + + +Creating Requests +~~~~~~~~~~~~~~~~~ + +.. class:: OCSPRequestBuilder + + .. versionadded:: 2.4 + + This class is used to create :class:`~cryptography.x509.ocsp.OCSPRequest` + objects. + + + .. method:: add_certificate(cert, issuer, algorithm) + + Adds a request using a certificate, issuer certificate, and hash + algorithm. This can only be called once. + + :param cert: The :class:`~cryptography.x509.Certificate` whose validity + is being checked. + + :param issuer: The issuer :class:`~cryptography.x509.Certificate` of + the certificate that is being checked. + + :param algorithm: A + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + instance. For OCSP only + :class:`~cryptography.hazmat.primitives.hashes.SHA1`, + :class:`~cryptography.hazmat.primitives.hashes.SHA224`, + :class:`~cryptography.hazmat.primitives.hashes.SHA256`, + :class:`~cryptography.hazmat.primitives.hashes.SHA384`, and + :class:`~cryptography.hazmat.primitives.hashes.SHA512` are allowed. + + .. method:: add_extension(extension, critical) + + Adds an extension to the request. + + :param extension: An extension conforming to the + :class:`~cryptography.x509.ExtensionType` interface. + + :param critical: Set to ``True`` if the extension must be understood and + handled. + + .. method:: build() + + :returns: A new :class:`~cryptography.x509.ocsp.OCSPRequest`. + + .. doctest:: + + >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import serialization + >>> from cryptography.hazmat.primitives.hashes import SHA1 + >>> from cryptography.x509 import load_pem_x509_certificate, ocsp + >>> cert = load_pem_x509_certificate(pem_cert, default_backend()) + >>> issuer = load_pem_x509_certificate(pem_issuer, default_backend()) + >>> builder = ocsp.OCSPRequestBuilder() + >>> # SHA1 is in this example because RFC 5019 mandates its use. + >>> builder = builder.add_certificate(cert, issuer, SHA1()) + >>> req = builder.build() + >>> base64.b64encode(req.public_bytes(serialization.Encoding.DER)) + b'MEMwQTA/MD0wOzAJBgUrDgMCGgUABBRAC0Z68eay0wmDug1gfn5ZN0gkxAQUw5zz/NNGCDS7zkZ/oHxb8+IIy1kCAj8g' + +Loading Responses +~~~~~~~~~~~~~~~~~ + +.. function:: load_der_ocsp_response(data) + + .. versionadded:: 2.4 + + Deserialize an OCSP response from DER encoded data. + + :param bytes data: The DER encoded OCSP response data. + + :returns: An instance of :class:`~cryptography.x509.ocsp.OCSPResponse`. + + .. doctest:: + + >>> from cryptography.x509 import ocsp + >>> ocsp_resp = ocsp.load_der_ocsp_response(der_ocsp_resp_unauth) + >>> print(ocsp_resp.response_status) + OCSPResponseStatus.UNAUTHORIZED + + +Creating Responses +~~~~~~~~~~~~~~~~~~ + +.. class:: OCSPResponseBuilder + + .. versionadded:: 2.4 + + This class is used to create :class:`~cryptography.x509.ocsp.OCSPResponse` + objects. You cannot set ``produced_at`` on OCSP responses at this time. + Instead the field is set to current UTC time when calling ``sign``. For + unsuccessful statuses call the class method + :meth:`~cryptography.x509.ocsp.OCSPResponseBuilder.build_unsuccessful`. + + .. method:: add_response(cert, issuer, algorithm, cert_status, this_update, next_update, revocation_time, revocation_reason) + + This method adds status information about the certificate that was + requested to the response. + + :param cert: The :class:`~cryptography.x509.Certificate` whose validity + is being checked. + + :param issuer: The issuer :class:`~cryptography.x509.Certificate` of + the certificate that is being checked. + + :param algorithm: A + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + instance. For OCSP only + :class:`~cryptography.hazmat.primitives.hashes.SHA1`, + :class:`~cryptography.hazmat.primitives.hashes.SHA224`, + :class:`~cryptography.hazmat.primitives.hashes.SHA256`, + :class:`~cryptography.hazmat.primitives.hashes.SHA384`, and + :class:`~cryptography.hazmat.primitives.hashes.SHA512` are allowed. + + :param cert_status: An item from the + :class:`~cryptography.x509.ocsp.OCSPCertStatus` enumeration. + + :param this_update: A naïve :class:`datetime.datetime` object + representing the most recent time in UTC at which the status being + indicated is known by the responder to be correct. + + :param next_update: A naïve :class:`datetime.datetime` object or + ``None``. The time in UTC at or before which newer information will + be available about the status of the certificate. + + :param revocation_time: A naïve :class:`datetime.datetime` object or + ``None`` if the ``cert`` is not revoked. The time in UTC at which + the certificate was revoked. + + :param revocation_reason: An item from the + :class:`~cryptography.x509.ReasonFlags` enumeration or ``None`` if + the ``cert`` is not revoked. + + .. method:: certificates(certs) + + Add additional certificates that should be used to verify the + signature on the response. This is typically used when the responder + utilizes an OCSP delegate. + + :param list certs: A list of :class:`~cryptography.x509.Certificate` + objects. + + .. method:: responder_id(encoding, responder_cert) + + Set the ``responderID`` on the OCSP response. This is the data a + client will use to determine what certificate signed the response. + + :param responder_cert: The :class:`~cryptography.x509.Certificate` + object for the certificate whose private key will sign the + OCSP response. If the certificate and key do not match an + error will be raised when calling ``sign``. + :param encoding: Either + :attr:`~cryptography.x509.ocsp.OCSPResponderEncoding.HASH` or + :attr:`~cryptography.x509.ocsp.OCSPResponderEncoding.NAME`. + + .. method:: add_extension(extension, critical) + + Adds an extension to the response. + + :param extension: An extension conforming to the + :class:`~cryptography.x509.ExtensionType` interface. + + :param critical: Set to ``True`` if the extension must be understood and + handled. + + .. method:: sign(private_key, algorithm) + + Creates the OCSP response that can then be serialized and sent to + clients. This method will create a + :attr:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL` response. + + :param private_key: The + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey` + or + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` + that will be used to sign the certificate. + + :param algorithm: The + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` that + will be used to generate the signature. + + :returns: A new :class:`~cryptography.x509.ocsp.OCSPResponse`. + + .. doctest:: + + >>> import datetime + >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import hashes, serialization + >>> from cryptography.x509 import load_pem_x509_certificate, ocsp + >>> cert = load_pem_x509_certificate(pem_cert, default_backend()) + >>> issuer = load_pem_x509_certificate(pem_issuer, default_backend()) + >>> responder_cert = load_pem_x509_certificate(pem_responder_cert, default_backend()) + >>> responder_key = serialization.load_pem_private_key(pem_responder_key, None, default_backend()) + >>> builder = ocsp.OCSPResponseBuilder() + >>> # SHA1 is in this example because RFC 5019 mandates its use. + >>> builder = builder.add_response( + ... cert=cert, issuer=issuer, algorithm=hashes.SHA1(), + ... cert_status=ocsp.OCSPCertStatus.GOOD, + ... this_update=datetime.datetime.now(), + ... next_update=datetime.datetime.now(), + ... revocation_time=None, revocation_reason=None + ... ).responder_id( + ... ocsp.OCSPResponderEncoding.HASH, responder_cert + ... ) + >>> response = builder.sign(responder_key, hashes.SHA256()) + >>> response.certificate_status + + + .. classmethod:: build_unsuccessful(response_status) + + Creates an unsigned OCSP response which can then be serialized and + sent to clients. ``build_unsuccessful`` may only be called with a + :class:`~cryptography.x509.ocsp.OCSPResponseStatus` that is not + ``SUCCESSFUL``. Since this is a class method note that no other + methods can or should be called as unsuccessful statuses do not + encode additional data. + + :returns: A new :class:`~cryptography.x509.ocsp.OCSPResponse`. + + .. doctest:: + + >>> from cryptography.hazmat.backends import default_backend + >>> from cryptography.hazmat.primitives import hashes, serialization + >>> from cryptography.x509 import load_pem_x509_certificate, ocsp + >>> response = ocsp.OCSPResponseBuilder.build_unsuccessful( + ... ocsp.OCSPResponseStatus.UNAUTHORIZED + ... ) + >>> response.response_status + + + +Interfaces +~~~~~~~~~~ + +.. class:: OCSPRequest + + .. versionadded:: 2.4 + + An ``OCSPRequest`` is an object containing information about a certificate + whose status is being checked. + + .. attribute:: issuer_key_hash + + :type: bytes + + The hash of the certificate issuer's key. The hash algorithm used + is defined by the ``hash_algorithm`` property. + + .. attribute:: issuer_name_hash + + :type: bytes + + The hash of the certificate issuer's name. The hash algorithm used + is defined by the ``hash_algorithm`` property. + + .. attribute:: hash_algorithm + + :type: :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + + The algorithm used to generate the ``issuer_key_hash`` and + ``issuer_name_hash``. + + .. attribute:: serial_number + + :type: int + + The serial number of the certificate to check. + + .. attribute:: extensions + + :type: :class:`~cryptography.x509.Extensions` + + The extensions encoded in the request. + + .. method:: public_bytes(encoding) + + :param encoding: The encoding to use. Only + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER` + is supported. + + :return bytes: The serialized OCSP request. + +.. class:: OCSPResponse + + .. versionadded:: 2.4 + + An ``OCSPResponse`` is the data provided by an OCSP responder in response + to an ``OCSPRequest``. + + .. attribute:: response_status + + :type: :class:`~cryptography.x509.ocsp.OCSPResponseStatus` + + The status of the response. + + .. attribute:: signature_algorithm_oid + + :type: :class:`~cryptography.x509.ObjectIdentifier` + + Returns the object identifier of the signature algorithm used + to sign the response. This will be one of the OIDs from + :class:`~cryptography.x509.oid.SignatureAlgorithmOID`. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: signature_hash_algorithm + + .. versionadded:: 2.5 + + :type: :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + + Returns the + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` which + was used in signing this response. + + .. attribute:: signature + + :type: bytes + + The signature bytes. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: tbs_response_bytes + + :type: bytes + + The DER encoded bytes payload that is hashed and then signed. This + data may be used to validate the signature on the OCSP response. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: certificates + + :type: list + + A list of zero or more :class:`~cryptography.x509.Certificate` objects + used to help build a chain to verify the OCSP response. This situation + occurs when the OCSP responder uses a delegate certificate. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: responder_key_hash + + :type: bytes or None + + The responder's key hash or ``None`` if the response has a + ``responder_name``. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: responder_name + + :type: :class:`~cryptography.x509.Name` or None + + The responder's ``Name`` or ``None`` if the response has a + ``responder_key_hash``. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: produced_at + + :type: :class:`datetime.datetime` + + A naïve datetime representing the time when the response was produced. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: certificate_status + + :type: :class:`~cryptography.x509.ocsp.OCSPCertStatus` + + The status of the certificate being checked. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: revocation_time + + :type: :class:`datetime.datetime` or None + + A naïve datetime representing the time when the certificate was revoked + or ``None`` if the certificate has not been revoked. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: revocation_reason + + :type: :class:`~cryptography.x509.ReasonFlags` or None + + The reason the certificate was revoked or ``None`` if not specified or + not revoked. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: this_update + + :type: :class:`datetime.datetime` + + A naïve datetime representing the most recent time at which the status + being indicated is known by the responder to have been correct. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: next_update + + :type: :class:`datetime.datetime` + + A naïve datetime representing the time when newer information will + be available. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: issuer_key_hash + + :type: bytes + + The hash of the certificate issuer's key. The hash algorithm used + is defined by the ``hash_algorithm`` property. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: issuer_name_hash + + :type: bytes + + The hash of the certificate issuer's name. The hash algorithm used + is defined by the ``hash_algorithm`` property. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: hash_algorithm + + :type: :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + + The algorithm used to generate the ``issuer_key_hash`` and + ``issuer_name_hash``. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: serial_number + + :type: int + + The serial number of the certificate that was checked. + + :raises ValueError: If ``response_status`` is not + :class:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL`. + + .. attribute:: extensions + + :type: :class:`~cryptography.x509.Extensions` + + The extensions encoded in the response. + + .. method:: public_bytes(encoding) + + :param encoding: The encoding to use. Only + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER` + is supported. + + :return bytes: The serialized OCSP response. + +.. class:: OCSPResponseStatus + + .. versionadded:: 2.4 + + An enumeration of response statuses. + + .. attribute:: SUCCESSFUL + + Represents a successful OCSP response. + + .. attribute:: MALFORMED_REQUEST + + May be returned by an OCSP responder that is unable to parse a + given request. + + .. attribute:: INTERNAL_ERROR + + May be returned by an OCSP responder that is currently experiencing + operational problems. + + .. attribute:: TRY_LATER + + May be returned by an OCSP responder that is overloaded. + + .. attribute:: SIG_REQUIRED + + May be returned by an OCSP responder that requires signed OCSP + requests. + + .. attribute:: UNAUTHORIZED + + May be returned by an OCSP responder when queried for a certificate for + which the responder is unaware or an issuer for which the responder is + not authoritative. + + +.. class:: OCSPCertStatus + + .. versionadded:: 2.4 + + An enumeration of certificate statuses in an OCSP response. + + .. attribute:: GOOD + + The value for a certificate that is not revoked. + + .. attribute:: REVOKED + + The certificate being checked is revoked. + + .. attribute:: UNKNOWN + + The certificate being checked is not known to the OCSP responder. + +.. class:: OCSPResponderEncoding + + .. versionadded:: 2.4 + + An enumeration of ``responderID`` encodings that can be passed to + :meth:`~cryptography.x509.ocsp.OCSPResponseBuilder.responder_id`. + + .. attribute:: HASH + + Encode the hash of the public key whose corresponding private key + signed the response. + + .. attribute:: NAME + + Encode the X.509 ``Name`` of the certificate whose private key signed + the response. diff -Nru python-cryptography-2.1.4/docs/x509/reference.rst python-cryptography-2.6.1/docs/x509/reference.rst --- python-cryptography-2.1.4/docs/x509/reference.rst 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/docs/x509/reference.rst 2019-02-27 23:27:53.000000000 +0000 @@ -101,6 +101,53 @@ -----END CERTIFICATE----- """.strip() + pem_issuer_public_key = b""" + -----BEGIN RSA PUBLIC KEY----- + MIICCgKCAgEAyYcqyuT6oQxpvg/VSn2Zc68wZ823D0VAJ2woramFx+2KPWB7B7Ot + tVSNRfm0OxJOU3TFAoep54Z2wgOoz0zRmeW6/7gvIuBKp2TW0qZAt3l9sgpE29iw + CsoZQlMrLKiDPzCC6Fptk+YPSST9sqwhWDKK1QvOg68DKRxTpEek1hBpC0XRsnuX + fvJJQqP39vxzpA0PsicI/wrvWX3vO8z+j9+botPerbeamoeHCsc0xgTLyIygWysB + rNskxlzC2U4Kw6mQhGghlLReo1rFsO2/hLTnvLs+Y1lQhnFeOKCx1WVXhzBIyO9B + dVVH5Cinb5wBNKvxbevRf4icdWcwtknmgKf69xj7yvFjt/vft74BB1Y5ltLYFmEb + 0JBxm5MAJfW4YnMQr0AxdjOhjHq4MN7X4ZzwEpJaYJdRmvMsMGN88cyjYPxsaOG+ + dZ/E9MmTjh0gnTjyD4gmsvR/gtTR/XFJ2wkbnnL1RyxNi6j2UW8C7tpNv0TIuArx + 3SHGPZN0WsaKTxZPb0L/ob1WBT0mhiq1GzB431cXgbxyh8EdKk+xSptA3V+ca2V2 + NuXlJIJaOoPMj/qjDW4I/peKGnk9tLknJ0hpRzz11j77pJsV0dGoGKVHIR2oZqT5 + 0ZJJb5DXNbiTnspKLNmBt0YlNiXtlCIPxVUkhL141FuCLc8h6FjD6E0CAwEAAQ== + -----END RSA PUBLIC KEY----- + """.strip() + + pem_data_to_check = b""" + -----BEGIN CERTIFICATE----- + MIIErjCCApagAwIBAgIUUrUZsZrrBmRD2hvRuspp+lPsZXcwDQYJKoZIhvcNAQEN + BQAwETEPMA0GA1UEAwwGSXNzdWVyMB4XDTE4MTAwODEzNDg1NFoXDTE4MTAxODEz + NDg1NFowETEPMA0GA1UEAwwGSXNzdWVyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A + MIICCgKCAgEAyYcqyuT6oQxpvg/VSn2Zc68wZ823D0VAJ2woramFx+2KPWB7B7Ot + tVSNRfm0OxJOU3TFAoep54Z2wgOoz0zRmeW6/7gvIuBKp2TW0qZAt3l9sgpE29iw + CsoZQlMrLKiDPzCC6Fptk+YPSST9sqwhWDKK1QvOg68DKRxTpEek1hBpC0XRsnuX + fvJJQqP39vxzpA0PsicI/wrvWX3vO8z+j9+botPerbeamoeHCsc0xgTLyIygWysB + rNskxlzC2U4Kw6mQhGghlLReo1rFsO2/hLTnvLs+Y1lQhnFeOKCx1WVXhzBIyO9B + dVVH5Cinb5wBNKvxbevRf4icdWcwtknmgKf69xj7yvFjt/vft74BB1Y5ltLYFmEb + 0JBxm5MAJfW4YnMQr0AxdjOhjHq4MN7X4ZzwEpJaYJdRmvMsMGN88cyjYPxsaOG+ + dZ/E9MmTjh0gnTjyD4gmsvR/gtTR/XFJ2wkbnnL1RyxNi6j2UW8C7tpNv0TIuArx + 3SHGPZN0WsaKTxZPb0L/ob1WBT0mhiq1GzB431cXgbxyh8EdKk+xSptA3V+ca2V2 + NuXlJIJaOoPMj/qjDW4I/peKGnk9tLknJ0hpRzz11j77pJsV0dGoGKVHIR2oZqT5 + 0ZJJb5DXNbiTnspKLNmBt0YlNiXtlCIPxVUkhL141FuCLc8h6FjD6E0CAwEAATAN + BgkqhkiG9w0BAQ0FAAOCAgEAVFzNKhEpkH8V8l0NEBAZHNi1e+lcg35fZZ9plqcw + Pvk+6M7LW0KD0QWYQWm/dJme4DFsM7lh5u4/m+H4yS7/RP9pads9YwBudchvGR1c + S4CCrRAmO8/A0vpQJcEwdS7fdYShBsqMrZ2TvzceVn2dvQbxB6pLkK7KIbDPVJA2 + HXFFXe2npHmdc80iTz2ShbdVSvyPvk6vc6NFFCg6lSQFuif3vV0+aYqi6DXv4h92 + 9qAdES8ZLDfDulxyajyPbtF35f2Of99CumP5UzG4RQbvtI8gShuK1YFYe2sWJFE0 + MgSsqGCbl5mcrWxm9YxysRKMZ+Hc4tnkvfmG6GsKtp8u/5pG11XgxXaQl4fZ7JNa + QFuD5gEXkEC1mCnhWlnguJgjQlpKadMOORmVTqG9dNQ6GEsha+XWpinm5L9fEZuA + F88nNyubKLwEl68N7WWWKQlIl4q8Pe5FEp1pd9rLjOW4gzgYBccIfBK3oMC7uFJg + a/9GeOKPiq90UMrCI+CAsIbzuPOaAp3g69JonuDwcs4cu8ui1udxs9q7ox3qSWGZ + G1U/hmwvZH9kfIv5BKIzNLy4oxXPDJ7MZIBsxVxaNv8KUQ/JLtpVJa3oYqEx18+V + JNr8Pr3y61X8pLmJnaCu+ixshiy2gjxXxDFBVEEt1G9JHrSs3R+yvcHxCrM3+ian + Nh4= + -----END CERTIFICATE----- + """.strip() + Loading Certificates ~~~~~~~~~~~~~~~~~~~~ @@ -271,7 +318,7 @@ >>> from cryptography.hazmat.primitives import hashes >>> cert.fingerprint(hashes.SHA256()) - '\x86\xd2\x187Gc\xfc\xe7}[+E9\x8d\xb4\x8f\x10\xe5S\xda\x18u\xbe}a\x03\x08[\xac\xa04?' + b'\x86\xd2\x187Gc\xfc\xe7}[+E9\x8d\xb4\x8f\x10\xe5S\xda\x18u\xbe}a\x03\x08[\xac\xa04?' .. attribute:: serial_number @@ -389,8 +436,8 @@ >>> for ext in cert.extensions: ... print(ext) - , critical=False, value=)> - , critical=False, value=)> + , critical=False, value=)> + , critical=False, value=)> , critical=True, value=)> , critical=False, value=, policy_qualifiers=None)>])>)> , critical=True, value=)> @@ -415,6 +462,32 @@ certificate validation is a complex problem that involves much more than just signature checks. + To validate the signature on a certificate you can do the following. + Note: This only verifies that the certificate was signed with the + private key associated with the public key provided and does not + perform any of the other checks needed for secure certificate + validation. Additionally, this example will only work for RSA public + keys with ``PKCS1v15`` signatures, and so it can't be used for general + purpose signature verification. + + .. doctest:: + + >>> from cryptography.hazmat.primitives.serialization import load_pem_public_key + >>> from cryptography.hazmat.primitives.asymmetric import padding + >>> issuer_public_key = load_pem_public_key(pem_issuer_public_key, default_backend()) + >>> cert_to_check = x509.load_pem_x509_certificate(pem_data_to_check, default_backend()) + >>> issuer_public_key.verify( + ... cert_to_check.signature, + ... cert_to_check.tbs_certificate_bytes, + ... # Depends on the algorithm used to create the certificate + ... padding.PKCS1v15(), + ... cert_to_check.signature_hash_algorithm, + ... ) + + An + :class:`~cryptography.exceptions.InvalidSignature` + exception will be raised if the signature fails to verify. + .. method:: public_bytes(encoding) .. versionadded:: 1.0 @@ -461,7 +534,16 @@ >>> from cryptography.hazmat.primitives import hashes >>> crl.fingerprint(hashes.SHA256()) - 'e\xcf.\xc4:\x83?1\xdc\xf3\xfc\x95\xd7\xb3\x87\xb3\x8e\xf8\xb93!\x87\x07\x9d\x1b\xb4!\xb9\xe4W\xf4\x1f' + b'e\xcf.\xc4:\x83?1\xdc\xf3\xfc\x95\xd7\xb3\x87\xb3\x8e\xf8\xb93!\x87\x07\x9d\x1b\xb4!\xb9\xe4W\xf4\x1f' + + .. method:: get_revoked_certificate_by_serial_number(serial_number) + + .. versionadded:: 2.3 + + :param serial_number: The serial as a Python integer. + :returns: :class:`~cryptography.x509.RevokedCertificate` if the + ``serial_number`` is present in the CRL or ``None`` if it + is not. .. attribute:: signature_hash_algorithm @@ -501,7 +583,7 @@ .. doctest:: >>> crl.issuer - , value=u'US')>, , value=u'cryptography.io')>])> + .. attribute:: next_update @@ -606,7 +688,7 @@ ... x509.NameAttribute(NameOID.COMMON_NAME, u'cryptography.io'), ... ])) >>> builder = builder.not_valid_before(datetime.datetime.today() - one_day) - >>> builder = builder.not_valid_after(datetime.datetime(2018, 8, 2)) + >>> builder = builder.not_valid_after(datetime.datetime.today() + (one_day * 30)) >>> builder = builder.serial_number(x509.random_serial_number()) >>> builder = builder.public_key(public_key) >>> builder = builder.add_extension( @@ -1112,12 +1194,12 @@ get every attribute or you can use :meth:`Name.get_attributes_for_oid` to obtain the specific type you want. Names are sometimes represented as a slash or comma delimited string (e.g. ``/CN=mydomain.com/O=My Org/C=US`` or - ``CN=mydomain.com, O=My Org, C=US``). + ``CN=mydomain.com,O=My Org,C=US``). Technically, a Name is a list of *sets* of attributes, called *Relative Distinguished Names* or *RDNs*, although multi-valued RDNs are rarely encountered. The iteration order of values within a multi-valued RDN is - undefined. If you need to handle multi-valued RDNs, the ``rdns`` property + preserved. If you need to handle multi-valued RDNs, the ``rdns`` property gives access to an ordered list of :class:`RelativeDistinguishedName` objects. @@ -1132,9 +1214,9 @@ 3 >>> for attribute in cert.subject: ... print(attribute) - , value=u'US')> - , value=u'Test Certificates 2011')> - , value=u'Good CA')> + , value='US')> + , value='Test Certificates 2011')> + , value='Good CA')> .. attribute:: rdns @@ -1152,7 +1234,7 @@ .. doctest:: >>> cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME) - [, value=u'Good CA')>] + [, value='Good CA')>] .. method:: public_bytes(backend) @@ -1164,6 +1246,14 @@ :return bytes: The DER encoded name. + .. method:: rfc4514_string() + + .. versionadded:: 2.5 + + :return str: Format the given name as a :rfc:`4514` Distinguished Name + string, for example ``CN=mydomain.com,O=My Org,C=US``. + + .. class:: Version .. versionadded:: 0.7 @@ -1197,13 +1287,21 @@ The value of the attribute. + .. method:: rfc4514_string() + + .. versionadded:: 2.5 + + :return str: Format the given attribute as a :rfc:`4514` Distinguished + Name string. + .. class:: RelativeDistinguishedName(attributes) .. versionadded:: 1.6 A relative distinguished name is a non-empty set of name attributes. The - object is iterable to get every attribute. + object is iterable to get every attribute, preserving the original order. + Passing duplicate attributes to the constructor raises ``ValueError``. .. method:: get_attributes_for_oid(oid) @@ -1212,6 +1310,13 @@ :returns: A list of :class:`NameAttribute` instances that match the OID provided. The list should contain zero or one values. + .. method:: rfc4514_string() + + .. versionadded:: 2.5 + + :return str: Format the given RDN set as a :rfc:`4514` Distinguished + Name string. + .. class:: ObjectIdentifier @@ -1226,6 +1331,7 @@ The dotted string value of the OID (e.g. ``"2.5.4.3"``) + .. _general_name_classes: General Name Classes @@ -1361,7 +1467,7 @@ .. attribute:: value - :type: `bytes` + :type: bytes X.509 Extensions ~~~~~~~~~~~~~~~~ @@ -1713,7 +1819,7 @@ .. attribute:: authority_cert_issuer - :type: :class:`Name` or None + :type: A list of :class:`GeneralName` instances or None The :class:`Name` of the issuer's issuer. @@ -1759,7 +1865,7 @@ >>> from cryptography.hazmat.backends import default_backend >>> issuer_cert = x509.load_pem_x509_certificate(pem_data, default_backend()) >>> x509.AuthorityKeyIdentifier.from_issuer_public_key(issuer_cert.public_key()) - + .. classmethod:: from_issuer_subject_key_identifier(ski) @@ -1790,7 +1896,7 @@ >>> issuer_cert = x509.load_pem_x509_certificate(pem_data, default_backend()) >>> ski = issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier) >>> x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(ski) - + .. class:: SubjectKeyIdentifier(digest) @@ -1837,7 +1943,7 @@ >>> from cryptography.hazmat.backends import default_backend >>> csr = x509.load_pem_x509_csr(pem_req_data, default_backend()) >>> x509.SubjectKeyIdentifier.from_public_key(csr.public_key()) - + .. class:: SubjectAlternativeName(general_names) @@ -1877,7 +1983,7 @@ >>> ext = cert.extensions.get_extension_for_oid(ExtensionOID.SUBJECT_ALTERNATIVE_NAME) >>> # Get the dNSName entries from the SAN extension >>> ext.value.get_values_for_type(x509.DNSName) - [u'www.cryptography.io', u'cryptography.io'] + ['www.cryptography.io', 'cryptography.io'] .. class:: IssuerAlternativeName(general_names) @@ -1934,6 +2040,23 @@ :attr:`~cryptography.x509.oid.ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS`. +.. class:: PrecertPoison() + + .. versionadded:: 2.4 + + This extension indicates that the certificate should not be treated as a + certificate for the purposes of validation, but is instead for submission + to a certificate transparency log in order to obtain SCTs which will be + embedded in a :class:`PrecertificateSignedCertificateTimestamps` extension + on the final certificate. + + .. attribute:: oid + + :type: :class:`ObjectIdentifier` + + Returns :attr:`~cryptography.x509.oid.ExtensionOID.PRECERT_POISON`. + + .. class:: DeltaCRLIndicator(crl_number) .. versionadded:: 2.1 @@ -2219,6 +2342,77 @@ :type: int +.. class:: IssuingDistributionPoint(full_name, relative_name,\ + only_contains_user_certs, only_contains_ca_certs, only_some_reasons,\ + indirect_crl, only_contains_attribute_certs) + + .. versionadded:: 2.5 + + Issuing distribution point is a CRL extension that identifies the CRL + distribution point and scope for a particular CRL. It indicates whether + the CRL covers revocation for end entity certificates only, CA certificates + only, attribute certificates only, or a limited set of reason codes. For + specific details on the way this extension should be processed see + :rfc:`5280`. + + .. attribute:: oid + + :type: :class:`ObjectIdentifier` + + Returns + :attr:`~cryptography.x509.oid.ExtensionOID.ISSUING_DISTRIBUTION_POINT`. + + .. attribute:: only_contains_user_certs + + :type: bool + + Set to ``True`` if the CRL this extension is embedded within only + contains information about user certificates. + + .. attribute:: only_contains_ca_certs + + :type: bool + + Set to ``True`` if the CRL this extension is embedded within only + contains information about CA certificates. + + .. attribute:: indirect_crl + + :type: bool + + Set to ``True`` if the CRL this extension is embedded within includes + certificates issued by one or more authorities other than the CRL + issuer. + + .. attribute:: only_contains_attribute_certs + + :type: bool + + Set to ``True`` if the CRL this extension is embedded within only + contains information about attribute certificates. + + .. attribute:: only_some_reasons + + :type: frozenset of :class:`ReasonFlags` or None + + The reasons for which the issuing distribution point is valid. None + indicates that it is valid for all reasons. + + .. attribute:: full_name + + :type: list of :class:`GeneralName` instances or None + + This field describes methods to retrieve the CRL. At most one of + ``full_name`` or ``relative_name`` will be non-None. + + .. attribute:: relative_name + + :type: :class:`RelativeDistinguishedName` or None + + This field describes methods to retrieve the CRL relative to the CRL + issuer. At most one of ``full_name`` or ``relative_name`` will be + non-None. + .. class:: UnrecognizedExtension .. versionadded:: 1.2 @@ -2234,7 +2428,7 @@ .. attribute:: value - :type: byte + :type: bytes Returns the DER encoded bytes payload of the extension. @@ -2405,6 +2599,30 @@ :type: :class:`datetime.datetime` +OCSP Extensions +~~~~~~~~~~~~~~~ + +.. class:: OCSPNonce(nonce) + + .. versionadded:: 2.4 + + OCSP nonce is an extension that is only valid inside + :class:`~cryptography.x509.ocsp.OCSPRequest` and + :class:`~cryptography.x509.ocsp.OCSPResponse` objects. The nonce + cryptographically binds a request and a response to prevent replay attacks. + In practice nonces are rarely used in OCSP due to the desire to precompute + OCSP responses at large scale. + + .. attribute:: oid + + :type: :class:`ObjectIdentifier` + + Returns + :attr:`~cryptography.x509.oid.OCSPExtensionOID.NONCE`. + + .. attribute:: nonce + + :type: bytes Object Identifiers ~~~~~~~~~~~~~~~~~~ @@ -2569,6 +2787,15 @@ Corresponds to the dotted string ``"1.2.840.113549.1.1.13"``. This is a SHA512 digest signed by an RSA key. + .. attribute:: RSASSA_PSS + + .. versionadded:: 2.3 + + Corresponds to the dotted string ``"1.2.840.113549.1.1.10"``. This is + signed by an RSA key using the Probabilistic Signature Scheme (PSS) + padding from :rfc:`4055`. The hash function and padding are defined by + signature algorithm parameters. + .. attribute:: ECDSA_WITH_SHA1 Corresponds to the dotted string ``"1.2.840.10045.4.1"``. This is a SHA1 @@ -2785,6 +3012,12 @@ Corresponds to the dotted string ``"1.3.6.1.4.1.11129.2.4.2"``. + .. attribute:: PRECERT_POISON + + .. versionadded:: 2.4 + + Corresponds to the dotted string ``"1.3.6.1.4.1.11129.2.4.3"``. + .. attribute:: POLICY_CONSTRAINTS Corresponds to the dotted string ``"2.5.29.36"``. The identifier for the @@ -2795,6 +3028,12 @@ Corresponds to the dotted string ``"2.5.29.46"``. The identifier for the :class:`~cryptography.x509.FreshestCRL` extension type. + .. attribute:: ISSUING_DISTRIBUTION_POINT + + .. versionadded:: 2.4 + + Corresponds to the dotted string ``"2.5.29.28"``. + .. class:: CRLEntryExtensionOID @@ -2812,6 +3051,15 @@ Corresponds to the dotted string ``"2.5.29.24"``. + +.. class:: OCSPExtensionOID + + .. versionadded:: 2.4 + + .. attribute:: NONCE + + Corresponds to the dotted string ``"1.3.6.1.5.5.7.48.1.2"``. + Helper Functions ~~~~~~~~~~~~~~~~ .. currentmodule:: cryptography.x509 diff -Nru python-cryptography-2.1.4/docs/x509/tutorial.rst python-cryptography-2.6.1/docs/x509/tutorial.rst --- python-cryptography-2.1.4/docs/x509/tutorial.rst 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/docs/x509/tutorial.rst 2019-02-27 23:27:53.000000000 +0000 @@ -63,16 +63,16 @@ >>> csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([ ... # Provide various details about who we are. ... x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), - ... x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"CA"), + ... x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"California"), ... x509.NameAttribute(NameOID.LOCALITY_NAME, u"San Francisco"), ... x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"My Company"), ... x509.NameAttribute(NameOID.COMMON_NAME, u"mysite.com"), ... ])).add_extension( ... x509.SubjectAlternativeName([ ... # Describe what sites we want this certificate for. - ... x509.DNSName(b"mysite.com"), - ... x509.DNSName(b"www.mysite.com"), - ... x509.DNSName(b"subdomain.mysite.com"), + ... x509.DNSName(u"mysite.com"), + ... x509.DNSName(u"www.mysite.com"), + ... x509.DNSName(u"subdomain.mysite.com"), ... ]), ... critical=False, ... # Sign the CSR with our private key. @@ -123,7 +123,7 @@ >>> # subject and issuer are always the same. >>> subject = issuer = x509.Name([ ... x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), - ... x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"CA"), + ... x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"California"), ... x509.NameAttribute(NameOID.LOCALITY_NAME, u"San Francisco"), ... x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"My Company"), ... x509.NameAttribute(NameOID.COMMON_NAME, u"mysite.com"), @@ -142,7 +142,7 @@ ... # Our certificate will be valid for 10 days ... datetime.datetime.utcnow() + datetime.timedelta(days=10) ... ).add_extension( - ... x509.SubjectAlternativeName([x509.DNSName(b"localhost")]), + ... x509.SubjectAlternativeName([x509.DNSName(u"localhost")]), ... critical=False, ... # Sign our certificate with our private key ... ).sign(key, hashes.SHA256(), default_backend()) diff -Nru python-cryptography-2.1.4/LICENSE python-cryptography-2.6.1/LICENSE --- python-cryptography-2.1.4/LICENSE 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/LICENSE 2019-02-27 23:27:53.000000000 +0000 @@ -3,5 +3,4 @@ under the terms of *both* these licenses. The code used in the OpenSSL locking callback and OS random engine is derived -from the same in CPython itself, and is licensed under the terms of the PSF -License Agreement. +from CPython, and is licensed under the terms of the PSF License Agreement. diff -Nru python-cryptography-2.1.4/LICENSE.APACHE python-cryptography-2.6.1/LICENSE.APACHE --- python-cryptography-2.1.4/LICENSE.APACHE 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/LICENSE.APACHE 2019-02-27 23:27:53.000000000 +0000 @@ -1,7 +1,7 @@ Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -193,7 +193,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff -Nru python-cryptography-2.1.4/MANIFEST.in python-cryptography-2.6.1/MANIFEST.in --- python-cryptography-2.1.4/MANIFEST.in 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/MANIFEST.in 2019-02-27 23:27:53.000000000 +0000 @@ -6,6 +6,8 @@ include LICENSE.BSD include README.rst +include pyproject.toml + recursive-include docs * recursive-include src/_cffi_src *.py *.c *.h prune docs/_build diff -Nru python-cryptography-2.1.4/PKG-INFO python-cryptography-2.6.1/PKG-INFO --- python-cryptography-2.1.4/PKG-INFO 2017-11-30 01:55:14.000000000 +0000 +++ python-cryptography-2.6.1/PKG-INFO 2019-02-27 23:28:31.000000000 +0000 @@ -1,17 +1,16 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: cryptography -Version: 2.1.4 +Version: 2.6.1 Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers. Home-page: https://github.com/pyca/cryptography Author: The cryptography developers Author-email: cryptography-dev@python.org License: BSD or Apache License, Version 2.0 -Description-Content-Type: UNKNOWN Description: pyca/cryptography ================= .. image:: https://img.shields.io/pypi/v/cryptography.svg - :target: https://pypi.python.org/pypi/cryptography/ + :target: https://pypi.org/project/cryptography/ :alt: Latest Version .. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest @@ -27,7 +26,7 @@ ``cryptography`` is a package which provides cryptographic recipes and primitives to Python developers. Our goal is for it to be your "cryptographic - standard library". It supports Python 2.6-2.7, Python 3.4+, and PyPy 5.3+. + standard library". It supports Python 2.7, Python 3.4+, and PyPy 5.4+. ``cryptography`` includes both high level recipes and low level interfaces to common cryptographic algorithms such as symmetric ciphers, message digests, and @@ -66,13 +65,21 @@ You can also join ``#cryptography-dev`` on Freenode to ask questions or get involved. + Security + ~~~~~~~~ + + Need to report a security issue? Please consult our `security reporting`_ + documentation. + .. _`documentation`: https://cryptography.io/ .. _`the installation documentation`: https://cryptography.io/en/latest/installation/ .. _`issue tracker`: https://github.com/pyca/cryptography/issues .. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev + .. _`security reporting`: https://cryptography.io/en/latest/security/ Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Apache Software License Classifier: License :: OSI Approved :: BSD License @@ -84,12 +91,18 @@ Classifier: Operating System :: Microsoft :: Windows Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Security :: Cryptography +Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.* +Provides-Extra: idna +Provides-Extra: docstest +Provides-Extra: pep8test +Provides-Extra: docs +Provides-Extra: test diff -Nru python-cryptography-2.1.4/pyproject.toml python-cryptography-2.6.1/pyproject.toml --- python-cryptography-2.1.4/pyproject.toml 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/pyproject.toml 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,7 @@ +[build-system] +# Must be kept in sync with `setup_requirements` in `setup.py` +requires = [ + "setuptools>=18.5", + "wheel", + "cffi>=1.8,!=1.11.3; python_implementation != 'PyPy'", +] diff -Nru python-cryptography-2.1.4/README.rst python-cryptography-2.6.1/README.rst --- python-cryptography-2.1.4/README.rst 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/README.rst 2019-02-27 23:27:53.000000000 +0000 @@ -2,7 +2,7 @@ ================= .. image:: https://img.shields.io/pypi/v/cryptography.svg - :target: https://pypi.python.org/pypi/cryptography/ + :target: https://pypi.org/project/cryptography/ :alt: Latest Version .. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest @@ -18,7 +18,7 @@ ``cryptography`` is a package which provides cryptographic recipes and primitives to Python developers. Our goal is for it to be your "cryptographic -standard library". It supports Python 2.6-2.7, Python 3.4+, and PyPy 5.3+. +standard library". It supports Python 2.7, Python 3.4+, and PyPy 5.4+. ``cryptography`` includes both high level recipes and low level interfaces to common cryptographic algorithms such as symmetric ciphers, message digests, and @@ -57,8 +57,15 @@ You can also join ``#cryptography-dev`` on Freenode to ask questions or get involved. +Security +~~~~~~~~ + +Need to report a security issue? Please consult our `security reporting`_ +documentation. + .. _`documentation`: https://cryptography.io/ .. _`the installation documentation`: https://cryptography.io/en/latest/installation/ .. _`issue tracker`: https://github.com/pyca/cryptography/issues .. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev +.. _`security reporting`: https://cryptography.io/en/latest/security/ diff -Nru python-cryptography-2.1.4/setup.py python-cryptography-2.6.1/setup.py --- python-cryptography-2.1.4/setup.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/setup.py 2019-02-27 23:27:53.000000000 +0000 @@ -14,11 +14,21 @@ import pkg_resources +import setuptools from setuptools import find_packages, setup from setuptools.command.install import install from setuptools.command.test import test +if ( + pkg_resources.parse_version(setuptools.__version__) < + pkg_resources.parse_version("18.5") +): + raise RuntimeError( + "cryptography requires setuptools 18.5 or newer, please upgrade to a " + "newer version of setuptools" + ) + base_dir = os.path.dirname(__file__) src_dir = os.path.join(base_dir, "src") @@ -33,25 +43,23 @@ VECTORS_DEPENDENCY = "cryptography_vectors=={0}".format(about['__version__']) -setup_requirements = [] +# `setup_requirements` must be kept in sync with `pyproject.toml` +setup_requirements = ["cffi>=1.8,!=1.11.3"] if platform.python_implementation() == "PyPy": - if sys.pypy_version_info < (5, 3): + if sys.pypy_version_info < (5, 4): raise RuntimeError( - "cryptography 1.9 is not compatible with PyPy < 5.3. Please " - "upgrade PyPy to use this library." + "cryptography is not compatible with PyPy < 5.4. Please upgrade " + "PyPy to use this library." ) -else: - setup_requirements.append("cffi>=1.7") test_requirements = [ - "pytest>=3.2.1,!=3.3.0", + "pytest>=3.6.0,!=3.9.0,!=3.9.1,!=3.9.2", "pretend", "iso8601", "pytz", + "hypothesis>=1.11.4,!=3.79.2", ] -if sys.version_info[:2] > (2, 6): - test_requirements.append("hypothesis>=1.11.4") # If there's no vectors locally that probably means we are in a tarball and @@ -249,6 +257,7 @@ author_email=about["__email__"], classifiers=[ + "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "License :: OSI Approved :: BSD License", @@ -260,12 +269,12 @@ "Operating System :: Microsoft :: Windows", "Programming Language :: Python", "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Security :: Cryptography", @@ -275,30 +284,38 @@ packages=find_packages(where="src", exclude=["_cffi_src", "_cffi_src.*"]), include_package_data=True, + python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*', + install_requires=[ - "idna >= 2.1", "asn1crypto >= 0.21.0", "six >= 1.4.1", - ], + ] + setup_requirements, tests_require=test_requirements, extras_require={ ":python_version < '3'": ["enum34", "ipaddress"], - ":platform_python_implementation != 'PyPy'": ["cffi >= 1.7"], "test": test_requirements, + "docs": [ + "sphinx >= 1.6.5,!=1.8.0", + "sphinx_rtd_theme", + ], "docstest": [ "doc8", "pyenchant >= 1.6.11", - "readme_renderer >= 16.0", - "sphinx", - "sphinx_rtd_theme", - "sphinxcontrib-spelling", + "twine >= 1.12.0", + "sphinxcontrib-spelling >= 4.0.1", ], "pep8test": [ "flake8", "flake8-import-order", "pep8-naming", ], + # This extra is for the U-label support that was deprecated in + # cryptography 2.1. If you need this deprecated path install with + # pip install cryptography[idna] + "idna": [ + "idna >= 2.1", + ] }, # for cffi diff -Nru python-cryptography-2.1.4/src/_cffi_src/build_openssl.py python-cryptography-2.6.1/src/_cffi_src/build_openssl.py --- python-cryptography-2.1.4/src/_cffi_src/build_openssl.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/build_openssl.py 2019-02-27 23:27:53.000000000 +0000 @@ -32,7 +32,7 @@ # In some circumstances, the order in which these libs are # specified on the linker command-line is significant; # libssl must come before libcrypto - # (http://marc.info/?l=openssl-users&m=135361825921871) + # (https://marc.info/?l=openssl-users&m=135361825921871) return ["ssl", "crypto"] @@ -46,7 +46,7 @@ When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 we can revisit this. """ - if platform != "win32": + if platform not in ["win32", "hp-ux11", "sunos5"]: return ["-Wconversion", "-Wno-error=sign-conversion"] else: return [] @@ -64,7 +64,6 @@ "bignum", "bio", "cmac", - "cms", "conf", "crypto", "ct", diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/aes.py python-cryptography-2.6.1/src/_cffi_src/openssl/aes.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/aes.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/aes.py 2019-02-27 23:27:53.000000000 +0000 @@ -9,12 +9,7 @@ """ TYPES = """ -static const int Cryptography_HAS_AES_WRAP; - -struct aes_key_st { - ...; -}; -typedef struct aes_key_st AES_KEY; +typedef ... AES_KEY; """ FUNCTIONS = """ @@ -28,5 +23,4 @@ """ CUSTOMIZATIONS = """ -static const long Cryptography_HAS_AES_WRAP = 1; """ diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/asn1.py python-cryptography-2.6.1/src/_cffi_src/openssl/asn1.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/asn1.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/asn1.py 2019-02-27 23:27:53.000000000 +0000 @@ -11,7 +11,6 @@ TYPES = """ typedef int... time_t; -typedef int ASN1_BOOLEAN; typedef ... ASN1_INTEGER; struct asn1_string_st { @@ -31,33 +30,17 @@ typedef ... ASN1_TYPE; typedef ... ASN1_GENERALIZEDTIME; typedef ... ASN1_ENUMERATED; -typedef ... ASN1_ITEM; -typedef ... ASN1_VALUE; - -typedef ... ASN1_ITEM_EXP; - -typedef ... ASN1_UTCTIME; +typedef ... ASN1_NULL; static const int V_ASN1_GENERALIZEDTIME; -static const int MBSTRING_FLAG; -static const int MBSTRING_ASC; -static const int MBSTRING_BMP; static const int MBSTRING_UTF8; -static const int MBSTRING_UNIV; """ FUNCTIONS = """ -ASN1_OBJECT *ASN1_OBJECT_new(void); void ASN1_OBJECT_free(ASN1_OBJECT *); -/* ASN1 OBJECT IDENTIFIER */ -ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **, const unsigned char **, long); - /* ASN1 STRING */ -ASN1_STRING *ASN1_STRING_new(void); -ASN1_STRING *ASN1_STRING_type_new(int); -void ASN1_STRING_free(ASN1_STRING *); unsigned char *ASN1_STRING_data(ASN1_STRING *); int ASN1_STRING_set(ASN1_STRING *, const void *, int); @@ -70,7 +53,6 @@ ASN1_IA5STRING *ASN1_IA5STRING_new(void); /* ASN1 INTEGER */ -ASN1_INTEGER *ASN1_INTEGER_new(void); void ASN1_INTEGER_free(ASN1_INTEGER *); int ASN1_INTEGER_set(ASN1_INTEGER *, long); @@ -80,29 +62,17 @@ ASN1_TIME *ASN1_TIME_set(ASN1_TIME *, time_t); int ASN1_TIME_set_string(ASN1_TIME *, const char *); -/* ASN1 UTCTIME */ -ASN1_UTCTIME *ASN1_UTCTIME_new(void); -void ASN1_UTCTIME_free(ASN1_UTCTIME *); -int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *, time_t); -ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *, time_t); - /* ASN1 GENERALIZEDTIME */ -int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *, const char *); ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *, time_t); void ASN1_GENERALIZEDTIME_free(ASN1_GENERALIZEDTIME *); -int i2d_ASN1_GENERALIZEDTIME(ASN1_GENERALIZEDTIME *, unsigned char **); /* ASN1 ENUMERATED */ ASN1_ENUMERATED *ASN1_ENUMERATED_new(void); void ASN1_ENUMERATED_free(ASN1_ENUMERATED *); int ASN1_ENUMERATED_set(ASN1_ENUMERATED *, long); -int i2d_ASN1_ENUMERATED(ASN1_ENUMERATED *, unsigned char **); -ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **, const unsigned char **, long, - const ASN1_ITEM *); int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *, int, int); /* These became const ASN1_* in 1.1.0 */ -int i2d_ASN1_OBJECT(ASN1_OBJECT *, unsigned char **); int ASN1_STRING_type(ASN1_STRING *); int ASN1_STRING_to_UTF8(unsigned char **, ASN1_STRING *); long ASN1_ENUMERATED_get(ASN1_ENUMERATED *); @@ -117,41 +87,19 @@ ASN1_BIT_STRING *ASN1_BIT_STRING_new(void); void ASN1_BIT_STRING_free(ASN1_BIT_STRING *); -int i2d_ASN1_BIT_STRING(ASN1_BIT_STRING *, unsigned char **); -int i2d_ASN1_OCTET_STRING(ASN1_OCTET_STRING *, unsigned char **); -int i2d_ASN1_INTEGER(ASN1_INTEGER *, unsigned char **); /* This is not a macro, but is const on some versions of OpenSSL */ int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *, int); -const ASN1_ITEM *ASN1_ITEM_ptr(ASN1_ITEM_EXP *); - -/* These aren't macros these arguments are all const X on openssl > 1.0.x */ -int ASN1_TIME_print(BIO *, ASN1_TIME *); int ASN1_STRING_length(ASN1_STRING *); -ASN1_STRING *ASN1_STRING_dup(ASN1_STRING *); -int ASN1_STRING_cmp(ASN1_STRING *, ASN1_STRING *); -int ASN1_UTCTIME_print(BIO *, ASN1_UTCTIME *); - -ASN1_OCTET_STRING *ASN1_OCTET_STRING_dup(ASN1_OCTET_STRING *); -int ASN1_OCTET_STRING_cmp(ASN1_OCTET_STRING *, ASN1_OCTET_STRING *); - -ASN1_INTEGER *ASN1_INTEGER_dup(ASN1_INTEGER *); -int ASN1_INTEGER_cmp(ASN1_INTEGER *, ASN1_INTEGER *); -long ASN1_INTEGER_get(ASN1_INTEGER *); +int ASN1_STRING_set_default_mask_asc(char *); BIGNUM *ASN1_INTEGER_to_BN(ASN1_INTEGER *, BIGNUM *); ASN1_INTEGER *BN_to_ASN1_INTEGER(BIGNUM *, ASN1_INTEGER *); -/* These isn't a macro the arg is const on openssl 1.0.2+ */ -int ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *); -int ASN1_UTCTIME_check(ASN1_UTCTIME *); -int ASN1_TIME_check(ASN1_TIME *); - -/* Not a macro, const on openssl 1.0 */ -int ASN1_STRING_set_default_mask_asc(char *); - int i2d_ASN1_TYPE(ASN1_TYPE *, unsigned char **); ASN1_TYPE *d2i_ASN1_TYPE(ASN1_TYPE **, const unsigned char **, long); + +ASN1_NULL *ASN1_NULL_new(void); """ CUSTOMIZATIONS = """ diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/bignum.py python-cryptography-2.6.1/src/_cffi_src/openssl/bignum.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/bignum.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/bignum.py 2019-02-27 23:27:53.000000000 +0000 @@ -10,13 +10,21 @@ TYPES = """ typedef ... BN_CTX; +typedef ... BN_MONT_CTX; typedef ... BIGNUM; typedef int... BN_ULONG; """ FUNCTIONS = """ +#define BN_FLG_CONSTTIME ... + +void BN_set_flags(BIGNUM *, int); + BIGNUM *BN_new(void); void BN_free(BIGNUM *); +void BN_clear_free(BIGNUM *); + +int BN_rand_range(BIGNUM *, const BIGNUM *); BN_CTX *BN_CTX_new(void); void BN_CTX_free(BN_CTX *); @@ -25,17 +33,18 @@ BIGNUM *BN_CTX_get(BN_CTX *); void BN_CTX_end(BN_CTX *); -BIGNUM *BN_copy(BIGNUM *, const BIGNUM *); +BN_MONT_CTX *BN_MONT_CTX_new(void); +int BN_MONT_CTX_set(BN_MONT_CTX *, const BIGNUM *, BN_CTX *); +void BN_MONT_CTX_free(BN_MONT_CTX *); + BIGNUM *BN_dup(const BIGNUM *); int BN_set_word(BIGNUM *, BN_ULONG); -BN_ULONG BN_get_word(const BIGNUM *); const BIGNUM *BN_value_one(void); char *BN_bn2hex(const BIGNUM *); int BN_hex2bn(BIGNUM **, const char *); -int BN_dec2bn(BIGNUM **, const char *); int BN_bn2bin(const BIGNUM *, unsigned char *); BIGNUM *BN_bin2bn(const unsigned char *, int, BIGNUM *); @@ -45,9 +54,6 @@ int BN_cmp(const BIGNUM *, const BIGNUM *); int BN_add(BIGNUM *, const BIGNUM *, const BIGNUM *); int BN_sub(BIGNUM *, const BIGNUM *, const BIGNUM *); -int BN_mul(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); -int BN_sqr(BIGNUM *, const BIGNUM *, BN_CTX *); -int BN_div(BIGNUM *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int BN_nnmod(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int BN_mod_add(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); @@ -55,31 +61,23 @@ BN_CTX *); int BN_mod_mul(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); -int BN_mod_sqr(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); -int BN_exp(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int BN_mod_exp(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); -int BN_gcd(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); +int BN_mod_exp_mont(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *, + BN_CTX *, BN_MONT_CTX *); +int BN_mod_exp_mont_consttime(BIGNUM *, const BIGNUM *, const BIGNUM *, + const BIGNUM *, BN_CTX *, BN_MONT_CTX *); BIGNUM *BN_mod_inverse(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); -int BN_set_bit(BIGNUM *, int); -int BN_clear_bit(BIGNUM *, int); - -int BN_is_bit_set(const BIGNUM *, int); - -int BN_mask_bits(BIGNUM *, int); - int BN_num_bytes(const BIGNUM *); -int BN_zero(BIGNUM *); -int BN_one(BIGNUM *); int BN_mod(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); -int BN_lshift(BIGNUM *, const BIGNUM *, int); -int BN_lshift1(BIGNUM *, BIGNUM *); - -int BN_rshift(BIGNUM *, BIGNUM *, int); -int BN_rshift1(BIGNUM *, BIGNUM *); +/* The following 3 prime methods are exposed for Tribler. */ +int BN_generate_prime_ex(BIGNUM *, int, int, const BIGNUM *, + const BIGNUM *, BN_GENCB *); +int BN_is_prime_ex(const BIGNUM *, int, BN_CTX *, BN_GENCB *); +const int BN_prime_checks_for_size(int); """ CUSTOMIZATIONS = """ diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/bio.py python-cryptography-2.6.1/src/_cffi_src/openssl/bio.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/bio.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/bio.py 2019-02-27 23:27:53.000000000 +0000 @@ -9,133 +9,38 @@ """ TYPES = """ -typedef struct bio_st BIO; -typedef void bio_info_cb(BIO *, int, const char *, int, long, long); -typedef ... bio_st; +typedef ... BIO; typedef ... BIO_METHOD; -typedef ... BUF_MEM; - -static const int BIO_TYPE_MEM; -static const int BIO_TYPE_FILE; -static const int BIO_TYPE_FD; -static const int BIO_TYPE_SOCKET; -static const int BIO_TYPE_CONNECT; -static const int BIO_TYPE_ACCEPT; -static const int BIO_TYPE_NULL; -static const int BIO_CLOSE; -static const int BIO_NOCLOSE; -static const int BIO_TYPE_SOURCE_SINK; -static const int BIO_CTRL_RESET; -static const int BIO_CTRL_EOF; -static const int BIO_CTRL_SET; -static const int BIO_CTRL_SET_CLOSE; -static const int BIO_CTRL_FLUSH; -static const int BIO_CTRL_DUP; -static const int BIO_CTRL_GET_CLOSE; -static const int BIO_CTRL_INFO; -static const int BIO_CTRL_GET; -static const int BIO_CTRL_PENDING; -static const int BIO_CTRL_WPENDING; -static const int BIO_C_FILE_SEEK; -static const int BIO_C_FILE_TELL; -static const int BIO_TYPE_NONE; -static const int BIO_TYPE_NBIO_TEST; -static const int BIO_TYPE_BIO; -static const int BIO_TYPE_DESCRIPTOR; -static const int BIO_FLAGS_READ; -static const int BIO_FLAGS_WRITE; -static const int BIO_FLAGS_IO_SPECIAL; -static const int BIO_FLAGS_RWS; -static const int BIO_FLAGS_SHOULD_RETRY; -static const int BIO_TYPE_NULL_FILTER; -static const int BIO_TYPE_SSL; -static const int BIO_TYPE_MD; -static const int BIO_TYPE_BUFFER; -static const int BIO_TYPE_CIPHER; -static const int BIO_TYPE_BASE64; -static const int BIO_TYPE_FILTER; """ FUNCTIONS = """ int BIO_free(BIO *); -void BIO_vfree(BIO *); -void BIO_free_all(BIO *); -BIO *BIO_push(BIO *, BIO *); -BIO *BIO_pop(BIO *); -BIO *BIO_next(BIO *); -BIO *BIO_find_type(BIO *, int); BIO *BIO_new_file(const char *, const char *); -BIO *BIO_new_fp(FILE *, int); -BIO *BIO_new_fd(int, int); -BIO *BIO_new_socket(int, int); -long BIO_ctrl(BIO *, int, long, void *); -long BIO_callback_ctrl( - BIO *, - int, - void (*)(struct bio_st *, int, const char *, int, long, long) -); -long BIO_int_ctrl(BIO *, int, long, int); +BIO *BIO_new_dgram(int, int); size_t BIO_ctrl_pending(BIO *); -size_t BIO_ctrl_wpending(BIO *); int BIO_read(BIO *, void *, int); int BIO_gets(BIO *, char *, int); int BIO_write(BIO *, const void *, int); -int BIO_puts(BIO *, const char *); -int BIO_method_type(const BIO *); /* Added in 1.1.0 */ int BIO_up_ref(BIO *); -/* These added const to BIO_METHOD in 1.1.0 */ BIO *BIO_new(BIO_METHOD *); BIO_METHOD *BIO_s_mem(void); -BIO_METHOD *BIO_s_file(void); -BIO_METHOD *BIO_s_fd(void); -BIO_METHOD *BIO_s_socket(void); -BIO_METHOD *BIO_s_null(void); -BIO_METHOD *BIO_f_null(void); -BIO_METHOD *BIO_f_buffer(void); -/* BIO_new_mem_buf became const void * in 1.0.2g */ -BIO *BIO_new_mem_buf(void *, int); -long BIO_set_fd(BIO *, int, long); -long BIO_get_fd(BIO *, char *); +BIO_METHOD *BIO_s_datagram(void); +BIO *BIO_new_mem_buf(const void *, int); long BIO_set_mem_eof_return(BIO *, int); long BIO_get_mem_data(BIO *, char **); -long BIO_set_mem_buf(BIO *, BUF_MEM *, int); -long BIO_get_mem_ptr(BIO *, BUF_MEM **); -long BIO_set_fp(BIO *, FILE *, int); -long BIO_get_fp(BIO *, FILE **); -long BIO_read_filename(BIO *, char *); -long BIO_write_filename(BIO *, char *); -long BIO_append_filename(BIO *, char *); -long BIO_rw_filename(BIO *, char *); int BIO_should_read(BIO *); int BIO_should_write(BIO *); int BIO_should_io_special(BIO *); -int BIO_retry_type(BIO *); int BIO_should_retry(BIO *); int BIO_reset(BIO *); -int BIO_seek(BIO *, int); -int BIO_tell(BIO *); -int BIO_flush(BIO *); -int BIO_eof(BIO *); -int BIO_set_close(BIO *,long); -int BIO_get_close(BIO *); -int BIO_pending(BIO *); -int BIO_wpending(BIO *); -int BIO_get_info_callback(BIO *, bio_info_cb **); -int BIO_set_info_callback(BIO *, bio_info_cb *); -long BIO_get_buffer_num_lines(BIO *); -long BIO_set_read_buffer_size(BIO *, long); -long BIO_set_write_buffer_size(BIO *, long); -long BIO_set_buffer_size(BIO *, long); -long BIO_set_buffer_read_data(BIO *, void *, long); -long BIO_set_nbio(BIO *, long); void BIO_set_retry_read(BIO *); void BIO_clear_retry_flags(BIO *); """ CUSTOMIZATIONS = """ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110PRE4 +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER int BIO_up_ref(BIO *b) { CRYPTO_add(&b->references, 1, CRYPTO_LOCK_BIO); return 1; diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/callbacks.py python-cryptography-2.6.1/src/_cffi_src/openssl/callbacks.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/callbacks.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/callbacks.py 2019-02-27 23:27:53.000000000 +0000 @@ -11,7 +11,10 @@ #include #ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN #include +#include +#include #else #include #include @@ -30,7 +33,7 @@ """ FUNCTIONS = """ -int _setup_ssl_threads(void); +int Cryptography_setup_ssl_threads(void); int Cryptography_pem_password_cb(char *, int, int, void *); """ @@ -44,6 +47,7 @@ using CPython APIs by Armin Rigo of the PyPy project. */ +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 #ifdef _WIN32 typedef CRITICAL_SECTION Cryptography_mutex; static __inline void cryptography_mutex_init(Cryptography_mutex *mutex) { @@ -77,7 +81,6 @@ #endif - static unsigned int _ssl_locks_count = 0; static Cryptography_mutex *_ssl_locks = NULL; @@ -117,7 +120,7 @@ } -int _setup_ssl_threads(void) { +int Cryptography_setup_ssl_threads(void) { if (_ssl_locks == NULL) { _ssl_locks_count = CRYPTO_num_locks(); _ssl_locks = calloc(_ssl_locks_count, sizeof(Cryptography_mutex)); @@ -132,6 +135,9 @@ } return 1; } +#else +int (*Cryptography_setup_ssl_threads)(void) = NULL; +#endif typedef struct { char *password; diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/cmac.py python-cryptography-2.6.1/src/_cffi_src/openssl/cmac.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/cmac.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/cmac.py 2019-02-27 23:27:53.000000000 +0000 @@ -11,7 +11,6 @@ """ TYPES = """ -static const int Cryptography_HAS_CMAC; typedef ... CMAC_CTX; """ @@ -25,5 +24,4 @@ """ CUSTOMIZATIONS = """ -static const long Cryptography_HAS_CMAC = 1; """ diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/cms.py python-cryptography-2.6.1/src/_cffi_src/openssl/cms.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/cms.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/cms.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import absolute_import, division, print_function - -INCLUDES = """ -#if !defined(OPENSSL_NO_CMS) -#include -#endif -""" - -TYPES = """ -static const long Cryptography_HAS_CMS; -static const long Cryptography_HAS_CMS_BIO_FUNCTIONS; - -typedef ... CMS_ContentInfo; -typedef ... CMS_SignerInfo; -typedef ... CMS_CertificateChoices; -typedef ... CMS_RevocationInfoChoice; -typedef ... CMS_RecipientInfo; -typedef ... CMS_ReceiptRequest; -typedef ... CMS_Receipt; - -static const int CMS_TEXT; -static const int CMS_NOCERTS; -static const int CMS_NO_CONTENT_VERIFY; -static const int CMS_NO_ATTR_VERIFY; -static const int CMS_NOSIGS; -static const int CMS_NOINTERN; -static const int CMS_NO_SIGNER_CERT_VERIFY; -static const int CMS_NOVERIFY; -static const int CMS_DETACHED; -static const int CMS_BINARY; -static const int CMS_NOATTR; -static const int CMS_NOSMIMECAP; -static const int CMS_NOOLDMIMETYPE; -static const int CMS_CRLFEOL; -static const int CMS_STREAM; -static const int CMS_NOCRL; -static const int CMS_PARTIAL; -static const int CMS_REUSE_DIGEST; -static const int CMS_USE_KEYID; -static const int CMS_DEBUG_DECRYPT; -""" - -FUNCTIONS = """ -BIO *BIO_new_CMS(BIO *, CMS_ContentInfo *); -int i2d_CMS_bio_stream(BIO *, CMS_ContentInfo *, BIO *, int); -int PEM_write_bio_CMS_stream(BIO *, CMS_ContentInfo *, BIO *, int); -int CMS_final(CMS_ContentInfo *, BIO *, BIO *, unsigned int); -CMS_ContentInfo *CMS_sign(X509 *, EVP_PKEY *, Cryptography_STACK_OF_X509 *, - BIO *, unsigned int); -int CMS_verify(CMS_ContentInfo *, Cryptography_STACK_OF_X509 *, X509_STORE *, - BIO *, BIO *, unsigned int); -CMS_ContentInfo *CMS_encrypt(Cryptography_STACK_OF_X509 *, BIO *, - const EVP_CIPHER *, unsigned int); -int CMS_decrypt(CMS_ContentInfo *, EVP_PKEY *, X509 *, BIO *, BIO *, - unsigned int); -CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *, X509 *, EVP_PKEY *, - const EVP_MD *, unsigned int); -""" - -CUSTOMIZATIONS = """ -#if !defined(OPENSSL_NO_CMS) -static const long Cryptography_HAS_CMS = 1; -static const long Cryptography_HAS_CMS_BIO_FUNCTIONS = 1; -#else -static const long Cryptography_HAS_CMS = 0; -static const long Cryptography_HAS_CMS_BIO_FUNCTIONS = 0; -typedef void CMS_ContentInfo; -typedef void CMS_SignerInfo; -typedef void CMS_CertificateChoices; -typedef void CMS_RevocationInfoChoice; -typedef void CMS_RecipientInfo; -typedef void CMS_ReceiptRequest; -typedef void CMS_Receipt; -const long CMS_TEXT = 0; -const long CMS_NOCERTS = 0; -const long CMS_NO_CONTENT_VERIFY = 0; -const long CMS_NO_ATTR_VERIFY = 0; -const long CMS_NOSIGS = 0; -const long CMS_NOINTERN = 0; -const long CMS_NO_SIGNER_CERT_VERIFY = 0; -const long CMS_NOVERIFY = 0; -const long CMS_DETACHED = 0; -const long CMS_BINARY = 0; -const long CMS_NOATTR = 0; -const long CMS_NOSMIMECAP = 0; -const long CMS_NOOLDMIMETYPE = 0; -const long CMS_CRLFEOL = 0; -const long CMS_STREAM = 0; -const long CMS_NOCRL = 0; -const long CMS_PARTIAL = 0; -const long CMS_REUSE_DIGEST = 0; -const long CMS_USE_KEYID = 0; -const long CMS_DEBUG_DECRYPT = 0; -BIO *(*BIO_new_CMS)(BIO *, CMS_ContentInfo *) = NULL; -int (*i2d_CMS_bio_stream)(BIO *, CMS_ContentInfo *, BIO *, int) = NULL; -int (*PEM_write_bio_CMS_stream)(BIO *, CMS_ContentInfo *, BIO *, int) = NULL; -int (*CMS_final)(CMS_ContentInfo *, BIO *, BIO *, unsigned int) = NULL; -CMS_ContentInfo *(*CMS_sign)(X509 *, EVP_PKEY *, Cryptography_STACK_OF_X509 *, - BIO *, unsigned int) = NULL; -int (*CMS_verify)(CMS_ContentInfo *, Cryptography_STACK_OF_X509 *, - X509_STORE *, BIO *, BIO *, unsigned int) = NULL; -CMS_ContentInfo *(*CMS_encrypt)(Cryptography_STACK_OF_X509 *, BIO *, - const EVP_CIPHER *, unsigned int) = NULL; -int (*CMS_decrypt)(CMS_ContentInfo *, EVP_PKEY *, X509 *, BIO *, BIO *, - unsigned int) = NULL; -CMS_SignerInfo *(*CMS_add1_signer)(CMS_ContentInfo *, X509 *, EVP_PKEY *, - const EVP_MD *, unsigned int) = NULL; -#endif -""" diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/cryptography.py python-cryptography-2.6.1/src/_cffi_src/openssl/cryptography.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/cryptography.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/cryptography.py 2019-02-27 23:27:53.000000000 +0000 @@ -5,6 +5,11 @@ from __future__ import absolute_import, division, print_function INCLUDES = """ +/* define our OpenSSL API compatibility level to 1.0.1. Any symbols older than + that will raise an error during compilation. We can raise this number again + after we drop 1.0.2 support in the distant future. */ +#define OPENSSL_API_COMPAT 0x10001000L + #include @@ -22,7 +27,20 @@ #include #endif #if defined(_WIN32) +#define WIN32_LEAN_AND_MEAN #include +#include +#include +#endif + +#if CRYPTOGRAPHY_IS_LIBRESSL +#define CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER \ + (LIBRESSL_VERSION_NUMBER >= 0x2070000f) +#define CRYPTOGRAPHY_LIBRESSL_28_OR_GREATER \ + (LIBRESSL_VERSION_NUMBER >= 0x2080000f) +#else +#define CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER (0) +#define CRYPTOGRAPHY_LIBRESSL_28_OR_GREATER (0) #endif #define CRYPTOGRAPHY_OPENSSL_102_OR_GREATER \ @@ -40,12 +58,12 @@ (OPENSSL_VERSION_NUMBER < 0x1000209f || CRYPTOGRAPHY_IS_LIBRESSL) #define CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 \ (OPENSSL_VERSION_NUMBER < 0x10100000 || CRYPTOGRAPHY_IS_LIBRESSL) -#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_110PRE4 \ - (OPENSSL_VERSION_NUMBER < 0x10100004 || CRYPTOGRAPHY_IS_LIBRESSL) -#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_110PRE5 \ - (OPENSSL_VERSION_NUMBER < 0x10100005 || CRYPTOGRAPHY_IS_LIBRESSL) -#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_110PRE6 \ - (OPENSSL_VERSION_NUMBER < 0x10100006 || CRYPTOGRAPHY_IS_LIBRESSL) +#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_110J \ + (OPENSSL_VERSION_NUMBER < 0x101000af || CRYPTOGRAPHY_IS_LIBRESSL) +#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 \ + (OPENSSL_VERSION_NUMBER < 0x10101000 || CRYPTOGRAPHY_IS_LIBRESSL) +#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B \ + (OPENSSL_VERSION_NUMBER < 0x10101020 || CRYPTOGRAPHY_IS_LIBRESSL) """ TYPES = """ @@ -55,8 +73,12 @@ static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_102I; static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_102; +static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_111; +static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B; static const int CRYPTOGRAPHY_IS_LIBRESSL; + +static const int CRYPTOGRAPHY_LIBRESSL_28_OR_GREATER; """ FUNCTIONS = """ diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/crypto.py python-cryptography-2.6.1/src/_cffi_src/openssl/crypto.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/crypto.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/crypto.py 2019-02-27 23:27:53.000000000 +0000 @@ -11,6 +11,7 @@ TYPES = """ static const long Cryptography_HAS_LOCKING_CALLBACKS; static const long Cryptography_HAS_MEM_FUNCTIONS; +static const long Cryptography_HAS_OPENSSL_CLEANUP; static const int SSLEAY_VERSION; static const int SSLEAY_CFLAGS; @@ -26,21 +27,15 @@ static const int CRYPTO_MEM_CHECK_OFF; static const int CRYPTO_MEM_CHECK_ENABLE; static const int CRYPTO_MEM_CHECK_DISABLE; -static const int CRYPTO_LOCK; -static const int CRYPTO_UNLOCK; -static const int CRYPTO_READ; -static const int CRYPTO_LOCK_SSL; """ FUNCTIONS = """ int CRYPTO_mem_ctrl(int); -/* CRYPTO_cleanup_all_ex_data became a macro in 1.1.0 */ -void CRYPTO_cleanup_all_ex_data(void); -/* as of 1.1.0 OpenSSL does its own locking *angelic chorus*. These functions - have become macros that are no ops */ -int CRYPTO_num_locks(void); -void CRYPTO_set_locking_callback(void(*)(int, int, const char *, int)); +void OPENSSL_cleanup(void); + +/* as of 1.1.0 OpenSSL does its own locking *angelic chorus*. This function + is now a noop macro. We can delete this once we drop 1.0.2 support. */ void (*CRYPTO_get_locking_callback(void))(int, int, const char *, int); /* SSLeay was removed in 1.1.0 */ @@ -54,8 +49,6 @@ void *OPENSSL_malloc(size_t); void OPENSSL_free(void *); -/* This was removed in 1.1.0 */ -void CRYPTO_lock(int, int, const char *, int); /* Signature changed significantly in 1.1.0, only expose there for sanity */ int Cryptography_CRYPTO_set_mem_functions( @@ -96,22 +89,13 @@ static const long Cryptography_HAS_LOCKING_CALLBACKS = 1; #else static const long Cryptography_HAS_LOCKING_CALLBACKS = 0; -#if !defined(CRYPTO_LOCK) -static const long CRYPTO_LOCK = 0; -#endif -#if !defined(CRYPTO_UNLOCK) -static const long CRYPTO_UNLOCK = 0; -#endif -#if !defined(CRYPTO_READ) -static const long CRYPTO_READ = 0; -#endif -#if !defined(CRYPTO_LOCK_SSL) -static const long CRYPTO_LOCK_SSL = 0; -#endif -void (*CRYPTO_lock)(int, int, const char *, int) = NULL; #endif #if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 +static const long Cryptography_HAS_OPENSSL_CLEANUP = 0; + +void (*OPENSSL_cleanup)(void) = NULL; + /* This function has a significantly different signature pre-1.1.0. since it is * for testing only, we don't bother to expose it on older OpenSSLs. */ @@ -122,6 +106,7 @@ void (*)(void *, const char *, int)) = NULL; #else +static const long Cryptography_HAS_OPENSSL_CLEANUP = 1; static const long Cryptography_HAS_MEM_FUNCTIONS = 1; int Cryptography_CRYPTO_set_mem_functions( @@ -143,6 +128,6 @@ } void Cryptography_free_wrapper(void *ptr, const char *path, int line) { - return free(ptr); + free(ptr); } """ diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/ct.py python-cryptography-2.6.1/src/_cffi_src/openssl/ct.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/ct.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/ct.py 2019-02-27 23:27:53.000000000 +0000 @@ -44,6 +44,8 @@ size_t SCT_get0_log_id(const SCT *, unsigned char **); +size_t SCT_get0_signature(const SCT *, unsigned char **); + uint64_t SCT_get_timestamp(const SCT *); int SCT_set_source(SCT *, sct_source_t); @@ -52,6 +54,14 @@ SCT *sk_SCT_value(const Cryptography_STACK_OF_SCT *, int); void SCT_LIST_free(Cryptography_STACK_OF_SCT *); + +int sk_SCT_push(Cryptography_STACK_OF_SCT *, SCT *); +Cryptography_STACK_OF_SCT *sk_SCT_new_null(void); +SCT *SCT_new(void); +int SCT_set1_log_id(SCT *, unsigned char *, size_t); +void SCT_set_timestamp(SCT *, uint64_t); +int SCT_set_version(SCT *, sct_version_t); +int SCT_set_log_entry_type(SCT *, ct_log_entry_type_t); """ CUSTOMIZATIONS = """ @@ -81,6 +91,7 @@ sct_version_t (*SCT_get_version)(const SCT *) = NULL; ct_log_entry_type_t (*SCT_get_log_entry_type)(const SCT *) = NULL; size_t (*SCT_get0_log_id)(const SCT *, unsigned char **) = NULL; +size_t (*SCT_get0_signature)(const SCT *, unsigned char **) = NULL; uint64_t (*SCT_get_timestamp)(const SCT *) = NULL; int (*SCT_set_source)(SCT *, sct_source_t) = NULL; @@ -89,5 +100,12 @@ SCT *(*sk_SCT_value)(const Cryptography_STACK_OF_SCT *, int) = NULL; void (*SCT_LIST_free)(Cryptography_STACK_OF_SCT *) = NULL; +int (*sk_SCT_push)(Cryptography_STACK_OF_SCT *, SCT *) = NULL; +Cryptography_STACK_OF_SCT *(*sk_SCT_new_null)(void) = NULL; +SCT *(*SCT_new)(void) = NULL; +int (*SCT_set1_log_id)(SCT *, unsigned char *, size_t) = NULL; +void (*SCT_set_timestamp)(SCT *, uint64_t) = NULL; +int (*SCT_set_version)(SCT *, sct_version_t) = NULL; +int (*SCT_set_log_entry_type)(SCT *, ct_log_entry_type_t) = NULL; #endif """ diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/dh.py python-cryptography-2.6.1/src/_cffi_src/openssl/dh.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/dh.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/dh.py 2019-02-27 23:27:53.000000000 +0000 @@ -18,15 +18,8 @@ DH *DH_new(void); void DH_free(DH *); int DH_size(const DH *); -int DH_check_pub_key(const DH *, const BIGNUM *, int *); int DH_generate_key(DH *); int DH_compute_key(unsigned char *, const BIGNUM *, DH *); -int DH_set_ex_data(DH *, int, void *); -void *DH_get_ex_data(DH *, int); -DH *d2i_DHparams(DH **, const unsigned char **, long); -int i2d_DHparams(const DH *, unsigned char **); -int DHparams_print_fp(FILE *, const DH *); -int DHparams_print(BIO *, const DH *); DH *DHparams_dup(DH *); /* added in 1.1.0 when the DH struct was opaqued */ @@ -45,8 +38,8 @@ """ CUSTOMIZATIONS = """ -/* These functions were added in OpenSSL 1.1.0-pre5 (beta2) */ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110PRE5 +/* These functions were added in OpenSSL 1.1.0 */ +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) { diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/dsa.py python-cryptography-2.6.1/src/_cffi_src/openssl/dsa.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/dsa.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/dsa.py 2019-02-27 23:27:53.000000000 +0000 @@ -34,8 +34,8 @@ """ CUSTOMIZATIONS = """ -/* These functions were added in OpenSSL 1.1.0-pre5 (beta2) */ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110PRE5 +/* These functions were added in OpenSSL 1.1.0 */ +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) { diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/ecdh.py python-cryptography-2.6.1/src/_cffi_src/openssl/ecdh.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/ecdh.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/ecdh.py 2019-02-27 23:27:53.000000000 +0000 @@ -9,7 +9,6 @@ """ TYPES = """ -static const int Cryptography_HAS_ECDH; static const int Cryptography_HAS_SET_ECDH_AUTO; """ @@ -20,8 +19,6 @@ """ CUSTOMIZATIONS = """ -static const long Cryptography_HAS_ECDH = 1; - #ifndef SSL_CTX_set_ecdh_auto static const long Cryptography_HAS_SET_ECDH_AUTO = 0; long (*SSL_CTX_set_ecdh_auto)(SSL_CTX *, int) = NULL; diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/ecdsa.py python-cryptography-2.6.1/src/_cffi_src/openssl/ecdsa.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/ecdsa.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/ecdsa.py 2019-02-27 23:27:53.000000000 +0000 @@ -24,14 +24,9 @@ int i2d_ECDSA_SIG(const ECDSA_SIG *, unsigned char **); ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **s, const unsigned char **, long); ECDSA_SIG *ECDSA_do_sign(const unsigned char *, int, EC_KEY *); -ECDSA_SIG *ECDSA_do_sign_ex(const unsigned char *, int, const BIGNUM *, - const BIGNUM *, EC_KEY *); int ECDSA_do_verify(const unsigned char *, int, const ECDSA_SIG *, EC_KEY *); -int ECDSA_sign_setup(EC_KEY *, BN_CTX *, BIGNUM **, BIGNUM **); int ECDSA_sign(int, const unsigned char *, int, unsigned char *, unsigned int *, EC_KEY *); -int ECDSA_sign_ex(int, const unsigned char *, int dgstlen, unsigned char *, - unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *); int ECDSA_verify(int, const unsigned char *, int, const unsigned char *, int, EC_KEY *); int ECDSA_size(const EC_KEY *); diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/ec.py python-cryptography-2.6.1/src/_cffi_src/openssl/ec.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/ec.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/ec.py 2019-02-27 23:27:53.000000000 +0000 @@ -10,7 +10,6 @@ """ TYPES = """ -static const int Cryptography_HAS_EC; static const int Cryptography_HAS_EC2M; static const int Cryptography_HAS_EC_1_0_2; @@ -27,34 +26,16 @@ typedef enum { POINT_CONVERSION_COMPRESSED, POINT_CONVERSION_UNCOMPRESSED, - POINT_CONVERSION_HYBRID, ... } point_conversion_form_t; """ FUNCTIONS = """ -EC_GROUP *EC_GROUP_new(const EC_METHOD *); void EC_GROUP_free(EC_GROUP *); -void EC_GROUP_clear_free(EC_GROUP *); -EC_GROUP *EC_GROUP_new_curve_GFp( - const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); -EC_GROUP *EC_GROUP_new_curve_GF2m( - const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); EC_GROUP *EC_GROUP_new_by_curve_name(int); -int EC_GROUP_set_curve_GFp( - EC_GROUP *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); -int EC_GROUP_get_curve_GFp( - const EC_GROUP *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *); -int EC_GROUP_set_curve_GF2m( - EC_GROUP *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); -int EC_GROUP_get_curve_GF2m( - const EC_GROUP *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *); - int EC_GROUP_get_degree(const EC_GROUP *); -void EC_GROUP_set_asn1_flag(EC_GROUP *, int); -void EC_GROUP_set_point_conversion_form(EC_GROUP *, point_conversion_form_t); const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *); const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *); @@ -65,13 +46,7 @@ EC_KEY *EC_KEY_new(void); void EC_KEY_free(EC_KEY *); -int EC_KEY_get_flags(const EC_KEY *); -void EC_KEY_set_flags(EC_KEY *, int); -void EC_KEY_clear_flags(EC_KEY *, int); EC_KEY *EC_KEY_new_by_curve_name(int); -EC_KEY *EC_KEY_copy(EC_KEY *, EC_KEY *); -EC_KEY *EC_KEY_dup(EC_KEY *); -int EC_KEY_up_ref(EC_KEY *); const EC_GROUP *EC_KEY_get0_group(const EC_KEY *); int EC_GROUP_get_order(const EC_GROUP *, BIGNUM *, BN_CTX *); int EC_KEY_set_group(EC_KEY *, const EC_GROUP *); @@ -79,30 +54,14 @@ int EC_KEY_set_private_key(EC_KEY *, const BIGNUM *); const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *); int EC_KEY_set_public_key(EC_KEY *, const EC_POINT *); -unsigned int EC_KEY_get_enc_flags(const EC_KEY *); -void EC_KEY_set_enc_flags(EC_KEY *eckey, unsigned int); -point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *); -void EC_KEY_set_conv_form(EC_KEY *, point_conversion_form_t); void EC_KEY_set_asn1_flag(EC_KEY *, int); -int EC_KEY_precompute_mult(EC_KEY *, BN_CTX *); int EC_KEY_generate_key(EC_KEY *); -int EC_KEY_check_key(const EC_KEY *); int EC_KEY_set_public_key_affine_coordinates(EC_KEY *, BIGNUM *, BIGNUM *); EC_POINT *EC_POINT_new(const EC_GROUP *); void EC_POINT_free(EC_POINT *); void EC_POINT_clear_free(EC_POINT *); -int EC_POINT_copy(EC_POINT *, const EC_POINT *); EC_POINT *EC_POINT_dup(const EC_POINT *, const EC_GROUP *); -const EC_METHOD *EC_POINT_method_of(const EC_POINT *); - -int EC_POINT_set_to_infinity(const EC_GROUP *, EC_POINT *); - -int EC_POINT_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *, - const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); - -int EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *, - const EC_POINT *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *); int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *, EC_POINT *, const BIGNUM *, const BIGNUM *, BN_CTX *); @@ -129,18 +88,6 @@ int EC_POINT_oct2point(const EC_GROUP *, EC_POINT *, const unsigned char *, size_t, BN_CTX *); -BIGNUM *EC_POINT_point2bn(const EC_GROUP *, const EC_POINT *, - point_conversion_form_t form, BIGNUM *, BN_CTX *); - -EC_POINT *EC_POINT_bn2point(const EC_GROUP *, const BIGNUM *, - EC_POINT *, BN_CTX *); - -char *EC_POINT_point2hex(const EC_GROUP *, const EC_POINT *, - point_conversion_form_t form, BN_CTX *); - -EC_POINT *EC_POINT_hex2point(const EC_GROUP *, const char *, - EC_POINT *, BN_CTX *); - int EC_POINT_add(const EC_GROUP *, EC_POINT *, const EC_POINT *, const EC_POINT *, BN_CTX *); @@ -152,38 +99,18 @@ int EC_POINT_cmp( const EC_GROUP *, const EC_POINT *, const EC_POINT *, BN_CTX *); -int EC_POINT_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *); -int EC_POINTs_make_affine(const EC_GROUP *, size_t, EC_POINT *[], BN_CTX *); - -int EC_POINTs_mul( - const EC_GROUP *, EC_POINT *, const BIGNUM *, - size_t, const EC_POINT *[], const BIGNUM *[], BN_CTX *); - int EC_POINT_mul(const EC_GROUP *, EC_POINT *, const BIGNUM *, const EC_POINT *, const BIGNUM *, BN_CTX *); -int EC_GROUP_precompute_mult(EC_GROUP *, BN_CTX *); -int EC_GROUP_have_precompute_mult(const EC_GROUP *); - -const EC_METHOD *EC_GFp_simple_method(); -const EC_METHOD *EC_GFp_mont_method(); -const EC_METHOD *EC_GFp_nist_method(); - -const EC_METHOD *EC_GF2m_simple_method(); - int EC_METHOD_get_field_type(const EC_METHOD *); const char *EC_curve_nid2nist(int); """ CUSTOMIZATIONS = """ -static const long Cryptography_HAS_EC = 1; - #if defined(OPENSSL_NO_EC2M) static const long Cryptography_HAS_EC2M = 0; -const EC_METHOD *(*EC_GF2m_simple_method)() = NULL; - int (*EC_POINT_set_affine_coordinates_GF2m)(const EC_GROUP *, EC_POINT *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL; @@ -192,21 +119,11 @@ int (*EC_POINT_set_compressed_coordinates_GF2m)(const EC_GROUP *, EC_POINT *, const BIGNUM *, int, BN_CTX *) = NULL; - -int (*EC_GROUP_set_curve_GF2m)( - EC_GROUP *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); - -int (*EC_GROUP_get_curve_GF2m)( - const EC_GROUP *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *); - -EC_GROUP *(*EC_GROUP_new_curve_GF2m)( - const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); #else static const long Cryptography_HAS_EC2M = 1; #endif -#if (!CRYPTOGRAPHY_IS_LIBRESSL && CRYPTOGRAPHY_OPENSSL_LESS_THAN_102) || \ - (CRYPTOGRAPHY_IS_LIBRESSL && LIBRESSL_VERSION_NUMBER < 0x20020002L) +#if (!CRYPTOGRAPHY_IS_LIBRESSL && CRYPTOGRAPHY_OPENSSL_LESS_THAN_102) static const long Cryptography_HAS_EC_1_0_2 = 0; const char *(*EC_curve_nid2nist)(int) = NULL; #else diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/engine.py python-cryptography-2.6.1/src/_cffi_src/openssl/engine.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/engine.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/engine.py 2019-02-27 23:27:53.000000000 +0000 @@ -10,124 +10,41 @@ TYPES = """ typedef ... ENGINE; -typedef ... RSA_METHOD; -typedef ... DSA_METHOD; -typedef ... DH_METHOD; -typedef struct { - int (*bytes)(unsigned char *, int); - int (*pseudorand)(unsigned char *, int); - int (*status)(); - ...; -} RAND_METHOD; -typedef int (*ENGINE_GEN_INT_FUNC_PTR)(ENGINE *); -typedef ... *ENGINE_CTRL_FUNC_PTR; -typedef ... *ENGINE_LOAD_KEY_PTR; -typedef ... *ENGINE_CIPHERS_PTR; -typedef ... *ENGINE_DIGESTS_PTR; -typedef ... ENGINE_CMD_DEFN; -typedef ... UI_METHOD; - -static const unsigned int ENGINE_METHOD_RSA; -static const unsigned int ENGINE_METHOD_DSA; -static const unsigned int ENGINE_METHOD_RAND; -static const unsigned int ENGINE_METHOD_CIPHERS; -static const unsigned int ENGINE_METHOD_DIGESTS; -static const unsigned int ENGINE_METHOD_ALL; -static const unsigned int ENGINE_METHOD_NONE; -static const int ENGINE_R_CONFLICTING_ENGINE_ID; +static const long Cryptography_HAS_ENGINE; """ FUNCTIONS = """ -ENGINE *ENGINE_get_first(void); -ENGINE *ENGINE_get_last(void); -ENGINE *ENGINE_get_next(ENGINE *); -ENGINE *ENGINE_get_prev(ENGINE *); -int ENGINE_add(ENGINE *); -int ENGINE_remove(ENGINE *); ENGINE *ENGINE_by_id(const char *); int ENGINE_init(ENGINE *); int ENGINE_finish(ENGINE *); -void ENGINE_load_builtin_engines(void); -ENGINE *ENGINE_get_default_RSA(void); -ENGINE *ENGINE_get_default_DSA(void); -ENGINE *ENGINE_get_default_DH(void); ENGINE *ENGINE_get_default_RAND(void); -ENGINE *ENGINE_get_cipher_engine(int); -ENGINE *ENGINE_get_digest_engine(int); -int ENGINE_set_default_RSA(ENGINE *); -int ENGINE_set_default_DSA(ENGINE *); -int ENGINE_set_default_DH(ENGINE *); int ENGINE_set_default_RAND(ENGINE *); -int ENGINE_set_default_ciphers(ENGINE *); -int ENGINE_set_default_digests(ENGINE *); -int ENGINE_set_default_string(ENGINE *, const char *); -int ENGINE_set_default(ENGINE *, unsigned int); -unsigned int ENGINE_get_table_flags(void); -void ENGINE_set_table_flags(unsigned int); -int ENGINE_register_RSA(ENGINE *); -void ENGINE_unregister_RSA(ENGINE *); -void ENGINE_register_all_RSA(void); -int ENGINE_register_DSA(ENGINE *); -void ENGINE_unregister_DSA(ENGINE *); -void ENGINE_register_all_DSA(void); -int ENGINE_register_DH(ENGINE *); -void ENGINE_unregister_DH(ENGINE *); -void ENGINE_register_all_DH(void); -int ENGINE_register_RAND(ENGINE *); void ENGINE_unregister_RAND(ENGINE *); -void ENGINE_register_all_RAND(void); -int ENGINE_register_ciphers(ENGINE *); -void ENGINE_unregister_ciphers(ENGINE *); -void ENGINE_register_all_ciphers(void); -int ENGINE_register_digests(ENGINE *); -void ENGINE_unregister_digests(ENGINE *); -void ENGINE_register_all_digests(void); -int ENGINE_register_complete(ENGINE *); -int ENGINE_register_all_complete(void); -int ENGINE_ctrl(ENGINE *, int, long, void *, void (*)(void)); -int ENGINE_cmd_is_executable(ENGINE *, int); int ENGINE_ctrl_cmd(ENGINE *, const char *, long, void *, void (*)(void), int); -int ENGINE_ctrl_cmd_string(ENGINE *, const char *, const char *, int); - -ENGINE *ENGINE_new(void); int ENGINE_free(ENGINE *); -int ENGINE_up_ref(ENGINE *); -int ENGINE_set_id(ENGINE *, const char *); -int ENGINE_set_name(ENGINE *, const char *); -int ENGINE_set_RSA(ENGINE *, const RSA_METHOD *); -int ENGINE_set_DSA(ENGINE *, const DSA_METHOD *); -int ENGINE_set_DH(ENGINE *, const DH_METHOD *); -int ENGINE_set_RAND(ENGINE *, const RAND_METHOD *); -int ENGINE_set_destroy_function(ENGINE *, ENGINE_GEN_INT_FUNC_PTR); -int ENGINE_set_init_function(ENGINE *, ENGINE_GEN_INT_FUNC_PTR); -int ENGINE_set_finish_function(ENGINE *, ENGINE_GEN_INT_FUNC_PTR); -int ENGINE_set_ctrl_function(ENGINE *, ENGINE_CTRL_FUNC_PTR); -int ENGINE_set_load_privkey_function(ENGINE *, ENGINE_LOAD_KEY_PTR); -int ENGINE_set_load_pubkey_function(ENGINE *, ENGINE_LOAD_KEY_PTR); -int ENGINE_set_ciphers(ENGINE *, ENGINE_CIPHERS_PTR); -int ENGINE_set_digests(ENGINE *, ENGINE_DIGESTS_PTR); -int ENGINE_set_flags(ENGINE *, int); -int ENGINE_set_cmd_defns(ENGINE *, const ENGINE_CMD_DEFN *); -const char *ENGINE_get_id(const ENGINE *); const char *ENGINE_get_name(const ENGINE *); -const RSA_METHOD *ENGINE_get_RSA(const ENGINE *); -const DSA_METHOD *ENGINE_get_DSA(const ENGINE *); -const DH_METHOD *ENGINE_get_DH(const ENGINE *); -const RAND_METHOD *ENGINE_get_RAND(const ENGINE *); - -const EVP_CIPHER *ENGINE_get_cipher(ENGINE *, int); -const EVP_MD *ENGINE_get_digest(ENGINE *, int); -int ENGINE_get_flags(const ENGINE *); -const ENGINE_CMD_DEFN *ENGINE_get_cmd_defns(const ENGINE *); -EVP_PKEY *ENGINE_load_private_key(ENGINE *, const char *, UI_METHOD *, void *); -EVP_PKEY *ENGINE_load_public_key(ENGINE *, const char *, UI_METHOD *, void *); -void ENGINE_add_conf_module(void); -/* these became macros in 1.1.0 */ -void ENGINE_load_openssl(void); -void ENGINE_load_dynamic(void); -void ENGINE_cleanup(void); + """ CUSTOMIZATIONS = """ +#ifdef OPENSSL_NO_ENGINE +static const long Cryptography_HAS_ENGINE = 0; + +ENGINE *(*ENGINE_by_id)(const char *) = NULL; +int (*ENGINE_init)(ENGINE *) = NULL; +int (*ENGINE_finish)(ENGINE *) = NULL; +ENGINE *(*ENGINE_get_default_RAND)(void) = NULL; +int (*ENGINE_set_default_RAND)(ENGINE *) = NULL; +void (*ENGINE_unregister_RAND)(ENGINE *) = NULL; +int (*ENGINE_ctrl_cmd)(ENGINE *, const char *, long, void *, + void (*)(void), int) = NULL; + +int (*ENGINE_free)(ENGINE *) = NULL; +const char *(*ENGINE_get_id)(const ENGINE *) = NULL; +const char *(*ENGINE_get_name)(const ENGINE *) = NULL; + +#else +static const long Cryptography_HAS_ENGINE = 1; +#endif """ diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/err.py python-cryptography-2.6.1/src/_cffi_src/openssl/err.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/err.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/err.py 2019-02-27 23:27:53.000000000 +0000 @@ -11,13 +11,7 @@ TYPES = """ static const int Cryptography_HAS_EC_CODES; static const int Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR; - -struct ERR_string_data_st { - unsigned long error; - const char *string; -}; -typedef struct ERR_string_data_st ERR_STRING_DATA; -typedef ... ERR_STATE; +static const int Cryptography_HAS_EVP_R_MEMORY_LIMIT_EXCEEDED; static const int ERR_LIB_DH; static const int ERR_LIB_EVP; @@ -29,35 +23,8 @@ static const int ERR_LIB_SSL; static const int ERR_LIB_X509; -static const int ASN1_F_ASN1_EX_C2I; -static const int ASN1_F_ASN1_FIND_END; -static const int ASN1_F_ASN1_GENERATE_V3; -static const int ASN1_F_ASN1_GET_OBJECT; -static const int ASN1_F_ASN1_ITEM_I2D_FP; -static const int ASN1_F_ASN1_ITEM_PACK; -static const int ASN1_F_ASN1_ITEM_SIGN; -static const int ASN1_F_ASN1_ITEM_UNPACK; -static const int ASN1_F_ASN1_ITEM_VERIFY; -static const int ASN1_F_ASN1_MBSTRING_NCOPY; -static const int ASN1_F_ASN1_TEMPLATE_EX_D2I; -static const int ASN1_F_ASN1_TEMPLATE_NEW; -static const int ASN1_F_ASN1_TEMPLATE_NOEXP_D2I; -static const int ASN1_F_ASN1_TYPE_GET_INT_OCTETSTRING; -static const int ASN1_F_ASN1_TYPE_GET_OCTETSTRING; -static const int ASN1_F_ASN1_VERIFY; -static const int ASN1_F_BITSTR_CB; -static const int ASN1_F_D2I_ASN1_UINTEGER; -static const int ASN1_F_D2I_PRIVATEKEY; -static const int ASN1_F_I2D_DSA_PUBKEY; -static const int ASN1_F_LONG_C2I; -static const int ASN1_F_OID_MODULE_INIT; -static const int ASN1_F_PARSE_TAGGING; -static const int ASN1_F_PKCS5_PBE_SET; -static const int ASN1_F_B64_READ_ASN1; -static const int ASN1_F_B64_WRITE_ASN1; -static const int ASN1_F_SMIME_READ_ASN1; -static const int ASN1_F_SMIME_TEXT; -static const int ASN1_F_ASN1_CHECK_TLEN; +static const int ERR_R_MALLOC_FAILURE; +static const int EVP_R_MEMORY_LIMIT_EXCEEDED; static const int ASN1_R_BOOLEAN_IS_WRONG_LENGTH; static const int ASN1_R_BUFFER_TOO_SMALL; @@ -84,33 +51,9 @@ static const int ASN1_R_NO_MULTIPART_BOUNDARY; static const int ASN1_R_HEADER_TOO_LONG; -static const int DH_F_COMPUTE_KEY; - static const int DH_R_INVALID_PUBKEY; -static const int EVP_F_AES_INIT_KEY; -static const int EVP_F_EVP_CIPHER_CTX_CTRL; -static const int EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH; -static const int EVP_F_EVP_CIPHERINIT_EX; -static const int EVP_F_EVP_DECRYPTFINAL_EX; -static const int EVP_F_EVP_DIGESTINIT_EX; static const int EVP_F_EVP_ENCRYPTFINAL_EX; -static const int EVP_F_EVP_MD_CTX_COPY_EX; -static const int EVP_F_EVP_OPENINIT; -static const int EVP_F_EVP_PBE_ALG_ADD; -static const int EVP_F_EVP_PBE_CIPHERINIT; -static const int EVP_F_EVP_PKCS82PKEY; -static const int EVP_F_EVP_PKEY_COPY_PARAMETERS; -static const int EVP_F_EVP_PKEY_DECRYPT; -static const int EVP_F_EVP_PKEY_ENCRYPT; -static const int EVP_F_EVP_PKEY_NEW; -static const int EVP_F_EVP_SIGNFINAL; -static const int EVP_F_EVP_VERIFYFINAL; -static const int EVP_F_PKCS5_PBE_KEYIVGEN; -static const int EVP_F_PKCS5_V2_PBE_KEYIVGEN; -static const int EVP_F_RC2_MAGIC_TO_METH; -static const int EVP_F_RC5_CTRL; -static const int EVP_F_CAMELLIA_INIT_KEY; static const int EVP_R_AES_KEY_SETUP_FAILED; static const int EVP_R_BAD_DECRYPT; @@ -137,33 +80,8 @@ static const int EVP_R_WRONG_FINAL_BLOCK_LENGTH; static const int EVP_R_CAMELLIA_KEY_SETUP_FAILED; -static const int EC_F_EC_GROUP_NEW_BY_CURVE_NAME; - static const int EC_R_UNKNOWN_GROUP; -static const int PEM_F_D2I_PKCS8PRIVATEKEY_BIO; -static const int PEM_F_D2I_PKCS8PRIVATEKEY_FP; -static const int PEM_F_DO_PK8PKEY; -static const int PEM_F_DO_PK8PKEY_FP; -static const int PEM_F_LOAD_IV; -static const int PEM_F_PEM_ASN1_READ; -static const int PEM_F_PEM_ASN1_READ_BIO; -static const int PEM_F_PEM_ASN1_WRITE; -static const int PEM_F_PEM_ASN1_WRITE_BIO; -static const int PEM_F_PEM_DEF_CALLBACK; -static const int PEM_F_PEM_DO_HEADER; -static const int PEM_F_PEM_GET_EVP_CIPHER_INFO; -static const int PEM_F_PEM_READ; -static const int PEM_F_PEM_READ_BIO; -static const int PEM_F_PEM_READ_BIO_PRIVATEKEY; -static const int PEM_F_PEM_READ_PRIVATEKEY; -static const int PEM_F_PEM_SIGNFINAL; -static const int PEM_F_PEM_WRITE; -static const int PEM_F_PEM_WRITE_BIO; -static const int PEM_F_PEM_X509_INFO_READ; -static const int PEM_F_PEM_X509_INFO_READ_BIO; -static const int PEM_F_PEM_X509_INFO_WRITE_BIO; - static const int PEM_R_BAD_BASE64_DECODE; static const int PEM_R_BAD_DECRYPT; static const int PEM_R_BAD_END_LINE; @@ -180,8 +98,6 @@ static const int PEM_R_UNSUPPORTED_CIPHER; static const int PEM_R_UNSUPPORTED_ENCRYPTION; -static const int PKCS12_F_PKCS12_PBE_CRYPT; - static const int PKCS12_R_PKCS12_CIPHERFINAL_ERROR; static const int RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE; @@ -191,7 +107,6 @@ static const int RSA_R_BLOCK_TYPE_IS_NOT_02; static const int RSA_R_PKCS_DECODING_ERROR; static const int RSA_R_OAEP_DECODING_ERROR; -static const int RSA_F_RSA_SIGN; static const int SSL_TLSEXT_ERR_OK; static const int SSL_TLSEXT_ERR_ALERT_WARNING; @@ -228,37 +143,20 @@ static const int SSL_AD_UNKNOWN_PSK_IDENTITY; static const int X509_R_CERT_ALREADY_IN_HASH_TABLE; +static const int X509_R_KEY_VALUES_MISMATCH; """ FUNCTIONS = """ -char *ERR_error_string(unsigned long, char *); void ERR_error_string_n(unsigned long, char *, size_t); const char *ERR_lib_error_string(unsigned long); const char *ERR_func_error_string(unsigned long); const char *ERR_reason_error_string(unsigned long); -void ERR_print_errors(BIO *); -void ERR_print_errors_fp(FILE *); unsigned long ERR_get_error(void); unsigned long ERR_peek_error(void); unsigned long ERR_peek_last_error(void); -unsigned long ERR_get_error_line(const char **, int *); -unsigned long ERR_peek_error_line(const char **, int *); -unsigned long ERR_peek_last_error_line(const char **, int *); -unsigned long ERR_get_error_line_data(const char **, int *, - const char **, int *); void ERR_clear_error(void); -unsigned long ERR_peek_error_line_data(const char **, - int *, const char **, int *); -unsigned long ERR_peek_last_error_line_data(const char **, - int *, const char **, int *); void ERR_put_error(int, int, int, const char *, int); -void ERR_add_error_data(int, ...); -int ERR_get_next_error_library(void); -ERR_STATE *ERR_get_state(void); -/* ERR_free_strings became a macro in 1.1.0 */ -void ERR_free_strings(void); -unsigned long ERR_PACK(int, int, int); int ERR_GET_LIB(unsigned long); int ERR_GET_FUNC(unsigned long); int ERR_GET_REASON(unsigned long); @@ -274,4 +172,11 @@ static const long Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR = 0; static const long RSA_R_PKCS_DECODING_ERROR = 0; #endif + +#ifdef EVP_R_MEMORY_LIMIT_EXCEEDED +static const long Cryptography_HAS_EVP_R_MEMORY_LIMIT_EXCEEDED = 1; +#else +static const long EVP_R_MEMORY_LIMIT_EXCEEDED = 0; +static const long Cryptography_HAS_EVP_R_MEMORY_LIMIT_EXCEEDED = 0; +#endif """ diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/evp.py python-cryptography-2.6.1/src/_cffi_src/openssl/evp.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/evp.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/evp.py 2019-02-27 23:27:53.000000000 +0000 @@ -21,38 +21,31 @@ static const int EVP_PKEY_DH; static const int EVP_PKEY_DHX; static const int EVP_PKEY_EC; +static const int EVP_PKEY_X25519; +static const int EVP_PKEY_ED25519; +static const int EVP_PKEY_X448; +static const int EVP_PKEY_ED448; static const int EVP_MAX_MD_SIZE; static const int EVP_CTRL_AEAD_SET_IVLEN; static const int EVP_CTRL_AEAD_GET_TAG; static const int EVP_CTRL_AEAD_SET_TAG; -static const int Cryptography_HAS_GCM; -static const int Cryptography_HAS_PBKDF2_HMAC; -static const int Cryptography_HAS_PKEY_CTX; static const int Cryptography_HAS_SCRYPT; static const int Cryptography_HAS_EVP_PKEY_DHX; static const int Cryptography_HAS_EVP_PKEY_get_set_tls_encodedpoint; +static const int Cryptography_HAS_ONESHOT_EVP_DIGEST_SIGN_VERIFY; +static const long Cryptography_HAS_RAW_KEY; +static const long Cryptography_HAS_EVP_DIGESTFINAL_XOF; """ FUNCTIONS = """ const EVP_CIPHER *EVP_get_cipherbyname(const char *); -int EVP_EncryptInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *, - const unsigned char *, const unsigned char *); int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *, int); -int EVP_EncryptUpdate(EVP_CIPHER_CTX *, unsigned char *, int *, - const unsigned char *, int); -int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *); -int EVP_DecryptInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *, - const unsigned char *, const unsigned char *); -int EVP_DecryptUpdate(EVP_CIPHER_CTX *, unsigned char *, int *, - const unsigned char *, int); -int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *); int EVP_CipherInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *, const unsigned char *, const unsigned char *, int); int EVP_CipherUpdate(EVP_CIPHER_CTX *, unsigned char *, int *, const unsigned char *, int); int EVP_CipherFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *); -int EVP_CIPHER_block_size(const EVP_CIPHER *); int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *); EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void); void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *); @@ -63,9 +56,8 @@ int EVP_DigestInit_ex(EVP_MD_CTX *, const EVP_MD *, ENGINE *); int EVP_DigestUpdate(EVP_MD_CTX *, const void *, size_t); int EVP_DigestFinal_ex(EVP_MD_CTX *, unsigned char *, unsigned int *); +int EVP_DigestFinalXOF(EVP_MD_CTX *, unsigned char *, size_t); const EVP_MD *EVP_get_digestbyname(const char *); -const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *); -int EVP_MD_size(const EVP_MD *); EVP_PKEY *EVP_PKEY_new(void); void EVP_PKEY_free(EVP_PKEY *); @@ -89,13 +81,11 @@ int EVP_VerifyFinal(EVP_MD_CTX *, const unsigned char *, unsigned int, EVP_PKEY *); -const EVP_MD *EVP_md5(void); -const EVP_MD *EVP_sha1(void); -const EVP_MD *EVP_ripemd160(void); -const EVP_MD *EVP_sha224(void); -const EVP_MD *EVP_sha256(void); -const EVP_MD *EVP_sha384(void); -const EVP_MD *EVP_sha512(void); +int EVP_DigestSignInit(EVP_MD_CTX *, EVP_PKEY_CTX **, const EVP_MD *, + ENGINE *, EVP_PKEY *); +int EVP_DigestVerifyInit(EVP_MD_CTX *, EVP_PKEY_CTX **, const EVP_MD *, + ENGINE *, EVP_PKEY *); + int PKCS5_PBKDF2_HMAC_SHA1(const char *, int, const unsigned char *, int, int, int, unsigned char *); @@ -117,18 +107,6 @@ int EVP_PKEY_set1_DSA(EVP_PKEY *, DSA *); int EVP_PKEY_set1_DH(EVP_PKEY *, DH *); -int EVP_PKEY_get_attr_count(const EVP_PKEY *); -int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *, int, int); -X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *, int); -X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *, int); -int EVP_PKEY_add1_attr(EVP_PKEY *, X509_ATTRIBUTE *); -int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *, const ASN1_OBJECT *, int, - const unsigned char *, int); -int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *, int, int, - const unsigned char *, int); -int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *, const char *, int, - const unsigned char *, int); - int EVP_PKEY_cmp(const EVP_PKEY *, const EVP_PKEY *); int EVP_PKEY_keygen_init(EVP_PKEY_CTX *); @@ -146,30 +124,25 @@ without worrying about what OpenSSL we're running against. */ EVP_MD_CTX *Cryptography_EVP_MD_CTX_new(void); void Cryptography_EVP_MD_CTX_free(EVP_MD_CTX *); +/* Added in 1.1.1 */ +int EVP_DigestSign(EVP_MD_CTX *, unsigned char *, size_t *, + const unsigned char *, size_t); +int EVP_DigestVerify(EVP_MD_CTX *, const unsigned char *, size_t, + const unsigned char *, size_t); /* Added in 1.1.0 */ size_t EVP_PKEY_get1_tls_encodedpoint(EVP_PKEY *, unsigned char **); int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *, const unsigned char *, size_t); -/* PKCS8_PRIV_KEY_INFO * became const in 1.1.0 */ -EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *); - /* EVP_PKEY * became const in 1.1.0 */ int EVP_PKEY_bits(EVP_PKEY *); -/* became a macro in 1.1.0 */ -void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *); - void OpenSSL_add_all_algorithms(void); int EVP_PKEY_assign_RSA(EVP_PKEY *, RSA *); -int EVP_PKEY_assign_DSA(EVP_PKEY *, DSA *); -int EVP_PKEY_assign_EC_KEY(EVP_PKEY *, EC_KEY *); EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *); int EVP_PKEY_set1_EC_KEY(EVP_PKEY *, EC_KEY *); -int EVP_MD_CTX_block_size(const EVP_MD_CTX *); -int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *); int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *, int, int, void *); int PKCS5_PBKDF2_HMAC(const char *, int, const unsigned char *, int, int, @@ -180,14 +153,16 @@ int EVP_PBE_scrypt(const char *, size_t, const unsigned char *, size_t, uint64_t, uint64_t, uint64_t, uint64_t, unsigned char *, size_t); + +EVP_PKEY *EVP_PKEY_new_raw_private_key(int, ENGINE *, const unsigned char *, + size_t); +EVP_PKEY *EVP_PKEY_new_raw_public_key(int, ENGINE *, const unsigned char *, + size_t); +int EVP_PKEY_get_raw_private_key(const EVP_PKEY *, unsigned char *, size_t *); +int EVP_PKEY_get_raw_public_key(const EVP_PKEY *, unsigned char *, size_t *); """ CUSTOMIZATIONS = """ -const long Cryptography_HAS_GCM = 1; - -const long Cryptography_HAS_PBKDF2_HMAC = 1; -const long Cryptography_HAS_PKEY_CTX = 1; - #ifdef EVP_PKEY_DHX const long Cryptography_HAS_EVP_PKEY_DHX = 1; #else @@ -231,6 +206,29 @@ size_t) = NULL; #endif +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 +static const long Cryptography_HAS_ONESHOT_EVP_DIGEST_SIGN_VERIFY = 0; +static const long Cryptography_HAS_RAW_KEY = 0; +static const long Cryptography_HAS_EVP_DIGESTFINAL_XOF = 0; +int (*EVP_DigestFinalXOF)(EVP_MD_CTX *, unsigned char *, size_t) = NULL; +int (*EVP_DigestSign)(EVP_MD_CTX *, unsigned char *, size_t *, + const unsigned char *tbs, size_t) = NULL; +int (*EVP_DigestVerify)(EVP_MD_CTX *, const unsigned char *, size_t, + const unsigned char *, size_t) = NULL; +EVP_PKEY *(*EVP_PKEY_new_raw_private_key)(int, ENGINE *, const unsigned char *, + size_t) = NULL; +EVP_PKEY *(*EVP_PKEY_new_raw_public_key)(int, ENGINE *, const unsigned char *, + size_t) = NULL; +int (*EVP_PKEY_get_raw_private_key)(const EVP_PKEY *, unsigned char *, + size_t *) = NULL; +int (*EVP_PKEY_get_raw_public_key)(const EVP_PKEY *, unsigned char *, + size_t *) = NULL; +#else +static const long Cryptography_HAS_ONESHOT_EVP_DIGEST_SIGN_VERIFY = 1; +static const long Cryptography_HAS_RAW_KEY = 1; +static const long Cryptography_HAS_EVP_DIGESTFINAL_XOF = 1; +#endif + /* OpenSSL 1.1.0+ does this define for us, but if not present we'll do it */ #if !defined(EVP_CTRL_AEAD_SET_IVLEN) # define EVP_CTRL_AEAD_SET_IVLEN EVP_CTRL_GCM_SET_IVLEN @@ -241,4 +239,31 @@ #if !defined(EVP_CTRL_AEAD_SET_TAG) # define EVP_CTRL_AEAD_SET_TAG EVP_CTRL_GCM_SET_TAG #endif + +/* This is tied to X25519 support so we reuse the Cryptography_HAS_X25519 + conditional to remove it. OpenSSL 1.1.0 didn't have this define, but + 1.1.1 will when it is released. We can remove this in the distant + future when we drop 1.1.0 support. */ +#ifndef EVP_PKEY_X25519 +#define EVP_PKEY_X25519 NID_X25519 +#endif + +/* This is tied to X448 support so we reuse the Cryptography_HAS_X448 + conditional to remove it. OpenSSL 1.1.1 adds this define. We can remove + this in the distant future when we drop 1.1.0 support. */ +#ifndef EVP_PKEY_X448 +#define EVP_PKEY_X448 NID_X448 +#endif + +/* This is tied to ED25519 support so we reuse the Cryptography_HAS_ED25519 + conditional to remove it. */ +#ifndef EVP_PKEY_ED25519 +#define EVP_PKEY_ED25519 NID_ED25519 +#endif + +/* This is tied to ED448 support so we reuse the Cryptography_HAS_ED448 + conditional to remove it. */ +#ifndef EVP_PKEY_ED448 +#define EVP_PKEY_ED448 NID_ED448 +#endif """ diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/nid.py python-cryptography-2.6.1/src/_cffi_src/openssl/nid.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/nid.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/nid.py 2019-02-27 23:27:53.000000000 +0000 @@ -10,217 +10,19 @@ TYPES = """ static const int Cryptography_HAS_X25519; +static const int Cryptography_HAS_X448; +static const int Cryptography_HAS_ED448; +static const int Cryptography_HAS_ED25519; static const int NID_undef; -static const int NID_dsa; -static const int NID_dsaWithSHA; -static const int NID_dsaWithSHA1; -static const int NID_md2; -static const int NID_md4; -static const int NID_md5; -static const int NID_mdc2; -static const int NID_ripemd160; -static const int NID_sha; -static const int NID_sha1; -static const int NID_sha256; -static const int NID_sha384; -static const int NID_sha512; -static const int NID_sha224; -static const int NID_sha; -static const int NID_ecdsa_with_SHA1; -static const int NID_ecdsa_with_SHA224; -static const int NID_ecdsa_with_SHA256; -static const int NID_ecdsa_with_SHA384; -static const int NID_ecdsa_with_SHA512; static const int NID_pbe_WithSHA1And3_Key_TripleDES_CBC; -static const int NID_X9_62_c2pnb163v1; -static const int NID_X9_62_c2pnb163v2; -static const int NID_X9_62_c2pnb163v3; -static const int NID_X9_62_c2pnb176v1; -static const int NID_X9_62_c2tnb191v1; -static const int NID_X9_62_c2tnb191v2; -static const int NID_X9_62_c2tnb191v3; -static const int NID_X9_62_c2onb191v4; -static const int NID_X9_62_c2onb191v5; -static const int NID_X9_62_c2pnb208w1; -static const int NID_X9_62_c2tnb239v1; -static const int NID_X9_62_c2tnb239v2; -static const int NID_X9_62_c2tnb239v3; -static const int NID_X9_62_c2onb239v4; -static const int NID_X9_62_c2onb239v5; -static const int NID_X9_62_c2pnb272w1; -static const int NID_X9_62_c2pnb304w1; -static const int NID_X9_62_c2tnb359v1; -static const int NID_X9_62_c2pnb368w1; -static const int NID_X9_62_c2tnb431r1; -static const int NID_X9_62_prime192v1; -static const int NID_X9_62_prime192v2; -static const int NID_X9_62_prime192v3; -static const int NID_X9_62_prime239v1; -static const int NID_X9_62_prime239v2; -static const int NID_X9_62_prime239v3; -static const int NID_X9_62_prime256v1; -static const int NID_secp112r1; -static const int NID_secp112r2; -static const int NID_secp128r1; -static const int NID_secp128r2; -static const int NID_secp160k1; -static const int NID_secp160r1; -static const int NID_secp160r2; -static const int NID_sect163k1; -static const int NID_sect163r1; -static const int NID_sect163r2; -static const int NID_secp192k1; -static const int NID_secp224k1; -static const int NID_secp224r1; -static const int NID_secp256k1; -static const int NID_secp384r1; -static const int NID_secp521r1; -static const int NID_sect113r1; -static const int NID_sect113r2; -static const int NID_sect131r1; -static const int NID_sect131r2; -static const int NID_sect193r1; -static const int NID_sect193r2; -static const int NID_sect233k1; -static const int NID_sect233r1; -static const int NID_sect239k1; -static const int NID_sect283k1; -static const int NID_sect283r1; -static const int NID_sect409k1; -static const int NID_sect409r1; -static const int NID_sect571k1; -static const int NID_sect571r1; static const int NID_X25519; -static const int NID_wap_wsg_idm_ecid_wtls1; -static const int NID_wap_wsg_idm_ecid_wtls3; -static const int NID_wap_wsg_idm_ecid_wtls4; -static const int NID_wap_wsg_idm_ecid_wtls5; -static const int NID_wap_wsg_idm_ecid_wtls6; -static const int NID_wap_wsg_idm_ecid_wtls7; -static const int NID_wap_wsg_idm_ecid_wtls8; -static const int NID_wap_wsg_idm_ecid_wtls9; -static const int NID_wap_wsg_idm_ecid_wtls10; -static const int NID_wap_wsg_idm_ecid_wtls11; -static const int NID_wap_wsg_idm_ecid_wtls12; -static const int NID_ipsec3; -static const int NID_ipsec4; -static const char *const SN_X9_62_c2pnb163v1; -static const char *const SN_X9_62_c2pnb163v2; -static const char *const SN_X9_62_c2pnb163v3; -static const char *const SN_X9_62_c2pnb176v1; -static const char *const SN_X9_62_c2tnb191v1; -static const char *const SN_X9_62_c2tnb191v2; -static const char *const SN_X9_62_c2tnb191v3; -static const char *const SN_X9_62_c2onb191v4; -static const char *const SN_X9_62_c2onb191v5; -static const char *const SN_X9_62_c2pnb208w1; -static const char *const SN_X9_62_c2tnb239v1; -static const char *const SN_X9_62_c2tnb239v2; -static const char *const SN_X9_62_c2tnb239v3; -static const char *const SN_X9_62_c2onb239v4; -static const char *const SN_X9_62_c2onb239v5; -static const char *const SN_X9_62_c2pnb272w1; -static const char *const SN_X9_62_c2pnb304w1; -static const char *const SN_X9_62_c2tnb359v1; -static const char *const SN_X9_62_c2pnb368w1; -static const char *const SN_X9_62_c2tnb431r1; -static const char *const SN_X9_62_prime192v1; -static const char *const SN_X9_62_prime192v2; -static const char *const SN_X9_62_prime192v3; -static const char *const SN_X9_62_prime239v1; -static const char *const SN_X9_62_prime239v2; -static const char *const SN_X9_62_prime239v3; -static const char *const SN_X9_62_prime256v1; -static const char *const SN_secp112r1; -static const char *const SN_secp112r2; -static const char *const SN_secp128r1; -static const char *const SN_secp128r2; -static const char *const SN_secp160k1; -static const char *const SN_secp160r1; -static const char *const SN_secp160r2; -static const char *const SN_sect163k1; -static const char *const SN_sect163r1; -static const char *const SN_sect163r2; -static const char *const SN_secp192k1; -static const char *const SN_secp224k1; -static const char *const SN_secp224r1; -static const char *const SN_secp256k1; -static const char *const SN_secp384r1; -static const char *const SN_secp521r1; -static const char *const SN_sect113r1; -static const char *const SN_sect113r2; -static const char *const SN_sect131r1; -static const char *const SN_sect131r2; -static const char *const SN_sect193r1; -static const char *const SN_sect193r2; -static const char *const SN_sect233k1; -static const char *const SN_sect233r1; -static const char *const SN_sect239k1; -static const char *const SN_sect283k1; -static const char *const SN_sect283r1; -static const char *const SN_sect409k1; -static const char *const SN_sect409r1; -static const char *const SN_sect571k1; -static const char *const SN_sect571r1; -static const char *const SN_wap_wsg_idm_ecid_wtls1; -static const char *const SN_wap_wsg_idm_ecid_wtls3; -static const char *const SN_wap_wsg_idm_ecid_wtls4; -static const char *const SN_wap_wsg_idm_ecid_wtls5; -static const char *const SN_wap_wsg_idm_ecid_wtls6; -static const char *const SN_wap_wsg_idm_ecid_wtls7; -static const char *const SN_wap_wsg_idm_ecid_wtls8; -static const char *const SN_wap_wsg_idm_ecid_wtls9; -static const char *const SN_wap_wsg_idm_ecid_wtls10; -static const char *const SN_wap_wsg_idm_ecid_wtls11; -static const char *const SN_wap_wsg_idm_ecid_wtls12; -static const char *const SN_ipsec3; -static const char *const SN_ipsec4; +static const int NID_X448; +static const int NID_ED25519; +static const int NID_ED448; -static const int NID_subject_key_identifier; -static const int NID_authority_key_identifier; -static const int NID_policy_constraints; -static const int NID_ext_key_usage; -static const int NID_info_access; -static const int NID_key_usage; static const int NID_subject_alt_name; -static const int NID_issuer_alt_name; -static const int NID_basic_constraints; -static const int NID_issuing_distribution_point; -static const int NID_certificate_issuer; -static const int NID_name_constraints; -static const int NID_crl_distribution_points; -static const int NID_certificate_policies; -static const int NID_inhibit_any_policy; - -static const int NID_private_key_usage_period; -static const int NID_crl_number; static const int NID_crl_reason; -static const int NID_invalidity_date; -static const int NID_delta_crl; -static const int NID_any_policy; -static const int NID_policy_mappings; -static const int NID_target_information; -static const int NID_no_rev_avail; - -static const int NID_commonName; -static const int NID_countryName; -static const int NID_localityName; -static const int NID_stateOrProvinceName; -static const int NID_organizationName; -static const int NID_organizationalUnitName; -static const int NID_serialNumber; -static const int NID_surname; -static const int NID_givenName; -static const int NID_title; -static const int NID_generationQualifier; -static const int NID_dnQualifier; -static const int NID_pseudonym; -static const int NID_domainComponent; -static const int NID_pkcs9_emailAddress; - -static const int NID_ad_OCSP; -static const int NID_ad_ca_issuers; """ FUNCTIONS = """ @@ -233,4 +35,22 @@ #else static const long Cryptography_HAS_X25519 = 1; #endif +#ifndef NID_ED25519 +static const long Cryptography_HAS_ED25519 = 0; +static const int NID_ED25519 = 0; +#else +static const long Cryptography_HAS_ED25519 = 1; +#endif +#ifndef NID_X448 +static const long Cryptography_HAS_X448 = 0; +static const int NID_X448 = 0; +#else +static const long Cryptography_HAS_X448 = 1; +#endif +#ifndef NID_ED448 +static const long Cryptography_HAS_ED448 = 0; +static const int NID_ED448 = 0; +#else +static const long Cryptography_HAS_ED448 = 1; +#endif """ diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/ocsp.py python-cryptography-2.6.1/src/_cffi_src/openssl/ocsp.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/ocsp.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/ocsp.py 2019-02-27 23:27:53.000000000 +0000 @@ -15,12 +15,24 @@ typedef ... OCSP_BASICRESP; typedef ... OCSP_SINGLERESP; typedef ... OCSP_CERTID; +typedef ... OCSP_RESPDATA; +static const long OCSP_NOCERTS; +static const long OCSP_RESPID_KEY; """ FUNCTIONS = """ int OCSP_response_status(OCSP_RESPONSE *); OCSP_BASICRESP *OCSP_response_get1_basic(OCSP_RESPONSE *); int OCSP_BASICRESP_get_ext_count(OCSP_BASICRESP *); +const ASN1_OCTET_STRING *OCSP_resp_get0_signature(const OCSP_BASICRESP *); +Cryptography_STACK_OF_X509 *OCSP_resp_get0_certs(const OCSP_BASICRESP *); +const ASN1_GENERALIZEDTIME *OCSP_resp_get0_produced_at( + const OCSP_BASICRESP *); +const OCSP_CERTID *OCSP_SINGLERESP_get0_id(const OCSP_SINGLERESP *); +int OCSP_resp_get0_id(const OCSP_BASICRESP *, const ASN1_OCTET_STRING **, + const X509_NAME **); +const X509_ALGOR *OCSP_resp_get0_tbs_sigalg(const OCSP_BASICRESP *); +const OCSP_RESPDATA *OCSP_resp_get0_respdata(const OCSP_BASICRESP *); X509_EXTENSION *OCSP_BASICRESP_get_ext(OCSP_BASICRESP *, int); int OCSP_resp_count(OCSP_BASICRESP *); OCSP_SINGLERESP *OCSP_resp_get0(OCSP_BASICRESP *, int); @@ -30,11 +42,16 @@ int OCSP_single_get0_status(OCSP_SINGLERESP *, int *, ASN1_GENERALIZEDTIME **, ASN1_GENERALIZEDTIME **, ASN1_GENERALIZEDTIME **); +int OCSP_REQUEST_get_ext_count(OCSP_REQUEST *); +X509_EXTENSION *OCSP_REQUEST_get_ext(OCSP_REQUEST *, int); int OCSP_request_onereq_count(OCSP_REQUEST *); OCSP_ONEREQ *OCSP_request_onereq_get0(OCSP_REQUEST *, int); int OCSP_ONEREQ_get_ext_count(OCSP_ONEREQ *); X509_EXTENSION *OCSP_ONEREQ_get_ext(OCSP_ONEREQ *, int); OCSP_CERTID *OCSP_onereq_get0_id(OCSP_ONEREQ *); +OCSP_ONEREQ *OCSP_request_add0_id(OCSP_REQUEST *, OCSP_CERTID *); +OCSP_CERTID *OCSP_cert_to_id(const EVP_MD *, const X509 *, const X509 *); +void OCSP_CERTID_free(OCSP_CERTID *); OCSP_BASICRESP *OCSP_BASICRESP_new(void); @@ -44,23 +61,110 @@ ASN1_TIME *); int OCSP_basic_add1_nonce(OCSP_BASICRESP *, unsigned char *, int); int OCSP_basic_add1_cert(OCSP_BASICRESP *, X509 *); -int OCSP_BASICRESP_add1_ext_i2d(OCSP_BASICRESP *, int, void *, int, - unsigned long); +int OCSP_BASICRESP_add_ext(OCSP_BASICRESP *, X509_EXTENSION *, int); int OCSP_basic_sign(OCSP_BASICRESP *, X509 *, EVP_PKEY *, const EVP_MD *, Cryptography_STACK_OF_X509 *, unsigned long); OCSP_RESPONSE *OCSP_response_create(int, OCSP_BASICRESP *); +void OCSP_RESPONSE_free(OCSP_RESPONSE *); OCSP_REQUEST *OCSP_REQUEST_new(void); void OCSP_REQUEST_free(OCSP_REQUEST *); int OCSP_request_add1_nonce(OCSP_REQUEST *, unsigned char *, int); -int OCSP_REQUEST_add1_ext_i2d(OCSP_REQUEST *, int, void *, int, unsigned long); +int OCSP_REQUEST_add_ext(OCSP_REQUEST *, X509_EXTENSION *, int); int OCSP_id_get0_info(ASN1_OCTET_STRING **, ASN1_OBJECT **, ASN1_OCTET_STRING **, ASN1_INTEGER **, OCSP_CERTID *); OCSP_REQUEST *d2i_OCSP_REQUEST_bio(BIO *, OCSP_REQUEST **); OCSP_RESPONSE *d2i_OCSP_RESPONSE_bio(BIO *, OCSP_RESPONSE **); int i2d_OCSP_REQUEST_bio(BIO *, OCSP_REQUEST *); int i2d_OCSP_RESPONSE_bio(BIO *, OCSP_RESPONSE *); +int i2d_OCSP_RESPDATA(OCSP_RESPDATA *, unsigned char **); """ CUSTOMIZATIONS = """ +#if ( \ + CRYPTOGRAPHY_OPENSSL_110_OR_GREATER && \ + CRYPTOGRAPHY_OPENSSL_LESS_THAN_110J \ + ) +/* These structs come from ocsp_lcl.h and are needed to de-opaque the struct + for the getters in OpenSSL 1.1.0 through 1.1.0i */ +struct ocsp_responder_id_st { + int type; + union { + X509_NAME *byName; + ASN1_OCTET_STRING *byKey; + } value; +}; +struct ocsp_response_data_st { + ASN1_INTEGER *version; + OCSP_RESPID responderId; + ASN1_GENERALIZEDTIME *producedAt; + STACK_OF(OCSP_SINGLERESP) *responses; + STACK_OF(X509_EXTENSION) *responseExtensions; +}; +struct ocsp_basic_response_st { + OCSP_RESPDATA tbsResponseData; + X509_ALGOR signatureAlgorithm; + ASN1_BIT_STRING *signature; + STACK_OF(X509) *certs; +}; +#endif + +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 +/* These functions are all taken from ocsp_cl.c in OpenSSL 1.1.0 */ +const OCSP_CERTID *OCSP_SINGLERESP_get0_id(const OCSP_SINGLERESP *single) +{ + return single->certId; +} +const Cryptography_STACK_OF_X509 *OCSP_resp_get0_certs( + const OCSP_BASICRESP *bs) +{ + return bs->certs; +} +int OCSP_resp_get0_id(const OCSP_BASICRESP *bs, + const ASN1_OCTET_STRING **pid, + const X509_NAME **pname) +{ + const OCSP_RESPID *rid = bs->tbsResponseData->responderId; + + if (rid->type == V_OCSP_RESPID_NAME) { + *pname = rid->value.byName; + *pid = NULL; + } else if (rid->type == V_OCSP_RESPID_KEY) { + *pid = rid->value.byKey; + *pname = NULL; + } else { + return 0; + } + return 1; +} +const ASN1_GENERALIZEDTIME *OCSP_resp_get0_produced_at( + const OCSP_BASICRESP* bs) +{ + return bs->tbsResponseData->producedAt; +} +const ASN1_OCTET_STRING *OCSP_resp_get0_signature(const OCSP_BASICRESP *bs) +{ + return bs->signature; +} +#endif + +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110J +const X509_ALGOR *OCSP_resp_get0_tbs_sigalg(const OCSP_BASICRESP *bs) +{ +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 + return bs->signatureAlgorithm; +#else + return &bs->signatureAlgorithm; +#endif +} + +const OCSP_RESPDATA *OCSP_resp_get0_respdata(const OCSP_BASICRESP *bs) +{ +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 + return bs->tbsResponseData; +#else + return &bs->tbsResponseData; +#endif +} +#endif """ diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/pem.py python-cryptography-2.6.1/src/_cffi_src/openssl/pem.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/pem.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/pem.py 2019-02-27 23:27:53.000000000 +0000 @@ -46,17 +46,11 @@ int PEM_write_bio_X509_CRL(BIO *, X509_CRL *); -X509 *PEM_read_bio_X509_AUX(BIO *, X509 **, pem_password_cb *, void *); - PKCS7 *PEM_read_bio_PKCS7(BIO *, PKCS7 **, pem_password_cb *, void *); int PEM_write_bio_PKCS7(BIO *, PKCS7 *); DH *PEM_read_bio_DHparams(BIO *, DH **, pem_password_cb *, void *); -DSA *PEM_read_bio_DSAPrivateKey(BIO *, DSA **, pem_password_cb *, void *); - -RSA *PEM_read_bio_RSAPrivateKey(BIO *, RSA **, pem_password_cb *, void *); - int PEM_write_bio_DSAPrivateKey(BIO *, DSA *, const EVP_CIPHER *, unsigned char *, int, pem_password_cb *, void *); @@ -65,12 +59,8 @@ unsigned char *, int, pem_password_cb *, void *); -DSA *PEM_read_bio_DSA_PUBKEY(BIO *, DSA **, pem_password_cb *, void *); - RSA *PEM_read_bio_RSAPublicKey(BIO *, RSA **, pem_password_cb *, void *); -int PEM_write_bio_DSA_PUBKEY(BIO *, DSA *); - int PEM_write_bio_RSAPublicKey(BIO *, const RSA *); EVP_PKEY *PEM_read_bio_PUBKEY(BIO *, EVP_PKEY **, pem_password_cb *, void *); diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/rand.py python-cryptography-2.6.1/src/_cffi_src/openssl/rand.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/rand.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/rand.py 2019-02-27 23:27:53.000000000 +0000 @@ -13,12 +13,8 @@ """ FUNCTIONS = """ -void RAND_seed(const void *, int); void RAND_add(const void *, int, double); int RAND_status(void); -const char *RAND_file_name(char *, size_t); -int RAND_load_file(const char *, long); -int RAND_write_file(const char *); int RAND_bytes(unsigned char *, int); /* ERR_load_RAND_strings started returning an int in 1.1.0. Unfortunately we can't declare a conditional signature like that. Since it always returns diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/rsa.py python-cryptography-2.6.1/src/_cffi_src/openssl/rsa.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/rsa.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/rsa.py 2019-02-27 23:27:53.000000000 +0000 @@ -12,10 +12,8 @@ typedef ... RSA; typedef ... BN_GENCB; static const int RSA_PKCS1_PADDING; -static const int RSA_SSLV23_PADDING; static const int RSA_NO_PADDING; static const int RSA_PKCS1_OAEP_PADDING; -static const int RSA_X931_PADDING; static const int RSA_PKCS1_PSS_PADDING; static const int RSA_F4; @@ -32,7 +30,6 @@ int RSA_check_key(const RSA *); RSA *RSAPublicKey_dup(RSA *); int RSA_blinding_on(RSA *, BN_CTX *); -void RSA_blinding_off(RSA *); int RSA_public_encrypt(int, const unsigned char *, unsigned char *, RSA *, int); int RSA_private_encrypt(int, const unsigned char *, unsigned char *, @@ -42,14 +39,6 @@ int RSA_private_decrypt(int, const unsigned char *, unsigned char *, RSA *, int); int RSA_print(BIO *, const RSA *, int); -int RSA_verify_PKCS1_PSS(RSA *, const unsigned char *, const EVP_MD *, - const unsigned char *, int); -int RSA_padding_add_PKCS1_PSS(RSA *, unsigned char *, const unsigned char *, - const EVP_MD *, int); -int RSA_padding_add_PKCS1_OAEP(unsigned char *, int, const unsigned char *, - int, const unsigned char *, int); -int RSA_padding_check_PKCS1_OAEP(unsigned char *, int, const unsigned char *, - int, int, const unsigned char *, int); /* added in 1.1.0 when the RSA struct was opaqued */ int RSA_set0_key(RSA *, BIGNUM *, BIGNUM *, BIGNUM *); @@ -86,8 +75,8 @@ int) = NULL; #endif -/* These functions were added in OpenSSL 1.1.0-pre5 (beta2) */ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110PRE5 +/* These functions were added in OpenSSL 1.1.0 */ +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) { /* If the fields n and e in r are NULL, the corresponding input diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/src/osrandom_engine.c python-cryptography-2.6.1/src/_cffi_src/openssl/src/osrandom_engine.c --- python-cryptography-2.1.4/src/_cffi_src/openssl/src/osrandom_engine.c 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/src/osrandom_engine.c 2019-02-27 23:27:53.000000000 +0000 @@ -4,7 +4,7 @@ * macOS >= 10.12 getentropy() * OpenBSD 5.6+ getentropy() * other BSD getentropy() if SYS_getentropy is defined - * Linux 3.4.17+ getrandom() with fallback to /dev/urandom + * Linux 3.17+ getrandom() with fallback to /dev/urandom * other /dev/urandom with cached fd * * The /dev/urandom, getrandom and getentropy code is derived from Python's @@ -13,6 +13,12 @@ * Copyright 2001-2016 Python Software Foundation; All Rights Reserved. */ +#ifdef __linux__ +#include +#endif + +#ifndef OPENSSL_NO_ENGINE +/* OpenSSL has ENGINE support so build the engine. */ static const char *Cryptography_osrandom_engine_id = "osrandom"; /**************************************************************************** @@ -90,9 +96,56 @@ ino_t st_ino; } urandom_cache = { -1 }; +static int open_cloexec(const char *path) { + int open_flags = O_RDONLY; +#ifdef O_CLOEXEC + open_flags |= O_CLOEXEC; +#endif + + int fd = open(path, open_flags); + if (fd == -1) { + return -1; + } + +#ifndef O_CLOEXEC + int flags = fcntl(fd, F_GETFD); + if (flags == -1) { + return -1; + } + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { + return -1; + } +#endif + return fd; +} + +#ifdef __linux__ +/* On Linux, we open("/dev/random") and use poll() to wait until it's readable + * before we read from /dev/urandom, this ensures that we don't read from + * /dev/urandom before the kernel CSPRNG is initialized. This isn't necessary on + * other platforms because they don't have the same _bug_ as Linux does with + * /dev/urandom and early boot. */ +static int wait_on_devrandom(void) { + struct pollfd pfd = {}; + int ret = 0; + int random_fd = open_cloexec("/dev/random"); + if (random_fd < 0) { + return -1; + } + pfd.fd = random_fd; + pfd.events = POLLIN; + pfd.revents = 0; + do { + ret = poll(&pfd, 1, -1); + } while (ret < 0 && (errno == EINTR || errno == EAGAIN)); + close(random_fd); + return ret; +} +#endif + /* return -1 on error */ static int dev_urandom_fd(void) { - int fd, n, flags; + int fd = -1; struct stat st; /* Check that fd still points to the correct device */ @@ -106,25 +159,22 @@ } } if (urandom_cache.fd < 0) { - fd = open("/dev/urandom", O_RDONLY); - if (fd < 0) { +#ifdef __linux__ + if (wait_on_devrandom() < 0) { goto error; } - if (fstat(fd, &st)) { +#endif + + fd = open_cloexec("/dev/urandom"); + if (fd < 0) { goto error; } - /* set CLOEXEC flag */ - flags = fcntl(fd, F_GETFD); - if (flags == -1) { - goto error; - } else if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { + if (fstat(fd, &st)) { goto error; } /* Another thread initialized the fd */ if (urandom_cache.fd >= 0) { - do { - n = close(fd); - } while (n < 0 && errno == EINTR); + close(fd); return urandom_cache.fd; } urandom_cache.st_dev = st.st_dev; @@ -135,9 +185,7 @@ error: if (fd != -1) { - do { - n = close(fd); - } while (n < 0 && errno == EINTR); + close(fd); } ERR_Cryptography_OSRandom_error( CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD, @@ -149,7 +197,7 @@ static int dev_urandom_read(unsigned char *buffer, int size) { int fd; - ssize_t n; + int n; fd = dev_urandom_fd(); if (fd < 0) { @@ -158,7 +206,7 @@ while (size > 0) { do { - n = read(fd, buffer, (size_t)size); + n = (int)read(fd, buffer, (size_t)size); } while (n < 0 && errno == EINTR); if (n <= 0) { @@ -177,7 +225,7 @@ static void dev_urandom_close(void) { if (urandom_cache.fd >= 0) { - int fd, n; + int fd; struct stat st; if (fstat(urandom_cache.fd, &st) @@ -185,9 +233,7 @@ && st.st_ino == urandom_cache.st_ino) { fd = urandom_cache.fd; urandom_cache.fd = -1; - do { - n = close(fd); - } while (n < 0 && errno == EINTR); + close(fd); } } } @@ -219,7 +265,7 @@ } static int osrandom_rand_bytes(unsigned char *buffer, int size) { - size_t len; + int len; int res; switch(getentropy_works) { @@ -230,8 +276,8 @@ case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS: while (size > 0) { /* OpenBSD and macOS restrict maximum buffer size to 256. */ - len = size > 256 ? 256 : (size_t)size; - res = getentropy(buffer, len); + len = size > 256 ? 256 : size; + res = getentropy(buffer, (size_t)len); if (res < 0) { ERR_Cryptography_OSRandom_error( CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES, @@ -281,7 +327,8 @@ if (getrandom_works != CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS) { long n; char dest[1]; - n = syscall(SYS_getrandom, dest, sizeof(dest), GRND_NONBLOCK); + /* if the kernel CSPRNG is not initialized this will block */ + n = syscall(SYS_getrandom, dest, sizeof(dest), 0); if (n == sizeof(dest)) { getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS; } else { @@ -295,15 +342,6 @@ /* Fallback: seccomp prevents syscall */ getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK; break; - case EAGAIN: - /* Failure: Kernel CRPNG has not been seeded yet */ - ERR_Cryptography_OSRandom_error( - CRYPTOGRAPHY_OSRANDOM_F_INIT, - CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_EAGAIN, - __FILE__, __LINE__ - ); - getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED; - break; default: /* EINTR cannot occur for buflen < 256. */ ERR_Cryptography_OSRandom_error( @@ -350,7 +388,7 @@ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS: while (size > 0) { do { - n = syscall(SYS_getrandom, buffer, size, GRND_NONBLOCK); + n = syscall(SYS_getrandom, buffer, size, 0); } while (n < 0 && errno == EINTR); if (n <= 0) { @@ -362,7 +400,7 @@ return 0; } buffer += n; - size -= n; + size -= (int)n; } return 1; } @@ -532,9 +570,6 @@ "Reading from /dev/urandom fd failed."}, {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED), "getrandom() initialization failed."}, - {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_EAGAIN), - "getrandom() initialization failed with EAGAIN. Most likely Kernel " - "CPRNG is not seeded yet."}, {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED), "getrandom() initialization failed with unexpected errno."}, {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED), @@ -605,3 +640,16 @@ return 1; } + +#else +/* If OpenSSL has no ENGINE support then we don't want + * to compile the osrandom engine, but we do need some + * placeholders */ +static const char *Cryptography_osrandom_engine_id = "no-engine-support"; +static const char *Cryptography_osrandom_engine_name = "osrandom_engine disabled due to no engine support"; + +int Cryptography_add_osrandom_engine(void) { + return 0; +} + +#endif diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/src/osrandom_engine.h python-cryptography-2.6.1/src/_cffi_src/openssl/src/osrandom_engine.h --- python-cryptography-2.1.4/src/_cffi_src/openssl/src/osrandom_engine.h 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/src/osrandom_engine.h 2019-02-27 23:27:53.000000000 +0000 @@ -1,3 +1,5 @@ +#ifndef OPENSSL_NO_ENGINE +/* OpenSSL has ENGINE support so include all of this. */ #ifdef _WIN32 #include #else @@ -41,7 +43,7 @@ * to urandom */ #define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY #elif defined(__linux__) && defined(SYS_getrandom) - /* Linux 3.4.17+ */ + /* Linux 3.17+ */ #define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM #else /* Keep this as last entry, fall back to /dev/urandom */ @@ -94,7 +96,7 @@ #define CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED 301 #define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED 400 -#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_EAGAIN 401 #define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED 402 #define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED 403 #define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT 404 +#endif diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/ssl.py python-cryptography-2.6.1/src/_cffi_src/openssl/ssl.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/ssl.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/ssl.py 2019-02-27 23:27:53.000000000 +0000 @@ -17,6 +17,7 @@ static const long Cryptography_HAS_SSL3_METHOD; static const long Cryptography_HAS_TLSv1_1; static const long Cryptography_HAS_TLSv1_2; +static const long Cryptography_HAS_TLSv1_3; static const long Cryptography_HAS_SECURE_RENEGOTIATION; static const long Cryptography_HAS_COMPRESSION; static const long Cryptography_HAS_TLSEXT_STATUS_REQ_CB; @@ -27,6 +28,9 @@ static const long Cryptography_HAS_SSL_CTX_CLEAR_OPTIONS; static const long Cryptography_HAS_DTLS; static const long Cryptography_HAS_GENERIC_DTLS_METHOD; +static const long Cryptography_HAS_SIGALGS; +static const long Cryptography_HAS_PSK; +static const long Cryptography_HAS_CIPHER_DETAILS; /* Internally invented symbol to tell us if SNI is supported */ static const long Cryptography_HAS_TLSEXT_HOSTNAME; @@ -46,6 +50,7 @@ static const long Cryptography_HAS_ALPN; static const long Cryptography_HAS_NEXTPROTONEG; static const long Cryptography_HAS_SET_CERT_CB; +static const long Cryptography_HAS_CUSTOM_EXT; static const long SSL_FILETYPE_PEM; static const long SSL_FILETYPE_ASN1; @@ -64,6 +69,9 @@ static const long SSL_OP_NO_TLSv1; static const long SSL_OP_NO_TLSv1_1; static const long SSL_OP_NO_TLSv1_2; +static const long SSL_OP_NO_TLSv1_3; +static const long SSL_OP_NO_DTLSv1; +static const long SSL_OP_NO_DTLSv1_2; static const long SSL_OP_NO_COMPRESSION; static const long SSL_OP_SINGLE_DH_USE; static const long SSL_OP_EPHEMERAL_RSA; @@ -94,6 +102,7 @@ static const long SSL_VERIFY_FAIL_IF_NO_PEER_CERT; static const long SSL_VERIFY_CLIENT_ONCE; static const long SSL_VERIFY_NONE; +static const long SSL_VERIFY_POST_HANDSHAKE; static const long SSL_SESS_CACHE_OFF; static const long SSL_SESS_CACHE_CLIENT; static const long SSL_SESS_CACHE_SERVER; @@ -145,6 +154,11 @@ typedef ... SSL_CIPHER; typedef ... Cryptography_STACK_OF_SSL_CIPHER; typedef ... COMP_METHOD; + +typedef struct { + const char *name; + unsigned long id; +} SRTP_PROTECTION_PROFILE; """ FUNCTIONS = """ @@ -175,9 +189,13 @@ int SSL_write(SSL *, const void *, int); int SSL_read(SSL *, void *, int); int SSL_peek(SSL *, void *, int); +X509 *SSL_get_certificate(const SSL *); X509 *SSL_get_peer_certificate(const SSL *); int SSL_get_ex_data_X509_STORE_CTX_idx(void); +/* Added in 1.0.2 */ +X509_VERIFY_PARAM *SSL_get0_param(SSL *); + int SSL_use_certificate(SSL *, X509 *); int SSL_use_certificate_ASN1(SSL *, const unsigned char *, int); int SSL_use_certificate_file(SSL *, const char *, int); @@ -186,6 +204,9 @@ int SSL_use_PrivateKey_file(SSL *, const char *, int); int SSL_check_private_key(const SSL *); +int SSL_get_sigalgs(SSL *, int, int *, int *, int *, unsigned char *, + unsigned char *); + Cryptography_STACK_OF_X509 *SSL_get_peer_cert_chain(const SSL *); Cryptography_STACK_OF_X509_NAME *SSL_get_client_CA_list(const SSL *); @@ -219,8 +240,36 @@ int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int); int SSL_CTX_check_private_key(const SSL_CTX *); void SSL_CTX_set_cert_verify_callback(SSL_CTX *, - int (*)(X509_STORE_CTX *,void *), + int (*)(X509_STORE_CTX *, void *), void *); + +void SSL_CTX_set_cookie_generate_cb(SSL_CTX *, + int (*)( + SSL *, + unsigned char *, + unsigned int * + )); +long SSL_CTX_get_read_ahead(SSL_CTX *); +long SSL_CTX_set_read_ahead(SSL_CTX *, long); + +int SSL_CTX_use_psk_identity_hint(SSL_CTX *, const char *); +void SSL_CTX_set_psk_server_callback(SSL_CTX *, + unsigned int (*)( + SSL *, + const char *, + unsigned char *, + unsigned int + )); +void SSL_CTX_set_psk_client_callback(SSL_CTX *, + unsigned int (*)( + SSL *, + const char *, + char *, + unsigned int, + unsigned char *, + unsigned int + )); + int SSL_CTX_set_session_id_context(SSL_CTX *, const unsigned char *, unsigned int); @@ -233,12 +282,23 @@ void SSL_CTX_set_info_callback(SSL_CTX *, void (*)(const SSL *, int, int)); void (*SSL_CTX_get_info_callback(SSL_CTX *))(const SSL *, int, int); +long SSL_CTX_set1_sigalgs_list(SSL_CTX *, const char *); + /* SSL_SESSION */ void SSL_SESSION_free(SSL_SESSION *); /* Information about actually used cipher */ const char *SSL_CIPHER_get_name(const SSL_CIPHER *); int SSL_CIPHER_get_bits(const SSL_CIPHER *, int *); +/* the modern signature of this is uint32_t, but older openssl declared it + as unsigned long. To make our compiler flags happy we'll declare it as a + 64-bit wide value, which should always be safe */ +uint64_t SSL_CIPHER_get_id(const SSL_CIPHER *); +int SSL_CIPHER_is_aead(const SSL_CIPHER *); +int SSL_CIPHER_get_cipher_nid(const SSL_CIPHER *); +int SSL_CIPHER_get_digest_nid(const SSL_CIPHER *); +int SSL_CIPHER_get_kx_nid(const SSL_CIPHER *); +int SSL_CIPHER_get_auth_nid(const SSL_CIPHER *); size_t SSL_get_finished(const SSL *, void *, size_t); size_t SSL_get_peer_finished(const SSL *, void *, size_t); @@ -261,6 +321,10 @@ SSL_SESSION *SSL_get_session(const SSL *); const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *, unsigned int *); +long SSL_SESSION_get_time(const SSL_SESSION *); +long SSL_SESSION_get_timeout(const SSL_SESSION *); +int SSL_SESSION_has_ticket(const SSL_SESSION *); +long SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *); /* not a macro, but older OpenSSLs don't pass the args as const */ char *SSL_CIPHER_description(const SSL_CIPHER *, char *, int); @@ -270,7 +334,6 @@ const COMP_METHOD *SSL_get_current_compression(SSL *); const COMP_METHOD *SSL_get_current_expansion(SSL *); const char *SSL_COMP_get_name(const COMP_METHOD *); -int SSL_CTX_set_client_cert_engine(SSL_CTX *, ENGINE *); unsigned long SSL_set_mode(SSL *, unsigned long); unsigned long SSL_get_mode(SSL *); @@ -352,7 +415,7 @@ void SSL_set_tlsext_host_name(SSL *, char *); void SSL_CTX_set_tlsext_servername_callback( SSL_CTX *, - int (*)(const SSL *, int *, void *)); + int (*)(SSL *, int *, void *)); void SSL_CTX_set_tlsext_servername_arg( SSL_CTX *, void *); @@ -362,6 +425,10 @@ long SSL_CTX_set_tlsext_status_cb(SSL_CTX *, int(*)(SSL *, void *)); long SSL_CTX_set_tlsext_status_arg(SSL_CTX *, void *); +int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *, const char *); +int SSL_set_tlsext_use_srtp(SSL *, const char *); +SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *); + long SSL_session_reused(SSL *); void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *, @@ -439,6 +506,47 @@ /* DTLS support */ long Cryptography_DTLSv1_get_timeout(SSL *, time_t *, long *); long DTLSv1_handle_timeout(SSL *); +long DTLS_set_link_mtu(SSL *, long); +long DTLS_get_link_min_mtu(SSL *); + +/* Custom extensions. */ +typedef int (*custom_ext_add_cb)(SSL *, unsigned int, + const unsigned char **, + size_t *, int *, + void *); + +typedef void (*custom_ext_free_cb)(SSL *, unsigned int, + const unsigned char *, + void *); + +typedef int (*custom_ext_parse_cb)(SSL *, unsigned int, + const unsigned char *, + size_t, int *, + void *); + +int SSL_CTX_add_client_custom_ext(SSL_CTX *, unsigned int, + custom_ext_add_cb, + custom_ext_free_cb, void *, + custom_ext_parse_cb, + void *); + +int SSL_CTX_add_server_custom_ext(SSL_CTX *, unsigned int, + custom_ext_add_cb, + custom_ext_free_cb, void *, + custom_ext_parse_cb, + void *); + +int SSL_extension_supported(unsigned int); + +int SSL_CTX_set_ciphersuites(SSL_CTX *, const char *); +int SSL_verify_client_post_handshake(SSL *); +void SSL_CTX_set_post_handshake_auth(SSL_CTX *, int); +void SSL_set_post_handshake_auth(SSL *, int); + +uint32_t SSL_SESSION_get_max_early_data(const SSL_SESSION *); +int SSL_write_early_data(SSL *, const void *, size_t, size_t *); +int SSL_read_early_data(SSL *, void *, size_t, size_t *); +int SSL_CTX_set_max_early_data(SSL_CTX *, uint32_t); """ CUSTOMIZATIONS = """ @@ -453,7 +561,7 @@ /* Added in 1.1.0 in the great opaquing, but we need to define it for older OpenSSLs. Such is our burden. */ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER /* from ssl/ssl_lib.c */ size_t SSL_get_client_random(const SSL *ssl, unsigned char *out, size_t outlen) { @@ -491,6 +599,16 @@ memcpy(out, session->master_key, outlen); return outlen; } +/* from ssl/ssl_sess.c */ +int SSL_SESSION_has_ticket(const SSL_SESSION *s) +{ + return (s->tlsext_ticklen > 0) ? 1 : 0; +} +/* from ssl/ssl_sess.c */ +unsigned long SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *s) +{ + return s->tlsext_tick_lifetime_hint; +} #endif static const long Cryptography_HAS_SECURE_RENEGOTIATION = 1; @@ -523,6 +641,12 @@ static const long Cryptography_HAS_SSL_SET_SSL_CTX = 1; static const long Cryptography_HAS_NEXTPROTONEG = 1; +/* SSL_get0_param was added in OpenSSL 1.0.2. */ +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER +X509_VERIFY_PARAM *(*SSL_get0_param)(SSL *) = NULL; +#else +#endif + /* ALPN was added in OpenSSL 1.0.2. */ #if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 && !CRYPTOGRAPHY_IS_LIBRESSL int (*SSL_CTX_set_alpn_protos)(SSL_CTX *, @@ -595,11 +719,15 @@ static const long TLS_ST_OK = 0; #endif -#if defined(OPENSSL_NO_DTLS) || CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 static const long Cryptography_HAS_GENERIC_DTLS_METHOD = 0; const SSL_METHOD *(*DTLS_method)(void) = NULL; const SSL_METHOD *(*DTLS_server_method)(void) = NULL; const SSL_METHOD *(*DTLS_client_method)(void) = NULL; +static const long SSL_OP_NO_DTLSv1 = 0; +static const long SSL_OP_NO_DTLSv1_2 = 0; +long (*DTLS_set_link_mtu)(SSL *, long) = NULL; +long (*DTLS_get_link_min_mtu)(SSL *) = NULL; #else static const long Cryptography_HAS_GENERIC_DTLS_METHOD = 1; #endif @@ -623,4 +751,101 @@ return r; } + +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 +static const long Cryptography_HAS_SIGALGS = 0; +const int (*SSL_get_sigalgs)(SSL *, int, int *, int *, int *, unsigned char *, + unsigned char *) = NULL; +const long (*SSL_CTX_set1_sigalgs_list)(SSL_CTX *, const char *) = NULL; +#else +static const long Cryptography_HAS_SIGALGS = 1; +#endif + +#if CRYPTOGRAPHY_IS_LIBRESSL || defined(OPENSSL_NO_PSK) +static const long Cryptography_HAS_PSK = 0; +int (*SSL_CTX_use_psk_identity_hint)(SSL_CTX *, const char *) = NULL; +void (*SSL_CTX_set_psk_server_callback)(SSL_CTX *, + unsigned int (*)( + SSL *, + const char *, + unsigned char *, + unsigned int + )) = NULL; +void (*SSL_CTX_set_psk_client_callback)(SSL_CTX *, + unsigned int (*)( + SSL *, + const char *, + char *, + unsigned int, + unsigned char *, + unsigned int + )) = NULL; +#else +static const long Cryptography_HAS_PSK = 1; +#endif + +/* + * Custom extensions were added in 1.0.2. 1.1.1 is adding a more general + * SSL_CTX_add_custom_ext function, but we're not binding that yet. + */ +#if CRYPTOGRAPHY_OPENSSL_102_OR_GREATER +static const long Cryptography_HAS_CUSTOM_EXT = 1; +#else +static const long Cryptography_HAS_CUSTOM_EXT = 0; + +typedef int (*custom_ext_add_cb)(SSL *, unsigned int, + const unsigned char **, + size_t *, int *, + void *); + +typedef void (*custom_ext_free_cb)(SSL *, unsigned int, + const unsigned char *, + void *); + +typedef int (*custom_ext_parse_cb)(SSL *, unsigned int, + const unsigned char *, + size_t, int *, + void *); + +int (*SSL_CTX_add_client_custom_ext)(SSL_CTX *, unsigned int, + custom_ext_add_cb, + custom_ext_free_cb, void *, + custom_ext_parse_cb, + void *) = NULL; + +int (*SSL_CTX_add_server_custom_ext)(SSL_CTX *, unsigned int, + custom_ext_add_cb, + custom_ext_free_cb, void *, + custom_ext_parse_cb, + void *) = NULL; + +int (*SSL_extension_supported)(unsigned int) = NULL; +#endif + +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER +int (*SSL_CIPHER_is_aead)(const SSL_CIPHER *) = NULL; +int (*SSL_CIPHER_get_cipher_nid)(const SSL_CIPHER *) = NULL; +int (*SSL_CIPHER_get_digest_nid)(const SSL_CIPHER *) = NULL; +int (*SSL_CIPHER_get_kx_nid)(const SSL_CIPHER *) = NULL; +int (*SSL_CIPHER_get_auth_nid)(const SSL_CIPHER *) = NULL; +static const long Cryptography_HAS_CIPHER_DETAILS = 0; +#else +static const long Cryptography_HAS_CIPHER_DETAILS = 1; +#endif + +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 +static const long Cryptography_HAS_TLSv1_3 = 0; +static const long SSL_OP_NO_TLSv1_3 = 0; +static const long SSL_VERIFY_POST_HANDSHAKE = 0; +int (*SSL_CTX_set_ciphersuites)(SSL_CTX *, const char *) = NULL; +int (*SSL_verify_client_post_handshake)(SSL *) = NULL; +void (*SSL_CTX_set_post_handshake_auth)(SSL_CTX *, int) = NULL; +void (*SSL_set_post_handshake_auth)(SSL *, int) = NULL; +uint32_t (*SSL_SESSION_get_max_early_data)(const SSL_SESSION *) = NULL; +int (*SSL_write_early_data)(SSL *, const void *, size_t, size_t *) = NULL; +int (*SSL_read_early_data)(SSL *, void *, size_t, size_t *) = NULL; +int (*SSL_CTX_set_max_early_data)(SSL_CTX *, uint32_t) = NULL; +#else +static const long Cryptography_HAS_TLSv1_3 = 1; +#endif """ diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/x509name.py python-cryptography-2.6.1/src/_cffi_src/openssl/x509name.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/x509name.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/x509name.py 2019-02-27 23:27:53.000000000 +0000 @@ -40,6 +40,7 @@ int X509_NAME_entry_count(X509_NAME *); X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *, int); char *X509_NAME_oneline(X509_NAME *, char *, int); +int X509_NAME_print_ex(BIO *, X509_NAME *, int, unsigned long); /* These became const X509_NAME_ENTRY * in 1.1.0 */ ASN1_OBJECT *X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *); diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/x509.py python-cryptography-2.6.1/src/_cffi_src/openssl/x509.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/x509.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/x509.py 2019-02-27 23:27:53.000000000 +0000 @@ -29,14 +29,10 @@ ...; } X509_ALGOR; -typedef ... X509_ATTRIBUTE; -typedef ... X509_CINF; typedef ... X509_EXTENSION; typedef ... X509_EXTENSIONS; typedef ... X509_REQ; -typedef ... X509_REQ_INFO; typedef ... X509_REVOKED; -typedef ... X509_CRL_INFO; typedef ... X509_CRL; typedef ... X509; @@ -44,38 +40,7 @@ typedef ... PKCS8_PRIV_KEY_INFO; -static const int X509_FLAG_COMPAT; -static const int X509_FLAG_NO_HEADER; -static const int X509_FLAG_NO_VERSION; -static const int X509_FLAG_NO_SERIAL; -static const int X509_FLAG_NO_SIGNAME; -static const int X509_FLAG_NO_ISSUER; -static const int X509_FLAG_NO_VALIDITY; -static const int X509_FLAG_NO_SUBJECT; -static const int X509_FLAG_NO_PUBKEY; -static const int X509_FLAG_NO_EXTENSIONS; -static const int X509_FLAG_NO_SIGDUMP; -static const int X509_FLAG_NO_AUX; -static const int X509_FLAG_NO_ATTRIBUTES; - -static const int XN_FLAG_SEP_MASK; -static const int XN_FLAG_COMPAT; -static const int XN_FLAG_SEP_COMMA_PLUS; -static const int XN_FLAG_SEP_CPLUS_SPC; -static const int XN_FLAG_SEP_SPLUS_SPC; -static const int XN_FLAG_SEP_MULTILINE; -static const int XN_FLAG_DN_REV; -static const int XN_FLAG_FN_MASK; -static const int XN_FLAG_FN_SN; -static const int XN_FLAG_FN_LN; -static const int XN_FLAG_FN_OID; -static const int XN_FLAG_FN_NONE; -static const int XN_FLAG_SPC_EQ; -static const int XN_FLAG_DUMP_UNKNOWN_FIELDS; -static const int XN_FLAG_FN_ALIGN; -static const int XN_FLAG_RFC2253; -static const int XN_FLAG_ONELINE; -static const int XN_FLAG_MULTILINE; +typedef void (*sk_X509_EXTENSION_freefunc)(X509_EXTENSION *); """ FUNCTIONS = """ @@ -106,14 +71,11 @@ int X509_set_issuer_name(X509 *, X509_NAME *); int X509_add_ext(X509 *, X509_EXTENSION *, int); -X509_EXTENSION *X509_delete_ext(X509 *, int); X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *); ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *); void X509_EXTENSION_free(X509_EXTENSION *); -int i2d_X509(X509 *, unsigned char **); - int X509_REQ_set_version(X509_REQ *, long); X509_REQ *X509_REQ_new(void); void X509_REQ_free(X509_REQ *); @@ -121,10 +83,7 @@ int X509_REQ_set_subject_name(X509_REQ *, X509_NAME *); int X509_REQ_sign(X509_REQ *, EVP_PKEY *, const EVP_MD *); int X509_REQ_verify(X509_REQ *, EVP_PKEY *); -int X509_REQ_digest(const X509_REQ *, const EVP_MD *, - unsigned char *, unsigned int *); EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *); -int X509_REQ_print(BIO *, X509_REQ *); int X509_REQ_print_ex(BIO *, X509_REQ *, unsigned long, unsigned long); int X509_REQ_add_extensions(X509_REQ *, X509_EXTENSIONS *); X509_EXTENSIONS *X509_REQ_get_extensions(X509_REQ *); @@ -144,6 +103,7 @@ int X509_REVOKED_set_revocationDate(X509_REVOKED *, ASN1_TIME *); X509_CRL *X509_CRL_new(void); +X509_CRL *X509_CRL_dup(X509_CRL *); X509_CRL *d2i_X509_CRL_bio(BIO *, X509_CRL **); int X509_CRL_add0_revoked(X509_CRL *, X509_REVOKED *); int X509_CRL_add_ext(X509_CRL *, X509_EXTENSION *, int); @@ -183,40 +143,19 @@ const char *X509_verify_cert_error_string(long); -const char *X509_get_default_cert_area(void); const char *X509_get_default_cert_dir(void); const char *X509_get_default_cert_file(void); const char *X509_get_default_cert_dir_env(void); const char *X509_get_default_cert_file_env(void); -const char *X509_get_default_private_dir(void); - -int i2d_RSA_PUBKEY(RSA *, unsigned char **); -RSA *d2i_RSA_PUBKEY(RSA **, const unsigned char **, long); -RSA *d2i_RSAPublicKey(RSA **, const unsigned char **, long); -RSA *d2i_RSAPrivateKey(RSA **, const unsigned char **, long); -int i2d_DSA_PUBKEY(DSA *, unsigned char **); -DSA *d2i_DSA_PUBKEY(DSA **, const unsigned char **, long); -DSA *d2i_DSAPublicKey(DSA **, const unsigned char **, long); -DSA *d2i_DSAPrivateKey(DSA **, const unsigned char **, long); -RSA *d2i_RSAPrivateKey_bio(BIO *, RSA **); int i2d_RSAPrivateKey_bio(BIO *, RSA *); RSA *d2i_RSAPublicKey_bio(BIO *, RSA **); int i2d_RSAPublicKey_bio(BIO *, RSA *); -RSA *d2i_RSA_PUBKEY_bio(BIO *, RSA **); -int i2d_RSA_PUBKEY_bio(BIO *, RSA *); -DSA *d2i_DSA_PUBKEY_bio(BIO *, DSA **); -int i2d_DSA_PUBKEY_bio(BIO *, DSA *); -DSA *d2i_DSAPrivateKey_bio(BIO *, DSA **); int i2d_DSAPrivateKey_bio(BIO *, DSA *); -PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *, - PKCS8_PRIV_KEY_INFO **); -void PKCS8_PRIV_KEY_INFO_free(PKCS8_PRIV_KEY_INFO *); /* These became const X509 in 1.1.0 */ int X509_get_ext_count(X509 *); X509_EXTENSION *X509_get_ext(X509 *, int); -int X509_get_ext_by_NID(X509 *, int, int); X509_NAME *X509_get_subject_name(X509 *); X509_NAME *X509_get_issuer_name(X509 *); @@ -237,26 +176,18 @@ X509_EXTENSION *X509_CRL_get_ext(X509_CRL *, int); int X509_CRL_get_ext_count(X509_CRL *); -/* these CRYPTO_EX_DATA functions became macros in 1.1.0 */ -int X509_get_ex_new_index(long, void *, CRYPTO_EX_new *, CRYPTO_EX_dup *, - CRYPTO_EX_free *); -int X509_set_ex_data(X509 *, int, void *); -void *X509_get_ex_data(X509 *, int); +int X509_CRL_get0_by_serial(X509_CRL *, X509_REVOKED **, ASN1_INTEGER *); X509_REVOKED *Cryptography_X509_REVOKED_dup(X509_REVOKED *); -int i2d_X509_CINF(X509_CINF *, unsigned char **); -int i2d_X509_CRL_INFO(X509_CRL_INFO *, unsigned char **); -int i2d_X509_REQ_INFO(X509_REQ_INFO *, unsigned char **); - /* new in 1.0.2 */ int i2d_re_X509_tbs(X509 *, unsigned char **); int X509_get_signature_nid(const X509 *); const X509_ALGOR *X509_get0_tbs_sigalg(const X509 *); -/* in 1.1.0 becomes const ASN1_BIT_STRING, const X509_ALGOR */ -void X509_get0_signature(ASN1_BIT_STRING **, X509_ALGOR **, X509 *); +void X509_get0_signature(const ASN1_BIT_STRING **, + const X509_ALGOR **, const X509 *); long X509_get_version(X509 *); @@ -279,6 +210,7 @@ int sk_X509_EXTENSION_insert(X509_EXTENSIONS *, X509_EXTENSION *, int); X509_EXTENSION *sk_X509_EXTENSION_delete(X509_EXTENSIONS *, int); void sk_X509_EXTENSION_free(X509_EXTENSIONS *); +void sk_X509_EXTENSION_pop_free(X509_EXTENSIONS *, sk_X509_EXTENSION_freefunc); int sk_X509_REVOKED_num(Cryptography_STACK_OF_X509_REVOKED *); X509_REVOKED *sk_X509_REVOKED_value(Cryptography_STACK_OF_X509_REVOKED *, int); @@ -289,11 +221,6 @@ int sk_X509_CRL_push(Cryptography_STACK_OF_X509_CRL *, X509_CRL *); X509_CRL *sk_X509_CRL_value(Cryptography_STACK_OF_X509_CRL *, int); -int i2d_RSAPublicKey(RSA *, unsigned char **); -int i2d_RSAPrivateKey(RSA *, unsigned char **); -int i2d_DSAPublicKey(DSA *, unsigned char **); -int i2d_DSAPrivateKey(DSA *, unsigned char **); - long X509_CRL_get_version(X509_CRL *); ASN1_TIME *X509_CRL_get_lastUpdate(X509_CRL *); ASN1_TIME *X509_CRL_get_nextUpdate(X509_CRL *); @@ -306,18 +233,11 @@ int X509_set_notBefore(X509 *, ASN1_TIME *); int X509_set_notAfter(X509 *, ASN1_TIME *); -int i2d_EC_PUBKEY(EC_KEY *, unsigned char **); -EC_KEY *d2i_EC_PUBKEY(EC_KEY **, const unsigned char **, long); EC_KEY *d2i_EC_PUBKEY_bio(BIO *, EC_KEY **); int i2d_EC_PUBKEY_bio(BIO *, EC_KEY *); -EC_KEY *d2i_ECPrivateKey(EC_KEY **, const unsigned char **, long); EC_KEY *d2i_ECPrivateKey_bio(BIO *, EC_KEY **); -int i2d_ECPrivateKey(EC_KEY *, unsigned char **); int i2d_ECPrivateKey_bio(BIO *, EC_KEY *); -EC_KEY *o2i_ECPublicKey(EC_KEY **, const unsigned char **, long); -int i2o_ECPublicKey(EC_KEY *, unsigned char **); - // declared in safestack int sk_ASN1_OBJECT_num(Cryptography_STACK_OF_ASN1_OBJECT *); ASN1_OBJECT *sk_ASN1_OBJECT_value(Cryptography_STACK_OF_ASN1_OBJECT *, int); @@ -339,10 +259,10 @@ CUSTOMIZATIONS = """ /* Added in 1.0.2 beta but we need it in all versions now due to the great opaquing. */ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER /* from x509/x_x509.c version 1.0.2 */ -void X509_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, - const X509 *x) +void X509_get0_signature(const ASN1_BIT_STRING **psig, + const X509_ALGOR **palg, const X509 *x) { if (psig) *psig = x->signature; @@ -376,13 +296,27 @@ IMPLEMENT_ASN1_DUP_FUNCTION. The below is the equivalent so we have it available on all OpenSSLs. */ X509_REVOKED *Cryptography_X509_REVOKED_dup(X509_REVOKED *rev) { +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 return ASN1_item_dup(ASN1_ITEM_rptr(X509_REVOKED), rev); +#else + return X509_REVOKED_dup(rev); +#endif } /* Added in 1.1.0 but we need it in all versions now due to the great opaquing. */ #if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 +int i2d_re_X509_REQ_tbs(X509_REQ *req, unsigned char **pp) +{ + req->req_info->enc.modified = 1; + return i2d_X509_REQ_INFO(req->req_info, pp); +} +int i2d_re_X509_CRL_tbs(X509_CRL *crl, unsigned char **pp) { + crl->crl->enc.modified = 1; + return i2d_X509_CRL_INFO(crl->crl, pp); +} +#if !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER int X509_up_ref(X509 *x) { return CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); } @@ -401,16 +335,6 @@ if (palg != NULL) *palg = req->sig_alg; } -int i2d_re_X509_REQ_tbs(X509_REQ *req, unsigned char **pp) -{ - req->req_info->enc.modified = 1; - return i2d_X509_REQ_INFO(req->req_info, pp); -} -int i2d_re_X509_CRL_tbs(X509_CRL *crl, unsigned char **pp) { - crl->crl->enc.modified = 1; - return i2d_X509_CRL_INFO(crl->crl, pp); -} - void X509_CRL_get0_signature(const X509_CRL *crl, const ASN1_BIT_STRING **psig, const X509_ALGOR **palg) { @@ -428,4 +352,5 @@ return x->serialNumber; } #endif +#endif """ diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/x509v3.py python-cryptography-2.6.1/src/_cffi_src/openssl/x509v3.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/x509v3.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/x509v3.py 2019-02-27 23:27:53.000000000 +0000 @@ -41,12 +41,6 @@ typedef void * (*X509V3_EXT_D2I)(void *, const unsigned char **, long); -typedef struct { - ASN1_ITEM_EXP *it; - X509V3_EXT_D2I d2i; - ...; -} X509V3_EXT_METHOD; - static const int GEN_OTHERNAME; static const int GEN_EMAIL; static const int GEN_X400; @@ -148,6 +142,15 @@ } DIST_POINT; typedef struct { + DIST_POINT_NAME *distpoint; + int onlyuser; + int onlyCA; + ASN1_BIT_STRING *onlysomereasons; + int indirectCRL; + int onlyattr; +} ISSUING_DIST_POINT; + +typedef struct { ASN1_STRING *organization; Cryptography_STACK_OF_ASN1_INTEGER *noticenos; } NOTICEREF; @@ -234,10 +237,6 @@ X509_EXTENSION *X509V3_EXT_conf_nid(Cryptography_LHASH_OF_CONF_VALUE *, X509V3_CTX *, int, char *); -/* These aren't macros these functions are all const X on openssl > 1.0.x */ -const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *); -const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int); - Cryptography_STACK_OF_DIST_POINT *sk_DIST_POINT_new_null(void); void sk_DIST_POINT_free(Cryptography_STACK_OF_DIST_POINT *); int sk_DIST_POINT_num(Cryptography_STACK_OF_DIST_POINT *); @@ -303,6 +302,9 @@ GENERAL_NAME *GENERAL_NAME_new(void); void GENERAL_NAME_free(GENERAL_NAME *); + +ISSUING_DIST_POINT *ISSUING_DIST_POINT_new(void); +void ISSUING_DIST_POINT_free(ISSUING_DIST_POINT *); """ CUSTOMIZATIONS = """ diff -Nru python-cryptography-2.1.4/src/_cffi_src/openssl/x509_vfy.py python-cryptography-2.6.1/src/_cffi_src/openssl/x509_vfy.py --- python-cryptography-2.1.4/src/_cffi_src/openssl/x509_vfy.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/openssl/x509_vfy.py 2019-02-27 23:27:53.000000000 +0000 @@ -21,6 +21,7 @@ TYPES = """ static const long Cryptography_HAS_102_VERIFICATION_ERROR_CODES; static const long Cryptography_HAS_102_VERIFICATION_PARAMS; +static const long Cryptography_HAS_110_VERIFICATION_PARAMS; static const long Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST; static const long Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN; static const long Cryptography_HAS_X509_STORE_CTX_GET_ISSUER; @@ -128,6 +129,13 @@ static const long X509_LU_X509; static const long X509_LU_CRL; + +static const long X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT; +static const long X509_CHECK_FLAG_NO_WILDCARDS; +static const long X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS; +static const long X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS; +static const long X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS; +static const long X509_CHECK_FLAG_NEVER_CHECK_SUBJECT; """ FUNCTIONS = """ @@ -239,6 +247,21 @@ #ifndef X509_V_ERR_IP_ADDRESS_MISMATCH static const long X509_V_ERR_IP_ADDRESS_MISMATCH = 0; #endif +#ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT +static const long X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT = 0; +#endif +#ifndef X509_CHECK_FLAG_NO_WILDCARDS +static const long X509_CHECK_FLAG_NO_WILDCARDS = 0; +#endif +#ifndef X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS +static const long X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS = 0; +#endif +#ifndef X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS +static const long X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS = 0; +#endif +#ifndef X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS +static const long X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS = 0; +#endif /* X509_V_FLAG_TRUSTED_FIRST is also new in 1.0.2+, but it is added separately below because it shows up in some earlier 3rd party OpenSSL packages. */ @@ -246,6 +269,7 @@ static const long X509_V_FLAG_SUITEB_192_LOS = 0; static const long X509_V_FLAG_SUITEB_128_LOS = 0; +#if !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER int (*X509_VERIFY_PARAM_set1_host)(X509_VERIFY_PARAM *, const char *, size_t) = NULL; int (*X509_VERIFY_PARAM_set1_email)(X509_VERIFY_PARAM *, const char *, @@ -256,6 +280,16 @@ void (*X509_VERIFY_PARAM_set_hostflags)(X509_VERIFY_PARAM *, unsigned int) = NULL; #endif +#endif + +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 || CRYPTOGRAPHY_IS_LIBRESSL +static const long Cryptography_HAS_110_VERIFICATION_PARAMS = 0; +#ifndef X509_CHECK_FLAG_NEVER_CHECK_SUBJECT +static const long X509_CHECK_FLAG_NEVER_CHECK_SUBJECT = 0; +#endif +#else +static const long Cryptography_HAS_110_VERIFICATION_PARAMS = 1; +#endif /* OpenSSL 1.0.2+ or Solaris's backport */ #ifdef X509_V_FLAG_PARTIAL_CHAIN @@ -273,7 +307,7 @@ static const long X509_V_FLAG_TRUSTED_FIRST = 0; #endif -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110PRE6 +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER Cryptography_STACK_OF_X509_OBJECT *X509_STORE_get0_objects(X509_STORE *ctx) { return ctx->objs; } @@ -283,9 +317,7 @@ int X509_OBJECT_get_type(const X509_OBJECT *x) { return x->type; } -#endif -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110PRE5 /* from x509/x509_vfy.c */ X509 *X509_STORE_CTX_get0_cert(X509_STORE_CTX *ctx) { diff -Nru python-cryptography-2.1.4/src/_cffi_src/utils.py python-cryptography-2.6.1/src/_cffi_src/utils.py --- python-cryptography-2.1.4/src/_cffi_src/utils.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/_cffi_src/utils.py 2019-02-27 23:27:53.000000000 +0000 @@ -4,6 +4,7 @@ from __future__ import absolute_import, division, print_function +import os import sys from distutils.ccompiler import new_compiler from distutils.dist import Distribution @@ -11,6 +12,13 @@ from cffi import FFI +# Load the cryptography __about__ to get the current package version +base_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +about = {} +with open(os.path.join(base_src, "cryptography", "__about__.py")) as f: + exec(f.read(), about) + + def build_ffi_for_binding(module_name, module_prefix, modules, libraries=[], extra_compile_args=[], extra_link_args=[]): """ @@ -55,6 +63,11 @@ def build_ffi(module_name, cdef_source, verify_source, libraries=[], extra_compile_args=[], extra_link_args=[]): ffi = FFI() + # Always add the CRYPTOGRAPHY_PACKAGE_VERSION to the shared object + cdef_source += "\nstatic const char *const CRYPTOGRAPHY_PACKAGE_VERSION;" + verify_source += '\n#define CRYPTOGRAPHY_PACKAGE_VERSION "{}"'.format( + about["__version__"] + ) ffi.cdef(cdef_source) ffi.set_source( module_name, diff -Nru python-cryptography-2.1.4/src/cryptography/__about__.py python-cryptography-2.6.1/src/cryptography/__about__.py --- python-cryptography-2.1.4/src/cryptography/__about__.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/__about__.py 2019-02-27 23:27:53.000000000 +0000 @@ -14,10 +14,10 @@ " and primitives to Python developers.") __uri__ = "https://github.com/pyca/cryptography" -__version__ = "2.1.4" +__version__ = "2.6.1" __author__ = "The cryptography developers" __email__ = "cryptography-dev@python.org" __license__ = "BSD or Apache License, Version 2.0" -__copyright__ = "Copyright 2013-2017 {0}".format(__author__) +__copyright__ = "Copyright 2013-2017 {}".format(__author__) diff -Nru python-cryptography-2.1.4/src/cryptography/fernet.py python-cryptography-2.6.1/src/cryptography/fernet.py --- python-cryptography-2.1.4/src/cryptography/fernet.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/fernet.py 2019-02-27 23:27:53.000000000 +0000 @@ -12,6 +12,7 @@ import six +from cryptography import utils from cryptography.exceptions import InvalidSignature from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, padding @@ -51,8 +52,7 @@ return self._encrypt_from_parts(data, current_time, iv) def _encrypt_from_parts(self, data, current_time, iv): - if not isinstance(data, bytes): - raise TypeError("data must be bytes.") + utils._check_bytes("data", data) padder = padding.PKCS7(algorithms.AES.block_size).padder() padded_data = padder.update(data) + padder.finalize() @@ -71,11 +71,18 @@ return base64.urlsafe_b64encode(basic_parts + hmac) def decrypt(self, token, ttl=None): - if not isinstance(token, bytes): - raise TypeError("token must be bytes.") - - current_time = int(time.time()) + timestamp, data = Fernet._get_unverified_token_data(token) + return self._decrypt_data(data, timestamp, ttl) + def extract_timestamp(self, token): + timestamp, data = Fernet._get_unverified_token_data(token) + # Verify the token was not tampered with. + self._verify_signature(data) + return timestamp + + @staticmethod + def _get_unverified_token_data(token): + utils._check_bytes("token", token) try: data = base64.urlsafe_b64decode(token) except (TypeError, binascii.Error): @@ -88,13 +95,9 @@ timestamp, = struct.unpack(">Q", data[1:9]) except struct.error: raise InvalidToken - if ttl is not None: - if timestamp + ttl < current_time: - raise InvalidToken - - if current_time + _MAX_CLOCK_SKEW < timestamp: - raise InvalidToken + return timestamp, data + def _verify_signature(self, data): h = HMAC(self._signing_key, hashes.SHA256(), backend=self._backend) h.update(data[:-32]) try: @@ -102,6 +105,17 @@ except InvalidSignature: raise InvalidToken + def _decrypt_data(self, data, timestamp, ttl): + current_time = int(time.time()) + if ttl is not None: + if timestamp + ttl < current_time: + raise InvalidToken + + if current_time + _MAX_CLOCK_SKEW < timestamp: + raise InvalidToken + + self._verify_signature(data) + iv = data[9:25] ciphertext = data[25:-32] decryptor = Cipher( @@ -134,6 +148,20 @@ def encrypt(self, msg): return self._fernets[0].encrypt(msg) + def rotate(self, msg): + timestamp, data = Fernet._get_unverified_token_data(msg) + for f in self._fernets: + try: + p = f._decrypt_data(data, timestamp, None) + break + except InvalidToken: + pass + else: + raise InvalidToken + + iv = os.urandom(16) + return self._fernets[0]._encrypt_from_parts(p, timestamp, iv) + def decrypt(self, msg, ttl=None): for f in self._fernets: try: diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/aead.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/aead.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/aead.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/aead.py 2019-02-27 23:27:53.000000000 +0000 @@ -18,10 +18,10 @@ if isinstance(cipher, ChaCha20Poly1305): return b"chacha20-poly1305" elif isinstance(cipher, AESCCM): - return "aes-{0}-ccm".format(len(cipher._key) * 8).encode("ascii") + return "aes-{}-ccm".format(len(cipher._key) * 8).encode("ascii") else: assert isinstance(cipher, AESGCM) - return "aes-{0}-gcm".format(len(cipher._key) * 8).encode("ascii") + return "aes-{}-gcm".format(len(cipher._key) * 8).encode("ascii") def _aead_setup(backend, cipher_name, key, nonce, tag, tag_len, operation): @@ -54,12 +54,14 @@ ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, tag_len, backend._ffi.NULL ) + nonce_ptr = backend._ffi.from_buffer(nonce) + key_ptr = backend._ffi.from_buffer(key) res = backend._lib.EVP_CipherInit_ex( ctx, backend._ffi.NULL, backend._ffi.NULL, - key, - nonce, + key_ptr, + nonce_ptr, int(operation == _ENCRYPT) ) backend.openssl_assert(res != 0) diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/backend.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/backend.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/backend.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/backend.py 2019-02-27 23:27:53.000000000 +0000 @@ -5,13 +5,15 @@ from __future__ import absolute_import, division, print_function import base64 -import calendar import collections import contextlib import itertools from contextlib import contextmanager +import asn1crypto.core + import six +from six.moves import range from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm, _Reasons @@ -23,10 +25,11 @@ from cryptography.hazmat.backends.openssl import aead from cryptography.hazmat.backends.openssl.ciphers import _CipherContext from cryptography.hazmat.backends.openssl.cmac import _CMACContext -from cryptography.hazmat.backends.openssl.decode_asn1 import _Integers +from cryptography.hazmat.backends.openssl.decode_asn1 import ( + _CRL_ENTRY_REASON_ENUM_TO_CODE, _Integers +) from cryptography.hazmat.backends.openssl.dh import ( - _DHParameters, _DHPrivateKey, _DHPublicKey, - _dh_params_dup + _DHParameters, _DHPrivateKey, _DHPublicKey, _dh_params_dup ) from cryptography.hazmat.backends.openssl.dsa import ( _DSAParameters, _DSAPrivateKey, _DSAPublicKey @@ -34,26 +37,40 @@ from cryptography.hazmat.backends.openssl.ec import ( _EllipticCurvePrivateKey, _EllipticCurvePublicKey ) +from cryptography.hazmat.backends.openssl.ed25519 import ( + _Ed25519PrivateKey, _Ed25519PublicKey +) +from cryptography.hazmat.backends.openssl.ed448 import ( + _ED448_KEY_SIZE, _Ed448PrivateKey, _Ed448PublicKey +) from cryptography.hazmat.backends.openssl.encode_asn1 import ( _CRL_ENTRY_EXTENSION_ENCODE_HANDLERS, _CRL_EXTENSION_ENCODE_HANDLERS, _EXTENSION_ENCODE_HANDLERS, + _OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS, + _OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS, _encode_asn1_int_gc, _encode_asn1_str_gc, _encode_name_gc, _txt2obj_gc, ) from cryptography.hazmat.backends.openssl.hashes import _HashContext from cryptography.hazmat.backends.openssl.hmac import _HMACContext +from cryptography.hazmat.backends.openssl.ocsp import ( + _OCSPRequest, _OCSPResponse +) from cryptography.hazmat.backends.openssl.rsa import ( _RSAPrivateKey, _RSAPublicKey ) from cryptography.hazmat.backends.openssl.x25519 import ( _X25519PrivateKey, _X25519PublicKey ) +from cryptography.hazmat.backends.openssl.x448 import ( + _X448PrivateKey, _X448PublicKey +) from cryptography.hazmat.backends.openssl.x509 import ( _Certificate, _CertificateRevocationList, _CertificateSigningRequest, _RevokedCertificate ) from cryptography.hazmat.bindings.openssl import binding from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa +from cryptography.hazmat.primitives.asymmetric import dsa, ec, ed25519, rsa from cryptography.hazmat.primitives.asymmetric.padding import ( MGF1, OAEP, PKCS1v15, PSS ) @@ -64,6 +81,8 @@ CBC, CFB, CFB8, CTR, ECB, GCM, OFB, XTS ) from cryptography.hazmat.primitives.kdf import scrypt +from cryptography.hazmat.primitives.serialization import ssh +from cryptography.x509 import ocsp _MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"]) @@ -106,21 +125,22 @@ return binding._openssl_assert(self._lib, ok) def activate_builtin_random(self): - # Obtain a new structural reference. - e = self._lib.ENGINE_get_default_RAND() - if e != self._ffi.NULL: - self._lib.ENGINE_unregister_RAND(e) - # Reset the RNG to use the new engine. - self._lib.RAND_cleanup() - # decrement the structural reference from get_default_RAND - res = self._lib.ENGINE_finish(e) - self.openssl_assert(res == 1) + if self._lib.Cryptography_HAS_ENGINE: + # Obtain a new structural reference. + e = self._lib.ENGINE_get_default_RAND() + if e != self._ffi.NULL: + self._lib.ENGINE_unregister_RAND(e) + # Reset the RNG to use the new engine. + self._lib.RAND_cleanup() + # decrement the structural reference from get_default_RAND + res = self._lib.ENGINE_finish(e) + self.openssl_assert(res == 1) @contextlib.contextmanager def _get_osurandom_engine(self): # Fetches an engine by id and returns it. This creates a structural # reference. - e = self._lib.ENGINE_by_id(self._binding._osrandom_engine_id) + e = self._lib.ENGINE_by_id(self._lib.Cryptography_osrandom_engine_id) self.openssl_assert(e != self._ffi.NULL) # Initialize the engine for use. This adds a functional reference. res = self._lib.ENGINE_init(e) @@ -137,14 +157,15 @@ self.openssl_assert(res == 1) def activate_osrandom_engine(self): - # Unregister and free the current engine. - self.activate_builtin_random() - with self._get_osurandom_engine() as e: - # Set the engine as the default RAND provider. - res = self._lib.ENGINE_set_default_RAND(e) - self.openssl_assert(res == 1) - # Reset the RNG to use the new engine. - self._lib.RAND_cleanup() + if self._lib.Cryptography_HAS_ENGINE: + # Unregister and free the current engine. + self.activate_builtin_random() + with self._get_osurandom_engine() as e: + # Set the engine as the default RAND provider. + res = self._lib.ENGINE_set_default_RAND(e) + self.openssl_assert(res == 1) + # Reset the RNG to use the new engine. + self._lib.RAND_cleanup() def osrandom_engine_implementation(self): buf = self._ffi.new("char[]", 64) @@ -172,20 +193,25 @@ def create_hmac_ctx(self, key, algorithm): return _HMACContext(self, key, algorithm) - def _build_openssl_digest_name(self, algorithm): + def _evp_md_from_algorithm(self, algorithm): if algorithm.name == "blake2b" or algorithm.name == "blake2s": - alg = "{0}{1}".format( + alg = "{}{}".format( algorithm.name, algorithm.digest_size * 8 ).encode("ascii") else: alg = algorithm.name.encode("ascii") - return alg + evp_md = self._lib.EVP_get_digestbyname(alg) + return evp_md + + def _evp_md_non_null_from_algorithm(self, algorithm): + evp_md = self._evp_md_from_algorithm(algorithm) + self.openssl_assert(evp_md != self._ffi.NULL) + return evp_md def hash_supported(self, algorithm): - name = self._build_openssl_digest_name(algorithm) - digest = self._lib.EVP_get_digestbyname(name) - return digest != self._ffi.NULL + evp_md = self._evp_md_from_algorithm(algorithm) + return evp_md != self._ffi.NULL def hmac_supported(self, algorithm): return self.hash_supported(algorithm) @@ -203,7 +229,7 @@ def register_cipher_adapter(self, cipher_cls, mode_cls, adapter): if (cipher_cls, mode_cls) in self._cipher_registry: - raise ValueError("Duplicate registration for: {0} {1}.".format( + raise ValueError("Duplicate registration for: {} {}.".format( cipher_cls, mode_cls) ) self._cipher_registry[cipher_cls, mode_cls] = adapter @@ -277,11 +303,10 @@ def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations, key_material): buf = self._ffi.new("unsigned char[]", length) - evp_md = self._lib.EVP_get_digestbyname( - algorithm.name.encode("ascii")) - self.openssl_assert(evp_md != self._ffi.NULL) + evp_md = self._evp_md_non_null_from_algorithm(algorithm) + key_material_ptr = self._ffi.from_buffer(key_material) res = self._lib.PKCS5_PBKDF2_HMAC( - key_material, + key_material_ptr, len(key_material), salt, len(salt), @@ -299,7 +324,7 @@ def _bn_to_int(self, bn): assert bn != self._ffi.NULL - if six.PY3: + if not six.PY2: # Python 3 has constant time from_bytes, so use that. bn_num_bytes = self._lib.BN_num_bytes(bn) bin_ptr = self._ffi.new("unsigned char[]", bn_num_bytes) @@ -327,7 +352,7 @@ if bn is None: bn = self._ffi.NULL - if six.PY3: + if not six.PY2: # Python 3 has constant time to_bytes, so use that. binary = num.to_bytes(int(num.bit_length() / 8.0 + 1), "big") @@ -434,13 +459,13 @@ The char* is the storage for the BIO and it must stay alive until the BIO is finished with. """ - data_char_p = self._ffi.new("char[]", data) + data_ptr = self._ffi.from_buffer(data) bio = self._lib.BIO_new_mem_buf( - data_char_p, len(data) + data_ptr, len(data) ) self.openssl_assert(bio != self._ffi.NULL) - return _MemoryBIO(self._ffi.gc(bio, self._lib.BIO_free), data_char_p) + return _MemoryBIO(self._ffi.gc(bio, self._lib.BIO_free), data_ptr) def _create_mem_bio_gc(self): """ @@ -492,6 +517,18 @@ self.openssl_assert(dh_cdata != self._ffi.NULL) dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) return _DHPrivateKey(self, dh_cdata, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): + # EVP_PKEY_ED25519 is not present in OpenSSL < 1.1.1 + return _Ed25519PrivateKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): + # EVP_PKEY_X448 is not present in OpenSSL < 1.1.1 + return _X448PrivateKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_X25519", None): + # EVP_PKEY_X25519 is not present in OpenSSL < 1.1.0 + return _X25519PrivateKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): + # EVP_PKEY_ED448 is not present in OpenSSL < 1.1.1 + return _Ed448PrivateKey(self, evp_pkey) else: raise UnsupportedAlgorithm("Unsupported key type.") @@ -523,6 +560,18 @@ self.openssl_assert(dh_cdata != self._ffi.NULL) dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) return _DHPublicKey(self, dh_cdata, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): + # EVP_PKEY_ED25519 is not present in OpenSSL < 1.1.1 + return _Ed25519PublicKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): + # EVP_PKEY_X448 is not present in OpenSSL < 1.1.1 + return _X448PublicKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_X25519", None): + # EVP_PKEY_X25519 is not present in OpenSSL < 1.1.0 + return _X25519PublicKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): + # EVP_PKEY_X25519 is not present in OpenSSL < 1.1.1 + return _Ed448PublicKey(self, evp_pkey) else: raise UnsupportedAlgorithm("Unsupported key type.") @@ -676,10 +725,7 @@ ) # Resolve the signature algorithm. - evp_md = self._lib.EVP_get_digestbyname( - algorithm.name.encode('ascii') - ) - self.openssl_assert(evp_md != self._ffi.NULL) + evp_md = self._evp_md_non_null_from_algorithm(algorithm) # Create an empty request. x509_req = self._lib.X509_REQ_new() @@ -707,10 +753,15 @@ sk_extension = self._lib.sk_X509_EXTENSION_new_null() self.openssl_assert(sk_extension != self._ffi.NULL) sk_extension = self._ffi.gc( - sk_extension, self._lib.sk_X509_EXTENSION_free + sk_extension, + lambda x: self._lib.sk_X509_EXTENSION_pop_free( + x, self._ffi.addressof( + self._lib._original_lib, "X509_EXTENSION_free" + ) + ) ) - # gc is not necessary for CSRs, as sk_X509_EXTENSION_free - # will release all the X509_EXTENSIONs. + # Don't GC individual extensions because the memory is owned by + # sk_extensions and will be freed along with it. self._create_x509_extensions( extensions=builder._extensions, handlers=_EXTENSION_ENCODE_HANDLERS, @@ -753,10 +804,7 @@ ) # Resolve the signature algorithm. - evp_md = self._lib.EVP_get_digestbyname( - algorithm.name.encode('ascii') - ) - self.openssl_assert(evp_md != self._ffi.NULL) + evp_md = self._evp_md_non_null_from_algorithm(algorithm) # Create an empty certificate. x509_cert = self._lib.X509_new() @@ -784,20 +832,14 @@ self.openssl_assert(res == 1) # Set the "not before" time. - res = self._lib.ASN1_TIME_set( - self._lib.X509_get_notBefore(x509_cert), - calendar.timegm(builder._not_valid_before.timetuple()) + self._set_asn1_time( + self._lib.X509_get_notBefore(x509_cert), builder._not_valid_before ) - if res == self._ffi.NULL: - self._raise_time_set_error() # Set the "not after" time. - res = self._lib.ASN1_TIME_set( - self._lib.X509_get_notAfter(x509_cert), - calendar.timegm(builder._not_valid_after.timetuple()) + self._set_asn1_time( + self._lib.X509_get_notAfter(x509_cert), builder._not_valid_after ) - if res == self._ffi.NULL: - self._raise_time_set_error() # Add extensions. self._create_x509_extensions( @@ -830,18 +872,20 @@ return _Certificate(self, x509_cert) - def _raise_time_set_error(self): - errors = self._consume_errors() - self.openssl_assert( - errors[0]._lib_reason_match( - self._lib.ERR_LIB_ASN1, - self._lib.ASN1_R_ERROR_GETTING_TIME - ) - ) - raise ValueError( - "Invalid time. This error can occur if you set a time too far in " - "the future on Windows." - ) + def _set_asn1_time(self, asn1_time, time): + if time.year >= 2050: + asn1_str = time.strftime('%Y%m%d%H%M%SZ').encode('ascii') + else: + asn1_str = time.strftime('%y%m%d%H%M%SZ').encode('ascii') + res = self._lib.ASN1_TIME_set_string(asn1_time, asn1_str) + self.openssl_assert(res == 1) + + def _create_asn1_time(self, time): + asn1_time = self._lib.ASN1_TIME_new() + self.openssl_assert(asn1_time != self._ffi.NULL) + asn1_time = self._ffi.gc(asn1_time, self._lib.ASN1_TIME_free) + self._set_asn1_time(asn1_time, time) + return asn1_time def create_x509_crl(self, builder, private_key, algorithm): if not isinstance(builder, x509.CertificateRevocationListBuilder): @@ -857,10 +901,7 @@ "MD5 is not a supported hash algorithm for EC/DSA CRLs" ) - evp_md = self._lib.EVP_get_digestbyname( - algorithm.name.encode('ascii') - ) - self.openssl_assert(evp_md != self._ffi.NULL) + evp_md = self._evp_md_non_null_from_algorithm(algorithm) # Create an empty CRL. x509_crl = self._lib.X509_CRL_new() @@ -877,20 +918,12 @@ self.openssl_assert(res == 1) # Set the last update time. - last_update = self._lib.ASN1_TIME_set( - self._ffi.NULL, calendar.timegm(builder._last_update.timetuple()) - ) - self.openssl_assert(last_update != self._ffi.NULL) - last_update = self._ffi.gc(last_update, self._lib.ASN1_TIME_free) + last_update = self._create_asn1_time(builder._last_update) res = self._lib.X509_CRL_set_lastUpdate(x509_crl, last_update) self.openssl_assert(res == 1) # Set the next update time. - next_update = self._lib.ASN1_TIME_set( - self._ffi.NULL, calendar.timegm(builder._next_update.timetuple()) - ) - self.openssl_assert(next_update != self._ffi.NULL) - next_update = self._ffi.gc(next_update, self._lib.ASN1_TIME_free) + next_update = self._create_asn1_time(builder._next_update) res = self._lib.X509_CRL_set_nextUpdate(x509_crl, next_update) self.openssl_assert(res == 1) @@ -952,20 +985,22 @@ def _create_x509_extension(self, handlers, extension): if isinstance(extension.value, x509.UnrecognizedExtension): - value = _encode_asn1_str_gc( - self, extension.value.value, len(extension.value.value) - ) + value = _encode_asn1_str_gc(self, extension.value.value) return self._create_raw_x509_extension(extension, value) elif isinstance(extension.value, x509.TLSFeature): asn1 = _Integers([x.value for x in extension.value]).dump() - value = _encode_asn1_str_gc(self, asn1, len(asn1)) + value = _encode_asn1_str_gc(self, asn1) + return self._create_raw_x509_extension(extension, value) + elif isinstance(extension.value, x509.PrecertPoison): + asn1 = asn1crypto.core.Null().dump() + value = _encode_asn1_str_gc(self, asn1) return self._create_raw_x509_extension(extension, value) else: try: encode = handlers[extension.oid] except KeyError: raise NotImplementedError( - 'Extension not supported: {0}'.format(extension.oid) + 'Extension not supported: {}'.format(extension.oid) ) ext_struct = encode(self, extension.value) @@ -989,12 +1024,7 @@ x509_revoked, serial_number ) self.openssl_assert(res == 1) - rev_date = self._lib.ASN1_TIME_set( - self._ffi.NULL, - calendar.timegm(builder._revocation_date.timetuple()) - ) - self.openssl_assert(rev_date != self._ffi.NULL) - rev_date = self._ffi.gc(rev_date, self._lib.ASN1_TIME_free) + rev_date = self._create_asn1_time(builder._revocation_date) res = self._lib.X509_REVOKED_set_revocationDate(x509_revoked, rev_date) self.openssl_assert(res == 1) # add CRL entry extensions @@ -1136,7 +1166,10 @@ ) if x509 == self._ffi.NULL: self._consume_errors() - raise ValueError("Unable to load certificate") + raise ValueError( + "Unable to load certificate. See https://cryptography.io/en/la" + "test/faq/#why-can-t-i-import-my-pem-file for more details." + ) x509 = self._ffi.gc(x509, self._lib.X509_free) return _Certificate(self, x509) @@ -1158,7 +1191,10 @@ ) if x509_crl == self._ffi.NULL: self._consume_errors() - raise ValueError("Unable to load CRL") + raise ValueError( + "Unable to load CRL. See https://cryptography.io/en/la" + "test/faq/#why-can-t-i-import-my-pem-file for more details." + ) x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free) return _CertificateRevocationList(self, x509_crl) @@ -1180,7 +1216,10 @@ ) if x509_req == self._ffi.NULL: self._consume_errors() - raise ValueError("Unable to load request") + raise ValueError( + "Unable to load request. See https://cryptography.io/en/la" + "test/faq/#why-can-t-i-import-my-pem-file for more details." + ) x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free) return _CertificateSigningRequest(self, x509_req) @@ -1198,13 +1237,11 @@ def _load_key(self, openssl_read_func, convert_func, data, password): mem_bio = self._bytes_to_bio(data) - if password is not None and not isinstance(password, bytes): - raise TypeError("Password must be bytes") - userdata = self._ffi.new("CRYPTOGRAPHY_PASSWORD_DATA *") if password is not None: - password_buf = self._ffi.new("char []", password) - userdata.password = password_buf + utils._check_byteslike("password", password) + password_ptr = self._ffi.from_buffer(password) + userdata.password = password_ptr userdata.length = len(password) evp_pkey = openssl_read_func( @@ -1227,7 +1264,7 @@ else: assert userdata.error == -2 raise ValueError( - "Passwords longer than {0} bytes are not supported " + "Passwords longer than {} bytes are not supported " "by this backend.".format(userdata.maxsize - 1) ) else: @@ -1297,9 +1334,9 @@ except UnsupportedAlgorithm: curve_nid = self._lib.NID_undef - ctx = self._lib.EC_GROUP_new_by_curve_name(curve_nid) + group = self._lib.EC_GROUP_new_by_curve_name(curve_nid) - if ctx == self._ffi.NULL: + if group == self._ffi.NULL: errors = self._consume_errors() self.openssl_assert( curve_nid == self._lib.NID_undef or @@ -1311,7 +1348,7 @@ return False else: self.openssl_assert(curve_nid != self._lib.NID_undef) - self._lib.EC_GROUP_free(ctx) + self._lib.EC_GROUP_free(group) return True def elliptic_curve_signature_algorithm_supported( @@ -1329,11 +1366,7 @@ """ if self.elliptic_curve_supported(curve): - curve_nid = self._elliptic_curve_to_nid(curve) - - ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) - self.openssl_assert(ec_cdata != self._ffi.NULL) - ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + ec_cdata = self._ec_key_new_by_curve(curve) res = self._lib.EC_KEY_generate_key(ec_cdata) self.openssl_assert(res == 1) @@ -1343,50 +1376,58 @@ return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) else: raise UnsupportedAlgorithm( - "Backend object does not support {0}.".format(curve.name), + "Backend object does not support {}.".format(curve.name), _Reasons.UNSUPPORTED_ELLIPTIC_CURVE ) def load_elliptic_curve_private_numbers(self, numbers): public = numbers.public_numbers - curve_nid = self._elliptic_curve_to_nid(public.curve) - - ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) - self.openssl_assert(ec_cdata != self._ffi.NULL) - ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) - - ec_cdata = self._ec_key_set_public_key_affine_coordinates( - ec_cdata, public.x, public.y) + ec_cdata = self._ec_key_new_by_curve(public.curve) private_value = self._ffi.gc( - self._int_to_bn(numbers.private_value), self._lib.BN_free + self._int_to_bn(numbers.private_value), self._lib.BN_clear_free ) res = self._lib.EC_KEY_set_private_key(ec_cdata, private_value) self.openssl_assert(res == 1) + + ec_cdata = self._ec_key_set_public_key_affine_coordinates( + ec_cdata, public.x, public.y) + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) def load_elliptic_curve_public_numbers(self, numbers): - curve_nid = self._elliptic_curve_to_nid(numbers.curve) - - ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) - self.openssl_assert(ec_cdata != self._ffi.NULL) - ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) - + ec_cdata = self._ec_key_new_by_curve(numbers.curve) ec_cdata = self._ec_key_set_public_key_affine_coordinates( ec_cdata, numbers.x, numbers.y) evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) - def derive_elliptic_curve_private_key(self, private_value, curve): - curve_nid = self._elliptic_curve_to_nid(curve) + def load_elliptic_curve_public_bytes(self, curve, point_bytes): + ec_cdata = self._ec_key_new_by_curve(curve) + group = self._lib.EC_KEY_get0_group(ec_cdata) + self.openssl_assert(group != self._ffi.NULL) + point = self._lib.EC_POINT_new(group) + self.openssl_assert(point != self._ffi.NULL) + point = self._ffi.gc(point, self._lib.EC_POINT_free) + with self._tmp_bn_ctx() as bn_ctx: + res = self._lib.EC_POINT_oct2point( + group, point, point_bytes, len(point_bytes), bn_ctx + ) + if res != 1: + self._consume_errors() + raise ValueError("Invalid public bytes for the given curve") - ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) - self.openssl_assert(ec_cdata != self._ffi.NULL) - ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + res = self._lib.EC_KEY_set_public_key(ec_cdata, point) + self.openssl_assert(res == 1) + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) + + def derive_elliptic_curve_private_key(self, private_value, curve): + ec_cdata = self._ec_key_new_by_curve(curve) get_func, group = self._ec_key_determine_group_get_func(ec_cdata) @@ -1395,7 +1436,7 @@ point = self._ffi.gc(point, self._lib.EC_POINT_free) value = self._int_to_bn(private_value) - value = self._ffi.gc(value, self._lib.BN_free) + value = self._ffi.gc(value, self._lib.BN_clear_free) with self._tmp_bn_ctx() as bn_ctx: res = self._lib.EC_POINT_mul(group, point, value, self._ffi.NULL, @@ -1410,14 +1451,158 @@ res = self._lib.EC_KEY_set_public_key(ec_cdata, point) self.openssl_assert(res == 1) - res = self._lib.EC_KEY_set_private_key( - ec_cdata, self._int_to_bn(private_value)) + private = self._int_to_bn(private_value) + private = self._ffi.gc(private, self._lib.BN_clear_free) + res = self._lib.EC_KEY_set_private_key(ec_cdata, private) self.openssl_assert(res == 1) evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + def _ec_key_new_by_curve(self, curve): + curve_nid = self._elliptic_curve_to_nid(curve) + ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) + self.openssl_assert(ec_cdata != self._ffi.NULL) + return self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + + def load_der_ocsp_request(self, data): + mem_bio = self._bytes_to_bio(data) + request = self._lib.d2i_OCSP_REQUEST_bio(mem_bio.bio, self._ffi.NULL) + if request == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load OCSP request") + + request = self._ffi.gc(request, self._lib.OCSP_REQUEST_free) + return _OCSPRequest(self, request) + + def load_der_ocsp_response(self, data): + mem_bio = self._bytes_to_bio(data) + response = self._lib.d2i_OCSP_RESPONSE_bio(mem_bio.bio, self._ffi.NULL) + if response == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load OCSP response") + + response = self._ffi.gc(response, self._lib.OCSP_RESPONSE_free) + return _OCSPResponse(self, response) + + def create_ocsp_request(self, builder): + ocsp_req = self._lib.OCSP_REQUEST_new() + self.openssl_assert(ocsp_req != self._ffi.NULL) + ocsp_req = self._ffi.gc(ocsp_req, self._lib.OCSP_REQUEST_free) + cert, issuer, algorithm = builder._request + evp_md = self._evp_md_non_null_from_algorithm(algorithm) + certid = self._lib.OCSP_cert_to_id( + evp_md, cert._x509, issuer._x509 + ) + self.openssl_assert(certid != self._ffi.NULL) + onereq = self._lib.OCSP_request_add0_id(ocsp_req, certid) + self.openssl_assert(onereq != self._ffi.NULL) + self._create_x509_extensions( + extensions=builder._extensions, + handlers=_OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS, + x509_obj=ocsp_req, + add_func=self._lib.OCSP_REQUEST_add_ext, + gc=True, + ) + return _OCSPRequest(self, ocsp_req) + + def _create_ocsp_basic_response(self, builder, private_key, algorithm): + basic = self._lib.OCSP_BASICRESP_new() + self.openssl_assert(basic != self._ffi.NULL) + basic = self._ffi.gc(basic, self._lib.OCSP_BASICRESP_free) + evp_md = self._evp_md_non_null_from_algorithm( + builder._response._algorithm + ) + certid = self._lib.OCSP_cert_to_id( + evp_md, builder._response._cert._x509, + builder._response._issuer._x509 + ) + self.openssl_assert(certid != self._ffi.NULL) + certid = self._ffi.gc(certid, self._lib.OCSP_CERTID_free) + if builder._response._revocation_reason is None: + reason = -1 + else: + reason = _CRL_ENTRY_REASON_ENUM_TO_CODE[ + builder._response._revocation_reason + ] + if builder._response._revocation_time is None: + rev_time = self._ffi.NULL + else: + rev_time = self._create_asn1_time( + builder._response._revocation_time + ) + + next_update = self._ffi.NULL + if builder._response._next_update is not None: + next_update = self._create_asn1_time( + builder._response._next_update + ) + + this_update = self._create_asn1_time(builder._response._this_update) + + res = self._lib.OCSP_basic_add1_status( + basic, + certid, + builder._response._cert_status.value, + reason, + rev_time, + this_update, + next_update + ) + self.openssl_assert(res != self._ffi.NULL) + # okay, now sign the basic structure + evp_md = self._evp_md_non_null_from_algorithm(algorithm) + responder_cert, responder_encoding = builder._responder_id + flags = self._lib.OCSP_NOCERTS + if responder_encoding is ocsp.OCSPResponderEncoding.HASH: + flags |= self._lib.OCSP_RESPID_KEY + + if builder._certs is not None: + for cert in builder._certs: + res = self._lib.OCSP_basic_add1_cert(basic, cert._x509) + self.openssl_assert(res == 1) + + self._create_x509_extensions( + extensions=builder._extensions, + handlers=_OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS, + x509_obj=basic, + add_func=self._lib.OCSP_BASICRESP_add_ext, + gc=True, + ) + + res = self._lib.OCSP_basic_sign( + basic, responder_cert._x509, private_key._evp_pkey, + evp_md, self._ffi.NULL, flags + ) + if res != 1: + errors = self._consume_errors() + self.openssl_assert( + errors[0]._lib_reason_match( + self._lib.ERR_LIB_X509, + self._lib.X509_R_KEY_VALUES_MISMATCH + ) + ) + raise ValueError("responder_cert must be signed by private_key") + + return basic + + def create_ocsp_response(self, response_status, builder, private_key, + algorithm): + if response_status is ocsp.OCSPResponseStatus.SUCCESSFUL: + basic = self._create_ocsp_basic_response( + builder, private_key, algorithm + ) + else: + basic = self._ffi.NULL + + ocsp_resp = self._lib.OCSP_response_create( + response_status.value, basic + ) + self.openssl_assert(ocsp_resp != self._ffi.NULL) + ocsp_resp = self._ffi.gc(ocsp_resp, self._lib.OCSP_RESPONSE_free) + return _OCSPResponse(self, ocsp_resp) + def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve): return ( self.elliptic_curve_supported(curve) and @@ -1445,7 +1630,7 @@ curve_nid = self._lib.OBJ_sn2nid(curve_name.encode()) if curve_nid == self._lib.NID_undef: raise UnsupportedAlgorithm( - "{0} is not a supported elliptic curve".format(curve.name), + "{} is not a supported elliptic curve".format(curve.name), _Reasons.UNSUPPORTED_ELLIPTIC_CURVE ) return curve_nid @@ -1516,6 +1701,20 @@ "format must be an item from the PrivateFormat enum" ) + # X9.62 encoding is only valid for EC public keys + if encoding is serialization.Encoding.X962: + raise ValueError("X9.62 format is only valid for EC public keys") + + # Raw format and encoding are only valid for X25519, Ed25519, X448, and + # Ed448 keys. We capture those cases before this method is called so if + # we see those enum values here it means the caller has passed them to + # a key that doesn't support raw type + if format is serialization.PrivateFormat.Raw: + raise ValueError("raw format is invalid with this key or encoding") + + if encoding is serialization.Encoding.Raw: + raise ValueError("raw encoding is invalid with this key or format") + if not isinstance(encryption_algorithm, serialization.KeySerializationEncryption): raise TypeError( @@ -1575,7 +1774,7 @@ write_bio = self._lib.i2d_PKCS8PrivateKey_bio key = evp_pkey else: - raise TypeError("encoding must be an item from the Encoding enum") + raise TypeError("encoding must be Encoding.PEM or Encoding.DER") bio = self._create_mem_bio_gc() res = write_bio( @@ -1608,6 +1807,23 @@ if not isinstance(encoding, serialization.Encoding): raise TypeError("encoding must be an item from the Encoding enum") + # Compressed/UncompressedPoint are only valid for EC keys and those + # cases are handled by the ECPublicKey public_bytes method before this + # method is called + if format in (serialization.PublicFormat.UncompressedPoint, + serialization.PublicFormat.CompressedPoint): + raise ValueError("Point formats are not valid for this key type") + + # Raw format and encoding are only valid for X25519, Ed25519, X448, and + # Ed448 keys. We capture those cases before this method is called so if + # we see those enum values here it means the caller has passed them to + # a key that doesn't support raw type + if format is serialization.PublicFormat.Raw: + raise ValueError("raw format is invalid with this key or encoding") + + if encoding is serialization.Encoding.Raw: + raise ValueError("raw encoding is invalid with this key or format") + if ( format is serialization.PublicFormat.OpenSSH or encoding is serialization.Encoding.OpenSSH @@ -1652,19 +1868,19 @@ if isinstance(key, rsa.RSAPublicKey): public_numbers = key.public_numbers() return b"ssh-rsa " + base64.b64encode( - serialization._ssh_write_string(b"ssh-rsa") + - serialization._ssh_write_mpint(public_numbers.e) + - serialization._ssh_write_mpint(public_numbers.n) + ssh._ssh_write_string(b"ssh-rsa") + + ssh._ssh_write_mpint(public_numbers.e) + + ssh._ssh_write_mpint(public_numbers.n) ) elif isinstance(key, dsa.DSAPublicKey): public_numbers = key.public_numbers() parameter_numbers = public_numbers.parameter_numbers return b"ssh-dss " + base64.b64encode( - serialization._ssh_write_string(b"ssh-dss") + - serialization._ssh_write_mpint(parameter_numbers.p) + - serialization._ssh_write_mpint(parameter_numbers.q) + - serialization._ssh_write_mpint(parameter_numbers.g) + - serialization._ssh_write_mpint(public_numbers.y) + ssh._ssh_write_string(b"ssh-dss") + + ssh._ssh_write_mpint(parameter_numbers.p) + + ssh._ssh_write_mpint(parameter_numbers.q) + + ssh._ssh_write_mpint(parameter_numbers.g) + + ssh._ssh_write_mpint(public_numbers.y) ) else: assert isinstance(key, ec.EllipticCurvePublicKey) @@ -1680,10 +1896,15 @@ "Only SECP256R1, SECP384R1, and SECP521R1 curves are " "supported by the SSH public key format" ) + + point = key.public_bytes( + serialization.Encoding.X962, + serialization.PublicFormat.UncompressedPoint + ) return b"ecdsa-sha2-" + curve_name + b" " + base64.b64encode( - serialization._ssh_write_string(b"ecdsa-sha2-" + curve_name) + - serialization._ssh_write_string(curve_name) + - serialization._ssh_write_string(public_numbers.encode_point()) + ssh._ssh_write_string(b"ecdsa-sha2-" + curve_name) + + ssh._ssh_write_string(curve_name) + + ssh._ssh_write_string(point) ) def _parameter_bytes(self, encoding, format, cdata): @@ -1887,6 +2108,11 @@ return self._ffi.buffer(pp[0], res)[:] def x25519_load_public_bytes(self, data): + # When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 we can + # switch this to EVP_PKEY_new_raw_public_key + if len(data) != 32: + raise ValueError("An X25519 public key is 32 bytes long") + evp_pkey = self._create_evp_pkey_gc() res = self._lib.EVP_PKEY_set_type(evp_pkey, self._lib.NID_X25519) backend.openssl_assert(res == 1) @@ -1897,9 +2123,12 @@ return _X25519PublicKey(self, evp_pkey) def x25519_load_private_bytes(self, data): + # When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 we can + # switch this to EVP_PKEY_new_raw_private_key and drop the + # zeroed_bytearray garbage. # OpenSSL only has facilities for loading PKCS8 formatted private # keys using the algorithm identifiers specified in - # https://tools.ietf.org/html/draft-ietf-curdle-pkix-03. + # https://tools.ietf.org/html/draft-ietf-curdle-pkix-09. # This is the standard PKCS8 prefix for a 32 byte X25519 key. # The form is: # 0:d=0 hl=2 l= 46 cons: SEQUENCE @@ -1910,21 +2139,27 @@ # Of course there's a bit more complexity. In reality OCTET STRING # contains an OCTET STRING of length 32! So the last two bytes here # are \x04\x20, which is an OCTET STRING of length 32. + if len(data) != 32: + raise ValueError("An X25519 private key is 32 bytes long") + pkcs8_prefix = b'0.\x02\x01\x000\x05\x06\x03+en\x04"\x04 ' - bio = self._bytes_to_bio(pkcs8_prefix + data) - evp_pkey = backend._lib.d2i_PrivateKey_bio(bio.bio, self._ffi.NULL) + with self._zeroed_bytearray(48) as ba: + ba[0:16] = pkcs8_prefix + ba[16:] = data + bio = self._bytes_to_bio(ba) + evp_pkey = backend._lib.d2i_PrivateKey_bio(bio.bio, self._ffi.NULL) + self.openssl_assert(evp_pkey != self._ffi.NULL) evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + self.openssl_assert( + self._lib.EVP_PKEY_id(evp_pkey) == self._lib.EVP_PKEY_X25519 + ) return _X25519PrivateKey(self, evp_pkey) - def x25519_generate_key(self): - evp_pkey_ctx = self._lib.EVP_PKEY_CTX_new_id( - self._lib.NID_X25519, self._ffi.NULL - ) + def _evp_pkey_keygen_gc(self, nid): + evp_pkey_ctx = self._lib.EVP_PKEY_CTX_new_id(nid, self._ffi.NULL) self.openssl_assert(evp_pkey_ctx != self._ffi.NULL) - evp_pkey_ctx = self._ffi.gc( - evp_pkey_ctx, self._lib.EVP_PKEY_CTX_free - ) + evp_pkey_ctx = self._ffi.gc(evp_pkey_ctx, self._lib.EVP_PKEY_CTX_free) res = self._lib.EVP_PKEY_keygen_init(evp_pkey_ctx) self.openssl_assert(res == 1) evp_ppkey = self._ffi.new("EVP_PKEY **") @@ -1932,18 +2167,143 @@ self.openssl_assert(res == 1) self.openssl_assert(evp_ppkey[0] != self._ffi.NULL) evp_pkey = self._ffi.gc(evp_ppkey[0], self._lib.EVP_PKEY_free) + return evp_pkey + + def x25519_generate_key(self): + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_X25519) return _X25519PrivateKey(self, evp_pkey) def x25519_supported(self): return self._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER + def x448_load_public_bytes(self, data): + if len(data) != 56: + raise ValueError("An X448 public key is 56 bytes long") + + evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( + self._lib.NID_X448, self._ffi.NULL, data, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return _X448PublicKey(self, evp_pkey) + + def x448_load_private_bytes(self, data): + if len(data) != 56: + raise ValueError("An X448 private key is 56 bytes long") + + data_ptr = self._ffi.from_buffer(data) + evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( + self._lib.NID_X448, self._ffi.NULL, data_ptr, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return _X448PrivateKey(self, evp_pkey) + + def x448_generate_key(self): + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_X448) + return _X448PrivateKey(self, evp_pkey) + + def x448_supported(self): + return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 + + def ed25519_supported(self): + return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B + + def ed25519_load_public_bytes(self, data): + utils._check_bytes("data", data) + + if len(data) != ed25519._ED25519_KEY_SIZE: + raise ValueError("An Ed25519 public key is 32 bytes long") + + evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( + self._lib.NID_ED25519, self._ffi.NULL, data, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed25519PublicKey(self, evp_pkey) + + def ed25519_load_private_bytes(self, data): + if len(data) != ed25519._ED25519_KEY_SIZE: + raise ValueError("An Ed25519 private key is 32 bytes long") + + utils._check_byteslike("data", data) + data_ptr = self._ffi.from_buffer(data) + evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( + self._lib.NID_ED25519, self._ffi.NULL, data_ptr, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed25519PrivateKey(self, evp_pkey) + + def ed25519_generate_key(self): + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED25519) + return _Ed25519PrivateKey(self, evp_pkey) + + def ed448_supported(self): + return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B + + def ed448_load_public_bytes(self, data): + utils._check_bytes("data", data) + if len(data) != _ED448_KEY_SIZE: + raise ValueError("An Ed448 public key is 57 bytes long") + + evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( + self._lib.NID_ED448, self._ffi.NULL, data, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed448PublicKey(self, evp_pkey) + + def ed448_load_private_bytes(self, data): + utils._check_byteslike("data", data) + if len(data) != _ED448_KEY_SIZE: + raise ValueError("An Ed448 private key is 57 bytes long") + + data_ptr = self._ffi.from_buffer(data) + evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( + self._lib.NID_ED448, self._ffi.NULL, data_ptr, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed448PrivateKey(self, evp_pkey) + + def ed448_generate_key(self): + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED448) + return _Ed448PrivateKey(self, evp_pkey) + def derive_scrypt(self, key_material, salt, length, n, r, p): buf = self._ffi.new("unsigned char[]", length) + key_material_ptr = self._ffi.from_buffer(key_material) res = self._lib.EVP_PBE_scrypt( - key_material, len(key_material), salt, len(salt), n, r, p, + key_material_ptr, len(key_material), salt, len(salt), n, r, p, scrypt._MEM_LIMIT, buf, length ) - self.openssl_assert(res == 1) + if res != 1: + errors = self._consume_errors() + if not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111: + # This error is only added to the stack in 1.1.1+ + self.openssl_assert( + errors[0]._lib_reason_match( + self._lib.ERR_LIB_EVP, + self._lib.ERR_R_MALLOC_FAILURE + ) or + errors[0]._lib_reason_match( + self._lib.ERR_LIB_EVP, + self._lib.EVP_R_MEMORY_LIMIT_EXCEEDED + ) + ) + + # memory required formula explained here: + # https://blog.filippo.io/the-scrypt-parameters/ + min_memory = 128 * n * r // (1024**2) + raise MemoryError( + "Not enough memory to derive key. These parameters require" + " {} MB of memory.".format(min_memory) + ) return self._ffi.buffer(buf)[:] def aead_cipher_supported(self, cipher): @@ -1952,6 +2312,95 @@ self._lib.EVP_get_cipherbyname(cipher_name) != self._ffi.NULL ) + @contextlib.contextmanager + def _zeroed_bytearray(self, length): + """ + This method creates a bytearray, which we copy data into (hopefully + also from a mutable buffer that can be dynamically erased!), and then + zero when we're done. + """ + ba = bytearray(length) + try: + yield ba + finally: + self._zero_data(ba, length) + + def _zero_data(self, data, length): + # We clear things this way because at the moment we're not + # sure of a better way that can guarantee it overwrites the + # memory of a bytearray and doesn't just replace the underlying char *. + for i in range(length): + data[i] = 0 + + @contextlib.contextmanager + def _zeroed_null_terminated_buf(self, data): + """ + This method takes bytes, which can be a bytestring or a mutable + buffer like a bytearray, and yields a null-terminated version of that + data. This is required because PKCS12_parse doesn't take a length with + its password char * and ffi.from_buffer doesn't provide null + termination. So, to support zeroing the data via bytearray we + need to build this ridiculous construct that copies the memory, but + zeroes it after use. + """ + if data is None: + yield self._ffi.NULL + else: + data_len = len(data) + buf = self._ffi.new("char[]", data_len + 1) + self._ffi.memmove(buf, data, data_len) + try: + yield buf + finally: + # Cast to a uint8_t * so we can assign by integer + self._zero_data(self._ffi.cast("uint8_t *", buf), data_len) + + def load_key_and_certificates_from_pkcs12(self, data, password): + if password is not None: + utils._check_byteslike("password", password) + + bio = self._bytes_to_bio(data) + p12 = self._lib.d2i_PKCS12_bio(bio.bio, self._ffi.NULL) + if p12 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Could not deserialize PKCS12 data") + + p12 = self._ffi.gc(p12, self._lib.PKCS12_free) + evp_pkey_ptr = self._ffi.new("EVP_PKEY **") + x509_ptr = self._ffi.new("X509 **") + sk_x509_ptr = self._ffi.new("Cryptography_STACK_OF_X509 **") + with self._zeroed_null_terminated_buf(password) as password_buf: + res = self._lib.PKCS12_parse( + p12, password_buf, evp_pkey_ptr, x509_ptr, sk_x509_ptr + ) + + if res == 0: + self._consume_errors() + raise ValueError("Invalid password or PKCS12 data") + + cert = None + key = None + additional_certificates = [] + + if evp_pkey_ptr[0] != self._ffi.NULL: + evp_pkey = self._ffi.gc(evp_pkey_ptr[0], self._lib.EVP_PKEY_free) + key = self._evp_pkey_to_private_key(evp_pkey) + + if x509_ptr[0] != self._ffi.NULL: + x509 = self._ffi.gc(x509_ptr[0], self._lib.X509_free) + cert = _Certificate(self, x509) + + if sk_x509_ptr[0] != self._ffi.NULL: + sk_x509 = self._ffi.gc(sk_x509_ptr[0], self._lib.sk_X509_free) + num = self._lib.sk_X509_num(sk_x509_ptr[0]) + for i in range(num): + x509 = self._lib.sk_X509_value(sk_x509, i) + x509 = self._ffi.gc(x509, self._lib.X509_free) + self.openssl_assert(x509 != self._ffi.NULL) + additional_certificates.append(_Certificate(self, x509)) + + return (key, cert, additional_certificates) + class GetCipherByName(object): def __init__(self, fmt): @@ -1963,7 +2412,7 @@ def _get_xts_cipher(backend, cipher, mode): - cipher_name = "aes-{0}-xts".format(cipher.key_size // 2) + cipher_name = "aes-{}-xts".format(cipher.key_size // 2) return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/ciphers.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/ciphers.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/ciphers.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/ciphers.py 2019-02-27 23:27:53.000000000 +0000 @@ -40,7 +40,7 @@ adapter = registry[type(cipher), type(mode)] except KeyError: raise UnsupportedAlgorithm( - "cipher {0} in {1} mode is not supported " + "cipher {} in {} mode is not supported " "by this backend.".format( cipher.name, mode.name if mode else mode), _Reasons.UNSUPPORTED_CIPHER @@ -48,21 +48,25 @@ evp_cipher = adapter(self._backend, cipher, mode) if evp_cipher == self._backend._ffi.NULL: - raise UnsupportedAlgorithm( - "cipher {0} in {1} mode is not supported " - "by this backend.".format( - cipher.name, mode.name if mode else mode), - _Reasons.UNSUPPORTED_CIPHER - ) + msg = "cipher {0.name} ".format(cipher) + if mode is not None: + msg += "in {0.name} mode ".format(mode) + msg += ( + "is not supported by this backend (Your version of OpenSSL " + "may be too old. Current version: {}.)" + ).format(self._backend.openssl_version_text()) + raise UnsupportedAlgorithm(msg, _Reasons.UNSUPPORTED_CIPHER) if isinstance(mode, modes.ModeWithInitializationVector): - iv_nonce = mode.initialization_vector + iv_nonce = self._backend._ffi.from_buffer( + mode.initialization_vector + ) elif isinstance(mode, modes.ModeWithTweak): - iv_nonce = mode.tweak + iv_nonce = self._backend._ffi.from_buffer(mode.tweak) elif isinstance(mode, modes.ModeWithNonce): - iv_nonce = mode.nonce + iv_nonce = self._backend._ffi.from_buffer(mode.nonce) elif isinstance(cipher, modes.ModeWithNonce): - iv_nonce = cipher.nonce + iv_nonce = self._backend._ffi.from_buffer(cipher.nonce) else: iv_nonce = self._backend._ffi.NULL # begin init with cipher and operation type @@ -105,7 +109,7 @@ ctx, self._backend._ffi.NULL, self._backend._ffi.NULL, - cipher.key, + self._backend._ffi.from_buffer(cipher.key), iv_nonce, operation ) @@ -123,7 +127,7 @@ def update_into(self, data, buf): if len(buf) < (len(data) + self._block_size_bytes - 1): raise ValueError( - "buffer must be at least {0} bytes for this " + "buffer must be at least {} bytes for this " "payload".format(len(data) + self._block_size_bytes - 1) ) @@ -131,8 +135,10 @@ "unsigned char *", self._backend._ffi.from_buffer(buf) ) outlen = self._backend._ffi.new("int *") - res = self._backend._lib.EVP_CipherUpdate(self._ctx, buf, outlen, - data, len(data)) + res = self._backend._lib.EVP_CipherUpdate( + self._ctx, buf, outlen, + self._backend._ffi.from_buffer(data), len(data) + ) self._backend.openssl_assert(res != 0) return outlen[0] @@ -167,9 +173,6 @@ errors[0]._lib_reason_match( self._backend._lib.ERR_LIB_EVP, self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH - ) or errors[0]._lib_reason_match( - self._backend._lib.ERR_LIB_EVP, - self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH ) ) raise ValueError( @@ -202,6 +205,11 @@ "finalize_with_tag requires OpenSSL >= 1.0.2. To use this " "method please update OpenSSL" ) + if len(tag) < self._mode._min_tag_length: + raise ValueError( + "Authentication tag must be {} bytes or longer.".format( + self._mode._min_tag_length) + ) res = self._backend._lib.EVP_CIPHER_CTX_ctrl( self._ctx, self._backend._lib.EVP_CTRL_AEAD_SET_TAG, len(tag), tag @@ -213,7 +221,8 @@ def authenticate_additional_data(self, data): outlen = self._backend._ffi.new("int *") res = self._backend._lib.EVP_CipherUpdate( - self._ctx, self._backend._ffi.NULL, outlen, data, len(data) + self._ctx, self._backend._ffi.NULL, outlen, + self._backend._ffi.from_buffer(data), len(data) ) self._backend.openssl_assert(res != 0) diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/cmac.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/cmac.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/cmac.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/cmac.py 2019-02-27 23:27:53.000000000 +0000 @@ -36,10 +36,12 @@ self._backend.openssl_assert(ctx != self._backend._ffi.NULL) ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free) - self._backend._lib.CMAC_Init( - ctx, self._key, len(self._key), + key_ptr = self._backend._ffi.from_buffer(self._key) + res = self._backend._lib.CMAC_Init( + ctx, key_ptr, len(self._key), evp_cipher, self._backend._ffi.NULL ) + self._backend.openssl_assert(res == 1) self._ctx = ctx diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/decode_asn1.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/decode_asn1.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/decode_asn1.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/decode_asn1.py 2019-02-27 23:27:53.000000000 +0000 @@ -7,18 +7,21 @@ import datetime import ipaddress -from asn1crypto.core import Integer, SequenceOf +import asn1crypto.core + +import six from cryptography import x509 from cryptography.x509.extensions import _TLS_FEATURE_TYPE_TO_ENUM from cryptography.x509.name import _ASN1_TYPE_TO_ENUM from cryptography.x509.oid import ( - CRLEntryExtensionOID, CertificatePoliciesOID, ExtensionOID + CRLEntryExtensionOID, CertificatePoliciesOID, ExtensionOID, + OCSPExtensionOID, ) -class _Integers(SequenceOf): - _child_spec = Integer +class _Integers(asn1crypto.core.SequenceOf): + _child_spec = asn1crypto.core.Integer def _obj2txt(backend, obj): @@ -132,7 +135,7 @@ if "1" in bits[prefix:]: raise ValueError("Invalid netmask") - ip = ipaddress.ip_network(base.exploded + u"/{0}".format(prefix)) + ip = ipaddress.ip_network(base.exploded + u"/{}".format(prefix)) else: ip = ipaddress.ip_address(data) @@ -157,7 +160,7 @@ else: # x400Address or ediPartyName raise x509.UnsupportedGeneralNameType( - "{0} is not a supported type".format( + "{} is not a supported type".format( x509._GENERAL_NAMES.get(gn.type, gn.type) ), gn.type @@ -199,11 +202,11 @@ ) if oid in seen_oids: raise x509.DuplicateExtension( - "Duplicate {0} extension found".format(oid), oid + "Duplicate {} extension found".format(oid), oid ) - # This OID is only supported in OpenSSL 1.1.0+ but we want - # to support it in all versions of OpenSSL so we decode it + # These OIDs are only supported in OpenSSL 1.1.0+ but we want + # to support them in all versions of OpenSSL so we decode them # ourselves. if oid == ExtensionOID.TLS_FEATURE: data = backend._lib.X509_EXTENSION_get_data(ext) @@ -214,6 +217,17 @@ extensions.append(x509.Extension(oid, critical, value)) seen_oids.add(oid) continue + elif oid == ExtensionOID.PRECERT_POISON: + data = backend._lib.X509_EXTENSION_get_data(ext) + parsed = asn1crypto.core.Null.load( + _asn1_string_to_bytes(backend, data) + ) + assert parsed == asn1crypto.core.Null() + extensions.append(x509.Extension( + oid, critical, x509.PrecertPoison() + )) + seen_oids.add(oid) + continue try: handler = self.handlers[oid] @@ -231,7 +245,7 @@ if ext_data == backend._ffi.NULL: backend._consume_errors() raise ValueError( - "The {0} extension is invalid and can't be " + "The {} extension is invalid and can't be " "parsed".format(oid) ) @@ -450,6 +464,30 @@ return subtrees +def _decode_issuing_dist_point(backend, idp): + idp = backend._ffi.cast("ISSUING_DIST_POINT *", idp) + idp = backend._ffi.gc(idp, backend._lib.ISSUING_DIST_POINT_free) + if idp.distpoint != backend._ffi.NULL: + full_name, relative_name = _decode_distpoint(backend, idp.distpoint) + else: + full_name = None + relative_name = None + + only_user = idp.onlyuser == 255 + only_ca = idp.onlyCA == 255 + indirect_crl = idp.indirectCRL == 255 + only_attr = idp.onlyattr == 255 + if idp.onlysomereasons != backend._ffi.NULL: + only_some_reasons = _decode_reasons(backend, idp.onlysomereasons) + else: + only_some_reasons = None + + return x509.IssuingDistributionPoint( + full_name, relative_name, only_user, only_ca, only_some_reasons, + indirect_crl, only_attr + ) + + def _decode_policy_constraints(backend, pc): pc = backend._ffi.cast("POLICY_CONSTRAINTS *", pc) pc = backend._ffi.gc(pc, backend._lib.POLICY_CONSTRAINTS_free) @@ -498,44 +536,7 @@ reasons = None cdp = backend._lib.sk_DIST_POINT_value(cdps, i) if cdp.reasons != backend._ffi.NULL: - # We will check each bit from RFC 5280 - # ReasonFlags ::= BIT STRING { - # unused (0), - # keyCompromise (1), - # cACompromise (2), - # affiliationChanged (3), - # superseded (4), - # cessationOfOperation (5), - # certificateHold (6), - # privilegeWithdrawn (7), - # aACompromise (8) } - reasons = [] - get_bit = backend._lib.ASN1_BIT_STRING_get_bit - if get_bit(cdp.reasons, 1): - reasons.append(x509.ReasonFlags.key_compromise) - - if get_bit(cdp.reasons, 2): - reasons.append(x509.ReasonFlags.ca_compromise) - - if get_bit(cdp.reasons, 3): - reasons.append(x509.ReasonFlags.affiliation_changed) - - if get_bit(cdp.reasons, 4): - reasons.append(x509.ReasonFlags.superseded) - - if get_bit(cdp.reasons, 5): - reasons.append(x509.ReasonFlags.cessation_of_operation) - - if get_bit(cdp.reasons, 6): - reasons.append(x509.ReasonFlags.certificate_hold) - - if get_bit(cdp.reasons, 7): - reasons.append(x509.ReasonFlags.privilege_withdrawn) - - if get_bit(cdp.reasons, 8): - reasons.append(x509.ReasonFlags.aa_compromise) - - reasons = frozenset(reasons) + reasons = _decode_reasons(backend, cdp.reasons) if cdp.CRLissuer != backend._ffi.NULL: crl_issuer = _decode_general_names(backend, cdp.CRLissuer) @@ -543,32 +544,9 @@ # Certificates may have a crl_issuer/reasons and no distribution # point so make sure it's not null. if cdp.distpoint != backend._ffi.NULL: - # Type 0 is fullName, there is no #define for it in the code. - if cdp.distpoint.type == _DISTPOINT_TYPE_FULLNAME: - full_name = _decode_general_names( - backend, cdp.distpoint.name.fullname - ) - # OpenSSL code doesn't test for a specific type for - # relativename, everything that isn't fullname is considered - # relativename. Per RFC 5280: - # - # DistributionPointName ::= CHOICE { - # fullName [0] GeneralNames, - # nameRelativeToCRLIssuer [1] RelativeDistinguishedName } - else: - rns = cdp.distpoint.name.relativename - rnum = backend._lib.sk_X509_NAME_ENTRY_num(rns) - attributes = set() - for i in range(rnum): - rn = backend._lib.sk_X509_NAME_ENTRY_value( - rns, i - ) - backend.openssl_assert(rn != backend._ffi.NULL) - attributes.add( - _decode_x509_name_entry(backend, rn) - ) - - relative_name = x509.RelativeDistinguishedName(attributes) + full_name, relative_name = _decode_distpoint( + backend, cdp.distpoint + ) dist_points.append( x509.DistributionPoint( @@ -579,6 +557,67 @@ return dist_points +# ReasonFlags ::= BIT STRING { +# unused (0), +# keyCompromise (1), +# cACompromise (2), +# affiliationChanged (3), +# superseded (4), +# cessationOfOperation (5), +# certificateHold (6), +# privilegeWithdrawn (7), +# aACompromise (8) } +_REASON_BIT_MAPPING = { + 1: x509.ReasonFlags.key_compromise, + 2: x509.ReasonFlags.ca_compromise, + 3: x509.ReasonFlags.affiliation_changed, + 4: x509.ReasonFlags.superseded, + 5: x509.ReasonFlags.cessation_of_operation, + 6: x509.ReasonFlags.certificate_hold, + 7: x509.ReasonFlags.privilege_withdrawn, + 8: x509.ReasonFlags.aa_compromise, +} + + +def _decode_reasons(backend, reasons): + # We will check each bit from RFC 5280 + enum_reasons = [] + for bit_position, reason in six.iteritems(_REASON_BIT_MAPPING): + if backend._lib.ASN1_BIT_STRING_get_bit(reasons, bit_position): + enum_reasons.append(reason) + + return frozenset(enum_reasons) + + +def _decode_distpoint(backend, distpoint): + if distpoint.type == _DISTPOINT_TYPE_FULLNAME: + full_name = _decode_general_names(backend, distpoint.name.fullname) + return full_name, None + + # OpenSSL code doesn't test for a specific type for + # relativename, everything that isn't fullname is considered + # relativename. Per RFC 5280: + # + # DistributionPointName ::= CHOICE { + # fullName [0] GeneralNames, + # nameRelativeToCRLIssuer [1] RelativeDistinguishedName } + rns = distpoint.name.relativename + rnum = backend._lib.sk_X509_NAME_ENTRY_num(rns) + attributes = set() + for i in range(rnum): + rn = backend._lib.sk_X509_NAME_ENTRY_value( + rns, i + ) + backend.openssl_assert(rn != backend._ffi.NULL) + attributes.add( + _decode_x509_name_entry(backend, rn) + ) + + relative_name = x509.RelativeDistinguishedName(attributes) + + return None, relative_name + + def _decode_crl_distribution_points(backend, cdps): dist_points = _decode_dist_points(backend, cdps) return x509.CRLDistributionPoints(dist_points) @@ -659,7 +698,7 @@ try: return x509.CRLReason(_CRL_ENTRY_REASON_CODE_TO_ENUM[code]) except KeyError: - raise ValueError("Unsupported reason code: {0}".format(code)) + raise ValueError("Unsupported reason code: {}".format(code)) def _decode_invalidity_date(backend, inv_date): @@ -719,7 +758,7 @@ res = backend._lib.ASN1_STRING_to_UTF8(buf, asn1_string) if res == -1: raise ValueError( - "Unsupported ASN1 string type. Type: {0}".format(asn1_string.type) + "Unsupported ASN1 string type. Type: {}".format(asn1_string.type) ) backend.openssl_assert(buf[0] != backend._ffi.NULL) @@ -734,7 +773,13 @@ generalized_time = backend._lib.ASN1_TIME_to_generalizedtime( asn1_time, backend._ffi.NULL ) - backend.openssl_assert(generalized_time != backend._ffi.NULL) + if generalized_time == backend._ffi.NULL: + raise ValueError( + "Couldn't parse ASN.1 time as generalizedtime {!r}".format( + _asn1_string_to_bytes(backend, asn1_time) + ) + ) + generalized_time = backend._ffi.gc( generalized_time, backend._lib.ASN1_GENERALIZEDTIME_free ) @@ -748,6 +793,12 @@ return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ") +def _decode_nonce(backend, nonce): + nonce = backend._ffi.cast("ASN1_OCTET_STRING *", nonce) + nonce = backend._ffi.gc(nonce, backend._lib.ASN1_OCTET_STRING_free) + return x509.OCSPNonce(_asn1_string_to_bytes(backend, nonce)) + + _EXTENSION_HANDLERS_NO_SCT = { ExtensionOID.BASIC_CONSTRAINTS: _decode_basic_constraints, ExtensionOID.SUBJECT_KEY_IDENTIFIER: _decode_subject_key_identifier, @@ -787,6 +838,15 @@ ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( _decode_authority_information_access ), + ExtensionOID.ISSUING_DISTRIBUTION_POINT: _decode_issuing_dist_point, +} + +_OCSP_REQ_EXTENSION_HANDLERS = { + OCSPExtensionOID.NONCE: _decode_nonce, +} + +_OCSP_BASICRESP_EXTENSION_HANDLERS = { + OCSPExtensionOID.NONCE: _decode_nonce, } _CERTIFICATE_EXTENSION_PARSER_NO_SCT = _X509ExtensionParser( @@ -818,3 +878,15 @@ get_ext=lambda backend, x, i: backend._lib.X509_CRL_get_ext(x, i), handlers=_CRL_EXTENSION_HANDLERS, ) + +_OCSP_REQ_EXT_PARSER = _X509ExtensionParser( + ext_count=lambda backend, x: backend._lib.OCSP_REQUEST_get_ext_count(x), + get_ext=lambda backend, x, i: backend._lib.OCSP_REQUEST_get_ext(x, i), + handlers=_OCSP_REQ_EXTENSION_HANDLERS, +) + +_OCSP_BASICRESP_EXT_PARSER = _X509ExtensionParser( + ext_count=lambda backend, x: backend._lib.OCSP_BASICRESP_get_ext_count(x), + get_ext=lambda backend, x, i: backend._lib.OCSP_BASICRESP_get_ext(x, i), + handlers=_OCSP_BASICRESP_EXTENSION_HANDLERS, +) diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/dh.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/dh.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/dh.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/dh.py 2019-02-27 23:27:53.000000000 +0000 @@ -17,7 +17,7 @@ param_cdata = lib.DHparams_dup(dh_cdata) backend.openssl_assert(param_cdata != ffi.NULL) param_cdata = ffi.gc(param_cdata, lib.DH_free) - if lib.OPENSSL_VERSION_NUMBER < 0x10002000 or lib.CRYPTOGRAPHY_IS_LIBRESSL: + if lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102: # In OpenSSL versions < 1.0.2 or libressl DHparams_dup don't copy q q = ffi.new("BIGNUM **") lib.DH_get0_pqg(dh_cdata, ffi.NULL, q, ffi.NULL) diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/dsa.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/dsa.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/dsa.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/dsa.py 2019-02-27 23:27:53.000000000 +0000 @@ -211,8 +211,7 @@ def verifier(self, signature, signature_algorithm): _warn_sign_verify_deprecated() - if not isinstance(signature, bytes): - raise TypeError("signature must be bytes.") + utils._check_bytes("signature", signature) _check_not_prehashed(signature_algorithm) return _DSAVerificationContext( diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/ec.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/ec.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/ec.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/ec.py 2019-02-27 23:27:53.000000000 +0000 @@ -62,7 +62,7 @@ return ec._CURVE_TYPES[sn]() except KeyError: raise UnsupportedAlgorithm( - "{0} is not a supported elliptic curve".format(sn), + "{} is not a supported elliptic curve".format(sn), _Reasons.UNSUPPORTED_ELLIPTIC_CURVE ) @@ -244,8 +244,7 @@ def verifier(self, signature, signature_algorithm): _warn_sign_verify_deprecated() - if not isinstance(signature, bytes): - raise TypeError("signature must be bytes.") + utils._check_bytes("signature", signature) _check_signature_algorithm(signature_algorithm) _check_not_prehashed(signature_algorithm.algorithm) @@ -276,19 +275,62 @@ curve=self._curve ) + def _encode_point(self, format): + if format is serialization.PublicFormat.CompressedPoint: + conversion = self._backend._lib.POINT_CONVERSION_COMPRESSED + else: + assert format is serialization.PublicFormat.UncompressedPoint + conversion = self._backend._lib.POINT_CONVERSION_UNCOMPRESSED + + group = self._backend._lib.EC_KEY_get0_group(self._ec_key) + self._backend.openssl_assert(group != self._backend._ffi.NULL) + point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) + self._backend.openssl_assert(point != self._backend._ffi.NULL) + with self._backend._tmp_bn_ctx() as bn_ctx: + buflen = self._backend._lib.EC_POINT_point2oct( + group, point, conversion, self._backend._ffi.NULL, 0, bn_ctx + ) + self._backend.openssl_assert(buflen > 0) + buf = self._backend._ffi.new("char[]", buflen) + res = self._backend._lib.EC_POINT_point2oct( + group, point, conversion, buf, buflen, bn_ctx + ) + self._backend.openssl_assert(buflen == res) + + return self._backend._ffi.buffer(buf)[:] + def public_bytes(self, encoding, format): if format is serialization.PublicFormat.PKCS1: raise ValueError( "EC public keys do not support PKCS1 serialization" ) - return self._backend._public_key_bytes( - encoding, - format, - self, - self._evp_pkey, - None - ) + if ( + encoding is serialization.Encoding.X962 or + format is serialization.PublicFormat.CompressedPoint or + format is serialization.PublicFormat.UncompressedPoint + ): + if ( + encoding is not serialization.Encoding.X962 or + format not in ( + serialization.PublicFormat.CompressedPoint, + serialization.PublicFormat.UncompressedPoint + ) + ): + raise ValueError( + "X962 encoding must be used with CompressedPoint or " + "UncompressedPoint format" + ) + + return self._encode_point(format) + else: + return self._backend._public_key_bytes( + encoding, + format, + self, + self._evp_pkey, + None + ) def verify(self, signature, data, signature_algorithm): _check_signature_algorithm(signature_algorithm) diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/ed25519.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/ed25519.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/ed25519.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/ed25519.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,151 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import exceptions, utils +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.ed25519 import ( + Ed25519PrivateKey, Ed25519PublicKey, _ED25519_KEY_SIZE, _ED25519_SIG_SIZE +) + + +@utils.register_interface(Ed25519PublicKey) +class _Ed25519PublicKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes(self, encoding, format): + if ( + encoding is serialization.Encoding.Raw or + format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw or + format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + if ( + encoding in serialization._PEM_DER and + format is not serialization.PublicFormat.SubjectPublicKeyInfo + ): + raise ValueError( + "format must be SubjectPublicKeyInfo when encoding is PEM or " + "DER" + ) + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:] + + def verify(self, signature, data): + evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestVerifyInit( + evp_md_ctx, self._backend._ffi.NULL, self._backend._ffi.NULL, + self._backend._ffi.NULL, self._evp_pkey + ) + self._backend.openssl_assert(res == 1) + res = self._backend._lib.EVP_DigestVerify( + evp_md_ctx, signature, len(signature), data, len(data) + ) + if res != 1: + self._backend._consume_errors() + raise exceptions.InvalidSignature + + +@utils.register_interface(Ed25519PrivateKey) +class _Ed25519PrivateKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self): + buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) + public_bytes = self._backend._ffi.buffer(buf)[:] + return self._backend.ed25519_load_public_bytes(public_bytes) + + def sign(self, data): + evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestSignInit( + evp_md_ctx, self._backend._ffi.NULL, self._backend._ffi.NULL, + self._backend._ffi.NULL, self._evp_pkey + ) + self._backend.openssl_assert(res == 1) + buf = self._backend._ffi.new("unsigned char[]", _ED25519_SIG_SIZE) + buflen = self._backend._ffi.new("size_t *", len(buf)) + res = self._backend._lib.EVP_DigestSign( + evp_md_ctx, buf, buflen, data, len(data) + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_SIG_SIZE) + return self._backend._ffi.buffer(buf, buflen[0])[:] + + def private_bytes(self, encoding, format, encryption_algorithm): + if ( + encoding is serialization.Encoding.Raw or + format is serialization.PublicFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw or + encoding is not serialization.Encoding.Raw or not + isinstance(encryption_algorithm, serialization.NoEncryption) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption" + ) + + return self._raw_private_bytes() + + if ( + encoding in serialization._PEM_DER and + format is not serialization.PrivateFormat.PKCS8 + ): + raise ValueError( + "format must be PKCS8 when encoding is PEM or DER" + ) + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self._evp_pkey, None + ) + + def _raw_private_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_private_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:] diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/ed448.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/ed448.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/ed448.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/ed448.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,154 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import exceptions, utils +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.ed448 import ( + Ed448PrivateKey, Ed448PublicKey +) + +_ED448_KEY_SIZE = 57 +_ED448_SIG_SIZE = 114 + + +@utils.register_interface(Ed448PublicKey) +class _Ed448PublicKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes(self, encoding, format): + if ( + encoding is serialization.Encoding.Raw or + format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw or + format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + if ( + encoding in serialization._PEM_DER and + format is not serialization.PublicFormat.SubjectPublicKeyInfo + ): + raise ValueError( + "format must be SubjectPublicKeyInfo when encoding is PEM or " + "DER" + ) + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:] + + def verify(self, signature, data): + evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestVerifyInit( + evp_md_ctx, self._backend._ffi.NULL, self._backend._ffi.NULL, + self._backend._ffi.NULL, self._evp_pkey + ) + self._backend.openssl_assert(res == 1) + res = self._backend._lib.EVP_DigestVerify( + evp_md_ctx, signature, len(signature), data, len(data) + ) + if res != 1: + self._backend._consume_errors() + raise exceptions.InvalidSignature + + +@utils.register_interface(Ed448PrivateKey) +class _Ed448PrivateKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self): + buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) + public_bytes = self._backend._ffi.buffer(buf)[:] + return self._backend.ed448_load_public_bytes(public_bytes) + + def sign(self, data): + evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestSignInit( + evp_md_ctx, self._backend._ffi.NULL, self._backend._ffi.NULL, + self._backend._ffi.NULL, self._evp_pkey + ) + self._backend.openssl_assert(res == 1) + buf = self._backend._ffi.new("unsigned char[]", _ED448_SIG_SIZE) + buflen = self._backend._ffi.new("size_t *", len(buf)) + res = self._backend._lib.EVP_DigestSign( + evp_md_ctx, buf, buflen, data, len(data) + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_SIG_SIZE) + return self._backend._ffi.buffer(buf, buflen[0])[:] + + def private_bytes(self, encoding, format, encryption_algorithm): + if ( + encoding is serialization.Encoding.Raw or + format is serialization.PublicFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw or + encoding is not serialization.Encoding.Raw or not + isinstance(encryption_algorithm, serialization.NoEncryption) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption" + ) + + return self._raw_private_bytes() + + if ( + encoding in serialization._PEM_DER and + format is not serialization.PrivateFormat.PKCS8 + ): + raise ValueError( + "format must be PKCS8 when encoding is PEM or DER" + ) + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self._evp_pkey, None + ) + + def _raw_private_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_private_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:] diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/encode_asn1.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/encode_asn1.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/encode_asn1.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/encode_asn1.py 2019-02-27 23:27:53.000000000 +0000 @@ -14,7 +14,10 @@ _CRL_ENTRY_REASON_ENUM_TO_CODE, _DISTPOINT_TYPE_FULLNAME, _DISTPOINT_TYPE_RELATIVENAME ) -from cryptography.x509.oid import CRLEntryExtensionOID, ExtensionOID +from cryptography.x509.name import _ASN1Type +from cryptography.x509.oid import ( + CRLEntryExtensionOID, ExtensionOID, OCSPExtensionOID, +) def _encode_asn1_int(backend, x): @@ -43,12 +46,12 @@ return i -def _encode_asn1_str(backend, data, length): +def _encode_asn1_str(backend, data): """ Create an ASN1_OCTET_STRING from a Python byte string. """ s = backend._lib.ASN1_OCTET_STRING_new() - res = backend._lib.ASN1_OCTET_STRING_set(s, data, length) + res = backend._lib.ASN1_OCTET_STRING_set(s, data, len(data)) backend.openssl_assert(res == 1) return s @@ -67,8 +70,8 @@ return s -def _encode_asn1_str_gc(backend, data, length): - s = _encode_asn1_str(backend, data, length) +def _encode_asn1_str_gc(backend, data): + s = _encode_asn1_str(backend, data) s = backend._ffi.gc(s, backend._lib.ASN1_OCTET_STRING_free) return s @@ -105,22 +108,26 @@ def _encode_sk_name_entry(backend, attributes): """ - The sk_X50_NAME_ENTRY created will not be gc'd. + The sk_X509_NAME_ENTRY created will not be gc'd. """ stack = backend._lib.sk_X509_NAME_ENTRY_new_null() for attribute in attributes: name_entry = _encode_name_entry(backend, attribute) res = backend._lib.sk_X509_NAME_ENTRY_push(stack, name_entry) - backend.openssl_assert(res == 1) + backend.openssl_assert(res >= 1) return stack def _encode_name_entry(backend, attribute): - value = attribute.value.encode('utf8') + if attribute._type is _ASN1Type.BMPString: + value = attribute.value.encode('utf_16_be') + else: + value = attribute.value.encode('utf8') + obj = _txt2obj_gc(backend, attribute.oid.dotted_string) name_entry = backend._lib.X509_NAME_ENTRY_create_by_OBJ( - backend._ffi.NULL, obj, attribute._type.value, value, -1 + backend._ffi.NULL, obj, attribute._type.value, value, len(value) ) return name_entry @@ -129,6 +136,28 @@ return _encode_asn1_int_gc(backend, ext.crl_number) +def _encode_issuing_dist_point(backend, ext): + idp = backend._lib.ISSUING_DIST_POINT_new() + backend.openssl_assert(idp != backend._ffi.NULL) + idp = backend._ffi.gc(idp, backend._lib.ISSUING_DIST_POINT_free) + idp.onlyuser = 255 if ext.only_contains_user_certs else 0 + idp.onlyCA = 255 if ext.only_contains_ca_certs else 0 + idp.indirectCRL = 255 if ext.indirect_crl else 0 + idp.onlyattr = 255 if ext.only_contains_attribute_certs else 0 + if ext.only_some_reasons: + idp.onlysomereasons = _encode_reasonflags( + backend, ext.only_some_reasons + ) + + if ext.full_name: + idp.distpoint = _encode_full_name(backend, ext.full_name) + + if ext.relative_name: + idp.distpoint = _encode_relative_name(backend, ext.relative_name) + + return idp + + def _encode_crl_reason(backend, crl_reason): asn1enum = backend._lib.ASN1_ENUMERATED_new() backend.openssl_assert(asn1enum != backend._ffi.NULL) @@ -179,7 +208,6 @@ pqi.d.cpsuri = _encode_asn1_str( backend, qualifier.encode("ascii"), - len(qualifier.encode("ascii")) ) else: assert isinstance(qualifier, x509.UserNotice) @@ -240,11 +268,8 @@ def _encode_ocsp_nocheck(backend, ext): - """ - The OCSP No Check extension is defined as a null ASN.1 value embedded in - an ASN.1 string. - """ - return _encode_asn1_str_gc(backend, b"\x05\x00", 2) + # Doesn't need to be GC'd + return backend._lib.ASN1_NULL_new() def _encode_key_usage(backend, key_usage): @@ -287,7 +312,6 @@ akid.keyid = _encode_asn1_str( backend, authority_keyid.key_identifier, - len(authority_keyid.key_identifier) ) if authority_keyid.authority_cert_issuer is not None: @@ -357,7 +381,7 @@ def _encode_subject_key_identifier(backend, ski): - return _encode_asn1_str_gc(backend, ski.digest, len(ski.digest)) + return _encode_asn1_str_gc(backend, ski.digest) def _encode_general_name(backend, name): @@ -405,7 +429,7 @@ ) else: packed = name.value.packed - ipaddr = _encode_asn1_str(backend, packed, len(packed)) + ipaddr = _encode_asn1_str(backend, packed) gn.type = backend._lib.GEN_IPADD gn.d.iPAddress = ipaddr elif isinstance(name, x509.OtherName): @@ -437,7 +461,7 @@ # ia5strings are supposed to be ITU T.50 but to allow round-tripping # of broken certs that encode utf8 we'll encode utf8 here too. data = name.value.encode("utf8") - asn1_str = _encode_asn1_str(backend, data, len(data)) + asn1_str = _encode_asn1_str(backend, data) gn.type = backend._lib.GEN_EMAIL gn.d.rfc822Name = asn1_str elif isinstance(name, x509.UniformResourceIdentifier): @@ -446,12 +470,12 @@ # ia5strings are supposed to be ITU T.50 but to allow round-tripping # of broken certs that encode utf8 we'll encode utf8 here too. data = name.value.encode("utf8") - asn1_str = _encode_asn1_str(backend, data, len(data)) + asn1_str = _encode_asn1_str(backend, data) gn.type = backend._lib.GEN_URI gn.d.uniformResourceIdentifier = asn1_str else: raise ValueError( - "{0} is an unknown GeneralName type".format(name) + "{} is an unknown GeneralName type".format(name) ) return gn @@ -480,6 +504,34 @@ } +def _encode_reasonflags(backend, reasons): + bitmask = backend._lib.ASN1_BIT_STRING_new() + backend.openssl_assert(bitmask != backend._ffi.NULL) + for reason in reasons: + res = backend._lib.ASN1_BIT_STRING_set_bit( + bitmask, _CRLREASONFLAGS[reason], 1 + ) + backend.openssl_assert(res == 1) + + return bitmask + + +def _encode_full_name(backend, full_name): + dpn = backend._lib.DIST_POINT_NAME_new() + backend.openssl_assert(dpn != backend._ffi.NULL) + dpn.type = _DISTPOINT_TYPE_FULLNAME + dpn.name.fullname = _encode_general_names(backend, full_name) + return dpn + + +def _encode_relative_name(backend, relative_name): + dpn = backend._lib.DIST_POINT_NAME_new() + backend.openssl_assert(dpn != backend._ffi.NULL) + dpn.type = _DISTPOINT_TYPE_RELATIVENAME + dpn.name.relativename = _encode_sk_name_entry(backend, relative_name) + return dpn + + def _encode_cdps_freshest_crl(backend, cdps): cdp = backend._lib.sk_DIST_POINT_new_null() cdp = backend._ffi.gc(cdp, backend._lib.sk_DIST_POINT_free) @@ -488,30 +540,13 @@ backend.openssl_assert(dp != backend._ffi.NULL) if point.reasons: - bitmask = backend._lib.ASN1_BIT_STRING_new() - backend.openssl_assert(bitmask != backend._ffi.NULL) - dp.reasons = bitmask - for reason in point.reasons: - res = backend._lib.ASN1_BIT_STRING_set_bit( - bitmask, _CRLREASONFLAGS[reason], 1 - ) - backend.openssl_assert(res == 1) + dp.reasons = _encode_reasonflags(backend, point.reasons) if point.full_name: - dpn = backend._lib.DIST_POINT_NAME_new() - backend.openssl_assert(dpn != backend._ffi.NULL) - dpn.type = _DISTPOINT_TYPE_FULLNAME - dpn.name.fullname = _encode_general_names(backend, point.full_name) - dp.distpoint = dpn + dp.distpoint = _encode_full_name(backend, point.full_name) if point.relative_name: - dpn = backend._lib.DIST_POINT_NAME_new() - backend.openssl_assert(dpn != backend._ffi.NULL) - dpn.type = _DISTPOINT_TYPE_RELATIVENAME - relativename = _encode_sk_name_entry(backend, point.relative_name) - backend.openssl_assert(relativename != backend._ffi.NULL) - dpn.name.relativename = relativename - dp.distpoint = dpn + dp.distpoint = _encode_relative_name(backend, point.relative_name) if point.crl_issuer: dp.CRLissuer = _encode_general_names(backend, point.crl_issuer) @@ -569,6 +604,10 @@ return general_subtrees +def _encode_nonce(backend, nonce): + return _encode_asn1_str_gc(backend, nonce.nonce) + + _EXTENSION_ENCODE_HANDLERS = { ExtensionOID.BASIC_CONSTRAINTS: _encode_basic_constraints, ExtensionOID.SUBJECT_KEY_IDENTIFIER: _encode_subject_key_identifier, @@ -597,6 +636,7 @@ ), ExtensionOID.CRL_NUMBER: _encode_crl_number_delta_crl_indicator, ExtensionOID.DELTA_CRL_INDICATOR: _encode_crl_number_delta_crl_indicator, + ExtensionOID.ISSUING_DISTRIBUTION_POINT: _encode_issuing_dist_point, } _CRL_ENTRY_EXTENSION_ENCODE_HANDLERS = { @@ -604,3 +644,11 @@ CRLEntryExtensionOID.CRL_REASON: _encode_crl_reason, CRLEntryExtensionOID.INVALIDITY_DATE: _encode_invalidity_date, } + +_OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS = { + OCSPExtensionOID.NONCE: _encode_nonce, +} + +_OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS = { + OCSPExtensionOID.NONCE: _encode_nonce, +} diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/hashes.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/hashes.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/hashes.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/hashes.py 2019-02-27 23:27:53.000000000 +0000 @@ -22,12 +22,11 @@ ctx = self._backend._ffi.gc( ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free ) - name = self._backend._build_openssl_digest_name(algorithm) - evp_md = self._backend._lib.EVP_get_digestbyname(name) + evp_md = self._backend._evp_md_from_algorithm(algorithm) if evp_md == self._backend._ffi.NULL: raise UnsupportedAlgorithm( - "{0} is not a supported hash on this backend.".format( - name), + "{} is not a supported hash on this backend.".format( + algorithm.name), _Reasons.UNSUPPORTED_HASH ) res = self._backend._lib.EVP_DigestInit_ex(ctx, evp_md, @@ -48,14 +47,32 @@ return _HashContext(self._backend, self.algorithm, ctx=copied_ctx) def update(self, data): - res = self._backend._lib.EVP_DigestUpdate(self._ctx, data, len(data)) + data_ptr = self._backend._ffi.from_buffer(data) + res = self._backend._lib.EVP_DigestUpdate( + self._ctx, data_ptr, len(data) + ) self._backend.openssl_assert(res != 0) def finalize(self): + if isinstance(self.algorithm, hashes.ExtendableOutputFunction): + # extendable output functions use a different finalize + return self._finalize_xof() + else: + buf = self._backend._ffi.new("unsigned char[]", + self._backend._lib.EVP_MAX_MD_SIZE) + outlen = self._backend._ffi.new("unsigned int *") + res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen) + self._backend.openssl_assert(res != 0) + self._backend.openssl_assert( + outlen[0] == self.algorithm.digest_size + ) + return self._backend._ffi.buffer(buf)[:outlen[0]] + + def _finalize_xof(self): buf = self._backend._ffi.new("unsigned char[]", - self._backend._lib.EVP_MAX_MD_SIZE) - outlen = self._backend._ffi.new("unsigned int *") - res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen) + self.algorithm.digest_size) + res = self._backend._lib.EVP_DigestFinalXOF( + self._ctx, buf, self.algorithm.digest_size + ) self._backend.openssl_assert(res != 0) - self._backend.openssl_assert(outlen[0] == self.algorithm.digest_size) - return self._backend._ffi.buffer(buf)[:outlen[0]] + return self._backend._ffi.buffer(buf)[:self.algorithm.digest_size] diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/hmac.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/hmac.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/hmac.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/hmac.py 2019-02-27 23:27:53.000000000 +0000 @@ -25,15 +25,16 @@ ctx = self._backend._ffi.gc( ctx, self._backend._lib.Cryptography_HMAC_CTX_free ) - name = self._backend._build_openssl_digest_name(algorithm) - evp_md = self._backend._lib.EVP_get_digestbyname(name) + evp_md = self._backend._evp_md_from_algorithm(algorithm) if evp_md == self._backend._ffi.NULL: raise UnsupportedAlgorithm( - "{0} is not a supported hash on this backend".format(name), + "{} is not a supported hash on this backend".format( + algorithm.name), _Reasons.UNSUPPORTED_HASH ) + key_ptr = self._backend._ffi.from_buffer(key) res = self._backend._lib.HMAC_Init_ex( - ctx, key, len(key), evp_md, self._backend._ffi.NULL + ctx, key_ptr, len(key), evp_md, self._backend._ffi.NULL ) self._backend.openssl_assert(res != 0) @@ -55,7 +56,8 @@ ) def update(self, data): - res = self._backend._lib.HMAC_Update(self._ctx, data, len(data)) + data_ptr = self._backend._ffi.from_buffer(data) + res = self._backend._lib.HMAC_Update(self._ctx, data_ptr, len(data)) self._backend.openssl_assert(res != 0) def finalize(self): diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/ocsp.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/ocsp.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/ocsp.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/ocsp.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,381 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import functools + +from cryptography import utils, x509 +from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat.backends.openssl.decode_asn1 import ( + _CRL_ENTRY_REASON_CODE_TO_ENUM, _OCSP_BASICRESP_EXT_PARSER, + _OCSP_REQ_EXT_PARSER, _asn1_integer_to_int, + _asn1_string_to_bytes, _decode_x509_name, _obj2txt, + _parse_asn1_generalized_time, +) +from cryptography.hazmat.backends.openssl.x509 import _Certificate +from cryptography.hazmat.primitives import serialization +from cryptography.x509.ocsp import ( + OCSPCertStatus, OCSPRequest, OCSPResponse, OCSPResponseStatus, + _CERT_STATUS_TO_ENUM, _OIDS_TO_HASH, _RESPONSE_STATUS_TO_ENUM, +) + + +def _requires_successful_response(func): + @functools.wraps(func) + def wrapper(self, *args): + if self.response_status != OCSPResponseStatus.SUCCESSFUL: + raise ValueError( + "OCSP response status is not successful so the property " + "has no value" + ) + else: + return func(self, *args) + + return wrapper + + +def _issuer_key_hash(backend, cert_id): + key_hash = backend._ffi.new("ASN1_OCTET_STRING **") + res = backend._lib.OCSP_id_get0_info( + backend._ffi.NULL, backend._ffi.NULL, + key_hash, backend._ffi.NULL, cert_id + ) + backend.openssl_assert(res == 1) + backend.openssl_assert(key_hash[0] != backend._ffi.NULL) + return _asn1_string_to_bytes(backend, key_hash[0]) + + +def _issuer_name_hash(backend, cert_id): + name_hash = backend._ffi.new("ASN1_OCTET_STRING **") + res = backend._lib.OCSP_id_get0_info( + name_hash, backend._ffi.NULL, + backend._ffi.NULL, backend._ffi.NULL, cert_id + ) + backend.openssl_assert(res == 1) + backend.openssl_assert(name_hash[0] != backend._ffi.NULL) + return _asn1_string_to_bytes(backend, name_hash[0]) + + +def _serial_number(backend, cert_id): + num = backend._ffi.new("ASN1_INTEGER **") + res = backend._lib.OCSP_id_get0_info( + backend._ffi.NULL, backend._ffi.NULL, + backend._ffi.NULL, num, cert_id + ) + backend.openssl_assert(res == 1) + backend.openssl_assert(num[0] != backend._ffi.NULL) + return _asn1_integer_to_int(backend, num[0]) + + +def _hash_algorithm(backend, cert_id): + asn1obj = backend._ffi.new("ASN1_OBJECT **") + res = backend._lib.OCSP_id_get0_info( + backend._ffi.NULL, asn1obj, + backend._ffi.NULL, backend._ffi.NULL, cert_id + ) + backend.openssl_assert(res == 1) + backend.openssl_assert(asn1obj[0] != backend._ffi.NULL) + oid = _obj2txt(backend, asn1obj[0]) + try: + return _OIDS_TO_HASH[oid] + except KeyError: + raise UnsupportedAlgorithm( + "Signature algorithm OID: {} not recognized".format(oid) + ) + + +@utils.register_interface(OCSPResponse) +class _OCSPResponse(object): + def __init__(self, backend, ocsp_response): + self._backend = backend + self._ocsp_response = ocsp_response + status = self._backend._lib.OCSP_response_status(self._ocsp_response) + self._backend.openssl_assert(status in _RESPONSE_STATUS_TO_ENUM) + self._status = _RESPONSE_STATUS_TO_ENUM[status] + if self._status is OCSPResponseStatus.SUCCESSFUL: + basic = self._backend._lib.OCSP_response_get1_basic( + self._ocsp_response + ) + self._backend.openssl_assert(basic != self._backend._ffi.NULL) + self._basic = self._backend._ffi.gc( + basic, self._backend._lib.OCSP_BASICRESP_free + ) + self._backend.openssl_assert( + self._backend._lib.OCSP_resp_count(self._basic) == 1 + ) + self._single = self._backend._lib.OCSP_resp_get0(self._basic, 0) + self._backend.openssl_assert( + self._single != self._backend._ffi.NULL + ) + self._cert_id = self._backend._lib.OCSP_SINGLERESP_get0_id( + self._single + ) + self._backend.openssl_assert( + self._cert_id != self._backend._ffi.NULL + ) + + response_status = utils.read_only_property("_status") + + @property + @_requires_successful_response + def signature_algorithm_oid(self): + alg = self._backend._lib.OCSP_resp_get0_tbs_sigalg(self._basic) + self._backend.openssl_assert(alg != self._backend._ffi.NULL) + oid = _obj2txt(self._backend, alg.algorithm) + return x509.ObjectIdentifier(oid) + + @property + @_requires_successful_response + def signature_hash_algorithm(self): + oid = self.signature_algorithm_oid + try: + return x509._SIG_OIDS_TO_HASH[oid] + except KeyError: + raise UnsupportedAlgorithm( + "Signature algorithm OID:{} not recognized".format(oid) + ) + + @property + @_requires_successful_response + def signature(self): + sig = self._backend._lib.OCSP_resp_get0_signature(self._basic) + self._backend.openssl_assert(sig != self._backend._ffi.NULL) + return _asn1_string_to_bytes(self._backend, sig) + + @property + @_requires_successful_response + def tbs_response_bytes(self): + respdata = self._backend._lib.OCSP_resp_get0_respdata(self._basic) + self._backend.openssl_assert(respdata != self._backend._ffi.NULL) + pp = self._backend._ffi.new("unsigned char **") + res = self._backend._lib.i2d_OCSP_RESPDATA(respdata, pp) + self._backend.openssl_assert(pp[0] != self._backend._ffi.NULL) + pp = self._backend._ffi.gc( + pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0]) + ) + self._backend.openssl_assert(res > 0) + return self._backend._ffi.buffer(pp[0], res)[:] + + @property + @_requires_successful_response + def certificates(self): + sk_x509 = self._backend._lib.OCSP_resp_get0_certs(self._basic) + num = self._backend._lib.sk_X509_num(sk_x509) + certs = [] + for i in range(num): + x509 = self._backend._lib.sk_X509_value(sk_x509, i) + self._backend.openssl_assert(x509 != self._backend._ffi.NULL) + cert = _Certificate(self._backend, x509) + # We need to keep the OCSP response that the certificate came from + # alive until the Certificate object itself goes out of scope, so + # we give it a private reference. + cert._ocsp_resp = self + certs.append(cert) + + return certs + + @property + @_requires_successful_response + def responder_key_hash(self): + _, asn1_string = self._responder_key_name() + if asn1_string == self._backend._ffi.NULL: + return None + else: + return _asn1_string_to_bytes(self._backend, asn1_string) + + @property + @_requires_successful_response + def responder_name(self): + x509_name, _ = self._responder_key_name() + if x509_name == self._backend._ffi.NULL: + return None + else: + return _decode_x509_name(self._backend, x509_name) + + def _responder_key_name(self): + asn1_string = self._backend._ffi.new("ASN1_OCTET_STRING **") + x509_name = self._backend._ffi.new("X509_NAME **") + res = self._backend._lib.OCSP_resp_get0_id( + self._basic, asn1_string, x509_name + ) + self._backend.openssl_assert(res == 1) + return x509_name[0], asn1_string[0] + + @property + @_requires_successful_response + def produced_at(self): + produced_at = self._backend._lib.OCSP_resp_get0_produced_at( + self._basic + ) + return _parse_asn1_generalized_time(self._backend, produced_at) + + @property + @_requires_successful_response + def certificate_status(self): + status = self._backend._lib.OCSP_single_get0_status( + self._single, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(status in _CERT_STATUS_TO_ENUM) + return _CERT_STATUS_TO_ENUM[status] + + @property + @_requires_successful_response + def revocation_time(self): + if self.certificate_status is not OCSPCertStatus.REVOKED: + return None + + asn1_time = self._backend._ffi.new("ASN1_GENERALIZEDTIME **") + self._backend._lib.OCSP_single_get0_status( + self._single, + self._backend._ffi.NULL, + asn1_time, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(asn1_time[0] != self._backend._ffi.NULL) + return _parse_asn1_generalized_time(self._backend, asn1_time[0]) + + @property + @_requires_successful_response + def revocation_reason(self): + if self.certificate_status is not OCSPCertStatus.REVOKED: + return None + + reason_ptr = self._backend._ffi.new("int *") + self._backend._lib.OCSP_single_get0_status( + self._single, + reason_ptr, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + ) + # If no reason is encoded OpenSSL returns -1 + if reason_ptr[0] == -1: + return None + else: + self._backend.openssl_assert( + reason_ptr[0] in _CRL_ENTRY_REASON_CODE_TO_ENUM + ) + return _CRL_ENTRY_REASON_CODE_TO_ENUM[reason_ptr[0]] + + @property + @_requires_successful_response + def this_update(self): + asn1_time = self._backend._ffi.new("ASN1_GENERALIZEDTIME **") + self._backend._lib.OCSP_single_get0_status( + self._single, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + asn1_time, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(asn1_time[0] != self._backend._ffi.NULL) + return _parse_asn1_generalized_time(self._backend, asn1_time[0]) + + @property + @_requires_successful_response + def next_update(self): + asn1_time = self._backend._ffi.new("ASN1_GENERALIZEDTIME **") + self._backend._lib.OCSP_single_get0_status( + self._single, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + asn1_time, + ) + if asn1_time[0] != self._backend._ffi.NULL: + return _parse_asn1_generalized_time(self._backend, asn1_time[0]) + else: + return None + + @property + @_requires_successful_response + def issuer_key_hash(self): + return _issuer_key_hash(self._backend, self._cert_id) + + @property + @_requires_successful_response + def issuer_name_hash(self): + return _issuer_name_hash(self._backend, self._cert_id) + + @property + @_requires_successful_response + def hash_algorithm(self): + return _hash_algorithm(self._backend, self._cert_id) + + @property + @_requires_successful_response + def serial_number(self): + return _serial_number(self._backend, self._cert_id) + + @utils.cached_property + @_requires_successful_response + def extensions(self): + return _OCSP_BASICRESP_EXT_PARSER.parse(self._backend, self._basic) + + def public_bytes(self, encoding): + if encoding is not serialization.Encoding.DER: + raise ValueError( + "The only allowed encoding value is Encoding.DER" + ) + + bio = self._backend._create_mem_bio_gc() + res = self._backend._lib.i2d_OCSP_RESPONSE_bio( + bio, self._ocsp_response + ) + self._backend.openssl_assert(res > 0) + return self._backend._read_mem_bio(bio) + + +@utils.register_interface(OCSPRequest) +class _OCSPRequest(object): + def __init__(self, backend, ocsp_request): + if backend._lib.OCSP_request_onereq_count(ocsp_request) > 1: + raise NotImplementedError( + 'OCSP request contains more than one request' + ) + self._backend = backend + self._ocsp_request = ocsp_request + self._request = self._backend._lib.OCSP_request_onereq_get0( + self._ocsp_request, 0 + ) + self._backend.openssl_assert(self._request != self._backend._ffi.NULL) + self._cert_id = self._backend._lib.OCSP_onereq_get0_id(self._request) + self._backend.openssl_assert(self._cert_id != self._backend._ffi.NULL) + + @property + def issuer_key_hash(self): + return _issuer_key_hash(self._backend, self._cert_id) + + @property + def issuer_name_hash(self): + return _issuer_name_hash(self._backend, self._cert_id) + + @property + def serial_number(self): + return _serial_number(self._backend, self._cert_id) + + @property + def hash_algorithm(self): + return _hash_algorithm(self._backend, self._cert_id) + + @utils.cached_property + def extensions(self): + return _OCSP_REQ_EXT_PARSER.parse(self._backend, self._ocsp_request) + + def public_bytes(self, encoding): + if encoding is not serialization.Encoding.DER: + raise ValueError( + "The only allowed encoding value is Encoding.DER" + ) + + bio = self._backend._create_mem_bio_gc() + res = self._backend._lib.i2d_OCSP_REQUEST_bio(bio, self._ocsp_request) + self._backend.openssl_assert(res > 0) + return self._backend._read_mem_bio(bio) diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/rsa.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/rsa.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/rsa.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/rsa.py 2019-02-27 23:27:53.000000000 +0000 @@ -59,7 +59,7 @@ else: raise UnsupportedAlgorithm( - "{0} is not supported by this backend.".format( + "{} is not supported by this backend.".format( padding.name ), _Reasons.UNSUPPORTED_PADDING @@ -92,14 +92,11 @@ isinstance(padding, OAEP) and backend._lib.Cryptography_HAS_RSA_OAEP_MD ): - mgf1_md = backend._lib.EVP_get_digestbyname( - padding._mgf._algorithm.name.encode("ascii")) - backend.openssl_assert(mgf1_md != backend._ffi.NULL) + mgf1_md = backend._evp_md_non_null_from_algorithm( + padding._mgf._algorithm) res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md) backend.openssl_assert(res > 0) - oaep_md = backend._lib.EVP_get_digestbyname( - padding._algorithm.name.encode("ascii")) - backend.openssl_assert(oaep_md != backend._ffi.NULL) + oaep_md = backend._evp_md_non_null_from_algorithm(padding._algorithm) res = backend._lib.EVP_PKEY_CTX_set_rsa_oaep_md(pkey_ctx, oaep_md) backend.openssl_assert(res > 0) @@ -129,11 +126,12 @@ def _handle_rsa_enc_dec_error(backend, key): errors = backend._consume_errors() - assert errors - assert errors[0].lib == backend._lib.ERR_LIB_RSA + backend.openssl_assert(errors) + backend.openssl_assert(errors[0].lib == backend._lib.ERR_LIB_RSA) if isinstance(key, _RSAPublicKey): - assert (errors[0].reason == - backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE) + backend.openssl_assert( + errors[0].reason == backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE + ) raise ValueError( "Data too long for key size. Encrypt less data or use a " "larger key size." @@ -151,7 +149,7 @@ if backend._lib.Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR: decoding_errors.append(backend._lib.RSA_R_PKCS_DECODING_ERROR) - assert errors[0].reason in decoding_errors + backend.openssl_assert(errors[0].reason in decoding_errors) raise ValueError("Decryption failed.") @@ -180,7 +178,7 @@ padding_enum = backend._lib.RSA_PKCS1_PSS_PADDING else: raise UnsupportedAlgorithm( - "{0} is not supported by this backend.".format(padding.name), + "{} is not supported by this backend.".format(padding.name), _Reasons.UNSUPPORTED_PADDING ) @@ -189,15 +187,21 @@ def _rsa_sig_setup(backend, padding, algorithm, key, data, init_func): padding_enum = _rsa_sig_determine_padding(backend, key, padding, algorithm) - evp_md = backend._lib.EVP_get_digestbyname(algorithm.name.encode("ascii")) - backend.openssl_assert(evp_md != backend._ffi.NULL) + evp_md = backend._evp_md_non_null_from_algorithm(algorithm) pkey_ctx = backend._lib.EVP_PKEY_CTX_new(key._evp_pkey, backend._ffi.NULL) backend.openssl_assert(pkey_ctx != backend._ffi.NULL) pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free) res = init_func(pkey_ctx) backend.openssl_assert(res == 1) res = backend._lib.EVP_PKEY_CTX_set_signature_md(pkey_ctx, evp_md) - backend.openssl_assert(res > 0) + if res == 0: + backend._consume_errors() + raise UnsupportedAlgorithm( + "{} is not supported by this backend for RSA signing.".format( + algorithm.name + ), + _Reasons.UNSUPPORTED_HASH + ) res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding_enum) backend.openssl_assert(res > 0) if isinstance(padding, PSS): @@ -206,10 +210,8 @@ ) backend.openssl_assert(res > 0) - mgf1_md = backend._lib.EVP_get_digestbyname( - padding._mgf._algorithm.name.encode("ascii") - ) - backend.openssl_assert(mgf1_md != backend._ffi.NULL) + mgf1_md = backend._evp_md_non_null_from_algorithm( + padding._mgf._algorithm) res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md) backend.openssl_assert(res > 0) @@ -235,17 +237,19 @@ pkey_ctx, buf, buflen, data, len(data)) if res != 1: errors = backend._consume_errors() - assert errors[0].lib == backend._lib.ERR_LIB_RSA - reason = None - if (errors[0].reason == - backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE): + backend.openssl_assert(errors[0].lib == backend._lib.ERR_LIB_RSA) + if ( + errors[0].reason == + backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE + ): reason = ("Salt length too long for key size. Try using " "MAX_LENGTH instead.") else: - assert (errors[0].reason == - backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY) + backend.openssl_assert( + errors[0].reason == + backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY + ) reason = "Digest too large for key size. Use a larger key." - assert reason is not None raise ValueError(reason) return backend._ffi.buffer(buf)[:] @@ -264,8 +268,7 @@ # occurs. backend.openssl_assert(res >= 0) if res == 0: - errors = backend._consume_errors() - assert errors + backend._consume_errors() raise InvalidSignature @@ -434,8 +437,7 @@ def verifier(self, signature, padding, algorithm): _warn_sign_verify_deprecated() - if not isinstance(signature, bytes): - raise TypeError("signature must be bytes.") + utils._check_bytes("signature", signature) _check_not_prehashed(algorithm) return _RSAVerificationContext( diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/utils.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/utils.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/utils.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/utils.py 2019-02-27 23:27:53.000000000 +0000 @@ -11,6 +11,30 @@ from cryptography.hazmat.primitives.asymmetric.utils import Prehashed +def _evp_pkey_derive(backend, evp_pkey, peer_public_key): + ctx = backend._lib.EVP_PKEY_CTX_new(evp_pkey, backend._ffi.NULL) + backend.openssl_assert(ctx != backend._ffi.NULL) + ctx = backend._ffi.gc(ctx, backend._lib.EVP_PKEY_CTX_free) + res = backend._lib.EVP_PKEY_derive_init(ctx) + backend.openssl_assert(res == 1) + res = backend._lib.EVP_PKEY_derive_set_peer( + ctx, peer_public_key._evp_pkey + ) + backend.openssl_assert(res == 1) + keylen = backend._ffi.new("size_t *") + res = backend._lib.EVP_PKEY_derive(ctx, backend._ffi.NULL, keylen) + backend.openssl_assert(res == 1) + backend.openssl_assert(keylen[0] > 0) + buf = backend._ffi.new("unsigned char[]", keylen[0]) + res = backend._lib.EVP_PKEY_derive(ctx, buf, keylen) + if res != 1: + raise ValueError( + "Null shared key derived from public/private pair." + ) + + return backend._ffi.buffer(buf, keylen[0])[:] + + def _calculate_digest_and_algorithm(backend, data, algorithm): if not isinstance(algorithm, Prehashed): hash_ctx = hashes.Hash(algorithm, backend) @@ -40,6 +64,6 @@ warnings.warn( "signer and verifier have been deprecated. Please use sign " "and verify instead.", - utils.PersistentlyDeprecated, + utils.PersistentlyDeprecated2017, stacklevel=3 ) diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/x25519.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/x25519.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/x25519.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/x25519.py 2019-02-27 23:27:53.000000000 +0000 @@ -4,19 +4,66 @@ from __future__ import absolute_import, division, print_function +import warnings + from cryptography import utils +from cryptography.hazmat.backends.openssl.utils import _evp_pkey_derive +from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric.x25519 import ( X25519PrivateKey, X25519PublicKey ) +_X25519_KEY_SIZE = 32 + + @utils.register_interface(X25519PublicKey) class _X25519PublicKey(object): def __init__(self, backend, evp_pkey): self._backend = backend self._evp_pkey = evp_pkey - def public_bytes(self): + def public_bytes(self, encoding=None, format=None): + if encoding is None or format is None: + if encoding is not None or format is not None: + raise ValueError("Both encoding and format are required") + else: + warnings.warn( + "public_bytes now requires encoding and format arguments. " + "Support for calling without arguments will be removed in " + "cryptography 2.7", + utils.DeprecatedIn25, + ) + encoding = serialization.Encoding.Raw + format = serialization.PublicFormat.Raw + if ( + encoding is serialization.Encoding.Raw or + format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw or + format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + if ( + encoding in serialization._PEM_DER and + format is not serialization.PublicFormat.SubjectPublicKeyInfo + ): + raise ValueError( + "format must be SubjectPublicKeyInfo when encoding is PEM or " + "DER" + ) + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self): ucharpp = self._backend._ffi.new("unsigned char **") res = self._backend._lib.EVP_PKEY_get1_tls_encodedpoint( self._evp_pkey, ucharpp @@ -42,30 +89,61 @@ evp_pkey = self._backend._lib.d2i_PUBKEY_bio( bio, self._backend._ffi.NULL ) + self._backend.openssl_assert(evp_pkey != self._backend._ffi.NULL) + evp_pkey = self._backend._ffi.gc( + evp_pkey, self._backend._lib.EVP_PKEY_free + ) return _X25519PublicKey(self._backend, evp_pkey) def exchange(self, peer_public_key): if not isinstance(peer_public_key, X25519PublicKey): raise TypeError("peer_public_key must be X25519PublicKey.") - ctx = self._backend._lib.EVP_PKEY_CTX_new( - self._evp_pkey, self._backend._ffi.NULL + return _evp_pkey_derive( + self._backend, self._evp_pkey, peer_public_key ) - self._backend.openssl_assert(ctx != self._backend._ffi.NULL) - ctx = self._backend._ffi.gc(ctx, self._backend._lib.EVP_PKEY_CTX_free) - res = self._backend._lib.EVP_PKEY_derive_init(ctx) - self._backend.openssl_assert(res == 1) - res = self._backend._lib.EVP_PKEY_derive_set_peer( - ctx, peer_public_key._evp_pkey - ) - self._backend.openssl_assert(res == 1) - keylen = self._backend._ffi.new("size_t *") - res = self._backend._lib.EVP_PKEY_derive( - ctx, self._backend._ffi.NULL, keylen + + def private_bytes(self, encoding, format, encryption_algorithm): + if ( + encoding is serialization.Encoding.Raw or + format is serialization.PublicFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw or + encoding is not serialization.Encoding.Raw or not + isinstance(encryption_algorithm, serialization.NoEncryption) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption" + ) + + return self._raw_private_bytes() + + if ( + encoding in serialization._PEM_DER and + format is not serialization.PrivateFormat.PKCS8 + ): + raise ValueError( + "format must be PKCS8 when encoding is PEM or DER" + ) + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self._evp_pkey, None + ) + + def _raw_private_bytes(self): + # When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 we can + # switch this to EVP_PKEY_new_raw_private_key + # The trick we use here is serializing to a PKCS8 key and just + # using the last 32 bytes, which is the key itself. + bio = self._backend._create_mem_bio_gc() + res = self._backend._lib.i2d_PKCS8PrivateKey_bio( + bio, self._evp_pkey, + self._backend._ffi.NULL, self._backend._ffi.NULL, + 0, self._backend._ffi.NULL, self._backend._ffi.NULL ) self._backend.openssl_assert(res == 1) - self._backend.openssl_assert(keylen[0] > 0) - buf = self._backend._ffi.new("unsigned char[]", keylen[0]) - res = self._backend._lib.EVP_PKEY_derive(ctx, buf, keylen) - self._backend.openssl_assert(res == 1) - return self._backend._ffi.buffer(buf, keylen[0])[:] + pkcs8 = self._backend._read_mem_bio(bio) + self._backend.openssl_assert(len(pkcs8) == 48) + return pkcs8[-_X25519_KEY_SIZE:] diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/x448.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/x448.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/x448.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/x448.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,123 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.hazmat.backends.openssl.utils import _evp_pkey_derive +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.x448 import ( + X448PrivateKey, X448PublicKey +) + +_X448_KEY_SIZE = 56 + + +@utils.register_interface(X448PublicKey) +class _X448PublicKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes(self, encoding, format): + if ( + encoding is serialization.Encoding.Raw or + format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw or + format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + if ( + encoding in serialization._PEM_DER and + format is not serialization.PublicFormat.SubjectPublicKeyInfo + ): + raise ValueError( + "format must be SubjectPublicKeyInfo when encoding is PEM or " + "DER" + ) + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _X448_KEY_SIZE)[:] + + +@utils.register_interface(X448PrivateKey) +class _X448PrivateKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self): + buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE) + return self._backend.x448_load_public_bytes(buf) + + def exchange(self, peer_public_key): + if not isinstance(peer_public_key, X448PublicKey): + raise TypeError("peer_public_key must be X448PublicKey.") + + return _evp_pkey_derive( + self._backend, self._evp_pkey, peer_public_key + ) + + def private_bytes(self, encoding, format, encryption_algorithm): + if ( + encoding is serialization.Encoding.Raw or + format is serialization.PublicFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw or + encoding is not serialization.Encoding.Raw or not + isinstance(encryption_algorithm, serialization.NoEncryption) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption" + ) + + return self._raw_private_bytes() + + if ( + encoding in serialization._PEM_DER and + format is not serialization.PrivateFormat.PKCS8 + ): + raise ValueError( + "format must be PKCS8 when encoding is PEM or DER" + ) + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self._evp_pkey, None + ) + + def _raw_private_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_private_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _X448_KEY_SIZE)[:] diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/x509.py python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/x509.py --- python-cryptography-2.1.4/src/cryptography/hazmat/backends/openssl/x509.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/backends/openssl/x509.py 2019-02-27 23:27:53.000000000 +0000 @@ -6,7 +6,6 @@ import datetime import operator -import warnings from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm @@ -16,6 +15,9 @@ _REVOKED_CERTIFICATE_EXTENSION_PARSER, _asn1_integer_to_int, _asn1_string_to_bytes, _decode_x509_name, _obj2txt, _parse_asn1_time ) +from cryptography.hazmat.backends.openssl.encode_asn1 import ( + _encode_asn1_int_gc +) from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa @@ -27,7 +29,7 @@ self._x509 = x509 def __repr__(self): - return "".format(self.subject) + return "".format(self.subject) def __eq__(self, other): if not isinstance(other, x509.Certificate): @@ -56,19 +58,10 @@ return x509.Version.v3 else: raise x509.InvalidVersion( - "{0} is not a valid X509 version".format(version), version + "{} is not a valid X509 version".format(version), version ) @property - def serial(self): - warnings.warn( - "Certificate serial is deprecated, use serial_number instead.", - utils.PersistentlyDeprecated, - stacklevel=2 - ) - return self.serial_number - - @property def serial_number(self): asn1_int = self._backend._lib.X509_get_serialNumber(self._x509) self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL) @@ -114,7 +107,7 @@ return x509._SIG_OIDS_TO_HASH[oid] except KeyError: raise UnsupportedAlgorithm( - "Signature algorithm OID:{0} not recognized".format(oid) + "Signature algorithm OID:{} not recognized".format(oid) ) @property @@ -235,6 +228,32 @@ h.update(der) return h.finalize() + @utils.cached_property + def _sorted_crl(self): + # X509_CRL_get0_by_serial sorts in place, which breaks a variety of + # things we don't want to break (like iteration and the signature). + # Let's dupe it and sort that instead. + dup = self._backend._lib.X509_CRL_dup(self._x509_crl) + self._backend.openssl_assert(dup != self._backend._ffi.NULL) + dup = self._backend._ffi.gc(dup, self._backend._lib.X509_CRL_free) + return dup + + def get_revoked_certificate_by_serial_number(self, serial_number): + revoked = self._backend._ffi.new("X509_REVOKED **") + asn1_int = _encode_asn1_int_gc(self._backend, serial_number) + res = self._backend._lib.X509_CRL_get0_by_serial( + self._sorted_crl, revoked, asn1_int + ) + if res == 0: + return None + else: + self._backend.openssl_assert( + revoked[0] != self._backend._ffi.NULL + ) + return _RevokedCertificate( + self._backend, self._sorted_crl, revoked[0] + ) + @property def signature_hash_algorithm(self): oid = self.signature_algorithm_oid @@ -242,7 +261,7 @@ return x509._SIG_OIDS_TO_HASH[oid] except KeyError: raise UnsupportedAlgorithm( - "Signature algorithm OID:{0} not recognized".format(oid) + "Signature algorithm OID:{} not recognized".format(oid) ) @property @@ -394,7 +413,7 @@ return x509._SIG_OIDS_TO_HASH[oid] except KeyError: raise UnsupportedAlgorithm( - "Signature algorithm OID:{0} not recognized".format(oid) + "Signature algorithm OID:{} not recognized".format(oid) ) @property @@ -410,6 +429,14 @@ @utils.cached_property def extensions(self): x509_exts = self._backend._lib.X509_REQ_get_extensions(self._x509_req) + x509_exts = self._backend._ffi.gc( + x509_exts, + lambda x: self._backend._lib.sk_X509_EXTENSION_pop_free( + x, self._backend._ffi.addressof( + self._backend._lib._original_lib, "X509_EXTENSION_free" + ) + ) + ) return _CSR_EXTENSION_PARSER.parse(self._backend, x509_exts) def public_bytes(self, encoding): @@ -497,3 +524,23 @@ # we only have precerts. assert entry_type == self._backend._lib.CT_LOG_ENTRY_TYPE_PRECERT return x509.certificate_transparency.LogEntryType.PRE_CERTIFICATE + + @property + def _signature(self): + ptrptr = self._backend._ffi.new("unsigned char **") + res = self._backend._lib.SCT_get0_signature(self._sct, ptrptr) + self._backend.openssl_assert(res > 0) + self._backend.openssl_assert(ptrptr[0] != self._backend._ffi.NULL) + return self._backend._ffi.buffer(ptrptr[0], res)[:] + + def __hash__(self): + return hash(self._signature) + + def __eq__(self, other): + if not isinstance(other, _SignedCertificateTimestamp): + return NotImplemented + + return self._signature == other._signature + + def __ne__(self, other): + return not self == other diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/bindings/openssl/binding.py python-cryptography-2.6.1/src/cryptography/hazmat/bindings/openssl/binding.py --- python-cryptography-2.1.4/src/cryptography/hazmat/bindings/openssl/binding.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/bindings/openssl/binding.py 2019-02-27 23:27:53.000000000 +0000 @@ -7,7 +7,9 @@ import collections import threading import types +import warnings +import cryptography from cryptography import utils from cryptography.exceptions import InternalError from cryptography.hazmat.bindings._openssl import ffi, lib @@ -55,9 +57,10 @@ errors = _consume_errors(lib) errors_with_text = [] for err in errors: - err_text_reason = ffi.string( - lib.ERR_error_string(err.code, ffi.NULL) - ) + buf = ffi.new("char[]", 256) + lib.ERR_error_string_n(err.code, buf, len(buf)) + err_text_reason = ffi.string(buf) + errors_with_text.append( _OpenSSLErrorWithText( err.code, err.lib, err.func, err.reason, err_text_reason @@ -112,10 +115,9 @@ # reliably clear the error queue. Once we clear it here we will # error on any subsequent unexpected item in the stack. cls.lib.ERR_clear_error() - cls._osrandom_engine_id = cls.lib.Cryptography_osrandom_engine_id - cls._osrandom_engine_name = cls.lib.Cryptography_osrandom_engine_name - result = cls.lib.Cryptography_add_osrandom_engine() - _openssl_assert(cls.lib, result in (1, 2)) + if cls.lib.Cryptography_HAS_ENGINE: + result = cls.lib.Cryptography_add_osrandom_engine() + _openssl_assert(cls.lib, result in (1, 2)) @classmethod def _ensure_ffi_initialized(cls): @@ -139,18 +141,57 @@ # the setup for this. __import__("_ssl") - if cls.lib.CRYPTO_get_locking_callback() != cls.ffi.NULL: + if (not cls.lib.Cryptography_HAS_LOCKING_CALLBACKS or + cls.lib.CRYPTO_get_locking_callback() != cls.ffi.NULL): return # If nothing else has setup a locking callback already, we set up # our own - res = lib._setup_ssl_threads() + res = lib.Cryptography_setup_ssl_threads() _openssl_assert(cls.lib, res == 1) +def _verify_openssl_version(lib): + if ( + lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and + not lib.CRYPTOGRAPHY_IS_LIBRESSL + ): + warnings.warn( + "OpenSSL version 1.0.1 is no longer supported by the OpenSSL " + "project, please upgrade. A future version of cryptography will " + "drop support for it.", + utils.CryptographyDeprecationWarning + ) + + +def _verify_package_version(version): + # Occasionally we run into situations where the version of the Python + # package does not match the version of the shared object that is loaded. + # This may occur in environments where multiple versions of cryptography + # are installed and available in the python path. To avoid errors cropping + # up later this code checks that the currently imported package and the + # shared object that were loaded have the same version and raise an + # ImportError if they do not + so_package_version = ffi.string(lib.CRYPTOGRAPHY_PACKAGE_VERSION) + if version.encode("ascii") != so_package_version: + raise ImportError( + "The version of cryptography does not match the loaded " + "shared object. This can happen if you have multiple copies of " + "cryptography installed in your Python path. Please try creating " + "a new virtual environment to resolve this issue. " + "Loaded python version: {}, shared object version: {}".format( + version, so_package_version + ) + ) + + +_verify_package_version(cryptography.__version__) + # OpenSSL is not thread safe until the locks are initialized. We call this # method in module scope so that it executes with the import lock. On # Pythons < 3.4 this import lock is a global lock, which can prevent a race # condition registering the OpenSSL locks. On Python 3.4+ the import lock # is per module so this approach will not work. Binding.init_static_locks() + +_verify_openssl_version(Binding.lib) diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/bindings/openssl/_conditional.py python-cryptography-2.6.1/src/cryptography/hazmat/bindings/openssl/_conditional.py --- python-cryptography-2.1.4/src/cryptography/hazmat/bindings/openssl/_conditional.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/bindings/openssl/_conditional.py 2019-02-27 23:27:53.000000000 +0000 @@ -5,49 +5,11 @@ from __future__ import absolute_import, division, print_function -def cryptography_has_cms(): - return [ - "BIO_new_CMS", - "i2d_CMS_bio_stream", - "PEM_write_bio_CMS_stream", - "CMS_final", - "CMS_sign", - "CMS_verify", - "CMS_encrypt", - "CMS_decrypt", - "CMS_add1_signer", - "CMS_TEXT", - "CMS_NOCERTS", - "CMS_NO_CONTENT_VERIFY", - "CMS_NO_ATTR_VERIFY", - "CMS_NOSIGS", - "CMS_NOINTERN", - "CMS_NO_SIGNER_CERT_VERIFY", - "CMS_NOVERIFY", - "CMS_DETACHED", - "CMS_BINARY", - "CMS_NOATTR", - "CMS_NOSMIMECAP", - "CMS_NOOLDMIMETYPE", - "CMS_CRLFEOL", - "CMS_STREAM", - "CMS_NOCRL", - "CMS_PARTIAL", - "CMS_REUSE_DIGEST", - "CMS_USE_KEYID", - "CMS_DEBUG_DECRYPT", - ] - - def cryptography_has_ec2m(): return [ - "EC_GF2m_simple_method", "EC_POINT_set_affine_coordinates_GF2m", "EC_POINT_get_affine_coordinates_GF2m", "EC_POINT_set_compressed_coordinates_GF2m", - "EC_GROUP_set_curve_GF2m", - "EC_GROUP_get_curve_GF2m", - "EC_GROUP_new_curve_GF2m", ] @@ -136,6 +98,18 @@ "X509_VERIFY_PARAM_set1_ip", "X509_VERIFY_PARAM_set1_ip_asc", "X509_VERIFY_PARAM_set_hostflags", + "SSL_get0_param", + "X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT", + "X509_CHECK_FLAG_NO_WILDCARDS", + "X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS", + "X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS", + "X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS" + ] + + +def cryptography_has_110_verification_params(): + return [ + "X509_CHECK_FLAG_NEVER_CHECK_SUBJECT" ] @@ -176,11 +150,7 @@ def cryptography_has_locking_callbacks(): return [ - "CRYPTO_LOCK", - "CRYPTO_UNLOCK", - "CRYPTO_READ", - "CRYPTO_LOCK_SSL", - "CRYPTO_lock", + "Cryptography_setup_ssl_threads", ] @@ -195,6 +165,10 @@ "DTLS_method", "DTLS_server_method", "DTLS_client_method", + "SSL_OP_NO_DTLSv1", + "SSL_OP_NO_DTLSv1_2", + "DTLS_set_link_mtu", + "DTLS_get_link_min_mtu", ] @@ -215,11 +189,19 @@ "SCT_get_version", "SCT_get_log_entry_type", "SCT_get0_log_id", + "SCT_get0_signature", "SCT_get_timestamp", "SCT_set_source", "sk_SCT_num", "sk_SCT_value", "SCT_LIST_free", + "sk_SCT_push", + "sk_SCT_new_null", + "SCT_new", + "SCT_set1_log_id", + "SCT_set_timestamp", + "SCT_set_version", + "SCT_set_log_entry_type", ] @@ -232,10 +214,45 @@ def cryptography_has_x25519(): return [ + "EVP_PKEY_X25519", "NID_X25519", ] +def cryptography_has_x448(): + return [ + "EVP_PKEY_X448", + "NID_X448", + ] + + +def cryptography_has_ed448(): + return [ + "EVP_PKEY_ED448", + "NID_ED448", + ] + + +def cryptography_has_ed25519(): + return [ + "NID_ED25519", + "EVP_PKEY_ED25519", + ] + + +def cryptography_has_oneshot_evp_digest_sign_verify(): + return [ + "EVP_DigestSign", + "EVP_DigestVerify", + ] + + +def cryptography_has_evp_digestfinal_xof(): + return [ + "EVP_DigestFinalXOF", + ] + + def cryptography_has_evp_pkey_get_set_tls_encodedpoint(): return [ "EVP_PKEY_get1_tls_encodedpoint", @@ -250,13 +267,96 @@ ] +def cryptography_has_ssl_sigalgs(): + return [ + "SSL_CTX_set1_sigalgs_list", + "SSL_get_sigalgs", + ] + + +def cryptography_has_psk(): + return [ + "SSL_CTX_use_psk_identity_hint", + "SSL_CTX_set_psk_server_callback", + "SSL_CTX_set_psk_client_callback", + ] + + +def cryptography_has_custom_ext(): + return [ + "SSL_CTX_add_client_custom_ext", + "SSL_CTX_add_server_custom_ext", + "SSL_extension_supported", + ] + + +def cryptography_has_openssl_cleanup(): + return [ + "OPENSSL_cleanup", + ] + + +def cryptography_has_cipher_details(): + return [ + "SSL_CIPHER_is_aead", + "SSL_CIPHER_get_cipher_nid", + "SSL_CIPHER_get_digest_nid", + "SSL_CIPHER_get_kx_nid", + "SSL_CIPHER_get_auth_nid", + ] + + +def cryptography_has_tlsv13(): + return [ + "SSL_OP_NO_TLSv1_3", + "SSL_VERIFY_POST_HANDSHAKE", + "SSL_CTX_set_ciphersuites", + "SSL_verify_client_post_handshake", + "SSL_CTX_set_post_handshake_auth", + "SSL_set_post_handshake_auth", + "SSL_SESSION_get_max_early_data", + "SSL_write_early_data", + "SSL_read_early_data", + "SSL_CTX_set_max_early_data", + ] + + +def cryptography_has_raw_key(): + return [ + "EVP_PKEY_new_raw_private_key", + "EVP_PKEY_new_raw_public_key", + "EVP_PKEY_get_raw_private_key", + "EVP_PKEY_get_raw_public_key", + ] + + +def cryptography_has_evp_r_memory_limit_exceeded(): + return [ + "EVP_R_MEMORY_LIMIT_EXCEEDED", + ] + + +def cryptography_has_engine(): + return [ + "ENGINE_by_id", + "ENGINE_init", + "ENGINE_finish", + "ENGINE_get_default_RAND", + "ENGINE_set_default_RAND", + "ENGINE_unregister_RAND", + "ENGINE_ctrl_cmd", + "ENGINE_free", + "ENGINE_get_name", + "Cryptography_add_osrandom_engine", + ] + + # This is a mapping of # {condition: function-returning-names-dependent-on-that-condition} so we can # loop over them and delete unsupported names at runtime. It will be removed # when cffi supports #if in cdef. We use functions instead of just a dict of # lists so we can use coverage to measure which are used. CONDITIONAL_NAMES = { - "Cryptography_HAS_CMS": cryptography_has_cms, "Cryptography_HAS_EC2M": cryptography_has_ec2m, "Cryptography_HAS_EC_1_0_2": cryptography_has_ec_1_0_2, "Cryptography_HAS_SET_ECDH_AUTO": cryptography_has_set_ecdh_auto, @@ -275,6 +375,9 @@ "Cryptography_HAS_102_VERIFICATION_PARAMS": ( cryptography_has_102_verification_params ), + "Cryptography_HAS_110_VERIFICATION_PARAMS": ( + cryptography_has_110_verification_params + ), "Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST": ( cryptography_has_x509_v_flag_trusted_first ), @@ -296,8 +399,28 @@ cryptography_has_x509_store_ctx_get_issuer ), "Cryptography_HAS_X25519": cryptography_has_x25519, + "Cryptography_HAS_X448": cryptography_has_x448, + "Cryptography_HAS_ED448": cryptography_has_ed448, + "Cryptography_HAS_ED25519": cryptography_has_ed25519, + "Cryptography_HAS_ONESHOT_EVP_DIGEST_SIGN_VERIFY": ( + cryptography_has_oneshot_evp_digest_sign_verify + ), "Cryptography_HAS_EVP_PKEY_get_set_tls_encodedpoint": ( cryptography_has_evp_pkey_get_set_tls_encodedpoint ), "Cryptography_HAS_FIPS": cryptography_has_fips, + "Cryptography_HAS_SIGALGS": cryptography_has_ssl_sigalgs, + "Cryptography_HAS_PSK": cryptography_has_psk, + "Cryptography_HAS_CUSTOM_EXT": cryptography_has_custom_ext, + "Cryptography_HAS_OPENSSL_CLEANUP": cryptography_has_openssl_cleanup, + "Cryptography_HAS_CIPHER_DETAILS": cryptography_has_cipher_details, + "Cryptography_HAS_TLSv1_3": cryptography_has_tlsv13, + "Cryptography_HAS_RAW_KEY": cryptography_has_raw_key, + "Cryptography_HAS_EVP_DIGESTFINAL_XOF": ( + cryptography_has_evp_digestfinal_xof + ), + "Cryptography_HAS_EVP_R_MEMORY_LIMIT_EXCEEDED": ( + cryptography_has_evp_r_memory_limit_exceeded + ), + "Cryptography_HAS_ENGINE": cryptography_has_engine, } diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/_oid.py python-cryptography-2.6.1/src/cryptography/hazmat/_oid.py --- python-cryptography-2.1.4/src/cryptography/hazmat/_oid.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/_oid.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,67 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils + + +class ObjectIdentifier(object): + def __init__(self, dotted_string): + self._dotted_string = dotted_string + + nodes = self._dotted_string.split(".") + intnodes = [] + + # There must be at least 2 nodes, the first node must be 0..2, and + # if less than 2, the second node cannot have a value outside the + # range 0..39. All nodes must be integers. + for node in nodes: + try: + intnodes.append(int(node, 0)) + except ValueError: + raise ValueError( + "Malformed OID: %s (non-integer nodes)" % ( + self._dotted_string)) + + if len(nodes) < 2: + raise ValueError( + "Malformed OID: %s (insufficient number of nodes)" % ( + self._dotted_string)) + + if intnodes[0] > 2: + raise ValueError( + "Malformed OID: %s (first node outside valid range)" % ( + self._dotted_string)) + + if intnodes[0] < 2 and intnodes[1] >= 40: + raise ValueError( + "Malformed OID: %s (second node outside valid range)" % ( + self._dotted_string)) + + def __eq__(self, other): + if not isinstance(other, ObjectIdentifier): + return NotImplemented + + return self.dotted_string == other.dotted_string + + def __ne__(self, other): + return not self == other + + def __repr__(self): + return "".format( + self.dotted_string, + self._name + ) + + def __hash__(self): + return hash(self.dotted_string) + + @property + def _name(self): + # Lazy import to avoid an import cycle + from cryptography.x509.oid import _OID_NAMES + return _OID_NAMES.get(self, "Unknown OID") + + dotted_string = utils.read_only_property("_dotted_string") diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/asymmetric/dsa.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/asymmetric/dsa.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/asymmetric/dsa.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/asymmetric/dsa.py 2019-02-27 23:27:53.000000000 +0000 @@ -128,10 +128,10 @@ def _check_dsa_parameters(parameters): - if utils.bit_length(parameters.p) not in [1024, 2048, 3072]: + if parameters.p.bit_length() not in [1024, 2048, 3072]: raise ValueError("p must be exactly 1024, 2048, or 3072 bits long") - if utils.bit_length(parameters.q) not in [160, 256]: - raise ValueError("q must be exactly 160 or 256 bits long") + if parameters.q.bit_length() not in [160, 224, 256]: + raise ValueError("q must be exactly 160, 224, or 256 bits long") if not (1 < parameters.g < parameters.p): raise ValueError("g, p don't satisfy 1 < g < p.") diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/asymmetric/ec.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/asymmetric/ec.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/asymmetric/ec.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/asymmetric/ec.py 2019-02-27 23:27:53.000000000 +0000 @@ -5,10 +5,34 @@ from __future__ import absolute_import, division, print_function import abc +import warnings import six from cryptography import utils +from cryptography.hazmat._oid import ObjectIdentifier + + +class EllipticCurveOID(object): + SECP192R1 = ObjectIdentifier("1.2.840.10045.3.1.1") + SECP224R1 = ObjectIdentifier("1.3.132.0.33") + SECP256K1 = ObjectIdentifier("1.3.132.0.10") + SECP256R1 = ObjectIdentifier("1.2.840.10045.3.1.7") + SECP384R1 = ObjectIdentifier("1.3.132.0.34") + SECP521R1 = ObjectIdentifier("1.3.132.0.35") + BRAINPOOLP256R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.7") + BRAINPOOLP384R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.11") + BRAINPOOLP512R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.13") + SECT163K1 = ObjectIdentifier("1.3.132.0.1") + SECT163R2 = ObjectIdentifier("1.3.132.0.15") + SECT233K1 = ObjectIdentifier("1.3.132.0.26") + SECT233R1 = ObjectIdentifier("1.3.132.0.27") + SECT283K1 = ObjectIdentifier("1.3.132.0.16") + SECT283R1 = ObjectIdentifier("1.3.132.0.17") + SECT409K1 = ObjectIdentifier("1.3.132.0.36") + SECT409R1 = ObjectIdentifier("1.3.132.0.37") + SECT571K1 = ObjectIdentifier("1.3.132.0.38") + SECT571R1 = ObjectIdentifier("1.3.132.0.39") @six.add_metaclass(abc.ABCMeta) @@ -68,7 +92,7 @@ Bit size of a secret scalar for the curve. """ - @abc.abstractproperty + @abc.abstractmethod def sign(self, data, signature_algorithm): """ Signs the data @@ -128,6 +152,22 @@ Verifies the signature of the data. """ + @classmethod + def from_encoded_point(cls, curve, data): + utils._check_bytes("data", data) + + if not isinstance(curve, EllipticCurve): + raise TypeError("curve must be an EllipticCurve instance") + + if len(data) == 0: + raise ValueError("data must not be an empty byte string") + + if six.indexbytes(data, 0) not in [0x02, 0x03, 0x04]: + raise ValueError("Unsupported elliptic curve point type") + + from cryptography.hazmat.backends.openssl.backend import backend + return backend.load_elliptic_curve_public_bytes(curve, data) + EllipticCurvePublicKeyWithSerialization = EllipticCurvePublicKey @@ -135,7 +175,7 @@ @utils.register_interface(EllipticCurve) class SECT571R1(object): name = "sect571r1" - key_size = 571 + key_size = 570 @utils.register_interface(EllipticCurve) @@ -228,6 +268,24 @@ key_size = 192 +@utils.register_interface(EllipticCurve) +class BrainpoolP256R1(object): + name = "brainpoolP256r1" + key_size = 256 + + +@utils.register_interface(EllipticCurve) +class BrainpoolP384R1(object): + name = "brainpoolP384r1" + key_size = 384 + + +@utils.register_interface(EllipticCurve) +class BrainpoolP512R1(object): + name = "brainpoolP512r1" + key_size = 512 + + _CURVE_TYPES = { "prime192v1": SECP192R1, "prime256v1": SECP256R1, @@ -250,6 +308,10 @@ "sect283r1": SECT283R1, "sect409r1": SECT409R1, "sect571r1": SECT571R1, + + "brainpoolP256r1": BrainpoolP256R1, + "brainpoolP384r1": BrainpoolP384R1, + "brainpoolP512r1": BrainpoolP512R1, } @@ -297,6 +359,14 @@ return backend.load_elliptic_curve_public_numbers(self) def encode_point(self): + warnings.warn( + "encode_point has been deprecated on EllipticCurvePublicNumbers" + " and will be removed in a future version. Please use " + "EllipticCurvePublicKey.public_bytes to obtain both " + "compressed and uncompressed point encoding.", + utils.DeprecatedIn25, + stacklevel=2, + ) # key_size is in bits. Convert to bytes and round up byte_length = (self.curve.key_size + 7) // 8 return ( @@ -309,6 +379,14 @@ if not isinstance(curve, EllipticCurve): raise TypeError("curve must be an EllipticCurve instance") + warnings.warn( + "Support for unsafe construction of public numbers from " + "encoded data will be removed in a future version. " + "Please use EllipticCurvePublicKey.from_encoded_point", + utils.DeprecatedIn25, + stacklevel=2, + ) + if data.startswith(b'\x04'): # key_size is in bits. Convert to bytes and round up byte_length = (curve.key_size + 7) // 8 @@ -387,3 +465,36 @@ class ECDH(object): pass + + +_OID_TO_CURVE = { + EllipticCurveOID.SECP192R1: SECP192R1, + EllipticCurveOID.SECP224R1: SECP224R1, + EllipticCurveOID.SECP256K1: SECP256K1, + EllipticCurveOID.SECP256R1: SECP256R1, + EllipticCurveOID.SECP384R1: SECP384R1, + EllipticCurveOID.SECP521R1: SECP521R1, + EllipticCurveOID.BRAINPOOLP256R1: BrainpoolP256R1, + EllipticCurveOID.BRAINPOOLP384R1: BrainpoolP384R1, + EllipticCurveOID.BRAINPOOLP512R1: BrainpoolP512R1, + EllipticCurveOID.SECT163K1: SECT163K1, + EllipticCurveOID.SECT163R2: SECT163R2, + EllipticCurveOID.SECT233K1: SECT233K1, + EllipticCurveOID.SECT233R1: SECT233R1, + EllipticCurveOID.SECT283K1: SECT283K1, + EllipticCurveOID.SECT283R1: SECT283R1, + EllipticCurveOID.SECT409K1: SECT409K1, + EllipticCurveOID.SECT409R1: SECT409R1, + EllipticCurveOID.SECT571K1: SECT571K1, + EllipticCurveOID.SECT571R1: SECT571R1, +} + + +def get_curve_for_oid(oid): + try: + return _OID_TO_CURVE[oid] + except KeyError: + raise LookupError( + "The provided object identifier has no matching elliptic " + "curve class" + ) diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/asymmetric/ed25519.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/asymmetric/ed25519.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/asymmetric/ed25519.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/asymmetric/ed25519.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,84 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons + + +_ED25519_KEY_SIZE = 32 +_ED25519_SIG_SIZE = 64 + + +@six.add_metaclass(abc.ABCMeta) +class Ed25519PublicKey(object): + @classmethod + def from_public_bytes(cls, data): + from cryptography.hazmat.backends.openssl.backend import backend + if not backend.ed25519_supported(): + raise UnsupportedAlgorithm( + "ed25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ) + + return backend.ed25519_load_public_bytes(data) + + @abc.abstractmethod + def public_bytes(self, encoding, format): + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def verify(self, signature, data): + """ + Verify the signature. + """ + + +@six.add_metaclass(abc.ABCMeta) +class Ed25519PrivateKey(object): + @classmethod + def generate(cls): + from cryptography.hazmat.backends.openssl.backend import backend + if not backend.ed25519_supported(): + raise UnsupportedAlgorithm( + "ed25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ) + + return backend.ed25519_generate_key() + + @classmethod + def from_private_bytes(cls, data): + from cryptography.hazmat.backends.openssl.backend import backend + if not backend.ed25519_supported(): + raise UnsupportedAlgorithm( + "ed25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ) + + return backend.ed25519_load_private_bytes(data) + + @abc.abstractmethod + def public_key(self): + """ + The Ed25519PublicKey derived from the private key. + """ + + @abc.abstractmethod + def private_bytes(self, encoding, format, encryption_algorithm): + """ + The serialized bytes of the private key. + """ + + @abc.abstractmethod + def sign(self, data): + """ + Signs the data. + """ diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/asymmetric/ed448.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/asymmetric/ed448.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/asymmetric/ed448.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/asymmetric/ed448.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,79 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons + + +@six.add_metaclass(abc.ABCMeta) +class Ed448PublicKey(object): + @classmethod + def from_public_bytes(cls, data): + from cryptography.hazmat.backends.openssl.backend import backend + if not backend.ed448_supported(): + raise UnsupportedAlgorithm( + "ed448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ) + + return backend.ed448_load_public_bytes(data) + + @abc.abstractmethod + def public_bytes(self, encoding, format): + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def verify(self, signature, data): + """ + Verify the signature. + """ + + +@six.add_metaclass(abc.ABCMeta) +class Ed448PrivateKey(object): + @classmethod + def generate(cls): + from cryptography.hazmat.backends.openssl.backend import backend + if not backend.ed448_supported(): + raise UnsupportedAlgorithm( + "ed448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ) + return backend.ed448_generate_key() + + @classmethod + def from_private_bytes(cls, data): + from cryptography.hazmat.backends.openssl.backend import backend + if not backend.ed448_supported(): + raise UnsupportedAlgorithm( + "ed448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ) + + return backend.ed448_load_private_bytes(data) + + @abc.abstractmethod + def public_key(self): + """ + The Ed448PublicKey derived from the private key. + """ + + @abc.abstractmethod + def sign(self, data): + """ + Signs the data. + """ + + @abc.abstractmethod + def private_bytes(self, encoding, format, encryption_algorithm): + """ + The serialized bytes of the private key. + """ diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/asymmetric/utils.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/asymmetric/utils.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/asymmetric/utils.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/asymmetric/utils.py 2019-02-27 23:27:53.000000000 +0000 @@ -4,8 +4,6 @@ from __future__ import absolute_import, division, print_function -import warnings - from asn1crypto.algos import DSASignature import six @@ -14,31 +12,11 @@ from cryptography.hazmat.primitives import hashes -def decode_rfc6979_signature(signature): - warnings.warn( - "decode_rfc6979_signature is deprecated and will " - "be removed in a future version, use decode_dss_signature instead.", - utils.PersistentlyDeprecated, - stacklevel=2 - ) - return decode_dss_signature(signature) - - def decode_dss_signature(signature): data = DSASignature.load(signature, strict=True).native return data['r'], data['s'] -def encode_rfc6979_signature(r, s): - warnings.warn( - "encode_rfc6979_signature is deprecated and will " - "be removed in a future version, use encode_dss_signature instead.", - utils.PersistentlyDeprecated, - stacklevel=2 - ) - return encode_dss_signature(r, s) - - def encode_dss_signature(r, s): if ( not isinstance(r, six.integer_types) or diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/asymmetric/x25519.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/asymmetric/x25519.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/asymmetric/x25519.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/asymmetric/x25519.py 2019-02-27 23:27:53.000000000 +0000 @@ -21,11 +21,14 @@ "X25519 is not supported by this version of OpenSSL.", _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM ) + return backend.x25519_load_public_bytes(data) @abc.abstractmethod - def public_bytes(self): - pass + def public_bytes(self, encoding=None, format=None): + """ + The serialized bytes of the public key. + """ @six.add_metaclass(abc.ABCMeta) @@ -41,14 +44,30 @@ return backend.x25519_generate_key() @classmethod - def _from_private_bytes(cls, data): + def from_private_bytes(cls, data): from cryptography.hazmat.backends.openssl.backend import backend + if not backend.x25519_supported(): + raise UnsupportedAlgorithm( + "X25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM + ) + return backend.x25519_load_private_bytes(data) @abc.abstractmethod def public_key(self): - pass + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def private_bytes(self, encoding, format, encryption_algorithm): + """ + The serialized bytes of the private key. + """ @abc.abstractmethod def exchange(self, peer_public_key): - pass + """ + Performs a key exchange operation using the provided peer's public key. + """ diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/asymmetric/x448.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/asymmetric/x448.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/asymmetric/x448.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/asymmetric/x448.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,73 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons + + +@six.add_metaclass(abc.ABCMeta) +class X448PublicKey(object): + @classmethod + def from_public_bytes(cls, data): + from cryptography.hazmat.backends.openssl.backend import backend + if not backend.x448_supported(): + raise UnsupportedAlgorithm( + "X448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM + ) + + return backend.x448_load_public_bytes(data) + + @abc.abstractmethod + def public_bytes(self, encoding, format): + """ + The serialized bytes of the public key. + """ + + +@six.add_metaclass(abc.ABCMeta) +class X448PrivateKey(object): + @classmethod + def generate(cls): + from cryptography.hazmat.backends.openssl.backend import backend + if not backend.x448_supported(): + raise UnsupportedAlgorithm( + "X448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM + ) + return backend.x448_generate_key() + + @classmethod + def from_private_bytes(cls, data): + from cryptography.hazmat.backends.openssl.backend import backend + if not backend.x448_supported(): + raise UnsupportedAlgorithm( + "X448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM + ) + + return backend.x448_load_private_bytes(data) + + @abc.abstractmethod + def public_key(self): + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def private_bytes(self, encoding, format, encryption_algorithm): + """ + The serialized bytes of the private key. + """ + + @abc.abstractmethod + def exchange(self, peer_public_key): + """ + Performs a key exchange operation using the provided peer's public key. + """ diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/ciphers/aead.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/ciphers/aead.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/ciphers/aead.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/ciphers/aead.py 2019-02-27 23:27:53.000000000 +0000 @@ -12,13 +12,15 @@ class ChaCha20Poly1305(object): + _MAX_SIZE = 2 ** 32 + def __init__(self, key): if not backend.aead_cipher_supported(self): raise exceptions.UnsupportedAlgorithm( "ChaCha20Poly1305 is not supported by this version of OpenSSL", exceptions._Reasons.UNSUPPORTED_CIPHER ) - utils._check_bytes("key", key) + utils._check_byteslike("key", key) if len(key) != 32: raise ValueError("ChaCha20Poly1305 key must be 32 bytes.") @@ -33,6 +35,12 @@ if associated_data is None: associated_data = b"" + if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE: + # This is OverflowError to match what cffi would raise + raise OverflowError( + "Data or associated data too long. Max 2**32 bytes" + ) + self._check_params(nonce, data, associated_data) return aead._encrypt( backend, self, nonce, data, associated_data, 16 @@ -48,7 +56,7 @@ ) def _check_params(self, nonce, data, associated_data): - utils._check_bytes("nonce", nonce) + utils._check_byteslike("nonce", nonce) utils._check_bytes("data", data) utils._check_bytes("associated_data", associated_data) if len(nonce) != 12: @@ -56,8 +64,10 @@ class AESCCM(object): + _MAX_SIZE = 2 ** 32 + def __init__(self, key, tag_length=16): - utils._check_bytes("key", key) + utils._check_byteslike("key", key) if len(key) not in (16, 24, 32): raise ValueError("AESCCM key must be 128, 192, or 256 bits.") @@ -65,7 +75,7 @@ if not isinstance(tag_length, int): raise TypeError("tag_length must be an integer") - if tag_length not in (4, 6, 8, 12, 14, 16): + if tag_length not in (4, 6, 8, 10, 12, 14, 16): raise ValueError("Invalid tag_length") self._tag_length = tag_length @@ -90,6 +100,12 @@ if associated_data is None: associated_data = b"" + if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE: + # This is OverflowError to match what cffi would raise + raise OverflowError( + "Data or associated data too long. Max 2**32 bytes" + ) + self._check_params(nonce, data, associated_data) self._validate_lengths(nonce, len(data)) return aead._encrypt( @@ -113,7 +129,7 @@ raise ValueError("Nonce too long for data") def _check_params(self, nonce, data, associated_data): - utils._check_bytes("nonce", nonce) + utils._check_byteslike("nonce", nonce) utils._check_bytes("data", data) utils._check_bytes("associated_data", associated_data) if not 7 <= len(nonce) <= 13: @@ -121,8 +137,10 @@ class AESGCM(object): + _MAX_SIZE = 2 ** 32 + def __init__(self, key): - utils._check_bytes("key", key) + utils._check_byteslike("key", key) if len(key) not in (16, 24, 32): raise ValueError("AESGCM key must be 128, 192, or 256 bits.") @@ -142,6 +160,12 @@ if associated_data is None: associated_data = b"" + if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE: + # This is OverflowError to match what cffi would raise + raise OverflowError( + "Data or associated data too long. Max 2**32 bytes" + ) + self._check_params(nonce, data, associated_data) return aead._encrypt( backend, self, nonce, data, associated_data, 16 @@ -157,6 +181,8 @@ ) def _check_params(self, nonce, data, associated_data): - utils._check_bytes("nonce", nonce) + utils._check_byteslike("nonce", nonce) utils._check_bytes("data", data) utils._check_bytes("associated_data", associated_data) + if len(nonce) == 0: + raise ValueError("Nonce must be at least 1 byte") diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/ciphers/algorithms.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/ciphers/algorithms.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/ciphers/algorithms.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/ciphers/algorithms.py 2019-02-27 23:27:53.000000000 +0000 @@ -12,9 +12,12 @@ def _verify_key_size(algorithm, key): + # Verify that the key is instance of bytes + utils._check_byteslike("key", key) + # Verify that the key size matches the expected key size if len(key) * 8 not in algorithm.key_sizes: - raise ValueError("Invalid key size ({0}) for {1}.".format( + raise ValueError("Invalid key size ({}) for {}.".format( len(key) * 8, algorithm.name )) return key @@ -150,8 +153,7 @@ def __init__(self, key, nonce): self.key = _verify_key_size(self, key) - if not isinstance(nonce, bytes): - raise TypeError("nonce must be bytes") + utils._check_byteslike("nonce", nonce) if len(nonce) != 16: raise ValueError("nonce must be 128-bits (16 bytes)") diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/ciphers/base.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/ciphers/base.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/ciphers/base.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/ciphers/base.py 2019-02-27 23:27:53.000000000 +0000 @@ -179,7 +179,7 @@ self._bytes_processed += data_size if self._bytes_processed > self._ctx._mode._MAX_ENCRYPTED_BYTES: raise ValueError( - "{0} has a maximum encrypted byte limit of {1}".format( + "{} has a maximum encrypted byte limit of {}".format( self._ctx._mode.name, self._ctx._mode._MAX_ENCRYPTED_BYTES ) ) @@ -217,7 +217,7 @@ self._aad_bytes_processed += len(data) if self._aad_bytes_processed > self._ctx._mode._MAX_AAD_BYTES: raise ValueError( - "{0} has a maximum AAD byte limit of {1}".format( + "{} has a maximum AAD byte limit of {}".format( self._ctx._mode.name, self._ctx._mode._MAX_AAD_BYTES ) ) diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/ciphers/modes.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/ciphers/modes.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/ciphers/modes.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/ciphers/modes.py 2019-02-27 23:27:53.000000000 +0000 @@ -72,7 +72,7 @@ def _check_iv_length(self, algorithm): if len(self.initialization_vector) * 8 != algorithm.block_size: - raise ValueError("Invalid IV size ({0}) for {1}.".format( + raise ValueError("Invalid IV size ({}) for {}.".format( len(self.initialization_vector), self.name )) @@ -88,9 +88,7 @@ name = "CBC" def __init__(self, initialization_vector): - if not isinstance(initialization_vector, bytes): - raise TypeError("initialization_vector must be bytes") - + utils._check_byteslike("initialization_vector", initialization_vector) self._initialization_vector = initialization_vector initialization_vector = utils.read_only_property("_initialization_vector") @@ -103,8 +101,7 @@ name = "XTS" def __init__(self, tweak): - if not isinstance(tweak, bytes): - raise TypeError("tweak must be bytes") + utils._check_byteslike("tweak", tweak) if len(tweak) != 16: raise ValueError("tweak must be 128-bits (16 bytes)") @@ -134,9 +131,7 @@ name = "OFB" def __init__(self, initialization_vector): - if not isinstance(initialization_vector, bytes): - raise TypeError("initialization_vector must be bytes") - + utils._check_byteslike("initialization_vector", initialization_vector) self._initialization_vector = initialization_vector initialization_vector = utils.read_only_property("_initialization_vector") @@ -149,9 +144,7 @@ name = "CFB" def __init__(self, initialization_vector): - if not isinstance(initialization_vector, bytes): - raise TypeError("initialization_vector must be bytes") - + utils._check_byteslike("initialization_vector", initialization_vector) self._initialization_vector = initialization_vector initialization_vector = utils.read_only_property("_initialization_vector") @@ -164,9 +157,7 @@ name = "CFB8" def __init__(self, initialization_vector): - if not isinstance(initialization_vector, bytes): - raise TypeError("initialization_vector must be bytes") - + utils._check_byteslike("initialization_vector", initialization_vector) self._initialization_vector = initialization_vector initialization_vector = utils.read_only_property("_initialization_vector") @@ -179,9 +170,7 @@ name = "CTR" def __init__(self, nonce): - if not isinstance(nonce, bytes): - raise TypeError("nonce must be bytes") - + utils._check_byteslike("nonce", nonce) self._nonce = nonce nonce = utils.read_only_property("_nonce") @@ -189,7 +178,7 @@ def validate_for_algorithm(self, algorithm): _check_aes_key_length(self, algorithm) if len(self.nonce) * 8 != algorithm.block_size: - raise ValueError("Invalid nonce size ({0}) for {1}.".format( + raise ValueError("Invalid nonce size ({}) for {}.".format( len(self.nonce), self.name )) @@ -206,20 +195,21 @@ # len(initialization_vector) must in [1, 2 ** 64), but it's impossible # to actually construct a bytes object that large, so we don't check # for it - if not isinstance(initialization_vector, bytes): - raise TypeError("initialization_vector must be bytes") + utils._check_byteslike("initialization_vector", initialization_vector) + if len(initialization_vector) == 0: + raise ValueError("initialization_vector must be at least 1 byte") self._initialization_vector = initialization_vector if tag is not None: - if not isinstance(tag, bytes): - raise TypeError("tag must be bytes or None") + utils._check_bytes("tag", tag) if min_tag_length < 4: raise ValueError("min_tag_length must be >= 4") if len(tag) < min_tag_length: raise ValueError( - "Authentication tag must be {0} bytes or longer.".format( + "Authentication tag must be {} bytes or longer.".format( min_tag_length) ) self._tag = tag + self._min_tag_length = min_tag_length tag = utils.read_only_property("_tag") initialization_vector = utils.read_only_property("_initialization_vector") diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/cmac.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/cmac.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/cmac.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/cmac.py 2019-02-27 23:27:53.000000000 +0000 @@ -36,8 +36,8 @@ def update(self, data): if self._ctx is None: raise AlreadyFinalized("Context was already finalized.") - if not isinstance(data, bytes): - raise TypeError("data must be bytes.") + + utils._check_bytes("data", data) self._ctx.update(data) def finalize(self): @@ -48,8 +48,7 @@ return digest def verify(self, signature): - if not isinstance(signature, bytes): - raise TypeError("signature must be bytes.") + utils._check_bytes("signature", signature) if self._ctx is None: raise AlreadyFinalized("Context was already finalized.") diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/constant_time.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/constant_time.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/constant_time.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/constant_time.py 2019-02-27 23:27:53.000000000 +0000 @@ -5,7 +5,9 @@ from __future__ import absolute_import, division, print_function import hmac +import warnings +from cryptography import utils from cryptography.hazmat.bindings._constant_time import lib @@ -17,6 +19,13 @@ return hmac.compare_digest(a, b) else: + warnings.warn( + "Support for your Python version is deprecated. The next version of " + "cryptography will remove support. Please upgrade to a 2.7.x " + "release that supports hmac.compare_digest as soon as possible.", + utils.PersistentlyDeprecated2018, + ) + def bytes_eq(a, b): if not isinstance(a, bytes) or not isinstance(b, bytes): raise TypeError("a and b must be bytes.") diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/hashes.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/hashes.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/hashes.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/hashes.py 2019-02-27 23:27:53.000000000 +0000 @@ -29,12 +29,6 @@ The size of the resulting digest in bytes. """ - @abc.abstractproperty - def block_size(self): - """ - The internal block size of the hash algorithm in bytes. - """ - @six.add_metaclass(abc.ABCMeta) class HashContext(object): @@ -63,6 +57,13 @@ """ +@six.add_metaclass(abc.ABCMeta) +class ExtendableOutputFunction(object): + """ + An interface for extendable output functions. + """ + + @utils.register_interface(HashContext) class Hash(object): def __init__(self, algorithm, backend, ctx=None): @@ -88,8 +89,7 @@ def update(self, data): if self._ctx is None: raise AlreadyFinalized("Context was already finalized.") - if not isinstance(data, bytes): - raise TypeError("data must be bytes.") + utils._check_byteslike("data", data) self._ctx.update(data) def copy(self): @@ -115,6 +115,20 @@ @utils.register_interface(HashAlgorithm) +class SHA512_224(object): # noqa: N801 + name = "sha512-224" + digest_size = 28 + block_size = 128 + + +@utils.register_interface(HashAlgorithm) +class SHA512_256(object): # noqa: N801 + name = "sha512-256" + digest_size = 32 + block_size = 128 + + +@utils.register_interface(HashAlgorithm) class SHA224(object): name = "sha224" digest_size = 28 @@ -143,6 +157,64 @@ @utils.register_interface(HashAlgorithm) +class SHA3_224(object): # noqa: N801 + name = "sha3-224" + digest_size = 28 + + +@utils.register_interface(HashAlgorithm) +class SHA3_256(object): # noqa: N801 + name = "sha3-256" + digest_size = 32 + + +@utils.register_interface(HashAlgorithm) +class SHA3_384(object): # noqa: N801 + name = "sha3-384" + digest_size = 48 + + +@utils.register_interface(HashAlgorithm) +class SHA3_512(object): # noqa: N801 + name = "sha3-512" + digest_size = 64 + + +@utils.register_interface(HashAlgorithm) +@utils.register_interface(ExtendableOutputFunction) +class SHAKE128(object): + name = "shake128" + + def __init__(self, digest_size): + if not isinstance(digest_size, six.integer_types): + raise TypeError("digest_size must be an integer") + + if digest_size < 1: + raise ValueError("digest_size must be a positive integer") + + self._digest_size = digest_size + + digest_size = utils.read_only_property("_digest_size") + + +@utils.register_interface(HashAlgorithm) +@utils.register_interface(ExtendableOutputFunction) +class SHAKE256(object): + name = "shake256" + + def __init__(self, digest_size): + if not isinstance(digest_size, six.integer_types): + raise TypeError("digest_size must be an integer") + + if digest_size < 1: + raise ValueError("digest_size must be a positive integer") + + self._digest_size = digest_size + + digest_size = utils.read_only_property("_digest_size") + + +@utils.register_interface(HashAlgorithm) class MD5(object): name = "md5" digest_size = 16 @@ -157,13 +229,9 @@ block_size = 128 def __init__(self, digest_size): - if ( - digest_size > self._max_digest_size or - digest_size < self._min_digest_size - ): - raise ValueError("Digest size must be {0}-{1}".format( - self._min_digest_size, self._max_digest_size) - ) + + if digest_size != 64: + raise ValueError("Digest size must be 64") self._digest_size = digest_size @@ -178,13 +246,9 @@ _min_digest_size = 1 def __init__(self, digest_size): - if ( - digest_size > self._max_digest_size or - digest_size < self._min_digest_size - ): - raise ValueError("Digest size must be {0}-{1}".format( - self._min_digest_size, self._max_digest_size) - ) + + if digest_size != 32: + raise ValueError("Digest size must be 32") self._digest_size = digest_size diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/hmac.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/hmac.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/hmac.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/hmac.py 2019-02-27 23:27:53.000000000 +0000 @@ -38,8 +38,7 @@ def update(self, data): if self._ctx is None: raise AlreadyFinalized("Context was already finalized.") - if not isinstance(data, bytes): - raise TypeError("data must be bytes.") + utils._check_byteslike("data", data) self._ctx.update(data) def copy(self): @@ -60,8 +59,7 @@ return digest def verify(self, signature): - if not isinstance(signature, bytes): - raise TypeError("signature must be bytes.") + utils._check_bytes("signature", signature) if self._ctx is None: raise AlreadyFinalized("Context was already finalized.") diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/kdf/concatkdf.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/kdf/concatkdf.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/kdf/concatkdf.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/kdf/concatkdf.py 2019-02-27 23:27:53.000000000 +0000 @@ -24,17 +24,15 @@ max_length = algorithm.digest_size * (2 ** 32 - 1) if length > max_length: raise ValueError( - "Can not derive keys larger than {0} bits.".format( + "Can not derive keys larger than {} bits.".format( max_length )) - if not (otherinfo is None or isinstance(otherinfo, bytes)): - raise TypeError("otherinfo must be bytes.") + if otherinfo is not None: + utils._check_bytes("otherinfo", otherinfo) def _concatkdf_derive(key_material, length, auxfn, otherinfo): - if not isinstance(key_material, bytes): - raise TypeError("key_material must be bytes.") - + utils._check_byteslike("key_material", key_material) output = [b""] outlen = 0 counter = 1 @@ -96,10 +94,11 @@ if self._otherinfo is None: self._otherinfo = b"" - if not (salt is None or isinstance(salt, bytes)): - raise TypeError("salt must be bytes.") if salt is None: salt = b"\x00" * algorithm.block_size + else: + utils._check_bytes("salt", salt) + self._salt = salt if not isinstance(backend, HMACBackend): diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/kdf/hkdf.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/kdf/hkdf.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/kdf/hkdf.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/kdf/hkdf.py 2019-02-27 23:27:53.000000000 +0000 @@ -26,11 +26,10 @@ self._algorithm = algorithm - if not (salt is None or isinstance(salt, bytes)): - raise TypeError("salt must be bytes.") - if salt is None: - salt = b"\x00" * (self._algorithm.digest_size // 8) + salt = b"\x00" * self._algorithm.digest_size + else: + utils._check_bytes("salt", salt) self._salt = salt @@ -44,9 +43,7 @@ return h.finalize() def derive(self, key_material): - if not isinstance(key_material, bytes): - raise TypeError("key_material must be bytes.") - + utils._check_byteslike("key_material", key_material) return self._hkdf_expand.derive(self._extract(key_material)) def verify(self, key_material, expected_key): @@ -67,21 +64,20 @@ self._backend = backend - max_length = 255 * (algorithm.digest_size // 8) + max_length = 255 * algorithm.digest_size if length > max_length: raise ValueError( - "Can not derive keys larger than {0} octets.".format( + "Can not derive keys larger than {} octets.".format( max_length )) self._length = length - if not (info is None or isinstance(info, bytes)): - raise TypeError("info must be bytes.") - if info is None: info = b"" + else: + utils._check_bytes("info", info) self._info = info @@ -102,9 +98,7 @@ return b"".join(output)[:self._length] def derive(self, key_material): - if not isinstance(key_material, bytes): - raise TypeError("key_material must be bytes.") - + utils._check_byteslike("key_material", key_material) if self._used: raise AlreadyFinalized diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/kdf/kbkdf.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/kdf/kbkdf.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/kdf/kbkdf.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/kdf/kbkdf.py 2019-02-27 23:27:53.000000000 +0000 @@ -73,10 +73,8 @@ if context is None: context = b'' - if (not isinstance(label, bytes) or - not isinstance(context, bytes)): - raise TypeError('label and context must be of type bytes') - + utils._check_bytes("label", label) + utils._check_bytes("context", context) self._algorithm = algorithm self._mode = mode self._length = length @@ -102,8 +100,7 @@ if self._used: raise AlreadyFinalized - if not isinstance(key_material, bytes): - raise TypeError('key_material must be bytes') + utils._check_byteslike("key_material", key_material) self._used = True # inverse floor division (equivalent to ceiling) diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/kdf/pbkdf2.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/kdf/pbkdf2.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/kdf/pbkdf2.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/kdf/pbkdf2.py 2019-02-27 23:27:53.000000000 +0000 @@ -24,15 +24,14 @@ if not backend.pbkdf2_hmac_supported(algorithm): raise UnsupportedAlgorithm( - "{0} is not supported for PBKDF2 by this backend.".format( + "{} is not supported for PBKDF2 by this backend.".format( algorithm.name), _Reasons.UNSUPPORTED_HASH ) self._used = False self._algorithm = algorithm self._length = length - if not isinstance(salt, bytes): - raise TypeError("salt must be bytes.") + utils._check_bytes("salt", salt) self._salt = salt self._iterations = iterations self._backend = backend @@ -42,8 +41,7 @@ raise AlreadyFinalized("PBKDF2 instances can only be used once.") self._used = True - if not isinstance(key_material, bytes): - raise TypeError("key_material must be bytes.") + utils._check_byteslike("key_material", key_material) return self._backend.derive_pbkdf2_hmac( self._algorithm, self._length, diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/kdf/scrypt.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/kdf/scrypt.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/kdf/scrypt.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/kdf/scrypt.py 2019-02-27 23:27:53.000000000 +0000 @@ -30,9 +30,7 @@ ) self._length = length - if not isinstance(salt, bytes): - raise TypeError("salt must be bytes.") - + utils._check_bytes("salt", salt) if n < 2 or (n & (n - 1)) != 0: raise ValueError("n must be greater than 1 and be a power of 2.") @@ -54,8 +52,7 @@ raise AlreadyFinalized("Scrypt instances can only be used once.") self._used = True - if not isinstance(key_material, bytes): - raise TypeError("key_material must be bytes.") + utils._check_byteslike("key_material", key_material) return self._backend.derive_scrypt( key_material, self._salt, self._length, self._n, self._r, self._p ) diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/kdf/x963kdf.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/kdf/x963kdf.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/kdf/x963kdf.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/kdf/x963kdf.py 2019-02-27 23:27:53.000000000 +0000 @@ -26,9 +26,10 @@ max_len = algorithm.digest_size * (2 ** 32 - 1) if length > max_len: raise ValueError( - "Can not derive keys larger than {0} bits.".format(max_len)) - if not (sharedinfo is None or isinstance(sharedinfo, bytes)): - raise TypeError("sharedinfo must be bytes.") + "Can not derive keys larger than {} bits.".format(max_len)) + if sharedinfo is not None: + utils._check_bytes("sharedinfo", sharedinfo) + self._algorithm = algorithm self._length = length self._sharedinfo = sharedinfo @@ -45,10 +46,7 @@ if self._used: raise AlreadyFinalized self._used = True - - if not isinstance(key_material, bytes): - raise TypeError("key_material must be bytes.") - + utils._check_byteslike("key_material", key_material) output = [b""] outlen = 0 counter = 1 diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/keywrap.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/keywrap.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/keywrap.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/keywrap.py 2019-02-27 23:27:53.000000000 +0000 @@ -68,12 +68,74 @@ return a, r +def aes_key_wrap_with_padding(wrapping_key, key_to_wrap, backend): + if len(wrapping_key) not in [16, 24, 32]: + raise ValueError("The wrapping key must be a valid AES key length") + + aiv = b"\xA6\x59\x59\xA6" + struct.pack(">i", len(key_to_wrap)) + # pad the key to wrap if necessary + pad = (8 - (len(key_to_wrap) % 8)) % 8 + key_to_wrap = key_to_wrap + b"\x00" * pad + if len(key_to_wrap) == 8: + # RFC 5649 - 4.1 - exactly 8 octets after padding + encryptor = Cipher(AES(wrapping_key), ECB(), backend).encryptor() + b = encryptor.update(aiv + key_to_wrap) + assert encryptor.finalize() == b"" + return b + else: + r = [key_to_wrap[i:i + 8] for i in range(0, len(key_to_wrap), 8)] + return _wrap_core(wrapping_key, aiv, r, backend) + + +def aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend): + if len(wrapped_key) < 16: + raise InvalidUnwrap("Must be at least 16 bytes") + + if len(wrapping_key) not in [16, 24, 32]: + raise ValueError("The wrapping key must be a valid AES key length") + + if len(wrapped_key) == 16: + # RFC 5649 - 4.2 - exactly two 64-bit blocks + decryptor = Cipher(AES(wrapping_key), ECB(), backend).decryptor() + b = decryptor.update(wrapped_key) + assert decryptor.finalize() == b"" + a = b[:8] + data = b[8:] + n = 1 + else: + r = [wrapped_key[i:i + 8] for i in range(0, len(wrapped_key), 8)] + encrypted_aiv = r.pop(0) + n = len(r) + a, r = _unwrap_core(wrapping_key, encrypted_aiv, r, backend) + data = b"".join(r) + + # 1) Check that MSB(32,A) = A65959A6. + # 2) Check that 8*(n-1) < LSB(32,A) <= 8*n. If so, let + # MLI = LSB(32,A). + # 3) Let b = (8*n)-MLI, and then check that the rightmost b octets of + # the output data are zero. + (mli,) = struct.unpack(">I", a[4:]) + b = (8 * n) - mli + if ( + not bytes_eq(a[:4], b"\xa6\x59\x59\xa6") or not + 8 * (n - 1) < mli <= 8 * n or ( + b != 0 and not bytes_eq(data[-b:], b"\x00" * b) + ) + ): + raise InvalidUnwrap() + + if b == 0: + return data + else: + return data[:-b] + + def aes_key_unwrap(wrapping_key, wrapped_key, backend): if len(wrapped_key) < 24: - raise ValueError("Must be at least 24 bytes") + raise InvalidUnwrap("Must be at least 24 bytes") if len(wrapped_key) % 8 != 0: - raise ValueError("The wrapped key must be a multiple of 8 bytes") + raise InvalidUnwrap("The wrapped key must be a multiple of 8 bytes") if len(wrapping_key) not in [16, 24, 32]: raise ValueError("The wrapping key must be a valid AES key length") diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/padding.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/padding.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/padding.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/padding.py 2019-02-27 23:27:53.000000000 +0000 @@ -40,8 +40,7 @@ if buffer_ is None: raise AlreadyFinalized("Context was already finalized.") - if not isinstance(data, bytes): - raise TypeError("data must be bytes.") + utils._check_bytes("data", data) buffer_ += data @@ -65,8 +64,7 @@ if buffer_ is None: raise AlreadyFinalized("Context was already finalized.") - if not isinstance(data, bytes): - raise TypeError("data must be bytes.") + utils._check_bytes("data", data) buffer_ += data diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/serialization/base.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/serialization/base.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/serialization/base.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/serialization/base.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,82 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc +from enum import Enum + +import six + +from cryptography import utils + + +def load_pem_private_key(data, password, backend): + return backend.load_pem_private_key(data, password) + + +def load_pem_public_key(data, backend): + return backend.load_pem_public_key(data) + + +def load_pem_parameters(data, backend): + return backend.load_pem_parameters(data) + + +def load_der_private_key(data, password, backend): + return backend.load_der_private_key(data, password) + + +def load_der_public_key(data, backend): + return backend.load_der_public_key(data) + + +def load_der_parameters(data, backend): + return backend.load_der_parameters(data) + + +class Encoding(Enum): + PEM = "PEM" + DER = "DER" + OpenSSH = "OpenSSH" + Raw = "Raw" + X962 = "ANSI X9.62" + + +class PrivateFormat(Enum): + PKCS8 = "PKCS8" + TraditionalOpenSSL = "TraditionalOpenSSL" + Raw = "Raw" + + +class PublicFormat(Enum): + SubjectPublicKeyInfo = "X.509 subjectPublicKeyInfo with PKCS#1" + PKCS1 = "Raw PKCS#1" + OpenSSH = "OpenSSH" + Raw = "Raw" + CompressedPoint = "X9.62 Compressed Point" + UncompressedPoint = "X9.62 Uncompressed Point" + + +class ParameterFormat(Enum): + PKCS3 = "PKCS3" + + +@six.add_metaclass(abc.ABCMeta) +class KeySerializationEncryption(object): + pass + + +@utils.register_interface(KeySerializationEncryption) +class BestAvailableEncryption(object): + def __init__(self, password): + if not isinstance(password, bytes) or len(password) == 0: + raise ValueError("Password must be 1 or more bytes.") + + self.password = password + + +@utils.register_interface(KeySerializationEncryption) +class NoEncryption(object): + pass diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/serialization/__init__.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/serialization/__init__.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/serialization/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/serialization/__init__.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,26 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography.hazmat.primitives.serialization.base import ( + BestAvailableEncryption, Encoding, KeySerializationEncryption, + NoEncryption, ParameterFormat, PrivateFormat, PublicFormat, + load_der_parameters, load_der_private_key, load_der_public_key, + load_pem_parameters, load_pem_private_key, load_pem_public_key, +) +from cryptography.hazmat.primitives.serialization.ssh import ( + load_ssh_public_key +) + + +_PEM_DER = (Encoding.PEM, Encoding.DER) + +__all__ = [ + "load_der_parameters", "load_der_private_key", "load_der_public_key", + "load_pem_parameters", "load_pem_private_key", "load_pem_public_key", + "load_ssh_public_key", "Encoding", "PrivateFormat", "PublicFormat", + "ParameterFormat", "KeySerializationEncryption", "BestAvailableEncryption", + "NoEncryption", +] diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/serialization/pkcs12.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/serialization/pkcs12.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/serialization/pkcs12.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/serialization/pkcs12.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,9 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + + +def load_key_and_certificates(data, password, backend): + return backend.load_key_and_certificates_from_pkcs12(data, password) diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/serialization/ssh.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/serialization/ssh.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/serialization/ssh.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/serialization/ssh.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,153 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import base64 +import struct + +import six + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat.primitives.asymmetric import dsa, ec, ed25519, rsa + + +def load_ssh_public_key(data, backend): + key_parts = data.split(b' ', 2) + + if len(key_parts) < 2: + raise ValueError( + 'Key is not in the proper format or contains extra data.') + + key_type = key_parts[0] + + if key_type == b'ssh-rsa': + loader = _load_ssh_rsa_public_key + elif key_type == b'ssh-dss': + loader = _load_ssh_dss_public_key + elif key_type in [ + b'ecdsa-sha2-nistp256', b'ecdsa-sha2-nistp384', b'ecdsa-sha2-nistp521', + ]: + loader = _load_ssh_ecdsa_public_key + elif key_type == b'ssh-ed25519': + loader = _load_ssh_ed25519_public_key + else: + raise UnsupportedAlgorithm('Key type is not supported.') + + key_body = key_parts[1] + + try: + decoded_data = base64.b64decode(key_body) + except TypeError: + raise ValueError('Key is not in the proper format.') + + inner_key_type, rest = _ssh_read_next_string(decoded_data) + + if inner_key_type != key_type: + raise ValueError( + 'Key header and key body contain different key type values.' + ) + + return loader(key_type, rest, backend) + + +def _load_ssh_rsa_public_key(key_type, decoded_data, backend): + e, rest = _ssh_read_next_mpint(decoded_data) + n, rest = _ssh_read_next_mpint(rest) + + if rest: + raise ValueError('Key body contains extra bytes.') + + return rsa.RSAPublicNumbers(e, n).public_key(backend) + + +def _load_ssh_dss_public_key(key_type, decoded_data, backend): + p, rest = _ssh_read_next_mpint(decoded_data) + q, rest = _ssh_read_next_mpint(rest) + g, rest = _ssh_read_next_mpint(rest) + y, rest = _ssh_read_next_mpint(rest) + + if rest: + raise ValueError('Key body contains extra bytes.') + + parameter_numbers = dsa.DSAParameterNumbers(p, q, g) + public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers) + + return public_numbers.public_key(backend) + + +def _load_ssh_ecdsa_public_key(expected_key_type, decoded_data, backend): + curve_name, rest = _ssh_read_next_string(decoded_data) + data, rest = _ssh_read_next_string(rest) + + if expected_key_type != b"ecdsa-sha2-" + curve_name: + raise ValueError( + 'Key header and key body contain different key type values.' + ) + + if rest: + raise ValueError('Key body contains extra bytes.') + + curve = { + b"nistp256": ec.SECP256R1, + b"nistp384": ec.SECP384R1, + b"nistp521": ec.SECP521R1, + }[curve_name]() + + if six.indexbytes(data, 0) != 4: + raise NotImplementedError( + "Compressed elliptic curve points are not supported" + ) + + return ec.EllipticCurvePublicKey.from_encoded_point(curve, data) + + +def _load_ssh_ed25519_public_key(expected_key_type, decoded_data, backend): + data, rest = _ssh_read_next_string(decoded_data) + + if rest: + raise ValueError('Key body contains extra bytes.') + + return ed25519.Ed25519PublicKey.from_public_bytes(data) + + +def _ssh_read_next_string(data): + """ + Retrieves the next RFC 4251 string value from the data. + + While the RFC calls these strings, in Python they are bytes objects. + """ + if len(data) < 4: + raise ValueError("Key is not in the proper format") + + str_len, = struct.unpack('>I', data[:4]) + if len(data) < str_len + 4: + raise ValueError("Key is not in the proper format") + + return data[4:4 + str_len], data[4 + str_len:] + + +def _ssh_read_next_mpint(data): + """ + Reads the next mpint from the data. + + Currently, all mpints are interpreted as unsigned. + """ + mpint_data, rest = _ssh_read_next_string(data) + + return ( + utils.int_from_bytes(mpint_data, byteorder='big', signed=False), rest + ) + + +def _ssh_write_string(data): + return struct.pack(">I", len(data)) + data + + +def _ssh_write_mpint(value): + data = utils.int_to_bytes(value) + if six.indexbytes(data, 0) & 0x80: + data = b"\x00" + data + return _ssh_write_string(data) diff -Nru python-cryptography-2.1.4/src/cryptography/hazmat/primitives/serialization.py python-cryptography-2.6.1/src/cryptography/hazmat/primitives/serialization.py --- python-cryptography-2.1.4/src/cryptography/hazmat/primitives/serialization.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/hazmat/primitives/serialization.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,209 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import absolute_import, division, print_function - -import abc -import base64 -import struct -from enum import Enum - -import six - -from cryptography import utils -from cryptography.exceptions import UnsupportedAlgorithm -from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa - - -def load_pem_private_key(data, password, backend): - return backend.load_pem_private_key(data, password) - - -def load_pem_public_key(data, backend): - return backend.load_pem_public_key(data) - - -def load_pem_parameters(data, backend): - return backend.load_pem_parameters(data) - - -def load_der_private_key(data, password, backend): - return backend.load_der_private_key(data, password) - - -def load_der_public_key(data, backend): - return backend.load_der_public_key(data) - - -def load_der_parameters(data, backend): - return backend.load_der_parameters(data) - - -def load_ssh_public_key(data, backend): - key_parts = data.split(b' ', 2) - - if len(key_parts) < 2: - raise ValueError( - 'Key is not in the proper format or contains extra data.') - - key_type = key_parts[0] - - if key_type == b'ssh-rsa': - loader = _load_ssh_rsa_public_key - elif key_type == b'ssh-dss': - loader = _load_ssh_dss_public_key - elif key_type in [ - b'ecdsa-sha2-nistp256', b'ecdsa-sha2-nistp384', b'ecdsa-sha2-nistp521', - ]: - loader = _load_ssh_ecdsa_public_key - else: - raise UnsupportedAlgorithm('Key type is not supported.') - - key_body = key_parts[1] - - try: - decoded_data = base64.b64decode(key_body) - except TypeError: - raise ValueError('Key is not in the proper format.') - - inner_key_type, rest = _ssh_read_next_string(decoded_data) - - if inner_key_type != key_type: - raise ValueError( - 'Key header and key body contain different key type values.' - ) - - return loader(key_type, rest, backend) - - -def _load_ssh_rsa_public_key(key_type, decoded_data, backend): - e, rest = _ssh_read_next_mpint(decoded_data) - n, rest = _ssh_read_next_mpint(rest) - - if rest: - raise ValueError('Key body contains extra bytes.') - - return rsa.RSAPublicNumbers(e, n).public_key(backend) - - -def _load_ssh_dss_public_key(key_type, decoded_data, backend): - p, rest = _ssh_read_next_mpint(decoded_data) - q, rest = _ssh_read_next_mpint(rest) - g, rest = _ssh_read_next_mpint(rest) - y, rest = _ssh_read_next_mpint(rest) - - if rest: - raise ValueError('Key body contains extra bytes.') - - parameter_numbers = dsa.DSAParameterNumbers(p, q, g) - public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers) - - return public_numbers.public_key(backend) - - -def _load_ssh_ecdsa_public_key(expected_key_type, decoded_data, backend): - curve_name, rest = _ssh_read_next_string(decoded_data) - data, rest = _ssh_read_next_string(rest) - - if expected_key_type != b"ecdsa-sha2-" + curve_name: - raise ValueError( - 'Key header and key body contain different key type values.' - ) - - if rest: - raise ValueError('Key body contains extra bytes.') - - curve = { - b"nistp256": ec.SECP256R1, - b"nistp384": ec.SECP384R1, - b"nistp521": ec.SECP521R1, - }[curve_name]() - - if six.indexbytes(data, 0) != 4: - raise NotImplementedError( - "Compressed elliptic curve points are not supported" - ) - - numbers = ec.EllipticCurvePublicNumbers.from_encoded_point(curve, data) - return numbers.public_key(backend) - - -def _ssh_read_next_string(data): - """ - Retrieves the next RFC 4251 string value from the data. - - While the RFC calls these strings, in Python they are bytes objects. - """ - if len(data) < 4: - raise ValueError("Key is not in the proper format") - - str_len, = struct.unpack('>I', data[:4]) - if len(data) < str_len + 4: - raise ValueError("Key is not in the proper format") - - return data[4:4 + str_len], data[4 + str_len:] - - -def _ssh_read_next_mpint(data): - """ - Reads the next mpint from the data. - - Currently, all mpints are interpreted as unsigned. - """ - mpint_data, rest = _ssh_read_next_string(data) - - return ( - utils.int_from_bytes(mpint_data, byteorder='big', signed=False), rest - ) - - -def _ssh_write_string(data): - return struct.pack(">I", len(data)) + data - - -def _ssh_write_mpint(value): - data = utils.int_to_bytes(value) - if six.indexbytes(data, 0) & 0x80: - data = b"\x00" + data - return _ssh_write_string(data) - - -class Encoding(Enum): - PEM = "PEM" - DER = "DER" - OpenSSH = "OpenSSH" - - -class PrivateFormat(Enum): - PKCS8 = "PKCS8" - TraditionalOpenSSL = "TraditionalOpenSSL" - - -class PublicFormat(Enum): - SubjectPublicKeyInfo = "X.509 subjectPublicKeyInfo with PKCS#1" - PKCS1 = "Raw PKCS#1" - OpenSSH = "OpenSSH" - - -class ParameterFormat(Enum): - PKCS3 = "PKCS3" - - -@six.add_metaclass(abc.ABCMeta) -class KeySerializationEncryption(object): - pass - - -@utils.register_interface(KeySerializationEncryption) -class BestAvailableEncryption(object): - def __init__(self, password): - if not isinstance(password, bytes) or len(password) == 0: - raise ValueError("Password must be 1 or more bytes.") - - self.password = password - - -@utils.register_interface(KeySerializationEncryption) -class NoEncryption(object): - pass diff -Nru python-cryptography-2.1.4/src/cryptography/__init__.py python-cryptography-2.6.1/src/cryptography/__init__.py --- python-cryptography-2.1.4/src/cryptography/__init__.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/__init__.py 2019-02-27 23:27:53.000000000 +0000 @@ -4,9 +4,6 @@ from __future__ import absolute_import, division, print_function -import sys -import warnings - from cryptography.__about__ import ( __author__, __copyright__, __email__, __license__, __summary__, __title__, __uri__, __version__ @@ -17,11 +14,3 @@ "__title__", "__summary__", "__uri__", "__version__", "__author__", "__email__", "__license__", "__copyright__", ] - -if sys.version_info[:2] == (2, 6): - warnings.warn( - "Python 2.6 is no longer supported by the Python core team, please " - "upgrade your Python. The next version of cryptography will drop " - "support for Python 2.6", - DeprecationWarning - ) diff -Nru python-cryptography-2.1.4/src/cryptography/utils.py python-cryptography-2.6.1/src/cryptography/utils.py --- python-cryptography-2.1.4/src/cryptography/utils.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/utils.py 2019-02-27 23:27:53.000000000 +0000 @@ -11,17 +11,30 @@ import warnings +# We use a UserWarning subclass, instead of DeprecationWarning, because CPython +# decided deprecation warnings should be invisble by default. +class CryptographyDeprecationWarning(UserWarning): + pass + + # Several APIs were deprecated with no specific end-of-life date because of the # ubiquity of their use. They should not be removed until we agree on when that # cycle ends. -PersistentlyDeprecated = DeprecationWarning -DeprecatedIn19 = DeprecationWarning -DeprecatedIn21 = PendingDeprecationWarning +PersistentlyDeprecated2017 = CryptographyDeprecationWarning +PersistentlyDeprecated2018 = CryptographyDeprecationWarning +DeprecatedIn25 = CryptographyDeprecationWarning def _check_bytes(name, value): if not isinstance(value, bytes): - raise TypeError("{0} must be bytes".format(name)) + raise TypeError("{} must be bytes".format(name)) + + +def _check_byteslike(name, value): + try: + memoryview(value) + except TypeError: + raise TypeError("{} must be bytes-like".format(name)) def read_only_property(name): @@ -52,8 +65,7 @@ assert byteorder == 'big' assert not signed - # call bytes() on data to allow the use of bytearrays - return int(bytes(data).encode('hex'), 16) + return int(binascii.hexlify(data), 16) if hasattr(int, "to_bytes"): @@ -85,7 +97,7 @@ for method in iface.__abstractmethods__: if not hasattr(klass, method): raise InterfaceNotImplemented( - "{0} is missing a {1!r} method".format(klass, method) + "{} is missing a {!r} method".format(klass, method) ) if isinstance(getattr(iface, method), abc.abstractproperty): # Can't properly verify these yet. @@ -94,19 +106,17 @@ actual = signature(getattr(klass, method)) if sig != actual: raise InterfaceNotImplemented( - "{0}.{1}'s signature differs from the expected. Expected: " - "{2!r}. Received: {3!r}".format( + "{}.{}'s signature differs from the expected. Expected: " + "{!r}. Received: {!r}".format( klass, method, sig, actual ) ) -if sys.version_info >= (2, 7): - def bit_length(x): - return x.bit_length() -else: - def bit_length(x): - return len(bin(x)) - (2 + (x <= 0)) +# No longer needed as of 2.2, but retained because we have external consumers +# who use it. +def bit_length(x): + return x.bit_length() class _DeprecatedValue(object): @@ -149,7 +159,7 @@ def cached_property(func): - cached_name = "_cached_{0}".format(func) + cached_name = "_cached_{}".format(func) sentinel = object() def inner(instance): diff -Nru python-cryptography-2.1.4/src/cryptography/x509/base.py python-cryptography-2.6.1/src/cryptography/x509/base.py --- python-cryptography-2.1.4/src/cryptography/x509/base.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/x509/base.py 2019-02-27 23:27:53.000000000 +0000 @@ -17,7 +17,14 @@ from cryptography.x509.name import Name -_UNIX_EPOCH = datetime.datetime(1970, 1, 1) +_EARLIEST_UTC_TIME = datetime.datetime(1950, 1, 1) + + +def _reject_duplicate_extension(extension, extensions): + # This is quadratic in the number of extensions + for e in extensions: + if e.oid == extension.oid: + raise ValueError('This extension has already been set.') def _convert_to_naive_utc_time(time): @@ -189,6 +196,13 @@ Returns bytes using digest passed. """ + @abc.abstractmethod + def get_revoked_certificate_by_serial_number(self, serial_number): + """ + Returns an instance of RevokedCertificate or None if the serial_number + is not in the CRL. + """ + @abc.abstractproperty def signature_hash_algorithm(self): """ @@ -251,6 +265,24 @@ """ @abc.abstractmethod + def __len__(self): + """ + Number of revoked certificates in the CRL. + """ + + @abc.abstractmethod + def __getitem__(self, idx): + """ + Returns a revoked certificate (or slice of revoked certificates). + """ + + @abc.abstractmethod + def __iter__(self): + """ + Iterator over the revoked certificates + """ + + @abc.abstractmethod def is_signature_valid(self, public_key): """ Verifies signature of revocation list against given public key. @@ -381,11 +413,8 @@ raise TypeError("extension must be an ExtensionType") extension = Extension(extension.oid, critical, extension) + _reject_duplicate_extension(extension, self._extensions) - # TODO: This is quadratic in the number of extensions - for e in self._extensions: - if e.oid == extension.oid: - raise ValueError('This extension has already been set.') return CertificateSigningRequestBuilder( self._subject_name, self._extensions + [extension] ) @@ -469,7 +498,7 @@ # ASN.1 integers are always signed, so most significant bit must be # zero. - if utils.bit_length(number) >= 160: # As defined in RFC 5280 + if number.bit_length() >= 160: # As defined in RFC 5280 raise ValueError('The serial number should not be more than 159 ' 'bits.') return CertificateBuilder( @@ -487,9 +516,9 @@ if self._not_valid_before is not None: raise ValueError('The not valid before may only be set once.') time = _convert_to_naive_utc_time(time) - if time <= _UNIX_EPOCH: - raise ValueError('The not valid before date must be after the unix' - ' epoch (1970 January 1).') + if time < _EARLIEST_UTC_TIME: + raise ValueError('The not valid before date must be on or after' + ' 1950 January 1).') if self._not_valid_after is not None and time > self._not_valid_after: raise ValueError( 'The not valid before date must be before the not valid after ' @@ -510,9 +539,9 @@ if self._not_valid_after is not None: raise ValueError('The not valid after may only be set once.') time = _convert_to_naive_utc_time(time) - if time <= _UNIX_EPOCH: - raise ValueError('The not valid after date must be after the unix' - ' epoch (1970 January 1).') + if time < _EARLIEST_UTC_TIME: + raise ValueError('The not valid after date must be on or after' + ' 1950 January 1.') if (self._not_valid_before is not None and time < self._not_valid_before): raise ValueError( @@ -533,11 +562,7 @@ raise TypeError("extension must be an ExtensionType") extension = Extension(extension.oid, critical, extension) - - # TODO: This is quadratic in the number of extensions - for e in self._extensions: - if e.oid == extension.oid: - raise ValueError('This extension has already been set.') + _reject_duplicate_extension(extension, self._extensions) return CertificateBuilder( self._issuer_name, self._subject_name, @@ -595,9 +620,9 @@ if self._last_update is not None: raise ValueError('Last update may only be set once.') last_update = _convert_to_naive_utc_time(last_update) - if last_update <= _UNIX_EPOCH: - raise ValueError('The last update date must be after the unix' - ' epoch (1970 January 1).') + if last_update < _EARLIEST_UTC_TIME: + raise ValueError('The last update date must be on or after' + ' 1950 January 1.') if self._next_update is not None and last_update > self._next_update: raise ValueError( 'The last update date must be before the next update date.' @@ -613,9 +638,9 @@ if self._next_update is not None: raise ValueError('Last update may only be set once.') next_update = _convert_to_naive_utc_time(next_update) - if next_update <= _UNIX_EPOCH: - raise ValueError('The last update date must be after the unix' - ' epoch (1970 January 1).') + if next_update < _EARLIEST_UTC_TIME: + raise ValueError('The last update date must be on or after' + ' 1950 January 1.') if self._last_update is not None and next_update < self._last_update: raise ValueError( 'The next update date must be after the last update date.' @@ -633,11 +658,7 @@ raise TypeError("extension must be an ExtensionType") extension = Extension(extension.oid, critical, extension) - - # TODO: This is quadratic in the number of extensions - for e in self._extensions: - if e.oid == extension.oid: - raise ValueError('This extension has already been set.') + _reject_duplicate_extension(extension, self._extensions) return CertificateRevocationListBuilder( self._issuer_name, self._last_update, self._next_update, self._extensions + [extension], self._revoked_certificates @@ -686,7 +707,7 @@ # ASN.1 integers are always signed, so most significant bit must be # zero. - if utils.bit_length(number) >= 160: # As defined in RFC 5280 + if number.bit_length() >= 160: # As defined in RFC 5280 raise ValueError('The serial number should not be more than 159 ' 'bits.') return RevokedCertificateBuilder( @@ -699,9 +720,9 @@ if self._revocation_date is not None: raise ValueError('The revocation date may only be set once.') time = _convert_to_naive_utc_time(time) - if time <= _UNIX_EPOCH: - raise ValueError('The revocation date must be after the unix' - ' epoch (1970 January 1).') + if time < _EARLIEST_UTC_TIME: + raise ValueError('The revocation date must be on or after' + ' 1950 January 1.') return RevokedCertificateBuilder( self._serial_number, time, self._extensions ) @@ -711,11 +732,7 @@ raise TypeError("extension must be an ExtensionType") extension = Extension(extension.oid, critical, extension) - - # TODO: This is quadratic in the number of extensions - for e in self._extensions: - if e.oid == extension.oid: - raise ValueError('This extension has already been set.') + _reject_duplicate_extension(extension, self._extensions) return RevokedCertificateBuilder( self._serial_number, self._revocation_date, self._extensions + [extension] diff -Nru python-cryptography-2.1.4/src/cryptography/x509/extensions.py python-cryptography-2.6.1/src/cryptography/x509/extensions.py --- python-cryptography-2.1.4/src/cryptography/x509/extensions.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/x509/extensions.py 2019-02-27 23:27:53.000000000 +0000 @@ -24,7 +24,7 @@ from cryptography.x509.general_name import GeneralName, IPAddress, OtherName from cryptography.x509.name import RelativeDistinguishedName from cryptography.x509.oid import ( - CRLEntryExtensionOID, ExtensionOID, ObjectIdentifier + CRLEntryExtensionOID, ExtensionOID, OCSPExtensionOID, ObjectIdentifier, ) @@ -35,7 +35,10 @@ serialization.PublicFormat.PKCS1, ) elif isinstance(public_key, EllipticCurvePublicKey): - data = public_key.public_numbers().encode_point() + data = public_key.public_bytes( + serialization.Encoding.X962, + serialization.PublicFormat.UncompressedPoint + ) else: # This is a very slow way to do this. serialized = public_key.public_bytes( @@ -43,7 +46,7 @@ serialization.PublicFormat.SubjectPublicKeyInfo ) - data = six.binary_type(PublicKeyInfo.load(serialized)['public_key']) + data = bytes(PublicKeyInfo.load(serialized)['public_key']) return hashlib.sha1(data).digest() @@ -78,7 +81,7 @@ if ext.oid == oid: return ext - raise ExtensionNotFound("No {0} extension was found".format(oid), oid) + raise ExtensionNotFound("No {} extension was found".format(oid), oid) def get_extension_for_class(self, extclass): if extclass is UnrecognizedExtension: @@ -93,7 +96,7 @@ return ext raise ExtensionNotFound( - "No {0} extension was found".format(extclass), extclass.oid + "No {} extension was found".format(extclass), extclass.oid ) def __iter__(self): @@ -107,7 +110,7 @@ def __repr__(self): return ( - "".format(self._extensions) + "".format(self._extensions) ) @@ -134,7 +137,7 @@ return hash(self.crl_number) def __repr__(self): - return "".format(self.crl_number) + return "".format(self.crl_number) crl_number = utils.read_only_property("_crl_number") @@ -279,7 +282,7 @@ return len(self._descriptions) def __repr__(self): - return "".format(self._descriptions) + return "".format(self._descriptions) def __eq__(self, other): if not isinstance(other, AuthorityInformationAccess): @@ -426,7 +429,7 @@ return len(self._distribution_points) def __repr__(self): - return "".format(self._distribution_points) + return "".format(self._distribution_points) def __eq__(self, other): if not isinstance(other, CRLDistributionPoints): @@ -467,7 +470,7 @@ return len(self._distribution_points) def __repr__(self): - return "".format(self._distribution_points) + return "".format(self._distribution_points) def __eq__(self, other): if not isinstance(other, FreshestCRL): @@ -541,8 +544,8 @@ def __repr__(self): return ( "".format(self) + "tive_name}, reasons={0.reasons}, crl_issuer={0.crl_issuer})>" + .format(self) ) def __eq__(self, other): @@ -673,7 +676,7 @@ return len(self._policies) def __repr__(self): - return "".format(self._policies) + return "".format(self._policies) def __eq__(self, other): if not isinstance(other, CertificatePolicies): @@ -834,7 +837,7 @@ return len(self._usages) def __repr__(self): - return "".format(self._usages) + return "".format(self._usages) def __eq__(self, other): if not isinstance(other, ExtendedKeyUsage): @@ -855,6 +858,11 @@ @utils.register_interface(ExtensionType) +class PrecertPoison(object): + oid = ExtensionOID.PRECERT_POISON + + +@utils.register_interface(ExtensionType) class TLSFeature(object): oid = ExtensionOID.TLS_FEATURE @@ -1184,7 +1192,7 @@ return list(objs) def __repr__(self): - return "".format(self._general_names) + return "".format(self._general_names) def __eq__(self, other): if not isinstance(other, GeneralNames): @@ -1219,7 +1227,7 @@ return self._general_names.get_values_for_type(type) def __repr__(self): - return "".format(self._general_names) + return "".format(self._general_names) def __eq__(self, other): if not isinstance(other, SubjectAlternativeName): @@ -1254,7 +1262,7 @@ return self._general_names.get_values_for_type(type) def __repr__(self): - return "".format(self._general_names) + return "".format(self._general_names) def __eq__(self, other): if not isinstance(other, IssuerAlternativeName): @@ -1289,7 +1297,7 @@ return self._general_names.get_values_for_type(type) def __repr__(self): - return "".format(self._general_names) + return "".format(self._general_names) def __eq__(self, other): if not isinstance(other, CertificateIssuer): @@ -1318,7 +1326,7 @@ self._reason = reason def __repr__(self): - return "".format(self._reason) + return "".format(self._reason) def __eq__(self, other): if not isinstance(other, CRLReason): @@ -1346,7 +1354,7 @@ self._invalidity_date = invalidity_date def __repr__(self): - return "".format( + return "".format( self._invalidity_date ) @@ -1392,11 +1400,184 @@ def __repr__(self): return ( - "".format( + "".format( list(self) ) ) + def __hash__(self): + return hash(tuple(self._signed_certificate_timestamps)) + + def __eq__(self, other): + if not isinstance(other, PrecertificateSignedCertificateTimestamps): + return NotImplemented + + return ( + self._signed_certificate_timestamps == + other._signed_certificate_timestamps + ) + + def __ne__(self, other): + return not self == other + + +@utils.register_interface(ExtensionType) +class OCSPNonce(object): + oid = OCSPExtensionOID.NONCE + + def __init__(self, nonce): + if not isinstance(nonce, bytes): + raise TypeError("nonce must be bytes") + + self._nonce = nonce + + def __eq__(self, other): + if not isinstance(other, OCSPNonce): + return NotImplemented + + return self.nonce == other.nonce + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.nonce) + + def __repr__(self): + return "".format(self) + + nonce = utils.read_only_property("_nonce") + + +@utils.register_interface(ExtensionType) +class IssuingDistributionPoint(object): + oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT + + def __init__(self, full_name, relative_name, only_contains_user_certs, + only_contains_ca_certs, only_some_reasons, indirect_crl, + only_contains_attribute_certs): + if ( + only_some_reasons and ( + not isinstance(only_some_reasons, frozenset) or not all( + isinstance(x, ReasonFlags) for x in only_some_reasons + ) + ) + ): + raise TypeError( + "only_some_reasons must be None or frozenset of ReasonFlags" + ) + + if only_some_reasons and ( + ReasonFlags.unspecified in only_some_reasons or + ReasonFlags.remove_from_crl in only_some_reasons + ): + raise ValueError( + "unspecified and remove_from_crl are not valid reasons in an " + "IssuingDistributionPoint" + ) + + if not ( + isinstance(only_contains_user_certs, bool) and + isinstance(only_contains_ca_certs, bool) and + isinstance(indirect_crl, bool) and + isinstance(only_contains_attribute_certs, bool) + ): + raise TypeError( + "only_contains_user_certs, only_contains_ca_certs, " + "indirect_crl and only_contains_attribute_certs " + "must all be boolean." + ) + + crl_constraints = [ + only_contains_user_certs, only_contains_ca_certs, + indirect_crl, only_contains_attribute_certs + ] + + if len([x for x in crl_constraints if x]) > 1: + raise ValueError( + "Only one of the following can be set to True: " + "only_contains_user_certs, only_contains_ca_certs, " + "indirect_crl, only_contains_attribute_certs" + ) + + if ( + not any([ + only_contains_user_certs, only_contains_ca_certs, + indirect_crl, only_contains_attribute_certs, full_name, + relative_name, only_some_reasons + ]) + ): + raise ValueError( + "Cannot create empty extension: " + "if only_contains_user_certs, only_contains_ca_certs, " + "indirect_crl, and only_contains_attribute_certs are all False" + ", then either full_name, relative_name, or only_some_reasons " + "must have a value." + ) + + self._only_contains_user_certs = only_contains_user_certs + self._only_contains_ca_certs = only_contains_ca_certs + self._indirect_crl = indirect_crl + self._only_contains_attribute_certs = only_contains_attribute_certs + self._only_some_reasons = only_some_reasons + self._full_name = full_name + self._relative_name = relative_name + + def __repr__(self): + return ( + "".format(self) + ) + + def __eq__(self, other): + if not isinstance(other, IssuingDistributionPoint): + return NotImplemented + + return ( + self.full_name == other.full_name and + self.relative_name == other.relative_name and + self.only_contains_user_certs == other.only_contains_user_certs and + self.only_contains_ca_certs == other.only_contains_ca_certs and + self.only_some_reasons == other.only_some_reasons and + self.indirect_crl == other.indirect_crl and + self.only_contains_attribute_certs == + other.only_contains_attribute_certs + ) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(( + self.full_name, + self.relative_name, + self.only_contains_user_certs, + self.only_contains_ca_certs, + self.only_some_reasons, + self.indirect_crl, + self.only_contains_attribute_certs, + )) + + full_name = utils.read_only_property("_full_name") + relative_name = utils.read_only_property("_relative_name") + only_contains_user_certs = utils.read_only_property( + "_only_contains_user_certs" + ) + only_contains_ca_certs = utils.read_only_property( + "_only_contains_ca_certs" + ) + only_some_reasons = utils.read_only_property("_only_some_reasons") + indirect_crl = utils.read_only_property("_indirect_crl") + only_contains_attribute_certs = utils.read_only_property( + "_only_contains_attribute_certs" + ) + @utils.register_interface(ExtensionType) class UnrecognizedExtension(object): diff -Nru python-cryptography-2.1.4/src/cryptography/x509/general_name.py python-cryptography-2.6.1/src/cryptography/x509/general_name.py --- python-cryptography-2.1.4/src/cryptography/x509/general_name.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/x509/general_name.py 2019-02-27 23:27:53.000000000 +0000 @@ -9,8 +9,6 @@ import warnings from email.utils import parseaddr -import idna - import six from six.moves import urllib_parse @@ -32,6 +30,20 @@ } +def _lazy_import_idna(): + # Import idna lazily becase it allocates a decent amount of memory, and + # we're only using it in deprecated paths. + try: + import idna + return idna + except ImportError: + raise ImportError( + "idna is not installed, but a deprecated feature that requires it" + " was used. See: https://cryptography.io/en/latest/faq/#importe" + "rror-idna-is-not-installed" + ) + + class UnsupportedGeneralNameType(Exception): def __init__(self, msg, type): super(UnsupportedGeneralNameType, self).__init__(msg) @@ -59,8 +71,8 @@ "RFC822Name values should be passed as an A-label string. " "This means unicode characters should be encoded via " "idna. Support for passing unicode strings (aka U-label) " - " will be removed in a future version.", - utils.DeprecatedIn21, + "will be removed in a future version.", + utils.PersistentlyDeprecated2017, stacklevel=2, ) else: @@ -83,6 +95,7 @@ return instance def _idna_encode(self, value): + idna = _lazy_import_idna() _, address = parseaddr(value) parts = address.split(u"@") return parts[0] + "@" + idna.encode(parts[1]).decode("ascii") @@ -104,6 +117,7 @@ def _idna_encode(value): + idna = _lazy_import_idna() # Retain prefixes '*.' for common/alt names and '.' for name constraints for prefix in ['*.', '.']: if value.startswith(prefix): @@ -124,8 +138,8 @@ "DNSName values should be passed as an A-label string. " "This means unicode characters should be encoded via " "idna. Support for passing unicode strings (aka U-label) " - " will be removed in a future version.", - utils.DeprecatedIn21, + "will be removed in a future version.", + utils.PersistentlyDeprecated2017, stacklevel=2, ) else: @@ -170,7 +184,7 @@ "This means unicode characters should be encoded via " "idna. Support for passing unicode strings (aka U-label) " " will be removed in a future version.", - utils.DeprecatedIn21, + utils.PersistentlyDeprecated2017, stacklevel=2, ) else: @@ -187,11 +201,12 @@ return instance def _idna_encode(self, value): + idna = _lazy_import_idna() parsed = urllib_parse.urlparse(value) if parsed.port: netloc = ( idna.encode(parsed.hostname) + - ":{0}".format(parsed.port).encode("ascii") + ":{}".format(parsed.port).encode("ascii") ).decode("ascii") else: netloc = idna.encode(parsed.hostname).decode("ascii") @@ -235,7 +250,7 @@ value = utils.read_only_property("_value") def __repr__(self): - return "".format(self.value) + return "".format(self.value) def __eq__(self, other): if not isinstance(other, DirectoryName): @@ -261,7 +276,7 @@ value = utils.read_only_property("_value") def __repr__(self): - return "".format(self.value) + return "".format(self.value) def __eq__(self, other): if not isinstance(other, RegisteredID): @@ -299,7 +314,7 @@ value = utils.read_only_property("_value") def __repr__(self): - return "".format(self.value) + return "".format(self.value) def __eq__(self, other): if not isinstance(other, IPAddress): @@ -329,7 +344,7 @@ value = utils.read_only_property("_value") def __repr__(self): - return "".format( + return "".format( self.type_id, self.value) def __eq__(self, other): diff -Nru python-cryptography-2.1.4/src/cryptography/x509/__init__.py python-cryptography-2.6.1/src/cryptography/x509/__init__.py --- python-cryptography-2.1.4/src/cryptography/x509/__init__.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/x509/__init__.py 2019-02-27 23:27:53.000000000 +0000 @@ -21,8 +21,9 @@ DeltaCRLIndicator, DistributionPoint, DuplicateExtension, ExtendedKeyUsage, Extension, ExtensionNotFound, ExtensionType, Extensions, FreshestCRL, GeneralNames, InhibitAnyPolicy, InvalidityDate, IssuerAlternativeName, - KeyUsage, NameConstraints, NoticeReference, OCSPNoCheck, PolicyConstraints, - PolicyInformation, PrecertificateSignedCertificateTimestamps, ReasonFlags, + IssuingDistributionPoint, KeyUsage, NameConstraints, NoticeReference, + OCSPNoCheck, OCSPNonce, PolicyConstraints, PolicyInformation, + PrecertPoison, PrecertificateSignedCertificateTimestamps, ReasonFlags, SubjectAlternativeName, SubjectKeyIdentifier, TLSFeature, TLSFeatureType, UnrecognizedExtension, UserNotice ) @@ -74,6 +75,7 @@ OID_RSA_WITH_SHA256 = SignatureAlgorithmOID.RSA_WITH_SHA256 OID_RSA_WITH_SHA384 = SignatureAlgorithmOID.RSA_WITH_SHA384 OID_RSA_WITH_SHA512 = SignatureAlgorithmOID.RSA_WITH_SHA512 +OID_RSASSA_PSS = SignatureAlgorithmOID.RSASSA_PSS OID_COMMON_NAME = NameOID.COMMON_NAME OID_COUNTRY_NAME = NameOID.COUNTRY_NAME @@ -132,6 +134,7 @@ "Extension", "ExtendedKeyUsage", "FreshestCRL", + "IssuingDistributionPoint", "TLSFeature", "TLSFeatureType", "OCSPNoCheck", @@ -181,4 +184,6 @@ "UnrecognizedExtension", "PolicyConstraints", "PrecertificateSignedCertificateTimestamps", + "PrecertPoison", + "OCSPNonce", ] diff -Nru python-cryptography-2.1.4/src/cryptography/x509/name.py python-cryptography-2.6.1/src/cryptography/x509/name.py --- python-cryptography-2.1.4/src/cryptography/x509/name.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/x509/name.py 2019-02-27 23:27:53.000000000 +0000 @@ -27,6 +27,49 @@ _ASN1_TYPE_TO_ENUM = dict((i.value, i) for i in _ASN1Type) _SENTINEL = object() +_NAMEOID_DEFAULT_TYPE = { + NameOID.COUNTRY_NAME: _ASN1Type.PrintableString, + NameOID.JURISDICTION_COUNTRY_NAME: _ASN1Type.PrintableString, + NameOID.SERIAL_NUMBER: _ASN1Type.PrintableString, + NameOID.DN_QUALIFIER: _ASN1Type.PrintableString, + NameOID.EMAIL_ADDRESS: _ASN1Type.IA5String, + NameOID.DOMAIN_COMPONENT: _ASN1Type.IA5String, +} + +#: Short attribute names from RFC 4514: +#: https://tools.ietf.org/html/rfc4514#page-7 +_NAMEOID_TO_NAME = { + NameOID.COMMON_NAME: 'CN', + NameOID.LOCALITY_NAME: 'L', + NameOID.STATE_OR_PROVINCE_NAME: 'ST', + NameOID.ORGANIZATION_NAME: 'O', + NameOID.ORGANIZATIONAL_UNIT_NAME: 'OU', + NameOID.COUNTRY_NAME: 'C', + NameOID.STREET_ADDRESS: 'STREET', + NameOID.DOMAIN_COMPONENT: 'DC', + NameOID.USER_ID: 'UID', +} + + +def _escape_dn_value(val): + """Escape special characters in RFC4514 Distinguished Name value.""" + + # See https://tools.ietf.org/html/rfc4514#section-2.4 + val = val.replace('\\', '\\\\') + val = val.replace('"', '\\"') + val = val.replace('+', '\\+') + val = val.replace(',', '\\,') + val = val.replace(';', '\\;') + val = val.replace('<', '\\<') + val = val.replace('>', '\\>') + val = val.replace('\0', '\\00') + + if val[0] in ('#', ' '): + val = '\\' + val + if val[-1] == ' ': + val = val[:-1] + '\\ ' + + return val class NameAttribute(object): @@ -50,17 +93,17 @@ "Country name must be a 2 character country code" ) - if _type == _SENTINEL: - _type = _ASN1Type.PrintableString - if len(value) == 0: raise ValueError("Value cannot be an empty string") - # Set the default string type for encoding ASN1 strings to UTF8. This - # is the default for newer OpenSSLs for several years (1.0.1h+) and is - # recommended in RFC 2459. + # The appropriate ASN1 string type varies by OID and is defined across + # multiple RFCs including 2459, 3280, and 5280. In general UTF8String + # is preferred (2459), but 3280 and 5280 specify several OIDs with + # alternate types. This means when we see the sentinel value we need + # to look up whether the OID has a non-UTF8 type. If it does, set it + # to that. Otherwise, UTF8! if _type == _SENTINEL: - _type = _ASN1Type.UTF8String + _type = _NAMEOID_DEFAULT_TYPE.get(oid, _ASN1Type.UTF8String) if not isinstance(_type, _ASN1Type): raise TypeError("_type must be from the _ASN1Type enum") @@ -72,6 +115,16 @@ oid = utils.read_only_property("_oid") value = utils.read_only_property("_value") + def rfc4514_string(self): + """ + Format as RFC4514 Distinguished Name string. + + Use short attribute name if available, otherwise fall back to OID + dotted string. + """ + key = _NAMEOID_TO_NAME.get(self.oid, self.oid.dotted_string) + return '%s=%s' % (key, _escape_dn_value(self.value)) + def __eq__(self, other): if not isinstance(other, NameAttribute): return NotImplemented @@ -93,28 +146,42 @@ class RelativeDistinguishedName(object): def __init__(self, attributes): - attributes = frozenset(attributes) + attributes = list(attributes) if not attributes: raise ValueError("a relative distinguished name cannot be empty") if not all(isinstance(x, NameAttribute) for x in attributes): raise TypeError("attributes must be an iterable of NameAttribute") + # Keep list and frozenset to preserve attribute order where it matters self._attributes = attributes + self._attribute_set = frozenset(attributes) + + if len(self._attribute_set) != len(attributes): + raise ValueError("duplicate attributes are not allowed") def get_attributes_for_oid(self, oid): return [i for i in self if i.oid == oid] + def rfc4514_string(self): + """ + Format as RFC4514 Distinguished Name string. + + Within each RDN, attributes are joined by '+', although that is rarely + used in certificates. + """ + return '+'.join(attr.rfc4514_string() for attr in self._attributes) + def __eq__(self, other): if not isinstance(other, RelativeDistinguishedName): return NotImplemented - return self._attributes == other._attributes + return self._attribute_set == other._attribute_set def __ne__(self, other): return not self == other def __hash__(self): - return hash(self._attributes) + return hash(self._attribute_set) def __iter__(self): return iter(self._attributes) @@ -123,7 +190,7 @@ return len(self._attributes) def __repr__(self): - return "".format(list(self)) + return "".format(self.rfc4514_string()) class Name(object): @@ -141,6 +208,18 @@ " or a list RelativeDistinguishedName" ) + def rfc4514_string(self): + """ + Format as RFC4514 Distinguished Name string. + For example 'CN=foobar.com,O=Foo Corp,C=US' + + An X.509 name is a two-level structure: a list of sets of attributes. + Each list element is separated by ',' and within each list element, set + elements are separated by '+'. The latter is almost never used in + real world certificates. + """ + return ','.join(attr.rfc4514_string() for attr in self._attributes) + def get_attributes_for_oid(self, oid): return [i for i in self if i.oid == oid] @@ -174,4 +253,4 @@ return sum(len(rdn) for rdn in self._attributes) def __repr__(self): - return "".format(list(self)) + return "".format(self.rfc4514_string()) diff -Nru python-cryptography-2.1.4/src/cryptography/x509/ocsp.py python-cryptography-2.6.1/src/cryptography/x509/ocsp.py --- python-cryptography-2.1.4/src/cryptography/x509/ocsp.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/x509/ocsp.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,422 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc +import datetime +from enum import Enum + +import six + +from cryptography import x509 +from cryptography.hazmat.primitives import hashes +from cryptography.x509.base import ( + _EARLIEST_UTC_TIME, _convert_to_naive_utc_time, _reject_duplicate_extension +) + + +_OIDS_TO_HASH = { + "1.3.14.3.2.26": hashes.SHA1(), + "2.16.840.1.101.3.4.2.4": hashes.SHA224(), + "2.16.840.1.101.3.4.2.1": hashes.SHA256(), + "2.16.840.1.101.3.4.2.2": hashes.SHA384(), + "2.16.840.1.101.3.4.2.3": hashes.SHA512(), +} + + +class OCSPResponderEncoding(Enum): + HASH = "By Hash" + NAME = "By Name" + + +class OCSPResponseStatus(Enum): + SUCCESSFUL = 0 + MALFORMED_REQUEST = 1 + INTERNAL_ERROR = 2 + TRY_LATER = 3 + SIG_REQUIRED = 5 + UNAUTHORIZED = 6 + + +_RESPONSE_STATUS_TO_ENUM = dict((x.value, x) for x in OCSPResponseStatus) +_ALLOWED_HASHES = ( + hashes.SHA1, hashes.SHA224, hashes.SHA256, + hashes.SHA384, hashes.SHA512 +) + + +def _verify_algorithm(algorithm): + if not isinstance(algorithm, _ALLOWED_HASHES): + raise ValueError( + "Algorithm must be SHA1, SHA224, SHA256, SHA384, or SHA512" + ) + + +class OCSPCertStatus(Enum): + GOOD = 0 + REVOKED = 1 + UNKNOWN = 2 + + +_CERT_STATUS_TO_ENUM = dict((x.value, x) for x in OCSPCertStatus) + + +def load_der_ocsp_request(data): + from cryptography.hazmat.backends.openssl.backend import backend + return backend.load_der_ocsp_request(data) + + +def load_der_ocsp_response(data): + from cryptography.hazmat.backends.openssl.backend import backend + return backend.load_der_ocsp_response(data) + + +class OCSPRequestBuilder(object): + def __init__(self, request=None, extensions=[]): + self._request = request + self._extensions = extensions + + def add_certificate(self, cert, issuer, algorithm): + if self._request is not None: + raise ValueError("Only one certificate can be added to a request") + + _verify_algorithm(algorithm) + if ( + not isinstance(cert, x509.Certificate) or + not isinstance(issuer, x509.Certificate) + ): + raise TypeError("cert and issuer must be a Certificate") + + return OCSPRequestBuilder((cert, issuer, algorithm), self._extensions) + + def add_extension(self, extension, critical): + if not isinstance(extension, x509.ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = x509.Extension(extension.oid, critical, extension) + _reject_duplicate_extension(extension, self._extensions) + + return OCSPRequestBuilder( + self._request, self._extensions + [extension] + ) + + def build(self): + from cryptography.hazmat.backends.openssl.backend import backend + if self._request is None: + raise ValueError("You must add a certificate before building") + + return backend.create_ocsp_request(self) + + +class _SingleResponse(object): + def __init__(self, cert, issuer, algorithm, cert_status, this_update, + next_update, revocation_time, revocation_reason): + if ( + not isinstance(cert, x509.Certificate) or + not isinstance(issuer, x509.Certificate) + ): + raise TypeError("cert and issuer must be a Certificate") + + _verify_algorithm(algorithm) + if not isinstance(this_update, datetime.datetime): + raise TypeError("this_update must be a datetime object") + if ( + next_update is not None and + not isinstance(next_update, datetime.datetime) + ): + raise TypeError("next_update must be a datetime object or None") + + self._cert = cert + self._issuer = issuer + self._algorithm = algorithm + self._this_update = this_update + self._next_update = next_update + + if not isinstance(cert_status, OCSPCertStatus): + raise TypeError( + "cert_status must be an item from the OCSPCertStatus enum" + ) + if cert_status is not OCSPCertStatus.REVOKED: + if revocation_time is not None: + raise ValueError( + "revocation_time can only be provided if the certificate " + "is revoked" + ) + if revocation_reason is not None: + raise ValueError( + "revocation_reason can only be provided if the certificate" + " is revoked" + ) + else: + if not isinstance(revocation_time, datetime.datetime): + raise TypeError("revocation_time must be a datetime object") + + revocation_time = _convert_to_naive_utc_time(revocation_time) + if revocation_time < _EARLIEST_UTC_TIME: + raise ValueError('The revocation_time must be on or after' + ' 1950 January 1.') + + if ( + revocation_reason is not None and + not isinstance(revocation_reason, x509.ReasonFlags) + ): + raise TypeError( + "revocation_reason must be an item from the ReasonFlags " + "enum or None" + ) + + self._cert_status = cert_status + self._revocation_time = revocation_time + self._revocation_reason = revocation_reason + + +class OCSPResponseBuilder(object): + def __init__(self, response=None, responder_id=None, certs=None, + extensions=[]): + self._response = response + self._responder_id = responder_id + self._certs = certs + self._extensions = extensions + + def add_response(self, cert, issuer, algorithm, cert_status, this_update, + next_update, revocation_time, revocation_reason): + if self._response is not None: + raise ValueError("Only one response per OCSPResponse.") + + singleresp = _SingleResponse( + cert, issuer, algorithm, cert_status, this_update, next_update, + revocation_time, revocation_reason + ) + return OCSPResponseBuilder( + singleresp, self._responder_id, + self._certs, self._extensions, + ) + + def responder_id(self, encoding, responder_cert): + if self._responder_id is not None: + raise ValueError("responder_id can only be set once") + if not isinstance(responder_cert, x509.Certificate): + raise TypeError("responder_cert must be a Certificate") + if not isinstance(encoding, OCSPResponderEncoding): + raise TypeError( + "encoding must be an element from OCSPResponderEncoding" + ) + + return OCSPResponseBuilder( + self._response, (responder_cert, encoding), + self._certs, self._extensions, + ) + + def certificates(self, certs): + if self._certs is not None: + raise ValueError("certificates may only be set once") + certs = list(certs) + if len(certs) == 0: + raise ValueError("certs must not be an empty list") + if not all(isinstance(x, x509.Certificate) for x in certs): + raise TypeError("certs must be a list of Certificates") + return OCSPResponseBuilder( + self._response, self._responder_id, + certs, self._extensions, + ) + + def add_extension(self, extension, critical): + if not isinstance(extension, x509.ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = x509.Extension(extension.oid, critical, extension) + _reject_duplicate_extension(extension, self._extensions) + + return OCSPResponseBuilder( + self._response, self._responder_id, + self._certs, self._extensions + [extension], + ) + + def sign(self, private_key, algorithm): + from cryptography.hazmat.backends.openssl.backend import backend + if self._response is None: + raise ValueError("You must add a response before signing") + if self._responder_id is None: + raise ValueError("You must add a responder_id before signing") + + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Algorithm must be a registered hash algorithm.") + + return backend.create_ocsp_response( + OCSPResponseStatus.SUCCESSFUL, self, private_key, algorithm + ) + + @classmethod + def build_unsuccessful(cls, response_status): + from cryptography.hazmat.backends.openssl.backend import backend + if not isinstance(response_status, OCSPResponseStatus): + raise TypeError( + "response_status must be an item from OCSPResponseStatus" + ) + if response_status is OCSPResponseStatus.SUCCESSFUL: + raise ValueError("response_status cannot be SUCCESSFUL") + + return backend.create_ocsp_response(response_status, None, None, None) + + +@six.add_metaclass(abc.ABCMeta) +class OCSPRequest(object): + @abc.abstractproperty + def issuer_key_hash(self): + """ + The hash of the issuer public key + """ + + @abc.abstractproperty + def issuer_name_hash(self): + """ + The hash of the issuer name + """ + + @abc.abstractproperty + def hash_algorithm(self): + """ + The hash algorithm used in the issuer name and key hashes + """ + + @abc.abstractproperty + def serial_number(self): + """ + The serial number of the cert whose status is being checked + """ + @abc.abstractmethod + def public_bytes(self, encoding): + """ + Serializes the request to DER + """ + + @abc.abstractproperty + def extensions(self): + """ + The list of request extensions. Not single request extensions. + """ + + +@six.add_metaclass(abc.ABCMeta) +class OCSPResponse(object): + @abc.abstractproperty + def response_status(self): + """ + The status of the response. This is a value from the OCSPResponseStatus + enumeration + """ + + @abc.abstractproperty + def signature_algorithm_oid(self): + """ + The ObjectIdentifier of the signature algorithm + """ + + @abc.abstractproperty + def signature_hash_algorithm(self): + """ + Returns a HashAlgorithm corresponding to the type of the digest signed + """ + + @abc.abstractproperty + def signature(self): + """ + The signature bytes + """ + + @abc.abstractproperty + def tbs_response_bytes(self): + """ + The tbsResponseData bytes + """ + + @abc.abstractproperty + def certificates(self): + """ + A list of certificates used to help build a chain to verify the OCSP + response. This situation occurs when the OCSP responder uses a delegate + certificate. + """ + + @abc.abstractproperty + def responder_key_hash(self): + """ + The responder's key hash or None + """ + + @abc.abstractproperty + def responder_name(self): + """ + The responder's Name or None + """ + + @abc.abstractproperty + def produced_at(self): + """ + The time the response was produced + """ + + @abc.abstractproperty + def certificate_status(self): + """ + The status of the certificate (an element from the OCSPCertStatus enum) + """ + + @abc.abstractproperty + def revocation_time(self): + """ + The date of when the certificate was revoked or None if not + revoked. + """ + + @abc.abstractproperty + def revocation_reason(self): + """ + The reason the certificate was revoked or None if not specified or + not revoked. + """ + + @abc.abstractproperty + def this_update(self): + """ + The most recent time at which the status being indicated is known by + the responder to have been correct + """ + + @abc.abstractproperty + def next_update(self): + """ + The time when newer information will be available + """ + + @abc.abstractproperty + def issuer_key_hash(self): + """ + The hash of the issuer public key + """ + + @abc.abstractproperty + def issuer_name_hash(self): + """ + The hash of the issuer name + """ + + @abc.abstractproperty + def hash_algorithm(self): + """ + The hash algorithm used in the issuer name and key hashes + """ + + @abc.abstractproperty + def serial_number(self): + """ + The serial number of the cert whose status is being checked + """ + + @abc.abstractproperty + def extensions(self): + """ + The list of response extensions. Not single response extensions. + """ diff -Nru python-cryptography-2.1.4/src/cryptography/x509/oid.py python-cryptography-2.6.1/src/cryptography/x509/oid.py --- python-cryptography-2.1.4/src/cryptography/x509/oid.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography/x509/oid.py 2019-02-27 23:27:53.000000000 +0000 @@ -4,68 +4,10 @@ from __future__ import absolute_import, division, print_function -from cryptography import utils +from cryptography.hazmat._oid import ObjectIdentifier from cryptography.hazmat.primitives import hashes -class ObjectIdentifier(object): - def __init__(self, dotted_string): - self._dotted_string = dotted_string - - nodes = self._dotted_string.split(".") - intnodes = [] - - # There must be at least 2 nodes, the first node must be 0..2, and - # if less than 2, the second node cannot have a value outside the - # range 0..39. All nodes must be integers. - for node in nodes: - try: - intnodes.append(int(node, 0)) - except ValueError: - raise ValueError( - "Malformed OID: %s (non-integer nodes)" % ( - self._dotted_string)) - - if len(nodes) < 2: - raise ValueError( - "Malformed OID: %s (insufficient number of nodes)" % ( - self._dotted_string)) - - if intnodes[0] > 2: - raise ValueError( - "Malformed OID: %s (first node outside valid range)" % ( - self._dotted_string)) - - if intnodes[0] < 2 and intnodes[1] >= 40: - raise ValueError( - "Malformed OID: %s (second node outside valid range)" % ( - self._dotted_string)) - - def __eq__(self, other): - if not isinstance(other, ObjectIdentifier): - return NotImplemented - - return self.dotted_string == other.dotted_string - - def __ne__(self, other): - return not self == other - - def __repr__(self): - return "".format( - self.dotted_string, - self._name - ) - - def __hash__(self): - return hash(self.dotted_string) - - @property - def _name(self): - return _OID_NAMES.get(self, "Unknown OID") - - dotted_string = utils.read_only_property("_dotted_string") - - class ExtensionOID(object): SUBJECT_DIRECTORY_ATTRIBUTES = ObjectIdentifier("2.5.29.9") SUBJECT_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.14") @@ -82,6 +24,7 @@ EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37") FRESHEST_CRL = ObjectIdentifier("2.5.29.46") INHIBIT_ANY_POLICY = ObjectIdentifier("2.5.29.54") + ISSUING_DISTRIBUTION_POINT = ObjectIdentifier("2.5.29.28") AUTHORITY_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.1") SUBJECT_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.11") OCSP_NO_CHECK = ObjectIdentifier("1.3.6.1.5.5.7.48.1.5") @@ -91,6 +34,13 @@ PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS = ( ObjectIdentifier("1.3.6.1.4.1.11129.2.4.2") ) + PRECERT_POISON = ( + ObjectIdentifier("1.3.6.1.4.1.11129.2.4.3") + ) + + +class OCSPExtensionOID(object): + NONCE = ObjectIdentifier("1.3.6.1.5.5.7.48.1.2") class CRLEntryExtensionOID(object): @@ -137,6 +87,7 @@ RSA_WITH_SHA256 = ObjectIdentifier("1.2.840.113549.1.1.11") RSA_WITH_SHA384 = ObjectIdentifier("1.2.840.113549.1.1.12") RSA_WITH_SHA512 = ObjectIdentifier("1.2.840.113549.1.1.13") + RSASSA_PSS = ObjectIdentifier("1.2.840.113549.1.1.10") ECDSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10045.4.1") ECDSA_WITH_SHA224 = ObjectIdentifier("1.2.840.10045.4.3.1") ECDSA_WITH_SHA256 = ObjectIdentifier("1.2.840.10045.4.3.2") @@ -221,6 +172,7 @@ SignatureAlgorithmOID.RSA_WITH_SHA256: "sha256WithRSAEncryption", SignatureAlgorithmOID.RSA_WITH_SHA384: "sha384WithRSAEncryption", SignatureAlgorithmOID.RSA_WITH_SHA512: "sha512WithRSAEncryption", + SignatureAlgorithmOID.RSASSA_PSS: "RSASSA-PSS", SignatureAlgorithmOID.ECDSA_WITH_SHA1: "ecdsa-with-SHA1", SignatureAlgorithmOID.ECDSA_WITH_SHA224: "ecdsa-with-SHA224", SignatureAlgorithmOID.ECDSA_WITH_SHA256: "ecdsa-with-SHA256", @@ -241,6 +193,9 @@ ExtensionOID.SUBJECT_ALTERNATIVE_NAME: "subjectAltName", ExtensionOID.ISSUER_ALTERNATIVE_NAME: "issuerAltName", ExtensionOID.BASIC_CONSTRAINTS: "basicConstraints", + ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: ( + "signedCertificateTimestampList" + ), CRLEntryExtensionOID.CRL_REASON: "cRLReason", CRLEntryExtensionOID.INVALIDITY_DATE: "invalidityDate", CRLEntryExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer", @@ -253,6 +208,9 @@ ExtensionOID.EXTENDED_KEY_USAGE: "extendedKeyUsage", ExtensionOID.FRESHEST_CRL: "freshestCRL", ExtensionOID.INHIBIT_ANY_POLICY: "inhibitAnyPolicy", + ExtensionOID.ISSUING_DISTRIBUTION_POINT: ( + "issuingDistributionPoint" + ), ExtensionOID.AUTHORITY_INFORMATION_ACCESS: "authorityInfoAccess", ExtensionOID.SUBJECT_INFORMATION_ACCESS: "subjectInfoAccess", ExtensionOID.OCSP_NO_CHECK: "OCSPNoCheck", @@ -263,4 +221,5 @@ AuthorityInformationAccessOID.CA_ISSUERS: "caIssuers", CertificatePoliciesOID.CPS_QUALIFIER: "id-qt-cps", CertificatePoliciesOID.CPS_USER_NOTICE: "id-qt-unotice", + OCSPExtensionOID.NONCE: "OCSPNonce", } diff -Nru python-cryptography-2.1.4/src/cryptography.egg-info/PKG-INFO python-cryptography-2.6.1/src/cryptography.egg-info/PKG-INFO --- python-cryptography-2.1.4/src/cryptography.egg-info/PKG-INFO 2017-11-30 01:55:14.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography.egg-info/PKG-INFO 2019-02-27 23:28:30.000000000 +0000 @@ -1,17 +1,16 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: cryptography -Version: 2.1.4 +Version: 2.6.1 Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers. Home-page: https://github.com/pyca/cryptography Author: The cryptography developers Author-email: cryptography-dev@python.org License: BSD or Apache License, Version 2.0 -Description-Content-Type: UNKNOWN Description: pyca/cryptography ================= .. image:: https://img.shields.io/pypi/v/cryptography.svg - :target: https://pypi.python.org/pypi/cryptography/ + :target: https://pypi.org/project/cryptography/ :alt: Latest Version .. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest @@ -27,7 +26,7 @@ ``cryptography`` is a package which provides cryptographic recipes and primitives to Python developers. Our goal is for it to be your "cryptographic - standard library". It supports Python 2.6-2.7, Python 3.4+, and PyPy 5.3+. + standard library". It supports Python 2.7, Python 3.4+, and PyPy 5.4+. ``cryptography`` includes both high level recipes and low level interfaces to common cryptographic algorithms such as symmetric ciphers, message digests, and @@ -66,13 +65,21 @@ You can also join ``#cryptography-dev`` on Freenode to ask questions or get involved. + Security + ~~~~~~~~ + + Need to report a security issue? Please consult our `security reporting`_ + documentation. + .. _`documentation`: https://cryptography.io/ .. _`the installation documentation`: https://cryptography.io/en/latest/installation/ .. _`issue tracker`: https://github.com/pyca/cryptography/issues .. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev + .. _`security reporting`: https://cryptography.io/en/latest/security/ Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Apache Software License Classifier: License :: OSI Approved :: BSD License @@ -84,12 +91,18 @@ Classifier: Operating System :: Microsoft :: Windows Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Security :: Cryptography +Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.* +Provides-Extra: idna +Provides-Extra: docstest +Provides-Extra: pep8test +Provides-Extra: docs +Provides-Extra: test diff -Nru python-cryptography-2.1.4/src/cryptography.egg-info/requires.txt python-cryptography-2.6.1/src/cryptography.egg-info/requires.txt --- python-cryptography-2.1.4/src/cryptography.egg-info/requires.txt 2017-11-30 01:55:14.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography.egg-info/requires.txt 2019-02-27 23:28:30.000000000 +0000 @@ -1,21 +1,23 @@ -idna>=2.1 asn1crypto>=0.21.0 six>=1.4.1 - -[:platform_python_implementation != 'PyPy'] -cffi>=1.7 +cffi!=1.11.3,>=1.8 [:python_version < '3'] enum34 ipaddress +[docs] +sphinx!=1.8.0,>=1.6.5 +sphinx_rtd_theme + [docstest] doc8 pyenchant>=1.6.11 -readme_renderer>=16.0 -sphinx -sphinx_rtd_theme -sphinxcontrib-spelling +twine>=1.12.0 +sphinxcontrib-spelling>=4.0.1 + +[idna] +idna>=2.1 [pep8test] flake8 @@ -23,8 +25,8 @@ pep8-naming [test] -pytest!=3.3.0,>=3.2.1 +pytest!=3.9.0,!=3.9.1,!=3.9.2,>=3.6.0 pretend iso8601 pytz -hypothesis>=1.11.4 +hypothesis!=3.79.2,>=1.11.4 diff -Nru python-cryptography-2.1.4/src/cryptography.egg-info/SOURCES.txt python-cryptography-2.6.1/src/cryptography.egg-info/SOURCES.txt --- python-cryptography-2.1.4/src/cryptography.egg-info/SOURCES.txt 2017-11-30 01:55:14.000000000 +0000 +++ python-cryptography-2.6.1/src/cryptography.egg-info/SOURCES.txt 2019-02-27 23:28:31.000000000 +0000 @@ -6,6 +6,7 @@ LICENSE.BSD MANIFEST.in README.rst +pyproject.toml setup.py docs/Makefile docs/api-stability.rst @@ -13,7 +14,6 @@ docs/community.rst docs/conf.py docs/cryptography-docs.py -docs/docutils.conf docs/doing-a-release.rst docs/exceptions.rst docs/faq.rst @@ -35,6 +35,7 @@ docs/development/test-vectors.rst docs/development/custom-vectors/arc4.rst docs/development/custom-vectors/cast5.rst +docs/development/custom-vectors/hkdf.rst docs/development/custom-vectors/idea.rst docs/development/custom-vectors/rsa-oaep-sha2.rst docs/development/custom-vectors/secp256k1.rst @@ -43,6 +44,8 @@ docs/development/custom-vectors/arc4/verify_arc4.go docs/development/custom-vectors/cast5/generate_cast5.py docs/development/custom-vectors/cast5/verify_cast5.go +docs/development/custom-vectors/hkdf/generate_hkdf.py +docs/development/custom-vectors/hkdf/verify_hkdf.go docs/development/custom-vectors/idea/generate_idea.py docs/development/custom-vectors/idea/verify_idea.py docs/development/custom-vectors/rsa-oaep-sha2/VerifyRSAOAEPSHA2.java @@ -68,16 +71,20 @@ docs/hazmat/primitives/asymmetric/dh.rst docs/hazmat/primitives/asymmetric/dsa.rst docs/hazmat/primitives/asymmetric/ec.rst +docs/hazmat/primitives/asymmetric/ed25519.rst +docs/hazmat/primitives/asymmetric/ed448.rst docs/hazmat/primitives/asymmetric/index.rst docs/hazmat/primitives/asymmetric/rsa.rst docs/hazmat/primitives/asymmetric/serialization.rst docs/hazmat/primitives/asymmetric/utils.rst docs/hazmat/primitives/asymmetric/x25519.rst +docs/hazmat/primitives/asymmetric/x448.rst docs/hazmat/primitives/mac/cmac.rst docs/hazmat/primitives/mac/hmac.rst docs/hazmat/primitives/mac/index.rst docs/x509/certificate-transparency.rst docs/x509/index.rst +docs/x509/ocsp.rst docs/x509/reference.rst docs/x509/tutorial.rst src/_cffi_src/__init__.py @@ -96,7 +103,6 @@ src/_cffi_src/openssl/bio.py src/_cffi_src/openssl/callbacks.py src/_cffi_src/openssl/cmac.py -src/_cffi_src/openssl/cms.py src/_cffi_src/openssl/conf.py src/_cffi_src/openssl/crypto.py src/_cffi_src/openssl/cryptography.py @@ -140,6 +146,7 @@ src/cryptography.egg-info/requires.txt src/cryptography.egg-info/top_level.txt src/cryptography/hazmat/__init__.py +src/cryptography/hazmat/_oid.py src/cryptography/hazmat/backends/__init__.py src/cryptography/hazmat/backends/interfaces.py src/cryptography/hazmat/backends/openssl/__init__.py @@ -151,12 +158,16 @@ src/cryptography/hazmat/backends/openssl/dh.py src/cryptography/hazmat/backends/openssl/dsa.py src/cryptography/hazmat/backends/openssl/ec.py +src/cryptography/hazmat/backends/openssl/ed25519.py +src/cryptography/hazmat/backends/openssl/ed448.py src/cryptography/hazmat/backends/openssl/encode_asn1.py src/cryptography/hazmat/backends/openssl/hashes.py src/cryptography/hazmat/backends/openssl/hmac.py +src/cryptography/hazmat/backends/openssl/ocsp.py src/cryptography/hazmat/backends/openssl/rsa.py src/cryptography/hazmat/backends/openssl/utils.py src/cryptography/hazmat/backends/openssl/x25519.py +src/cryptography/hazmat/backends/openssl/x448.py src/cryptography/hazmat/backends/openssl/x509.py src/cryptography/hazmat/bindings/__init__.py src/cryptography/hazmat/bindings/openssl/__init__.py @@ -170,15 +181,17 @@ src/cryptography/hazmat/primitives/keywrap.py src/cryptography/hazmat/primitives/mac.py src/cryptography/hazmat/primitives/padding.py -src/cryptography/hazmat/primitives/serialization.py src/cryptography/hazmat/primitives/asymmetric/__init__.py src/cryptography/hazmat/primitives/asymmetric/dh.py src/cryptography/hazmat/primitives/asymmetric/dsa.py src/cryptography/hazmat/primitives/asymmetric/ec.py +src/cryptography/hazmat/primitives/asymmetric/ed25519.py +src/cryptography/hazmat/primitives/asymmetric/ed448.py src/cryptography/hazmat/primitives/asymmetric/padding.py src/cryptography/hazmat/primitives/asymmetric/rsa.py src/cryptography/hazmat/primitives/asymmetric/utils.py src/cryptography/hazmat/primitives/asymmetric/x25519.py +src/cryptography/hazmat/primitives/asymmetric/x448.py src/cryptography/hazmat/primitives/ciphers/__init__.py src/cryptography/hazmat/primitives/ciphers/aead.py src/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -191,6 +204,10 @@ src/cryptography/hazmat/primitives/kdf/pbkdf2.py src/cryptography/hazmat/primitives/kdf/scrypt.py src/cryptography/hazmat/primitives/kdf/x963kdf.py +src/cryptography/hazmat/primitives/serialization/__init__.py +src/cryptography/hazmat/primitives/serialization/base.py +src/cryptography/hazmat/primitives/serialization/pkcs12.py +src/cryptography/hazmat/primitives/serialization/ssh.py src/cryptography/hazmat/primitives/twofactor/__init__.py src/cryptography/hazmat/primitives/twofactor/hotp.py src/cryptography/hazmat/primitives/twofactor/totp.py @@ -201,6 +218,7 @@ src/cryptography/x509/extensions.py src/cryptography/x509/general_name.py src/cryptography/x509/name.py +src/cryptography/x509/ocsp.py src/cryptography/x509/oid.py tests/__init__.py tests/conftest.py @@ -237,6 +255,8 @@ tests/hazmat/primitives/test_dh.py tests/hazmat/primitives/test_dsa.py tests/hazmat/primitives/test_ec.py +tests/hazmat/primitives/test_ed25519.py +tests/hazmat/primitives/test_ed448.py tests/hazmat/primitives/test_hash_vectors.py tests/hazmat/primitives/test_hashes.py tests/hazmat/primitives/test_hkdf.py @@ -250,11 +270,13 @@ tests/hazmat/primitives/test_padding.py tests/hazmat/primitives/test_pbkdf2hmac.py tests/hazmat/primitives/test_pbkdf2hmac_vectors.py +tests/hazmat/primitives/test_pkcs12.py tests/hazmat/primitives/test_rsa.py tests/hazmat/primitives/test_scrypt.py tests/hazmat/primitives/test_seed.py tests/hazmat/primitives/test_serialization.py tests/hazmat/primitives/test_x25519.py +tests/hazmat/primitives/test_x448.py tests/hazmat/primitives/test_x963_vectors.py tests/hazmat/primitives/test_x963kdf.py tests/hazmat/primitives/utils.py @@ -264,7 +286,20 @@ tests/hypothesis/__init__.py tests/hypothesis/test_fernet.py tests/hypothesis/test_padding.py +tests/wycheproof/__init__.py +tests/wycheproof/test_aes.py +tests/wycheproof/test_chacha20poly1305.py +tests/wycheproof/test_cmac.py +tests/wycheproof/test_dsa.py +tests/wycheproof/test_ecdh.py +tests/wycheproof/test_ecdsa.py +tests/wycheproof/test_eddsa.py +tests/wycheproof/test_keywrap.py +tests/wycheproof/test_rsa.py +tests/wycheproof/test_utils.py +tests/wycheproof/test_x25519.py tests/x509/__init__.py +tests/x509/test_ocsp.py tests/x509/test_x509.py tests/x509/test_x509_crlbuilder.py tests/x509/test_x509_ext.py diff -Nru python-cryptography-2.1.4/tests/conftest.py python-cryptography-2.6.1/tests/conftest.py --- python-cryptography-2.1.4/tests/conftest.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/conftest.py 2019-02-27 23:27:53.000000000 +0000 @@ -8,24 +8,42 @@ from cryptography.hazmat.backends.openssl import backend as openssl_backend -from .utils import check_backend_support +from .utils import ( + check_backend_support, load_wycheproof_tests, skip_if_wycheproof_none +) def pytest_report_header(config): - return "OpenSSL: {0}".format(openssl_backend.openssl_version_text()) + return "OpenSSL: {}".format(openssl_backend.openssl_version_text()) + + +def pytest_addoption(parser): + parser.addoption("--wycheproof-root", default=None) + + +def pytest_generate_tests(metafunc): + if "wycheproof" in metafunc.fixturenames: + wycheproof = metafunc.config.getoption("--wycheproof-root") + skip_if_wycheproof_none(wycheproof) + + testcases = [] + marker = metafunc.definition.get_closest_marker("wycheproof_tests") + for path in marker.args: + testcases.extend(load_wycheproof_tests(wycheproof, path)) + metafunc.parametrize("wycheproof", testcases) @pytest.fixture() def backend(request): required_interfaces = [ mark.kwargs["interface"] - for mark in request.node.get_marker("requires_backend_interface") + for mark in request.node.iter_markers("requires_backend_interface") ] if not all( isinstance(openssl_backend, iface) for iface in required_interfaces ): pytest.skip( - "OpenSSL doesn't implement required interfaces: {0}".format( + "OpenSSL doesn't implement required interfaces: {}".format( required_interfaces ) ) diff -Nru python-cryptography-2.1.4/tests/hazmat/backends/test_openssl_memleak.py python-cryptography-2.6.1/tests/hazmat/backends/test_openssl_memleak.py --- python-cryptography-2.1.4/tests/hazmat/backends/test_openssl_memleak.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/backends/test_openssl_memleak.py 2019-02-27 23:27:53.000000000 +0000 @@ -23,14 +23,46 @@ import gc import json + import cffi + from cryptography.hazmat.bindings._openssl import ffi, lib heap = {} + BACKTRACE_ENABLED = False + if BACKTRACE_ENABLED: + backtrace_ffi = cffi.FFI() + backtrace_ffi.cdef(''' + int backtrace(void **, int); + char **backtrace_symbols(void *const *, int); + ''') + backtrace_lib = backtrace_ffi.dlopen(None) + + def backtrace(): + buf = backtrace_ffi.new("void*[]", 24) + length = backtrace_lib.backtrace(buf, len(buf)) + return (buf, length) + + def symbolize_backtrace(trace): + (buf, length) = trace + symbols = backtrace_lib.backtrace_symbols(buf, length) + stack = [ + backtrace_ffi.string(symbols[i]).decode() + for i in range(length) + ] + lib.Cryptography_free_wrapper(symbols, backtrace_ffi.NULL, 0) + return stack + else: + def backtrace(): + return None + + def symbolize_backtrace(trace): + return None + @ffi.callback("void *(size_t, const char *, int)") def malloc(size, path, line): ptr = lib.Cryptography_malloc_wrapper(size, path, line) - heap[ptr] = (size, path, line) + heap[ptr] = (size, path, line, backtrace()) return ptr @ffi.callback("void *(void *, size_t, const char *, int)") @@ -38,7 +70,7 @@ if ptr != ffi.NULL: del heap[ptr] new_ptr = lib.Cryptography_realloc_wrapper(ptr, size, path, line) - heap[new_ptr] = (size, path, line) + heap[new_ptr] = (size, path, line, backtrace()) return new_ptr @ffi.callback("void(void *, const char *, int)") @@ -60,6 +92,9 @@ gc.collect() gc.collect() + if lib.Cryptography_HAS_OPENSSL_CLEANUP: + lib.OPENSSL_cleanup() + # Swap back to the original functions so that if OpenSSL tries to free # something from its atexit handle it won't be going through a Python # function, which will be deallocated when this function returns @@ -78,6 +113,7 @@ "size": heap[ptr][0], "path": ffi.string(heap[ptr][1]).decode(), "line": heap[ptr][2], + "backtrace": symbolize_backtrace(heap[ptr][3]), }) for ptr in remaining ))) @@ -92,7 +128,7 @@ env = os.environ.copy() env["PYTHONPATH"] = os.pathsep.join(sys.path) argv = [ - sys.executable, "-c", "{0}\n\n{1}".format(s, MEMORY_LEAK_SCRIPT) + sys.executable, "-c", "{}\n\n{}".format(s, MEMORY_LEAK_SCRIPT) ] + argv # Shell out to a fresh Python process because OpenSSL does not allow you to # install new memory hooks after the first malloc/free occurs. @@ -174,7 +210,7 @@ @pytest.mark.parametrize("path", [ "x509/PKITS_data/certs/ValidcRLIssuerTest28EE.crt", ]) - def test_x509_extensions(self, path): + def test_x509_certificate_extensions(self, path): assert_no_memory_leaks(textwrap.dedent(""" def func(path): from cryptography import x509 @@ -190,6 +226,26 @@ cert.extensions """), [path]) + def test_x509_csr_extensions(self): + assert_no_memory_leaks(textwrap.dedent(""" + def func(): + from cryptography import x509 + from cryptography.hazmat.backends.openssl import backend + from cryptography.hazmat.primitives import hashes + from cryptography.hazmat.primitives.asymmetric import rsa + + private_key = rsa.generate_private_key( + key_size=2048, public_exponent=65537, backend=backend + ) + cert = x509.CertificateSigningRequestBuilder().subject_name( + x509.Name([]) + ).add_extension( + x509.OCSPNoCheck(), critical=False + ).sign(private_key, hashes.SHA256(), backend) + + cert.extensions + """)) + def test_ec_private_numbers_private_key(self): assert_no_memory_leaks(textwrap.dedent(""" def func(): @@ -214,3 +270,103 @@ ) ).private_key(backend) """)) + + def test_ec_derive_private_key(self): + assert_no_memory_leaks(textwrap.dedent(""" + def func(): + from cryptography.hazmat.backends.openssl import backend + from cryptography.hazmat.primitives.asymmetric import ec + ec.derive_private_key(1, ec.SECP256R1(), backend) + """)) + + def test_x25519_pubkey_from_private_key(self): + assert_no_memory_leaks(textwrap.dedent(""" + def func(): + from cryptography.hazmat.primitives.asymmetric import x25519 + private_key = x25519.X25519PrivateKey.generate() + private_key.public_key() + """)) + + def test_create_ocsp_request(self): + assert_no_memory_leaks(textwrap.dedent(""" + def func(): + from cryptography import x509 + from cryptography.hazmat.backends.openssl import backend + from cryptography.hazmat.primitives import hashes + from cryptography.x509 import ocsp + import cryptography_vectors + + path = "x509/PKITS_data/certs/ValidcRLIssuerTest28EE.crt" + with cryptography_vectors.open_vector_file(path, "rb") as f: + cert = x509.load_der_x509_certificate( + f.read(), backend + ) + builder = ocsp.OCSPRequestBuilder() + builder = builder.add_certificate( + cert, cert, hashes.SHA1() + ).add_extension(x509.OCSPNonce(b"0000"), False) + req = builder.build() + """)) + + @pytest.mark.parametrize("path", [ + "pkcs12/cert-aes256cbc-no-key.p12", + "pkcs12/cert-key-aes256cbc.p12", + ]) + def test_load_pkcs12_key_and_certificates(self, path): + assert_no_memory_leaks(textwrap.dedent(""" + def func(path): + from cryptography import x509 + from cryptography.hazmat.backends.openssl import backend + from cryptography.hazmat.primitives.serialization import pkcs12 + import cryptography_vectors + + with cryptography_vectors.open_vector_file(path, "rb") as f: + pkcs12.load_key_and_certificates( + f.read(), b"cryptography", backend + ) + """), [path]) + + def test_create_crl_with_idp(self): + assert_no_memory_leaks(textwrap.dedent(""" + def func(): + import datetime + from cryptography import x509 + from cryptography.hazmat.backends.openssl import backend + from cryptography.hazmat.primitives import hashes + from cryptography.hazmat.primitives.asymmetric import ec + from cryptography.x509.oid import NameOID + + key = ec.generate_private_key(ec.SECP256R1(), backend) + last_update = datetime.datetime(2002, 1, 1, 12, 1) + next_update = datetime.datetime(2030, 1, 1, 12, 1) + idp = x509.IssuingDistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") + ]), + only_contains_user_certs=False, + only_contains_ca_certs=True, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ) + builder = x509.CertificateRevocationListBuilder().issuer_name( + x509.Name([ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ]) + ).last_update( + last_update + ).next_update( + next_update + ).add_extension( + idp, True + ) + + crl = builder.sign(key, hashes.SHA256(), backend) + crl.extensions.get_extension_for_class( + x509.IssuingDistributionPoint + ) + """)) diff -Nru python-cryptography-2.1.4/tests/hazmat/backends/test_openssl.py python-cryptography-2.6.1/tests/hazmat/backends/test_openssl.py --- python-cryptography-2.1.4/tests/hazmat/backends/test_openssl.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/backends/test_openssl.py 2019-02-27 23:27:53.000000000 +0000 @@ -14,7 +14,7 @@ import pytest -from cryptography import utils, x509 +from cryptography import x509 from cryptography.exceptions import InternalError, _Reasons from cryptography.hazmat.backends.interfaces import DHBackend, RSABackend from cryptography.hazmat.backends.openssl.backend import ( @@ -115,7 +115,7 @@ assert len(errors) == 10 def test_ssl_ciphers_registered(self): - meth = backend._lib.TLSv1_method() + meth = backend._lib.SSLv23_method() ctx = backend._lib.SSL_CTX_new(meth) assert ctx != backend._ffi.NULL backend._lib.SSL_CTX_free(ctx) @@ -125,9 +125,9 @@ assert cipher != backend._ffi.NULL def test_error_strings_loaded(self): - # returns a value in a static buffer - err = backend._lib.ERR_error_string(101183626, backend._ffi.NULL) - assert b"data not multiple of block length" in backend._ffi.string(err) + buf = backend._ffi.new("char[]", 256) + backend._lib.ERR_error_string_n(101183626, buf, len(buf)) + assert b"data not multiple of block length" in backend._ffi.string(buf) def test_unknown_error_in_cipher_finalize(self): cipher = Cipher(AES(b"\0" * 16), CBC(b"\0" * 16), backend=backend) @@ -141,16 +141,16 @@ def test_large_key_size_on_new_openssl(self): parameters = dsa.generate_parameters(2048, backend) param_num = parameters.parameter_numbers() - assert utils.bit_length(param_num.p) == 2048 + assert param_num.p.bit_length() == 2048 parameters = dsa.generate_parameters(3072, backend) param_num = parameters.parameter_numbers() - assert utils.bit_length(param_num.p) == 3072 + assert param_num.p.bit_length() == 3072 def test_int_to_bn(self): value = (2 ** 4242) - 4242 bn = backend._int_to_bn(value) assert bn != backend._ffi.NULL - bn = backend._ffi.gc(bn, backend._lib.BN_free) + bn = backend._ffi.gc(bn, backend._lib.BN_clear_free) assert bn assert backend._bn_to_int(bn) == value @@ -170,6 +170,9 @@ assert backend._bn_to_int(bn) == 0 +@pytest.mark.skipif( + backend._lib.Cryptography_HAS_ENGINE == 0, + reason="Requires OpenSSL with ENGINE support") class TestOpenSSLRandomEngine(object): def setup(self): # The default RAND engine is global and shared between @@ -178,7 +181,7 @@ # that engine in teardown. current_default = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(current_default) - assert name == backend._binding._osrandom_engine_name + assert name == backend._lib.Cryptography_osrandom_engine_name def teardown(self): # we need to reset state to being default. backend is a shared global @@ -186,7 +189,7 @@ backend.activate_osrandom_engine() current_default = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(current_default) - assert name == backend._binding._osrandom_engine_name + assert name == backend._lib.Cryptography_osrandom_engine_name @pytest.mark.skipif(sys.executable is None, reason="No Python interpreter available.") @@ -223,7 +226,7 @@ ) osrandom_engine_name = backend._ffi.string( - backend._binding._osrandom_engine_name + backend._lib.Cryptography_osrandom_engine_name ) assert engine_name.read().encode('ascii') == osrandom_engine_name @@ -242,7 +245,7 @@ backend.activate_osrandom_engine() e = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(e) - assert name == backend._binding._osrandom_engine_name + assert name == backend._lib.Cryptography_osrandom_engine_name res = backend._lib.ENGINE_free(e) assert res == 1 @@ -250,7 +253,7 @@ e = backend._lib.ENGINE_get_default_RAND() assert e != backend._ffi.NULL name = backend._lib.ENGINE_get_name(e) - assert name == backend._binding._osrandom_engine_name + assert name == backend._lib.Cryptography_osrandom_engine_name res = backend._lib.ENGINE_free(e) assert res == 1 backend.activate_builtin_random() @@ -277,25 +280,42 @@ assert name == 'getentropy' else: assert name == '/dev/urandom' - if 'bsd' in sys.platform: - assert name in ['getentropy', '/dev/urandom'] if sys.platform == 'win32': assert name == 'CryptGenRandom' def test_activate_osrandom_already_default(self): e = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(e) - assert name == backend._binding._osrandom_engine_name + assert name == backend._lib.Cryptography_osrandom_engine_name res = backend._lib.ENGINE_free(e) assert res == 1 backend.activate_osrandom_engine() e = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(e) - assert name == backend._binding._osrandom_engine_name + assert name == backend._lib.Cryptography_osrandom_engine_name res = backend._lib.ENGINE_free(e) assert res == 1 +@pytest.mark.skipif( + backend._lib.Cryptography_HAS_ENGINE == 1, + reason="Requires OpenSSL without ENGINE support") +class TestOpenSSLNoEngine(object): + def test_no_engine_support(self): + assert backend._ffi.string( + backend._lib.Cryptography_osrandom_engine_id + ) == b"no-engine-support" + assert backend._ffi.string( + backend._lib.Cryptography_osrandom_engine_name + ) == b"osrandom_engine disabled due to no engine support" + + def test_activate_builtin_random_does_nothing(self): + backend.activate_builtin_random() + + def test_activate_osrandom_does_nothing(self): + backend.activate_osrandom_engine() + + class TestOpenSSLRSA(object): def test_generate_rsa_parameters_supported(self): assert backend.generate_rsa_parameters_supported(1, 1024) is False diff -Nru python-cryptography-2.1.4/tests/hazmat/bindings/test_openssl.py python-cryptography-2.6.1/tests/hazmat/bindings/test_openssl.py --- python-cryptography-2.1.4/tests/hazmat/bindings/test_openssl.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/bindings/test_openssl.py 2019-02-27 23:27:53.000000000 +0000 @@ -8,7 +8,7 @@ from cryptography.exceptions import InternalError from cryptography.hazmat.bindings.openssl.binding import ( - Binding, _consume_errors, _openssl_assert + Binding, _consume_errors, _openssl_assert, _verify_package_version ) @@ -21,12 +21,15 @@ def test_crypto_lock_init(self): b = Binding() - if b.lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER: - pytest.skip("Requires an older OpenSSL. Must be < 1.1.0") b.init_static_locks() lock_cb = b.lib.CRYPTO_get_locking_callback() - assert lock_cb != b.ffi.NULL + if b.lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER: + assert lock_cb == b.ffi.NULL + assert b.lib.Cryptography_HAS_LOCKING_CALLBACKS == 0 + else: + assert lock_cb != b.ffi.NULL + assert b.lib.Cryptography_HAS_LOCKING_CALLBACKS == 1 def test_add_engine_more_than_once(self): b = Binding() @@ -37,7 +40,8 @@ # Test that we're properly handling 32-bit unsigned on all platforms. b = Binding() assert b.lib.SSL_OP_ALL > 0 - ctx = b.lib.SSL_CTX_new(b.lib.TLSv1_method()) + ctx = b.lib.SSL_CTX_new(b.lib.SSLv23_method()) + assert ctx != b.ffi.NULL ctx = b.ffi.gc(ctx, b.lib.SSL_CTX_free) current_options = b.lib.SSL_CTX_get_options(ctx) resp = b.lib.SSL_CTX_set_options(ctx, b.lib.SSL_OP_ALL) @@ -49,7 +53,8 @@ # Test that we're properly handling 32-bit unsigned on all platforms. b = Binding() assert b.lib.SSL_OP_ALL > 0 - ctx = b.lib.SSL_CTX_new(b.lib.TLSv1_method()) + ctx = b.lib.SSL_CTX_new(b.lib.SSLv23_method()) + assert ctx != b.ffi.NULL ctx = b.ffi.gc(ctx, b.lib.SSL_CTX_free) ssl = b.lib.SSL_new(ctx) ssl = b.ffi.gc(ssl, b.lib.SSL_free) @@ -63,7 +68,8 @@ # Test that we're properly handling 32-bit unsigned on all platforms. b = Binding() assert b.lib.SSL_OP_ALL > 0 - ctx = b.lib.SSL_CTX_new(b.lib.TLSv1_method()) + ctx = b.lib.SSL_CTX_new(b.lib.SSLv23_method()) + assert ctx != b.ffi.NULL ctx = b.ffi.gc(ctx, b.lib.SSL_CTX_free) ssl = b.lib.SSL_new(ctx) ssl = b.ffi.gc(ssl, b.lib.SSL_free) @@ -112,3 +118,7 @@ ) b._register_osrandom_engine() assert _consume_errors(b.lib) == [] + + def test_version_mismatch(self): + with pytest.raises(ImportError): + _verify_package_version("nottherightversion") diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_3des.py python-cryptography-2.6.1/tests/hazmat/primitives/test_3des.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_3des.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_3des.py 2019-02-27 23:27:53.000000000 +0000 @@ -28,7 +28,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestTripleDESModeCBC(object): - test_KAT = generate_encrypt_test( + test_kat = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "CBC"), [ @@ -42,7 +42,7 @@ lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)), ) - test_MMT = generate_encrypt_test( + test_mmt = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "CBC"), [ @@ -65,7 +65,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestTripleDESModeOFB(object): - test_KAT = generate_encrypt_test( + test_kat = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "OFB"), [ @@ -79,7 +79,7 @@ lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)), ) - test_MMT = generate_encrypt_test( + test_mmt = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "OFB"), [ @@ -102,7 +102,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestTripleDESModeCFB(object): - test_KAT = generate_encrypt_test( + test_kat = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "CFB"), [ @@ -116,7 +116,7 @@ lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)), ) - test_MMT = generate_encrypt_test( + test_mmt = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "CFB"), [ @@ -139,7 +139,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestTripleDESModeCFB8(object): - test_KAT = generate_encrypt_test( + test_kat = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "CFB"), [ @@ -153,7 +153,7 @@ lambda iv, **kwargs: modes.CFB8(binascii.unhexlify(iv)), ) - test_MMT = generate_encrypt_test( + test_mmt = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "CFB"), [ @@ -170,13 +170,13 @@ @pytest.mark.supported( only_if=lambda backend: backend.cipher_supported( - algorithms.TripleDES("\x00" * 8), modes.ECB() + algorithms.TripleDES(b"\x00" * 8), modes.ECB() ), skip_message="Does not support TripleDES ECB", ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestTripleDESModeECB(object): - test_KAT = generate_encrypt_test( + test_kat = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "ECB"), [ @@ -190,7 +190,7 @@ lambda **kwargs: modes.ECB(), ) - test_MMT = generate_encrypt_test( + test_mmt = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "ECB"), [ diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_aead.py python-cryptography-2.6.1/tests/hazmat/primitives/test_aead.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_aead.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_aead.py 2019-02-27 23:27:53.000000000 +0000 @@ -22,6 +22,11 @@ ) +class FakeData(object): + def __len__(self): + return 2 ** 32 + 1 + + def _aead_supported(cls): try: cls(b"0" * 32) @@ -46,6 +51,17 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestChaCha20Poly1305(object): + def test_data_too_large(self): + key = ChaCha20Poly1305.generate_key() + chacha = ChaCha20Poly1305(key) + nonce = b"0" * 12 + + with pytest.raises(OverflowError): + chacha.encrypt(nonce, FakeData(), b"") + + with pytest.raises(OverflowError): + chacha.encrypt(nonce, b"", FakeData()) + def test_generate_key(self): key = ChaCha20Poly1305.generate_key() assert len(key) == 32 @@ -151,6 +167,21 @@ computed_ct = chacha.encrypt(nonce, pt, aad) assert computed_ct == ct + tag + def test_buffer_protocol(self, backend): + key = ChaCha20Poly1305.generate_key() + chacha = ChaCha20Poly1305(key) + pt = b"encrypt me" + ad = b"additional" + nonce = os.urandom(12) + ct = chacha.encrypt(nonce, pt, ad) + computed_pt = chacha.decrypt(nonce, ct, ad) + assert computed_pt == pt + chacha2 = ChaCha20Poly1305(bytearray(key)) + ct2 = chacha2.encrypt(bytearray(nonce), pt, ad) + assert ct2 == ct + computed_pt2 = chacha2.decrypt(bytearray(nonce), ct2, ad) + assert computed_pt2 == pt + @pytest.mark.skipif( _aead_supported(AESCCM), @@ -168,6 +199,17 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESCCM(object): + def test_data_too_large(self): + key = AESCCM.generate_key(128) + aesccm = AESCCM(key) + nonce = b"0" * 12 + + with pytest.raises(OverflowError): + aesccm.encrypt(nonce, FakeData(), b"") + + with pytest.raises(OverflowError): + aesccm.encrypt(nonce, b"", FakeData()) + def test_default_tag_length(self, backend): key = AESCCM.generate_key(128) aesccm = AESCCM(key) @@ -290,6 +332,21 @@ with pytest.raises(InvalidTag): aesccm.decrypt(b"0" * 12, b"0", None) + def test_buffer_protocol(self, backend): + key = AESCCM.generate_key(128) + aesccm = AESCCM(key) + pt = b"encrypt me" + ad = b"additional" + nonce = os.urandom(12) + ct = aesccm.encrypt(nonce, pt, ad) + computed_pt = aesccm.decrypt(nonce, ct, ad) + assert computed_pt == pt + aesccm2 = AESCCM(bytearray(key)) + ct2 = aesccm2.encrypt(bytearray(nonce), pt, ad) + assert ct2 == ct + computed_pt2 = aesccm2.decrypt(bytearray(nonce), ct2, ad) + assert computed_pt2 == pt + def _load_gcm_vectors(): vectors = _load_all_params( @@ -309,6 +366,17 @@ @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESGCM(object): + def test_data_too_large(self): + key = AESGCM.generate_key(128) + aesgcm = AESGCM(key) + nonce = b"0" * 12 + + with pytest.raises(OverflowError): + aesgcm.encrypt(nonce, FakeData(), b"") + + with pytest.raises(OverflowError): + aesgcm.encrypt(nonce, b"", FakeData()) + @pytest.mark.parametrize("vector", _load_gcm_vectors()) def test_vectors(self, vector): key = binascii.unhexlify(vector["key"]) @@ -345,6 +413,12 @@ with pytest.raises(TypeError): aesgcm.decrypt(nonce, data, associated_data) + def test_invalid_nonce_length(self, backend): + key = AESGCM.generate_key(128) + aesgcm = AESGCM(key) + with pytest.raises(ValueError): + aesgcm.encrypt(b"", b"hi", None) + def test_bad_key(self, backend): with pytest.raises(TypeError): AESGCM(object()) @@ -369,3 +443,18 @@ pt1 = aesgcm.decrypt(nonce, ct1, None) pt2 = aesgcm.decrypt(nonce, ct2, b"") assert pt1 == pt2 + + def test_buffer_protocol(self, backend): + key = AESGCM.generate_key(128) + aesgcm = AESGCM(key) + pt = b"encrypt me" + ad = b"additional" + nonce = os.urandom(12) + ct = aesgcm.encrypt(nonce, pt, ad) + computed_pt = aesgcm.decrypt(nonce, ct, ad) + assert computed_pt == pt + aesgcm2 = AESGCM(bytearray(key)) + ct2 = aesgcm2.encrypt(bytearray(nonce), pt, ad) + assert ct2 == ct + computed_pt2 = aesgcm2.decrypt(bytearray(nonce), ct2, ad) + assert computed_pt2 == pt diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_aes.py python-cryptography-2.6.1/tests/hazmat/primitives/test_aes.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_aes.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_aes.py 2019-02-27 23:27:53.000000000 +0000 @@ -58,7 +58,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeCBC(object): - test_CBC = generate_encrypt_test( + test_cbc = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "AES", "CBC"), [ @@ -85,13 +85,13 @@ @pytest.mark.supported( only_if=lambda backend: backend.cipher_supported( - algorithms.AES("\x00" * 16), modes.ECB() + algorithms.AES(b"\x00" * 16), modes.ECB() ), skip_message="Does not support AES ECB", ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeECB(object): - test_ECB = generate_encrypt_test( + test_ecb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "AES", "ECB"), [ @@ -124,7 +124,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeOFB(object): - test_OFB = generate_encrypt_test( + test_ofb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "AES", "OFB"), [ @@ -157,7 +157,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeCFB(object): - test_CFB = generate_encrypt_test( + test_cfb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "AES", "CFB"), [ @@ -190,7 +190,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeCFB8(object): - test_CFB8 = generate_encrypt_test( + test_cfb8 = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "AES", "CFB"), [ @@ -223,7 +223,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeCTR(object): - test_CTR = generate_encrypt_test( + test_ctr = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "AES", "CTR"), ["aes-128-ctr.txt", "aes-192-ctr.txt", "aes-256-ctr.txt"], @@ -240,7 +240,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeGCM(object): - test_GCM = generate_aead_test( + test_gcm = generate_aead_test( load_nist_vectors, os.path.join("ciphers", "AES", "GCM"), [ @@ -439,3 +439,61 @@ decryptor.finalize() else: decryptor.finalize_with_tag(tag) + + @pytest.mark.supported( + only_if=lambda backend: ( + not backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 or + backend._lib.CRYPTOGRAPHY_IS_LIBRESSL + ), + skip_message="Not supported on OpenSSL 1.0.1", + ) + def test_gcm_tag_decrypt_finalize_tag_length(self, backend): + decryptor = base.Cipher( + algorithms.AES(b"0" * 16), + modes.GCM(b"0" * 12), + backend=backend + ).decryptor() + with pytest.raises(ValueError): + decryptor.finalize_with_tag(b"tagtooshort") + + def test_buffer_protocol(self, backend): + data = bytearray(b"helloworld") + enc = base.Cipher( + algorithms.AES(bytearray(b"\x00" * 16)), + modes.GCM(bytearray(b"\x00" * 12)), + backend + ).encryptor() + enc.authenticate_additional_data(bytearray(b"foo")) + ct = enc.update(data) + enc.finalize() + dec = base.Cipher( + algorithms.AES(bytearray(b"\x00" * 16)), + modes.GCM(bytearray(b"\x00" * 12), enc.tag), + backend + ).decryptor() + dec.authenticate_additional_data(bytearray(b"foo")) + pt = dec.update(ct) + dec.finalize() + assert pt == data + + +@pytest.mark.parametrize( + "mode", + [ + modes.CBC(bytearray(b"\x00" * 16)), + modes.CTR(bytearray(b"\x00" * 16)), + modes.OFB(bytearray(b"\x00" * 16)), + modes.CFB(bytearray(b"\x00" * 16)), + modes.CFB8(bytearray(b"\x00" * 16)), + modes.XTS(bytearray(b"\x00" * 16)), + ] +) +@pytest.mark.requires_backend_interface(interface=CipherBackend) +def test_buffer_protocol_alternate_modes(mode, backend): + data = bytearray(b"sixteen_byte_msg") + cipher = base.Cipher( + algorithms.AES(bytearray(b"\x00" * 32)), mode, backend + ) + enc = cipher.encryptor() + ct = enc.update(data) + enc.finalize() + dec = cipher.decryptor() + pt = dec.update(ct) + dec.finalize() + assert pt == data diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_asym_utils.py python-cryptography-2.6.1/tests/hazmat/primitives/test_asym_utils.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_asym_utils.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_asym_utils.py 2019-02-27 23:27:53.000000000 +0000 @@ -7,18 +7,10 @@ import pytest from cryptography.hazmat.primitives.asymmetric.utils import ( - Prehashed, decode_dss_signature, decode_rfc6979_signature, - encode_dss_signature, encode_rfc6979_signature, + Prehashed, decode_dss_signature, encode_dss_signature ) -def test_deprecated_rfc6979_signature(): - sig = pytest.deprecated_call(encode_rfc6979_signature, 1, 1) - assert sig == b"0\x06\x02\x01\x01\x02\x01\x01" - decoded = pytest.deprecated_call(decode_rfc6979_signature, sig) - assert decoded == (1, 1) - - def test_dss_signature(): sig = encode_dss_signature(1, 1) assert sig == b"0\x06\x02\x01\x01\x02\x01\x01" diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_block.py python-cryptography-2.6.1/tests/hazmat/primitives/test_block.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_block.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_block.py 2019-02-27 23:27:53.000000000 +0000 @@ -191,6 +191,10 @@ backend, ) + def test_gcm(self): + with pytest.raises(ValueError): + modes.GCM(b"") + class TestModesRequireBytes(object): def test_cbc(self): diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_blowfish.py python-cryptography-2.6.1/tests/hazmat/primitives/test_blowfish.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_blowfish.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_blowfish.py 2019-02-27 23:27:53.000000000 +0000 @@ -24,7 +24,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestBlowfishModeECB(object): - test_ECB = generate_encrypt_test( + test_ecb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "Blowfish"), ["bf-ecb.txt"], @@ -41,7 +41,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestBlowfishModeCBC(object): - test_CBC = generate_encrypt_test( + test_cbc = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "Blowfish"), ["bf-cbc.txt"], @@ -58,7 +58,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestBlowfishModeOFB(object): - test_OFB = generate_encrypt_test( + test_ofb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "Blowfish"), ["bf-ofb.txt"], @@ -75,7 +75,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestBlowfishModeCFB(object): - test_CFB = generate_encrypt_test( + test_cfb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "Blowfish"), ["bf-cfb.txt"], diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_camellia.py python-cryptography-2.6.1/tests/hazmat/primitives/test_camellia.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_camellia.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_camellia.py 2019-02-27 23:27:53.000000000 +0000 @@ -26,7 +26,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCamelliaModeECB(object): - test_ECB = generate_encrypt_test( + test_ecb = generate_encrypt_test( load_cryptrec_vectors, os.path.join("ciphers", "Camellia"), [ @@ -47,7 +47,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCamelliaModeCBC(object): - test_CBC = generate_encrypt_test( + test_cbc = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "Camellia"), ["camellia-cbc.txt"], @@ -64,7 +64,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCamelliaModeOFB(object): - test_OFB = generate_encrypt_test( + test_ofb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "Camellia"), ["camellia-ofb.txt"], @@ -81,7 +81,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCamelliaModeCFB(object): - test_CFB = generate_encrypt_test( + test_cfb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "Camellia"), ["camellia-cfb.txt"], diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_cast5.py python-cryptography-2.6.1/tests/hazmat/primitives/test_cast5.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_cast5.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_cast5.py 2019-02-27 23:27:53.000000000 +0000 @@ -24,7 +24,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCAST5ModeECB(object): - test_ECB = generate_encrypt_test( + test_ecb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "CAST5"), ["cast5-ecb.txt"], @@ -41,7 +41,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCAST5ModeCBC(object): - test_CBC = generate_encrypt_test( + test_cbc = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "CAST5"), ["cast5-cbc.txt"], @@ -58,7 +58,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCAST5ModeOFB(object): - test_OFB = generate_encrypt_test( + test_ofb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "CAST5"), ["cast5-ofb.txt"], @@ -75,7 +75,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCAST5ModeCFB(object): - test_CFB = generate_encrypt_test( + test_cfb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "CAST5"), ["cast5-cfb.txt"], diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_chacha20.py python-cryptography-2.6.1/tests/hazmat/primitives/test_chacha20.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_chacha20.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_chacha20.py 2019-02-27 23:27:53.000000000 +0000 @@ -44,6 +44,18 @@ computed_ct = encryptor.update(pt) + encryptor.finalize() assert binascii.hexlify(computed_ct) == vector["ciphertext"] + def test_buffer_protocol(self, backend): + key = bytearray(os.urandom(32)) + nonce = bytearray(os.urandom(16)) + cipher = Cipher( + algorithms.ChaCha20(key, nonce), None, backend + ) + enc = cipher.encryptor() + ct = enc.update(bytearray(b"hello")) + enc.finalize() + dec = cipher.decryptor() + pt = dec.update(ct) + dec.finalize() + assert pt == b"hello" + def test_key_size(self): chacha = algorithms.ChaCha20(b"0" * 32, b"0" * 16) assert chacha.key_size == 256 @@ -58,3 +70,7 @@ with pytest.raises(TypeError): algorithms.ChaCha20(b"0" * 32, object()) + + def test_invalid_key_type(self): + with pytest.raises(TypeError, match="key must be bytes"): + algorithms.ChaCha20(u"0" * 32, b"0" * 16) diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_ciphers.py python-cryptography-2.6.1/tests/hazmat/primitives/test_ciphers.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_ciphers.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_ciphers.py 2019-02-27 23:27:53.000000000 +0000 @@ -36,6 +36,10 @@ with pytest.raises(ValueError): AES(binascii.unhexlify(b"0" * 12)) + def test_invalid_key_type(self): + with pytest.raises(TypeError, match="key must be bytes"): + AES(u"0" * 32) + class TestAESXTS(object): @pytest.mark.requires_backend_interface(interface=CipherBackend) @@ -75,6 +79,10 @@ with pytest.raises(ValueError): Camellia(binascii.unhexlify(b"0" * 12)) + def test_invalid_key_type(self): + with pytest.raises(TypeError, match="key must be bytes"): + Camellia(u"0" * 32) + class TestTripleDES(object): @pytest.mark.parametrize("key", [ @@ -90,6 +98,10 @@ with pytest.raises(ValueError): TripleDES(binascii.unhexlify(b"0" * 12)) + def test_invalid_key_type(self): + with pytest.raises(TypeError, match="key must be bytes"): + TripleDES(u"0" * 16) + class TestBlowfish(object): @pytest.mark.parametrize(("key", "keysize"), [ @@ -103,6 +115,10 @@ with pytest.raises(ValueError): Blowfish(binascii.unhexlify(b"0" * 6)) + def test_invalid_key_type(self): + with pytest.raises(TypeError, match="key must be bytes"): + Blowfish(u"0" * 8) + class TestCAST5(object): @pytest.mark.parametrize(("key", "keysize"), [ @@ -116,6 +132,10 @@ with pytest.raises(ValueError): CAST5(binascii.unhexlify(b"0" * 34)) + def test_invalid_key_type(self): + with pytest.raises(TypeError, match="key must be bytes"): + CAST5(u"0" * 10) + class TestARC4(object): @pytest.mark.parametrize(("key", "keysize"), [ @@ -135,6 +155,10 @@ with pytest.raises(ValueError): ARC4(binascii.unhexlify(b"0" * 34)) + def test_invalid_key_type(self): + with pytest.raises(TypeError, match="key must be bytes"): + ARC4(u"0" * 10) + class TestIDEA(object): def test_key_size(self): @@ -145,6 +169,10 @@ with pytest.raises(ValueError): IDEA(b"\x00" * 17) + def test_invalid_key_type(self): + with pytest.raises(TypeError, match="key must be bytes"): + IDEA(u"0" * 16) + class TestSEED(object): def test_key_size(self): @@ -155,6 +183,10 @@ with pytest.raises(ValueError): SEED(b"\x00" * 17) + def test_invalid_key_type(self): + with pytest.raises(TypeError, match="key must be bytes"): + SEED(u"0" * 16) + def test_invalid_backend(): pretend_backend = object() diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_cmac.py python-cryptography-2.6.1/tests/hazmat/primitives/test_cmac.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_cmac.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_cmac.py 2019-02-27 23:27:53.000000000 +0000 @@ -183,6 +183,19 @@ copy_cmac = cmac.copy() assert cmac.finalize() == copy_cmac.finalize() + @pytest.mark.supported( + only_if=lambda backend: backend.cmac_algorithm_supported( + AES(fake_key)), + skip_message="Does not support CMAC." + ) + def test_buffer_protocol(self, backend): + key = bytearray(b"2b7e151628aed2a6abf7158809cf4f3c") + cmac = CMAC(AES(key), backend) + cmac.update(b"6bc1bee22e409f96e93d7e117393172a") + assert cmac.finalize() == binascii.unhexlify( + b"a21e6e647bfeaf5ca0a5e1bcd957dfad" + ) + def test_invalid_backend(): key = b"2b7e151628aed2a6abf7158809cf4f3c" diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_concatkdf.py python-cryptography-2.6.1/tests/hazmat/primitives/test_concatkdf.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_concatkdf.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_concatkdf.py 2019-02-27 23:27:53.000000000 +0000 @@ -52,6 +52,22 @@ assert ckdf.derive(prk) == okm + def test_buffer_protocol(self, backend): + prk = binascii.unhexlify( + b"52169af5c485dcc2321eb8d26d5efa21fb9b93c98e38412ee2484cf14f0d0d23" + ) + + okm = binascii.unhexlify(b"1c3bc9e7c4547c5191c0d478cccaed55") + + oinfo = binascii.unhexlify( + b"a1b2c3d4e53728157e634612c12d6d5223e204aeea4341565369647bd184bcd2" + b"46f72971f292badaa2fe4124612cba" + ) + + ckdf = ConcatKDFHash(hashes.SHA256(), 16, oinfo, backend) + + assert ckdf.derive(bytearray(prk)) == okm + def test_verify(self, backend): prk = binascii.unhexlify( b"52169af5c485dcc2321eb8d26d5efa21fb9b93c98e38412ee2484cf14f0d0d23" @@ -158,6 +174,25 @@ assert ckdf.derive(prk) == okm + def test_buffer_protocol(self, backend): + prk = binascii.unhexlify( + b"013951627c1dea63ea2d7702dd24e963eef5faac6b4af7e4" + b"b831cde499dff1ce45f6179f741c728aa733583b02409208" + b"8f0af7fce1d045edbc5790931e8d5ca79c73" + ) + + okm = binascii.unhexlify(b"64ce901db10d558661f10b6836a122a7" + b"605323ce2f39bf27eaaac8b34cf89f2f") + + oinfo = binascii.unhexlify( + b"a1b2c3d4e55e600be5f367e0e8a465f4bf2704db00c9325c" + b"9fbd216d12b49160b2ae5157650f43415653696421e68e" + ) + + ckdf = ConcatKDFHMAC(hashes.SHA512(), 32, None, oinfo, backend) + + assert ckdf.derive(bytearray(prk)) == okm + def test_derive_explicit_salt(self, backend): prk = binascii.unhexlify( b"013951627c1dea63ea2d7702dd24e963eef5faac6b4af7e4" diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_dh.py python-cryptography-2.6.1/tests/hazmat/primitives/test_dh.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_dh.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_dh.py 2019-02-27 23:27:53.000000000 +0000 @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function import binascii +import itertools import os import pytest @@ -13,7 +14,7 @@ DERSerializationBackend, DHBackend, PEMSerializationBackend) from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import dh -from cryptography.utils import bit_length, int_from_bytes +from cryptography.utils import int_from_bytes from ...doubles import DummyKeySerializationEncryption from ...utils import load_nist_vectors, load_vectors_from_file @@ -262,7 +263,7 @@ assert isinstance(parameters, dh.DHParametersWithSerialization) parameter_numbers = parameters.parameter_numbers() assert isinstance(parameter_numbers, dh.DHParameterNumbers) - assert bit_length(parameter_numbers.p) == key_size + assert parameter_numbers.p.bit_length() == key_size assert isinstance(public, dh.DHPublicKeyWithSerialization) assert isinstance(public.public_numbers(), dh.DHPublicNumbers) @@ -425,6 +426,21 @@ assert loaded_priv_num == priv_num @pytest.mark.parametrize( + ("encoding", "fmt"), + [ + (serialization.Encoding.Raw, serialization.PrivateFormat.PKCS8), + (serialization.Encoding.DER, serialization.PrivateFormat.Raw), + (serialization.Encoding.Raw, serialization.PrivateFormat.Raw), + (serialization.Encoding.X962, serialization.PrivateFormat.PKCS8), + ] + ) + def test_private_bytes_rejects_invalid(self, encoding, fmt, backend): + parameters = dh.generate_parameters(2, 512, backend) + key = parameters.generate_private_key() + with pytest.raises(ValueError): + key.private_bytes(encoding, fmt, serialization.NoEncryption()) + + @pytest.mark.parametrize( ("key_path", "loader_func", "encoding", "is_dhx"), [ ( @@ -806,6 +822,34 @@ else: assert parameter_numbers.q is None + @pytest.mark.parametrize( + ("encoding", "fmt"), + [ + ( + serialization.Encoding.Raw, + serialization.PublicFormat.SubjectPublicKeyInfo + ), + (serialization.Encoding.Raw, serialization.PublicFormat.PKCS1), + ] + list(itertools.product( + [ + serialization.Encoding.Raw, + serialization.Encoding.X962, + serialization.Encoding.PEM, + serialization.Encoding.DER + ], + [ + serialization.PublicFormat.Raw, + serialization.PublicFormat.UncompressedPoint, + serialization.PublicFormat.CompressedPoint + ] + )) + ) + def test_public_bytes_rejects_invalid(self, encoding, fmt, backend): + parameters = dh.generate_parameters(2, 512, backend) + key = parameters.generate_private_key().public_key() + with pytest.raises(ValueError): + key.public_bytes(encoding, fmt) + def test_parameter_bytes_invalid_encoding(self, backend): parameters = dh.generate_parameters(2, 512, backend) with pytest.raises(TypeError): diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_dsa.py python-cryptography-2.6.1/tests/hazmat/primitives/test_dsa.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_dsa.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_dsa.py 2019-02-27 23:27:53.000000000 +0000 @@ -18,7 +18,7 @@ from cryptography.hazmat.primitives.asymmetric.utils import ( Prehashed, encode_dss_signature ) -from cryptography.utils import bit_length +from cryptography.utils import CryptographyDeprecationWarning from .fixtures_dsa import ( DSA_KEY_1024, DSA_KEY_2048, DSA_KEY_3072 @@ -36,7 +36,7 @@ not backend.dsa_hash_supported(algorithm) ): pytest.skip( - "{0} does not support the provided parameters".format(backend) + "{} does not support the provided parameters".format(backend) ) @@ -82,7 +82,7 @@ assert skey_parameters.p == vector['p'] assert skey_parameters.q == vector['q'] assert skey_parameters.g == vector['g'] - assert skey.key_size == bit_length(vector['p']) + assert skey.key_size == vector['p'].bit_length() assert pkey.key_size == skey.key_size public_numbers = pkey.public_numbers() assert numbers.public_numbers.y == public_numbers.y @@ -99,446 +99,254 @@ skey_parameters.g, numbers.x, skey_parameters.p ) - def test_invalid_parameters_values(self, backend): - # Test a p < 1024 bits in length - with pytest.raises(ValueError): - dsa.DSAParameterNumbers( - p=2 ** 1000, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=DSA_KEY_1024.public_numbers.parameter_numbers.g, - ).parameters(backend) - - # Test a p < 2048 bits in length - with pytest.raises(ValueError): - dsa.DSAParameterNumbers( - p=2 ** 2000, - q=DSA_KEY_2048.public_numbers.parameter_numbers.q, - g=DSA_KEY_2048.public_numbers.parameter_numbers.g, - ).parameters(backend) - - # Test a p < 3072 bits in length - with pytest.raises(ValueError): - dsa.DSAParameterNumbers( - p=2 ** 3000, - q=DSA_KEY_3072.public_numbers.parameter_numbers.q, - g=DSA_KEY_3072.public_numbers.parameter_numbers.g, - ).parameters(backend) - - # Test a p > 3072 bits in length - with pytest.raises(ValueError): - dsa.DSAParameterNumbers( - p=2 ** 3100, - q=DSA_KEY_3072.public_numbers.parameter_numbers.q, - g=DSA_KEY_3072.public_numbers.parameter_numbers.g, - ).parameters(backend) - - # Test a q < 160 bits in length - with pytest.raises(ValueError): - dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=2 ** 150, - g=DSA_KEY_1024.public_numbers.parameter_numbers.g, - ).parameters(backend) - - # Test a q < 256 bits in length - with pytest.raises(ValueError): - dsa.DSAParameterNumbers( - p=DSA_KEY_2048.public_numbers.parameter_numbers.p, - q=2 ** 250, - g=DSA_KEY_2048.public_numbers.parameter_numbers.g - ).parameters(backend) - - # Test a q > 256 bits in length - with pytest.raises(ValueError): - dsa.DSAParameterNumbers( - p=DSA_KEY_3072.public_numbers.parameter_numbers.p, - q=2 ** 260, - g=DSA_KEY_3072.public_numbers.parameter_numbers.g, - ).parameters(backend) - - # Test a g < 1 - with pytest.raises(ValueError): - dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=0 - ).parameters(backend) - - # Test a g = 1 - with pytest.raises(ValueError): - dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=1 - ).parameters(backend) - - # Test a g > p - with pytest.raises(ValueError): - dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=2 ** 1200 - ).parameters(backend) - - def test_invalid_dsa_private_key_arguments(self, backend): - # Test a p < 1024 bits in length - with pytest.raises(ValueError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=2 ** 1000, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=DSA_KEY_1024.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_1024.public_numbers.y - ), - x=DSA_KEY_1024.x - ).private_key(backend) - - # Test a p < 2048 bits in length - with pytest.raises(ValueError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=2 ** 2000, - q=DSA_KEY_2048.public_numbers.parameter_numbers.q, - g=DSA_KEY_2048.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_2048.public_numbers.y - ), - x=DSA_KEY_2048.x, - ).private_key(backend) - - # Test a p < 3072 bits in length - with pytest.raises(ValueError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=2 ** 3000, - q=DSA_KEY_3072.public_numbers.parameter_numbers.q, - g=DSA_KEY_3072.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_3072.public_numbers.y - ), - x=DSA_KEY_3072.x, - ).private_key(backend) - - # Test a p > 3072 bits in length - with pytest.raises(ValueError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=2 ** 3100, - q=DSA_KEY_3072.public_numbers.parameter_numbers.q, - g=DSA_KEY_3072.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_3072.public_numbers.y - ), - x=DSA_KEY_3072.x, - ).private_key(backend) - - # Test a q < 160 bits in length - with pytest.raises(ValueError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=2 ** 150, - g=DSA_KEY_1024.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_1024.public_numbers.y - ), - x=DSA_KEY_1024.x, - ).private_key(backend) - - # Test a q < 256 bits in length - with pytest.raises(ValueError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_2048.public_numbers.parameter_numbers.p, - q=2 ** 250, - g=DSA_KEY_2048.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_2048.public_numbers.y - ), - x=DSA_KEY_2048.x, - ).private_key(backend) - - # Test a q > 256 bits in length - with pytest.raises(ValueError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_3072.public_numbers.parameter_numbers.p, - q=2 ** 260, - g=DSA_KEY_3072.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_3072.public_numbers.y - ), - x=DSA_KEY_3072.x, - ).private_key(backend) - - # Test a g < 1 - with pytest.raises(ValueError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=0, - ), - y=DSA_KEY_1024.public_numbers.y - ), - x=DSA_KEY_1024.x, - ).private_key(backend) - - # Test a g = 1 - with pytest.raises(ValueError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=1, - ), - y=DSA_KEY_1024.public_numbers.y - ), - x=DSA_KEY_1024.x, - ).private_key(backend) - - # Test a g > p - with pytest.raises(ValueError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=2 ** 1200, - ), - y=DSA_KEY_1024.public_numbers.y - ), - x=DSA_KEY_1024.x, - ).private_key(backend) - - # Test x = 0 - with pytest.raises(ValueError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=DSA_KEY_1024.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_1024.public_numbers.y - ), - x=0, - ).private_key(backend) - - # Test x < 0 - with pytest.raises(ValueError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=DSA_KEY_1024.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_1024.public_numbers.y - ), - x=-2, - ).private_key(backend) - - # Test x = q - with pytest.raises(ValueError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=DSA_KEY_1024.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_1024.public_numbers.y - ), - x=2 ** 159, - ).private_key(backend) - - # Test x > q + @pytest.mark.parametrize( + ("p", "q", "g"), + [ + ( + 2 ** 1000, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + DSA_KEY_1024.public_numbers.parameter_numbers.g, + ), + ( + 2 ** 2000, + DSA_KEY_2048.public_numbers.parameter_numbers.q, + DSA_KEY_2048.public_numbers.parameter_numbers.g, + ), + ( + 2 ** 3000, + DSA_KEY_3072.public_numbers.parameter_numbers.q, + DSA_KEY_3072.public_numbers.parameter_numbers.g, + ), + ( + 2 ** 3100, + DSA_KEY_3072.public_numbers.parameter_numbers.q, + DSA_KEY_3072.public_numbers.parameter_numbers.g, + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + 2 ** 150, + DSA_KEY_1024.public_numbers.parameter_numbers.g, + ), + ( + DSA_KEY_2048.public_numbers.parameter_numbers.p, + 2 ** 250, + DSA_KEY_2048.public_numbers.parameter_numbers.g + ), + ( + DSA_KEY_3072.public_numbers.parameter_numbers.p, + 2 ** 260, + DSA_KEY_3072.public_numbers.parameter_numbers.g, + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + 0 + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + 1 + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + 2 ** 1200 + ), + ] + ) + def test_invalid_parameters_values(self, p, q, g, backend): with pytest.raises(ValueError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=DSA_KEY_1024.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_1024.public_numbers.y - ), - x=2 ** 200, - ).private_key(backend) + dsa.DSAParameterNumbers(p, q, g).parameters(backend) - # Test y != (g ** x) % p + @pytest.mark.parametrize( + ("p", "q", "g", "y", "x"), + [ + ( + 2 ** 1000, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + DSA_KEY_1024.public_numbers.parameter_numbers.g, + DSA_KEY_1024.public_numbers.y, + DSA_KEY_1024.x, + ), + ( + 2 ** 2000, + DSA_KEY_2048.public_numbers.parameter_numbers.q, + DSA_KEY_2048.public_numbers.parameter_numbers.g, + DSA_KEY_2048.public_numbers.y, + DSA_KEY_2048.x, + ), + ( + 2 ** 3000, + DSA_KEY_3072.public_numbers.parameter_numbers.q, + DSA_KEY_3072.public_numbers.parameter_numbers.g, + DSA_KEY_3072.public_numbers.y, + DSA_KEY_3072.x, + ), + ( + 2 ** 3100, + DSA_KEY_3072.public_numbers.parameter_numbers.q, + DSA_KEY_3072.public_numbers.parameter_numbers.g, + DSA_KEY_3072.public_numbers.y, + DSA_KEY_3072.x, + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + 2 ** 150, + DSA_KEY_1024.public_numbers.parameter_numbers.g, + DSA_KEY_1024.public_numbers.y, + DSA_KEY_1024.x, + ), + ( + DSA_KEY_2048.public_numbers.parameter_numbers.p, + 2 ** 250, + DSA_KEY_2048.public_numbers.parameter_numbers.g, + DSA_KEY_2048.public_numbers.y, + DSA_KEY_2048.x, + ), + ( + DSA_KEY_3072.public_numbers.parameter_numbers.p, + 2 ** 260, + DSA_KEY_3072.public_numbers.parameter_numbers.g, + DSA_KEY_3072.public_numbers.y, + DSA_KEY_3072.x, + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + 0, + DSA_KEY_1024.public_numbers.y, + DSA_KEY_1024.x, + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + 1, + DSA_KEY_1024.public_numbers.y, + DSA_KEY_1024.x, + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + 2 ** 1200, + DSA_KEY_1024.public_numbers.y, + DSA_KEY_1024.x, + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + DSA_KEY_1024.public_numbers.parameter_numbers.g, + DSA_KEY_1024.public_numbers.y, + 0, + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + DSA_KEY_1024.public_numbers.parameter_numbers.g, + DSA_KEY_1024.public_numbers.y, + -2, + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + DSA_KEY_1024.public_numbers.parameter_numbers.g, + DSA_KEY_1024.public_numbers.y, + 2 ** 159, + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + DSA_KEY_1024.public_numbers.parameter_numbers.g, + DSA_KEY_1024.public_numbers.y, + 2 ** 200, + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + DSA_KEY_1024.public_numbers.parameter_numbers.g, + 2 ** 100, + DSA_KEY_1024.x + ), + ] + ) + def test_invalid_dsa_private_key_arguments(self, p, q, g, y, x, backend): with pytest.raises(ValueError): dsa.DSAPrivateNumbers( public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=DSA_KEY_1024.public_numbers.parameter_numbers.g, - ), - y=2 ** 100 - ), - x=DSA_KEY_1024.x, - ).private_key(backend) - - # Test a non-integer y value - with pytest.raises(TypeError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=DSA_KEY_1024.public_numbers.parameter_numbers.g, - ), - y=None - ), - x=DSA_KEY_1024.x, - ).private_key(backend) - - # Test a non-integer x value - with pytest.raises(TypeError): - dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=DSA_KEY_1024.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_1024.public_numbers.y - ), - x=None, + parameter_numbers=dsa.DSAParameterNumbers(p=p, q=q, g=g), + y=y + ), x=x ).private_key(backend) - def test_invalid_dsa_public_key_arguments(self, backend): - # Test a p < 1024 bits in length - with pytest.raises(ValueError): - dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=2 ** 1000, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=DSA_KEY_1024.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_1024.public_numbers.y - ).public_key(backend) - - # Test a p < 2048 bits in length - with pytest.raises(ValueError): - dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=2 ** 2000, - q=DSA_KEY_2048.public_numbers.parameter_numbers.q, - g=DSA_KEY_2048.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_2048.public_numbers.y - ).public_key(backend) - - # Test a p < 3072 bits in length - with pytest.raises(ValueError): - dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=2 ** 3000, - q=DSA_KEY_3072.public_numbers.parameter_numbers.q, - g=DSA_KEY_3072.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_3072.public_numbers.y - ).public_key(backend) - - # Test a p > 3072 bits in length - with pytest.raises(ValueError): - dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=2 ** 3100, - q=DSA_KEY_3072.public_numbers.parameter_numbers.q, - g=DSA_KEY_3072.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_3072.public_numbers.y - ).public_key(backend) - - # Test a q < 160 bits in length - with pytest.raises(ValueError): - dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=2 ** 150, - g=DSA_KEY_1024.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_1024.public_numbers.y - ).public_key(backend) - - # Test a q < 256 bits in length - with pytest.raises(ValueError): - dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_2048.public_numbers.parameter_numbers.p, - q=2 ** 250, - g=DSA_KEY_2048.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_2048.public_numbers.y - ).public_key(backend) - - # Test a q > 256 bits in length - with pytest.raises(ValueError): - dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_3072.public_numbers.parameter_numbers.p, - q=2 ** 260, - g=DSA_KEY_3072.public_numbers.parameter_numbers.g, - ), - y=DSA_KEY_3072.public_numbers.y - ).public_key(backend) - - # Test a g < 1 - with pytest.raises(ValueError): - dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=0, - ), - y=DSA_KEY_1024.public_numbers.y - ).public_key(backend) - - # Test a g = 1 - with pytest.raises(ValueError): - dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=1, - ), - y=DSA_KEY_1024.public_numbers.y - ).public_key(backend) - - # Test a g > p + @pytest.mark.parametrize( + ("p", "q", "g", "y"), + [ + ( + 2 ** 1000, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + DSA_KEY_1024.public_numbers.parameter_numbers.g, + DSA_KEY_1024.public_numbers.y, + ), + ( + 2 ** 2000, + DSA_KEY_2048.public_numbers.parameter_numbers.q, + DSA_KEY_2048.public_numbers.parameter_numbers.g, + DSA_KEY_2048.public_numbers.y, + ), + ( + 2 ** 3000, + DSA_KEY_3072.public_numbers.parameter_numbers.q, + DSA_KEY_3072.public_numbers.parameter_numbers.g, + DSA_KEY_3072.public_numbers.y, + ), + ( + 2 ** 3100, + DSA_KEY_3072.public_numbers.parameter_numbers.q, + DSA_KEY_3072.public_numbers.parameter_numbers.g, + DSA_KEY_3072.public_numbers.y, + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + 2 ** 150, + DSA_KEY_1024.public_numbers.parameter_numbers.g, + DSA_KEY_1024.public_numbers.y, + ), + ( + DSA_KEY_2048.public_numbers.parameter_numbers.p, + 2 ** 250, + DSA_KEY_2048.public_numbers.parameter_numbers.g, + DSA_KEY_2048.public_numbers.y, + ), + ( + DSA_KEY_3072.public_numbers.parameter_numbers.p, + 2 ** 260, + DSA_KEY_3072.public_numbers.parameter_numbers.g, + DSA_KEY_3072.public_numbers.y, + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + 0, + DSA_KEY_1024.public_numbers.y, + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + 1, + DSA_KEY_1024.public_numbers.y, + ), + ( + DSA_KEY_1024.public_numbers.parameter_numbers.p, + DSA_KEY_1024.public_numbers.parameter_numbers.q, + 2 ** 1200, + DSA_KEY_1024.public_numbers.y, + ), + ] + ) + def test_invalid_dsa_public_key_arguments(self, p, q, g, y, backend): with pytest.raises(ValueError): dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=2 ** 1200, - ), - y=DSA_KEY_1024.public_numbers.y - ).public_key(backend) - - # Test a non-integer y value - with pytest.raises(TypeError): - dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=DSA_KEY_1024.public_numbers.parameter_numbers.p, - q=DSA_KEY_1024.public_numbers.parameter_numbers.q, - g=DSA_KEY_1024.public_numbers.parameter_numbers.g, - ), - y=None + parameter_numbers=dsa.DSAParameterNumbers(p=p, q=q, g=g), + y=y ).public_key(backend) @@ -575,32 +383,28 @@ y=vector['y'] ).public_key(backend) sig = encode_dss_signature(vector['r'], vector['s']) - verifier = pytest.deprecated_call( - public_key.verifier, sig, algorithm() - ) - verifier.update(vector['msg']) if vector['result'] == "F": with pytest.raises(InvalidSignature): - verifier.verify() + public_key.verify(sig, vector['msg'], algorithm()) else: - verifier.verify() + public_key.verify(sig, vector['msg'], algorithm()) def test_dsa_verify_invalid_asn1(self, backend): public_key = DSA_KEY_1024.public_numbers.public_key(backend) - verifier = public_key.verifier(b'fakesig', hashes.SHA1()) - verifier.update(b'fakesig') with pytest.raises(InvalidSignature): - verifier.verify() + public_key.verify(b'fakesig', b'fakemsg', hashes.SHA1()) def test_signature_not_bytes(self, backend): public_key = DSA_KEY_1024.public_numbers.public_key(backend) - with pytest.raises(TypeError): + with pytest.raises(TypeError), \ + pytest.warns(CryptographyDeprecationWarning): public_key.verifier(1234, hashes.SHA1()) def test_use_after_finalize(self, backend): public_key = DSA_KEY_1024.public_numbers.public_key(backend) - verifier = public_key.verifier(b'fakesig', hashes.SHA1()) + with pytest.warns(CryptographyDeprecationWarning): + verifier = public_key.verifier(b'fakesig', hashes.SHA1()) verifier.update(b'irrelevant') with pytest.raises(InvalidSignature): verifier.verify() @@ -613,9 +417,7 @@ message = b"one little message" algorithm = hashes.SHA1() private_key = DSA_KEY_1024.private_key(backend) - signer = private_key.signer(algorithm) - signer.update(message) - signature = signer.finalize() + signature = private_key.sign(message, algorithm) public_key = private_key.public_key() public_key.verify(signature, message, algorithm) @@ -643,12 +445,14 @@ def test_prehashed_unsupported_in_signer_ctx(self, backend): private_key = DSA_KEY_1024.private_key(backend) - with pytest.raises(TypeError): + with pytest.raises(TypeError), \ + pytest.warns(CryptographyDeprecationWarning): private_key.signer(Prehashed(hashes.SHA1())) def test_prehashed_unsupported_in_verifier_ctx(self, backend): public_key = DSA_KEY_1024.private_key(backend).public_key() - with pytest.raises(TypeError): + with pytest.raises(TypeError), \ + pytest.warns(CryptographyDeprecationWarning): public_key.verifier( b"0" * 64, Prehashed(hashes.SHA1()) ) @@ -688,19 +492,15 @@ ), x=vector['x'] ).private_key(backend) - signer = pytest.deprecated_call(private_key.signer, algorithm()) - signer.update(vector['msg']) - signature = signer.finalize() + signature = private_key.sign(vector['msg'], algorithm()) assert signature - public_key = private_key.public_key() - verifier = public_key.verifier(signature, algorithm()) - verifier.update(vector['msg']) - verifier.verify() + private_key.public_key().verify(signature, vector['msg'], algorithm()) def test_use_after_finalize(self, backend): private_key = DSA_KEY_1024.private_key(backend) - signer = private_key.signer(hashes.SHA1()) + with pytest.warns(CryptographyDeprecationWarning): + signer = private_key.signer(hashes.SHA1()) signer.update(b"data") signer.finalize() with pytest.raises(AlreadyFinalized): @@ -714,9 +514,7 @@ algorithm = hashes.SHA1() signature = private_key.sign(message, algorithm) public_key = private_key.public_key() - verifier = public_key.verifier(signature, algorithm) - verifier.update(message) - verifier.verify() + public_key.verify(signature, message, algorithm) def test_prehashed_sign(self, backend): private_key = DSA_KEY_1024.private_key(backend) @@ -727,9 +525,7 @@ prehashed_alg = Prehashed(hashes.SHA1()) signature = private_key.sign(digest, prehashed_alg) public_key = private_key.public_key() - verifier = public_key.verifier(signature, hashes.SHA1()) - verifier.update(message) - verifier.verify() + public_key.verify(signature, message, hashes.SHA1()) def test_prehashed_digest_mismatch(self, backend): private_key = DSA_KEY_1024.private_key(backend) @@ -918,6 +714,20 @@ assert loaded_priv_num == priv_num @pytest.mark.parametrize( + ("encoding", "fmt"), + [ + (serialization.Encoding.Raw, serialization.PrivateFormat.PKCS8), + (serialization.Encoding.DER, serialization.PrivateFormat.Raw), + (serialization.Encoding.Raw, serialization.PrivateFormat.Raw), + (serialization.Encoding.X962, serialization.PrivateFormat.PKCS8), + ] + ) + def test_private_bytes_rejects_invalid(self, encoding, fmt, backend): + key = DSA_KEY_1024.private_key(backend) + with pytest.raises(ValueError): + key.private_bytes(encoding, fmt, serialization.NoEncryption()) + + @pytest.mark.parametrize( ("fmt", "password"), [ [serialization.PrivateFormat.PKCS8, b"s"], @@ -1155,3 +965,30 @@ key.public_bytes( serialization.Encoding.PEM, serialization.PublicFormat.PKCS1 ) + + @pytest.mark.parametrize( + ("encoding", "fmt"), + [ + ( + serialization.Encoding.Raw, + serialization.PublicFormat.SubjectPublicKeyInfo + ), + (serialization.Encoding.Raw, serialization.PublicFormat.PKCS1), + ] + list(itertools.product( + [ + serialization.Encoding.Raw, + serialization.Encoding.X962, + serialization.Encoding.PEM, + serialization.Encoding.DER + ], + [ + serialization.PublicFormat.Raw, + serialization.PublicFormat.UncompressedPoint, + serialization.PublicFormat.CompressedPoint + ] + )) + ) + def test_public_bytes_rejects_invalid(self, encoding, fmt, backend): + key = DSA_KEY_2048.private_key(backend).public_key() + with pytest.raises(ValueError): + key.public_bytes(encoding, fmt) diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_ec.py python-cryptography-2.6.1/tests/hazmat/primitives/test_ec.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_ec.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_ec.py 2019-02-27 23:27:53.000000000 +0000 @@ -11,7 +11,7 @@ import pytest -from cryptography import exceptions, utils +from cryptography import exceptions, utils, x509 from cryptography.hazmat.backends.interfaces import ( EllipticCurveBackend, PEMSerializationBackend ) @@ -20,12 +20,13 @@ from cryptography.hazmat.primitives.asymmetric.utils import ( Prehashed, encode_dss_signature ) +from cryptography.utils import CryptographyDeprecationWarning from .fixtures_ec import EC_KEY_SECP384R1 from ...doubles import DummyKeySerializationEncryption from ...utils import ( load_fips_ecdsa_key_pair_vectors, load_fips_ecdsa_signing_vectors, - load_kasvs_ecdh_vectors, load_vectors_from_file, + load_kasvs_ecdh_vectors, load_nist_vectors, load_vectors_from_file, raises_unsupported_algorithm ) @@ -44,7 +45,7 @@ curve_type() ): pytest.skip( - "ECDSA not supported with this hash {0} and curve {1}".format( + "ECDSA not supported with this hash {} and curve {}".format( hash_type().name, curve_type().name ) ) @@ -53,7 +54,7 @@ def _skip_curve_unsupported(backend, curve): if not backend.elliptic_curve_supported(curve): pytest.skip( - "Curve {0} is not supported by this backend {1}".format( + "Curve {} is not supported by this backend {}".format( curve.name, backend ) ) @@ -64,12 +65,18 @@ algorithm, curve ): pytest.skip( - "Exchange algorithm is not supported by this backend {0}".format( - backend + "Exchange with {} curve is not supported by {}".format( + curve.name, backend ) ) +def test_get_curve_for_oid(): + assert ec.get_curve_for_oid(ec.EllipticCurveOID.SECP256R1) == ec.SECP256R1 + with pytest.raises(LookupError): + ec.get_curve_for_oid(x509.ObjectIdentifier("1.1.1.1")) + + @utils.register_interface(ec.EllipticCurve) class DummyCurve(object): name = "dummy-curve" @@ -141,43 +148,26 @@ assert numbers.public_numbers.y == 3 assert isinstance(numbers.public_numbers.curve, DummyCurve) - with pytest.raises(TypeError): - ec.EllipticCurvePrivateNumbers( - None, - ec.EllipticCurvePublicNumbers( - 2, 3, DummyCurve() - ) - ) +@pytest.mark.parametrize( + ("private_value", "x", "y", "curve"), + [ + (None, 2, 3, DummyCurve()), + (1, None, 3, DummyCurve()), + (1, 2, None, DummyCurve()), + (1, 2, 3, None), + ] +) +def test_invalid_ec_numbers_args(private_value, x, y, curve): with pytest.raises(TypeError): ec.EllipticCurvePrivateNumbers( - 1, - ec.EllipticCurvePublicNumbers( - None, 3, DummyCurve() - ) + private_value, ec.EllipticCurvePublicNumbers(x, y, curve) ) - with pytest.raises(TypeError): - ec.EllipticCurvePrivateNumbers( - 1, - ec.EllipticCurvePublicNumbers( - 2, None, DummyCurve() - ) - ) +def test_invalid_private_numbers_public_numbers(): with pytest.raises(TypeError): - ec.EllipticCurvePrivateNumbers( - 1, - ec.EllipticCurvePublicNumbers( - 2, 3, None - ) - ) - - with pytest.raises(TypeError): - ec.EllipticCurvePrivateNumbers( - 1, - None - ) + ec.EllipticCurvePrivateNumbers(1, None) def test_encode_point(): @@ -191,7 +181,8 @@ 16 ) pn = ec.EllipticCurvePublicNumbers(x, y, ec.SECP256R1()) - data = pn.encode_point() + with pytest.warns(utils.DeprecatedIn25): + data = pn.encode_point() assert data == binascii.unhexlify( "04233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22ae" "c3ea2c10a84153862be4ec82940f0543f9ba866af9751a6ee79d38460b35f442e" @@ -204,9 +195,10 @@ "04233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22ae" "c3ea2c10a84153862be4ec82940f0543f9ba866af9751a6ee79d38460b35f442e" ) - pn = ec.EllipticCurvePublicNumbers.from_encoded_point( - ec.SECP256R1(), data - ) + with pytest.warns(CryptographyDeprecationWarning): + pn = ec.EllipticCurvePublicNumbers.from_encoded_point( + ec.SECP256R1(), data + ) assert pn.x == int( '233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22aec', 16 @@ -223,27 +215,30 @@ "c3ea2c10a84153862be4ec82940f0543f9ba866af9751a6ee79d38460" ) with pytest.raises(ValueError): - ec.EllipticCurvePublicNumbers.from_encoded_point( - ec.SECP384R1(), bad_data - ) + with pytest.warns(CryptographyDeprecationWarning): + ec.EllipticCurvePublicNumbers.from_encoded_point( + ec.SECP384R1(), bad_data + ) -def test_from_encoded_point_unsupported_point_type(): +def test_from_encoded_point_unsupported_point_no_backend(): # set to point type 2. unsupported_type = binascii.unhexlify( "02233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22a" ) with pytest.raises(ValueError): - ec.EllipticCurvePublicNumbers.from_encoded_point( - ec.SECP256R1(), unsupported_type - ) + with pytest.warns(CryptographyDeprecationWarning): + ec.EllipticCurvePublicNumbers.from_encoded_point( + ec.SECP256R1(), unsupported_type + ) def test_from_encoded_point_not_a_curve(): with pytest.raises(TypeError): - ec.EllipticCurvePublicNumbers.from_encoded_point( - "notacurve", b"\x04data" - ) + with pytest.warns(CryptographyDeprecationWarning): + ec.EllipticCurvePublicNumbers.from_encoded_point( + "notacurve", b"\x04data" + ) def test_ec_public_numbers_repr(): @@ -350,13 +345,13 @@ pkey = key.public_key() assert pkey - signer = pytest.deprecated_call(key.signer, ec.ECDSA(hash_type())) + with pytest.warns(CryptographyDeprecationWarning): + signer = key.signer(ec.ECDSA(hash_type())) signer.update(b"YELLOW SUBMARINE") signature = signer.finalize() - verifier = pytest.deprecated_call( - pkey.verifier, signature, ec.ECDSA(hash_type()) - ) + with pytest.warns(CryptographyDeprecationWarning): + verifier = pkey.verifier(signature, ec.ECDSA(hash_type())) verifier.update(b"YELLOW SUBMARINE") verifier.verify() @@ -394,7 +389,7 @@ with raises_unsupported_algorithm( exceptions._Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM - ): + ), pytest.warns(CryptographyDeprecationWarning): key.signer(DummySignatureAlgorithm()) with raises_unsupported_algorithm( @@ -404,7 +399,7 @@ with raises_unsupported_algorithm( exceptions._Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM - ): + ), pytest.warns(CryptographyDeprecationWarning): key.public_key().verifier(b"", DummySignatureAlgorithm()) with raises_unsupported_algorithm( @@ -513,12 +508,11 @@ signature = encode_dss_signature(vector['r'], vector['s']) - verifier = key.verifier( + key.verify( signature, + vector['message'], ec.ECDSA(hash_type()) ) - verifier.update(vector['message']) - verifier.verify() @pytest.mark.parametrize( "vector", @@ -542,17 +536,19 @@ signature = encode_dss_signature(vector['r'], vector['s']) - verifier = key.verifier( - signature, - ec.ECDSA(hash_type()) - ) - verifier.update(vector['message']) - if vector["fail"] is True: with pytest.raises(exceptions.InvalidSignature): - verifier.verify() + key.verify( + signature, + vector['message'], + ec.ECDSA(hash_type()) + ) else: - verifier.verify() + key.verify( + signature, + vector['message'], + ec.ECDSA(hash_type()) + ) def test_sign(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) @@ -561,9 +557,7 @@ private_key = ec.generate_private_key(ec.SECP256R1(), backend) signature = private_key.sign(message, algorithm) public_key = private_key.public_key() - verifier = public_key.verifier(signature, algorithm) - verifier.update(message) - verifier.verify() + public_key.verify(signature, message, algorithm) def test_sign_prehashed(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) @@ -575,9 +569,7 @@ private_key = ec.generate_private_key(ec.SECP256R1(), backend) signature = private_key.sign(data, algorithm) public_key = private_key.public_key() - verifier = public_key.verifier(signature, ec.ECDSA(hashes.SHA1())) - verifier.update(message) - verifier.verify() + public_key.verify(signature, message, ec.ECDSA(hashes.SHA1())) def test_sign_prehashed_digest_mismatch(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) @@ -595,9 +587,7 @@ message = b"one little message" algorithm = ec.ECDSA(hashes.SHA1()) private_key = ec.generate_private_key(ec.SECP256R1(), backend) - signer = private_key.signer(algorithm) - signer.update(message) - signature = signer.finalize() + signature = private_key.sign(message, algorithm) public_key = private_key.public_key() public_key.verify(signature, message, algorithm) @@ -606,9 +596,7 @@ message = b"one little message" algorithm = ec.ECDSA(hashes.SHA1()) private_key = ec.generate_private_key(ec.SECP256R1(), backend) - signer = private_key.signer(algorithm) - signer.update(message) - signature = signer.finalize() + signature = private_key.sign(message, algorithm) h = hashes.Hash(hashes.SHA1(), backend) h.update(message) data = h.finalize() @@ -633,14 +621,16 @@ def test_prehashed_unsupported_in_signer_ctx(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) private_key = ec.generate_private_key(ec.SECP256R1(), backend) - with pytest.raises(TypeError): + with pytest.raises(TypeError), \ + pytest.warns(CryptographyDeprecationWarning): private_key.signer(ec.ECDSA(Prehashed(hashes.SHA1()))) def test_prehashed_unsupported_in_verifier_ctx(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) private_key = ec.generate_private_key(ec.SECP256R1(), backend) public_key = private_key.public_key() - with pytest.raises(TypeError): + with pytest.raises(TypeError), \ + pytest.warns(CryptographyDeprecationWarning): public_key.verifier( b"0" * 64, ec.ECDSA(Prehashed(hashes.SHA1())) @@ -723,6 +713,21 @@ assert loaded_priv_num == priv_num @pytest.mark.parametrize( + ("encoding", "fmt"), + [ + (serialization.Encoding.Raw, serialization.PrivateFormat.PKCS8), + (serialization.Encoding.DER, serialization.PrivateFormat.Raw), + (serialization.Encoding.Raw, serialization.PrivateFormat.Raw), + (serialization.Encoding.X962, serialization.PrivateFormat.PKCS8), + ] + ) + def test_private_bytes_rejects_invalid(self, encoding, fmt, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key = ec.generate_private_key(ec.SECP256R1(), backend) + with pytest.raises(ValueError): + key.private_bytes(encoding, fmt, serialization.NoEncryption()) + + @pytest.mark.parametrize( ("fmt", "password"), [ [serialization.PrivateFormat.PKCS8, b"s"], @@ -1002,6 +1007,34 @@ serialization.PublicFormat.SubjectPublicKeyInfo ) + @pytest.mark.parametrize( + ("encoding", "fmt"), + list(itertools.product( + [ + serialization.Encoding.Raw, + serialization.Encoding.X962, + serialization.Encoding.PEM, + serialization.Encoding.DER + ], + [ + serialization.PublicFormat.Raw, + ] + )) + list(itertools.product( + [serialization.Encoding.Raw], + [ + serialization.PublicFormat.SubjectPublicKeyInfo, + serialization.PublicFormat.PKCS1, + serialization.PublicFormat.UncompressedPoint, + serialization.PublicFormat.CompressedPoint, + ] + )) + ) + def test_public_bytes_rejects_invalid(self, encoding, fmt, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key = ec.generate_private_key(ec.SECP256R1(), backend).public_key() + with pytest.raises(ValueError): + key.public_bytes(encoding, fmt) + def test_public_bytes_invalid_format(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) key = load_vectors_from_file( @@ -1030,6 +1063,116 @@ serialization.Encoding.PEM, serialization.PublicFormat.PKCS1 ) + @pytest.mark.parametrize( + "vector", + load_vectors_from_file( + os.path.join("asymmetric", "EC", "compressed_points.txt"), + load_nist_vectors + ) + ) + def test_from_encoded_point_compressed(self, vector): + curve = { + b"SECP256R1": ec.SECP256R1(), + b"SECP256K1": ec.SECP256K1(), + }[vector["curve"]] + point = binascii.unhexlify(vector["point"]) + pn = ec.EllipticCurvePublicKey.from_encoded_point(curve, point) + public_num = pn.public_numbers() + assert public_num.x == int(vector["x"], 16) + assert public_num.y == int(vector["y"], 16) + + def test_from_encoded_point_notoncurve(self): + uncompressed_point = binascii.unhexlify( + "047399336a9edf2197c2f8eb3d39aed9c34a66e45d918a07dc7684c42c9b37ac" + "686699ececc4f5f0d756d3c450708a0694eb0a07a68b805070b40b058d27271f" + "6e" + ) + with pytest.raises(ValueError): + ec.EllipticCurvePublicKey.from_encoded_point( + ec.SECP256R1(), uncompressed_point + ) + + def test_from_encoded_point_uncompressed(self): + uncompressed_point = binascii.unhexlify( + "047399336a9edf2197c2f8eb3d39aed9c34a66e45d918a07dc7684c42c9b37ac" + "686699ececc4f5f0d756d3c450708a0694eb0a07a68b805070b40b058d27271f" + "6d" + ) + pn = ec.EllipticCurvePublicKey.from_encoded_point( + ec.SECP256R1(), uncompressed_point + ) + assert pn.public_numbers().x == int( + '7399336a9edf2197c2f8eb3d39aed9c34a66e45d918a07dc7684c42c9b37ac68', + 16 + ) + assert pn.public_numbers().y == int( + '6699ececc4f5f0d756d3c450708a0694eb0a07a68b805070b40b058d27271f6d', + 16 + ) + + def test_from_encoded_point_invalid_length(self): + bad_data = binascii.unhexlify( + "047399336a9edf2197c2f8eb3d39aed9c34a66e45d918a07dc7684c42c9b37ac" + "686699ececc4f5f0d756d3c450708a0694eb0a07a68b805070b40b058d27271f" + "6d" + ) + with pytest.raises(ValueError): + ec.EllipticCurvePublicKey.from_encoded_point( + ec.SECP384R1(), bad_data + ) + + def test_from_encoded_point_empty_byte_string(self): + with pytest.raises(ValueError): + ec.EllipticCurvePublicKey.from_encoded_point( + ec.SECP384R1(), b"" + ) + + def test_from_encoded_point_not_a_curve(self): + with pytest.raises(TypeError): + ec.EllipticCurvePublicKey.from_encoded_point( + "notacurve", b"\x04data" + ) + + def test_from_encoded_point_unsupported_encoding(self): + unsupported_type = binascii.unhexlify( + "057399336a9edf2197c2f8eb3d39aed9c34a66e45d918a07dc7684c42c9b37ac6" + "8" + ) + with pytest.raises(ValueError): + ec.EllipticCurvePublicKey.from_encoded_point( + ec.SECP256R1(), unsupported_type + ) + + @pytest.mark.parametrize( + "vector", + load_vectors_from_file( + os.path.join("asymmetric", "EC", "compressed_points.txt"), + load_nist_vectors + ) + ) + def test_serialize_point(self, vector, backend): + curve = { + b"SECP256R1": ec.SECP256R1(), + b"SECP256K1": ec.SECP256K1(), + }[vector["curve"]] + point = binascii.unhexlify(vector["point"]) + key = ec.EllipticCurvePublicKey.from_encoded_point(curve, point) + key2 = ec.EllipticCurvePublicKey.from_encoded_point( + curve, + key.public_bytes( + serialization.Encoding.X962, + serialization.PublicFormat.UncompressedPoint + ) + ) + assert key.public_bytes( + serialization.Encoding.X962, + serialization.PublicFormat.CompressedPoint + ) == point + assert key2.public_bytes( + serialization.Encoding.X962, + serialization.PublicFormat.CompressedPoint + ) == point + @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) class TestECDSAVerification(object): @@ -1037,7 +1180,8 @@ _skip_curve_unsupported(backend, ec.SECP256R1()) key = ec.generate_private_key(ec.SECP256R1(), backend) public_key = key.public_key() - with pytest.raises(TypeError): + with pytest.raises(TypeError), \ + pytest.warns(CryptographyDeprecationWarning): public_key.verifier(1234, ec.ECDSA(hashes.SHA256())) @@ -1066,9 +1210,9 @@ ec._CURVE_TYPES[vector['curve']]() ) ) - # Errno 5 and 6 indicates a bad public key, this doesn't test the ECDH - # code at all - if vector['fail'] and vector['errno'] in [5, 6]: + # Errno 5-7 indicates a bad public or private key, this doesn't test + # the ECDH code at all + if vector['fail'] and vector['errno'] in [5, 6, 7]: with pytest.raises(ValueError): private_numbers.private_key(backend) return @@ -1095,10 +1239,39 @@ # At this point fail indicates that one of the underlying keys was # changed. This results in a non-matching derived key. if vector['fail']: + # Errno 8 indicates Z should be changed. + assert vector['errno'] == 8 assert z != vector['Z'] else: assert z == vector['Z'] + @pytest.mark.parametrize( + "vector", + load_vectors_from_file( + os.path.join("asymmetric", "ECDH", "brainpool.txt"), + load_nist_vectors + ) + ) + def test_brainpool_kex(self, backend, vector): + curve = ec._CURVE_TYPES[vector['curve'].decode('ascii')] + _skip_exchange_algorithm_unsupported(backend, ec.ECDH(), curve) + key = ec.EllipticCurvePrivateNumbers( + int(vector['da'], 16), + ec.EllipticCurvePublicNumbers( + int(vector['x_qa'], 16), int(vector['y_qa'], 16), curve() + ) + ).private_key(backend) + peer = ec.EllipticCurvePrivateNumbers( + int(vector['db'], 16), + ec.EllipticCurvePublicNumbers( + int(vector['x_qb'], 16), int(vector['y_qb'], 16), curve() + ) + ).private_key(backend) + shared_secret = key.exchange(ec.ECDH(), peer.public_key()) + assert shared_secret == binascii.unhexlify(vector["x_z"]) + shared_secret_2 = peer.exchange(ec.ECDH(), key.public_key()) + assert shared_secret_2 == binascii.unhexlify(vector["x_z"]) + def test_exchange_unsupported_algorithm(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_ed25519.py python-cryptography-2.6.1/tests/hazmat/primitives/test_ed25519.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_ed25519.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_ed25519.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,229 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii +import os + +import pytest + +from cryptography.exceptions import InvalidSignature, _Reasons +from cryptography.hazmat.backends.interfaces import DHBackend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.ed25519 import ( + Ed25519PrivateKey, Ed25519PublicKey +) + +from ...utils import ( + load_vectors_from_file, raises_unsupported_algorithm +) + + +def load_ed25519_vectors(vector_data): + """ + djb's ed25519 vectors are structured as a colon delimited array: + 0: secret key (32 bytes) + public key (32 bytes) + 1: public key (32 bytes) + 2: message (0+ bytes) + 3: signature + message (64+ bytes) + """ + data = [] + for line in vector_data: + secret_key, public_key, message, signature, _ = line.split(':') + secret_key = secret_key[0:64] + signature = signature[0:128] + data.append({ + "secret_key": secret_key, + "public_key": public_key, + "message": message, + "signature": signature + }) + return data + + +@pytest.mark.supported( + only_if=lambda backend: not backend.ed25519_supported(), + skip_message="Requires OpenSSL without Ed25519 support" +) +@pytest.mark.requires_backend_interface(interface=DHBackend) +def test_ed25519_unsupported(backend): + with raises_unsupported_algorithm( + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ): + Ed25519PublicKey.from_public_bytes(b"0" * 32) + + with raises_unsupported_algorithm( + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ): + Ed25519PrivateKey.from_private_bytes(b"0" * 32) + + with raises_unsupported_algorithm( + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ): + Ed25519PrivateKey.generate() + + +@pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support" +) +@pytest.mark.requires_backend_interface(interface=DHBackend) +class TestEd25519Signing(object): + @pytest.mark.parametrize( + "vector", + load_vectors_from_file( + os.path.join("asymmetric", "Ed25519", "sign.input"), + load_ed25519_vectors + ) + ) + def test_sign_verify_input(self, vector, backend): + sk = binascii.unhexlify(vector["secret_key"]) + pk = binascii.unhexlify(vector["public_key"]) + message = binascii.unhexlify(vector["message"]) + signature = binascii.unhexlify(vector["signature"]) + private_key = Ed25519PrivateKey.from_private_bytes(sk) + computed_sig = private_key.sign(message) + assert computed_sig == signature + public_key = private_key.public_key() + assert public_key.public_bytes( + serialization.Encoding.Raw, serialization.PublicFormat.Raw + ) == pk + public_key.verify(signature, message) + + def test_invalid_signature(self, backend): + key = Ed25519PrivateKey.generate() + signature = key.sign(b"test data") + with pytest.raises(InvalidSignature): + key.public_key().verify(signature, b"wrong data") + + with pytest.raises(InvalidSignature): + key.public_key().verify(b"0" * 64, b"test data") + + def test_generate(self, backend): + key = Ed25519PrivateKey.generate() + assert key + assert key.public_key() + + def test_load_public_bytes(self, backend): + public_key = Ed25519PrivateKey.generate().public_key() + public_bytes = public_key.public_bytes( + serialization.Encoding.Raw, serialization.PublicFormat.Raw + ) + public_key2 = Ed25519PublicKey.from_public_bytes(public_bytes) + assert public_bytes == public_key2.public_bytes( + serialization.Encoding.Raw, serialization.PublicFormat.Raw + ) + + def test_invalid_type_public_bytes(self, backend): + with pytest.raises(TypeError): + Ed25519PublicKey.from_public_bytes(object()) + + def test_invalid_type_private_bytes(self, backend): + with pytest.raises(TypeError): + Ed25519PrivateKey.from_private_bytes(object()) + + def test_invalid_length_from_public_bytes(self, backend): + with pytest.raises(ValueError): + Ed25519PublicKey.from_public_bytes(b"a" * 31) + with pytest.raises(ValueError): + Ed25519PublicKey.from_public_bytes(b"a" * 33) + + def test_invalid_length_from_private_bytes(self, backend): + with pytest.raises(ValueError): + Ed25519PrivateKey.from_private_bytes(b"a" * 31) + with pytest.raises(ValueError): + Ed25519PrivateKey.from_private_bytes(b"a" * 33) + + def test_invalid_private_bytes(self, backend): + key = Ed25519PrivateKey.generate() + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.Raw, + serialization.PrivateFormat.Raw, + None + ) + + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.Raw, + serialization.PrivateFormat.PKCS8, + None + ) + + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.Raw, + serialization.NoEncryption() + ) + + def test_invalid_public_bytes(self, backend): + key = Ed25519PrivateKey.generate().public_key() + with pytest.raises(ValueError): + key.public_bytes( + serialization.Encoding.Raw, + serialization.PublicFormat.SubjectPublicKeyInfo + ) + + with pytest.raises(ValueError): + key.public_bytes( + serialization.Encoding.PEM, + serialization.PublicFormat.PKCS1 + ) + + with pytest.raises(ValueError): + key.public_bytes( + serialization.Encoding.PEM, + serialization.PublicFormat.Raw + ) + + @pytest.mark.parametrize( + ("encoding", "fmt", "encryption", "passwd", "load_func"), + [ + ( + serialization.Encoding.PEM, + serialization.PrivateFormat.PKCS8, + serialization.BestAvailableEncryption(b"password"), + b"password", + serialization.load_pem_private_key + ), + ( + serialization.Encoding.DER, + serialization.PrivateFormat.PKCS8, + serialization.BestAvailableEncryption(b"password"), + b"password", + serialization.load_der_private_key + ), + ( + serialization.Encoding.PEM, + serialization.PrivateFormat.PKCS8, + serialization.NoEncryption(), + None, + serialization.load_pem_private_key + ), + ( + serialization.Encoding.DER, + serialization.PrivateFormat.PKCS8, + serialization.NoEncryption(), + None, + serialization.load_der_private_key + ), + ] + ) + def test_round_trip_private_serialization(self, encoding, fmt, encryption, + passwd, load_func, backend): + key = Ed25519PrivateKey.generate() + serialized = key.private_bytes(encoding, fmt, encryption) + loaded_key = load_func(serialized, passwd, backend) + assert isinstance(loaded_key, Ed25519PrivateKey) + + def test_buffer_protocol(self, backend): + private_bytes = os.urandom(32) + key = Ed25519PrivateKey.from_private_bytes(bytearray(private_bytes)) + assert key.private_bytes( + serialization.Encoding.Raw, + serialization.PrivateFormat.Raw, + serialization.NoEncryption() + ) == private_bytes diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_ed448.py python-cryptography-2.6.1/tests/hazmat/primitives/test_ed448.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_ed448.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_ed448.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,242 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii +import os + +import pytest + +from cryptography.exceptions import InvalidSignature, _Reasons +from cryptography.hazmat.backends.interfaces import DHBackend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.ed448 import ( + Ed448PrivateKey, Ed448PublicKey +) + +from ...utils import ( + load_nist_vectors, load_vectors_from_file, raises_unsupported_algorithm +) + + +@pytest.mark.supported( + only_if=lambda backend: not backend.ed448_supported(), + skip_message="Requires OpenSSL without Ed448 support" +) +@pytest.mark.requires_backend_interface(interface=DHBackend) +def test_ed448_unsupported(backend): + with raises_unsupported_algorithm( + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ): + Ed448PublicKey.from_public_bytes(b"0" * 57) + + with raises_unsupported_algorithm( + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ): + Ed448PrivateKey.from_private_bytes(b"0" * 57) + + with raises_unsupported_algorithm( + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM + ): + Ed448PrivateKey.generate() + + +@pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support" +) +@pytest.mark.requires_backend_interface(interface=DHBackend) +class TestEd448Signing(object): + @pytest.mark.parametrize( + "vector", + load_vectors_from_file( + os.path.join("asymmetric", "Ed448", "rfc8032.txt"), + load_nist_vectors + ) + ) + def test_sign_input(self, vector, backend): + if vector.get("context") is not None: + pytest.skip("ed448 contexts are not currently supported") + + sk = binascii.unhexlify(vector["secret"]) + pk = binascii.unhexlify(vector["public"]) + message = binascii.unhexlify(vector["message"]) + signature = binascii.unhexlify(vector["signature"]) + private_key = Ed448PrivateKey.from_private_bytes(sk) + computed_sig = private_key.sign(message) + assert computed_sig == signature + public_key = private_key.public_key() + assert public_key.public_bytes( + serialization.Encoding.Raw, serialization.PublicFormat.Raw + ) == pk + public_key.verify(signature, message) + + def test_invalid_signature(self, backend): + key = Ed448PrivateKey.generate() + signature = key.sign(b"test data") + with pytest.raises(InvalidSignature): + key.public_key().verify(signature, b"wrong data") + + with pytest.raises(InvalidSignature): + key.public_key().verify(b"0" * 64, b"test data") + + def test_generate(self, backend): + key = Ed448PrivateKey.generate() + assert key + assert key.public_key() + + @pytest.mark.parametrize( + "vector", + load_vectors_from_file( + os.path.join("asymmetric", "Ed448", "rfc8032.txt"), + load_nist_vectors + ) + ) + def test_pub_priv_bytes_raw(self, vector, backend): + sk = binascii.unhexlify(vector["secret"]) + pk = binascii.unhexlify(vector["public"]) + private_key = Ed448PrivateKey.from_private_bytes(sk) + assert private_key.private_bytes( + serialization.Encoding.Raw, + serialization.PrivateFormat.Raw, + serialization.NoEncryption() + ) == sk + assert private_key.public_key().public_bytes( + serialization.Encoding.Raw, serialization.PublicFormat.Raw + ) == pk + public_key = Ed448PublicKey.from_public_bytes(pk) + assert public_key.public_bytes( + serialization.Encoding.Raw, serialization.PublicFormat.Raw + ) == pk + + @pytest.mark.parametrize( + ("encoding", "fmt", "encryption", "passwd", "load_func"), + [ + ( + serialization.Encoding.PEM, + serialization.PrivateFormat.PKCS8, + serialization.BestAvailableEncryption(b"password"), + b"password", + serialization.load_pem_private_key + ), + ( + serialization.Encoding.DER, + serialization.PrivateFormat.PKCS8, + serialization.BestAvailableEncryption(b"password"), + b"password", + serialization.load_der_private_key + ), + ( + serialization.Encoding.PEM, + serialization.PrivateFormat.PKCS8, + serialization.NoEncryption(), + None, + serialization.load_pem_private_key + ), + ( + serialization.Encoding.DER, + serialization.PrivateFormat.PKCS8, + serialization.NoEncryption(), + None, + serialization.load_der_private_key + ), + ] + ) + def test_round_trip_private_serialization(self, encoding, fmt, encryption, + passwd, load_func, backend): + key = Ed448PrivateKey.generate() + serialized = key.private_bytes(encoding, fmt, encryption) + loaded_key = load_func(serialized, passwd, backend) + assert isinstance(loaded_key, Ed448PrivateKey) + + def test_invalid_type_public_bytes(self, backend): + with pytest.raises(TypeError): + Ed448PublicKey.from_public_bytes(object()) + + def test_invalid_type_private_bytes(self, backend): + with pytest.raises(TypeError): + Ed448PrivateKey.from_private_bytes(object()) + + def test_invalid_length_from_public_bytes(self, backend): + with pytest.raises(ValueError): + Ed448PublicKey.from_public_bytes(b"a" * 56) + with pytest.raises(ValueError): + Ed448PublicKey.from_public_bytes(b"a" * 58) + + def test_invalid_length_from_private_bytes(self, backend): + with pytest.raises(ValueError): + Ed448PrivateKey.from_private_bytes(b"a" * 56) + with pytest.raises(ValueError): + Ed448PrivateKey.from_private_bytes(b"a" * 58) + + def test_invalid_private_bytes(self, backend): + key = Ed448PrivateKey.generate() + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.Raw, + serialization.PrivateFormat.Raw, + None + ) + + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.Raw, + serialization.PrivateFormat.PKCS8, + None + ) + + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.Raw, + serialization.NoEncryption() + ) + + def test_invalid_public_bytes(self, backend): + key = Ed448PrivateKey.generate().public_key() + with pytest.raises(ValueError): + key.public_bytes( + serialization.Encoding.Raw, + serialization.PublicFormat.SubjectPublicKeyInfo + ) + + with pytest.raises(ValueError): + key.public_bytes( + serialization.Encoding.PEM, + serialization.PublicFormat.PKCS1 + ) + + with pytest.raises(ValueError): + key.public_bytes( + serialization.Encoding.PEM, + serialization.PublicFormat.Raw + ) + + def test_buffer_protocol(self, backend): + private_bytes = os.urandom(57) + key = Ed448PrivateKey.from_private_bytes(bytearray(private_bytes)) + assert key.private_bytes( + serialization.Encoding.Raw, + serialization.PrivateFormat.Raw, + serialization.NoEncryption() + ) == private_bytes + + def test_malleability(self, backend): + # This is a signature where r > the group order. It should be + # rejected to prevent signature malleability issues. This test can + # be removed when wycheproof grows ed448 vectors + public_bytes = binascii.unhexlify( + "fedb02a658d74990244d9d10cf338e977565cbbda6b24c716829ed6ee1e4f28cf" + "2620c052db8d878f6243bffc22242816c1aaa67d2f3603600" + ) + signature = binascii.unhexlify( + "0cc16ba24d69277f927c1554b0f08a2a711bbdd20b058ccc660d00ca13542a3ce" + "f9e5c44c54ab23a2eb14f947e167b990b080863e28b399380f30db6e54d5d1406" + "d23378ffde11b1fb81b2b438a3b8e8aa7f7f4e1befcc905023fab5a5465053844" + "f04cf0c1b51d84760f869588687f57500" + ) + key = Ed448PublicKey.from_public_bytes(public_bytes) + with pytest.raises(InvalidSignature): + key.verify(signature, b"8") diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_hashes.py python-cryptography-2.6.1/tests/hazmat/primitives/test_hashes.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_hashes.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_hashes.py 2019-02-27 23:27:53.000000000 +0000 @@ -4,6 +4,8 @@ from __future__ import absolute_import, division, print_function +import binascii + import pytest from cryptography.exceptions import AlreadyFinalized, _Reasons @@ -50,10 +52,9 @@ ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA1(object): - test_SHA1 = generate_base_hash_test( + test_sha1 = generate_base_hash_test( hashes.SHA1(), digest_size=20, - block_size=64, ) @@ -63,10 +64,9 @@ ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA224(object): - test_SHA224 = generate_base_hash_test( + test_sha224 = generate_base_hash_test( hashes.SHA224(), digest_size=28, - block_size=64, ) @@ -76,10 +76,9 @@ ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA256(object): - test_SHA256 = generate_base_hash_test( + test_sha256 = generate_base_hash_test( hashes.SHA256(), digest_size=32, - block_size=64, ) @@ -89,10 +88,9 @@ ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA384(object): - test_SHA384 = generate_base_hash_test( + test_sha384 = generate_base_hash_test( hashes.SHA384(), digest_size=48, - block_size=128, ) @@ -102,10 +100,9 @@ ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA512(object): - test_SHA512 = generate_base_hash_test( + test_sha512 = generate_base_hash_test( hashes.SHA512(), digest_size=64, - block_size=128, ) @@ -115,10 +112,9 @@ ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestMD5(object): - test_MD5 = generate_base_hash_test( + test_md5 = generate_base_hash_test( hashes.MD5(), digest_size=16, - block_size=64, ) @@ -129,10 +125,9 @@ ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestBLAKE2b(object): - test_BLAKE2b = generate_base_hash_test( + test_blake2b = generate_base_hash_test( hashes.BLAKE2b(digest_size=64), digest_size=64, - block_size=128, ) def test_invalid_digest_size(self, backend): @@ -153,10 +148,9 @@ ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestBLAKE2s(object): - test_BLAKE2s = generate_base_hash_test( + test_blake2s = generate_base_hash_test( hashes.BLAKE2s(digest_size=32), digest_size=32, - block_size=64, ) def test_invalid_digest_size(self, backend): @@ -175,3 +169,34 @@ with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): hashes.Hash(hashes.SHA1(), pretend_backend) + + +@pytest.mark.requires_backend_interface(interface=HashBackend) +def test_buffer_protocol_hash(backend): + data = binascii.unhexlify(b"b4190e") + h = hashes.Hash(hashes.SHA256(), backend) + h.update(bytearray(data)) + assert h.finalize() == binascii.unhexlify( + b"dff2e73091f6c05e528896c4c831b9448653dc2ff043528f6769437bc7b975c2" + ) + + +class TestSHAKE(object): + @pytest.mark.parametrize( + "xof", + [hashes.SHAKE128, hashes.SHAKE256] + ) + def test_invalid_digest_type(self, xof): + with pytest.raises(TypeError): + xof(digest_size=object()) + + @pytest.mark.parametrize( + "xof", + [hashes.SHAKE128, hashes.SHAKE256] + ) + def test_invalid_digest_size(self, xof): + with pytest.raises(ValueError): + xof(digest_size=-5) + + with pytest.raises(ValueError): + xof(digest_size=0) diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_hash_vectors.py python-cryptography-2.6.1/tests/hazmat/primitives/test_hash_vectors.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_hash_vectors.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_hash_vectors.py 2019-02-27 23:27:53.000000000 +0000 @@ -4,6 +4,7 @@ from __future__ import absolute_import, division, print_function +import binascii import os import pytest @@ -11,8 +12,8 @@ from cryptography.hazmat.backends.interfaces import HashBackend from cryptography.hazmat.primitives import hashes -from .utils import generate_hash_test -from ...utils import load_hash_vectors +from .utils import _load_all_params, generate_hash_test +from ...utils import load_hash_vectors, load_nist_vectors @pytest.mark.supported( @@ -21,7 +22,7 @@ ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA1(object): - test_SHA1 = generate_hash_test( + test_sha1 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA1"), [ @@ -38,7 +39,7 @@ ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA224(object): - test_SHA224 = generate_hash_test( + test_sha224 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA2"), [ @@ -55,7 +56,7 @@ ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA256(object): - test_SHA256 = generate_hash_test( + test_sha256 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA2"), [ @@ -72,7 +73,7 @@ ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA384(object): - test_SHA384 = generate_hash_test( + test_sha384 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA2"), [ @@ -89,7 +90,7 @@ ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA512(object): - test_SHA512 = generate_hash_test( + test_sha512 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA2"), [ @@ -101,6 +102,40 @@ @pytest.mark.supported( + only_if=lambda backend: backend.hash_supported(hashes.SHA512_224()), + skip_message="Does not support SHA512/224", +) +@pytest.mark.requires_backend_interface(interface=HashBackend) +class TestSHA512224(object): + test_sha512_224 = generate_hash_test( + load_hash_vectors, + os.path.join("hashes", "SHA2"), + [ + "SHA512_224LongMsg.rsp", + "SHA512_224ShortMsg.rsp", + ], + hashes.SHA512_224(), + ) + + +@pytest.mark.supported( + only_if=lambda backend: backend.hash_supported(hashes.SHA512_256()), + skip_message="Does not support SHA512/256", +) +@pytest.mark.requires_backend_interface(interface=HashBackend) +class TestSHA512256(object): + test_sha512_256 = generate_hash_test( + load_hash_vectors, + os.path.join("hashes", "SHA2"), + [ + "SHA512_256LongMsg.rsp", + "SHA512_256ShortMsg.rsp", + ], + hashes.SHA512_256(), + ) + + +@pytest.mark.supported( only_if=lambda backend: backend.hash_supported(hashes.MD5()), skip_message="Does not support MD5", ) @@ -148,3 +183,143 @@ ], hashes.BLAKE2s(digest_size=32), ) + + +@pytest.mark.supported( + only_if=lambda backend: backend.hash_supported(hashes.SHA3_224()), + skip_message="Does not support SHA3_224", +) +@pytest.mark.requires_backend_interface(interface=HashBackend) +class TestSHA3224(object): + test_sha3_224 = generate_hash_test( + load_hash_vectors, + os.path.join("hashes", "SHA3"), + [ + "SHA3_224LongMsg.rsp", + "SHA3_224ShortMsg.rsp", + ], + hashes.SHA3_224(), + ) + + +@pytest.mark.supported( + only_if=lambda backend: backend.hash_supported(hashes.SHA3_256()), + skip_message="Does not support SHA3_256", +) +@pytest.mark.requires_backend_interface(interface=HashBackend) +class TestSHA3256(object): + test_sha3_256 = generate_hash_test( + load_hash_vectors, + os.path.join("hashes", "SHA3"), + [ + "SHA3_256LongMsg.rsp", + "SHA3_256ShortMsg.rsp", + ], + hashes.SHA3_256(), + ) + + +@pytest.mark.supported( + only_if=lambda backend: backend.hash_supported(hashes.SHA3_384()), + skip_message="Does not support SHA3_384", +) +@pytest.mark.requires_backend_interface(interface=HashBackend) +class TestSHA3384(object): + test_sha3_384 = generate_hash_test( + load_hash_vectors, + os.path.join("hashes", "SHA3"), + [ + "SHA3_384LongMsg.rsp", + "SHA3_384ShortMsg.rsp", + ], + hashes.SHA3_384(), + ) + + +@pytest.mark.supported( + only_if=lambda backend: backend.hash_supported(hashes.SHA3_512()), + skip_message="Does not support SHA3_512", +) +@pytest.mark.requires_backend_interface(interface=HashBackend) +class TestSHA3512(object): + test_sha3_512 = generate_hash_test( + load_hash_vectors, + os.path.join("hashes", "SHA3"), + [ + "SHA3_512LongMsg.rsp", + "SHA3_512ShortMsg.rsp", + ], + hashes.SHA3_512(), + ) + + +@pytest.mark.supported( + only_if=lambda backend: backend.hash_supported( + hashes.SHAKE128(digest_size=16)), + skip_message="Does not support SHAKE128", +) +@pytest.mark.requires_backend_interface(interface=HashBackend) +class TestSHAKE128(object): + test_shake128 = generate_hash_test( + load_hash_vectors, + os.path.join("hashes", "SHAKE"), + [ + "SHAKE128LongMsg.rsp", + "SHAKE128ShortMsg.rsp", + ], + hashes.SHAKE128(digest_size=16), + ) + + @pytest.mark.parametrize( + "vector", + _load_all_params( + os.path.join("hashes", "SHAKE"), + [ + "SHAKE128VariableOut.rsp", + ], + load_nist_vectors, + ) + ) + def test_shake128_variable(self, vector, backend): + output_length = int(vector['outputlen']) // 8 + msg = binascii.unhexlify(vector['msg']) + shake = hashes.SHAKE128(digest_size=output_length) + m = hashes.Hash(shake, backend=backend) + m.update(msg) + assert m.finalize() == binascii.unhexlify(vector['output']) + + +@pytest.mark.supported( + only_if=lambda backend: backend.hash_supported( + hashes.SHAKE256(digest_size=32)), + skip_message="Does not support SHAKE256", +) +@pytest.mark.requires_backend_interface(interface=HashBackend) +class TestSHAKE256(object): + test_shake256 = generate_hash_test( + load_hash_vectors, + os.path.join("hashes", "SHAKE"), + [ + "SHAKE256LongMsg.rsp", + "SHAKE256ShortMsg.rsp", + ], + hashes.SHAKE256(digest_size=32), + ) + + @pytest.mark.parametrize( + "vector", + _load_all_params( + os.path.join("hashes", "SHAKE"), + [ + "SHAKE256VariableOut.rsp", + ], + load_nist_vectors, + ) + ) + def test_shake256_variable(self, vector, backend): + output_length = int(vector['outputlen']) // 8 + msg = binascii.unhexlify(vector['msg']) + shake = hashes.SHAKE256(digest_size=output_length) + m = hashes.Hash(shake, backend=backend) + m.update(msg) + assert m.finalize() == binascii.unhexlify(vector['output']) diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_hkdf.py python-cryptography-2.6.1/tests/hazmat/primitives/test_hkdf.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_hkdf.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_hkdf.py 2019-02-27 23:27:53.000000000 +0000 @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function import binascii +import os import pytest @@ -15,13 +16,15 @@ from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.hkdf import HKDF, HKDFExpand -from ...utils import raises_unsupported_algorithm +from ...utils import ( + load_nist_vectors, load_vectors_from_file, raises_unsupported_algorithm +) @pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHKDF(object): def test_length_limit(self, backend): - big_length = 255 * (hashes.SHA256().digest_size // 8) + 1 + big_length = 255 * hashes.SHA256().digest_size + 1 with pytest.raises(ValueError): HKDF( @@ -153,6 +156,36 @@ assert hkdf.derive(b"\x01" * 16) == b"gJ\xfb{" + def test_derive_long_output(self, backend): + vector = load_vectors_from_file( + os.path.join("KDF", "hkdf-generated.txt"), load_nist_vectors + )[0] + hkdf = HKDF( + hashes.SHA256(), + int(vector["l"]), + salt=vector["salt"], + info=vector["info"], + backend=backend + ) + ikm = binascii.unhexlify(vector["ikm"]) + + assert hkdf.derive(ikm) == binascii.unhexlify(vector["okm"]) + + def test_buffer_protocol(self, backend): + vector = load_vectors_from_file( + os.path.join("KDF", "hkdf-generated.txt"), load_nist_vectors + )[0] + hkdf = HKDF( + hashes.SHA256(), + int(vector["l"]), + salt=vector["salt"], + info=vector["info"], + backend=backend + ) + ikm = bytearray(binascii.unhexlify(vector["ikm"])) + + assert hkdf.derive(ikm) == binascii.unhexlify(vector["okm"]) + @pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHKDFExpand(object): @@ -163,6 +196,19 @@ okm = (b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c" b"5bf34007208d5b887185865") + + info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9") + hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend) + + assert binascii.hexlify(hkdf.derive(prk)) == okm + + def test_buffer_protocol(self, backend): + prk = bytearray(binascii.unhexlify( + b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5" + )) + + okm = (b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c" + b"5bf34007208d5b887185865") info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9") hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend) diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_hkdf_vectors.py python-cryptography-2.6.1/tests/hazmat/primitives/test_hkdf_vectors.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_hkdf_vectors.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_hkdf_vectors.py 2019-02-27 23:27:53.000000000 +0000 @@ -21,7 +21,7 @@ ) @pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHKDFSHA1(object): - test_HKDFSHA1 = generate_hkdf_test( + test_hkdfsha1 = generate_hkdf_test( load_nist_vectors, os.path.join("KDF"), ["rfc-5869-HKDF-SHA1.txt"], @@ -35,7 +35,7 @@ ) @pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHKDFSHA256(object): - test_HKDFSHA1 = generate_hkdf_test( + test_hkdfsha256 = generate_hkdf_test( load_nist_vectors, os.path.join("KDF"), ["rfc-5869-HKDF-SHA256.txt"], diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_hmac.py python-cryptography-2.6.1/tests/hazmat/primitives/test_hmac.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_hmac.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_hmac.py 2019-02-27 23:27:53.000000000 +0000 @@ -4,6 +4,8 @@ from __future__ import absolute_import, division, print_function +import binascii + import pytest from cryptography.exceptions import ( @@ -79,6 +81,14 @@ with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_HASH): hmac.HMAC(b"key", DummyHashAlgorithm(), backend) + def test_buffer_protocol(self, backend): + key = bytearray(b"2b7e151628aed2a6abf7158809cf4f3c") + h = hmac.HMAC(key, hashes.SHA256(), backend) + h.update(bytearray(b"6bc1bee22e409f96e93d7e117393172a")) + assert h.finalize() == binascii.unhexlify( + b"a1bf7169c56a501c6585190ff4f07cad6e492a3ee187c0372614fb444b9fc3f0" + ) + def test_invalid_backend(): pretend_backend = object() diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_idea.py python-cryptography-2.6.1/tests/hazmat/primitives/test_idea.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_idea.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_idea.py 2019-02-27 23:27:53.000000000 +0000 @@ -24,7 +24,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestIDEAModeECB(object): - test_ECB = generate_encrypt_test( + test_ecb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "IDEA"), ["idea-ecb.txt"], @@ -41,7 +41,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestIDEAModeCBC(object): - test_CBC = generate_encrypt_test( + test_cbc = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "IDEA"), ["idea-cbc.txt"], @@ -58,7 +58,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestIDEAModeOFB(object): - test_OFB = generate_encrypt_test( + test_ofb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "IDEA"), ["idea-ofb.txt"], @@ -75,7 +75,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestIDEAModeCFB(object): - test_CFB = generate_encrypt_test( + test_cfb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "IDEA"), ["idea-cfb.txt"], diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_kbkdf.py python-cryptography-2.6.1/tests/hazmat/primitives/test_kbkdf.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_kbkdf.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_kbkdf.py 2019-02-27 23:27:53.000000000 +0000 @@ -9,7 +9,7 @@ from cryptography.exceptions import ( AlreadyFinalized, InvalidKey, _Reasons ) -from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.kbkdf import ( CounterLocation, KBKDFHMAC, Mode @@ -19,25 +19,26 @@ from ...utils import raises_unsupported_algorithm +@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestKBKDFHMAC(object): - def test_invalid_key(self): + def test_invalid_key(self, backend): kdf = KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, CounterLocation.BeforeFixed, b'label', b'context', - None, backend=default_backend()) + None, backend=backend) key = kdf.derive(b"material") kdf = KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, CounterLocation.BeforeFixed, b'label', b'context', - None, backend=default_backend()) + None, backend=backend) with pytest.raises(InvalidKey): kdf.verify(b"material2", key) - def test_already_finalized(self): + def test_already_finalized(self, backend): kdf = KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, CounterLocation.BeforeFixed, b'label', b'context', - None, backend=default_backend()) + None, backend=backend) kdf.derive(b'material') @@ -46,7 +47,7 @@ kdf = KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, CounterLocation.BeforeFixed, b'label', b'context', - None, backend=default_backend()) + None, backend=backend) key = kdf.derive(b'material') @@ -55,97 +56,103 @@ kdf = KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, CounterLocation.BeforeFixed, b'label', b'context', - None, backend=default_backend()) + None, backend=backend) kdf.verify(b'material', key) with pytest.raises(AlreadyFinalized): kdf.verify(b"material", key) - def test_key_length(self): + def test_key_length(self, backend): kdf = KBKDFHMAC(hashes.SHA1(), Mode.CounterMode, 85899345920, 4, 4, CounterLocation.BeforeFixed, b'label', b'context', - None, backend=default_backend()) + None, backend=backend) with pytest.raises(ValueError): kdf.derive(b'material') - def test_rlen(self): + def test_rlen(self, backend): with pytest.raises(ValueError): KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 5, 4, CounterLocation.BeforeFixed, b'label', b'context', - None, backend=default_backend()) + None, backend=backend) - def test_r_type(self): + def test_r_type(self, backend): with pytest.raises(TypeError): KBKDFHMAC(hashes.SHA1(), Mode.CounterMode, 32, b'r', 4, CounterLocation.BeforeFixed, b'label', b'context', - None, backend=default_backend()) + None, backend=backend) - def test_l_type(self): + def test_l_type(self, backend): with pytest.raises(TypeError): KBKDFHMAC(hashes.SHA1(), Mode.CounterMode, 32, 4, b'l', CounterLocation.BeforeFixed, b'label', b'context', - None, backend=default_backend()) + None, backend=backend) - def test_l(self): + def test_l(self, backend): with pytest.raises(ValueError): KBKDFHMAC(hashes.SHA1(), Mode.CounterMode, 32, 4, None, CounterLocation.BeforeFixed, b'label', b'context', - None, backend=default_backend()) + None, backend=backend) - def test_unsupported_mode(self): + def test_unsupported_mode(self, backend): with pytest.raises(TypeError): KBKDFHMAC(hashes.SHA256(), None, 32, 4, 4, CounterLocation.BeforeFixed, b'label', b'context', - None, backend=default_backend()) + None, backend=backend) - def test_unsupported_location(self): + def test_unsupported_location(self, backend): with pytest.raises(TypeError): KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, None, b'label', b'context', None, - backend=default_backend()) + backend=backend) - def test_unsupported_parameters(self): + def test_unsupported_parameters(self, backend): with pytest.raises(ValueError): KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, CounterLocation.BeforeFixed, b'label', b'context', - b'fixed', backend=default_backend()) + b'fixed', backend=backend) - def test_unsupported_hash(self): + def test_unsupported_hash(self, backend): with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_HASH): KBKDFHMAC(object(), Mode.CounterMode, 32, 4, 4, CounterLocation.BeforeFixed, b'label', b'context', - None, backend=default_backend()) + None, backend=backend) - def test_unsupported_algorithm(self): + def test_unsupported_algorithm(self, backend): with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_HASH): KBKDFHMAC(DummyHashAlgorithm(), Mode.CounterMode, 32, 4, 4, CounterLocation.BeforeFixed, b'label', b'context', - None, backend=default_backend()) - - def test_invalid_backend(self): - mock_backend = object + None, backend=backend) + def test_invalid_backend(self, backend): with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, CounterLocation.BeforeFixed, b'label', b'context', - None, backend=mock_backend()) + None, backend=object()) - def test_unicode_error_label(self): + def test_unicode_error_label(self, backend): with pytest.raises(TypeError): KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, CounterLocation.BeforeFixed, u'label', b'context', - backend=default_backend()) + backend=backend) - def test_unicode_error_context(self): + def test_unicode_error_context(self, backend): with pytest.raises(TypeError): KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, CounterLocation.BeforeFixed, b'label', u'context', - None, backend=default_backend()) + None, backend=backend) - def test_unicode_error_key_material(self): + def test_unicode_error_key_material(self, backend): with pytest.raises(TypeError): kdf = KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, CounterLocation.BeforeFixed, b'label', - b'context', None, backend=default_backend()) + b'context', None, backend=backend) kdf.derive(u'material') + + def test_buffer_protocol(self, backend): + kdf = KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 10, 4, 4, + CounterLocation.BeforeFixed, b'label', b'context', + None, backend=backend) + + key = kdf.derive(bytearray(b"material")) + assert key == b'\xb7\x01\x05\x98\xf5\x1a\x12L\xc7.' diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_kbkdf_vectors.py python-cryptography-2.6.1/tests/hazmat/primitives/test_kbkdf_vectors.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_kbkdf_vectors.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_kbkdf_vectors.py 2019-02-27 23:27:53.000000000 +0000 @@ -16,7 +16,7 @@ @pytest.mark.requires_backend_interface(interface=HMACBackend) class TestCounterKDFCounterMode(object): - test_HKDFSHA1 = generate_kbkdf_counter_mode_test( + test_kbkdfctr = generate_kbkdf_counter_mode_test( load_nist_kbkdf_vectors, os.path.join("KDF"), ["nist-800-108-KBKDF-CTR.txt"] diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_keywrap.py python-cryptography-2.6.1/tests/hazmat/primitives/test_keywrap.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_keywrap.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_keywrap.py 2019-02-27 23:27:53.000000000 +0000 @@ -108,9 +108,100 @@ def test_unwrap_invalid_wrapped_key_length(self, backend): # Keys to unwrap must be at least 24 bytes - with pytest.raises(ValueError): + with pytest.raises(keywrap.InvalidUnwrap): keywrap.aes_key_unwrap(b"sixteen_byte_key", b"\x00" * 16, backend) # Keys to unwrap must be a multiple of 8 bytes - with pytest.raises(ValueError): + with pytest.raises(keywrap.InvalidUnwrap): keywrap.aes_key_unwrap(b"sixteen_byte_key", b"\x00" * 27, backend) + + +@pytest.mark.supported( + only_if=lambda backend: backend.cipher_supported( + algorithms.AES(b"\x00" * 16), modes.ECB() + ), + skip_message="Does not support AES key wrap (RFC 5649) because AES-ECB" + " is unsupported", +) +@pytest.mark.requires_backend_interface(interface=CipherBackend) +class TestAESKeyWrapWithPadding(object): + @pytest.mark.parametrize( + "params", + _load_all_params( + os.path.join("keywrap", "kwtestvectors"), + ["KWP_AE_128.txt", "KWP_AE_192.txt", "KWP_AE_256.txt"], + load_nist_vectors + ) + ) + def test_wrap(self, backend, params): + wrapping_key = binascii.unhexlify(params["k"]) + key_to_wrap = binascii.unhexlify(params["p"]) + wrapped_key = keywrap.aes_key_wrap_with_padding( + wrapping_key, key_to_wrap, backend + ) + assert params["c"] == binascii.hexlify(wrapped_key) + + @pytest.mark.parametrize( + "params", + _load_all_params("keywrap", ["kwp_botan.txt"], load_nist_vectors) + ) + def test_wrap_additional_vectors(self, backend, params): + wrapping_key = binascii.unhexlify(params["key"]) + key_to_wrap = binascii.unhexlify(params["input"]) + wrapped_key = keywrap.aes_key_wrap_with_padding( + wrapping_key, key_to_wrap, backend + ) + assert wrapped_key == binascii.unhexlify(params["output"]) + + @pytest.mark.parametrize( + "params", + _load_all_params( + os.path.join("keywrap", "kwtestvectors"), + ["KWP_AD_128.txt", "KWP_AD_192.txt", "KWP_AD_256.txt"], + load_nist_vectors + ) + ) + def test_unwrap(self, backend, params): + wrapping_key = binascii.unhexlify(params["k"]) + wrapped_key = binascii.unhexlify(params["c"]) + if params.get("fail") is True: + with pytest.raises(keywrap.InvalidUnwrap): + keywrap.aes_key_unwrap_with_padding( + wrapping_key, wrapped_key, backend + ) + else: + unwrapped_key = keywrap.aes_key_unwrap_with_padding( + wrapping_key, wrapped_key, backend + ) + assert params["p"] == binascii.hexlify(unwrapped_key) + + @pytest.mark.parametrize( + "params", + _load_all_params("keywrap", ["kwp_botan.txt"], load_nist_vectors) + ) + def test_unwrap_additional_vectors(self, backend, params): + wrapping_key = binascii.unhexlify(params["key"]) + wrapped_key = binascii.unhexlify(params["output"]) + unwrapped_key = keywrap.aes_key_unwrap_with_padding( + wrapping_key, wrapped_key, backend + ) + assert unwrapped_key == binascii.unhexlify(params["input"]) + + def test_unwrap_invalid_wrapped_key_length(self, backend): + # Keys to unwrap must be at least 16 bytes + with pytest.raises( + keywrap.InvalidUnwrap, match='Must be at least 16 bytes' + ): + keywrap.aes_key_unwrap_with_padding( + b"sixteen_byte_key", b"\x00" * 15, backend + ) + + def test_wrap_invalid_key_length(self, backend): + with pytest.raises(ValueError, match='must be a valid AES key length'): + keywrap.aes_key_wrap_with_padding(b"badkey", b"\x00", backend) + + def test_unwrap_invalid_key_length(self, backend): + with pytest.raises(ValueError, match='must be a valid AES key length'): + keywrap.aes_key_unwrap_with_padding( + b"badkey", b"\x00" * 16, backend + ) diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_pbkdf2hmac.py python-cryptography-2.6.1/tests/hazmat/primitives/test_pbkdf2hmac.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_pbkdf2hmac.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_pbkdf2hmac.py 2019-02-27 23:27:53.000000000 +0000 @@ -57,6 +57,11 @@ with pytest.raises(TypeError): kdf.derive(u"unicode here") + def test_buffer_protocol(self, backend): + kdf = PBKDF2HMAC(hashes.SHA1(), 10, b"salt", 10, default_backend()) + data = bytearray(b"data") + assert kdf.derive(data) == b"\xe9n\xaa\x81\xbbt\xa4\xf6\x08\xce" + def test_invalid_backend(): pretend_backend = object() diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_pkcs12.py python-cryptography-2.6.1/tests/hazmat/primitives/test_pkcs12.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_pkcs12.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_pkcs12.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,123 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import os + +import pytest + +from cryptography import x509 +from cryptography.hazmat.backends.interfaces import DERSerializationBackend +from cryptography.hazmat.primitives.serialization import load_pem_private_key +from cryptography.hazmat.primitives.serialization.pkcs12 import ( + load_key_and_certificates +) + +from .utils import load_vectors_from_file + + +@pytest.mark.requires_backend_interface(interface=DERSerializationBackend) +class TestPKCS12(object): + @pytest.mark.parametrize( + ("filename", "password"), + [ + ("cert-key-aes256cbc.p12", b"cryptography"), + ("cert-none-key-none.p12", b"cryptography"), + ("cert-rc2-key-3des.p12", b"cryptography"), + ("no-password.p12", None), + ] + ) + def test_load_pkcs12_ec_keys(self, filename, password, backend): + cert = load_vectors_from_file( + os.path.join("x509", "custom", "ca", "ca.pem"), + lambda pemfile: x509.load_pem_x509_certificate( + pemfile.read(), backend + ), mode="rb" + ) + key = load_vectors_from_file( + os.path.join("x509", "custom", "ca", "ca_key.pem"), + lambda pemfile: load_pem_private_key( + pemfile.read(), None, backend + ), mode="rb" + ) + parsed_key, parsed_cert, parsed_more_certs = load_vectors_from_file( + os.path.join("pkcs12", filename), + lambda derfile: load_key_and_certificates( + derfile.read(), password, backend + ), mode="rb" + ) + assert parsed_cert == cert + assert parsed_key.private_numbers() == key.private_numbers() + assert parsed_more_certs == [] + + def test_load_pkcs12_cert_only(self, backend): + cert = load_vectors_from_file( + os.path.join("x509", "custom", "ca", "ca.pem"), + lambda pemfile: x509.load_pem_x509_certificate( + pemfile.read(), backend + ), mode="rb" + ) + parsed_key, parsed_cert, parsed_more_certs = load_vectors_from_file( + os.path.join("pkcs12", "cert-aes256cbc-no-key.p12"), + lambda data: load_key_and_certificates( + data.read(), b"cryptography", backend + ), + mode="rb" + ) + assert parsed_cert is None + assert parsed_key is None + assert parsed_more_certs == [cert] + + def test_load_pkcs12_key_only(self, backend): + key = load_vectors_from_file( + os.path.join("x509", "custom", "ca", "ca_key.pem"), + lambda pemfile: load_pem_private_key( + pemfile.read(), None, backend + ), mode="rb" + ) + parsed_key, parsed_cert, parsed_more_certs = load_vectors_from_file( + os.path.join("pkcs12", "no-cert-key-aes256cbc.p12"), + lambda data: load_key_and_certificates( + data.read(), b"cryptography", backend + ), + mode="rb" + ) + assert parsed_key.private_numbers() == key.private_numbers() + assert parsed_cert is None + assert parsed_more_certs == [] + + def test_non_bytes(self, backend): + with pytest.raises(TypeError): + load_key_and_certificates( + b"irrelevant", object(), backend + ) + + def test_not_a_pkcs12(self, backend): + with pytest.raises(ValueError): + load_key_and_certificates( + b"invalid", b"pass", backend + ) + + def test_invalid_password(self, backend): + with pytest.raises(ValueError): + load_vectors_from_file( + os.path.join("pkcs12", "cert-key-aes256cbc.p12"), + lambda derfile: load_key_and_certificates( + derfile.read(), b"invalid", backend + ), mode="rb" + ) + + def test_buffer_protocol(self, backend): + p12 = load_vectors_from_file( + os.path.join("pkcs12", "cert-key-aes256cbc.p12"), + lambda derfile: derfile.read(), mode="rb" + ) + p12buffer = bytearray(p12) + parsed_key, parsed_cert, parsed_more_certs = load_key_and_certificates( + p12buffer, bytearray(b"cryptography"), backend + ) + assert parsed_key is not None + assert parsed_cert is not None + assert parsed_more_certs == [] diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_rsa.py python-cryptography-2.6.1/tests/hazmat/primitives/test_rsa.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_rsa.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_rsa.py 2019-02-27 23:27:53.000000000 +0000 @@ -24,6 +24,7 @@ from cryptography.hazmat.primitives.asymmetric.rsa import ( RSAPrivateNumbers, RSAPublicNumbers ) +from cryptography.utils import CryptographyDeprecationWarning from .fixtures_rsa import ( RSA_KEY_1024, RSA_KEY_1025, RSA_KEY_1026, RSA_KEY_1027, RSA_KEY_1028, @@ -88,7 +89,7 @@ load_vectors_from_file( os.path.join( base_path, - "oaep-{0}-{1}.txt".format( + "oaep-{}-{}.txt".format( mgf1alg.name, oaepalg.name ) ), @@ -111,7 +112,7 @@ ) ): pytest.skip( - "Does not support {0} in MGF1 using PSS.".format(hash_alg.name) + "Does not support {} in MGF1 using PSS.".format(hash_alg.name) ) @@ -383,13 +384,11 @@ n=private["modulus"] ) ).private_key(backend) - signer = pytest.deprecated_call( - private_key.signer, + signature = private_key.sign( + binascii.unhexlify(example["message"]), padding.PKCS1v15(), hashes.SHA1() ) - signer.update(binascii.unhexlify(example["message"])) - signature = signer.finalize() assert binascii.hexlify(signature) == example["signature"] @pytest.mark.supported( @@ -427,29 +426,27 @@ e=public["public_exponent"], n=public["modulus"] ).public_key(backend) - signer = private_key.signer( + signature = private_key.sign( + binascii.unhexlify(example["message"]), padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), salt_length=padding.PSS.MAX_LENGTH ), hashes.SHA1() ) - signer.update(binascii.unhexlify(example["message"])) - signature = signer.finalize() assert len(signature) == math.ceil(private_key.key_size / 8.0) # PSS signatures contain randomness so we can't do an exact # signature check. Instead we'll verify that the signature created # successfully verifies. - verifier = public_key.verifier( + public_key.verify( signature, + binascii.unhexlify(example["message"]), padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), salt_length=padding.PSS.MAX_LENGTH ), hashes.SHA1(), ) - verifier.update(binascii.unhexlify(example["message"])) - verifier.verify() @pytest.mark.parametrize( "hash_alg", @@ -463,12 +460,9 @@ mgf=padding.MGF1(hash_alg), salt_length=padding.PSS.MAX_LENGTH ) - signer = private_key.signer(pss, hash_alg) - signer.update(b"testing signature") - signature = signer.finalize() - verifier = public_key.verifier(signature, pss, hash_alg) - verifier.update(b"testing signature") - verifier.verify() + msg = b"testing signature" + signature = private_key.sign(msg, pss, hash_alg) + public_key.verify(signature, msg, pss, hash_alg) @pytest.mark.supported( only_if=lambda backend: ( @@ -484,15 +478,14 @@ ) def test_pss_minimum_key_size_for_digest(self, backend): private_key = RSA_KEY_522.private_key(backend) - signer = private_key.signer( + private_key.sign( + b"no failure", padding.PSS( mgf=padding.MGF1(hashes.SHA1()), salt_length=padding.PSS.MAX_LENGTH ), hashes.SHA512() ) - signer.update(b"no failure") - signer.finalize() @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -510,7 +503,8 @@ def test_pss_signing_digest_too_large_for_key_size(self, backend): private_key = RSA_KEY_512.private_key(backend) with pytest.raises(ValueError): - private_key.signer( + private_key.sign( + b"msg", padding.PSS( mgf=padding.MGF1(hashes.SHA1()), salt_length=padding.PSS.MAX_LENGTH @@ -529,16 +523,15 @@ ) def test_pss_signing_salt_length_too_long(self, backend): private_key = RSA_KEY_512.private_key(backend) - signer = private_key.signer( - padding.PSS( - mgf=padding.MGF1(hashes.SHA1()), - salt_length=1000000 - ), - hashes.SHA1() - ) - signer.update(b"failure coming") with pytest.raises(ValueError): - signer.finalize() + private_key.sign( + b"failure coming", + padding.PSS( + mgf=padding.MGF1(hashes.SHA1()), + salt_length=1000000 + ), + hashes.SHA1() + ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -548,7 +541,8 @@ ) def test_use_after_finalize(self, backend): private_key = RSA_KEY_512.private_key(backend) - signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1()) + with pytest.warns(CryptographyDeprecationWarning): + signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1()) signer.update(b"sign me") signer.finalize() with pytest.raises(AlreadyFinalized): @@ -559,12 +553,12 @@ def test_unsupported_padding(self, backend): private_key = RSA_KEY_512.private_key(backend) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING): - private_key.signer(DummyAsymmetricPadding(), hashes.SHA1()) + private_key.sign(b"msg", DummyAsymmetricPadding(), hashes.SHA1()) def test_padding_incorrect_type(self, backend): private_key = RSA_KEY_512.private_key(backend) with pytest.raises(TypeError): - private_key.signer("notpadding", hashes.SHA1()) + private_key.sign(b"msg", "notpadding", hashes.SHA1()) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -575,7 +569,8 @@ def test_unsupported_pss_mgf(self, backend): private_key = RSA_KEY_512.private_key(backend) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_MGF): - private_key.signer( + private_key.sign( + b"msg", padding.PSS( mgf=DummyMGF(), salt_length=padding.PSS.MAX_LENGTH @@ -591,13 +586,12 @@ ) def test_pkcs1_digest_too_large_for_key_size(self, backend): private_key = RSA_KEY_599.private_key(backend) - signer = private_key.signer( - padding.PKCS1v15(), - hashes.SHA512() - ) - signer.update(b"failure coming") with pytest.raises(ValueError): - signer.finalize() + private_key.sign( + b"failure coming", + padding.PKCS1v15(), + hashes.SHA512() + ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -607,12 +601,11 @@ ) def test_pkcs1_minimum_key_size(self, backend): private_key = RSA_KEY_745.private_key(backend) - signer = private_key.signer( + private_key.sign( + b"no failure", padding.PKCS1v15(), hashes.SHA512() ) - signer.update(b"no failure") - signer.finalize() def test_sign(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -621,9 +614,7 @@ algorithm = hashes.SHA1() signature = private_key.sign(message, pkcs, algorithm) public_key = private_key.public_key() - verifier = public_key.verifier(signature, pkcs, algorithm) - verifier.update(message) - verifier.verify() + public_key.verify(signature, message, pkcs, algorithm) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -641,9 +632,25 @@ prehashed_alg = asym_utils.Prehashed(hashes.SHA1()) signature = private_key.sign(digest, pss, prehashed_alg) public_key = private_key.public_key() - verifier = public_key.verifier(signature, pss, hashes.SHA1()) - verifier.update(message) - verifier.verify() + public_key.verify(signature, message, pss, hashes.SHA1()) + + @pytest.mark.supported( + only_if=lambda backend: backend.hash_supported( + hashes.BLAKE2s(digest_size=32)), + skip_message="Does not support BLAKE2s", + ) + @pytest.mark.supported( + only_if=lambda backend: backend.rsa_padding_supported( + padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0) + ), + skip_message="Does not support PSS." + ) + def test_unsupported_hash(self, backend): + private_key = RSA_KEY_512.private_key(backend) + message = b"one little message" + pss = padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=0) + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_HASH): + private_key.sign(message, pss, hashes.BLAKE2s(32)) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -670,7 +677,8 @@ ) def test_prehashed_unsupported_in_signer_ctx(self, backend): private_key = RSA_KEY_512.private_key(backend) - with pytest.raises(TypeError): + with pytest.raises(TypeError), \ + pytest.warns(CryptographyDeprecationWarning): private_key.signer( padding.PKCS1v15(), asym_utils.Prehashed(hashes.SHA1()) @@ -684,7 +692,8 @@ ) def test_prehashed_unsupported_in_verifier_ctx(self, backend): public_key = RSA_KEY_512.private_key(backend).public_key() - with pytest.raises(TypeError): + with pytest.raises(TypeError), \ + pytest.warns(CryptographyDeprecationWarning): public_key.verifier( b"0" * 64, padding.PKCS1v15(), @@ -714,14 +723,12 @@ e=public["public_exponent"], n=public["modulus"] ).public_key(backend) - verifier = pytest.deprecated_call( - public_key.verifier, + public_key.verify( binascii.unhexlify(example["signature"]), + binascii.unhexlify(example["message"]), padding.PKCS1v15(), hashes.SHA1() ) - verifier.update(binascii.unhexlify(example["message"])) - verifier.verify() @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -732,17 +739,51 @@ def test_invalid_pkcs1v15_signature_wrong_data(self, backend): private_key = RSA_KEY_512.private_key(backend) public_key = private_key.public_key() - signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1()) - signer.update(b"sign me") - signature = signer.finalize() - verifier = public_key.verifier( - signature, - padding.PKCS1v15(), - hashes.SHA1() + signature = private_key.sign( + b"sign me", padding.PKCS1v15(), hashes.SHA1() ) - verifier.update(b"incorrect data") with pytest.raises(InvalidSignature): - verifier.verify() + public_key.verify( + signature, + b"incorrect data", + padding.PKCS1v15(), + hashes.SHA1() + ) + + def test_invalid_signature_sequence_removed(self, backend): + """ + This test comes from wycheproof + """ + key_der = binascii.unhexlify( + b"30820122300d06092a864886f70d01010105000382010f003082010a02820101" + b"00a2b451a07d0aa5f96e455671513550514a8a5b462ebef717094fa1fee82224" + b"e637f9746d3f7cafd31878d80325b6ef5a1700f65903b469429e89d6eac88450" + b"97b5ab393189db92512ed8a7711a1253facd20f79c15e8247f3d3e42e46e48c9" + b"8e254a2fe9765313a03eff8f17e1a029397a1fa26a8dce26f490ed81299615d9" + b"814c22da610428e09c7d9658594266f5c021d0fceca08d945a12be82de4d1ece" + b"6b4c03145b5d3495d4ed5411eb878daf05fd7afc3e09ada0f1126422f590975a" + b"1969816f48698bcbba1b4d9cae79d460d8f9f85e7975005d9bc22c4e5ac0f7c1" + b"a45d12569a62807d3b9a02e5a530e773066f453d1f5b4c2e9cf7820283f742b9" + b"d50203010001" + ) + sig = binascii.unhexlify( + b"498209f59a0679a1f926eccf3056da2cba553d7ab3064e7c41ad1d739f038249" + b"f02f5ad12ee246073d101bc3cdb563e8b6be61562056422b7e6c16ad53deb12a" + b"f5de744197753a35859833f41bb59c6597f3980132b7478fd0b95fd27dfad64a" + b"20fd5c25312bbd41a85286cd2a83c8df5efa0779158d01b0747ff165b055eb28" + b"80ea27095700a295593196d8c5922cf6aa9d7e29b5056db5ded5eb20aeb31b89" + b"42e26b15a5188a4934cd7e39cfe379a197f49a204343a493452deebca436ee61" + b"4f4daf989e355544489f7e69ffa8ccc6a1e81cf0ab33c3e6d7591091485a6a31" + b"bda3b33946490057b9a3003d3fd9daf7c4778b43fd46144d945d815f12628ff4" + ) + public_key = serialization.load_der_public_key(key_der, backend) + with pytest.raises(InvalidSignature): + public_key.verify( + sig, + binascii.unhexlify(b"313233343030"), + padding.PKCS1v15(), + hashes.SHA256() + ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -754,17 +795,12 @@ private_key = RSA_KEY_512.private_key(backend) private_key2 = RSA_KEY_512_ALT.private_key(backend) public_key = private_key2.public_key() - signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1()) - signer.update(b"sign me") - signature = signer.finalize() - verifier = public_key.verifier( - signature, - padding.PKCS1v15(), - hashes.SHA1() - ) - verifier.update(b"sign me") + msg = b"sign me" + signature = private_key.sign(msg, padding.PKCS1v15(), hashes.SHA1()) with pytest.raises(InvalidSignature): - verifier.verify() + public_key.verify( + signature, msg, padding.PKCS1v15(), hashes.SHA1() + ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -789,16 +825,15 @@ e=public["public_exponent"], n=public["modulus"] ).public_key(backend) - verifier = public_key.verifier( + public_key.verify( binascii.unhexlify(example["signature"]), + binascii.unhexlify(example["message"]), padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), salt_length=20 ), hashes.SHA1() ) - verifier.update(binascii.unhexlify(example["message"])) - verifier.verify() @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -822,17 +857,16 @@ b"0e68c3649df91c5bc3665f96e157efa75b71934aaa514d91e94ca8418d100f45" b"6f05288e58525f99666bab052adcffdf7186eb40f583bd38d98c97d3d524808b" ) - verifier = public_key.verifier( - signature, - padding.PSS( - mgf=padding.MGF1(algorithm=hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH - ), - hashes.SHA1() - ) - verifier.update(b"incorrect data") with pytest.raises(InvalidSignature): - verifier.verify() + public_key.verify( + signature, + b"incorrect data", + padding.PSS( + mgf=padding.MGF1(algorithm=hashes.SHA1()), + salt_length=padding.PSS.MAX_LENGTH + ), + hashes.SHA1() + ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -858,17 +892,16 @@ ), e=65537 ).public_key(backend) - verifier = public_key.verifier( - signature, - padding.PSS( - mgf=padding.MGF1(algorithm=hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH - ), - hashes.SHA1() - ) - verifier.update(b"sign me") with pytest.raises(InvalidSignature): - verifier.verify() + public_key.verify( + signature, + b"sign me", + padding.PSS( + mgf=padding.MGF1(algorithm=hashes.SHA1()), + salt_length=padding.PSS.MAX_LENGTH + ), + hashes.SHA1() + ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -894,17 +927,16 @@ ), e=65537 ).public_key(backend) - verifier = public_key.verifier( - signature, - padding.PSS( - mgf=padding.MGF1(algorithm=hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH - ), - hashes.SHA1() - ) - verifier.update(b"sign me") with pytest.raises(InvalidSignature): - verifier.verify() + public_key.verify( + signature, + b"sign me", + padding.PSS( + mgf=padding.MGF1(algorithm=hashes.SHA1()), + salt_length=padding.PSS.MAX_LENGTH + ), + hashes.SHA1() + ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -915,15 +947,16 @@ def test_use_after_finalize(self, backend): private_key = RSA_KEY_512.private_key(backend) public_key = private_key.public_key() - signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1()) - signer.update(b"sign me") - signature = signer.finalize() - - verifier = public_key.verifier( - signature, - padding.PKCS1v15(), - hashes.SHA1() + signature = private_key.sign( + b"sign me", padding.PKCS1v15(), hashes.SHA1() ) + + with pytest.warns(CryptographyDeprecationWarning): + verifier = public_key.verifier( + signature, + padding.PKCS1v15(), + hashes.SHA1() + ) verifier.update(b"sign me") verifier.verify() with pytest.raises(AlreadyFinalized): @@ -935,8 +968,8 @@ private_key = RSA_KEY_512.private_key(backend) public_key = private_key.public_key() with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING): - public_key.verifier( - b"sig", DummyAsymmetricPadding(), hashes.SHA1() + public_key.verify( + b"sig", b"msg", DummyAsymmetricPadding(), hashes.SHA1() ) @pytest.mark.supported( @@ -949,7 +982,8 @@ public_key = RSA_KEY_512.public_numbers.public_key(backend) signature = 1234 - with pytest.raises(TypeError): + with pytest.raises(TypeError), \ + pytest.warns(CryptographyDeprecationWarning): public_key.verifier( signature, padding.PKCS1v15(), @@ -960,7 +994,7 @@ private_key = RSA_KEY_512.private_key(backend) public_key = private_key.public_key() with pytest.raises(TypeError): - public_key.verifier(b"sig", "notpadding", hashes.SHA1()) + public_key.verify(b"sig", b"msg", "notpadding", hashes.SHA1()) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -972,8 +1006,9 @@ private_key = RSA_KEY_512.private_key(backend) public_key = private_key.public_key() with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_MGF): - public_key.verifier( + public_key.verify( b"sig", + b"msg", padding.PSS( mgf=DummyMGF(), salt_length=padding.PSS.MAX_LENGTH @@ -1002,8 +1037,9 @@ ) public_key = private_key.public_key() with pytest.raises(ValueError): - public_key.verifier( + public_key.verify( signature, + b"msg doesn't matter", padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), salt_length=padding.PSS.MAX_LENGTH @@ -1033,28 +1069,25 @@ ), e=65537 ).public_key(backend) - verifier = public_key.verifier( - signature, - padding.PSS( - mgf=padding.MGF1( - algorithm=hashes.SHA1(), - ), - salt_length=1000000 - ), - hashes.SHA1() - ) - verifier.update(b"sign me") with pytest.raises(InvalidSignature): - verifier.verify() + public_key.verify( + signature, + b"sign me", + padding.PSS( + mgf=padding.MGF1( + algorithm=hashes.SHA1(), + ), + salt_length=1000000 + ), + hashes.SHA1() + ) def test_verify(self, backend): private_key = RSA_KEY_512.private_key(backend) message = b"one little message" pkcs = padding.PKCS1v15() algorithm = hashes.SHA1() - signer = private_key.signer(pkcs, algorithm) - signer.update(message) - signature = signer.finalize() + signature = private_key.sign(message, pkcs, algorithm) public_key = private_key.public_key() public_key.verify(signature, message, pkcs, algorithm) @@ -1820,304 +1853,81 @@ with pytest.raises(TypeError): rsa.RSAPublicNumbers(e=1, n=None) - def test_private_numbers_invalid_types(self): - public_numbers = rsa.RSAPublicNumbers(e=1, n=15) - - with pytest.raises(TypeError): - rsa.RSAPrivateNumbers( - p=None, - q=5, - d=1, - dmp1=1, - dmq1=1, - iqmp=2, - public_numbers=public_numbers - ) - - with pytest.raises(TypeError): - rsa.RSAPrivateNumbers( - p=3, - q=None, - d=1, - dmp1=1, - dmq1=1, - iqmp=2, - public_numbers=public_numbers - ) - - with pytest.raises(TypeError): - rsa.RSAPrivateNumbers( - p=3, - q=5, - d=None, - dmp1=1, - dmq1=1, - iqmp=2, - public_numbers=public_numbers - ) - - with pytest.raises(TypeError): - rsa.RSAPrivateNumbers( - p=3, - q=5, - d=1, - dmp1=None, - dmq1=1, - iqmp=2, - public_numbers=public_numbers - ) - - with pytest.raises(TypeError): - rsa.RSAPrivateNumbers( - p=3, - q=5, - d=1, - dmp1=1, - dmq1=None, - iqmp=2, - public_numbers=public_numbers - ) - + @pytest.mark.parametrize( + ("p", "q", "d", "dmp1", "dmq1", "iqmp", "public_numbers"), + [ + (None, 5, 1, 1, 1, 2, rsa.RSAPublicNumbers(e=1, n=15)), + (3, None, 1, 1, 1, 2, rsa.RSAPublicNumbers(e=1, n=15)), + (3, 5, None, 1, 1, 2, rsa.RSAPublicNumbers(e=1, n=15)), + (3, 5, 1, None, 1, 2, rsa.RSAPublicNumbers(e=1, n=15)), + (3, 5, 1, 1, None, 2, rsa.RSAPublicNumbers(e=1, n=15)), + (3, 5, 1, 1, 1, None, rsa.RSAPublicNumbers(e=1, n=15)), + (3, 5, 1, 1, 1, 2, None), + ] + ) + def test_private_numbers_invalid_types(self, p, q, d, dmp1, dmq1, iqmp, + public_numbers): with pytest.raises(TypeError): rsa.RSAPrivateNumbers( - p=3, - q=5, - d=1, - dmp1=1, - dmq1=1, - iqmp=None, + p=p, q=q, + d=d, + dmp1=dmp1, + dmq1=dmq1, + iqmp=iqmp, public_numbers=public_numbers ) - with pytest.raises(TypeError): - rsa.RSAPrivateNumbers( - p=3, - q=5, - d=1, - dmp1=1, - dmq1=1, - iqmp=2, - public_numbers=None - ) - - def test_invalid_public_numbers_argument_values(self, backend): + @pytest.mark.parametrize( + ("e", "n"), + [ + (7, 2), # modulus < 3 + (1, 15), # public_exponent < 3 + (17, 15), # public_exponent > modulus + (14, 15), # public_exponent not odd + ] + ) + def test_invalid_public_numbers_argument_values(self, e, n, backend): # Start with public_exponent=7, modulus=15. Then change one value at a # time to test the bounds. - # Test a modulus < 3. - - with pytest.raises(ValueError): - rsa.RSAPublicNumbers(e=7, n=2).public_key(backend) - - # Test a public_exponent < 3 - with pytest.raises(ValueError): - rsa.RSAPublicNumbers(e=1, n=15).public_key(backend) - - # Test a public_exponent > modulus - with pytest.raises(ValueError): - rsa.RSAPublicNumbers(e=17, n=15).public_key(backend) - - # Test a public_exponent that is not odd. with pytest.raises(ValueError): - rsa.RSAPublicNumbers(e=14, n=15).public_key(backend) + rsa.RSAPublicNumbers(e=e, n=n).public_key(backend) - def test_invalid_private_numbers_argument_values(self, backend): + @pytest.mark.parametrize( + ("p", "q", "d", "dmp1", "dmq1", "iqmp", "e", "n"), + [ + (3, 11, 3, 1, 3, 2, 7, 2), # modulus < 3 + (3, 11, 3, 1, 3, 2, 7, 35), # modulus != p * q + (37, 11, 3, 1, 3, 2, 7, 33), # p > modulus + (3, 37, 3, 1, 3, 2, 7, 33), # q > modulus + (3, 11, 3, 35, 3, 2, 7, 33), # dmp1 > modulus + (3, 11, 3, 1, 35, 2, 7, 33), # dmq1 > modulus + (3, 11, 3, 1, 3, 35, 7, 33), # iqmp > modulus + (3, 11, 37, 1, 3, 2, 7, 33), # d > modulus + (3, 11, 3, 1, 3, 2, 1, 33), # public_exponent < 3 + (3, 11, 3, 1, 3, 35, 65537, 33), # public_exponent > modulus + (3, 11, 3, 1, 3, 2, 6, 33), # public_exponent is not odd + (3, 11, 3, 2, 3, 2, 7, 33), # dmp1 is not odd + (3, 11, 3, 1, 4, 2, 7, 33), # dmq1 is not odd + ] + ) + def test_invalid_private_numbers_argument_values(self, p, q, d, dmp1, dmq1, + iqmp, e, n, backend): # Start with p=3, q=11, private_exponent=3, public_exponent=7, # modulus=33, dmp1=1, dmq1=3, iqmp=2. Then change one value at # a time to test the bounds. - # Test a modulus < 3. - with pytest.raises(ValueError): - rsa.RSAPrivateNumbers( - p=3, - q=11, - d=3, - dmp1=1, - dmq1=3, - iqmp=2, - public_numbers=rsa.RSAPublicNumbers( - e=7, - n=2 - ) - ).private_key(backend) - - # Test a modulus != p * q. - with pytest.raises(ValueError): - rsa.RSAPrivateNumbers( - p=3, - q=11, - d=3, - dmp1=1, - dmq1=3, - iqmp=2, - public_numbers=rsa.RSAPublicNumbers( - e=7, - n=35 - ) - ).private_key(backend) - - # Test a p > modulus. - with pytest.raises(ValueError): - rsa.RSAPrivateNumbers( - p=37, - q=11, - d=3, - dmp1=1, - dmq1=3, - iqmp=2, - public_numbers=rsa.RSAPublicNumbers( - e=7, - n=33 - ) - ).private_key(backend) - - # Test a q > modulus. - with pytest.raises(ValueError): - rsa.RSAPrivateNumbers( - p=3, - q=37, - d=3, - dmp1=1, - dmq1=3, - iqmp=2, - public_numbers=rsa.RSAPublicNumbers( - e=7, - n=33 - ) - ).private_key(backend) - - # Test a dmp1 > modulus. - with pytest.raises(ValueError): - rsa.RSAPrivateNumbers( - p=3, - q=11, - d=3, - dmp1=35, - dmq1=3, - iqmp=2, - public_numbers=rsa.RSAPublicNumbers( - e=7, - n=33 - ) - ).private_key(backend) - - # Test a dmq1 > modulus. - with pytest.raises(ValueError): - rsa.RSAPrivateNumbers( - p=3, - q=11, - d=3, - dmp1=1, - dmq1=35, - iqmp=2, - public_numbers=rsa.RSAPublicNumbers( - e=7, - n=33 - ) - ).private_key(backend) - - # Test an iqmp > modulus. - with pytest.raises(ValueError): - rsa.RSAPrivateNumbers( - p=3, - q=11, - d=3, - dmp1=1, - dmq1=3, - iqmp=35, - public_numbers=rsa.RSAPublicNumbers( - e=7, - n=33 - ) - ).private_key(backend) - - # Test a private_exponent > modulus - with pytest.raises(ValueError): - rsa.RSAPrivateNumbers( - p=3, - q=11, - d=37, - dmp1=1, - dmq1=3, - iqmp=2, - public_numbers=rsa.RSAPublicNumbers( - e=7, - n=33 - ) - ).private_key(backend) - - # Test a public_exponent < 3 - with pytest.raises(ValueError): - rsa.RSAPrivateNumbers( - p=3, - q=11, - d=3, - dmp1=1, - dmq1=3, - iqmp=2, - public_numbers=rsa.RSAPublicNumbers( - e=1, - n=33 - ) - ).private_key(backend) - - # Test a public_exponent > modulus with pytest.raises(ValueError): rsa.RSAPrivateNumbers( - p=3, - q=11, - d=3, - dmp1=1, - dmq1=3, - iqmp=35, + p=p, + q=q, + d=d, + dmp1=dmp1, + dmq1=dmq1, + iqmp=iqmp, public_numbers=rsa.RSAPublicNumbers( - e=65537, - n=33 - ) - ).private_key(backend) - - # Test a public_exponent that is not odd. - with pytest.raises(ValueError): - rsa.RSAPrivateNumbers( - p=3, - q=11, - d=3, - dmp1=1, - dmq1=3, - iqmp=2, - public_numbers=rsa.RSAPublicNumbers( - e=6, - n=33 - ) - ).private_key(backend) - - # Test a dmp1 that is not odd. - with pytest.raises(ValueError): - rsa.RSAPrivateNumbers( - p=3, - q=11, - d=3, - dmp1=2, - dmq1=3, - iqmp=2, - public_numbers=rsa.RSAPublicNumbers( - e=7, - n=33 - ) - ).private_key(backend) - - # Test a dmq1 that is not odd. - with pytest.raises(ValueError): - rsa.RSAPrivateNumbers( - p=3, - q=11, - d=3, - dmp1=1, - dmq1=4, - iqmp=2, - public_numbers=rsa.RSAPublicNumbers( - e=7, - n=33 + e=e, + n=n ) ).private_key(backend) @@ -2252,6 +2062,20 @@ assert loaded_priv_num == priv_num @pytest.mark.parametrize( + ("encoding", "fmt"), + [ + (serialization.Encoding.Raw, serialization.PrivateFormat.PKCS8), + (serialization.Encoding.DER, serialization.PrivateFormat.Raw), + (serialization.Encoding.Raw, serialization.PrivateFormat.Raw), + (serialization.Encoding.X962, serialization.PrivateFormat.PKCS8), + ] + ) + def test_private_bytes_rejects_invalid(self, encoding, fmt, backend): + key = RSA_KEY_2048.private_key(backend) + with pytest.raises(ValueError): + key.private_bytes(encoding, fmt, serialization.NoEncryption()) + + @pytest.mark.parametrize( ("fmt", "password"), [ [serialization.PrivateFormat.PKCS8, b"s"], @@ -2476,3 +2300,30 @@ key = RSA_KEY_2048.private_key(backend).public_key() with pytest.raises(TypeError): key.public_bytes(serialization.Encoding.PEM, "invalidformat") + + @pytest.mark.parametrize( + ("encoding", "fmt"), + [ + ( + serialization.Encoding.Raw, + serialization.PublicFormat.SubjectPublicKeyInfo + ), + (serialization.Encoding.Raw, serialization.PublicFormat.PKCS1), + ] + list(itertools.product( + [ + serialization.Encoding.Raw, + serialization.Encoding.X962, + serialization.Encoding.PEM, + serialization.Encoding.DER + ], + [ + serialization.PublicFormat.Raw, + serialization.PublicFormat.UncompressedPoint, + serialization.PublicFormat.CompressedPoint + ] + )) + ) + def test_public_bytes_rejects_invalid(self, encoding, fmt, backend): + key = RSA_KEY_2048.private_key(backend).public_key() + with pytest.raises(ValueError): + key.public_bytes(encoding, fmt) diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_scrypt.py python-cryptography-2.6.1/tests/hazmat/primitives/test_scrypt.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_scrypt.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_scrypt.py 2019-02-27 23:27:53.000000000 +0000 @@ -80,6 +80,20 @@ Scrypt(salt, length, work_factor, block_size, parallelization_factor, backend) + def test_scrypt_malloc_failure(self, backend): + password = b"NaCl" + work_factor = 1024 ** 3 + block_size = 589824 + parallelization_factor = 16 + length = 64 + salt = b"NaCl" + + scrypt = Scrypt(salt, length, work_factor, block_size, + parallelization_factor, backend) + + with pytest.raises(MemoryError): + scrypt.derive(password) + def test_password_not_bytes(self, backend): password = 1 work_factor = 1024 @@ -94,6 +108,19 @@ with pytest.raises(TypeError): scrypt.derive(password) + def test_buffer_protocol(self, backend): + password = bytearray(b"password") + work_factor = 256 + block_size = 8 + parallelization_factor = 16 + length = 10 + salt = b"NaCl" + + scrypt = Scrypt(salt, length, work_factor, block_size, + parallelization_factor, backend) + + assert scrypt.derive(password) == b'\xf4\x92\x86\xb2\x06\x0c\x848W\x87' + @pytest.mark.parametrize("params", vectors) def test_verify(self, backend, params): _skip_if_memory_limited(_MEM_LIMIT, params) diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_seed.py python-cryptography-2.6.1/tests/hazmat/primitives/test_seed.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_seed.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_seed.py 2019-02-27 23:27:53.000000000 +0000 @@ -24,7 +24,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSEEDModeECB(object): - test_ECB = generate_encrypt_test( + test_ecb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "SEED"), ["rfc-4269.txt"], @@ -41,7 +41,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSEEDModeCBC(object): - test_CBC = generate_encrypt_test( + test_cbc = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "SEED"), ["rfc-4196.txt"], @@ -58,7 +58,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSEEDModeOFB(object): - test_OFB = generate_encrypt_test( + test_ofb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "SEED"), ["seed-ofb.txt"], @@ -75,7 +75,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSEEDModeCFB(object): - test_CFB = generate_encrypt_test( + test_cfb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "SEED"), ["seed-cfb.txt"], diff -Nru python-cryptography-2.1.4/tests/hazmat/primitives/test_serialization.py python-cryptography-2.6.1/tests/hazmat/primitives/test_serialization.py --- python-cryptography-2.1.4/tests/hazmat/primitives/test_serialization.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/hazmat/primitives/test_serialization.py 2019-02-27 23:27:53.000000000 +0000 @@ -16,9 +16,11 @@ DERSerializationBackend, DSABackend, EllipticCurveBackend, PEMSerializationBackend, RSABackend ) -from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa +from cryptography.hazmat.primitives.asymmetric import dsa, ec, ed25519, rsa from cryptography.hazmat.primitives.serialization import ( - BestAvailableEncryption, load_der_parameters, load_der_private_key, + BestAvailableEncryption, Encoding, NoEncryption, + PrivateFormat, PublicFormat, + load_der_parameters, load_der_private_key, load_der_public_key, load_pem_parameters, load_pem_private_key, load_pem_public_key, load_ssh_public_key ) @@ -32,6 +34,55 @@ from ...utils import raises_unsupported_algorithm +class TestBufferProtocolSerialization(object): + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.parametrize( + ("key_path", "password"), + [ + (["DER_Serialization", "enc-rsa-pkcs8.der"], bytearray(b"foobar")), + (["DER_Serialization", "enc2-rsa-pkcs8.der"], bytearray(b"baz")), + (["DER_Serialization", "unenc-rsa-pkcs8.der"], None), + (["DER_Serialization", "testrsa.der"], None), + ] + ) + def test_load_der_rsa_private_key(self, key_path, password, backend): + data = load_vectors_from_file( + os.path.join("asymmetric", *key_path), + lambda derfile: derfile.read(), mode="rb" + ) + key = load_der_private_key(bytearray(data), password, backend) + assert key + assert isinstance(key, rsa.RSAPrivateKey) + _check_rsa_private_numbers(key.private_numbers()) + + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.parametrize( + ("key_path", "password"), + [ + ( + ["PEM_Serialization", "rsa_private_key.pem"], + bytearray(b"123456") + ), + (["PKCS8", "unenc-rsa-pkcs8.pem"], None), + (["PKCS8", "enc-rsa-pkcs8.pem"], bytearray(b"foobar")), + (["PKCS8", "enc2-rsa-pkcs8.pem"], bytearray(b"baz")), + ( + ["Traditional_OpenSSL_Serialization", "key1.pem"], + bytearray(b"123456") + ), + ] + ) + def test_load_pem_rsa_private_key(self, key_path, password, backend): + data = load_vectors_from_file( + os.path.join("asymmetric", *key_path), + lambda pemfile: pemfile.read(), mode="rb" + ) + key = load_pem_private_key(bytearray(data), password, backend) + assert key + assert isinstance(key, rsa.RSAPrivateKey) + _check_rsa_private_numbers(key.private_numbers()) + + @pytest.mark.requires_backend_interface(interface=DERSerializationBackend) class TestDERSerialization(object): @pytest.mark.requires_backend_interface(interface=RSABackend) @@ -1223,6 +1274,42 @@ load_ssh_public_key(ssh_key, backend) +@pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support" +) +class TestEd25519SSHSerialization(object): + def test_load_ssh_public_key(self, backend): + ssh_key = ( + b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG2fgpmpYO61qeAxGd0wgRaN/E4" + b"GR+xWvBmvxjxrB1vG user@chiron.local" + ) + key = load_ssh_public_key(ssh_key, backend) + assert isinstance(key, ed25519.Ed25519PublicKey) + assert key.public_bytes( + Encoding.Raw, PublicFormat.Raw + ) == ( + b"m\x9f\x82\x99\xa9`\xee\xb5\xa9\xe01\x19\xdd0\x81\x16\x8d\xfc" + b"N\x06G\xecV\xbc\x19\xaf\xc6 0 else b"" - elif line.startswith("MD"): + elif line.startswith("MD") or line.startswith("Output"): md = line.split(" = ")[1] # after MD is found the Msg+MD (+ potential key) tuple is complete if key is not None: @@ -353,43 +353,28 @@ Loads data out of the FIPS DSA KeyPair vector files. """ vectors = [] - # When reading_key_data is set to True it tells the loader to continue - # constructing dictionaries. We set reading_key_data to False during the - # blocks of the vectors of N=224 because we don't support it. - reading_key_data = True for line in vector_data: line = line.strip() - if not line or line.startswith("#"): - continue - elif line.startswith("[mod = L=1024"): - continue - elif line.startswith("[mod = L=2048, N=224"): - reading_key_data = False - continue - elif line.startswith("[mod = L=2048, N=256"): - reading_key_data = True + if not line or line.startswith("#") or line.startswith("[mod"): continue - elif line.startswith("[mod = L=3072"): - continue - - if reading_key_data: - if line.startswith("P"): - vectors.append({'p': int(line.split("=")[1], 16)}) - elif line.startswith("Q"): - vectors[-1]['q'] = int(line.split("=")[1], 16) - elif line.startswith("G"): - vectors[-1]['g'] = int(line.split("=")[1], 16) - elif line.startswith("X") and 'x' not in vectors[-1]: - vectors[-1]['x'] = int(line.split("=")[1], 16) - elif line.startswith("X") and 'x' in vectors[-1]: - vectors.append({'p': vectors[-1]['p'], - 'q': vectors[-1]['q'], - 'g': vectors[-1]['g'], - 'x': int(line.split("=")[1], 16) - }) - elif line.startswith("Y"): - vectors[-1]['y'] = int(line.split("=")[1], 16) + + if line.startswith("P"): + vectors.append({'p': int(line.split("=")[1], 16)}) + elif line.startswith("Q"): + vectors[-1]['q'] = int(line.split("=")[1], 16) + elif line.startswith("G"): + vectors[-1]['g'] = int(line.split("=")[1], 16) + elif line.startswith("X") and 'x' not in vectors[-1]: + vectors[-1]['x'] = int(line.split("=")[1], 16) + elif line.startswith("X") and 'x' in vectors[-1]: + vectors.append({'p': vectors[-1]['p'], + 'q': vectors[-1]['q'], + 'g': vectors[-1]['g'], + 'x': int(line.split("=")[1], 16) + }) + elif line.startswith("Y"): + vectors[-1]['y'] = int(line.split("=")[1], 16) return vectors @@ -402,10 +387,6 @@ sha_regex = re.compile( r"\[mod = L=...., N=..., SHA-(?P1|224|256|384|512)\]" ) - # When reading_key_data is set to True it tells the loader to continue - # constructing dictionaries. We set reading_key_data to False during the - # blocks of the vectors of N=224 because we don't support it. - reading_key_data = True for line in vector_data: line = line.strip() @@ -415,16 +396,9 @@ sha_match = sha_regex.match(line) if sha_match: - digest_algorithm = "SHA-{0}".format(sha_match.group("sha")) - - if line.startswith("[mod = L=2048, N=224"): - reading_key_data = False - continue - elif line.startswith("[mod = L=2048, N=256"): - reading_key_data = True - continue + digest_algorithm = "SHA-{}".format(sha_match.group("sha")) - if not reading_key_data or line.startswith("[mod"): + if line.startswith("[mod"): continue name, value = [c.strip() for c in line.split("=")] @@ -461,7 +435,7 @@ return vectors -# http://tools.ietf.org/html/rfc4492#appendix-A +# https://tools.ietf.org/html/rfc4492#appendix-A _ECDSA_CURVE_NAMES = { "P-192": "secp192r1", "P-224": "secp224r1", @@ -537,7 +511,7 @@ curve_match = curve_rx.match(line) if curve_match: curve_name = _ECDSA_CURVE_NAMES[curve_match.group("curve")] - digest_name = "SHA-{0}".format(curve_match.group("sha")) + digest_name = "SHA-{}".format(curve_match.group("sha")) elif line.startswith("Msg = "): if data is not None: @@ -910,3 +884,46 @@ test_data[name.lower()] = value.encode("ascii") return data + + +class WycheproofTest(object): + def __init__(self, testgroup, testcase): + self.testgroup = testgroup + self.testcase = testcase + + def __repr__(self): + return "".format( + self.testgroup, self.testcase, self.testcase["tcId"], + ) + + @property + def valid(self): + return self.testcase["result"] == "valid" + + @property + def acceptable(self): + return self.testcase["result"] == "acceptable" + + @property + def invalid(self): + return self.testcase["result"] == "invalid" + + def has_flag(self, flag): + return flag in self.testcase["flags"] + + +def skip_if_wycheproof_none(wycheproof): + # This is factored into its own function so we can easily test both + # branches + if wycheproof is None: + pytest.skip("--wycheproof-root not provided") + + +def load_wycheproof_tests(wycheproof, test_file): + path = os.path.join(wycheproof, "testvectors", test_file) + with open(path) as f: + data = json.load(f) + for group in data["testGroups"]: + cases = group.pop("tests") + for c in cases: + yield WycheproofTest(group, c) diff -Nru python-cryptography-2.1.4/tests/wycheproof/test_aes.py python-cryptography-2.6.1/tests/wycheproof/test_aes.py --- python-cryptography-2.1.4/tests/wycheproof/test_aes.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/tests/wycheproof/test_aes.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,144 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +import pytest + +from cryptography.exceptions import InvalidTag +from cryptography.hazmat.backends.interfaces import CipherBackend +from cryptography.hazmat.primitives import padding +from cryptography.hazmat.primitives.ciphers import ( + Cipher, algorithms, modes +) +from cryptography.hazmat.primitives.ciphers.aead import AESCCM, AESGCM + +from ..hazmat.primitives.test_aead import _aead_supported + + +@pytest.mark.requires_backend_interface(interface=CipherBackend) +@pytest.mark.wycheproof_tests("aes_cbc_pkcs5_test.json") +def test_aes_cbc_pkcs5(backend, wycheproof): + key = binascii.unhexlify(wycheproof.testcase["key"]) + iv = binascii.unhexlify(wycheproof.testcase["iv"]) + msg = binascii.unhexlify(wycheproof.testcase["msg"]) + ct = binascii.unhexlify(wycheproof.testcase["ct"]) + + padder = padding.PKCS7(128).padder() + + cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend) + enc = cipher.encryptor() + computed_ct = enc.update( + padder.update(msg) + padder.finalize()) + enc.finalize() + dec = cipher.decryptor() + padded_msg = dec.update(ct) + dec.finalize() + unpadder = padding.PKCS7(128).unpadder() + if wycheproof.valid or wycheproof.acceptable: + assert computed_ct == ct + computed_msg = unpadder.update(padded_msg) + unpadder.finalize() + assert computed_msg == msg + else: + assert computed_ct != ct + with pytest.raises(ValueError): + unpadder.update(padded_msg) + unpadder.finalize() + + +@pytest.mark.requires_backend_interface(interface=CipherBackend) +@pytest.mark.wycheproof_tests("aes_gcm_test.json") +def test_aes_gcm(backend, wycheproof): + key = binascii.unhexlify(wycheproof.testcase["key"]) + iv = binascii.unhexlify(wycheproof.testcase["iv"]) + aad = binascii.unhexlify(wycheproof.testcase["aad"]) + msg = binascii.unhexlify(wycheproof.testcase["msg"]) + ct = binascii.unhexlify(wycheproof.testcase["ct"]) + tag = binascii.unhexlify(wycheproof.testcase["tag"]) + if wycheproof.valid or wycheproof.acceptable: + enc = Cipher(algorithms.AES(key), modes.GCM(iv), backend).encryptor() + enc.authenticate_additional_data(aad) + computed_ct = enc.update(msg) + enc.finalize() + computed_tag = enc.tag + assert computed_ct == ct + assert computed_tag == tag + dec = Cipher( + algorithms.AES(key), + modes.GCM(iv, tag, min_tag_length=len(tag)), + backend + ).decryptor() + dec.authenticate_additional_data(aad) + computed_msg = dec.update(ct) + dec.finalize() + assert computed_msg == msg + elif len(iv) == 0: + with pytest.raises(ValueError): + Cipher(algorithms.AES(key), modes.GCM(iv), backend) + else: + dec = Cipher( + algorithms.AES(key), + modes.GCM(iv, tag, min_tag_length=len(tag)), + backend + ).decryptor() + dec.authenticate_additional_data(aad) + dec.update(ct) + with pytest.raises(InvalidTag): + dec.finalize() + + +@pytest.mark.requires_backend_interface(interface=CipherBackend) +@pytest.mark.wycheproof_tests("aes_gcm_test.json") +def test_aes_gcm_aead_api(backend, wycheproof): + key = binascii.unhexlify(wycheproof.testcase["key"]) + iv = binascii.unhexlify(wycheproof.testcase["iv"]) + aad = binascii.unhexlify(wycheproof.testcase["aad"]) + msg = binascii.unhexlify(wycheproof.testcase["msg"]) + ct = binascii.unhexlify(wycheproof.testcase["ct"]) + tag = binascii.unhexlify(wycheproof.testcase["tag"]) + aesgcm = AESGCM(key) + if wycheproof.valid or wycheproof.acceptable: + computed_ct = aesgcm.encrypt(iv, msg, aad) + assert computed_ct == ct + tag + computed_msg = aesgcm.decrypt(iv, ct + tag, aad) + assert computed_msg == msg + elif len(iv) == 0: + with pytest.raises(ValueError): + aesgcm.encrypt(iv, msg, aad) + else: + with pytest.raises(InvalidTag): + aesgcm.decrypt(iv, ct + tag, aad) + + +@pytest.mark.skipif( + not _aead_supported(AESCCM), + reason="Requires OpenSSL with AES-CCM support", +) +@pytest.mark.requires_backend_interface(interface=CipherBackend) +@pytest.mark.wycheproof_tests("aes_ccm_test.json") +def test_aes_ccm_aead_api(backend, wycheproof): + key = binascii.unhexlify(wycheproof.testcase["key"]) + iv = binascii.unhexlify(wycheproof.testcase["iv"]) + aad = binascii.unhexlify(wycheproof.testcase["aad"]) + msg = binascii.unhexlify(wycheproof.testcase["msg"]) + ct = binascii.unhexlify(wycheproof.testcase["ct"]) + tag = binascii.unhexlify(wycheproof.testcase["tag"]) + + if ( + wycheproof.invalid and + wycheproof.testcase["comment"] == "Invalid tag size" + ): + with pytest.raises(ValueError): + AESCCM(key, tag_length=wycheproof.testgroup["tagSize"] // 8) + return + + aesccm = AESCCM(key, tag_length=wycheproof.testgroup["tagSize"] // 8) + if wycheproof.valid or wycheproof.acceptable: + computed_ct = aesccm.encrypt(iv, msg, aad) + assert computed_ct == ct + tag + computed_msg = aesccm.decrypt(iv, ct + tag, aad) + assert computed_msg == msg + elif not 7 <= len(iv) <= 13: + with pytest.raises(ValueError): + aesccm.decrypt(iv, ct + tag, aad) + else: + with pytest.raises(InvalidTag): + aesccm.decrypt(iv, ct + tag, aad) diff -Nru python-cryptography-2.1.4/tests/wycheproof/test_chacha20poly1305.py python-cryptography-2.6.1/tests/wycheproof/test_chacha20poly1305.py --- python-cryptography-2.1.4/tests/wycheproof/test_chacha20poly1305.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/tests/wycheproof/test_chacha20poly1305.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,47 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +import pytest + +from cryptography.exceptions import InvalidTag +from cryptography.hazmat.backends.interfaces import CipherBackend +from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 + +from ..hazmat.primitives.test_aead import _aead_supported + + +@pytest.mark.skipif( + not _aead_supported(ChaCha20Poly1305), + reason="Requires OpenSSL with ChaCha20Poly1305 support" +) +@pytest.mark.requires_backend_interface(interface=CipherBackend) +@pytest.mark.wycheproof_tests("chacha20_poly1305_test.json") +def test_chacha2poly1305(wycheproof): + key = binascii.unhexlify(wycheproof.testcase["key"]) + iv = binascii.unhexlify(wycheproof.testcase["iv"]) + aad = binascii.unhexlify(wycheproof.testcase["aad"]) + msg = binascii.unhexlify(wycheproof.testcase["msg"]) + ct = binascii.unhexlify(wycheproof.testcase["ct"]) + tag = binascii.unhexlify(wycheproof.testcase["tag"]) + + if wycheproof.valid: + chacha = ChaCha20Poly1305(key) + computed_ct = chacha.encrypt(iv, msg, aad) + assert computed_ct == ct + tag + computed_msg = chacha.decrypt(iv, ct + tag, aad) + assert computed_msg == msg + elif len(iv) != 12: + chacha = ChaCha20Poly1305(key) + with pytest.raises(ValueError): + chacha.encrypt(iv, msg, aad) + with pytest.raises(ValueError): + chacha.decrypt(iv, ct + tag, aad) + else: + chacha = ChaCha20Poly1305(key) + with pytest.raises(InvalidTag): + chacha.decrypt(iv, msg + tag, aad) diff -Nru python-cryptography-2.1.4/tests/wycheproof/test_cmac.py python-cryptography-2.6.1/tests/wycheproof/test_cmac.py --- python-cryptography-2.1.4/tests/wycheproof/test_cmac.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/tests/wycheproof/test_cmac.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,36 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +import pytest + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.backends.interfaces import CMACBackend +from cryptography.hazmat.primitives.ciphers.algorithms import AES +from cryptography.hazmat.primitives.cmac import CMAC + + +@pytest.mark.requires_backend_interface(interface=CMACBackend) +@pytest.mark.wycheproof_tests("aes_cmac_test.json") +def test_aes_cmac(backend, wycheproof): + key = binascii.unhexlify(wycheproof.testcase["key"]) + msg = binascii.unhexlify(wycheproof.testcase["msg"]) + tag = binascii.unhexlify(wycheproof.testcase["tag"]) + + # skip truncated tags, which we don't support in the API + if wycheproof.valid and len(tag) == 16: + ctx = CMAC(AES(key), backend) + ctx.update(msg) + ctx.verify(tag) + elif len(key) not in [16, 24, 32]: + with pytest.raises(ValueError): + CMAC(AES(key), backend) + else: + ctx = CMAC(AES(key), backend) + ctx.update(msg) + with pytest.raises(InvalidSignature): + ctx.verify(tag) diff -Nru python-cryptography-2.1.4/tests/wycheproof/test_dsa.py python-cryptography-2.6.1/tests/wycheproof/test_dsa.py --- python-cryptography-2.1.4/tests/wycheproof/test_dsa.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/tests/wycheproof/test_dsa.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,49 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +import pytest + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.backends.interfaces import DSABackend +from cryptography.hazmat.primitives import hashes, serialization + + +_DIGESTS = { + "SHA-1": hashes.SHA1(), + "SHA-224": hashes.SHA224(), + "SHA-256": hashes.SHA256(), +} + + +@pytest.mark.requires_backend_interface(interface=DSABackend) +@pytest.mark.wycheproof_tests( + "dsa_test.json", +) +def test_dsa_signature(backend, wycheproof): + key = serialization.load_der_public_key( + binascii.unhexlify(wycheproof.testgroup["keyDer"]), backend + ) + digest = _DIGESTS[wycheproof.testgroup["sha"]] + + if ( + wycheproof.valid or ( + wycheproof.acceptable and not wycheproof.has_flag("NoLeadingZero") + ) + ): + key.verify( + binascii.unhexlify(wycheproof.testcase["sig"]), + binascii.unhexlify(wycheproof.testcase["msg"]), + digest, + ) + else: + with pytest.raises(InvalidSignature): + key.verify( + binascii.unhexlify(wycheproof.testcase["sig"]), + binascii.unhexlify(wycheproof.testcase["msg"]), + digest, + ) diff -Nru python-cryptography-2.1.4/tests/wycheproof/test_ecdh.py python-cryptography-2.6.1/tests/wycheproof/test_ecdh.py --- python-cryptography-2.1.4/tests/wycheproof/test_ecdh.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/tests/wycheproof/test_ecdh.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,114 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +import pytest + +from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat.backends.interfaces import EllipticCurveBackend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import ec + +from ..hazmat.primitives.test_ec import _skip_exchange_algorithm_unsupported + + +_CURVES = { + "secp224r1": ec.SECP224R1(), + "secp256r1": ec.SECP256R1(), + "secp384r1": ec.SECP384R1(), + "secp521r1": ec.SECP521R1(), + "secp256k1": ec.SECP256K1(), + "brainpoolP224r1": None, + "brainpoolP256r1": ec.BrainpoolP256R1(), + "brainpoolP320r1": None, + "brainpoolP384r1": ec.BrainpoolP384R1(), + "brainpoolP512r1": ec.BrainpoolP512R1(), + "brainpoolP224t1": None, + "brainpoolP256t1": None, + "brainpoolP320t1": None, + "brainpoolP384t1": None, + "brainpoolP512t1": None, +} + + +@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) +@pytest.mark.wycheproof_tests( + "ecdh_test.json", + "ecdh_brainpoolP224r1_test.json", + "ecdh_brainpoolP256r1_test.json", + "ecdh_brainpoolP320r1_test.json", + "ecdh_brainpoolP384r1_test.json", + "ecdh_brainpoolP512r1_test.json", + "ecdh_secp224r1_test.json", + "ecdh_secp256k1_test.json", + "ecdh_secp256r1_test.json", + "ecdh_secp384r1_test.json", + "ecdh_secp521r1_test.json", +) +def test_ecdh(backend, wycheproof): + curve = _CURVES[wycheproof.testgroup["curve"]] + if curve is None: + pytest.skip( + "Unsupported curve ({})".format(wycheproof.testgroup["curve"]) + ) + _skip_exchange_algorithm_unsupported(backend, ec.ECDH(), curve) + + private_key = ec.derive_private_key( + int(wycheproof.testcase["private"], 16), curve, backend + ) + + try: + public_key = serialization.load_der_public_key( + binascii.unhexlify(wycheproof.testcase["public"]), backend + ) + except NotImplementedError: + assert wycheproof.has_flag("UnnamedCurve") + return + except ValueError: + assert wycheproof.invalid or wycheproof.acceptable + return + except UnsupportedAlgorithm: + return + + if wycheproof.valid or wycheproof.acceptable: + computed_shared = private_key.exchange(ec.ECDH(), public_key) + expected_shared = binascii.unhexlify(wycheproof.testcase["shared"]) + assert computed_shared == expected_shared + else: + with pytest.raises(ValueError): + private_key.exchange(ec.ECDH(), public_key) + + +@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) +@pytest.mark.wycheproof_tests( + "ecdh_secp224r1_ecpoint_test.json", + "ecdh_secp256r1_ecpoint_test.json", + "ecdh_secp384r1_ecpoint_test.json", + "ecdh_secp521r1_ecpoint_test.json", +) +def test_ecdh_ecpoint(backend, wycheproof): + curve = _CURVES[wycheproof.testgroup["curve"]] + _skip_exchange_algorithm_unsupported(backend, ec.ECDH(), curve) + + private_key = ec.derive_private_key( + int(wycheproof.testcase["private"], 16), curve, backend + ) + + if wycheproof.invalid: + with pytest.raises(ValueError): + ec.EllipticCurvePublicKey.from_encoded_point( + curve, binascii.unhexlify(wycheproof.testcase["public"]) + ) + return + + assert wycheproof.valid or wycheproof.acceptable + public_key = ec.EllipticCurvePublicKey.from_encoded_point( + curve, binascii.unhexlify(wycheproof.testcase["public"]) + ) + computed_shared = private_key.exchange(ec.ECDH(), public_key) + expected_shared = binascii.unhexlify(wycheproof.testcase["shared"]) + assert computed_shared == expected_shared diff -Nru python-cryptography-2.1.4/tests/wycheproof/test_ecdsa.py python-cryptography-2.6.1/tests/wycheproof/test_ecdsa.py --- python-cryptography-2.1.4/tests/wycheproof/test_ecdsa.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/tests/wycheproof/test_ecdsa.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,76 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +import pytest + +from cryptography.exceptions import InvalidSignature, UnsupportedAlgorithm +from cryptography.hazmat.backends.interfaces import EllipticCurveBackend +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ec + + +_DIGESTS = { + "SHA-1": hashes.SHA1(), + "SHA-224": hashes.SHA224(), + "SHA-256": hashes.SHA256(), + "SHA-384": hashes.SHA384(), + "SHA-512": hashes.SHA512(), +} + + +@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) +@pytest.mark.wycheproof_tests( + "ecdsa_test.json", + "ecdsa_brainpoolP224r1_sha224_test.json", + "ecdsa_brainpoolP256r1_sha256_test.json", + "ecdsa_brainpoolP320r1_sha384_test.json", + "ecdsa_brainpoolP384r1_sha384_test.json", + "ecdsa_brainpoolP512r1_sha512_test.json", + "ecdsa_secp224r1_sha224_test.json", + "ecdsa_secp224r1_sha256_test.json", + "ecdsa_secp224r1_sha512_test.json", + "ecdsa_secp256k1_sha256_test.json", + "ecdsa_secp256k1_sha512_test.json", + "ecdsa_secp256r1_sha256_test.json", + "ecdsa_secp256r1_sha512_test.json", + "ecdsa_secp384r1_sha384_test.json", + "ecdsa_secp384r1_sha512_test.json", + "ecdsa_secp521r1_sha512_test.json", +) +def test_ecdsa_signature(backend, wycheproof): + try: + key = serialization.load_der_public_key( + binascii.unhexlify(wycheproof.testgroup["keyDer"]), backend + ) + except (UnsupportedAlgorithm, ValueError): + # In OpenSSL 1.0.1, some keys fail to load with ValueError, instead of + # Unsupported Algorithm. We can remove handling for that exception + # when we drop support. + pytest.skip( + "unable to load key (curve {})".format( + wycheproof.testgroup["key"]["curve"] + ) + ) + digest = _DIGESTS[wycheproof.testgroup["sha"]] + + if ( + wycheproof.valid or + (wycheproof.acceptable and not wycheproof.has_flag("MissingZero")) + ): + key.verify( + binascii.unhexlify(wycheproof.testcase["sig"]), + binascii.unhexlify(wycheproof.testcase["msg"]), + ec.ECDSA(digest), + ) + else: + with pytest.raises(InvalidSignature): + key.verify( + binascii.unhexlify(wycheproof.testcase["sig"]), + binascii.unhexlify(wycheproof.testcase["msg"]), + ec.ECDSA(digest), + ) diff -Nru python-cryptography-2.1.4/tests/wycheproof/test_eddsa.py python-cryptography-2.6.1/tests/wycheproof/test_eddsa.py --- python-cryptography-2.1.4/tests/wycheproof/test_eddsa.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/tests/wycheproof/test_eddsa.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,45 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +import pytest + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.backends.interfaces import DHBackend +from cryptography.hazmat.primitives.asymmetric.ed25519 import ( + Ed25519PublicKey +) + + +@pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support" +) +@pytest.mark.requires_backend_interface(interface=DHBackend) +@pytest.mark.wycheproof_tests( + "eddsa_test.json", +) +def test_ed25519_signature(backend, wycheproof): + # We want to fail if/when wycheproof adds more edwards curve tests + # so we can add them as well. + assert wycheproof.testgroup["key"]["curve"] == "edwards25519" + + key = Ed25519PublicKey.from_public_bytes( + binascii.unhexlify(wycheproof.testgroup["key"]["pk"]) + ) + + if wycheproof.valid or wycheproof.acceptable: + key.verify( + binascii.unhexlify(wycheproof.testcase["sig"]), + binascii.unhexlify(wycheproof.testcase["msg"]), + ) + else: + with pytest.raises(InvalidSignature): + key.verify( + binascii.unhexlify(wycheproof.testcase["sig"]), + binascii.unhexlify(wycheproof.testcase["msg"]), + ) diff -Nru python-cryptography-2.1.4/tests/wycheproof/test_keywrap.py python-cryptography-2.6.1/tests/wycheproof/test_keywrap.py --- python-cryptography-2.1.4/tests/wycheproof/test_keywrap.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/tests/wycheproof/test_keywrap.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,61 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +import pytest + +from cryptography.hazmat.backends.interfaces import CipherBackend +from cryptography.hazmat.primitives import keywrap + + +@pytest.mark.requires_backend_interface(interface=CipherBackend) +@pytest.mark.wycheproof_tests("kwp_test.json") +def test_keywrap_with_padding(backend, wycheproof): + wrapping_key = binascii.unhexlify(wycheproof.testcase["key"]) + key_to_wrap = binascii.unhexlify(wycheproof.testcase["msg"]) + expected = binascii.unhexlify(wycheproof.testcase["ct"]) + + result = keywrap.aes_key_wrap_with_padding( + wrapping_key, key_to_wrap, backend + ) + if wycheproof.valid or wycheproof.acceptable: + assert result == expected + + if wycheproof.valid or (wycheproof.acceptable and not len(expected) < 16): + result = keywrap.aes_key_unwrap_with_padding( + wrapping_key, expected, backend + ) + assert result == key_to_wrap + else: + with pytest.raises(keywrap.InvalidUnwrap): + keywrap.aes_key_unwrap_with_padding( + wrapping_key, expected, backend + ) + + +@pytest.mark.requires_backend_interface(interface=CipherBackend) +@pytest.mark.wycheproof_tests("kw_test.json") +def test_keywrap(backend, wycheproof): + wrapping_key = binascii.unhexlify(wycheproof.testcase["key"]) + key_to_wrap = binascii.unhexlify(wycheproof.testcase["msg"]) + expected = binascii.unhexlify(wycheproof.testcase["ct"]) + + if ( + wycheproof.valid or ( + wycheproof.acceptable and + wycheproof.testcase["comment"] != "invalid size of wrapped key" + ) + ): + result = keywrap.aes_key_wrap(wrapping_key, key_to_wrap, backend) + assert result == expected + + if wycheproof.valid or wycheproof.acceptable: + result = keywrap.aes_key_unwrap(wrapping_key, expected, backend) + assert result == key_to_wrap + else: + with pytest.raises(keywrap.InvalidUnwrap): + keywrap.aes_key_unwrap(wrapping_key, expected, backend) diff -Nru python-cryptography-2.1.4/tests/wycheproof/test_rsa.py python-cryptography-2.6.1/tests/wycheproof/test_rsa.py --- python-cryptography-2.1.4/tests/wycheproof/test_rsa.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/tests/wycheproof/test_rsa.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,125 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +import pytest + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.backends.interfaces import RSABackend +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import padding + + +_DIGESTS = { + "SHA-1": hashes.SHA1(), + "SHA-224": hashes.SHA224(), + "SHA-256": hashes.SHA256(), + "SHA-384": hashes.SHA384(), + "SHA-512": hashes.SHA512(), +} + + +def should_verify(backend, wycheproof): + if wycheproof.valid: + return True + + if wycheproof.acceptable: + if ( + ( + backend._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER or + backend._lib.CRYPTOGRAPHY_LIBRESSL_28_OR_GREATER + ) and wycheproof.has_flag("MissingNull") + ): + return False + return True + + return False + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.supported( + only_if=lambda backend: ( + not backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 or + backend._lib.CRYPTOGRAPHY_LIBRESSL_28_OR_GREATER + ), + skip_message=( + "Many of these tests fail on OpenSSL < 1.0.2 and since upstream isn't" + " maintaining it, they'll never be fixed." + ), +) +@pytest.mark.wycheproof_tests( + "rsa_signature_test.json", + "rsa_signature_2048_sha224_test.json", + "rsa_signature_2048_sha256_test.json", + "rsa_signature_2048_sha512_test.json", + "rsa_signature_3072_sha256_test.json", + "rsa_signature_3072_sha384_test.json", + "rsa_signature_3072_sha512_test.json", + "rsa_signature_4096_sha384_test.json", + "rsa_signature_4096_sha512_test.json", +) +def test_rsa_pkcs1v15_signature(backend, wycheproof): + key = serialization.load_der_public_key( + binascii.unhexlify(wycheproof.testgroup["keyDer"]), backend + ) + digest = _DIGESTS[wycheproof.testgroup["sha"]] + + if should_verify(backend, wycheproof): + key.verify( + binascii.unhexlify(wycheproof.testcase["sig"]), + binascii.unhexlify(wycheproof.testcase["msg"]), + padding.PKCS1v15(), + digest, + ) + else: + with pytest.raises(InvalidSignature): + key.verify( + binascii.unhexlify(wycheproof.testcase["sig"]), + binascii.unhexlify(wycheproof.testcase["msg"]), + padding.PKCS1v15(), + digest, + ) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.wycheproof_tests( + "rsa_pss_2048_sha1_mgf1_20_test.json", + "rsa_pss_2048_sha256_mgf1_0_test.json", + "rsa_pss_2048_sha256_mgf1_32_test.json", + "rsa_pss_3072_sha256_mgf1_32_test.json", + "rsa_pss_4096_sha256_mgf1_32_test.json", + "rsa_pss_4096_sha512_mgf1_32_test.json", + "rsa_pss_misc_test.json", +) +def test_rsa_pss_signature(backend, wycheproof): + key = serialization.load_der_public_key( + binascii.unhexlify(wycheproof.testgroup["keyDer"]), backend + ) + digest = _DIGESTS[wycheproof.testgroup["sha"]] + mgf_digest = _DIGESTS[wycheproof.testgroup["mgfSha"]] + + if wycheproof.valid or wycheproof.acceptable: + key.verify( + binascii.unhexlify(wycheproof.testcase["sig"]), + binascii.unhexlify(wycheproof.testcase["msg"]), + padding.PSS( + mgf=padding.MGF1(mgf_digest), + salt_length=wycheproof.testgroup["sLen"] + ), + digest + ) + else: + with pytest.raises(InvalidSignature): + key.verify( + binascii.unhexlify(wycheproof.testcase["sig"]), + binascii.unhexlify(wycheproof.testcase["msg"]), + padding.PSS( + mgf=padding.MGF1(mgf_digest), + salt_length=wycheproof.testgroup["sLen"] + ), + digest + ) diff -Nru python-cryptography-2.1.4/tests/wycheproof/test_utils.py python-cryptography-2.6.1/tests/wycheproof/test_utils.py --- python-cryptography-2.1.4/tests/wycheproof/test_utils.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/tests/wycheproof/test_utils.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,21 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import pytest + +from ..utils import WycheproofTest, skip_if_wycheproof_none + + +def test_wycheproof_test_repr(): + wycheproof = WycheproofTest({}, {"tcId": 3}) + assert repr(wycheproof) == "" + + +def test_skip_if_wycheproof_none(): + with pytest.raises(pytest.skip.Exception): + skip_if_wycheproof_none(None) + + skip_if_wycheproof_none("abc") diff -Nru python-cryptography-2.1.4/tests/wycheproof/test_x25519.py python-cryptography-2.6.1/tests/wycheproof/test_x25519.py --- python-cryptography-2.1.4/tests/wycheproof/test_x25519.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/tests/wycheproof/test_x25519.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,42 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +import pytest + +from cryptography.hazmat.backends.interfaces import DHBackend +from cryptography.hazmat.primitives.asymmetric.x25519 import ( + X25519PrivateKey, X25519PublicKey +) + + +@pytest.mark.supported( + only_if=lambda backend: backend.x25519_supported(), + skip_message="Requires OpenSSL with X25519 support" +) +@pytest.mark.requires_backend_interface(interface=DHBackend) +@pytest.mark.wycheproof_tests("x25519_test.json") +def test_x25519(backend, wycheproof): + assert list(wycheproof.testgroup.items()) == [("curve", "curve25519")] + + private_key = X25519PrivateKey.from_private_bytes( + binascii.unhexlify(wycheproof.testcase["private"]) + ) + public_key = X25519PublicKey.from_public_bytes( + binascii.unhexlify(wycheproof.testcase["public"]) + ) + + assert wycheproof.valid or wycheproof.acceptable + + expected = binascii.unhexlify(wycheproof.testcase["shared"]) + if expected == b"\x00" * 32: + assert wycheproof.acceptable + # OpenSSL returns an error on all zeros shared key + with pytest.raises(ValueError): + private_key.exchange(public_key) + else: + assert private_key.exchange(public_key) == expected diff -Nru python-cryptography-2.1.4/tests/x509/test_ocsp.py python-cryptography-2.6.1/tests/x509/test_ocsp.py --- python-cryptography-2.1.4/tests/x509/test_ocsp.py 1970-01-01 00:00:00.000000000 +0000 +++ python-cryptography-2.6.1/tests/x509/test_ocsp.py 2019-02-27 23:27:53.000000000 +0000 @@ -0,0 +1,755 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import base64 +import datetime +import os + +import pytest + +from cryptography import x509 +from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15 +from cryptography.x509 import ocsp + +from .test_x509 import _load_cert +from ..hazmat.primitives.fixtures_ec import EC_KEY_SECP256R1 +from ..utils import load_vectors_from_file + + +def _load_data(filename, loader): + return load_vectors_from_file( + filename=filename, + loader=lambda data: loader(data.read()), + mode="rb" + ) + + +def _cert_and_issuer(): + from cryptography.hazmat.backends.openssl.backend import backend + cert = _load_cert( + os.path.join("x509", "cryptography.io.pem"), + x509.load_pem_x509_certificate, + backend + ) + issuer = _load_cert( + os.path.join("x509", "rapidssl_sha256_ca_g3.pem"), + x509.load_pem_x509_certificate, + backend + ) + return cert, issuer + + +def _generate_root(): + from cryptography.hazmat.backends.openssl.backend import backend + + private_key = EC_KEY_SECP256R1.private_key(backend) + subject = x509.Name([ + x509.NameAttribute(x509.NameOID.COUNTRY_NAME, u'US'), + x509.NameAttribute(x509.NameOID.COMMON_NAME, u'Cryptography CA'), + ]) + + builder = x509.CertificateBuilder().serial_number( + 123456789 + ).issuer_name( + subject + ).subject_name( + subject + ).public_key( + private_key.public_key() + ).not_valid_before( + datetime.datetime.now() + ).not_valid_after( + datetime.datetime.now() + datetime.timedelta(days=3650) + ) + + cert = builder.sign(private_key, hashes.SHA256(), backend) + return cert, private_key + + +class TestOCSPRequest(object): + def test_bad_request(self): + with pytest.raises(ValueError): + ocsp.load_der_ocsp_request(b"invalid") + + def test_load_request(self): + req = _load_data( + os.path.join("x509", "ocsp", "req-sha1.der"), + ocsp.load_der_ocsp_request, + ) + assert req.issuer_name_hash == (b"8\xcaF\x8c\x07D\x8d\xf4\x81\x96" + b"\xc7mmLpQ\x9e`\xa7\xbd") + assert req.issuer_key_hash == (b"yu\xbb\x84:\xcb,\xdez\t\xbe1" + b"\x1bC\xbc\x1c*MSX") + assert isinstance(req.hash_algorithm, hashes.SHA1) + assert req.serial_number == int( + "98D9E5C0B4C373552DF77C5D0F1EB5128E4945F9", 16 + ) + assert len(req.extensions) == 0 + + def test_load_request_with_extensions(self): + req = _load_data( + os.path.join("x509", "ocsp", "req-ext-nonce.der"), + ocsp.load_der_ocsp_request, + ) + assert len(req.extensions) == 1 + ext = req.extensions[0] + assert ext.critical is False + assert ext.value == x509.OCSPNonce( + b"\x04\x10{\x80Z\x1d7&\xb8\xb8OH\xd2\xf8\xbf\xd7-\xfd" + ) + + def test_load_request_two_requests(self): + with pytest.raises(NotImplementedError): + _load_data( + os.path.join("x509", "ocsp", "req-multi-sha1.der"), + ocsp.load_der_ocsp_request, + ) + + def test_invalid_hash_algorithm(self): + req = _load_data( + os.path.join("x509", "ocsp", "req-invalid-hash-alg.der"), + ocsp.load_der_ocsp_request, + ) + with pytest.raises(UnsupportedAlgorithm): + req.hash_algorithm + + def test_serialize_request(self): + req_bytes = load_vectors_from_file( + filename=os.path.join("x509", "ocsp", "req-sha1.der"), + loader=lambda data: data.read(), + mode="rb" + ) + req = ocsp.load_der_ocsp_request(req_bytes) + assert req.public_bytes(serialization.Encoding.DER) == req_bytes + + def test_invalid_serialize_encoding(self): + req = _load_data( + os.path.join("x509", "ocsp", "req-sha1.der"), + ocsp.load_der_ocsp_request, + ) + with pytest.raises(ValueError): + req.public_bytes("invalid") + with pytest.raises(ValueError): + req.public_bytes(serialization.Encoding.PEM) + + +class TestOCSPRequestBuilder(object): + def test_add_two_certs(self): + cert, issuer = _cert_and_issuer() + builder = ocsp.OCSPRequestBuilder() + builder = builder.add_certificate(cert, issuer, hashes.SHA1()) + with pytest.raises(ValueError): + builder.add_certificate(cert, issuer, hashes.SHA1()) + + def test_create_ocsp_request_no_req(self): + builder = ocsp.OCSPRequestBuilder() + with pytest.raises(ValueError): + builder.build() + + def test_create_ocsp_request_invalid_alg(self): + cert, issuer = _cert_and_issuer() + builder = ocsp.OCSPRequestBuilder() + with pytest.raises(ValueError): + builder.add_certificate(cert, issuer, hashes.MD5()) + + def test_add_extension_twice(self): + builder = ocsp.OCSPRequestBuilder() + builder = builder.add_extension(x509.OCSPNonce(b"123"), False) + with pytest.raises(ValueError): + builder.add_extension(x509.OCSPNonce(b"123"), False) + + def test_add_invalid_extension(self): + builder = ocsp.OCSPRequestBuilder() + with pytest.raises(TypeError): + builder.add_extension("notanext", False) + + def test_create_ocsp_request_invalid_cert(self): + cert, issuer = _cert_and_issuer() + builder = ocsp.OCSPRequestBuilder() + with pytest.raises(TypeError): + builder.add_certificate(b"notacert", issuer, hashes.SHA1()) + + with pytest.raises(TypeError): + builder.add_certificate(cert, b"notacert", hashes.SHA1()) + + def test_create_ocsp_request(self): + cert, issuer = _cert_and_issuer() + builder = ocsp.OCSPRequestBuilder() + builder = builder.add_certificate(cert, issuer, hashes.SHA1()) + req = builder.build() + serialized = req.public_bytes(serialization.Encoding.DER) + assert serialized == base64.b64decode( + b"MEMwQTA/MD0wOzAJBgUrDgMCGgUABBRAC0Z68eay0wmDug1gfn5ZN0gkxAQUw5zz" + b"/NNGCDS7zkZ/oHxb8+IIy1kCAj8g" + ) + + @pytest.mark.parametrize( + ("ext", "critical"), + [ + [x509.OCSPNonce(b"0000"), False], + [x509.OCSPNonce(b"\x00\x01\x02"), True], + ] + ) + def test_create_ocsp_request_with_extension(self, ext, critical): + cert, issuer = _cert_and_issuer() + builder = ocsp.OCSPRequestBuilder() + builder = builder.add_certificate( + cert, issuer, hashes.SHA1() + ).add_extension( + ext, critical + ) + req = builder.build() + assert len(req.extensions) == 1 + assert req.extensions[0].value == ext + assert req.extensions[0].oid == ext.oid + assert req.extensions[0].critical is critical + + +class TestOCSPResponseBuilder(object): + def test_add_response_twice(self): + cert, issuer = _cert_and_issuer() + time = datetime.datetime.now() + builder = ocsp.OCSPResponseBuilder() + builder = builder.add_response( + cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, time, + time, None, None + ) + with pytest.raises(ValueError): + builder.add_response( + cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, time, + time, None, None + ) + + def test_invalid_add_response(self): + cert, issuer = _cert_and_issuer() + time = datetime.datetime.utcnow() + reason = x509.ReasonFlags.cessation_of_operation + builder = ocsp.OCSPResponseBuilder() + with pytest.raises(TypeError): + builder.add_response( + 'bad', issuer, hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, + time, time, None, None + ) + with pytest.raises(TypeError): + builder.add_response( + cert, 'bad', hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, + time, time, None, None + ) + with pytest.raises(ValueError): + builder.add_response( + cert, issuer, 'notahash', ocsp.OCSPCertStatus.GOOD, + time, time, None, None + ) + with pytest.raises(TypeError): + builder.add_response( + cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, + 'bad', time, None, None + ) + with pytest.raises(TypeError): + builder.add_response( + cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, + time, 'bad', None, None + ) + + with pytest.raises(TypeError): + builder.add_response( + cert, issuer, hashes.SHA256(), 0, time, time, None, None + ) + with pytest.raises(ValueError): + builder.add_response( + cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, + time, time, time, None + ) + with pytest.raises(ValueError): + builder.add_response( + cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, + time, time, None, reason + ) + with pytest.raises(TypeError): + builder.add_response( + cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.REVOKED, + time, time, None, reason + ) + with pytest.raises(TypeError): + builder.add_response( + cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.REVOKED, + time, time, time, 0 + ) + with pytest.raises(ValueError): + builder.add_response( + cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.REVOKED, + time, time, time - datetime.timedelta(days=36500), None + ) + + def test_invalid_certificates(self): + builder = ocsp.OCSPResponseBuilder() + with pytest.raises(ValueError): + builder.certificates([]) + with pytest.raises(TypeError): + builder.certificates(['notacert']) + with pytest.raises(TypeError): + builder.certificates('invalid') + + _, issuer = _cert_and_issuer() + builder = builder.certificates([issuer]) + with pytest.raises(ValueError): + builder.certificates([issuer]) + + def test_invalid_responder_id(self): + builder = ocsp.OCSPResponseBuilder() + cert, _ = _cert_and_issuer() + with pytest.raises(TypeError): + builder.responder_id(ocsp.OCSPResponderEncoding.HASH, 'invalid') + with pytest.raises(TypeError): + builder.responder_id('notanenum', cert) + + builder = builder.responder_id(ocsp.OCSPResponderEncoding.NAME, cert) + with pytest.raises(ValueError): + builder.responder_id(ocsp.OCSPResponderEncoding.NAME, cert) + + def test_invalid_extension(self): + builder = ocsp.OCSPResponseBuilder() + with pytest.raises(TypeError): + builder.add_extension("notanextension", True) + + def test_sign_no_response(self): + builder = ocsp.OCSPResponseBuilder() + root_cert, private_key = _generate_root() + builder = builder.responder_id( + ocsp.OCSPResponderEncoding.NAME, root_cert + ) + with pytest.raises(ValueError): + builder.sign(private_key, hashes.SHA256()) + + def test_sign_no_responder_id(self): + builder = ocsp.OCSPResponseBuilder() + cert, issuer = _cert_and_issuer() + _, private_key = _generate_root() + current_time = datetime.datetime.utcnow().replace(microsecond=0) + this_update = current_time - datetime.timedelta(days=1) + next_update = this_update + datetime.timedelta(days=7) + builder = builder.add_response( + cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.GOOD, this_update, + next_update, None, None + ) + with pytest.raises(ValueError): + builder.sign(private_key, hashes.SHA256()) + + def test_sign_invalid_hash_algorithm(self): + builder = ocsp.OCSPResponseBuilder() + cert, issuer = _cert_and_issuer() + root_cert, private_key = _generate_root() + current_time = datetime.datetime.utcnow().replace(microsecond=0) + this_update = current_time - datetime.timedelta(days=1) + next_update = this_update + datetime.timedelta(days=7) + builder = builder.responder_id( + ocsp.OCSPResponderEncoding.NAME, root_cert + ).add_response( + cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.GOOD, this_update, + next_update, None, None + ) + with pytest.raises(TypeError): + builder.sign(private_key, 'notahash') + + def test_sign_good_cert(self): + builder = ocsp.OCSPResponseBuilder() + cert, issuer = _cert_and_issuer() + root_cert, private_key = _generate_root() + current_time = datetime.datetime.utcnow().replace(microsecond=0) + this_update = current_time - datetime.timedelta(days=1) + next_update = this_update + datetime.timedelta(days=7) + builder = builder.responder_id( + ocsp.OCSPResponderEncoding.NAME, root_cert + ).add_response( + cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.GOOD, this_update, + next_update, None, None + ) + resp = builder.sign(private_key, hashes.SHA256()) + assert resp.responder_name == root_cert.subject + assert resp.responder_key_hash is None + assert (current_time - resp.produced_at).total_seconds() < 10 + assert (resp.signature_algorithm_oid == + x509.SignatureAlgorithmOID.ECDSA_WITH_SHA256) + assert resp.certificate_status == ocsp.OCSPCertStatus.GOOD + assert resp.revocation_time is None + assert resp.revocation_reason is None + assert resp.this_update == this_update + assert resp.next_update == next_update + private_key.public_key().verify( + resp.signature, resp.tbs_response_bytes, ec.ECDSA(hashes.SHA256()) + ) + + def test_sign_revoked_cert(self): + builder = ocsp.OCSPResponseBuilder() + cert, issuer = _cert_and_issuer() + root_cert, private_key = _generate_root() + current_time = datetime.datetime.utcnow().replace(microsecond=0) + this_update = current_time - datetime.timedelta(days=1) + next_update = this_update + datetime.timedelta(days=7) + revoked_date = this_update - datetime.timedelta(days=300) + builder = builder.responder_id( + ocsp.OCSPResponderEncoding.NAME, root_cert + ).add_response( + cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.REVOKED, + this_update, next_update, revoked_date, None + ) + resp = builder.sign(private_key, hashes.SHA256()) + assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED + assert resp.revocation_time == revoked_date + assert resp.revocation_reason is None + assert resp.this_update == this_update + assert resp.next_update == next_update + private_key.public_key().verify( + resp.signature, resp.tbs_response_bytes, ec.ECDSA(hashes.SHA256()) + ) + + def test_sign_with_appended_certs(self): + builder = ocsp.OCSPResponseBuilder() + cert, issuer = _cert_and_issuer() + root_cert, private_key = _generate_root() + current_time = datetime.datetime.utcnow().replace(microsecond=0) + this_update = current_time - datetime.timedelta(days=1) + next_update = this_update + datetime.timedelta(days=7) + builder = builder.responder_id( + ocsp.OCSPResponderEncoding.NAME, root_cert + ).add_response( + cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.GOOD, this_update, + next_update, None, None + ).certificates( + [root_cert] + ) + resp = builder.sign(private_key, hashes.SHA256()) + assert resp.certificates == [root_cert] + + def test_sign_revoked_no_next_update(self): + builder = ocsp.OCSPResponseBuilder() + cert, issuer = _cert_and_issuer() + root_cert, private_key = _generate_root() + current_time = datetime.datetime.utcnow().replace(microsecond=0) + this_update = current_time - datetime.timedelta(days=1) + revoked_date = this_update - datetime.timedelta(days=300) + builder = builder.responder_id( + ocsp.OCSPResponderEncoding.NAME, root_cert + ).add_response( + cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.REVOKED, + this_update, None, revoked_date, None + ) + resp = builder.sign(private_key, hashes.SHA256()) + assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED + assert resp.revocation_time == revoked_date + assert resp.revocation_reason is None + assert resp.this_update == this_update + assert resp.next_update is None + private_key.public_key().verify( + resp.signature, resp.tbs_response_bytes, ec.ECDSA(hashes.SHA256()) + ) + + def test_sign_revoked_with_reason(self): + builder = ocsp.OCSPResponseBuilder() + cert, issuer = _cert_and_issuer() + root_cert, private_key = _generate_root() + current_time = datetime.datetime.utcnow().replace(microsecond=0) + this_update = current_time - datetime.timedelta(days=1) + next_update = this_update + datetime.timedelta(days=7) + revoked_date = this_update - datetime.timedelta(days=300) + builder = builder.responder_id( + ocsp.OCSPResponderEncoding.NAME, root_cert + ).add_response( + cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.REVOKED, + this_update, next_update, revoked_date, + x509.ReasonFlags.key_compromise + ) + resp = builder.sign(private_key, hashes.SHA256()) + assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED + assert resp.revocation_time == revoked_date + assert resp.revocation_reason is x509.ReasonFlags.key_compromise + assert resp.this_update == this_update + assert resp.next_update == next_update + private_key.public_key().verify( + resp.signature, resp.tbs_response_bytes, ec.ECDSA(hashes.SHA256()) + ) + + def test_sign_responder_id_key_hash(self): + builder = ocsp.OCSPResponseBuilder() + cert, issuer = _cert_and_issuer() + root_cert, private_key = _generate_root() + current_time = datetime.datetime.utcnow().replace(microsecond=0) + this_update = current_time - datetime.timedelta(days=1) + next_update = this_update + datetime.timedelta(days=7) + builder = builder.responder_id( + ocsp.OCSPResponderEncoding.HASH, root_cert + ).add_response( + cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.GOOD, this_update, + next_update, None, None + ) + resp = builder.sign(private_key, hashes.SHA256()) + assert resp.responder_name is None + assert resp.responder_key_hash == ( + b'\x8ca\x94\xe0\x948\xed\x89\xd8\xd4N\x89p\t\xd6\xf9^_\xec}' + ) + private_key.public_key().verify( + resp.signature, resp.tbs_response_bytes, ec.ECDSA(hashes.SHA256()) + ) + + def test_invalid_sign_responder_cert_does_not_match_private_key(self): + builder = ocsp.OCSPResponseBuilder() + cert, issuer = _cert_and_issuer() + root_cert, private_key = _generate_root() + current_time = datetime.datetime.utcnow().replace(microsecond=0) + this_update = current_time - datetime.timedelta(days=1) + next_update = this_update + datetime.timedelta(days=7) + builder = builder.responder_id( + ocsp.OCSPResponderEncoding.HASH, root_cert + ).add_response( + cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.GOOD, this_update, + next_update, None, None + ) + from cryptography.hazmat.backends.openssl.backend import backend + diff_key = ec.generate_private_key(ec.SECP256R1(), backend) + with pytest.raises(ValueError): + builder.sign(diff_key, hashes.SHA256()) + + def test_sign_with_extension(self): + builder = ocsp.OCSPResponseBuilder() + cert, issuer = _cert_and_issuer() + root_cert, private_key = _generate_root() + current_time = datetime.datetime.utcnow().replace(microsecond=0) + this_update = current_time - datetime.timedelta(days=1) + next_update = this_update + datetime.timedelta(days=7) + builder = builder.responder_id( + ocsp.OCSPResponderEncoding.HASH, root_cert + ).add_response( + cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.GOOD, this_update, + next_update, None, None + ).add_extension( + x509.OCSPNonce(b"012345"), False + ) + resp = builder.sign(private_key, hashes.SHA256()) + assert len(resp.extensions) == 1 + assert resp.extensions[0].value == x509.OCSPNonce(b"012345") + assert resp.extensions[0].critical is False + private_key.public_key().verify( + resp.signature, resp.tbs_response_bytes, ec.ECDSA(hashes.SHA256()) + ) + + @pytest.mark.parametrize( + ("status", "der"), + [ + (ocsp.OCSPResponseStatus.MALFORMED_REQUEST, b"0\x03\n\x01\x01"), + (ocsp.OCSPResponseStatus.INTERNAL_ERROR, b"0\x03\n\x01\x02"), + (ocsp.OCSPResponseStatus.TRY_LATER, b"0\x03\n\x01\x03"), + (ocsp.OCSPResponseStatus.SIG_REQUIRED, b"0\x03\n\x01\x05"), + (ocsp.OCSPResponseStatus.UNAUTHORIZED, b"0\x03\n\x01\x06"), + ] + ) + def test_build_non_successful_statuses(self, status, der): + resp = ocsp.OCSPResponseBuilder.build_unsuccessful(status) + assert resp.response_status is status + assert resp.public_bytes(serialization.Encoding.DER) == der + + def test_invalid_build_not_a_status(self): + with pytest.raises(TypeError): + ocsp.OCSPResponseBuilder.build_unsuccessful("notastatus") + + def test_invalid_build_successful_status(self): + with pytest.raises(ValueError): + ocsp.OCSPResponseBuilder.build_unsuccessful( + ocsp.OCSPResponseStatus.SUCCESSFUL + ) + + +class TestOCSPResponse(object): + def test_bad_response(self): + with pytest.raises(ValueError): + ocsp.load_der_ocsp_response(b"invalid") + + def test_load_response(self): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-sha256.der"), + ocsp.load_der_ocsp_response, + ) + from cryptography.hazmat.backends.openssl.backend import backend + issuer = _load_cert( + os.path.join("x509", "letsencryptx3.pem"), + x509.load_pem_x509_certificate, + backend + ) + assert resp.response_status == ocsp.OCSPResponseStatus.SUCCESSFUL + assert (resp.signature_algorithm_oid == + x509.SignatureAlgorithmOID.RSA_WITH_SHA256) + assert isinstance(resp.signature_hash_algorithm, hashes.SHA256) + assert resp.signature == base64.b64decode( + b"I9KUlyLV/2LbNCVu1BQphxdNlU/jBzXsPYVscPjW5E93pCrSO84GkIWoOJtqsnt" + b"78DLcQPnF3W24NXGzSGKlSWfXIsyoXCxnBm0mIbD5ZMnKyXEnqSR33Z9He/A+ML" + b"A8gbrDUipGNPosesenkKUnOtFIzEGv29hV5E6AMP2ORPVsVlTAZegPJFbbVIWc0" + b"rZGFCXKxijDxtUtgWzBhpBAI50JbPHi+IVuaOe4aDJLYgZ0BIBNa6bDI+rScyoy" + b"5U0DToV7SZn6CoJ3U19X7BHdYn6TLX0xi43eXuzBGzdHnSzmsc7r/DvkAKJm3vb" + b"dVECXqe/gFlXJUBcZ25jhs70MUA==" + ) + assert resp.tbs_response_bytes == base64.b64decode( + b"MIHWoUwwSjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzA" + b"hBgNVBAMTGkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzGA8yMDE4MDgzMDExMT" + b"UwMFowdTBzMEswCQYFKw4DAhoFAAQUfuZq53Kas/z4oiBkbBahLWBxCF0EFKhKa" + b"mMEfd265tE5t6ZFZe/zqOyhAhIDHHh6fckClQB7xfIiCztSevCAABgPMjAxODA4" + b"MzAxMTAwMDBaoBEYDzIwMTgwOTA2MTEwMDAwWg==" + ) + issuer.public_key().verify( + resp.signature, + resp.tbs_response_bytes, + PKCS1v15(), + resp.signature_hash_algorithm + ) + assert resp.certificates == [] + assert resp.responder_key_hash is None + assert resp.responder_name == issuer.subject + assert resp.produced_at == datetime.datetime(2018, 8, 30, 11, 15) + assert resp.certificate_status == ocsp.OCSPCertStatus.GOOD + assert resp.revocation_time is None + assert resp.revocation_reason is None + assert resp.this_update == datetime.datetime(2018, 8, 30, 11, 0) + assert resp.next_update == datetime.datetime(2018, 9, 6, 11, 0) + assert resp.issuer_key_hash == ( + b'\xa8Jjc\x04}\xdd\xba\xe6\xd19\xb7\xa6Ee\xef\xf3\xa8\xec\xa1' + ) + assert resp.issuer_name_hash == ( + b'~\xe6j\xe7r\x9a\xb3\xfc\xf8\xa2 dl\x16\xa1-`q\x08]' + ) + assert isinstance(resp.hash_algorithm, hashes.SHA1) + assert resp.serial_number == 271024907440004808294641238224534273948400 + assert len(resp.extensions) == 0 + + def test_load_unauthorized(self): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-unauthorized.der"), + ocsp.load_der_ocsp_response, + ) + assert resp.response_status == ocsp.OCSPResponseStatus.UNAUTHORIZED + with pytest.raises(ValueError): + resp.signature_algorithm_oid + with pytest.raises(ValueError): + resp.signature_hash_algorithm + with pytest.raises(ValueError): + resp.signature + with pytest.raises(ValueError): + resp.tbs_response_bytes + with pytest.raises(ValueError): + resp.certificates + with pytest.raises(ValueError): + resp.responder_key_hash + with pytest.raises(ValueError): + resp.responder_name + with pytest.raises(ValueError): + resp.produced_at + with pytest.raises(ValueError): + resp.certificate_status + with pytest.raises(ValueError): + resp.revocation_time + with pytest.raises(ValueError): + resp.revocation_reason + with pytest.raises(ValueError): + resp.this_update + with pytest.raises(ValueError): + resp.next_update + with pytest.raises(ValueError): + resp.issuer_key_hash + with pytest.raises(ValueError): + resp.issuer_name_hash + with pytest.raises(ValueError): + resp.hash_algorithm + with pytest.raises(ValueError): + resp.serial_number + with pytest.raises(ValueError): + resp.extensions + + def test_load_revoked(self): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-revoked.der"), + ocsp.load_der_ocsp_response, + ) + assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED + assert resp.revocation_time == datetime.datetime( + 2016, 9, 2, 21, 28, 48 + ) + assert resp.revocation_reason is None + + def test_load_delegate_unknown_cert(self): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-delegate-unknown-cert.der"), + ocsp.load_der_ocsp_response, + ) + assert len(resp.certificates) == 1 + assert isinstance(resp.certificates[0], x509.Certificate) + assert resp.certificate_status == ocsp.OCSPCertStatus.UNKNOWN + + def test_load_invalid_signature_oid(self): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-invalid-signature-oid.der"), + ocsp.load_der_ocsp_response, + ) + assert resp.signature_algorithm_oid == x509.ObjectIdentifier( + "1.2.840.113549.1.1.2" + ) + with pytest.raises(UnsupportedAlgorithm): + resp.signature_hash_algorithm + + def test_load_responder_key_hash(self): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-responder-key-hash.der"), + ocsp.load_der_ocsp_response, + ) + assert resp.responder_name is None + assert resp.responder_key_hash == ( + b'\x0f\x80a\x1c\x821a\xd5/(\xe7\x8dF8\xb4,\xe1\xc6\xd9\xe2' + ) + + def test_load_revoked_reason(self): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-revoked-reason.der"), + ocsp.load_der_ocsp_response, + ) + assert resp.revocation_reason is x509.ReasonFlags.superseded + + def test_load_revoked_no_next_update(self): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-revoked-no-next-update.der"), + ocsp.load_der_ocsp_response, + ) + assert resp.serial_number == 16160 + assert resp.next_update is None + + def test_response_extensions(self): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-revoked-reason.der"), + ocsp.load_der_ocsp_response, + ) + assert len(resp.extensions) == 1 + ext = resp.extensions[0] + assert ext.critical is False + assert ext.value == x509.OCSPNonce( + b'\x04\x105\x957\x9fa\x03\x83\x87\x89rW\x8f\xae\x99\xf7"' + ) + + def test_serialize_reponse(self): + resp_bytes = load_vectors_from_file( + filename=os.path.join("x509", "ocsp", "resp-revoked.der"), + loader=lambda data: data.read(), + mode="rb" + ) + resp = ocsp.load_der_ocsp_response(resp_bytes) + assert resp.public_bytes(serialization.Encoding.DER) == resp_bytes + + def test_invalid_serialize_encoding(self): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-revoked.der"), + ocsp.load_der_ocsp_response, + ) + with pytest.raises(ValueError): + resp.public_bytes("invalid") + with pytest.raises(ValueError): + resp.public_bytes(serialization.Encoding.PEM) diff -Nru python-cryptography-2.1.4/tests/x509/test_x509_crlbuilder.py python-cryptography-2.6.1/tests/x509/test_x509_crlbuilder.py --- python-cryptography-2.1.4/tests/x509/test_x509_crlbuilder.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/x509/test_x509_crlbuilder.py 2019-02-27 23:27:53.000000000 +0000 @@ -62,10 +62,10 @@ with pytest.raises(TypeError): builder.last_update("notadatetime") - def test_last_update_before_unix_epoch(self): + def test_last_update_before_1950(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(ValueError): - builder.last_update(datetime.datetime(1960, 8, 10)) + builder.last_update(datetime.datetime(1940, 8, 10)) def test_set_last_update_twice(self): builder = x509.CertificateRevocationListBuilder().last_update( @@ -97,10 +97,10 @@ with pytest.raises(TypeError): builder.next_update("notadatetime") - def test_next_update_before_unix_epoch(self): + def test_next_update_before_1950(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(ValueError): - builder.next_update(datetime.datetime(1960, 8, 10)) + builder.next_update(datetime.datetime(1940, 8, 10)) def test_set_next_update_twice(self): builder = x509.CertificateRevocationListBuilder().next_update( diff -Nru python-cryptography-2.1.4/tests/x509/test_x509_ext.py python-cryptography-2.6.1/tests/x509/test_x509_ext.py --- python-cryptography-2.1.4/tests/x509/test_x509_ext.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/x509/test_x509_ext.py 2019-02-27 23:27:53.000000000 +0000 @@ -20,6 +20,7 @@ from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec from cryptography.x509 import DNSName, NameConstraints, SubjectAlternativeName +from cryptography.x509.general_name import _lazy_import_idna from cryptography.x509.oid import ( AuthorityInformationAccessOID, ExtendedKeyUsageOID, ExtensionOID, NameOID, ObjectIdentifier @@ -44,6 +45,17 @@ ) +def test_lazy_idna_import(): + try: + __import__("idna") + pytest.skip("idna is installed") + except ImportError: + pass + + with pytest.raises(ImportError): + _lazy_import_idna() + + class TestExtension(object): def test_not_an_oid(self): bc = x509.BasicConstraints(ca=False, path_length=None) @@ -206,7 +218,7 @@ ext1 = x509.UnrecognizedExtension( x509.ObjectIdentifier("1.2.3.4"), b"\x03\x02\x01" ) - if six.PY3: + if not six.PY2: assert repr(ext1) == ( ", value=b'\\x03\\x02\\x01')>" @@ -267,7 +279,7 @@ def test_repr(self): ci = x509.CertificateIssuer([x509.DNSName(u"cryptography.io")]) - if six.PY3: + if not six.PY2: assert repr(ci) == ( "])>)>" @@ -403,7 +415,7 @@ def test_repr(self): nr = x509.NoticeReference(u"org", [1, 3, 4]) - if six.PY3: + if not six.PY2: assert repr(nr) == ( "" @@ -447,7 +459,7 @@ def test_repr(self): un = x509.UserNotice(x509.NoticeReference(u"org", [1]), u"text") - if six.PY3: + if not six.PY2: assert repr(un) == ( ", explicit_text='text')>" @@ -513,7 +525,7 @@ def test_repr(self): pq = [u"string", x509.UserNotice(None, u"hi")] pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), pq) - if six.PY3: + if not six.PY2: assert repr(pi) == ( ", policy_qualifiers=['string', , policy_qualifi" @@ -1003,7 +1015,7 @@ binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9") ) ext = x509.Extension(ExtensionOID.SUBJECT_KEY_IDENTIFIER, False, ski) - if six.PY3: + if not six.PY2: assert repr(ext) == ( ", critical=False, value=, value='myC" - "N')>])>)>], authority_cert_serial_number=1234)>" + "cert_issuer=[)>], author" + "ity_cert_serial_number=1234)>" ) else: assert repr(aki) == ( - ", value=u'myCN')" - ">])>)>], authority_cert_serial_number=1234)>" + ")>], author" + "ity_cert_serial_number=1234)>" ) def test_eq(self): @@ -1661,18 +1671,20 @@ class TestDNSName(object): - def test_init(self): - name = x509.DNSName(u"*.xn--4ca7aey.example.com") - assert name.value == u"*.xn--4ca7aey.example.com" - - with pytest.warns(utils.DeprecatedIn21): + def test_init_deprecated(self): + pytest.importorskip("idna") + with pytest.warns(utils.CryptographyDeprecationWarning): name = x509.DNSName(u".\xf5\xe4\xf6\xfc.example.com") assert name.value == u".xn--4ca7aey.example.com" - with pytest.warns(utils.DeprecatedIn21): + with pytest.warns(utils.CryptographyDeprecationWarning): name = x509.DNSName(u"\xf5\xe4\xf6\xfc.example.com") assert name.value == u"xn--4ca7aey.example.com" + def test_init(self): + name = x509.DNSName(u"*.xn--4ca7aey.example.com") + assert name.value == u"*.xn--4ca7aey.example.com" + with pytest.raises(TypeError): x509.DNSName(1.3) @@ -1705,16 +1717,7 @@ def test_repr(self): name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'value1')]) gn = x509.DirectoryName(name) - if six.PY3: - assert repr(gn) == ( - ", value='value1')>])>)>" - ) - else: - assert repr(gn) == ( - ", value=u'value1')>])>)>" - ) + assert repr(gn) == ")>" def test_eq(self): name = x509.Name([ @@ -1756,7 +1759,7 @@ class TestRFC822Name(object): def test_repr(self): gn = x509.RFC822Name(u"string") - if six.PY3: + if not six.PY2: assert repr(gn) == "" else: assert repr(gn) == "" @@ -1788,7 +1791,8 @@ assert gn.value == u"administrator" def test_idna(self): - with pytest.warns(utils.DeprecatedIn21): + pytest.importorskip("idna") + with pytest.warns(utils.CryptographyDeprecationWarning): gn = x509.RFC822Name(u"email@em\xe5\xefl.com") assert gn.value == u"email@xn--eml-vla4c.com" @@ -1827,7 +1831,8 @@ assert gn.value == u"singlelabel:443/test" def test_idna_no_port(self): - with pytest.warns(utils.DeprecatedIn21): + pytest.importorskip("idna") + with pytest.warns(utils.CryptographyDeprecationWarning): gn = x509.UniformResourceIdentifier( u"http://\u043f\u044b\u043a\u0430.cryptography" ) @@ -1835,7 +1840,8 @@ assert gn.value == u"http://xn--80ato2c.cryptography" def test_idna_with_port(self): - with pytest.warns(utils.DeprecatedIn21): + pytest.importorskip("idna") + with pytest.warns(utils.CryptographyDeprecationWarning): gn = x509.UniformResourceIdentifier( u"gopher://\u043f\u044b\u043a\u0430.cryptography:70/some/path" ) @@ -1849,7 +1855,8 @@ assert gn.value == "ldap:///some-nonsense" def test_query_and_fragment(self): - with pytest.warns(utils.DeprecatedIn21): + pytest.importorskip("idna") + with pytest.warns(utils.CryptographyDeprecationWarning): gn = x509.UniformResourceIdentifier( u"ldap://\u043f\u044b\u043a\u0430.cryptography:90/path?query=" u"true#somedata" @@ -1868,7 +1875,7 @@ def test_repr(self): gn = x509.UniformResourceIdentifier(u"string") - if six.PY3: + if not six.PY2: assert repr(gn) == ( "" ) @@ -1962,7 +1969,7 @@ def test_repr(self): gn = x509.OtherName(x509.ObjectIdentifier("1.2.3.4"), b"derdata") - if six.PY3: + if not six.PY2: assert repr(gn) == ( ", value=b'derdata')>" @@ -1974,7 +1981,7 @@ ) gn = x509.OtherName(x509.ObjectIdentifier("2.5.4.65"), b"derdata") - if six.PY3: + if not six.PY2: assert repr(gn) == ( ", value=b'derdata')>" @@ -2058,7 +2065,7 @@ x509.DNSName(u"cryptography.io") ] ) - if six.PY3: + if not six.PY2: assert repr(gns) == ( "])>" ) @@ -2136,7 +2143,7 @@ x509.DNSName(u"cryptography.io") ] ) - if six.PY3: + if not six.PY2: assert repr(san) == ( "])>)>" @@ -2261,7 +2268,7 @@ x509.DNSName(u"cryptography.io") ] ) - if six.PY3: + if not six.PY2: assert repr(san) == ( "])>)>" @@ -2665,7 +2672,7 @@ AuthorityInformationAccessOID.OCSP, x509.UniformResourceIdentifier(u"http://ocsp.domain.com") ) - if six.PY3: + if not six.PY2: assert repr(ad) == ( ", access_location=, acces" @@ -3266,7 +3273,7 @@ permitted_subtrees=permitted, excluded_subtrees=None ) - if six.PY3: + if not six.PY2: assert repr(nc) == ( ", , value='myCN')>])>, reasons=frozenset(" - "{}), crl_issuer=[<" - "DirectoryName(value=, value='Important CA')>])>)" - ">])>" + "tinguishedName(CN=myCN)>, reasons=frozenset({}), crl_issuer=[)>])>" ) else: assert repr(dp) == ( ", value=u'myCN')>])>, reasons=frozenset" - "([]), crl_issuer=[" - ", value=u'Important CA')>])" - ">)>])>" + "tinguishedName(CN=myCN)>, reasons=frozenset([]), crl_issuer=[)>])>" ) def test_hash(self): @@ -3736,7 +3737,7 @@ None ), ]) - if six.PY3: + if not six.PY2: assert repr(fcrl) == ( "], relative" @@ -3947,7 +3948,7 @@ None ), ]) - if six.PY3: + if not six.PY2: assert repr(cdp) == ( "], relative" @@ -4426,7 +4427,7 @@ @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) class TestInhibitAnyPolicyExtension(object): - def test_nocheck(self, backend): + def test_inhibit_any_policy(self, backend): cert = _load_cert( os.path.join( "x509", "custom", "inhibit_any_policy_5.pem" @@ -4440,6 +4441,539 @@ assert iap.skip_certs == 5 +class TestIssuingDistributionPointExtension(object): + @pytest.mark.parametrize( + ("filename", "expected"), + [ + ( + "crl_idp_fullname_indirect_crl.pem", + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl") + ], + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=True, + only_contains_attribute_certs=False, + ) + ), + ( + "crl_idp_fullname_only.pem", + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl") + ], + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ) + ), + ( + "crl_idp_fullname_only_aa.pem", + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl") + ], + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=True, + ) + ), + ( + "crl_idp_fullname_only_user.pem", + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl") + ], + relative_name=None, + only_contains_user_certs=True, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ) + ), + ( + "crl_idp_only_ca.pem", + x509.IssuingDistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ]), + only_contains_user_certs=False, + only_contains_ca_certs=True, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ) + ), + ( + "crl_idp_reasons_only.pem", + x509.IssuingDistributionPoint( + full_name=None, + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=frozenset([ + x509.ReasonFlags.key_compromise + ]), + indirect_crl=False, + only_contains_attribute_certs=False, + ) + ), + ( + "crl_idp_relative_user_all_reasons.pem", + x509.IssuingDistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ]), + only_contains_user_certs=True, + only_contains_ca_certs=False, + only_some_reasons=frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + x509.ReasonFlags.affiliation_changed, + x509.ReasonFlags.superseded, + x509.ReasonFlags.cessation_of_operation, + x509.ReasonFlags.certificate_hold, + x509.ReasonFlags.privilege_withdrawn, + x509.ReasonFlags.aa_compromise, + ]), + indirect_crl=False, + only_contains_attribute_certs=False, + ) + ), + ( + "crl_idp_relativename_only.pem", + x509.IssuingDistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ]), + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ) + ), + ] + ) + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_vectors(self, filename, expected, backend): + crl = _load_cert( + os.path.join("x509", "custom", filename), + x509.load_pem_x509_crl, backend + ) + idp = crl.extensions.get_extension_for_class( + x509.IssuingDistributionPoint + ).value + assert idp == expected + + @pytest.mark.parametrize( + ( + "error", "only_contains_user_certs", "only_contains_ca_certs", + "indirect_crl", "only_contains_attribute_certs", + "only_some_reasons", "full_name", "relative_name" + ), + [ + ( + TypeError, False, False, False, False, 'notafrozenset', None, + None + ), + ( + TypeError, False, False, False, False, frozenset(['bad']), + None, None + ), + ( + ValueError, False, False, False, False, + frozenset([x509.ReasonFlags.unspecified]), None, None + ), + ( + ValueError, False, False, False, False, + frozenset([x509.ReasonFlags.remove_from_crl]), None, None + ), + (TypeError, 'notabool', False, False, False, None, None, None), + (TypeError, False, 'notabool', False, False, None, None, None), + (TypeError, False, False, 'notabool', False, None, None, None), + (TypeError, False, False, False, 'notabool', None, None, None), + (ValueError, True, True, False, False, None, None, None), + (ValueError, False, False, True, True, None, None, None), + (ValueError, False, False, False, False, None, None, None), + ] + ) + def test_invalid_init(self, error, only_contains_user_certs, + only_contains_ca_certs, indirect_crl, + only_contains_attribute_certs, only_some_reasons, + full_name, relative_name): + with pytest.raises(error): + x509.IssuingDistributionPoint( + full_name, relative_name, only_contains_user_certs, + only_contains_ca_certs, only_some_reasons, indirect_crl, + only_contains_attribute_certs + ) + + def test_repr(self): + idp = x509.IssuingDistributionPoint( + None, None, False, False, + frozenset([x509.ReasonFlags.key_compromise]), False, False + ) + if not six.PY2: + assert repr(idp) == ( + "}), indirect_crl=False, only_contains_attribut" + "e_certs=False)>" + ) + else: + assert repr(idp) == ( + "]), indirect_crl=False, only_contains_attribut" + "e_certs=False)>" + ) + + def test_eq(self): + idp1 = x509.IssuingDistributionPoint( + only_contains_user_certs=False, + only_contains_ca_certs=False, + indirect_crl=False, + only_contains_attribute_certs=False, + only_some_reasons=None, + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") + ]) + ) + idp2 = x509.IssuingDistributionPoint( + only_contains_user_certs=False, + only_contains_ca_certs=False, + indirect_crl=False, + only_contains_attribute_certs=False, + only_some_reasons=None, + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") + ]) + ) + assert idp1 == idp2 + + def test_ne(self): + idp1 = x509.IssuingDistributionPoint( + only_contains_user_certs=False, + only_contains_ca_certs=False, + indirect_crl=False, + only_contains_attribute_certs=False, + only_some_reasons=None, + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") + ]) + ) + idp2 = x509.IssuingDistributionPoint( + only_contains_user_certs=True, + only_contains_ca_certs=False, + indirect_crl=False, + only_contains_attribute_certs=False, + only_some_reasons=None, + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") + ]) + ) + assert idp1 != idp2 + assert idp1 != object() + + def test_hash(self): + idp1 = x509.IssuingDistributionPoint( + None, None, True, False, None, False, False + ) + idp2 = x509.IssuingDistributionPoint( + None, None, True, False, None, False, False + ) + idp3 = x509.IssuingDistributionPoint( + None, + x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") + ]), + True, False, None, False, False + ) + assert hash(idp1) == hash(idp2) + assert hash(idp1) != hash(idp3) + + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + @pytest.mark.parametrize( + "idp", + [ + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl" + ) + ], + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=True, + only_contains_attribute_certs=False, + ), + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl" + ) + ], + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ), + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl" + ) + ], + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=True, + ), + x509.IssuingDistributionPoint( + full_name=[ + x509.UniformResourceIdentifier( + u"http://myhost.com/myca.crl" + ) + ], + relative_name=None, + only_contains_user_certs=True, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ), + x509.IssuingDistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ]), + only_contains_user_certs=False, + only_contains_ca_certs=True, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ), + x509.IssuingDistributionPoint( + full_name=None, + relative_name=None, + only_contains_user_certs=False, + only_contains_ca_certs=True, + only_some_reasons=frozenset([x509.ReasonFlags.key_compromise]), + indirect_crl=False, + only_contains_attribute_certs=False, + ), + x509.IssuingDistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA"), + x509.NameAttribute( + oid=x509.NameOID.COMMON_NAME, value=u"cryptography") + ]), + only_contains_user_certs=True, + only_contains_ca_certs=False, + only_some_reasons=frozenset([ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + x509.ReasonFlags.affiliation_changed, + x509.ReasonFlags.privilege_withdrawn, + x509.ReasonFlags.aa_compromise, + ]), + indirect_crl=False, + only_contains_attribute_certs=False, + ), + x509.IssuingDistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ]), + only_contains_user_certs=False, + only_contains_ca_certs=False, + only_some_reasons=None, + indirect_crl=False, + only_contains_attribute_certs=False, + ), + ] + ) + def test_generate(self, idp, backend): + key = RSA_KEY_2048.private_key(backend) + last_update = datetime.datetime(2002, 1, 1, 12, 1) + next_update = datetime.datetime(2030, 1, 1, 12, 1) + builder = x509.CertificateRevocationListBuilder().issuer_name( + x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") + ]) + ).last_update( + last_update + ).next_update( + next_update + ).add_extension( + idp, True + ) + + crl = builder.sign(key, hashes.SHA256(), backend) + ext = crl.extensions.get_extension_for_class( + x509.IssuingDistributionPoint + ) + assert ext.critical is True + assert ext.value == idp + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestPrecertPoisonExtension(object): + def test_load(self, backend): + cert = _load_cert( + os.path.join("x509", "cryptography.io.precert.pem"), + x509.load_pem_x509_certificate, + backend + ) + poison = cert.extensions.get_extension_for_oid( + ExtensionOID.PRECERT_POISON + ).value + assert isinstance(poison, x509.PrecertPoison) + poison = cert.extensions.get_extension_for_class( + x509.PrecertPoison + ).value + assert isinstance(poison, x509.PrecertPoison) + + def test_generate(self, backend): + private_key = RSA_KEY_2048.private_key(backend) + cert = _make_certbuilder(private_key).add_extension( + x509.PrecertPoison(), critical=True + ).sign(private_key, hashes.SHA256(), backend) + poison = cert.extensions.get_extension_for_oid( + ExtensionOID.PRECERT_POISON + ).value + assert isinstance(poison, x509.PrecertPoison) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestSignedCertificateTimestamps(object): + @pytest.mark.supported( + only_if=lambda backend: ( + backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), + skip_message="Requires OpenSSL 1.1.0f+", + ) + def test_eq(self, backend): + sct = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value[0] + sct2 = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value[0] + assert sct == sct2 + + @pytest.mark.supported( + only_if=lambda backend: ( + backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), + skip_message="Requires OpenSSL 1.1.0f+", + ) + def test_ne(self, backend): + sct = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value[0] + sct2 = _load_cert( + os.path.join("x509", "cryptography-scts.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value[0] + assert sct != sct2 + assert sct != object() + + @pytest.mark.supported( + only_if=lambda backend: ( + backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), + skip_message="Requires OpenSSL 1.1.0f+", + ) + def test_hash(self, backend): + sct = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value[0] + sct2 = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value[0] + sct3 = _load_cert( + os.path.join("x509", "cryptography-scts.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value[0] + assert hash(sct) == hash(sct2) + assert hash(sct) != hash(sct3) + + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) class TestPrecertificateSignedCertificateTimestampsExtension(object): @@ -4457,6 +4991,81 @@ backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), skip_message="Requires OpenSSL 1.1.0f+", ) + def test_eq(self, backend): + psct1 = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value + psct2 = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value + assert psct1 == psct2 + + @pytest.mark.supported( + only_if=lambda backend: ( + backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), + skip_message="Requires OpenSSL 1.1.0f+", + ) + def test_ne(self, backend): + psct1 = _load_cert( + os.path.join("x509", "cryptography-scts.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value + psct2 = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value + assert psct1 != psct2 + assert psct1 != object() + + @pytest.mark.supported( + only_if=lambda backend: ( + backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), + skip_message="Requires OpenSSL 1.1.0f+", + ) + def test_hash(self, backend): + psct1 = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value + psct2 = _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value + psct3 = _load_cert( + os.path.join("x509", "cryptography-scts.pem"), + x509.load_pem_x509_certificate, + backend + ).extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ).value + assert hash(psct1) == hash(psct2) + assert hash(psct1) != hash(psct3) + + @pytest.mark.supported( + only_if=lambda backend: ( + backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), + skip_message="Requires OpenSSL 1.1.0f+", + ) def test_simple(self, backend): cert = _load_cert( os.path.join("x509", "badssl-sct.pem"), @@ -4518,3 +5127,34 @@ ) with pytest.raises(ValueError): cert.extensions + + +class TestOCSPNonce(object): + def test_non_bytes(self): + with pytest.raises(TypeError): + x509.OCSPNonce(38) + + def test_eq(self): + nonce1 = x509.OCSPNonce(b"0" * 5) + nonce2 = x509.OCSPNonce(b"0" * 5) + assert nonce1 == nonce2 + + def test_ne(self): + nonce1 = x509.OCSPNonce(b"0" * 5) + nonce2 = x509.OCSPNonce(b"0" * 6) + assert nonce1 != nonce2 + assert nonce1 != object() + + def test_repr(self): + nonce1 = x509.OCSPNonce(b"nonce") + if not six.PY2: + assert repr(nonce1) == "" + else: + assert repr(nonce1) == "" + + def test_hash(self): + nonce1 = x509.OCSPNonce(b"0" * 5) + nonce2 = x509.OCSPNonce(b"0" * 5) + nonce3 = x509.OCSPNonce(b"1" * 5) + assert hash(nonce1) == hash(nonce2) + assert hash(nonce1) != hash(nonce3) diff -Nru python-cryptography-2.1.4/tests/x509/test_x509.py python-cryptography-2.6.1/tests/x509/test_x509.py --- python-cryptography-2.1.4/tests/x509/test_x509.py 2017-11-30 01:54:42.000000000 +0000 +++ python-cryptography-2.6.1/tests/x509/test_x509.py 2019-02-27 23:27:53.000000000 +0000 @@ -8,7 +8,6 @@ import datetime import ipaddress import os -import sys from asn1crypto.x509 import Certificate @@ -111,7 +110,7 @@ ) with pytest.raises(UnsupportedAlgorithm): - crl.signature_hash_algorithm() + crl.signature_hash_algorithm() def test_issuer(self, backend): crl = _load_cert( @@ -181,6 +180,18 @@ # Check that len() works for CRLs. assert len(crl) == 12 + def test_get_revoked_certificate_by_serial_number(self, backend): + crl = _load_cert( + os.path.join( + "x509", "PKITS_data", "crls", "LongSerialNumberCACRL.crl"), + x509.load_der_x509_crl, + backend + ) + serial_number = 725064303890588110203033396814564464046290047507 + revoked = crl.get_revoked_certificate_by_serial_number(serial_number) + assert revoked.serial_number == serial_number + assert crl.get_revoked_certificate_by_serial_number(500) is None + def test_revoked_cert_retrieval_retain_only_revoked(self, backend): """ This test attempts to trigger the crash condition described in @@ -278,11 +289,10 @@ backend ) - verifier = ca_cert.public_key().verifier( - crl.signature, padding.PKCS1v15(), crl.signature_hash_algorithm + ca_cert.public_key().verify( + crl.signature, crl.tbs_certlist_bytes, + padding.PKCS1v15(), crl.signature_hash_algorithm ) - verifier.update(crl.tbs_certlist_bytes) - verifier.verify() def test_public_bytes_pem(self, backend): crl = _load_cert( @@ -539,6 +549,35 @@ assert crl[2:4][0].serial_number == crl[2].serial_number assert crl[2:4][1].serial_number == crl[3].serial_number + def test_get_revoked_certificate_doesnt_reorder(self, backend): + private_key = RSA_KEY_2048.private_key(backend) + last_update = datetime.datetime(2002, 1, 1, 12, 1) + next_update = datetime.datetime(2030, 1, 1, 12, 1) + builder = x509.CertificateRevocationListBuilder().issuer_name( + x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") + ]) + ).last_update( + last_update + ).next_update( + next_update + ) + for i in [2, 500, 3, 49, 7, 1]: + revoked_cert = x509.RevokedCertificateBuilder().serial_number( + i + ).revocation_date( + datetime.datetime(2012, 1, 1, 1, 1) + ).build(backend) + builder = builder.add_revoked_certificate(revoked_cert) + crl = builder.sign(private_key, hashes.SHA256(), backend) + assert crl[0].serial_number == 2 + assert crl[2].serial_number == 3 + # make sure get_revoked_certificate_by_serial_number doesn't affect + # ordering after being invoked + crl.get_revoked_certificate_by_serial_number(500) + assert crl[0].serial_number == 2 + assert crl[2].serial_number == 3 + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) @@ -570,27 +609,6 @@ SignatureAlgorithmOID._RSA_WITH_SHA1 ) - def test_cert_serial_number(self, backend): - cert = _load_cert( - os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), - x509.load_der_x509_certificate, - backend - ) - - with pytest.deprecated_call(): - assert cert.serial == 2 - assert cert.serial_number == 2 - - def test_cert_serial_warning(self, backend): - cert = _load_cert( - os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), - x509.load_der_x509_certificate, - backend - ) - - with pytest.deprecated_call(): - cert.serial - def test_load_der_cert(self, backend): cert = _load_cert( os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), @@ -654,11 +672,10 @@ b"03550403130848656c6c6f204341820900a06cb4b955f7f4db300c0603551d1" b"3040530030101ff" ) - verifier = cert.public_key().verifier( - cert.signature, padding.PKCS1v15(), cert.signature_hash_algorithm + cert.public_key().verify( + cert.signature, cert.tbs_certificate_bytes, + padding.PKCS1v15(), cert.signature_hash_algorithm ) - verifier.update(cert.tbs_certificate_bytes) - verifier.verify() def test_issuer(self, backend): cert = _load_cert( @@ -1099,30 +1116,11 @@ x509.load_pem_x509_certificate, backend ) - if six.PY3: - assert repr(cert) == ( - ", value='GT487" - "42965')>, , value='See www.rapidssl.com/re" - "sources/cps (c)14')>, , value='Domain Cont" - "rol Validated - RapidSSL(R)')>, , value='www.cryptograp" - "hy.io')>])>, ...)>" - ) - else: - assert repr(cert) == ( - ", value=u'GT48" - "742965')>, , value=u'See www.rapidssl.com/" - "resources/cps (c)14')>, , value=u'Domain C" - "ontrol Validated - RapidSSL(R)')>, , value=u'www.crypto" - "graphy.io')>])>, ...)>" - ) + assert repr(cert) == ( + ", ...)>" + ) def test_parse_tls_feature_extension(self, backend): cert = _load_cert( @@ -1357,13 +1355,12 @@ b"db048d51921e50766a37b1b130ee6b11f507d20a834001e8de16a92c14f2e964" b"a30203010001a000" ) - verifier = request.public_key().verifier( + request.public_key().verify( request.signature, + request.tbs_certrequest_bytes, padding.PKCS1v15(), request.signature_hash_algorithm ) - verifier.update(request.tbs_certrequest_bytes) - verifier.verify() def test_public_bytes_invalid_encoding(self, backend): request = _load_cert( @@ -1650,18 +1647,69 @@ builder.sign(private_key, hashes.SHA256(), backend) - @pytest.mark.skipif(sys.platform != "win32", reason="Requires windows") + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_subject_dn_asn1_types(self, backend): + private_key = RSA_KEY_2048.private_key(backend) + + name = x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u"mysite.com"), + x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), + x509.NameAttribute(NameOID.LOCALITY_NAME, u"value"), + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"value"), + x509.NameAttribute(NameOID.STREET_ADDRESS, u"value"), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"value"), + x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, u"value"), + x509.NameAttribute(NameOID.SERIAL_NUMBER, u"value"), + x509.NameAttribute(NameOID.SURNAME, u"value"), + x509.NameAttribute(NameOID.GIVEN_NAME, u"value"), + x509.NameAttribute(NameOID.TITLE, u"value"), + x509.NameAttribute(NameOID.GENERATION_QUALIFIER, u"value"), + x509.NameAttribute(NameOID.X500_UNIQUE_IDENTIFIER, u"value"), + x509.NameAttribute(NameOID.DN_QUALIFIER, u"value"), + x509.NameAttribute(NameOID.PSEUDONYM, u"value"), + x509.NameAttribute(NameOID.USER_ID, u"value"), + x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u"value"), + x509.NameAttribute(NameOID.EMAIL_ADDRESS, u"value"), + x509.NameAttribute(NameOID.JURISDICTION_COUNTRY_NAME, u"US"), + x509.NameAttribute(NameOID.JURISDICTION_LOCALITY_NAME, u"value"), + x509.NameAttribute( + NameOID.JURISDICTION_STATE_OR_PROVINCE_NAME, u"value" + ), + x509.NameAttribute(NameOID.BUSINESS_CATEGORY, u"value"), + x509.NameAttribute(NameOID.POSTAL_ADDRESS, u"value"), + x509.NameAttribute(NameOID.POSTAL_CODE, u"value"), + ]) + cert = x509.CertificateBuilder().subject_name( + name + ).issuer_name( + name + ).public_key( + private_key.public_key() + ).serial_number( + 777 + ).not_valid_before( + datetime.datetime(1999, 1, 1) + ).not_valid_after( + datetime.datetime(2020, 1, 1) + ).sign(private_key, hashes.SHA256(), backend) + + for dn in (cert.subject, cert.issuer): + for oid, asn1_type in TestNameAttribute.EXPECTED_TYPES: + assert dn.get_attributes_for_oid( + oid + )[0]._type == asn1_type + @pytest.mark.parametrize( ("not_valid_before", "not_valid_after"), [ - [datetime.datetime(1999, 1, 1), datetime.datetime(9999, 1, 1)], - [datetime.datetime(9999, 1, 1), datetime.datetime(9999, 12, 31)], + [datetime.datetime(1970, 2, 1), datetime.datetime(9999, 1, 1)], + [datetime.datetime(1970, 2, 1), datetime.datetime(9999, 12, 31)], ] ) @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) - def test_invalid_time_windows(self, not_valid_before, not_valid_after, - backend): + def test_extreme_times(self, not_valid_before, not_valid_after, backend): private_key = RSA_KEY_2048.private_key(backend) builder = x509.CertificateBuilder().subject_name(x509.Name([ x509.NameAttribute(NameOID.COUNTRY_NAME, u'US'), @@ -1676,8 +1724,16 @@ ).not_valid_after( not_valid_after ) - with pytest.raises(ValueError): - builder.sign(private_key, hashes.SHA256(), backend) + cert = builder.sign(private_key, hashes.SHA256(), backend) + assert cert.not_valid_before == not_valid_before + assert cert.not_valid_after == not_valid_after + parsed = Certificate.load( + cert.public_bytes(serialization.Encoding.DER) + ) + not_before = parsed['tbs_certificate']['validity']['not_before'] + not_after = parsed['tbs_certificate']['validity']['not_after'] + assert not_before.chosen.tag == 23 # UTCTime + assert not_after.chosen.tag == 24 # GeneralizedTime @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) @@ -1950,6 +2006,35 @@ cert = cert_builder.sign(private_key, hashes.SHA256(), backend) assert cert.not_valid_after == utc_time + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_earliest_time(self, backend): + time = datetime.datetime(1950, 1, 1) + private_key = RSA_KEY_2048.private_key(backend) + cert_builder = x509.CertificateBuilder().subject_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) + ).issuer_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) + ).serial_number( + 1 + ).public_key( + private_key.public_key() + ).not_valid_before( + time + ).not_valid_after( + time + ) + cert = cert_builder.sign(private_key, hashes.SHA256(), backend) + assert cert.not_valid_before == time + assert cert.not_valid_after == time + parsed = Certificate.load( + cert.public_bytes(serialization.Encoding.DER) + ) + not_before = parsed['tbs_certificate']['validity']['not_before'] + not_after = parsed['tbs_certificate']['validity']['not_after'] + assert not_before.chosen.tag == 23 # UTCTime + assert not_after.chosen.tag == 23 # UTCTime + def test_invalid_not_valid_after(self): with pytest.raises(TypeError): x509.CertificateBuilder().not_valid_after(104204304504) @@ -1959,7 +2044,7 @@ with pytest.raises(ValueError): x509.CertificateBuilder().not_valid_after( - datetime.datetime(1960, 8, 10) + datetime.datetime(1940, 8, 10) ) def test_not_valid_after_may_only_be_set_once(self): @@ -2005,7 +2090,7 @@ with pytest.raises(ValueError): x509.CertificateBuilder().not_valid_before( - datetime.datetime(1960, 8, 10) + datetime.datetime(1940, 8, 10) ) def test_not_valid_before_may_only_be_set_once(self): @@ -2507,6 +2592,23 @@ crl_issuer=None, ) ]), + x509.FreshestCRL([ + x509.DistributionPoint( + full_name=None, + relative_name=x509.RelativeDistinguishedName([ + x509.NameAttribute( + NameOID.COMMON_NAME, + u"indirect CRL for indirectCRL CA3" + ), + x509.NameAttribute( + NameOID.COUNTRY_NAME, + u"US" + ), + ]), + reasons=None, + crl_issuer=None, + ) + ]), ] ) def test_ext(self, add_ext, backend): @@ -2748,6 +2850,47 @@ ] @pytest.mark.requires_backend_interface(interface=RSABackend) + def test_subject_dn_asn1_types(self, backend): + private_key = RSA_KEY_2048.private_key(backend) + + request = x509.CertificateSigningRequestBuilder().subject_name( + x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u"mysite.com"), + x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), + x509.NameAttribute(NameOID.LOCALITY_NAME, u"value"), + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"value"), + x509.NameAttribute(NameOID.STREET_ADDRESS, u"value"), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"value"), + x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, u"value"), + x509.NameAttribute(NameOID.SERIAL_NUMBER, u"value"), + x509.NameAttribute(NameOID.SURNAME, u"value"), + x509.NameAttribute(NameOID.GIVEN_NAME, u"value"), + x509.NameAttribute(NameOID.TITLE, u"value"), + x509.NameAttribute(NameOID.GENERATION_QUALIFIER, u"value"), + x509.NameAttribute(NameOID.X500_UNIQUE_IDENTIFIER, u"value"), + x509.NameAttribute(NameOID.DN_QUALIFIER, u"value"), + x509.NameAttribute(NameOID.PSEUDONYM, u"value"), + x509.NameAttribute(NameOID.USER_ID, u"value"), + x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u"value"), + x509.NameAttribute(NameOID.EMAIL_ADDRESS, u"value"), + x509.NameAttribute(NameOID.JURISDICTION_COUNTRY_NAME, u"US"), + x509.NameAttribute( + NameOID.JURISDICTION_LOCALITY_NAME, u"value" + ), + x509.NameAttribute( + NameOID.JURISDICTION_STATE_OR_PROVINCE_NAME, u"value" + ), + x509.NameAttribute(NameOID.BUSINESS_CATEGORY, u"value"), + x509.NameAttribute(NameOID.POSTAL_ADDRESS, u"value"), + x509.NameAttribute(NameOID.POSTAL_CODE, u"value"), + ]) + ).sign(private_key, hashes.SHA256(), backend) + for oid, asn1_type in TestNameAttribute.EXPECTED_TYPES: + assert request.subject.get_attributes_for_oid( + oid + )[0]._type == asn1_type + + @pytest.mark.requires_backend_interface(interface=RSABackend) def test_build_ca_request_with_multivalue_rdns(self, backend): private_key = RSA_KEY_2048.private_key(backend) subject = x509.Name([ @@ -3018,9 +3161,9 @@ ), x509.RFC822Name(u"test@example.com"), x509.RFC822Name(u"email"), - x509.RFC822Name(u"email@em\xe5\xefl.com"), + x509.RFC822Name(u"email@xn--eml-vla4c.com"), x509.UniformResourceIdentifier( - u"https://\u043f\u044b\u043a\u0430.cryptography" + u"https://xn--80ato2c.cryptography" ), x509.UniformResourceIdentifier( u"gopher://cryptography:70/some/path" @@ -3411,11 +3554,10 @@ b"4c7464311430120603550403130b5079434120445341204341820900a37352e" b"0b2142f86300c0603551d13040530030101ff" ) - verifier = cert.public_key().verifier( - cert.signature, cert.signature_hash_algorithm + cert.public_key().verify( + cert.signature, cert.tbs_certificate_bytes, + cert.signature_hash_algorithm ) - verifier.update(cert.tbs_certificate_bytes) - verifier.verify() @pytest.mark.requires_backend_interface(interface=DSABackend) @@ -3485,12 +3627,11 @@ b"04a697bc8fd965b952f9f7e850edf13c8acdb5d753b6d10e59e0b5732e3c82ba" b"fa140342bc4a3bba16bd0681c8a6a2dbbb7efe6ce2b8463b170ba000" ) - verifier = request.public_key().verifier( + request.public_key().verify( request.signature, + request.tbs_certrequest_bytes, request.signature_hash_algorithm ) - verifier.update(request.tbs_certrequest_bytes) - verifier.verify() @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) @@ -3565,11 +3706,10 @@ b"f300e0603551d0f0101ff040403020186301d0603551d0e04160414b3db48a4" b"f9a1c5d8ae3641cc1163696229bc4bc6" ) - verifier = cert.public_key().verifier( - cert.signature, ec.ECDSA(cert.signature_hash_algorithm) + cert.public_key().verify( + cert.signature, cert.tbs_certificate_bytes, + ec.ECDSA(cert.signature_hash_algorithm) ) - verifier.update(cert.tbs_certificate_bytes) - verifier.verify() def test_load_ecdsa_no_named_curve(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) @@ -3644,12 +3784,10 @@ b"04d8b32a551038d09086803a6d3fb91a1a1167ec02158b00efad39c9396462f" b"accff0ffaf7155812909d3726bd59fde001cff4bb9b2f5af8cbaa000" ) - verifier = request.public_key().verifier( - request.signature, + request.public_key().verify( + request.signature, request.tbs_certrequest_bytes, ec.ECDSA(request.signature_hash_algorithm) ) - verifier.update(request.tbs_certrequest_bytes) - verifier.verify() @pytest.mark.requires_backend_interface(interface=X509Backend) @@ -3666,8 +3804,61 @@ with pytest.raises(ValueError): cert.public_key() + def test_bad_time_in_validity(self, backend): + cert = _load_cert( + os.path.join( + "x509", "badasn1time.pem" + ), + x509.load_pem_x509_certificate, + backend, + ) + + with pytest.raises(ValueError, match='19020701025736Z'): + cert.not_valid_after + class TestNameAttribute(object): + EXPECTED_TYPES = [ + (NameOID.COMMON_NAME, _ASN1Type.UTF8String), + (NameOID.COUNTRY_NAME, _ASN1Type.PrintableString), + (NameOID.LOCALITY_NAME, _ASN1Type.UTF8String), + (NameOID.STATE_OR_PROVINCE_NAME, _ASN1Type.UTF8String), + (NameOID.STREET_ADDRESS, _ASN1Type.UTF8String), + (NameOID.ORGANIZATION_NAME, _ASN1Type.UTF8String), + (NameOID.ORGANIZATIONAL_UNIT_NAME, _ASN1Type.UTF8String), + (NameOID.SERIAL_NUMBER, _ASN1Type.PrintableString), + (NameOID.SURNAME, _ASN1Type.UTF8String), + (NameOID.GIVEN_NAME, _ASN1Type.UTF8String), + (NameOID.TITLE, _ASN1Type.UTF8String), + (NameOID.GENERATION_QUALIFIER, _ASN1Type.UTF8String), + (NameOID.X500_UNIQUE_IDENTIFIER, _ASN1Type.UTF8String), + (NameOID.DN_QUALIFIER, _ASN1Type.PrintableString), + (NameOID.PSEUDONYM, _ASN1Type.UTF8String), + (NameOID.USER_ID, _ASN1Type.UTF8String), + (NameOID.DOMAIN_COMPONENT, _ASN1Type.IA5String), + (NameOID.EMAIL_ADDRESS, _ASN1Type.IA5String), + (NameOID.JURISDICTION_COUNTRY_NAME, _ASN1Type.PrintableString), + (NameOID.JURISDICTION_LOCALITY_NAME, _ASN1Type.UTF8String), + ( + NameOID.JURISDICTION_STATE_OR_PROVINCE_NAME, + _ASN1Type.UTF8String + ), + (NameOID.BUSINESS_CATEGORY, _ASN1Type.UTF8String), + (NameOID.POSTAL_ADDRESS, _ASN1Type.UTF8String), + (NameOID.POSTAL_CODE, _ASN1Type.UTF8String), + ] + + def test_default_types(self): + for oid, asn1_type in TestNameAttribute.EXPECTED_TYPES: + na = x509.NameAttribute(oid, u"US") + assert na._type == asn1_type + + def test_alternate_type(self): + na2 = x509.NameAttribute( + NameOID.COMMON_NAME, u"common", _ASN1Type.IA5String + ) + assert na2._type == _ASN1Type.IA5String + def test_init_bad_oid(self): with pytest.raises(TypeError): x509.NameAttribute(None, u'value') @@ -3697,22 +3888,6 @@ with pytest.raises(ValueError): x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'') - def test_country_name_type(self): - na = x509.NameAttribute(NameOID.COUNTRY_NAME, u"US") - assert na._type == _ASN1Type.PrintableString - na2 = x509.NameAttribute( - NameOID.COUNTRY_NAME, u"US", _ASN1Type.IA5String - ) - assert na2._type == _ASN1Type.IA5String - - def test_types(self): - na = x509.NameAttribute(NameOID.COMMON_NAME, u"common") - assert na._type == _ASN1Type.UTF8String - na2 = x509.NameAttribute( - NameOID.COMMON_NAME, u"common", _ASN1Type.IA5String - ) - assert na2._type == _ASN1Type.IA5String - def test_invalid_type(self): with pytest.raises(TypeError): x509.NameAttribute(NameOID.COMMON_NAME, u"common", "notanenum") @@ -3741,7 +3916,7 @@ def test_repr(self): na = x509.NameAttribute(x509.ObjectIdentifier('2.5.4.3'), u'value') - if six.PY3: + if not six.PY2: assert repr(na) == ( ", value='value')>" @@ -3752,6 +3927,18 @@ "nName)>, value=u'value')>" ) + def test_distinugished_name(self): + # Escaping + na = x509.NameAttribute(NameOID.COMMON_NAME, u'James "Jim" Smith, III') + assert na.rfc4514_string() == r'CN=James \"Jim\" Smith\, III' + na = x509.NameAttribute(NameOID.USER_ID, u'# escape+,;\0this ') + assert na.rfc4514_string() == r'UID=\# escape\+\,\;\00this\ ' + + # Nonstandard attribute OID + na = x509.NameAttribute(NameOID.EMAIL_ADDRESS, u'somebody@example.com') + assert (na.rfc4514_string() == + '1.2.840.113549.1.9.1=somebody@example.com') + class TestRelativeDistinguishedName(object): def test_init_empty(self): @@ -3763,11 +3950,11 @@ x509.RelativeDistinguishedName(["not-a-NameAttribute"]) def test_init_duplicate_attribute(self): - rdn = x509.RelativeDistinguishedName([ - x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'), - x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'), - ]) - assert len(rdn) == 1 + with pytest.raises(ValueError): + x509.RelativeDistinguishedName([ + x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'val1'), + x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'val1'), + ]) def test_hash(self): rdn1 = x509.RelativeDistinguishedName([ @@ -3809,8 +3996,11 @@ assert rdn1 != object() def test_iter_input(self): + # Order must be preserved too attrs = [ - x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1') + x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1'), + x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value2'), + x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value3') ] rdn = x509.RelativeDistinguishedName(iter(attrs)) assert list(rdn) == attrs @@ -3936,20 +4126,23 @@ x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'PyCA'), ]) - if six.PY3: - assert repr(name) == ( - ", value='cryptography.io')>, , valu" - "e='PyCA')>])>" - ) - else: - assert repr(name) == ( - ", value=u'cryptography.io')>, , val" - "ue=u'PyCA')>])>" - ) + assert repr(name) == "" + + def test_rfc4514_string(self): + n = x509.Name([ + x509.RelativeDistinguishedName([ + x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, u'Sales'), + x509.NameAttribute(NameOID.COMMON_NAME, u'J. Smith'), + ]), + x509.RelativeDistinguishedName([ + x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u'example'), + ]), + x509.RelativeDistinguishedName([ + x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u'net'), + ]), + ]) + assert (n.rfc4514_string() == + 'OU=Sales+CN=J. Smith,DC=example,DC=net') def test_not_nameattribute(self): with pytest.raises(TypeError): @@ -3966,6 +4159,24 @@ b"b060355040a0c0450794341" ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_bmpstring_bytes(self, backend): + # For this test we need an odd length string. BMPString is UCS-2 + # encoded so it will always be even length and OpenSSL will error if + # you pass an odd length string without encoding it properly first. + name = x509.Name([ + x509.NameAttribute( + NameOID.COMMON_NAME, + u'cryptography.io', + _ASN1Type.BMPString + ), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'PyCA'), + ]) + assert name.public_bytes(backend) == binascii.unhexlify( + b"30383127302506035504031e1e00630072007900700074006f00670072006100" + b"7000680079002e0069006f310d300b060355040a0c0450794341" + ) + def test_random_serial_number(monkeypatch): sample_data = os.urandom(20) @@ -3981,4 +4192,4 @@ assert ( serial_number == utils.int_from_bytes(sample_data, "big") >> 1 ) - assert utils.bit_length(serial_number) < 160 + assert serial_number.bit_length() < 160 diff -Nru python-cryptography-2.1.4/tests/x509/test_x509_revokedcertbuilder.py python-cryptography-2.6.1/tests/x509/test_x509_revokedcertbuilder.py --- python-cryptography-2.1.4/tests/x509/test_x509_revokedcertbuilder.py 2017-11-30 01:53:32.000000000 +0000 +++ python-cryptography-2.6.1/tests/x509/test_x509_revokedcertbuilder.py 2019-02-27 23:27:53.000000000 +0000 @@ -80,10 +80,10 @@ with pytest.raises(TypeError): x509.RevokedCertificateBuilder().revocation_date("notadatetime") - def test_revocation_date_before_unix_epoch(self): + def test_revocation_date_before_1950(self): with pytest.raises(ValueError): x509.RevokedCertificateBuilder().revocation_date( - datetime.datetime(1960, 8, 10) + datetime.datetime(1940, 8, 10) ) def test_set_revocation_date_twice(self):