From c22f3230f28d02362c626bec6c6bf6d82e7e06d9 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 7 Feb 2021 14:38:03 -0500 Subject: [PATCH 0001/1456] fix macos target for wheel builder (#5751) --- .github/workflows/wheel-builder.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 528c07fd4ac0..fa564effeae8 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -92,6 +92,8 @@ jobs: LDFLAGS="${HOME}/openssl-macos-x86-64/lib/libcrypto.a ${HOME}/openssl-macos-x86-64/lib/libssl.a" \ CFLAGS="-I${HOME}/openssl-macos-x86-64/include -mmacosx-version-min=10.10 -march=core2" \ ../venv/bin/python setup.py bdist_wheel --py-limited-api=${{ matrix.PYTHON.ABI_VERSION }} && mv dist/cryptography*.whl ../wheelhouse + env: + MACOSX_DEPLOYMENT_TARGET: "10.10" - run: venv/bin/pip install -f wheelhouse --no-index cryptography - run: | venv/bin/python -c "from cryptography.hazmat.backends.openssl.backend import backend;print('Loaded: ' + backend.openssl_version_text());print('Linked Against: ' + backend._ffi.string(backend._lib.OPENSSL_VERSION_TEXT).decode('ascii'))" From 9f931ff99e13f68e6b8235d7ccdd0e688435fa52 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 7 Feb 2021 14:38:15 -0500 Subject: [PATCH 0002/1456] fixed manylinxu wheel builder for rust (#5750) --- .github/workflows/wheel-builder.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index fa564effeae8..cb7b11615684 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -32,6 +32,8 @@ jobs: LDFLAGS="-L/opt/pyca/cryptography/openssl/lib" \ CFLAGS="-I/opt/pyca/cryptography/openssl/include -Wl,--exclude-libs,ALL" \ ../.venv/bin/python setup.py bdist_wheel $PY_LIMITED_API && mv dist/cryptography*.whl ../tmpwheelhouse + env: + RUSTUP_HOME: /root/.rustup - run: auditwheel repair --plat ${{ matrix.MANYLINUX.NAME }} tmpwheelhouse/cryptograph*.whl -w wheelhouse/ - run: unzip wheelhouse/*.whl -d execstack.check - run: | From cac6703ccafafa4f879bad1d69ae926fb4e426ca Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 7 Feb 2021 14:22:02 -0600 Subject: [PATCH 0003/1456] reopen master for 3.5 (#5752) * reopen master for 3.5 * Update CHANGELOG.rst Co-authored-by: Alex Gaynor Co-authored-by: Alex Gaynor --- CHANGELOG.rst | 7 +++++++ src/cryptography/__about__.py | 2 +- vectors/cryptography_vectors/__about__.py | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 15f94549726b..23498769ea40 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,13 @@ Changelog ========= +.. _v3-5: + +3.5 - `master`_ +~~~~~~~~~~~~~~~~ + + .. note:: This version is not yet released and is under active development. + .. _v3-4: 3.4 - 2021-02-07 diff --git a/src/cryptography/__about__.py b/src/cryptography/__about__.py index 2e71757c56b5..451d0fe52ff4 100644 --- a/src/cryptography/__about__.py +++ b/src/cryptography/__about__.py @@ -21,7 +21,7 @@ ) __uri__ = "https://github.com/pyca/cryptography" -__version__ = "3.4" +__version__ = "3.5.dev1" __author__ = "The Python Cryptographic Authority and individual contributors" __email__ = "cryptography-dev@python.org" diff --git a/vectors/cryptography_vectors/__about__.py b/vectors/cryptography_vectors/__about__.py index bed5270de919..eee22cf0e5bb 100644 --- a/vectors/cryptography_vectors/__about__.py +++ b/vectors/cryptography_vectors/__about__.py @@ -18,7 +18,7 @@ __uri__ = "https://github.com/pyca/cryptography" -__version__ = "3.4" +__version__ = "3.5.dev1" __author__ = "The Python Cryptographic Authority and individual contributors" __email__ = "cryptography-dev@python.org" From ab537a610dbde082ab2910b2dbaa648aa03640d0 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 7 Feb 2021 16:06:02 -0500 Subject: [PATCH 0004/1456] Try to assist folks having issues with older pips (#5757) * Try to assist folks having issues with older pips * Update setup.py * Update setup.py --- setup.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 58de2f4a8c5c..9fb3e3200401 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,21 @@ from setuptools import find_packages, setup -from setuptools_rust import RustExtension +try: + from setuptools_rust import RustExtension +except ImportError: + print( + """ + =============================DEBUG ASSISTANCE========================== + If you are seeing an error here please try the following to + successfully install cryptography: + + Upgrade to the latest pip and try again. This will fix errors for most + users. See: https://pip.pypa.io/en/stable/installing/#upgrading-pip + =============================DEBUG ASSISTANCE========================== + """ + ) + raise base_dir = os.path.dirname(__file__) From a3e435f1b1ecaddce14849f502426d0605133fc8 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 7 Feb 2021 15:06:34 -0600 Subject: [PATCH 0005/1456] update issue template with more words few people will read (#5759) --- .github/ISSUE_TEMPLATE.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE.rst b/.github/ISSUE_TEMPLATE.rst index 011d571c9f19..ea489382c1a2 100644 --- a/.github/ISSUE_TEMPLATE.rst +++ b/.github/ISSUE_TEMPLATE.rst @@ -1,9 +1,13 @@ If you're filing a bug (as opposed to a feature request), please try the following things: +* Check the FAQ to see if your issue is covered there: + https://cryptography.io/en/latest/faq.html * Upgrade to the latest version of ``setuptools`` and ``pip`` * Make sure you're on a supported version of OpenSSL * Try with the latest version of ``cryptography`` +* Be sure you have the required compilers (both a C compiler and Rust) + installed if you aren't using the binary wheels. If none of that works, please make sure to include the following information in your bug report: @@ -15,4 +19,4 @@ your bug report: Please do not report security issues on Github! Follow the instructions in our documentation for reporting security issues: -https://cryptography.io/en/latest/security/ +https://cryptography.io/en/latest/security.html From 4f03b8e89921c5f975cb0ea0e13b6420ffa88700 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 7 Feb 2021 15:11:20 -0600 Subject: [PATCH 0006/1456] fix import cycle with asymmetricpadding (#5758) * fix import cycle with asymmetricpadding * Update src/cryptography/hazmat/primitives/_asymmetric.py --- .../hazmat/primitives/_asymmetric.py | 17 +++++++++++++++++ .../hazmat/primitives/asymmetric/padding.py | 10 +--------- .../hazmat/primitives/asymmetric/rsa.py | 2 +- 3 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 src/cryptography/hazmat/primitives/_asymmetric.py diff --git a/src/cryptography/hazmat/primitives/_asymmetric.py b/src/cryptography/hazmat/primitives/_asymmetric.py new file mode 100644 index 000000000000..cdadbdeff799 --- /dev/null +++ b/src/cryptography/hazmat/primitives/_asymmetric.py @@ -0,0 +1,17 @@ +# 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. + +import abc + + +# This exists to break an import cycle. It is normally accessible from the +# asymmetric padding module. + + +class AsymmetricPadding(metaclass=abc.ABCMeta): + @abc.abstractproperty + def name(self) -> str: + """ + A string naming this padding (e.g. "PSS", "PKCS1"). + """ diff --git a/src/cryptography/hazmat/primitives/asymmetric/padding.py b/src/cryptography/hazmat/primitives/asymmetric/padding.py index a3b850ff5725..301c64c92898 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/padding.py +++ b/src/cryptography/hazmat/primitives/asymmetric/padding.py @@ -3,21 +3,13 @@ # for complete details. -import abc import typing from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding from cryptography.hazmat.primitives.asymmetric import rsa -class AsymmetricPadding(metaclass=abc.ABCMeta): - @abc.abstractproperty - def name(self) -> str: - """ - A string naming this padding (e.g. "PSS", "PKCS1"). - """ - - class PKCS1v15(AsymmetricPadding): name = "EMSA-PKCS1-v1_5" diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py index 375356002814..213e518db41a 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -12,12 +12,12 @@ from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import RSABackend from cryptography.hazmat.primitives import _serialization, hashes +from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding from cryptography.hazmat.primitives.asymmetric import ( AsymmetricSignatureContext, AsymmetricVerificationContext, utils as asym_utils, ) -from cryptography.hazmat.primitives.asymmetric.padding import AsymmetricPadding class RSAPrivateKey(metaclass=abc.ABCMeta): From 585c53f382dab5a35caf265490801fb659297364 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 7 Feb 2021 16:23:25 -0600 Subject: [PATCH 0007/1456] forward port 3.4.1 changelog (#5762) --- CHANGELOG.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 23498769ea40..4522f628b0a0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,15 @@ Changelog .. note:: This version is not yet released and is under active development. +.. _v3-4-1: + +3.4.1 - 2021-02-07 +~~~~~~~~~~~~~~~~~~ + +* Fixed a circular import issue. +* Added additional debug output to assist users seeing installation errors + due to outdated ``pip`` or missing ``rustc``. + .. _v3-4: 3.4 - 2021-02-07 From ab96eccb743be3d7e412143fb9529a2304451653 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 7 Feb 2021 17:30:55 -0500 Subject: [PATCH 0008/1456] include cargo in the docs for alpine (#5763) --- docs/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index 9f7eb1d7d75b..6d89a7971c79 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -94,7 +94,7 @@ Alpine .. code-block:: console - $ sudo apk add gcc musl-dev python3-dev libffi-dev openssl-dev + $ sudo apk add gcc musl-dev python3-dev libffi-dev openssl-dev cargo If you get an error with ``openssl-dev`` you may have to use ``libressl-dev``. From f9277dc3763b2aeaeebc1b3d87c781d3f2ef3c84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Feb 2021 08:46:28 -0500 Subject: [PATCH 0009/1456] Bump actions/cache from v2 to v2.1.4 (#5770) Bumps [actions/cache](https://github.com/actions/cache) from v2 to v2.1.4. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v2...26968a09c0ea4f3e233fdddbafd1166051a095f6) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c8c17e9b2761..72d10002a40d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/cache@v2.1.4 with: path: | ~/.cargo/registry @@ -65,7 +65,7 @@ jobs: CONFIG_FLAGS: ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }} if: matrix.PYTHON.OPENSSL - name: Load cache - uses: actions/cache@v2 + uses: actions/cache@v2.1.4 id: ossl-cache with: path: ${{ github.workspace }}/osslcache @@ -115,7 +115,7 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/cache@v2.1.4 with: path: | ~/.cargo/registry @@ -151,7 +151,7 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/cache@v2.1.4 with: path: | ~/.cargo/registry @@ -193,7 +193,7 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/cache@v2.1.4 with: path: | ~/.cargo/registry @@ -252,7 +252,7 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/cache@v2.1.4 with: path: | ~/.cargo/registry @@ -313,7 +313,7 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/cache@v2.1.4 with: path: | ~/.cargo/registry From 13e7e56c6094639cce1293f88a633270dfbe037c Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 8 Feb 2021 15:07:59 +0100 Subject: [PATCH 0010/1456] Interface: Make annotation check optional (#5775) * Interface: Make annotation check optional Fixes: https://github.com/pyca/cryptography/issues/5774 Signed-off-by: Christian Heimes * Use param.replace() Co-authored-by: Stanislav Levin Signed-off-by: Christian Heimes Co-authored-by: Stanislav Levin --- src/cryptography/utils.py | 25 +++++++++++++++++++------ tests/test_interfaces.py | 24 ++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index 9bf31faadbec..ef0fc44332d0 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -41,8 +41,8 @@ def read_only_property(name: str): def register_interface(iface): - def register_decorator(klass): - verify_interface(iface, klass) + def register_decorator(klass, *, check_annotations=False): + verify_interface(iface, klass, check_annotations=check_annotations) iface.register(klass) return klass @@ -50,9 +50,9 @@ def register_decorator(klass): def register_interface_if(predicate, iface): - def register_decorator(klass): + def register_decorator(klass, *, check_annotations=False): if predicate: - verify_interface(iface, klass) + verify_interface(iface, klass, check_annotations=check_annotations) iface.register(klass) return klass @@ -69,7 +69,16 @@ class InterfaceNotImplemented(Exception): pass -def verify_interface(iface, klass): +def strip_annotation(signature): + return inspect.Signature( + [ + param.replace(annotation=inspect.Parameter.empty) + for param in signature.parameters.values() + ] + ) + + +def verify_interface(iface, klass, *, check_annotations=False): for method in iface.__abstractmethods__: if not hasattr(klass, method): raise InterfaceNotImplemented( @@ -80,7 +89,11 @@ def verify_interface(iface, klass): continue sig = inspect.signature(getattr(iface, method)) actual = inspect.signature(getattr(klass, method)) - if sig != actual: + if check_annotations: + ok = sig == actual + else: + ok = strip_annotation(sig) == strip_annotation(actual) + if not ok: raise InterfaceNotImplemented( "{}.{}'s signature differs from the expected. Expected: " "{!r}. Received: {!r}".format(klass, method, sig, actual) diff --git a/tests/test_interfaces.py b/tests/test_interfaces.py index c5c579da0ca7..89d802aed017 100644 --- a/tests/test_interfaces.py +++ b/tests/test_interfaces.py @@ -77,3 +77,27 @@ def property(self): # Invoke this to ensure the line is covered NonImplementer().property verify_interface(SimpleInterface, NonImplementer) + + def test_signature_mismatch(self): + class SimpleInterface(metaclass=abc.ABCMeta): + @abc.abstractmethod + def method(self, other: object) -> int: + """Method with signature""" + + class ClassWithoutSignature: + def method(self, other): + """Method without signature""" + + class ClassWithSignature: + def method(self, other: object) -> int: + """Method with signature""" + + verify_interface(SimpleInterface, ClassWithoutSignature) + verify_interface(SimpleInterface, ClassWithSignature) + with pytest.raises(InterfaceNotImplemented): + verify_interface( + SimpleInterface, ClassWithoutSignature, check_annotations=True + ) + verify_interface( + SimpleInterface, ClassWithSignature, check_annotations=True + ) From 048f7c6cb4cd5a46b252e17c3463d254e1c552ab Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 8 Feb 2021 15:32:58 +0100 Subject: [PATCH 0011/1456] Remove setuptools_rust from install requirement (#5779) * Remove setuptools_rust from install requirement setuptools_rust is only required for building cryptography. Fixes: https://github.com/pyca/cryptography/issues/5778 Signed-off-by: Christian Heimes * sdist needs setuptools_rust Signed-off-by: Christian Heimes --- setup.py | 12 +++++++++--- tox.ini | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 9fb3e3200401..0142faccea85 100644 --- a/setup.py +++ b/setup.py @@ -39,8 +39,11 @@ exec(f.read(), about) -# `setup_requirements` must be kept in sync with `pyproject.toml` -setup_requirements = ["cffi>=1.12", "setuptools-rust>=0.11.4"] +# `install_requirements` and `setup_requirements` must be kept in sync with +# `pyproject.toml` +setuptools_rust = "setuptools-rust>=0.11.4" +install_requirements = ["cffi>=1.12"] +setup_requirements = install_requirements + [setuptools_rust] if os.environ.get("CRYPTOGRAPHY_DONT_BUILD_RUST"): rust_extensions = [] @@ -102,7 +105,7 @@ ), include_package_data=True, python_requires=">=3.6", - install_requires=setup_requirements, + install_requires=install_requirements, setup_requires=setup_requirements, extras_require={ "test": [ @@ -125,6 +128,9 @@ "twine >= 1.12.0", "sphinxcontrib-spelling >= 4.0.1", ], + "sdist": [ + setuptools_rust, + ], "pep8test": [ "black", "flake8", diff --git a/tox.ini b/tox.ini index e58612ce5fd6..93f4b253ab8d 100644 --- a/tox.ini +++ b/tox.ini @@ -20,6 +20,7 @@ commands = extras = docs docstest + sdist basepython = python3 commands = sphinx-build -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html From 9aa369af8c02d86a096e8c5338faa5b83e5cf2ee Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 8 Feb 2021 15:58:34 +0100 Subject: [PATCH 0012/1456] Update build instructions (#5764) The Rust version in CentOS 7 SCL is too old to build cryptography. Signed-off-by: Christian Heimes --- docs/installation.rst | 12 ++++++------ docs/spelling_wordlist.txt | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 6d89a7971c79..7edd92432d30 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -103,16 +103,16 @@ Debian/Ubuntu .. code-block:: console - $ sudo apt-get install build-essential libssl-dev libffi-dev python3-dev + $ sudo apt-get install build-essential libssl-dev libffi-dev \ + python3-dev cargo -RHEL/CentOS -~~~~~~~~~~~ +Fedora/RHEL 8/CentOS 8 +~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: console - $ sudo yum install redhat-rpm-config gcc libffi-devel python-devel \ - openssl-devel - + $ sudo dnf install redhat-rpm-config gcc libffi-devel python3-devel \ + openssl-devel cargo Building ~~~~~~~~ diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index f59c3e413506..cad47e53677a 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -14,6 +14,7 @@ Botan Brainpool Bullseye Capitan +CentOS changelog Changelog ciphertext @@ -80,6 +81,7 @@ online paddings Parallelization personalization +RHEL pickleable plaintext Poly From 5fdc9c1b8563c2ffe99d6dff3f0632fb9dc29936 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 8 Feb 2021 10:18:13 -0500 Subject: [PATCH 0013/1456] More aggressively point people at Rust version docs (#5782) --- docs/faq.rst | 4 +++- docs/installation.rst | 2 ++ setup.py | 5 ++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/faq.rst b/docs/faq.rst index 7eec9c53b427..4123a1cf8461 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -123,7 +123,9 @@ Installing ``cryptography`` fails with ``error: Can not find Rust compiler`` Building ``cryptography`` from source requires you have :ref:`Rust installed and available` on your ``PATH``. You may be able to fix this by upgrading to a newer version of ``pip`` which will install a pre-compiled -``cryptography`` wheel. If not, you'll need to install Rust. +``cryptography`` wheel. If not, you'll need to install Rust. Follow the +:ref:`instructions` to ensure you install a recent Rust +version. For the current release *only* you can temporarily bypass the requirement to have Rust installed by setting the ``CRYPTOGRAPHY_DONT_BUILD_RUST`` environment diff --git a/docs/installation.rst b/docs/installation.rst index 7edd92432d30..e167f5af10d6 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -273,6 +273,8 @@ Building ``cryptography`` requires having a working Rust toolchain. The current minimum supported Rust version is 1.45.0. Instructions for installing Rust can be found on `the Rust Project's website`_. +We recommend installing Rust with ``rustup`` (as documented by the Rust +Project) in order to ensure you have a recent version. .. _`Homebrew`: https://brew.sh .. _`MacPorts`: https://www.macports.org diff --git a/setup.py b/setup.py index 0142faccea85..7e19d38e5c31 100644 --- a/setup.py +++ b/setup.py @@ -169,7 +169,10 @@ instructions for your platform. 3) Check our frequently asked questions for more information: https://cryptography.io/en/latest/faq.html - 4) Ensure you have a recent Rust toolchain installed. + 4) Ensure you have a recent Rust toolchain installed: + https://cryptography.io/en/latest/installation.html#rust + 5) If you are experiencing issues with Rust for *this release only* you may + set the environment variable `CRYPTOGRAPHY_DONT_BUILD_RUST=1`. =============================DEBUG ASSISTANCE============================= """ ) From b20507ae687dc2bf1841e7d7bc89cd4237177ae1 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 8 Feb 2021 10:50:39 -0600 Subject: [PATCH 0014/1456] link a lot more things, repeat advice in more places (#5785) * link a lot more things, repeat advice in more places * updated with Christian's comments * empty commit poor github --- docs/installation.rst | 69 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index e167f5af10d6..310f13c9f3b7 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -7,6 +7,9 @@ You can install ``cryptography`` with ``pip``: $ pip install cryptography +If this does not work please **upgrade your pip** first, as that is the +single most common cause of installation problems. + Supported platforms ------------------- @@ -72,18 +75,26 @@ local `wheel cache`_. Building cryptography on Linux ------------------------------ +.. note:: + + If you are on RHEL/CentOS/Fedora/Debian/Ubuntu or another distribution + derived from the preceding list, then you should **upgrade pip** and + attempt to install ``cryptography`` again before following the instructions + to compile it below. These platforms will receive a binary wheel and + require no compiler if you have an updated ``pip``! + ``cryptography`` ships ``manylinux`` wheels (as of 2.0) so all dependencies -are included. For users on pip 19.0 or above running on a ``manylinux2010`` (or -greater) compatible distribution (almost everything except Alpine) all you -should need to do is: +are included. For users on **pip 19.0** or above running on a ``manylinux2010`` +(or greater) compatible distribution (almost everything **except Alpine**) all +you should need to do is: .. code-block:: console $ pip install cryptography If you are on Alpine or just want to compile it yourself then -``cryptography`` requires a compiler, headers for Python (if you're not -using ``pypy``), and headers for the OpenSSL and ``libffi`` libraries +``cryptography`` requires a C compiler, a Rust compiler, headers for Python (if +you're not using ``pypy``), and headers for the OpenSSL and ``libffi`` libraries available on your system. On all Linux distributions you will need to have :ref:`Rust installed and @@ -92,6 +103,12 @@ available`. Alpine ~~~~~~ +.. warning:: + + The Rust available by default in Alpine < 3.13 is older than the minimum + supported version. See the :ref:`Rust installation instructions + ` for information about installing a newer Rust. + .. code-block:: console $ sudo apk add gcc musl-dev python3-dev libffi-dev openssl-dev cargo @@ -101,6 +118,14 @@ If you get an error with ``openssl-dev`` you may have to use ``libressl-dev``. Debian/Ubuntu ~~~~~~~~~~~~~ +.. warning:: + + The Rust available in current Debian stable and some Ubuntu versions is + older than the minimum supported version. Ubuntu 18.04 and 20.04 are + sufficiently new, but otherwise please see the + :ref:`Rust installation instructions ` for information + about installing a newer Rust. + .. code-block:: console $ sudo apt-get install build-essential libssl-dev libffi-dev \ @@ -109,11 +134,33 @@ Debian/Ubuntu Fedora/RHEL 8/CentOS 8 ~~~~~~~~~~~~~~~~~~~~~~ +.. warning:: + + For RHEL and CentOS you must be on version 8.3 or newer for the command + below to install a sufficiently new Rust. If your Rust is less than 1.45.0 + please see the :ref:`Rust installation instructions ` + for information about installing a newer Rust. + .. code-block:: console $ sudo dnf install redhat-rpm-config gcc libffi-devel python3-devel \ openssl-devel cargo +RHEL 7/CentOS 7 +~~~~~~~~~~~~~~~ + +.. warning:: + + You must install Rust using the :ref:`Rust installation instructions + `. ``cryptography`` requires a Rust version newer than + what is provided in the distribution packages. + +.. code-block:: console + + $ sudo yum install redhat-rpm-config gcc libffi-devel python-devel \ + openssl-devel + + Building ~~~~~~~~ @@ -269,8 +316,18 @@ local `wheel cache`_. Rust ---- +.. note:: + + If you are on RHEL/CentOS/Fedora/Debian/Ubuntu or another distribution + derived from the preceding list, then you should **upgrade ``pip``** (in + a virtual environment!) and attempt to install ``cryptography`` again + before trying to install the Rust toolchain. These platforms will receive + a binary wheel and require no compiler if you have an updated ``pip``! + Building ``cryptography`` requires having a working Rust toolchain. The current -minimum supported Rust version is 1.45.0. +minimum supported Rust version is 1.45.0. **This is newer than the Rust most +package managers ship**, so users will likely need to install with the +instructions below. Instructions for installing Rust can be found on `the Rust Project's website`_. We recommend installing Rust with ``rustup`` (as documented by the Rust From 9bf3880bc5b68903dae372d0953a5db820914172 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 8 Feb 2021 12:31:35 -0500 Subject: [PATCH 0015/1456] forward port 3.4.2 changelog (#5786) --- CHANGELOG.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4522f628b0a0..de952c3bffad 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,16 @@ Changelog .. note:: This version is not yet released and is under active development. +.. _v3-4-2: + +3.4.2 - 2021-02-08 +~~~~~~~~~~~~~~~~~~ + +* Improvements to make the rust transition a bit easier. This includes some + better error messages and small dependency fixes. If you experience + installation problems **Be sure to update pip** first, then check the + :doc:`FAQ `. + .. _v3-4-1: 3.4.1 - 2021-02-07 From e6df973a92e9026dc6f1a63e575bab1ff9b99910 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 8 Feb 2021 12:01:53 -0600 Subject: [PATCH 0016/1456] docs docs docs (#5788) --- docs/installation.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 310f13c9f3b7..ea2f33c7bb94 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -273,10 +273,12 @@ This will install a compiler (clang) along with (most of) the required development headers. You will also need to have :ref:`Rust installed and -available`. +available`, which can be obtained from `Homebrew`_, +`MacPorts`_, or directly from the Rust website. -You'll also need OpenSSL, which you can obtain from `Homebrew`_ or `MacPorts`_. -Cryptography does **not** support Apple's deprecated OpenSSL distribution. +Finally you need OpenSSL, which you can obtain from `Homebrew`_ or `MacPorts`_. +Cryptography does **not** support the OpenSSL/LibreSSL libraries Apple ships +in its base operating system. To build cryptography and dynamically link it: @@ -284,14 +286,14 @@ To build cryptography and dynamically link it: .. code-block:: console - $ brew install openssl@1.1 + $ brew install openssl@1.1 rust $ env LDFLAGS="-L$(brew --prefix openssl@1.1)/lib" CFLAGS="-I$(brew --prefix openssl@1.1)/include" pip install cryptography `MacPorts`_: .. code-block:: console - $ sudo port install openssl + $ sudo port install openssl rust $ env LDFLAGS="-L/opt/local/lib" CFLAGS="-I/opt/local/include" pip install cryptography You can also build cryptography statically: @@ -300,14 +302,14 @@ You can also build cryptography statically: .. code-block:: console - $ brew install openssl@1.1 + $ brew install openssl@1.1 rust $ env CRYPTOGRAPHY_SUPPRESS_LINK_FLAGS=1 LDFLAGS="$(brew --prefix openssl@1.1)/lib/libssl.a $(brew --prefix openssl@1.1)/lib/libcrypto.a" CFLAGS="-I$(brew --prefix openssl@1.1)/include" pip install cryptography `MacPorts`_: .. code-block:: console - $ sudo port install openssl + $ sudo port install openssl rust $ env CRYPTOGRAPHY_SUPPRESS_LINK_FLAGS=1 LDFLAGS="/opt/local/lib/libssl.a /opt/local/lib/libcrypto.a" CFLAGS="-I/opt/local/include" pip install cryptography If you need to rebuild ``cryptography`` for any reason be sure to clear the @@ -319,7 +321,7 @@ Rust .. note:: If you are on RHEL/CentOS/Fedora/Debian/Ubuntu or another distribution - derived from the preceding list, then you should **upgrade ``pip``** (in + derived from the preceding list, then you should **upgrade pip** (in a virtual environment!) and attempt to install ``cryptography`` again before trying to install the Rust toolchain. These platforms will receive a binary wheel and require no compiler if you have an updated ``pip``! From f01dcd62affe5dbc9f9dddc31f095cf15abcde9d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 8 Feb 2021 19:09:31 -0500 Subject: [PATCH 0017/1456] Specify an MSRV in setup.py (#5789) --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 7e19d38e5c31..1a22695427a4 100644 --- a/setup.py +++ b/setup.py @@ -59,6 +59,7 @@ if platform.python_implementation() == "PyPy" else ["pyo3/abi3-py36"] ), + rust_version=">=1.45.0", ) ] From 9954a67ea93a101dc4a41331188ad9ac6c51409a Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 8 Feb 2021 23:11:43 -0600 Subject: [PATCH 0018/1456] port 3.4.3 changelog to master (#5792) --- CHANGELOG.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index de952c3bffad..02c2e76910c0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,14 @@ Changelog .. note:: This version is not yet released and is under active development. +.. _v3-4-3: + +3.4.3 - 2021-02-08 +~~~~~~~~~~~~~~~~~~ + +* Specify our supported Rust version (>=1.45.0) in our ``setup.py`` so users + on older versions will get a clear error message. + .. _v3-4-2: 3.4.2 - 2021-02-08 From 4b7ebaff0e3e01af1229d5f4c3dd5b152a43cb85 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Feb 2021 08:45:46 -0500 Subject: [PATCH 0019/1456] Bump libc from 0.2.85 to 0.2.86 in /src/rust (#5793) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.85 to 0.2.86. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.85...0.2.86) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index d4b90b8c4203..88161c27d45d 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -76,9 +76,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.85" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3" +checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" [[package]] name = "lock_api" From f6ca69c2af0f6728bc59ccad3513c5189bc5589e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 9 Feb 2021 10:38:33 -0500 Subject: [PATCH 0020/1456] fixed a circular import error (due to type hints) (#5800) fixes #5794 closes #5795 --- src/cryptography/hazmat/primitives/serialization/base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cryptography/hazmat/primitives/serialization/base.py b/src/cryptography/hazmat/primitives/serialization/base.py index 00334b2e3b16..9f7531db2f7a 100644 --- a/src/cryptography/hazmat/primitives/serialization/base.py +++ b/src/cryptography/hazmat/primitives/serialization/base.py @@ -25,7 +25,7 @@ def load_pem_public_key(data: bytes, backend=None) -> _PUBLIC_KEY_TYPES: return backend.load_pem_public_key(data) -def load_pem_parameters(data: bytes, backend=None) -> dh.DHParameters: +def load_pem_parameters(data: bytes, backend=None) -> "dh.DHParameters": backend = _get_backend(backend) return backend.load_pem_parameters(data) @@ -42,6 +42,6 @@ def load_der_public_key(data: bytes, backend=None) -> _PUBLIC_KEY_TYPES: return backend.load_der_public_key(data) -def load_der_parameters(data: bytes, backend=None) -> dh.DHParameters: +def load_der_parameters(data: bytes, backend=None) -> "dh.DHParameters": backend = _get_backend(backend) return backend.load_der_parameters(data) From e8ec55cedc2e164f3c22d43768007e0d43ff9803 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 9 Feb 2021 11:31:25 -0500 Subject: [PATCH 0021/1456] Added a py.typed so mypy prefers us to typeshed (#5802) closes #5796 --- MANIFEST.in | 1 + src/cryptography/py.typed | 0 2 files changed, 1 insertion(+) create mode 100644 src/cryptography/py.typed diff --git a/MANIFEST.in b/MANIFEST.in index 4b4ec2dfc8e5..78889eaeb541 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -7,6 +7,7 @@ include LICENSE.PSF include README.rst include pyproject.toml +recursive-include src py.typed recursive-include docs * recursive-include src/_cffi_src *.py *.c *.h diff --git a/src/cryptography/py.typed b/src/cryptography/py.typed new file mode 100644 index 000000000000..e69de29bb2d1 From 4bbf9dfce880c40040f8a15a7f2994b66e716dcc Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 9 Feb 2021 14:25:47 -0500 Subject: [PATCH 0022/1456] Added a unit test to protect against import cycles (#5804) --- tests/test_meta.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/test_meta.py diff --git a/tests/test_meta.py b/tests/test_meta.py new file mode 100644 index 000000000000..d89daad81027 --- /dev/null +++ b/tests/test_meta.py @@ -0,0 +1,38 @@ +# 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. + +import os +import pkgutil +import subprocess +import sys +import typing + +import cryptography + + +def find_all_modules() -> typing.List[str]: + return sorted( + mod + for _, mod, _ in pkgutil.walk_packages( + cryptography.__path__, # type: ignore[attr-defined] + prefix=cryptography.__name__ + ".", + ) + ) + + +def test_no_circular_imports(subtests): + env = os.environ.copy() + env["PYTHONPATH"] = os.pathsep.join(sys.path) + + # When using pytest-cov it attempts to instrument subprocesses. This + # causes the memleak tests to raise exceptions. + # we don't need coverage so we remove the env vars. + env.pop("COV_CORE_CONFIG", None) + env.pop("COV_CORE_DATAFILE", None) + env.pop("COV_CORE_SOURCE", None) + + for module in find_all_modules(): + with subtests.test(): + argv = [sys.executable, "-c", f"__import__({module!r})"] + subprocess.check_call(argv, env=env) From aef024dc5668028f9f2ac67152a9573beb6606fe Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 9 Feb 2021 14:59:45 -0500 Subject: [PATCH 0023/1456] forward port 3.4.4 changelog (#5805) --- CHANGELOG.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 02c2e76910c0..afd1d61372a7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,15 @@ Changelog .. note:: This version is not yet released and is under active development. +.. _v3-4-4: + +3.4.4 - 2021-02-09 +~~~~~~~~~~~~~~~~~~ + +* Added a ``py.typed`` file so that ``mypy`` will know to use our type + annotations. +* Fixed an import cycle that could be triggered by certain import sequences. + .. _v3-4-3: 3.4.3 - 2021-02-08 From 395384e811e46edebffce04ec84f484882d6a49f Mon Sep 17 00:00:00 2001 From: Markus Wamser Date: Wed, 10 Feb 2021 16:01:33 +0100 Subject: [PATCH 0024/1456] fix signature of EllipticCurvePublicKey.verify() (#5808) The signature change was introduced in https://github.com/pyca/cryptography/pull/5729 but is inconsistent with respect to related methods, breaks backward compatibility and compatibility with the OpenSSL backend (and maybe other backends) when named arguments are used. --- src/cryptography/hazmat/primitives/asymmetric/ec.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptography/hazmat/primitives/asymmetric/ec.py b/src/cryptography/hazmat/primitives/asymmetric/ec.py index 6374305d8754..56c5f9a02c21 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ec.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ec.py @@ -176,7 +176,7 @@ def verify( self, signature: bytes, data: bytes, - algorithm: EllipticCurveSignatureAlgorithm, + signature_algorithm: EllipticCurveSignatureAlgorithm, ) -> None: """ Verifies the signature of the data. From 278fece69889898f0638dd4429cf40481e18ee14 Mon Sep 17 00:00:00 2001 From: Dan Halperin Date: Wed, 10 Feb 2021 12:32:21 -0800 Subject: [PATCH 0025/1456] Name: update get_attributes_for_oid return type (#5809) `List` gives more power to the caller. Note that `RelativeDistinguishedName`, the same function returns a `List`. Is there a reason this was `Iterable` only for `Name`? If we don't want to promise `List`, `Sequence` is another alternative. --- src/cryptography/x509/name.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py index c183160e0aca..a579aa219638 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -216,7 +216,7 @@ def rfc4514_string(self) -> str: attr.rfc4514_string() for attr in reversed(self._attributes) ) - def get_attributes_for_oid(self, oid) -> typing.Iterable[NameAttribute]: + def get_attributes_for_oid(self, oid) -> typing.List[NameAttribute]: return [i for i in self if i.oid == oid] @property From 9efc6d46fb98a52a9bb956096a9389f21bd8de92 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 11 Feb 2021 11:47:20 -0500 Subject: [PATCH 0026/1456] fix a false positive from the latest clippy (#5813) --- src/rust/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index f06ac5f02125..1580ca4fcef7 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -3,6 +3,8 @@ // for complete details. #[pyo3::prelude::pymodule] +// False positive: https://github.com/rust-lang/rust-clippy/issues/6721 +#[allow(clippy::unnecessary_wraps)] fn _rust(_py: pyo3::Python<'_>, _m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { Ok(()) } From 5511445e95a16fa12b464d57ace4bb17855fe844 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 11 Feb 2021 13:56:46 -0500 Subject: [PATCH 0027/1456] Start typing a bunch of stuff from x509 extensions (#5812) --- src/cryptography/x509/extensions.py | 60 +++++++++++++-------- src/cryptography/x509/general_name.py | 21 +++----- tests/x509/test_ocsp.py | 4 +- tests/x509/test_x509.py | 4 +- tests/x509/test_x509_ext.py | 77 ++++++++++++++++++++------- 5 files changed, 110 insertions(+), 56 deletions(-) diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 9f3d8f62d084..2f8612277d8f 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -990,15 +990,15 @@ class KeyUsage(ExtensionType): def __init__( self, - digital_signature, - content_commitment, - key_encipherment, - data_encipherment, - key_agreement, - key_cert_sign, - crl_sign, - encipher_only, - decipher_only, + digital_signature: bool, + content_commitment: bool, + key_encipherment: bool, + data_encipherment: bool, + key_agreement: bool, + key_cert_sign: bool, + crl_sign: bool, + encipher_only: bool, + decipher_only: bool, ): if not key_agreement and (encipher_only or decipher_only): raise ValueError( @@ -1101,7 +1101,11 @@ def __hash__(self): class NameConstraints(ExtensionType): oid = ExtensionOID.NAME_CONSTRAINTS - def __init__(self, permitted_subtrees, excluded_subtrees): + def __init__( + self, + permitted_subtrees: typing.Optional[typing.Iterable[GeneralName]], + excluded_subtrees: typing.Optional[typing.Iterable[GeneralName]], + ): if permitted_subtrees is not None: permitted_subtrees = list(permitted_subtrees) if not all(isinstance(x, GeneralName) for x in permitted_subtrees): @@ -1180,7 +1184,9 @@ def __hash__(self): class Extension(object): - def __init__(self, oid, critical, value): + def __init__( + self, oid: ObjectIdentifier, critical: bool, value: ExtensionType + ): if not isinstance(oid, ObjectIdentifier): raise TypeError( "oid argument must be an ObjectIdentifier instance." @@ -1221,7 +1227,7 @@ def __hash__(self): class GeneralNames(object): - def __init__(self, general_names): + def __init__(self, general_names: typing.Iterable[GeneralName]): general_names = list(general_names) if not all(isinstance(x, GeneralName) for x in general_names): raise TypeError( @@ -1233,7 +1239,7 @@ def __init__(self, general_names): __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") - def get_values_for_type(self, type): + def get_values_for_type(self, type: typing.Type[GeneralName]): # Return the value of each GeneralName, except for OtherName instances # which we return directly because it has two important properties not # just one value. @@ -1261,7 +1267,7 @@ def __hash__(self): class SubjectAlternativeName(ExtensionType): oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME - def __init__(self, general_names): + def __init__(self, general_names: typing.Iterable[GeneralName]): self._general_names = GeneralNames(general_names) __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") @@ -1288,7 +1294,7 @@ def __hash__(self): class IssuerAlternativeName(ExtensionType): oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME - def __init__(self, general_names): + def __init__(self, general_names: typing.Iterable[GeneralName]): self._general_names = GeneralNames(general_names) __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") @@ -1315,7 +1321,7 @@ def __hash__(self): class CertificateIssuer(ExtensionType): oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER - def __init__(self, general_names): + def __init__(self, general_names: typing.Iterable[GeneralName]): self._general_names = GeneralNames(general_names) __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") @@ -1342,7 +1348,7 @@ def __hash__(self): class CRLReason(ExtensionType): oid = CRLEntryExtensionOID.CRL_REASON - def __init__(self, reason): + def __init__(self, reason: ReasonFlags): if not isinstance(reason, ReasonFlags): raise TypeError("reason must be an element from ReasonFlags") @@ -1369,7 +1375,7 @@ def __hash__(self): class InvalidityDate(ExtensionType): oid = CRLEntryExtensionOID.INVALIDITY_DATE - def __init__(self, invalidity_date): + def __init__(self, invalidity_date: datetime.datetime): if not isinstance(invalidity_date, datetime.datetime): raise TypeError("invalidity_date must be a datetime.datetime") @@ -1398,7 +1404,12 @@ def __hash__(self): class PrecertificateSignedCertificateTimestamps(ExtensionType): oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS - def __init__(self, signed_certificate_timestamps): + def __init__( + self, + signed_certificate_timestamps: typing.Iterable[ + SignedCertificateTimestamp + ], + ): signed_certificate_timestamps = list(signed_certificate_timestamps) if not all( isinstance(sct, SignedCertificateTimestamp) @@ -1438,7 +1449,12 @@ def __ne__(self, other): class SignedCertificateTimestamps(ExtensionType): oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS - def __init__(self, signed_certificate_timestamps): + def __init__( + self, + signed_certificate_timestamps: typing.Iterable[ + SignedCertificateTimestamp + ], + ): signed_certificate_timestamps = list(signed_certificate_timestamps) if not all( isinstance(sct, SignedCertificateTimestamp) @@ -1476,7 +1492,7 @@ def __ne__(self, other): class OCSPNonce(ExtensionType): oid = OCSPExtensionOID.NONCE - def __init__(self, nonce): + def __init__(self, nonce: bytes): if not isinstance(nonce, bytes): raise TypeError("nonce must be bytes") @@ -1642,7 +1658,7 @@ def __hash__(self): class UnrecognizedExtension(ExtensionType): - def __init__(self, oid, value): + def __init__(self, oid: ObjectIdentifier, value: bytes): if not isinstance(oid, ObjectIdentifier): raise TypeError("oid must be an ObjectIdentifier") self._oid = oid diff --git a/src/cryptography/x509/general_name.py b/src/cryptography/x509/general_name.py index 6683e9313ce8..a83471e93131 100644 --- a/src/cryptography/x509/general_name.py +++ b/src/cryptography/x509/general_name.py @@ -40,8 +40,7 @@ def value(self): """ -@utils.register_interface(GeneralName) -class RFC822Name(object): +class RFC822Name(GeneralName): def __init__(self, value: str): if isinstance(value, str): try: @@ -87,8 +86,7 @@ def __hash__(self) -> int: return hash(self.value) -@utils.register_interface(GeneralName) -class DNSName(object): +class DNSName(GeneralName): def __init__(self, value: str): if isinstance(value, str): try: @@ -128,8 +126,7 @@ def __hash__(self) -> int: return hash(self.value) -@utils.register_interface(GeneralName) -class UniformResourceIdentifier(object): +class UniformResourceIdentifier(GeneralName): def __init__(self, value: str): if isinstance(value, str): try: @@ -169,8 +166,7 @@ def __hash__(self) -> int: return hash(self.value) -@utils.register_interface(GeneralName) -class DirectoryName(object): +class DirectoryName(GeneralName): def __init__(self, value: Name): if not isinstance(value, Name): raise TypeError("value must be a Name") @@ -195,8 +191,7 @@ def __hash__(self) -> int: return hash(self.value) -@utils.register_interface(GeneralName) -class RegisteredID(object): +class RegisteredID(GeneralName): def __init__(self, value: ObjectIdentifier): if not isinstance(value, ObjectIdentifier): raise TypeError("value must be an ObjectIdentifier") @@ -221,8 +216,7 @@ def __hash__(self) -> int: return hash(self.value) -@utils.register_interface(GeneralName) -class IPAddress(object): +class IPAddress(GeneralName): def __init__( self, value: typing.Union[ @@ -267,8 +261,7 @@ def __hash__(self) -> int: return hash(self.value) -@utils.register_interface(GeneralName) -class OtherName(object): +class OtherName(GeneralName): def __init__(self, type_id: ObjectIdentifier, value: bytes): if not isinstance(type_id, ObjectIdentifier): raise TypeError("type_id must be an ObjectIdentifier") diff --git a/tests/x509/test_ocsp.py b/tests/x509/test_ocsp.py index 5793f6d62be3..5d9da790af9f 100644 --- a/tests/x509/test_ocsp.py +++ b/tests/x509/test_ocsp.py @@ -726,7 +726,9 @@ def test_invalid_build_successful_status(self): class TestSignedCertificateTimestampsExtension(object): def test_init(self): with pytest.raises(TypeError): - x509.SignedCertificateTimestamps([object()]) + x509.SignedCertificateTimestamps( + [object()] # type: ignore[list-item] + ) def test_repr(self): assert repr(x509.SignedCertificateTimestamps([])) == ( diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 39f7bb951d41..b1e86f43647e 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -4070,7 +4070,9 @@ def test_subject_alt_name_unsupported_general_name(self, backend): x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "SAN")]) ) .add_extension( - x509.SubjectAlternativeName([FakeGeneralName("")]), + x509.SubjectAlternativeName( + [FakeGeneralName("")] # type:ignore[list-item] + ), critical=False, ) ) diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index 011649f4ecd9..938357f2d514 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -56,12 +56,16 @@ class TestExtension(object): def test_not_an_oid(self): bc = x509.BasicConstraints(ca=False, path_length=None) with pytest.raises(TypeError): - x509.Extension("notanoid", True, bc) + x509.Extension("notanoid", True, bc) # type:ignore[arg-type] def test_critical_not_a_bool(self): bc = x509.BasicConstraints(ca=False, path_length=None) with pytest.raises(TypeError): - x509.Extension(ExtensionOID.BASIC_CONSTRAINTS, "notabool", bc) + x509.Extension( + ExtensionOID.BASIC_CONSTRAINTS, + "notabool", # type:ignore[arg-type] + bc, + ) def test_repr(self): bc = x509.BasicConstraints(ca=False, path_length=None) @@ -73,16 +77,38 @@ def test_repr(self): ) def test_eq(self): - ext1 = x509.Extension(x509.ObjectIdentifier("1.2.3.4"), False, "value") - ext2 = x509.Extension(x509.ObjectIdentifier("1.2.3.4"), False, "value") + ext1 = x509.Extension( + x509.ObjectIdentifier("1.2.3.4"), + False, + x509.BasicConstraints(ca=False, path_length=None), + ) + ext2 = x509.Extension( + x509.ObjectIdentifier("1.2.3.4"), + False, + x509.BasicConstraints(ca=False, path_length=None), + ) assert ext1 == ext2 def test_ne(self): - ext1 = x509.Extension(x509.ObjectIdentifier("1.2.3.4"), False, "value") - ext2 = x509.Extension(x509.ObjectIdentifier("1.2.3.5"), False, "value") - ext3 = x509.Extension(x509.ObjectIdentifier("1.2.3.4"), True, "value") + ext1 = x509.Extension( + x509.ObjectIdentifier("1.2.3.4"), + False, + x509.BasicConstraints(ca=False, path_length=None), + ) + ext2 = x509.Extension( + x509.ObjectIdentifier("1.2.3.5"), + False, + x509.BasicConstraints(ca=False, path_length=None), + ) + ext3 = x509.Extension( + x509.ObjectIdentifier("1.2.3.4"), + True, + x509.BasicConstraints(ca=False, path_length=None), + ) ext4 = x509.Extension( - x509.ObjectIdentifier("1.2.3.4"), False, "value4" + x509.ObjectIdentifier("1.2.3.4"), + False, + x509.BasicConstraints(ca=True, path_length=None), ) assert ext1 != ext2 assert ext1 != ext3 @@ -181,7 +207,9 @@ def test_indexing(self): class TestUnrecognizedExtension(object): def test_invalid_oid(self): with pytest.raises(TypeError): - x509.UnrecognizedExtension("notanoid", b"somedata") + x509.UnrecognizedExtension( + "notanoid", b"somedata" # type:ignore[arg-type] + ) def test_eq(self): ext1 = x509.UnrecognizedExtension( @@ -289,7 +317,7 @@ def test_hash(self): class TestCRLReason(object): def test_invalid_reason_flags(self): with pytest.raises(TypeError): - x509.CRLReason("notareason") + x509.CRLReason("notareason") # type:ignore[arg-type] def test_eq(self): reason1 = x509.CRLReason(x509.ReasonFlags.unspecified) @@ -346,7 +374,7 @@ def test_hash(self): class TestInvalidityDate(object): def test_invalid_invalidity_date(self): with pytest.raises(TypeError): - x509.InvalidityDate("notadate") + x509.InvalidityDate("notadate") # type:ignore[arg-type] def test_eq(self): invalid1 = x509.InvalidityDate(datetime.datetime(2015, 1, 1, 1, 1)) @@ -1990,7 +2018,12 @@ def test_indexing(self): def test_invalid_general_names(self): with pytest.raises(TypeError): - x509.GeneralNames([x509.DNSName("cryptography.io"), "invalid"]) + x509.GeneralNames( + [ + x509.DNSName("cryptography.io"), + "invalid", # type:ignore[list-item] + ] + ) def test_repr(self): gns = x509.GeneralNames([x509.DNSName("cryptography.io")]) @@ -2049,7 +2082,10 @@ def test_indexing(self): def test_invalid_general_names(self): with pytest.raises(TypeError): x509.IssuerAlternativeName( - [x509.DNSName("cryptography.io"), "invalid"] + [ + x509.DNSName("cryptography.io"), + "invalid", # type:ignore[list-item] + ] ) def test_repr(self): @@ -2157,7 +2193,10 @@ def test_indexing(self): def test_invalid_general_names(self): with pytest.raises(TypeError): x509.SubjectAlternativeName( - [x509.DNSName("cryptography.io"), "invalid"] + [ + x509.DNSName("cryptography.io"), + "invalid", # type:ignore[list-item] + ] ) def test_repr(self): @@ -3335,11 +3374,11 @@ def test_ipaddress_allowed_type(self): def test_invalid_permitted_subtrees(self): with pytest.raises(TypeError): - x509.NameConstraints("badpermitted", None) + x509.NameConstraints("badpermitted", None) # type:ignore[arg-type] def test_invalid_excluded_subtrees(self): with pytest.raises(TypeError): - x509.NameConstraints(None, "badexcluded") + x509.NameConstraints(None, "badexcluded") # type:ignore[arg-type] def test_no_subtrees(self): with pytest.raises(ValueError): @@ -5365,7 +5404,9 @@ def test_hash(self, backend): class TestPrecertificateSignedCertificateTimestampsExtension(object): def test_init(self): with pytest.raises(TypeError): - x509.PrecertificateSignedCertificateTimestamps([object()]) + x509.PrecertificateSignedCertificateTimestamps( + [object()] # type:ignore[list-item] + ) def test_repr(self): assert repr(x509.PrecertificateSignedCertificateTimestamps([])) == ( @@ -5566,7 +5607,7 @@ def test_invalid_certificate_policies_data(self, backend): class TestOCSPNonce(object): def test_non_bytes(self): with pytest.raises(TypeError): - x509.OCSPNonce(38) + x509.OCSPNonce(38) # type:ignore[arg-type] def test_eq(self): nonce1 = x509.OCSPNonce(b"0" * 5) From 250b992d37fb64fb4b9a0373d4e307e58beb37ce Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 11 Feb 2021 21:42:04 -0500 Subject: [PATCH 0028/1456] part 2 of typing x509 extensions (#5815) --- .../hazmat/backends/openssl/decode_asn1.py | 2 +- src/cryptography/x509/extensions.py | 97 +++++++++++------ tests/x509/test_x509_ext.py | 102 ++++++++++++------ 3 files changed, 138 insertions(+), 63 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 96ba4cdbc42c..167acc078743 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -768,7 +768,7 @@ def _asn1_string_to_ascii(backend, asn1_string): return _asn1_string_to_bytes(backend, asn1_string).decode("ascii") -def _asn1_string_to_utf8(backend, asn1_string): +def _asn1_string_to_utf8(backend, asn1_string) -> str: buf = backend._ffi.new("unsigned char **") res = backend._lib.ASN1_STRING_to_UTF8(buf, asn1_string) if res == -1: diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 2f8612277d8f..6cae016a1c60 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -17,6 +17,7 @@ OBJECT_IDENTIFIER, SEQUENCE, ) +from cryptography.hazmat._types import _PUBLIC_KEY_TYPES from cryptography.hazmat.primitives import constant_time, serialization from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey @@ -33,7 +34,7 @@ ) -def _key_identifier_from_public_key(public_key): +def _key_identifier_from_public_key(public_key: _PUBLIC_KEY_TYPES) -> bytes: if isinstance(public_key, RSAPublicKey): data = public_key.public_bytes( serialization.Encoding.DER, @@ -54,7 +55,7 @@ def _key_identifier_from_public_key(public_key): reader = DERReader(serialized) with reader.read_single_element(SEQUENCE) as public_key_info: algorithm = public_key_info.read_element(SEQUENCE) - public_key = public_key_info.read_element(BIT_STRING) + public_key_data = public_key_info.read_element(BIT_STRING) # Double-check the algorithm structure. with algorithm: @@ -65,10 +66,10 @@ def _key_identifier_from_public_key(public_key): # BIT STRING contents begin with the number of padding bytes added. It # must be zero for SubjectPublicKeyInfo structures. - if public_key.read_byte() != 0: + if public_key_data.read_byte() != 0: raise ValueError("Invalid public key encoding") - data = public_key.data + data = public_key_data.data return hashlib.sha1(data).digest() @@ -110,14 +111,14 @@ class Extensions(object): def __init__(self, extensions: typing.List["Extension"]): self._extensions = extensions - def get_extension_for_oid(self, oid): + def get_extension_for_oid(self, oid: ObjectIdentifier) -> "Extension": for ext in self: if ext.oid == oid: return ext raise ExtensionNotFound("No {} extension was found".format(oid), oid) - def get_extension_for_class(self, extclass): + def get_extension_for_class(self, extclass) -> "Extension": if extclass is UnrecognizedExtension: raise TypeError( "UnrecognizedExtension can't be used with " @@ -142,7 +143,7 @@ def __repr__(self): class CRLNumber(ExtensionType): oid = ExtensionOID.CRL_NUMBER - def __init__(self, crl_number): + def __init__(self, crl_number: int): if not isinstance(crl_number, int): raise TypeError("crl_number must be an integer") @@ -171,9 +172,9 @@ class AuthorityKeyIdentifier(ExtensionType): def __init__( self, - key_identifier, - authority_cert_issuer, - authority_cert_serial_number, + key_identifier: typing.Optional[bytes], + authority_cert_issuer: typing.Optional[typing.Iterable[GeneralName]], + authority_cert_serial_number: typing.Optional[int], ): if (authority_cert_issuer is None) != ( authority_cert_serial_number is None @@ -203,7 +204,9 @@ def __init__( self._authority_cert_serial_number = authority_cert_serial_number @classmethod - def from_issuer_public_key(cls, public_key): + def from_issuer_public_key( + cls, public_key: _PUBLIC_KEY_TYPES + ) -> "AuthorityKeyIdentifier": digest = _key_identifier_from_public_key(public_key) return cls( key_identifier=digest, @@ -212,7 +215,9 @@ def from_issuer_public_key(cls, public_key): ) @classmethod - def from_issuer_subject_key_identifier(cls, ski): + def from_issuer_subject_key_identifier( + cls, ski: "SubjectKeyIdentifier" + ) -> "AuthorityKeyIdentifier": return cls( key_identifier=ski.digest, authority_cert_issuer=None, @@ -260,11 +265,13 @@ def __hash__(self): class SubjectKeyIdentifier(ExtensionType): oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER - def __init__(self, digest): + def __init__(self, digest: bytes): self._digest = digest @classmethod - def from_public_key(cls, public_key): + def from_public_key( + cls, public_key: _PUBLIC_KEY_TYPES + ) -> "SubjectKeyIdentifier": return cls(_key_identifier_from_public_key(public_key)) digest = utils.read_only_property("_digest") @@ -288,7 +295,7 @@ def __hash__(self): class AuthorityInformationAccess(ExtensionType): oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS - def __init__(self, descriptions): + def __init__(self, descriptions: typing.Iterable["AccessDescription"]): descriptions = list(descriptions) if not all(isinstance(x, AccessDescription) for x in descriptions): raise TypeError( @@ -319,7 +326,7 @@ def __hash__(self): class SubjectInformationAccess(ExtensionType): oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS - def __init__(self, descriptions): + def __init__(self, descriptions: typing.Iterable["AccessDescription"]): descriptions = list(descriptions) if not all(isinstance(x, AccessDescription) for x in descriptions): raise TypeError( @@ -348,7 +355,9 @@ def __hash__(self): class AccessDescription(object): - def __init__(self, access_method, access_location): + def __init__( + self, access_method: ObjectIdentifier, access_location: GeneralName + ): if not isinstance(access_method, ObjectIdentifier): raise TypeError("access_method must be an ObjectIdentifier") @@ -386,7 +395,7 @@ def __hash__(self): class BasicConstraints(ExtensionType): oid = ExtensionOID.BASIC_CONSTRAINTS - def __init__(self, ca, path_length): + def __init__(self, ca: bool, path_length: typing.Optional[int]): if not isinstance(ca, bool): raise TypeError("ca must be a boolean value") @@ -427,7 +436,7 @@ def __hash__(self): class DeltaCRLIndicator(ExtensionType): oid = ExtensionOID.DELTA_CRL_INDICATOR - def __init__(self, crl_number): + def __init__(self, crl_number: int): if not isinstance(crl_number, int): raise TypeError("crl_number must be an integer") @@ -454,7 +463,9 @@ def __repr__(self): class CRLDistributionPoints(ExtensionType): oid = ExtensionOID.CRL_DISTRIBUTION_POINTS - def __init__(self, distribution_points): + def __init__( + self, distribution_points: typing.Iterable["DistributionPoint"] + ): distribution_points = list(distribution_points) if not all( isinstance(x, DistributionPoint) for x in distribution_points @@ -489,7 +500,9 @@ def __hash__(self): class FreshestCRL(ExtensionType): oid = ExtensionOID.FRESHEST_CRL - def __init__(self, distribution_points): + def __init__( + self, distribution_points: typing.Iterable["DistributionPoint"] + ): distribution_points = list(distribution_points) if not all( isinstance(x, DistributionPoint) for x in distribution_points @@ -522,7 +535,13 @@ def __hash__(self): class DistributionPoint(object): - def __init__(self, full_name, relative_name, reasons, crl_issuer): + def __init__( + self, + full_name: typing.Optional[typing.Iterable[GeneralName]], + relative_name: typing.Optional[RelativeDistinguishedName], + reasons: typing.Optional[typing.FrozenSet["ReasonFlags"]], + crl_issuer: typing.Optional[typing.Iterable[GeneralName]], + ): if full_name and relative_name: raise ValueError( "You cannot provide both full_name and relative_name, at " @@ -631,7 +650,11 @@ class ReasonFlags(Enum): class PolicyConstraints(ExtensionType): oid = ExtensionOID.POLICY_CONSTRAINTS - def __init__(self, require_explicit_policy, inhibit_policy_mapping): + def __init__( + self, + require_explicit_policy: typing.Optional[int], + inhibit_policy_mapping: typing.Optional[int], + ): if require_explicit_policy is not None and not isinstance( require_explicit_policy, int ): @@ -691,7 +714,7 @@ def __hash__(self): class CertificatePolicies(ExtensionType): oid = ExtensionOID.CERTIFICATE_POLICIES - def __init__(self, policies): + def __init__(self, policies: typing.Iterable["PolicyInformation"]): policies = list(policies) if not all(isinstance(x, PolicyInformation) for x in policies): raise TypeError( @@ -720,7 +743,13 @@ def __hash__(self): class PolicyInformation(object): - def __init__(self, policy_identifier, policy_qualifiers): + def __init__( + self, + policy_identifier: ObjectIdentifier, + policy_qualifiers: typing.Optional[ + typing.Iterable[typing.Union[str, "UserNotice"]] + ], + ): if not isinstance(policy_identifier, ObjectIdentifier): raise TypeError("policy_identifier must be an ObjectIdentifier") @@ -769,7 +798,11 @@ def __hash__(self): class UserNotice(object): - def __init__(self, notice_reference, explicit_text): + def __init__( + self, + notice_reference: typing.Optional["NoticeReference"], + explicit_text: typing.Optional[str], + ): if notice_reference and not isinstance( notice_reference, NoticeReference ): @@ -806,7 +839,11 @@ def __hash__(self): class NoticeReference(object): - def __init__(self, organization, notice_numbers): + def __init__( + self, + organization: typing.Optional[str], + notice_numbers: typing.Iterable[int], + ): self._organization = organization notice_numbers = list(notice_numbers) if not all(isinstance(x, int) for x in notice_numbers): @@ -842,7 +879,7 @@ def __hash__(self): class ExtendedKeyUsage(ExtensionType): oid = ExtensionOID.EXTENDED_KEY_USAGE - def __init__(self, usages): + def __init__(self, usages: typing.Iterable[ObjectIdentifier]): usages = list(usages) if not all(isinstance(x, ObjectIdentifier) for x in usages): raise TypeError( @@ -910,7 +947,7 @@ def __repr__(self): class TLSFeature(ExtensionType): oid = ExtensionOID.TLS_FEATURE - def __init__(self, features): + def __init__(self, features: typing.Iterable["TLSFeatureType"]): features = list(features) if ( not all(isinstance(x, TLSFeatureType) for x in features) @@ -958,7 +995,7 @@ class TLSFeatureType(Enum): class InhibitAnyPolicy(ExtensionType): oid = ExtensionOID.INHIBIT_ANY_POLICY - def __init__(self, skip_certs): + def __init__(self, skip_certs: int): if not isinstance(skip_certs, int): raise TypeError("skip_certs must be an integer") diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index 938357f2d514..b8f226d5f848 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -7,6 +7,7 @@ import datetime import ipaddress import os +import typing import pretend @@ -138,7 +139,7 @@ def test_hash(self): class TestTLSFeature(object): def test_not_enum_type(self): with pytest.raises(TypeError): - x509.TLSFeature([3]) + x509.TLSFeature([3]) # type:ignore[list-item] def test_empty_list(self): with pytest.raises(TypeError): @@ -346,7 +347,7 @@ def test_repr(self): class TestDeltaCRLIndicator(object): def test_not_int(self): with pytest.raises(TypeError): - x509.DeltaCRLIndicator("notanint") + x509.DeltaCRLIndicator("notanint") # type:ignore[arg-type] def test_eq(self): delta1 = x509.DeltaCRLIndicator(1) @@ -404,11 +405,13 @@ def test_hash(self): class TestNoticeReference(object): def test_notice_numbers_not_all_int(self): with pytest.raises(TypeError): - x509.NoticeReference("org", [1, 2, "three"]) + x509.NoticeReference( + "org", [1, 2, "three"] # type:ignore[list-item] + ) def test_notice_numbers_none(self): with pytest.raises(TypeError): - x509.NoticeReference("org", None) + x509.NoticeReference("org", None) # type:ignore[arg-type] def test_iter_input(self): numbers = [1, 3, 4] @@ -447,7 +450,7 @@ def test_hash(self): class TestUserNotice(object): def test_notice_reference_invalid(self): with pytest.raises(TypeError): - x509.UserNotice("invalid", None) + x509.UserNotice("invalid", None) # type:ignore[arg-type] def test_notice_reference_none(self): un = x509.UserNotice(None, "text") @@ -491,7 +494,7 @@ def test_hash(self): class TestPolicyInformation(object): def test_invalid_policy_identifier(self): with pytest.raises(TypeError): - x509.PolicyInformation("notanoid", None) + x509.PolicyInformation("notanoid", None) # type:ignore[arg-type] def test_none_policy_qualifiers(self): pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), None) @@ -506,7 +509,10 @@ def test_policy_qualifiers(self): def test_invalid_policy_identifiers(self): with pytest.raises(TypeError): - x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), [1, 2]) + x509.PolicyInformation( + x509.ObjectIdentifier("1.2.3"), + [1, 2], # type:ignore[list-item] + ) def test_iter_input(self): qual = ["foo", "bar"] @@ -514,7 +520,10 @@ def test_iter_input(self): assert list(pi.policy_qualifiers) == qual def test_repr(self): - pq = ["string", x509.UserNotice(None, "hi")] + pq: typing.List[typing.Union[str, x509.UserNotice]] = [ + "string", + x509.UserNotice(None, "hi"), + ] pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), pq) assert repr(pi) == ( " Date: Thu, 11 Feb 2021 22:15:39 -0500 Subject: [PATCH 0029/1456] Updates for our new main branch (#5818) --- .github/workflows/ci.yml | 4 ++-- CHANGELOG.rst | 6 +++--- README.rst | 8 ++++---- docs/development/reviewing-patches.rst | 6 +++--- docs/security.rst | 4 ++-- release.py | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 72d10002a40d..ba020a4a915f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,7 @@ on: pull_request: {} push: branches: - - master + - main - '*.*.x' tags: - '*.*' @@ -338,7 +338,7 @@ jobs: - run: ./.github/downstream.d/${{ matrix.DOWNSTREAM }}.sh run docs-linkcheck: - if: github.event_name == 'push' && github.ref == 'refs/heads/master' + if: github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest name: "linkcheck" timeout-minutes: 30 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index afd1d61372a7..0570a16eacce 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,8 +3,8 @@ Changelog .. _v3-5: -3.5 - `master`_ -~~~~~~~~~~~~~~~~ +3.5 - `main`_ +~~~~~~~~~~~~~ .. note:: This version is not yet released and is under active development. @@ -1691,5 +1691,5 @@ Changelog * Initial release. -.. _`master`: https://github.com/pyca/cryptography/ +.. _`main`: https://github.com/pyca/cryptography/ .. _`cffi`: https://cffi.readthedocs.io/ diff --git a/README.rst b/README.rst index 06bdbbec1f65..bb5f6f300666 100644 --- a/README.rst +++ b/README.rst @@ -9,11 +9,11 @@ pyca/cryptography :target: https://cryptography.io :alt: Latest Docs -.. image:: https://github.com/pyca/cryptography/workflows/CI/badge.svg?branch=master - :target: https://github.com/pyca/cryptography/actions?query=workflow%3ACI+branch%3Amaster +.. image:: https://github.com/pyca/cryptography/workflows/CI/badge.svg?branch=main + :target: https://github.com/pyca/cryptography/actions?query=workflow%3ACI+branch%3Amain -.. image:: https://codecov.io/github/pyca/cryptography/coverage.svg?branch=master - :target: https://codecov.io/github/pyca/cryptography?branch=master +.. image:: https://codecov.io/github/pyca/cryptography/coverage.svg?branch=main + :target: https://codecov.io/github/pyca/cryptography?branch=main ``cryptography`` is a package which provides cryptographic recipes and diff --git a/docs/development/reviewing-patches.rst b/docs/development/reviewing-patches.rst index 084461830be3..d3d66482aaed 100644 --- a/docs/development/reviewing-patches.rst +++ b/docs/development/reviewing-patches.rst @@ -41,15 +41,15 @@ Merge requirements Because cryptography is so complex, and the implications of getting it wrong so devastating, ``cryptography`` has a strict merge policy for committers: -* Patches must *never* be pushed directly to ``master``, all changes (even the +* Patches must *never* be pushed directly to ``main``, all changes (even the most trivial typo fixes!) must be submitted as a pull request. * A committer may *never* merge their own pull request, a second party must merge their changes. If multiple people work on a pull request, it must be merged by someone who did not work on it. * A patch that breaks tests, or introduces regressions by changing or removing existing tests should not be merged. Tests must always be passing on - ``master``. -* If somehow the tests get into a failing state on ``master`` (such as by a + ``main``. +* If somehow the tests get into a failing state on ``main`` (such as by a backwards incompatible release of a dependency) no pull requests may be merged until this is rectified. * All merged patches must have 100% test coverage. diff --git a/docs/security.rst b/docs/security.rst index d11f2700012a..6cd9dbe33937 100644 --- a/docs/security.rst +++ b/docs/security.rst @@ -64,7 +64,7 @@ further follow-up emails. Supported Versions ------------------ -At any given time, we will provide security support for the `master`_ branch +At any given time, we will provide security support for the `main`_ branch as well as the most recent release. New releases for OpenSSL updates @@ -89,4 +89,4 @@ The steps for issuing a security release are described in our :doc:`/doing-a-release` documentation. -.. _`master`: https://github.com/pyca/cryptography +.. _`main`: https://github.com/pyca/cryptography diff --git a/release.py b/release.py index 3416c8c56340..f5cf54d92575 100644 --- a/release.py +++ b/release.py @@ -90,7 +90,7 @@ def build_github_actions_wheels(token, version): "Accept": "application/vnd.github.v3+json", "Authorization": "token {}".format(token), }, - data=json.dumps({"ref": "master", "inputs": {"version": version}}), + data=json.dumps({"ref": "main", "inputs": {"version": version}}), ) response.raise_for_status() From 5ec07b89a203c896042c8dc1f6f810789c6ab573 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 11 Feb 2021 21:19:44 -0600 Subject: [PATCH 0030/1456] document how we should publish CVEs more rigorously (#5819) short version: in git commit, in changelog, in GH security advisory --- docs/doing-a-release.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/doing-a-release.rst b/docs/doing-a-release.rst index 5583ac4c2692..12d6bb063f18 100644 --- a/docs/doing-a-release.rst +++ b/docs/doing-a-release.rst @@ -13,7 +13,11 @@ security vulnerability, you should also include the following steps: 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. +* Document the CVE in the git commit that fixes the issue. +* Ensure that the :doc:`changelog` entry credits whoever reported the issue and + contains the assigned CVE. +* Publish a GitHub Security Advisory on the repository with all relevant + information. * The release should be announced on the `oss-security`_ mailing list, in addition to the regular announcement lists. From 32e540d10cbb17dd524d40fdb41fa4abfdcde1c4 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 12 Feb 2021 13:34:01 -0500 Subject: [PATCH 0031/1456] Add a comment to our readthedocs config file (#5821) --- .readthedocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.readthedocs.yml b/.readthedocs.yml index 728bb390c30c..ac4882422355 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,5 +1,6 @@ version: 2 build: + # First RTD build env which includes a rust toolchain image: "7.0" From 4b6b5063d3b2d8370be7dac9c264688e083b28cd Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 12 Feb 2021 15:43:56 -0500 Subject: [PATCH 0032/1456] Document that Rust is required at build time only (#5822) * Document that Rust is required at build time only * Update docs/faq.rst Co-authored-by: Paul Kehrer * Update docs/installation.rst Co-authored-by: Paul Kehrer Co-authored-by: Paul Kehrer --- docs/faq.rst | 5 +++++ docs/installation.rst | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/docs/faq.rst b/docs/faq.rst index 4123a1cf8461..c43396cf911e 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -127,6 +127,11 @@ by upgrading to a newer version of ``pip`` which will install a pre-compiled :ref:`instructions` to ensure you install a recent Rust version. +Rust is only required during the build phase of ``cryptography``, you do not +need to have Rust installed after you've built ``cryptography``. This is the +same as the C compiler toolchain which is also required to build +``cryptography``, but not afterwards. + For the current release *only* you can temporarily bypass the requirement to have Rust installed by setting the ``CRYPTOGRAPHY_DONT_BUILD_RUST`` environment variable. Note that this option will be removed in the next release and not diff --git a/docs/installation.rst b/docs/installation.rst index ea2f33c7bb94..ee435a6b4f22 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -335,6 +335,14 @@ Instructions for installing Rust can be found on `the Rust Project's website`_. We recommend installing Rust with ``rustup`` (as documented by the Rust Project) in order to ensure you have a recent version. +Rust is only required when building ``cryptography``, meaning that you may +install it for the duration of your ``pip install`` command and then remove it +from a system. A Rust toolchain is not required to **use** ``cryptography``. In +deployments such as ``docker``, you may use a multi-stage ``Dockerfile`` where +you install Rust during the build phase but do not install it in the runtime +image. This is the same as the C compiler toolchain which is also required to +build ``cryptography``, but not afterwards. + .. _`Homebrew`: https://brew.sh .. _`MacPorts`: https://www.macports.org .. _`a binary distribution`: https://wiki.openssl.org/index.php/Binaries From e82cd4e4e5947cc733876d815a455aa624b87141 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 13 Feb 2021 12:25:31 -0500 Subject: [PATCH 0033/1456] change to a new version scheme (#5825) * change to a new version scheme fixes #5801 * Update docs/api-stability.rst Co-authored-by: Paul Kehrer * line length Co-authored-by: Paul Kehrer --- CHANGELOG.rst | 6 +-- docs/api-stability.rst | 51 +++++++++++++++++------ src/cryptography/__about__.py | 2 +- vectors/cryptography_vectors/__about__.py | 2 +- 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0570a16eacce..39e9e78bc78e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,10 +1,10 @@ Changelog ========= -.. _v3-5: +.. _v35-0-0: -3.5 - `main`_ -~~~~~~~~~~~~~ +35.0.0 - `main`_ +~~~~~~~~~~~~~~~~ .. note:: This version is not yet released and is under active development. diff --git a/docs/api-stability.rst b/docs/api-stability.rst index fd34ced0aba1..3822702d3937 100644 --- a/docs/api-stability.rst +++ b/docs/api-stability.rst @@ -37,18 +37,23 @@ policy as necessary in order to resolve a security issue or harden Versioning ---------- -This project uses a custom versioning scheme as described below. +Version 35.0.0+ +~~~~~~~~~~~~~~~ -Given a version ``cryptography X.Y.Z``, +Beginning with release 35.0.0 ``cryptography`` uses a Firefox-inspired version +scheme. -* ``X.Y`` is a decimal number that is incremented for - potentially-backwards-incompatible releases. +Given a version ``cryptography X.Y.Z``, - * 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. +* ``X`` indicates the major version number. This is incremented on any feature + release. +* ``Y`` is always ``0``. +* ``Z`` is an integer that is incremented for minor backward-compatible + releases (such as fixing security issues or correcting regressions in a major + release). -* ``Z`` is an integer that is incremented for backward-compatible releases. +This scheme is compatible with `SemVer`_, though many major releases will +**not** include any backwards-incompatible changes. Deprecation ~~~~~~~~~~~ @@ -56,16 +61,36 @@ 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 + 0.1`` using that feature will emit a +* In ``cryptography X.0.0`` the feature exists. +* In ``cryptography (X + 1).0.0`` using that feature will emit a ``UserWarning``. -* In ``cryptography X.Y + 0.2`` using that feature will emit a +* In ``cryptography (X + 2).0.0`` using that feature will emit a ``UserWarning``. -* In ``cryptography X.Y + 0.3`` the feature will be removed or changed. +* In ``cryptography (X + 3).0.0`` 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. +period of two major releases. From time to time, we may decide to deprecate an API that is particularly widely used. In these cases, we may decide to provide an extended deprecation period, at our discretion. + +Previous Scheme +~~~~~~~~~~~~~~~ + +Before version 35.0.0 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. + + +.. _`SemVer`: https://semver.org/ diff --git a/src/cryptography/__about__.py b/src/cryptography/__about__.py index 451d0fe52ff4..a035fa12ffd2 100644 --- a/src/cryptography/__about__.py +++ b/src/cryptography/__about__.py @@ -21,7 +21,7 @@ ) __uri__ = "https://github.com/pyca/cryptography" -__version__ = "3.5.dev1" +__version__ = "35.0.0.dev1" __author__ = "The Python Cryptographic Authority and individual contributors" __email__ = "cryptography-dev@python.org" diff --git a/vectors/cryptography_vectors/__about__.py b/vectors/cryptography_vectors/__about__.py index eee22cf0e5bb..05fa40efc53d 100644 --- a/vectors/cryptography_vectors/__about__.py +++ b/vectors/cryptography_vectors/__about__.py @@ -18,7 +18,7 @@ __uri__ = "https://github.com/pyca/cryptography" -__version__ = "3.5.dev1" +__version__ = "35.0.0.dev1" __author__ = "The Python Cryptographic Authority and individual contributors" __email__ = "cryptography-dev@python.org" From 2ed07926a9a19595f51ed1b6c5f985652c16bda8 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 13 Feb 2021 12:31:44 -0500 Subject: [PATCH 0034/1456] Start replacing read_only_property with dedicated functions (#5824) read_only_property is basically impossible for mypy to check --- .../hazmat/primitives/asymmetric/dh.py | 15 +++++++------ .../hazmat/primitives/asymmetric/dsa.py | 15 +++++++------ .../hazmat/primitives/asymmetric/ec.py | 21 ++++++++++++------- .../hazmat/primitives/asymmetric/rsa.py | 19 ++++++++--------- .../hazmat/primitives/asymmetric/utils.py | 3 +-- tests/hazmat/primitives/test_asym_utils.py | 6 ++++++ 6 files changed, 44 insertions(+), 35 deletions(-) diff --git a/src/cryptography/hazmat/primitives/asymmetric/dh.py b/src/cryptography/hazmat/primitives/asymmetric/dh.py index 9c53e509288b..6867f5365510 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/dh.py +++ b/src/cryptography/hazmat/primitives/asymmetric/dh.py @@ -6,7 +6,6 @@ import abc import typing -from cryptography import utils from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.primitives import serialization @@ -53,9 +52,9 @@ def parameters(self, backend=None): backend = _get_backend(backend) return backend.load_dh_parameter_numbers(self) - p = utils.read_only_property("_p") - g = utils.read_only_property("_g") - q = utils.read_only_property("_q") + p = property(lambda self: self._p) + g = property(lambda self: self._g) + q = property(lambda self: self._q) class DHPublicNumbers(object): @@ -87,8 +86,8 @@ def public_key(self, backend=None) -> "DHPublicKey": backend = _get_backend(backend) return backend.load_dh_public_numbers(self) - y = utils.read_only_property("_y") - parameter_numbers = utils.read_only_property("_parameter_numbers") + y = property(lambda self: self._y) + parameter_numbers = property(lambda self: self._parameter_numbers) class DHPrivateNumbers(object): @@ -120,8 +119,8 @@ def private_key(self, backend=None) -> "DHPrivateKey": backend = _get_backend(backend) return backend.load_dh_private_numbers(self) - public_numbers = utils.read_only_property("_public_numbers") - x = utils.read_only_property("_x") + public_numbers = property(lambda self: self._public_numbers) + x = property(lambda self: self._x) class DHParameters(metaclass=abc.ABCMeta): diff --git a/src/cryptography/hazmat/primitives/asymmetric/dsa.py b/src/cryptography/hazmat/primitives/asymmetric/dsa.py index c6f991bc7492..7946c02a7c60 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/dsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -6,7 +6,6 @@ import abc import typing -from cryptography import utils from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.primitives import _serialization, hashes from cryptography.hazmat.primitives.asymmetric import ( @@ -161,9 +160,9 @@ def __init__(self, p: int, q: int, g: int): self._q = q self._g = g - p = utils.read_only_property("_p") - q = utils.read_only_property("_q") - g = utils.read_only_property("_g") + p = property(lambda self: self._p) + q = property(lambda self: self._q) + g = property(lambda self: self._g) def parameters(self, backend=None) -> DSAParameters: backend = _get_backend(backend) @@ -198,8 +197,8 @@ def __init__(self, y: int, parameter_numbers: DSAParameterNumbers): self._y = y self._parameter_numbers = parameter_numbers - y = utils.read_only_property("_y") - parameter_numbers = utils.read_only_property("_parameter_numbers") + y = property(lambda self: self._y) + parameter_numbers = property(lambda self: self._parameter_numbers) def public_key(self, backend=None) -> DSAPublicKey: backend = _get_backend(backend) @@ -236,8 +235,8 @@ def __init__(self, x: int, public_numbers: DSAPublicNumbers): self._public_numbers = public_numbers self._x = x - x = utils.read_only_property("_x") - public_numbers = utils.read_only_property("_public_numbers") + x = property(lambda self: self._x) + public_numbers = property(lambda self: self._public_numbers) def private_key(self, backend=None) -> DSAPrivateKey: backend = _get_backend(backend) diff --git a/src/cryptography/hazmat/primitives/asymmetric/ec.py b/src/cryptography/hazmat/primitives/asymmetric/ec.py index 56c5f9a02c21..41dc5b58079c 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ec.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ec.py @@ -326,10 +326,17 @@ class BrainpoolP512R1(EllipticCurve): class ECDSA(EllipticCurveSignatureAlgorithm): - def __init__(self, algorithm): + def __init__( + self, + algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], + ): self._algorithm = algorithm - algorithm = utils.read_only_property("_algorithm") + @property + def algorithm( + self, + ) -> typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm]: + return self._algorithm def generate_private_key( @@ -415,9 +422,9 @@ def from_encoded_point( else: raise ValueError("Unsupported elliptic curve point type") - curve = utils.read_only_property("_curve") - x = utils.read_only_property("_x") - y = utils.read_only_property("_y") + curve = property(lambda self: self._curve) + x = property(lambda self: self._x) + y = property(lambda self: self._y) def __eq__(self, other): if not isinstance(other, EllipticCurvePublicNumbers): @@ -463,8 +470,8 @@ def private_key(self, backend=None) -> EllipticCurvePrivateKey: backend = _get_backend(backend) return backend.load_elliptic_curve_private_numbers(self) - private_value = utils.read_only_property("_private_value") - public_numbers = utils.read_only_property("_public_numbers") + private_value = property(lambda self: self._private_value) + public_numbers = property(lambda self: self._public_numbers) def __eq__(self, other): if not isinstance(other, EllipticCurvePrivateNumbers): diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py index 213e518db41a..106e464bc49a 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -7,7 +7,6 @@ import typing from math import gcd -from cryptography import utils from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import RSABackend @@ -354,13 +353,13 @@ def __init__( self._iqmp = iqmp self._public_numbers = public_numbers - p = utils.read_only_property("_p") - q = utils.read_only_property("_q") - d = utils.read_only_property("_d") - dmp1 = utils.read_only_property("_dmp1") - dmq1 = utils.read_only_property("_dmq1") - iqmp = utils.read_only_property("_iqmp") - public_numbers = utils.read_only_property("_public_numbers") + p = property(lambda self: self._p) + q = property(lambda self: self._q) + d = property(lambda self: self._d) + dmp1 = property(lambda self: self._dmp1) + dmq1 = property(lambda self: self._dmq1) + iqmp = property(lambda self: self._iqmp) + public_numbers = property(lambda self: self._public_numbers) def private_key(self, backend=None) -> RSAPrivateKey: backend = _get_backend(backend) @@ -405,8 +404,8 @@ def __init__(self, e: int, n: int): self._e = e self._n = n - e = utils.read_only_property("_e") - n = utils.read_only_property("_n") + e = property(lambda self: self._e) + n = property(lambda self: self._n) def public_key(self, backend=None) -> RSAPublicKey: backend = _get_backend(backend) diff --git a/src/cryptography/hazmat/primitives/asymmetric/utils.py b/src/cryptography/hazmat/primitives/asymmetric/utils.py index 1118abcf251f..931df018414b 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/utils.py +++ b/src/cryptography/hazmat/primitives/asymmetric/utils.py @@ -5,7 +5,6 @@ import typing -from cryptography import utils from cryptography.hazmat._der import ( DERReader, INTEGER, @@ -39,4 +38,4 @@ def __init__(self, algorithm: hashes.HashAlgorithm): self._algorithm = algorithm self._digest_size = algorithm.digest_size - digest_size = utils.read_only_property("_digest_size") + digest_size = property(lambda self: self._digest_size) diff --git a/tests/hazmat/primitives/test_asym_utils.py b/tests/hazmat/primitives/test_asym_utils.py index 0891cc87aa1d..e4f22d7303e9 100644 --- a/tests/hazmat/primitives/test_asym_utils.py +++ b/tests/hazmat/primitives/test_asym_utils.py @@ -5,6 +5,7 @@ import pytest +from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric.utils import ( Prehashed, decode_dss_signature, @@ -74,3 +75,8 @@ def test_decode_dss_invalid_asn1(): def test_pass_invalid_prehashed_arg(): with pytest.raises(TypeError): Prehashed(object()) # type: ignore[arg-type] + + +def test_prehashed_digest_size(): + p = Prehashed(hashes.SHA256()) + assert p.digest_size == 32 From 7e30277483f5556ba05ab57edec11f0b8eebbb6e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 13 Feb 2021 14:35:56 -0500 Subject: [PATCH 0035/1456] Bump pyo3 and lower MSRV (#5823) --- .github/workflows/ci.yml | 3 +- docs/installation.rst | 6 ++-- setup.py | 2 +- src/rust/Cargo.lock | 74 +++++++++++++++++++++++++++++++--------- 4 files changed, 64 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba020a4a915f..e599991971ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -143,7 +143,8 @@ jobs: PYTHON: - {VERSION: "3.9", TOXENV: "py39"} RUST: - # Cover MSRV and in-dev versions + # Cover MSRV (and likely next MSRV) and in-dev versions + - 1.41.0 - 1.45.0 - beta - nightly diff --git a/docs/installation.rst b/docs/installation.rst index ee435a6b4f22..278e680ce1f5 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -105,7 +105,7 @@ Alpine .. warning:: - The Rust available by default in Alpine < 3.13 is older than the minimum + The Rust available by default in Alpine < 3.12 is older than the minimum supported version. See the :ref:`Rust installation instructions ` for information about installing a newer Rust. @@ -137,7 +137,7 @@ Fedora/RHEL 8/CentOS 8 .. warning:: For RHEL and CentOS you must be on version 8.3 or newer for the command - below to install a sufficiently new Rust. If your Rust is less than 1.45.0 + below to install a sufficiently new Rust. If your Rust is less than 1.41.0 please see the :ref:`Rust installation instructions ` for information about installing a newer Rust. @@ -327,7 +327,7 @@ Rust a binary wheel and require no compiler if you have an updated ``pip``! Building ``cryptography`` requires having a working Rust toolchain. The current -minimum supported Rust version is 1.45.0. **This is newer than the Rust most +minimum supported Rust version is 1.41.0. **This is newer than the Rust most package managers ship**, so users will likely need to install with the instructions below. diff --git a/setup.py b/setup.py index 1a22695427a4..74f69e7148a6 100644 --- a/setup.py +++ b/setup.py @@ -59,7 +59,7 @@ if platform.python_implementation() == "PyPy" else ["pyo3/abi3-py36"] ), - rust_version=">=1.45.0", + rust_version=">=1.41.0", ) ] diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 88161c27d45d..94f89ff74762 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -1,5 +1,11 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + [[package]] name = "cfg-if" version = "1.0.0" @@ -36,10 +42,24 @@ dependencies = [ [[package]] name = "indoc" -version = "1.0.3" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47741a8bc60fb26eb8d6e0238bbb26d8575ff623fdc97b1a2c00c050b9684ed8" +dependencies = [ + "indoc-impl", + "proc-macro-hack", +] + +[[package]] +name = "indoc-impl" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a75aeaaef0ce18b58056d306c27b07436fbb34b8816c53094b76dd81803136" +checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0" dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", "unindent", ] @@ -102,9 +122,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" dependencies = [ "cfg-if", "instant", @@ -116,9 +136,28 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.4" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d65c4d95931acda4498f675e332fcbdc9a06705cd07086c510e9b6009cd1c1" +checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880" +dependencies = [ + "paste-impl", + "proc-macro-hack", +] + +[[package]] +name = "paste-impl" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6" +dependencies = [ + "proc-macro-hack", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" @@ -131,9 +170,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00ca634cf3acd58a599b535ed6cb188223298977d471d146121792bfa23b754c" +checksum = "4837b8e8e18a102c23f79d1e9a110b597ea3b684c95e874eb1ad88f8683109c3" dependencies = [ "cfg-if", "ctor", @@ -148,9 +187,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "483ac516dbda6789a5b4be0271e7a31b9ad4ec8c0a5955050e8076f72bdbef8f" +checksum = "a47f2c300ceec3e58064fd5f8f5b61230f2ffd64bde4970c81fdd0563a2db1bb" dependencies = [ "pyo3-macros-backend", "quote", @@ -159,9 +198,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15230cabcda008f03565ed8bac40f094cbb5ee1b46e6551f1ec3a0e922cf7df9" +checksum = "87b097e5d84fcbe3e167f400fbedd657820a375b034c78bd852050749a575d66" dependencies = [ "proc-macro2", "quote", @@ -170,18 +209,21 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.1.57" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +dependencies = [ + "bitflags", +] [[package]] name = "scopeguard" From 151aa097cdf4632f382bc8c95d7771ed7290cf66 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 13 Feb 2021 17:17:39 -0600 Subject: [PATCH 0036/1456] port 3.4.5 changelog (#5828) --- CHANGELOG.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 39e9e78bc78e..91e50b278243 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,19 @@ Changelog .. note:: This version is not yet released and is under active development. +.. _v3-4-5: + +3.4.5 - 2021-02-13 +~~~~~~~~~~~~~~~~~~ + +* Various improvements to type hints. +* Lower the minimum supported Rust version (MSRV) to >=1.41.0. This change + improves compatibility with system-provided Rust on several Linux + distributions. +* ``cryptography`` will be switching to a new versioning scheme with its next + feature release. More information is available in our + :doc:`/api-stability` documentation. + .. _v3-4-4: 3.4.4 - 2021-02-09 From a15b5808ebc80da42d6c54663eb8070141343eb6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Feb 2021 08:47:11 -0500 Subject: [PATCH 0037/1456] Bump redox_syscall from 0.2.4 to 0.2.5 in /src/rust (#5832) Bumps redox_syscall from 0.2.4 to 0.2.5. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 94f89ff74762..83fd7eb8f48b 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -218,9 +218,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" dependencies = [ "bitflags", ] From 96801ff92e861c8ee333c14afda691d1025e5e8f Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Mon, 15 Feb 2021 22:11:50 +0100 Subject: [PATCH 0038/1456] add typehints for read only properties (#5826) * add typehints for read only properties * fix typing in test cases * fix last missing assertion * add typehints to all read_only_properties where type hints are already available * check for isnot None instead, as per PR suggestion * convert read_only_property to @property decorators * remove unused import * use List instead of Iterable for return values * use @property instead of read_only_property * fix type errors * remove last occurance of annotated read_only_property * use is not None check (works because we now return list) * fix unused import --- src/cryptography/hazmat/_oid.py | 7 +- .../hazmat/backends/openssl/hashes.py | 5 +- .../hazmat/backends/openssl/hmac.py | 5 +- .../hazmat/primitives/ciphers/algorithms.py | 4 +- .../hazmat/primitives/ciphers/modes.py | 39 +++- src/cryptography/hazmat/primitives/hashes.py | 20 +- src/cryptography/hazmat/primitives/hmac.py | 4 +- src/cryptography/x509/extensions.py | 201 +++++++++++++----- src/cryptography/x509/general_name.py | 41 +++- src/cryptography/x509/name.py | 12 +- tests/x509/test_x509_crlbuilder.py | 1 + tests/x509/test_x509_ext.py | 6 + 12 files changed, 259 insertions(+), 86 deletions(-) diff --git a/src/cryptography/hazmat/_oid.py b/src/cryptography/hazmat/_oid.py index 27eeb7d7d7ff..3e22ea9f284e 100644 --- a/src/cryptography/hazmat/_oid.py +++ b/src/cryptography/hazmat/_oid.py @@ -3,9 +3,6 @@ # for complete details. -from cryptography import utils - - class ObjectIdentifier(object): def __init__(self, dotted_string: str): self._dotted_string = dotted_string @@ -73,4 +70,6 @@ def _name(self): return _OID_NAMES.get(self, "Unknown OID") - dotted_string = utils.read_only_property("_dotted_string") + @property + def dotted_string(self) -> str: + return self._dotted_string diff --git a/src/cryptography/hazmat/backends/openssl/hashes.py b/src/cryptography/hazmat/backends/openssl/hashes.py index 823d24f91595..aa816c122663 100644 --- a/src/cryptography/hazmat/backends/openssl/hashes.py +++ b/src/cryptography/hazmat/backends/openssl/hashes.py @@ -3,7 +3,6 @@ # for complete details. -from cryptography import utils from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.hazmat.primitives import hashes @@ -34,7 +33,9 @@ def __init__(self, backend, algorithm: hashes.HashAlgorithm, ctx=None): self._ctx = ctx - algorithm = utils.read_only_property("_algorithm") + @property + def algorithm(self) -> hashes.HashAlgorithm: + return self._algorithm def copy(self) -> "_HashContext": copied_ctx = self._backend._lib.EVP_MD_CTX_new() diff --git a/src/cryptography/hazmat/backends/openssl/hmac.py b/src/cryptography/hazmat/backends/openssl/hmac.py index e9e461300f7a..c9c28f5967ae 100644 --- a/src/cryptography/hazmat/backends/openssl/hmac.py +++ b/src/cryptography/hazmat/backends/openssl/hmac.py @@ -3,7 +3,6 @@ # for complete details. -from cryptography import utils from cryptography.exceptions import ( InvalidSignature, UnsupportedAlgorithm, @@ -40,7 +39,9 @@ def __init__( self._ctx = ctx self._key = key - algorithm = utils.read_only_property("_algorithm") + @property + def algorithm(self) -> hashes.HashAlgorithm: + return self._algorithm def copy(self) -> "_HMACContext": copied_ctx = self._backend._lib.HMAC_CTX_new() diff --git a/src/cryptography/hazmat/primitives/ciphers/algorithms.py b/src/cryptography/hazmat/primitives/ciphers/algorithms.py index ed72516611f3..b1c321941510 100644 --- a/src/cryptography/hazmat/primitives/ciphers/algorithms.py +++ b/src/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -146,7 +146,9 @@ def __init__(self, key: bytes, nonce: bytes): self._nonce = nonce - nonce = utils.read_only_property("_nonce") + @property + def nonce(self) -> bytes: + return self._nonce @property def key_size(self) -> int: diff --git a/src/cryptography/hazmat/primitives/ciphers/modes.py b/src/cryptography/hazmat/primitives/ciphers/modes.py index 5265aad2378a..ec14412e53c4 100644 --- a/src/cryptography/hazmat/primitives/ciphers/modes.py +++ b/src/cryptography/hazmat/primitives/ciphers/modes.py @@ -51,7 +51,7 @@ def nonce(self) -> bytes: class ModeWithAuthenticationTag(metaclass=abc.ABCMeta): @abc.abstractproperty - def tag(self) -> bytes: + def tag(self) -> typing.Optional[bytes]: """ The value of the tag supplied to the constructor of this mode. """ @@ -92,7 +92,10 @@ def __init__(self, initialization_vector: bytes): utils._check_byteslike("initialization_vector", initialization_vector) self._initialization_vector = initialization_vector - initialization_vector = utils.read_only_property("_initialization_vector") + @property + def initialization_vector(self) -> bytes: + return self._initialization_vector + validate_for_algorithm = _check_iv_and_key_length @@ -107,7 +110,9 @@ def __init__(self, tweak: bytes): self._tweak = tweak - tweak = utils.read_only_property("_tweak") + @property + def tweak(self) -> bytes: + return self._tweak def validate_for_algorithm(self, algorithm: CipherAlgorithm): if algorithm.key_size not in (256, 512): @@ -130,7 +135,10 @@ def __init__(self, initialization_vector: bytes): utils._check_byteslike("initialization_vector", initialization_vector) self._initialization_vector = initialization_vector - initialization_vector = utils.read_only_property("_initialization_vector") + @property + def initialization_vector(self) -> bytes: + return self._initialization_vector + validate_for_algorithm = _check_iv_and_key_length @@ -141,7 +149,10 @@ def __init__(self, initialization_vector: bytes): utils._check_byteslike("initialization_vector", initialization_vector) self._initialization_vector = initialization_vector - initialization_vector = utils.read_only_property("_initialization_vector") + @property + def initialization_vector(self) -> bytes: + return self._initialization_vector + validate_for_algorithm = _check_iv_and_key_length @@ -152,7 +163,10 @@ def __init__(self, initialization_vector: bytes): utils._check_byteslike("initialization_vector", initialization_vector) self._initialization_vector = initialization_vector - initialization_vector = utils.read_only_property("_initialization_vector") + @property + def initialization_vector(self) -> bytes: + return self._initialization_vector + validate_for_algorithm = _check_iv_and_key_length @@ -163,7 +177,9 @@ def __init__(self, nonce: bytes): utils._check_byteslike("nonce", nonce) self._nonce = nonce - nonce = utils.read_only_property("_nonce") + @property + def nonce(self) -> bytes: + return self._nonce def validate_for_algorithm(self, algorithm: CipherAlgorithm): _check_aes_key_length(self, algorithm) @@ -203,8 +219,13 @@ def __init__( self._tag = tag self._min_tag_length = min_tag_length - tag = utils.read_only_property("_tag") - initialization_vector = utils.read_only_property("_initialization_vector") + @property + def tag(self) -> typing.Optional[bytes]: + return self._tag + + @property + def initialization_vector(self) -> bytes: + return self._initialization_vector def validate_for_algorithm(self, algorithm: CipherAlgorithm): _check_aes_key_length(self, algorithm) diff --git a/src/cryptography/hazmat/primitives/hashes.py b/src/cryptography/hazmat/primitives/hashes.py index 33907a35a7c5..4f92d6d271da 100644 --- a/src/cryptography/hazmat/primitives/hashes.py +++ b/src/cryptography/hazmat/primitives/hashes.py @@ -88,7 +88,9 @@ def __init__(self, algorithm: HashAlgorithm, backend=None, ctx=None): else: self._ctx = ctx - algorithm = utils.read_only_property("_algorithm") + @property + def algorithm(self) -> HashAlgorithm: + return self._algorithm def update(self, data: bytes) -> None: if self._ctx is None: @@ -190,7 +192,9 @@ def __init__(self, digest_size: int): self._digest_size = digest_size - digest_size = utils.read_only_property("_digest_size") + @property + def digest_size(self) -> int: + return self._digest_size class SHAKE256(HashAlgorithm, ExtendableOutputFunction): @@ -206,7 +210,9 @@ def __init__(self, digest_size: int): self._digest_size = digest_size - digest_size = utils.read_only_property("_digest_size") + @property + def digest_size(self) -> int: + return self._digest_size class MD5(HashAlgorithm): @@ -228,7 +234,9 @@ def __init__(self, digest_size: int): self._digest_size = digest_size - digest_size = utils.read_only_property("_digest_size") + @property + def digest_size(self) -> int: + return self._digest_size class BLAKE2s(HashAlgorithm): @@ -244,4 +252,6 @@ def __init__(self, digest_size: int): self._digest_size = digest_size - digest_size = utils.read_only_property("_digest_size") + @property + def digest_size(self) -> int: + return self._digest_size diff --git a/src/cryptography/hazmat/primitives/hmac.py b/src/cryptography/hazmat/primitives/hmac.py index 5911925b8bdc..927fb87bdf53 100644 --- a/src/cryptography/hazmat/primitives/hmac.py +++ b/src/cryptography/hazmat/primitives/hmac.py @@ -40,7 +40,9 @@ def __init__( else: self._ctx = ctx - algorithm = utils.read_only_property("_algorithm") + @property + def algorithm(self) -> hashes.HashAlgorithm: + return self._algorithm def update(self, data: bytes) -> None: if self._ctx is None: diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 6cae016a1c60..94072aab7f3f 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -164,7 +164,9 @@ def __hash__(self): def __repr__(self): return "".format(self.crl_number) - crl_number = utils.read_only_property("_crl_number") + @property + def crl_number(self) -> int: + return self._crl_number class AuthorityKeyIdentifier(ExtensionType): @@ -255,11 +257,19 @@ def __hash__(self): (self.key_identifier, aci, self.authority_cert_serial_number) ) - key_identifier = utils.read_only_property("_key_identifier") - authority_cert_issuer = utils.read_only_property("_authority_cert_issuer") - authority_cert_serial_number = utils.read_only_property( - "_authority_cert_serial_number" - ) + @property + def key_identifier(self) -> typing.Optional[bytes]: + return self._key_identifier + + @property + def authority_cert_issuer( + self, + ) -> typing.Optional[typing.List[GeneralName]]: + return self._authority_cert_issuer + + @property + def authority_cert_serial_number(self) -> typing.Optional[int]: + return self._authority_cert_serial_number class SubjectKeyIdentifier(ExtensionType): @@ -274,7 +284,9 @@ def from_public_key( ) -> "SubjectKeyIdentifier": return cls(_key_identifier_from_public_key(public_key)) - digest = utils.read_only_property("_digest") + @property + def digest(self) -> bytes: + return self._digest def __repr__(self): return "".format(self.digest) @@ -388,8 +400,13 @@ def __ne__(self, other): def __hash__(self): return hash((self.access_method, self.access_location)) - access_method = utils.read_only_property("_access_method") - access_location = utils.read_only_property("_access_location") + @property + def access_method(self) -> ObjectIdentifier: + return self._access_method + + @property + def access_location(self) -> GeneralName: + return self._access_location class BasicConstraints(ExtensionType): @@ -412,8 +429,13 @@ def __init__(self, ca: bool, path_length: typing.Optional[int]): self._ca = ca self._path_length = path_length - ca = utils.read_only_property("_ca") - path_length = utils.read_only_property("_path_length") + @property + def ca(self) -> bool: + return self._ca + + @property + def path_length(self) -> typing.Optional[int]: + return self._path_length def __repr__(self): return ( @@ -442,7 +464,9 @@ def __init__(self, crl_number: int): self._crl_number = crl_number - crl_number = utils.read_only_property("_crl_number") + @property + def crl_number(self) -> int: + return self._crl_number def __eq__(self, other): if not isinstance(other, DeltaCRLIndicator): @@ -548,7 +572,7 @@ def __init__( "least one must be None." ) - if full_name: + if full_name is not None: full_name = list(full_name) if not all(isinstance(x, GeneralName) for x in full_name): raise TypeError( @@ -561,7 +585,7 @@ def __init__( "relative_name must be a RelativeDistinguishedName" ) - if crl_issuer: + if crl_issuer is not None: crl_issuer = list(crl_issuer) if not all(isinstance(x, GeneralName) for x in crl_issuer): raise TypeError( @@ -628,10 +652,21 @@ def __hash__(self): return hash((fn, self.relative_name, self.reasons, crl_issuer)) - full_name = utils.read_only_property("_full_name") - relative_name = utils.read_only_property("_relative_name") - reasons = utils.read_only_property("_reasons") - crl_issuer = utils.read_only_property("_crl_issuer") + @property + def full_name(self) -> typing.Optional[typing.List[GeneralName]]: + return self._full_name + + @property + def relative_name(self) -> typing.Optional[RelativeDistinguishedName]: + return self._relative_name + + @property + def reasons(self) -> typing.Optional[typing.FrozenSet["ReasonFlags"]]: + return self._reasons + + @property + def crl_issuer(self) -> typing.Optional[typing.List[GeneralName]]: + return self._crl_issuer class ReasonFlags(Enum): @@ -703,12 +738,13 @@ def __hash__(self): (self.require_explicit_policy, self.inhibit_policy_mapping) ) - require_explicit_policy = utils.read_only_property( - "_require_explicit_policy" - ) - inhibit_policy_mapping = utils.read_only_property( - "_inhibit_policy_mapping" - ) + @property + def require_explicit_policy(self) -> typing.Optional[int]: + return self._require_explicit_policy + + @property + def inhibit_policy_mapping(self) -> typing.Optional[int]: + return self._inhibit_policy_mapping class CertificatePolicies(ExtensionType): @@ -755,7 +791,7 @@ def __init__( self._policy_identifier = policy_identifier - if policy_qualifiers: + if policy_qualifiers is not None: policy_qualifiers = list(policy_qualifiers) if not all( isinstance(x, (str, UserNotice)) for x in policy_qualifiers @@ -793,8 +829,15 @@ def __hash__(self): return hash((self.policy_identifier, pq)) - policy_identifier = utils.read_only_property("_policy_identifier") - policy_qualifiers = utils.read_only_property("_policy_qualifiers") + @property + def policy_identifier(self) -> ObjectIdentifier: + return self._policy_identifier + + @property + def policy_qualifiers( + self, + ) -> typing.Optional[typing.List[typing.Union[str, "UserNotice"]]]: + return self._policy_qualifiers class UserNotice(object): @@ -834,8 +877,13 @@ def __ne__(self, other): def __hash__(self): return hash((self.notice_reference, self.explicit_text)) - notice_reference = utils.read_only_property("_notice_reference") - explicit_text = utils.read_only_property("_explicit_text") + @property + def notice_reference(self) -> typing.Optional["NoticeReference"]: + return self._notice_reference + + @property + def explicit_text(self) -> typing.Optional[str]: + return self._explicit_text class NoticeReference(object): @@ -872,8 +920,13 @@ def __ne__(self, other): def __hash__(self): return hash((self.organization, tuple(self.notice_numbers))) - organization = utils.read_only_property("_organization") - notice_numbers = utils.read_only_property("_notice_numbers") + @property + def organization(self) -> typing.Optional[str]: + return self._organization + + @property + def notice_numbers(self) -> typing.List[int]: + return self._notice_numbers class ExtendedKeyUsage(ExtensionType): @@ -1019,7 +1072,9 @@ def __ne__(self, other): def __hash__(self): return hash(self.skip_certs) - skip_certs = utils.read_only_property("_skip_certs") + @property + def skip_certs(self) -> int: + return self._skip_certs class KeyUsage(ExtensionType): @@ -1053,13 +1108,33 @@ def __init__( self._encipher_only = encipher_only self._decipher_only = decipher_only - digital_signature = utils.read_only_property("_digital_signature") - content_commitment = utils.read_only_property("_content_commitment") - key_encipherment = utils.read_only_property("_key_encipherment") - data_encipherment = utils.read_only_property("_data_encipherment") - key_agreement = utils.read_only_property("_key_agreement") - key_cert_sign = utils.read_only_property("_key_cert_sign") - crl_sign = utils.read_only_property("_crl_sign") + @property + def digital_signature(self) -> bool: + return self._digital_signature + + @property + def content_commitment(self) -> bool: + return self._content_commitment + + @property + def key_encipherment(self) -> bool: + return self._key_encipherment + + @property + def data_encipherment(self) -> bool: + return self._data_encipherment + + @property + def key_agreement(self) -> bool: + return self._key_agreement + + @property + def key_cert_sign(self) -> bool: + return self._key_cert_sign + + @property + def crl_sign(self) -> bool: + return self._crl_sign @property def encipher_only(self): @@ -1216,8 +1291,17 @@ def __hash__(self): return hash((ps, es)) - permitted_subtrees = utils.read_only_property("_permitted_subtrees") - excluded_subtrees = utils.read_only_property("_excluded_subtrees") + @property + def permitted_subtrees( + self, + ) -> typing.Optional[typing.List[GeneralName]]: + return self._permitted_subtrees + + @property + def excluded_subtrees( + self, + ) -> typing.Optional[typing.List[GeneralName]]: + return self._excluded_subtrees class Extension(object): @@ -1236,9 +1320,17 @@ def __init__( self._critical = critical self._value = value - oid = utils.read_only_property("_oid") - critical = utils.read_only_property("_critical") - value = utils.read_only_property("_value") + @property + def oid(self) -> ObjectIdentifier: + return self._oid + + @property + def critical(self) -> bool: + return self._critical + + @property + def value(self) -> ExtensionType: + return self._value def __repr__(self): return ( @@ -1406,7 +1498,9 @@ def __ne__(self, other): def __hash__(self): return hash(self.reason) - reason = utils.read_only_property("_reason") + @property + def reason(self) -> ReasonFlags: + return self._reason class InvalidityDate(ExtensionType): @@ -1435,7 +1529,9 @@ def __ne__(self, other): def __hash__(self): return hash(self.invalidity_date) - invalidity_date = utils.read_only_property("_invalidity_date") + @property + def invalidity_date(self) -> datetime.datetime: + return self._invalidity_date class PrecertificateSignedCertificateTimestamps(ExtensionType): @@ -1550,7 +1646,9 @@ def __hash__(self): def __repr__(self): return "".format(self) - nonce = utils.read_only_property("_nonce") + @property + def nonce(self) -> bytes: + return self._nonce class IssuingDistributionPoint(ExtensionType): @@ -1701,8 +1799,13 @@ def __init__(self, oid: ObjectIdentifier, value: bytes): self._oid = oid self._value = value - oid = utils.read_only_property("_oid") - value = utils.read_only_property("_value") + @property + def oid(self) -> ObjectIdentifier: + return self._oid + + @property + def value(self) -> bytes: + return self._value def __repr__(self): return ( diff --git a/src/cryptography/x509/general_name.py b/src/cryptography/x509/general_name.py index a83471e93131..e9495909018b 100644 --- a/src/cryptography/x509/general_name.py +++ b/src/cryptography/x509/general_name.py @@ -8,7 +8,6 @@ import typing from email.utils import parseaddr -from cryptography import utils from cryptography.x509.name import Name from cryptography.x509.oid import ObjectIdentifier @@ -62,7 +61,9 @@ def __init__(self, value: str): self._value = value - value = utils.read_only_property("_value") + @property + def value(self) -> str: + return self._value @classmethod def _init_without_validation(cls, value): @@ -102,7 +103,9 @@ def __init__(self, value: str): self._value = value - value = utils.read_only_property("_value") + @property + def value(self) -> str: + return self._value @classmethod def _init_without_validation(cls, value): @@ -142,7 +145,9 @@ def __init__(self, value: str): self._value = value - value = utils.read_only_property("_value") + @property + def value(self) -> str: + return self._value @classmethod def _init_without_validation(cls, value): @@ -173,7 +178,9 @@ def __init__(self, value: Name): self._value = value - value = utils.read_only_property("_value") + @property + def value(self) -> Name: + return self._value def __repr__(self) -> str: return "".format(self.value) @@ -198,7 +205,9 @@ def __init__(self, value: ObjectIdentifier): self._value = value - value = utils.read_only_property("_value") + @property + def value(self) -> ObjectIdentifier: + return self._value def __repr__(self) -> str: return "".format(self.value) @@ -243,7 +252,16 @@ def __init__( self._value = value - value = utils.read_only_property("_value") + @property + def value( + self, + ) -> typing.Union[ + ipaddress.IPv4Address, + ipaddress.IPv6Address, + ipaddress.IPv4Network, + ipaddress.IPv6Network, + ]: + return self._value def __repr__(self) -> str: return "".format(self.value) @@ -271,8 +289,13 @@ def __init__(self, type_id: ObjectIdentifier, value: bytes): self._type_id = type_id self._value = value - type_id = utils.read_only_property("_type_id") - value = utils.read_only_property("_value") + @property + def type_id(self) -> ObjectIdentifier: + return self._type_id + + @property + def value(self) -> bytes: + return self._value def __repr__(self) -> str: return "".format( diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py index a579aa219638..2d506f73bb39 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -5,7 +5,6 @@ import typing from enum import Enum -from cryptography import utils from cryptography.hazmat.backends import _get_backend from cryptography.x509.oid import NameOID, ObjectIdentifier @@ -108,8 +107,13 @@ def __init__(self, oid: ObjectIdentifier, value: str, _type=_SENTINEL): self._value = value self._type = _type - oid = utils.read_only_property("_oid") - value = utils.read_only_property("_value") + @property + def oid(self) -> ObjectIdentifier: + return self._oid + + @property + def value(self) -> str: + return self._value def rfc4514_string(self) -> str: """ @@ -220,7 +224,7 @@ def get_attributes_for_oid(self, oid) -> typing.List[NameAttribute]: return [i for i in self if i.oid == oid] @property - def rdns(self) -> typing.Iterable[RelativeDistinguishedName]: + def rdns(self) -> typing.List[RelativeDistinguishedName]: return self._attributes def public_bytes(self, backend=None) -> bytes: diff --git a/tests/x509/test_x509_crlbuilder.py b/tests/x509/test_x509_crlbuilder.py index cbf0b073b5a5..88725710d7fd 100644 --- a/tests/x509/test_x509_crlbuilder.py +++ b/tests/x509/test_x509_crlbuilder.py @@ -366,6 +366,7 @@ def test_freshestcrl_extension(self, backend): ext1 = crl.extensions.get_extension_for_class(x509.FreshestCRL) assert ext1.critical is False assert isinstance(ext1.value[0], x509.DistributionPoint) + assert ext1.value[0].full_name is not None uri = ext1.value[0].full_name[0] assert isinstance(uri, x509.UniformResourceIdentifier) assert uri.value == "http://d.om/delta" diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index b8f226d5f848..41a35e264b24 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -517,6 +517,7 @@ def test_invalid_policy_identifiers(self): def test_iter_input(self): qual = ["foo", "bar"] pi = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), iter(qual)) + assert pi.policy_qualifiers is not None assert list(pi.policy_qualifiers) == qual def test_repr(self): @@ -1104,6 +1105,7 @@ def test_iter_input(self): ) ] aki = x509.AuthorityKeyIdentifier(b"digest", iter(dirnames), 1234) + assert aki.authority_cert_issuer is not None assert list(aki.authority_cert_issuer) == dirnames def test_repr(self): @@ -3429,7 +3431,9 @@ def test_excluded_none(self): def test_iter_input(self): subtrees = [x509.IPAddress(ipaddress.IPv4Network("192.168.0.0/24"))] nc = x509.NameConstraints(iter(subtrees), iter(subtrees)) + assert nc.permitted_subtrees is not None assert list(nc.permitted_subtrees) == subtrees + assert nc.excluded_subtrees is not None assert list(nc.excluded_subtrees) == subtrees def test_repr(self): @@ -3781,7 +3785,9 @@ def test_iter_input(self): frozenset([x509.ReasonFlags.ca_compromise]), iter(issuer), ) + assert dp.full_name is not None assert list(dp.full_name) == name + assert dp.crl_issuer is not None assert list(dp.crl_issuer) == issuer def test_repr(self): From 4f48f39543a09eb336f3ccc053006cdd029ab22f Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 15 Feb 2021 22:19:18 -0600 Subject: [PATCH 0039/1456] test against libre 3.2.4 (#5835) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e599991971ce..77ddfd8b99b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "2.9.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.1.5"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.2.3"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.2.4"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.3.1"}} RUST: - stable From ade36103176145fa774050c5ff9f73b03b28187d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 16 Feb 2021 08:54:16 -0500 Subject: [PATCH 0040/1456] protect against integer overfows in release rust (#5836) this would have categorically prevented CVE-2020-36242 --- src/rust/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 8d154fbbe48d..bcb9add10020 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -14,3 +14,4 @@ crate-type = ["cdylib"] [profile.release] lto = "thin" +overflow-checks = true From 208b95dac29e53224f20f8ddfc6783a7a8576934 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 16 Feb 2021 11:56:59 -0500 Subject: [PATCH 0041/1456] update here too (#5839) --- .github/ISSUE_TEMPLATE/openssl-release.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/openssl-release.md b/.github/ISSUE_TEMPLATE/openssl-release.md index 336953722fb2..c9ee70436bac 100644 --- a/.github/ISSUE_TEMPLATE/openssl-release.md +++ b/.github/ISSUE_TEMPLATE/openssl-release.md @@ -1,7 +1,7 @@ - [ ] Windows, macOS, `manylinux` - - [ ] Send a pull request to `pyca/infra` updating the [version and hash](https://github.com/pyca/infra/blob/master/cryptography-manylinux/openssl-version.sh) + - [ ] Send a pull request to `pyca/infra` updating the [version and hash](https://github.com/pyca/infra/blob/main/cryptography-manylinux/openssl-version.sh) - [ ] Wait for it to be merged - [ ] Wait for the Github Actions job to complete - [ ] Changelog entry - [ ] Release -- [ ] Forward port changelog entry (if releasing from release branch) \ No newline at end of file +- [ ] Forward port changelog entry (if releasing from release branch) From 21f1bc607a311c4974c7d4f9a93a0a8b4eaad621 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 16 Feb 2021 11:57:18 -0500 Subject: [PATCH 0042/1456] Update for branch name change (#5838) --- .github/workflows/download_openssl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/download_openssl.py b/.github/workflows/download_openssl.py index 46b3b7f0ee02..496e05385b0e 100644 --- a/.github/workflows/download_openssl.py +++ b/.github/workflows/download_openssl.py @@ -51,7 +51,7 @@ def main(platform, target): print("Looking for: {}".format(target)) runs_url = ( "https://api.github.com/repos/pyca/infra/actions/workflows/" - "{}/runs?branch=master&status=success".format(workflow) + "{}/runs?branch=main&status=success".format(workflow) ) response = get_response(session, runs_url, token).json() From c37a445a19b4c293047d0e9d77dc39b9ff9972c4 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 16 Feb 2021 15:12:41 -0600 Subject: [PATCH 0043/1456] 1.1.1j in more places (#5841) --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 77ddfd8b99b9..026a5020178f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,9 +18,9 @@ jobs: - {VERSION: "3.9", TOXENV: "flake,rust,docs", COVERAGE: "false"} - {VERSION: "pypy3", TOXENV: "pypy3"} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.0l"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1i"}} - - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1i"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1i", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} + - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "2.9.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.1.5"}} From 9a2e1dfacd54fbae855a5fcc85857548b4ba2617 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 16 Feb 2021 16:18:35 -0600 Subject: [PATCH 0044/1456] port 3.4.6 changelog (#5842) * port 3.4.6 changelog Also link CVE-2020-36242 to CVE-2021-23840 since our 3.3.2 security fix is just a workaround for the OpenSSL issue. * Update CHANGELOG.rst Co-authored-by: Alex Gaynor Co-authored-by: Alex Gaynor --- CHANGELOG.rst | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 91e50b278243..8a7a663c76d8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,14 @@ Changelog .. note:: This version is not yet released and is under active development. +.. _v3-4-6: + +3.4.6 - 2021-02-16 +~~~~~~~~~~~~~~~~~~ + +* Updated Windows, macOS, and ``manylinux`` wheels to be compiled with + OpenSSL 1.1.1j. + .. _v3-4-5: 3.4.5 - 2021-02-13 @@ -80,7 +88,9 @@ Changelog * **SECURITY ISSUE:** Fixed a bug where certain sequences of ``update()`` calls when symmetrically encrypting very large payloads (>2GB) could result in an - integer overflow, leading to buffer overflows. *CVE-2020-36242* + integer overflow, leading to buffer overflows. *CVE-2020-36242* **Update:** + This fix is a workaround for *CVE-2021-23840* in OpenSSL, fixed in OpenSSL + 1.1.1j. .. _v3-3-1: From 577e058798e0e6ae04eac07f958f1072e351e859 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 18 Feb 2021 16:57:43 -0600 Subject: [PATCH 0045/1456] Strict is deprecated (#5846) * Strict is deprecated * bump pytest dep --- setup.py | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 74f69e7148a6..e448479caa19 100644 --- a/setup.py +++ b/setup.py @@ -110,7 +110,7 @@ setup_requires=setup_requirements, extras_require={ "test": [ - "pytest>=6.0", + "pytest>=6.2.0", "pytest-cov", "pytest-subtests", "pytest-xdist", diff --git a/tox.ini b/tox.ini index 93f4b253ab8d..3130777c6c47 100644 --- a/tox.ini +++ b/tox.ini @@ -14,7 +14,7 @@ deps = passenv = ARCHFLAGS LDFLAGS CFLAGS INCLUDE LIB LD_LIBRARY_PATH USERNAME PYTHONIOENCODING OPENSSL_FORCE_FIPS_MODE commands = pip list - pytest -n auto --cov=cryptography --cov=tests --capture=no --strict --durations=10 {posargs} + pytest -n auto --cov=cryptography --cov=tests --capture=no --strict-markers --durations=10 {posargs} [testenv:docs] extras = From 770e3d18954483f6bc90d5166552a309b7a22c85 Mon Sep 17 00:00:00 2001 From: Robert Martin Date: Sat, 20 Feb 2021 07:56:55 -0600 Subject: [PATCH 0046/1456] Fix typo in error messages: can not => cannot (#5851) --- src/cryptography/hazmat/primitives/kdf/concatkdf.py | 2 +- src/cryptography/hazmat/primitives/kdf/hkdf.py | 2 +- src/cryptography/hazmat/primitives/kdf/x963kdf.py | 2 +- tests/hazmat/primitives/test_rsa.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cryptography/hazmat/primitives/kdf/concatkdf.py b/src/cryptography/hazmat/primitives/kdf/concatkdf.py index 4b7fce878acb..6ec4cbd372b4 100644 --- a/src/cryptography/hazmat/primitives/kdf/concatkdf.py +++ b/src/cryptography/hazmat/primitives/kdf/concatkdf.py @@ -32,7 +32,7 @@ def _common_args_checks( max_length = algorithm.digest_size * (2 ** 32 - 1) if length > max_length: raise ValueError( - "Can not derive keys larger than {} bits.".format(max_length) + "Cannot derive keys larger than {} bits.".format(max_length) ) if otherinfo is not None: utils._check_bytes("otherinfo", otherinfo) diff --git a/src/cryptography/hazmat/primitives/kdf/hkdf.py b/src/cryptography/hazmat/primitives/kdf/hkdf.py index 9a05a139265b..6b65b0c0717b 100644 --- a/src/cryptography/hazmat/primitives/kdf/hkdf.py +++ b/src/cryptography/hazmat/primitives/kdf/hkdf.py @@ -84,7 +84,7 @@ def __init__( if length > max_length: raise ValueError( - "Can not derive keys larger than {} octets.".format(max_length) + "Cannot derive keys larger than {} octets.".format(max_length) ) self._length = length diff --git a/src/cryptography/hazmat/primitives/kdf/x963kdf.py b/src/cryptography/hazmat/primitives/kdf/x963kdf.py index 21a47f665ff3..1a67d3ee0c4f 100644 --- a/src/cryptography/hazmat/primitives/kdf/x963kdf.py +++ b/src/cryptography/hazmat/primitives/kdf/x963kdf.py @@ -36,7 +36,7 @@ def __init__( max_len = algorithm.digest_size * (2 ** 32 - 1) if length > max_len: raise ValueError( - "Can not derive keys larger than {} bits.".format(max_len) + "Cannot derive keys larger than {} bits.".format(max_len) ) if sharedinfo is not None: utils._check_bytes("sharedinfo", sharedinfo) diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 6d2f32145a27..46f011f477dc 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -1023,7 +1023,7 @@ def test_invalid_pss_signature_recover(self, backend): ) signature = private_key.sign(b"sign me", pss_padding, hashes.SHA1()) - # Hash algorithm can not be absent for PSS padding + # Hash algorithm cannot be absent for PSS padding with pytest.raises(TypeError): public_key.recover_data_from_signature( signature, pss_padding, None # type: ignore[arg-type] From 2b94360394a4fa177701954f96f864cfa7c65b9f Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sat, 20 Feb 2021 16:38:56 +0100 Subject: [PATCH 0047/1456] make Extension a generic class (fixes #5830) (#5831) --- .../hazmat/backends/openssl/decode_asn1.py | 3 ++- src/cryptography/x509/extensions.py | 14 +++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 167acc078743..e62c25406b39 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -5,6 +5,7 @@ import datetime import ipaddress +import typing from cryptography import x509 from cryptography.hazmat._der import DERReader, INTEGER, NULL, SEQUENCE @@ -185,7 +186,7 @@ def __init__(self, backend, ext_count, get_ext, handlers): self._backend = backend def parse(self, x509_obj): - extensions = [] + extensions: typing.List[x509.Extension[x509.ExtensionType]] = [] seen_oids = set() for i in range(self.ext_count(x509_obj)): ext = self.get_ext(x509_obj, i) diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 94072aab7f3f..95e3a9f39d45 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -33,6 +33,8 @@ ObjectIdentifier, ) +ExtensionTypeVar = typing.TypeVar("ExtensionTypeVar", bound="ExtensionType") + def _key_identifier_from_public_key(public_key: _PUBLIC_KEY_TYPES) -> bytes: if isinstance(public_key, RSAPublicKey): @@ -108,17 +110,19 @@ def oid(self) -> ObjectIdentifier: class Extensions(object): - def __init__(self, extensions: typing.List["Extension"]): + def __init__(self, extensions: typing.List["Extension[ExtensionType]"]): self._extensions = extensions - def get_extension_for_oid(self, oid: ObjectIdentifier) -> "Extension": + def get_extension_for_oid( + self, oid: ObjectIdentifier + ) -> "Extension[ExtensionType]": for ext in self: if ext.oid == oid: return ext raise ExtensionNotFound("No {} extension was found".format(oid), oid) - def get_extension_for_class(self, extclass) -> "Extension": + def get_extension_for_class(self, extclass) -> "Extension[ExtensionType]": if extclass is UnrecognizedExtension: raise TypeError( "UnrecognizedExtension can't be used with " @@ -1304,9 +1308,9 @@ def excluded_subtrees( return self._excluded_subtrees -class Extension(object): +class Extension(typing.Generic[ExtensionTypeVar]): def __init__( - self, oid: ObjectIdentifier, critical: bool, value: ExtensionType + self, oid: ObjectIdentifier, critical: bool, value: ExtensionTypeVar ): if not isinstance(oid, ObjectIdentifier): raise TypeError( From 540a9828cc704abf3ebad7ee5b56852cf25e5aaa Mon Sep 17 00:00:00 2001 From: Arnaud Durand Date: Sun, 21 Feb 2021 19:36:24 +0100 Subject: [PATCH 0048/1456] Add key_identifier property to SubjectKeyIdentifier (#5849) Fix #5848 --- docs/x509/reference.rst | 9 +++++++++ src/cryptography/x509/extensions.py | 4 ++++ tests/x509/test_x509_ext.py | 1 + 3 files changed, 14 insertions(+) diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index c6eba06f881e..df09af148926 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -1945,6 +1945,15 @@ X.509 Extensions Returns :attr:`~cryptography.x509.oid.ExtensionOID.SUBJECT_KEY_IDENTIFIER`. + .. attribute:: key_identifier + + .. versionadded:: 35.0.0 + + :type: bytes + + A value derived from the public key used to verify the certificate's + signature. + .. attribute:: digest :type: bytes diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 95e3a9f39d45..aad8bcfd9c5b 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -292,6 +292,10 @@ def from_public_key( def digest(self) -> bytes: return self._digest + @property + def key_identifier(self) -> bytes: + return self._digest + def __repr__(self): return "".format(self.digest) diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index 41a35e264b24..f74f3d5a5f56 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -994,6 +994,7 @@ def test_properties(self): value = binascii.unhexlify(b"092384932230498bc980aa8098456f6ff7ff3ac9") ski = x509.SubjectKeyIdentifier(value) assert ski.digest == value + assert ski.key_identifier == value def test_repr(self): ski = x509.SubjectKeyIdentifier( From d7fcfb5a0a692d32df0283b95b0bcfdca9f71db9 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 21 Feb 2021 13:26:04 -0600 Subject: [PATCH 0049/1456] simplify docs a bit (#5855) --- docs/x509/reference.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index df09af148926..216896f045cc 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -1951,14 +1951,13 @@ X.509 Extensions :type: bytes - A value derived from the public key used to verify the certificate's - signature. + The binary value of the identifier. .. attribute:: digest :type: bytes - The binary value of the identifier. + The binary value of the identifier. An alias of ``key_identifier``. .. classmethod:: from_public_key(public_key) From f1127596560211661d5deb42afafa1993a6338e6 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 21 Feb 2021 20:26:24 +0100 Subject: [PATCH 0050/1456] add typehint for name (#5856) --- src/cryptography/hazmat/_oid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptography/hazmat/_oid.py b/src/cryptography/hazmat/_oid.py index 3e22ea9f284e..84268b8dea45 100644 --- a/src/cryptography/hazmat/_oid.py +++ b/src/cryptography/hazmat/_oid.py @@ -64,7 +64,7 @@ def __hash__(self): return hash(self.dotted_string) @property - def _name(self): + def _name(self) -> str: # Lazy import to avoid an import cycle from cryptography.x509.oid import _OID_NAMES From 82a12a54b602c994cd0361d1b95bcb4047d67a31 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 21 Feb 2021 14:28:00 -0500 Subject: [PATCH 0051/1456] Convert unpadding code to Rust (#5668) --- docs/faq.rst | 5 -- mypy.ini | 2 +- setup.py | 36 +++----- src/_cffi_src/build_padding.py | 26 ------ src/_cffi_src/hazmat_src/padding.c | 65 -------------- src/_cffi_src/hazmat_src/padding.h | 6 -- src/cryptography/hazmat/primitives/padding.py | 13 +-- src/rust/src/lib.rs | 85 ++++++++++++++++++- tox.ini | 1 + 9 files changed, 106 insertions(+), 133 deletions(-) delete mode 100644 src/_cffi_src/build_padding.py delete mode 100644 src/_cffi_src/hazmat_src/padding.c delete mode 100644 src/_cffi_src/hazmat_src/padding.h diff --git a/docs/faq.rst b/docs/faq.rst index c43396cf911e..cfa2952fec29 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -132,11 +132,6 @@ need to have Rust installed after you've built ``cryptography``. This is the same as the C compiler toolchain which is also required to build ``cryptography``, but not afterwards. -For the current release *only* you can temporarily bypass the requirement to -have Rust installed by setting the ``CRYPTOGRAPHY_DONT_BUILD_RUST`` environment -variable. Note that this option will be removed in the next release and not -having Rust available will be a hard error. - Why are there no wheels for my Python3.x version? ------------------------------------------------- diff --git a/mypy.ini b/mypy.ini index bf4cc82270c9..a1755b1fe0be 100644 --- a/mypy.ini +++ b/mypy.ini @@ -4,7 +4,7 @@ check_untyped_defs = True [mypy-cryptography.hazmat.bindings._openssl] ignore_missing_imports = True -[mypy-cryptography.hazmat.bindings._padding] +[mypy-cryptography.hazmat.bindings._rust] ignore_missing_imports = True [mypy-iso8601] diff --git a/setup.py b/setup.py index e448479caa19..f524c2be3d03 100644 --- a/setup.py +++ b/setup.py @@ -45,24 +45,6 @@ install_requirements = ["cffi>=1.12"] setup_requirements = install_requirements + [setuptools_rust] -if os.environ.get("CRYPTOGRAPHY_DONT_BUILD_RUST"): - rust_extensions = [] -else: - rust_extensions = [ - RustExtension( - "_rust", - "src/rust/Cargo.toml", - py_limited_api=True, - # Enable abi3 mode if we're not using PyPy. - features=( - [] - if platform.python_implementation() == "PyPy" - else ["pyo3/abi3-py36"] - ), - rust_version=">=1.41.0", - ) - ] - with open(os.path.join(base_dir, "README.rst")) as f: long_description = f.read() @@ -147,9 +129,21 @@ ext_package="cryptography.hazmat.bindings", cffi_modules=[ "src/_cffi_src/build_openssl.py:ffi", - "src/_cffi_src/build_padding.py:ffi", ], - rust_extensions=rust_extensions, + rust_extensions=[ + RustExtension( + "_rust", + "src/rust/Cargo.toml", + py_limited_api=True, + # Enable abi3 mode if we're not using PyPy. + features=( + [] + if platform.python_implementation() == "PyPy" + else ["pyo3/abi3-py36"] + ), + rust_version=">=1.41.0", + ) + ], ) except: # noqa: E722 # Note: This is a bare exception that re-raises so that we don't interfere @@ -172,8 +166,6 @@ https://cryptography.io/en/latest/faq.html 4) Ensure you have a recent Rust toolchain installed: https://cryptography.io/en/latest/installation.html#rust - 5) If you are experiencing issues with Rust for *this release only* you may - set the environment variable `CRYPTOGRAPHY_DONT_BUILD_RUST=1`. =============================DEBUG ASSISTANCE============================= """ ) diff --git a/src/_cffi_src/build_padding.py b/src/_cffi_src/build_padding.py deleted file mode 100644 index 61f36ef69109..000000000000 --- a/src/_cffi_src/build_padding.py +++ /dev/null @@ -1,26 +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. - - -import os - -from _cffi_src.utils import build_ffi, compiler_type, extra_link_args - - -with open( - os.path.join(os.path.dirname(__file__), "hazmat_src/padding.h") -) as f: - types = f.read() - -with open( - os.path.join(os.path.dirname(__file__), "hazmat_src/padding.c") -) as f: - functions = f.read() - -ffi = build_ffi( - module_name="_padding", - cdef_source=types, - verify_source=functions, - extra_link_args=extra_link_args(compiler_type()), -) diff --git a/src/_cffi_src/hazmat_src/padding.c b/src/_cffi_src/hazmat_src/padding.c deleted file mode 100644 index a6e05dee1e39..000000000000 --- a/src/_cffi_src/hazmat_src/padding.c +++ /dev/null @@ -1,65 +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. - -/* Returns the value of the input with the most-significant-bit copied to all - of the bits. */ -static uint16_t Cryptography_DUPLICATE_MSB_TO_ALL(uint16_t a) { - return (1 - (a >> (sizeof(uint16_t) * 8 - 1))) - 1; -} - -/* This returns 0xFFFF if a < b else 0x0000, but does so in a constant time - fashion */ -static uint16_t Cryptography_constant_time_lt(uint16_t a, uint16_t b) { - a -= b; - return Cryptography_DUPLICATE_MSB_TO_ALL(a); -} - -uint8_t Cryptography_check_pkcs7_padding(const uint8_t *data, - uint16_t block_len) { - uint16_t i; - uint16_t pad_size = data[block_len - 1]; - uint16_t mismatch = 0; - for (i = 0; i < block_len; i++) { - unsigned int mask = Cryptography_constant_time_lt(i, pad_size); - uint16_t b = data[block_len - 1 - i]; - mismatch |= (mask & (pad_size ^ b)); - } - - /* Check to make sure the pad_size was within the valid range. */ - mismatch |= ~Cryptography_constant_time_lt(0, pad_size); - mismatch |= Cryptography_constant_time_lt(block_len, pad_size); - - /* Make sure any bits set are copied to the lowest bit */ - mismatch |= mismatch >> 8; - mismatch |= mismatch >> 4; - mismatch |= mismatch >> 2; - mismatch |= mismatch >> 1; - /* Now check the low bit to see if it's set */ - return (mismatch & 1) == 0; -} - -uint8_t Cryptography_check_ansix923_padding(const uint8_t *data, - uint16_t block_len) { - uint16_t i; - uint16_t pad_size = data[block_len - 1]; - uint16_t mismatch = 0; - /* Skip the first one with the pad size */ - for (i = 1; i < block_len; i++) { - unsigned int mask = Cryptography_constant_time_lt(i, pad_size); - uint16_t b = data[block_len - 1 - i]; - mismatch |= (mask & b); - } - - /* Check to make sure the pad_size was within the valid range. */ - mismatch |= ~Cryptography_constant_time_lt(0, pad_size); - mismatch |= Cryptography_constant_time_lt(block_len, pad_size); - - /* Make sure any bits set are copied to the lowest bit */ - mismatch |= mismatch >> 8; - mismatch |= mismatch >> 4; - mismatch |= mismatch >> 2; - mismatch |= mismatch >> 1; - /* Now check the low bit to see if it's set */ - return (mismatch & 1) == 0; -} diff --git a/src/_cffi_src/hazmat_src/padding.h b/src/_cffi_src/hazmat_src/padding.h deleted file mode 100644 index fb023c171108..000000000000 --- a/src/_cffi_src/hazmat_src/padding.h +++ /dev/null @@ -1,6 +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. - -uint8_t Cryptography_check_pkcs7_padding(const uint8_t *, uint8_t); -uint8_t Cryptography_check_ansix923_padding(const uint8_t *, uint8_t); diff --git a/src/cryptography/hazmat/primitives/padding.py b/src/cryptography/hazmat/primitives/padding.py index e6f46eb4fa0b..ccfde74049e7 100644 --- a/src/cryptography/hazmat/primitives/padding.py +++ b/src/cryptography/hazmat/primitives/padding.py @@ -8,7 +8,10 @@ from cryptography import utils from cryptography.exceptions import AlreadyFinalized -from cryptography.hazmat.bindings._padding import lib +from cryptography.hazmat.bindings._rust import ( + check_ansix923_padding, + check_pkcs7_padding, +) class PaddingContext(metaclass=abc.ABCMeta): @@ -84,7 +87,7 @@ def _byte_unpadding_update( def _byte_unpadding_check( buffer_: typing.Optional[bytes], block_size: int, - checkfn: typing.Callable[[bytes, int], int], + checkfn: typing.Callable[[bytes], int], ) -> bytes: if buffer_ is None: raise AlreadyFinalized("Context was already finalized.") @@ -92,7 +95,7 @@ def _byte_unpadding_check( if len(buffer_) != block_size // 8: raise ValueError("Invalid padding bytes.") - valid = checkfn(buffer_, block_size // 8) + valid = checkfn(buffer_) if not valid: raise ValueError("Invalid padding bytes.") @@ -154,7 +157,7 @@ def update(self, data: bytes) -> bytes: def finalize(self) -> bytes: result = _byte_unpadding_check( - self._buffer, self.block_size, lib.Cryptography_check_pkcs7_padding + self._buffer, self.block_size, check_pkcs7_padding ) self._buffer = None return result @@ -215,7 +218,7 @@ def finalize(self) -> bytes: result = _byte_unpadding_check( self._buffer, self.block_size, - lib.Cryptography_check_ansix923_padding, + check_ansix923_padding, ) self._buffer = None return result diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 1580ca4fcef7..3257b35e123f 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -2,9 +2,88 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. +use std::convert::TryInto; + +/// Returns the value of the input with the most-significant-bit copied to all +/// of the bits. +fn duplicate_msb_to_all(a: u8) -> u8 { + 0u8.wrapping_sub(a >> 7) +} + +/// This returns 0xFF if a < b else 0x00, but does so in a constant time +/// fashion. +fn constant_time_lt(a: u8, b: u8) -> u8 { + // Derived from: + // https://github.com/openssl/openssl/blob/OpenSSL_1_1_1i/include/internal/constant_time.h#L120 + duplicate_msb_to_all(a ^ ((a ^ b) | (a.wrapping_sub(b) ^ b))) +} + +#[pyo3::prelude::pyfunction] +fn check_pkcs7_padding(data: &[u8]) -> bool { + let mut mismatch = 0; + let pad_size = *data.last().unwrap(); + let len: u8 = data.len().try_into().expect("data too long"); + for (i, b) in (0..len).zip(data.iter().rev()) { + let mask = constant_time_lt(i, pad_size); + mismatch |= mask & (pad_size ^ b); + } + + // Check to make sure the pad_size was within the valid range. + mismatch |= !constant_time_lt(0, pad_size); + mismatch |= constant_time_lt(len, pad_size); + + // Make sure any bits set are copied to the lowest bit + mismatch |= mismatch >> 4; + mismatch |= mismatch >> 2; + mismatch |= mismatch >> 1; + + // Now check the low bit to see if it's set + (mismatch & 1) == 0 +} + +#[pyo3::prelude::pyfunction] +fn check_ansix923_padding(data: &[u8]) -> bool { + let mut mismatch = 0; + let pad_size = *data.last().unwrap(); + let len: u8 = data.len().try_into().expect("data too long"); + // Skip the first one with the pad size + for (i, b) in (1..len).zip(data[..data.len() - 1].iter().rev()) { + let mask = constant_time_lt(i, pad_size); + mismatch |= mask & b; + } + + // Check to make sure the pad_size was within the valid range. + mismatch |= !constant_time_lt(0, pad_size); + mismatch |= constant_time_lt(len, pad_size); + + // Make sure any bits set are copied to the lowest bit + mismatch |= mismatch >> 4; + mismatch |= mismatch >> 2; + mismatch |= mismatch >> 1; + + // Now check the low bit to see if it's set + (mismatch & 1) == 0 +} + #[pyo3::prelude::pymodule] -// False positive: https://github.com/rust-lang/rust-clippy/issues/6721 -#[allow(clippy::unnecessary_wraps)] -fn _rust(_py: pyo3::Python<'_>, _m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { +fn _rust(_py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { + m.add_function(pyo3::wrap_pyfunction!(check_pkcs7_padding, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(check_ansix923_padding, m)?)?; + Ok(()) } + +#[cfg(test)] +mod tests { + use super::constant_time_lt; + + #[test] + fn test_constant_time_lt() { + for a in 0..=255 { + for b in 0..=255 { + let expected = if a < b { 0xff } else { 0 }; + assert_eq!(constant_time_lt(a, b), expected); + } + } + } +} diff --git a/tox.ini b/tox.ini index 3130777c6c47..bdc4da283493 100644 --- a/tox.ini +++ b/tox.ini @@ -61,6 +61,7 @@ allowlist_externals = commands = cargo fmt --all -- --check cargo clippy -- -D warnings + cargo test [flake8] ignore = E203,E211,W503,W504 From 8928e8e1d2fd3fcc8f8fb0738a45aa16b0ec570c Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 21 Feb 2021 16:11:34 -0600 Subject: [PATCH 0052/1456] test pypy3.6 and pypy3.7 (#5857) --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 026a5020178f..e68f089a73af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,8 @@ jobs: matrix: PYTHON: - {VERSION: "3.9", TOXENV: "flake,rust,docs", COVERAGE: "false"} - - {VERSION: "pypy3", TOXENV: "pypy3"} + - {VERSION: "pypy-3.6", TOXENV: "pypy3"} + - {VERSION: "pypy-3.7", TOXENV: "pypy3"} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.0l"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} From 7491e6b4fdd38cf1163bb89df0c122b293957c5a Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 21 Feb 2021 16:53:44 -0600 Subject: [PATCH 0053/1456] remove virtualenv in wheel builders (#5858) now that we're py3+ only we should be able to directly use venv --- .github/workflows/wheel-builder.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index cb7b11615684..e67feaf48429 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -19,7 +19,7 @@ jobs: CONTAINER: "cryptography-manylinux2014:x86_64" name: "${{ matrix.PYTHON }} for ${{ matrix.MANYLINUX.NAME }}" steps: - - run: /opt/python/${{ matrix.PYTHON }}/bin/python -m virtualenv .venv + - run: /opt/python/${{ matrix.PYTHON }}/bin/python -m venv .venv - name: Install Python dependencies run: .venv/bin/pip install -U pip wheel cffi six ipaddress setuptools-rust - run: .venv/bin/pip download cryptography==${{ github.event.inputs.version }} --no-deps --no-binary cryptography && tar zxvf cryptography*.tar.gz && mkdir tmpwheelhouse @@ -71,7 +71,7 @@ jobs: sudo installer -pkg python.pkg -target / env: PYTHON_DOWNLOAD_URL: ${{ matrix.PYTHON.DOWNLOAD_URL }} - - run: ${{ matrix.PYTHON.BIN_PATH }} -m pip install -U virtualenv requests + - run: ${{ matrix.PYTHON.BIN_PATH }} -m pip install -U requests - name: Download OpenSSL run: | ${{ matrix.PYTHON.BIN_PATH }} .github/workflows/download_openssl.py macos openssl-macos-x86-64 @@ -84,7 +84,7 @@ jobs: override: true default: true - - run: ${{ matrix.PYTHON.BIN_PATH }} -m virtualenv venv + - run: ${{ matrix.PYTHON.BIN_PATH }} -m venv venv - run: venv/bin/pip install -U pip wheel cffi six ipaddress setuptools-rust - run: venv/bin/pip download cryptography==${{ github.event.inputs.version }} --no-deps --no-binary cryptography && tar zxvf cryptography*.tar.gz && mkdir wheelhouse - name: Build the wheel From 5efb07d0308047386fa83628d2dec7579b514b15 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 21 Feb 2021 19:12:10 -0600 Subject: [PATCH 0054/1456] don't use virtualenv in zuul wheel building either (#5860) * don't use virtualenv in zuul wheel building either * we need wheel and not these other things * newer pip, also don't need six --- .../wheel/roles/build-wheel-manylinux/files/build-wheels.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/files/build-wheels.sh b/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/files/build-wheels.sh index b701c21fa532..d28ff4e7961a 100644 --- a/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/files/build-wheels.sh +++ b/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/files/build-wheels.sh @@ -9,9 +9,9 @@ for P in ${PYTHONS}; do PYBIN=/opt/python/${P}/bin - "${PYBIN}"/python -m virtualenv .venv + "${PYBIN}"/python -m venv .venv - .venv/bin/pip install cffi six ipaddress "enum34; python_version < '3'" setuptools-rust + .venv/bin/pip install -U pip wheel cffi setuptools-rust REGEX="cp3([0-9])*" if [[ "${PYBIN}" =~ $REGEX ]]; then From dd09d500f9187df9f620aa7c984d01738cb60b11 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 21 Feb 2021 20:02:58 -0600 Subject: [PATCH 0055/1456] build pypy wheels too (#5859) * build pypy wheels too * remove unneeded packages --- .github/workflows/wheel-builder.yml | 31 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index e67feaf48429..090a70d526a9 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -11,22 +11,23 @@ jobs: container: ghcr.io/pyca/${{ matrix.MANYLINUX.CONTAINER }} strategy: matrix: - PYTHON: ["cp36-cp36m"] + PYTHON: + - { VERSION: "cp36-cp36m", PATH: "/opt/python/cp36-cp36m/bin/python", ABI_VERSION: 'cp36' } + - { VERSION: "pypy3.6", PATH: "/opt/pypy3.6/bin/pypy" } + - { VERSION: "pypy3.7", PATH: "/opt/pypy3.7/bin/pypy" } MANYLINUX: - - NAME: manylinux2010_x86_64 - CONTAINER: "cryptography-manylinux2010:x86_64" - - NAME: manylinux2014_x86_64 - CONTAINER: "cryptography-manylinux2014:x86_64" - name: "${{ matrix.PYTHON }} for ${{ matrix.MANYLINUX.NAME }}" + - { NAME: "manylinux2010_x86_64", CONTAINER: "cryptography-manylinux2010:x86_64" } + - { NAME: "manylinux2014_x86_64", CONTAINER: "cryptography-manylinux2014:x86_64" } + name: "${{ matrix.PYTHON.VERSION }} for ${{ matrix.MANYLINUX.NAME }}" steps: - - run: /opt/python/${{ matrix.PYTHON }}/bin/python -m venv .venv + - run: ${{ matrix.PYTHON.PATH }} -m venv .venv - name: Install Python dependencies - run: .venv/bin/pip install -U pip wheel cffi six ipaddress setuptools-rust + run: .venv/bin/pip install -U pip wheel cffi setuptools-rust - run: .venv/bin/pip download cryptography==${{ github.event.inputs.version }} --no-deps --no-binary cryptography && tar zxvf cryptography*.tar.gz && mkdir tmpwheelhouse - - run: | - REGEX="cp3([0-9])*" - if [[ "${{ matrix.PYTHON }}" =~ $REGEX ]]; then - PY_LIMITED_API="--py-limited-api=cp3${BASH_REMATCH[1]}" + - name: Build the wheel + run: | + if [ -n "${{ matrix.PYTHON.ABI_VERSION }}" ]; then + PY_LIMITED_API="--py-limited-api=${{ matrix.PYTHON.ABI_VERSION }}" fi cd cryptography* LDFLAGS="-L/opt/pyca/cryptography/openssl/lib" \ @@ -51,7 +52,7 @@ jobs: - run: mv wheelhouse/cryptography*.whl cryptography-wheelhouse/ - uses: actions/upload-artifact@v1 with: - name: "cryptography-${{ github.event.inputs.version }}-${{ matrix.MANYLINUX.NAME }}-${{ matrix.PYTHON }}" + name: "cryptography-${{ github.event.inputs.version }}-${{ matrix.MANYLINUX.NAME }}-${{ matrix.PYTHON.VERSION }}" path: cryptography-wheelhouse/ macos: @@ -85,7 +86,7 @@ jobs: default: true - run: ${{ matrix.PYTHON.BIN_PATH }} -m venv venv - - run: venv/bin/pip install -U pip wheel cffi six ipaddress setuptools-rust + - run: venv/bin/pip install -U pip wheel cffi setuptools-rust - run: venv/bin/pip download cryptography==${{ github.event.inputs.version }} --no-deps --no-binary cryptography && tar zxvf cryptography*.tar.gz && mkdir wheelhouse - name: Build the wheel run: | @@ -142,7 +143,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} shell: bash - - run: python -m pip install -U pip wheel cffi six ipaddress setuptools-rust + - run: python -m pip install -U pip wheel cffi setuptools-rust - run: pip download cryptography==${{ github.event.inputs.version }} --no-deps --no-binary cryptography && tar zxvf cryptography*.tar.gz && mkdir wheelhouse shell: bash - run: cd cryptography* && python setup.py bdist_wheel --py-limited-api=${{ matrix.PYTHON.ABI_VERSION }} && mv dist/cryptography*.whl ../wheelhouse From b157a7e5c472197a0e703d964fb4bf2420f2efe1 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 26 Feb 2021 16:31:20 -0500 Subject: [PATCH 0056/1456] Remove unused X509 verification flags bindings (#5868) These don't appear to be used in pyopenssl or cryptography.io. One less source of conditionals. --- src/_cffi_src/openssl/x509_vfy.py | 25 ------------------- .../hazmat/bindings/openssl/_conditional.py | 15 ----------- 2 files changed, 40 deletions(-) diff --git a/src/_cffi_src/openssl/x509_vfy.py b/src/_cffi_src/openssl/x509_vfy.py index 66cc0176115d..4642d827765c 100644 --- a/src/_cffi_src/openssl/x509_vfy.py +++ b/src/_cffi_src/openssl/x509_vfy.py @@ -18,7 +18,6 @@ """ TYPES = """ -static const long Cryptography_HAS_102_VERIFICATION; static const long Cryptography_HAS_110_VERIFICATION_PARAMS; static const long Cryptography_HAS_X509_STORE_CTX_GET_ISSUER; @@ -90,12 +89,6 @@ static const int X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX; static const int X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; static const int X509_V_ERR_CRL_PATH_VALIDATION_ERROR; -static const int X509_V_ERR_SUITE_B_INVALID_VERSION; -static const int X509_V_ERR_SUITE_B_INVALID_ALGORITHM; -static const int X509_V_ERR_SUITE_B_INVALID_CURVE; -static const int X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM; -static const int X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED; -static const int X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256; static const int X509_V_ERR_HOSTNAME_MISMATCH; static const int X509_V_ERR_EMAIL_MISMATCH; static const int X509_V_ERR_IP_ADDRESS_MISMATCH; @@ -118,9 +111,6 @@ static const long X509_V_FLAG_USE_DELTAS; static const long X509_V_FLAG_CHECK_SS_SIGNATURE; static const long X509_V_FLAG_TRUSTED_FIRST; -static const long X509_V_FLAG_SUITEB_128_LOS_ONLY; -static const long X509_V_FLAG_SUITEB_192_LOS; -static const long X509_V_FLAG_SUITEB_128_LOS; static const long X509_V_FLAG_PARTIAL_CHAIN; static const long X509_V_FLAG_NO_ALT_CHAINS; static const long X509_V_FLAG_NO_CHECK_TIME; @@ -224,21 +214,6 @@ """ CUSTOMIZATIONS = """ -#if !CRYPTOGRAPHY_IS_LIBRESSL -static const long Cryptography_HAS_102_VERIFICATION = 1; -#else -static const long Cryptography_HAS_102_VERIFICATION = 0; -static const long X509_V_ERR_SUITE_B_INVALID_VERSION = 0; -static const long X509_V_ERR_SUITE_B_INVALID_ALGORITHM = 0; -static const long X509_V_ERR_SUITE_B_INVALID_CURVE = 0; -static const long X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM = 0; -static const long X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED = 0; -static const long X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 = 0; -static const long X509_V_FLAG_SUITEB_128_LOS_ONLY = 0; -static const long X509_V_FLAG_SUITEB_192_LOS = 0; -static const long X509_V_FLAG_SUITEB_128_LOS = 0; -#endif - #if CRYPTOGRAPHY_IS_LIBRESSL static const long Cryptography_HAS_110_VERIFICATION_PARAMS = 0; #ifndef X509_CHECK_FLAG_NEVER_CHECK_SUBJECT diff --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py index 8654835796b6..aaa7d1392028 100644 --- a/src/cryptography/hazmat/bindings/openssl/_conditional.py +++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py @@ -31,20 +31,6 @@ def cryptography_has_ssl3_method(): ] -def cryptography_has_102_verification(): - return [ - "X509_V_ERR_SUITE_B_INVALID_VERSION", - "X509_V_ERR_SUITE_B_INVALID_ALGORITHM", - "X509_V_ERR_SUITE_B_INVALID_CURVE", - "X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM", - "X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED", - "X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256", - "X509_V_FLAG_SUITEB_128_LOS_ONLY", - "X509_V_FLAG_SUITEB_192_LOS", - "X509_V_FLAG_SUITEB_128_LOS", - ] - - def cryptography_has_110_verification_params(): return ["X509_CHECK_FLAG_NEVER_CHECK_SUBJECT"] @@ -280,7 +266,6 @@ def cryptography_has_get_proto_version(): "Cryptography_HAS_RSA_OAEP_MD": cryptography_has_rsa_oaep_md, "Cryptography_HAS_RSA_OAEP_LABEL": cryptography_has_rsa_oaep_label, "Cryptography_HAS_SSL3_METHOD": cryptography_has_ssl3_method, - "Cryptography_HAS_102_VERIFICATION": cryptography_has_102_verification, "Cryptography_HAS_110_VERIFICATION_PARAMS": ( cryptography_has_110_verification_params ), From 1f4794cae956213b882c26c0070af097598cc57b Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sat, 27 Feb 2021 17:19:54 +0100 Subject: [PATCH 0057/1456] Strict typehints for extensions and OIDs (#5870) * add typehint for name * strictly type ObjectIdentifier * explicit reexport for mypy * type (most) of extensions.py * minor cleanup * more consistently return None in constructors * revert explicit reexport, as requested * use _make_sequence_methods for now (#5870) * mark oid as normal type-hinted property so that classes can access it * fix spelling (upper case) use short form for reference * annotate as ClassVar * add type ignore for special extension class --- docs/x509/reference.rst | 6 + src/cryptography/hazmat/_oid.py | 12 +- src/cryptography/x509/extensions.py | 475 +++++++++++++++------------- 3 files changed, 269 insertions(+), 224 deletions(-) diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index 216896f045cc..105f8e10686c 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -1574,6 +1574,12 @@ X.509 Extensions This is the interface against which all the following extension types are registered. + .. attribute:: oid + + :type: :class:`ObjectIdentifier` + + Returns the OID associated with the given extension type. + .. class:: KeyUsage(digital_signature, content_commitment, key_encipherment, data_encipherment, key_agreement, key_cert_sign, crl_sign, encipher_only, decipher_only) .. versionadded:: 0.9 diff --git a/src/cryptography/hazmat/_oid.py b/src/cryptography/hazmat/_oid.py index 84268b8dea45..dbd04bc37609 100644 --- a/src/cryptography/hazmat/_oid.py +++ b/src/cryptography/hazmat/_oid.py @@ -2,9 +2,11 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +import typing + class ObjectIdentifier(object): - def __init__(self, dotted_string: str): + def __init__(self, dotted_string: str) -> None: self._dotted_string = dotted_string nodes = self._dotted_string.split(".") @@ -46,21 +48,21 @@ def __init__(self, dotted_string: str): % (self._dotted_string) ) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, ObjectIdentifier): return NotImplemented return self.dotted_string == other.dotted_string - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __repr__(self): + def __repr__(self) -> str: return "".format( self.dotted_string, self._name ) - def __hash__(self): + def __hash__(self) -> int: return hash(self.dotted_string) @property diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index aad8bcfd9c5b..e57190dda8e7 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -10,7 +10,6 @@ import typing from enum import Enum -from cryptography import utils from cryptography.hazmat._der import ( BIT_STRING, DERReader, @@ -76,8 +75,8 @@ def _key_identifier_from_public_key(public_key: _PUBLIC_KEY_TYPES) -> bytes: return hashlib.sha1(data).digest() -def _make_sequence_methods(field_name): - def len_method(self): +def _make_sequence_methods(field_name: str): + def len_method(self) -> int: return len(getattr(self, field_name)) def iter_method(self): @@ -90,27 +89,25 @@ def getitem_method(self, idx): class DuplicateExtension(Exception): - def __init__(self, msg: str, oid: ObjectIdentifier): + def __init__(self, msg: str, oid: ObjectIdentifier) -> None: super(DuplicateExtension, self).__init__(msg) self.oid = oid class ExtensionNotFound(Exception): - def __init__(self, msg: str, oid: ObjectIdentifier): + def __init__(self, msg: str, oid: ObjectIdentifier) -> None: super(ExtensionNotFound, self).__init__(msg) self.oid = oid class ExtensionType(metaclass=abc.ABCMeta): - @abc.abstractproperty - def oid(self) -> ObjectIdentifier: - """ - Returns the oid associated with the given extension type. - """ + oid: typing.ClassVar[ObjectIdentifier] class Extensions(object): - def __init__(self, extensions: typing.List["Extension[ExtensionType]"]): + def __init__( + self, extensions: typing.List["Extension[ExtensionType]"] + ) -> None: self._extensions = extensions def get_extension_for_oid( @@ -122,7 +119,9 @@ def get_extension_for_oid( raise ExtensionNotFound("No {} extension was found".format(oid), oid) - def get_extension_for_class(self, extclass) -> "Extension[ExtensionType]": + def get_extension_for_class( + self, extclass: typing.Type[ExtensionType] + ) -> "Extension[ExtensionType]": if extclass is UnrecognizedExtension: raise TypeError( "UnrecognizedExtension can't be used with " @@ -140,32 +139,32 @@ def get_extension_for_class(self, extclass) -> "Extension[ExtensionType]": __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions") - def __repr__(self): + def __repr__(self) -> str: return "".format(self._extensions) class CRLNumber(ExtensionType): oid = ExtensionOID.CRL_NUMBER - def __init__(self, crl_number: int): + def __init__(self, crl_number: int) -> None: if not isinstance(crl_number, int): raise TypeError("crl_number must be an integer") self._crl_number = crl_number - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, CRLNumber): return NotImplemented return self.crl_number == other.crl_number - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(self.crl_number) - def __repr__(self): + def __repr__(self) -> str: return "".format(self.crl_number) @property @@ -181,7 +180,7 @@ def __init__( key_identifier: typing.Optional[bytes], authority_cert_issuer: typing.Optional[typing.Iterable[GeneralName]], authority_cert_serial_number: typing.Optional[int], - ): + ) -> None: if (authority_cert_issuer is None) != ( authority_cert_serial_number is None ): @@ -230,7 +229,7 @@ def from_issuer_subject_key_identifier( authority_cert_serial_number=None, ) - def __repr__(self): + def __repr__(self) -> str: return ( "".format(self) ) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, AuthorityKeyIdentifier): return NotImplemented @@ -249,10 +248,10 @@ def __eq__(self, other): == other.authority_cert_serial_number ) - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: if self.authority_cert_issuer is None: aci = None else: @@ -279,7 +278,7 @@ def authority_cert_serial_number(self) -> typing.Optional[int]: class SubjectKeyIdentifier(ExtensionType): oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER - def __init__(self, digest: bytes): + def __init__(self, digest: bytes) -> None: self._digest = digest @classmethod @@ -296,26 +295,28 @@ def digest(self) -> bytes: def key_identifier(self) -> bytes: return self._digest - def __repr__(self): + def __repr__(self) -> str: return "".format(self.digest) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, SubjectKeyIdentifier): return NotImplemented return constant_time.bytes_eq(self.digest, other.digest) - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(self.digest) class AuthorityInformationAccess(ExtensionType): oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS - def __init__(self, descriptions: typing.Iterable["AccessDescription"]): + def __init__( + self, descriptions: typing.Iterable["AccessDescription"] + ) -> None: descriptions = list(descriptions) if not all(isinstance(x, AccessDescription) for x in descriptions): raise TypeError( @@ -327,26 +328,28 @@ def __init__(self, descriptions: typing.Iterable["AccessDescription"]): __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") - def __repr__(self): + def __repr__(self) -> str: return "".format(self._descriptions) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, AuthorityInformationAccess): return NotImplemented return self._descriptions == other._descriptions - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(tuple(self._descriptions)) class SubjectInformationAccess(ExtensionType): oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS - def __init__(self, descriptions: typing.Iterable["AccessDescription"]): + def __init__( + self, descriptions: typing.Iterable["AccessDescription"] + ) -> None: descriptions = list(descriptions) if not all(isinstance(x, AccessDescription) for x in descriptions): raise TypeError( @@ -358,26 +361,26 @@ def __init__(self, descriptions: typing.Iterable["AccessDescription"]): __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") - def __repr__(self): + def __repr__(self) -> str: return "".format(self._descriptions) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, SubjectInformationAccess): return NotImplemented return self._descriptions == other._descriptions - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(tuple(self._descriptions)) class AccessDescription(object): def __init__( self, access_method: ObjectIdentifier, access_location: GeneralName - ): + ) -> None: if not isinstance(access_method, ObjectIdentifier): raise TypeError("access_method must be an ObjectIdentifier") @@ -387,13 +390,13 @@ def __init__( self._access_method = access_method self._access_location = access_location - def __repr__(self): + def __repr__(self) -> str: return ( "".format(self) ) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, AccessDescription): return NotImplemented @@ -402,10 +405,10 @@ def __eq__(self, other): and self.access_location == other.access_location ) - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash((self.access_method, self.access_location)) @property @@ -420,7 +423,7 @@ def access_location(self) -> GeneralName: class BasicConstraints(ExtensionType): oid = ExtensionOID.BASIC_CONSTRAINTS - def __init__(self, ca: bool, path_length: typing.Optional[int]): + def __init__(self, ca: bool, path_length: typing.Optional[int]) -> None: if not isinstance(ca, bool): raise TypeError("ca must be a boolean value") @@ -445,28 +448,28 @@ def ca(self) -> bool: def path_length(self) -> typing.Optional[int]: return self._path_length - def __repr__(self): + def __repr__(self) -> str: return ( "" ).format(self) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, BasicConstraints): return NotImplemented return self.ca == other.ca and self.path_length == other.path_length - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash((self.ca, self.path_length)) class DeltaCRLIndicator(ExtensionType): oid = ExtensionOID.DELTA_CRL_INDICATOR - def __init__(self, crl_number: int): + def __init__(self, crl_number: int) -> None: if not isinstance(crl_number, int): raise TypeError("crl_number must be an integer") @@ -476,19 +479,19 @@ def __init__(self, crl_number: int): def crl_number(self) -> int: return self._crl_number - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, DeltaCRLIndicator): return NotImplemented return self.crl_number == other.crl_number - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(self.crl_number) - def __repr__(self): + def __repr__(self) -> str: return "".format(self) @@ -497,7 +500,7 @@ class CRLDistributionPoints(ExtensionType): def __init__( self, distribution_points: typing.Iterable["DistributionPoint"] - ): + ) -> None: distribution_points = list(distribution_points) if not all( isinstance(x, DistributionPoint) for x in distribution_points @@ -513,19 +516,19 @@ def __init__( "_distribution_points" ) - def __repr__(self): + def __repr__(self) -> str: return "".format(self._distribution_points) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, CRLDistributionPoints): return NotImplemented return self._distribution_points == other._distribution_points - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(tuple(self._distribution_points)) @@ -534,7 +537,7 @@ class FreshestCRL(ExtensionType): def __init__( self, distribution_points: typing.Iterable["DistributionPoint"] - ): + ) -> None: distribution_points = list(distribution_points) if not all( isinstance(x, DistributionPoint) for x in distribution_points @@ -550,19 +553,19 @@ def __init__( "_distribution_points" ) - def __repr__(self): + def __repr__(self) -> str: return "".format(self._distribution_points) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, FreshestCRL): return NotImplemented return self._distribution_points == other._distribution_points - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(tuple(self._distribution_points)) @@ -573,7 +576,7 @@ def __init__( relative_name: typing.Optional[RelativeDistinguishedName], reasons: typing.Optional[typing.FrozenSet["ReasonFlags"]], crl_issuer: typing.Optional[typing.Iterable[GeneralName]], - ): + ) -> None: if full_name and relative_name: raise ValueError( "You cannot provide both full_name and relative_name, at " @@ -626,14 +629,14 @@ def __init__( self._reasons = reasons self._crl_issuer = crl_issuer - def __repr__(self): + def __repr__(self) -> str: return ( "".format(self) ) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, DistributionPoint): return NotImplemented @@ -644,17 +647,21 @@ def __eq__(self, other): and self.crl_issuer == other.crl_issuer ) - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: if self.full_name is not None: - fn: typing.Optional[tuple] = tuple(self.full_name) + fn: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple( + self.full_name + ) else: fn = None if self.crl_issuer is not None: - crl_issuer: typing.Optional[tuple] = tuple(self.crl_issuer) + crl_issuer: typing.Optional[ + typing.Tuple[GeneralName, ...] + ] = tuple(self.crl_issuer) else: crl_issuer = None @@ -697,7 +704,7 @@ def __init__( self, require_explicit_policy: typing.Optional[int], inhibit_policy_mapping: typing.Optional[int], - ): + ) -> None: if require_explicit_policy is not None and not isinstance( require_explicit_policy, int ): @@ -722,14 +729,14 @@ def __init__( self._require_explicit_policy = require_explicit_policy self._inhibit_policy_mapping = inhibit_policy_mapping - def __repr__(self): + def __repr__(self) -> str: return ( "".format(self) ) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, PolicyConstraints): return NotImplemented @@ -738,10 +745,10 @@ def __eq__(self, other): and self.inhibit_policy_mapping == other.inhibit_policy_mapping ) - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash( (self.require_explicit_policy, self.inhibit_policy_mapping) ) @@ -758,7 +765,7 @@ def inhibit_policy_mapping(self) -> typing.Optional[int]: class CertificatePolicies(ExtensionType): oid = ExtensionOID.CERTIFICATE_POLICIES - def __init__(self, policies: typing.Iterable["PolicyInformation"]): + def __init__(self, policies: typing.Iterable["PolicyInformation"]) -> None: policies = list(policies) if not all(isinstance(x, PolicyInformation) for x in policies): raise TypeError( @@ -770,19 +777,19 @@ def __init__(self, policies: typing.Iterable["PolicyInformation"]): __len__, __iter__, __getitem__ = _make_sequence_methods("_policies") - def __repr__(self): + def __repr__(self) -> str: return "".format(self._policies) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, CertificatePolicies): return NotImplemented return self._policies == other._policies - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(tuple(self._policies)) @@ -793,7 +800,7 @@ def __init__( policy_qualifiers: typing.Optional[ typing.Iterable[typing.Union[str, "UserNotice"]] ], - ): + ) -> None: if not isinstance(policy_identifier, ObjectIdentifier): raise TypeError("policy_identifier must be an ObjectIdentifier") @@ -811,13 +818,13 @@ def __init__( self._policy_qualifiers = policy_qualifiers - def __repr__(self): + def __repr__(self) -> str: return ( "".format(self) ) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, PolicyInformation): return NotImplemented @@ -826,12 +833,14 @@ def __eq__(self, other): and self.policy_qualifiers == other.policy_qualifiers ) - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: if self.policy_qualifiers is not None: - pq: typing.Optional[tuple] = tuple(self.policy_qualifiers) + pq: typing.Optional[ + typing.Tuple[typing.Union[str, "UserNotice"], ...] + ] = tuple(self.policy_qualifiers) else: pq = None @@ -853,7 +862,7 @@ def __init__( self, notice_reference: typing.Optional["NoticeReference"], explicit_text: typing.Optional[str], - ): + ) -> None: if notice_reference and not isinstance( notice_reference, NoticeReference ): @@ -864,13 +873,13 @@ def __init__( self._notice_reference = notice_reference self._explicit_text = explicit_text - def __repr__(self): + def __repr__(self) -> str: return ( "".format(self) ) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, UserNotice): return NotImplemented @@ -879,10 +888,10 @@ def __eq__(self, other): and self.explicit_text == other.explicit_text ) - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash((self.notice_reference, self.explicit_text)) @property @@ -899,7 +908,7 @@ def __init__( self, organization: typing.Optional[str], notice_numbers: typing.Iterable[int], - ): + ) -> None: self._organization = organization notice_numbers = list(notice_numbers) if not all(isinstance(x, int) for x in notice_numbers): @@ -907,13 +916,13 @@ def __init__( self._notice_numbers = notice_numbers - def __repr__(self): + def __repr__(self) -> str: return ( "".format(self) ) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, NoticeReference): return NotImplemented @@ -922,10 +931,10 @@ def __eq__(self, other): and self.notice_numbers == other.notice_numbers ) - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash((self.organization, tuple(self.notice_numbers))) @property @@ -940,7 +949,7 @@ def notice_numbers(self) -> typing.List[int]: class ExtendedKeyUsage(ExtensionType): oid = ExtensionOID.EXTENDED_KEY_USAGE - def __init__(self, usages: typing.Iterable[ObjectIdentifier]): + def __init__(self, usages: typing.Iterable[ObjectIdentifier]) -> None: usages = list(usages) if not all(isinstance(x, ObjectIdentifier) for x in usages): raise TypeError( @@ -951,64 +960,64 @@ def __init__(self, usages: typing.Iterable[ObjectIdentifier]): __len__, __iter__, __getitem__ = _make_sequence_methods("_usages") - def __repr__(self): + def __repr__(self) -> str: return "".format(self._usages) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, ExtendedKeyUsage): return NotImplemented return self._usages == other._usages - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(tuple(self._usages)) class OCSPNoCheck(ExtensionType): oid = ExtensionOID.OCSP_NO_CHECK - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, OCSPNoCheck): return NotImplemented return True - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(OCSPNoCheck) - def __repr__(self): + def __repr__(self) -> str: return "" class PrecertPoison(ExtensionType): oid = ExtensionOID.PRECERT_POISON - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, PrecertPoison): return NotImplemented return True - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(PrecertPoison) - def __repr__(self): + def __repr__(self) -> str: return "" class TLSFeature(ExtensionType): oid = ExtensionOID.TLS_FEATURE - def __init__(self, features: typing.Iterable["TLSFeatureType"]): + def __init__(self, features: typing.Iterable["TLSFeatureType"]) -> None: features = list(features) if ( not all(isinstance(x, TLSFeatureType) for x in features) @@ -1023,19 +1032,19 @@ def __init__(self, features: typing.Iterable["TLSFeatureType"]): __len__, __iter__, __getitem__ = _make_sequence_methods("_features") - def __repr__(self): + def __repr__(self) -> str: return "".format(self) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, TLSFeature): return NotImplemented return self._features == other._features - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(tuple(self._features)) @@ -1056,7 +1065,7 @@ class TLSFeatureType(Enum): class InhibitAnyPolicy(ExtensionType): oid = ExtensionOID.INHIBIT_ANY_POLICY - def __init__(self, skip_certs: int): + def __init__(self, skip_certs: int) -> None: if not isinstance(skip_certs, int): raise TypeError("skip_certs must be an integer") @@ -1065,19 +1074,19 @@ def __init__(self, skip_certs: int): self._skip_certs = skip_certs - def __repr__(self): + def __repr__(self) -> str: return "".format(self) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, InhibitAnyPolicy): return NotImplemented return self.skip_certs == other.skip_certs - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(self.skip_certs) @property @@ -1099,7 +1108,7 @@ def __init__( crl_sign: bool, encipher_only: bool, decipher_only: bool, - ): + ) -> None: if not key_agreement and (encipher_only or decipher_only): raise ValueError( "encipher_only and decipher_only can only be true when " @@ -1145,7 +1154,7 @@ def crl_sign(self) -> bool: return self._crl_sign @property - def encipher_only(self): + def encipher_only(self) -> bool: if not self.key_agreement: raise ValueError( "encipher_only is undefined unless key_agreement is true" @@ -1154,7 +1163,7 @@ def encipher_only(self): return self._encipher_only @property - def decipher_only(self): + def decipher_only(self) -> bool: if not self.key_agreement: raise ValueError( "decipher_only is undefined unless key_agreement is true" @@ -1162,7 +1171,7 @@ def decipher_only(self): else: return self._decipher_only - def __repr__(self): + def __repr__(self) -> str: try: encipher_only = self.encipher_only decipher_only = self.decipher_only @@ -1183,7 +1192,7 @@ def __repr__(self): "encipher_only={1}, decipher_only={2})>" ).format(self, encipher_only, decipher_only) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, KeyUsage): return NotImplemented @@ -1199,10 +1208,10 @@ def __eq__(self, other): and self._decipher_only == other._decipher_only ) - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash( ( self.digital_signature, @@ -1225,7 +1234,7 @@ def __init__( self, permitted_subtrees: typing.Optional[typing.Iterable[GeneralName]], excluded_subtrees: typing.Optional[typing.Iterable[GeneralName]], - ): + ) -> None: if permitted_subtrees is not None: permitted_subtrees = list(permitted_subtrees) if not all(isinstance(x, GeneralName) for x in permitted_subtrees): @@ -1255,7 +1264,7 @@ def __init__( self._permitted_subtrees = permitted_subtrees self._excluded_subtrees = excluded_subtrees - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, NameConstraints): return NotImplemented @@ -1264,10 +1273,10 @@ def __eq__(self, other): and self.permitted_subtrees == other.permitted_subtrees ) - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def _validate_ip_name(self, tree): + def _validate_ip_name(self, tree: typing.Iterable[GeneralName]) -> None: if any( isinstance(name, IPAddress) and not isinstance( @@ -1280,20 +1289,24 @@ def _validate_ip_name(self, tree): " IPv6Network object" ) - def __repr__(self): + def __repr__(self) -> str: return ( "".format(self) ) - def __hash__(self): + def __hash__(self) -> int: if self.permitted_subtrees is not None: - ps: typing.Optional[tuple] = tuple(self.permitted_subtrees) + ps: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple( + self.permitted_subtrees + ) else: ps = None if self.excluded_subtrees is not None: - es: typing.Optional[tuple] = tuple(self.excluded_subtrees) + es: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple( + self.excluded_subtrees + ) else: es = None @@ -1315,7 +1328,7 @@ def excluded_subtrees( class Extension(typing.Generic[ExtensionTypeVar]): def __init__( self, oid: ObjectIdentifier, critical: bool, value: ExtensionTypeVar - ): + ) -> None: if not isinstance(oid, ObjectIdentifier): raise TypeError( "oid argument must be an ObjectIdentifier instance." @@ -1340,13 +1353,13 @@ def critical(self) -> bool: def value(self) -> ExtensionType: return self._value - def __repr__(self): + def __repr__(self) -> str: return ( "" ).format(self) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, Extension): return NotImplemented @@ -1356,15 +1369,15 @@ def __eq__(self, other): and self.value == other.value ) - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash((self.oid, self.critical, self.value)) class GeneralNames(object): - def __init__(self, general_names: typing.Iterable[GeneralName]): + def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: general_names = list(general_names) if not all(isinstance(x, GeneralName) for x in general_names): raise TypeError( @@ -1376,7 +1389,9 @@ def __init__(self, general_names: typing.Iterable[GeneralName]): __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") - def get_values_for_type(self, type: typing.Type[GeneralName]): + def get_values_for_type( + self, type: typing.Type[GeneralName] + ) -> typing.List[GeneralName]: # Return the value of each GeneralName, except for OtherName instances # which we return directly because it has two important properties not # just one value. @@ -1385,125 +1400,131 @@ def get_values_for_type(self, type: typing.Type[GeneralName]): objs = (i.value for i in objs) return list(objs) - def __repr__(self): + def __repr__(self) -> str: return "".format(self._general_names) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, GeneralNames): return NotImplemented return self._general_names == other._general_names - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(tuple(self._general_names)) class SubjectAlternativeName(ExtensionType): oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME - def __init__(self, general_names: typing.Iterable[GeneralName]): + def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: self._general_names = GeneralNames(general_names) __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") - def get_values_for_type(self, type): + def get_values_for_type( + self, type: typing.Type[GeneralName] + ) -> typing.List[GeneralName]: return self._general_names.get_values_for_type(type) - def __repr__(self): + def __repr__(self) -> str: return "".format(self._general_names) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, SubjectAlternativeName): return NotImplemented return self._general_names == other._general_names - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(self._general_names) class IssuerAlternativeName(ExtensionType): oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME - def __init__(self, general_names: typing.Iterable[GeneralName]): + def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: self._general_names = GeneralNames(general_names) __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") - def get_values_for_type(self, type): + def get_values_for_type( + self, type: typing.Type[GeneralName] + ) -> typing.List[GeneralName]: return self._general_names.get_values_for_type(type) - def __repr__(self): + def __repr__(self) -> str: return "".format(self._general_names) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, IssuerAlternativeName): return NotImplemented return self._general_names == other._general_names - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(self._general_names) class CertificateIssuer(ExtensionType): oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER - def __init__(self, general_names: typing.Iterable[GeneralName]): + def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: self._general_names = GeneralNames(general_names) __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") - def get_values_for_type(self, type): + def get_values_for_type( + self, type: typing.Type[GeneralName] + ) -> typing.List[GeneralName]: return self._general_names.get_values_for_type(type) - def __repr__(self): + def __repr__(self) -> str: return "".format(self._general_names) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, CertificateIssuer): return NotImplemented return self._general_names == other._general_names - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(self._general_names) class CRLReason(ExtensionType): oid = CRLEntryExtensionOID.CRL_REASON - def __init__(self, reason: ReasonFlags): + def __init__(self, reason: ReasonFlags) -> None: if not isinstance(reason, ReasonFlags): raise TypeError("reason must be an element from ReasonFlags") self._reason = reason - def __repr__(self): + def __repr__(self) -> str: return "".format(self._reason) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, CRLReason): return NotImplemented return self.reason == other.reason - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(self.reason) @property @@ -1514,27 +1535,27 @@ def reason(self) -> ReasonFlags: class InvalidityDate(ExtensionType): oid = CRLEntryExtensionOID.INVALIDITY_DATE - def __init__(self, invalidity_date: datetime.datetime): + def __init__(self, invalidity_date: datetime.datetime) -> None: if not isinstance(invalidity_date, datetime.datetime): raise TypeError("invalidity_date must be a datetime.datetime") self._invalidity_date = invalidity_date - def __repr__(self): + def __repr__(self) -> str: return "".format( self._invalidity_date ) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, InvalidityDate): return NotImplemented return self.invalidity_date == other.invalidity_date - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(self.invalidity_date) @property @@ -1550,7 +1571,7 @@ def __init__( signed_certificate_timestamps: typing.Iterable[ SignedCertificateTimestamp ], - ): + ) -> None: signed_certificate_timestamps = list(signed_certificate_timestamps) if not all( isinstance(sct, SignedCertificateTimestamp) @@ -1566,15 +1587,15 @@ def __init__( "_signed_certificate_timestamps" ) - def __repr__(self): + def __repr__(self) -> str: return "".format( list(self) ) - def __hash__(self): + def __hash__(self) -> int: return hash(tuple(self._signed_certificate_timestamps)) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, PrecertificateSignedCertificateTimestamps): return NotImplemented @@ -1583,7 +1604,7 @@ def __eq__(self, other): == other._signed_certificate_timestamps ) - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other @@ -1595,7 +1616,7 @@ def __init__( signed_certificate_timestamps: typing.Iterable[ SignedCertificateTimestamp ], - ): + ) -> None: signed_certificate_timestamps = list(signed_certificate_timestamps) if not all( isinstance(sct, SignedCertificateTimestamp) @@ -1611,13 +1632,13 @@ def __init__( "_signed_certificate_timestamps" ) - def __repr__(self): + def __repr__(self) -> str: return "".format(list(self)) - def __hash__(self): + def __hash__(self) -> int: return hash(tuple(self._signed_certificate_timestamps)) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, SignedCertificateTimestamps): return NotImplemented @@ -1626,32 +1647,32 @@ def __eq__(self, other): == other._signed_certificate_timestamps ) - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other class OCSPNonce(ExtensionType): oid = OCSPExtensionOID.NONCE - def __init__(self, nonce: bytes): + def __init__(self, nonce: bytes) -> None: if not isinstance(nonce, bytes): raise TypeError("nonce must be bytes") self._nonce = nonce - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, OCSPNonce): return NotImplemented return self.nonce == other.nonce - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash(self.nonce) - def __repr__(self): + def __repr__(self) -> str: return "".format(self) @property @@ -1664,14 +1685,14 @@ class IssuingDistributionPoint(ExtensionType): def __init__( self, - full_name, - relative_name, - only_contains_user_certs, - only_contains_ca_certs, - only_some_reasons, - indirect_crl, - only_contains_attribute_certs, - ): + full_name: typing.Optional[typing.List[GeneralName]], + relative_name: typing.Optional[RelativeDistinguishedName], + only_contains_user_certs: bool, + only_contains_ca_certs: bool, + only_some_reasons: typing.Optional[typing.FrozenSet[ReasonFlags]], + indirect_crl: bool, + only_contains_attribute_certs: bool, + ) -> None: if only_some_reasons and ( not isinstance(only_some_reasons, frozenset) or not all(isinstance(x, ReasonFlags) for x in only_some_reasons) @@ -1742,7 +1763,7 @@ def __init__( self._full_name = full_name self._relative_name = relative_name - def __repr__(self): + def __repr__(self) -> str: return ( "".format(self) ) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, IssuingDistributionPoint): return NotImplemented @@ -1769,10 +1790,10 @@ def __eq__(self, other): == other.only_contains_attribute_certs ) - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash( ( self.full_name, @@ -1785,50 +1806,66 @@ def __hash__(self): ) ) - 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" - ) + @property + def full_name(self) -> typing.Optional[typing.List[GeneralName]]: + return self._full_name + + @property + def relative_name(self) -> typing.Optional[RelativeDistinguishedName]: + return self._relative_name + + @property + def only_contains_user_certs(self) -> bool: + return self._only_contains_user_certs + + @property + def only_contains_ca_certs(self) -> bool: + return self._only_contains_ca_certs + + @property + def only_some_reasons( + self, + ) -> typing.Optional[typing.FrozenSet[ReasonFlags]]: + return self._only_some_reasons + + @property + def indirect_crl(self) -> bool: + return self._indirect_crl + + @property + def only_contains_attribute_certs(self) -> bool: + return self._only_contains_attribute_certs class UnrecognizedExtension(ExtensionType): - def __init__(self, oid: ObjectIdentifier, value: bytes): + def __init__(self, oid: ObjectIdentifier, value: bytes) -> None: if not isinstance(oid, ObjectIdentifier): raise TypeError("oid must be an ObjectIdentifier") self._oid = oid self._value = value @property - def oid(self) -> ObjectIdentifier: + def oid(self) -> ObjectIdentifier: # type: ignore[override] return self._oid @property def value(self) -> bytes: return self._value - def __repr__(self): + def __repr__(self) -> str: return ( "".format(self) ) - def __eq__(self, other): + def __eq__(self, other: typing.Any) -> bool: if not isinstance(other, UnrecognizedExtension): return NotImplemented return self.oid == other.oid and self.value == other.value - def __ne__(self, other): + def __ne__(self, other: typing.Any) -> bool: return not self == other - def __hash__(self): + def __hash__(self) -> int: return hash((self.oid, self.value)) From 60c67792b46d7f6a38ba7540ad768572cd505fe7 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sat, 27 Feb 2021 22:00:50 +0100 Subject: [PATCH 0058/1456] consistently typecast to list (#5873) --- src/cryptography/x509/extensions.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index e57190dda8e7..d43f2b8d2a58 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -106,9 +106,9 @@ class ExtensionType(metaclass=abc.ABCMeta): class Extensions(object): def __init__( - self, extensions: typing.List["Extension[ExtensionType]"] + self, extensions: typing.Iterable["Extension[ExtensionType]"] ) -> None: - self._extensions = extensions + self._extensions = list(extensions) def get_extension_for_oid( self, oid: ObjectIdentifier @@ -1685,7 +1685,7 @@ class IssuingDistributionPoint(ExtensionType): def __init__( self, - full_name: typing.Optional[typing.List[GeneralName]], + full_name: typing.Optional[typing.Iterable[GeneralName]], relative_name: typing.Optional[RelativeDistinguishedName], only_contains_user_certs: bool, only_contains_ca_certs: bool, @@ -1693,6 +1693,9 @@ def __init__( indirect_crl: bool, only_contains_attribute_certs: bool, ) -> None: + if full_name is not None: + full_name = list(full_name) + if only_some_reasons and ( not isinstance(only_some_reasons, frozenset) or not all(isinstance(x, ReasonFlags) for x in only_some_reasons) From dcbec5ea993b22fa7033c0cf37f8abab6b3fc9e6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 27 Feb 2021 18:34:39 -0500 Subject: [PATCH 0059/1456] Annotate asymetric contexts (#5874) --- src/cryptography/hazmat/primitives/asymmetric/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cryptography/hazmat/primitives/asymmetric/__init__.py b/src/cryptography/hazmat/primitives/asymmetric/__init__.py index efa23a6e8cd7..f4953efcc532 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/__init__.py +++ b/src/cryptography/hazmat/primitives/asymmetric/__init__.py @@ -8,13 +8,13 @@ class AsymmetricSignatureContext(metaclass=abc.ABCMeta): @abc.abstractmethod - def update(self, data): + def update(self, data: bytes) -> None: """ Processes the provided bytes and returns nothing. """ @abc.abstractmethod - def finalize(self): + def finalize(self) -> bytes: """ Returns the signature as bytes. """ @@ -22,13 +22,13 @@ def finalize(self): class AsymmetricVerificationContext(metaclass=abc.ABCMeta): @abc.abstractmethod - def update(self, data): + def update(self, data: bytes) -> None: """ Processes the provided bytes and returns nothing. """ @abc.abstractmethod - def verify(self): + def verify(self) -> None: """ Raises an exception if the bytes provided to update do not match the signature or the signature does not match the public key. From e0e9688a29de5920a764ca7bedb72744b0e4491e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 27 Feb 2021 19:18:13 -0500 Subject: [PATCH 0060/1456] Type a bunch of random functions (#5875) --- src/cryptography/hazmat/_der.py | 10 +++++----- src/cryptography/x509/general_name.py | 14 ++++++++------ src/cryptography/x509/name.py | 14 ++++++++++---- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/cryptography/hazmat/_der.py b/src/cryptography/hazmat/_der.py index fa5940b23672..ba1db4caf682 100644 --- a/src/cryptography/hazmat/_der.py +++ b/src/cryptography/hazmat/_der.py @@ -31,20 +31,20 @@ class DERReader(object): - def __init__(self, data): + def __init__(self, data: bytes) -> None: self.data = memoryview(data) - def __enter__(self): + def __enter__(self) -> "DERReader": return self def __exit__(self, exc_type, exc_value, tb): if exc_value is None: self.check_empty() - def is_empty(self): + def is_empty(self) -> bool: return len(self.data) == 0 - def check_empty(self): + def check_empty(self) -> None: if not self.is_empty(): raise ValueError("Invalid DER input: trailing data") @@ -55,7 +55,7 @@ def read_byte(self) -> int: self.data = self.data[1:] return ret - def read_bytes(self, n) -> memoryview: + def read_bytes(self, n: int) -> memoryview: if len(self.data) < n: raise ValueError("Invalid DER input: insufficient data") ret = self.data[:n] diff --git a/src/cryptography/x509/general_name.py b/src/cryptography/x509/general_name.py index e9495909018b..f16aef85e15f 100644 --- a/src/cryptography/x509/general_name.py +++ b/src/cryptography/x509/general_name.py @@ -26,14 +26,14 @@ class UnsupportedGeneralNameType(Exception): - def __init__(self, msg, type): + def __init__(self, msg: str, type: int) -> None: super(UnsupportedGeneralNameType, self).__init__(msg) self.type = type class GeneralName(metaclass=abc.ABCMeta): @abc.abstractproperty - def value(self): + def value(self) -> typing.Any: """ Return the value of the object """ @@ -66,7 +66,7 @@ def value(self) -> str: return self._value @classmethod - def _init_without_validation(cls, value): + def _init_without_validation(cls, value: str) -> "RFC822Name": instance = cls.__new__(cls) instance._value = value return instance @@ -108,12 +108,12 @@ def value(self) -> str: return self._value @classmethod - def _init_without_validation(cls, value): + def _init_without_validation(cls, value: str) -> "DNSName": instance = cls.__new__(cls) instance._value = value return instance - def __repr__(self): + def __repr__(self) -> str: return "".format(self.value) def __eq__(self, other: object) -> bool: @@ -150,7 +150,9 @@ def value(self) -> str: return self._value @classmethod - def _init_without_validation(cls, value): + def _init_without_validation( + cls, value: str + ) -> "UniformResourceIdentifier": instance = cls.__new__(cls) instance._value = value return instance diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py index 2d506f73bb39..5c171ad615c1 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -48,7 +48,7 @@ class _ASN1Type(Enum): } -def _escape_dn_value(val): +def _escape_dn_value(val: str) -> str: """Escape special characters in RFC4514 Distinguished Name value.""" if not val: @@ -73,7 +73,9 @@ def _escape_dn_value(val): class NameAttribute(object): - def __init__(self, oid: ObjectIdentifier, value: str, _type=_SENTINEL): + def __init__( + self, oid: ObjectIdentifier, value: str, _type=_SENTINEL + ) -> None: if not isinstance(oid, ObjectIdentifier): raise TypeError( "oid argument must be an ObjectIdentifier instance." @@ -156,7 +158,9 @@ def __init__(self, attributes: typing.Iterable[NameAttribute]): if len(self._attribute_set) != len(attributes): raise ValueError("duplicate attributes are not allowed") - def get_attributes_for_oid(self, oid) -> typing.List[NameAttribute]: + def get_attributes_for_oid( + self, oid: ObjectIdentifier + ) -> typing.List[NameAttribute]: return [i for i in self if i.oid == oid] def rfc4514_string(self) -> str: @@ -220,7 +224,9 @@ def rfc4514_string(self) -> str: attr.rfc4514_string() for attr in reversed(self._attributes) ) - def get_attributes_for_oid(self, oid) -> typing.List[NameAttribute]: + def get_attributes_for_oid( + self, oid: ObjectIdentifier + ) -> typing.List[NameAttribute]: return [i for i in self if i.oid == oid] @property From 616cdd32203192692e177501bfc59234374d870a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 27 Feb 2021 21:39:59 -0500 Subject: [PATCH 0061/1456] Update comment (#5876) --- tests/x509/test_x509.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index b1e86f43647e..3acb3ef9c3dc 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -1814,7 +1814,7 @@ def read_next_rdn_value_tag(reader): assert read_next_rdn_value_tag(subject) == PRINTABLE_STRING assert read_next_rdn_value_tag(issuer) == PRINTABLE_STRING if ( - # This only works correctly in OpenSSL 1.1.0f+ and 1.0.2l+ + # This only works correctly in OpenSSL 1.1.0f+ backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER ): assert read_next_rdn_value_tag(subject) == PRINTABLE_STRING From 0cb83aeb71822cd30c75c7c5acda09c4e8160ca9 Mon Sep 17 00:00:00 2001 From: tobyp Date: Sun, 28 Feb 2021 20:19:44 +0100 Subject: [PATCH 0062/1456] Add SM3 hash algorithm (#5833) Co-authored-by: Tobias Peter --- .../primitives/cryptographic-hashes.rst | 15 +++++++++ src/cryptography/hazmat/primitives/hashes.py | 6 ++++ tests/hazmat/primitives/test_hash_vectors.py | 14 +++++++++ tests/hazmat/primitives/test_hashes.py | 12 +++++++ .../cryptography_vectors/hashes/SM3/oscca.txt | 31 +++++++++++++++++++ 5 files changed, 78 insertions(+) create mode 100644 vectors/cryptography_vectors/hashes/SM3/oscca.txt diff --git a/docs/hazmat/primitives/cryptographic-hashes.rst b/docs/hazmat/primitives/cryptographic-hashes.rst index 4cdc034a6b84..f79f8d7066cb 100644 --- a/docs/hazmat/primitives/cryptographic-hashes.rst +++ b/docs/hazmat/primitives/cryptographic-hashes.rst @@ -245,6 +245,19 @@ MD5 message digest and has practical known collision attacks. +SM3 +~~~ + +.. class:: SM3() + + .. versionadded:: 35.0.0 + + SM3 is a cryptographic hash function standardized by the Chinese National + Cryptography Administration in `GM/T 0004-2012`_. It produces 256-bit + message digests. (An English description is available at + `draft-oscca-cfrg-sm3-02`_.) + + Interfaces ~~~~~~~~~~ @@ -286,3 +299,5 @@ Interfaces .. _`Lifetimes of cryptographic hash functions`: https://valerieaurora.org/hash.html .. _`BLAKE2`: https://blake2.net .. _`length-extension attacks`: https://en.wikipedia.org/wiki/Length_extension_attack +.. _`GM/T 0004-2012`: http://www.oscca.gov.cn/sca/xxgk/2010-12/17/1002389/files/302a3ada057c4a73830536d03e683110.pdf +.. _`draft-oscca-cfrg-sm3-02`: https://tools.ietf.org/id/draft-oscca-cfrg-sm3-02.html diff --git a/src/cryptography/hazmat/primitives/hashes.py b/src/cryptography/hazmat/primitives/hashes.py index 4f92d6d271da..6552fb95de68 100644 --- a/src/cryptography/hazmat/primitives/hashes.py +++ b/src/cryptography/hazmat/primitives/hashes.py @@ -255,3 +255,9 @@ def __init__(self, digest_size: int): @property def digest_size(self) -> int: return self._digest_size + + +class SM3(HashAlgorithm): + name = "sm3" + digest_size = 32 + block_size = 64 diff --git a/tests/hazmat/primitives/test_hash_vectors.py b/tests/hazmat/primitives/test_hash_vectors.py index 553eee37599f..6b76f8db9550 100644 --- a/tests/hazmat/primitives/test_hash_vectors.py +++ b/tests/hazmat/primitives/test_hash_vectors.py @@ -275,3 +275,17 @@ def test_shake256_variable(self, backend, subtests): 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.SM3()), + skip_message="Does not support SM3", +) +@pytest.mark.requires_backend_interface(interface=HashBackend) +class TestSM3(object): + test_sm3 = generate_hash_test( + load_hash_vectors, + os.path.join("hashes", "SM3"), + ["oscca.txt"], + hashes.SM3(), + ) diff --git a/tests/hazmat/primitives/test_hashes.py b/tests/hazmat/primitives/test_hashes.py index 559eb6d674c4..c0f5a9282c81 100644 --- a/tests/hazmat/primitives/test_hashes.py +++ b/tests/hazmat/primitives/test_hashes.py @@ -195,3 +195,15 @@ def test_invalid_digest_size(self, xof): with pytest.raises(ValueError): xof(digest_size=0) + + +@pytest.mark.supported( + only_if=lambda backend: backend.hash_supported(hashes.SM3()), + skip_message="Does not support SM3", +) +@pytest.mark.requires_backend_interface(interface=HashBackend) +class TestSM3(object): + test_sm3 = generate_base_hash_test( + hashes.SM3(), + digest_size=32, + ) diff --git a/vectors/cryptography_vectors/hashes/SM3/oscca.txt b/vectors/cryptography_vectors/hashes/SM3/oscca.txt new file mode 100644 index 000000000000..b0d0475ce7c5 --- /dev/null +++ b/vectors/cryptography_vectors/hashes/SM3/oscca.txt @@ -0,0 +1,31 @@ +# Vectors from https://raw.githubusercontent.com/torvalds/linux/master/crypto/testmgr.h, +# originally from http://www.oscca.gov.cn/UpFile/20101222141857786.pdf and +# https://github.com/adamws/oscca-sm3 +# Reformatted to work with the NIST loader +# SM3 + +Len = 0 +Msg = 00 +MD = 1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b + +Len = 8 +Msg = 61 +MD = 623476ac18f65a2909e43c7fec61b49c7e764a91a18ccb82f1917a29c86c5e88 + +# A.1. Example 1 +Len = 24 +Msg = 616263 +MD = 66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0 + +# A.1. Example 2 +Len = 208 +Msg = 6162636465666768696a6b6c6d6e6f707172737475767778797a +MD = b80fe97a4da24afc277564f66a359ef440462ad28dcc6d63adb24d5c20a61595 + +Len = 512 +Msg = 61626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364 +MD = debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732 + +Len = 2048 +Msg = 61626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364616263646162636461626364 +MD = b965764c8bebb091c7602b74afd34eefb531dccb4e0076d9b7cd813199b45971 From f69f27b1dd20ad2d24f48053a72545527e808104 Mon Sep 17 00:00:00 2001 From: tobyp Date: Sun, 28 Feb 2021 20:57:50 +0100 Subject: [PATCH 0063/1456] Add SM4 symmetric block cipher (#5834) Co-authored-by: Tobias Peter --- .../primitives/symmetric-encryption.rst | 15 +++ .../hazmat/backends/openssl/backend.py | 5 + .../hazmat/primitives/ciphers/algorithms.py | 13 +++ tests/hazmat/primitives/test_sm4.py | 99 +++++++++++++++++++ .../SM4/draft-ribose-cfrg-sm4-10-cbc.txt | 17 ++++ .../SM4/draft-ribose-cfrg-sm4-10-cfb.txt | 17 ++++ .../SM4/draft-ribose-cfrg-sm4-10-ctr.txt | 17 ++++ .../SM4/draft-ribose-cfrg-sm4-10-ecb.txt | 28 ++++++ .../SM4/draft-ribose-cfrg-sm4-10-ofb.txt | 17 ++++ 9 files changed, 228 insertions(+) create mode 100644 tests/hazmat/primitives/test_sm4.py create mode 100644 vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-cbc.txt create mode 100644 vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-cfb.txt create mode 100644 vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-ctr.txt create mode 100644 vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-ecb.txt create mode 100644 vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-ofb.txt diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index 8551acb2693f..6e10d67fef82 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -196,6 +196,19 @@ Algorithms :term:`bits` in length. :type key: :term:`bytes-like` +.. class:: SM4(key) + + .. versionadded:: 35.0.0 + + SM4 is a block cipher developed by the Chinese Government and standardized + in the `GB/T 32907-2016`_. It is used in the Chinese WAPI + (Wired Authentication and Privacy Infrastructure) standard. (An English + description is available at `draft-ribose-cfrg-sm4-10`_.) + + :param key: The secret key. This must be kept secret. ``128`` + :term:`bits` in length. + :type key: :term:`bytes-like` + Weak ciphers ------------ @@ -815,3 +828,5 @@ Exceptions .. _`International Data Encryption Algorithm`: https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm .. _`OpenPGP`: https://www.openpgp.org/ .. _`disk encryption`: https://en.wikipedia.org/wiki/Disk_encryption_theory#XTS +.. _`GB/T 32907-2016`: http://www.cnnic.cn/gcjsyj/qyjsyj/mmsfbz/sm4/201312/t20131204_43341.htm +.. _`draft-ribose-cfrg-sm4-10`: https://tools.ietf.org/html/draft-ribose-cfrg-sm4-10 diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 271873d92ad2..bb934094086a 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -135,6 +135,7 @@ ChaCha20, IDEA, SEED, + SM4, TripleDES, ) from cryptography.hazmat.primitives.ciphers.modes import ( @@ -411,6 +412,10 @@ def _register_default_ciphers(self): ChaCha20, type(None), GetCipherByName("chacha20") ) self.register_cipher_adapter(AES, XTS, _get_xts_cipher) + for mode_cls in [ECB, CBC, OFB, CFB, CTR]: + self.register_cipher_adapter( + SM4, mode_cls, GetCipherByName("sm4-{mode.name}") + ) def _register_x509_ext_parsers(self): ext_handlers = _EXTENSION_HANDLERS_BASE.copy() diff --git a/src/cryptography/hazmat/primitives/ciphers/algorithms.py b/src/cryptography/hazmat/primitives/ciphers/algorithms.py index b1c321941510..2fafa8ead883 100644 --- a/src/cryptography/hazmat/primitives/ciphers/algorithms.py +++ b/src/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -153,3 +153,16 @@ def nonce(self) -> bytes: @property def key_size(self) -> int: return len(self.key) * 8 + + +class SM4(CipherAlgorithm, BlockCipherAlgorithm): + name = "SM4" + block_size = 128 + key_sizes = frozenset([128]) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 diff --git a/tests/hazmat/primitives/test_sm4.py b/tests/hazmat/primitives/test_sm4.py new file mode 100644 index 000000000000..b7573443f791 --- /dev/null +++ b/tests/hazmat/primitives/test_sm4.py @@ -0,0 +1,99 @@ +# 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. + +import binascii +import os + +import pytest + +from cryptography.hazmat.backends.interfaces import CipherBackend +from cryptography.hazmat.primitives.ciphers import algorithms, modes + +from .utils import generate_encrypt_test +from ...utils import load_nist_vectors + + +@pytest.mark.supported( + only_if=lambda backend: backend.cipher_supported( + algorithms.SM4(b"\x00" * 16), modes.ECB() + ), + skip_message="Does not support SM4 ECB", +) +@pytest.mark.requires_backend_interface(interface=CipherBackend) +class TestSM4ModeECB(object): + test_ecb = generate_encrypt_test( + load_nist_vectors, + os.path.join("ciphers", "SM4"), + ["draft-ribose-cfrg-sm4-10-ecb.txt"], + lambda key, **kwargs: algorithms.SM4(binascii.unhexlify((key))), + lambda **kwargs: modes.ECB(), + ) + + +@pytest.mark.supported( + only_if=lambda backend: backend.cipher_supported( + algorithms.SM4(b"\x00" * 16), modes.CBC(b"\x00" * 16) + ), + skip_message="Does not support SM4 CBC", +) +@pytest.mark.requires_backend_interface(interface=CipherBackend) +class TestSM4ModeCBC(object): + test_cbc = generate_encrypt_test( + load_nist_vectors, + os.path.join("ciphers", "SM4"), + ["draft-ribose-cfrg-sm4-10-cbc.txt"], + lambda key, **kwargs: algorithms.SM4(binascii.unhexlify((key))), + lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)), + ) + + +@pytest.mark.supported( + only_if=lambda backend: backend.cipher_supported( + algorithms.SM4(b"\x00" * 16), modes.OFB(b"\x00" * 16) + ), + skip_message="Does not support SM4 OFB", +) +@pytest.mark.requires_backend_interface(interface=CipherBackend) +class TestSM4ModeOFB(object): + test_ofb = generate_encrypt_test( + load_nist_vectors, + os.path.join("ciphers", "SM4"), + ["draft-ribose-cfrg-sm4-10-ofb.txt"], + lambda key, **kwargs: algorithms.SM4(binascii.unhexlify((key))), + lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)), + ) + + +@pytest.mark.supported( + only_if=lambda backend: backend.cipher_supported( + algorithms.SM4(b"\x00" * 16), modes.CFB(b"\x00" * 16) + ), + skip_message="Does not support SM4 CFB", +) +@pytest.mark.requires_backend_interface(interface=CipherBackend) +class TestSM4ModeCFB(object): + test_cfb = generate_encrypt_test( + load_nist_vectors, + os.path.join("ciphers", "SM4"), + ["draft-ribose-cfrg-sm4-10-cfb.txt"], + lambda key, **kwargs: algorithms.SM4(binascii.unhexlify((key))), + lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)), + ) + + +@pytest.mark.supported( + only_if=lambda backend: backend.cipher_supported( + algorithms.SM4(b"\x00" * 16), modes.CTR(b"\x00" * 16) + ), + skip_message="Does not support SM4 CTR", +) +@pytest.mark.requires_backend_interface(interface=CipherBackend) +class TestSM4ModeCTR(object): + test_cfb = generate_encrypt_test( + load_nist_vectors, + os.path.join("ciphers", "SM4"), + ["draft-ribose-cfrg-sm4-10-ctr.txt"], + lambda key, **kwargs: algorithms.SM4(binascii.unhexlify((key))), + lambda iv, **kwargs: modes.CTR(binascii.unhexlify(iv)), + ) diff --git a/vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-cbc.txt b/vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-cbc.txt new file mode 100644 index 000000000000..49c5f8516803 --- /dev/null +++ b/vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-cbc.txt @@ -0,0 +1,17 @@ +# Vectors from draft-ribose-cfrg-sm4-10.txt. Reformatted to work with the NIST loader +# SM4 CBC +[ENCRYPT] + +# A.2.2.1 +COUNT = 0 +KEY = 0123456789abcdeffedcba9876543210 +PLAINTEXT = aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffaaaaaaaabbbbbbbb +IV = 000102030405060708090a0b0c0d0e0f +CIPHERTEXT = 78ebb11cc40b0a48312aaeb2040244cb4cb7016951909226979b0d15dc6a8f6d + +# A.2.2.2 +COUNT = 1 +KEY = fedcba98765432100123456789abcdef +PLAINTEXT = aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffaaaaaaaabbbbbbbb +IV = 000102030405060708090a0b0c0d0e0f +CIPHERTEXT = 0d3a6ddc2d21c698857215587b7bb59a91f2c147911a4144665e1fa1d40bae38 diff --git a/vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-cfb.txt b/vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-cfb.txt new file mode 100644 index 000000000000..4c2e4abf3706 --- /dev/null +++ b/vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-cfb.txt @@ -0,0 +1,17 @@ +# Vectors from draft-ribose-cfrg-sm4-10.txt. Reformatted to work with the NIST loader +# SM4 CFB +[ENCRYPT] + +# A.2.4.1 +COUNT = 0 +KEY = 0123456789abcdeffedcba9876543210 +PLAINTEXT = aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffaaaaaaaabbbbbbbb +IV = 000102030405060708090a0b0c0d0e0f +CIPHERTEXT = ac3236cb861dd316e6413b4e3c7524b769d4c54ed433b9a0346009beb37b2b3f + +# A.2.4.2 +COUNT = 1 +KEY = fedcba98765432100123456789abcdef +PLAINTEXT = aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffaaaaaaaabbbbbbbb +IV = 000102030405060708090a0b0c0d0e0f +CIPHERTEXT = 5dcccd25a84ba16560d7f265887068490d9b86ff20c3bfe115ffa02ca6192cc5 diff --git a/vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-ctr.txt b/vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-ctr.txt new file mode 100644 index 000000000000..0aea1572a8f6 --- /dev/null +++ b/vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-ctr.txt @@ -0,0 +1,17 @@ +# Vectors from draft-ribose-cfrg-sm4-10.txt. Reformatted to work with the NIST loader +# SM4 CTR +[ENCRYPT] + +# A.2.5.1 +COUNT = 0 +KEY = 0123456789abcdeffedcba9876543210 +PLAINTEXT = aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbccccccccccccccccddddddddddddddddeeeeeeeeeeeeeeeeffffffffffffffffaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb +IV = 000102030405060708090a0b0c0d0e0f +CIPHERTEXT = ac3236cb970cc20791364c395a1342d1a3cbc1878c6f30cd074cce385cdd70c7f234bc0e24c11980fd1286310ce37b926e02fcd0faa0baf38b2933851d824514 + +# A.2.5.2 +COUNT = 1 +KEY = fedcba98765432100123456789abcdef +PLAINTEXT = aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbccccccccccccccccddddddddddddddddeeeeeeeeeeeeeeeeffffffffffffffffaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb +IV = 000102030405060708090a0b0c0d0e0f +CIPHERTEXT = 5dcccd25b95ab07417a08512ee160e2f8f661521cbbab44cc87138445bc29e5c0ae0297205d62704173b21239b887f6c8cb5b800917a2488284bde9e16ea2906 diff --git a/vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-ecb.txt b/vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-ecb.txt new file mode 100644 index 000000000000..c9a6874228fe --- /dev/null +++ b/vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-ecb.txt @@ -0,0 +1,28 @@ +# Vectors from draft-ribose-cfrg-sm4-10.txt. Reformatted to work with the NIST loader +# Originally from GB/T 32907-2016 Example 1 +# SM4 ECB +[ENCRYPT] + +# A.1.1/A.1.2 +COUNT = 0 +KEY = 0123456789abcdeffedcba9876543210 +PLAINTEXT = 0123456789abcdeffedcba9876543210 +CIPHERTEXT = 681edf34d206965e86b3e94f536e4246 + +# A.1.4/A.1.5 +COUNT = 1 +KEY = fedcba98765432100123456789abcdef +PLAINTEXT = 000102030405060708090a0b0c0d0e0f +CIPHERTEXT = f766678f13f01adeac1b3ea955adb594 + +# A.2.1.1 +COUNT = 2 +KEY = 0123456789abcdeffedcba9876543210 +PLAINTEXT = aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffaaaaaaaabbbbbbbb +CIPHERTEXT = 5ec8143de509cff7b5179f8f474b86192f1d305a7fb17df985f81c8482192304 + +# A.2.1.2 +COUNT = 3 +KEY = fedcba98765432100123456789abcdef +PLAINTEXT = aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffaaaaaaaabbbbbbbb +CIPHERTEXT = c5876897e4a59bbba72a10c83872245b12dd90bc2d200692b529a4155ac9e600 diff --git a/vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-ofb.txt b/vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-ofb.txt new file mode 100644 index 000000000000..27c611d2a8f5 --- /dev/null +++ b/vectors/cryptography_vectors/ciphers/SM4/draft-ribose-cfrg-sm4-10-ofb.txt @@ -0,0 +1,17 @@ +# Vectors from draft-ribose-cfrg-sm4-10.txt. Reformatted to work with the NIST loader +# SM4 OFB +[ENCRYPT] + +# A.2.3.1 +COUNT = 0 +KEY = 0123456789abcdeffedcba9876543210 +PLAINTEXT = aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffaaaaaaaabbbbbbbb +IV = 000102030405060708090a0b0c0d0e0f +CIPHERTEXT = ac3236cb861dd316e6413b4e3c7524b71d01aca2487ca582cbf5463e6698539b + +# A.2.3.2 +COUNT = 1 +KEY = fedcba98765432100123456789abcdef +PLAINTEXT = aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffaaaaaaaabbbbbbbb +IV = 000102030405060708090a0b0c0d0e0f +CIPHERTEXT = 5dcccd25a84ba16560d7f2658870684933fa16bd5cd9c856cacaa1e101897a97 From bdca10e3f7c850a54bda9e9332b8df9493d0a8fa Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 28 Feb 2021 15:26:12 -0600 Subject: [PATCH 0064/1456] tell people SM3/SM4 are available for compat/compliance reasons (#5878) * tell people SM3/SM4 are available for compat/compliance reasons * add to changelog and linkcheck fix * tweaked language --- CHANGELOG.rst | 6 ++++++ docs/hazmat/primitives/cryptographic-hashes.rst | 3 ++- docs/hazmat/primitives/symmetric-encryption.rst | 7 ++++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8a7a663c76d8..f2aaebb5c27a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,12 @@ Changelog .. note:: This version is not yet released and is under active development. +* Added support for + :class:`~cryptography.hazmat.primitives.hashes.SM3` and + :class:`~cryptography.hazmat.primitives.ciphers.algorithms.SM4`, + when using OpenSSL 1.1.1. These algorithms are provided for compatibility + in regions where they may be required, and are not generally recommended. + .. _v3-4-6: 3.4.6 - 2021-02-16 diff --git a/docs/hazmat/primitives/cryptographic-hashes.rst b/docs/hazmat/primitives/cryptographic-hashes.rst index f79f8d7066cb..a113992513e3 100644 --- a/docs/hazmat/primitives/cryptographic-hashes.rst +++ b/docs/hazmat/primitives/cryptographic-hashes.rst @@ -255,7 +255,8 @@ SM3 SM3 is a cryptographic hash function standardized by the Chinese National Cryptography Administration in `GM/T 0004-2012`_. It produces 256-bit message digests. (An English description is available at - `draft-oscca-cfrg-sm3-02`_.) + `draft-oscca-cfrg-sm3-02`_.) This hash should be used for compatibility + purposes where required and is not otherwise recommended for use. Interfaces diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index 6e10d67fef82..985a9502c345 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -201,9 +201,11 @@ Algorithms .. versionadded:: 35.0.0 SM4 is a block cipher developed by the Chinese Government and standardized - in the `GB/T 32907-2016`_. It is used in the Chinese WAPI + in the GB/T 32907-2016. It is used in the Chinese WAPI (Wired Authentication and Privacy Infrastructure) standard. (An English - description is available at `draft-ribose-cfrg-sm4-10`_.) + description is available at `draft-ribose-cfrg-sm4-10`_.) This block + cipher should be used for compatibility purposes where required and is + not otherwise recommended for use. :param key: The secret key. This must be kept secret. ``128`` :term:`bits` in length. @@ -828,5 +830,4 @@ Exceptions .. _`International Data Encryption Algorithm`: https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm .. _`OpenPGP`: https://www.openpgp.org/ .. _`disk encryption`: https://en.wikipedia.org/wiki/Disk_encryption_theory#XTS -.. _`GB/T 32907-2016`: http://www.cnnic.cn/gcjsyj/qyjsyj/mmsfbz/sm4/201312/t20131204_43341.htm .. _`draft-ribose-cfrg-sm4-10`: https://tools.ietf.org/html/draft-ribose-cfrg-sm4-10 From e2449138c0bfce8ea82cad050be0e8355508ab43 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 28 Feb 2021 16:06:11 -0600 Subject: [PATCH 0065/1456] fix pkcs12 parse ordering. fixes #5872 (#5879) * fix pkcs12 parse ordering. fixes #5872 * remove an unneeded print * simplify the test a bit more * index * black * Update tests/hazmat/primitives/test_pkcs12.py Co-authored-by: Alex Gaynor Co-authored-by: Alex Gaynor --- .../hazmat/backends/openssl/backend.py | 8 +-- tests/hazmat/primitives/test_pkcs12.py | 58 ++++++++++++++++++- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index bb934094086a..9dc4ca059ca4 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -2524,7 +2524,9 @@ def load_key_and_certificates_from_pkcs12(self, data, password): 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): + # In OpenSSL < 3.0.0 PKCS12 parsing reverses the order of the + # certificates. + for i in reversed(range(num)): x509 = self._lib.sk_X509_value(sk_x509, i) self.openssl_assert(x509 != self._ffi.NULL) x509 = self._ffi.gc(x509, self._lib.X509_free) @@ -2567,9 +2569,7 @@ def serialize_key_and_certificates_to_pkcs12( sk_x509 = self._lib.sk_X509_new_null() sk_x509 = self._ffi.gc(sk_x509, self._lib.sk_X509_free) - # reverse the list when building the stack so that they're encoded - # in the order they were originally provided. it is a mystery - for ca in reversed(cas): + for ca in cas: res = self._lib.sk_X509_push(sk_x509, ca._x509) backend.openssl_assert(res >= 1) diff --git a/tests/hazmat/primitives/test_pkcs12.py b/tests/hazmat/primitives/test_pkcs12.py index b5de09f95ca4..b1759a1bc8ab 100644 --- a/tests/hazmat/primitives/test_pkcs12.py +++ b/tests/hazmat/primitives/test_pkcs12.py @@ -4,13 +4,15 @@ import os +from datetime import datetime import pytest from cryptography import x509 from cryptography.hazmat.backends.interfaces import DERSerializationBackend from cryptography.hazmat.backends.openssl.backend import _RC2 -from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.serialization import load_pem_private_key from cryptography.hazmat.primitives.serialization.pkcs12 import ( load_key_and_certificates, @@ -273,3 +275,57 @@ def test_generate_unsupported_encryption_type(self, backend): DummyKeySerializationEncryption(), ) assert str(exc.value) == "Unsupported key encryption type" + + +def test_pkcs12_ordering(): + """ + In OpenSSL < 3.0.0 PKCS12 parsing reverses the order. However, we + accidentally thought it was **encoding** that did it, leading to bug + https://github.com/pyca/cryptography/issues/5872 + This test ensures our ordering is correct going forward. + """ + + def make_cert(name): + key = ec.generate_private_key(ec.SECP256R1()) + subject = x509.Name( + [ + x509.NameAttribute(x509.NameOID.COMMON_NAME, name), + ] + ) + now = datetime.utcnow() + cert = ( + x509.CertificateBuilder() + .subject_name(subject) + .issuer_name(subject) + .public_key(key.public_key()) + .serial_number(x509.random_serial_number()) + .not_valid_before(now) + .not_valid_after(now) + .sign(key, hashes.SHA256()) + ) + return (key, cert) + + # Make some certificates with distinct names. + a_name = "A" * 20 + b_name = "B" * 20 + c_name = "C" * 20 + a_key, a_cert = make_cert(a_name) + _, b_cert = make_cert(b_name) + _, c_cert = make_cert(c_name) + + # Bundle them in a PKCS#12 file in order A, B, C. + p12 = serialize_key_and_certificates( + b"p12", a_key, a_cert, [b_cert, c_cert], serialization.NoEncryption() + ) + + # Parse them out. The API should report them in the same order. + (key, cert, certs) = load_key_and_certificates(p12, None) + assert cert == a_cert + assert certs == [b_cert, c_cert] + + # The ordering in the PKCS#12 file itself should also match. + a_idx = p12.index(a_name.encode("utf-8")) + b_idx = p12.index(b_name.encode("utf-8")) + c_idx = p12.index(c_name.encode("utf-8")) + + assert a_idx < b_idx < c_idx From 08c6484cd9534a2fc6a2accad17d1cc61d7ba764 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 28 Feb 2021 17:00:52 -0600 Subject: [PATCH 0066/1456] update ocsp docs to use sha256 (#5880) rfc 6960 suggests it and we want our docs to be best practice --- docs/x509/ocsp.rst | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/x509/ocsp.rst b/docs/x509/ocsp.rst index 6a3e1e7064f2..99864620d854 100644 --- a/docs/x509/ocsp.rst +++ b/docs/x509/ocsp.rst @@ -168,16 +168,19 @@ Creating Requests .. doctest:: >>> from cryptography.hazmat.primitives import serialization - >>> from cryptography.hazmat.primitives.hashes import SHA1 + >>> from cryptography.hazmat.primitives.hashes import SHA256 >>> from cryptography.x509 import load_pem_x509_certificate, ocsp >>> cert = load_pem_x509_certificate(pem_cert) >>> issuer = load_pem_x509_certificate(pem_issuer) >>> builder = ocsp.OCSPRequestBuilder() - >>> # SHA1 is in this example because RFC 5019 mandates its use. - >>> builder = builder.add_certificate(cert, issuer, SHA1()) + >>> # SHA256 is in this example because while RFC 5019 originally + >>> # required SHA1 RFC 6960 updates that to SHA256. + >>> # However, depending on your requirements you may need to use SHA1 + >>> # for compatibility reasons. + >>> builder = builder.add_certificate(cert, issuer, SHA256()) >>> req = builder.build() >>> base64.b64encode(req.public_bytes(serialization.Encoding.DER)) - b'MEMwQTA/MD0wOzAJBgUrDgMCGgUABBRAC0Z68eay0wmDug1gfn5ZN0gkxAQUw5zz/NNGCDS7zkZ/oHxb8+IIy1kCAj8g' + b'MF8wXTBbMFkwVzANBglghkgBZQMEAgEFAAQgn3BowBaoh77h17ULfkX6781dUDPD82Taj8wO1jZWhZoEINxPgjoQth3w7q4AouKKerMxIMIuUG4EuWU2pZfwih52AgI/IA==' Loading Responses ~~~~~~~~~~~~~~~~~ @@ -321,9 +324,12 @@ Creating Responses >>> responder_cert = load_pem_x509_certificate(pem_responder_cert) >>> responder_key = serialization.load_pem_private_key(pem_responder_key, None) >>> builder = ocsp.OCSPResponseBuilder() - >>> # SHA1 is in this example because RFC 5019 mandates its use. + >>> # SHA256 is in this example because while RFC 5019 originally + >>> # required SHA1 RFC 6960 updates that to SHA256. + >>> # However, depending on your requirements you may need to use SHA1 + >>> # for compatibility reasons. >>> builder = builder.add_response( - ... cert=cert, issuer=issuer, algorithm=hashes.SHA1(), + ... cert=cert, issuer=issuer, algorithm=hashes.SHA256(), ... cert_status=ocsp.OCSPCertStatus.GOOD, ... this_update=datetime.datetime.now(), ... next_update=datetime.datetime.now(), From 38381f63f61470128814f5daefa596c8ba3a0e09 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 28 Feb 2021 17:14:29 -0600 Subject: [PATCH 0067/1456] keep on typing (#5881) * keep on typing * swear i did this --- .../hazmat/primitives/twofactor/hotp.py | 33 +++++++++++++++- .../hazmat/primitives/twofactor/totp.py | 2 +- .../hazmat/primitives/twofactor/utils.py | 38 ------------------- 3 files changed, 33 insertions(+), 40 deletions(-) delete mode 100644 src/cryptography/hazmat/primitives/twofactor/utils.py diff --git a/src/cryptography/hazmat/primitives/twofactor/hotp.py b/src/cryptography/hazmat/primitives/twofactor/hotp.py index 01da4707b421..26e786fd4c37 100644 --- a/src/cryptography/hazmat/primitives/twofactor/hotp.py +++ b/src/cryptography/hazmat/primitives/twofactor/hotp.py @@ -3,8 +3,10 @@ # for complete details. +import base64 import struct import typing +from urllib.parse import quote, urlencode from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.hazmat.backends import _get_backend @@ -12,12 +14,41 @@ from cryptography.hazmat.primitives import constant_time, hmac from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512 from cryptography.hazmat.primitives.twofactor import InvalidToken -from cryptography.hazmat.primitives.twofactor.utils import _generate_uri _ALLOWED_HASH_TYPES = typing.Union[SHA1, SHA256, SHA512] +def _generate_uri( + hotp: "HOTP", + type_name: str, + account_name: str, + issuer: typing.Optional[str], + extra_parameters, +) -> str: + parameters = [ + ("digits", hotp._length), + ("secret", base64.b32encode(hotp._key)), + ("algorithm", hotp._algorithm.name.upper()), + ] + + if issuer is not None: + parameters.append(("issuer", issuer)) + + parameters.extend(extra_parameters) + + uriparts = { + "type": type_name, + "label": ( + "%s:%s" % (quote(issuer), quote(account_name)) + if issuer + else quote(account_name) + ), + "parameters": urlencode(parameters), + } + return "otpauth://{type}/{label}?{parameters}".format(**uriparts) + + class HOTP(object): def __init__( self, diff --git a/src/cryptography/hazmat/primitives/twofactor/totp.py b/src/cryptography/hazmat/primitives/twofactor/totp.py index 727891180489..92bf6496867d 100644 --- a/src/cryptography/hazmat/primitives/twofactor/totp.py +++ b/src/cryptography/hazmat/primitives/twofactor/totp.py @@ -12,8 +12,8 @@ from cryptography.hazmat.primitives.twofactor.hotp import ( HOTP, _ALLOWED_HASH_TYPES, + _generate_uri, ) -from cryptography.hazmat.primitives.twofactor.utils import _generate_uri class TOTP(object): diff --git a/src/cryptography/hazmat/primitives/twofactor/utils.py b/src/cryptography/hazmat/primitives/twofactor/utils.py deleted file mode 100644 index fcf40c8837cf..000000000000 --- a/src/cryptography/hazmat/primitives/twofactor/utils.py +++ /dev/null @@ -1,38 +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. - - -import base64 -import typing -from urllib.parse import quote, urlencode - - -def _generate_uri( - hotp, - type_name: str, - account_name: str, - issuer: typing.Optional[str], - extra_parameters, -) -> str: - parameters = [ - ("digits", hotp._length), - ("secret", base64.b32encode(hotp._key)), - ("algorithm", hotp._algorithm.name.upper()), - ] - - if issuer is not None: - parameters.append(("issuer", issuer)) - - parameters.extend(extra_parameters) - - uriparts = { - "type": type_name, - "label": ( - "%s:%s" % (quote(issuer), quote(account_name)) - if issuer - else quote(account_name) - ), - "parameters": urlencode(parameters), - } - return "otpauth://{type}/{label}?{parameters}".format(**uriparts) From ed1dea60795d6b0fd844a8da9a5e81569fff8eb3 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 28 Feb 2021 17:59:39 -0600 Subject: [PATCH 0068/1456] changes to support typing backend (#5882) this gets rid of the conditional backend type registration --- .../hazmat/backends/interfaces.py | 6 ++++ .../hazmat/backends/openssl/backend.py | 34 ++++++++++--------- tests/hazmat/primitives/test_scrypt.py | 4 +++ 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/cryptography/hazmat/backends/interfaces.py b/src/cryptography/hazmat/backends/interfaces.py index c5dfed3114c6..d5debb5426e0 100644 --- a/src/cryptography/hazmat/backends/interfaces.py +++ b/src/cryptography/hazmat/backends/interfaces.py @@ -378,3 +378,9 @@ def derive_scrypt(self, key_material, salt, length, n, r, p): """ Return bytes derived from provided Scrypt parameters. """ + + @abc.abstractmethod + def scrypt_supported(self): + """ + Return True if Scrypt is supported. + """ diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 9dc4ca059ca4..fb0070386505 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -161,22 +161,21 @@ class _RC2(object): pass -@utils.register_interface(CipherBackend) -@utils.register_interface(CMACBackend) -@utils.register_interface(DERSerializationBackend) -@utils.register_interface(DHBackend) -@utils.register_interface(DSABackend) -@utils.register_interface(EllipticCurveBackend) -@utils.register_interface(HashBackend) -@utils.register_interface(HMACBackend) -@utils.register_interface(PBKDF2HMACBackend) -@utils.register_interface(RSABackend) -@utils.register_interface(PEMSerializationBackend) -@utils.register_interface(X509Backend) -@utils.register_interface_if( - binding.Binding().lib.Cryptography_HAS_SCRYPT, ScryptBackend -) -class Backend(object): +class Backend( + CipherBackend, + CMACBackend, + DERSerializationBackend, + DHBackend, + DSABackend, + EllipticCurveBackend, + HashBackend, + HMACBackend, + PBKDF2HMACBackend, + RSABackend, + PEMSerializationBackend, + ScryptBackend, + X509Backend, +): """ OpenSSL API binding interfaces. """ @@ -343,6 +342,9 @@ def hash_supported(self, algorithm): evp_md = self._evp_md_from_algorithm(algorithm) return evp_md != self._ffi.NULL + def scrypt_supported(self): + return self._lib.Cryptography_HAS_SCRYPT == 1 + def hmac_supported(self, algorithm): return self.hash_supported(algorithm) diff --git a/tests/hazmat/primitives/test_scrypt.py b/tests/hazmat/primitives/test_scrypt.py index f6bbd0bcf295..d3fea28ca7c8 100644 --- a/tests/hazmat/primitives/test_scrypt.py +++ b/tests/hazmat/primitives/test_scrypt.py @@ -44,6 +44,10 @@ def test_memory_limit_skip(): _skip_if_memory_limited(2 ** 31, {"p": 16, "r": 64, "n": 1024}) +@pytest.mark.supported( + only_if=lambda backend: backend.scrypt_supported(), + skip_message="Does not support Scrypt", +) @pytest.mark.requires_backend_interface(interface=ScryptBackend) class TestScrypt(object): @pytest.mark.parametrize("params", vectors) From 245d15b5636392113af7db501196fd2930f776f8 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 1 Mar 2021 12:59:24 -0500 Subject: [PATCH 0069/1456] Remove requires_backend_interface from tests because it was useless (#5884) --- pyproject.toml | 1 - tests/conftest.py | 13 -- tests/hazmat/backends/test_openssl.py | 3 - tests/hazmat/primitives/test_3des.py | 6 - tests/hazmat/primitives/test_aead.py | 5 - tests/hazmat/primitives/test_aes.py | 9 -- tests/hazmat/primitives/test_aes_gcm.py | 2 - tests/hazmat/primitives/test_arc4.py | 2 - tests/hazmat/primitives/test_block.py | 5 - tests/hazmat/primitives/test_blowfish.py | 5 - tests/hazmat/primitives/test_camellia.py | 5 - tests/hazmat/primitives/test_cast5.py | 5 - tests/hazmat/primitives/test_chacha20.py | 2 - tests/hazmat/primitives/test_ciphers.py | 4 - tests/hazmat/primitives/test_cmac.py | 2 - tests/hazmat/primitives/test_concatkdf.py | 4 - tests/hazmat/primitives/test_dh.py | 15 --- tests/hazmat/primitives/test_dsa.py | 12 -- tests/hazmat/primitives/test_ec.py | 18 --- tests/hazmat/primitives/test_hash_vectors.py | 18 --- tests/hazmat/primitives/test_hashes.py | 12 -- tests/hazmat/primitives/test_hkdf.py | 3 - tests/hazmat/primitives/test_hkdf_vectors.py | 3 - tests/hazmat/primitives/test_hmac.py | 3 - tests/hazmat/primitives/test_hmac_vectors.py | 8 -- tests/hazmat/primitives/test_idea.py | 5 - tests/hazmat/primitives/test_kbkdf.py | 2 - tests/hazmat/primitives/test_kbkdf_vectors.py | 5 - tests/hazmat/primitives/test_keywrap.py | 3 - .../primitives/test_pbkdf2hmac_vectors.py | 2 - tests/hazmat/primitives/test_pkcs12.py | 2 - tests/hazmat/primitives/test_rsa.py | 17 --- tests/hazmat/primitives/test_scrypt.py | 2 - tests/hazmat/primitives/test_seed.py | 5 - tests/hazmat/primitives/test_serialization.py | 29 ----- tests/hazmat/primitives/test_sm4.py | 6 - tests/hazmat/primitives/test_x963_vectors.py | 2 - tests/hazmat/primitives/test_x963kdf.py | 2 - .../hazmat/primitives/twofactor/test_hotp.py | 2 - .../hazmat/primitives/twofactor/test_totp.py | 2 - tests/test_fernet.py | 5 - tests/wycheproof/test_aes.py | 5 - tests/wycheproof/test_chacha20poly1305.py | 2 - tests/wycheproof/test_cmac.py | 2 - tests/wycheproof/test_dsa.py | 2 - tests/wycheproof/test_ecdh.py | 3 - tests/wycheproof/test_ecdsa.py | 2 - tests/wycheproof/test_keywrap.py | 3 - tests/wycheproof/test_rsa.py | 4 - tests/x509/test_x509.py | 120 ------------------ tests/x509/test_x509_crlbuilder.py | 44 ------- tests/x509/test_x509_ext.py | 68 ---------- tests/x509/test_x509_revokedcertbuilder.py | 9 -- 53 files changed, 520 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ecd77063890c..2c90d97ae06c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,6 @@ target-version = ["py36"] [tool.pytest.ini_options] addopts = "-r s" markers = [ - "requires_backend_interface: this test requires a specific backend interface", "skip_fips: this test is not executed in FIPS mode", "supported: parametrized test requiring only_if and skip_message", "wycheproof_tests: this test runs a wycheproof fixture", diff --git a/tests/conftest.py b/tests/conftest.py index 43debdd61a85..2fea50c17b8f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -31,18 +31,5 @@ def pytest_runtest_setup(item): @pytest.fixture() def backend(request): - required_interfaces = [ - mark.kwargs["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: {}".format( - required_interfaces - ) - ) - check_backend_support(openssl_backend, request) return openssl_backend diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 4211b5d39128..e6abadbd099e 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -13,7 +13,6 @@ 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 Backend, backend from cryptography.hazmat.backends.openssl.ec import _sn_to_elliptic_curve from cryptography.hazmat.primitives import hashes, serialization @@ -566,7 +565,6 @@ def test_sn_to_elliptic_curve_not_supported(self): _sn_to_elliptic_curve(backend, b"fake") -@pytest.mark.requires_backend_interface(interface=RSABackend) class TestRSAPEMSerialization(object): def test_password_length_limit(self): password = b"x" * 1024 @@ -607,7 +605,6 @@ def test_numeric_string_x509_name_entry(self): backend._lib.Cryptography_HAS_EVP_PKEY_DHX == 1, reason="Requires OpenSSL without EVP_PKEY_DHX (< 1.0.2)", ) -@pytest.mark.requires_backend_interface(interface=DHBackend) class TestOpenSSLDHSerialization(object): @pytest.mark.parametrize( "vector", diff --git a/tests/hazmat/primitives/test_3des.py b/tests/hazmat/primitives/test_3des.py index f1bca78c0454..53c2080df0e1 100644 --- a/tests/hazmat/primitives/test_3des.py +++ b/tests/hazmat/primitives/test_3des.py @@ -12,7 +12,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import algorithms, modes from .utils import generate_encrypt_test @@ -25,7 +24,6 @@ ), skip_message="Does not support TripleDES CBC", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestTripleDESModeCBC(object): test_kat = generate_encrypt_test( load_nist_vectors, @@ -58,7 +56,6 @@ class TestTripleDESModeCBC(object): ), skip_message="Does not support TripleDES OFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestTripleDESModeOFB(object): test_kat = generate_encrypt_test( load_nist_vectors, @@ -91,7 +88,6 @@ class TestTripleDESModeOFB(object): ), skip_message="Does not support TripleDES CFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestTripleDESModeCFB(object): test_kat = generate_encrypt_test( load_nist_vectors, @@ -124,7 +120,6 @@ class TestTripleDESModeCFB(object): ), skip_message="Does not support TripleDES CFB8", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestTripleDESModeCFB8(object): test_kat = generate_encrypt_test( load_nist_vectors, @@ -157,7 +152,6 @@ class TestTripleDESModeCFB8(object): ), skip_message="Does not support TripleDES ECB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestTripleDESModeECB(object): test_kat = generate_encrypt_test( load_nist_vectors, diff --git a/tests/hazmat/primitives/test_aead.py b/tests/hazmat/primitives/test_aead.py index 87df06c6a8f0..e90308a07533 100644 --- a/tests/hazmat/primitives/test_aead.py +++ b/tests/hazmat/primitives/test_aead.py @@ -9,7 +9,6 @@ import pytest from cryptography.exceptions import InvalidTag, UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers.aead import ( AESCCM, AESGCM, @@ -42,7 +41,6 @@ def _aead_supported(cls): _aead_supported(ChaCha20Poly1305), reason="Requires OpenSSL without ChaCha20Poly1305 support", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) def test_chacha20poly1305_unsupported_on_older_openssl(backend): with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER): ChaCha20Poly1305(ChaCha20Poly1305.generate_key()) @@ -52,7 +50,6 @@ def test_chacha20poly1305_unsupported_on_older_openssl(backend): not _aead_supported(ChaCha20Poly1305), reason="Does not support ChaCha20Poly1305", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestChaCha20Poly1305(object): def test_data_too_large(self): key = ChaCha20Poly1305.generate_key() @@ -185,7 +182,6 @@ def test_buffer_protocol(self, backend): assert computed_pt2 == pt -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESCCM(object): def test_data_too_large(self): key = AESCCM.generate_key(128) @@ -359,7 +355,6 @@ def _load_gcm_vectors(): return [x for x in vectors if len(x["tag"]) == 32 and len(x["iv"]) >= 16] -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESGCM(object): def test_data_too_large(self): key = AESGCM.generate_key(128) diff --git a/tests/hazmat/primitives/test_aes.py b/tests/hazmat/primitives/test_aes.py index c9cb980037f8..29a9404633fb 100644 --- a/tests/hazmat/primitives/test_aes.py +++ b/tests/hazmat/primitives/test_aes.py @@ -8,7 +8,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import algorithms, base, modes from .utils import _load_all_params, generate_encrypt_test @@ -22,7 +21,6 @@ ), skip_message="Does not support AES XTS", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeXTS(object): def test_xts_vectors(self, backend, subtests): # This list comprehension excludes any vector that does not have a @@ -61,7 +59,6 @@ def test_xts_vectors(self, backend, subtests): ), skip_message="Does not support AES CBC", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeCBC(object): test_cbc = generate_encrypt_test( load_nist_vectors, @@ -94,7 +91,6 @@ class TestAESModeCBC(object): ), skip_message="Does not support AES ECB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeECB(object): test_ecb = generate_encrypt_test( load_nist_vectors, @@ -127,7 +123,6 @@ class TestAESModeECB(object): ), skip_message="Does not support AES OFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeOFB(object): test_ofb = generate_encrypt_test( load_nist_vectors, @@ -160,7 +155,6 @@ class TestAESModeOFB(object): ), skip_message="Does not support AES CFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeCFB(object): test_cfb = generate_encrypt_test( load_nist_vectors, @@ -193,7 +187,6 @@ class TestAESModeCFB(object): ), skip_message="Does not support AES CFB8", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeCFB8(object): test_cfb8 = generate_encrypt_test( load_nist_vectors, @@ -226,7 +219,6 @@ class TestAESModeCFB8(object): ), skip_message="Does not support AES CTR", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeCTR(object): test_ctr = generate_encrypt_test( load_nist_vectors, @@ -250,7 +242,6 @@ class TestAESModeCTR(object): DummyMode(), ], ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) def test_buffer_protocol_alternate_modes(mode, backend): data = bytearray(b"sixteen_byte_msg") key = algorithms.AES(bytearray(os.urandom(32))) diff --git a/tests/hazmat/primitives/test_aes_gcm.py b/tests/hazmat/primitives/test_aes_gcm.py index 77f9c6f2757c..bae213da82d9 100644 --- a/tests/hazmat/primitives/test_aes_gcm.py +++ b/tests/hazmat/primitives/test_aes_gcm.py @@ -8,7 +8,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import algorithms, base, modes from .utils import generate_aead_test @@ -21,7 +20,6 @@ ), skip_message="Does not support AES GCM", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeGCM(object): test_gcm = generate_aead_test( load_nist_vectors, diff --git a/tests/hazmat/primitives/test_arc4.py b/tests/hazmat/primitives/test_arc4.py index be40b578c398..61c7a82d9619 100644 --- a/tests/hazmat/primitives/test_arc4.py +++ b/tests/hazmat/primitives/test_arc4.py @@ -8,7 +8,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import algorithms from .utils import generate_stream_encryption_test @@ -21,7 +20,6 @@ ), skip_message="Does not support ARC4", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestARC4(object): test_rfc = generate_stream_encryption_test( load_nist_vectors, diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py index 1e01628ad7aa..135c2a0907ab 100644 --- a/tests/hazmat/primitives/test_block.py +++ b/tests/hazmat/primitives/test_block.py @@ -8,7 +8,6 @@ import pytest from cryptography.exceptions import AlreadyFinalized, _Reasons -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import ( Cipher, algorithms, @@ -24,7 +23,6 @@ from ...utils import raises_unsupported_algorithm -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCipher(object): def test_creates_encryptor(self, backend): cipher = Cipher( @@ -50,7 +48,6 @@ def test_instantiate_with_non_algorithm(self, backend): ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCipherContext(object): def test_use_after_finalize(self, backend): cipher = Cipher( @@ -134,7 +131,6 @@ def test_incorrectly_padded(self, backend): ), skip_message="Does not support AES GCM", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAEADCipherContext(object): test_aead_exceptions = generate_aead_exception_test( algorithms.AES, @@ -146,7 +142,6 @@ class TestAEADCipherContext(object): ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestModeValidation(object): def test_cbc(self, backend): with pytest.raises(ValueError): diff --git a/tests/hazmat/primitives/test_blowfish.py b/tests/hazmat/primitives/test_blowfish.py index ca0aaaa7848f..beb95062c1a3 100644 --- a/tests/hazmat/primitives/test_blowfish.py +++ b/tests/hazmat/primitives/test_blowfish.py @@ -8,7 +8,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import algorithms, modes from .utils import generate_encrypt_test @@ -21,7 +20,6 @@ ), skip_message="Does not support Blowfish ECB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestBlowfishModeECB(object): test_ecb = generate_encrypt_test( load_nist_vectors, @@ -38,7 +36,6 @@ class TestBlowfishModeECB(object): ), skip_message="Does not support Blowfish CBC", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestBlowfishModeCBC(object): test_cbc = generate_encrypt_test( load_nist_vectors, @@ -55,7 +52,6 @@ class TestBlowfishModeCBC(object): ), skip_message="Does not support Blowfish OFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestBlowfishModeOFB(object): test_ofb = generate_encrypt_test( load_nist_vectors, @@ -72,7 +68,6 @@ class TestBlowfishModeOFB(object): ), skip_message="Does not support Blowfish CFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestBlowfishModeCFB(object): test_cfb = generate_encrypt_test( load_nist_vectors, diff --git a/tests/hazmat/primitives/test_camellia.py b/tests/hazmat/primitives/test_camellia.py index f903c8156625..b783383d03e3 100644 --- a/tests/hazmat/primitives/test_camellia.py +++ b/tests/hazmat/primitives/test_camellia.py @@ -8,7 +8,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import algorithms, modes from .utils import generate_encrypt_test @@ -21,7 +20,6 @@ ), skip_message="Does not support Camellia ECB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCamelliaModeECB(object): test_ecb = generate_encrypt_test( load_cryptrec_vectors, @@ -42,7 +40,6 @@ class TestCamelliaModeECB(object): ), skip_message="Does not support Camellia CBC", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCamelliaModeCBC(object): test_cbc = generate_encrypt_test( load_nist_vectors, @@ -59,7 +56,6 @@ class TestCamelliaModeCBC(object): ), skip_message="Does not support Camellia OFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCamelliaModeOFB(object): test_ofb = generate_encrypt_test( load_nist_vectors, @@ -76,7 +72,6 @@ class TestCamelliaModeOFB(object): ), skip_message="Does not support Camellia CFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCamelliaModeCFB(object): test_cfb = generate_encrypt_test( load_nist_vectors, diff --git a/tests/hazmat/primitives/test_cast5.py b/tests/hazmat/primitives/test_cast5.py index 9b720594795a..093330bd7f78 100644 --- a/tests/hazmat/primitives/test_cast5.py +++ b/tests/hazmat/primitives/test_cast5.py @@ -8,7 +8,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import algorithms, modes from .utils import generate_encrypt_test @@ -21,7 +20,6 @@ ), skip_message="Does not support CAST5 ECB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCAST5ModeECB(object): test_ecb = generate_encrypt_test( load_nist_vectors, @@ -38,7 +36,6 @@ class TestCAST5ModeECB(object): ), skip_message="Does not support CAST5 CBC", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCAST5ModeCBC(object): test_cbc = generate_encrypt_test( load_nist_vectors, @@ -55,7 +52,6 @@ class TestCAST5ModeCBC(object): ), skip_message="Does not support CAST5 OFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCAST5ModeOFB(object): test_ofb = generate_encrypt_test( load_nist_vectors, @@ -72,7 +68,6 @@ class TestCAST5ModeOFB(object): ), skip_message="Does not support CAST5 CFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCAST5ModeCFB(object): test_cfb = generate_encrypt_test( load_nist_vectors, diff --git a/tests/hazmat/primitives/test_chacha20.py b/tests/hazmat/primitives/test_chacha20.py index 03165a4d1c32..72e63c376c15 100644 --- a/tests/hazmat/primitives/test_chacha20.py +++ b/tests/hazmat/primitives/test_chacha20.py @@ -9,7 +9,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import Cipher, algorithms from .utils import _load_all_params @@ -22,7 +21,6 @@ ), skip_message="Does not support ChaCha20", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestChaCha20(object): @pytest.mark.parametrize( "vector", diff --git a/tests/hazmat/primitives/test_ciphers.py b/tests/hazmat/primitives/test_ciphers.py index e82e3c26d995..f00282eccdeb 100644 --- a/tests/hazmat/primitives/test_ciphers.py +++ b/tests/hazmat/primitives/test_ciphers.py @@ -9,7 +9,6 @@ import pytest from cryptography.exceptions import AlreadyFinalized, _Reasons -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives import ciphers from cryptography.hazmat.primitives.ciphers import modes from cryptography.hazmat.primitives.ciphers.algorithms import ( @@ -49,7 +48,6 @@ def test_invalid_key_type(self): class TestAESXTS(object): - @pytest.mark.requires_backend_interface(interface=CipherBackend) @pytest.mark.parametrize( "mode", (modes.CBC, modes.CTR, modes.CFB, modes.CFB8, modes.OFB) ) @@ -65,7 +63,6 @@ def test_xts_tweak_too_small(self): with pytest.raises(ValueError): modes.XTS(b"0") - @pytest.mark.requires_backend_interface(interface=CipherBackend) def test_xts_wrong_key_size(self, backend): with pytest.raises(ValueError): ciphers.Cipher(AES(b"0" * 16), modes.XTS(b"0" * 16), backend) @@ -214,7 +211,6 @@ def test_invalid_backend(): ), skip_message="Does not support AES ECB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCipherUpdateInto(object): @pytest.mark.parametrize( "params", diff --git a/tests/hazmat/primitives/test_cmac.py b/tests/hazmat/primitives/test_cmac.py index 0022ab05c5e6..1c8841ac849e 100644 --- a/tests/hazmat/primitives/test_cmac.py +++ b/tests/hazmat/primitives/test_cmac.py @@ -12,7 +12,6 @@ InvalidSignature, _Reasons, ) -from cryptography.hazmat.backends.interfaces import CMACBackend from cryptography.hazmat.primitives.ciphers.algorithms import ( AES, ARC4, @@ -48,7 +47,6 @@ fake_key = b"\x00" * 16 -@pytest.mark.requires_backend_interface(interface=CMACBackend) class TestCMAC(object): @pytest.mark.supported( only_if=lambda backend: backend.cmac_algorithm_supported( diff --git a/tests/hazmat/primitives/test_concatkdf.py b/tests/hazmat/primitives/test_concatkdf.py index 8a6ee2e41200..18134eecac06 100644 --- a/tests/hazmat/primitives/test_concatkdf.py +++ b/tests/hazmat/primitives/test_concatkdf.py @@ -8,8 +8,6 @@ import pytest from cryptography.exceptions import AlreadyFinalized, InvalidKey, _Reasons -from cryptography.hazmat.backends.interfaces import HMACBackend -from cryptography.hazmat.backends.interfaces import HashBackend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.concatkdf import ConcatKDFHMAC from cryptography.hazmat.primitives.kdf.concatkdf import ConcatKDFHash @@ -17,7 +15,6 @@ from ...utils import raises_unsupported_algorithm -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestConcatKDFHash(object): def test_length_limit(self, backend): big_length = hashes.SHA256().digest_size * (2 ** 32 - 1) + 1 @@ -127,7 +124,6 @@ def test_unicode_typeerror(self, backend): ckdf.verify(b"foo", "bar") # type: ignore[arg-type] -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestConcatKDFHMAC(object): def test_length_limit(self, backend): big_length = hashes.SHA256().digest_size * (2 ** 32 - 1) + 1 diff --git a/tests/hazmat/primitives/test_dh.py b/tests/hazmat/primitives/test_dh.py index 131807fc0860..b37eca4eba54 100644 --- a/tests/hazmat/primitives/test_dh.py +++ b/tests/hazmat/primitives/test_dh.py @@ -10,11 +10,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import ( - DERSerializationBackend, - DHBackend, - PEMSerializationBackend, -) from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import dh @@ -140,7 +135,6 @@ def test_dh_public_numbers_equality(): assert public != object() -@pytest.mark.requires_backend_interface(interface=DHBackend) class TestDH(object): def test_small_key_generate_dh(self, backend): with pytest.raises(ValueError): @@ -440,9 +434,6 @@ def test_dh_vectors_with_q(self, backend, vector): assert int.from_bytes(symkey2, "big") == int(vector["z"], 16) -@pytest.mark.requires_backend_interface(interface=DHBackend) -@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) -@pytest.mark.requires_backend_interface(interface=DERSerializationBackend) class TestDHPrivateKeySerialization(object): @pytest.mark.parametrize( ("encoding", "loader_func"), @@ -630,9 +621,6 @@ def test_private_bytes_unsupported_encryption_type(self, backend): ) -@pytest.mark.requires_backend_interface(interface=DHBackend) -@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) -@pytest.mark.requires_backend_interface(interface=DERSerializationBackend) class TestDHPublicKeySerialization(object): @pytest.mark.parametrize( ("encoding", "loader_func"), @@ -759,9 +747,6 @@ def test_public_bytes_pkcs1_unsupported(self, backend): ) -@pytest.mark.requires_backend_interface(interface=DHBackend) -@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) -@pytest.mark.requires_backend_interface(interface=DERSerializationBackend) class TestDHParameterSerialization(object): @pytest.mark.parametrize( ("encoding", "loader_func"), diff --git a/tests/hazmat/primitives/test_dsa.py b/tests/hazmat/primitives/test_dsa.py index 6d8b2867fb81..066f83c4eca1 100644 --- a/tests/hazmat/primitives/test_dsa.py +++ b/tests/hazmat/primitives/test_dsa.py @@ -10,10 +10,6 @@ import pytest from cryptography.exceptions import AlreadyFinalized, InvalidSignature -from cryptography.hazmat.backends.interfaces import ( - DSABackend, - PEMSerializationBackend, -) from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import dsa from cryptography.hazmat.primitives.asymmetric.utils import ( @@ -49,13 +45,11 @@ def _skip_if_dsa_not_supported(backend, algorithm, p, q, g): ) -@pytest.mark.requires_backend_interface(interface=DSABackend) def test_skip_if_dsa_not_supported(backend): with pytest.raises(pytest.skip.Exception): _skip_if_dsa_not_supported(backend, DummyHashAlgorithm(), 1, 1, 1) -@pytest.mark.requires_backend_interface(interface=DSABackend) class TestDSA(object): def test_generate_dsa_parameters(self, backend): parameters = dsa.generate_parameters(2048, backend) @@ -385,7 +379,6 @@ def test_large_p(self, backend): ).private_key(backend) -@pytest.mark.requires_backend_interface(interface=DSABackend) class TestDSAVerification(object): def test_dsa_verification(self, backend, subtests): vectors = load_vectors_from_file( @@ -488,7 +481,6 @@ def test_prehashed_unsupported_in_verifier_ctx(self, backend): ) -@pytest.mark.requires_backend_interface(interface=DSABackend) class TestDSASignature(object): def test_dsa_signing(self, backend, subtests): vectors = load_vectors_from_file( @@ -693,8 +685,6 @@ def test_private_numbers_ne(self): assert priv != object() -@pytest.mark.requires_backend_interface(interface=DSABackend) -@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) class TestDSASerialization(object): @pytest.mark.parametrize( ("fmt", "password"), @@ -916,8 +906,6 @@ def test_private_bytes_unsupported_encryption_type(self, backend): ) -@pytest.mark.requires_backend_interface(interface=DSABackend) -@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) class TestDSAPEMPublicKeySerialization(object): @pytest.mark.parametrize( ("key_path", "loader_func", "encoding"), diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py index c089adc43c76..708395867b6b 100644 --- a/tests/hazmat/primitives/test_ec.py +++ b/tests/hazmat/primitives/test_ec.py @@ -12,10 +12,6 @@ import pytest from cryptography import exceptions, utils, x509 -from cryptography.hazmat.backends.interfaces import ( - EllipticCurveBackend, - PEMSerializationBackend, -) from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.asymmetric.utils import ( @@ -91,25 +87,21 @@ class DummySignatureAlgorithm(ec.EllipticCurveSignatureAlgorithm): algorithm = hashes.SHA256() -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_skip_curve_unsupported(backend): with pytest.raises(pytest.skip.Exception): _skip_curve_unsupported(backend, DummyCurve()) -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_skip_exchange_algorithm_unsupported(backend): with pytest.raises(pytest.skip.Exception): _skip_exchange_algorithm_unsupported(backend, ec.ECDH(), DummyCurve()) -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_skip_ecdsa_vector(backend): with pytest.raises(pytest.skip.Exception): _skip_ecdsa_vector(backend, DummyCurve, hashes.SHA256) -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_derive_private_key_success(backend): curve = ec.SECP256K1() _skip_curve_unsupported(backend, curve) @@ -123,7 +115,6 @@ def test_derive_private_key_success(backend): assert private_numbers == derived_key.private_numbers() -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_derive_private_key_errors(backend): curve = ec.SECP256K1() _skip_curve_unsupported(backend, curve) @@ -266,7 +257,6 @@ def test_ec_private_numbers_hash(): assert hash(numbers1) != hash(numbers3) -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_ec_key_key_size(backend): curve = ec.SECP256R1() _skip_curve_unsupported(backend, curve) @@ -275,7 +265,6 @@ def test_ec_key_key_size(backend): assert key.public_key().key_size == 256 -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) class TestECWithNumbers(object): def test_with_numbers(self, backend, subtests): vectors = itertools.product( @@ -310,7 +299,6 @@ def test_with_numbers(self, backend, subtests): assert curve_type().name == priv_num.public_numbers.curve.name -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) class TestECDSAVectors(object): def test_signing_with_example_keys(self, backend, subtests): vectors = itertools.product( @@ -666,8 +654,6 @@ def test_private_numbers_ne(self): assert priv != object() -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) -@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) class TestECSerialization(object): @pytest.mark.parametrize( ("fmt", "password"), @@ -924,8 +910,6 @@ def test_public_bytes_from_derived_public_key(self, backend): assert parsed_public -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) -@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) class TestEllipticCurvePEMPublicKeySerialization(object): @pytest.mark.parametrize( ("key_path", "loader_func", "encoding"), @@ -1178,7 +1162,6 @@ def test_serialize_point(self, vector, backend): ) -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) class TestECDSAVerification(object): def test_signature_not_bytes(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) @@ -1192,7 +1175,6 @@ def test_signature_not_bytes(self, backend): ) -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) class TestECDH(object): def test_key_exchange_with_vectors(self, backend, subtests): vectors = load_vectors_from_file( diff --git a/tests/hazmat/primitives/test_hash_vectors.py b/tests/hazmat/primitives/test_hash_vectors.py index 6b76f8db9550..be345563265d 100644 --- a/tests/hazmat/primitives/test_hash_vectors.py +++ b/tests/hazmat/primitives/test_hash_vectors.py @@ -8,7 +8,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import HashBackend from cryptography.hazmat.primitives import hashes from .utils import _load_all_params, generate_hash_test @@ -19,7 +18,6 @@ only_if=lambda backend: backend.hash_supported(hashes.SHA1()), skip_message="Does not support SHA1", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA1(object): test_sha1 = generate_hash_test( load_hash_vectors, @@ -33,7 +31,6 @@ class TestSHA1(object): only_if=lambda backend: backend.hash_supported(hashes.SHA224()), skip_message="Does not support SHA224", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA224(object): test_sha224 = generate_hash_test( load_hash_vectors, @@ -47,7 +44,6 @@ class TestSHA224(object): only_if=lambda backend: backend.hash_supported(hashes.SHA256()), skip_message="Does not support SHA256", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA256(object): test_sha256 = generate_hash_test( load_hash_vectors, @@ -61,7 +57,6 @@ class TestSHA256(object): only_if=lambda backend: backend.hash_supported(hashes.SHA384()), skip_message="Does not support SHA384", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA384(object): test_sha384 = generate_hash_test( load_hash_vectors, @@ -75,7 +70,6 @@ class TestSHA384(object): only_if=lambda backend: backend.hash_supported(hashes.SHA512()), skip_message="Does not support SHA512", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA512(object): test_sha512 = generate_hash_test( load_hash_vectors, @@ -89,7 +83,6 @@ class TestSHA512(object): 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, @@ -103,7 +96,6 @@ class TestSHA512224(object): 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, @@ -117,7 +109,6 @@ class TestSHA512256(object): only_if=lambda backend: backend.hash_supported(hashes.MD5()), skip_message="Does not support MD5", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestMD5(object): test_md5 = generate_hash_test( load_hash_vectors, @@ -133,7 +124,6 @@ class TestMD5(object): ), skip_message="Does not support BLAKE2b", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestBLAKE2b(object): test_b2b = generate_hash_test( load_hash_vectors, @@ -149,7 +139,6 @@ class TestBLAKE2b(object): ), skip_message="Does not support BLAKE2s", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestBLAKE2s256(object): test_b2s = generate_hash_test( load_hash_vectors, @@ -163,7 +152,6 @@ class TestBLAKE2s256(object): 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, @@ -177,7 +165,6 @@ class TestSHA3224(object): 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, @@ -191,7 +178,6 @@ class TestSHA3256(object): 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, @@ -205,7 +191,6 @@ class TestSHA3384(object): 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, @@ -221,7 +206,6 @@ class TestSHA3512(object): ), skip_message="Does not support SHAKE128", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHAKE128(object): test_shake128 = generate_hash_test( load_hash_vectors, @@ -252,7 +236,6 @@ def test_shake128_variable(self, backend, subtests): ), skip_message="Does not support SHAKE256", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHAKE256(object): test_shake256 = generate_hash_test( load_hash_vectors, @@ -281,7 +264,6 @@ def test_shake256_variable(self, backend, subtests): only_if=lambda backend: backend.hash_supported(hashes.SM3()), skip_message="Does not support SM3", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestSM3(object): test_sm3 = generate_hash_test( load_hash_vectors, diff --git a/tests/hazmat/primitives/test_hashes.py b/tests/hazmat/primitives/test_hashes.py index c0f5a9282c81..67de7947bb25 100644 --- a/tests/hazmat/primitives/test_hashes.py +++ b/tests/hazmat/primitives/test_hashes.py @@ -8,7 +8,6 @@ import pytest from cryptography.exceptions import AlreadyFinalized, _Reasons -from cryptography.hazmat.backends.interfaces import HashBackend from cryptography.hazmat.primitives import hashes from .utils import generate_base_hash_test @@ -16,7 +15,6 @@ from ...utils import raises_unsupported_algorithm -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestHashContext(object): def test_hash_reject_unicode(self, backend): m = hashes.Hash(hashes.SHA1(), backend=backend) @@ -49,7 +47,6 @@ def test_unsupported_hash(self, backend): only_if=lambda backend: backend.hash_supported(hashes.SHA1()), skip_message="Does not support SHA1", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA1(object): test_sha1 = generate_base_hash_test( hashes.SHA1(), @@ -61,7 +58,6 @@ class TestSHA1(object): only_if=lambda backend: backend.hash_supported(hashes.SHA224()), skip_message="Does not support SHA224", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA224(object): test_sha224 = generate_base_hash_test( hashes.SHA224(), @@ -73,7 +69,6 @@ class TestSHA224(object): only_if=lambda backend: backend.hash_supported(hashes.SHA256()), skip_message="Does not support SHA256", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA256(object): test_sha256 = generate_base_hash_test( hashes.SHA256(), @@ -85,7 +80,6 @@ class TestSHA256(object): only_if=lambda backend: backend.hash_supported(hashes.SHA384()), skip_message="Does not support SHA384", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA384(object): test_sha384 = generate_base_hash_test( hashes.SHA384(), @@ -97,7 +91,6 @@ class TestSHA384(object): only_if=lambda backend: backend.hash_supported(hashes.SHA512()), skip_message="Does not support SHA512", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA512(object): test_sha512 = generate_base_hash_test( hashes.SHA512(), @@ -109,7 +102,6 @@ class TestSHA512(object): only_if=lambda backend: backend.hash_supported(hashes.MD5()), skip_message="Does not support MD5", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestMD5(object): test_md5 = generate_base_hash_test( hashes.MD5(), @@ -123,7 +115,6 @@ class TestMD5(object): ), skip_message="Does not support BLAKE2b", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestBLAKE2b(object): test_blake2b = generate_base_hash_test( hashes.BLAKE2b(digest_size=64), @@ -147,7 +138,6 @@ def test_invalid_digest_size(self, backend): ), skip_message="Does not support BLAKE2s", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestBLAKE2s(object): test_blake2s = generate_base_hash_test( hashes.BLAKE2s(digest_size=32), @@ -172,7 +162,6 @@ def test_invalid_backend(): 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) @@ -201,7 +190,6 @@ def test_invalid_digest_size(self, xof): only_if=lambda backend: backend.hash_supported(hashes.SM3()), skip_message="Does not support SM3", ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestSM3(object): test_sm3 = generate_base_hash_test( hashes.SM3(), diff --git a/tests/hazmat/primitives/test_hkdf.py b/tests/hazmat/primitives/test_hkdf.py index 5ee6680b998e..80b27b9a9150 100644 --- a/tests/hazmat/primitives/test_hkdf.py +++ b/tests/hazmat/primitives/test_hkdf.py @@ -9,7 +9,6 @@ import pytest from cryptography.exceptions import AlreadyFinalized, InvalidKey, _Reasons -from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.hkdf import HKDF, HKDFExpand @@ -20,7 +19,6 @@ ) -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHKDF(object): def test_length_limit(self, backend): big_length = 255 * hashes.SHA256().digest_size + 1 @@ -138,7 +136,6 @@ def test_buffer_protocol(self, backend): assert hkdf.derive(ikm) == binascii.unhexlify(vector["okm"]) -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHKDFExpand(object): def test_derive(self, backend): prk = binascii.unhexlify( diff --git a/tests/hazmat/primitives/test_hkdf_vectors.py b/tests/hazmat/primitives/test_hkdf_vectors.py index 7561369436ad..f3df7594db75 100644 --- a/tests/hazmat/primitives/test_hkdf_vectors.py +++ b/tests/hazmat/primitives/test_hkdf_vectors.py @@ -7,7 +7,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import hashes from .utils import generate_hkdf_test @@ -18,7 +17,6 @@ only_if=lambda backend: backend.hmac_supported(hashes.SHA1()), skip_message="Does not support SHA1.", ) -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHKDFSHA1(object): test_hkdfsha1 = generate_hkdf_test( load_nist_vectors, @@ -32,7 +30,6 @@ class TestHKDFSHA1(object): only_if=lambda backend: backend.hmac_supported(hashes.SHA256()), skip_message="Does not support SHA256.", ) -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHKDFSHA256(object): test_hkdfsha256 = generate_hkdf_test( load_nist_vectors, diff --git a/tests/hazmat/primitives/test_hmac.py b/tests/hazmat/primitives/test_hmac.py index 0321eff94b1f..1cbd39c10538 100644 --- a/tests/hazmat/primitives/test_hmac.py +++ b/tests/hazmat/primitives/test_hmac.py @@ -12,7 +12,6 @@ InvalidSignature, _Reasons, ) -from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import hashes, hmac from .utils import generate_base_hmac_test @@ -24,14 +23,12 @@ only_if=lambda backend: backend.hmac_supported(hashes.MD5()), skip_message="Does not support MD5", ) -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHMACCopy(object): test_copy = generate_base_hmac_test( hashes.MD5(), ) -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHMAC(object): def test_hmac_reject_unicode(self, backend): h = hmac.HMAC(b"mykey", hashes.SHA1(), backend=backend) diff --git a/tests/hazmat/primitives/test_hmac_vectors.py b/tests/hazmat/primitives/test_hmac_vectors.py index fd2a4041dae1..808b17d196cb 100644 --- a/tests/hazmat/primitives/test_hmac_vectors.py +++ b/tests/hazmat/primitives/test_hmac_vectors.py @@ -7,7 +7,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import hashes, hmac from .utils import generate_hmac_test @@ -18,7 +17,6 @@ only_if=lambda backend: backend.hmac_supported(hashes.MD5()), skip_message="Does not support MD5", ) -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHMACMD5(object): test_hmac_md5 = generate_hmac_test( load_hash_vectors, @@ -32,7 +30,6 @@ class TestHMACMD5(object): only_if=lambda backend: backend.hmac_supported(hashes.SHA1()), skip_message="Does not support SHA1", ) -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHMACSHA1(object): test_hmac_sha1 = generate_hmac_test( load_hash_vectors, @@ -46,7 +43,6 @@ class TestHMACSHA1(object): only_if=lambda backend: backend.hmac_supported(hashes.SHA224()), skip_message="Does not support SHA224", ) -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHMACSHA224(object): test_hmac_sha224 = generate_hmac_test( load_hash_vectors, @@ -60,7 +56,6 @@ class TestHMACSHA224(object): only_if=lambda backend: backend.hmac_supported(hashes.SHA256()), skip_message="Does not support SHA256", ) -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHMACSHA256(object): test_hmac_sha256 = generate_hmac_test( load_hash_vectors, @@ -74,7 +69,6 @@ class TestHMACSHA256(object): only_if=lambda backend: backend.hmac_supported(hashes.SHA384()), skip_message="Does not support SHA384", ) -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHMACSHA384(object): test_hmac_sha384 = generate_hmac_test( load_hash_vectors, @@ -88,7 +82,6 @@ class TestHMACSHA384(object): only_if=lambda backend: backend.hmac_supported(hashes.SHA512()), skip_message="Does not support SHA512", ) -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHMACSHA512(object): test_hmac_sha512 = generate_hmac_test( load_hash_vectors, @@ -104,7 +97,6 @@ class TestHMACSHA512(object): ), skip_message="Does not support BLAKE2", ) -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHMACBLAKE2(object): def test_blake2b(self, backend): h = hmac.HMAC(b"0" * 64, hashes.BLAKE2b(digest_size=64), backend) diff --git a/tests/hazmat/primitives/test_idea.py b/tests/hazmat/primitives/test_idea.py index ea5dbb2f4188..4f98960a2a7d 100644 --- a/tests/hazmat/primitives/test_idea.py +++ b/tests/hazmat/primitives/test_idea.py @@ -8,7 +8,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import algorithms, modes from .utils import generate_encrypt_test @@ -21,7 +20,6 @@ ), skip_message="Does not support IDEA ECB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestIDEAModeECB(object): test_ecb = generate_encrypt_test( load_nist_vectors, @@ -38,7 +36,6 @@ class TestIDEAModeECB(object): ), skip_message="Does not support IDEA CBC", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestIDEAModeCBC(object): test_cbc = generate_encrypt_test( load_nist_vectors, @@ -55,7 +52,6 @@ class TestIDEAModeCBC(object): ), skip_message="Does not support IDEA OFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestIDEAModeOFB(object): test_ofb = generate_encrypt_test( load_nist_vectors, @@ -72,7 +68,6 @@ class TestIDEAModeOFB(object): ), skip_message="Does not support IDEA CFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestIDEAModeCFB(object): test_cfb = generate_encrypt_test( load_nist_vectors, diff --git a/tests/hazmat/primitives/test_kbkdf.py b/tests/hazmat/primitives/test_kbkdf.py index 2c94d18167bd..ddbf953b1323 100644 --- a/tests/hazmat/primitives/test_kbkdf.py +++ b/tests/hazmat/primitives/test_kbkdf.py @@ -6,7 +6,6 @@ import pytest from cryptography.exceptions import AlreadyFinalized, InvalidKey, _Reasons -from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.kbkdf import ( CounterLocation, @@ -18,7 +17,6 @@ from ...utils import raises_unsupported_algorithm -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestKBKDFHMAC(object): def test_invalid_key(self, backend): kdf = KBKDFHMAC( diff --git a/tests/hazmat/primitives/test_kbkdf_vectors.py b/tests/hazmat/primitives/test_kbkdf_vectors.py index 7545a85da7be..fffd28ad4b10 100644 --- a/tests/hazmat/primitives/test_kbkdf_vectors.py +++ b/tests/hazmat/primitives/test_kbkdf_vectors.py @@ -5,15 +5,10 @@ import os -import pytest - -from cryptography.hazmat.backends.interfaces import HMACBackend - from .utils import generate_kbkdf_counter_mode_test from ...utils import load_nist_kbkdf_vectors -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestCounterKDFCounterMode(object): test_kbkdfctr = generate_kbkdf_counter_mode_test( load_nist_kbkdf_vectors, diff --git a/tests/hazmat/primitives/test_keywrap.py b/tests/hazmat/primitives/test_keywrap.py index c5486fe1ee1c..e46ed7924ea8 100644 --- a/tests/hazmat/primitives/test_keywrap.py +++ b/tests/hazmat/primitives/test_keywrap.py @@ -8,7 +8,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives import keywrap from cryptography.hazmat.primitives.ciphers import algorithms, modes @@ -16,7 +15,6 @@ from ...utils import load_nist_vectors -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESKeyWrap(object): @pytest.mark.supported( only_if=lambda backend: backend.cipher_supported( @@ -124,7 +122,6 @@ def test_unwrap_invalid_wrapped_key_length(self, backend): 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): def test_wrap(self, backend, subtests): params = _load_all_params( diff --git a/tests/hazmat/primitives/test_pbkdf2hmac_vectors.py b/tests/hazmat/primitives/test_pbkdf2hmac_vectors.py index 6b02540284ff..255009de428c 100644 --- a/tests/hazmat/primitives/test_pbkdf2hmac_vectors.py +++ b/tests/hazmat/primitives/test_pbkdf2hmac_vectors.py @@ -5,7 +5,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import PBKDF2HMACBackend from cryptography.hazmat.primitives import hashes from .utils import generate_pbkdf2_test @@ -16,7 +15,6 @@ only_if=lambda backend: backend.pbkdf2_hmac_supported(hashes.SHA1()), skip_message="Does not support SHA1 for PBKDF2HMAC", ) -@pytest.mark.requires_backend_interface(interface=PBKDF2HMACBackend) class TestPBKDF2HMACSHA1(object): test_pbkdf2_sha1 = generate_pbkdf2_test( load_nist_vectors, diff --git a/tests/hazmat/primitives/test_pkcs12.py b/tests/hazmat/primitives/test_pkcs12.py index b1759a1bc8ab..f99c121d9554 100644 --- a/tests/hazmat/primitives/test_pkcs12.py +++ b/tests/hazmat/primitives/test_pkcs12.py @@ -9,7 +9,6 @@ import pytest from cryptography import x509 -from cryptography.hazmat.backends.interfaces import DERSerializationBackend from cryptography.hazmat.backends.openssl.backend import _RC2 from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ec @@ -23,7 +22,6 @@ from ...doubles import DummyKeySerializationEncryption -@pytest.mark.requires_backend_interface(interface=DERSerializationBackend) class TestPKCS12Loading(object): def _test_load_pkcs12_ec_keys(self, filename, password, backend): cert = load_vectors_from_file( diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 46f011f477dc..9c98dbbab2e7 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -14,10 +14,6 @@ InvalidSignature, _Reasons, ) -from cryptography.hazmat.backends.interfaces import ( - PEMSerializationBackend, - RSABackend, -) from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ( padding, @@ -138,7 +134,6 @@ def _skip_pss_hash_algorithm_unsupported(backend, hash_alg): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) def test_skip_pss_hash_algorithm_unsupported(backend): with pytest.raises(pytest.skip.Exception): _skip_pss_hash_algorithm_unsupported(backend, DummyHashAlgorithm()) @@ -168,7 +163,6 @@ def test_modular_inverse(): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) class TestRSA(object): @pytest.mark.parametrize( ("public_exponent", "key_size"), @@ -390,7 +384,6 @@ def test_rsa_generate_invalid_backend(): rsa.generate_private_key(65537, 2048, pretend_backend) -@pytest.mark.requires_backend_interface(interface=RSABackend) class TestRSASignature(object): @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -755,7 +748,6 @@ def test_corrupted_private_key(self, backend): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) class TestRSAVerification(object): @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -1212,7 +1204,6 @@ def test_prehashed_digest_mismatch(self, backend): public_key.verify(b"\x00" * 64, data, pkcs, prehashed_alg) -@pytest.mark.requires_backend_interface(interface=RSABackend) class TestRSAPSSMGF1Verification(object): test_rsa_pss_mgf1_sha1 = pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -1350,7 +1341,6 @@ class TestRSAPSSMGF1Verification(object): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) class TestRSAPKCS1Verification(object): test_rsa_pkcs1v15_verify_sha1 = pytest.mark.supported( only_if=lambda backend: ( @@ -1506,7 +1496,6 @@ def test_invalid_algorithm(self): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) class TestRSADecryption(object): @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -1750,7 +1739,6 @@ def test_unsupported_oaep_mgf(self, backend): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) class TestRSAEncryption(object): @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -1938,7 +1926,6 @@ def test_unsupported_oaep_mgf(self, backend): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) class TestRSANumbers(object): def test_rsa_public_numbers(self): public_numbers = rsa.RSAPublicNumbers(e=1, n=15) @@ -2160,8 +2147,6 @@ def test_invalid_recover_prime_factors(self): rsa.rsa_recover_prime_factors(34, 3, 7) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) class TestRSAPrivateKeySerialization(object): @pytest.mark.parametrize( ("fmt", "password"), @@ -2351,8 +2336,6 @@ def test_private_bytes_unsupported_encryption_type(self, backend): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) class TestRSAPEMPublicKeySerialization(object): @pytest.mark.parametrize( ("key_path", "loader_func", "encoding", "format"), diff --git a/tests/hazmat/primitives/test_scrypt.py b/tests/hazmat/primitives/test_scrypt.py index d3fea28ca7c8..63e6b35ced1f 100644 --- a/tests/hazmat/primitives/test_scrypt.py +++ b/tests/hazmat/primitives/test_scrypt.py @@ -13,7 +13,6 @@ InvalidKey, UnsupportedAlgorithm, ) -from cryptography.hazmat.backends.interfaces import ScryptBackend from cryptography.hazmat.primitives.kdf.scrypt import Scrypt, _MEM_LIMIT from tests.utils import load_nist_vectors, load_vectors_from_file @@ -48,7 +47,6 @@ def test_memory_limit_skip(): only_if=lambda backend: backend.scrypt_supported(), skip_message="Does not support Scrypt", ) -@pytest.mark.requires_backend_interface(interface=ScryptBackend) class TestScrypt(object): @pytest.mark.parametrize("params", vectors) def test_derive(self, backend, params): diff --git a/tests/hazmat/primitives/test_seed.py b/tests/hazmat/primitives/test_seed.py index e01aa0d8b45a..3225ddda5ac7 100644 --- a/tests/hazmat/primitives/test_seed.py +++ b/tests/hazmat/primitives/test_seed.py @@ -8,7 +8,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import algorithms, modes from .utils import generate_encrypt_test @@ -21,7 +20,6 @@ ), skip_message="Does not support SEED ECB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSEEDModeECB(object): test_ecb = generate_encrypt_test( load_nist_vectors, @@ -38,7 +36,6 @@ class TestSEEDModeECB(object): ), skip_message="Does not support SEED CBC", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSEEDModeCBC(object): test_cbc = generate_encrypt_test( load_nist_vectors, @@ -55,7 +52,6 @@ class TestSEEDModeCBC(object): ), skip_message="Does not support SEED OFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSEEDModeOFB(object): test_ofb = generate_encrypt_test( load_nist_vectors, @@ -72,7 +68,6 @@ class TestSEEDModeOFB(object): ), skip_message="Does not support SEED CFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSEEDModeCFB(object): test_cfb = generate_encrypt_test( load_nist_vectors, diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index ca969e031cfc..ed3f8e7f8f05 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -11,13 +11,6 @@ import pytest from cryptography.exceptions import UnsupportedAlgorithm -from cryptography.hazmat.backends.interfaces import ( - DERSerializationBackend, - DSABackend, - EllipticCurveBackend, - PEMSerializationBackend, - RSABackend, -) from cryptography.hazmat.primitives.asymmetric import ( dsa, ec, @@ -64,7 +57,6 @@ def _skip_fips_format(key_path, password, backend): class TestBufferProtocolSerialization(object): - @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.parametrize( ("key_path", "password"), [ @@ -85,7 +77,6 @@ def test_load_der_rsa_private_key(self, key_path, password, backend): 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"), [ @@ -115,9 +106,7 @@ def test_load_pem_rsa_private_key(self, key_path, password, backend): _check_rsa_private_numbers(key.private_numbers()) -@pytest.mark.requires_backend_interface(interface=DERSerializationBackend) class TestDERSerialization(object): - @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.parametrize( ("key_path", "password"), [ @@ -139,7 +128,6 @@ def test_load_der_rsa_private_key(self, key_path, password, backend): assert isinstance(key, rsa.RSAPrivateKey) _check_rsa_private_numbers(key.private_numbers()) - @pytest.mark.requires_backend_interface(interface=DSABackend) @pytest.mark.parametrize( ("key_path", "password"), [ @@ -164,7 +152,6 @@ def test_load_der_dsa_private_key(self, key_path, password, backend): @pytest.mark.parametrize( "key_path", [["DER_Serialization", "enc-rsa-pkcs8.der"]] ) - @pytest.mark.requires_backend_interface(interface=RSABackend) def test_password_not_bytes(self, key_path, backend): key_file = os.path.join("asymmetric", *key_path) password = "this password is not bytes" @@ -187,7 +174,6 @@ def test_password_not_bytes(self, key_path, backend): (["DER_Serialization", "ec_private_key_encrypted.der"], b"123456"), ], ) - @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_load_der_ec_private_key(self, key_path, password, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) key = load_vectors_from_file( @@ -206,7 +192,6 @@ def test_load_der_ec_private_key(self, key_path, password, backend): @pytest.mark.parametrize( "key_path", [["DER_Serialization", "enc-rsa-pkcs8.der"]] ) - @pytest.mark.requires_backend_interface(interface=RSABackend) def test_wrong_password(self, key_path, backend): key_file = os.path.join("asymmetric", *key_path) password = b"this password is wrong" @@ -223,7 +208,6 @@ def test_wrong_password(self, key_path, backend): @pytest.mark.parametrize( "key_path", [["DER_Serialization", "unenc-rsa-pkcs8.der"]] ) - @pytest.mark.requires_backend_interface(interface=RSABackend) def test_unused_password(self, key_path, backend): key_file = os.path.join("asymmetric", *key_path) password = b"this password will not be used" @@ -243,7 +227,6 @@ def test_unused_password(self, key_path, backend): [["DER_Serialization", "enc-rsa-pkcs8.der"]], [b"", None] ), ) - @pytest.mark.requires_backend_interface(interface=RSABackend) def test_missing_password(self, key_path, password, backend): key_file = os.path.join("asymmetric", *key_path) @@ -330,7 +313,6 @@ def test_corrupt_traditional_format_der(self, backend): os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.der"), ], ) - @pytest.mark.requires_backend_interface(interface=RSABackend) def test_load_der_rsa_public_key(self, key_file, backend): key = load_vectors_from_file( key_file, @@ -357,7 +339,6 @@ def test_load_der_invalid_public_key(self, backend): ), ], ) - @pytest.mark.requires_backend_interface(interface=DSABackend) def test_load_der_dsa_public_key(self, key_file, backend): key = load_vectors_from_file( key_file, @@ -367,7 +348,6 @@ def test_load_der_dsa_public_key(self, key_file, backend): assert key assert isinstance(key, dsa.DSAPublicKey) - @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_load_ec_public_key(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) key = load_vectors_from_file( @@ -389,7 +369,6 @@ def test_wrong_parameters_format(self, backend): load_der_parameters(param_data, backend) -@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) class TestPEMSerialization(object): @pytest.mark.parametrize( ("key_file", "password"), @@ -461,7 +440,6 @@ def test_load_dsa_private_key(self, key_path, password, backend): (["PEM_Serialization", "ec_private_key_encrypted.pem"], b"123456"), ], ) - @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_load_pem_ec_private_key(self, key_path, password, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) _skip_fips_format(key_path, password, backend) @@ -518,7 +496,6 @@ def test_load_pem_dsa_public_key(self, key_file, backend): assert key assert isinstance(key, dsa.DSAPublicKey) - @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_load_ec_public_key(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) key = load_vectors_from_file( @@ -976,7 +953,6 @@ def test_load_bad_encryption_oid_key(self, key_file, password, backend): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) class TestRSASSHSerialization(object): def test_load_ssh_public_key_unsupported(self, backend): ssh_key = b"ecdsa-sha2-junk AAAAE2VjZHNhLXNoYTItbmlzdHAyNTY=" @@ -1089,7 +1065,6 @@ def test_load_ssh_public_key_rsa(self, backend): assert numbers == expected -@pytest.mark.requires_backend_interface(interface=DSABackend) class TestDSSSSHSerialization(object): def test_load_ssh_public_key_dss_too_short(self, backend): ssh_key = b"ssh-dss" @@ -1203,7 +1178,6 @@ def test_load_ssh_public_key_dss(self, backend): assert numbers == expected -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) class TestECDSASSHSerialization(object): def test_load_ssh_public_key_ecdsa_nist_p256(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) @@ -1822,9 +1796,6 @@ def test_dh_private_key(self, backend): private_key.private_bytes(enc, fmt, NoEncryption()) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=DSABackend) -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) class TestOpenSSHSerialization(object): @pytest.mark.parametrize( ("key_file", "cert_file"), diff --git a/tests/hazmat/primitives/test_sm4.py b/tests/hazmat/primitives/test_sm4.py index b7573443f791..b5152d79858a 100644 --- a/tests/hazmat/primitives/test_sm4.py +++ b/tests/hazmat/primitives/test_sm4.py @@ -7,7 +7,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import algorithms, modes from .utils import generate_encrypt_test @@ -20,7 +19,6 @@ ), skip_message="Does not support SM4 ECB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSM4ModeECB(object): test_ecb = generate_encrypt_test( load_nist_vectors, @@ -37,7 +35,6 @@ class TestSM4ModeECB(object): ), skip_message="Does not support SM4 CBC", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSM4ModeCBC(object): test_cbc = generate_encrypt_test( load_nist_vectors, @@ -54,7 +51,6 @@ class TestSM4ModeCBC(object): ), skip_message="Does not support SM4 OFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSM4ModeOFB(object): test_ofb = generate_encrypt_test( load_nist_vectors, @@ -71,7 +67,6 @@ class TestSM4ModeOFB(object): ), skip_message="Does not support SM4 CFB", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSM4ModeCFB(object): test_cfb = generate_encrypt_test( load_nist_vectors, @@ -88,7 +83,6 @@ class TestSM4ModeCFB(object): ), skip_message="Does not support SM4 CTR", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSM4ModeCTR(object): test_cfb = generate_encrypt_test( load_nist_vectors, diff --git a/tests/hazmat/primitives/test_x963_vectors.py b/tests/hazmat/primitives/test_x963_vectors.py index ef3a186e1894..8006a9a040b6 100644 --- a/tests/hazmat/primitives/test_x963_vectors.py +++ b/tests/hazmat/primitives/test_x963_vectors.py @@ -9,7 +9,6 @@ import pytest -from cryptography.hazmat.backends.interfaces import HashBackend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.x963kdf import X963KDF @@ -26,7 +25,6 @@ def _skip_hashfn_unsupported(backend, hashfn): ) -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestX963(object): _algorithms_dict: typing.Dict[str, typing.Type[hashes.HashAlgorithm]] = { "SHA-1": hashes.SHA1, diff --git a/tests/hazmat/primitives/test_x963kdf.py b/tests/hazmat/primitives/test_x963kdf.py index 08c94db84645..5254aa006cb3 100644 --- a/tests/hazmat/primitives/test_x963kdf.py +++ b/tests/hazmat/primitives/test_x963kdf.py @@ -8,14 +8,12 @@ import pytest from cryptography.exceptions import AlreadyFinalized, InvalidKey, _Reasons -from cryptography.hazmat.backends.interfaces import HashBackend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.x963kdf import X963KDF from ...utils import raises_unsupported_algorithm -@pytest.mark.requires_backend_interface(interface=HashBackend) class TestX963KDF(object): def test_length_limit(self, backend): big_length = hashes.SHA256().digest_size * (2 ** 32 - 1) + 1 diff --git a/tests/hazmat/primitives/twofactor/test_hotp.py b/tests/hazmat/primitives/twofactor/test_hotp.py index 66c9b4ba0e43..979f3f004efc 100644 --- a/tests/hazmat/primitives/twofactor/test_hotp.py +++ b/tests/hazmat/primitives/twofactor/test_hotp.py @@ -8,7 +8,6 @@ import pytest from cryptography.exceptions import _Reasons -from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.hashes import MD5, SHA1 from cryptography.hazmat.primitives.twofactor import InvalidToken @@ -27,7 +26,6 @@ only_if=lambda backend: backend.hmac_supported(hashes.SHA1()), skip_message="Does not support HMAC-SHA1.", ) -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHOTP(object): def test_invalid_key_length(self, backend): secret = os.urandom(10) diff --git a/tests/hazmat/primitives/twofactor/test_totp.py b/tests/hazmat/primitives/twofactor/test_totp.py index 87c1e6144e9b..0159773399e2 100644 --- a/tests/hazmat/primitives/twofactor/test_totp.py +++ b/tests/hazmat/primitives/twofactor/test_totp.py @@ -6,7 +6,6 @@ import pytest from cryptography.exceptions import _Reasons -from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.twofactor import InvalidToken from cryptography.hazmat.primitives.twofactor.totp import TOTP @@ -20,7 +19,6 @@ vectors = load_vectors_from_file("twofactor/rfc-6238.txt", load_nist_vectors) -@pytest.mark.requires_backend_interface(interface=HMACBackend) class TestTOTP(object): @pytest.mark.supported( only_if=lambda backend: backend.hmac_supported(hashes.SHA1()), diff --git a/tests/test_fernet.py b/tests/test_fernet.py index fc21398834a8..a8a140e98266 100644 --- a/tests/test_fernet.py +++ b/tests/test_fernet.py @@ -17,7 +17,6 @@ from cryptography.fernet import Fernet, InvalidToken, MultiFernet from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.backends.interfaces import CipherBackend, HMACBackend from cryptography.hazmat.primitives.ciphers import algorithms, modes import cryptography_vectors @@ -39,8 +38,6 @@ def test_default_backend(): assert f._backend is default_backend() -@pytest.mark.requires_backend_interface(interface=CipherBackend) -@pytest.mark.requires_backend_interface(interface=HMACBackend) @pytest.mark.supported( only_if=lambda backend: backend.cipher_supported( algorithms.AES(b"\x00" * 32), modes.CBC(b"\x00" * 16) @@ -152,8 +149,6 @@ def test_extract_timestamp(self, monkeypatch, backend): f.extract_timestamp(b"nonsensetoken") -@pytest.mark.requires_backend_interface(interface=CipherBackend) -@pytest.mark.requires_backend_interface(interface=HMACBackend) @pytest.mark.supported( only_if=lambda backend: backend.cipher_supported( algorithms.AES(b"\x00" * 32), modes.CBC(b"\x00" * 16) diff --git a/tests/wycheproof/test_aes.py b/tests/wycheproof/test_aes.py index c041b47e15c4..891d8df4301b 100644 --- a/tests/wycheproof/test_aes.py +++ b/tests/wycheproof/test_aes.py @@ -8,7 +8,6 @@ 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 @@ -17,7 +16,6 @@ from ..hazmat.primitives.test_aead import _aead_supported -@pytest.mark.requires_backend_interface(interface=CipherBackend) @wycheproof_tests("aes_cbc_pkcs5_test.json") def test_aes_cbc_pkcs5(backend, wycheproof): key = binascii.unhexlify(wycheproof.testcase["key"]) @@ -45,7 +43,6 @@ def test_aes_cbc_pkcs5(backend, wycheproof): unpadder.update(padded_msg) + unpadder.finalize() -@pytest.mark.requires_backend_interface(interface=CipherBackend) @wycheproof_tests("aes_gcm_test.json") def test_aes_gcm(backend, wycheproof): key = binascii.unhexlify(wycheproof.testcase["key"]) @@ -90,7 +87,6 @@ def test_aes_gcm(backend, wycheproof): dec.finalize() -@pytest.mark.requires_backend_interface(interface=CipherBackend) @wycheproof_tests("aes_gcm_test.json") def test_aes_gcm_aead_api(backend, wycheproof): key = binascii.unhexlify(wycheproof.testcase["key"]) @@ -124,7 +120,6 @@ def test_aes_gcm_aead_api(backend, wycheproof): not _aead_supported(AESCCM), reason="Requires OpenSSL with AES-CCM support", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) @wycheproof_tests("aes_ccm_test.json") def test_aes_ccm_aead_api(backend, wycheproof): key = binascii.unhexlify(wycheproof.testcase["key"]) diff --git a/tests/wycheproof/test_chacha20poly1305.py b/tests/wycheproof/test_chacha20poly1305.py index 9c94c58f74d9..d36ea66a7750 100644 --- a/tests/wycheproof/test_chacha20poly1305.py +++ b/tests/wycheproof/test_chacha20poly1305.py @@ -8,7 +8,6 @@ import pytest from cryptography.exceptions import InvalidTag -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 from .utils import wycheproof_tests @@ -19,7 +18,6 @@ not _aead_supported(ChaCha20Poly1305), reason="Requires OpenSSL with ChaCha20Poly1305 support", ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) @wycheproof_tests("chacha20_poly1305_test.json") def test_chacha2poly1305(backend, wycheproof): key = binascii.unhexlify(wycheproof.testcase["key"]) diff --git a/tests/wycheproof/test_cmac.py b/tests/wycheproof/test_cmac.py index 21ce9af888f8..bca84805d7b9 100644 --- a/tests/wycheproof/test_cmac.py +++ b/tests/wycheproof/test_cmac.py @@ -8,14 +8,12 @@ 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 from .utils import wycheproof_tests -@pytest.mark.requires_backend_interface(interface=CMACBackend) @wycheproof_tests("aes_cmac_test.json") def test_aes_cmac(backend, wycheproof): key = binascii.unhexlify(wycheproof.testcase["key"]) diff --git a/tests/wycheproof/test_dsa.py b/tests/wycheproof/test_dsa.py index ac4647ef1b6f..3d31ee170dd5 100644 --- a/tests/wycheproof/test_dsa.py +++ b/tests/wycheproof/test_dsa.py @@ -8,7 +8,6 @@ import pytest from cryptography.exceptions import InvalidSignature -from cryptography.hazmat.backends.interfaces import DSABackend from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import dsa @@ -22,7 +21,6 @@ } -@pytest.mark.requires_backend_interface(interface=DSABackend) @wycheproof_tests( "dsa_test.json", "dsa_2048_224_sha224_test.json", diff --git a/tests/wycheproof/test_ecdh.py b/tests/wycheproof/test_ecdh.py index 510ec93373a9..02bf1182b0f6 100644 --- a/tests/wycheproof/test_ecdh.py +++ b/tests/wycheproof/test_ecdh.py @@ -8,7 +8,6 @@ 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 @@ -36,7 +35,6 @@ } -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) @wycheproof_tests( "ecdh_test.json", "ecdh_brainpoolP224r1_test.json", @@ -85,7 +83,6 @@ def test_ecdh(backend, wycheproof): private_key.exchange(ec.ECDH(), public_key) -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) @wycheproof_tests( "ecdh_secp224r1_ecpoint_test.json", "ecdh_secp256r1_ecpoint_test.json", diff --git a/tests/wycheproof/test_ecdsa.py b/tests/wycheproof/test_ecdsa.py index b7f252c6df82..2f7b7425b3d9 100644 --- a/tests/wycheproof/test_ecdsa.py +++ b/tests/wycheproof/test_ecdsa.py @@ -8,7 +8,6 @@ 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 @@ -28,7 +27,6 @@ } -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) @wycheproof_tests( "ecdsa_test.json", "ecdsa_brainpoolP224r1_sha224_test.json", diff --git a/tests/wycheproof/test_keywrap.py b/tests/wycheproof/test_keywrap.py index 6a8cfd08bc69..7aec26989b20 100644 --- a/tests/wycheproof/test_keywrap.py +++ b/tests/wycheproof/test_keywrap.py @@ -7,13 +7,11 @@ import pytest -from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives import keywrap from .utils import wycheproof_tests -@pytest.mark.requires_backend_interface(interface=CipherBackend) @wycheproof_tests("kwp_test.json") def test_keywrap_with_padding(backend, wycheproof): wrapping_key = binascii.unhexlify(wycheproof.testcase["key"]) @@ -38,7 +36,6 @@ def test_keywrap_with_padding(backend, wycheproof): ) -@pytest.mark.requires_backend_interface(interface=CipherBackend) @wycheproof_tests("kw_test.json") def test_keywrap(backend, wycheproof): wrapping_key = binascii.unhexlify(wycheproof.testcase["key"]) diff --git a/tests/wycheproof/test_rsa.py b/tests/wycheproof/test_rsa.py index 0b0983da3590..73ff711154d9 100644 --- a/tests/wycheproof/test_rsa.py +++ b/tests/wycheproof/test_rsa.py @@ -8,7 +8,6 @@ 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, rsa @@ -41,7 +40,6 @@ def should_verify(backend, wycheproof): return False -@pytest.mark.requires_backend_interface(interface=RSABackend) @wycheproof_tests( "rsa_signature_test.json", "rsa_signature_2048_sha224_test.json", @@ -113,7 +111,6 @@ def test_rsa_pkcs1v15_signature_generation(backend, wycheproof): assert sig == binascii.unhexlify(wycheproof.testcase["sig"]) -@pytest.mark.requires_backend_interface(interface=RSABackend) @wycheproof_tests( "rsa_pss_2048_sha1_mgf1_20_test.json", "rsa_pss_2048_sha256_mgf1_0_test.json", @@ -164,7 +161,6 @@ def test_rsa_pss_signature(backend, wycheproof): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) @wycheproof_tests( "rsa_oaep_2048_sha1_mgf1sha1_test.json", "rsa_oaep_2048_sha224_mgf1sha1_test.json", diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 3acb3ef9c3dc..87b6b29e6fdb 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -30,12 +30,6 @@ SET, UTC_TIME, ) -from cryptography.hazmat.backends.interfaces import ( - DSABackend, - EllipticCurveBackend, - RSABackend, - X509Backend, -) from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ( dh, @@ -134,7 +128,6 @@ def _parse_cert(der): ) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestCertificateRevocationList(object): def test_load_pem_crl(self, backend): crl = _load_cert( @@ -484,7 +477,6 @@ def test_verify_argument_must_be_a_public_key(self, backend): crl.is_signature_valid(object) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestRevokedCertificate(object): def test_revoked_basics(self, backend): crl = _load_cert( @@ -672,8 +664,6 @@ def test_get_revoked_certificate_doesnt_reorder(self, backend): assert crl[2].serial_number == 3 -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestRSACertificate(object): def test_load_pem_cert(self, backend): cert = _load_cert( @@ -1247,8 +1237,6 @@ def test_parse_tls_feature_extension(self, backend): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestRSACertificateRequest(object): @pytest.mark.parametrize( ("path", "loader_func"), @@ -1822,8 +1810,6 @@ def read_next_rdn_value_tag(reader): class TestCertificateBuilder(object): - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_checks_for_unsupported_extensions(self, backend): private_key = RSA_KEY_2048.private_key(backend) builder = ( @@ -1844,8 +1830,6 @@ def test_checks_for_unsupported_extensions(self, backend): with pytest.raises(NotImplementedError): builder.sign(private_key, hashes.SHA1(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_encode_nonstandard_aia(self, backend): private_key = RSA_KEY_2048.private_key(backend) @@ -1875,8 +1859,6 @@ def test_encode_nonstandard_aia(self, backend): builder.sign(private_key, hashes.SHA256(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_encode_nonstandard_sia(self, backend): private_key = RSA_KEY_2048.private_key(backend) @@ -1910,8 +1892,6 @@ def test_encode_nonstandard_sia(self, backend): ) assert ext.value == sia - @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) @@ -1969,8 +1949,6 @@ def test_subject_dn_asn1_types(self, backend): [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_extreme_times(self, not_valid_before, not_valid_after, backend): private_key = RSA_KEY_2048.private_key(backend) builder = ( @@ -1993,8 +1971,6 @@ def test_extreme_times(self, not_valid_before, not_valid_after, backend): assert parsed.not_before_tag == UTC_TIME assert parsed.not_after_tag == GENERALIZED_TIME - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_subject_name(self, backend): subject_private_key = RSA_KEY_2048.private_key(backend) builder = ( @@ -2010,8 +1986,6 @@ def test_no_subject_name(self, backend): with pytest.raises(ValueError): builder.sign(subject_private_key, hashes.SHA256(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_issuer_name(self, backend): subject_private_key = RSA_KEY_2048.private_key(backend) builder = ( @@ -2027,8 +2001,6 @@ def test_no_issuer_name(self, backend): with pytest.raises(ValueError): builder.sign(subject_private_key, hashes.SHA256(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_public_key(self, backend): subject_private_key = RSA_KEY_2048.private_key(backend) builder = ( @@ -2046,8 +2018,6 @@ def test_no_public_key(self, backend): with pytest.raises(ValueError): builder.sign(subject_private_key, hashes.SHA256(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_not_valid_before(self, backend): subject_private_key = RSA_KEY_2048.private_key(backend) builder = ( @@ -2065,8 +2035,6 @@ def test_no_not_valid_before(self, backend): with pytest.raises(ValueError): builder.sign(subject_private_key, hashes.SHA256(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_not_valid_after(self, backend): subject_private_key = RSA_KEY_2048.private_key(backend) builder = ( @@ -2084,8 +2052,6 @@ def test_no_not_valid_after(self, backend): with pytest.raises(ValueError): builder.sign(subject_private_key, hashes.SHA256(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_serial_number(self, backend): subject_private_key = RSA_KEY_2048.private_key(backend) builder = ( @@ -2151,8 +2117,6 @@ def test_not_valid_after_before_not_valid_before(self): with pytest.raises(ValueError): builder.not_valid_after(datetime.datetime(2001, 1, 1, 12, 1)) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_public_key_must_be_public_key(self, backend): private_key = RSA_KEY_2048.private_key(backend) builder = x509.CertificateBuilder() @@ -2160,8 +2124,6 @@ def test_public_key_must_be_public_key(self, backend): with pytest.raises(TypeError): builder.public_key(private_key) # type: ignore[arg-type] - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_public_key_may_only_be_set_once(self, backend): private_key = RSA_KEY_2048.private_key(backend) public_key = private_key.public_key() @@ -2184,8 +2146,6 @@ def test_serial_number_must_be_positive(self): with pytest.raises(ValueError): x509.CertificateBuilder().serial_number(0) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_minimal_serial_number(self, backend): subject_private_key = RSA_KEY_2048.private_key(backend) builder = ( @@ -2204,8 +2164,6 @@ def test_minimal_serial_number(self, backend): cert = builder.sign(subject_private_key, hashes.SHA256(), backend) assert cert.serial_number == 1 - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_biggest_serial_number(self, backend): subject_private_key = RSA_KEY_2048.private_key(backend) builder = ( @@ -2234,8 +2192,6 @@ def test_serial_number_may_only_be_set_once(self): with pytest.raises(ValueError): builder.serial_number(20) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_aware_not_valid_after(self, backend): time = datetime.datetime(2012, 1, 16, 22, 43) tz = pytz.timezone("US/Pacific") @@ -2258,8 +2214,6 @@ def test_aware_not_valid_after(self, backend): 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) @@ -2307,8 +2261,6 @@ def test_not_valid_after_may_only_be_set_once(self): with pytest.raises(ValueError): builder.not_valid_after(datetime.datetime.now()) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_aware_not_valid_before(self, backend): time = datetime.datetime(2012, 1, 16, 22, 43) tz = pytz.timezone("US/Pacific") @@ -2376,8 +2328,6 @@ def test_add_invalid_extension_type(self): False, ) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) @pytest.mark.parametrize("algorithm", [object(), None]) def test_sign_with_unsupported_hash(self, algorithm, backend): private_key = RSA_KEY_2048.private_key(backend) @@ -2402,7 +2352,6 @@ def test_sign_with_unsupported_hash(self, algorithm, backend): only_if=lambda backend: backend.ed25519_supported(), skip_message="Requires OpenSSL with Ed25519 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_with_unsupported_hash_ed25519(self, backend): private_key = ed25519.Ed25519PrivateKey.generate() builder = ( @@ -2426,7 +2375,6 @@ def test_sign_with_unsupported_hash_ed25519(self, backend): only_if=lambda backend: backend.ed448_supported(), skip_message="Requires OpenSSL with Ed448 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_with_unsupported_hash_ed448(self, backend): private_key = ed448.Ed448PrivateKey.generate() builder = ( @@ -2446,8 +2394,6 @@ def test_sign_with_unsupported_hash_ed448(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) @pytest.mark.supported( only_if=lambda backend: backend.hash_supported(hashes.MD5()), skip_message="Requires OpenSSL with MD5 support", @@ -2470,8 +2416,6 @@ def test_sign_rsa_with_md5(self, backend): cert = builder.sign(private_key, hashes.MD5(), backend) assert isinstance(cert.signature_hash_algorithm, hashes.MD5) - @pytest.mark.requires_backend_interface(interface=DSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) @pytest.mark.supported( only_if=lambda backend: backend.hash_supported(hashes.MD5()), skip_message="Requires OpenSSL with MD5 support", @@ -2494,8 +2438,6 @@ def test_sign_dsa_with_md5(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.MD5(), backend) - @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) @pytest.mark.supported( only_if=lambda backend: backend.hash_supported(hashes.MD5()), skip_message="Requires OpenSSL with MD5 support", @@ -2519,8 +2461,6 @@ def test_sign_ec_with_md5(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.MD5(), backend) - @pytest.mark.requires_backend_interface(interface=DSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_build_cert_with_dsa_private_key(self, backend): issuer_private_key = DSA_KEY_2048.private_key(backend) subject_private_key = DSA_KEY_2048.private_key(backend) @@ -2567,8 +2507,6 @@ def test_build_cert_with_dsa_private_key(self, backend): x509.DNSName("cryptography.io"), ] - @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_build_cert_with_ec_private_key(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) issuer_private_key = ec.generate_private_key(ec.SECP256R1(), backend) @@ -2620,7 +2558,6 @@ def test_build_cert_with_ec_private_key(self, backend): only_if=lambda backend: backend.ed25519_supported(), skip_message="Requires OpenSSL with Ed25519 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_build_cert_with_ed25519(self, backend): issuer_private_key = ed25519.Ed25519PrivateKey.generate() subject_private_key = ed25519.Ed25519PrivateKey.generate() @@ -2676,8 +2613,6 @@ def test_build_cert_with_ed25519(self, backend): only_if=lambda backend: backend.ed25519_supported(), skip_message="Requires OpenSSL with Ed25519 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) def test_build_cert_with_public_ed25519_rsa_sig(self, backend): issuer_private_key = RSA_KEY_2048.private_key(backend) subject_private_key = ed25519.Ed25519PrivateKey.generate() @@ -2716,7 +2651,6 @@ def test_build_cert_with_public_ed25519_rsa_sig(self, backend): only_if=lambda backend: backend.ed448_supported(), skip_message="Requires OpenSSL with Ed448 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_build_cert_with_ed448(self, backend): issuer_private_key = ed448.Ed448PrivateKey.generate() subject_private_key = ed448.Ed448PrivateKey.generate() @@ -2772,8 +2706,6 @@ def test_build_cert_with_ed448(self, backend): only_if=lambda backend: backend.ed448_supported(), skip_message="Requires OpenSSL with Ed448 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) def test_build_cert_with_public_ed448_rsa_sig(self, backend): issuer_private_key = RSA_KEY_2048.private_key(backend) subject_private_key = ed448.Ed448PrivateKey.generate() @@ -2808,8 +2740,6 @@ def test_build_cert_with_public_ed448_rsa_sig(self, backend): assert isinstance(cert.signature_hash_algorithm, hashes.SHA256) assert isinstance(cert.public_key(), ed448.Ed448PublicKey) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_build_cert_with_rsa_key_too_small(self, backend): issuer_private_key = RSA_KEY_512.private_key(backend) subject_private_key = RSA_KEY_512.private_key(backend) @@ -2834,8 +2764,6 @@ def test_build_cert_with_rsa_key_too_small(self, backend): with pytest.raises(ValueError): builder.sign(issuer_private_key, hashes.SHA512(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) @pytest.mark.parametrize( "add_ext", [ @@ -3228,8 +3156,6 @@ def test_ext(self, add_ext, backend): assert ext.critical is False assert ext.value == add_ext - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_key_usage(self, backend): issuer_private_key = RSA_KEY_2048.private_key(backend) subject_private_key = RSA_KEY_2048.private_key(backend) @@ -3280,8 +3206,6 @@ def test_key_usage(self, backend): decipher_only=False, ) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_build_ca_request_with_path_length_none(self, backend): private_key = RSA_KEY_2048.private_key(backend) @@ -3317,8 +3241,6 @@ def test_build_ca_request_with_path_length_none(self, backend): ) ], ) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_unrecognized_extension(self, backend, unrecognized): private_key = RSA_KEY_2048.private_key(backend) @@ -3343,9 +3265,7 @@ def test_unrecognized_extension(self, backend, unrecognized): assert ext.value == unrecognized -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestCertificateSigningRequestBuilder(object): - @pytest.mark.requires_backend_interface(interface=RSABackend) def test_sign_invalid_hash_algorithm(self, backend): private_key = RSA_KEY_2048.private_key(backend) @@ -3359,7 +3279,6 @@ def test_sign_invalid_hash_algorithm(self, backend): only_if=lambda backend: backend.ed25519_supported(), skip_message="Requires OpenSSL with Ed25519 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_request_with_unsupported_hash_ed25519(self, backend): private_key = ed25519.Ed25519PrivateKey.generate() builder = x509.CertificateSigningRequestBuilder().subject_name( @@ -3373,7 +3292,6 @@ def test_request_with_unsupported_hash_ed25519(self, backend): only_if=lambda backend: backend.ed448_supported(), skip_message="Requires OpenSSL with Ed448 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_request_with_unsupported_hash_ed448(self, backend): private_key = ed448.Ed448PrivateKey.generate() builder = x509.CertificateSigningRequestBuilder().subject_name( @@ -3383,7 +3301,6 @@ def test_request_with_unsupported_hash_ed448(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.supported( only_if=lambda backend: backend.hash_supported(hashes.MD5()), skip_message="Requires OpenSSL with MD5 support", @@ -3397,7 +3314,6 @@ def test_sign_rsa_with_md5(self, backend): request = builder.sign(private_key, hashes.MD5(), backend) assert isinstance(request.signature_hash_algorithm, hashes.MD5) - @pytest.mark.requires_backend_interface(interface=DSABackend) @pytest.mark.supported( only_if=lambda backend: backend.hash_supported(hashes.MD5()), skip_message="Requires OpenSSL with MD5 support", @@ -3410,7 +3326,6 @@ def test_sign_dsa_with_md5(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.MD5(), backend) - @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) @pytest.mark.supported( only_if=lambda backend: backend.hash_supported(hashes.MD5()), skip_message="Requires OpenSSL with MD5 support", @@ -3424,7 +3339,6 @@ def test_sign_ec_with_md5(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.MD5(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) def test_no_subject_name(self, backend): private_key = RSA_KEY_2048.private_key(backend) @@ -3432,7 +3346,6 @@ def test_no_subject_name(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) def test_build_ca_request_with_rsa(self, backend): private_key = RSA_KEY_2048.private_key(backend) @@ -3463,7 +3376,6 @@ def test_build_ca_request_with_rsa(self, backend): assert basic_constraints.value.ca is True assert basic_constraints.value.path_length == 2 - @pytest.mark.requires_backend_interface(interface=RSABackend) def test_build_ca_request_with_unicode(self, backend): private_key = RSA_KEY_2048.private_key(backend) @@ -3493,7 +3405,6 @@ def test_build_ca_request_with_unicode(self, backend): x509.NameAttribute(NameOID.ORGANIZATION_NAME, "PyCA\U0001f37a"), ] - @pytest.mark.requires_backend_interface(interface=RSABackend) def test_subject_dn_asn1_types(self, backend): private_key = RSA_KEY_2048.private_key(backend) @@ -3552,7 +3463,6 @@ def test_subject_dn_asn1_types(self, backend): == 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( @@ -3582,7 +3492,6 @@ def test_build_ca_request_with_multivalue_rdns(self, backend): assert isinstance(loaded_request.subject, x509.Name) assert loaded_request.subject == subject - @pytest.mark.requires_backend_interface(interface=RSABackend) def test_build_nonca_request_with_rsa(self, backend): private_key = RSA_KEY_2048.private_key(backend) @@ -3612,7 +3521,6 @@ def test_build_nonca_request_with_rsa(self, backend): assert basic_constraints.value.ca is False assert basic_constraints.value.path_length is None - @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_build_ca_request_with_ec(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) private_key = ec.generate_private_key(ec.SECP256R1(), backend) @@ -3652,7 +3560,6 @@ def test_build_ca_request_with_ec(self, backend): only_if=lambda backend: backend.ed25519_supported(), skip_message="Requires OpenSSL with Ed25519 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_build_ca_request_with_ed25519(self, backend): private_key = ed25519.Ed25519PrivateKey.generate() @@ -3691,7 +3598,6 @@ def test_build_ca_request_with_ed25519(self, backend): only_if=lambda backend: backend.ed448_supported(), skip_message="Requires OpenSSL with Ed448 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_build_ca_request_with_ed448(self, backend): private_key = ed448.Ed448PrivateKey.generate() @@ -3726,7 +3632,6 @@ def test_build_ca_request_with_ed448(self, backend): assert basic_constraints.value.ca is True assert basic_constraints.value.path_length == 2 - @pytest.mark.requires_backend_interface(interface=DSABackend) def test_build_ca_request_with_dsa(self, backend): private_key = DSA_KEY_2048.private_key(backend) @@ -3902,7 +3807,6 @@ def test_add_two_extensions(self, backend): ) assert list(ext.value) == [x509.DNSName("cryptography.io")] - @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_add_attributes(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) private_key = ec.generate_private_key(ec.SECP256R1(), backend) @@ -4104,7 +4008,6 @@ def test_extended_key_usage(self, backend): assert ext.critical is False assert ext.value == eku - @pytest.mark.requires_backend_interface(interface=RSABackend) def test_rsa_key_too_small(self, backend): private_key = RSA_KEY_512.private_key(backend) builder = x509.CertificateSigningRequestBuilder() @@ -4115,8 +4018,6 @@ def test_rsa_key_too_small(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA512(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_build_cert_with_aia(self, backend): issuer_private_key = RSA_KEY_2048.private_key(backend) subject_private_key = RSA_KEY_2048.private_key(backend) @@ -4159,8 +4060,6 @@ def test_build_cert_with_aia(self, backend): ) assert ext.value == aia - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_build_cert_with_sia(self, backend): issuer_private_key = RSA_KEY_2048.private_key(backend) subject_private_key = RSA_KEY_2048.private_key(backend) @@ -4199,8 +4098,6 @@ def test_build_cert_with_sia(self, backend): ) assert ext.value == sia - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_build_cert_with_ski(self, backend): issuer_private_key = RSA_KEY_2048.private_key(backend) subject_private_key = RSA_KEY_2048.private_key(backend) @@ -4282,8 +4179,6 @@ def test_build_cert_with_ski(self, backend): ), ], ) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_build_cert_with_aki(self, aki, backend): issuer_private_key = RSA_KEY_2048.private_key(backend) subject_private_key = RSA_KEY_2048.private_key(backend) @@ -4341,8 +4236,6 @@ def test_ocsp_nocheck(self, backend): assert isinstance(ext.value, x509.OCSPNoCheck) -@pytest.mark.requires_backend_interface(interface=DSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestDSACertificate(object): def test_load_dsa_cert(self, backend): cert = _load_cert( @@ -4465,8 +4358,6 @@ def test_tbs_certificate_bytes(self, backend): ) -@pytest.mark.requires_backend_interface(interface=DSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestDSACertificateRequest(object): @pytest.mark.parametrize( ("path", "loader_func"), @@ -4539,8 +4430,6 @@ def test_tbs_certrequest_bytes(self, backend): ) -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestECDSACertificate(object): def test_load_ecdsa_cert(self, backend): _skip_curve_unsupported(backend, ec.SECP384R1()) @@ -4630,8 +4519,6 @@ def test_load_ecdsa_no_named_curve(self, backend): cert.public_key() -@pytest.mark.requires_backend_interface(interface=X509Backend) -@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) class TestECDSACertificateRequest(object): @pytest.mark.parametrize( ("path", "loader_func"), @@ -4699,7 +4586,6 @@ def test_tbs_certrequest_bytes(self, backend): ) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestOtherCertificate(object): def test_unsupported_subject_public_key_info(self, backend): cert = _load_cert( @@ -5105,7 +4991,6 @@ def test_not_nameattribute(self): with pytest.raises(TypeError): x509.Name(["not-a-NameAttribute"]) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_bytes(self, backend): name = x509.Name( [ @@ -5118,7 +5003,6 @@ def test_bytes(self, backend): 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 @@ -5138,7 +5022,6 @@ def test_bmpstring_bytes(self, backend): b"7000680079002e0069006f310d300b060355040a0c0450794341" ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_universalstring_bytes(self, backend): # UniversalString is UCS-4 name = x509.Name( @@ -5162,7 +5045,6 @@ def test_universalstring_bytes(self, backend): only_if=lambda backend: backend.ed25519_supported(), skip_message="Requires OpenSSL with Ed25519 support", ) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestEd25519Certificate(object): def test_load_pem_cert(self, backend): cert = _load_cert( @@ -5190,7 +5072,6 @@ def test_deepcopy(self, backend): only_if=lambda backend: backend.ed448_supported(), skip_message="Requires OpenSSL with Ed448 support", ) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestEd448Certificate(object): def test_load_pem_cert(self, backend): cert = _load_cert( @@ -5206,7 +5087,6 @@ def test_load_pem_cert(self, backend): assert cert.signature_algorithm_oid == SignatureAlgorithmOID.ED448 -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestSignatureRejection(object): """Test if signing rejects DH keys properly.""" diff --git a/tests/x509/test_x509_crlbuilder.py b/tests/x509/test_x509_crlbuilder.py index 88725710d7fd..b32322f975e6 100644 --- a/tests/x509/test_x509_crlbuilder.py +++ b/tests/x509/test_x509_crlbuilder.py @@ -10,12 +10,6 @@ import pytz from cryptography import x509 -from cryptography.hazmat.backends.interfaces import ( - DSABackend, - EllipticCurveBackend, - RSABackend, - X509Backend, -) from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec, ed25519, ed448 from cryptography.x509.oid import ( @@ -45,8 +39,6 @@ def test_set_issuer_name_twice(self): x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) ) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_aware_last_update(self, backend): last_time = datetime.datetime(2012, 1, 16, 22, 43) tz = pytz.timezone("US/Pacific") @@ -89,8 +81,6 @@ def test_set_last_update_twice(self): with pytest.raises(ValueError): builder.last_update(datetime.datetime(2002, 1, 1, 12, 1)) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_aware_next_update(self, backend): next_time = datetime.datetime(2022, 1, 16, 22, 43) tz = pytz.timezone("US/Pacific") @@ -167,8 +157,6 @@ def test_add_invalid_revoked_certificate(self): with pytest.raises(TypeError): builder.add_revoked_certificate(object()) # type:ignore[arg-type] - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_issuer_name(self, backend): private_key = RSA_KEY_2048.private_key(backend) builder = ( @@ -180,8 +168,6 @@ def test_no_issuer_name(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_last_update(self, backend): private_key = RSA_KEY_2048.private_key(backend) builder = ( @@ -195,8 +181,6 @@ def test_no_last_update(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_next_update(self, backend): private_key = RSA_KEY_2048.private_key(backend) builder = ( @@ -210,8 +194,6 @@ def test_no_next_update(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_empty_list(self, backend): private_key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) @@ -260,8 +242,6 @@ def test_sign_empty_list(self, backend): ), ], ) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_extensions(self, backend, extension): private_key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) @@ -289,8 +269,6 @@ def test_sign_extensions(self, backend, extension): assert ext.critical is False assert ext.value == extension - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_multiple_extensions_critical(self, backend): private_key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) @@ -328,8 +306,6 @@ def test_sign_multiple_extensions_critical(self, backend): assert ext2.critical is True assert ext2.value == ian - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_freshestcrl_extension(self, backend): private_key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) @@ -371,8 +347,6 @@ def test_freshestcrl_extension(self, backend): assert isinstance(uri, x509.UniformResourceIdentifier) assert uri.value == "http://d.om/delta" - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_add_unsupported_extension(self, backend): private_key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) @@ -395,8 +369,6 @@ def test_add_unsupported_extension(self, backend): with pytest.raises(NotImplementedError): builder.sign(private_key, hashes.SHA256(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_rsa_key_too_small(self, backend): private_key = RSA_KEY_512.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) @@ -419,8 +391,6 @@ def test_sign_rsa_key_too_small(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA512(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_with_invalid_hash(self, backend): private_key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) @@ -447,7 +417,6 @@ def test_sign_with_invalid_hash(self, backend): only_if=lambda backend: backend.ed25519_supported(), skip_message="Requires OpenSSL with Ed25519 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_with_invalid_hash_ed25519(self, backend): private_key = ed25519.Ed25519PrivateKey.generate() last_update = datetime.datetime(2002, 1, 1, 12, 1) @@ -476,7 +445,6 @@ def test_sign_with_invalid_hash_ed25519(self, backend): only_if=lambda backend: backend.ed448_supported(), skip_message="Requires OpenSSL with Ed448 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_with_invalid_hash_ed448(self, backend): private_key = ed448.Ed448PrivateKey.generate() last_update = datetime.datetime(2002, 1, 1, 12, 1) @@ -501,8 +469,6 @@ def test_sign_with_invalid_hash_ed448(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) - @pytest.mark.requires_backend_interface(interface=DSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_dsa_key(self, backend): private_key = DSA_KEY_2048.private_key(backend) invalidity_date = x509.InvalidityDate( @@ -551,8 +517,6 @@ def test_sign_dsa_key(self, backend): assert ext.critical is False assert ext.value == invalidity_date - @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_ec_key(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) private_key = ec.generate_private_key(ec.SECP256R1(), backend) @@ -606,7 +570,6 @@ def test_sign_ec_key(self, backend): only_if=lambda backend: backend.ed25519_supported(), skip_message="Requires OpenSSL with Ed25519 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_ed25519_key(self, backend): private_key = ed25519.Ed25519PrivateKey.generate() invalidity_date = x509.InvalidityDate( @@ -661,7 +624,6 @@ def test_sign_ed25519_key(self, backend): only_if=lambda backend: backend.ed448_supported(), skip_message="Requires OpenSSL with Ed448 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_ed448_key(self, backend): private_key = ed448.Ed448PrivateKey.generate() invalidity_date = x509.InvalidityDate( @@ -712,8 +674,6 @@ def test_sign_ed448_key(self, backend): assert ext.critical is False assert ext.value == invalidity_date - @pytest.mark.requires_backend_interface(interface=DSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_dsa_key_sign_md5(self, backend): private_key = DSA_KEY_2048.private_key(backend) last_time = datetime.datetime(2012, 1, 16, 22, 43) @@ -736,8 +696,6 @@ def test_dsa_key_sign_md5(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.MD5(), backend) - @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_ec_key_sign_md5(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) private_key = EC_KEY_SECP256R1.private_key(backend) @@ -761,8 +719,6 @@ def test_ec_key_sign_md5(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.MD5(), backend) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_with_revoked_certificates(self, backend): private_key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index f74f3d5a5f56..5fd3b527f5eb 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -14,12 +14,6 @@ import pytest from cryptography import x509 -from cryptography.hazmat.backends.interfaces import ( - DSABackend, - EllipticCurveBackend, - RSABackend, - X509Backend, -) from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec from cryptography.x509 import DNSName, NameConstraints, SubjectAlternativeName @@ -569,7 +563,6 @@ def test_hash(self): assert hash(pi) != hash(pi3) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestCertificatePolicies(object): def test_invalid_policies(self): pq = ["string"] @@ -665,8 +658,6 @@ def test_hash(self): assert hash(cp) != hash(cp3) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestCertificatePoliciesExtension(object): def test_cps_uri_policy_qualifier(self, backend): cert = _load_cert( @@ -1278,8 +1269,6 @@ def test_hash(self): assert hash(eku) != hash(eku3) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestExtensions(object): def test_no_extensions(self, backend): cert = _load_cert( @@ -1332,7 +1321,6 @@ def test_unsupported_critical_extension(self, backend): ) assert ext.value.value == b"value" - @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_unsupported_extension(self, backend): cert = _load_cert( os.path.join("x509", "custom", "unsupported_extension_2.pem"), @@ -1410,8 +1398,6 @@ def test_repr(self, backend): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestBasicConstraintsExtension(object): def test_ca_true_pathlen_6(self, backend): cert = _load_cert( @@ -1504,8 +1490,6 @@ def test_basic_constraint_not_critical(self, backend): class TestSubjectKeyIdentifierExtension(object): - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_subject_key_identifier(self, backend): cert = _load_cert( os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), @@ -1522,8 +1506,6 @@ def test_subject_key_identifier(self, backend): b"580184241bbc2b52944a3da510721451f5af3ac9" ) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_subject_key_identifier(self, backend): cert = _load_cert( os.path.join("x509", "custom", "bc_path_length_zero.pem"), @@ -1535,8 +1517,6 @@ def test_no_subject_key_identifier(self, backend): ExtensionOID.SUBJECT_KEY_IDENTIFIER ) - @pytest.mark.requires_backend_interface(interface=RSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_from_rsa_public_key(self, backend): cert = _load_cert( os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), @@ -1549,8 +1529,6 @@ def test_from_rsa_public_key(self, backend): ski = x509.SubjectKeyIdentifier.from_public_key(cert.public_key()) assert ext.value == ski - @pytest.mark.requires_backend_interface(interface=DSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_from_dsa_public_key(self, backend): cert = _load_cert( os.path.join("x509", "custom", "dsa_selfsigned_ca.pem"), @@ -1564,8 +1542,6 @@ def test_from_dsa_public_key(self, backend): ski = x509.SubjectKeyIdentifier.from_public_key(cert.public_key()) assert ext.value == ski - @pytest.mark.requires_backend_interface(interface=DSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_invalid_bit_string_padding_from_public_key(self, backend): data = load_vectors_from_file( filename=os.path.join( @@ -1580,8 +1556,6 @@ def test_invalid_bit_string_padding_from_public_key(self, backend): with pytest.raises(ValueError): _key_identifier_from_public_key(pretend_key) - @pytest.mark.requires_backend_interface(interface=DSABackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_optional_params_allowed_from_public_key(self, backend): data = load_vectors_from_file( filename=os.path.join( @@ -1598,8 +1572,6 @@ def test_no_optional_params_allowed_from_public_key(self, backend): b"24c0133a6a492f2c48a18c7648e515db5ac76749" ) - @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_from_ec_public_key(self, backend): _skip_curve_unsupported(backend, ec.SECP384R1()) cert = _load_cert( @@ -1618,7 +1590,6 @@ def test_from_ec_public_key(self, backend): only_if=lambda backend: backend.ed25519_supported(), skip_message="Requires OpenSSL with Ed25519 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_from_ed25519_public_key(self, backend): cert = _load_cert( os.path.join("x509", "ed25519", "root-ed25519.pem"), @@ -1636,7 +1607,6 @@ def test_from_ed25519_public_key(self, backend): only_if=lambda backend: backend.ed448_supported(), skip_message="Requires OpenSSL with Ed448 support", ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_from_ed448_public_key(self, backend): cert = _load_cert( os.path.join("x509", "ed448", "root-ed448.pem"), @@ -1651,8 +1621,6 @@ def test_from_ed448_public_key(self, backend): assert ext.value == ski -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestKeyUsageExtension(object): def test_no_key_usage(self, backend): cert = _load_cert( @@ -2140,8 +2108,6 @@ def test_hash(self): assert hash(ian) != hash(ian3) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestRSAIssuerAlternativeNameExtension(object): def test_uri(self, backend): cert = _load_cert( @@ -2251,8 +2217,6 @@ def test_hash(self): assert hash(san) != hash(san3) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestRSASubjectAlternativeNameExtension(object): def test_dns_name(self, backend): cert = _load_cert( @@ -2552,8 +2516,6 @@ def test_certbuilder(self, backend): assert result == sans -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestExtendedKeyUsageExtension(object): def test_eku(self, backend): cert = _load_cert( @@ -2698,8 +2660,6 @@ def test_hash(self): assert hash(pc) != hash(pc3) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestPolicyConstraintsExtension(object): def test_inhibit_policy_mapping(self, backend): cert = _load_cert( @@ -3098,8 +3058,6 @@ def test_hash(self): assert hash(sia) != hash(sia3) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestSubjectInformationAccessExtension(object): def test_sia(self, backend): cert = _load_cert( @@ -3129,8 +3087,6 @@ def test_sia(self, backend): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestAuthorityInformationAccessExtension(object): def test_aia_ocsp_ca_issuers(self, backend): cert = _load_cert( @@ -3253,8 +3209,6 @@ def test_aia_ca_issuers_only(self, backend): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestAuthorityKeyIdentifierExtension(object): def test_aki_keyid(self, backend): cert = _load_cert( @@ -3499,8 +3453,6 @@ def test_hash(self): assert hash(nc3) != hash(nc4) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestNameConstraintsExtension(object): def test_permitted_excluded(self, backend): cert = _load_cert( @@ -4354,8 +4306,6 @@ def test_indexing(self): assert ci[2:6:2] == [ci[2], ci[4]] -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestCRLDistributionPointsExtension(object): def test_fullname_and_crl_issuer(self, backend): cert = _load_cert( @@ -4641,8 +4591,6 @@ def test_crl_empty_hostname(self, backend): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestFreshestCRLExtension(object): def test_vector(self, backend): cert = _load_cert( @@ -4689,8 +4637,6 @@ def test_vector(self, backend): ) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestOCSPNoCheckExtension(object): def test_nocheck(self, backend): cert = _load_cert( @@ -4759,8 +4705,6 @@ def test_hash(self): assert hash(iap) != hash(iap3) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestInhibitAnyPolicyExtension(object): def test_inhibit_any_policy(self, backend): cert = _load_cert( @@ -4926,8 +4870,6 @@ class TestIssuingDistributionPointExtension(object): ), ], ) - @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), @@ -5132,8 +5074,6 @@ def test_hash(self): 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", [ @@ -5284,8 +5224,6 @@ def test_generate(self, idp, backend): 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( @@ -5340,8 +5278,6 @@ def test_repr(self): assert repr(pcp) == "" -@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_HAS_SCT), @@ -5444,8 +5380,6 @@ def test_hash(self, backend): assert hash(sct) != hash(sct3) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestPrecertificateSignedCertificateTimestampsExtension(object): def test_init(self): with pytest.raises(TypeError): @@ -5636,8 +5570,6 @@ def test_skips_scts_if_unsupported(self, backend): assert isinstance(ext.value, x509.UnrecognizedExtension) -@pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.requires_backend_interface(interface=X509Backend) class TestInvalidExtension(object): def test_invalid_certificate_policies_data(self, backend): cert = _load_cert( diff --git a/tests/x509/test_x509_revokedcertbuilder.py b/tests/x509/test_x509_revokedcertbuilder.py index 34738e513e9a..b504185d3e36 100644 --- a/tests/x509/test_x509_revokedcertbuilder.py +++ b/tests/x509/test_x509_revokedcertbuilder.py @@ -10,7 +10,6 @@ import pytz from cryptography import x509 -from cryptography.hazmat.backends.interfaces import X509Backend class TestRevokedCertificateBuilder(object): @@ -28,7 +27,6 @@ def test_serial_number_must_be_positive(self): with pytest.raises(ValueError): x509.RevokedCertificateBuilder().serial_number(0) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_minimal_serial_number(self, backend): revocation_date = datetime.datetime(2002, 1, 1, 12, 1) builder = ( @@ -40,7 +38,6 @@ def test_minimal_serial_number(self, backend): revoked_certificate = builder.build(backend) assert revoked_certificate.serial_number == 1 - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_biggest_serial_number(self, backend): revocation_date = datetime.datetime(2002, 1, 1, 12, 1) builder = ( @@ -61,7 +58,6 @@ def test_set_serial_number_twice(self): with pytest.raises(ValueError): builder.serial_number(4) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_aware_revocation_date(self, backend): time = datetime.datetime(2012, 1, 16, 22, 43) tz = pytz.timezone("US/Pacific") @@ -112,7 +108,6 @@ def test_add_invalid_extension(self): "notanextension", False # type: ignore[arg-type] ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_serial_number(self, backend): builder = x509.RevokedCertificateBuilder().revocation_date( datetime.datetime(2002, 1, 1, 12, 1) @@ -121,14 +116,12 @@ def test_no_serial_number(self, backend): with pytest.raises(ValueError): builder.build(backend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_revocation_date(self, backend): builder = x509.RevokedCertificateBuilder().serial_number(3) with pytest.raises(ValueError): builder.build(backend) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_create_revoked(self, backend): serial_number = 333 revocation_date = datetime.datetime(2002, 1, 1, 12, 1) @@ -151,7 +144,6 @@ def test_create_revoked(self, backend): x509.CertificateIssuer([x509.DNSName("cryptography.io")]), ], ) - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_add_extensions(self, backend, extension): serial_number = 333 revocation_date = datetime.datetime(2002, 1, 1, 12, 1) @@ -172,7 +164,6 @@ def test_add_extensions(self, backend, extension): assert ext.critical is False assert ext.value == extension - @pytest.mark.requires_backend_interface(interface=X509Backend) def test_add_multiple_extensions(self, backend): serial_number = 333 revocation_date = datetime.datetime(2002, 1, 1, 12, 1) From 17ec5db3374e7804c840cb2bafbe25cd07d9b065 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 1 Mar 2021 16:40:25 -0500 Subject: [PATCH 0070/1456] Delete unused register_interface_if (#5883) --- src/cryptography/utils.py | 10 ---------- tests/test_interfaces.py | 23 ----------------------- 2 files changed, 33 deletions(-) diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index ef0fc44332d0..e0abd4a8ab6c 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -49,16 +49,6 @@ def register_decorator(klass, *, check_annotations=False): return register_decorator -def register_interface_if(predicate, iface): - def register_decorator(klass, *, check_annotations=False): - if predicate: - verify_interface(iface, klass, check_annotations=check_annotations) - iface.register(klass) - return klass - - return register_decorator - - def int_to_bytes(integer: int, length: typing.Optional[int] = None) -> bytes: return integer.to_bytes( length or (integer.bit_length() + 7) // 8 or 1, "big" diff --git a/tests/test_interfaces.py b/tests/test_interfaces.py index 89d802aed017..7736690cb536 100644 --- a/tests/test_interfaces.py +++ b/tests/test_interfaces.py @@ -8,33 +8,10 @@ from cryptography.utils import ( InterfaceNotImplemented, - register_interface_if, verify_interface, ) -def test_register_interface_if_true(): - class SimpleInterface(metaclass=abc.ABCMeta): - pass - - @register_interface_if(1 == 1, SimpleInterface) - class SimpleClass(object): - pass - - assert issubclass(SimpleClass, SimpleInterface) is True - - -def test_register_interface_if_false(): - class SimpleInterface(metaclass=abc.ABCMeta): - pass - - @register_interface_if(1 == 2, SimpleInterface) - class SimpleClass(object): - pass - - assert issubclass(SimpleClass, SimpleInterface) is False - - class TestVerifyInterface(object): def test_verify_missing_method(self): class SimpleInterface(metaclass=abc.ABCMeta): From a2d4ea3e1a0858f0f68ebf4724d37e0e4edf0660 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 1 Mar 2021 19:39:41 -0500 Subject: [PATCH 0071/1456] wycheproof_tests is not longer a fixture (#5886) --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2c90d97ae06c..b2bf92caf086 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,5 +19,4 @@ addopts = "-r s" markers = [ "skip_fips: this test is not executed in FIPS mode", "supported: parametrized test requiring only_if and skip_message", - "wycheproof_tests: this test runs a wycheproof fixture", ] From 032a7f3cdca5207d3b1e2a5eed14897d88f78378 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 2 Mar 2021 11:48:03 -0600 Subject: [PATCH 0072/1456] more typing (#5887) * backend typing for twofactor package and more otp work * even more typing * style fixes * no generic typing for _get_backend * remove unneeded typing --- src/cryptography/fernet.py | 3 +- src/cryptography/hazmat/backends/__init__.py | 6 +- .../hazmat/backends/interfaces.py | 63 +++++++++++ .../hazmat/backends/openssl/backend.py | 32 +----- .../hazmat/primitives/asymmetric/dh.py | 23 ++-- .../hazmat/primitives/asymmetric/dsa.py | 27 +++-- .../hazmat/primitives/asymmetric/ec.py | 17 ++- .../hazmat/primitives/asymmetric/ed25519.py | 2 +- .../hazmat/primitives/asymmetric/ed448.py | 4 +- .../hazmat/primitives/asymmetric/rsa.py | 14 ++- .../hazmat/primitives/asymmetric/x448.py | 2 +- .../hazmat/primitives/ciphers/aead.py | 6 +- .../hazmat/primitives/ciphers/algorithms.py | 2 +- .../hazmat/primitives/ciphers/base.py | 6 +- .../hazmat/primitives/ciphers/modes.py | 8 +- src/cryptography/hazmat/primitives/cmac.py | 9 +- src/cryptography/hazmat/primitives/hashes.py | 9 +- src/cryptography/hazmat/primitives/hmac.py | 6 +- .../hazmat/primitives/kdf/concatkdf.py | 13 ++- .../hazmat/primitives/kdf/hkdf.py | 6 +- .../hazmat/primitives/kdf/kbkdf.py | 4 +- .../hazmat/primitives/kdf/pbkdf2.py | 6 +- .../hazmat/primitives/kdf/scrypt.py | 11 +- .../hazmat/primitives/kdf/x963kdf.py | 4 +- src/cryptography/hazmat/primitives/keywrap.py | 27 ++++- .../hazmat/primitives/serialization/base.py | 25 ++++- .../hazmat/primitives/serialization/pkcs12.py | 5 +- .../hazmat/primitives/serialization/pkcs7.py | 3 +- .../hazmat/primitives/serialization/ssh.py | 13 ++- .../hazmat/primitives/twofactor/hotp.py | 8 +- .../hazmat/primitives/twofactor/totp.py | 4 +- src/cryptography/utils.py | 4 +- src/cryptography/x509/base.py | 105 ++++++++++++------ src/cryptography/x509/name.py | 3 +- tests/hazmat/backends/test_no_backend.py | 2 +- tests/hazmat/primitives/test_ciphers.py | 6 +- tests/hazmat/primitives/test_cmac.py | 2 +- tests/hazmat/primitives/test_concatkdf.py | 15 ++- tests/hazmat/primitives/test_dh.py | 21 ++-- tests/hazmat/primitives/test_hashes.py | 2 +- tests/hazmat/primitives/test_hkdf.py | 12 +- tests/hazmat/primitives/test_hmac.py | 4 +- tests/hazmat/primitives/test_kbkdf.py | 2 +- tests/hazmat/primitives/test_pbkdf2hmac.py | 8 +- tests/hazmat/primitives/test_rsa.py | 4 +- tests/hazmat/primitives/test_scrypt.py | 2 +- tests/hazmat/primitives/test_x963kdf.py | 7 +- .../hazmat/primitives/twofactor/test_hotp.py | 4 +- .../hazmat/primitives/twofactor/test_totp.py | 8 +- tests/x509/test_x509.py | 36 +++++- tests/x509/test_x509_crlbuilder.py | 17 ++- 51 files changed, 448 insertions(+), 184 deletions(-) diff --git a/src/cryptography/fernet.py b/src/cryptography/fernet.py index 57772fee424a..bcf1c9848c6e 100644 --- a/src/cryptography/fernet.py +++ b/src/cryptography/fernet.py @@ -13,6 +13,7 @@ from cryptography import utils from cryptography.exceptions import InvalidSignature from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.backends.interfaces import Backend from cryptography.hazmat.primitives import hashes, padding from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.hmac import HMAC @@ -26,7 +27,7 @@ class InvalidToken(Exception): class Fernet(object): - def __init__(self, key: bytes, backend=None): + def __init__(self, key: bytes, backend: typing.Optional[Backend] = None): backend = _get_backend(backend) key = base64.urlsafe_b64decode(key) diff --git a/src/cryptography/hazmat/backends/__init__.py b/src/cryptography/hazmat/backends/__init__.py index 72c65b197f09..7f74cba2c9b2 100644 --- a/src/cryptography/hazmat/backends/__init__.py +++ b/src/cryptography/hazmat/backends/__init__.py @@ -4,7 +4,9 @@ import typing -_default_backend: typing.Any = None +from cryptography.hazmat.backends.interfaces import Backend + +_default_backend: typing.Optional[Backend] = None def default_backend(): @@ -18,7 +20,7 @@ def default_backend(): return _default_backend -def _get_backend(backend): +def _get_backend(backend: typing.Optional[Backend]) -> Backend: if backend is None: return default_backend() else: diff --git a/src/cryptography/hazmat/backends/interfaces.py b/src/cryptography/hazmat/backends/interfaces.py index d5debb5426e0..d57289bb1dc2 100644 --- a/src/cryptography/hazmat/backends/interfaces.py +++ b/src/cryptography/hazmat/backends/interfaces.py @@ -317,6 +317,18 @@ def x509_name_bytes(self, name): Compute the DER encoded bytes of an X509 Name object. """ + @abc.abstractmethod + def load_pem_x509_crl(self, data): + """ + Load an X.509 CRL from PEM encoded data. + """ + + @abc.abstractmethod + def load_der_x509_crl(self, data): + """ + Load an X.509 CRL from DER encoded data. + """ + class DHBackend(metaclass=abc.ABCMeta): @abc.abstractmethod @@ -384,3 +396,54 @@ def scrypt_supported(self): """ Return True if Scrypt is supported. """ + + +# This is the catch-all for future backend methods and inherits all the +# other interfaces as well so we can just use Backend for typing. +class Backend( + CipherBackend, + CMACBackend, + DERSerializationBackend, + DHBackend, + DSABackend, + EllipticCurveBackend, + HashBackend, + HMACBackend, + PBKDF2HMACBackend, + RSABackend, + PEMSerializationBackend, + ScryptBackend, + X509Backend, + metaclass=abc.ABCMeta, +): + @abc.abstractmethod + def load_pem_pkcs7_certificates(self, data): + """ + Returns a list of x509.Certificate + """ + + @abc.abstractmethod + def load_der_pkcs7_certificates(self, data): + """ + Returns a list of x509.Certificate + """ + + @abc.abstractmethod + def pkcs7_sign(self, builder, encoding, options): + """ + Returns bytes + """ + + @abc.abstractmethod + def load_key_and_certificates_from_pkcs12(self, data, password): + """ + Returns a tuple of (key, cert, [certs]) + """ + + @abc.abstractmethod + def serialize_key_and_certificates_to_pkcs12( + self, name, key, cert, cas, encryption_algorithm + ): + """ + Returns bytes + """ diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index fb0070386505..c87a466c9307 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -18,21 +18,7 @@ encode_der, encode_der_integer, ) -from cryptography.hazmat.backends.interfaces import ( - CMACBackend, - CipherBackend, - DERSerializationBackend, - DHBackend, - DSABackend, - EllipticCurveBackend, - HMACBackend, - HashBackend, - PBKDF2HMACBackend, - PEMSerializationBackend, - RSABackend, - ScryptBackend, - X509Backend, -) +from cryptography.hazmat.backends.interfaces import Backend as BackendInterface from cryptography.hazmat.backends.openssl import aead from cryptography.hazmat.backends.openssl.ciphers import _CipherContext from cryptography.hazmat.backends.openssl.cmac import _CMACContext @@ -161,21 +147,7 @@ class _RC2(object): pass -class Backend( - CipherBackend, - CMACBackend, - DERSerializationBackend, - DHBackend, - DSABackend, - EllipticCurveBackend, - HashBackend, - HMACBackend, - PBKDF2HMACBackend, - RSABackend, - PEMSerializationBackend, - ScryptBackend, - X509Backend, -): +class Backend(BackendInterface): """ OpenSSL API binding interfaces. """ diff --git a/src/cryptography/hazmat/primitives/asymmetric/dh.py b/src/cryptography/hazmat/primitives/asymmetric/dh.py index 6867f5365510..8f1d093e400f 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/dh.py +++ b/src/cryptography/hazmat/primitives/asymmetric/dh.py @@ -7,19 +7,22 @@ import typing from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.backends.interfaces import Backend from cryptography.hazmat.primitives import serialization _MIN_MODULUS_SIZE = 512 -def generate_parameters(generator, key_size, backend=None) -> "DHParameters": +def generate_parameters( + generator: int, key_size: int, backend: typing.Optional[Backend] = None +) -> "DHParameters": backend = _get_backend(backend) return backend.generate_dh_parameters(generator, key_size) class DHParameterNumbers(object): - def __init__(self, p: int, g: int, q: typing.Optional[int] = None): + def __init__(self, p: int, g: int, q: typing.Optional[int] = None) -> None: if not isinstance(p, int) or not isinstance(g, int): raise TypeError("p and g must be integers") if q is not None and not isinstance(q, int): @@ -48,7 +51,9 @@ def __eq__(self, other): def __ne__(self, other): return not self == other - def parameters(self, backend=None): + def parameters( + self, backend: typing.Optional[Backend] = None + ) -> "DHParameters": backend = _get_backend(backend) return backend.load_dh_parameter_numbers(self) @@ -58,7 +63,7 @@ def parameters(self, backend=None): class DHPublicNumbers(object): - def __init__(self, y, parameter_numbers: DHParameterNumbers): + def __init__(self, y: int, parameter_numbers: DHParameterNumbers) -> None: if not isinstance(y, int): raise TypeError("y must be an integer.") @@ -82,7 +87,9 @@ def __eq__(self, other): def __ne__(self, other): return not self == other - def public_key(self, backend=None) -> "DHPublicKey": + def public_key( + self, backend: typing.Optional[Backend] = None + ) -> "DHPublicKey": backend = _get_backend(backend) return backend.load_dh_public_numbers(self) @@ -91,7 +98,7 @@ def public_key(self, backend=None) -> "DHPublicKey": class DHPrivateNumbers(object): - def __init__(self, x, public_numbers: DHPublicNumbers): + def __init__(self, x: int, public_numbers: DHPublicNumbers) -> None: if not isinstance(x, int): raise TypeError("x must be an integer.") @@ -115,7 +122,9 @@ def __eq__(self, other): def __ne__(self, other): return not self == other - def private_key(self, backend=None) -> "DHPrivateKey": + def private_key( + self, backend: typing.Optional[Backend] = None + ) -> "DHPrivateKey": backend = _get_backend(backend) return backend.load_dh_private_numbers(self) diff --git a/src/cryptography/hazmat/primitives/asymmetric/dsa.py b/src/cryptography/hazmat/primitives/asymmetric/dsa.py index 7946c02a7c60..8587ecf09a9c 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/dsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -7,6 +7,7 @@ import typing from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.backends.interfaces import Backend from cryptography.hazmat.primitives import _serialization, hashes from cryptography.hazmat.primitives.asymmetric import ( AsymmetricSignatureContext, @@ -136,7 +137,7 @@ def verify( signature: bytes, data: bytes, algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], - ): + ) -> None: """ Verifies the signature of the data. """ @@ -164,7 +165,9 @@ def __init__(self, p: int, q: int, g: int): q = property(lambda self: self._q) g = property(lambda self: self._g) - def parameters(self, backend=None) -> DSAParameters: + def parameters( + self, backend: typing.Optional[Backend] = None + ) -> DSAParameters: backend = _get_backend(backend) return backend.load_dsa_parameter_numbers(self) @@ -200,7 +203,9 @@ def __init__(self, y: int, parameter_numbers: DSAParameterNumbers): y = property(lambda self: self._y) parameter_numbers = property(lambda self: self._parameter_numbers) - def public_key(self, backend=None) -> DSAPublicKey: + def public_key( + self, backend: typing.Optional[Backend] = None + ) -> DSAPublicKey: backend = _get_backend(backend) return backend.load_dsa_public_numbers(self) @@ -238,7 +243,9 @@ def __init__(self, x: int, public_numbers: DSAPublicNumbers): x = property(lambda self: self._x) public_numbers = property(lambda self: self._public_numbers) - def private_key(self, backend=None) -> DSAPrivateKey: + def private_key( + self, backend: typing.Optional[Backend] = None + ) -> DSAPrivateKey: backend = _get_backend(backend) return backend.load_dsa_private_numbers(self) @@ -254,17 +261,21 @@ def __ne__(self, other): return not self == other -def generate_parameters(key_size: int, backend=None) -> DSAParameters: +def generate_parameters( + key_size: int, backend: typing.Optional[Backend] = None +) -> DSAParameters: backend = _get_backend(backend) return backend.generate_dsa_parameters(key_size) -def generate_private_key(key_size: int, backend=None) -> DSAPrivateKey: +def generate_private_key( + key_size: int, backend: typing.Optional[Backend] = None +) -> DSAPrivateKey: backend = _get_backend(backend) return backend.generate_dsa_private_key_and_parameters(key_size) -def _check_dsa_parameters(parameters: DSAParameterNumbers): +def _check_dsa_parameters(parameters: DSAParameterNumbers) -> None: if parameters.p.bit_length() not in [1024, 2048, 3072, 4096]: raise ValueError( "p must be exactly 1024, 2048, 3072, or 4096 bits long" @@ -276,7 +287,7 @@ def _check_dsa_parameters(parameters: DSAParameterNumbers): raise ValueError("g, p don't satisfy 1 < g < p.") -def _check_dsa_private_numbers(numbers: DSAPrivateNumbers): +def _check_dsa_private_numbers(numbers: DSAPrivateNumbers) -> None: parameters = numbers.public_numbers.parameter_numbers _check_dsa_parameters(parameters) if numbers.x <= 0 or numbers.x >= parameters.q: diff --git a/src/cryptography/hazmat/primitives/asymmetric/ec.py b/src/cryptography/hazmat/primitives/asymmetric/ec.py index 41dc5b58079c..c5bc27968d93 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ec.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ec.py @@ -10,6 +10,7 @@ from cryptography import utils from cryptography.hazmat._oid import ObjectIdentifier from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.backends.interfaces import Backend from cryptography.hazmat.primitives import _serialization, hashes from cryptography.hazmat.primitives.asymmetric import ( AsymmetricSignatureContext, @@ -104,7 +105,7 @@ def key_size(self) -> int: @abc.abstractmethod def sign( self, - data, + data: bytes, signature_algorithm: EllipticCurveSignatureAlgorithm, ) -> bytes: """ @@ -340,14 +341,16 @@ def algorithm( def generate_private_key( - curve: EllipticCurve, backend=None + curve: EllipticCurve, backend: typing.Optional[Backend] = None ) -> EllipticCurvePrivateKey: backend = _get_backend(backend) return backend.generate_elliptic_curve_private_key(curve) def derive_private_key( - private_value: int, curve: EllipticCurve, backend=None + private_value: int, + curve: EllipticCurve, + backend: typing.Optional[Backend] = None, ) -> EllipticCurvePrivateKey: backend = _get_backend(backend) if not isinstance(private_value, int): @@ -374,7 +377,9 @@ def __init__(self, x: int, y: int, curve: EllipticCurve): self._x = x self._curve = curve - def public_key(self, backend=None) -> EllipticCurvePublicKey: + def public_key( + self, backend: typing.Optional[Backend] = None + ) -> EllipticCurvePublicKey: backend = _get_backend(backend) return backend.load_elliptic_curve_public_numbers(self) @@ -466,7 +471,9 @@ def __init__( self._private_value = private_value self._public_numbers = public_numbers - def private_key(self, backend=None) -> EllipticCurvePrivateKey: + def private_key( + self, backend: typing.Optional[Backend] = None + ) -> EllipticCurvePrivateKey: backend = _get_backend(backend) return backend.load_elliptic_curve_private_numbers(self) diff --git a/src/cryptography/hazmat/primitives/asymmetric/ed25519.py b/src/cryptography/hazmat/primitives/asymmetric/ed25519.py index 8e649bf04a7e..43277028338a 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ed25519.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ed25519.py @@ -80,7 +80,7 @@ def private_bytes( encoding: _serialization.Encoding, format: _serialization.PrivateFormat, encryption_algorithm: _serialization.KeySerializationEncryption, - ): + ) -> bytes: """ The serialized bytes of the private key. """ diff --git a/src/cryptography/hazmat/primitives/asymmetric/ed448.py b/src/cryptography/hazmat/primitives/asymmetric/ed448.py index 41985462142c..27bc27c69f31 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ed448.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ed448.py @@ -33,7 +33,7 @@ def public_bytes( """ @abc.abstractmethod - def verify(self, signature: bytes, data: bytes): + def verify(self, signature: bytes, data: bytes) -> None: """ Verify the signature. """ @@ -81,7 +81,7 @@ def private_bytes( encoding: _serialization.Encoding, format: _serialization.PrivateFormat, encryption_algorithm: _serialization.KeySerializationEncryption, - ): + ) -> bytes: """ The serialized bytes of the private key. """ diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py index 106e464bc49a..35b0e86a4a71 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -9,7 +9,7 @@ from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.hazmat.backends import _get_backend -from cryptography.hazmat.backends.interfaces import RSABackend +from cryptography.hazmat.backends.interfaces import Backend, RSABackend from cryptography.hazmat.primitives import _serialization, hashes from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding from cryptography.hazmat.primitives.asymmetric import ( @@ -146,7 +146,9 @@ def recover_data_from_signature( def generate_private_key( - public_exponent: int, key_size: int, backend=None + public_exponent: int, + key_size: int, + backend: typing.Optional[Backend] = None, ) -> RSAPrivateKey: backend = _get_backend(backend) if not isinstance(backend, RSABackend): @@ -361,7 +363,9 @@ def __init__( iqmp = property(lambda self: self._iqmp) public_numbers = property(lambda self: self._public_numbers) - def private_key(self, backend=None) -> RSAPrivateKey: + def private_key( + self, backend: typing.Optional[Backend] = None + ) -> RSAPrivateKey: backend = _get_backend(backend) return backend.load_rsa_private_numbers(self) @@ -407,7 +411,9 @@ def __init__(self, e: int, n: int): e = property(lambda self: self._e) n = property(lambda self: self._n) - def public_key(self, backend=None) -> RSAPublicKey: + def public_key( + self, backend: typing.Optional[Backend] = None + ) -> RSAPublicKey: backend = _get_backend(backend) return backend.load_rsa_public_numbers(self) diff --git a/src/cryptography/hazmat/primitives/asymmetric/x448.py b/src/cryptography/hazmat/primitives/asymmetric/x448.py index 4282543d92bc..7f71c2722a67 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/x448.py +++ b/src/cryptography/hazmat/primitives/asymmetric/x448.py @@ -11,7 +11,7 @@ class X448PublicKey(metaclass=abc.ABCMeta): @classmethod - def from_public_bytes(cls, data) -> "X448PublicKey": + def from_public_bytes(cls, data: bytes) -> "X448PublicKey": from cryptography.hazmat.backends.openssl.backend import backend if not backend.x448_supported(): diff --git a/src/cryptography/hazmat/primitives/ciphers/aead.py b/src/cryptography/hazmat/primitives/ciphers/aead.py index 5c7cdc25b0ac..d47bb445cd2f 100644 --- a/src/cryptography/hazmat/primitives/ciphers/aead.py +++ b/src/cryptography/hazmat/primitives/ciphers/aead.py @@ -136,14 +136,16 @@ def decrypt( backend, self, nonce, data, associated_data, self._tag_length ) - def _validate_lengths(self, nonce: bytes, data_len: int): + def _validate_lengths(self, nonce: bytes, data_len: int) -> None: # For information about computing this, see # https://tools.ietf.org/html/rfc3610#section-2.1 l_val = 15 - len(nonce) if 2 ** (8 * l_val) < data_len: raise ValueError("Data too long for nonce") - def _check_params(self, nonce: bytes, data: bytes, associated_data: bytes): + def _check_params( + self, nonce: bytes, data: bytes, associated_data: bytes + ) -> None: utils._check_byteslike("nonce", nonce) utils._check_bytes("data", data) utils._check_bytes("associated_data", associated_data) diff --git a/src/cryptography/hazmat/primitives/ciphers/algorithms.py b/src/cryptography/hazmat/primitives/ciphers/algorithms.py index 2fafa8ead883..ba3c968e0241 100644 --- a/src/cryptography/hazmat/primitives/ciphers/algorithms.py +++ b/src/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -11,7 +11,7 @@ from cryptography.hazmat.primitives.ciphers.modes import ModeWithNonce -def _verify_key_size(algorithm: CipherAlgorithm, key: bytes): +def _verify_key_size(algorithm: CipherAlgorithm, key: bytes) -> bytes: # Verify that the key is instance of bytes utils._check_byteslike("key", key) diff --git a/src/cryptography/hazmat/primitives/ciphers/base.py b/src/cryptography/hazmat/primitives/ciphers/base.py index 6f02597a725b..7261a275b42e 100644 --- a/src/cryptography/hazmat/primitives/ciphers/base.py +++ b/src/cryptography/hazmat/primitives/ciphers/base.py @@ -15,7 +15,7 @@ _Reasons, ) from cryptography.hazmat.backends import _get_backend -from cryptography.hazmat.backends.interfaces import CipherBackend +from cryptography.hazmat.backends.interfaces import Backend, CipherBackend from cryptography.hazmat.primitives._cipheralgorithm import CipherAlgorithm from cryptography.hazmat.primitives.ciphers import modes @@ -81,7 +81,7 @@ def __init__( self, algorithm: CipherAlgorithm, mode: typing.Optional[modes.Mode], - backend=None, + backend: typing.Optional[Backend] = None, ): backend = _get_backend(backend) if not isinstance(backend, CipherBackend): @@ -161,7 +161,7 @@ def __init__(self, ctx): self._tag = None self._updated = False - def _check_limit(self, data_size: int): + def _check_limit(self, data_size: int) -> None: if self._ctx is None: raise AlreadyFinalized("Context was already finalized.") self._updated = True diff --git a/src/cryptography/hazmat/primitives/ciphers/modes.py b/src/cryptography/hazmat/primitives/ciphers/modes.py index ec14412e53c4..43ddc6d24678 100644 --- a/src/cryptography/hazmat/primitives/ciphers/modes.py +++ b/src/cryptography/hazmat/primitives/ciphers/modes.py @@ -73,7 +73,7 @@ def _check_iv_length(self, algorithm): ) -def _check_nonce_length(nonce: bytes, name: str, algorithm): +def _check_nonce_length(nonce: bytes, name: str, algorithm) -> None: if len(nonce) * 8 != algorithm.block_size: raise ValueError( "Invalid nonce size ({}) for {}.".format(len(nonce), name) @@ -114,7 +114,7 @@ def __init__(self, tweak: bytes): def tweak(self) -> bytes: return self._tweak - def validate_for_algorithm(self, algorithm: CipherAlgorithm): + def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: if algorithm.key_size not in (256, 512): raise ValueError( "The XTS specification requires a 256-bit key for AES-128-XTS" @@ -181,7 +181,7 @@ def __init__(self, nonce: bytes): def nonce(self) -> bytes: return self._nonce - def validate_for_algorithm(self, algorithm: CipherAlgorithm): + def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: _check_aes_key_length(self, algorithm) _check_nonce_length(self.nonce, self.name, algorithm) @@ -227,5 +227,5 @@ def tag(self) -> typing.Optional[bytes]: def initialization_vector(self) -> bytes: return self._initialization_vector - def validate_for_algorithm(self, algorithm: CipherAlgorithm): + def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: _check_aes_key_length(self, algorithm) diff --git a/src/cryptography/hazmat/primitives/cmac.py b/src/cryptography/hazmat/primitives/cmac.py index 1ebdb052c69d..d6dc7cff6e7b 100644 --- a/src/cryptography/hazmat/primitives/cmac.py +++ b/src/cryptography/hazmat/primitives/cmac.py @@ -3,6 +3,8 @@ # for complete details. +import typing + from cryptography import utils from cryptography.exceptions import ( AlreadyFinalized, @@ -10,13 +12,16 @@ _Reasons, ) from cryptography.hazmat.backends import _get_backend -from cryptography.hazmat.backends.interfaces import CMACBackend +from cryptography.hazmat.backends.interfaces import Backend, CMACBackend from cryptography.hazmat.primitives import ciphers class CMAC(object): def __init__( - self, algorithm: ciphers.BlockCipherAlgorithm, backend=None, ctx=None + self, + algorithm: ciphers.BlockCipherAlgorithm, + backend: typing.Optional[Backend] = None, + ctx=None, ): backend = _get_backend(backend) if not isinstance(backend, CMACBackend): diff --git a/src/cryptography/hazmat/primitives/hashes.py b/src/cryptography/hazmat/primitives/hashes.py index 6552fb95de68..898017692eed 100644 --- a/src/cryptography/hazmat/primitives/hashes.py +++ b/src/cryptography/hazmat/primitives/hashes.py @@ -12,7 +12,7 @@ _Reasons, ) from cryptography.hazmat.backends import _get_backend -from cryptography.hazmat.backends.interfaces import HashBackend +from cryptography.hazmat.backends.interfaces import Backend, HashBackend class HashAlgorithm(metaclass=abc.ABCMeta): @@ -69,7 +69,12 @@ class ExtendableOutputFunction(metaclass=abc.ABCMeta): class Hash(HashContext): - def __init__(self, algorithm: HashAlgorithm, backend=None, ctx=None): + def __init__( + self, + algorithm: HashAlgorithm, + backend: typing.Optional[Backend] = None, + ctx: typing.Optional["HashContext"] = None, + ): backend = _get_backend(backend) if not isinstance(backend, HashBackend): raise UnsupportedAlgorithm( diff --git a/src/cryptography/hazmat/primitives/hmac.py b/src/cryptography/hazmat/primitives/hmac.py index 927fb87bdf53..540d6a24bfd9 100644 --- a/src/cryptography/hazmat/primitives/hmac.py +++ b/src/cryptography/hazmat/primitives/hmac.py @@ -3,6 +3,8 @@ # for complete details. +import typing + from cryptography import utils from cryptography.exceptions import ( AlreadyFinalized, @@ -10,7 +12,7 @@ _Reasons, ) from cryptography.hazmat.backends import _get_backend -from cryptography.hazmat.backends.interfaces import HMACBackend +from cryptography.hazmat.backends.interfaces import Backend, HMACBackend from cryptography.hazmat.primitives import hashes @@ -19,7 +21,7 @@ def __init__( self, key: bytes, algorithm: hashes.HashAlgorithm, - backend=None, + backend: typing.Optional[Backend] = None, ctx=None, ): backend = _get_backend(backend) diff --git a/src/cryptography/hazmat/primitives/kdf/concatkdf.py b/src/cryptography/hazmat/primitives/kdf/concatkdf.py index 6ec4cbd372b4..be86388d4652 100644 --- a/src/cryptography/hazmat/primitives/kdf/concatkdf.py +++ b/src/cryptography/hazmat/primitives/kdf/concatkdf.py @@ -14,8 +14,11 @@ _Reasons, ) from cryptography.hazmat.backends import _get_backend -from cryptography.hazmat.backends.interfaces import HMACBackend -from cryptography.hazmat.backends.interfaces import HashBackend +from cryptography.hazmat.backends.interfaces import ( + Backend, + HMACBackend, + HashBackend, +) from cryptography.hazmat.primitives import constant_time, hashes, hmac from cryptography.hazmat.primitives.kdf import KeyDerivationFunction @@ -28,7 +31,7 @@ def _common_args_checks( algorithm: hashes.HashAlgorithm, length: int, otherinfo: typing.Optional[bytes], -): +) -> None: max_length = algorithm.digest_size * (2 ** 32 - 1) if length > max_length: raise ValueError( @@ -67,7 +70,7 @@ def __init__( algorithm: hashes.HashAlgorithm, length: int, otherinfo: typing.Optional[bytes], - backend=None, + backend: typing.Optional[Backend] = None, ): backend = _get_backend(backend) @@ -107,7 +110,7 @@ def __init__( length: int, salt: typing.Optional[bytes], otherinfo: typing.Optional[bytes], - backend=None, + backend: typing.Optional[Backend] = None, ): backend = _get_backend(backend) diff --git a/src/cryptography/hazmat/primitives/kdf/hkdf.py b/src/cryptography/hazmat/primitives/kdf/hkdf.py index 6b65b0c0717b..9f5cd5bc2c7d 100644 --- a/src/cryptography/hazmat/primitives/kdf/hkdf.py +++ b/src/cryptography/hazmat/primitives/kdf/hkdf.py @@ -13,7 +13,7 @@ _Reasons, ) from cryptography.hazmat.backends import _get_backend -from cryptography.hazmat.backends.interfaces import HMACBackend +from cryptography.hazmat.backends.interfaces import Backend, HMACBackend from cryptography.hazmat.primitives import constant_time, hashes, hmac from cryptography.hazmat.primitives.kdf import KeyDerivationFunction @@ -25,7 +25,7 @@ def __init__( length: int, salt: typing.Optional[bytes], info: typing.Optional[bytes], - backend=None, + backend: typing.Optional[Backend] = None, ): backend = _get_backend(backend) if not isinstance(backend, HMACBackend): @@ -67,7 +67,7 @@ def __init__( algorithm: hashes.HashAlgorithm, length: int, info: typing.Optional[bytes], - backend=None, + backend: typing.Optional[Backend] = None, ): backend = _get_backend(backend) if not isinstance(backend, HMACBackend): diff --git a/src/cryptography/hazmat/primitives/kdf/kbkdf.py b/src/cryptography/hazmat/primitives/kdf/kbkdf.py index ac36474fd7ae..eee2200be4bf 100644 --- a/src/cryptography/hazmat/primitives/kdf/kbkdf.py +++ b/src/cryptography/hazmat/primitives/kdf/kbkdf.py @@ -14,7 +14,7 @@ _Reasons, ) from cryptography.hazmat.backends import _get_backend -from cryptography.hazmat.backends.interfaces import HMACBackend +from cryptography.hazmat.backends.interfaces import Backend, HMACBackend from cryptography.hazmat.primitives import constant_time, hashes, hmac from cryptography.hazmat.primitives.kdf import KeyDerivationFunction @@ -40,7 +40,7 @@ def __init__( label: typing.Optional[bytes], context: typing.Optional[bytes], fixed: typing.Optional[bytes], - backend=None, + backend: typing.Optional[Backend] = None, ): backend = _get_backend(backend) if not isinstance(backend, HMACBackend): diff --git a/src/cryptography/hazmat/primitives/kdf/pbkdf2.py b/src/cryptography/hazmat/primitives/kdf/pbkdf2.py index d1c10af53591..f68cef43affd 100644 --- a/src/cryptography/hazmat/primitives/kdf/pbkdf2.py +++ b/src/cryptography/hazmat/primitives/kdf/pbkdf2.py @@ -3,6 +3,8 @@ # for complete details. +import typing + from cryptography import utils from cryptography.exceptions import ( AlreadyFinalized, @@ -11,7 +13,7 @@ _Reasons, ) from cryptography.hazmat.backends import _get_backend -from cryptography.hazmat.backends.interfaces import PBKDF2HMACBackend +from cryptography.hazmat.backends.interfaces import Backend, PBKDF2HMACBackend from cryptography.hazmat.primitives import constant_time, hashes from cryptography.hazmat.primitives.kdf import KeyDerivationFunction @@ -23,7 +25,7 @@ def __init__( length: int, salt: bytes, iterations: int, - backend=None, + backend: typing.Optional[Backend] = None, ): backend = _get_backend(backend) if not isinstance(backend, PBKDF2HMACBackend): diff --git a/src/cryptography/hazmat/primitives/kdf/scrypt.py b/src/cryptography/hazmat/primitives/kdf/scrypt.py index 7547dca5c095..9c3a9187da99 100644 --- a/src/cryptography/hazmat/primitives/kdf/scrypt.py +++ b/src/cryptography/hazmat/primitives/kdf/scrypt.py @@ -4,6 +4,7 @@ import sys +import typing from cryptography import utils from cryptography.exceptions import ( @@ -13,7 +14,7 @@ _Reasons, ) from cryptography.hazmat.backends import _get_backend -from cryptography.hazmat.backends.interfaces import ScryptBackend +from cryptography.hazmat.backends.interfaces import Backend, ScryptBackend from cryptography.hazmat.primitives import constant_time from cryptography.hazmat.primitives.kdf import KeyDerivationFunction @@ -25,7 +26,13 @@ class Scrypt(KeyDerivationFunction): def __init__( - self, salt: bytes, length: int, n: int, r: int, p: int, backend=None + self, + salt: bytes, + length: int, + n: int, + r: int, + p: int, + backend: typing.Optional[Backend] = None, ): backend = _get_backend(backend) if not isinstance(backend, ScryptBackend): diff --git a/src/cryptography/hazmat/primitives/kdf/x963kdf.py b/src/cryptography/hazmat/primitives/kdf/x963kdf.py index 1a67d3ee0c4f..d575d86adf12 100644 --- a/src/cryptography/hazmat/primitives/kdf/x963kdf.py +++ b/src/cryptography/hazmat/primitives/kdf/x963kdf.py @@ -14,7 +14,7 @@ _Reasons, ) from cryptography.hazmat.backends import _get_backend -from cryptography.hazmat.backends.interfaces import HashBackend +from cryptography.hazmat.backends.interfaces import Backend, HashBackend from cryptography.hazmat.primitives import constant_time, hashes from cryptography.hazmat.primitives.kdf import KeyDerivationFunction @@ -29,7 +29,7 @@ def __init__( algorithm: hashes.HashAlgorithm, length: int, sharedinfo: typing.Optional[bytes], - backend=None, + backend: typing.Optional[Backend] = None, ): backend = _get_backend(backend) diff --git a/src/cryptography/hazmat/primitives/keywrap.py b/src/cryptography/hazmat/primitives/keywrap.py index 52d49d35f2eb..b8de85dd434a 100644 --- a/src/cryptography/hazmat/primitives/keywrap.py +++ b/src/cryptography/hazmat/primitives/keywrap.py @@ -7,6 +7,7 @@ import typing from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.backends.interfaces import Backend from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import ECB @@ -14,7 +15,10 @@ def _wrap_core( - wrapping_key: bytes, a: bytes, r: typing.List[bytes], backend + wrapping_key: bytes, + a: bytes, + r: typing.List[bytes], + backend: Backend, ) -> bytes: # RFC 3394 Key Wrap - 2.2.1 (index method) encryptor = Cipher(AES(wrapping_key), ECB(), backend).encryptor() @@ -37,7 +41,9 @@ def _wrap_core( def aes_key_wrap( - wrapping_key: bytes, key_to_wrap: bytes, backend=None + wrapping_key: bytes, + key_to_wrap: bytes, + backend: typing.Optional[Backend] = None, ) -> bytes: backend = _get_backend(backend) if len(wrapping_key) not in [16, 24, 32]: @@ -55,7 +61,10 @@ def aes_key_wrap( def _unwrap_core( - wrapping_key: bytes, a: bytes, r: typing.List[bytes], backend + wrapping_key: bytes, + a: bytes, + r: typing.List[bytes], + backend: Backend, ) -> typing.Tuple[bytes, typing.List[bytes]]: # Implement RFC 3394 Key Unwrap - 2.2.2 (index method) decryptor = Cipher(AES(wrapping_key), ECB(), backend).decryptor() @@ -80,7 +89,9 @@ def _unwrap_core( def aes_key_wrap_with_padding( - wrapping_key: bytes, key_to_wrap: bytes, backend=None + wrapping_key: bytes, + key_to_wrap: bytes, + backend: typing.Optional[Backend] = None, ) -> bytes: backend = _get_backend(backend) if len(wrapping_key) not in [16, 24, 32]: @@ -102,7 +113,9 @@ def aes_key_wrap_with_padding( def aes_key_unwrap_with_padding( - wrapping_key: bytes, wrapped_key: bytes, backend=None + wrapping_key: bytes, + wrapped_key: bytes, + backend: typing.Optional[Backend] = None, ) -> bytes: backend = _get_backend(backend) if len(wrapped_key) < 16: @@ -147,7 +160,9 @@ def aes_key_unwrap_with_padding( def aes_key_unwrap( - wrapping_key: bytes, wrapped_key: bytes, backend=None + wrapping_key: bytes, + wrapped_key: bytes, + backend: typing.Optional[Backend] = None, ) -> bytes: backend = _get_backend(backend) if len(wrapped_key) < 24: diff --git a/src/cryptography/hazmat/primitives/serialization/base.py b/src/cryptography/hazmat/primitives/serialization/base.py index 9f7531db2f7a..30679c87ef0c 100644 --- a/src/cryptography/hazmat/primitives/serialization/base.py +++ b/src/cryptography/hazmat/primitives/serialization/base.py @@ -10,38 +10,51 @@ _PUBLIC_KEY_TYPES, ) from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.backends.interfaces import Backend from cryptography.hazmat.primitives.asymmetric import dh def load_pem_private_key( - data: bytes, password: typing.Optional[bytes], backend=None + data: bytes, + password: typing.Optional[bytes], + backend: typing.Optional[Backend] = None, ) -> _PRIVATE_KEY_TYPES: backend = _get_backend(backend) return backend.load_pem_private_key(data, password) -def load_pem_public_key(data: bytes, backend=None) -> _PUBLIC_KEY_TYPES: +def load_pem_public_key( + data: bytes, backend: typing.Optional[Backend] = None +) -> _PUBLIC_KEY_TYPES: backend = _get_backend(backend) return backend.load_pem_public_key(data) -def load_pem_parameters(data: bytes, backend=None) -> "dh.DHParameters": +def load_pem_parameters( + data: bytes, backend: typing.Optional[Backend] = None +) -> "dh.DHParameters": backend = _get_backend(backend) return backend.load_pem_parameters(data) def load_der_private_key( - data: bytes, password: typing.Optional[bytes], backend=None + data: bytes, + password: typing.Optional[bytes], + backend: typing.Optional[Backend] = None, ) -> _PRIVATE_KEY_TYPES: backend = _get_backend(backend) return backend.load_der_private_key(data, password) -def load_der_public_key(data: bytes, backend=None) -> _PUBLIC_KEY_TYPES: +def load_der_public_key( + data: bytes, backend: typing.Optional[Backend] = None +) -> _PUBLIC_KEY_TYPES: backend = _get_backend(backend) return backend.load_der_public_key(data) -def load_der_parameters(data: bytes, backend=None) -> "dh.DHParameters": +def load_der_parameters( + data: bytes, backend: typing.Optional[Backend] = None +) -> "dh.DHParameters": backend = _get_backend(backend) return backend.load_der_parameters(data) diff --git a/src/cryptography/hazmat/primitives/serialization/pkcs12.py b/src/cryptography/hazmat/primitives/serialization/pkcs12.py index 1dabfca5534a..215f601279aa 100644 --- a/src/cryptography/hazmat/primitives/serialization/pkcs12.py +++ b/src/cryptography/hazmat/primitives/serialization/pkcs12.py @@ -6,6 +6,7 @@ from cryptography import x509 from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.backends.interfaces import Backend from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa @@ -18,7 +19,9 @@ def load_key_and_certificates( - data: bytes, password: typing.Optional[bytes], backend=None + data: bytes, + password: typing.Optional[bytes], + backend: typing.Optional[Backend] = None, ) -> typing.Tuple[ typing.Optional[_ALLOWED_PKCS12_TYPES], typing.Optional[x509.Certificate], diff --git a/src/cryptography/hazmat/primitives/serialization/pkcs7.py b/src/cryptography/hazmat/primitives/serialization/pkcs7.py index bcd9e330d58d..c6b2eec21092 100644 --- a/src/cryptography/hazmat/primitives/serialization/pkcs7.py +++ b/src/cryptography/hazmat/primitives/serialization/pkcs7.py @@ -7,6 +7,7 @@ from cryptography import x509 from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.backends.interfaces import Backend from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ec, rsa from cryptography.utils import _check_byteslike @@ -104,7 +105,7 @@ def sign( self, encoding: serialization.Encoding, options: typing.Iterable[PKCS7Options], - backend=None, + backend: typing.Optional[Backend] = None, ) -> bytes: if len(self._signers) == 0: raise ValueError("Must have at least one signer") diff --git a/src/cryptography/hazmat/primitives/serialization/ssh.py b/src/cryptography/hazmat/primitives/serialization/ssh.py index f276c1e84a2d..b36065dc7518 100644 --- a/src/cryptography/hazmat/primitives/serialization/ssh.py +++ b/src/cryptography/hazmat/primitives/serialization/ssh.py @@ -13,6 +13,7 @@ from cryptography import utils from cryptography.exceptions import UnsupportedAlgorithm from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.backends.interfaces import Backend from cryptography.hazmat.primitives.asymmetric import dsa, ec, ed25519, rsa from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.serialization import ( @@ -474,7 +475,9 @@ def _lookup_kformat(key_type): def load_ssh_private_key( - data: bytes, password: typing.Optional[bytes], backend=None + data: bytes, + password: typing.Optional[bytes], + backend: typing.Optional[Backend] = None, ) -> _SSH_PRIVATE_KEY_TYPES: """Load private key from OpenSSH custom encoding.""" utils._check_byteslike("data", data) @@ -552,7 +555,7 @@ def load_ssh_private_key( def serialize_ssh_private_key( private_key: _SSH_PRIVATE_KEY_TYPES, password: typing.Optional[bytes] = None, -): +) -> bytes: """Serialize private key with OpenSSH custom encoding.""" if password is not None: utils._check_bytes("password", password) @@ -584,7 +587,7 @@ def serialize_ssh_private_key( salt = os.urandom(16) f_kdfoptions.put_sshstr(salt) f_kdfoptions.put_u32(rounds) - backend = _get_backend(None) + backend: Backend = _get_backend(None) ciph = _init_cipher(ciphername, password, salt, rounds, backend) else: ciphername = kdfname = _NONE @@ -642,7 +645,9 @@ def serialize_ssh_private_key( ] -def load_ssh_public_key(data: bytes, backend=None) -> _SSH_PUBLIC_KEY_TYPES: +def load_ssh_public_key( + data: bytes, backend: typing.Optional[Backend] = None +) -> _SSH_PUBLIC_KEY_TYPES: """Load public key from OpenSSH one-line format.""" backend = _get_backend(backend) utils._check_byteslike("data", data) diff --git a/src/cryptography/hazmat/primitives/twofactor/hotp.py b/src/cryptography/hazmat/primitives/twofactor/hotp.py index 26e786fd4c37..b4b2b41d0ad9 100644 --- a/src/cryptography/hazmat/primitives/twofactor/hotp.py +++ b/src/cryptography/hazmat/primitives/twofactor/hotp.py @@ -10,7 +10,7 @@ from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.hazmat.backends import _get_backend -from cryptography.hazmat.backends.interfaces import HMACBackend +from cryptography.hazmat.backends.interfaces import Backend, HMACBackend from cryptography.hazmat.primitives import constant_time, hmac from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512 from cryptography.hazmat.primitives.twofactor import InvalidToken @@ -24,7 +24,7 @@ def _generate_uri( type_name: str, account_name: str, issuer: typing.Optional[str], - extra_parameters, + extra_parameters: typing.List[typing.Tuple[str, int]], ) -> str: parameters = [ ("digits", hotp._length), @@ -55,9 +55,9 @@ def __init__( key: bytes, length: int, algorithm: _ALLOWED_HASH_TYPES, - backend=None, + backend: typing.Optional[Backend] = None, enforce_key_length: bool = True, - ): + ) -> None: backend = _get_backend(backend) if not isinstance(backend, HMACBackend): raise UnsupportedAlgorithm( diff --git a/src/cryptography/hazmat/primitives/twofactor/totp.py b/src/cryptography/hazmat/primitives/twofactor/totp.py index 92bf6496867d..a88008209bf2 100644 --- a/src/cryptography/hazmat/primitives/twofactor/totp.py +++ b/src/cryptography/hazmat/primitives/twofactor/totp.py @@ -6,7 +6,7 @@ from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.hazmat.backends import _get_backend -from cryptography.hazmat.backends.interfaces import HMACBackend +from cryptography.hazmat.backends.interfaces import Backend, HMACBackend from cryptography.hazmat.primitives import constant_time from cryptography.hazmat.primitives.twofactor import InvalidToken from cryptography.hazmat.primitives.twofactor.hotp import ( @@ -23,7 +23,7 @@ def __init__( length: int, algorithm: _ALLOWED_HASH_TYPES, time_step: int, - backend=None, + backend: typing.Optional[Backend] = None, enforce_key_length: bool = True, ): backend = _get_backend(backend) diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index e0abd4a8ab6c..a8fd7d01a7c9 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -24,12 +24,12 @@ class CryptographyDeprecationWarning(UserWarning): DeprecatedIn34 = CryptographyDeprecationWarning -def _check_bytes(name: str, value: bytes): +def _check_bytes(name: str, value: bytes) -> None: if not isinstance(value, bytes): raise TypeError("{} must be bytes".format(name)) -def _check_byteslike(name: str, value: bytes): +def _check_byteslike(name: str, value: bytes) -> None: try: memoryview(value) except TypeError: diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index 5505fa3b6d5e..1e98b469c1bb 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -11,6 +11,7 @@ from cryptography.hazmat._types import _PRIVATE_KEY_TYPES, _PUBLIC_KEY_TYPES from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.backends.interfaces import Backend from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ( dsa, @@ -35,7 +36,7 @@ def __init__(self, msg, oid): def _reject_duplicate_extension( extension: Extension, extensions: typing.List[Extension] -): +) -> None: # This is quadratic in the number of extensions for e in extensions: if e.oid == extension.oid: @@ -45,7 +46,7 @@ def _reject_duplicate_extension( def _reject_duplicate_attribute( oid: ObjectIdentifier, attributes: typing.List[typing.Tuple[ObjectIdentifier, bytes]], -): +) -> None: # This is quadratic in the number of attributes for attr_oid, _ in attributes: if attr_oid == oid: @@ -394,32 +395,44 @@ def get_attribute_for_oid(self, oid: ObjectIdentifier) -> bytes: """ -def load_pem_x509_certificate(data: bytes, backend=None) -> Certificate: +def load_pem_x509_certificate( + data: bytes, backend: typing.Optional[Backend] = None +) -> Certificate: backend = _get_backend(backend) return backend.load_pem_x509_certificate(data) -def load_der_x509_certificate(data: bytes, backend=None) -> Certificate: +def load_der_x509_certificate( + data: bytes, backend: typing.Optional[Backend] = None +) -> Certificate: backend = _get_backend(backend) return backend.load_der_x509_certificate(data) -def load_pem_x509_csr(data: bytes, backend=None) -> CertificateSigningRequest: +def load_pem_x509_csr( + data: bytes, backend: typing.Optional[Backend] = None +) -> CertificateSigningRequest: backend = _get_backend(backend) return backend.load_pem_x509_csr(data) -def load_der_x509_csr(data: bytes, backend=None) -> CertificateSigningRequest: +def load_der_x509_csr( + data: bytes, backend: typing.Optional[Backend] = None +) -> CertificateSigningRequest: backend = _get_backend(backend) return backend.load_der_x509_csr(data) -def load_pem_x509_crl(data: bytes, backend=None) -> CertificateRevocationList: +def load_pem_x509_crl( + data: bytes, backend: typing.Optional[Backend] = None +) -> CertificateRevocationList: backend = _get_backend(backend) return backend.load_pem_x509_crl(data) -def load_der_x509_crl(data: bytes, backend=None) -> CertificateRevocationList: +def load_der_x509_crl( + data: bytes, backend: typing.Optional[Backend] = None +) -> CertificateRevocationList: backend = _get_backend(backend) return backend.load_der_x509_crl(data) @@ -433,7 +446,7 @@ def __init__(self, subject_name=None, extensions=[], attributes=[]): self._extensions = extensions self._attributes = attributes - def subject_name(self, name: Name): + def subject_name(self, name: Name) -> "CertificateSigningRequestBuilder": """ Sets the certificate requestor's distinguished name. """ @@ -445,7 +458,9 @@ def subject_name(self, name: Name): name, self._extensions, self._attributes ) - def add_extension(self, extval: ExtensionType, critical: bool): + def add_extension( + self, extval: ExtensionType, critical: bool + ) -> "CertificateSigningRequestBuilder": """ Adds an X.509 extension to the certificate request. """ @@ -461,7 +476,9 @@ def add_extension(self, extval: ExtensionType, critical: bool): self._attributes, ) - def add_attribute(self, oid: ObjectIdentifier, value: bytes): + def add_attribute( + self, oid: ObjectIdentifier, value: bytes + ) -> "CertificateSigningRequestBuilder": """ Adds an X.509 attribute with an OID and associated value. """ @@ -482,8 +499,8 @@ def add_attribute(self, oid: ObjectIdentifier, value: bytes): def sign( self, private_key: _PRIVATE_KEY_TYPES, - algorithm: hashes.HashAlgorithm, - backend=None, + algorithm: typing.Optional[hashes.HashAlgorithm], + backend: typing.Optional[Backend] = None, ) -> CertificateSigningRequest: """ Signs the request using the requestor's private key. @@ -504,7 +521,7 @@ def __init__( not_valid_before=None, not_valid_after=None, extensions=[], - ): + ) -> None: self._version = Version.v3 self._issuer_name = issuer_name self._subject_name = subject_name @@ -514,7 +531,7 @@ def __init__( self._not_valid_after = not_valid_after self._extensions = extensions - def issuer_name(self, name: Name): + def issuer_name(self, name: Name) -> "CertificateBuilder": """ Sets the CA's distinguished name. """ @@ -532,7 +549,7 @@ def issuer_name(self, name: Name): self._extensions, ) - def subject_name(self, name: Name): + def subject_name(self, name: Name) -> "CertificateBuilder": """ Sets the requestor's distinguished name. """ @@ -553,7 +570,7 @@ def subject_name(self, name: Name): def public_key( self, key: _PUBLIC_KEY_TYPES, - ): + ) -> "CertificateBuilder": """ Sets the requestor's public key (as found in the signing request). """ @@ -584,7 +601,7 @@ def public_key( self._extensions, ) - def serial_number(self, number: int): + def serial_number(self, number: int) -> "CertificateBuilder": """ Sets the certificate serial number. """ @@ -611,7 +628,9 @@ def serial_number(self, number: int): self._extensions, ) - def not_valid_before(self, time: datetime.datetime): + def not_valid_before( + self, time: datetime.datetime + ) -> "CertificateBuilder": """ Sets the certificate activation time. """ @@ -640,7 +659,7 @@ def not_valid_before(self, time: datetime.datetime): self._extensions, ) - def not_valid_after(self, time: datetime.datetime): + def not_valid_after(self, time: datetime.datetime) -> "CertificateBuilder": """ Sets the certificate expiration time. """ @@ -672,7 +691,9 @@ def not_valid_after(self, time: datetime.datetime): self._extensions, ) - def add_extension(self, extval: ExtensionType, critical: bool): + def add_extension( + self, extval: ExtensionType, critical: bool + ) -> "CertificateBuilder": """ Adds an X.509 extension to the certificate. """ @@ -695,8 +716,8 @@ def add_extension(self, extval: ExtensionType, critical: bool): def sign( self, private_key: _PRIVATE_KEY_TYPES, - algorithm: hashes.HashAlgorithm, - backend=None, + algorithm: typing.Optional[hashes.HashAlgorithm], + backend: typing.Optional[Backend] = None, ) -> Certificate: """ Signs the certificate using the CA's private key. @@ -738,7 +759,9 @@ def __init__( self._extensions = extensions self._revoked_certificates = revoked_certificates - def issuer_name(self, issuer_name: Name): + def issuer_name( + self, issuer_name: Name + ) -> "CertificateRevocationListBuilder": if not isinstance(issuer_name, Name): raise TypeError("Expecting x509.Name object.") if self._issuer_name is not None: @@ -751,7 +774,9 @@ def issuer_name(self, issuer_name: Name): self._revoked_certificates, ) - def last_update(self, last_update: datetime.datetime): + def last_update( + self, last_update: datetime.datetime + ) -> "CertificateRevocationListBuilder": if not isinstance(last_update, datetime.datetime): raise TypeError("Expecting datetime object.") if self._last_update is not None: @@ -773,7 +798,9 @@ def last_update(self, last_update: datetime.datetime): self._revoked_certificates, ) - def next_update(self, next_update: datetime.datetime): + def next_update( + self, next_update: datetime.datetime + ) -> "CertificateRevocationListBuilder": if not isinstance(next_update, datetime.datetime): raise TypeError("Expecting datetime object.") if self._next_update is not None: @@ -795,7 +822,9 @@ def next_update(self, next_update: datetime.datetime): self._revoked_certificates, ) - def add_extension(self, extval: ExtensionType, critical: bool): + def add_extension( + self, extval: ExtensionType, critical: bool + ) -> "CertificateRevocationListBuilder": """ Adds an X.509 extension to the certificate revocation list. """ @@ -812,7 +841,9 @@ def add_extension(self, extval: ExtensionType, critical: bool): self._revoked_certificates, ) - def add_revoked_certificate(self, revoked_certificate: RevokedCertificate): + def add_revoked_certificate( + self, revoked_certificate: RevokedCertificate + ) -> "CertificateRevocationListBuilder": """ Adds a revoked certificate to the CRL. """ @@ -830,8 +861,8 @@ def add_revoked_certificate(self, revoked_certificate: RevokedCertificate): def sign( self, private_key: _PRIVATE_KEY_TYPES, - algorithm: hashes.HashAlgorithm, - backend=None, + algorithm: typing.Optional[hashes.HashAlgorithm], + backend: typing.Optional[Backend] = None, ) -> CertificateRevocationList: backend = _get_backend(backend) if self._issuer_name is None: @@ -854,7 +885,7 @@ def __init__( self._revocation_date = revocation_date self._extensions = extensions - def serial_number(self, number: int): + def serial_number(self, number: int) -> "RevokedCertificateBuilder": if not isinstance(number, int): raise TypeError("Serial number must be of integral type.") if self._serial_number is not None: @@ -872,7 +903,9 @@ def serial_number(self, number: int): number, self._revocation_date, self._extensions ) - def revocation_date(self, time: datetime.datetime): + def revocation_date( + self, time: datetime.datetime + ) -> "RevokedCertificateBuilder": if not isinstance(time, datetime.datetime): raise TypeError("Expecting datetime object.") if self._revocation_date is not None: @@ -886,7 +919,9 @@ def revocation_date(self, time: datetime.datetime): self._serial_number, time, self._extensions ) - def add_extension(self, extval: ExtensionType, critical: bool): + def add_extension( + self, extval: ExtensionType, critical: bool + ) -> "RevokedCertificateBuilder": if not isinstance(extval, ExtensionType): raise TypeError("extension must be an ExtensionType") @@ -898,7 +933,9 @@ def add_extension(self, extval: ExtensionType, critical: bool): self._extensions + [extension], ) - def build(self, backend=None) -> RevokedCertificate: + def build( + self, backend: typing.Optional[Backend] = None + ) -> RevokedCertificate: backend = _get_backend(backend) if self._serial_number is None: raise ValueError("A revoked certificate must have a serial number") diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py index 5c171ad615c1..5f0b88e1794d 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -6,6 +6,7 @@ from enum import Enum from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.backends.interfaces import Backend from cryptography.x509.oid import NameOID, ObjectIdentifier @@ -233,7 +234,7 @@ def get_attributes_for_oid( def rdns(self) -> typing.List[RelativeDistinguishedName]: return self._attributes - def public_bytes(self, backend=None) -> bytes: + def public_bytes(self, backend: typing.Optional[Backend] = None) -> bytes: backend = _get_backend(backend) return backend.x509_name_bytes(self) diff --git a/tests/hazmat/backends/test_no_backend.py b/tests/hazmat/backends/test_no_backend.py index 9c01d1368227..282238d70843 100644 --- a/tests/hazmat/backends/test_no_backend.py +++ b/tests/hazmat/backends/test_no_backend.py @@ -12,4 +12,4 @@ def test_get_backend_no_backend(): def test_get_backend(): faux_backend = object() - assert _get_backend(faux_backend) is faux_backend + assert _get_backend(faux_backend) is faux_backend # type: ignore[arg-type] diff --git a/tests/hazmat/primitives/test_ciphers.py b/tests/hazmat/primitives/test_ciphers.py index f00282eccdeb..99aa4af3f919 100644 --- a/tests/hazmat/primitives/test_ciphers.py +++ b/tests/hazmat/primitives/test_ciphers.py @@ -202,7 +202,11 @@ def test_invalid_backend(): pretend_backend = object() with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - ciphers.Cipher(AES(b"AAAAAAAAAAAAAAAA"), modes.ECB(), pretend_backend) + ciphers.Cipher( + AES(b"AAAAAAAAAAAAAAAA"), + modes.ECB(), + pretend_backend, # type: ignore[arg-type] + ) @pytest.mark.supported( diff --git a/tests/hazmat/primitives/test_cmac.py b/tests/hazmat/primitives/test_cmac.py index 1c8841ac849e..1d6892540e47 100644 --- a/tests/hazmat/primitives/test_cmac.py +++ b/tests/hazmat/primitives/test_cmac.py @@ -217,4 +217,4 @@ def test_invalid_backend(): pretend_backend = object() with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - CMAC(AES(key), pretend_backend) + CMAC(AES(key), pretend_backend) # type: ignore[arg-type] diff --git a/tests/hazmat/primitives/test_concatkdf.py b/tests/hazmat/primitives/test_concatkdf.py index 18134eecac06..5da47ecc4e0a 100644 --- a/tests/hazmat/primitives/test_concatkdf.py +++ b/tests/hazmat/primitives/test_concatkdf.py @@ -298,6 +298,17 @@ def test_invalid_backend(): pretend_backend = object() with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - ConcatKDFHash(hashes.SHA256(), 16, None, pretend_backend) + ConcatKDFHash( + hashes.SHA256(), + 16, + None, + pretend_backend, # type: ignore[arg-type] + ) with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - ConcatKDFHMAC(hashes.SHA256(), 16, None, None, pretend_backend) + ConcatKDFHMAC( + hashes.SHA256(), + 16, + None, + None, + pretend_backend, # type: ignore[arg-type] + ) diff --git a/tests/hazmat/primitives/test_dh.py b/tests/hazmat/primitives/test_dh.py index b37eca4eba54..17d3a776e7a3 100644 --- a/tests/hazmat/primitives/test_dh.py +++ b/tests/hazmat/primitives/test_dh.py @@ -82,7 +82,7 @@ def test_dh_numbers(): dh.DHPublicNumbers(1, None) # type: ignore[arg-type] with pytest.raises(TypeError): - dh.DHPublicNumbers(None, params) + dh.DHPublicNumbers(None, params) # type:ignore[arg-type] private = dh.DHPrivateNumbers(1, public) @@ -93,7 +93,7 @@ def test_dh_numbers(): dh.DHPrivateNumbers(1, None) # type: ignore[arg-type] with pytest.raises(TypeError): - dh.DHPrivateNumbers(None, public) + dh.DHPrivateNumbers(None, public) # type:ignore[arg-type] def test_dh_parameter_numbers_equality(): @@ -585,7 +585,7 @@ def test_private_bytes_invalid_encoding(self, backend): key = parameters.generate_private_key() with pytest.raises(TypeError): key.private_bytes( - "notencoding", + "notencoding", # type:ignore[arg-type] serialization.PrivateFormat.PKCS8, serialization.NoEncryption(), ) @@ -596,7 +596,7 @@ def test_private_bytes_invalid_format(self, backend): with pytest.raises(ValueError): key.private_bytes( serialization.Encoding.PEM, - "invalidformat", + "invalidformat", # type:ignore[arg-type] serialization.NoEncryption(), ) @@ -607,7 +607,7 @@ def test_private_bytes_invalid_encryption_algorithm(self, backend): key.private_bytes( serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, - "notanencalg", + "notanencalg", # type:ignore[arg-type] ) def test_private_bytes_unsupported_encryption_type(self, backend): @@ -735,7 +735,8 @@ def test_public_bytes_invalid_encoding(self, backend): key = parameters.generate_private_key().public_key() with pytest.raises(TypeError): key.public_bytes( - "notencoding", serialization.PublicFormat.SubjectPublicKeyInfo + "notencoding", # type:ignore[arg-type] + serialization.PublicFormat.SubjectPublicKeyInfo, ) def test_public_bytes_pkcs1_unsupported(self, backend): @@ -888,13 +889,17 @@ def test_parameter_bytes_invalid_encoding(self, backend): parameters = FFDH3072_P.parameters(backend) with pytest.raises(TypeError): parameters.parameter_bytes( - "notencoding", serialization.ParameterFormat.PKCS3 + "notencoding", # type:ignore[arg-type] + serialization.ParameterFormat.PKCS3, ) def test_parameter_bytes_invalid_format(self, backend): parameters = FFDH3072_P.parameters(backend) with pytest.raises(ValueError): - parameters.parameter_bytes(serialization.Encoding.PEM, "notformat") + parameters.parameter_bytes( + serialization.Encoding.PEM, + "notformat", # type: ignore[arg-type] + ) def test_parameter_bytes_openssh_unsupported(self, backend): parameters = FFDH3072_P.parameters(backend) diff --git a/tests/hazmat/primitives/test_hashes.py b/tests/hazmat/primitives/test_hashes.py index 67de7947bb25..e433d9c01900 100644 --- a/tests/hazmat/primitives/test_hashes.py +++ b/tests/hazmat/primitives/test_hashes.py @@ -159,7 +159,7 @@ def test_invalid_backend(): pretend_backend = object() with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - hashes.Hash(hashes.SHA1(), pretend_backend) + hashes.Hash(hashes.SHA1(), pretend_backend) # type:ignore[arg-type] def test_buffer_protocol_hash(backend): diff --git a/tests/hazmat/primitives/test_hkdf.py b/tests/hazmat/primitives/test_hkdf.py index 80b27b9a9150..e5218723c96d 100644 --- a/tests/hazmat/primitives/test_hkdf.py +++ b/tests/hazmat/primitives/test_hkdf.py @@ -217,7 +217,15 @@ def test_invalid_backend(): pretend_backend = object() with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - HKDF(hashes.SHA256(), 16, None, None, pretend_backend) + HKDF( + hashes.SHA256(), + 16, + None, + None, + pretend_backend, # type:ignore[arg-type] + ) with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - HKDFExpand(hashes.SHA256(), 16, None, pretend_backend) + HKDFExpand( + hashes.SHA256(), 16, None, pretend_backend # type:ignore[arg-type] + ) diff --git a/tests/hazmat/primitives/test_hmac.py b/tests/hazmat/primitives/test_hmac.py index 1cbd39c10538..44dd94e05aed 100644 --- a/tests/hazmat/primitives/test_hmac.py +++ b/tests/hazmat/primitives/test_hmac.py @@ -94,4 +94,6 @@ def test_invalid_backend(): pretend_backend = object() with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - hmac.HMAC(b"key", hashes.SHA1(), pretend_backend) + hmac.HMAC( + b"key", hashes.SHA1(), pretend_backend # type:ignore[arg-type] + ) diff --git a/tests/hazmat/primitives/test_kbkdf.py b/tests/hazmat/primitives/test_kbkdf.py index ddbf953b1323..ae9330807140 100644 --- a/tests/hazmat/primitives/test_kbkdf.py +++ b/tests/hazmat/primitives/test_kbkdf.py @@ -268,7 +268,7 @@ def test_invalid_backend(self, backend): b"label", b"context", None, - backend=object(), + backend=object(), # type: ignore[arg-type] ) def test_unicode_error_label(self, backend): diff --git a/tests/hazmat/primitives/test_pbkdf2hmac.py b/tests/hazmat/primitives/test_pbkdf2hmac.py index 8586debe4f1f..0c83c6a01754 100644 --- a/tests/hazmat/primitives/test_pbkdf2hmac.py +++ b/tests/hazmat/primitives/test_pbkdf2hmac.py @@ -67,4 +67,10 @@ def test_invalid_backend(): pretend_backend = object() with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, pretend_backend) + PBKDF2HMAC( + hashes.SHA1(), + 20, + b"salt", + 10, + pretend_backend, # type:ignore[arg-type] + ) diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 9c98dbbab2e7..2c8715b24eb5 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -381,7 +381,9 @@ def test_rsa_generate_invalid_backend(): pretend_backend = object() with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - rsa.generate_private_key(65537, 2048, pretend_backend) + rsa.generate_private_key( + 65537, 2048, pretend_backend # type:ignore[arg-type] + ) class TestRSASignature(object): diff --git a/tests/hazmat/primitives/test_scrypt.py b/tests/hazmat/primitives/test_scrypt.py index 63e6b35ced1f..b87cb220a88f 100644 --- a/tests/hazmat/primitives/test_scrypt.py +++ b/tests/hazmat/primitives/test_scrypt.py @@ -84,7 +84,7 @@ def test_unsupported_backend(self): work_factor, block_size, parallelization_factor, - backend, + backend, # type: ignore[arg-type] ) def test_salt_not_bytes(self, backend): diff --git a/tests/hazmat/primitives/test_x963kdf.py b/tests/hazmat/primitives/test_x963kdf.py index 5254aa006cb3..c0c3c37d26d4 100644 --- a/tests/hazmat/primitives/test_x963kdf.py +++ b/tests/hazmat/primitives/test_x963kdf.py @@ -116,4 +116,9 @@ def test_invalid_backend(): pretend_backend = object() with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - X963KDF(hashes.SHA256(), 16, None, pretend_backend) + X963KDF( + hashes.SHA256(), + 16, + None, + pretend_backend, # type: ignore[arg-type] + ) diff --git a/tests/hazmat/primitives/twofactor/test_hotp.py b/tests/hazmat/primitives/twofactor/test_hotp.py index 979f3f004efc..3e983f83f431 100644 --- a/tests/hazmat/primitives/twofactor/test_hotp.py +++ b/tests/hazmat/primitives/twofactor/test_hotp.py @@ -120,4 +120,6 @@ def test_invalid_backend(): pretend_backend = object() with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - HOTP(secret, 8, hashes.SHA1(), pretend_backend) + HOTP( + secret, 8, hashes.SHA1(), pretend_backend # type: ignore[arg-type] + ) diff --git a/tests/hazmat/primitives/twofactor/test_totp.py b/tests/hazmat/primitives/twofactor/test_totp.py index 0159773399e2..2e7311ff88dd 100644 --- a/tests/hazmat/primitives/twofactor/test_totp.py +++ b/tests/hazmat/primitives/twofactor/test_totp.py @@ -155,4 +155,10 @@ def test_invalid_backend(): pretend_backend = object() with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - TOTP(secret, 8, hashes.SHA1(), 30, pretend_backend) + TOTP( + secret, + 8, + hashes.SHA1(), + 30, + pretend_backend, # type: ignore[arg-type] + ) diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 87b6b29e6fdb..5baa37861680 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -60,8 +60,7 @@ from ..utils import load_nist_vectors, load_vectors_from_file -@utils.register_interface(x509.ExtensionType) -class DummyExtension(object): +class DummyExtension(x509.ExtensionType): oid = x509.ObjectIdentifier("1.2.3.4") @@ -1683,11 +1682,15 @@ def test_build_cert(self, backend): basic_constraints = cert.extensions.get_extension_for_oid( ExtensionOID.BASIC_CONSTRAINTS ) + assert isinstance(basic_constraints.value, x509.BasicConstraints) assert basic_constraints.value.ca is False assert basic_constraints.value.path_length is None subject_alternative_name = cert.extensions.get_extension_for_oid( ExtensionOID.SUBJECT_ALTERNATIVE_NAME ) + assert isinstance( + subject_alternative_name.value, x509.SubjectAlternativeName + ) assert list(subject_alternative_name.value) == [ x509.DNSName("cryptography.io"), ] @@ -2498,11 +2501,15 @@ def test_build_cert_with_dsa_private_key(self, backend): basic_constraints = cert.extensions.get_extension_for_oid( ExtensionOID.BASIC_CONSTRAINTS ) + assert isinstance(basic_constraints.value, x509.BasicConstraints) assert basic_constraints.value.ca is False assert basic_constraints.value.path_length is None subject_alternative_name = cert.extensions.get_extension_for_oid( ExtensionOID.SUBJECT_ALTERNATIVE_NAME ) + assert isinstance( + subject_alternative_name.value, x509.SubjectAlternativeName + ) assert list(subject_alternative_name.value) == [ x509.DNSName("cryptography.io"), ] @@ -2545,11 +2552,15 @@ def test_build_cert_with_ec_private_key(self, backend): basic_constraints = cert.extensions.get_extension_for_oid( ExtensionOID.BASIC_CONSTRAINTS ) + assert isinstance(basic_constraints.value, x509.BasicConstraints) assert basic_constraints.value.ca is False assert basic_constraints.value.path_length is None subject_alternative_name = cert.extensions.get_extension_for_oid( ExtensionOID.SUBJECT_ALTERNATIVE_NAME ) + assert isinstance( + subject_alternative_name.value, x509.SubjectAlternativeName + ) assert list(subject_alternative_name.value) == [ x509.DNSName("cryptography.io"), ] @@ -2600,11 +2611,15 @@ def test_build_cert_with_ed25519(self, backend): basic_constraints = cert.extensions.get_extension_for_oid( ExtensionOID.BASIC_CONSTRAINTS ) + assert isinstance(basic_constraints.value, x509.BasicConstraints) assert basic_constraints.value.ca is False assert basic_constraints.value.path_length is None subject_alternative_name = cert.extensions.get_extension_for_oid( ExtensionOID.SUBJECT_ALTERNATIVE_NAME ) + assert isinstance( + subject_alternative_name.value, x509.SubjectAlternativeName + ) assert list(subject_alternative_name.value) == [ x509.DNSName("cryptography.io"), ] @@ -2635,6 +2650,7 @@ def test_build_cert_with_public_ed25519_rsa_sig(self, backend): ) cert = builder.sign(issuer_private_key, hashes.SHA256(), backend) + assert cert.signature_hash_algorithm is not None issuer_private_key.public_key().verify( cert.signature, cert.tbs_certificate_bytes, @@ -2693,11 +2709,15 @@ def test_build_cert_with_ed448(self, backend): basic_constraints = cert.extensions.get_extension_for_oid( ExtensionOID.BASIC_CONSTRAINTS ) + assert isinstance(basic_constraints.value, x509.BasicConstraints) assert basic_constraints.value.ca is False assert basic_constraints.value.path_length is None subject_alternative_name = cert.extensions.get_extension_for_oid( ExtensionOID.SUBJECT_ALTERNATIVE_NAME ) + assert isinstance( + subject_alternative_name.value, x509.SubjectAlternativeName + ) assert list(subject_alternative_name.value) == [ x509.DNSName("cryptography.io"), ] @@ -2728,6 +2748,7 @@ def test_build_cert_with_public_ed448_rsa_sig(self, backend): ) cert = builder.sign(issuer_private_key, hashes.SHA256(), backend) + assert cert.signature_hash_algorithm is not None issuer_private_key.public_key().verify( cert.signature, cert.tbs_certificate_bytes, @@ -3230,6 +3251,7 @@ def test_build_ca_request_with_path_length_none(self, backend): basic_constraints = request.extensions.get_extension_for_oid( ExtensionOID.BASIC_CONSTRAINTS ) + assert isinstance(basic_constraints.value, x509.BasicConstraints) assert basic_constraints.value.path_length is None @pytest.mark.parametrize( @@ -3273,7 +3295,9 @@ def test_sign_invalid_hash_algorithm(self, backend): x509.Name([]) ) with pytest.raises(TypeError): - builder.sign(private_key, "NotAHash", backend) + builder.sign( + private_key, "NotAHash", backend # type: ignore[arg-type] + ) @pytest.mark.supported( only_if=lambda backend: backend.ed25519_supported(), @@ -3373,6 +3397,7 @@ def test_build_ca_request_with_rsa(self, backend): basic_constraints = request.extensions.get_extension_for_oid( ExtensionOID.BASIC_CONSTRAINTS ) + assert isinstance(basic_constraints.value, x509.BasicConstraints) assert basic_constraints.value.ca is True assert basic_constraints.value.path_length == 2 @@ -3518,6 +3543,7 @@ def test_build_nonca_request_with_rsa(self, backend): basic_constraints = request.extensions.get_extension_for_oid( ExtensionOID.BASIC_CONSTRAINTS ) + assert isinstance(basic_constraints.value, x509.BasicConstraints) assert basic_constraints.value.ca is False assert basic_constraints.value.path_length is None @@ -3553,6 +3579,7 @@ def test_build_ca_request_with_ec(self, backend): basic_constraints = request.extensions.get_extension_for_oid( ExtensionOID.BASIC_CONSTRAINTS ) + assert isinstance(basic_constraints.value, x509.BasicConstraints) assert basic_constraints.value.ca is True assert basic_constraints.value.path_length == 2 @@ -3657,6 +3684,7 @@ def test_build_ca_request_with_dsa(self, backend): basic_constraints = request.extensions.get_extension_for_oid( ExtensionOID.BASIC_CONSTRAINTS ) + assert isinstance(basic_constraints.value, x509.BasicConstraints) assert basic_constraints.value.ca is True assert basic_constraints.value.path_length == 2 @@ -3800,11 +3828,13 @@ def test_add_two_extensions(self, backend): basic_constraints = request.extensions.get_extension_for_oid( ExtensionOID.BASIC_CONSTRAINTS ) + assert isinstance(basic_constraints.value, x509.BasicConstraints) assert basic_constraints.value.ca is True assert basic_constraints.value.path_length == 2 ext = request.extensions.get_extension_for_oid( ExtensionOID.SUBJECT_ALTERNATIVE_NAME ) + assert isinstance(ext.value, x509.SubjectAlternativeName) assert list(ext.value) == [x509.DNSName("cryptography.io")] def test_add_attributes(self, backend): diff --git a/tests/x509/test_x509_crlbuilder.py b/tests/x509/test_x509_crlbuilder.py index b32322f975e6..14fe2387107f 100644 --- a/tests/x509/test_x509_crlbuilder.py +++ b/tests/x509/test_x509_crlbuilder.py @@ -341,6 +341,7 @@ def test_freshestcrl_extension(self, backend): assert len(crl.extensions) == 1 ext1 = crl.extensions.get_extension_for_class(x509.FreshestCRL) assert ext1.critical is False + assert isinstance(ext1.value, x509.FreshestCRL) assert isinstance(ext1.value[0], x509.DistributionPoint) assert ext1.value[0].full_name is not None uri = ext1.value[0].full_name[0] @@ -411,7 +412,9 @@ def test_sign_with_invalid_hash(self, backend): ) with pytest.raises(TypeError): - builder.sign(private_key, object(), backend) + builder.sign( + private_key, object(), backend # type: ignore[arg-type] + ) @pytest.mark.supported( only_if=lambda backend: backend.ed25519_supported(), @@ -437,7 +440,11 @@ def test_sign_with_invalid_hash_ed25519(self, backend): ) with pytest.raises(ValueError): - builder.sign(private_key, object(), backend) + builder.sign( + private_key, + object(), # type:ignore[arg-type] + backend, + ) with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) @@ -465,7 +472,11 @@ def test_sign_with_invalid_hash_ed448(self, backend): ) with pytest.raises(ValueError): - builder.sign(private_key, object(), backend) + builder.sign( + private_key, + object(), # type:ignore[arg-type] + backend, + ) with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) From e09cd90f77a31832bdde1d3652c115be282cced9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Mar 2021 07:39:57 -0500 Subject: [PATCH 0073/1456] Bump libc from 0.2.86 to 0.2.87 in /src/rust (#5891) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.86 to 0.2.87. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.86...0.2.87) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 83fd7eb8f48b..a78ee8f67ab3 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.86" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" +checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213" [[package]] name = "lock_api" From 6539e3381e5da8329509d2546e0f6ce3e4ca8896 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Mar 2021 07:55:13 -0500 Subject: [PATCH 0074/1456] Bump syn from 1.0.60 to 1.0.61 in /src/rust (#5895) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.60 to 1.0.61. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.60...1.0.61) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index a78ee8f67ab3..275c34709476 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -239,9 +239,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +checksum = "ed22b90a0e734a23a7610f4283ac9e5acfb96cbb30dfefa540d66f866f1c09c5" dependencies = [ "proc-macro2", "quote", From 9ef995722153f7c59b378f4c56b8affbfa13ff54 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sat, 6 Mar 2021 19:03:32 +0100 Subject: [PATCH 0075/1456] Generic extension value/typehint x509.Name (#5897) * make value property return the generic value * typehint x509.Name * also ignore overloaded functions --- .coveragerc | 1 + src/cryptography/x509/extensions.py | 2 +- src/cryptography/x509/name.py | 24 +++++++++++++++++++++--- tests/x509/test_x509.py | 2 +- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/.coveragerc b/.coveragerc index 62a0ff5fb763..0ee0cd107461 100644 --- a/.coveragerc +++ b/.coveragerc @@ -14,3 +14,4 @@ source = exclude_lines = @abc.abstractmethod @abc.abstractproperty + @typing.overload diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index d43f2b8d2a58..2f32d58d96a5 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -1350,7 +1350,7 @@ def critical(self) -> bool: return self._critical @property - def value(self) -> ExtensionType: + def value(self) -> ExtensionTypeVar: return self._value def __repr__(self) -> str: diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py index 5f0b88e1794d..0bfc2d94d452 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -196,14 +196,32 @@ def __repr__(self) -> str: class Name(object): - def __init__(self, attributes): + @typing.overload + def __init__(self, attributes: typing.Iterable[NameAttribute]) -> None: + ... + + @typing.overload + def __init__( + self, attributes: typing.Iterable[RelativeDistinguishedName] + ) -> None: + ... + + def __init__( + self, + attributes: typing.Iterable[ + typing.Union[NameAttribute, RelativeDistinguishedName] + ], + ) -> None: attributes = list(attributes) if all(isinstance(x, NameAttribute) for x in attributes): self._attributes = [ - RelativeDistinguishedName([x]) for x in attributes + RelativeDistinguishedName([typing.cast(NameAttribute, x)]) + for x in attributes ] elif all(isinstance(x, RelativeDistinguishedName) for x in attributes): - self._attributes = attributes + self._attributes = typing.cast( + typing.List[RelativeDistinguishedName], attributes + ) else: raise TypeError( "attributes must be a list of NameAttribute" diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 5baa37861680..e47c109f414e 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -5019,7 +5019,7 @@ def test_rfc4514_string_empty_values(self): def test_not_nameattribute(self): with pytest.raises(TypeError): - x509.Name(["not-a-NameAttribute"]) + x509.Name(["not-a-NameAttribute"]) # type: ignore[list-item] def test_bytes(self, backend): name = x509.Name( From 6384cbb2fe25469ecfb6d6e431211a8426380893 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 7 Mar 2021 18:59:30 +0100 Subject: [PATCH 0076/1456] Bugfix/issue 5889 typehint get values for types (#5900) * add type alias for IP addresses * Re-export module attributes in cryptography.x509.oid Without exporting attributes via `__all__` mypy will consider typehints of classes imported from `cryptography.x509.oid` as type Any. Example: from cryptography.x509.oid import ObjectIdentifier oid = ObjectIdentifier("1.2.3") # Any, if we do not re-export Note that while the canonical location of ObjectIdentifier is in `crytography.x509`, it is imported many times from `crytography.x509.oid` instead * add return type annotiations to constructors * overload GeneralNames.get_values_for_type * overload all implementations --- src/cryptography/x509/extensions.py | 240 ++++++++++++++++++++++++-- src/cryptography/x509/general_name.py | 37 ++-- src/cryptography/x509/oid.py | 15 ++ 3 files changed, 258 insertions(+), 34 deletions(-) diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 2f32d58d96a5..d9443106fa0c 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -23,8 +23,18 @@ from cryptography.x509.certificate_transparency import ( SignedCertificateTimestamp, ) -from cryptography.x509.general_name import GeneralName, IPAddress, OtherName -from cryptography.x509.name import RelativeDistinguishedName +from cryptography.x509.general_name import ( + DNSName, + DirectoryName, + GeneralName, + IPAddress, + OtherName, + RFC822Name, + RegisteredID, + UniformResourceIdentifier, + _IPADDRESS_TYPES, +) +from cryptography.x509.name import Name, RelativeDistinguishedName from cryptography.x509.oid import ( CRLEntryExtensionOID, ExtensionOID, @@ -1389,15 +1399,67 @@ def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") + @typing.overload + def get_values_for_type( + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[UniformResourceIdentifier], + typing.Type[RFC822Name], + ], + ) -> typing.List[str]: + ... + + @typing.overload def get_values_for_type( - self, type: typing.Type[GeneralName] - ) -> typing.List[GeneralName]: + self, + type: typing.Type[DirectoryName], + ) -> typing.List[Name]: + ... + + @typing.overload + def get_values_for_type( + self, + type: typing.Type[RegisteredID], + ) -> typing.List[ObjectIdentifier]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[IPAddress] + ) -> typing.List[_IPADDRESS_TYPES]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[OtherName] + ) -> typing.List[OtherName]: + ... + + def get_values_for_type( + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[DirectoryName], + typing.Type[IPAddress], + typing.Type[OtherName], + typing.Type[RFC822Name], + typing.Type[RegisteredID], + typing.Type[UniformResourceIdentifier], + ], + ) -> typing.Union[ + typing.List[_IPADDRESS_TYPES], + typing.List[str], + typing.List[OtherName], + typing.List[Name], + typing.List[ObjectIdentifier], + ]: # Return the value of each GeneralName, except for OtherName instances # which we return directly because it has two important properties not # just one value. objs = (i for i in self if isinstance(i, type)) if type != OtherName: - objs = (i.value for i in objs) + return [i.value for i in objs] return list(objs) def __repr__(self) -> str: @@ -1424,9 +1486,61 @@ def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") + @typing.overload def get_values_for_type( - self, type: typing.Type[GeneralName] - ) -> typing.List[GeneralName]: + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[UniformResourceIdentifier], + typing.Type[RFC822Name], + ], + ) -> typing.List[str]: + ... + + @typing.overload + def get_values_for_type( + self, + type: typing.Type[DirectoryName], + ) -> typing.List[Name]: + ... + + @typing.overload + def get_values_for_type( + self, + type: typing.Type[RegisteredID], + ) -> typing.List[ObjectIdentifier]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[IPAddress] + ) -> typing.List[_IPADDRESS_TYPES]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[OtherName] + ) -> typing.List[OtherName]: + ... + + def get_values_for_type( + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[DirectoryName], + typing.Type[IPAddress], + typing.Type[OtherName], + typing.Type[RFC822Name], + typing.Type[RegisteredID], + typing.Type[UniformResourceIdentifier], + ], + ) -> typing.Union[ + typing.List[_IPADDRESS_TYPES], + typing.List[str], + typing.List[OtherName], + typing.List[Name], + typing.List[ObjectIdentifier], + ]: return self._general_names.get_values_for_type(type) def __repr__(self) -> str: @@ -1453,9 +1567,61 @@ def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") + @typing.overload def get_values_for_type( - self, type: typing.Type[GeneralName] - ) -> typing.List[GeneralName]: + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[UniformResourceIdentifier], + typing.Type[RFC822Name], + ], + ) -> typing.List[str]: + ... + + @typing.overload + def get_values_for_type( + self, + type: typing.Type[DirectoryName], + ) -> typing.List[Name]: + ... + + @typing.overload + def get_values_for_type( + self, + type: typing.Type[RegisteredID], + ) -> typing.List[ObjectIdentifier]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[IPAddress] + ) -> typing.List[_IPADDRESS_TYPES]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[OtherName] + ) -> typing.List[OtherName]: + ... + + def get_values_for_type( + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[DirectoryName], + typing.Type[IPAddress], + typing.Type[OtherName], + typing.Type[RFC822Name], + typing.Type[RegisteredID], + typing.Type[UniformResourceIdentifier], + ], + ) -> typing.Union[ + typing.List[_IPADDRESS_TYPES], + typing.List[str], + typing.List[OtherName], + typing.List[Name], + typing.List[ObjectIdentifier], + ]: return self._general_names.get_values_for_type(type) def __repr__(self) -> str: @@ -1482,9 +1648,61 @@ def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") + @typing.overload def get_values_for_type( - self, type: typing.Type[GeneralName] - ) -> typing.List[GeneralName]: + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[UniformResourceIdentifier], + typing.Type[RFC822Name], + ], + ) -> typing.List[str]: + ... + + @typing.overload + def get_values_for_type( + self, + type: typing.Type[DirectoryName], + ) -> typing.List[Name]: + ... + + @typing.overload + def get_values_for_type( + self, + type: typing.Type[RegisteredID], + ) -> typing.List[ObjectIdentifier]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[IPAddress] + ) -> typing.List[_IPADDRESS_TYPES]: + ... + + @typing.overload + def get_values_for_type( + self, type: typing.Type[OtherName] + ) -> typing.List[OtherName]: + ... + + def get_values_for_type( + self, + type: typing.Union[ + typing.Type[DNSName], + typing.Type[DirectoryName], + typing.Type[IPAddress], + typing.Type[OtherName], + typing.Type[RFC822Name], + typing.Type[RegisteredID], + typing.Type[UniformResourceIdentifier], + ], + ) -> typing.Union[ + typing.List[_IPADDRESS_TYPES], + typing.List[str], + typing.List[OtherName], + typing.List[Name], + typing.List[ObjectIdentifier], + ]: return self._general_names.get_values_for_type(type) def __repr__(self) -> str: diff --git a/src/cryptography/x509/general_name.py b/src/cryptography/x509/general_name.py index f16aef85e15f..d49582c41e11 100644 --- a/src/cryptography/x509/general_name.py +++ b/src/cryptography/x509/general_name.py @@ -23,6 +23,12 @@ 7: "iPAddress", 8: "registeredID", } +_IPADDRESS_TYPES = typing.Union[ + ipaddress.IPv4Address, + ipaddress.IPv6Address, + ipaddress.IPv4Network, + ipaddress.IPv6Network, +] class UnsupportedGeneralNameType(Exception): @@ -40,7 +46,7 @@ def value(self) -> typing.Any: class RFC822Name(GeneralName): - def __init__(self, value: str): + def __init__(self, value: str) -> None: if isinstance(value, str): try: value.encode("ascii") @@ -88,7 +94,7 @@ def __hash__(self) -> int: class DNSName(GeneralName): - def __init__(self, value: str): + def __init__(self, value: str) -> None: if isinstance(value, str): try: value.encode("ascii") @@ -130,7 +136,7 @@ def __hash__(self) -> int: class UniformResourceIdentifier(GeneralName): - def __init__(self, value: str): + def __init__(self, value: str) -> None: if isinstance(value, str): try: value.encode("ascii") @@ -174,7 +180,7 @@ def __hash__(self) -> int: class DirectoryName(GeneralName): - def __init__(self, value: Name): + def __init__(self, value: Name) -> None: if not isinstance(value, Name): raise TypeError("value must be a Name") @@ -201,7 +207,7 @@ def __hash__(self) -> int: class RegisteredID(GeneralName): - def __init__(self, value: ObjectIdentifier): + def __init__(self, value: ObjectIdentifier) -> None: if not isinstance(value, ObjectIdentifier): raise TypeError("value must be an ObjectIdentifier") @@ -228,15 +234,7 @@ def __hash__(self) -> int: class IPAddress(GeneralName): - def __init__( - self, - value: typing.Union[ - ipaddress.IPv4Address, - ipaddress.IPv6Address, - ipaddress.IPv4Network, - ipaddress.IPv6Network, - ], - ): + def __init__(self, value: _IPADDRESS_TYPES) -> None: if not isinstance( value, ( @@ -255,14 +253,7 @@ def __init__( self._value = value @property - def value( - self, - ) -> typing.Union[ - ipaddress.IPv4Address, - ipaddress.IPv6Address, - ipaddress.IPv4Network, - ipaddress.IPv6Network, - ]: + def value(self) -> _IPADDRESS_TYPES: return self._value def __repr__(self) -> str: @@ -282,7 +273,7 @@ def __hash__(self) -> int: class OtherName(GeneralName): - def __init__(self, type_id: ObjectIdentifier, value: bytes): + def __init__(self, type_id: ObjectIdentifier, value: bytes) -> None: if not isinstance(type_id, ObjectIdentifier): raise TypeError("type_id must be an ObjectIdentifier") if not isinstance(value, bytes): diff --git a/src/cryptography/x509/oid.py b/src/cryptography/x509/oid.py index c7695bdb5397..228ac1155324 100644 --- a/src/cryptography/x509/oid.py +++ b/src/cryptography/x509/oid.py @@ -265,3 +265,18 @@ class AttributeOID(object): OCSPExtensionOID.NONCE: "OCSPNonce", AttributeOID.CHALLENGE_PASSWORD: "challengePassword", } + + +__all__ = [ + "AttributeOID", + "AuthorityInformationAccessOID", + "CRLEntryExtensionOID", + "CertificatePoliciesOID", + "ExtendedKeyUsageOID", + "ExtensionOID", + "NameOID", + "OCSPExtensionOID", + "ObjectIdentifier", + "SignatureAlgorithmOID", + "SubjectInformationAccessOID", +] From 8ca4d5a014191be8de10c3f46935bc7780eae444 Mon Sep 17 00:00:00 2001 From: "Ajitomi, Daisuke" Date: Mon, 8 Mar 2021 03:50:20 +0900 Subject: [PATCH 0077/1456] Add exceptions to Ed25519PrivateKey and Edd25519PublicKey methods. (#5898) --- docs/hazmat/primitives/asymmetric/ed25519.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/hazmat/primitives/asymmetric/ed25519.rst b/docs/hazmat/primitives/asymmetric/ed25519.rst index 47d95ec1b9da..152dcfe6f947 100644 --- a/docs/hazmat/primitives/asymmetric/ed25519.rst +++ b/docs/hazmat/primitives/asymmetric/ed25519.rst @@ -43,6 +43,11 @@ Key interfaces :returns: :class:`Ed25519PrivateKey` + :raises ValueError: This is raised if the private key is not 32 bytes long. + + :raises cryptography.exceptions.UnsupportedAlgorithm: If the private key + is of a type that is not supported by the backend. + .. doctest:: >>> from cryptography.hazmat.primitives import serialization @@ -108,6 +113,11 @@ Key interfaces :returns: :class:`Ed25519PublicKey` + :raises ValueError: This is raised if the public key is not 32 bytes long. + + :raises cryptography.exceptions.UnsupportedAlgorithm: If the public key + is of a type that is not supported by the backend. + .. doctest:: >>> from cryptography.hazmat.primitives import serialization From 7a9a9e15b8ebd250fa9d6b562f6ff657a8cfbd8a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Mar 2021 07:49:42 -0500 Subject: [PATCH 0078/1456] Bump libc from 0.2.87 to 0.2.88 in /src/rust (#5902) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.87 to 0.2.88. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.87...0.2.88) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 275c34709476..ed8d6c0e8d6f 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213" +checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a" [[package]] name = "lock_api" From 8df153664a06e77e344566417426a5a31c0be69e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Mar 2021 07:57:35 -0500 Subject: [PATCH 0079/1456] Bump syn from 1.0.61 to 1.0.62 in /src/rust (#5903) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.61 to 1.0.62. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.61...1.0.62) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index ed8d6c0e8d6f..cb594157e509 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -239,9 +239,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "1.0.61" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed22b90a0e734a23a7610f4283ac9e5acfb96cbb30dfefa540d66f866f1c09c5" +checksum = "123a78a3596b24fee53a6464ce52d8ecbf62241e6294c7e7fe12086cd161f512" dependencies = [ "proc-macro2", "quote", From c5cc44a313b5b90a710c40f213679900ab5783c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Mar 2021 07:28:12 -0500 Subject: [PATCH 0080/1456] Bump syn from 1.0.62 to 1.0.63 in /src/rust (#5909) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.62 to 1.0.63. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.62...1.0.63) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index cb594157e509..7f289ef10f15 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -239,9 +239,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "1.0.62" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "123a78a3596b24fee53a6464ce52d8ecbf62241e6294c7e7fe12086cd161f512" +checksum = "8fd9bc7ccc2688b3344c2f48b9b546648b25ce0b20fc717ee7fa7981a8ca9717" dependencies = [ "proc-macro2", "quote", From 2428b11ab84bb796bfcc595cd48fc00e3195e6bb Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Thu, 11 Mar 2021 21:35:48 +0100 Subject: [PATCH 0081/1456] Typehint x509.base (only) (#5904) * typehint x509.base * cast extension class * don't use string in typecast * use lists as default argument values (see #5904) * restore import since this is now re-exported * ignore linting errors * empty commit to trigger github actions * fix formatting issue --- .../hazmat/backends/openssl/backend.py | 7 +- src/cryptography/x509/base.py | 70 +++++++++++++------ tests/x509/test_x509.py | 15 ++-- 3 files changed, 65 insertions(+), 27 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index c87a466c9307..605af068d480 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -991,7 +991,8 @@ def create_x509_certificate(self, builder, private_key, algorithm): # Set the subject's public key. res = self._lib.X509_set_pubkey( - x509_cert, builder._public_key._evp_pkey + x509_cert, + builder._public_key._evp_pkey, # type: ignore[union-attr] ) self.openssl_assert(res == 1) @@ -1101,7 +1102,9 @@ def create_x509_crl(self, builder, private_key, algorithm): for revoked_cert in builder._revoked_certificates: # Duplicating because the X509_CRL takes ownership and will free # this memory when X509_CRL_free is called. - revoked = self._lib.X509_REVOKED_dup(revoked_cert._x509_revoked) + revoked = self._lib.X509_REVOKED_dup( + revoked_cert._x509_revoked # type: ignore[attr-defined] + ) self.openssl_assert(revoked != self._ffi.NULL) res = self._lib.X509_CRL_add0_revoked(x509_crl, revoked) self.openssl_assert(res == 1) diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index 1e98b469c1bb..9bbde978fda1 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -29,13 +29,14 @@ class AttributeNotFound(Exception): - def __init__(self, msg, oid): + def __init__(self, msg: str, oid: ObjectIdentifier) -> None: super(AttributeNotFound, self).__init__(msg) self.oid = oid def _reject_duplicate_extension( - extension: Extension, extensions: typing.List[Extension] + extension: Extension[ExtensionType], + extensions: typing.List[Extension[ExtensionType]], ) -> None: # This is quadratic in the number of extensions for e in extensions: @@ -73,7 +74,7 @@ class Version(Enum): class InvalidVersion(Exception): - def __init__(self, msg, parsed_version): + def __init__(self, msg: str, parsed_version: int) -> None: super(InvalidVersion, self).__init__(msg) self.parsed_version = parsed_version @@ -228,7 +229,9 @@ def get_revoked_certificate_by_serial_number( """ @abc.abstractproperty - def signature_hash_algorithm(self) -> hashes.HashAlgorithm: + def signature_hash_algorithm( + self, + ) -> typing.Optional[hashes.HashAlgorithm]: """ Returns a HashAlgorithm corresponding to the type of the digest signed in the certificate. @@ -294,14 +297,24 @@ def __len__(self) -> int: Number of revoked certificates in the CRL. """ + @typing.overload + def __getitem__(self, idx: int) -> RevokedCertificate: + ... + + @typing.overload + def __getitem__(self, idx: slice) -> typing.List[RevokedCertificate]: + ... + @abc.abstractmethod - def __getitem__(self, idx): + def __getitem__( + self, idx: typing.Union[int, slice] + ) -> typing.Union[RevokedCertificate, typing.List[RevokedCertificate]]: """ Returns a revoked certificate (or slice of revoked certificates). """ @abc.abstractmethod - def __iter__(self): + def __iter__(self) -> typing.Iterator[RevokedCertificate]: """ Iterator over the revoked certificates """ @@ -345,7 +358,9 @@ def subject(self) -> Name: """ @abc.abstractproperty - def signature_hash_algorithm(self) -> hashes.HashAlgorithm: + def signature_hash_algorithm( + self, + ) -> typing.Optional[hashes.HashAlgorithm]: """ Returns a HashAlgorithm corresponding to the type of the digest signed in the certificate. @@ -438,7 +453,12 @@ def load_der_x509_crl( class CertificateSigningRequestBuilder(object): - def __init__(self, subject_name=None, extensions=[], attributes=[]): + def __init__( + self, + subject_name: typing.Optional[Name] = None, + extensions: typing.List[Extension[ExtensionType]] = [], + attributes: typing.List[typing.Tuple[ObjectIdentifier, bytes]] = [], + ): """ Creates an empty X.509 certificate request (v1). """ @@ -512,15 +532,17 @@ def sign( class CertificateBuilder(object): + _extensions: typing.List[Extension[ExtensionType]] + def __init__( self, - issuer_name=None, - subject_name=None, - public_key=None, - serial_number=None, - not_valid_before=None, - not_valid_after=None, - extensions=[], + issuer_name: typing.Optional[Name] = None, + subject_name: typing.Optional[Name] = None, + public_key: typing.Optional[_PUBLIC_KEY_TYPES] = None, + serial_number: typing.Optional[int] = None, + not_valid_before: typing.Optional[datetime.datetime] = None, + not_valid_after: typing.Optional[datetime.datetime] = None, + extensions: typing.List[Extension[ExtensionType]] = [], ) -> None: self._version = Version.v3 self._issuer_name = issuer_name @@ -745,13 +767,16 @@ def sign( class CertificateRevocationListBuilder(object): + _extensions: typing.List[Extension[ExtensionType]] + _revoked_certificates: typing.List[RevokedCertificate] + def __init__( self, - issuer_name=None, - last_update=None, - next_update=None, - extensions=[], - revoked_certificates=[], + issuer_name: typing.Optional[Name] = None, + last_update: typing.Optional[datetime.datetime] = None, + next_update: typing.Optional[datetime.datetime] = None, + extensions: typing.List[Extension[ExtensionType]] = [], + revoked_certificates: typing.List[RevokedCertificate] = [], ): self._issuer_name = issuer_name self._last_update = last_update @@ -879,7 +904,10 @@ def sign( class RevokedCertificateBuilder(object): def __init__( - self, serial_number=None, revocation_date=None, extensions=[] + self, + serial_number: typing.Optional[int] = None, + revocation_date: typing.Optional[datetime.datetime] = None, + extensions: typing.List[Extension[ExtensionType]] = [], ): self._serial_number = serial_number self._revocation_date = revocation_date diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index e47c109f414e..b3bf78a6862e 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -10,6 +10,7 @@ import datetime import ipaddress import os +import typing import pytest @@ -3615,8 +3616,11 @@ def test_build_ca_request_with_ed25519(self, backend): assert list(subject) == [ x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Texas"), ] - basic_constraints = request.extensions.get_extension_for_oid( - ExtensionOID.BASIC_CONSTRAINTS + basic_constraints = typing.cast( + x509.Extension[x509.BasicConstraints], + request.extensions.get_extension_for_oid( + ExtensionOID.BASIC_CONSTRAINTS + ), ) assert basic_constraints.value.ca is True assert basic_constraints.value.path_length == 2 @@ -3653,8 +3657,11 @@ def test_build_ca_request_with_ed448(self, backend): assert list(subject) == [ x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Texas"), ] - basic_constraints = request.extensions.get_extension_for_oid( - ExtensionOID.BASIC_CONSTRAINTS + basic_constraints = typing.cast( + x509.Extension[x509.BasicConstraints], + request.extensions.get_extension_for_oid( + ExtensionOID.BASIC_CONSTRAINTS + ), ) assert basic_constraints.value.ca is True assert basic_constraints.value.path_length == 2 From 4ba7f21c01573641cb520c9d0476ab53ac14111c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Mar 2021 07:54:04 -0400 Subject: [PATCH 0082/1456] Bump syn from 1.0.63 to 1.0.64 in /src/rust (#5915) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.63 to 1.0.64. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.63...1.0.64) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 7f289ef10f15..7f59f413b425 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -239,9 +239,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd9bc7ccc2688b3344c2f48b9b546648b25ce0b20fc717ee7fa7981a8ca9717" +checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" dependencies = [ "proc-macro2", "quote", From cd2ab9ec6c14333e10fb161295d5ae355c4a8f96 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 15 Mar 2021 09:44:38 -0400 Subject: [PATCH 0083/1456] update java sdk download link (#5916) --- docs/development/custom-vectors/rsa-oaep-sha2.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/development/custom-vectors/rsa-oaep-sha2.rst b/docs/development/custom-vectors/rsa-oaep-sha2.rst index 36f256d7c68e..30c3e273505a 100644 --- a/docs/development/custom-vectors/rsa-oaep-sha2.rst +++ b/docs/development/custom-vectors/rsa-oaep-sha2.rst @@ -33,7 +33,7 @@ Download link: :download:`VerifyRSAOAEPSHA2.java Using the Verifier ------------------ -Download and install the `Java 8 SDK`_. Initial verification was performed +Download and install the `Java SDK`_. Initial verification was performed using ``jdk-8u77-macosx-x64.dmg``. Download the latest `Bouncy Castle`_ JAR. Initial verification was performed @@ -53,4 +53,4 @@ Finally, run the program with the path to the SHA-2 vectors: $ java -classpath ~/Downloads/bcprov-jdk15on-154.jar:./ VerifyRSAOAEPSHA2 .. _`Bouncy Castle`: https://www.bouncycastle.org/ -.. _`Java 8 SDK`: https://www.oracle.com/technetwork/java/javase/downloads/index.html +.. _`Java SDK`: https://www.oracle.com/java/technologies/javase-downloads.html From 8d41a94bba7674cfcb120ce7a76b7c3df5c2bb73 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Mon, 15 Mar 2021 23:44:02 +0100 Subject: [PATCH 0084/1456] typehint x509.base (#5899) * start typing x509.base * statically type x509.base * typehint X509Backend interface * typehint at least the X509Backend interface * make _CertificateRevocationList/_CertificateSigningRequest actual subclasses of the interface (as done before for Certificate in f16bff2cb) * tell mypy to ignore lines with deliberately wrong types * signature_hash_algorithm always returns a hash algorithm (it's not optional) * Revert "signature_hash_algorithm always returns a hash algorithm (it's not optional)" This reverts commit f6a5b172b416f8ddea561203c0cf03b55e4ec50e. * hash algorithm is actually optional * fix import style * typehint parsed_version to int, which it de facto always is * minimize changes * break import cycle with conditional imports * ignore access to private members of openssl implementation * reformat code with Black * test check for missing public key --- .coveragerc | 1 + src/cryptography/hazmat/backends/__init__.py | 2 +- .../hazmat/backends/interfaces.py | 56 +++++++++++++---- .../hazmat/backends/openssl/backend.py | 62 ++++++++++++++----- .../hazmat/backends/openssl/x509.py | 6 +- tests/hazmat/backends/test_openssl.py | 29 +++++++-- 6 files changed, 121 insertions(+), 35 deletions(-) diff --git a/.coveragerc b/.coveragerc index 0ee0cd107461..6579cf6c8d42 100644 --- a/.coveragerc +++ b/.coveragerc @@ -15,3 +15,4 @@ exclude_lines = @abc.abstractmethod @abc.abstractproperty @typing.overload + if typing.TYPE_CHECKING diff --git a/src/cryptography/hazmat/backends/__init__.py b/src/cryptography/hazmat/backends/__init__.py index 7f74cba2c9b2..64eedecb57e4 100644 --- a/src/cryptography/hazmat/backends/__init__.py +++ b/src/cryptography/hazmat/backends/__init__.py @@ -9,7 +9,7 @@ _default_backend: typing.Optional[Backend] = None -def default_backend(): +def default_backend() -> Backend: global _default_backend if _default_backend is None: diff --git a/src/cryptography/hazmat/backends/interfaces.py b/src/cryptography/hazmat/backends/interfaces.py index d57289bb1dc2..bb51060809f9 100644 --- a/src/cryptography/hazmat/backends/interfaces.py +++ b/src/cryptography/hazmat/backends/interfaces.py @@ -4,6 +4,23 @@ import abc +import typing + + +if typing.TYPE_CHECKING: + from cryptography.hazmat._types import _PRIVATE_KEY_TYPES + from cryptography.hazmat.primitives import hashes + from cryptography.x509.base import ( + Certificate, + CertificateBuilder, + CertificateRevocationList, + CertificateRevocationListBuilder, + CertificateSigningRequest, + CertificateSigningRequestBuilder, + RevokedCertificate, + RevokedCertificateBuilder, + ) + from cryptography.x509.name import Name class CipherBackend(metaclass=abc.ABCMeta): @@ -262,69 +279,86 @@ def load_der_parameters(self, data): class X509Backend(metaclass=abc.ABCMeta): @abc.abstractmethod - def load_pem_x509_certificate(self, data): + def load_pem_x509_certificate(self, data: bytes) -> "Certificate": """ Load an X.509 certificate from PEM encoded data. """ @abc.abstractmethod - def load_der_x509_certificate(self, data): + def load_der_x509_certificate(self, data: bytes) -> "Certificate": """ Load an X.509 certificate from DER encoded data. """ @abc.abstractmethod - def load_der_x509_csr(self, data): + def load_der_x509_csr(self, data: bytes) -> "CertificateSigningRequest": """ Load an X.509 CSR from DER encoded data. """ @abc.abstractmethod - def load_pem_x509_csr(self, data): + def load_pem_x509_csr(self, data: bytes) -> "CertificateSigningRequest": """ Load an X.509 CSR from PEM encoded data. """ @abc.abstractmethod - def create_x509_csr(self, builder, private_key, algorithm): + def create_x509_csr( + self, + builder: "CertificateSigningRequestBuilder", + private_key: "_PRIVATE_KEY_TYPES", + algorithm: typing.Optional["hashes.HashAlgorithm"], + ) -> "CertificateSigningRequest": """ Create and sign an X.509 CSR from a CSR builder object. """ @abc.abstractmethod - def create_x509_certificate(self, builder, private_key, algorithm): + def create_x509_certificate( + self, + builder: "CertificateBuilder", + private_key: "_PRIVATE_KEY_TYPES", + algorithm: typing.Optional["hashes.HashAlgorithm"], + ) -> "Certificate": """ Create and sign an X.509 certificate from a CertificateBuilder object. """ @abc.abstractmethod - def create_x509_crl(self, builder, private_key, algorithm): + def create_x509_crl( + self, + builder: "CertificateRevocationListBuilder", + private_key: "_PRIVATE_KEY_TYPES", + algorithm: typing.Optional["hashes.HashAlgorithm"], + ) -> "CertificateRevocationList": """ Create and sign an X.509 CertificateRevocationList from a CertificateRevocationListBuilder object. """ @abc.abstractmethod - def create_x509_revoked_certificate(self, builder): + def create_x509_revoked_certificate( + self, builder: "RevokedCertificateBuilder" + ) -> "RevokedCertificate": """ Create a RevokedCertificate object from a RevokedCertificateBuilder object. """ @abc.abstractmethod - def x509_name_bytes(self, name): + def x509_name_bytes(self, name: "Name") -> bytes: """ Compute the DER encoded bytes of an X509 Name object. """ @abc.abstractmethod - def load_pem_x509_crl(self, data): + def load_pem_x509_crl(self, data: bytes) -> "CertificateRevocationList": """ Load an X.509 CRL from PEM encoded data. """ @abc.abstractmethod - def load_der_x509_crl(self, data): + def load_der_x509_crl(self, data: bytes) -> "CertificateRevocationList": """ Load an X.509 CRL from DER encoded data. """ diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 605af068d480..90957324c462 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -6,6 +6,7 @@ import collections import contextlib import itertools +import typing import warnings from contextlib import contextmanager @@ -18,6 +19,7 @@ encode_der, encode_der_integer, ) +from cryptography.hazmat._types import _PRIVATE_KEY_TYPES from cryptography.hazmat.backends.interfaces import Backend as BackendInterface from cryptography.hazmat.backends.openssl import aead from cryptography.hazmat.backends.openssl.ciphers import _CipherContext @@ -137,6 +139,7 @@ from cryptography.hazmat.primitives.kdf import scrypt from cryptography.hazmat.primitives.serialization import pkcs7, ssh from cryptography.x509 import ocsp +from cryptography.x509.name import Name _MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"]) @@ -895,7 +898,12 @@ def _x509_check_signature_params(self, private_key, algorithm): "MD5 hash algorithm is only supported with RSA keys" ) - def create_x509_csr(self, builder, private_key, algorithm): + def create_x509_csr( + self, + builder: x509.CertificateSigningRequestBuilder, + private_key: _PRIVATE_KEY_TYPES, + algorithm: typing.Optional[hashes.HashAlgorithm], + ) -> _CertificateSigningRequest: if not isinstance(builder, x509.CertificateSigningRequestBuilder): raise TypeError("Builder type mismatch.") self._x509_check_signature_params(private_key, algorithm) @@ -920,7 +928,9 @@ def create_x509_csr(self, builder, private_key, algorithm): # Set subject public key. public_key = private_key.public_key() - res = self._lib.X509_REQ_set_pubkey(x509_req, public_key._evp_pkey) + res = self._lib.X509_REQ_set_pubkey( + x509_req, public_key._evp_pkey # type: ignore[union-attr] + ) self.openssl_assert(res == 1) # Add extensions. @@ -960,16 +970,25 @@ def create_x509_csr(self, builder, private_key, algorithm): self.openssl_assert(res == 1) # Sign the request using the requester's private key. - res = self._lib.X509_REQ_sign(x509_req, private_key._evp_pkey, evp_md) + res = self._lib.X509_REQ_sign( + x509_req, private_key._evp_pkey, evp_md # type: ignore[union-attr] + ) if res == 0: errors = self._consume_errors_with_text() raise ValueError("Signing failed", errors) return _CertificateSigningRequest(self, x509_req) - def create_x509_certificate(self, builder, private_key, algorithm): + def create_x509_certificate( + self, + builder: x509.CertificateBuilder, + private_key: _PRIVATE_KEY_TYPES, + algorithm: typing.Optional[hashes.HashAlgorithm], + ) -> _Certificate: if not isinstance(builder, x509.CertificateBuilder): raise TypeError("Builder type mismatch.") + if builder._public_key is None: + raise TypeError("Builder has no public key.") self._x509_check_signature_params(private_key, algorithm) # Resolve the signature algorithm. @@ -1027,7 +1046,11 @@ def create_x509_certificate(self, builder, private_key, algorithm): self.openssl_assert(res == 1) # Sign the certificate with the issuer's private key. - res = self._lib.X509_sign(x509_cert, private_key._evp_pkey, evp_md) + res = self._lib.X509_sign( + x509_cert, + private_key._evp_pkey, # type: ignore[union-attr] + evp_md, + ) if res == 0: errors = self._consume_errors_with_text() raise ValueError("Signing failed", errors) @@ -1058,7 +1081,12 @@ def _create_asn1_time(self, time): self._set_asn1_time(asn1_time, time) return asn1_time - def create_x509_crl(self, builder, private_key, algorithm): + def create_x509_crl( + self, + builder: x509.CertificateRevocationListBuilder, + private_key: _PRIVATE_KEY_TYPES, + algorithm: typing.Optional[hashes.HashAlgorithm], + ) -> _CertificateRevocationList: if not isinstance(builder, x509.CertificateRevocationListBuilder): raise TypeError("Builder type mismatch.") self._x509_check_signature_params(private_key, algorithm) @@ -1109,7 +1137,9 @@ def create_x509_crl(self, builder, private_key, algorithm): res = self._lib.X509_CRL_add0_revoked(x509_crl, revoked) self.openssl_assert(res == 1) - res = self._lib.X509_CRL_sign(x509_crl, private_key._evp_pkey, evp_md) + res = self._lib.X509_CRL_sign( + x509_crl, private_key._evp_pkey, evp_md # type: ignore[union-attr] + ) if res == 0: errors = self._consume_errors_with_text() raise ValueError("Signing failed", errors) @@ -1170,7 +1200,9 @@ def _create_x509_extension(self, handlers, extension): nid, 1 if extension.critical else 0, ext_struct ) - def create_x509_revoked_certificate(self, builder): + def create_x509_revoked_certificate( + self, builder: x509.RevokedCertificateBuilder + ) -> _RevokedCertificate: if not isinstance(builder, x509.RevokedCertificateBuilder): raise TypeError("Builder type mismatch.") @@ -1316,7 +1348,7 @@ def load_der_parameters(self, data): self._handle_key_loading_error() - def load_pem_x509_certificate(self, data): + def load_pem_x509_certificate(self, data: bytes) -> _Certificate: mem_bio = self._bytes_to_bio(data) x509 = self._lib.PEM_read_bio_X509( mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL @@ -1332,7 +1364,7 @@ def load_pem_x509_certificate(self, data): x509 = self._ffi.gc(x509, self._lib.X509_free) return _Certificate(self, x509) - def load_der_x509_certificate(self, data): + def load_der_x509_certificate(self, data: bytes) -> _Certificate: mem_bio = self._bytes_to_bio(data) x509 = self._lib.d2i_X509_bio(mem_bio.bio, self._ffi.NULL) if x509 == self._ffi.NULL: @@ -1342,7 +1374,7 @@ def load_der_x509_certificate(self, data): x509 = self._ffi.gc(x509, self._lib.X509_free) return _Certificate(self, x509) - def load_pem_x509_crl(self, data): + def load_pem_x509_crl(self, data: bytes) -> _CertificateRevocationList: mem_bio = self._bytes_to_bio(data) x509_crl = self._lib.PEM_read_bio_X509_CRL( mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL @@ -1358,7 +1390,7 @@ def load_pem_x509_crl(self, data): x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free) return _CertificateRevocationList(self, x509_crl) - def load_der_x509_crl(self, data): + def load_der_x509_crl(self, data: bytes) -> _CertificateRevocationList: mem_bio = self._bytes_to_bio(data) x509_crl = self._lib.d2i_X509_CRL_bio(mem_bio.bio, self._ffi.NULL) if x509_crl == self._ffi.NULL: @@ -1368,7 +1400,7 @@ def load_der_x509_crl(self, data): x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free) return _CertificateRevocationList(self, x509_crl) - def load_pem_x509_csr(self, data): + def load_pem_x509_csr(self, data: bytes) -> _CertificateSigningRequest: mem_bio = self._bytes_to_bio(data) x509_req = self._lib.PEM_read_bio_X509_REQ( mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL @@ -1384,7 +1416,7 @@ def load_pem_x509_csr(self, data): x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free) return _CertificateSigningRequest(self, x509_req) - def load_der_x509_csr(self, data): + def load_der_x509_csr(self, data: bytes) -> _CertificateSigningRequest: mem_bio = self._bytes_to_bio(data) x509_req = self._lib.d2i_X509_REQ_bio(mem_bio.bio, self._ffi.NULL) if x509_req == self._ffi.NULL: @@ -2200,7 +2232,7 @@ def dh_parameters_supported(self, p, g, q=None): def dh_x942_serialization_supported(self): return self._lib.Cryptography_HAS_EVP_PKEY_DHX == 1 - def x509_name_bytes(self, name): + def x509_name_bytes(self, name: Name) -> bytes: x509_name = _encode_name_gc(self, name) pp = self._ffi.new("unsigned char **") res = self._lib.i2d_X509_NAME(x509_name, pp) diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 07a1dd8a4722..ea938a272389 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -204,8 +204,7 @@ def extensions(self) -> x509.Extensions: ) -@utils.register_interface(x509.CertificateRevocationList) -class _CertificateRevocationList(object): +class _CertificateRevocationList(x509.CertificateRevocationList): def __init__(self, backend, x509_crl): self._backend = backend self._x509_crl = x509_crl @@ -385,8 +384,7 @@ def is_signature_valid(self, public_key: _PUBLIC_KEY_TYPES) -> bool: return True -@utils.register_interface(x509.CertificateSigningRequest) -class _CertificateSigningRequest(object): +class _CertificateSigningRequest(x509.CertificateSigningRequest): def __init__(self, backend, x509_req): self._backend = backend self._x509_req = x509_req diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index e6abadbd099e..a559998f1699 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -478,7 +478,20 @@ def test_requires_certificate_builder(self): with pytest.raises(TypeError): backend.create_x509_certificate( - object(), private_key, DummyHashAlgorithm() + object(), # type: ignore[arg-type] + private_key, + DummyHashAlgorithm(), + ) + + def test_builder_requires_public_key(self): + builder = x509.CertificateBuilder() + private_key = RSA_KEY_2048.private_key(backend) + + with pytest.raises(TypeError): + backend.create_x509_certificate( + builder, + private_key, + DummyHashAlgorithm(), ) @@ -488,7 +501,9 @@ def test_requires_csr_builder(self): with pytest.raises(TypeError): backend.create_x509_csr( - object(), private_key, DummyHashAlgorithm() + object(), # type: ignore[arg-type] + private_key, + DummyHashAlgorithm(), ) @@ -497,13 +512,19 @@ def test_invalid_builder(self): private_key = RSA_KEY_2048.private_key(backend) with pytest.raises(TypeError): - backend.create_x509_crl(object(), private_key, hashes.SHA256()) + backend.create_x509_crl( + object(), # type: ignore[arg-type] + private_key, + hashes.SHA256(), + ) class TestOpenSSLCreateRevokedCertificate(object): def test_invalid_builder(self): with pytest.raises(TypeError): - backend.create_x509_revoked_certificate(object()) + backend.create_x509_revoked_certificate( + object() # type: ignore[arg-type] + ) class TestOpenSSLSerializationWithOpenSSL(object): From bd2fb1f09c603ba14c0b86fd89e39c5d70a46aef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Mar 2021 08:13:06 -0400 Subject: [PATCH 0085/1456] Bump libc from 0.2.88 to 0.2.89 in /src/rust (#5917) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.88 to 0.2.89. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.88...0.2.89) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 7f59f413b425..fd579e99287e 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.88" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a" +checksum = "538c092e5586f4cdd7dd8078c4a79220e3e168880218124dcbce860f0ea938c6" [[package]] name = "lock_api" From a141ebe694497cb649e15bfaeadc02c782f7417e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Mar 2021 19:53:42 -0400 Subject: [PATCH 0086/1456] Bump libc from 0.2.89 to 0.2.90 in /src/rust (#5922) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.89 to 0.2.90. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.89...0.2.90) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index fd579e99287e..0a20349aeb47 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "538c092e5586f4cdd7dd8078c4a79220e3e168880218124dcbce860f0ea938c6" +checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae" [[package]] name = "lock_api" From d95bf3277b893ce64b979ce8da83521aeb80fce0 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sat, 20 Mar 2021 15:26:14 +0100 Subject: [PATCH 0087/1456] make get_extension_for_class a generic function (#5923) --- src/cryptography/x509/extensions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index d9443106fa0c..296de95d81b6 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -130,8 +130,8 @@ def get_extension_for_oid( raise ExtensionNotFound("No {} extension was found".format(oid), oid) def get_extension_for_class( - self, extclass: typing.Type[ExtensionType] - ) -> "Extension[ExtensionType]": + self, extclass: typing.Type[ExtensionTypeVar] + ) -> "Extension[ExtensionTypeVar]": if extclass is UnrecognizedExtension: raise TypeError( "UnrecognizedExtension can't be used with " From bd63f3a1a4bbb23fa4b8f9e2549d609317808b95 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 21 Mar 2021 19:05:37 -0500 Subject: [PATCH 0088/1456] document that we support more keys in our asymmetric loaders. (#5926) fixes #5911 --- .../primitives/asymmetric/serialization.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index 07a7456e4992..15dfbfcb6331 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -143,6 +143,10 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend`. :returns: One of + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.x25519.X25519PrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.x448.X448PrivateKey`, :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`, @@ -182,6 +186,10 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END :returns: One of + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.x25519.X25519PublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.x448.X448PublicKey`, :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`, @@ -252,6 +260,10 @@ the rest. :class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend`. :returns: One of + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.x25519.X25519PrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.x448.X448PrivateKey`, :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`, @@ -291,6 +303,10 @@ the rest. :class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend`. :returns: One of + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.x25519.X25519PublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.x448.X448PublicKey`, :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey`, From 6f7a5fd9e9c133273063227e3ad80232899b4ca3 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 21 Mar 2021 19:05:57 -0500 Subject: [PATCH 0089/1456] properly document the return of load_ssh_private_key (#5927) fixes #5862 --- docs/hazmat/primitives/asymmetric/serialization.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index 15dfbfcb6331..b23e7524db06 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -448,11 +448,11 @@ An example ECDSA key in OpenSSH format:: depending on the key's type. :returns: One of - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey`, depending on the contents of ``data``. :raises ValueError: If the OpenSSH data could not be properly decoded, From 3005e107a83b8fc22f3d2ee2caab72351bce0d7b Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 21 Mar 2021 19:14:00 -0500 Subject: [PATCH 0090/1456] fix XTS less than one block length. fixes #5885 (#5925) * fix XTS less than one block length. fixes #5885 * make XTS test key happy --- src/cryptography/hazmat/backends/openssl/ciphers.py | 8 +++++++- tests/hazmat/primitives/test_aes.py | 8 ++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/cryptography/hazmat/backends/openssl/ciphers.py b/src/cryptography/hazmat/backends/openssl/ciphers.py index 0f96795fdc73..50cbeb69a680 100644 --- a/src/cryptography/hazmat/backends/openssl/ciphers.py +++ b/src/cryptography/hazmat/backends/openssl/ciphers.py @@ -145,7 +145,13 @@ def update_into(self, data: bytes, buf) -> int: res = self._backend._lib.EVP_CipherUpdate( self._ctx, outbuf, outlen, inbuf, inlen ) - self._backend.openssl_assert(res != 0) + if res == 0 and isinstance(self._mode, modes.XTS): + raise ValueError( + "In XTS mode you must supply at least a full block in the " + "first update call. For AES this is 16 bytes." + ) + else: + self._backend.openssl_assert(res != 0) data_processed += inlen total_out += outlen[0] diff --git a/tests/hazmat/primitives/test_aes.py b/tests/hazmat/primitives/test_aes.py index 29a9404633fb..fd37b7696d96 100644 --- a/tests/hazmat/primitives/test_aes.py +++ b/tests/hazmat/primitives/test_aes.py @@ -52,6 +52,14 @@ def test_xts_vectors(self, backend, subtests): computed_pt = dec.update(ct) + dec.finalize() assert computed_pt == pt + def test_xts_too_short(self): + key = b"thirty_two_byte_keys_are_great!!" + tweak = b"\x00" * 16 + cipher = base.Cipher(algorithms.AES(key), modes.XTS(tweak)) + enc = cipher.encryptor() + with pytest.raises(ValueError): + enc.update(b"0" * 15) + @pytest.mark.supported( only_if=lambda backend: backend.cipher_supported( From 0ce239be02693fd80e9e6ed0e68c90e180915afe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Mar 2021 07:48:49 -0400 Subject: [PATCH 0091/1456] Bump ctor from 0.1.19 to 0.1.20 in /src/rust (#5930) Bumps [ctor](https://github.com/mmastrac/rust-ctor) from 0.1.19 to 0.1.20. - [Release notes](https://github.com/mmastrac/rust-ctor/releases) - [Commits](https://github.com/mmastrac/rust-ctor/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 0a20349aeb47..b691e86fc567 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -21,9 +21,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8f45d9ad417bcef4817d614a501ab55cdd96a6fdb24f49aab89a54acfd66b19" +checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d" dependencies = [ "quote", "syn", From fe5cb7551e989286daa1413e9f8d39c2402b8ec1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Mar 2021 08:39:39 -0400 Subject: [PATCH 0092/1456] Bump libc from 0.2.90 to 0.2.91 in /src/rust (#5929) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.90 to 0.2.91. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.90...0.2.91) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index b691e86fc567..40bcc7f2b983 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae" +checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7" [[package]] name = "lock_api" From 1bb7effbf70c55663c556ff497bf774984f07de8 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 25 Mar 2021 23:23:48 -0400 Subject: [PATCH 0093/1456] Backport the 3.4.7 changelog (#5934) --- CHANGELOG.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f2aaebb5c27a..a45502685bf5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,14 @@ Changelog when using OpenSSL 1.1.1. These algorithms are provided for compatibility in regions where they may be required, and are not generally recommended. +.. _v3-4-7: + +3.4.7 - 2021-03-25 +~~~~~~~~~~~~~~~~~~ + +* Updated Windows, macOS, and ``manylinux`` wheels to be compiled with + OpenSSL 1.1.1k. + .. _v3-4-6: 3.4.6 - 2021-02-16 From 40b2ca7c4251b9fc90e9f7a50bf4abba9c9053cc Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 26 Mar 2021 13:35:13 -0400 Subject: [PATCH 0094/1456] bump to latest liberssl (#5937) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e68f089a73af..eb7f6ab658c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "2.9.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.1.5"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.2.4"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.2.5"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.3.1"}} RUST: - stable From e6f5871ed9882b5567bc820f81d0578fdc4731c8 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 30 Mar 2021 20:45:58 -0400 Subject: [PATCH 0095/1456] Attempt to fix the cargo cache (#5942) --- .github/workflows/ci.yml | 7 +++++++ tox.ini | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb7f6ab658c0..19486321457a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -90,6 +90,7 @@ jobs: tox -r -- --color=yes --wycheproof-root=wycheproof env: TOXENV: ${{ matrix.PYTHON.TOXENV }} + CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - uses: ./.github/actions/upload-coverage with: name: "tox -e ${{ matrix.PYTHON.TOXENV }} ${{ env.OSSL_INFO }}" @@ -133,6 +134,7 @@ jobs: env: TOXENV: ${{ matrix.IMAGE.TOXENV }} RUSTUP_HOME: /root/.rustup + CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - uses: ./.github/actions/upload-coverage with: name: "${{ matrix.IMAGE.TOXENV }} on ${{ matrix.IMAGE.IMAGE }}" @@ -178,6 +180,7 @@ jobs: tox -r -- --color=yes --wycheproof-root=wycheproof env: TOXENV: ${{ matrix.PYTHON.TOXENV }} + CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - uses: ./.github/actions/upload-coverage with: name: "${{ matrix.PYTHON.TOXENV }} with Rust ${{ matrix.RUST }}" @@ -232,6 +235,7 @@ jobs: env: TOXENV: ${{ matrix.PYTHON.TOXENV }} EXTRA_CFLAGS: ${{ matrix.PYTHON.EXTRA_CFLAGS }} + CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - uses: ./.github/actions/upload-coverage with: @@ -290,6 +294,7 @@ jobs: - run: tox -r -- --color=yes --wycheproof-root=wycheproof --num-shards=4 --shard-id=${{ matrix.JOB_NUMBER }} env: TOXENV: ${{ matrix.PYTHON.TOXENV }} + CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - uses: ./.github/actions/upload-coverage with: @@ -337,6 +342,8 @@ jobs: - run: ./.github/downstream.d/${{ matrix.DOWNSTREAM }}.sh install - run: pip uninstall -y enum34 - run: pip install . + env: + CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - run: ./.github/downstream.d/${{ matrix.DOWNSTREAM }}.sh run docs-linkcheck: diff --git a/tox.ini b/tox.ini index bdc4da283493..cccbf65efc73 100644 --- a/tox.ini +++ b/tox.ini @@ -8,7 +8,7 @@ extras = test ssh: ssh deps = - ./vectors + -e ./vectors pytest-shard>=0.1.2 randomorder: pytest-randomly passenv = ARCHFLAGS LDFLAGS CFLAGS INCLUDE LIB LD_LIBRARY_PATH USERNAME PYTHONIOENCODING OPENSSL_FORCE_FIPS_MODE From a9de28df8c70be4b145f10ed9fa382dddecbf10a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 30 Mar 2021 22:38:13 -0400 Subject: [PATCH 0096/1456] passenv CARGO_TARGET_DIR (#5943) --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index cccbf65efc73..6fccaed6be3d 100644 --- a/tox.ini +++ b/tox.ini @@ -11,7 +11,7 @@ deps = -e ./vectors pytest-shard>=0.1.2 randomorder: pytest-randomly -passenv = ARCHFLAGS LDFLAGS CFLAGS INCLUDE LIB LD_LIBRARY_PATH USERNAME PYTHONIOENCODING OPENSSL_FORCE_FIPS_MODE +passenv = ARCHFLAGS LDFLAGS CFLAGS INCLUDE LIB LD_LIBRARY_PATH USERNAME PYTHONIOENCODING CARGO_TARGET_DIR OPENSSL_FORCE_FIPS_MODE commands = pip list pytest -n auto --cov=cryptography --cov=tests --capture=no --strict-markers --durations=10 {posargs} From 395fce1704649a436152d50ba5f3dec49565d321 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Mar 2021 22:43:36 -0400 Subject: [PATCH 0097/1456] Bump syn from 1.0.64 to 1.0.67 in /src/rust (#5940) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.64 to 1.0.67. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.64...1.0.67) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 40bcc7f2b983..59992d167847 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -239,9 +239,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "1.0.64" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" +checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" dependencies = [ "proc-macro2", "quote", From 2e4777b6d3a4fedbb339458fffa0622213688d5a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 30 Mar 2021 23:43:52 -0400 Subject: [PATCH 0098/1456] dont reuse caches across different builds (#5945) --- .github/workflows/ci.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19486321457a..07de77115408 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: ~/.cargo/registry ~/.cargo/git src/rust/target/ - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.PYTHON.VERSION }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Setup python uses: actions/setup-python@v2.2.1 @@ -123,7 +123,7 @@ jobs: ~/.cargo/registry ~/.cargo/git src/rust/target/ - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.IMAGE.IMAGE }}-cargo-${{ hashFiles('**/Cargo.lock') }} - run: 'git clone --depth=1 https://github.com/google/wycheproof "$HOME/wycheproof"' - run: | @@ -204,7 +204,7 @@ jobs: ~/.cargo/registry ~/.cargo/git src/rust/target/ - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.PYTHON.VERSION }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Setup python uses: actions/setup-python@v2.2.1 @@ -264,7 +264,7 @@ jobs: ~/.cargo/registry ~/.cargo/git src/rust/target/ - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.WINDOWS.ARCH }}-${{ matrix.PYTHON.VERSION }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Setup python uses: actions/setup-python@v2.2.1 From dd63aca1ae8360429e5923bde7e60374c01e233e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 31 Mar 2021 01:02:24 -0400 Subject: [PATCH 0099/1456] Disable coverage on pypy again (#5944) --- .github/workflows/ci.yml | 4 ++-- tox.ini | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 07de77115408..a6f6ef65ff53 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,8 +16,8 @@ jobs: matrix: PYTHON: - {VERSION: "3.9", TOXENV: "flake,rust,docs", COVERAGE: "false"} - - {VERSION: "pypy-3.6", TOXENV: "pypy3"} - - {VERSION: "pypy-3.7", TOXENV: "pypy3"} + - {VERSION: "pypy-3.6", TOXENV: "pypy3-nocoverage"} + - {VERSION: "pypy-3.7", TOXENV: "pypy3-nocoverage"} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.0l"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} diff --git a/tox.ini b/tox.ini index 6fccaed6be3d..cf01d69de382 100644 --- a/tox.ini +++ b/tox.ini @@ -16,6 +16,14 @@ commands = pip list pytest -n auto --cov=cryptography --cov=tests --capture=no --strict-markers --durations=10 {posargs} +# This target disables coverage on pypy because of performance problems with +# coverage.py on pypy. +[testenv:pypy3-nocoverage] +basepython = pypy3 +commands = + pip list + pytest -n auto --capture=no --strict-markers --durations=10 {posargs} + [testenv:docs] extras = docs From f0b2269f7221f06aacf883b58577ffc9627e7522 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 Mar 2021 08:10:09 -0400 Subject: [PATCH 0100/1456] Bump libc from 0.2.91 to 0.2.92 in /src/rust (#5946) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.91 to 0.2.92. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.91...0.2.92) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 59992d167847..5a523c937f5f 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7" +checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" [[package]] name = "lock_api" From 2839b4b6a2e6c98023748ebccf58649afe6038e4 Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Sun, 4 Apr 2021 00:02:22 +0100 Subject: [PATCH 0101/1456] Update annotation for key (#5951) * Update annotation for key * Update fernet.py * Update fernet.py --- src/cryptography/fernet.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cryptography/fernet.py b/src/cryptography/fernet.py index bcf1c9848c6e..64c12c69a84d 100644 --- a/src/cryptography/fernet.py +++ b/src/cryptography/fernet.py @@ -27,7 +27,11 @@ class InvalidToken(Exception): class Fernet(object): - def __init__(self, key: bytes, backend: typing.Optional[Backend] = None): + def __init__( + self, + key: typing.Union[bytes, str], + backend: typing.Optional[Backend] = None, + ): backend = _get_backend(backend) key = base64.urlsafe_b64decode(key) From 451dcce7fd98c9638247aeb131f186631b4281b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 3 Apr 2021 19:02:45 -0400 Subject: [PATCH 0102/1456] Bump syn from 1.0.67 to 1.0.68 in /src/rust (#5949) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.67 to 1.0.68. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.67...1.0.68) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 5a523c937f5f..8efa08ef8956 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -161,9 +161,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ "unicode-xid", ] @@ -239,9 +239,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "1.0.67" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6498a9efc342871f91cc2d0d694c674368b4ceb40f62b65a7a08c3792935e702" +checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" dependencies = [ "proc-macro2", "quote", From 18bfc45d7150d804eb8fdc57c7f3d93fd09292d1 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 3 Apr 2021 19:15:32 -0400 Subject: [PATCH 0103/1456] Build manylinux_2_24 wheels (#5952) * Build manylinux_2_24 wheels * poke GHA * poke GHA * fix * poke GHA * fix --- .github/workflows/wheel-builder.yml | 1 + .zuul.d/jobs.yaml | 8 ++++++++ .../roles/build-wheel-manylinux/files/build-wheels.sh | 2 +- CHANGELOG.rst | 2 ++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 090a70d526a9..271bd4de46e2 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -18,6 +18,7 @@ jobs: MANYLINUX: - { NAME: "manylinux2010_x86_64", CONTAINER: "cryptography-manylinux2010:x86_64" } - { NAME: "manylinux2014_x86_64", CONTAINER: "cryptography-manylinux2014:x86_64" } + - { name: "manylinux_2_24_x86_64", CONTAINER: "cryptography-manylinux_2_24:x86_64"} name: "${{ matrix.PYTHON.VERSION }} for ${{ matrix.MANYLINUX.NAME }}" steps: - run: ${{ matrix.PYTHON.PATH }} -m venv .venv diff --git a/.zuul.d/jobs.yaml b/.zuul.d/jobs.yaml index 0a0982bab4bd..e9e1561c6fc4 100644 --- a/.zuul.d/jobs.yaml +++ b/.zuul.d/jobs.yaml @@ -42,6 +42,10 @@ image: ghcr.io/pyca/cryptography-manylinux2014_aarch64 pythons: - cp36-cp36m + - platform: manylinux_2_24_aarch64 + image: ghcr.io/pyca/cryptography-manylinux_2_24:aarch64 + pythons: + - cp36-cp36m - job: name: pyca-cryptography-build-wheel-x86_64 @@ -57,3 +61,7 @@ image: ghcr.io/pyca/cryptography-manylinux2014:x86_64 pythons: - cp36-cp36m + - platform: manylinux_2_24_x86_64 + image: ghcr.io/pyca/cryptography-manylinux_2_24:x86_64 + pythons: + - cp36-cp36m diff --git a/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/files/build-wheels.sh b/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/files/build-wheels.sh index d28ff4e7961a..41cd6bcaedf9 100644 --- a/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/files/build-wheels.sh +++ b/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/files/build-wheels.sh @@ -28,7 +28,7 @@ for P in ${PYTHONS}; do # NOTE(ianw) : no execstack on aarch64, comes from # prelink, which was never supported. CentOS 8 does # have it separate, skip for now. - if [[ "${PLAT}" != "manylinux2014_aarch64" ]]; then + if [[ ! "${PLAT}" =~ "aarch64" ]]; then for f in wheelhouse/*.whl; do unzip $f -d execstack.check diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a45502685bf5..2d9e6520697b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,6 +13,8 @@ Changelog :class:`~cryptography.hazmat.primitives.ciphers.algorithms.SM4`, when using OpenSSL 1.1.1. These algorithms are provided for compatibility in regions where they may be required, and are not generally recommended. +* We now ship ``manylinux_2_24`` wheels, in addition to our ``manylinux2010`` + and ``manylinux2014`` wheels. .. _v3-4-7: From 16a3227ccd76617e66f673c1c5acefcca5174ee5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Apr 2021 08:26:14 -0400 Subject: [PATCH 0104/1456] Bump lock_api from 0.4.2 to 0.4.3 in /src/rust (#5953) Bumps [lock_api](https://github.com/Amanieu/parking_lot) from 0.4.2 to 0.4.3. - [Release notes](https://github.com/Amanieu/parking_lot/releases) - [Changelog](https://github.com/Amanieu/parking_lot/blob/master/CHANGELOG.md) - [Commits](https://github.com/Amanieu/parking_lot/compare/lock_api-0.4.2...lock_api-0.4.3) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 8efa08ef8956..a0043367b25f 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -102,9 +102,9 @@ checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" [[package]] name = "lock_api" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" dependencies = [ "scopeguard", ] From fb2246ed00a1f099036c96f6951369ff7e404825 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Apr 2021 08:04:04 -0400 Subject: [PATCH 0105/1456] Bump libc from 0.2.92 to 0.2.93 in /src/rust (#5955) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.92 to 0.2.93. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.92...0.2.93) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index a0043367b25f..6893477010bd 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" +checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" [[package]] name = "lock_api" From cac146f62aa92ea2ca137d3682d63624b35b6629 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 7 Apr 2021 11:43:14 -0400 Subject: [PATCH 0106/1456] Comment out centos arm64 builders so long as they're broken (#5956) --- .zuul.d/project.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.zuul.d/project.yaml b/.zuul.d/project.yaml index b05d6b56f164..6358bc344699 100644 --- a/.zuul.d/project.yaml +++ b/.zuul.d/project.yaml @@ -5,7 +5,8 @@ - pyca-cryptography-build-wheel-x86_64 - pyca-cryptography-ubuntu-focal-py38-arm64 - pyca-cryptography-ubuntu-bionic-py36-arm64 - - pyca-cryptography-centos-8-py36-arm64 + # Commented out because these builders currently do not boot + # - pyca-cryptography-centos-8-py36-arm64 release: jobs: - pyca-cryptography-build-wheel-arm64 From 58f0ad5b6b928677931c7ad44deee839a29ee9d3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 8 Apr 2021 07:58:46 -0400 Subject: [PATCH 0107/1456] Bump syn from 1.0.68 to 1.0.69 in /src/rust (#5957) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.68 to 1.0.69. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.68...1.0.69) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 6893477010bd..2bd1b9f4639d 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -239,9 +239,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" +checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb" dependencies = [ "proc-macro2", "quote", From 19b96a04eb60d23e77824610b3237e9db22b0c06 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 9 Apr 2021 13:57:38 -0400 Subject: [PATCH 0108/1456] re-enable arm64 on centos (#5961) --- .zuul.d/project.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.zuul.d/project.yaml b/.zuul.d/project.yaml index 6358bc344699..b05d6b56f164 100644 --- a/.zuul.d/project.yaml +++ b/.zuul.d/project.yaml @@ -5,8 +5,7 @@ - pyca-cryptography-build-wheel-x86_64 - pyca-cryptography-ubuntu-focal-py38-arm64 - pyca-cryptography-ubuntu-bionic-py36-arm64 - # Commented out because these builders currently do not boot - # - pyca-cryptography-centos-8-py36-arm64 + - pyca-cryptography-centos-8-py36-arm64 release: jobs: - pyca-cryptography-build-wheel-arm64 From 851877e3e8dd7e6b6035c2e02d80690c4c8b9cf6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 9 Apr 2021 15:57:06 -0400 Subject: [PATCH 0109/1456] pin to 3.9.2 due to bugs (#5962) https://github.com/actions/setup-python/issues/202 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6f6ef65ff53..113e46d9d801 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -250,7 +250,7 @@ jobs: - {ARCH: 'x64', WINDOWS: 'win64', RUST_TRIPLE: 'x86_64-pc-windows-msvc'} PYTHON: - {VERSION: "3.6", TOXENV: "py36", MSVC_VERSION: "2019", CL_FLAGS: ""} - - {VERSION: "3.9", TOXENV: "py39", MSVC_VERSION: "2019", CL_FLAGS: "/D USE_OSRANDOM_RNG_FOR_TESTING"} + - {VERSION: "3.9.2", TOXENV: "py39", MSVC_VERSION: "2019", CL_FLAGS: "/D USE_OSRANDOM_RNG_FOR_TESTING"} RUST: - stable JOB_NUMBER: [0, 1, 2, 3] From ead82753899c4ad1d4096d718d65d4df64836ddd Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 11 Apr 2021 16:44:27 -0400 Subject: [PATCH 0110/1456] Port a tiny tiny bit of the ASN.1 parsing to Rust (#5357) --- .../hazmat/backends/openssl/decode_asn1.py | 23 ++---- src/rust/Cargo.lock | 47 ++++++++++++ src/rust/Cargo.toml | 1 + src/rust/src/asn1.rs | 75 +++++++++++++++++++ src/rust/src/lib.rs | 6 +- 5 files changed, 135 insertions(+), 17 deletions(-) create mode 100644 src/rust/src/asn1.rs diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index e62c25406b39..6e4dc0e939d1 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -8,8 +8,7 @@ import typing from cryptography import x509 -from cryptography.hazmat._der import DERReader, INTEGER, NULL, SEQUENCE -from cryptography.x509.extensions import _TLS_FEATURE_TYPE_TO_ENUM +from cryptography.hazmat.bindings._rust import asn1 from cryptography.x509.name import _ASN1_TYPE_TO_ENUM from cryptography.x509.oid import ( CRLEntryExtensionOID, @@ -211,25 +210,17 @@ def parse(self, x509_obj): # The extension contents are a SEQUENCE OF INTEGERs. data = self._backend._lib.X509_EXTENSION_get_data(ext) data_bytes = _asn1_string_to_bytes(self._backend, data) - features = DERReader(data_bytes).read_single_element(SEQUENCE) - parsed = [] - while not features.is_empty(): - parsed.append(features.read_element(INTEGER).as_integer()) - # Map the features to their enum value. - value = x509.TLSFeature( - [_TLS_FEATURE_TYPE_TO_ENUM[x] for x in parsed] - ) + value = asn1.parse_tls_feature(data_bytes) + extensions.append(x509.Extension(oid, critical, value)) seen_oids.add(oid) continue elif oid == ExtensionOID.PRECERT_POISON: data = self._backend._lib.X509_EXTENSION_get_data(ext) - # The contents of the extension must be an ASN.1 NULL. - reader = DERReader(_asn1_string_to_bytes(self._backend, data)) - reader.read_single_element(NULL).check_empty() - extensions.append( - x509.Extension(oid, critical, x509.PrecertPoison()) - ) + data_bytes = _asn1_string_to_bytes(self._backend, data) + value = asn1.parse_precert_poison(data_bytes) + + extensions.append(x509.Extension(oid, critical, value)) seen_oids.add(oid) continue diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 2bd1b9f4639d..8cd155ba8fbc 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -1,5 +1,22 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + +[[package]] +name = "asn1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d2efbfc907088c522a054db6e60277d3f3bf0cf73cd3e2676806f4d95f3b20" +dependencies = [ + "chrono", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + [[package]] name = "bitflags" version = "1.2.1" @@ -12,10 +29,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "cryptography-rust" version = "0.1.0" dependencies = [ + "asn1", "pyo3", ] @@ -109,6 +137,25 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + [[package]] name = "parking_lot" version = "0.11.1" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index bcb9add10020..b0dbc6f119f8 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -7,6 +7,7 @@ publish = false [dependencies] pyo3 = { version = "0.13.1", features = ["extension-module"] } +asn1 = { version = "0.3", default-features = false } [lib] name = "cryptography_rust" diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs new file mode 100644 index 000000000000..a2db23e12328 --- /dev/null +++ b/src/rust/src/asn1.rs @@ -0,0 +1,75 @@ +// 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. + +use pyo3::conversion::ToPyObject; + +enum PyAsn1Error { + Asn1(asn1::ParseError), + Py(pyo3::PyErr), +} + +impl From for PyAsn1Error { + fn from(e: asn1::ParseError) -> PyAsn1Error { + PyAsn1Error::Asn1(e) + } +} + +impl From for PyAsn1Error { + fn from(e: pyo3::PyErr) -> PyAsn1Error { + PyAsn1Error::Py(e) + } +} + +impl From for pyo3::PyErr { + fn from(e: PyAsn1Error) -> pyo3::PyErr { + match e { + PyAsn1Error::Asn1(asn1_error) => pyo3::exceptions::PyValueError::new_err(format!( + "error parsing asn1 value: {:?}", + asn1_error + )), + PyAsn1Error::Py(py_error) => py_error, + } + } +} + +#[pyo3::prelude::pyfunction] +fn parse_tls_feature(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult { + let tls_feature_type_to_enum = py + .import("cryptography.x509.extensions")? + .getattr("_TLS_FEATURE_TYPE_TO_ENUM")?; + + let features = asn1::parse::<_, PyAsn1Error, _>(data, |p| { + let features = pyo3::types::PyList::empty(py); + for el in p.read_element::>()? { + let feature = el?; + let py_feature = tls_feature_type_to_enum.get_item(feature.to_object(py))?; + features.append(py_feature)?; + } + Ok(features) + })?; + + let x509_module = py.import("cryptography.x509")?; + x509_module + .call1("TLSFeature", (features,)) + .map(|o| o.to_object(py)) +} + +#[pyo3::prelude::pyfunction] +fn parse_precert_poison(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult { + asn1::parse::<_, PyAsn1Error, _>(data, |p| { + p.read_element::<()>()?; + Ok(()) + })?; + + let x509_module = py.import("cryptography.x509")?; + x509_module.call0("PrecertPoison").map(|o| o.to_object(py)) +} + +pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let submod = pyo3::prelude::PyModule::new(py, "asn1")?; + submod.add_wrapped(pyo3::wrap_pyfunction!(parse_tls_feature))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(parse_precert_poison))?; + + Ok(submod) +} diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 3257b35e123f..a3b3fb715141 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -2,6 +2,8 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. +mod asn1; + use std::convert::TryInto; /// Returns the value of the input with the most-significant-bit copied to all @@ -66,10 +68,12 @@ fn check_ansix923_padding(data: &[u8]) -> bool { } #[pyo3::prelude::pymodule] -fn _rust(_py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { +fn _rust(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { m.add_function(pyo3::wrap_pyfunction!(check_pkcs7_padding, m)?)?; m.add_function(pyo3::wrap_pyfunction!(check_ansix923_padding, m)?)?; + m.add_submodule(asn1::create_submodule(py)?)?; + Ok(()) } From bc8df094247f703701667263818b3d57e77b6848 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 11 Apr 2021 23:43:58 -0400 Subject: [PATCH 0111/1456] Converted DER parsing of SPKIs to rust (#5963) --- src/cryptography/x509/extensions.py | 27 ++------------------------ src/rust/Cargo.lock | 4 ++-- src/rust/Cargo.toml | 2 +- src/rust/src/asn1.rs | 30 +++++++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 296de95d81b6..fb229d395070 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -10,13 +10,8 @@ import typing from enum import Enum -from cryptography.hazmat._der import ( - BIT_STRING, - DERReader, - OBJECT_IDENTIFIER, - SEQUENCE, -) from cryptography.hazmat._types import _PUBLIC_KEY_TYPES +from cryptography.hazmat.bindings._rust import asn1 from cryptography.hazmat.primitives import constant_time, serialization from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey @@ -62,25 +57,7 @@ def _key_identifier_from_public_key(public_key: _PUBLIC_KEY_TYPES) -> bytes: serialization.Encoding.DER, serialization.PublicFormat.SubjectPublicKeyInfo, ) - - reader = DERReader(serialized) - with reader.read_single_element(SEQUENCE) as public_key_info: - algorithm = public_key_info.read_element(SEQUENCE) - public_key_data = public_key_info.read_element(BIT_STRING) - - # Double-check the algorithm structure. - with algorithm: - algorithm.read_element(OBJECT_IDENTIFIER) - if not algorithm.is_empty(): - # Skip the optional parameters field. - algorithm.read_any_element() - - # BIT STRING contents begin with the number of padding bytes added. It - # must be zero for SubjectPublicKeyInfo structures. - if public_key_data.read_byte() != 0: - raise ValueError("Invalid public key encoding") - - data = public_key_data.data + data = asn1.parse_spki_for_data(serialized) return hashlib.sha1(data).digest() diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 8cd155ba8fbc..adb82e4e45e4 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "asn1" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d2efbfc907088c522a054db6e60277d3f3bf0cf73cd3e2676806f4d95f3b20" +checksum = "698c3b9621a1a2f9c98fceabba22e495a5f2604e773ec5fbd8a42cd797aa6d24" dependencies = [ "chrono", ] diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index b0dbc6f119f8..6d2a1e199c18 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] pyo3 = { version = "0.13.1", features = ["extension-module"] } -asn1 = { version = "0.3", default-features = false } +asn1 = { version = "0.3.1", default-features = false } [lib] name = "cryptography_rust" diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index a2db23e12328..a5a9a856f092 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -66,10 +66,40 @@ fn parse_precert_poison(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult, data: &[u8]) -> pyo3::PyResult { + let result = asn1::parse::<_, PyAsn1Error, _>(data, |p| { + p.read_element::()? + .parse::<_, PyAsn1Error, _>(|p| { + // AlgorithmIdentifier + p.read_element::()? + .parse::<_, PyAsn1Error, _>(|p| { + p.read_element::()?; + if !p.is_empty() { + p.read_element::()?; + } + Ok(()) + })?; + + let pubkey_data = p.read_element::()?; + if pubkey_data.padding_bits() != 0 { + return Err(pyo3::exceptions::PyValueError::new_err( + "Invalid public key encoding", + ) + .into()); + } + Ok(pubkey_data.as_bytes()) + }) + })?; + + Ok(pyo3::types::PyBytes::new(py, result).to_object(py)) +} + pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let submod = pyo3::prelude::PyModule::new(py, "asn1")?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_tls_feature))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_precert_poison))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(parse_spki_for_data))?; Ok(submod) } From 39966b2a22d3fcddb5c464baff19b11daf67ebdc Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Mon, 12 Apr 2021 17:33:40 +0200 Subject: [PATCH 0112/1456] Set `dirhtml` builder explicitly in the RTD config (#5964) After introducing the `.readthedocs.yml` config in the repo, it started overriding all of the settings set via the RTD UI unintentionally switching the URL scheme. This change reverts that switch resurrecting the old one. Fixes #5863 Refs: * https://github.com/pyca/cryptography/issues/5863#issuecomment-817828152 --- .readthedocs.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.readthedocs.yml b/.readthedocs.yml index ac4882422355..04d5d1a444d8 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,5 +1,10 @@ version: 2 +sphinx: + # The config file overrides the UI settings: + # https://github.com/pyca/cryptography/issues/5863#issuecomment-817828152 + builder: dirhtml + build: # First RTD build env which includes a rust toolchain image: "7.0" From 89679f64104f309938594e601dad9cf8e0930fc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Apr 2021 07:45:25 -0400 Subject: [PATCH 0113/1456] Bump actions/cache from v2.1.4 to v2.1.5 (#5967) Bumps [actions/cache](https://github.com/actions/cache) from v2.1.4 to v2.1.5. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v2.1.4...1a9e2138d905efd099035b49d8b7a3888c653ca8) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 113e46d9d801..f9fe126cf41f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v2 - - uses: actions/cache@v2.1.4 + - uses: actions/cache@v2.1.5 with: path: | ~/.cargo/registry @@ -66,7 +66,7 @@ jobs: CONFIG_FLAGS: ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }} if: matrix.PYTHON.OPENSSL - name: Load cache - uses: actions/cache@v2.1.4 + uses: actions/cache@v2.1.5 id: ossl-cache with: path: ${{ github.workspace }}/osslcache @@ -117,7 +117,7 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v2 - - uses: actions/cache@v2.1.4 + - uses: actions/cache@v2.1.5 with: path: | ~/.cargo/registry @@ -155,7 +155,7 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v2 - - uses: actions/cache@v2.1.4 + - uses: actions/cache@v2.1.5 with: path: | ~/.cargo/registry @@ -198,7 +198,7 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v2 - - uses: actions/cache@v2.1.4 + - uses: actions/cache@v2.1.5 with: path: | ~/.cargo/registry @@ -258,7 +258,7 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v2 - - uses: actions/cache@v2.1.4 + - uses: actions/cache@v2.1.5 with: path: | ~/.cargo/registry @@ -320,7 +320,7 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v2 - - uses: actions/cache@v2.1.4 + - uses: actions/cache@v2.1.5 with: path: | ~/.cargo/registry From c5acddf1d4020073d0b0560991314d1b6d83ba80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Apr 2021 07:46:43 -0400 Subject: [PATCH 0114/1456] Bump actions/setup-python from v2.2.1 to v2.2.2 (#5966) Bumps [actions/setup-python](https://github.com/actions/setup-python) from v2.2.1 to v2.2.2. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v2.2.1...dc73133d4da04e56a135ae2246682783cc7c7cb6) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 12 ++++++------ .github/workflows/wheel-builder.yml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f9fe126cf41f..3d9ac0a535ca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,7 +42,7 @@ jobs: key: ${{ runner.os }}-${{ matrix.PYTHON.VERSION }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Setup python - uses: actions/setup-python@v2.2.1 + uses: actions/setup-python@v2.2.2 with: python-version: ${{ matrix.PYTHON.VERSION }} - uses: actions-rs/toolchain@v1 @@ -164,7 +164,7 @@ jobs: key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-${{ matrix.RUST }} - name: Setup python - uses: actions/setup-python@v2.2.1 + uses: actions/setup-python@v2.2.2 with: python-version: ${{ matrix.PYTHON.VERSION }} - uses: actions-rs/toolchain@v1 @@ -207,7 +207,7 @@ jobs: key: ${{ runner.os }}-${{ matrix.PYTHON.VERSION }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Setup python - uses: actions/setup-python@v2.2.1 + uses: actions/setup-python@v2.2.2 with: python-version: ${{ matrix.PYTHON.VERSION }} - uses: actions-rs/toolchain@v1 @@ -267,7 +267,7 @@ jobs: key: ${{ runner.os }}-${{ matrix.WINDOWS.ARCH }}-${{ matrix.PYTHON.VERSION }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Setup python - uses: actions/setup-python@v2.2.1 + uses: actions/setup-python@v2.2.2 with: python-version: ${{ matrix.PYTHON.VERSION }} architecture: ${{ matrix.WINDOWS.ARCH }} @@ -329,7 +329,7 @@ jobs: key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - name: Setup python - uses: actions/setup-python@v2.2.1 + uses: actions/setup-python@v2.2.2 with: python-version: ${{ matrix.PYTHON }} - uses: actions-rs/toolchain@v1 @@ -354,7 +354,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Setup python - uses: actions/setup-python@v2.2.1 + uses: actions/setup-python@v2.2.2 with: python-version: 3.9 - uses: actions-rs/toolchain@v1 diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 271bd4de46e2..2b165041fa0b 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -122,7 +122,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Setup python - uses: actions/setup-python@v2.2.1 + uses: actions/setup-python@v2.2.2 with: python-version: ${{ matrix.PYTHON.VERSION }} architecture: ${{ matrix.WINDOWS.ARCH }} From db89e50033c1e41d0bd881785cdb096481ed7401 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Apr 2021 08:16:58 -0400 Subject: [PATCH 0115/1456] Bump asn1 from 0.3.1 to 0.3.3 in /src/rust (#5968) Bumps [asn1](https://github.com/alex/rust-asn1) from 0.3.1 to 0.3.3. - [Release notes](https://github.com/alex/rust-asn1/releases) - [Commits](https://github.com/alex/rust-asn1/compare/0.3.1...0.3.3) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- src/rust/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index adb82e4e45e4..af5e87fe0062 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "asn1" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "698c3b9621a1a2f9c98fceabba22e495a5f2604e773ec5fbd8a42cd797aa6d24" +checksum = "8c84b3b0c3c7051ba03423057b884aee14dc2c5b7741d58e6ad31d0908f0887a" dependencies = [ "chrono", ] diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 6d2a1e199c18..961356f051eb 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] pyo3 = { version = "0.13.1", features = ["extension-module"] } -asn1 = { version = "0.3.1", default-features = false } +asn1 = { version = "0.3.3", default-features = false } [lib] name = "cryptography_rust" From b2f9a0e1a546c3b10a6e96cd5e8423a7b04970c7 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Tue, 13 Apr 2021 20:45:01 +0200 Subject: [PATCH 0116/1456] Add x509.Name.rfc4514_attribute_name (#5969) * add x509.Name.rfc4514_attribute_name * tests++, docs++ * lint++ --- CHANGELOG.rst | 2 ++ docs/x509/reference.rst | 9 +++++++++ src/cryptography/x509/name.py | 14 ++++++++++++-- tests/x509/test_x509.py | 6 ++++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2d9e6520697b..4f368b00f4a3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,8 @@ Changelog in regions where they may be required, and are not generally recommended. * We now ship ``manylinux_2_24`` wheels, in addition to our ``manylinux2010`` and ``manylinux2014`` wheels. +* Added ``rfc4514_attribute_name`` attribute to + :attr:`x509.NameAttribute `, .. _v3-4-7: diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index 105f8e10686c..6c058f9f78d5 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -1333,6 +1333,15 @@ X.509 CSR (Certificate Signing Request) Builder Object The value of the attribute. + .. attribute:: rfc4514_attribute_name + + .. versionadded:: 35.0 + + :type: :term:`text` + + The :rfc:`4514` short attribute name (for example "CN"), + or the OID dotted string if a short name is unavailable. + .. method:: rfc4514_string() .. versionadded:: 2.5 diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py index 0bfc2d94d452..e0ba6674d5b1 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -118,6 +118,14 @@ def oid(self) -> ObjectIdentifier: def value(self) -> str: return self._value + @property + def rfc4514_attribute_name(self) -> str: + """ + The short attribute name (for example "CN") if available, + otherwise the OID dotted string. + """ + return _NAMEOID_TO_NAME.get(self.oid, self.oid.dotted_string) + def rfc4514_string(self) -> str: """ Format as RFC4514 Distinguished Name string. @@ -125,8 +133,10 @@ def rfc4514_string(self) -> str: 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)) + return "%s=%s" % ( + self.rfc4514_attribute_name, + _escape_dn_value(self.value), + ) def __eq__(self, other: object) -> bool: if not isinstance(other, NameAttribute): diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index b3bf78a6862e..765beaebe1af 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -4991,6 +4991,12 @@ def test_repr(self, common_name, org_name, expected_repr): assert repr(name) == expected_repr + def test_rfc4514_attribute_name(self): + a = x509.NameAttribute(NameOID.COMMON_NAME, "cryptography.io") + assert a.rfc4514_attribute_name == "CN" + b = x509.NameAttribute(NameOID.PSEUDONYM, "cryptography.io") + assert b.rfc4514_attribute_name == "2.5.4.65" + def test_rfc4514_string(self): n = x509.Name( [ From 42884072d1f0851bdd50129b6831dbac6c072717 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Apr 2021 08:30:21 -0400 Subject: [PATCH 0117/1456] Bump redox_syscall from 0.2.5 to 0.2.6 in /src/rust (#5971) Bumps redox_syscall from 0.2.5 to 0.2.6. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index af5e87fe0062..8bfc5208b00a 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -265,9 +265,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +checksum = "8270314b5ccceb518e7e578952f0b72b88222d02e8f77f5ecf7abbb673539041" dependencies = [ "bitflags", ] From af1465acaf32dbecea3716a1d427cb8b02a06fc0 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 14 Apr 2021 13:15:57 -0500 Subject: [PATCH 0118/1456] switch to using EVP_PKEY_derive instead of DH_compute_key in DH (#5972) * switch to using EVP_PKEY_derive instead of DH_compute_key in DH Where checks are occurring is changing in OpenSSL 3.0 and this makes it easier to be consistent (and is the API we should be using anyway). The tests change because EVP_PKEY_derive now verifies that we have shared parameters, which the test previously only verified by asserting that the derived keys didn't match * review feedback * type ignores required for typeerror tests. some day i will remember this --- src/_cffi_src/openssl/dh.py | 1 - .../hazmat/backends/openssl/dh.py | 57 ++++++++++++------- tests/hazmat/primitives/test_dh.py | 19 ++++--- 3 files changed, 45 insertions(+), 32 deletions(-) diff --git a/src/_cffi_src/openssl/dh.py b/src/_cffi_src/openssl/dh.py index 979dafa94253..50989e45343a 100644 --- a/src/_cffi_src/openssl/dh.py +++ b/src/_cffi_src/openssl/dh.py @@ -18,7 +18,6 @@ void DH_free(DH *); int DH_size(const DH *); int DH_generate_key(DH *); -int DH_compute_key(unsigned char *, const BIGNUM *, DH *); DH *DHparams_dup(DH *); /* added in 1.1.0 when the DH struct was opaqued */ diff --git a/src/cryptography/hazmat/backends/openssl/dh.py b/src/cryptography/hazmat/backends/openssl/dh.py index 65ddaeec5fe2..b928f024f56f 100644 --- a/src/cryptography/hazmat/backends/openssl/dh.py +++ b/src/cryptography/hazmat/backends/openssl/dh.py @@ -127,35 +127,48 @@ def private_numbers(self) -> dh.DHPrivateNumbers: ) def exchange(self, peer_public_key: dh.DHPublicKey) -> bytes: - buf = self._backend._ffi.new("unsigned char[]", self._key_size_bytes) - pub_key = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DH_get0_key( - peer_public_key._dh_cdata, # type: ignore[attr-defined] - pub_key, - self._backend._ffi.NULL, + if not isinstance(peer_public_key, _DHPublicKey): + raise TypeError("peer_public_key must be a DHPublicKey") + + ctx = self._backend._lib.EVP_PKEY_CTX_new( + self._evp_pkey, self._backend._ffi.NULL ) - self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) - res = self._backend._lib.DH_compute_key( - buf, pub_key[0], self._dh_cdata + 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 + ) + # Invalid kex errors here in OpenSSL 3.0 because checks were moved + # to EVP_PKEY_derive_set_peer + self._exchange_assert(res == 1) + keylen = self._backend._ffi.new("size_t *") + res = self._backend._lib.EVP_PKEY_derive( + ctx, self._backend._ffi.NULL, keylen ) + # Invalid kex errors here in OpenSSL < 3 + self._exchange_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) - if res == -1: + key = self._backend._ffi.buffer(buf, keylen[0])[:] + pad = self._key_size_bytes - len(key) + + if pad > 0: + key = (b"\x00" * pad) + key + + return key + + def _exchange_assert(self, ok): + if not ok: errors_with_text = self._backend._consume_errors_with_text() raise ValueError( - "Error computing shared key. Public key is likely invalid " - "for this exchange.", + "Error computing shared key.", errors_with_text, ) - else: - self._backend.openssl_assert(res >= 1) - - key = self._backend._ffi.buffer(buf)[:res] - pad = self._key_size_bytes - len(key) - - if pad > 0: - key = (b"\x00" * pad) + key - - return key def public_key(self) -> dh.DHPublicKey: dh_cdata = _dh_params_dup(self._dh_cdata, self._backend) diff --git a/tests/hazmat/primitives/test_dh.py b/tests/hazmat/primitives/test_dh.py index 17d3a776e7a3..9e7f7f51d3d7 100644 --- a/tests/hazmat/primitives/test_dh.py +++ b/tests/hazmat/primitives/test_dh.py @@ -274,6 +274,12 @@ def test_generate_dh(self, backend, with_q): assert isinstance(key.private_numbers(), dh.DHPrivateNumbers) assert isinstance(key.parameters(), dh.DHParameters) + def test_exchange_wrong_type(self, backend): + parameters = FFDH3072_P.parameters(backend) + key1 = parameters.generate_private_key() + with pytest.raises(TypeError): + key1.exchange(b"invalidtype") # type: ignore[arg-type] + def test_exchange(self, backend): parameters = FFDH3072_P.parameters(backend) assert isinstance(parameters, dh.DHParameters) @@ -364,16 +370,11 @@ def test_bad_exchange(self, backend, vector): key2 = private2.private_key(backend) pub_key2 = key2.public_key() - if pub_key2.public_numbers().y >= parameters1.p: - with pytest.raises(ValueError): - key1.exchange(pub_key2) - else: - symkey1 = key1.exchange(pub_key2) - assert symkey1 - - symkey2 = key2.exchange(pub_key1) + with pytest.raises(ValueError): + key1.exchange(pub_key2) - assert symkey1 != symkey2 + with pytest.raises(ValueError): + key2.exchange(pub_key1) @pytest.mark.skip_fips(reason="key_size too small for FIPS") def test_load_256bit_key_from_pkcs8(self, backend): From 31564b8423a17913a374406782801b7372c98124 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 14 Apr 2021 20:21:04 -0400 Subject: [PATCH 0119/1456] Attempt to capture rust coverage and sent it to codecov (#5970) * Attempt to capture rust coverage and sent it to codecov * Allow this var in tox.ini * fix tox job * added llvm-tools-preview * Install cargo-binutils * Futz with paths * fix? * Make paths relative to repo base * Upload this so I can poke it * add format * A new testcase * typo * Do the workaround so we can have 100% coverage * typo * we don't need this --- .github/workflows/ci.yml | 56 +++++++++++++++++++++++++++++++++++++ src/rust/src/asn1.rs | 5 ++-- tests/x509/test_x509_ext.py | 11 ++++++++ tox.ini | 2 +- 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3d9ac0a535ca..ca049fc8fa69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -185,6 +185,62 @@ jobs: with: name: "${{ matrix.PYTHON.TOXENV }} with Rust ${{ matrix.RUST }}" + linux-rust-coverage: + runs-on: ubuntu-latest + name: "Rust Coverage" + timeout-minutes: 30 + steps: + - uses: actions/checkout@v2 + - uses: actions/cache@v2.1.5 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + src/rust/target/ + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-rust-nightly-coverage + + - name: Setup python + uses: actions/setup-python@v2.2.2 + with: + python-version: 3.9 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + default: true + components: llvm-tools-preview + - uses: actions-rs/install@v0.1 + with: + crate: cargo-binutils + version: latest + + - run: git clone --depth=1 https://github.com/google/wycheproof + - run: python -m pip install tox coverage + - name: Tests + run: | + tox -r -- --color=yes --wycheproof-root=wycheproof + env: + TOXENV: py39 + CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} + RUSTFLAGS: "-Zinstrument-coverage" + LLVM_PROFILE_FILE: "rust-cov/cov-%p.profraw" + - name: Process coverage data + run: | + cd src/rust/ + cargo profdata -- merge -sparse ../../rust-cov/*.profraw -o rust-cov.profdata + cargo cov -- export ../../.tox/py39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust.abi3.so \ + -instr-profile=rust-cov.profdata \ + --ignore-filename-regex='/.cargo/registry' \ + --ignore-filename-regex='/.rustup/toolchains/' --format=lcov > ../../rust-cov.lcov + + sed -E -i 's/SF:src\/(.*)/SF:src\/rust\/src\/\1/g' ../../rust-cov.lcov + + - uses: ./.github/actions/upload-coverage + with: + name: "Rust Coverage" + + macos: runs-on: macos-latest strategy: diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index a5a9a856f092..0eac927553de 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -35,9 +35,8 @@ impl From for pyo3::PyErr { #[pyo3::prelude::pyfunction] fn parse_tls_feature(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult { - let tls_feature_type_to_enum = py - .import("cryptography.x509.extensions")? - .getattr("_TLS_FEATURE_TYPE_TO_ENUM")?; + let x509_mod = py.import("cryptography.x509.extensions")?; + let tls_feature_type_to_enum = x509_mod.getattr("_TLS_FEATURE_TYPE_TO_ENUM")?; let features = asn1::parse::<_, PyAsn1Error, _>(data, |p| { let features = pyo3::types::PyList::empty(py); diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index 5fd3b527f5eb..480a8757dad9 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -1556,6 +1556,17 @@ def test_invalid_bit_string_padding_from_public_key(self, backend): with pytest.raises(ValueError): _key_identifier_from_public_key(pretend_key) + # The previous value is invalid for 2 reasons: a) it's got non-zero + # padding bits (i.e. the first byte of the value is not zero), b) the + # padding bits aren't all set to zero (i.e. the last bits of the value) + # Here we swap the last byte out with zeros so we can hit both error + # checks. + pretend_key = pretend.stub( + public_bytes=lambda x, y: data[:-1] + b"\x00" + ) + with pytest.raises(ValueError, match="Invalid public key encoding"): + _key_identifier_from_public_key(pretend_key) + def test_no_optional_params_allowed_from_public_key(self, backend): data = load_vectors_from_file( filename=os.path.join( diff --git a/tox.ini b/tox.ini index cf01d69de382..03cb89bf5bd3 100644 --- a/tox.ini +++ b/tox.ini @@ -11,7 +11,7 @@ deps = -e ./vectors pytest-shard>=0.1.2 randomorder: pytest-randomly -passenv = ARCHFLAGS LDFLAGS CFLAGS INCLUDE LIB LD_LIBRARY_PATH USERNAME PYTHONIOENCODING CARGO_TARGET_DIR OPENSSL_FORCE_FIPS_MODE +passenv = ARCHFLAGS LDFLAGS CFLAGS INCLUDE LIB LD_LIBRARY_PATH USERNAME PYTHONIOENCODING RUSTFLAGS CARGO_TARGET_DIR LLVM_PROFILE_FILE OPENSSL_FORCE_FIPS_MODE commands = pip list pytest -n auto --cov=cryptography --cov=tests --capture=no --strict-markers --durations=10 {posargs} From 6dc334feacf0b68bfcfdb720748369cce0630997 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 14 Apr 2021 22:15:00 -0500 Subject: [PATCH 0120/1456] switch to evp_pkey_derive for ECDH (#5973) remove unused lower level bindings, improve error msg --- src/_cffi_src/openssl/ec.py | 2 -- src/_cffi_src/openssl/ecdh.py | 2 -- src/cryptography/hazmat/backends/openssl/ec.py | 15 ++------------- src/cryptography/hazmat/backends/openssl/utils.py | 3 ++- 4 files changed, 4 insertions(+), 18 deletions(-) diff --git a/src/_cffi_src/openssl/ec.py b/src/_cffi_src/openssl/ec.py index 32d9b5843197..61d1cb3bb93d 100644 --- a/src/_cffi_src/openssl/ec.py +++ b/src/_cffi_src/openssl/ec.py @@ -33,8 +33,6 @@ EC_GROUP *EC_GROUP_new_by_curve_name(int); -int EC_GROUP_get_degree(const EC_GROUP *); - const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *); const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *); int EC_GROUP_get_curve_name(const EC_GROUP *); diff --git a/src/_cffi_src/openssl/ecdh.py b/src/_cffi_src/openssl/ecdh.py index 522642aafabc..d42c988b1e68 100644 --- a/src/_cffi_src/openssl/ecdh.py +++ b/src/_cffi_src/openssl/ecdh.py @@ -11,8 +11,6 @@ """ FUNCTIONS = """ -int ECDH_compute_key(void *, size_t, const EC_POINT *, EC_KEY *, - void *(*)(const void *, size_t, void *, size_t *)); long SSL_CTX_set_ecdh_auto(SSL_CTX *, int); """ diff --git a/src/cryptography/hazmat/backends/openssl/ec.py b/src/cryptography/hazmat/backends/openssl/ec.py index 3f54d72811e6..0199b5ea72e4 100644 --- a/src/cryptography/hazmat/backends/openssl/ec.py +++ b/src/cryptography/hazmat/backends/openssl/ec.py @@ -12,6 +12,7 @@ from cryptography.hazmat.backends.openssl.utils import ( _calculate_digest_and_algorithm, _check_not_prehashed, + _evp_pkey_derive, _warn_sign_verify_deprecated, ) from cryptography.hazmat.primitives import hashes, serialization @@ -195,19 +196,7 @@ def exchange( "peer_public_key and self are not on the same curve" ) - group = self._backend._lib.EC_KEY_get0_group(self._ec_key) - z_len = (self._backend._lib.EC_GROUP_get_degree(group) + 7) // 8 - self._backend.openssl_assert(z_len > 0) - z_buf = self._backend._ffi.new("uint8_t[]", z_len) - peer_key = self._backend._lib.EC_KEY_get0_public_key( - peer_public_key._ec_key # type: ignore[attr-defined] - ) - - r = self._backend._lib.ECDH_compute_key( - z_buf, z_len, peer_key, self._ec_key, self._backend._ffi.NULL - ) - self._backend.openssl_assert(r > 0) - return self._backend._ffi.buffer(z_buf)[:z_len] + return _evp_pkey_derive(self._backend, self._evp_pkey, peer_public_key) def public_key(self) -> ec.EllipticCurvePublicKey: group = self._backend._lib.EC_KEY_get0_group(self._ec_key) diff --git a/src/cryptography/hazmat/backends/openssl/utils.py b/src/cryptography/hazmat/backends/openssl/utils.py index 03e36f5b05f6..44945d30a9a0 100644 --- a/src/cryptography/hazmat/backends/openssl/utils.py +++ b/src/cryptography/hazmat/backends/openssl/utils.py @@ -25,7 +25,8 @@ def _evp_pkey_derive(backend, evp_pkey, peer_public_key): 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.") + errors_with_text = backend._consume_errors_with_text() + raise ValueError("Error computing shared key.", errors_with_text) return backend._ffi.buffer(buf, keylen[0])[:] From 136a6f6baa42bb4d737b1c22ac68124c0af76368 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 14 Apr 2021 23:10:52 -0500 Subject: [PATCH 0121/1456] remove bionic and centos 8 arm64 jobs (#5974) * remove bionic and centos 8 arm64 jobs Reliability and speed is insufficient and we get almost the same CI bug finding value with just one arm64 job for now. * missed this --- .zuul.d/jobs.yaml | 14 -------------- .zuul.d/project.yaml | 2 -- 2 files changed, 16 deletions(-) diff --git a/.zuul.d/jobs.yaml b/.zuul.d/jobs.yaml index e9e1561c6fc4..8a61080ea537 100644 --- a/.zuul.d/jobs.yaml +++ b/.zuul.d/jobs.yaml @@ -12,20 +12,6 @@ vars: tox_envlist: py38 -- job: - name: pyca-cryptography-ubuntu-bionic-py36-arm64 - parent: pyca-cryptography-base - nodeset: ubuntu-bionic-arm64 - vars: - tox_envlist: py36 - -- job: - name: pyca-cryptography-centos-8-py36-arm64 - parent: pyca-cryptography-base - nodeset: centos-8-arm64 - vars: - tox_envlist: py36 - - job: name: pyca-cryptography-build-wheel abstract: true diff --git a/.zuul.d/project.yaml b/.zuul.d/project.yaml index b05d6b56f164..6d6d899d1ee9 100644 --- a/.zuul.d/project.yaml +++ b/.zuul.d/project.yaml @@ -4,8 +4,6 @@ - pyca-cryptography-build-wheel-arm64 - pyca-cryptography-build-wheel-x86_64 - pyca-cryptography-ubuntu-focal-py38-arm64 - - pyca-cryptography-ubuntu-bionic-py36-arm64 - - pyca-cryptography-centos-8-py36-arm64 release: jobs: - pyca-cryptography-build-wheel-arm64 From ae1368c9892c5472ecac905ca377fb6462ff3312 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 15 Apr 2021 00:35:22 -0400 Subject: [PATCH 0122/1456] Convert encode/decode of DSS signatures to Rust (#5965) * Convert encode/decode of DSS signatures to Rust * Add an additional test case * Refactor this code * Rewrite for readability --- .../hazmat/primitives/asymmetric/utils.py | 25 +------- src/rust/src/asn1.rs | 61 +++++++++++++++++++ tests/hazmat/primitives/test_asym_utils.py | 12 ++-- 3 files changed, 71 insertions(+), 27 deletions(-) diff --git a/src/cryptography/hazmat/primitives/asymmetric/utils.py b/src/cryptography/hazmat/primitives/asymmetric/utils.py index 931df018414b..b01a0dbcf565 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/utils.py +++ b/src/cryptography/hazmat/primitives/asymmetric/utils.py @@ -3,31 +3,12 @@ # for complete details. -import typing - -from cryptography.hazmat._der import ( - DERReader, - INTEGER, - SEQUENCE, - encode_der, - encode_der_integer, -) +from cryptography.hazmat.bindings._rust import asn1 from cryptography.hazmat.primitives import hashes -def decode_dss_signature(signature: bytes) -> typing.Tuple[int, int]: - with DERReader(signature).read_single_element(SEQUENCE) as seq: - r = seq.read_element(INTEGER).as_integer() - s = seq.read_element(INTEGER).as_integer() - return r, s - - -def encode_dss_signature(r: int, s: int) -> bytes: - return encode_der( - SEQUENCE, - encode_der(INTEGER, encode_der_integer(r)), - encode_der(INTEGER, encode_der_integer(s)), - ) +decode_dss_signature = asn1.decode_dss_signature +encode_dss_signature = asn1.encode_dss_signature class Prehashed(object): diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 0eac927553de..6cfe4f7878ea 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -2,6 +2,7 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. +use pyo3::class::basic::CompareOp; use pyo3::conversion::ToPyObject; enum PyAsn1Error { @@ -94,11 +95,71 @@ fn parse_spki_for_data(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult( + py: pyo3::Python<'p>, + v: asn1::BigUint, +) -> pyo3::PyResult<&'p pyo3::PyAny> { + let int_type = py.get_type::(); + int_type.call_method1("from_bytes", (v.as_bytes(), "big")) +} + +#[pyo3::prelude::pyfunction] +fn decode_dss_signature(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult { + let (r, s) = asn1::parse::<_, PyAsn1Error, _>(data, |p| { + p.read_element::()?.parse(|p| { + let r = p.read_element::()?; + let s = p.read_element::()?; + Ok((r, s)) + }) + })?; + + Ok((big_asn1_uint_to_py(py, r)?, big_asn1_uint_to_py(py, s)?).to_object(py)) +} + +fn py_uint_to_big_endian_bytes<'p>( + py: pyo3::Python<'p>, + v: &'p pyo3::types::PyLong, +) -> pyo3::PyResult<&'p [u8]> { + let zero = (0).to_object(py); + if v.rich_compare(zero, CompareOp::Lt)?.is_true()? { + return Err(pyo3::exceptions::PyValueError::new_err( + "Negative integers are not supported", + )); + } + + // Round the length up so that we prefix an extra \x00. This ensures that + // integers that'd have the high bit set in their first octet are not + // encoded as negative in DER. + let n = v.call_method0("bit_length")?.extract::()? / 8 + 1; + v.call_method1("to_bytes", (n, "big"))?.extract() +} + +#[pyo3::prelude::pyfunction] +fn encode_dss_signature( + py: pyo3::Python<'_>, + r: &pyo3::types::PyLong, + s: &pyo3::types::PyLong, +) -> pyo3::PyResult { + let r = asn1::BigUint::new(py_uint_to_big_endian_bytes(py, r)?).unwrap(); + let s = asn1::BigUint::new(py_uint_to_big_endian_bytes(py, s)?).unwrap(); + let result = asn1::write(|w| { + w.write_element_with_type::(&|w| { + w.write_element(r); + w.write_element(s); + }); + }); + + Ok(pyo3::types::PyBytes::new(py, &result).to_object(py)) +} + pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let submod = pyo3::prelude::PyModule::new(py, "asn1")?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_tls_feature))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_precert_poison))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_spki_for_data))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(decode_dss_signature))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(encode_dss_signature))?; + Ok(submod) } diff --git a/tests/hazmat/primitives/test_asym_utils.py b/tests/hazmat/primitives/test_asym_utils.py index e4f22d7303e9..8ff5a65bdd75 100644 --- a/tests/hazmat/primitives/test_asym_utils.py +++ b/tests/hazmat/primitives/test_asym_utils.py @@ -35,25 +35,27 @@ def test_dss_signature(): def test_encode_dss_non_integer(): - with pytest.raises(ValueError): + with pytest.raises(TypeError): encode_dss_signature("h", 3) # type: ignore[arg-type] - with pytest.raises(ValueError): + with pytest.raises(TypeError): encode_dss_signature("3", "2") # type: ignore[arg-type] - with pytest.raises(ValueError): + with pytest.raises(TypeError): encode_dss_signature(3, "h") # type: ignore[arg-type] - with pytest.raises(ValueError): + with pytest.raises(TypeError): encode_dss_signature(3.3, 1.2) # type: ignore[arg-type] - with pytest.raises(ValueError): + with pytest.raises(TypeError): encode_dss_signature("hello", "world") # type: ignore[arg-type] def test_encode_dss_negative(): with pytest.raises(ValueError): encode_dss_signature(-1, 0) + with pytest.raises(ValueError): + encode_dss_signature(0, -1) def test_decode_dss_trailing_bytes(): From 1e1af7234a4598b6f4eb7677ebaa598e99ca4cd1 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 15 Apr 2021 11:02:09 -0400 Subject: [PATCH 0123/1456] fixes #5975 -- added typing stubs for rust module (#5976) --- MANIFEST.in | 2 +- mypy.ini | 2 -- .../hazmat/backends/openssl/decode_asn1.py | 10 ++++++---- src/cryptography/hazmat/bindings/_rust/__init__.pyi | 2 ++ src/cryptography/hazmat/bindings/_rust/asn1.pyi | 9 +++++++++ 5 files changed, 18 insertions(+), 7 deletions(-) create mode 100644 src/cryptography/hazmat/bindings/_rust/__init__.pyi create mode 100644 src/cryptography/hazmat/bindings/_rust/asn1.pyi diff --git a/MANIFEST.in b/MANIFEST.in index 78889eaeb541..94f0a4f38d9c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -7,7 +7,7 @@ include LICENSE.PSF include README.rst include pyproject.toml -recursive-include src py.typed +recursive-include src py.typed *.pyi recursive-include docs * recursive-include src/_cffi_src *.py *.c *.h diff --git a/mypy.ini b/mypy.ini index a1755b1fe0be..055619c090f6 100644 --- a/mypy.ini +++ b/mypy.ini @@ -4,8 +4,6 @@ check_untyped_defs = True [mypy-cryptography.hazmat.bindings._openssl] ignore_missing_imports = True -[mypy-cryptography.hazmat.bindings._rust] -ignore_missing_imports = True [mypy-iso8601] ignore_missing_imports = True diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 6e4dc0e939d1..72955a034732 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -210,17 +210,19 @@ def parse(self, x509_obj): # The extension contents are a SEQUENCE OF INTEGERs. data = self._backend._lib.X509_EXTENSION_get_data(ext) data_bytes = _asn1_string_to_bytes(self._backend, data) - value = asn1.parse_tls_feature(data_bytes) + tls_feature = asn1.parse_tls_feature(data_bytes) - extensions.append(x509.Extension(oid, critical, value)) + extensions.append(x509.Extension(oid, critical, tls_feature)) seen_oids.add(oid) continue elif oid == ExtensionOID.PRECERT_POISON: data = self._backend._lib.X509_EXTENSION_get_data(ext) data_bytes = _asn1_string_to_bytes(self._backend, data) - value = asn1.parse_precert_poison(data_bytes) + precert_poison = asn1.parse_precert_poison(data_bytes) - extensions.append(x509.Extension(oid, critical, value)) + extensions.append( + x509.Extension(oid, critical, precert_poison) + ) seen_oids.add(oid) continue diff --git a/src/cryptography/hazmat/bindings/_rust/__init__.pyi b/src/cryptography/hazmat/bindings/_rust/__init__.pyi new file mode 100644 index 000000000000..393ee7ab2b5c --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/__init__.pyi @@ -0,0 +1,2 @@ +def check_pkcs7_padding(data: bytes) -> bool: ... +def check_ansix923_padding(data: bytes) -> bool: ... diff --git a/src/cryptography/hazmat/bindings/_rust/asn1.pyi b/src/cryptography/hazmat/bindings/_rust/asn1.pyi new file mode 100644 index 000000000000..dca9ce7efdea --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/asn1.pyi @@ -0,0 +1,9 @@ +import typing + +from cryptography.x509 import TLSFeature, PrecertPoison + +def decode_dss_signature(signature: bytes) -> typing.Tuple[int, int]: ... +def encode_dss_signature(r: int, s: int) -> bytes: ... +def parse_tls_feature(data: bytes) -> TLSFeature: ... +def parse_precert_poison(data: bytes) -> PrecertPoison: ... +def parse_spki_for_data(data: bytes) -> bytes: ... From ed6f7a76591b7232744c2686fe7c2b39a0cf8d80 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 15 Apr 2021 21:04:48 -0400 Subject: [PATCH 0124/1456] Convert encoding two X.509 extensions to Rust (#5977) --- .../hazmat/backends/openssl/backend.py | 21 ++++---------- .../hazmat/bindings/_rust/asn1.pyi | 2 ++ src/rust/src/asn1.rs | 29 +++++++++++++++++++ 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 90957324c462..8afd1bdb38bc 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -12,13 +12,6 @@ from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat._der import ( - INTEGER, - NULL, - SEQUENCE, - encode_der, - encode_der_integer, -) from cryptography.hazmat._types import _PRIVATE_KEY_TYPES from cryptography.hazmat.backends.interfaces import Backend as BackendInterface from cryptography.hazmat.backends.openssl import aead @@ -98,6 +91,7 @@ _CertificateSigningRequest, _RevokedCertificate, ) +from cryptography.hazmat.bindings._rust import asn1 from cryptography.hazmat.bindings.openssl import binding from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ( @@ -1171,17 +1165,14 @@ def _create_x509_extension(self, handlers, extension): value = _encode_asn1_str_gc(self, extension.value.value) return self._create_raw_x509_extension(extension, value) elif isinstance(extension.value, x509.TLSFeature): - asn1 = encode_der( - SEQUENCE, - *[ - encode_der(INTEGER, encode_der_integer(x.value)) - for x in extension.value - ], + value = _encode_asn1_str_gc( + self, asn1.encode_tls_feature(extension.value) ) - value = _encode_asn1_str_gc(self, asn1) return self._create_raw_x509_extension(extension, value) elif isinstance(extension.value, x509.PrecertPoison): - value = _encode_asn1_str_gc(self, encode_der(NULL)) + value = _encode_asn1_str_gc( + self, asn1.encode_precert_poison(extension.value) + ) return self._create_raw_x509_extension(extension, value) else: try: diff --git a/src/cryptography/hazmat/bindings/_rust/asn1.pyi b/src/cryptography/hazmat/bindings/_rust/asn1.pyi index dca9ce7efdea..207d76a71427 100644 --- a/src/cryptography/hazmat/bindings/_rust/asn1.pyi +++ b/src/cryptography/hazmat/bindings/_rust/asn1.pyi @@ -4,6 +4,8 @@ from cryptography.x509 import TLSFeature, PrecertPoison def decode_dss_signature(signature: bytes) -> typing.Tuple[int, int]: ... def encode_dss_signature(r: int, s: int) -> bytes: ... +def encode_tls_feature(ext: TLSFeature) -> bytes: ... def parse_tls_feature(data: bytes) -> TLSFeature: ... +def encode_precert_poison(ext: PrecertPoison) -> bytes: ... def parse_precert_poison(data: bytes) -> PrecertPoison: ... def parse_spki_for_data(data: bytes) -> bytes: ... diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 6cfe4f7878ea..640f0bda2038 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -34,6 +34,24 @@ impl From for pyo3::PyErr { } } +#[pyo3::prelude::pyfunction] +fn encode_tls_feature(py: pyo3::Python<'_>, ext: &pyo3::PyAny) -> pyo3::PyResult { + // Ideally we'd skip building up a vec and just write directly into the + // writer. This isn't possible at the moment because the callback to write + // an asn1::Sequence can't return an error, and we need to handle errors + // from Python. + let mut els = vec![]; + for el in ext.iter()? { + els.push(el?.getattr("value")?.extract::()?); + } + + let result = asn1::write(|w| { + w.write_element_with_type::>(&els); + }); + + Ok(pyo3::types::PyBytes::new(py, &result).to_object(py)) +} + #[pyo3::prelude::pyfunction] fn parse_tls_feature(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult { let x509_mod = py.import("cryptography.x509.extensions")?; @@ -55,6 +73,15 @@ fn parse_tls_feature(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult, _ext: &pyo3::PyAny) -> pyo3::PyObject { + let result = asn1::write(|w| { + w.write_element(()); + }); + + pyo3::types::PyBytes::new(py, &result).to_object(py) +} + #[pyo3::prelude::pyfunction] fn parse_precert_poison(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult { asn1::parse::<_, PyAsn1Error, _>(data, |p| { @@ -154,7 +181,9 @@ fn encode_dss_signature( pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let submod = pyo3::prelude::PyModule::new(py, "asn1")?; + submod.add_wrapped(pyo3::wrap_pyfunction!(encode_tls_feature))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_tls_feature))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(encode_precert_poison))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_precert_poison))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_spki_for_data))?; From 6f36709588c243327080439f3c3dd898dbca17a7 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 16 Apr 2021 11:29:58 -0400 Subject: [PATCH 0125/1456] Corrected test parsing of certificates (#5978) RFC 5280 says these fields are both `IMPLICIT` tagging, and `IMPLICIT` tagging is only `CONSTRUCTED` if the inner type is, and the inner type is `BIT STRING` here, which is not `CONSTRUCTED`. In practice this is irrelevant since _no one_ ever uses these fields --- tests/x509/test_x509.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 765beaebe1af..c2dfdf250d2e 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -110,9 +110,9 @@ def _parse_cert(der): # Skip subjectPublicKeyInfo _ = tbs_cert.read_element(SEQUENCE) # Skip issuerUniqueID - _ = tbs_cert.read_optional_element(CONTEXT_SPECIFIC | CONSTRUCTED | 1) + _ = tbs_cert.read_optional_element(CONTEXT_SPECIFIC | 1) # Skip subjectUniqueID - _ = tbs_cert.read_optional_element(CONTEXT_SPECIFIC | CONSTRUCTED | 2) + _ = tbs_cert.read_optional_element(CONTEXT_SPECIFIC | 2) # Skip extensions _ = tbs_cert.read_optional_element(CONTEXT_SPECIFIC | CONSTRUCTED | 3) From f2a334cf6dec5a4931be843951057d2bb848e587 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Apr 2021 18:24:57 -0400 Subject: [PATCH 0126/1456] Bump asn1 from 0.3.3 to 0.3.5 in /src/rust (#5980) Bumps [asn1](https://github.com/alex/rust-asn1) from 0.3.3 to 0.3.5. - [Release notes](https://github.com/alex/rust-asn1/releases) - [Commits](https://github.com/alex/rust-asn1/compare/0.3.3...0.3.5) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- src/rust/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 8bfc5208b00a..0a319970507d 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "asn1" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c84b3b0c3c7051ba03423057b884aee14dc2c5b7741d58e6ad31d0908f0887a" +checksum = "fa8adeb6d7e2500bc2ee17c688f0e337ae6665a34d394adeaf9bf493f98acfd1" dependencies = [ "chrono", ] diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 961356f051eb..eff05b5f489e 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] pyo3 = { version = "0.13.1", features = ["extension-module"] } -asn1 = { version = "0.3.3", default-features = false } +asn1 = { version = "0.3.5", default-features = false } [lib] name = "cryptography_rust" From 19b29cddfe4802190a38b1a9650b165952195194 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 18 Apr 2021 20:56:49 -0400 Subject: [PATCH 0127/1456] properly mark pypy3-nocoverage jobs as no coverage (#5984) --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca049fc8fa69..de24503ab812 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,8 +16,8 @@ jobs: matrix: PYTHON: - {VERSION: "3.9", TOXENV: "flake,rust,docs", COVERAGE: "false"} - - {VERSION: "pypy-3.6", TOXENV: "pypy3-nocoverage"} - - {VERSION: "pypy-3.7", TOXENV: "pypy3-nocoverage"} + - {VERSION: "pypy-3.6", TOXENV: "pypy3-nocoverage", COVERAGE: "false"} + - {VERSION: "pypy-3.7", TOXENV: "pypy3-nocoverage", COVERAGE: "false"} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.0l"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} From 79b0136cb26e3431cad2d250751ef334f97a641c Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 18 Apr 2021 20:57:19 -0400 Subject: [PATCH 0128/1456] Add another ignore path to rust coverage (#5985) --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de24503ab812..815b113a04a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -232,6 +232,7 @@ jobs: cargo cov -- export ../../.tox/py39/lib/python3.9/site-packages/cryptography/hazmat/bindings/_rust.abi3.so \ -instr-profile=rust-cov.profdata \ --ignore-filename-regex='/.cargo/registry' \ + --ignore-filename-regex='/rustc/' \ --ignore-filename-regex='/.rustup/toolchains/' --format=lcov > ../../rust-cov.lcov sed -E -i 's/SF:src\/(.*)/SF:src\/rust\/src\/\1/g' ../../rust-cov.lcov From 89934a23950e79d3250668759d38bde60804e0ec Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 18 Apr 2021 22:06:51 -0400 Subject: [PATCH 0129/1456] Added more paths to coverage path combiner (#5983) * Added more paths to coverage path combiner * Update .coveragerc --- .coveragerc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.coveragerc b/.coveragerc index 6579cf6c8d42..ef820f0d4c6e 100644 --- a/.coveragerc +++ b/.coveragerc @@ -7,7 +7,8 @@ source = [paths] source = src/cryptography - .tox/*/lib/python*/site-packages/cryptography + .tox/*/lib*/python*/site-packages/cryptography + .tox\*\Lib\site-packages\cryptography .tox/pypy/site-packages/cryptography [report] From 6db4e0fb859c11106e1633988bda4341fc6f949b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Apr 2021 08:09:35 -0400 Subject: [PATCH 0130/1456] Bump asn1 from 0.3.5 to 0.3.6 in /src/rust (#5987) Bumps [asn1](https://github.com/alex/rust-asn1) from 0.3.5 to 0.3.6. - [Release notes](https://github.com/alex/rust-asn1/releases) - [Commits](https://github.com/alex/rust-asn1/compare/0.3.5...0.3.6) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- src/rust/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 0a319970507d..229c9cdb0139 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "asn1" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa8adeb6d7e2500bc2ee17c688f0e337ae6665a34d394adeaf9bf493f98acfd1" +checksum = "98ff0918103df4ea847a9a11dba5960b6e5743835560494c6ca3307c9063d931" dependencies = [ "chrono", ] diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index eff05b5f489e..57e94ae1b588 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] pyo3 = { version = "0.13.1", features = ["extension-module"] } -asn1 = { version = "0.3.5", default-features = false } +asn1 = { version = "0.3.6", default-features = false } [lib] name = "cryptography_rust" From 94590a9aecc9e5ef6fc8eda52bae43643a4c44bd Mon Sep 17 00:00:00 2001 From: Charlie Li Date: Mon, 19 Apr 2021 18:38:38 -0400 Subject: [PATCH 0131/1456] Fix build with LibreSSL 3.3.2 (#5988) * LibreSSL 3.3.2 supports SSL_OP_NO_DTLS* While here, bump CI * Fix preprocessor guards for LibreSSL's SSL_OP_NO_DTLS* DTLS_set_link_mtu and DTLS_get_link_min_mtu are not part of 3.3.2 * Switch to LESS_THAN context for LibreSSL 3.3.2 While here, fix indents * Remove extra C variable declaration The variable is not actually used from Python --- .github/workflows/ci.yml | 2 +- src/_cffi_src/openssl/cryptography.py | 7 +++++++ src/_cffi_src/openssl/ssl.py | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 815b113a04a1..1794d2fb190e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.1.5"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.2.5"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.3.1"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.3.2"}} RUST: - stable name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" diff --git a/src/_cffi_src/openssl/cryptography.py b/src/_cffi_src/openssl/cryptography.py index e2b5a13235ae..b9c7a793b3b6 100644 --- a/src/_cffi_src/openssl/cryptography.py +++ b/src/_cffi_src/openssl/cryptography.py @@ -32,6 +32,13 @@ #include #endif +#if CRYPTOGRAPHY_IS_LIBRESSL +#define CRYPTOGRAPHY_LIBRESSL_LESS_THAN_332 \ + (LIBRESSL_VERSION_NUMBER < 0x3030200f) +#else +#define CRYPTOGRAPHY_LIBRESSL_LESS_THAN_332 (0) +#endif + #define CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER \ (OPENSSL_VERSION_NUMBER >= 0x1010006f && !CRYPTOGRAPHY_IS_LIBRESSL) diff --git a/src/_cffi_src/openssl/ssl.py b/src/_cffi_src/openssl/ssl.py index 11a7d63a961a..081ef041fa33 100644 --- a/src/_cffi_src/openssl/ssl.py +++ b/src/_cffi_src/openssl/ssl.py @@ -586,8 +586,10 @@ #endif #if CRYPTOGRAPHY_IS_LIBRESSL +#if CRYPTOGRAPHY_LIBRESSL_LESS_THAN_332 static const long SSL_OP_NO_DTLSv1 = 0; static const long SSL_OP_NO_DTLSv1_2 = 0; +#endif long (*DTLS_set_link_mtu)(SSL *, long) = NULL; long (*DTLS_get_link_min_mtu)(SSL *) = NULL; #endif From 0c4caa295e28aec37b4d76702f9779451ec7927d Mon Sep 17 00:00:00 2001 From: Yang Yang Date: Tue, 20 Apr 2021 19:31:31 +0800 Subject: [PATCH 0132/1456] Fix typo: ANSI X.923 to ANSI X9.23 (#5989) --- docs/hazmat/primitives/padding.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/hazmat/primitives/padding.rst b/docs/hazmat/primitives/padding.rst index 99d500a05b68..ecd70e6d5084 100644 --- a/docs/hazmat/primitives/padding.rst +++ b/docs/hazmat/primitives/padding.rst @@ -58,7 +58,7 @@ multiple of the block size. .. versionadded:: 1.3 - `ANSI X.923`_ padding works by appending ``N-1`` bytes with the value of + `ANSI X9.23`_ padding works by appending ``N-1`` bytes with the value of ``0`` and a last byte with the value of ``chr(N)``, where ``N`` is the number of bytes required to make the final block of data the same size as the block size. A simple example of padding is: @@ -127,4 +127,4 @@ multiple of the block size. :raises ValueError: When trying to remove padding from incorrectly padded data. -.. _`ANSI X.923`: https://en.wikipedia.org/wiki/Padding_%28cryptography%29#ANSI_X9.23 +.. _`ANSI X9.23`: https://en.wikipedia.org/wiki/Padding_%28cryptography%29#ANSI_X9.23 From 09a5fb47ac2f423205edb1ff6dd07c34530c7e76 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 20 Apr 2021 09:19:10 -0400 Subject: [PATCH 0133/1456] Unpin 3.9 version on windows (#5990) * Unpin 3.9 version on windows And update cache key to include exact version instaled. * fix --- .github/workflows/ci.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1794d2fb190e..ec3b5d0dca0e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -307,7 +307,7 @@ jobs: - {ARCH: 'x64', WINDOWS: 'win64', RUST_TRIPLE: 'x86_64-pc-windows-msvc'} PYTHON: - {VERSION: "3.6", TOXENV: "py36", MSVC_VERSION: "2019", CL_FLAGS: ""} - - {VERSION: "3.9.2", TOXENV: "py39", MSVC_VERSION: "2019", CL_FLAGS: "/D USE_OSRANDOM_RNG_FOR_TESTING"} + - {VERSION: "3.9", TOXENV: "py39", MSVC_VERSION: "2019", CL_FLAGS: "/D USE_OSRANDOM_RNG_FOR_TESTING"} RUST: - stable JOB_NUMBER: [0, 1, 2, 3] @@ -315,19 +315,20 @@ jobs: timeout-minutes: 30 steps: - uses: actions/checkout@v2 + - name: Setup python + id: setup-python + uses: actions/setup-python@v2.2.2 + with: + python-version: ${{ matrix.PYTHON.VERSION }} + architecture: ${{ matrix.WINDOWS.ARCH }} - uses: actions/cache@v2.1.5 with: path: | ~/.cargo/registry ~/.cargo/git src/rust/target/ - key: ${{ runner.os }}-${{ matrix.WINDOWS.ARCH }}-${{ matrix.PYTHON.VERSION }}-cargo-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.WINDOWS.ARCH }}-${{ steps.setup-python.outputs.python-version }}-cargo-${{ hashFiles('**/Cargo.lock') }} - - name: Setup python - uses: actions/setup-python@v2.2.2 - with: - python-version: ${{ matrix.PYTHON.VERSION }} - architecture: ${{ matrix.WINDOWS.ARCH }} - uses: actions-rs/toolchain@v1 with: profile: minimal From 4447e1b3d2d37125977315655d4c68465c6452b1 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 21 Apr 2021 21:51:29 -0400 Subject: [PATCH 0134/1456] Port X.509 test parser to Rust (#5979) --- .../hazmat/bindings/_rust/asn1.pyi | 7 ++ src/rust/Cargo.toml | 6 +- src/rust/src/asn1.rs | 89 +++++++++++++++ tests/x509/test_x509.py | 104 ++++-------------- tox.ini | 2 +- 5 files changed, 123 insertions(+), 85 deletions(-) diff --git a/src/cryptography/hazmat/bindings/_rust/asn1.pyi b/src/cryptography/hazmat/bindings/_rust/asn1.pyi index 207d76a71427..bd73221baf37 100644 --- a/src/cryptography/hazmat/bindings/_rust/asn1.pyi +++ b/src/cryptography/hazmat/bindings/_rust/asn1.pyi @@ -2,6 +2,12 @@ import typing from cryptography.x509 import TLSFeature, PrecertPoison +class TestCertificate: + not_after_tag: int + not_before_tag: int + issuer_value_tags: typing.List[int] + subject_value_tags: typing.List[int] + def decode_dss_signature(signature: bytes) -> typing.Tuple[int, int]: ... def encode_dss_signature(r: int, s: int) -> bytes: ... def encode_tls_feature(ext: TLSFeature) -> bytes: ... @@ -9,3 +15,4 @@ def parse_tls_feature(data: bytes) -> TLSFeature: ... def encode_precert_poison(ext: PrecertPoison) -> bytes: ... def parse_precert_poison(data: bytes) -> PrecertPoison: ... def parse_spki_for_data(data: bytes) -> bytes: ... +def test_parse_certificate(data: bytes) -> TestCertificate: ... diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 57e94ae1b588..b49c473a7418 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -6,9 +6,13 @@ edition = "2018" publish = false [dependencies] -pyo3 = { version = "0.13.1", features = ["extension-module"] } +pyo3 = { version = "0.13.1" } asn1 = { version = "0.3.6", default-features = false } +[features] +extension-module = ["pyo3/extension-module"] +default = ["extension-module"] + [lib] name = "cryptography_rust" crate-type = ["cdylib"] diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 640f0bda2038..9af05ca03a87 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -179,6 +179,93 @@ fn encode_dss_signature( Ok(pyo3::types::PyBytes::new(py, &result).to_object(py)) } +#[pyo3::prelude::pyclass] +struct TestCertificate { + #[pyo3(get)] + not_before_tag: u8, + #[pyo3(get)] + not_after_tag: u8, + #[pyo3(get)] + issuer_value_tags: Vec, + #[pyo3(get)] + subject_value_tags: Vec, +} + +fn parse_name_value_tags(p: &mut asn1::Parser) -> asn1::ParseResult> { + let mut tags = vec![]; + for rdn in p.read_element::>>()? { + let mut attributes = rdn?.collect::>>()?; + assert_eq!(attributes.len(), 1); + + let tag = attributes + .pop() + .unwrap() + .parse::<_, asn1::ParseError, _>(|p| { + p.read_element::()?; + let tlv = p.read_element::()?; + Ok(tlv.tag()) + })?; + tags.push(tag); + } + Ok(tags) +} + +#[pyo3::prelude::pyfunction] +fn test_parse_certificate(data: &[u8]) -> pyo3::PyResult { + let result = asn1::parse::<_, PyAsn1Error, _>(data, |p| { + // Outer SEQUENCE + p.read_element::()?.parse(|p| { + // TBS certificate + let result = p + .read_element::()? + .parse::<_, PyAsn1Error, _>(|p| { + // Version + p.read_optional_explicit_element::(0)?; + // Serial number + p.read_element::()?; + // Inner signature algorithm + p.read_element::()?; + + // Issuer + let issuer_value_tags = parse_name_value_tags(p)?; + // Validity + let (not_before_tag, not_after_tag) = p + .read_element::()? + .parse::<_, asn1::ParseError, _>(|p| { + let not_before_tag = p.read_element::()?.tag(); + let not_after_tag = p.read_element::()?.tag(); + Ok((not_before_tag, not_after_tag)) + })?; + // Subject + let subject_value_tags = parse_name_value_tags(p)?; + + // Subject public key info + p.read_element::()?; + // Issuer unique ID - never used in the real world + p.read_optional_implicit_element::(1)?; + // Subject unique ID - never used in the real world + p.read_optional_implicit_element::(2)?; + // Extensions + p.read_optional_explicit_element::(3)?; + + Ok(TestCertificate { + not_before_tag, + not_after_tag, + issuer_value_tags, + subject_value_tags, + }) + })?; + // Outer signature algorithm + p.read_element::()?; + // Signature + p.read_element::()?; + Ok(result) + }) + })?; + + Ok(result) +} + pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let submod = pyo3::prelude::PyModule::new(py, "asn1")?; submod.add_wrapped(pyo3::wrap_pyfunction!(encode_tls_feature))?; @@ -190,5 +277,7 @@ pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelud submod.add_wrapped(pyo3::wrap_pyfunction!(decode_dss_signature))?; submod.add_wrapped(pyo3::wrap_pyfunction!(encode_dss_signature))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(test_parse_certificate))?; + Ok(submod) } diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index c2dfdf250d2e..c6f758574e48 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -5,7 +5,6 @@ import binascii -import collections import copy import datetime import ipaddress @@ -18,19 +17,7 @@ from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm -from cryptography.hazmat._der import ( - BIT_STRING, - CONSTRUCTED, - CONTEXT_SPECIFIC, - DERReader, - GENERALIZED_TIME, - INTEGER, - OBJECT_IDENTIFIER, - PRINTABLE_STRING, - SEQUENCE, - SET, - UTC_TIME, -) +from cryptography.hazmat.bindings._rust import asn1 from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ( dh, @@ -82,52 +69,6 @@ def _load_cert(filename, loader, backend): return cert -ParsedCertificate = collections.namedtuple( - "ParsedCertificate", - ["not_before_tag", "not_after_tag", "issuer", "subject"], -) - - -def _parse_cert(der): - # See the Certificate structured, defined in RFC 5280. - with DERReader(der).read_single_element(SEQUENCE) as cert: - tbs_cert = cert.read_element(SEQUENCE) - # Skip outer signature algorithm - _ = cert.read_element(SEQUENCE) - # Skip signature - _ = cert.read_element(BIT_STRING) - - with tbs_cert: - # Skip version - _ = tbs_cert.read_optional_element(CONTEXT_SPECIFIC | CONSTRUCTED | 0) - # Skip serialNumber - _ = tbs_cert.read_element(INTEGER) - # Skip inner signature algorithm - _ = tbs_cert.read_element(SEQUENCE) - issuer = tbs_cert.read_element(SEQUENCE) - validity = tbs_cert.read_element(SEQUENCE) - subject = tbs_cert.read_element(SEQUENCE) - # Skip subjectPublicKeyInfo - _ = tbs_cert.read_element(SEQUENCE) - # Skip issuerUniqueID - _ = tbs_cert.read_optional_element(CONTEXT_SPECIFIC | 1) - # Skip subjectUniqueID - _ = tbs_cert.read_optional_element(CONTEXT_SPECIFIC | 2) - # Skip extensions - _ = tbs_cert.read_optional_element(CONTEXT_SPECIFIC | CONSTRUCTED | 3) - - with validity: - not_before_tag, _ = validity.read_any_element() - not_after_tag, _ = validity.read_any_element() - - return ParsedCertificate( - not_before_tag=not_before_tag, - not_after_tag=not_after_tag, - issuer=issuer, - subject=subject, - ) - - class TestCertificateRevocationList(object): def test_load_pem_crl(self, backend): crl = _load_cert( @@ -1788,29 +1729,19 @@ def test_build_cert_printable_string_country_name(self, backend): cert = builder.sign(issuer_private_key, hashes.SHA256(), backend) - parsed = _parse_cert(cert.public_bytes(serialization.Encoding.DER)) - subject = parsed.subject - issuer = parsed.issuer - - def read_next_rdn_value_tag(reader): - # Assume each RDN has a single attribute. - with reader.read_element(SET) as rdn: - attribute = rdn.read_element(SEQUENCE) - - with attribute: - _ = attribute.read_element(OBJECT_IDENTIFIER) - tag, value = attribute.read_any_element() - return tag + parsed = asn1.test_parse_certificate( + cert.public_bytes(serialization.Encoding.DER) + ) # Check that each value was encoded as an ASN.1 PRINTABLESTRING. - assert read_next_rdn_value_tag(subject) == PRINTABLE_STRING - assert read_next_rdn_value_tag(issuer) == PRINTABLE_STRING + assert parsed.issuer_value_tags[0] == 0x13 + assert parsed.subject_value_tags[0] == 0x13 if ( # This only works correctly in OpenSSL 1.1.0f+ backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER ): - assert read_next_rdn_value_tag(subject) == PRINTABLE_STRING - assert read_next_rdn_value_tag(issuer) == PRINTABLE_STRING + assert parsed.issuer_value_tags[1] == 0x13 + assert parsed.subject_value_tags[1] == 0x13 class TestCertificateBuilder(object): @@ -1971,9 +1902,13 @@ def test_extreme_times(self, not_valid_before, not_valid_after, 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 = _parse_cert(cert.public_bytes(serialization.Encoding.DER)) - assert parsed.not_before_tag == UTC_TIME - assert parsed.not_after_tag == GENERALIZED_TIME + parsed = asn1.test_parse_certificate( + cert.public_bytes(serialization.Encoding.DER) + ) + # UTC TIME + assert parsed.not_before_tag == 0x17 + # GENERALIZED TIME + assert parsed.not_after_tag == 0x18 def test_no_subject_name(self, backend): subject_private_key = RSA_KEY_2048.private_key(backend) @@ -2237,9 +2172,12 @@ def test_earliest_time(self, backend): cert = cert_builder.sign(private_key, hashes.SHA256(), backend) assert cert.not_valid_before == time assert cert.not_valid_after == time - parsed = _parse_cert(cert.public_bytes(serialization.Encoding.DER)) - assert parsed.not_before_tag == UTC_TIME - assert parsed.not_after_tag == UTC_TIME + parsed = asn1.test_parse_certificate( + cert.public_bytes(serialization.Encoding.DER) + ) + # UTC TIME + assert parsed.not_before_tag == 0x17 + assert parsed.not_after_tag == 0x17 def test_invalid_not_valid_after(self): with pytest.raises(TypeError): diff --git a/tox.ini b/tox.ini index 03cb89bf5bd3..19adafc2b28a 100644 --- a/tox.ini +++ b/tox.ini @@ -69,7 +69,7 @@ allowlist_externals = commands = cargo fmt --all -- --check cargo clippy -- -D warnings - cargo test + cargo test --no-default-features [flake8] ignore = E203,E211,W503,W504 From 57b9b1aa517fa97c9620ebd3155330b63db5742f Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 21 Apr 2021 22:46:17 -0400 Subject: [PATCH 0135/1456] Delete _der.py (#5992) --- src/cryptography/hazmat/_der.py | 156 --------------------- tests/hazmat/test_der.py | 232 -------------------------------- 2 files changed, 388 deletions(-) delete mode 100644 src/cryptography/hazmat/_der.py delete mode 100644 tests/hazmat/test_der.py diff --git a/src/cryptography/hazmat/_der.py b/src/cryptography/hazmat/_der.py deleted file mode 100644 index ba1db4caf682..000000000000 --- a/src/cryptography/hazmat/_der.py +++ /dev/null @@ -1,156 +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. - -import typing - -from cryptography.utils import int_to_bytes - - -# This module contains a lightweight DER encoder and decoder. See X.690 for the -# specification. This module intentionally does not implement the more complex -# BER encoding, only DER. -# -# Note this implementation treats an element's constructed bit as part of the -# tag. This is fine for DER, where the bit is always computable from the type. - - -CONSTRUCTED = 0x20 -CONTEXT_SPECIFIC = 0x80 - -INTEGER = 0x02 -BIT_STRING = 0x03 -OCTET_STRING = 0x04 -NULL = 0x05 -OBJECT_IDENTIFIER = 0x06 -SEQUENCE = 0x10 | CONSTRUCTED -SET = 0x11 | CONSTRUCTED -PRINTABLE_STRING = 0x13 -UTC_TIME = 0x17 -GENERALIZED_TIME = 0x18 - - -class DERReader(object): - def __init__(self, data: bytes) -> None: - self.data = memoryview(data) - - def __enter__(self) -> "DERReader": - return self - - def __exit__(self, exc_type, exc_value, tb): - if exc_value is None: - self.check_empty() - - def is_empty(self) -> bool: - return len(self.data) == 0 - - def check_empty(self) -> None: - if not self.is_empty(): - raise ValueError("Invalid DER input: trailing data") - - def read_byte(self) -> int: - if len(self.data) < 1: - raise ValueError("Invalid DER input: insufficient data") - ret = self.data[0] - self.data = self.data[1:] - return ret - - def read_bytes(self, n: int) -> memoryview: - if len(self.data) < n: - raise ValueError("Invalid DER input: insufficient data") - ret = self.data[:n] - self.data = self.data[n:] - return ret - - def read_any_element(self) -> typing.Tuple[int, "DERReader"]: - tag = self.read_byte() - # Tag numbers 31 or higher are stored in multiple bytes. No supported - # ASN.1 types use such tags, so reject these. - if tag & 0x1F == 0x1F: - raise ValueError("Invalid DER input: unexpected high tag number") - length_byte = self.read_byte() - if length_byte & 0x80 == 0: - # If the high bit is clear, the first length byte is the length. - length = length_byte - else: - # If the high bit is set, the first length byte encodes the length - # of the length. - length_byte &= 0x7F - if length_byte == 0: - raise ValueError( - "Invalid DER input: indefinite length form is not allowed " - "in DER" - ) - length = 0 - for i in range(length_byte): - length <<= 8 - length |= self.read_byte() - if length == 0: - raise ValueError( - "Invalid DER input: length was not minimally-encoded" - ) - if length < 0x80: - # If the length could have been encoded in short form, it must - # not use long form. - raise ValueError( - "Invalid DER input: length was not minimally-encoded" - ) - body = self.read_bytes(length) - return tag, DERReader(body) - - def read_element(self, expected_tag: int) -> "DERReader": - tag, body = self.read_any_element() - if tag != expected_tag: - raise ValueError("Invalid DER input: unexpected tag") - return body - - def read_single_element(self, expected_tag: int) -> "DERReader": - with self: - return self.read_element(expected_tag) - - def read_optional_element( - self, expected_tag: int - ) -> typing.Optional["DERReader"]: - if len(self.data) > 0 and self.data[0] == expected_tag: - return self.read_element(expected_tag) - return None - - def as_integer(self) -> int: - if len(self.data) == 0: - raise ValueError("Invalid DER input: empty integer contents") - first = self.data[0] - if first & 0x80 == 0x80: - raise ValueError("Negative DER integers are not supported") - # The first 9 bits must not all be zero or all be ones. Otherwise, the - # encoding should have been one byte shorter. - if len(self.data) > 1: - second = self.data[1] - if first == 0 and second & 0x80 == 0: - raise ValueError( - "Invalid DER input: integer not minimally-encoded" - ) - return int.from_bytes(self.data, "big") - - -def encode_der_integer(x: int) -> bytes: - if not isinstance(x, int): - raise ValueError("Value must be an integer") - if x < 0: - raise ValueError("Negative integers are not supported") - n = x.bit_length() // 8 + 1 - return int_to_bytes(x, n) - - -def encode_der(tag: int, *children: bytes) -> bytes: - length = 0 - for child in children: - length += len(child) - chunks = [bytes([tag])] - if length < 0x80: - chunks.append(bytes([length])) - else: - length_bytes = int_to_bytes(length) - chunks.append(bytes([0x80 | len(length_bytes)])) - chunks.append(length_bytes) - chunks.extend(children) - return b"".join(chunks) diff --git a/tests/hazmat/test_der.py b/tests/hazmat/test_der.py deleted file mode 100644 index aeae01db3f9f..000000000000 --- a/tests/hazmat/test_der.py +++ /dev/null @@ -1,232 +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. - - -import pytest - -from cryptography.hazmat._der import ( - DERReader, - INTEGER, - NULL, - OCTET_STRING, - SEQUENCE, - encode_der, - encode_der_integer, -) - - -def test_der_reader_basic(): - reader = DERReader(b"123456789") - assert reader.read_byte() == ord(b"1") - assert reader.read_bytes(1).tobytes() == b"2" - assert reader.read_bytes(4).tobytes() == b"3456" - - with pytest.raises(ValueError): - reader.read_bytes(4) - - assert reader.read_bytes(3).tobytes() == b"789" - - # The input is now empty. - with pytest.raises(ValueError): - reader.read_bytes(1) - with pytest.raises(ValueError): - reader.read_byte() - - -def test_der(): - # This input is the following structure, using - # https://github.com/google/der-ascii - # - # SEQUENCE { - # SEQUENCE { - # NULL {} - # INTEGER { 42 } - # OCTET_STRING { "hello" } - # } - # } - der = b"\x30\x0e\x30\x0c\x05\x00\x02\x01\x2a\x04\x05\x68\x65\x6c\x6c\x6f" - reader = DERReader(der) - with pytest.raises(ValueError): - reader.check_empty() - - with pytest.raises(ValueError): - with reader: - pass - - with pytest.raises(ZeroDivisionError): - with DERReader(der): - raise ZeroDivisionError - - # Parse the outer element. - outer = reader.read_element(SEQUENCE) - reader.check_empty() - assert outer.data.tobytes() == der[2:] - - # Parse the outer element with read_any_element. - reader = DERReader(der) - tag, outer2 = reader.read_any_element() - reader.check_empty() - assert tag == SEQUENCE - assert outer2.data.tobytes() == der[2:] - - # Parse the outer element with read_single_element. - outer3 = DERReader(der).read_single_element(SEQUENCE) - assert outer3.data.tobytes() == der[2:] - - # read_single_element rejects trailing data. - with pytest.raises(ValueError): - DERReader(der + der).read_single_element(SEQUENCE) - - # Continue parsing the structure. - inner = outer.read_element(SEQUENCE) - outer.check_empty() - - # Parsing a missing optional element should work. - assert inner.read_optional_element(INTEGER) is None - - null = inner.read_element(NULL) - null.check_empty() - - # Parsing a present optional element should work. - integer = inner.read_optional_element(INTEGER) - assert integer is not None - assert integer.as_integer() == 42 - - octet_string = inner.read_element(OCTET_STRING) - assert octet_string.data.tobytes() == b"hello" - - # Parsing a missing optional element should work when the input is empty. - inner.check_empty() - assert inner.read_optional_element(INTEGER) is None - - # Re-encode the same structure. - der2 = encode_der( - SEQUENCE, - encode_der( - SEQUENCE, - encode_der(NULL), - encode_der(INTEGER, encode_der_integer(42)), - encode_der(OCTET_STRING, b"hello"), - ), - ) - assert der2 == der - - -@pytest.mark.parametrize( - "length,header", - [ - # Single-byte lengths. - (0, b"\x04\x00"), - (1, b"\x04\x01"), - (2, b"\x04\x02"), - (127, b"\x04\x7f"), - # Long-form lengths. - (128, b"\x04\x81\x80"), - (129, b"\x04\x81\x81"), - (255, b"\x04\x81\xff"), - (0x100, b"\x04\x82\x01\x00"), - (0x101, b"\x04\x82\x01\x01"), - (0xFFFF, b"\x04\x82\xff\xff"), - (0x10000, b"\x04\x83\x01\x00\x00"), - ], -) -def test_der_lengths(length, header): - body = length * b"a" - der = header + body - - reader = DERReader(der) - element = reader.read_element(OCTET_STRING) - reader.check_empty() - assert element.data.tobytes() == body - - assert encode_der(OCTET_STRING, body) == der - - -@pytest.mark.parametrize( - "bad_input", - [ - # The input ended before the tag. - b"", - # The input ended before the length. - b"\x30", - # The input ended before the second byte of the length. - b"\x30\x81", - # The input ended before the body. - b"\x30\x01", - # The length used long form when it should be short form. - b"\x30\x81\x01\x00", - # The length was not minimally-encoded. - b"\x30\x82\x00\x80" + (0x80 * b"a"), - # Indefinite-length encoding is not valid DER. - b"\x30\x80\x00\x00" - # Tag number (the bottom 5 bits) 31 indicates long form tags, which we - # do not support. - b"\x1f\x00", - b"\x9f\x00", - b"\xbf\x00", - b"\xff\x00", - ], -) -def test_der_reader_bad_input(bad_input): - reader = DERReader(bad_input) - with pytest.raises(ValueError): - reader.read_any_element() - - -def test_der_reader_wrong_tag(): - reader = DERReader(b"\x04\x00") - with pytest.raises(ValueError): - reader.read_element(SEQUENCE) - - -@pytest.mark.parametrize( - "value,der", - [ - (0, b"\x00"), - (1, b"\x01"), - (2, b"\x02"), - (3, b"\x03"), - (127, b"\x7f"), - (128, b"\x00\x80"), - ( - 0x112233445566778899AABBCCDDEEFF, - b"\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff", - ), - ], -) -def test_integer(value, der): - assert encode_der_integer(value) == der - assert DERReader(der).as_integer() == value - - -@pytest.mark.parametrize( - "bad_input", - [ - # Zero is encoded as b"\x00", not the empty string. - b"", - # Too many leading zeros. - b"\x00\x00", - b"\x00\x7f", - # Too many leading ones. - b"\xff\xff", - b"\xff\x80", - # Negative integers are not supported. - b"\x80", - b"\x81", - b"\x80\x00\x00", - b"\xff", - ], -) -def test_invalid_integer(bad_input): - reader = DERReader(bad_input) - with pytest.raises(ValueError): - reader.as_integer() - - -def test_invalid_integer_encode(): - with pytest.raises(ValueError): - encode_der_integer(-1) - - with pytest.raises(ValueError): - encode_der_integer("not an integer") # type: ignore[arg-type] From 5ecb3d45b0c52f13888fcb9536526f463135e6a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Apr 2021 08:36:10 -0400 Subject: [PATCH 0136/1456] Bump syn from 1.0.69 to 1.0.70 in /src/rust (#5993) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.69 to 1.0.70. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.69...1.0.70) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 229c9cdb0139..c8ad2bfa4ec5 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -286,9 +286,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb" +checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883" dependencies = [ "proc-macro2", "quote", From 063a2048d1584ff6a74bbd4fa0ae4d9184bcab9b Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Thu, 22 Apr 2021 16:00:43 +0200 Subject: [PATCH 0137/1456] add typehints to OCSPRequestBuilder() (#5994) --- src/cryptography/x509/ocsp.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/cryptography/x509/ocsp.py b/src/cryptography/x509/ocsp.py index 1c5de73e45b1..905ae745a8b5 100644 --- a/src/cryptography/x509/ocsp.py +++ b/src/cryptography/x509/ocsp.py @@ -312,7 +312,15 @@ def public_bytes(self, encoding: serialization.Encoding) -> bytes: class OCSPRequestBuilder(object): - def __init__(self, request=None, extensions=[]): + def __init__( + self, + request: typing.Optional[ + typing.Tuple[ + x509.Certificate, x509.Certificate, hashes.HashAlgorithm + ] + ] = None, + extensions: typing.List[x509.Extension[x509.ExtensionType]] = [], + ) -> None: self._request = request self._extensions = extensions From f08a7de651f9e6475c8c0a67d2a61ed8b669ddf6 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 22 Apr 2021 19:16:38 -0500 Subject: [PATCH 0138/1456] [WIP] 3.0.0 support (#5250) * 3.0.0 support * almost...there... * make mypy happy --- .github/workflows/ci.yml | 1 + src/_cffi_src/build_openssl.py | 1 + src/_cffi_src/openssl/cryptography.py | 3 ++ src/_cffi_src/openssl/err.py | 6 +++ src/_cffi_src/openssl/fips.py | 2 +- src/_cffi_src/openssl/provider.py | 40 +++++++++++++++++++ .../hazmat/backends/openssl/backend.py | 40 ++++++++++++++++--- .../hazmat/backends/openssl/ciphers.py | 8 ++++ .../hazmat/bindings/openssl/_conditional.py | 11 +++++ .../hazmat/bindings/openssl/binding.py | 20 ++++++++++ tests/hazmat/backends/test_openssl_memleak.py | 6 ++- tests/hazmat/bindings/test_openssl.py | 4 +- tests/hazmat/primitives/test_dh.py | 24 ++++++++++- 13 files changed, 156 insertions(+), 10 deletions(-) create mode 100644 src/_cffi_src/openssl/provider.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec3b5d0dca0e..18b5bf2251ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,7 @@ jobs: - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0-alpha15"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "2.9.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.1.5"}} diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py index 08499d66f629..557296ed5354 100644 --- a/src/_cffi_src/build_openssl.py +++ b/src/_cffi_src/build_openssl.py @@ -104,6 +104,7 @@ def _extra_compile_args(platform): "osrandom_engine", "pem", "pkcs12", + "provider", "rand", "rsa", "ssl", diff --git a/src/_cffi_src/openssl/cryptography.py b/src/_cffi_src/openssl/cryptography.py index b9c7a793b3b6..e9a9a522e8b6 100644 --- a/src/_cffi_src/openssl/cryptography.py +++ b/src/_cffi_src/openssl/cryptography.py @@ -41,6 +41,8 @@ #define CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER \ (OPENSSL_VERSION_NUMBER >= 0x1010006f && !CRYPTOGRAPHY_IS_LIBRESSL) +#define CRYPTOGRAPHY_OPENSSL_300_OR_GREATER \ + (OPENSSL_VERSION_NUMBER >= 0x30000000 && !CRYPTOGRAPHY_IS_LIBRESSL) #define CRYPTOGRAPHY_OPENSSL_LESS_THAN_110J \ (OPENSSL_VERSION_NUMBER < 0x101000af || CRYPTOGRAPHY_IS_LIBRESSL) @@ -60,6 +62,7 @@ TYPES = """ static const int CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER; +static const int CRYPTOGRAPHY_OPENSSL_300_OR_GREATER; static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_111; static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B; diff --git a/src/_cffi_src/openssl/err.py b/src/_cffi_src/openssl/err.py index 0634b656c0f4..8cfeaf5ba38a 100644 --- a/src/_cffi_src/openssl/err.py +++ b/src/_cffi_src/openssl/err.py @@ -18,6 +18,7 @@ static const int ERR_LIB_EVP; static const int ERR_LIB_PEM; +static const int ERR_LIB_PROV; static const int ERR_LIB_ASN1; static const int ERR_LIB_PKCS12; @@ -45,4 +46,9 @@ """ CUSTOMIZATIONS = """ +/* This define is tied to provider support and is conditionally + removed if Cryptography_HAS_PROVIDERS is false */ +#ifndef ERR_LIB_PROV +#define ERR_LIB_PROV 0 +#endif """ diff --git a/src/_cffi_src/openssl/fips.py b/src/_cffi_src/openssl/fips.py index b9d0d64d84fb..23c10af92209 100644 --- a/src/_cffi_src/openssl/fips.py +++ b/src/_cffi_src/openssl/fips.py @@ -17,7 +17,7 @@ """ CUSTOMIZATIONS = """ -#if CRYPTOGRAPHY_IS_LIBRESSL +#if CRYPTOGRAPHY_IS_LIBRESSL || CRYPTOGRAPHY_OPENSSL_300_OR_GREATER static const long Cryptography_HAS_FIPS = 0; int (*FIPS_mode_set)(int) = NULL; int (*FIPS_mode)(void) = NULL; diff --git a/src/_cffi_src/openssl/provider.py b/src/_cffi_src/openssl/provider.py new file mode 100644 index 000000000000..d7d659ea5ef4 --- /dev/null +++ b/src/_cffi_src/openssl/provider.py @@ -0,0 +1,40 @@ +# 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. + + +INCLUDES = """ +#if CRYPTOGRAPHY_OPENSSL_300_OR_GREATER +#include +#include +#endif +""" + +TYPES = """ +static const long Cryptography_HAS_PROVIDERS; + +typedef ... OSSL_PROVIDER; +typedef ... OSSL_LIB_CTX; + +static const long PROV_R_BAD_DECRYPT; +static const long PROV_R_WRONG_FINAL_BLOCK_LENGTH; +""" + +FUNCTIONS = """ +OSSL_PROVIDER *OSSL_PROVIDER_load(OSSL_LIB_CTX *, const char *); +int OSSL_PROVIDER_unload(OSSL_PROVIDER *prov); +""" + +CUSTOMIZATIONS = """ +#if CRYPTOGRAPHY_OPENSSL_300_OR_GREATER +static const long Cryptography_HAS_PROVIDERS = 1; +#else +static const long Cryptography_HAS_PROVIDERS = 0; +typedef void OSSL_PROVIDER; +typedef void OSSL_LIB_CTX; +static const long PROV_R_BAD_DECRYPT = 0; +static const long PROV_R_WRONG_FINAL_BLOCK_LENGTH = 0; +OSSL_PROVIDER *(*OSSL_PROVIDER_load)(OSSL_LIB_CTX *, const char *) = NULL; +int (*OSSL_PROVIDER_unload)(OSSL_PROVIDER *) = NULL; +#endif +""" diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 8afd1bdb38bc..28c49c151e33 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -1285,6 +1285,11 @@ def load_der_private_key(self, data, password): def _evp_pkey_from_der_traditional_key(self, bio_data, password): key = self._lib.d2i_PrivateKey_bio(bio_data.bio, self._ffi.NULL) if key != self._ffi.NULL: + # In OpenSSL 3.0.0-alpha15 there exist scenarios where the key will + # successfully load but errors are still put on the stack. Tracked + # as https://github.com/openssl/openssl/issues/14996 + self._consume_errors() + key = self._ffi.gc(key, self._lib.EVP_PKEY_free) if password is not None: raise TypeError( @@ -1452,6 +1457,11 @@ def _load_key(self, openssl_read_func, convert_func, data, password): else: self._handle_key_loading_error() + # In OpenSSL 3.0.0-alpha15 there exist scenarios where the key will + # successfully load but errors are still put on the stack. Tracked + # as https://github.com/openssl/openssl/issues/14996 + self._consume_errors() + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) if password is not None and userdata.called == 0: @@ -1474,11 +1484,22 @@ def _handle_key_loading_error(self): "incorrect format or it may be encrypted with an unsupported " "algorithm." ) - elif errors[0]._lib_reason_match( - self._lib.ERR_LIB_EVP, self._lib.EVP_R_BAD_DECRYPT - ) or errors[0]._lib_reason_match( - self._lib.ERR_LIB_PKCS12, - self._lib.PKCS12_R_PKCS12_CIPHERFINAL_ERROR, + + elif ( + errors[0]._lib_reason_match( + self._lib.ERR_LIB_EVP, self._lib.EVP_R_BAD_DECRYPT + ) + or errors[0]._lib_reason_match( + self._lib.ERR_LIB_PKCS12, + self._lib.PKCS12_R_PKCS12_CIPHERFINAL_ERROR, + ) + or ( + self._lib.Cryptography_HAS_PROVIDERS + and errors[0]._lib_reason_match( + self._lib.ERR_LIB_PROV, + self._lib.PROV_R_BAD_DECRYPT, + ) + ) ): raise ValueError("Bad decrypt. Incorrect password?") @@ -2524,9 +2545,16 @@ def load_key_and_certificates_from_pkcs12(self, data, password): 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]) + # In OpenSSL < 3.0.0 PKCS12 parsing reverses the order of the # certificates. - for i in reversed(range(num)): + indices: typing.Iterable[int] + if self._lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER: + indices = range(num) + else: + indices = reversed(range(num)) + + for i in indices: x509 = self._lib.sk_X509_value(sk_x509, i) self.openssl_assert(x509 != self._ffi.NULL) x509 = self._ffi.gc(x509, self._lib.X509_free) diff --git a/src/cryptography/hazmat/backends/openssl/ciphers.py b/src/cryptography/hazmat/backends/openssl/ciphers.py index 50cbeb69a680..eb302e44f9eb 100644 --- a/src/cryptography/hazmat/backends/openssl/ciphers.py +++ b/src/cryptography/hazmat/backends/openssl/ciphers.py @@ -146,6 +146,7 @@ def update_into(self, data: bytes, buf) -> int: self._ctx, outbuf, outlen, inbuf, inlen ) if res == 0 and isinstance(self._mode, modes.XTS): + self._backend._consume_errors() raise ValueError( "In XTS mode you must supply at least a full block in the " "first update call. For AES this is 16 bytes." @@ -180,6 +181,13 @@ def finalize(self) -> bytes: errors[0]._lib_reason_match( self._backend._lib.ERR_LIB_EVP, self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH, + ) + or ( + self._backend._lib.Cryptography_HAS_PROVIDERS + and errors[0]._lib_reason_match( + self._backend._lib.ERR_LIB_PROV, + self._backend._lib.PROV_R_WRONG_FINAL_BLOCK_LENGTH, + ) ), errors=errors, ) diff --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py index aaa7d1392028..55b2117cd53b 100644 --- a/src/cryptography/hazmat/bindings/openssl/_conditional.py +++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py @@ -256,6 +256,16 @@ def cryptography_has_get_proto_version(): ] +def cryptography_has_providers(): + return [ + "OSSL_PROVIDER_load", + "OSSL_PROVIDER_unload", + "ERR_LIB_PROV", + "PROV_R_WRONG_FINAL_BLOCK_LENGTH", + "PROV_R_BAD_DECRYPT", + ] + + # 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 @@ -303,4 +313,5 @@ def cryptography_has_get_proto_version(): "Cryptography_HAS_VERIFIED_CHAIN": cryptography_has_verified_chain, "Cryptography_HAS_SRTP": cryptography_has_srtp, "Cryptography_HAS_GET_PROTO_VERSION": cryptography_has_get_proto_version, + "Cryptography_HAS_PROVIDERS": cryptography_has_providers, } diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py index a2bc36a83a71..6dcec26ab8a3 100644 --- a/src/cryptography/hazmat/bindings/openssl/binding.py +++ b/src/cryptography/hazmat/bindings/openssl/binding.py @@ -113,6 +113,8 @@ class Binding(object): ffi = ffi _lib_loaded = False _init_lock = threading.Lock() + _legacy_provider: typing.Any = None + _default_provider: typing.Any = None def __init__(self): self._ensure_ffi_initialized() @@ -140,6 +142,24 @@ def _ensure_ffi_initialized(cls): # adds all ciphers/digests for EVP cls.lib.OpenSSL_add_all_algorithms() cls._register_osrandom_engine() + # As of OpenSSL 3.0.0 we must register a legacy cipher provider + # to get RC2 (needed for junk asymmetric private key + # serialization), RC4, Blowfish, IDEA, SEED, etc. These things + # are ugly legacy, but we aren't going to get rid of them + # any time soon. + if cls.lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER: + cls._legacy_provider = cls.lib.OSSL_PROVIDER_load( + cls.ffi.NULL, b"legacy" + ) + _openssl_assert( + cls.lib, cls._legacy_provider != cls.ffi.NULL + ) + cls._default_provider = cls.lib.OSSL_PROVIDER_load( + cls.ffi.NULL, b"default" + ) + _openssl_assert( + cls.lib, cls._default_provider != cls.ffi.NULL + ) @classmethod def init_static_locks(cls): diff --git a/tests/hazmat/backends/test_openssl_memleak.py b/tests/hazmat/backends/test_openssl_memleak.py index 0c96516fa19f..0316b5d9602e 100644 --- a/tests/hazmat/backends/test_openssl_memleak.py +++ b/tests/hazmat/backends/test_openssl_memleak.py @@ -82,7 +82,7 @@ def free(ptr, path, line): assert result == 1 # Trigger a bunch of initialization stuff. - import cryptography.hazmat.backends.openssl + from cryptography.hazmat.backends.openssl.backend import backend start_heap = set(heap) @@ -91,6 +91,10 @@ def free(ptr, path, line): gc.collect() gc.collect() + if lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER: + lib.OSSL_PROVIDER_unload(backend._binding._legacy_provider) + lib.OSSL_PROVIDER_unload(backend._binding._default_provider) + if lib.Cryptography_HAS_OPENSSL_CLEANUP: lib.OPENSSL_cleanup() diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py index fb9a1e363742..4d1e3b5566d5 100644 --- a/tests/hazmat/bindings/test_openssl.py +++ b/tests/hazmat/bindings/test_openssl.py @@ -91,7 +91,9 @@ def test_openssl_assert_error_on_stack(self): _openssl_assert(b.lib, False) error = exc_info.value.err_code[0] - assert error.code == 101183626 + # As of 3.0.0 OpenSSL sets func codes to 0, so the combined + # code is a different value + assert error.code in (101183626, 50331786) assert error.lib == b.lib.ERR_LIB_EVP assert error.func == b.lib.EVP_F_EVP_ENCRYPTFINAL_EX assert error.reason == b.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH diff --git a/tests/hazmat/primitives/test_dh.py b/tests/hazmat/primitives/test_dh.py index 9e7f7f51d3d7..7efc09456e6d 100644 --- a/tests/hazmat/primitives/test_dh.py +++ b/tests/hazmat/primitives/test_dh.py @@ -174,7 +174,23 @@ def test_dh_parameters_allows_rfc3526_groups(self, backend, vector): params = dh.DHParameterNumbers(p, int(vector["g"])) param = params.parameters(backend) key = param.generate_private_key() - assert key.private_numbers().public_numbers.parameter_numbers == params + # In OpenSSL 3.0.0 OpenSSL maps to known groups. This results in + # a scenario where loading a known group with p and g returns a + # re-serialized form that has q as well (the Sophie Germain prime of + # that group). This makes a naive comparison of the parameter numbers + # objects fail, so we have to be a bit smarter + serialized_params = ( + key.private_numbers().public_numbers.parameter_numbers + ) + if serialized_params.q is None: + # This is the path OpenSSL < 3.0 takes + assert serialized_params == params + else: + assert serialized_params.p == params.p + assert serialized_params.g == params.g + # p = 2q + 1 since it is a Sophie Germain prime, so we can compute + # what we expect OpenSSL to have done here. + assert serialized_params.q == (params.p - 1) // 2 @pytest.mark.skip_fips(reason="non-FIPS parameters") @pytest.mark.parametrize( @@ -377,6 +393,12 @@ def test_bad_exchange(self, backend, vector): key2.exchange(pub_key1) @pytest.mark.skip_fips(reason="key_size too small for FIPS") + @pytest.mark.supported( + only_if=lambda backend: ( + not backend._lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER + ), + skip_message="256-bit DH keys are not supported in OpenSSL 3.0.0+", + ) def test_load_256bit_key_from_pkcs8(self, backend): data = load_vectors_from_file( os.path.join("asymmetric", "DH", "dh_key_256.pem"), From 4dd2d988ca18afcb8eb789bc3cdb9f8f79ff2123 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Apr 2021 08:20:21 -0400 Subject: [PATCH 0139/1456] Bump asn1 from 0.3.6 to 0.3.7 in /src/rust (#5999) Bumps [asn1](https://github.com/alex/rust-asn1) from 0.3.6 to 0.3.7. - [Release notes](https://github.com/alex/rust-asn1/releases) - [Commits](https://github.com/alex/rust-asn1/compare/0.3.6...0.3.7) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- src/rust/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index c8ad2bfa4ec5..21f5f3b18d0d 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "asn1" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ff0918103df4ea847a9a11dba5960b6e5743835560494c6ca3307c9063d931" +checksum = "6e73776acd44522682c2f4f7a2a316c038e318796bf5a720679a21b892e3c7a8" dependencies = [ "chrono", ] diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index b49c473a7418..e337ac592dbf 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] pyo3 = { version = "0.13.1" } -asn1 = { version = "0.3.6", default-features = false } +asn1 = { version = "0.3.7", default-features = false } [features] extension-module = ["pyo3/extension-module"] From fdb69922493d1e64cf7f807b85d198abe2200aeb Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Fri, 23 Apr 2021 14:56:54 +0200 Subject: [PATCH 0140/1456] typehint OCSPResponseBuilder builder (#6002) * typehint response builder * change to list as suggested by @alex --- src/cryptography/x509/ocsp.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cryptography/x509/ocsp.py b/src/cryptography/x509/ocsp.py index 905ae745a8b5..1d136e7f9be3 100644 --- a/src/cryptography/x509/ocsp.py +++ b/src/cryptography/x509/ocsp.py @@ -365,7 +365,13 @@ def build(self) -> OCSPRequest: class OCSPResponseBuilder(object): def __init__( - self, response=None, responder_id=None, certs=None, extensions=[] + self, + response: typing.Optional[_SingleResponse] = None, + responder_id: typing.Optional[ + typing.Tuple[x509.Certificate, OCSPResponderEncoding] + ] = None, + certs: typing.Optional[typing.List[x509.Certificate]] = None, + extensions: typing.List[x509.Extension[x509.ExtensionType]] = [], ): self._response = response self._responder_id = responder_id From 58bddfd7e9588a8bdfc32baa1ea2fb93c121571d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 23 Apr 2021 09:02:49 -0400 Subject: [PATCH 0141/1456] removed paragraph in docs that was very out of date (#6003) --- docs/development/getting-started.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/development/getting-started.rst b/docs/development/getting-started.rst index e230fc30d405..b52a4fd0cd45 100644 --- a/docs/development/getting-started.rst +++ b/docs/development/getting-started.rst @@ -26,12 +26,6 @@ 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. -.. note:: - There is an upstream bug in ``enchant`` that prevents its installation on - Windows with 64-bit Python. See `this Github issue`_ for more information. - The easiest workaround is to use 32-bit Python for ``cryptography`` - development, even on 64-bit Windows. - You are now ready to run the tests and build the documentation. OpenSSL on macOS @@ -115,4 +109,3 @@ The HTML documentation index can now be found at .. _`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 From 62124e673aa3b37a1b3652bfed7bdcb9ac8d33a2 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 24 Apr 2021 15:33:47 -0400 Subject: [PATCH 0142/1456] Port OCSP Request extension parsing to Rust (#6005) * Port OCSP Request extension parsing to Rust * Added test for rando oid * Update src/rust/src/asn1.rs Co-authored-by: Paul Kehrer Co-authored-by: Paul Kehrer --- docs/development/test-vectors.rst | 2 ++ src/_cffi_src/openssl/objects.py | 20 +++++++++++ .../hazmat/backends/openssl/backend.py | 3 +- .../hazmat/backends/openssl/decode_asn1.py | 23 +++++++++--- .../hazmat/bindings/_rust/asn1.pyi | 5 ++- src/rust/Cargo.lock | 11 ++++-- src/rust/Cargo.toml | 3 +- src/rust/src/asn1.rs | 33 ++++++++++++++++++ tests/x509/test_ocsp.py | 13 +++++++ .../x509/ocsp/req-ext-unknown-oid.der | Bin 0 -> 121 bytes 10 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 vectors/cryptography_vectors/x509/ocsp/req-ext-unknown-oid.der diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index f952337e2347..e8e466d4a999 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -551,6 +551,8 @@ Custom X.509 OCSP Test Vectors invalid hash algorithm OID. * ``x509/ocsp/req-ext-nonce.der`` - An OCSP request containing a nonce extension. +* ``x509/ocsp/req-ext-unknown-oid.der`` - An OCSP request containing an + extension with an unknown OID. Custom PKCS12 Test Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/_cffi_src/openssl/objects.py b/src/_cffi_src/openssl/objects.py index bddaa84284ea..10ceb2b1493b 100644 --- a/src/_cffi_src/openssl/objects.py +++ b/src/_cffi_src/openssl/objects.py @@ -26,7 +26,27 @@ int OBJ_txt2nid(const char *); ASN1_OBJECT *OBJ_txt2obj(const char *, int); int OBJ_obj2txt(char *, int, const ASN1_OBJECT *, int); + +const unsigned char *Cryptography_OBJ_get0_data(const ASN1_OBJECT *); +size_t Cryptography_OBJ_length(const ASN1_OBJECT *); """ CUSTOMIZATIONS = """ +#if CRYPTOGRAPHY_IS_LIBRESSL +const unsigned char *Cryptography_OBJ_get0_data(const ASN1_OBJECT *a) { + return a->data; +} + +size_t Cryptography_OBJ_length(const ASN1_OBJECT *a) { + return a->length; +} +#else +const unsigned char *Cryptography_OBJ_get0_data(const ASN1_OBJECT *a) { + return OBJ_get0_data(a); +} + +size_t Cryptography_OBJ_length(const ASN1_OBJECT *a) { + return OBJ_length(a); +} +#endif """ diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 28c49c151e33..4cc8b63f1f3f 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -23,7 +23,6 @@ _EXTENSION_HANDLERS_BASE, _EXTENSION_HANDLERS_SCT, _OCSP_BASICRESP_EXTENSION_HANDLERS, - _OCSP_REQ_EXTENSION_HANDLERS, _OCSP_SINGLERESP_EXTENSION_HANDLERS_SCT, _REVOKED_EXTENSION_HANDLERS, _X509ExtensionParser, @@ -426,7 +425,7 @@ def _register_x509_ext_parsers(self): self, ext_count=self._lib.OCSP_REQUEST_get_ext_count, get_ext=self._lib.OCSP_REQUEST_get_ext, - handlers=_OCSP_REQ_EXTENSION_HANDLERS, + rust_callback=asn1.parse_ocsp_req_extension, ) self._ocsp_basicresp_ext_parser = _X509ExtensionParser( self, diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 72955a034732..9a85e9464dce 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -178,10 +178,14 @@ def _decode_delta_crl_indicator(backend, ext): class _X509ExtensionParser(object): - def __init__(self, backend, ext_count, get_ext, handlers): + def __init__( + self, backend, ext_count, get_ext, handlers=None, rust_callback=None + ): + assert handlers or rust_callback self.ext_count = ext_count self.get_ext = get_ext self.handlers = handlers + self.rust_callback = rust_callback self._backend = backend def parse(self, x509_obj): @@ -203,6 +207,19 @@ def parse(self, x509_obj): "Duplicate {} extension found".format(oid), oid ) + if self.rust_callback is not None: + oid_ptr = self._backend._lib.X509_EXTENSION_get_object(ext) + oid_der_bytes = self._backend._ffi.buffer( + self._backend._lib.Cryptography_OBJ_get0_data(oid_ptr), + self._backend._lib.Cryptography_OBJ_length(oid_ptr), + )[:] + data = self._backend._lib.X509_EXTENSION_get_data(ext) + data_bytes = _asn1_string_to_bytes(self._backend, data) + ext = self.rust_callback(oid_der_bytes, data_bytes) + extensions.append(x509.Extension(oid, critical, ext)) + seen_oids.add(oid) + continue + # 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. @@ -854,10 +871,6 @@ def _decode_nonce(backend, nonce): ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, } -_OCSP_REQ_EXTENSION_HANDLERS = { - OCSPExtensionOID.NONCE: _decode_nonce, -} - _OCSP_BASICRESP_EXTENSION_HANDLERS = { OCSPExtensionOID.NONCE: _decode_nonce, } diff --git a/src/cryptography/hazmat/bindings/_rust/asn1.pyi b/src/cryptography/hazmat/bindings/_rust/asn1.pyi index bd73221baf37..5f4afc92f1cf 100644 --- a/src/cryptography/hazmat/bindings/_rust/asn1.pyi +++ b/src/cryptography/hazmat/bindings/_rust/asn1.pyi @@ -1,6 +1,6 @@ import typing -from cryptography.x509 import TLSFeature, PrecertPoison +from cryptography.x509 import ExtensionType, TLSFeature, PrecertPoison class TestCertificate: not_after_tag: int @@ -14,5 +14,8 @@ def encode_tls_feature(ext: TLSFeature) -> bytes: ... def parse_tls_feature(data: bytes) -> TLSFeature: ... def encode_precert_poison(ext: PrecertPoison) -> bytes: ... def parse_precert_poison(data: bytes) -> PrecertPoison: ... +def parse_ocsp_req_extension( + der_oid: bytes, ext_data: bytes +) -> ExtensionType: ... def parse_spki_for_data(data: bytes) -> bytes: ... def test_parse_certificate(data: bytes) -> TestCertificate: ... diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 21f5f3b18d0d..b5ceed20b367 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "asn1" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e73776acd44522682c2f4f7a2a316c038e318796bf5a720679a21b892e3c7a8" +checksum = "842b2cc51640a5737c94248d328936d11f53ea8080e3fdba6ba523b41fa6ea15" dependencies = [ "chrono", ] @@ -44,6 +44,7 @@ name = "cryptography-rust" version = "0.1.0" dependencies = [ "asn1", + "lazy_static", "pyo3", ] @@ -122,6 +123,12 @@ dependencies = [ "syn", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.93" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index e337ac592dbf..144f34106cbe 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -6,8 +6,9 @@ edition = "2018" publish = false [dependencies] +lazy_static = "1" pyo3 = { version = "0.13.1" } -asn1 = { version = "0.3.7", default-features = false } +asn1 = { version = "0.3.8", default-features = false } [features] extension-module = ["pyo3/extension-module"] diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 9af05ca03a87..5d63bac65d82 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -122,6 +122,37 @@ fn parse_spki_for_data(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.48.1.2").unwrap(); +} + +#[pyo3::prelude::pyfunction] +fn parse_ocsp_req_extension( + py: pyo3::Python<'_>, + der_oid: &[u8], + ext_data: &[u8], +) -> pyo3::PyResult { + let oid = asn1::ObjectIdentifier::from_der(der_oid).unwrap(); + + let x509_module = py.import("cryptography.x509")?; + if oid == *NONCE_OID { + // This is a disaster. RFC 2560 says that the contents of the nonce is + // just the raw extension value. This is nonsense, since they're always + // supposed to be ASN.1 TLVs. RFC 6960 correctly specifies that the + // nonce is an OCTET STRING, and so you should unwrap the TLV to get + // the nonce. For now we just implement the old behavior, even though + // it's deranged. + Ok(x509_module + .call_method1("OCSPNonce", (ext_data,))? + .to_object(py)) + } else { + let oid_obj = x509_module.call_method1("ObjectIdentifier", (oid.to_string(),))?; + Ok(x509_module + .call_method1("UnrecognizedExtension", (oid_obj, ext_data))? + .to_object(py)) + } +} + fn big_asn1_uint_to_py<'p>( py: pyo3::Python<'p>, v: asn1::BigUint, @@ -274,6 +305,8 @@ pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelud submod.add_wrapped(pyo3::wrap_pyfunction!(parse_precert_poison))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_spki_for_data))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(parse_ocsp_req_extension))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(decode_dss_signature))?; submod.add_wrapped(pyo3::wrap_pyfunction!(encode_dss_signature))?; diff --git a/tests/x509/test_ocsp.py b/tests/x509/test_ocsp.py index 5d9da790af9f..6b839b3d048f 100644 --- a/tests/x509/test_ocsp.py +++ b/tests/x509/test_ocsp.py @@ -106,6 +106,19 @@ def test_load_request_with_extensions(self): b"\x04\x10{\x80Z\x1d7&\xb8\xb8OH\xd2\xf8\xbf\xd7-\xfd" ) + def test_load_request_with_unknown_extension(self): + req = _load_data( + os.path.join("x509", "ocsp", "req-ext-unknown-oid.der"), + ocsp.load_der_ocsp_request, + ) + assert len(req.extensions) == 1 + ext = req.extensions[0] + assert ext.critical is False + assert ext.value == x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.3.6.1.5.5.7.48.1.2213"), + 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( diff --git a/vectors/cryptography_vectors/x509/ocsp/req-ext-unknown-oid.der b/vectors/cryptography_vectors/x509/ocsp/req-ext-unknown-oid.der new file mode 100644 index 0000000000000000000000000000000000000000..2283aae03494bd8139147cde2ab34a619558be8b GIT binary patch literal 121 zcmV-<0EYiCcQAD@O)yI^NiYcp1uG5%0vZJX1QZZorh0$~owX;QHO_+zLx`TE#|;D& z4}f7Df-zy$FDU1YMmV%A;l|nG0uTYO9{b&1t_e~y3ncz)RcN9lFd{G@1_~<%0R;sI bFaePz1QG-gdw^OUHzv5aPe{`Ezt=7OxoIbX literal 0 HcmV?d00001 From 3b6c09ba86f4c2d7f4e8fc720f038ec824de1846 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 24 Apr 2021 17:30:49 -0400 Subject: [PATCH 0143/1456] Update link (#6007) --- docs/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index 278e680ce1f5..a9f40bf9afa4 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -348,5 +348,5 @@ build ``cryptography``, but not afterwards. .. _`a binary distribution`: https://wiki.openssl.org/index.php/Binaries .. _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 +.. _`wheel cache`: https://pip.pypa.io/en/stable/cli/pip_install/#caching .. _`the Rust Project's website`: https://www.rust-lang.org/tools/install From e9f842545b96922d1ef38494eebcd85710ccae85 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 24 Apr 2021 21:30:20 -0500 Subject: [PATCH 0144/1456] update the tests to use sha2 in more places (#6008) --- tests/hazmat/primitives/test_ec.py | 8 +++---- tests/x509/test_x509.py | 36 +++++++++++++++--------------- tests/x509/test_x509_ext.py | 4 ++-- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py index 708395867b6b..0bc0952ee81e 100644 --- a/tests/hazmat/primitives/test_ec.py +++ b/tests/hazmat/primitives/test_ec.py @@ -1188,7 +1188,7 @@ def test_key_exchange_with_vectors(self, backend, subtests): for vector in vectors: with subtests.test(): _skip_exchange_algorithm_unsupported( - backend, ec.ECDH(), ec._CURVE_TYPES[vector["curve"]] + backend, ec.ECDH(), ec._CURVE_TYPES[vector["curve"]]() ) key_numbers = vector["IUT"] @@ -1243,18 +1243,18 @@ def test_key_exchange_with_vectors(self, backend, subtests): ), ) def test_brainpool_kex(self, backend, vector): - curve = ec._CURVE_TYPES[vector["curve"].decode("ascii")] + 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() + 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() + int(vector["x_qb"], 16), int(vector["y_qb"], 16), curve ), ).private_key(backend) shared_secret = key.exchange(ec.ECDH(), peer.public_key()) diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index c6f758574e48..9e0a6fbaaa6e 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -1616,7 +1616,7 @@ def test_build_cert(self, backend): .not_valid_after(not_valid_after) ) - cert = builder.sign(issuer_private_key, hashes.SHA1(), backend) + cert = builder.sign(issuer_private_key, hashes.SHA256(), backend) assert cert.version is x509.Version.v3 assert cert.not_valid_before == not_valid_before @@ -2432,7 +2432,7 @@ def test_build_cert_with_dsa_private_key(self, backend): .not_valid_after(not_valid_after) ) - cert = builder.sign(issuer_private_key, hashes.SHA1(), backend) + cert = builder.sign(issuer_private_key, hashes.SHA256(), backend) assert cert.version is x509.Version.v3 assert cert.not_valid_before == not_valid_before @@ -2483,7 +2483,7 @@ def test_build_cert_with_ec_private_key(self, backend): .not_valid_after(not_valid_after) ) - cert = builder.sign(issuer_private_key, hashes.SHA1(), backend) + cert = builder.sign(issuer_private_key, hashes.SHA256(), backend) assert cert.version is x509.Version.v3 assert cert.not_valid_before == not_valid_before @@ -3179,7 +3179,7 @@ def test_build_ca_request_with_path_length_none(self, backend): .add_extension( x509.BasicConstraints(ca=True, path_length=None), critical=True ) - .sign(private_key, hashes.SHA1(), backend) + .sign(private_key, hashes.SHA256(), backend) ) loaded_request = x509.load_pem_x509_csr( @@ -3322,10 +3322,10 @@ def test_build_ca_request_with_rsa(self, backend): .add_extension( x509.BasicConstraints(ca=True, path_length=2), critical=True ) - .sign(private_key, hashes.SHA1(), backend) + .sign(private_key, hashes.SHA256(), backend) ) - assert isinstance(request.signature_hash_algorithm, hashes.SHA1) + assert isinstance(request.signature_hash_algorithm, hashes.SHA256) public_key = request.public_key() assert isinstance(public_key, rsa.RSAPublicKey) subject = request.subject @@ -3357,7 +3357,7 @@ def test_build_ca_request_with_unicode(self, backend): .add_extension( x509.BasicConstraints(ca=True, path_length=2), critical=True ) - .sign(private_key, hashes.SHA1(), backend) + .sign(private_key, hashes.SHA256(), backend) ) loaded_request = x509.load_pem_x509_csr( @@ -3447,7 +3447,7 @@ def test_build_ca_request_with_multivalue_rdns(self, backend): request = ( x509.CertificateSigningRequestBuilder() .subject_name(subject) - .sign(private_key, hashes.SHA1(), backend) + .sign(private_key, hashes.SHA256(), backend) ) loaded_request = x509.load_pem_x509_csr( @@ -3468,10 +3468,10 @@ def test_build_nonca_request_with_rsa(self, backend): x509.BasicConstraints(ca=False, path_length=None), critical=True, ) - .sign(private_key, hashes.SHA1(), backend) + .sign(private_key, hashes.SHA256(), backend) ) - assert isinstance(request.signature_hash_algorithm, hashes.SHA1) + assert isinstance(request.signature_hash_algorithm, hashes.SHA256) public_key = request.public_key() assert isinstance(public_key, rsa.RSAPublicKey) subject = request.subject @@ -3504,10 +3504,10 @@ def test_build_ca_request_with_ec(self, backend): .add_extension( x509.BasicConstraints(ca=True, path_length=2), critical=True ) - .sign(private_key, hashes.SHA1(), backend) + .sign(private_key, hashes.SHA256(), backend) ) - assert isinstance(request.signature_hash_algorithm, hashes.SHA1) + assert isinstance(request.signature_hash_algorithm, hashes.SHA256) public_key = request.public_key() assert isinstance(public_key, ec.EllipticCurvePublicKey) subject = request.subject @@ -3615,10 +3615,10 @@ def test_build_ca_request_with_dsa(self, backend): .add_extension( x509.BasicConstraints(ca=True, path_length=2), critical=True ) - .sign(private_key, hashes.SHA1(), backend) + .sign(private_key, hashes.SHA256(), backend) ) - assert isinstance(request.signature_hash_algorithm, hashes.SHA1) + assert isinstance(request.signature_hash_algorithm, hashes.SHA256) public_key = request.public_key() assert isinstance(public_key, dsa.DSAPublicKey) subject = request.subject @@ -3764,10 +3764,10 @@ def test_add_two_extensions(self, backend): .add_extension( x509.BasicConstraints(ca=True, path_length=2), critical=True ) - .sign(private_key, hashes.SHA1(), backend) + .sign(private_key, hashes.SHA256(), backend) ) - assert isinstance(request.signature_hash_algorithm, hashes.SHA1) + assert isinstance(request.signature_hash_algorithm, hashes.SHA256) public_key = request.public_key() assert isinstance(public_key, rsa.RSAPublicKey) basic_constraints = request.extensions.get_extension_for_oid( @@ -4028,7 +4028,7 @@ def test_build_cert_with_aia(self, backend): .not_valid_after(not_valid_after) ) - cert = builder.sign(issuer_private_key, hashes.SHA1(), backend) + cert = builder.sign(issuer_private_key, hashes.SHA256(), backend) ext = cert.extensions.get_extension_for_oid( ExtensionOID.AUTHORITY_INFORMATION_ACCESS @@ -4099,7 +4099,7 @@ def test_build_cert_with_ski(self, backend): .not_valid_after(not_valid_after) ) - cert = builder.sign(issuer_private_key, hashes.SHA1(), backend) + cert = builder.sign(issuer_private_key, hashes.SHA256(), backend) ext = cert.extensions.get_extension_for_oid( ExtensionOID.SUBJECT_KEY_IDENTIFIER diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index 480a8757dad9..9d2585c9ef5e 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -2517,7 +2517,7 @@ def test_certbuilder(self, backend): SubjectAlternativeName(list(map(DNSName, sans))), True ) - cert = builder.sign(private_key, hashes.SHA1(), backend) + cert = builder.sign(private_key, hashes.SHA256(), backend) result = [ x.value for x in cert.extensions.get_extension_for_class( @@ -3597,7 +3597,7 @@ def test_certbuilder(self, backend): True, ) - cert = builder.sign(private_key, hashes.SHA1(), backend) + cert = builder.sign(private_key, hashes.SHA256(), backend) result = [ x.value for x in cert.extensions.get_extension_for_class( From 4d066d62141adbcc201f14e5d77ae41df1a228c2 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 24 Apr 2021 21:30:39 -0500 Subject: [PATCH 0145/1456] correct type mistake in DSA skip logic (#6009) --- tests/hazmat/primitives/test_dsa.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/tests/hazmat/primitives/test_dsa.py b/tests/hazmat/primitives/test_dsa.py index 066f83c4eca1..0192e413dc82 100644 --- a/tests/hazmat/primitives/test_dsa.py +++ b/tests/hazmat/primitives/test_dsa.py @@ -10,6 +10,7 @@ import pytest from cryptography.exceptions import AlreadyFinalized, InvalidSignature +from cryptography.hazmat.backends.interfaces import Backend from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import dsa from cryptography.hazmat.primitives.asymmetric.utils import ( @@ -36,12 +37,20 @@ } -def _skip_if_dsa_not_supported(backend, algorithm, p, q, g): +def _skip_if_dsa_not_supported( + backend: Backend, + algorithm: hashes.HashAlgorithm, + p: int, + q: int, + g: int, +) -> None: if not backend.dsa_parameters_supported( p, q, g ) or not backend.dsa_hash_supported(algorithm): pytest.skip( - "{} does not support the provided parameters".format(backend) + "{} does not support the provided args. p: {}, hash: {}".format( + backend, p.bit_length(), algorithm.name + ) ) @@ -388,7 +397,7 @@ def test_dsa_verification(self, backend, subtests): for vector in vectors: with subtests.test(): digest_algorithm = vector["digest_algorithm"].replace("-", "") - algorithm = _ALGORITHMS_DICT[digest_algorithm] + algorithm = _ALGORITHMS_DICT[digest_algorithm]() _skip_if_dsa_not_supported( backend, algorithm, vector["p"], vector["q"], vector["g"] @@ -404,9 +413,9 @@ def test_dsa_verification(self, backend, subtests): if vector["result"] == "F": with pytest.raises(InvalidSignature): - public_key.verify(sig, vector["msg"], algorithm()) + public_key.verify(sig, vector["msg"], algorithm) else: - public_key.verify(sig, vector["msg"], algorithm()) + 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) @@ -490,7 +499,7 @@ def test_dsa_signing(self, backend, subtests): for vector in vectors: with subtests.test(): digest_algorithm = vector["digest_algorithm"].replace("-", "") - algorithm = _ALGORITHMS_DICT[digest_algorithm] + algorithm = _ALGORITHMS_DICT[digest_algorithm]() _skip_if_dsa_not_supported( backend, algorithm, vector["p"], vector["q"], vector["g"] @@ -505,11 +514,11 @@ def test_dsa_signing(self, backend, subtests): ), x=vector["x"], ).private_key(backend) - signature = private_key.sign(vector["msg"], algorithm()) + signature = private_key.sign(vector["msg"], algorithm) assert signature private_key.public_key().verify( - signature, vector["msg"], algorithm() + signature, vector["msg"], algorithm ) def test_use_after_finalize(self, backend): From d1686fc0229b36cec18a9eac1f71b7c8641daf0e Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 25 Apr 2021 06:40:25 +0200 Subject: [PATCH 0146/1456] make PRIVATE/PUBLIC_KEY_TYPES a public API (#6001) --- .../hazmat/backends/interfaces.py | 10 +++++---- .../hazmat/backends/openssl/backend.py | 8 +++---- .../hazmat/backends/openssl/x509.py | 8 +++---- .../asymmetric/types.py} | 4 ++-- .../hazmat/primitives/serialization/base.py | 16 +++++++------- src/cryptography/x509/base.py | 21 +++++++++++-------- src/cryptography/x509/extensions.py | 8 +++---- src/cryptography/x509/ocsp.py | 4 ++-- 8 files changed, 42 insertions(+), 37 deletions(-) rename src/cryptography/hazmat/{_types.py => primitives/asymmetric/types.py} (89%) diff --git a/src/cryptography/hazmat/backends/interfaces.py b/src/cryptography/hazmat/backends/interfaces.py index bb51060809f9..2aeee4927b3d 100644 --- a/src/cryptography/hazmat/backends/interfaces.py +++ b/src/cryptography/hazmat/backends/interfaces.py @@ -8,7 +8,9 @@ if typing.TYPE_CHECKING: - from cryptography.hazmat._types import _PRIVATE_KEY_TYPES + from cryptography.hazmat.primitives.asymmetric.types import ( + PRIVATE_KEY_TYPES, + ) from cryptography.hazmat.primitives import hashes from cryptography.x509.base import ( Certificate, @@ -306,7 +308,7 @@ def load_pem_x509_csr(self, data: bytes) -> "CertificateSigningRequest": def create_x509_csr( self, builder: "CertificateSigningRequestBuilder", - private_key: "_PRIVATE_KEY_TYPES", + private_key: "PRIVATE_KEY_TYPES", algorithm: typing.Optional["hashes.HashAlgorithm"], ) -> "CertificateSigningRequest": """ @@ -317,7 +319,7 @@ def create_x509_csr( def create_x509_certificate( self, builder: "CertificateBuilder", - private_key: "_PRIVATE_KEY_TYPES", + private_key: "PRIVATE_KEY_TYPES", algorithm: typing.Optional["hashes.HashAlgorithm"], ) -> "Certificate": """ @@ -328,7 +330,7 @@ def create_x509_certificate( def create_x509_crl( self, builder: "CertificateRevocationListBuilder", - private_key: "_PRIVATE_KEY_TYPES", + private_key: "PRIVATE_KEY_TYPES", algorithm: typing.Optional["hashes.HashAlgorithm"], ) -> "CertificateRevocationList": """ diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 4cc8b63f1f3f..29f353db3292 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -12,7 +12,6 @@ from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat._types import _PRIVATE_KEY_TYPES from cryptography.hazmat.backends.interfaces import Backend as BackendInterface from cryptography.hazmat.backends.openssl import aead from cryptography.hazmat.backends.openssl.ciphers import _CipherContext @@ -107,6 +106,7 @@ PKCS1v15, PSS, ) +from cryptography.hazmat.primitives.asymmetric.types import PRIVATE_KEY_TYPES from cryptography.hazmat.primitives.ciphers.algorithms import ( AES, ARC4, @@ -894,7 +894,7 @@ def _x509_check_signature_params(self, private_key, algorithm): def create_x509_csr( self, builder: x509.CertificateSigningRequestBuilder, - private_key: _PRIVATE_KEY_TYPES, + private_key: PRIVATE_KEY_TYPES, algorithm: typing.Optional[hashes.HashAlgorithm], ) -> _CertificateSigningRequest: if not isinstance(builder, x509.CertificateSigningRequestBuilder): @@ -975,7 +975,7 @@ def create_x509_csr( def create_x509_certificate( self, builder: x509.CertificateBuilder, - private_key: _PRIVATE_KEY_TYPES, + private_key: PRIVATE_KEY_TYPES, algorithm: typing.Optional[hashes.HashAlgorithm], ) -> _Certificate: if not isinstance(builder, x509.CertificateBuilder): @@ -1077,7 +1077,7 @@ def _create_asn1_time(self, time): def create_x509_crl( self, builder: x509.CertificateRevocationListBuilder, - private_key: _PRIVATE_KEY_TYPES, + private_key: PRIVATE_KEY_TYPES, algorithm: typing.Optional[hashes.HashAlgorithm], ) -> _CertificateRevocationList: if not isinstance(builder, x509.CertificateRevocationListBuilder): diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index ea938a272389..54daddb08eea 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -22,7 +22,7 @@ _txt2obj_gc, ) from cryptography.hazmat.primitives import hashes, serialization -from cryptography.x509.base import _PUBLIC_KEY_TYPES +from cryptography.x509.base import PUBLIC_KEY_TYPES from cryptography.x509.name import _ASN1Type @@ -76,7 +76,7 @@ def serial_number(self) -> int: self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL) return _asn1_integer_to_int(self._backend, asn1_int) - def public_key(self) -> _PUBLIC_KEY_TYPES: + def public_key(self) -> PUBLIC_KEY_TYPES: pkey = self._backend._lib.X509_get_pubkey(self._x509) if pkey == self._backend._ffi.NULL: # Remove errors from the stack. @@ -360,7 +360,7 @@ def __len__(self) -> int: def extensions(self) -> x509.Extensions: return self._backend._crl_extension_parser.parse(self._x509_crl) - def is_signature_valid(self, public_key: _PUBLIC_KEY_TYPES) -> bool: + def is_signature_valid(self, public_key: PUBLIC_KEY_TYPES) -> bool: if not isinstance( public_key, ( @@ -403,7 +403,7 @@ def __ne__(self, other: object) -> bool: def __hash__(self) -> int: return hash(self.public_bytes(serialization.Encoding.DER)) - def public_key(self) -> _PUBLIC_KEY_TYPES: + def public_key(self) -> PUBLIC_KEY_TYPES: pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req) self._backend.openssl_assert(pkey != self._backend._ffi.NULL) pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free) diff --git a/src/cryptography/hazmat/_types.py b/src/cryptography/hazmat/primitives/asymmetric/types.py similarity index 89% rename from src/cryptography/hazmat/_types.py rename to src/cryptography/hazmat/primitives/asymmetric/types.py index ba29baf28b2c..ef946cf4b75f 100644 --- a/src/cryptography/hazmat/_types.py +++ b/src/cryptography/hazmat/primitives/asymmetric/types.py @@ -13,14 +13,14 @@ ) -_PUBLIC_KEY_TYPES = typing.Union[ +PUBLIC_KEY_TYPES = typing.Union[ dsa.DSAPublicKey, rsa.RSAPublicKey, ec.EllipticCurvePublicKey, ed25519.Ed25519PublicKey, ed448.Ed448PublicKey, ] -_PRIVATE_KEY_TYPES = typing.Union[ +PRIVATE_KEY_TYPES = typing.Union[ ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey, rsa.RSAPrivateKey, diff --git a/src/cryptography/hazmat/primitives/serialization/base.py b/src/cryptography/hazmat/primitives/serialization/base.py index 30679c87ef0c..d0f304757626 100644 --- a/src/cryptography/hazmat/primitives/serialization/base.py +++ b/src/cryptography/hazmat/primitives/serialization/base.py @@ -5,27 +5,27 @@ import typing -from cryptography.hazmat._types import ( - _PRIVATE_KEY_TYPES, - _PUBLIC_KEY_TYPES, -) from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import Backend from cryptography.hazmat.primitives.asymmetric import dh +from cryptography.hazmat.primitives.asymmetric.types import ( + PRIVATE_KEY_TYPES, + PUBLIC_KEY_TYPES, +) def load_pem_private_key( data: bytes, password: typing.Optional[bytes], backend: typing.Optional[Backend] = None, -) -> _PRIVATE_KEY_TYPES: +) -> PRIVATE_KEY_TYPES: backend = _get_backend(backend) return backend.load_pem_private_key(data, password) def load_pem_public_key( data: bytes, backend: typing.Optional[Backend] = None -) -> _PUBLIC_KEY_TYPES: +) -> PUBLIC_KEY_TYPES: backend = _get_backend(backend) return backend.load_pem_public_key(data) @@ -41,14 +41,14 @@ def load_der_private_key( data: bytes, password: typing.Optional[bytes], backend: typing.Optional[Backend] = None, -) -> _PRIVATE_KEY_TYPES: +) -> PRIVATE_KEY_TYPES: backend = _get_backend(backend) return backend.load_der_private_key(data, password) def load_der_public_key( data: bytes, backend: typing.Optional[Backend] = None -) -> _PUBLIC_KEY_TYPES: +) -> PUBLIC_KEY_TYPES: backend = _get_backend(backend) return backend.load_der_public_key(data) diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index 9bbde978fda1..e97c32cb9167 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -9,7 +9,6 @@ import typing from enum import Enum -from cryptography.hazmat._types import _PRIVATE_KEY_TYPES, _PUBLIC_KEY_TYPES from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import Backend from cryptography.hazmat.primitives import hashes, serialization @@ -20,6 +19,10 @@ ed448, rsa, ) +from cryptography.hazmat.primitives.asymmetric.types import ( + PRIVATE_KEY_TYPES, + PUBLIC_KEY_TYPES, +) from cryptography.x509.extensions import Extension, ExtensionType, Extensions from cryptography.x509.name import Name from cryptography.x509.oid import ObjectIdentifier @@ -99,7 +102,7 @@ def version(self) -> Version: """ @abc.abstractmethod - def public_key(self) -> _PUBLIC_KEY_TYPES: + def public_key(self) -> PUBLIC_KEY_TYPES: """ Returns the public key """ @@ -320,7 +323,7 @@ def __iter__(self) -> typing.Iterator[RevokedCertificate]: """ @abc.abstractmethod - def is_signature_valid(self, public_key: _PUBLIC_KEY_TYPES) -> bool: + def is_signature_valid(self, public_key: PUBLIC_KEY_TYPES) -> bool: """ Verifies signature of revocation list against given public key. """ @@ -346,7 +349,7 @@ def __hash__(self) -> int: """ @abc.abstractmethod - def public_key(self) -> _PUBLIC_KEY_TYPES: + def public_key(self) -> PUBLIC_KEY_TYPES: """ Returns the public key """ @@ -518,7 +521,7 @@ def add_attribute( def sign( self, - private_key: _PRIVATE_KEY_TYPES, + private_key: PRIVATE_KEY_TYPES, algorithm: typing.Optional[hashes.HashAlgorithm], backend: typing.Optional[Backend] = None, ) -> CertificateSigningRequest: @@ -538,7 +541,7 @@ def __init__( self, issuer_name: typing.Optional[Name] = None, subject_name: typing.Optional[Name] = None, - public_key: typing.Optional[_PUBLIC_KEY_TYPES] = None, + public_key: typing.Optional[PUBLIC_KEY_TYPES] = None, serial_number: typing.Optional[int] = None, not_valid_before: typing.Optional[datetime.datetime] = None, not_valid_after: typing.Optional[datetime.datetime] = None, @@ -591,7 +594,7 @@ def subject_name(self, name: Name) -> "CertificateBuilder": def public_key( self, - key: _PUBLIC_KEY_TYPES, + key: PUBLIC_KEY_TYPES, ) -> "CertificateBuilder": """ Sets the requestor's public key (as found in the signing request). @@ -737,7 +740,7 @@ def add_extension( def sign( self, - private_key: _PRIVATE_KEY_TYPES, + private_key: PRIVATE_KEY_TYPES, algorithm: typing.Optional[hashes.HashAlgorithm], backend: typing.Optional[Backend] = None, ) -> Certificate: @@ -885,7 +888,7 @@ def add_revoked_certificate( def sign( self, - private_key: _PRIVATE_KEY_TYPES, + private_key: PRIVATE_KEY_TYPES, algorithm: typing.Optional[hashes.HashAlgorithm], backend: typing.Optional[Backend] = None, ) -> CertificateRevocationList: diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index fb229d395070..35ed776b7932 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -10,11 +10,11 @@ import typing from enum import Enum -from cryptography.hazmat._types import _PUBLIC_KEY_TYPES from cryptography.hazmat.bindings._rust import asn1 from cryptography.hazmat.primitives import constant_time, serialization from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey +from cryptography.hazmat.primitives.asymmetric.types import PUBLIC_KEY_TYPES from cryptography.x509.certificate_transparency import ( SignedCertificateTimestamp, ) @@ -40,7 +40,7 @@ ExtensionTypeVar = typing.TypeVar("ExtensionTypeVar", bound="ExtensionType") -def _key_identifier_from_public_key(public_key: _PUBLIC_KEY_TYPES) -> bytes: +def _key_identifier_from_public_key(public_key: PUBLIC_KEY_TYPES) -> bytes: if isinstance(public_key, RSAPublicKey): data = public_key.public_bytes( serialization.Encoding.DER, @@ -197,7 +197,7 @@ def __init__( @classmethod def from_issuer_public_key( - cls, public_key: _PUBLIC_KEY_TYPES + cls, public_key: PUBLIC_KEY_TYPES ) -> "AuthorityKeyIdentifier": digest = _key_identifier_from_public_key(public_key) return cls( @@ -270,7 +270,7 @@ def __init__(self, digest: bytes) -> None: @classmethod def from_public_key( - cls, public_key: _PUBLIC_KEY_TYPES + cls, public_key: PUBLIC_KEY_TYPES ) -> "SubjectKeyIdentifier": return cls(_key_identifier_from_public_key(public_key)) diff --git a/src/cryptography/x509/ocsp.py b/src/cryptography/x509/ocsp.py index 1d136e7f9be3..f35e25f8a6d1 100644 --- a/src/cryptography/x509/ocsp.py +++ b/src/cryptography/x509/ocsp.py @@ -11,8 +11,8 @@ from cryptography import x509 from cryptography.hazmat.primitives import hashes, serialization from cryptography.x509.base import ( + PRIVATE_KEY_TYPES, _EARLIEST_UTC_TIME, - _PRIVATE_KEY_TYPES, _convert_to_naive_utc_time, _reject_duplicate_extension, ) @@ -463,7 +463,7 @@ def add_extension( def sign( self, - private_key: _PRIVATE_KEY_TYPES, + private_key: PRIVATE_KEY_TYPES, algorithm: typing.Optional[hashes.HashAlgorithm], ) -> OCSPResponse: from cryptography.hazmat.backends.openssl.backend import backend From ffb425f6dca4f6eb8c8a04a887c9c8ec7745e900 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 25 Apr 2021 08:22:49 -0500 Subject: [PATCH 0147/1456] update RSA tests with larger key sizes, better hash funcs (#6010) and some more FIPS skips. This also removes some unneeded fixtures now. --- tests/hazmat/primitives/fixtures_rsa.py | 74 ------------ tests/hazmat/primitives/test_rsa.py | 143 ++++++++++++++---------- 2 files changed, 84 insertions(+), 133 deletions(-) diff --git a/tests/hazmat/primitives/fixtures_rsa.py b/tests/hazmat/primitives/fixtures_rsa.py index bfb11bc8710a..f6b5c3b9fa78 100644 --- a/tests/hazmat/primitives/fixtures_rsa.py +++ b/tests/hazmat/primitives/fixtures_rsa.py @@ -40,37 +40,6 @@ ), ) -RSA_KEY_512_ALT = RSAPrivateNumbers( - p=int( - "febe19c29a0b50fefa4f7b1832f84df1caf9be8242da25c9d689e18226e67ce5", 16 - ), - q=int( - "eb616c639dd999feda26517e1c77b6878f363fe828c4e6670ec1787f28b1e731", 16 - ), - d=int( - "80edecfde704a806445a4cc782b85d3f36f17558f385654ea767f006470fdfcbda5e2" - "206839289d3f419b4e4fb8e1acee1b4fb9c591f69b64ec83937f5829241", - 16, - ), - dmp1=int( - "7f4fa06e2a3077a54691cc5216bf13ad40a4b9fa3dd0ea4bca259487484baea5", 16 - ), - dmq1=int( - "35eaa70d5a8711c352ed1c15ab27b0e3f46614d575214535ae279b166597fac1", 16 - ), - iqmp=int( - "cc1f272de6846851ec80cb89a02dbac78f44b47bc08f53b67b4651a3acde8b19", 16 - ), - public_numbers=RSAPublicNumbers( - e=65537, - n=int( - "ea397388b999ef0f7e7416fa000367efd9a0ba0deddd3f8160d1c36d62267f210" - "fbd9c97abeb6654450ff03e7601b8caa6c6f4cba18f0b52c179d17e8f258ad5", - 16, - ), - ), -) - RSA_KEY_522 = RSAPrivateNumbers( p=int( "1a8aab9a069f92b52fdf05824f2846223dc27adfc806716a247a77d4c36885e4bf", @@ -192,49 +161,6 @@ ), ) -RSA_KEY_768 = RSAPrivateNumbers( - p=int( - "f80c0061b607f93206b68e208906498d68c6e396faf457150cf975c8f849848465869" - "7ecd402313397088044c4c2071b", - 16, - ), - q=int( - "e5b5dbecc93c6d306fc14e6aa9737f9be2728bc1a326a8713d2849b34c1cb54c63468" - "3a68abb1d345dbf15a3c492cf55", - 16, - ), - d=int( - "d44601442255ffa331212c60385b5e898555c75c0272632ff42d57c4b16ca97dbca9f" - "d6d99cd2c9fd298df155ed5141b4be06c651934076133331d4564d73faed7ce98e283" - "2f7ce3949bc183be7e7ca34f6dd04a9098b6c73649394b0a76c541", - 16, - ), - dmp1=int( - "a5763406fa0b65929661ce7b2b8c73220e43a5ebbfe99ff15ddf464fd238105ad4f2a" - "c83818518d70627d8908703bb03", - 16, - ), - dmq1=int( - "cb467a9ef899a39a685aecd4d0ad27b0bfdc53b68075363c373d8eb2bed8eccaf3533" - "42f4db735a9e087b7539c21ba9d", - 16, - ), - iqmp=int( - "5fe86bd3aee0c4d09ef11e0530a78a4534c9b833422813b5c934a450c8e564d8097a0" - "6fd74f1ebe2d5573782093f587a", - 16, - ), - public_numbers=RSAPublicNumbers( - e=65537, - n=int( - "de92f1eb5f4abf426b6cac9dd1e9bf57132a4988b4ed3f8aecc15e251028bd6df" - "46eb97c711624af7db15e6430894d1b640c13929329241ee094f5a4fe1a20bc9b" - "75232320a72bc567207ec54d6b48dccb19737cf63acc1021abb337f19130f7", - 16, - ), - ), -) - RSA_KEY_1024 = RSAPrivateNumbers( p=int( "ea4d9d9a1a068be44b9a5f8f6de0512b2c5ba1fb804a4655babba688e6e890b347c1a" diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 2c8715b24eb5..2666fdfc1787 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -39,11 +39,9 @@ RSA_KEY_2048, RSA_KEY_2048_ALT, RSA_KEY_512, - RSA_KEY_512_ALT, RSA_KEY_522, RSA_KEY_599, RSA_KEY_745, - RSA_KEY_768, RSA_KEY_CORRUPTED, ) from .utils import ( @@ -69,6 +67,16 @@ class DummyMGF(object): _salt_length = 0 +def _check_fips_key_length(backend, private_key): + if ( + backend._fips_enabled + and private_key.key_size < backend._fips_rsa_min_key_size + ): + pytest.skip( + "Key size not FIPS compliant: {}".format(private_key.key_size) + ) + + def _check_rsa_private_numbers_if_serializable(key): if isinstance(key, rsa.RSAPrivateKey): _check_rsa_private_numbers(key.private_numbers()) @@ -393,6 +401,7 @@ class TestRSASignature(object): ), skip_message="Does not support PKCS1v1.5.", ) + @pytest.mark.skip_fips(reason="SHA1 signing not supported in FIPS mode.") def test_pkcs1v15_signing(self, backend, subtests): vectors = _flatten_pkcs1_examples( load_vectors_from_file( @@ -440,6 +449,7 @@ def test_pkcs1v15_signing(self, backend, subtests): ) ), ) + @pytest.mark.skip_fips(reason="SHA1 signing not supported in FIPS mode.") def test_pss_signing(self, pkcs1_example, backend): private, public, example = pkcs1_example private_key = rsa.RSAPrivateNumbers( @@ -484,7 +494,7 @@ def test_pss_signing(self, pkcs1_example, backend): ) def test_pss_signing_sha2(self, hash_alg, backend): _skip_pss_hash_algorithm_unsupported(backend, hash_alg) - private_key = RSA_KEY_768.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) public_key = private_key.public_key() pss = padding.PSS( mgf=padding.MGF1(hash_alg), salt_length=padding.PSS.MAX_LENGTH @@ -505,6 +515,7 @@ def test_pss_signing_sha2(self, hash_alg, backend): ), skip_message="Does not support SHA512.", ) + @pytest.mark.skip_fips(reason="Unsupported key size in FIPS mode.") def test_pss_minimum_key_size_for_digest(self, backend): private_key = RSA_KEY_522.private_key(backend) private_key.sign( @@ -529,6 +540,7 @@ def test_pss_minimum_key_size_for_digest(self, backend): only_if=lambda backend: backend.hash_supported(hashes.SHA512()), skip_message="Does not support SHA512.", ) + @pytest.mark.skip_fips(reason="Unsupported key size in FIPS mode.") def test_pss_signing_digest_too_large_for_key_size(self, backend): private_key = RSA_KEY_512.private_key(backend) with pytest.raises(ValueError): @@ -551,14 +563,14 @@ def test_pss_signing_digest_too_large_for_key_size(self, backend): skip_message="Does not support PSS.", ) def test_pss_signing_salt_length_too_long(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) with pytest.raises(ValueError): private_key.sign( b"failure coming", padding.PSS( mgf=padding.MGF1(hashes.SHA1()), salt_length=1000000 ), - hashes.SHA1(), + hashes.SHA256(), ) @pytest.mark.supported( @@ -568,9 +580,9 @@ def test_pss_signing_salt_length_too_long(self, backend): skip_message="Does not support PKCS1v1.5.", ) def test_use_after_finalize(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) with pytest.warns(CryptographyDeprecationWarning): - signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1()) + signer = private_key.signer(padding.PKCS1v15(), hashes.SHA256()) signer.update(b"sign me") signer.finalize() with pytest.raises(AlreadyFinalized): @@ -579,12 +591,12 @@ def test_use_after_finalize(self, backend): signer.update(b"more data") def test_unsupported_padding(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING): private_key.sign(b"msg", DummyAsymmetricPadding(), hashes.SHA1()) def test_padding_incorrect_type(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) with pytest.raises(TypeError): private_key.sign( b"msg", @@ -616,6 +628,7 @@ def test_unsupported_pss_mgf(self, backend): ), skip_message="Does not support PKCS1v1.5.", ) + @pytest.mark.skip_fips(reason="Unsupported key size in FIPS mode.") def test_pkcs1_digest_too_large_for_key_size(self, backend): private_key = RSA_KEY_599.private_key(backend) with pytest.raises(ValueError): @@ -629,15 +642,16 @@ def test_pkcs1_digest_too_large_for_key_size(self, backend): ), skip_message="Does not support PKCS1v1.5.", ) + @pytest.mark.skip_fips(reason="Unsupported key size in FIPS mode.") def test_pkcs1_minimum_key_size(self, backend): private_key = RSA_KEY_745.private_key(backend) private_key.sign(b"no failure", padding.PKCS1v15(), hashes.SHA512()) def test_sign(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) message = b"one little message" pkcs = padding.PKCS1v15() - algorithm = hashes.SHA1() + algorithm = hashes.SHA256() signature = private_key.sign(message, pkcs, algorithm) public_key = private_key.public_key() public_key.verify(signature, message, pkcs, algorithm) @@ -649,16 +663,16 @@ def test_sign(self, backend): skip_message="Does not support PSS.", ) def test_prehashed_sign(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) message = b"one little message" - h = hashes.Hash(hashes.SHA1(), backend) + h = hashes.Hash(hashes.SHA256(), backend) h.update(message) digest = h.finalize() pss = padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0) - prehashed_alg = asym_utils.Prehashed(hashes.SHA1()) + prehashed_alg = asym_utils.Prehashed(hashes.SHA256()) signature = private_key.sign(digest, pss, prehashed_alg) public_key = private_key.public_key() - public_key.verify(signature, message, pss, hashes.SHA1()) + public_key.verify(signature, message, pss, hashes.SHA256()) @pytest.mark.supported( only_if=lambda backend: backend.hash_supported( @@ -730,12 +744,12 @@ def test_prehashed_unsupported_in_verifier_ctx(self, backend): ) def test_prehashed_unsupported_in_signature_recover(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) public_key = private_key.public_key() signature = private_key.sign( - b"sign me", padding.PKCS1v15(), hashes.SHA1() + b"sign me", padding.PKCS1v15(), hashes.SHA256() ) - prehashed_alg = asym_utils.Prehashed(hashes.SHA1()) + prehashed_alg = asym_utils.Prehashed(hashes.SHA256()) with pytest.raises(TypeError): public_key.recover_data_from_signature( signature, @@ -799,25 +813,28 @@ def test_pkcs1v15_verification(self, backend, subtests): skip_message="Does not support PKCS1v1.5.", ) def test_invalid_pkcs1v15_signature_wrong_data(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) public_key = private_key.public_key() signature = private_key.sign( - b"sign me", padding.PKCS1v15(), hashes.SHA1() + b"sign me", padding.PKCS1v15(), hashes.SHA256() ) with pytest.raises(InvalidSignature): public_key.verify( - signature, b"incorrect data", padding.PKCS1v15(), hashes.SHA1() + signature, + b"incorrect data", + padding.PKCS1v15(), + hashes.SHA256(), ) def test_invalid_pkcs1v15_signature_recover_wrong_hash_alg(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) public_key = private_key.public_key() signature = private_key.sign( - b"sign me", padding.PKCS1v15(), hashes.SHA1() + b"sign me", padding.PKCS1v15(), hashes.SHA256() ) with pytest.raises(InvalidSignature): public_key.recover_data_from_signature( - signature, padding.PKCS1v15(), hashes.SHA256() + signature, padding.PKCS1v15(), hashes.SHA512() ) def test_invalid_signature_sequence_removed(self, backend): @@ -863,14 +880,14 @@ def test_invalid_signature_sequence_removed(self, backend): skip_message="Does not support PKCS1v1.5.", ) def test_invalid_pkcs1v15_signature_wrong_key(self, backend): - private_key = RSA_KEY_512.private_key(backend) - private_key2 = RSA_KEY_512_ALT.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) + private_key2 = RSA_KEY_2048_ALT.private_key(backend) public_key = private_key2.public_key() msg = b"sign me" - signature = private_key.sign(msg, padding.PKCS1v15(), hashes.SHA1()) + signature = private_key.sign(msg, padding.PKCS1v15(), hashes.SHA256()) with pytest.raises(InvalidSignature): public_key.verify( - signature, msg, padding.PKCS1v15(), hashes.SHA1() + signature, msg, padding.PKCS1v15(), hashes.SHA256() ) @pytest.mark.supported( @@ -913,6 +930,7 @@ def test_pss_verification(self, pkcs1_example, backend): ), skip_message="Does not support PSS.", ) + @pytest.mark.skip_fips(reason="Unsupported key size in FIPS mode.") def test_invalid_pss_signature_wrong_data(self, backend): public_key = rsa.RSAPublicNumbers( n=int( @@ -947,6 +965,7 @@ def test_invalid_pss_signature_wrong_data(self, backend): ), skip_message="Does not support PSS.", ) + @pytest.mark.skip_fips(reason="Unsupported key size in FIPS mode.") def test_invalid_pss_signature_wrong_key(self, backend): signature = binascii.unhexlify( b"3a1880165014ba6eb53cc1449d13e5132ebcc0cfd9ade6d7a2494a0503bd0826" @@ -983,6 +1002,7 @@ def test_invalid_pss_signature_wrong_key(self, backend): ), skip_message="Does not support PSS.", ) + @pytest.mark.skip_fips(reason="Unsupported key size in FIPS mode.") def test_invalid_pss_signature_data_too_large_for_modulus(self, backend): # 2048 bit PSS signature signature = binascii.unhexlify( @@ -1009,13 +1029,13 @@ def test_invalid_pss_signature_data_too_large_for_modulus(self, backend): ) def test_invalid_pss_signature_recover(self, backend): - private_key = RSA_KEY_1024.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) public_key = private_key.public_key() pss_padding = padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), salt_length=padding.PSS.MAX_LENGTH, ) - signature = private_key.sign(b"sign me", pss_padding, hashes.SHA1()) + signature = private_key.sign(b"sign me", pss_padding, hashes.SHA256()) # Hash algorithm cannot be absent for PSS padding with pytest.raises(TypeError): @@ -1026,7 +1046,7 @@ def test_invalid_pss_signature_recover(self, backend): # Signature data recovery not supported with PSS with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING): public_key.recover_data_from_signature( - signature, pss_padding, hashes.SHA1() + signature, pss_padding, hashes.SHA256() ) @pytest.mark.supported( @@ -1036,15 +1056,15 @@ def test_invalid_pss_signature_recover(self, backend): skip_message="Does not support PKCS1v1.5.", ) def test_use_after_finalize(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) public_key = private_key.public_key() signature = private_key.sign( - b"sign me", padding.PKCS1v15(), hashes.SHA1() + b"sign me", padding.PKCS1v15(), hashes.SHA256() ) with pytest.warns(CryptographyDeprecationWarning): verifier = public_key.verifier( - signature, padding.PKCS1v15(), hashes.SHA1() + signature, padding.PKCS1v15(), hashes.SHA256() ) verifier.update(b"sign me") verifier.verify() @@ -1054,7 +1074,7 @@ def test_use_after_finalize(self, backend): verifier.update(b"more data") def test_unsupported_padding(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) public_key = private_key.public_key() with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING): public_key.verify( @@ -1068,7 +1088,7 @@ def test_unsupported_padding(self, backend): skip_message="Does not support PKCS1v1.5.", ) def test_signature_not_bytes(self, backend): - public_key = RSA_KEY_512.public_numbers.public_key(backend) + public_key = RSA_KEY_2048.public_numbers.public_key(backend) signature = 1234 with pytest.raises(TypeError), pytest.warns( @@ -1077,7 +1097,7 @@ def test_signature_not_bytes(self, backend): public_key.verifier(signature, padding.PKCS1v15(), hashes.SHA1()) def test_padding_incorrect_type(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) public_key = private_key.public_key() with pytest.raises(TypeError): public_key.verify( @@ -1094,7 +1114,7 @@ def test_padding_incorrect_type(self, backend): skip_message="Does not support PSS.", ) def test_unsupported_pss_mgf(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) public_key = private_key.public_key() with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_MGF): public_key.verify( @@ -1119,6 +1139,7 @@ def test_unsupported_pss_mgf(self, backend): only_if=lambda backend: backend.hash_supported(hashes.SHA512()), skip_message="Does not support SHA512.", ) + @pytest.mark.skip_fips(reason="Unsupported key size in FIPS mode.") def test_pss_verify_digest_too_large_for_key_size(self, backend): private_key = RSA_KEY_512.private_key(backend) signature = binascii.unhexlify( @@ -1146,6 +1167,7 @@ def test_pss_verify_digest_too_large_for_key_size(self, backend): ), skip_message="Does not support PSS.", ) + @pytest.mark.skip_fips(reason="Unsupported key size in FIPS mode.") def test_pss_verify_salt_length_too_long(self, backend): signature = binascii.unhexlify( b"8b9a3ae9fb3b64158f3476dd8d8a1f1425444e98940e0926378baa9944d219d8" @@ -1174,30 +1196,30 @@ def test_pss_verify_salt_length_too_long(self, backend): ) def test_verify(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) message = b"one little message" pkcs = padding.PKCS1v15() - algorithm = hashes.SHA1() + algorithm = hashes.SHA256() signature = private_key.sign(message, pkcs, algorithm) public_key = private_key.public_key() public_key.verify(signature, message, pkcs, algorithm) def test_prehashed_verify(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) message = b"one little message" - h = hashes.Hash(hashes.SHA1(), backend) + h = hashes.Hash(hashes.SHA256(), backend) h.update(message) digest = h.finalize() - prehashed_alg = asym_utils.Prehashed(hashes.SHA1()) + prehashed_alg = asym_utils.Prehashed(hashes.SHA256()) pkcs = padding.PKCS1v15() - signature = private_key.sign(message, pkcs, hashes.SHA1()) + signature = private_key.sign(message, pkcs, hashes.SHA256()) public_key = private_key.public_key() public_key.verify(signature, digest, pkcs, prehashed_alg) def test_prehashed_digest_mismatch(self, backend): - public_key = RSA_KEY_512.private_key(backend).public_key() + public_key = RSA_KEY_2048.private_key(backend).public_key() message = b"one little message" - h = hashes.Hash(hashes.SHA1(), backend) + h = hashes.Hash(hashes.SHA256(), backend) h.update(message) data = h.finalize() prehashed_alg = asym_utils.Prehashed(hashes.SHA512()) @@ -1531,9 +1553,9 @@ def test_decrypt_pkcs1v15_vectors(self, backend, subtests): assert message == binascii.unhexlify(example["message"]) def test_unsupported_padding(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING): - private_key.decrypt(b"0" * 64, DummyAsymmetricPadding()) + private_key.decrypt(b"0" * 256, DummyAsymmetricPadding()) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -1542,9 +1564,9 @@ def test_unsupported_padding(self, backend): skip_message="Does not support PKCS1v1.5.", ) def test_decrypt_invalid_decrypt(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) with pytest.raises(ValueError): - private_key.decrypt(b"\x00" * 64, padding.PKCS1v15()) + private_key.decrypt(b"\x00" * 256, padding.PKCS1v15()) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -1553,9 +1575,9 @@ def test_decrypt_invalid_decrypt(self, backend): skip_message="Does not support PKCS1v1.5.", ) def test_decrypt_ciphertext_too_large(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) with pytest.raises(ValueError): - private_key.decrypt(b"\x00" * 65, padding.PKCS1v15()) + private_key.decrypt(b"\x00" * 257, padding.PKCS1v15()) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( @@ -1564,7 +1586,7 @@ def test_decrypt_ciphertext_too_large(self, backend): skip_message="Does not support PKCS1v1.5.", ) def test_decrypt_ciphertext_too_small(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) ct = binascii.unhexlify( b"50b4c14136bd198c2f3c3ed243fce036e168d56517984a263cd66492b80804f1" b"69d210f2b9bdfb48b12f9ea05009c77da257cc600ccefe3a6283789d8ea0" @@ -1667,7 +1689,7 @@ def test_invalid_oaep_decryption(self, backend): # More recent versions of OpenSSL may raise different errors. # This test triggers a failure and confirms that we properly handle # it. - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) ciphertext = private_key.public_key().encrypt( b"secure data", @@ -1678,7 +1700,7 @@ def test_invalid_oaep_decryption(self, backend): ), ) - private_key_alt = RSA_KEY_512_ALT.private_key(backend) + private_key_alt = RSA_KEY_2048_ALT.private_key(backend) with pytest.raises(ValueError): private_key_alt.decrypt( @@ -1729,10 +1751,10 @@ def test_invalid_oaep_decryption_data_to_large_for_modulus(self, backend): ) def test_unsupported_oaep_mgf(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_MGF): private_key.decrypt( - b"0" * 64, + b"0" * 256, padding.OAEP( mgf=DummyMGF(), # type: ignore[arg-type] algorithm=hashes.SHA1(), @@ -1778,6 +1800,7 @@ class TestRSAEncryption(object): ) def test_rsa_encrypt_oaep(self, key_data, pad, backend): private_key = key_data.private_key(backend) + _check_fips_key_length(backend, private_key) pt = b"encrypt me!" public_key = private_key.public_key() ct = public_key.encrypt(pt, pad) @@ -1858,6 +1881,7 @@ def test_rsa_encrypt_oaep_sha2(self, mgf1hash, oaephash, backend): ) def test_rsa_encrypt_pkcs1v15(self, key_data, pad, backend): private_key = key_data.private_key(backend) + _check_fips_key_length(backend, private_key) pt = b"encrypt me!" public_key = private_key.public_key() ct = public_key.encrypt(pt, pad) @@ -1893,6 +1917,7 @@ def test_rsa_encrypt_pkcs1v15(self, key_data, pad, backend): ) def test_rsa_encrypt_key_too_small(self, key_data, pad, backend): private_key = key_data.private_key(backend) + _check_fips_key_length(backend, private_key) public_key = private_key.public_key() # Slightly smaller than the key size but not enough for padding. with pytest.raises(ValueError): @@ -1903,7 +1928,7 @@ def test_rsa_encrypt_key_too_small(self, key_data, pad, backend): public_key.encrypt(b"\x00" * (private_key.key_size // 8 + 5), pad) def test_unsupported_padding(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) public_key = private_key.public_key() with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_PADDING): @@ -1914,7 +1939,7 @@ def test_unsupported_padding(self, backend): ) def test_unsupported_oaep_mgf(self, backend): - private_key = RSA_KEY_512.private_key(backend) + private_key = RSA_KEY_2048.private_key(backend) public_key = private_key.public_key() with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_MGF): From b1c3e2f2836ea668ea9e36623bef353e4a6daca8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 27 Apr 2021 08:39:16 -0400 Subject: [PATCH 0148/1456] Bump libc from 0.2.93 to 0.2.94 in /src/rust (#6014) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.93 to 0.2.94. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.93...0.2.94) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index b5ceed20b367..252a760133d3 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -131,9 +131,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.93" +version = "0.2.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" +checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" [[package]] name = "lock_api" From bc03d94a930786580bbe016309973e0cb8052548 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 27 Apr 2021 10:01:34 -0400 Subject: [PATCH 0149/1456] reduce timeout time for CI jobs (#6016) * reduce timeout time for CI jobs * ubuntu rolling is py39 now --- .github/workflows/ci.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 18b5bf2251ec..76d5e0b71a5b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: RUST: - stable name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" - timeout-minutes: 30 + timeout-minutes: 20 steps: - uses: actions/checkout@v2 - uses: actions/cache@v2.1.5 @@ -110,12 +110,12 @@ jobs: - {IMAGE: "sid", TOXENV: "py39"} - {IMAGE: "ubuntu-bionic", TOXENV: "py36"} - {IMAGE: "ubuntu-focal", TOXENV: "py38"} - - {IMAGE: "ubuntu-rolling", TOXENV: "py38"} - - {IMAGE: "ubuntu-rolling", TOXENV: "py38-randomorder"} + - {IMAGE: "ubuntu-rolling", TOXENV: "py39"} + - {IMAGE: "ubuntu-rolling", TOXENV: "py39-randomorder"} - {IMAGE: "fedora", TOXENV: "py39"} - {IMAGE: "alpine", TOXENV: "py38"} name: "${{ matrix.IMAGE.TOXENV }} on ${{ matrix.IMAGE.IMAGE }}" - timeout-minutes: 30 + timeout-minutes: 20 steps: - uses: actions/checkout@v2 - uses: actions/cache@v2.1.5 @@ -153,7 +153,7 @@ jobs: - beta - nightly name: "${{ matrix.PYTHON.TOXENV }} with Rust ${{ matrix.RUST }}" - timeout-minutes: 30 + timeout-minutes: 20 steps: - uses: actions/checkout@v2 - uses: actions/cache@v2.1.5 @@ -189,7 +189,7 @@ jobs: linux-rust-coverage: runs-on: ubuntu-latest name: "Rust Coverage" - timeout-minutes: 30 + timeout-minutes: 20 steps: - uses: actions/checkout@v2 - uses: actions/cache@v2.1.5 @@ -253,7 +253,7 @@ jobs: RUST: - stable name: "${{ matrix.PYTHON.TOXENV }} on macOS" - timeout-minutes: 30 + timeout-minutes: 20 steps: - uses: actions/checkout@v2 - uses: actions/cache@v2.1.5 @@ -313,7 +313,7 @@ jobs: - stable JOB_NUMBER: [0, 1, 2, 3] name: "${{ matrix.PYTHON.TOXENV }} on ${{ matrix.WINDOWS.WINDOWS }} (part ${{ matrix.JOB_NUMBER }})" - timeout-minutes: 30 + timeout-minutes: 20 steps: - uses: actions/checkout@v2 - name: Setup python @@ -376,7 +376,7 @@ jobs: PYTHON: - 3.7 name: "Downstream tests for ${{ matrix.DOWNSTREAM }}" - timeout-minutes: 30 + timeout-minutes: 20 steps: - uses: actions/checkout@v2 - uses: actions/cache@v2.1.5 @@ -409,7 +409,7 @@ jobs: if: github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest name: "linkcheck" - timeout-minutes: 30 + timeout-minutes: 20 steps: - uses: actions/checkout@v2 - name: Setup python From 9720335e76cb457e380faa67f49c5d4b8cd9f3d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Apr 2021 08:37:48 -0400 Subject: [PATCH 0150/1456] Bump syn from 1.0.70 to 1.0.71 in /src/rust (#6019) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.70 to 1.0.71. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.70...1.0.71) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 252a760133d3..6db17973d78a 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -293,9 +293,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9505f307c872bab8eb46f77ae357c8eba1fdacead58ee5a850116b1d7f82883" +checksum = "ad184cc9470f9117b2ac6817bfe297307418819ba40552f9b3846f05c33d5373" dependencies = [ "proc-macro2", "quote", From 33bc4fd2394b0168508cff1e8a0c6645528d47de Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 28 Apr 2021 13:48:03 -0400 Subject: [PATCH 0151/1456] Set up more github actions permissioning stuff (#6020) --- .github/workflows/ci.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 76d5e0b71a5b..4c0cbaa9234e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,8 @@ on: - '*.*' - '*.*.*' +permissions: read-all + jobs: linux: runs-on: ubuntu-latest @@ -34,6 +36,8 @@ jobs: timeout-minutes: 20 steps: - uses: actions/checkout@v2 + with: + persist-credentials: false - uses: actions/cache@v2.1.5 with: path: | @@ -118,6 +122,8 @@ jobs: timeout-minutes: 20 steps: - uses: actions/checkout@v2 + with: + persist-credentials: false - uses: actions/cache@v2.1.5 with: path: | @@ -156,6 +162,8 @@ jobs: timeout-minutes: 20 steps: - uses: actions/checkout@v2 + with: + persist-credentials: false - uses: actions/cache@v2.1.5 with: path: | @@ -192,6 +200,8 @@ jobs: timeout-minutes: 20 steps: - uses: actions/checkout@v2 + with: + persist-credentials: false - uses: actions/cache@v2.1.5 with: path: | @@ -256,6 +266,8 @@ jobs: timeout-minutes: 20 steps: - uses: actions/checkout@v2 + with: + persist-credentials: false - uses: actions/cache@v2.1.5 with: path: | @@ -316,6 +328,8 @@ jobs: timeout-minutes: 20 steps: - uses: actions/checkout@v2 + with: + persist-credentials: false - name: Setup python id: setup-python uses: actions/setup-python@v2.2.2 @@ -379,6 +393,8 @@ jobs: timeout-minutes: 20 steps: - uses: actions/checkout@v2 + with: + persist-credentials: false - uses: actions/cache@v2.1.5 with: path: | @@ -412,6 +428,8 @@ jobs: timeout-minutes: 20 steps: - uses: actions/checkout@v2 + with: + persist-credentials: false - name: Setup python uses: actions/setup-python@v2.2.2 with: From 4b31b1d7ff83cafba5da6ae71007774b85cabd89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Apr 2021 07:45:35 -0400 Subject: [PATCH 0152/1456] Bump redox_syscall from 0.2.6 to 0.2.7 in /src/rust (#6021) Bumps redox_syscall from 0.2.6 to 0.2.7. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 6db17973d78a..cb8986de2d49 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -272,9 +272,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8270314b5ccceb518e7e578952f0b72b88222d02e8f77f5ecf7abbb673539041" +checksum = "85dd92e586f7355c633911e11f77f3d12f04b1b1bd76a198bd34ae3af8341ef2" dependencies = [ "bitflags", ] From 073fc7ba4e1236cbcd9aba795e5ba26e0e379f13 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 29 Apr 2021 13:25:03 -0400 Subject: [PATCH 0153/1456] lock down lock-issues github token permissions (#6022) --- .github/workflows/lock.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index 7356bd4af3f9..6cd1b72d8e26 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -3,6 +3,9 @@ on: schedule: - cron: '0 0 * * *' +permissions: + issues: "write" + jobs: lock: runs-on: ubuntu-latest From 056d52980a3519b6a9814ab6ca91a8e99ed5b9b0 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 29 Apr 2021 14:05:30 -0400 Subject: [PATCH 0154/1456] Make running lock by hand possible (#6023) --- .github/workflows/lock.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index 6cd1b72d8e26..5f55eb2cec49 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -1,5 +1,6 @@ name: Lock Issues on: + workflow_dispatch: schedule: - cron: '0 0 * * *' From 233579d4be0b5969836659d91f5ed6f861e415ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 30 Apr 2021 07:03:31 -0400 Subject: [PATCH 0155/1456] Bump unicode-xid from 0.2.1 to 0.2.2 in /src/rust (#6025) Bumps [unicode-xid](https://github.com/unicode-rs/unicode-xid) from 0.2.1 to 0.2.2. - [Release notes](https://github.com/unicode-rs/unicode-xid/releases) - [Commits](https://github.com/unicode-rs/unicode-xid/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index cb8986de2d49..85221fdf7d0d 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -304,9 +304,9 @@ dependencies = [ [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "unindent" From 5900414e855fd7b642f577f8486e84e116fc9e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastien=20G=C3=A9rard?= Date: Sat, 1 May 2021 17:21:57 +0200 Subject: [PATCH 0156/1456] Update changelog to document the version scheme to avoid possible confusion (#6027) --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4f368b00f4a3..f6548de81989 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,7 @@ Changelog .. note:: This version is not yet released and is under active development. +* Changed the `version scheme `_. * Added support for :class:`~cryptography.hazmat.primitives.hashes.SM3` and :class:`~cryptography.hazmat.primitives.ciphers.algorithms.SM4`, From 04ac16bce0380c0103548d69a542f8bda2795695 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 1 May 2021 12:06:20 -0400 Subject: [PATCH 0157/1456] Use a relative URL and add a sentence (#6028) * Use a relative URL and add a sentence * Update CHANGELOG.rst Co-authored-by: Paul Kehrer Co-authored-by: Paul Kehrer --- CHANGELOG.rst | 4 +++- docs/spelling_wordlist.txt | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f6548de81989..6760ba76979e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,7 +8,9 @@ Changelog .. note:: This version is not yet released and is under active development. -* Changed the `version scheme `_. +* Changed the :ref:`version scheme `. This will + result in us incrementing the major version more frequently, but does not + change our existing backwards compatibility policy. * Added support for :class:`~cryptography.hazmat.primitives.hashes.SM3` and :class:`~cryptography.hazmat.primitives.ciphers.algorithms.SM4`, diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index cad47e53677a..c74cfa469b6a 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -57,6 +57,7 @@ Google hazmat Homebrew hostname +incrementing indistinguishability initialisms interoperability From a67f3066dca697af07caf88aab560086f75aa6ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 May 2021 07:55:56 -0400 Subject: [PATCH 0158/1456] Bump lock_api from 0.4.3 to 0.4.4 in /src/rust (#6032) Bumps [lock_api](https://github.com/Amanieu/parking_lot) from 0.4.3 to 0.4.4. - [Release notes](https://github.com/Amanieu/parking_lot/releases) - [Changelog](https://github.com/Amanieu/parking_lot/blob/master/CHANGELOG.md) - [Commits](https://github.com/Amanieu/parking_lot/compare/lock_api-0.4.3...lock_api-0.4.4) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 85221fdf7d0d..2376a07f9f2e 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -137,9 +137,9 @@ checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" [[package]] name = "lock_api" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" dependencies = [ "scopeguard", ] From 5c434bb07365483bc1eb0115fa76ee0fd917eef5 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 3 May 2021 12:10:32 -0400 Subject: [PATCH 0159/1456] update for rust-asn1 0.4 (#6030) --- src/rust/Cargo.lock | 16 ++- src/rust/Cargo.toml | 2 +- src/rust/src/asn1.rs | 240 +++++++++++++++++++------------------------ 3 files changed, 119 insertions(+), 139 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 2376a07f9f2e..7347fda5d102 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -4,13 +4,25 @@ version = 3 [[package]] name = "asn1" -version = "0.3.8" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "842b2cc51640a5737c94248d328936d11f53ea8080e3fdba6ba523b41fa6ea15" +checksum = "85bdcc33cd1ec0ebfee9cc2d1f6497454f984c1f5c6550ad27af4b7bd7731442" dependencies = [ + "asn1_derive", "chrono", ] +[[package]] +name = "asn1_derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce75fd5d9c4402a45fdec13c4701db332b4dfd307a3220494d6888c86edfff4b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.0.1" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 144f34106cbe..3c2e79b8f85c 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] lazy_static = "1" pyo3 = { version = "0.13.1" } -asn1 = { version = "0.3.8", default-features = false } +asn1 = { version = "0.4.1", default-features = false, features = ["derive"] } [features] extension-module = ["pyo3/extension-module"] diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 5d63bac65d82..683b4a09fbee 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -45,81 +45,60 @@ fn encode_tls_feature(py: pyo3::Python<'_>, ext: &pyo3::PyAny) -> pyo3::PyResult els.push(el?.getattr("value")?.extract::()?); } - let result = asn1::write(|w| { - w.write_element_with_type::>(&els); - }); - + let result = asn1::write_single(&asn1::SequenceOfWriter::new(&els)); Ok(pyo3::types::PyBytes::new(py, &result).to_object(py)) } #[pyo3::prelude::pyfunction] -fn parse_tls_feature(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult { +fn parse_tls_feature(py: pyo3::Python<'_>, data: &[u8]) -> Result { let x509_mod = py.import("cryptography.x509.extensions")?; let tls_feature_type_to_enum = x509_mod.getattr("_TLS_FEATURE_TYPE_TO_ENUM")?; - let features = asn1::parse::<_, PyAsn1Error, _>(data, |p| { - let features = pyo3::types::PyList::empty(py); - for el in p.read_element::>()? { - let feature = el?; - let py_feature = tls_feature_type_to_enum.get_item(feature.to_object(py))?; - features.append(py_feature)?; - } - Ok(features) - })?; + let features = pyo3::types::PyList::empty(py); + for el in asn1::parse_single::>(data)? { + let feature = el?; + let py_feature = tls_feature_type_to_enum.get_item(feature.to_object(py))?; + features.append(py_feature)?; + } let x509_module = py.import("cryptography.x509")?; - x509_module - .call1("TLSFeature", (features,)) - .map(|o| o.to_object(py)) + Ok(x509_module.call1("TLSFeature", (features,))?.to_object(py)) } #[pyo3::prelude::pyfunction] fn encode_precert_poison(py: pyo3::Python<'_>, _ext: &pyo3::PyAny) -> pyo3::PyObject { - let result = asn1::write(|w| { - w.write_element(()); - }); - + let result = asn1::write_single(&()); pyo3::types::PyBytes::new(py, &result).to_object(py) } #[pyo3::prelude::pyfunction] -fn parse_precert_poison(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult { - asn1::parse::<_, PyAsn1Error, _>(data, |p| { - p.read_element::<()>()?; - Ok(()) - })?; +fn parse_precert_poison(py: pyo3::Python<'_>, data: &[u8]) -> Result { + asn1::parse_single::<()>(data)?; let x509_module = py.import("cryptography.x509")?; - x509_module.call0("PrecertPoison").map(|o| o.to_object(py)) + Ok(x509_module.call0("PrecertPoison")?.to_object(py)) +} + +#[derive(asn1::Asn1Read)] +struct AlgorithmIdentifier<'a> { + _oid: asn1::ObjectIdentifier<'a>, + _params: Option>, +} + +#[derive(asn1::Asn1Read)] +struct Spki<'a> { + _algorithm: AlgorithmIdentifier<'a>, + data: asn1::BitString<'a>, } #[pyo3::prelude::pyfunction] -fn parse_spki_for_data(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult { - let result = asn1::parse::<_, PyAsn1Error, _>(data, |p| { - p.read_element::()? - .parse::<_, PyAsn1Error, _>(|p| { - // AlgorithmIdentifier - p.read_element::()? - .parse::<_, PyAsn1Error, _>(|p| { - p.read_element::()?; - if !p.is_empty() { - p.read_element::()?; - } - Ok(()) - })?; - - let pubkey_data = p.read_element::()?; - if pubkey_data.padding_bits() != 0 { - return Err(pyo3::exceptions::PyValueError::new_err( - "Invalid public key encoding", - ) - .into()); - } - Ok(pubkey_data.as_bytes()) - }) - })?; - - Ok(pyo3::types::PyBytes::new(py, result).to_object(py)) +fn parse_spki_for_data(py: pyo3::Python<'_>, data: &[u8]) -> Result { + let spki = asn1::parse_single::(data)?; + if spki.data.padding_bits() != 0 { + return Err(pyo3::exceptions::PyValueError::new_err("Invalid public key encoding").into()); + } + + Ok(pyo3::types::PyBytes::new(py, spki.data.as_bytes()).to_object(py)) } lazy_static::lazy_static! { @@ -153,6 +132,12 @@ fn parse_ocsp_req_extension( } } +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +struct DssSignature<'a> { + r: asn1::BigUint<'a>, + s: asn1::BigUint<'a>, +} + fn big_asn1_uint_to_py<'p>( py: pyo3::Python<'p>, v: asn1::BigUint, @@ -162,16 +147,14 @@ fn big_asn1_uint_to_py<'p>( } #[pyo3::prelude::pyfunction] -fn decode_dss_signature(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult { - let (r, s) = asn1::parse::<_, PyAsn1Error, _>(data, |p| { - p.read_element::()?.parse(|p| { - let r = p.read_element::()?; - let s = p.read_element::()?; - Ok((r, s)) - }) - })?; - - Ok((big_asn1_uint_to_py(py, r)?, big_asn1_uint_to_py(py, s)?).to_object(py)) +fn decode_dss_signature(py: pyo3::Python<'_>, data: &[u8]) -> Result { + let sig = asn1::parse_single::(data)?; + + Ok(( + big_asn1_uint_to_py(py, sig.r)?, + big_asn1_uint_to_py(py, sig.s)?, + ) + .to_object(py)) } fn py_uint_to_big_endian_bytes<'p>( @@ -198,15 +181,11 @@ fn encode_dss_signature( r: &pyo3::types::PyLong, s: &pyo3::types::PyLong, ) -> pyo3::PyResult { - let r = asn1::BigUint::new(py_uint_to_big_endian_bytes(py, r)?).unwrap(); - let s = asn1::BigUint::new(py_uint_to_big_endian_bytes(py, s)?).unwrap(); - let result = asn1::write(|w| { - w.write_element_with_type::(&|w| { - w.write_element(r); - w.write_element(s); - }); - }); - + let sig = DssSignature { + r: asn1::BigUint::new(py_uint_to_big_endian_bytes(py, r)?).unwrap(), + s: asn1::BigUint::new(py_uint_to_big_endian_bytes(py, s)?).unwrap(), + }; + let result = asn1::write_single(&sig); Ok(pyo3::types::PyBytes::new(py, &result).to_object(py)) } @@ -222,79 +201,68 @@ struct TestCertificate { subject_value_tags: Vec, } -fn parse_name_value_tags(p: &mut asn1::Parser) -> asn1::ParseResult> { +#[derive(asn1::Asn1Read)] +struct Asn1Certificate<'a> { + tbs_cert: TbsCertificate<'a>, + _signature_alg: asn1::Sequence<'a>, + _signature: asn1::BitString<'a>, +} + +#[derive(asn1::Asn1Read)] +struct TbsCertificate<'a> { + #[explicit(0)] + _version: Option, + _serial: asn1::BigUint<'a>, + _signature_alg: asn1::Sequence<'a>, + + issuer: Name<'a>, + validity: Validity<'a>, + subject: Name<'a>, + + _spki: asn1::Sequence<'a>, + #[implicit(1)] + _issuer_unique_id: Option>, + #[implicit(2)] + _subject_unique_id: Option>, + #[explicit(3)] + _extensions: Option>, +} + +type Name<'a> = asn1::SequenceOf<'a, asn1::SetOf<'a, AttributeTypeValue<'a>>>; + +#[derive(asn1::Asn1Read)] +struct AttributeTypeValue<'a> { + _type: asn1::ObjectIdentifier<'a>, + value: asn1::Tlv<'a>, +} + +#[derive(asn1::Asn1Read)] +struct Validity<'a> { + not_before: asn1::Tlv<'a>, + not_after: asn1::Tlv<'a>, +} + +fn parse_name_value_tags(rdns: &mut Name<'_>) -> Result, PyAsn1Error> { let mut tags = vec![]; - for rdn in p.read_element::>>()? { + for rdn in rdns { let mut attributes = rdn?.collect::>>()?; assert_eq!(attributes.len(), 1); - let tag = attributes - .pop() - .unwrap() - .parse::<_, asn1::ParseError, _>(|p| { - p.read_element::()?; - let tlv = p.read_element::()?; - Ok(tlv.tag()) - })?; - tags.push(tag); + tags.push(attributes.pop().unwrap().value.tag()); } Ok(tags) } #[pyo3::prelude::pyfunction] -fn test_parse_certificate(data: &[u8]) -> pyo3::PyResult { - let result = asn1::parse::<_, PyAsn1Error, _>(data, |p| { - // Outer SEQUENCE - p.read_element::()?.parse(|p| { - // TBS certificate - let result = p - .read_element::()? - .parse::<_, PyAsn1Error, _>(|p| { - // Version - p.read_optional_explicit_element::(0)?; - // Serial number - p.read_element::()?; - // Inner signature algorithm - p.read_element::()?; - - // Issuer - let issuer_value_tags = parse_name_value_tags(p)?; - // Validity - let (not_before_tag, not_after_tag) = p - .read_element::()? - .parse::<_, asn1::ParseError, _>(|p| { - let not_before_tag = p.read_element::()?.tag(); - let not_after_tag = p.read_element::()?.tag(); - Ok((not_before_tag, not_after_tag)) - })?; - // Subject - let subject_value_tags = parse_name_value_tags(p)?; - - // Subject public key info - p.read_element::()?; - // Issuer unique ID - never used in the real world - p.read_optional_implicit_element::(1)?; - // Subject unique ID - never used in the real world - p.read_optional_implicit_element::(2)?; - // Extensions - p.read_optional_explicit_element::(3)?; - - Ok(TestCertificate { - not_before_tag, - not_after_tag, - issuer_value_tags, - subject_value_tags, - }) - })?; - // Outer signature algorithm - p.read_element::()?; - // Signature - p.read_element::()?; - Ok(result) - }) - })?; - - Ok(result) +fn test_parse_certificate(data: &[u8]) -> Result { + let mut asn1_cert = asn1::parse_single::(data)?; + + Ok(TestCertificate { + not_before_tag: asn1_cert.tbs_cert.validity.not_before.tag(), + not_after_tag: asn1_cert.tbs_cert.validity.not_after.tag(), + issuer_value_tags: parse_name_value_tags(&mut asn1_cert.tbs_cert.issuer)?, + subject_value_tags: parse_name_value_tags(&mut asn1_cert.tbs_cert.subject)?, + }) } pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelude::PyModule> { From 70a8d6e8999c1d4327faac83bbadca418093a8f6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 May 2021 08:18:20 -0400 Subject: [PATCH 0160/1456] Bump syn from 1.0.71 to 1.0.72 in /src/rust (#6033) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.71 to 1.0.72. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.71...1.0.72) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 7347fda5d102..0df83d8f778f 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -305,9 +305,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad184cc9470f9117b2ac6817bfe297307418819ba40552f9b3846f05c33d5373" +checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" dependencies = [ "proc-macro2", "quote", From 46b3be6fd7687ce7d0d01eaad1d16e1f644d16a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 May 2021 07:52:18 -0400 Subject: [PATCH 0161/1456] Bump redox_syscall from 0.2.7 to 0.2.8 in /src/rust (#6036) Bumps redox_syscall from 0.2.7 to 0.2.8. Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 0df83d8f778f..2a82b0aeae43 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -284,9 +284,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85dd92e586f7355c633911e11f77f3d12f04b1b1bd76a198bd34ae3af8341ef2" +checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" dependencies = [ "bitflags", ] From bbaeaccea48c731ad0067f6d3d85bd7523dc7aa4 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 6 May 2021 09:18:44 -0400 Subject: [PATCH 0162/1456] bump to latest openssl3 alpha (#6037) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c0cbaa9234e..5b41b39b3a8b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0-alpha15"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0-alpha16"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "2.9.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.1.5"}} From 79416cdfe707592033de633b3e69aa8624bf4534 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 7 May 2021 00:20:31 -0500 Subject: [PATCH 0163/1456] test against 1.1.1k on our 1.1.1 jobs (#6038) --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5b41b39b3a8b..43447c4e08dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,9 +21,9 @@ jobs: - {VERSION: "pypy-3.6", TOXENV: "pypy3-nocoverage", COVERAGE: "false"} - {VERSION: "pypy-3.7", TOXENV: "pypy3-nocoverage", COVERAGE: "false"} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.0l"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} - - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k"}} + - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0-alpha16"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "2.9.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} From b1416562fb9c6d1dbf527d7dbe1a8a47c8fd0955 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 7 May 2021 09:41:05 -0400 Subject: [PATCH 0164/1456] revert stylistic change now that rust coverage handles it (#6039) this was written this way to work around https://github.com/rust-lang/rust/issues/84180, which is fixed --- src/rust/src/asn1.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 683b4a09fbee..93a6899c5fd5 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -51,8 +51,9 @@ fn encode_tls_feature(py: pyo3::Python<'_>, ext: &pyo3::PyAny) -> pyo3::PyResult #[pyo3::prelude::pyfunction] fn parse_tls_feature(py: pyo3::Python<'_>, data: &[u8]) -> Result { - let x509_mod = py.import("cryptography.x509.extensions")?; - let tls_feature_type_to_enum = x509_mod.getattr("_TLS_FEATURE_TYPE_TO_ENUM")?; + let tls_feature_type_to_enum = py + .import("cryptography.x509.extensions")? + .getattr("_TLS_FEATURE_TYPE_TO_ENUM")?; let features = pyo3::types::PyList::empty(py); for el in asn1::parse_single::>(data)? { From 920574069ab74de9aa1b35c9ece2a1ed4a9a178f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 9 May 2021 20:56:07 -0400 Subject: [PATCH 0165/1456] Bump asn1 from 0.4.1 to 0.4.2 in /src/rust (#6041) Bumps [asn1](https://github.com/alex/rust-asn1) from 0.4.1 to 0.4.2. - [Release notes](https://github.com/alex/rust-asn1/releases) - [Commits](https://github.com/alex/rust-asn1/compare/0.4.1...0.4.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 8 ++++---- src/rust/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 2a82b0aeae43..a27a949e53d3 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "asn1" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bdcc33cd1ec0ebfee9cc2d1f6497454f984c1f5c6550ad27af4b7bd7731442" +checksum = "150eef712394a4e814c83771b4027c5b4e9f9cb8f5ed30e8556c8e7bdeca5864" dependencies = [ "asn1_derive", "chrono", @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "asn1_derive" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce75fd5d9c4402a45fdec13c4701db332b4dfd307a3220494d6888c86edfff4b" +checksum = "511fd42f2524a4771b3d51149b9af8c196e6ab479795ab7ef6d743f5696fd141" dependencies = [ "proc-macro2", "quote", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 3c2e79b8f85c..38e21e57dba8 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] lazy_static = "1" pyo3 = { version = "0.13.1" } -asn1 = { version = "0.4.1", default-features = false, features = ["derive"] } +asn1 = { version = "0.4.2", default-features = false, features = ["derive"] } [features] extension-module = ["pyo3/extension-module"] From bdc0389d3bafcd796c5f2d3dd3b483cd07e851c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 May 2021 08:17:35 -0400 Subject: [PATCH 0166/1456] Bump dessant/lock-threads from 2 to 2.0.3 (#6044) Bumps [dessant/lock-threads](https://github.com/dessant/lock-threads) from 2 to 2.0.3. - [Release notes](https://github.com/dessant/lock-threads/releases) - [Changelog](https://github.com/dessant/lock-threads/blob/master/CHANGELOG.md) - [Commits](https://github.com/dessant/lock-threads/compare/v2...v2.0.3) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/lock.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index 5f55eb2cec49..cc4bc369a99f 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -11,7 +11,7 @@ jobs: lock: runs-on: ubuntu-latest steps: - - uses: dessant/lock-threads@v2 + - uses: dessant/lock-threads@v2.0.3 with: github-token: ${{ secrets.GITHUB_TOKEN }} issue-lock-inactive-days: 90 From 5c609881e063f1cc68dda3fa9b7cd114e181bbcd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 May 2021 08:20:27 -0400 Subject: [PATCH 0167/1456] Bump actions/checkout from 2 to 2.3.4 (#6047) Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 2.3.4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v2.3.4) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 16 ++++++++-------- .github/workflows/wheel-builder.yml | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 43447c4e08dc..74ef2e1b22cc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2.3.4 with: persist-credentials: false - uses: actions/cache@v2.1.5 @@ -121,7 +121,7 @@ jobs: name: "${{ matrix.IMAGE.TOXENV }} on ${{ matrix.IMAGE.IMAGE }}" timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2.3.4 with: persist-credentials: false - uses: actions/cache@v2.1.5 @@ -161,7 +161,7 @@ jobs: name: "${{ matrix.PYTHON.TOXENV }} with Rust ${{ matrix.RUST }}" timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2.3.4 with: persist-credentials: false - uses: actions/cache@v2.1.5 @@ -199,7 +199,7 @@ jobs: name: "Rust Coverage" timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2.3.4 with: persist-credentials: false - uses: actions/cache@v2.1.5 @@ -265,7 +265,7 @@ jobs: name: "${{ matrix.PYTHON.TOXENV }} on macOS" timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2.3.4 with: persist-credentials: false - uses: actions/cache@v2.1.5 @@ -327,7 +327,7 @@ jobs: name: "${{ matrix.PYTHON.TOXENV }} on ${{ matrix.WINDOWS.WINDOWS }} (part ${{ matrix.JOB_NUMBER }})" timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2.3.4 with: persist-credentials: false - name: Setup python @@ -392,7 +392,7 @@ jobs: name: "Downstream tests for ${{ matrix.DOWNSTREAM }}" timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2.3.4 with: persist-credentials: false - uses: actions/cache@v2.1.5 @@ -427,7 +427,7 @@ jobs: name: "linkcheck" timeout-minutes: 20 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2.3.4 with: persist-credentials: false - name: Setup python diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 2b165041fa0b..cba2e01485de 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -67,7 +67,7 @@ jobs: BIN_PATH: '/Library/Frameworks/Python.framework/Versions/3.8/bin/python3' name: "${{ matrix.PYTHON.VERSION }} ABI ${{ matrix.PYTHON.ABI_VERSION }} macOS" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2.3.4 - run: | curl "$PYTHON_DOWNLOAD_URL" -o python.pkg sudo installer -pkg python.pkg -target / @@ -120,7 +120,7 @@ jobs: - {VERSION: "3.8", MSVC_VERSION: "2019", "ABI_VERSION": "cp36"} name: "${{ matrix.PYTHON.VERSION }} ${{ matrix.WINDOWS.WINDOWS }} ${{ matrix.PYTHON.ABI_VERSION }}" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v2.3.4 - name: Setup python uses: actions/setup-python@v2.2.2 with: From faaa077c9f4beba71746a6f62d0d2b5434019a89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 May 2021 08:25:52 -0400 Subject: [PATCH 0168/1456] Bump actions-rs/toolchain from 1 to 1.0.7 (#6043) Bumps [actions-rs/toolchain](https://github.com/actions-rs/toolchain) from 1 to 1.0.7. - [Release notes](https://github.com/actions-rs/toolchain/releases) - [Changelog](https://github.com/actions-rs/toolchain/blob/master/CHANGELOG.md) - [Commits](https://github.com/actions-rs/toolchain/compare/v1...v1.0.7) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 14 +++++++------- .github/workflows/wheel-builder.yml | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 74ef2e1b22cc..4909b2c96105 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,7 +50,7 @@ jobs: uses: actions/setup-python@v2.2.2 with: python-version: ${{ matrix.PYTHON.VERSION }} - - uses: actions-rs/toolchain@v1 + - uses: actions-rs/toolchain@v1.0.7 with: profile: minimal toolchain: ${{ matrix.RUST }} @@ -176,7 +176,7 @@ jobs: uses: actions/setup-python@v2.2.2 with: python-version: ${{ matrix.PYTHON.VERSION }} - - uses: actions-rs/toolchain@v1 + - uses: actions-rs/toolchain@v1.0.7 with: profile: minimal toolchain: ${{ matrix.RUST }} @@ -214,7 +214,7 @@ jobs: uses: actions/setup-python@v2.2.2 with: python-version: 3.9 - - uses: actions-rs/toolchain@v1 + - uses: actions-rs/toolchain@v1.0.7 with: profile: minimal toolchain: nightly @@ -280,7 +280,7 @@ jobs: uses: actions/setup-python@v2.2.2 with: python-version: ${{ matrix.PYTHON.VERSION }} - - uses: actions-rs/toolchain@v1 + - uses: actions-rs/toolchain@v1.0.7 with: profile: minimal toolchain: ${{ matrix.RUST }} @@ -344,7 +344,7 @@ jobs: src/rust/target/ key: ${{ runner.os }}-${{ matrix.WINDOWS.ARCH }}-${{ steps.setup-python.outputs.python-version }}-cargo-${{ hashFiles('**/Cargo.lock') }} - - uses: actions-rs/toolchain@v1 + - uses: actions-rs/toolchain@v1.0.7 with: profile: minimal toolchain: ${{ matrix.RUST }} @@ -407,7 +407,7 @@ jobs: uses: actions/setup-python@v2.2.2 with: python-version: ${{ matrix.PYTHON }} - - uses: actions-rs/toolchain@v1 + - uses: actions-rs/toolchain@v1.0.7 with: profile: minimal toolchain: ${{ matrix.RUST }} @@ -434,7 +434,7 @@ jobs: uses: actions/setup-python@v2.2.2 with: python-version: 3.9 - - uses: actions-rs/toolchain@v1 + - uses: actions-rs/toolchain@v1.0.7 with: profile: minimal toolchain: stable diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index cba2e01485de..160ba8f0e6ca 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -79,7 +79,7 @@ jobs: ${{ matrix.PYTHON.BIN_PATH }} .github/workflows/download_openssl.py macos openssl-macos-x86-64 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: actions-rs/toolchain@v1 + - uses: actions-rs/toolchain@v1.0.7 with: profile: minimal toolchain: stable @@ -126,7 +126,7 @@ jobs: with: python-version: ${{ matrix.PYTHON.VERSION }} architecture: ${{ matrix.WINDOWS.ARCH }} - - uses: actions-rs/toolchain@v1 + - uses: actions-rs/toolchain@v1.0.7 with: profile: minimal toolchain: stable From 44d042c27b7c22541f0ee2e9fe1174fa9154e5ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 May 2021 08:49:20 -0400 Subject: [PATCH 0169/1456] Bump actions-rs/install from 0.1 to 0.1.2 (#6045) Bumps [actions-rs/install](https://github.com/actions-rs/install) from 0.1 to 0.1.2. - [Release notes](https://github.com/actions-rs/install/releases) - [Changelog](https://github.com/actions-rs/install/blob/master/CHANGELOG.md) - [Commits](https://github.com/actions-rs/install/compare/v0.1...v0.1.2) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4909b2c96105..9a9886a055a6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -221,7 +221,7 @@ jobs: override: true default: true components: llvm-tools-preview - - uses: actions-rs/install@v0.1 + - uses: actions-rs/install@v0.1.2 with: crate: cargo-binutils version: latest From 1b922ed1dee0cd7e165a868639ce6d0869c8b2f5 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Wed, 12 May 2021 14:54:23 +0200 Subject: [PATCH 0170/1456] Use well-defined enum representation (#6042) Python 3.10 changed enum's object and string representation. PyCA cryptography now uses a custom subclass of enum.Enum() will well-defined __repr__ and __str__ from Python 3.9. Related: https://bugs.python.org/issue40066 Fixes: https://github.com/pyca/cryptography/issues/5995 Signed-off-by: Christian Heimes --- .github/workflows/ci.yml | 1 + src/cryptography/exceptions.py | 4 ++-- src/cryptography/hazmat/primitives/_serialization.py | 11 ++++++----- src/cryptography/hazmat/primitives/kdf/kbkdf.py | 5 ++--- .../hazmat/primitives/serialization/pkcs7.py | 4 ++-- src/cryptography/utils.py | 11 +++++++++++ src/cryptography/x509/base.py | 4 ++-- src/cryptography/x509/certificate_transparency.py | 7 ++++--- src/cryptography/x509/extensions.py | 6 +++--- src/cryptography/x509/name.py | 4 ++-- src/cryptography/x509/ocsp.py | 8 ++++---- tests/test_cryptography_utils.py | 11 +++++++++++ 12 files changed, 50 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9a9886a055a6..49b41971ab5b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,6 +30,7 @@ jobs: - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.1.5"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.2.5"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.3.2"}} + - {VERSION: "3.10-dev", TOXENV: "py310"} RUST: - stable name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" diff --git a/src/cryptography/exceptions.py b/src/cryptography/exceptions.py index f5860590571b..3bd98d8252ad 100644 --- a/src/cryptography/exceptions.py +++ b/src/cryptography/exceptions.py @@ -3,10 +3,10 @@ # for complete details. -from enum import Enum +from cryptography import utils -class _Reasons(Enum): +class _Reasons(utils.Enum): BACKEND_MISSING_INTERFACE = 0 UNSUPPORTED_HASH = 1 UNSUPPORTED_CIPHER = 2 diff --git a/src/cryptography/hazmat/primitives/_serialization.py b/src/cryptography/hazmat/primitives/_serialization.py index 96a5ed9b75d9..160a6b89c089 100644 --- a/src/cryptography/hazmat/primitives/_serialization.py +++ b/src/cryptography/hazmat/primitives/_serialization.py @@ -3,13 +3,14 @@ # for complete details. import abc -from enum import Enum + +from cryptography import utils # This exists to break an import cycle. These classes are normally accessible # from the serialization module. -class Encoding(Enum): +class Encoding(utils.Enum): PEM = "PEM" DER = "DER" OpenSSH = "OpenSSH" @@ -18,14 +19,14 @@ class Encoding(Enum): SMIME = "S/MIME" -class PrivateFormat(Enum): +class PrivateFormat(utils.Enum): PKCS8 = "PKCS8" TraditionalOpenSSL = "TraditionalOpenSSL" Raw = "Raw" OpenSSH = "OpenSSH" -class PublicFormat(Enum): +class PublicFormat(utils.Enum): SubjectPublicKeyInfo = "X.509 subjectPublicKeyInfo with PKCS#1" PKCS1 = "Raw PKCS#1" OpenSSH = "OpenSSH" @@ -34,7 +35,7 @@ class PublicFormat(Enum): UncompressedPoint = "X9.62 Uncompressed Point" -class ParameterFormat(Enum): +class ParameterFormat(utils.Enum): PKCS3 = "PKCS3" diff --git a/src/cryptography/hazmat/primitives/kdf/kbkdf.py b/src/cryptography/hazmat/primitives/kdf/kbkdf.py index eee2200be4bf..1d106d1e5dec 100644 --- a/src/cryptography/hazmat/primitives/kdf/kbkdf.py +++ b/src/cryptography/hazmat/primitives/kdf/kbkdf.py @@ -4,7 +4,6 @@ import typing -from enum import Enum from cryptography import utils from cryptography.exceptions import ( @@ -19,11 +18,11 @@ from cryptography.hazmat.primitives.kdf import KeyDerivationFunction -class Mode(Enum): +class Mode(utils.Enum): CounterMode = "ctr" -class CounterLocation(Enum): +class CounterLocation(utils.Enum): BeforeFixed = "before_fixed" AfterFixed = "after_fixed" diff --git a/src/cryptography/hazmat/primitives/serialization/pkcs7.py b/src/cryptography/hazmat/primitives/serialization/pkcs7.py index c6b2eec21092..79e9b64da800 100644 --- a/src/cryptography/hazmat/primitives/serialization/pkcs7.py +++ b/src/cryptography/hazmat/primitives/serialization/pkcs7.py @@ -3,8 +3,8 @@ # for complete details. import typing -from enum import Enum +from cryptography import utils from cryptography import x509 from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import Backend @@ -36,7 +36,7 @@ def load_der_pkcs7_certificates(data: bytes) -> typing.List[x509.Certificate]: ] -class PKCS7Options(Enum): +class PKCS7Options(utils.Enum): Text = "Add text/plain MIME type" Binary = "Don't translate input data into canonical MIME format" DetachedSignature = "Don't embed data in the PKCS7 structure" diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index a8fd7d01a7c9..f07d5fdad249 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -4,6 +4,7 @@ import abc +import enum import inspect import sys import typing @@ -152,3 +153,13 @@ def inner(instance): "int_from_bytes is deprecated, use int.from_bytes instead", DeprecatedIn34, ) + + +# Python 3.10 changed representation of enums. We use well-defined object +# representation and string representation from Python 3.9. +class Enum(enum.Enum): + def __repr__(self): + return f"<{self.__class__.__name__}.{self._name_}: {self._value_!r}>" + + def __str__(self): + return f"{self.__class__.__name__}.{self._name_}" diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index e97c32cb9167..4e8b4a844a41 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -7,8 +7,8 @@ import datetime import os import typing -from enum import Enum +from cryptography import utils from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import Backend from cryptography.hazmat.primitives import hashes, serialization @@ -71,7 +71,7 @@ def _convert_to_naive_utc_time(time: datetime.datetime) -> datetime.datetime: return time -class Version(Enum): +class Version(utils.Enum): v1 = 0 v3 = 2 diff --git a/src/cryptography/x509/certificate_transparency.py b/src/cryptography/x509/certificate_transparency.py index d51bee92effc..d80f051a68ae 100644 --- a/src/cryptography/x509/certificate_transparency.py +++ b/src/cryptography/x509/certificate_transparency.py @@ -5,15 +5,16 @@ import abc import datetime -from enum import Enum +from cryptography import utils -class LogEntryType(Enum): + +class LogEntryType(utils.Enum): X509_CERTIFICATE = 0 PRE_CERTIFICATE = 1 -class Version(Enum): +class Version(utils.Enum): v1 = 0 diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 35ed776b7932..58e7ea7f5a5d 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -8,8 +8,8 @@ import hashlib import ipaddress import typing -from enum import Enum +from cryptography import utils from cryptography.hazmat.bindings._rust import asn1 from cryptography.hazmat.primitives import constant_time, serialization from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey @@ -671,7 +671,7 @@ def crl_issuer(self) -> typing.Optional[typing.List[GeneralName]]: return self._crl_issuer -class ReasonFlags(Enum): +class ReasonFlags(utils.Enum): unspecified = "unspecified" key_compromise = "keyCompromise" ca_compromise = "cACompromise" @@ -1035,7 +1035,7 @@ def __hash__(self) -> int: return hash(tuple(self._features)) -class TLSFeatureType(Enum): +class TLSFeatureType(utils.Enum): # status_request is defined in RFC 6066 and is used for what is commonly # called OCSP Must-Staple when present in the TLS Feature extension in an # X.509 certificate. diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py index e0ba6674d5b1..d1a3e3331fb1 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -3,14 +3,14 @@ # for complete details. import typing -from enum import Enum +from cryptography import utils from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import Backend from cryptography.x509.oid import NameOID, ObjectIdentifier -class _ASN1Type(Enum): +class _ASN1Type(utils.Enum): UTF8String = 12 NumericString = 18 PrintableString = 19 diff --git a/src/cryptography/x509/ocsp.py b/src/cryptography/x509/ocsp.py index f35e25f8a6d1..7f8711b79d2d 100644 --- a/src/cryptography/x509/ocsp.py +++ b/src/cryptography/x509/ocsp.py @@ -6,8 +6,8 @@ import abc import datetime import typing -from enum import Enum +from cryptography import utils from cryptography import x509 from cryptography.hazmat.primitives import hashes, serialization from cryptography.x509.base import ( @@ -27,12 +27,12 @@ } -class OCSPResponderEncoding(Enum): +class OCSPResponderEncoding(utils.Enum): HASH = "By Hash" NAME = "By Name" -class OCSPResponseStatus(Enum): +class OCSPResponseStatus(utils.Enum): SUCCESSFUL = 0 MALFORMED_REQUEST = 1 INTERNAL_ERROR = 2 @@ -58,7 +58,7 @@ def _verify_algorithm(algorithm): ) -class OCSPCertStatus(Enum): +class OCSPCertStatus(utils.Enum): GOOD = 0 REVOKED = 1 UNKNOWN = 2 diff --git a/tests/test_cryptography_utils.py b/tests/test_cryptography_utils.py index 6b795e0c683a..803997ac06ea 100644 --- a/tests/test_cryptography_utils.py +++ b/tests/test_cryptography_utils.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +import enum import typing import pytest @@ -51,3 +52,13 @@ def t(self): assert len(accesses) == 1 assert t.t == 14 assert len(accesses) == 1 + + +def test_enum(): + class TestEnum(utils.Enum): + value = "something" + + assert issubclass(TestEnum, enum.Enum) + assert isinstance(TestEnum.value, enum.Enum) + assert repr(TestEnum.value) == "" + assert str(TestEnum.value) == "TestEnum.value" From 3465cb88245022afe68602f3610e8c553660521d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 18 May 2021 09:05:56 -0400 Subject: [PATCH 0171/1456] libressl 3.3.3 (#6052) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 49b41971ab5b..5b71f13294f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.1.5"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.2.5"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.3.2"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.3.3"}} - {VERSION: "3.10-dev", TOXENV: "py310"} RUST: - stable From f19b0f41f552b606e8860a80f1184b733212c733 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 19 May 2021 15:56:36 -0400 Subject: [PATCH 0172/1456] Point folks towards irc.libera.chat (#6054) * Point folks towards irc.libera.chat * Update community.rst --- docs/community.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/community.rst b/docs/community.rst index da6376531ab3..7feb476e61be 100644 --- a/docs/community.rst +++ b/docs/community.rst @@ -7,7 +7,7 @@ You can find ``cryptography`` all over the web: * `Source code`_ * `Issue tracker`_ * `Documentation`_ -* IRC: ``#cryptography-dev`` on ``irc.freenode.net`` +* IRC: ``#pyca`` on ``irc.libera.chat`` Wherever we interact, we adhere to the `Python Community Code of Conduct`_. From 996b6934d544e036ec8fbdb57785c727bbf5b879 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 19 May 2021 16:26:15 -0400 Subject: [PATCH 0173/1456] Update IRC in the README as well (#6055) --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index bb5f6f300666..1a4e65a0fc9d 100644 --- a/README.rst +++ b/README.rst @@ -54,7 +54,7 @@ If you run into bugs, you can file them in our `issue tracker`_. We maintain a `cryptography-dev`_ mailing list for development discussion. -You can also join ``#cryptography-dev`` on Freenode to ask questions or get +You can also join ``#pyca`` on ``irc.libera.chat`` to ask questions or get involved. Security From 84beab1921a3734e9f9e27b051eccdc2858354c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 May 2021 07:36:44 -0400 Subject: [PATCH 0174/1456] Bump proc-macro2 from 1.0.26 to 1.0.27 in /src/rust (#6058) Bumps [proc-macro2](https://github.com/alexcrichton/proc-macro2) from 1.0.26 to 1.0.27. - [Release notes](https://github.com/alexcrichton/proc-macro2/releases) - [Commits](https://github.com/alexcrichton/proc-macro2/compare/1.0.26...1.0.27) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index a27a949e53d3..0732f7cea8f9 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -227,9 +227,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" dependencies = [ "unicode-xid", ] From ec05c55c206b2839903732b19bee780092f0b497 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 20 May 2021 10:23:54 -0400 Subject: [PATCH 0175/1456] Bump to latest openssl 3 alpha (#6060) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5b71f13294f3..94d3cb20c82f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k"}} - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0-alpha16"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0-alpha17"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "2.9.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.1.5"}} From 596d30d04083e69446ebe1a94febea29e8c5029f Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 23 May 2021 13:56:55 -0400 Subject: [PATCH 0176/1456] Use Rust extension parser for OCSP basicresp (#6062) --- src/cryptography/hazmat/backends/openssl/backend.py | 4 ++-- .../hazmat/backends/openssl/decode_asn1.py | 11 ----------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 29f353db3292..ce9b3dc63e82 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -21,7 +21,6 @@ _CRL_EXTENSION_HANDLERS, _EXTENSION_HANDLERS_BASE, _EXTENSION_HANDLERS_SCT, - _OCSP_BASICRESP_EXTENSION_HANDLERS, _OCSP_SINGLERESP_EXTENSION_HANDLERS_SCT, _REVOKED_EXTENSION_HANDLERS, _X509ExtensionParser, @@ -431,7 +430,8 @@ def _register_x509_ext_parsers(self): self, ext_count=self._lib.OCSP_BASICRESP_get_ext_count, get_ext=self._lib.OCSP_BASICRESP_get_ext, - handlers=_OCSP_BASICRESP_EXTENSION_HANDLERS, + # OCSP basic resp has the same extensions as req. + rust_callback=asn1.parse_ocsp_req_extension, ) self._ocsp_singleresp_ext_parser = _X509ExtensionParser( self, diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 9a85e9464dce..eb384263d6de 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -14,7 +14,6 @@ CRLEntryExtensionOID, CertificatePoliciesOID, ExtensionOID, - OCSPExtensionOID, ) @@ -819,12 +818,6 @@ def _parse_asn1_generalized_time(backend, generalized_time): 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_BASE = { ExtensionOID.BASIC_CONSTRAINTS: _decode_basic_constraints, ExtensionOID.SUBJECT_KEY_IDENTIFIER: _decode_subject_key_identifier, @@ -871,10 +864,6 @@ def _decode_nonce(backend, nonce): ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, } -_OCSP_BASICRESP_EXTENSION_HANDLERS = { - OCSPExtensionOID.NONCE: _decode_nonce, -} - _OCSP_SINGLERESP_EXTENSION_HANDLERS_SCT = { ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS: ( _decode_signed_certificate_timestamps From fa2f68dd35da79a52ef05713bfb5f0ed1d380c8a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 24 May 2021 00:53:33 -0400 Subject: [PATCH 0177/1456] Added a test vector for OCSP with an unknown extension (#6063) --- docs/development/test-vectors.rst | 2 ++ tests/x509/test_ocsp.py | 13 +++++++++++++ .../x509/ocsp/resp-unknown-extension.der | Bin 0 -> 1894 bytes 3 files changed, 15 insertions(+) create mode 100644 vectors/cryptography_vectors/x509/ocsp/resp-unknown-extension.der diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index e8e466d4a999..b1ae00c08c59 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -540,6 +540,8 @@ X.509 OCSP Test Vectors ``CT Certificate SCTs`` single extension, from the SwissSign OCSP responder. * ``x509/ocsp/ocsp-army.deps.mil-resp.der`` - An OCSP response containing multiple ``SINGLERESP`` values. +* ``x509/ocsp/resp-unknown-extension.der`` - An OCSP response containing an + extension with an unknown OID. Custom X.509 OCSP Test Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/x509/test_ocsp.py b/tests/x509/test_ocsp.py index 6b839b3d048f..9772c9bf3a7d 100644 --- a/tests/x509/test_ocsp.py +++ b/tests/x509/test_ocsp.py @@ -1005,6 +1005,19 @@ def test_response_extensions(self): b'\x04\x105\x957\x9fa\x03\x83\x87\x89rW\x8f\xae\x99\xf7"' ) + def test_response_unknown_extension(self): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-unknown-extension.der"), + ocsp.load_der_ocsp_response, + ) + assert len(resp.extensions) == 1 + ext = resp.extensions[0] + assert ext.critical is False + assert ext.value == x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.3.6.1.5.5.7.48.1.2.200"), + 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"), diff --git a/vectors/cryptography_vectors/x509/ocsp/resp-unknown-extension.der b/vectors/cryptography_vectors/x509/ocsp/resp-unknown-extension.der new file mode 100644 index 0000000000000000000000000000000000000000..2d127d74ae39d6ed5595728d85f3ef8f06cdc705 GIT binary patch literal 1894 zcmXqLVo%~?WLVI|9&OOX9?r(8&Bn;e%5K2O$kN2_0TgmEXkxTlm~W74$Zf#M#vIDR zCd}mIYba?T4&rbL3j~(thb5+D7AyE<=4O_prWlGFh=QcJh57uQg98+TQi}`n^HNfa z47Ch2KoZQtif}z(6^^AP8Tmz-C6x-nndy0nC8b5F68uI6h86~v28M=~CKiU~Q3j2D z294bYzCbsyYV$EONwG4ph-9tfEnLZdF3Eg?T>D#}-e1!fv0q{l*(}t#b)~oI9#Mu5 z4KHt0w0{(?DPt1hknNr^Z_=-4ond#LX>}TLF5IJXd7&889y23zLnC7Y1H-5V%v_8t z7`87EgbNu%9kfu@K-oZ%jT;tTOpP8aLM#HNQ_bfmGB>w(7KQh(oB3VIfR~L^tIebB zJ1-+6H!A~k6C)!-Nali@Dl=KiJ^r6hW)MDl;dMOA)h!10hb(eupDnqye$T~?JGf33 zZ=WF;cIx)SN1~c@?(ZxxdhfV_*HvKMf}@AbbrQEl`t*FamtS+trkY>5tyPgZ=kBf+ zo%)|k{=ewdUG4HCbYf8Rfw)%F$lGpOPESh?mRRzu-eo1 ziBQ}t_RCA{@9EtTn(*x3Gj2}do1dO|9ZCID-?Z`Bs^Y^3J@#q_EqgGt<|6-xTbGZ< z-|yJ`QPfE;D2oCm9@N{-ma5pxP6X!KF zGc+_XHZ(P{FtCUc=QT0{a?K1)Oo7QSiq451nA1?w3nMta@G}6#xtKr+XK6%JfpMLu z_Y2RZp6s4s*2O!l!lZo?=g-V|R6KpTgY0tm(AW#?_YQnq;%IvN?+J(LW_z99tP0=8 zXUnjCU6J}8(;4|+ZFbdupQ;(ps3`8S*tR8$^(-S>#$ScT>untWTe_AlN_!|WJO9j~ zu2bIs`j?2_va?(Mx#COb_x;B&Z@JZJ*_ShQ!P&jpt5fb5HGD2jUU09XRaQAS{g!C1 zsg-(&+JmKA@AK}ubhy6tIm`BI7mH08=ecFOSoI!Q*EnS463L#r$L(kFhC>(5_Y zUCqSI$iTR`ajrq*EO1#QE6l=Vz+k|SD79Ewm{=LWMU$)oi+};20S_A&Fo&`*?u%e- z(lOuzCJ9-7M#ldvEX+*o4FzA6ik0T&wwBqK9(8pwkLm02VV#2T=cB?ht}1$-=G zEFz2(WSHl_ihk+P{`2uEHb#GS%YQ4;k}Pu*6C(r5dX)$F4hDbUAy*@+yeGcO_ogpr z;HmwsOl}p{Mwfb;84q}Vyz%^J%%fhNyB~DaUUHhfc~RZh-kR_yd&{4HKfb$r+)`9q z5x1V%Yhv15#bq72Mwiz-XLS>6J(3;0CU57|BW*{W)Ol7e(Q*scbzv@TOQ?FZ z@y+a9!@cGv=WYasoOZfdc`}t(Z&S1e|GmBLChCh1dz@MjwqNz|mzFRiF5x#@V@^)n zZFBwE1MXKR?ieg-cfVJ0w^dDG)AAqB_6g;gFhBGw;=H7AR@YVdz(Q-Wh<@cW_F0$z z%&)wB#`2%^$|r`l4Rh~4oV@O~i)y~sUFJWRwr1ShyUM_^CU5QmmEVPjrd&w7sL6kz z)qqVcN#y0z;{Q+LeX=AnKUIuA;=Ra8bw@7Mwzof)Um3zbEGps8rqFJB>gMh0Rpz&aZqB_ewQ_ICyI;?ouiWK{;4p&>I ze%fQ_EY~)#GbQyUTYMMKvbZu&-}*AA=#J`A-K(NToadi8a?5eP_e{KI9CPFMiN$^Z DXnWaY literal 0 HcmV?d00001 From f94ce1271516de7e3cc94b5da4bf81ca1b6064e4 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 24 May 2021 20:58:33 -0400 Subject: [PATCH 0178/1456] Added a test vector for duplicate extensions in OCSP requests (#6064) --- docs/development/test-vectors.rst | 6 ++++-- tests/x509/test_ocsp.py | 8 ++++++++ .../x509/ocsp/req-duplicate-ext.der | Bin 0 -> 155 bytes 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 vectors/cryptography_vectors/x509/ocsp/req-duplicate-ext.der diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index b1ae00c08c59..8799786031a6 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -540,8 +540,6 @@ X.509 OCSP Test Vectors ``CT Certificate SCTs`` single extension, from the SwissSign OCSP responder. * ``x509/ocsp/ocsp-army.deps.mil-resp.der`` - An OCSP response containing multiple ``SINGLERESP`` values. -* ``x509/ocsp/resp-unknown-extension.der`` - An OCSP response containing an - extension with an unknown OID. Custom X.509 OCSP Test Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -555,6 +553,10 @@ Custom X.509 OCSP Test Vectors extension. * ``x509/ocsp/req-ext-unknown-oid.der`` - An OCSP request containing an extension with an unknown OID. +* ``x509/ocsp/req-duplicate-ext.der`` - An OCSP request with duplicate + extensions. +* ``x509/ocsp/resp-unknown-extension.der`` - An OCSP response containing an + extension with an unknown OID. Custom PKCS12 Test Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/x509/test_ocsp.py b/tests/x509/test_ocsp.py index 9772c9bf3a7d..af05b83fa923 100644 --- a/tests/x509/test_ocsp.py +++ b/tests/x509/test_ocsp.py @@ -119,6 +119,14 @@ def test_load_request_with_unknown_extension(self): b"\x04\x10{\x80Z\x1d7&\xb8\xb8OH\xd2\xf8\xbf\xd7-\xfd", ) + def test_load_request_with_duplicate_extension(self): + req = _load_data( + os.path.join("x509", "ocsp", "req-duplicate-ext.der"), + ocsp.load_der_ocsp_request, + ) + with pytest.raises(x509.DuplicateExtension): + req.extensions + def test_load_request_two_requests(self): with pytest.raises(NotImplementedError): _load_data( diff --git a/vectors/cryptography_vectors/x509/ocsp/req-duplicate-ext.der b/vectors/cryptography_vectors/x509/ocsp/req-duplicate-ext.der new file mode 100644 index 0000000000000000000000000000000000000000..d92324dfe9b21713bb3dc80827b1e73111c6ce2a GIT binary patch literal 155 zcmXqLoMF&7)xg)l+rZO+lZ{oIkC{n|m4QV>Abwd@1IOI0>hn#{HFG<6%v*e%mqmoX zAyKBuF!8Fs#`9h`i!C}2kKKI4B*3^{?)Tleb(}#)+$#UFLo*h+7&sZovvF#(F|x9< f8!$4l2(buMH$=&rtL@m~?{VqJ{_DDb2`T^pwR Date: Mon, 24 May 2021 21:54:13 -0400 Subject: [PATCH 0179/1456] Retry in more cases (#6066) --- .github/workflows/download_openssl.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/download_openssl.py b/.github/workflows/download_openssl.py index 496e05385b0e..1c192cf2539b 100644 --- a/.github/workflows/download_openssl.py +++ b/.github/workflows/download_openssl.py @@ -12,9 +12,14 @@ def get_response(session, url, token): # Retry on non-502s for i in range(5): - response = session.get( - url, headers={"Authorization": "token " + token} - ) + try: + response = session.get( + url, headers={"Authorization": "token " + token} + ) + except requests.exceptions.ChunkedEncodingError as e: + print("Exception ({}) fetching {}, retrying".format(e, url)) + time.sleep(2) + continue if response.status_code != 200: print( "HTTP error ({}) fetching {}, retrying".format( From b937d25173b9b6bae6586d9298e91457786710c2 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 24 May 2021 21:55:41 -0400 Subject: [PATCH 0180/1456] Added a test vector for an OCSP response with an unknown hash algorithm (#6065) --- docs/development/test-vectors.rst | 2 ++ tests/x509/test_ocsp.py | 8 ++++++++ .../x509/ocsp/resp-unknown-hash-alg.der | Bin 0 -> 491 bytes 3 files changed, 10 insertions(+) create mode 100644 vectors/cryptography_vectors/x509/ocsp/resp-unknown-hash-alg.der diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 8799786031a6..edd2c609f430 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -557,6 +557,8 @@ Custom X.509 OCSP Test Vectors extensions. * ``x509/ocsp/resp-unknown-extension.der`` - An OCSP response containing an extension with an unknown OID. +* ``x509/ocsp/resp-unknown-hash-alg.der`` - AN OCSP response containing an + invalid hash algorithm OID. Custom PKCS12 Test Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/x509/test_ocsp.py b/tests/x509/test_ocsp.py index af05b83fa923..e1ea7590a33b 100644 --- a/tests/x509/test_ocsp.py +++ b/tests/x509/test_ocsp.py @@ -976,6 +976,14 @@ def test_load_invalid_signature_oid(self): with pytest.raises(UnsupportedAlgorithm): resp.signature_hash_algorithm + def test_unknown_hash_algorithm(self): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-unknown-hash-alg.der"), + ocsp.load_der_ocsp_response, + ) + with pytest.raises(UnsupportedAlgorithm): + resp.hash_algorithm + def test_load_responder_key_hash(self): resp = _load_data( os.path.join("x509", "ocsp", "resp-responder-key-hash.der"), diff --git a/vectors/cryptography_vectors/x509/ocsp/resp-unknown-hash-alg.der b/vectors/cryptography_vectors/x509/ocsp/resp-unknown-hash-alg.der new file mode 100644 index 0000000000000000000000000000000000000000..aad0cb5ad33e7ab268653e1bbeba7e5ffb6a4b4a GIT binary patch literal 491 zcmXqLVtmfU$grS^@qs}T;~h3mZ8k<$R(1nMMwTYVvp}Jf2928*iLr?AHzdk5875xU z*LdFRX0b)*;jx>KB>0UC3@r>S4Gay9O-zjpq6`|_3>upaybQS5*tGeWnWO|+8CXOF z;+Iu5aLnDRKHv0QGq-ccyv4_Pu^Y%Fz`tOToaiC$eX<#^`kxo1nJyGWSYlveXlQB@ zg%E(+x&WcZ!qC{j0OSx}HcqWJkGAi;jEvl@49rc8j11-_|Am;pe6CEt(JSVVRXE{- z-zLw{1t<@awVv(iD`qmEU6w?BXP^RV@C{NuSS`Ur0*`};3dzXZ-MzgNG3 z>rj+M2XE|E>obXS^`^~Qv+c(B`3Kni-W=0C)2@23FrqVKRe;Rx9}XX5!h4(UyirTd zT-B$j5*aS@=4G)*8^^)<%a-$c@;e=V;rWjBzt5dB^?dy=W#+^SO#BsYUlS!!c&PL1 xAeunKkp;kLY@SouiQZ5&&h($36f6 literal 0 HcmV?d00001 From 37103b3b65c5a41a7d4dd8cc00b09684f136c2d0 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Tue, 25 May 2021 13:16:36 -0500 Subject: [PATCH 0181/1456] Remove straddling jargon "text". (#6067) --- docs/glossary.rst | 4 ---- docs/hazmat/primitives/twofactor.rst | 8 ++++---- docs/x509/reference.rst | 25 ++++++++++++------------- src/cryptography/x509/name.py | 2 +- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/docs/glossary.rst b/docs/glossary.rst index 95b893c8fee6..b85a61091e38 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -61,10 +61,6 @@ Glossary aren't distinguishable without knowing the encryption key. This is considered a basic, necessary property for a working encryption system. - text - This type corresponds to ``unicode`` on Python 2 and ``str`` on Python - 3. This is equivalent to ``six.text_type``. - nonce A nonce is a **n**\ umber used **once**. Nonces are used in many cryptographic protocols. Generally, a nonce does not have to be secret diff --git a/docs/hazmat/primitives/twofactor.rst b/docs/hazmat/primitives/twofactor.rst index 1d2ab452ce0a..dcbc7bb76aec 100644 --- a/docs/hazmat/primitives/twofactor.rst +++ b/docs/hazmat/primitives/twofactor.rst @@ -91,11 +91,11 @@ codes (HMAC). :param account_name: The display name of account, such as ``'Alice Smith'`` or ``'alice@example.com'``. - :type account_name: :term:`text` + :type account_name: str :param issuer: The optional display name of issuer. This is typically the provider or service the user wants to access using the OTP token. - :type issuer: :term:`text` or `None` + :type issuer: ``str`` or ``None`` :param int counter: The current value of counter. :return: A URI string. @@ -212,11 +212,11 @@ similar to the following code. :param account_name: The display name of account, such as ``'Alice Smith'`` or ``'alice@example.com'``. - :type account_name: :term:`text` + :type account_name: str :param issuer: The optional display name of issuer. This is typically the provider or service the user wants to access using the OTP token. - :type issuer: :term:`text` or `None` + :type issuer: ``str`` or ``None`` :return: A URI string. Provisioning URI diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index 6c058f9f78d5..eb4d07b54508 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -1329,7 +1329,7 @@ X.509 CSR (Certificate Signing Request) Builder Object .. attribute:: value - :type: :term:`text` + :type: str The value of the attribute. @@ -1337,7 +1337,7 @@ X.509 CSR (Certificate Signing Request) Builder Object .. versionadded:: 35.0 - :type: :term:`text` + :type: str The :rfc:`4514` short attribute name (for example "CN"), or the OID dotted string if a short name is unavailable. @@ -1418,7 +1418,7 @@ General Name Classes .. attribute:: value - :type: :term:`text` + :type: str .. class:: DNSName(value) @@ -1437,11 +1437,11 @@ General Name Classes :raises ValueError: If the provided string is not an :term:`A-label`. - :type: :term:`text` + :type: str .. attribute:: value - :type: :term:`text` + :type: str .. class:: DirectoryName(value) @@ -1473,7 +1473,7 @@ General Name Classes .. attribute:: value - :type: :term:`text` + :type: str .. class:: IPAddress(value) @@ -2592,11 +2592,10 @@ These classes may be present within a :class:`CertificatePolicies` instance. :type: list - A list consisting of :term:`text` and/or :class:`UserNotice` objects. - If the value is text it is a pointer to the practice statement - published by the certificate authority. If it is a user notice it is - meant for display to the relying party when the certificate is - used. + A list consisting of ``str`` and/or :class:`UserNotice` objects. If the + value is ``str`` it is a pointer to the practice statement published by + the certificate authority. If it is a user notice it is meant for + display to the relying party when the certificate is used. .. class:: UserNotice(notice_reference, explicit_text) @@ -2618,7 +2617,7 @@ These classes may be present within a :class:`CertificatePolicies` instance. This field includes an arbitrary textual statement directly in the certificate. - :type: :term:`text` + :type: str .. class:: NoticeReference(organization, notice_numbers) @@ -2633,7 +2632,7 @@ These classes may be present within a :class:`CertificatePolicies` instance. .. attribute:: organization - :type: :term:`text` + :type: str .. attribute:: notice_numbers diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py index d1a3e3331fb1..b02fda9cfe67 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -83,7 +83,7 @@ def __init__( ) if not isinstance(value, str): - raise TypeError("value argument must be a text type.") + raise TypeError("value argument must be a str.") if ( oid == NameOID.COUNTRY_NAME From d119c40afcf576ce4e3b37f26fb6bc9248963fb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 May 2021 08:11:46 -0400 Subject: [PATCH 0182/1456] Bump libc from 0.2.94 to 0.2.95 in /src/rust (#6068) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.94 to 0.2.95. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.94...0.2.95) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 0732f7cea8f9..9352ad1899cd 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -143,9 +143,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.94" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" +checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" [[package]] name = "lock_api" From d8653ccf8e12bb216f08e1b6411e78ffb7353ba5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 May 2021 06:47:21 -0400 Subject: [PATCH 0183/1456] Bump actions/cache from 2.1.5 to 2.1.6 (#6070) Bumps [actions/cache](https://github.com/actions/cache) from 2.1.5 to 2.1.6. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v2.1.5...v2.1.6) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 94d3cb20c82f..748e7057834e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: - uses: actions/checkout@v2.3.4 with: persist-credentials: false - - uses: actions/cache@v2.1.5 + - uses: actions/cache@v2.1.6 with: path: | ~/.cargo/registry @@ -72,7 +72,7 @@ jobs: CONFIG_FLAGS: ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }} if: matrix.PYTHON.OPENSSL - name: Load cache - uses: actions/cache@v2.1.5 + uses: actions/cache@v2.1.6 id: ossl-cache with: path: ${{ github.workspace }}/osslcache @@ -125,7 +125,7 @@ jobs: - uses: actions/checkout@v2.3.4 with: persist-credentials: false - - uses: actions/cache@v2.1.5 + - uses: actions/cache@v2.1.6 with: path: | ~/.cargo/registry @@ -165,7 +165,7 @@ jobs: - uses: actions/checkout@v2.3.4 with: persist-credentials: false - - uses: actions/cache@v2.1.5 + - uses: actions/cache@v2.1.6 with: path: | ~/.cargo/registry @@ -203,7 +203,7 @@ jobs: - uses: actions/checkout@v2.3.4 with: persist-credentials: false - - uses: actions/cache@v2.1.5 + - uses: actions/cache@v2.1.6 with: path: | ~/.cargo/registry @@ -269,7 +269,7 @@ jobs: - uses: actions/checkout@v2.3.4 with: persist-credentials: false - - uses: actions/cache@v2.1.5 + - uses: actions/cache@v2.1.6 with: path: | ~/.cargo/registry @@ -337,7 +337,7 @@ jobs: with: python-version: ${{ matrix.PYTHON.VERSION }} architecture: ${{ matrix.WINDOWS.ARCH }} - - uses: actions/cache@v2.1.5 + - uses: actions/cache@v2.1.6 with: path: | ~/.cargo/registry @@ -396,7 +396,7 @@ jobs: - uses: actions/checkout@v2.3.4 with: persist-credentials: false - - uses: actions/cache@v2.1.5 + - uses: actions/cache@v2.1.6 with: path: | ~/.cargo/registry From 5fc7556f9a607fcd1717c87ad160bf5b7f1f6c30 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 28 May 2021 09:45:57 -0400 Subject: [PATCH 0184/1456] Update cargh cache dirs in CI to match recommendtions (#6071) --- .github/workflows/ci.yml | 56 +++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 748e7057834e..9347f7e07675 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,10 +42,12 @@ jobs: - uses: actions/cache@v2.1.6 with: path: | - ~/.cargo/registry - ~/.cargo/git + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ src/rust/target/ - key: ${{ runner.os }}-${{ matrix.PYTHON.VERSION }}-cargo-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.PYTHON.VERSION }}-cargo-2-${{ hashFiles('**/Cargo.lock') }} - name: Setup python uses: actions/setup-python@v2.2.2 @@ -128,10 +130,12 @@ jobs: - uses: actions/cache@v2.1.6 with: path: | - ~/.cargo/registry - ~/.cargo/git + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ src/rust/target/ - key: ${{ runner.os }}-${{ matrix.IMAGE.IMAGE }}-cargo-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.IMAGE.IMAGE }}-cargo-2-${{ hashFiles('**/Cargo.lock') }} - run: 'git clone --depth=1 https://github.com/google/wycheproof "$HOME/wycheproof"' - run: | @@ -168,10 +172,12 @@ jobs: - uses: actions/cache@v2.1.6 with: path: | - ~/.cargo/registry - ~/.cargo/git + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ src/rust/target/ - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-${{ matrix.RUST }} + key: ${{ runner.os }}-cargo-2-${{ hashFiles('**/Cargo.lock') }}-${{ matrix.RUST }} - name: Setup python uses: actions/setup-python@v2.2.2 @@ -206,10 +212,12 @@ jobs: - uses: actions/cache@v2.1.6 with: path: | - ~/.cargo/registry - ~/.cargo/git + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ src/rust/target/ - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-rust-nightly-coverage + key: ${{ runner.os }}-cargo-2-${{ hashFiles('**/Cargo.lock') }}-rust-nightly-coverage - name: Setup python uses: actions/setup-python@v2.2.2 @@ -272,10 +280,12 @@ jobs: - uses: actions/cache@v2.1.6 with: path: | - ~/.cargo/registry - ~/.cargo/git + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ src/rust/target/ - key: ${{ runner.os }}-${{ matrix.PYTHON.VERSION }}-cargo-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.PYTHON.VERSION }}-cargo-2-${{ hashFiles('**/Cargo.lock') }} - name: Setup python uses: actions/setup-python@v2.2.2 @@ -340,10 +350,12 @@ jobs: - uses: actions/cache@v2.1.6 with: path: | - ~/.cargo/registry - ~/.cargo/git + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ src/rust/target/ - key: ${{ runner.os }}-${{ matrix.WINDOWS.ARCH }}-${{ steps.setup-python.outputs.python-version }}-cargo-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.WINDOWS.ARCH }}-${{ steps.setup-python.outputs.python-version }}-cargo-2-${{ hashFiles('**/Cargo.lock') }} - uses: actions-rs/toolchain@v1.0.7 with: @@ -399,10 +411,12 @@ jobs: - uses: actions/cache@v2.1.6 with: path: | - ~/.cargo/registry - ~/.cargo/git + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ src/rust/target/ - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + key: ${{ runner.os }}-cargo-2-${{ hashFiles('**/Cargo.lock') }} - name: Setup python uses: actions/setup-python@v2.2.2 From dde3586efce9efa2c42690588248be71a52172eb Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 29 May 2021 11:39:58 -0400 Subject: [PATCH 0185/1456] don't install cargo-binutils if we had a cargo cache hit (#6073) --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9347f7e07675..d1d1d1e42a1e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -210,6 +210,7 @@ jobs: with: persist-credentials: false - uses: actions/cache@v2.1.6 + id: cargo-cache with: path: | ~/.cargo/bin/ @@ -234,6 +235,7 @@ jobs: with: crate: cargo-binutils version: latest + if: steps.cargo-cache.outputs.cache-hit != 'true' - run: git clone --depth=1 https://github.com/google/wycheproof - run: python -m pip install tox coverage From e22242f28090f6636debc7bc1e9e31b7d9f26faf Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 30 May 2021 19:34:11 -0400 Subject: [PATCH 0186/1456] Bump to rust-asn1 0.5.0 (#6074) --- src/rust/Cargo.lock | 8 ++++---- src/rust/Cargo.toml | 2 +- src/rust/src/asn1.rs | 5 ++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 9352ad1899cd..9422bc7a71bf 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "asn1" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "150eef712394a4e814c83771b4027c5b4e9f9cb8f5ed30e8556c8e7bdeca5864" +checksum = "2b0b5d36e3f25768cc488c4aff0e38c645b34d30552e5739aed33ebdd02b2c31" dependencies = [ "asn1_derive", "chrono", @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "asn1_derive" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "511fd42f2524a4771b3d51149b9af8c196e6ab479795ab7ef6d743f5696fd141" +checksum = "4be4b1a957d65a39deba1154b39d0ee6806705ed293c43dcb2ec9ab71a95c889" dependencies = [ "proc-macro2", "quote", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 38e21e57dba8..1b95deb09d0f 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] lazy_static = "1" pyo3 = { version = "0.13.1" } -asn1 = { version = "0.4.2", default-features = false, features = ["derive"] } +asn1 = { version = "0.5.0", default-features = false, features = ["derive"] } [features] extension-module = ["pyo3/extension-module"] diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 93a6899c5fd5..2921200af1f1 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -56,8 +56,7 @@ fn parse_tls_feature(py: pyo3::Python<'_>, data: &[u8]) -> Result>(data)? { - let feature = el?; + for feature in asn1::parse_single::>(data)? { let py_feature = tls_feature_type_to_enum.get_item(feature.to_object(py))?; features.append(py_feature)?; } @@ -246,7 +245,7 @@ struct Validity<'a> { fn parse_name_value_tags(rdns: &mut Name<'_>) -> Result, PyAsn1Error> { let mut tags = vec![]; for rdn in rdns { - let mut attributes = rdn?.collect::>>()?; + let mut attributes = rdn.collect::>(); assert_eq!(attributes.len(), 1); tags.push(attributes.pop().unwrap().value.tag()); From 2cdbaff2d127a313ca49e84841c0828fface2796 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 30 May 2021 20:09:34 -0400 Subject: [PATCH 0187/1456] Move OCSPRequest implementation to Rust (#6059) * Move OCSPRequest implementation to Rust --- .../hazmat/backends/openssl/backend.py | 32 +- .../hazmat/backends/openssl/ocsp.py | 46 --- .../hazmat/bindings/_rust/asn1.pyi | 5 +- .../hazmat/bindings/_rust/ocsp.pyi | 7 + src/cryptography/x509/ocsp.py | 5 +- src/rust/Cargo.lock | 66 ++++ src/rust/Cargo.toml | 1 + src/rust/src/asn1.rs | 37 +-- src/rust/src/lib.rs | 2 + src/rust/src/ocsp.rs | 298 ++++++++++++++++++ 10 files changed, 387 insertions(+), 112 deletions(-) create mode 100644 src/cryptography/hazmat/bindings/_rust/ocsp.pyi create mode 100644 src/rust/src/ocsp.rs diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index ce9b3dc63e82..448bd68241d4 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -62,10 +62,7 @@ ) 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.ocsp import _OCSPResponse from cryptography.hazmat.backends.openssl.poly1305 import ( _POLY1305_KEY_SIZE, _Poly1305Context, @@ -88,7 +85,7 @@ _CertificateSigningRequest, _RevokedCertificate, ) -from cryptography.hazmat.bindings._rust import asn1 +from cryptography.hazmat.bindings._rust import asn1, ocsp as rust_ocsp from cryptography.hazmat.bindings.openssl import binding from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ( @@ -420,18 +417,11 @@ def _register_x509_ext_parsers(self): get_ext=self._lib.X509_CRL_get_ext, handlers=_CRL_EXTENSION_HANDLERS, ) - self._ocsp_req_ext_parser = _X509ExtensionParser( - self, - ext_count=self._lib.OCSP_REQUEST_get_ext_count, - get_ext=self._lib.OCSP_REQUEST_get_ext, - rust_callback=asn1.parse_ocsp_req_extension, - ) self._ocsp_basicresp_ext_parser = _X509ExtensionParser( self, ext_count=self._lib.OCSP_BASICRESP_get_ext_count, get_ext=self._lib.OCSP_BASICRESP_get_ext, - # OCSP basic resp has the same extensions as req. - rust_callback=asn1.parse_ocsp_req_extension, + rust_callback=rust_ocsp.parse_ocsp_resp_extension, ) self._ocsp_singleresp_ext_parser = _X509ExtensionParser( self, @@ -1655,16 +1645,6 @@ def _ec_key_new_by_curve_nid(self, 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) @@ -1692,7 +1672,11 @@ def create_ocsp_request(self, builder): add_func=self._lib.OCSP_REQUEST_add_ext, gc=True, ) - return _OCSPRequest(self, ocsp_req) + + bio = self._create_mem_bio_gc() + res = self._lib.i2d_OCSP_REQUEST_bio(bio, ocsp_req) + self.openssl_assert(res > 0) + return ocsp.load_der_ocsp_request(self._read_mem_bio(bio)) def _create_ocsp_basic_response(self, builder, private_key, algorithm): self._x509_check_signature_params(private_key, algorithm) diff --git a/src/cryptography/hazmat/backends/openssl/ocsp.py b/src/cryptography/hazmat/backends/openssl/ocsp.py index 9138e78dba62..6ef9316e975e 100644 --- a/src/cryptography/hazmat/backends/openssl/ocsp.py +++ b/src/cryptography/hazmat/backends/openssl/ocsp.py @@ -19,7 +19,6 @@ from cryptography.hazmat.primitives import hashes, serialization from cryptography.x509.ocsp import ( OCSPCertStatus, - OCSPRequest, OCSPResponse, OCSPResponseStatus, _CERT_STATUS_TO_ENUM, @@ -346,48 +345,3 @@ def public_bytes(self, encoding: serialization.Encoding) -> bytes: ) self._backend.openssl_assert(res > 0) return self._backend._read_mem_bio(bio) - - -class _OCSPRequest(OCSPRequest): - 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) -> bytes: - return _issuer_key_hash(self._backend, self._cert_id) - - @property - def issuer_name_hash(self) -> bytes: - return _issuer_name_hash(self._backend, self._cert_id) - - @property - def serial_number(self) -> int: - return _serial_number(self._backend, self._cert_id) - - @property - def hash_algorithm(self) -> hashes.HashAlgorithm: - return _hash_algorithm(self._backend, self._cert_id) - - @utils.cached_property - def extensions(self) -> x509.Extensions: - return self._backend._ocsp_req_ext_parser.parse(self._ocsp_request) - - def public_bytes(self, encoding: serialization.Encoding) -> bytes: - 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 --git a/src/cryptography/hazmat/bindings/_rust/asn1.pyi b/src/cryptography/hazmat/bindings/_rust/asn1.pyi index 5f4afc92f1cf..bd73221baf37 100644 --- a/src/cryptography/hazmat/bindings/_rust/asn1.pyi +++ b/src/cryptography/hazmat/bindings/_rust/asn1.pyi @@ -1,6 +1,6 @@ import typing -from cryptography.x509 import ExtensionType, TLSFeature, PrecertPoison +from cryptography.x509 import TLSFeature, PrecertPoison class TestCertificate: not_after_tag: int @@ -14,8 +14,5 @@ def encode_tls_feature(ext: TLSFeature) -> bytes: ... def parse_tls_feature(data: bytes) -> TLSFeature: ... def encode_precert_poison(ext: PrecertPoison) -> bytes: ... def parse_precert_poison(data: bytes) -> PrecertPoison: ... -def parse_ocsp_req_extension( - der_oid: bytes, ext_data: bytes -) -> ExtensionType: ... def parse_spki_for_data(data: bytes) -> bytes: ... def test_parse_certificate(data: bytes) -> TestCertificate: ... diff --git a/src/cryptography/hazmat/bindings/_rust/ocsp.pyi b/src/cryptography/hazmat/bindings/_rust/ocsp.pyi new file mode 100644 index 000000000000..2d8c04fc31ea --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/ocsp.pyi @@ -0,0 +1,7 @@ +from cryptography.x509 import ExtensionType +from cryptography.x509.ocsp import OCSPRequest + +def load_der_ocsp_request(data: bytes) -> OCSPRequest: ... +def parse_ocsp_resp_extension( + der_oid: bytes, ext_data: bytes +) -> ExtensionType: ... diff --git a/src/cryptography/x509/ocsp.py b/src/cryptography/x509/ocsp.py index 7f8711b79d2d..2c6a450a1d62 100644 --- a/src/cryptography/x509/ocsp.py +++ b/src/cryptography/x509/ocsp.py @@ -9,6 +9,7 @@ from cryptography import utils from cryptography import x509 +from cryptography.hazmat.bindings._rust import ocsp from cryptography.hazmat.primitives import hashes, serialization from cryptography.x509.base import ( PRIVATE_KEY_TYPES, @@ -494,9 +495,7 @@ def build_unsuccessful( def load_der_ocsp_request(data: bytes) -> OCSPRequest: - from cryptography.hazmat.backends.openssl.backend import backend - - return backend.load_der_ocsp_request(data) + return ocsp.load_der_ocsp_request(data) def load_der_ocsp_response(data: bytes) -> OCSPResponse: diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 9422bc7a71bf..c1a44b7e3077 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" + [[package]] name = "asn1" version = "0.5.0" @@ -57,6 +63,7 @@ version = "0.1.0" dependencies = [ "asn1", "lazy_static", + "ouroboros", "pyo3", ] @@ -175,6 +182,29 @@ dependencies = [ "autocfg", ] +[[package]] +name = "ouroboros" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f52300b81ac4eeeb6c00c20f7e86556c427d9fb2d92b68fc73c22f331cd15" +dependencies = [ + "ouroboros_macro", + "stable_deref_trait", +] + +[[package]] +name = "ouroboros_macro" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41db02c8f8731cdd7a72b433c7900cce4bf245465b452c364bfd21f4566ab055" +dependencies = [ + "Inflector", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "parking_lot" version = "0.11.1" @@ -219,6 +249,30 @@ dependencies = [ "proc-macro-hack", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro-hack" version = "0.5.19" @@ -303,6 +357,12 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "syn" version = "1.0.72" @@ -326,6 +386,12 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7" +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + [[package]] name = "winapi" version = "0.3.9" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 1b95deb09d0f..824fe1cf2a2a 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -9,6 +9,7 @@ publish = false lazy_static = "1" pyo3 = { version = "0.13.1" } asn1 = { version = "0.5.0", default-features = false, features = ["derive"] } +ouroboros = "0.9" [features] extension-module = ["pyo3/extension-module"] diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 2921200af1f1..8f7bb486aaea 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -5,7 +5,7 @@ use pyo3::class::basic::CompareOp; use pyo3::conversion::ToPyObject; -enum PyAsn1Error { +pub(crate) enum PyAsn1Error { Asn1(asn1::ParseError), Py(pyo3::PyErr), } @@ -101,44 +101,13 @@ fn parse_spki_for_data(py: pyo3::Python<'_>, data: &[u8]) -> Result = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.48.1.2").unwrap(); -} - -#[pyo3::prelude::pyfunction] -fn parse_ocsp_req_extension( - py: pyo3::Python<'_>, - der_oid: &[u8], - ext_data: &[u8], -) -> pyo3::PyResult { - let oid = asn1::ObjectIdentifier::from_der(der_oid).unwrap(); - - let x509_module = py.import("cryptography.x509")?; - if oid == *NONCE_OID { - // This is a disaster. RFC 2560 says that the contents of the nonce is - // just the raw extension value. This is nonsense, since they're always - // supposed to be ASN.1 TLVs. RFC 6960 correctly specifies that the - // nonce is an OCTET STRING, and so you should unwrap the TLV to get - // the nonce. For now we just implement the old behavior, even though - // it's deranged. - Ok(x509_module - .call_method1("OCSPNonce", (ext_data,))? - .to_object(py)) - } else { - let oid_obj = x509_module.call_method1("ObjectIdentifier", (oid.to_string(),))?; - Ok(x509_module - .call_method1("UnrecognizedExtension", (oid_obj, ext_data))? - .to_object(py)) - } -} - #[derive(asn1::Asn1Read, asn1::Asn1Write)] struct DssSignature<'a> { r: asn1::BigUint<'a>, s: asn1::BigUint<'a>, } -fn big_asn1_uint_to_py<'p>( +pub(crate) fn big_asn1_uint_to_py<'p>( py: pyo3::Python<'p>, v: asn1::BigUint, ) -> pyo3::PyResult<&'p pyo3::PyAny> { @@ -273,8 +242,6 @@ pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelud submod.add_wrapped(pyo3::wrap_pyfunction!(parse_precert_poison))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_spki_for_data))?; - submod.add_wrapped(pyo3::wrap_pyfunction!(parse_ocsp_req_extension))?; - submod.add_wrapped(pyo3::wrap_pyfunction!(decode_dss_signature))?; submod.add_wrapped(pyo3::wrap_pyfunction!(encode_dss_signature))?; diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index a3b3fb715141..3f5236267992 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -3,6 +3,7 @@ // for complete details. mod asn1; +mod ocsp; use std::convert::TryInto; @@ -73,6 +74,7 @@ fn _rust(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> m.add_function(pyo3::wrap_pyfunction!(check_ansix923_padding, m)?)?; m.add_submodule(asn1::create_submodule(py)?)?; + m.add_submodule(ocsp::create_submodule(py)?)?; Ok(()) } diff --git a/src/rust/src/ocsp.rs b/src/rust/src/ocsp.rs new file mode 100644 index 000000000000..d551e3f3c2cd --- /dev/null +++ b/src/rust/src/ocsp.rs @@ -0,0 +1,298 @@ +// 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. + +use crate::asn1::{big_asn1_uint_to_py, PyAsn1Error}; +use pyo3::conversion::ToPyObject; +use pyo3::exceptions; +use std::collections::{HashMap, HashSet}; + +lazy_static::lazy_static! { + static ref SHA1_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.14.3.2.26").unwrap(); + static ref SHA224_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.16.840.1.101.3.4.2.4").unwrap(); + static ref SHA256_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.16.840.1.101.3.4.2.1").unwrap(); + static ref SHA384_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.16.840.1.101.3.4.2.2").unwrap(); + static ref SHA512_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.16.840.1.101.3.4.2.3").unwrap(); + + static ref OIDS_TO_HASH: HashMap<&'static asn1::ObjectIdentifier<'static>, &'static str> = { + let mut h = HashMap::new(); + h.insert(&*SHA1_OID, "SHA1"); + h.insert(&*SHA224_OID, "SHA224"); + h.insert(&*SHA256_OID, "SHA256"); + h.insert(&*SHA384_OID, "SHA384"); + h.insert(&*SHA512_OID, "SHA512"); + h + }; + + static ref NONCE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.48.1.2").unwrap(); +} + +#[ouroboros::self_referencing] +struct OwnedRawOCSPRequest { + data: Vec, + #[borrows(data)] + #[covariant] + value: RawOCSPRequest<'this>, +} + +#[pyo3::prelude::pyfunction] +fn load_der_ocsp_request(_py: pyo3::Python<'_>, data: &[u8]) -> Result { + let raw = OwnedRawOCSPRequest::try_new(data.to_vec(), |data| asn1::parse_single(data))?; + + if raw.borrow_value().tbs_request.request_list.clone().count() != 1 { + return Err(PyAsn1Error::from( + exceptions::PyNotImplementedError::new_err( + "OCSP request contains more than one request", + ), + )); + } + + Ok(OCSPRequest { + raw, + cached_extensions: None, + }) +} + +#[pyo3::prelude::pyclass] +struct OCSPRequest { + raw: OwnedRawOCSPRequest, + + cached_extensions: Option, +} + +impl OCSPRequest { + fn cert_id(&self) -> Result { + Ok(self + .raw + .borrow_value() + .tbs_request + .request_list + .clone() + .next() + .unwrap() + .req_cert) + } +} + +fn parse_and_cache_extensions< + 'p, + F: Fn(&asn1::ObjectIdentifier, &[u8]) -> Result, PyAsn1Error>, +>( + py: pyo3::Python<'p>, + cached_extensions: &mut Option, + raw_exts: &Option, + parse_ext: F, +) -> Result { + if let Some(cached) = cached_extensions { + return Ok(cached.clone_ref(py)); + } + + let x509_module = py.import("cryptography.x509")?; + let exts = pyo3::types::PyList::empty(py); + let mut seen_oids = HashSet::new(); + if let Some(raw_exts) = raw_exts { + for raw_ext in raw_exts.clone() { + let oid_obj = + x509_module.call_method1("ObjectIdentifier", (raw_ext.extn_id.to_string(),))?; + + if seen_oids.contains(&raw_ext.extn_id) { + return Err(PyAsn1Error::from(pyo3::PyErr::from_instance( + x509_module.call_method1( + "DuplicateExtension", + ( + format!("Duplicate {} extension found", raw_ext.extn_id), + oid_obj, + ), + )?, + ))); + } + + let extn_value = match parse_ext(&raw_ext.extn_id, raw_ext.extn_value)? { + Some(e) => e, + None => x509_module + .call_method1("UnrecognizedExtension", (oid_obj, raw_ext.extn_value))?, + }; + let ext_obj = + x509_module.call_method1("Extension", (oid_obj, raw_ext.critical, extn_value))?; + exts.append(ext_obj)?; + seen_oids.insert(raw_ext.extn_id); + } + } + let extensions = x509_module + .call_method1("Extensions", (exts,))? + .to_object(py); + *cached_extensions = Some(extensions.clone_ref(py)); + Ok(extensions) +} + +#[pyo3::prelude::pymethods] +impl OCSPRequest { + #[getter] + fn issuer_name_hash(&self) -> Result<&[u8], PyAsn1Error> { + Ok(self.cert_id()?.issuer_name_hash) + } + + #[getter] + fn issuer_key_hash(&self) -> Result<&[u8], PyAsn1Error> { + Ok(self.cert_id()?.issuer_key_hash) + } + + #[getter] + fn hash_algorithm<'p>(&self, py: pyo3::Python<'p>) -> Result<&'p pyo3::PyAny, PyAsn1Error> { + let cert_id = self.cert_id()?; + + let hashes = py.import("cryptography.hazmat.primitives.hashes")?; + match OIDS_TO_HASH.get(&cert_id.hash_algorithm.oid) { + Some(alg_name) => Ok(hashes.call0(alg_name)?), + None => { + let exceptions = py.import("cryptography.exceptions")?; + Err(PyAsn1Error::from(pyo3::PyErr::from_instance( + exceptions.call1( + "UnsupportedAlgorithm", + (format!( + "Signature algorithm OID: {} not recognized", + cert_id.hash_algorithm.oid + ),), + )?, + ))) + } + } + } + + #[getter] + fn serial_number<'p>(&self, py: pyo3::Python<'p>) -> Result<&'p pyo3::PyAny, PyAsn1Error> { + Ok(big_asn1_uint_to_py(py, self.cert_id()?.serial_number)?) + } + + #[getter] + fn extensions(&mut self, py: pyo3::Python) -> Result { + let x509_module = py.import("cryptography.x509")?; + parse_and_cache_extensions( + py, + &mut self.cached_extensions, + &self.raw.borrow_value().tbs_request.request_extensions, + |oid, value| { + if oid == &*NONCE_OID { + // This is a disaster. RFC 2560 says that the contents of the nonce is + // just the raw extension value. This is nonsense, since they're always + // supposed to be ASN.1 TLVs. RFC 6960 correctly specifies that the + // nonce is an OCTET STRING, and so you should unwrap the TLV to get + // the nonce. For now we just implement the old behavior, even though + // it's deranged. + Ok(Some(x509_module.call_method1("OCSPNonce", (value,))?)) + } else { + Ok(None) + } + }, + ) + } + + fn public_bytes<'p>( + &self, + py: pyo3::Python<'p>, + encoding: &pyo3::PyAny, + ) -> Result<&'p pyo3::types::PyBytes, PyAsn1Error> { + let der = py + .import("cryptography.hazmat.primitives.serialization")? + .getattr("Encoding")? + .getattr("DER")?; + if encoding != der { + return Err(PyAsn1Error::from(exceptions::PyValueError::new_err( + "The only allowed encoding value is Encoding.DER", + ))); + } + let result = asn1::write_single(self.raw.borrow_value()); + Ok(pyo3::types::PyBytes::new(py, &result)) + } +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +struct RawOCSPRequest<'a> { + tbs_request: TBSRequest<'a>, + // Parsing out the full structure, which includes the entirety of a + // certificate is more trouble than it's worth, since it's not in the + // Python API. + #[explicit(0)] + _optional_signature: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +struct TBSRequest<'a> { + #[explicit(0)] + #[default(0)] + version: u8, + // This is virtually unused, not supported until GeneralName is implemented + // and used elsewhere. + // #[explicit(1)] + // _requestor_name: Option>, + request_list: asn1::SequenceOf<'a, Request<'a>>, + #[explicit(2)] + request_extensions: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +struct Request<'a> { + req_cert: CertID<'a>, + #[explicit(0)] + _single_request_extensions: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +struct CertID<'a> { + hash_algorithm: AlgorithmIdentifier<'a>, + issuer_name_hash: &'a [u8], + issuer_key_hash: &'a [u8], + serial_number: asn1::BigUint<'a>, +} + +type Extensions<'a> = asn1::SequenceOf<'a, Extension<'a>>; + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +struct AlgorithmIdentifier<'a> { + oid: asn1::ObjectIdentifier<'a>, + _params: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +struct Extension<'a> { + extn_id: asn1::ObjectIdentifier<'a>, + #[default(false)] + critical: bool, + extn_value: &'a [u8], +} + +#[pyo3::prelude::pyfunction] +fn parse_ocsp_resp_extension( + py: pyo3::Python<'_>, + der_oid: &[u8], + ext_data: &[u8], +) -> pyo3::PyResult { + let oid = asn1::ObjectIdentifier::from_der(der_oid).unwrap(); + + let x509_module = py.import("cryptography.x509")?; + if oid == *NONCE_OID { + // This is a disaster. RFC 2560 says that the contents of the nonce is + // just the raw extension value. This is nonsense, since they're always + // supposed to be ASN.1 TLVs. RFC 6960 correctly specifies that the + // nonce is an OCTET STRING, and so you should unwrap the TLV to get + // the nonce. For now we just implement the old behavior, even though + // it's deranged. + Ok(x509_module + .call_method1("OCSPNonce", (ext_data,))? + .to_object(py)) + } else { + let oid_obj = x509_module.call_method1("ObjectIdentifier", (oid.to_string(),))?; + Ok(x509_module + .call_method1("UnrecognizedExtension", (oid_obj, ext_data))? + .to_object(py)) + } +} + +pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let submod = pyo3::prelude::PyModule::new(py, "ocsp")?; + + submod.add_wrapped(pyo3::wrap_pyfunction!(load_der_ocsp_request))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(parse_ocsp_resp_extension))?; + + Ok(submod) +} From 42332b725ff1a995a55532e773befa65a884cf6a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 31 May 2021 10:09:45 -0400 Subject: [PATCH 0188/1456] Simplify delegation of rust for extension parsing (#6075) Also now supports part openssl/part rust setups --- .../hazmat/backends/openssl/backend.py | 7 ++- .../hazmat/backends/openssl/decode_asn1.py | 35 +++----------- .../hazmat/bindings/_rust/asn1.pyi | 2 - .../hazmat/bindings/_rust/x509.pyi | 3 ++ src/rust/src/asn1.rs | 26 ---------- src/rust/src/lib.rs | 2 + src/rust/src/ocsp.rs | 5 +- src/rust/src/x509.rs | 47 +++++++++++++++++++ 8 files changed, 65 insertions(+), 62 deletions(-) create mode 100644 src/cryptography/hazmat/bindings/_rust/x509.pyi create mode 100644 src/rust/src/x509.rs diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 448bd68241d4..8ab05ffb1067 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -85,7 +85,11 @@ _CertificateSigningRequest, _RevokedCertificate, ) -from cryptography.hazmat.bindings._rust import asn1, ocsp as rust_ocsp +from cryptography.hazmat.bindings._rust import ( + asn1, + ocsp as rust_ocsp, + x509 as rust_x509, +) from cryptography.hazmat.bindings.openssl import binding from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ( @@ -398,6 +402,7 @@ def _register_x509_ext_parsers(self): ext_count=self._lib.X509_get_ext_count, get_ext=self._lib.X509_get_ext, handlers=ext_handlers, + rust_callback=rust_x509.parse_x509_extension, ) self._csr_extension_parser = _X509ExtensionParser( self, diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index eb384263d6de..efa4dd14f7f0 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -8,7 +8,6 @@ import typing from cryptography import x509 -from cryptography.hazmat.bindings._rust import asn1 from cryptography.x509.name import _ASN1_TYPE_TO_ENUM from cryptography.x509.oid import ( CRLEntryExtensionOID, @@ -178,7 +177,7 @@ def _decode_delta_crl_indicator(backend, ext): class _X509ExtensionParser(object): def __init__( - self, backend, ext_count, get_ext, handlers=None, rust_callback=None + self, backend, ext_count, get_ext, handlers={}, rust_callback=None ): assert handlers or rust_callback self.ext_count = ext_count @@ -214,33 +213,11 @@ def parse(self, x509_obj): )[:] data = self._backend._lib.X509_EXTENSION_get_data(ext) data_bytes = _asn1_string_to_bytes(self._backend, data) - ext = self.rust_callback(oid_der_bytes, data_bytes) - extensions.append(x509.Extension(oid, critical, ext)) - seen_oids.add(oid) - continue - - # 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: - # The extension contents are a SEQUENCE OF INTEGERs. - data = self._backend._lib.X509_EXTENSION_get_data(ext) - data_bytes = _asn1_string_to_bytes(self._backend, data) - tls_feature = asn1.parse_tls_feature(data_bytes) - - extensions.append(x509.Extension(oid, critical, tls_feature)) - seen_oids.add(oid) - continue - elif oid == ExtensionOID.PRECERT_POISON: - data = self._backend._lib.X509_EXTENSION_get_data(ext) - data_bytes = _asn1_string_to_bytes(self._backend, data) - precert_poison = asn1.parse_precert_poison(data_bytes) - - extensions.append( - x509.Extension(oid, critical, precert_poison) - ) - seen_oids.add(oid) - continue + ext_obj = self.rust_callback(oid_der_bytes, data_bytes) + if ext_obj is not None: + extensions.append(x509.Extension(oid, critical, ext_obj)) + seen_oids.add(oid) + continue try: handler = self.handlers[oid] diff --git a/src/cryptography/hazmat/bindings/_rust/asn1.pyi b/src/cryptography/hazmat/bindings/_rust/asn1.pyi index bd73221baf37..6809271014f7 100644 --- a/src/cryptography/hazmat/bindings/_rust/asn1.pyi +++ b/src/cryptography/hazmat/bindings/_rust/asn1.pyi @@ -11,8 +11,6 @@ class TestCertificate: def decode_dss_signature(signature: bytes) -> typing.Tuple[int, int]: ... def encode_dss_signature(r: int, s: int) -> bytes: ... def encode_tls_feature(ext: TLSFeature) -> bytes: ... -def parse_tls_feature(data: bytes) -> TLSFeature: ... def encode_precert_poison(ext: PrecertPoison) -> bytes: ... -def parse_precert_poison(data: bytes) -> PrecertPoison: ... def parse_spki_for_data(data: bytes) -> bytes: ... def test_parse_certificate(data: bytes) -> TestCertificate: ... diff --git a/src/cryptography/hazmat/bindings/_rust/x509.pyi b/src/cryptography/hazmat/bindings/_rust/x509.pyi new file mode 100644 index 000000000000..d1e26e0b15b5 --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/x509.pyi @@ -0,0 +1,3 @@ +from cryptography.x509 import ExtensionType + +def parse_x509_extension(der_oid: bytes, ext_data: bytes) -> ExtensionType: ... diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 8f7bb486aaea..08c22790506b 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -49,36 +49,12 @@ fn encode_tls_feature(py: pyo3::Python<'_>, ext: &pyo3::PyAny) -> pyo3::PyResult Ok(pyo3::types::PyBytes::new(py, &result).to_object(py)) } -#[pyo3::prelude::pyfunction] -fn parse_tls_feature(py: pyo3::Python<'_>, data: &[u8]) -> Result { - let tls_feature_type_to_enum = py - .import("cryptography.x509.extensions")? - .getattr("_TLS_FEATURE_TYPE_TO_ENUM")?; - - let features = pyo3::types::PyList::empty(py); - for feature in asn1::parse_single::>(data)? { - let py_feature = tls_feature_type_to_enum.get_item(feature.to_object(py))?; - features.append(py_feature)?; - } - - let x509_module = py.import("cryptography.x509")?; - Ok(x509_module.call1("TLSFeature", (features,))?.to_object(py)) -} - #[pyo3::prelude::pyfunction] fn encode_precert_poison(py: pyo3::Python<'_>, _ext: &pyo3::PyAny) -> pyo3::PyObject { let result = asn1::write_single(&()); pyo3::types::PyBytes::new(py, &result).to_object(py) } -#[pyo3::prelude::pyfunction] -fn parse_precert_poison(py: pyo3::Python<'_>, data: &[u8]) -> Result { - asn1::parse_single::<()>(data)?; - - let x509_module = py.import("cryptography.x509")?; - Ok(x509_module.call0("PrecertPoison")?.to_object(py)) -} - #[derive(asn1::Asn1Read)] struct AlgorithmIdentifier<'a> { _oid: asn1::ObjectIdentifier<'a>, @@ -237,9 +213,7 @@ fn test_parse_certificate(data: &[u8]) -> Result { pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let submod = pyo3::prelude::PyModule::new(py, "asn1")?; submod.add_wrapped(pyo3::wrap_pyfunction!(encode_tls_feature))?; - submod.add_wrapped(pyo3::wrap_pyfunction!(parse_tls_feature))?; submod.add_wrapped(pyo3::wrap_pyfunction!(encode_precert_poison))?; - submod.add_wrapped(pyo3::wrap_pyfunction!(parse_precert_poison))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_spki_for_data))?; submod.add_wrapped(pyo3::wrap_pyfunction!(decode_dss_signature))?; diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 3f5236267992..dbde1d9de22a 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -4,6 +4,7 @@ mod asn1; mod ocsp; +mod x509; use std::convert::TryInto; @@ -75,6 +76,7 @@ fn _rust(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> m.add_submodule(asn1::create_submodule(py)?)?; m.add_submodule(ocsp::create_submodule(py)?)?; + m.add_submodule(x509::create_submodule(py)?)?; Ok(()) } diff --git a/src/rust/src/ocsp.rs b/src/rust/src/ocsp.rs index d551e3f3c2cd..ddbe4f0503c0 100644 --- a/src/rust/src/ocsp.rs +++ b/src/rust/src/ocsp.rs @@ -281,10 +281,7 @@ fn parse_ocsp_resp_extension( .call_method1("OCSPNonce", (ext_data,))? .to_object(py)) } else { - let oid_obj = x509_module.call_method1("ObjectIdentifier", (oid.to_string(),))?; - Ok(x509_module - .call_method1("UnrecognizedExtension", (oid_obj, ext_data))? - .to_object(py)) + Ok(py.None()) } } diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs new file mode 100644 index 000000000000..845423d033e3 --- /dev/null +++ b/src/rust/src/x509.rs @@ -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. + +use crate::asn1::PyAsn1Error; +use pyo3::conversion::ToPyObject; + +lazy_static::lazy_static! { + static ref TLS_FEATURE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.1.24").unwrap(); + static ref PRECERT_POISON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.4.1.11129.2.4.3").unwrap(); +} + +#[pyo3::prelude::pyfunction] +fn parse_x509_extension( + py: pyo3::Python<'_>, + der_oid: &[u8], + ext_data: &[u8], +) -> Result { + let oid = asn1::ObjectIdentifier::from_der(der_oid).unwrap(); + + let x509_module = py.import("cryptography.x509")?; + if oid == *TLS_FEATURE_OID { + let tls_feature_type_to_enum = py + .import("cryptography.x509.extensions")? + .getattr("_TLS_FEATURE_TYPE_TO_ENUM")?; + + let features = pyo3::types::PyList::empty(py); + for feature in asn1::parse_single::>(ext_data)? { + let py_feature = tls_feature_type_to_enum.get_item(feature.to_object(py))?; + features.append(py_feature)?; + } + Ok(x509_module.call1("TLSFeature", (features,))?.to_object(py)) + } else if oid == *PRECERT_POISON_OID { + asn1::parse_single::<()>(ext_data)?; + Ok(x509_module.call0("PrecertPoison")?.to_object(py)) + } else { + Ok(py.None()) + } +} + +pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let submod = pyo3::prelude::PyModule::new(py, "x509")?; + + submod.add_wrapped(pyo3::wrap_pyfunction!(parse_x509_extension))?; + + Ok(submod) +} From 8969f918cbad20acb505850913c1c58a9e92e4c9 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 31 May 2021 11:36:05 -0400 Subject: [PATCH 0189/1456] Burn down now unused OCSP request bindings (#6078) --- src/_cffi_src/openssl/ocsp.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/_cffi_src/openssl/ocsp.py b/src/_cffi_src/openssl/ocsp.py index 9b939f0f85f9..03d2f3d1fde1 100644 --- a/src/_cffi_src/openssl/ocsp.py +++ b/src/_cffi_src/openssl/ocsp.py @@ -41,11 +41,6 @@ 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); -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 *); @@ -68,7 +63,6 @@ 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 *); From 1557201ab3d565355618f4c4feae1cd47fda41d9 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 31 May 2021 11:38:31 -0400 Subject: [PATCH 0190/1456] Convert CRLReason parsing to rust (#6076) --- .../hazmat/backends/openssl/backend.py | 2 + .../hazmat/backends/openssl/decode_asn1.py | 12 ------ .../hazmat/bindings/_rust/x509.pyi | 3 ++ src/rust/src/x509.rs | 37 +++++++++++++++++++ 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 8ab05ffb1067..219b7e1e14eb 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -415,6 +415,7 @@ def _register_x509_ext_parsers(self): ext_count=self._lib.X509_REVOKED_get_ext_count, get_ext=self._lib.X509_REVOKED_get_ext, handlers=_REVOKED_EXTENSION_HANDLERS, + rust_callback=rust_x509.parse_crl_entry_extension, ) self._crl_extension_parser = _X509ExtensionParser( self, @@ -433,6 +434,7 @@ def _register_x509_ext_parsers(self): ext_count=self._lib.OCSP_SINGLERESP_get_ext_count, get_ext=self._lib.OCSP_SINGLERESP_get_ext, handlers=singleresp_handlers, + rust_callback=rust_x509.parse_crl_entry_extension, ) def _register_x509_encoders(self): diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index efa4dd14f7f0..abfbf6cfafcd 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -694,17 +694,6 @@ def _decode_signed_certificate_timestamps(backend, asn1_scts): } -def _decode_crl_reason(backend, enum): - enum = backend._ffi.cast("ASN1_ENUMERATED *", enum) - enum = backend._ffi.gc(enum, backend._lib.ASN1_ENUMERATED_free) - code = backend._lib.ASN1_ENUMERATED_get(enum) - - try: - return x509.CRLReason(_CRL_ENTRY_REASON_CODE_TO_ENUM[code]) - except KeyError: - raise ValueError("Unsupported reason code: {}".format(code)) - - def _decode_invalidity_date(backend, inv_date): generalized_time = backend._ffi.cast("ASN1_GENERALIZEDTIME *", inv_date) generalized_time = backend._ffi.gc( @@ -824,7 +813,6 @@ def _parse_asn1_generalized_time(backend, generalized_time): } _REVOKED_EXTENSION_HANDLERS = { - CRLEntryExtensionOID.CRL_REASON: _decode_crl_reason, CRLEntryExtensionOID.INVALIDITY_DATE: _decode_invalidity_date, CRLEntryExtensionOID.CERTIFICATE_ISSUER: _decode_cert_issuer, } diff --git a/src/cryptography/hazmat/bindings/_rust/x509.pyi b/src/cryptography/hazmat/bindings/_rust/x509.pyi index d1e26e0b15b5..aad2b0e0ce9a 100644 --- a/src/cryptography/hazmat/bindings/_rust/x509.pyi +++ b/src/cryptography/hazmat/bindings/_rust/x509.pyi @@ -1,3 +1,6 @@ from cryptography.x509 import ExtensionType def parse_x509_extension(der_oid: bytes, ext_data: bytes) -> ExtensionType: ... +def parse_crl_entry_extension( + der_oid: bytes, ext_data: bytes +) -> ExtensionType: ... diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index 845423d033e3..359a4b38a126 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -8,6 +8,8 @@ use pyo3::conversion::ToPyObject; lazy_static::lazy_static! { static ref TLS_FEATURE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.1.24").unwrap(); static ref PRECERT_POISON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.4.1.11129.2.4.3").unwrap(); + + static ref CRL_REASON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.21").unwrap(); } #[pyo3::prelude::pyfunction] @@ -38,10 +40,45 @@ fn parse_x509_extension( } } +#[pyo3::prelude::pyfunction] +fn parse_crl_entry_extension( + py: pyo3::Python<'_>, + der_oid: &[u8], + ext_data: &[u8], +) -> Result { + let oid = asn1::ObjectIdentifier::from_der(der_oid).unwrap(); + + let x509_module = py.import("cryptography.x509")?; + if oid == *CRL_REASON_OID { + let flag_name = match asn1::parse_single::(ext_data)?.value() { + 0 => "unspecified", + 1 => "key_compromise", + 2 => "ca_compromise", + 3 => "affiliation_changed", + 4 => "superseded", + 5 => "cessation_of_operation", + 6 => "certificate_hold", + 8 => "remove_from_crl", + 9 => "privilege_withdrawn", + 10 => "aa_compromise", + value => { + return Err(PyAsn1Error::from(pyo3::exceptions::PyValueError::new_err( + format!("Unsupported reason code: {}", value), + ))) + } + }; + let flag = x509_module.getattr("ReasonFlags")?.getattr(flag_name)?; + Ok(x509_module.call1("CRLReason", (flag,))?.to_object(py)) + } else { + Ok(py.None()) + } +} + pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let submod = pyo3::prelude::PyModule::new(py, "x509")?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_x509_extension))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(parse_crl_entry_extension))?; Ok(submod) } From 8397d8a181915e79b319da176d4892296154fedd Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 31 May 2021 12:00:43 -0500 Subject: [PATCH 0191/1456] oxidize crlnumber (#6079) * oxidize crlnumber * cargo fmt --- .../hazmat/backends/openssl/backend.py | 1 + .../hazmat/backends/openssl/decode_asn1.py | 7 ------ .../hazmat/bindings/_rust/x509.pyi | 1 + src/rust/src/x509.rs | 22 ++++++++++++++++++- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 219b7e1e14eb..2efc386f01ae 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -422,6 +422,7 @@ def _register_x509_ext_parsers(self): ext_count=self._lib.X509_CRL_get_ext_count, get_ext=self._lib.X509_CRL_get_ext, handlers=_CRL_EXTENSION_HANDLERS, + rust_callback=rust_x509.parse_crl_extension, ) self._ocsp_basicresp_ext_parser = _X509ExtensionParser( self, diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index abfbf6cfafcd..4b45fbce5f28 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -163,12 +163,6 @@ def _decode_ocsp_no_check(backend, ext): return x509.OCSPNoCheck() -def _decode_crl_number(backend, ext): - asn1_int = backend._ffi.cast("ASN1_INTEGER *", ext) - asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free) - return x509.CRLNumber(_asn1_integer_to_int(backend, asn1_int)) - - def _decode_delta_crl_indicator(backend, ext): asn1_int = backend._ffi.cast("ASN1_INTEGER *", ext) asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free) @@ -818,7 +812,6 @@ def _parse_asn1_generalized_time(backend, generalized_time): } _CRL_EXTENSION_HANDLERS = { - ExtensionOID.CRL_NUMBER: _decode_crl_number, ExtensionOID.DELTA_CRL_INDICATOR: _decode_delta_crl_indicator, ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier, ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name, diff --git a/src/cryptography/hazmat/bindings/_rust/x509.pyi b/src/cryptography/hazmat/bindings/_rust/x509.pyi index aad2b0e0ce9a..2d41f9e91f5f 100644 --- a/src/cryptography/hazmat/bindings/_rust/x509.pyi +++ b/src/cryptography/hazmat/bindings/_rust/x509.pyi @@ -4,3 +4,4 @@ def parse_x509_extension(der_oid: bytes, ext_data: bytes) -> ExtensionType: ... def parse_crl_entry_extension( der_oid: bytes, ext_data: bytes ) -> ExtensionType: ... +def parse_crl_extension(der_oid: bytes, ext_data: bytes) -> ExtensionType: ... diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index 359a4b38a126..9c996f3b8426 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -2,7 +2,7 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::PyAsn1Error; +use crate::asn1::{big_asn1_uint_to_py, PyAsn1Error}; use pyo3::conversion::ToPyObject; lazy_static::lazy_static! { @@ -10,6 +10,7 @@ lazy_static::lazy_static! { static ref PRECERT_POISON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.4.1.11129.2.4.3").unwrap(); static ref CRL_REASON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.21").unwrap(); + static ref CRL_NUMBER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.20").unwrap(); } #[pyo3::prelude::pyfunction] @@ -74,11 +75,30 @@ fn parse_crl_entry_extension( } } +#[pyo3::prelude::pyfunction] +fn parse_crl_extension( + py: pyo3::Python<'_>, + der_oid: &[u8], + ext_data: &[u8], +) -> Result { + let oid = asn1::ObjectIdentifier::from_der(der_oid).unwrap(); + + let x509_module = py.import("cryptography.x509")?; + if oid == *CRL_NUMBER_OID { + let bignum = asn1::parse_single::(ext_data)?; + let pynum = big_asn1_uint_to_py(py, bignum)?; + Ok(x509_module.call1("CRLNumber", (pynum,))?.to_object(py)) + } else { + Ok(py.None()) + } +} + pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let submod = pyo3::prelude::PyModule::new(py, "x509")?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_x509_extension))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_crl_entry_extension))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(parse_crl_extension))?; Ok(submod) } From 52ccb8eb1efbd820c7fd29b6196c70d40f443315 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 31 May 2021 13:40:16 -0500 Subject: [PATCH 0192/1456] oxidize basic constraints (#6080) --- .../hazmat/backends/openssl/backend.py | 1 + .../hazmat/backends/openssl/decode_asn1.py | 17 ----------------- src/rust/src/x509.rs | 13 +++++++++++++ 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 2efc386f01ae..83a4cca69b4a 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -409,6 +409,7 @@ def _register_x509_ext_parsers(self): ext_count=self._lib.sk_X509_EXTENSION_num, get_ext=self._lib.sk_X509_EXTENSION_value, handlers=ext_handlers, + rust_callback=rust_x509.parse_x509_extension, ) self._revoked_cert_extension_parser = _X509ExtensionParser( self, diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 4b45fbce5f28..7be2b2789166 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -296,22 +296,6 @@ def _decode_user_notice(backend, un): return x509.UserNotice(notice_reference, explicit_text) -def _decode_basic_constraints(backend, bc_st): - basic_constraints = backend._ffi.cast("BASIC_CONSTRAINTS *", bc_st) - basic_constraints = backend._ffi.gc( - basic_constraints, backend._lib.BASIC_CONSTRAINTS_free - ) - # The byte representation of an ASN.1 boolean true is \xff. OpenSSL - # chooses to just map this to its ordinal value, so true is 255 and - # false is 0. - ca = basic_constraints.ca == 255 - path_length = _asn1_integer_to_int_or_none( - backend, basic_constraints.pathlen - ) - - return x509.BasicConstraints(ca, path_length) - - def _decode_subject_key_identifier(backend, asn1_string): asn1_string = backend._ffi.cast("ASN1_OCTET_STRING *", asn1_string) asn1_string = backend._ffi.gc( @@ -779,7 +763,6 @@ def _parse_asn1_generalized_time(backend, generalized_time): _EXTENSION_HANDLERS_BASE = { - ExtensionOID.BASIC_CONSTRAINTS: _decode_basic_constraints, ExtensionOID.SUBJECT_KEY_IDENTIFIER: _decode_subject_key_identifier, ExtensionOID.KEY_USAGE: _decode_key_usage, ExtensionOID.SUBJECT_ALTERNATIVE_NAME: _decode_subject_alt_name, diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index 9c996f3b8426..a8be601aedd5 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -9,10 +9,18 @@ lazy_static::lazy_static! { static ref TLS_FEATURE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.1.24").unwrap(); static ref PRECERT_POISON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.4.1.11129.2.4.3").unwrap(); + static ref BASIC_CONSTRAINTS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.19").unwrap(); static ref CRL_REASON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.21").unwrap(); static ref CRL_NUMBER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.20").unwrap(); } +#[derive(asn1::Asn1Read)] +struct BasicConstraints { + #[default(false)] + ca: bool, + path_length: Option, +} + #[pyo3::prelude::pyfunction] fn parse_x509_extension( py: pyo3::Python<'_>, @@ -36,6 +44,11 @@ fn parse_x509_extension( } else if oid == *PRECERT_POISON_OID { asn1::parse_single::<()>(ext_data)?; Ok(x509_module.call0("PrecertPoison")?.to_object(py)) + } else if oid == *BASIC_CONSTRAINTS_OID { + let bc = asn1::parse_single::(ext_data)?; + Ok(x509_module + .call1("BasicConstraints", (bc.ca, bc.path_length))? + .to_object(py)) } else { Ok(py.None()) } From 0ffabb02a9c749afbc6d063797b019652fd1d973 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 31 May 2021 15:14:35 -0500 Subject: [PATCH 0193/1456] oxidize EKU and KU (#6081) * oxidize EKU and KU * we always pass a rust_callback now. refactor for that --- .../hazmat/backends/openssl/backend.py | 10 +-- .../hazmat/backends/openssl/decode_asn1.py | 76 +++++-------------- src/rust/src/x509.rs | 48 ++++++++++++ 3 files changed, 70 insertions(+), 64 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 83a4cca69b4a..0376843d15d2 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -401,29 +401,29 @@ def _register_x509_ext_parsers(self): self, ext_count=self._lib.X509_get_ext_count, get_ext=self._lib.X509_get_ext, - handlers=ext_handlers, rust_callback=rust_x509.parse_x509_extension, + handlers=ext_handlers, ) self._csr_extension_parser = _X509ExtensionParser( self, ext_count=self._lib.sk_X509_EXTENSION_num, get_ext=self._lib.sk_X509_EXTENSION_value, - handlers=ext_handlers, rust_callback=rust_x509.parse_x509_extension, + handlers=ext_handlers, ) self._revoked_cert_extension_parser = _X509ExtensionParser( self, ext_count=self._lib.X509_REVOKED_get_ext_count, get_ext=self._lib.X509_REVOKED_get_ext, - handlers=_REVOKED_EXTENSION_HANDLERS, rust_callback=rust_x509.parse_crl_entry_extension, + handlers=_REVOKED_EXTENSION_HANDLERS, ) self._crl_extension_parser = _X509ExtensionParser( self, ext_count=self._lib.X509_CRL_get_ext_count, get_ext=self._lib.X509_CRL_get_ext, - handlers=_CRL_EXTENSION_HANDLERS, rust_callback=rust_x509.parse_crl_extension, + handlers=_CRL_EXTENSION_HANDLERS, ) self._ocsp_basicresp_ext_parser = _X509ExtensionParser( self, @@ -435,8 +435,8 @@ def _register_x509_ext_parsers(self): self, ext_count=self._lib.OCSP_SINGLERESP_get_ext_count, get_ext=self._lib.OCSP_SINGLERESP_get_ext, - handlers=singleresp_handlers, rust_callback=rust_x509.parse_crl_entry_extension, + handlers=singleresp_handlers, ) def _register_x509_encoders(self): diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 7be2b2789166..706baace55f4 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -171,9 +171,8 @@ def _decode_delta_crl_indicator(backend, ext): class _X509ExtensionParser(object): def __init__( - self, backend, ext_count, get_ext, handlers={}, rust_callback=None + self, backend, ext_count, get_ext, rust_callback, handlers={} ): - assert handlers or rust_callback self.ext_count = ext_count self.get_ext = get_ext self.handlers = handlers @@ -199,20 +198,22 @@ def parse(self, x509_obj): "Duplicate {} extension found".format(oid), oid ) - if self.rust_callback is not None: - oid_ptr = self._backend._lib.X509_EXTENSION_get_object(ext) - oid_der_bytes = self._backend._ffi.buffer( - self._backend._lib.Cryptography_OBJ_get0_data(oid_ptr), - self._backend._lib.Cryptography_OBJ_length(oid_ptr), - )[:] - data = self._backend._lib.X509_EXTENSION_get_data(ext) - data_bytes = _asn1_string_to_bytes(self._backend, data) - ext_obj = self.rust_callback(oid_der_bytes, data_bytes) - if ext_obj is not None: - extensions.append(x509.Extension(oid, critical, ext_obj)) - seen_oids.add(oid) - continue - + # Try to parse this with the rust callback first + oid_ptr = self._backend._lib.X509_EXTENSION_get_object(ext) + oid_der_bytes = self._backend._ffi.buffer( + self._backend._lib.Cryptography_OBJ_get0_data(oid_ptr), + self._backend._lib.Cryptography_OBJ_length(oid_ptr), + )[:] + data = self._backend._lib.X509_EXTENSION_get_data(ext) + data_bytes = _asn1_string_to_bytes(self._backend, data) + ext_obj = self.rust_callback(oid_der_bytes, data_bytes) + if ext_obj is not None: + extensions.append(x509.Extension(oid, critical, ext_obj)) + seen_oids.add(oid) + continue + + # Fallback to our older parsing because the rust code doesn't + # know how to parse this. try: handler = self.handlers[oid] except KeyError: @@ -363,32 +364,6 @@ def _decode_subject_information_access(backend, aia): return x509.SubjectInformationAccess(access_descriptions) -def _decode_key_usage(backend, bit_string): - bit_string = backend._ffi.cast("ASN1_BIT_STRING *", bit_string) - bit_string = backend._ffi.gc(bit_string, backend._lib.ASN1_BIT_STRING_free) - get_bit = backend._lib.ASN1_BIT_STRING_get_bit - digital_signature = get_bit(bit_string, 0) == 1 - content_commitment = get_bit(bit_string, 1) == 1 - key_encipherment = get_bit(bit_string, 2) == 1 - data_encipherment = get_bit(bit_string, 3) == 1 - key_agreement = get_bit(bit_string, 4) == 1 - key_cert_sign = get_bit(bit_string, 5) == 1 - crl_sign = get_bit(bit_string, 6) == 1 - encipher_only = get_bit(bit_string, 7) == 1 - decipher_only = get_bit(bit_string, 8) == 1 - return x509.KeyUsage( - digital_signature, - content_commitment, - key_encipherment, - data_encipherment, - key_agreement, - key_cert_sign, - crl_sign, - encipher_only, - decipher_only, - ) - - def _decode_general_names_extension(backend, gns): gns = backend._ffi.cast("GENERAL_NAMES *", gns) gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free) @@ -479,21 +454,6 @@ def _decode_policy_constraints(backend, pc): ) -def _decode_extended_key_usage(backend, sk): - sk = backend._ffi.cast("Cryptography_STACK_OF_ASN1_OBJECT *", sk) - sk = backend._ffi.gc(sk, backend._lib.sk_ASN1_OBJECT_free) - num = backend._lib.sk_ASN1_OBJECT_num(sk) - ekus = [] - - for i in range(num): - obj = backend._lib.sk_ASN1_OBJECT_value(sk, i) - backend.openssl_assert(obj != backend._ffi.NULL) - oid = x509.ObjectIdentifier(_obj2txt(backend, obj)) - ekus.append(oid) - - return x509.ExtendedKeyUsage(ekus) - - _DISTPOINT_TYPE_FULLNAME = 0 _DISTPOINT_TYPE_RELATIVENAME = 1 @@ -764,9 +724,7 @@ def _parse_asn1_generalized_time(backend, generalized_time): _EXTENSION_HANDLERS_BASE = { ExtensionOID.SUBJECT_KEY_IDENTIFIER: _decode_subject_key_identifier, - ExtensionOID.KEY_USAGE: _decode_key_usage, ExtensionOID.SUBJECT_ALTERNATIVE_NAME: _decode_subject_alt_name, - ExtensionOID.EXTENDED_KEY_USAGE: _decode_extended_key_usage, ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier, ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( _decode_authority_information_access diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index a8be601aedd5..a89c25e483c0 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -9,6 +9,8 @@ lazy_static::lazy_static! { static ref TLS_FEATURE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.1.24").unwrap(); static ref PRECERT_POISON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.4.1.11129.2.4.3").unwrap(); + static ref KEY_USAGE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.15").unwrap(); + static ref EXTENDED_KEY_USAGE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.37").unwrap(); static ref BASIC_CONSTRAINTS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.19").unwrap(); static ref CRL_REASON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.21").unwrap(); static ref CRL_NUMBER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.20").unwrap(); @@ -21,6 +23,16 @@ struct BasicConstraints { path_length: Option, } +fn get_bit(input: &[u8], n: usize) -> bool { + let idx = n / 8; + let v = 1 << (7 - (n & 0x07)); + if input.len() < (idx + 1) { + false + } else { + input[idx] & v != 0 + } +} + #[pyo3::prelude::pyfunction] fn parse_x509_extension( py: pyo3::Python<'_>, @@ -41,6 +53,42 @@ fn parse_x509_extension( features.append(py_feature)?; } Ok(x509_module.call1("TLSFeature", (features,))?.to_object(py)) + } else if oid == *EXTENDED_KEY_USAGE_OID { + let ekus = pyo3::types::PyList::empty(py); + for oid in asn1::parse_single::>(ext_data)? { + let oid_obj = x509_module.call_method1("ObjectIdentifier", (oid.to_string(),))?; + ekus.append(oid_obj)?; + } + Ok(x509_module + .call1("ExtendedKeyUsage", (ekus,))? + .to_object(py)) + } else if oid == *KEY_USAGE_OID { + let kus = asn1::parse_single::(ext_data)?.as_bytes(); + let digital_signature = get_bit(kus, 0); + let content_comitment = get_bit(kus, 1); + let key_encipherment = get_bit(kus, 2); + let data_encipherment = get_bit(kus, 3); + let key_agreement = get_bit(kus, 4); + let key_cert_sign = get_bit(kus, 5); + let crl_sign = get_bit(kus, 6); + let encipher_only = get_bit(kus, 7); + let decipher_only = get_bit(kus, 8); + Ok(x509_module + .call1( + "KeyUsage", + ( + digital_signature, + content_comitment, + key_encipherment, + data_encipherment, + key_agreement, + key_cert_sign, + crl_sign, + encipher_only, + decipher_only, + ), + )? + .to_object(py)) } else if oid == *PRECERT_POISON_OID { asn1::parse_single::<()>(ext_data)?; Ok(x509_module.call0("PrecertPoison")?.to_object(py)) From 686185003b03c9611fd31ba409d90d8080130f36 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 31 May 2021 15:33:25 -0500 Subject: [PATCH 0194/1456] oxidize OCSPNoCheck, DeltaCRLIndicator, InhibitAnyPolicy, and SubjectKeyIdentifier (#6082) * oxidize OCSPNoCheck * oxidize delta CRL indicator * oxidize inhibitanypolicy * oxidize SKI, cargo fmt --- .../hazmat/backends/openssl/decode_asn1.py | 31 ------------------- src/rust/src/x509.rs | 24 ++++++++++++++ 2 files changed, 24 insertions(+), 31 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 706baace55f4..9a566bf77b0f 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -159,16 +159,6 @@ def _decode_general_name(backend, gn): ) -def _decode_ocsp_no_check(backend, ext): - return x509.OCSPNoCheck() - - -def _decode_delta_crl_indicator(backend, ext): - asn1_int = backend._ffi.cast("ASN1_INTEGER *", ext) - asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free) - return x509.DeltaCRLIndicator(_asn1_integer_to_int(backend, asn1_int)) - - class _X509ExtensionParser(object): def __init__( self, backend, ext_count, get_ext, rust_callback, handlers={} @@ -297,16 +287,6 @@ def _decode_user_notice(backend, un): return x509.UserNotice(notice_reference, explicit_text) -def _decode_subject_key_identifier(backend, asn1_string): - asn1_string = backend._ffi.cast("ASN1_OCTET_STRING *", asn1_string) - asn1_string = backend._ffi.gc( - asn1_string, backend._lib.ASN1_OCTET_STRING_free - ) - return x509.SubjectKeyIdentifier( - backend._ffi.buffer(asn1_string.data, asn1_string.length)[:] - ) - - def _decode_authority_key_identifier(backend, akid): akid = backend._ffi.cast("AUTHORITY_KEYID *", akid) akid = backend._ffi.gc(akid, backend._lib.AUTHORITY_KEYID_free) @@ -559,13 +539,6 @@ def _decode_freshest_crl(backend, cdps): return x509.FreshestCRL(dist_points) -def _decode_inhibit_any_policy(backend, asn1_int): - asn1_int = backend._ffi.cast("ASN1_INTEGER *", asn1_int) - asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free) - skip_certs = _asn1_integer_to_int(backend, asn1_int) - return x509.InhibitAnyPolicy(skip_certs) - - def _decode_scts(backend, asn1_scts): from cryptography.hazmat.backends.openssl.x509 import ( _SignedCertificateTimestamp, @@ -723,7 +696,6 @@ def _parse_asn1_generalized_time(backend, generalized_time): _EXTENSION_HANDLERS_BASE = { - ExtensionOID.SUBJECT_KEY_IDENTIFIER: _decode_subject_key_identifier, ExtensionOID.SUBJECT_ALTERNATIVE_NAME: _decode_subject_alt_name, ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier, ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( @@ -735,8 +707,6 @@ def _parse_asn1_generalized_time(backend, generalized_time): ExtensionOID.CERTIFICATE_POLICIES: _decode_certificate_policies, ExtensionOID.CRL_DISTRIBUTION_POINTS: _decode_crl_distribution_points, ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, - ExtensionOID.OCSP_NO_CHECK: _decode_ocsp_no_check, - ExtensionOID.INHIBIT_ANY_POLICY: _decode_inhibit_any_policy, ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name, ExtensionOID.NAME_CONSTRAINTS: _decode_name_constraints, ExtensionOID.POLICY_CONSTRAINTS: _decode_policy_constraints, @@ -753,7 +723,6 @@ def _parse_asn1_generalized_time(backend, generalized_time): } _CRL_EXTENSION_HANDLERS = { - ExtensionOID.DELTA_CRL_INDICATOR: _decode_delta_crl_indicator, ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier, ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name, ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index a89c25e483c0..bcefde675c0d 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -8,12 +8,16 @@ use pyo3::conversion::ToPyObject; lazy_static::lazy_static! { static ref TLS_FEATURE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.1.24").unwrap(); static ref PRECERT_POISON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.4.1.11129.2.4.3").unwrap(); + static ref OCSP_NO_CHECK_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.48.1.5").unwrap(); static ref KEY_USAGE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.15").unwrap(); static ref EXTENDED_KEY_USAGE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.37").unwrap(); static ref BASIC_CONSTRAINTS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.19").unwrap(); + static ref SUBJECT_KEY_IDENTIFIER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.14").unwrap(); + static ref INHIBIT_ANY_POLICY_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.54").unwrap(); static ref CRL_REASON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.21").unwrap(); static ref CRL_NUMBER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.20").unwrap(); + static ref DELTA_CRL_INDICATOR_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.27").unwrap(); } #[derive(asn1::Asn1Read)] @@ -53,6 +57,11 @@ fn parse_x509_extension( features.append(py_feature)?; } Ok(x509_module.call1("TLSFeature", (features,))?.to_object(py)) + } else if oid == *SUBJECT_KEY_IDENTIFIER_OID { + let identifier = asn1::parse_single::<&[u8]>(ext_data)?; + Ok(x509_module + .call1("SubjectKeyIdentifier", (identifier,))? + .to_object(py)) } else if oid == *EXTENDED_KEY_USAGE_OID { let ekus = pyo3::types::PyList::empty(py); for oid in asn1::parse_single::>(ext_data)? { @@ -92,6 +101,15 @@ fn parse_x509_extension( } else if oid == *PRECERT_POISON_OID { asn1::parse_single::<()>(ext_data)?; Ok(x509_module.call0("PrecertPoison")?.to_object(py)) + } else if oid == *OCSP_NO_CHECK_OID { + asn1::parse_single::<()>(ext_data)?; + Ok(x509_module.call0("OCSPNoCheck")?.to_object(py)) + } else if oid == *INHIBIT_ANY_POLICY_OID { + let bignum = asn1::parse_single::(ext_data)?; + let pynum = big_asn1_uint_to_py(py, bignum)?; + Ok(x509_module + .call1("InhibitAnyPolicy", (pynum,))? + .to_object(py)) } else if oid == *BASIC_CONSTRAINTS_OID { let bc = asn1::parse_single::(ext_data)?; Ok(x509_module @@ -149,6 +167,12 @@ fn parse_crl_extension( let bignum = asn1::parse_single::(ext_data)?; let pynum = big_asn1_uint_to_py(py, bignum)?; Ok(x509_module.call1("CRLNumber", (pynum,))?.to_object(py)) + } else if oid == *DELTA_CRL_INDICATOR_OID { + let bignum = asn1::parse_single::(ext_data)?; + let pynum = big_asn1_uint_to_py(py, bignum)?; + Ok(x509_module + .call1("DeltaCRLIndicator", (pynum,))? + .to_object(py)) } else { Ok(py.None()) } From 144a39cfbe86b18e5f48548decd42e39a8d3437a Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 4 Jun 2021 22:15:25 -0500 Subject: [PATCH 0195/1456] oxidize policy constraints (#6087) * oxidize policy constraints * cargo fmt --- .../hazmat/backends/openssl/decode_asn1.py | 17 ----------------- src/rust/src/x509.rs | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 9a566bf77b0f..6a805e580957 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -418,22 +418,6 @@ def _decode_issuing_dist_point(backend, idp): ) -def _decode_policy_constraints(backend, pc): - pc = backend._ffi.cast("POLICY_CONSTRAINTS *", pc) - pc = backend._ffi.gc(pc, backend._lib.POLICY_CONSTRAINTS_free) - - require_explicit_policy = _asn1_integer_to_int_or_none( - backend, pc.requireExplicitPolicy - ) - inhibit_policy_mapping = _asn1_integer_to_int_or_none( - backend, pc.inhibitPolicyMapping - ) - - return x509.PolicyConstraints( - require_explicit_policy, inhibit_policy_mapping - ) - - _DISTPOINT_TYPE_FULLNAME = 0 _DISTPOINT_TYPE_RELATIVENAME = 1 @@ -709,7 +693,6 @@ def _parse_asn1_generalized_time(backend, generalized_time): ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name, ExtensionOID.NAME_CONSTRAINTS: _decode_name_constraints, - ExtensionOID.POLICY_CONSTRAINTS: _decode_policy_constraints, } _EXTENSION_HANDLERS_SCT = { ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: ( diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index bcefde675c0d..21f2a2d7fa25 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -11,6 +11,7 @@ lazy_static::lazy_static! { static ref OCSP_NO_CHECK_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.48.1.5").unwrap(); static ref KEY_USAGE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.15").unwrap(); + static ref POLICY_CONSTRAINTS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.36").unwrap(); static ref EXTENDED_KEY_USAGE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.37").unwrap(); static ref BASIC_CONSTRAINTS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.19").unwrap(); static ref SUBJECT_KEY_IDENTIFIER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.14").unwrap(); @@ -27,6 +28,14 @@ struct BasicConstraints { path_length: Option, } +#[derive(asn1::Asn1Read)] +struct PolicyConstraints { + #[implicit(0)] + require_explicit_policy: Option, + #[implicit(1)] + inhibit_policy_mapping: Option, +} + fn get_bit(input: &[u8], n: usize) -> bool { let idx = n / 8; let v = 1 << (7 - (n & 0x07)); @@ -98,6 +107,14 @@ fn parse_x509_extension( ), )? .to_object(py)) + } else if oid == *POLICY_CONSTRAINTS_OID { + let pc = asn1::parse_single::(ext_data)?; + Ok(x509_module + .call1( + "PolicyConstraints", + (pc.require_explicit_policy, pc.inhibit_policy_mapping), + )? + .to_object(py)) } else if oid == *PRECERT_POISON_OID { asn1::parse_single::<()>(ext_data)?; Ok(x509_module.call0("PrecertPoison")?.to_object(py)) From a85e7c6fb7734734de16925749bb51b3ce842c39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 6 Jun 2021 19:51:53 -0400 Subject: [PATCH 0196/1456] Bump asn1 from 0.5.0 to 0.5.1 in /src/rust (#6091) Bumps [asn1](https://github.com/alex/rust-asn1) from 0.5.0 to 0.5.1. - [Release notes](https://github.com/alex/rust-asn1/releases) - [Commits](https://github.com/alex/rust-asn1/compare/0.5.0...0.5.1) --- updated-dependencies: - dependency-name: asn1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 8 ++++---- src/rust/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index c1a44b7e3077..240d2b1c124a 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -10,9 +10,9 @@ checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" [[package]] name = "asn1" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b0b5d36e3f25768cc488c4aff0e38c645b34d30552e5739aed33ebdd02b2c31" +checksum = "f4e2ec2f073674e49321449dbfd51accb77effab6ade9f311f0f631903d20c39" dependencies = [ "asn1_derive", "chrono", @@ -20,9 +20,9 @@ dependencies = [ [[package]] name = "asn1_derive" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be4b1a957d65a39deba1154b39d0ee6806705ed293c43dcb2ec9ab71a95c889" +checksum = "18175ce37dddb6ef19f30996c31f63b38571fea8351f321088181cd089efd203" dependencies = [ "proc-macro2", "quote", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 824fe1cf2a2a..e70b20865346 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] lazy_static = "1" pyo3 = { version = "0.13.1" } -asn1 = { version = "0.5.0", default-features = false, features = ["derive"] } +asn1 = { version = "0.5.1", default-features = false, features = ["derive"] } ouroboros = "0.9" [features] From 60f5f9ff9beb41f662b23be243aba7a327883af4 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 7 Jun 2021 08:55:36 -0400 Subject: [PATCH 0197/1456] Use the new BitString::has_bit_set API (#6092) * Use the new BitString::has_bit_set API * poke GHA --- src/rust/src/x509.rs | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index 21f2a2d7fa25..8d1221187673 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -36,16 +36,6 @@ struct PolicyConstraints { inhibit_policy_mapping: Option, } -fn get_bit(input: &[u8], n: usize) -> bool { - let idx = n / 8; - let v = 1 << (7 - (n & 0x07)); - if input.len() < (idx + 1) { - false - } else { - input[idx] & v != 0 - } -} - #[pyo3::prelude::pyfunction] fn parse_x509_extension( py: pyo3::Python<'_>, @@ -81,16 +71,16 @@ fn parse_x509_extension( .call1("ExtendedKeyUsage", (ekus,))? .to_object(py)) } else if oid == *KEY_USAGE_OID { - let kus = asn1::parse_single::(ext_data)?.as_bytes(); - let digital_signature = get_bit(kus, 0); - let content_comitment = get_bit(kus, 1); - let key_encipherment = get_bit(kus, 2); - let data_encipherment = get_bit(kus, 3); - let key_agreement = get_bit(kus, 4); - let key_cert_sign = get_bit(kus, 5); - let crl_sign = get_bit(kus, 6); - let encipher_only = get_bit(kus, 7); - let decipher_only = get_bit(kus, 8); + let kus = asn1::parse_single::(ext_data)?; + let digital_signature = kus.has_bit_set(0); + let content_comitment = kus.has_bit_set(1); + let key_encipherment = kus.has_bit_set(2); + let data_encipherment = kus.has_bit_set(3); + let key_agreement = kus.has_bit_set(4); + let key_cert_sign = kus.has_bit_set(5); + let crl_sign = kus.has_bit_set(6); + let encipher_only = kus.has_bit_set(7); + let decipher_only = kus.has_bit_set(8); Ok(x509_module .call1( "KeyUsage", From c2ba1fe7b0e446fa6a0191032723fac15bdf2ac8 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 7 Jun 2021 10:23:32 -0500 Subject: [PATCH 0198/1456] oxidize SubjectAltName (#6089) * oxidize SubjectAltName This encompasses oxidizing parsing of GeneralName, which most of the remaining extensions need * empty commit for codecov --- .../hazmat/backends/openssl/decode_asn1.py | 82 +++------ src/cryptography/x509/general_name.py | 4 +- src/rust/src/asn1.rs | 8 +- src/rust/src/x509.rs | 162 +++++++++++++++++- tests/x509/test_x509_ext.py | 4 +- 5 files changed, 192 insertions(+), 68 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 6a805e580957..0248585556bd 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -81,6 +81,10 @@ def _decode_general_names(backend, gns): return names +# This is now a hacked up decoder where we progressively remove chunks as +# we port more and more to rust. SAN exercised every branch in this, but +# other extensions (which are still in Python/OpenSSL) don't so we'll remove +# anything that isn't covered progressively until we remove the entire function def _decode_general_name(backend, gn): if gn.type == backend._lib.GEN_DNS: # Convert to bytes and then decode to utf8. We don't use @@ -102,41 +106,37 @@ def _decode_general_name(backend, gn): # This allows us to create URI objects that have unicode chars # when a certificate (against the RFC) contains them. return x509.UniformResourceIdentifier._init_without_validation(data) - elif gn.type == backend._lib.GEN_RID: - oid = _obj2txt(backend, gn.d.registeredID) - return x509.RegisteredID(x509.ObjectIdentifier(oid)) elif gn.type == backend._lib.GEN_IPADD: data = _asn1_string_to_bytes(backend, gn.d.iPAddress) data_len = len(data) - if data_len == 8 or data_len == 32: - # This is an IPv4 or IPv6 Network and not a single IP. This - # type of data appears in Name Constraints. Unfortunately, - # ipaddress doesn't support packed bytes + netmask. Additionally, - # IPv6Network can only handle CIDR rather than the full 16 byte - # netmask. To handle this we convert the netmask to integer, then - # find the first 0 bit, which will be the prefix. If another 1 - # bit is present after that the netmask is invalid. - base = ipaddress.ip_address(data[: data_len // 2]) - netmask = ipaddress.ip_address(data[data_len // 2 :]) - bits = bin(int(netmask))[2:] - prefix = bits.find("0") - # If no 0 bits are found it is a /32 or /128 - if prefix == -1: - prefix = len(bits) - - if "1" in bits[prefix:]: - raise ValueError("Invalid netmask") - - ip = ipaddress.ip_network(base.exploded + "/{}".format(prefix)) - else: - ip = ipaddress.ip_address(data) + assert data_len == 8 or data_len == 32 + # This is an IPv4 or IPv6 Network and not a single IP. This + # type of data appears in Name Constraints. Unfortunately, + # ipaddress doesn't support packed bytes + netmask. Additionally, + # IPv6Network can only handle CIDR rather than the full 16 byte + # netmask. To handle this we convert the netmask to integer, then + # find the first 0 bit, which will be the prefix. If another 1 + # bit is present after that the netmask is invalid. + base = ipaddress.ip_address(data[: data_len // 2]) + netmask = ipaddress.ip_address(data[data_len // 2 :]) + bits = bin(int(netmask))[2:] + prefix = bits.find("0") + # If no 0 bits are found it is a /32 or /128 + if prefix == -1: + prefix = len(bits) + + if "1" in bits[prefix:]: + raise ValueError("Invalid netmask") + + ip = ipaddress.ip_network(base.exploded + "/{}".format(prefix)) return x509.IPAddress(ip) elif gn.type == backend._lib.GEN_DIRNAME: return x509.DirectoryName( _decode_x509_name(backend, gn.d.directoryName) ) - elif gn.type == backend._lib.GEN_EMAIL: + else: + assert gn.type == backend._lib.GEN_EMAIL # Convert to bytes and then decode to utf8. We don't use # asn1_string_to_utf8 here because it doesn't properly convert # utf8 from ia5strings. @@ -145,18 +145,6 @@ def _decode_general_name(backend, gn): # validation. This allows us to create RFC822Name objects that have # unicode chars when a certificate (against the RFC) contains them. return x509.RFC822Name._init_without_validation(data) - elif gn.type == backend._lib.GEN_OTHERNAME: - type_id = _obj2txt(backend, gn.d.otherName.type_id) - value = _asn1_to_der(backend, gn.d.otherName.value) - return x509.OtherName(x509.ObjectIdentifier(type_id), value) - else: - # x400Address or ediPartyName - raise x509.UnsupportedGeneralNameType( - "{} is not a supported type".format( - x509._GENERAL_NAMES.get(gn.type, gn.type) - ), - gn.type, - ) class _X509ExtensionParser(object): @@ -351,12 +339,6 @@ def _decode_general_names_extension(backend, gns): return general_names -def _decode_subject_alt_name(backend, ext): - return x509.SubjectAlternativeName( - _decode_general_names_extension(backend, ext) - ) - - def _decode_issuer_alt_name(backend, ext): return x509.IssuerAlternativeName( _decode_general_names_extension(backend, ext) @@ -606,17 +588,6 @@ def _decode_cert_issuer(backend, gns): return x509.CertificateIssuer(general_names) -def _asn1_to_der(backend, asn1_type): - buf = backend._ffi.new("unsigned char **") - res = backend._lib.i2d_ASN1_TYPE(asn1_type, buf) - backend.openssl_assert(res >= 0) - backend.openssl_assert(buf[0] != backend._ffi.NULL) - buf = backend._ffi.gc( - buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0]) - ) - return backend._ffi.buffer(buf[0], res)[:] - - def _asn1_integer_to_int(backend, asn1_int): bn = backend._lib.ASN1_INTEGER_to_BN(asn1_int, backend._ffi.NULL) backend.openssl_assert(bn != backend._ffi.NULL) @@ -680,7 +651,6 @@ def _parse_asn1_generalized_time(backend, generalized_time): _EXTENSION_HANDLERS_BASE = { - ExtensionOID.SUBJECT_ALTERNATIVE_NAME: _decode_subject_alt_name, ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier, ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( _decode_authority_information_access diff --git a/src/cryptography/x509/general_name.py b/src/cryptography/x509/general_name.py index d49582c41e11..66890550d073 100644 --- a/src/cryptography/x509/general_name.py +++ b/src/cryptography/x509/general_name.py @@ -32,9 +32,7 @@ class UnsupportedGeneralNameType(Exception): - def __init__(self, msg: str, type: int) -> None: - super(UnsupportedGeneralNameType, self).__init__(msg) - self.type = type + pass class GeneralName(metaclass=abc.ABCMeta): diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 08c22790506b..706ced54d9b3 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -173,12 +173,12 @@ struct TbsCertificate<'a> { _extensions: Option>, } -type Name<'a> = asn1::SequenceOf<'a, asn1::SetOf<'a, AttributeTypeValue<'a>>>; +pub(crate) type Name<'a> = asn1::SequenceOf<'a, asn1::SetOf<'a, AttributeTypeValue<'a>>>; #[derive(asn1::Asn1Read)] -struct AttributeTypeValue<'a> { - _type: asn1::ObjectIdentifier<'a>, - value: asn1::Tlv<'a>, +pub(crate) struct AttributeTypeValue<'a> { + pub(crate) type_id: asn1::ObjectIdentifier<'a>, + pub(crate) value: asn1::Tlv<'a>, } #[derive(asn1::Asn1Read)] diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index 8d1221187673..588c45d2a610 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -2,7 +2,7 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::{big_asn1_uint_to_py, PyAsn1Error}; +use crate::asn1::{big_asn1_uint_to_py, AttributeTypeValue, Name, PyAsn1Error}; use pyo3::conversion::ToPyObject; lazy_static::lazy_static! { @@ -19,6 +19,51 @@ lazy_static::lazy_static! { static ref CRL_REASON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.21").unwrap(); static ref CRL_NUMBER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.20").unwrap(); static ref DELTA_CRL_INDICATOR_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.27").unwrap(); + static ref SUBJECT_ALTERNATIVE_NAME_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.17").unwrap(); +} + +struct UnvalidatedIA5String<'a>(&'a str); + +impl<'a> asn1::SimpleAsn1Readable<'a> for UnvalidatedIA5String<'a> { + const TAG: u8 = 0x16; + fn parse_data(data: &'a [u8]) -> asn1::ParseResult { + Ok(UnvalidatedIA5String( + std::str::from_utf8(data).map_err(|_| asn1::ParseError::InvalidValue)?, + )) + } +} + +#[derive(asn1::Asn1Read)] +enum GeneralName<'a> { + #[implicit(0)] + OtherName(AttributeTypeValue<'a>), + + #[implicit(1)] + RFC822Name(UnvalidatedIA5String<'a>), + + #[implicit(2)] + DNSName(UnvalidatedIA5String<'a>), + + #[implicit(3)] + // unsupported + X400Address(asn1::Sequence<'a>), + + // Name is explicit per RFC 5280 Appendix A.1. + #[explicit(4)] + DirectoryName(Name<'a>), + + #[implicit(5)] + // unsupported + EDIPartyName(asn1::Sequence<'a>), + + #[implicit(6)] + UniformResourceIdentifier(UnvalidatedIA5String<'a>), + + #[implicit(7)] + IPAddress(&'a [u8]), + + #[implicit(8)] + RegisteredID(asn1::ObjectIdentifier<'a>), } #[derive(asn1::Asn1Read)] @@ -36,6 +81,114 @@ struct PolicyConstraints { inhibit_policy_mapping: Option, } +fn parse_name_attribute( + py: pyo3::Python<'_>, + attribute: AttributeTypeValue, +) -> Result { + let x509_module = py.import("cryptography.x509")?; + let oid = x509_module + .call_method1("ObjectIdentifier", (attribute.type_id.to_string(),))? + .to_object(py); + let tag_enum = py + .import("cryptography.x509.name")? + .getattr("_ASN1_TYPE_TO_ENUM")?; + let py_tag = tag_enum.get_item(attribute.value.tag().to_object(py))?; + let py_data = + std::str::from_utf8(attribute.value.data()).map_err(|_| asn1::ParseError::InvalidValue)?; + Ok(x509_module + .call_method1("NameAttribute", (oid, py_data, py_tag))? + .to_object(py)) +} + +fn parse_name(py: pyo3::Python<'_>, name: Name) -> Result { + let x509_module = py.import("cryptography.x509")?; + let py_rdns = pyo3::types::PyList::empty(py); + for rdn in name { + let py_attrs = pyo3::types::PySet::empty(py)?; + for attribute in rdn { + let na = parse_name_attribute(py, attribute)?; + py_attrs.add(na)?; + } + let py_rdn = x509_module + .call_method1("RelativeDistinguishedName", (py_attrs,))? + .to_object(py); + py_rdns.append(py_rdn)?; + } + let py_name = x509_module.call_method1("Name", (py_rdns,))?.to_object(py); + Ok(py_name) +} + +fn parse_general_name( + py: pyo3::Python<'_>, + gn: GeneralName, +) -> Result { + let x509_module = py.import("cryptography.x509")?; + let py_gn = match gn { + GeneralName::OtherName(data) => { + let oid = x509_module + .call_method1("ObjectIdentifier", (data.type_id.to_string(),))? + .to_object(py); + x509_module + .call_method1("OtherName", (oid, data.value.data()))? + .to_object(py) + } + GeneralName::RFC822Name(data) => x509_module + .getattr("RFC822Name")? + .call_method1("_init_without_validation", (data.0,))? + .to_object(py), + GeneralName::DNSName(data) => x509_module + .getattr("DNSName")? + .call_method1("_init_without_validation", (data.0,))? + .to_object(py), + GeneralName::DirectoryName(data) => { + let py_name = parse_name(py, data)?; + x509_module + .call_method1("DirectoryName", (py_name,))? + .to_object(py) + } + GeneralName::UniformResourceIdentifier(data) => x509_module + .getattr("UniformResourceIdentifier")? + .call_method1("_init_without_validation", (data.0,))? + .to_object(py), + GeneralName::IPAddress(data) => { + let ip_module = py.import("ipaddress")?; + let ip_addr = ip_module.call_method1("ip_address", (data,))?.to_object(py); + x509_module + .call_method1("IPAddress", (ip_addr,))? + .to_object(py) + } + GeneralName::RegisteredID(data) => { + let oid = x509_module + .call_method1("ObjectIdentifier", (data.to_string(),))? + .to_object(py); + x509_module + .call_method1("RegisteredID", (oid,))? + .to_object(py) + } + _ => { + return Err(PyAsn1Error::from(pyo3::PyErr::from_instance( + x509_module.call_method1( + "UnsupportedGeneralNameType", + ("x400Address/EDIPartyName are not supported types",), + )?, + ))) + } + }; + Ok(py_gn) +} + +fn parse_general_names( + py: pyo3::Python<'_>, + ext_data: &[u8], +) -> Result { + let gns = pyo3::types::PyList::empty(py); + for gn in asn1::parse_single::>(ext_data)? { + let py_gn = parse_general_name(py, gn)?; + gns.append(py_gn)?; + } + Ok(gns.to_object(py)) +} + #[pyo3::prelude::pyfunction] fn parse_x509_extension( py: pyo3::Python<'_>, @@ -45,7 +198,12 @@ fn parse_x509_extension( let oid = asn1::ObjectIdentifier::from_der(der_oid).unwrap(); let x509_module = py.import("cryptography.x509")?; - if oid == *TLS_FEATURE_OID { + if oid == *SUBJECT_ALTERNATIVE_NAME_OID { + let sans = parse_general_names(py, ext_data)?; + Ok(x509_module + .call1("SubjectAlternativeName", (sans,))? + .to_object(py)) + } else if oid == *TLS_FEATURE_OID { let tls_feature_type_to_enum = py .import("cryptography.x509.extensions")? .getattr("_TLS_FEATURE_TYPE_TO_ENUM")?; diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index 9d2585c9ef5e..67011d09cd10 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -2296,11 +2296,9 @@ def test_unsupported_gn(self, backend): x509.load_der_x509_certificate, backend, ) - with pytest.raises(x509.UnsupportedGeneralNameType) as exc: + with pytest.raises(x509.UnsupportedGeneralNameType): cert.extensions - assert exc.value.type == 3 - def test_registered_id(self, backend): cert = _load_cert( os.path.join("x509", "custom", "san_registered_id.pem"), From 8f433233e844da1befa201d8e1634d3829a1d31b Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 7 Jun 2021 11:15:00 -0500 Subject: [PATCH 0199/1456] oxidize cert issuer, IAN, AIA, SIA (#6093) * oxidize cert issuer * WIP: oxidize IAN (needs vector for CRL) * oxidize authorityinfoaccess and subjectinfoaccess * no longer need email path in SAN parser * cargo fmt --- .../hazmat/backends/openssl/decode_asn1.py | 72 +------------------ src/rust/src/x509.rs | 59 +++++++++++++++ 2 files changed, 61 insertions(+), 70 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 0248585556bd..035f084a817d 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -131,20 +131,11 @@ def _decode_general_name(backend, gn): ip = ipaddress.ip_network(base.exploded + "/{}".format(prefix)) return x509.IPAddress(ip) - elif gn.type == backend._lib.GEN_DIRNAME: + else: + assert gn.type == backend._lib.GEN_DIRNAME return x509.DirectoryName( _decode_x509_name(backend, gn.d.directoryName) ) - else: - assert gn.type == backend._lib.GEN_EMAIL - # Convert to bytes and then decode to utf8. We don't use - # asn1_string_to_utf8 here because it doesn't properly convert - # utf8 from ia5strings. - data = _asn1_string_to_bytes(backend, gn.d.rfc822Name).decode("utf8") - # We don't use the constructor for RFC822Name so we can bypass - # validation. This allows us to create RFC822Name objects that have - # unicode chars when a certificate (against the RFC) contains them. - return x509.RFC822Name._init_without_validation(data) class _X509ExtensionParser(object): @@ -298,40 +289,6 @@ def _decode_authority_key_identifier(backend, akid): ) -def _decode_information_access(backend, ia): - ia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", ia) - ia = backend._ffi.gc( - ia, - lambda x: backend._lib.sk_ACCESS_DESCRIPTION_pop_free( - x, - backend._ffi.addressof( - backend._lib._original_lib, "ACCESS_DESCRIPTION_free" - ), - ), - ) - num = backend._lib.sk_ACCESS_DESCRIPTION_num(ia) - access_descriptions = [] - for i in range(num): - ad = backend._lib.sk_ACCESS_DESCRIPTION_value(ia, i) - backend.openssl_assert(ad.method != backend._ffi.NULL) - oid = x509.ObjectIdentifier(_obj2txt(backend, ad.method)) - backend.openssl_assert(ad.location != backend._ffi.NULL) - gn = _decode_general_name(backend, ad.location) - access_descriptions.append(x509.AccessDescription(oid, gn)) - - return access_descriptions - - -def _decode_authority_information_access(backend, aia): - access_descriptions = _decode_information_access(backend, aia) - return x509.AuthorityInformationAccess(access_descriptions) - - -def _decode_subject_information_access(backend, aia): - access_descriptions = _decode_information_access(backend, aia) - return x509.SubjectInformationAccess(access_descriptions) - - def _decode_general_names_extension(backend, gns): gns = backend._ffi.cast("GENERAL_NAMES *", gns) gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free) @@ -339,12 +296,6 @@ def _decode_general_names_extension(backend, gns): return general_names -def _decode_issuer_alt_name(backend, ext): - return x509.IssuerAlternativeName( - _decode_general_names_extension(backend, ext) - ) - - def _decode_name_constraints(backend, nc): nc = backend._ffi.cast("NAME_CONSTRAINTS *", nc) nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free) @@ -581,13 +532,6 @@ def _decode_invalidity_date(backend, inv_date): ) -def _decode_cert_issuer(backend, gns): - gns = backend._ffi.cast("GENERAL_NAMES *", gns) - gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free) - general_names = _decode_general_names(backend, gns) - return x509.CertificateIssuer(general_names) - - def _asn1_integer_to_int(backend, asn1_int): bn = backend._lib.ASN1_INTEGER_to_BN(asn1_int, backend._ffi.NULL) backend.openssl_assert(bn != backend._ffi.NULL) @@ -652,16 +596,9 @@ def _parse_asn1_generalized_time(backend, generalized_time): _EXTENSION_HANDLERS_BASE = { ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier, - ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( - _decode_authority_information_access - ), - ExtensionOID.SUBJECT_INFORMATION_ACCESS: ( - _decode_subject_information_access - ), ExtensionOID.CERTIFICATE_POLICIES: _decode_certificate_policies, ExtensionOID.CRL_DISTRIBUTION_POINTS: _decode_crl_distribution_points, ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, - ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name, ExtensionOID.NAME_CONSTRAINTS: _decode_name_constraints, } _EXTENSION_HANDLERS_SCT = { @@ -672,15 +609,10 @@ def _parse_asn1_generalized_time(backend, generalized_time): _REVOKED_EXTENSION_HANDLERS = { CRLEntryExtensionOID.INVALIDITY_DATE: _decode_invalidity_date, - CRLEntryExtensionOID.CERTIFICATE_ISSUER: _decode_cert_issuer, } _CRL_EXTENSION_HANDLERS = { ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier, - ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name, - ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( - _decode_authority_information_access - ), ExtensionOID.ISSUING_DISTRIBUTION_POINT: _decode_issuing_dist_point, ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, } diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index 588c45d2a610..6db28400e119 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -9,6 +9,8 @@ lazy_static::lazy_static! { static ref TLS_FEATURE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.1.24").unwrap(); static ref PRECERT_POISON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.4.1.11129.2.4.3").unwrap(); static ref OCSP_NO_CHECK_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.48.1.5").unwrap(); + static ref AUTHORITY_INFORMATION_ACCESS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.1.1").unwrap(); + static ref SUBJECT_INFORMATION_ACCESS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.1.11").unwrap(); static ref KEY_USAGE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.15").unwrap(); static ref POLICY_CONSTRAINTS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.36").unwrap(); @@ -17,9 +19,11 @@ lazy_static::lazy_static! { static ref SUBJECT_KEY_IDENTIFIER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.14").unwrap(); static ref INHIBIT_ANY_POLICY_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.54").unwrap(); static ref CRL_REASON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.21").unwrap(); + static ref CERTIFICATE_ISSUER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.29").unwrap(); static ref CRL_NUMBER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.20").unwrap(); static ref DELTA_CRL_INDICATOR_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.27").unwrap(); static ref SUBJECT_ALTERNATIVE_NAME_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.17").unwrap(); + static ref ISSUER_ALTERNATIVE_NAME_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.18").unwrap(); } struct UnvalidatedIA5String<'a>(&'a str); @@ -81,6 +85,12 @@ struct PolicyConstraints { inhibit_policy_mapping: Option, } +#[derive(asn1::Asn1Read)] +struct AccessDescription<'a> { + access_method: asn1::ObjectIdentifier<'a>, + access_location: GeneralName<'a>, +} + fn parse_name_attribute( py: pyo3::Python<'_>, attribute: AttributeTypeValue, @@ -189,6 +199,25 @@ fn parse_general_names( Ok(gns.to_object(py)) } +fn parse_access_descriptions( + py: pyo3::Python<'_>, + ext_data: &[u8], +) -> Result { + let x509_module = py.import("cryptography.x509")?; + let ads = pyo3::types::PyList::empty(py); + for access in asn1::parse_single::>(ext_data)? { + let py_oid = x509_module + .call_method1("ObjectIdentifier", (access.access_method.to_string(),))? + .to_object(py); + let gn = parse_general_name(py, access.access_location)?; + let ad = x509_module + .call1("AccessDescription", (py_oid, gn))? + .to_object(py); + ads.append(ad)?; + } + Ok(ads.to_object(py)) +} + #[pyo3::prelude::pyfunction] fn parse_x509_extension( py: pyo3::Python<'_>, @@ -203,6 +232,11 @@ fn parse_x509_extension( Ok(x509_module .call1("SubjectAlternativeName", (sans,))? .to_object(py)) + } else if oid == *ISSUER_ALTERNATIVE_NAME_OID { + let ians = parse_general_names(py, ext_data)?; + Ok(x509_module + .call1("IssuerAlternativeName", (ians,))? + .to_object(py)) } else if oid == *TLS_FEATURE_OID { let tls_feature_type_to_enum = py .import("cryptography.x509.extensions")? @@ -255,6 +289,16 @@ fn parse_x509_extension( ), )? .to_object(py)) + } else if oid == *AUTHORITY_INFORMATION_ACCESS_OID { + let ads = parse_access_descriptions(py, ext_data)?; + Ok(x509_module + .call1("AuthorityInformationAccess", (ads,))? + .to_object(py)) + } else if oid == *SUBJECT_INFORMATION_ACCESS_OID { + let ads = parse_access_descriptions(py, ext_data)?; + Ok(x509_module + .call1("SubjectInformationAccess", (ads,))? + .to_object(py)) } else if oid == *POLICY_CONSTRAINTS_OID { let pc = asn1::parse_single::(ext_data)?; Ok(x509_module @@ -314,6 +358,11 @@ fn parse_crl_entry_extension( }; let flag = x509_module.getattr("ReasonFlags")?.getattr(flag_name)?; Ok(x509_module.call1("CRLReason", (flag,))?.to_object(py)) + } else if oid == *CERTIFICATE_ISSUER_OID { + let gns = parse_general_names(py, ext_data)?; + Ok(x509_module + .call1("CertificateIssuer", (gns,))? + .to_object(py)) } else { Ok(py.None()) } @@ -338,6 +387,16 @@ fn parse_crl_extension( Ok(x509_module .call1("DeltaCRLIndicator", (pynum,))? .to_object(py)) + } else if oid == *ISSUER_ALTERNATIVE_NAME_OID { + let ians = parse_general_names(py, ext_data)?; + Ok(x509_module + .call1("IssuerAlternativeName", (ians,))? + .to_object(py)) + } else if oid == *AUTHORITY_INFORMATION_ACCESS_OID { + let ads = parse_access_descriptions(py, ext_data)?; + Ok(x509_module + .call1("AuthorityInformationAccess", (ads,))? + .to_object(py)) } else { Ok(py.None()) } From 63bfe529da518dbf8a2de0fa45c4fb6c5e410b9a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 7 Jun 2021 13:24:41 -0400 Subject: [PATCH 0200/1456] remove dead function (#6094) --- src/cryptography/hazmat/backends/openssl/decode_asn1.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 035f084a817d..c947de11d88a 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -289,13 +289,6 @@ def _decode_authority_key_identifier(backend, akid): ) -def _decode_general_names_extension(backend, gns): - gns = backend._ffi.cast("GENERAL_NAMES *", gns) - gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free) - general_names = _decode_general_names(backend, gns) - return general_names - - def _decode_name_constraints(backend, nc): nc = backend._ffi.cast("NAME_CONSTRAINTS *", nc) nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free) From 69bafedf7d3d16af9c75e3929c728b7353af30e3 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 7 Jun 2021 22:05:43 -0500 Subject: [PATCH 0201/1456] oxidize authoritykeyidentifier (#6096) * oxidize authoritykeyidentifier * cargo fmt * Apply suggestions from code review Co-authored-by: Alex Gaynor * coverage Co-authored-by: Alex Gaynor --- .../hazmat/backends/openssl/decode_asn1.py | 32 ----------- src/rust/src/x509.rs | 55 ++++++++++++++++--- 2 files changed, 48 insertions(+), 39 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index c947de11d88a..8b2bc6aa46c6 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -266,29 +266,6 @@ def _decode_user_notice(backend, un): return x509.UserNotice(notice_reference, explicit_text) -def _decode_authority_key_identifier(backend, akid): - akid = backend._ffi.cast("AUTHORITY_KEYID *", akid) - akid = backend._ffi.gc(akid, backend._lib.AUTHORITY_KEYID_free) - key_identifier = None - authority_cert_issuer = None - - if akid.keyid != backend._ffi.NULL: - key_identifier = backend._ffi.buffer( - akid.keyid.data, akid.keyid.length - )[:] - - if akid.issuer != backend._ffi.NULL: - authority_cert_issuer = _decode_general_names(backend, akid.issuer) - - authority_cert_serial_number = _asn1_integer_to_int_or_none( - backend, akid.serial - ) - - return x509.AuthorityKeyIdentifier( - key_identifier, authority_cert_issuer, authority_cert_serial_number - ) - - def _decode_name_constraints(backend, nc): nc = backend._ffi.cast("NAME_CONSTRAINTS *", nc) nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free) @@ -532,13 +509,6 @@ def _asn1_integer_to_int(backend, asn1_int): return backend._bn_to_int(bn) -def _asn1_integer_to_int_or_none(backend, asn1_int): - if asn1_int == backend._ffi.NULL: - return None - else: - return _asn1_integer_to_int(backend, asn1_int) - - def _asn1_string_to_bytes(backend, asn1_string): return backend._ffi.buffer(asn1_string.data, asn1_string.length)[:] @@ -588,7 +558,6 @@ def _parse_asn1_generalized_time(backend, generalized_time): _EXTENSION_HANDLERS_BASE = { - ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier, ExtensionOID.CERTIFICATE_POLICIES: _decode_certificate_policies, ExtensionOID.CRL_DISTRIBUTION_POINTS: _decode_crl_distribution_points, ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, @@ -605,7 +574,6 @@ def _parse_asn1_generalized_time(backend, generalized_time): } _CRL_EXTENSION_HANDLERS = { - ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier, ExtensionOID.ISSUING_DISTRIBUTION_POINT: _decode_issuing_dist_point, ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, } diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index 6db28400e119..3e64e1e2e524 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -14,6 +14,7 @@ lazy_static::lazy_static! { static ref KEY_USAGE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.15").unwrap(); static ref POLICY_CONSTRAINTS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.36").unwrap(); + static ref AUTHORITY_KEY_IDENTIFIER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.35").unwrap(); static ref EXTENDED_KEY_USAGE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.37").unwrap(); static ref BASIC_CONSTRAINTS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.19").unwrap(); static ref SUBJECT_KEY_IDENTIFIER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.14").unwrap(); @@ -37,6 +38,16 @@ impl<'a> asn1::SimpleAsn1Readable<'a> for UnvalidatedIA5String<'a> { } } +#[derive(asn1::Asn1Read)] +struct AuthorityKeyIdentifier<'a> { + #[implicit(0)] + key_identifier: Option<&'a [u8]>, + #[implicit(1)] + authority_cert_issuer: Option>>, + #[implicit(2)] + authority_cert_serial_number: Option>, +} + #[derive(asn1::Asn1Read)] enum GeneralName<'a> { #[implicit(0)] @@ -91,6 +102,28 @@ struct AccessDescription<'a> { access_location: GeneralName<'a>, } +fn parse_authority_key_identifier( + py: pyo3::Python<'_>, + ext_data: &[u8], +) -> Result { + let x509_module = py.import("cryptography.x509")?; + let aki = asn1::parse_single::(ext_data)?; + let serial = match aki.authority_cert_serial_number { + Some(biguint) => big_asn1_uint_to_py(py, biguint)?.to_object(py), + None => py.None(), + }; + let issuer = match aki.authority_cert_issuer { + Some(aci) => parse_general_names(py, aci)?, + None => py.None(), + }; + Ok(x509_module + .call1( + "AuthorityKeyIdentifier", + (aki.key_identifier, issuer, serial), + )? + .to_object(py)) +} + fn parse_name_attribute( py: pyo3::Python<'_>, attribute: AttributeTypeValue, @@ -187,12 +220,12 @@ fn parse_general_name( Ok(py_gn) } -fn parse_general_names( +fn parse_general_names<'a>( py: pyo3::Python<'_>, - ext_data: &[u8], + gn_seq: asn1::SequenceOf<'a, GeneralName<'a>>, ) -> Result { let gns = pyo3::types::PyList::empty(py); - for gn in asn1::parse_single::>(ext_data)? { + for gn in gn_seq { let py_gn = parse_general_name(py, gn)?; gns.append(py_gn)?; } @@ -228,12 +261,14 @@ fn parse_x509_extension( let x509_module = py.import("cryptography.x509")?; if oid == *SUBJECT_ALTERNATIVE_NAME_OID { - let sans = parse_general_names(py, ext_data)?; + let gn_seq = asn1::parse_single::>(ext_data)?; + let sans = parse_general_names(py, gn_seq)?; Ok(x509_module .call1("SubjectAlternativeName", (sans,))? .to_object(py)) } else if oid == *ISSUER_ALTERNATIVE_NAME_OID { - let ians = parse_general_names(py, ext_data)?; + let gn_seq = asn1::parse_single::>(ext_data)?; + let ians = parse_general_names(py, gn_seq)?; Ok(x509_module .call1("IssuerAlternativeName", (ians,))? .to_object(py)) @@ -324,6 +359,8 @@ fn parse_x509_extension( Ok(x509_module .call1("BasicConstraints", (bc.ca, bc.path_length))? .to_object(py)) + } else if oid == *AUTHORITY_KEY_IDENTIFIER_OID { + Ok(parse_authority_key_identifier(py, ext_data)?) } else { Ok(py.None()) } @@ -359,7 +396,8 @@ fn parse_crl_entry_extension( let flag = x509_module.getattr("ReasonFlags")?.getattr(flag_name)?; Ok(x509_module.call1("CRLReason", (flag,))?.to_object(py)) } else if oid == *CERTIFICATE_ISSUER_OID { - let gns = parse_general_names(py, ext_data)?; + let gn_seq = asn1::parse_single::>(ext_data)?; + let gns = parse_general_names(py, gn_seq)?; Ok(x509_module .call1("CertificateIssuer", (gns,))? .to_object(py)) @@ -388,7 +426,8 @@ fn parse_crl_extension( .call1("DeltaCRLIndicator", (pynum,))? .to_object(py)) } else if oid == *ISSUER_ALTERNATIVE_NAME_OID { - let ians = parse_general_names(py, ext_data)?; + let gn_seq = asn1::parse_single::>(ext_data)?; + let ians = parse_general_names(py, gn_seq)?; Ok(x509_module .call1("IssuerAlternativeName", (ians,))? .to_object(py)) @@ -397,6 +436,8 @@ fn parse_crl_extension( Ok(x509_module .call1("AuthorityInformationAccess", (ads,))? .to_object(py)) + } else if oid == *AUTHORITY_KEY_IDENTIFIER_OID { + Ok(parse_authority_key_identifier(py, ext_data)?) } else { Ok(py.None()) } From 0ce8f3a25120fbba775b6a7c8cc344a32c55afbf Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 7 Jun 2021 23:28:18 -0400 Subject: [PATCH 0202/1456] Enable the Rust 2018 idioms warning and fix them (#6095) --- src/rust/src/asn1.rs | 10 +++++----- src/rust/src/lib.rs | 2 ++ src/rust/src/ocsp.rs | 10 +++++----- src/rust/src/x509.rs | 33 +++++++++++++++++---------------- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 706ced54d9b3..28f458e49c0c 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -69,7 +69,7 @@ struct Spki<'a> { #[pyo3::prelude::pyfunction] fn parse_spki_for_data(py: pyo3::Python<'_>, data: &[u8]) -> Result { - let spki = asn1::parse_single::(data)?; + let spki = asn1::parse_single::>(data)?; if spki.data.padding_bits() != 0 { return Err(pyo3::exceptions::PyValueError::new_err("Invalid public key encoding").into()); } @@ -85,7 +85,7 @@ struct DssSignature<'a> { pub(crate) fn big_asn1_uint_to_py<'p>( py: pyo3::Python<'p>, - v: asn1::BigUint, + v: asn1::BigUint<'_>, ) -> pyo3::PyResult<&'p pyo3::PyAny> { let int_type = py.get_type::(); int_type.call_method1("from_bytes", (v.as_bytes(), "big")) @@ -93,7 +93,7 @@ pub(crate) fn big_asn1_uint_to_py<'p>( #[pyo3::prelude::pyfunction] fn decode_dss_signature(py: pyo3::Python<'_>, data: &[u8]) -> Result { - let sig = asn1::parse_single::(data)?; + let sig = asn1::parse_single::>(data)?; Ok(( big_asn1_uint_to_py(py, sig.r)?, @@ -200,7 +200,7 @@ fn parse_name_value_tags(rdns: &mut Name<'_>) -> Result, PyAsn1Error> { #[pyo3::prelude::pyfunction] fn test_parse_certificate(data: &[u8]) -> Result { - let mut asn1_cert = asn1::parse_single::(data)?; + let mut asn1_cert = asn1::parse_single::>(data)?; Ok(TestCertificate { not_before_tag: asn1_cert.tbs_cert.validity.not_before.tag(), @@ -210,7 +210,7 @@ fn test_parse_certificate(data: &[u8]) -> Result { }) } -pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelude::PyModule> { +pub(crate) fn create_submodule(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let submod = pyo3::prelude::PyModule::new(py, "asn1")?; submod.add_wrapped(pyo3::wrap_pyfunction!(encode_tls_feature))?; submod.add_wrapped(pyo3::wrap_pyfunction!(encode_precert_poison))?; diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index dbde1d9de22a..9e7315c40ff5 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -2,6 +2,8 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. +#![deny(rust_2018_idioms)] + mod asn1; mod ocsp; mod x509; diff --git a/src/rust/src/ocsp.rs b/src/rust/src/ocsp.rs index ddbe4f0503c0..6068e72116a8 100644 --- a/src/rust/src/ocsp.rs +++ b/src/rust/src/ocsp.rs @@ -61,7 +61,7 @@ struct OCSPRequest { } impl OCSPRequest { - fn cert_id(&self) -> Result { + fn cert_id(&self) -> Result, PyAsn1Error> { Ok(self .raw .borrow_value() @@ -76,11 +76,11 @@ impl OCSPRequest { fn parse_and_cache_extensions< 'p, - F: Fn(&asn1::ObjectIdentifier, &[u8]) -> Result, PyAsn1Error>, + F: Fn(&asn1::ObjectIdentifier<'_>, &[u8]) -> Result, PyAsn1Error>, >( py: pyo3::Python<'p>, cached_extensions: &mut Option, - raw_exts: &Option, + raw_exts: &Option>, parse_ext: F, ) -> Result { if let Some(cached) = cached_extensions { @@ -165,7 +165,7 @@ impl OCSPRequest { } #[getter] - fn extensions(&mut self, py: pyo3::Python) -> Result { + fn extensions(&mut self, py: pyo3::Python<'_>) -> Result { let x509_module = py.import("cryptography.x509")?; parse_and_cache_extensions( py, @@ -285,7 +285,7 @@ fn parse_ocsp_resp_extension( } } -pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelude::PyModule> { +pub(crate) fn create_submodule(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let submod = pyo3::prelude::PyModule::new(py, "ocsp")?; submod.add_wrapped(pyo3::wrap_pyfunction!(load_der_ocsp_request))?; diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index 3e64e1e2e524..e2480013c7c0 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -107,7 +107,7 @@ fn parse_authority_key_identifier( ext_data: &[u8], ) -> Result { let x509_module = py.import("cryptography.x509")?; - let aki = asn1::parse_single::(ext_data)?; + let aki = asn1::parse_single::>(ext_data)?; let serial = match aki.authority_cert_serial_number { Some(biguint) => big_asn1_uint_to_py(py, biguint)?.to_object(py), None => py.None(), @@ -126,7 +126,7 @@ fn parse_authority_key_identifier( fn parse_name_attribute( py: pyo3::Python<'_>, - attribute: AttributeTypeValue, + attribute: AttributeTypeValue<'_>, ) -> Result { let x509_module = py.import("cryptography.x509")?; let oid = x509_module @@ -143,7 +143,7 @@ fn parse_name_attribute( .to_object(py)) } -fn parse_name(py: pyo3::Python<'_>, name: Name) -> Result { +fn parse_name(py: pyo3::Python<'_>, name: Name<'_>) -> Result { let x509_module = py.import("cryptography.x509")?; let py_rdns = pyo3::types::PyList::empty(py); for rdn in name { @@ -163,7 +163,7 @@ fn parse_name(py: pyo3::Python<'_>, name: Name) -> Result, - gn: GeneralName, + gn: GeneralName<'_>, ) -> Result { let x509_module = py.import("cryptography.x509")?; let py_gn = match gn { @@ -238,7 +238,7 @@ fn parse_access_descriptions( ) -> Result { let x509_module = py.import("cryptography.x509")?; let ads = pyo3::types::PyList::empty(py); - for access in asn1::parse_single::>(ext_data)? { + for access in asn1::parse_single::>>(ext_data)? { let py_oid = x509_module .call_method1("ObjectIdentifier", (access.access_method.to_string(),))? .to_object(py); @@ -261,13 +261,13 @@ fn parse_x509_extension( let x509_module = py.import("cryptography.x509")?; if oid == *SUBJECT_ALTERNATIVE_NAME_OID { - let gn_seq = asn1::parse_single::>(ext_data)?; + let gn_seq = asn1::parse_single::>>(ext_data)?; let sans = parse_general_names(py, gn_seq)?; Ok(x509_module .call1("SubjectAlternativeName", (sans,))? .to_object(py)) } else if oid == *ISSUER_ALTERNATIVE_NAME_OID { - let gn_seq = asn1::parse_single::>(ext_data)?; + let gn_seq = asn1::parse_single::>>(ext_data)?; let ians = parse_general_names(py, gn_seq)?; Ok(x509_module .call1("IssuerAlternativeName", (ians,))? @@ -278,7 +278,7 @@ fn parse_x509_extension( .getattr("_TLS_FEATURE_TYPE_TO_ENUM")?; let features = pyo3::types::PyList::empty(py); - for feature in asn1::parse_single::>(ext_data)? { + for feature in asn1::parse_single::>(ext_data)? { let py_feature = tls_feature_type_to_enum.get_item(feature.to_object(py))?; features.append(py_feature)?; } @@ -290,7 +290,8 @@ fn parse_x509_extension( .to_object(py)) } else if oid == *EXTENDED_KEY_USAGE_OID { let ekus = pyo3::types::PyList::empty(py); - for oid in asn1::parse_single::>(ext_data)? { + for oid in asn1::parse_single::>>(ext_data)? + { let oid_obj = x509_module.call_method1("ObjectIdentifier", (oid.to_string(),))?; ekus.append(oid_obj)?; } @@ -298,7 +299,7 @@ fn parse_x509_extension( .call1("ExtendedKeyUsage", (ekus,))? .to_object(py)) } else if oid == *KEY_USAGE_OID { - let kus = asn1::parse_single::(ext_data)?; + let kus = asn1::parse_single::>(ext_data)?; let digital_signature = kus.has_bit_set(0); let content_comitment = kus.has_bit_set(1); let key_encipherment = kus.has_bit_set(2); @@ -349,7 +350,7 @@ fn parse_x509_extension( asn1::parse_single::<()>(ext_data)?; Ok(x509_module.call0("OCSPNoCheck")?.to_object(py)) } else if oid == *INHIBIT_ANY_POLICY_OID { - let bignum = asn1::parse_single::(ext_data)?; + let bignum = asn1::parse_single::>(ext_data)?; let pynum = big_asn1_uint_to_py(py, bignum)?; Ok(x509_module .call1("InhibitAnyPolicy", (pynum,))? @@ -396,7 +397,7 @@ fn parse_crl_entry_extension( let flag = x509_module.getattr("ReasonFlags")?.getattr(flag_name)?; Ok(x509_module.call1("CRLReason", (flag,))?.to_object(py)) } else if oid == *CERTIFICATE_ISSUER_OID { - let gn_seq = asn1::parse_single::>(ext_data)?; + let gn_seq = asn1::parse_single::>>(ext_data)?; let gns = parse_general_names(py, gn_seq)?; Ok(x509_module .call1("CertificateIssuer", (gns,))? @@ -416,17 +417,17 @@ fn parse_crl_extension( let x509_module = py.import("cryptography.x509")?; if oid == *CRL_NUMBER_OID { - let bignum = asn1::parse_single::(ext_data)?; + let bignum = asn1::parse_single::>(ext_data)?; let pynum = big_asn1_uint_to_py(py, bignum)?; Ok(x509_module.call1("CRLNumber", (pynum,))?.to_object(py)) } else if oid == *DELTA_CRL_INDICATOR_OID { - let bignum = asn1::parse_single::(ext_data)?; + let bignum = asn1::parse_single::>(ext_data)?; let pynum = big_asn1_uint_to_py(py, bignum)?; Ok(x509_module .call1("DeltaCRLIndicator", (pynum,))? .to_object(py)) } else if oid == *ISSUER_ALTERNATIVE_NAME_OID { - let gn_seq = asn1::parse_single::>(ext_data)?; + let gn_seq = asn1::parse_single::>>(ext_data)?; let ians = parse_general_names(py, gn_seq)?; Ok(x509_module .call1("IssuerAlternativeName", (ians,))? @@ -443,7 +444,7 @@ fn parse_crl_extension( } } -pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelude::PyModule> { +pub(crate) fn create_submodule(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let submod = pyo3::prelude::PyModule::new(py, "x509")?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_x509_extension))?; From 6a843c42e2a2f0f278238e3a91242d41dc40388d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 8 Jun 2021 20:57:02 -0400 Subject: [PATCH 0203/1456] fix mypy build for latest release (#6099) --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 19adafc2b28a..1f7debd4ed5a 100644 --- a/tox.ini +++ b/tox.ini @@ -54,6 +54,7 @@ extras = ssh deps = mypy + types-pytz check-manifest commands = flake8 . From 5565587b0b03e067a0c2f701884504cfae384886 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 8 Jun 2021 23:25:07 -0500 Subject: [PATCH 0204/1456] oxidize invaliditydate (#6101) * oxidize invaliditydate * linters win every time * prettier --- .../hazmat/backends/openssl/backend.py | 4 +--- .../hazmat/backends/openssl/decode_asn1.py | 15 --------------- src/rust/Cargo.lock | 1 + src/rust/Cargo.toml | 1 + src/rust/src/x509.rs | 18 ++++++++++++++++++ 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 0376843d15d2..53ba826a726a 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -22,7 +22,6 @@ _EXTENSION_HANDLERS_BASE, _EXTENSION_HANDLERS_SCT, _OCSP_SINGLERESP_EXTENSION_HANDLERS_SCT, - _REVOKED_EXTENSION_HANDLERS, _X509ExtensionParser, ) from cryptography.hazmat.backends.openssl.dh import ( @@ -391,7 +390,7 @@ def _register_x509_ext_parsers(self): ext_handlers = _EXTENSION_HANDLERS_BASE.copy() # All revoked extensions are valid single response extensions, see: # https://tools.ietf.org/html/rfc6960#section-4.4.5 - singleresp_handlers = _REVOKED_EXTENSION_HANDLERS.copy() + singleresp_handlers = {} if self._lib.Cryptography_HAS_SCT: ext_handlers.update(_EXTENSION_HANDLERS_SCT) @@ -416,7 +415,6 @@ def _register_x509_ext_parsers(self): ext_count=self._lib.X509_REVOKED_get_ext_count, get_ext=self._lib.X509_REVOKED_get_ext, rust_callback=rust_x509.parse_crl_entry_extension, - handlers=_REVOKED_EXTENSION_HANDLERS, ) self._crl_extension_parser = _X509ExtensionParser( self, diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 8b2bc6aa46c6..3cdd5345fe1f 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -10,7 +10,6 @@ from cryptography import x509 from cryptography.x509.name import _ASN1_TYPE_TO_ENUM from cryptography.x509.oid import ( - CRLEntryExtensionOID, CertificatePoliciesOID, ExtensionOID, ) @@ -492,16 +491,6 @@ def _decode_signed_certificate_timestamps(backend, asn1_scts): } -def _decode_invalidity_date(backend, inv_date): - generalized_time = backend._ffi.cast("ASN1_GENERALIZEDTIME *", inv_date) - generalized_time = backend._ffi.gc( - generalized_time, backend._lib.ASN1_GENERALIZEDTIME_free - ) - return x509.InvalidityDate( - _parse_asn1_generalized_time(backend, generalized_time) - ) - - def _asn1_integer_to_int(backend, asn1_int): bn = backend._lib.ASN1_INTEGER_to_BN(asn1_int, backend._ffi.NULL) backend.openssl_assert(bn != backend._ffi.NULL) @@ -569,10 +558,6 @@ def _parse_asn1_generalized_time(backend, generalized_time): ) } -_REVOKED_EXTENSION_HANDLERS = { - CRLEntryExtensionOID.INVALIDITY_DATE: _decode_invalidity_date, -} - _CRL_EXTENSION_HANDLERS = { ExtensionOID.ISSUING_DISTRIBUTION_POINT: _decode_issuing_dist_point, ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 240d2b1c124a..70f01f1895a0 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -62,6 +62,7 @@ name = "cryptography-rust" version = "0.1.0" dependencies = [ "asn1", + "chrono", "lazy_static", "ouroboros", "pyo3", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index e70b20865346..dd535181f95c 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -9,6 +9,7 @@ publish = false lazy_static = "1" pyo3 = { version = "0.13.1" } asn1 = { version = "0.5.1", default-features = false, features = ["derive"] } +chrono = { version = "0.4", default-features = false, features = ["alloc"] } ouroboros = "0.9" [features] diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index e2480013c7c0..977f4e8edc53 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -3,6 +3,7 @@ // for complete details. use crate::asn1::{big_asn1_uint_to_py, AttributeTypeValue, Name, PyAsn1Error}; +use chrono::{Datelike, Timelike}; use pyo3::conversion::ToPyObject; lazy_static::lazy_static! { @@ -22,6 +23,7 @@ lazy_static::lazy_static! { static ref CRL_REASON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.21").unwrap(); static ref CERTIFICATE_ISSUER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.29").unwrap(); static ref CRL_NUMBER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.20").unwrap(); + static ref INVALIDITY_DATE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.24").unwrap(); static ref DELTA_CRL_INDICATOR_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.27").unwrap(); static ref SUBJECT_ALTERNATIVE_NAME_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.17").unwrap(); static ref ISSUER_ALTERNATIVE_NAME_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.18").unwrap(); @@ -402,6 +404,22 @@ fn parse_crl_entry_extension( Ok(x509_module .call1("CertificateIssuer", (gns,))? .to_object(py)) + } else if oid == *INVALIDITY_DATE_OID { + let time = asn1::parse_single::(ext_data)?; + let time_chrono = time.as_chrono(); + let datetime_module = py.import("datetime")?; + let py_dt = datetime_module.call1( + "datetime", + ( + time_chrono.year(), + time_chrono.month(), + time_chrono.day(), + time_chrono.hour(), + time_chrono.minute(), + time_chrono.second(), + ), + )?; + Ok(x509_module.call1("InvalidityDate", (py_dt,))?.to_object(py)) } else { Ok(py.None()) } From 1eeee2b8431b81b52a006881d2381ef97c2d1914 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 07:23:56 -0400 Subject: [PATCH 0205/1456] Bump libc from 0.2.95 to 0.2.96 in /src/rust (#6102) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.95 to 0.2.96. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.95...0.2.96) --- updated-dependencies: - dependency-name: libc dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 70f01f1895a0..7622e6587187 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -151,9 +151,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.95" +version = "0.2.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" +checksum = "5600b4e6efc5421841a2138a6b082e07fe12f9aaa12783d50e5d13325b26b4fc" [[package]] name = "lock_api" From f0715b835ed5d71cf0b38f165ac6d28e003b4bb5 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Wed, 9 Jun 2021 21:41:36 +1000 Subject: [PATCH 0206/1456] Added handling for OpenSSL "xts duplicated keys" error. (#6085) * Added handling for OpenSSL "xts duplicated keys" error. Closes #5998 This error value was added pre-OpenSSL 1.1.1d here: https://github.com/openssl/openssl/commit/2a5f63c9a61be7582620c4b5da202bb3fd7e4138 and refined to only cover encryption shortly after: https://github.com/openssl/openssl/commit/58ae5a47da1e4843b0cd1846eb297b341d0e7201 * test_aes: Remove unnecessary assignment * xts: Update duplicated keys check for OpenSSL 3 providers Also, change the exception message slightly: - Now matches the tense used by openssl - Turns out decryption *is* checked for duplicate keys by OpenSSL 3 when in FIPS mode --- src/_cffi_src/openssl/cryptography.py | 3 +++ src/_cffi_src/openssl/err.py | 5 ++++ src/_cffi_src/openssl/provider.py | 2 ++ .../hazmat/backends/openssl/ciphers.py | 23 ++++++++++++++++++- tests/hazmat/primitives/test_aes.py | 13 +++++++++++ 5 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/_cffi_src/openssl/cryptography.py b/src/_cffi_src/openssl/cryptography.py index e9a9a522e8b6..802a72acbf58 100644 --- a/src/_cffi_src/openssl/cryptography.py +++ b/src/_cffi_src/openssl/cryptography.py @@ -41,6 +41,8 @@ #define CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER \ (OPENSSL_VERSION_NUMBER >= 0x1010006f && !CRYPTOGRAPHY_IS_LIBRESSL) +#define CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER \ + (OPENSSL_VERSION_NUMBER >= 0x10101040 && !CRYPTOGRAPHY_IS_LIBRESSL) #define CRYPTOGRAPHY_OPENSSL_300_OR_GREATER \ (OPENSSL_VERSION_NUMBER >= 0x30000000 && !CRYPTOGRAPHY_IS_LIBRESSL) @@ -62,6 +64,7 @@ TYPES = """ static const int CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER; +static const int CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER; static const int CRYPTOGRAPHY_OPENSSL_300_OR_GREATER; static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_111; diff --git a/src/_cffi_src/openssl/err.py b/src/_cffi_src/openssl/err.py index 8cfeaf5ba38a..54dd1e44c43d 100644 --- a/src/_cffi_src/openssl/err.py +++ b/src/_cffi_src/openssl/err.py @@ -15,6 +15,7 @@ static const int PKCS12_R_PKCS12_CIPHERFINAL_ERROR; static const int PEM_R_UNSUPPORTED_ENCRYPTION; static const int EVP_R_UNKNOWN_PBE_ALGORITHM; +static const int EVP_R_XTS_DUPLICATED_KEYS; static const int ERR_LIB_EVP; static const int ERR_LIB_PEM; @@ -51,4 +52,8 @@ #ifndef ERR_LIB_PROV #define ERR_LIB_PROV 0 #endif + +#if !CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER +static const int EVP_R_XTS_DUPLICATED_KEYS = 0; +#endif """ diff --git a/src/_cffi_src/openssl/provider.py b/src/_cffi_src/openssl/provider.py index d7d659ea5ef4..d741ad7e4f55 100644 --- a/src/_cffi_src/openssl/provider.py +++ b/src/_cffi_src/openssl/provider.py @@ -17,6 +17,7 @@ typedef ... OSSL_LIB_CTX; static const long PROV_R_BAD_DECRYPT; +static const long PROV_R_XTS_DUPLICATED_KEYS; static const long PROV_R_WRONG_FINAL_BLOCK_LENGTH; """ @@ -33,6 +34,7 @@ typedef void OSSL_PROVIDER; typedef void OSSL_LIB_CTX; static const long PROV_R_BAD_DECRYPT = 0; +static const long PROV_R_XTS_DUPLICATED_KEYS = 0; static const long PROV_R_WRONG_FINAL_BLOCK_LENGTH = 0; OSSL_PROVIDER *(*OSSL_PROVIDER_load)(OSSL_LIB_CTX *, const char *) = NULL; int (*OSSL_PROVIDER_unload)(OSSL_PROVIDER *) = NULL; diff --git a/src/cryptography/hazmat/backends/openssl/ciphers.py b/src/cryptography/hazmat/backends/openssl/ciphers.py index eb302e44f9eb..ec272e04d4f4 100644 --- a/src/cryptography/hazmat/backends/openssl/ciphers.py +++ b/src/cryptography/hazmat/backends/openssl/ciphers.py @@ -112,7 +112,28 @@ def __init__(self, backend, cipher, mode, operation): iv_nonce, operation, ) - self._backend.openssl_assert(res != 0) + + # Check for XTS mode duplicate keys error + errors = self._backend._consume_errors() + lib = self._backend._lib + if res == 0 and ( + ( + lib.CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER + and errors[0]._lib_reason_match( + lib.ERR_LIB_EVP, lib.EVP_R_XTS_DUPLICATED_KEYS + ) + ) + or ( + lib.Cryptography_HAS_PROVIDERS + and errors[0]._lib_reason_match( + lib.ERR_LIB_PROV, lib.PROV_R_XTS_DUPLICATED_KEYS + ) + ) + ): + raise ValueError("In XTS mode duplicated keys are not allowed") + + self._backend.openssl_assert(res != 0, errors=errors) + # We purposely disable padding here as it's handled higher up in the # API. self._backend._lib.EVP_CIPHER_CTX_set_padding(ctx, 0) diff --git a/tests/hazmat/primitives/test_aes.py b/tests/hazmat/primitives/test_aes.py index fd37b7696d96..eb6f74b92d5a 100644 --- a/tests/hazmat/primitives/test_aes.py +++ b/tests/hazmat/primitives/test_aes.py @@ -60,6 +60,19 @@ def test_xts_too_short(self): with pytest.raises(ValueError): enc.update(b"0" * 15) + @pytest.mark.supported( + only_if=lambda backend: ( + backend._lib.CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER + ), + skip_message="duplicate key encryption error added in OpenSSL 1.1.1d", + ) + def test_xts_no_duplicate_keys_encryption(self, backend): + key = bytes(range(16)) * 2 + tweak = b"\x00" * 16 + cipher = base.Cipher(algorithms.AES(key), modes.XTS(tweak)) + with pytest.raises(ValueError, match="duplicated keys"): + cipher.encryptor() + @pytest.mark.supported( only_if=lambda backend: backend.cipher_supported( From acf5db529ce5ab6f0f8dc492b11afaa3c3b7adf3 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 9 Jun 2021 23:26:58 -0400 Subject: [PATCH 0207/1456] Added more testcases for invalid SCTs (#6103) --- docs/development/test-vectors.rst | 4 ++ .../hazmat/backends/openssl/x509.py | 5 +- tests/x509/test_x509_ext.py | 56 ++++++++++++++++++ .../x509/custom/invalid-sct-length.der | Bin 0 -> 958 bytes .../x509/custom/invalid-sct-version.der | Bin 0 -> 1028 bytes 5 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 vectors/cryptography_vectors/x509/custom/invalid-sct-length.der create mode 100644 vectors/cryptography_vectors/x509/custom/invalid-sct-version.der diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index edd2c609f430..3420fce8e2a8 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -420,6 +420,10 @@ Custom X.509 Vectors using ``ed448-pkcs8.pem`` as key. * ``ca/rsa_ca.pem`` - A self-signed RSA certificate with ``basicConstraints`` set to true. Its private key is ``ca/rsa_key.pem``. +* ``invalid-sct-version.der`` - A certificate with an SCT with an unknown + version. +* ``invalid-sct-length.der`` - A certificate with an SCT with an internal + length greater than the amount of data. Custom X.509 Request Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 54daddb08eea..820b5f1f49bb 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -549,10 +549,11 @@ def __init__(self, backend, sct_list, sct): self._sct_list = sct_list self._sct = sct + if backend._lib.SCT_get_version(sct) != backend._lib.SCT_VERSION_V1: + raise ValueError("Invalid SCT version") + @property def version(self) -> x509.certificate_transparency.Version: - version = self._backend._lib.SCT_get_version(self._sct) - assert version == self._backend._lib.SCT_VERSION_V1 return x509.certificate_transparency.Version.v1 @property diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index 67011d09cd10..89e4502bb381 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -5460,6 +5460,36 @@ def test_ne(self, backend): assert psct1 != psct2 assert psct1 != object() + @pytest.mark.supported( + only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), + skip_message="Requires CT support", + ) + def test_ordering(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 + ) + with pytest.raises(TypeError): + psct1[0] < psct2[0] + @pytest.mark.supported( only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), skip_message="Requires CT support", @@ -5578,6 +5608,32 @@ def test_skips_scts_if_unsupported(self, backend): ) assert isinstance(ext.value, x509.UnrecognizedExtension) + @pytest.mark.supported( + only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), + skip_message="Requires CT support", + ) + def test_invalid_version(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "invalid-sct-version.der"), + x509.load_der_x509_certificate, + backend, + ) + with pytest.raises(ValueError): + cert.extensions + + @pytest.mark.supported( + only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), + skip_message="Requires CT support", + ) + def test_invalid_length(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "invalid-sct-length.der"), + x509.load_der_x509_certificate, + backend, + ) + with pytest.raises(ValueError): + cert.extensions + class TestInvalidExtension(object): def test_invalid_certificate_policies_data(self, backend): diff --git a/vectors/cryptography_vectors/x509/custom/invalid-sct-length.der b/vectors/cryptography_vectors/x509/custom/invalid-sct-length.der new file mode 100644 index 0000000000000000000000000000000000000000..3b3b92d4ac8eb83905c3bcb18446376399a0f5ab GIT binary patch literal 958 zcmXqLV%}xY#I$GuGZP~dlMwS|6u^^*T zFEihuiBSpJX^gB4%uS5^3_x)%rY1&4hDFXxl>UA(&G=kb^XAmm9Df9e&lo(bF)>;-f5p3HQpTC(odhq+UyO}}tx;ksAr zugQid%oA;J=RGD66vkIyFj>Gs+@EQ=MQDb{zmD}&w*Pf!V~#kq$l{&crPZ(2U&viG zDI_%LBF|+r!AgxWbf`NfCO?TecS$juTS%v+Mkdb@0m((1(iQ)zu#_H}rxLg9T>@9e^NR_G`lGvNM1AiSz1Ydm z@>@f^ee<2^!t8NJGZsF}pCEB;VUv@_iq(+|uAJxpnwNGgt-yXuPGhMv&k38m@0P2x zHk?za7dcsFdQy4Dsrxzd&Ydyh&yF)b@sd7#HS8l-@?@TA4@C~xuf4i#W4zSg8O;EE CrHP^d literal 0 HcmV?d00001 diff --git a/vectors/cryptography_vectors/x509/custom/invalid-sct-version.der b/vectors/cryptography_vectors/x509/custom/invalid-sct-version.der new file mode 100644 index 0000000000000000000000000000000000000000..96cce1d524e56224a45a885c67377ecc942c1f9e GIT binary patch literal 1028 zcmXqLVqq|7VtTQFnTe5!Nr?HfanXwBhPH1vn4Y?`>(iqr9tON@oLX%jZQpqr8M#>* z47?1v4LI4DLs{5_nL>jN#SBD194=vApVSidVg=W{*aTJJaXk=sx72@ zns%~O{PLAfzje=}|JE&A`|0as{i#>HdM0pJuoukHdot6ZYRS4+ALdS-HvPh(h3j6e zza|@=Fi*6>o%fhPP#9l*!DImkaet=e7NHp)|2o!B+5Xp^jXC1bB8zu&msY=8e<63( zq>#{{i#(Uj1UJp!^ndlEz1NQF1%LP$HgD}NPxA`yZBu;<5}BA885kEgG4g>z1c=$# zxU|_ASs1TXGO;kRG=67k{KD{wp`20ECU9EF3Cq-7s{;N+uwU7pzdxc%v*^x}!#rP} zy1IXA4j(0eOWzYL7j3f8jpJSNg)Y_L)_;uUuUx zSJAB{4nQUMR(`y2IQY+H^M}!e@eLZSr46y(SzWID*8$=17xW0v_%VTi@v1xOYzdT{e!@)VIDd(U3~Hh05>t2-vK zZ)rH*b?E33J~O#Vio9P&^_U$c?$qTl*uJ&C!yUwpTZjV{XV_CZ-VGUjvm((>|3g2@=N^HaTgmSRJ|G%6a~; zd1=Se3hcM!G?qH^oUpn3Zn-*Z!#Ra|k&{)XCzWTMx}PKO+!-VO>^S2SFX_Wq!#;8) WPv)8SP~?F9+N;Yp#!LO3(F_22BdhQL literal 0 HcmV?d00001 From b9ce2292a4480f9b9bc85680b8f557247ce47c30 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Jun 2021 08:37:51 -0400 Subject: [PATCH 0208/1456] Bump syn from 1.0.72 to 1.0.73 in /src/rust (#6105) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.72 to 1.0.73. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.72...1.0.73) --- updated-dependencies: - dependency-name: syn dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 7622e6587187..a017dae9f325 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -366,9 +366,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "1.0.72" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" +checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" dependencies = [ "proc-macro2", "quote", From ae4ed8d4375a765f69cfc8e1bfbe4021655171f4 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 10 Jun 2021 23:10:10 -0400 Subject: [PATCH 0209/1456] Move SCT encoding/decoding to Rust (#6098) --- .../hazmat/backends/openssl/backend.py | 28 ++- .../hazmat/backends/openssl/decode_asn1.py | 37 ---- .../hazmat/backends/openssl/encode_asn1.py | 13 -- .../hazmat/backends/openssl/x509.py | 61 ------ .../hazmat/bindings/_rust/ocsp.pyi | 3 + .../hazmat/bindings/_rust/x509.pyi | 10 +- .../x509/certificate_transparency.py | 4 + src/rust/src/ocsp.rs | 23 +++ src/rust/src/x509.rs | 182 +++++++++++++++++- tests/x509/test_ocsp.py | 37 ---- tests/x509/test_x509_ext.py | 65 ------- 11 files changed, 233 insertions(+), 230 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 53ba826a726a..b6481f224088 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -20,8 +20,6 @@ _CRL_ENTRY_REASON_ENUM_TO_CODE, _CRL_EXTENSION_HANDLERS, _EXTENSION_HANDLERS_BASE, - _EXTENSION_HANDLERS_SCT, - _OCSP_SINGLERESP_EXTENSION_HANDLERS_SCT, _X509ExtensionParser, ) from cryptography.hazmat.backends.openssl.dh import ( @@ -387,28 +385,19 @@ def _register_default_ciphers(self): ) def _register_x509_ext_parsers(self): - ext_handlers = _EXTENSION_HANDLERS_BASE.copy() - # All revoked extensions are valid single response extensions, see: - # https://tools.ietf.org/html/rfc6960#section-4.4.5 - singleresp_handlers = {} - - if self._lib.Cryptography_HAS_SCT: - ext_handlers.update(_EXTENSION_HANDLERS_SCT) - singleresp_handlers.update(_OCSP_SINGLERESP_EXTENSION_HANDLERS_SCT) - self._certificate_extension_parser = _X509ExtensionParser( self, ext_count=self._lib.X509_get_ext_count, get_ext=self._lib.X509_get_ext, rust_callback=rust_x509.parse_x509_extension, - handlers=ext_handlers, + handlers=_EXTENSION_HANDLERS_BASE, ) self._csr_extension_parser = _X509ExtensionParser( self, ext_count=self._lib.sk_X509_EXTENSION_num, get_ext=self._lib.sk_X509_EXTENSION_value, rust_callback=rust_x509.parse_x509_extension, - handlers=ext_handlers, + handlers=_EXTENSION_HANDLERS_BASE, ) self._revoked_cert_extension_parser = _X509ExtensionParser( self, @@ -433,8 +422,7 @@ def _register_x509_ext_parsers(self): self, ext_count=self._lib.OCSP_SINGLERESP_get_ext_count, get_ext=self._lib.OCSP_SINGLERESP_get_ext, - rust_callback=rust_x509.parse_crl_entry_extension, - handlers=singleresp_handlers, + rust_callback=rust_ocsp.parse_ocsp_singleresp_extension, ) def _register_x509_encoders(self): @@ -1170,6 +1158,16 @@ def _create_x509_extension(self, handlers, extension): self, asn1.encode_precert_poison(extension.value) ) return self._create_raw_x509_extension(extension, value) + elif isinstance( + extension.value, x509.PrecertificateSignedCertificateTimestamps + ): + value = _encode_asn1_str_gc( + self, + rust_x509.encode_precertificate_signed_certificate_timestamps( + extension.value + ), + ) + return self._create_raw_x509_extension(extension, value) else: try: encode = handlers[extension.oid] diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 3cdd5345fe1f..e0d7505f8390 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -425,32 +425,6 @@ def _decode_freshest_crl(backend, cdps): return x509.FreshestCRL(dist_points) -def _decode_scts(backend, asn1_scts): - from cryptography.hazmat.backends.openssl.x509 import ( - _SignedCertificateTimestamp, - ) - - asn1_scts = backend._ffi.cast("Cryptography_STACK_OF_SCT *", asn1_scts) - asn1_scts = backend._ffi.gc(asn1_scts, backend._lib.SCT_LIST_free) - - scts = [] - for i in range(backend._lib.sk_SCT_num(asn1_scts)): - sct = backend._lib.sk_SCT_value(asn1_scts, i) - - scts.append(_SignedCertificateTimestamp(backend, asn1_scts, sct)) - return scts - - -def _decode_precert_signed_certificate_timestamps(backend, asn1_scts): - return x509.PrecertificateSignedCertificateTimestamps( - _decode_scts(backend, asn1_scts) - ) - - -def _decode_signed_certificate_timestamps(backend, asn1_scts): - return x509.SignedCertificateTimestamps(_decode_scts(backend, asn1_scts)) - - # CRLReason ::= ENUMERATED { # unspecified (0), # keyCompromise (1), @@ -552,19 +526,8 @@ def _parse_asn1_generalized_time(backend, generalized_time): ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, ExtensionOID.NAME_CONSTRAINTS: _decode_name_constraints, } -_EXTENSION_HANDLERS_SCT = { - ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: ( - _decode_precert_signed_certificate_timestamps - ) -} _CRL_EXTENSION_HANDLERS = { ExtensionOID.ISSUING_DISTRIBUTION_POINT: _decode_issuing_dist_point, ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, } - -_OCSP_SINGLERESP_EXTENSION_HANDLERS_SCT = { - ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS: ( - _decode_signed_certificate_timestamps - ) -} diff --git a/src/cryptography/hazmat/backends/openssl/encode_asn1.py b/src/cryptography/hazmat/backends/openssl/encode_asn1.py index 0daae661367a..97080abea1ee 100644 --- a/src/cryptography/hazmat/backends/openssl/encode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/encode_asn1.py @@ -606,16 +606,6 @@ def _encode_general_subtree(backend, subtrees): return general_subtrees -def _encode_precert_signed_certificate_timestamps(backend, scts): - sct_stack = backend._lib.sk_SCT_new_null() - backend.openssl_assert(sct_stack != backend._ffi.NULL) - sct_stack = backend._ffi.gc(sct_stack, backend._lib.sk_SCT_free) - for sct in scts: - res = backend._lib.sk_SCT_push(sct_stack, sct._sct) - backend.openssl_assert(res >= 1) - return sct_stack - - def _encode_nonce(backend, nonce): return _encode_asn1_str_gc(backend, nonce.nonce) @@ -637,9 +627,6 @@ def _encode_nonce(backend, nonce): ExtensionOID.OCSP_NO_CHECK: _encode_ocsp_nocheck, ExtensionOID.NAME_CONSTRAINTS: _encode_name_constraints, ExtensionOID.POLICY_CONSTRAINTS: _encode_policy_constraints, - ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: ( - _encode_precert_signed_certificate_timestamps - ), } _CRL_EXTENSION_ENCODE_HANDLERS = { diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 820b5f1f49bb..edbc7c6d5f0c 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -537,64 +537,3 @@ def get_attribute_for_oid(self, oid: x509.ObjectIdentifier) -> bytes: # that it is always a type of ASN1_STRING data = self._backend._ffi.cast("ASN1_STRING *", data) return _asn1_string_to_bytes(self._backend, data) - - -@utils.register_interface( - x509.certificate_transparency.SignedCertificateTimestamp -) -class _SignedCertificateTimestamp(object): - def __init__(self, backend, sct_list, sct): - self._backend = backend - # Keep the SCT_LIST that this SCT came from alive. - self._sct_list = sct_list - self._sct = sct - - if backend._lib.SCT_get_version(sct) != backend._lib.SCT_VERSION_V1: - raise ValueError("Invalid SCT version") - - @property - def version(self) -> x509.certificate_transparency.Version: - return x509.certificate_transparency.Version.v1 - - @property - def log_id(self) -> bytes: - out = self._backend._ffi.new("unsigned char **") - log_id_length = self._backend._lib.SCT_get0_log_id(self._sct, out) - assert log_id_length >= 0 - return self._backend._ffi.buffer(out[0], log_id_length)[:] - - @property - def timestamp(self) -> datetime.datetime: - timestamp = self._backend._lib.SCT_get_timestamp(self._sct) - milliseconds = timestamp % 1000 - return datetime.datetime.utcfromtimestamp(timestamp // 1000).replace( - microsecond=milliseconds * 1000 - ) - - @property - def entry_type(self) -> x509.certificate_transparency.LogEntryType: - entry_type = self._backend._lib.SCT_get_log_entry_type(self._sct) - # We currently only support loading SCTs from the X.509 extension, so - # 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) -> int: - return hash(self._signature) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, _SignedCertificateTimestamp): - return NotImplemented - - return self._signature == other._signature - - def __ne__(self, other: object) -> bool: - return not self == other diff --git a/src/cryptography/hazmat/bindings/_rust/ocsp.pyi b/src/cryptography/hazmat/bindings/_rust/ocsp.pyi index 2d8c04fc31ea..14f5eaf88f31 100644 --- a/src/cryptography/hazmat/bindings/_rust/ocsp.pyi +++ b/src/cryptography/hazmat/bindings/_rust/ocsp.pyi @@ -5,3 +5,6 @@ def load_der_ocsp_request(data: bytes) -> OCSPRequest: ... def parse_ocsp_resp_extension( der_oid: bytes, ext_data: bytes ) -> ExtensionType: ... +def parse_ocsp_singleresp_extension( + der_oid: bytes, ext_data: bytes +) -> ExtensionType: ... diff --git a/src/cryptography/hazmat/bindings/_rust/x509.pyi b/src/cryptography/hazmat/bindings/_rust/x509.pyi index 2d41f9e91f5f..a2ed70282e17 100644 --- a/src/cryptography/hazmat/bindings/_rust/x509.pyi +++ b/src/cryptography/hazmat/bindings/_rust/x509.pyi @@ -1,7 +1,15 @@ -from cryptography.x509 import ExtensionType +from cryptography.x509 import ( + ExtensionType, + PrecertificateSignedCertificateTimestamps, +) def parse_x509_extension(der_oid: bytes, ext_data: bytes) -> ExtensionType: ... def parse_crl_entry_extension( der_oid: bytes, ext_data: bytes ) -> ExtensionType: ... def parse_crl_extension(der_oid: bytes, ext_data: bytes) -> ExtensionType: ... +def encode_precertificate_signed_certificate_timestamps( + extension: PrecertificateSignedCertificateTimestamps, +) -> bytes: ... + +class Sct: ... diff --git a/src/cryptography/x509/certificate_transparency.py b/src/cryptography/x509/certificate_transparency.py index d80f051a68ae..8c198a1c0823 100644 --- a/src/cryptography/x509/certificate_transparency.py +++ b/src/cryptography/x509/certificate_transparency.py @@ -7,6 +7,7 @@ import datetime from cryptography import utils +from cryptography.hazmat.bindings._rust import x509 as rust_x509 class LogEntryType(utils.Enum): @@ -42,3 +43,6 @@ def entry_type(self) -> LogEntryType: """ Returns whether this is an SCT for a certificate or pre-certificate. """ + + +SignedCertificateTimestamp.register(rust_x509.Sct) diff --git a/src/rust/src/ocsp.rs b/src/rust/src/ocsp.rs index 6068e72116a8..fbac6c389213 100644 --- a/src/rust/src/ocsp.rs +++ b/src/rust/src/ocsp.rs @@ -3,6 +3,7 @@ // for complete details. use crate::asn1::{big_asn1_uint_to_py, PyAsn1Error}; +use crate::x509; use pyo3::conversion::ToPyObject; use pyo3::exceptions; use std::collections::{HashMap, HashSet}; @@ -25,6 +26,7 @@ lazy_static::lazy_static! { }; static ref NONCE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.48.1.2").unwrap(); + static ref SIGNED_CERTIFICATE_TIMESTAMPS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.4.1.11129.2.4.5").unwrap(); } #[ouroboros::self_referencing] @@ -285,11 +287,32 @@ fn parse_ocsp_resp_extension( } } +#[pyo3::prelude::pyfunction] +fn parse_ocsp_singleresp_extension( + py: pyo3::Python<'_>, + der_oid: &[u8], + ext_data: &[u8], +) -> Result { + let oid = asn1::ObjectIdentifier::from_der(der_oid).unwrap(); + + let x509_module = py.import("cryptography.x509")?; + if oid == *SIGNED_CERTIFICATE_TIMESTAMPS_OID { + let contents = asn1::parse_single::<&[u8]>(ext_data)?; + let scts = x509::parse_scts(py, contents, x509::LogEntryType::Certificate)?; + Ok(x509_module + .call1("SignedCertificateTimestamps", (scts,))? + .to_object(py)) + } else { + x509::parse_crl_entry_extension(py, der_oid, ext_data) + } +} + pub(crate) fn create_submodule(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let submod = pyo3::prelude::PyModule::new(py, "ocsp")?; submod.add_wrapped(pyo3::wrap_pyfunction!(load_der_ocsp_request))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_ocsp_resp_extension))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(parse_ocsp_singleresp_extension))?; Ok(submod) } diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index 977f4e8edc53..902aa6969652 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -5,6 +5,10 @@ use crate::asn1::{big_asn1_uint_to_py, AttributeTypeValue, Name, PyAsn1Error}; use chrono::{Datelike, Timelike}; use pyo3::conversion::ToPyObject; +use pyo3::types::IntoPyDict; +use std::collections::hash_map::DefaultHasher; +use std::convert::TryInto; +use std::hash::{Hash, Hasher}; lazy_static::lazy_static! { static ref TLS_FEATURE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.1.24").unwrap(); @@ -27,6 +31,7 @@ lazy_static::lazy_static! { static ref DELTA_CRL_INDICATOR_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.27").unwrap(); static ref SUBJECT_ALTERNATIVE_NAME_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.17").unwrap(); static ref ISSUER_ALTERNATIVE_NAME_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.18").unwrap(); + static ref PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.4.1.11129.2.4.2").unwrap(); } struct UnvalidatedIA5String<'a>(&'a str); @@ -253,6 +258,171 @@ fn parse_access_descriptions( Ok(ads.to_object(py)) } +struct TLSReader<'a> { + data: &'a [u8], +} + +impl<'a> TLSReader<'a> { + fn new(data: &'a [u8]) -> TLSReader<'a> { + TLSReader { data } + } + + fn is_empty(&self) -> bool { + self.data.is_empty() + } + + fn read_byte(&mut self) -> Result { + Ok(self.read_exact(1)?[0]) + } + + fn read_exact(&mut self, length: usize) -> Result<&'a [u8], PyAsn1Error> { + if length > self.data.len() { + return Err(PyAsn1Error::from(pyo3::exceptions::PyValueError::new_err( + "Invalid SCT length", + ))); + } + let (result, data) = self.data.split_at(length); + self.data = data; + Ok(result) + } + + fn read_length_prefixed(&mut self) -> Result, PyAsn1Error> { + let length = u16::from_be_bytes(self.read_exact(2)?.try_into().unwrap()); + Ok(TLSReader::new(self.read_exact(length.into())?)) + } +} + +#[derive(Clone)] +pub(crate) enum LogEntryType { + Certificate, + PreCertificate, +} + +#[pyo3::prelude::pyclass] +struct Sct { + log_id: [u8; 32], + timestamp: u64, + entry_type: LogEntryType, + sct_data: Vec, +} + +#[pyo3::prelude::pymethods] +impl Sct { + #[getter] + fn version<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { + py.import("cryptography.x509.certificate_transparency")? + .getattr("Version")? + .getattr("v1") + } + + #[getter] + fn log_id(&self) -> &[u8] { + &self.log_id + } + + #[getter] + fn timestamp<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { + let datetime_class = py.import("datetime")?.getattr("datetime")?; + datetime_class + .call_method1("utcfromtimestamp", (self.timestamp / 1000,))? + .call_method( + "replace", + (), + Some(vec![("microsecond", self.timestamp % 1000 * 1000)].into_py_dict(py)), + ) + } + + #[getter] + fn entry_type<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { + let et_class = py + .import("cryptography.x509.certificate_transparency")? + .getattr("LogEntryType")?; + let attr_name = match self.entry_type { + LogEntryType::Certificate => "X509_CERTIFICATE", + LogEntryType::PreCertificate => "PRE_CERTIFICATE", + }; + et_class.getattr(attr_name) + } +} + +#[pyo3::prelude::pyproto] +impl pyo3::class::basic::PyObjectProtocol for Sct { + fn __richcmp__( + &self, + other: pyo3::pycell::PyRef, + op: pyo3::class::basic::CompareOp, + ) -> pyo3::PyResult { + match op { + pyo3::class::basic::CompareOp::Eq => Ok(self.sct_data == other.sct_data), + pyo3::class::basic::CompareOp::Ne => Ok(self.sct_data != other.sct_data), + _ => Err(pyo3::exceptions::PyTypeError::new_err( + "SCTs cannot be ordered", + )), + } + } + + fn __hash__(&self) -> u64 { + let mut hasher = DefaultHasher::new(); + self.sct_data.hash(&mut hasher); + hasher.finish() + } +} + +#[pyo3::prelude::pyfunction] +fn encode_precertificate_signed_certificate_timestamps( + py: pyo3::Python<'_>, + extension: &pyo3::PyAny, +) -> pyo3::PyResult { + let mut length = 0; + for sct in extension.iter()? { + let sct = sct?.downcast::>()?; + length += sct.borrow().sct_data.len() + 2; + } + + let mut result = vec![]; + result.extend_from_slice(&(length as u16).to_be_bytes()); + for sct in extension.iter()? { + let sct = sct?.downcast::>()?; + result.extend_from_slice(&(sct.borrow().sct_data.len() as u16).to_be_bytes()); + result.extend_from_slice(&sct.borrow().sct_data); + } + Ok(pyo3::types::PyBytes::new(py, &asn1::write_single(&result.as_slice())).to_object(py)) +} + +pub(crate) fn parse_scts( + py: pyo3::Python<'_>, + data: &[u8], + entry_type: LogEntryType, +) -> Result { + let mut reader = TLSReader::new(data).read_length_prefixed()?; + + let py_scts = pyo3::types::PyList::empty(py); + while !reader.is_empty() { + let mut sct_data = reader.read_length_prefixed()?; + let raw_sct_data = sct_data.data.to_vec(); + let version = sct_data.read_byte()?; + if version != 0 { + return Err(PyAsn1Error::from(pyo3::exceptions::PyValueError::new_err( + "Invalid SCT version", + ))); + } + let log_id = sct_data.read_exact(32)?.try_into().unwrap(); + let timestamp = u64::from_be_bytes(sct_data.read_exact(8)?.try_into().unwrap()); + let _extensions = sct_data.read_length_prefixed()?; + let _sig_alg = sct_data.read_exact(2)?; + let _signature = sct_data.read_length_prefixed()?; + + let sct = Sct { + log_id, + timestamp, + entry_type: entry_type.clone(), + sct_data: raw_sct_data, + }; + py_scts.append(pyo3::PyCell::new(py, sct)?)?; + } + Ok(py_scts.to_object(py)) +} + #[pyo3::prelude::pyfunction] fn parse_x509_extension( py: pyo3::Python<'_>, @@ -364,13 +534,19 @@ fn parse_x509_extension( .to_object(py)) } else if oid == *AUTHORITY_KEY_IDENTIFIER_OID { Ok(parse_authority_key_identifier(py, ext_data)?) + } else if oid == *PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS_OID { + let contents = asn1::parse_single::<&[u8]>(ext_data)?; + let scts = parse_scts(py, contents, LogEntryType::PreCertificate)?; + Ok(x509_module + .call1("PrecertificateSignedCertificateTimestamps", (scts,))? + .to_object(py)) } else { Ok(py.None()) } } #[pyo3::prelude::pyfunction] -fn parse_crl_entry_extension( +pub(crate) fn parse_crl_entry_extension( py: pyo3::Python<'_>, der_oid: &[u8], ext_data: &[u8], @@ -468,6 +644,10 @@ pub(crate) fn create_submodule(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::pr submod.add_wrapped(pyo3::wrap_pyfunction!(parse_x509_extension))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_crl_entry_extension))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_crl_extension))?; + submod.add_wrapped(pyo3::wrap_pyfunction!( + encode_precertificate_signed_certificate_timestamps + ))?; + submod.add_class::()?; Ok(submod) } diff --git a/tests/x509/test_ocsp.py b/tests/x509/test_ocsp.py index e1ea7590a33b..0b8e49074cba 100644 --- a/tests/x509/test_ocsp.py +++ b/tests/x509/test_ocsp.py @@ -756,10 +756,6 @@ def test_repr(self): "" ) - @pytest.mark.supported( - only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), - skip_message="Requires CT support", - ) def test_eq(self, backend): sct1 = ( _load_data( @@ -783,10 +779,6 @@ def test_eq(self, backend): ) assert sct1 == sct2 - @pytest.mark.supported( - only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), - skip_message="Requires CT support", - ) def test_ne(self, backend): sct1 = ( _load_data( @@ -802,10 +794,6 @@ def test_ne(self, backend): assert sct1 != sct2 assert sct1 != object() - @pytest.mark.supported( - only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), - skip_message="Requires CT support", - ) def test_hash(self, backend): sct1 = ( _load_data( @@ -1053,10 +1041,6 @@ def test_invalid_serialize_encoding(self): with pytest.raises(ValueError): resp.public_bytes(serialization.Encoding.PEM) - @pytest.mark.supported( - only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), - skip_message="Requires CT support", - ) def test_single_extensions_sct(self, backend): resp = _load_data( os.path.join("x509", "ocsp", "resp-sct-extension.der"), @@ -1074,27 +1058,6 @@ def test_single_extensions_sct(self, backend): b"7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/cs=", ] - @pytest.mark.supported( - only_if=lambda backend: ( - not backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER - ), - skip_message="Requires OpenSSL < 1.1.0f", - ) - def test_skips_single_extensions_scts_if_unsupported(self, backend): - resp = _load_data( - os.path.join("x509", "ocsp", "resp-sct-extension.der"), - ocsp.load_der_ocsp_response, - ) - with pytest.raises(x509.ExtensionNotFound): - resp.single_extensions.get_extension_for_class( - x509.SignedCertificateTimestamps - ) - - ext = resp.single_extensions.get_extension_for_oid( - x509.ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS - ) - assert isinstance(ext.value, x509.UnrecognizedExtension) - def test_single_extensions(self, backend): resp = _load_data( os.path.join("x509", "ocsp", "resp-single-extension-reason.der"), diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index 89e4502bb381..6741def2a8c0 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -5288,10 +5288,6 @@ def test_repr(self): class TestSignedCertificateTimestamps(object): - @pytest.mark.supported( - only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), - skip_message="Requires CT support", - ) def test_eq(self, backend): sct = ( _load_cert( @@ -5317,10 +5313,6 @@ def test_eq(self, backend): ) assert sct == sct2 - @pytest.mark.supported( - only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), - skip_message="Requires CT support", - ) def test_ne(self, backend): sct = ( _load_cert( @@ -5347,10 +5339,6 @@ def test_ne(self, backend): assert sct != sct2 assert sct != object() - @pytest.mark.supported( - only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), - skip_message="Requires CT support", - ) def test_hash(self, backend): sct = ( _load_cert( @@ -5401,10 +5389,6 @@ def test_repr(self): "" ) - @pytest.mark.supported( - only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), - skip_message="Requires CT support", - ) def test_eq(self, backend): psct1 = ( _load_cert( @@ -5430,10 +5414,6 @@ def test_eq(self, backend): ) assert psct1 == psct2 - @pytest.mark.supported( - only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), - skip_message="Requires CT support", - ) def test_ne(self, backend): psct1 = ( _load_cert( @@ -5460,10 +5440,6 @@ def test_ne(self, backend): assert psct1 != psct2 assert psct1 != object() - @pytest.mark.supported( - only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), - skip_message="Requires CT support", - ) def test_ordering(self, backend): psct1 = ( _load_cert( @@ -5490,10 +5466,6 @@ def test_ordering(self, backend): with pytest.raises(TypeError): psct1[0] < psct2[0] - @pytest.mark.supported( - only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), - skip_message="Requires CT support", - ) def test_hash(self, backend): psct1 = ( _load_cert( @@ -5531,10 +5503,6 @@ def test_hash(self, backend): assert hash(psct1) == hash(psct2) assert hash(psct1) != hash(psct3) - @pytest.mark.supported( - only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), - skip_message="Requires CT support", - ) def test_simple(self, backend): cert = _load_cert( os.path.join("x509", "badssl-sct.pem"), @@ -5560,10 +5528,6 @@ def test_simple(self, backend): == x509.certificate_transparency.LogEntryType.PRE_CERTIFICATE ) - @pytest.mark.supported( - only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), - skip_message="Requires CT support", - ) def test_generate(self, backend): cert = _load_cert( os.path.join("x509", "badssl-sct.pem"), @@ -5587,31 +5551,6 @@ def test_generate(self, backend): ).value assert list(ext) == [sct] - @pytest.mark.supported( - only_if=lambda backend: backend._lib.CRYPTOGRAPHY_IS_LIBRESSL, - skip_message="Requires LibreSSL", - ) - def test_skips_scts_if_unsupported(self, backend): - cert = _load_cert( - os.path.join("x509", "badssl-sct.pem"), - x509.load_pem_x509_certificate, - backend, - ) - assert len(cert.extensions) == 10 - with pytest.raises(x509.ExtensionNotFound): - cert.extensions.get_extension_for_class( - x509.PrecertificateSignedCertificateTimestamps - ) - - ext = cert.extensions.get_extension_for_oid( - x509.ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS - ) - assert isinstance(ext.value, x509.UnrecognizedExtension) - - @pytest.mark.supported( - only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), - skip_message="Requires CT support", - ) def test_invalid_version(self, backend): cert = _load_cert( os.path.join("x509", "custom", "invalid-sct-version.der"), @@ -5621,10 +5560,6 @@ def test_invalid_version(self, backend): with pytest.raises(ValueError): cert.extensions - @pytest.mark.supported( - only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), - skip_message="Requires CT support", - ) def test_invalid_length(self, backend): cert = _load_cert( os.path.join("x509", "custom", "invalid-sct-length.der"), From d036964b3c45c80fc39e1d56444ca734496cc0a8 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 11 Jun 2021 08:15:51 -0500 Subject: [PATCH 0210/1456] oxidize issuing distribution point (#6108) * oxidize issuing distribution point * cleanup * clippy --- .../hazmat/backends/openssl/decode_asn1.py | 30 ----- src/cryptography/x509/extensions.py | 24 ++++ src/rust/src/x509.rs | 104 ++++++++++++++++-- 3 files changed, 120 insertions(+), 38 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index e0d7505f8390..244c517ce42c 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -291,35 +291,6 @@ def _decode_general_subtrees(backend, stack_subtrees): 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, - ) - - _DISTPOINT_TYPE_FULLNAME = 0 _DISTPOINT_TYPE_RELATIVENAME = 1 @@ -528,6 +499,5 @@ def _parse_asn1_generalized_time(backend, generalized_time): } _CRL_EXTENSION_HANDLERS = { - ExtensionOID.ISSUING_DISTRIBUTION_POINT: _decode_issuing_dist_point, ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, } diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 58e7ea7f5a5d..bbcb128723cd 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -684,6 +684,30 @@ class ReasonFlags(utils.Enum): remove_from_crl = "removeFromCRL" +# These are distribution point bit string mappings. Not to be confused with +# CRLReason reason flags bit string mappings. +# 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: ReasonFlags.key_compromise, + 2: ReasonFlags.ca_compromise, + 3: ReasonFlags.affiliation_changed, + 4: ReasonFlags.superseded, + 5: ReasonFlags.cessation_of_operation, + 6: ReasonFlags.certificate_hold, + 7: ReasonFlags.privilege_withdrawn, + 8: ReasonFlags.aa_compromise, +} + + class PolicyConstraints(ExtensionType): oid = ExtensionOID.POLICY_CONSTRAINTS diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index 902aa6969652..a0d1b4ab0d5d 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -25,6 +25,7 @@ lazy_static::lazy_static! { static ref SUBJECT_KEY_IDENTIFIER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.14").unwrap(); static ref INHIBIT_ANY_POLICY_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.54").unwrap(); static ref CRL_REASON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.21").unwrap(); + static ref ISSUING_DISTRIBUTION_POINT_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.28").unwrap(); static ref CERTIFICATE_ISSUER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.29").unwrap(); static ref CRL_NUMBER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.20").unwrap(); static ref INVALIDITY_DATE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.24").unwrap(); @@ -45,6 +46,40 @@ impl<'a> asn1::SimpleAsn1Readable<'a> for UnvalidatedIA5String<'a> { } } +#[derive(asn1::Asn1Read)] +struct IssuingDistributionPoint<'a> { + #[explicit(0)] + distribution_point: Option>, + + #[implicit(1)] + #[default(false)] + only_contains_user_certs: bool, + + #[implicit(2)] + #[default(false)] + only_contains_ca_certs: bool, + + #[implicit(3)] + only_some_reasons: Option>, + + #[implicit(4)] + #[default(false)] + indirect_crl: bool, + + #[implicit(5)] + #[default(false)] + only_contains_attribute_certs: bool, +} + +#[derive(asn1::Asn1Read)] +enum DistributionPointName<'a> { + #[implicit(0)] + FullName(asn1::SequenceOf<'a, GeneralName<'a>>), + + #[implicit(1)] + NameRelativeToCRLIssuer(asn1::SetOf<'a, AttributeTypeValue<'a>>), +} + #[derive(asn1::Asn1Read)] struct AuthorityKeyIdentifier<'a> { #[implicit(0)] @@ -55,6 +90,16 @@ struct AuthorityKeyIdentifier<'a> { authority_cert_serial_number: Option>, } +fn parse_distribution_point( + py: pyo3::Python<'_>, + dp: DistributionPointName<'_>, +) -> Result<(pyo3::PyObject, pyo3::PyObject), PyAsn1Error> { + Ok(match dp { + DistributionPointName::FullName(data) => (parse_general_names(py, data)?, py.None()), + DistributionPointName::NameRelativeToCRLIssuer(data) => (py.None(), parse_rdn(py, data)?), + }) +} + #[derive(asn1::Asn1Read)] enum GeneralName<'a> { #[implicit(0)] @@ -150,18 +195,26 @@ fn parse_name_attribute( .to_object(py)) } +fn parse_rdn<'a>( + py: pyo3::Python<'_>, + rdn: asn1::SetOf<'a, AttributeTypeValue<'a>>, +) -> Result { + let x509_module = py.import("cryptography.x509")?; + let py_attrs = pyo3::types::PySet::empty(py)?; + for attribute in rdn { + let na = parse_name_attribute(py, attribute)?; + py_attrs.add(na)?; + } + Ok(x509_module + .call_method1("RelativeDistinguishedName", (py_attrs,))? + .to_object(py)) +} + fn parse_name(py: pyo3::Python<'_>, name: Name<'_>) -> Result { let x509_module = py.import("cryptography.x509")?; let py_rdns = pyo3::types::PyList::empty(py); for rdn in name { - let py_attrs = pyo3::types::PySet::empty(py)?; - for attribute in rdn { - let na = parse_name_attribute(py, attribute)?; - py_attrs.add(na)?; - } - let py_rdn = x509_module - .call_method1("RelativeDistinguishedName", (py_attrs,))? - .to_object(py); + let py_rdn = parse_rdn(py, rdn)?; py_rdns.append(py_rdn)?; } let py_name = x509_module.call_method1("Name", (py_rdns,))?.to_object(py); @@ -633,6 +686,41 @@ fn parse_crl_extension( .to_object(py)) } else if oid == *AUTHORITY_KEY_IDENTIFIER_OID { Ok(parse_authority_key_identifier(py, ext_data)?) + } else if oid == *ISSUING_DISTRIBUTION_POINT_OID { + let reason_bit_mapping = py + .import("cryptography.x509.extensions")? + .getattr("_REASON_BIT_MAPPING")?; + let idp = asn1::parse_single::>(ext_data)?; + let (full_name, relative_name) = match idp.distribution_point { + Some(data) => parse_distribution_point(py, data)?, + None => (py.None(), py.None()), + }; + let reasons = match idp.only_some_reasons { + Some(bs) => { + let mut vec = Vec::new(); + for i in 1..=8 { + if bs.has_bit_set(i) { + vec.push(reason_bit_mapping.get_item(i)?); + } + } + pyo3::types::PyFrozenSet::new(py, &vec)?.to_object(py) + } + None => py.None(), + }; + Ok(x509_module + .call1( + "IssuingDistributionPoint", + ( + full_name, + relative_name, + idp.only_contains_user_certs, + idp.only_contains_ca_certs, + reasons, + idp.indirect_crl, + idp.only_contains_attribute_certs, + ), + )? + .to_object(py)) } else { Ok(py.None()) } From 6f0260b766458f5c5c49af784413795de14be94a Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 11 Jun 2021 16:12:29 -0500 Subject: [PATCH 0211/1456] fix certbot downstream (#6110) --- .github/downstream.d/certbot.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/downstream.d/certbot.sh b/.github/downstream.d/certbot.sh index e2890a3a100c..2479d0c25b86 100755 --- a/.github/downstream.d/certbot.sh +++ b/.github/downstream.d/certbot.sh @@ -5,8 +5,8 @@ case "${1}" in git clone --depth=1 https://github.com/certbot/certbot cd certbot git rev-parse HEAD - tools/pip_install_editable.py ./acme[dev] - tools/pip_install_editable.py ./certbot[dev] + tools/pip_install_editable.py ./acme[test] + tools/pip_install_editable.py ./certbot[test] ;; run) cd certbot From 11d9622995a4ff70ac0d1feb1bf2ce1f2df389ea Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 12 Jun 2021 08:41:34 -0500 Subject: [PATCH 0212/1456] add unrecognized extension CRL vector (#6111) * add unrecognized extension CRL vector * sigh * add test * always a linter --- docs/development/test-vectors.rst | 3 +++ tests/x509/test_x509.py | 13 +++++++++++++ .../x509/custom/crl_unrecognized_extension.der | Bin 0 -> 381 bytes 3 files changed, 16 insertions(+) create mode 100644 vectors/cryptography_vectors/x509/custom/crl_unrecognized_extension.der diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 3420fce8e2a8..e41cdf1712d7 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -517,6 +517,9 @@ Custom X.509 Certificate Revocation List Vectors * ``crl_idp_relativename_only.pem`` - Contains a CRL with an ``IssuingDistributionPoints`` extension with only a ``relativename`` for the distribution point. +* ``crl_unrecognized_extension.der`` - Contains a CRL containing an + unsupported extension type. The OID was encoded as "1.2.3.4.5" with an + ``extnValue`` of ``abcdef``. X.509 OCSP Test Vectors ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 9e0a6fbaaa6e..306fbe246219 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -173,6 +173,19 @@ def test_update_dates(self, backend): assert crl.next_update.isoformat() == "2016-01-01T00:00:00" assert crl.last_update.isoformat() == "2015-01-01T00:00:00" + def test_unrecognized_extension(self, backend): + crl = _load_cert( + os.path.join("x509", "custom", "crl_unrecognized_extension.der"), + x509.load_der_x509_crl, + backend, + ) + unrecognized = x509.UnrecognizedExtension( + x509.ObjectIdentifier("1.2.3.4.5"), + b"abcdef", + ) + ext = crl.extensions.get_extension_for_oid(unrecognized.oid) + assert ext.value == unrecognized + def test_revoked_cert_retrieval(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_all_reasons.pem"), diff --git a/vectors/cryptography_vectors/x509/custom/crl_unrecognized_extension.der b/vectors/cryptography_vectors/x509/custom/crl_unrecognized_extension.der new file mode 100644 index 0000000000000000000000000000000000000000..a29fe2025c3d4df53c569adfa5f62759a59f1442 GIT binary patch literal 381 zcmXqLVyrYsW@2PC;AP{~YV&CO&dbQi&B|aPYbb3X$;KSY!ptL-TvS<5lAm6bSddYv zmzl5N>?qD_U}RuuU}y*;4Wh((jSY~v3xo^=4EWesw3t~~S=bVjl2cOC(9CCUVq|2f zwy$~DYZuRS;lR!<%)4VN&5avm*(UVADJZ^_^!#9COX<{D9zKyT1+FV~*KN`N5MjFZ zhphi6@s~ZO1^3r)a+&!1t%3FX2X7K?mARW#=bRDfxy61jSaMnV{jZXnyeB_1^yhG^ zK7U6|$9gA=-?40tzRxax?cS%3Rka77;l5n6zoP1&<%;ro&Z>uAU2Ix#^nJX$n46*D z+A|+tN3e)o-QnL~jM(yxLvYZN$E?bUmx@I&ZN$r|%rJD$&ow-#CA z6)|Dk Date: Sat, 12 Jun 2021 08:42:03 -0500 Subject: [PATCH 0213/1456] add nameconstraints vector with invalid length for IPv6 + netmask (#6112) --- docs/development/test-vectors.rst | 4 ++++ tests/x509/test_x509_ext.py | 12 ++++++++++++ .../x509/custom/nc_ip_invalid_length.pem | 19 +++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 vectors/cryptography_vectors/x509/custom/nc_ip_invalid_length.pem diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index e41cdf1712d7..6fae15ce2d9f 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -377,6 +377,10 @@ Custom X.509 Vectors * ``nc_single_ip_netmask.pem`` - An RSA 2048 bit self-signed certificate containing a name constraints extension with a permitted element that has two IPs with ``/32`` and ``/128`` network masks. +* ``nc_ip_invalid_length.pem`` - An RSA 2048 bit self-signed certificate + containing a name constraints extension with a permitted element that has an + invalid length (33 bytes instead of 32) for an ``IPv6`` address with + network mask. The signature on this certificate is invalid. * ``cp_user_notice_with_notice_reference.pem`` - An RSA 2048 bit self-signed certificate containing a certificate policies extension with a notice reference in the user notice. diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index 6741def2a8c0..a3db196efe28 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -3568,6 +3568,18 @@ def test_single_ip_netmask(self, backend): excluded_subtrees=None, ) + def test_ip_invalid_length(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "nc_ip_invalid_length.pem"), + x509.load_pem_x509_certificate, + backend, + ) + # NOTE: This will change to ValueError upon oxidization. + with pytest.raises(AssertionError): + cert.extensions.get_extension_for_oid( + ExtensionOID.NAME_CONSTRAINTS + ) + def test_invalid_netmask(self, backend): cert = _load_cert( os.path.join("x509", "custom", "nc_invalid_ip_netmask.pem"), diff --git a/vectors/cryptography_vectors/x509/custom/nc_ip_invalid_length.pem b/vectors/cryptography_vectors/x509/custom/nc_ip_invalid_length.pem new file mode 100644 index 000000000000..e4df5184d19f --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/nc_ip_invalid_length.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIC/jCCAeagAwIBAgITBnA4pkis5m3OGusBaihd9qH0hzANBgkqhkiG9w0BAQsF +ADAXMRUwEwYDVQQDDAxjcnlwdG9ncmFwaHkwHhcNMTUwNzAxMjAxNDAwWhcNMTYw +NjMwMjAxNDAwWjAXMRUwEwYDVQQDDAxjcnlwdG9ncmFwaHkwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCYyaGtu90vcm+jN+SoQHXxWMQyplY1neL9KjfE ++TsKKcy8TKJEqlT8qZr6bIL3KVbTIiYO8bCW9fHSMgHWrmtr37LlFoQ3emcLfDbM +kybmOolAxA78im0L2BIW1wT2iSHh1p/ZO5QLdt+e8zP5AkZAnXCZk912RcJYyGUW +7JQzzRfEANSLE9Gmh78NsxWNI1Ipc3dhyuk3+YHwePGCzLCeXCiF4FHGNMg8Drtr +rENNHZjHJCbMLfK9irHV5Xh1FHTK8xlqEq+YecpqboUyqgWVOOvpxUxiKagfp//Z ++iFDC1+GgpuupzFUiHPSVCZGMnE3bHvIBOkoHkNu7kNK7VX3AgMBAAGjQzBBMD8G +A1UdHgEB/wQ1MDOgMTAjhyEA/wAAAAAAAAAAAAAAAAAA//////////////////// +//8wCocIwKgAAf////8wDQYJKoZIhvcNAQELBQADggEBAF0g5qJ5waYr7FvzShPO +XNYaOOPSvfPtXBVA+dVXiuNqD1HdBkUAlNxE2CeWMiuzjKEKnuC07TQ8emQhfus/ +67WXLX3acEZqodnmxp96g7NRQHJJMMEgkbZCU3YM55rTuvNC7ORr3jRa4GCZGHxY +4zlqcwsqbHv9497lYEmpJowUUuATrMl+KO7azfpNTJkDqzKVhLS5Zq2SaTOurID9 +I1qSPeZeKWiDKZBWq8AgkHyQjQaZe1KJfgQ+Lyb3/ye3+2cMUDBFggT52JNxCjJy +mmgrJqkTFdVu0s8S9O3RzM1p7AvyOaCTY+B3bYRnCCX9SbrfQPShVaHTiQMSjs4s +9mk= +-----END CERTIFICATE----- From 7a06e8a47c1d45057a43b190fdcb27e7477afb31 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 12 Jun 2021 10:16:09 -0500 Subject: [PATCH 0214/1456] oxidize CRLDP and FreshestCRL (#6109) * oxidize CRLDP * oxidize freshestcrl * coverage fixes * remove more functions --- .../hazmat/backends/openssl/backend.py | 2 - .../hazmat/backends/openssl/decode_asn1.py | 118 ------------------ src/rust/src/x509.rs | 103 ++++++++++++--- 3 files changed, 86 insertions(+), 137 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index b6481f224088..bfc9dd07a7a3 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -18,7 +18,6 @@ from cryptography.hazmat.backends.openssl.cmac import _CMACContext from cryptography.hazmat.backends.openssl.decode_asn1 import ( _CRL_ENTRY_REASON_ENUM_TO_CODE, - _CRL_EXTENSION_HANDLERS, _EXTENSION_HANDLERS_BASE, _X509ExtensionParser, ) @@ -410,7 +409,6 @@ def _register_x509_ext_parsers(self): ext_count=self._lib.X509_CRL_get_ext_count, get_ext=self._lib.X509_CRL_get_ext, rust_callback=rust_x509.parse_crl_extension, - handlers=_CRL_EXTENSION_HANDLERS, ) self._ocsp_basicresp_ext_parser = _X509ExtensionParser( self, diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 244c517ce42c..0e1f19fc6f3c 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -69,17 +69,6 @@ def _decode_x509_name(backend, x509_name): return x509.Name(x509.RelativeDistinguishedName(rdn) for rdn in attributes) -def _decode_general_names(backend, gns): - num = backend._lib.sk_GENERAL_NAME_num(gns) - names = [] - for i in range(num): - gn = backend._lib.sk_GENERAL_NAME_value(gns, i) - backend.openssl_assert(gn != backend._ffi.NULL) - names.append(_decode_general_name(backend, gn)) - - return names - - # This is now a hacked up decoder where we progressively remove chunks as # we port more and more to rust. SAN exercised every branch in this, but # other extensions (which are still in Python/OpenSSL) don't so we'll remove @@ -295,107 +284,6 @@ def _decode_general_subtrees(backend, stack_subtrees): _DISTPOINT_TYPE_RELATIVENAME = 1 -def _decode_dist_points(backend, cdps): - cdps = backend._ffi.cast("Cryptography_STACK_OF_DIST_POINT *", cdps) - cdps = backend._ffi.gc(cdps, backend._lib.CRL_DIST_POINTS_free) - - num = backend._lib.sk_DIST_POINT_num(cdps) - dist_points = [] - for i in range(num): - full_name = None - relative_name = None - crl_issuer = None - reasons = None - cdp = backend._lib.sk_DIST_POINT_value(cdps, i) - if cdp.reasons != backend._ffi.NULL: - reasons = _decode_reasons(backend, cdp.reasons) - - if cdp.CRLissuer != backend._ffi.NULL: - crl_issuer = _decode_general_names(backend, cdp.CRLissuer) - - # Certificates may have a crl_issuer/reasons and no distribution - # point so make sure it's not null. - if cdp.distpoint != backend._ffi.NULL: - full_name, relative_name = _decode_distpoint( - backend, cdp.distpoint - ) - - dist_points.append( - x509.DistributionPoint( - full_name, relative_name, reasons, crl_issuer - ) - ) - - 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 _REASON_BIT_MAPPING.items(): - 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) - - -def _decode_freshest_crl(backend, cdps): - dist_points = _decode_dist_points(backend, cdps) - return x509.FreshestCRL(dist_points) - - # CRLReason ::= ENUMERATED { # unspecified (0), # keyCompromise (1), @@ -493,11 +381,5 @@ def _parse_asn1_generalized_time(backend, generalized_time): _EXTENSION_HANDLERS_BASE = { ExtensionOID.CERTIFICATE_POLICIES: _decode_certificate_policies, - ExtensionOID.CRL_DISTRIBUTION_POINTS: _decode_crl_distribution_points, - ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, ExtensionOID.NAME_CONSTRAINTS: _decode_name_constraints, } - -_CRL_EXTENSION_HANDLERS = { - ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, -} diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index a0d1b4ab0d5d..e38b9671b091 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -27,6 +27,8 @@ lazy_static::lazy_static! { static ref CRL_REASON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.21").unwrap(); static ref ISSUING_DISTRIBUTION_POINT_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.28").unwrap(); static ref CERTIFICATE_ISSUER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.29").unwrap(); + static ref CRL_DISTRIBUTION_POINTS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.31").unwrap(); + static ref FRESHEST_CRL_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.46").unwrap(); static ref CRL_NUMBER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.20").unwrap(); static ref INVALIDITY_DATE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.24").unwrap(); static ref DELTA_CRL_INDICATOR_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.27").unwrap(); @@ -71,6 +73,18 @@ struct IssuingDistributionPoint<'a> { only_contains_attribute_certs: bool, } +#[derive(asn1::Asn1Read)] +struct DistributionPoint<'a> { + #[explicit(0)] + distribution_point: Option>, + + #[implicit(1)] + reasons: Option>, + + #[implicit(2)] + crl_issuer: Option>>, +} + #[derive(asn1::Asn1Read)] enum DistributionPointName<'a> { #[implicit(0)] @@ -90,7 +104,7 @@ struct AuthorityKeyIdentifier<'a> { authority_cert_serial_number: Option>, } -fn parse_distribution_point( +fn parse_distribution_point_name( py: pyo3::Python<'_>, dp: DistributionPointName<'_>, ) -> Result<(pyo3::PyObject, pyo3::PyObject), PyAsn1Error> { @@ -100,6 +114,62 @@ fn parse_distribution_point( }) } +fn parse_distribution_point( + py: pyo3::Python<'_>, + dp: DistributionPoint<'_>, +) -> Result { + let (full_name, relative_name) = match dp.distribution_point { + Some(data) => parse_distribution_point_name(py, data)?, + None => (py.None(), py.None()), + }; + let reasons = parse_distribution_point_reasons(py, dp.reasons)?; + let crl_issuer = match dp.crl_issuer { + Some(aci) => parse_general_names(py, aci)?, + None => py.None(), + }; + let x509_module = py.import("cryptography.x509")?; + Ok(x509_module + .call1( + "DistributionPoint", + (full_name, relative_name, reasons, crl_issuer), + )? + .to_object(py)) +} + +fn parse_distribution_points( + py: pyo3::Python<'_>, + data: &[u8], +) -> Result { + let dps = asn1::parse_single::>>(data)?; + let py_dps = pyo3::types::PyList::empty(py); + for dp in dps { + let py_dp = parse_distribution_point(py, dp)?; + py_dps.append(py_dp)?; + } + Ok(py_dps.to_object(py)) +} + +fn parse_distribution_point_reasons( + py: pyo3::Python<'_>, + reasons: Option>, +) -> Result { + let reason_bit_mapping = py + .import("cryptography.x509.extensions")? + .getattr("_REASON_BIT_MAPPING")?; + Ok(match reasons { + Some(bs) => { + let mut vec = Vec::new(); + for i in 1..=8 { + if bs.has_bit_set(i) { + vec.push(reason_bit_mapping.get_item(i)?); + } + } + pyo3::types::PyFrozenSet::new(py, &vec)?.to_object(py) + } + None => py.None(), + }) +} + #[derive(asn1::Asn1Read)] enum GeneralName<'a> { #[implicit(0)] @@ -587,6 +657,15 @@ fn parse_x509_extension( .to_object(py)) } else if oid == *AUTHORITY_KEY_IDENTIFIER_OID { Ok(parse_authority_key_identifier(py, ext_data)?) + } else if oid == *CRL_DISTRIBUTION_POINTS_OID { + let dp = parse_distribution_points(py, ext_data)?; + Ok(x509_module + .call1("CRLDistributionPoints", (dp,))? + .to_object(py)) + } else if oid == *FRESHEST_CRL_OID { + Ok(x509_module + .call1("FreshestCRL", (parse_distribution_points(py, ext_data)?,))? + .to_object(py)) } else if oid == *PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS_OID { let contents = asn1::parse_single::<&[u8]>(ext_data)?; let scts = parse_scts(py, contents, LogEntryType::PreCertificate)?; @@ -687,26 +766,12 @@ fn parse_crl_extension( } else if oid == *AUTHORITY_KEY_IDENTIFIER_OID { Ok(parse_authority_key_identifier(py, ext_data)?) } else if oid == *ISSUING_DISTRIBUTION_POINT_OID { - let reason_bit_mapping = py - .import("cryptography.x509.extensions")? - .getattr("_REASON_BIT_MAPPING")?; let idp = asn1::parse_single::>(ext_data)?; let (full_name, relative_name) = match idp.distribution_point { - Some(data) => parse_distribution_point(py, data)?, + Some(data) => parse_distribution_point_name(py, data)?, None => (py.None(), py.None()), }; - let reasons = match idp.only_some_reasons { - Some(bs) => { - let mut vec = Vec::new(); - for i in 1..=8 { - if bs.has_bit_set(i) { - vec.push(reason_bit_mapping.get_item(i)?); - } - } - pyo3::types::PyFrozenSet::new(py, &vec)?.to_object(py) - } - None => py.None(), - }; + let reasons = parse_distribution_point_reasons(py, idp.only_some_reasons)?; Ok(x509_module .call1( "IssuingDistributionPoint", @@ -721,6 +786,10 @@ fn parse_crl_extension( ), )? .to_object(py)) + } else if oid == *FRESHEST_CRL_OID { + Ok(x509_module + .call1("FreshestCRL", (parse_distribution_points(py, ext_data)?,))? + .to_object(py)) } else { Ok(py.None()) } From f3612c8585cf6320b325e58fde4ff7f14d4dcc80 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 12 Jun 2021 15:29:22 -0500 Subject: [PATCH 0215/1456] name constraint vector with invalid IPv4 netmask (#6114) --- docs/development/test-vectors.rst | 4 ++++ tests/x509/test_x509_ext.py | 13 ++++++++++++- .../x509/custom/nc_invalid_ip4_netmask.der | Bin 0 -> 733 bytes 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 vectors/cryptography_vectors/x509/custom/nc_invalid_ip4_netmask.der diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 6fae15ce2d9f..0aed4313b0e9 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -374,6 +374,10 @@ Custom X.509 Vectors * ``nc_invalid_ip_netmask.pem`` - An RSA 2048 bit self-signed certificate containing a name constraints extension with a permitted element that has an ``IPv6`` IP and an invalid network mask. +* ``nc_invalid_ip4_netmask.der`` - An RSA 2048 bit self-signed certificate + containing a name constraints extension with a permitted element that has an + ``IPv4`` IP and an invalid network mask. The signature on this certificate + is invalid. * ``nc_single_ip_netmask.pem`` - An RSA 2048 bit self-signed certificate containing a name constraints extension with a permitted element that has two IPs with ``/32`` and ``/128`` network masks. diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index a3db196efe28..166ab256b896 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -3580,7 +3580,7 @@ def test_ip_invalid_length(self, backend): ExtensionOID.NAME_CONSTRAINTS ) - def test_invalid_netmask(self, backend): + def test_invalid_ipv6_netmask(self, backend): cert = _load_cert( os.path.join("x509", "custom", "nc_invalid_ip_netmask.pem"), x509.load_pem_x509_certificate, @@ -3591,6 +3591,17 @@ def test_invalid_netmask(self, backend): ExtensionOID.NAME_CONSTRAINTS ) + def test_invalid_ipv4_netmask(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "nc_invalid_ip4_netmask.der"), + x509.load_der_x509_certificate, + backend, + ) + with pytest.raises(ValueError): + cert.extensions.get_extension_for_oid( + ExtensionOID.NAME_CONSTRAINTS + ) + def test_certbuilder(self, backend): permitted = [ ".example.org", diff --git a/vectors/cryptography_vectors/x509/custom/nc_invalid_ip4_netmask.der b/vectors/cryptography_vectors/x509/custom/nc_invalid_ip4_netmask.der new file mode 100644 index 0000000000000000000000000000000000000000..ea3e3515b5c437065a947191d9832d8741770c83 GIT binary patch literal 733 zcmXqLV!CP2#CUK4GZP~dlQ3I>#WIgI&vMU6y=KhPi2b(kOS=It8>d#AN85K^Mn-N{ z1_N-99-ic)%7T*o^rFOqj7kGJab81H19JmIBLhPd1A{0a*UZ4o*Z|7K zt+9zw3E2`xRtDxKMt%mMv$&X=7#SI6oLsne_g(#>{Ke)^RydS?j5uPnEX;K7qrY0_ zM}As!X`b2Rv&dyt$e)$7e&sZM*9^O?q{jDg!?dp-FBvgjTbG@Ef74U37W1lf?i#Z* zlhvMCbvhj3`_q-neM3m>I?K0C#fR7C-?W~>U3P!oXXBqtZVqz`W=_6a=6WdNM5@@E zDaL2Tk1$;67QVQweLwGJ(O%^s&EoRJQ!mYbHh!r1*mP#Yycmtv2Z6^-PT276&R*l} zD?8)3irN|7PkXyIUVU0oDpGRlvt*Xg`Wcm{vhrGuRVIIPm<;e`Q`s_{!(=2 zj&Ez4y>7W-NJsId5H&ZWLi3#J6D%(^nRC#cj_M7O>Uc%>Mu1Q%uzO?uA z+Za)YpI5`X9%u0f-eq%Tm~zMEhWa!k?ae(4x#m6C^47$rDn+sGwf*a@({*ca6}V+B zy!q_d{Ho^7feuBU1_u=;ZgUDQ<9R;o@~+QLZ=Ph|Gl_bTFjJx?;<05`F}GGu_20+$ zo+fy%RO=B5dLX>!WSz#lTW5dy`pjfrZ8WuI%g(g5lQNCht!enH95u=IS)67@v*v`b z)dv(N)J*7Qn^_&yS;u0hulD`F`u5-HJOKu-O)NieOfKXyDw>s{t+rBF^lILv^Fm+V rUOaO)^9}bW%LS8@AC%{|q;shL_1tye;mg9%g_k>-h5F9ve9Hs?4VyUW literal 0 HcmV?d00001 From a0075afb7b65331b7c1d2a9b667ece933321edd8 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 12 Jun 2021 16:42:02 -0500 Subject: [PATCH 0216/1456] oxidize nameconstraints (#6113) * oxidize nameconstraints * cargo fmt * fix logic * make clippy happy * make it work with rust 1.46.0 * missed these * coverage * review comments --- .../hazmat/backends/openssl/decode_asn1.py | 86 ------------- src/rust/src/x509.rs | 113 +++++++++++++++++- tests/x509/test_x509_ext.py | 3 +- 3 files changed, 110 insertions(+), 92 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 0e1f19fc6f3c..843e0e3ca1ec 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -4,7 +4,6 @@ import datetime -import ipaddress import typing from cryptography import x509 @@ -69,63 +68,6 @@ def _decode_x509_name(backend, x509_name): return x509.Name(x509.RelativeDistinguishedName(rdn) for rdn in attributes) -# This is now a hacked up decoder where we progressively remove chunks as -# we port more and more to rust. SAN exercised every branch in this, but -# other extensions (which are still in Python/OpenSSL) don't so we'll remove -# anything that isn't covered progressively until we remove the entire function -def _decode_general_name(backend, gn): - if gn.type == backend._lib.GEN_DNS: - # Convert to bytes and then decode to utf8. We don't use - # asn1_string_to_utf8 here because it doesn't properly convert - # utf8 from ia5strings. - data = _asn1_string_to_bytes(backend, gn.d.dNSName).decode("utf8") - # We don't use the constructor for DNSName so we can bypass validation - # This allows us to create DNSName objects that have unicode chars - # when a certificate (against the RFC) contains them. - return x509.DNSName._init_without_validation(data) - elif gn.type == backend._lib.GEN_URI: - # Convert to bytes and then decode to utf8. We don't use - # asn1_string_to_utf8 here because it doesn't properly convert - # utf8 from ia5strings. - data = _asn1_string_to_bytes( - backend, gn.d.uniformResourceIdentifier - ).decode("utf8") - # We don't use the constructor for URI so we can bypass validation - # This allows us to create URI objects that have unicode chars - # when a certificate (against the RFC) contains them. - return x509.UniformResourceIdentifier._init_without_validation(data) - elif gn.type == backend._lib.GEN_IPADD: - data = _asn1_string_to_bytes(backend, gn.d.iPAddress) - data_len = len(data) - assert data_len == 8 or data_len == 32 - # This is an IPv4 or IPv6 Network and not a single IP. This - # type of data appears in Name Constraints. Unfortunately, - # ipaddress doesn't support packed bytes + netmask. Additionally, - # IPv6Network can only handle CIDR rather than the full 16 byte - # netmask. To handle this we convert the netmask to integer, then - # find the first 0 bit, which will be the prefix. If another 1 - # bit is present after that the netmask is invalid. - base = ipaddress.ip_address(data[: data_len // 2]) - netmask = ipaddress.ip_address(data[data_len // 2 :]) - bits = bin(int(netmask))[2:] - prefix = bits.find("0") - # If no 0 bits are found it is a /32 or /128 - if prefix == -1: - prefix = len(bits) - - if "1" in bits[prefix:]: - raise ValueError("Invalid netmask") - - ip = ipaddress.ip_network(base.exploded + "/{}".format(prefix)) - - return x509.IPAddress(ip) - else: - assert gn.type == backend._lib.GEN_DIRNAME - return x509.DirectoryName( - _decode_x509_name(backend, gn.d.directoryName) - ) - - class _X509ExtensionParser(object): def __init__( self, backend, ext_count, get_ext, rust_callback, handlers={} @@ -254,36 +196,9 @@ def _decode_user_notice(backend, un): return x509.UserNotice(notice_reference, explicit_text) -def _decode_name_constraints(backend, nc): - nc = backend._ffi.cast("NAME_CONSTRAINTS *", nc) - nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free) - permitted = _decode_general_subtrees(backend, nc.permittedSubtrees) - excluded = _decode_general_subtrees(backend, nc.excludedSubtrees) - return x509.NameConstraints( - permitted_subtrees=permitted, excluded_subtrees=excluded - ) - - -def _decode_general_subtrees(backend, stack_subtrees): - if stack_subtrees == backend._ffi.NULL: - return None - - num = backend._lib.sk_GENERAL_SUBTREE_num(stack_subtrees) - subtrees = [] - - for i in range(num): - obj = backend._lib.sk_GENERAL_SUBTREE_value(stack_subtrees, i) - backend.openssl_assert(obj != backend._ffi.NULL) - name = _decode_general_name(backend, obj.base) - subtrees.append(name) - - return subtrees - - _DISTPOINT_TYPE_FULLNAME = 0 _DISTPOINT_TYPE_RELATIVENAME = 1 - # CRLReason ::= ENUMERATED { # unspecified (0), # keyCompromise (1), @@ -381,5 +296,4 @@ def _parse_asn1_generalized_time(backend, generalized_time): _EXTENSION_HANDLERS_BASE = { ExtensionOID.CERTIFICATE_POLICIES: _decode_certificate_policies, - ExtensionOID.NAME_CONSTRAINTS: _decode_name_constraints, } diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index e38b9671b091..161562cabab1 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -27,6 +27,7 @@ lazy_static::lazy_static! { static ref CRL_REASON_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.21").unwrap(); static ref ISSUING_DISTRIBUTION_POINT_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.28").unwrap(); static ref CERTIFICATE_ISSUER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.29").unwrap(); + static ref NAME_CONSTRAINTS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.30").unwrap(); static ref CRL_DISTRIBUTION_POINTS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.31").unwrap(); static ref FRESHEST_CRL_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.46").unwrap(); static ref CRL_NUMBER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.20").unwrap(); @@ -48,6 +49,38 @@ impl<'a> asn1::SimpleAsn1Readable<'a> for UnvalidatedIA5String<'a> { } } +#[derive(asn1::Asn1Read)] +struct NameConstraints<'a> { + #[implicit(0)] + permitted_subtrees: Option>>, + + #[implicit(1)] + excluded_subtrees: Option>>, +} + +#[derive(asn1::Asn1Read)] +struct GeneralSubtree<'a> { + base: GeneralName<'a>, + + #[implicit(0)] + #[default(0u64)] + _minimum: u64, + + #[implicit(1)] + _maximum: Option, +} + +fn parse_general_subtrees<'a>( + py: pyo3::Python<'_>, + subtrees: asn1::SequenceOf<'a, GeneralSubtree<'a>>, +) -> Result { + let gns = pyo3::types::PyList::empty(py); + for gs in subtrees { + gns.append(parse_general_name(py, gs.base)?)?; + } + Ok(gns.to_object(py)) +} + #[derive(asn1::Asn1Read)] struct IssuingDistributionPoint<'a> { #[explicit(0)] @@ -291,6 +324,59 @@ fn parse_name(py: pyo3::Python<'_>, name: Name<'_>) -> Result Result { + // we invert and check leading zeros because leading_ones wasn't stabilized + // until 1.46.0. When we raise our MSRV we should change this + if (!num).leading_zeros() + num.trailing_zeros() != 32 { + return Err(PyAsn1Error::from(pyo3::exceptions::PyValueError::new_err( + "Invalid netmask", + ))); + } + Ok((!num).leading_zeros()) +} + +fn ipv6_netmask(num: u128) -> Result { + // we invert and check leading zeros because leading_ones wasn't stabilized + // until 1.46.0. When we raise our MSRV we should change this + if (!num).leading_zeros() + num.trailing_zeros() != 128 { + return Err(PyAsn1Error::from(pyo3::exceptions::PyValueError::new_err( + "Invalid netmask", + ))); + } + Ok((!num).leading_zeros()) +} + +fn create_ip_network(py: pyo3::Python<'_>, data: &[u8]) -> Result { + let ip_module = py.import("ipaddress")?; + let x509_module = py.import("cryptography.x509")?; + let prefix = match data.len() { + 8 => { + let num = u32::from_be_bytes(data[4..].try_into().unwrap()); + ipv4_netmask(num) + } + 32 => { + let num = u128::from_be_bytes(data[16..].try_into().unwrap()); + ipv6_netmask(num) + } + _ => Err(PyAsn1Error::from(pyo3::exceptions::PyValueError::new_err( + format!("Invalid IPNetwork, must be 8 bytes for IPv4 and 32 bytes for IPv6. Found length: {}", data.len()), + ))), + }; + let base = ip_module.call_method1( + "ip_address", + (pyo3::types::PyBytes::new(py, &data[..data.len() / 2]),), + )?; + let net = format!( + "{}/{}", + base.getattr("exploded")?.extract::<&str>()?, + prefix? + ); + let addr = ip_module.call_method1("ip_network", (net,))?.to_object(py); + Ok(x509_module + .call_method1("IPAddress", (addr,))? + .to_object(py)) +} + fn parse_general_name( py: pyo3::Python<'_>, gn: GeneralName<'_>, @@ -325,10 +411,16 @@ fn parse_general_name( .to_object(py), GeneralName::IPAddress(data) => { let ip_module = py.import("ipaddress")?; - let ip_addr = ip_module.call_method1("ip_address", (data,))?.to_object(py); - x509_module - .call_method1("IPAddress", (ip_addr,))? - .to_object(py) + if data.len() == 4 || data.len() == 16 { + let addr = ip_module.call_method1("ip_address", (data,))?.to_object(py); + x509_module + .call_method1("IPAddress", (addr,))? + .to_object(py) + } else { + // if it's not an IPv4 or IPv6 we assume it's an IPNetwork and + // verify length in this function. + create_ip_network(py, data)? + } } GeneralName::RegisteredID(data) => { let oid = x509_module @@ -672,6 +764,19 @@ fn parse_x509_extension( Ok(x509_module .call1("PrecertificateSignedCertificateTimestamps", (scts,))? .to_object(py)) + } else if oid == *NAME_CONSTRAINTS_OID { + let nc = asn1::parse_single::>(ext_data)?; + let permitted_subtrees = match nc.permitted_subtrees { + Some(data) => parse_general_subtrees(py, data)?, + None => py.None(), + }; + let excluded_subtrees = match nc.excluded_subtrees { + Some(data) => parse_general_subtrees(py, data)?, + None => py.None(), + }; + Ok(x509_module + .call1("NameConstraints", (permitted_subtrees, excluded_subtrees))? + .to_object(py)) } else { Ok(py.None()) } diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index 166ab256b896..a69f40d4e43d 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -3574,8 +3574,7 @@ def test_ip_invalid_length(self, backend): x509.load_pem_x509_certificate, backend, ) - # NOTE: This will change to ValueError upon oxidization. - with pytest.raises(AssertionError): + with pytest.raises(ValueError): cert.extensions.get_extension_for_oid( ExtensionOID.NAME_CONSTRAINTS ) From 13839c36b8dffd2794d612b1b0d9306c90a25d83 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 12 Jun 2021 18:13:30 -0400 Subject: [PATCH 0217/1456] Remove OpenSSL ct.h usage (#6115) --- src/_cffi_src/build_openssl.py | 1 - src/_cffi_src/openssl/ct.py | 117 ------------------ .../hazmat/bindings/openssl/_conditional.py | 23 ---- 3 files changed, 141 deletions(-) delete mode 100644 src/_cffi_src/openssl/ct.py diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py index 557296ed5354..df11130371d1 100644 --- a/src/_cffi_src/build_openssl.py +++ b/src/_cffi_src/build_openssl.py @@ -86,7 +86,6 @@ def _extra_compile_args(platform): "cmac", "conf", "crypto", - "ct", "dh", "dsa", "ec", diff --git a/src/_cffi_src/openssl/ct.py b/src/_cffi_src/openssl/ct.py deleted file mode 100644 index 6271497625db..000000000000 --- a/src/_cffi_src/openssl/ct.py +++ /dev/null @@ -1,117 +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. - - -INCLUDES = """ -#if CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER && !defined(OPENSSL_NO_CT) -#include - -typedef STACK_OF(SCT) Cryptography_STACK_OF_SCT; -#endif -""" - -TYPES = """ -static const long Cryptography_HAS_SCT; - -typedef enum { - SCT_VERSION_NOT_SET, - SCT_VERSION_V1 -} sct_version_t; - -typedef enum { - CT_LOG_ENTRY_TYPE_NOT_SET, - CT_LOG_ENTRY_TYPE_X509, - CT_LOG_ENTRY_TYPE_PRECERT -} ct_log_entry_type_t; - -typedef enum { - SCT_SOURCE_UNKNOWN, - SCT_SOURCE_TLS_EXTENSION, - SCT_SOURCE_X509V3_EXTENSION, - SCT_SOURCE_OCSP_STAPLED_RESPONSE -} sct_source_t; - -typedef ... SCT; -typedef ... Cryptography_STACK_OF_SCT; -""" - -FUNCTIONS = """ -sct_version_t SCT_get_version(const SCT *); - -ct_log_entry_type_t SCT_get_log_entry_type(const SCT *); - -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); - -Cryptography_STACK_OF_SCT *sk_SCT_new_null(void); -void sk_SCT_free(Cryptography_STACK_OF_SCT *); -int sk_SCT_num(const Cryptography_STACK_OF_SCT *); -SCT *sk_SCT_value(const Cryptography_STACK_OF_SCT *, int); -int sk_SCT_push(Cryptography_STACK_OF_SCT *, SCT *); - -void SCT_LIST_free(Cryptography_STACK_OF_SCT *); - -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 = """ -#if CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER && !defined(OPENSSL_NO_CT) -static const long Cryptography_HAS_SCT = 1; -#else -static const long Cryptography_HAS_SCT = 0; - -typedef enum { - SCT_VERSION_NOT_SET, - SCT_VERSION_V1 -} sct_version_t; -typedef enum { - CT_LOG_ENTRY_TYPE_NOT_SET, - CT_LOG_ENTRY_TYPE_X509, - CT_LOG_ENTRY_TYPE_PRECERT -} ct_log_entry_type_t; -typedef enum { - SCT_SOURCE_UNKNOWN, - SCT_SOURCE_TLS_EXTENSION, - SCT_SOURCE_X509V3_EXTENSION, - SCT_SOURCE_OCSP_STAPLED_RESPONSE -} sct_source_t; - -/* OpenSSL compiled with `no-ct` still defines the `SCT` struct. */ -#if !defined(OPENSSL_NO_CT) -typedef void SCT; -#endif - -typedef void Cryptography_STACK_OF_SCT; - -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; - -Cryptography_STACK_OF_SCT *(*sk_SCT_new_null)(void) = NULL; -void (*sk_SCT_free)(Cryptography_STACK_OF_SCT *) = NULL; -int (*sk_SCT_num)(const Cryptography_STACK_OF_SCT *) = NULL; -SCT *(*sk_SCT_value)(const Cryptography_STACK_OF_SCT *, int) = NULL; -int (*sk_SCT_push)(Cryptography_STACK_OF_SCT *, SCT *) = NULL; - -void (*SCT_LIST_free)(Cryptography_STACK_OF_SCT *) = 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 --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py index 55b2117cd53b..ba01169f1e10 100644 --- a/src/cryptography/hazmat/bindings/openssl/_conditional.py +++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py @@ -76,28 +76,6 @@ def cryptography_has_mem_functions(): ] -def cryptography_has_sct(): - return [ - "SCT_get_version", - "SCT_get_log_entry_type", - "SCT_get0_log_id", - "SCT_get0_signature", - "SCT_get_timestamp", - "SCT_set_source", - "sk_SCT_new_null", - "sk_SCT_free", - "sk_SCT_num", - "sk_SCT_value", - "sk_SCT_push", - "SCT_LIST_free", - "SCT_new", - "SCT_set1_log_id", - "SCT_set_timestamp", - "SCT_set_version", - "SCT_set_log_entry_type", - ] - - def cryptography_has_x509_store_ctx_get_issuer(): return [ "X509_STORE_get_get_issuer", @@ -285,7 +263,6 @@ def cryptography_has_providers(): "Cryptography_HAS_SCRYPT": cryptography_has_scrypt, "Cryptography_HAS_EVP_PKEY_DHX": cryptography_has_evp_pkey_dhx, "Cryptography_HAS_MEM_FUNCTIONS": cryptography_has_mem_functions, - "Cryptography_HAS_SCT": cryptography_has_sct, "Cryptography_HAS_X509_STORE_CTX_GET_ISSUER": ( cryptography_has_x509_store_ctx_get_issuer ), From 52dd0e55e3dc05b5458a2877fe0af938b5cf8ccd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Jun 2021 07:57:13 -0400 Subject: [PATCH 0218/1456] Bump libc from 0.2.96 to 0.2.97 in /src/rust (#6117) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.96 to 0.2.97. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.96...0.2.97) --- updated-dependencies: - dependency-name: libc dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index a017dae9f325..f100b8c39cdc 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -151,9 +151,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.96" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5600b4e6efc5421841a2138a6b082e07fe12f9aaa12783d50e5d13325b26b4fc" +checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" [[package]] name = "lock_api" From a6499679eb898f6b36804b325ea0a055904ddcd9 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 14 Jun 2021 22:36:55 -0500 Subject: [PATCH 0219/1456] add certificate policies test vector (#6118) --- docs/development/test-vectors.rst | 7 ++++++- tests/x509/test_x509_ext.py | 10 ++++++++++ .../x509/custom/cp_invalid2.der | Bin 0 -> 761 bytes 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 vectors/cryptography_vectors/x509/custom/cp_invalid2.der diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 0aed4313b0e9..db897f79fbac 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -397,7 +397,12 @@ Custom X.509 Vectors certificate containing a certificate policies extension with a user notice with no explicit text. * ``cp_invalid.pem`` - An RSA 2048 bit self-signed certificate containing a - certificate policies extension with invalid data. + certificate policies extension with invalid data. The ``policyQualifierId`` + is for ``id-qt-unotice`` but the value is an ``id-qt-cps`` ASN.1 structure. +* ``cp_invalid2.der`` - An RSA 2048 bit self-signed certificate containing a + certificate policies extension with invalid data. The ``policyQualifierId`` + is for ``id-qt-cps`` but the value is an ``id-qt-unotice`` ASN.1 structure. + The signature on this certificate is invalid. * ``ian_uri.pem`` - An RSA 2048 bit certificate containing an issuer alternative name extension with a ``URI`` general name. * ``ocsp_nocheck.pem`` - An RSA 2048 bit self-signed certificate containing diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index a69f40d4e43d..bc3688bd0d8f 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -5594,6 +5594,7 @@ def test_invalid_length(self, backend): class TestInvalidExtension(object): def test_invalid_certificate_policies_data(self, backend): + # UserNotice OID but CPSURI structure cert = _load_cert( os.path.join("x509", "custom", "cp_invalid.pem"), x509.load_pem_x509_certificate, @@ -5602,6 +5603,15 @@ def test_invalid_certificate_policies_data(self, backend): with pytest.raises(ValueError): cert.extensions + # CPSURI OID but UserNotice structure + cert = _load_cert( + os.path.join("x509", "custom", "cp_invalid2.der"), + x509.load_der_x509_certificate, + backend, + ) + with pytest.raises(ValueError): + cert.extensions + class TestOCSPNonce(object): def test_non_bytes(self): diff --git a/vectors/cryptography_vectors/x509/custom/cp_invalid2.der b/vectors/cryptography_vectors/x509/custom/cp_invalid2.der new file mode 100644 index 0000000000000000000000000000000000000000..08d31db26b4f732dc10815554a6900a6bbe07eef GIT binary patch literal 761 zcmXqLV)|;(#CUfBGZP~dlQ3Jh?Yx)qZkfg+DVn-7+Fn>5TW-M1#;Mij(e|B}k&%^^ z!9d7Rz<`g9Ih2K&hdrRu*-^pS(Lhd|*U;3!)X)e>8W|Zy0l8*Ct|63*RZkP660*^Z ztPIRejQk8h$8a$M;e!&>>Z5!bJrKeBe8{MUCYYIKu=FP^ad zsk70=+sA0)U(s8+&Ozyad)fB7uYJrqr%pe`KR%>5 z@3LY)-4bNraJFYFb2CqM`X{ejFK$arc(7wj9^1i3>wFi!7Ckakb>pf>&GCG^b5|O$ zt*V)@BH*^jrO2A7oLe~`0ve6Gnckn^YIt09FYHE1VebEgkjDxCa&+yJO3fojr6VX5D`9&^7AEk=oajp0%}yD4O>)y8eB$;_v|lkywjGck+u? zURU|L?~c>13H_&^XC~gY+&Z_YelPpETVlQ2GUrdb^j1?y>8kQ0T_ctWbI(^^P?)r? zqFH$2Bj+E-=2Tx}779AQA*!hJ{I$lVPOf*;19CWC9M66}tA;yqc`<{2M! Date: Wed, 16 Jun 2021 07:38:09 -0400 Subject: [PATCH 0220/1456] Bump asn1 from 0.5.1 to 0.5.2 in /src/rust (#6121) Bumps [asn1](https://github.com/alex/rust-asn1) from 0.5.1 to 0.5.2. - [Release notes](https://github.com/alex/rust-asn1/releases) - [Commits](https://github.com/alex/rust-asn1/compare/0.5.1...0.5.2) --- updated-dependencies: - dependency-name: asn1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 8 ++++---- src/rust/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index f100b8c39cdc..f8c78afcc547 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -10,9 +10,9 @@ checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" [[package]] name = "asn1" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e2ec2f073674e49321449dbfd51accb77effab6ade9f311f0f631903d20c39" +checksum = "f8ed4a28082a1239ef1f2de61139d9421958e92e044190f052021c4b952ee75a" dependencies = [ "asn1_derive", "chrono", @@ -20,9 +20,9 @@ dependencies = [ [[package]] name = "asn1_derive" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18175ce37dddb6ef19f30996c31f63b38571fea8351f321088181cd089efd203" +checksum = "40b1bb20092bbe014fe3b06d23d86c4d42a422cb42632101231b19092b402536" dependencies = [ "proc-macro2", "quote", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index dd535181f95c..b5729a38b6b2 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] lazy_static = "1" pyo3 = { version = "0.13.1" } -asn1 = { version = "0.5.1", default-features = false, features = ["derive"] } +asn1 = { version = "0.5.2", default-features = false, features = ["derive"] } chrono = { version = "0.4", default-features = false, features = ["alloc"] } ouroboros = "0.9" From 45e9599848a9fa1000f314319607e15a4820bc95 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 16 Jun 2021 09:12:25 -0500 Subject: [PATCH 0221/1456] oxidize certificate policies (#6119) --- .../hazmat/backends/openssl/backend.py | 3 - .../hazmat/backends/openssl/decode_asn1.py | 101 +------------ src/rust/src/x509.rs | 136 ++++++++++++++++++ tests/hazmat/backends/test_openssl.py | 11 ++ 4 files changed, 151 insertions(+), 100 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index bfc9dd07a7a3..ab9f2ce80f8b 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -18,7 +18,6 @@ from cryptography.hazmat.backends.openssl.cmac import _CMACContext from cryptography.hazmat.backends.openssl.decode_asn1 import ( _CRL_ENTRY_REASON_ENUM_TO_CODE, - _EXTENSION_HANDLERS_BASE, _X509ExtensionParser, ) from cryptography.hazmat.backends.openssl.dh import ( @@ -389,14 +388,12 @@ def _register_x509_ext_parsers(self): ext_count=self._lib.X509_get_ext_count, get_ext=self._lib.X509_get_ext, rust_callback=rust_x509.parse_x509_extension, - handlers=_EXTENSION_HANDLERS_BASE, ) self._csr_extension_parser = _X509ExtensionParser( self, ext_count=self._lib.sk_X509_EXTENSION_num, get_ext=self._lib.sk_X509_EXTENSION_value, rust_callback=rust_x509.parse_x509_extension, - handlers=_EXTENSION_HANDLERS_BASE, ) self._revoked_cert_extension_parser = _X509ExtensionParser( self, diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 843e0e3ca1ec..228d3e008392 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -8,10 +8,6 @@ from cryptography import x509 from cryptography.x509.name import _ASN1_TYPE_TO_ENUM -from cryptography.x509.oid import ( - CertificatePoliciesOID, - ExtensionOID, -) def _obj2txt(backend, obj): @@ -69,12 +65,9 @@ def _decode_x509_name(backend, x509_name): class _X509ExtensionParser(object): - def __init__( - self, backend, ext_count, get_ext, rust_callback, handlers={} - ): + def __init__(self, backend, ext_count, get_ext, rust_callback): self.ext_count = ext_count self.get_ext = get_ext - self.handlers = handlers self.rust_callback = rust_callback self._backend = backend @@ -106,96 +99,15 @@ def parse(self, x509_obj): data = self._backend._lib.X509_EXTENSION_get_data(ext) data_bytes = _asn1_string_to_bytes(self._backend, data) ext_obj = self.rust_callback(oid_der_bytes, data_bytes) - if ext_obj is not None: - extensions.append(x509.Extension(oid, critical, ext_obj)) - seen_oids.add(oid) - continue - - # Fallback to our older parsing because the rust code doesn't - # know how to parse this. - try: - handler = self.handlers[oid] - except KeyError: - # Dump the DER payload into an UnrecognizedExtension object - data = self._backend._lib.X509_EXTENSION_get_data(ext) - self._backend.openssl_assert(data != self._backend._ffi.NULL) - der = self._backend._ffi.buffer(data.data, data.length)[:] - unrecognized = x509.UnrecognizedExtension(oid, der) - extensions.append(x509.Extension(oid, critical, unrecognized)) - else: - ext_data = self._backend._lib.X509V3_EXT_d2i(ext) - if ext_data == self._backend._ffi.NULL: - self._backend._consume_errors() - raise ValueError( - "The {} extension is invalid and can't be " - "parsed".format(oid) - ) - - value = handler(self._backend, ext_data) - extensions.append(x509.Extension(oid, critical, value)) + if ext_obj is None: + ext_obj = x509.UnrecognizedExtension(oid, data_bytes) + extensions.append(x509.Extension(oid, critical, ext_obj)) seen_oids.add(oid) return x509.Extensions(extensions) -def _decode_certificate_policies(backend, cp): - cp = backend._ffi.cast("Cryptography_STACK_OF_POLICYINFO *", cp) - cp = backend._ffi.gc(cp, backend._lib.CERTIFICATEPOLICIES_free) - - num = backend._lib.sk_POLICYINFO_num(cp) - certificate_policies = [] - for i in range(num): - qualifiers = None - pi = backend._lib.sk_POLICYINFO_value(cp, i) - oid = x509.ObjectIdentifier(_obj2txt(backend, pi.policyid)) - if pi.qualifiers != backend._ffi.NULL: - qnum = backend._lib.sk_POLICYQUALINFO_num(pi.qualifiers) - qualifiers = [] - for j in range(qnum): - pqi = backend._lib.sk_POLICYQUALINFO_value(pi.qualifiers, j) - pqualid = x509.ObjectIdentifier(_obj2txt(backend, pqi.pqualid)) - if pqualid == CertificatePoliciesOID.CPS_QUALIFIER: - cpsuri = backend._ffi.buffer( - pqi.d.cpsuri.data, pqi.d.cpsuri.length - )[:].decode("ascii") - qualifiers.append(cpsuri) - else: - assert pqualid == CertificatePoliciesOID.CPS_USER_NOTICE - user_notice = _decode_user_notice( - backend, pqi.d.usernotice - ) - qualifiers.append(user_notice) - - certificate_policies.append(x509.PolicyInformation(oid, qualifiers)) - - return x509.CertificatePolicies(certificate_policies) - - -def _decode_user_notice(backend, un): - explicit_text = None - notice_reference = None - - if un.exptext != backend._ffi.NULL: - explicit_text = _asn1_string_to_utf8(backend, un.exptext) - - if un.noticeref != backend._ffi.NULL: - organization = _asn1_string_to_utf8(backend, un.noticeref.organization) - - num = backend._lib.sk_ASN1_INTEGER_num(un.noticeref.noticenos) - notice_numbers = [] - for i in range(num): - asn1_int = backend._lib.sk_ASN1_INTEGER_value( - un.noticeref.noticenos, i - ) - notice_num = _asn1_integer_to_int(backend, asn1_int) - notice_numbers.append(notice_num) - - notice_reference = x509.NoticeReference(organization, notice_numbers) - - return x509.UserNotice(notice_reference, explicit_text) - - _DISTPOINT_TYPE_FULLNAME = 0 _DISTPOINT_TYPE_RELATIVENAME = 1 @@ -292,8 +204,3 @@ def _parse_asn1_generalized_time(backend, generalized_time): backend, backend._ffi.cast("ASN1_STRING *", generalized_time) ) return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ") - - -_EXTENSION_HANDLERS_BASE = { - ExtensionOID.CERTIFICATE_POLICIES: _decode_certificate_policies, -} diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index 161562cabab1..45518aebbd5b 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -29,6 +29,7 @@ lazy_static::lazy_static! { static ref CERTIFICATE_ISSUER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.29").unwrap(); static ref NAME_CONSTRAINTS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.30").unwrap(); static ref CRL_DISTRIBUTION_POINTS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.31").unwrap(); + static ref CERTIFICATE_POLICIES_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.32").unwrap(); static ref FRESHEST_CRL_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.46").unwrap(); static ref CRL_NUMBER_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.20").unwrap(); static ref INVALIDITY_DATE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.24").unwrap(); @@ -36,6 +37,136 @@ lazy_static::lazy_static! { static ref SUBJECT_ALTERNATIVE_NAME_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.17").unwrap(); static ref ISSUER_ALTERNATIVE_NAME_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("2.5.29.18").unwrap(); static ref PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.4.1.11129.2.4.2").unwrap(); + + static ref CP_CPS_URI_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.2.1").unwrap(); + static ref CP_USER_NOTICE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.2.2").unwrap(); +} + +#[derive(asn1::Asn1Read)] +struct PolicyInformation<'a> { + policy_identifier: asn1::ObjectIdentifier<'a>, + policy_qualifiers: Option>>, +} + +#[derive(asn1::Asn1Read)] +struct PolicyQualifierInfo<'a> { + policy_qualifier_id: asn1::ObjectIdentifier<'a>, + qualifier: Qualifier<'a>, +} + +#[derive(asn1::Asn1Read)] +enum Qualifier<'a> { + CpsUri(asn1::IA5String<'a>), + UserNotice(UserNotice<'a>), +} + +#[derive(asn1::Asn1Read)] +struct UserNotice<'a> { + notice_ref: Option>, + explicit_text: Option>, +} + +#[derive(asn1::Asn1Read)] +struct NoticeReference<'a> { + organization: DisplayText<'a>, + notice_numbers: asn1::SequenceOf<'a, asn1::BigUint<'a>>, +} + +// DisplayText also allows BMPString, which we currently do not support. +#[allow(clippy::enum_variant_names)] +#[derive(asn1::Asn1Read)] +enum DisplayText<'a> { + IA5String(asn1::IA5String<'a>), + Utf8String(asn1::Utf8String<'a>), + VisibleString(asn1::VisibleString<'a>), +} + +fn parse_display_text(py: pyo3::Python<'_>, text: DisplayText<'_>) -> pyo3::PyObject { + match text { + DisplayText::IA5String(o) => pyo3::types::PyString::new(py, o.as_str()).to_object(py), + DisplayText::Utf8String(o) => pyo3::types::PyString::new(py, o.as_str()).to_object(py), + DisplayText::VisibleString(o) => pyo3::types::PyString::new(py, o.as_str()).to_object(py), + } +} + +fn parse_user_notice( + py: pyo3::Python<'_>, + un: UserNotice<'_>, +) -> Result { + let x509_module = py.import("cryptography.x509")?; + let et = match un.explicit_text { + Some(data) => parse_display_text(py, data), + None => py.None(), + }; + let nr = match un.notice_ref { + Some(data) => { + let org = parse_display_text(py, data.organization); + let numbers = pyo3::types::PyList::empty(py); + for num in data.notice_numbers { + numbers.append(big_asn1_uint_to_py(py, num)?.to_object(py))?; + } + x509_module + .call_method1("NoticeReference", (org, numbers))? + .to_object(py) + } + None => py.None(), + }; + Ok(x509_module + .call_method1("UserNotice", (nr, et))? + .to_object(py)) +} + +fn parse_policy_qualifiers<'a>( + py: pyo3::Python<'_>, + policy_qualifiers: asn1::SequenceOf<'a, PolicyQualifierInfo<'a>>, +) -> Result { + let py_pq = pyo3::types::PyList::empty(py); + for pqi in policy_qualifiers { + let qualifier = match pqi.qualifier { + Qualifier::CpsUri(data) => { + if pqi.policy_qualifier_id == *CP_CPS_URI_OID { + pyo3::types::PyString::new(py, data.as_str()).to_object(py) + } else { + return Err(PyAsn1Error::from(pyo3::exceptions::PyValueError::new_err( + "CpsUri ASN.1 structure found but OID did not match", + ))); + } + } + Qualifier::UserNotice(un) => { + if pqi.policy_qualifier_id != *CP_USER_NOTICE_OID { + return Err(PyAsn1Error::from(pyo3::exceptions::PyValueError::new_err( + "UserNotice ASN.1 structure found but OID did not match", + ))); + } + parse_user_notice(py, un)? + } + }; + py_pq.append(qualifier)?; + } + Ok(py_pq.to_object(py)) +} + +fn parse_cp(py: pyo3::Python<'_>, ext_data: &[u8]) -> Result { + let cp = asn1::parse_single::>>(ext_data)?; + let x509_module = py.import("cryptography.x509")?; + let certificate_policies = pyo3::types::PyList::empty(py); + for policyinfo in cp { + let pi_oid = x509_module + .call_method1( + "ObjectIdentifier", + (policyinfo.policy_identifier.to_string(),), + )? + .to_object(py); + let py_pqis = match policyinfo.policy_qualifiers { + Some(policy_qualifiers) => parse_policy_qualifiers(py, policy_qualifiers)?, + None => py.None(), + }; + let pi = x509_module + .call_method1("PolicyInformation", (pi_oid, py_pqis))? + .to_object(py); + certificate_policies.append(pi)?; + } + Ok(certificate_policies.to_object(py)) } struct UnvalidatedIA5String<'a>(&'a str); @@ -722,6 +853,11 @@ fn parse_x509_extension( Ok(x509_module .call1("SubjectInformationAccess", (ads,))? .to_object(py)) + } else if oid == *CERTIFICATE_POLICIES_OID { + let cp = parse_cp(py, ext_data)?; + Ok(x509_module + .call_method1("CertificatePolicies", (cp,))? + .to_object(py)) } else if oid == *POLICY_CONSTRAINTS_OID { let pc = asn1::parse_single::(ext_data)?; Ok(x509_module diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index a559998f1699..a59aa09f31bd 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -13,6 +13,7 @@ from cryptography import x509 from cryptography.exceptions import InternalError, _Reasons +from cryptography.hazmat.backends.openssl import decode_asn1, encode_asn1 from cryptography.hazmat.backends.openssl.backend import Backend, backend from cryptography.hazmat.backends.openssl.ec import _sn_to_elliptic_curve from cryptography.hazmat.primitives import hashes, serialization @@ -164,6 +165,16 @@ def test_bn_to_int(self): bn = backend._int_to_bn(0) assert backend._bn_to_int(bn) == 0 + def test_obj2txt_buffer_sizing(self): + # This test exercises a branch for larger than default buffer sizing + # in _obj2txt + oid_str = ( + "1.2.3.182382138123818.1293813123.12381238123.3434834834888" + ".383488234284.2348234.234819299576434.23482434203" + ) + obj = encode_asn1._txt2obj_gc(backend, oid_str) + assert decode_asn1._obj2txt(backend, obj) == oid_str + @pytest.mark.skipif( not backend._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE, From 6e8106f73d639d3a95c96ab041e96418121bf5bc Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Thu, 17 Jun 2021 12:54:05 +0100 Subject: [PATCH 0222/1456] type annotate cryptography.utils:register_interface (#6123) --- src/cryptography/utils.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index f07d5fdad249..8611d95c8e74 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -41,8 +41,22 @@ def read_only_property(name: str): return property(lambda self: getattr(self, name)) -def register_interface(iface): - def register_decorator(klass, *, check_annotations=False): +if typing.TYPE_CHECKING: + from typing_extensions import Protocol + + _T_class = typing.TypeVar("_T_class", bound=type) + + class _RegisterDecoratorType(Protocol): + def __call__( + self, klass: _T_class, *, check_annotations: bool = False + ) -> _T_class: + ... + + +def register_interface(iface: abc.ABCMeta) -> "_RegisterDecoratorType": + def register_decorator( + klass: "_T_class", *, check_annotations: bool = False + ) -> "_T_class": verify_interface(iface, klass, check_annotations=check_annotations) iface.register(klass) return klass From 1e3eab5d178ce94e903f9131d011efe68e1da97b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 17 Jun 2021 08:29:28 -0400 Subject: [PATCH 0223/1456] Bump redox_syscall from 0.2.8 to 0.2.9 in /src/rust (#6126) Bumps redox_syscall from 0.2.8 to 0.2.9. --- updated-dependencies: - dependency-name: redox_syscall dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index f8c78afcc547..1bcce8a65d6c 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -339,9 +339,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" +checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" dependencies = [ "bitflags", ] From 60eeb4eb7a981fd9d8b18b06391592f06a0a1a41 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 17 Jun 2021 10:23:24 -0500 Subject: [PATCH 0224/1456] bump CI to 3.0.0-beta1 (#6127) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d1d1d1e42a1e..cedaa32e44a5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k"}} - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0-alpha17"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0-beta1"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "2.9.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.1.5"}} From b2db8579f3a71ca1c57b652f4e7f98bcba872780 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 18 Jun 2021 15:05:23 -0400 Subject: [PATCH 0225/1456] Move some X.509 types from the OCSP module (#6128) --- src/rust/src/ocsp.rs | 77 +++----------------------------------------- src/rust/src/x509.rs | 68 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 72 deletions(-) diff --git a/src/rust/src/ocsp.rs b/src/rust/src/ocsp.rs index fbac6c389213..8bba14b11673 100644 --- a/src/rust/src/ocsp.rs +++ b/src/rust/src/ocsp.rs @@ -6,7 +6,7 @@ use crate::asn1::{big_asn1_uint_to_py, PyAsn1Error}; use crate::x509; use pyo3::conversion::ToPyObject; use pyo3::exceptions; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; lazy_static::lazy_static! { static ref SHA1_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.14.3.2.26").unwrap(); @@ -76,57 +76,6 @@ impl OCSPRequest { } } -fn parse_and_cache_extensions< - 'p, - F: Fn(&asn1::ObjectIdentifier<'_>, &[u8]) -> Result, PyAsn1Error>, ->( - py: pyo3::Python<'p>, - cached_extensions: &mut Option, - raw_exts: &Option>, - parse_ext: F, -) -> Result { - if let Some(cached) = cached_extensions { - return Ok(cached.clone_ref(py)); - } - - let x509_module = py.import("cryptography.x509")?; - let exts = pyo3::types::PyList::empty(py); - let mut seen_oids = HashSet::new(); - if let Some(raw_exts) = raw_exts { - for raw_ext in raw_exts.clone() { - let oid_obj = - x509_module.call_method1("ObjectIdentifier", (raw_ext.extn_id.to_string(),))?; - - if seen_oids.contains(&raw_ext.extn_id) { - return Err(PyAsn1Error::from(pyo3::PyErr::from_instance( - x509_module.call_method1( - "DuplicateExtension", - ( - format!("Duplicate {} extension found", raw_ext.extn_id), - oid_obj, - ), - )?, - ))); - } - - let extn_value = match parse_ext(&raw_ext.extn_id, raw_ext.extn_value)? { - Some(e) => e, - None => x509_module - .call_method1("UnrecognizedExtension", (oid_obj, raw_ext.extn_value))?, - }; - let ext_obj = - x509_module.call_method1("Extension", (oid_obj, raw_ext.critical, extn_value))?; - exts.append(ext_obj)?; - seen_oids.insert(raw_ext.extn_id); - } - } - let extensions = x509_module - .call_method1("Extensions", (exts,))? - .to_object(py); - *cached_extensions = Some(extensions.clone_ref(py)); - Ok(extensions) -} - #[pyo3::prelude::pymethods] impl OCSPRequest { #[getter] @@ -169,7 +118,7 @@ impl OCSPRequest { #[getter] fn extensions(&mut self, py: pyo3::Python<'_>) -> Result { let x509_module = py.import("cryptography.x509")?; - parse_and_cache_extensions( + x509::parse_and_cache_extensions( py, &mut self.cached_extensions, &self.raw.borrow_value().tbs_request.request_extensions, @@ -229,40 +178,24 @@ struct TBSRequest<'a> { // _requestor_name: Option>, request_list: asn1::SequenceOf<'a, Request<'a>>, #[explicit(2)] - request_extensions: Option>, + request_extensions: Option>, } #[derive(asn1::Asn1Read, asn1::Asn1Write)] struct Request<'a> { req_cert: CertID<'a>, #[explicit(0)] - _single_request_extensions: Option>, + _single_request_extensions: Option>, } #[derive(asn1::Asn1Read, asn1::Asn1Write)] struct CertID<'a> { - hash_algorithm: AlgorithmIdentifier<'a>, + hash_algorithm: x509::AlgorithmIdentifier<'a>, issuer_name_hash: &'a [u8], issuer_key_hash: &'a [u8], serial_number: asn1::BigUint<'a>, } -type Extensions<'a> = asn1::SequenceOf<'a, Extension<'a>>; - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -struct AlgorithmIdentifier<'a> { - oid: asn1::ObjectIdentifier<'a>, - _params: Option>, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -struct Extension<'a> { - extn_id: asn1::ObjectIdentifier<'a>, - #[default(false)] - critical: bool, - extn_value: &'a [u8], -} - #[pyo3::prelude::pyfunction] fn parse_ocsp_resp_extension( py: pyo3::Python<'_>, diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index 45518aebbd5b..36bc590d7863 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -7,6 +7,7 @@ use chrono::{Datelike, Timelike}; use pyo3::conversion::ToPyObject; use pyo3::types::IntoPyDict; use std::collections::hash_map::DefaultHasher; +use std::collections::HashSet; use std::convert::TryInto; use std::hash::{Hash, Hasher}; @@ -42,6 +43,73 @@ lazy_static::lazy_static! { static ref CP_USER_NOTICE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.2.2").unwrap(); } +pub(crate) fn parse_and_cache_extensions< + 'p, + F: Fn(&asn1::ObjectIdentifier<'_>, &[u8]) -> Result, PyAsn1Error>, +>( + py: pyo3::Python<'p>, + cached_extensions: &mut Option, + raw_exts: &Option>, + parse_ext: F, +) -> Result { + if let Some(cached) = cached_extensions { + return Ok(cached.clone_ref(py)); + } + + let x509_module = py.import("cryptography.x509")?; + let exts = pyo3::types::PyList::empty(py); + let mut seen_oids = HashSet::new(); + if let Some(raw_exts) = raw_exts { + for raw_ext in raw_exts.clone() { + let oid_obj = + x509_module.call_method1("ObjectIdentifier", (raw_ext.extn_id.to_string(),))?; + + if seen_oids.contains(&raw_ext.extn_id) { + return Err(PyAsn1Error::from(pyo3::PyErr::from_instance( + x509_module.call_method1( + "DuplicateExtension", + ( + format!("Duplicate {} extension found", raw_ext.extn_id), + oid_obj, + ), + )?, + ))); + } + + let extn_value = match parse_ext(&raw_ext.extn_id, raw_ext.extn_value)? { + Some(e) => e, + None => x509_module + .call_method1("UnrecognizedExtension", (oid_obj, raw_ext.extn_value))?, + }; + let ext_obj = + x509_module.call_method1("Extension", (oid_obj, raw_ext.critical, extn_value))?; + exts.append(ext_obj)?; + seen_oids.insert(raw_ext.extn_id); + } + } + let extensions = x509_module + .call_method1("Extensions", (exts,))? + .to_object(py); + *cached_extensions = Some(extensions.clone_ref(py)); + Ok(extensions) +} + +pub(crate) type Extensions<'a> = asn1::SequenceOf<'a, Extension<'a>>; + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub(crate) struct AlgorithmIdentifier<'a> { + pub(crate) oid: asn1::ObjectIdentifier<'a>, + pub(crate) _params: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub(crate) struct Extension<'a> { + pub(crate) extn_id: asn1::ObjectIdentifier<'a>, + #[default(false)] + pub(crate) critical: bool, + pub(crate) extn_value: &'a [u8], +} + #[derive(asn1::Asn1Read)] struct PolicyInformation<'a> { policy_identifier: asn1::ObjectIdentifier<'a>, From a4aa852a17f8f097c46d16a58fc66ebfcf5e121e Mon Sep 17 00:00:00 2001 From: Tanvi Moharir <74228962+tanvimoharir@users.noreply.github.com> Date: Sat, 19 Jun 2021 23:09:00 +0530 Subject: [PATCH 0226/1456] Adding mypy configuration to pyproject (#6116) * Adding mypy configuration to pytproject * Correcting specifications for pyproject.toml --- mypy.ini | 11 ----------- pyproject.toml | 13 +++++++++++++ 2 files changed, 13 insertions(+), 11 deletions(-) delete mode 100644 mypy.ini diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 055619c090f6..000000000000 --- a/mypy.ini +++ /dev/null @@ -1,11 +0,0 @@ -[mypy] -show_error_codes = True -check_untyped_defs = True - -[mypy-cryptography.hazmat.bindings._openssl] -ignore_missing_imports = True - -[mypy-iso8601] -ignore_missing_imports = True -[mypy-pretend] -ignore_missing_imports = True diff --git a/pyproject.toml b/pyproject.toml index b2bf92caf086..0b692437096a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,3 +20,16 @@ markers = [ "skip_fips: this test is not executed in FIPS mode", "supported: parametrized test requiring only_if and skip_message", ] + +[tool.mypy] +show_error_codes = true +check_untyped_defs = true + +[[tool.mypy.overrides]] +module = [ + "cryptography.hazmat.bindings._openssl", + "iso8601", + "pretend" +] +ignore_missing_imports = true + From ce80be2d26b76563cd2e495ab13f09f9ce0da4dd Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 19 Jun 2021 15:10:50 -0400 Subject: [PATCH 0227/1456] Add another linkcheck ignore (#6129) --- docs/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index 0db9dd8b842d..f3b84c4111d6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -198,6 +198,8 @@ r"https://info.isl.ntt.co.jp/crypt/eng/camellia/", # Inconsistent small DH params they seem incapable of fixing r"https://www.secg.org/sec1-v2.pdf", + # Incomplete cert chain + r"https://e-trust.gosuslugi.ru", ] autosectionlabel_prefix_document = True From 5ad2488a72c1c2e32b1ab942995cddae4e675aed Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 19 Jun 2021 19:00:16 -0400 Subject: [PATCH 0228/1456] Make whitespcae in pyproject.toml normal (#6130) --- pyproject.toml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0b692437096a..913a4e46d1c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,9 +27,8 @@ check_untyped_defs = true [[tool.mypy.overrides]] module = [ - "cryptography.hazmat.bindings._openssl", - "iso8601", - "pretend" + "cryptography.hazmat.bindings._openssl", + "iso8601", + "pretend" ] ignore_missing_imports = true - From 06e279228295cebea115e3decbf99d27b5315e63 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 20 Jun 2021 11:27:34 -0400 Subject: [PATCH 0229/1456] Bump asn1 from 0.5.2 to 0.5.3 in /src/rust (#6132) Bumps [asn1](https://github.com/alex/rust-asn1) from 0.5.2 to 0.5.3. - [Release notes](https://github.com/alex/rust-asn1/releases) - [Commits](https://github.com/alex/rust-asn1/compare/0.5.2...0.5.3) --- updated-dependencies: - dependency-name: asn1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 8 ++++---- src/rust/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 1bcce8a65d6c..499f57427da9 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -10,9 +10,9 @@ checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" [[package]] name = "asn1" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed4a28082a1239ef1f2de61139d9421958e92e044190f052021c4b952ee75a" +checksum = "5f56417796de18d5398ee1ba4058d061a9be1bcfdef9a46f73e96e94f5bb21e0" dependencies = [ "asn1_derive", "chrono", @@ -20,9 +20,9 @@ dependencies = [ [[package]] name = "asn1_derive" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b1bb20092bbe014fe3b06d23d86c4d42a422cb42632101231b19092b402536" +checksum = "be3a3360bd6e363428f7ce00ccd251efcd2639b6942ab22e5f322a452aa6f079" dependencies = [ "proc-macro2", "quote", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index b5729a38b6b2..6ea95be09f67 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] lazy_static = "1" pyo3 = { version = "0.13.1" } -asn1 = { version = "0.5.2", default-features = false, features = ["derive"] } +asn1 = { version = "0.5.3", default-features = false, features = ["derive"] } chrono = { version = "0.4", default-features = false, features = ["alloc"] } ouroboros = "0.9" From 5db5158f3829cd37e12b82c9ca9a4d74cca69a42 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 26 Jun 2021 05:46:35 -0400 Subject: [PATCH 0230/1456] moar linkcheck ignores (#6137) * moar linkcheck ignores * new alpine new python --- .github/workflows/ci.yml | 2 +- docs/conf.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cedaa32e44a5..f52a9faab5f0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -120,7 +120,7 @@ jobs: - {IMAGE: "ubuntu-rolling", TOXENV: "py39"} - {IMAGE: "ubuntu-rolling", TOXENV: "py39-randomorder"} - {IMAGE: "fedora", TOXENV: "py39"} - - {IMAGE: "alpine", TOXENV: "py38"} + - {IMAGE: "alpine", TOXENV: "py39"} name: "${{ matrix.IMAGE.TOXENV }} on ${{ matrix.IMAGE.IMAGE }}" timeout-minutes: 20 steps: diff --git a/docs/conf.py b/docs/conf.py index f3b84c4111d6..f79db277abfa 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -200,6 +200,8 @@ r"https://www.secg.org/sec1-v2.pdf", # Incomplete cert chain r"https://e-trust.gosuslugi.ru", + # Expired cert (1 week at time of writing) + r"https://www.cosic.esat.kuleuven.be", ] autosectionlabel_prefix_document = True From 1dfb72a6c29b42dcfb38f0b7ef960a189200ede0 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 26 Jun 2021 13:46:31 -0400 Subject: [PATCH 0231/1456] This is a property (#6139) --- tests/x509/test_x509.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 306fbe246219..f9f0d2fe6091 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -116,7 +116,7 @@ def test_unknown_signature_algorithm(self, backend): ) with pytest.raises(UnsupportedAlgorithm): - crl.signature_hash_algorithm() + crl.signature_hash_algorithm def test_issuer(self, backend): crl = _load_cert( From a6c8b2d9d916bf04d5f873690e9b46062a0df24e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 26 Jun 2021 15:06:41 -0400 Subject: [PATCH 0232/1456] Various cleanups and refactorings from my CRL work (#6140) --- src/rust/src/ocsp.rs | 2 +- src/rust/src/x509.rs | 79 ++++++++++++++++++++++---------------------- 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/rust/src/ocsp.rs b/src/rust/src/ocsp.rs index 8bba14b11673..0ef58c34f648 100644 --- a/src/rust/src/ocsp.rs +++ b/src/rust/src/ocsp.rs @@ -116,7 +116,7 @@ impl OCSPRequest { } #[getter] - fn extensions(&mut self, py: pyo3::Python<'_>) -> Result { + fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult { let x509_module = py.import("cryptography.x509")?; x509::parse_and_cache_extensions( py, diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index 36bc590d7863..f9bb51861b79 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -51,7 +51,7 @@ pub(crate) fn parse_and_cache_extensions< cached_extensions: &mut Option, raw_exts: &Option>, parse_ext: F, -) -> Result { +) -> pyo3::PyResult { if let Some(cached) = cached_extensions { return Ok(cached.clone_ref(py)); } @@ -65,15 +65,13 @@ pub(crate) fn parse_and_cache_extensions< x509_module.call_method1("ObjectIdentifier", (raw_ext.extn_id.to_string(),))?; if seen_oids.contains(&raw_ext.extn_id) { - return Err(PyAsn1Error::from(pyo3::PyErr::from_instance( - x509_module.call_method1( - "DuplicateExtension", - ( - format!("Duplicate {} extension found", raw_ext.extn_id), - oid_obj, - ), - )?, - ))); + return Err(pyo3::PyErr::from_instance(x509_module.call_method1( + "DuplicateExtension", + ( + format!("Duplicate {} extension found", raw_ext.extn_id), + oid_obj, + ), + )?)); } let extn_value = match parse_ext(&raw_ext.extn_id, raw_ext.extn_value)? { @@ -237,6 +235,24 @@ fn parse_cp(py: pyo3::Python<'_>, ext_data: &[u8]) -> Result( + py: pyo3::Python<'p>, + dt: &chrono::DateTime, +) -> pyo3::PyResult<&'p pyo3::PyAny> { + let datetime_module = py.import("datetime")?; + datetime_module.call1( + "datetime", + ( + dt.year(), + dt.month(), + dt.day(), + dt.hour(), + dt.minute(), + dt.second(), + ), + ) +} + struct UnvalidatedIA5String<'a>(&'a str); impl<'a> asn1::SimpleAsn1Readable<'a> for UnvalidatedIA5String<'a> { @@ -456,10 +472,10 @@ struct AccessDescription<'a> { access_location: GeneralName<'a>, } -fn parse_authority_key_identifier( - py: pyo3::Python<'_>, +fn parse_authority_key_identifier<'p>( + py: pyo3::Python<'p>, ext_data: &[u8], -) -> Result { +) -> Result<&'p pyo3::PyAny, PyAsn1Error> { let x509_module = py.import("cryptography.x509")?; let aki = asn1::parse_single::>(ext_data)?; let serial = match aki.authority_cert_serial_number { @@ -470,12 +486,10 @@ fn parse_authority_key_identifier( Some(aci) => parse_general_names(py, aci)?, None => py.None(), }; - Ok(x509_module - .call1( - "AuthorityKeyIdentifier", - (aki.key_identifier, issuer, serial), - )? - .to_object(py)) + Ok(x509_module.call1( + "AuthorityKeyIdentifier", + (aki.key_identifier, issuer, serial), + )?) } fn parse_name_attribute( @@ -512,15 +526,14 @@ fn parse_rdn<'a>( .to_object(py)) } -fn parse_name(py: pyo3::Python<'_>, name: Name<'_>) -> Result { +fn parse_name<'p>(py: pyo3::Python<'p>, name: &Name<'_>) -> pyo3::PyResult<&'p pyo3::PyAny> { let x509_module = py.import("cryptography.x509")?; let py_rdns = pyo3::types::PyList::empty(py); - for rdn in name { + for rdn in name.clone() { let py_rdn = parse_rdn(py, rdn)?; py_rdns.append(py_rdn)?; } - let py_name = x509_module.call_method1("Name", (py_rdns,))?.to_object(py); - Ok(py_name) + x509_module.call_method1("Name", (py_rdns,)) } fn ipv4_netmask(num: u32) -> Result { @@ -599,7 +612,7 @@ fn parse_general_name( .call_method1("_init_without_validation", (data.0,))? .to_object(py), GeneralName::DirectoryName(data) => { - let py_name = parse_name(py, data)?; + let py_name = parse_name(py, &data)?; x509_module .call_method1("DirectoryName", (py_name,))? .to_object(py) @@ -952,7 +965,7 @@ fn parse_x509_extension( .call1("BasicConstraints", (bc.ca, bc.path_length))? .to_object(py)) } else if oid == *AUTHORITY_KEY_IDENTIFIER_OID { - Ok(parse_authority_key_identifier(py, ext_data)?) + Ok(parse_authority_key_identifier(py, ext_data)?.to_object(py)) } else if oid == *CRL_DISTRIBUTION_POINTS_OID { let dp = parse_distribution_points(py, ext_data)?; Ok(x509_module @@ -1023,19 +1036,7 @@ pub(crate) fn parse_crl_entry_extension( .to_object(py)) } else if oid == *INVALIDITY_DATE_OID { let time = asn1::parse_single::(ext_data)?; - let time_chrono = time.as_chrono(); - let datetime_module = py.import("datetime")?; - let py_dt = datetime_module.call1( - "datetime", - ( - time_chrono.year(), - time_chrono.month(), - time_chrono.day(), - time_chrono.hour(), - time_chrono.minute(), - time_chrono.second(), - ), - )?; + let py_dt = chrono_to_py(py, time.as_chrono())?; Ok(x509_module.call1("InvalidityDate", (py_dt,))?.to_object(py)) } else { Ok(py.None()) @@ -1073,7 +1074,7 @@ fn parse_crl_extension( .call1("AuthorityInformationAccess", (ads,))? .to_object(py)) } else if oid == *AUTHORITY_KEY_IDENTIFIER_OID { - Ok(parse_authority_key_identifier(py, ext_data)?) + Ok(parse_authority_key_identifier(py, ext_data)?.to_object(py)) } else if oid == *ISSUING_DISTRIBUTION_POINT_OID { let idp = asn1::parse_single::>(ext_data)?; let (full_name, relative_name) = match idp.distribution_point { From c2efb00be2fcce202ca0eaca2dca294e043e49b1 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 26 Jun 2021 16:19:58 -0400 Subject: [PATCH 0233/1456] Simplify public_bytes (#6141) --- src/rust/src/ocsp.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rust/src/ocsp.rs b/src/rust/src/ocsp.rs index 0ef58c34f648..e6436631950f 100644 --- a/src/rust/src/ocsp.rs +++ b/src/rust/src/ocsp.rs @@ -142,15 +142,15 @@ impl OCSPRequest { &self, py: pyo3::Python<'p>, encoding: &pyo3::PyAny, - ) -> Result<&'p pyo3::types::PyBytes, PyAsn1Error> { + ) -> pyo3::PyResult<&'p pyo3::types::PyBytes> { let der = py .import("cryptography.hazmat.primitives.serialization")? .getattr("Encoding")? .getattr("DER")?; if encoding != der { - return Err(PyAsn1Error::from(exceptions::PyValueError::new_err( + return Err(exceptions::PyValueError::new_err( "The only allowed encoding value is Encoding.DER", - ))); + )); } let result = asn1::write_single(self.raw.borrow_value()); Ok(pyo3::types::PyBytes::new(py, &result)) From 8328cea9b4a9b2d41356e9c0c1179be5d063456c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 26 Jun 2021 16:50:57 -0400 Subject: [PATCH 0234/1456] Bump ouroboros from 0.9.3 to 0.9.5 in /src/rust (#6143) Bumps [ouroboros](https://github.com/joshua-maros/ouroboros) from 0.9.3 to 0.9.5. - [Release notes](https://github.com/joshua-maros/ouroboros/releases) - [Commits](https://github.com/joshua-maros/ouroboros/commits) --- updated-dependencies: - dependency-name: ouroboros dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 499f57427da9..6453ed9c698b 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -185,9 +185,9 @@ dependencies = [ [[package]] name = "ouroboros" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f52300b81ac4eeeb6c00c20f7e86556c427d9fb2d92b68fc73c22f331cd15" +checksum = "fbeff60e3e37407a80ead3e9458145b456e978c4068cddbfea6afb48572962ca" dependencies = [ "ouroboros_macro", "stable_deref_trait", @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "ouroboros_macro" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41db02c8f8731cdd7a72b433c7900cce4bf245465b452c364bfd21f4566ab055" +checksum = "03f2cb802b5bdfdf52f1ffa0b54ce105e4d346e91990dd571f86c91321ad49e2" dependencies = [ "Inflector", "proc-macro-error", From 4161898e59b5acb35cd1c1047c51a7e2d2c75024 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 26 Jun 2021 21:37:37 -0400 Subject: [PATCH 0235/1456] Remove unused gf2m bindings (#6144) * Remove unused gf2m bindings * Update ec.py --- src/_cffi_src/openssl/ec.py | 14 -------------- .../hazmat/bindings/openssl/_conditional.py | 2 -- 2 files changed, 16 deletions(-) diff --git a/src/_cffi_src/openssl/ec.py b/src/_cffi_src/openssl/ec.py index 61d1cb3bb93d..d9c3074cc06e 100644 --- a/src/_cffi_src/openssl/ec.py +++ b/src/_cffi_src/openssl/ec.py @@ -65,18 +65,9 @@ int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *, const EC_POINT *, BIGNUM *, BIGNUM *, BN_CTX *); -int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *, EC_POINT *, - const BIGNUM *, int, BN_CTX *); - -int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *, EC_POINT *, - const BIGNUM *, const BIGNUM *, BN_CTX *); - int EC_POINT_get_affine_coordinates_GF2m(const EC_GROUP *, const EC_POINT *, BIGNUM *, BIGNUM *, BN_CTX *); -int EC_POINT_set_compressed_coordinates_GF2m(const EC_GROUP *, EC_POINT *, - const BIGNUM *, int, BN_CTX *); - size_t EC_POINT_point2oct(const EC_GROUP *, const EC_POINT *, point_conversion_form_t, unsigned char *, size_t, BN_CTX *); @@ -109,14 +100,9 @@ #if defined(OPENSSL_NO_EC2M) static const long Cryptography_HAS_EC2M = 0; -int (*EC_POINT_set_affine_coordinates_GF2m)(const EC_GROUP *, EC_POINT *, - const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL; - int (*EC_POINT_get_affine_coordinates_GF2m)(const EC_GROUP *, const EC_POINT *, BIGNUM *, BIGNUM *, BN_CTX *) = NULL; -int (*EC_POINT_set_compressed_coordinates_GF2m)(const EC_GROUP *, EC_POINT *, - const BIGNUM *, int, BN_CTX *) = NULL; #else static const long Cryptography_HAS_EC2M = 1; #endif diff --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py index ba01169f1e10..124c12d5bfef 100644 --- a/src/cryptography/hazmat/bindings/openssl/_conditional.py +++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py @@ -5,9 +5,7 @@ def cryptography_has_ec2m(): return [ - "EC_POINT_set_affine_coordinates_GF2m", "EC_POINT_get_affine_coordinates_GF2m", - "EC_POINT_set_compressed_coordinates_GF2m", ] From a1dc9f2347de6a99aaa1316b075e669211579019 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 27 Jun 2021 16:33:39 -0400 Subject: [PATCH 0236/1456] separate test vectors (#6145) * separate test vectors * be correct --- docs/development/test-vectors.rst | 14 +++++++++----- tests/x509/test_x509.py | 10 +++++----- ...id_signature.pem => invalid_signature_cert.pem} | 11 ----------- .../x509/custom/invalid_signature_crl.pem | 11 +++++++++++ ...alid_signature.pem => valid_signature_cert.pem} | 11 ----------- .../x509/custom/valid_signature_crl.pem | 11 +++++++++++ 6 files changed, 36 insertions(+), 32 deletions(-) rename vectors/cryptography_vectors/x509/custom/{invalid_signature.pem => invalid_signature_cert.pem} (64%) create mode 100644 vectors/cryptography_vectors/x509/custom/invalid_signature_crl.pem rename vectors/cryptography_vectors/x509/custom/{valid_signature.pem => valid_signature_cert.pem} (64%) create mode 100644 vectors/cryptography_vectors/x509/custom/valid_signature_crl.pem diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index db897f79fbac..c5fc4d4857e8 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -499,11 +499,15 @@ Custom X.509 Certificate Revocation List Vectors * ``crl_ian_aia_aki.pem`` - Contains a CRL with ``IssuerAlternativeName``, ``AuthorityInformationAccess``, ``AuthorityKeyIdentifier`` and ``CRLNumber`` extensions. -* ``valid_signature.pem`` - Contains a CRL with the public key which was used - to generate it. -* ``invalid_signature.pem`` - Contains a CRL with the last signature byte - incremented by 1 to produce an invalid signature, and the public key which - was used to generate it. +* ``valid_signature_crl.pem`` - Contains a CRL with a valid signature. +* ``valid_signature_cert.pem`` - Contains a cert whose public key corresponds + to the private key that produced the signature for + ``valid_signature_crl.pem``. +* ``invalid_signature_crl.pem`` - Contains a CRL with the last signature byte + incremented by 1 to produce an invalid signature. +* ``invalid_signature_cert.pem`` - Contains a cert whose public key corresponds + to the private key that produced the signature for + ``invalid_signature_crl.pem``. * ``crl_delta_crl_indicator.pem`` - Contains a CRL with the ``DeltaCRLIndicator`` extension. * ``crl_idp_fullname_only.pem`` - Contains a CRL with an diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index f9f0d2fe6091..7e4e63e5ae86 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -391,12 +391,12 @@ def test_public_bytes_invalid_encoding(self, backend): def test_verify_bad(self, backend): crl = _load_cert( - os.path.join("x509", "custom", "invalid_signature.pem"), + os.path.join("x509", "custom", "invalid_signature_crl.pem"), x509.load_pem_x509_crl, backend, ) crt = _load_cert( - os.path.join("x509", "custom", "invalid_signature.pem"), + os.path.join("x509", "custom", "invalid_signature_cert.pem"), x509.load_pem_x509_certificate, backend, ) @@ -405,12 +405,12 @@ def test_verify_bad(self, backend): def test_verify_good(self, backend): crl = _load_cert( - os.path.join("x509", "custom", "valid_signature.pem"), + os.path.join("x509", "custom", "valid_signature_crl.pem"), x509.load_pem_x509_crl, backend, ) crt = _load_cert( - os.path.join("x509", "custom", "valid_signature.pem"), + os.path.join("x509", "custom", "valid_signature_cert.pem"), x509.load_pem_x509_certificate, backend, ) @@ -419,7 +419,7 @@ def test_verify_good(self, backend): def test_verify_argument_must_be_a_public_key(self, backend): crl = _load_cert( - os.path.join("x509", "custom", "valid_signature.pem"), + os.path.join("x509", "custom", "valid_signature_crl.pem"), x509.load_pem_x509_crl, backend, ) diff --git a/vectors/cryptography_vectors/x509/custom/invalid_signature.pem b/vectors/cryptography_vectors/x509/custom/invalid_signature_cert.pem similarity index 64% rename from vectors/cryptography_vectors/x509/custom/invalid_signature.pem rename to vectors/cryptography_vectors/x509/custom/invalid_signature_cert.pem index 2fc483d95b5e..0c9589fe174a 100644 --- a/vectors/cryptography_vectors/x509/custom/invalid_signature.pem +++ b/vectors/cryptography_vectors/x509/custom/invalid_signature_cert.pem @@ -1,14 +1,3 @@ ------BEGIN X509 CRL----- -MIIBfTBnAgEBMA0GCSqGSIb3DQEBCwUAMCUxIzAhBgNVBAMMGmludmFsaWRfc2ln -bmF0dXJlIENSTCB0ZXN0Fw0xNzA4MDYwMTQ4MjVaFw0xNzA5MDUwMTQ4MjVaoA4w -DDAKBgNVHRQEAwIBAzANBgkqhkiG9w0BAQsFAAOCAQEAFgGnFwwqviPvA0bfmnvI -c6oGIlq9Bmx/vSH6gwLCuGWn2BrKCWCIJNEtK4hrTfQRASb/uywHvhnByAE2lQlY -9FiefdvXgF5zEah/gV/2A0azvqfvOlPBLzreeoW3Q1fizmip3XN1fXiq8cXBpEYt -SRTJPzgbHvIu50EB2J0hs+rGo1hPTDtZn/r63hcQzUhIWQVmwP+NOzhpUcdnQj3/ -pn6BAJcxyYO2xDoUIncq586k8XVqshEl9xVwJMKhDDk84m/WQZg8i8szgI/muFsm -3vilMgIISrTMYeFIZWAy8rYfKLDMlmAtPRXYqyqOdTsLqz2X3RDMRHMXf1Vf8V31 -vA== ------END X509 CRL----- -----BEGIN CERTIFICATE----- MIICxjCCAa4CCQCETsDmKRzISDANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDDBpp bnZhbGlkX3NpZ25hdHVyZSBDUkwgdGVzdDAeFw0xNzA4MDYwMTM5MzRaFw0xNzA5 diff --git a/vectors/cryptography_vectors/x509/custom/invalid_signature_crl.pem b/vectors/cryptography_vectors/x509/custom/invalid_signature_crl.pem new file mode 100644 index 000000000000..54f77382d0be --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/invalid_signature_crl.pem @@ -0,0 +1,11 @@ +-----BEGIN X509 CRL----- +MIIBfTBnAgEBMA0GCSqGSIb3DQEBCwUAMCUxIzAhBgNVBAMMGmludmFsaWRfc2ln +bmF0dXJlIENSTCB0ZXN0Fw0xNzA4MDYwMTQ4MjVaFw0xNzA5MDUwMTQ4MjVaoA4w +DDAKBgNVHRQEAwIBAzANBgkqhkiG9w0BAQsFAAOCAQEAFgGnFwwqviPvA0bfmnvI +c6oGIlq9Bmx/vSH6gwLCuGWn2BrKCWCIJNEtK4hrTfQRASb/uywHvhnByAE2lQlY +9FiefdvXgF5zEah/gV/2A0azvqfvOlPBLzreeoW3Q1fizmip3XN1fXiq8cXBpEYt +SRTJPzgbHvIu50EB2J0hs+rGo1hPTDtZn/r63hcQzUhIWQVmwP+NOzhpUcdnQj3/ +pn6BAJcxyYO2xDoUIncq586k8XVqshEl9xVwJMKhDDk84m/WQZg8i8szgI/muFsm +3vilMgIISrTMYeFIZWAy8rYfKLDMlmAtPRXYqyqOdTsLqz2X3RDMRHMXf1Vf8V31 +vA== +-----END X509 CRL----- diff --git a/vectors/cryptography_vectors/x509/custom/valid_signature.pem b/vectors/cryptography_vectors/x509/custom/valid_signature_cert.pem similarity index 64% rename from vectors/cryptography_vectors/x509/custom/valid_signature.pem rename to vectors/cryptography_vectors/x509/custom/valid_signature_cert.pem index 9c2180985001..0c9589fe174a 100644 --- a/vectors/cryptography_vectors/x509/custom/valid_signature.pem +++ b/vectors/cryptography_vectors/x509/custom/valid_signature_cert.pem @@ -1,14 +1,3 @@ ------BEGIN X509 CRL----- -MIIBfTBnAgEBMA0GCSqGSIb3DQEBCwUAMCUxIzAhBgNVBAMMGmludmFsaWRfc2ln -bmF0dXJlIENSTCB0ZXN0Fw0xNzA4MDYwMTQ4MjVaFw0xNzA5MDUwMTQ4MjVaoA4w -DDAKBgNVHRQEAwIBAzANBgkqhkiG9w0BAQsFAAOCAQEAFgGnFwwqviPvA0bfmnvI -c6oGIlq9Bmx/vSH6gwLCuGWn2BrKCWCIJNEtK4hrTfQRASb/uywHvhnByAE2lQlY -9FiefdvXgF5zEah/gV/2A0azvqfvOlPBLzreeoW3Q1fizmip3XN1fXiq8cXBpEYt -SRTJPzgbHvIu50EB2J0hs+rGo1hPTDtZn/r63hcQzUhIWQVmwP+NOzhpUcdnQj3/ -pn6BAJcxyYO2xDoUIncq586k8XVqshEl9xVwJMKhDDk84m/WQZg8i8szgI/muFsm -3vilMgIISrTMYeFIZWAy8rYfKLDMlmAtPRXYqyqOdTsLqz2X3RDMRHMXf1Vf8V31 -ug== ------END X509 CRL----- -----BEGIN CERTIFICATE----- MIICxjCCAa4CCQCETsDmKRzISDANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDDBpp bnZhbGlkX3NpZ25hdHVyZSBDUkwgdGVzdDAeFw0xNzA4MDYwMTM5MzRaFw0xNzA5 diff --git a/vectors/cryptography_vectors/x509/custom/valid_signature_crl.pem b/vectors/cryptography_vectors/x509/custom/valid_signature_crl.pem new file mode 100644 index 000000000000..3aba91308bf8 --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/valid_signature_crl.pem @@ -0,0 +1,11 @@ +-----BEGIN X509 CRL----- +MIIBfTBnAgEBMA0GCSqGSIb3DQEBCwUAMCUxIzAhBgNVBAMMGmludmFsaWRfc2ln +bmF0dXJlIENSTCB0ZXN0Fw0xNzA4MDYwMTQ4MjVaFw0xNzA5MDUwMTQ4MjVaoA4w +DDAKBgNVHRQEAwIBAzANBgkqhkiG9w0BAQsFAAOCAQEAFgGnFwwqviPvA0bfmnvI +c6oGIlq9Bmx/vSH6gwLCuGWn2BrKCWCIJNEtK4hrTfQRASb/uywHvhnByAE2lQlY +9FiefdvXgF5zEah/gV/2A0azvqfvOlPBLzreeoW3Q1fizmip3XN1fXiq8cXBpEYt +SRTJPzgbHvIu50EB2J0hs+rGo1hPTDtZn/r63hcQzUhIWQVmwP+NOzhpUcdnQj3/ +pn6BAJcxyYO2xDoUIncq586k8XVqshEl9xVwJMKhDDk84m/WQZg8i8szgI/muFsm +3vilMgIISrTMYeFIZWAy8rYfKLDMlmAtPRXYqyqOdTsLqz2X3RDMRHMXf1Vf8V31 +ug== +-----END X509 CRL----- From fe1f078673dd99da5e2d9cfc9473b243d0013bc7 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 27 Jun 2021 17:45:10 -0400 Subject: [PATCH 0237/1456] modify alternate-rsa-sha1-oid to not contain a negative serial number (#6146) --- docs/development/test-vectors.rst | 5 ++--- tests/x509/test_x509.py | 4 ++-- .../x509/alternate-rsa-sha1-oid.pem | 12 ------------ .../x509/custom/alternate-rsa-sha1-oid.der | Bin 0 -> 455 bytes 4 files changed, 4 insertions(+), 17 deletions(-) delete mode 100644 vectors/cryptography_vectors/x509/alternate-rsa-sha1-oid.pem create mode 100644 vectors/cryptography_vectors/x509/custom/alternate-rsa-sha1-oid.der diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index c5fc4d4857e8..512dfb63799e 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -220,9 +220,8 @@ X.509 * ``e-trust.ru.der`` - A certificate from a `Russian CA`_ signed using the GOST cipher and containing numerous unusual encodings such as NUMERICSTRING in the subject DN. -* ``alternate-rsa-sha1-oid.pem`` - A certificate from an - `unknown signature OID`_ Mozilla bug that uses an alternate signature OID for - RSA with SHA1. +* ``alternate-rsa-sha1-oid.der`` - A certificate that uses an alternate + signature OID for RSA with SHA1. This certificate has an invalid signature. * ``badssl-sct.pem`` - A certificate with the certificate transparency signed certificate timestamp extension. * ``bigoid.pem`` - A certificate with a rather long OID in the diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 7e4e63e5ae86..61aefc6a59b6 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -644,8 +644,8 @@ def test_negative_serial_number(self, backend): def test_alternate_rsa_with_sha1_oid(self, backend): cert = _load_cert( - os.path.join("x509", "alternate-rsa-sha1-oid.pem"), - x509.load_pem_x509_certificate, + os.path.join("x509", "custom", "alternate-rsa-sha1-oid.der"), + x509.load_der_x509_certificate, backend, ) assert isinstance(cert.signature_hash_algorithm, hashes.SHA1) diff --git a/vectors/cryptography_vectors/x509/alternate-rsa-sha1-oid.pem b/vectors/cryptography_vectors/x509/alternate-rsa-sha1-oid.pem deleted file mode 100644 index 807a28b5547f..000000000000 --- a/vectors/cryptography_vectors/x509/alternate-rsa-sha1-oid.pem +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBwjCCAS+gAwIBAgIQj2d4hVEz0L1DYFVhA9CxCzAJBgUrDgMCHQUAMA8xDTAL -BgNVBAMTBFZQUzEwHhcNMDcwODE4MDkyODUzWhcNMDgwODE3MDkyODUzWjAPMQ0w -CwYDVQQDEwRWUFMxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaqKn40uaU -DbFL1NXXZ8/b4ZqDJ6eSI5lysMZHfZDs60G3ocbNKofBvURIutabrFuBCB2S5f/z -ICan0LR4uFpGuZ2I/PuVaU8X5fT8gBh7L636cWzHPPScYts00OyywEq381UB7XwX -YuWpM5kUW5rkbq1JV3ystTR/4YnLl48YtQIDAQABoycwJTATBgNVHSUEDDAKBggr -BgEFBQcDATAOBgNVHQ8EBwMFALAAAAAwCQYFKw4DAh0FAAOBgQBuUrU+J2Z5WKcO -VNjJHFUKo8qpbn8jKQZDl2nvVaXCTXQZblz/qxOm4FaGGzJ/m3GybVZNVfdyHg+U -lmDpFpOITkvcyNc3xjJCf2GVBo/VvdtVt7Myq0IQtAi/CXRK22BRNhSt9uu2EcRu -HIXdFWHEzi6eD4PpNw/0X3ID6Gxk4A== ------END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/custom/alternate-rsa-sha1-oid.der b/vectors/cryptography_vectors/x509/custom/alternate-rsa-sha1-oid.der new file mode 100644 index 0000000000000000000000000000000000000000..e8f4d4ca6c7db49708f1bd3938aed0704eec7ffc GIT binary patch literal 455 zcmXqLVmxfn#AvX9nTe5!NsysGy`nYH_`+W2gwRCh3mdr&IN4aW`IwnxSs4uY4S5Z? z*_cCFn1xxw0)h<<KB7iOU2^Mbb8si##& zEawZkaZ)CfYw@X-dG*SgY|hg&--j+ei^1n;$cBs!yEC)_-;H?a=L;jaEAeY~k3?S>km&A<#@@?YGz41drs& bwB8j>JaSHN9)I&obN(;!Ma(a9QXT*RpuMNg literal 0 HcmV?d00001 From 77fb53c75e47f50e09b1b3be3a4d10c7e4e34dc2 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 30 Jun 2021 06:14:42 -0500 Subject: [PATCH 0238/1456] 3.0.0 deprecated func and it isn't useful to us in general (#6148) remove it everywhere and assert on the code/lib/reason --- src/cryptography/hazmat/bindings/openssl/binding.py | 11 ++++------- tests/hazmat/bindings/test_openssl.py | 5 ++--- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py index 6dcec26ab8a3..f651ab672383 100644 --- a/src/cryptography/hazmat/bindings/openssl/binding.py +++ b/src/cryptography/hazmat/bindings/openssl/binding.py @@ -15,15 +15,14 @@ from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES _OpenSSLErrorWithText = collections.namedtuple( - "_OpenSSLErrorWithText", ["code", "lib", "func", "reason", "reason_text"] + "_OpenSSLErrorWithText", ["code", "lib", "reason", "reason_text"] ) class _OpenSSLError(object): - def __init__(self, code, lib, func, reason): + def __init__(self, code, lib, reason): self._code = code self._lib = lib - self._func = func self._reason = reason def _lib_reason_match(self, lib, reason): @@ -31,7 +30,6 @@ def _lib_reason_match(self, lib, reason): code = utils.read_only_property("_code") lib = utils.read_only_property("_lib") - func = utils.read_only_property("_func") reason = utils.read_only_property("_reason") @@ -43,10 +41,9 @@ def _consume_errors(lib): break err_lib = lib.ERR_GET_LIB(code) - err_func = lib.ERR_GET_FUNC(code) err_reason = lib.ERR_GET_REASON(code) - errors.append(_OpenSSLError(code, err_lib, err_func, err_reason)) + errors.append(_OpenSSLError(code, err_lib, err_reason)) return errors @@ -60,7 +57,7 @@ def _errors_with_text(errors): errors_with_text.append( _OpenSSLErrorWithText( - err.code, err.lib, err.func, err.reason, err_text_reason + err.code, err.lib, err.reason, err_text_reason ) ) diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py index 4d1e3b5566d5..1d9b87bad52f 100644 --- a/tests/hazmat/bindings/test_openssl.py +++ b/tests/hazmat/bindings/test_openssl.py @@ -91,11 +91,10 @@ def test_openssl_assert_error_on_stack(self): _openssl_assert(b.lib, False) error = exc_info.value.err_code[0] - # As of 3.0.0 OpenSSL sets func codes to 0, so the combined - # code is a different value + # As of 3.0.0 OpenSSL no longer sets func codes (which we now also + # ignore), so the combined code is a different value assert error.code in (101183626, 50331786) assert error.lib == b.lib.ERR_LIB_EVP - assert error.func == b.lib.EVP_F_EVP_ENCRYPTFINAL_EX assert error.reason == b.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH assert b"data not multiple of block length" in error.reason_text From 1b281ba52517572af0dc0c81388f8d9189914b98 Mon Sep 17 00:00:00 2001 From: "Nathaniel J. Smith" Date: Wed, 30 Jun 2021 11:25:39 -0700 Subject: [PATCH 0239/1456] Expose a few more OpenSSL functions that are useful for DTLS support (#6138) * Expose a few more OpenSSL functions that are useful for DTLS support * Move BIO_ADDR gunk to proper place * const correct * Throw more #ifdefs at the wall and see if they stick * njsmith used "think about what he's doing" it's probably not very effective * LibreSSL is not my favorite library * Attempt to hide my new undefined symbols * deflake * Give up on trying to check function pointers for NULLness AFAICT it works fine in CFFI's ABI mode, but I can't figure out how to do it in the API mode. --- src/_cffi_src/openssl/bio.py | 17 +++++++++++ src/_cffi_src/openssl/ssl.py | 28 +++++++++++++++++++ .../hazmat/bindings/openssl/_conditional.py | 16 +++++++++++ 3 files changed, 61 insertions(+) diff --git a/src/_cffi_src/openssl/bio.py b/src/_cffi_src/openssl/bio.py index 9310c1beb0f9..248a01e50e60 100644 --- a/src/_cffi_src/openssl/bio.py +++ b/src/_cffi_src/openssl/bio.py @@ -10,6 +10,7 @@ TYPES = """ typedef ... BIO; typedef ... BIO_METHOD; +typedef ... BIO_ADDR; """ FUNCTIONS = """ @@ -37,7 +38,23 @@ int BIO_reset(BIO *); void BIO_set_retry_read(BIO *); void BIO_clear_retry_flags(BIO *); + +BIO_ADDR *BIO_ADDR_new(void); +void BIO_ADDR_free(BIO_ADDR *); """ CUSTOMIZATIONS = """ +#if CRYPTOGRAPHY_IS_LIBRESSL +#include +#include +typedef struct sockaddr BIO_ADDR; + +BIO_ADDR *BIO_ADDR_new(void) { + return malloc(sizeof(struct sockaddr_storage)); +} + +void BIO_ADDR_free(BIO_ADDR *ptr) { + free(ptr); +} +#endif """ diff --git a/src/_cffi_src/openssl/ssl.py b/src/_cffi_src/openssl/ssl.py index 081ef041fa33..34d0283894f3 100644 --- a/src/_cffi_src/openssl/ssl.py +++ b/src/_cffi_src/openssl/ssl.py @@ -35,6 +35,7 @@ * supported */ static const long Cryptography_HAS_OP_NO_COMPRESSION; +static const long Cryptography_HAS_OP_NO_RENEGOTIATION; static const long Cryptography_HAS_SSL_OP_MSIE_SSLV2_RSA_PADDING; static const long Cryptography_HAS_SSL_SET_SSL_CTX; static const long Cryptography_HAS_SSL_OP_NO_TICKET; @@ -43,6 +44,7 @@ static const long Cryptography_HAS_SET_CERT_CB; static const long Cryptography_HAS_CUSTOM_EXT; static const long Cryptography_HAS_SRTP; +static const long Cryptography_HAS_DTLS_GET_DATA_MTU; static const long SSL_FILETYPE_PEM; static const long SSL_FILETYPE_ASN1; @@ -64,6 +66,7 @@ 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_RENEGOTIATION; static const long SSL_OP_NO_COMPRESSION; static const long SSL_OP_SINGLE_DH_USE; static const long SSL_OP_EPHEMERAL_RSA; @@ -225,6 +228,13 @@ unsigned char *, unsigned int * )); +void SSL_CTX_set_cookie_verify_cb(SSL_CTX *, + int (*)( + SSL *, + const unsigned char *, + unsigned int + )); + long SSL_CTX_get_read_ahead(SSL_CTX *); long SSL_CTX_set_read_ahead(SSL_CTX *, long); @@ -468,6 +478,10 @@ long DTLSv1_handle_timeout(SSL *); long DTLS_set_link_mtu(SSL *, long); long DTLS_get_link_min_mtu(SSL *); +long SSL_set_mtu(SSL *, long); +int DTLSv1_listen(SSL *, BIO_ADDR *); +size_t DTLS_get_data_mtu(SSL *); + /* Custom extensions. */ typedef int (*custom_ext_add_cb)(SSL *, unsigned int, @@ -556,6 +570,13 @@ static const long Cryptography_HAS_NEXTPROTONEG = 0; static const long Cryptography_HAS_ALPN = 1; +#ifdef SSL_OP_NO_RENEGOTIATION +static const long Cryptography_HAS_OP_NO_RENEGOTIATION = 1; +#else +static const long Cryptography_HAS_OP_NO_RENEGOTIATION = 0; +static const long SSL_OP_NO_RENEGOTIATION = 0; +#endif + #if CRYPTOGRAPHY_IS_LIBRESSL void (*SSL_CTX_set_cert_cb)(SSL_CTX *, int (*)(SSL *, void *), void *) = NULL; void (*SSL_set_cert_cb)(SSL *, int (*)(SSL *, void *), void *) = NULL; @@ -594,6 +615,13 @@ long (*DTLS_get_link_min_mtu)(SSL *) = NULL; #endif +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 +static const long Cryptography_HAS_DTLS_GET_DATA_MTU = 0; +size_t (*DTLS_get_data_mtu)(SSL *) = NULL; +#else +static const long Cryptography_HAS_DTLS_GET_DATA_MTU = 1; +#endif + static const long Cryptography_HAS_DTLS = 1; /* Wrap DTLSv1_get_timeout to avoid cffi to handle a 'struct timeval'. */ long Cryptography_DTLSv1_get_timeout(SSL *ssl, time_t *ptv_sec, diff --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py index 124c12d5bfef..912aff302607 100644 --- a/src/cryptography/hazmat/bindings/openssl/_conditional.py +++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py @@ -242,6 +242,18 @@ def cryptography_has_providers(): ] +def cryptography_has_op_no_renegotiation(): + return [ + "SSL_OP_NO_RENEGOTIATION", + ] + + +def cryptography_has_dtls_get_data_mtu(): + return [ + "DTLS_get_data_mtu", + ] + + # 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 @@ -289,4 +301,8 @@ def cryptography_has_providers(): "Cryptography_HAS_SRTP": cryptography_has_srtp, "Cryptography_HAS_GET_PROTO_VERSION": cryptography_has_get_proto_version, "Cryptography_HAS_PROVIDERS": cryptography_has_providers, + "Cryptography_HAS_OP_NO_RENEGOTIATION": ( + cryptography_has_op_no_renegotiation + ), + "Cryptography_HAS_DTLS_GET_DATA_MTU": cryptography_has_dtls_get_data_mtu, } From 50ec692749b7e2e62685b443f5e629627b03987e Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 30 Jun 2021 21:12:46 -0500 Subject: [PATCH 0240/1456] remove unneeded binding (#6150) --- src/_cffi_src/openssl/err.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/_cffi_src/openssl/err.py b/src/_cffi_src/openssl/err.py index 54dd1e44c43d..b81247ac7ed4 100644 --- a/src/_cffi_src/openssl/err.py +++ b/src/_cffi_src/openssl/err.py @@ -41,7 +41,6 @@ void ERR_put_error(int, int, int, const char *, int); int ERR_GET_LIB(unsigned long); -int ERR_GET_FUNC(unsigned long); int ERR_GET_REASON(unsigned long); """ From 95ba73be85c3887d5d4388891fc68839a828e02f Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 30 Jun 2021 21:43:45 -0500 Subject: [PATCH 0241/1456] reduce test duplication (#6151) --- tests/x509/test_x509.py | 568 +++++++++++----------------------------- 1 file changed, 159 insertions(+), 409 deletions(-) diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 61aefc6a59b6..1a185ffddd0d 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -3100,15 +3100,100 @@ def test_build_cert_with_rsa_key_too_small(self, backend): ) ] ), + x509.AuthorityInformationAccess( + [ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier( + "http://ocsp.domain.com" + ), + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier( + "http://domain.com/ca.crt" + ), + ), + ] + ), + x509.SubjectInformationAccess( + [ + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier("http://ca.domain.com"), + ), + ] + ), + x509.AuthorityKeyIdentifier( + b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08" + b"\xcbY", + None, + None, + ), + x509.AuthorityKeyIdentifier( + b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08" + b"\xcbY", + [ + x509.DirectoryName( + x509.Name( + [ + x509.NameAttribute( + NameOID.ORGANIZATION_NAME, "PyCA" + ), + x509.NameAttribute( + NameOID.COMMON_NAME, "cryptography CA" + ), + ] + ) + ) + ], + 333, + ), + x509.AuthorityKeyIdentifier( + None, + [ + x509.DirectoryName( + x509.Name( + [ + x509.NameAttribute( + NameOID.ORGANIZATION_NAME, "PyCA" + ), + x509.NameAttribute( + NameOID.COMMON_NAME, "cryptography CA" + ), + ] + ) + ) + ], + 333, + ), + x509.KeyUsage( + digital_signature=True, + content_commitment=True, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=True, + crl_sign=False, + encipher_only=False, + decipher_only=False, + ), + x509.OCSPNoCheck(), + x509.SubjectKeyIdentifier, ], ) - def test_ext(self, add_ext, backend): + def test_extensions(self, add_ext, backend): issuer_private_key = RSA_KEY_2048.private_key(backend) subject_private_key = RSA_KEY_2048.private_key(backend) not_valid_before = datetime.datetime(2002, 1, 1, 12, 1) not_valid_after = datetime.datetime(2030, 12, 31, 8, 30) + if add_ext is x509.SubjectKeyIdentifier: + add_ext = x509.SubjectKeyIdentifier.from_public_key( + subject_private_key.public_key() + ) + cert = ( x509.CertificateBuilder() .subject_name( @@ -3129,56 +3214,6 @@ def test_ext(self, add_ext, backend): assert ext.critical is False assert ext.value == add_ext - def test_key_usage(self, backend): - issuer_private_key = RSA_KEY_2048.private_key(backend) - subject_private_key = RSA_KEY_2048.private_key(backend) - - not_valid_before = datetime.datetime(2002, 1, 1, 12, 1) - not_valid_after = datetime.datetime(2030, 12, 31, 8, 30) - - cert = ( - x509.CertificateBuilder() - .subject_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) - ) - .issuer_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) - ) - .not_valid_before(not_valid_before) - .not_valid_after(not_valid_after) - .public_key(subject_private_key.public_key()) - .serial_number(123) - .add_extension( - x509.KeyUsage( - digital_signature=True, - content_commitment=True, - key_encipherment=False, - data_encipherment=False, - key_agreement=False, - key_cert_sign=True, - crl_sign=False, - encipher_only=False, - decipher_only=False, - ), - critical=False, - ) - .sign(issuer_private_key, hashes.SHA256(), backend) - ) - - ext = cert.extensions.get_extension_for_oid(ExtensionOID.KEY_USAGE) - assert ext.critical is False - assert ext.value == x509.KeyUsage( - digital_signature=True, - content_commitment=True, - key_encipherment=False, - data_encipherment=False, - key_agreement=False, - key_cert_sign=True, - crl_sign=False, - encipher_only=False, - decipher_only=False, - ) - def test_build_ca_request_with_path_length_none(self, backend): private_key = RSA_KEY_2048.private_key(backend) @@ -3687,82 +3722,6 @@ def test_add_unsupported_extension(self, backend): with pytest.raises(NotImplementedError): builder.sign(private_key, hashes.SHA256(), backend) - def test_key_usage(self, backend): - private_key = RSA_KEY_2048.private_key(backend) - builder = x509.CertificateSigningRequestBuilder() - request = ( - builder.subject_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) - ) - .add_extension( - x509.KeyUsage( - digital_signature=True, - content_commitment=True, - key_encipherment=False, - data_encipherment=False, - key_agreement=False, - key_cert_sign=True, - crl_sign=False, - encipher_only=False, - decipher_only=False, - ), - critical=False, - ) - .sign(private_key, hashes.SHA256(), backend) - ) - assert len(request.extensions) == 1 - ext = request.extensions.get_extension_for_oid(ExtensionOID.KEY_USAGE) - assert ext.critical is False - assert ext.value == x509.KeyUsage( - digital_signature=True, - content_commitment=True, - key_encipherment=False, - data_encipherment=False, - key_agreement=False, - key_cert_sign=True, - crl_sign=False, - encipher_only=False, - decipher_only=False, - ) - - def test_key_usage_key_agreement_bit(self, backend): - private_key = RSA_KEY_2048.private_key(backend) - builder = x509.CertificateSigningRequestBuilder() - request = ( - builder.subject_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) - ) - .add_extension( - x509.KeyUsage( - digital_signature=False, - content_commitment=False, - key_encipherment=False, - data_encipherment=False, - key_agreement=True, - key_cert_sign=True, - crl_sign=False, - encipher_only=False, - decipher_only=True, - ), - critical=False, - ) - .sign(private_key, hashes.SHA256(), backend) - ) - assert len(request.extensions) == 1 - ext = request.extensions.get_extension_for_oid(ExtensionOID.KEY_USAGE) - assert ext.critical is False - assert ext.value == x509.KeyUsage( - digital_signature=False, - content_commitment=False, - key_encipherment=False, - data_encipherment=False, - key_agreement=True, - key_cert_sign=True, - crl_sign=False, - encipher_only=False, - decipher_only=True, - ) - def test_add_two_extensions(self, backend): private_key = RSA_KEY_2048.private_key(backend) builder = x509.CertificateSigningRequestBuilder() @@ -3873,62 +3832,94 @@ def test_set_subject_twice(self): x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) ) - def test_subject_alt_names(self, backend): + @pytest.mark.parametrize( + "add_ext", + [ + x509.KeyUsage( + digital_signature=True, + content_commitment=True, + key_encipherment=False, + data_encipherment=False, + key_agreement=False, + key_cert_sign=True, + crl_sign=False, + encipher_only=False, + decipher_only=False, + ), + x509.KeyUsage( + digital_signature=False, + content_commitment=False, + key_encipherment=False, + data_encipherment=False, + key_agreement=True, + key_cert_sign=True, + crl_sign=False, + encipher_only=False, + decipher_only=True, + ), + x509.SubjectAlternativeName( + [ + x509.DNSName("example.com"), + x509.DNSName("*.example.com"), + x509.RegisteredID(x509.ObjectIdentifier("1.2.3.4.5.6.7")), + x509.DirectoryName( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, "PyCA" + ), + x509.NameAttribute( + NameOID.ORGANIZATION_NAME, + "We heart UTF8!\u2122", + ), + ] + ) + ), + x509.IPAddress(ipaddress.ip_address("127.0.0.1")), + x509.IPAddress(ipaddress.ip_address("ff::")), + x509.OtherName( + type_id=x509.ObjectIdentifier("1.2.3.3.3.3"), + value=b"0\x03\x02\x01\x05", + ), + x509.RFC822Name("test@example.com"), + x509.RFC822Name("email"), + x509.RFC822Name("email@xn--eml-vla4c.com"), + x509.UniformResourceIdentifier( + "https://xn--80ato2c.cryptography" + ), + x509.UniformResourceIdentifier( + "gopher://cryptography:70/some/path" + ), + ] + ), + x509.ExtendedKeyUsage( + [ + ExtendedKeyUsageOID.CLIENT_AUTH, + ExtendedKeyUsageOID.SERVER_AUTH, + ExtendedKeyUsageOID.CODE_SIGNING, + ] + ), + ], + ) + def test_extensions(self, add_ext, backend): private_key = RSA_KEY_2048.private_key(backend) - san = x509.SubjectAlternativeName( - [ - x509.DNSName("example.com"), - x509.DNSName("*.example.com"), - x509.RegisteredID(x509.ObjectIdentifier("1.2.3.4.5.6.7")), - x509.DirectoryName( - x509.Name( - [ - x509.NameAttribute(NameOID.COMMON_NAME, "PyCA"), - x509.NameAttribute( - NameOID.ORGANIZATION_NAME, - "We heart UTF8!\u2122", - ), - ] - ) - ), - x509.IPAddress(ipaddress.ip_address("127.0.0.1")), - x509.IPAddress(ipaddress.ip_address("ff::")), - x509.OtherName( - type_id=x509.ObjectIdentifier("1.2.3.3.3.3"), - value=b"0\x03\x02\x01\x05", - ), - x509.RFC822Name("test@example.com"), - x509.RFC822Name("email"), - x509.RFC822Name("email@xn--eml-vla4c.com"), - x509.UniformResourceIdentifier( - "https://xn--80ato2c.cryptography" - ), - x509.UniformResourceIdentifier( - "gopher://cryptography:70/some/path" - ), - ] - ) - csr = ( x509.CertificateSigningRequestBuilder() .subject_name( x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "SAN")]) ) .add_extension( - san, + add_ext, critical=False, ) .sign(private_key, hashes.SHA256(), backend) ) assert len(csr.extensions) == 1 - ext = csr.extensions.get_extension_for_oid( - ExtensionOID.SUBJECT_ALTERNATIVE_NAME - ) + ext = csr.extensions.get_extension_for_class(type(add_ext)) assert not ext.critical - assert ext.oid == ExtensionOID.SUBJECT_ALTERNATIVE_NAME - assert ext.value == san + assert ext.value == add_ext def test_invalid_asn1_othername(self, backend): private_key = RSA_KEY_2048.private_key(backend) @@ -3972,30 +3963,6 @@ def test_subject_alt_name_unsupported_general_name(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) - def test_extended_key_usage(self, backend): - private_key = RSA_KEY_2048.private_key(backend) - eku = x509.ExtendedKeyUsage( - [ - ExtendedKeyUsageOID.CLIENT_AUTH, - ExtendedKeyUsageOID.SERVER_AUTH, - ExtendedKeyUsageOID.CODE_SIGNING, - ] - ) - builder = x509.CertificateSigningRequestBuilder() - request = ( - builder.subject_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) - ) - .add_extension(eku, critical=False) - .sign(private_key, hashes.SHA256(), backend) - ) - - ext = request.extensions.get_extension_for_oid( - ExtensionOID.EXTENDED_KEY_USAGE - ) - assert ext.critical is False - assert ext.value == eku - def test_rsa_key_too_small(self, backend): private_key = RSA_KEY_512.private_key(backend) builder = x509.CertificateSigningRequestBuilder() @@ -4006,223 +3973,6 @@ def test_rsa_key_too_small(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA512(), backend) - def test_build_cert_with_aia(self, backend): - issuer_private_key = RSA_KEY_2048.private_key(backend) - subject_private_key = RSA_KEY_2048.private_key(backend) - - not_valid_before = datetime.datetime(2002, 1, 1, 12, 1) - not_valid_after = datetime.datetime(2030, 12, 31, 8, 30) - - aia = x509.AuthorityInformationAccess( - [ - x509.AccessDescription( - AuthorityInformationAccessOID.OCSP, - x509.UniformResourceIdentifier("http://ocsp.domain.com"), - ), - x509.AccessDescription( - AuthorityInformationAccessOID.CA_ISSUERS, - x509.UniformResourceIdentifier("http://domain.com/ca.crt"), - ), - ] - ) - - builder = ( - x509.CertificateBuilder() - .serial_number(777) - .issuer_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) - ) - .subject_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) - ) - .public_key(subject_private_key.public_key()) - .add_extension(aia, critical=False) - .not_valid_before(not_valid_before) - .not_valid_after(not_valid_after) - ) - - cert = builder.sign(issuer_private_key, hashes.SHA256(), backend) - - ext = cert.extensions.get_extension_for_oid( - ExtensionOID.AUTHORITY_INFORMATION_ACCESS - ) - assert ext.value == aia - - def test_build_cert_with_sia(self, backend): - issuer_private_key = RSA_KEY_2048.private_key(backend) - subject_private_key = RSA_KEY_2048.private_key(backend) - - not_valid_before = datetime.datetime(2002, 1, 1, 12, 1) - not_valid_after = datetime.datetime(2030, 12, 31, 8, 30) - - sia = x509.SubjectInformationAccess( - [ - x509.AccessDescription( - SubjectInformationAccessOID.CA_REPOSITORY, - x509.UniformResourceIdentifier("http://ca.domain.com"), - ), - ] - ) - - builder = ( - x509.CertificateBuilder() - .serial_number(777) - .issuer_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) - ) - .subject_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) - ) - .public_key(subject_private_key.public_key()) - .add_extension(sia, critical=False) - .not_valid_before(not_valid_before) - .not_valid_after(not_valid_after) - ) - - cert = builder.sign(issuer_private_key, hashes.SHA256(), backend) - - ext = cert.extensions.get_extension_for_oid( - ExtensionOID.SUBJECT_INFORMATION_ACCESS - ) - assert ext.value == sia - - def test_build_cert_with_ski(self, backend): - issuer_private_key = RSA_KEY_2048.private_key(backend) - subject_private_key = RSA_KEY_2048.private_key(backend) - - not_valid_before = datetime.datetime(2002, 1, 1, 12, 1) - not_valid_after = datetime.datetime(2030, 12, 31, 8, 30) - - ski = x509.SubjectKeyIdentifier.from_public_key( - subject_private_key.public_key() - ) - - builder = ( - x509.CertificateBuilder() - .serial_number(777) - .issuer_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) - ) - .subject_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) - ) - .public_key(subject_private_key.public_key()) - .add_extension(ski, critical=False) - .not_valid_before(not_valid_before) - .not_valid_after(not_valid_after) - ) - - cert = builder.sign(issuer_private_key, hashes.SHA256(), backend) - - ext = cert.extensions.get_extension_for_oid( - ExtensionOID.SUBJECT_KEY_IDENTIFIER - ) - assert ext.value == ski - - @pytest.mark.parametrize( - "aki", - [ - x509.AuthorityKeyIdentifier( - b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08" - b"\xcbY", - None, - None, - ), - x509.AuthorityKeyIdentifier( - b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08" - b"\xcbY", - [ - x509.DirectoryName( - x509.Name( - [ - x509.NameAttribute( - NameOID.ORGANIZATION_NAME, "PyCA" - ), - x509.NameAttribute( - NameOID.COMMON_NAME, "cryptography CA" - ), - ] - ) - ) - ], - 333, - ), - x509.AuthorityKeyIdentifier( - None, - [ - x509.DirectoryName( - x509.Name( - [ - x509.NameAttribute( - NameOID.ORGANIZATION_NAME, "PyCA" - ), - x509.NameAttribute( - NameOID.COMMON_NAME, "cryptography CA" - ), - ] - ) - ) - ], - 333, - ), - ], - ) - def test_build_cert_with_aki(self, aki, backend): - issuer_private_key = RSA_KEY_2048.private_key(backend) - subject_private_key = RSA_KEY_2048.private_key(backend) - - not_valid_before = datetime.datetime(2002, 1, 1, 12, 1) - not_valid_after = datetime.datetime(2030, 12, 31, 8, 30) - - builder = ( - x509.CertificateBuilder() - .serial_number(777) - .issuer_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) - ) - .subject_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) - ) - .public_key(subject_private_key.public_key()) - .add_extension(aki, critical=False) - .not_valid_before(not_valid_before) - .not_valid_after(not_valid_after) - ) - - cert = builder.sign(issuer_private_key, hashes.SHA256(), backend) - - ext = cert.extensions.get_extension_for_oid( - ExtensionOID.AUTHORITY_KEY_IDENTIFIER - ) - assert ext.value == aki - - def test_ocsp_nocheck(self, backend): - issuer_private_key = RSA_KEY_2048.private_key(backend) - subject_private_key = RSA_KEY_2048.private_key(backend) - - not_valid_before = datetime.datetime(2002, 1, 1, 12, 1) - not_valid_after = datetime.datetime(2030, 12, 31, 8, 30) - - builder = ( - x509.CertificateBuilder() - .serial_number(777) - .issuer_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) - ) - .subject_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) - ) - .public_key(subject_private_key.public_key()) - .add_extension(x509.OCSPNoCheck(), critical=False) - .not_valid_before(not_valid_before) - .not_valid_after(not_valid_after) - ) - - cert = builder.sign(issuer_private_key, hashes.SHA256(), backend) - - ext = cert.extensions.get_extension_for_oid(ExtensionOID.OCSP_NO_CHECK) - assert isinstance(ext.value, x509.OCSPNoCheck) - class TestDSACertificate(object): def test_load_dsa_cert(self, backend): From 0034926f2cca02258f50e9faccb90ec344790159 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 1 Jul 2021 05:51:55 -0500 Subject: [PATCH 0242/1456] add invalid time CRL vector (#6152) * add invalid time CRL vector * more words --- docs/development/test-vectors.rst | 2 ++ tests/x509/test_x509.py | 10 ++++++++++ .../x509/custom/crl_invalid_time.der | Bin 0 -> 388 bytes 3 files changed, 12 insertions(+) create mode 100644 vectors/cryptography_vectors/x509/custom/crl_invalid_time.der diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 512dfb63799e..ee8e617edd4d 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -536,6 +536,8 @@ Custom X.509 Certificate Revocation List Vectors * ``crl_unrecognized_extension.der`` - Contains a CRL containing an unsupported extension type. The OID was encoded as "1.2.3.4.5" with an ``extnValue`` of ``abcdef``. +* ``crl_invalid_time.der`` - Contains a CRL with an invalid ``GeneralizedTime`` + value in ``thisUpdate``. The signature on this CRL is invalid. X.509 OCSP Test Vectors ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 1a185ffddd0d..fc36d5f4111b 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -106,6 +106,16 @@ def test_invalid_der(self, backend): with pytest.raises(ValueError): x509.load_der_x509_crl(b"notacrl", backend) + def test_invalid_time(self, backend): + crl = _load_cert( + os.path.join("x509", "custom", "crl_invalid_time.der"), + x509.load_der_x509_crl, + backend, + ) + + with pytest.raises(ValueError, match="18102813516Z"): + crl.last_update + def test_unknown_signature_algorithm(self, backend): crl = _load_cert( os.path.join( diff --git a/vectors/cryptography_vectors/x509/custom/crl_invalid_time.der b/vectors/cryptography_vectors/x509/custom/crl_invalid_time.der new file mode 100644 index 0000000000000000000000000000000000000000..a0122954944728fe8c91a805763830d706433bc3 GIT binary patch literal 388 zcmXqLVr($TVq#=8;AP{~YV&CO&dbQi&B|aPY$#~J&&C|e!py_rS(KTVsNn1<&SPj{ zXkcVvXl!a|7A4LL719>3s0u=)#0|lTCSs6yg|14q#A`AEz@)~f1%;4f-38-{- zY-0S6W({)_BO}B5h|~$!XC`?Yx|^)AWRsg=^5dgF^S8Mt1=f7sf!VjLv006AJm(KtI literal 0 HcmV?d00001 From 665126dd2b78c46f622389dfe6fb4c2d19f006b4 Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Sat, 3 Jul 2021 18:26:36 -0600 Subject: [PATCH 0243/1456] Disable fail-fast in tests. (#6155) This makes it easier to isolate regressions by running all tests even if one fails. --- .github/workflows/ci.yml | 6 ++++++ .github/workflows/wheel-builder.yml | 3 +++ 2 files changed, 9 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f52a9faab5f0..46450d94d0c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,7 @@ jobs: linux: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: PYTHON: - {VERSION: "3.9", TOXENV: "flake,rust,docs", COVERAGE: "false"} @@ -108,6 +109,7 @@ jobs: runs-on: ubuntu-latest container: ghcr.io/pyca/cryptography-runner-${{ matrix.IMAGE.IMAGE }} strategy: + fail-fast: false matrix: IMAGE: - {IMAGE: "centos8", TOXENV: "py36"} @@ -154,6 +156,7 @@ jobs: linux-rust: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: PYTHON: - {VERSION: "3.9", TOXENV: "py39"} @@ -267,6 +270,7 @@ jobs: macos: runs-on: macos-latest strategy: + fail-fast: false matrix: PYTHON: - {VERSION: "3.6", TOXENV: "py36", EXTRA_CFLAGS: ""} @@ -327,6 +331,7 @@ jobs: windows: runs-on: windows-latest strategy: + fail-fast: false matrix: WINDOWS: - {ARCH: 'x86', WINDOWS: 'win32', RUST_TRIPLE: 'i686-pc-windows-msvc'} @@ -391,6 +396,7 @@ jobs: linux-downstream: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: DOWNSTREAM: - paramiko diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 160ba8f0e6ca..29a1e154f473 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -10,6 +10,7 @@ jobs: runs-on: ubuntu-latest container: ghcr.io/pyca/${{ matrix.MANYLINUX.CONTAINER }} strategy: + fail-fast: false matrix: PYTHON: - { VERSION: "cp36-cp36m", PATH: "/opt/python/cp36-cp36m/bin/python", ABI_VERSION: 'cp36' } @@ -59,6 +60,7 @@ jobs: macos: runs-on: macos-latest strategy: + fail-fast: false matrix: PYTHON: - VERSION: '3.8' @@ -112,6 +114,7 @@ jobs: windows: runs-on: windows-latest strategy: + fail-fast: false matrix: WINDOWS: - {ARCH: 'x86', WINDOWS: 'win32', RUST_TRIPLE: 'i686-pc-windows-msvc'} From 120e804d8a36b4adfa71b2e5700a773ff9cfd19a Mon Sep 17 00:00:00 2001 From: James Hilliard Date: Sun, 4 Jul 2021 17:01:10 -0600 Subject: [PATCH 0244/1456] pyo3: bump to version 0.14.1 (#6154) --- src/rust/Cargo.lock | 74 ++++++------------- src/rust/Cargo.toml | 2 +- src/rust/src/ocsp.rs | 16 ++--- src/rust/src/x509.rs | 166 ++++++++++++++++++++++++------------------- 4 files changed, 124 insertions(+), 134 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 6453ed9c698b..8ebd9ff10d26 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -68,27 +68,6 @@ dependencies = [ "pyo3", ] -[[package]] -name = "ctor" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "ghost" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "indoc" version = "0.3.6" @@ -121,28 +100,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "inventory" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0f7efb804ec95e33db9ad49e4252f049e37e8b0a4652e3cd61f7999f2eff7f" -dependencies = [ - "ctor", - "ghost", - "inventory-impl", -] - -[[package]] -name = "inventory-impl" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75c094e94816723ab936484666968f5b58060492e880f3c8d00489a1e244fa51" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -183,6 +140,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + [[package]] name = "ouroboros" version = "0.9.5" @@ -291,26 +254,34 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.13.2" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4837b8e8e18a102c23f79d1e9a110b597ea3b684c95e874eb1ad88f8683109c3" +checksum = "338f7f3701e11fd7f76508c91fbcaabc982564bcaf4d1ca7e1574ff2b4778aec" dependencies = [ "cfg-if", - "ctor", "indoc", - "inventory", "libc", "parking_lot", "paste", + "pyo3-build-config", "pyo3-macros", "unindent", ] +[[package]] +name = "pyo3-build-config" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb2e98cc9ccc83d4f7115c8f925e0057e88c8d324b1bc4c2db4a7270c06ac9d" +dependencies = [ + "once_cell", +] + [[package]] name = "pyo3-macros" -version = "0.13.2" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47f2c300ceec3e58064fd5f8f5b61230f2ffd64bde4970c81fdd0563a2db1bb" +checksum = "cfb8671a42d0ecc4bec8cc107ae96d49292ca20cd1968e09b98af4aafd516adf" dependencies = [ "pyo3-macros-backend", "quote", @@ -319,11 +290,12 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.13.2" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87b097e5d84fcbe3e167f400fbedd657820a375b034c78bd852050749a575d66" +checksum = "9addf6dc422f05d4949cc0990195ee74fa43e3c3780cc9a1972fe9e7b68a9f48" dependencies = [ "proc-macro2", + "pyo3-build-config", "quote", "syn", ] diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 6ea95be09f67..f402456859ea 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] lazy_static = "1" -pyo3 = { version = "0.13.1" } +pyo3 = { version = "0.14.1" } asn1 = { version = "0.5.3", default-features = false, features = ["derive"] } chrono = { version = "0.4", default-features = false, features = ["alloc"] } ouroboros = "0.9" diff --git a/src/rust/src/ocsp.rs b/src/rust/src/ocsp.rs index e6436631950f..e097aacc852e 100644 --- a/src/rust/src/ocsp.rs +++ b/src/rust/src/ocsp.rs @@ -94,17 +94,14 @@ impl OCSPRequest { let hashes = py.import("cryptography.hazmat.primitives.hashes")?; match OIDS_TO_HASH.get(&cert_id.hash_algorithm.oid) { - Some(alg_name) => Ok(hashes.call0(alg_name)?), + Some(alg_name) => Ok(hashes.getattr(alg_name)?.call0()?), None => { let exceptions = py.import("cryptography.exceptions")?; Err(PyAsn1Error::from(pyo3::PyErr::from_instance( - exceptions.call1( - "UnsupportedAlgorithm", - (format!( - "Signature algorithm OID: {} not recognized", - cert_id.hash_algorithm.oid - ),), - )?, + exceptions.getattr("UnsupportedAlgorithm")?.call1((format!( + "Signature algorithm OID: {} not recognized", + cert_id.hash_algorithm.oid + ),))?, ))) } } @@ -233,7 +230,8 @@ fn parse_ocsp_singleresp_extension( let contents = asn1::parse_single::<&[u8]>(ext_data)?; let scts = x509::parse_scts(py, contents, x509::LogEntryType::Certificate)?; Ok(x509_module - .call1("SignedCertificateTimestamps", (scts,))? + .getattr("SignedCertificateTimestamps")? + .call1((scts,))? .to_object(py)) } else { x509::parse_crl_entry_extension(py, der_oid, ext_data) diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index f9bb51861b79..f23ae7dd7e81 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -240,17 +240,14 @@ fn chrono_to_py<'p>( dt: &chrono::DateTime, ) -> pyo3::PyResult<&'p pyo3::PyAny> { let datetime_module = py.import("datetime")?; - datetime_module.call1( - "datetime", - ( - dt.year(), - dt.month(), - dt.day(), - dt.hour(), - dt.minute(), - dt.second(), - ), - ) + datetime_module.getattr("datetime")?.call1(( + dt.year(), + dt.month(), + dt.day(), + dt.hour(), + dt.minute(), + dt.second(), + )) } struct UnvalidatedIA5String<'a>(&'a str); @@ -377,10 +374,8 @@ fn parse_distribution_point( }; let x509_module = py.import("cryptography.x509")?; Ok(x509_module - .call1( - "DistributionPoint", - (full_name, relative_name, reasons, crl_issuer), - )? + .getattr("DistributionPoint")? + .call1((full_name, relative_name, reasons, crl_issuer))? .to_object(py)) } @@ -486,10 +481,11 @@ fn parse_authority_key_identifier<'p>( Some(aci) => parse_general_names(py, aci)?, None => py.None(), }; - Ok(x509_module.call1( - "AuthorityKeyIdentifier", - (aki.key_identifier, issuer, serial), - )?) + Ok(x509_module.getattr("AuthorityKeyIdentifier")?.call1(( + aki.key_identifier, + issuer, + serial, + ))?) } fn parse_name_attribute( @@ -678,7 +674,8 @@ fn parse_access_descriptions( .to_object(py); let gn = parse_general_name(py, access.access_location)?; let ad = x509_module - .call1("AccessDescription", (py_oid, gn))? + .getattr("AccessDescription")? + .call1((py_oid, gn))? .to_object(py); ads.append(ad)?; } @@ -863,13 +860,15 @@ fn parse_x509_extension( let gn_seq = asn1::parse_single::>>(ext_data)?; let sans = parse_general_names(py, gn_seq)?; Ok(x509_module - .call1("SubjectAlternativeName", (sans,))? + .getattr("SubjectAlternativeName")? + .call1((sans,))? .to_object(py)) } else if oid == *ISSUER_ALTERNATIVE_NAME_OID { let gn_seq = asn1::parse_single::>>(ext_data)?; let ians = parse_general_names(py, gn_seq)?; Ok(x509_module - .call1("IssuerAlternativeName", (ians,))? + .getattr("IssuerAlternativeName")? + .call1((ians,))? .to_object(py)) } else if oid == *TLS_FEATURE_OID { let tls_feature_type_to_enum = py @@ -881,11 +880,15 @@ fn parse_x509_extension( let py_feature = tls_feature_type_to_enum.get_item(feature.to_object(py))?; features.append(py_feature)?; } - Ok(x509_module.call1("TLSFeature", (features,))?.to_object(py)) + Ok(x509_module + .getattr("TLSFeature")? + .call1((features,))? + .to_object(py)) } else if oid == *SUBJECT_KEY_IDENTIFIER_OID { let identifier = asn1::parse_single::<&[u8]>(ext_data)?; Ok(x509_module - .call1("SubjectKeyIdentifier", (identifier,))? + .getattr("SubjectKeyIdentifier")? + .call1((identifier,))? .to_object(py)) } else if oid == *EXTENDED_KEY_USAGE_OID { let ekus = pyo3::types::PyList::empty(py); @@ -895,7 +898,8 @@ fn parse_x509_extension( ekus.append(oid_obj)?; } Ok(x509_module - .call1("ExtendedKeyUsage", (ekus,))? + .getattr("ExtendedKeyUsage")? + .call1((ekus,))? .to_object(py)) } else if oid == *KEY_USAGE_OID { let kus = asn1::parse_single::>(ext_data)?; @@ -909,30 +913,30 @@ fn parse_x509_extension( let encipher_only = kus.has_bit_set(7); let decipher_only = kus.has_bit_set(8); Ok(x509_module - .call1( - "KeyUsage", - ( - digital_signature, - content_comitment, - key_encipherment, - data_encipherment, - key_agreement, - key_cert_sign, - crl_sign, - encipher_only, - decipher_only, - ), - )? + .getattr("KeyUsage")? + .call1(( + digital_signature, + content_comitment, + key_encipherment, + data_encipherment, + key_agreement, + key_cert_sign, + crl_sign, + encipher_only, + decipher_only, + ))? .to_object(py)) } else if oid == *AUTHORITY_INFORMATION_ACCESS_OID { let ads = parse_access_descriptions(py, ext_data)?; Ok(x509_module - .call1("AuthorityInformationAccess", (ads,))? + .getattr("AuthorityInformationAccess")? + .call1((ads,))? .to_object(py)) } else if oid == *SUBJECT_INFORMATION_ACCESS_OID { let ads = parse_access_descriptions(py, ext_data)?; Ok(x509_module - .call1("SubjectInformationAccess", (ads,))? + .getattr("SubjectInformationAccess")? + .call1((ads,))? .to_object(py)) } else if oid == *CERTIFICATE_POLICIES_OID { let cp = parse_cp(py, ext_data)?; @@ -942,44 +946,47 @@ fn parse_x509_extension( } else if oid == *POLICY_CONSTRAINTS_OID { let pc = asn1::parse_single::(ext_data)?; Ok(x509_module - .call1( - "PolicyConstraints", - (pc.require_explicit_policy, pc.inhibit_policy_mapping), - )? + .getattr("PolicyConstraints")? + .call1((pc.require_explicit_policy, pc.inhibit_policy_mapping))? .to_object(py)) } else if oid == *PRECERT_POISON_OID { asn1::parse_single::<()>(ext_data)?; - Ok(x509_module.call0("PrecertPoison")?.to_object(py)) + Ok(x509_module.getattr("PrecertPoison")?.call0()?.to_object(py)) } else if oid == *OCSP_NO_CHECK_OID { asn1::parse_single::<()>(ext_data)?; - Ok(x509_module.call0("OCSPNoCheck")?.to_object(py)) + Ok(x509_module.getattr("OCSPNoCheck")?.call0()?.to_object(py)) } else if oid == *INHIBIT_ANY_POLICY_OID { let bignum = asn1::parse_single::>(ext_data)?; let pynum = big_asn1_uint_to_py(py, bignum)?; Ok(x509_module - .call1("InhibitAnyPolicy", (pynum,))? + .getattr("InhibitAnyPolicy")? + .call1((pynum,))? .to_object(py)) } else if oid == *BASIC_CONSTRAINTS_OID { let bc = asn1::parse_single::(ext_data)?; Ok(x509_module - .call1("BasicConstraints", (bc.ca, bc.path_length))? + .getattr("BasicConstraints")? + .call1((bc.ca, bc.path_length))? .to_object(py)) } else if oid == *AUTHORITY_KEY_IDENTIFIER_OID { Ok(parse_authority_key_identifier(py, ext_data)?.to_object(py)) } else if oid == *CRL_DISTRIBUTION_POINTS_OID { let dp = parse_distribution_points(py, ext_data)?; Ok(x509_module - .call1("CRLDistributionPoints", (dp,))? + .getattr("CRLDistributionPoints")? + .call1((dp,))? .to_object(py)) } else if oid == *FRESHEST_CRL_OID { Ok(x509_module - .call1("FreshestCRL", (parse_distribution_points(py, ext_data)?,))? + .getattr("FreshestCRL")? + .call1((parse_distribution_points(py, ext_data)?,))? .to_object(py)) } else if oid == *PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS_OID { let contents = asn1::parse_single::<&[u8]>(ext_data)?; let scts = parse_scts(py, contents, LogEntryType::PreCertificate)?; Ok(x509_module - .call1("PrecertificateSignedCertificateTimestamps", (scts,))? + .getattr("PrecertificateSignedCertificateTimestamps")? + .call1((scts,))? .to_object(py)) } else if oid == *NAME_CONSTRAINTS_OID { let nc = asn1::parse_single::>(ext_data)?; @@ -992,7 +999,8 @@ fn parse_x509_extension( None => py.None(), }; Ok(x509_module - .call1("NameConstraints", (permitted_subtrees, excluded_subtrees))? + .getattr("NameConstraints")? + .call1((permitted_subtrees, excluded_subtrees))? .to_object(py)) } else { Ok(py.None()) @@ -1027,17 +1035,24 @@ pub(crate) fn parse_crl_entry_extension( } }; let flag = x509_module.getattr("ReasonFlags")?.getattr(flag_name)?; - Ok(x509_module.call1("CRLReason", (flag,))?.to_object(py)) + Ok(x509_module + .getattr("CRLReason")? + .call1((flag,))? + .to_object(py)) } else if oid == *CERTIFICATE_ISSUER_OID { let gn_seq = asn1::parse_single::>>(ext_data)?; let gns = parse_general_names(py, gn_seq)?; Ok(x509_module - .call1("CertificateIssuer", (gns,))? + .getattr("CertificateIssuer")? + .call1((gns,))? .to_object(py)) } else if oid == *INVALIDITY_DATE_OID { let time = asn1::parse_single::(ext_data)?; let py_dt = chrono_to_py(py, time.as_chrono())?; - Ok(x509_module.call1("InvalidityDate", (py_dt,))?.to_object(py)) + Ok(x509_module + .getattr("InvalidityDate")? + .call1((py_dt,))? + .to_object(py)) } else { Ok(py.None()) } @@ -1055,23 +1070,29 @@ fn parse_crl_extension( if oid == *CRL_NUMBER_OID { let bignum = asn1::parse_single::>(ext_data)?; let pynum = big_asn1_uint_to_py(py, bignum)?; - Ok(x509_module.call1("CRLNumber", (pynum,))?.to_object(py)) + Ok(x509_module + .getattr("CRLNumber")? + .call1((pynum,))? + .to_object(py)) } else if oid == *DELTA_CRL_INDICATOR_OID { let bignum = asn1::parse_single::>(ext_data)?; let pynum = big_asn1_uint_to_py(py, bignum)?; Ok(x509_module - .call1("DeltaCRLIndicator", (pynum,))? + .getattr("DeltaCRLIndicator")? + .call1((pynum,))? .to_object(py)) } else if oid == *ISSUER_ALTERNATIVE_NAME_OID { let gn_seq = asn1::parse_single::>>(ext_data)?; let ians = parse_general_names(py, gn_seq)?; Ok(x509_module - .call1("IssuerAlternativeName", (ians,))? + .getattr("IssuerAlternativeName")? + .call1((ians,))? .to_object(py)) } else if oid == *AUTHORITY_INFORMATION_ACCESS_OID { let ads = parse_access_descriptions(py, ext_data)?; Ok(x509_module - .call1("AuthorityInformationAccess", (ads,))? + .getattr("AuthorityInformationAccess")? + .call1((ads,))? .to_object(py)) } else if oid == *AUTHORITY_KEY_IDENTIFIER_OID { Ok(parse_authority_key_identifier(py, ext_data)?.to_object(py)) @@ -1083,22 +1104,21 @@ fn parse_crl_extension( }; let reasons = parse_distribution_point_reasons(py, idp.only_some_reasons)?; Ok(x509_module - .call1( - "IssuingDistributionPoint", - ( - full_name, - relative_name, - idp.only_contains_user_certs, - idp.only_contains_ca_certs, - reasons, - idp.indirect_crl, - idp.only_contains_attribute_certs, - ), - )? + .getattr("IssuingDistributionPoint")? + .call1(( + full_name, + relative_name, + idp.only_contains_user_certs, + idp.only_contains_ca_certs, + reasons, + idp.indirect_crl, + idp.only_contains_attribute_certs, + ))? .to_object(py)) } else if oid == *FRESHEST_CRL_OID { Ok(x509_module - .call1("FreshestCRL", (parse_distribution_points(py, ext_data)?,))? + .getattr("FreshestCRL")? + .call1((parse_distribution_points(py, ext_data)?,))? .to_object(py)) } else { Ok(py.None()) From cdb79af0ecafadd44f845440646461b6da89e23b Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 8 Jul 2021 22:25:23 -0400 Subject: [PATCH 0245/1456] Silence overly zealous flake8 warning (#6163) --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 1f7debd4ed5a..73ff96785c6a 100644 --- a/tox.ini +++ b/tox.ini @@ -73,7 +73,7 @@ commands = cargo test --no-default-features [flake8] -ignore = E203,E211,W503,W504 +ignore = E203,E211,W503,W504,N818 exclude = .tox,*.egg,.git,_build,.hypothesis select = E,W,F,N,I application-import-names = cryptography,cryptography_vectors,tests From 6150eaaa91f2cdc73437f94f4bb4a8c82865d3c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Jul 2021 08:21:30 -0400 Subject: [PATCH 0246/1456] Bump dessant/lock-threads from 2.0.3 to 2.1.1 (#6168) Bumps [dessant/lock-threads](https://github.com/dessant/lock-threads) from 2.0.3 to 2.1.1. - [Release notes](https://github.com/dessant/lock-threads/releases) - [Changelog](https://github.com/dessant/lock-threads/blob/master/CHANGELOG.md) - [Commits](https://github.com/dessant/lock-threads/compare/v2.0.3...v2.1.1) --- updated-dependencies: - dependency-name: dessant/lock-threads dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/lock.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index cc4bc369a99f..2e19c82c41f5 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -11,7 +11,7 @@ jobs: lock: runs-on: ubuntu-latest steps: - - uses: dessant/lock-threads@v2.0.3 + - uses: dessant/lock-threads@v2.1.1 with: github-token: ${{ secrets.GITHUB_TOKEN }} issue-lock-inactive-days: 90 From f770e453dbf5f307b8cafb19568cd489595f12a6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 14 Jul 2021 19:03:58 -0400 Subject: [PATCH 0247/1456] [hack] see if putting this on one line fixes coverage (#6173) * Attempt to fix coverage by shortening lines * Comment --- .../hazmat/backends/openssl/backend.py | 4 +-- .../hazmat/bindings/_rust/ocsp.pyi | 6 ++-- .../hazmat/bindings/_rust/x509.pyi | 4 +-- src/rust/src/asn1.rs | 7 ++++- src/rust/src/ocsp.rs | 22 +++++---------- src/rust/src/x509.rs | 28 ++++++------------- 6 files changed, 27 insertions(+), 44 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index ab9f2ce80f8b..621a7df53523 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -399,7 +399,7 @@ def _register_x509_ext_parsers(self): self, ext_count=self._lib.X509_REVOKED_get_ext_count, get_ext=self._lib.X509_REVOKED_get_ext, - rust_callback=rust_x509.parse_crl_entry_extension, + rust_callback=rust_x509.parse_crl_entry_ext, ) self._crl_extension_parser = _X509ExtensionParser( self, @@ -417,7 +417,7 @@ def _register_x509_ext_parsers(self): self, ext_count=self._lib.OCSP_SINGLERESP_get_ext_count, get_ext=self._lib.OCSP_SINGLERESP_get_ext, - rust_callback=rust_ocsp.parse_ocsp_singleresp_extension, + rust_callback=rust_ocsp.parse_ocsp_singleresp_ext, ) def _register_x509_encoders(self): diff --git a/src/cryptography/hazmat/bindings/_rust/ocsp.pyi b/src/cryptography/hazmat/bindings/_rust/ocsp.pyi index 14f5eaf88f31..7e318fdace0c 100644 --- a/src/cryptography/hazmat/bindings/_rust/ocsp.pyi +++ b/src/cryptography/hazmat/bindings/_rust/ocsp.pyi @@ -3,8 +3,8 @@ from cryptography.x509.ocsp import OCSPRequest def load_der_ocsp_request(data: bytes) -> OCSPRequest: ... def parse_ocsp_resp_extension( - der_oid: bytes, ext_data: bytes + der_oid: bytes, data: bytes ) -> ExtensionType: ... -def parse_ocsp_singleresp_extension( - der_oid: bytes, ext_data: bytes +def parse_ocsp_singleresp_ext( + der_oid: bytes, data: bytes ) -> ExtensionType: ... diff --git a/src/cryptography/hazmat/bindings/_rust/x509.pyi b/src/cryptography/hazmat/bindings/_rust/x509.pyi index a2ed70282e17..53f99a554797 100644 --- a/src/cryptography/hazmat/bindings/_rust/x509.pyi +++ b/src/cryptography/hazmat/bindings/_rust/x509.pyi @@ -4,9 +4,7 @@ from cryptography.x509 import ( ) def parse_x509_extension(der_oid: bytes, ext_data: bytes) -> ExtensionType: ... -def parse_crl_entry_extension( - der_oid: bytes, ext_data: bytes -) -> ExtensionType: ... +def parse_crl_entry_ext(der_oid: bytes, data: bytes) -> ExtensionType: ... def parse_crl_extension(der_oid: bytes, ext_data: bytes) -> ExtensionType: ... def encode_precertificate_signed_certificate_timestamps( extension: PrecertificateSignedCertificateTimestamps, diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 28f458e49c0c..ac511ab5d6c2 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -5,7 +5,7 @@ use pyo3::class::basic::CompareOp; use pyo3::conversion::ToPyObject; -pub(crate) enum PyAsn1Error { +pub enum PyAsn1Error { Asn1(asn1::ParseError), Py(pyo3::PyErr), } @@ -34,6 +34,11 @@ impl From for pyo3::PyErr { } } +// The primary purpose of this alias is for brevity to keep function signatures +// to a single-line as a work around for coverage issues. See +// https://github.com/pyca/cryptography/pull/6173 +pub(crate) type PyAsn1Result = Result; + #[pyo3::prelude::pyfunction] fn encode_tls_feature(py: pyo3::Python<'_>, ext: &pyo3::PyAny) -> pyo3::PyResult { // Ideally we'd skip building up a vec and just write directly into the diff --git a/src/rust/src/ocsp.rs b/src/rust/src/ocsp.rs index e097aacc852e..97dda1144e3f 100644 --- a/src/rust/src/ocsp.rs +++ b/src/rust/src/ocsp.rs @@ -2,7 +2,7 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::{big_asn1_uint_to_py, PyAsn1Error}; +use crate::asn1::{big_asn1_uint_to_py, PyAsn1Error, PyAsn1Result}; use crate::x509; use pyo3::conversion::ToPyObject; use pyo3::exceptions; @@ -194,11 +194,7 @@ struct CertID<'a> { } #[pyo3::prelude::pyfunction] -fn parse_ocsp_resp_extension( - py: pyo3::Python<'_>, - der_oid: &[u8], - ext_data: &[u8], -) -> pyo3::PyResult { +fn parse_ocsp_resp_extension(py: pyo3::Python<'_>, der_oid: &[u8], data: &[u8]) -> PyAsn1Result { let oid = asn1::ObjectIdentifier::from_der(der_oid).unwrap(); let x509_module = py.import("cryptography.x509")?; @@ -210,7 +206,7 @@ fn parse_ocsp_resp_extension( // the nonce. For now we just implement the old behavior, even though // it's deranged. Ok(x509_module - .call_method1("OCSPNonce", (ext_data,))? + .call_method1("OCSPNonce", (data,))? .to_object(py)) } else { Ok(py.None()) @@ -218,23 +214,19 @@ fn parse_ocsp_resp_extension( } #[pyo3::prelude::pyfunction] -fn parse_ocsp_singleresp_extension( - py: pyo3::Python<'_>, - der_oid: &[u8], - ext_data: &[u8], -) -> Result { +fn parse_ocsp_singleresp_ext(py: pyo3::Python<'_>, der_oid: &[u8], data: &[u8]) -> PyAsn1Result { let oid = asn1::ObjectIdentifier::from_der(der_oid).unwrap(); let x509_module = py.import("cryptography.x509")?; if oid == *SIGNED_CERTIFICATE_TIMESTAMPS_OID { - let contents = asn1::parse_single::<&[u8]>(ext_data)?; + let contents = asn1::parse_single::<&[u8]>(data)?; let scts = x509::parse_scts(py, contents, x509::LogEntryType::Certificate)?; Ok(x509_module .getattr("SignedCertificateTimestamps")? .call1((scts,))? .to_object(py)) } else { - x509::parse_crl_entry_extension(py, der_oid, ext_data) + x509::parse_crl_entry_ext(py, der_oid, data) } } @@ -243,7 +235,7 @@ pub(crate) fn create_submodule(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::pr submod.add_wrapped(pyo3::wrap_pyfunction!(load_der_ocsp_request))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_ocsp_resp_extension))?; - submod.add_wrapped(pyo3::wrap_pyfunction!(parse_ocsp_singleresp_extension))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(parse_ocsp_singleresp_ext))?; Ok(submod) } diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index f23ae7dd7e81..b2ef945ef82a 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -2,7 +2,7 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::{big_asn1_uint_to_py, AttributeTypeValue, Name, PyAsn1Error}; +use crate::asn1::{big_asn1_uint_to_py, AttributeTypeValue, Name, PyAsn1Error, PyAsn1Result}; use chrono::{Datelike, Timelike}; use pyo3::conversion::ToPyObject; use pyo3::types::IntoPyDict; @@ -848,11 +848,7 @@ pub(crate) fn parse_scts( } #[pyo3::prelude::pyfunction] -fn parse_x509_extension( - py: pyo3::Python<'_>, - der_oid: &[u8], - ext_data: &[u8], -) -> Result { +fn parse_x509_extension(py: pyo3::Python<'_>, der_oid: &[u8], ext_data: &[u8]) -> PyAsn1Result { let oid = asn1::ObjectIdentifier::from_der(der_oid).unwrap(); let x509_module = py.import("cryptography.x509")?; @@ -1008,16 +1004,12 @@ fn parse_x509_extension( } #[pyo3::prelude::pyfunction] -pub(crate) fn parse_crl_entry_extension( - py: pyo3::Python<'_>, - der_oid: &[u8], - ext_data: &[u8], -) -> Result { +pub fn parse_crl_entry_ext(py: pyo3::Python<'_>, der_oid: &[u8], data: &[u8]) -> PyAsn1Result { let oid = asn1::ObjectIdentifier::from_der(der_oid).unwrap(); let x509_module = py.import("cryptography.x509")?; if oid == *CRL_REASON_OID { - let flag_name = match asn1::parse_single::(ext_data)?.value() { + let flag_name = match asn1::parse_single::(data)?.value() { 0 => "unspecified", 1 => "key_compromise", 2 => "ca_compromise", @@ -1040,14 +1032,14 @@ pub(crate) fn parse_crl_entry_extension( .call1((flag,))? .to_object(py)) } else if oid == *CERTIFICATE_ISSUER_OID { - let gn_seq = asn1::parse_single::>>(ext_data)?; + let gn_seq = asn1::parse_single::>>(data)?; let gns = parse_general_names(py, gn_seq)?; Ok(x509_module .getattr("CertificateIssuer")? .call1((gns,))? .to_object(py)) } else if oid == *INVALIDITY_DATE_OID { - let time = asn1::parse_single::(ext_data)?; + let time = asn1::parse_single::(data)?; let py_dt = chrono_to_py(py, time.as_chrono())?; Ok(x509_module .getattr("InvalidityDate")? @@ -1059,11 +1051,7 @@ pub(crate) fn parse_crl_entry_extension( } #[pyo3::prelude::pyfunction] -fn parse_crl_extension( - py: pyo3::Python<'_>, - der_oid: &[u8], - ext_data: &[u8], -) -> Result { +fn parse_crl_extension(py: pyo3::Python<'_>, der_oid: &[u8], ext_data: &[u8]) -> PyAsn1Result { let oid = asn1::ObjectIdentifier::from_der(der_oid).unwrap(); let x509_module = py.import("cryptography.x509")?; @@ -1129,7 +1117,7 @@ pub(crate) fn create_submodule(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::pr let submod = pyo3::prelude::PyModule::new(py, "x509")?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_x509_extension))?; - submod.add_wrapped(pyo3::wrap_pyfunction!(parse_crl_entry_extension))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(parse_crl_entry_ext))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_crl_extension))?; submod.add_wrapped(pyo3::wrap_pyfunction!( encode_precertificate_signed_certificate_timestamps From 4baa220d5a6d02f57dcef135338c082e14996922 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Jul 2021 19:29:44 -0400 Subject: [PATCH 0248/1456] Bump ouroboros from 0.9.5 to 0.10.1 in /src/rust (#6172) Bumps [ouroboros](https://github.com/joshua-maros/ouroboros) from 0.9.5 to 0.10.1. - [Release notes](https://github.com/joshua-maros/ouroboros/releases) - [Commits](https://github.com/joshua-maros/ouroboros/commits) --- updated-dependencies: - dependency-name: ouroboros dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 15 +++++++++++---- src/rust/Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 8ebd9ff10d26..4d3d15b5ea6d 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -8,6 +8,12 @@ version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + [[package]] name = "asn1" version = "0.5.3" @@ -148,19 +154,20 @@ checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "ouroboros" -version = "0.9.5" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeff60e3e37407a80ead3e9458145b456e978c4068cddbfea6afb48572962ca" +checksum = "84236d64f1718c387232287cf036eb6632a5ecff226f4ff9dccb8c2b79ba0bde" dependencies = [ + "aliasable", "ouroboros_macro", "stable_deref_trait", ] [[package]] name = "ouroboros_macro" -version = "0.9.5" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03f2cb802b5bdfdf52f1ffa0b54ce105e4d346e91990dd571f86c91321ad49e2" +checksum = "f463857a6eb96c0136b1d56e56c718350cef30412ec065b48294799a088bca68" dependencies = [ "Inflector", "proc-macro-error", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index f402456859ea..0d0f66f26f53 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -10,7 +10,7 @@ lazy_static = "1" pyo3 = { version = "0.14.1" } asn1 = { version = "0.5.3", default-features = false, features = ["derive"] } chrono = { version = "0.4", default-features = false, features = ["alloc"] } -ouroboros = "0.9" +ouroboros = "0.10" [features] extension-module = ["pyo3/extension-module"] From 646d8ee99b45c3b2d28d5f281024521f8b6784c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Jul 2021 19:31:08 -0400 Subject: [PATCH 0249/1456] Bump libc from 0.2.97 to 0.2.98 in /src/rust (#6162) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.97 to 0.2.98. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.97...0.2.98) --- updated-dependencies: - dependency-name: libc dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 4d3d15b5ea6d..2d6a2bd40aee 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -114,9 +114,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.97" +version = "0.2.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" +checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" [[package]] name = "lock_api" From 69f9a412de436e2e7a0520bade56751ca5cbe47a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Jul 2021 19:53:27 -0400 Subject: [PATCH 0250/1456] Bump instant from 0.1.9 to 0.1.10 in /src/rust (#6170) Bumps [instant](https://github.com/sebcrozet/instant) from 0.1.9 to 0.1.10. - [Release notes](https://github.com/sebcrozet/instant/releases) - [Commits](https://github.com/sebcrozet/instant/commits) --- updated-dependencies: - dependency-name: instant dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 2d6a2bd40aee..6f9af66f872d 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -99,9 +99,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" dependencies = [ "cfg-if", ] From b681f3cbe96784a97b84a26c10db89e4dc742d35 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 17 Jul 2021 11:31:40 -0400 Subject: [PATCH 0251/1456] Bump to rust-asn1 0.6.0 (#6175) --- src/rust/Cargo.lock | 8 ++++---- src/rust/Cargo.toml | 2 +- src/rust/src/x509.rs | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 6f9af66f872d..973d86535114 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -16,9 +16,9 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" [[package]] name = "asn1" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f56417796de18d5398ee1ba4058d061a9be1bcfdef9a46f73e96e94f5bb21e0" +checksum = "9680a48fea09cb1af33dc233179b9723674ca43ad9e5c9d01ab6ad1c3c58c0dc" dependencies = [ "asn1_derive", "chrono", @@ -26,9 +26,9 @@ dependencies = [ [[package]] name = "asn1_derive" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be3a3360bd6e363428f7ce00ccd251efcd2639b6942ab22e5f322a452aa6f079" +checksum = "f828598cd99548327735aae5db2852e3d78d1508ed81543f204b8ca3cf3ba859" dependencies = [ "proc-macro2", "quote", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 0d0f66f26f53..df187bfa4e2b 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] lazy_static = "1" pyo3 = { version = "0.14.1" } -asn1 = { version = "0.5.3", default-features = false, features = ["derive"] } +asn1 = { version = "0.6", default-features = false, features = ["derive"] } chrono = { version = "0.4", default-features = false, features = ["alloc"] } ouroboros = "0.10" diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index b2ef945ef82a..0dae8b72706a 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -255,9 +255,9 @@ struct UnvalidatedIA5String<'a>(&'a str); impl<'a> asn1::SimpleAsn1Readable<'a> for UnvalidatedIA5String<'a> { const TAG: u8 = 0x16; fn parse_data(data: &'a [u8]) -> asn1::ParseResult { - Ok(UnvalidatedIA5String( - std::str::from_utf8(data).map_err(|_| asn1::ParseError::InvalidValue)?, - )) + Ok(UnvalidatedIA5String(std::str::from_utf8(data).map_err( + |_| asn1::ParseError::new(asn1::ParseErrorKind::InvalidValue), + )?)) } } @@ -500,8 +500,8 @@ fn parse_name_attribute( .import("cryptography.x509.name")? .getattr("_ASN1_TYPE_TO_ENUM")?; let py_tag = tag_enum.get_item(attribute.value.tag().to_object(py))?; - let py_data = - std::str::from_utf8(attribute.value.data()).map_err(|_| asn1::ParseError::InvalidValue)?; + let py_data = std::str::from_utf8(attribute.value.data()) + .map_err(|_| asn1::ParseError::new(asn1::ParseErrorKind::InvalidValue))?; Ok(x509_module .call_method1("NameAttribute", (oid, py_data, py_tag))? .to_object(py)) From d20e4a67045edb5e0b1289c12ad93293779919b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Jul 2021 09:27:52 -0400 Subject: [PATCH 0252/1456] Bump syn from 1.0.73 to 1.0.74 in /src/rust (#6176) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.73 to 1.0.74. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.73...1.0.74) --- updated-dependencies: - dependency-name: syn dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 973d86535114..8241c803f9b6 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -345,9 +345,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "1.0.73" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" +checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" dependencies = [ "proc-macro2", "quote", From 603018110973ded97cd586b55901fabf59101c1c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Jul 2021 21:23:59 -0400 Subject: [PATCH 0253/1456] Bump proc-macro2 from 1.0.27 to 1.0.28 in /src/rust (#6177) Bumps [proc-macro2](https://github.com/alexcrichton/proc-macro2) from 1.0.27 to 1.0.28. - [Release notes](https://github.com/alexcrichton/proc-macro2/releases) - [Commits](https://github.com/alexcrichton/proc-macro2/compare/1.0.27...1.0.28) --- updated-dependencies: - dependency-name: proc-macro2 dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 8241c803f9b6..aa62697a09cb 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -252,9 +252,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" dependencies = [ "unicode-xid", ] From 87f43fb77e7f1c56471d3233a56000a51dc4a311 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 25 Jul 2021 15:03:14 -0700 Subject: [PATCH 0254/1456] parse certificates with pure rust (#6147) * parse certificates with pure rust * fix coverage * various review comments * save the buffer * more feedback --- CHANGELOG.rst | 7 + docs/hazmat/backends/interfaces.rst | 12 - .../hazmat/backends/interfaces.py | 12 - .../hazmat/backends/openssl/backend.py | 96 ++-- .../hazmat/backends/openssl/decode_asn1.py | 6 +- .../hazmat/backends/openssl/ocsp.py | 7 +- .../hazmat/backends/openssl/x509.py | 149 +---- .../hazmat/bindings/_rust/x509.pyi | 23 +- src/cryptography/utils.py | 1 + src/cryptography/x509/base.py | 17 +- src/rust/Cargo.lock | 33 ++ src/rust/Cargo.toml | 1 + src/rust/src/asn1.rs | 18 +- src/rust/src/x509.rs | 515 +++++++++++++++++- tests/hazmat/backends/test_openssl.py | 42 +- tests/hazmat/primitives/test_pkcs7.py | 6 +- tests/x509/test_x509.py | 86 ++- 17 files changed, 730 insertions(+), 301 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6760ba76979e..429b3af61e8b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,13 @@ Changelog * Changed the :ref:`version scheme `. This will result in us incrementing the major version more frequently, but does not change our existing backwards compatibility policy. +* **BACKWARDS INCOMPATIBLE:** The X.509 certificate parser no longer allows + negative serial numbers. :rfc:`5280` has always prohibited these. +* **BACKWARDS INCOMPATIBLE:** Invalid ASN.1 found during certificate parsing + will raise an error on initial parse rather than when the invalid field is + accessed. +* **BACKWARDS INCOMPATIBLE:** Values passed to the X.509 PEM parser must be + a single PEM payload and will error on extraneous data. * Added support for :class:`~cryptography.hazmat.primitives.hashes.SM3` and :class:`~cryptography.hazmat.primitives.ciphers.algorithms.SM4`, diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst index 36dd3a7a5a1e..664710181eef 100644 --- a/docs/hazmat/backends/interfaces.rst +++ b/docs/hazmat/backends/interfaces.rst @@ -500,18 +500,6 @@ A specific ``backend`` may provide one or more of these interfaces. A backend with methods for working with X.509 objects. - .. method:: load_pem_x509_certificate(data) - - :param bytes data: PEM formatted certificate data. - - :returns: An instance of :class:`~cryptography.x509.Certificate`. - - .. method:: load_der_x509_certificate(data) - - :param bytes data: DER formatted certificate data. - - :returns: An instance of :class:`~cryptography.x509.Certificate`. - .. method:: load_pem_x509_csr(data) .. versionadded:: 0.9 diff --git a/src/cryptography/hazmat/backends/interfaces.py b/src/cryptography/hazmat/backends/interfaces.py index 2aeee4927b3d..4b2d80a7770a 100644 --- a/src/cryptography/hazmat/backends/interfaces.py +++ b/src/cryptography/hazmat/backends/interfaces.py @@ -280,18 +280,6 @@ def load_der_parameters(self, data): class X509Backend(metaclass=abc.ABCMeta): - @abc.abstractmethod - def load_pem_x509_certificate(self, data: bytes) -> "Certificate": - """ - Load an X.509 certificate from PEM encoded data. - """ - - @abc.abstractmethod - def load_der_x509_certificate(self, data: bytes) -> "Certificate": - """ - Load an X.509 certificate from DER encoded data. - """ - @abc.abstractmethod def load_der_x509_csr(self, data: bytes) -> "CertificateSigningRequest": """ diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 621a7df53523..349205b13340 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -75,7 +75,6 @@ _X448PublicKey, ) from cryptography.hazmat.backends.openssl.x509 import ( - _Certificate, _CertificateRevocationList, _CertificateSigningRequest, _RevokedCertificate, @@ -383,17 +382,11 @@ def _register_default_ciphers(self): ) def _register_x509_ext_parsers(self): - self._certificate_extension_parser = _X509ExtensionParser( - self, - ext_count=self._lib.X509_get_ext_count, - get_ext=self._lib.X509_get_ext, - rust_callback=rust_x509.parse_x509_extension, - ) self._csr_extension_parser = _X509ExtensionParser( self, ext_count=self._lib.sk_X509_EXTENSION_num, get_ext=self._lib.sk_X509_EXTENSION_value, - rust_callback=rust_x509.parse_x509_extension, + rust_callback=rust_x509.parse_csr_extension, ) self._revoked_cert_extension_parser = _X509ExtensionParser( self, @@ -471,6 +464,7 @@ def _consume_errors_with_text(self): def _bn_to_int(self, bn): assert bn != self._ffi.NULL + self.openssl_assert(not self._lib.BN_is_negative(bn)) bn_num_bytes = self._lib.BN_num_bytes(bn) bin_ptr = self._ffi.new("unsigned char[]", bn_num_bytes) @@ -478,8 +472,6 @@ def _bn_to_int(self, bn): # A zero length means the BN has value 0 self.openssl_assert(bin_len >= 0) val = int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big") - if self._lib.BN_is_negative(bn): - val = -val return val def _int_to_bn(self, num, bn=None): @@ -957,7 +949,7 @@ def create_x509_certificate( builder: x509.CertificateBuilder, private_key: PRIVATE_KEY_TYPES, algorithm: typing.Optional[hashes.HashAlgorithm], - ) -> _Certificate: + ) -> x509.Certificate: if not isinstance(builder, x509.CertificateBuilder): raise TypeError("Builder type mismatch.") if builder._public_key is None: @@ -1028,7 +1020,7 @@ def create_x509_certificate( errors = self._consume_errors_with_text() raise ValueError("Signing failed", errors) - return _Certificate(self, x509_cert) + return self._ossl2cert(x509_cert) def _evp_md_x509_null_if_eddsa(self, private_key, algorithm): if isinstance( @@ -1333,31 +1325,19 @@ def load_der_parameters(self, data): self._handle_key_loading_error() - def load_pem_x509_certificate(self, data: bytes) -> _Certificate: - mem_bio = self._bytes_to_bio(data) - x509 = self._lib.PEM_read_bio_X509( - mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL - ) - if x509 == self._ffi.NULL: - self._consume_errors() - raise ValueError( - "Unable to load certificate. See https://cryptography.io/en/" - "latest/faq.html#why-can-t-i-import-my-pem-file for more" - " details." - ) - - x509 = self._ffi.gc(x509, self._lib.X509_free) - return _Certificate(self, x509) - - def load_der_x509_certificate(self, data: bytes) -> _Certificate: + def _cert2ossl(self, cert: x509.Certificate) -> typing.Any: + data = cert.public_bytes(serialization.Encoding.DER) mem_bio = self._bytes_to_bio(data) x509 = self._lib.d2i_X509_bio(mem_bio.bio, self._ffi.NULL) - if x509 == self._ffi.NULL: - self._consume_errors() - raise ValueError("Unable to load certificate") - + self.openssl_assert(x509 != self._ffi.NULL) x509 = self._ffi.gc(x509, self._lib.X509_free) - return _Certificate(self, x509) + return x509 + + def _ossl2cert(self, x509: typing.Any) -> x509.Certificate: + bio = self._create_mem_bio_gc() + res = self._lib.i2d_X509_bio(bio, x509) + self.openssl_assert(res == 1) + return rust_x509.load_der_x509_certificate(self._read_mem_bio(bio)) def load_pem_x509_crl(self, data: bytes) -> _CertificateRevocationList: mem_bio = self._bytes_to_bio(data) @@ -1661,7 +1641,9 @@ def create_ocsp_request(self, builder): 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) + ossl_cert = self._cert2ossl(cert) + ossl_issuer = self._cert2ossl(issuer) + certid = self._lib.OCSP_cert_to_id(evp_md, ossl_cert, ossl_issuer) self.openssl_assert(certid != self._ffi.NULL) onereq = self._lib.OCSP_request_add0_id(ocsp_req, certid) self.openssl_assert(onereq != self._ffi.NULL) @@ -1687,10 +1669,12 @@ def _create_ocsp_basic_response(self, builder, private_key, algorithm): evp_md = self._evp_md_non_null_from_algorithm( builder._response._algorithm ) + ossl_cert = self._cert2ossl(builder._response._cert) + ossl_issuer = self._cert2ossl(builder._response._issuer) certid = self._lib.OCSP_cert_to_id( evp_md, - builder._response._cert._x509, - builder._response._issuer._x509, + ossl_cert, + ossl_issuer, ) self.openssl_assert(certid != self._ffi.NULL) certid = self._ffi.gc(certid, self._lib.OCSP_CERTID_free) @@ -1732,9 +1716,13 @@ def _create_ocsp_basic_response(self, builder, private_key, algorithm): if responder_encoding is ocsp.OCSPResponderEncoding.HASH: flags |= self._lib.OCSP_RESPID_KEY + # This list is to keep the x509 values alive until end of function + ossl_certs = [] if builder._certs is not None: for cert in builder._certs: - res = self._lib.OCSP_basic_add1_cert(basic, cert._x509) + ossl_cert = self._cert2ossl(cert) + ossl_certs.append(ossl_cert) + res = self._lib.OCSP_basic_add1_cert(basic, ossl_cert) self.openssl_assert(res == 1) self._create_x509_extensions( @@ -1745,9 +1733,10 @@ def _create_ocsp_basic_response(self, builder, private_key, algorithm): gc=True, ) + ossl_cert = self._cert2ossl(responder_cert) res = self._lib.OCSP_basic_sign( basic, - responder_cert._x509, + ossl_cert, private_key._evp_pkey, evp_md, self._ffi.NULL, @@ -2523,7 +2512,7 @@ def load_key_and_certificates_from_pkcs12(self, data, password): if x509_ptr[0] != self._ffi.NULL: x509 = self._ffi.gc(x509_ptr[0], self._lib.X509_free) - cert = _Certificate(self, x509) + cert = self._ossl2cert(x509) if sk_x509_ptr[0] != self._ffi.NULL: sk_x509 = self._ffi.gc(sk_x509_ptr[0], self._lib.sk_X509_free) @@ -2541,7 +2530,8 @@ def load_key_and_certificates_from_pkcs12(self, data, password): x509 = self._lib.sk_X509_value(sk_x509, i) self.openssl_assert(x509 != self._ffi.NULL) x509 = self._ffi.gc(x509, self._lib.X509_free) - additional_certificates.append(_Certificate(self, x509)) + addl_cert = self._ossl2cert(x509) + additional_certificates.append(addl_cert) return (key, cert, additional_certificates) @@ -2580,17 +2570,23 @@ def serialize_key_and_certificates_to_pkcs12( sk_x509 = self._lib.sk_X509_new_null() sk_x509 = self._ffi.gc(sk_x509, self._lib.sk_X509_free) + # This list is to keep the x509 values alive until end of function + ossl_cas = [] for ca in cas: - res = self._lib.sk_X509_push(sk_x509, ca._x509) + ossl_ca = self._cert2ossl(ca) + ossl_cas.append(ossl_ca) + res = self._lib.sk_X509_push(sk_x509, ossl_ca) backend.openssl_assert(res >= 1) with self._zeroed_null_terminated_buf(password) as password_buf: with self._zeroed_null_terminated_buf(name) as name_buf: + ossl_cert = self._cert2ossl(cert) if cert else self._ffi.NULL + evp_pkey = key._evp_pkey if key else self._ffi.NULL p12 = self._lib.PKCS12_create( password_buf, name_buf, - key._evp_pkey if key else self._ffi.NULL, - cert._x509 if cert else self._ffi.NULL, + evp_pkey, + ossl_cert, sk_x509, nid_key, nid_cert, @@ -2664,7 +2660,8 @@ def _load_pkcs7_certificates(self, p7): # refcount. On 1.1.0+ it returns 1 for success. self.openssl_assert(res >= 1) x509 = self._ffi.gc(x509, self._lib.X509_free) - certs.append(_Certificate(self, x509)) + cert = self._ossl2cert(x509) + certs.append(cert) return certs @@ -2678,8 +2675,12 @@ def pkcs7_sign(self, builder, encoding, options): else: certs = self._lib.sk_X509_new_null() certs = self._ffi.gc(certs, self._lib.sk_X509_free) + # This list is to keep the x509 values alive until end of function + ossl_certs = [] for cert in builder._additional_certs: - res = self._lib.sk_X509_push(certs, cert._x509) + ossl_cert = self._cert2ossl(cert) + ossl_certs.append(ossl_cert) + res = self._lib.sk_X509_push(certs, ossl_cert) self.openssl_assert(res >= 1) if pkcs7.PKCS7Options.DetachedSignature in options: @@ -2711,9 +2712,10 @@ def pkcs7_sign(self, builder, encoding, options): signer_flags |= self._lib.PKCS7_NOCERTS for certificate, private_key, hash_algorithm in builder._signers: + ossl_cert = self._cert2ossl(certificate) md = self._evp_md_non_null_from_algorithm(hash_algorithm) p7signerinfo = self._lib.PKCS7_sign_add_signer( - p7, certificate._x509, private_key._evp_pkey, md, signer_flags + p7, ossl_cert, private_key._evp_pkey, md, signer_flags ) self.openssl_assert(p7signerinfo != self._ffi.NULL) diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 228d3e008392..8e648eba6685 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -169,11 +169,7 @@ def _asn1_string_to_ascii(backend, asn1_string): def _asn1_string_to_utf8(backend, asn1_string) -> str: buf = backend._ffi.new("unsigned char **") res = backend._lib.ASN1_STRING_to_UTF8(buf, asn1_string) - if res == -1: - raise ValueError( - "Unsupported ASN1 string type. Type: {}".format(asn1_string.type) - ) - + backend.openssl_assert(res >= 0) backend.openssl_assert(buf[0] != backend._ffi.NULL) buf = backend._ffi.gc( buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0]) diff --git a/src/cryptography/hazmat/backends/openssl/ocsp.py b/src/cryptography/hazmat/backends/openssl/ocsp.py index 6ef9316e975e..c69be3123c5e 100644 --- a/src/cryptography/hazmat/backends/openssl/ocsp.py +++ b/src/cryptography/hazmat/backends/openssl/ocsp.py @@ -15,7 +15,6 @@ _obj2txt, _parse_asn1_generalized_time, ) -from cryptography.hazmat.backends.openssl.x509 import _Certificate from cryptography.hazmat.primitives import hashes, serialization from cryptography.x509.ocsp import ( OCSPCertStatus, @@ -178,11 +177,7 @@ def certificates(self) -> typing.List[x509.Certificate]: for i in range(num): x509_ptr = self._backend._lib.sk_X509_value(sk_x509, i) self._backend.openssl_assert(x509_ptr != self._backend._ffi.NULL) - cert = _Certificate(self._backend, x509_ptr) - # 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_ref = self + cert = self._backend._ossl2cert(x509_ptr) certs.append(cert) return certs diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index edbc7c6d5f0c..d2017efdf559 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -6,6 +6,7 @@ import datetime import operator import typing +import warnings from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm @@ -26,145 +27,15 @@ from cryptography.x509.name import _ASN1Type -class _Certificate(x509.Certificate): - # Keep-alive reference used by OCSP - _ocsp_resp_ref: typing.Any - - def __init__(self, backend, x509_cert): - self._backend = backend - self._x509 = x509_cert - - version = self._backend._lib.X509_get_version(self._x509) - if version == 0: - self._version = x509.Version.v1 - elif version == 2: - self._version = x509.Version.v3 - else: - raise x509.InvalidVersion( - "{} is not a valid X509 version".format(version), version - ) - - def __repr__(self): - return "".format(self.subject) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, _Certificate): - return NotImplemented - - res = self._backend._lib.X509_cmp(self._x509, other._x509) - return res == 0 - - def __ne__(self, other: object) -> bool: - return not self == other - - def __hash__(self) -> int: - return hash(self.public_bytes(serialization.Encoding.DER)) - - def __deepcopy__(self, memo): - return self - - def fingerprint(self, algorithm: hashes.HashAlgorithm) -> bytes: - h = hashes.Hash(algorithm, self._backend) - h.update(self.public_bytes(serialization.Encoding.DER)) - return h.finalize() - - version = utils.read_only_property("_version") - - @property - def serial_number(self) -> int: - asn1_int = self._backend._lib.X509_get_serialNumber(self._x509) - self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL) - return _asn1_integer_to_int(self._backend, asn1_int) - - def public_key(self) -> PUBLIC_KEY_TYPES: - pkey = self._backend._lib.X509_get_pubkey(self._x509) - if pkey == self._backend._ffi.NULL: - # Remove errors from the stack. - self._backend._consume_errors() - raise ValueError("Certificate public key is of an unknown type") - - pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free) - - return self._backend._evp_pkey_to_public_key(pkey) - - @property - def not_valid_before(self) -> datetime.datetime: - asn1_time = self._backend._lib.X509_get0_notBefore(self._x509) - return _parse_asn1_time(self._backend, asn1_time) - - @property - def not_valid_after(self) -> datetime.datetime: - asn1_time = self._backend._lib.X509_get0_notAfter(self._x509) - return _parse_asn1_time(self._backend, asn1_time) - - @property - def issuer(self) -> x509.Name: - issuer = self._backend._lib.X509_get_issuer_name(self._x509) - self._backend.openssl_assert(issuer != self._backend._ffi.NULL) - return _decode_x509_name(self._backend, issuer) - - @property - def subject(self) -> x509.Name: - subject = self._backend._lib.X509_get_subject_name(self._x509) - self._backend.openssl_assert(subject != self._backend._ffi.NULL) - return _decode_x509_name(self._backend, subject) - - @property - def signature_hash_algorithm( - self, - ) -> typing.Optional[hashes.HashAlgorithm]: - 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 - def signature_algorithm_oid(self) -> x509.ObjectIdentifier: - alg = self._backend._ffi.new("X509_ALGOR **") - self._backend._lib.X509_get0_signature( - self._backend._ffi.NULL, alg, self._x509 - ) - self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) - oid = _obj2txt(self._backend, alg[0].algorithm) - return x509.ObjectIdentifier(oid) - - @utils.cached_property - def extensions(self) -> x509.Extensions: - return self._backend._certificate_extension_parser.parse(self._x509) - - @property - def signature(self) -> bytes: - sig = self._backend._ffi.new("ASN1_BIT_STRING **") - self._backend._lib.X509_get0_signature( - sig, self._backend._ffi.NULL, self._x509 - ) - self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL) - return _asn1_string_to_bytes(self._backend, sig[0]) - - @property - def tbs_certificate_bytes(self) -> bytes: - pp = self._backend._ffi.new("unsigned char **") - res = self._backend._lib.i2d_re_X509_tbs(self._x509, pp) - self._backend.openssl_assert(res > 0) - pp = self._backend._ffi.gc( - pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0]) - ) - return self._backend._ffi.buffer(pp[0], res)[:] - - def public_bytes(self, encoding: serialization.Encoding) -> bytes: - bio = self._backend._create_mem_bio_gc() - if encoding is serialization.Encoding.PEM: - res = self._backend._lib.PEM_write_bio_X509(bio, self._x509) - elif encoding is serialization.Encoding.DER: - res = self._backend._lib.i2d_X509_bio(bio, self._x509) - else: - raise TypeError("encoding must be an item from the Encoding enum") - - self._backend.openssl_assert(res == 1) - return self._backend._read_mem_bio(bio) +# This exists for pyOpenSSL compatibility and SHOULD NOT BE USED +# WE WILL REMOVE THIS VERY SOON. +def _Certificate(backend, x509) -> x509.Certificate: # noqa: N802 + warnings.warn( + "This version of cryptography contains a temporary pyOpenSSL " + "fallback path. Upgrade pyOpenSSL now.", + utils.DeprecatedIn35, + ) + return backend._ossl2cert(x509) class _RevokedCertificate(x509.RevokedCertificate): diff --git a/src/cryptography/hazmat/bindings/_rust/x509.pyi b/src/cryptography/hazmat/bindings/_rust/x509.pyi index 53f99a554797..9c334441fb96 100644 --- a/src/cryptography/hazmat/bindings/_rust/x509.pyi +++ b/src/cryptography/hazmat/bindings/_rust/x509.pyi @@ -1,13 +1,20 @@ -from cryptography.x509 import ( - ExtensionType, - PrecertificateSignedCertificateTimestamps, -) +import datetime +import typing -def parse_x509_extension(der_oid: bytes, ext_data: bytes) -> ExtensionType: ... -def parse_crl_entry_ext(der_oid: bytes, data: bytes) -> ExtensionType: ... -def parse_crl_extension(der_oid: bytes, ext_data: bytes) -> ExtensionType: ... +from cryptography import x509 + +def parse_csr_extension( + der_oid: bytes, ext_data: bytes +) -> x509.ExtensionType: ... +def parse_crl_entry_ext(der_oid: bytes, data: bytes) -> x509.ExtensionType: ... +def parse_crl_extension( + der_oid: bytes, ext_data: bytes +) -> x509.ExtensionType: ... +def load_pem_x509_certificate(data: bytes) -> x509.Certificate: ... +def load_der_x509_certificate(data: bytes) -> x509.Certificate: ... def encode_precertificate_signed_certificate_timestamps( - extension: PrecertificateSignedCertificateTimestamps, + extension: x509.PrecertificateSignedCertificateTimestamps, ) -> bytes: ... class Sct: ... +class Certificate: ... diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index 8611d95c8e74..3cfd32e98855 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -23,6 +23,7 @@ class CryptographyDeprecationWarning(UserWarning): PersistentlyDeprecated2017 = CryptographyDeprecationWarning PersistentlyDeprecated2019 = CryptographyDeprecationWarning DeprecatedIn34 = CryptographyDeprecationWarning +DeprecatedIn35 = CryptographyDeprecationWarning def _check_bytes(name: str, value: bytes) -> None: diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index 4e8b4a844a41..3c626efc57cf 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -11,6 +11,7 @@ from cryptography import utils from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import Backend +from cryptography.hazmat.bindings._rust import x509 as rust_x509 from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ( dsa, @@ -189,6 +190,10 @@ def public_bytes(self, encoding: serialization.Encoding) -> bytes: """ +# Runtime isinstance checks need this since the rust class is not a subclass. +Certificate.register(rust_x509.Certificate) + + class RevokedCertificate(metaclass=abc.ABCMeta): @abc.abstractproperty def serial_number(self) -> int: @@ -413,18 +418,18 @@ def get_attribute_for_oid(self, oid: ObjectIdentifier) -> bytes: """ +# Backend argument preserved for API compatibility, but ignored. def load_pem_x509_certificate( - data: bytes, backend: typing.Optional[Backend] = None + data: bytes, backend: typing.Any = None ) -> Certificate: - backend = _get_backend(backend) - return backend.load_pem_x509_certificate(data) + return rust_x509.load_pem_x509_certificate(data) +# Backend argument preserved for API compatibility, but ignored. def load_der_x509_certificate( - data: bytes, backend: typing.Optional[Backend] = None + data: bytes, backend: typing.Any = None ) -> Certificate: - backend = _get_backend(backend) - return backend.load_der_x509_certificate(data) + return rust_x509.load_der_x509_certificate(data) def load_pem_x509_csr( diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index aa62697a09cb..9efe36c6bf65 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -41,6 +41,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + [[package]] name = "bitflags" version = "1.2.1" @@ -71,6 +77,7 @@ dependencies = [ "chrono", "lazy_static", "ouroboros", + "pem", "pyo3", ] @@ -220,6 +227,17 @@ dependencies = [ "proc-macro-hack", ] +[[package]] +name = "pem" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb" +dependencies = [ + "base64", + "once_cell", + "regex", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -325,6 +343,21 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + [[package]] name = "scopeguard" version = "1.1.0" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index df187bfa4e2b..aa4331ce96e3 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -9,6 +9,7 @@ publish = false lazy_static = "1" pyo3 = { version = "0.14.1" } asn1 = { version = "0.6", default-features = false, features = ["derive"] } +pem = "0.8" chrono = { version = "0.4", default-features = false, features = ["alloc"] } ouroboros = "0.10" diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index ac511ab5d6c2..f9a1e05ad546 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -2,6 +2,7 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. +use crate::x509::Name; use pyo3::class::basic::CompareOp; use pyo3::conversion::ToPyObject; @@ -22,6 +23,15 @@ impl From for PyAsn1Error { } } +impl From for PyAsn1Error { + fn from(e: pem::PemError) -> PyAsn1Error { + PyAsn1Error::Py(pyo3::exceptions::PyValueError::new_err(format!( + "Unable to load PEM file. See https://cryptography.io/en/latest/faq.html#why-can-t-i-import-my-pem-file for more details. {:?}", + e + ))) + } +} + impl From for pyo3::PyErr { fn from(e: PyAsn1Error) -> pyo3::PyErr { match e { @@ -178,14 +188,6 @@ struct TbsCertificate<'a> { _extensions: Option>, } -pub(crate) type Name<'a> = asn1::SequenceOf<'a, asn1::SetOf<'a, AttributeTypeValue<'a>>>; - -#[derive(asn1::Asn1Read)] -pub(crate) struct AttributeTypeValue<'a> { - pub(crate) type_id: asn1::ObjectIdentifier<'a>, - pub(crate) value: asn1::Tlv<'a>, -} - #[derive(asn1::Asn1Read)] struct Validity<'a> { not_before: asn1::Tlv<'a>, diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index 0dae8b72706a..cbc8b2c359c6 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -2,7 +2,7 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::{big_asn1_uint_to_py, AttributeTypeValue, Name, PyAsn1Error, PyAsn1Result}; +use crate::asn1::{big_asn1_uint_to_py, PyAsn1Error, PyAsn1Result}; use chrono::{Datelike, Timelike}; use pyo3::conversion::ToPyObject; use pyo3::types::IntoPyDict; @@ -43,6 +43,502 @@ lazy_static::lazy_static! { static ref CP_USER_NOTICE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.2.2").unwrap(); } +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +struct RawCertificate<'a> { + tbs_cert: TbsCertificate<'a>, + signature_alg: AlgorithmIdentifier<'a>, + signature: asn1::BitString<'a>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +struct TbsCertificate<'a> { + #[explicit(0)] + #[default(0)] + version: u8, + serial: asn1::BigUint<'a>, + _signature_alg: asn1::Sequence<'a>, + + issuer: Name<'a>, + validity: Validity, + subject: Name<'a>, + + spki: asn1::Sequence<'a>, + #[implicit(1)] + _issuer_unique_id: Option>, + #[implicit(2)] + _subject_unique_id: Option>, + #[explicit(3)] + extensions: Option>, +} + +pub(crate) type Name<'a> = asn1::SequenceOf<'a, asn1::SetOf<'a, AttributeTypeValue<'a>>>; + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub(crate) struct AttributeTypeValue<'a> { + pub(crate) type_id: asn1::ObjectIdentifier<'a>, + pub(crate) value: asn1::Tlv<'a>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +enum Time { + UtcTime(asn1::UtcTime), + GeneralizedTime(asn1::GeneralizedTime), +} + +impl Time { + fn as_chrono(&self) -> &chrono::DateTime { + match self { + Time::UtcTime(data) => data.as_chrono(), + Time::GeneralizedTime(data) => data.as_chrono(), + } + } +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub(crate) struct Validity { + not_before: Time, + not_after: Time, +} + +#[ouroboros::self_referencing] +struct OwnedRawCertificate { + data: Vec, + #[borrows(data)] + #[covariant] + value: RawCertificate<'this>, +} + +#[pyo3::prelude::pyclass] +struct Certificate { + raw: OwnedRawCertificate, + cached_extensions: Option, +} + +#[pyo3::prelude::pyproto] +impl pyo3::class::basic::PyObjectProtocol for Certificate { + fn __hash__(&self) -> u64 { + let mut hasher = DefaultHasher::new(); + self.raw.borrow_data().hash(&mut hasher); + hasher.finish() + } + + fn __richcmp__( + &self, + other: pyo3::pycell::PyRef, + op: pyo3::class::basic::CompareOp, + ) -> pyo3::PyResult { + match op { + pyo3::class::basic::CompareOp::Eq => { + Ok(self.raw.borrow_data() == other.raw.borrow_data()) + } + pyo3::class::basic::CompareOp::Ne => { + Ok(self.raw.borrow_data() != other.raw.borrow_data()) + } + _ => Err(pyo3::exceptions::PyTypeError::new_err( + "Certificates cannot be ordered", + )), + } + } + + fn __repr__(&self) -> pyo3::PyResult { + let mut repr = String::from(", + _memo: pyo3::PyObject, + ) -> pyo3::pycell::PyRef<'_, Self> { + slf + } + + fn public_key<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { + // This makes an unnecessary copy. It'd be nice to get rid of it. + let serialized = pyo3::types::PyBytes::new( + py, + &asn1::write_single(&self.raw.borrow_value().tbs_cert.spki), + ); + py.import("cryptography.hazmat.primitives.serialization")? + .getattr("load_der_public_key")? + .call1((serialized,)) + } + + fn fingerprint<'p>( + &self, + py: pyo3::Python<'p>, + algorithm: pyo3::PyObject, + ) -> pyo3::PyResult<&'p pyo3::PyAny> { + let hasher = py + .import("cryptography.hazmat.primitives.hashes")? + .getattr("Hash")? + .call1((algorithm,))?; + // This makes an unnecessary copy. It'd be nice to get rid of it. + let serialized = + pyo3::types::PyBytes::new(py, &asn1::write_single(&self.raw.borrow_value())); + hasher.call_method1("update", (serialized,))?; + hasher.call_method0("finalize") + } + + fn public_bytes<'p>( + &self, + py: pyo3::Python<'p>, + encoding: &pyo3::PyAny, + ) -> pyo3::PyResult<&'p pyo3::types::PyBytes> { + let encoding_class = py + .import("cryptography.hazmat.primitives.serialization")? + .getattr("Encoding")?; + + let result = asn1::write_single(self.raw.borrow_value()); + if encoding == encoding_class.getattr("DER")? { + Ok(pyo3::types::PyBytes::new(py, &result)) + } else if encoding == encoding_class.getattr("PEM")? { + let pem = pem::encode_config( + &pem::Pem { + tag: "CERTIFICATE".to_string(), + contents: result, + }, + pem::EncodeConfig { + line_ending: pem::LineEnding::LF, + }, + ) + .into_bytes(); + Ok(pyo3::types::PyBytes::new(py, &pem)) + } else { + Err(pyo3::exceptions::PyTypeError::new_err( + "encoding must be an item from the Encoding enum", + )) + } + } + + #[getter] + fn serial_number<'p>(&self, py: pyo3::Python<'p>) -> Result<&'p pyo3::PyAny, PyAsn1Error> { + Ok(big_asn1_uint_to_py( + py, + self.raw.borrow_value().tbs_cert.serial, + )?) + } + + #[getter] + fn version<'p>(&self, py: pyo3::Python<'p>) -> Result<&'p pyo3::PyAny, PyAsn1Error> { + let version = &self.raw.borrow_value().tbs_cert.version; + cert_version(py, *version) + } + + #[getter] + fn issuer<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { + parse_name(py, &self.raw.borrow_value().tbs_cert.issuer) + } + + #[getter] + fn subject<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { + parse_name(py, &self.raw.borrow_value().tbs_cert.subject) + } + + #[getter] + fn tbs_certificate_bytes<'p>( + &self, + py: pyo3::Python<'p>, + ) -> Result<&'p pyo3::types::PyBytes, PyAsn1Error> { + let result = asn1::write_single(&self.raw.borrow_value().tbs_cert); + Ok(pyo3::types::PyBytes::new(py, &result)) + } + + #[getter] + fn signature<'p>(&self, py: pyo3::Python<'p>) -> Result<&'p pyo3::types::PyBytes, PyAsn1Error> { + Ok(pyo3::types::PyBytes::new( + py, + self.raw.borrow_value().signature.as_bytes(), + )) + } + + #[getter] + fn not_valid_before<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { + let chrono = &self + .raw + .borrow_value() + .tbs_cert + .validity + .not_before + .as_chrono(); + chrono_to_py(py, chrono) + } + + #[getter] + fn not_valid_after<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { + let chrono = &self + .raw + .borrow_value() + .tbs_cert + .validity + .not_after + .as_chrono(); + chrono_to_py(py, chrono) + } + + #[getter] + fn signature_hash_algorithm<'p>( + &self, + py: pyo3::Python<'p>, + ) -> Result<&'p pyo3::PyAny, PyAsn1Error> { + let sig_oids_to_hash = py + .import("cryptography.x509")? + .getattr("_SIG_OIDS_TO_HASH")?; + let hash_alg = sig_oids_to_hash.get_item(self.signature_algorithm_oid(py)?); + match hash_alg { + Ok(data) => Ok(data), + Err(_) => Err(PyAsn1Error::from(pyo3::PyErr::from_instance( + py.import("cryptography.exceptions")?.call_method1( + "UnsupportedAlgorithm", + (format!( + "Signature algorithm OID: {} not recognized", + self.raw.borrow_value().signature_alg.oid.to_string() + ),), + )?, + ))), + } + } + + #[getter] + fn signature_algorithm_oid<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { + py.import("cryptography.x509")?.call_method1( + "ObjectIdentifier", + (self.raw.borrow_value().signature_alg.oid.to_string(),), + ) + } + + #[getter] + fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult { + let x509_module = py.import("cryptography.x509")?; + parse_and_cache_extensions( + py, + &mut self.cached_extensions, + &self.raw.borrow_value().tbs_cert.extensions, + |oid, ext_data| { + if oid == &*SUBJECT_ALTERNATIVE_NAME_OID { + let gn_seq = + asn1::parse_single::>>(ext_data)?; + let sans = parse_general_names(py, gn_seq)?; + Ok(Some( + x509_module + .getattr("SubjectAlternativeName")? + .call1((sans,))?, + )) + } else if oid == &*ISSUER_ALTERNATIVE_NAME_OID { + let gn_seq = + asn1::parse_single::>>(ext_data)?; + let ians = parse_general_names(py, gn_seq)?; + Ok(Some( + x509_module + .getattr("IssuerAlternativeName")? + .call1((ians,))?, + )) + } else if oid == &*TLS_FEATURE_OID { + let tls_feature_type_to_enum = py + .import("cryptography.x509.extensions")? + .getattr("_TLS_FEATURE_TYPE_TO_ENUM")?; + + let features = pyo3::types::PyList::empty(py); + for feature in asn1::parse_single::>(ext_data)? { + let py_feature = + tls_feature_type_to_enum.get_item(feature.to_object(py))?; + features.append(py_feature)?; + } + Ok(Some(x509_module.getattr("TLSFeature")?.call1((features,))?)) + } else if oid == &*SUBJECT_KEY_IDENTIFIER_OID { + let identifier = asn1::parse_single::<&[u8]>(ext_data)?; + Ok(Some( + x509_module + .getattr("SubjectKeyIdentifier")? + .call1((identifier,))?, + )) + } else if oid == &*EXTENDED_KEY_USAGE_OID { + let ekus = pyo3::types::PyList::empty(py); + for oid in asn1::parse_single::>>( + ext_data, + )? { + let oid_obj = + x509_module.call_method1("ObjectIdentifier", (oid.to_string(),))?; + ekus.append(oid_obj)?; + } + Ok(Some( + x509_module.getattr("ExtendedKeyUsage")?.call1((ekus,))?, + )) + } else if oid == &*KEY_USAGE_OID { + let kus = asn1::parse_single::>(ext_data)?; + let digital_signature = kus.has_bit_set(0); + let content_comitment = kus.has_bit_set(1); + let key_encipherment = kus.has_bit_set(2); + let data_encipherment = kus.has_bit_set(3); + let key_agreement = kus.has_bit_set(4); + let key_cert_sign = kus.has_bit_set(5); + let crl_sign = kus.has_bit_set(6); + let encipher_only = kus.has_bit_set(7); + let decipher_only = kus.has_bit_set(8); + Ok(Some(x509_module.getattr("KeyUsage")?.call1(( + digital_signature, + content_comitment, + key_encipherment, + data_encipherment, + key_agreement, + key_cert_sign, + crl_sign, + encipher_only, + decipher_only, + ))?)) + } else if oid == &*AUTHORITY_INFORMATION_ACCESS_OID { + let ads = parse_access_descriptions(py, ext_data)?; + Ok(Some( + x509_module + .getattr("AuthorityInformationAccess")? + .call1((ads,))?, + )) + } else if oid == &*SUBJECT_INFORMATION_ACCESS_OID { + let ads = parse_access_descriptions(py, ext_data)?; + Ok(Some( + x509_module + .getattr("SubjectInformationAccess")? + .call1((ads,))?, + )) + } else if oid == &*CERTIFICATE_POLICIES_OID { + let cp = parse_cp(py, ext_data)?; + Ok(Some( + x509_module.call_method1("CertificatePolicies", (cp,))?, + )) + } else if oid == &*POLICY_CONSTRAINTS_OID { + let pc = asn1::parse_single::(ext_data)?; + Ok(Some(x509_module.getattr("PolicyConstraints")?.call1(( + pc.require_explicit_policy, + pc.inhibit_policy_mapping, + ))?)) + } else if oid == &*PRECERT_POISON_OID { + asn1::parse_single::<()>(ext_data)?; + Ok(Some(x509_module.getattr("PrecertPoison")?.call0()?)) + } else if oid == &*OCSP_NO_CHECK_OID { + asn1::parse_single::<()>(ext_data)?; + Ok(Some(x509_module.getattr("OCSPNoCheck")?.call0()?)) + } else if oid == &*INHIBIT_ANY_POLICY_OID { + let bignum = asn1::parse_single::>(ext_data)?; + let pynum = big_asn1_uint_to_py(py, bignum)?; + Ok(Some( + x509_module.getattr("InhibitAnyPolicy")?.call1((pynum,))?, + )) + } else if oid == &*BASIC_CONSTRAINTS_OID { + let bc = asn1::parse_single::(ext_data)?; + Ok(Some( + x509_module + .getattr("BasicConstraints")? + .call1((bc.ca, bc.path_length))?, + )) + } else if oid == &*AUTHORITY_KEY_IDENTIFIER_OID { + Ok(Some(parse_authority_key_identifier(py, ext_data)?)) + } else if oid == &*CRL_DISTRIBUTION_POINTS_OID { + let dp = parse_distribution_points(py, ext_data)?; + Ok(Some( + x509_module.getattr("CRLDistributionPoints")?.call1((dp,))?, + )) + } else if oid == &*FRESHEST_CRL_OID { + let dp = parse_distribution_points(py, ext_data)?; + Ok(Some(x509_module.getattr("FreshestCRL")?.call1((dp,))?)) + } else if oid == &*PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS_OID { + let contents = asn1::parse_single::<&[u8]>(ext_data)?; + let scts = parse_scts(py, contents, LogEntryType::PreCertificate)?; + Ok(Some( + x509_module + .getattr("PrecertificateSignedCertificateTimestamps")? + .call1((scts,))?, + )) + } else if oid == &*NAME_CONSTRAINTS_OID { + let nc = asn1::parse_single::>(ext_data)?; + let permitted_subtrees = match nc.permitted_subtrees { + Some(data) => parse_general_subtrees(py, data)?, + None => py.None(), + }; + let excluded_subtrees = match nc.excluded_subtrees { + Some(data) => parse_general_subtrees(py, data)?, + None => py.None(), + }; + Ok(Some( + x509_module + .getattr("NameConstraints")? + .call1((permitted_subtrees, excluded_subtrees))?, + )) + } else { + Ok(None) + } + }, + ) + } + // This getter exists for compatibility with pyOpenSSL and will be removed. + // DO NOT RELY ON IT. WE WILL BREAK YOU WHEN WE FEEL LIKE IT. + #[getter] + fn _x509<'p>( + slf: pyo3::pycell::PyRef<'_, Self>, + py: pyo3::Python<'p>, + ) -> Result<&'p pyo3::PyAny, PyAsn1Error> { + let cryptography_warning = py.import("cryptography.utils")?.getattr("DeprecatedIn35")?; + let warnings = py.import("warnings")?; + warnings.call_method1( + "warn", + ( + "This version of cryptography contains a temporary pyOpenSSL fallback path. Upgrade pyOpenSSL now.", + cryptography_warning, + ), + )?; + let backend = py + .import("cryptography.hazmat.backends.openssl.backend")? + .getattr("backend")?; + Ok(backend.call_method1("_cert2ossl", (slf,))?) + } +} + +fn cert_version(py: pyo3::Python<'_>, version: u8) -> Result<&pyo3::PyAny, PyAsn1Error> { + let x509_module = py.import("cryptography.x509")?; + match version { + 0 => Ok(x509_module.getattr("Version")?.get_item("v1")?), + 2 => Ok(x509_module.getattr("Version")?.get_item("v3")?), + _ => Err(PyAsn1Error::from(pyo3::PyErr::from_instance( + x509_module + .getattr("InvalidVersion")? + .call1((format!("{} is not a valid X509 version", version), version))?, + ))), + } +} + +#[pyo3::prelude::pyfunction] +fn load_pem_x509_certificate(py: pyo3::Python<'_>, data: &[u8]) -> PyAsn1Result { + let parsed = pem::parse(data)?; + if parsed.tag != "CERTIFICATE" { + return Err(PyAsn1Error::from(pyo3::exceptions::PyValueError::new_err( + "Valid PEM but no BEGIN CERTIFICATE/END CERTIFICATE delimiters. Are you sure this is a certificate?" + ))); + } + load_der_x509_certificate(py, &parsed.contents) +} + +#[pyo3::prelude::pyfunction] +fn load_der_x509_certificate(py: pyo3::Python<'_>, data: &[u8]) -> PyAsn1Result { + let raw = OwnedRawCertificate::try_new(data.to_vec(), |data| asn1::parse_single(data))?; + // Parse cert version immediately so we can raise error on parse if it is invalid. + cert_version(py, raw.borrow_value().tbs_cert.version)?; + Ok(Certificate { + raw, + cached_extensions: None, + }) +} + pub(crate) fn parse_and_cache_extensions< 'p, F: Fn(&asn1::ObjectIdentifier<'_>, &[u8]) -> Result, PyAsn1Error>, @@ -848,7 +1344,7 @@ pub(crate) fn parse_scts( } #[pyo3::prelude::pyfunction] -fn parse_x509_extension(py: pyo3::Python<'_>, der_oid: &[u8], ext_data: &[u8]) -> PyAsn1Result { +fn parse_csr_extension(py: pyo3::Python<'_>, der_oid: &[u8], ext_data: &[u8]) -> PyAsn1Result { let oid = asn1::ObjectIdentifier::from_der(der_oid).unwrap(); let x509_module = py.import("cryptography.x509")?; @@ -945,9 +1441,6 @@ fn parse_x509_extension(py: pyo3::Python<'_>, der_oid: &[u8], ext_data: &[u8]) - .getattr("PolicyConstraints")? .call1((pc.require_explicit_policy, pc.inhibit_policy_mapping))? .to_object(py)) - } else if oid == *PRECERT_POISON_OID { - asn1::parse_single::<()>(ext_data)?; - Ok(x509_module.getattr("PrecertPoison")?.call0()?.to_object(py)) } else if oid == *OCSP_NO_CHECK_OID { asn1::parse_single::<()>(ext_data)?; Ok(x509_module.getattr("OCSPNoCheck")?.call0()?.to_object(py)) @@ -977,13 +1470,6 @@ fn parse_x509_extension(py: pyo3::Python<'_>, der_oid: &[u8], ext_data: &[u8]) - .getattr("FreshestCRL")? .call1((parse_distribution_points(py, ext_data)?,))? .to_object(py)) - } else if oid == *PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS_OID { - let contents = asn1::parse_single::<&[u8]>(ext_data)?; - let scts = parse_scts(py, contents, LogEntryType::PreCertificate)?; - Ok(x509_module - .getattr("PrecertificateSignedCertificateTimestamps")? - .call1((scts,))? - .to_object(py)) } else if oid == *NAME_CONSTRAINTS_OID { let nc = asn1::parse_single::>(ext_data)?; let permitted_subtrees = match nc.permitted_subtrees { @@ -1116,12 +1602,15 @@ fn parse_crl_extension(py: pyo3::Python<'_>, der_oid: &[u8], ext_data: &[u8]) -> pub(crate) fn create_submodule(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let submod = pyo3::prelude::PyModule::new(py, "x509")?; - submod.add_wrapped(pyo3::wrap_pyfunction!(parse_x509_extension))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(load_der_x509_certificate))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(load_pem_x509_certificate))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(parse_csr_extension))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_crl_entry_ext))?; submod.add_wrapped(pyo3::wrap_pyfunction!(parse_crl_extension))?; submod.add_wrapped(pyo3::wrap_pyfunction!( encode_precertificate_signed_certificate_timestamps ))?; + submod.add_class::()?; submod.add_class::()?; Ok(submod) diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index a59aa09f31bd..ebc1d8148bc0 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -11,7 +11,7 @@ import pytest -from cryptography import x509 +from cryptography import utils, x509 from cryptography.exceptions import InternalError, _Reasons from cryptography.hazmat.backends.openssl import decode_asn1, encode_asn1 from cryptography.hazmat.backends.openssl.backend import Backend, backend @@ -609,30 +609,6 @@ def test_password_length_limit(self): ) -class TestGOSTCertificate(object): - def test_numeric_string_x509_name_entry(self): - cert = _load_cert( - os.path.join("x509", "e-trust.ru.der"), - x509.load_der_x509_certificate, - backend, - ) - if backend._lib.CRYPTOGRAPHY_IS_LIBRESSL: - with pytest.raises(ValueError) as exc: - cert.subject - - # We assert on the message in this case because if the certificate - # fails to load it will also raise a ValueError and this test could - # erroneously pass. - assert str(exc.value) == "Unsupported ASN1 string type. Type: 18" - else: - assert ( - cert.subject.get_attributes_for_oid( - x509.ObjectIdentifier("1.2.643.3.131.1.1") - )[0].value - == "007710474375" - ) - - @pytest.mark.skipif( backend._lib.Cryptography_HAS_EVP_PKEY_DHX == 1, reason="Requires OpenSSL without EVP_PKEY_DHX (< 1.0.2)", @@ -709,3 +685,19 @@ def test_public_load_dhx_unsupported(self, key_path, loader_func, backend): ) with pytest.raises(ValueError): loader_func(key_bytes, backend) + + +def test_pyopenssl_cert_fallback(): + cert = _load_cert( + os.path.join("x509", "cryptography.io.pem"), + x509.load_pem_x509_certificate, + ) + x509_ossl = None + with pytest.warns(utils.CryptographyDeprecationWarning): + x509_ossl = cert._x509 + assert x509_ossl is not None + + from cryptography.hazmat.backends.openssl.x509 import _Certificate + + with pytest.warns(utils.CryptographyDeprecationWarning): + _Certificate(backend, x509_ossl) diff --git a/tests/hazmat/primitives/test_pkcs7.py b/tests/hazmat/primitives/test_pkcs7.py index 6bc65eef3104..60aa367dde09 100644 --- a/tests/hazmat/primitives/test_pkcs7.py +++ b/tests/hazmat/primitives/test_pkcs7.py @@ -104,8 +104,12 @@ def _pkcs7_verify(encoding, sig, msg, certs, options, backend): store = backend._lib.X509_STORE_new() backend.openssl_assert(store != backend._ffi.NULL) store = backend._ffi.gc(store, backend._lib.X509_STORE_free) + # This list is to keep the x509 values alive until end of function + ossl_certs = [] for cert in certs: - res = backend._lib.X509_STORE_add_cert(store, cert._x509) + ossl_cert = backend._cert2ossl(cert) + ossl_certs.append(ossl_cert) + res = backend._lib.X509_STORE_add_cert(store, ossl_cert) backend.openssl_assert(res == 1) if msg is None: res = backend._lib.PKCS7_verify( diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index fc36d5f4111b..db0a3e819820 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -60,7 +60,7 @@ def __init__(self, value): value = utils.read_only_property("_value") -def _load_cert(filename, loader, backend): +def _load_cert(filename, loader, backend=None): cert = load_vectors_from_file( filename=filename, loader=lambda pemfile: loader(pemfile.read(), backend), @@ -645,12 +645,12 @@ def test_load_pem_cert(self, backend): ) def test_negative_serial_number(self, backend): - cert = _load_cert( - os.path.join("x509", "custom", "negative_serial.pem"), - x509.load_pem_x509_certificate, - backend, - ) - assert cert.serial_number == -18008675309 + with pytest.raises(ValueError, match="TbsCertificate::serial"): + _load_cert( + os.path.join("x509", "custom", "negative_serial.pem"), + x509.load_pem_x509_certificate, + backend, + ) def test_alternate_rsa_with_sha1_oid(self, backend): cert = _load_cert( @@ -1039,6 +1039,20 @@ def test_ne(self, backend): assert cert != cert2 assert cert != object() + def test_ordering_unsupported(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "post2000utctime.pem"), + x509.load_pem_x509_certificate, + backend, + ) + cert2 = _load_cert( + os.path.join("x509", "custom", "post2000utctime.pem"), + x509.load_pem_x509_certificate, + backend, + ) + with pytest.raises(TypeError, match="cannot be ordered"): + cert > cert2 + def test_hash(self, backend): cert1 = _load_cert( os.path.join("x509", "custom", "post2000utctime.pem"), @@ -1073,9 +1087,17 @@ def test_version_1_cert(self, backend): assert cert.version is x509.Version.v1 def test_invalid_pem(self, backend): - with pytest.raises(ValueError): + with pytest.raises(ValueError, match="Unable to load"): x509.load_pem_x509_certificate(b"notacert", backend) + crl = load_vectors_from_file( + filename=os.path.join("x509", "custom", "crl_empty.pem"), + loader=lambda pemfile: pemfile.read(), + mode="rb", + ) + with pytest.raises(ValueError, match="Valid PEM but no"): + x509.load_pem_x509_certificate(crl, backend) + def test_invalid_der(self, backend): with pytest.raises(ValueError): x509.load_der_x509_certificate(b"notacert", backend) @@ -1183,9 +1205,9 @@ def test_certificate_repr(self, backend): backend, ) assert repr(cert) == ( - ", ...)>" + ", ...)>" ) def test_parse_tls_feature_extension(self, backend): @@ -3204,6 +3226,7 @@ def test_extensions(self, add_ext, backend): subject_private_key.public_key() ) + # Cert cert = ( x509.CertificateBuilder() .subject_name( @@ -3224,6 +3247,19 @@ def test_extensions(self, add_ext, backend): assert ext.critical is False assert ext.value == add_ext + # CSR + csr = ( + x509.CertificateSigningRequestBuilder() + .subject_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) + ) + .add_extension(add_ext, False) + .sign(subject_private_key, hashes.SHA256()) + ) + ext = csr.extensions.get_extension_for_class(type(add_ext)) + assert ext.critical is False + assert ext.value == add_ext + def test_build_ca_request_with_path_length_none(self, backend): private_key = RSA_KEY_2048.private_key(backend) @@ -4178,6 +4214,20 @@ def test_tbs_certrequest_bytes(self, backend): ) +class TestGOSTCertificate(object): + def test_numeric_string_x509_name_entry(self): + cert = _load_cert( + os.path.join("x509", "e-trust.ru.der"), + x509.load_der_x509_certificate, + ) + assert ( + cert.subject.get_attributes_for_oid( + x509.ObjectIdentifier("1.2.643.3.131.1.1") + )[0].value + == "007710474375" + ) + + class TestECDSACertificate(object): def test_load_ecdsa_cert(self, backend): _skip_curve_unsupported(backend, ec.SECP384R1()) @@ -4348,14 +4398,12 @@ def test_unsupported_subject_public_key_info(self, backend): 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 + with pytest.raises(ValueError, match="Validity::not_after"): + _load_cert( + os.path.join("x509", "badasn1time.pem"), + x509.load_pem_x509_certificate, + backend, + ) class TestNameAttribute(object): From 4aabad3dbf101810323a0d19d71a6970203375f6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 31 Jul 2021 11:17:51 -0400 Subject: [PATCH 0255/1456] Fixes #6158 -- added more type annotations (#6185) --- src/cryptography/hazmat/backends/openssl/dsa.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/dsa.py b/src/cryptography/hazmat/backends/openssl/dsa.py index d3c54b82fad1..fbce96c2121f 100644 --- a/src/cryptography/hazmat/backends/openssl/dsa.py +++ b/src/cryptography/hazmat/backends/openssl/dsa.py @@ -58,10 +58,10 @@ def __init__(self, backend, public_key, signature, algorithm): self._hash_ctx = hashes.Hash(self._algorithm, self._backend) - def update(self, data): + def update(self, data: bytes): self._hash_ctx.update(data) - def verify(self): + def verify(self) -> None: data_to_verify = self._hash_ctx.finalize() _dsa_sig_verify( @@ -282,7 +282,7 @@ def verify( signature: bytes, data: bytes, algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], - ): + ) -> None: data, algorithm = _calculate_digest_and_algorithm( self._backend, data, algorithm ) From eab2e804380cf17fd2a11e4c74eb5915235ee414 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Sun, 8 Aug 2021 16:17:31 +0200 Subject: [PATCH 0256/1456] Test with 3.0.0-beta2 (#6192) - OpenSSL 3.0.0-beta2 now uses lib64 on X86_64 - fail on implicit function definition --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 46450d94d0c7..c32b5c52f12e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k"}} - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0-beta1"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0-beta2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "2.9.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.1.5"}} @@ -91,8 +91,8 @@ jobs: if: matrix.PYTHON.OPENSSL && steps.ossl-cache.outputs.cache-hit != 'true' - name: Set CFLAGS/LDFLAGS run: | - echo "CFLAGS=${CFLAGS} -I${OSSL_PATH}/include" >> $GITHUB_ENV - echo "LDFLAGS=${LDFLAGS} -L${OSSL_PATH}/lib -Wl,-rpath=${OSSL_PATH}/lib" >> $GITHUB_ENV + echo "CFLAGS=${CFLAGS} -Werror=implicit-function-declaration -I${OSSL_PATH}/include" >> $GITHUB_ENV + echo "LDFLAGS=${LDFLAGS} -L${OSSL_PATH}/lib -L${OSSL_PATH}/lib64 -Wl,-rpath=${OSSL_PATH}/lib -Wl,-rpath=${OSSL_PATH}/lib64" >> $GITHUB_ENV if: matrix.PYTHON.OPENSSL - name: Tests run: | From 50d51933b20714b3f2aabe7dc82a7dca31c7b24d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 8 Aug 2021 10:23:55 -0400 Subject: [PATCH 0257/1456] Correct the documentation on crl_invalid_time.der (#6191) --- docs/development/test-vectors.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index ee8e617edd4d..6d096f63e43b 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -536,7 +536,7 @@ Custom X.509 Certificate Revocation List Vectors * ``crl_unrecognized_extension.der`` - Contains a CRL containing an unsupported extension type. The OID was encoded as "1.2.3.4.5" with an ``extnValue`` of ``abcdef``. -* ``crl_invalid_time.der`` - Contains a CRL with an invalid ``GeneralizedTime`` +* ``crl_invalid_time.der`` - Contains a CRL with an invalid ``UTCTime`` value in ``thisUpdate``. The signature on this CRL is invalid. X.509 OCSP Test Vectors From 97913343d6c8156cdb0e10707f398dae26f933b7 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 8 Aug 2021 11:47:49 -0400 Subject: [PATCH 0258/1456] remove twisted from downstream testing for now (#6193) spurious failures and no resolution so far --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c32b5c52f12e..cc7b9c2ccca0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -401,7 +401,6 @@ jobs: DOWNSTREAM: - paramiko - pyopenssl - - twisted - aws-encryption-sdk - dynamodb-encryption-sdk - certbot From db650fbc784e4ae9ffa7ca8ece7336db16ce0165 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 8 Aug 2021 13:13:44 -0400 Subject: [PATCH 0259/1456] fix OAEP pdf link (#6195) --- docs/hazmat/primitives/asymmetric/rsa.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hazmat/primitives/asymmetric/rsa.rst b/docs/hazmat/primitives/asymmetric/rsa.rst index 7a3e835a13d5..009e23ea45b9 100644 --- a/docs/hazmat/primitives/asymmetric/rsa.rst +++ b/docs/hazmat/primitives/asymmetric/rsa.rst @@ -778,4 +778,4 @@ Key interfaces .. _`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`: https://www.daemonology.net/blog/2009-06-11-cryptographic-right-answers.html -.. _`proven secure`: https://cseweb.ucsd.edu/~mihir/papers/oae.pdf +.. _`proven secure`: https://cseweb.ucsd.edu/~mihir/papers/oaep.pdf From 3e93f53ba2516f0ef92af39ad5abf077aa6c2580 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 8 Aug 2021 15:46:27 -0400 Subject: [PATCH 0260/1456] more pypy (#6180) --- .github/workflows/wheel-builder.yml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 29a1e154f473..1adb7cf2469b 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -3,6 +3,7 @@ on: workflow_dispatch: inputs: version: + description: The version to build required: true jobs: @@ -65,16 +66,25 @@ jobs: PYTHON: - VERSION: '3.8' ABI_VERSION: 'cp36' - DOWNLOAD_URL: 'https://www.python.org/ftp/python/3.8.2/python-3.8.2-macosx10.9.pkg' + DOWNLOAD_URL: 'https://www.python.org/ftp/python/3.8.10/python-3.8.10-macosx10.9.pkg' BIN_PATH: '/Library/Frameworks/Python.framework/Versions/3.8/bin/python3' + - VERSION: 'pypy-3.7' + BIN_PATH: 'pypy3' name: "${{ matrix.PYTHON.VERSION }} ABI ${{ matrix.PYTHON.ABI_VERSION }} macOS" steps: - uses: actions/checkout@v2.3.4 - - run: | + - name: Setup python + run: | curl "$PYTHON_DOWNLOAD_URL" -o python.pkg sudo installer -pkg python.pkg -target / env: PYTHON_DOWNLOAD_URL: ${{ matrix.PYTHON.DOWNLOAD_URL }} + if: contains(matrix.PYTHON.VERSION, 'pypy') == false + - name: Setup pypy + uses: actions/setup-python@v2.2.2 + with: + python-version: ${{ matrix.PYTHON.VERSION }} + if: contains(matrix.PYTHON.VERSION, 'pypy') - run: ${{ matrix.PYTHON.BIN_PATH }} -m pip install -U requests - name: Download OpenSSL run: | @@ -121,6 +131,11 @@ jobs: - {ARCH: 'x64', WINDOWS: 'win64', RUST_TRIPLE: 'x86_64-pc-windows-msvc'} PYTHON: - {VERSION: "3.8", MSVC_VERSION: "2019", "ABI_VERSION": "cp36"} + - {VERSION: "pypy-3.7", MSVC_VERSION: "2019"} + exclude: + # We need to exclude the below configuration because there is no 32-bit pypy3 + - WINDOWS: {ARCH: 'x86', WINDOWS: 'win32', RUST_TRIPLE: 'i686-pc-windows-msvc'} + PYTHON: {VERSION: "pypy-3.7", MSVC_VERSION: "2019"} name: "${{ matrix.PYTHON.VERSION }} ${{ matrix.WINDOWS.WINDOWS }} ${{ matrix.PYTHON.ABI_VERSION }}" steps: - uses: actions/checkout@v2.3.4 From e739727fc3ea3dd3237b45583ce5bd4f388b9c9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Aug 2021 08:24:19 -0400 Subject: [PATCH 0261/1456] Bump redox_syscall from 0.2.9 to 0.2.10 in /src/rust (#6198) Bumps redox_syscall from 0.2.9 to 0.2.10. --- updated-dependencies: - dependency-name: redox_syscall dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 9efe36c6bf65..691efbcfaf6a 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -336,9 +336,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] From 3ba2c3d3ac40876a49f9b58bf7eede00a696d0f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Aug 2021 08:26:47 -0400 Subject: [PATCH 0262/1456] Bump pyo3 from 0.14.1 to 0.14.2 in /src/rust (#6200) Bumps [pyo3](https://github.com/pyo3/pyo3) from 0.14.1 to 0.14.2. - [Release notes](https://github.com/pyo3/pyo3/releases) - [Changelog](https://github.com/PyO3/pyo3/blob/main/CHANGELOG.md) - [Commits](https://github.com/pyo3/pyo3/compare/v0.14.1...v0.14.2) --- updated-dependencies: - dependency-name: pyo3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 16 ++++++++-------- src/rust/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 691efbcfaf6a..812a39a5b6b3 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -279,9 +279,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "338f7f3701e11fd7f76508c91fbcaabc982564bcaf4d1ca7e1574ff2b4778aec" +checksum = "af205762ba65eec9f27a2fa1a57a40644e8e3368784b8c8b2f2de48f6e8ddd96" dependencies = [ "cfg-if", "indoc", @@ -295,18 +295,18 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb2e98cc9ccc83d4f7115c8f925e0057e88c8d324b1bc4c2db4a7270c06ac9d" +checksum = "755944027ce803c7238e59c5a18e59c1d0a4553db50b23e9ba209a568353028d" dependencies = [ "once_cell", ] [[package]] name = "pyo3-macros" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfb8671a42d0ecc4bec8cc107ae96d49292ca20cd1968e09b98af4aafd516adf" +checksum = "cd31b36bccfd902c78804bd96c28ea93eac6fa0ca311f9d21ef2230b6665b29a" dependencies = [ "pyo3-macros-backend", "quote", @@ -315,9 +315,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9addf6dc422f05d4949cc0990195ee74fa43e3c3780cc9a1972fe9e7b68a9f48" +checksum = "c21c59ba36db9c823e931c662766b0dd01a030b1d96585b67d8857a96a56b972" dependencies = [ "proc-macro2", "pyo3-build-config", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index aa4331ce96e3..45a853d83bd9 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] lazy_static = "1" -pyo3 = { version = "0.14.1" } +pyo3 = { version = "0.14.2" } asn1 = { version = "0.6", default-features = false, features = ["derive"] } pem = "0.8" chrono = { version = "0.4", default-features = false, features = ["alloc"] } From b48abfb7aeef94a4c6fe2051b494be4e46ed80eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Aug 2021 16:58:03 -0400 Subject: [PATCH 0263/1456] Bump asn1 from 0.6.0 to 0.6.1 in /src/rust (#6202) Bumps [asn1](https://github.com/alex/rust-asn1) from 0.6.0 to 0.6.1. - [Release notes](https://github.com/alex/rust-asn1/releases) - [Commits](https://github.com/alex/rust-asn1/compare/0.6.0...0.6.1) --- updated-dependencies: - dependency-name: asn1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 812a39a5b6b3..3e7ae7c10c34 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -16,9 +16,9 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" [[package]] name = "asn1" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9680a48fea09cb1af33dc233179b9723674ca43ad9e5c9d01ab6ad1c3c58c0dc" +checksum = "a9c13a3c9cd71e1799fc16511efe36d0281b60bce3b32b4b211156a7b1925bfd" dependencies = [ "asn1_derive", "chrono", @@ -26,9 +26,9 @@ dependencies = [ [[package]] name = "asn1_derive" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f828598cd99548327735aae5db2852e3d78d1508ed81543f204b8ca3cf3ba859" +checksum = "62fc4b7f90b9540f1719f333e3ed85100ea072035d690000d7c01252ecdff096" dependencies = [ "proc-macro2", "quote", From e889be5110a96e95ef91fccdb7bd18da08afa17b Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 9 Aug 2021 20:00:11 -0400 Subject: [PATCH 0264/1456] add concurrency to cancel in-progress jobs (#6203) * add concurrency to cancel in-progress jobs * empty commit to test canceling --- .github/workflows/ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc7b9c2ccca0..90e56ae978d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,11 @@ on: permissions: read-all +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + + jobs: linux: runs-on: ubuntu-latest From d4e04edd5938c9af62586f16329b3fcd87e1c35a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Aug 2021 08:41:31 -0400 Subject: [PATCH 0265/1456] Bump libc from 0.2.98 to 0.2.99 in /src/rust (#6205) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.98 to 0.2.99. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.98...0.2.99) --- updated-dependencies: - dependency-name: libc dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 3e7ae7c10c34..4ab9b0bf38f8 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -121,9 +121,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.98" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" +checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" [[package]] name = "lock_api" From 5f5eb5493dd2453b98480330dbf149fc5a0489d1 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 10 Aug 2021 22:56:24 -0400 Subject: [PATCH 0266/1456] support arm64 in GHA (#6204) * support arm64 in GHA * separate workflow that only runs on main, version branches, and tags --- .github/workflows/arm64.yml | 52 +++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 .github/workflows/arm64.yml diff --git a/.github/workflows/arm64.yml b/.github/workflows/arm64.yml new file mode 100644 index 000000000000..f8be149af632 --- /dev/null +++ b/.github/workflows/arm64.yml @@ -0,0 +1,52 @@ +name: Arm64 CI +on: + push: + branches: + - main + - '*.*.x' + tags: + - '*.*' + - '*.*.*' + +permissions: read-all + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + linux-arm64: + runs-on: [self-hosted, linux, ARM64] + container: ghcr.io/pyca/cryptography-runner-${{ matrix.IMAGE.IMAGE }} + strategy: + fail-fast: false + matrix: + IMAGE: + - {IMAGE: "ubuntu-focal:aarch64", TOXENV: "py38"} + name: "${{ matrix.IMAGE.TOXENV }} on ${{ matrix.IMAGE.IMAGE }}" + timeout-minutes: 20 + steps: + - name: "Delete workspace" # self-hosted runners need this, sigh + run: find ! -name '.' ! -name '..' -delete + - uses: actions/checkout@v2.3.4 + with: + persist-credentials: false + - uses: actions/cache@v2.1.6 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + src/rust/target/ + key: ${{ runner.os }}-${{ matrix.IMAGE.IMAGE }}-cargo-2-${{ hashFiles('**/Cargo.lock') }} + + - run: 'git clone --depth=1 https://github.com/google/wycheproof "$HOME/wycheproof"' + - run: 'tox -- --wycheproof-root="$HOME/wycheproof"' + env: + TOXENV: ${{ matrix.IMAGE.TOXENV }} + RUSTUP_HOME: /root/.rustup + CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} + - uses: ./.github/actions/upload-coverage + with: + name: "${{ matrix.IMAGE.TOXENV }} on ${{ matrix.IMAGE.IMAGE }}" From b93f405c07a312945935a1a718d8d6e1b5153a9b Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 11 Aug 2021 22:47:25 -0400 Subject: [PATCH 0267/1456] Speed up RSA tests in 3.0.0 (#6206) * Speed up RSA tests in 3.0.0 RSA_check_key is slower in OpenSSL 3.0.0 due to improved primality checking. In normal use this is unlikely to be a problem since users don't load new keys constantly, but we do in our tests. This adds some private flags to allow skipping those checks for performance reasons. On my laptop with this patch it takes 16s to run test_rsa.py. The previous commit takes 72s. * black * different approach * skip rsa key checks in wycheproof wycheproof's tets don't rely on broken keys --- .../hazmat/backends/openssl/backend.py | 13 ++++++++++--- src/cryptography/hazmat/backends/openssl/rsa.py | 16 +++++++++++----- tests/conftest.py | 9 +++++++++ tests/hazmat/primitives/test_rsa.py | 10 +++++++--- tests/wycheproof/utils.py | 4 +++- 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 349205b13340..3603a1c34adb 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -182,6 +182,7 @@ def __init__(self): self._binding = binding.Binding() self._ffi = self._binding.ffi self._lib = self._binding.lib + self._rsa_skip_check_key = False self._fips_enabled = self._is_fips_enabled() self._cipher_registry = {} @@ -507,7 +508,9 @@ def generate_rsa_private_key(self, public_exponent, key_size): self.openssl_assert(res == 1) evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) - return _RSAPrivateKey(self, rsa_cdata, evp_pkey) + return _RSAPrivateKey( + self, rsa_cdata, evp_pkey, self._rsa_skip_check_key + ) def generate_rsa_parameters_supported(self, public_exponent, key_size): return ( @@ -546,7 +549,9 @@ def load_rsa_private_numbers(self, numbers): self.openssl_assert(res == 1) evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) - return _RSAPrivateKey(self, rsa_cdata, evp_pkey) + return _RSAPrivateKey( + self, rsa_cdata, evp_pkey, self._rsa_skip_check_key + ) def load_rsa_public_numbers(self, numbers): rsa._check_public_key_components(numbers.e, numbers.n) @@ -620,7 +625,9 @@ def _evp_pkey_to_private_key(self, evp_pkey): rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) self.openssl_assert(rsa_cdata != self._ffi.NULL) rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) - return _RSAPrivateKey(self, rsa_cdata, evp_pkey) + return _RSAPrivateKey( + self, rsa_cdata, evp_pkey, self._rsa_skip_check_key + ) elif key_type == self._lib.EVP_PKEY_DSA: dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) self.openssl_assert(dsa_cdata != self._ffi.NULL) diff --git a/src/cryptography/hazmat/backends/openssl/rsa.py b/src/cryptography/hazmat/backends/openssl/rsa.py index 74375ca0e983..ab639c8c7f72 100644 --- a/src/cryptography/hazmat/backends/openssl/rsa.py +++ b/src/cryptography/hazmat/backends/openssl/rsa.py @@ -382,11 +382,17 @@ def verify(self) -> None: class _RSAPrivateKey(RSAPrivateKey): - def __init__(self, backend, rsa_cdata, evp_pkey): - res = backend._lib.RSA_check_key(rsa_cdata) - if res != 1: - errors = backend._consume_errors_with_text() - raise ValueError("Invalid private key", errors) + def __init__(self, backend, rsa_cdata, evp_pkey, _skip_check_key): + # RSA_check_key is slower in OpenSSL 3.0.0 due to improved + # primality checking. In normal use this is unlikely to be a problem + # since users don't load new keys constantly, but for TESTING we've + # added an init arg that allows skipping the checks. You should not + # use this in production code unless you understand the consequences. + if not _skip_check_key: + res = backend._lib.RSA_check_key(rsa_cdata) + if res != 1: + errors = backend._consume_errors_with_text() + raise ValueError("Invalid private key", errors) # Blinding is on by default in many versions of OpenSSL, but let's # just be conservative here. diff --git a/tests/conftest.py b/tests/conftest.py index 2fea50c17b8f..01aba7784586 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -33,3 +33,12 @@ def pytest_runtest_setup(item): def backend(request): check_backend_support(openssl_backend, request) return openssl_backend + + +@pytest.fixture +def disable_rsa_checks(backend): + # Use this fixture to skip RSA key checks in tests that need the + # performance. + backend._rsa_skip_check_key = True + yield + backend._rsa_skip_check_key = False diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 2666fdfc1787..d98bf638d4ec 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -402,7 +402,7 @@ class TestRSASignature(object): skip_message="Does not support PKCS1v1.5.", ) @pytest.mark.skip_fips(reason="SHA1 signing not supported in FIPS mode.") - def test_pkcs1v15_signing(self, backend, subtests): + def test_pkcs1v15_signing(self, backend, disable_rsa_checks, subtests): vectors = _flatten_pkcs1_examples( load_vectors_from_file( os.path.join("asymmetric", "RSA", "pkcs1v15sign-vectors.txt"), @@ -1527,7 +1527,9 @@ class TestRSADecryption(object): ), skip_message="Does not support PKCS1v1.5.", ) - def test_decrypt_pkcs1v15_vectors(self, backend, subtests): + def test_decrypt_pkcs1v15_vectors( + self, backend, disable_rsa_checks, subtests + ): vectors = _flatten_pkcs1_examples( load_vectors_from_file( os.path.join("asymmetric", "RSA", "pkcs1v15crypt-vectors.txt"), @@ -1650,7 +1652,9 @@ def test_decrypt_oaep_vectors(self, vector, backend): "Does not support OAEP using SHA224 MGF1 and SHA224 hash." ), ) - def test_decrypt_oaep_sha2_vectors(self, backend, subtests): + def test_decrypt_oaep_sha2_vectors( + self, backend, disable_rsa_checks, subtests + ): vectors = _build_oaep_sha2_vectors() for private, public, example, mgf1_alg, hash_alg in vectors: with subtests.test(): diff --git a/tests/wycheproof/utils.py b/tests/wycheproof/utils.py index eebbe7ce3bf6..3c18e62afa43 100644 --- a/tests/wycheproof/utils.py +++ b/tests/wycheproof/utils.py @@ -3,7 +3,9 @@ def wycheproof_tests(*paths): def wrapper(func): - def run_wycheproof(backend, subtests, pytestconfig): + def run_wycheproof( + backend, disable_rsa_checks, subtests, pytestconfig + ): wycheproof_root = pytestconfig.getoption( "--wycheproof-root", skip=True ) From f6a81b9c639481684d17ca3bbe5236b3b041d425 Mon Sep 17 00:00:00 2001 From: DivineHawk Date: Thu, 12 Aug 2021 08:09:23 -0400 Subject: [PATCH 0268/1456] Add RDN for emailAddress (#6100) * Add RDN for email address * Update test for nonstandard attribute OID * Fix indent --- src/cryptography/x509/name.py | 1 + tests/x509/test_x509.py | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py index b02fda9cfe67..cab8f4b790f1 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -46,6 +46,7 @@ class _ASN1Type(utils.Enum): NameOID.STREET_ADDRESS: "STREET", NameOID.DOMAIN_COMPONENT: "DC", NameOID.USER_ID: "UID", + NameOID.EMAIL_ADDRESS: "E", } diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index db0a3e819820..58dde9b1aa59 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -4509,10 +4509,8 @@ def test_distinugished_name(self): assert na.rfc4514_string() == r"UID=\# escape\+\,\;\00this\ " # Nonstandard attribute OID - na = x509.NameAttribute(NameOID.EMAIL_ADDRESS, "somebody@example.com") - assert ( - na.rfc4514_string() == "1.2.840.113549.1.9.1=somebody@example.com" - ) + na = x509.NameAttribute(NameOID.BUSINESS_CATEGORY, "banking") + assert na.rfc4514_string() == "2.5.4.15=banking" def test_empty_value(self): na = x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "") From d316405a5a53ab51c89b644febd2ed3bf9dba9de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Aug 2021 12:57:59 -0400 Subject: [PATCH 0269/1456] Bump bitflags from 1.2.1 to 1.3.1 in /src/rust (#6208) Bumps [bitflags](https://github.com/bitflags/bitflags) from 1.2.1 to 1.3.1. - [Release notes](https://github.com/bitflags/bitflags/releases) - [Changelog](https://github.com/bitflags/bitflags/blob/main/CHANGELOG.md) - [Commits](https://github.com/bitflags/bitflags/compare/1.2.1...1.3.1) --- updated-dependencies: - dependency-name: bitflags dependency-type: indirect update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 4ab9b0bf38f8..16429852ae3f 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -49,9 +49,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "2da1976d75adbe5fbc88130ecd119529cf1cc6a93ae1546d8696ee66f0d21af1" [[package]] name = "cfg-if" From 6c1c15feea8bb0b344e2b32a43d237dca8dcd9e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Aug 2021 08:41:31 -0400 Subject: [PATCH 0270/1456] Bump bitflags from 1.3.1 to 1.3.2 in /src/rust (#6211) Bumps [bitflags](https://github.com/bitflags/bitflags) from 1.3.1 to 1.3.2. - [Release notes](https://github.com/bitflags/bitflags/releases) - [Changelog](https://github.com/bitflags/bitflags/blob/main/CHANGELOG.md) - [Commits](https://github.com/bitflags/bitflags/compare/1.3.1...1.3.2) --- updated-dependencies: - dependency-name: bitflags dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 16429852ae3f..3541471995bb 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -49,9 +49,9 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bitflags" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da1976d75adbe5fbc88130ecd119529cf1cc6a93ae1546d8696ee66f0d21af1" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cfg-if" From 7eb9d5a7a3bee399c94d248f8faaad556aeb721c Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Tue, 17 Aug 2021 15:07:32 +0200 Subject: [PATCH 0271/1456] Add more debug assistance (#6210) Print Python version, platform, setuptools, pip, and setuptools_rust on failed builds. Signed-off-by: Christian Heimes --- setup.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/setup.py b/setup.py index f524c2be3d03..51ce120ed25f 100644 --- a/setup.py +++ b/setup.py @@ -153,6 +153,9 @@ # during PEP517 building and prints this text. setuptools raises SystemExit # when compilation fails right now, but it's possible this isn't stable # or a public API commitment so we'll remain ultra conservative. + + import pkg_resources + print( """ =============================DEBUG ASSISTANCE============================= @@ -166,6 +169,18 @@ https://cryptography.io/en/latest/faq.html 4) Ensure you have a recent Rust toolchain installed: https://cryptography.io/en/latest/installation.html#rust + """ + ) + print(f" Python: {'.'.join(str(v) for v in sys.version_info[:3])}") + print(f" platform: {platform.platform()}") + for dist in ["pip", "setuptools", "setuptools_rust"]: + try: + version = pkg_resources.get_distribution(dist).version + except pkg_resources.DistributionNotFound: + version = "n/a" + print(f" {dist}: {version}") + print( + """\ =============================DEBUG ASSISTANCE============================= """ ) From f7ba53cb5050c465338baa127abc0243663cf217 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Aug 2021 09:12:23 -0400 Subject: [PATCH 0272/1456] Bump dessant/lock-threads from 2.1.1 to 2.1.2 (#6212) Bumps [dessant/lock-threads](https://github.com/dessant/lock-threads) from 2.1.1 to 2.1.2. - [Release notes](https://github.com/dessant/lock-threads/releases) - [Changelog](https://github.com/dessant/lock-threads/blob/master/CHANGELOG.md) - [Commits](https://github.com/dessant/lock-threads/compare/v2.1.1...v2.1.2) --- updated-dependencies: - dependency-name: dessant/lock-threads dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/lock.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index 2e19c82c41f5..fe96f070d66a 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -11,7 +11,7 @@ jobs: lock: runs-on: ubuntu-latest steps: - - uses: dessant/lock-threads@v2.1.1 + - uses: dessant/lock-threads@v2.1.2 with: github-token: ${{ secrets.GITHUB_TOKEN }} issue-lock-inactive-days: 90 From 8e671be7a1f9738719617e2da08c26d9da2d44b8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Aug 2021 08:52:00 -0400 Subject: [PATCH 0273/1456] Bump pyo3 from 0.14.2 to 0.14.3 in /src/rust (#6216) Bumps [pyo3](https://github.com/pyo3/pyo3) from 0.14.2 to 0.14.3. - [Release notes](https://github.com/pyo3/pyo3/releases) - [Changelog](https://github.com/PyO3/pyo3/blob/main/CHANGELOG.md) - [Commits](https://github.com/pyo3/pyo3/compare/v0.14.2...v0.14.3) --- updated-dependencies: - dependency-name: pyo3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 16 ++++++++-------- src/rust/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 3541471995bb..5cd467f25f67 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -279,9 +279,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af205762ba65eec9f27a2fa1a57a40644e8e3368784b8c8b2f2de48f6e8ddd96" +checksum = "4ce0e80b2b35e9697353a25b0e4fa5374e38c451da2f86f0cd83c40e7f1d5191" dependencies = [ "cfg-if", "indoc", @@ -295,18 +295,18 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755944027ce803c7238e59c5a18e59c1d0a4553db50b23e9ba209a568353028d" +checksum = "96007b58c38d68ae449ea4d82fbc390faf5f1f2c80c76a6e3d51385bceb56741" dependencies = [ "once_cell", ] [[package]] name = "pyo3-macros" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd31b36bccfd902c78804bd96c28ea93eac6fa0ca311f9d21ef2230b6665b29a" +checksum = "326afb5c23f9789d0a367c37d58275c4d0e97ca74f05b9a25c0d66c6395c1c7b" dependencies = [ "pyo3-macros-backend", "quote", @@ -315,9 +315,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c21c59ba36db9c823e931c662766b0dd01a030b1d96585b67d8857a96a56b972" +checksum = "7e38169a08f98219bba484d19100811a1646d4962706b75d60766d21dce64f9c" dependencies = [ "proc-macro2", "pyo3-build-config", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 45a853d83bd9..d8c1f2c351cf 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] lazy_static = "1" -pyo3 = { version = "0.14.2" } +pyo3 = { version = "0.14.3" } asn1 = { version = "0.6", default-features = false, features = ["derive"] } pem = "0.8" chrono = { version = "0.4", default-features = false, features = ["alloc"] } From 6cc76c153e86cbb230231efde2e8dbe0b1234b28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Aug 2021 08:52:45 -0400 Subject: [PATCH 0274/1456] Bump syn from 1.0.74 to 1.0.75 in /src/rust (#6217) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.74 to 1.0.75. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.74...1.0.75) --- updated-dependencies: - dependency-name: syn dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 5cd467f25f67..23af7bcf6e0b 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -378,9 +378,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "1.0.74" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7" dependencies = [ "proc-macro2", "quote", From dc05cc85ce3579e28b8ab1ff6ddcd72957e91824 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Aug 2021 08:53:21 -0400 Subject: [PATCH 0275/1456] Bump libc from 0.2.99 to 0.2.100 in /src/rust (#6218) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.99 to 0.2.100. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.99...0.2.100) --- updated-dependencies: - dependency-name: libc dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 23af7bcf6e0b..2f87394760f7 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -121,9 +121,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" +checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5" [[package]] name = "lock_api" From 62c270fba93501bcc1061e95093485573c8f0bc3 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 23 Aug 2021 19:45:21 -0400 Subject: [PATCH 0276/1456] move linkcheck to its own action (#6220) this lets us restart it with minimal blast radius --- .github/workflows/ci.yml | 24 ------------------------ .github/workflows/linkcheck.yml | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/linkcheck.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 90e56ae978d7..289c2c3fb200 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -447,27 +447,3 @@ jobs: env: CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - run: ./.github/downstream.d/${{ matrix.DOWNSTREAM }}.sh run - - docs-linkcheck: - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - runs-on: ubuntu-latest - name: "linkcheck" - timeout-minutes: 20 - steps: - - uses: actions/checkout@v2.3.4 - with: - persist-credentials: false - - name: Setup python - uses: actions/setup-python@v2.2.2 - with: - python-version: 3.9 - - uses: actions-rs/toolchain@v1.0.7 - with: - profile: minimal - toolchain: stable - override: true - default: true - - run: python -m pip install -U tox - - run: tox -r -- --color=yes - env: - TOXENV: docs-linkcheck diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml new file mode 100644 index 000000000000..e867b22f618e --- /dev/null +++ b/.github/workflows/linkcheck.yml @@ -0,0 +1,32 @@ +name: "linkcheck" +on: + push: + branches: + - main + +permissions: + contents: read + +jobs: + docs-linkcheck: + runs-on: ubuntu-latest + name: "linkcheck" + timeout-minutes: 20 + steps: + - uses: actions/checkout@v2.3.4 + with: + persist-credentials: false + - name: Setup python + uses: actions/setup-python@v2.2.2 + with: + python-version: 3.9 + - uses: actions-rs/toolchain@v1.0.7 + with: + profile: minimal + toolchain: stable + override: true + default: true + - run: python -m pip install -U tox + - run: tox -r -- --color=yes + env: + TOXENV: docs-linkcheck \ No newline at end of file From d98b2aa16fa2051b33b7fddc8c8c2d99c50901cf Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 23 Aug 2021 21:06:14 -0400 Subject: [PATCH 0277/1456] Don't cancel builds on main -- we always want to run those (#6221) --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 289c2c3fb200..60797299056d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ on: permissions: read-all concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true From 4b1e1d448f83f2f4b285667262bd2e326bbd37b0 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 23 Aug 2021 21:06:51 -0400 Subject: [PATCH 0278/1456] #6221 but for a different workflow (#6222) --- .github/workflows/arm64.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/arm64.yml b/.github/workflows/arm64.yml index f8be149af632..372bace94038 100644 --- a/.github/workflows/arm64.yml +++ b/.github/workflows/arm64.yml @@ -11,7 +11,7 @@ on: permissions: read-all concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true jobs: From f284cc86139d72ce3cfe3147523563ab57b0128c Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 24 Aug 2021 11:01:16 -0400 Subject: [PATCH 0279/1456] test against 1.1.1l (#6223) --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 60797299056d..8f343100698e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,9 +27,9 @@ jobs: - {VERSION: "pypy-3.6", TOXENV: "pypy3-nocoverage", COVERAGE: "false"} - {VERSION: "pypy-3.7", TOXENV: "pypy3-nocoverage", COVERAGE: "false"} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.0l"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k"}} - - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1l"}} + - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1l"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1l", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0-beta2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "2.9.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} From b9eda9f993eabc0114a38f17f9a5e27a537f1bce Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 24 Aug 2021 12:18:12 -0400 Subject: [PATCH 0280/1456] mention we support 3.0.0 (#6224) --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 429b3af61e8b..4304cf7baafe 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -18,6 +18,7 @@ Changelog accessed. * **BACKWARDS INCOMPATIBLE:** Values passed to the X.509 PEM parser must be a single PEM payload and will error on extraneous data. +* Added support for OpenSSL 3.0.0 as a compilation target. * Added support for :class:`~cryptography.hazmat.primitives.hashes.SM3` and :class:`~cryptography.hazmat.primitives.ciphers.algorithms.SM4`, From 69620d612690f5dbf66caacecb237170f5d599af Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 24 Aug 2021 13:45:21 -0400 Subject: [PATCH 0281/1456] port 3.4.8 changelog to main (#6226) --- CHANGELOG.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4304cf7baafe..39929f76ffe0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -29,6 +29,14 @@ Changelog * Added ``rfc4514_attribute_name`` attribute to :attr:`x509.NameAttribute `, +.. _v3-4-8: + +3.4.8 - 2021-08-24 +~~~~~~~~~~~~~~~~~~ + +* Updated Windows, macOS, and ``manylinux`` wheels to be compiled with + OpenSSL 1.1.1l. + .. _v3-4-7: 3.4.7 - 2021-03-25 From bb0575debe2dbb98b59eb896c46782f350788faf Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 25 Aug 2021 20:02:51 -0400 Subject: [PATCH 0282/1456] bump libre versions for test (#6230) --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8f343100698e..d671ddec620b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,8 +34,8 @@ jobs: - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "2.9.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.1.5"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.2.5"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.3.3"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.2.6"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.3.4"}} - {VERSION: "3.10-dev", TOXENV: "py310"} RUST: - stable From 93f733aeaa158bf00a5a52e65df0b259ddcb0d1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Aug 2021 08:33:25 -0400 Subject: [PATCH 0283/1456] Bump libc from 0.2.100 to 0.2.101 in /src/rust (#6231) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.100 to 0.2.101. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.100...0.2.101) --- updated-dependencies: - dependency-name: libc dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 2f87394760f7..4a5adc344a0d 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -121,9 +121,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5" +checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" [[package]] name = "lock_api" From 57fd59717951e7df4adc50d1c6499f3f641cef71 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Thu, 26 Aug 2021 14:24:41 +0100 Subject: [PATCH 0284/1456] add project_urls especially changelog (#6228) --- setup.cfg | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 000000000000..b3a64b77bfc5 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,6 @@ +[metadata] +project_urls = + Documentation=https://cryptography.io/ + Source=https://github.com/pyca/cryptography/ + Issues=https://github.com/pyca/cryptography/issues + Changelog=https://cryptography.io/en/latest/changelog/ From 3c2488b8a2f46bb897128eb0ae0bde5a2347b307 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 29 Aug 2021 09:43:38 -0400 Subject: [PATCH 0285/1456] Added a missing test case for x509 scts (#6237) --- tests/x509/test_ocsp.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/x509/test_ocsp.py b/tests/x509/test_ocsp.py index 0b8e49074cba..0dc36648c850 100644 --- a/tests/x509/test_ocsp.py +++ b/tests/x509/test_ocsp.py @@ -819,6 +819,22 @@ def test_hash(self, backend): assert hash(sct1) == hash(sct2) assert hash(sct1) != hash(sct3) + def test_entry_type(self, backend): + [sct, _, _, _] = ( + _load_data( + os.path.join("x509", "ocsp", "resp-sct-extension.der"), + ocsp.load_der_ocsp_response, + ) + .single_extensions.get_extension_for_class( + x509.SignedCertificateTimestamps + ) + .value + ) + assert ( + sct.entry_type + == x509.certificate_transparency.LogEntryType.X509_CERTIFICATE + ) + class TestOCSPResponse(object): def test_bad_response(self): From cd4ae74ef123f8ce14f00a0c85f48a4b3b1a7d1f Mon Sep 17 00:00:00 2001 From: match man Date: Sun, 29 Aug 2021 16:45:19 +0300 Subject: [PATCH 0286/1456] Add more demonstrative code to examples (#6234) 1. In signature generation code example, add a `key' assignment so it can be run solely. 2. In verify() code example, add a positive case before the negative one. Also use copy() to do self authentication. Co-authored-by: Baofeng Wang --- docs/hazmat/primitives/mac/hmac.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/hazmat/primitives/mac/hmac.rst b/docs/hazmat/primitives/mac/hmac.rst index 3695270b7ab2..5d44e1272d9b 100644 --- a/docs/hazmat/primitives/mac/hmac.rst +++ b/docs/hazmat/primitives/mac/hmac.rst @@ -28,10 +28,12 @@ of a message. .. doctest:: >>> from cryptography.hazmat.primitives import hashes, hmac + >>> key = b'test key. Beware! A real key should use os.urandom or TRNG to generate' >>> h = hmac.HMAC(key, hashes.SHA256()) >>> h.update(b"message to hash") - >>> h.finalize() - b'#F\xdaI\x8b"e\xc4\xf1\xbb\x9a\x8fc\xff\xf5\xdex.\xbc\xcd/+\x8a\x86\x1d\x84\'\xc3\xa6\x1d\xd8J' + >>> signature = h.finalize() + >>> signature + b'k\xd9\xb29\xefS\xf8\xcf\xec\xed\xbf\x95\xe6\x97X\x18\x9e%\x11DU1\x9fq}\x9a\x9c\xe0)y`=' If the backend doesn't support the requested ``algorithm`` an :class:`~cryptography.exceptions.UnsupportedAlgorithm` exception will be @@ -48,7 +50,10 @@ of a message. >>> h = hmac.HMAC(key, hashes.SHA256()) >>> h.update(b"message to hash") - >>> h.verify(b"an incorrect signature") + >>> h_copy = h.copy() # get a copy of `h' to be reused + >>> h.verify(signature) + >>> + >>> h_copy.verify(b"an incorrect signature") Traceback (most recent call last): ... cryptography.exceptions.InvalidSignature: Signature did not match digest. From 27374c62c7b2854ea22a01e9dd5894fa2ec77722 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 29 Aug 2021 10:05:32 -0400 Subject: [PATCH 0287/1456] FIPS 3.0.0 support (#6012) * FIPS 3.0.0 support * comments * remove unneeded error clear * review comments * small refactor * black * flake8 too * review feedback * oops * fix --- .github/workflows/build_openssl.sh | 12 ++++ .github/workflows/ci.yml | 7 +- src/_cffi_src/build_openssl.py | 3 +- src/_cffi_src/openssl/evp.py | 12 ++++ .../hazmat/backends/openssl/backend.py | 67 ++++++++++++++++--- .../hazmat/bindings/openssl/_conditional.py | 8 +++ .../hazmat/bindings/openssl/binding.py | 16 +++++ tests/conftest.py | 6 ++ tests/hazmat/primitives/test_dh.py | 2 + tests/hazmat/primitives/test_pkcs12.py | 10 ++- tests/hazmat/primitives/test_pkcs7.py | 10 ++- tests/hazmat/primitives/test_serialization.py | 18 ++++- tests/wycheproof/test_hmac.py | 2 +- tests/wycheproof/test_rsa.py | 7 ++ 14 files changed, 163 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build_openssl.sh b/.github/workflows/build_openssl.sh index 99c3f4d33805..440cdcecc69f 100755 --- a/.github/workflows/build_openssl.sh +++ b/.github/workflows/build_openssl.sh @@ -22,6 +22,18 @@ if [[ "${TYPE}" == "openssl" ]]; then # avoid installing the docs (for performance) # https://github.com/openssl/openssl/issues/6685#issuecomment-403838728 make install_sw install_ssldirs + # For OpenSSL 3.0.0 set up the FIPS config. This does not activate it by + # default, but allows programmatic activation at runtime + if [[ "${VERSION}" =~ 3.0.0 && "${CONFIG_FLAGS}" =~ enable-fips ]]; then + # As of alpha16 we have to install it separately and enable it in the config flags + make -j"$(nproc)" install_fips + pushd "${OSSL_PATH}" + # include the conf file generated as part of install_fips + sed -i "s:# .include fipsmodule.cnf:.include $(pwd)/ssl/fipsmodule.cnf:" ssl/openssl.cnf + # uncomment the FIPS section + sed -i 's:# fips = fips_sect:fips = fips_sect:' ssl/openssl.cnf + popd + fi popd elif [[ "${TYPE}" == "libressl" ]]; then curl -O "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${VERSION}.tar.gz" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d671ddec620b..0fb86db7f068 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,6 +31,7 @@ jobs: - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1l"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1l", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0-beta2"}} + - {VERSION: "3.9", TOXENV: "py39", TOXARGS: "--enable-fips=1", OPENSSL: {TYPE: "openssl", CONFIG_FLAGS: "enable-fips", VERSION: "3.0.0-beta2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "2.9.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.1.5"}} @@ -39,7 +40,7 @@ jobs: - {VERSION: "3.10-dev", TOXENV: "py310"} RUST: - stable - name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" + name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.TOXARGS }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" timeout-minutes: 20 steps: - uses: actions/checkout@v2.3.4 @@ -86,7 +87,7 @@ jobs: path: ${{ github.workspace }}/osslcache # When altering the openssl build process you may need to increment the value on the end of this cache key # so that you can prevent it from fetching the cache and skipping the build step. - key: ${{ matrix.PYTHON.OPENSSL.TYPE }}-${{ matrix.PYTHON.OPENSSL.VERSION }}-${{ env.CONFIG_HASH }}-1 + key: ${{ matrix.PYTHON.OPENSSL.TYPE }}-${{ matrix.PYTHON.OPENSSL.VERSION }}-${{ env.CONFIG_HASH }}-2 if: matrix.PYTHON.OPENSSL - name: Build custom OpenSSL/LibreSSL run: .github/workflows/build_openssl.sh @@ -101,7 +102,7 @@ jobs: if: matrix.PYTHON.OPENSSL - name: Tests run: | - tox -r -- --color=yes --wycheproof-root=wycheproof + tox -r -- --color=yes --wycheproof-root=wycheproof ${{ matrix.PYTHON.TOXARGS }} env: TOXENV: ${{ matrix.PYTHON.TOXENV }} CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py index df11130371d1..04d6d4611b33 100644 --- a/src/_cffi_src/build_openssl.py +++ b/src/_cffi_src/build_openssl.py @@ -79,6 +79,8 @@ def _extra_compile_args(platform): modules=[ # This goes first so we can define some cryptography-wide symbols. "cryptography", + # Provider comes early as well so we define OSSL_LIB_CTX + "provider", "aes", "asn1", "bignum", @@ -103,7 +105,6 @@ def _extra_compile_args(platform): "osrandom_engine", "pem", "pkcs12", - "provider", "rand", "rsa", "ssl", diff --git a/src/_cffi_src/openssl/evp.py b/src/_cffi_src/openssl/evp.py index 2b2f995e389f..735b8c37cfa2 100644 --- a/src/_cffi_src/openssl/evp.py +++ b/src/_cffi_src/openssl/evp.py @@ -36,6 +36,7 @@ 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; +static const long Cryptography_HAS_300_FIPS; """ FUNCTIONS = """ @@ -165,6 +166,9 @@ 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 *); + +int EVP_default_properties_is_fips_enabled(OSSL_LIB_CTX *); +int EVP_default_properties_enable_fips(OSSL_LIB_CTX *, int); """ CUSTOMIZATIONS = """ @@ -269,4 +273,12 @@ #ifndef EVP_PKEY_POLY1305 #define EVP_PKEY_POLY1305 NID_poly1305 #endif + +#if CRYPTOGRAPHY_OPENSSL_300_OR_GREATER +static const long Cryptography_HAS_300_FIPS = 1; +#else +static const long Cryptography_HAS_300_FIPS = 0; +int (*EVP_default_properties_is_fips_enabled)(OSSL_LIB_CTX *) = NULL; +int (*EVP_default_properties_enable_fips)(OSSL_LIB_CTX *, int) = NULL; +#endif """ diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 3603a1c34adb..1a1db1ccca60 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -157,8 +157,9 @@ class Backend(BackendInterface): b"aes-256-gcm", } _fips_ciphers = (AES, TripleDES) + # Sometimes SHA1 is still permissible. That logic is contained + # within the various *_supported methods. _fips_hashes = ( - hashes.SHA1, hashes.SHA224, hashes.SHA256, hashes.SHA384, @@ -172,6 +173,12 @@ class Backend(BackendInterface): hashes.SHAKE128, hashes.SHAKE256, ) + _fips_ecdh_curves = ( + ec.SECP224R1, + ec.SECP256R1, + ec.SECP384R1, + ec.SECP521R1, + ) _fips_rsa_min_key_size = 2048 _fips_rsa_min_public_exponent = 65537 _fips_dsa_min_modulus = 1 << 2048 @@ -200,17 +207,34 @@ def __init__(self): if self._lib.Cryptography_HAS_EVP_PKEY_DHX: self._dh_types.append(self._lib.EVP_PKEY_DHX) + def __repr__(self): + return "".format( + self.openssl_version_text(), self._fips_enabled + ) + def openssl_assert(self, ok, errors=None): return binding._openssl_assert(self._lib, ok, errors=errors) def _is_fips_enabled(self): - fips_mode = getattr(self._lib, "FIPS_mode", lambda: 0) - mode = fips_mode() + if self._lib.Cryptography_HAS_300_FIPS: + mode = self._lib.EVP_default_properties_is_fips_enabled( + self._ffi.NULL + ) + else: + mode = getattr(self._lib, "FIPS_mode", lambda: 0)() + if mode == 0: # OpenSSL without FIPS pushes an error on the error stack self._lib.ERR_clear_error() return bool(mode) + def _enable_fips(self): + # This function enables FIPS mode for OpenSSL 3.0.0 on installs that + # have the FIPS provider installed properly. + self._binding._enable_fips() + assert self._is_fips_enabled() + self._fips_enabled = self._is_fips_enabled() + def activate_builtin_random(self): if self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: # Obtain a new structural reference. @@ -306,17 +330,31 @@ def hash_supported(self, algorithm): return evp_md != self._ffi.NULL def scrypt_supported(self): - return self._lib.Cryptography_HAS_SCRYPT == 1 + if self._fips_enabled: + return False + else: + return self._lib.Cryptography_HAS_SCRYPT == 1 def hmac_supported(self, algorithm): + # FIPS mode still allows SHA1 for HMAC + if self._fips_enabled and isinstance(algorithm, hashes.SHA1): + return True + return self.hash_supported(algorithm) def create_hash_ctx(self, algorithm): return _HashContext(self, algorithm) def cipher_supported(self, cipher, mode): - if self._fips_enabled and not isinstance(cipher, self._fips_ciphers): - return False + if self._fips_enabled: + # FIPS mode requires AES or TripleDES, but only CBC/ECB allowed + # in TripleDES mode. + if not isinstance(cipher, self._fips_ciphers) or ( + isinstance(cipher, TripleDES) + and not isinstance(mode, (CBC, ECB)) + ): + return False + try: adapter = self._cipher_registry[type(cipher), type(mode)] except KeyError: @@ -720,7 +758,13 @@ def rsa_padding_supported(self, padding): if isinstance(padding, PKCS1v15): return True elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1): - return self.hash_supported(padding._mgf._algorithm) + # SHA1 is permissible in MGF1 in FIPS + if self._fips_enabled and isinstance( + padding._mgf._algorithm, hashes.SHA1 + ): + return True + else: + return self.hash_supported(padding._mgf._algorithm) elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1): return ( self._oaep_hash_supported(padding._mgf._algorithm) @@ -1489,10 +1533,12 @@ def _handle_key_loading_error(self): raise ValueError("Unsupported public key algorithm.") else: + errors = binding._errors_with_text(errors) raise ValueError( "Could not deserialize key data. The data may be in an " "incorrect format or it may be encrypted with an unsupported " - "algorithm." + "algorithm.", + errors, ) def elliptic_curve_supported(self, curve): @@ -1777,6 +1823,11 @@ def create_ocsp_response( return _OCSPResponse(self, ocsp_resp) def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve): + if self._fips_enabled and not isinstance( + curve, self._fips_ecdh_curves + ): + return False + return self.elliptic_curve_supported(curve) and isinstance( algorithm, ec.ECDH ) diff --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py index 912aff302607..5f403e610ebf 100644 --- a/src/cryptography/hazmat/bindings/openssl/_conditional.py +++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py @@ -254,6 +254,13 @@ def cryptography_has_dtls_get_data_mtu(): ] +def cryptography_has_300_fips(): + return [ + "EVP_default_properties_is_fips_enabled", + "EVP_default_properties_enable_fips", + ] + + # 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 @@ -305,4 +312,5 @@ def cryptography_has_dtls_get_data_mtu(): cryptography_has_op_no_renegotiation ), "Cryptography_HAS_DTLS_GET_DATA_MTU": cryptography_has_dtls_get_data_mtu, + "Cryptography_HAS_300_FIPS": cryptography_has_300_fips, } diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py index f651ab672383..92d5b2448a48 100644 --- a/src/cryptography/hazmat/bindings/openssl/binding.py +++ b/src/cryptography/hazmat/bindings/openssl/binding.py @@ -116,6 +116,22 @@ class Binding(object): def __init__(self): self._ensure_ffi_initialized() + def _enable_fips(self): + # This function enables FIPS mode for OpenSSL 3.0.0 on installs that + # have the FIPS provider installed properly. + _openssl_assert(self.lib, self.lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER) + self._base_provider = self.lib.OSSL_PROVIDER_load( + self.ffi.NULL, b"base" + ) + _openssl_assert(self.lib, self._base_provider != self.ffi.NULL) + self.lib._fips_provider = self.lib.OSSL_PROVIDER_load( + self.ffi.NULL, b"fips" + ) + _openssl_assert(self.lib, self.lib._fips_provider != self.ffi.NULL) + + res = self.lib.EVP_default_properties_enable_fips(self.ffi.NULL, 1) + _openssl_assert(self.lib, res == 1) + @classmethod def _register_osrandom_engine(cls): # Clear any errors extant in the queue before we start. In many diff --git a/tests/conftest.py b/tests/conftest.py index 01aba7784586..b2f963c534d6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,6 +10,11 @@ from .utils import check_backend_support +def pytest_configure(config): + if config.getoption("--enable-fips"): + openssl_backend._enable_fips() + + def pytest_report_header(config): return "\n".join( [ @@ -21,6 +26,7 @@ def pytest_report_header(config): def pytest_addoption(parser): parser.addoption("--wycheproof-root", default=None) + parser.addoption("--enable-fips", default=False) def pytest_runtest_setup(item): diff --git a/tests/hazmat/primitives/test_dh.py b/tests/hazmat/primitives/test_dh.py index 7efc09456e6d..29b77543c20a 100644 --- a/tests/hazmat/primitives/test_dh.py +++ b/tests/hazmat/primitives/test_dh.py @@ -663,6 +663,7 @@ def test_public_bytes(self, backend, encoding, loader_func): pub_num = key.public_numbers() assert loaded_pub_num == pub_num + @pytest.mark.skip_fips(reason="non-FIPS parameters") @pytest.mark.parametrize( ("key_path", "loader_func", "encoding", "is_dhx"), [ @@ -706,6 +707,7 @@ def test_public_bytes_match( ) assert serialized == key_bytes + @pytest.mark.skip_fips(reason="non-FIPS parameters") @pytest.mark.parametrize( ("key_path", "loader_func", "vec_path", "is_dhx"), [ diff --git a/tests/hazmat/primitives/test_pkcs12.py b/tests/hazmat/primitives/test_pkcs12.py index f99c121d9554..62006643769c 100644 --- a/tests/hazmat/primitives/test_pkcs12.py +++ b/tests/hazmat/primitives/test_pkcs12.py @@ -22,6 +22,9 @@ from ...doubles import DummyKeySerializationEncryption +@pytest.mark.skip_fips( + reason="PKCS12 unsupported in FIPS mode. So much bad crypto in it." +) class TestPKCS12Loading(object): def _test_load_pkcs12_ec_keys(self, filename, password, backend): cert = load_vectors_from_file( @@ -70,7 +73,6 @@ def test_load_pkcs12_ec_keys(self, filename, password, backend): only_if=lambda backend: backend.cipher_supported(_RC2(), None), skip_message="Does not support RC2", ) - @pytest.mark.skip_fips(reason="Unsupported algorithm in FIPS mode") def test_load_pkcs12_ec_keys_rc2(self, filename, password, backend): self._test_load_pkcs12_ec_keys(filename, password, backend) @@ -167,6 +169,9 @@ def _load_ca(backend): return cert, key +@pytest.mark.skip_fips( + reason="PKCS12 unsupported in FIPS mode. So much bad crypto in it." +) class TestPKCS12Creation(object): @pytest.mark.parametrize("name", [None, b"name"]) @pytest.mark.parametrize( @@ -275,6 +280,9 @@ def test_generate_unsupported_encryption_type(self, backend): assert str(exc.value) == "Unsupported key encryption type" +@pytest.mark.skip_fips( + reason="PKCS12 unsupported in FIPS mode. So much bad crypto in it." +) def test_pkcs12_ordering(): """ In OpenSSL < 3.0.0 PKCS12 parsing reverses the order. However, we diff --git a/tests/hazmat/primitives/test_pkcs7.py b/tests/hazmat/primitives/test_pkcs7.py index 60aa367dde09..519c01b57449 100644 --- a/tests/hazmat/primitives/test_pkcs7.py +++ b/tests/hazmat/primitives/test_pkcs7.py @@ -335,6 +335,9 @@ def test_sign_pem(self, backend): def test_sign_alternate_digests_der( self, hash_alg, expected_value, backend ): + if isinstance(hash_alg, hashes.SHA1) and backend._fips_enabled: + pytest.skip("SHA1 not supported in FIPS mode") + data = b"hello world" cert, key = _load_cert_key() builder = ( @@ -358,7 +361,12 @@ def test_sign_alternate_digests_der( (hashes.SHA512(), b"sha-512"), ], ) - def test_sign_alternate_digests_detached(self, hash_alg, expected_value): + def test_sign_alternate_digests_detached( + self, hash_alg, expected_value, backend + ): + if isinstance(hash_alg, hashes.SHA1) and backend._fips_enabled: + pytest.skip("SHA1 not supported in FIPS mode") + data = b"hello world" cert, key = _load_cert_key() builder = ( diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index ed3f8e7f8f05..5c845018437d 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -52,8 +52,19 @@ def _skip_fips_format(key_path, password, backend): if backend._fips_enabled: if key_path[0] == "Traditional_OpenSSL_Serialization": pytest.skip("Traditional OpenSSL format blocked in FIPS mode") - if key_path[0] == "PEM_Serialization" and password is not None: - pytest.skip("Encrypted PEM_Serialization blocked in FIPS mode") + if ( + key_path[0] in ("PEM_Serialization", "PKCS8") + and password is not None + ): + pytest.skip( + "The encrypted PEM vectors currently have encryption " + "that is not FIPS approved in the 3.0 provider" + ) + if key_path[0] == "DER_Serialization" and password is not None: + pytest.skip( + "The encrypted PKCS8 DER vectors currently have encryption " + "that is not FIPS approved in the 3.0 provider" + ) class TestBufferProtocolSerialization(object): @@ -67,6 +78,7 @@ class TestBufferProtocolSerialization(object): ], ) def test_load_der_rsa_private_key(self, key_path, password, backend): + _skip_fips_format(key_path, password, backend) data = load_vectors_from_file( os.path.join("asymmetric", *key_path), lambda derfile: derfile.read(), @@ -117,6 +129,7 @@ class TestDERSerialization(object): ], ) def test_load_der_rsa_private_key(self, key_path, password, backend): + _skip_fips_format(key_path, password, backend) key = load_vectors_from_file( os.path.join("asymmetric", *key_path), lambda derfile: load_der_private_key( @@ -814,6 +827,7 @@ def test_pks8_encrypted_corrupt_format(self, backend): with pytest.raises(ValueError): load_pem_private_key(key_data, password, backend) + @pytest.mark.skip_fips(reason="non-FIPS parameters") def test_rsa_pkcs8_encrypted_values(self, backend): pkey = load_vectors_from_file( os.path.join("asymmetric", "PKCS8", "enc-rsa-pkcs8.pem"), diff --git a/tests/wycheproof/test_hmac.py b/tests/wycheproof/test_hmac.py index bfc690795122..84b0c19a0539 100644 --- a/tests/wycheproof/test_hmac.py +++ b/tests/wycheproof/test_hmac.py @@ -41,7 +41,7 @@ def test_hmac(backend, wycheproof): hash_algo = _HMAC_ALGORITHMS[wycheproof.testfiledata["algorithm"]] if wycheproof.testgroup["tagSize"] // 8 != hash_algo.digest_size: pytest.skip("Truncated HMAC not supported") - if not backend.hash_supported(hash_algo): + if not backend.hmac_supported(hash_algo): pytest.skip("Hash {} not supported".format(hash_algo.name)) h = hmac.HMAC( diff --git a/tests/wycheproof/test_rsa.py b/tests/wycheproof/test_rsa.py index 73ff711154d9..79fd682b7e70 100644 --- a/tests/wycheproof/test_rsa.py +++ b/tests/wycheproof/test_rsa.py @@ -102,6 +102,13 @@ def test_rsa_pkcs1v15_signature_generation(backend, wycheproof): assert isinstance(key, rsa.RSAPrivateKey) digest = _DIGESTS[wycheproof.testgroup["sha"]] assert digest is not None + if backend._fips_enabled: + if key.key_size < 2048 or isinstance(digest, hashes.SHA1): + pytest.skip( + "Invalid params for FIPS. key: {} bits, digest: {}".format( + key.key_size, digest.name + ) + ) sig = key.sign( binascii.unhexlify(wycheproof.testcase["msg"]), From 5b966396a255cdb0f8e90f998c7e42b11ffdecd8 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 29 Aug 2021 10:19:36 -0400 Subject: [PATCH 0288/1456] split flake, rust, and docs jobs back into separate CI jobs (#6238) we previously combined these to simplify our CI matrix, but it's difficult to read the output and now that we have auto-cancellation job proliferation isn't really an issue. Reverting --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0fb86db7f068..fec19064ae39 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,9 @@ jobs: fail-fast: false matrix: PYTHON: - - {VERSION: "3.9", TOXENV: "flake,rust,docs", COVERAGE: "false"} + - {VERSION: "3.9", TOXENV: "flake", COVERAGE: "false"} + - {VERSION: "3.9", TOXENV: "rust", COVERAGE: "false"} + - {VERSION: "3.9", TOXENV: "docs", COVERAGE: "false"} - {VERSION: "pypy-3.6", TOXENV: "pypy3-nocoverage", COVERAGE: "false"} - {VERSION: "pypy-3.7", TOXENV: "pypy3-nocoverage", COVERAGE: "false"} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.0l"}} From eb6f658e5fccf0f5a66e1d6bdb4dda4ced5c6aa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mathias=20Panzenb=C3=B6ck?= Date: Sun, 29 Aug 2021 19:43:16 +0200 Subject: [PATCH 0289/1456] add PKCS7_get0_signers(), X509_STORE_set_purpose(), and X509_PURPOSE_* (#6187) * add PKCS7_get0_signers(), X509_STORE_set_purpose(), and X509_PURPOSE_* * removed argument names of X509_STORE_set_purpose() and PKCS7_get0_signers() * Update pkcs7.py * Update x509_vfy.py Co-authored-by: Paul Kehrer --- src/_cffi_src/openssl/pkcs7.py | 5 +++++ src/_cffi_src/openssl/x509_vfy.py | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/_cffi_src/openssl/pkcs7.py b/src/_cffi_src/openssl/pkcs7.py index 052bd050819f..b58b293a5c0c 100644 --- a/src/_cffi_src/openssl/pkcs7.py +++ b/src/_cffi_src/openssl/pkcs7.py @@ -68,6 +68,11 @@ int PKCS7_verify(PKCS7 *, Cryptography_STACK_OF_X509 *, X509_STORE *, BIO *, BIO *, int); PKCS7 *SMIME_read_PKCS7(BIO *, BIO **); +/* Included due to external consumer, see + https://github.com/pyca/pyopenssl/issues/1031 */ +Cryptography_STACK_OF_X509 *PKCS7_get0_signers(PKCS7 *, + Cryptography_STACK_OF_X509 *, + int); int PKCS7_type_is_signed(PKCS7 *); int PKCS7_type_is_enveloped(PKCS7 *); diff --git a/src/_cffi_src/openssl/x509_vfy.py b/src/_cffi_src/openssl/x509_vfy.py index 4642d827765c..16c0ae0beb50 100644 --- a/src/_cffi_src/openssl/x509_vfy.py +++ b/src/_cffi_src/openssl/x509_vfy.py @@ -124,6 +124,20 @@ 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; + +/* Included due to external consumer, see + https://github.com/pyca/pyopenssl/issues/1031 */ +static const long X509_PURPOSE_SSL_CLIENT; +static const long X509_PURPOSE_SSL_SERVER; +static const long X509_PURPOSE_NS_SSL_SERVER; +static const long X509_PURPOSE_SMIME_SIGN; +static const long X509_PURPOSE_SMIME_ENCRYPT; +static const long X509_PURPOSE_CRL_SIGN; +static const long X509_PURPOSE_ANY; +static const long X509_PURPOSE_OCSP_HELPER; +static const long X509_PURPOSE_TIMESTAMP_SIGN; +static const long X509_PURPOSE_MIN; +static const long X509_PURPOSE_MAX; """ FUNCTIONS = """ @@ -137,6 +151,9 @@ int X509_STORE_set1_param(X509_STORE *, X509_VERIFY_PARAM *); int X509_STORE_set_default_paths(X509_STORE *); int X509_STORE_set_flags(X509_STORE *, unsigned long); +/* Included due to external consumer, see + https://github.com/pyca/pyopenssl/issues/1031 */ +int X509_STORE_set_purpose(X509_STORE *, int); void X509_STORE_free(X509_STORE *); /* X509_STORE_CTX */ From b5c3bd213099b6e35c30bee5d37258b5f084b901 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 29 Aug 2021 14:18:18 -0500 Subject: [PATCH 0290/1456] turn on mypy disallow implicit reexport and fix issues (#6240) * turn on mypy disallow implicit reexport and fix issues * import ordering --- pyproject.toml | 1 + src/cryptography/hazmat/primitives/asymmetric/padding.py | 4 +++- src/cryptography/hazmat/primitives/ciphers/base.py | 4 +++- src/cryptography/x509/__init__.py | 2 ++ src/cryptography/x509/base.py | 4 ++-- tests/hazmat/primitives/test_pkcs12.py | 2 +- tests/hazmat/primitives/test_pkcs7.py | 3 +-- tests/hazmat/primitives/test_serialization.py | 2 +- 8 files changed, 14 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 913a4e46d1c1..cffd317087d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ markers = [ [tool.mypy] show_error_codes = true check_untyped_defs = true +no_implicit_reexport = true [[tool.mypy.overrides]] module = [ diff --git a/src/cryptography/hazmat/primitives/asymmetric/padding.py b/src/cryptography/hazmat/primitives/asymmetric/padding.py index 301c64c92898..a97c5db09177 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/padding.py +++ b/src/cryptography/hazmat/primitives/asymmetric/padding.py @@ -6,7 +6,9 @@ import typing from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding +from cryptography.hazmat.primitives._asymmetric import ( + AsymmetricPadding as AsymmetricPadding, +) from cryptography.hazmat.primitives.asymmetric import rsa diff --git a/src/cryptography/hazmat/primitives/ciphers/base.py b/src/cryptography/hazmat/primitives/ciphers/base.py index 7261a275b42e..ad3c7ed8fdc4 100644 --- a/src/cryptography/hazmat/primitives/ciphers/base.py +++ b/src/cryptography/hazmat/primitives/ciphers/base.py @@ -16,7 +16,9 @@ ) from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import Backend, CipherBackend -from cryptography.hazmat.primitives._cipheralgorithm import CipherAlgorithm +from cryptography.hazmat.primitives._cipheralgorithm import ( + CipherAlgorithm as CipherAlgorithm, +) from cryptography.hazmat.primitives.ciphers import modes diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py index 793714693040..5003e09d3fa9 100644 --- a/src/cryptography/x509/__init__.py +++ b/src/cryptography/x509/__init__.py @@ -244,4 +244,6 @@ "PrecertPoison", "OCSPNonce", "SignedCertificateTimestamps", + "SignatureAlgorithmOID", + "NameOID", ] diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index 3c626efc57cf..0e8154425f5d 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -21,8 +21,8 @@ rsa, ) from cryptography.hazmat.primitives.asymmetric.types import ( - PRIVATE_KEY_TYPES, - PUBLIC_KEY_TYPES, + PRIVATE_KEY_TYPES as PRIVATE_KEY_TYPES, + PUBLIC_KEY_TYPES as PUBLIC_KEY_TYPES, ) from cryptography.x509.extensions import Extension, ExtensionType, Extensions from cryptography.x509.name import Name diff --git a/tests/hazmat/primitives/test_pkcs12.py b/tests/hazmat/primitives/test_pkcs12.py index 62006643769c..47262e5e1922 100644 --- a/tests/hazmat/primitives/test_pkcs12.py +++ b/tests/hazmat/primitives/test_pkcs12.py @@ -18,8 +18,8 @@ serialize_key_and_certificates, ) -from .utils import load_vectors_from_file from ...doubles import DummyKeySerializationEncryption +from ...utils import load_vectors_from_file @pytest.mark.skip_fips( diff --git a/tests/hazmat/primitives/test_pkcs7.py b/tests/hazmat/primitives/test_pkcs7.py index 519c01b57449..f90fd1810b8f 100644 --- a/tests/hazmat/primitives/test_pkcs7.py +++ b/tests/hazmat/primitives/test_pkcs7.py @@ -14,8 +14,7 @@ from cryptography.hazmat.primitives.asymmetric import ed25519 from cryptography.hazmat.primitives.serialization import pkcs7 -from .utils import load_vectors_from_file -from ...utils import raises_unsupported_algorithm +from ...utils import load_vectors_from_file, raises_unsupported_algorithm class TestPKCS7Loading(object): diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 5c845018437d..c9b8fd641840 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -43,9 +43,9 @@ from .utils import ( _check_dsa_private_numbers, _check_rsa_private_numbers, - load_vectors_from_file, ) from ...doubles import DummyKeySerializationEncryption +from ...utils import load_vectors_from_file def _skip_fips_format(key_path, password, backend): From 4dbac5c5c716827edc557774038280b280d31643 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 29 Aug 2021 15:35:20 -0400 Subject: [PATCH 0291/1456] Use action to clone wycheproof for consistency (#6241) --- .github/workflows/ci.yml | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fec19064ae39..f1f9619cf374 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,7 +68,10 @@ jobs: toolchain: ${{ matrix.RUST }} override: true default: true - - run: git clone --depth=1 https://github.com/google/wycheproof + - uses: actions/checkout@v2.3.4 + with: + repository: "google/wycheproof" + path: "wycheproof" - run: python -m pip install tox requests coverage - name: Compute config hash and set config vars run: | @@ -147,12 +150,15 @@ jobs: src/rust/target/ key: ${{ runner.os }}-${{ matrix.IMAGE.IMAGE }}-cargo-2-${{ hashFiles('**/Cargo.lock') }} - - run: 'git clone --depth=1 https://github.com/google/wycheproof "$HOME/wycheproof"' + - uses: actions/checkout@v2.3.4 + with: + repository: "google/wycheproof" + path: "wycheproof" - run: | echo "OPENSSL_FORCE_FIPS_MODE=1" >> $GITHUB_ENV echo "CFLAGS=-DUSE_OSRANDOM_RNG_FOR_TESTING" >> $GITHUB_ENV if: matrix.IMAGE.FIPS - - run: 'tox -- --wycheproof-root="$HOME/wycheproof"' + - run: 'tox -- --wycheproof-root="wycheproof"' env: TOXENV: ${{ matrix.IMAGE.TOXENV }} RUSTUP_HOME: /root/.rustup @@ -200,7 +206,10 @@ jobs: toolchain: ${{ matrix.RUST }} override: true default: true - - run: git clone --depth=1 https://github.com/google/wycheproof + - uses: actions/checkout@v2.3.4 + with: + repository: "google/wycheproof" + path: "wycheproof" - run: python -m pip install tox coverage - name: Tests run: | @@ -248,7 +257,10 @@ jobs: version: latest if: steps.cargo-cache.outputs.cache-hit != 'true' - - run: git clone --depth=1 https://github.com/google/wycheproof + - uses: actions/checkout@v2.3.4 + with: + repository: "google/wycheproof" + path: "wycheproof" - run: python -m pip install tox coverage - name: Tests run: | @@ -314,7 +326,10 @@ jobs: - run: python -m pip install tox requests coverage - - run: git clone https://github.com/google/wycheproof + - uses: actions/checkout@v2.3.4 + with: + repository: "google/wycheproof" + path: "wycheproof" - name: Download OpenSSL run: | @@ -390,7 +405,10 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} shell: bash - - run: git clone https://github.com/google/wycheproof + - uses: actions/checkout@v2.3.4 + with: + repository: "google/wycheproof" + path: "wycheproof" - run: tox -r -- --color=yes --wycheproof-root=wycheproof --num-shards=4 --shard-id=${{ matrix.JOB_NUMBER }} env: From 4b2a3d630c3b4c8895c2e8199a183f260a4b3569 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 29 Aug 2021 16:05:47 -0400 Subject: [PATCH 0292/1456] same as #6241 but for arm64 (#6242) --- .github/workflows/arm64.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/arm64.yml b/.github/workflows/arm64.yml index 372bace94038..39fe46517ec8 100644 --- a/.github/workflows/arm64.yml +++ b/.github/workflows/arm64.yml @@ -41,8 +41,11 @@ jobs: src/rust/target/ key: ${{ runner.os }}-${{ matrix.IMAGE.IMAGE }}-cargo-2-${{ hashFiles('**/Cargo.lock') }} - - run: 'git clone --depth=1 https://github.com/google/wycheproof "$HOME/wycheproof"' - - run: 'tox -- --wycheproof-root="$HOME/wycheproof"' + - uses: actions/checkout@v2.3.4 + with: + repository: "google/wycheproof" + path: "wycheproof" + - run: 'tox -- --wycheproof-root="wycheproof"' env: TOXENV: ${{ matrix.IMAGE.TOXENV }} RUSTUP_HOME: /root/.rustup From e703fb9f3a8114513481f032913e73b09fc509c8 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 29 Aug 2021 16:38:34 -0500 Subject: [PATCH 0293/1456] Port most of setup.py to setup.cfg (#6239) * try porting over setup.py config * reduce duplication * flake * move long_description, remove more lines from setup.py --- setup.cfg | 82 ++++++++++++++++++++++++++++++ setup.py | 94 +---------------------------------- src/cryptography/__about__.py | 15 ------ src/cryptography/__init__.py | 10 ---- 4 files changed, 84 insertions(+), 117 deletions(-) diff --git a/setup.cfg b/setup.cfg index b3a64b77bfc5..b8c396964a45 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,88 @@ [metadata] +name = cryptography +version = attr: cryptography.__version__ +description = cryptography is a package which provides cryptographic recipes and primitives to Python developers. +long_description = file: README.rst +long_description_content_type = text/x-rst +license = BSD or Apache License, Version 2.0 +url = https://github.com/pyca/cryptography +author = The Python Cryptographic Authority and individual contributors +author_email = cryptography-dev@python.org project_urls = Documentation=https://cryptography.io/ Source=https://github.com/pyca/cryptography/ Issues=https://github.com/pyca/cryptography/issues Changelog=https://cryptography.io/en/latest/changelog/ +classifiers = + Development Status :: 5 - Production/Stable + Intended Audience :: Developers + License :: OSI Approved :: Apache Software License + License :: OSI Approved :: BSD License + Natural Language :: English + Operating System :: MacOS :: MacOS X + Operating System :: POSIX + Operating System :: POSIX :: BSD + Operating System :: POSIX :: Linux + Operating System :: Microsoft :: Windows + Programming Language :: Python + Programming Language :: Python :: 3 + Programming Language :: Python :: 3 :: Only + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + Programming Language :: Python :: Implementation :: CPython + Programming Language :: Python :: Implementation :: PyPy + Topic :: Security :: Cryptography + +[options] +python_requires = >=3.6 +include_package_data = True +zip_safe = False +package_dir = + =src +packages = find: +ext_package = cryptography.hazmat.bindings +# `install_requires` and `setup_requires` must be kept in sync with +# `pyproject.toml` +install_requires = + cffi >=1.12 +setup_requires = + cffi >=1.12 + setuptools_rust >= 0.11.4 + +[options.packages.find] +where = src +exclude = + _cffi_src + _cffi_src.* + +[options.extras_require] +test = + pytest>=6.2.0 + pytest-cov + pytest-subtests + pytest-xdist + pretend + iso8601 + pytz + hypothesis>=1.11.4,!=3.79.2 +docs = + sphinx >= 1.6.5,!=1.8.0,!=3.1.0,!=3.1.1 + sphinx_rtd_theme +docstest = + doc8 + pyenchant >= 1.6.11 + twine >= 1.12.0 + sphinxcontrib-spelling >= 4.0.1 +sdist = + setuptools_rust >= 0.11.4 +pep8test = + black + flake8 + flake8-import-order + pep8-naming +# This extra is for OpenSSH private keys that use bcrypt KDF +# Versions: v3.1.3 - ignore_few_rounds, v3.1.5 - abi3 +ssh = + bcrypt >= 3.1.5 \ No newline at end of file diff --git a/setup.py b/setup.py index 51ce120ed25f..f91c04cfc895 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ import platform import sys -from setuptools import find_packages, setup +from setuptools import setup try: from setuptools_rust import RustExtension @@ -34,99 +34,9 @@ # means that we need to add the src/ directory to the sys.path. sys.path.insert(0, src_dir) -about = {} -with open(os.path.join(src_dir, "cryptography", "__about__.py")) as f: - exec(f.read(), about) - - -# `install_requirements` and `setup_requirements` must be kept in sync with -# `pyproject.toml` -setuptools_rust = "setuptools-rust>=0.11.4" -install_requirements = ["cffi>=1.12"] -setup_requirements = install_requirements + [setuptools_rust] - -with open(os.path.join(base_dir, "README.rst")) as f: - long_description = f.read() - - try: + # See setup.cfg for most of the config metadata. setup( - name=about["__title__"], - version=about["__version__"], - description=about["__summary__"], - long_description=long_description, - long_description_content_type="text/x-rst", - license=about["__license__"], - url=about["__uri__"], - author=about["__author__"], - author_email=about["__email__"], - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "License :: OSI Approved :: Apache Software License", - "License :: OSI Approved :: BSD License", - "Natural Language :: English", - "Operating System :: MacOS :: MacOS X", - "Operating System :: POSIX", - "Operating System :: POSIX :: BSD", - "Operating System :: POSIX :: Linux", - "Operating System :: Microsoft :: Windows", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", - "Topic :: Security :: Cryptography", - ], - package_dir={"": "src"}, - packages=find_packages( - where="src", exclude=["_cffi_src", "_cffi_src.*"] - ), - include_package_data=True, - python_requires=">=3.6", - install_requires=install_requirements, - setup_requires=setup_requirements, - extras_require={ - "test": [ - "pytest>=6.2.0", - "pytest-cov", - "pytest-subtests", - "pytest-xdist", - "pretend", - "iso8601", - "pytz", - "hypothesis>=1.11.4,!=3.79.2", - ], - "docs": [ - "sphinx >= 1.6.5,!=1.8.0,!=3.1.0,!=3.1.1", - "sphinx_rtd_theme", - ], - "docstest": [ - "doc8", - "pyenchant >= 1.6.11", - "twine >= 1.12.0", - "sphinxcontrib-spelling >= 4.0.1", - ], - "sdist": [ - setuptools_rust, - ], - "pep8test": [ - "black", - "flake8", - "flake8-import-order", - "pep8-naming", - ], - # This extra is for OpenSSH private keys that use bcrypt KDF - # Versions: v3.1.3 - ignore_few_rounds, v3.1.5 - abi3 - "ssh": ["bcrypt >= 3.1.5"], - }, - # for cffi - zip_safe=False, - ext_package="cryptography.hazmat.bindings", cffi_modules=[ "src/_cffi_src/build_openssl.py:ffi", ], diff --git a/src/cryptography/__about__.py b/src/cryptography/__about__.py index a035fa12ffd2..7dd3030517c0 100644 --- a/src/cryptography/__about__.py +++ b/src/cryptography/__about__.py @@ -4,27 +4,12 @@ __all__ = [ - "__title__", - "__summary__", - "__uri__", "__version__", "__author__", - "__email__", - "__license__", "__copyright__", ] -__title__ = "cryptography" -__summary__ = ( - "cryptography is a package which provides cryptographic recipes" - " and primitives to Python developers." -) -__uri__ = "https://github.com/pyca/cryptography" - __version__ = "35.0.0.dev1" __author__ = "The Python Cryptographic Authority and individual contributors" -__email__ = "cryptography-dev@python.org" - -__license__ = "BSD or Apache License, Version 2.0" __copyright__ = "Copyright 2013-2021 {}".format(__author__) diff --git a/src/cryptography/__init__.py b/src/cryptography/__init__.py index 15e7835e1d2f..983b6018c68d 100644 --- a/src/cryptography/__init__.py +++ b/src/cryptography/__init__.py @@ -6,22 +6,12 @@ from cryptography.__about__ import ( __author__, __copyright__, - __email__, - __license__, - __summary__, - __title__, - __uri__, __version__, ) __all__ = [ - "__title__", - "__summary__", - "__uri__", "__version__", "__author__", - "__email__", - "__license__", "__copyright__", ] From efc37b4a23eb51f6ae80c0ac496ab25911c2a714 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 29 Aug 2021 17:07:54 -0500 Subject: [PATCH 0294/1456] convert cryptography_vectors to setup.cfg (#6243) * convert cryptography_vectors to setup.cfg * put it in the right section --- vectors/cryptography_vectors/__about__.py | 18 ----------------- vectors/cryptography_vectors/__init__.py | 18 +---------------- vectors/setup.cfg | 16 +++++++++++++++ vectors/setup.py | 24 ++--------------------- 4 files changed, 19 insertions(+), 57 deletions(-) diff --git a/vectors/cryptography_vectors/__about__.py b/vectors/cryptography_vectors/__about__.py index 05fa40efc53d..6c670bb6efa8 100644 --- a/vectors/cryptography_vectors/__about__.py +++ b/vectors/cryptography_vectors/__about__.py @@ -3,25 +3,7 @@ # for complete details. __all__ = [ - "__title__", - "__summary__", - "__uri__", "__version__", - "__author__", - "__email__", - "__license__", - "__copyright__", ] -__title__ = "cryptography_vectors" -__summary__ = "Test vectors for the cryptography package." - -__uri__ = "https://github.com/pyca/cryptography" - __version__ = "35.0.0.dev1" - -__author__ = "The Python Cryptographic Authority and individual contributors" -__email__ = "cryptography-dev@python.org" - -__license__ = "BSD or Apache License, Version 2.0" -__copyright__ = "Copyright 2013-2021 %s" % __author__ diff --git a/vectors/cryptography_vectors/__init__.py b/vectors/cryptography_vectors/__init__.py index 86cddaca382f..1fe176754275 100644 --- a/vectors/cryptography_vectors/__init__.py +++ b/vectors/cryptography_vectors/__init__.py @@ -5,27 +5,11 @@ import os import typing -from cryptography_vectors.__about__ import ( - __author__, - __copyright__, - __email__, - __license__, - __summary__, - __title__, - __uri__, - __version__, -) +from cryptography_vectors.__about__ import __version__ __all__ = [ - "__title__", - "__summary__", - "__uri__", "__version__", - "__author__", - "__email__", - "__license__", - "__copyright__", ] diff --git a/vectors/setup.cfg b/vectors/setup.cfg index 2a9acf13daa9..99faeffba83b 100644 --- a/vectors/setup.cfg +++ b/vectors/setup.cfg @@ -1,2 +1,18 @@ +[metadata] +name = cryptography_vectors +version = attr: cryptography_vectors.__version__ +description = Test vectors for the cryptography package. +license = BSD or Apache License, Version 2.0 +url = https://github.com/pyca/cryptography +author = The Python Cryptographic Authority and individual contributors +author_email = cryptography-dev@python.org + + +[options] +zip_safe = False +include_package_data = True +packages = find: + + [bdist_wheel] universal = 1 diff --git a/vectors/setup.py b/vectors/setup.py index 5aaa62101978..68ff1cd8a507 100644 --- a/vectors/setup.py +++ b/vectors/setup.py @@ -4,27 +4,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. -import os +from setuptools import setup -from setuptools import find_packages, setup - -base_dir = os.path.dirname(__file__) - -about = {} -with open(os.path.join(base_dir, "cryptography_vectors", "__about__.py")) as f: - exec(f.read(), about) - - -setup( - name=about["__title__"], - version=about["__version__"], - description=about["__summary__"], - license=about["__license__"], - url=about["__uri__"], - author=about["__author__"], - author_email=about["__email__"], - packages=find_packages(), - zip_safe=False, - include_package_data=True, -) +setup() From 66ac2ad6ac4a51b9a433f0847106e74254f941ee Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 29 Aug 2021 22:41:52 -0400 Subject: [PATCH 0295/1456] updated comments in pyproject.tom (#6245) --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index cffd317087d5..a942869cd49a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,10 @@ [build-system] requires = [ # The minimum setuptools version is specific to the PEP 517 backend, - # and may be stricter than the version required in `setup.py` + # and may be stricter than the version required in `setup.cfg` "setuptools>=40.6.0", "wheel", - # Must be kept in sync with the `setup_requirements` in `setup.py` + # Must be kept in sync with the `setup_requirements` in `setup.cfg` "cffi>=1.12; platform_python_implementation != 'PyPy'", "setuptools-rust>=0.11.4", ] From 141a1ffaf2efb79900872bebd46b5149755573a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Aug 2021 08:16:17 -0500 Subject: [PATCH 0296/1456] Bump pyo3 from 0.14.3 to 0.14.4 in /src/rust (#6251) Bumps [pyo3](https://github.com/pyo3/pyo3) from 0.14.3 to 0.14.4. - [Release notes](https://github.com/pyo3/pyo3/releases) - [Changelog](https://github.com/PyO3/pyo3/blob/main/CHANGELOG.md) - [Commits](https://github.com/pyo3/pyo3/compare/v0.14.3...v0.14.4) --- updated-dependencies: - dependency-name: pyo3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 16 ++++++++-------- src/rust/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 4a5adc344a0d..77b7dd53ac20 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -279,9 +279,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ce0e80b2b35e9697353a25b0e4fa5374e38c451da2f86f0cd83c40e7f1d5191" +checksum = "a192cd06356bb941c663c969a7f3e27c7c8e187efe772c1406a447f122443f71" dependencies = [ "cfg-if", "indoc", @@ -295,18 +295,18 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96007b58c38d68ae449ea4d82fbc390faf5f1f2c80c76a6e3d51385bceb56741" +checksum = "650911ce22a793e9af67a0a880741ab1519e4f84740642716cbe83e129d17a2e" dependencies = [ "once_cell", ] [[package]] name = "pyo3-macros" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "326afb5c23f9789d0a367c37d58275c4d0e97ca74f05b9a25c0d66c6395c1c7b" +checksum = "92d6659c1e336eec5a6ebc53bd80705e31ea0b95bff03bf384e868984b8ce573" dependencies = [ "pyo3-macros-backend", "quote", @@ -315,9 +315,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e38169a08f98219bba484d19100811a1646d4962706b75d60766d21dce64f9c" +checksum = "0b425a4975523acb80087d24903cffce30287a1324ab29714ce33006043c7dbe" dependencies = [ "proc-macro2", "pyo3-build-config", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index d8c1f2c351cf..16cec56f848b 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] lazy_static = "1" -pyo3 = { version = "0.14.3" } +pyo3 = { version = "0.14.4" } asn1 = { version = "0.6", default-features = false, features = ["derive"] } pem = "0.8" chrono = { version = "0.4", default-features = false, features = ["alloc"] } From fa9e7f638bc8935d468d2fa84848ab43766b6146 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Aug 2021 08:16:43 -0500 Subject: [PATCH 0297/1456] Bump lock_api from 0.4.4 to 0.4.5 in /src/rust (#6247) Bumps [lock_api](https://github.com/Amanieu/parking_lot) from 0.4.4 to 0.4.5. - [Release notes](https://github.com/Amanieu/parking_lot/releases) - [Changelog](https://github.com/Amanieu/parking_lot/blob/master/CHANGELOG.md) - [Commits](https://github.com/Amanieu/parking_lot/compare/lock_api-0.4.4...lock_api-0.4.5) --- updated-dependencies: - dependency-name: lock_api dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 77b7dd53ac20..a632446b93e1 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -127,9 +127,9 @@ checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" [[package]] name = "lock_api" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ "scopeguard", ] From 7b70affdabf9ae7e6f2860fbad4795e1a44008e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Aug 2021 08:17:24 -0500 Subject: [PATCH 0298/1456] Bump parking_lot from 0.11.1 to 0.11.2 in /src/rust (#6249) Bumps [parking_lot](https://github.com/Amanieu/parking_lot) from 0.11.1 to 0.11.2. - [Release notes](https://github.com/Amanieu/parking_lot/releases) - [Changelog](https://github.com/Amanieu/parking_lot/blob/master/CHANGELOG.md) - [Commits](https://github.com/Amanieu/parking_lot/compare/0.11.1...0.11.2) --- updated-dependencies: - dependency-name: parking_lot dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index a632446b93e1..6677f1b35715 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -185,9 +185,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", @@ -196,9 +196,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ "cfg-if", "instant", From 905fa95de679738e0e64a59a8ce98e47b12e364c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Aug 2021 20:08:08 -0400 Subject: [PATCH 0299/1456] Bump proc-macro2 from 1.0.28 to 1.0.29 in /src/rust (#6252) Bumps [proc-macro2](https://github.com/alexcrichton/proc-macro2) from 1.0.28 to 1.0.29. - [Release notes](https://github.com/alexcrichton/proc-macro2/releases) - [Commits](https://github.com/alexcrichton/proc-macro2/compare/1.0.28...1.0.29) --- updated-dependencies: - dependency-name: proc-macro2 dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 6677f1b35715..c875915d6d89 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -270,9 +270,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.28" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" dependencies = [ "unicode-xid", ] From 032edb255c57eba80c9aea6986b72efdd464add4 Mon Sep 17 00:00:00 2001 From: April King Date: Fri, 3 Sep 2021 16:08:21 -0500 Subject: [PATCH 0300/1456] Updated recommendations for PBKDF2 (#6257) Django recommends 320,000 rounds of PBKDF2 as of January 2021. Note that it hasn't been 100,000 for some time, so this number should probably be revisited somewhat more frequently. I did point to the source code, to make that number easier to find for people. --- docs/fernet.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/fernet.rst b/docs/fernet.rst index 5e2655d3a72b..95579d4e6aed 100644 --- a/docs/fernet.rst +++ b/docs/fernet.rst @@ -251,8 +251,8 @@ 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. The iteration count used should be adjusted to be as high as your server can -tolerate. A good default is at least 100,000 iterations which is what Django -recommended in 2014. +tolerate. A good default is at least 320,000 iterations, which is what `Django +recommends as of January 2021`_. Implementation -------------- @@ -280,4 +280,5 @@ unsuitable for very large files at this time. .. _`Fernet`: https://github.com/fernet/spec/ +.. _`Django recommends as of January 2021`: https://github.com/django/django/blob/main/django/contrib/auth/hashers.py .. _`specification`: https://github.com/fernet/spec/blob/master/Spec.md From 5dfda63a97d71e33e191ceed80e5b1b1c174c7bc Mon Sep 17 00:00:00 2001 From: kjackiewicz Date: Sat, 4 Sep 2021 00:40:27 +0200 Subject: [PATCH 0301/1456] Implement KBKDFCMAC (#6181) * Implement KBKDFCMAC Also adjust KBKDFHMAC to avoid code duplication. * Add KBKDFCMAC unit tests * Enable KBKDFCMAC vector tests * Fix doc8 too long line issue in changelog Adding bullet list entries after line 30 in the CHANGELOG.rst leads to doc8 D001 error in line 30. Looks like a doc8 bug. Breaking the line in the middle of the cross-reference solves the problem for now. Also replace the trailing comma with a dot. * Add KBKDFCMAC documentation and update changelog --- CHANGELOG.rst | 5 +- .../primitives/key-derivation-functions.rst | 137 +++++++ .../hazmat/primitives/kdf/kbkdf.py | 174 ++++++-- tests/doubles.py | 12 +- tests/hazmat/primitives/test_kbkdf.py | 374 +++++++++++++++++- tests/hazmat/primitives/utils.py | 89 ++++- 6 files changed, 736 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 39929f76ffe0..2b054e8cfa78 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,8 +26,9 @@ Changelog in regions where they may be required, and are not generally recommended. * We now ship ``manylinux_2_24`` wheels, in addition to our ``manylinux2010`` and ``manylinux2014`` wheels. -* Added ``rfc4514_attribute_name`` attribute to - :attr:`x509.NameAttribute `, +* Added ``rfc4514_attribute_name`` attribute to :attr:`x509.NameAttribute + `. +* Added :class:`~cryptography.hazmat.primitives.kdf.kbkdf.KBKDFCMAC`. .. _v3-4-8: diff --git a/docs/hazmat/primitives/key-derivation-functions.rst b/docs/hazmat/primitives/key-derivation-functions.rst index 62457b28490c..0ec4eccb5f5f 100644 --- a/docs/hazmat/primitives/key-derivation-functions.rst +++ b/docs/hazmat/primitives/key-derivation-functions.rst @@ -755,6 +755,143 @@ KBKDF ``key_material`` generates the same key as the ``expected_key``, and raises an exception if they do not match. +.. class:: KBKDFCMAC(algorithm, mode, length, rlen, llen, location,\ + label, context, fixed, backend=None) + + .. versionadded:: 35.0 + + KBKDF (Key Based Key Derivation Function) is defined by the + `NIST SP 800-108`_ document, to be used to derive additional + keys from a key that has been established through an automated + key-establishment scheme. + + .. warning:: + + KBKDFCMAC should not be used for password storage. + + .. doctest:: + + >>> from cryptography.hazmat.primitives.ciphers import algorithms + >>> from cryptography.hazmat.primitives.kdf.kbkdf import ( + ... CounterLocation, KBKDFCMAC, Mode + ... ) + >>> label = b"KBKDF CMAC Label" + >>> context = b"KBKDF CMAC Context" + >>> kdf = KBKDFCMAC( + ... algorithm=algorithms.AES, + ... mode=Mode.CounterMode, + ... length=32, + ... rlen=4, + ... llen=4, + ... location=CounterLocation.BeforeFixed, + ... label=label, + ... context=context, + ... fixed=None, + ... ) + >>> key = kdf.derive(b"32 bytes long input key material") + >>> kdf = KBKDFCMAC( + ... algorithm=algorithms.AES, + ... mode=Mode.CounterMode, + ... length=32, + ... rlen=4, + ... llen=4, + ... location=CounterLocation.BeforeFixed, + ... label=label, + ... context=context, + ... fixed=None, + ... ) + >>> kdf.verify(b"32 bytes long input key material", key) + + :param algorithm: A class implementing a block cipher algorithm being a + subclass of + :class:`~cryptography.hazmat.primitives.ciphers.CipherAlgorithm` and + :class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm`. + + :param mode: The desired mode of the PRF. A value from the + :class:`~cryptography.hazmat.primitives.kdf.kbkdf.Mode` enum. + + :param int length: The desired length of the derived key in bytes. + + :param int rlen: An integer that indicates the length of the binary + representation of the counter in bytes. + + :param int llen: An integer that indicates the binary + representation of the ``length`` in bytes. + + :param location: The desired location of the counter. A value from the + :class:`~cryptography.hazmat.primitives.kdf.kbkdf.CounterLocation` enum. + + :param bytes label: Application specific label information. If ``None`` + is explicitly passed an empty byte string will be used. + + :param bytes context: Application specific context information. If ``None`` + is explicitly passed an empty byte string will be used. + + :param bytes fixed: Instead of specifying ``label`` and ``context`` you + may supply your own fixed data. If ``fixed`` is specified, ``label`` + and ``context`` is ignored. + + :param backend: An optional instance of + :class:`~cryptography.hazmat.backends.interfaces.CMACBackend`. + + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised + if the provided ``backend`` does not implement + :class:`~cryptography.hazmat.backends.interfaces.CMACBackend` or + ``algorithm`` is not a subclass of + :class:`~cryptography.hazmat.primitives.ciphers.CipherAlgorithm` and + :class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm`. + + :raises TypeError: This exception is raised if ``label`` or ``context`` + is not ``bytes``, ``rlen`` or ``llen`` is not ``int``, ``mode`` is not + :class:`~cryptography.hazmat.primitives.kdf.kbkdf.Mode` or ``location`` + is not + :class:`~cryptography.hazmat.primitives.kdf.kbkdf.CounterLocation`. + + :raises ValueError: This exception is raised if ``rlen`` or ``llen`` + is greater than 4 or less than 1. This exception is also raised if + you specify a ``label`` or ``context`` and ``fixed``. + + .. method:: derive(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``. + :raises ValueError: This exception is raised if ``key_material`` is + not a valid key for ``algorithm`` passed to + :class:`~cryptography.hazmat.primitives.kdf.kbkdf.KBKDFCMAC` + constructor. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised + if ``backend`` passed to + :class:`~cryptography.hazmat.primitives.kdf.kbkdf.KBKDFCMAC` + constructor does not support an ``algorithm`` passed to + :class:`~cryptography.hazmat.primitives.kdf.kbkdf.KBKDFCMAC` + constructor with given ``key_material``. + + Derives a new key from the input key material. + + .. method:: verify(key_material, expected_key) + + :param bytes key_material: The input key material. This is the same as + ``key_material`` in :meth:`derive`. + :param bytes expected_key: The expected result of deriving a new key, + this is the same as the return value of + :meth:`derive`. + :raises cryptography.exceptions.InvalidKey: This is raised when the + derived key does not match + the expected key. + :raises: Exceptions raised by :meth:`derive`. + + This checks whether deriving a new key from the supplied + ``key_material`` generates the same key as the ``expected_key``, and + raises an exception if they do not match. + .. class:: Mode An enumeration for the key based key derivative modes. diff --git a/src/cryptography/hazmat/primitives/kdf/kbkdf.py b/src/cryptography/hazmat/primitives/kdf/kbkdf.py index 1d106d1e5dec..d09da2b64748 100644 --- a/src/cryptography/hazmat/primitives/kdf/kbkdf.py +++ b/src/cryptography/hazmat/primitives/kdf/kbkdf.py @@ -2,7 +2,6 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. - import typing from cryptography import utils @@ -13,8 +12,18 @@ _Reasons, ) from cryptography.hazmat.backends import _get_backend -from cryptography.hazmat.backends.interfaces import Backend, HMACBackend -from cryptography.hazmat.primitives import constant_time, hashes, hmac +from cryptography.hazmat.backends.interfaces import ( + Backend, + CMACBackend, + HMACBackend, +) +from cryptography.hazmat.primitives import ( + ciphers, + cmac, + constant_time, + hashes, + hmac, +) from cryptography.hazmat.primitives.kdf import KeyDerivationFunction @@ -27,10 +36,10 @@ class CounterLocation(utils.Enum): AfterFixed = "after_fixed" -class KBKDFHMAC(KeyDerivationFunction): +class _KBKDFDeriver: def __init__( self, - algorithm: hashes.HashAlgorithm, + prf: typing.Callable, mode: Mode, length: int, rlen: int, @@ -39,26 +48,8 @@ def __init__( label: typing.Optional[bytes], context: typing.Optional[bytes], fixed: typing.Optional[bytes], - backend: typing.Optional[Backend] = None, ): - backend = _get_backend(backend) - if not isinstance(backend, HMACBackend): - raise UnsupportedAlgorithm( - "Backend object does not implement HMACBackend.", - _Reasons.BACKEND_MISSING_INTERFACE, - ) - - if not isinstance(algorithm, hashes.HashAlgorithm): - raise UnsupportedAlgorithm( - "Algorithm supplied is not a supported hash algorithm.", - _Reasons.UNSUPPORTED_HASH, - ) - - if not backend.hmac_supported(algorithm): - raise UnsupportedAlgorithm( - "Algorithm supplied is not a supported hmac algorithm.", - _Reasons.UNSUPPORTED_HASH, - ) + assert callable(prf) if not isinstance(mode, Mode): raise TypeError("mode must be of type Mode") @@ -88,7 +79,7 @@ def __init__( utils._check_bytes("label", label) utils._check_bytes("context", context) - self._algorithm = algorithm + self._prf = prf self._mode = mode self._length = length self._rlen = rlen @@ -96,11 +87,11 @@ def __init__( self._location = location self._label = label self._context = context - self._backend = backend self._used = False self._fixed_data = fixed - def _valid_byte_length(self, value: int) -> bool: + @staticmethod + def _valid_byte_length(value: int) -> bool: if not isinstance(value, int): raise TypeError("value must be of type int") @@ -109,7 +100,7 @@ def _valid_byte_length(self, value: int) -> bool: return False return True - def derive(self, key_material: bytes) -> bytes: + def derive(self, key_material: bytes, prf_output_size: int) -> bytes: if self._used: raise AlreadyFinalized @@ -117,7 +108,7 @@ def derive(self, key_material: bytes) -> bytes: self._used = True # inverse floor division (equivalent to ceiling) - rounds = -(-self._length // self._algorithm.digest_size) + rounds = -(-self._length // prf_output_size) output = [b""] @@ -130,7 +121,7 @@ def derive(self, key_material: bytes) -> bytes: raise ValueError("There are too many iterations.") for i in range(1, rounds + 1): - h = hmac.HMAC(key_material, self._algorithm, backend=self._backend) + h = self._prf(key_material) counter = utils.int_to_bytes(i, self._rlen) if self._location == CounterLocation.BeforeFixed: @@ -153,6 +144,129 @@ def _generate_fixed_input(self) -> bytes: return b"".join([self._label, b"\x00", self._context, l_val]) + +class KBKDFHMAC(KeyDerivationFunction): + def __init__( + self, + algorithm: hashes.HashAlgorithm, + mode: Mode, + length: int, + rlen: int, + llen: typing.Optional[int], + location: CounterLocation, + label: typing.Optional[bytes], + context: typing.Optional[bytes], + fixed: typing.Optional[bytes], + backend: typing.Optional[Backend] = None, + ): + backend = _get_backend(backend) + if not isinstance(backend, HMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement HMACBackend.", + _Reasons.BACKEND_MISSING_INTERFACE, + ) + + if not isinstance(algorithm, hashes.HashAlgorithm): + raise UnsupportedAlgorithm( + "Algorithm supplied is not a supported hash algorithm.", + _Reasons.UNSUPPORTED_HASH, + ) + + if not backend.hmac_supported(algorithm): + raise UnsupportedAlgorithm( + "Algorithm supplied is not a supported hmac algorithm.", + _Reasons.UNSUPPORTED_HASH, + ) + + self._algorithm = algorithm + self._backend = backend + + self._deriver = _KBKDFDeriver( + self._prf, + mode, + length, + rlen, + llen, + location, + label, + context, + fixed, + ) + + def _prf(self, key_material: bytes): + return hmac.HMAC(key_material, self._algorithm, backend=self._backend) + + def derive(self, key_material) -> bytes: + return self._deriver.derive(key_material, self._algorithm.digest_size) + + def verify(self, key_material: bytes, expected_key: bytes) -> None: + if not constant_time.bytes_eq(self.derive(key_material), expected_key): + raise InvalidKey + + +class KBKDFCMAC(KeyDerivationFunction): + def __init__( + self, + algorithm, + mode: Mode, + length: int, + rlen: int, + llen: typing.Optional[int], + location: CounterLocation, + label: typing.Optional[bytes], + context: typing.Optional[bytes], + fixed: typing.Optional[bytes], + backend: typing.Optional[Backend] = None, + ): + backend = _get_backend(backend) + if not isinstance(backend, CMACBackend): + raise UnsupportedAlgorithm( + "Backend object does not implement CMACBackend.", + _Reasons.BACKEND_MISSING_INTERFACE, + ) + + if not issubclass( + algorithm, ciphers.BlockCipherAlgorithm + ) or not issubclass(algorithm, ciphers.CipherAlgorithm): + raise UnsupportedAlgorithm( + "Algorithm supplied is not a supported cipher algorithm.", + _Reasons.UNSUPPORTED_CIPHER, + ) + + self._algorithm = algorithm + self._backend = backend + self._cipher: typing.Optional[ciphers.BlockCipherAlgorithm] = None + + self._deriver = _KBKDFDeriver( + self._prf, + mode, + length, + rlen, + llen, + location, + label, + context, + fixed, + ) + + def _prf(self, _: bytes): + assert self._cipher is not None + + return cmac.CMAC(self._cipher, backend=self._backend) + + def derive(self, key_material: bytes) -> bytes: + self._cipher = self._algorithm(key_material) + + assert self._cipher is not None + + if not self._backend.cmac_algorithm_supported(self._cipher): + raise UnsupportedAlgorithm( + "Algorithm supplied is not a supported cipher algorithm.", + _Reasons.UNSUPPORTED_CIPHER, + ) + + return self._deriver.derive(key_material, self._cipher.block_size // 8) + def verify(self, key_material: bytes, expected_key: bytes) -> None: if not constant_time.bytes_eq(self.derive(key_material), expected_key): raise InvalidKey diff --git a/tests/doubles.py b/tests/doubles.py index de79fbe8c435..3b6f2db35994 100644 --- a/tests/doubles.py +++ b/tests/doubles.py @@ -5,7 +5,10 @@ from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding -from cryptography.hazmat.primitives.ciphers import CipherAlgorithm +from cryptography.hazmat.primitives.ciphers import ( + BlockCipherAlgorithm, + CipherAlgorithm, +) from cryptography.hazmat.primitives.ciphers.modes import Mode @@ -16,6 +19,13 @@ class DummyCipherAlgorithm(CipherAlgorithm): key_sizes = frozenset([256]) +class DummyBlockCipherAlgorithm(DummyCipherAlgorithm, BlockCipherAlgorithm): + def __init__(self, _): + pass + + name = "dummy-block-cipher" + + class DummyMode(Mode): name = "dummy-mode" diff --git a/tests/hazmat/primitives/test_kbkdf.py b/tests/hazmat/primitives/test_kbkdf.py index ae9330807140..4a44db8d8cd4 100644 --- a/tests/hazmat/primitives/test_kbkdf.py +++ b/tests/hazmat/primitives/test_kbkdf.py @@ -7,13 +7,19 @@ from cryptography.exceptions import AlreadyFinalized, InvalidKey, _Reasons from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.ciphers import algorithms from cryptography.hazmat.primitives.kdf.kbkdf import ( CounterLocation, + KBKDFCMAC, KBKDFHMAC, Mode, ) -from ...doubles import DummyHashAlgorithm +from ...doubles import ( + DummyBlockCipherAlgorithm, + DummyCipherAlgorithm, + DummyHashAlgorithm, +) from ...utils import raises_unsupported_algorithm @@ -333,3 +339,369 @@ def test_buffer_protocol(self, backend): key = kdf.derive(bytearray(b"material")) assert key == b"\xb7\x01\x05\x98\xf5\x1a\x12L\xc7." + + +class TestKBKDFCMAC(object): + _KEY_MATERIAL = bytes(32) + _KEY_MATERIAL2 = _KEY_MATERIAL.replace(b"\x00", b"\x01", 1) + + def test_invalid_key(self, backend): + kdf = KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + + key = kdf.derive(self._KEY_MATERIAL) + + kdf = KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + + with pytest.raises(InvalidKey): + kdf.verify(self._KEY_MATERIAL2, key) + + def test_already_finalized(self, backend): + kdf = KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + + kdf.derive(self._KEY_MATERIAL) + + with pytest.raises(AlreadyFinalized): + kdf.derive(self._KEY_MATERIAL2) + + kdf = KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + + key = kdf.derive(self._KEY_MATERIAL) + + with pytest.raises(AlreadyFinalized): + kdf.verify(self._KEY_MATERIAL, key) + + kdf = KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + kdf.verify(self._KEY_MATERIAL, key) + + with pytest.raises(AlreadyFinalized): + kdf.verify(self._KEY_MATERIAL, key) + + def test_key_length(self, backend): + kdf = KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 85899345920, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + + with pytest.raises(ValueError): + kdf.derive(self._KEY_MATERIAL) + + def test_rlen(self, backend): + with pytest.raises(ValueError): + KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + 5, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + + def test_r_type(self, backend): + with pytest.raises(TypeError): + KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + b"r", # type: ignore[arg-type] + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + + def test_l_type(self, backend): + with pytest.raises(TypeError): + KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + 4, + b"l", # type: ignore[arg-type] + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + + def test_l(self, backend): + with pytest.raises(ValueError): + KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + 4, + None, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + + def test_unsupported_mode(self, backend): + with pytest.raises(TypeError): + KBKDFCMAC( + algorithms.AES, + None, # type: ignore[arg-type] + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + + def test_unsupported_location(self, backend): + with pytest.raises(TypeError): + KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + 4, + 4, + None, # type: ignore[arg-type] + b"label", + b"context", + None, + backend=backend, + ) + + def test_unsupported_parameters(self, backend): + with pytest.raises(ValueError): + KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + b"fixed", + backend=backend, + ) + + def test_unsupported_algorithm(self, backend): + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER): + KBKDFCMAC( + object, # type: ignore[arg-type] + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER): + KBKDFCMAC( + DummyCipherAlgorithm, + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER): + KBKDFCMAC( + algorithms.ARC4, + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + + def test_invalid_backend(self, backend): + with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): + KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=object(), # type: ignore[arg-type] + ) + + def test_unicode_error_label(self, backend): + with pytest.raises(TypeError): + KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + "label", # type: ignore[arg-type] + b"context", + None, + backend=backend, + ) + + def test_unicode_error_context(self, backend): + with pytest.raises(TypeError): + KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + "context", # type: ignore[arg-type] + None, + backend=backend, + ) + + def test_unsupported_cipher(self, backend): + kdf = KBKDFCMAC( + DummyBlockCipherAlgorithm, + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER): + kdf.derive(self._KEY_MATERIAL) + + def test_unicode_error_key_material(self, backend): + kdf = KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + with pytest.raises(TypeError): + kdf.derive("material") # type: ignore[arg-type] + + def test_wrong_key_material_length(self, backend): + kdf = KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + with pytest.raises(ValueError): + kdf.derive(b"material") # type: ignore[arg-type] + + def test_buffer_protocol(self, backend): + kdf = KBKDFCMAC( + algorithms.AES, + Mode.CounterMode, + 10, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + + key = kdf.derive(bytearray(self._KEY_MATERIAL)) + assert key == b"\x19\xcd\xbe\x17Lb\x115<\xd0" diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 44af12dcbf4f..639f8d5bef70 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -18,11 +18,16 @@ ) from cryptography.hazmat.primitives import hashes, hmac, serialization from cryptography.hazmat.primitives.asymmetric import rsa -from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers import ( + BlockCipherAlgorithm, + Cipher, + algorithms, +) from cryptography.hazmat.primitives.ciphers.modes import GCM from cryptography.hazmat.primitives.kdf.hkdf import HKDF, HKDFExpand from cryptography.hazmat.primitives.kdf.kbkdf import ( CounterLocation, + KBKDFCMAC, KBKDFHMAC, Mode, ) @@ -411,8 +416,8 @@ def test_kbkdf(self, backend, subtests): return test_kbkdf -def kbkdf_counter_mode_test(backend, params): - supported_algorithms: typing.Dict[ +def _kbkdf_hmac_counter_mode_test(backend, prf, ctr_loc, params): + supported_hash_algorithms: typing.Dict[ str, typing.Type[hashes.HashAlgorithm] ] = { "hmac_sha1": hashes.SHA1, @@ -422,24 +427,9 @@ def kbkdf_counter_mode_test(backend, params): "hmac_sha512": hashes.SHA512, } - supported_counter_locations = { - "before_fixed": CounterLocation.BeforeFixed, - "after_fixed": CounterLocation.AfterFixed, - } - - algorithm = supported_algorithms.get(params.get("prf")) - if algorithm is None or not backend.hmac_supported(algorithm()): - pytest.skip( - "KBKDF does not support algorithm: {}".format(params.get("prf")) - ) - - ctr_loc = supported_counter_locations.get(params.get("ctrlocation")) - if ctr_loc is None or not isinstance(ctr_loc, CounterLocation): - pytest.skip( - "Does not support counter location: {}".format( - params.get("ctrlocation") - ) - ) + algorithm = supported_hash_algorithms.get(prf) + assert algorithm is not None + assert backend.hmac_supported(algorithm()) ctrkdf = KBKDFHMAC( algorithm(), @@ -458,6 +448,63 @@ def kbkdf_counter_mode_test(backend, params): assert binascii.hexlify(ko) == params["ko"] +def _kbkdf_cmac_counter_mode_test(backend, prf, ctr_loc, params): + supported_cipher_algorithms: typing.Dict[ + str, typing.Type[BlockCipherAlgorithm] + ] = { + "cmac_aes128": algorithms.AES, + "cmac_aes192": algorithms.AES, + "cmac_aes256": algorithms.AES, + "cmac_tdes2": algorithms.TripleDES, + "cmac_tdes3": algorithms.TripleDES, + } + + algorithm = supported_cipher_algorithms.get(prf) + assert algorithm is not None + + ctrkdf = KBKDFCMAC( + algorithm, + Mode.CounterMode, + params["l"] // 8, + params["rlen"] // 8, + None, + ctr_loc, + None, + None, + binascii.unhexlify(params["fixedinputdata"]), + backend=backend, + ) + + ko = ctrkdf.derive(binascii.unhexlify(params["ki"])) + assert binascii.hexlify(ko) == params["ko"] + + +def kbkdf_counter_mode_test(backend, params): + supported_counter_locations = { + "before_fixed": CounterLocation.BeforeFixed, + "after_fixed": CounterLocation.AfterFixed, + } + + ctr_loc = supported_counter_locations.get(params.get("ctrlocation")) + if ctr_loc is None or not isinstance(ctr_loc, CounterLocation): + pytest.skip( + "Does not support counter location: {}".format( + params.get("ctrlocation") + ) + ) + del params["ctrlocation"] + + prf = params.get("prf") + assert prf is not None + assert isinstance(prf, str) + del params["prf"] + if prf.startswith("hmac"): + _kbkdf_hmac_counter_mode_test(backend, prf, ctr_loc, params) + else: + assert prf.startswith("cmac") + _kbkdf_cmac_counter_mode_test(backend, prf, ctr_loc, params) + + def generate_rsa_verification_test( param_loader, path, file_names, hash_alg, pad_factory ): From 9adb7519ded3dd6411dfeb19595c16e566d5f48f Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 4 Sep 2021 04:02:29 -0700 Subject: [PATCH 0302/1456] raise a ValueError if the AEAD tag is too long (#6246) * raise a ValueError if the GCM tag is too long this is checked in both the GCM mode constructor as well as finalize_with_tag * make it work * fix * import ordering --- .../hazmat/backends/openssl/ciphers.py | 9 ++++++++- .../hazmat/primitives/ciphers/__init__.py | 6 ++++-- .../hazmat/primitives/ciphers/base.py | 12 +----------- .../hazmat/primitives/ciphers/modes.py | 18 +++++++++++++++++- tests/hazmat/primitives/test_aes_gcm.py | 5 +++-- tests/hazmat/primitives/test_ciphers.py | 8 ++++++++ tests/hazmat/primitives/utils.py | 7 +++++++ 7 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/ciphers.py b/src/cryptography/hazmat/backends/openssl/ciphers.py index ec272e04d4f4..69f7f6bfd382 100644 --- a/src/cryptography/hazmat/backends/openssl/ciphers.py +++ b/src/cryptography/hazmat/backends/openssl/ciphers.py @@ -238,12 +238,19 @@ def finalize(self) -> bytes: return self._backend._ffi.buffer(buf)[: outlen[0]] def finalize_with_tag(self, tag: bytes) -> bytes: - if len(tag) < self._mode._min_tag_length: + tag_len = len(tag) + if tag_len < self._mode._min_tag_length: raise ValueError( "Authentication tag must be {} bytes or longer.".format( self._mode._min_tag_length ) ) + elif tag_len > self._block_size_bytes: + raise ValueError( + "Authentication tag cannot be more than {} bytes.".format( + self._block_size_bytes + ) + ) res = self._backend._lib.EVP_CIPHER_CTX_ctrl( self._ctx, self._backend._lib.EVP_CTRL_AEAD_SET_TAG, len(tag), tag ) diff --git a/src/cryptography/hazmat/primitives/ciphers/__init__.py b/src/cryptography/hazmat/primitives/ciphers/__init__.py index 7d3a2dcc65f8..874dbd456e8f 100644 --- a/src/cryptography/hazmat/primitives/ciphers/__init__.py +++ b/src/cryptography/hazmat/primitives/ciphers/__init__.py @@ -3,13 +3,15 @@ # for complete details. +from cryptography.hazmat.primitives._cipheralgorithm import ( + BlockCipherAlgorithm, + CipherAlgorithm, +) from cryptography.hazmat.primitives.ciphers.base import ( AEADCipherContext, AEADDecryptionContext, AEADEncryptionContext, - BlockCipherAlgorithm, Cipher, - CipherAlgorithm, CipherContext, ) diff --git a/src/cryptography/hazmat/primitives/ciphers/base.py b/src/cryptography/hazmat/primitives/ciphers/base.py index ad3c7ed8fdc4..0ae519c6d5e2 100644 --- a/src/cryptography/hazmat/primitives/ciphers/base.py +++ b/src/cryptography/hazmat/primitives/ciphers/base.py @@ -16,20 +16,10 @@ ) from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import Backend, CipherBackend -from cryptography.hazmat.primitives._cipheralgorithm import ( - CipherAlgorithm as CipherAlgorithm, -) +from cryptography.hazmat.primitives._cipheralgorithm import CipherAlgorithm from cryptography.hazmat.primitives.ciphers import modes -class BlockCipherAlgorithm(metaclass=abc.ABCMeta): - @abc.abstractproperty - def block_size(self) -> int: - """ - The size of a block as an integer in bits (e.g. 64, 128). - """ - - class CipherContext(metaclass=abc.ABCMeta): @abc.abstractmethod def update(self, data: bytes) -> bytes: diff --git a/src/cryptography/hazmat/primitives/ciphers/modes.py b/src/cryptography/hazmat/primitives/ciphers/modes.py index 43ddc6d24678..3491dc2038c2 100644 --- a/src/cryptography/hazmat/primitives/ciphers/modes.py +++ b/src/cryptography/hazmat/primitives/ciphers/modes.py @@ -7,7 +7,11 @@ import typing from cryptography import utils -from cryptography.hazmat.primitives._cipheralgorithm import CipherAlgorithm +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives._cipheralgorithm import ( + BlockCipherAlgorithm, + CipherAlgorithm, +) class Mode(metaclass=abc.ABCMeta): @@ -229,3 +233,15 @@ def initialization_vector(self) -> bytes: def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: _check_aes_key_length(self, algorithm) + if not isinstance(algorithm, BlockCipherAlgorithm): + raise UnsupportedAlgorithm( + "GCM requires a block cipher algorithm", + _Reasons.UNSUPPORTED_CIPHER, + ) + block_size_bytes = algorithm.block_size // 8 + if self._tag is not None and len(self._tag) > block_size_bytes: + raise ValueError( + "Authentication tag cannot be more than {} bytes.".format( + block_size_bytes + ) + ) diff --git a/tests/hazmat/primitives/test_aes_gcm.py b/tests/hazmat/primitives/test_aes_gcm.py index bae213da82d9..cc3b386aa697 100644 --- a/tests/hazmat/primitives/test_aes_gcm.py +++ b/tests/hazmat/primitives/test_aes_gcm.py @@ -168,12 +168,13 @@ def test_gcm_tag_decrypt_finalize(self, backend): decryptor.finalize_with_tag(tag) - def test_gcm_tag_decrypt_finalize_tag_length(self, backend): + @pytest.mark.parametrize("tag", [b"tagtooshort", b"toolong" * 12]) + def test_gcm_tag_decrypt_finalize_tag_length(self, tag, 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") + decryptor.finalize_with_tag(tag) def test_buffer_protocol(self, backend): data = bytearray(b"helloworld") diff --git a/tests/hazmat/primitives/test_ciphers.py b/tests/hazmat/primitives/test_ciphers.py index 99aa4af3f919..bb5d0e8bd668 100644 --- a/tests/hazmat/primitives/test_ciphers.py +++ b/tests/hazmat/primitives/test_ciphers.py @@ -209,6 +209,14 @@ def test_invalid_backend(): ) +def test_invalid_gcm_algorithm(): + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER): + ciphers.Cipher( + ARC4(b"\x00" * 16), + modes.GCM(b"\x00" * 12), + ) + + @pytest.mark.supported( only_if=lambda backend: backend.cipher_supported( AES(b"\x00" * 16), modes.ECB() diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 639f8d5bef70..682adfbb6b04 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -337,6 +337,13 @@ def aead_tag_exception_test(backend, cipher_factory, mode_factory): with pytest.raises(ValueError): mode_factory(binascii.unhexlify(b"0" * 24), b"000") + with pytest.raises(ValueError): + Cipher( + cipher_factory(binascii.unhexlify(b"0" * 32)), + mode_factory(binascii.unhexlify(b"0" * 24), b"toolong" * 12), + backend, + ) + with pytest.raises(ValueError): mode_factory(binascii.unhexlify(b"0" * 24), b"000000", 2) From 2b19ea98872c6dad69b32f6a87e74e0d5343e42d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 4 Sep 2021 19:47:21 -0400 Subject: [PATCH 0303/1456] Bump asn1 from 0.6.1 to 0.6.2 in /src/rust (#6258) Bumps [asn1](https://github.com/alex/rust-asn1) from 0.6.1 to 0.6.2. - [Release notes](https://github.com/alex/rust-asn1/releases) - [Commits](https://github.com/alex/rust-asn1/compare/0.6.1...0.6.2) --- updated-dependencies: - dependency-name: asn1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index c875915d6d89..1d70e791970c 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -16,9 +16,9 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" [[package]] name = "asn1" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c13a3c9cd71e1799fc16511efe36d0281b60bce3b32b4b211156a7b1925bfd" +checksum = "fec9ecc08f53758f70c0517f9dcc2b045da21f288642c9dbcb0f2064c8471aa8" dependencies = [ "asn1_derive", "chrono", @@ -26,9 +26,9 @@ dependencies = [ [[package]] name = "asn1_derive" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62fc4b7f90b9540f1719f333e3ed85100ea072035d690000d7c01252ecdff096" +checksum = "48b320511d6729e965d3d9f7a2e9d35249d5abf7a6d74a033df4f3f6e2780379" dependencies = [ "proc-macro2", "quote", From 0b719e38f9e63bef7ce92f4a57dffe95972acc9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 4 Sep 2021 20:02:58 -0400 Subject: [PATCH 0304/1456] Bump syn from 1.0.75 to 1.0.76 in /src/rust (#6259) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.75 to 1.0.76. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.75...1.0.76) --- updated-dependencies: - dependency-name: syn dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 1d70e791970c..b5d6f2035676 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -378,9 +378,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "1.0.75" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7" +checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" dependencies = [ "proc-macro2", "quote", From 8804475a92bb5300342917b24e7fef5e0171e0ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Sep 2021 08:27:47 -0400 Subject: [PATCH 0305/1456] Bump pyo3 from 0.14.4 to 0.14.5 in /src/rust (#6261) Bumps [pyo3](https://github.com/pyo3/pyo3) from 0.14.4 to 0.14.5. - [Release notes](https://github.com/pyo3/pyo3/releases) - [Changelog](https://github.com/PyO3/pyo3/blob/main/CHANGELOG.md) - [Commits](https://github.com/pyo3/pyo3/compare/v0.14.4...v0.14.5) --- updated-dependencies: - dependency-name: pyo3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 16 ++++++++-------- src/rust/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index b5d6f2035676..481e7385218f 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -279,9 +279,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a192cd06356bb941c663c969a7f3e27c7c8e187efe772c1406a447f122443f71" +checksum = "35100f9347670a566a67aa623369293703322bb9db77d99d7df7313b575ae0c8" dependencies = [ "cfg-if", "indoc", @@ -295,18 +295,18 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650911ce22a793e9af67a0a880741ab1519e4f84740642716cbe83e129d17a2e" +checksum = "d12961738cacbd7f91b7c43bc25cfeeaa2698ad07a04b3be0aa88b950865738f" dependencies = [ "once_cell", ] [[package]] name = "pyo3-macros" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d6659c1e336eec5a6ebc53bd80705e31ea0b95bff03bf384e868984b8ce573" +checksum = "fc0bc5215d704824dfddddc03f93cb572e1155c68b6761c37005e1c288808ea8" dependencies = [ "pyo3-macros-backend", "quote", @@ -315,9 +315,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b425a4975523acb80087d24903cffce30287a1324ab29714ce33006043c7dbe" +checksum = "71623fc593224afaab918aa3afcaf86ed2f43d34f6afde7f3922608f253240df" dependencies = [ "proc-macro2", "pyo3-build-config", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 16cec56f848b..3c3d9d7433e9 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] lazy_static = "1" -pyo3 = { version = "0.14.4" } +pyo3 = { version = "0.14.5" } asn1 = { version = "0.6", default-features = false, features = ["derive"] } pem = "0.8" chrono = { version = "0.4", default-features = false, features = ["alloc"] } From e4934064868c8863a66fcc54802f829086af24cf Mon Sep 17 00:00:00 2001 From: match man Date: Mon, 6 Sep 2021 23:53:29 +0300 Subject: [PATCH 0306/1456] Make OAEP test vector generating works on python3 (#6255) Use always string as output format Co-authored-by: Baofeng Wang --- .../rsa-oaep-sha2/generate_rsa_oaep_sha2.py | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py b/docs/development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py index 000467327538..2fe62303b506 100644 --- a/docs/development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py +++ b/docs/development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py @@ -27,29 +27,29 @@ def build_vectors(mgf1alg, hashalg, filename): skey = rsa.generate_private_key(65537, 2048, backend) pn = skey.private_numbers() examples = private["examples"] - output.append(b"# =============================================") - output.append(b"# Example") - output.append(b"# Public key") - output.append(b"# Modulus:") + output.append("# =============================================") + output.append("# Example") + output.append("# Public key") + output.append("# Modulus:") output.append(format(pn.public_numbers.n, "x")) - output.append(b"# Exponent:") + output.append("# Exponent:") output.append(format(pn.public_numbers.e, "x")) - output.append(b"# Private key") - output.append(b"# Modulus:") + output.append("# Private key") + output.append("# Modulus:") output.append(format(pn.public_numbers.n, "x")) - output.append(b"# Public exponent:") + output.append("# Public exponent:") output.append(format(pn.public_numbers.e, "x")) - output.append(b"# Exponent:") + output.append("# Exponent:") output.append(format(pn.d, "x")) - output.append(b"# Prime 1:") + output.append("# Prime 1:") output.append(format(pn.p, "x")) - output.append(b"# Prime 2:") + output.append("# Prime 2:") output.append(format(pn.q, "x")) - output.append(b"# Prime exponent 1:") + output.append("# Prime exponent 1:") output.append(format(pn.dmp1, "x")) - output.append(b"# Prime exponent 2:") + output.append("# Prime exponent 2:") output.append(format(pn.dmq1, "x")) - output.append(b"# Coefficient:") + output.append("# Coefficient:") output.append(format(pn.iqmp, "x")) pkey = skey.public_key() vectorkey = rsa.RSAPrivateNumbers( @@ -84,17 +84,17 @@ def build_vectors(mgf1alg, hashalg, filename): ), ) output.append( - b"# OAEP Example {0} alg={1} mgf1={2}".format( + "# OAEP Example {0} alg={1} mgf1={2}".format( count, hashalg.name, mgf1alg.name ) ) count += 1 - output.append(b"# Message:") - output.append(example["message"]) - output.append(b"# Encryption:") - output.append(binascii.hexlify(ct)) + output.append("# Message:") + output.append(example["message"].decode("utf-8")) + output.append("# Encryption:") + output.append(binascii.hexlify(ct).decode("utf-8")) - return b"\n".join(output) + return "\n".join(output) def write_file(data, filename): From 3cf6f7d56777177d9031f7cb47ed6e1e2eae5f9c Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 7 Sep 2021 09:37:58 -0400 Subject: [PATCH 0307/1456] updated installation docs to reflect what we test on (#6265) --- docs/installation.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index a9f40bf9afa4..65a8d012452a 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -16,10 +16,11 @@ Supported platforms Currently we test ``cryptography`` on Python 3.6+ and PyPy3 7.3.1 on these operating systems. -* x86-64 & AArch64 CentOS 8.x +* x86-64 CentOS 8.x * x86-64 Fedora (latest) * x86-64 macOS 10.15 Catalina -* x86-64 & AArch64 Ubuntu 18.04, 20.04 +* x86-64 Ubuntu 18.04, 20.04 +* AArch64 Ubuntu 20.04 * x86-64 Ubuntu rolling * x86-64 Debian Stretch (9.x), Buster (10.x), Bullseye (11.x), and Sid (unstable) @@ -31,6 +32,7 @@ OpenSSL releases: * ``OpenSSL 1.1.0-latest`` * ``OpenSSL 1.1.1-latest`` +* ``OpenSSL 3.0-latest`` Building cryptography on Windows From 7bb03065237d9a16477e2d94734638aa8f8ba692 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 7 Sep 2021 09:38:30 -0400 Subject: [PATCH 0308/1456] new year, new openssl (#6264) --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1f9619cf374..be414baa0307 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,8 +32,8 @@ jobs: - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1l"}} - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1l"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1l", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0-beta2"}} - - {VERSION: "3.9", TOXENV: "py39", TOXARGS: "--enable-fips=1", OPENSSL: {TYPE: "openssl", CONFIG_FLAGS: "enable-fips", VERSION: "3.0.0-beta2"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0"}} + - {VERSION: "3.9", TOXENV: "py39", TOXARGS: "--enable-fips=1", OPENSSL: {TYPE: "openssl", CONFIG_FLAGS: "enable-fips", VERSION: "3.0.0"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "2.9.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.1.5"}} From 11939664bcb1221278f90fb33a3f2a626665b6dd Mon Sep 17 00:00:00 2001 From: match man Date: Mon, 13 Sep 2021 01:20:14 +0300 Subject: [PATCH 0309/1456] cffi: check openssl version is less than 1.1.0 (#6266) Issue an #error directive if it is Signed-off-by: Baofeng Wang Co-authored-by: Baofeng Wang --- src/_cffi_src/openssl/cryptography.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/_cffi_src/openssl/cryptography.py b/src/_cffi_src/openssl/cryptography.py index 802a72acbf58..310b78baf165 100644 --- a/src/_cffi_src/openssl/cryptography.py +++ b/src/_cffi_src/openssl/cryptography.py @@ -39,6 +39,10 @@ #define CRYPTOGRAPHY_LIBRESSL_LESS_THAN_332 (0) #endif +#if OPENSSL_VERSION_NUMBER < 0x10100000 + #error "pyca/cryptography MUST be linked with Openssl 1.1.0 or later" +#endif + #define CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER \ (OPENSSL_VERSION_NUMBER >= 0x1010006f && !CRYPTOGRAPHY_IS_LIBRESSL) #define CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER \ From 86a14d8fa8b8a69236a987b195fdac3e600bdc68 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 13 Sep 2021 07:43:26 +0800 Subject: [PATCH 0310/1456] add more eku oids (#6271) * add more eku oids fixes #5892 * kerberos is a word in our world --- docs/spelling_wordlist.txt | 1 + docs/x509/reference.rst | 17 +++++++++++++++++ src/cryptography/x509/oid.py | 4 ++++ 3 files changed, 22 insertions(+) diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index c74cfa469b6a..6de134333858 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -66,6 +66,7 @@ introspectability invariants iOS iterable +Kerberos Koblitz Lange logins diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index eb4d07b54508..92d6f9062cef 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -3027,6 +3027,23 @@ instances. The following common OIDs are available as constants. the application. Therefore, the presence of this OID does not mean a given application will accept the certificate for all purposes. + .. attribute:: SMARTCARD_LOGON + + .. versionadded:: 35.0 + + Corresponds to the dotted string ``"1.3.6.1.4.1.311.20.2.2"``. This + is used to denote that a certificate may be used for ``PKINIT`` access + on Windows. + + .. attribute:: KERBEROS_PKINIT_KDC + + .. versionadded:: 35.0 + + Corresponds to the dotted string ``"1.3.6.1.5.2.3.5"``. This + is used to denote that a certificate may be used as a Kerberos + domain controller certificate authorizing ``PKINIT`` access. For + more information see :rfc:`4556`. + .. class:: AuthorityInformationAccessOID diff --git a/src/cryptography/x509/oid.py b/src/cryptography/x509/oid.py index 228ac1155324..cc3250c891d0 100644 --- a/src/cryptography/x509/oid.py +++ b/src/cryptography/x509/oid.py @@ -140,6 +140,8 @@ class ExtendedKeyUsageOID(object): TIME_STAMPING = ObjectIdentifier("1.3.6.1.5.5.7.3.8") OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9") ANY_EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37.0") + SMARTCARD_LOGON = ObjectIdentifier("1.3.6.1.4.1.311.20.2.2") + KERBEROS_PKINIT_KDC = ObjectIdentifier("1.3.6.1.5.2.3.5") class AuthorityInformationAccessOID(object): @@ -225,6 +227,8 @@ class AttributeOID(object): ExtendedKeyUsageOID.EMAIL_PROTECTION: "emailProtection", ExtendedKeyUsageOID.TIME_STAMPING: "timeStamping", ExtendedKeyUsageOID.OCSP_SIGNING: "OCSPSigning", + ExtendedKeyUsageOID.SMARTCARD_LOGON: "msSmartcardLogin", + ExtendedKeyUsageOID.KERBEROS_PKINIT_KDC: "pkInitKDC", ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES: "subjectDirectoryAttributes", ExtensionOID.SUBJECT_KEY_IDENTIFIER: "subjectKeyIdentifier", ExtensionOID.KEY_USAGE: "keyUsage", From 7b5634911c892fbc64b363523b8af74a4b772f7b Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 13 Sep 2021 08:12:04 +0800 Subject: [PATCH 0311/1456] resolve lazy import race condition (#6272) some private constants are no longer re-exported to the same spots --- src/cryptography/hazmat/_oid.py | 268 ++++++++++++++++- .../hazmat/backends/openssl/ocsp.py | 3 +- .../hazmat/backends/openssl/x509.py | 5 +- src/cryptography/x509/__init__.py | 2 - src/cryptography/x509/oid.py | 280 +----------------- src/rust/src/x509.rs | 2 +- tests/x509/test_x509_ext.py | 2 +- 7 files changed, 285 insertions(+), 277 deletions(-) diff --git a/src/cryptography/hazmat/_oid.py b/src/cryptography/hazmat/_oid.py index dbd04bc37609..71d41a17ddcd 100644 --- a/src/cryptography/hazmat/_oid.py +++ b/src/cryptography/hazmat/_oid.py @@ -4,6 +4,8 @@ import typing +from cryptography.hazmat.primitives import hashes + class ObjectIdentifier(object): def __init__(self, dotted_string: str) -> None: @@ -67,11 +69,271 @@ def __hash__(self) -> int: @property def _name(self) -> str: - # Lazy import to avoid an import cycle - from cryptography.x509.oid import _OID_NAMES - return _OID_NAMES.get(self, "Unknown OID") @property def dotted_string(self) -> str: return self._dotted_string + + +class ExtensionOID(object): + SUBJECT_DIRECTORY_ATTRIBUTES = ObjectIdentifier("2.5.29.9") + SUBJECT_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.14") + KEY_USAGE = ObjectIdentifier("2.5.29.15") + SUBJECT_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.17") + ISSUER_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.18") + BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19") + NAME_CONSTRAINTS = ObjectIdentifier("2.5.29.30") + CRL_DISTRIBUTION_POINTS = ObjectIdentifier("2.5.29.31") + CERTIFICATE_POLICIES = ObjectIdentifier("2.5.29.32") + POLICY_MAPPINGS = ObjectIdentifier("2.5.29.33") + AUTHORITY_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.35") + POLICY_CONSTRAINTS = ObjectIdentifier("2.5.29.36") + 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") + TLS_FEATURE = ObjectIdentifier("1.3.6.1.5.5.7.1.24") + CRL_NUMBER = ObjectIdentifier("2.5.29.20") + DELTA_CRL_INDICATOR = ObjectIdentifier("2.5.29.27") + 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") + SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.5") + + +class OCSPExtensionOID(object): + NONCE = ObjectIdentifier("1.3.6.1.5.5.7.48.1.2") + + +class CRLEntryExtensionOID(object): + CERTIFICATE_ISSUER = ObjectIdentifier("2.5.29.29") + CRL_REASON = ObjectIdentifier("2.5.29.21") + INVALIDITY_DATE = ObjectIdentifier("2.5.29.24") + + +class NameOID(object): + COMMON_NAME = ObjectIdentifier("2.5.4.3") + COUNTRY_NAME = ObjectIdentifier("2.5.4.6") + LOCALITY_NAME = ObjectIdentifier("2.5.4.7") + STATE_OR_PROVINCE_NAME = ObjectIdentifier("2.5.4.8") + STREET_ADDRESS = ObjectIdentifier("2.5.4.9") + ORGANIZATION_NAME = ObjectIdentifier("2.5.4.10") + ORGANIZATIONAL_UNIT_NAME = ObjectIdentifier("2.5.4.11") + SERIAL_NUMBER = ObjectIdentifier("2.5.4.5") + SURNAME = ObjectIdentifier("2.5.4.4") + GIVEN_NAME = ObjectIdentifier("2.5.4.42") + TITLE = ObjectIdentifier("2.5.4.12") + GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44") + X500_UNIQUE_IDENTIFIER = ObjectIdentifier("2.5.4.45") + DN_QUALIFIER = ObjectIdentifier("2.5.4.46") + PSEUDONYM = ObjectIdentifier("2.5.4.65") + USER_ID = ObjectIdentifier("0.9.2342.19200300.100.1.1") + DOMAIN_COMPONENT = ObjectIdentifier("0.9.2342.19200300.100.1.25") + EMAIL_ADDRESS = ObjectIdentifier("1.2.840.113549.1.9.1") + JURISDICTION_COUNTRY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.3") + JURISDICTION_LOCALITY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.1") + JURISDICTION_STATE_OR_PROVINCE_NAME = ObjectIdentifier( + "1.3.6.1.4.1.311.60.2.1.2" + ) + BUSINESS_CATEGORY = ObjectIdentifier("2.5.4.15") + POSTAL_ADDRESS = ObjectIdentifier("2.5.4.16") + POSTAL_CODE = ObjectIdentifier("2.5.4.17") + INN = ObjectIdentifier("1.2.643.3.131.1.1") + OGRN = ObjectIdentifier("1.2.643.100.1") + SNILS = ObjectIdentifier("1.2.643.100.3") + UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") + + +class SignatureAlgorithmOID(object): + RSA_WITH_MD5 = ObjectIdentifier("1.2.840.113549.1.1.4") + RSA_WITH_SHA1 = ObjectIdentifier("1.2.840.113549.1.1.5") + # This is an alternate OID for RSA with SHA1 that is occasionally seen + _RSA_WITH_SHA1 = ObjectIdentifier("1.3.14.3.2.29") + RSA_WITH_SHA224 = ObjectIdentifier("1.2.840.113549.1.1.14") + 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") + ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3") + ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4") + DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3") + DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1") + DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2") + ED25519 = ObjectIdentifier("1.3.101.112") + ED448 = ObjectIdentifier("1.3.101.113") + GOSTR3411_94_WITH_3410_2001 = ObjectIdentifier("1.2.643.2.2.3") + GOSTR3410_2012_WITH_3411_2012_256 = ObjectIdentifier("1.2.643.7.1.1.3.2") + GOSTR3410_2012_WITH_3411_2012_512 = ObjectIdentifier("1.2.643.7.1.1.3.3") + + +_SIG_OIDS_TO_HASH: typing.Dict[ + ObjectIdentifier, typing.Optional[hashes.HashAlgorithm] +] = { + SignatureAlgorithmOID.RSA_WITH_MD5: hashes.MD5(), + SignatureAlgorithmOID.RSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID._RSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.RSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.RSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.RSA_WITH_SHA384: hashes.SHA384(), + SignatureAlgorithmOID.RSA_WITH_SHA512: hashes.SHA512(), + SignatureAlgorithmOID.ECDSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.ECDSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.ECDSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.ECDSA_WITH_SHA384: hashes.SHA384(), + SignatureAlgorithmOID.ECDSA_WITH_SHA512: hashes.SHA512(), + SignatureAlgorithmOID.DSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.DSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.DSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.ED25519: None, + SignatureAlgorithmOID.ED448: None, + SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: None, + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: None, + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: None, +} + + +class ExtendedKeyUsageOID(object): + SERVER_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.1") + CLIENT_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.2") + CODE_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.3") + EMAIL_PROTECTION = ObjectIdentifier("1.3.6.1.5.5.7.3.4") + TIME_STAMPING = ObjectIdentifier("1.3.6.1.5.5.7.3.8") + OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9") + ANY_EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37.0") + SMARTCARD_LOGON = ObjectIdentifier("1.3.6.1.4.1.311.20.2.2") + KERBEROS_PKINIT_KDC = ObjectIdentifier("1.3.6.1.5.2.3.5") + + +class AuthorityInformationAccessOID(object): + CA_ISSUERS = ObjectIdentifier("1.3.6.1.5.5.7.48.2") + OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1") + + +class SubjectInformationAccessOID(object): + CA_REPOSITORY = ObjectIdentifier("1.3.6.1.5.5.7.48.5") + + +class CertificatePoliciesOID(object): + CPS_QUALIFIER = ObjectIdentifier("1.3.6.1.5.5.7.2.1") + CPS_USER_NOTICE = ObjectIdentifier("1.3.6.1.5.5.7.2.2") + ANY_POLICY = ObjectIdentifier("2.5.29.32.0") + + +class AttributeOID(object): + CHALLENGE_PASSWORD = ObjectIdentifier("1.2.840.113549.1.9.7") + UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") + + +_OID_NAMES = { + NameOID.COMMON_NAME: "commonName", + NameOID.COUNTRY_NAME: "countryName", + NameOID.LOCALITY_NAME: "localityName", + NameOID.STATE_OR_PROVINCE_NAME: "stateOrProvinceName", + NameOID.STREET_ADDRESS: "streetAddress", + NameOID.ORGANIZATION_NAME: "organizationName", + NameOID.ORGANIZATIONAL_UNIT_NAME: "organizationalUnitName", + NameOID.SERIAL_NUMBER: "serialNumber", + NameOID.SURNAME: "surname", + NameOID.GIVEN_NAME: "givenName", + NameOID.TITLE: "title", + NameOID.GENERATION_QUALIFIER: "generationQualifier", + NameOID.X500_UNIQUE_IDENTIFIER: "x500UniqueIdentifier", + NameOID.DN_QUALIFIER: "dnQualifier", + NameOID.PSEUDONYM: "pseudonym", + NameOID.USER_ID: "userID", + NameOID.DOMAIN_COMPONENT: "domainComponent", + NameOID.EMAIL_ADDRESS: "emailAddress", + NameOID.JURISDICTION_COUNTRY_NAME: "jurisdictionCountryName", + NameOID.JURISDICTION_LOCALITY_NAME: "jurisdictionLocalityName", + NameOID.JURISDICTION_STATE_OR_PROVINCE_NAME: ( + "jurisdictionStateOrProvinceName" + ), + NameOID.BUSINESS_CATEGORY: "businessCategory", + NameOID.POSTAL_ADDRESS: "postalAddress", + NameOID.POSTAL_CODE: "postalCode", + NameOID.INN: "INN", + NameOID.OGRN: "OGRN", + NameOID.SNILS: "SNILS", + NameOID.UNSTRUCTURED_NAME: "unstructuredName", + SignatureAlgorithmOID.RSA_WITH_MD5: "md5WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA1: "sha1WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA224: "sha224WithRSAEncryption", + 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", + SignatureAlgorithmOID.ECDSA_WITH_SHA384: "ecdsa-with-SHA384", + SignatureAlgorithmOID.ECDSA_WITH_SHA512: "ecdsa-with-SHA512", + SignatureAlgorithmOID.DSA_WITH_SHA1: "dsa-with-sha1", + SignatureAlgorithmOID.DSA_WITH_SHA224: "dsa-with-sha224", + SignatureAlgorithmOID.DSA_WITH_SHA256: "dsa-with-sha256", + SignatureAlgorithmOID.ED25519: "ed25519", + SignatureAlgorithmOID.ED448: "ed448", + SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: ( + "GOST R 34.11-94 with GOST R 34.10-2001" + ), + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: ( + "GOST R 34.10-2012 with GOST R 34.11-2012 (256 bit)" + ), + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: ( + "GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)" + ), + ExtendedKeyUsageOID.SERVER_AUTH: "serverAuth", + ExtendedKeyUsageOID.CLIENT_AUTH: "clientAuth", + ExtendedKeyUsageOID.CODE_SIGNING: "codeSigning", + ExtendedKeyUsageOID.EMAIL_PROTECTION: "emailProtection", + ExtendedKeyUsageOID.TIME_STAMPING: "timeStamping", + ExtendedKeyUsageOID.OCSP_SIGNING: "OCSPSigning", + ExtendedKeyUsageOID.SMARTCARD_LOGON: "msSmartcardLogin", + ExtendedKeyUsageOID.KERBEROS_PKINIT_KDC: "pkInitKDC", + ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES: "subjectDirectoryAttributes", + ExtensionOID.SUBJECT_KEY_IDENTIFIER: "subjectKeyIdentifier", + ExtensionOID.KEY_USAGE: "keyUsage", + ExtensionOID.SUBJECT_ALTERNATIVE_NAME: "subjectAltName", + ExtensionOID.ISSUER_ALTERNATIVE_NAME: "issuerAltName", + ExtensionOID.BASIC_CONSTRAINTS: "basicConstraints", + ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: ( + "signedCertificateTimestampList" + ), + ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS: ( + "signedCertificateTimestampList" + ), + ExtensionOID.PRECERT_POISON: "ctPoison", + CRLEntryExtensionOID.CRL_REASON: "cRLReason", + CRLEntryExtensionOID.INVALIDITY_DATE: "invalidityDate", + CRLEntryExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer", + ExtensionOID.NAME_CONSTRAINTS: "nameConstraints", + ExtensionOID.CRL_DISTRIBUTION_POINTS: "cRLDistributionPoints", + ExtensionOID.CERTIFICATE_POLICIES: "certificatePolicies", + ExtensionOID.POLICY_MAPPINGS: "policyMappings", + ExtensionOID.AUTHORITY_KEY_IDENTIFIER: "authorityKeyIdentifier", + ExtensionOID.POLICY_CONSTRAINTS: "policyConstraints", + 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", + ExtensionOID.CRL_NUMBER: "cRLNumber", + ExtensionOID.DELTA_CRL_INDICATOR: "deltaCRLIndicator", + ExtensionOID.TLS_FEATURE: "TLSFeature", + AuthorityInformationAccessOID.OCSP: "OCSP", + AuthorityInformationAccessOID.CA_ISSUERS: "caIssuers", + SubjectInformationAccessOID.CA_REPOSITORY: "caRepository", + CertificatePoliciesOID.CPS_QUALIFIER: "id-qt-cps", + CertificatePoliciesOID.CPS_USER_NOTICE: "id-qt-unotice", + OCSPExtensionOID.NONCE: "OCSPNonce", + AttributeOID.CHALLENGE_PASSWORD: "challengePassword", +} diff --git a/src/cryptography/hazmat/backends/openssl/ocsp.py b/src/cryptography/hazmat/backends/openssl/ocsp.py index c69be3123c5e..82a5c057b124 100644 --- a/src/cryptography/hazmat/backends/openssl/ocsp.py +++ b/src/cryptography/hazmat/backends/openssl/ocsp.py @@ -7,6 +7,7 @@ from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat._oid import _SIG_OIDS_TO_HASH from cryptography.hazmat.backends.openssl.decode_asn1 import ( _CRL_ENTRY_REASON_CODE_TO_ENUM, _asn1_integer_to_int, @@ -141,7 +142,7 @@ def signature_hash_algorithm( self._requires_successful_response() oid = self.signature_algorithm_oid try: - return x509._SIG_OIDS_TO_HASH[oid] + return _SIG_OIDS_TO_HASH[oid] except KeyError: raise UnsupportedAlgorithm( "Signature algorithm OID:{} not recognized".format(oid) diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index d2017efdf559..be9436e01ae7 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -10,6 +10,7 @@ from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat._oid import _SIG_OIDS_TO_HASH from cryptography.hazmat.backends.openssl import dsa, ec, rsa from cryptography.hazmat.backends.openssl.decode_asn1 import ( _asn1_integer_to_int, @@ -131,7 +132,7 @@ def signature_hash_algorithm( ) -> typing.Optional[hashes.HashAlgorithm]: oid = self.signature_algorithm_oid try: - return x509._SIG_OIDS_TO_HASH[oid] + return _SIG_OIDS_TO_HASH[oid] except KeyError: raise UnsupportedAlgorithm( "Signature algorithm OID:{} not recognized".format(oid) @@ -292,7 +293,7 @@ def signature_hash_algorithm( ) -> typing.Optional[hashes.HashAlgorithm]: oid = self.signature_algorithm_oid try: - return x509._SIG_OIDS_TO_HASH[oid] + return _SIG_OIDS_TO_HASH[oid] except KeyError: raise UnsupportedAlgorithm( "Signature algorithm OID:{} not recognized".format(oid) diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py index 5003e09d3fa9..fa7fbd48094d 100644 --- a/src/cryptography/x509/__init__.py +++ b/src/cryptography/x509/__init__.py @@ -93,7 +93,6 @@ NameOID, ObjectIdentifier, SignatureAlgorithmOID, - _SIG_OIDS_TO_HASH, ) @@ -231,7 +230,6 @@ "CertificateSigningRequestBuilder", "CertificateBuilder", "Version", - "_SIG_OIDS_TO_HASH", "OID_CA_ISSUERS", "OID_OCSP", "_GENERAL_NAMES", diff --git a/src/cryptography/x509/oid.py b/src/cryptography/x509/oid.py index cc3250c891d0..9bfac75a4803 100644 --- a/src/cryptography/x509/oid.py +++ b/src/cryptography/x509/oid.py @@ -2,273 +2,19 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. -import typing - -from cryptography.hazmat._oid import ObjectIdentifier -from cryptography.hazmat.primitives import hashes - - -class ExtensionOID(object): - SUBJECT_DIRECTORY_ATTRIBUTES = ObjectIdentifier("2.5.29.9") - SUBJECT_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.14") - KEY_USAGE = ObjectIdentifier("2.5.29.15") - SUBJECT_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.17") - ISSUER_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.18") - BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19") - NAME_CONSTRAINTS = ObjectIdentifier("2.5.29.30") - CRL_DISTRIBUTION_POINTS = ObjectIdentifier("2.5.29.31") - CERTIFICATE_POLICIES = ObjectIdentifier("2.5.29.32") - POLICY_MAPPINGS = ObjectIdentifier("2.5.29.33") - AUTHORITY_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.35") - POLICY_CONSTRAINTS = ObjectIdentifier("2.5.29.36") - 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") - TLS_FEATURE = ObjectIdentifier("1.3.6.1.5.5.7.1.24") - CRL_NUMBER = ObjectIdentifier("2.5.29.20") - DELTA_CRL_INDICATOR = ObjectIdentifier("2.5.29.27") - 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") - SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.5") - - -class OCSPExtensionOID(object): - NONCE = ObjectIdentifier("1.3.6.1.5.5.7.48.1.2") - - -class CRLEntryExtensionOID(object): - CERTIFICATE_ISSUER = ObjectIdentifier("2.5.29.29") - CRL_REASON = ObjectIdentifier("2.5.29.21") - INVALIDITY_DATE = ObjectIdentifier("2.5.29.24") - - -class NameOID(object): - COMMON_NAME = ObjectIdentifier("2.5.4.3") - COUNTRY_NAME = ObjectIdentifier("2.5.4.6") - LOCALITY_NAME = ObjectIdentifier("2.5.4.7") - STATE_OR_PROVINCE_NAME = ObjectIdentifier("2.5.4.8") - STREET_ADDRESS = ObjectIdentifier("2.5.4.9") - ORGANIZATION_NAME = ObjectIdentifier("2.5.4.10") - ORGANIZATIONAL_UNIT_NAME = ObjectIdentifier("2.5.4.11") - SERIAL_NUMBER = ObjectIdentifier("2.5.4.5") - SURNAME = ObjectIdentifier("2.5.4.4") - GIVEN_NAME = ObjectIdentifier("2.5.4.42") - TITLE = ObjectIdentifier("2.5.4.12") - GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44") - X500_UNIQUE_IDENTIFIER = ObjectIdentifier("2.5.4.45") - DN_QUALIFIER = ObjectIdentifier("2.5.4.46") - PSEUDONYM = ObjectIdentifier("2.5.4.65") - USER_ID = ObjectIdentifier("0.9.2342.19200300.100.1.1") - DOMAIN_COMPONENT = ObjectIdentifier("0.9.2342.19200300.100.1.25") - EMAIL_ADDRESS = ObjectIdentifier("1.2.840.113549.1.9.1") - JURISDICTION_COUNTRY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.3") - JURISDICTION_LOCALITY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.1") - JURISDICTION_STATE_OR_PROVINCE_NAME = ObjectIdentifier( - "1.3.6.1.4.1.311.60.2.1.2" - ) - BUSINESS_CATEGORY = ObjectIdentifier("2.5.4.15") - POSTAL_ADDRESS = ObjectIdentifier("2.5.4.16") - POSTAL_CODE = ObjectIdentifier("2.5.4.17") - INN = ObjectIdentifier("1.2.643.3.131.1.1") - OGRN = ObjectIdentifier("1.2.643.100.1") - SNILS = ObjectIdentifier("1.2.643.100.3") - UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") - - -class SignatureAlgorithmOID(object): - RSA_WITH_MD5 = ObjectIdentifier("1.2.840.113549.1.1.4") - RSA_WITH_SHA1 = ObjectIdentifier("1.2.840.113549.1.1.5") - # This is an alternate OID for RSA with SHA1 that is occasionally seen - _RSA_WITH_SHA1 = ObjectIdentifier("1.3.14.3.2.29") - RSA_WITH_SHA224 = ObjectIdentifier("1.2.840.113549.1.1.14") - 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") - ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3") - ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4") - DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3") - DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1") - DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2") - ED25519 = ObjectIdentifier("1.3.101.112") - ED448 = ObjectIdentifier("1.3.101.113") - GOSTR3411_94_WITH_3410_2001 = ObjectIdentifier("1.2.643.2.2.3") - GOSTR3410_2012_WITH_3411_2012_256 = ObjectIdentifier("1.2.643.7.1.1.3.2") - GOSTR3410_2012_WITH_3411_2012_512 = ObjectIdentifier("1.2.643.7.1.1.3.3") - - -_SIG_OIDS_TO_HASH: typing.Dict[ - ObjectIdentifier, typing.Optional[hashes.HashAlgorithm] -] = { - SignatureAlgorithmOID.RSA_WITH_MD5: hashes.MD5(), - SignatureAlgorithmOID.RSA_WITH_SHA1: hashes.SHA1(), - SignatureAlgorithmOID._RSA_WITH_SHA1: hashes.SHA1(), - SignatureAlgorithmOID.RSA_WITH_SHA224: hashes.SHA224(), - SignatureAlgorithmOID.RSA_WITH_SHA256: hashes.SHA256(), - SignatureAlgorithmOID.RSA_WITH_SHA384: hashes.SHA384(), - SignatureAlgorithmOID.RSA_WITH_SHA512: hashes.SHA512(), - SignatureAlgorithmOID.ECDSA_WITH_SHA1: hashes.SHA1(), - SignatureAlgorithmOID.ECDSA_WITH_SHA224: hashes.SHA224(), - SignatureAlgorithmOID.ECDSA_WITH_SHA256: hashes.SHA256(), - SignatureAlgorithmOID.ECDSA_WITH_SHA384: hashes.SHA384(), - SignatureAlgorithmOID.ECDSA_WITH_SHA512: hashes.SHA512(), - SignatureAlgorithmOID.DSA_WITH_SHA1: hashes.SHA1(), - SignatureAlgorithmOID.DSA_WITH_SHA224: hashes.SHA224(), - SignatureAlgorithmOID.DSA_WITH_SHA256: hashes.SHA256(), - SignatureAlgorithmOID.ED25519: None, - SignatureAlgorithmOID.ED448: None, - SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: None, - SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: None, - SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: None, -} - - -class ExtendedKeyUsageOID(object): - SERVER_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.1") - CLIENT_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.2") - CODE_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.3") - EMAIL_PROTECTION = ObjectIdentifier("1.3.6.1.5.5.7.3.4") - TIME_STAMPING = ObjectIdentifier("1.3.6.1.5.5.7.3.8") - OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9") - ANY_EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37.0") - SMARTCARD_LOGON = ObjectIdentifier("1.3.6.1.4.1.311.20.2.2") - KERBEROS_PKINIT_KDC = ObjectIdentifier("1.3.6.1.5.2.3.5") - - -class AuthorityInformationAccessOID(object): - CA_ISSUERS = ObjectIdentifier("1.3.6.1.5.5.7.48.2") - OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1") - - -class SubjectInformationAccessOID(object): - CA_REPOSITORY = ObjectIdentifier("1.3.6.1.5.5.7.48.5") - - -class CertificatePoliciesOID(object): - CPS_QUALIFIER = ObjectIdentifier("1.3.6.1.5.5.7.2.1") - CPS_USER_NOTICE = ObjectIdentifier("1.3.6.1.5.5.7.2.2") - ANY_POLICY = ObjectIdentifier("2.5.29.32.0") - - -class AttributeOID(object): - CHALLENGE_PASSWORD = ObjectIdentifier("1.2.840.113549.1.9.7") - UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") - - -_OID_NAMES = { - NameOID.COMMON_NAME: "commonName", - NameOID.COUNTRY_NAME: "countryName", - NameOID.LOCALITY_NAME: "localityName", - NameOID.STATE_OR_PROVINCE_NAME: "stateOrProvinceName", - NameOID.STREET_ADDRESS: "streetAddress", - NameOID.ORGANIZATION_NAME: "organizationName", - NameOID.ORGANIZATIONAL_UNIT_NAME: "organizationalUnitName", - NameOID.SERIAL_NUMBER: "serialNumber", - NameOID.SURNAME: "surname", - NameOID.GIVEN_NAME: "givenName", - NameOID.TITLE: "title", - NameOID.GENERATION_QUALIFIER: "generationQualifier", - NameOID.X500_UNIQUE_IDENTIFIER: "x500UniqueIdentifier", - NameOID.DN_QUALIFIER: "dnQualifier", - NameOID.PSEUDONYM: "pseudonym", - NameOID.USER_ID: "userID", - NameOID.DOMAIN_COMPONENT: "domainComponent", - NameOID.EMAIL_ADDRESS: "emailAddress", - NameOID.JURISDICTION_COUNTRY_NAME: "jurisdictionCountryName", - NameOID.JURISDICTION_LOCALITY_NAME: "jurisdictionLocalityName", - NameOID.JURISDICTION_STATE_OR_PROVINCE_NAME: ( - "jurisdictionStateOrProvinceName" - ), - NameOID.BUSINESS_CATEGORY: "businessCategory", - NameOID.POSTAL_ADDRESS: "postalAddress", - NameOID.POSTAL_CODE: "postalCode", - NameOID.INN: "INN", - NameOID.OGRN: "OGRN", - NameOID.SNILS: "SNILS", - NameOID.UNSTRUCTURED_NAME: "unstructuredName", - SignatureAlgorithmOID.RSA_WITH_MD5: "md5WithRSAEncryption", - SignatureAlgorithmOID.RSA_WITH_SHA1: "sha1WithRSAEncryption", - SignatureAlgorithmOID.RSA_WITH_SHA224: "sha224WithRSAEncryption", - 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", - SignatureAlgorithmOID.ECDSA_WITH_SHA384: "ecdsa-with-SHA384", - SignatureAlgorithmOID.ECDSA_WITH_SHA512: "ecdsa-with-SHA512", - SignatureAlgorithmOID.DSA_WITH_SHA1: "dsa-with-sha1", - SignatureAlgorithmOID.DSA_WITH_SHA224: "dsa-with-sha224", - SignatureAlgorithmOID.DSA_WITH_SHA256: "dsa-with-sha256", - SignatureAlgorithmOID.ED25519: "ed25519", - SignatureAlgorithmOID.ED448: "ed448", - SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: ( - "GOST R 34.11-94 with GOST R 34.10-2001" - ), - SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: ( - "GOST R 34.10-2012 with GOST R 34.11-2012 (256 bit)" - ), - SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: ( - "GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)" - ), - ExtendedKeyUsageOID.SERVER_AUTH: "serverAuth", - ExtendedKeyUsageOID.CLIENT_AUTH: "clientAuth", - ExtendedKeyUsageOID.CODE_SIGNING: "codeSigning", - ExtendedKeyUsageOID.EMAIL_PROTECTION: "emailProtection", - ExtendedKeyUsageOID.TIME_STAMPING: "timeStamping", - ExtendedKeyUsageOID.OCSP_SIGNING: "OCSPSigning", - ExtendedKeyUsageOID.SMARTCARD_LOGON: "msSmartcardLogin", - ExtendedKeyUsageOID.KERBEROS_PKINIT_KDC: "pkInitKDC", - ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES: "subjectDirectoryAttributes", - ExtensionOID.SUBJECT_KEY_IDENTIFIER: "subjectKeyIdentifier", - ExtensionOID.KEY_USAGE: "keyUsage", - ExtensionOID.SUBJECT_ALTERNATIVE_NAME: "subjectAltName", - ExtensionOID.ISSUER_ALTERNATIVE_NAME: "issuerAltName", - ExtensionOID.BASIC_CONSTRAINTS: "basicConstraints", - ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: ( - "signedCertificateTimestampList" - ), - ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS: ( - "signedCertificateTimestampList" - ), - ExtensionOID.PRECERT_POISON: "ctPoison", - CRLEntryExtensionOID.CRL_REASON: "cRLReason", - CRLEntryExtensionOID.INVALIDITY_DATE: "invalidityDate", - CRLEntryExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer", - ExtensionOID.NAME_CONSTRAINTS: "nameConstraints", - ExtensionOID.CRL_DISTRIBUTION_POINTS: "cRLDistributionPoints", - ExtensionOID.CERTIFICATE_POLICIES: "certificatePolicies", - ExtensionOID.POLICY_MAPPINGS: "policyMappings", - ExtensionOID.AUTHORITY_KEY_IDENTIFIER: "authorityKeyIdentifier", - ExtensionOID.POLICY_CONSTRAINTS: "policyConstraints", - 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", - ExtensionOID.CRL_NUMBER: "cRLNumber", - ExtensionOID.DELTA_CRL_INDICATOR: "deltaCRLIndicator", - ExtensionOID.TLS_FEATURE: "TLSFeature", - AuthorityInformationAccessOID.OCSP: "OCSP", - AuthorityInformationAccessOID.CA_ISSUERS: "caIssuers", - SubjectInformationAccessOID.CA_REPOSITORY: "caRepository", - CertificatePoliciesOID.CPS_QUALIFIER: "id-qt-cps", - CertificatePoliciesOID.CPS_USER_NOTICE: "id-qt-unotice", - OCSPExtensionOID.NONCE: "OCSPNonce", - AttributeOID.CHALLENGE_PASSWORD: "challengePassword", -} +from cryptography.hazmat._oid import ( + AttributeOID, + AuthorityInformationAccessOID, + CRLEntryExtensionOID, + CertificatePoliciesOID, + ExtendedKeyUsageOID, + ExtensionOID, + NameOID, + OCSPExtensionOID, + ObjectIdentifier, + SignatureAlgorithmOID, + SubjectInformationAccessOID, +) __all__ = [ diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index cbc8b2c359c6..1be065a89d18 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -294,7 +294,7 @@ impl Certificate { py: pyo3::Python<'p>, ) -> Result<&'p pyo3::PyAny, PyAsn1Error> { let sig_oids_to_hash = py - .import("cryptography.x509")? + .import("cryptography.hazmat._oid")? .getattr("_SIG_OIDS_TO_HASH")?; let hash_alg = sig_oids_to_hash.get_item(self.signature_algorithm_oid(py)?); match hash_alg { diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index bc3688bd0d8f..3a8d78168df7 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -14,6 +14,7 @@ import pytest from cryptography import x509 +from cryptography.hazmat._oid import _OID_NAMES from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec from cryptography.x509 import DNSName, NameConstraints, SubjectAlternativeName @@ -25,7 +26,6 @@ NameOID, ObjectIdentifier, SubjectInformationAccessOID, - _OID_NAMES, ) from .test_x509 import _load_cert From bacf23f3edfa2ce880b7cd740d63f10058732fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A1ndor=20Jenei?= <35337337+SlaushVunter@users.noreply.github.com> Date: Mon, 13 Sep 2021 11:08:34 +0200 Subject: [PATCH 0312/1456] _ModuleWithDeprecations should inherit from types.ModuleType (#6267) (#6268) * _ModuleWithDeprecations should inherit from types.ModuleType (#6267) Update utils.py * fix typos reported by black * flake8 fix * Test should fail when int_from_bytes will be removed. Because this test would become pointless then. --- src/cryptography/utils.py | 4 +++- tests/test_utils.py | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index 3cfd32e98855..2ce68f7ce887 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -7,6 +7,7 @@ import enum import inspect import sys +import types import typing import warnings @@ -113,8 +114,9 @@ def __init__(self, value, message, warning_class): self.warning_class = warning_class -class _ModuleWithDeprecations(object): +class _ModuleWithDeprecations(types.ModuleType): def __init__(self, module): + super().__init__(module.__name__) self.__dict__["_module"] = module def __getattr__(self, attr): diff --git a/tests/test_utils.py b/tests/test_utils.py index 389638f151a8..ee411c36718c 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -4,6 +4,7 @@ import binascii +import inspect import os import textwrap @@ -12,6 +13,7 @@ import pytest import cryptography +import cryptography.utils from cryptography.exceptions import UnsupportedAlgorithm, _Reasons import cryptography_vectors @@ -4444,3 +4446,13 @@ def test_raises_unsupported_algorithm(): "An error.", _Reasons.BACKEND_MISSING_INTERFACE ) assert exc_info.type is UnsupportedAlgorithm + + +def test_inspect_deprecated_module(): + # Check if inspection is supported by _ModuleWithDeprecations. + assert isinstance( + cryptography.utils, cryptography.utils._ModuleWithDeprecations + ) + source_file = inspect.getsourcefile(cryptography.utils) + assert isinstance(source_file, str) + assert source_file.endswith("utils.py") From e6f0e1f7063491a03cbb273f8c8d2b012921da14 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Sep 2021 08:22:28 -0400 Subject: [PATCH 0313/1456] Bump libc from 0.2.101 to 0.2.102 in /src/rust (#6274) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.101 to 0.2.102. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.101...0.2.102) --- updated-dependencies: - dependency-name: libc dependency-type: indirect update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/rust/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 481e7385218f..7ea29279d5fd 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -121,9 +121,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.101" +version = "0.2.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" +checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" [[package]] name = "lock_api" From dda20a4438ac440ada18139d96fb6b74471514d4 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 18 Sep 2021 19:07:45 -0400 Subject: [PATCH 0314/1456] backport some tests needed for full coverage of rust (#6277) --- tests/x509/test_x509.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 58dde9b1aa59..405c09e8d869 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -102,6 +102,14 @@ def test_invalid_pem(self, backend): with pytest.raises(ValueError): x509.load_pem_x509_crl(b"notacrl", backend) + pem_bytes = _load_cert( + os.path.join("x509", "custom", "valid_signature_cert.pem"), + lambda data, backend: data, + backend, + ) + with pytest.raises(ValueError): + x509.load_pem_x509_crl(pem_bytes, backend) + def test_invalid_der(self, backend): with pytest.raises(ValueError): x509.load_der_x509_crl(b"notacrl", backend) @@ -170,6 +178,15 @@ def test_equality(self, backend): assert crl1 != crl3 assert crl1 != object() + def test_comparison(self, backend): + crl1 = _load_cert( + os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"), + x509.load_der_x509_crl, + backend, + ) + with pytest.raises(TypeError): + crl1 < crl1 + def test_update_dates(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_all_reasons.pem"), From 88e805808883d2b321857f956ee523d0665bbf35 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 19 Sep 2021 07:50:12 +0800 Subject: [PATCH 0315/1456] add vector omitting optional ASN.1 SEQUENCE for an empty CRL (#6279) --- docs/development/test-vectors.rst | 2 ++ tests/x509/test_x509.py | 10 ++++++++++ .../x509/custom/crl_empty_no_sequence.der | Bin 0 -> 361 bytes 3 files changed, 12 insertions(+) create mode 100644 vectors/cryptography_vectors/x509/custom/crl_empty_no_sequence.der diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 6d096f63e43b..8de8bf347e51 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -495,6 +495,8 @@ Custom X.509 Certificate Revocation List Vectors * ``crl_inval_cert_issuer_entry_ext.pem`` - Contains a CRL with one revocation which has one entry extension for certificate issuer with an empty value. * ``crl_empty.pem`` - Contains a CRL with no revoked certificates. +* ``crl_empty_no_sequence.der`` - Contains a CRL with no revoked certificates + and the optional ASN.1 sequence for revoked certificates is omitted. * ``crl_ian_aia_aki.pem`` - Contains a CRL with ``IssuerAlternativeName``, ``AuthorityInformationAccess``, ``AuthorityKeyIdentifier`` and ``CRLNumber`` extensions. diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 405c09e8d869..ef412bc606d0 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -98,6 +98,16 @@ def test_load_der_crl(self, backend): assert fingerprint == b"dd3db63c50f4c4a13e090f14053227cb1011a5ad" assert isinstance(crl.signature_hash_algorithm, hashes.SHA256) + def test_empty_crl_no_sequence(self, backend): + # The SEQUENCE for revoked certificates is optional so let's + # test that we handle it properly. + crl = _load_cert( + os.path.join("x509", "custom", "crl_empty_no_sequence.der"), + x509.load_der_x509_crl, + backend, + ) + assert len(crl) == 0 + def test_invalid_pem(self, backend): with pytest.raises(ValueError): x509.load_pem_x509_crl(b"notacrl", backend) diff --git a/vectors/cryptography_vectors/x509/custom/crl_empty_no_sequence.der b/vectors/cryptography_vectors/x509/custom/crl_empty_no_sequence.der new file mode 100644 index 0000000000000000000000000000000000000000..7dd7b7ffb34082f564a09ca2e39a8f3d4d11e6eb GIT binary patch literal 361 zcmXqLVoWvgXJTYD;AP{~YV&CO&dbQi&B|aPYbb3X$;KSY!ptL-TvS<5lAm6bSddYv zmzl5N>?qD_U}RuuU}y*;4Wh((jSY~vXl5}tF)}i!v`>5S>4{_a17r4+rw>i3-a4hQ zNPJsVc~thcCdE(H;Tt~B_jwzZyewXaapHucv*j7Q*>dGfamuZBtNgA9&6j?d#-iWy zWm-iw*TyAs%CApsO5~rtZQfnwmr~A7lX9nY`DQ)jU04&i`bJTG!;>Ex{L3zKYgvli zc*B`){M=%v*Piz$^Gq1H0*2A-7kyUL zuATJJ_ox#uj>ihDS34ci>=Lk@Ebzq}AV8QS!ErG=x(D*f~Cm2_D@ ut$Q47CH1pt3uArM!^;O9L;PM$-*e*Sm9I~#EjzU(_OS_Ef2sYeUkCugot4%A literal 0 HcmV?d00001 From 77358f80fd66f8c9edef4cab6dafd6f21db7459d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 18 Sep 2021 20:15:37 -0400 Subject: [PATCH 0316/1456] Added a test of encoding a CRLReason, needed for Rust coverage (#6278) --- tests/x509/test_x509_crlbuilder.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/x509/test_x509_crlbuilder.py b/tests/x509/test_x509_crlbuilder.py index 14fe2387107f..cc09db78f1f9 100644 --- a/tests/x509/test_x509_crlbuilder.py +++ b/tests/x509/test_x509_crlbuilder.py @@ -748,6 +748,9 @@ def test_sign_with_revoked_certificates(self, backend): .serial_number(2) .revocation_date(datetime.datetime(2012, 1, 1, 1, 1)) .add_extension(invalidity_date, False) + .add_extension( + x509.CRLReason(x509.ReasonFlags.ca_compromise), False + ) .build(backend) ) builder = ( @@ -776,7 +779,7 @@ def test_sign_with_revoked_certificates(self, backend): assert len(crl[0].extensions) == 0 assert crl[1].serial_number == revoked_cert1.serial_number assert crl[1].revocation_date == revoked_cert1.revocation_date - assert len(crl[1].extensions) == 1 + assert len(crl[1].extensions) == 2 ext = crl[1].extensions.get_extension_for_class(x509.InvalidityDate) assert ext.critical is False assert ext.value == invalidity_date From 0af8579975d1449157900679080888199e0fad5e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 18 Sep 2021 20:27:37 -0400 Subject: [PATCH 0317/1456] Added more tests for empty CRL (#6281) --- tests/x509/test_x509.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index ef412bc606d0..0d0997baaec1 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -108,6 +108,11 @@ def test_empty_crl_no_sequence(self, backend): ) assert len(crl) == 0 + with pytest.raises(IndexError): + crl[0] + assert crl.get_revoked_certificate_by_serial_number(12) is None + assert list(iter(crl)) == [] + def test_invalid_pem(self, backend): with pytest.raises(ValueError): x509.load_pem_x509_crl(b"notacrl", backend) From 1a0ba3e79d1f52cf1967e4ac177cdae788d9829a Mon Sep 17 00:00:00 2001 From: John Jones Date: Sat, 18 Sep 2021 18:13:45 -0700 Subject: [PATCH 0318/1456] preparations for musllinux (#6236) * preparations for musllinux * wheel-builder | skip PyPy on musllinux builds --- .github/workflows/wheel-builder.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 1adb7cf2469b..b4936b42a92f 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -21,6 +21,13 @@ jobs: - { NAME: "manylinux2010_x86_64", CONTAINER: "cryptography-manylinux2010:x86_64" } - { NAME: "manylinux2014_x86_64", CONTAINER: "cryptography-manylinux2014:x86_64" } - { name: "manylinux_2_24_x86_64", CONTAINER: "cryptography-manylinux_2_24:x86_64"} + - { name: "musllinux_1_1_x86_64", CONTAINER: "cryptography-musllinux_1_1:x86_64"} + exclude: + # There are no readily available musllinux PyPy distributions + - PYTHON: { VERSION: "pypy3.6", PATH: "/opt/pypy3.6/bin/pypy" } + MANYLINUX: { name: "musllinux_1_1_x86_64", CONTAINER: "cryptography-musllinux_1_1:x86_64" } + - PYTHON: { VERSION: "pypy3.7", PATH: "/opt/pypy3.7/bin/pypy" } + MANYLINUX: { name: "musllinux_1_1_x86_64", CONTAINER: "cryptography-musllinux_1_1:x86_64"} name: "${{ matrix.PYTHON.VERSION }} for ${{ matrix.MANYLINUX.NAME }}" steps: - run: ${{ matrix.PYTHON.PATH }} -m venv .venv @@ -41,8 +48,8 @@ jobs: - run: auditwheel repair --plat ${{ matrix.MANYLINUX.NAME }} tmpwheelhouse/cryptograph*.whl -w wheelhouse/ - run: unzip wheelhouse/*.whl -d execstack.check - run: | - results=$(execstack execstack.check/cryptography/hazmat/bindings/*.so) - count=$(echo "$results" | grep -c '^X' || true) + results=$(readelf -lW execstack.check/cryptography/hazmat/bindings/*.so) + count=$(echo "$results" | grep -c 'GNU_STACK.*[R ][W ]E' || true) if [ "$count" -ne 0 ]; then exit 1 else From 6542c2f2f4beab41e883e860d3b3554993231bf4 Mon Sep 17 00:00:00 2001 From: John Jones Date: Sat, 18 Sep 2021 18:30:58 -0700 Subject: [PATCH 0319/1456] per discussion in #6236 (#6254) --- docs/faq.rst | 5 ++--- docs/installation.rst | 27 +++++++++++++-------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/docs/faq.rst b/docs/faq.rst index cfa2952fec29..befe3942e624 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -78,9 +78,8 @@ OpenSSL. If you see this error it is likely because your copy of ``pip`` is too old to find our wheel files. Upgrade your ``pip`` with ``pip install -U pip`` and then try to install ``cryptography`` again. -Users on PyPy, unusual CPU architectures, or distributions of Linux using -``musl`` (like Alpine) will need to compile ``cryptography`` themselves. Please -view our :doc:`/installation` documentation. +Users on unusual CPU architectures will need to compile ``cryptography`` +themselves. Please view our :doc:`/installation` documentation. ``cryptography`` raised an ``InternalError`` and I'm not sure what to do? ------------------------------------------------------------------------- diff --git a/docs/installation.rst b/docs/installation.rst index 65a8d012452a..a3b0cafdf730 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -87,17 +87,16 @@ Building cryptography on Linux ``cryptography`` ships ``manylinux`` wheels (as of 2.0) so all dependencies are included. For users on **pip 19.0** or above running on a ``manylinux2010`` -(or greater) compatible distribution (almost everything **except Alpine**) all +(or greater) compatible distribution (or **pip 21.2.4** for ``musllinux``) all you should need to do is: .. code-block:: console $ pip install cryptography -If you are on Alpine or just want to compile it yourself then -``cryptography`` requires a C compiler, a Rust compiler, headers for Python (if -you're not using ``pypy``), and headers for the OpenSSL and ``libffi`` libraries -available on your system. +If you want to compile ``cryptography`` yourself you'll need a C compiler, a +Rust compiler, headers for Python (if you're not using ``pypy``), and headers +for the OpenSSL and ``libffi`` libraries available on your system. On all Linux distributions you will need to have :ref:`Rust installed and available`. @@ -198,15 +197,15 @@ Static Wheels ~~~~~~~~~~~~~ Cryptography ships statically-linked wheels for macOS, Windows, and Linux (via -``manylinux``). This allows compatible environments to use the most recent -OpenSSL, regardless of what is shipped by default on those platforms. Some -Linux distributions (most notably Alpine) are not ``manylinux`` compatible so -we cannot distribute wheels for them. - -However, you can build your own statically-linked wheels that will work on your -own systems. This will allow you to continue to use relatively old Linux -distributions (such as LTS releases), while making sure you have the most -recent OpenSSL available to your Python programs. +``manylinux`` and ``musllinux``). This allows compatible environments to use +the most recent OpenSSL, regardless of what is shipped by default on those +platforms. + +If you are using a platform not covered by our wheels, you can build your own +statically-linked wheels that will work on your own systems. This will allow +you to continue to use relatively old Linux distributions (such as LTS +releases), while making sure you have the most recent OpenSSL available to +your Python programs. To do so, you should find yourself a machine that is as similar as possible to your target environment (e.g. your production environment): for example, spin From b1002451c01c455a21931a3fa51d9a19411fd83c Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 18 Sep 2021 21:57:38 -0400 Subject: [PATCH 0320/1456] Don't internal error on CRL with no nextUpdate value (#6282) * Don't internal error on CRL with no nextUpdate value * Fix typing * docs --- docs/development/test-vectors.rst | 2 ++ src/cryptography/hazmat/backends/openssl/x509.py | 5 +++-- src/cryptography/x509/base.py | 2 +- tests/x509/test_x509.py | 8 ++++++++ .../x509/custom/crl_no_next_update.pem | 12 ++++++++++++ 5 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 vectors/cryptography_vectors/x509/custom/crl_no_next_update.pem diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 8de8bf347e51..20f246cf6e68 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -540,6 +540,8 @@ Custom X.509 Certificate Revocation List Vectors ``extnValue`` of ``abcdef``. * ``crl_invalid_time.der`` - Contains a CRL with an invalid ``UTCTime`` value in ``thisUpdate``. The signature on this CRL is invalid. +* ``crl_no_next_time.pem`` - Contains a CRL with no ``nextUpdate`` value. The + signature on this CRL is invalid. X.509 OCSP Test Vectors ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index be9436e01ae7..b2dedcfd1338 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -155,9 +155,10 @@ def issuer(self) -> x509.Name: return _decode_x509_name(self._backend, issuer) @property - def next_update(self) -> datetime.datetime: + def next_update(self) -> typing.Optional[datetime.datetime]: nu = self._backend._lib.X509_CRL_get0_nextUpdate(self._x509_crl) - self._backend.openssl_assert(nu != self._backend._ffi.NULL) + if nu == self._backend._ffi.NULL: + return None return _parse_asn1_time(self._backend, nu) @property diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index 0e8154425f5d..22f6509f6eb5 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -258,7 +258,7 @@ def issuer(self) -> Name: """ @abc.abstractproperty - def next_update(self) -> datetime.datetime: + def next_update(self) -> typing.Optional[datetime.datetime]: """ Returns the date of next update for this CRL. """ diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 0d0997baaec1..99b7d4f82f69 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -215,6 +215,14 @@ def test_update_dates(self, backend): assert crl.next_update.isoformat() == "2016-01-01T00:00:00" assert crl.last_update.isoformat() == "2015-01-01T00:00:00" + def test_no_next_update(self, backend): + crl = _load_cert( + os.path.join("x509", "custom", "crl_no_next_update.pem"), + x509.load_pem_x509_crl, + backend, + ) + assert crl.next_update is None + def test_unrecognized_extension(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_unrecognized_extension.der"), diff --git a/vectors/cryptography_vectors/x509/custom/crl_no_next_update.pem b/vectors/cryptography_vectors/x509/custom/crl_no_next_update.pem new file mode 100644 index 000000000000..9acfa2dc953d --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/crl_no_next_update.pem @@ -0,0 +1,12 @@ +-----BEGIN X509 CRL----- +MIIBtjCBnwIBATANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJVUzERMA8GA1UE +CAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xETAPBgNVBAoMCHI1MDkgTExD +MRowGAYDVQQDDBFyNTA5IENSTCBEZWxlZ2F0ZRcNMTUxMjIwMjM0NDQ3WqAZMBcw +CgYDVR0UBAMCAQEwCQYDVR0jBAIwADANBgkqhkiG9w0BAQUFAAOCAQEAXebqoZfE +VAC4NcSEB5oGqUviUn/AnY6TzB6hUe8XC7yqEkBcyTgkG1Zq+b+T/5X1ewTldvuU +qv19WAU/Epbbu4488PoH5qMV8Aii2XcotLJOR9OBANp0Yy4ir/n6qyw8kM3hXJlo +E+xgkELhd5JmKCnlXihM1BTl7Xp7jyKeQ86omR+DhItbCU+9RoqOK9Hm087Z7Rur +XVrz5RKltQo7VLCp8VmrxFwfALCZENXGEQ+g5VkvoCjcph5jqOSyzp7aZy1pnLE/ +6U6V32ItskrwqA+x4oj2Wvzir/Q23y2zYfqOkuq4fTd2lWW+w5mB167fIWmd6efe +cDn1ZqbdECDPUg== +-----END X509 CRL----- From df4a0fd70b90a45d7bfb1973969d671fb46e156f Mon Sep 17 00:00:00 2001 From: "Nathaniel J. Smith" Date: Sun, 19 Sep 2021 01:35:30 -0700 Subject: [PATCH 0321/1456] musllinux ftw (#6285) * musllinux ftw * appease the spellchecker --- docs/installation.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index a3b0cafdf730..7737ed12f7a9 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -321,11 +321,11 @@ Rust .. note:: - If you are on RHEL/CentOS/Fedora/Debian/Ubuntu or another distribution - derived from the preceding list, then you should **upgrade pip** (in - a virtual environment!) and attempt to install ``cryptography`` again - before trying to install the Rust toolchain. These platforms will receive - a binary wheel and require no compiler if you have an updated ``pip``! + If you are using Linux, then you should **upgrade pip** (in + a virtual environment!) and attempt to install ``cryptography`` again before + trying to install the Rust toolchain. On most Linux distributions, the latest + version of ``pip`` will be able to install a binary wheel, so you won't need + a Rust toolchain. Building ``cryptography`` requires having a working Rust toolchain. The current minimum supported Rust version is 1.41.0. **This is newer than the Rust most From 770de275181a2f06358d916f629e88404835d793 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 19 Sep 2021 19:49:40 +0800 Subject: [PATCH 0322/1456] add musllinux arm64 build to zuul (#6280) * add musllinux arm64 build to zuul * remove unneeded installs + more debug * absurd * experiment * cccchanges * sigh --- .zuul.d/jobs.yaml | 4 ++++ .../wheel/roles/build-wheel-manylinux/files/build-wheels.sh | 2 ++ .../wheel/roles/build-wheel-manylinux/tasks/main.yaml | 4 ---- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.zuul.d/jobs.yaml b/.zuul.d/jobs.yaml index 8a61080ea537..cf4abaf9e9ec 100644 --- a/.zuul.d/jobs.yaml +++ b/.zuul.d/jobs.yaml @@ -32,6 +32,10 @@ image: ghcr.io/pyca/cryptography-manylinux_2_24:aarch64 pythons: - cp36-cp36m + - platform: musllinux_1_1_aarch64 + image: ghcr.io/pyca/cryptography-musllinux_1_1:aarch64 + pythons: + - cp36-cp36m - job: name: pyca-cryptography-build-wheel-x86_64 diff --git a/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/files/build-wheels.sh b/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/files/build-wheels.sh index 41cd6bcaedf9..216a839338e8 100644 --- a/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/files/build-wheels.sh +++ b/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/files/build-wheels.sh @@ -4,6 +4,8 @@ cd /io mkdir -p wheelhouse.final +rm -rf build +rm -rf dist for P in ${PYTHONS}; do diff --git a/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/tasks/main.yaml b/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/tasks/main.yaml index dbd2328713b1..680da00055d9 100644 --- a/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/tasks/main.yaml +++ b/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/tasks/main.yaml @@ -23,10 +23,6 @@ become: yes when: ansible_distribution in ['Debian', 'Ubuntu'] -- name: Install rust - include_role: - name: ensure-rust - - name: Install setuptools-rust pip: name: setuptools-rust From d702f5cdd88831feff7237006a86262164e4f04b Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 19 Sep 2021 19:51:54 +0800 Subject: [PATCH 0323/1456] changelog for musllinux (#6283) --- CHANGELOG.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2b054e8cfa78..3a84238ce7db 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,8 +24,10 @@ Changelog :class:`~cryptography.hazmat.primitives.ciphers.algorithms.SM4`, when using OpenSSL 1.1.1. These algorithms are provided for compatibility in regions where they may be required, and are not generally recommended. -* We now ship ``manylinux_2_24`` wheels, in addition to our ``manylinux2010`` - and ``manylinux2014`` wheels. +* We now ship ``manylinux_2_24`` and ``musllinux_1_1`` wheels, in addition to + our ``manylinux2010`` and ``manylinux2014`` wheels. Users on distributions + like Alpine Linux should ensure they upgrade to the latest ``pip`` to + correctly receive wheels. * Added ``rfc4514_attribute_name`` attribute to :attr:`x509.NameAttribute `. * Added :class:`~cryptography.hazmat.primitives.kdf.kbkdf.KBKDFCMAC`. From 6bc56acc25658a3e3c3a2ee76e6e92369f3915ab Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 19 Sep 2021 19:52:10 +0800 Subject: [PATCH 0324/1456] update setup.py links to the canonical URL (#6284) URL fragments don't work on the redirects anyway --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index f91c04cfc895..24b9f102bbf0 100644 --- a/setup.py +++ b/setup.py @@ -73,12 +73,12 @@ successfully install cryptography: 1) Upgrade to the latest pip and try again. This will fix errors for most users. See: https://pip.pypa.io/en/stable/installing/#upgrading-pip - 2) Read https://cryptography.io/en/latest/installation.html for specific + 2) Read https://cryptography.io/en/latest/installation/ for specific instructions for your platform. 3) Check our frequently asked questions for more information: - https://cryptography.io/en/latest/faq.html + https://cryptography.io/en/latest/faq/ 4) Ensure you have a recent Rust toolchain installed: - https://cryptography.io/en/latest/installation.html#rust + https://cryptography.io/en/latest/installation/#rust """ ) print(f" Python: {'.'.join(str(v) for v in sys.version_info[:3])}") From 9f6ac959a099702b89368d3b704044a2a8f231d8 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 19 Sep 2021 18:49:10 -0400 Subject: [PATCH 0325/1456] Migrate CRL implementation to Rust (#6276) (Lots of commits that got squashed) --- docs/x509/reference.rst | 2 +- .../hazmat/backends/interfaces.py | 12 - .../hazmat/backends/openssl/backend.py | 125 ++-- .../hazmat/backends/openssl/decode_asn1.py | 18 - .../hazmat/backends/openssl/x509.py | 247 +------ .../hazmat/bindings/_rust/x509.pyi | 8 +- src/cryptography/x509/base.py | 13 +- src/rust/src/asn1.rs | 2 +- src/rust/src/ocsp.rs | 4 +- src/rust/src/x509.rs | 615 +++++++++++++++--- tests/x509/test_x509.py | 18 +- 11 files changed, 642 insertions(+), 422 deletions(-) diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index 92d6f9062cef..36dbd6db68a7 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -513,7 +513,7 @@ X.509 CRL (Certificate Revocation List) Object 1 >>> revoked_certificate = crl[0] >>> type(revoked_certificate) - + >>> for r in crl: ... print(r.serial_number) 0 diff --git a/src/cryptography/hazmat/backends/interfaces.py b/src/cryptography/hazmat/backends/interfaces.py index 4b2d80a7770a..db708d4cdb0f 100644 --- a/src/cryptography/hazmat/backends/interfaces.py +++ b/src/cryptography/hazmat/backends/interfaces.py @@ -341,18 +341,6 @@ def x509_name_bytes(self, name: "Name") -> bytes: Compute the DER encoded bytes of an X509 Name object. """ - @abc.abstractmethod - def load_pem_x509_crl(self, data: bytes) -> "CertificateRevocationList": - """ - Load an X.509 CRL from PEM encoded data. - """ - - @abc.abstractmethod - def load_der_x509_crl(self, data: bytes) -> "CertificateRevocationList": - """ - Load an X.509 CRL from DER encoded data. - """ - class DHBackend(metaclass=abc.ABCMeta): @abc.abstractmethod diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 1a1db1ccca60..ab4ff1015f20 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -75,9 +75,8 @@ _X448PublicKey, ) from cryptography.hazmat.backends.openssl.x509 import ( - _CertificateRevocationList, _CertificateSigningRequest, - _RevokedCertificate, + _RawRevokedCertificate, ) from cryptography.hazmat.bindings._rust import ( asn1, @@ -126,6 +125,7 @@ from cryptography.hazmat.primitives.kdf import scrypt from cryptography.hazmat.primitives.serialization import pkcs7, ssh from cryptography.x509 import ocsp +from cryptography.x509.base import PUBLIC_KEY_TYPES from cryptography.x509.name import Name @@ -427,18 +427,6 @@ def _register_x509_ext_parsers(self): get_ext=self._lib.sk_X509_EXTENSION_value, rust_callback=rust_x509.parse_csr_extension, ) - self._revoked_cert_extension_parser = _X509ExtensionParser( - self, - ext_count=self._lib.X509_REVOKED_get_ext_count, - get_ext=self._lib.X509_REVOKED_get_ext, - rust_callback=rust_x509.parse_crl_entry_ext, - ) - self._crl_extension_parser = _X509ExtensionParser( - self, - ext_count=self._lib.X509_CRL_get_ext_count, - get_ext=self._lib.X509_CRL_get_ext, - rust_callback=rust_x509.parse_crl_extension, - ) self._ocsp_basicresp_ext_parser = _X509ExtensionParser( self, ext_count=self._lib.OCSP_BASICRESP_get_ext_count, @@ -1102,7 +1090,7 @@ def create_x509_crl( builder: x509.CertificateRevocationListBuilder, private_key: PRIVATE_KEY_TYPES, algorithm: typing.Optional[hashes.HashAlgorithm], - ) -> _CertificateRevocationList: + ) -> x509.CertificateRevocationList: if not isinstance(builder, x509.CertificateRevocationListBuilder): raise TypeError("Builder type mismatch.") self._x509_check_signature_params(private_key, algorithm) @@ -1144,13 +1132,30 @@ def create_x509_crl( # add revoked certificates for revoked_cert in builder._revoked_certificates: - # Duplicating because the X509_CRL takes ownership and will free - # this memory when X509_CRL_free is called. - revoked = self._lib.X509_REVOKED_dup( - revoked_cert._x509_revoked # type: ignore[attr-defined] + x509_revoked = self._lib.X509_REVOKED_new() + self.openssl_assert(x509_revoked != self._ffi.NULL) + serial_number = _encode_asn1_int_gc( + self, revoked_cert.serial_number + ) + res = self._lib.X509_REVOKED_set_serialNumber( + x509_revoked, serial_number ) - self.openssl_assert(revoked != self._ffi.NULL) - res = self._lib.X509_CRL_add0_revoked(x509_crl, revoked) + self.openssl_assert(res == 1) + rev_date = self._create_asn1_time(revoked_cert.revocation_date) + res = self._lib.X509_REVOKED_set_revocationDate( + x509_revoked, rev_date + ) + self.openssl_assert(res == 1) + # add CRL entry extensions + self._create_x509_extensions( + extensions=revoked_cert.extensions, + handlers=self._crl_entry_extension_encode_handlers, + x509_obj=x509_revoked, + add_func=self._lib.X509_REVOKED_add_ext, + gc=True, + ) + + res = self._lib.X509_CRL_add0_revoked(x509_crl, x509_revoked) self.openssl_assert(res == 1) res = self._lib.X509_CRL_sign( @@ -1160,7 +1165,10 @@ def create_x509_crl( errors = self._consume_errors_with_text() raise ValueError("Signing failed", errors) - return _CertificateRevocationList(self, x509_crl) + bio = self._create_mem_bio_gc() + res = self._lib.i2d_X509_CRL_bio(bio, x509_crl) + self.openssl_assert(res == 1) + return rust_x509.load_der_x509_crl(self._read_mem_bio(bio)) def _create_x509_extensions( self, extensions, handlers, x509_obj, add_func, gc @@ -1225,30 +1233,18 @@ def _create_x509_extension(self, handlers, extension): def create_x509_revoked_certificate( self, builder: x509.RevokedCertificateBuilder - ) -> _RevokedCertificate: + ) -> x509.RevokedCertificate: if not isinstance(builder, x509.RevokedCertificateBuilder): raise TypeError("Builder type mismatch.") - - x509_revoked = self._lib.X509_REVOKED_new() - self.openssl_assert(x509_revoked != self._ffi.NULL) - x509_revoked = self._ffi.gc(x509_revoked, self._lib.X509_REVOKED_free) - serial_number = _encode_asn1_int_gc(self, builder._serial_number) - res = self._lib.X509_REVOKED_set_serialNumber( - x509_revoked, serial_number - ) - self.openssl_assert(res == 1) - 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 - self._create_x509_extensions( - extensions=builder._extensions, - handlers=self._crl_entry_extension_encode_handlers, - x509_obj=x509_revoked, - add_func=self._lib.X509_REVOKED_add_ext, - gc=True, + serial_number = builder._serial_number + revocation_date = builder._revocation_date + assert serial_number is not None + assert revocation_date is not None + return _RawRevokedCertificate( + serial_number, + revocation_date, + x509.Extensions(builder._extensions), ) - return _RevokedCertificate(self, None, x509_revoked) def load_pem_private_key(self, data, password): return self._load_key( @@ -1390,31 +1386,34 @@ def _ossl2cert(self, x509: typing.Any) -> x509.Certificate: self.openssl_assert(res == 1) return rust_x509.load_der_x509_certificate(self._read_mem_bio(bio)) - def load_pem_x509_crl(self, data: bytes) -> _CertificateRevocationList: - mem_bio = self._bytes_to_bio(data) - x509_crl = self._lib.PEM_read_bio_X509_CRL( - mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL - ) - if x509_crl == self._ffi.NULL: - self._consume_errors() - raise ValueError( - "Unable to load CRL. See https://cryptography.io/en/la" - "test/faq.html#why-can-t-i-import-my-pem-file for more" - " details." + def _crl_is_signature_valid( + self, crl: x509.CertificateRevocationList, public_key: PUBLIC_KEY_TYPES + ) -> bool: + if not isinstance( + public_key, + ( + _DSAPublicKey, + _RSAPublicKey, + _EllipticCurvePublicKey, + ), + ): + raise TypeError( + "Expecting one of DSAPublicKey, RSAPublicKey," + " or EllipticCurvePublicKey." ) - - x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free) - return _CertificateRevocationList(self, x509_crl) - - def load_der_x509_crl(self, data: bytes) -> _CertificateRevocationList: + data = crl.public_bytes(serialization.Encoding.DER) mem_bio = self._bytes_to_bio(data) x509_crl = self._lib.d2i_X509_CRL_bio(mem_bio.bio, self._ffi.NULL) - if x509_crl == self._ffi.NULL: + self.openssl_assert(x509_crl != self._ffi.NULL) + x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free) + + res = self._lib.X509_CRL_verify(x509_crl, public_key._evp_pkey) + + if res != 1: self._consume_errors() - raise ValueError("Unable to load CRL") + return False - x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free) - return _CertificateRevocationList(self, x509_crl) + return True def load_pem_x509_csr(self, data: bytes) -> _CertificateSigningRequest: mem_bio = self._bytes_to_bio(data) diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 8e648eba6685..9a7b9f6eeb5c 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -177,24 +177,6 @@ def _asn1_string_to_utf8(backend, asn1_string) -> str: return backend._ffi.buffer(buf[0], res)[:].decode("utf8") -def _parse_asn1_time(backend, asn1_time): - backend.openssl_assert(asn1_time != backend._ffi.NULL) - generalized_time = backend._lib.ASN1_TIME_to_generalizedtime( - asn1_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 - ) - return _parse_asn1_generalized_time(backend, generalized_time) - - def _parse_asn1_generalized_time(backend, generalized_time): time = _asn1_string_to_ascii( backend, backend._ffi.cast("ASN1_STRING *", generalized_time) diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index b2dedcfd1338..52d08a0249b5 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -4,23 +4,18 @@ import datetime -import operator import typing import warnings from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm from cryptography.hazmat._oid import _SIG_OIDS_TO_HASH -from cryptography.hazmat.backends.openssl import dsa, ec, rsa from cryptography.hazmat.backends.openssl.decode_asn1 import ( - _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, _txt2obj_gc, ) from cryptography.hazmat.primitives import hashes, serialization @@ -39,224 +34,6 @@ def _Certificate(backend, x509) -> x509.Certificate: # noqa: N802 return backend._ossl2cert(x509) -class _RevokedCertificate(x509.RevokedCertificate): - def __init__(self, backend, crl, x509_revoked): - self._backend = backend - # The X509_REVOKED_value is a X509_REVOKED * that has - # no reference counting. This means when X509_CRL_free is - # called then the CRL and all X509_REVOKED * are freed. Since - # you can retain a reference to a single revoked certificate - # and let the CRL fall out of scope we need to retain a - # private reference to the CRL inside the RevokedCertificate - # object to prevent the gc from being called inappropriately. - self._crl = crl - self._x509_revoked = x509_revoked - - @property - def serial_number(self) -> int: - asn1_int = self._backend._lib.X509_REVOKED_get0_serialNumber( - self._x509_revoked - ) - self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL) - return _asn1_integer_to_int(self._backend, asn1_int) - - @property - def revocation_date(self) -> datetime.datetime: - return _parse_asn1_time( - self._backend, - self._backend._lib.X509_REVOKED_get0_revocationDate( - self._x509_revoked - ), - ) - - @utils.cached_property - def extensions(self) -> x509.Extensions: - return self._backend._revoked_cert_extension_parser.parse( - self._x509_revoked - ) - - -class _CertificateRevocationList(x509.CertificateRevocationList): - def __init__(self, backend, x509_crl): - self._backend = backend - self._x509_crl = x509_crl - - def __eq__(self, other: object) -> bool: - if not isinstance(other, _CertificateRevocationList): - return NotImplemented - - res = self._backend._lib.X509_CRL_cmp(self._x509_crl, other._x509_crl) - return res == 0 - - def __ne__(self, other: object) -> bool: - return not self == other - - def fingerprint(self, algorithm: hashes.HashAlgorithm) -> bytes: - h = hashes.Hash(algorithm, self._backend) - bio = self._backend._create_mem_bio_gc() - res = self._backend._lib.i2d_X509_CRL_bio(bio, self._x509_crl) - self._backend.openssl_assert(res == 1) - der = self._backend._read_mem_bio(bio) - 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: int - ) -> typing.Optional[x509.RevokedCertificate]: - 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, - ) -> typing.Optional[hashes.HashAlgorithm]: - oid = self.signature_algorithm_oid - try: - return _SIG_OIDS_TO_HASH[oid] - except KeyError: - raise UnsupportedAlgorithm( - "Signature algorithm OID:{} not recognized".format(oid) - ) - - @property - def signature_algorithm_oid(self) -> x509.ObjectIdentifier: - alg = self._backend._ffi.new("X509_ALGOR **") - self._backend._lib.X509_CRL_get0_signature( - self._x509_crl, self._backend._ffi.NULL, alg - ) - self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) - oid = _obj2txt(self._backend, alg[0].algorithm) - return x509.ObjectIdentifier(oid) - - @property - def issuer(self) -> x509.Name: - issuer = self._backend._lib.X509_CRL_get_issuer(self._x509_crl) - self._backend.openssl_assert(issuer != self._backend._ffi.NULL) - return _decode_x509_name(self._backend, issuer) - - @property - def next_update(self) -> typing.Optional[datetime.datetime]: - nu = self._backend._lib.X509_CRL_get0_nextUpdate(self._x509_crl) - if nu == self._backend._ffi.NULL: - return None - return _parse_asn1_time(self._backend, nu) - - @property - def last_update(self) -> datetime.datetime: - lu = self._backend._lib.X509_CRL_get0_lastUpdate(self._x509_crl) - self._backend.openssl_assert(lu != self._backend._ffi.NULL) - return _parse_asn1_time(self._backend, lu) - - @property - def signature(self) -> bytes: - sig = self._backend._ffi.new("ASN1_BIT_STRING **") - self._backend._lib.X509_CRL_get0_signature( - self._x509_crl, sig, self._backend._ffi.NULL - ) - self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL) - return _asn1_string_to_bytes(self._backend, sig[0]) - - @property - def tbs_certlist_bytes(self) -> bytes: - pp = self._backend._ffi.new("unsigned char **") - res = self._backend._lib.i2d_re_X509_CRL_tbs(self._x509_crl, pp) - self._backend.openssl_assert(res > 0) - pp = self._backend._ffi.gc( - pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0]) - ) - return self._backend._ffi.buffer(pp[0], res)[:] - - def public_bytes(self, encoding: serialization.Encoding) -> bytes: - bio = self._backend._create_mem_bio_gc() - if encoding is serialization.Encoding.PEM: - res = self._backend._lib.PEM_write_bio_X509_CRL( - bio, self._x509_crl - ) - elif encoding is serialization.Encoding.DER: - res = self._backend._lib.i2d_X509_CRL_bio(bio, self._x509_crl) - else: - raise TypeError("encoding must be an item from the Encoding enum") - - self._backend.openssl_assert(res == 1) - return self._backend._read_mem_bio(bio) - - def _revoked_cert(self, idx): - revoked = self._backend._lib.X509_CRL_get_REVOKED(self._x509_crl) - r = self._backend._lib.sk_X509_REVOKED_value(revoked, idx) - self._backend.openssl_assert(r != self._backend._ffi.NULL) - return _RevokedCertificate(self._backend, self, r) - - def __iter__(self): - for i in range(len(self)): - yield self._revoked_cert(i) - - def __getitem__(self, idx): - if isinstance(idx, slice): - start, stop, step = idx.indices(len(self)) - return [self._revoked_cert(i) for i in range(start, stop, step)] - else: - idx = operator.index(idx) - if idx < 0: - idx += len(self) - if not 0 <= idx < len(self): - raise IndexError - return self._revoked_cert(idx) - - def __len__(self) -> int: - revoked = self._backend._lib.X509_CRL_get_REVOKED(self._x509_crl) - if revoked == self._backend._ffi.NULL: - return 0 - else: - return self._backend._lib.sk_X509_REVOKED_num(revoked) - - @utils.cached_property - def extensions(self) -> x509.Extensions: - return self._backend._crl_extension_parser.parse(self._x509_crl) - - def is_signature_valid(self, public_key: PUBLIC_KEY_TYPES) -> bool: - if not isinstance( - public_key, - ( - dsa._DSAPublicKey, - rsa._RSAPublicKey, - ec._EllipticCurvePublicKey, - ), - ): - raise TypeError( - "Expecting one of DSAPublicKey, RSAPublicKey," - " or EllipticCurvePublicKey." - ) - res = self._backend._lib.X509_CRL_verify( - self._x509_crl, public_key._evp_pkey - ) - - if res != 1: - self._backend._consume_errors() - return False - - return True - - class _CertificateSigningRequest(x509.CertificateSigningRequest): def __init__(self, backend, x509_req): self._backend = backend @@ -410,3 +187,27 @@ def get_attribute_for_oid(self, oid: x509.ObjectIdentifier) -> bytes: # that it is always a type of ASN1_STRING data = self._backend._ffi.cast("ASN1_STRING *", data) return _asn1_string_to_bytes(self._backend, data) + + +class _RawRevokedCertificate(x509.RevokedCertificate): + def __init__( + self, + serial_number: int, + revocation_date: datetime.datetime, + extensions: x509.Extensions, + ): + self._serial_number = serial_number + self._revocation_date = revocation_date + self._extensions = extensions + + @property + def serial_number(self) -> int: + return self._serial_number + + @property + def revocation_date(self) -> datetime.datetime: + return self._revocation_date + + @property + def extensions(self) -> x509.Extensions: + return self._extensions diff --git a/src/cryptography/hazmat/bindings/_rust/x509.pyi b/src/cryptography/hazmat/bindings/_rust/x509.pyi index 9c334441fb96..08b4e6c2ec06 100644 --- a/src/cryptography/hazmat/bindings/_rust/x509.pyi +++ b/src/cryptography/hazmat/bindings/_rust/x509.pyi @@ -6,15 +6,15 @@ from cryptography import x509 def parse_csr_extension( der_oid: bytes, ext_data: bytes ) -> x509.ExtensionType: ... -def parse_crl_entry_ext(der_oid: bytes, data: bytes) -> x509.ExtensionType: ... -def parse_crl_extension( - der_oid: bytes, ext_data: bytes -) -> x509.ExtensionType: ... def load_pem_x509_certificate(data: bytes) -> x509.Certificate: ... def load_der_x509_certificate(data: bytes) -> x509.Certificate: ... +def load_pem_x509_crl(data: bytes) -> x509.CertificateRevocationList: ... +def load_der_x509_crl(data: bytes) -> x509.CertificateRevocationList: ... def encode_precertificate_signed_certificate_timestamps( extension: x509.PrecertificateSignedCertificateTimestamps, ) -> bytes: ... class Sct: ... class Certificate: ... +class RevokedCertificate: ... +class CertificateRevocationList: ... diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index 22f6509f6eb5..17ab61fe7376 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -214,6 +214,10 @@ def extensions(self) -> Extensions: """ +# Runtime isinstance checks need this since the rust class is not a subclass. +RevokedCertificate.register(rust_x509.RevokedCertificate) + + class CertificateRevocationList(metaclass=abc.ABCMeta): @abc.abstractmethod def public_bytes(self, encoding: serialization.Encoding) -> bytes: @@ -334,6 +338,9 @@ def is_signature_valid(self, public_key: PUBLIC_KEY_TYPES) -> bool: """ +CertificateRevocationList.register(rust_x509.CertificateRevocationList) + + class CertificateSigningRequest(metaclass=abc.ABCMeta): @abc.abstractmethod def __eq__(self, other: object) -> bool: @@ -449,15 +456,13 @@ def load_der_x509_csr( def load_pem_x509_crl( data: bytes, backend: typing.Optional[Backend] = None ) -> CertificateRevocationList: - backend = _get_backend(backend) - return backend.load_pem_x509_crl(data) + return rust_x509.load_pem_x509_crl(data) def load_der_x509_crl( data: bytes, backend: typing.Optional[Backend] = None ) -> CertificateRevocationList: - backend = _get_backend(backend) - return backend.load_der_x509_crl(data) + return rust_x509.load_der_x509_crl(data) class CertificateSigningRequestBuilder(object): diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index f9a1e05ad546..07590b3d2606 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -117,7 +117,7 @@ fn decode_dss_signature(py: pyo3::Python<'_>, data: &[u8]) -> Result( +pub(crate) fn py_uint_to_big_endian_bytes<'p>( py: pyo3::Python<'p>, v: &'p pyo3::types::PyLong, ) -> pyo3::PyResult<&'p [u8]> { diff --git a/src/rust/src/ocsp.rs b/src/rust/src/ocsp.rs index 97dda1144e3f..4b6e391a53f9 100644 --- a/src/rust/src/ocsp.rs +++ b/src/rust/src/ocsp.rs @@ -226,7 +226,9 @@ fn parse_ocsp_singleresp_ext(py: pyo3::Python<'_>, der_oid: &[u8], data: &[u8]) .call1((scts,))? .to_object(py)) } else { - x509::parse_crl_entry_ext(py, der_oid, data) + Ok(x509::parse_crl_entry_ext(py, oid, data)? + .map(|p| p.to_object(py)) + .unwrap_or_else(|| py.None())) } } diff --git a/src/rust/src/x509.rs b/src/rust/src/x509.rs index 1be065a89d18..22136da56097 100644 --- a/src/rust/src/x509.rs +++ b/src/rust/src/x509.rs @@ -2,7 +2,7 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::asn1::{big_asn1_uint_to_py, PyAsn1Error, PyAsn1Result}; +use crate::asn1::{big_asn1_uint_to_py, py_uint_to_big_endian_bytes, PyAsn1Error, PyAsn1Result}; use chrono::{Datelike, Timelike}; use pyo3::conversion::ToPyObject; use pyo3::types::IntoPyDict; @@ -10,6 +10,7 @@ use std::collections::hash_map::DefaultHasher; use std::collections::HashSet; use std::convert::TryInto; use std::hash::{Hash, Hasher}; +use std::sync::Arc; lazy_static::lazy_static! { static ref TLS_FEATURE_OID: asn1::ObjectIdentifier<'static> = asn1::ObjectIdentifier::from_string("1.3.6.1.5.5.7.1.24").unwrap(); @@ -73,13 +74,13 @@ struct TbsCertificate<'a> { pub(crate) type Name<'a> = asn1::SequenceOf<'a, asn1::SetOf<'a, AttributeTypeValue<'a>>>; -#[derive(asn1::Asn1Read, asn1::Asn1Write)] +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash)] pub(crate) struct AttributeTypeValue<'a> { pub(crate) type_id: asn1::ObjectIdentifier<'a>, pub(crate) value: asn1::Tlv<'a>, } -#[derive(asn1::Asn1Read, asn1::Asn1Write)] +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash, Clone)] enum Time { UtcTime(asn1::UtcTime), GeneralizedTime(asn1::GeneralizedTime), @@ -539,6 +540,509 @@ fn load_der_x509_certificate(py: pyo3::Python<'_>, data: &[u8]) -> PyAsn1Result< }) } +#[pyo3::prelude::pyfunction] +fn load_der_x509_crl( + _py: pyo3::Python<'_>, + data: &[u8], +) -> Result { + let raw = OwnedRawCertificateRevocationList::try_new( + data.to_vec(), + |data| asn1::parse_single(data), + |_| Ok(pyo3::once_cell::GILOnceCell::new()), + )?; + + Ok(CertificateRevocationList { + raw: Arc::new(raw), + cached_extensions: None, + }) +} + +#[pyo3::prelude::pyfunction] +fn load_pem_x509_crl( + py: pyo3::Python<'_>, + data: &[u8], +) -> Result { + let block = pem::parse(data)?; + if block.tag != "X509 CRL" { + return Err(PyAsn1Error::from(pyo3::exceptions::PyValueError::new_err( + "Valid PEM but no BEGIN X509 CRL/END X509 delimiters. Are you sure this is a CRL?", + ))); + } + // TODO: Produces an extra copy + load_der_x509_crl(py, &block.contents) +} + +#[ouroboros::self_referencing] +struct OwnedRawCertificateRevocationList { + data: Vec, + #[borrows(data)] + #[covariant] + value: RawCertificateRevocationList<'this>, + #[borrows(data)] + #[not_covariant] + revoked_certs: pyo3::once_cell::GILOnceCell>>, +} + +#[pyo3::prelude::pyclass] +struct CertificateRevocationList { + raw: Arc, + + cached_extensions: Option, +} + +impl CertificateRevocationList { + fn public_bytes_der(&self) -> Vec { + asn1::write_single(self.raw.borrow_value()) + } + + fn revoked_cert(&self, py: pyo3::Python<'_>, idx: usize) -> pyo3::PyResult { + let raw = try_map_arc_data_crl(&self.raw, |_crl, revoked_certs| { + let revoked_certs = revoked_certs.get(py).unwrap(); + Ok::<_, pyo3::PyErr>(revoked_certs.get(idx).cloned().unwrap()) + })?; + Ok(RevokedCertificate { + raw, + cached_extensions: None, + }) + } + + fn len(&self) -> usize { + self.raw + .borrow_value() + .tbs_cert_list + .revoked_certificates + .as_ref() + .map_or(0, |v| v.len()) + } +} + +#[pyo3::prelude::pyproto] +impl pyo3::class::basic::PyObjectProtocol for CertificateRevocationList { + fn __richcmp__( + &self, + other: pyo3::pycell::PyRef, + op: pyo3::class::basic::CompareOp, + ) -> pyo3::PyResult { + match op { + pyo3::class::basic::CompareOp::Eq => { + Ok(self.raw.borrow_value() == other.raw.borrow_value()) + } + pyo3::class::basic::CompareOp::Ne => { + Ok(self.raw.borrow_value() != other.raw.borrow_value()) + } + _ => Err(pyo3::exceptions::PyTypeError::new_err( + "CRLs cannot be ordered", + )), + } + } +} + +#[pyo3::prelude::pyproto] +impl pyo3::PyMappingProtocol for CertificateRevocationList { + fn __len__(&self) -> usize { + self.len() + } + + fn __getitem__(&self, idx: &pyo3::PyAny) -> pyo3::PyResult { + let gil = pyo3::Python::acquire_gil(); + let py = gil.python(); + + self.raw.with(|val| { + val.revoked_certs.get_or_init(py, || { + match &val.value.tbs_cert_list.revoked_certificates { + Some(c) => c.clone().collect(), + None => vec![], + } + }); + }); + + if idx.is_instance::()? { + let indices = idx + .downcast::()? + .indices(self.len().try_into().unwrap())?; + let result = pyo3::types::PyList::empty(py); + for i in (indices.start..indices.stop).step_by(indices.step.try_into().unwrap()) { + let revoked_cert = + pyo3::pycell::PyCell::new(py, self.revoked_cert(py, i as usize)?)?; + result.append(revoked_cert)?; + } + Ok(result.to_object(py)) + } else { + let mut idx = idx.extract::()?; + if idx < 0 { + idx += self.len() as isize; + } + if idx >= (self.len() as isize) || idx < 0 { + return Err(pyo3::exceptions::PyIndexError::new_err(())); + } + Ok(pyo3::pycell::PyCell::new(py, self.revoked_cert(py, idx as usize)?)?.to_object(py)) + } + } +} + +#[pyo3::prelude::pymethods] +impl CertificateRevocationList { + fn fingerprint<'p>( + &self, + py: pyo3::Python<'p>, + algorithm: pyo3::PyObject, + ) -> pyo3::PyResult<&'p pyo3::PyAny> { + let hashes_mod = py.import("cryptography.hazmat.primitives.hashes")?; + let h = hashes_mod.getattr("Hash")?.call1((algorithm,))?; + h.call_method1("update", (self.public_bytes_der().as_slice(),))?; + h.call_method0("finalize") + } + + #[getter] + fn signature_algorithm_oid<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { + let x509_module = py.import("cryptography.x509")?; + x509_module.call_method1( + "ObjectIdentifier", + (self.raw.borrow_value().signature_algorithm.oid.to_string(),), + ) + } + + #[getter] + fn signature_hash_algorithm<'p>( + &self, + py: pyo3::Python<'p>, + ) -> pyo3::PyResult<&'p pyo3::PyAny> { + let oid = self.signature_algorithm_oid(py)?; + let oid_module = py.import("cryptography.hazmat._oid")?; + let exceptions_module = py.import("cryptography.exceptions")?; + match oid_module.getattr("_SIG_OIDS_TO_HASH")?.get_item(oid) { + Ok(v) => Ok(v), + Err(_) => Err(pyo3::PyErr::from_instance(exceptions_module.call_method1( + "UnsupportedAlgorithm", + (format!( + "Signature algorithm OID:{} not recognized", + self.raw.borrow_value().signature_algorithm.oid + ),), + )?)), + } + } + + #[getter] + fn signature(&self) -> &[u8] { + self.raw.borrow_value().signature_value.as_bytes() + } + + #[getter] + fn tbs_certlist_bytes<'p>(&self, py: pyo3::Python<'p>) -> &'p pyo3::types::PyBytes { + let b = asn1::write_single(&self.raw.borrow_value().tbs_cert_list); + pyo3::types::PyBytes::new(py, &b) + } + + fn public_bytes<'p>( + &self, + py: pyo3::Python<'p>, + encoding: &pyo3::PyAny, + ) -> pyo3::PyResult<&'p pyo3::types::PyBytes> { + let encoding_class = py + .import("cryptography.hazmat.primitives.serialization")? + .getattr("Encoding")?; + + let result = asn1::write_single(self.raw.borrow_value()); + if encoding == encoding_class.getattr("DER")? { + Ok(pyo3::types::PyBytes::new(py, &result)) + } else if encoding == encoding_class.getattr("PEM")? { + let pem = pem::encode_config( + &pem::Pem { + tag: "X509 CRL".to_string(), + contents: result, + }, + pem::EncodeConfig { + line_ending: pem::LineEnding::LF, + }, + ) + .into_bytes(); + Ok(pyo3::types::PyBytes::new(py, &pem)) + } else { + Err(pyo3::exceptions::PyTypeError::new_err( + "encoding must be an item from the Encoding enum", + )) + } + } + + #[getter] + fn issuer<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { + parse_name(py, &self.raw.borrow_value().tbs_cert_list.issuer) + } + + #[getter] + fn next_update<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { + match &self.raw.borrow_value().tbs_cert_list.next_update { + Some(t) => chrono_to_py(py, t.as_chrono()), + None => Ok(py.None().into_ref(py)), + } + } + + #[getter] + fn last_update<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { + chrono_to_py( + py, + self.raw + .borrow_value() + .tbs_cert_list + .this_update + .as_chrono(), + ) + } + + #[getter] + fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult { + let x509_module = py.import("cryptography.x509")?; + parse_and_cache_extensions( + py, + &mut self.cached_extensions, + &self.raw.borrow_value().tbs_cert_list.crl_extensions, + |oid, ext_data| { + if oid == &*CRL_NUMBER_OID { + let bignum = asn1::parse_single::>(ext_data)?; + let pynum = big_asn1_uint_to_py(py, bignum)?; + Ok(Some(x509_module.getattr("CRLNumber")?.call1((pynum,))?)) + } else if oid == &*DELTA_CRL_INDICATOR_OID { + let bignum = asn1::parse_single::>(ext_data)?; + let pynum = big_asn1_uint_to_py(py, bignum)?; + Ok(Some( + x509_module.getattr("DeltaCRLIndicator")?.call1((pynum,))?, + )) + } else if oid == &*ISSUER_ALTERNATIVE_NAME_OID { + let gn_seq = + asn1::parse_single::>>(ext_data)?; + let ians = parse_general_names(py, gn_seq)?; + Ok(Some( + x509_module + .getattr("IssuerAlternativeName")? + .call1((ians,))?, + )) + } else if oid == &*AUTHORITY_INFORMATION_ACCESS_OID { + let ads = parse_access_descriptions(py, ext_data)?; + Ok(Some( + x509_module + .getattr("AuthorityInformationAccess")? + .call1((ads,))?, + )) + } else if oid == &*AUTHORITY_KEY_IDENTIFIER_OID { + Ok(Some(parse_authority_key_identifier(py, ext_data)?)) + } else if oid == &*ISSUING_DISTRIBUTION_POINT_OID { + let idp = asn1::parse_single::>(ext_data)?; + let (full_name, relative_name) = match idp.distribution_point { + Some(data) => parse_distribution_point_name(py, data)?, + None => (py.None(), py.None()), + }; + let reasons = parse_distribution_point_reasons(py, idp.only_some_reasons)?; + Ok(Some( + x509_module.getattr("IssuingDistributionPoint")?.call1(( + full_name, + relative_name, + idp.only_contains_user_certs, + idp.only_contains_ca_certs, + reasons, + idp.indirect_crl, + idp.only_contains_attribute_certs, + ))?, + )) + } else if oid == &*FRESHEST_CRL_OID { + Ok(Some( + x509_module + .getattr("FreshestCRL")? + .call1((parse_distribution_points(py, ext_data)?,))?, + )) + } else { + Ok(None) + } + }, + ) + } + + fn get_revoked_certificate_by_serial_number( + &mut self, + py: pyo3::Python<'_>, + serial: &pyo3::types::PyLong, + ) -> pyo3::PyResult> { + let serial_bytes = py_uint_to_big_endian_bytes(py, serial)?; + let owned = OwnedRawRevokedCertificate::try_new(Arc::clone(&self.raw), |v| { + let certs = match v.borrow_value().tbs_cert_list.revoked_certificates.clone() { + Some(certs) => certs, + None => return Err(()), + }; + + // TODO: linear scan. Make a hash or bisect! + for cert in certs { + if serial_bytes == cert.user_certificate.as_bytes() { + return Ok(cert); + } + } + Err(()) + }); + match owned { + Ok(o) => Ok(Some(RevokedCertificate { + raw: o, + cached_extensions: None, + })), + Err(()) => Ok(None), + } + } + + fn is_signature_valid<'p>( + slf: pyo3::pycell::PyRef<'_, Self>, + py: pyo3::Python<'p>, + public_key: &'p pyo3::PyAny, + ) -> pyo3::PyResult<&'p pyo3::PyAny> { + let backend = py + .import("cryptography.hazmat.backends.openssl.backend")? + .getattr("backend")?; + backend.call_method1("_crl_is_signature_valid", (slf, public_key)) + } +} + +#[pyo3::prelude::pyproto] +impl pyo3::PyIterProtocol<'_> for CertificateRevocationList { + fn __iter__(slf: pyo3::pycell::PyRef<'p, Self>) -> CRLIterator { + CRLIterator { + contents: OwnedCRLIteratorData::try_new(Arc::clone(&slf.raw), |v| { + Ok::<_, ()>(v.borrow_value().tbs_cert_list.revoked_certificates.clone()) + }) + .unwrap(), + } + } +} + +#[ouroboros::self_referencing] +struct OwnedCRLIteratorData { + data: Arc, + #[borrows(data)] + #[covariant] + value: Option>>, +} + +#[pyo3::prelude::pyclass] +struct CRLIterator { + contents: OwnedCRLIteratorData, +} + +// Open-coded implementation of the API discussed in +// https://github.com/joshua-maros/ouroboros/issues/38 +fn try_map_arc_data_crl( + crl: &Arc, + f: impl for<'this> FnOnce( + &'this OwnedRawCertificateRevocationList, + &pyo3::once_cell::GILOnceCell>>, + ) -> Result, E>, +) -> Result { + OwnedRawRevokedCertificate::try_new(Arc::clone(crl), |inner_crl| { + crl.with(|value| { + f(inner_crl, unsafe { + std::mem::transmute(value.revoked_certs) + }) + }) + }) +} +fn try_map_arc_data_mut_crl_iterator( + it: &mut OwnedCRLIteratorData, + f: impl for<'this> FnOnce( + &'this OwnedRawCertificateRevocationList, + &mut Option>>, + ) -> Result, E>, +) -> Result { + OwnedRawRevokedCertificate::try_new(Arc::clone(it.borrow_data()), |inner_it| { + it.with_value_mut(|value| f(inner_it, unsafe { std::mem::transmute(value) })) + }) +} + +#[pyo3::prelude::pyproto] +impl pyo3::PyIterProtocol<'_> for CRLIterator { + fn __iter__(slf: pyo3::pycell::PyRef<'p, Self>) -> pyo3::pycell::PyRef<'p, Self> { + slf + } + + fn __next__(mut slf: pyo3::pycell::PyRefMut<'p, Self>) -> Option { + let revoked = try_map_arc_data_mut_crl_iterator(&mut slf.contents, |_data, v| match v { + Some(v) => match v.next() { + Some(revoked) => Ok(revoked), + None => Err(()), + }, + None => Err(()), + }) + .ok()?; + Some(RevokedCertificate { + raw: revoked, + cached_extensions: None, + }) + } +} + +#[pyo3::prelude::pyproto] +impl pyo3::PySequenceProtocol<'_> for CRLIterator { + fn __len__(&self) -> usize { + self.contents.borrow_value().clone().map_or(0, |v| v.len()) + } +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash)] +struct RawCertificateRevocationList<'a> { + tbs_cert_list: TBSCertList<'a>, + signature_algorithm: AlgorithmIdentifier<'a>, + signature_value: asn1::BitString<'a>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash)] +struct TBSCertList<'a> { + version: Option, + signature: AlgorithmIdentifier<'a>, + issuer: Name<'a>, + this_update: Time, + next_update: Option