From 4157ead1e04778fcebc40c288f9d71721b6dd8cf Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 24 Mar 2023 13:01:01 +0800 Subject: [PATCH 001/316] reopen main for 41 dev (#8584) --- 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 7bf627776069..5afb57d52a33 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,13 @@ Changelog ========= +.. _v41-0-0: + +41.0.0 - `main`_ +~~~~~~~~~~~~~~~~ + +.. note:: This version is not yet released and is under active development. + .. _v40-0-0: 40.0.0 - 2023-03-24 diff --git a/src/cryptography/__about__.py b/src/cryptography/__about__.py index 20d197b6bbe7..489579eb635f 100644 --- a/src/cryptography/__about__.py +++ b/src/cryptography/__about__.py @@ -9,7 +9,7 @@ "__copyright__", ] -__version__ = "40.0.0" +__version__ = "41.0.0.dev1" __author__ = "The Python Cryptographic Authority and individual contributors" __copyright__ = f"Copyright 2013-2022 {__author__}" diff --git a/vectors/cryptography_vectors/__about__.py b/vectors/cryptography_vectors/__about__.py index e99963664735..24340ac421e4 100644 --- a/vectors/cryptography_vectors/__about__.py +++ b/vectors/cryptography_vectors/__about__.py @@ -6,4 +6,4 @@ "__version__", ] -__version__ = "40.0.0" +__version__ = "41.0.0.dev1" From fc7a8717cef0ea8be9dc17698cce84768324a50d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Mar 2023 08:25:59 +0000 Subject: [PATCH 002/316] Bump actions/checkout from 3.4.0 to 3.5.0 in /.github/actions/wycheproof (#8588) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.4.0 to 3.5.0. - [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/v3.4.0...v3.5.0) --- updated-dependencies: - dependency-name: actions/checkout 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/actions/wycheproof/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/wycheproof/action.yml b/.github/actions/wycheproof/action.yml index 5a1042c10c4e..a7f265e12f29 100644 --- a/.github/actions/wycheproof/action.yml +++ b/.github/actions/wycheproof/action.yml @@ -5,7 +5,7 @@ runs: using: "composite" steps: - - uses: actions/checkout@v3.4.0 + - uses: actions/checkout@v3.5.0 with: repository: "google/wycheproof" path: "wycheproof" From fd70d79bf61cf661dccb684198051a06eebd6d2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Mar 2023 08:38:53 +0000 Subject: [PATCH 003/316] Bump actions/checkout from 3.4.0 to 3.5.0 (#8590) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.4.0 to 3.5.0. - [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/v3.4.0...v3.5.0) --- updated-dependencies: - dependency-name: actions/checkout 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/benchmark.yml | 4 ++-- .github/workflows/boring-open-version-bump.yml | 2 +- .github/workflows/ci.yml | 18 +++++++++--------- .github/workflows/wheel-builder.yml | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 7f332cc11800..ced2eee2ab75 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -17,12 +17,12 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 15 steps: - - uses: actions/checkout@v3.4.0 + - uses: actions/checkout@v3.5.0 timeout-minutes: 3 with: persist-credentials: false path: "cryptography-pr" - - uses: actions/checkout@v3.4.0 + - uses: actions/checkout@v3.5.0 timeout-minutes: 3 with: repository: "pyca/cryptography" diff --git a/.github/workflows/boring-open-version-bump.yml b/.github/workflows/boring-open-version-bump.yml index 353015d9be32..66a9ad5b0c28 100644 --- a/.github/workflows/boring-open-version-bump.yml +++ b/.github/workflows/boring-open-version-bump.yml @@ -13,7 +13,7 @@ jobs: if: github.repository_owner == 'pyca' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.4.0 + - uses: actions/checkout@v3.5.0 - id: check-sha-boring run: | SHA=$(git ls-remote https://boringssl.googlesource.com/boringssl refs/heads/master | cut -f1) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f5323c56d7a3..504acdb56bd0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.TOXARGS }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" timeout-minutes: 15 steps: - - uses: actions/checkout@v3.4.0 + - uses: actions/checkout@v3.5.0 timeout-minutes: 3 with: persist-credentials: false @@ -158,7 +158,7 @@ jobs: sed -i "s:ID=alpine:ID=NotpineForGHA:" /etc/os-release if: matrix.IMAGE.IMAGE == 'alpine:aarch64' - - uses: actions/checkout@v3.4.0 + - uses: actions/checkout@v3.5.0 timeout-minutes: 3 with: persist-credentials: false @@ -221,7 +221,7 @@ jobs: name: "${{ matrix.PYTHON.TOXENV }} with Rust ${{ matrix.RUST }}" timeout-minutes: 15 steps: - - uses: actions/checkout@v3.4.0 + - uses: actions/checkout@v3.5.0 timeout-minutes: 3 with: persist-credentials: false @@ -269,7 +269,7 @@ jobs: name: "Rust Coverage" timeout-minutes: 15 steps: - - uses: actions/checkout@v3.4.0 + - uses: actions/checkout@v3.5.0 timeout-minutes: 3 with: persist-credentials: false @@ -382,7 +382,7 @@ jobs: name: "${{ matrix.PYTHON.TOXENV }} on macOS ${{ matrix.RUNNER.ARCH }}" timeout-minutes: 15 steps: - - uses: actions/checkout@v3.4.0 + - uses: actions/checkout@v3.5.0 timeout-minutes: 3 with: persist-credentials: false @@ -449,7 +449,7 @@ jobs: name: "${{ matrix.PYTHON.TOXENV }} on ${{ matrix.WINDOWS.WINDOWS }} (part ${{ matrix.JOB_NUMBER }})" timeout-minutes: 15 steps: - - uses: actions/checkout@v3.4.0 + - uses: actions/checkout@v3.5.0 timeout-minutes: 3 with: persist-credentials: false @@ -523,7 +523,7 @@ jobs: name: "Downstream tests for ${{ matrix.DOWNSTREAM }}" timeout-minutes: 15 steps: - - uses: actions/checkout@v3.4.0 + - uses: actions/checkout@v3.5.0 timeout-minutes: 3 with: persist-credentials: false @@ -566,7 +566,7 @@ jobs: name: "linkcheck" timeout-minutes: 10 steps: - - uses: actions/checkout@v3.4.0 + - uses: actions/checkout@v3.5.0 with: persist-credentials: false fetch-depth: 0 @@ -602,7 +602,7 @@ jobs: needs: [linux, distros, linux-rust, linux-rust-coverage, macos, windows, linux-downstream] if: ${{ always() }} steps: - - uses: actions/checkout@v3.4.0 + - uses: actions/checkout@v3.5.0 timeout-minutes: 3 with: persist-credentials: false diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index b81de2063f27..36df9f926a79 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest name: sdists steps: - - uses: actions/checkout@v3.4.0 + - uses: actions/checkout@v3.5.0 with: # The tag to build or the tag received by the tag event ref: ${{ github.event.inputs.version || github.ref }} From 4c24dd05eb99c0f6f02d243168d0a4916d5abbf3 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 24 Mar 2023 20:33:48 +0800 Subject: [PATCH 004/316] get the proper workflow id for publishing (#8586) does this fix #8585? maybe. --- .github/workflows/pypi-publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml index 8a90d24a93ba..f12b7244c32b 100644 --- a/.github/workflows/pypi-publish.yml +++ b/.github/workflows/pypi-publish.yml @@ -28,7 +28,7 @@ jobs: - uses: dawidd6/action-download-artifact@5e780fc7bbd0cac69fc73271ed86edf5dcb72d67 with: path: dist/ - run_id: ${{ github.event.inputs.run_id || github.event.workflow_run.event.id }} + run_id: ${{ github.event.inputs.run_id || github.event.workflow_run.id }} - run: pip install twine requests - run: | From 5e6476a4c6e094926a983dcf5cbe9488c30aeb53 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 24 Mar 2023 20:36:58 +0800 Subject: [PATCH 005/316] drop support for openssl < 1.1.1d (#8449) This removes the OS random engine, which contained the only CPython PSF licensed code in the repository. Accordingly, that license has now been removed. --- .github/workflows/ci.yml | 16 +- CHANGELOG.rst | 3 + LICENSE | 3 - LICENSE.PSF | 41 -- MANIFEST.in | 1 - docs/openssl.rst | 82 +-- setup.cfg | 2 +- src/_cffi_src/build_openssl.py | 1 - src/_cffi_src/openssl/cryptography.py | 23 +- src/_cffi_src/openssl/err.py | 2 +- src/_cffi_src/openssl/osrandom_engine.py | 23 - src/_cffi_src/openssl/src/osrandom_engine.c | 627 ------------------ src/_cffi_src/openssl/src/osrandom_engine.h | 116 ---- .../hazmat/backends/openssl/backend.py | 64 +- .../hazmat/backends/openssl/ciphers.py | 2 +- .../hazmat/bindings/openssl/_conditional.py | 1 - .../hazmat/bindings/openssl/binding.py | 31 - tests/hazmat/backends/test_openssl.py | 155 ----- tests/hazmat/bindings/test_openssl.py | 17 - tests/hazmat/primitives/test_aes.py | 4 +- 20 files changed, 20 insertions(+), 1194 deletions(-) delete mode 100644 LICENSE.PSF delete mode 100644 src/_cffi_src/openssl/osrandom_engine.py delete mode 100644 src/_cffi_src/openssl/src/osrandom_engine.c delete mode 100644 src/_cffi_src/openssl/src/osrandom_engine.h diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 504acdb56bd0..1824b269aa9b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -136,7 +136,6 @@ jobs: - {IMAGE: "bullseye", TOXENV: "py39", RUNNER: "ubuntu-latest"} - {IMAGE: "bookworm", TOXENV: "py311", RUNNER: "ubuntu-latest"} - {IMAGE: "sid", TOXENV: "py311", RUNNER: "ubuntu-latest"} - - {IMAGE: "ubuntu-bionic", TOXENV: "py36", RUNNER: "ubuntu-latest"} - {IMAGE: "ubuntu-focal", TOXENV: "py38", RUNNER: "ubuntu-latest"} - {IMAGE: "ubuntu-jammy", TOXENV: "py310", RUNNER: "ubuntu-latest"} - {IMAGE: "ubuntu-rolling", TOXENV: "py310", RUNNER: "ubuntu-latest"} @@ -182,7 +181,6 @@ jobs: run: mkdir -p "${HOME}/.cache/pip" - run: | echo "OPENSSL_FORCE_FIPS_MODE=1" >> $GITHUB_ENV - echo "CFLAGS=-DUSE_OSRANDOM_RNG_FOR_TESTING" >> $GITHUB_ENV if: matrix.IMAGE.FIPS - run: /venv/bin/python -m pip install -c ci-constraints-requirements.txt 'tox>3' coverage - run: '/venv/bin/tox -vvv --notest' @@ -373,11 +371,11 @@ jobs: - {OS: 'macos-12', ARCH: 'x86_64'} - {OS: [self-hosted, macos, ARM64, tart], ARCH: 'arm64'} PYTHON: - - {VERSION: "3.6", TOXENV: "py36-nocoverage", EXTRA_CFLAGS: ""} - - {VERSION: "3.11", TOXENV: "py311", EXTRA_CFLAGS: "-DUSE_OSRANDOM_RNG_FOR_TESTING"} + - {VERSION: "3.6", TOXENV: "py36-nocoverage"} + - {VERSION: "3.11", TOXENV: "py311"} exclude: # We only test latest Python on arm64. The py36 won't work since there's no universal2 binary - - PYTHON: {VERSION: "3.6", TOXENV: "py36-nocoverage", EXTRA_CFLAGS: ""} + - PYTHON: {VERSION: "3.6", TOXENV: "py36-nocoverage"} RUNNER: {OS: [self-hosted, macos, ARM64, tart], ARCH: 'arm64'} name: "${{ matrix.PYTHON.TOXENV }} on macOS ${{ matrix.RUNNER.ARCH }}" timeout-minutes: 15 @@ -420,11 +418,10 @@ jobs: run: | OPENSSL_DIR=$(readlink -f ../openssl-macos-universal2/) \ OPENSSL_STATIC=1 \ - CFLAGS="-Werror -Wno-error=deprecated-declarations -Wno-error=incompatible-pointer-types-discards-qualifiers -Wno-error=unused-function -mmacosx-version-min=10.12 $EXTRA_CFLAGS" \ + CFLAGS="-Werror -Wno-error=deprecated-declarations -Wno-error=incompatible-pointer-types-discards-qualifiers -Wno-error=unused-function -mmacosx-version-min=10.12" \ tox -vvv --notest env: TOXENV: ${{ matrix.PYTHON.TOXENV }} - EXTRA_CFLAGS: ${{ matrix.PYTHON.EXTRA_CFLAGS }} CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - name: Tests run: tox --skip-pkg-install -- --color=yes --wycheproof-root=wycheproof @@ -443,8 +440,8 @@ jobs: - {ARCH: 'x86', WINDOWS: 'win32'} - {ARCH: 'x64', WINDOWS: 'win64'} PYTHON: - - {VERSION: "3.6", TOXENV: "py36-nocoverage", CL_FLAGS: ""} - - {VERSION: "3.11", TOXENV: "py311", CL_FLAGS: "/D USE_OSRANDOM_RNG_FOR_TESTING"} + - {VERSION: "3.6", TOXENV: "py36-nocoverage"} + - {VERSION: "3.11", TOXENV: "py311"} JOB_NUMBER: [0, 1] name: "${{ matrix.PYTHON.TOXENV }} on ${{ matrix.WINDOWS.WINDOWS }} (part ${{ matrix.JOB_NUMBER }})" timeout-minutes: 15 @@ -481,7 +478,6 @@ jobs: - name: Configure run: | echo "OPENSSL_DIR=C:/openssl-${{ matrix.WINDOWS.WINDOWS }}" >> $GITHUB_ENV - echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV shell: bash - name: Clone wycheproof diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5afb57d52a33..40426a6745a0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,9 @@ Changelog .. note:: This version is not yet released and is under active development. +* **BACKWARDS INCOMPATIBLE:** Support for OpenSSL less than 1.1.1d has been + removed. Users on older version of OpenSSL will need to upgrade. + .. _v40-0-0: 40.0.0 - 2023-03-24 diff --git a/LICENSE b/LICENSE index 07074259b61a..b11f379efe15 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,3 @@ This software is made available under the terms of *either* of the licenses found in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made under the terms of *both* these licenses. - -The code used in the OS random engine is derived from CPython, and is licensed -under the terms of the PSF License Agreement. diff --git a/LICENSE.PSF b/LICENSE.PSF deleted file mode 100644 index 4d3a4f57dea9..000000000000 --- a/LICENSE.PSF +++ /dev/null @@ -1,41 +0,0 @@ -1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and - the Individual or Organization ("Licensee") accessing and otherwise using Python - 2.7.12 software in source or binary form and its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, PSF hereby - grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, - analyze, test, perform and/or display publicly, prepare derivative works, - distribute, and otherwise use Python 2.7.12 alone or in any derivative - version, provided, however, that PSF's License Agreement and PSF's notice of - copyright, i.e., "Copyright © 2001-2016 Python Software Foundation; All Rights - Reserved" are retained in Python 2.7.12 alone or in any derivative version - prepared by Licensee. - -3. In the event Licensee prepares a derivative work that is based on or - incorporates Python 2.7.12 or any part thereof, and wants to make the - derivative work available to others as provided herein, then Licensee hereby - agrees to include in any such work a brief summary of the changes made to Python - 2.7.12. - -4. PSF is making Python 2.7.12 available to Licensee on an "AS IS" basis. - PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF - EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR - WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE - USE OF PYTHON 2.7.12 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.7.12 - FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF - MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.7.12, OR ANY DERIVATIVE - THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material breach of - its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any relationship - of agency, partnership, or joint venture between PSF and Licensee. This License - Agreement does not grant permission to use PSF trademarks or trade name in a - trademark sense to endorse or promote products or services of Licensee, or any - third party. - -8. By copying, installing or otherwise using Python 2.7.12, Licensee agrees - to be bound by the terms and conditions of this License Agreement. diff --git a/MANIFEST.in b/MANIFEST.in index 995e3b0cedc2..c171033124b4 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,7 +3,6 @@ include CONTRIBUTING.rst include LICENSE include LICENSE.APACHE include LICENSE.BSD -include LICENSE.PSF include README.rst include tox.ini diff --git a/docs/openssl.rst b/docs/openssl.rst index edf185d2e10e..d4e69f4c86f6 100644 --- a/docs/openssl.rst +++ b/docs/openssl.rst @@ -10,8 +10,8 @@ A list of supported versions can be found in our :doc:`/installation` documentation. In general the backend should be considered an internal implementation detail -of the project, but there are some public methods available for more advanced -control. +of the project, but there are some public methods available for debugging +purposes. .. data:: cryptography.hazmat.backends.openssl.backend @@ -29,21 +29,6 @@ control. typically shown in hexadecimal (e.g. ``0x1010003f``). This is not necessarily the same version as it was compiled against. - .. method:: activate_osrandom_engine() - - Activates the OS random engine. This will effectively disable OpenSSL's - default CSPRNG. - - .. method:: osrandom_engine_implementation() - - .. versionadded:: 1.7 - - Returns the implementation of OS random engine. - - .. method:: activate_builtin_random() - - This will activate the default OpenSSL CSPRNG. - .. _legacy-provider: Legacy provider in OpenSSL 3.x @@ -56,68 +41,5 @@ disable the legacy provider in OpenSSL 3.x. This will disable legacy cryptographic algorithms, including ``Blowfish``, ``CAST5``, ``SEED``, ``ARC4``, and ``RC2`` (which is used by some encrypted serialization formats). -OS random engine ----------------- - -.. note:: - - As of OpenSSL 1.1.1d its CSPRNG is fork-safe by default. - ``cryptography`` does not compile or load the custom engine on - >= 1.1.1d. - -By default OpenSSL uses a user-space CSPRNG that is seeded from system random ( -``/dev/urandom`` or ``CryptGenRandom``). This CSPRNG is not reseeded -automatically when a process calls ``fork()``. This can result in situations -where two different processes can return similar or identical keys and -compromise the security of the system. - -The approach this project has chosen to mitigate this vulnerability is to -include an engine that replaces the OpenSSL default CSPRNG with one that -sources its entropy from ``/dev/urandom`` on UNIX-like operating systems and -uses ``CryptGenRandom`` on Windows. This method of pulling from the system pool -allows us to avoid potential issues with `initializing the RNG`_ as well as -protecting us from the ``fork()`` weakness. - -This engine is **active** by default when importing the OpenSSL backend. When -active this engine will be used to generate all the random data OpenSSL -requests. - -When importing only the binding it is added to the engine list but -**not activated**. - - -OS random sources ------------------ - -On macOS and FreeBSD ``/dev/urandom`` is an alias for ``/dev/random``. The -implementation on macOS uses the `Yarrow`_ algorithm. FreeBSD uses the -`Fortuna`_ algorithm. - -On Windows the implementation of ``CryptGenRandom`` depends on which version of -the operation system you are using. See the `Microsoft documentation`_ for more -details. - -Linux uses its own PRNG design. ``/dev/urandom`` is a non-blocking source -seeded from the same pool as ``/dev/random``. - -+------------------------------------------+------------------------------+ -| Windows | ``CryptGenRandom()`` | -+------------------------------------------+------------------------------+ -| Linux >= 3.17 with working | ``getrandom()`` | -| ``SYS_getrandom`` syscall | | -+------------------------------------------+------------------------------+ -| OpenBSD >= 5.6 | ``getentropy()`` | -+------------------------------------------+------------------------------+ -| BSD family (including macOS 10.12+) with | ``getentropy()`` | -| ``SYS_getentropy`` in ``sys/syscall.h`` | | -+------------------------------------------+------------------------------+ -| fallback | ``/dev/urandom`` with | -| | cached file descriptor | -+------------------------------------------+------------------------------+ - .. _`OpenSSL`: https://www.openssl.org/ -.. _`initializing the RNG`: https://en.wikipedia.org/wiki/OpenSSL#Predictable_private_keys_.28Debian-specific.29 -.. _`Fortuna`: https://en.wikipedia.org/wiki/Fortuna_(PRNG) -.. _`Yarrow`: https://en.wikipedia.org/wiki/Yarrow_algorithm -.. _`Microsoft documentation`: https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-cryptgenrandom diff --git a/setup.cfg b/setup.cfg index 172ac932ae31..416206fb271a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,7 +4,7 @@ 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 = (Apache-2.0 OR BSD-3-Clause) AND PSF-2.0 +license = Apache-2.0 OR BSD-3-Clause url = https://github.com/pyca/cryptography author = The Python Cryptographic Authority and individual contributors author_email = cryptography-dev@python.org diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py index 5f191ce2ed40..e971fd955882 100644 --- a/src/_cffi_src/build_openssl.py +++ b/src/_cffi_src/build_openssl.py @@ -100,7 +100,6 @@ def _extra_compile_args(platform): "nid", "objects", "opensslv", - "osrandom_engine", "pem", "pkcs12", "rand", diff --git a/src/_cffi_src/openssl/cryptography.py b/src/_cffi_src/openssl/cryptography.py index 6a79091c81c4..40e6ce9846fd 100644 --- a/src/_cffi_src/openssl/cryptography.py +++ b/src/_cffi_src/openssl/cryptography.py @@ -52,40 +52,25 @@ #define CRYPTOGRAPHY_LIBRESSL_LESS_THAN_370 (0) #endif -#if OPENSSL_VERSION_NUMBER < 0x10101000 - #error "pyca/cryptography MUST be linked with Openssl 1.1.1 or later" +#if OPENSSL_VERSION_NUMBER < 0x10101040 + #error "pyca/cryptography MUST be linked with Openssl 1.1.1d or later" #endif -#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) -#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B \ - (OPENSSL_VERSION_NUMBER < 0x10101020 || CRYPTOGRAPHY_IS_LIBRESSL) -#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_111D \ - (OPENSSL_VERSION_NUMBER < 0x10101040 || CRYPTOGRAPHY_IS_LIBRESSL) #define CRYPTOGRAPHY_OPENSSL_LESS_THAN_111E \ (OPENSSL_VERSION_NUMBER < 0x10101050 || CRYPTOGRAPHY_IS_LIBRESSL) -#if (CRYPTOGRAPHY_OPENSSL_LESS_THAN_111D && !CRYPTOGRAPHY_IS_LIBRESSL && \ - !defined(OPENSSL_NO_ENGINE)) || defined(USE_OSRANDOM_RNG_FOR_TESTING) -#define CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE 1 -#else -#define CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE 0 -#endif -/* Ed25519 support is available from OpenSSL 1.1.1b and LibreSSL 3.7.0. */ +/* Ed25519 support is in all supported OpenSSLs as well as LibreSSL 3.7.0. */ #define CRYPTOGRAPHY_HAS_WORKING_ED25519 \ - (!CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B || \ + (!CRYPTOGRAPHY_IS_LIBRESSL || \ (CRYPTOGRAPHY_IS_LIBRESSL && !CRYPTOGRAPHY_LIBRESSL_LESS_THAN_370)) """ TYPES = """ -static const int CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER; static const int CRYPTOGRAPHY_OPENSSL_300_OR_GREATER; -static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B; static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_111E; -static const int CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE; static const int CRYPTOGRAPHY_HAS_WORKING_ED25519; static const int CRYPTOGRAPHY_LIBRESSL_LESS_THAN_370; diff --git a/src/_cffi_src/openssl/err.py b/src/_cffi_src/openssl/err.py index be8c0774c945..ebe6c3559837 100644 --- a/src/_cffi_src/openssl/err.py +++ b/src/_cffi_src/openssl/err.py @@ -49,7 +49,7 @@ #define ERR_LIB_PROV 0 #endif -#if !CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER || CRYPTOGRAPHY_IS_BORINGSSL +#ifndef EVP_R_XTS_DUPLICATED_KEYS static const int EVP_R_XTS_DUPLICATED_KEYS = 0; #endif diff --git a/src/_cffi_src/openssl/osrandom_engine.py b/src/_cffi_src/openssl/osrandom_engine.py deleted file mode 100644 index dbc304b399c7..000000000000 --- a/src/_cffi_src/openssl/osrandom_engine.py +++ /dev/null @@ -1,23 +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 - -HERE = os.path.dirname(os.path.abspath(__file__)) - -with open(os.path.join(HERE, "src/osrandom_engine.h")) as f: - INCLUDES = f.read() - -TYPES = """ -static const char *const Cryptography_osrandom_engine_name; -static const char *const Cryptography_osrandom_engine_id; -""" - -FUNCTIONS = """ -int Cryptography_add_osrandom_engine(void); -""" - -with open(os.path.join(HERE, "src/osrandom_engine.c")) as f: - CUSTOMIZATIONS = f.read() diff --git a/src/_cffi_src/openssl/src/osrandom_engine.c b/src/_cffi_src/openssl/src/osrandom_engine.c deleted file mode 100644 index 257fcd50968f..000000000000 --- a/src/_cffi_src/openssl/src/osrandom_engine.c +++ /dev/null @@ -1,627 +0,0 @@ -/* osurandom engine - * - * Windows CryptGenRandom() - * macOS >= 10.12 getentropy() - * OpenBSD 5.6+ getentropy() - * other BSD getentropy() if SYS_getentropy is defined - * Linux 3.17+ getrandom() with fallback to /dev/urandom - * other /dev/urandom with cached fd - * - * The /dev/urandom, getrandom and getentropy code is derived from Python's - * Python/random.c, written by Antoine Pitrou and Victor Stinner. - * - * Copyright 2001-2016 Python Software Foundation; All Rights Reserved. - */ - -#ifdef __linux__ -#include -#endif - -#if CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE -/* OpenSSL has ENGINE support and is older than 1.1.1d (the first version that - * properly implements fork safety in its RNG) so build the engine. */ -static const char *Cryptography_osrandom_engine_id = "osrandom"; - -/**************************************************************************** - * Windows - */ -#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM -static const char *Cryptography_osrandom_engine_name = "osrandom_engine CryptGenRandom()"; -static HCRYPTPROV hCryptProv = 0; - -static int osrandom_init(ENGINE *e) { - if (hCryptProv != 0) { - return 1; - } - if (CryptAcquireContext(&hCryptProv, NULL, NULL, - PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { - return 1; - } else { - ERR_Cryptography_OSRandom_error( - CRYPTOGRAPHY_OSRANDOM_F_INIT, - CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT, - __FILE__, __LINE__ - ); - return 0; - } -} - -static int osrandom_rand_bytes(unsigned char *buffer, int size) { - if (hCryptProv == 0) { - return 0; - } - - if (!CryptGenRandom(hCryptProv, (DWORD)size, buffer)) { - ERR_Cryptography_OSRandom_error( - CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES, - CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM, - __FILE__, __LINE__ - ); - return 0; - } - return 1; -} - -static int osrandom_finish(ENGINE *e) { - if (CryptReleaseContext(hCryptProv, 0)) { - hCryptProv = 0; - return 1; - } else { - ERR_Cryptography_OSRandom_error( - CRYPTOGRAPHY_OSRANDOM_F_FINISH, - CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT, - __FILE__, __LINE__ - ); - return 0; - } -} - -static int osrandom_rand_status(void) { - return hCryptProv != 0; -} - -static const char *osurandom_get_implementation(void) { - return "CryptGenRandom"; -} - -#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM */ - -/**************************************************************************** - * /dev/urandom helpers for all non-BSD Unix platforms - */ -#ifdef CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM - -static struct { - int fd; - dev_t st_dev; - ino_t st_ino; -} urandom_cache = { -1 }; - -static int open_cloexec(const char *path) { - int open_flags = O_RDONLY; -#ifdef O_CLOEXEC - open_flags |= O_CLOEXEC; -#endif - - int fd = open(path, open_flags); - if (fd == -1) { - return -1; - } - -#ifndef O_CLOEXEC - int flags = fcntl(fd, F_GETFD); - if (flags == -1) { - return -1; - } - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { - return -1; - } -#endif - return fd; -} - -#ifdef __linux__ -/* On Linux, we open("/dev/random") and use poll() to wait until it's readable - * before we read from /dev/urandom, this ensures that we don't read from - * /dev/urandom before the kernel CSPRNG is initialized. This isn't necessary on - * other platforms because they don't have the same _bug_ as Linux does with - * /dev/urandom and early boot. */ -static int wait_on_devrandom(void) { - struct pollfd pfd = {}; - int ret = 0; - int random_fd = open_cloexec("/dev/random"); - if (random_fd < 0) { - return -1; - } - pfd.fd = random_fd; - pfd.events = POLLIN; - pfd.revents = 0; - do { - ret = poll(&pfd, 1, -1); - } while (ret < 0 && (errno == EINTR || errno == EAGAIN)); - close(random_fd); - return ret; -} -#endif - -/* return -1 on error */ -static int dev_urandom_fd(void) { - int fd = -1; - struct stat st; - - /* Check that fd still points to the correct device */ - if (urandom_cache.fd >= 0) { - if (fstat(urandom_cache.fd, &st) - || st.st_dev != urandom_cache.st_dev - || st.st_ino != urandom_cache.st_ino) { - /* Somebody replaced our FD. Invalidate our cache but don't - * close the fd. */ - urandom_cache.fd = -1; - } - } - if (urandom_cache.fd < 0) { -#ifdef __linux__ - if (wait_on_devrandom() < 0) { - goto error; - } -#endif - - fd = open_cloexec("/dev/urandom"); - if (fd < 0) { - goto error; - } - if (fstat(fd, &st)) { - goto error; - } - /* Another thread initialized the fd */ - if (urandom_cache.fd >= 0) { - close(fd); - return urandom_cache.fd; - } - urandom_cache.st_dev = st.st_dev; - urandom_cache.st_ino = st.st_ino; - urandom_cache.fd = fd; - } - return urandom_cache.fd; - - error: - if (fd != -1) { - close(fd); - } - ERR_Cryptography_OSRandom_error( - CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD, - CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED, - __FILE__, __LINE__ - ); - return -1; -} - -static int dev_urandom_read(unsigned char *buffer, int size) { - int fd; - int n; - - fd = dev_urandom_fd(); - if (fd < 0) { - return 0; - } - - while (size > 0) { - do { - n = (int)read(fd, buffer, (size_t)size); - } while (n < 0 && errno == EINTR); - - if (n <= 0) { - ERR_Cryptography_OSRandom_error( - CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ, - CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED, - __FILE__, __LINE__ - ); - return 0; - } - buffer += n; - size -= n; - } - return 1; -} - -static void dev_urandom_close(void) { - if (urandom_cache.fd >= 0) { - int fd; - struct stat st; - - if (fstat(urandom_cache.fd, &st) - && st.st_dev == urandom_cache.st_dev - && st.st_ino == urandom_cache.st_ino) { - fd = urandom_cache.fd; - urandom_cache.fd = -1; - close(fd); - } - } -} -#endif /* CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM */ - -/**************************************************************************** - * BSD getentropy - */ -#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY -static const char *Cryptography_osrandom_engine_name = "osrandom_engine getentropy()"; - -static int osrandom_init(ENGINE *e) { - return 1; -} - -static int osrandom_rand_bytes(unsigned char *buffer, int size) { - int len; - int res; - - while (size > 0) { - /* OpenBSD and macOS restrict maximum buffer size to 256. */ - len = size > 256 ? 256 : size; - res = getentropy(buffer, (size_t)len); - if (res < 0) { - ERR_Cryptography_OSRandom_error( - CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES, - CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED, - __FILE__, __LINE__ - ); - return 0; - } - buffer += len; - size -= len; - } - return 1; -} - -static int osrandom_finish(ENGINE *e) { - return 1; -} - -static int osrandom_rand_status(void) { - return 1; -} - -static const char *osurandom_get_implementation(void) { - return "getentropy"; -} -#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY */ - -/**************************************************************************** - * Linux getrandom engine with fallback to dev_urandom - */ - -#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM -static const char *Cryptography_osrandom_engine_name = "osrandom_engine getrandom()"; - -static int getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT; - -static int osrandom_init(ENGINE *e) { - /* We try to detect working getrandom until we succeed. */ - if (getrandom_works != CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS) { - long n; - char dest[1]; - /* if the kernel CSPRNG is not initialized this will block */ - n = syscall(SYS_getrandom, dest, sizeof(dest), 0); - if (n == sizeof(dest)) { - getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS; - } else { - int e = errno; - switch(e) { - case ENOSYS: - /* Fallback: Kernel does not support the syscall. */ - getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK; - break; - case EPERM: - /* Fallback: seccomp prevents syscall */ - getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK; - break; - default: - /* EINTR cannot occur for buflen < 256. */ - ERR_Cryptography_OSRandom_error( - CRYPTOGRAPHY_OSRANDOM_F_INIT, - CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED, - "errno", e - ); - getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED; - break; - } - } - } - - /* fallback to dev urandom */ - if (getrandom_works == CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK) { - int fd = dev_urandom_fd(); - if (fd < 0) { - return 0; - } - } - return 1; -} - -static int osrandom_rand_bytes(unsigned char *buffer, int size) { - long n; - - switch(getrandom_works) { - case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED: - ERR_Cryptography_OSRandom_error( - CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES, - CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED, - __FILE__, __LINE__ - ); - return 0; - case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT: - ERR_Cryptography_OSRandom_error( - CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES, - CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT, - __FILE__, __LINE__ - ); - return 0; - case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK: - return dev_urandom_read(buffer, size); - case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS: - while (size > 0) { - do { - n = syscall(SYS_getrandom, buffer, size, 0); - } while (n < 0 && errno == EINTR); - - if (n <= 0) { - ERR_Cryptography_OSRandom_error( - CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES, - CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED, - __FILE__, __LINE__ - ); - return 0; - } - buffer += n; - size -= (int)n; - } - return 1; - } - __builtin_unreachable(); -} - -static int osrandom_finish(ENGINE *e) { - dev_urandom_close(); - return 1; -} - -static int osrandom_rand_status(void) { - switch(getrandom_works) { - case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED: - return 0; - case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT: - return 0; - case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK: - return urandom_cache.fd >= 0; - case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS: - return 1; - } - __builtin_unreachable(); -} - -static const char *osurandom_get_implementation(void) { - switch(getrandom_works) { - case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED: - return ""; - case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT: - return ""; - case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK: - return "/dev/urandom"; - case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS: - return "getrandom"; - } - __builtin_unreachable(); -} -#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM */ - -/**************************************************************************** - * dev_urandom engine for all remaining platforms - */ - -#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM -static const char *Cryptography_osrandom_engine_name = "osrandom_engine /dev/urandom"; - -static int osrandom_init(ENGINE *e) { - int fd = dev_urandom_fd(); - if (fd < 0) { - return 0; - } - return 1; -} - -static int osrandom_rand_bytes(unsigned char *buffer, int size) { - return dev_urandom_read(buffer, size); -} - -static int osrandom_finish(ENGINE *e) { - dev_urandom_close(); - return 1; -} - -static int osrandom_rand_status(void) { - return urandom_cache.fd >= 0; -} - -static const char *osurandom_get_implementation(void) { - return "/dev/urandom"; -} -#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM */ - -/**************************************************************************** - * ENGINE boiler plate - */ - -/* This replicates the behavior of the OpenSSL FIPS RNG, which returns a - -1 in the event that there is an error when calling RAND_pseudo_bytes. */ -static int osrandom_pseudo_rand_bytes(unsigned char *buffer, int size) { - int res = osrandom_rand_bytes(buffer, size); - if (res == 0) { - return -1; - } else { - return res; - } -} - -static RAND_METHOD osrandom_rand = { - NULL, - osrandom_rand_bytes, - NULL, - NULL, - osrandom_pseudo_rand_bytes, - osrandom_rand_status, -}; - -static const ENGINE_CMD_DEFN osrandom_cmd_defns[] = { - {CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION, - "get_implementation", - "Get CPRNG implementation.", - ENGINE_CMD_FLAG_NO_INPUT}, - {0, NULL, NULL, 0} -}; - -static int osrandom_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) { - const char *name; - size_t len; - - switch (cmd) { - case CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION: - /* i: buffer size, p: char* buffer */ - name = osurandom_get_implementation(); - len = strlen(name); - if ((p == NULL) && (i == 0)) { - /* return required buffer len */ - return (int)len; - } - if ((p == NULL) || i < 0 || ((size_t)i <= len)) { - /* no buffer or buffer too small */ - ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_INVALID_ARGUMENT); - return 0; - } - strcpy((char *)p, name); - return (int)len; - default: - ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED); - return 0; - } -} - -/* error reporting */ -#define ERR_FUNC(func) ERR_PACK(0, func, 0) -#define ERR_REASON(reason) ERR_PACK(0, 0, reason) - -static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_lib_name[] = { - {0, "osrandom_engine"}, - {0, NULL} -}; - -static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_str_funcs[] = { - {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_INIT), - "osrandom_init"}, - {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES), - "osrandom_rand_bytes"}, - {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_FINISH), - "osrandom_finish"}, - {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD), - "dev_urandom_fd"}, - {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ), - "dev_urandom_read"}, - {0, NULL} -}; - -static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_str_reasons[] = { - {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT), - "CryptAcquireContext() failed."}, - {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM), - "CryptGenRandom() failed."}, - {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT), - "CryptReleaseContext() failed."}, - {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED), - "getentropy() failed"}, - {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED), - "open('/dev/urandom') failed."}, - {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED), - "Reading from /dev/urandom fd failed."}, - {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED), - "getrandom() initialization failed."}, - {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED), - "getrandom() initialization failed with unexpected errno."}, - {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED), - "getrandom() syscall failed."}, - {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT), - "getrandom() engine was not properly initialized."}, - {0, NULL} -}; - -static int Cryptography_OSRandom_lib_error_code = 0; - -static void ERR_load_Cryptography_OSRandom_strings(void) -{ - if (Cryptography_OSRandom_lib_error_code == 0) { - Cryptography_OSRandom_lib_error_code = ERR_get_next_error_library(); - ERR_load_strings(Cryptography_OSRandom_lib_error_code, - CRYPTOGRAPHY_OSRANDOM_lib_name); - ERR_load_strings(Cryptography_OSRandom_lib_error_code, - CRYPTOGRAPHY_OSRANDOM_str_funcs); - ERR_load_strings(Cryptography_OSRandom_lib_error_code, - CRYPTOGRAPHY_OSRANDOM_str_reasons); - } -} - -static void ERR_Cryptography_OSRandom_error(int function, int reason, - char *file, int line) -{ - ERR_PUT_error(Cryptography_OSRandom_lib_error_code, function, reason, - file, line); -} - -/* Returns 1 if successfully added, 2 if engine has previously been added, - and 0 for error. */ -int Cryptography_add_osrandom_engine(void) { - ENGINE *e; - - ERR_load_Cryptography_OSRandom_strings(); - - e = ENGINE_by_id(Cryptography_osrandom_engine_id); - if (e != NULL) { - ENGINE_free(e); - return 2; - } else { - ERR_clear_error(); - } - - e = ENGINE_new(); - if (e == NULL) { - return 0; - } - if (!ENGINE_set_id(e, Cryptography_osrandom_engine_id) || - !ENGINE_set_name(e, Cryptography_osrandom_engine_name) || - !ENGINE_set_RAND(e, &osrandom_rand) || - !ENGINE_set_init_function(e, osrandom_init) || - !ENGINE_set_finish_function(e, osrandom_finish) || - !ENGINE_set_cmd_defns(e, osrandom_cmd_defns) || - !ENGINE_set_ctrl_function(e, osrandom_ctrl)) { - ENGINE_free(e); - return 0; - } - if (!ENGINE_add(e)) { - ENGINE_free(e); - return 0; - } - if (!ENGINE_free(e)) { - return 0; - } - - return 1; -} - -#else -/* If OpenSSL has no ENGINE support then we don't want - * to compile the osrandom engine, but we do need some - * placeholders */ -static const char *Cryptography_osrandom_engine_id = "no-engine-support"; -static const char *Cryptography_osrandom_engine_name = "osrandom_engine disabled"; - -int Cryptography_add_osrandom_engine(void) { - return 0; -} - -#endif diff --git a/src/_cffi_src/openssl/src/osrandom_engine.h b/src/_cffi_src/openssl/src/osrandom_engine.h deleted file mode 100644 index 89e45265186f..000000000000 --- a/src/_cffi_src/openssl/src/osrandom_engine.h +++ /dev/null @@ -1,116 +0,0 @@ -#if CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE -/* OpenSSL has ENGINE support so include all of this. */ -#ifdef _WIN32 - #include -#else - #include - #include - /* for defined(BSD) */ - #ifndef __MVS__ - #include - #endif - - #ifdef BSD - /* for SYS_getentropy */ - #include - #endif - - #ifdef __APPLE__ - #include - /* To support weak linking we need to declare this as a weak import even if - * it's not present in sys/random (e.g. macOS < 10.12). */ - extern int getentropy(void *buffer, size_t size) __attribute((weak_import)); - #endif - - #ifdef __linux__ - /* for SYS_getrandom */ - #include - #ifndef GRND_NONBLOCK - #define GRND_NONBLOCK 0x0001 - #endif /* GRND_NONBLOCK */ - - #ifndef SYS_getrandom - /* We only bother to define the constants for platforms where we ship - * wheels, since that's the predominant way you get a situation where - * you don't have SYS_getrandom at compile time but do have the syscall - * at runtime */ - #if defined(__x86_64__) - #define SYS_getrandom 318 - #elif defined(__i386__) - #define SYS_getrandom 355 - #elif defined(__aarch64__) - #define SYS_getrandom 278 - #endif - #endif - #endif /* __linux__ */ -#endif /* _WIN32 */ - -#define CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM 1 -#define CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY 2 -#define CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM 3 -#define CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM 4 - -#ifndef CRYPTOGRAPHY_OSRANDOM_ENGINE - #if defined(_WIN32) - /* Windows */ - #define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM - #elif defined(BSD) && defined(SYS_getentropy) - /* OpenBSD 5.6+ & macOS with SYS_getentropy defined, although < 10.12 will fallback - * to urandom */ - #define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY - #elif defined(__linux__) && defined(SYS_getrandom) - /* Linux 3.17+ */ - #define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM - #else - /* Keep this as last entry, fall back to /dev/urandom */ - #define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM - #endif -#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE */ - -/* Fallbacks need /dev/urandom helper functions. */ -#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM || \ - CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM - #define CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM 1 -#endif - -enum { - CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED = -2, - CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT, - CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK, - CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS -}; - -enum { - CRYPTOGRAPHY_OSRANDOM_GETENTROPY_NOT_INIT, - CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK, - CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS -}; - -/* engine ctrl */ -#define CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION ENGINE_CMD_BASE - -/* error reporting */ -static void ERR_load_Cryptography_OSRandom_strings(void); -static void ERR_Cryptography_OSRandom_error(int function, int reason, - char *file, int line); - -#define CRYPTOGRAPHY_OSRANDOM_F_INIT 100 -#define CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES 101 -#define CRYPTOGRAPHY_OSRANDOM_F_FINISH 102 -#define CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD 300 -#define CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ 301 - -#define CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT 100 -#define CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM 101 -#define CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT 102 - -#define CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED 200 - -#define CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED 300 -#define CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED 301 - -#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED 400 -#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED 402 -#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED 403 -#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT 404 -#endif diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 53e3486c0da2..facdb48a03a8 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -7,7 +7,6 @@ import contextlib import itertools import typing -import warnings from contextlib import contextmanager from cryptography import utils, x509 @@ -185,13 +184,6 @@ def __init__(self) -> None: typing.Callable, ] = {} self._register_default_ciphers() - if self._fips_enabled and self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: - warnings.warn( - "OpenSSL FIPS mode is enabled. Can't enable DRBG fork safety.", - UserWarning, - ) - else: - self.activate_osrandom_engine() self._dh_types = [self._lib.EVP_PKEY_DH] if self._lib.Cryptography_HAS_EVP_PKEY_DHX: self._dh_types.append(self._lib.EVP_PKEY_DHX) @@ -230,60 +222,6 @@ def _enable_fips(self) -> None: assert self._is_fips_enabled() self._fips_enabled = self._is_fips_enabled() - def activate_builtin_random(self) -> None: - if self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: - # Obtain a new structural reference. - e = self._lib.ENGINE_get_default_RAND() - if e != self._ffi.NULL: - self._lib.ENGINE_unregister_RAND(e) - # Reset the RNG to use the built-in. - res = self._lib.RAND_set_rand_method(self._ffi.NULL) - self.openssl_assert(res == 1) - # decrement the structural reference from get_default_RAND - res = self._lib.ENGINE_finish(e) - self.openssl_assert(res == 1) - - @contextlib.contextmanager - def _get_osurandom_engine(self): - # Fetches an engine by id and returns it. This creates a structural - # reference. - e = self._lib.ENGINE_by_id(self._lib.Cryptography_osrandom_engine_id) - self.openssl_assert(e != self._ffi.NULL) - # Initialize the engine for use. This adds a functional reference. - res = self._lib.ENGINE_init(e) - self.openssl_assert(res == 1) - - try: - yield e - finally: - # Decrement the structural ref incremented by ENGINE_by_id. - res = self._lib.ENGINE_free(e) - self.openssl_assert(res == 1) - # Decrement the functional ref incremented by ENGINE_init. - res = self._lib.ENGINE_finish(e) - self.openssl_assert(res == 1) - - def activate_osrandom_engine(self) -> None: - if self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: - # Unregister and free the current engine. - self.activate_builtin_random() - with self._get_osurandom_engine() as e: - # Set the engine as the default RAND provider. - res = self._lib.ENGINE_set_default_RAND(e) - self.openssl_assert(res == 1) - # Reset the RNG to use the engine - res = self._lib.RAND_set_rand_method(self._ffi.NULL) - self.openssl_assert(res == 1) - - def osrandom_engine_implementation(self) -> str: - buf = self._ffi.new("char[]", 64) - with self._get_osurandom_engine() as e: - res = self._lib.ENGINE_ctrl_cmd( - e, b"get_implementation", len(buf), buf, self._ffi.NULL, 0 - ) - self.openssl_assert(res > 0) - return self._ffi.string(buf).decode("ascii") - def openssl_version_text(self) -> str: """ Friendly string name of the loaded OpenSSL library. This is not @@ -1968,7 +1906,7 @@ def ed448_supported(self) -> bool: if self._fips_enabled: return False return ( - not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B + not self._lib.CRYPTOGRAPHY_IS_LIBRESSL and not self._lib.CRYPTOGRAPHY_IS_BORINGSSL ) diff --git a/src/cryptography/hazmat/backends/openssl/ciphers.py b/src/cryptography/hazmat/backends/openssl/ciphers.py index 075d68fb9057..8d4b8dc3bbf1 100644 --- a/src/cryptography/hazmat/backends/openssl/ciphers.py +++ b/src/cryptography/hazmat/backends/openssl/ciphers.py @@ -119,7 +119,7 @@ def __init__( lib = self._backend._lib if res == 0 and ( ( - lib.CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER + not lib.CRYPTOGRAPHY_IS_LIBRESSL and errors[0]._lib_reason_match( lib.ERR_LIB_EVP, lib.EVP_R_XTS_DUPLICATED_KEYS ) diff --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py index c34fc3ae6960..35829a2821da 100644 --- a/src/cryptography/hazmat/bindings/openssl/_conditional.py +++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py @@ -162,7 +162,6 @@ def cryptography_has_engine() -> typing.List[str]: "ENGINE_ctrl_cmd", "ENGINE_free", "ENGINE_get_name", - "Cryptography_add_osrandom_engine", "ENGINE_ctrl_cmd_string", "ENGINE_load_builtin_engines", "ENGINE_load_private_key", diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py index 7327157fd8d5..99061e21b421 100644 --- a/src/cryptography/hazmat/bindings/openssl/binding.py +++ b/src/cryptography/hazmat/bindings/openssl/binding.py @@ -10,7 +10,6 @@ import warnings import cryptography -from cryptography import utils from cryptography.exceptions import InternalError from cryptography.hazmat.bindings._rust import _openssl, openssl from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES @@ -98,18 +97,6 @@ def _enable_fips(self) -> None: res = self.lib.EVP_default_properties_enable_fips(self.ffi.NULL, 1) _openssl_assert(self.lib, res == 1) - @classmethod - def _register_osrandom_engine(cls) -> None: - # Clear any errors extant in the queue before we start. In many - # scenarios other things may be interacting with OpenSSL in the same - # process space and it has proven untenable to assume that they will - # reliably clear the error queue. Once we clear it here we will - # error on any subsequent unexpected item in the stack. - cls.lib.ERR_clear_error() - if cls.lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: - result = cls.lib.Cryptography_add_osrandom_engine() - _openssl_assert(cls.lib, result in (1, 2)) - @classmethod def _ensure_ffi_initialized(cls) -> None: with cls._init_lock: @@ -118,7 +105,6 @@ def _ensure_ffi_initialized(cls) -> None: _openssl.lib, CONDITIONAL_NAMES ) cls._lib_loaded = True - 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 @@ -189,20 +175,3 @@ def _verify_package_version(version: str) -> None: UserWarning, stacklevel=2, ) - - -def _verify_openssl_version(lib): - if ( - not lib.CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER - and not lib.CRYPTOGRAPHY_IS_LIBRESSL - and not lib.CRYPTOGRAPHY_IS_BORINGSSL - ): - warnings.warn( - "Support for OpenSSL less than version 1.1.1d is deprecated and " - "the next release of cryptography will drop support. Please " - "upgrade your OpenSSL to version 1.1.1d or newer.", - utils.DeprecatedIn40, - ) - - -_verify_openssl_version(Binding.lib) diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 6f3f4a2bf508..572431ebbd4a 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -5,9 +5,6 @@ import itertools import os -import subprocess -import sys -import textwrap import pytest @@ -179,158 +176,6 @@ def test_bn_to_int(self): assert backend._bn_to_int(bn) == 0 -@pytest.mark.skipif( - not backend._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE, - reason="Requires OpenSSL with ENGINE support and OpenSSL < 1.1.1d", -) -@pytest.mark.skip_fips(reason="osrandom engine disabled for FIPS") -class TestOpenSSLRandomEngine: - def setup_method(self): - # The default RAND engine is global and shared between - # tests. We make sure that the default engine is osrandom - # before we start each test and restore the global state to - # that engine in teardown. - current_default = backend._lib.ENGINE_get_default_RAND() - name = backend._lib.ENGINE_get_name(current_default) - assert name == backend._lib.Cryptography_osrandom_engine_name - - def teardown_method(self): - # we need to reset state to being default. backend is a shared global - # for all these tests. - backend.activate_osrandom_engine() - current_default = backend._lib.ENGINE_get_default_RAND() - name = backend._lib.ENGINE_get_name(current_default) - assert name == backend._lib.Cryptography_osrandom_engine_name - - @pytest.mark.skipif( - sys.executable is None, reason="No Python interpreter available." - ) - def test_osrandom_engine_is_default(self, tmpdir): - engine_printer = textwrap.dedent( - """ - import sys - from cryptography.hazmat.backends.openssl.backend import backend - - e = backend._lib.ENGINE_get_default_RAND() - name = backend._lib.ENGINE_get_name(e) - sys.stdout.write(backend._ffi.string(name).decode('ascii')) - res = backend._lib.ENGINE_free(e) - assert res == 1 - """ - ) - engine_name = tmpdir.join("engine_name") - - # If we're running tests via ``python setup.py test`` in a clean - # environment then all of our dependencies are going to be installed - # into either the current directory or the .eggs directory. However the - # subprocess won't know to activate these dependencies, so we'll get it - # to do so by passing our entire sys.path into the subprocess via the - # PYTHONPATH environment variable. - env = os.environ.copy() - env["PYTHONPATH"] = os.pathsep.join(sys.path) - - with engine_name.open("w") as out: - subprocess.check_call( - [sys.executable, "-c", engine_printer], - env=env, - stdout=out, - stderr=subprocess.PIPE, - ) - - osrandom_engine_name = backend._ffi.string( - backend._lib.Cryptography_osrandom_engine_name - ) - - assert engine_name.read().encode("ascii") == osrandom_engine_name - - def test_osrandom_sanity_check(self): - # This test serves as a check against catastrophic failure. - buf = backend._ffi.new("unsigned char[]", 500) - res = backend._lib.RAND_bytes(buf, 500) - assert res == 1 - assert backend._ffi.buffer(buf)[:] != "\x00" * 500 - - def test_activate_osrandom_no_default(self): - backend.activate_builtin_random() - e = backend._lib.ENGINE_get_default_RAND() - assert e == backend._ffi.NULL - backend.activate_osrandom_engine() - e = backend._lib.ENGINE_get_default_RAND() - name = backend._lib.ENGINE_get_name(e) - assert name == backend._lib.Cryptography_osrandom_engine_name - res = backend._lib.ENGINE_free(e) - assert res == 1 - - def test_activate_builtin_random(self): - e = backend._lib.ENGINE_get_default_RAND() - assert e != backend._ffi.NULL - name = backend._lib.ENGINE_get_name(e) - assert name == backend._lib.Cryptography_osrandom_engine_name - res = backend._lib.ENGINE_free(e) - assert res == 1 - backend.activate_builtin_random() - e = backend._lib.ENGINE_get_default_RAND() - assert e == backend._ffi.NULL - - def test_activate_builtin_random_already_active(self): - backend.activate_builtin_random() - e = backend._lib.ENGINE_get_default_RAND() - assert e == backend._ffi.NULL - backend.activate_builtin_random() - e = backend._lib.ENGINE_get_default_RAND() - assert e == backend._ffi.NULL - - def test_osrandom_engine_implementation(self): - name = backend.osrandom_engine_implementation() - assert name in [ - "/dev/urandom", - "CryptGenRandom", - "getentropy", - "getrandom", - ] - if sys.platform.startswith("linux"): - assert name in ["getrandom", "/dev/urandom"] - if sys.platform == "darwin": - assert name in ["getentropy"] - if sys.platform == "win32": - assert name == "CryptGenRandom" - - def test_activate_osrandom_already_default(self): - e = backend._lib.ENGINE_get_default_RAND() - name = backend._lib.ENGINE_get_name(e) - assert name == backend._lib.Cryptography_osrandom_engine_name - res = backend._lib.ENGINE_free(e) - assert res == 1 - backend.activate_osrandom_engine() - e = backend._lib.ENGINE_get_default_RAND() - name = backend._lib.ENGINE_get_name(e) - assert name == backend._lib.Cryptography_osrandom_engine_name - res = backend._lib.ENGINE_free(e) - assert res == 1 - - -@pytest.mark.skipif( - backend._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE, - reason="Requires OpenSSL without ENGINE support or OpenSSL >=1.1.1d", -) -class TestOpenSSLNoEngine: - def test_no_engine_support(self): - assert ( - backend._ffi.string(backend._lib.Cryptography_osrandom_engine_id) - == b"no-engine-support" - ) - assert ( - backend._ffi.string(backend._lib.Cryptography_osrandom_engine_name) - == b"osrandom_engine disabled" - ) - - def test_activate_builtin_random_does_nothing(self): - backend.activate_builtin_random() - - def test_activate_osrandom_does_nothing(self): - backend.activate_osrandom_engine() - - class TestOpenSSLRSA: def test_generate_rsa_parameters_supported(self): assert backend.generate_rsa_parameters_supported(1, 1024) is False diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py index 118b850ee3ff..c061c9bf11b0 100644 --- a/tests/hazmat/bindings/test_openssl.py +++ b/tests/hazmat/bindings/test_openssl.py @@ -21,11 +21,6 @@ def test_binding_loads(self): assert binding.lib assert binding.ffi - def test_add_engine_more_than_once(self): - b = Binding() - b._register_osrandom_engine() - assert b.lib.ERR_get_error() == 0 - def test_ssl_ctx_options(self): # Test that we're properly handling 32-bit unsigned on all platforms. b = Binding() @@ -85,18 +80,6 @@ def test_openssl_assert_error_on_stack(self): if not b.lib.CRYPTOGRAPHY_IS_BORINGSSL: assert b"data not multiple of block length" in error.reason_text - def test_check_startup_errors_are_allowed(self): - b = Binding() - b.lib.ERR_put_error( - b.lib.ERR_LIB_EVP, - b.lib.EVP_F_EVP_ENCRYPTFINAL_EX, - b.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH, - b"", - -1, - ) - b._register_osrandom_engine() - assert rust_openssl.capture_error_stack() == [] - def test_version_mismatch(self): with pytest.raises(ImportError): _verify_package_version("nottherightversion") diff --git a/tests/hazmat/primitives/test_aes.py b/tests/hazmat/primitives/test_aes.py index 5322f8f4afea..1f3dfd0014b4 100644 --- a/tests/hazmat/primitives/test_aes.py +++ b/tests/hazmat/primitives/test_aes.py @@ -61,9 +61,7 @@ def test_xts_too_short(self, backend): enc.update(b"0" * 15) @pytest.mark.supported( - only_if=lambda backend: ( - backend._lib.CRYPTOGRAPHY_OPENSSL_111D_OR_GREATER - ), + only_if=lambda backend: (not backend._lib.CRYPTOGRAPHY_IS_LIBRESSL), skip_message="duplicate key encryption error added in OpenSSL 1.1.1d", ) def test_xts_no_duplicate_keys_encryption(self, backend): From b5170bf26dcc2834e2279e1e739d94916e5a5fc3 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 24 Mar 2023 21:15:13 +0800 Subject: [PATCH 006/316] drop python 3.6 support (#8448) * drop python 3.6 support * Update tests/hazmat/bindings/test_openssl.py Co-authored-by: Alex Gaynor --------- Co-authored-by: Alex Gaynor --- .github/workflows/ci.yml | 10 +++----- .github/workflows/wheel-builder.yml | 20 +++++++-------- CHANGELOG.rst | 1 + README.rst | 2 +- ci-constraints-requirements.txt | 38 ++++++++++++++--------------- docs/installation.rst | 6 ++--- pyproject.toml | 5 ++-- setup.cfg | 6 ++--- setup.py | 3 +-- src/cryptography/__init__.py | 13 ---------- src/rust/build.rs | 4 +-- tests/conftest.py | 6 ----- tox.ini | 4 +-- 13 files changed, 47 insertions(+), 71 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1824b269aa9b..8553a79d16a5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -128,8 +128,6 @@ jobs: fail-fast: false matrix: IMAGE: - - {IMAGE: "rhel8", TOXENV: "py36", RUNNER: "ubuntu-latest"} - - {IMAGE: "rhel8-fips", TOXENV: "py36", RUNNER: "ubuntu-latest", FIPS: true} - {IMAGE: "rhel8", TOXENV: "py38", RUNNER: "ubuntu-latest"} - {IMAGE: "rhel8-fips", TOXENV: "py38", RUNNER: "ubuntu-latest", FIPS: true} - {IMAGE: "buster", TOXENV: "py37", RUNNER: "ubuntu-latest"} @@ -371,11 +369,11 @@ jobs: - {OS: 'macos-12', ARCH: 'x86_64'} - {OS: [self-hosted, macos, ARM64, tart], ARCH: 'arm64'} PYTHON: - - {VERSION: "3.6", TOXENV: "py36-nocoverage"} + - {VERSION: "3.7", TOXENV: "py37-nocoverage"} - {VERSION: "3.11", TOXENV: "py311"} exclude: - # We only test latest Python on arm64. The py36 won't work since there's no universal2 binary - - PYTHON: {VERSION: "3.6", TOXENV: "py36-nocoverage"} + # We only test latest Python on arm64. py37 won't work since there's no universal2 binary + - PYTHON: {VERSION: "3.7", TOXENV: "py37-nocoverage"} RUNNER: {OS: [self-hosted, macos, ARM64, tart], ARCH: 'arm64'} name: "${{ matrix.PYTHON.TOXENV }} on macOS ${{ matrix.RUNNER.ARCH }}" timeout-minutes: 15 @@ -440,7 +438,7 @@ jobs: - {ARCH: 'x86', WINDOWS: 'win32'} - {ARCH: 'x64', WINDOWS: 'win64'} PYTHON: - - {VERSION: "3.6", TOXENV: "py36-nocoverage"} + - {VERSION: "3.7", TOXENV: "py37-nocoverage"} - {VERSION: "3.11", TOXENV: "py311"} JOB_NUMBER: [0, 1] name: "${{ matrix.PYTHON.TOXENV }} on ${{ matrix.WINDOWS.WINDOWS }} (part ${{ matrix.JOB_NUMBER }})" diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 36df9f926a79..1aec8c5cf439 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -58,7 +58,7 @@ jobs: fail-fast: false matrix: PYTHON: - - { VERSION: "cp36-cp36m", ABI_VERSION: 'cp36' } + - { VERSION: "cp37-cp37m", ABI_VERSION: 'cp37' } - { VERSION: "pp38-pypy38_pp73" } - { VERSION: "pp39-pypy39_pp73" } MANYLINUX: @@ -145,11 +145,11 @@ jobs: fail-fast: false matrix: PYTHON: - - VERSION: '3.10' - ABI_VERSION: 'cp36' + - VERSION: '3.11' + ABI_VERSION: 'cp37' # Despite the name, this is built for the macOS 11 SDK on arm64 and 10.9+ on intel - DOWNLOAD_URL: 'https://www.python.org/ftp/python/3.10.9/python-3.10.9-macos11.pkg' - BIN_PATH: '/Library/Frameworks/Python.framework/Versions/3.10/bin/python3' + DOWNLOAD_URL: 'https://www.python.org/ftp/python/3.11.2/python-3.11.2-macos11.pkg' + BIN_PATH: '/Library/Frameworks/Python.framework/Versions/3.11/bin/python3' DEPLOYMENT_TARGET: '10.12' # This archflags is default, but let's be explicit ARCHFLAGS: '-arch x86_64 -arch arm64' @@ -157,10 +157,10 @@ jobs: # This will change in the future as we change the base Python we # build against _PYTHON_HOST_PLATFORM: 'macosx-10.9-universal2' - - VERSION: '3.10' - ABI_VERSION: 'cp36' - DOWNLOAD_URL: 'https://www.python.org/ftp/python/3.10.9/python-3.10.9-macos11.pkg' - BIN_PATH: '/Library/Frameworks/Python.framework/Versions/3.10/bin/python3' + - VERSION: '3.11' + ABI_VERSION: 'cp37' + DOWNLOAD_URL: 'https://www.python.org/ftp/python/3.11.2/python-3.11.2-macos11.pkg' + BIN_PATH: '/Library/Frameworks/Python.framework/Versions/3.11/bin/python3' DEPLOYMENT_TARGET: '10.12' # We continue to build a non-universal2 for a bit to see metrics on # download counts (this is a proxy for pip version since universal2 @@ -249,7 +249,7 @@ jobs: - {ARCH: 'x86', WINDOWS: 'win32', RUST_TRIPLE: 'i686-pc-windows-msvc'} - {ARCH: 'x64', WINDOWS: 'win64', RUST_TRIPLE: 'x86_64-pc-windows-msvc'} PYTHON: - - {VERSION: "3.8", "ABI_VERSION": "cp36"} + - {VERSION: "3.11", "ABI_VERSION": "cp37"} - {VERSION: "pypy-3.8"} - {VERSION: "pypy-3.9"} exclude: diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 40426a6745a0..13ea2ef6e1c3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,6 +10,7 @@ Changelog * **BACKWARDS INCOMPATIBLE:** Support for OpenSSL less than 1.1.1d has been removed. Users on older version of OpenSSL will need to upgrade. +* **BACKWARDS INCOMPATIBLE:** Support for Python 3.6 has been removed. .. _v40-0-0: diff --git a/README.rst b/README.rst index e03cfcdff8a9..d71765b8dba3 100644 --- a/README.rst +++ b/README.rst @@ -15,7 +15,7 @@ pyca/cryptography ``cryptography`` is a package which provides cryptographic recipes and primitives to Python developers. Our goal is for it to be your "cryptographic -standard library". It supports Python 3.6+ and PyPy3 7.3.10+. +standard library". It supports Python 3.7+ and PyPy3 7.3.10+. ``cryptography`` includes both high level recipes and low level interfaces to common cryptographic algorithms such as symmetric ciphers, message digests, and diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 7494fbb6d14e..0ae7fa2f88ed 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -24,15 +24,15 @@ certifi==2022.12.7 # via requests chardet==5.1.0 # via tox -charset-normalizer==3.1.0; python_version >= "3.7" +charset-normalizer==3.1.0 # via requests check-manifest==0.49 # via cryptography (setup.cfg) click==8.1.3 # via black -colorama==0.4.6; python_version >= "3.7" +colorama==0.4.6 # via tox -coverage==7.2.2; python_version >= "3.7" +coverage==7.2.2 # via pytest-cov distlib==0.3.6 # via virtualenv @@ -46,7 +46,7 @@ exceptiongroup==1.1.1 # pytest execnet==1.9.0 # via pytest-xdist -filelock==3.10.3; python_version >= "3.7" +filelock==3.10.3 # via # tox # virtualenv @@ -54,11 +54,11 @@ idna==3.4 # via requests imagesize==1.4.1 # via sphinx -importlib-metadata==6.1.0; python_version >= "3.7" +importlib-metadata==6.1.0 # via # keyring # twine -iniconfig==2.0.0; python_version >= "3.7" +iniconfig==2.0.0 # via pytest iso8601==1.1.0 # via cryptography (setup.cfg) @@ -82,7 +82,7 @@ mypy-extensions==1.0.0 # via # black # mypy -packaging==23.0; python_version >= "3.7" +packaging==23.0 # via # black # build @@ -94,12 +94,12 @@ pathspec==0.11.1 # via black pkginfo==1.9.6 # via twine -platformdirs==3.1.1; python_version >= "3.7" +platformdirs==3.1.1 # via # black # tox # virtualenv -pluggy==1.0.0; python_version >= "3.7" +pluggy==1.0.0 # via # pytest # tox @@ -120,7 +120,7 @@ pyproject-api==1.5.1 # via tox pyproject-hooks==1.0.0 # via build -pytest==7.2.2; python_version >= "3.7" +pytest==7.2.2 # via # cryptography (setup.cfg) # pytest-benchmark @@ -129,7 +129,7 @@ pytest==7.2.2; python_version >= "3.7" # pytest-shard # pytest-subtests # pytest-xdist -pytest-benchmark==4.0.0; python_version >= "3.7" +pytest-benchmark==4.0.0 # via cryptography (setup.cfg) pytest-cov==4.0.0 # via cryptography (setup.cfg) @@ -137,16 +137,16 @@ pytest-randomly==3.12.0 # via cryptography (setup.cfg) pytest-shard==0.1.2 # via cryptography (setup.cfg) -pytest-subtests==0.10.0; python_version >= "3.7" +pytest-subtests==0.10.0 # via cryptography (setup.cfg) -pytest-xdist==3.2.1; python_version >= "3.7" +pytest-xdist==3.2.1 # via cryptography (setup.cfg) pytz==2022.7.1 # via # babel readme-renderer==37.3 # via twine -requests==2.28.2; python_version >= "3.7" +requests==2.28.2 # via # requests-toolbelt # sphinx @@ -186,7 +186,7 @@ sphinxcontrib-serializinghtml==1.1.5 # via sphinx sphinxcontrib-spelling==8.0.0 # via cryptography (setup.cfg) -tomli==2.0.1; python_version >= "3.7" +tomli==2.0.1 # via # black # build @@ -197,21 +197,21 @@ tomli==2.0.1; python_version >= "3.7" # pyproject-hooks # pytest # tox -tox==4.4.7; python_version >= "3.7" +tox==4.4.7 # via cryptography (setup.cfg) twine==4.0.2 # via cryptography (setup.cfg) -typing-extensions==4.5.0; python_version >= "3.7" +typing-extensions==4.5.0 # via mypy urllib3==1.26.15 # via # requests # twine -virtualenv==20.21.0; python_version >= "3.7" +virtualenv==20.21.0 # via tox webencodings==0.5.1 # via bleach -zipp==3.15.0; python_version >= "3.7" +zipp==3.15.0 # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: diff --git a/docs/installation.rst b/docs/installation.rst index e659668b26a4..83c8313b9b48 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -13,7 +13,7 @@ single most common cause of installation problems. Supported platforms ------------------- -Currently we test ``cryptography`` on Python 3.6+ and PyPy3 7.3.10+ on these +Currently we test ``cryptography`` on Python 3.7+ and PyPy3 7.3.10+ on these operating systems. * x86-64 RHEL 8.x @@ -21,7 +21,7 @@ operating systems. * x86-64 Fedora (latest) * x86-64 macOS 12 Monterey * ARM64 macOS 13 Ventura -* x86-64 Ubuntu 18.04, 20.04, 22.04, rolling +* x86-64 Ubuntu 20.04, 22.04, rolling * ARM64 Ubuntu 22.04 * x86-64 Debian Buster (10.x), Bullseye (11.x), Bookworm (12.x) and Sid (unstable) @@ -56,7 +56,7 @@ just run If you prefer to compile it yourself you'll need to have OpenSSL installed. You can compile OpenSSL yourself as well or use `a binary distribution`_. Be sure to download the proper version for your architecture and Python -(VC2015 is required for 3.6 and above). Wherever you place your copy of OpenSSL +(VC2015 is required for 3.7 and above). Wherever you place your copy of OpenSSL you'll need to set the ``OPENSSL_DIR`` environment variable to include the proper location. For example: diff --git a/pyproject.toml b/pyproject.toml index 6844bc096894..5ee817601047 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ build-backend = "setuptools.build_meta" [tool.black] line-length = 79 -target-version = ["py36"] +target-version = ["py37"] [tool.pytest.ini_options] addopts = "-r s --capture=no --strict-markers --benchmark-disable --no-subtests-shortletter" @@ -67,8 +67,7 @@ exclude_lines = [ [tool.ruff] # UP006: Minimum Python 3.9 # UP007, UP038: Minimum Python 3.10 -# UP022: Minimum Python 3.7 -ignore = ['N818', 'UP006', 'UP007', 'UP038', 'UP022'] +ignore = ['N818', 'UP006', 'UP007', 'UP038'] select = ['E', 'F', 'I', 'N', 'W', 'UP'] line-length = 79 diff --git a/setup.cfg b/setup.cfg index 416206fb271a..3cdae292d92e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -27,7 +27,6 @@ classifiers = 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 @@ -38,7 +37,7 @@ classifiers = Topic :: Security :: Cryptography [options] -python_requires = >=3.6 +python_requires = >=3.7 include_package_data = True zip_safe = False package_dir = @@ -62,8 +61,7 @@ test = pytest-shard>=0.1.2 pytest-benchmark pytest-cov - # pytest-subtests needs >=0.10.0 when we drop py36 support - pytest-subtests + pytest-subtests>=0.10.0 pytest-xdist pretend iso8601 diff --git a/setup.py b/setup.py index e1adff269ed6..2d084d1efbe7 100644 --- a/setup.py +++ b/setup.py @@ -101,8 +101,7 @@ # If for any reason `rustc --version` fails, silently ignore it rustc_output = subprocess.run( ["rustc", "--version"], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + capture_output=True, timeout=0.5, encoding="utf8", check=True, diff --git a/src/cryptography/__init__.py b/src/cryptography/__init__.py index 7f8a25c6ed9c..ffa979a4ea9d 100644 --- a/src/cryptography/__init__.py +++ b/src/cryptography/__init__.py @@ -2,23 +2,10 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. -import sys -import warnings - from cryptography.__about__ import __author__, __copyright__, __version__ -from cryptography.utils import CryptographyDeprecationWarning __all__ = [ "__version__", "__author__", "__copyright__", ] - -if sys.version_info[:2] == (3, 6): - warnings.warn( - "Python 3.6 is no longer supported by the Python core team. " - "Therefore, support for it is deprecated in cryptography. The next " - "release of cryptography will remove support for Python 3.6.", - CryptographyDeprecationWarning, - stacklevel=2, - ) diff --git a/src/rust/build.rs b/src/rust/build.rs index 01177ac0e96c..4f0f39aae6b1 100644 --- a/src/rust/build.rs +++ b/src/rust/build.rs @@ -63,8 +63,8 @@ fn main() { // Enable abi3 mode if we're not using PyPy. if python_impl != "PyPy" { - // cp36 - build.define("Py_LIMITED_API", "0x030600f0"); + // cp37 (Python 3.7 to help our grep when we some day drop 3.7 support) + build.define("Py_LIMITED_API", "0x030700f0"); } if cfg!(windows) { diff --git a/tests/conftest.py b/tests/conftest.py index 98f60959e413..51dca19850a3 100644 --- a/tests/conftest.py +++ b/tests/conftest.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 sys import pytest @@ -28,11 +27,6 @@ def pytest_report_header(config): def pytest_addoption(parser): parser.addoption("--wycheproof-root", default=None) parser.addoption("--enable-fips", default=False) - # REMOVE ME WHEN WE DROP PYTHON 3.6 SUPPORT - # This just adds a no-op flag so that we don't error on py36 where - # pytest-subtests is stuck on 0.8.0 - if sys.version_info[:2] == (3, 6): - parser.addoption("--no-subtests-shortletter", action="store_true") def pytest_runtest_setup(item): diff --git a/tox.ini b/tox.ini index 505bccba49b1..0a8806afce09 100644 --- a/tox.ini +++ b/tox.ini @@ -35,8 +35,8 @@ setenv = PIP_CONSTRAINT=ci-constraints-requirements.txt commands = pip list - !nocoverage: pytest -n auto --cov=cryptography --cov=tests --durations=10 {posargs} tests/ - nocoverage: pytest -n auto --durations=10 {posargs} tests/ + !nocoverage: pytest -n auto --dist=worksteal --cov=cryptography --cov=tests --durations=10 {posargs} tests/ + nocoverage: pytest -n auto --dist=worksteal --durations=10 {posargs} tests/ [testenv:docs] extras = From 0794b0e31aae4c550a009550f55f0976ae700083 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 24 Mar 2023 21:36:14 +0800 Subject: [PATCH 007/316] update MSRV 1.48.0 -> 1.56.0 (#8587) * update MSRV 1.48.0 -> 1.56.0 * bump some deps for MSRV --- .github/workflows/ci.yml | 12 +++--------- CHANGELOG.rst | 1 + docs/installation.rst | 4 ++-- setup.py | 2 +- src/rust/Cargo.lock | 8 ++++---- src/rust/Cargo.toml | 2 +- 6 files changed, 12 insertions(+), 17 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8553a79d16a5..9d9f7ed9f0ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -204,16 +204,8 @@ jobs: PYTHON: - {VERSION: "3.11", TOXENV: "py311"} RUST: - # Cover MSRV (and likely next MSRV). In-dev versions are below in - # the linux-rust-coverage section. Once our MSRV is 1.60 we can - # remove this section entirely. - - 1.48.0 - # 1.49.0 is the MSRV for parking_lot 0.12 - # 1.51 - const generics (for rust-asn1) - # 1.56 - new versions of once_cell and bumpalo + # Cover MSRV. 1.60+ and beta/nightly are in the linux-rust-coverage section. - 1.56.0 - # Potential future MSRVs - # 1.60 - new version of cxx name: "${{ matrix.PYTHON.TOXENV }} with Rust ${{ matrix.RUST }}" timeout-minutes: 15 steps: @@ -260,6 +252,8 @@ jobs: PYTHON: - {VERSION: "3.11", TOXENV: "py311"} RUST: + # 1.60 - new version of cxx + - 1.60.0 - beta - nightly name: "Rust Coverage" diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 13ea2ef6e1c3..02f12738c1d3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,7 @@ Changelog * **BACKWARDS INCOMPATIBLE:** Support for OpenSSL less than 1.1.1d has been removed. Users on older version of OpenSSL will need to upgrade. * **BACKWARDS INCOMPATIBLE:** Support for Python 3.6 has been removed. +* Updated the minimum supported Rust version (MSRV) to 1.56.0, from 1.48.0. .. _v40-0-0: diff --git a/docs/installation.rst b/docs/installation.rst index 83c8313b9b48..0023187f9b7d 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -137,7 +137,7 @@ Fedora/RHEL/CentOS .. 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.48.0 + below to install a sufficiently new Rust. If your Rust is less than 1.56.0 please see the :ref:`Rust installation instructions ` for information about installing a newer Rust. @@ -315,7 +315,7 @@ Rust a Rust toolchain. Building ``cryptography`` requires having a working Rust toolchain. The current -minimum supported Rust version is 1.48.0. **This is newer than the Rust some +minimum supported Rust version is 1.56.0. **This is newer than the Rust some package managers ship**, so users may need to install with the instructions below. diff --git a/setup.py b/setup.py index 2d084d1efbe7..662f483af3e3 100644 --- a/setup.py +++ b/setup.py @@ -57,7 +57,7 @@ if platform.python_implementation() == "PyPy" else ["pyo3/abi3-py36"] ), - rust_version=">=1.48.0", + rust_version=">=1.56.0", ) ], ) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index dd8c6b0c6fb2..72a8c60a81ad 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -64,9 +64,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bumpalo" -version = "3.10.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "cc" @@ -303,9 +303,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.14.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "openssl" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 2b1b94001683..dcd754a2876e 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -5,7 +5,7 @@ authors = ["The cryptography developers "] edition = "2018" publish = false # This specifies the MSRV -rust-version = "1.48.0" +rust-version = "1.56.0" [dependencies] once_cell = "1" From ffc10f9bb0f71102b743a7b8f2fa4a9a33e86d60 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 24 Mar 2023 21:41:35 +0800 Subject: [PATCH 008/316] remove a test dep (#8446) --- ci-constraints-requirements.txt | 2 -- setup.cfg | 1 - tests/test_fernet.py | 9 ++++----- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 0ae7fa2f88ed..1f72e311b1f7 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -60,8 +60,6 @@ importlib-metadata==6.1.0 # twine iniconfig==2.0.0 # via pytest -iso8601==1.1.0 - # via cryptography (setup.cfg) jaraco-classes==3.2.3 # via keyring jinja2==3.1.2 diff --git a/setup.cfg b/setup.cfg index 3cdae292d92e..610ce986d7c4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -64,7 +64,6 @@ test = pytest-subtests>=0.10.0 pytest-xdist pretend - iso8601 test-randomorder: pytest-randomly docs = diff --git a/tests/test_fernet.py b/tests/test_fernet.py index d4b1561a0af6..89908e2793b8 100644 --- a/tests/test_fernet.py +++ b/tests/test_fernet.py @@ -4,12 +4,11 @@ import base64 -import calendar +import datetime import json import os import time -import iso8601 import pretend import pytest @@ -46,7 +45,7 @@ def test_generate(self, secret, now, iv, src, token, backend): f = Fernet(secret.encode("ascii"), backend=backend) actual_token = f._encrypt_from_parts( src.encode("ascii"), - calendar.timegm(iso8601.parse_date(now).utctimetuple()), + int(datetime.datetime.fromisoformat(now).timestamp()), bytes(iv), ) assert actual_token == token.encode("ascii") @@ -60,7 +59,7 @@ def test_verify( ): # secret & token are both str f = Fernet(secret.encode("ascii"), backend=backend) - current_time = calendar.timegm(iso8601.parse_date(now).utctimetuple()) + current_time = int(datetime.datetime.fromisoformat(now).timestamp()) payload = f.decrypt_at_time( token, # str ttl=ttl_sec, @@ -86,7 +85,7 @@ def test_verify( @json_parametrize(("secret", "token", "now", "ttl_sec"), "invalid.json") def test_invalid(self, secret, token, now, ttl_sec, backend, monkeypatch): f = Fernet(secret.encode("ascii"), backend=backend) - current_time = calendar.timegm(iso8601.parse_date(now).utctimetuple()) + current_time = int(datetime.datetime.fromisoformat(now).timestamp()) with pytest.raises(InvalidToken): f.decrypt_at_time( token.encode("ascii"), From e030da4b541be839516129b132b5febde2ce7562 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 24 Mar 2023 16:50:08 -0400 Subject: [PATCH 009/316] fix copyright years (#8595) * fix copyright year in docs * update copyright year --- docs/conf.py | 2 +- src/cryptography/__about__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 4764cd70540a..0d8f866362a3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -72,7 +72,7 @@ # General information about the project. project = "Cryptography" -copyright = "2013-2022, Individual Contributors" +copyright = "2013-2023, Individual Contributors" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/src/cryptography/__about__.py b/src/cryptography/__about__.py index 489579eb635f..ef6399c179b5 100644 --- a/src/cryptography/__about__.py +++ b/src/cryptography/__about__.py @@ -12,4 +12,4 @@ __version__ = "41.0.0.dev1" __author__ = "The Python Cryptographic Authority and individual contributors" -__copyright__ = f"Copyright 2013-2022 {__author__}" +__copyright__ = f"Copyright 2013-2023 {__author__}" From 378068948d64d706c2ef57878d2c7ca682732199 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 24 Mar 2023 16:51:56 -0400 Subject: [PATCH 010/316] remove unused warning constant (#8594) --- src/cryptography/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index a84069f1c822..da4067a8e6ed 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -21,7 +21,6 @@ class CryptographyDeprecationWarning(UserWarning): # cycle ends. DeprecatedIn36 = CryptographyDeprecationWarning DeprecatedIn37 = CryptographyDeprecationWarning -DeprecatedIn39 = CryptographyDeprecationWarning DeprecatedIn40 = CryptographyDeprecationWarning From dcada6b3e4a5d8e4f41dae72377b65537ecd774a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 24 Mar 2023 16:52:28 -0400 Subject: [PATCH 011/316] remove unused binding (#8593) --- src/_cffi_src/openssl/rand.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/_cffi_src/openssl/rand.py b/src/_cffi_src/openssl/rand.py index 9e95fe792a7a..a2cce0ad201e 100644 --- a/src/_cffi_src/openssl/rand.py +++ b/src/_cffi_src/openssl/rand.py @@ -12,7 +12,6 @@ """ FUNCTIONS = """ -int RAND_set_rand_method(const RAND_METHOD *); void RAND_add(const void *, int, double); int RAND_status(void); int RAND_bytes(unsigned char *, int); From baea42771ad1a545f14b39bf6ab1aaf2af231216 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 24 Mar 2023 16:55:43 -0400 Subject: [PATCH 012/316] Use the DEFINED BY functionality from rust-asn1 in pkcs7.rs (#7848) --- src/rust/Cargo.toml | 2 +- src/rust/src/pkcs7.rs | 42 ++++++++++++++++++++---------------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index dcd754a2876e..2c3e1ae93f65 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -10,7 +10,7 @@ rust-version = "1.56.0" [dependencies] once_cell = "1" pyo3 = { version = "0.15.2" } -asn1 = { version = "0.13.0", default-features = false } +asn1 = { version = "0.13.0", default-features = false, features = ["const-generics"] } pem = "1.1" chrono = { version = "0.4.24", default-features = false, features = ["alloc", "clock"] } ouroboros = "0.15" diff --git a/src/rust/src/pkcs7.rs b/src/rust/src/pkcs7.rs index da2a6561b69a..c23300ac49a3 100644 --- a/src/rust/src/pkcs7.rs +++ b/src/rust/src/pkcs7.rs @@ -25,13 +25,6 @@ const AES_256_CBC_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3 const AES_192_CBC_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 1, 22); const AES_128_CBC_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 1, 2); -static EMPTY_STRING_DER: Lazy> = Lazy::new(|| { - // TODO: kind of verbose way to say "\x04\x00". - asn1::write_single(&(&[] as &[u8])).unwrap() -}); -static EMPTY_STRING_TLV: Lazy> = - Lazy::new(|| asn1::parse_single(&EMPTY_STRING_DER).unwrap()); - static OIDS_TO_MIC_NAME: Lazy> = Lazy::new(|| { let mut h = HashMap::new(); h.insert(&x509::oid::SHA224_OID, "sha-224"); @@ -43,9 +36,18 @@ static OIDS_TO_MIC_NAME: Lazy> = Lazy::ne #[derive(asn1::Asn1Write)] struct ContentInfo<'a> { - content_type: asn1::ObjectIdentifier, - #[explicit(0)] - content: Option>, + _content_type: asn1::DefinedByMarker, + + #[defined_by(_content_type)] + content: Content<'a>, +} + +#[derive(asn1::Asn1DefinedByWrite)] +enum Content<'a> { + #[defined_by(PKCS7_SIGNED_DATA_OID)] + SignedData(asn1::Explicit<'a, Box>, 0>), + #[defined_by(PKCS7_DATA_OID)] + Data(Option>), } #[derive(asn1::Asn1Write)] @@ -106,19 +108,17 @@ fn serialize_certificates<'p>( version: 1, digest_algorithms: asn1::SetOfWriter::new(&[]), content_info: ContentInfo { - content_type: PKCS7_DATA_OID, - content: Some(*EMPTY_STRING_TLV), + _content_type: asn1::DefinedByMarker::marker(), + content: Content::Data(Some(asn1::Explicit::new(b""))), }, certificates: Some(asn1::SetOfWriter::new(&raw_certs)), crls: None, signer_infos: asn1::SetOfWriter::new(&[]), }; - let signed_data_bytes = asn1::write_single(&signed_data)?; - let content_info = ContentInfo { - content_type: PKCS7_SIGNED_DATA_OID, - content: Some(asn1::parse_single(&signed_data_bytes).unwrap()), + _content_type: asn1::DefinedByMarker::marker(), + content: Content::SignedData(asn1::Explicit::new(Box::new(signed_data))), }; let content_info_bytes = asn1::write_single(&content_info)?; @@ -276,8 +276,8 @@ fn sign_and_serialize<'p>( version: 1, digest_algorithms: asn1::SetOfWriter::new(&digest_algs), content_info: ContentInfo { - content_type: PKCS7_DATA_OID, - content, + _content_type: asn1::DefinedByMarker::marker(), + content: Content::Data(content.map(asn1::Explicit::new)), }, certificates: if options.contains(pkcs7_options.getattr(crate::intern!(py, "NoCerts"))?)? { None @@ -288,11 +288,9 @@ fn sign_and_serialize<'p>( signer_infos: asn1::SetOfWriter::new(&signer_infos), }; - let signed_data_bytes = asn1::write_single(&signed_data)?; - let content_info = ContentInfo { - content_type: PKCS7_SIGNED_DATA_OID, - content: Some(asn1::parse_single(&signed_data_bytes).unwrap()), + _content_type: asn1::DefinedByMarker::marker(), + content: Content::SignedData(asn1::Explicit::new(Box::new(signed_data))), }; let ci_bytes = asn1::write_single(&content_info)?; From 7e19ff0229a0a8d9263e126a01b11299221a0741 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 24 Mar 2023 16:59:44 -0400 Subject: [PATCH 013/316] Migrate from setup.cfg to pyproject.toml completely (#8116) One less file? --- .github/workflows/wheel-builder.yml | 1 - ci-constraints-requirements.txt | 46 ++++++++------- pyproject.toml | 86 +++++++++++++++++++++++++++-- setup.cfg | 86 ----------------------------- setup.py | 2 +- 5 files changed, 105 insertions(+), 116 deletions(-) delete mode 100644 setup.cfg diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 1aec8c5cf439..e7b7ace10347 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -16,7 +16,6 @@ on: paths: - .github/workflows/wheel-builder.yml - setup.py - - setup.cfg - pyproject.toml - src/cryptography/__about__.py diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 1f72e311b1f7..d55b250ebfb3 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -1,7 +1,7 @@ # This is named ambigiously, but it's a pip constraints file, named like a # requirements file so dependabot will update the pins. # It was originally generated with; -# pip-compile --extra=docs --extra=docstest --extra=pep8test --extra=test --extra=test-randomorder --extra=tox --resolver=backtracking --strip-extras --unsafe-package=cffi --unsafe-package=pycparser --unsafe-package=setuptools setup.cfg +# pip-compile --extra=docs --extra=docstest --extra=pep8test --extra=test --extra=test-randomorder --extra=tox --resolver=backtracking --strip-extras --unsafe-package=cffi --unsafe-package=pycparser --unsafe-package=setuptools pyproject.toml # and then manually massaged to add version specifiers to packages whose # versions vary by Python version @@ -10,10 +10,11 @@ alabaster==0.7.13 attrs==22.2.0 # via # pytest + # pytest-subtests babel==2.12.1 # via sphinx black==23.1.0 - # via cryptography (setup.cfg) + # via cryptography (pyproject.toml) bleach==6.0.0 # via readme-renderer build==0.10.0 @@ -27,7 +28,7 @@ chardet==5.1.0 charset-normalizer==3.1.0 # via requests check-manifest==0.49 - # via cryptography (setup.cfg) + # via cryptography (pyproject.toml) click==8.1.3 # via black colorama==0.4.6 @@ -42,8 +43,7 @@ docutils==0.18.1 # sphinx # sphinx-rtd-theme exceptiongroup==1.1.1 - # via - # pytest + # via pytest execnet==1.9.0 # via pytest-xdist filelock==3.10.3 @@ -75,7 +75,7 @@ mdurl==0.1.2 more-itertools==9.1.0 # via jaraco-classes mypy==1.1.1 - # via cryptography (setup.cfg) + # via cryptography (pyproject.toml) mypy-extensions==1.0.0 # via # black @@ -102,12 +102,12 @@ pluggy==1.0.0 # pytest # tox pretend==1.0.9 - # via cryptography (setup.cfg) + # via cryptography (pyproject.toml) py-cpuinfo==9.0.0 # via pytest-benchmark pyenchant==3.2.2 # via - # cryptography (setup.cfg) + # cryptography (pyproject.toml) # sphinxcontrib-spelling pygments==2.14.0 # via @@ -120,7 +120,7 @@ pyproject-hooks==1.0.0 # via build pytest==7.2.2 # via - # cryptography (setup.cfg) + # cryptography (pyproject.toml) # pytest-benchmark # pytest-cov # pytest-randomly @@ -128,20 +128,17 @@ pytest==7.2.2 # pytest-subtests # pytest-xdist pytest-benchmark==4.0.0 - # via cryptography (setup.cfg) + # via cryptography (pyproject.toml) pytest-cov==4.0.0 - # via cryptography (setup.cfg) + # via cryptography (pyproject.toml) pytest-randomly==3.12.0 - # via cryptography (setup.cfg) + # via cryptography (pyproject.toml) pytest-shard==0.1.2 - # via cryptography (setup.cfg) + # via cryptography (pyproject.toml) pytest-subtests==0.10.0 - # via cryptography (setup.cfg) + # via cryptography (pyproject.toml) pytest-xdist==3.2.1 - # via cryptography (setup.cfg) -pytz==2022.7.1 - # via - # babel + # via cryptography (pyproject.toml) readme-renderer==37.3 # via twine requests==2.28.2 @@ -156,18 +153,19 @@ rfc3986==2.0.0 rich==13.3.2 # via twine ruff==0.0.259 - # via cryptography (setup.cfg) + # via cryptography (pyproject.toml) six==1.16.0 # via bleach snowballstemmer==2.2.0 # via sphinx sphinx==6.1.3 # via - # cryptography (setup.cfg) + # cryptography (pyproject.toml) # sphinx-rtd-theme + # sphinxcontrib-jquery # sphinxcontrib-spelling sphinx-rtd-theme==1.2.0 - # via cryptography (setup.cfg) + # via cryptography (pyproject.toml) sphinxcontrib-applehelp==1.0.4 # via sphinx sphinxcontrib-devhelp==1.0.2 @@ -183,7 +181,7 @@ sphinxcontrib-qthelp==1.0.3 sphinxcontrib-serializinghtml==1.1.5 # via sphinx sphinxcontrib-spelling==8.0.0 - # via cryptography (setup.cfg) + # via cryptography (pyproject.toml) tomli==2.0.1 # via # black @@ -196,9 +194,9 @@ tomli==2.0.1 # pytest # tox tox==4.4.7 - # via cryptography (setup.cfg) + # via cryptography (pyproject.toml) twine==4.0.2 - # via cryptography (setup.cfg) + # via cryptography (pyproject.toml) typing-extensions==4.5.0 # via mypy urllib3==1.26.15 diff --git a/pyproject.toml b/pyproject.toml index 5ee817601047..2a94aa26405b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,93 @@ [build-system] requires = [ - # The minimum setuptools version is specific to the PEP 517 backend, - # and may be stricter than the version required in `setup.cfg` - "setuptools>=40.6.0,!=60.9.0", + # First version of setuptools to support pyproject.toml configuration + "setuptools>=61.0.0", "wheel", - # Must be kept in sync with the `install_requirements` in `setup.cfg` + # Must be kept in sync with `project.dependencies` "cffi>=1.12; platform_python_implementation != 'PyPy'", "setuptools-rust>=0.11.4", ] build-backend = "setuptools.build_meta" +[project] +name = "cryptography" +authors = [ + {name = "The Python Cryptographic Authority and individual contributors", email = "cryptography-dev@python.org"} +] +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +license = {text = "Apache-2.0 OR BSD-3-Clause"} +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.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Security :: Cryptography", +] +requires-python = ">=3.7" +dependencies = [ + # Must be kept in sync with `build-system.requires` + "cffi >=1.12", +] +dynamic = ["version", "readme"] + +[project.urls] +homepage = "https://github.com/pyca/cryptography" +documentation = "https://cryptography.io/" +source = "https://github.com/pyca/cryptography/" +issues = "https://github.com/pyca/cryptography/issues" +changelog = "https://cryptography.io/en/latest/changelog/" + +[tool.setuptools] +zip-safe = false +package-dir = {"" = "src"} + +[tool.setuptools.packages.find] +where = ["src"] +exclude = [ + "_cffi_src", + "_cffi_src.*", +] + +[tool.setuptools.dynamic] +version = {attr = "cryptography.__version__"} +readme = {file = "README.rst", content-type = "text/x-rst"} + +[project.optional-dependencies] +ssh = ["bcrypt >=3.1.5"] + +# All the following are used for our own testing. +tox = ["tox"] +test = [ + "pytest >=6.2.0", + "pytest-shard >=0.1.2", + "pytest-benchmark", + "pytest-cov", + "pytest-subtests >=0.10.0", + "pytest-xdist", + "pretend", +] +test-randomorder = ["pytest-randomly"] +docs = ["sphinx >=5.3.0", "sphinx-rtd-theme >=1.1.1"] +docstest = ["pyenchant >=1.6.11", "twine >=1.12.0", "sphinxcontrib-spelling >=4.0.1"] +sdist = ["setuptools_rust >=0.11.4"] +pep8test = ["black", "ruff", "mypy", "check-manifest"] + [tool.black] line-length = 79 target-version = ["py37"] diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 610ce986d7c4..000000000000 --- a/setup.cfg +++ /dev/null @@ -1,86 +0,0 @@ -[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 = Apache-2.0 OR BSD-3-Clause -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.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - Programming Language :: Python :: 3.11 - Programming Language :: Python :: Implementation :: CPython - Programming Language :: Python :: Implementation :: PyPy - Topic :: Security :: Cryptography - -[options] -python_requires = >=3.7 -include_package_data = True -zip_safe = False -package_dir = - =src -packages = find: -# `install_requires` must be kept in sync with `pyproject.toml` -install_requires = - cffi >=1.12 - -[options.packages.find] -where = src -exclude = - _cffi_src - _cffi_src.* - -[options.extras_require] -tox = - tox -test = - pytest>=6.2.0 - pytest-shard>=0.1.2 - pytest-benchmark - pytest-cov - pytest-subtests>=0.10.0 - pytest-xdist - pretend -test-randomorder: - pytest-randomly -docs = - sphinx >= 5.3.0 - sphinx-rtd-theme>=1.1.1 -docstest = - pyenchant >= 1.6.11 - twine >= 1.12.0 - sphinxcontrib-spelling >= 4.0.1 -sdist = - setuptools_rust >= 0.11.4 -pep8test = - black - ruff - mypy - check-manifest -# 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 diff --git a/setup.py b/setup.py index 662f483af3e3..8ccc0c1f1de5 100644 --- a/setup.py +++ b/setup.py @@ -44,7 +44,7 @@ sys.path.insert(0, src_dir) try: - # See setup.cfg for most of the config metadata. + # See pyproject.toml for most of the config metadata. setup( rust_extensions=[ RustExtension( From 7e62312797cc018891fa4ffcfd9485fafacd3dfe Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 24 Mar 2023 17:23:13 -0400 Subject: [PATCH 014/316] Upgrade to pyo3 0.18 (#6935) * Upgrade to pyo3 0.16 * Upgrade to pyo3 0.17 * Upgrade to pyo3 0.18 --- MANIFEST.in | 2 + setup.py | 2 +- src/rust/Cargo.lock | 90 ++++++++++++--------------- src/rust/Cargo.toml | 2 +- src/rust/src/asn1.rs | 4 +- src/rust/src/backend/x25519.rs | 42 ++++++------- src/rust/src/error.rs | 23 +++---- src/rust/src/lib.rs | 3 - src/rust/src/oid.rs | 10 +-- src/rust/src/pkcs7.rs | 2 +- src/rust/src/x509/certificate.rs | 22 +++---- src/rust/src/x509/common.rs | 26 ++++---- src/rust/src/x509/crl.rs | 79 ++++++++++------------- src/rust/src/x509/csr.rs | 15 ++--- src/rust/src/x509/extensions.rs | 2 +- src/rust/src/x509/ocsp_req.rs | 6 +- src/rust/src/x509/ocsp_resp.rs | 39 ++++++------ src/rust/src/x509/sct.rs | 43 ++++++------- src/rust/src/x509/sign.rs | 26 ++++---- tests/hazmat/primitives/test_pkcs7.py | 2 +- 20 files changed, 196 insertions(+), 244 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index c171033124b4..2417dd9d3088 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -16,6 +16,8 @@ prune docs/_build recursive-include tests *.py exclude vectors recursive-exclude vectors * +exclude src/rust/target +recursive-exclude src/rust/target * recursive-exclude .github * diff --git a/setup.py b/setup.py index 8ccc0c1f1de5..b3a7cf9b241e 100644 --- a/setup.py +++ b/setup.py @@ -55,7 +55,7 @@ features=( [] if platform.python_implementation() == "PyPy" - else ["pyo3/abi3-py36"] + else ["pyo3/abi3-py37"] ), rust_version=">=1.56.0", ) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 72a8c60a81ad..2aabfbb66e66 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -209,24 +209,10 @@ dependencies = [ [[package]] name = "indoc" -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" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0" +checksum = "e7906a9fababaeacb774f72410e497a1d18de916322e33797bb2cd29baa23c9e" dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", "unindent", ] @@ -282,6 +268,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -394,25 +389,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "paste" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -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 = "pem" version = "1.1.1" @@ -452,12 +428,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" version = "1.0.53" @@ -469,35 +439,48 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.15.2" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d41d50a7271e08c7c8a54cd24af5d62f73ee3a6f6a314215281ebdec421d5752" +checksum = "06a3d8e8a46ab2738109347433cb7b96dffda2e4a218b03ef27090238886b147" dependencies = [ "cfg-if", "indoc", "libc", + "memoffset", "parking_lot", - "paste", "pyo3-build-config", + "pyo3-ffi", "pyo3-macros", "unindent", ] [[package]] name = "pyo3-build-config" -version = "0.15.2" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "779239fc40b8e18bc8416d3a37d280ca9b9fb04bda54b98037bb6748595c2410" +checksum = "75439f995d07ddfad42b192dfcf3bc66a7ecfd8b4a1f5f6f046aa5c2c5d7677d" dependencies = [ "once_cell", + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "839526a5c07a17ff44823679b68add4a58004de00512a95b6c1c98a6dcac0ee5" +dependencies = [ + "libc", + "pyo3-build-config", ] [[package]] name = "pyo3-macros" -version = "0.15.2" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b247e8c664be87998d8628e86f282c25066165f1f8dda66100c48202fdb93a" +checksum = "bd44cf207476c6a9760c4653559be4f206efafb924d3e4cbf2721475fc0d6cc5" dependencies = [ + "proc-macro2", "pyo3-macros-backend", "quote", "syn", @@ -505,12 +488,11 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.15.2" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a8c2812c412e00e641d99eeb79dd478317d981d938aa60325dfa7157b607095" +checksum = "dc1f43d8e30460f36350d18631ccf85ded64c059829208fe680904c65bcd0a4c" dependencies = [ "proc-macro2", - "pyo3-build-config", "quote", "syn", ] @@ -562,6 +544,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "target-lexicon" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1" + [[package]] name = "termcolor" version = "1.2.0" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 2c3e1ae93f65..5de812febf45 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -9,7 +9,7 @@ rust-version = "1.56.0" [dependencies] once_cell = "1" -pyo3 = { version = "0.15.2" } +pyo3 = { version = "0.18" } asn1 = { version = "0.13.0", default-features = false, features = ["const-generics"] } pem = "1.1" chrono = { version = "0.4.24", default-features = false, features = ["alloc", "clock"] } diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 0bc57341e592..9d034ab77332 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -105,9 +105,9 @@ pub(crate) fn encode_der_data<'p>( .import("cryptography.hazmat.primitives.serialization")? .getattr(crate::intern!(py, "Encoding"))?; - if encoding == encoding_class.getattr(crate::intern!(py, "DER"))? { + if encoding.is(encoding_class.getattr(crate::intern!(py, "DER"))?) { Ok(pyo3::types::PyBytes::new(py, &data)) - } else if encoding == encoding_class.getattr(crate::intern!(py, "PEM"))? { + } else if encoding.is(encoding_class.getattr(crate::intern!(py, "PEM"))?) { Ok(pyo3::types::PyBytes::new( py, &pem::encode_config( diff --git a/src/rust/src/backend/x25519.rs b/src/rust/src/backend/x25519.rs index 96a2c7a5cc6e..72649ec7bdc1 100644 --- a/src/rust/src/backend/x25519.rs +++ b/src/rust/src/backend/x25519.rs @@ -118,14 +118,14 @@ impl X25519PrivateKey { .getattr(crate::intern!(py, "BestAvailableEncryption"))? .extract()?; - if !encoding_class.is_instance(encoding)? { + if !encoding.is_instance(encoding_class)? { return Err(CryptographyError::from( pyo3::exceptions::PyTypeError::new_err( "encoding must be an item from the Encoding enum", ), )); } - if !private_format_class.is_instance(format)? { + if !format.is_instance(private_format_class)? { return Err(CryptographyError::from( pyo3::exceptions::PyTypeError::new_err( "format must be an item from the PrivateFormat enum", @@ -133,12 +133,12 @@ impl X25519PrivateKey { )); } - if encoding == encoding_class.getattr(crate::intern!(py, "Raw"))? - || format == private_format_class.getattr(crate::intern!(py, "Raw"))? + if encoding.is(encoding_class.getattr(crate::intern!(py, "Raw"))?) + || format.is(private_format_class.getattr(crate::intern!(py, "Raw"))?) { - if encoding != encoding_class.getattr(crate::intern!(py, "Raw"))? - || format != private_format_class.getattr(crate::intern!(py, "Raw"))? - || !no_encryption_class.is_instance(encryption_algorithm)? + if !encoding.is(encoding_class.getattr(crate::intern!(py, "Raw"))?) + || !format.is(private_format_class.getattr(crate::intern!(py, "Raw"))?) + || !encryption_algorithm.is_instance(no_encryption_class)? { return Err(CryptographyError::from(pyo3::exceptions::PyValueError::new_err( "When using Raw both encoding and format must be Raw and encryption_algorithm must be NoEncryption()" @@ -148,9 +148,9 @@ impl X25519PrivateKey { return Ok(pyo3::types::PyBytes::new(py, &raw_bytes)); } - let password = if no_encryption_class.is_instance(encryption_algorithm)? { + let password = if encryption_algorithm.is_instance(no_encryption_class)? { b"" - } else if best_available_encryption_class.is_instance(encryption_algorithm)? { + } else if encryption_algorithm.is_instance(best_available_encryption_class)? { encryption_algorithm .getattr(crate::intern!(py, "password"))? .extract::<&[u8]>()? @@ -170,8 +170,8 @@ impl X25519PrivateKey { )); } - if format == private_format_class.getattr(crate::intern!(py, "PKCS8"))? { - if encoding == encoding_class.getattr(crate::intern!(py, "PEM"))? { + if format.is(private_format_class.getattr(crate::intern!(py, "PKCS8"))?) { + if encoding.is(encoding_class.getattr(crate::intern!(py, "PEM"))?) { let pem_bytes = if password.is_empty() { self.pkey.private_key_to_pem_pkcs8()? } else { @@ -181,7 +181,7 @@ impl X25519PrivateKey { )? }; return Ok(pyo3::types::PyBytes::new(py, &pem_bytes)); - } else if encoding == encoding_class.getattr(crate::intern!(py, "DER"))? { + } else if encoding.is(encoding_class.getattr(crate::intern!(py, "DER"))?) { let der_bytes = if password.is_empty() { self.pkey.private_key_to_pkcs8()? } else { @@ -228,14 +228,14 @@ impl X25519PublicKey { .getattr(crate::intern!(py, "PublicFormat"))? .extract()?; - if !encoding_class.is_instance(encoding)? { + if !encoding.is_instance(encoding_class)? { return Err(CryptographyError::from( pyo3::exceptions::PyTypeError::new_err( "encoding must be an item from the Encoding enum", ), )); } - if !public_format_class.is_instance(format)? { + if !format.is_instance(public_format_class)? { return Err(CryptographyError::from( pyo3::exceptions::PyTypeError::new_err( "format must be an item from the PublicFormat enum", @@ -243,11 +243,11 @@ impl X25519PublicKey { )); } - if encoding == encoding_class.getattr(crate::intern!(py, "Raw"))? - || format == public_format_class.getattr(crate::intern!(py, "Raw"))? + if encoding.is(encoding_class.getattr(crate::intern!(py, "Raw"))?) + || format.is(public_format_class.getattr(crate::intern!(py, "Raw"))?) { - if encoding != encoding_class.getattr(crate::intern!(py, "Raw"))? - || format != public_format_class.getattr(crate::intern!(py, "Raw"))? + if !encoding.is(encoding_class.getattr(crate::intern!(py, "Raw"))?) + || !format.is(public_format_class.getattr(crate::intern!(py, "Raw"))?) { return Err(CryptographyError::from( pyo3::exceptions::PyValueError::new_err( @@ -260,11 +260,11 @@ impl X25519PublicKey { } // SubjectPublicKeyInfo + PEM/DER - if format == public_format_class.getattr(crate::intern!(py, "SubjectPublicKeyInfo"))? { - if encoding == encoding_class.getattr(crate::intern!(py, "PEM"))? { + if format.is(public_format_class.getattr(crate::intern!(py, "SubjectPublicKeyInfo"))?) { + if encoding.is(encoding_class.getattr(crate::intern!(py, "PEM"))?) { let pem_bytes = self.pkey.public_key_to_pem()?; return Ok(pyo3::types::PyBytes::new(py, &pem_bytes)); - } else if encoding == encoding_class.getattr(crate::intern!(py, "DER"))? { + } else if encoding.is(encoding_class.getattr(crate::intern!(py, "DER"))?) { let der_bytes = self.pkey.public_key_to_der()?; return Ok(pyo3::types::PyBytes::new(py, &der_bytes)); } else { diff --git a/src/rust/src/error.rs b/src/rust/src/error.rs index 6c6440c8d33c..35713bbab75a 100644 --- a/src/rust/src/error.rs +++ b/src/rust/src/error.rs @@ -62,10 +62,7 @@ impl From for pyo3::PyErr { ) } CryptographyError::Py(py_error) => py_error, - CryptographyError::OpenSSL(error_stack) => { - let gil = pyo3::Python::acquire_gil(); - let py = gil.python(); - + CryptographyError::OpenSSL(error_stack) => pyo3::Python::with_gil(|py| { let internal_error = py .import("cryptography.exceptions") .expect("Failed to import cryptography module") @@ -81,21 +78,21 @@ impl From for pyo3::PyErr { ) .expect("Failed to append to list"); } - pyo3::PyErr::from_instance( + pyo3::PyErr::from_value( internal_error .call1(( "Unknown OpenSSL error. This error is commonly encountered - when another library is not cleaning up the OpenSSL error - stack. If you are using cryptography with another library - that uses OpenSSL try disabling it before reporting a bug. - Otherwise please file an issue at - https://github.com/pyca/cryptography/issues with - information on how to reproduce this.", + when another library is not cleaning up the OpenSSL error + stack. If you are using cryptography with another library + that uses OpenSSL try disabling it before reporting a bug. + Otherwise please file an issue at + https://github.com/pyca/cryptography/issues with + information on how to reproduce this.", errors, )) .expect("Failed to create InternalError"), ) - } + }), } } } @@ -130,7 +127,7 @@ mod tests { CryptographyError::Asn1Write(asn1::WriteError::AllocationError) )); let py_e: pyo3::PyErr = e.into(); - assert!(py_e.is_instance::(py)); + assert!(py_e.is_instance_of::(py)); let e: CryptographyError = pyo3::PyDowncastError::new(py.None().as_ref(py), "abc").into(); diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 2ec4e66bb5c2..dae286cc0d56 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -128,10 +128,7 @@ impl OpenSSLError { fn _lib_reason_match(&self, lib: i32, reason: i32) -> bool { self.e.library_code() == lib && self.e.reason_code() == reason } -} -#[pyo3::prelude::pyproto] -impl pyo3::PyObjectProtocol for OpenSSLError { fn __repr__(&self) -> pyo3::PyResult { Ok(format!( "", diff --git a/src/rust/src/oid.rs b/src/rust/src/oid.rs index a13668579a74..43d26802aaed 100644 --- a/src/rust/src/oid.rs +++ b/src/rust/src/oid.rs @@ -39,14 +39,8 @@ impl ObjectIdentifier { fn __deepcopy__(slf: pyo3::PyRef<'_, Self>, _memo: pyo3::PyObject) -> pyo3::PyRef<'_, Self> { slf } -} - -#[pyo3::prelude::pyproto] -impl pyo3::PyObjectProtocol for ObjectIdentifier { - fn __repr__(&self) -> pyo3::PyResult { - let gil = pyo3::Python::acquire_gil(); - let py = gil.python(); + fn __repr__(&self, py: pyo3::Python<'_>) -> pyo3::PyResult { let self_clone = pyo3::PyCell::new( py, ObjectIdentifier { @@ -62,7 +56,7 @@ impl pyo3::PyObjectProtocol for ObjectIdentifier { fn __richcmp__( &self, - other: pyo3::PyRef, + other: pyo3::PyRef<'_, ObjectIdentifier>, op: pyo3::basic::CompareOp, ) -> pyo3::PyResult { match op { diff --git a/src/rust/src/pkcs7.rs b/src/rust/src/pkcs7.rs index c23300ac49a3..53e479e5b3e2 100644 --- a/src/rust/src/pkcs7.rs +++ b/src/rust/src/pkcs7.rs @@ -298,7 +298,7 @@ fn sign_and_serialize<'p>( .import("cryptography.hazmat.primitives.serialization")? .getattr(crate::intern!(py, "Encoding"))?; - if encoding == encoding_class.getattr(crate::intern!(py, "SMIME"))? { + if encoding.is(encoding_class.getattr(crate::intern!(py, "SMIME"))?) { let mic_algs = digest_algs .iter() .map(|d| OIDS_TO_MIC_NAME[&d.oid]) diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 1a9820e5ea06..2e0378ff9d40 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -83,8 +83,8 @@ pub(crate) struct Certificate { pub(crate) cached_extensions: Option, } -#[pyo3::prelude::pyproto] -impl pyo3::PyObjectProtocol for Certificate { +#[pyo3::prelude::pymethods] +impl Certificate { fn __hash__(&self) -> u64 { let mut hasher = DefaultHasher::new(); self.raw.borrow_value().hash(&mut hasher); @@ -93,7 +93,7 @@ impl pyo3::PyObjectProtocol for Certificate { fn __richcmp__( &self, - other: pyo3::PyRef, + other: pyo3::PyRef<'_, Certificate>, op: pyo3::basic::CompareOp, ) -> pyo3::PyResult { match op { @@ -105,18 +105,12 @@ impl pyo3::PyObjectProtocol for Certificate { } } - fn __repr__(&self) -> pyo3::PyResult { - let gil = pyo3::Python::acquire_gil(); - let py = gil.python(); - + fn __repr__(&self, py: pyo3::Python<'_>) -> pyo3::PyResult { let subject = self.subject(py)?; let subject_repr = subject.repr()?.extract::<&str>()?; Ok(format!("", subject_repr)) } -} -#[pyo3::prelude::pymethods] -impl Certificate { fn __deepcopy__(slf: pyo3::PyRef<'_, Self>, _memo: pyo3::PyObject) -> pyo3::PyRef<'_, Self> { slf } @@ -277,7 +271,7 @@ impl Certificate { let hash_alg = sig_oids_to_hash.get_item(self.signature_algorithm_oid(py)?); match hash_alg { Ok(data) => Ok(data), - Err(_) => Err(CryptographyError::from(pyo3::PyErr::from_instance( + Err(_) => Err(CryptographyError::from(pyo3::PyErr::from_value( py.import("cryptography.exceptions")?.call_method1( "UnsupportedAlgorithm", (format!( @@ -359,11 +353,11 @@ fn cert_version(py: pyo3::Python<'_>, version: u8) -> Result<&pyo3::PyAny, Crypt match version { 0 => Ok(x509_module .getattr(crate::intern!(py, "Version"))? - .get_item("v1")?), + .get_item(crate::intern!(py, "v1"))?), 2 => Ok(x509_module .getattr(crate::intern!(py, "Version"))? - .get_item("v3")?), - _ => Err(CryptographyError::from(pyo3::PyErr::from_instance( + .get_item(crate::intern!(py, "v3"))?), + _ => Err(CryptographyError::from(pyo3::PyErr::from_value( x509_module .getattr(crate::intern!(py, "InvalidVersion"))? .call1((format!("{} is not a valid X509 version", version), version))?, diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index a765d614457c..59710a3aed17 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -112,10 +112,10 @@ pub(crate) fn encode_name_entry<'p>( let tag = attr_type .getattr(crate::intern!(py, "value"))? .extract::()?; - let value: &[u8] = if attr_type != asn1_type.getattr(crate::intern!(py, "BitString"))? { - let encoding = if attr_type == asn1_type.getattr(crate::intern!(py, "BMPString"))? { + let value: &[u8] = if !attr_type.is(asn1_type.getattr(crate::intern!(py, "BitString"))?) { + let encoding = if attr_type.is(asn1_type.getattr(crate::intern!(py, "BMPString"))?) { "utf_16_be" - } else if attr_type == asn1_type.getattr(crate::intern!(py, "UniversalString"))? { + } else if attr_type.is(asn1_type.getattr(crate::intern!(py, "UniversalString"))?) { "utf_32_be" } else { "utf8" @@ -233,18 +233,18 @@ pub(crate) fn encode_general_name<'a>( let gn_module = py.import("cryptography.x509.general_name")?; let gn_type = gn.get_type().as_ref(); let gn_value = gn.getattr(crate::intern!(py, "value"))?; - if gn_type == gn_module.getattr(crate::intern!(py, "DNSName"))? { + if gn_type.is(gn_module.getattr(crate::intern!(py, "DNSName"))?) { Ok(GeneralName::DNSName(UnvalidatedIA5String( gn_value.extract::<&str>()?, ))) - } else if gn_type == gn_module.getattr(crate::intern!(py, "RFC822Name"))? { + } else if gn_type.is(gn_module.getattr(crate::intern!(py, "RFC822Name"))?) { Ok(GeneralName::RFC822Name(UnvalidatedIA5String( gn_value.extract::<&str>()?, ))) - } else if gn_type == gn_module.getattr(crate::intern!(py, "DirectoryName"))? { + } else if gn_type.is(gn_module.getattr(crate::intern!(py, "DirectoryName"))?) { let name = encode_name(py, gn_value)?; Ok(GeneralName::DirectoryName(name)) - } else if gn_type == gn_module.getattr(crate::intern!(py, "OtherName"))? { + } else if gn_type.is(gn_module.getattr(crate::intern!(py, "OtherName"))?) { Ok(GeneralName::OtherName(OtherName { type_id: py_oid_to_oid(gn.getattr(crate::intern!(py, "type_id"))?)?, value: asn1::parse_single(gn_value.extract::<&[u8]>()?).map_err(|e| { @@ -254,15 +254,15 @@ pub(crate) fn encode_general_name<'a>( )) })?, })) - } else if gn_type == gn_module.getattr(crate::intern!(py, "UniformResourceIdentifier"))? { + } else if gn_type.is(gn_module.getattr(crate::intern!(py, "UniformResourceIdentifier"))?) { Ok(GeneralName::UniformResourceIdentifier( UnvalidatedIA5String(gn_value.extract::<&str>()?), )) - } else if gn_type == gn_module.getattr(crate::intern!(py, "IPAddress"))? { + } else if gn_type.is(gn_module.getattr(crate::intern!(py, "IPAddress"))?) { Ok(GeneralName::IPAddress( gn.call_method0("_packed")?.extract::<&[u8]>()?, )) - } else if gn_type == gn_module.getattr(crate::intern!(py, "RegisteredID"))? { + } else if gn_type.is(gn_module.getattr(crate::intern!(py, "RegisteredID"))?) { let oid = py_oid_to_oid(gn_value)?; Ok(GeneralName::RegisteredID(oid)) } else { @@ -462,7 +462,7 @@ pub(crate) fn parse_general_name( .to_object(py) } _ => { - return Err(CryptographyError::from(pyo3::PyErr::from_instance( + return Err(CryptographyError::from(pyo3::PyErr::from_value( x509_module.call_method1( "UnsupportedGeneralNameType", ("x400Address/EDIPartyName are not supported types",), @@ -563,7 +563,7 @@ pub(crate) fn parse_and_cache_extensions< let oid_obj = oid_to_py_oid(py, &raw_ext.extn_id)?; if seen_oids.contains(&raw_ext.extn_id) { - return Err(pyo3::PyErr::from_instance(x509_module.call_method1( + return Err(pyo3::PyErr::from_value(x509_module.call_method1( "DuplicateExtension", ( format!("Duplicate {} extension found", raw_ext.extn_id), @@ -613,7 +613,7 @@ pub(crate) fn encode_extensions< let oid = py_oid_to_oid(py_ext.getattr(crate::intern!(py, "oid"))?)?; let ext_val = py_ext.getattr(crate::intern!(py, "value"))?; - if unrecognized_extension_type.is_instance(ext_val)? { + if ext_val.is_instance(unrecognized_extension_type)? { exts.push(Extension { extn_id: oid, critical: py_ext.getattr(crate::intern!(py, "critical"))?.extract()?, diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index c1b5c8c48d86..37a4902aea2b 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -26,7 +26,7 @@ fn load_der_x509_crl( let version = raw.borrow_value().tbs_cert_list.version.unwrap_or(1); if version != 1 { let x509_module = py.import("cryptography.x509")?; - return Err(CryptographyError::from(pyo3::PyErr::from_instance( + return Err(CryptographyError::from(pyo3::PyErr::from_value( x509_module .getattr(crate::intern!(py, "InvalidVersion"))? .call1((format!("{} is not a valid CRL version", version), version))?, @@ -97,11 +97,11 @@ impl CertificateRevocationList { } } -#[pyo3::prelude::pyproto] -impl pyo3::PyObjectProtocol for CertificateRevocationList { +#[pyo3::prelude::pymethods] +impl CertificateRevocationList { fn __richcmp__( &self, - other: pyo3::PyRef, + other: pyo3::PyRef<'_, CertificateRevocationList>, op: pyo3::basic::CompareOp, ) -> pyo3::PyResult { match op { @@ -112,18 +112,31 @@ impl pyo3::PyObjectProtocol for CertificateRevocationList { )), } } -} -#[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(); + fn __iter__(&self) -> CRLIterator { + CRLIterator { + contents: OwnedCRLIteratorData::try_new(Arc::clone(&self.raw), |v| { + Ok::<_, ()>( + v.borrow_value() + .tbs_cert_list + .revoked_certificates + .as_ref() + .map(|v| v.unwrap_read().clone()), + ) + }) + .unwrap(), + } + } + fn __getitem__( + &self, + py: pyo3::Python<'_>, + idx: &pyo3::PyAny, + ) -> pyo3::PyResult { self.raw.with(|val| { val.revoked_certs.get_or_init(py, || { match &val.value.tbs_cert_list.revoked_certificates { @@ -133,7 +146,7 @@ impl pyo3::PyMappingProtocol for CertificateRevocationList { }); }); - if idx.is_instance::()? { + if idx.is_instance_of::()? { let indices = idx .downcast::()? .indices(self.len().try_into().unwrap())?; @@ -154,10 +167,7 @@ impl pyo3::PyMappingProtocol for CertificateRevocationList { Ok(pyo3::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>, @@ -189,7 +199,7 @@ impl CertificateRevocationList { .get_item(oid) { Ok(v) => Ok(v), - Err(_) => Err(pyo3::PyErr::from_instance(exceptions_module.call_method1( + Err(_) => Err(pyo3::PyErr::from_value(exceptions_module.call_method1( "UnsupportedAlgorithm", (format!( "Signature algorithm OID:{} not recognized", @@ -395,24 +405,6 @@ impl CertificateRevocationList { } } -#[pyo3::prelude::pyproto] -impl pyo3::PyIterProtocol<'_> for CertificateRevocationList { - fn __iter__(slf: pyo3::PyRef<'p, Self>) -> CRLIterator { - CRLIterator { - contents: OwnedCRLIteratorData::try_new(Arc::clone(&slf.raw), |v| { - Ok::<_, ()>( - v.borrow_value() - .tbs_cert_list - .revoked_certificates - .as_ref() - .map(|v| v.unwrap_read().clone()), - ) - }) - .unwrap(), - } - } -} - #[ouroboros::self_referencing] struct OwnedCRLIteratorData { data: Arc, @@ -455,14 +447,18 @@ fn try_map_arc_data_mut_crl_iterator( }) } -#[pyo3::prelude::pyproto] -impl pyo3::PyIterProtocol<'_> for CRLIterator { - fn __iter__(slf: pyo3::PyRef<'p, Self>) -> pyo3::PyRef<'p, Self> { +#[pyo3::prelude::pymethods] +impl CRLIterator { + fn __len__(&self) -> usize { + self.contents.borrow_value().clone().map_or(0, |v| v.len()) + } + + fn __iter__(slf: pyo3::PyRef<'_, Self>) -> pyo3::PyRef<'_, Self> { slf } - fn __next__(mut slf: pyo3::PyRefMut<'p, Self>) -> Option { - let revoked = try_map_arc_data_mut_crl_iterator(&mut slf.contents, |_data, v| match v { + fn __next__(&mut self) -> Option { + let revoked = try_map_arc_data_mut_crl_iterator(&mut self.contents, |_data, v| match v { Some(v) => match v.next() { Some(revoked) => Ok(revoked), None => Err(()), @@ -477,13 +473,6 @@ impl pyo3::PyIterProtocol<'_> for CRLIterator { } } -#[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>, diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index e16a58164c17..8a7f533041c1 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -84,8 +84,8 @@ struct CertificateSigningRequest { cached_extensions: Option, } -#[pyo3::prelude::pyproto] -impl pyo3::basic::PyObjectProtocol for CertificateSigningRequest { +#[pyo3::prelude::pymethods] +impl CertificateSigningRequest { fn __hash__(&self) -> u64 { let mut hasher = DefaultHasher::new(); self.raw.borrow_data().hash(&mut hasher); @@ -94,7 +94,7 @@ impl pyo3::basic::PyObjectProtocol for CertificateSigningRequest { fn __richcmp__( &self, - other: pyo3::PyRef, + other: pyo3::PyRef<'_, CertificateSigningRequest>, op: pyo3::basic::CompareOp, ) -> pyo3::PyResult { match op { @@ -105,10 +105,7 @@ impl pyo3::basic::PyObjectProtocol for CertificateSigningRequest { )), } } -} -#[pyo3::prelude::pymethods] -impl CertificateSigningRequest { fn public_key<'p>(&self, py: pyo3::Python<'p>) -> CryptographyResult<&'p pyo3::PyAny> { // This makes an unnecessary copy. It'd be nice to get rid of it. let serialized = pyo3::types::PyBytes::new( @@ -154,7 +151,7 @@ impl CertificateSigningRequest { let hash_alg = sig_oids_to_hash.get_item(self.signature_algorithm_oid(py)?); match hash_alg { Ok(data) => Ok(data), - Err(_) => Err(CryptographyError::from(pyo3::PyErr::from_instance( + Err(_) => Err(CryptographyError::from(pyo3::PyErr::from_value( py.import("cryptography.exceptions")?.call_method1( "UnsupportedAlgorithm", (format!( @@ -222,7 +219,7 @@ impl CertificateSigningRequest { } } } - Err(pyo3::PyErr::from_instance( + Err(pyo3::PyErr::from_value( py.import("cryptography.x509")?.call_method1( "AttributeNotFound", (format!("No {} attribute was found", oid), oid), @@ -309,7 +306,7 @@ fn load_der_x509_csr( let version = raw.borrow_value().csr_info.version; if version != 0 { let x509_module = py.import("cryptography.x509")?; - return Err(CryptographyError::from(pyo3::PyErr::from_instance( + return Err(CryptographyError::from(pyo3::PyErr::from_value( x509_module .getattr(crate::intern!(py, "InvalidVersion"))? .call1((format!("{} is not a valid CSR version", version), version))?, diff --git a/src/rust/src/x509/extensions.rs b/src/rust/src/x509/extensions.rs index d93e87c0f1a3..1af8d389de72 100644 --- a/src/rust/src/x509/extensions.rs +++ b/src/rust/src/x509/extensions.rs @@ -229,7 +229,7 @@ pub(crate) fn encode_extension( let mut qualifiers = vec![]; for py_qualifier in py_policy_qualifiers.iter()? { let py_qualifier = py_qualifier?; - let qualifier = if py_qualifier.is_instance::()? { + let qualifier = if py_qualifier.is_instance_of::()? { let cps_uri = match asn1::IA5String::new(py_qualifier.extract()?) { Some(s) => s, None => { diff --git a/src/rust/src/x509/ocsp_req.rs b/src/rust/src/x509/ocsp_req.rs index 638caf9b2494..5711dd4a9546 100644 --- a/src/rust/src/x509/ocsp_req.rs +++ b/src/rust/src/x509/ocsp_req.rs @@ -83,10 +83,10 @@ impl OCSPRequest { let hashes = py.import("cryptography.hazmat.primitives.hashes")?; match ocsp::OIDS_TO_HASH.get(&cert_id.hash_algorithm.oid) { - Some(alg_name) => Ok(hashes.getattr(alg_name)?.call0()?), + Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), None => { let exceptions = py.import("cryptography.exceptions")?; - Err(CryptographyError::from(pyo3::PyErr::from_instance( + Err(CryptographyError::from(pyo3::PyErr::from_value( exceptions .getattr(crate::intern!(py, "UnsupportedAlgorithm"))? .call1((format!( @@ -141,7 +141,7 @@ impl OCSPRequest { .import("cryptography.hazmat.primitives.serialization")? .getattr(crate::intern!(py, "Encoding"))? .getattr(crate::intern!(py, "DER"))?; - if encoding != der { + if !encoding.is(der) { return Err(pyo3::exceptions::PyValueError::new_err( "The only allowed encoding value is Encoding.DER", ) diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index 2f878b2c4c3e..9f38282931bc 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -183,7 +183,7 @@ impl OCSPResponse { "Signature algorithm OID: {} not recognized", self.requires_successful_response()?.signature_algorithm.oid ); - Err(CryptographyError::from(pyo3::PyErr::from_instance( + Err(CryptographyError::from(pyo3::PyErr::from_value( py.import("cryptography.exceptions")? .call_method1("UnsupportedAlgorithm", (exc_messsage,))?, ))) @@ -383,7 +383,7 @@ impl OCSPResponse { .import("cryptography.hazmat.primitives.serialization")? .getattr(crate::intern!(py, "Encoding"))? .getattr(crate::intern!(py, "DER"))?; - if encoding != der { + if !encoding.is(der) { return Err(pyo3::exceptions::PyValueError::new_err( "The only allowed encoding value is Encoding.DER", ) @@ -528,10 +528,10 @@ impl SingleResponse<'_> { ) -> Result<&'p pyo3::PyAny, CryptographyError> { let hashes = py.import("cryptography.hazmat.primitives.hashes")?; match ocsp::OIDS_TO_HASH.get(&self.cert_id.hash_algorithm.oid) { - Some(alg_name) => Ok(hashes.getattr(alg_name)?.call0()?), + Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), None => { let exceptions = py.import("cryptography.exceptions")?; - Err(CryptographyError::from(pyo3::PyErr::from_instance( + Err(CryptographyError::from(pyo3::PyErr::from_value( exceptions .getattr(crate::intern!(py, "UnsupportedAlgorithm"))? .call1((format!( @@ -627,16 +627,14 @@ fn create_ocsp_response( .extract()?; let py_cert_status = py_single_resp.getattr(crate::intern!(py, "_cert_status"))?; - let cert_status = if py_cert_status - == ocsp_mod - .getattr(crate::intern!(py, "OCSPCertStatus"))? - .getattr(crate::intern!(py, "GOOD"))? + let cert_status = if py_cert_status.is(ocsp_mod + .getattr(crate::intern!(py, "OCSPCertStatus"))? + .getattr(crate::intern!(py, "GOOD"))?) { CertStatus::Good(()) - } else if py_cert_status - == ocsp_mod - .getattr(crate::intern!(py, "OCSPCertStatus"))? - .getattr(crate::intern!(py, "UNKNOWN"))? + } else if py_cert_status.is(ocsp_mod + .getattr(crate::intern!(py, "OCSPCertStatus"))? + .getattr(crate::intern!(py, "UNKNOWN"))?) { CertStatus::Unknown(()) } else { @@ -687,10 +685,9 @@ fn create_ocsp_response( }]; borrowed_cert = responder_cert.borrow(); - let responder_id = if responder_encoding - == ocsp_mod - .getattr(crate::intern!(py, "OCSPResponderEncoding"))? - .getattr(crate::intern!(py, "HASH"))? + let responder_id = if responder_encoding.is(ocsp_mod + .getattr(crate::intern!(py, "OCSPResponderEncoding"))? + .getattr(crate::intern!(py, "HASH"))?) { let sha1 = py .import("cryptography.hazmat.primitives.hashes")? @@ -801,15 +798,15 @@ struct OCSPResponseIterator { contents: OwnedOCSPResponseIteratorData, } -#[pyo3::prelude::pyproto] -impl pyo3::PyIterProtocol<'_> for OCSPResponseIterator { - fn __iter__(slf: pyo3::PyRef<'p, Self>) -> pyo3::PyRef<'p, Self> { +#[pyo3::prelude::pymethods] +impl OCSPResponseIterator { + fn __iter__(slf: pyo3::PyRef<'_, Self>) -> pyo3::PyRef<'_, Self> { slf } - fn __next__(mut slf: pyo3::PyRefMut<'p, Self>) -> Option { + fn __next__(&mut self) -> Option { let single_resp = - try_map_arc_data_mut_ocsp_response_iterator(&mut slf.contents, |_data, v| { + try_map_arc_data_mut_ocsp_response_iterator(&mut self.contents, |_data, v| { match v.next() { Some(single_resp) => Ok(single_resp), None => Err(()), diff --git a/src/rust/src/x509/sct.rs b/src/rust/src/x509/sct.rs index e3f7be4d9036..b6b2e56dab86 100644 --- a/src/rust/src/x509/sct.rs +++ b/src/rust/src/x509/sct.rs @@ -143,6 +143,26 @@ pub(crate) struct Sct { #[pyo3::prelude::pymethods] impl Sct { + fn __richcmp__( + &self, + other: pyo3::PyRef<'_, Sct>, + op: pyo3::basic::CompareOp, + ) -> pyo3::PyResult { + match op { + pyo3::basic::CompareOp::Eq => Ok(self.sct_data == other.sct_data), + pyo3::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() + } + #[getter] fn version<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { py.import("cryptography.x509.certificate_transparency")? @@ -209,29 +229,6 @@ impl Sct { } } -#[pyo3::prelude::pyproto] -impl pyo3::PyObjectProtocol for Sct { - fn __richcmp__( - &self, - other: pyo3::PyRef, - op: pyo3::basic::CompareOp, - ) -> pyo3::PyResult { - match op { - pyo3::basic::CompareOp::Eq => Ok(self.sct_data == other.sct_data), - pyo3::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() - } -} - pub(crate) fn parse_scts( py: pyo3::Python<'_>, data: &[u8], diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index 33d293b21527..4d505ece7886 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -59,15 +59,15 @@ fn identify_key_type(py: pyo3::Python<'_>, private_key: &pyo3::PyAny) -> pyo3::P .getattr(crate::intern!(py, "Ed448PrivateKey"))? .extract()?; - if rsa_private_key.is_instance(private_key)? { + if private_key.is_instance(rsa_private_key)? { Ok(KeyType::Rsa) - } else if dsa_key_type.is_instance(private_key)? { + } else if private_key.is_instance(dsa_key_type)? { Ok(KeyType::Dsa) - } else if ec_key_type.is_instance(private_key)? { + } else if private_key.is_instance(ec_key_type)? { Ok(KeyType::Ec) - } else if ed25519_key_type.is_instance(private_key)? { + } else if private_key.is_instance(ed25519_key_type)? { Ok(KeyType::Ed25519) - } else if ed448_key_type.is_instance(private_key)? { + } else if private_key.is_instance(ed448_key_type)? { Ok(KeyType::Ed448) } else { Err(pyo3::exceptions::PyTypeError::new_err( @@ -88,7 +88,7 @@ fn identify_hash_type( .import("cryptography.hazmat.primitives.hashes")? .getattr(crate::intern!(py, "HashAlgorithm"))? .extract()?; - if !hash_algorithm_type.is_instance(hash_algorithm)? { + if !hash_algorithm.is_instance(hash_algorithm_type)? { return Err(pyo3::exceptions::PyTypeError::new_err( "Algorithm must be a registered hash algorithm.", )); @@ -106,7 +106,7 @@ fn identify_hash_type( "sha3-256" => Ok(HashType::Sha3_256), "sha3-384" => Ok(HashType::Sha3_384), "sha3-512" => Ok(HashType::Sha3_512), - name => Err(pyo3::PyErr::from_instance( + name => Err(pyo3::PyErr::from_value( py.import("cryptography.exceptions")?.call_method1( "UnsupportedAlgorithm", (format!( @@ -226,7 +226,7 @@ pub(crate) fn compute_signature_algorithm<'p>( (KeyType::Dsa, HashType::Sha3_224) | (KeyType::Dsa, HashType::Sha3_256) | (KeyType::Dsa, HashType::Sha3_384) - | (KeyType::Dsa, HashType::Sha3_512) => Err(pyo3::PyErr::from_instance( + | (KeyType::Dsa, HashType::Sha3_512) => Err(pyo3::PyErr::from_value( py.import("cryptography.exceptions")?.call_method1( "UnsupportedAlgorithm", ("SHA3 hashes are not supported with DSA keys",), @@ -354,15 +354,15 @@ pub(crate) fn identify_public_key_type( .getattr(crate::intern!(py, "Ed448PublicKey"))? .extract()?; - if rsa_key_type.is_instance(public_key)? { + if public_key.is_instance(rsa_key_type)? { Ok(KeyType::Rsa) - } else if dsa_key_type.is_instance(public_key)? { + } else if public_key.is_instance(dsa_key_type)? { Ok(KeyType::Dsa) - } else if ec_key_type.is_instance(public_key)? { + } else if public_key.is_instance(ec_key_type)? { Ok(KeyType::Ec) - } else if ed25519_key_type.is_instance(public_key)? { + } else if public_key.is_instance(ed25519_key_type)? { Ok(KeyType::Ed25519) - } else if ed448_key_type.is_instance(public_key)? { + } else if public_key.is_instance(ed448_key_type)? { Ok(KeyType::Ed448) } else { Err(pyo3::exceptions::PyTypeError::new_err( diff --git a/tests/hazmat/primitives/test_pkcs7.py b/tests/hazmat/primitives/test_pkcs7.py index 4e61c5ef55e8..172cf40bd6e4 100644 --- a/tests/hazmat/primitives/test_pkcs7.py +++ b/tests/hazmat/primitives/test_pkcs7.py @@ -807,7 +807,7 @@ def test_invalid_types(self): ) with pytest.raises(TypeError): pkcs7.serialize_certificates( - "not a list of certs", # type: ignore[arg-type] + object(), # type: ignore[arg-type] serialization.Encoding.PEM, ) From 3df3fc8987d72560fd6c8434e535f6f88fc6cb60 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 24 Mar 2023 17:46:25 -0400 Subject: [PATCH 015/316] Drop our own intern! macro in favor of pyo3's (#8596) --- src/rust/src/asn1.rs | 6 +- src/rust/src/backend/x25519.rs | 42 ++++++------ src/rust/src/error.rs | 2 +- src/rust/src/intern.rs | 44 ------------ src/rust/src/lib.rs | 1 - src/rust/src/oid.rs | 2 +- src/rust/src/pkcs7.rs | 28 ++++---- src/rust/src/x509/certificate.rs | 112 +++++++++++++++---------------- src/rust/src/x509/common.rs | 80 +++++++++++----------- src/rust/src/x509/crl.rs | 42 ++++++------ src/rust/src/x509/csr.rs | 22 +++--- src/rust/src/x509/extensions.rs | 86 +++++++++++------------- src/rust/src/x509/ocsp.rs | 6 +- src/rust/src/x509/ocsp_req.rs | 12 ++-- src/rust/src/x509/ocsp_resp.rs | 62 ++++++++--------- src/rust/src/x509/sct.rs | 10 +-- src/rust/src/x509/sign.rs | 32 ++++----- 17 files changed, 266 insertions(+), 323 deletions(-) delete mode 100644 src/rust/src/intern.rs diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 9d034ab77332..2cc9431bb5fd 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -103,11 +103,11 @@ pub(crate) fn encode_der_data<'p>( ) -> CryptographyResult<&'p pyo3::types::PyBytes> { let encoding_class = py .import("cryptography.hazmat.primitives.serialization")? - .getattr(crate::intern!(py, "Encoding"))?; + .getattr(pyo3::intern!(py, "Encoding"))?; - if encoding.is(encoding_class.getattr(crate::intern!(py, "DER"))?) { + if encoding.is(encoding_class.getattr(pyo3::intern!(py, "DER"))?) { Ok(pyo3::types::PyBytes::new(py, &data)) - } else if encoding.is(encoding_class.getattr(crate::intern!(py, "PEM"))?) { + } else if encoding.is(encoding_class.getattr(pyo3::intern!(py, "PEM"))?) { Ok(pyo3::types::PyBytes::new( py, &pem::encode_config( diff --git a/src/rust/src/backend/x25519.rs b/src/rust/src/backend/x25519.rs index 72649ec7bdc1..94af22636b00 100644 --- a/src/rust/src/backend/x25519.rs +++ b/src/rust/src/backend/x25519.rs @@ -106,16 +106,16 @@ impl X25519PrivateKey { ) -> CryptographyResult<&'p pyo3::types::PyBytes> { let serialization_mod = py.import("cryptography.hazmat.primitives.serialization")?; let encoding_class: &pyo3::types::PyType = serialization_mod - .getattr(crate::intern!(py, "Encoding"))? + .getattr(pyo3::intern!(py, "Encoding"))? .extract()?; let private_format_class: &pyo3::types::PyType = serialization_mod - .getattr(crate::intern!(py, "PrivateFormat"))? + .getattr(pyo3::intern!(py, "PrivateFormat"))? .extract()?; let no_encryption_class: &pyo3::types::PyType = serialization_mod - .getattr(crate::intern!(py, "NoEncryption"))? + .getattr(pyo3::intern!(py, "NoEncryption"))? .extract()?; let best_available_encryption_class: &pyo3::types::PyType = serialization_mod - .getattr(crate::intern!(py, "BestAvailableEncryption"))? + .getattr(pyo3::intern!(py, "BestAvailableEncryption"))? .extract()?; if !encoding.is_instance(encoding_class)? { @@ -133,11 +133,11 @@ impl X25519PrivateKey { )); } - if encoding.is(encoding_class.getattr(crate::intern!(py, "Raw"))?) - || format.is(private_format_class.getattr(crate::intern!(py, "Raw"))?) + if encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) + || format.is(private_format_class.getattr(pyo3::intern!(py, "Raw"))?) { - if !encoding.is(encoding_class.getattr(crate::intern!(py, "Raw"))?) - || !format.is(private_format_class.getattr(crate::intern!(py, "Raw"))?) + if !encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) + || !format.is(private_format_class.getattr(pyo3::intern!(py, "Raw"))?) || !encryption_algorithm.is_instance(no_encryption_class)? { return Err(CryptographyError::from(pyo3::exceptions::PyValueError::new_err( @@ -152,7 +152,7 @@ impl X25519PrivateKey { b"" } else if encryption_algorithm.is_instance(best_available_encryption_class)? { encryption_algorithm - .getattr(crate::intern!(py, "password"))? + .getattr(pyo3::intern!(py, "password"))? .extract::<&[u8]>()? } else { return Err(CryptographyError::from( @@ -170,8 +170,8 @@ impl X25519PrivateKey { )); } - if format.is(private_format_class.getattr(crate::intern!(py, "PKCS8"))?) { - if encoding.is(encoding_class.getattr(crate::intern!(py, "PEM"))?) { + if format.is(private_format_class.getattr(pyo3::intern!(py, "PKCS8"))?) { + if encoding.is(encoding_class.getattr(pyo3::intern!(py, "PEM"))?) { let pem_bytes = if password.is_empty() { self.pkey.private_key_to_pem_pkcs8()? } else { @@ -181,7 +181,7 @@ impl X25519PrivateKey { )? }; return Ok(pyo3::types::PyBytes::new(py, &pem_bytes)); - } else if encoding.is(encoding_class.getattr(crate::intern!(py, "DER"))?) { + } else if encoding.is(encoding_class.getattr(pyo3::intern!(py, "DER"))?) { let der_bytes = if password.is_empty() { self.pkey.private_key_to_pkcs8()? } else { @@ -222,10 +222,10 @@ impl X25519PublicKey { ) -> CryptographyResult<&'p pyo3::types::PyBytes> { let serialization_mod = py.import("cryptography.hazmat.primitives.serialization")?; let encoding_class: &pyo3::types::PyType = serialization_mod - .getattr(crate::intern!(py, "Encoding"))? + .getattr(pyo3::intern!(py, "Encoding"))? .extract()?; let public_format_class: &pyo3::types::PyType = serialization_mod - .getattr(crate::intern!(py, "PublicFormat"))? + .getattr(pyo3::intern!(py, "PublicFormat"))? .extract()?; if !encoding.is_instance(encoding_class)? { @@ -243,11 +243,11 @@ impl X25519PublicKey { )); } - if encoding.is(encoding_class.getattr(crate::intern!(py, "Raw"))?) - || format.is(public_format_class.getattr(crate::intern!(py, "Raw"))?) + if encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) + || format.is(public_format_class.getattr(pyo3::intern!(py, "Raw"))?) { - if !encoding.is(encoding_class.getattr(crate::intern!(py, "Raw"))?) - || !format.is(public_format_class.getattr(crate::intern!(py, "Raw"))?) + if !encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) + || !format.is(public_format_class.getattr(pyo3::intern!(py, "Raw"))?) { return Err(CryptographyError::from( pyo3::exceptions::PyValueError::new_err( @@ -260,11 +260,11 @@ impl X25519PublicKey { } // SubjectPublicKeyInfo + PEM/DER - if format.is(public_format_class.getattr(crate::intern!(py, "SubjectPublicKeyInfo"))?) { - if encoding.is(encoding_class.getattr(crate::intern!(py, "PEM"))?) { + if format.is(public_format_class.getattr(pyo3::intern!(py, "SubjectPublicKeyInfo"))?) { + if encoding.is(encoding_class.getattr(pyo3::intern!(py, "PEM"))?) { let pem_bytes = self.pkey.public_key_to_pem()?; return Ok(pyo3::types::PyBytes::new(py, &pem_bytes)); - } else if encoding.is(encoding_class.getattr(crate::intern!(py, "DER"))?) { + } else if encoding.is(encoding_class.getattr(pyo3::intern!(py, "DER"))?) { let der_bytes = self.pkey.public_key_to_der()?; return Ok(pyo3::types::PyBytes::new(py, &der_bytes)); } else { diff --git a/src/rust/src/error.rs b/src/rust/src/error.rs index 35713bbab75a..1cabbb11a948 100644 --- a/src/rust/src/error.rs +++ b/src/rust/src/error.rs @@ -66,7 +66,7 @@ impl From for pyo3::PyErr { let internal_error = py .import("cryptography.exceptions") .expect("Failed to import cryptography module") - .getattr(crate::intern!(py, "InternalError")) + .getattr(pyo3::intern!(py, "InternalError")) .expect("Failed to get InternalError attribute"); let errors = pyo3::types::PyList::empty(py); diff --git a/src/rust/src/intern.rs b/src/rust/src/intern.rs deleted file mode 100644 index 94f2118334e6..000000000000 --- a/src/rust/src/intern.rs +++ /dev/null @@ -1,44 +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. - -// This file is a backport of `pyo3::intern!` from pyo3 0.16. - -#[macro_export] -macro_rules! intern { - ($py: expr, $text: expr) => {{ - static INTERNED: $crate::intern::Interned = $crate::intern::Interned::new($text); - INTERNED.get($py) - }}; -} - -#[doc(hidden)] -pub struct Interned( - &'static str, - pyo3::once_cell::GILOnceCell>, -); - -impl Interned { - pub const fn new(value: &'static str) -> Self { - Interned(value, pyo3::once_cell::GILOnceCell::new()) - } - - #[inline] - pub fn get<'py>(&'py self, py: pyo3::Python<'py>) -> &'py pyo3::types::PyString { - self.1 - .get_or_init(py, || pyo3::types::PyString::new(py, self.0).into()) - .as_ref(py) - } -} - -#[cfg(test)] -mod tests { - use super::Interned; - - #[test] - fn test_interned_new() { - for s in ["abc", "123"] { - Interned::new(s); - } - } -} diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index dae286cc0d56..d7dbbba6067d 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -13,7 +13,6 @@ mod asn1; mod backend; mod buf; mod error; -mod intern; pub(crate) mod oid; mod pkcs7; mod pool; diff --git a/src/rust/src/oid.rs b/src/rust/src/oid.rs index 43d26802aaed..1c12f775a621 100644 --- a/src/rust/src/oid.rs +++ b/src/rust/src/oid.rs @@ -32,7 +32,7 @@ impl ObjectIdentifier { ) -> pyo3::PyResult<&'p pyo3::PyAny> { let oid_names = py .import("cryptography.hazmat._oid")? - .getattr(crate::intern!(py, "_OID_NAMES"))?; + .getattr(pyo3::intern!(py, "_OID_NAMES"))?; oid_names.call_method1("get", (slf, "Unknown OID")) } diff --git a/src/rust/src/pkcs7.rs b/src/rust/src/pkcs7.rs index 53e479e5b3e2..4904dd8cc250 100644 --- a/src/rust/src/pkcs7.rs +++ b/src/rust/src/pkcs7.rs @@ -134,12 +134,12 @@ fn sign_and_serialize<'p>( ) -> CryptographyResult<&'p pyo3::types::PyBytes> { let pkcs7_options = py .import("cryptography.hazmat.primitives.serialization.pkcs7")? - .getattr(crate::intern!(py, "PKCS7Options"))?; + .getattr(pyo3::intern!(py, "PKCS7Options"))?; - let raw_data: CffiBuf<'p> = builder.getattr(crate::intern!(py, "_data"))?.extract()?; - let text_mode = options.contains(pkcs7_options.getattr(crate::intern!(py, "Text"))?)?; + let raw_data: CffiBuf<'p> = builder.getattr(pyo3::intern!(py, "_data"))?.extract()?; + let text_mode = options.contains(pkcs7_options.getattr(pyo3::intern!(py, "Text"))?)?; let (data_with_header, data_without_header) = - if options.contains(pkcs7_options.getattr(crate::intern!(py, "Binary"))?)? { + if options.contains(pkcs7_options.getattr(pyo3::intern!(py, "Binary"))?)? { ( Cow::Borrowed(raw_data.as_bytes()), Cow::Borrowed(raw_data.as_bytes()), @@ -165,10 +165,10 @@ fn sign_and_serialize<'p>( pyo3::PyRef<'p, x509::Certificate>, &pyo3::PyAny, &pyo3::PyAny, - )> = builder.getattr(crate::intern!(py, "_signers"))?.extract()?; + )> = builder.getattr(pyo3::intern!(py, "_signers"))?.extract()?; let py_certs: Vec> = builder - .getattr(crate::intern!(py, "_additional_certs"))? + .getattr(pyo3::intern!(py, "_additional_certs"))? .extract()?; let mut signer_infos = vec![]; @@ -179,7 +179,7 @@ fn sign_and_serialize<'p>( .collect::>(); for (cert, py_private_key, py_hash_alg) in &py_signers { let (authenticated_attrs, signature) = if options - .contains(pkcs7_options.getattr(crate::intern!(py, "NoAttributes"))?)? + .contains(pkcs7_options.getattr(pyo3::intern!(py, "NoAttributes"))?)? { ( None, @@ -212,7 +212,7 @@ fn sign_and_serialize<'p>( ])), }); - if !options.contains(pkcs7_options.getattr(crate::intern!(py, "NoCapabilities"))?)? { + if !options.contains(pkcs7_options.getattr(pyo3::intern!(py, "NoCapabilities"))?)? { authenticated_attrs.push(x509::csr::Attribute { type_id: PKCS7_SMIME_CAP_OID, values: x509::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ @@ -234,7 +234,7 @@ fn sign_and_serialize<'p>( let digest_alg = x509::AlgorithmIdentifier { oid: x509::ocsp::HASH_NAME_TO_OIDS[py_hash_alg - .getattr(crate::intern!(py, "name"))? + .getattr(pyo3::intern!(py, "name"))? .extract::<&str>()?] .clone(), params: Some(*x509::sign::NULL_TLV), @@ -265,7 +265,7 @@ fn sign_and_serialize<'p>( let data_tlv_bytes; let content = - if options.contains(pkcs7_options.getattr(crate::intern!(py, "DetachedSignature"))?)? { + if options.contains(pkcs7_options.getattr(pyo3::intern!(py, "DetachedSignature"))?)? { None } else { data_tlv_bytes = asn1::write_single(&data_with_header.deref())?; @@ -279,7 +279,7 @@ fn sign_and_serialize<'p>( _content_type: asn1::DefinedByMarker::marker(), content: Content::Data(content.map(asn1::Explicit::new)), }, - certificates: if options.contains(pkcs7_options.getattr(crate::intern!(py, "NoCerts"))?)? { + certificates: if options.contains(pkcs7_options.getattr(pyo3::intern!(py, "NoCerts"))?)? { None } else { Some(asn1::SetOfWriter::new(&certs)) @@ -296,9 +296,9 @@ fn sign_and_serialize<'p>( let encoding_class = py .import("cryptography.hazmat.primitives.serialization")? - .getattr(crate::intern!(py, "Encoding"))?; + .getattr(pyo3::intern!(py, "Encoding"))?; - if encoding.is(encoding_class.getattr(crate::intern!(py, "SMIME"))?) { + if encoding.is(encoding_class.getattr(pyo3::intern!(py, "SMIME"))?) { let mic_algs = digest_algs .iter() .map(|d| OIDS_TO_MIC_NAME[&d.oid]) @@ -306,7 +306,7 @@ fn sign_and_serialize<'p>( .join(","); let smime_encode = py .import("cryptography.hazmat.primitives.serialization.pkcs7")? - .getattr(crate::intern!(py, "_smime_encode"))?; + .getattr(pyo3::intern!(py, "_smime_encode"))?; Ok(smime_encode .call1((&*data_without_header, &*ci_bytes, mic_algs, text_mode))? .extract()?) diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 2e0378ff9d40..219698fa54d5 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -123,7 +123,7 @@ impl Certificate { ); Ok(py .import("cryptography.hazmat.primitives.serialization")? - .getattr(crate::intern!(py, "load_der_public_key"))? + .getattr(pyo3::intern!(py, "load_der_public_key"))? .call1((serialized,))?) } @@ -134,7 +134,7 @@ impl Certificate { ) -> CryptographyResult<&'p pyo3::PyAny> { let hasher = py .import("cryptography.hazmat.primitives.hashes")? - .getattr(crate::intern!(py, "Hash"))? + .getattr(pyo3::intern!(py, "Hash"))? .call1((algorithm,))?; // This makes an unnecessary copy. It'd be nice to get rid of it. let serialized = @@ -267,7 +267,7 @@ impl Certificate { ) -> Result<&'p pyo3::PyAny, CryptographyError> { let sig_oids_to_hash = py .import("cryptography.hazmat._oid")? - .getattr(crate::intern!(py, "_SIG_OIDS_TO_HASH"))?; + .getattr(pyo3::intern!(py, "_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), @@ -300,7 +300,7 @@ impl Certificate { asn1::parse_single::<()>(ext_data)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "PrecertPoison"))? + .getattr(pyo3::intern!(py, "PrecertPoison"))? .call0()?, )) } @@ -309,7 +309,7 @@ impl Certificate { let scts = sct::parse_scts(py, contents, sct::LogEntryType::PreCertificate)?; Ok(Some( x509_module - .getattr(crate::intern!( + .getattr(pyo3::intern!( py, "PrecertificateSignedCertificateTimestamps" ))? @@ -352,14 +352,14 @@ fn cert_version(py: pyo3::Python<'_>, version: u8) -> Result<&pyo3::PyAny, Crypt let x509_module = py.import("cryptography.x509")?; match version { 0 => Ok(x509_module - .getattr(crate::intern!(py, "Version"))? - .get_item(crate::intern!(py, "v1"))?), + .getattr(pyo3::intern!(py, "Version"))? + .get_item(pyo3::intern!(py, "v1"))?), 2 => Ok(x509_module - .getattr(crate::intern!(py, "Version"))? - .get_item(crate::intern!(py, "v3"))?), + .getattr(pyo3::intern!(py, "Version"))? + .get_item(pyo3::intern!(py, "v3"))?), _ => Err(CryptographyError::from(pyo3::PyErr::from_value( x509_module - .getattr(crate::intern!(py, "InvalidVersion"))? + .getattr(pyo3::intern!(py, "InvalidVersion"))? .call1((format!("{} is not a valid X509 version", version), version))?, ))), } @@ -414,7 +414,7 @@ fn warn_if_negative_serial(py: pyo3::Python<'_>, bytes: &'_ [u8]) -> pyo3::PyRes if bytes[0] & 0x80 != 0 { let cryptography_warning = py .import("cryptography.utils")? - .getattr(crate::intern!(py, "DeprecatedIn36"))?; + .getattr(pyo3::intern!(py, "DeprecatedIn36"))?; pyo3::PyErr::warn( py, cryptography_warning, @@ -684,7 +684,7 @@ fn parse_distribution_point( }; let x509_module = py.import("cryptography.x509")?; Ok(x509_module - .getattr(crate::intern!(py, "DistributionPoint"))? + .getattr(pyo3::intern!(py, "DistributionPoint"))? .call1((full_name, relative_name, reasons, crl_issuer))? .to_object(py)) } @@ -708,7 +708,7 @@ pub(crate) fn parse_distribution_point_reasons( ) -> Result { let reason_bit_mapping = py .import("cryptography.x509.extensions")? - .getattr(crate::intern!(py, "_REASON_BIT_MAPPING"))?; + .getattr(pyo3::intern!(py, "_REASON_BIT_MAPPING"))?; Ok(match reasons { Some(bs) => { let mut vec = Vec::new(); @@ -729,7 +729,7 @@ pub(crate) fn encode_distribution_point_reasons( ) -> pyo3::PyResult { let reason_flag_mapping = py .import("cryptography.x509.extensions")? - .getattr(crate::intern!(py, "_CRLREASONFLAGS"))?; + .getattr(pyo3::intern!(py, "_CRLREASONFLAGS"))?; let mut bits = vec![0, 0]; for py_reason in py_reasons.iter()? { @@ -775,7 +775,7 @@ pub(crate) fn parse_authority_key_identifier<'p>( None => py.None(), }; Ok(x509_module - .getattr(crate::intern!(py, "AuthorityKeyIdentifier"))? + .getattr(pyo3::intern!(py, "AuthorityKeyIdentifier"))? .call1((aki.key_identifier, issuer, serial))?) } @@ -790,7 +790,7 @@ pub(crate) fn parse_access_descriptions( let py_oid = oid_to_py_oid(py, &access.access_method)?.to_object(py); let gn = x509::parse_general_name(py, access.access_location)?; let ad = x509_module - .getattr(crate::intern!(py, "AccessDescription"))? + .getattr(pyo3::intern!(py, "AccessDescription"))? .call1((py_oid, gn))? .to_object(py); ads.append(ad)?; @@ -811,7 +811,7 @@ pub fn parse_cert_ext<'p>( let sans = x509::parse_general_names(py, &gn_seq)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "SubjectAlternativeName"))? + .getattr(pyo3::intern!(py, "SubjectAlternativeName"))? .call1((sans,))?, )) } @@ -821,14 +821,14 @@ pub fn parse_cert_ext<'p>( let ians = x509::parse_general_names(py, &gn_seq)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "IssuerAlternativeName"))? + .getattr(pyo3::intern!(py, "IssuerAlternativeName"))? .call1((ians,))?, )) } oid::TLS_FEATURE_OID => { let tls_feature_type_to_enum = py .import("cryptography.x509.extensions")? - .getattr(crate::intern!(py, "_TLS_FEATURE_TYPE_TO_ENUM"))?; + .getattr(pyo3::intern!(py, "_TLS_FEATURE_TYPE_TO_ENUM"))?; let features = pyo3::types::PyList::empty(py); for feature in asn1::parse_single::>(ext_data)? { @@ -837,7 +837,7 @@ pub fn parse_cert_ext<'p>( } Ok(Some( x509_module - .getattr(crate::intern!(py, "TLSFeature"))? + .getattr(pyo3::intern!(py, "TLSFeature"))? .call1((features,))?, )) } @@ -845,7 +845,7 @@ pub fn parse_cert_ext<'p>( let identifier = asn1::parse_single::<&[u8]>(ext_data)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "SubjectKeyIdentifier"))? + .getattr(pyo3::intern!(py, "SubjectKeyIdentifier"))? .call1((identifier,))?, )) } @@ -858,7 +858,7 @@ pub fn parse_cert_ext<'p>( } Ok(Some( x509_module - .getattr(crate::intern!(py, "ExtendedKeyUsage"))? + .getattr(pyo3::intern!(py, "ExtendedKeyUsage"))? .call1((ekus,))?, )) } @@ -874,26 +874,24 @@ pub fn parse_cert_ext<'p>( let encipher_only = kus.has_bit_set(7); let decipher_only = kus.has_bit_set(8); Ok(Some( - x509_module - .getattr(crate::intern!(py, "KeyUsage"))? - .call1(( - digital_signature, - content_comitment, - key_encipherment, - data_encipherment, - key_agreement, - key_cert_sign, - crl_sign, - encipher_only, - decipher_only, - ))?, + x509_module.getattr(pyo3::intern!(py, "KeyUsage"))?.call1(( + digital_signature, + content_comitment, + key_encipherment, + data_encipherment, + key_agreement, + key_cert_sign, + crl_sign, + encipher_only, + decipher_only, + ))?, )) } oid::AUTHORITY_INFORMATION_ACCESS_OID => { let ads = parse_access_descriptions(py, ext_data)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "AuthorityInformationAccess"))? + .getattr(pyo3::intern!(py, "AuthorityInformationAccess"))? .call1((ads,))?, )) } @@ -901,7 +899,7 @@ pub fn parse_cert_ext<'p>( let ads = parse_access_descriptions(py, ext_data)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "SubjectInformationAccess"))? + .getattr(pyo3::intern!(py, "SubjectInformationAccess"))? .call1((ads,))?, )) } @@ -915,7 +913,7 @@ pub fn parse_cert_ext<'p>( let pc = asn1::parse_single::(ext_data)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "PolicyConstraints"))? + .getattr(pyo3::intern!(py, "PolicyConstraints"))? .call1((pc.require_explicit_policy, pc.inhibit_policy_mapping))?, )) } @@ -923,7 +921,7 @@ pub fn parse_cert_ext<'p>( asn1::parse_single::<()>(ext_data)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "OCSPNoCheck"))? + .getattr(pyo3::intern!(py, "OCSPNoCheck"))? .call0()?, )) } @@ -932,7 +930,7 @@ pub fn parse_cert_ext<'p>( let pynum = big_byte_slice_to_py_int(py, bignum.as_bytes())?; Ok(Some( x509_module - .getattr(crate::intern!(py, "InhibitAnyPolicy"))? + .getattr(pyo3::intern!(py, "InhibitAnyPolicy"))? .call1((pynum,))?, )) } @@ -940,7 +938,7 @@ pub fn parse_cert_ext<'p>( let bc = asn1::parse_single::(ext_data)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "BasicConstraints"))? + .getattr(pyo3::intern!(py, "BasicConstraints"))? .call1((bc.ca, bc.path_length))?, )) } @@ -951,7 +949,7 @@ pub fn parse_cert_ext<'p>( let dp = parse_distribution_points(py, ext_data)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "CRLDistributionPoints"))? + .getattr(pyo3::intern!(py, "CRLDistributionPoints"))? .call1((dp,))?, )) } @@ -959,7 +957,7 @@ pub fn parse_cert_ext<'p>( let dp = parse_distribution_points(py, ext_data)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "FreshestCRL"))? + .getattr(pyo3::intern!(py, "FreshestCRL"))? .call1((dp,))?, )) } @@ -975,7 +973,7 @@ pub fn parse_cert_ext<'p>( }; Ok(Some( x509_module - .getattr(crate::intern!(py, "NameConstraints"))? + .getattr(pyo3::intern!(py, "NameConstraints"))? .call1((permitted_subtrees, excluded_subtrees))?, )) } @@ -1011,30 +1009,30 @@ fn create_x509_certificate( let sigalg = x509::sign::compute_signature_algorithm(py, private_key, hash_algorithm)?; let serialization_mod = py.import("cryptography.hazmat.primitives.serialization")?; let der_encoding = serialization_mod - .getattr(crate::intern!(py, "Encoding"))? - .getattr(crate::intern!(py, "DER"))?; + .getattr(pyo3::intern!(py, "Encoding"))? + .getattr(pyo3::intern!(py, "DER"))?; let spki_format = serialization_mod - .getattr(crate::intern!(py, "PublicFormat"))? - .getattr(crate::intern!(py, "SubjectPublicKeyInfo"))?; + .getattr(pyo3::intern!(py, "PublicFormat"))? + .getattr(pyo3::intern!(py, "SubjectPublicKeyInfo"))?; let spki_bytes = builder - .getattr(crate::intern!(py, "_public_key"))? + .getattr(pyo3::intern!(py, "_public_key"))? .call_method1("public_bytes", (der_encoding, spki_format))? .extract::<&[u8]>()?; let py_serial = builder - .getattr(crate::intern!(py, "_serial_number"))? + .getattr(pyo3::intern!(py, "_serial_number"))? .extract()?; - let py_issuer_name = builder.getattr(crate::intern!(py, "_issuer_name"))?; - let py_subject_name = builder.getattr(crate::intern!(py, "_subject_name"))?; - let py_not_before = builder.getattr(crate::intern!(py, "_not_valid_before"))?; - let py_not_after = builder.getattr(crate::intern!(py, "_not_valid_after"))?; + let py_issuer_name = builder.getattr(pyo3::intern!(py, "_issuer_name"))?; + let py_subject_name = builder.getattr(pyo3::intern!(py, "_subject_name"))?; + let py_not_before = builder.getattr(pyo3::intern!(py, "_not_valid_before"))?; + let py_not_after = builder.getattr(pyo3::intern!(py, "_not_valid_after"))?; let tbs_cert = TbsCertificate { version: builder - .getattr(crate::intern!(py, "_version"))? - .getattr(crate::intern!(py, "value"))? + .getattr(pyo3::intern!(py, "_version"))? + .getattr(pyo3::intern!(py, "value"))? .extract()?, serial: asn1::BigInt::new(py_uint_to_big_endian_bytes(py, py_serial)?).unwrap(), signature_alg: sigalg.clone(), @@ -1049,7 +1047,7 @@ fn create_x509_certificate( subject_unique_id: None, extensions: x509::common::encode_extensions( py, - builder.getattr(crate::intern!(py, "_extensions"))?, + builder.getattr(pyo3::intern!(py, "_extensions"))?, extensions::encode_extension, )?, }; diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index 59710a3aed17..a5f642e0d1ef 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -86,7 +86,7 @@ pub(crate) fn encode_name<'p>( ) -> pyo3::PyResult> { let mut rdns = vec![]; - for py_rdn in py_name.getattr(crate::intern!(py, "rdns"))?.iter()? { + for py_rdn in py_name.getattr(pyo3::intern!(py, "rdns"))?.iter()? { let py_rdn = py_rdn?; let mut attrs = vec![]; @@ -106,30 +106,30 @@ pub(crate) fn encode_name_entry<'p>( ) -> CryptographyResult> { let asn1_type = py .import("cryptography.x509.name")? - .getattr(crate::intern!(py, "_ASN1Type"))?; + .getattr(pyo3::intern!(py, "_ASN1Type"))?; - let attr_type = py_name_entry.getattr(crate::intern!(py, "_type"))?; + let attr_type = py_name_entry.getattr(pyo3::intern!(py, "_type"))?; let tag = attr_type - .getattr(crate::intern!(py, "value"))? + .getattr(pyo3::intern!(py, "value"))? .extract::()?; - let value: &[u8] = if !attr_type.is(asn1_type.getattr(crate::intern!(py, "BitString"))?) { - let encoding = if attr_type.is(asn1_type.getattr(crate::intern!(py, "BMPString"))?) { + let value: &[u8] = if !attr_type.is(asn1_type.getattr(pyo3::intern!(py, "BitString"))?) { + let encoding = if attr_type.is(asn1_type.getattr(pyo3::intern!(py, "BMPString"))?) { "utf_16_be" - } else if attr_type.is(asn1_type.getattr(crate::intern!(py, "UniversalString"))?) { + } else if attr_type.is(asn1_type.getattr(pyo3::intern!(py, "UniversalString"))?) { "utf_32_be" } else { "utf8" }; py_name_entry - .getattr(crate::intern!(py, "value"))? + .getattr(pyo3::intern!(py, "value"))? .call_method1("encode", (encoding,))? .extract()? } else { py_name_entry - .getattr(crate::intern!(py, "value"))? + .getattr(pyo3::intern!(py, "value"))? .extract()? }; - let oid = py_oid_to_oid(py_name_entry.getattr(crate::intern!(py, "oid"))?)?; + let oid = py_oid_to_oid(py_name_entry.getattr(pyo3::intern!(py, "oid"))?)?; Ok(AttributeTypeValue { type_id: oid, @@ -232,21 +232,21 @@ pub(crate) fn encode_general_name<'a>( ) -> Result, CryptographyError> { let gn_module = py.import("cryptography.x509.general_name")?; let gn_type = gn.get_type().as_ref(); - let gn_value = gn.getattr(crate::intern!(py, "value"))?; - if gn_type.is(gn_module.getattr(crate::intern!(py, "DNSName"))?) { + let gn_value = gn.getattr(pyo3::intern!(py, "value"))?; + if gn_type.is(gn_module.getattr(pyo3::intern!(py, "DNSName"))?) { Ok(GeneralName::DNSName(UnvalidatedIA5String( gn_value.extract::<&str>()?, ))) - } else if gn_type.is(gn_module.getattr(crate::intern!(py, "RFC822Name"))?) { + } else if gn_type.is(gn_module.getattr(pyo3::intern!(py, "RFC822Name"))?) { Ok(GeneralName::RFC822Name(UnvalidatedIA5String( gn_value.extract::<&str>()?, ))) - } else if gn_type.is(gn_module.getattr(crate::intern!(py, "DirectoryName"))?) { + } else if gn_type.is(gn_module.getattr(pyo3::intern!(py, "DirectoryName"))?) { let name = encode_name(py, gn_value)?; Ok(GeneralName::DirectoryName(name)) - } else if gn_type.is(gn_module.getattr(crate::intern!(py, "OtherName"))?) { + } else if gn_type.is(gn_module.getattr(pyo3::intern!(py, "OtherName"))?) { Ok(GeneralName::OtherName(OtherName { - type_id: py_oid_to_oid(gn.getattr(crate::intern!(py, "type_id"))?)?, + type_id: py_oid_to_oid(gn.getattr(pyo3::intern!(py, "type_id"))?)?, value: asn1::parse_single(gn_value.extract::<&[u8]>()?).map_err(|e| { pyo3::exceptions::PyValueError::new_err(format!( "OtherName value must be valid DER: {:?}", @@ -254,15 +254,15 @@ pub(crate) fn encode_general_name<'a>( )) })?, })) - } else if gn_type.is(gn_module.getattr(crate::intern!(py, "UniformResourceIdentifier"))?) { + } else if gn_type.is(gn_module.getattr(pyo3::intern!(py, "UniformResourceIdentifier"))?) { Ok(GeneralName::UniformResourceIdentifier( UnvalidatedIA5String(gn_value.extract::<&str>()?), )) - } else if gn_type.is(gn_module.getattr(crate::intern!(py, "IPAddress"))?) { + } else if gn_type.is(gn_module.getattr(pyo3::intern!(py, "IPAddress"))?) { Ok(GeneralName::IPAddress( gn.call_method0("_packed")?.extract::<&[u8]>()?, )) - } else if gn_type.is(gn_module.getattr(crate::intern!(py, "RegisteredID"))?) { + } else if gn_type.is(gn_module.getattr(pyo3::intern!(py, "RegisteredID"))?) { let oid = py_oid_to_oid(gn_value)?; Ok(GeneralName::RegisteredID(oid)) } else { @@ -291,9 +291,9 @@ pub(crate) fn encode_access_descriptions<'a>( let mut ads = vec![]; for py_ad in py_ads.iter()? { let py_ad = py_ad?; - let access_method = py_oid_to_oid(py_ad.getattr(crate::intern!(py, "access_method"))?)?; + let access_method = py_oid_to_oid(py_ad.getattr(pyo3::intern!(py, "access_method"))?)?; let access_location = - encode_general_name(py, py_ad.getattr(crate::intern!(py, "access_location"))?)?; + encode_general_name(py, py_ad.getattr(pyo3::intern!(py, "access_location"))?)?; ads.push(AccessDescription { access_method, access_location, @@ -360,7 +360,7 @@ fn parse_name_attribute( let oid = oid_to_py_oid(py, &attribute.type_id)?.to_object(py); let tag_enum = py .import("cryptography.x509.name")? - .getattr(crate::intern!(py, "_ASN1_TYPE_TO_ENUM"))?; + .getattr(pyo3::intern!(py, "_ASN1_TYPE_TO_ENUM"))?; let tag_val = attribute .value .tag() @@ -425,11 +425,11 @@ pub(crate) fn parse_general_name( .to_object(py) } GeneralName::RFC822Name(data) => x509_module - .getattr(crate::intern!(py, "RFC822Name"))? + .getattr(pyo3::intern!(py, "RFC822Name"))? .call_method1("_init_without_validation", (data.0,))? .to_object(py), GeneralName::DNSName(data) => x509_module - .getattr(crate::intern!(py, "DNSName"))? + .getattr(pyo3::intern!(py, "DNSName"))? .call_method1("_init_without_validation", (data.0,))? .to_object(py), GeneralName::DirectoryName(data) => { @@ -439,7 +439,7 @@ pub(crate) fn parse_general_name( .to_object(py) } GeneralName::UniformResourceIdentifier(data) => x509_module - .getattr(crate::intern!(py, "UniformResourceIdentifier"))? + .getattr(pyo3::intern!(py, "UniformResourceIdentifier"))? .call_method1("_init_without_validation", (data.0,))? .to_object(py), GeneralName::IPAddress(data) => { @@ -510,7 +510,7 @@ fn create_ip_network( )?; let net = format!( "{}/{}", - base.getattr(crate::intern!(py, "exploded"))? + base.getattr(pyo3::intern!(py, "exploded"))? .extract::<&str>()?, prefix? ); @@ -604,21 +604,21 @@ pub(crate) fn encode_extensions< ) -> pyo3::PyResult>> { let unrecognized_extension_type: &pyo3::types::PyType = py .import("cryptography.x509")? - .getattr(crate::intern!(py, "UnrecognizedExtension"))? + .getattr(pyo3::intern!(py, "UnrecognizedExtension"))? .extract()?; let mut exts = vec![]; for py_ext in py_exts.iter()? { let py_ext = py_ext?; - let oid = py_oid_to_oid(py_ext.getattr(crate::intern!(py, "oid"))?)?; + let oid = py_oid_to_oid(py_ext.getattr(pyo3::intern!(py, "oid"))?)?; - let ext_val = py_ext.getattr(crate::intern!(py, "value"))?; + let ext_val = py_ext.getattr(pyo3::intern!(py, "value"))?; if ext_val.is_instance(unrecognized_extension_type)? { exts.push(Extension { extn_id: oid, - critical: py_ext.getattr(crate::intern!(py, "critical"))?.extract()?, + critical: py_ext.getattr(pyo3::intern!(py, "critical"))?.extract()?, extn_value: ext_val - .getattr(crate::intern!(py, "value"))? + .getattr(pyo3::intern!(py, "value"))? .extract::<&[u8]>()?, }); continue; @@ -629,7 +629,7 @@ pub(crate) fn encode_extensions< let py_data = pyo3::types::PyBytes::new(py, &data); exts.push(Extension { extn_id: oid, - critical: py_ext.getattr(crate::intern!(py, "critical"))?.extract()?, + critical: py_ext.getattr(pyo3::intern!(py, "critical"))?.extract()?, extn_value: py_data.as_bytes(), }) } @@ -654,7 +654,7 @@ fn encode_extension_value<'p>( py: pyo3::Python<'p>, py_ext: &'p pyo3::PyAny, ) -> pyo3::PyResult<&'p pyo3::types::PyBytes> { - let oid = py_oid_to_oid(py_ext.getattr(crate::intern!(py, "oid"))?)?; + let oid = py_oid_to_oid(py_ext.getattr(pyo3::intern!(py, "oid"))?)?; if let Some(data) = x509::extensions::encode_extension(py, &oid, py_ext)? { // TODO: extra copy @@ -674,7 +674,7 @@ pub(crate) fn chrono_to_py<'p>( ) -> pyo3::PyResult<&'p pyo3::PyAny> { let datetime_module = py.import("datetime")?; datetime_module - .getattr(crate::intern!(py, "datetime"))? + .getattr(pyo3::intern!(py, "datetime"))? .call1(( dt.year(), dt.month(), @@ -691,12 +691,12 @@ pub(crate) fn py_to_chrono( ) -> pyo3::PyResult> { Ok(chrono::Utc .with_ymd_and_hms( - val.getattr(crate::intern!(py, "year"))?.extract()?, - val.getattr(crate::intern!(py, "month"))?.extract()?, - val.getattr(crate::intern!(py, "day"))?.extract()?, - val.getattr(crate::intern!(py, "hour"))?.extract()?, - val.getattr(crate::intern!(py, "minute"))?.extract()?, - val.getattr(crate::intern!(py, "second"))?.extract()?, + val.getattr(pyo3::intern!(py, "year"))?.extract()?, + val.getattr(pyo3::intern!(py, "month"))?.extract()?, + val.getattr(pyo3::intern!(py, "day"))?.extract()?, + val.getattr(pyo3::intern!(py, "hour"))?.extract()?, + val.getattr(pyo3::intern!(py, "minute"))?.extract()?, + val.getattr(pyo3::intern!(py, "second"))?.extract()?, ) .unwrap()) } diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index 37a4902aea2b..5100c3afb6db 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -28,7 +28,7 @@ fn load_der_x509_crl( let x509_module = py.import("cryptography.x509")?; return Err(CryptographyError::from(pyo3::PyErr::from_value( x509_module - .getattr(crate::intern!(py, "InvalidVersion"))? + .getattr(pyo3::intern!(py, "InvalidVersion"))? .call1((format!("{} is not a valid CRL version", version), version))?, ))); } @@ -175,7 +175,7 @@ impl CertificateRevocationList { ) -> pyo3::PyResult<&'p pyo3::PyAny> { let hashes_mod = py.import("cryptography.hazmat.primitives.hashes")?; let h = hashes_mod - .getattr(crate::intern!(py, "Hash"))? + .getattr(pyo3::intern!(py, "Hash"))? .call1((algorithm,))?; h.call_method1("update", (self.public_bytes_der()?.as_slice(),))?; h.call_method0("finalize") @@ -195,7 +195,7 @@ impl CertificateRevocationList { let oid_module = py.import("cryptography.hazmat._oid")?; let exceptions_module = py.import("cryptography.exceptions")?; match oid_module - .getattr(crate::intern!(py, "_SIG_OIDS_TO_HASH"))? + .getattr(pyo3::intern!(py, "_SIG_OIDS_TO_HASH"))? .get_item(oid) { Ok(v) => Ok(v), @@ -274,7 +274,7 @@ impl CertificateRevocationList { let pynum = big_byte_slice_to_py_int(py, bignum.as_bytes())?; Ok(Some( x509_module - .getattr(crate::intern!(py, "CRLNumber"))? + .getattr(pyo3::intern!(py, "CRLNumber"))? .call1((pynum,))?, )) } @@ -283,7 +283,7 @@ impl CertificateRevocationList { let pynum = big_byte_slice_to_py_int(py, bignum.as_bytes())?; Ok(Some( x509_module - .getattr(crate::intern!(py, "DeltaCRLIndicator"))? + .getattr(pyo3::intern!(py, "DeltaCRLIndicator"))? .call1((pynum,))?, )) } @@ -294,7 +294,7 @@ impl CertificateRevocationList { let ians = x509::parse_general_names(py, &gn_seq)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "IssuerAlternativeName"))? + .getattr(pyo3::intern!(py, "IssuerAlternativeName"))? .call1((ians,))?, )) } @@ -302,7 +302,7 @@ impl CertificateRevocationList { let ads = certificate::parse_access_descriptions(py, ext_data)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "AuthorityInformationAccess"))? + .getattr(pyo3::intern!(py, "AuthorityInformationAccess"))? .call1((ads,))?, )) } @@ -325,7 +325,7 @@ impl CertificateRevocationList { }; Ok(Some( x509_module - .getattr(crate::intern!(py, "IssuingDistributionPoint"))? + .getattr(pyo3::intern!(py, "IssuingDistributionPoint"))? .call1(( full_name, relative_name, @@ -341,7 +341,7 @@ impl CertificateRevocationList { let dp = certificate::parse_distribution_points(py, ext_data)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "FreshestCRL"))? + .getattr(pyo3::intern!(py, "FreshestCRL"))? .call1((dp,))?, )) } @@ -600,7 +600,7 @@ pub(crate) fn parse_crl_reason_flags<'p>( } }; Ok(x509_module - .getattr(crate::intern!(py, "ReasonFlags"))? + .getattr(pyo3::intern!(py, "ReasonFlags"))? .getattr(flag_name)?) } @@ -615,7 +615,7 @@ pub fn parse_crl_entry_ext<'p>( let flags = parse_crl_reason_flags(py, &asn1::parse_single::(data)?)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "CRLReason"))? + .getattr(pyo3::intern!(py, "CRLReason"))? .call1((flags,))?, )) } @@ -624,7 +624,7 @@ pub fn parse_crl_entry_ext<'p>( let gns = x509::parse_general_names(py, &gn_seq)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "CertificateIssuer"))? + .getattr(pyo3::intern!(py, "CertificateIssuer"))? .call1((gns,))?, )) } @@ -633,7 +633,7 @@ pub fn parse_crl_entry_ext<'p>( let py_dt = x509::chrono_to_py(py, time.as_chrono())?; Ok(Some( x509_module - .getattr(crate::intern!(py, "InvalidityDate"))? + .getattr(pyo3::intern!(py, "InvalidityDate"))? .call1((py_dt,))?, )) } @@ -652,29 +652,29 @@ fn create_x509_crl( let mut revoked_certs = vec![]; for py_revoked_cert in builder - .getattr(crate::intern!(py, "_revoked_certificates"))? + .getattr(pyo3::intern!(py, "_revoked_certificates"))? .iter()? { let py_revoked_cert = py_revoked_cert?; let serial_number = py_revoked_cert - .getattr(crate::intern!(py, "serial_number"))? + .getattr(pyo3::intern!(py, "serial_number"))? .extract()?; - let py_revocation_date = py_revoked_cert.getattr(crate::intern!(py, "revocation_date"))?; + let py_revocation_date = py_revoked_cert.getattr(pyo3::intern!(py, "revocation_date"))?; revoked_certs.push(RawRevokedCertificate { user_certificate: asn1::BigUint::new(py_uint_to_big_endian_bytes(py, serial_number)?) .unwrap(), revocation_date: x509::certificate::time_from_py(py, py_revocation_date)?, crl_entry_extensions: x509::common::encode_extensions( py, - py_revoked_cert.getattr(crate::intern!(py, "extensions"))?, + py_revoked_cert.getattr(pyo3::intern!(py, "extensions"))?, extensions::encode_extension, )?, }); } - let py_issuer_name = builder.getattr(crate::intern!(py, "_issuer_name"))?; - let py_this_update = builder.getattr(crate::intern!(py, "_last_update"))?; - let py_next_update = builder.getattr(crate::intern!(py, "_next_update"))?; + let py_issuer_name = builder.getattr(pyo3::intern!(py, "_issuer_name"))?; + let py_this_update = builder.getattr(pyo3::intern!(py, "_last_update"))?; + let py_next_update = builder.getattr(pyo3::intern!(py, "_next_update"))?; let tbs_cert_list = TBSCertList { version: Some(1), signature: sigalg.clone(), @@ -690,7 +690,7 @@ fn create_x509_crl( }, crl_extensions: x509::common::encode_extensions( py, - builder.getattr(crate::intern!(py, "_extensions"))?, + builder.getattr(pyo3::intern!(py, "_extensions"))?, extensions::encode_extension, )?, }; diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index 8a7f533041c1..0a6c7cbd8fc1 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -114,7 +114,7 @@ impl CertificateSigningRequest { ); Ok(py .import("cryptography.hazmat.primitives.serialization")? - .getattr(crate::intern!(py, "load_der_public_key"))? + .getattr(pyo3::intern!(py, "load_der_public_key"))? .call1((serialized,))?) } @@ -147,7 +147,7 @@ impl CertificateSigningRequest { ) -> Result<&'p pyo3::PyAny, CryptographyError> { let sig_oids_to_hash = py .import("cryptography.hazmat._oid")? - .getattr(crate::intern!(py, "_SIG_OIDS_TO_HASH"))?; + .getattr(pyo3::intern!(py, "_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), @@ -185,7 +185,7 @@ impl CertificateSigningRequest { ) -> pyo3::PyResult<&'p pyo3::PyAny> { let cryptography_warning = py .import("cryptography.utils")? - .getattr(crate::intern!(py, "DeprecatedIn36"))?; + .getattr(pyo3::intern!(py, "DeprecatedIn36"))?; pyo3::PyErr::warn( py, cryptography_warning, @@ -308,7 +308,7 @@ fn load_der_x509_csr( let x509_module = py.import("cryptography.x509")?; return Err(CryptographyError::from(pyo3::PyErr::from_value( x509_module - .getattr(crate::intern!(py, "InvalidVersion"))? + .getattr(pyo3::intern!(py, "InvalidVersion"))? .call1((format!("{} is not a valid CSR version", version), version))?, ))); } @@ -329,11 +329,11 @@ fn create_x509_csr( let sigalg = x509::sign::compute_signature_algorithm(py, private_key, hash_algorithm)?; let serialization_mod = py.import("cryptography.hazmat.primitives.serialization")?; let der_encoding = serialization_mod - .getattr(crate::intern!(py, "Encoding"))? - .getattr(crate::intern!(py, "DER"))?; + .getattr(pyo3::intern!(py, "Encoding"))? + .getattr(pyo3::intern!(py, "DER"))?; let spki_format = serialization_mod - .getattr(crate::intern!(py, "PublicFormat"))? - .getattr(crate::intern!(py, "SubjectPublicKeyInfo"))?; + .getattr(pyo3::intern!(py, "PublicFormat"))? + .getattr(pyo3::intern!(py, "SubjectPublicKeyInfo"))?; let spki_bytes = private_key .call_method0("public_key")? @@ -344,7 +344,7 @@ fn create_x509_csr( let ext_bytes; if let Some(exts) = x509::common::encode_extensions( py, - builder.getattr(crate::intern!(py, "_extensions"))?, + builder.getattr(pyo3::intern!(py, "_extensions"))?, x509::extensions::encode_extension, )? { ext_bytes = asn1::write_single(&exts)?; @@ -356,7 +356,7 @@ fn create_x509_csr( }) } - for py_attr in builder.getattr(crate::intern!(py, "_attributes"))?.iter()? { + for py_attr in builder.getattr(pyo3::intern!(py, "_attributes"))?.iter()? { let (py_oid, value, tag): (&pyo3::PyAny, &[u8], Option) = py_attr?.extract()?; let oid = py_oid_to_oid(py_oid)?; let tag = if let Some(tag) = tag { @@ -380,7 +380,7 @@ fn create_x509_csr( }) } - let py_subject_name = builder.getattr(crate::intern!(py, "_subject_name"))?; + let py_subject_name = builder.getattr(pyo3::intern!(py, "_subject_name"))?; let csr_info = CertificationRequestInfo { version: 0, diff --git a/src/rust/src/x509/extensions.rs b/src/rust/src/x509/extensions.rs index 1af8d389de72..d5473a576735 100644 --- a/src/rust/src/x509/extensions.rs +++ b/src/rust/src/x509/extensions.rs @@ -129,7 +129,7 @@ pub(crate) fn encode_extension( } &oid::SUBJECT_KEY_IDENTIFIER_OID => { let digest = ext - .getattr(crate::intern!(py, "digest"))? + .getattr(pyo3::intern!(py, "digest"))? .extract::<&[u8]>()?; Ok(Some(asn1::write_single(&digest)?)) } @@ -138,59 +138,52 @@ pub(crate) fn encode_extension( certificate::set_bit( &mut bs, 0, - ext.getattr(crate::intern!(py, "digital_signature"))? + ext.getattr(pyo3::intern!(py, "digital_signature"))? .is_true()?, ); certificate::set_bit( &mut bs, 1, - ext.getattr(crate::intern!(py, "content_commitment"))? + ext.getattr(pyo3::intern!(py, "content_commitment"))? .is_true()?, ); certificate::set_bit( &mut bs, 2, - ext.getattr(crate::intern!(py, "key_encipherment"))? + ext.getattr(pyo3::intern!(py, "key_encipherment"))? .is_true()?, ); certificate::set_bit( &mut bs, 3, - ext.getattr(crate::intern!(py, "data_encipherment"))? + ext.getattr(pyo3::intern!(py, "data_encipherment"))? .is_true()?, ); certificate::set_bit( &mut bs, 4, - ext.getattr(crate::intern!(py, "key_agreement"))? - .is_true()?, + ext.getattr(pyo3::intern!(py, "key_agreement"))?.is_true()?, ); certificate::set_bit( &mut bs, 5, - ext.getattr(crate::intern!(py, "key_cert_sign"))? - .is_true()?, + ext.getattr(pyo3::intern!(py, "key_cert_sign"))?.is_true()?, ); certificate::set_bit( &mut bs, 6, - ext.getattr(crate::intern!(py, "crl_sign"))?.is_true()?, + ext.getattr(pyo3::intern!(py, "crl_sign"))?.is_true()?, ); - if ext - .getattr(crate::intern!(py, "key_agreement"))? - .is_true()? - { + if ext.getattr(pyo3::intern!(py, "key_agreement"))?.is_true()? { certificate::set_bit( &mut bs, 7, - ext.getattr(crate::intern!(py, "encipher_only"))? - .is_true()?, + ext.getattr(pyo3::intern!(py, "encipher_only"))?.is_true()?, ); certificate::set_bit( &mut bs, 8, - ext.getattr(crate::intern!(py, "decipher_only"))? - .is_true()?, + ext.getattr(pyo3::intern!(py, "decipher_only"))?.is_true()?, ); } let (bits, unused_bits) = if bs[1] == 0 { @@ -224,7 +217,7 @@ pub(crate) fn encode_extension( for py_policy_info in ext.iter()? { let py_policy_info = py_policy_info?; let py_policy_qualifiers = - py_policy_info.getattr(crate::intern!(py, "policy_qualifiers"))?; + py_policy_info.getattr(pyo3::intern!(py, "policy_qualifiers"))?; let qualifiers = if py_policy_qualifiers.is_true()? { let mut qualifiers = vec![]; for py_qualifier in py_policy_qualifiers.iter()? { @@ -245,11 +238,11 @@ pub(crate) fn encode_extension( } } else { let py_notice = - py_qualifier.getattr(crate::intern!(py, "notice_reference"))?; + py_qualifier.getattr(pyo3::intern!(py, "notice_reference"))?; let notice_ref = if py_notice.is_true()? { let mut notice_numbers = vec![]; for py_num in py_notice - .getattr(crate::intern!(py, "notice_numbers"))? + .getattr(pyo3::intern!(py, "notice_numbers"))? .iter()? { let bytes = @@ -261,7 +254,7 @@ pub(crate) fn encode_extension( organization: certificate::DisplayText::Utf8String( asn1::Utf8String::new( py_notice - .getattr(crate::intern!(py, "organization"))? + .getattr(pyo3::intern!(py, "organization"))? .extract()?, ), ), @@ -273,7 +266,7 @@ pub(crate) fn encode_extension( None }; let py_explicit_text = - py_qualifier.getattr(crate::intern!(py, "explicit_text"))?; + py_qualifier.getattr(pyo3::intern!(py, "explicit_text"))?; let explicit_text = if py_explicit_text.is_true()? { Some(certificate::DisplayText::Utf8String(asn1::Utf8String::new( py_explicit_text.extract()?, @@ -301,7 +294,7 @@ pub(crate) fn encode_extension( None }; let py_policy_id = - py_policy_info.getattr(crate::intern!(py, "policy_identifier"))?; + py_policy_info.getattr(pyo3::intern!(py, "policy_identifier"))?; policy_informations.push(certificate::PolicyInformation { policy_identifier: py_oid_to_oid(py_policy_id)?, policy_qualifiers: qualifiers, @@ -314,17 +307,17 @@ pub(crate) fn encode_extension( &oid::POLICY_CONSTRAINTS_OID => { let pc = certificate::PolicyConstraints { require_explicit_policy: ext - .getattr(crate::intern!(py, "require_explicit_policy"))? + .getattr(pyo3::intern!(py, "require_explicit_policy"))? .extract()?, inhibit_policy_mapping: ext - .getattr(crate::intern!(py, "inhibit_policy_mapping"))? + .getattr(pyo3::intern!(py, "inhibit_policy_mapping"))? .extract()?, }; Ok(Some(asn1::write_single(&pc)?)) } &oid::NAME_CONSTRAINTS_OID => { - let permitted = ext.getattr(crate::intern!(py, "permitted_subtrees"))?; - let excluded = ext.getattr(crate::intern!(py, "excluded_subtrees"))?; + let permitted = ext.getattr(pyo3::intern!(py, "permitted_subtrees"))?; + let excluded = ext.getattr(pyo3::intern!(py, "excluded_subtrees"))?; let nc = certificate::NameConstraints { permitted_subtrees: encode_general_subtrees(ext.py(), permitted)?, excluded_subtrees: encode_general_subtrees(ext.py(), excluded)?, @@ -333,7 +326,7 @@ pub(crate) fn encode_extension( } &oid::INHIBIT_ANY_POLICY_OID => { let intval = ext - .getattr(crate::intern!(py, "skip_certs"))? + .getattr(pyo3::intern!(py, "skip_certs"))? .downcast::()?; let bytes = py_uint_to_big_endian_bytes(ext.py(), intval)?; Ok(Some(asn1::write_single( @@ -360,7 +353,7 @@ pub(crate) fn encode_extension( // from Python. let mut els = vec![]; for el in ext.iter()? { - els.push(el?.getattr(crate::intern!(py, "value"))?.extract::()?); + els.push(el?.getattr(pyo3::intern!(py, "value"))?.extract::()?); } Ok(Some(asn1::write_single(&asn1::SequenceOfWriter::new(els))?)) @@ -387,8 +380,8 @@ pub(crate) fn encode_extension( let value = ext .py() .import("cryptography.hazmat.backends.openssl.decode_asn1")? - .getattr(crate::intern!(py, "_CRL_ENTRY_REASON_ENUM_TO_CODE"))? - .get_item(ext.getattr(crate::intern!(py, "reason"))?)? + .getattr(pyo3::intern!(py, "_CRL_ENTRY_REASON_ENUM_TO_CODE"))? + .get_item(ext.getattr(pyo3::intern!(py, "reason"))?)? .extract::()?; Ok(Some(asn1::write_single(&asn1::Enumerated::new(value))?)) } @@ -398,14 +391,14 @@ pub(crate) fn encode_extension( } &oid::INVALIDITY_DATE_OID => { let chrono_dt = - x509::py_to_chrono(py, ext.getattr(crate::intern!(py, "invalidity_date"))?)?; + x509::py_to_chrono(py, ext.getattr(pyo3::intern!(py, "invalidity_date"))?)?; Ok(Some(asn1::write_single(&asn1::GeneralizedTime::new( chrono_dt, )?)?)) } &oid::CRL_NUMBER_OID | &oid::DELTA_CRL_INDICATOR_OID => { let intval = ext - .getattr(crate::intern!(py, "crl_number"))? + .getattr(pyo3::intern!(py, "crl_number"))? .downcast::()?; let bytes = py_uint_to_big_endian_bytes(ext.py(), intval)?; Ok(Some(asn1::write_single( @@ -414,27 +407,24 @@ pub(crate) fn encode_extension( } &oid::ISSUING_DISTRIBUTION_POINT_OID => { let only_some_reasons = if ext - .getattr(crate::intern!(py, "only_some_reasons"))? + .getattr(pyo3::intern!(py, "only_some_reasons"))? .is_true()? { - let py_reasons = ext.getattr(crate::intern!(py, "only_some_reasons"))?; + let py_reasons = ext.getattr(pyo3::intern!(py, "only_some_reasons"))?; let reasons = certificate::encode_distribution_point_reasons(ext.py(), py_reasons)?; Some(x509::Asn1ReadableOrWritable::new_write(reasons)) } else { None }; - let distribution_point = if ext.getattr(crate::intern!(py, "full_name"))?.is_true()? { - let py_full_name = ext.getattr(crate::intern!(py, "full_name"))?; + let distribution_point = if ext.getattr(pyo3::intern!(py, "full_name"))?.is_true()? { + let py_full_name = ext.getattr(pyo3::intern!(py, "full_name"))?; let gns = x509::common::encode_general_names(ext.py(), py_full_name)?; Some(certificate::DistributionPointName::FullName( x509::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new(gns)), )) - } else if ext - .getattr(crate::intern!(py, "relative_name"))? - .is_true()? - { + } else if ext.getattr(pyo3::intern!(py, "relative_name"))?.is_true()? { let mut name_entries = vec![]; - for py_name_entry in ext.getattr(crate::intern!(py, "relative_name"))?.iter()? { + for py_name_entry in ext.getattr(pyo3::intern!(py, "relative_name"))?.iter()? { name_entries.push(x509::common::encode_name_entry(ext.py(), py_name_entry?)?); } Some(certificate::DistributionPointName::NameRelativeToCRLIssuer( @@ -446,15 +436,15 @@ pub(crate) fn encode_extension( let idp = crl::IssuingDistributionPoint { distribution_point, - indirect_crl: ext.getattr(crate::intern!(py, "indirect_crl"))?.extract()?, + indirect_crl: ext.getattr(pyo3::intern!(py, "indirect_crl"))?.extract()?, only_contains_attribute_certs: ext - .getattr(crate::intern!(py, "only_contains_attribute_certs"))? + .getattr(pyo3::intern!(py, "only_contains_attribute_certs"))? .extract()?, only_contains_ca_certs: ext - .getattr(crate::intern!(py, "only_contains_ca_certs"))? + .getattr(pyo3::intern!(py, "only_contains_ca_certs"))? .extract()?, only_contains_user_certs: ext - .getattr(crate::intern!(py, "only_contains_user_certs"))? + .getattr(pyo3::intern!(py, "only_contains_user_certs"))? .extract()?, only_some_reasons, }; @@ -462,7 +452,7 @@ pub(crate) fn encode_extension( } &oid::NONCE_OID => { let nonce = ext - .getattr(crate::intern!(py, "nonce"))? + .getattr(pyo3::intern!(py, "nonce"))? .extract::<&[u8]>()?; Ok(Some(asn1::write_single(&nonce)?)) } diff --git a/src/rust/src/x509/ocsp.rs b/src/rust/src/x509/ocsp.rs index a06e7f1cc278..2b10291b8c1e 100644 --- a/src/rust/src/x509/ocsp.rs +++ b/src/rust/src/x509/ocsp.rs @@ -60,7 +60,7 @@ impl CertID<'_> { Ok(CertID { hash_algorithm: x509::AlgorithmIdentifier { oid: HASH_NAME_TO_OIDS[hash_algorithm - .getattr(crate::intern!(py, "name"))? + .getattr(pyo3::intern!(py, "name"))? .extract::<&str>()?] .clone(), params: Some(*x509::sign::NULL_TLV), @@ -81,7 +81,7 @@ impl CertID<'_> { Ok(CertID { hash_algorithm: x509::AlgorithmIdentifier { oid: HASH_NAME_TO_OIDS[hash_algorithm - .getattr(crate::intern!(py, "name"))? + .getattr(pyo3::intern!(py, "name"))? .extract::<&str>()?] .clone(), params: Some(*x509::sign::NULL_TLV), @@ -100,7 +100,7 @@ pub(crate) fn hash_data<'p>( ) -> pyo3::PyResult<&'p [u8]> { let hash = py .import("cryptography.hazmat.primitives.hashes")? - .getattr(crate::intern!(py, "Hash"))? + .getattr(pyo3::intern!(py, "Hash"))? .call1((py_hash_alg,))?; hash.call_method1("update", (data,))?; hash.call_method0("finalize")?.extract() diff --git a/src/rust/src/x509/ocsp_req.rs b/src/rust/src/x509/ocsp_req.rs index 5711dd4a9546..66dc862fd96b 100644 --- a/src/rust/src/x509/ocsp_req.rs +++ b/src/rust/src/x509/ocsp_req.rs @@ -88,7 +88,7 @@ impl OCSPRequest { let exceptions = py.import("cryptography.exceptions")?; Err(CryptographyError::from(pyo3::PyErr::from_value( exceptions - .getattr(crate::intern!(py, "UnsupportedAlgorithm"))? + .getattr(pyo3::intern!(py, "UnsupportedAlgorithm"))? .call1((format!( "Signature algorithm OID: {} not recognized", cert_id.hash_algorithm.oid @@ -139,8 +139,8 @@ impl OCSPRequest { ) -> CryptographyResult<&'p pyo3::types::PyBytes> { let der = py .import("cryptography.hazmat.primitives.serialization")? - .getattr(crate::intern!(py, "Encoding"))? - .getattr(crate::intern!(py, "DER"))?; + .getattr(pyo3::intern!(py, "Encoding"))? + .getattr(pyo3::intern!(py, "DER"))?; if !encoding.is(der) { return Err(pyo3::exceptions::PyValueError::new_err( "The only allowed encoding value is Encoding.DER", @@ -190,7 +190,7 @@ fn create_ocsp_request( py: pyo3::Python<'_>, builder: &pyo3::PyAny, ) -> CryptographyResult { - let builder_request = builder.getattr(crate::intern!(py, "_request"))?; + let builder_request = builder.getattr(pyo3::intern!(py, "_request"))?; // Declare outside the if-block so the lifetimes are right. let (py_cert, py_issuer, py_hash): ( @@ -215,7 +215,7 @@ fn create_ocsp_request( &pyo3::types::PyLong, &pyo3::PyAny, ) = builder - .getattr(crate::intern!(py, "_request_hash"))? + .getattr(pyo3::intern!(py, "_request_hash"))? .extract()?; let serial_number = asn1::BigInt::new(py_uint_to_big_endian_bytes(py, py_serial)?).unwrap(); ocsp::CertID::new_from_hash( @@ -229,7 +229,7 @@ fn create_ocsp_request( let extensions = x509::common::encode_extensions( py, - builder.getattr(crate::intern!(py, "_extensions"))?, + builder.getattr(pyo3::intern!(py, "_extensions"))?, extensions::encode_extension, )?; let reqs = [Request { diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index 9f38282931bc..ff8050abe0b0 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -133,7 +133,7 @@ impl OCSPResponse { "UNAUTHORIZED" }; py.import("cryptography.x509.ocsp")? - .getattr(crate::intern!(py, "OCSPResponseStatus"))? + .getattr(pyo3::intern!(py, "OCSPResponseStatus"))? .getattr(attr) } @@ -174,7 +174,7 @@ impl OCSPResponse { ) -> Result<&'p pyo3::PyAny, CryptographyError> { let sig_oids_to_hash = py .import("cryptography.hazmat._oid")? - .getattr(crate::intern!(py, "_SIG_OIDS_TO_HASH"))?; + .getattr(pyo3::intern!(py, "_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), @@ -365,7 +365,7 @@ impl OCSPResponse { let scts = sct::parse_scts(py, contents, sct::LogEntryType::Certificate)?; Ok(Some( x509_module - .getattr(crate::intern!(py, "SignedCertificateTimestamps"))? + .getattr(pyo3::intern!(py, "SignedCertificateTimestamps"))? .call1((scts,))?, )) } @@ -381,8 +381,8 @@ impl OCSPResponse { ) -> CryptographyResult<&'p pyo3::types::PyBytes> { let der = py .import("cryptography.hazmat.primitives.serialization")? - .getattr(crate::intern!(py, "Encoding"))? - .getattr(crate::intern!(py, "DER"))?; + .getattr(pyo3::intern!(py, "Encoding"))? + .getattr(pyo3::intern!(py, "DER"))?; if !encoding.is(der) { return Err(pyo3::exceptions::PyValueError::new_err( "The only allowed encoding value is Encoding.DER", @@ -518,7 +518,7 @@ impl SingleResponse<'_> { CertStatus::Unknown(_) => "UNKNOWN", }; py.import("cryptography.x509.ocsp")? - .getattr(crate::intern!(py, "OCSPCertStatus"))? + .getattr(pyo3::intern!(py, "OCSPCertStatus"))? .getattr(attr) } @@ -533,7 +533,7 @@ impl SingleResponse<'_> { let exceptions = py.import("cryptography.exceptions")?; Err(CryptographyError::from(pyo3::PyErr::from_value( exceptions - .getattr(crate::intern!(py, "UnsupportedAlgorithm"))? + .getattr(pyo3::intern!(py, "UnsupportedAlgorithm"))? .call1((format!( "Signature algorithm OID: {} not recognized", self.cert_id.hash_algorithm.oid @@ -603,7 +603,7 @@ fn create_ocsp_response( hash_algorithm: &pyo3::PyAny, ) -> CryptographyResult { let response_status = status - .getattr(crate::intern!(py, "value"))? + .getattr(pyo3::intern!(py, "value"))? .extract::()?; let py_cert: pyo3::PyRef<'_, x509::Certificate>; @@ -613,39 +613,39 @@ fn create_ocsp_response( let response_bytes = if response_status == SUCCESSFUL_RESPONSE { let ocsp_mod = py.import("cryptography.x509.ocsp")?; - let py_single_resp = builder.getattr(crate::intern!(py, "_response"))?; + let py_single_resp = builder.getattr(pyo3::intern!(py, "_response"))?; py_cert = py_single_resp - .getattr(crate::intern!(py, "_cert"))? + .getattr(pyo3::intern!(py, "_cert"))? .extract()?; py_issuer = py_single_resp - .getattr(crate::intern!(py, "_issuer"))? + .getattr(pyo3::intern!(py, "_issuer"))? .extract()?; - let py_cert_hash_algorithm = py_single_resp.getattr(crate::intern!(py, "_algorithm"))?; + let py_cert_hash_algorithm = py_single_resp.getattr(pyo3::intern!(py, "_algorithm"))?; let (responder_cert, responder_encoding): (&pyo3::PyCell, &pyo3::PyAny) = builder - .getattr(crate::intern!(py, "_responder_id"))? + .getattr(pyo3::intern!(py, "_responder_id"))? .extract()?; - let py_cert_status = py_single_resp.getattr(crate::intern!(py, "_cert_status"))?; + let py_cert_status = py_single_resp.getattr(pyo3::intern!(py, "_cert_status"))?; let cert_status = if py_cert_status.is(ocsp_mod - .getattr(crate::intern!(py, "OCSPCertStatus"))? - .getattr(crate::intern!(py, "GOOD"))?) + .getattr(pyo3::intern!(py, "OCSPCertStatus"))? + .getattr(pyo3::intern!(py, "GOOD"))?) { CertStatus::Good(()) } else if py_cert_status.is(ocsp_mod - .getattr(crate::intern!(py, "OCSPCertStatus"))? - .getattr(crate::intern!(py, "UNKNOWN"))?) + .getattr(pyo3::intern!(py, "OCSPCertStatus"))? + .getattr(pyo3::intern!(py, "UNKNOWN"))?) { CertStatus::Unknown(()) } else { let revocation_reason = if !py_single_resp - .getattr(crate::intern!(py, "_revocation_reason"))? + .getattr(pyo3::intern!(py, "_revocation_reason"))? .is_none() { let value = py .import("cryptography.hazmat.backends.openssl.decode_asn1")? - .getattr(crate::intern!(py, "_CRL_ENTRY_REASON_ENUM_TO_CODE"))? - .get_item(py_single_resp.getattr(crate::intern!(py, "_revocation_reason"))?)? + .getattr(pyo3::intern!(py, "_CRL_ENTRY_REASON_ENUM_TO_CODE"))? + .get_item(py_single_resp.getattr(pyo3::intern!(py, "_revocation_reason"))?)? .extract::()?; Some(asn1::Enumerated::new(value)) } else { @@ -653,7 +653,7 @@ fn create_ocsp_response( }; // REVOKED let py_revocation_time = - py_single_resp.getattr(crate::intern!(py, "_revocation_time"))?; + py_single_resp.getattr(pyo3::intern!(py, "_revocation_time"))?; let revocation_time = asn1::GeneralizedTime::new(py_to_chrono(py, py_revocation_time)?)?; CertStatus::Revoked(RevokedInfo { @@ -662,10 +662,10 @@ fn create_ocsp_response( }) }; let next_update = if !py_single_resp - .getattr(crate::intern!(py, "_next_update"))? + .getattr(pyo3::intern!(py, "_next_update"))? .is_none() { - let py_next_update = py_single_resp.getattr(crate::intern!(py, "_next_update"))?; + let py_next_update = py_single_resp.getattr(pyo3::intern!(py, "_next_update"))?; Some(asn1::GeneralizedTime::new(py_to_chrono( py, py_next_update, @@ -673,7 +673,7 @@ fn create_ocsp_response( } else { None }; - let py_this_update = py_single_resp.getattr(crate::intern!(py, "_this_update"))?; + let py_this_update = py_single_resp.getattr(pyo3::intern!(py, "_this_update"))?; let this_update = asn1::GeneralizedTime::new(py_to_chrono(py, py_this_update)?)?; let responses = vec![SingleResponse { @@ -686,12 +686,12 @@ fn create_ocsp_response( borrowed_cert = responder_cert.borrow(); let responder_id = if responder_encoding.is(ocsp_mod - .getattr(crate::intern!(py, "OCSPResponderEncoding"))? - .getattr(crate::intern!(py, "HASH"))?) + .getattr(pyo3::intern!(py, "OCSPResponderEncoding"))? + .getattr(pyo3::intern!(py, "HASH"))?) { let sha1 = py .import("cryptography.hazmat.primitives.hashes")? - .getattr(crate::intern!(py, "SHA1"))? + .getattr(pyo3::intern!(py, "SHA1"))? .call0()?; ResponderId::ByKey(ocsp::hash_data( py, @@ -726,7 +726,7 @@ fn create_ocsp_response( )), response_extensions: x509::common::encode_extensions( py, - builder.getattr(crate::intern!(py, "_extensions"))?, + builder.getattr(pyo3::intern!(py, "_extensions"))?, extensions::encode_extension, )?, }; @@ -736,7 +736,7 @@ fn create_ocsp_response( let signature = x509::sign::sign_data(py, private_key, hash_algorithm, &tbs_bytes)?; py.import("cryptography.hazmat.backends.openssl.backend")? - .getattr(crate::intern!(py, "backend"))? + .getattr(pyo3::intern!(py, "backend"))? .call_method1( "_check_keys_correspond", ( @@ -745,7 +745,7 @@ fn create_ocsp_response( ), )?; - py_certs = builder.getattr(crate::intern!(py, "_certs"))?.extract()?; + py_certs = builder.getattr(pyo3::intern!(py, "_certs"))?.extract()?; let certs = py_certs.as_ref().map(|py_certs| { x509::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new( py_certs diff --git a/src/rust/src/x509/sct.rs b/src/rust/src/x509/sct.rs index b6b2e56dab86..4b8414e109d3 100644 --- a/src/rust/src/x509/sct.rs +++ b/src/rust/src/x509/sct.rs @@ -166,8 +166,8 @@ impl Sct { #[getter] fn version<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { py.import("cryptography.x509.certificate_transparency")? - .getattr(crate::intern!(py, "Version"))? - .getattr(crate::intern!(py, "v1")) + .getattr(pyo3::intern!(py, "Version"))? + .getattr(pyo3::intern!(py, "v1")) } #[getter] @@ -179,7 +179,7 @@ impl Sct { fn timestamp<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let datetime_class = py .import("datetime")? - .getattr(crate::intern!(py, "datetime"))?; + .getattr(pyo3::intern!(py, "datetime"))?; datetime_class .call_method1("utcfromtimestamp", (self.timestamp / 1000,))? .call_method( @@ -193,7 +193,7 @@ impl Sct { fn entry_type<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let et_class = py .import("cryptography.x509.certificate_transparency")? - .getattr(crate::intern!(py, "LogEntryType"))?; + .getattr(pyo3::intern!(py, "LogEntryType"))?; let attr_name = match self.entry_type { LogEntryType::Certificate => "X509_CERTIFICATE", LogEntryType::PreCertificate => "PRE_CERTIFICATE", @@ -214,7 +214,7 @@ impl Sct { fn signature_algorithm<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let sa_class = py .import("cryptography.x509.certificate_transparency")? - .getattr(crate::intern!(py, "SignatureAlgorithm"))?; + .getattr(pyo3::intern!(py, "SignatureAlgorithm"))?; sa_class.getattr(self.signature_algorithm.to_attr()) } diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index 4d505ece7886..7a788300ebbf 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -40,23 +40,23 @@ enum HashType { fn identify_key_type(py: pyo3::Python<'_>, private_key: &pyo3::PyAny) -> pyo3::PyResult { let rsa_private_key: &pyo3::types::PyType = py .import("cryptography.hazmat.primitives.asymmetric.rsa")? - .getattr(crate::intern!(py, "RSAPrivateKey"))? + .getattr(pyo3::intern!(py, "RSAPrivateKey"))? .extract()?; let dsa_key_type: &pyo3::types::PyType = py .import("cryptography.hazmat.primitives.asymmetric.dsa")? - .getattr(crate::intern!(py, "DSAPrivateKey"))? + .getattr(pyo3::intern!(py, "DSAPrivateKey"))? .extract()?; let ec_key_type: &pyo3::types::PyType = py .import("cryptography.hazmat.primitives.asymmetric.ec")? - .getattr(crate::intern!(py, "EllipticCurvePrivateKey"))? + .getattr(pyo3::intern!(py, "EllipticCurvePrivateKey"))? .extract()?; let ed25519_key_type: &pyo3::types::PyType = py .import("cryptography.hazmat.primitives.asymmetric.ed25519")? - .getattr(crate::intern!(py, "Ed25519PrivateKey"))? + .getattr(pyo3::intern!(py, "Ed25519PrivateKey"))? .extract()?; let ed448_key_type: &pyo3::types::PyType = py .import("cryptography.hazmat.primitives.asymmetric.ed448")? - .getattr(crate::intern!(py, "Ed448PrivateKey"))? + .getattr(pyo3::intern!(py, "Ed448PrivateKey"))? .extract()?; if private_key.is_instance(rsa_private_key)? { @@ -86,7 +86,7 @@ fn identify_hash_type( let hash_algorithm_type: &pyo3::types::PyType = py .import("cryptography.hazmat.primitives.hashes")? - .getattr(crate::intern!(py, "HashAlgorithm"))? + .getattr(pyo3::intern!(py, "HashAlgorithm"))? .extract()?; if !hash_algorithm.is_instance(hash_algorithm_type)? { return Err(pyo3::exceptions::PyTypeError::new_err( @@ -95,7 +95,7 @@ fn identify_hash_type( } match hash_algorithm - .getattr(crate::intern!(py, "name"))? + .getattr(pyo3::intern!(py, "name"))? .extract()? { "sha224" => Ok(HashType::Sha224), @@ -251,14 +251,14 @@ pub(crate) fn sign_data<'p>( KeyType::Ec => { let ec_mod = py.import("cryptography.hazmat.primitives.asymmetric.ec")?; let ecdsa = ec_mod - .getattr(crate::intern!(py, "ECDSA"))? + .getattr(pyo3::intern!(py, "ECDSA"))? .call1((hash_algorithm,))?; private_key.call_method1("sign", (data, ecdsa))? } KeyType::Rsa => { let padding_mod = py.import("cryptography.hazmat.primitives.asymmetric.padding")?; let pkcs1v15 = padding_mod - .getattr(crate::intern!(py, "PKCS1v15"))? + .getattr(pyo3::intern!(py, "PKCS1v15"))? .call0()?; private_key.call_method1("sign", (data, pkcs1v15, hash_algorithm))? } @@ -311,14 +311,14 @@ pub(crate) fn verify_signature_with_oid<'p>( KeyType::Ec => { let ec_mod = py.import("cryptography.hazmat.primitives.asymmetric.ec")?; let ecdsa = ec_mod - .getattr(crate::intern!(py, "ECDSA"))? + .getattr(pyo3::intern!(py, "ECDSA"))? .call1((signature_hash,))?; issuer_public_key.call_method1("verify", (signature, data, ecdsa))? } KeyType::Rsa => { let padding_mod = py.import("cryptography.hazmat.primitives.asymmetric.padding")?; let pkcs1v15 = padding_mod - .getattr(crate::intern!(py, "PKCS1v15"))? + .getattr(pyo3::intern!(py, "PKCS1v15"))? .call0()?; issuer_public_key.call_method1("verify", (signature, data, pkcs1v15, signature_hash))? } @@ -335,23 +335,23 @@ pub(crate) fn identify_public_key_type( ) -> pyo3::PyResult { let rsa_key_type: &pyo3::types::PyType = py .import("cryptography.hazmat.primitives.asymmetric.rsa")? - .getattr(crate::intern!(py, "RSAPublicKey"))? + .getattr(pyo3::intern!(py, "RSAPublicKey"))? .extract()?; let dsa_key_type: &pyo3::types::PyType = py .import("cryptography.hazmat.primitives.asymmetric.dsa")? - .getattr(crate::intern!(py, "DSAPublicKey"))? + .getattr(pyo3::intern!(py, "DSAPublicKey"))? .extract()?; let ec_key_type: &pyo3::types::PyType = py .import("cryptography.hazmat.primitives.asymmetric.ec")? - .getattr(crate::intern!(py, "EllipticCurvePublicKey"))? + .getattr(pyo3::intern!(py, "EllipticCurvePublicKey"))? .extract()?; let ed25519_key_type: &pyo3::types::PyType = py .import("cryptography.hazmat.primitives.asymmetric.ed25519")? - .getattr(crate::intern!(py, "Ed25519PublicKey"))? + .getattr(pyo3::intern!(py, "Ed25519PublicKey"))? .extract()?; let ed448_key_type: &pyo3::types::PyType = py .import("cryptography.hazmat.primitives.asymmetric.ed448")? - .getattr(crate::intern!(py, "Ed448PublicKey"))? + .getattr(pyo3::intern!(py, "Ed448PublicKey"))? .extract()?; if public_key.is_instance(rsa_key_type)? { From e565402f2fed15fad00680e40b8c78dfd4c08d58 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 24 Mar 2023 18:16:56 -0400 Subject: [PATCH 016/316] Add benchmark for loading DER certificates (#8597) --- tests/bench/test_x509.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/bench/test_x509.py b/tests/bench/test_x509.py index 8a36d3b5fa48..87a60af0f597 100644 --- a/tests/bench/test_x509.py +++ b/tests/bench/test_x509.py @@ -22,6 +22,16 @@ def test_aki_public_bytes(benchmark): benchmark(aki.public_bytes) +def test_load_der_certificate(benchmark): + cert_bytes = load_vectors_from_file( + os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), + loader=lambda pemfile: pemfile.read(), + mode="rb", + ) + + benchmark(x509.load_der_x509_certificate, cert_bytes) + + def test_load_pem_certificate(benchmark): cert_bytes = load_vectors_from_file( os.path.join("x509", "cryptography.io.pem"), From ddb95f53a86b4d5bcc3905d76e1ace75edcef34d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 24 Mar 2023 18:42:27 -0400 Subject: [PATCH 017/316] Use sparse protocol in bench (#8599) --- .github/workflows/benchmark.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index ced2eee2ab75..325d4e81eb1a 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -12,6 +12,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true +env: + CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse + jobs: benchmark: runs-on: ubuntu-latest From 9091c369476a59edbac7c373a936341cb6daf1b0 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Sat, 25 Mar 2023 00:21:25 +0000 Subject: [PATCH 018/316] Bump BoringSSL and/or OpenSSL in CI (#8601) Co-authored-by: pyca-boringbot[bot] --- .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 9d9f7ed9f0ad..c164da3f4b9b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,8 +42,8 @@ jobs: - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "libressl", VERSION: "3.7.1"}} - {VERSION: "3.11", TOXENV: "py311-randomorder"} - {VERSION: "3.12-dev", TOXENV: "py312"} - # Latest commit on the BoringSSL master branch, as of Mar 23, 2023. - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "boringssl", VERSION: "b6a50fd62d1ae44ad211ebe26f803c66db444302"}} + # Latest commit on the BoringSSL master branch, as of Mar 25, 2023. + - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "boringssl", VERSION: "2e13e36e7477cfe2ef48312634b1c34103da4899"}} # Latest commit on the OpenSSL master branch, as of Mar 24, 2023. - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "908ba3ed9adbb3df90f7684a3111ca916a45202d"}} name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.TOXARGS }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" From 0f0247198decdaa4c26fbdf85534ae3929f4fef6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 24 Mar 2023 20:51:14 -0400 Subject: [PATCH 019/316] Fix handling very large pointer values (32-bit) (#8602) --- src/cryptography/hazmat/backends/openssl/backend.py | 4 ++-- src/cryptography/utils.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index facdb48a03a8..5876563695b5 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -650,7 +650,7 @@ def _evp_pkey_to_private_key( return _X448PrivateKey(self, evp_pkey) elif key_type == self._lib.EVP_PKEY_X25519: return rust_openssl.x25519.private_key_from_ptr( - int(self._ffi.cast("intptr_t", evp_pkey)) + int(self._ffi.cast("uintptr_t", evp_pkey)) ) elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): # EVP_PKEY_ED448 is not present in CRYPTOGRAPHY_IS_LIBRESSL @@ -709,7 +709,7 @@ def _evp_pkey_to_public_key(self, evp_pkey) -> PublicKeyTypes: return _X448PublicKey(self, evp_pkey) elif key_type == self._lib.EVP_PKEY_X25519: return rust_openssl.x25519.public_key_from_ptr( - int(self._ffi.cast("intptr_t", evp_pkey)) + int(self._ffi.cast("uintptr_t", evp_pkey)) ) elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): # EVP_PKEY_ED448 is not present in CRYPTOGRAPHY_IS_LIBRESSL diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index da4067a8e6ed..9beea653e330 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -46,7 +46,7 @@ def _extract_buffer_length(obj: typing.Any) -> typing.Tuple[int, int]: from cryptography.hazmat.bindings._rust import _openssl buf = _openssl.ffi.from_buffer(obj) - return int(_openssl.ffi.cast("intptr_t", buf)), len(buf) + return int(_openssl.ffi.cast("uintptr_t", buf)), len(buf) class InterfaceNotImplemented(Exception): From ed037df90e36cb9c3351254ab305883f12d250e5 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 25 Mar 2023 09:25:51 +0800 Subject: [PATCH 020/316] port 40.0.1 changelog to main (#8604) --- CHANGELOG.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 02f12738c1d3..a0b5bf719a26 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -13,6 +13,14 @@ Changelog * **BACKWARDS INCOMPATIBLE:** Support for Python 3.6 has been removed. * Updated the minimum supported Rust version (MSRV) to 1.56.0, from 1.48.0. +.. _v40-0-1: + +40.0.1 - 2023-03-24 +~~~~~~~~~~~~~~~~~~~ + +* Fixed a bug where certain operations would fail if an object happened to be + in the top-half of the memory-space. This only impacted 32-bit systems. + .. _v40-0-0: 40.0.0 - 2023-03-24 From 46509ea575baa3091540a659d6bcc5ab90aeae24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 25 Mar 2023 01:59:22 +0000 Subject: [PATCH 021/316] Bump parking_lot from 0.11.2 to 0.12.1 in /src/rust (#8606) Bumps [parking_lot](https://github.com/Amanieu/parking_lot) from 0.11.2 to 0.12.1. - [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.2...0.12.1) --- updated-dependencies: - dependency-name: parking_lot 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 | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 2aabfbb66e66..96c12cb554a0 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -216,15 +216,6 @@ dependencies = [ "unindent", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "js-sys" version = "0.3.61" @@ -366,27 +357,25 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.11.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "instant", "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", - "instant", "libc", "redox_syscall", "smallvec", - "winapi", + "windows-sys", ] [[package]] @@ -683,6 +672,15 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" version = "0.42.2" From 91cc99118e059c101387844eb4e24808437bda6d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 25 Mar 2023 01:59:33 +0000 Subject: [PATCH 022/316] Bump pyo3 from 0.18.1 to 0.18.2 in /src/rust (#8607) Bumps [pyo3](https://github.com/pyo3/pyo3) from 0.18.1 to 0.18.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.18.1...v0.18.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 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 96c12cb554a0..d9733c38330b 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -428,9 +428,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06a3d8e8a46ab2738109347433cb7b96dffda2e4a218b03ef27090238886b147" +checksum = "cfb848f80438f926a9ebddf0a539ed6065434fd7aae03a89312a9821f81b8501" dependencies = [ "cfg-if", "indoc", @@ -445,9 +445,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75439f995d07ddfad42b192dfcf3bc66a7ecfd8b4a1f5f6f046aa5c2c5d7677d" +checksum = "98a42e7f42e917ce6664c832d5eee481ad514c98250c49e0b03b20593e2c7ed0" dependencies = [ "once_cell", "target-lexicon", @@ -455,9 +455,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "839526a5c07a17ff44823679b68add4a58004de00512a95b6c1c98a6dcac0ee5" +checksum = "a0707f0ab26826fe4ccd59b69106e9df5e12d097457c7b8f9c0fd1d2743eec4d" dependencies = [ "libc", "pyo3-build-config", @@ -465,9 +465,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd44cf207476c6a9760c4653559be4f206efafb924d3e4cbf2721475fc0d6cc5" +checksum = "978d18e61465ecd389e1f235ff5a467146dc4e3c3968b90d274fe73a5dd4a438" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -477,9 +477,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1f43d8e30460f36350d18631ccf85ded64c059829208fe680904c65bcd0a4c" +checksum = "8e0e1128f85ce3fca66e435e08aa2089a2689c1c48ce97803e13f63124058462" dependencies = [ "proc-macro2", "quote", From cfaaf82e44c0fbbc421693667b45be2871f84f9e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 25 Mar 2023 02:15:43 +0000 Subject: [PATCH 023/316] Bump filelock from 3.10.3 to 3.10.4 (#8605) Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.10.3 to 3.10.4. - [Release notes](https://github.com/tox-dev/py-filelock/releases) - [Changelog](https://github.com/tox-dev/py-filelock/blob/main/docs/changelog.rst) - [Commits](https://github.com/tox-dev/py-filelock/compare/3.10.3...3.10.4) --- updated-dependencies: - dependency-name: filelock 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index d55b250ebfb3..8f59ed792e57 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -46,7 +46,7 @@ exceptiongroup==1.1.1 # via pytest execnet==1.9.0 # via pytest-xdist -filelock==3.10.3 +filelock==3.10.4 # via # tox # virtualenv From e2b7fc4b53fef2848dc9567d9915aae9804203ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 25 Mar 2023 02:24:38 +0000 Subject: [PATCH 024/316] Bump indoc from 1.0.4 to 1.0.9 in /src/rust (#8610) Bumps [indoc](https://github.com/dtolnay/indoc) from 1.0.4 to 1.0.9. - [Release notes](https://github.com/dtolnay/indoc/releases) - [Commits](https://github.com/dtolnay/indoc/compare/1.0.4...1.0.9) --- updated-dependencies: - dependency-name: indoc 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 | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index d9733c38330b..ac34af03f27d 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -209,12 +209,9 @@ dependencies = [ [[package]] name = "indoc" -version = "1.0.4" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7906a9fababaeacb774f72410e497a1d18de916322e33797bb2cd29baa23c9e" -dependencies = [ - "unindent", -] +checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" [[package]] name = "js-sys" From 1c0c2d41561fc911469425ee9a6a617b865e42a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 25 Mar 2023 02:28:29 +0000 Subject: [PATCH 025/316] Bump target-lexicon from 0.12.4 to 0.12.6 in /src/rust (#8608) Bumps [target-lexicon](https://github.com/bytecodealliance/target-lexicon) from 0.12.4 to 0.12.6. - [Release notes](https://github.com/bytecodealliance/target-lexicon/releases) - [Commits](https://github.com/bytecodealliance/target-lexicon/compare/v0.12.4...v0.12.6) --- updated-dependencies: - dependency-name: target-lexicon 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 ac34af03f27d..927039d5f424 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -532,9 +532,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.4" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02424087780c9b71cc96799eaeddff35af2bc513278cda5c99fc1f5d026d3c1" +checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" [[package]] name = "termcolor" From d5ca0d8c9b57203ee6022d7289dcdeb4e0d22450 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 25 Mar 2023 02:35:52 -0400 Subject: [PATCH 026/316] Additional MSRV comments (#8611) --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c164da3f4b9b..2d89e25133d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -252,8 +252,10 @@ jobs: PYTHON: - {VERSION: "3.11", TOXENV: "py311"} RUST: + # Potential future MSRVs: # 1.60 - new version of cxx - 1.60.0 + # 1.67 - new version of pem - beta - nightly name: "Rust Coverage" From 4ea157805fe4c86b1230eee791cf404aef61c376 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 25 Mar 2023 06:57:32 -0400 Subject: [PATCH 027/316] Store X.509 structure contents as PyBytes (#8598) This avoids a copy when we're loading from DER. There's still an extra copy when loading from PEM. --- src/rust/src/x509/certificate.rs | 30 +++++++++++++++++++----------- src/rust/src/x509/crl.rs | 19 ++++++++++--------- src/rust/src/x509/csr.rs | 28 ++++++++++++++++++---------- src/rust/src/x509/ocsp_req.rs | 14 ++++++++------ src/rust/src/x509/ocsp_resp.rs | 23 ++++++++++++++--------- 5 files changed, 69 insertions(+), 45 deletions(-) diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 219698fa54d5..3a76571e98c9 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -9,10 +9,9 @@ use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{crl, extensions, oid, sct, sign, Asn1ReadableOrWritable}; use chrono::Datelike; -use pyo3::ToPyObject; +use pyo3::{IntoPy, ToPyObject}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; -use std::sync::Arc; #[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Clone)] pub(crate) struct RawCertificate<'a> { @@ -56,7 +55,7 @@ pub(crate) struct SubjectPublicKeyInfo<'a> { #[ouroboros::self_referencing] pub(crate) struct OwnedRawCertificate { - data: Arc<[u8]>, + data: pyo3::Py, #[borrows(data)] #[covariant] @@ -66,8 +65,10 @@ pub(crate) struct OwnedRawCertificate { impl OwnedRawCertificate { // Re-expose ::new with `pub(crate)` visibility. pub(crate) fn new_public( - data: Arc<[u8]>, - value_ref_builder: impl for<'this> FnOnce(&'this Arc<[u8]>) -> RawCertificate<'this>, + data: pyo3::Py, + value_ref_builder: impl for<'this> FnOnce( + &'this pyo3::Py, + ) -> RawCertificate<'this>, ) -> OwnedRawCertificate { OwnedRawCertificate::new(data, value_ref_builder) } @@ -374,7 +375,10 @@ fn load_pem_x509_certificate(py: pyo3::Python<'_>, data: &[u8]) -> CryptographyR |p| p.tag == "CERTIFICATE" || p.tag == "X509 CERTIFICATE", "Valid PEM but no BEGIN CERTIFICATE/END CERTIFICATE delimiters. Are you sure this is a certificate?", )?; - load_der_x509_certificate(py, &parsed.contents) + load_der_x509_certificate( + py, + pyo3::types::PyBytes::new(py, &parsed.contents).into_py(py), + ) } #[pyo3::prelude::pyfunction] @@ -385,7 +389,9 @@ fn load_pem_x509_certificates( let certs = pem::parse_many(data)? .iter() .filter(|p| p.tag == "CERTIFICATE" || p.tag == "X509 CERTIFICATE") - .map(|p| load_der_x509_certificate(py, &p.contents)) + .map(|p| { + load_der_x509_certificate(py, pyo3::types::PyBytes::new(py, &p.contents).into_py(py)) + }) .collect::, _>>()?; if certs.is_empty() { @@ -396,8 +402,11 @@ fn load_pem_x509_certificates( } #[pyo3::prelude::pyfunction] -fn load_der_x509_certificate(py: pyo3::Python<'_>, data: &[u8]) -> CryptographyResult { - let raw = OwnedRawCertificate::try_new(Arc::from(data), |data| asn1::parse_single(data))?; +fn load_der_x509_certificate( + py: pyo3::Python<'_>, + data: pyo3::Py, +) -> CryptographyResult { + let raw = OwnedRawCertificate::try_new(data, |data| asn1::parse_single(data.as_bytes(py)))?; // Parse cert version immediately so we can raise error on parse if it is invalid. cert_version(py, raw.borrow_value().tbs_cert.version)?; // determine if the serial is negative and raise a warning if it is. We want to drop support @@ -1059,8 +1068,7 @@ fn create_x509_certificate( signature_alg: sigalg, signature: asn1::BitString::new(signature, 0).unwrap(), })?; - // TODO: extra copy as we round-trip through a slice - load_der_x509_certificate(py, &data) + load_der_x509_certificate(py, pyo3::types::PyBytes::new(py, &data).into_py(py)) } pub(crate) fn set_bit(vals: &mut [u8], n: usize, set: bool) { diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index 5100c3afb6db..601268746459 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -8,18 +8,18 @@ use crate::asn1::{ use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{certificate, extensions, oid, sign}; -use pyo3::ToPyObject; +use pyo3::{IntoPy, ToPyObject}; use std::convert::TryInto; use std::sync::Arc; #[pyo3::prelude::pyfunction] fn load_der_x509_crl( py: pyo3::Python<'_>, - data: &[u8], + data: pyo3::Py, ) -> Result { let raw = OwnedRawCertificateRevocationList::try_new( - Arc::from(data), - |data| asn1::parse_single(data), + data, + |data| asn1::parse_single(data.as_bytes(py)), |_| Ok(pyo3::once_cell::GILOnceCell::new()), )?; @@ -49,13 +49,15 @@ fn load_pem_x509_crl( |p| p.tag == "X509 CRL", "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) + load_der_x509_crl( + py, + pyo3::types::PyBytes::new(py, &block.contents).into_py(py), + ) } #[ouroboros::self_referencing] struct OwnedRawCertificateRevocationList { - data: Arc<[u8]>, + data: pyo3::Py, #[borrows(data)] #[covariant] value: RawCertificateRevocationList<'this>, @@ -702,8 +704,7 @@ fn create_x509_crl( signature_algorithm: sigalg, signature_value: asn1::BitString::new(signature, 0).unwrap(), })?; - // TODO: extra copy as we round-trip through a slice - load_der_x509_crl(py, &data) + load_der_x509_crl(py, pyo3::types::PyBytes::new(py, &data).into_py(py)) } pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index 0a6c7cbd8fc1..b920e5fe72f1 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -7,6 +7,7 @@ use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{certificate, oid, sign}; use asn1::SimpleAsn1Readable; +use pyo3::IntoPy; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; @@ -72,7 +73,7 @@ impl CertificationRequestInfo<'_> { #[ouroboros::self_referencing] struct OwnedRawCsr { - data: Vec, + data: pyo3::Py, #[borrows(data)] #[covariant] value: RawCsr<'this>, @@ -86,20 +87,25 @@ struct CertificateSigningRequest { #[pyo3::prelude::pymethods] impl CertificateSigningRequest { - fn __hash__(&self) -> u64 { + fn __hash__(&self, py: pyo3::Python<'_>) -> u64 { let mut hasher = DefaultHasher::new(); - self.raw.borrow_data().hash(&mut hasher); + self.raw.borrow_data().as_bytes(py).hash(&mut hasher); hasher.finish() } fn __richcmp__( &self, + py: pyo3::Python<'_>, other: pyo3::PyRef<'_, CertificateSigningRequest>, op: pyo3::basic::CompareOp, ) -> pyo3::PyResult { match op { - pyo3::basic::CompareOp::Eq => Ok(self.raw.borrow_data() == other.raw.borrow_data()), - pyo3::basic::CompareOp::Ne => Ok(self.raw.borrow_data() != other.raw.borrow_data()), + pyo3::basic::CompareOp::Eq => { + Ok(self.raw.borrow_data().as_bytes(py) == other.raw.borrow_data().as_bytes(py)) + } + pyo3::basic::CompareOp::Ne => { + Ok(self.raw.borrow_data().as_bytes(py) != other.raw.borrow_data().as_bytes(py)) + } _ => Err(pyo3::exceptions::PyTypeError::new_err( "CSRs cannot be ordered", )), @@ -293,15 +299,18 @@ fn load_pem_x509_csr( |p| p.tag == "CERTIFICATE REQUEST" || p.tag == "NEW CERTIFICATE REQUEST", "Valid PEM but no BEGIN CERTIFICATE REQUEST/END CERTIFICATE REQUEST delimiters. Are you sure this is a CSR?", )?; - load_der_x509_csr(py, &parsed.contents) + load_der_x509_csr( + py, + pyo3::types::PyBytes::new(py, &parsed.contents).into_py(py), + ) } #[pyo3::prelude::pyfunction] fn load_der_x509_csr( py: pyo3::Python<'_>, - data: &[u8], + data: pyo3::Py, ) -> CryptographyResult { - let raw = OwnedRawCsr::try_new(data.to_vec(), |data| asn1::parse_single(data))?; + let raw = OwnedRawCsr::try_new(data, |data| asn1::parse_single(data.as_bytes(py)))?; let version = raw.borrow_value().csr_info.version; if version != 0 { @@ -396,8 +405,7 @@ fn create_x509_csr( signature_alg: sigalg, signature: asn1::BitString::new(signature, 0).unwrap(), })?; - // TODO: extra copy as we round-trip through a slice - load_der_x509_csr(py, &data) + load_der_x509_csr(py, pyo3::types::PyBytes::new(py, &data).into_py(py)) } pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { diff --git a/src/rust/src/x509/ocsp_req.rs b/src/rust/src/x509/ocsp_req.rs index 66dc862fd96b..b239869d900d 100644 --- a/src/rust/src/x509/ocsp_req.rs +++ b/src/rust/src/x509/ocsp_req.rs @@ -6,19 +6,22 @@ use crate::asn1::{big_byte_slice_to_py_int, py_uint_to_big_endian_bytes}; use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{extensions, ocsp, oid}; -use std::sync::Arc; +use pyo3::IntoPy; #[ouroboros::self_referencing] struct OwnedRawOCSPRequest { - data: Arc<[u8]>, + data: pyo3::Py, #[borrows(data)] #[covariant] value: RawOCSPRequest<'this>, } #[pyo3::prelude::pyfunction] -fn load_der_ocsp_request(_py: pyo3::Python<'_>, data: &[u8]) -> CryptographyResult { - let raw = OwnedRawOCSPRequest::try_new(Arc::from(data), |data| asn1::parse_single(data))?; +fn load_der_ocsp_request( + py: pyo3::Python<'_>, + data: pyo3::Py, +) -> CryptographyResult { + let raw = OwnedRawOCSPRequest::try_new(data, |data| asn1::parse_single(data.as_bytes(py)))?; if raw .borrow_value() @@ -248,8 +251,7 @@ fn create_ocsp_request( optional_signature: None, }; let data = asn1::write_single(&ocsp_req)?; - // TODO: extra copy as we round-trip through a slice - load_der_ocsp_request(py, &data) + load_der_ocsp_request(py, pyo3::types::PyBytes::new(py, &data).into_py(py)) } pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index ff8050abe0b0..6913f5b177f6 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -7,16 +7,17 @@ use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{certificate, crl, extensions, ocsp, oid, py_to_chrono, sct}; use chrono::Timelike; +use pyo3::IntoPy; use std::sync::Arc; const BASIC_RESPONSE_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 5, 5, 7, 48, 1, 1); #[pyo3::prelude::pyfunction] fn load_der_ocsp_response( - _py: pyo3::Python<'_>, - data: &[u8], + py: pyo3::Python<'_>, + data: pyo3::Py, ) -> Result { - let raw = OwnedRawOCSPResponse::try_new(Arc::from(data), |data| asn1::parse_single(data))?; + let raw = OwnedRawOCSPResponse::try_new(data, |data| asn1::parse_single(data.as_bytes(py)))?; let response = raw.borrow_value(); match response.response_status.value() { @@ -58,7 +59,7 @@ fn load_der_ocsp_response( #[ouroboros::self_referencing] struct OwnedRawOCSPResponse { - data: Arc<[u8]>, + data: pyo3::Py, #[borrows(data)] #[covariant] value: RawOCSPResponse<'this>, @@ -217,7 +218,7 @@ impl OCSPResponse { }; for i in 0..certs.len() { // TODO: O(n^2), don't have too many certificates! - let raw_cert = map_arc_data_ocsp_response(&self.raw, |_data, resp| { + let raw_cert = map_arc_data_ocsp_response(py, &self.raw, |_data, resp| { resp.response_bytes .as_ref() .unwrap() @@ -397,14 +398,19 @@ impl OCSPResponse { // Open-coded implementation of the API discussed in // https://github.com/joshua-maros/ouroboros/issues/38 fn map_arc_data_ocsp_response( + py: pyo3::Python<'_>, it: &OwnedRawOCSPResponse, f: impl for<'this> FnOnce( &'this [u8], &RawOCSPResponse<'this>, ) -> certificate::RawCertificate<'this>, ) -> certificate::OwnedRawCertificate { - certificate::OwnedRawCertificate::new_public(Arc::clone(it.borrow_data()), |inner_it| { - it.with(|value| f(inner_it, unsafe { std::mem::transmute(value.value) })) + certificate::OwnedRawCertificate::new_public(it.borrow_data().clone_ref(py), |inner_it| { + it.with(|value| { + f(inner_it.as_bytes(py), unsafe { + std::mem::transmute(value.value) + }) + }) }) } fn try_map_arc_data_mut_ocsp_response_iterator( @@ -774,8 +780,7 @@ fn create_ocsp_response( response_bytes, }; let data = asn1::write_single(&resp)?; - // TODO: extra copy as we round-trip through a slice - load_der_ocsp_response(py, &data) + load_der_ocsp_response(py, pyo3::types::PyBytes::new(py, &data).into_py(py)) } pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { From 232875752ef45af0b1f054265a3e1dd6d0f9f2c6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 25 Mar 2023 17:13:03 -0400 Subject: [PATCH 028/316] Make CffiBuf implementation sounder (#8612) This keeps the buffer object alive, in addition to the original object. Some buffer-implementors have different behavior based on whether there's a buffer object alive. --- src/cryptography/utils.py | 4 ++-- src/rust/src/buf.rs | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index 9beea653e330..c8a5ee83139b 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -42,11 +42,11 @@ def int_to_bytes(integer: int, length: typing.Optional[int] = None) -> bytes: ) -def _extract_buffer_length(obj: typing.Any) -> typing.Tuple[int, int]: +def _extract_buffer_length(obj: typing.Any) -> typing.Tuple[typing.Any, int]: from cryptography.hazmat.bindings._rust import _openssl buf = _openssl.ffi.from_buffer(obj) - return int(_openssl.ffi.cast("uintptr_t", buf)), len(buf) + return buf, int(_openssl.ffi.cast("uintptr_t", buf)) class InterfaceNotImplemented(Exception): diff --git a/src/rust/src/buf.rs b/src/rust/src/buf.rs index 23dddfd26993..b45e1b5c342e 100644 --- a/src/rust/src/buf.rs +++ b/src/rust/src/buf.rs @@ -6,6 +6,7 @@ use std::{ptr, slice}; pub(crate) struct CffiBuf<'p> { _pyobj: &'p pyo3::PyAny, + _bufobj: &'p pyo3::PyAny, buf: &'p [u8], } @@ -19,10 +20,12 @@ impl<'a> pyo3::conversion::FromPyObject<'a> for CffiBuf<'a> { fn extract(pyobj: &'a pyo3::PyAny) -> pyo3::PyResult { let py = pyobj.py(); - let (ptrval, len): (usize, usize) = py + let (bufobj, ptrval): (&pyo3::PyAny, usize) = py .import("cryptography.utils")? .call_method1("_extract_buffer_length", (pyobj,))? .extract()?; + + let len = bufobj.len()?; let ptr = if len == 0 { ptr::NonNull::dangling().as_ptr() } else { @@ -31,6 +34,7 @@ impl<'a> pyo3::conversion::FromPyObject<'a> for CffiBuf<'a> { Ok(CffiBuf { _pyobj: pyobj, + _bufobj: bufobj, // SAFETY: _extract_buffer_length ensures that we have a valid ptr // and length (and we ensure we meet slice's requirements for // 0-length slices above), we're keeping pyobj alive which ensures From c012d7c9467173286bf3d70201b6a3ab93accd94 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Sun, 26 Mar 2023 10:00:48 +0900 Subject: [PATCH 029/316] Bump BoringSSL and/or OpenSSL in CI (#8615) Co-authored-by: pyca-boringbot[bot] --- .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 2d89e25133d8..72caeec0b85b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,8 +44,8 @@ jobs: - {VERSION: "3.12-dev", TOXENV: "py312"} # Latest commit on the BoringSSL master branch, as of Mar 25, 2023. - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "boringssl", VERSION: "2e13e36e7477cfe2ef48312634b1c34103da4899"}} - # Latest commit on the OpenSSL master branch, as of Mar 24, 2023. - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "908ba3ed9adbb3df90f7684a3111ca916a45202d"}} + # Latest commit on the OpenSSL master branch, as of Mar 26, 2023. + - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "46032426e42238ca8662b98752f9bc8d44512f29"}} name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.TOXARGS }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" timeout-minutes: 15 steps: From 829ccf65de0504231a879b967edd1ef8dcfa4ea6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 26 Mar 2023 17:05:53 -0400 Subject: [PATCH 030/316] Close stale issues more quickly (#8616) This is still more than one week of no response --- .github/workflows/auto-close-stale.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/auto-close-stale.yml b/.github/workflows/auto-close-stale.yml index 2dd48549fd6c..46b4d3e2a9cf 100644 --- a/.github/workflows/auto-close-stale.yml +++ b/.github/workflows/auto-close-stale.yml @@ -16,8 +16,8 @@ jobs: - uses: actions/stale@v8.0.0 with: only-labels: waiting-on-reporter - days-before-stale: 5 - days-before-close: 7 - stale-issue-message: "This issue has been waiting for a reporter response for 5 days. It will be auto-closed if no activity occurs in the next week." + days-before-stale: 3 + days-before-close: 5 + stale-issue-message: "This issue has been waiting for a reporter response for 3 days. It will be auto-closed if no activity occurs in the next 5 days." close-issue-message: "This issue has not received a reporter response and has been auto-closed. If the issue is still relevant please leave a comment and we can reopen it." close-issue-reason: completed From f208befa25131fcbd3fd809c6fc2471ac72ca381 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 26 Mar 2023 23:35:18 +0000 Subject: [PATCH 031/316] Bump filelock from 3.10.4 to 3.10.6 (#8618) Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.10.4 to 3.10.6. - [Release notes](https://github.com/tox-dev/py-filelock/releases) - [Changelog](https://github.com/tox-dev/py-filelock/blob/main/docs/changelog.rst) - [Commits](https://github.com/tox-dev/py-filelock/compare/3.10.4...3.10.6) --- updated-dependencies: - dependency-name: filelock 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 8f59ed792e57..bd9c0cbac95b 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -46,7 +46,7 @@ exceptiongroup==1.1.1 # via pytest execnet==1.9.0 # via pytest-xdist -filelock==3.10.4 +filelock==3.10.6 # via # tox # virtualenv From 64e2d9b554b954a0329554a5f01b95f6969570a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 26 Mar 2023 23:35:33 +0000 Subject: [PATCH 032/316] Bump platformdirs from 3.1.1 to 3.2.0 (#8620) Bumps [platformdirs](https://github.com/platformdirs/platformdirs) from 3.1.1 to 3.2.0. - [Release notes](https://github.com/platformdirs/platformdirs/releases) - [Changelog](https://github.com/platformdirs/platformdirs/blob/main/CHANGES.rst) - [Commits](https://github.com/platformdirs/platformdirs/compare/3.1.1...3.2.0) --- updated-dependencies: - dependency-name: platformdirs 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index bd9c0cbac95b..452cc1e40ea0 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -92,7 +92,7 @@ pathspec==0.11.1 # via black pkginfo==1.9.6 # via twine -platformdirs==3.1.1 +platformdirs==3.2.0 # via # black # tox From 06fd7706a71a1370f9048468775498579dc4b580 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 26 Mar 2023 23:36:10 +0000 Subject: [PATCH 033/316] Bump tox from 4.4.7 to 4.4.8 (#8619) Bumps [tox](https://github.com/tox-dev/tox) from 4.4.7 to 4.4.8. - [Release notes](https://github.com/tox-dev/tox/releases) - [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst) - [Commits](https://github.com/tox-dev/tox/compare/4.4.7...4.4.8) --- updated-dependencies: - dependency-name: tox 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 452cc1e40ea0..2ea238f89d60 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -193,7 +193,7 @@ tomli==2.0.1 # pyproject-hooks # pytest # tox -tox==4.4.7 +tox==4.4.8 # via cryptography (pyproject.toml) twine==4.0.2 # via cryptography (pyproject.toml) From 55c13c31148d54516dcc18ecc936f9657af05071 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 26 Mar 2023 23:52:12 +0000 Subject: [PATCH 034/316] Bump proc-macro2 from 1.0.53 to 1.0.54 in /src/rust (#8621) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.53 to 1.0.54. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.53...1.0.54) --- 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 927039d5f424..49988efec0c5 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -416,9 +416,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.53" +version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73" +checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" dependencies = [ "unicode-ident", ] From 89228a9deb9a0901c87329414b4d8a062bd38bae Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 26 Mar 2023 20:51:04 -0400 Subject: [PATCH 035/316] Added support for OCSP AcceptableResponses extension (#8617) fixes #8589 --- CHANGELOG.rst | 2 + docs/development/test-vectors.rst | 4 +- docs/x509/reference.rst | 29 ++++++++ src/cryptography/hazmat/_oid.py | 1 + src/cryptography/x509/__init__.py | 2 + src/cryptography/x509/extensions.py | 29 ++++++++ src/rust/src/x509/extensions.rs | 2 +- src/rust/src/x509/ocsp_req.rs | 19 ++++- src/rust/src/x509/oid.rs | 2 + tests/x509/test_ocsp.py | 12 ++++ tests/x509/test_x509_ext.py | 67 ++++++++++++++++++ .../x509/ocsp/req-acceptable-responses.der | Bin 0 -> 116 bytes 12 files changed, 164 insertions(+), 5 deletions(-) create mode 100644 vectors/cryptography_vectors/x509/ocsp/req-acceptable-responses.der diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a0b5bf719a26..ec7a3db5ddc9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,8 @@ Changelog removed. Users on older version of OpenSSL will need to upgrade. * **BACKWARDS INCOMPATIBLE:** Support for Python 3.6 has been removed. * Updated the minimum supported Rust version (MSRV) to 1.56.0, from 1.48.0. +* Added support for the :class:`~cryptography.x509.OCSPAcceptableResponses` + OCSP extension. .. _v40-0-1: diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 72fdf7fabac1..2cb822306707 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -658,8 +658,10 @@ 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 +* ``x509/ocsp/resp-unknown-hash-alg.der`` - An OCSP response containing an invalid hash algorithm OID. +* ``x509/ocsp/req-acceptable-responses.der`` - An OCSP request containing an + acceptable responses extension. Custom PKCS12 Test Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index 12ac440cb8ba..d0f864b56a5b 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -2874,6 +2874,29 @@ OCSP Extensions :type: bytes +.. class:: OCSPAcceptableResponses(response) + :canonical: cryptography.x509.extensions.OCSPAcceptableResponses + + .. versionadded:: 41.0.0 + + OCSP acceptable responses is an extension that is only valid inside + :class:`~cryptography.x509.ocsp.OCSPRequest` objects. This allows an OCSP + client to tell the server what types of responses it supports. In practice + this is rarely used, because there is only one kind of OCSP response in + wide use. + + .. attribute:: oid + + :type: :class:`ObjectIdentifier` + + Returns + :attr:`~cryptography.x509.oid.OCSPExtensionOID.ACCEPTABLE_RESPONSES`. + + .. attribute:: nonce + + :type: bytes + + X.509 Request Attributes ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -3509,6 +3532,12 @@ instances. The following common OIDs are available as constants. Corresponds to the dotted string ``"1.3.6.1.5.5.7.48.1.2"``. + .. attribute:: ACCEPTABLE_RESPONSES + + .. versionadded:: 41.0.0 + + Corresponds to the dotted string ``"1.3.6.1.5.5.7.48.1.4"``. + .. class:: AttributeOID :canonical: cryptography.hazmat._oid.AttributeOID diff --git a/src/cryptography/hazmat/_oid.py b/src/cryptography/hazmat/_oid.py index 927ffc4c5412..bc9c046c6a78 100644 --- a/src/cryptography/hazmat/_oid.py +++ b/src/cryptography/hazmat/_oid.py @@ -42,6 +42,7 @@ class ExtensionOID: class OCSPExtensionOID: NONCE = ObjectIdentifier("1.3.6.1.5.5.7.48.1.2") + ACCEPTABLE_RESPONSES = ObjectIdentifier("1.3.6.1.5.5.7.48.1.4") class CRLEntryExtensionOID: diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py index ad924ad42dff..df7fd3fbb5bb 100644 --- a/src/cryptography/x509/__init__.py +++ b/src/cryptography/x509/__init__.py @@ -54,6 +54,7 @@ KeyUsage, NameConstraints, NoticeReference, + OCSPAcceptableResponses, OCSPNoCheck, OCSPNonce, PolicyConstraints, @@ -196,6 +197,7 @@ "IssuingDistributionPoint", "TLSFeature", "TLSFeatureType", + "OCSPAcceptableResponses", "OCSPNoCheck", "BasicConstraints", "CRLNumber", diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 551887b4a60d..6fe3888bf788 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -1932,6 +1932,35 @@ def public_bytes(self) -> bytes: return rust_x509.encode_extension_value(self) +class OCSPAcceptableResponses(ExtensionType): + oid = OCSPExtensionOID.ACCEPTABLE_RESPONSES + + def __init__(self, responses: typing.Iterable[ObjectIdentifier]) -> None: + responses = list(responses) + if any(not isinstance(r, ObjectIdentifier) for r in responses): + raise TypeError("All responses must be ObjectIdentifiers") + + self._responses = responses + + def __eq__(self, other: object) -> bool: + if not isinstance(other, OCSPAcceptableResponses): + return NotImplemented + + return self._responses == other._responses + + def __hash__(self) -> int: + return hash(tuple(self._responses)) + + def __repr__(self) -> str: + return f"" + + def __iter__(self) -> typing.Iterator[ObjectIdentifier]: + return iter(self._responses) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + class IssuingDistributionPoint(ExtensionType): oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT diff --git a/src/rust/src/x509/extensions.rs b/src/rust/src/x509/extensions.rs index d5473a576735..79170a616612 100644 --- a/src/rust/src/x509/extensions.rs +++ b/src/rust/src/x509/extensions.rs @@ -202,7 +202,7 @@ pub(crate) fn encode_extension( let ads = x509::common::encode_access_descriptions(ext.py(), ext)?; Ok(Some(asn1::write_single(&ads)?)) } - &oid::EXTENDED_KEY_USAGE_OID => { + &oid::EXTENDED_KEY_USAGE_OID | &oid::ACCEPTABLE_RESPONSES_OID => { let mut oids = vec![]; for el in ext.iter()? { let oid = py_oid_to_oid(el?)?; diff --git a/src/rust/src/x509/ocsp_req.rs b/src/rust/src/x509/ocsp_req.rs index b239869d900d..47810a023d68 100644 --- a/src/rust/src/x509/ocsp_req.rs +++ b/src/rust/src/x509/ocsp_req.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_byte_slice_to_py_int, py_uint_to_big_endian_bytes}; +use crate::asn1::{big_byte_slice_to_py_int, oid_to_py_oid, py_uint_to_big_endian_bytes}; use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{extensions, ocsp, oid}; @@ -118,8 +118,8 @@ impl OCSPRequest { &mut self.cached_extensions, &self.raw.borrow_value().tbs_request.request_extensions, |oid, value| { - match oid { - &oid::NONCE_OID => { + match *oid { + 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 @@ -129,6 +129,19 @@ impl OCSPRequest { let nonce = asn1::parse_single::<&[u8]>(value).unwrap_or(value); Ok(Some(x509_module.call_method1("OCSPNonce", (nonce,))?)) } + oid::ACCEPTABLE_RESPONSES_OID => { + let oids = asn1::parse_single::< + asn1::SequenceOf<'_, asn1::ObjectIdentifier>, + >(value)?; + let py_oids = pyo3::types::PyList::empty(py); + for oid in oids { + py_oids.append(oid_to_py_oid(py, &oid)?)?; + } + + Ok(Some( + x509_module.call_method1("OCSPAcceptableResponses", (py_oids,))?, + )) + } _ => Ok(None), } }, diff --git a/src/rust/src/x509/oid.rs b/src/rust/src/x509/oid.rs index 55477c60826a..2c9b36d0a186 100644 --- a/src/rust/src/x509/oid.rs +++ b/src/rust/src/x509/oid.rs @@ -41,6 +41,8 @@ pub(crate) const POLICY_CONSTRAINTS_OID: asn1::ObjectIdentifier = asn1::oid!(2, pub(crate) const EXTENDED_KEY_USAGE_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 37); pub(crate) const FRESHEST_CRL_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 46); pub(crate) const INHIBIT_ANY_POLICY_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 54); +pub(crate) const ACCEPTABLE_RESPONSES_OID: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 5, 5, 7, 48, 1, 4); // Signing methods pub(crate) const ECDSA_WITH_SHA224_OID: asn1::ObjectIdentifier = diff --git a/tests/x509/test_ocsp.py b/tests/x509/test_ocsp.py index fd8bbfc1babe..2c595db324f5 100644 --- a/tests/x509/test_ocsp.py +++ b/tests/x509/test_ocsp.py @@ -102,6 +102,18 @@ def test_load_request_with_extensions(self): b"{\x80Z\x1d7&\xb8\xb8OH\xd2\xf8\xbf\xd7-\xfd" ) + def test_load_request_with_acceptable_responses(self): + req = _load_data( + os.path.join("x509", "ocsp", "req-acceptable-responses.der"), + ocsp.load_der_ocsp_request, + ) + assert len(req.extensions) == 1 + ext = req.extensions[0] + assert ext.critical is False + assert ext.value == x509.OCSPAcceptableResponses( + [x509.ObjectIdentifier("1.3.6.1.5.5.7.48.1.1")] + ) + def test_load_request_with_unknown_extension(self): req = _load_data( os.path.join("x509", "ocsp", "req-ext-unknown-oid.der"), diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index a4f0f0f8b6a0..d11ba3db0408 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -6132,6 +6132,73 @@ def test_public_bytes(self): assert ext.public_bytes() == b"\x04\x0500000" +class TestOCSPAcceptableResponses: + def test_invalid_types(self): + with pytest.raises(TypeError): + x509.OCSPAcceptableResponses(38) # type:ignore[arg-type] + with pytest.raises(TypeError): + x509.OCSPAcceptableResponses([38]) # type:ignore[list-item] + + def test_eq(self): + acceptable_responses1 = x509.OCSPAcceptableResponses( + [ObjectIdentifier("1.2.3")] + ) + acceptable_responses2 = x509.OCSPAcceptableResponses( + [ObjectIdentifier("1.2.3")] + ) + assert acceptable_responses1 == acceptable_responses2 + + def test_ne(self): + acceptable_responses1 = x509.OCSPAcceptableResponses( + [ObjectIdentifier("1.2.3")] + ) + acceptable_responses2 = x509.OCSPAcceptableResponses( + [ObjectIdentifier("1.2.4")] + ) + assert acceptable_responses1 != acceptable_responses2 + assert acceptable_responses1 != object() + + def test_repr(self): + acceptable_responses = x509.OCSPAcceptableResponses([]) + assert ( + repr(acceptable_responses) + == "" + ) + + def test_hash(self): + acceptable_responses1 = x509.OCSPAcceptableResponses( + [ObjectIdentifier("1.2.3")] + ) + acceptable_responses2 = x509.OCSPAcceptableResponses( + [ObjectIdentifier("1.2.3")] + ) + acceptable_responses3 = x509.OCSPAcceptableResponses( + [ObjectIdentifier("1.2.4")] + ) + + assert hash(acceptable_responses1) == hash(acceptable_responses2) + assert hash(acceptable_responses1) != hash(acceptable_responses3) + + def test_iter(self): + acceptable_responses1 = x509.OCSPAcceptableResponses( + [ObjectIdentifier("1.2.3")] + ) + + assert list(acceptable_responses1) == [ObjectIdentifier("1.2.3")] + + def test_public_bytes(self): + ext = x509.OCSPAcceptableResponses([]) + assert ext.public_bytes() == b"\x30\x00" + + ext = x509.OCSPAcceptableResponses( + [ObjectIdentifier("1.3.6.1.5.5.7.48.1.1")] + ) + assert ( + ext.public_bytes() + == b"\x30\x0b\x06\t+\x06\x01\x05\x05\x07\x30\x01\x01" + ) + + def test_all_extension_oid_members_have_names_defined(): for oid in dir(ExtensionOID): if oid.startswith("__"): diff --git a/vectors/cryptography_vectors/x509/ocsp/req-acceptable-responses.der b/vectors/cryptography_vectors/x509/ocsp/req-acceptable-responses.der new file mode 100644 index 0000000000000000000000000000000000000000..0afa906d2f558528b77ba93b8fa2a54cc1b12d9c GIT binary patch literal 116 zcmXpgGAJxm)#hVnl450G5s6aXRa5WAVcM&5`m?6)qnz{X+}l}1l;S*} zth&+vAUD~&L3m@-L;Zb`3QU3wPgUmMTCt_3?fID Date: Mon, 27 Mar 2023 20:49:14 +0000 Subject: [PATCH 036/316] Bump rich from 13.3.2 to 13.3.3 (#8624) Bumps [rich](https://github.com/Textualize/rich) from 13.3.2 to 13.3.3. - [Release notes](https://github.com/Textualize/rich/releases) - [Changelog](https://github.com/Textualize/rich/blob/master/CHANGELOG.md) - [Commits](https://github.com/Textualize/rich/compare/v13.3.2...v13.3.3) --- updated-dependencies: - dependency-name: rich 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 2ea238f89d60..c69473a6678b 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -150,7 +150,7 @@ requests-toolbelt==0.10.1 # via twine rfc3986==2.0.0 # via twine -rich==13.3.2 +rich==13.3.3 # via twine ruff==0.0.259 # via cryptography (pyproject.toml) From fa62d75f617be26f649204ccbbfc6576ffabf128 Mon Sep 17 00:00:00 2001 From: Itamar Turner-Trauring Date: Mon, 27 Mar 2023 23:16:29 -0400 Subject: [PATCH 037/316] Restore the x509 error verification codes (#8626) * Restore the x509 error verification codes. This is necessary for custom TLS certificate validation logic; see https://github.com/pyca/pyopenssl/issues/1201 * Remove changelog entry. --------- Co-authored-by: Itamar Turner-Trauring --- src/_cffi_src/openssl/x509_vfy.py | 61 ++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/src/_cffi_src/openssl/x509_vfy.py b/src/_cffi_src/openssl/x509_vfy.py index 69c31c966185..71d0cec38d4f 100644 --- a/src/_cffi_src/openssl/x509_vfy.py +++ b/src/_cffi_src/openssl/x509_vfy.py @@ -30,12 +30,69 @@ typedef int (*X509_STORE_CTX_get_issuer_fn)(X509 **, X509_STORE_CTX *, X509 *); +static const int X509_V_OK; +static const int X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT; +static const int X509_V_ERR_UNABLE_TO_GET_CRL; +static const int X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE; +static const int X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE; +static const int X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY; +static const int X509_V_ERR_CERT_SIGNATURE_FAILURE; +static const int X509_V_ERR_CRL_SIGNATURE_FAILURE; +static const int X509_V_ERR_CERT_NOT_YET_VALID; +static const int X509_V_ERR_CERT_HAS_EXPIRED; +static const int X509_V_ERR_CRL_NOT_YET_VALID; +static const int X509_V_ERR_CRL_HAS_EXPIRED; +static const int X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD; +static const int X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD; +static const int X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD; +static const int X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD; +static const int X509_V_ERR_OUT_OF_MEM; +static const int X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT; +static const int X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN; +static const int X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY; +static const int X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE; +static const int X509_V_ERR_CERT_CHAIN_TOO_LONG; +static const int X509_V_ERR_CERT_REVOKED; +static const int X509_V_ERR_INVALID_CA; +static const int X509_V_ERR_PATH_LENGTH_EXCEEDED; +static const int X509_V_ERR_INVALID_PURPOSE; +static const int X509_V_ERR_CERT_UNTRUSTED; +static const int X509_V_ERR_CERT_REJECTED; +static const int X509_V_ERR_SUBJECT_ISSUER_MISMATCH; +static const int X509_V_ERR_AKID_SKID_MISMATCH; +static const int X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH; +static const int X509_V_ERR_KEYUSAGE_NO_CERTSIGN; +static const int X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER; +static const int X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION; +static const int X509_V_ERR_KEYUSAGE_NO_CRL_SIGN; +static const int X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION; +static const int X509_V_ERR_INVALID_NON_CA; +static const int X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED; +static const int X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE; +static const int X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED; +static const int X509_V_ERR_INVALID_EXTENSION; +static const int X509_V_ERR_INVALID_POLICY_EXTENSION; +static const int X509_V_ERR_NO_EXPLICIT_POLICY; +static const int X509_V_ERR_DIFFERENT_CRL_SCOPE; +static const int X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE; +static const int X509_V_ERR_UNNESTED_RESOURCE; +static const int X509_V_ERR_PERMITTED_VIOLATION; +static const int X509_V_ERR_EXCLUDED_VIOLATION; +static const int X509_V_ERR_SUBTREE_MINMAX; +static const int X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE; +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_HOSTNAME_MISMATCH; +static const int X509_V_ERR_EMAIL_MISMATCH; +static const int X509_V_ERR_IP_ADDRESS_MISMATCH; +static const int X509_V_ERR_APPLICATION_VERIFICATION; + + /* While these are defined in the source as ints, they're tagged here as longs, just in case they ever grow to large, such as what we saw with OP_ALL. */ -static const int X509_V_OK; - /* Verification parameters */ static const long X509_V_FLAG_CRL_CHECK; static const long X509_V_FLAG_CRL_CHECK_ALL; From bf688c9294f7f807e27e1575112b254597a18524 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Tue, 28 Mar 2023 03:17:03 +0000 Subject: [PATCH 038/316] Bump BoringSSL and/or OpenSSL in CI (#8627) Co-authored-by: pyca-boringbot[bot] --- .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 72caeec0b85b..c86c1ad0114d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,8 +44,8 @@ jobs: - {VERSION: "3.12-dev", TOXENV: "py312"} # Latest commit on the BoringSSL master branch, as of Mar 25, 2023. - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "boringssl", VERSION: "2e13e36e7477cfe2ef48312634b1c34103da4899"}} - # Latest commit on the OpenSSL master branch, as of Mar 26, 2023. - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "46032426e42238ca8662b98752f9bc8d44512f29"}} + # Latest commit on the OpenSSL master branch, as of Mar 28, 2023. + - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "864c70e43ea5f1d7fe20bfea457e53e79fd46b6e"}} name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.TOXARGS }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" timeout-minutes: 15 steps: From 29508fcf126d3dd4a8120d14be426dee2dacc346 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Mar 2023 13:17:33 +0000 Subject: [PATCH 039/316] Bump filelock from 3.10.6 to 3.10.7 (#8630) Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.10.6 to 3.10.7. - [Release notes](https://github.com/tox-dev/py-filelock/releases) - [Changelog](https://github.com/tox-dev/py-filelock/blob/main/docs/changelog.rst) - [Commits](https://github.com/tox-dev/py-filelock/compare/3.10.6...3.10.7) --- updated-dependencies: - dependency-name: filelock 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index c69473a6678b..29ca1f3f38b5 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -46,7 +46,7 @@ exceptiongroup==1.1.1 # via pytest execnet==1.9.0 # via pytest-xdist -filelock==3.10.6 +filelock==3.10.7 # via # tox # virtualenv From 8158e45ee746faea3fcf43e23a339bb02145a7af Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 29 Mar 2023 10:46:50 +0900 Subject: [PATCH 040/316] certbot moved their tests to an internal package (#8632) --- .github/downstream.d/certbot.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/downstream.d/certbot.sh b/.github/downstream.d/certbot.sh index e2f2203bbf0a..13508c87a0c8 100755 --- a/.github/downstream.d/certbot.sh +++ b/.github/downstream.d/certbot.sh @@ -14,7 +14,7 @@ case "${1}" in # Ignore some warnings for now since they're now automatically promoted # to errors. We can probably remove this when acme gets split into # its own repo - pytest -Wignore certbot/tests + pytest -Wignore certbot pytest acme ;; *) From 60d3f709eb96ba5df9bdfede5c024c1f2db9f0e5 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 28 Mar 2023 22:11:23 -0400 Subject: [PATCH 041/316] Error cleanly in setup.py when using a too-old PyPy (#8634) --- setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.py b/setup.py index b3a7cf9b241e..b05dc2f129c3 100644 --- a/setup.py +++ b/setup.py @@ -43,6 +43,9 @@ # means that we need to add the src/ directory to the sys.path. sys.path.insert(0, src_dir) +if hasattr(sys, "pypy_version_info") and sys.pypy_version_info < (7, 3, 10): + raise RuntimeError("cryptography is not compatible with PyPy3 < 7.3.10") + try: # See pyproject.toml for most of the config metadata. setup( From f8514b30dfe2872653caeb6bf6776367c2d66671 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Wed, 29 Mar 2023 02:20:09 +0000 Subject: [PATCH 042/316] Bump BoringSSL and/or OpenSSL in CI (#8631) Co-authored-by: pyca-boringbot[bot] --- .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 c86c1ad0114d..ac3e1644a4e2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,10 +42,10 @@ jobs: - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "libressl", VERSION: "3.7.1"}} - {VERSION: "3.11", TOXENV: "py311-randomorder"} - {VERSION: "3.12-dev", TOXENV: "py312"} - # Latest commit on the BoringSSL master branch, as of Mar 25, 2023. - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "boringssl", VERSION: "2e13e36e7477cfe2ef48312634b1c34103da4899"}} - # Latest commit on the OpenSSL master branch, as of Mar 28, 2023. - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "864c70e43ea5f1d7fe20bfea457e53e79fd46b6e"}} + # Latest commit on the BoringSSL master branch, as of Mar 29, 2023. + - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "boringssl", VERSION: "678bae408369d614e0777bc5cd5a380dac35ed59"}} + # Latest commit on the OpenSSL master branch, as of Mar 29, 2023. + - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "30ab774770a7e8547b0d6363b63a73cc80f33a7b"}} name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.TOXARGS }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" timeout-minutes: 15 steps: From 59a749333e336b5aa1f9864fe01d67ec11c3a065 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 29 Mar 2023 11:20:33 +0900 Subject: [PATCH 043/316] define path for type for rust classes (no more builtins) (#8635) --- src/rust/src/asn1.rs | 2 +- src/rust/src/backend/x25519.rs | 4 ++-- src/rust/src/lib.rs | 2 +- src/rust/src/oid.rs | 2 +- src/rust/src/pool.rs | 4 ++-- src/rust/src/x509/certificate.rs | 2 +- src/rust/src/x509/crl.rs | 6 +++--- src/rust/src/x509/csr.rs | 2 +- src/rust/src/x509/ocsp_req.rs | 2 +- src/rust/src/x509/ocsp_resp.rs | 6 +++--- src/rust/src/x509/sct.rs | 2 +- 11 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 2cc9431bb5fd..833a72031e16 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -143,7 +143,7 @@ fn encode_dss_signature( Ok(pyo3::types::PyBytes::new(py, &result).to_object(py)) } -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.asn1")] struct TestCertificate { #[pyo3(get)] not_before_tag: u8, diff --git a/src/rust/src/backend/x25519.rs b/src/rust/src/backend/x25519.rs index 94af22636b00..988d0076ef5f 100644 --- a/src/rust/src/backend/x25519.rs +++ b/src/rust/src/backend/x25519.rs @@ -6,12 +6,12 @@ use crate::buf::CffiBuf; use crate::error::{CryptographyError, CryptographyResult}; use foreign_types_shared::ForeignTypeRef; -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.x25519")] struct X25519PrivateKey { pkey: openssl::pkey::PKey, } -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.x25519")] struct X25519PublicKey { pkey: openssl::pkey::PKey, } diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index d7dbbba6067d..e8608150421c 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -102,7 +102,7 @@ fn raise_openssl_error() -> crate::error::CryptographyResult<()> { Err(openssl::error::ErrorStack::get().into()) } -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl")] struct OpenSSLError { e: openssl::error::Error, } diff --git a/src/rust/src/oid.rs b/src/rust/src/oid.rs index 1c12f775a621..23bdd7362dd0 100644 --- a/src/rust/src/oid.rs +++ b/src/rust/src/oid.rs @@ -6,7 +6,7 @@ use crate::error::CryptographyResult; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust")] pub(crate) struct ObjectIdentifier { pub(crate) oid: asn1::ObjectIdentifier, } diff --git a/src/rust/src/pool.rs b/src/rust/src/pool.rs index 384273a69b57..b9e6e27cd4af 100644 --- a/src/rust/src/pool.rs +++ b/src/rust/src/pool.rs @@ -7,14 +7,14 @@ use std::cell::Cell; // An object pool that can contain a single object and will dynamically // allocate new objects to fulfill requests if the pool'd object is already in // use. -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust")] pub(crate) struct FixedPool { create_fn: pyo3::PyObject, value: Cell>, } -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust")] struct PoolAcquisition { pool: pyo3::Py, diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 3a76571e98c9..efbab2449780 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -78,7 +78,7 @@ impl OwnedRawCertificate { } } -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")] pub(crate) struct Certificate { pub(crate) raw: OwnedRawCertificate, pub(crate) cached_extensions: Option, diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index 601268746459..7644cfd2715a 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -66,7 +66,7 @@ struct OwnedRawCertificateRevocationList { revoked_certs: pyo3::once_cell::GILOnceCell>>, } -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")] struct CertificateRevocationList { raw: Arc, @@ -415,7 +415,7 @@ struct OwnedCRLIteratorData { value: Option>>, } -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")] struct CRLIterator { contents: OwnedCRLIteratorData, } @@ -517,7 +517,7 @@ struct OwnedRawRevokedCertificate { value: RawRevokedCertificate<'this>, } -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")] struct RevokedCertificate { raw: OwnedRawRevokedCertificate, cached_extensions: Option, diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index b920e5fe72f1..b90e49e3e0ee 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -79,7 +79,7 @@ struct OwnedRawCsr { value: RawCsr<'this>, } -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")] struct CertificateSigningRequest { raw: OwnedRawCsr, cached_extensions: Option, diff --git a/src/rust/src/x509/ocsp_req.rs b/src/rust/src/x509/ocsp_req.rs index 47810a023d68..0eef4bccb2ef 100644 --- a/src/rust/src/x509/ocsp_req.rs +++ b/src/rust/src/x509/ocsp_req.rs @@ -44,7 +44,7 @@ fn load_der_ocsp_request( }) } -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.ocsp")] struct OCSPRequest { raw: OwnedRawOCSPRequest, diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index 6913f5b177f6..e8f864c42f1e 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -65,7 +65,7 @@ struct OwnedRawOCSPResponse { value: RawOCSPResponse<'this>, } -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.ocsp")] struct OCSPResponse { raw: Arc, @@ -798,7 +798,7 @@ struct OwnedOCSPResponseIteratorData { value: asn1::SequenceOf<'this, SingleResponse<'this>>, } -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.ocsp")] struct OCSPResponseIterator { contents: OwnedOCSPResponseIteratorData, } @@ -830,7 +830,7 @@ struct OwnedSingleResponse { value: SingleResponse<'this>, } -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.ocsp")] struct OCSPSingleResponse { raw: OwnedSingleResponse, } diff --git a/src/rust/src/x509/sct.rs b/src/rust/src/x509/sct.rs index 4b8414e109d3..09e1ae4486c9 100644 --- a/src/rust/src/x509/sct.rs +++ b/src/rust/src/x509/sct.rs @@ -128,7 +128,7 @@ impl TryFrom for SignatureAlgorithm { } } -#[pyo3::prelude::pyclass] +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")] pub(crate) struct Sct { log_id: [u8; 32], timestamp: u64, From 22759dbab0bc85da995febcc3e82680fe6b2804a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 28 Mar 2023 22:28:17 -0400 Subject: [PATCH 044/316] Switch from pytest-subtests to a mini-version that's faster (#8613) --- ci-constraints-requirements.txt | 4 ---- pyproject.toml | 3 +-- tests/conftest.py | 19 +++++++++++++++++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 29ca1f3f38b5..1054e9d91042 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -10,7 +10,6 @@ alabaster==0.7.13 attrs==22.2.0 # via # pytest - # pytest-subtests babel==2.12.1 # via sphinx black==23.1.0 @@ -125,7 +124,6 @@ pytest==7.2.2 # pytest-cov # pytest-randomly # pytest-shard - # pytest-subtests # pytest-xdist pytest-benchmark==4.0.0 # via cryptography (pyproject.toml) @@ -135,8 +133,6 @@ pytest-randomly==3.12.0 # via cryptography (pyproject.toml) pytest-shard==0.1.2 # via cryptography (pyproject.toml) -pytest-subtests==0.10.0 - # via cryptography (pyproject.toml) pytest-xdist==3.2.1 # via cryptography (pyproject.toml) readme-renderer==37.3 diff --git a/pyproject.toml b/pyproject.toml index 2a94aa26405b..7bdf2a5cfaa4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,7 +78,6 @@ test = [ "pytest-shard >=0.1.2", "pytest-benchmark", "pytest-cov", - "pytest-subtests >=0.10.0", "pytest-xdist", "pretend", ] @@ -93,7 +92,7 @@ line-length = 79 target-version = ["py37"] [tool.pytest.ini_options] -addopts = "-r s --capture=no --strict-markers --benchmark-disable --no-subtests-shortletter" +addopts = "-r s --capture=no --strict-markers --benchmark-disable" console_output_style = "progress-even-when-capture-no" markers = [ "skip_fips: this test is not executed in FIPS mode", diff --git a/tests/conftest.py b/tests/conftest.py index 51dca19850a3..0e128a16513e 100644 --- a/tests/conftest.py +++ b/tests/conftest.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 contextlib import pytest @@ -46,3 +47,21 @@ def backend(request): # Ensure the error stack is clear after the test errors = openssl_backend._consume_errors() assert not errors + + +@pytest.fixture() +def subtests(): + # This is a miniature version of the pytest-subtests package, but + # optimized for lower overhead. + # + # When tests are skipped, these are not logged in the final pytest output. + yield SubTests() + + +class SubTests: + @contextlib.contextmanager + def test(self): + try: + yield + except pytest.skip.Exception: + pass From 24463e35882a1b7152f9fc8b2a2cb22fe3bc8805 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Mar 2023 05:40:02 +0900 Subject: [PATCH 045/316] Bump black from 23.1.0 to 23.3.0 (#8636) Bumps [black](https://github.com/psf/black) from 23.1.0 to 23.3.0. - [Release notes](https://github.com/psf/black/releases) - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - [Commits](https://github.com/psf/black/compare/23.1.0...23.3.0) --- updated-dependencies: - dependency-name: black 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 1054e9d91042..a0ae6856e7a0 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -12,7 +12,7 @@ attrs==22.2.0 # pytest babel==2.12.1 # via sphinx -black==23.1.0 +black==23.3.0 # via cryptography (pyproject.toml) bleach==6.0.0 # via readme-renderer From 92f2932ace9ec316952e1c3653de8c22b183680c Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Thu, 30 Mar 2023 00:18:39 +0000 Subject: [PATCH 046/316] Bump BoringSSL and/or OpenSSL in CI (#8638) Co-authored-by: pyca-boringbot[bot] --- .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 ac3e1644a4e2..8be80dc30c31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,10 +42,10 @@ jobs: - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "libressl", VERSION: "3.7.1"}} - {VERSION: "3.11", TOXENV: "py311-randomorder"} - {VERSION: "3.12-dev", TOXENV: "py312"} - # Latest commit on the BoringSSL master branch, as of Mar 29, 2023. - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "boringssl", VERSION: "678bae408369d614e0777bc5cd5a380dac35ed59"}} - # Latest commit on the OpenSSL master branch, as of Mar 29, 2023. - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "30ab774770a7e8547b0d6363b63a73cc80f33a7b"}} + # Latest commit on the BoringSSL master branch, as of Mar 30, 2023. + - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "boringssl", VERSION: "fca688f26b939db9c9981204373cecbd108b5d6c"}} + # Latest commit on the OpenSSL master branch, as of Mar 30, 2023. + - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "09cb8718fd65dc7126247808cb96b05147bb923f"}} name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.TOXARGS }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" timeout-minutes: 15 steps: From 61ffde1f66b4d0f798044195e8eaee172a8865e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Mar 2023 13:09:44 +0000 Subject: [PATCH 047/316] Bump iana-time-zone from 0.1.54 to 0.1.55 in /src/rust (#8641) Bumps [iana-time-zone](https://github.com/strawlab/iana-time-zone) from 0.1.54 to 0.1.55. - [Release notes](https://github.com/strawlab/iana-time-zone/releases) - [Changelog](https://github.com/strawlab/iana-time-zone/blob/main/CHANGELOG.md) - [Commits](https://github.com/strawlab/iana-time-zone/compare/v0.1.54...v0.1.55) --- updated-dependencies: - dependency-name: iana-time-zone 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 | 83 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 13 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 49988efec0c5..24a98758c1f4 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -185,9 +185,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "iana-time-zone" -version = "0.1.54" +version = "0.1.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d" +checksum = "716f12fbcfac6ffab0a5e9ec51d0a0ff70503742bb2dc7b99396394c9dc323f0" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -662,11 +662,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.46.0" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" +checksum = "2649ff315bee4c98757f15dac226efe3d81927adbb6e882084bb1ee3e0c330a7" dependencies = [ - "windows-targets", + "windows-targets 0.47.0", ] [[package]] @@ -675,7 +675,7 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.2", ] [[package]] @@ -684,13 +684,28 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f8996d3f43b4b2d44327cd71b7b0efd1284ab60e6e9d0e8b630e18555d87d3e" +dependencies = [ + "windows_aarch64_gnullvm 0.47.0", + "windows_aarch64_msvc 0.47.0", + "windows_i686_gnu 0.47.0", + "windows_i686_msvc 0.47.0", + "windows_x86_64_gnu 0.47.0", + "windows_x86_64_gnullvm 0.47.0", + "windows_x86_64_msvc 0.47.0", ] [[package]] @@ -699,38 +714,80 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831d567d53d4f3cb1db332b68e6e2b6260228eb4d99a777d8b2e8ed794027c90" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a42d54a417c60ce4f0e31661eed628f0fa5aca73448c093ec4d45fab4c51cdf" + [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1925beafdbb22201a53a483db861a5644123157c1c3cee83323a2ed565d71e3" + [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8ef8f2f1711b223947d9b69b596cf5a4e452c930fb58b6fc3fdae7d0ec6b31" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7acaa0c2cf0d2ef99b61c308a0c3dbae430a51b7345dedec470bd8f53f5a3642" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a0628f71be1d11e17ca4a0e9e15b3a5180f6fbf1c2d55e3ba3f850378052c1" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6e62c256dc6d40b8c8707df17df8d774e60e39db723675241e7c15e910bce7" From 5890361c5fa70e3c48d863a383a9d5a2586039ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Mar 2023 13:33:16 +0000 Subject: [PATCH 048/316] Bump ruff from 0.0.259 to 0.0.260 (#8642) Bumps [ruff](https://github.com/charliermarsh/ruff) from 0.0.259 to 0.0.260. - [Release notes](https://github.com/charliermarsh/ruff/releases) - [Changelog](https://github.com/charliermarsh/ruff/blob/main/BREAKING_CHANGES.md) - [Commits](https://github.com/charliermarsh/ruff/compare/v0.0.259...v0.0.260) --- updated-dependencies: - dependency-name: ruff 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index a0ae6856e7a0..11f850c7efbc 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -148,7 +148,7 @@ rfc3986==2.0.0 # via twine rich==13.3.3 # via twine -ruff==0.0.259 +ruff==0.0.260 # via cryptography (pyproject.toml) six==1.16.0 # via bleach From 394ae30408f4286bddac211afe67cbdcb545dcac Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 30 Mar 2023 17:46:16 -0400 Subject: [PATCH 049/316] Use from __future__ import annotations everywhere (#8643) --- src/_cffi_src/build_openssl.py | 1 + src/_cffi_src/openssl/asn1.py | 1 + src/_cffi_src/openssl/bignum.py | 1 + src/_cffi_src/openssl/bio.py | 1 + src/_cffi_src/openssl/callbacks.py | 1 + src/_cffi_src/openssl/cmac.py | 1 + src/_cffi_src/openssl/crypto.py | 1 + src/_cffi_src/openssl/cryptography.py | 1 + src/_cffi_src/openssl/dh.py | 1 + src/_cffi_src/openssl/dsa.py | 1 + src/_cffi_src/openssl/ec.py | 1 + src/_cffi_src/openssl/ecdsa.py | 1 + src/_cffi_src/openssl/engine.py | 1 + src/_cffi_src/openssl/err.py | 1 + src/_cffi_src/openssl/evp.py | 1 + src/_cffi_src/openssl/fips.py | 1 + src/_cffi_src/openssl/hmac.py | 1 + src/_cffi_src/openssl/nid.py | 1 + src/_cffi_src/openssl/objects.py | 1 + src/_cffi_src/openssl/opensslv.py | 1 + src/_cffi_src/openssl/pem.py | 1 + src/_cffi_src/openssl/pkcs12.py | 1 + src/_cffi_src/openssl/pkcs7.py | 1 + src/_cffi_src/openssl/provider.py | 1 + src/_cffi_src/openssl/rand.py | 1 + src/_cffi_src/openssl/rsa.py | 1 + src/_cffi_src/openssl/ssl.py | 1 + src/_cffi_src/openssl/x509.py | 1 + src/_cffi_src/openssl/x509_vfy.py | 1 + src/_cffi_src/openssl/x509name.py | 1 + src/_cffi_src/openssl/x509v3.py | 1 + src/_cffi_src/utils.py | 1 + src/cryptography/__about__.py | 1 + src/cryptography/__init__.py | 2 + src/cryptography/exceptions.py | 3 +- src/cryptography/fernet.py | 1 + src/cryptography/hazmat/__init__.py | 3 ++ src/cryptography/hazmat/_oid.py | 2 + src/cryptography/hazmat/backends/__init__.py | 3 ++ .../hazmat/backends/openssl/__init__.py | 1 + .../hazmat/backends/openssl/aead.py | 26 ++++++------ .../hazmat/backends/openssl/backend.py | 1 + .../hazmat/backends/openssl/ciphers.py | 6 +-- .../hazmat/backends/openssl/cmac.py | 8 ++-- .../hazmat/backends/openssl/decode_asn1.py | 1 + .../hazmat/backends/openssl/dh.py | 12 +++--- .../hazmat/backends/openssl/dsa.py | 13 +++--- .../hazmat/backends/openssl/ec.py | 20 +++++---- .../hazmat/backends/openssl/ed25519.py | 6 ++- .../hazmat/backends/openssl/ed448.py | 6 ++- .../hazmat/backends/openssl/hashes.py | 6 ++- .../hazmat/backends/openssl/hmac.py | 6 ++- .../hazmat/backends/openssl/poly1305.py | 4 +- .../hazmat/backends/openssl/rsa.py | 36 ++++++++-------- .../hazmat/backends/openssl/utils.py | 4 +- .../hazmat/backends/openssl/x448.py | 6 ++- .../hazmat/bindings/openssl/_conditional.py | 2 + .../hazmat/bindings/openssl/binding.py | 2 + .../hazmat/primitives/_asymmetric.py | 2 + .../hazmat/primitives/_cipheralgorithm.py | 2 + .../hazmat/primitives/_serialization.py | 10 +++-- .../hazmat/primitives/asymmetric/dh.py | 11 ++--- .../hazmat/primitives/asymmetric/dsa.py | 11 ++--- .../hazmat/primitives/asymmetric/ec.py | 11 ++--- .../hazmat/primitives/asymmetric/ed25519.py | 7 ++-- .../hazmat/primitives/asymmetric/ed448.py | 7 ++-- .../hazmat/primitives/asymmetric/padding.py | 7 ++-- .../hazmat/primitives/asymmetric/rsa.py | 11 ++--- .../hazmat/primitives/asymmetric/types.py | 2 + .../hazmat/primitives/asymmetric/utils.py | 1 + .../hazmat/primitives/asymmetric/x25519.py | 7 ++-- .../hazmat/primitives/asymmetric/x448.py | 7 ++-- .../hazmat/primitives/ciphers/__init__.py | 1 + .../hazmat/primitives/ciphers/aead.py | 1 + .../hazmat/primitives/ciphers/algorithms.py | 1 + .../hazmat/primitives/ciphers/base.py | 19 +++++---- .../hazmat/primitives/ciphers/modes.py | 1 + src/cryptography/hazmat/primitives/cmac.py | 7 ++-- .../hazmat/primitives/constant_time.py | 1 + src/cryptography/hazmat/primitives/hashes.py | 8 ++-- src/cryptography/hazmat/primitives/hmac.py | 3 +- .../hazmat/primitives/kdf/__init__.py | 1 + .../hazmat/primitives/kdf/concatkdf.py | 1 + .../hazmat/primitives/kdf/hkdf.py | 1 + .../hazmat/primitives/kdf/kbkdf.py | 2 + .../hazmat/primitives/kdf/pbkdf2.py | 1 + .../hazmat/primitives/kdf/scrypt.py | 1 + .../hazmat/primitives/kdf/x963kdf.py | 1 + src/cryptography/hazmat/primitives/keywrap.py | 1 + src/cryptography/hazmat/primitives/padding.py | 1 + .../hazmat/primitives/poly1305.py | 2 + .../primitives/serialization/__init__.py | 1 + .../hazmat/primitives/serialization/base.py | 5 ++- .../hazmat/primitives/serialization/pkcs12.py | 2 + .../hazmat/primitives/serialization/pkcs7.py | 8 ++-- .../hazmat/primitives/serialization/ssh.py | 23 ++++++----- .../hazmat/primitives/twofactor/__init__.py | 2 + .../hazmat/primitives/twofactor/hotp.py | 3 +- .../hazmat/primitives/twofactor/totp.py | 2 + src/cryptography/utils.py | 1 + src/cryptography/x509/__init__.py | 1 + src/cryptography/x509/base.py | 41 +++++++++---------- .../x509/certificate_transparency.py | 1 + src/cryptography/x509/extensions.py | 41 ++++++++++--------- src/cryptography/x509/general_name.py | 9 ++-- src/cryptography/x509/name.py | 4 +- src/cryptography/x509/ocsp.py | 15 +++---- src/cryptography/x509/oid.py | 2 + 108 files changed, 330 insertions(+), 194 deletions(-) diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py index e971fd955882..42754fb6417b 100644 --- a/src/_cffi_src/build_openssl.py +++ b/src/_cffi_src/build_openssl.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import os import pathlib diff --git a/src/_cffi_src/openssl/asn1.py b/src/_cffi_src/openssl/asn1.py index 4927432898eb..d2be452a687b 100644 --- a/src/_cffi_src/openssl/asn1.py +++ b/src/_cffi_src/openssl/asn1.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/bignum.py b/src/_cffi_src/openssl/bignum.py index 1e9f81128271..9ea729001433 100644 --- a/src/_cffi_src/openssl/bignum.py +++ b/src/_cffi_src/openssl/bignum.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/bio.py b/src/_cffi_src/openssl/bio.py index 899856d355c2..1742e348122a 100644 --- a/src/_cffi_src/openssl/bio.py +++ b/src/_cffi_src/openssl/bio.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/callbacks.py b/src/_cffi_src/openssl/callbacks.py index 57a393686197..ddb764283920 100644 --- a/src/_cffi_src/openssl/callbacks.py +++ b/src/_cffi_src/openssl/callbacks.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/cmac.py b/src/_cffi_src/openssl/cmac.py index a25426305131..7095066dac54 100644 --- a/src/_cffi_src/openssl/cmac.py +++ b/src/_cffi_src/openssl/cmac.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #if !defined(OPENSSL_NO_CMAC) diff --git a/src/_cffi_src/openssl/crypto.py b/src/_cffi_src/openssl/crypto.py index 63843e02ee26..f36a0fa17616 100644 --- a/src/_cffi_src/openssl/crypto.py +++ b/src/_cffi_src/openssl/crypto.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/cryptography.py b/src/_cffi_src/openssl/cryptography.py index 40e6ce9846fd..05d3e0e50165 100644 --- a/src/_cffi_src/openssl/cryptography.py +++ b/src/_cffi_src/openssl/cryptography.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ /* define our OpenSSL API compatibility level to 1.1.0. Any symbols older than diff --git a/src/_cffi_src/openssl/dh.py b/src/_cffi_src/openssl/dh.py index 44b3d817ae7e..1a75b6d22879 100644 --- a/src/_cffi_src/openssl/dh.py +++ b/src/_cffi_src/openssl/dh.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/dsa.py b/src/_cffi_src/openssl/dsa.py index cf34913b530b..04478a0e577b 100644 --- a/src/_cffi_src/openssl/dsa.py +++ b/src/_cffi_src/openssl/dsa.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/ec.py b/src/_cffi_src/openssl/ec.py index b037675f0d68..e745b3efcd14 100644 --- a/src/_cffi_src/openssl/ec.py +++ b/src/_cffi_src/openssl/ec.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/ecdsa.py b/src/_cffi_src/openssl/ecdsa.py index 53294afc60f7..716b5d03016f 100644 --- a/src/_cffi_src/openssl/ecdsa.py +++ b/src/_cffi_src/openssl/ecdsa.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/engine.py b/src/_cffi_src/openssl/engine.py index 9931639b4828..609313ec57ae 100644 --- a/src/_cffi_src/openssl/engine.py +++ b/src/_cffi_src/openssl/engine.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/err.py b/src/_cffi_src/openssl/err.py index ebe6c3559837..2bb2545fc932 100644 --- a/src/_cffi_src/openssl/err.py +++ b/src/_cffi_src/openssl/err.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/evp.py b/src/_cffi_src/openssl/evp.py index b8a38995c00b..aa92f1ddb968 100644 --- a/src/_cffi_src/openssl/evp.py +++ b/src/_cffi_src/openssl/evp.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/fips.py b/src/_cffi_src/openssl/fips.py index 9fb1e7aed0bb..9e3ce9524b44 100644 --- a/src/_cffi_src/openssl/fips.py +++ b/src/_cffi_src/openssl/fips.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/hmac.py b/src/_cffi_src/openssl/hmac.py index 8b1915361be3..8fbc2b411608 100644 --- a/src/_cffi_src/openssl/hmac.py +++ b/src/_cffi_src/openssl/hmac.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/nid.py b/src/_cffi_src/openssl/nid.py index 28135b428d46..8933c95d82f0 100644 --- a/src/_cffi_src/openssl/nid.py +++ b/src/_cffi_src/openssl/nid.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/objects.py b/src/_cffi_src/openssl/objects.py index cfa7fac21268..5f9bdb3361d0 100644 --- a/src/_cffi_src/openssl/objects.py +++ b/src/_cffi_src/openssl/objects.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/opensslv.py b/src/_cffi_src/openssl/opensslv.py index 630ebd7a1b91..7957bd7dd58c 100644 --- a/src/_cffi_src/openssl/opensslv.py +++ b/src/_cffi_src/openssl/opensslv.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/pem.py b/src/_cffi_src/openssl/pem.py index 62253da7a544..aac77ac71111 100644 --- a/src/_cffi_src/openssl/pem.py +++ b/src/_cffi_src/openssl/pem.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/pkcs12.py b/src/_cffi_src/openssl/pkcs12.py index 135afc94b47a..234f97b3ea65 100644 --- a/src/_cffi_src/openssl/pkcs12.py +++ b/src/_cffi_src/openssl/pkcs12.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/pkcs7.py b/src/_cffi_src/openssl/pkcs7.py index e0d52322f7e1..60741bbac19d 100644 --- a/src/_cffi_src/openssl/pkcs7.py +++ b/src/_cffi_src/openssl/pkcs7.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/provider.py b/src/_cffi_src/openssl/provider.py index d741ad7e4f55..769fded96d23 100644 --- a/src/_cffi_src/openssl/provider.py +++ b/src/_cffi_src/openssl/provider.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #if CRYPTOGRAPHY_OPENSSL_300_OR_GREATER diff --git a/src/_cffi_src/openssl/rand.py b/src/_cffi_src/openssl/rand.py index a2cce0ad201e..ee00fe68d821 100644 --- a/src/_cffi_src/openssl/rand.py +++ b/src/_cffi_src/openssl/rand.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/rsa.py b/src/_cffi_src/openssl/rsa.py index a7a3256b71bb..eea6e396e3fb 100644 --- a/src/_cffi_src/openssl/rsa.py +++ b/src/_cffi_src/openssl/rsa.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/ssl.py b/src/_cffi_src/openssl/ssl.py index 3e1b09209e3b..1b59e97ff083 100644 --- a/src/_cffi_src/openssl/ssl.py +++ b/src/_cffi_src/openssl/ssl.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/x509.py b/src/_cffi_src/openssl/x509.py index 06445f12c4af..66e8592042fd 100644 --- a/src/_cffi_src/openssl/x509.py +++ b/src/_cffi_src/openssl/x509.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/x509_vfy.py b/src/_cffi_src/openssl/x509_vfy.py index 71d0cec38d4f..0337afa3497d 100644 --- a/src/_cffi_src/openssl/x509_vfy.py +++ b/src/_cffi_src/openssl/x509_vfy.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/x509name.py b/src/_cffi_src/openssl/x509name.py index 9eca79e38e7c..876af17f2d5e 100644 --- a/src/_cffi_src/openssl/x509name.py +++ b/src/_cffi_src/openssl/x509name.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/openssl/x509v3.py b/src/_cffi_src/openssl/x509v3.py index 838bda2903ec..dae98da1bf4e 100644 --- a/src/_cffi_src/openssl/x509v3.py +++ b/src/_cffi_src/openssl/x509v3.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations INCLUDES = """ #include diff --git a/src/_cffi_src/utils.py b/src/_cffi_src/utils.py index 5d2c4224a12b..cc2a2fb5f050 100644 --- a/src/_cffi_src/utils.py +++ b/src/_cffi_src/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. +from __future__ import annotations import os import platform diff --git a/src/cryptography/__about__.py b/src/cryptography/__about__.py index ef6399c179b5..9ab3785b18f7 100644 --- a/src/cryptography/__about__.py +++ b/src/cryptography/__about__.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations __all__ = [ "__version__", diff --git a/src/cryptography/__init__.py b/src/cryptography/__init__.py index ffa979a4ea9d..86b9a25726d1 100644 --- a/src/cryptography/__init__.py +++ b/src/cryptography/__init__.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + from cryptography.__about__ import __author__, __copyright__, __version__ __all__ = [ diff --git a/src/cryptography/exceptions.py b/src/cryptography/exceptions.py index 5e69c1192434..59c7ebaff43c 100644 --- a/src/cryptography/exceptions.py +++ b/src/cryptography/exceptions.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import typing @@ -56,7 +57,7 @@ class InvalidSignature(Exception): class InternalError(Exception): def __init__( - self, msg: str, err_code: typing.List["rust_openssl.OpenSSLError"] + self, msg: str, err_code: typing.List[rust_openssl.OpenSSLError] ) -> None: super().__init__(msg) self.err_code = err_code diff --git a/src/cryptography/fernet.py b/src/cryptography/fernet.py index a2601f80f680..ad8fb40b9d44 100644 --- a/src/cryptography/fernet.py +++ b/src/cryptography/fernet.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import base64 import binascii diff --git a/src/cryptography/hazmat/__init__.py b/src/cryptography/hazmat/__init__.py index 007694bc5060..b9f1187011bd 100644 --- a/src/cryptography/hazmat/__init__.py +++ b/src/cryptography/hazmat/__init__.py @@ -1,6 +1,9 @@ # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. + +from __future__ import annotations + """ Hazardous Materials diff --git a/src/cryptography/hazmat/_oid.py b/src/cryptography/hazmat/_oid.py index bc9c046c6a78..82a6498f92c2 100644 --- a/src/cryptography/hazmat/_oid.py +++ b/src/cryptography/hazmat/_oid.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography.hazmat.bindings._rust import ( diff --git a/src/cryptography/hazmat/backends/__init__.py b/src/cryptography/hazmat/backends/__init__.py index 3926f85f1d18..b4400aa03745 100644 --- a/src/cryptography/hazmat/backends/__init__.py +++ b/src/cryptography/hazmat/backends/__init__.py @@ -1,6 +1,9 @@ # This file is dual licensed under the terms of the Apache License, Version # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. + +from __future__ import annotations + from typing import Any diff --git a/src/cryptography/hazmat/backends/openssl/__init__.py b/src/cryptography/hazmat/backends/openssl/__init__.py index 42c4539df3ed..51b04476cbb7 100644 --- a/src/cryptography/hazmat/backends/openssl/__init__.py +++ b/src/cryptography/hazmat/backends/openssl/__init__.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations from cryptography.hazmat.backends.openssl.backend import backend diff --git a/src/cryptography/hazmat/backends/openssl/aead.py b/src/cryptography/hazmat/backends/openssl/aead.py index d43deb432a16..7361f227914d 100644 --- a/src/cryptography/hazmat/backends/openssl/aead.py +++ b/src/cryptography/hazmat/backends/openssl/aead.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography.exceptions import InvalidTag @@ -24,7 +26,7 @@ _DECRYPT = 0 -def _aead_cipher_name(cipher: "_AEADTypes") -> bytes: +def _aead_cipher_name(cipher: _AEADTypes) -> bytes: from cryptography.hazmat.primitives.ciphers.aead import ( AESCCM, AESGCM, @@ -46,7 +48,7 @@ def _aead_cipher_name(cipher: "_AEADTypes") -> bytes: return f"aes-{len(cipher._key) * 8}-gcm".encode("ascii") -def _evp_cipher(cipher_name: bytes, backend: "Backend"): +def _evp_cipher(cipher_name: bytes, backend: Backend): if cipher_name.endswith(b"-siv"): evp_cipher = backend._lib.EVP_CIPHER_fetch( backend._ffi.NULL, @@ -63,8 +65,8 @@ def _evp_cipher(cipher_name: bytes, backend: "Backend"): def _aead_create_ctx( - backend: "Backend", - cipher: "_AEADTypes", + backend: Backend, + cipher: _AEADTypes, key: bytes, ): ctx = backend._lib.EVP_CIPHER_CTX_new() @@ -86,7 +88,7 @@ def _aead_create_ctx( def _aead_setup( - backend: "Backend", + backend: Backend, cipher_name: bytes, key: bytes, nonce: bytes, @@ -158,7 +160,7 @@ def _set_nonce_operation(backend, ctx, nonce: bytes, operation: int) -> None: backend.openssl_assert(res != 0) -def _set_length(backend: "Backend", ctx, data_len: int) -> None: +def _set_length(backend: Backend, ctx, data_len: int) -> None: intptr = backend._ffi.new("int *") res = backend._lib.EVP_CipherUpdate( ctx, backend._ffi.NULL, intptr, backend._ffi.NULL, data_len @@ -166,7 +168,7 @@ def _set_length(backend: "Backend", ctx, data_len: int) -> None: backend.openssl_assert(res != 0) -def _process_aad(backend: "Backend", ctx, associated_data: bytes) -> None: +def _process_aad(backend: Backend, ctx, associated_data: bytes) -> None: outlen = backend._ffi.new("int *") a_data_ptr = backend._ffi.from_buffer(associated_data) res = backend._lib.EVP_CipherUpdate( @@ -175,7 +177,7 @@ def _process_aad(backend: "Backend", ctx, associated_data: bytes) -> None: backend.openssl_assert(res != 0) -def _process_data(backend: "Backend", ctx, data: bytes) -> bytes: +def _process_data(backend: Backend, ctx, data: bytes) -> bytes: outlen = backend._ffi.new("int *") buf = backend._ffi.new("unsigned char[]", len(data)) data_ptr = backend._ffi.from_buffer(data) @@ -188,8 +190,8 @@ def _process_data(backend: "Backend", ctx, data: bytes) -> bytes: def _encrypt( - backend: "Backend", - cipher: "_AEADTypes", + backend: Backend, + cipher: _AEADTypes, nonce: bytes, data: bytes, associated_data: typing.List[bytes], @@ -246,8 +248,8 @@ def _encrypt( def _decrypt( - backend: "Backend", - cipher: "_AEADTypes", + backend: Backend, + cipher: _AEADTypes, nonce: bytes, data: bytes, associated_data: typing.List[bytes], diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 5876563695b5..ac464e75a809 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import collections import contextlib diff --git a/src/cryptography/hazmat/backends/openssl/ciphers.py b/src/cryptography/hazmat/backends/openssl/ciphers.py index 8d4b8dc3bbf1..bc42adbd49a5 100644 --- a/src/cryptography/hazmat/backends/openssl/ciphers.py +++ b/src/cryptography/hazmat/backends/openssl/ciphers.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography.exceptions import InvalidTag, UnsupportedAlgorithm, _Reasons @@ -17,9 +19,7 @@ class _CipherContext: _DECRYPT = 0 _MAX_CHUNK_SIZE = 2**30 - 1 - def __init__( - self, backend: "Backend", cipher, mode, operation: int - ) -> None: + def __init__(self, backend: Backend, cipher, mode, operation: int) -> None: self._backend = backend self._cipher = cipher self._mode = mode diff --git a/src/cryptography/hazmat/backends/openssl/cmac.py b/src/cryptography/hazmat/backends/openssl/cmac.py index 6f7363294179..bdd7fec611d1 100644 --- a/src/cryptography/hazmat/backends/openssl/cmac.py +++ b/src/cryptography/hazmat/backends/openssl/cmac.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography.exceptions import ( @@ -20,8 +22,8 @@ class _CMACContext: def __init__( self, - backend: "Backend", - algorithm: "ciphers.BlockCipherAlgorithm", + backend: Backend, + algorithm: ciphers.BlockCipherAlgorithm, ctx=None, ) -> None: if not backend.cmac_algorithm_supported(algorithm): @@ -72,7 +74,7 @@ def finalize(self) -> bytes: return self._backend._ffi.buffer(buf)[:] - def copy(self) -> "_CMACContext": + def copy(self) -> _CMACContext: copied_ctx = self._backend._lib.CMAC_CTX_new() copied_ctx = self._backend._ffi.gc( copied_ctx, self._backend._lib.CMAC_CTX_free diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index df91d6d8a73e..bf123b6285b6 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations from cryptography import x509 diff --git a/src/cryptography/hazmat/backends/openssl/dh.py b/src/cryptography/hazmat/backends/openssl/dh.py index 87d6fb8af694..6c1889bc3ac2 100644 --- a/src/cryptography/hazmat/backends/openssl/dh.py +++ b/src/cryptography/hazmat/backends/openssl/dh.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography.exceptions import UnsupportedAlgorithm, _Reasons @@ -12,7 +14,7 @@ from cryptography.hazmat.backends.openssl.backend import Backend -def _dh_params_dup(dh_cdata, backend: "Backend"): +def _dh_params_dup(dh_cdata, backend: Backend): lib = backend._lib ffi = backend._ffi @@ -30,13 +32,13 @@ def _dh_params_dup(dh_cdata, backend: "Backend"): return param_cdata -def _dh_cdata_to_parameters(dh_cdata, backend: "Backend") -> "_DHParameters": +def _dh_cdata_to_parameters(dh_cdata, backend: Backend) -> _DHParameters: param_cdata = _dh_params_dup(dh_cdata, backend) return _DHParameters(backend, param_cdata) class _DHParameters(dh.DHParameters): - def __init__(self, backend: "Backend", dh_cdata): + def __init__(self, backend: Backend, dh_cdata): self._backend = backend self._dh_cdata = dh_cdata @@ -112,7 +114,7 @@ def _get_dh_num_bits(backend, dh_cdata) -> int: class _DHPrivateKey(dh.DHPrivateKey): - def __init__(self, backend: "Backend", dh_cdata, evp_pkey): + def __init__(self, backend: Backend, dh_cdata, evp_pkey): self._backend = backend self._dh_cdata = dh_cdata self._evp_pkey = evp_pkey @@ -249,7 +251,7 @@ def private_bytes( class _DHPublicKey(dh.DHPublicKey): - def __init__(self, backend: "Backend", dh_cdata, evp_pkey): + def __init__(self, backend: Backend, dh_cdata, evp_pkey): self._backend = backend self._dh_cdata = dh_cdata self._evp_pkey = evp_pkey diff --git a/src/cryptography/hazmat/backends/openssl/dsa.py b/src/cryptography/hazmat/backends/openssl/dsa.py index 15bd84a7b5a5..be0500152aeb 100644 --- a/src/cryptography/hazmat/backends/openssl/dsa.py +++ b/src/cryptography/hazmat/backends/openssl/dsa.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import typing @@ -18,7 +19,7 @@ def _dsa_sig_sign( - backend: "Backend", private_key: "_DSAPrivateKey", data: bytes + backend: Backend, private_key: _DSAPrivateKey, data: bytes ) -> bytes: sig_buf_len = backend._lib.DSA_size(private_key._dsa_cdata) sig_buf = backend._ffi.new("unsigned char[]", sig_buf_len) @@ -36,8 +37,8 @@ def _dsa_sig_sign( def _dsa_sig_verify( - backend: "Backend", - public_key: "_DSAPublicKey", + backend: Backend, + public_key: _DSAPublicKey, signature: bytes, data: bytes, ) -> None: @@ -53,7 +54,7 @@ def _dsa_sig_verify( class _DSAParameters(dsa.DSAParameters): - def __init__(self, backend: "Backend", dsa_cdata): + def __init__(self, backend: Backend, dsa_cdata): self._backend = backend self._dsa_cdata = dsa_cdata @@ -78,7 +79,7 @@ def generate_private_key(self) -> dsa.DSAPrivateKey: class _DSAPrivateKey(dsa.DSAPrivateKey): _key_size: int - def __init__(self, backend: "Backend", dsa_cdata, evp_pkey): + def __init__(self, backend: Backend, dsa_cdata, evp_pkey): self._backend = backend self._dsa_cdata = dsa_cdata self._evp_pkey = evp_pkey @@ -173,7 +174,7 @@ def sign( class _DSAPublicKey(dsa.DSAPublicKey): _key_size: int - def __init__(self, backend: "Backend", dsa_cdata, evp_pkey): + def __init__(self, backend: Backend, dsa_cdata, evp_pkey): self._backend = backend self._dsa_cdata = dsa_cdata self._evp_pkey = evp_pkey diff --git a/src/cryptography/hazmat/backends/openssl/ec.py b/src/cryptography/hazmat/backends/openssl/ec.py index 969306bcb893..90a7b6fa3fc1 100644 --- a/src/cryptography/hazmat/backends/openssl/ec.py +++ b/src/cryptography/hazmat/backends/openssl/ec.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography.exceptions import ( @@ -30,7 +32,7 @@ def _check_signature_algorithm( ) -def _ec_key_curve_sn(backend: "Backend", ec_key) -> str: +def _ec_key_curve_sn(backend: Backend, ec_key) -> str: group = backend._lib.EC_KEY_get0_group(ec_key) backend.openssl_assert(group != backend._ffi.NULL) @@ -60,7 +62,7 @@ def _ec_key_curve_sn(backend: "Backend", ec_key) -> str: return sn -def _mark_asn1_named_ec_curve(backend: "Backend", ec_cdata): +def _mark_asn1_named_ec_curve(backend: Backend, ec_cdata): """ Set the named curve flag on the EC_KEY. This causes OpenSSL to serialize EC keys along with their curve OID which makes @@ -72,7 +74,7 @@ def _mark_asn1_named_ec_curve(backend: "Backend", ec_cdata): ) -def _check_key_infinity(backend: "Backend", ec_cdata) -> None: +def _check_key_infinity(backend: Backend, ec_cdata) -> None: point = backend._lib.EC_KEY_get0_public_key(ec_cdata) backend.openssl_assert(point != backend._ffi.NULL) group = backend._lib.EC_KEY_get0_group(ec_cdata) @@ -83,7 +85,7 @@ def _check_key_infinity(backend: "Backend", ec_cdata) -> None: ) -def _sn_to_elliptic_curve(backend: "Backend", sn: str) -> ec.EllipticCurve: +def _sn_to_elliptic_curve(backend: Backend, sn: str) -> ec.EllipticCurve: try: return ec._CURVE_TYPES[sn]() except KeyError: @@ -94,7 +96,7 @@ def _sn_to_elliptic_curve(backend: "Backend", sn: str) -> ec.EllipticCurve: def _ecdsa_sig_sign( - backend: "Backend", private_key: "_EllipticCurvePrivateKey", data: bytes + backend: Backend, private_key: _EllipticCurvePrivateKey, data: bytes ) -> bytes: max_size = backend._lib.ECDSA_size(private_key._ec_key) backend.openssl_assert(max_size > 0) @@ -109,8 +111,8 @@ def _ecdsa_sig_sign( def _ecdsa_sig_verify( - backend: "Backend", - public_key: "_EllipticCurvePublicKey", + backend: Backend, + public_key: _EllipticCurvePublicKey, signature: bytes, data: bytes, ) -> None: @@ -123,7 +125,7 @@ def _ecdsa_sig_verify( class _EllipticCurvePrivateKey(ec.EllipticCurvePrivateKey): - def __init__(self, backend: "Backend", ec_key_cdata, evp_pkey): + def __init__(self, backend: Backend, ec_key_cdata, evp_pkey): self._backend = backend self._ec_key = ec_key_cdata self._evp_pkey = evp_pkey @@ -215,7 +217,7 @@ def sign( class _EllipticCurvePublicKey(ec.EllipticCurvePublicKey): - def __init__(self, backend: "Backend", ec_key_cdata, evp_pkey): + def __init__(self, backend: Backend, ec_key_cdata, evp_pkey): self._backend = backend self._ec_key = ec_key_cdata self._evp_pkey = evp_pkey diff --git a/src/cryptography/hazmat/backends/openssl/ed25519.py b/src/cryptography/hazmat/backends/openssl/ed25519.py index 6f393e5b6aa9..4e33a78f35f3 100644 --- a/src/cryptography/hazmat/backends/openssl/ed25519.py +++ b/src/cryptography/hazmat/backends/openssl/ed25519.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography import exceptions @@ -18,7 +20,7 @@ class _Ed25519PublicKey(Ed25519PublicKey): - def __init__(self, backend: "Backend", evp_pkey): + def __init__(self, backend: Backend, evp_pkey): self._backend = backend self._evp_pkey = evp_pkey @@ -78,7 +80,7 @@ def verify(self, signature: bytes, data: bytes) -> None: class _Ed25519PrivateKey(Ed25519PrivateKey): - def __init__(self, backend: "Backend", evp_pkey): + def __init__(self, backend: Backend, evp_pkey): self._backend = backend self._evp_pkey = evp_pkey diff --git a/src/cryptography/hazmat/backends/openssl/ed448.py b/src/cryptography/hazmat/backends/openssl/ed448.py index 0d27ea638ad6..b2300367697c 100644 --- a/src/cryptography/hazmat/backends/openssl/ed448.py +++ b/src/cryptography/hazmat/backends/openssl/ed448.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography import exceptions @@ -19,7 +21,7 @@ class _Ed448PublicKey(Ed448PublicKey): - def __init__(self, backend: "Backend", evp_pkey): + def __init__(self, backend: Backend, evp_pkey): self._backend = backend self._evp_pkey = evp_pkey @@ -79,7 +81,7 @@ def verify(self, signature: bytes, data: bytes) -> None: class _Ed448PrivateKey(Ed448PrivateKey): - def __init__(self, backend: "Backend", evp_pkey): + def __init__(self, backend: Backend, evp_pkey): self._backend = backend self._evp_pkey = evp_pkey diff --git a/src/cryptography/hazmat/backends/openssl/hashes.py b/src/cryptography/hazmat/backends/openssl/hashes.py index 52d4646a7ab0..370407aac58d 100644 --- a/src/cryptography/hazmat/backends/openssl/hashes.py +++ b/src/cryptography/hazmat/backends/openssl/hashes.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography.exceptions import UnsupportedAlgorithm, _Reasons @@ -13,7 +15,7 @@ class _HashContext(hashes.HashContext): def __init__( - self, backend: "Backend", algorithm: hashes.HashAlgorithm, ctx=None + self, backend: Backend, algorithm: hashes.HashAlgorithm, ctx=None ) -> None: self._algorithm = algorithm @@ -43,7 +45,7 @@ def __init__( def algorithm(self) -> hashes.HashAlgorithm: return self._algorithm - def copy(self) -> "_HashContext": + def copy(self) -> _HashContext: copied_ctx = self._backend._lib.EVP_MD_CTX_new() copied_ctx = self._backend._ffi.gc( copied_ctx, self._backend._lib.EVP_MD_CTX_free diff --git a/src/cryptography/hazmat/backends/openssl/hmac.py b/src/cryptography/hazmat/backends/openssl/hmac.py index ba3dfb53f8b3..669f380705e1 100644 --- a/src/cryptography/hazmat/backends/openssl/hmac.py +++ b/src/cryptography/hazmat/backends/openssl/hmac.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography.exceptions import ( @@ -18,7 +20,7 @@ class _HMACContext(hashes.HashContext): def __init__( self, - backend: "Backend", + backend: Backend, key: bytes, algorithm: hashes.HashAlgorithm, ctx=None, @@ -51,7 +53,7 @@ def __init__( def algorithm(self) -> hashes.HashAlgorithm: return self._algorithm - def copy(self) -> "_HMACContext": + def copy(self) -> _HMACContext: copied_ctx = self._backend._lib.HMAC_CTX_new() self._backend.openssl_assert(copied_ctx != self._backend._ffi.NULL) copied_ctx = self._backend._ffi.gc( diff --git a/src/cryptography/hazmat/backends/openssl/poly1305.py b/src/cryptography/hazmat/backends/openssl/poly1305.py index d0d44f6fd96e..bb0c3738b667 100644 --- a/src/cryptography/hazmat/backends/openssl/poly1305.py +++ b/src/cryptography/hazmat/backends/openssl/poly1305.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography.exceptions import InvalidSignature @@ -16,7 +18,7 @@ class _Poly1305Context: - def __init__(self, backend: "Backend", key: bytes) -> None: + def __init__(self, backend: Backend, key: bytes) -> None: self._backend = backend key_ptr = self._backend._ffi.from_buffer(key) diff --git a/src/cryptography/hazmat/backends/openssl/rsa.py b/src/cryptography/hazmat/backends/openssl/rsa.py index c960105e718e..f8ca3341af85 100644 --- a/src/cryptography/hazmat/backends/openssl/rsa.py +++ b/src/cryptography/hazmat/backends/openssl/rsa.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import threading import typing @@ -38,7 +40,7 @@ def _get_rsa_pss_salt_length( - backend: "Backend", + backend: Backend, pss: PSS, key: typing.Union[RSAPrivateKey, RSAPublicKey], hash_algorithm: hashes.HashAlgorithm, @@ -60,8 +62,8 @@ def _get_rsa_pss_salt_length( def _enc_dec_rsa( - backend: "Backend", - key: typing.Union["_RSAPrivateKey", "_RSAPublicKey"], + backend: Backend, + key: typing.Union[_RSAPrivateKey, _RSAPublicKey], data: bytes, padding: AsymmetricPadding, ) -> bytes: @@ -96,8 +98,8 @@ def _enc_dec_rsa( def _enc_dec_rsa_pkey_ctx( - backend: "Backend", - key: typing.Union["_RSAPrivateKey", "_RSAPublicKey"], + backend: Backend, + key: typing.Union[_RSAPrivateKey, _RSAPublicKey], data: bytes, padding_enum: int, padding: AsymmetricPadding, @@ -163,8 +165,8 @@ def _enc_dec_rsa_pkey_ctx( def _rsa_sig_determine_padding( - backend: "Backend", - key: typing.Union["_RSAPrivateKey", "_RSAPublicKey"], + backend: Backend, + key: typing.Union[_RSAPrivateKey, _RSAPublicKey], padding: AsymmetricPadding, algorithm: typing.Optional[hashes.HashAlgorithm], ) -> int: @@ -211,10 +213,10 @@ def _rsa_sig_determine_padding( # padding type, where it means that the signature data is encoded/decoded # as provided, without being wrapped in a DigestInfo structure. def _rsa_sig_setup( - backend: "Backend", + backend: Backend, padding: AsymmetricPadding, algorithm: typing.Optional[hashes.HashAlgorithm], - key: typing.Union["_RSAPublicKey", "_RSAPrivateKey"], + key: typing.Union[_RSAPublicKey, _RSAPrivateKey], init_func: typing.Callable[[typing.Any], int], ): padding_enum = _rsa_sig_determine_padding(backend, key, padding, algorithm) @@ -264,10 +266,10 @@ def _rsa_sig_setup( def _rsa_sig_sign( - backend: "Backend", + backend: Backend, padding: AsymmetricPadding, algorithm: hashes.HashAlgorithm, - private_key: "_RSAPrivateKey", + private_key: _RSAPrivateKey, data: bytes, ) -> bytes: pkey_ctx = _rsa_sig_setup( @@ -296,10 +298,10 @@ def _rsa_sig_sign( def _rsa_sig_verify( - backend: "Backend", + backend: Backend, padding: AsymmetricPadding, algorithm: hashes.HashAlgorithm, - public_key: "_RSAPublicKey", + public_key: _RSAPublicKey, signature: bytes, data: bytes, ) -> None: @@ -323,10 +325,10 @@ def _rsa_sig_verify( def _rsa_sig_recover( - backend: "Backend", + backend: Backend, padding: AsymmetricPadding, algorithm: typing.Optional[hashes.HashAlgorithm], - public_key: "_RSAPublicKey", + public_key: _RSAPublicKey, signature: bytes, ) -> bytes: pkey_ctx = _rsa_sig_setup( @@ -365,7 +367,7 @@ class _RSAPrivateKey(RSAPrivateKey): def __init__( self, - backend: "Backend", + backend: Backend, rsa_cdata, evp_pkey, *, @@ -516,7 +518,7 @@ class _RSAPublicKey(RSAPublicKey): _rsa_cdata: object _key_size: int - def __init__(self, backend: "Backend", rsa_cdata, evp_pkey): + def __init__(self, backend: Backend, rsa_cdata, evp_pkey): self._backend = backend self._rsa_cdata = rsa_cdata self._evp_pkey = evp_pkey diff --git a/src/cryptography/hazmat/backends/openssl/utils.py b/src/cryptography/hazmat/backends/openssl/utils.py index 64b4a8334b51..5b404defde33 100644 --- a/src/cryptography/hazmat/backends/openssl/utils.py +++ b/src/cryptography/hazmat/backends/openssl/utils.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography.hazmat.primitives import hashes @@ -11,7 +13,7 @@ from cryptography.hazmat.backends.openssl.backend import Backend -def _evp_pkey_derive(backend: "Backend", evp_pkey, peer_public_key) -> bytes: +def _evp_pkey_derive(backend: Backend, evp_pkey, peer_public_key) -> bytes: ctx = backend._lib.EVP_PKEY_CTX_new(evp_pkey, backend._ffi.NULL) backend.openssl_assert(ctx != backend._ffi.NULL) ctx = backend._ffi.gc(ctx, backend._lib.EVP_PKEY_CTX_free) diff --git a/src/cryptography/hazmat/backends/openssl/x448.py b/src/cryptography/hazmat/backends/openssl/x448.py index d738188c71f7..5c91fba45279 100644 --- a/src/cryptography/hazmat/backends/openssl/x448.py +++ b/src/cryptography/hazmat/backends/openssl/x448.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography.hazmat.backends.openssl.utils import _evp_pkey_derive @@ -18,7 +20,7 @@ class _X448PublicKey(X448PublicKey): - def __init__(self, backend: "Backend", evp_pkey): + def __init__(self, backend: Backend, evp_pkey): self._backend = backend self._evp_pkey = evp_pkey @@ -57,7 +59,7 @@ def _raw_public_bytes(self) -> bytes: class _X448PrivateKey(X448PrivateKey): - def __init__(self, backend: "Backend", evp_pkey): + def __init__(self, backend: Backend, evp_pkey): self._backend = backend self._evp_pkey = evp_pkey diff --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py index 35829a2821da..95d5297d5711 100644 --- a/src/cryptography/hazmat/bindings/openssl/_conditional.py +++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py index 99061e21b421..b50d631518c1 100644 --- a/src/cryptography/hazmat/bindings/openssl/binding.py +++ b/src/cryptography/hazmat/bindings/openssl/binding.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import os import sys import threading diff --git a/src/cryptography/hazmat/primitives/_asymmetric.py b/src/cryptography/hazmat/primitives/_asymmetric.py index fb815a0e9154..ea55ffdf1a72 100644 --- a/src/cryptography/hazmat/primitives/_asymmetric.py +++ b/src/cryptography/hazmat/primitives/_asymmetric.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import abc # This exists to break an import cycle. It is normally accessible from the diff --git a/src/cryptography/hazmat/primitives/_cipheralgorithm.py b/src/cryptography/hazmat/primitives/_cipheralgorithm.py index b36dccfb3427..3b880b648849 100644 --- a/src/cryptography/hazmat/primitives/_cipheralgorithm.py +++ b/src/cryptography/hazmat/primitives/_cipheralgorithm.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import abc import typing diff --git a/src/cryptography/hazmat/primitives/_serialization.py b/src/cryptography/hazmat/primitives/_serialization.py index aa41f30d2586..34f3fbc86026 100644 --- a/src/cryptography/hazmat/primitives/_serialization.py +++ b/src/cryptography/hazmat/primitives/_serialization.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import abc import typing @@ -33,7 +35,7 @@ class PrivateFormat(utils.Enum): OpenSSH = "OpenSSH" PKCS12 = "PKCS12" - def encryption_builder(self) -> "KeySerializationEncryptionBuilder": + def encryption_builder(self) -> KeySerializationEncryptionBuilder: if self not in (PrivateFormat.OpenSSH, PrivateFormat.PKCS12): raise ValueError( "encryption_builder only supported with PrivateFormat.OpenSSH" @@ -86,7 +88,7 @@ def __init__( self._hmac_hash = _hmac_hash self._key_cert_algorithm = _key_cert_algorithm - def kdf_rounds(self, rounds: int) -> "KeySerializationEncryptionBuilder": + def kdf_rounds(self, rounds: int) -> KeySerializationEncryptionBuilder: if self._kdf_rounds is not None: raise ValueError("kdf_rounds already set") @@ -105,7 +107,7 @@ def kdf_rounds(self, rounds: int) -> "KeySerializationEncryptionBuilder": def hmac_hash( self, algorithm: HashAlgorithm - ) -> "KeySerializationEncryptionBuilder": + ) -> KeySerializationEncryptionBuilder: if self._format is not PrivateFormat.PKCS12: raise TypeError( "hmac_hash only supported with PrivateFormat.PKCS12" @@ -122,7 +124,7 @@ def hmac_hash( def key_cert_algorithm( self, algorithm: PBES - ) -> "KeySerializationEncryptionBuilder": + ) -> KeySerializationEncryptionBuilder: if self._format is not PrivateFormat.PKCS12: raise TypeError( "key_cert_algorithm only supported with " diff --git a/src/cryptography/hazmat/primitives/asymmetric/dh.py b/src/cryptography/hazmat/primitives/asymmetric/dh.py index debf01e134fa..272cc5e54671 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/dh.py +++ b/src/cryptography/hazmat/primitives/asymmetric/dh.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc import typing @@ -13,7 +14,7 @@ def generate_parameters( generator: int, key_size: int, backend: typing.Any = None -) -> "DHParameters": +) -> DHParameters: from cryptography.hazmat.backends.openssl.backend import backend as ossl return ossl.generate_dh_parameters(generator, key_size) @@ -46,7 +47,7 @@ def __eq__(self, other: object) -> bool: self._p == other._p and self._g == other._g and self._q == other._q ) - def parameters(self, backend: typing.Any = None) -> "DHParameters": + def parameters(self, backend: typing.Any = None) -> DHParameters: from cryptography.hazmat.backends.openssl.backend import ( backend as ossl, ) @@ -88,7 +89,7 @@ def __eq__(self, other: object) -> bool: and self._parameter_numbers == other._parameter_numbers ) - def public_key(self, backend: typing.Any = None) -> "DHPublicKey": + def public_key(self, backend: typing.Any = None) -> DHPublicKey: from cryptography.hazmat.backends.openssl.backend import ( backend as ossl, ) @@ -126,7 +127,7 @@ def __eq__(self, other: object) -> bool: and self._public_numbers == other._public_numbers ) - def private_key(self, backend: typing.Any = None) -> "DHPrivateKey": + def private_key(self, backend: typing.Any = None) -> DHPrivateKey: from cryptography.hazmat.backends.openssl.backend import ( backend as ossl, ) @@ -144,7 +145,7 @@ def x(self) -> int: class DHParameters(metaclass=abc.ABCMeta): @abc.abstractmethod - def generate_private_key(self) -> "DHPrivateKey": + def generate_private_key(self) -> DHPrivateKey: """ Generates and returns a DHPrivateKey. """ diff --git a/src/cryptography/hazmat/primitives/asymmetric/dsa.py b/src/cryptography/hazmat/primitives/asymmetric/dsa.py index 6103d809355f..e846d3e83a9c 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/dsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc import typing @@ -12,13 +13,13 @@ class DSAParameters(metaclass=abc.ABCMeta): @abc.abstractmethod - def generate_private_key(self) -> "DSAPrivateKey": + def generate_private_key(self) -> DSAPrivateKey: """ Generates and returns a DSAPrivateKey. """ @abc.abstractmethod - def parameter_numbers(self) -> "DSAParameterNumbers": + def parameter_numbers(self) -> DSAParameterNumbers: """ Returns a DSAParameterNumbers. """ @@ -36,7 +37,7 @@ def key_size(self) -> int: """ @abc.abstractmethod - def public_key(self) -> "DSAPublicKey": + def public_key(self) -> DSAPublicKey: """ The DSAPublicKey associated with this private key. """ @@ -58,7 +59,7 @@ def sign( """ @abc.abstractmethod - def private_numbers(self) -> "DSAPrivateNumbers": + def private_numbers(self) -> DSAPrivateNumbers: """ Returns a DSAPrivateNumbers. """ @@ -93,7 +94,7 @@ def parameters(self) -> DSAParameters: """ @abc.abstractmethod - def public_numbers(self) -> "DSAPublicNumbers": + def public_numbers(self) -> DSAPublicNumbers: """ Returns a DSAPublicNumbers. """ diff --git a/src/cryptography/hazmat/primitives/asymmetric/ec.py b/src/cryptography/hazmat/primitives/asymmetric/ec.py index c5df2c27a6e8..2e3b0108b194 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ec.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ec.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc import typing @@ -64,7 +65,7 @@ def algorithm( class EllipticCurvePrivateKey(metaclass=abc.ABCMeta): @abc.abstractmethod def exchange( - self, algorithm: "ECDH", peer_public_key: "EllipticCurvePublicKey" + self, algorithm: ECDH, peer_public_key: EllipticCurvePublicKey ) -> bytes: """ Performs a key exchange operation using the provided algorithm with the @@ -72,7 +73,7 @@ def exchange( """ @abc.abstractmethod - def public_key(self) -> "EllipticCurvePublicKey": + def public_key(self) -> EllipticCurvePublicKey: """ The EllipticCurvePublicKey for this private key. """ @@ -102,7 +103,7 @@ def sign( """ @abc.abstractmethod - def private_numbers(self) -> "EllipticCurvePrivateNumbers": + def private_numbers(self) -> EllipticCurvePrivateNumbers: """ Returns an EllipticCurvePrivateNumbers. """ @@ -138,7 +139,7 @@ def key_size(self) -> int: """ @abc.abstractmethod - def public_numbers(self) -> "EllipticCurvePublicNumbers": + def public_numbers(self) -> EllipticCurvePublicNumbers: """ Returns an EllipticCurvePublicNumbers. """ @@ -167,7 +168,7 @@ def verify( @classmethod def from_encoded_point( cls, curve: EllipticCurve, data: bytes - ) -> "EllipticCurvePublicKey": + ) -> EllipticCurvePublicKey: utils._check_bytes("data", data) if not isinstance(curve, EllipticCurve): diff --git a/src/cryptography/hazmat/primitives/asymmetric/ed25519.py b/src/cryptography/hazmat/primitives/asymmetric/ed25519.py index df34159ec7e0..83aa9d310e85 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ed25519.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ed25519.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc @@ -14,7 +15,7 @@ class Ed25519PublicKey(metaclass=abc.ABCMeta): @classmethod - def from_public_bytes(cls, data: bytes) -> "Ed25519PublicKey": + def from_public_bytes(cls, data: bytes) -> Ed25519PublicKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.ed25519_supported(): @@ -53,7 +54,7 @@ def verify(self, signature: bytes, data: bytes) -> None: class Ed25519PrivateKey(metaclass=abc.ABCMeta): @classmethod - def generate(cls) -> "Ed25519PrivateKey": + def generate(cls) -> Ed25519PrivateKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.ed25519_supported(): @@ -65,7 +66,7 @@ def generate(cls) -> "Ed25519PrivateKey": return backend.ed25519_generate_key() @classmethod - def from_private_bytes(cls, data: bytes) -> "Ed25519PrivateKey": + def from_private_bytes(cls, data: bytes) -> Ed25519PrivateKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.ed25519_supported(): diff --git a/src/cryptography/hazmat/primitives/asymmetric/ed448.py b/src/cryptography/hazmat/primitives/asymmetric/ed448.py index 8b0ac1fd87a3..c2a64796c2f4 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ed448.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ed448.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc @@ -11,7 +12,7 @@ class Ed448PublicKey(metaclass=abc.ABCMeta): @classmethod - def from_public_bytes(cls, data: bytes) -> "Ed448PublicKey": + def from_public_bytes(cls, data: bytes) -> Ed448PublicKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.ed448_supported(): @@ -50,7 +51,7 @@ def verify(self, signature: bytes, data: bytes) -> None: class Ed448PrivateKey(metaclass=abc.ABCMeta): @classmethod - def generate(cls) -> "Ed448PrivateKey": + def generate(cls) -> Ed448PrivateKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.ed448_supported(): @@ -61,7 +62,7 @@ def generate(cls) -> "Ed448PrivateKey": return backend.ed448_generate_key() @classmethod - def from_private_bytes(cls, data: bytes) -> "Ed448PrivateKey": + def from_private_bytes(cls, data: bytes) -> Ed448PrivateKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.ed448_supported(): diff --git a/src/cryptography/hazmat/primitives/asymmetric/padding.py b/src/cryptography/hazmat/primitives/asymmetric/padding.py index dd3c648f165e..7198808effd0 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/padding.py +++ b/src/cryptography/hazmat/primitives/asymmetric/padding.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc import typing @@ -38,7 +39,7 @@ class PSS(AsymmetricPadding): def __init__( self, - mgf: "MGF", + mgf: MGF, salt_length: typing.Union[int, _MaxLength, _Auto, _DigestLength], ) -> None: self._mgf = mgf @@ -62,7 +63,7 @@ class OAEP(AsymmetricPadding): def __init__( self, - mgf: "MGF", + mgf: MGF, algorithm: hashes.HashAlgorithm, label: typing.Optional[bytes], ): @@ -89,7 +90,7 @@ def __init__(self, algorithm: hashes.HashAlgorithm): def calculate_max_pss_salt_length( - key: typing.Union["rsa.RSAPrivateKey", "rsa.RSAPublicKey"], + key: typing.Union[rsa.RSAPrivateKey, rsa.RSAPublicKey], hash_algorithm: hashes.HashAlgorithm, ) -> int: if not isinstance(key, (rsa.RSAPrivateKey, rsa.RSAPublicKey)): diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py index 81f5a0ec639f..c83f7fc88999 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc import typing @@ -27,7 +28,7 @@ def key_size(self) -> int: """ @abc.abstractmethod - def public_key(self) -> "RSAPublicKey": + def public_key(self) -> RSAPublicKey: """ The RSAPublicKey associated with this private key. """ @@ -44,7 +45,7 @@ def sign( """ @abc.abstractmethod - def private_numbers(self) -> "RSAPrivateNumbers": + def private_numbers(self) -> RSAPrivateNumbers: """ Returns an RSAPrivateNumbers. """ @@ -79,7 +80,7 @@ def key_size(self) -> int: """ @abc.abstractmethod - def public_numbers(self) -> "RSAPublicNumbers": + def public_numbers(self) -> RSAPublicNumbers: """ Returns an RSAPublicNumbers """ @@ -297,7 +298,7 @@ def __init__( dmp1: int, dmq1: int, iqmp: int, - public_numbers: "RSAPublicNumbers", + public_numbers: RSAPublicNumbers, ): if ( not isinstance(p, int) @@ -351,7 +352,7 @@ def iqmp(self) -> int: return self._iqmp @property - def public_numbers(self) -> "RSAPublicNumbers": + def public_numbers(self) -> RSAPublicNumbers: return self._public_numbers def private_key( diff --git a/src/cryptography/hazmat/primitives/asymmetric/types.py b/src/cryptography/hazmat/primitives/asymmetric/types.py index e911a9f602c2..1fe4eaf51d85 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/types.py +++ b/src/cryptography/hazmat/primitives/asymmetric/types.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography import utils diff --git a/src/cryptography/hazmat/primitives/asymmetric/utils.py b/src/cryptography/hazmat/primitives/asymmetric/utils.py index 140ca1960d9f..826b9567b47b 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/utils.py +++ b/src/cryptography/hazmat/primitives/asymmetric/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. +from __future__ import annotations from cryptography.hazmat.bindings._rust import asn1 from cryptography.hazmat.primitives import hashes diff --git a/src/cryptography/hazmat/primitives/asymmetric/x25519.py b/src/cryptography/hazmat/primitives/asymmetric/x25519.py index fb21fe1749a5..5455751508c4 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/x25519.py +++ b/src/cryptography/hazmat/primitives/asymmetric/x25519.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc @@ -12,7 +13,7 @@ class X25519PublicKey(metaclass=abc.ABCMeta): @classmethod - def from_public_bytes(cls, data: bytes) -> "X25519PublicKey": + def from_public_bytes(cls, data: bytes) -> X25519PublicKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.x25519_supported(): @@ -48,7 +49,7 @@ def public_bytes_raw(self) -> bytes: class X25519PrivateKey(metaclass=abc.ABCMeta): @classmethod - def generate(cls) -> "X25519PrivateKey": + def generate(cls) -> X25519PrivateKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.x25519_supported(): @@ -59,7 +60,7 @@ def generate(cls) -> "X25519PrivateKey": return backend.x25519_generate_key() @classmethod - def from_private_bytes(cls, data: bytes) -> "X25519PrivateKey": + def from_private_bytes(cls, data: bytes) -> X25519PrivateKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.x25519_supported(): diff --git a/src/cryptography/hazmat/primitives/asymmetric/x448.py b/src/cryptography/hazmat/primitives/asymmetric/x448.py index dcab0445a4f7..25ff4c6ec36a 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/x448.py +++ b/src/cryptography/hazmat/primitives/asymmetric/x448.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc @@ -11,7 +12,7 @@ class X448PublicKey(metaclass=abc.ABCMeta): @classmethod - def from_public_bytes(cls, data: bytes) -> "X448PublicKey": + def from_public_bytes(cls, data: bytes) -> X448PublicKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.x448_supported(): @@ -44,7 +45,7 @@ def public_bytes_raw(self) -> bytes: class X448PrivateKey(metaclass=abc.ABCMeta): @classmethod - def generate(cls) -> "X448PrivateKey": + def generate(cls) -> X448PrivateKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.x448_supported(): @@ -55,7 +56,7 @@ def generate(cls) -> "X448PrivateKey": return backend.x448_generate_key() @classmethod - def from_private_bytes(cls, data: bytes) -> "X448PrivateKey": + def from_private_bytes(cls, data: bytes) -> X448PrivateKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.x448_supported(): diff --git a/src/cryptography/hazmat/primitives/ciphers/__init__.py b/src/cryptography/hazmat/primitives/ciphers/__init__.py index 95f02842ad1a..cc88fbf2c4c3 100644 --- a/src/cryptography/hazmat/primitives/ciphers/__init__.py +++ b/src/cryptography/hazmat/primitives/ciphers/__init__.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations from cryptography.hazmat.primitives._cipheralgorithm import ( BlockCipherAlgorithm, diff --git a/src/cryptography/hazmat/primitives/ciphers/aead.py b/src/cryptography/hazmat/primitives/ciphers/aead.py index f2e206bbfa5d..957b2d221b62 100644 --- a/src/cryptography/hazmat/primitives/ciphers/aead.py +++ b/src/cryptography/hazmat/primitives/ciphers/aead.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import os import typing diff --git a/src/cryptography/hazmat/primitives/ciphers/algorithms.py b/src/cryptography/hazmat/primitives/ciphers/algorithms.py index 4357c17acab0..4bfc5d840d67 100644 --- a/src/cryptography/hazmat/primitives/ciphers/algorithms.py +++ b/src/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations from cryptography import utils from cryptography.hazmat.primitives.ciphers import ( diff --git a/src/cryptography/hazmat/primitives/ciphers/base.py b/src/cryptography/hazmat/primitives/ciphers/base.py index d80ef3f15d34..38a2ebbe081e 100644 --- a/src/cryptography/hazmat/primitives/ciphers/base.py +++ b/src/cryptography/hazmat/primitives/ciphers/base.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc import typing @@ -95,13 +96,13 @@ def __init__( @typing.overload def encryptor( - self: "Cipher[modes.ModeWithAuthenticationTag]", + self: Cipher[modes.ModeWithAuthenticationTag], ) -> AEADEncryptionContext: ... @typing.overload def encryptor( - self: "_CIPHER_TYPE", + self: _CIPHER_TYPE, ) -> CipherContext: ... @@ -120,13 +121,13 @@ def encryptor(self): @typing.overload def decryptor( - self: "Cipher[modes.ModeWithAuthenticationTag]", + self: Cipher[modes.ModeWithAuthenticationTag], ) -> AEADDecryptionContext: ... @typing.overload def decryptor( - self: "_CIPHER_TYPE", + self: _CIPHER_TYPE, ) -> CipherContext: ... @@ -139,7 +140,7 @@ def decryptor(self): return self._wrap_ctx(ctx, encrypt=False) def _wrap_ctx( - self, ctx: "_BackendCipherContext", encrypt: bool + self, ctx: _BackendCipherContext, encrypt: bool ) -> typing.Union[ AEADEncryptionContext, AEADDecryptionContext, CipherContext ]: @@ -164,9 +165,9 @@ def _wrap_ctx( class _CipherContext(CipherContext): - _ctx: typing.Optional["_BackendCipherContext"] + _ctx: typing.Optional[_BackendCipherContext] - def __init__(self, ctx: "_BackendCipherContext") -> None: + def __init__(self, ctx: _BackendCipherContext) -> None: self._ctx = ctx def update(self, data: bytes) -> bytes: @@ -188,10 +189,10 @@ def finalize(self) -> bytes: class _AEADCipherContext(AEADCipherContext): - _ctx: typing.Optional["_BackendCipherContext"] + _ctx: typing.Optional[_BackendCipherContext] _tag: typing.Optional[bytes] - def __init__(self, ctx: "_BackendCipherContext") -> None: + def __init__(self, ctx: _BackendCipherContext) -> None: self._ctx = ctx self._bytes_processed = 0 self._aad_bytes_processed = 0 diff --git a/src/cryptography/hazmat/primitives/ciphers/modes.py b/src/cryptography/hazmat/primitives/ciphers/modes.py index 1fba397feb7a..d8ea1888d67b 100644 --- a/src/cryptography/hazmat/primitives/ciphers/modes.py +++ b/src/cryptography/hazmat/primitives/ciphers/modes.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc import typing diff --git a/src/cryptography/hazmat/primitives/cmac.py b/src/cryptography/hazmat/primitives/cmac.py index 00c4bd11d877..8aa1d791acdd 100644 --- a/src/cryptography/hazmat/primitives/cmac.py +++ b/src/cryptography/hazmat/primitives/cmac.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import typing @@ -14,14 +15,14 @@ class CMAC: - _ctx: typing.Optional["_CMACContext"] + _ctx: typing.Optional[_CMACContext] _algorithm: ciphers.BlockCipherAlgorithm def __init__( self, algorithm: ciphers.BlockCipherAlgorithm, backend: typing.Any = None, - ctx: typing.Optional["_CMACContext"] = None, + ctx: typing.Optional[_CMACContext] = None, ) -> None: if not isinstance(algorithm, ciphers.BlockCipherAlgorithm): raise TypeError("Expected instance of BlockCipherAlgorithm.") @@ -58,7 +59,7 @@ def verify(self, signature: bytes) -> None: ctx, self._ctx = self._ctx, None ctx.verify(signature) - def copy(self) -> "CMAC": + def copy(self) -> CMAC: if self._ctx is None: raise AlreadyFinalized("Context was already finalized.") return CMAC(self._algorithm, ctx=self._ctx.copy()) diff --git a/src/cryptography/hazmat/primitives/constant_time.py b/src/cryptography/hazmat/primitives/constant_time.py index a02fa9c45345..3975c7147eb9 100644 --- a/src/cryptography/hazmat/primitives/constant_time.py +++ b/src/cryptography/hazmat/primitives/constant_time.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import hmac diff --git a/src/cryptography/hazmat/primitives/hashes.py b/src/cryptography/hazmat/primitives/hashes.py index 6bbab4c0b92a..c4b7d1060ada 100644 --- a/src/cryptography/hazmat/primitives/hashes.py +++ b/src/cryptography/hazmat/primitives/hashes.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import abc import typing @@ -54,7 +56,7 @@ def finalize(self) -> bytes: """ @abc.abstractmethod - def copy(self) -> "HashContext": + def copy(self) -> HashContext: """ Return a HashContext that is a copy of the current context. """ @@ -73,7 +75,7 @@ def __init__( self, algorithm: HashAlgorithm, backend: typing.Any = None, - ctx: typing.Optional["HashContext"] = None, + ctx: typing.Optional[HashContext] = None, ) -> None: if not isinstance(algorithm, HashAlgorithm): raise TypeError("Expected instance of hashes.HashAlgorithm.") @@ -98,7 +100,7 @@ def update(self, data: bytes) -> None: utils._check_byteslike("data", data) self._ctx.update(data) - def copy(self) -> "Hash": + def copy(self) -> Hash: if self._ctx is None: raise AlreadyFinalized("Context was already finalized.") return Hash(self.algorithm, ctx=self._ctx.copy()) diff --git a/src/cryptography/hazmat/primitives/hmac.py b/src/cryptography/hazmat/primitives/hmac.py index 8f1c0eae6e1f..6627f57499ec 100644 --- a/src/cryptography/hazmat/primitives/hmac.py +++ b/src/cryptography/hazmat/primitives/hmac.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import typing @@ -45,7 +46,7 @@ def update(self, data: bytes) -> None: utils._check_byteslike("data", data) self._ctx.update(data) - def copy(self) -> "HMAC": + def copy(self) -> HMAC: if self._ctx is None: raise AlreadyFinalized("Context was already finalized.") return HMAC( diff --git a/src/cryptography/hazmat/primitives/kdf/__init__.py b/src/cryptography/hazmat/primitives/kdf/__init__.py index 38e2f8bc4d66..79bb459f01ec 100644 --- a/src/cryptography/hazmat/primitives/kdf/__init__.py +++ b/src/cryptography/hazmat/primitives/kdf/__init__.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc diff --git a/src/cryptography/hazmat/primitives/kdf/concatkdf.py b/src/cryptography/hazmat/primitives/kdf/concatkdf.py index 7bbce4ffcdbc..d5ea58a94522 100644 --- a/src/cryptography/hazmat/primitives/kdf/concatkdf.py +++ b/src/cryptography/hazmat/primitives/kdf/concatkdf.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import typing diff --git a/src/cryptography/hazmat/primitives/kdf/hkdf.py b/src/cryptography/hazmat/primitives/kdf/hkdf.py index 7d59a7ef77b9..d47689443631 100644 --- a/src/cryptography/hazmat/primitives/kdf/hkdf.py +++ b/src/cryptography/hazmat/primitives/kdf/hkdf.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import typing diff --git a/src/cryptography/hazmat/primitives/kdf/kbkdf.py b/src/cryptography/hazmat/primitives/kdf/kbkdf.py index 7f185a9af8d1..967763828f3f 100644 --- a/src/cryptography/hazmat/primitives/kdf/kbkdf.py +++ b/src/cryptography/hazmat/primitives/kdf/kbkdf.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography import utils diff --git a/src/cryptography/hazmat/primitives/kdf/pbkdf2.py b/src/cryptography/hazmat/primitives/kdf/pbkdf2.py index 8d23f8c250d1..2caa50e80a19 100644 --- a/src/cryptography/hazmat/primitives/kdf/pbkdf2.py +++ b/src/cryptography/hazmat/primitives/kdf/pbkdf2.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import typing diff --git a/src/cryptography/hazmat/primitives/kdf/scrypt.py b/src/cryptography/hazmat/primitives/kdf/scrypt.py index 286f4388cb2a..6443832aa382 100644 --- a/src/cryptography/hazmat/primitives/kdf/scrypt.py +++ b/src/cryptography/hazmat/primitives/kdf/scrypt.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import sys import typing diff --git a/src/cryptography/hazmat/primitives/kdf/x963kdf.py b/src/cryptography/hazmat/primitives/kdf/x963kdf.py index 4ab64d08b1c5..17acc5174bb0 100644 --- a/src/cryptography/hazmat/primitives/kdf/x963kdf.py +++ b/src/cryptography/hazmat/primitives/kdf/x963kdf.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import typing diff --git a/src/cryptography/hazmat/primitives/keywrap.py b/src/cryptography/hazmat/primitives/keywrap.py index 64771ca3c5b0..59b0326c2a86 100644 --- a/src/cryptography/hazmat/primitives/keywrap.py +++ b/src/cryptography/hazmat/primitives/keywrap.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import typing diff --git a/src/cryptography/hazmat/primitives/padding.py b/src/cryptography/hazmat/primitives/padding.py index d6c1d9152820..fde3094b00ae 100644 --- a/src/cryptography/hazmat/primitives/padding.py +++ b/src/cryptography/hazmat/primitives/padding.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc import typing diff --git a/src/cryptography/hazmat/primitives/poly1305.py b/src/cryptography/hazmat/primitives/poly1305.py index 7fcf4a50f575..77df07f02e68 100644 --- a/src/cryptography/hazmat/primitives/poly1305.py +++ b/src/cryptography/hazmat/primitives/poly1305.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography import utils diff --git a/src/cryptography/hazmat/primitives/serialization/__init__.py b/src/cryptography/hazmat/primitives/serialization/__init__.py index 213c49958a74..b6c9a5cdc520 100644 --- a/src/cryptography/hazmat/primitives/serialization/__init__.py +++ b/src/cryptography/hazmat/primitives/serialization/__init__.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations from cryptography.hazmat.primitives._serialization import ( BestAvailableEncryption, diff --git a/src/cryptography/hazmat/primitives/serialization/base.py b/src/cryptography/hazmat/primitives/serialization/base.py index 7956ce0feb3f..18a96ccfd5cd 100644 --- a/src/cryptography/hazmat/primitives/serialization/base.py +++ b/src/cryptography/hazmat/primitives/serialization/base.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import typing @@ -36,7 +37,7 @@ def load_pem_public_key( def load_pem_parameters( data: bytes, backend: typing.Any = None -) -> "dh.DHParameters": +) -> dh.DHParameters: from cryptography.hazmat.backends.openssl.backend import backend as ossl return ossl.load_pem_parameters(data) @@ -66,7 +67,7 @@ def load_der_public_key( def load_der_parameters( data: bytes, backend: typing.Any = None -) -> "dh.DHParameters": +) -> dh.DHParameters: from cryptography.hazmat.backends.openssl.backend import backend as ossl return ossl.load_der_parameters(data) diff --git a/src/cryptography/hazmat/primitives/serialization/pkcs12.py b/src/cryptography/hazmat/primitives/serialization/pkcs12.py index 1d36146a97e4..27133a3fa851 100644 --- a/src/cryptography/hazmat/primitives/serialization/pkcs12.py +++ b/src/cryptography/hazmat/primitives/serialization/pkcs12.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography import x509 diff --git a/src/cryptography/hazmat/primitives/serialization/pkcs7.py b/src/cryptography/hazmat/primitives/serialization/pkcs7.py index 0a72e0df80d5..9998bcaa1131 100644 --- a/src/cryptography/hazmat/primitives/serialization/pkcs7.py +++ b/src/cryptography/hazmat/primitives/serialization/pkcs7.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import email.base64mime import email.generator import email.message @@ -73,7 +75,7 @@ def __init__( self._signers = signers self._additional_certs = additional_certs - def set_data(self, data: bytes) -> "PKCS7SignatureBuilder": + def set_data(self, data: bytes) -> PKCS7SignatureBuilder: _check_byteslike("data", data) if self._data is not None: raise ValueError("data may only be set once") @@ -85,7 +87,7 @@ def add_signer( certificate: x509.Certificate, private_key: PKCS7PrivateKeyTypes, hash_algorithm: PKCS7HashTypes, - ) -> "PKCS7SignatureBuilder": + ) -> PKCS7SignatureBuilder: if not isinstance( hash_algorithm, ( @@ -114,7 +116,7 @@ def add_signer( def add_certificate( self, certificate: x509.Certificate - ) -> "PKCS7SignatureBuilder": + ) -> PKCS7SignatureBuilder: if not isinstance(certificate, x509.Certificate): raise TypeError("certificate must be a x509.Certificate") diff --git a/src/cryptography/hazmat/primitives/serialization/ssh.py b/src/cryptography/hazmat/primitives/serialization/ssh.py index fa278d9ed47a..90261845143a 100644 --- a/src/cryptography/hazmat/primitives/serialization/ssh.py +++ b/src/cryptography/hazmat/primitives/serialization/ssh.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import binascii import enum @@ -100,7 +101,7 @@ def _bcrypt_kdf( def _get_ssh_key_type( - key: typing.Union["SSHPrivateKeyTypes", "SSHPublicKeyTypes"] + key: typing.Union[SSHPrivateKeyTypes, SSHPublicKeyTypes] ) -> bytes: if isinstance(key, ec.EllipticCurvePrivateKey): key_type = _ecdsa_key_type(key.public_key()) @@ -229,7 +230,7 @@ def put_u64(self, val: int) -> None: """Big-endian uint64""" self.flist.append(val.to_bytes(length=8, byteorder="big")) - def put_sshstr(self, val: typing.Union[bytes, "_FragList"]) -> None: + def put_sshstr(self, val: typing.Union[bytes, _FragList]) -> None: """Bytes prefixed with u32 length""" if isinstance(val, (bytes, memoryview, bytearray)): self.put_u32(len(val)) @@ -1084,7 +1085,7 @@ def __init__( def public_key( self, public_key: SSHCertPublicKeyTypes - ) -> "SSHCertificateBuilder": + ) -> SSHCertificateBuilder: if not isinstance( public_key, ( @@ -1110,7 +1111,7 @@ def public_key( _extensions=self._extensions, ) - def serial(self, serial: int) -> "SSHCertificateBuilder": + def serial(self, serial: int) -> SSHCertificateBuilder: if not isinstance(serial, int): raise TypeError("serial must be an integer") if not 0 <= serial < 2**64: @@ -1131,7 +1132,7 @@ def serial(self, serial: int) -> "SSHCertificateBuilder": _extensions=self._extensions, ) - def type(self, type: SSHCertificateType) -> "SSHCertificateBuilder": + def type(self, type: SSHCertificateType) -> SSHCertificateBuilder: if not isinstance(type, SSHCertificateType): raise TypeError("type must be an SSHCertificateType") if self._type is not None: @@ -1150,7 +1151,7 @@ def type(self, type: SSHCertificateType) -> "SSHCertificateBuilder": _extensions=self._extensions, ) - def key_id(self, key_id: bytes) -> "SSHCertificateBuilder": + def key_id(self, key_id: bytes) -> SSHCertificateBuilder: if not isinstance(key_id, bytes): raise TypeError("key_id must be bytes") if self._key_id is not None: @@ -1171,7 +1172,7 @@ def key_id(self, key_id: bytes) -> "SSHCertificateBuilder": def valid_principals( self, valid_principals: typing.List[bytes] - ) -> "SSHCertificateBuilder": + ) -> SSHCertificateBuilder: if self._valid_for_all_principals: raise ValueError( "Principals can't be set because the cert is valid " @@ -1229,7 +1230,7 @@ def valid_for_all_principals(self): def valid_before( self, valid_before: typing.Union[int, float] - ) -> "SSHCertificateBuilder": + ) -> SSHCertificateBuilder: if not isinstance(valid_before, (int, float)): raise TypeError("valid_before must be an int or float") valid_before = int(valid_before) @@ -1253,7 +1254,7 @@ def valid_before( def valid_after( self, valid_after: typing.Union[int, float] - ) -> "SSHCertificateBuilder": + ) -> SSHCertificateBuilder: if not isinstance(valid_after, (int, float)): raise TypeError("valid_after must be an int or float") valid_after = int(valid_after) @@ -1277,7 +1278,7 @@ def valid_after( def add_critical_option( self, name: bytes, value: bytes - ) -> "SSHCertificateBuilder": + ) -> SSHCertificateBuilder: if not isinstance(name, bytes) or not isinstance(value, bytes): raise TypeError("name and value must be bytes") # This is O(n**2) @@ -1299,7 +1300,7 @@ def add_critical_option( def add_extension( self, name: bytes, value: bytes - ) -> "SSHCertificateBuilder": + ) -> SSHCertificateBuilder: if not isinstance(name, bytes) or not isinstance(value, bytes): raise TypeError("name and value must be bytes") # This is O(n**2) diff --git a/src/cryptography/hazmat/primitives/twofactor/__init__.py b/src/cryptography/hazmat/primitives/twofactor/__init__.py index 8a8b30f2aa8f..c1af42300486 100644 --- a/src/cryptography/hazmat/primitives/twofactor/__init__.py +++ b/src/cryptography/hazmat/primitives/twofactor/__init__.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + class InvalidToken(Exception): pass diff --git a/src/cryptography/hazmat/primitives/twofactor/hotp.py b/src/cryptography/hazmat/primitives/twofactor/hotp.py index 260822214db9..2067108a63d6 100644 --- a/src/cryptography/hazmat/primitives/twofactor/hotp.py +++ b/src/cryptography/hazmat/primitives/twofactor/hotp.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import base64 import typing @@ -15,7 +16,7 @@ def _generate_uri( - hotp: "HOTP", + hotp: HOTP, type_name: str, account_name: str, issuer: typing.Optional[str], diff --git a/src/cryptography/hazmat/primitives/twofactor/totp.py b/src/cryptography/hazmat/primitives/twofactor/totp.py index c66fa1de13c9..daddcea2f77e 100644 --- a/src/cryptography/hazmat/primitives/twofactor/totp.py +++ b/src/cryptography/hazmat/primitives/twofactor/totp.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import typing from cryptography.hazmat.primitives import constant_time diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index c8a5ee83139b..651e8509acf4 100644 --- a/src/cryptography/utils.py +++ b/src/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. +from __future__ import annotations import enum import sys diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py index df7fd3fbb5bb..6d4a10eab579 100644 --- a/src/cryptography/x509/__init__.py +++ b/src/cryptography/x509/__init__.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations from cryptography.x509 import certificate_transparency from cryptography.x509.base import ( diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index 35c846d34eda..63eaa6bd4013 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc import datetime @@ -279,7 +280,7 @@ def public_bytes(self, encoding: serialization.Encoding) -> bytes: """ @abc.abstractmethod - def verify_directly_issued_by(self, issuer: "Certificate") -> None: + def verify_directly_issued_by(self, issuer: Certificate) -> None: """ This method verifies that certificate issuer name matches the issuer subject name and that the certificate is signed by the @@ -627,7 +628,7 @@ def __init__( self._extensions = extensions self._attributes = attributes - def subject_name(self, name: Name) -> "CertificateSigningRequestBuilder": + def subject_name(self, name: Name) -> CertificateSigningRequestBuilder: """ Sets the certificate requestor's distinguished name. """ @@ -641,7 +642,7 @@ def subject_name(self, name: Name) -> "CertificateSigningRequestBuilder": def add_extension( self, extval: ExtensionType, critical: bool - ) -> "CertificateSigningRequestBuilder": + ) -> CertificateSigningRequestBuilder: """ Adds an X.509 extension to the certificate request. """ @@ -663,7 +664,7 @@ def add_attribute( value: bytes, *, _tag: typing.Optional[_ASN1Type] = None, - ) -> "CertificateSigningRequestBuilder": + ) -> CertificateSigningRequestBuilder: """ Adds an X.509 attribute with an OID and associated value. """ @@ -725,7 +726,7 @@ def __init__( self._not_valid_after = not_valid_after self._extensions = extensions - def issuer_name(self, name: Name) -> "CertificateBuilder": + def issuer_name(self, name: Name) -> CertificateBuilder: """ Sets the CA's distinguished name. """ @@ -743,7 +744,7 @@ def issuer_name(self, name: Name) -> "CertificateBuilder": self._extensions, ) - def subject_name(self, name: Name) -> "CertificateBuilder": + def subject_name(self, name: Name) -> CertificateBuilder: """ Sets the requestor's distinguished name. """ @@ -764,7 +765,7 @@ def subject_name(self, name: Name) -> "CertificateBuilder": def public_key( self, key: CertificatePublicKeyTypes, - ) -> "CertificateBuilder": + ) -> CertificateBuilder: """ Sets the requestor's public key (as found in the signing request). """ @@ -798,7 +799,7 @@ def public_key( self._extensions, ) - def serial_number(self, number: int) -> "CertificateBuilder": + def serial_number(self, number: int) -> CertificateBuilder: """ Sets the certificate serial number. """ @@ -825,9 +826,7 @@ def serial_number(self, number: int) -> "CertificateBuilder": self._extensions, ) - def not_valid_before( - self, time: datetime.datetime - ) -> "CertificateBuilder": + def not_valid_before(self, time: datetime.datetime) -> CertificateBuilder: """ Sets the certificate activation time. """ @@ -856,7 +855,7 @@ def not_valid_before( self._extensions, ) - def not_valid_after(self, time: datetime.datetime) -> "CertificateBuilder": + def not_valid_after(self, time: datetime.datetime) -> CertificateBuilder: """ Sets the certificate expiration time. """ @@ -890,7 +889,7 @@ def not_valid_after(self, time: datetime.datetime) -> "CertificateBuilder": def add_extension( self, extval: ExtensionType, critical: bool - ) -> "CertificateBuilder": + ) -> CertificateBuilder: """ Adds an X.509 extension to the certificate. """ @@ -960,7 +959,7 @@ def __init__( def issuer_name( self, issuer_name: Name - ) -> "CertificateRevocationListBuilder": + ) -> CertificateRevocationListBuilder: if not isinstance(issuer_name, Name): raise TypeError("Expecting x509.Name object.") if self._issuer_name is not None: @@ -975,7 +974,7 @@ def issuer_name( def last_update( self, last_update: datetime.datetime - ) -> "CertificateRevocationListBuilder": + ) -> CertificateRevocationListBuilder: if not isinstance(last_update, datetime.datetime): raise TypeError("Expecting datetime object.") if self._last_update is not None: @@ -999,7 +998,7 @@ def last_update( def next_update( self, next_update: datetime.datetime - ) -> "CertificateRevocationListBuilder": + ) -> CertificateRevocationListBuilder: if not isinstance(next_update, datetime.datetime): raise TypeError("Expecting datetime object.") if self._next_update is not None: @@ -1023,7 +1022,7 @@ def next_update( def add_extension( self, extval: ExtensionType, critical: bool - ) -> "CertificateRevocationListBuilder": + ) -> CertificateRevocationListBuilder: """ Adds an X.509 extension to the certificate revocation list. """ @@ -1042,7 +1041,7 @@ def add_extension( def add_revoked_certificate( self, revoked_certificate: RevokedCertificate - ) -> "CertificateRevocationListBuilder": + ) -> CertificateRevocationListBuilder: """ Adds a revoked certificate to the CRL. """ @@ -1086,7 +1085,7 @@ def __init__( self._revocation_date = revocation_date self._extensions = extensions - def serial_number(self, number: int) -> "RevokedCertificateBuilder": + 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: @@ -1106,7 +1105,7 @@ def serial_number(self, number: int) -> "RevokedCertificateBuilder": def revocation_date( self, time: datetime.datetime - ) -> "RevokedCertificateBuilder": + ) -> RevokedCertificateBuilder: if not isinstance(time, datetime.datetime): raise TypeError("Expecting datetime object.") if self._revocation_date is not None: @@ -1122,7 +1121,7 @@ def revocation_date( def add_extension( self, extval: ExtensionType, critical: bool - ) -> "RevokedCertificateBuilder": + ) -> RevokedCertificateBuilder: if not isinstance(extval, ExtensionType): raise TypeError("extension must be an ExtensionType") diff --git a/src/cryptography/x509/certificate_transparency.py b/src/cryptography/x509/certificate_transparency.py index a67709865d44..73647ee716fc 100644 --- a/src/cryptography/x509/certificate_transparency.py +++ b/src/cryptography/x509/certificate_transparency.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc import datetime diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 6fe3888bf788..981161a63b5b 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc import datetime @@ -111,13 +112,13 @@ def public_bytes(self) -> bytes: class Extensions: def __init__( - self, extensions: typing.Iterable["Extension[ExtensionType]"] + self, extensions: typing.Iterable[Extension[ExtensionType]] ) -> None: self._extensions = list(extensions) def get_extension_for_oid( self, oid: ObjectIdentifier - ) -> "Extension[ExtensionType]": + ) -> Extension[ExtensionType]: for ext in self: if ext.oid == oid: return ext @@ -126,7 +127,7 @@ def get_extension_for_oid( def get_extension_for_class( self, extclass: typing.Type[ExtensionTypeVar] - ) -> "Extension[ExtensionTypeVar]": + ) -> Extension[ExtensionTypeVar]: if extclass is UnrecognizedExtension: raise TypeError( "UnrecognizedExtension can't be used with " @@ -221,7 +222,7 @@ def __init__( @classmethod def from_issuer_public_key( cls, public_key: CertificateIssuerPublicKeyTypes - ) -> "AuthorityKeyIdentifier": + ) -> AuthorityKeyIdentifier: digest = _key_identifier_from_public_key(public_key) return cls( key_identifier=digest, @@ -231,8 +232,8 @@ def from_issuer_public_key( @classmethod def from_issuer_subject_key_identifier( - cls, ski: "SubjectKeyIdentifier" - ) -> "AuthorityKeyIdentifier": + cls, ski: SubjectKeyIdentifier + ) -> AuthorityKeyIdentifier: return cls( key_identifier=ski.digest, authority_cert_issuer=None, @@ -294,7 +295,7 @@ def __init__(self, digest: bytes) -> None: @classmethod def from_public_key( cls, public_key: CertificatePublicKeyTypes - ) -> "SubjectKeyIdentifier": + ) -> SubjectKeyIdentifier: return cls(_key_identifier_from_public_key(public_key)) @property @@ -325,7 +326,7 @@ class AuthorityInformationAccess(ExtensionType): oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS def __init__( - self, descriptions: typing.Iterable["AccessDescription"] + self, descriptions: typing.Iterable[AccessDescription] ) -> None: descriptions = list(descriptions) if not all(isinstance(x, AccessDescription) for x in descriptions): @@ -358,7 +359,7 @@ class SubjectInformationAccess(ExtensionType): oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS def __init__( - self, descriptions: typing.Iterable["AccessDescription"] + self, descriptions: typing.Iterable[AccessDescription] ) -> None: descriptions = list(descriptions) if not all(isinstance(x, AccessDescription) for x in descriptions): @@ -506,7 +507,7 @@ class CRLDistributionPoints(ExtensionType): oid = ExtensionOID.CRL_DISTRIBUTION_POINTS def __init__( - self, distribution_points: typing.Iterable["DistributionPoint"] + self, distribution_points: typing.Iterable[DistributionPoint] ) -> None: distribution_points = list(distribution_points) if not all( @@ -543,7 +544,7 @@ class FreshestCRL(ExtensionType): oid = ExtensionOID.FRESHEST_CRL def __init__( - self, distribution_points: typing.Iterable["DistributionPoint"] + self, distribution_points: typing.Iterable[DistributionPoint] ) -> None: distribution_points = list(distribution_points) if not all( @@ -581,7 +582,7 @@ def __init__( self, full_name: typing.Optional[typing.Iterable[GeneralName]], relative_name: typing.Optional[RelativeDistinguishedName], - reasons: typing.Optional[typing.FrozenSet["ReasonFlags"]], + reasons: typing.Optional[typing.FrozenSet[ReasonFlags]], crl_issuer: typing.Optional[typing.Iterable[GeneralName]], ) -> None: if full_name and relative_name: @@ -679,7 +680,7 @@ def relative_name(self) -> typing.Optional[RelativeDistinguishedName]: return self._relative_name @property - def reasons(self) -> typing.Optional[typing.FrozenSet["ReasonFlags"]]: + def reasons(self) -> typing.Optional[typing.FrozenSet[ReasonFlags]]: return self._reasons @property @@ -803,7 +804,7 @@ def public_bytes(self) -> bytes: class CertificatePolicies(ExtensionType): oid = ExtensionOID.CERTIFICATE_POLICIES - def __init__(self, policies: typing.Iterable["PolicyInformation"]) -> None: + def __init__(self, policies: typing.Iterable[PolicyInformation]) -> None: policies = list(policies) if not all(isinstance(x, PolicyInformation) for x in policies): raise TypeError( @@ -836,7 +837,7 @@ def __init__( self, policy_identifier: ObjectIdentifier, policy_qualifiers: typing.Optional[ - typing.Iterable[typing.Union[str, "UserNotice"]] + typing.Iterable[typing.Union[str, UserNotice]] ], ) -> None: if not isinstance(policy_identifier, ObjectIdentifier): @@ -874,7 +875,7 @@ def __eq__(self, other: object) -> bool: def __hash__(self) -> int: if self.policy_qualifiers is not None: pq: typing.Optional[ - typing.Tuple[typing.Union[str, "UserNotice"], ...] + typing.Tuple[typing.Union[str, UserNotice], ...] ] = tuple(self.policy_qualifiers) else: pq = None @@ -888,14 +889,14 @@ def policy_identifier(self) -> ObjectIdentifier: @property def policy_qualifiers( self, - ) -> typing.Optional[typing.List[typing.Union[str, "UserNotice"]]]: + ) -> typing.Optional[typing.List[typing.Union[str, UserNotice]]]: return self._policy_qualifiers class UserNotice: def __init__( self, - notice_reference: typing.Optional["NoticeReference"], + notice_reference: typing.Optional[NoticeReference], explicit_text: typing.Optional[str], ) -> None: if notice_reference and not isinstance( @@ -927,7 +928,7 @@ def __hash__(self) -> int: return hash((self.notice_reference, self.explicit_text)) @property - def notice_reference(self) -> typing.Optional["NoticeReference"]: + def notice_reference(self) -> typing.Optional[NoticeReference]: return self._notice_reference @property @@ -1046,7 +1047,7 @@ def public_bytes(self) -> bytes: class TLSFeature(ExtensionType): oid = ExtensionOID.TLS_FEATURE - def __init__(self, features: typing.Iterable["TLSFeatureType"]) -> None: + def __init__(self, features: typing.Iterable[TLSFeatureType]) -> None: features = list(features) if ( not all(isinstance(x, TLSFeatureType) for x in features) diff --git a/src/cryptography/x509/general_name.py b/src/cryptography/x509/general_name.py index ce8367b078d1..79271afbf91e 100644 --- a/src/cryptography/x509/general_name.py +++ b/src/cryptography/x509/general_name.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc import ipaddress @@ -59,7 +60,7 @@ def value(self) -> str: return self._value @classmethod - def _init_without_validation(cls, value: str) -> "RFC822Name": + def _init_without_validation(cls, value: str) -> RFC822Name: instance = cls.__new__(cls) instance._value = value return instance @@ -98,7 +99,7 @@ def value(self) -> str: return self._value @classmethod - def _init_without_validation(cls, value: str) -> "DNSName": + def _init_without_validation(cls, value: str) -> DNSName: instance = cls.__new__(cls) instance._value = value return instance @@ -137,9 +138,7 @@ def value(self) -> str: return self._value @classmethod - def _init_without_validation( - cls, value: str - ) -> "UniformResourceIdentifier": + 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 fd0782026392..ff98e8724af1 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + import binascii import re import sys @@ -300,7 +302,7 @@ def from_rfc4514_string( cls, data: str, attr_name_overrides: typing.Optional[_NameOidMap] = None, - ) -> "Name": + ) -> Name: return _RFC4514NameParser(data, attr_name_overrides or {}).parse() def rfc4514_string( diff --git a/src/cryptography/x509/ocsp.py b/src/cryptography/x509/ocsp.py index 857e75afc191..7054795fcda8 100644 --- a/src/cryptography/x509/ocsp.py +++ b/src/cryptography/x509/ocsp.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations import abc import datetime @@ -423,7 +424,7 @@ def add_certificate( cert: x509.Certificate, issuer: x509.Certificate, algorithm: hashes.HashAlgorithm, - ) -> "OCSPRequestBuilder": + ) -> OCSPRequestBuilder: if self._request is not None or self._request_hash is not None: raise ValueError("Only one certificate can be added to a request") @@ -443,7 +444,7 @@ def add_certificate_by_hash( issuer_key_hash: bytes, serial_number: int, algorithm: hashes.HashAlgorithm, - ) -> "OCSPRequestBuilder": + ) -> OCSPRequestBuilder: if self._request is not None or self._request_hash is not None: raise ValueError("Only one certificate can be added to a request") @@ -469,7 +470,7 @@ def add_certificate_by_hash( def add_extension( self, extval: x509.ExtensionType, critical: bool - ) -> "OCSPRequestBuilder": + ) -> OCSPRequestBuilder: if not isinstance(extval, x509.ExtensionType): raise TypeError("extension must be an ExtensionType") @@ -512,7 +513,7 @@ def add_response( next_update: typing.Optional[datetime.datetime], revocation_time: typing.Optional[datetime.datetime], revocation_reason: typing.Optional[x509.ReasonFlags], - ) -> "OCSPResponseBuilder": + ) -> OCSPResponseBuilder: if self._response is not None: raise ValueError("Only one response per OCSPResponse.") @@ -535,7 +536,7 @@ def add_response( def responder_id( self, encoding: OCSPResponderEncoding, responder_cert: x509.Certificate - ) -> "OCSPResponseBuilder": + ) -> OCSPResponseBuilder: if self._responder_id is not None: raise ValueError("responder_id can only be set once") if not isinstance(responder_cert, x509.Certificate): @@ -554,7 +555,7 @@ def responder_id( def certificates( self, certs: typing.Iterable[x509.Certificate] - ) -> "OCSPResponseBuilder": + ) -> OCSPResponseBuilder: if self._certs is not None: raise ValueError("certificates may only be set once") certs = list(certs) @@ -571,7 +572,7 @@ def certificates( def add_extension( self, extval: x509.ExtensionType, critical: bool - ) -> "OCSPResponseBuilder": + ) -> OCSPResponseBuilder: if not isinstance(extval, x509.ExtensionType): raise TypeError("extension must be an ExtensionType") diff --git a/src/cryptography/x509/oid.py b/src/cryptography/x509/oid.py index 0d91a5469503..cda50cced5c4 100644 --- a/src/cryptography/x509/oid.py +++ b/src/cryptography/x509/oid.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from __future__ import annotations + from cryptography.hazmat._oid import ( AttributeOID, AuthorityInformationAccessOID, From 14d45c2259b01f1459eeab8bb7d85ce4cfb0841b Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 30 Mar 2023 15:30:32 -0700 Subject: [PATCH 050/316] do not use pip_install_editable (#8644) --- .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 13508c87a0c8..561251d5b1d5 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[test] - tools/pip_install_editable.py ./certbot[test] + tools/pip_install.py -e ./acme[test] + tools/pip_install.py -e ./certbot[test] pip install -U pyopenssl ;; run) From 3622cb389709e632678bf80649fcf26833572da8 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Fri, 31 Mar 2023 00:18:29 +0000 Subject: [PATCH 051/316] Bump BoringSSL and/or OpenSSL in CI (#8645) Co-authored-by: pyca-boringbot[bot] --- .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 8be80dc30c31..6d19bcec980c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,10 +42,10 @@ jobs: - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "libressl", VERSION: "3.7.1"}} - {VERSION: "3.11", TOXENV: "py311-randomorder"} - {VERSION: "3.12-dev", TOXENV: "py312"} - # Latest commit on the BoringSSL master branch, as of Mar 30, 2023. - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "boringssl", VERSION: "fca688f26b939db9c9981204373cecbd108b5d6c"}} - # Latest commit on the OpenSSL master branch, as of Mar 30, 2023. - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "09cb8718fd65dc7126247808cb96b05147bb923f"}} + # Latest commit on the BoringSSL master branch, as of Mar 31, 2023. + - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "boringssl", VERSION: "58472cc752c92554343d032ab34c683005f63e30"}} + # Latest commit on the OpenSSL master branch, as of Mar 31, 2023. + - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "bbe9d2de6c643a2c6758fae4274c307943a59624"}} name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.TOXARGS }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" timeout-minutes: 15 steps: From 35ef119e2fbc0263077bae319e22d2f12767efe9 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 31 Mar 2023 02:13:40 -0400 Subject: [PATCH 052/316] Make the readme metadata static (#8639) --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7bdf2a5cfaa4..230f2fecda50 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ authors = [ {name = "The Python Cryptographic Authority and individual contributors", email = "cryptography-dev@python.org"} ] description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +readme = "README.rst" license = {text = "Apache-2.0 OR BSD-3-Clause"} classifiers = [ "Development Status :: 5 - Production/Stable", @@ -44,7 +45,7 @@ dependencies = [ # Must be kept in sync with `build-system.requires` "cffi >=1.12", ] -dynamic = ["version", "readme"] +dynamic = ["version"] [project.urls] homepage = "https://github.com/pyca/cryptography" @@ -66,7 +67,6 @@ exclude = [ [tool.setuptools.dynamic] version = {attr = "cryptography.__version__"} -readme = {file = "README.rst", content-type = "text/x-rst"} [project.optional-dependencies] ssh = ["bcrypt >=3.1.5"] From ab26f4fa9a09225bfa9db5a53de1081ecd8153eb Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Sat, 1 Apr 2023 00:18:28 +0000 Subject: [PATCH 053/316] Bump BoringSSL and/or OpenSSL in CI (#8647) Co-authored-by: pyca-boringbot[bot] --- .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 6d19bcec980c..995bb987db76 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,10 +42,10 @@ jobs: - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "libressl", VERSION: "3.7.1"}} - {VERSION: "3.11", TOXENV: "py311-randomorder"} - {VERSION: "3.12-dev", TOXENV: "py312"} - # Latest commit on the BoringSSL master branch, as of Mar 31, 2023. - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "boringssl", VERSION: "58472cc752c92554343d032ab34c683005f63e30"}} - # Latest commit on the OpenSSL master branch, as of Mar 31, 2023. - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "bbe9d2de6c643a2c6758fae4274c307943a59624"}} + # Latest commit on the BoringSSL master branch, as of Apr 01, 2023. + - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "boringssl", VERSION: "d89702704febab30774e8af22450899af297bfb0"}} + # Latest commit on the OpenSSL master branch, as of Apr 01, 2023. + - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "9559ad0e8d433a2a212b63cc848fa2ac82a9b048"}} name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.TOXARGS }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" timeout-minutes: 15 steps: From 4e6bfbb98f7f303d6e5171002834a578d7ba71a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Apr 2023 14:17:25 +0000 Subject: [PATCH 054/316] Bump openssl-macros from 0.1.0 to 0.1.1 in /src/rust (#8648) Bumps openssl-macros from 0.1.0 to 0.1.1. --- updated-dependencies: - dependency-name: openssl-macros 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 | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 24a98758c1f4..de146f162f96 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -41,7 +41,7 @@ checksum = "bfab79c195875e5aef2bd20b4c8ed8d43ef9610bcffefbbcf66f88f555cc78af" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -148,7 +148,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn", + "syn 1.0.109", ] [[package]] @@ -165,7 +165,7 @@ checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -307,13 +307,13 @@ dependencies = [ [[package]] name = "openssl-macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.12", ] [[package]] @@ -349,7 +349,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -399,7 +399,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -469,7 +469,7 @@ dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -480,7 +480,7 @@ checksum = "8e0e1128f85ce3fca66e435e08aa2089a2689c1c48ce97803e13f63124058462" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -530,6 +530,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "target-lexicon" version = "0.12.6" @@ -596,7 +607,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-shared", ] @@ -618,7 +629,7 @@ checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] From b4a63a5c301b270c513dd799deec286999355853 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Apr 2023 14:24:24 +0000 Subject: [PATCH 055/316] Bump openssl-sys from 0.9.83 to 0.9.84 in /src/rust (#8649) Bumps [openssl-sys](https://github.com/sfackler/rust-openssl) from 0.9.83 to 0.9.84. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.83...openssl-sys-v0.9.84) --- updated-dependencies: - dependency-name: openssl-sys 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 | 5 ++--- src/rust/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index de146f162f96..00e50d8da71a 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -318,11 +318,10 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.83" +version = "0.9.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "666416d899cf077260dac8698d60a60b435a46d57e82acb1be3d0dad87284e5b" +checksum = "3a20eace9dc2d82904039cb76dcf50fb1a0bba071cfd1629720b5d6f1ddba0fa" dependencies = [ - "autocfg", "cc", "libc", "pkg-config", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 5de812febf45..f922111b4301 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -15,7 +15,7 @@ pem = "1.1" chrono = { version = "0.4.24", default-features = false, features = ["alloc", "clock"] } ouroboros = "0.15" openssl = "0.10.48" -openssl-sys = "0.9.72" +openssl-sys = "0.9.84" foreign-types-shared = "0.1" [build-dependencies] From dd513528ecd81b98909ce9e237352dd276bce8a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Apr 2023 14:41:12 +0000 Subject: [PATCH 056/316] Bump openssl from 0.10.48 to 0.10.49 in /src/rust (#8650) Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.48 to 0.10.49. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.48...openssl-v0.10.49) --- updated-dependencies: - dependency-name: openssl 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 | 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 00e50d8da71a..955b8b01770a 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -292,9 +292,9 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "openssl" -version = "0.10.48" +version = "0.10.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518915b97df115dd36109bfa429a48b8f737bd05508cf9588977b599648926d2" +checksum = "4d2f106ab837a24e03672c59b1239669a0596406ff657c3c0835b6b7f0f35a33" dependencies = [ "bitflags", "cfg-if", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index f922111b4301..5b5a671d497b 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -14,7 +14,7 @@ asn1 = { version = "0.13.0", default-features = false, features = ["const-generi pem = "1.1" chrono = { version = "0.4.24", default-features = false, features = ["alloc", "clock"] } ouroboros = "0.15" -openssl = "0.10.48" +openssl = "0.10.49" openssl-sys = "0.9.84" foreign-types-shared = "0.1" From 045287a86f223c912975eb909a3d0dcc5f07b385 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 1 Apr 2023 17:19:25 -0400 Subject: [PATCH 057/316] Update cargo packages that dependabot couldn't handle (#8646) --- src/rust/Cargo.lock | 83 +++++++-------------------------------------- 1 file changed, 13 insertions(+), 70 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 955b8b01770a..8abe5121f2a1 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -185,9 +185,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "iana-time-zone" -version = "0.1.55" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "716f12fbcfac6ffab0a5e9ec51d0a0ff70503742bb2dc7b99396394c9dc323f0" +checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -672,11 +672,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.47.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2649ff315bee4c98757f15dac226efe3d81927adbb6e882084bb1ee3e0c330a7" +checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" dependencies = [ - "windows-targets 0.47.0", + "windows-targets", ] [[package]] @@ -685,7 +685,7 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets 0.42.2", + "windows-targets", ] [[package]] @@ -694,28 +694,13 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f8996d3f43b4b2d44327cd71b7b0efd1284ab60e6e9d0e8b630e18555d87d3e" -dependencies = [ - "windows_aarch64_gnullvm 0.47.0", - "windows_aarch64_msvc 0.47.0", - "windows_i686_gnu 0.47.0", - "windows_i686_msvc 0.47.0", - "windows_x86_64_gnu 0.47.0", - "windows_x86_64_gnullvm 0.47.0", - "windows_x86_64_msvc 0.47.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -724,80 +709,38 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831d567d53d4f3cb1db332b68e6e2b6260228eb4d99a777d8b2e8ed794027c90" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" -[[package]] -name = "windows_aarch64_msvc" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a42d54a417c60ce4f0e31661eed628f0fa5aca73448c093ec4d45fab4c51cdf" - [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" -[[package]] -name = "windows_i686_gnu" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1925beafdbb22201a53a483db861a5644123157c1c3cee83323a2ed565d71e3" - [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" -[[package]] -name = "windows_i686_msvc" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8ef8f2f1711b223947d9b69b596cf5a4e452c930fb58b6fc3fdae7d0ec6b31" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" -[[package]] -name = "windows_x86_64_gnu" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acaa0c2cf0d2ef99b61c308a0c3dbae430a51b7345dedec470bd8f53f5a3642" - [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a0628f71be1d11e17ca4a0e9e15b3a5180f6fbf1c2d55e3ba3f850378052c1" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.47.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6e62c256dc6d40b8c8707df17df8d774e60e39db723675241e7c15e910bce7" From 4a95379c5698b62aac8b1ec2bdbee6d4ba0602d1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Apr 2023 21:36:57 +0000 Subject: [PATCH 058/316] Bump proc-macro2 from 1.0.54 to 1.0.55 in /src/rust (#8652) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.54 to 1.0.55. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.54...1.0.55) --- 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 8abe5121f2a1..03939c106b2e 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -415,9 +415,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.54" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" +checksum = "1d0dd4be24fcdcfeaa12a432d588dc59bbad6cad3510c67e74a2b6b2fc950564" dependencies = [ "unicode-ident", ] From 1e49cb9c13845ee973e74d1ffca6fe8ca47c0a35 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 2 Apr 2023 03:28:22 -0400 Subject: [PATCH 059/316] Switch from tox to nox (#8651) --- .github/actions/mtime-fix/action.yml | 2 +- .github/workflows/ci.yml | 192 ++++++++++++------------ MANIFEST.in | 2 +- ci-constraints-requirements.txt | 38 ++--- docs/development/getting-started.rst | 41 ++--- docs/development/submitting-patches.rst | 6 +- docs/spelling_wordlist.txt | 1 + noxfile.py | 147 ++++++++++++++++++ pyproject.toml | 8 +- tox.ini | 85 ----------- 10 files changed, 271 insertions(+), 251 deletions(-) create mode 100644 noxfile.py delete mode 100644 tox.ini diff --git a/.github/actions/mtime-fix/action.yml b/.github/actions/mtime-fix/action.yml index 4589aece1b8b..0690132db689 100644 --- a/.github/actions/mtime-fix/action.yml +++ b/.github/actions/mtime-fix/action.yml @@ -20,7 +20,7 @@ runs: exit 1 fi echo "Setting mtimes for dirs" - for f in $(git ls-files src/rust src/_cffi_src); do touch -t $(git log --pretty=format:%cd --date=format-local:%Y%m%d%H%M.%S -1 HEAD -- "$f") "$f"; done + for f in $(git ls-tree -t -r --name-only HEAD src/rust src/_cffi_src); do touch -t $(git log --pretty=format:%cd --date=format-local:%Y%m%d%H%M.%S -1 HEAD -- "$f") "$f"; done echo "Done" ls -Rla src/rust/src src/_cffi_src shell: bash diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 995bb987db76..51c532929c57 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,27 +26,26 @@ jobs: fail-fast: false matrix: PYTHON: - - {VERSION: "3.11", TOXENV: "flake"} - - {VERSION: "3.11", TOXENV: "rust"} - - {VERSION: "3.11", TOXENV: "docs", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0"}} - - {VERSION: "pypy-3.8", TOXENV: "pypy3-nocoverage"} - - {VERSION: "pypy-3.9", TOXENV: "pypy3-nocoverage"} - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1t"}} - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "3.0.8"}} - - {VERSION: "3.11", TOXENV: "py311-ssh", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0"}} - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct no-psk"}} - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0", CONFIG_FLAGS: "no-legacy", NO_LEGACY: "1"}} - - {VERSION: "3.11", TOXENV: "py311", TOXARGS: "--enable-fips=1", OPENSSL: {TYPE: "openssl", CONFIG_FLAGS: "enable-fips", VERSION: "3.1.0"}} - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "libressl", VERSION: "3.5.4"}} - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "libressl", VERSION: "3.6.2"}} - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "libressl", VERSION: "3.7.1"}} - - {VERSION: "3.11", TOXENV: "py311-randomorder"} - - {VERSION: "3.12-dev", TOXENV: "py312"} + - {VERSION: "3.11", NOXSESSION: "flake"} + - {VERSION: "3.11", NOXSESSION: "rust"} + - {VERSION: "3.11", NOXSESSION: "docs", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0"}} + - {VERSION: "pypy-3.8", NOXSESSION: "tests-nocoverage"} + - {VERSION: "pypy-3.9", NOXSESSION: "tests-nocoverage"} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1t"}} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.0.8"}} + - {VERSION: "3.11", NOXSESSION: "tests-ssh", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0"}} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct no-psk"}} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0", CONFIG_FLAGS: "no-legacy", NO_LEGACY: "1"}} + - {VERSION: "3.11", NOXSESSION: "tests", NOXARGS: "--enable-fips=1", OPENSSL: {TYPE: "openssl", CONFIG_FLAGS: "enable-fips", VERSION: "3.1.0"}} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.5.4"}} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.6.2"}} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.1"}} + - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} + - {VERSION: "3.12-dev", NOXSESSION: "tests"} # Latest commit on the BoringSSL master branch, as of Apr 01, 2023. - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "boringssl", VERSION: "d89702704febab30774e8af22450899af297bfb0"}} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "d89702704febab30774e8af22450899af297bfb0"}} # Latest commit on the OpenSSL master branch, as of Apr 01, 2023. - - {VERSION: "3.11", TOXENV: "py311", OPENSSL: {TYPE: "openssl", VERSION: "9559ad0e8d433a2a212b63cc848fa2ac82a9b048"}} - name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.TOXARGS }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "9559ad0e8d433a2a212b63cc848fa2ac82a9b048"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.0 @@ -61,24 +60,18 @@ jobs: uses: actions/setup-python@v4.5.0 with: python-version: ${{ matrix.PYTHON.VERSION }} - - name: Cache rust and pip - uses: ./.github/actions/cache - timeout-minutes: 2 - with: - key: ${{ matrix.PYTHON.VERSION }}-${{ steps.setup-python.outputs.python-version }} - name: Clone wycheproof timeout-minutes: 2 uses: ./.github/actions/wycheproof - - run: python -m pip install -c ci-constraints-requirements.txt 'tox>3' coverage[toml] - name: Compute config hash and set config vars run: | DEFAULT_CONFIG_FLAGS="shared no-ssl2 no-ssl3" CONFIG_FLAGS="$DEFAULT_CONFIG_FLAGS $CONFIG_FLAGS" - CONFIG_HASH=$(echo "$CONFIG_FLAGS" | sha1sum | sed 's/ .*$//') + OPENSSL_HASH=$(echo "${{ matrix.PYTHON.OPENSSL.TYPE }}-${{ matrix.PYTHON.OPENSSL.VERSION }}-$CONFIG_FLAGS" | sha1sum | sed 's/ .*$//') echo "CONFIG_FLAGS=${CONFIG_FLAGS}" >> $GITHUB_ENV - echo "CONFIG_HASH=${CONFIG_HASH}" >> $GITHUB_ENV + echo "OPENSSL_HASH=${OPENSSL_HASH}" >> $GITHUB_ENV echo "OSSL_INFO=${{ matrix.PYTHON.OPENSSL.TYPE }}-${{ matrix.PYTHON.OPENSSL.VERSION }}-${CONFIG_FLAGS}" >> $GITHUB_ENV - echo "OSSL_PATH=${{ github.workspace }}/osslcache/${{ matrix.PYTHON.OPENSSL.TYPE }}-${{ matrix.PYTHON.OPENSSL.VERSION }}-${CONFIG_HASH}" >> $GITHUB_ENV + echo "OSSL_PATH=${{ github.workspace }}/osslcache/${{ matrix.PYTHON.OPENSSL.TYPE }}-${{ matrix.PYTHON.OPENSSL.VERSION }}-${OPENSSL_HASH}" >> $GITHUB_ENV env: CONFIG_FLAGS: ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }} if: matrix.PYTHON.OPENSSL @@ -90,7 +83,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 }}-8 + key: ${{ matrix.PYTHON.OPENSSL.TYPE }}-${{ matrix.PYTHON.OPENSSL.VERSION }}-${{ env.OPENSSL_HASH }}-8 if: matrix.PYTHON.OPENSSL - name: Build custom OpenSSL/LibreSSL run: .github/workflows/build_openssl.sh @@ -104,17 +97,27 @@ jobs: echo "CFLAGS=${CFLAGS} -Werror=implicit-function-declaration" >> $GITHUB_ENV echo "RUSTFLAGS=-Clink-arg=-Wl,-rpath=${OSSL_PATH}/lib -Clink-arg=-Wl,-rpath=${OSSL_PATH}/lib64" >> $GITHUB_ENV if: matrix.PYTHON.OPENSSL - - name: Build toxenv + - name: Cache rust and pip + uses: ./.github/actions/cache + timeout-minutes: 2 + with: + # We have both the Python version from the matrix and from the + # setup-python step because the latter doesn't distinguish + # pypy3-3.8 and pypy3-3.9 -- both of them show up as 7.3.11. + key: ${{ matrix.PYTHON.VERSION }}-${{ steps.setup-python.outputs.python-version }}-${{ matrix.PYTHON.NOXSESSION }}-${{ env.OPENSSL_HASH }} + + - run: python -m pip install -c ci-constraints-requirements.txt 'nox' coverage[toml] + - name: Create nox environment run: | - tox -vvv --notest + nox -v --install-only env: - TOXENV: ${{ matrix.PYTHON.TOXENV }} + NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }} CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - name: Tests run: | - tox --skip-pkg-install -- --color=yes --wycheproof-root=wycheproof ${{ matrix.PYTHON.TOXARGS }} + nox --no-install -- --color=yes --wycheproof-root=wycheproof ${{ matrix.PYTHON.NOXARGS }} env: - TOXENV: ${{ matrix.PYTHON.TOXENV }} + NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }} COLUMNS: 80 CRYPTOGRAPHY_OPENSSL_NO_LEGACY: ${{ matrix.PYTHON.OPENSSL.NO_LEGACY }} CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} @@ -128,22 +131,22 @@ jobs: fail-fast: false matrix: IMAGE: - - {IMAGE: "rhel8", TOXENV: "py38", RUNNER: "ubuntu-latest"} - - {IMAGE: "rhel8-fips", TOXENV: "py38", RUNNER: "ubuntu-latest", FIPS: true} - - {IMAGE: "buster", TOXENV: "py37", RUNNER: "ubuntu-latest"} - - {IMAGE: "bullseye", TOXENV: "py39", RUNNER: "ubuntu-latest"} - - {IMAGE: "bookworm", TOXENV: "py311", RUNNER: "ubuntu-latest"} - - {IMAGE: "sid", TOXENV: "py311", RUNNER: "ubuntu-latest"} - - {IMAGE: "ubuntu-focal", TOXENV: "py38", RUNNER: "ubuntu-latest"} - - {IMAGE: "ubuntu-jammy", TOXENV: "py310", RUNNER: "ubuntu-latest"} - - {IMAGE: "ubuntu-rolling", TOXENV: "py310", RUNNER: "ubuntu-latest"} - - {IMAGE: "fedora", TOXENV: "py311", RUNNER: "ubuntu-latest"} - - {IMAGE: "alpine", TOXENV: "py310", RUNNER: "ubuntu-latest"} - - {IMAGE: "centos-stream9", TOXENV: "py39", RUNNER: "ubuntu-latest"} - - {IMAGE: "centos-stream9-fips", TOXENV: "py39", RUNNER: "ubuntu-latest", FIPS: true} + - {IMAGE: "rhel8", RUNNER: "ubuntu-latest"} + - {IMAGE: "rhel8-fips", RUNNER: "ubuntu-latest", FIPS: true} + - {IMAGE: "buster", RUNNER: "ubuntu-latest"} + - {IMAGE: "bullseye", RUNNER: "ubuntu-latest"} + - {IMAGE: "bookworm", RUNNER: "ubuntu-latest"} + - {IMAGE: "sid", RUNNER: "ubuntu-latest"} + - {IMAGE: "ubuntu-focal", RUNNER: "ubuntu-latest"} + - {IMAGE: "ubuntu-jammy", RUNNER: "ubuntu-latest"} + - {IMAGE: "ubuntu-rolling", RUNNER: "ubuntu-latest"} + - {IMAGE: "fedora", RUNNER: "ubuntu-latest"} + - {IMAGE: "alpine", RUNNER: "ubuntu-latest"} + - {IMAGE: "centos-stream9", RUNNER: "ubuntu-latest"} + - {IMAGE: "centos-stream9-fips", RUNNER: "ubuntu-latest", FIPS: true} - - {IMAGE: "ubuntu-jammy:aarch64", TOXENV: "py310", RUNNER: [self-hosted, Linux, ARM64]} - - {IMAGE: "alpine:aarch64", TOXENV: "py310", RUNNER: [self-hosted, Linux, ARM64]} + - {IMAGE: "ubuntu-jammy:aarch64", RUNNER: [self-hosted, Linux, ARM64]} + - {IMAGE: "alpine:aarch64", RUNNER: [self-hosted, Linux, ARM64]} timeout-minutes: 15 steps: - name: Ridiculous alpine workaround for actions support on arm64 @@ -180,17 +183,15 @@ jobs: - run: | echo "OPENSSL_FORCE_FIPS_MODE=1" >> $GITHUB_ENV if: matrix.IMAGE.FIPS - - run: /venv/bin/python -m pip install -c ci-constraints-requirements.txt 'tox>3' coverage - - run: '/venv/bin/tox -vvv --notest' + - run: /venv/bin/python -m pip install -c ci-constraints-requirements.txt 'nox' coverage + - run: '/venv/bin/nox -v --install-only -s tests' env: - TOXENV: ${{ matrix.IMAGE.TOXENV }} RUSTUP_HOME: /root/.rustup CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} # OPENSSL_ENABLE_SHA1_SIGNATURES is for CentOS 9 Stream OPENSSL_ENABLE_SHA1_SIGNATURES: 1 - - run: '/venv/bin/tox --skip-pkg-install -- --color=yes --wycheproof-root="wycheproof"' + - run: '/venv/bin/nox --no-install -s tests -- --color=yes --wycheproof-root="wycheproof"' env: - TOXENV: ${{ matrix.IMAGE.TOXENV }} COLUMNS: 80 # OPENSSL_ENABLE_SHA1_SIGNATURES is for CentOS 9 Stream OPENSSL_ENABLE_SHA1_SIGNATURES: 1 @@ -202,11 +203,11 @@ jobs: fail-fast: false matrix: PYTHON: - - {VERSION: "3.11", TOXENV: "py311"} + - "3.11" RUST: # Cover MSRV. 1.60+ and beta/nightly are in the linux-rust-coverage section. - 1.56.0 - name: "${{ matrix.PYTHON.TOXENV }} with Rust ${{ matrix.RUST }}" + name: "${{ matrix.PYTHON }} with Rust ${{ matrix.RUST }}" timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.0 @@ -224,23 +225,21 @@ jobs: - name: Setup python uses: actions/setup-python@v4.5.0 with: - python-version: ${{ matrix.PYTHON.VERSION }} + python-version: ${{ matrix.PYTHON }} - uses: dtolnay/rust-toolchain@52e69531e6f69a396bc9d1226284493a5db969ff with: toolchain: ${{ matrix.RUST }} - name: Clone wycheproof timeout-minutes: 2 uses: ./.github/actions/wycheproof - - run: python -m pip install -c ci-constraints-requirements.txt 'tox>3' coverage[toml] - - name: Create toxenv - run: tox -vvv --notest + - run: python -m pip install -c ci-constraints-requirements.txt 'nox' coverage[toml] + - name: Create nox environment + run: nox -v --install-only -s tests env: - TOXENV: ${{ matrix.PYTHON.TOXENV }} CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - name: Tests - run: tox --skip-pkg-install -- --color=yes --wycheproof-root=wycheproof + run: nox --no-install -s tests -- --color=yes --wycheproof-root=wycheproof env: - TOXENV: ${{ matrix.PYTHON.TOXENV }} COLUMNS: 80 - uses: ./.github/actions/upload-coverage @@ -250,7 +249,7 @@ jobs: fail-fast: false matrix: PYTHON: - - {VERSION: "3.11", TOXENV: "py311"} + - "3.11" RUST: # Potential future MSRVs: # 1.60 - new version of cxx @@ -302,25 +301,23 @@ jobs: - name: Setup python uses: actions/setup-python@v4.5.0 with: - python-version: ${{ matrix.PYTHON.VERSION }} + python-version: ${{ matrix.PYTHON }} - run: cargo install cargo-binutils if: steps.cargo-cache.outputs.cache-hit != 'true' - name: Clone wycheproof timeout-minutes: 2 uses: ./.github/actions/wycheproof - - run: python -m pip install -c ci-constraints-requirements.txt 'tox>3' coverage[toml] cffi - - name: Create toxenv - run: tox -vvv --notest + - run: python -m pip install -c ci-constraints-requirements.txt 'nox' coverage[toml] cffi + - name: Create nox environment + run: nox -v --install-only -s tests env: - TOXENV: ${{ matrix.PYTHON.TOXENV }} CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} RUSTFLAGS: "-Cinstrument-coverage" LLVM_PROFILE_FILE: "rust-cov/cov-%p.profraw" - name: Tests - run: tox --skip-pkg-install -- --color=yes --wycheproof-root=wycheproof + run: nox --no-install -s tests -- --color=yes --wycheproof-root=wycheproof env: - TOXENV: ${{ matrix.PYTHON.TOXENV }} COLUMNS: 80 CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} RUSTFLAGS: "-Cinstrument-coverage" @@ -341,7 +338,7 @@ jobs: COV_UUID=$(python3 -c "import uuid; print(uuid.uuid4())") cargo cov -- export \ - ../../.tox/${{ matrix.PYTHON.TOXENV }}/lib/python${{ matrix.PYTHON.VERSION }}/site-packages/cryptography/hazmat/bindings/_rust.abi3.so \ + ../../.nox/tests/lib/python${{ matrix.PYTHON }}/site-packages/cryptography/hazmat/bindings/_rust.abi3.so \ -instr-profile=pytest-rust-cov.profdata \ --ignore-filename-regex='/.cargo/registry' \ --ignore-filename-regex='/rustc/' \ @@ -365,13 +362,12 @@ jobs: - {OS: 'macos-12', ARCH: 'x86_64'} - {OS: [self-hosted, macos, ARM64, tart], ARCH: 'arm64'} PYTHON: - - {VERSION: "3.7", TOXENV: "py37-nocoverage"} - - {VERSION: "3.11", TOXENV: "py311"} + - {VERSION: "3.7", NOXSESSION: "tests-nocoverage"} + - {VERSION: "3.11", NOXSESSION: "tests"} exclude: # We only test latest Python on arm64. py37 won't work since there's no universal2 binary - - PYTHON: {VERSION: "3.7", TOXENV: "py37-nocoverage"} + - PYTHON: {VERSION: "3.7", NOXSESSION: "tests-nocoverage"} RUNNER: {OS: [self-hosted, macos, ARM64, tart], ARCH: 'arm64'} - name: "${{ matrix.PYTHON.TOXENV }} on macOS ${{ matrix.RUNNER.ARCH }}" timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.0 @@ -385,7 +381,7 @@ jobs: uses: ./.github/actions/cache timeout-minutes: 2 with: - key: ${{ matrix.PYTHON.VERSION }} + key: ${{ matrix.PYTHON.NOXSESSION }}-${{ matrix.PYTHON.VERSION }} - name: Setup python uses: actions/setup-python@v4.5.0 @@ -393,7 +389,7 @@ jobs: python-version: ${{ matrix.PYTHON.VERSION }} architecture: 'x64' # we force this right now so that it will install the universal2 on arm64 - - run: python -m pip install -c ci-constraints-requirements.txt 'tox>3' coverage[toml] + - run: python -m pip install -c ci-constraints-requirements.txt 'nox' coverage[toml] - name: Clone wycheproof timeout-minutes: 2 @@ -408,19 +404,19 @@ jobs: name: openssl-macos-universal2 path: "../openssl-macos-universal2/" github_token: ${{ secrets.GITHUB_TOKEN }} - - name: Build toxenv + - name: Build nox environment run: | OPENSSL_DIR=$(readlink -f ../openssl-macos-universal2/) \ OPENSSL_STATIC=1 \ CFLAGS="-Werror -Wno-error=deprecated-declarations -Wno-error=incompatible-pointer-types-discards-qualifiers -Wno-error=unused-function -mmacosx-version-min=10.12" \ - tox -vvv --notest + nox -v --install-only env: - TOXENV: ${{ matrix.PYTHON.TOXENV }} + NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }} CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - name: Tests - run: tox --skip-pkg-install -- --color=yes --wycheproof-root=wycheproof + run: nox --no-install -- --color=yes --wycheproof-root=wycheproof env: - TOXENV: ${{ matrix.PYTHON.TOXENV }} + NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }} COLUMNS: 80 - uses: ./.github/actions/upload-coverage @@ -434,10 +430,9 @@ jobs: - {ARCH: 'x86', WINDOWS: 'win32'} - {ARCH: 'x64', WINDOWS: 'win64'} PYTHON: - - {VERSION: "3.7", TOXENV: "py37-nocoverage"} - - {VERSION: "3.11", TOXENV: "py311"} + - {VERSION: "3.7", NOXSESSION: "tests-nocoverage"} + - {VERSION: "3.11", NOXSESSION: "tests"} JOB_NUMBER: [0, 1] - name: "${{ matrix.PYTHON.TOXENV }} on ${{ matrix.WINDOWS.WINDOWS }} (part ${{ matrix.JOB_NUMBER }})" timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.0 @@ -457,8 +452,8 @@ jobs: uses: ./.github/actions/cache timeout-minutes: 2 with: - key: ${{ matrix.WINDOWS.ARCH }}-${{ steps.setup-python.outputs.python-version }} - - run: python -m pip install -c ci-constraints-requirements.txt "tox>3" coverage[toml] + key: ${{ matrix.PYTHON.NOXSESSION }}-${{ matrix.WINDOWS.ARCH }}-${{ steps.setup-python.outputs.python-version }} + - run: python -m pip install -c ci-constraints-requirements.txt "nox" coverage[toml] - uses: dawidd6/action-download-artifact@5e780fc7bbd0cac69fc73271ed86edf5dcb72d67 with: @@ -478,15 +473,15 @@ jobs: timeout-minutes: 2 uses: ./.github/actions/wycheproof - - name: Build toxenv - run: tox -vvv --notest + - name: Build nox environment + run: nox -v --install-only env: - TOXENV: ${{ matrix.PYTHON.TOXENV }} + NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }} CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - name: Tests - run: tox --skip-pkg-install -- --color=yes --wycheproof-root=wycheproof --num-shards=2 --shard-id=${{ matrix.JOB_NUMBER }} + run: nox --no-install -- --color=yes --wycheproof-root=wycheproof --num-shards=2 --shard-id=${{ matrix.JOB_NUMBER }} env: - TOXENV: ${{ matrix.PYTHON.TOXENV }} + NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }} COLUMNS: 80 CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} @@ -574,17 +569,14 @@ jobs: # This creates the same key as the docs job (as long as they have the same # python version) key: 3.11-${{ steps.setup-python.outputs.python-version }} - - run: python -m pip install -c ci-constraints-requirements.txt tox - - name: Build toxenv + - run: python -m pip install -c ci-constraints-requirements.txt nox + - name: Build nox environment run: | - tox -vvv --notest + nox -v --install-only -s docs-linkcheck env: - TOXENV: docs-linkcheck CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - name: linkcheck - run: tox --skip-pkg-install -- --color=yes - env: - TOXENV: docs-linkcheck + run: nox --no-install -s docs-linkcheck -- --color=yes all-green: # https://github.community/t/is-it-possible-to-require-all-github-actions-tasks-to-pass-without-enumerating-them/117957/4?u=graingert diff --git a/MANIFEST.in b/MANIFEST.in index 2417dd9d3088..dcffd6024d1c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,7 +4,7 @@ include LICENSE include LICENSE.APACHE include LICENSE.BSD include README.rst -include tox.ini +include noxfile.py include pyproject.toml recursive-include src py.typed *.pyi diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 11f850c7efbc..20bf7a5cedce 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -1,12 +1,14 @@ # This is named ambigiously, but it's a pip constraints file, named like a # requirements file so dependabot will update the pins. # It was originally generated with; -# pip-compile --extra=docs --extra=docstest --extra=pep8test --extra=test --extra=test-randomorder --extra=tox --resolver=backtracking --strip-extras --unsafe-package=cffi --unsafe-package=pycparser --unsafe-package=setuptools pyproject.toml +# pip-compile --extra=docs --extra=docstest --extra=pep8test --extra=test --extra=test-randomorder --extra=nox --resolver=backtracking --strip-extras --unsafe-package=cffi --unsafe-package=pycparser --unsafe-package=setuptools pyproject.toml # and then manually massaged to add version specifiers to packages whose # versions vary by Python version alabaster==0.7.13 # via sphinx +argcomplete==2.1.2 + # via nox attrs==22.2.0 # via # pytest @@ -18,20 +20,16 @@ bleach==6.0.0 # via readme-renderer build==0.10.0 # via check-manifest -cachetools==5.3.0 - # via tox certifi==2022.12.7 # via requests -chardet==5.1.0 - # via tox charset-normalizer==3.1.0 # via requests check-manifest==0.49 # via cryptography (pyproject.toml) click==8.1.3 # via black -colorama==0.4.6 - # via tox +colorlog==6.7.0 + # via nox coverage==7.2.2 # via pytest-cov distlib==0.3.6 @@ -46,17 +44,11 @@ exceptiongroup==1.1.1 execnet==1.9.0 # via pytest-xdist filelock==3.10.7 - # via - # tox - # virtualenv + # via virtualenv idna==3.4 # via requests imagesize==1.4.1 # via sphinx -importlib-metadata==6.1.0 - # via - # keyring - # twine iniconfig==2.0.0 # via pytest jaraco-classes==3.2.3 @@ -79,14 +71,15 @@ mypy-extensions==1.0.0 # via # black # mypy +nox==2022.11.21 + # via cryptography (pyproject.toml) packaging==23.0 # via # black # build - # pyproject-api + # nox # pytest # sphinx - # tox pathspec==0.11.1 # via black pkginfo==1.9.6 @@ -94,12 +87,9 @@ pkginfo==1.9.6 platformdirs==3.2.0 # via # black - # tox # virtualenv pluggy==1.0.0 - # via - # pytest - # tox + # via pytest pretend==1.0.9 # via cryptography (pyproject.toml) py-cpuinfo==9.0.0 @@ -113,8 +103,6 @@ pygments==2.14.0 # readme-renderer # rich # sphinx -pyproject-api==1.5.1 - # via tox pyproject-hooks==1.0.0 # via build pytest==7.2.2 @@ -185,12 +173,8 @@ tomli==2.0.1 # check-manifest # coverage # mypy - # pyproject-api # pyproject-hooks # pytest - # tox -tox==4.4.8 - # via cryptography (pyproject.toml) twine==4.0.2 # via cryptography (pyproject.toml) typing-extensions==4.5.0 @@ -200,7 +184,7 @@ urllib3==1.26.15 # requests # twine virtualenv==20.21.0 - # via tox + # via nox webencodings==0.5.1 # via bleach zipp==3.15.0 diff --git a/docs/development/getting-started.rst b/docs/development/getting-started.rst index 00638aa576d1..782c731102a0 100644 --- a/docs/development/getting-started.rst +++ b/docs/development/getting-started.rst @@ -6,22 +6,22 @@ Development dependencies Working on ``cryptography`` requires the installation of a small number of development dependencies in addition to the dependencies for -:doc:`/installation`. These are handled by the use of ``tox``, which can be +:doc:`/installation`. These are handled by the use of ``nox``, which can be installed with ``pip``. .. code-block:: console $ # Create a virtualenv and activate it $ # Set up your cryptography build environment - $ pip install tox + $ pip install nox $ # Specify your Python version here. - $ tox -e py310 + $ nox -e tests -p py310 OpenSSL on macOS ~~~~~~~~~~~~~~~~ You must have installed `OpenSSL`_ via `Homebrew`_ or `MacPorts`_ and must set -``CFLAGS`` and ``LDFLAGS`` environment variables before running ``tox`` +``CFLAGS`` and ``LDFLAGS`` environment variables before running ``nox`` otherwise pip will fail with include errors. For example, with `Homebrew`_: @@ -30,7 +30,7 @@ For example, with `Homebrew`_: $ env LDFLAGS="-L$(brew --prefix openssl@1.1)/lib" \ CFLAGS="-I$(brew --prefix openssl@1.1)/include" \ - tox -e py310 + nox -e tests -p py310 Alternatively for a static build you can specify ``CRYPTOGRAPHY_SUPPRESS_LINK_FLAGS=1`` and ensure ``LDFLAGS`` points to the @@ -43,32 +43,14 @@ Running tests ------------- ``cryptography`` unit tests are found in the ``tests/`` directory and are -designed to be run using `pytest`_. ``tox`` automatically invokes ``pytest``: +designed to be run using `pytest`_. ``nox`` automatically invokes ``pytest``: .. code-block:: console - $ tox -e py310 + $ nox -e tests -p py310 ... 62746 passed in 220.43 seconds -You can also verify that the tests pass on other supported Python interpreters -with ``tox``. For example: - -.. code-block:: console - - $ tox - ... - ERROR: pypy: InterpreterNotFound: pypy - py38: commands succeeded - py39: commands succeeded - py310: commands succeeded - py311: commands succeeded - docs: commands succeeded - pep8: commands succeeded - -You may not have all the required Python versions installed, in which case you -will see one or more ``InterpreterNotFound`` errors. - Building documentation ---------------------- @@ -76,14 +58,13 @@ Building documentation ``cryptography`` documentation is stored in the ``docs/`` directory. It is written in `reStructured Text`_ and rendered using `Sphinx`_. -Use `tox`_ to build the documentation. For example: +Use `nox`_ to build the documentation. For example: .. code-block:: console - $ tox -e docs + $ nox -e docs ... - docs: commands succeeded - congratulations :) + nox > Session docs was successful. The HTML documentation index can now be found at ``docs/_build/html/index.html``. @@ -92,7 +73,7 @@ The HTML documentation index can now be found at .. _`MacPorts`: https://www.macports.org .. _`OpenSSL`: https://www.openssl.org .. _`pytest`: https://pypi.org/project/pytest/ -.. _`tox`: https://pypi.org/project/tox/ +.. _`nox`: https://pypi.org/project/nox/ .. _`virtualenv`: https://pypi.org/project/virtualenv/ .. _`pip`: https://pypi.org/project/pip/ .. _`sphinx`: https://pypi.org/project/Sphinx/ diff --git a/docs/development/submitting-patches.rst b/docs/development/submitting-patches.rst index 4deaafe09e0f..6148419ce134 100644 --- a/docs/development/submitting-patches.rst +++ b/docs/development/submitting-patches.rst @@ -21,8 +21,8 @@ Code When in doubt, refer to :pep:`8` for Python code. You can check if your code meets our automated requirements by formatting it with ``black`` and running ``ruff`` against it. If you've installed the development requirements this -will automatically use our configuration. You can also run the ``tox`` job with -``tox -e flake``. +will automatically use our configuration. You can also run the ``nox`` job with +``nox -e flake``. `Write comments as complete sentences.`_ @@ -95,7 +95,7 @@ Documentation ------------- All features should be documented with prose in the ``docs`` section. To ensure -it builds you can run ``tox -e docs``. +it builds you can run ``nox -e docs``. Because of the inherent challenges in implementing correct cryptographic systems, we want to make our documentation point people in the right directions diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index ea485aaef77a..d581d3d4c490 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -129,6 +129,7 @@ unencrypted unicode unpadded unpadding +Ventura verifier Verifier Verisign diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 000000000000..8f2a38ab9176 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,147 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import nox + +nox.options.reuse_existing_virtualenvs = True + + +def install(session: nox.Session, *args: str) -> None: + session.install( + "-v", + "-c", + "ci-constraints-requirements.txt", + *args, + ) + + +@nox.session +@nox.session(name="tests-ssh") +@nox.session(name="tests-randomorder") +@nox.session(name="tests-nocoverage") +def tests(session: nox.Session) -> None: + extras = "test" + if session.name == "tests-ssh": + extras += ",ssh" + if session.name == "tests-randomorder": + extras += ",test-randomorder" + + install(session, f".[{extras}]") + install(session, "-e", "./vectors") + + session.run("pip", "list") + + if session.name != "tests-nocoverage": + session.run( + "pytest", + "-n", + "auto", + "--dist=worksteal", + "--cov=cryptography", + "--cov=tests", + "--durations=10", + *session.posargs, + "tests/", + ) + else: + session.run( + "pytest", + "-n", + "auto", + "--dist=worksteal", + "--durations=10", + *session.posargs, + "tests/", + ) + + +@nox.session +def docs(session: nox.Session) -> None: + install(session, ".[docs,docstest,sdist,ssh]") + + temp_dir = session.create_tmp() + session.run( + "sphinx-build", + "-T", + "-W", + "-b", + "html", + "-d", + f"{temp_dir}/doctrees", + "docs", + "docs/_build/html", + ) + session.run( + "sphinx-build", + "-T", + "-W", + "-b", + "latex", + "-d", + f"{temp_dir}/doctrees", + "docs", + "docs/_build/latex", + ) + + session.run( + "sphinx-build", + "-T", + "-W", + "-b", + "doctest", + "-d", + f"{temp_dir}/doctrees", + "docs", + "docs/_build/html", + ) + session.run( + "sphinx-build", + "-T", + "-W", + "-b", + "spelling", + "docs", + "docs/_build/html", + ) + + session.run("python", "setup.py", "sdist") + session.run("twine", "check", "dist/*") + + +@nox.session(name="docs-linkcheck") +def docs_linkcheck(session: nox.Session) -> None: + install(session, ".[docs]") + + session.run( + "sphinx-build", "-W", "-b", "linkcheck", "docs", "docs/_build/html" + ) + + +@nox.session +def flake(session: nox.Session) -> None: + install(session, ".[pep8test,test,ssh,nox]") + + session.run("ruff", ".") + session.run("black", "--check", ".") + session.run("check-manifest") + session.run( + "mypy", + "src/cryptography/", + "vectors/cryptography_vectors/", + "tests/", + "release.py", + "noxfile.py", + ) + + +@nox.session +def rust(session: nox.Session) -> None: + install(session, ".") + + with session.chdir("src/rust/"): + session.run("cargo", "fmt", "--all", "--", "--check") + session.run("cargo", "clippy", "--", "-D", "warnings") + session.run("cargo", "test", "--no-default-features") diff --git a/pyproject.toml b/pyproject.toml index 230f2fecda50..480b4fbbeb3d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,7 +72,7 @@ version = {attr = "cryptography.__version__"} ssh = ["bcrypt >=3.1.5"] # All the following are used for our own testing. -tox = ["tox"] +nox = ["nox"] test = [ "pytest >=6.2.0", "pytest-shard >=0.1.2", @@ -125,9 +125,9 @@ source = [ [tool.coverage.paths] source = [ "src/cryptography", - "*.tox/*/lib*/python*/site-packages/cryptography", - "*.tox\\*\\Lib\\site-packages\\cryptography", - "*.tox/pypy/site-packages/cryptography", + "*.nox/*/lib*/python*/site-packages/cryptography", + "*.nox\\*\\Lib\\site-packages\\cryptography", + "*.nox/pypy/site-packages/cryptography", ] tests =[ "tests/", diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 0a8806afce09..000000000000 --- a/tox.ini +++ /dev/null @@ -1,85 +0,0 @@ -[tox] -minversion = 2.4 -isolated_build = True - -[testenv] -# This is the default install_command but with -v added -install_command = python -I -m pip install -v {opts} {packages} -extras = - test - ssh: ssh - randomorder: test-randomorder -deps = - -e ./vectors -passenv = - ARCHFLAGS - LDFLAGS - CFLAGS - CL - COLUMNS - INCLUDE - LIB - LD_LIBRARY_PATH - RUSTFLAGS - RUSTUP_HOME - CARGO_TARGET_DIR - CARGO_REGISTRIES_CRATES_IO_PROTOCOL - LLVM_PROFILE_FILE - OPENSSL_FORCE_FIPS_MODE - RUSTUP_TOOLCHAIN - CRYPTOGRAPHY_OPENSSL_NO_LEGACY - OPENSSL_ENABLE_SHA1_SIGNATURES - CRYPTOGRAPHY_SUPPRESS_LINK_FLAGS - OPENSSL_DIR -setenv = - PIP_CONSTRAINT=ci-constraints-requirements.txt -commands = - pip list - !nocoverage: pytest -n auto --dist=worksteal --cov=cryptography --cov=tests --durations=10 {posargs} tests/ - nocoverage: pytest -n auto --dist=worksteal --durations=10 {posargs} tests/ - -[testenv:docs] -extras = - docs - docstest - sdist - ssh -basepython = python3 -commands = - sphinx-build -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html - sphinx-build -T -W -b latex -d {envtmpdir}/doctrees docs docs/_build/latex - sphinx-build -T -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html - sphinx-build -T -W -b spelling docs docs/_build/html - python setup.py sdist - twine check dist/* - -[testenv:docs-linkcheck] -extras = - docs -basepython = python3 -commands = - sphinx-build -W -b linkcheck docs docs/_build/html - -[testenv:flake] -basepython = python3 -extras = - pep8test - test - ssh -commands = - ruff . - black --check . - check-manifest - mypy src/cryptography/ vectors/cryptography_vectors/ tests/ release.py - -[testenv:rust] -basepython = python3 -extras = -deps = -changedir = src/rust/ -allowlist_externals = - cargo -commands = - cargo fmt --all -- --check - cargo clippy -- -D warnings - cargo test --no-default-features From 5fef27733c6cf52d54626ca775c2899c31a3f65b Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 2 Apr 2023 22:01:31 +0900 Subject: [PATCH 060/316] update docs for macOS dev with rust openssl (#8653) --- docs/development/getting-started.rst | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/docs/development/getting-started.rst b/docs/development/getting-started.rst index 782c731102a0..a4283469b5cc 100644 --- a/docs/development/getting-started.rst +++ b/docs/development/getting-started.rst @@ -20,24 +20,9 @@ installed with ``pip``. OpenSSL on macOS ~~~~~~~~~~~~~~~~ -You must have installed `OpenSSL`_ via `Homebrew`_ or `MacPorts`_ and must set -``CFLAGS`` and ``LDFLAGS`` environment variables before running ``nox`` -otherwise pip will fail with include errors. - -For example, with `Homebrew`_: - -.. code-block:: console - - $ env LDFLAGS="-L$(brew --prefix openssl@1.1)/lib" \ - CFLAGS="-I$(brew --prefix openssl@1.1)/include" \ - nox -e tests -p py310 - -Alternatively for a static build you can specify -``CRYPTOGRAPHY_SUPPRESS_LINK_FLAGS=1`` and ensure ``LDFLAGS`` points to the -absolute path for the `OpenSSL`_ libraries before calling pip. - -.. tip:: - You will also need to set these values when `Building documentation`_. +You must have installed `OpenSSL`_ (via `Homebrew`_ , `MacPorts`_, or a custom +build) and must configure the build `as documented here`_ before calling +``nox`` or else pip will fail to compile. Running tests ------------- @@ -78,3 +63,4 @@ 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 +.. _`as documented here`: https://docs.rs/openssl/latest/openssl/#automatic \ No newline at end of file From b3782ca0334a9300a18736814e7910dfa43b6628 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 2 Apr 2023 22:03:45 +0900 Subject: [PATCH 061/316] remove cffi helper funcs and args that are no longer needed (#8654) --- src/_cffi_src/build_openssl.py | 65 +--------------------------------- src/_cffi_src/utils.py | 23 ------------ 2 files changed, 1 insertion(+), 87 deletions(-) diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py index 42754fb6417b..3ff1332e2772 100644 --- a/src/_cffi_src/build_openssl.py +++ b/src/_cffi_src/build_openssl.py @@ -8,73 +8,12 @@ import pathlib import platform import sys -from distutils import dist -from distutils.ccompiler import get_default_compiler -from distutils.command.config import config # Add the src directory to the path so we can import _cffi_src.utils src_dir = str(pathlib.Path(__file__).parent.parent) sys.path.insert(0, src_dir) -from _cffi_src.utils import build_ffi_for_binding, compiler_type # noqa: E402 - - -def _get_openssl_libraries(platform): - if os.environ.get("CRYPTOGRAPHY_SUPPRESS_LINK_FLAGS", None): - return [] - # OpenSSL goes by a different library name on different operating systems. - if platform == "win32" and compiler_type() == "msvc": - return [ - "libssl", - "libcrypto", - "advapi32", - "crypt32", - "gdi32", - "user32", - "ws2_32", - ] - else: - # darwin, linux, mingw all use this path - # In some circumstances, the order in which these libs are - # specified on the linker command-line is significant; - # libssl must come before libcrypto - # (https://marc.info/?l=openssl-users&m=135361825921871) - # -lpthread required due to usage of pthread an potential - # existence of a static part containing e.g. pthread_atfork - # (https://github.com/pyca/cryptography/issues/5084) - if sys.platform == "zos": - return ["ssl", "crypto"] - else: - return ["ssl", "crypto", "pthread"] - - -def _extra_compile_args(platform): - """ - We set -Wconversion args here so that we only do Wconversion checks on the - code we're compiling and not on cffi itself (as passing -Wconversion in - CFLAGS would do). We set no error on sign conversion because some - function signatures in LibreSSL differ from OpenSSL have changed on long - vs. unsigned long in the past. Since that isn't a precision issue we don't - care. - """ - # make sure the compiler used supports the flags to be added - is_gcc = False - if get_default_compiler() == "unix": - d = dist.Distribution() - cmd = config(d) - cmd._check_compiler() - is_gcc = ( - "gcc" in cmd.compiler.compiler[0] - or "clang" in cmd.compiler.compiler[0] - ) - if is_gcc or not ( - platform in ["win32", "hp-ux11", "sunos5"] - or platform.startswith("aix") - ): - return ["-Wconversion", "-Wno-error=sign-conversion"] - else: - return [] - +from _cffi_src.utils import build_ffi_for_binding # noqa: E402 ffi = build_ffi_for_binding( module_name="_openssl", @@ -113,8 +52,6 @@ def _extra_compile_args(platform): "pkcs7", "callbacks", ], - libraries=_get_openssl_libraries(sys.platform), - extra_compile_args=_extra_compile_args(sys.platform), ) if __name__ == "__main__": diff --git a/src/_cffi_src/utils.py b/src/_cffi_src/utils.py index cc2a2fb5f050..9eb782686eae 100644 --- a/src/_cffi_src/utils.py +++ b/src/_cffi_src/utils.py @@ -7,8 +7,6 @@ import os import platform import sys -from distutils.ccompiler import new_compiler -from distutils.dist import Distribution from cffi import FFI @@ -23,8 +21,6 @@ def build_ffi_for_binding( module_name, module_prefix, modules, - libraries, - extra_compile_args, ): """ Modules listed in ``modules`` should have the following attributes: @@ -54,8 +50,6 @@ def build_ffi_for_binding( module_name, cdef_source="\n".join(types + functions), verify_source=verify_source, - libraries=libraries, - extra_compile_args=extra_compile_args, ) @@ -63,8 +57,6 @@ def build_ffi( module_name, cdef_source, verify_source, - libraries, - extra_compile_args, ): ffi = FFI() # Always add the CRYPTOGRAPHY_PACKAGE_VERSION to the shared object @@ -88,20 +80,5 @@ def build_ffi( ffi.set_source( module_name, verify_source, - libraries=libraries, - extra_compile_args=extra_compile_args, ) return ffi - - -def compiler_type(): - """ - Gets the compiler type from distutils. On Windows with MSVC it will be - "msvc". On macOS and linux it is "unix". - """ - dist = Distribution() - dist.parse_config_files() - cmd = dist.get_command_obj("build") - cmd.ensure_finalized() - compiler = new_compiler(compiler=cmd.compiler) - return compiler.compiler_type From 963add367b4e3de70d80916c83335551b5c2830b Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 2 Apr 2023 17:17:37 -0400 Subject: [PATCH 062/316] Several improvements to our noxfile (#8655) 1. Stream the output of pip install, don't blit it all out at the end 2. Reduce duplication in test job 3. Add an explanatory comment to the docs job --- noxfile.py | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/noxfile.py b/noxfile.py index 8f2a38ab9176..62634b03fe43 100644 --- a/noxfile.py +++ b/noxfile.py @@ -15,6 +15,7 @@ def install(session: nox.Session, *args: str) -> None: "-c", "ci-constraints-requirements.txt", *args, + silent=False, ) @@ -35,27 +36,23 @@ def tests(session: nox.Session) -> None: session.run("pip", "list") if session.name != "tests-nocoverage": - session.run( - "pytest", - "-n", - "auto", - "--dist=worksteal", + cov_args = [ "--cov=cryptography", "--cov=tests", - "--durations=10", - *session.posargs, - "tests/", - ) + ] else: - session.run( - "pytest", - "-n", - "auto", - "--dist=worksteal", - "--durations=10", - *session.posargs, - "tests/", - ) + cov_args = [] + + session.run( + "pytest", + "-n", + "auto", + "--dist=worksteal", + *cov_args, + "--durations=10", + *session.posargs, + "tests/", + ) @nox.session @@ -107,6 +104,8 @@ def docs(session: nox.Session) -> None: "docs/_build/html", ) + # This is in the docs job because `twine check` verifies that the README + # is valid reStructuredText. session.run("python", "setup.py", "sdist") session.run("twine", "check", "dist/*") From 5a0ca4e25d177926a9ec94562a9e6a3d937f78aa Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 2 Apr 2023 17:19:38 -0400 Subject: [PATCH 063/316] Drop usage of clock feature of chrono (#8657) It adds a zillion dependencies, we can just let python get the current time --- .github/workflows/ci.yml | 1 - src/rust/Cargo.lock | 243 --------------------------------- src/rust/Cargo.toml | 2 +- src/rust/src/pkcs7.rs | 6 +- src/rust/src/x509/common.rs | 9 ++ src/rust/src/x509/ocsp_resp.rs | 5 +- 6 files changed, 13 insertions(+), 253 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51c532929c57..1ac9b63b9c50 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -252,7 +252,6 @@ jobs: - "3.11" RUST: # Potential future MSRVs: - # 1.60 - new version of cxx - 1.60.0 # 1.67 - new version of pem - beta diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 03939c106b2e..df2b1abaf649 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -14,15 +14,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "asn1" version = "0.13.0" @@ -62,12 +53,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bumpalo" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" - [[package]] name = "cc" version = "1.0.79" @@ -86,28 +71,10 @@ version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" dependencies = [ - "iana-time-zone", "num-integer", "num-traits", - "winapi", ] -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - [[package]] name = "cryptography-rust" version = "0.1.0" @@ -124,50 +91,6 @@ dependencies = [ "pyo3", ] -[[package]] -name = "cxx" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d1075c37807dcf850c379432f0df05ba52cc30f279c5cfc43cc221ce7f8579" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5044281f61b27bc598f2f6647d480aed48d2bf52d6eb0b627d84c0361b17aa70" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 1.0.109", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b50bc93ba22c27b0d31128d2d130a0a6b3d267ae27ef7e4fae2167dfe8781c" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e61fda7e62115119469c7b3591fd913ecca96fb766cfd3f2e2502ab7bc87a5" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "foreign-types" version = "0.3.2" @@ -183,60 +106,18 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -[[package]] -name = "iana-time-zone" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" -dependencies = [ - "cxx", - "cxx-build", -] - [[package]] name = "indoc" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" -[[package]] -name = "js-sys" -version = "0.3.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" -dependencies = [ - "wasm-bindgen", -] - [[package]] name = "libc" version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - [[package]] name = "lock_api" version = "0.4.9" @@ -247,15 +128,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - [[package]] name = "memoffset" version = "0.8.0" @@ -506,12 +378,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scratch" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" - [[package]] name = "smallvec" version = "1.10.0" @@ -546,27 +412,12 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - [[package]] name = "unicode-ident" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - [[package]] name = "unindent" version = "0.1.11" @@ -585,100 +436,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "wasm-bindgen" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 1.0.109", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.45.0" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 5b5a671d497b..e7f0e1baddd6 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -12,7 +12,7 @@ once_cell = "1" pyo3 = { version = "0.18" } asn1 = { version = "0.13.0", default-features = false, features = ["const-generics"] } pem = "1.1" -chrono = { version = "0.4.24", default-features = false, features = ["alloc", "clock"] } +chrono = { version = "0.4.24", default-features = false } ouroboros = "0.15" openssl = "0.10.49" openssl-sys = "0.9.84" diff --git a/src/rust/src/pkcs7.rs b/src/rust/src/pkcs7.rs index 4904dd8cc250..9b1920f1d2ed 100644 --- a/src/rust/src/pkcs7.rs +++ b/src/rust/src/pkcs7.rs @@ -7,7 +7,6 @@ use crate::buf::CffiBuf; use crate::error::CryptographyResult; use crate::x509; -use chrono::Timelike; use once_cell::sync::Lazy; use std::borrow::Cow; use std::collections::HashMap; @@ -149,9 +148,8 @@ fn sign_and_serialize<'p>( }; let content_type_bytes = asn1::write_single(&PKCS7_DATA_OID)?; - let signing_time_bytes = asn1::write_single(&x509::certificate::time_from_chrono( - chrono::Utc::now().with_nanosecond(0).unwrap(), - )?)?; + let now = x509::common::chrono_now(py)?; + let signing_time_bytes = asn1::write_single(&x509::certificate::time_from_chrono(now)?)?; let smime_cap_bytes = asn1::write_single(&asn1::SequenceOfWriter::new([ // Subset of values OpenSSL provides: // https://github.com/openssl/openssl/blob/667a8501f0b6e5705fd611d5bb3ca24848b07154/crypto/pkcs7/pk7_smime.c#L150 diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index a5f642e0d1ef..9bed702d7991 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -701,6 +701,15 @@ pub(crate) fn py_to_chrono( .unwrap()) } +pub(crate) fn chrono_now(py: pyo3::Python<'_>) -> pyo3::PyResult> { + py_to_chrono( + py, + py.import(pyo3::intern!(py, "datetime"))? + .getattr(pyo3::intern!(py, "datetime"))? + .call_method0(pyo3::intern!(py, "utcnow"))?, + ) +} + #[derive(Hash, PartialEq, Clone)] pub(crate) enum Asn1ReadableOrWritable<'a, T, U> { Read(T, PhantomData<&'a ()>), diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index e8f864c42f1e..1679503b6b2a 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -6,7 +6,6 @@ use crate::asn1::{big_byte_slice_to_py_int, oid_to_py_oid}; use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{certificate, crl, extensions, ocsp, oid, py_to_chrono, sct}; -use chrono::Timelike; use pyo3::IntoPy; use std::sync::Arc; @@ -723,9 +722,7 @@ fn create_ocsp_response( let tbs_response_data = ResponseData { version: 0, - produced_at: asn1::GeneralizedTime::new( - chrono::Utc::now().with_nanosecond(0).unwrap(), - )?, + produced_at: asn1::GeneralizedTime::new(x509::common::chrono_now(py)?)?, responder_id, responses: x509::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new( responses, From 5a2c495b2962332816da00dbefc644dc1c92a8f5 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 2 Apr 2023 17:31:26 -0400 Subject: [PATCH 064/316] Upgrade to Rust 2021 edition (#8656) --- src/rust/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index e7f0e1baddd6..4608a992eb2c 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -2,7 +2,7 @@ name = "cryptography-rust" version = "0.1.0" authors = ["The cryptography developers "] -edition = "2018" +edition = "2021" publish = false # This specifies the MSRV rust-version = "1.56.0" From 48c3226bf4d59240cc9fba1e3648ed19d121eece Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 00:17:08 +0000 Subject: [PATCH 065/316] Bump BoringSSL and/or OpenSSL in CI (#8659) Co-authored-by: pyca-boringbot[bot] --- .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 1ac9b63b9c50..38ded9a1ec2c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,8 +44,8 @@ jobs: - {VERSION: "3.12-dev", NOXSESSION: "tests"} # Latest commit on the BoringSSL master branch, as of Apr 01, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "d89702704febab30774e8af22450899af297bfb0"}} - # Latest commit on the OpenSSL master branch, as of Apr 01, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "9559ad0e8d433a2a212b63cc848fa2ac82a9b048"}} + # Latest commit on the OpenSSL master branch, as of Apr 03, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "eb52450f5151e8e78743ab05de21a344823316f5"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.0 From 84ffbe3c6bdc5d1e9a892432f4563740d7b540c9 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 2 Apr 2023 23:38:22 -0400 Subject: [PATCH 066/316] Several rust cleanups suggested by clippy in pedantic mode (#8658) --- src/rust/build.rs | 2 +- src/rust/src/backend/x25519.rs | 18 ++++++++---------- src/rust/src/lib.rs | 1 - src/rust/src/x509/common.rs | 1 - src/rust/src/x509/crl.rs | 1 - src/rust/src/x509/csr.rs | 11 +++++------ src/rust/src/x509/sct.rs | 1 - src/rust/src/x509/sign.rs | 16 +++++++--------- 8 files changed, 21 insertions(+), 30 deletions(-) diff --git a/src/rust/build.rs b/src/rust/build.rs index 4f0f39aae6b1..faddff8eceb4 100644 --- a/src/rust/build.rs +++ b/src/rust/build.rs @@ -78,7 +78,7 @@ fn main() { println!("cargo:rustc-cfg=CRYPTOGRAPHY_IS_LIBRESSL"); if version >= 0x3_07_00_00_0 { - println!("cargo:rustc-cfg=CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER") + println!("cargo:rustc-cfg=CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER"); } } } diff --git a/src/rust/src/backend/x25519.rs b/src/rust/src/backend/x25519.rs index 988d0076ef5f..7fb6ca2fc4b1 100644 --- a/src/rust/src/backend/x25519.rs +++ b/src/rust/src/backend/x25519.rs @@ -191,11 +191,10 @@ impl X25519PrivateKey { )? }; return Ok(pyo3::types::PyBytes::new(py, &der_bytes)); - } else { - return Err(CryptographyError::from( - pyo3::exceptions::PyValueError::new_err("Unsupported encoding for PKCS8"), - )); } + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err("Unsupported encoding for PKCS8"), + )); } Err(CryptographyError::from( @@ -267,13 +266,12 @@ impl X25519PublicKey { } else if encoding.is(encoding_class.getattr(pyo3::intern!(py, "DER"))?) { let der_bytes = self.pkey.public_key_to_der()?; return Ok(pyo3::types::PyBytes::new(py, &der_bytes)); - } else { - return Err(CryptographyError::from( - pyo3::exceptions::PyValueError::new_err( - "SubjectPublicKeyInfo works only with PEM or DER encoding", - ), - )); } + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err( + "SubjectPublicKeyInfo works only with PEM or DER encoding", + ), + )); } Err(CryptographyError::from( diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index e8608150421c..74989350bad7 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -20,7 +20,6 @@ mod x509; #[cfg(not(python_implementation = "PyPy"))] use pyo3::FromPyPointer; -use std::convert::TryInto; #[cfg(python_implementation = "PyPy")] extern "C" { diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index 9bed702d7991..608a4bb6d4d7 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -9,7 +9,6 @@ use chrono::{Datelike, TimeZone, Timelike}; use pyo3::types::IntoPyDict; use pyo3::ToPyObject; use std::collections::HashSet; -use std::convert::TryInto; use std::marker::PhantomData; /// Parse all sections in a PEM file and return the first matching section. diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index 7644cfd2715a..fbe27501db2e 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -9,7 +9,6 @@ use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{certificate, extensions, oid, sign}; use pyo3::{IntoPy, ToPyObject}; -use std::convert::TryInto; use std::sync::Arc; #[pyo3::prelude::pyfunction] diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index b90e49e3e0ee..d9eeb400ac66 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -216,13 +216,12 @@ impl CertificateSigningRequest { || val.tag() == asn1::IA5String::TAG { return Ok(pyo3::types::PyBytes::new(py, val.data())); - } else { - return Err(pyo3::exceptions::PyValueError::new_err(format!( - "OID {} has a disallowed ASN.1 type: {:?}", - oid, - val.tag() - ))); } + return Err(pyo3::exceptions::PyValueError::new_err(format!( + "OID {} has a disallowed ASN.1 type: {:?}", + oid, + val.tag() + ))); } } Err(pyo3::PyErr::from_value( diff --git a/src/rust/src/x509/sct.rs b/src/rust/src/x509/sct.rs index 09e1ae4486c9..35ae088c0b85 100644 --- a/src/rust/src/x509/sct.rs +++ b/src/rust/src/x509/sct.rs @@ -6,7 +6,6 @@ use crate::error::CryptographyError; use pyo3::types::IntoPyDict; use pyo3::ToPyObject; use std::collections::hash_map::DefaultHasher; -use std::convert::{TryFrom, TryInto}; use std::hash::{Hash, Hasher}; struct TLSReader<'a> { diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index 7a788300ebbf..fb46c5c8fb1d 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -135,11 +135,9 @@ pub(crate) fn compute_signature_algorithm<'p>( oid: (oid::ED448_OID).clone(), params: None, }), - (KeyType::Ed25519, _) | (KeyType::Ed448, _) => { - Err(pyo3::exceptions::PyValueError::new_err( - "Algorithm must be None when signing via ed25519 or ed448", - )) - } + (KeyType::Ed25519 | KeyType::Ed448, _) => Err(pyo3::exceptions::PyValueError::new_err( + "Algorithm must be None when signing via ed25519 or ed448", + )), (KeyType::Ec, HashType::Sha224) => Ok(x509::AlgorithmIdentifier { oid: (oid::ECDSA_WITH_SHA224_OID).clone(), @@ -223,10 +221,10 @@ pub(crate) fn compute_signature_algorithm<'p>( oid: (oid::DSA_WITH_SHA512_OID).clone(), params: None, }), - (KeyType::Dsa, HashType::Sha3_224) - | (KeyType::Dsa, HashType::Sha3_256) - | (KeyType::Dsa, HashType::Sha3_384) - | (KeyType::Dsa, HashType::Sha3_512) => Err(pyo3::PyErr::from_value( + ( + KeyType::Dsa, + HashType::Sha3_224 | HashType::Sha3_256 | HashType::Sha3_384 | HashType::Sha3_512, + ) => Err(pyo3::PyErr::from_value( py.import("cryptography.exceptions")?.call_method1( "UnsupportedAlgorithm", ("SHA3 hashes are not supported with DSA keys",), From 0e2421c810747ff09755d36e65b78abd753c7720 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 20:54:18 +0000 Subject: [PATCH 067/316] Bump proc-macro2 from 1.0.55 to 1.0.56 in /src/rust (#8661) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.55 to 1.0.56. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.55...1.0.56) --- 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 df2b1abaf649..8c60123ac456 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -287,9 +287,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.55" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0dd4be24fcdcfeaa12a432d588dc59bbad6cad3510c67e74a2b6b2fc950564" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] From a4fae22d7ccc6764d41117ebf764eadb0604111e Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Tue, 4 Apr 2023 00:58:20 +0000 Subject: [PATCH 068/316] Bump BoringSSL and/or OpenSSL in CI (#8663) Co-authored-by: pyca-boringbot[bot] --- .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 38ded9a1ec2c..e8a3320c3e47 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,10 +42,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.1"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 01, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "d89702704febab30774e8af22450899af297bfb0"}} - # Latest commit on the OpenSSL master branch, as of Apr 03, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "eb52450f5151e8e78743ab05de21a344823316f5"}} + # Latest commit on the BoringSSL master branch, as of Apr 04, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "6e723e5b37f7387f1c787a57c63e6d993d0c0d92"}} + # Latest commit on the OpenSSL master branch, as of Apr 04, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "418c6c520764491262018c45481a20ef10cd3bca"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.0 From eb59d966b6ba7e34071088de16f33d9cee682102 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 4 Apr 2023 19:51:51 +0900 Subject: [PATCH 069/316] remove pytest-shard (#8665) --- .github/workflows/ci.yml | 3 +-- ci-constraints-requirements.txt | 3 --- pyproject.toml | 1 - 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e8a3320c3e47..16787de8cefc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -431,7 +431,6 @@ jobs: PYTHON: - {VERSION: "3.7", NOXSESSION: "tests-nocoverage"} - {VERSION: "3.11", NOXSESSION: "tests"} - JOB_NUMBER: [0, 1] timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.0 @@ -478,7 +477,7 @@ jobs: NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }} CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - name: Tests - run: nox --no-install -- --color=yes --wycheproof-root=wycheproof --num-shards=2 --shard-id=${{ matrix.JOB_NUMBER }} + run: nox --no-install -- --color=yes --wycheproof-root=wycheproof env: NOXSESSION: ${{ matrix.PYTHON.NOXSESSION }} COLUMNS: 80 diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 20bf7a5cedce..92fb5fc9d4c3 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -111,7 +111,6 @@ pytest==7.2.2 # pytest-benchmark # pytest-cov # pytest-randomly - # pytest-shard # pytest-xdist pytest-benchmark==4.0.0 # via cryptography (pyproject.toml) @@ -119,8 +118,6 @@ pytest-cov==4.0.0 # via cryptography (pyproject.toml) pytest-randomly==3.12.0 # via cryptography (pyproject.toml) -pytest-shard==0.1.2 - # via cryptography (pyproject.toml) pytest-xdist==3.2.1 # via cryptography (pyproject.toml) readme-renderer==37.3 diff --git a/pyproject.toml b/pyproject.toml index 480b4fbbeb3d..8024179a9738 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,7 +75,6 @@ ssh = ["bcrypt >=3.1.5"] nox = ["nox"] test = [ "pytest >=6.2.0", - "pytest-shard >=0.1.2", "pytest-benchmark", "pytest-cov", "pytest-xdist", From eeca346f23d2595864ec3cff86d562974cff480a Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 4 Apr 2023 20:04:55 +0900 Subject: [PATCH 070/316] upgrade rust-asn1, which removes chrono dep (#8664) * use new rust-asn1 non-chrono path * bump asn1 * oh yeah, remove that --- src/rust/Cargo.lock | 41 ++++------------------------- src/rust/Cargo.toml | 3 +-- src/rust/src/pkcs7.rs | 4 +-- src/rust/src/x509/certificate.rs | 21 +++++++-------- src/rust/src/x509/common.rs | 44 ++++++++++++++++---------------- src/rust/src/x509/crl.rs | 10 ++++---- src/rust/src/x509/extensions.rs | 7 ++--- src/rust/src/x509/mod.rs | 6 ++--- src/rust/src/x509/ocsp_resp.rs | 18 ++++++------- 9 files changed, 58 insertions(+), 96 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 8c60123ac456..b24b3373933e 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -16,23 +16,22 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" [[package]] name = "asn1" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2affba5e62ee09eeba078f01a00c4aed45ac4287e091298eccbb0d4802efbdc5" +checksum = "48a34f02cde9e43d380b3c72f3deb14b9ef8bf262bd3c92426437b21e74a509a" dependencies = [ "asn1_derive", - "chrono", ] [[package]] name = "asn1_derive" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfab79c195875e5aef2bd20b4c8ed8d43ef9610bcffefbbcf66f88f555cc78af" +checksum = "ee4d9abdcc064cc9568bff2599089bb497a7de2c4b59608de35e3380b496617a" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.12", ] [[package]] @@ -65,23 +64,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chrono" -version = "0.4.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" -dependencies = [ - "num-integer", - "num-traits", -] - [[package]] name = "cryptography-rust" version = "0.1.0" dependencies = [ "asn1", "cc", - "chrono", "foreign-types-shared", "once_cell", "openssl", @@ -137,25 +125,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - [[package]] name = "once_cell" version = "1.17.1" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 4608a992eb2c..5fa9c31df72d 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -10,9 +10,8 @@ rust-version = "1.56.0" [dependencies] once_cell = "1" pyo3 = { version = "0.18" } -asn1 = { version = "0.13.0", default-features = false, features = ["const-generics"] } +asn1 = { version = "0.14.0", default-features = false } pem = "1.1" -chrono = { version = "0.4.24", default-features = false } ouroboros = "0.15" openssl = "0.10.49" openssl-sys = "0.9.84" diff --git a/src/rust/src/pkcs7.rs b/src/rust/src/pkcs7.rs index 9b1920f1d2ed..360c767b36cd 100644 --- a/src/rust/src/pkcs7.rs +++ b/src/rust/src/pkcs7.rs @@ -148,8 +148,8 @@ fn sign_and_serialize<'p>( }; let content_type_bytes = asn1::write_single(&PKCS7_DATA_OID)?; - let now = x509::common::chrono_now(py)?; - let signing_time_bytes = asn1::write_single(&x509::certificate::time_from_chrono(now)?)?; + let now = x509::common::datetime_now(py)?; + let signing_time_bytes = asn1::write_single(&x509::certificate::time_from_datetime(now)?)?; let smime_cap_bytes = asn1::write_single(&asn1::SequenceOfWriter::new([ // Subset of values OpenSSL provides: // https://github.com/openssl/openssl/blob/667a8501f0b6e5705fd611d5bb3ca24848b07154/crypto/pkcs7/pk7_smime.c#L150 diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index efbab2449780..160048436e24 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -8,7 +8,6 @@ use crate::asn1::{ use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{crl, extensions, oid, sct, sign, Asn1ReadableOrWritable}; -use chrono::Datelike; use pyo3::{IntoPy, ToPyObject}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; @@ -239,26 +238,26 @@ impl Certificate { #[getter] fn not_valid_before<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - let chrono = &self + let dt = &self .raw .borrow_value() .tbs_cert .validity .not_before - .as_chrono(); - x509::chrono_to_py(py, chrono) + .as_datetime(); + x509::datetime_to_py(py, dt) } #[getter] fn not_valid_after<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - let chrono = &self + let dt = &self .raw .borrow_value() .tbs_cert .validity .not_after - .as_chrono(); - x509::chrono_to_py(py, chrono) + .as_datetime(); + x509::datetime_to_py(py, dt) } #[getter] @@ -994,13 +993,11 @@ pub(crate) fn time_from_py( py: pyo3::Python<'_>, val: &pyo3::PyAny, ) -> CryptographyResult { - let dt = x509::py_to_chrono(py, val)?; - time_from_chrono(dt) + let dt = x509::py_to_datetime(py, val)?; + time_from_datetime(dt) } -pub(crate) fn time_from_chrono( - dt: chrono::DateTime, -) -> CryptographyResult { +pub(crate) fn time_from_datetime(dt: asn1::DateTime) -> CryptographyResult { if dt.year() >= 2050 { Ok(x509::Time::GeneralizedTime(asn1::GeneralizedTime::new(dt)?)) } else { diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index 608a4bb6d4d7..fe3c21768ab2 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -5,7 +5,6 @@ use crate::asn1::{oid_to_py_oid, py_oid_to_oid}; use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; -use chrono::{Datelike, TimeZone, Timelike}; use pyo3::types::IntoPyDict; use pyo3::ToPyObject; use std::collections::HashSet; @@ -310,10 +309,10 @@ pub(crate) enum Time { } impl Time { - pub(crate) fn as_chrono(&self) -> &chrono::DateTime { + pub(crate) fn as_datetime(&self) -> &asn1::DateTime { match self { - Time::UtcTime(data) => data.as_chrono(), - Time::GeneralizedTime(data) => data.as_chrono(), + Time::UtcTime(data) => data.as_datetime(), + Time::GeneralizedTime(data) => data.as_datetime(), } } } @@ -667,9 +666,9 @@ fn encode_extension_value<'p>( ))) } -pub(crate) fn chrono_to_py<'p>( +pub(crate) fn datetime_to_py<'p>( py: pyo3::Python<'p>, - dt: &chrono::DateTime, + dt: &asn1::DateTime, ) -> pyo3::PyResult<&'p pyo3::PyAny> { let datetime_module = py.import("datetime")?; datetime_module @@ -684,24 +683,25 @@ pub(crate) fn chrono_to_py<'p>( )) } -pub(crate) fn py_to_chrono( +// TODO +pub(crate) fn py_to_datetime( py: pyo3::Python<'_>, val: &pyo3::PyAny, -) -> pyo3::PyResult> { - Ok(chrono::Utc - .with_ymd_and_hms( - val.getattr(pyo3::intern!(py, "year"))?.extract()?, - val.getattr(pyo3::intern!(py, "month"))?.extract()?, - val.getattr(pyo3::intern!(py, "day"))?.extract()?, - val.getattr(pyo3::intern!(py, "hour"))?.extract()?, - val.getattr(pyo3::intern!(py, "minute"))?.extract()?, - val.getattr(pyo3::intern!(py, "second"))?.extract()?, - ) - .unwrap()) -} - -pub(crate) fn chrono_now(py: pyo3::Python<'_>) -> pyo3::PyResult> { - py_to_chrono( +) -> pyo3::PyResult { + Ok(asn1::DateTime::new( + val.getattr(pyo3::intern!(py, "year"))?.extract()?, + val.getattr(pyo3::intern!(py, "month"))?.extract()?, + val.getattr(pyo3::intern!(py, "day"))?.extract()?, + val.getattr(pyo3::intern!(py, "hour"))?.extract()?, + val.getattr(pyo3::intern!(py, "minute"))?.extract()?, + val.getattr(pyo3::intern!(py, "second"))?.extract()?, + ) + .unwrap()) +} + +// TODO +pub(crate) fn datetime_now(py: pyo3::Python<'_>) -> pyo3::PyResult { + py_to_datetime( py, py.import(pyo3::intern!(py, "datetime"))? .getattr(pyo3::intern!(py, "datetime"))? diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index fbe27501db2e..50beb85ecda2 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -245,20 +245,20 @@ impl CertificateRevocationList { #[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) => x509::chrono_to_py(py, t.as_chrono()), + Some(t) => x509::datetime_to_py(py, t.as_datetime()), None => Ok(py.None().into_ref(py)), } } #[getter] fn last_update<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - x509::chrono_to_py( + x509::datetime_to_py( py, self.raw .borrow_value() .tbs_cert_list .this_update - .as_chrono(), + .as_datetime(), ) } @@ -531,7 +531,7 @@ impl RevokedCertificate { #[getter] fn revocation_date<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - x509::chrono_to_py(py, self.raw.borrow_value().revocation_date.as_chrono()) + x509::datetime_to_py(py, self.raw.borrow_value().revocation_date.as_datetime()) } #[getter] @@ -631,7 +631,7 @@ pub fn parse_crl_entry_ext<'p>( } oid::INVALIDITY_DATE_OID => { let time = asn1::parse_single::(data)?; - let py_dt = x509::chrono_to_py(py, time.as_chrono())?; + let py_dt = x509::datetime_to_py(py, time.as_datetime())?; Ok(Some( x509_module .getattr(pyo3::intern!(py, "InvalidityDate"))? diff --git a/src/rust/src/x509/extensions.rs b/src/rust/src/x509/extensions.rs index 79170a616612..cded8890dbac 100644 --- a/src/rust/src/x509/extensions.rs +++ b/src/rust/src/x509/extensions.rs @@ -390,11 +390,8 @@ pub(crate) fn encode_extension( Ok(Some(asn1::write_single(&asn1::SequenceOfWriter::new(gns))?)) } &oid::INVALIDITY_DATE_OID => { - let chrono_dt = - x509::py_to_chrono(py, ext.getattr(pyo3::intern!(py, "invalidity_date"))?)?; - Ok(Some(asn1::write_single(&asn1::GeneralizedTime::new( - chrono_dt, - )?)?)) + let dt = x509::py_to_datetime(py, ext.getattr(pyo3::intern!(py, "invalidity_date"))?)?; + Ok(Some(asn1::write_single(&asn1::GeneralizedTime::new(dt)?)?)) } &oid::CRL_NUMBER_OID | &oid::DELTA_CRL_INDICATOR_OID => { let intval = ext diff --git a/src/rust/src/x509/mod.rs b/src/rust/src/x509/mod.rs index 8c7b39f4b369..2ad15c6e6dbc 100644 --- a/src/rust/src/x509/mod.rs +++ b/src/rust/src/x509/mod.rs @@ -16,7 +16,7 @@ pub(crate) mod sign; pub(crate) use certificate::Certificate; pub(crate) use common::{ - chrono_to_py, find_in_pem, parse_and_cache_extensions, parse_general_name, parse_general_names, - parse_name, parse_rdn, py_to_chrono, AlgorithmIdentifier, Asn1ReadableOrWritable, - AttributeTypeValue, Extensions, GeneralName, Name, Time, + datetime_to_py, find_in_pem, parse_and_cache_extensions, parse_general_name, + parse_general_names, parse_name, parse_rdn, py_to_datetime, AlgorithmIdentifier, + Asn1ReadableOrWritable, AttributeTypeValue, Extensions, GeneralName, Name, Time, }; diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index 1679503b6b2a..cec07a2ffbd8 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -5,7 +5,7 @@ use crate::asn1::{big_byte_slice_to_py_int, oid_to_py_oid}; use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; -use crate::x509::{certificate, crl, extensions, ocsp, oid, py_to_chrono, sct}; +use crate::x509::{certificate, crl, extensions, ocsp, oid, py_to_datetime, sct}; use pyo3::IntoPy; use std::sync::Arc; @@ -158,7 +158,7 @@ impl OCSPResponse { #[getter] fn produced_at<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let resp = self.requires_successful_response()?; - x509::chrono_to_py(py, resp.tbs_response_data.produced_at.as_chrono()) + x509::datetime_to_py(py, resp.tbs_response_data.produced_at.as_datetime()) } #[getter] @@ -549,12 +549,12 @@ impl SingleResponse<'_> { } fn py_this_update<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - x509::chrono_to_py(py, self.this_update.as_chrono()) + x509::datetime_to_py(py, self.this_update.as_datetime()) } fn py_next_update<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { match &self.next_update { - Some(v) => x509::chrono_to_py(py, v.as_chrono()), + Some(v) => x509::datetime_to_py(py, v.as_datetime()), None => Ok(py.None().into_ref(py)), } } @@ -575,7 +575,7 @@ impl SingleResponse<'_> { fn py_revocation_time<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { match &self.cert_status { CertStatus::Revoked(revoked_info) => { - x509::chrono_to_py(py, revoked_info.revocation_time.as_chrono()) + x509::datetime_to_py(py, revoked_info.revocation_time.as_datetime()) } CertStatus::Good(_) | CertStatus::Unknown(_) => Ok(py.None().into_ref(py)), } @@ -660,7 +660,7 @@ fn create_ocsp_response( let py_revocation_time = py_single_resp.getattr(pyo3::intern!(py, "_revocation_time"))?; let revocation_time = - asn1::GeneralizedTime::new(py_to_chrono(py, py_revocation_time)?)?; + asn1::GeneralizedTime::new(py_to_datetime(py, py_revocation_time)?)?; CertStatus::Revoked(RevokedInfo { revocation_time, revocation_reason, @@ -671,7 +671,7 @@ fn create_ocsp_response( .is_none() { let py_next_update = py_single_resp.getattr(pyo3::intern!(py, "_next_update"))?; - Some(asn1::GeneralizedTime::new(py_to_chrono( + Some(asn1::GeneralizedTime::new(py_to_datetime( py, py_next_update, )?)?) @@ -679,7 +679,7 @@ fn create_ocsp_response( None }; let py_this_update = py_single_resp.getattr(pyo3::intern!(py, "_this_update"))?; - let this_update = asn1::GeneralizedTime::new(py_to_chrono(py, py_this_update)?)?; + let this_update = asn1::GeneralizedTime::new(py_to_datetime(py, py_this_update)?)?; let responses = vec![SingleResponse { cert_id: ocsp::CertID::new(py, &py_cert, &py_issuer, py_cert_hash_algorithm)?, @@ -722,7 +722,7 @@ fn create_ocsp_response( let tbs_response_data = ResponseData { version: 0, - produced_at: asn1::GeneralizedTime::new(x509::common::chrono_now(py)?)?, + produced_at: asn1::GeneralizedTime::new(x509::common::datetime_now(py)?)?, responder_id, responses: x509::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new( responses, From 57be62f356e2b8e9bfb02099348b1ff2508aac68 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 4 Apr 2023 07:32:17 -0400 Subject: [PATCH 071/316] Remove accidentally left-over TODO comments (#8666) --- src/rust/src/x509/common.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index fe3c21768ab2..a4ac9b3d4cd9 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -683,7 +683,6 @@ pub(crate) fn datetime_to_py<'p>( )) } -// TODO pub(crate) fn py_to_datetime( py: pyo3::Python<'_>, val: &pyo3::PyAny, @@ -699,7 +698,6 @@ pub(crate) fn py_to_datetime( .unwrap()) } -// TODO pub(crate) fn datetime_now(py: pyo3::Python<'_>) -> pyo3::PyResult { py_to_datetime( py, From 634471258ff755c45b90f59d9a10b3b535f7b4d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Apr 2023 13:07:18 +0000 Subject: [PATCH 072/316] Bump libc from 0.2.140 to 0.2.141 in /src/rust (#8667) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.140 to 0.2.141. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/commits) --- 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 b24b3373933e..fd554872706f 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -102,9 +102,9 @@ checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" [[package]] name = "lock_api" From e970aefaaf94c5b010593dcbcc03a5d7adabea52 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Wed, 5 Apr 2023 09:28:20 +0900 Subject: [PATCH 073/316] Bump BoringSSL and/or OpenSSL in CI (#8670) Co-authored-by: pyca-boringbot[bot] --- .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 16787de8cefc..51196e4f3bd0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,8 +44,8 @@ jobs: - {VERSION: "3.12-dev", NOXSESSION: "tests"} # Latest commit on the BoringSSL master branch, as of Apr 04, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "6e723e5b37f7387f1c787a57c63e6d993d0c0d92"}} - # Latest commit on the OpenSSL master branch, as of Apr 04, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "418c6c520764491262018c45481a20ef10cd3bca"}} + # Latest commit on the OpenSSL master branch, as of Apr 05, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "f06ef1657a3d4322153b26231a7afa3d55724e52"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.0 From 0d4f9013d5fe09c9151e25fdba37d02044561931 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Apr 2023 13:06:58 +0000 Subject: [PATCH 074/316] Bump peter-evans/create-pull-request from 4.2.4 to 5.0.0 (#8672) Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 4.2.4 to 5.0.0. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/38e0b6e68b4c852a5500a94740f0e535e0d7ba54...5b4a9f6a9e2af26e5f02351490b90d01eb8ec1e5) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/boring-open-version-bump.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/boring-open-version-bump.yml b/.github/workflows/boring-open-version-bump.yml index 66a9ad5b0c28..5e96a3e3ba8a 100644 --- a/.github/workflows/boring-open-version-bump.yml +++ b/.github/workflows/boring-open-version-bump.yml @@ -58,7 +58,7 @@ jobs: private_key: ${{ secrets.BORINGBOT_PRIVATE_KEY }} if: steps.check-sha-boring.outputs.COMMIT_SHA || steps.check-sha-openssl.outputs.COMMIT_SHA - name: Create Pull Request - uses: peter-evans/create-pull-request@38e0b6e68b4c852a5500a94740f0e535e0d7ba54 + uses: peter-evans/create-pull-request@5b4a9f6a9e2af26e5f02351490b90d01eb8ec1e5 with: commit-message: "Bump BoringSSL and/or OpenSSL in CI" title: "Bump BoringSSL and/or OpenSSL in CI" From 074e0a41288e9b4c8655e26cd81e198a14df933e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Apr 2023 13:07:27 +0000 Subject: [PATCH 075/316] Bump dawidd6/action-download-artifact from 2.26.0 to 2.26.1 (#8673) Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 2.26.0 to 2.26.1. - [Release notes](https://github.com/dawidd6/action-download-artifact/releases) - [Commits](https://github.com/dawidd6/action-download-artifact/compare/5e780fc7bbd0cac69fc73271ed86edf5dcb72d67...7132ab516fba5f602fafae6fdd4822afa10db76f) --- updated-dependencies: - dependency-name: dawidd6/action-download-artifact 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/ci.yml | 4 ++-- .github/workflows/pypi-publish.yml | 2 +- .github/workflows/wheel-builder.yml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 51196e4f3bd0..e8aeacc5344d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -394,7 +394,7 @@ jobs: timeout-minutes: 2 uses: ./.github/actions/wycheproof - - uses: dawidd6/action-download-artifact@5e780fc7bbd0cac69fc73271ed86edf5dcb72d67 + - uses: dawidd6/action-download-artifact@7132ab516fba5f602fafae6fdd4822afa10db76f with: repo: pyca/infra workflow: build-macos-openssl.yml @@ -453,7 +453,7 @@ jobs: key: ${{ matrix.PYTHON.NOXSESSION }}-${{ matrix.WINDOWS.ARCH }}-${{ steps.setup-python.outputs.python-version }} - run: python -m pip install -c ci-constraints-requirements.txt "nox" coverage[toml] - - uses: dawidd6/action-download-artifact@5e780fc7bbd0cac69fc73271ed86edf5dcb72d67 + - uses: dawidd6/action-download-artifact@7132ab516fba5f602fafae6fdd4822afa10db76f with: repo: pyca/infra workflow: build-windows-openssl.yml diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml index f12b7244c32b..172bb131a9b9 100644 --- a/.github/workflows/pypi-publish.yml +++ b/.github/workflows/pypi-publish.yml @@ -25,7 +25,7 @@ jobs: permissions: id-token: "write" steps: - - uses: dawidd6/action-download-artifact@5e780fc7bbd0cac69fc73271ed86edf5dcb72d67 + - uses: dawidd6/action-download-artifact@7132ab516fba5f602fafae6fdd4822afa10db76f with: path: dist/ run_id: ${{ github.event.inputs.run_id || github.event.workflow_run.id }} diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index e7b7ace10347..62af5f7d8322 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -194,7 +194,7 @@ jobs: with: python-version: ${{ matrix.PYTHON.VERSION }} if: contains(matrix.PYTHON.VERSION, 'pypy') - - uses: dawidd6/action-download-artifact@5e780fc7bbd0cac69fc73271ed86edf5dcb72d67 + - uses: dawidd6/action-download-artifact@7132ab516fba5f602fafae6fdd4822afa10db76f with: repo: pyca/infra workflow: build-macos-openssl.yml @@ -273,7 +273,7 @@ jobs: toolchain: stable target: ${{ matrix.WINDOWS.RUST_TRIPLE }} - - uses: dawidd6/action-download-artifact@5e780fc7bbd0cac69fc73271ed86edf5dcb72d67 + - uses: dawidd6/action-download-artifact@7132ab516fba5f602fafae6fdd4822afa10db76f with: repo: pyca/infra workflow: build-windows-openssl.yml From 4ca343eec771d9f0c1a907e19168b57ceeb5b528 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Apr 2023 13:15:23 +0000 Subject: [PATCH 076/316] Bump ruff from 0.0.260 to 0.0.261 (#8674) Bumps [ruff](https://github.com/charliermarsh/ruff) from 0.0.260 to 0.0.261. - [Release notes](https://github.com/charliermarsh/ruff/releases) - [Changelog](https://github.com/charliermarsh/ruff/blob/main/BREAKING_CHANGES.md) - [Commits](https://github.com/charliermarsh/ruff/compare/v0.0.260...v0.0.261) --- updated-dependencies: - dependency-name: ruff 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 92fb5fc9d4c3..5e509a81d637 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -133,7 +133,7 @@ rfc3986==2.0.0 # via twine rich==13.3.3 # via twine -ruff==0.0.260 +ruff==0.0.261 # via cryptography (pyproject.toml) six==1.16.0 # via bleach From 88f0df598da153f8cfab37b43420140ccb4bb59d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 6 Apr 2023 17:21:02 -0500 Subject: [PATCH 077/316] Update MSRV comment (#8678) --- .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 e8aeacc5344d..d2a1118103ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -252,8 +252,8 @@ jobs: - "3.11" RUST: # Potential future MSRVs: + # 1.60 - pem 2.0.1 - 1.60.0 - # 1.67 - new version of pem - beta - nightly name: "Rust Coverage" From c70fdad216f56b1fe92875638fdc039c45986da4 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Thu, 6 Apr 2023 22:14:02 -0500 Subject: [PATCH 078/316] Bump BoringSSL and/or OpenSSL in CI (#8681) Co-authored-by: pyca-boringbot[bot] --- .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 d2a1118103ea..26549f45f1df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,8 +44,8 @@ jobs: - {VERSION: "3.12-dev", NOXSESSION: "tests"} # Latest commit on the BoringSSL master branch, as of Apr 04, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "6e723e5b37f7387f1c787a57c63e6d993d0c0d92"}} - # Latest commit on the OpenSSL master branch, as of Apr 05, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "f06ef1657a3d4322153b26231a7afa3d55724e52"}} + # Latest commit on the OpenSSL master branch, as of Apr 07, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "f309b3f6087db6c83126f8f227f1fc4984cf24b1"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.0 From f1b3858afe7fe670bc1eaa06ac87210d49e12a45 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Apr 2023 13:11:59 +0000 Subject: [PATCH 079/316] Bump coverage from 7.2.2 to 7.2.3 (#8683) Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.2.2 to 7.2.3. - [Release notes](https://github.com/nedbat/coveragepy/releases) - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst) - [Commits](https://github.com/nedbat/coveragepy/compare/7.2.2...7.2.3) --- updated-dependencies: - dependency-name: coverage 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 5e509a81d637..ef8e883478d8 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -30,7 +30,7 @@ click==8.1.3 # via black colorlog==6.7.0 # via nox -coverage==7.2.2 +coverage==7.2.3 # via pytest-cov distlib==0.3.6 # via virtualenv From 58f34d5b52d99b121a50fc4fc143307bbe5c9f37 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Apr 2023 13:14:33 +0000 Subject: [PATCH 080/316] Bump mypy from 1.1.1 to 1.2.0 (#8684) Bumps [mypy](https://github.com/python/mypy) from 1.1.1 to 1.2.0. - [Release notes](https://github.com/python/mypy/releases) - [Commits](https://github.com/python/mypy/compare/v1.1.1...v1.2.0) --- updated-dependencies: - dependency-name: mypy 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index ef8e883478d8..91fbf1f314f8 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -65,7 +65,7 @@ mdurl==0.1.2 # via markdown-it-py more-itertools==9.1.0 # via jaraco-classes -mypy==1.1.1 +mypy==1.2.0 # via cryptography (pyproject.toml) mypy-extensions==1.0.0 # via From 21c681ac880fc4009a760ca5bc7d9d6560944be4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Apr 2023 13:15:11 +0000 Subject: [PATCH 081/316] Bump filelock from 3.10.7 to 3.11.0 (#8685) Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.10.7 to 3.11.0. - [Release notes](https://github.com/tox-dev/py-filelock/releases) - [Changelog](https://github.com/tox-dev/py-filelock/blob/main/docs/changelog.rst) - [Commits](https://github.com/tox-dev/py-filelock/compare/3.10.7...3.11.0) --- updated-dependencies: - dependency-name: filelock 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 91fbf1f314f8..e119b6a70783 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -43,7 +43,7 @@ exceptiongroup==1.1.1 # via pytest execnet==1.9.0 # via pytest-xdist -filelock==3.10.7 +filelock==3.11.0 # via virtualenv idna==3.4 # via requests From 9077391b9057892303518b1c184d9917b28a2c21 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Sat, 8 Apr 2023 00:13:53 +0000 Subject: [PATCH 082/316] Bump BoringSSL and/or OpenSSL in CI (#8687) Co-authored-by: pyca-boringbot[bot] --- .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 26549f45f1df..accb44b8faf7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,8 +42,8 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.1"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 04, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "6e723e5b37f7387f1c787a57c63e6d993d0c0d92"}} + # Latest commit on the BoringSSL master branch, as of Apr 08, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "44a389a7fce31013b5953038d4231f33cbf2ba9d"}} # Latest commit on the OpenSSL master branch, as of Apr 07, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "f309b3f6087db6c83126f8f227f1fc4984cf24b1"}} timeout-minutes: 15 From 9f36c3fe69644ba0d0d880f8472d4b9a8677f384 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 8 Apr 2023 23:27:03 +0000 Subject: [PATCH 083/316] Bump pytest from 7.2.2 to 7.3.0 (#8689) Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.2.2 to 7.3.0. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.2.2...7.3.0) --- updated-dependencies: - dependency-name: pytest 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index e119b6a70783..b6b9289cb6e2 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -105,7 +105,7 @@ pygments==2.14.0 # sphinx pyproject-hooks==1.0.0 # via build -pytest==7.2.2 +pytest==7.3.0 # via # cryptography (pyproject.toml) # pytest-benchmark From 86ec17028522926bb21ee7bf49b0a1cf6b0477d6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 8 Apr 2023 18:29:06 -0500 Subject: [PATCH 084/316] silence noxfile warnings running cargo (#8688) --- noxfile.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/noxfile.py b/noxfile.py index 62634b03fe43..b60d6a602e63 100644 --- a/noxfile.py +++ b/noxfile.py @@ -141,6 +141,6 @@ def rust(session: nox.Session) -> None: install(session, ".") with session.chdir("src/rust/"): - session.run("cargo", "fmt", "--all", "--", "--check") - session.run("cargo", "clippy", "--", "-D", "warnings") - session.run("cargo", "test", "--no-default-features") + session.run("cargo", "fmt", "--all", "--", "--check", external=True) + session.run("cargo", "clippy", "--", "-D", "warnings", external=True) + session.run("cargo", "test", "--no-default-features", external=True) From 122211bb457a86f6588deb40242869449077d8e5 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 9 Apr 2023 16:48:42 -0500 Subject: [PATCH 085/316] Remove coverage workaround that might not be required anymore (#8690) --- tests/utils.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/utils.py b/tests/utils.py index 10f73c7ebd92..c87df65c1507 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -243,9 +243,6 @@ def load_pkcs1_vectors(vector_data): attr = None if private_key_vector is None or public_key_vector is None: - # Random garbage to defeat CPython's peephole optimizer so that - # coverage records correctly: https://bugs.python.org/issue2506 - 1 + 1 continue if line.startswith("# Private key"): From 84f69b169d10ee9985e7cc32f56b8afafb7d5595 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 9 Apr 2023 18:33:45 -0500 Subject: [PATCH 086/316] Migrate x448 to Rust (#8691) --- .../hazmat/backends/openssl/backend.py | 36 +--- .../hazmat/backends/openssl/x448.py | 119 ------------ .../bindings/_rust/openssl/__init__.pyi | 4 +- .../hazmat/bindings/_rust/openssl/x448.pyi | 14 ++ .../hazmat/primitives/asymmetric/x448.py | 19 +- src/rust/build.rs | 3 + src/rust/src/backend/mod.rs | 6 + src/rust/src/backend/utils.rs | 176 ++++++++++++++++++ src/rust/src/backend/x25519.rs | 159 +--------------- src/rust/src/backend/x448.rs | 144 ++++++++++++++ 10 files changed, 369 insertions(+), 311 deletions(-) delete mode 100644 src/cryptography/hazmat/backends/openssl/x448.py create mode 100644 src/cryptography/hazmat/bindings/_rust/openssl/x448.pyi create mode 100644 src/rust/src/backend/utils.rs create mode 100644 src/rust/src/backend/x448.rs diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index ac464e75a809..adda33285676 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -49,10 +49,6 @@ _RSAPrivateKey, _RSAPublicKey, ) -from cryptography.hazmat.backends.openssl.x448 import ( - _X448PrivateKey, - _X448PublicKey, -) from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.bindings.openssl import binding from cryptography.hazmat.primitives import hashes, serialization @@ -648,7 +644,9 @@ def _evp_pkey_to_private_key( return _Ed25519PrivateKey(self, evp_pkey) elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): # EVP_PKEY_X448 is not present in CRYPTOGRAPHY_IS_LIBRESSL - return _X448PrivateKey(self, evp_pkey) + return rust_openssl.x448.private_key_from_ptr( + int(self._ffi.cast("uintptr_t", evp_pkey)) + ) elif key_type == self._lib.EVP_PKEY_X25519: return rust_openssl.x25519.private_key_from_ptr( int(self._ffi.cast("uintptr_t", evp_pkey)) @@ -707,7 +705,9 @@ def _evp_pkey_to_public_key(self, evp_pkey) -> PublicKeyTypes: return _Ed25519PublicKey(self, evp_pkey) elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): # EVP_PKEY_X448 is not present in CRYPTOGRAPHY_IS_LIBRESSL - return _X448PublicKey(self, evp_pkey) + return rust_openssl.x448.public_key_from_ptr( + int(self._ffi.cast("uintptr_t", evp_pkey)) + ) elif key_type == self._lib.EVP_PKEY_X25519: return rust_openssl.x25519.public_key_from_ptr( int(self._ffi.cast("uintptr_t", evp_pkey)) @@ -1828,31 +1828,13 @@ def x25519_supported(self) -> bool: return not self._lib.CRYPTOGRAPHY_LIBRESSL_LESS_THAN_370 def x448_load_public_bytes(self, data: bytes) -> x448.X448PublicKey: - if len(data) != 56: - raise ValueError("An X448 public key is 56 bytes long") - - evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( - self._lib.NID_X448, self._ffi.NULL, data, len(data) - ) - self.openssl_assert(evp_pkey != self._ffi.NULL) - evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) - return _X448PublicKey(self, evp_pkey) + return rust_openssl.x448.from_public_bytes(data) def x448_load_private_bytes(self, data: bytes) -> x448.X448PrivateKey: - if len(data) != 56: - raise ValueError("An X448 private key is 56 bytes long") - - data_ptr = self._ffi.from_buffer(data) - evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( - self._lib.NID_X448, self._ffi.NULL, data_ptr, len(data) - ) - self.openssl_assert(evp_pkey != self._ffi.NULL) - evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) - return _X448PrivateKey(self, evp_pkey) + return rust_openssl.x448.from_private_bytes(data) def x448_generate_key(self) -> x448.X448PrivateKey: - evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_X448) - return _X448PrivateKey(self, evp_pkey) + return rust_openssl.x448.generate_key() def x448_supported(self) -> bool: if self._fips_enabled: diff --git a/src/cryptography/hazmat/backends/openssl/x448.py b/src/cryptography/hazmat/backends/openssl/x448.py deleted file mode 100644 index 5c91fba45279..000000000000 --- a/src/cryptography/hazmat/backends/openssl/x448.py +++ /dev/null @@ -1,119 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography.hazmat.backends.openssl.utils import _evp_pkey_derive -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives.asymmetric.x448 import ( - X448PrivateKey, - X448PublicKey, -) - -if typing.TYPE_CHECKING: - from cryptography.hazmat.backends.openssl.backend import Backend - -_X448_KEY_SIZE = 56 - - -class _X448PublicKey(X448PublicKey): - def __init__(self, backend: Backend, evp_pkey): - self._backend = backend - self._evp_pkey = evp_pkey - - def public_bytes( - self, - encoding: serialization.Encoding, - format: serialization.PublicFormat, - ) -> bytes: - if ( - encoding is serialization.Encoding.Raw - or format is serialization.PublicFormat.Raw - ): - if ( - encoding is not serialization.Encoding.Raw - or format is not serialization.PublicFormat.Raw - ): - raise ValueError( - "When using Raw both encoding and format must be Raw" - ) - - return self._raw_public_bytes() - - return self._backend._public_key_bytes( - encoding, format, self, self._evp_pkey, None - ) - - def _raw_public_bytes(self) -> bytes: - buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE) - buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE) - res = self._backend._lib.EVP_PKEY_get_raw_public_key( - self._evp_pkey, buf, buflen - ) - self._backend.openssl_assert(res == 1) - self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE) - return self._backend._ffi.buffer(buf, _X448_KEY_SIZE)[:] - - -class _X448PrivateKey(X448PrivateKey): - def __init__(self, backend: Backend, evp_pkey): - self._backend = backend - self._evp_pkey = evp_pkey - - def public_key(self) -> X448PublicKey: - buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE) - buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE) - res = self._backend._lib.EVP_PKEY_get_raw_public_key( - self._evp_pkey, buf, buflen - ) - self._backend.openssl_assert(res == 1) - self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE) - public_bytes = self._backend._ffi.buffer(buf)[:] - return self._backend.x448_load_public_bytes(public_bytes) - - def exchange(self, peer_public_key: X448PublicKey) -> bytes: - if not isinstance(peer_public_key, X448PublicKey): - raise TypeError("peer_public_key must be X448PublicKey.") - - return _evp_pkey_derive(self._backend, self._evp_pkey, peer_public_key) - - def private_bytes( - self, - encoding: serialization.Encoding, - format: serialization.PrivateFormat, - encryption_algorithm: serialization.KeySerializationEncryption, - ) -> bytes: - if ( - encoding is serialization.Encoding.Raw - or format is serialization.PrivateFormat.Raw - ): - if ( - format is not serialization.PrivateFormat.Raw - or encoding is not serialization.Encoding.Raw - or not isinstance( - encryption_algorithm, serialization.NoEncryption - ) - ): - raise ValueError( - "When using Raw both encoding and format must be Raw " - "and encryption_algorithm must be NoEncryption()" - ) - - return self._raw_private_bytes() - - return self._backend._private_key_bytes( - encoding, format, encryption_algorithm, self, self._evp_pkey, None - ) - - def _raw_private_bytes(self) -> bytes: - buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE) - buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE) - res = self._backend._lib.EVP_PKEY_get_raw_private_key( - self._evp_pkey, buf, buflen - ) - self._backend.openssl_assert(res == 1) - self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE) - return self._backend._ffi.buffer(buf, _X448_KEY_SIZE)[:] diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi index c19b6a9bcbeb..31e682b9ae36 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -4,9 +4,9 @@ import typing -from cryptography.hazmat.bindings._rust.openssl import x25519 +from cryptography.hazmat.bindings._rust.openssl import x448, x25519 -__all__ = ["openssl_version", "raise_openssl_error", "x25519"] +__all__ = ["openssl_version", "raise_openssl_error", "x448", "x25519"] def openssl_version() -> int: ... def raise_openssl_error() -> typing.NoReturn: ... diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/x448.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/x448.pyi new file mode 100644 index 000000000000..d326c8d2d7c5 --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/openssl/x448.pyi @@ -0,0 +1,14 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives.asymmetric import x448 + +class X448PrivateKey: ... +class X448PublicKey: ... + +def generate_key() -> x448.X448PrivateKey: ... +def private_key_from_ptr(ptr: int) -> x448.X448PrivateKey: ... +def public_key_from_ptr(ptr: int) -> x448.X448PublicKey: ... +def from_private_bytes(data: bytes) -> x448.X448PrivateKey: ... +def from_public_bytes(data: bytes) -> x448.X448PublicKey: ... diff --git a/src/cryptography/hazmat/primitives/asymmetric/x448.py b/src/cryptography/hazmat/primitives/asymmetric/x448.py index 25ff4c6ec36a..06b55d44b2a6 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/x448.py +++ b/src/cryptography/hazmat/primitives/asymmetric/x448.py @@ -7,6 +7,7 @@ import abc from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives import _serialization @@ -33,14 +34,16 @@ def public_bytes( The serialized bytes of the public key. """ + @abc.abstractmethod def public_bytes_raw(self) -> bytes: """ The raw bytes of the public key. Equivalent to public_bytes(Raw, Raw). """ - return self.public_bytes( - _serialization.Encoding.Raw, _serialization.PublicFormat.Raw - ) + + +if hasattr(rust_openssl, "x448"): + X448PublicKey.register(rust_openssl.x448.X448PublicKey) class X448PrivateKey(metaclass=abc.ABCMeta): @@ -84,19 +87,19 @@ def private_bytes( The serialized bytes of the private key. """ + @abc.abstractmethod def private_bytes_raw(self) -> bytes: """ The raw bytes of the private key. Equivalent to private_bytes(Raw, Raw, NoEncryption()). """ - return self.private_bytes( - _serialization.Encoding.Raw, - _serialization.PrivateFormat.Raw, - _serialization.NoEncryption(), - ) @abc.abstractmethod def exchange(self, peer_public_key: X448PublicKey) -> bytes: """ Performs a key exchange operation using the provided peer's public key. """ + + +if hasattr(rust_openssl, "x448"): + X448PrivateKey.register(rust_openssl.x448.X448PrivateKey) diff --git a/src/rust/build.rs b/src/rust/build.rs index faddff8eceb4..d315ec62d869 100644 --- a/src/rust/build.rs +++ b/src/rust/build.rs @@ -81,6 +81,9 @@ fn main() { println!("cargo:rustc-cfg=CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER"); } } + if env::var("DEP_OPENSSL_BORINGSSL").is_ok() { + println!("cargo:rustc-cfg=CRYPTOGRAPHY_IS_BORINGSSL"); + } } /// Run a python script using the specified interpreter binary. diff --git a/src/rust/src/backend/mod.rs b/src/rust/src/backend/mod.rs index c7e086b56efb..82beb444a2cb 100644 --- a/src/rust/src/backend/mod.rs +++ b/src/rust/src/backend/mod.rs @@ -2,12 +2,18 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. +#[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] +pub(crate) mod utils; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] pub(crate) mod x25519; +#[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] +pub(crate) mod x448; pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] module.add_submodule(x25519::create_module(module.py())?)?; + #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] + module.add_submodule(x448::create_module(module.py())?)?; Ok(()) } diff --git a/src/rust/src/backend/utils.rs b/src/rust/src/backend/utils.rs new file mode 100644 index 000000000000..97b2b0c64a63 --- /dev/null +++ b/src/rust/src/backend/utils.rs @@ -0,0 +1,176 @@ +// 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::error::{CryptographyError, CryptographyResult}; + +pub(crate) fn pkey_private_bytes<'p>( + py: pyo3::Python<'p>, + pkey: &openssl::pkey::PKey, + encoding: &pyo3::PyAny, + format: &pyo3::PyAny, + encryption_algorithm: &pyo3::PyAny, +) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let serialization_mod = py.import("cryptography.hazmat.primitives.serialization")?; + let encoding_class: &pyo3::types::PyType = serialization_mod + .getattr(pyo3::intern!(py, "Encoding"))? + .extract()?; + let private_format_class: &pyo3::types::PyType = serialization_mod + .getattr(pyo3::intern!(py, "PrivateFormat"))? + .extract()?; + let no_encryption_class: &pyo3::types::PyType = serialization_mod + .getattr(pyo3::intern!(py, "NoEncryption"))? + .extract()?; + let best_available_encryption_class: &pyo3::types::PyType = serialization_mod + .getattr(pyo3::intern!(py, "BestAvailableEncryption"))? + .extract()?; + + if !encoding.is_instance(encoding_class)? { + return Err(CryptographyError::from( + pyo3::exceptions::PyTypeError::new_err( + "encoding must be an item from the Encoding enum", + ), + )); + } + if !format.is_instance(private_format_class)? { + return Err(CryptographyError::from( + pyo3::exceptions::PyTypeError::new_err( + "format must be an item from the PrivateFormat enum", + ), + )); + } + + if encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) + || format.is(private_format_class.getattr(pyo3::intern!(py, "Raw"))?) + { + if !encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) + || !format.is(private_format_class.getattr(pyo3::intern!(py, "Raw"))?) + || !encryption_algorithm.is_instance(no_encryption_class)? + { + return Err(CryptographyError::from(pyo3::exceptions::PyValueError::new_err( + "When using Raw both encoding and format must be Raw and encryption_algorithm must be NoEncryption()" + ))); + } + let raw_bytes = pkey.raw_private_key()?; + return Ok(pyo3::types::PyBytes::new(py, &raw_bytes)); + } + + let password = if encryption_algorithm.is_instance(no_encryption_class)? { + b"" + } else if encryption_algorithm.is_instance(best_available_encryption_class)? { + encryption_algorithm + .getattr(pyo3::intern!(py, "password"))? + .extract::<&[u8]>()? + } else { + return Err(CryptographyError::from( + pyo3::exceptions::PyTypeError::new_err( + "Encryption algorithm must be a KeySerializationEncryption instance", + ), + )); + }; + + if password.len() > 1023 { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err( + "Passwords longer than 1023 bytes are not supported by this backend", + ), + )); + } + + if format.is(private_format_class.getattr(pyo3::intern!(py, "PKCS8"))?) { + if encoding.is(encoding_class.getattr(pyo3::intern!(py, "PEM"))?) { + let pem_bytes = if password.is_empty() { + pkey.private_key_to_pem_pkcs8()? + } else { + pkey.private_key_to_pem_pkcs8_passphrase( + openssl::symm::Cipher::aes_256_cbc(), + password, + )? + }; + return Ok(pyo3::types::PyBytes::new(py, &pem_bytes)); + } else if encoding.is(encoding_class.getattr(pyo3::intern!(py, "DER"))?) { + let der_bytes = if password.is_empty() { + pkey.private_key_to_pkcs8()? + } else { + pkey.private_key_to_pkcs8_passphrase( + openssl::symm::Cipher::aes_256_cbc(), + password, + )? + }; + return Ok(pyo3::types::PyBytes::new(py, &der_bytes)); + } + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err("Unsupported encoding for PKCS8"), + )); + } + + Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err("format is invalid with this key"), + )) +} + +pub(crate) fn pkey_public_bytes<'p>( + py: pyo3::Python<'p>, + pkey: &openssl::pkey::PKey, + encoding: &pyo3::PyAny, + format: &pyo3::PyAny, +) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let serialization_mod = py.import("cryptography.hazmat.primitives.serialization")?; + let encoding_class: &pyo3::types::PyType = serialization_mod + .getattr(pyo3::intern!(py, "Encoding"))? + .extract()?; + let public_format_class: &pyo3::types::PyType = serialization_mod + .getattr(pyo3::intern!(py, "PublicFormat"))? + .extract()?; + + if !encoding.is_instance(encoding_class)? { + return Err(CryptographyError::from( + pyo3::exceptions::PyTypeError::new_err( + "encoding must be an item from the Encoding enum", + ), + )); + } + if !format.is_instance(public_format_class)? { + return Err(CryptographyError::from( + pyo3::exceptions::PyTypeError::new_err( + "format must be an item from the PublicFormat enum", + ), + )); + } + + if encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) + || format.is(public_format_class.getattr(pyo3::intern!(py, "Raw"))?) + { + if !encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) + || !format.is(public_format_class.getattr(pyo3::intern!(py, "Raw"))?) + { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err( + "When using Raw both encoding and format must be Raw", + ), + )); + } + let raw_bytes = pkey.raw_public_key()?; + return Ok(pyo3::types::PyBytes::new(py, &raw_bytes)); + } + + // SubjectPublicKeyInfo + PEM/DER + if format.is(public_format_class.getattr(pyo3::intern!(py, "SubjectPublicKeyInfo"))?) { + if encoding.is(encoding_class.getattr(pyo3::intern!(py, "PEM"))?) { + let pem_bytes = pkey.public_key_to_pem()?; + return Ok(pyo3::types::PyBytes::new(py, &pem_bytes)); + } else if encoding.is(encoding_class.getattr(pyo3::intern!(py, "DER"))?) { + let der_bytes = pkey.public_key_to_der()?; + return Ok(pyo3::types::PyBytes::new(py, &der_bytes)); + } + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err( + "SubjectPublicKeyInfo works only with PEM or DER encoding", + ), + )); + } + + Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err("format is invalid with this key"), + )) +} diff --git a/src/rust/src/backend/x25519.rs b/src/rust/src/backend/x25519.rs index 7fb6ca2fc4b1..9cd86b00af8f 100644 --- a/src/rust/src/backend/x25519.rs +++ b/src/rust/src/backend/x25519.rs @@ -2,8 +2,9 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. +use crate::backend::utils; use crate::buf::CffiBuf; -use crate::error::{CryptographyError, CryptographyResult}; +use crate::error::CryptographyResult; use foreign_types_shared::ForeignTypeRef; #[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.x25519")] @@ -104,102 +105,7 @@ impl X25519PrivateKey { format: &pyo3::PyAny, encryption_algorithm: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - let serialization_mod = py.import("cryptography.hazmat.primitives.serialization")?; - let encoding_class: &pyo3::types::PyType = serialization_mod - .getattr(pyo3::intern!(py, "Encoding"))? - .extract()?; - let private_format_class: &pyo3::types::PyType = serialization_mod - .getattr(pyo3::intern!(py, "PrivateFormat"))? - .extract()?; - let no_encryption_class: &pyo3::types::PyType = serialization_mod - .getattr(pyo3::intern!(py, "NoEncryption"))? - .extract()?; - let best_available_encryption_class: &pyo3::types::PyType = serialization_mod - .getattr(pyo3::intern!(py, "BestAvailableEncryption"))? - .extract()?; - - if !encoding.is_instance(encoding_class)? { - return Err(CryptographyError::from( - pyo3::exceptions::PyTypeError::new_err( - "encoding must be an item from the Encoding enum", - ), - )); - } - if !format.is_instance(private_format_class)? { - return Err(CryptographyError::from( - pyo3::exceptions::PyTypeError::new_err( - "format must be an item from the PrivateFormat enum", - ), - )); - } - - if encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) - || format.is(private_format_class.getattr(pyo3::intern!(py, "Raw"))?) - { - if !encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) - || !format.is(private_format_class.getattr(pyo3::intern!(py, "Raw"))?) - || !encryption_algorithm.is_instance(no_encryption_class)? - { - return Err(CryptographyError::from(pyo3::exceptions::PyValueError::new_err( - "When using Raw both encoding and format must be Raw and encryption_algorithm must be NoEncryption()" - ))); - } - let raw_bytes = self.pkey.raw_private_key()?; - return Ok(pyo3::types::PyBytes::new(py, &raw_bytes)); - } - - let password = if encryption_algorithm.is_instance(no_encryption_class)? { - b"" - } else if encryption_algorithm.is_instance(best_available_encryption_class)? { - encryption_algorithm - .getattr(pyo3::intern!(py, "password"))? - .extract::<&[u8]>()? - } else { - return Err(CryptographyError::from( - pyo3::exceptions::PyTypeError::new_err( - "Encryption algorithm must be a KeySerializationEncryption instance", - ), - )); - }; - - if password.len() > 1023 { - return Err(CryptographyError::from( - pyo3::exceptions::PyValueError::new_err( - "Passwords longer than 1023 bytes are not supported by this backend", - ), - )); - } - - if format.is(private_format_class.getattr(pyo3::intern!(py, "PKCS8"))?) { - if encoding.is(encoding_class.getattr(pyo3::intern!(py, "PEM"))?) { - let pem_bytes = if password.is_empty() { - self.pkey.private_key_to_pem_pkcs8()? - } else { - self.pkey.private_key_to_pem_pkcs8_passphrase( - openssl::symm::Cipher::aes_256_cbc(), - password, - )? - }; - return Ok(pyo3::types::PyBytes::new(py, &pem_bytes)); - } else if encoding.is(encoding_class.getattr(pyo3::intern!(py, "DER"))?) { - let der_bytes = if password.is_empty() { - self.pkey.private_key_to_pkcs8()? - } else { - self.pkey.private_key_to_pkcs8_passphrase( - openssl::symm::Cipher::aes_256_cbc(), - password, - )? - }; - return Ok(pyo3::types::PyBytes::new(py, &der_bytes)); - } - return Err(CryptographyError::from( - pyo3::exceptions::PyValueError::new_err("Unsupported encoding for PKCS8"), - )); - } - - Err(CryptographyError::from( - pyo3::exceptions::PyValueError::new_err("format is invalid with this key"), - )) + utils::pkey_private_bytes(py, &self.pkey, encoding, format, encryption_algorithm) } } @@ -219,64 +125,7 @@ impl X25519PublicKey { encoding: &pyo3::PyAny, format: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - let serialization_mod = py.import("cryptography.hazmat.primitives.serialization")?; - let encoding_class: &pyo3::types::PyType = serialization_mod - .getattr(pyo3::intern!(py, "Encoding"))? - .extract()?; - let public_format_class: &pyo3::types::PyType = serialization_mod - .getattr(pyo3::intern!(py, "PublicFormat"))? - .extract()?; - - if !encoding.is_instance(encoding_class)? { - return Err(CryptographyError::from( - pyo3::exceptions::PyTypeError::new_err( - "encoding must be an item from the Encoding enum", - ), - )); - } - if !format.is_instance(public_format_class)? { - return Err(CryptographyError::from( - pyo3::exceptions::PyTypeError::new_err( - "format must be an item from the PublicFormat enum", - ), - )); - } - - if encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) - || format.is(public_format_class.getattr(pyo3::intern!(py, "Raw"))?) - { - if !encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) - || !format.is(public_format_class.getattr(pyo3::intern!(py, "Raw"))?) - { - return Err(CryptographyError::from( - pyo3::exceptions::PyValueError::new_err( - "When using Raw both encoding and format must be Raw", - ), - )); - } - let raw_bytes = self.pkey.raw_public_key()?; - return Ok(pyo3::types::PyBytes::new(py, &raw_bytes)); - } - - // SubjectPublicKeyInfo + PEM/DER - if format.is(public_format_class.getattr(pyo3::intern!(py, "SubjectPublicKeyInfo"))?) { - if encoding.is(encoding_class.getattr(pyo3::intern!(py, "PEM"))?) { - let pem_bytes = self.pkey.public_key_to_pem()?; - return Ok(pyo3::types::PyBytes::new(py, &pem_bytes)); - } else if encoding.is(encoding_class.getattr(pyo3::intern!(py, "DER"))?) { - let der_bytes = self.pkey.public_key_to_der()?; - return Ok(pyo3::types::PyBytes::new(py, &der_bytes)); - } - return Err(CryptographyError::from( - pyo3::exceptions::PyValueError::new_err( - "SubjectPublicKeyInfo works only with PEM or DER encoding", - ), - )); - } - - Err(CryptographyError::from( - pyo3::exceptions::PyValueError::new_err("format is invalid with this key"), - )) + utils::pkey_public_bytes(py, &self.pkey, encoding, format) } } diff --git a/src/rust/src/backend/x448.rs b/src/rust/src/backend/x448.rs new file mode 100644 index 000000000000..ff6d7f5b685c --- /dev/null +++ b/src/rust/src/backend/x448.rs @@ -0,0 +1,144 @@ +// This file is dual licensed under the terms of the Apache License, Version +// 2.0, and the BSD License. See the LICENSE file in the root of this repository +// for complete details. + +use crate::backend::utils; +use crate::buf::CffiBuf; +use crate::error::CryptographyResult; +use foreign_types_shared::ForeignTypeRef; + +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.x448")] +struct X448PrivateKey { + pkey: openssl::pkey::PKey, +} + +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.x448")] +struct X448PublicKey { + pkey: openssl::pkey::PKey, +} + +#[pyo3::prelude::pyfunction] +fn generate_key() -> CryptographyResult { + Ok(X448PrivateKey { + pkey: openssl::pkey::PKey::generate_x448()?, + }) +} + +#[pyo3::prelude::pyfunction] +fn private_key_from_ptr(ptr: usize) -> X448PrivateKey { + let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; + X448PrivateKey { + pkey: pkey.to_owned(), + } +} + +#[pyo3::prelude::pyfunction] +fn public_key_from_ptr(ptr: usize) -> X448PublicKey { + let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; + X448PublicKey { + pkey: pkey.to_owned(), + } +} + +#[pyo3::prelude::pyfunction] +fn from_private_bytes(data: CffiBuf<'_>) -> pyo3::PyResult { + let pkey = + openssl::pkey::PKey::private_key_from_raw_bytes(data.as_bytes(), openssl::pkey::Id::X448) + .map_err(|e| { + pyo3::exceptions::PyValueError::new_err(format!( + "An X448 private key is 56 bytes long: {}", + e + )) + })?; + Ok(X448PrivateKey { pkey }) +} +#[pyo3::prelude::pyfunction] +fn from_public_bytes(data: &[u8]) -> pyo3::PyResult { + let pkey = openssl::pkey::PKey::public_key_from_raw_bytes(data, openssl::pkey::Id::X448) + .map_err(|_| { + pyo3::exceptions::PyValueError::new_err("An X448 public key is 32 bytes long") + })?; + Ok(X448PublicKey { pkey }) +} + +#[pyo3::prelude::pymethods] +impl X448PrivateKey { + fn exchange<'p>( + &self, + py: pyo3::Python<'p>, + public_key: &X448PublicKey, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let mut deriver = openssl::derive::Deriver::new(&self.pkey)?; + deriver.set_peer(&public_key.pkey)?; + + Ok(pyo3::types::PyBytes::new_with(py, deriver.len()?, |b| { + let n = deriver.derive(b).map_err(|_| { + pyo3::exceptions::PyValueError::new_err("Error computing shared key.") + })?; + assert_eq!(n, b.len()); + Ok(()) + })?) + } + + fn public_key(&self) -> CryptographyResult { + let raw_bytes = self.pkey.raw_public_key()?; + Ok(X448PublicKey { + pkey: openssl::pkey::PKey::public_key_from_raw_bytes( + &raw_bytes, + openssl::pkey::Id::X448, + )?, + }) + } + + fn private_bytes_raw<'p>( + &self, + py: pyo3::Python<'p>, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let raw_bytes = self.pkey.raw_private_key()?; + Ok(pyo3::types::PyBytes::new(py, &raw_bytes)) + } + + fn private_bytes<'p>( + &self, + py: pyo3::Python<'p>, + encoding: &pyo3::PyAny, + format: &pyo3::PyAny, + encryption_algorithm: &pyo3::PyAny, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + utils::pkey_private_bytes(py, &self.pkey, encoding, format, encryption_algorithm) + } +} + +#[pyo3::prelude::pymethods] +impl X448PublicKey { + fn public_bytes_raw<'p>( + &self, + py: pyo3::Python<'p>, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let raw_bytes = self.pkey.raw_public_key()?; + Ok(pyo3::types::PyBytes::new(py, &raw_bytes)) + } + + fn public_bytes<'p>( + &self, + py: pyo3::Python<'p>, + encoding: &pyo3::PyAny, + format: &pyo3::PyAny, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + utils::pkey_public_bytes(py, &self.pkey, encoding, format) + } +} + +pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let m = pyo3::prelude::PyModule::new(py, "x448")?; + m.add_wrapped(pyo3::wrap_pyfunction!(generate_key))?; + m.add_wrapped(pyo3::wrap_pyfunction!(private_key_from_ptr))?; + m.add_wrapped(pyo3::wrap_pyfunction!(public_key_from_ptr))?; + m.add_wrapped(pyo3::wrap_pyfunction!(from_private_bytes))?; + m.add_wrapped(pyo3::wrap_pyfunction!(from_public_bytes))?; + + m.add_class::()?; + m.add_class::()?; + + Ok(m) +} From 684b710bea009efb062e5a5502583afe43390956 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Apr 2023 00:29:59 +0000 Subject: [PATCH 087/316] Bump openssl from 0.10.49 to 0.10.50 in /src/rust (#8693) Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.49 to 0.10.50. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.49...openssl-v0.10.50) --- updated-dependencies: - dependency-name: openssl 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 fd554872706f..2cf3919ebc5a 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -133,9 +133,9 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "openssl" -version = "0.10.49" +version = "0.10.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d2f106ab837a24e03672c59b1239669a0596406ff657c3c0835b6b7f0f35a33" +checksum = "7e30d8bc91859781f0a943411186324d580f2bbeb71b452fe91ae344806af3f1" dependencies = [ "bitflags", "cfg-if", @@ -159,9 +159,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.84" +version = "0.9.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a20eace9dc2d82904039cb76dcf50fb1a0bba071cfd1629720b5d6f1ddba0fa" +checksum = "0d3d193fb1488ad46ffe3aaabc912cc931d02ee8518fe2959aea8ef52718b0c0" dependencies = [ "cc", "libc", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 5fa9c31df72d..1e188960257d 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -13,7 +13,7 @@ pyo3 = { version = "0.18" } asn1 = { version = "0.14.0", default-features = false } pem = "1.1" ouroboros = "0.15" -openssl = "0.10.49" +openssl = "0.10.50" openssl-sys = "0.9.84" foreign-types-shared = "0.1" From 253fb2abcf2bbf1184661020374eb75c0dc8bdd2 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 9 Apr 2023 20:45:31 -0400 Subject: [PATCH 088/316] libressl 3.7.2 (#8692) --- .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 accb44b8faf7..ac4c512496bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", NOXARGS: "--enable-fips=1", OPENSSL: {TYPE: "openssl", CONFIG_FLAGS: "enable-fips", VERSION: "3.1.0"}} - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.5.4"}} - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.6.2"}} - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.1"}} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} # Latest commit on the BoringSSL master branch, as of Apr 08, 2023. From f724c9b2fd424c6ac318951fb348a6a2d667b385 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 10 Apr 2023 11:10:41 +0800 Subject: [PATCH 089/316] Support msCertificateTemplate extension (#8695) * support ms certificate template * contortions for rust coverage * review feedback --- CHANGELOG.rst | 2 + docs/development/test-vectors.rst | 2 + docs/x509/reference.rst | 34 ++++++++ src/cryptography/hazmat/_oid.py | 2 + src/cryptography/x509/__init__.py | 2 + src/cryptography/x509/extensions.py | 59 +++++++++++++ src/rust/src/x509/certificate.rs | 16 ++++ src/rust/src/x509/extensions.rs | 9 ++ src/rust/src/x509/oid.rs | 2 + tests/x509/test_x509.py | 16 ++++ tests/x509/test_x509_ext.py | 83 +++++++++++++++++++ .../x509/custom/ms-certificate-template.pem | 9 ++ 12 files changed, 236 insertions(+) create mode 100644 vectors/cryptography_vectors/x509/custom/ms-certificate-template.pem diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ec7a3db5ddc9..7e44bd9061e9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,8 @@ Changelog * Updated the minimum supported Rust version (MSRV) to 1.56.0, from 1.48.0. * Added support for the :class:`~cryptography.x509.OCSPAcceptableResponses` OCSP extension. +* Added support for the :class:`~cryptography.x509.MSCertificateTemplate` + proprietary Microsoft certificate extension. .. _v40-0-1: diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 2cb822306707..b3a1c301da58 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -483,6 +483,8 @@ Custom X.509 Vectors * ``mismatch_inner_outer_sig_algorithm.der`` - A leaf certificate derived from ``x509/cryptography.io.pem`` but modifying the ``tbs_cert.signature_algorithm`` OID to not match the outer signature algorithm OID. +* ``ms-certificate-template.pem`` - A certificate with a ``msCertificateTemplate`` + extension. Custom X.509 Request Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index d0f864b56a5b..2f7040ebfa12 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -2663,6 +2663,34 @@ X.509 Extensions Returns the DER encoded bytes payload of the extension. +.. class:: MSCertificateTemplate(template_id, major_version, minor_version) + :canonical: cryptography.x509.extensions.MSCertificateTemplate + + .. versionadded:: 41.0.0 + + The Microsoft certificate template extension is a proprietary Microsoft + PKI extension that is used to provide information about the template + associated with the certificate. + + .. attribute:: oid + + :type: :class:`ObjectIdentifier` + + Returns + :attr:`~cryptography.x509.oid.ExtensionOID.MS_CERTIFICATE_TEMPLATE`. + + .. attribute:: template_id + + :type: :class:`ObjectIdentifier` + + .. attribute:: major_version + + :type: int or None + + .. attribute:: minor_version + + :type: int or None + .. class:: CertificatePolicies(policies) :canonical: cryptography.x509.extensions.CertificatePolicies @@ -3504,6 +3532,12 @@ instances. The following common OIDs are available as constants. Corresponds to the dotted string ``"2.5.29.9"``. + .. attribute:: MS_CERTIFICATE_TEMPLATE + + .. versionadded:: 41.0.0 + + Corresponds to the dotted string ``"1.3.6.1.4.1.311.21.7"``. + .. class:: CRLEntryExtensionOID :canonical: cryptography.hazmat._oid.CRLEntryExtensionOID diff --git a/src/cryptography/hazmat/_oid.py b/src/cryptography/hazmat/_oid.py index 82a6498f92c2..908f6206db3f 100644 --- a/src/cryptography/hazmat/_oid.py +++ b/src/cryptography/hazmat/_oid.py @@ -40,6 +40,7 @@ class ExtensionOID: ) 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") + MS_CERTIFICATE_TEMPLATE = ObjectIdentifier("1.3.6.1.4.1.311.21.7") class OCSPExtensionOID: @@ -267,6 +268,7 @@ class AttributeOID: "signedCertificateTimestampList" ), ExtensionOID.PRECERT_POISON: "ctPoison", + ExtensionOID.MS_CERTIFICATE_TEMPLATE: "msCertificateTemplate", CRLEntryExtensionOID.CRL_REASON: "cRLReason", CRLEntryExtensionOID.INVALIDITY_DATE: "invalidityDate", CRLEntryExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer", diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py index 6d4a10eab579..d77694a29906 100644 --- a/src/cryptography/x509/__init__.py +++ b/src/cryptography/x509/__init__.py @@ -53,6 +53,7 @@ IssuerAlternativeName, IssuingDistributionPoint, KeyUsage, + MSCertificateTemplate, NameConstraints, NoticeReference, OCSPAcceptableResponses, @@ -250,4 +251,5 @@ "SignedCertificateTimestamps", "SignatureAlgorithmOID", "NameOID", + "MSCertificateTemplate", ] diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 981161a63b5b..ac99592f55a7 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -2122,6 +2122,65 @@ def public_bytes(self) -> bytes: return rust_x509.encode_extension_value(self) +class MSCertificateTemplate(ExtensionType): + oid = ExtensionOID.MS_CERTIFICATE_TEMPLATE + + def __init__( + self, + template_id: ObjectIdentifier, + major_version: typing.Optional[int], + minor_version: typing.Optional[int], + ) -> None: + if not isinstance(template_id, ObjectIdentifier): + raise TypeError("oid must be an ObjectIdentifier") + self._template_id = template_id + if ( + major_version is not None and not isinstance(major_version, int) + ) or ( + minor_version is not None and not isinstance(minor_version, int) + ): + raise TypeError( + "major_version and minor_version must be integers or None" + ) + self._major_version = major_version + self._minor_version = minor_version + + @property + def template_id(self) -> ObjectIdentifier: + return self._template_id + + @property + def major_version(self) -> typing.Optional[int]: + return self._major_version + + @property + def minor_version(self) -> typing.Optional[int]: + return self._minor_version + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, MSCertificateTemplate): + return NotImplemented + + return ( + self.template_id == other.template_id + and self.major_version == other.major_version + and self.minor_version == other.minor_version + ) + + def __hash__(self) -> int: + return hash((self.template_id, self.major_version, self.minor_version)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + class UnrecognizedExtension(ExtensionType): def __init__(self, oid: ObjectIdentifier, value: bytes) -> None: if not isinstance(oid, ObjectIdentifier): diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 160048436e24..838fa1a1c2ee 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -613,6 +613,13 @@ pub(crate) struct GeneralSubtree<'a> { pub maximum: Option, } +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub(crate) struct MSCertificateTemplate { + pub template_id: asn1::ObjectIdentifier, + pub major_version: Option, + pub minor_version: Option, +} + fn parse_general_subtrees( py: pyo3::Python<'_>, subtrees: SequenceOfSubtrees<'_>, @@ -985,6 +992,15 @@ pub fn parse_cert_ext<'p>( .call1((permitted_subtrees, excluded_subtrees))?, )) } + oid::MS_CERTIFICATE_TEMPLATE => { + let ms_cert_tpl = asn1::parse_single::(ext_data)?; + let py_oid = oid_to_py_oid(py, &ms_cert_tpl.template_id)?; + Ok(Some( + x509_module + .getattr(pyo3::intern!(py, "MSCertificateTemplate"))? + .call1((py_oid, ms_cert_tpl.major_version, ms_cert_tpl.minor_version))?, + )) + } _ => Ok(None), } } diff --git a/src/rust/src/x509/extensions.rs b/src/rust/src/x509/extensions.rs index cded8890dbac..7f143d852679 100644 --- a/src/rust/src/x509/extensions.rs +++ b/src/rust/src/x509/extensions.rs @@ -453,6 +453,15 @@ pub(crate) fn encode_extension( .extract::<&[u8]>()?; Ok(Some(asn1::write_single(&nonce)?)) } + &oid::MS_CERTIFICATE_TEMPLATE => { + let py_template_id = ext.getattr(pyo3::intern!(py, "template_id"))?; + let mstpl = certificate::MSCertificateTemplate { + template_id: py_oid_to_oid(py_template_id)?, + major_version: ext.getattr(pyo3::intern!(py, "major_version"))?.extract()?, + minor_version: ext.getattr(pyo3::intern!(py, "minor_version"))?.extract()?, + }; + Ok(Some(asn1::write_single(&mstpl)?)) + } _ => Ok(None), } } diff --git a/src/rust/src/x509/oid.rs b/src/rust/src/x509/oid.rs index 2c9b36d0a186..b2e3a36acd3e 100644 --- a/src/rust/src/x509/oid.rs +++ b/src/rust/src/x509/oid.rs @@ -6,6 +6,8 @@ pub(crate) const EXTENSION_REQUEST: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 9, 14); pub(crate) const MS_EXTENSION_REQUEST: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 4, 1, 311, 2, 1, 14); +pub(crate) const MS_CERTIFICATE_TEMPLATE: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 4, 1, 311, 21, 7); pub(crate) const PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 4, 1, 11129, 2, 4, 2); pub(crate) const PRECERT_POISON_OID: asn1::ObjectIdentifier = diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 736c0113ec82..4a3fb26c63ad 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -4861,6 +4861,22 @@ def test_load_name_attribute_long_form_asn1_tag(self, backend): with pytest.raises(ValueError, match="Long-form"): cert.issuer + def test_ms_certificate_template(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "ms-certificate-template.pem"), + x509.load_pem_x509_certificate, + ) + ext = cert.extensions.get_extension_for_class( + x509.MSCertificateTemplate + ) + tpl = ext.value + assert isinstance(tpl, x509.MSCertificateTemplate) + assert tpl == x509.MSCertificateTemplate( + template_id=x509.ObjectIdentifier("1.2.3.4.5.6.7.8.9.0"), + major_version=1, + minor_version=None, + ) + def test_signature(self, backend): cert = _load_cert( os.path.join("x509", "ecdsa_root.pem"), diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index d11ba3db0408..fd7ff957b1dd 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -6199,6 +6199,89 @@ def test_public_bytes(self): ) +class TestMSCertificateTemplate: + def test_invalid_type(self): + with pytest.raises(TypeError): + x509.MSCertificateTemplate( + "notanoid", None, None # type:ignore[arg-type] + ) + oid = x509.ObjectIdentifier("1.2.3.4") + with pytest.raises(TypeError): + x509.MSCertificateTemplate( + oid, "notanint", None # type:ignore[arg-type] + ) + with pytest.raises(TypeError): + x509.MSCertificateTemplate( + oid, None, "notanint" # type:ignore[arg-type] + ) + + def test_eq(self): + template1 = x509.MSCertificateTemplate( + ObjectIdentifier("1.2.3.4"), None, None + ) + template2 = x509.MSCertificateTemplate( + ObjectIdentifier("1.2.3.4"), None, None + ) + assert template1 == template2 + + def test_ne(self): + template1 = x509.MSCertificateTemplate( + ObjectIdentifier("1.2.3.4"), None, None + ) + template2 = x509.MSCertificateTemplate( + ObjectIdentifier("1.2.3.4"), 1, None + ) + template3 = x509.MSCertificateTemplate( + ObjectIdentifier("1.2.3.4"), None, 1 + ) + template4 = x509.MSCertificateTemplate( + ObjectIdentifier("1.2.3"), None, None + ) + assert template1 != template2 + assert template1 != template3 + assert template1 != template4 + assert template1 != object() + + def test_repr(self): + template = x509.MSCertificateTemplate( + ObjectIdentifier("1.2.3.4"), None, None + ) + assert repr(template) == ( + ", major_version=None, minor_version=None)>" + ) + + def test_hash(self): + template1 = x509.MSCertificateTemplate( + ObjectIdentifier("1.2.3.4"), None, None + ) + template2 = x509.MSCertificateTemplate( + ObjectIdentifier("1.2.3.4"), None, None + ) + template3 = x509.MSCertificateTemplate( + ObjectIdentifier("1.2.3.4"), None, 1 + ) + template4 = x509.MSCertificateTemplate( + ObjectIdentifier("1.2.3"), None, None + ) + + assert hash(template1) == hash(template2) + assert hash(template1) != hash(template3) + assert hash(template1) != hash(template4) + + def test_public_bytes(self): + ext = x509.MSCertificateTemplate( + ObjectIdentifier("1.2.3.4"), None, None + ) + assert ext.public_bytes() == b"0\x05\x06\x03*\x03\x04" + + ext = x509.MSCertificateTemplate(ObjectIdentifier("1.2.3.4"), 1, 0) + assert ( + ext.public_bytes() + == b"0\x0b\x06\x03*\x03\x04\x02\x01\x01\x02\x01\x00" + ) + + def test_all_extension_oid_members_have_names_defined(): for oid in dir(ExtensionOID): if oid.startswith("__"): diff --git a/vectors/cryptography_vectors/x509/custom/ms-certificate-template.pem b/vectors/cryptography_vectors/x509/custom/ms-certificate-template.pem new file mode 100644 index 000000000000..ccf02e58a21f --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/ms-certificate-template.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBKDCB0KADAgECAgEBMAoGCCqGSM49BAMCMA0xCzAJBgNVBAYTAlVTMB4XDTIz +MDEwMTEyMDEwMFoXDTMzMDEwMTEyMDEwMFowDTELMAkGA1UEBhMCVVMwWTATBgcq +hkjOPQIBBggqhkjOPQMBBwNCAARtDYTQ38TdHTMQb6pr7IAVcFjoW15DPK8V2rsR +kcOS2XJSWVpUkGttfUi1XQyVrIXDBA+Fma4s+lAHO5UrKtR9oyEwHzAdBgkrBgEE +AYI3FQcEEDAOBgkqAwQFBgcICQACAQEwCgYIKoZIzj0EAwIDRwAwRAIgcbUufnLk +Jd23LBlFM1fRhoW8wxi6VuwNCmFqx9n7E+gCIFPAi0/ZhTMyfK/X9BHVtR/B4r84 +R/YOuYr4MtmIMM4Q +-----END CERTIFICATE----- From 40c16dc1800002cf2c2c3046ef466bed2bcd7e37 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 10 Apr 2023 11:32:50 +0800 Subject: [PATCH 090/316] OCSP responses are responses, not certificates (#8696) --- docs/x509/ocsp.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/x509/ocsp.rst b/docs/x509/ocsp.rst index 603f9f6dd040..76bfc023f15f 100644 --- a/docs/x509/ocsp.rst +++ b/docs/x509/ocsp.rst @@ -329,7 +329,7 @@ Creating Responses :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`, :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey` or :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey` - that will be used to sign the certificate. + that will be used to sign the response. :param algorithm: The :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` that @@ -804,4 +804,4 @@ Interfaces :type: int - The serial number of the certificate that was checked. \ No newline at end of file + The serial number of the certificate that was checked. From 7d3f8a43d434be3c38d80969bbadcf4516afad82 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 10 Apr 2023 12:13:55 +0800 Subject: [PATCH 091/316] we made WithSerialization an alias to the main types long ago (#8698) stop documenting them entirely --- CHANGELOG.rst | 44 +++++++------------ docs/hazmat/primitives/asymmetric/dh.rst | 21 --------- docs/hazmat/primitives/asymmetric/dsa.rst | 14 ------ docs/hazmat/primitives/asymmetric/ec.rst | 21 +-------- docs/hazmat/primitives/asymmetric/rsa.rst | 14 ------ .../primitives/asymmetric/serialization.rst | 26 +++++------ 6 files changed, 31 insertions(+), 109 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7e44bd9061e9..b1fb92e04c6f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1782,16 +1782,16 @@ Changelog ``no-comp`` (``OPENSSL_NO_COMP``) option. * Support :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER` serialization of public keys using the ``public_bytes`` method of - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization`, - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKeyWithSerialization`, + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, and - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization`. + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`. * Support :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER` serialization of private keys using the ``private_bytes`` method of - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization`, - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization`, + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, and - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization`. + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`. * Add support for parsing X.509 certificate signing requests (CSRs) with :func:`~cryptography.x509.load_pem_x509_csr` and :func:`~cryptography.x509.load_der_x509_csr`. @@ -1864,42 +1864,32 @@ Changelog and :func:`~cryptography.hazmat.primitives.serialization.load_der_public_key` now support PKCS1 RSA public keys (in addition to the previous support for SubjectPublicKeyInfo format for RSA, EC, and DSA). -* Added - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization` - and deprecated ``EllipticCurvePrivateKeyWithNumbers``. +* Added ``EllipticCurvePrivateKeyWithSerialization`` and deprecated + ``EllipticCurvePrivateKeyWithNumbers``. * Added :meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey.private_bytes` to :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`. -* Added - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization` - and deprecated ``RSAPrivateKeyWithNumbers``. +* Added ``RSAPrivateKeyWithSerialization`` and deprecated ``RSAPrivateKeyWithNumbers``. * Added :meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey.private_bytes` to :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`. -* Added - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization` - and deprecated ``DSAPrivateKeyWithNumbers``. +* Added ``DSAPrivateKeyWithSerialization`` and deprecated ``DSAPrivateKeyWithNumbers``. * Added :meth:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey.private_bytes` to :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`. -* Added - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization` - and deprecated ``RSAPublicKeyWithNumbers``. +* Added ``RSAPublicKeyWithSerialization`` and deprecated ``RSAPublicKeyWithNumbers``. * Added ``public_bytes`` to - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization`. -* Added - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization` - and deprecated ``EllipticCurvePublicKeyWithNumbers``. + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`. +* Added ``EllipticCurvePublicKeyWithSerialization`` and deprecated + ``EllipticCurvePublicKeyWithNumbers``. * Added ``public_bytes`` to - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization`. -* Added - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKeyWithSerialization` - and deprecated ``DSAPublicKeyWithNumbers``. + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`. +* Added ``DSAPublicKeyWithSerialization`` and deprecated ``DSAPublicKeyWithNumbers``. * Added ``public_bytes`` to - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKeyWithSerialization`. + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`. * :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` and :class:`~cryptography.hazmat.primitives.hashes.HashContext` were moved from ``cryptography.hazmat.primitives.interfaces`` to diff --git a/docs/hazmat/primitives/asymmetric/dh.rst b/docs/hazmat/primitives/asymmetric/dh.rst index e880b8145899..361aa6dff82b 100644 --- a/docs/hazmat/primitives/asymmetric/dh.rst +++ b/docs/hazmat/primitives/asymmetric/dh.rst @@ -174,13 +174,6 @@ Group parameters :return bytes: Serialized parameters. -.. class:: DHParametersWithSerialization - - .. versionadded:: 1.7 - - Alias for :class:`DHParameters`. - - Key interfaces ~~~~~~~~~~~~~~ @@ -247,13 +240,6 @@ Key interfaces :return bytes: Serialized key. -.. class:: DHPrivateKeyWithSerialization - - .. versionadded:: 1.7 - - Alias for :class:`DHPrivateKey`. - - .. class:: DHPublicKey .. versionadded:: 1.7 @@ -293,13 +279,6 @@ Key interfaces :return bytes: Serialized key. -.. class:: DHPublicKeyWithSerialization - - .. versionadded:: 1.7 - - Alias for :class:`DHPublicKey`. - - Numbers ~~~~~~~ diff --git a/docs/hazmat/primitives/asymmetric/dsa.rst b/docs/hazmat/primitives/asymmetric/dsa.rst index e70312cc3baa..5df80149bb9b 100644 --- a/docs/hazmat/primitives/asymmetric/dsa.rst +++ b/docs/hazmat/primitives/asymmetric/dsa.rst @@ -336,13 +336,6 @@ Key interfaces :return bytes: Serialized key. -.. class:: DSAPrivateKeyWithSerialization - - .. versionadded:: 0.8 - - Alias for :class:`DSAPrivateKey`. - - .. class:: DSAPublicKey .. versionadded:: 0.3 @@ -412,13 +405,6 @@ Key interfaces not validate. -.. class:: DSAPublicKeyWithSerialization - - .. versionadded:: 0.8 - - Alias for :class:`DSAPublicKey`. - - .. _`DSA`: https://en.wikipedia.org/wiki/Digital_Signature_Algorithm .. _`public-key`: https://en.wikipedia.org/wiki/Public-key_cryptography .. _`FIPS 186-4`: https://csrc.nist.gov/publications/detail/fips/186/4/final diff --git a/docs/hazmat/primitives/asymmetric/ec.rst b/docs/hazmat/primitives/asymmetric/ec.rst index 8da29eea142a..5842e9ca1667 100644 --- a/docs/hazmat/primitives/asymmetric/ec.rst +++ b/docs/hazmat/primitives/asymmetric/ec.rst @@ -534,11 +534,7 @@ Key Interfaces .. versionadded:: 0.5 - An elliptic curve private key for use with an algorithm such as `ECDSA`_ or - `EdDSA`_. An elliptic curve private key that is not an - :term:`opaque key` also implements - :class:`EllipticCurvePrivateKeyWithSerialization` to provide serialization - methods. + An elliptic curve private key for use with an algorithm such as `ECDSA`_. .. method:: exchange(algorithm, peer_public_key) @@ -632,13 +628,6 @@ Key Interfaces :return bytes: Serialized key. -.. class:: EllipticCurvePrivateKeyWithSerialization - - .. versionadded:: 0.8 - - Alias for :class:`EllipticCurvePrivateKey`. - - .. class:: EllipticCurvePublicKey .. versionadded:: 0.5 @@ -734,13 +723,6 @@ Key Interfaces :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurve`. -.. class:: EllipticCurvePublicKeyWithSerialization - - .. versionadded:: 0.6 - - Alias for :class:`EllipticCurvePublicKey`. - - Serialization ~~~~~~~~~~~~~ @@ -937,7 +919,6 @@ Elliptic Curve Object Identifiers .. _`minimize the number of security concerns for elliptic-curve cryptography`: https://cr.yp.to/ecdh/curve25519-20060209.pdf .. _`SafeCurves`: https://safecurves.cr.yp.to/ .. _`ECDSA`: https://en.wikipedia.org/wiki/ECDSA -.. _`EdDSA`: https://en.wikipedia.org/wiki/EdDSA .. _`forward secrecy`: https://en.wikipedia.org/wiki/Forward_secrecy .. _`SEC 1 v2.0`: https://www.secg.org/sec1-v2.pdf .. _`bad cryptographic practice`: https://crypto.stackexchange.com/a/3313 diff --git a/docs/hazmat/primitives/asymmetric/rsa.rst b/docs/hazmat/primitives/asymmetric/rsa.rst index 7c268320ae21..23401f52793a 100644 --- a/docs/hazmat/primitives/asymmetric/rsa.rst +++ b/docs/hazmat/primitives/asymmetric/rsa.rst @@ -642,13 +642,6 @@ Key interfaces :return bytes: Serialized key. -.. class:: RSAPrivateKeyWithSerialization - - .. versionadded:: 0.8 - - Alias for :class:`RSAPrivateKey`. - - .. class:: RSAPublicKey .. versionadded:: 0.2 @@ -783,13 +776,6 @@ Key interfaces :raises cryptography.exceptions.UnsupportedAlgorithm: If signature data recovery is not supported with the provided ``padding`` type. -.. class:: RSAPublicKeyWithSerialization - - .. versionadded:: 0.8 - - Alias for :class:`RSAPublicKey`. - - .. _`RSA`: https://en.wikipedia.org/wiki/RSA_(cryptosystem) .. _`public-key`: https://en.wikipedia.org/wiki/Public-key_cryptography .. _`specific mathematical properties`: https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Key_generation diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index 5fb248b554f9..c60accca6b40 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -1219,12 +1219,12 @@ Serialization Formats An enumeration for private key formats. Used with the ``private_bytes`` method available on - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization` + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey` , - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization` - , :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKeyWithSerialization` + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` + , :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey` and - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization`. + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`. .. attribute:: TraditionalOpenSSL @@ -1326,12 +1326,12 @@ Serialization Formats An enumeration for public key formats. Used with the ``public_bytes`` method available on - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization` + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey` , - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization` - , :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKeyWithSerialization` + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` + , :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPublicKey` , and - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKeyWithSerialization`. + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`. .. attribute:: SubjectPublicKeyInfo @@ -1390,7 +1390,7 @@ Serialization Formats An enumeration for parameters formats. Used with the ``parameter_bytes`` method available on - :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParametersWithSerialization`. + :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHParameters`. .. attribute:: PKCS3 @@ -1404,11 +1404,11 @@ Serialization Encodings An enumeration for encoding types. Used with the ``private_bytes`` method available on - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization` + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey` , - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization` - , :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKeyWithSerialization`, - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` + , :class:`~cryptography.hazmat.primitives.asymmetric.dh.DHPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, and :class:`~cryptography.hazmat.primitives.asymmetric.x448.X448PrivateKey` as well as ``public_bytes`` on From 577c9bb7a89dd1fb0849311be0e765f04128f0a5 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 10 Apr 2023 20:13:21 +0800 Subject: [PATCH 092/316] support equality checks on all public asymmetric key types (#8700) * support equality checks on all public asymmetric key types * review feedback --- CHANGELOG.rst | 1 + .../hazmat/backends/openssl/backend.py | 4 ---- .../hazmat/backends/openssl/dh.py | 12 ++++++++++ .../hazmat/backends/openssl/dsa.py | 9 ++++++++ .../hazmat/backends/openssl/ec.py | 9 ++++++++ .../hazmat/backends/openssl/ed25519.py | 6 +++++ .../hazmat/backends/openssl/ed448.py | 6 +++++ .../hazmat/backends/openssl/rsa.py | 9 ++++++++ .../hazmat/primitives/asymmetric/dh.py | 6 +++++ .../hazmat/primitives/asymmetric/dsa.py | 6 +++++ .../hazmat/primitives/asymmetric/ec.py | 6 +++++ .../hazmat/primitives/asymmetric/ed25519.py | 6 +++++ .../hazmat/primitives/asymmetric/ed448.py | 6 +++++ .../hazmat/primitives/asymmetric/rsa.py | 6 +++++ .../hazmat/primitives/asymmetric/x25519.py | 6 +++++ .../hazmat/primitives/asymmetric/x448.py | 6 +++++ src/rust/src/backend/x25519.rs | 12 ++++++++++ src/rust/src/backend/x448.rs | 12 ++++++++++ src/rust/src/x509/ocsp_resp.rs | 17 +++++++------- tests/hazmat/primitives/test_dh.py | 22 +++++++++++++++++++ tests/hazmat/primitives/test_dsa.py | 12 ++++++++++ tests/hazmat/primitives/test_ec.py | 15 ++++++++++++- tests/hazmat/primitives/test_ed25519.py | 18 +++++++++++++++ tests/hazmat/primitives/test_ed448.py | 18 +++++++++++++++ tests/hazmat/primitives/test_rsa.py | 12 ++++++++++ tests/hazmat/primitives/test_x25519.py | 20 +++++++++++++++++ tests/hazmat/primitives/test_x448.py | 20 +++++++++++++++++ 27 files changed, 269 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b1fb92e04c6f..9387ea6a9c0e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -16,6 +16,7 @@ Changelog OCSP extension. * Added support for the :class:`~cryptography.x509.MSCertificateTemplate` proprietary Microsoft certificate extension. +* Implemented support for equality checks on all asymmetric public key types. .. _v40-0-1: diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index adda33285676..9c414e1a9c83 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -1049,10 +1049,6 @@ def _ossl2cert(self, x509_ptr: typing.Any) -> x509.Certificate: self.openssl_assert(res == 1) return x509.load_der_x509_certificate(self._read_mem_bio(bio)) - def _check_keys_correspond(self, key1, key2) -> None: - if self._lib.EVP_PKEY_cmp(key1._evp_pkey, key2._evp_pkey) != 1: - raise ValueError("Keys do not correspond") - def _load_key( self, openssl_read_func, data, password, unsafe_skip_rsa_key_validation ) -> PrivateKeyTypes: diff --git a/src/cryptography/hazmat/backends/openssl/dh.py b/src/cryptography/hazmat/backends/openssl/dh.py index 6c1889bc3ac2..42a92bcc1cd6 100644 --- a/src/cryptography/hazmat/backends/openssl/dh.py +++ b/src/cryptography/hazmat/backends/openssl/dh.py @@ -261,6 +261,18 @@ def __init__(self, backend: Backend, dh_cdata, evp_pkey): def key_size(self) -> int: return self._key_size_bits + def __eq__(self, other: object) -> bool: + if not isinstance(other, _DHPublicKey): + return NotImplemented + + res = self._backend._lib.EVP_PKEY_cmp(self._evp_pkey, other._evp_pkey) + if res < 0: + # DH public keys have two types (DH, DHX) that OpenSSL + # considers different types but we do not. Mismatched types + # push an error on the stack, so we need to consume it. + self._backend._consume_errors() + return res == 1 + def public_numbers(self) -> dh.DHPublicNumbers: p = self._backend._ffi.new("BIGNUM **") g = self._backend._ffi.new("BIGNUM **") diff --git a/src/cryptography/hazmat/backends/openssl/dsa.py b/src/cryptography/hazmat/backends/openssl/dsa.py index be0500152aeb..411a80820e85 100644 --- a/src/cryptography/hazmat/backends/openssl/dsa.py +++ b/src/cryptography/hazmat/backends/openssl/dsa.py @@ -189,6 +189,15 @@ def __init__(self, backend: Backend, dsa_cdata, evp_pkey): def key_size(self) -> int: return self._key_size + def __eq__(self, other: object) -> bool: + if not isinstance(other, _DSAPublicKey): + return NotImplemented + + return ( + self._backend._lib.EVP_PKEY_cmp(self._evp_pkey, other._evp_pkey) + == 1 + ) + def public_numbers(self) -> dsa.DSAPublicNumbers: p = self._backend._ffi.new("BIGNUM **") q = self._backend._ffi.new("BIGNUM **") diff --git a/src/cryptography/hazmat/backends/openssl/ec.py b/src/cryptography/hazmat/backends/openssl/ec.py index 90a7b6fa3fc1..9821bd193e29 100644 --- a/src/cryptography/hazmat/backends/openssl/ec.py +++ b/src/cryptography/hazmat/backends/openssl/ec.py @@ -235,6 +235,15 @@ def curve(self) -> ec.EllipticCurve: def key_size(self) -> int: return self.curve.key_size + def __eq__(self, other: object) -> bool: + if not isinstance(other, _EllipticCurvePublicKey): + return NotImplemented + + return ( + self._backend._lib.EVP_PKEY_cmp(self._evp_pkey, other._evp_pkey) + == 1 + ) + def public_numbers(self) -> ec.EllipticCurvePublicNumbers: group = self._backend._lib.EC_KEY_get0_group(self._ec_key) self._backend.openssl_assert(group != self._backend._ffi.NULL) diff --git a/src/cryptography/hazmat/backends/openssl/ed25519.py b/src/cryptography/hazmat/backends/openssl/ed25519.py index 4e33a78f35f3..72678c87721c 100644 --- a/src/cryptography/hazmat/backends/openssl/ed25519.py +++ b/src/cryptography/hazmat/backends/openssl/ed25519.py @@ -78,6 +78,12 @@ def verify(self, signature: bytes, data: bytes) -> None: self._backend._consume_errors() raise exceptions.InvalidSignature + def __eq__(self, other: object) -> bool: + if not isinstance(other, Ed25519PublicKey): + return NotImplemented + + return self.public_bytes_raw() == other.public_bytes_raw() + class _Ed25519PrivateKey(Ed25519PrivateKey): def __init__(self, backend: Backend, evp_pkey): diff --git a/src/cryptography/hazmat/backends/openssl/ed448.py b/src/cryptography/hazmat/backends/openssl/ed448.py index b2300367697c..1f829420d143 100644 --- a/src/cryptography/hazmat/backends/openssl/ed448.py +++ b/src/cryptography/hazmat/backends/openssl/ed448.py @@ -79,6 +79,12 @@ def verify(self, signature: bytes, data: bytes) -> None: self._backend._consume_errors() raise exceptions.InvalidSignature + def __eq__(self, other: object) -> bool: + if not isinstance(other, Ed448PublicKey): + return NotImplemented + + return self.public_bytes_raw() == other.public_bytes_raw() + class _Ed448PrivateKey(Ed448PrivateKey): def __init__(self, backend: Backend, evp_pkey): diff --git a/src/cryptography/hazmat/backends/openssl/rsa.py b/src/cryptography/hazmat/backends/openssl/rsa.py index f8ca3341af85..ef27d4ead570 100644 --- a/src/cryptography/hazmat/backends/openssl/rsa.py +++ b/src/cryptography/hazmat/backends/openssl/rsa.py @@ -537,6 +537,15 @@ def __init__(self, backend: Backend, rsa_cdata, evp_pkey): def key_size(self) -> int: return self._key_size + def __eq__(self, other: object) -> bool: + if not isinstance(other, _RSAPublicKey): + return NotImplemented + + return ( + self._backend._lib.EVP_PKEY_cmp(self._evp_pkey, other._evp_pkey) + == 1 + ) + def encrypt(self, plaintext: bytes, padding: AsymmetricPadding) -> bytes: return _enc_dec_rsa(self._backend, self, plaintext, padding) diff --git a/src/cryptography/hazmat/primitives/asymmetric/dh.py b/src/cryptography/hazmat/primitives/asymmetric/dh.py index 272cc5e54671..02feb5f2ed4c 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/dh.py +++ b/src/cryptography/hazmat/primitives/asymmetric/dh.py @@ -200,6 +200,12 @@ def public_bytes( Returns the key serialized as bytes. """ + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + DHPublicKeyWithSerialization = DHPublicKey diff --git a/src/cryptography/hazmat/primitives/asymmetric/dsa.py b/src/cryptography/hazmat/primitives/asymmetric/dsa.py index e846d3e83a9c..1ebfcd52ad13 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/dsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -120,6 +120,12 @@ def verify( Verifies the signature of the data. """ + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + DSAPublicKeyWithSerialization = DSAPublicKey diff --git a/src/cryptography/hazmat/primitives/asymmetric/ec.py b/src/cryptography/hazmat/primitives/asymmetric/ec.py index 2e3b0108b194..ddfaabf4f3e4 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ec.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ec.py @@ -184,6 +184,12 @@ def from_encoded_point( return backend.load_elliptic_curve_public_bytes(curve, data) + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + EllipticCurvePublicKeyWithSerialization = EllipticCurvePublicKey diff --git a/src/cryptography/hazmat/primitives/asymmetric/ed25519.py b/src/cryptography/hazmat/primitives/asymmetric/ed25519.py index 83aa9d310e85..1e435fece6eb 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ed25519.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ed25519.py @@ -51,6 +51,12 @@ def verify(self, signature: bytes, data: bytes) -> None: Verify the signature. """ + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + class Ed25519PrivateKey(metaclass=abc.ABCMeta): @classmethod diff --git a/src/cryptography/hazmat/primitives/asymmetric/ed448.py b/src/cryptography/hazmat/primitives/asymmetric/ed448.py index c2a64796c2f4..40c7e090257e 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ed448.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ed448.py @@ -48,6 +48,12 @@ def verify(self, signature: bytes, data: bytes) -> None: Verify the signature. """ + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + class Ed448PrivateKey(metaclass=abc.ABCMeta): @classmethod diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py index c83f7fc88999..b740f01f7c4c 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -118,6 +118,12 @@ def recover_data_from_signature( Recovers the original data from the signature. """ + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + RSAPublicKeyWithSerialization = RSAPublicKey diff --git a/src/cryptography/hazmat/primitives/asymmetric/x25519.py b/src/cryptography/hazmat/primitives/asymmetric/x25519.py index 5455751508c4..699054c9689b 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/x25519.py +++ b/src/cryptography/hazmat/primitives/asymmetric/x25519.py @@ -41,6 +41,12 @@ def public_bytes_raw(self) -> bytes: Equivalent to public_bytes(Raw, Raw). """ + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + # For LibreSSL if hasattr(rust_openssl, "x25519"): diff --git a/src/cryptography/hazmat/primitives/asymmetric/x448.py b/src/cryptography/hazmat/primitives/asymmetric/x448.py index 06b55d44b2a6..abf7848550b8 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/x448.py +++ b/src/cryptography/hazmat/primitives/asymmetric/x448.py @@ -41,6 +41,12 @@ def public_bytes_raw(self) -> bytes: Equivalent to public_bytes(Raw, Raw). """ + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + if hasattr(rust_openssl, "x448"): X448PublicKey.register(rust_openssl.x448.X448PublicKey) diff --git a/src/rust/src/backend/x25519.rs b/src/rust/src/backend/x25519.rs index 9cd86b00af8f..a20e7092beb8 100644 --- a/src/rust/src/backend/x25519.rs +++ b/src/rust/src/backend/x25519.rs @@ -127,6 +127,18 @@ impl X25519PublicKey { ) -> CryptographyResult<&'p pyo3::types::PyBytes> { utils::pkey_public_bytes(py, &self.pkey, encoding, format) } + + fn __richcmp__( + &self, + other: pyo3::PyRef<'_, X25519PublicKey>, + op: pyo3::basic::CompareOp, + ) -> pyo3::PyResult { + match op { + pyo3::basic::CompareOp::Eq => Ok(self.pkey.public_eq(&other.pkey)), + pyo3::basic::CompareOp::Ne => Ok(!self.pkey.public_eq(&other.pkey)), + _ => Err(pyo3::exceptions::PyTypeError::new_err("Cannot be ordered")), + } + } } pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { diff --git a/src/rust/src/backend/x448.rs b/src/rust/src/backend/x448.rs index ff6d7f5b685c..1361b1da1bdd 100644 --- a/src/rust/src/backend/x448.rs +++ b/src/rust/src/backend/x448.rs @@ -127,6 +127,18 @@ impl X448PublicKey { ) -> CryptographyResult<&'p pyo3::types::PyBytes> { utils::pkey_public_bytes(py, &self.pkey, encoding, format) } + + fn __richcmp__( + &self, + other: pyo3::PyRef<'_, X448PublicKey>, + op: pyo3::basic::CompareOp, + ) -> pyo3::PyResult { + match op { + pyo3::basic::CompareOp::Eq => Ok(self.pkey.public_eq(&other.pkey)), + pyo3::basic::CompareOp::Ne => Ok(!self.pkey.public_eq(&other.pkey)), + _ => Err(pyo3::exceptions::PyTypeError::new_err("Cannot be ordered")), + } + } } pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index cec07a2ffbd8..33eac6ed8bba 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -738,15 +738,16 @@ fn create_ocsp_response( let tbs_bytes = asn1::write_single(&tbs_response_data)?; let signature = x509::sign::sign_data(py, private_key, hash_algorithm, &tbs_bytes)?; - py.import("cryptography.hazmat.backends.openssl.backend")? - .getattr(pyo3::intern!(py, "backend"))? - .call_method1( - "_check_keys_correspond", - ( - responder_cert.call_method0("public_key")?, - private_key.call_method0("public_key")?, + if !responder_cert + .call_method0("public_key")? + .eq(private_key.call_method0("public_key")?)? + { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err( + "Certificate public key and provided private key do not match", ), - )?; + )); + } py_certs = builder.getattr(pyo3::intern!(py, "_certs"))?.extract()?; let certs = py_certs.as_ref().map(|py_certs| { diff --git a/tests/hazmat/primitives/test_dh.py b/tests/hazmat/primitives/test_dh.py index 9a28d6114dc2..d47739ac07e8 100644 --- a/tests/hazmat/primitives/test_dh.py +++ b/tests/hazmat/primitives/test_dh.py @@ -464,6 +464,28 @@ def test_dh_vectors_with_q(self, backend, vector): assert int.from_bytes(symkey1, "big") == int(vector["z"], 16) assert int.from_bytes(symkey2, "big") == int(vector["z"], 16) + @pytest.mark.supported( + only_if=lambda backend: backend.dh_x942_serialization_supported(), + skip_message="DH X9.42 not supported", + ) + def test_public_key_equality(self, backend): + key_bytes = load_vectors_from_file( + os.path.join("asymmetric", "DH", "dhpub.pem"), + lambda pemfile: pemfile.read(), + mode="rb", + ) + key_bytes_2 = load_vectors_from_file( + os.path.join("asymmetric", "DH", "dhpub_rfc5114_2.pem"), + lambda pemfile: pemfile.read(), + mode="rb", + ) + key1 = serialization.load_pem_public_key(key_bytes) + key2 = serialization.load_pem_public_key(key_bytes) + key3 = serialization.load_pem_public_key(key_bytes_2) + assert key1 == key2 + assert key1 != key3 + assert key1 != object() + @pytest.mark.supported( only_if=lambda backend: backend.dh_supported(), diff --git a/tests/hazmat/primitives/test_dsa.py b/tests/hazmat/primitives/test_dsa.py index a1814c08209d..b97d7634396e 100644 --- a/tests/hazmat/primitives/test_dsa.py +++ b/tests/hazmat/primitives/test_dsa.py @@ -384,6 +384,18 @@ def test_large_p(self, backend): x=pn.x, ).private_key(backend) + def test_public_key_equality(self, backend): + key_bytes = load_vectors_from_file( + os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"), + lambda pemfile: pemfile.read().encode(), + ) + key1 = serialization.load_pem_private_key(key_bytes, None).public_key() + key2 = serialization.load_pem_private_key(key_bytes, None).public_key() + key3 = DSA_KEY_2048.private_key().public_key() + assert key1 == key2 + assert key1 != key3 + assert key1 != object() + @pytest.mark.supported( only_if=lambda backend: backend.dsa_supported(), diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py index 142024459cf2..601edcc48bd4 100644 --- a/tests/hazmat/primitives/test_ec.py +++ b/tests/hazmat/primitives/test_ec.py @@ -565,7 +565,7 @@ def test_verify_prehashed_digest_mismatch(self, backend): ) -class TestECNumbersEquality: +class TestECEquality: def test_public_numbers_eq(self): pub = ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1()) assert pub == ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1()) @@ -601,6 +601,19 @@ def test_private_numbers_ne(self): ) assert priv != object() + def test_public_key_equality(self, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + key_bytes = load_vectors_from_file( + os.path.join("asymmetric", "PKCS8", "ec_private_key.pem"), + lambda pemfile: pemfile.read().encode(), + ) + key1 = serialization.load_pem_private_key(key_bytes, None).public_key() + key2 = serialization.load_pem_private_key(key_bytes, None).public_key() + key3 = ec.generate_private_key(ec.SECP256R1()).public_key() + assert key1 == key2 + assert key1 != key3 + assert key1 != object() + class TestECSerialization: @pytest.mark.parametrize( diff --git a/tests/hazmat/primitives/test_ed25519.py b/tests/hazmat/primitives/test_ed25519.py index 5833c5c327b9..ca27544c730c 100644 --- a/tests/hazmat/primitives/test_ed25519.py +++ b/tests/hazmat/primitives/test_ed25519.py @@ -247,3 +247,21 @@ def test_buffer_protocol(self, backend): ) == private_bytes ) + + +@pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support", +) +def test_public_key_equality(backend): + key_bytes = load_vectors_from_file( + os.path.join("asymmetric", "Ed25519", "ed25519-pkcs8.der"), + lambda derfile: derfile.read(), + mode="rb", + ) + key1 = serialization.load_der_private_key(key_bytes, None).public_key() + key2 = serialization.load_der_private_key(key_bytes, None).public_key() + key3 = Ed25519PrivateKey.generate().public_key() + assert key1 == key2 + assert key1 != key3 + assert key1 != object() diff --git a/tests/hazmat/primitives/test_ed448.py b/tests/hazmat/primitives/test_ed448.py index ac915c79953c..5658b2b00821 100644 --- a/tests/hazmat/primitives/test_ed448.py +++ b/tests/hazmat/primitives/test_ed448.py @@ -260,3 +260,21 @@ def test_malleability(self, backend): key = Ed448PublicKey.from_public_bytes(public_bytes) with pytest.raises(InvalidSignature): key.verify(signature, b"8") + + +@pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support", +) +def test_public_key_equality(backend): + key_bytes = load_vectors_from_file( + os.path.join("asymmetric", "Ed448", "ed448-pkcs8.der"), + lambda derfile: derfile.read(), + mode="rb", + ) + key1 = serialization.load_der_private_key(key_bytes, None).public_key() + key2 = serialization.load_der_private_key(key_bytes, None).public_key() + key3 = Ed448PrivateKey.generate().public_key() + assert key1 == key2 + assert key1 != key3 + assert key1 != object() diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 36e65359bf51..017e02d424b2 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -2763,3 +2763,15 @@ def test_public_bytes_rejects_invalid( key = rsa_key_2048.public_key() with pytest.raises(ValueError): key.public_bytes(encoding, fmt) + + def test_public_key_equality(self, rsa_key_2048: rsa.RSAPrivateKey): + key1 = rsa_key_2048.public_key() + key2 = RSA_KEY_2048.private_key( + unsafe_skip_rsa_key_validation=True + ).public_key() + key3 = RSA_KEY_2048_ALT.private_key( + unsafe_skip_rsa_key_validation=True + ).public_key() + assert key1 == key2 + assert key1 != key3 + assert key1 != object() diff --git a/tests/hazmat/primitives/test_x25519.py b/tests/hazmat/primitives/test_x25519.py index 3eb642df5542..21cc55edfc03 100644 --- a/tests/hazmat/primitives/test_x25519.py +++ b/tests/hazmat/primitives/test_x25519.py @@ -317,3 +317,23 @@ def test_buffer_protocol(self, backend): ) == private_bytes ) + + +@pytest.mark.supported( + only_if=lambda backend: backend.x25519_supported(), + skip_message="Requires OpenSSL with X25519 support", +) +def test_public_key_equality(backend): + key_bytes = load_vectors_from_file( + os.path.join("asymmetric", "X25519", "x25519-pkcs8.der"), + lambda derfile: derfile.read(), + mode="rb", + ) + key1 = serialization.load_der_private_key(key_bytes, None).public_key() + key2 = serialization.load_der_private_key(key_bytes, None).public_key() + key3 = X25519PrivateKey.generate().public_key() + assert key1 == key2 + assert key1 != key3 + assert key1 != object() + with pytest.raises(TypeError): + key1 < key2 # type: ignore[operator] diff --git a/tests/hazmat/primitives/test_x448.py b/tests/hazmat/primitives/test_x448.py index 3e6506732b5f..c9d92112b698 100644 --- a/tests/hazmat/primitives/test_x448.py +++ b/tests/hazmat/primitives/test_x448.py @@ -253,3 +253,23 @@ def test_buffer_protocol(self, backend): ) == private_bytes ) + + +@pytest.mark.supported( + only_if=lambda backend: backend.x448_supported(), + skip_message="Requires OpenSSL with X448 support", +) +def test_public_key_equality(backend): + key_bytes = load_vectors_from_file( + os.path.join("asymmetric", "X448", "x448-pkcs8.der"), + lambda derfile: derfile.read(), + mode="rb", + ) + key1 = serialization.load_der_private_key(key_bytes, None).public_key() + key2 = serialization.load_der_private_key(key_bytes, None).public_key() + key3 = X448PrivateKey.generate().public_key() + assert key1 == key2 + assert key1 != key3 + assert key1 != object() + with pytest.raises(TypeError): + key1 < key2 # type: ignore[operator] From f8e929a22599c7c312785ac686bfada1d525c9c6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 10 Apr 2023 08:28:50 -0400 Subject: [PATCH 093/316] Fix alpine installation docs (#8701) --- docs/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index 0023187f9b7d..7bbdddcba2e6 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -106,7 +106,7 @@ Alpine .. warning:: - The Rust available by default in Alpine < 3.14 is older than the minimum + The Rust available by default in Alpine < 3.15 is older than the minimum supported version. See the :ref:`Rust installation instructions ` for information about installing a newer Rust. From 253a97a34b2a66e6df50ac04be1a3197fead60e6 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 10 Apr 2023 20:34:46 +0800 Subject: [PATCH 094/316] update docs for rust versions in debian and rhel (#8702) --- docs/installation.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 7bbdddcba2e6..896baf8f6d1d 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -121,8 +121,8 @@ Debian/Ubuntu .. warning:: - The Rust available in some Debian versions is older than the minimum - supported version. Debian Bullseye is sufficiently new, but otherwise + The Rust available in most Debian versions is older than the minimum + supported version. Debian Bookworm is sufficiently new, but otherwise please see the :ref:`Rust installation instructions ` for information about installing a newer Rust. @@ -136,7 +136,7 @@ Fedora/RHEL/CentOS .. warning:: - For RHEL and CentOS you must be on version 8.3 or newer for the command + For RHEL and CentOS you must be on version 8.6 or newer for the command below to install a sufficiently new Rust. If your Rust is less than 1.56.0 please see the :ref:`Rust installation instructions ` for information about installing a newer Rust. From d5db3d4bfcf69b5916c7e1513953acef288ab8dd Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 10 Apr 2023 08:39:03 -0400 Subject: [PATCH 095/316] Added extra test cases for Ed25519 serialization (#8703) --- tests/hazmat/primitives/test_ed25519.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/hazmat/primitives/test_ed25519.py b/tests/hazmat/primitives/test_ed25519.py index ca27544c730c..6d03332f292e 100644 --- a/tests/hazmat/primitives/test_ed25519.py +++ b/tests/hazmat/primitives/test_ed25519.py @@ -177,6 +177,13 @@ def test_invalid_private_bytes(self, backend): serialization.NoEncryption(), ) + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.DER, + serialization.PrivateFormat.OpenSSH, + serialization.NoEncryption(), + ) + def test_invalid_public_bytes(self, backend): key = Ed25519PrivateKey.generate().public_key() with pytest.raises(ValueError): @@ -195,6 +202,11 @@ def test_invalid_public_bytes(self, backend): serialization.Encoding.PEM, serialization.PublicFormat.Raw ) + with pytest.raises(ValueError): + key.public_bytes( + serialization.Encoding.DER, serialization.PublicFormat.OpenSSH + ) + @pytest.mark.parametrize( ("encoding", "fmt", "encryption", "passwd", "load_func"), [ From f5c750deab0722ecfd18aa741259e2f1e279a1bc Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 10 Apr 2023 08:55:57 -0400 Subject: [PATCH 096/316] Convert ed25519 to Rust (#8697) --- .../hazmat/backends/openssl/backend.py | 65 +++---- .../hazmat/backends/openssl/ed25519.py | 163 ---------------- .../bindings/_rust/openssl/__init__.pyi | 10 +- .../hazmat/bindings/_rust/openssl/ed25519.pyi | 14 ++ .../hazmat/primitives/asymmetric/ed25519.py | 19 +- src/rust/src/backend/ed25519.rs | 181 ++++++++++++++++++ src/rust/src/backend/mod.rs | 5 + src/rust/src/backend/utils.rs | 45 +++++ src/rust/src/backend/x25519.rs | 17 +- src/rust/src/backend/x448.rs | 16 +- tests/hazmat/primitives/test_ed25519.py | 3 + 11 files changed, 320 insertions(+), 218 deletions(-) delete mode 100644 src/cryptography/hazmat/backends/openssl/ed25519.py create mode 100644 src/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi create mode 100644 src/rust/src/backend/ed25519.rs diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 9c414e1a9c83..896b0476a9f7 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -35,10 +35,6 @@ _Ed448PrivateKey, _Ed448PublicKey, ) -from cryptography.hazmat.backends.openssl.ed25519 import ( - _Ed25519PrivateKey, - _Ed25519PublicKey, -) from cryptography.hazmat.backends.openssl.hashes import _HashContext from cryptography.hazmat.backends.openssl.hmac import _HMACContext from cryptography.hazmat.backends.openssl.poly1305 import ( @@ -641,7 +637,9 @@ def _evp_pkey_to_private_key( return _DHPrivateKey(self, dh_cdata, evp_pkey) elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): # EVP_PKEY_ED25519 is not present in CRYPTOGRAPHY_IS_LIBRESSL - return _Ed25519PrivateKey(self, evp_pkey) + return rust_openssl.ed25519.private_key_from_ptr( + int(self._ffi.cast("uintptr_t", evp_pkey)) + ) elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): # EVP_PKEY_X448 is not present in CRYPTOGRAPHY_IS_LIBRESSL return rust_openssl.x448.private_key_from_ptr( @@ -702,7 +700,9 @@ def _evp_pkey_to_public_key(self, evp_pkey) -> PublicKeyTypes: return _DHPublicKey(self, dh_cdata, evp_pkey) elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): # EVP_PKEY_ED25519 is not present in CRYPTOGRAPHY_IS_LIBRESSL - return _Ed25519PublicKey(self, evp_pkey) + return rust_openssl.ed25519.public_key_from_ptr( + int(self._ffi.cast("uintptr_t", evp_pkey)) + ) elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): # EVP_PKEY_X448 is not present in CRYPTOGRAPHY_IS_LIBRESSL return rust_openssl.x448.public_key_from_ptr( @@ -1049,6 +1049,21 @@ def _ossl2cert(self, x509_ptr: typing.Any) -> x509.Certificate: self.openssl_assert(res == 1) return x509.load_der_x509_certificate(self._read_mem_bio(bio)) + def _key2ossl(self, key: PKCS12PrivateKeyTypes) -> typing.Any: + data = key.private_bytes( + serialization.Encoding.DER, + serialization.PrivateFormat.PKCS8, + serialization.NoEncryption(), + ) + mem_bio = self._bytes_to_bio(data) + + evp_pkey = self._lib.d2i_PrivateKey_bio( + mem_bio.bio, + self._ffi.NULL, + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + return self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + def _load_key( self, openssl_read_func, data, password, unsafe_skip_rsa_key_validation ) -> PrivateKeyTypes: @@ -1848,38 +1863,15 @@ def ed25519_supported(self) -> bool: def ed25519_load_public_bytes( self, data: bytes ) -> ed25519.Ed25519PublicKey: - utils._check_bytes("data", data) - - if len(data) != ed25519._ED25519_KEY_SIZE: - raise ValueError("An Ed25519 public key is 32 bytes long") - - evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( - self._lib.NID_ED25519, self._ffi.NULL, data, len(data) - ) - self.openssl_assert(evp_pkey != self._ffi.NULL) - evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) - - return _Ed25519PublicKey(self, evp_pkey) + return rust_openssl.ed25519.from_public_bytes(data) def ed25519_load_private_bytes( self, data: bytes ) -> ed25519.Ed25519PrivateKey: - if len(data) != ed25519._ED25519_KEY_SIZE: - raise ValueError("An Ed25519 private key is 32 bytes long") - - utils._check_byteslike("data", data) - data_ptr = self._ffi.from_buffer(data) - evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( - self._lib.NID_ED25519, self._ffi.NULL, data_ptr, len(data) - ) - self.openssl_assert(evp_pkey != self._ffi.NULL) - evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) - - return _Ed25519PrivateKey(self, evp_pkey) + return rust_openssl.ed25519.from_private_bytes(data) def ed25519_generate_key(self) -> ed25519.Ed25519PrivateKey: - evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED25519) - return _Ed25519PrivateKey(self, evp_pkey) + return rust_openssl.ed25519.generate_key() def ed448_supported(self) -> bool: if self._fips_enabled: @@ -2207,15 +2199,14 @@ def serialize_key_and_certificates_to_pkcs12( 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 - if key is not None: - evp_pkey = key._evp_pkey # type: ignore[union-attr] - else: - evp_pkey = self._ffi.NULL + ossl_pkey = ( + self._key2ossl(key) if key is not None else self._ffi.NULL + ) p12 = self._lib.PKCS12_create( password_buf, name_buf, - evp_pkey, + ossl_pkey, ossl_cert, sk_x509, nid_key, diff --git a/src/cryptography/hazmat/backends/openssl/ed25519.py b/src/cryptography/hazmat/backends/openssl/ed25519.py deleted file mode 100644 index 72678c87721c..000000000000 --- a/src/cryptography/hazmat/backends/openssl/ed25519.py +++ /dev/null @@ -1,163 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography import exceptions -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives.asymmetric.ed25519 import ( - _ED25519_KEY_SIZE, - _ED25519_SIG_SIZE, - Ed25519PrivateKey, - Ed25519PublicKey, -) - -if typing.TYPE_CHECKING: - from cryptography.hazmat.backends.openssl.backend import Backend - - -class _Ed25519PublicKey(Ed25519PublicKey): - def __init__(self, backend: Backend, evp_pkey): - self._backend = backend - self._evp_pkey = evp_pkey - - def public_bytes( - self, - encoding: serialization.Encoding, - format: serialization.PublicFormat, - ) -> bytes: - if ( - encoding is serialization.Encoding.Raw - or format is serialization.PublicFormat.Raw - ): - if ( - encoding is not serialization.Encoding.Raw - or format is not serialization.PublicFormat.Raw - ): - raise ValueError( - "When using Raw both encoding and format must be Raw" - ) - - return self._raw_public_bytes() - - return self._backend._public_key_bytes( - encoding, format, self, self._evp_pkey, None - ) - - def _raw_public_bytes(self) -> bytes: - buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) - buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) - res = self._backend._lib.EVP_PKEY_get_raw_public_key( - self._evp_pkey, buf, buflen - ) - self._backend.openssl_assert(res == 1) - self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) - return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:] - - def verify(self, signature: bytes, data: bytes) -> None: - evp_md_ctx = self._backend._lib.EVP_MD_CTX_new() - self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) - evp_md_ctx = self._backend._ffi.gc( - evp_md_ctx, self._backend._lib.EVP_MD_CTX_free - ) - res = self._backend._lib.EVP_DigestVerifyInit( - evp_md_ctx, - self._backend._ffi.NULL, - self._backend._ffi.NULL, - self._backend._ffi.NULL, - self._evp_pkey, - ) - self._backend.openssl_assert(res == 1) - res = self._backend._lib.EVP_DigestVerify( - evp_md_ctx, signature, len(signature), data, len(data) - ) - if res != 1: - self._backend._consume_errors() - raise exceptions.InvalidSignature - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Ed25519PublicKey): - return NotImplemented - - return self.public_bytes_raw() == other.public_bytes_raw() - - -class _Ed25519PrivateKey(Ed25519PrivateKey): - def __init__(self, backend: Backend, evp_pkey): - self._backend = backend - self._evp_pkey = evp_pkey - - def public_key(self) -> Ed25519PublicKey: - buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) - buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) - res = self._backend._lib.EVP_PKEY_get_raw_public_key( - self._evp_pkey, buf, buflen - ) - self._backend.openssl_assert(res == 1) - self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) - public_bytes = self._backend._ffi.buffer(buf)[:] - return self._backend.ed25519_load_public_bytes(public_bytes) - - def sign(self, data: bytes) -> bytes: - evp_md_ctx = self._backend._lib.EVP_MD_CTX_new() - self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) - evp_md_ctx = self._backend._ffi.gc( - evp_md_ctx, self._backend._lib.EVP_MD_CTX_free - ) - res = self._backend._lib.EVP_DigestSignInit( - evp_md_ctx, - self._backend._ffi.NULL, - self._backend._ffi.NULL, - self._backend._ffi.NULL, - self._evp_pkey, - ) - self._backend.openssl_assert(res == 1) - buf = self._backend._ffi.new("unsigned char[]", _ED25519_SIG_SIZE) - buflen = self._backend._ffi.new("size_t *", len(buf)) - res = self._backend._lib.EVP_DigestSign( - evp_md_ctx, buf, buflen, data, len(data) - ) - self._backend.openssl_assert(res == 1) - self._backend.openssl_assert(buflen[0] == _ED25519_SIG_SIZE) - return self._backend._ffi.buffer(buf, buflen[0])[:] - - def private_bytes( - self, - encoding: serialization.Encoding, - format: serialization.PrivateFormat, - encryption_algorithm: serialization.KeySerializationEncryption, - ) -> bytes: - if ( - encoding is serialization.Encoding.Raw - or format is serialization.PrivateFormat.Raw - ): - if ( - format is not serialization.PrivateFormat.Raw - or encoding is not serialization.Encoding.Raw - or not isinstance( - encryption_algorithm, serialization.NoEncryption - ) - ): - raise ValueError( - "When using Raw both encoding and format must be Raw " - "and encryption_algorithm must be NoEncryption()" - ) - - return self._raw_private_bytes() - - return self._backend._private_key_bytes( - encoding, format, encryption_algorithm, self, self._evp_pkey, None - ) - - def _raw_private_bytes(self) -> bytes: - buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) - buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) - res = self._backend._lib.EVP_PKEY_get_raw_private_key( - self._evp_pkey, buf, buflen - ) - self._backend.openssl_assert(res == 1) - self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) - return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:] diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi index 31e682b9ae36..6ed6f17ade16 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -4,9 +4,15 @@ import typing -from cryptography.hazmat.bindings._rust.openssl import x448, x25519 +from cryptography.hazmat.bindings._rust.openssl import ed25519, x448, x25519 -__all__ = ["openssl_version", "raise_openssl_error", "x448", "x25519"] +__all__ = [ + "openssl_version", + "raise_openssl_error", + "ed25519", + "x448", + "x25519", +] def openssl_version() -> int: ... def raise_openssl_error() -> typing.NoReturn: ... diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi new file mode 100644 index 000000000000..c7f127f0b157 --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi @@ -0,0 +1,14 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives.asymmetric import ed25519 + +class Ed25519PrivateKey: ... +class Ed25519PublicKey: ... + +def generate_key() -> ed25519.Ed25519PrivateKey: ... +def private_key_from_ptr(ptr: int) -> ed25519.Ed25519PrivateKey: ... +def public_key_from_ptr(ptr: int) -> ed25519.Ed25519PublicKey: ... +def from_private_bytes(data: bytes) -> ed25519.Ed25519PrivateKey: ... +def from_public_bytes(data: bytes) -> ed25519.Ed25519PublicKey: ... diff --git a/src/cryptography/hazmat/primitives/asymmetric/ed25519.py b/src/cryptography/hazmat/primitives/asymmetric/ed25519.py index 1e435fece6eb..772e5de82362 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ed25519.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ed25519.py @@ -7,6 +7,7 @@ import abc from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives import _serialization _ED25519_KEY_SIZE = 32 @@ -36,14 +37,12 @@ def public_bytes( The serialized bytes of the public key. """ + @abc.abstractmethod def public_bytes_raw(self) -> bytes: """ The raw bytes of the public key. Equivalent to public_bytes(Raw, Raw). """ - return self.public_bytes( - _serialization.Encoding.Raw, _serialization.PublicFormat.Raw - ) @abc.abstractmethod def verify(self, signature: bytes, data: bytes) -> None: @@ -58,6 +57,10 @@ def __eq__(self, other: object) -> bool: """ +if hasattr(rust_openssl, "ed25519"): + Ed25519PublicKey.register(rust_openssl.ed25519.Ed25519PublicKey) + + class Ed25519PrivateKey(metaclass=abc.ABCMeta): @classmethod def generate(cls) -> Ed25519PrivateKey: @@ -100,19 +103,19 @@ def private_bytes( The serialized bytes of the private key. """ + @abc.abstractmethod def private_bytes_raw(self) -> bytes: """ The raw bytes of the private key. Equivalent to private_bytes(Raw, Raw, NoEncryption()). """ - return self.private_bytes( - _serialization.Encoding.Raw, - _serialization.PrivateFormat.Raw, - _serialization.NoEncryption(), - ) @abc.abstractmethod def sign(self, data: bytes) -> bytes: """ Signs the data. """ + + +if hasattr(rust_openssl, "x25519"): + Ed25519PrivateKey.register(rust_openssl.ed25519.Ed25519PrivateKey) diff --git a/src/rust/src/backend/ed25519.rs b/src/rust/src/backend/ed25519.rs new file mode 100644 index 000000000000..a8d10c880e4c --- /dev/null +++ b/src/rust/src/backend/ed25519.rs @@ -0,0 +1,181 @@ +// 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::backend::utils; +use crate::buf::CffiBuf; +use crate::error::{CryptographyError, CryptographyResult}; +use foreign_types_shared::ForeignTypeRef; + +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.ed25519")] +struct Ed25519PrivateKey { + pkey: openssl::pkey::PKey, +} + +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.ed25519")] +struct Ed25519PublicKey { + pkey: openssl::pkey::PKey, +} + +#[pyo3::prelude::pyfunction] +fn generate_key() -> CryptographyResult { + Ok(Ed25519PrivateKey { + pkey: openssl::pkey::PKey::generate_ed25519()?, + }) +} + +#[pyo3::prelude::pyfunction] +fn private_key_from_ptr(ptr: usize) -> Ed25519PrivateKey { + let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; + Ed25519PrivateKey { + pkey: pkey.to_owned(), + } +} + +#[pyo3::prelude::pyfunction] +fn public_key_from_ptr(ptr: usize) -> Ed25519PublicKey { + let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; + Ed25519PublicKey { + pkey: pkey.to_owned(), + } +} + +#[pyo3::prelude::pyfunction] +fn from_private_bytes(data: CffiBuf<'_>) -> pyo3::PyResult { + let pkey = openssl::pkey::PKey::private_key_from_raw_bytes( + data.as_bytes(), + openssl::pkey::Id::ED25519, + ) + .map_err(|_| { + pyo3::exceptions::PyValueError::new_err("An Ed25519 private key is 32 bytes long") + })?; + Ok(Ed25519PrivateKey { pkey }) +} + +#[pyo3::prelude::pyfunction] +fn from_public_bytes(data: &[u8]) -> pyo3::PyResult { + let pkey = openssl::pkey::PKey::public_key_from_raw_bytes(data, openssl::pkey::Id::ED25519) + .map_err(|_| { + pyo3::exceptions::PyValueError::new_err("An Ed25519 public key is 32 bytes long") + })?; + Ok(Ed25519PublicKey { pkey }) +} + +#[pyo3::prelude::pymethods] +impl Ed25519PrivateKey { + fn sign<'p>( + &self, + py: pyo3::Python<'p>, + data: &[u8], + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let mut signer = openssl::sign::Signer::new_without_digest(&self.pkey)?; + Ok(pyo3::types::PyBytes::new_with(py, signer.len()?, |b| { + let n = signer + .sign_oneshot(b, data) + .map_err(CryptographyError::from)?; + assert_eq!(n, b.len()); + Ok(()) + })?) + } + + fn public_key(&self) -> CryptographyResult { + let raw_bytes = self.pkey.raw_public_key()?; + Ok(Ed25519PublicKey { + pkey: openssl::pkey::PKey::public_key_from_raw_bytes( + &raw_bytes, + openssl::pkey::Id::ED25519, + )?, + }) + } + + fn private_bytes_raw<'p>( + &self, + py: pyo3::Python<'p>, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let raw_bytes = self.pkey.raw_private_key()?; + Ok(pyo3::types::PyBytes::new(py, &raw_bytes)) + } + + fn private_bytes<'p>( + slf: &pyo3::PyCell, + py: pyo3::Python<'p>, + encoding: &pyo3::PyAny, + format: &pyo3::PyAny, + encryption_algorithm: &pyo3::PyAny, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + utils::pkey_private_bytes( + py, + &*slf, + &slf.borrow().pkey, + encoding, + format, + encryption_algorithm, + true, + ) + } +} + +#[pyo3::prelude::pymethods] +impl Ed25519PublicKey { + fn verify( + &self, + py: pyo3::Python<'_>, + signature: &[u8], + data: &[u8], + ) -> CryptographyResult<()> { + let valid = openssl::sign::Verifier::new_without_digest(&self.pkey)? + .verify_oneshot(signature, data)?; + + if !valid { + return Err(CryptographyError::from(pyo3::PyErr::from_value( + py.import("cryptography.exceptions")? + .call_method1("InvalidSignature", ())?, + ))); + } + + Ok(()) + } + + fn public_bytes_raw<'p>( + &self, + py: pyo3::Python<'p>, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let raw_bytes = self.pkey.raw_public_key()?; + Ok(pyo3::types::PyBytes::new(py, &raw_bytes)) + } + + fn public_bytes<'p>( + slf: &pyo3::PyCell, + py: pyo3::Python<'p>, + encoding: &pyo3::PyAny, + format: &pyo3::PyAny, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + utils::pkey_public_bytes(py, &*slf, &slf.borrow().pkey, encoding, format, true) + } + + fn __richcmp__( + &self, + other: pyo3::PyRef<'_, Ed25519PublicKey>, + op: pyo3::basic::CompareOp, + ) -> pyo3::PyResult { + match op { + pyo3::basic::CompareOp::Eq => Ok(self.pkey.public_eq(&other.pkey)), + pyo3::basic::CompareOp::Ne => Ok(!self.pkey.public_eq(&other.pkey)), + _ => Err(pyo3::exceptions::PyTypeError::new_err("Cannot be ordered")), + } + } +} + +pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let m = pyo3::prelude::PyModule::new(py, "ed25519")?; + m.add_wrapped(pyo3::wrap_pyfunction!(generate_key))?; + m.add_wrapped(pyo3::wrap_pyfunction!(private_key_from_ptr))?; + m.add_wrapped(pyo3::wrap_pyfunction!(public_key_from_ptr))?; + m.add_wrapped(pyo3::wrap_pyfunction!(from_private_bytes))?; + m.add_wrapped(pyo3::wrap_pyfunction!(from_public_bytes))?; + + m.add_class::()?; + m.add_class::()?; + + Ok(m) +} diff --git a/src/rust/src/backend/mod.rs b/src/rust/src/backend/mod.rs index 82beb444a2cb..95aa08a6e2c3 100644 --- a/src/rust/src/backend/mod.rs +++ b/src/rust/src/backend/mod.rs @@ -2,6 +2,8 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. +#[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] +pub(crate) mod ed25519; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] pub(crate) mod utils; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] @@ -10,6 +12,9 @@ pub(crate) mod x25519; pub(crate) mod x448; pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { + #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] + module.add_submodule(ed25519::create_module(module.py())?)?; + #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] module.add_submodule(x25519::create_module(module.py())?)?; #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] diff --git a/src/rust/src/backend/utils.rs b/src/rust/src/backend/utils.rs index 97b2b0c64a63..6b41a6548008 100644 --- a/src/rust/src/backend/utils.rs +++ b/src/rust/src/backend/utils.rs @@ -6,10 +6,12 @@ use crate::error::{CryptographyError, CryptographyResult}; pub(crate) fn pkey_private_bytes<'p>( py: pyo3::Python<'p>, + key_obj: &pyo3::PyAny, pkey: &openssl::pkey::PKey, encoding: &pyo3::PyAny, format: &pyo3::PyAny, encryption_algorithm: &pyo3::PyAny, + openssh_allowed: bool, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { let serialization_mod = py.import("cryptography.hazmat.primitives.serialization")?; let encoding_class: &pyo3::types::PyType = serialization_mod @@ -104,6 +106,28 @@ pub(crate) fn pkey_private_bytes<'p>( )); } + // OpenSSH + PEM + if openssh_allowed && format.is(private_format_class.getattr(pyo3::intern!(py, "OpenSSH"))?) { + if encoding.is(encoding_class.getattr(pyo3::intern!(py, "PEM"))?) { + return Ok(py + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization.ssh" + ))? + .call_method1( + pyo3::intern!(py, "_serialize_ssh_private_key"), + (key_obj, password, encryption_algorithm), + )? + .extract()?); + } + + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err( + "OpenSSH private key format can only be used with PEM encoding", + ), + )); + } + Err(CryptographyError::from( pyo3::exceptions::PyValueError::new_err("format is invalid with this key"), )) @@ -111,9 +135,11 @@ pub(crate) fn pkey_private_bytes<'p>( pub(crate) fn pkey_public_bytes<'p>( py: pyo3::Python<'p>, + key_obj: &pyo3::PyAny, pkey: &openssl::pkey::PKey, encoding: &pyo3::PyAny, format: &pyo3::PyAny, + openssh_allowed: bool, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { let serialization_mod = py.import("cryptography.hazmat.primitives.serialization")?; let encoding_class: &pyo3::types::PyType = serialization_mod @@ -170,6 +196,25 @@ pub(crate) fn pkey_public_bytes<'p>( )); } + // OpenSSH + OpenSSH + if openssh_allowed && format.is(public_format_class.getattr(pyo3::intern!(py, "OpenSSH"))?) { + if encoding.is(encoding_class.getattr(pyo3::intern!(py, "OpenSSH"))?) { + return Ok(py + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization.ssh" + ))? + .call_method1(pyo3::intern!(py, "serialize_ssh_public_key"), (key_obj,))? + .extract()?); + } + + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err( + "OpenSSH format must be used with OpenSSH encoding", + ), + )); + } + Err(CryptographyError::from( pyo3::exceptions::PyValueError::new_err("format is invalid with this key"), )) diff --git a/src/rust/src/backend/x25519.rs b/src/rust/src/backend/x25519.rs index a20e7092beb8..409f28c87a18 100644 --- a/src/rust/src/backend/x25519.rs +++ b/src/rust/src/backend/x25519.rs @@ -52,6 +52,7 @@ fn from_private_bytes(data: CffiBuf<'_>) -> pyo3::PyResult { })?; Ok(X25519PrivateKey { pkey }) } + #[pyo3::prelude::pyfunction] fn from_public_bytes(data: &[u8]) -> pyo3::PyResult { let pkey = openssl::pkey::PKey::public_key_from_raw_bytes(data, openssl::pkey::Id::X25519) @@ -99,13 +100,21 @@ impl X25519PrivateKey { } fn private_bytes<'p>( - &self, + slf: &pyo3::PyCell, py: pyo3::Python<'p>, encoding: &pyo3::PyAny, format: &pyo3::PyAny, encryption_algorithm: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - utils::pkey_private_bytes(py, &self.pkey, encoding, format, encryption_algorithm) + utils::pkey_private_bytes( + py, + &*slf, + &slf.borrow().pkey, + encoding, + format, + encryption_algorithm, + false, + ) } } @@ -120,12 +129,12 @@ impl X25519PublicKey { } fn public_bytes<'p>( - &self, + slf: &pyo3::PyCell, py: pyo3::Python<'p>, encoding: &pyo3::PyAny, format: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - utils::pkey_public_bytes(py, &self.pkey, encoding, format) + utils::pkey_public_bytes(py, &*slf, &slf.borrow().pkey, encoding, format, false) } fn __richcmp__( diff --git a/src/rust/src/backend/x448.rs b/src/rust/src/backend/x448.rs index 1361b1da1bdd..acfc9f2a0945 100644 --- a/src/rust/src/backend/x448.rs +++ b/src/rust/src/backend/x448.rs @@ -99,13 +99,21 @@ impl X448PrivateKey { } fn private_bytes<'p>( - &self, + slf: &pyo3::PyCell, py: pyo3::Python<'p>, encoding: &pyo3::PyAny, format: &pyo3::PyAny, encryption_algorithm: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - utils::pkey_private_bytes(py, &self.pkey, encoding, format, encryption_algorithm) + utils::pkey_private_bytes( + py, + &*slf, + &slf.borrow().pkey, + encoding, + format, + encryption_algorithm, + false, + ) } } @@ -120,12 +128,12 @@ impl X448PublicKey { } fn public_bytes<'p>( - &self, + slf: &pyo3::PyCell, py: pyo3::Python<'p>, encoding: &pyo3::PyAny, format: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - utils::pkey_public_bytes(py, &self.pkey, encoding, format) + utils::pkey_public_bytes(py, &*slf, &slf.borrow().pkey, encoding, format, false) } fn __richcmp__( diff --git a/tests/hazmat/primitives/test_ed25519.py b/tests/hazmat/primitives/test_ed25519.py index 6d03332f292e..7f847078c345 100644 --- a/tests/hazmat/primitives/test_ed25519.py +++ b/tests/hazmat/primitives/test_ed25519.py @@ -277,3 +277,6 @@ def test_public_key_equality(backend): assert key1 == key2 assert key1 != key3 assert key1 != object() + + with pytest.raises(TypeError): + key1 < key2 # type: ignore[operator] From f82890de4d56d3277521554185b35f53bb90387d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Apr 2023 13:16:14 +0000 Subject: [PATCH 097/316] Bump pygments from 2.14.0 to 2.15.0 (#8704) Bumps [pygments](https://github.com/pygments/pygments) from 2.14.0 to 2.15.0. - [Release notes](https://github.com/pygments/pygments/releases) - [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES) - [Commits](https://github.com/pygments/pygments/compare/2.14.0...2.15.0) --- updated-dependencies: - dependency-name: pygments 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index b6b9289cb6e2..ddb738150e4f 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -98,7 +98,7 @@ pyenchant==3.2.2 # via # cryptography (pyproject.toml) # sphinxcontrib-spelling -pygments==2.14.0 +pygments==2.15.0 # via # readme-renderer # rich From cef2be76e891942205ffede30f64016de1b61644 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 10 Apr 2023 19:41:53 -0400 Subject: [PATCH 098/316] Convert ed448 to Rust (#8705) --- .../hazmat/backends/openssl/backend.py | 68 ++----- .../hazmat/backends/openssl/ed448.py | 164 ---------------- .../bindings/_rust/openssl/__init__.pyi | 8 +- .../hazmat/bindings/_rust/openssl/ed448.pyi | 14 ++ .../hazmat/primitives/asymmetric/ed448.py | 19 +- src/rust/src/backend/ed448.rs | 179 ++++++++++++++++++ src/rust/src/backend/mod.rs | 4 + tests/hazmat/primitives/test_ed448.py | 3 + 8 files changed, 231 insertions(+), 228 deletions(-) delete mode 100644 src/cryptography/hazmat/backends/openssl/ed448.py create mode 100644 src/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi create mode 100644 src/rust/src/backend/ed448.rs diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 896b0476a9f7..256f3a1c1645 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -30,11 +30,6 @@ _EllipticCurvePrivateKey, _EllipticCurvePublicKey, ) -from cryptography.hazmat.backends.openssl.ed448 import ( - _ED448_KEY_SIZE, - _Ed448PrivateKey, - _Ed448PublicKey, -) from cryptography.hazmat.backends.openssl.hashes import _HashContext from cryptography.hazmat.backends.openssl.hmac import _HMACContext from cryptography.hazmat.backends.openssl.poly1305 import ( @@ -651,7 +646,9 @@ def _evp_pkey_to_private_key( ) elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): # EVP_PKEY_ED448 is not present in CRYPTOGRAPHY_IS_LIBRESSL - return _Ed448PrivateKey(self, evp_pkey) + return rust_openssl.ed448.private_key_from_ptr( + int(self._ffi.cast("uintptr_t", evp_pkey)) + ) else: raise UnsupportedAlgorithm("Unsupported key type.") @@ -714,7 +711,9 @@ def _evp_pkey_to_public_key(self, evp_pkey) -> PublicKeyTypes: ) elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): # EVP_PKEY_ED448 is not present in CRYPTOGRAPHY_IS_LIBRESSL - return _Ed448PublicKey(self, evp_pkey) + return rust_openssl.ed448.public_key_from_ptr( + int(self._ffi.cast("uintptr_t", evp_pkey)) + ) else: raise UnsupportedAlgorithm("Unsupported key type.") @@ -1503,12 +1502,9 @@ def _private_key_bytes( write_bio = self._lib.PEM_write_bio_RSAPrivateKey elif key_type == self._lib.EVP_PKEY_DSA: write_bio = self._lib.PEM_write_bio_DSAPrivateKey - elif key_type == self._lib.EVP_PKEY_EC: - write_bio = self._lib.PEM_write_bio_ECPrivateKey else: - raise ValueError( - "Unsupported key type for TraditionalOpenSSL" - ) + assert key_type == self._lib.EVP_PKEY_EC + write_bio = self._lib.PEM_write_bio_ECPrivateKey return self._private_key_bytes_via_bio( write_bio, cdata, password ) @@ -1523,12 +1519,9 @@ def _private_key_bytes( write_bio = self._lib.i2d_RSAPrivateKey_bio elif key_type == self._lib.EVP_PKEY_EC: write_bio = self._lib.i2d_ECPrivateKey_bio - elif key_type == self._lib.EVP_PKEY_DSA: - write_bio = self._lib.i2d_DSAPrivateKey_bio else: - raise ValueError( - "Unsupported key type for TraditionalOpenSSL" - ) + assert key_type == self._lib.EVP_PKEY_DSA + write_bio = self._lib.i2d_DSAPrivateKey_bio return self._bio_func_output(write_bio, cdata) raise ValueError("Unsupported encoding for TraditionalOpenSSL") @@ -1817,19 +1810,6 @@ def x25519_load_private_bytes( ) -> x25519.X25519PrivateKey: return rust_openssl.x25519.from_private_bytes(data) - def _evp_pkey_keygen_gc(self, nid): - evp_pkey_ctx = self._lib.EVP_PKEY_CTX_new_id(nid, self._ffi.NULL) - self.openssl_assert(evp_pkey_ctx != self._ffi.NULL) - evp_pkey_ctx = self._ffi.gc(evp_pkey_ctx, self._lib.EVP_PKEY_CTX_free) - res = self._lib.EVP_PKEY_keygen_init(evp_pkey_ctx) - self.openssl_assert(res == 1) - evp_ppkey = self._ffi.new("EVP_PKEY **") - res = self._lib.EVP_PKEY_keygen(evp_pkey_ctx, evp_ppkey) - self.openssl_assert(res == 1) - self.openssl_assert(evp_ppkey[0] != self._ffi.NULL) - evp_pkey = self._ffi.gc(evp_ppkey[0], self._lib.EVP_PKEY_free) - return evp_pkey - def x25519_generate_key(self) -> x25519.X25519PrivateKey: return rust_openssl.x25519.generate_key() @@ -1882,35 +1862,13 @@ def ed448_supported(self) -> bool: ) def ed448_load_public_bytes(self, data: bytes) -> ed448.Ed448PublicKey: - utils._check_bytes("data", data) - if len(data) != _ED448_KEY_SIZE: - raise ValueError("An Ed448 public key is 57 bytes long") - - evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( - self._lib.NID_ED448, self._ffi.NULL, data, len(data) - ) - self.openssl_assert(evp_pkey != self._ffi.NULL) - evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) - - return _Ed448PublicKey(self, evp_pkey) + return rust_openssl.ed448.from_public_bytes(data) def ed448_load_private_bytes(self, data: bytes) -> ed448.Ed448PrivateKey: - utils._check_byteslike("data", data) - if len(data) != _ED448_KEY_SIZE: - raise ValueError("An Ed448 private key is 57 bytes long") - - data_ptr = self._ffi.from_buffer(data) - evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( - self._lib.NID_ED448, self._ffi.NULL, data_ptr, len(data) - ) - self.openssl_assert(evp_pkey != self._ffi.NULL) - evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) - - return _Ed448PrivateKey(self, evp_pkey) + return rust_openssl.ed448.from_private_bytes(data) def ed448_generate_key(self) -> ed448.Ed448PrivateKey: - evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED448) - return _Ed448PrivateKey(self, evp_pkey) + return rust_openssl.ed448.generate_key() def derive_scrypt( self, diff --git a/src/cryptography/hazmat/backends/openssl/ed448.py b/src/cryptography/hazmat/backends/openssl/ed448.py deleted file mode 100644 index 1f829420d143..000000000000 --- a/src/cryptography/hazmat/backends/openssl/ed448.py +++ /dev/null @@ -1,164 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography import exceptions -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives.asymmetric.ed448 import ( - Ed448PrivateKey, - Ed448PublicKey, -) - -if typing.TYPE_CHECKING: - from cryptography.hazmat.backends.openssl.backend import Backend - -_ED448_KEY_SIZE = 57 -_ED448_SIG_SIZE = 114 - - -class _Ed448PublicKey(Ed448PublicKey): - def __init__(self, backend: Backend, evp_pkey): - self._backend = backend - self._evp_pkey = evp_pkey - - def public_bytes( - self, - encoding: serialization.Encoding, - format: serialization.PublicFormat, - ) -> bytes: - if ( - encoding is serialization.Encoding.Raw - or format is serialization.PublicFormat.Raw - ): - if ( - encoding is not serialization.Encoding.Raw - or format is not serialization.PublicFormat.Raw - ): - raise ValueError( - "When using Raw both encoding and format must be Raw" - ) - - return self._raw_public_bytes() - - return self._backend._public_key_bytes( - encoding, format, self, self._evp_pkey, None - ) - - def _raw_public_bytes(self) -> bytes: - buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) - buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) - res = self._backend._lib.EVP_PKEY_get_raw_public_key( - self._evp_pkey, buf, buflen - ) - self._backend.openssl_assert(res == 1) - self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) - return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:] - - def verify(self, signature: bytes, data: bytes) -> None: - evp_md_ctx = self._backend._lib.EVP_MD_CTX_new() - self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) - evp_md_ctx = self._backend._ffi.gc( - evp_md_ctx, self._backend._lib.EVP_MD_CTX_free - ) - res = self._backend._lib.EVP_DigestVerifyInit( - evp_md_ctx, - self._backend._ffi.NULL, - self._backend._ffi.NULL, - self._backend._ffi.NULL, - self._evp_pkey, - ) - self._backend.openssl_assert(res == 1) - res = self._backend._lib.EVP_DigestVerify( - evp_md_ctx, signature, len(signature), data, len(data) - ) - if res != 1: - self._backend._consume_errors() - raise exceptions.InvalidSignature - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Ed448PublicKey): - return NotImplemented - - return self.public_bytes_raw() == other.public_bytes_raw() - - -class _Ed448PrivateKey(Ed448PrivateKey): - def __init__(self, backend: Backend, evp_pkey): - self._backend = backend - self._evp_pkey = evp_pkey - - def public_key(self) -> Ed448PublicKey: - buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) - buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) - res = self._backend._lib.EVP_PKEY_get_raw_public_key( - self._evp_pkey, buf, buflen - ) - self._backend.openssl_assert(res == 1) - self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) - public_bytes = self._backend._ffi.buffer(buf)[:] - return self._backend.ed448_load_public_bytes(public_bytes) - - def sign(self, data: bytes) -> bytes: - evp_md_ctx = self._backend._lib.EVP_MD_CTX_new() - self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) - evp_md_ctx = self._backend._ffi.gc( - evp_md_ctx, self._backend._lib.EVP_MD_CTX_free - ) - res = self._backend._lib.EVP_DigestSignInit( - evp_md_ctx, - self._backend._ffi.NULL, - self._backend._ffi.NULL, - self._backend._ffi.NULL, - self._evp_pkey, - ) - self._backend.openssl_assert(res == 1) - buf = self._backend._ffi.new("unsigned char[]", _ED448_SIG_SIZE) - buflen = self._backend._ffi.new("size_t *", len(buf)) - res = self._backend._lib.EVP_DigestSign( - evp_md_ctx, buf, buflen, data, len(data) - ) - self._backend.openssl_assert(res == 1) - self._backend.openssl_assert(buflen[0] == _ED448_SIG_SIZE) - return self._backend._ffi.buffer(buf, buflen[0])[:] - - def private_bytes( - self, - encoding: serialization.Encoding, - format: serialization.PrivateFormat, - encryption_algorithm: serialization.KeySerializationEncryption, - ) -> bytes: - if ( - encoding is serialization.Encoding.Raw - or format is serialization.PrivateFormat.Raw - ): - if ( - format is not serialization.PrivateFormat.Raw - or encoding is not serialization.Encoding.Raw - or not isinstance( - encryption_algorithm, serialization.NoEncryption - ) - ): - raise ValueError( - "When using Raw both encoding and format must be Raw " - "and encryption_algorithm must be NoEncryption()" - ) - - return self._raw_private_bytes() - - return self._backend._private_key_bytes( - encoding, format, encryption_algorithm, self, self._evp_pkey, None - ) - - def _raw_private_bytes(self) -> bytes: - buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) - buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) - res = self._backend._lib.EVP_PKEY_get_raw_private_key( - self._evp_pkey, buf, buflen - ) - self._backend.openssl_assert(res == 1) - self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) - return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:] diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi index 6ed6f17ade16..aceb859c63c7 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -4,11 +4,17 @@ import typing -from cryptography.hazmat.bindings._rust.openssl import ed25519, x448, x25519 +from cryptography.hazmat.bindings._rust.openssl import ( + ed448, + ed25519, + x448, + x25519, +) __all__ = [ "openssl_version", "raise_openssl_error", + "ed448", "ed25519", "x448", "x25519", diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi new file mode 100644 index 000000000000..1cf5f1773a0b --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi @@ -0,0 +1,14 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives.asymmetric import ed448 + +class Ed448PrivateKey: ... +class Ed448PublicKey: ... + +def generate_key() -> ed448.Ed448PrivateKey: ... +def private_key_from_ptr(ptr: int) -> ed448.Ed448PrivateKey: ... +def public_key_from_ptr(ptr: int) -> ed448.Ed448PublicKey: ... +def from_private_bytes(data: bytes) -> ed448.Ed448PrivateKey: ... +def from_public_bytes(data: bytes) -> ed448.Ed448PublicKey: ... diff --git a/src/cryptography/hazmat/primitives/asymmetric/ed448.py b/src/cryptography/hazmat/primitives/asymmetric/ed448.py index 40c7e090257e..a9a34b251b01 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ed448.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ed448.py @@ -7,6 +7,7 @@ import abc from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives import _serialization @@ -33,14 +34,12 @@ def public_bytes( The serialized bytes of the public key. """ + @abc.abstractmethod def public_bytes_raw(self) -> bytes: """ The raw bytes of the public key. Equivalent to public_bytes(Raw, Raw). """ - return self.public_bytes( - _serialization.Encoding.Raw, _serialization.PublicFormat.Raw - ) @abc.abstractmethod def verify(self, signature: bytes, data: bytes) -> None: @@ -55,6 +54,10 @@ def __eq__(self, other: object) -> bool: """ +if hasattr(rust_openssl, "ed448"): + Ed448PublicKey.register(rust_openssl.ed448.Ed448PublicKey) + + class Ed448PrivateKey(metaclass=abc.ABCMeta): @classmethod def generate(cls) -> Ed448PrivateKey: @@ -102,13 +105,13 @@ def private_bytes( The serialized bytes of the private key. """ + @abc.abstractmethod def private_bytes_raw(self) -> bytes: """ The raw bytes of the private key. Equivalent to private_bytes(Raw, Raw, NoEncryption()). """ - return self.private_bytes( - _serialization.Encoding.Raw, - _serialization.PrivateFormat.Raw, - _serialization.NoEncryption(), - ) + + +if hasattr(rust_openssl, "x448"): + Ed448PrivateKey.register(rust_openssl.ed448.Ed448PrivateKey) diff --git a/src/rust/src/backend/ed448.rs b/src/rust/src/backend/ed448.rs new file mode 100644 index 000000000000..c0c7d0c6aa74 --- /dev/null +++ b/src/rust/src/backend/ed448.rs @@ -0,0 +1,179 @@ +// 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::backend::utils; +use crate::buf::CffiBuf; +use crate::error::{CryptographyError, CryptographyResult}; +use foreign_types_shared::ForeignTypeRef; + +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.ed448")] +struct Ed448PrivateKey { + pkey: openssl::pkey::PKey, +} + +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.ed448")] +struct Ed448PublicKey { + pkey: openssl::pkey::PKey, +} + +#[pyo3::prelude::pyfunction] +fn generate_key() -> CryptographyResult { + Ok(Ed448PrivateKey { + pkey: openssl::pkey::PKey::generate_ed448()?, + }) +} + +#[pyo3::prelude::pyfunction] +fn private_key_from_ptr(ptr: usize) -> Ed448PrivateKey { + let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; + Ed448PrivateKey { + pkey: pkey.to_owned(), + } +} + +#[pyo3::prelude::pyfunction] +fn public_key_from_ptr(ptr: usize) -> Ed448PublicKey { + let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; + Ed448PublicKey { + pkey: pkey.to_owned(), + } +} + +#[pyo3::prelude::pyfunction] +fn from_private_bytes(data: CffiBuf<'_>) -> pyo3::PyResult { + let pkey = + openssl::pkey::PKey::private_key_from_raw_bytes(data.as_bytes(), openssl::pkey::Id::ED448) + .map_err(|_| { + pyo3::exceptions::PyValueError::new_err("An Ed448 private key is 56 bytes long") + })?; + Ok(Ed448PrivateKey { pkey }) +} + +#[pyo3::prelude::pyfunction] +fn from_public_bytes(data: &[u8]) -> pyo3::PyResult { + let pkey = openssl::pkey::PKey::public_key_from_raw_bytes(data, openssl::pkey::Id::ED448) + .map_err(|_| { + pyo3::exceptions::PyValueError::new_err("An Ed448 public key is 57 bytes long") + })?; + Ok(Ed448PublicKey { pkey }) +} + +#[pyo3::prelude::pymethods] +impl Ed448PrivateKey { + fn sign<'p>( + &self, + py: pyo3::Python<'p>, + data: &[u8], + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let mut signer = openssl::sign::Signer::new_without_digest(&self.pkey)?; + Ok(pyo3::types::PyBytes::new_with(py, signer.len()?, |b| { + let n = signer + .sign_oneshot(b, data) + .map_err(CryptographyError::from)?; + assert_eq!(n, b.len()); + Ok(()) + })?) + } + + fn public_key(&self) -> CryptographyResult { + let raw_bytes = self.pkey.raw_public_key()?; + Ok(Ed448PublicKey { + pkey: openssl::pkey::PKey::public_key_from_raw_bytes( + &raw_bytes, + openssl::pkey::Id::ED448, + )?, + }) + } + + fn private_bytes_raw<'p>( + &self, + py: pyo3::Python<'p>, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let raw_bytes = self.pkey.raw_private_key()?; + Ok(pyo3::types::PyBytes::new(py, &raw_bytes)) + } + + fn private_bytes<'p>( + slf: &pyo3::PyCell, + py: pyo3::Python<'p>, + encoding: &pyo3::PyAny, + format: &pyo3::PyAny, + encryption_algorithm: &pyo3::PyAny, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + utils::pkey_private_bytes( + py, + &*slf, + &slf.borrow().pkey, + encoding, + format, + encryption_algorithm, + true, + ) + } +} + +#[pyo3::prelude::pymethods] +impl Ed448PublicKey { + fn verify( + &self, + py: pyo3::Python<'_>, + signature: &[u8], + data: &[u8], + ) -> CryptographyResult<()> { + let valid = openssl::sign::Verifier::new_without_digest(&self.pkey)? + .verify_oneshot(signature, data)?; + + if !valid { + return Err(CryptographyError::from(pyo3::PyErr::from_value( + py.import("cryptography.exceptions")? + .call_method1("InvalidSignature", ())?, + ))); + } + + Ok(()) + } + + fn public_bytes_raw<'p>( + &self, + py: pyo3::Python<'p>, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let raw_bytes = self.pkey.raw_public_key()?; + Ok(pyo3::types::PyBytes::new(py, &raw_bytes)) + } + + fn public_bytes<'p>( + slf: &pyo3::PyCell, + py: pyo3::Python<'p>, + encoding: &pyo3::PyAny, + format: &pyo3::PyAny, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + utils::pkey_public_bytes(py, &*slf, &slf.borrow().pkey, encoding, format, true) + } + + fn __richcmp__( + &self, + other: pyo3::PyRef<'_, Ed448PublicKey>, + op: pyo3::basic::CompareOp, + ) -> pyo3::PyResult { + match op { + pyo3::basic::CompareOp::Eq => Ok(self.pkey.public_eq(&other.pkey)), + pyo3::basic::CompareOp::Ne => Ok(!self.pkey.public_eq(&other.pkey)), + _ => Err(pyo3::exceptions::PyTypeError::new_err("Cannot be ordered")), + } + } +} + +pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let m = pyo3::prelude::PyModule::new(py, "ed448")?; + m.add_wrapped(pyo3::wrap_pyfunction!(generate_key))?; + m.add_wrapped(pyo3::wrap_pyfunction!(private_key_from_ptr))?; + m.add_wrapped(pyo3::wrap_pyfunction!(public_key_from_ptr))?; + m.add_wrapped(pyo3::wrap_pyfunction!(from_private_bytes))?; + m.add_wrapped(pyo3::wrap_pyfunction!(from_public_bytes))?; + + m.add_class::()?; + m.add_class::()?; + + Ok(m) +} diff --git a/src/rust/src/backend/mod.rs b/src/rust/src/backend/mod.rs index 95aa08a6e2c3..d2d8cd478548 100644 --- a/src/rust/src/backend/mod.rs +++ b/src/rust/src/backend/mod.rs @@ -4,6 +4,8 @@ #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] pub(crate) mod ed25519; +#[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] +pub(crate) mod ed448; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] pub(crate) mod utils; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] @@ -14,6 +16,8 @@ pub(crate) mod x448; pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] module.add_submodule(ed25519::create_module(module.py())?)?; + #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] + module.add_submodule(ed448::create_module(module.py())?)?; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] module.add_submodule(x25519::create_module(module.py())?)?; diff --git a/tests/hazmat/primitives/test_ed448.py b/tests/hazmat/primitives/test_ed448.py index 5658b2b00821..e88d3dce2ccc 100644 --- a/tests/hazmat/primitives/test_ed448.py +++ b/tests/hazmat/primitives/test_ed448.py @@ -278,3 +278,6 @@ def test_public_key_equality(backend): assert key1 == key2 assert key1 != key3 assert key1 != object() + + with pytest.raises(TypeError): + key1 < key2 # type: ignore[operator] From ec7dbc4ee7e8c3ed9da71783b1f90d3904ec97d7 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Tue, 11 Apr 2023 00:17:11 +0000 Subject: [PATCH 099/316] Bump BoringSSL and/or OpenSSL in CI (#8706) Co-authored-by: pyca-boringbot[bot] --- .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 ac4c512496bb..ff830b85c935 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,8 +42,8 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 08, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "44a389a7fce31013b5953038d4231f33cbf2ba9d"}} + # Latest commit on the BoringSSL master branch, as of Apr 11, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "0c069cbf33d6a682e97a12c74284901a9bcd66b9"}} # Latest commit on the OpenSSL master branch, as of Apr 07, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "f309b3f6087db6c83126f8f227f1fc4984cf24b1"}} timeout-minutes: 15 From edf5bd5184cdb7c0df0eac5180bfa0818f62f517 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 11 Apr 2023 00:41:16 -0400 Subject: [PATCH 100/316] Remove unused parameter (#8707) --- src/cryptography/hazmat/backends/openssl/backend.py | 9 ++------- tests/hazmat/backends/test_openssl.py | 10 ---------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 256f3a1c1645..71215e6b4c24 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -422,20 +422,15 @@ def _bn_to_int(self, bn) -> int: val = int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big") return val - def _int_to_bn(self, num: int, bn=None): + def _int_to_bn(self, num: int): """ Converts a python integer to a BIGNUM. The returned BIGNUM will not be garbage collected (to support adding them to structs that take ownership of the object). Be sure to register it for GC if it will be discarded after use. """ - assert bn is None or bn != self._ffi.NULL - - if bn is None: - bn = self._ffi.NULL - binary = num.to_bytes(int(num.bit_length() / 8.0 + 1), "big") - bn_ptr = self._lib.BN_bin2bn(binary, len(binary), bn) + bn_ptr = self._lib.BN_bin2bn(binary, len(binary), self._ffi.NULL) self.openssl_assert(bn_ptr != self._ffi.NULL) return bn_ptr diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 572431ebbd4a..27a0b95286ce 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -161,16 +161,6 @@ def test_int_to_bn(self): assert bn assert backend._bn_to_int(bn) == value - def test_int_to_bn_inplace(self): - value = (2**4242) - 4242 - bn_ptr = backend._lib.BN_new() - assert bn_ptr != backend._ffi.NULL - bn_ptr = backend._ffi.gc(bn_ptr, backend._lib.BN_free) - bn = backend._int_to_bn(value, bn_ptr) - - assert bn == bn_ptr - assert backend._bn_to_int(bn_ptr) == value - def test_bn_to_int(self): bn = backend._int_to_bn(0) assert backend._bn_to_int(bn) == 0 From e9bf608d8c31d44c3f38f4c3d87008934b085baf Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 00:16:38 +0000 Subject: [PATCH 101/316] Bump BoringSSL and/or OpenSSL in CI (#8712) Co-authored-by: pyca-boringbot[bot] --- .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 ff830b85c935..29a80d797a96 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,10 +42,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 11, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "0c069cbf33d6a682e97a12c74284901a9bcd66b9"}} - # Latest commit on the OpenSSL master branch, as of Apr 07, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "f309b3f6087db6c83126f8f227f1fc4984cf24b1"}} + # Latest commit on the BoringSSL master branch, as of Apr 12, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "7b9b9baa95449d49019f7ce45b94963f8763005f"}} + # Latest commit on the OpenSSL master branch, as of Apr 12, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "dfb8e185134df90fd3f21fb6ec625e7c295fdcea"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.0 From 58ac802727e96144503b5ed5480e2cfb2c83b6b7 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 11 Apr 2023 20:19:48 -0400 Subject: [PATCH 102/316] Use pyo3::intern! comprehensively (#8711) --- src/rust/src/asn1.rs | 16 +++- src/rust/src/backend/ed25519.rs | 4 +- src/rust/src/backend/ed448.rs | 4 +- src/rust/src/backend/utils.rs | 10 ++- src/rust/src/buf.rs | 4 +- src/rust/src/error.rs | 2 +- src/rust/src/oid.rs | 4 +- src/rust/src/pkcs7.rs | 15 +++- src/rust/src/x509/certificate.rs | 80 ++++++++++++-------- src/rust/src/x509/common.rs | 86 ++++++++++++--------- src/rust/src/x509/crl.rs | 20 ++--- src/rust/src/x509/csr.rs | 55 ++++++++------ src/rust/src/x509/extensions.rs | 5 +- src/rust/src/x509/ocsp.rs | 6 +- src/rust/src/x509/ocsp_req.rs | 22 ++++-- src/rust/src/x509/ocsp_resp.rs | 40 ++++++---- src/rust/src/x509/sct.rs | 28 +++++-- src/rust/src/x509/sign.rs | 126 ++++++++++++++++++++++--------- 18 files changed, 337 insertions(+), 190 deletions(-) diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 833a72031e16..53981ddac6e8 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -60,7 +60,7 @@ pub(crate) fn big_byte_slice_to_py_int<'p>( ) -> pyo3::PyResult<&'p pyo3::PyAny> { let int_type = py.get_type::(); let kwargs = [("signed", true)].into_py_dict(py); - int_type.call_method("from_bytes", (v, "big"), Some(kwargs)) + int_type.call_method(pyo3::intern!(py, "from_bytes"), (v, "big"), Some(kwargs)) } #[pyo3::prelude::pyfunction] @@ -91,8 +91,13 @@ pub(crate) fn py_uint_to_big_endian_bytes<'p>( // 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() + let n = v + .call_method0(pyo3::intern!(py, "bit_length"))? + .extract::()? + / 8 + + 1; + v.call_method1(pyo3::intern!(py, "to_bytes"), (n, "big"))? + .extract() } pub(crate) fn encode_der_data<'p>( @@ -102,7 +107,10 @@ pub(crate) fn encode_der_data<'p>( encoding: &'p pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { let encoding_class = py - .import("cryptography.hazmat.primitives.serialization")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization" + ))? .getattr(pyo3::intern!(py, "Encoding"))?; if encoding.is(encoding_class.getattr(pyo3::intern!(py, "DER"))?) { diff --git a/src/rust/src/backend/ed25519.rs b/src/rust/src/backend/ed25519.rs index a8d10c880e4c..09ed9ac10eff 100644 --- a/src/rust/src/backend/ed25519.rs +++ b/src/rust/src/backend/ed25519.rs @@ -128,8 +128,8 @@ impl Ed25519PublicKey { if !valid { return Err(CryptographyError::from(pyo3::PyErr::from_value( - py.import("cryptography.exceptions")? - .call_method1("InvalidSignature", ())?, + py.import(pyo3::intern!(py, "cryptography.exceptions"))? + .call_method1(pyo3::intern!(py, "InvalidSignature"), ())?, ))); } diff --git a/src/rust/src/backend/ed448.rs b/src/rust/src/backend/ed448.rs index c0c7d0c6aa74..db17a7062bfe 100644 --- a/src/rust/src/backend/ed448.rs +++ b/src/rust/src/backend/ed448.rs @@ -126,8 +126,8 @@ impl Ed448PublicKey { if !valid { return Err(CryptographyError::from(pyo3::PyErr::from_value( - py.import("cryptography.exceptions")? - .call_method1("InvalidSignature", ())?, + py.import(pyo3::intern!(py, "cryptography.exceptions"))? + .call_method1(pyo3::intern!(py, "InvalidSignature"), ())?, ))); } diff --git a/src/rust/src/backend/utils.rs b/src/rust/src/backend/utils.rs index 6b41a6548008..25b7a5b9f87e 100644 --- a/src/rust/src/backend/utils.rs +++ b/src/rust/src/backend/utils.rs @@ -13,7 +13,10 @@ pub(crate) fn pkey_private_bytes<'p>( encryption_algorithm: &pyo3::PyAny, openssh_allowed: bool, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - let serialization_mod = py.import("cryptography.hazmat.primitives.serialization")?; + let serialization_mod = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization" + ))?; let encoding_class: &pyo3::types::PyType = serialization_mod .getattr(pyo3::intern!(py, "Encoding"))? .extract()?; @@ -141,7 +144,10 @@ pub(crate) fn pkey_public_bytes<'p>( format: &pyo3::PyAny, openssh_allowed: bool, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - let serialization_mod = py.import("cryptography.hazmat.primitives.serialization")?; + let serialization_mod = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization" + ))?; let encoding_class: &pyo3::types::PyType = serialization_mod .getattr(pyo3::intern!(py, "Encoding"))? .extract()?; diff --git a/src/rust/src/buf.rs b/src/rust/src/buf.rs index b45e1b5c342e..b7afcf047da4 100644 --- a/src/rust/src/buf.rs +++ b/src/rust/src/buf.rs @@ -21,8 +21,8 @@ impl<'a> pyo3::conversion::FromPyObject<'a> for CffiBuf<'a> { let py = pyobj.py(); let (bufobj, ptrval): (&pyo3::PyAny, usize) = py - .import("cryptography.utils")? - .call_method1("_extract_buffer_length", (pyobj,))? + .import(pyo3::intern!(py, "cryptography.utils"))? + .call_method1(pyo3::intern!(py, "_extract_buffer_length"), (pyobj,))? .extract()?; let len = bufobj.len()?; diff --git a/src/rust/src/error.rs b/src/rust/src/error.rs index 1cabbb11a948..e484993cced7 100644 --- a/src/rust/src/error.rs +++ b/src/rust/src/error.rs @@ -64,7 +64,7 @@ impl From for pyo3::PyErr { CryptographyError::Py(py_error) => py_error, CryptographyError::OpenSSL(error_stack) => pyo3::Python::with_gil(|py| { let internal_error = py - .import("cryptography.exceptions") + .import(pyo3::intern!(py, "cryptography.exceptions")) .expect("Failed to import cryptography module") .getattr(pyo3::intern!(py, "InternalError")) .expect("Failed to get InternalError attribute"); diff --git a/src/rust/src/oid.rs b/src/rust/src/oid.rs index 23bdd7362dd0..f6dae6122bbf 100644 --- a/src/rust/src/oid.rs +++ b/src/rust/src/oid.rs @@ -31,9 +31,9 @@ impl ObjectIdentifier { py: pyo3::Python<'p>, ) -> pyo3::PyResult<&'p pyo3::PyAny> { let oid_names = py - .import("cryptography.hazmat._oid")? + .import(pyo3::intern!(py, "cryptography.hazmat._oid"))? .getattr(pyo3::intern!(py, "_OID_NAMES"))?; - oid_names.call_method1("get", (slf, "Unknown OID")) + oid_names.call_method1(pyo3::intern!(py, "get"), (slf, "Unknown OID")) } fn __deepcopy__(slf: pyo3::PyRef<'_, Self>, _memo: pyo3::PyObject) -> pyo3::PyRef<'_, Self> { diff --git a/src/rust/src/pkcs7.rs b/src/rust/src/pkcs7.rs index 360c767b36cd..bb516143425f 100644 --- a/src/rust/src/pkcs7.rs +++ b/src/rust/src/pkcs7.rs @@ -132,7 +132,10 @@ fn sign_and_serialize<'p>( options: &'p pyo3::types::PyList, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { let pkcs7_options = py - .import("cryptography.hazmat.primitives.serialization.pkcs7")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization.pkcs7" + ))? .getattr(pyo3::intern!(py, "PKCS7Options"))?; let raw_data: CffiBuf<'p> = builder.getattr(pyo3::intern!(py, "_data"))?.extract()?; @@ -293,7 +296,10 @@ fn sign_and_serialize<'p>( let ci_bytes = asn1::write_single(&content_info)?; let encoding_class = py - .import("cryptography.hazmat.primitives.serialization")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization" + ))? .getattr(pyo3::intern!(py, "Encoding"))?; if encoding.is(encoding_class.getattr(pyo3::intern!(py, "SMIME"))?) { @@ -303,7 +309,10 @@ fn sign_and_serialize<'p>( .collect::>() .join(","); let smime_encode = py - .import("cryptography.hazmat.primitives.serialization.pkcs7")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization.pkcs7" + ))? .getattr(pyo3::intern!(py, "_smime_encode"))?; Ok(smime_encode .call1((&*data_without_header, &*ci_bytes, mic_algs, text_mode))? diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 838fa1a1c2ee..6ccde6542cb3 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -122,7 +122,10 @@ impl Certificate { &asn1::write_single(&self.raw.borrow_value().tbs_cert.spki)?, ); Ok(py - .import("cryptography.hazmat.primitives.serialization")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization" + ))? .getattr(pyo3::intern!(py, "load_der_public_key"))? .call1((serialized,))?) } @@ -133,14 +136,14 @@ impl Certificate { algorithm: pyo3::PyObject, ) -> CryptographyResult<&'p pyo3::PyAny> { let hasher = py - .import("cryptography.hazmat.primitives.hashes")? + .import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))? .getattr(pyo3::intern!(py, "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,))?; - Ok(hasher.call_method0("finalize")?) + hasher.call_method1(pyo3::intern!(py, "update"), (serialized,))?; + Ok(hasher.call_method0(pyo3::intern!(py, "finalize"))?) } fn public_bytes<'p>( @@ -266,19 +269,20 @@ impl Certificate { py: pyo3::Python<'p>, ) -> Result<&'p pyo3::PyAny, CryptographyError> { let sig_oids_to_hash = py - .import("cryptography.hazmat._oid")? + .import(pyo3::intern!(py, "cryptography.hazmat._oid"))? .getattr(pyo3::intern!(py, "_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(CryptographyError::from(pyo3::PyErr::from_value( - py.import("cryptography.exceptions")?.call_method1( - "UnsupportedAlgorithm", - (format!( - "Signature algorithm OID: {} not recognized", - self.raw.borrow_value().signature_alg.oid - ),), - )?, + py.import(pyo3::intern!(py, "cryptography.exceptions"))? + .call_method1( + "UnsupportedAlgorithm", + (format!( + "Signature algorithm OID: {} not recognized", + self.raw.borrow_value().signature_alg.oid + ),), + )?, ))), } } @@ -290,7 +294,7 @@ impl Certificate { #[getter] fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; x509::parse_and_cache_extensions( py, &mut self.cached_extensions, @@ -349,7 +353,7 @@ impl Certificate { } fn cert_version(py: pyo3::Python<'_>, version: u8) -> Result<&pyo3::PyAny, CryptographyError> { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; match version { 0 => Ok(x509_module .getattr(pyo3::intern!(py, "Version"))? @@ -421,7 +425,7 @@ fn load_der_x509_certificate( fn warn_if_negative_serial(py: pyo3::Python<'_>, bytes: &'_ [u8]) -> pyo3::PyResult<()> { if bytes[0] & 0x80 != 0 { let cryptography_warning = py - .import("cryptography.utils")? + .import(pyo3::intern!(py, "cryptography.utils"))? .getattr(pyo3::intern!(py, "DeprecatedIn36"))?; pyo3::PyErr::warn( py, @@ -498,7 +502,10 @@ fn parse_display_text( let py_bytes = pyo3::types::PyBytes::new(py, o.as_utf16_be_bytes()); // TODO: do the string conversion in rust perhaps Ok(py_bytes - .call_method1("decode", ("utf_16_be",))? + .call_method1( + pyo3::intern!(py, "decode"), + (pyo3::intern!(py, "utf_16_be"),), + )? .to_object(py)) } } @@ -508,7 +515,7 @@ fn parse_user_notice( py: pyo3::Python<'_>, un: UserNotice<'_>, ) -> Result { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; let et = match un.explicit_text { Some(data) => parse_display_text(py, data)?, None => py.None(), @@ -521,13 +528,13 @@ fn parse_user_notice( numbers.append(big_byte_slice_to_py_int(py, num.as_bytes())?.to_object(py))?; } x509_module - .call_method1("NoticeReference", (org, numbers))? + .call_method1(pyo3::intern!(py, "NoticeReference"), (org, numbers))? .to_object(py) } None => py.None(), }; Ok(x509_module - .call_method1("UserNotice", (nr, et))? + .call_method1(pyo3::intern!(py, "UserNotice"), (nr, et))? .to_object(py)) } @@ -567,7 +574,7 @@ fn parse_policy_qualifiers<'a>( 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 x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; let certificate_policies = pyo3::types::PyList::empty(py); for policyinfo in cp { let pi_oid = oid_to_py_oid(py, &policyinfo.policy_identifier)?.to_object(py); @@ -578,7 +585,7 @@ fn parse_cp(py: pyo3::Python<'_>, ext_data: &[u8]) -> Result py.None(), }; let pi = x509_module - .call_method1("PolicyInformation", (pi_oid, py_pqis))? + .call_method1(pyo3::intern!(py, "PolicyInformation"), (pi_oid, py_pqis))? .to_object(py); certificate_policies.append(pi)?; } @@ -697,7 +704,7 @@ fn parse_distribution_point( Some(aci) => x509::parse_general_names(py, aci.unwrap_read())?, None => py.None(), }; - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; Ok(x509_module .getattr(pyo3::intern!(py, "DistributionPoint"))? .call1((full_name, relative_name, reasons, crl_issuer))? @@ -722,7 +729,7 @@ pub(crate) fn parse_distribution_point_reasons( reasons: Option<&asn1::BitString<'_>>, ) -> Result { let reason_bit_mapping = py - .import("cryptography.x509.extensions")? + .import(pyo3::intern!(py, "cryptography.x509.extensions"))? .getattr(pyo3::intern!(py, "_REASON_BIT_MAPPING"))?; Ok(match reasons { Some(bs) => { @@ -743,7 +750,7 @@ pub(crate) fn encode_distribution_point_reasons( py_reasons: &pyo3::PyAny, ) -> pyo3::PyResult { let reason_flag_mapping = py - .import("cryptography.x509.extensions")? + .import(pyo3::intern!(py, "cryptography.x509.extensions"))? .getattr(pyo3::intern!(py, "_CRLREASONFLAGS"))?; let mut bits = vec![0, 0]; @@ -779,7 +786,7 @@ pub(crate) fn parse_authority_key_identifier<'p>( py: pyo3::Python<'p>, ext_data: &[u8], ) -> Result<&'p pyo3::PyAny, CryptographyError> { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; let aki = asn1::parse_single::>(ext_data)?; let serial = match aki.authority_cert_serial_number { Some(biguint) => big_byte_slice_to_py_int(py, biguint.as_bytes())?.to_object(py), @@ -798,7 +805,7 @@ pub(crate) fn parse_access_descriptions( py: pyo3::Python<'_>, ext_data: &[u8], ) -> Result { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; let ads = pyo3::types::PyList::empty(py); let parsed = asn1::parse_single::>(ext_data)?; for access in parsed.unwrap_read().clone() { @@ -818,7 +825,7 @@ pub fn parse_cert_ext<'p>( oid: asn1::ObjectIdentifier, ext_data: &[u8], ) -> CryptographyResult> { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; match oid { oid::SUBJECT_ALTERNATIVE_NAME_OID => { let gn_seq = @@ -842,7 +849,7 @@ pub fn parse_cert_ext<'p>( } oid::TLS_FEATURE_OID => { let tls_feature_type_to_enum = py - .import("cryptography.x509.extensions")? + .import(pyo3::intern!(py, "cryptography.x509.extensions"))? .getattr(pyo3::intern!(py, "_TLS_FEATURE_TYPE_TO_ENUM"))?; let features = pyo3::types::PyList::empty(py); @@ -920,9 +927,10 @@ pub fn parse_cert_ext<'p>( } oid::CERTIFICATE_POLICIES_OID => { let cp = parse_cp(py, ext_data)?; - Ok(Some( - x509_module.call_method1("CertificatePolicies", (cp,))?, - )) + Ok(Some(x509_module.call_method1( + pyo3::intern!(py, "CertificatePolicies"), + (cp,), + )?)) } oid::POLICY_CONSTRAINTS_OID => { let pc = asn1::parse_single::(ext_data)?; @@ -1029,7 +1037,10 @@ fn create_x509_certificate( hash_algorithm: &pyo3::PyAny, ) -> CryptographyResult { let sigalg = x509::sign::compute_signature_algorithm(py, private_key, hash_algorithm)?; - let serialization_mod = py.import("cryptography.hazmat.primitives.serialization")?; + let serialization_mod = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization" + ))?; let der_encoding = serialization_mod .getattr(pyo3::intern!(py, "Encoding"))? .getattr(pyo3::intern!(py, "DER"))?; @@ -1039,7 +1050,10 @@ fn create_x509_certificate( let spki_bytes = builder .getattr(pyo3::intern!(py, "_public_key"))? - .call_method1("public_bytes", (der_encoding, spki_format))? + .call_method1( + pyo3::intern!(py, "public_bytes"), + (der_encoding, spki_format), + )? .extract::<&[u8]>()?; let py_serial = builder diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index a4ac9b3d4cd9..3d4aec39cc71 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -103,7 +103,7 @@ pub(crate) fn encode_name_entry<'p>( py_name_entry: &'p pyo3::PyAny, ) -> CryptographyResult> { let asn1_type = py - .import("cryptography.x509.name")? + .import(pyo3::intern!(py, "cryptography.x509.name"))? .getattr(pyo3::intern!(py, "_ASN1Type"))?; let attr_type = py_name_entry.getattr(pyo3::intern!(py, "_type"))?; @@ -120,7 +120,7 @@ pub(crate) fn encode_name_entry<'p>( }; py_name_entry .getattr(pyo3::intern!(py, "value"))? - .call_method1("encode", (encoding,))? + .call_method1(pyo3::intern!(py, "encode"), (encoding,))? .extract()? } else { py_name_entry @@ -228,7 +228,7 @@ pub(crate) fn encode_general_name<'a>( py: pyo3::Python<'a>, gn: &'a pyo3::PyAny, ) -> Result, CryptographyError> { - let gn_module = py.import("cryptography.x509.general_name")?; + let gn_module = py.import(pyo3::intern!(py, "cryptography.x509.general_name"))?; let gn_type = gn.get_type().as_ref(); let gn_value = gn.getattr(pyo3::intern!(py, "value"))?; if gn_type.is(gn_module.getattr(pyo3::intern!(py, "DNSName"))?) { @@ -258,7 +258,8 @@ pub(crate) fn encode_general_name<'a>( )) } else if gn_type.is(gn_module.getattr(pyo3::intern!(py, "IPAddress"))?) { Ok(GeneralName::IPAddress( - gn.call_method0("_packed")?.extract::<&[u8]>()?, + gn.call_method0(pyo3::intern!(py, "_packed"))? + .extract::<&[u8]>()?, )) } else if gn_type.is(gn_module.getattr(pyo3::intern!(py, "RegisteredID"))?) { let oid = py_oid_to_oid(gn_value)?; @@ -341,23 +342,23 @@ pub(crate) fn parse_name<'p>( py: pyo3::Python<'p>, name: &Name<'_>, ) -> Result<&'p pyo3::PyAny, CryptographyError> { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; let py_rdns = pyo3::types::PyList::empty(py); for rdn in name.unwrap_read().clone() { let py_rdn = parse_rdn(py, &rdn)?; py_rdns.append(py_rdn)?; } - Ok(x509_module.call_method1("Name", (py_rdns,))?) + Ok(x509_module.call_method1(pyo3::intern!(py, "Name"), (py_rdns,))?) } fn parse_name_attribute( py: pyo3::Python<'_>, attribute: AttributeTypeValue<'_>, ) -> Result { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; let oid = oid_to_py_oid(py, &attribute.type_id)?.to_object(py); let tag_enum = py - .import("cryptography.x509.name")? + .import(pyo3::intern!(py, "cryptography.x509.name"))? .getattr(pyo3::intern!(py, "_ASN1_TYPE_TO_ENUM"))?; let tag_val = attribute .value @@ -376,12 +377,12 @@ fn parse_name_attribute( // BMPString tag value Some(30) => { let py_bytes = pyo3::types::PyBytes::new(py, attribute.value.data()); - py_bytes.call_method1("decode", ("utf_16_be",))? + py_bytes.call_method1(pyo3::intern!(py, "decode"), ("utf_16_be",))? } // UniversalString Some(28) => { let py_bytes = pyo3::types::PyBytes::new(py, attribute.value.data()); - py_bytes.call_method1("decode", ("utf_32_be",))? + py_bytes.call_method1(pyo3::intern!(py, "decode"), ("utf_32_be",))? } _ => { let parsed = std::str::from_utf8(attribute.value.data()) @@ -391,7 +392,11 @@ fn parse_name_attribute( }; let kwargs = [("_validate", false)].into_py_dict(py); Ok(x509_module - .call_method("NameAttribute", (oid, py_data, py_tag), Some(kwargs))? + .call_method( + pyo3::intern!(py, "NameAttribute"), + (oid, py_data, py_tag), + Some(kwargs), + )? .to_object(py)) } @@ -399,14 +404,14 @@ pub(crate) fn parse_rdn<'a>( py: pyo3::Python<'_>, rdn: &asn1::SetOf<'a, AttributeTypeValue<'a>>, ) -> Result { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; let py_attrs = pyo3::types::PySet::empty(py)?; for attribute in rdn.clone() { let na = parse_name_attribute(py, attribute)?; py_attrs.add(na)?; } Ok(x509_module - .call_method1("RelativeDistinguishedName", (py_attrs,))? + .call_method1(pyo3::intern!(py, "RelativeDistinguishedName"), (py_attrs,))? .to_object(py)) } @@ -414,38 +419,43 @@ pub(crate) fn parse_general_name( py: pyo3::Python<'_>, gn: GeneralName<'_>, ) -> Result { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; let py_gn = match gn { GeneralName::OtherName(data) => { let oid = oid_to_py_oid(py, &data.type_id)?.to_object(py); x509_module - .call_method1("OtherName", (oid, data.value.full_data()))? + .call_method1( + pyo3::intern!(py, "OtherName"), + (oid, data.value.full_data()), + )? .to_object(py) } GeneralName::RFC822Name(data) => x509_module .getattr(pyo3::intern!(py, "RFC822Name"))? - .call_method1("_init_without_validation", (data.0,))? + .call_method1(pyo3::intern!(py, "_init_without_validation"), (data.0,))? .to_object(py), GeneralName::DNSName(data) => x509_module .getattr(pyo3::intern!(py, "DNSName"))? - .call_method1("_init_without_validation", (data.0,))? + .call_method1(pyo3::intern!(py, "_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,))? + .call_method1(pyo3::intern!(py, "DirectoryName"), (py_name,))? .to_object(py) } GeneralName::UniformResourceIdentifier(data) => x509_module .getattr(pyo3::intern!(py, "UniformResourceIdentifier"))? - .call_method1("_init_without_validation", (data.0,))? + .call_method1(pyo3::intern!(py, "_init_without_validation"), (data.0,))? .to_object(py), GeneralName::IPAddress(data) => { - let ip_module = py.import("ipaddress")?; + let ip_module = py.import(pyo3::intern!(py, "ipaddress"))?; if data.len() == 4 || data.len() == 16 { - let addr = ip_module.call_method1("ip_address", (data,))?.to_object(py); + let addr = ip_module + .call_method1(pyo3::intern!(py, "ip_address"), (data,))? + .to_object(py); x509_module - .call_method1("IPAddress", (addr,))? + .call_method1(pyo3::intern!(py, "IPAddress"), (addr,))? .to_object(py) } else { // if it's not an IPv4 or IPv6 we assume it's an IPNetwork and @@ -456,7 +466,7 @@ pub(crate) fn parse_general_name( GeneralName::RegisteredID(data) => { let oid = oid_to_py_oid(py, &data)?.to_object(py); x509_module - .call_method1("RegisteredID", (oid,))? + .call_method1(pyo3::intern!(py, "RegisteredID"), (oid,))? .to_object(py) } _ => { @@ -487,8 +497,8 @@ fn create_ip_network( py: pyo3::Python<'_>, data: &[u8], ) -> Result { - let ip_module = py.import("ipaddress")?; - let x509_module = py.import("cryptography.x509")?; + let ip_module = py.import(pyo3::intern!(py, "ipaddress"))?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; let prefix = match data.len() { 8 => { let num = u32::from_be_bytes(data[4..].try_into().unwrap()); @@ -512,9 +522,11 @@ fn create_ip_network( .extract::<&str>()?, prefix? ); - let addr = ip_module.call_method1("ip_network", (net,))?.to_object(py); + let addr = ip_module + .call_method1(pyo3::intern!(py, "ip_network"), (net,))? + .to_object(py); Ok(x509_module - .call_method1("IPAddress", (addr,))? + .call_method1(pyo3::intern!(py, "IPAddress"), (addr,))? .to_object(py)) } @@ -553,7 +565,7 @@ pub(crate) fn parse_and_cache_extensions< return Ok(cached.clone_ref(py)); } - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; let exts = pyo3::types::PyList::empty(py); let mut seen_oids = HashSet::new(); if let Some(raw_exts) = raw_exts { @@ -572,17 +584,21 @@ pub(crate) fn parse_and_cache_extensions< 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))?, + None => x509_module.call_method1( + pyo3::intern!(py, "UnrecognizedExtension"), + (oid_obj, raw_ext.extn_value), + )?, }; - let ext_obj = - x509_module.call_method1("Extension", (oid_obj, raw_ext.critical, extn_value))?; + let ext_obj = x509_module.call_method1( + pyo3::intern!(py, "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,))? + .call_method1(pyo3::intern!(py, "Extensions"), (exts,))? .to_object(py); *cached_extensions = Some(extensions.clone_ref(py)); Ok(extensions) @@ -601,7 +617,7 @@ pub(crate) fn encode_extensions< encode_ext: F, ) -> pyo3::PyResult>> { let unrecognized_extension_type: &pyo3::types::PyType = py - .import("cryptography.x509")? + .import(pyo3::intern!(py, "cryptography.x509"))? .getattr(pyo3::intern!(py, "UnrecognizedExtension"))? .extract()?; @@ -670,7 +686,7 @@ pub(crate) fn datetime_to_py<'p>( py: pyo3::Python<'p>, dt: &asn1::DateTime, ) -> pyo3::PyResult<&'p pyo3::PyAny> { - let datetime_module = py.import("datetime")?; + let datetime_module = py.import(pyo3::intern!(py, "datetime"))?; datetime_module .getattr(pyo3::intern!(py, "datetime"))? .call1(( diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index 50beb85ecda2..f5ab1b0c02da 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -24,7 +24,7 @@ fn load_der_x509_crl( let version = raw.borrow_value().tbs_cert_list.version.unwrap_or(1); if version != 1 { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; return Err(CryptographyError::from(pyo3::PyErr::from_value( x509_module .getattr(pyo3::intern!(py, "InvalidVersion"))? @@ -174,12 +174,14 @@ impl CertificateRevocationList { py: pyo3::Python<'p>, algorithm: pyo3::PyObject, ) -> pyo3::PyResult<&'p pyo3::PyAny> { - let hashes_mod = py.import("cryptography.hazmat.primitives.hashes")?; + let hashes_mod = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; let h = hashes_mod .getattr(pyo3::intern!(py, "Hash"))? .call1((algorithm,))?; - h.call_method1("update", (self.public_bytes_der()?.as_slice(),))?; - h.call_method0("finalize") + + let data = self.public_bytes_der()?; + h.call_method1(pyo3::intern!(py, "update"), (data.as_slice(),))?; + h.call_method0(pyo3::intern!(py, "finalize")) } #[getter] @@ -193,8 +195,8 @@ impl CertificateRevocationList { 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")?; + let oid_module = py.import(pyo3::intern!(py, "cryptography.hazmat._oid"))?; + let exceptions_module = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; match oid_module .getattr(pyo3::intern!(py, "_SIG_OIDS_TO_HASH"))? .get_item(oid) @@ -264,7 +266,7 @@ impl CertificateRevocationList { #[getter] fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; x509::parse_and_cache_extensions( py, &mut self.cached_extensions, @@ -579,7 +581,7 @@ pub(crate) fn parse_crl_reason_flags<'p>( py: pyo3::Python<'p>, reason: &CRLReason, ) -> CryptographyResult<&'p pyo3::PyAny> { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; let flag_name = match reason.value() { 0 => "unspecified", 1 => "key_compromise", @@ -610,7 +612,7 @@ pub fn parse_crl_entry_ext<'p>( oid: asn1::ObjectIdentifier, data: &[u8], ) -> CryptographyResult> { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; match oid { oid::CRL_REASON_OID => { let flags = parse_crl_reason_flags(py, &asn1::parse_single::(data)?)?; diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index d9eeb400ac66..2122018e069c 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -119,7 +119,10 @@ impl CertificateSigningRequest { &asn1::write_single(&self.raw.borrow_value().csr_info.spki)?, ); Ok(py - .import("cryptography.hazmat.primitives.serialization")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization" + ))? .getattr(pyo3::intern!(py, "load_der_public_key"))? .call1((serialized,))?) } @@ -152,19 +155,20 @@ impl CertificateSigningRequest { py: pyo3::Python<'p>, ) -> Result<&'p pyo3::PyAny, CryptographyError> { let sig_oids_to_hash = py - .import("cryptography.hazmat._oid")? + .import(pyo3::intern!(py, "cryptography.hazmat._oid"))? .getattr(pyo3::intern!(py, "_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(CryptographyError::from(pyo3::PyErr::from_value( - py.import("cryptography.exceptions")?.call_method1( - "UnsupportedAlgorithm", - (format!( - "Signature algorithm OID: {} not recognized", - self.raw.borrow_value().signature_alg.oid - ),), - )?, + py.import(pyo3::intern!(py, "cryptography.exceptions"))? + .call_method1( + "UnsupportedAlgorithm", + (format!( + "Signature algorithm OID: {} not recognized", + self.raw.borrow_value().signature_alg.oid + ),), + )?, ))), } } @@ -190,7 +194,7 @@ impl CertificateSigningRequest { oid: &pyo3::PyAny, ) -> pyo3::PyResult<&'p pyo3::PyAny> { let cryptography_warning = py - .import("cryptography.utils")? + .import(pyo3::intern!(py, "cryptography.utils"))? .getattr(pyo3::intern!(py, "DeprecatedIn36"))?; pyo3::PyErr::warn( py, @@ -225,10 +229,11 @@ impl CertificateSigningRequest { } } Err(pyo3::PyErr::from_value( - py.import("cryptography.x509")?.call_method1( - "AttributeNotFound", - (format!("No {} attribute was found", oid), oid), - )?, + py.import(pyo3::intern!(py, "cryptography.x509"))? + .call_method1( + "AttributeNotFound", + (format!("No {} attribute was found", oid), oid), + )?, )) } @@ -253,12 +258,12 @@ impl CertificateSigningRequest { )) })?; let pyattr = py - .import("cryptography.x509")? - .call_method1("Attribute", (oid, serialized, tag))?; + .import(pyo3::intern!(py, "cryptography.x509"))? + .call_method1(pyo3::intern!(py, "Attribute"), (oid, serialized, tag))?; pyattrs.append(pyattr)?; } - py.import("cryptography.x509")? - .call_method1("Attributes", (pyattrs,)) + py.import(pyo3::intern!(py, "cryptography.x509"))? + .call_method1(pyo3::intern!(py, "Attributes"), (pyattrs,)) } #[getter] @@ -313,7 +318,7 @@ fn load_der_x509_csr( let version = raw.borrow_value().csr_info.version; if version != 0 { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; return Err(CryptographyError::from(pyo3::PyErr::from_value( x509_module .getattr(pyo3::intern!(py, "InvalidVersion"))? @@ -335,7 +340,10 @@ fn create_x509_csr( hash_algorithm: &pyo3::PyAny, ) -> CryptographyResult { let sigalg = x509::sign::compute_signature_algorithm(py, private_key, hash_algorithm)?; - let serialization_mod = py.import("cryptography.hazmat.primitives.serialization")?; + let serialization_mod = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization" + ))?; let der_encoding = serialization_mod .getattr(pyo3::intern!(py, "Encoding"))? .getattr(pyo3::intern!(py, "DER"))?; @@ -344,8 +352,11 @@ fn create_x509_csr( .getattr(pyo3::intern!(py, "SubjectPublicKeyInfo"))?; let spki_bytes = private_key - .call_method0("public_key")? - .call_method1("public_bytes", (der_encoding, spki_format))? + .call_method0(pyo3::intern!(py, "public_key"))? + .call_method1( + pyo3::intern!(py, "public_bytes"), + (der_encoding, spki_format), + )? .extract::<&[u8]>()?; let mut attrs = vec![]; diff --git a/src/rust/src/x509/extensions.rs b/src/rust/src/x509/extensions.rs index 7f143d852679..84009b0c7c48 100644 --- a/src/rust/src/x509/extensions.rs +++ b/src/rust/src/x509/extensions.rs @@ -379,7 +379,10 @@ pub(crate) fn encode_extension( &oid::CRL_REASON_OID => { let value = ext .py() - .import("cryptography.hazmat.backends.openssl.decode_asn1")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.backends.openssl.decode_asn1" + ))? .getattr(pyo3::intern!(py, "_CRL_ENTRY_REASON_ENUM_TO_CODE"))? .get_item(ext.getattr(pyo3::intern!(py, "reason"))?)? .extract::()?; diff --git a/src/rust/src/x509/ocsp.rs b/src/rust/src/x509/ocsp.rs index 2b10291b8c1e..e3568ca9df8b 100644 --- a/src/rust/src/x509/ocsp.rs +++ b/src/rust/src/x509/ocsp.rs @@ -99,9 +99,9 @@ pub(crate) fn hash_data<'p>( data: &[u8], ) -> pyo3::PyResult<&'p [u8]> { let hash = py - .import("cryptography.hazmat.primitives.hashes")? + .import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))? .getattr(pyo3::intern!(py, "Hash"))? .call1((py_hash_alg,))?; - hash.call_method1("update", (data,))?; - hash.call_method0("finalize")?.extract() + hash.call_method1(pyo3::intern!(py, "update"), (data,))?; + hash.call_method0(pyo3::intern!(py, "finalize"))?.extract() } diff --git a/src/rust/src/x509/ocsp_req.rs b/src/rust/src/x509/ocsp_req.rs index 0eef4bccb2ef..afd939d478f4 100644 --- a/src/rust/src/x509/ocsp_req.rs +++ b/src/rust/src/x509/ocsp_req.rs @@ -84,11 +84,11 @@ impl OCSPRequest { ) -> Result<&'p pyo3::PyAny, CryptographyError> { let cert_id = self.cert_id(); - let hashes = py.import("cryptography.hazmat.primitives.hashes")?; + let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; match ocsp::OIDS_TO_HASH.get(&cert_id.hash_algorithm.oid) { Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), None => { - let exceptions = py.import("cryptography.exceptions")?; + let exceptions = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; Err(CryptographyError::from(pyo3::PyErr::from_value( exceptions .getattr(pyo3::intern!(py, "UnsupportedAlgorithm"))? @@ -112,7 +112,7 @@ impl OCSPRequest { #[getter] fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult { - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; x509::parse_and_cache_extensions( py, &mut self.cached_extensions, @@ -127,7 +127,9 @@ impl OCSPRequest { // the nonce. So we try parsing as a TLV and fall back to just using // the raw value. let nonce = asn1::parse_single::<&[u8]>(value).unwrap_or(value); - Ok(Some(x509_module.call_method1("OCSPNonce", (nonce,))?)) + Ok(Some( + x509_module.call_method1(pyo3::intern!(py, "OCSPNonce"), (nonce,))?, + )) } oid::ACCEPTABLE_RESPONSES_OID => { let oids = asn1::parse_single::< @@ -138,9 +140,10 @@ impl OCSPRequest { py_oids.append(oid_to_py_oid(py, &oid)?)?; } - Ok(Some( - x509_module.call_method1("OCSPAcceptableResponses", (py_oids,))?, - )) + Ok(Some(x509_module.call_method1( + pyo3::intern!(py, "OCSPAcceptableResponses"), + (py_oids,), + )?)) } _ => Ok(None), } @@ -154,7 +157,10 @@ impl OCSPRequest { encoding: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { let der = py - .import("cryptography.hazmat.primitives.serialization")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization" + ))? .getattr(pyo3::intern!(py, "Encoding"))? .getattr(pyo3::intern!(py, "DER"))?; if !encoding.is(der) { diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index 33eac6ed8bba..0b2cab5f0b07 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -132,7 +132,7 @@ impl OCSPResponse { assert_eq!(status, UNAUTHORIZED_RESPONSE); "UNAUTHORIZED" }; - py.import("cryptography.x509.ocsp")? + py.import(pyo3::intern!(py, "cryptography.x509.ocsp"))? .getattr(pyo3::intern!(py, "OCSPResponseStatus"))? .getattr(attr) } @@ -173,7 +173,7 @@ impl OCSPResponse { py: pyo3::Python<'p>, ) -> Result<&'p pyo3::PyAny, CryptographyError> { let sig_oids_to_hash = py - .import("cryptography.hazmat._oid")? + .import(pyo3::intern!(py, "cryptography.hazmat._oid"))? .getattr(pyo3::intern!(py, "_SIG_OIDS_TO_HASH"))?; let hash_alg = sig_oids_to_hash.get_item(self.signature_algorithm_oid(py)?); match hash_alg { @@ -184,8 +184,8 @@ impl OCSPResponse { self.requires_successful_response()?.signature_algorithm.oid ); Err(CryptographyError::from(pyo3::PyErr::from_value( - py.import("cryptography.exceptions")? - .call_method1("UnsupportedAlgorithm", (exc_messsage,))?, + py.import(pyo3::intern!(py, "cryptography.exceptions"))? + .call_method1(pyo3::intern!(py, "UnsupportedAlgorithm"), (exc_messsage,))?, ))) } } @@ -310,7 +310,7 @@ impl OCSPResponse { #[getter] fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult { self.requires_successful_response()?; - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; x509::parse_and_cache_extensions( py, &mut self.cached_extensions, @@ -334,7 +334,9 @@ impl OCSPResponse { // the nonce. So we try parsing as a TLV and fall back to just using // the raw value. let nonce = asn1::parse_single::<&[u8]>(ext_data).unwrap_or(ext_data); - Ok(Some(x509_module.call_method1("OCSPNonce", (nonce,))?)) + Ok(Some( + x509_module.call_method1(pyo3::intern!(py, "OCSPNonce"), (nonce,))?, + )) } _ => Ok(None), } @@ -354,7 +356,7 @@ impl OCSPResponse { .response .get() .single_response()?; - let x509_module = py.import("cryptography.x509")?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; x509::parse_and_cache_extensions( py, &mut self.cached_single_extensions, @@ -380,7 +382,10 @@ impl OCSPResponse { encoding: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { let der = py - .import("cryptography.hazmat.primitives.serialization")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization" + ))? .getattr(pyo3::intern!(py, "Encoding"))? .getattr(pyo3::intern!(py, "DER"))?; if !encoding.is(der) { @@ -522,7 +527,7 @@ impl SingleResponse<'_> { CertStatus::Revoked(_) => "REVOKED", CertStatus::Unknown(_) => "UNKNOWN", }; - py.import("cryptography.x509.ocsp")? + py.import(pyo3::intern!(py, "cryptography.x509.ocsp"))? .getattr(pyo3::intern!(py, "OCSPCertStatus"))? .getattr(attr) } @@ -531,11 +536,11 @@ impl SingleResponse<'_> { &self, py: pyo3::Python<'p>, ) -> Result<&'p pyo3::PyAny, CryptographyError> { - let hashes = py.import("cryptography.hazmat.primitives.hashes")?; + let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; match ocsp::OIDS_TO_HASH.get(&self.cert_id.hash_algorithm.oid) { Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), None => { - let exceptions = py.import("cryptography.exceptions")?; + let exceptions = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; Err(CryptographyError::from(pyo3::PyErr::from_value( exceptions .getattr(pyo3::intern!(py, "UnsupportedAlgorithm"))? @@ -616,7 +621,7 @@ fn create_ocsp_response( let borrowed_cert; let py_certs: Option>>; let response_bytes = if response_status == SUCCESSFUL_RESPONSE { - let ocsp_mod = py.import("cryptography.x509.ocsp")?; + let ocsp_mod = py.import(pyo3::intern!(py, "cryptography.x509.ocsp"))?; let py_single_resp = builder.getattr(pyo3::intern!(py, "_response"))?; py_cert = py_single_resp @@ -648,7 +653,10 @@ fn create_ocsp_response( .is_none() { let value = py - .import("cryptography.hazmat.backends.openssl.decode_asn1")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.backends.openssl.decode_asn1" + ))? .getattr(pyo3::intern!(py, "_CRL_ENTRY_REASON_ENUM_TO_CODE"))? .get_item(py_single_resp.getattr(pyo3::intern!(py, "_revocation_reason"))?)? .extract::()?; @@ -695,7 +703,7 @@ fn create_ocsp_response( .getattr(pyo3::intern!(py, "HASH"))?) { let sha1 = py - .import("cryptography.hazmat.primitives.hashes")? + .import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))? .getattr(pyo3::intern!(py, "SHA1"))? .call0()?; ResponderId::ByKey(ocsp::hash_data( @@ -739,8 +747,8 @@ fn create_ocsp_response( let signature = x509::sign::sign_data(py, private_key, hash_algorithm, &tbs_bytes)?; if !responder_cert - .call_method0("public_key")? - .eq(private_key.call_method0("public_key")?)? + .call_method0(pyo3::intern!(py, "public_key"))? + .eq(private_key.call_method0(pyo3::intern!(py, "public_key"))?)? { return Err(CryptographyError::from( pyo3::exceptions::PyValueError::new_err( diff --git a/src/rust/src/x509/sct.rs b/src/rust/src/x509/sct.rs index 35ae088c0b85..a13785bf3fb1 100644 --- a/src/rust/src/x509/sct.rs +++ b/src/rust/src/x509/sct.rs @@ -164,9 +164,12 @@ impl Sct { #[getter] fn version<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - py.import("cryptography.x509.certificate_transparency")? - .getattr(pyo3::intern!(py, "Version"))? - .getattr(pyo3::intern!(py, "v1")) + py.import(pyo3::intern!( + py, + "cryptography.x509.certificate_transparency" + ))? + .getattr(pyo3::intern!(py, "Version"))? + .getattr(pyo3::intern!(py, "v1")) } #[getter] @@ -177,10 +180,13 @@ impl Sct { #[getter] fn timestamp<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let datetime_class = py - .import("datetime")? + .import(pyo3::intern!(py, "datetime"))? .getattr(pyo3::intern!(py, "datetime"))?; datetime_class - .call_method1("utcfromtimestamp", (self.timestamp / 1000,))? + .call_method1( + pyo3::intern!(py, "utcfromtimestamp"), + (self.timestamp / 1000,), + )? .call_method( "replace", (), @@ -191,7 +197,10 @@ impl Sct { #[getter] fn entry_type<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let et_class = py - .import("cryptography.x509.certificate_transparency")? + .import(pyo3::intern!( + py, + "cryptography.x509.certificate_transparency" + ))? .getattr(pyo3::intern!(py, "LogEntryType"))?; let attr_name = match self.entry_type { LogEntryType::Certificate => "X509_CERTIFICATE", @@ -205,14 +214,17 @@ impl Sct { &self, py: pyo3::Python<'p>, ) -> pyo3::PyResult<&'p pyo3::PyAny> { - let hashes_mod = py.import("cryptography.hazmat.primitives.hashes")?; + let hashes_mod = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; hashes_mod.call_method0(self.hash_algorithm.to_attr()) } #[getter] fn signature_algorithm<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let sa_class = py - .import("cryptography.x509.certificate_transparency")? + .import(pyo3::intern!( + py, + "cryptography.x509.certificate_transparency" + ))? .getattr(pyo3::intern!(py, "SignatureAlgorithm"))?; sa_class.getattr(self.signature_algorithm.to_attr()) } diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index fb46c5c8fb1d..4be023bb2331 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -39,23 +39,38 @@ enum HashType { fn identify_key_type(py: pyo3::Python<'_>, private_key: &pyo3::PyAny) -> pyo3::PyResult { let rsa_private_key: &pyo3::types::PyType = py - .import("cryptography.hazmat.primitives.asymmetric.rsa")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.rsa" + ))? .getattr(pyo3::intern!(py, "RSAPrivateKey"))? .extract()?; let dsa_key_type: &pyo3::types::PyType = py - .import("cryptography.hazmat.primitives.asymmetric.dsa")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.dsa" + ))? .getattr(pyo3::intern!(py, "DSAPrivateKey"))? .extract()?; let ec_key_type: &pyo3::types::PyType = py - .import("cryptography.hazmat.primitives.asymmetric.ec")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.ec" + ))? .getattr(pyo3::intern!(py, "EllipticCurvePrivateKey"))? .extract()?; let ed25519_key_type: &pyo3::types::PyType = py - .import("cryptography.hazmat.primitives.asymmetric.ed25519")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.ed25519" + ))? .getattr(pyo3::intern!(py, "Ed25519PrivateKey"))? .extract()?; let ed448_key_type: &pyo3::types::PyType = py - .import("cryptography.hazmat.primitives.asymmetric.ed448")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.ed448" + ))? .getattr(pyo3::intern!(py, "Ed448PrivateKey"))? .extract()?; @@ -85,7 +100,7 @@ fn identify_hash_type( } let hash_algorithm_type: &pyo3::types::PyType = py - .import("cryptography.hazmat.primitives.hashes")? + .import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))? .getattr(pyo3::intern!(py, "HashAlgorithm"))? .extract()?; if !hash_algorithm.is_instance(hash_algorithm_type)? { @@ -107,13 +122,14 @@ fn identify_hash_type( "sha3-384" => Ok(HashType::Sha3_384), "sha3-512" => Ok(HashType::Sha3_512), name => Err(pyo3::PyErr::from_value( - py.import("cryptography.exceptions")?.call_method1( - "UnsupportedAlgorithm", - (format!( - "Hash algorithm {:?} not supported for signatures", - name - ),), - )?, + py.import(pyo3::intern!(py, "cryptography.exceptions"))? + .call_method1( + "UnsupportedAlgorithm", + (format!( + "Hash algorithm {:?} not supported for signatures", + name + ),), + )?, )), } } @@ -225,10 +241,11 @@ pub(crate) fn compute_signature_algorithm<'p>( KeyType::Dsa, HashType::Sha3_224 | HashType::Sha3_256 | HashType::Sha3_384 | HashType::Sha3_512, ) => Err(pyo3::PyErr::from_value( - py.import("cryptography.exceptions")?.call_method1( - "UnsupportedAlgorithm", - ("SHA3 hashes are not supported with DSA keys",), - )?, + py.import(pyo3::intern!(py, "cryptography.exceptions"))? + .call_method1( + "UnsupportedAlgorithm", + ("SHA3 hashes are not supported with DSA keys",), + )?, )), (_, HashType::None) => Err(pyo3::exceptions::PyTypeError::new_err( "Algorithm must be a registered hash algorithm, not None.", @@ -245,22 +262,32 @@ pub(crate) fn sign_data<'p>( let key_type = identify_key_type(py, private_key)?; let signature = match key_type { - KeyType::Ed25519 | KeyType::Ed448 => private_key.call_method1("sign", (data,))?, + KeyType::Ed25519 | KeyType::Ed448 => { + private_key.call_method1(pyo3::intern!(py, "sign"), (data,))? + } KeyType::Ec => { - let ec_mod = py.import("cryptography.hazmat.primitives.asymmetric.ec")?; + let ec_mod = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.ec" + ))?; let ecdsa = ec_mod .getattr(pyo3::intern!(py, "ECDSA"))? .call1((hash_algorithm,))?; - private_key.call_method1("sign", (data, ecdsa))? + private_key.call_method1(pyo3::intern!(py, "sign"), (data, ecdsa))? } KeyType::Rsa => { - let padding_mod = py.import("cryptography.hazmat.primitives.asymmetric.padding")?; + let padding_mod = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.padding" + ))?; let pkcs1v15 = padding_mod .getattr(pyo3::intern!(py, "PKCS1v15"))? .call0()?; - private_key.call_method1("sign", (data, pkcs1v15, hash_algorithm))? + private_key.call_method1(pyo3::intern!(py, "sign"), (data, pkcs1v15, hash_algorithm))? + } + KeyType::Dsa => { + private_key.call_method1(pyo3::intern!(py, "sign"), (data, hash_algorithm))? } - KeyType::Dsa => private_key.call_method1("sign", (data, hash_algorithm))?, }; signature.extract() } @@ -296,7 +323,7 @@ pub(crate) fn verify_signature_with_oid<'p>( )); } let sig_hash_name = py_hash_name_from_hash_type(sig_hash_type); - let hashes = py.import("cryptography.hazmat.primitives.hashes")?; + let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; let signature_hash = match sig_hash_name { Some(data) => hashes.getattr(data)?.call0()?, None => py.None().into_ref(py), @@ -304,25 +331,35 @@ pub(crate) fn verify_signature_with_oid<'p>( match key_type { KeyType::Ed25519 | KeyType::Ed448 => { - issuer_public_key.call_method1("verify", (signature, data))? + issuer_public_key.call_method1(pyo3::intern!(py, "verify"), (signature, data))? } KeyType::Ec => { - let ec_mod = py.import("cryptography.hazmat.primitives.asymmetric.ec")?; + let ec_mod = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.ec" + ))?; let ecdsa = ec_mod .getattr(pyo3::intern!(py, "ECDSA"))? .call1((signature_hash,))?; - issuer_public_key.call_method1("verify", (signature, data, ecdsa))? + issuer_public_key.call_method1(pyo3::intern!(py, "verify"), (signature, data, ecdsa))? } KeyType::Rsa => { - let padding_mod = py.import("cryptography.hazmat.primitives.asymmetric.padding")?; + let padding_mod = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.padding" + ))?; let pkcs1v15 = padding_mod .getattr(pyo3::intern!(py, "PKCS1v15"))? .call0()?; - issuer_public_key.call_method1("verify", (signature, data, pkcs1v15, signature_hash))? - } - KeyType::Dsa => { - issuer_public_key.call_method1("verify", (signature, data, signature_hash))? + issuer_public_key.call_method1( + pyo3::intern!(py, "verify"), + (signature, data, pkcs1v15, signature_hash), + )? } + KeyType::Dsa => issuer_public_key.call_method1( + pyo3::intern!(py, "verify"), + (signature, data, signature_hash), + )?, }; Ok(()) } @@ -332,23 +369,38 @@ pub(crate) fn identify_public_key_type( public_key: &pyo3::PyAny, ) -> pyo3::PyResult { let rsa_key_type: &pyo3::types::PyType = py - .import("cryptography.hazmat.primitives.asymmetric.rsa")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.rsa" + ))? .getattr(pyo3::intern!(py, "RSAPublicKey"))? .extract()?; let dsa_key_type: &pyo3::types::PyType = py - .import("cryptography.hazmat.primitives.asymmetric.dsa")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.dsa" + ))? .getattr(pyo3::intern!(py, "DSAPublicKey"))? .extract()?; let ec_key_type: &pyo3::types::PyType = py - .import("cryptography.hazmat.primitives.asymmetric.ec")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.ec" + ))? .getattr(pyo3::intern!(py, "EllipticCurvePublicKey"))? .extract()?; let ed25519_key_type: &pyo3::types::PyType = py - .import("cryptography.hazmat.primitives.asymmetric.ed25519")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.ed25519" + ))? .getattr(pyo3::intern!(py, "Ed25519PublicKey"))? .extract()?; let ed448_key_type: &pyo3::types::PyType = py - .import("cryptography.hazmat.primitives.asymmetric.ed448")? + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.ed448" + ))? .getattr(pyo3::intern!(py, "Ed448PublicKey"))? .extract()?; From a38b2bcfac0d61b995b5034e6b5f112b2cec428b Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 12 Apr 2023 08:20:24 -0400 Subject: [PATCH 103/316] Remove unused consts (#8713) --- src/cryptography/hazmat/primitives/asymmetric/ed25519.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/cryptography/hazmat/primitives/asymmetric/ed25519.py b/src/cryptography/hazmat/primitives/asymmetric/ed25519.py index 772e5de82362..f26e54d24ec5 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ed25519.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ed25519.py @@ -10,9 +10,6 @@ from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives import _serialization -_ED25519_KEY_SIZE = 32 -_ED25519_SIG_SIZE = 64 - class Ed25519PublicKey(metaclass=abc.ABCMeta): @classmethod From ce2951a1bed0e628720920e01b73ad3ff741f4ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 23:10:54 +0000 Subject: [PATCH 104/316] Bump rich from 13.3.3 to 13.3.4 (#8717) Bumps [rich](https://github.com/Textualize/rich) from 13.3.3 to 13.3.4. - [Release notes](https://github.com/Textualize/rich/releases) - [Changelog](https://github.com/Textualize/rich/blob/master/CHANGELOG.md) - [Commits](https://github.com/Textualize/rich/compare/v13.3.3...v13.3.4) --- updated-dependencies: - dependency-name: rich 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index ddb738150e4f..95d4c8e7f39f 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -131,7 +131,7 @@ requests-toolbelt==0.10.1 # via twine rfc3986==2.0.0 # via twine -rich==13.3.3 +rich==13.3.4 # via twine ruff==0.0.261 # via cryptography (pyproject.toml) From 35beedf25a073bf84434be6b816c8e93cb4ecd65 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 23:11:11 +0000 Subject: [PATCH 105/316] Bump packaging from 23.0 to 23.1 (#8716) Bumps [packaging](https://github.com/pypa/packaging) from 23.0 to 23.1. - [Release notes](https://github.com/pypa/packaging/releases) - [Changelog](https://github.com/pypa/packaging/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pypa/packaging/compare/23.0...23.1) --- updated-dependencies: - dependency-name: packaging 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 95d4c8e7f39f..9668353db5a3 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -73,7 +73,7 @@ mypy-extensions==1.0.0 # mypy nox==2022.11.21 # via cryptography (pyproject.toml) -packaging==23.0 +packaging==23.1 # via # black # build From 500fb88199175b196a89730d124a58f58666313c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 23:11:25 +0000 Subject: [PATCH 106/316] Bump actions/checkout from 3.5.0 to 3.5.1 (#8715) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.0 to 3.5.1. - [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/v3.5.0...v3.5.1) --- updated-dependencies: - dependency-name: actions/checkout 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/benchmark.yml | 4 ++-- .github/workflows/boring-open-version-bump.yml | 2 +- .github/workflows/ci.yml | 18 +++++++++--------- .github/workflows/wheel-builder.yml | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 325d4e81eb1a..fcc0acf06769 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -20,12 +20,12 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 15 steps: - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v3.5.1 timeout-minutes: 3 with: persist-credentials: false path: "cryptography-pr" - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v3.5.1 timeout-minutes: 3 with: repository: "pyca/cryptography" diff --git a/.github/workflows/boring-open-version-bump.yml b/.github/workflows/boring-open-version-bump.yml index 5e96a3e3ba8a..927b826bdec9 100644 --- a/.github/workflows/boring-open-version-bump.yml +++ b/.github/workflows/boring-open-version-bump.yml @@ -13,7 +13,7 @@ jobs: if: github.repository_owner == 'pyca' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v3.5.1 - id: check-sha-boring run: | SHA=$(git ls-remote https://boringssl.googlesource.com/boringssl refs/heads/master | cut -f1) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 29a80d797a96..7eb2e8d22a27 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,7 +48,7 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "dfb8e185134df90fd3f21fb6ec625e7c295fdcea"}} timeout-minutes: 15 steps: - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v3.5.1 timeout-minutes: 3 with: persist-credentials: false @@ -158,7 +158,7 @@ jobs: sed -i "s:ID=alpine:ID=NotpineForGHA:" /etc/os-release if: matrix.IMAGE.IMAGE == 'alpine:aarch64' - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v3.5.1 timeout-minutes: 3 with: persist-credentials: false @@ -210,7 +210,7 @@ jobs: name: "${{ matrix.PYTHON }} with Rust ${{ matrix.RUST }}" timeout-minutes: 15 steps: - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v3.5.1 timeout-minutes: 3 with: persist-credentials: false @@ -259,7 +259,7 @@ jobs: name: "Rust Coverage" timeout-minutes: 15 steps: - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v3.5.1 timeout-minutes: 3 with: persist-credentials: false @@ -369,7 +369,7 @@ jobs: RUNNER: {OS: [self-hosted, macos, ARM64, tart], ARCH: 'arm64'} timeout-minutes: 15 steps: - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v3.5.1 timeout-minutes: 3 with: persist-credentials: false @@ -433,7 +433,7 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests"} timeout-minutes: 15 steps: - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v3.5.1 timeout-minutes: 3 with: persist-credentials: false @@ -506,7 +506,7 @@ jobs: name: "Downstream tests for ${{ matrix.DOWNSTREAM }}" timeout-minutes: 15 steps: - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v3.5.1 timeout-minutes: 3 with: persist-credentials: false @@ -549,7 +549,7 @@ jobs: name: "linkcheck" timeout-minutes: 10 steps: - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v3.5.1 with: persist-credentials: false fetch-depth: 0 @@ -582,7 +582,7 @@ jobs: needs: [linux, distros, linux-rust, linux-rust-coverage, macos, windows, linux-downstream] if: ${{ always() }} steps: - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v3.5.1 timeout-minutes: 3 with: persist-credentials: false diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 62af5f7d8322..9bd56612b73a 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -27,7 +27,7 @@ jobs: runs-on: ubuntu-latest name: sdists steps: - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v3.5.1 with: # The tag to build or the tag received by the tag event ref: ${{ github.event.inputs.version || github.ref }} From 870bb7006c7c0b9c4c8c7e94f03fe992c85606d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Apr 2023 00:03:39 +0000 Subject: [PATCH 107/316] Bump actions/checkout from 3.5.0 to 3.5.1 in /.github/actions/wycheproof (#8714) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.0 to 3.5.1. - [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/v3.5.0...v3.5.1) --- updated-dependencies: - dependency-name: actions/checkout 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/actions/wycheproof/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/wycheproof/action.yml b/.github/actions/wycheproof/action.yml index a7f265e12f29..14ec46fdb57c 100644 --- a/.github/actions/wycheproof/action.yml +++ b/.github/actions/wycheproof/action.yml @@ -5,7 +5,7 @@ runs: using: "composite" steps: - - uses: actions/checkout@v3.5.0 + - uses: actions/checkout@v3.5.1 with: repository: "google/wycheproof" path: "wycheproof" From f0c37fb9c2e659ca213c98b1c7693c89daef85a6 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Thu, 13 Apr 2023 00:19:02 +0000 Subject: [PATCH 108/316] Bump BoringSSL and/or OpenSSL in CI (#8718) Co-authored-by: pyca-boringbot[bot] --- .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 7eb2e8d22a27..3c86cc4388ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,10 +42,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 12, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "7b9b9baa95449d49019f7ce45b94963f8763005f"}} - # Latest commit on the OpenSSL master branch, as of Apr 12, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "dfb8e185134df90fd3f21fb6ec625e7c295fdcea"}} + # Latest commit on the BoringSSL master branch, as of Apr 13, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "abfd5ebc87ddca0fab9fca067c9d7edbc355eae8"}} + # Latest commit on the OpenSSL master branch, as of Apr 13, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "40f4884990a1717755df366e2aa06d01a1affd63"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.1 From ed89e1219e7198e05c682e5a7db71fc70fa344a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Apr 2023 13:05:51 +0000 Subject: [PATCH 109/316] Bump actions/checkout from 3.5.1 to 3.5.2 (#8719) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.1 to 3.5.2. - [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/v3.5.1...v3.5.2) --- updated-dependencies: - dependency-name: actions/checkout 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/benchmark.yml | 4 ++-- .github/workflows/boring-open-version-bump.yml | 2 +- .github/workflows/ci.yml | 18 +++++++++--------- .github/workflows/wheel-builder.yml | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index fcc0acf06769..2353be18d900 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -20,12 +20,12 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 15 steps: - - uses: actions/checkout@v3.5.1 + - uses: actions/checkout@v3.5.2 timeout-minutes: 3 with: persist-credentials: false path: "cryptography-pr" - - uses: actions/checkout@v3.5.1 + - uses: actions/checkout@v3.5.2 timeout-minutes: 3 with: repository: "pyca/cryptography" diff --git a/.github/workflows/boring-open-version-bump.yml b/.github/workflows/boring-open-version-bump.yml index 927b826bdec9..c2625a51b801 100644 --- a/.github/workflows/boring-open-version-bump.yml +++ b/.github/workflows/boring-open-version-bump.yml @@ -13,7 +13,7 @@ jobs: if: github.repository_owner == 'pyca' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.5.1 + - uses: actions/checkout@v3.5.2 - id: check-sha-boring run: | SHA=$(git ls-remote https://boringssl.googlesource.com/boringssl refs/heads/master | cut -f1) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c86cc4388ac..c4e779915284 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,7 +48,7 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "40f4884990a1717755df366e2aa06d01a1affd63"}} timeout-minutes: 15 steps: - - uses: actions/checkout@v3.5.1 + - uses: actions/checkout@v3.5.2 timeout-minutes: 3 with: persist-credentials: false @@ -158,7 +158,7 @@ jobs: sed -i "s:ID=alpine:ID=NotpineForGHA:" /etc/os-release if: matrix.IMAGE.IMAGE == 'alpine:aarch64' - - uses: actions/checkout@v3.5.1 + - uses: actions/checkout@v3.5.2 timeout-minutes: 3 with: persist-credentials: false @@ -210,7 +210,7 @@ jobs: name: "${{ matrix.PYTHON }} with Rust ${{ matrix.RUST }}" timeout-minutes: 15 steps: - - uses: actions/checkout@v3.5.1 + - uses: actions/checkout@v3.5.2 timeout-minutes: 3 with: persist-credentials: false @@ -259,7 +259,7 @@ jobs: name: "Rust Coverage" timeout-minutes: 15 steps: - - uses: actions/checkout@v3.5.1 + - uses: actions/checkout@v3.5.2 timeout-minutes: 3 with: persist-credentials: false @@ -369,7 +369,7 @@ jobs: RUNNER: {OS: [self-hosted, macos, ARM64, tart], ARCH: 'arm64'} timeout-minutes: 15 steps: - - uses: actions/checkout@v3.5.1 + - uses: actions/checkout@v3.5.2 timeout-minutes: 3 with: persist-credentials: false @@ -433,7 +433,7 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests"} timeout-minutes: 15 steps: - - uses: actions/checkout@v3.5.1 + - uses: actions/checkout@v3.5.2 timeout-minutes: 3 with: persist-credentials: false @@ -506,7 +506,7 @@ jobs: name: "Downstream tests for ${{ matrix.DOWNSTREAM }}" timeout-minutes: 15 steps: - - uses: actions/checkout@v3.5.1 + - uses: actions/checkout@v3.5.2 timeout-minutes: 3 with: persist-credentials: false @@ -549,7 +549,7 @@ jobs: name: "linkcheck" timeout-minutes: 10 steps: - - uses: actions/checkout@v3.5.1 + - uses: actions/checkout@v3.5.2 with: persist-credentials: false fetch-depth: 0 @@ -582,7 +582,7 @@ jobs: needs: [linux, distros, linux-rust, linux-rust-coverage, macos, windows, linux-downstream] if: ${{ always() }} steps: - - uses: actions/checkout@v3.5.1 + - uses: actions/checkout@v3.5.2 timeout-minutes: 3 with: persist-credentials: false diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 9bd56612b73a..c5446fcee0bb 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -27,7 +27,7 @@ jobs: runs-on: ubuntu-latest name: sdists steps: - - uses: actions/checkout@v3.5.1 + - uses: actions/checkout@v3.5.2 with: # The tag to build or the tag received by the tag event ref: ${{ github.event.inputs.version || github.ref }} From 06fbca955fa0e370be863b157d55dd28e01b6fda Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Apr 2023 13:16:37 +0000 Subject: [PATCH 110/316] Bump actions/checkout from 3.5.1 to 3.5.2 in /.github/actions/wycheproof (#8720) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.1 to 3.5.2. - [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/v3.5.1...v3.5.2) --- updated-dependencies: - dependency-name: actions/checkout 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/actions/wycheproof/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/wycheproof/action.yml b/.github/actions/wycheproof/action.yml index 14ec46fdb57c..6ededc54b15d 100644 --- a/.github/actions/wycheproof/action.yml +++ b/.github/actions/wycheproof/action.yml @@ -5,7 +5,7 @@ runs: using: "composite" steps: - - uses: actions/checkout@v3.5.1 + - uses: actions/checkout@v3.5.2 with: repository: "google/wycheproof" path: "wycheproof" From 77f94f031d207ea4338c013f278fff1463802cf6 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Fri, 14 Apr 2023 08:24:28 +0800 Subject: [PATCH 111/316] Bump BoringSSL and/or OpenSSL in CI (#8721) Co-authored-by: pyca-boringbot[bot] --- .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 c4e779915284..573966225335 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,10 +42,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 13, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "abfd5ebc87ddca0fab9fca067c9d7edbc355eae8"}} - # Latest commit on the OpenSSL master branch, as of Apr 13, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "40f4884990a1717755df366e2aa06d01a1affd63"}} + # Latest commit on the BoringSSL master branch, as of Apr 14, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "298e6c2b9c97ca17ee8cf65d24819ec19420013c"}} + # Latest commit on the OpenSSL master branch, as of Apr 14, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "efbff4de3e259cee71a4e1bbd86b30ebd86bbdae"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 017c70454439caaafe2cb4f4b10b0c561f14f8c3 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 14 Apr 2023 19:29:11 +0800 Subject: [PATCH 112/316] re-add a binding for an upcoming pyopenssl release (#8724) --- src/_cffi_src/openssl/ssl.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/_cffi_src/openssl/ssl.py b/src/_cffi_src/openssl/ssl.py index 1b59e97ff083..c836be4f9f6d 100644 --- a/src/_cffi_src/openssl/ssl.py +++ b/src/_cffi_src/openssl/ssl.py @@ -254,6 +254,7 @@ unsigned int); X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *); +void SSL_CTX_set_cert_store(SSL_CTX *, X509_STORE *); int SSL_CTX_add_client_CA(SSL_CTX *, X509 *); void SSL_CTX_set_client_CA_list(SSL_CTX *, Cryptography_STACK_OF_X509_NAME *); From 746ce97a84e3bf519e80985c6729d9e1a38403e7 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 14 Apr 2023 07:30:49 -0400 Subject: [PATCH 113/316] Compare benchmarks against the target branch, not main (#8726) * Compare benchmarks against the target branch, not main * Update benchmark.yml --- .github/workflows/benchmark.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 2353be18d900..abc595c97d93 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -2,6 +2,7 @@ name: Benchmark on: pull_request: paths: + - '.github/workflows/benchmark.yml' - 'src/**' - 'tests/**' @@ -30,7 +31,7 @@ jobs: with: repository: "pyca/cryptography" path: "cryptography-main" - ref: "main" + ref: "${{ github.base_ref }}" - name: Setup python id: setup-python From 7f8d0dcdf44d95663f1f83fe182b3e092e52f6ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Apr 2023 13:09:43 +0000 Subject: [PATCH 114/316] Bump pyo3 from 0.18.2 to 0.18.3 in /src/rust (#8734) Bumps [pyo3](https://github.com/pyo3/pyo3) from 0.18.2 to 0.18.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.18.2...v0.18.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 | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 2cf3919ebc5a..c16a7fcecbdc 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -265,9 +265,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.18.2" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfb848f80438f926a9ebddf0a539ed6065434fd7aae03a89312a9821f81b8501" +checksum = "e3b1ac5b3731ba34fdaa9785f8d74d17448cd18f30cf19e0c7e7b1fdb5272109" dependencies = [ "cfg-if", "indoc", @@ -282,9 +282,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.18.2" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98a42e7f42e917ce6664c832d5eee481ad514c98250c49e0b03b20593e2c7ed0" +checksum = "9cb946f5ac61bb61a5014924910d936ebd2b23b705f7a4a3c40b05c720b079a3" dependencies = [ "once_cell", "target-lexicon", @@ -292,9 +292,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.18.2" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0707f0ab26826fe4ccd59b69106e9df5e12d097457c7b8f9c0fd1d2743eec4d" +checksum = "fd4d7c5337821916ea2a1d21d1092e8443cf34879e53a0ac653fbb98f44ff65c" dependencies = [ "libc", "pyo3-build-config", @@ -302,9 +302,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.18.2" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978d18e61465ecd389e1f235ff5a467146dc4e3c3968b90d274fe73a5dd4a438" +checksum = "a9d39c55dab3fc5a4b25bbd1ac10a2da452c4aca13bb450f22818a002e29648d" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -314,9 +314,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.18.2" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e0e1128f85ce3fca66e435e08aa2089a2689c1c48ce97803e13f63124058462" +checksum = "97daff08a4c48320587b5224cc98d609e3c27b6d437315bd40b605c98eeb5918" dependencies = [ "proc-macro2", "quote", From 9f1130623ec1197b27b58ef0cb40a1319f4ea5e0 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 14 Apr 2023 21:44:42 +0800 Subject: [PATCH 115/316] port 40.0.2 changelog (#8729) --- CHANGELOG.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9387ea6a9c0e..75cd3a49df57 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -18,6 +18,14 @@ Changelog proprietary Microsoft certificate extension. * Implemented support for equality checks on all asymmetric public key types. +.. _v40-0-2: + +40.0.2 - 2023-04-14 +~~~~~~~~~~~~~~~~~~~ + +* Fixed compilation when using LibreSSL 3.7.2. +* Added some functions to support an upcoming ``pyOpenSSL`` release. + .. _v40-0-1: 40.0.1 - 2023-03-24 From 71efa27c1745d83fce801b02a01e8817ef4f6a89 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 14 Apr 2023 21:45:52 +0800 Subject: [PATCH 116/316] separate linkcheck job from ci.yml (#8730) --- .github/workflows/ci.yml | 33 ----------------------- .github/workflows/linkcheck.yml | 46 +++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 33 deletions(-) create mode 100644 .github/workflows/linkcheck.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 573966225335..878431a99dbd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -543,39 +543,6 @@ jobs: shell: python - run: ./.github/downstream.d/${{ matrix.DOWNSTREAM }}.sh run - docs-linkcheck: - if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'pull_request' && contains(github.event.pull_request.title, 'linkcheck')) - runs-on: ubuntu-latest - name: "linkcheck" - timeout-minutes: 10 - steps: - - uses: actions/checkout@v3.5.2 - with: - persist-credentials: false - fetch-depth: 0 - - name: set mtimes for rust dirs - uses: ./.github/actions/mtime-fix - - name: Setup python - id: setup-python - uses: actions/setup-python@v4.5.0 - with: - python-version: 3.11 - - name: Cache rust and pip - uses: ./.github/actions/cache - timeout-minutes: 2 - with: - # This creates the same key as the docs job (as long as they have the same - # python version) - key: 3.11-${{ steps.setup-python.outputs.python-version }} - - run: python -m pip install -c ci-constraints-requirements.txt nox - - name: Build nox environment - run: | - nox -v --install-only -s docs-linkcheck - env: - CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - - name: linkcheck - run: nox --no-install -s docs-linkcheck -- --color=yes - all-green: # https://github.community/t/is-it-possible-to-require-all-github-actions-tasks-to-pass-without-enumerating-them/117957/4?u=graingert runs-on: ubuntu-latest diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml new file mode 100644 index 000000000000..02457ec7bf18 --- /dev/null +++ b/.github/workflows/linkcheck.yml @@ -0,0 +1,46 @@ +name: linkcheck +on: + pull_request: {} + push: + branches: + - main + +permissions: + contents: read + +env: + CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse + +jobs: + docs-linkcheck: + if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'pull_request' && contains(github.event.pull_request.title, 'linkcheck')) + runs-on: ubuntu-latest + name: "linkcheck" + timeout-minutes: 10 + steps: + - uses: actions/checkout@v3.5.2 + with: + persist-credentials: false + fetch-depth: 0 + - name: set mtimes for rust dirs + uses: ./.github/actions/mtime-fix + - name: Setup python + id: setup-python + uses: actions/setup-python@v4.5.0 + with: + python-version: 3.11 + - name: Cache rust and pip + uses: ./.github/actions/cache + timeout-minutes: 2 + with: + # This creates the same key as the docs job (as long as they have the same + # python version) + key: 3.11-${{ steps.setup-python.outputs.python-version }} + - run: python -m pip install -c ci-constraints-requirements.txt nox + - name: Build nox environment + run: | + nox -v --install-only -s docs-linkcheck + env: + CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} + - name: linkcheck + run: nox --no-install -s docs-linkcheck -- --color=yes \ No newline at end of file From c22b1d6fbe4c04ee1851208b782c0784cae3b648 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 14 Apr 2023 21:46:21 +0800 Subject: [PATCH 117/316] call it base instead of main (#8731) --- .github/workflows/benchmark.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index abc595c97d93..09745aa48ca8 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -30,7 +30,7 @@ jobs: timeout-minutes: 3 with: repository: "pyca/cryptography" - path: "cryptography-main" + path: "cryptography-base" ref: "${{ github.base_ref }}" - name: Setup python @@ -39,19 +39,19 @@ jobs: with: python-version: "3.11" - - name: Create virtualenv (main) + - name: Create virtualenv (base) run: | - python -m venv .venv-main - .venv-main/bin/pip install -v -c ./cryptography-main/ci-constraints-requirements.txt "./cryptography-main[test]" ./cryptography-main/vectors/ + python -m venv .venv-base + .venv-base/bin/pip install -v -c ./cryptography-base/ci-constraints-requirements.txt "./cryptography-base[test]" ./cryptography-base/vectors/ - name: Create virtualenv (PR) run: | python -m venv .venv-pr .venv-pr/bin/pip install -v -c ./cryptography-pr/ci-constraints-requirements.txt "./cryptography-pr[test]" ./cryptography-pr/vectors/ - - name: Run benchmarks (main) - run: .venv-main/bin/pytest --benchmark-enable --benchmark-only ./cryptography-pr/tests/bench/ --benchmark-json=bench-main.json + - name: Run benchmarks (base) + run: .venv-base/bin/pytest --benchmark-enable --benchmark-only ./cryptography-pr/tests/bench/ --benchmark-json=bench-base.json - name: Run benchmarks (PR) run: .venv-pr/bin/pytest --benchmark-enable --benchmark-only ./cryptography-pr/tests/bench/ --benchmark-json=bench-pr.json - name: Compare results - run: python ./cryptography-pr/.github/compare_benchmarks.py bench-main.json bench-pr.json | tee -a $GITHUB_STEP_SUMMARY + run: python ./cryptography-pr/.github/compare_benchmarks.py bench-base.json bench-pr.json | tee -a $GITHUB_STEP_SUMMARY From f2dbe6fb2afc23090ec443dfa9af2ff8d42a0a2f Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 14 Apr 2023 21:46:37 +0800 Subject: [PATCH 118/316] update cargo.toml's openssl-sys (#8732) the .lock is correct since it got updated by dependabot when it bumped to 0.9.85 for openssl, but the PR bumping this closed. The lock supersedes this, but this should be right! --- src/rust/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 1e188960257d..3175cd12ba27 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -14,7 +14,7 @@ asn1 = { version = "0.14.0", default-features = false } pem = "1.1" ouroboros = "0.15" openssl = "0.10.50" -openssl-sys = "0.9.84" +openssl-sys = "0.9.85" foreign-types-shared = "0.1" [build-dependencies] From 3b62a90c448aeed395a41639b41f32b42c6f05b8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Apr 2023 13:56:45 +0000 Subject: [PATCH 119/316] Bump dawidd6/action-download-artifact from 2.26.1 to 2.27.0 (#8735) Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 2.26.1 to 2.27.0. - [Release notes](https://github.com/dawidd6/action-download-artifact/releases) - [Commits](https://github.com/dawidd6/action-download-artifact/compare/7132ab516fba5f602fafae6fdd4822afa10db76f...246dbf436b23d7c49e21a7ab8204ca9ecd1fe615) --- updated-dependencies: - dependency-name: dawidd6/action-download-artifact 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/ci.yml | 4 ++-- .github/workflows/pypi-publish.yml | 2 +- .github/workflows/wheel-builder.yml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 878431a99dbd..cf3941e422cc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -394,7 +394,7 @@ jobs: timeout-minutes: 2 uses: ./.github/actions/wycheproof - - uses: dawidd6/action-download-artifact@7132ab516fba5f602fafae6fdd4822afa10db76f + - uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 with: repo: pyca/infra workflow: build-macos-openssl.yml @@ -453,7 +453,7 @@ jobs: key: ${{ matrix.PYTHON.NOXSESSION }}-${{ matrix.WINDOWS.ARCH }}-${{ steps.setup-python.outputs.python-version }} - run: python -m pip install -c ci-constraints-requirements.txt "nox" coverage[toml] - - uses: dawidd6/action-download-artifact@7132ab516fba5f602fafae6fdd4822afa10db76f + - uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 with: repo: pyca/infra workflow: build-windows-openssl.yml diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml index 172bb131a9b9..e873b579b58f 100644 --- a/.github/workflows/pypi-publish.yml +++ b/.github/workflows/pypi-publish.yml @@ -25,7 +25,7 @@ jobs: permissions: id-token: "write" steps: - - uses: dawidd6/action-download-artifact@7132ab516fba5f602fafae6fdd4822afa10db76f + - uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 with: path: dist/ run_id: ${{ github.event.inputs.run_id || github.event.workflow_run.id }} diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index c5446fcee0bb..83fe53d3aa4f 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -194,7 +194,7 @@ jobs: with: python-version: ${{ matrix.PYTHON.VERSION }} if: contains(matrix.PYTHON.VERSION, 'pypy') - - uses: dawidd6/action-download-artifact@7132ab516fba5f602fafae6fdd4822afa10db76f + - uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 with: repo: pyca/infra workflow: build-macos-openssl.yml @@ -273,7 +273,7 @@ jobs: toolchain: stable target: ${{ matrix.WINDOWS.RUST_TRIPLE }} - - uses: dawidd6/action-download-artifact@7132ab516fba5f602fafae6fdd4822afa10db76f + - uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 with: repo: pyca/infra workflow: build-windows-openssl.yml From dcff16cded0ed5ce5ef956fae7fbf6eb41e9b1e9 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Sat, 15 Apr 2023 00:18:02 +0000 Subject: [PATCH 120/316] Bump BoringSSL and/or OpenSSL in CI (#8736) Co-authored-by: pyca-boringbot[bot] --- .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 cf3941e422cc..706d50bb3315 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,10 +42,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 14, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "298e6c2b9c97ca17ee8cf65d24819ec19420013c"}} - # Latest commit on the OpenSSL master branch, as of Apr 14, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "efbff4de3e259cee71a4e1bbd86b30ebd86bbdae"}} + # Latest commit on the BoringSSL master branch, as of Apr 15, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "d3acd45456450f7e8091f0f56084bc2da93e48fe"}} + # Latest commit on the OpenSSL master branch, as of Apr 15, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "7eab7680ee61c64b2ae7acd9dd199ab6734f3d1f"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 0da9abfbe79a7a171e58c905b6621dc614d5e8ac Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 15 Apr 2023 08:49:31 +0800 Subject: [PATCH 121/316] we also need X509_STORE_up_ref for pyopenssl (#8737) --- src/_cffi_src/openssl/x509_vfy.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/_cffi_src/openssl/x509_vfy.py b/src/_cffi_src/openssl/x509_vfy.py index 0337afa3497d..f1ea8ee6af82 100644 --- a/src/_cffi_src/openssl/x509_vfy.py +++ b/src/_cffi_src/openssl/x509_vfy.py @@ -143,6 +143,7 @@ /* Included due to external consumer, see https://github.com/pyca/pyopenssl/issues/1031 */ int X509_STORE_set_purpose(X509_STORE *, int); +int X509_STORE_up_ref(X509_STORE *); void X509_STORE_free(X509_STORE *); /* X509_STORE_CTX */ From 45bddbfb192656e8e6819d060d2f060a24fffd54 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 15 Apr 2023 12:05:11 +0800 Subject: [PATCH 122/316] add support for aes256-gcm@openssh.com decryption for SSH keys (#8738) * add support for aes256-gcm@openssh.com decryption for SSH keys * review feedback * skip when bcrypt isn't present --- CHANGELOG.rst | 2 + docs/development/test-vectors.rst | 4 + .../hazmat/primitives/serialization/ssh.py | 108 ++++++++++++++---- tests/hazmat/primitives/test_ssh.py | 45 +++++++- .../asymmetric/OpenSSH/ed25519-aesgcm-psw.key | 8 ++ .../OpenSSH/ed25519-aesgcm-psw.key.pub | 1 + 6 files changed, 144 insertions(+), 24 deletions(-) create mode 100644 vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-aesgcm-psw.key create mode 100644 vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-aesgcm-psw.key.pub diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 75cd3a49df57..5a550584ef8e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,6 +17,8 @@ Changelog * Added support for the :class:`~cryptography.x509.MSCertificateTemplate` proprietary Microsoft certificate extension. * Implemented support for equality checks on all asymmetric public key types. +* Added support for ``aes256-gcm@openssh.com`` encrypted keys in + :func:`~cryptography.hazmat.primitives.serialization.load_ssh_private_key`. .. _v40-0-2: diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index b3a1c301da58..c042eb9bf331 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -803,6 +803,10 @@ Custom PKCS7 Test Vectors Custom OpenSSH Test Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +* ``ed25519-aesgcm-psw.key`` and ``ed25519-aesgcm-psw.key.pub`` generated by + exporting an Ed25519 key from ``1password 8`` with the password "password". + This key is encrypted using the ``aes256-gcm@openssh.com`` algorithm. + Generated by ``asymmetric/OpenSSH/gen.sh`` using command-line tools from OpenSSH_7.6p1 package. diff --git a/src/cryptography/hazmat/primitives/serialization/ssh.py b/src/cryptography/hazmat/primitives/serialization/ssh.py index 90261845143a..7725c83543e8 100644 --- a/src/cryptography/hazmat/primitives/serialization/ssh.py +++ b/src/cryptography/hazmat/primitives/serialization/ssh.py @@ -11,6 +11,7 @@ import typing import warnings from base64 import encodebytes as _base64_encode +from dataclasses import dataclass from cryptography import utils from cryptography.exceptions import UnsupportedAlgorithm @@ -23,7 +24,12 @@ rsa, ) from cryptography.hazmat.primitives.asymmetric import utils as asym_utils -from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives.ciphers import ( + AEADDecryptionContext, + Cipher, + algorithms, + modes, +) from cryptography.hazmat.primitives.serialization import ( Encoding, KeySerializationEncryption, @@ -78,18 +84,51 @@ def _bcrypt_kdf( # padding for max blocksize _PADDING = memoryview(bytearray(range(1, 1 + 16))) + +@dataclass +class _SSHCipher: + alg: typing.Type[algorithms.AES] + key_len: int + mode: typing.Union[ + typing.Type[modes.CTR], + typing.Type[modes.CBC], + typing.Type[modes.GCM], + ] + block_len: int + iv_len: int + tag_len: typing.Optional[int] + is_aead: bool + + # ciphers that are actually used in key wrapping -_SSH_CIPHERS: typing.Dict[ - bytes, - typing.Tuple[ - typing.Type[algorithms.AES], - int, - typing.Union[typing.Type[modes.CTR], typing.Type[modes.CBC]], - int, - ], -] = { - b"aes256-ctr": (algorithms.AES, 32, modes.CTR, 16), - b"aes256-cbc": (algorithms.AES, 32, modes.CBC, 16), +_SSH_CIPHERS: typing.Dict[bytes, _SSHCipher] = { + b"aes256-ctr": _SSHCipher( + alg=algorithms.AES, + key_len=32, + mode=modes.CTR, + block_len=16, + iv_len=16, + tag_len=None, + is_aead=False, + ), + b"aes256-cbc": _SSHCipher( + alg=algorithms.AES, + key_len=32, + mode=modes.CBC, + block_len=16, + iv_len=16, + tag_len=None, + is_aead=False, + ), + b"aes256-gcm@openssh.com": _SSHCipher( + alg=algorithms.AES, + key_len=32, + mode=modes.GCM, + block_len=16, + iv_len=12, + tag_len=16, + is_aead=True, + ), } # map local curve name to key type @@ -156,14 +195,19 @@ def _init_cipher( password: typing.Optional[bytes], salt: bytes, rounds: int, -) -> Cipher[typing.Union[modes.CBC, modes.CTR]]: +) -> Cipher[typing.Union[modes.CBC, modes.CTR, modes.GCM]]: """Generate key + iv and return cipher.""" if not password: raise ValueError("Key is password-protected.") - algo, key_len, mode, iv_len = _SSH_CIPHERS[ciphername] - seed = _bcrypt_kdf(password, salt, key_len + iv_len, rounds, True) - return Cipher(algo(seed[:key_len]), mode(seed[key_len:])) + ciph = _SSH_CIPHERS[ciphername] + seed = _bcrypt_kdf( + password, salt, ciph.key_len + ciph.iv_len, rounds, True + ) + return Cipher( + ciph.alg(seed[: ciph.key_len]), + ciph.mode(seed[ciph.key_len :]), + ) def _get_u32(data: memoryview) -> typing.Tuple[int, memoryview]: @@ -604,10 +648,6 @@ def load_ssh_private_key( pubfields, pubdata = kformat.get_public(pubdata) _check_empty(pubdata) - # load secret data - edata, data = _get_sshstr(data) - _check_empty(data) - if (ciphername, kdfname) != (_NONE, _NONE): ciphername_bytes = ciphername.tobytes() if ciphername_bytes not in _SSH_CIPHERS: @@ -616,14 +656,36 @@ def load_ssh_private_key( ) if kdfname != _BCRYPT: raise UnsupportedAlgorithm(f"Unsupported KDF: {kdfname!r}") - blklen = _SSH_CIPHERS[ciphername_bytes][3] + blklen = _SSH_CIPHERS[ciphername_bytes].block_len + tag_len = _SSH_CIPHERS[ciphername_bytes].tag_len + # load secret data + edata, data = _get_sshstr(data) + # see https://bugzilla.mindrot.org/show_bug.cgi?id=3553 for + # information about how OpenSSH handles AEAD tags + if _SSH_CIPHERS[ciphername_bytes].is_aead: + tag = bytes(data) + if len(tag) != tag_len: + raise ValueError("Corrupt data: invalid tag length for cipher") + else: + _check_empty(data) _check_block_size(edata, blklen) salt, kbuf = _get_sshstr(kdfoptions) rounds, kbuf = _get_u32(kbuf) _check_empty(kbuf) ciph = _init_cipher(ciphername_bytes, password, salt.tobytes(), rounds) - edata = memoryview(ciph.decryptor().update(edata)) + dec = ciph.decryptor() + edata = memoryview(dec.update(edata)) + if _SSH_CIPHERS[ciphername_bytes].is_aead: + assert isinstance(dec, AEADDecryptionContext) + _check_empty(dec.finalize_with_tag(tag)) + else: + # _check_block_size requires data to be a full block so there + # should be no output from finalize + _check_empty(dec.finalize()) else: + # load secret data + edata, data = _get_sshstr(data) + _check_empty(data) blklen = 8 _check_block_size(edata, blklen) ck1, edata = _get_u32(edata) @@ -676,7 +738,7 @@ def _serialize_ssh_private_key( f_kdfoptions = _FragList() if password: ciphername = _DEFAULT_CIPHER - blklen = _SSH_CIPHERS[ciphername][3] + blklen = _SSH_CIPHERS[ciphername].block_len kdfname = _BCRYPT rounds = _DEFAULT_ROUNDS if ( diff --git a/tests/hazmat/primitives/test_ssh.py b/tests/hazmat/primitives/test_ssh.py index c9f995b1f0c6..e5c58062d075 100644 --- a/tests/hazmat/primitives/test_ssh.py +++ b/tests/hazmat/primitives/test_ssh.py @@ -10,7 +10,7 @@ import pytest from cryptography import utils -from cryptography.exceptions import InvalidSignature +from cryptography.exceptions import InvalidSignature, InvalidTag from cryptography.hazmat.primitives.asymmetric import ( dsa, ec, @@ -153,6 +153,7 @@ def run_partial_pubkey(self, pubdata, backend): ("ecdsa-psw.key",), ("ed25519-nopsw.key",), ("ed25519-psw.key",), + ("ed25519-aesgcm-psw.key",), ], ) def test_load_ssh_private_key(self, key_file, backend): @@ -243,6 +244,48 @@ def test_load_ssh_private_key(self, key_file, backend): maxline = max(map(len, priv_data2.split(b"\n"))) assert maxline < 80 + @pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires Ed25519 support", + ) + @pytest.mark.supported( + only_if=lambda backend: ssh._bcrypt_supported, + skip_message="Requires that bcrypt exists", + ) + def test_load_ssh_private_key_invalid_tag(self, backend): + priv_data = bytearray( + load_vectors_from_file( + os.path.join( + "asymmetric", "OpenSSH", "ed25519-aesgcm-psw.key" + ), + lambda f: f.read(), + mode="rb", + ) + ) + # mutate one byte to break the tag + priv_data[-38] = 82 + with pytest.raises(InvalidTag): + load_ssh_private_key(priv_data, b"password") + + @pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires Ed25519 support", + ) + @pytest.mark.supported( + only_if=lambda backend: ssh._bcrypt_supported, + skip_message="Requires that bcrypt exists", + ) + def test_load_ssh_private_key_tag_incorrect_length(self, backend): + priv_data = load_vectors_from_file( + os.path.join("asymmetric", "OpenSSH", "ed25519-aesgcm-psw.key"), + lambda f: f.read(), + mode="rb", + ) + # clip out a byte + broken_data = priv_data[:-37] + priv_data[-38:] + with pytest.raises(ValueError): + load_ssh_private_key(broken_data, b"password") + @pytest.mark.supported( only_if=lambda backend: ssh._bcrypt_supported, skip_message="Requires that bcrypt exists", diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-aesgcm-psw.key b/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-aesgcm-psw.key new file mode 100644 index 000000000000..673cf2d79101 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-aesgcm-psw.key @@ -0,0 +1,8 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAAFmFlczI1Ni1nY21Ab3BlbnNzaC5jb20AAAAGYmNyeXB0AA +AAGAAAABBxwbaftabtGFPlzbCIuqOIAAAAIAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAA +ICuPdFT6OORNyXh9rMfOx3LUCm9yANYovOfNlGd2hg01AAAAkBl0VICPNwd88NHm9w10X0 +bn0WTOJMzyQBw8cNZvswPvczViEFmW0pZwDmeVrBBTLmktn4b3D7IfCMJIbfAq+N+rRZ0p +xhPi6toZopq1wP4dE44DYQ1dr2K4evLv5pRCLJUkmNny/7jFEOggVx8N5o8pOSuf0tNhYd +SCn7oNc1syjS2w0Zjb2ZTiX4L9d60tSLDwLOolS1Xc0nPUMnzC5hM= +-----END OPENSSH PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-aesgcm-psw.key.pub b/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-aesgcm-psw.key.pub new file mode 100644 index 000000000000..ed7c311aee03 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-aesgcm-psw.key.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICuPdFT6OORNyXh9rMfOx3LUCm9yANYovOfNlGd2hg01 From a9d1bcfe5fce9f6e257231521c96298b952ad72a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 15 Apr 2023 11:02:05 -0400 Subject: [PATCH 123/316] Bump pytest from 7.3.0 to 7.3.1 (#8739) Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.3.0 to 7.3.1. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.3.0...7.3.1) --- updated-dependencies: - dependency-name: pytest 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 9668353db5a3..4f00c537256f 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -105,7 +105,7 @@ pygments==2.15.0 # sphinx pyproject-hooks==1.0.0 # via build -pytest==7.3.0 +pytest==7.3.1 # via # cryptography (pyproject.toml) # pytest-benchmark From 9c09a67204223578896026035ce877d7ea2ffdf4 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 16 Apr 2023 19:34:00 +0800 Subject: [PATCH 124/316] drop libressl 3.5.x support (#8741) OpenBSD 7.1 is no longer supported so neither is LibreSSL 3.5.x --- .github/workflows/ci.yml | 1 - CHANGELOG.rst | 1 + src/_cffi_src/openssl/crypto.py | 8 -------- src/_cffi_src/openssl/cryptography.py | 3 --- src/cryptography/hazmat/bindings/openssl/_conditional.py | 7 ------- tests/hazmat/backends/test_openssl_memleak.py | 3 +-- 6 files changed, 2 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 706d50bb3315..92dd1db1b763 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,6 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct no-psk"}} - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0", CONFIG_FLAGS: "no-legacy", NO_LEGACY: "1"}} - {VERSION: "3.11", NOXSESSION: "tests", NOXARGS: "--enable-fips=1", OPENSSL: {TYPE: "openssl", CONFIG_FLAGS: "enable-fips", VERSION: "3.1.0"}} - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.5.4"}} - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.6.2"}} - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5a550584ef8e..fcc6f28cbc47 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,7 @@ Changelog * **BACKWARDS INCOMPATIBLE:** Support for OpenSSL less than 1.1.1d has been removed. Users on older version of OpenSSL will need to upgrade. * **BACKWARDS INCOMPATIBLE:** Support for Python 3.6 has been removed. +* **BACKWARDS INCOMPATIBLE:** Dropped support for LibreSSL < 3.6. * Updated the minimum supported Rust version (MSRV) to 1.56.0, from 1.48.0. * Added support for the :class:`~cryptography.x509.OCSPAcceptableResponses` OCSP extension. diff --git a/src/_cffi_src/openssl/crypto.py b/src/_cffi_src/openssl/crypto.py index f36a0fa17616..b81b5de1da27 100644 --- a/src/_cffi_src/openssl/crypto.py +++ b/src/_cffi_src/openssl/crypto.py @@ -10,7 +10,6 @@ TYPES = """ static const long Cryptography_HAS_MEM_FUNCTIONS; -static const long Cryptography_HAS_OPENSSL_CLEANUP; static const int OPENSSL_VERSION; static const int OPENSSL_CFLAGS; @@ -42,13 +41,6 @@ """ CUSTOMIZATIONS = """ -#if CRYPTOGRAPHY_LIBRESSL_LESS_THAN_360 -static const long Cryptography_HAS_OPENSSL_CLEANUP = 0; -void (*OPENSSL_cleanup)(void) = NULL; -#else -static const long Cryptography_HAS_OPENSSL_CLEANUP = 1; -#endif - #if CRYPTOGRAPHY_IS_LIBRESSL || CRYPTOGRAPHY_IS_BORINGSSL static const long Cryptography_HAS_MEM_FUNCTIONS = 0; int (*Cryptography_CRYPTO_set_mem_functions)( diff --git a/src/_cffi_src/openssl/cryptography.py b/src/_cffi_src/openssl/cryptography.py index 05d3e0e50165..f5fcb04405b5 100644 --- a/src/_cffi_src/openssl/cryptography.py +++ b/src/_cffi_src/openssl/cryptography.py @@ -43,13 +43,10 @@ #endif #if CRYPTOGRAPHY_IS_LIBRESSL -#define CRYPTOGRAPHY_LIBRESSL_LESS_THAN_360 \ - (LIBRESSL_VERSION_NUMBER < 0x3060000f) #define CRYPTOGRAPHY_LIBRESSL_LESS_THAN_370 \ (LIBRESSL_VERSION_NUMBER < 0x3070000f) #else -#define CRYPTOGRAPHY_LIBRESSL_LESS_THAN_360 (0) #define CRYPTOGRAPHY_LIBRESSL_LESS_THAN_370 (0) #endif diff --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py index 95d5297d5711..3130edd490ff 100644 --- a/src/cryptography/hazmat/bindings/openssl/_conditional.py +++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py @@ -124,12 +124,6 @@ def cryptography_has_custom_ext() -> typing.List[str]: ] -def cryptography_has_openssl_cleanup() -> typing.List[str]: - return [ - "OPENSSL_cleanup", - ] - - def cryptography_has_tlsv13_functions() -> typing.List[str]: return [ "SSL_VERIFY_POST_HANDSHAKE", @@ -299,7 +293,6 @@ def cryptography_has_evp_pkey_set_peer_ex() -> typing.List[str]: "Cryptography_HAS_PSK": cryptography_has_psk, "Cryptography_HAS_PSK_TLSv1_3": cryptography_has_psk_tlsv13, "Cryptography_HAS_CUSTOM_EXT": cryptography_has_custom_ext, - "Cryptography_HAS_OPENSSL_CLEANUP": cryptography_has_openssl_cleanup, "Cryptography_HAS_TLSv1_3_FUNCTIONS": cryptography_has_tlsv13_functions, "Cryptography_HAS_RAW_KEY": cryptography_has_raw_key, "Cryptography_HAS_EVP_DIGESTFINAL_XOF": ( diff --git a/tests/hazmat/backends/test_openssl_memleak.py b/tests/hazmat/backends/test_openssl_memleak.py index 755f1827d278..05e8f9480356 100644 --- a/tests/hazmat/backends/test_openssl_memleak.py +++ b/tests/hazmat/backends/test_openssl_memleak.py @@ -122,8 +122,7 @@ def free(ptr, path, line): _openssl.lib.OSSL_PROVIDER_unload(backend._binding._legacy_provider) _openssl.lib.OSSL_PROVIDER_unload(backend._binding._default_provider) - if _openssl.lib.Cryptography_HAS_OPENSSL_CLEANUP: - _openssl.lib.OPENSSL_cleanup() + _openssl.lib.OPENSSL_cleanup() # Swap back to the original functions so that if OpenSSL tries to free # something from its atexit handle it won't be going through a Python From 3e40017b5fff43b2bc3be774eca47c0643e97649 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 17 Apr 2023 05:45:25 +0800 Subject: [PATCH 125/316] begin separation of x509 crate from cryptography crate (#8740) * begin separation of x509 crate from cryptography crate this will not be a published crate for now and the separation is incomplete. * no more rawcertificate, no more re-exporting * rename RawCsr * rename rawcrl * port ocsprequest and rename * more raw renaming * switch to a workspace, rename * remove unneeded imports * add license headers, remove more unneeded imports * coverage * this should actually be possible iwth just --all * merge all the coverage files * path fix * one last guess * coverage * remove extra definition --- .github/workflows/ci.yml | 6 +- src/rust/Cargo.lock | 8 + src/rust/Cargo.toml | 4 + src/rust/cryptography-x509/Cargo.toml | 11 + src/rust/cryptography-x509/src/certificate.rs | 41 +++ src/rust/cryptography-x509/src/common.rs | 142 +++++++++++ src/rust/cryptography-x509/src/crl.rs | 69 +++++ src/rust/cryptography-x509/src/csr.rs | 70 +++++ src/rust/cryptography-x509/src/extensions.rs | 175 +++++++++++++ src/rust/cryptography-x509/src/lib.rs | 14 + src/rust/cryptography-x509/src/name.rs | 88 +++++++ src/rust/cryptography-x509/src/ocsp_req.rs | 46 ++++ src/rust/cryptography-x509/src/oid.rs | 86 +++++++ src/rust/src/asn1.rs | 2 +- src/rust/src/pkcs7.rs | 51 ++-- src/rust/src/x509/certificate.rs | 234 +++-------------- src/rust/src/x509/common.rs | 240 +----------------- src/rust/src/x509/crl.rs | 193 +++++--------- src/rust/src/x509/csr.rs | 105 +++----- src/rust/src/x509/extensions.rs | 80 +++--- src/rust/src/x509/mod.rs | 5 +- src/rust/src/x509/ocsp.rs | 116 ++++----- src/rust/src/x509/ocsp_req.rs | 66 ++--- src/rust/src/x509/ocsp_resp.rs | 57 +++-- src/rust/src/x509/oid.rs | 101 -------- src/rust/src/x509/sign.rs | 51 ++-- 26 files changed, 1096 insertions(+), 965 deletions(-) create mode 100644 src/rust/cryptography-x509/Cargo.toml create mode 100644 src/rust/cryptography-x509/src/certificate.rs create mode 100644 src/rust/cryptography-x509/src/common.rs create mode 100644 src/rust/cryptography-x509/src/crl.rs create mode 100644 src/rust/cryptography-x509/src/csr.rs create mode 100644 src/rust/cryptography-x509/src/extensions.rs create mode 100644 src/rust/cryptography-x509/src/lib.rs create mode 100644 src/rust/cryptography-x509/src/name.rs create mode 100644 src/rust/cryptography-x509/src/ocsp_req.rs create mode 100644 src/rust/cryptography-x509/src/oid.rs delete mode 100644 src/rust/src/x509/oid.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92dd1db1b763..5ee7a8595905 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -323,7 +323,7 @@ jobs: - name: Rust Tests run: | cd src/rust - cargo test --no-default-features + cargo test --no-default-features --all env: RUSTFLAGS: "-Cinstrument-coverage" LLVM_PROFILE_FILE: "rust-cov/cov-%m-%p.profraw" @@ -332,7 +332,7 @@ jobs: set -xe cd src/rust/ cargo profdata -- merge -sparse ../../rust-cov/*.profraw -o pytest-rust-cov.profdata - cargo profdata -- merge -sparse rust-cov/*.profraw -o cargo-test-rust-cov.profdata + cargo profdata -- merge -sparse rust-cov/*.profraw cryptography-x509/rust-cov/*.profraw -o cargo-test-rust-cov.profdata COV_UUID=$(python3 -c "import uuid; print(uuid.uuid4())") cargo cov -- export \ @@ -342,7 +342,7 @@ jobs: --ignore-filename-regex='/rustc/' \ --ignore-filename-regex='/.rustup/toolchains/' --format=lcov > ../../${COV_UUID}-1.lcov cargo cov -- export \ - $(env RUSTFLAGS="-Cinstrument-coverage" cargo test --no-default-features --tests --no-run --message-format=json | jq -r "select(.profile.test == true) | .filenames[]") \ + $(env RUSTFLAGS="-Cinstrument-coverage" cargo test --no-default-features --all --tests --no-run --message-format=json | jq -r "select(.profile.test == true) | .filenames[]") \ -instr-profile=cargo-test-rust-cov.profdata \ --ignore-filename-regex='/.cargo/registry' \ --ignore-filename-regex='/rustc/' \ diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index c16a7fcecbdc..1fc04cecd0dc 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -70,6 +70,7 @@ version = "0.1.0" dependencies = [ "asn1", "cc", + "cryptography-x509", "foreign-types-shared", "once_cell", "openssl", @@ -79,6 +80,13 @@ dependencies = [ "pyo3", ] +[[package]] +name = "cryptography-x509" +version = "0.1.0" +dependencies = [ + "asn1", +] + [[package]] name = "foreign-types" version = "0.3.2" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 3175cd12ba27..e96b1fc2b505 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -11,6 +11,7 @@ rust-version = "1.56.0" once_cell = "1" pyo3 = { version = "0.18" } asn1 = { version = "0.14.0", default-features = false } +cryptography-x509 = { path = "cryptography-x509" } pem = "1.1" ouroboros = "0.15" openssl = "0.10.50" @@ -31,3 +32,6 @@ crate-type = ["cdylib"] [profile.release] lto = "thin" overflow-checks = true + +[workspace] +members = ["cryptography-x509"] diff --git a/src/rust/cryptography-x509/Cargo.toml b/src/rust/cryptography-x509/Cargo.toml new file mode 100644 index 000000000000..b062ddbbfb57 --- /dev/null +++ b/src/rust/cryptography-x509/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "cryptography-x509" +version = "0.1.0" +authors = ["The cryptography developers "] +edition = "2021" +publish = false +# This specifies the MSRV +rust-version = "1.56.0" + +[dependencies] +asn1 = { version = "0.14.0", default-features = false } diff --git a/src/rust/cryptography-x509/src/certificate.rs b/src/rust/cryptography-x509/src/certificate.rs new file mode 100644 index 000000000000..bb9a666f5f78 --- /dev/null +++ b/src/rust/cryptography-x509/src/certificate.rs @@ -0,0 +1,41 @@ +// 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::common; +use crate::extensions; +use crate::name; + +#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Clone)] +pub struct Certificate<'a> { + pub tbs_cert: TbsCertificate<'a>, + pub signature_alg: common::AlgorithmIdentifier<'a>, + pub signature: asn1::BitString<'a>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Clone)] +pub struct TbsCertificate<'a> { + #[explicit(0)] + #[default(0)] + pub version: u8, + pub serial: asn1::BigInt<'a>, + pub signature_alg: common::AlgorithmIdentifier<'a>, + + pub issuer: name::Name<'a>, + pub validity: Validity, + pub subject: name::Name<'a>, + + pub spki: common::SubjectPublicKeyInfo<'a>, + #[implicit(1)] + pub issuer_unique_id: Option>, + #[implicit(2)] + pub subject_unique_id: Option>, + #[explicit(3)] + pub extensions: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Clone)] +pub struct Validity { + pub not_before: common::Time, + pub not_after: common::Time, +} diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs new file mode 100644 index 000000000000..13fcb3368243 --- /dev/null +++ b/src/rust/cryptography-x509/src/common.rs @@ -0,0 +1,142 @@ +// 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 std::marker::PhantomData; + +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash, Clone)] +pub struct AlgorithmIdentifier<'a> { + pub oid: asn1::ObjectIdentifier, + pub params: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Clone)] +pub struct SubjectPublicKeyInfo<'a> { + _algorithm: AlgorithmIdentifier<'a>, + pub subject_public_key: asn1::BitString<'a>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Eq, Hash, Clone)] +pub struct AttributeTypeValue<'a> { + pub type_id: asn1::ObjectIdentifier, + pub value: RawTlv<'a>, +} + +// Like `asn1::Tlv` but doesn't store `full_data` so it can be constructed from +// an un-encoded tag and value. +#[derive(Hash, PartialEq, Eq, Clone)] +pub struct RawTlv<'a> { + tag: asn1::Tag, + value: &'a [u8], +} + +impl<'a> RawTlv<'a> { + pub fn new(tag: asn1::Tag, value: &'a [u8]) -> Self { + RawTlv { tag, value } + } + + pub fn tag(&self) -> asn1::Tag { + self.tag + } + pub fn data(&self) -> &'a [u8] { + self.value + } +} +impl<'a> asn1::Asn1Readable<'a> for RawTlv<'a> { + fn parse(parser: &mut asn1::Parser<'a>) -> asn1::ParseResult { + let tlv = parser.read_element::>()?; + Ok(RawTlv::new(tlv.tag(), tlv.data())) + } + + fn can_parse(_tag: asn1::Tag) -> bool { + true + } +} +impl<'a> asn1::Asn1Writable for RawTlv<'a> { + fn write(&self, w: &mut asn1::Writer<'_>) -> asn1::WriteResult { + w.write_tlv(self.tag, move |dest| dest.push_slice(self.value)) + } +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash, Clone)] +pub enum Time { + UtcTime(asn1::UtcTime), + GeneralizedTime(asn1::GeneralizedTime), +} + +impl Time { + pub fn as_datetime(&self) -> &asn1::DateTime { + match self { + Time::UtcTime(data) => data.as_datetime(), + Time::GeneralizedTime(data) => data.as_datetime(), + } + } +} + +#[derive(Hash, PartialEq, Clone)] +pub enum Asn1ReadableOrWritable<'a, T, U> { + Read(T, PhantomData<&'a ()>), + Write(U, PhantomData<&'a ()>), +} + +impl<'a, T, U> Asn1ReadableOrWritable<'a, T, U> { + pub fn new_read(v: T) -> Self { + Asn1ReadableOrWritable::Read(v, PhantomData) + } + + pub fn new_write(v: U) -> Self { + Asn1ReadableOrWritable::Write(v, PhantomData) + } + + pub fn unwrap_read(&self) -> &T { + match self { + Asn1ReadableOrWritable::Read(v, _) => v, + Asn1ReadableOrWritable::Write(_, _) => panic!("unwrap_read called on a Write value"), + } + } +} + +impl<'a, T: asn1::SimpleAsn1Readable<'a>, U> asn1::SimpleAsn1Readable<'a> + for Asn1ReadableOrWritable<'a, T, U> +{ + const TAG: asn1::Tag = T::TAG; + fn parse_data(data: &'a [u8]) -> asn1::ParseResult { + Ok(Self::new_read(T::parse_data(data)?)) + } +} + +impl<'a, T: asn1::SimpleAsn1Writable, U: asn1::SimpleAsn1Writable> asn1::SimpleAsn1Writable + for Asn1ReadableOrWritable<'a, T, U> +{ + const TAG: asn1::Tag = U::TAG; + fn write_data(&self, w: &mut asn1::WriteBuf) -> asn1::WriteResult { + match self { + Asn1ReadableOrWritable::Read(v, _) => T::write_data(v, w), + Asn1ReadableOrWritable::Write(v, _) => U::write_data(v, w), + } + } +} + +#[cfg(test)] +mod tests { + use super::{Asn1ReadableOrWritable, RawTlv}; + use asn1::Asn1Readable; + + #[test] + #[should_panic] + fn test_asn1_readable_or_writable_unwrap_read() { + Asn1ReadableOrWritable::::new_write(17).unwrap_read(); + } + + #[test] + fn test_asn1_readable_or_writable_write_read_data() { + let v = Asn1ReadableOrWritable::::new_read(17); + assert_eq!(&asn1::write_single(&v).unwrap(), b"\x02\x01\x11"); + } + + #[test] + fn test_raw_tlv_can_parse() { + let t = asn1::Tag::from_bytes(&[0]).unwrap().0; + assert!(RawTlv::can_parse(t)); + } +} diff --git a/src/rust/cryptography-x509/src/crl.rs b/src/rust/cryptography-x509/src/crl.rs new file mode 100644 index 000000000000..3a47e0a37727 --- /dev/null +++ b/src/rust/cryptography-x509/src/crl.rs @@ -0,0 +1,69 @@ +// 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::{common, extensions, name}; + +pub type ReasonFlags<'a> = + Option, asn1::OwnedBitString>>; + +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash)] +pub struct CertificateRevocationList<'a> { + pub tbs_cert_list: TBSCertList<'a>, + pub signature_algorithm: common::AlgorithmIdentifier<'a>, + pub signature_value: asn1::BitString<'a>, +} + +pub type RevokedCertificates<'a> = Option< + common::Asn1ReadableOrWritable< + 'a, + asn1::SequenceOf<'a, RevokedCertificate<'a>>, + asn1::SequenceOfWriter<'a, RevokedCertificate<'a>, Vec>>, + >, +>; + +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash)] +pub struct TBSCertList<'a> { + pub version: Option, + pub signature: common::AlgorithmIdentifier<'a>, + pub issuer: name::Name<'a>, + pub this_update: common::Time, + pub next_update: Option, + pub revoked_certificates: RevokedCertificates<'a>, + #[explicit(0)] + pub crl_extensions: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash, Clone)] +pub struct RevokedCertificate<'a> { + pub user_certificate: asn1::BigUint<'a>, + pub revocation_date: common::Time, + pub crl_entry_extensions: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct IssuingDistributionPoint<'a> { + #[explicit(0)] + pub distribution_point: Option>, + + #[implicit(1)] + #[default(false)] + pub only_contains_user_certs: bool, + + #[implicit(2)] + #[default(false)] + pub only_contains_ca_certs: bool, + + #[implicit(3)] + pub only_some_reasons: ReasonFlags<'a>, + + #[implicit(4)] + #[default(false)] + pub indirect_crl: bool, + + #[implicit(5)] + #[default(false)] + pub only_contains_attribute_certs: bool, +} + +pub type CRLReason = asn1::Enumerated; diff --git a/src/rust/cryptography-x509/src/csr.rs b/src/rust/cryptography-x509/src/csr.rs new file mode 100644 index 000000000000..c23d22d0fd11 --- /dev/null +++ b/src/rust/cryptography-x509/src/csr.rs @@ -0,0 +1,70 @@ +// 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::common; +use crate::extensions; +use crate::name; +use crate::oid; + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct Csr<'a> { + pub csr_info: CertificationRequestInfo<'a>, + pub signature_alg: common::AlgorithmIdentifier<'a>, + pub signature: asn1::BitString<'a>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct CertificationRequestInfo<'a> { + pub version: u8, + pub subject: name::Name<'a>, + pub spki: common::SubjectPublicKeyInfo<'a>, + #[implicit(0, required)] + pub attributes: Attributes<'a>, +} + +impl CertificationRequestInfo<'_> { + pub fn get_extension_attribute( + &self, + ) -> Result>, asn1::ParseError> { + for attribute in self.attributes.unwrap_read().clone() { + if attribute.type_id == oid::EXTENSION_REQUEST + || attribute.type_id == oid::MS_EXTENSION_REQUEST + { + check_attribute_length(attribute.values.unwrap_read().clone())?; + let val = attribute.values.unwrap_read().clone().next().unwrap(); + let exts = asn1::parse_single(val.full_data())?; + return Ok(Some(exts)); + } + } + Ok(None) + } +} + +pub fn check_attribute_length<'a>( + values: asn1::SetOf<'a, asn1::Tlv<'a>>, +) -> Result<(), asn1::ParseError> { + if values.count() > 1 { + // TODO: We should raise a more specific error here + // Only single-valued attributes are supported + Err(asn1::ParseError::new(asn1::ParseErrorKind::InvalidValue)) + } else { + Ok(()) + } +} + +pub type Attributes<'a> = common::Asn1ReadableOrWritable< + 'a, + asn1::SetOf<'a, Attribute<'a>>, + asn1::SetOfWriter<'a, Attribute<'a>, Vec>>, +>; + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct Attribute<'a> { + pub type_id: asn1::ObjectIdentifier, + pub values: common::Asn1ReadableOrWritable< + 'a, + asn1::SetOf<'a, asn1::Tlv<'a>>, + asn1::SetOfWriter<'a, common::RawTlv<'a>, [common::RawTlv<'a>; 1]>, + >, +} diff --git a/src/rust/cryptography-x509/src/extensions.rs b/src/rust/cryptography-x509/src/extensions.rs new file mode 100644 index 000000000000..11c6e54a4d34 --- /dev/null +++ b/src/rust/cryptography-x509/src/extensions.rs @@ -0,0 +1,175 @@ +// 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::common; +use crate::crl; +use crate::name; + +pub type Extensions<'a> = common::Asn1ReadableOrWritable< + 'a, + asn1::SequenceOf<'a, Extension<'a>>, + asn1::SequenceOfWriter<'a, Extension<'a>, Vec>>, +>; + +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Eq, Hash, Clone)] +pub struct Extension<'a> { + pub extn_id: asn1::ObjectIdentifier, + #[default(false)] + pub critical: bool, + pub extn_value: &'a [u8], +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct PolicyConstraints { + #[implicit(0)] + pub require_explicit_policy: Option, + #[implicit(1)] + pub inhibit_policy_mapping: Option, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct AccessDescription<'a> { + pub access_method: asn1::ObjectIdentifier, + pub access_location: name::GeneralName<'a>, +} + +pub type SequenceOfAccessDescriptions<'a> = common::Asn1ReadableOrWritable< + 'a, + asn1::SequenceOf<'a, AccessDescription<'a>>, + asn1::SequenceOfWriter<'a, AccessDescription<'a>, Vec>>, +>; + +// Needed due to clippy type complexity warning. +type SequenceOfPolicyQualifiers<'a> = common::Asn1ReadableOrWritable< + 'a, + asn1::SequenceOf<'a, PolicyQualifierInfo<'a>>, + asn1::SequenceOfWriter<'a, PolicyQualifierInfo<'a>, Vec>>, +>; + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct PolicyInformation<'a> { + pub policy_identifier: asn1::ObjectIdentifier, + pub policy_qualifiers: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct PolicyQualifierInfo<'a> { + pub policy_qualifier_id: asn1::ObjectIdentifier, + pub qualifier: Qualifier<'a>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub enum Qualifier<'a> { + CpsUri(asn1::IA5String<'a>), + UserNotice(UserNotice<'a>), +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct UserNotice<'a> { + pub notice_ref: Option>, + pub explicit_text: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct NoticeReference<'a> { + pub organization: DisplayText<'a>, + pub notice_numbers: common::Asn1ReadableOrWritable< + 'a, + asn1::SequenceOf<'a, asn1::BigUint<'a>>, + asn1::SequenceOfWriter<'a, asn1::BigUint<'a>, Vec>>, + >, +} + +// DisplayText also allows BMPString, which we currently do not support. +#[allow(clippy::enum_variant_names)] +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub enum DisplayText<'a> { + IA5String(asn1::IA5String<'a>), + Utf8String(asn1::Utf8String<'a>), + VisibleString(asn1::VisibleString<'a>), + BmpString(asn1::BMPString<'a>), +} + +// Needed due to clippy type complexity warning. +pub type SequenceOfSubtrees<'a> = common::Asn1ReadableOrWritable< + 'a, + asn1::SequenceOf<'a, GeneralSubtree<'a>>, + asn1::SequenceOfWriter<'a, GeneralSubtree<'a>, Vec>>, +>; + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct NameConstraints<'a> { + #[implicit(0)] + pub permitted_subtrees: Option>, + + #[implicit(1)] + pub excluded_subtrees: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct GeneralSubtree<'a> { + pub base: name::GeneralName<'a>, + + #[implicit(0)] + #[default(0u64)] + pub minimum: u64, + + #[implicit(1)] + pub maximum: Option, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct MSCertificateTemplate { + pub template_id: asn1::ObjectIdentifier, + pub major_version: Option, + pub minor_version: Option, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct DistributionPoint<'a> { + #[explicit(0)] + pub distribution_point: Option>, + + #[implicit(1)] + pub reasons: crl::ReasonFlags<'a>, + + #[implicit(2)] + pub crl_issuer: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub enum DistributionPointName<'a> { + #[implicit(0)] + FullName(name::SequenceOfGeneralName<'a>), + + #[implicit(1)] + NameRelativeToCRLIssuer( + common::Asn1ReadableOrWritable< + 'a, + asn1::SetOf<'a, common::AttributeTypeValue<'a>>, + asn1::SetOfWriter< + 'a, + common::AttributeTypeValue<'a>, + Vec>, + >, + >, + ), +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct AuthorityKeyIdentifier<'a> { + #[implicit(0)] + pub key_identifier: Option<&'a [u8]>, + #[implicit(1)] + pub authority_cert_issuer: Option>, + #[implicit(2)] + pub authority_cert_serial_number: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct BasicConstraints { + #[default(false)] + pub ca: bool, + pub path_length: Option, +} diff --git a/src/rust/cryptography-x509/src/lib.rs b/src/rust/cryptography-x509/src/lib.rs new file mode 100644 index 000000000000..3f8878772dd1 --- /dev/null +++ b/src/rust/cryptography-x509/src/lib.rs @@ -0,0 +1,14 @@ +// 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. + +#![forbid(unsafe_code)] + +pub mod certificate; +pub mod common; +pub mod crl; +pub mod csr; +pub mod extensions; +pub mod name; +pub mod ocsp_req; +pub mod oid; diff --git a/src/rust/cryptography-x509/src/name.rs b/src/rust/cryptography-x509/src/name.rs new file mode 100644 index 000000000000..f53e342cbf33 --- /dev/null +++ b/src/rust/cryptography-x509/src/name.rs @@ -0,0 +1,88 @@ +// 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::common; + +pub type Name<'a> = common::Asn1ReadableOrWritable< + 'a, + asn1::SequenceOf<'a, asn1::SetOf<'a, common::AttributeTypeValue<'a>>>, + asn1::SequenceOfWriter< + 'a, + asn1::SetOfWriter<'a, common::AttributeTypeValue<'a>, Vec>>, + Vec< + asn1::SetOfWriter< + 'a, + common::AttributeTypeValue<'a>, + Vec>, + >, + >, + >, +>; + +/// An IA5String ASN.1 element whose contents is not validated as meeting the +/// requirements (ASCII characters only), and instead is only known to be +/// valid UTF-8. +pub struct UnvalidatedIA5String<'a>(pub &'a str); + +impl<'a> asn1::SimpleAsn1Readable<'a> for UnvalidatedIA5String<'a> { + const TAG: asn1::Tag = asn1::IA5String::TAG; + fn parse_data(data: &'a [u8]) -> asn1::ParseResult { + Ok(UnvalidatedIA5String(std::str::from_utf8(data).map_err( + |_| asn1::ParseError::new(asn1::ParseErrorKind::InvalidValue), + )?)) + } +} + +impl<'a> asn1::SimpleAsn1Writable for UnvalidatedIA5String<'a> { + const TAG: asn1::Tag = asn1::IA5String::TAG; + fn write_data(&self, dest: &mut asn1::WriteBuf) -> asn1::WriteResult { + dest.push_slice(self.0.as_bytes()) + } +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash)] +pub struct OtherName<'a> { + pub type_id: asn1::ObjectIdentifier, + #[explicit(0, required)] + pub value: asn1::Tlv<'a>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub enum GeneralName<'a> { + #[implicit(0)] + OtherName(OtherName<'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), +} + +pub(crate) type SequenceOfGeneralName<'a> = common::Asn1ReadableOrWritable< + 'a, + asn1::SequenceOf<'a, GeneralName<'a>>, + asn1::SequenceOfWriter<'a, GeneralName<'a>, Vec>>, +>; diff --git a/src/rust/cryptography-x509/src/ocsp_req.rs b/src/rust/cryptography-x509/src/ocsp_req.rs new file mode 100644 index 000000000000..1e096e71f1da --- /dev/null +++ b/src/rust/cryptography-x509/src/ocsp_req.rs @@ -0,0 +1,46 @@ +// 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::{common, extensions, name}; + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct TBSRequest<'a> { + #[explicit(0)] + #[default(0)] + pub version: u8, + #[explicit(1)] + pub requestor_name: Option>, + pub request_list: common::Asn1ReadableOrWritable< + 'a, + asn1::SequenceOf<'a, Request<'a>>, + asn1::SequenceOfWriter<'a, Request<'a>>, + >, + #[explicit(2)] + pub request_extensions: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct Request<'a> { + pub req_cert: CertID<'a>, + #[explicit(0)] + pub single_request_extensions: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct CertID<'a> { + pub hash_algorithm: common::AlgorithmIdentifier<'a>, + pub issuer_name_hash: &'a [u8], + pub issuer_key_hash: &'a [u8], + pub serial_number: asn1::BigInt<'a>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct OCSPRequest<'a> { + pub 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)] + pub optional_signature: Option>, +} diff --git a/src/rust/cryptography-x509/src/oid.rs b/src/rust/cryptography-x509/src/oid.rs new file mode 100644 index 000000000000..b2d22ebddb1c --- /dev/null +++ b/src/rust/cryptography-x509/src/oid.rs @@ -0,0 +1,86 @@ +// 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. + +pub const EXTENSION_REQUEST: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 9, 14); +pub const MS_EXTENSION_REQUEST: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 4, 1, 311, 2, 1, 14); +pub const MS_CERTIFICATE_TEMPLATE: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 4, 1, 311, 21, 7); +pub const PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS_OID: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 4, 1, 11129, 2, 4, 2); +pub const PRECERT_POISON_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 4, 1, 11129, 2, 4, 3); +pub const SIGNED_CERTIFICATE_TIMESTAMPS_OID: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 4, 1, 11129, 2, 4, 5); +pub const AUTHORITY_INFORMATION_ACCESS_OID: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 5, 5, 7, 1, 1); +pub const SUBJECT_INFORMATION_ACCESS_OID: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 5, 5, 7, 1, 11); +pub const TLS_FEATURE_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 5, 5, 7, 1, 24); +pub const CP_CPS_URI_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 5, 5, 7, 2, 1); +pub const CP_USER_NOTICE_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 5, 5, 7, 2, 2); +pub const NONCE_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 5, 5, 7, 48, 1, 2); +pub const OCSP_NO_CHECK_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 5, 5, 7, 48, 1, 5); +pub const SUBJECT_KEY_IDENTIFIER_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 14); +pub const KEY_USAGE_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 15); +pub const SUBJECT_ALTERNATIVE_NAME_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 17); +pub const ISSUER_ALTERNATIVE_NAME_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 18); +pub const BASIC_CONSTRAINTS_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 19); +pub const CRL_NUMBER_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 20); +pub const CRL_REASON_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 21); +pub const INVALIDITY_DATE_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 24); +pub const DELTA_CRL_INDICATOR_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 27); +pub const ISSUING_DISTRIBUTION_POINT_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 28); +pub const CERTIFICATE_ISSUER_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 29); +pub const NAME_CONSTRAINTS_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 30); +pub const CRL_DISTRIBUTION_POINTS_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 31); +pub const CERTIFICATE_POLICIES_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 32); +pub const AUTHORITY_KEY_IDENTIFIER_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 35); +pub const POLICY_CONSTRAINTS_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 36); +pub const EXTENDED_KEY_USAGE_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 37); +pub const FRESHEST_CRL_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 46); +pub const INHIBIT_ANY_POLICY_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 54); +pub const ACCEPTABLE_RESPONSES_OID: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 5, 5, 7, 48, 1, 4); + +// Signing methods +pub const ECDSA_WITH_SHA224_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 10045, 4, 3, 1); +pub const ECDSA_WITH_SHA256_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 10045, 4, 3, 2); +pub const ECDSA_WITH_SHA384_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 10045, 4, 3, 3); +pub const ECDSA_WITH_SHA512_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 10045, 4, 3, 4); +pub const ECDSA_WITH_SHA3_224_OID: asn1::ObjectIdentifier = + asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 9); +pub const ECDSA_WITH_SHA3_256_OID: asn1::ObjectIdentifier = + asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 10); +pub const ECDSA_WITH_SHA3_384_OID: asn1::ObjectIdentifier = + asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 11); +pub const ECDSA_WITH_SHA3_512_OID: asn1::ObjectIdentifier = + asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 12); + +pub const RSA_WITH_SHA224_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 14); +pub const RSA_WITH_SHA256_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 11); +pub const RSA_WITH_SHA384_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 12); +pub const RSA_WITH_SHA512_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 13); +pub const RSA_WITH_SHA3_224_OID: asn1::ObjectIdentifier = + asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 13); +pub const RSA_WITH_SHA3_256_OID: asn1::ObjectIdentifier = + asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 14); +pub const RSA_WITH_SHA3_384_OID: asn1::ObjectIdentifier = + asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 15); +pub const RSA_WITH_SHA3_512_OID: asn1::ObjectIdentifier = + asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 16); + +pub const DSA_WITH_SHA224_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 1); +pub const DSA_WITH_SHA256_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 2); +pub const DSA_WITH_SHA384_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 3); +pub const DSA_WITH_SHA512_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 4); + +pub const ED25519_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 101, 112); +pub const ED448_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 101, 113); + +// Hashes +pub const SHA1_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 14, 3, 2, 26); +pub const SHA224_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 4); +pub const SHA256_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 1); +pub const SHA384_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 2); +pub const SHA512_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 3); diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 53981ddac6e8..cad48a73f174 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -3,7 +3,7 @@ // for complete details. use crate::error::{CryptographyError, CryptographyResult}; -use crate::x509::Name; +use cryptography_x509::name::Name; use pyo3::basic::CompareOp; use pyo3::types::IntoPyDict; use pyo3::ToPyObject; diff --git a/src/rust/src/pkcs7.rs b/src/rust/src/pkcs7.rs index bb516143425f..2fdb610e3e82 100644 --- a/src/rust/src/pkcs7.rs +++ b/src/rust/src/pkcs7.rs @@ -6,6 +6,8 @@ use crate::asn1::encode_der_data; use crate::buf::CffiBuf; use crate::error::CryptographyResult; use crate::x509; +use cryptography_x509::csr::{Attribute, Attributes}; +use cryptography_x509::{common, name, oid}; use once_cell::sync::Lazy; use std::borrow::Cow; @@ -26,10 +28,10 @@ const AES_128_CBC_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3 static OIDS_TO_MIC_NAME: Lazy> = Lazy::new(|| { let mut h = HashMap::new(); - h.insert(&x509::oid::SHA224_OID, "sha-224"); - h.insert(&x509::oid::SHA256_OID, "sha-256"); - h.insert(&x509::oid::SHA384_OID, "sha-384"); - h.insert(&x509::oid::SHA512_OID, "sha-512"); + h.insert(&oid::SHA224_OID, "sha-224"); + h.insert(&oid::SHA256_OID, "sha-256"); + h.insert(&oid::SHA384_OID, "sha-384"); + h.insert(&oid::SHA512_OID, "sha-512"); h }); @@ -52,10 +54,11 @@ enum Content<'a> { #[derive(asn1::Asn1Write)] struct SignedData<'a> { version: u8, - digest_algorithms: asn1::SetOfWriter<'a, x509::AlgorithmIdentifier<'a>>, + digest_algorithms: asn1::SetOfWriter<'a, common::AlgorithmIdentifier<'a>>, content_info: ContentInfo<'a>, #[implicit(0)] - certificates: Option>>, + certificates: + Option>>, // We don't ever supply any of these, so for now, don't fill out the fields. #[implicit(1)] @@ -68,27 +71,27 @@ struct SignedData<'a> { struct SignerInfo<'a> { version: u8, issuer_and_serial_number: IssuerAndSerialNumber<'a>, - digest_algorithm: x509::AlgorithmIdentifier<'a>, + digest_algorithm: common::AlgorithmIdentifier<'a>, #[implicit(0)] - authenticated_attributes: Option>, + authenticated_attributes: Option>, - digest_encryption_algorithm: x509::AlgorithmIdentifier<'a>, + digest_encryption_algorithm: common::AlgorithmIdentifier<'a>, encrypted_digest: &'a [u8], #[implicit(1)] - unauthenticated_attributes: Option>, + unauthenticated_attributes: Option>, } #[derive(asn1::Asn1Write)] struct IssuerAndSerialNumber<'a> { - issuer: x509::Name<'a>, + issuer: name::Name<'a>, serial_number: asn1::BigInt<'a>, } #[pyo3::prelude::pyfunction] fn serialize_certificates<'p>( py: pyo3::Python<'p>, - py_certs: Vec>, + py_certs: Vec>, encoding: &'p pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { if py_certs.is_empty() { @@ -163,12 +166,12 @@ fn sign_and_serialize<'p>( ]))?; let py_signers: Vec<( - pyo3::PyRef<'p, x509::Certificate>, + pyo3::PyRef<'p, x509::certificate::Certificate>, &pyo3::PyAny, &pyo3::PyAny, )> = builder.getattr(pyo3::intern!(py, "_signers"))?.extract()?; - let py_certs: Vec> = builder + let py_certs: Vec> = builder .getattr(pyo3::intern!(py, "_additional_certs"))? .extract()?; @@ -189,15 +192,15 @@ fn sign_and_serialize<'p>( } else { let mut authenticated_attrs = vec![]; - authenticated_attrs.push(x509::csr::Attribute { + authenticated_attrs.push(Attribute { type_id: PKCS7_CONTENT_TYPE_OID, - values: x509::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ + values: common::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ asn1::parse_single(&content_type_bytes).unwrap(), ])), }); - authenticated_attrs.push(x509::csr::Attribute { + authenticated_attrs.push(Attribute { type_id: PKCS7_SIGNING_TIME_OID, - values: x509::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ + values: common::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ asn1::parse_single(&signing_time_bytes).unwrap(), ])), }); @@ -206,17 +209,17 @@ fn sign_and_serialize<'p>( asn1::write_single(&x509::ocsp::hash_data(py, py_hash_alg, &data_with_header)?)?; // Gross hack: copy to PyBytes to extend the lifetime to 'p let digest_bytes = pyo3::types::PyBytes::new(py, &digest); - authenticated_attrs.push(x509::csr::Attribute { + authenticated_attrs.push(Attribute { type_id: PKCS7_MESSAGE_DIGEST_OID, - values: x509::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ + values: common::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ asn1::parse_single(digest_bytes.as_bytes()).unwrap(), ])), }); if !options.contains(pkcs7_options.getattr(pyo3::intern!(py, "NoCapabilities"))?)? { - authenticated_attrs.push(x509::csr::Attribute { + authenticated_attrs.push(Attribute { type_id: PKCS7_SMIME_CAP_OID, - values: x509::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ + values: common::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ asn1::parse_single(&smime_cap_bytes).unwrap(), ])), }); @@ -226,14 +229,14 @@ fn sign_and_serialize<'p>( asn1::write_single(&asn1::SetOfWriter::new(authenticated_attrs.as_slice()))?; ( - Some(x509::Asn1ReadableOrWritable::new_write( + Some(common::Asn1ReadableOrWritable::new_write( asn1::SetOfWriter::new(authenticated_attrs), )), x509::sign::sign_data(py, py_private_key, py_hash_alg, &signed_data)?, ) }; - let digest_alg = x509::AlgorithmIdentifier { + let digest_alg = common::AlgorithmIdentifier { oid: x509::ocsp::HASH_NAME_TO_OIDS[py_hash_alg .getattr(pyo3::intern!(py, "name"))? .extract::<&str>()?] diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 6ccde6542cb3..a20e3fe5ff1a 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -7,79 +7,49 @@ use crate::asn1::{ }; use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; -use crate::x509::{crl, extensions, oid, sct, sign, Asn1ReadableOrWritable}; +use crate::x509::{extensions, sct, sign}; +use cryptography_x509::common::Asn1ReadableOrWritable; +use cryptography_x509::extensions::{ + AuthorityKeyIdentifier, BasicConstraints, DisplayText, DistributionPoint, + DistributionPointName, MSCertificateTemplate, NameConstraints, PolicyConstraints, + PolicyInformation, PolicyQualifierInfo, Qualifier, SequenceOfAccessDescriptions, + SequenceOfSubtrees, UserNotice, +}; +use cryptography_x509::extensions::{Extension, Extensions}; +use cryptography_x509::{common, name, oid}; use pyo3::{IntoPy, ToPyObject}; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; -#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Clone)] -pub(crate) struct RawCertificate<'a> { - pub(crate) tbs_cert: TbsCertificate<'a>, - signature_alg: x509::AlgorithmIdentifier<'a>, - signature: asn1::BitString<'a>, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Clone)] -pub(crate) struct TbsCertificate<'a> { - #[explicit(0)] - #[default(0)] - version: u8, - pub(crate) serial: asn1::BigInt<'a>, - signature_alg: x509::AlgorithmIdentifier<'a>, - - pub(crate) issuer: x509::Name<'a>, - validity: Validity, - pub(crate) subject: x509::Name<'a>, - - pub(crate) spki: SubjectPublicKeyInfo<'a>, - #[implicit(1)] - issuer_unique_id: Option>, - #[implicit(2)] - subject_unique_id: Option>, - #[explicit(3)] - extensions: Option>, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Clone)] -pub(crate) struct Validity { - not_before: x509::Time, - not_after: x509::Time, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Clone)] -pub(crate) struct SubjectPublicKeyInfo<'a> { - _algorithm: x509::AlgorithmIdentifier<'a>, - pub(crate) subject_public_key: asn1::BitString<'a>, -} - #[ouroboros::self_referencing] -pub(crate) struct OwnedRawCertificate { +pub(crate) struct OwnedCertificate { data: pyo3::Py, #[borrows(data)] #[covariant] - value: RawCertificate<'this>, + value: cryptography_x509::certificate::Certificate<'this>, } -impl OwnedRawCertificate { +impl OwnedCertificate { // Re-expose ::new with `pub(crate)` visibility. pub(crate) fn new_public( data: pyo3::Py, value_ref_builder: impl for<'this> FnOnce( &'this pyo3::Py, - ) -> RawCertificate<'this>, - ) -> OwnedRawCertificate { - OwnedRawCertificate::new(data, value_ref_builder) + ) + -> cryptography_x509::certificate::Certificate<'this>, + ) -> OwnedCertificate { + OwnedCertificate::new(data, value_ref_builder) } - pub(crate) fn borrow_value_public(&self) -> &RawCertificate<'_> { + pub(crate) fn borrow_value_public(&self) -> &cryptography_x509::certificate::Certificate<'_> { self.borrow_value() } } #[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")] pub(crate) struct Certificate { - pub(crate) raw: OwnedRawCertificate, + pub(crate) raw: OwnedCertificate, pub(crate) cached_extensions: Option, } @@ -209,7 +179,7 @@ impl Certificate { Some(extensions) => { let readable_extensions = extensions.unwrap_read().clone(); let ext_count = readable_extensions.len(); - let filtered_extensions: Vec> = readable_extensions + let filtered_extensions: Vec> = readable_extensions .filter(|x| x.extn_id != oid::PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS_OID) .collect(); if filtered_extensions.len() == ext_count { @@ -219,7 +189,7 @@ impl Certificate { ), )); } - let filtered_extensions: x509::Extensions<'_> = Asn1ReadableOrWritable::new_write( + let filtered_extensions: Extensions<'_> = Asn1ReadableOrWritable::new_write( asn1::SequenceOfWriter::new(filtered_extensions), ); tbs_precert.extensions = Some(filtered_extensions); @@ -409,7 +379,7 @@ fn load_der_x509_certificate( py: pyo3::Python<'_>, data: pyo3::Py, ) -> CryptographyResult { - let raw = OwnedRawCertificate::try_new(data, |data| asn1::parse_single(data.as_bytes(py)))?; + let raw = OwnedCertificate::try_new(data, |data| asn1::parse_single(data.as_bytes(py)))?; // Parse cert version immediately so we can raise error on parse if it is invalid. cert_version(py, raw.borrow_value().tbs_cert.version)?; // determine if the serial is negative and raise a warning if it is. We want to drop support @@ -437,57 +407,6 @@ fn warn_if_negative_serial(py: pyo3::Python<'_>, bytes: &'_ [u8]) -> pyo3::PyRes Ok(()) } -// Needed due to clippy type complexity warning. -type SequenceOfPolicyQualifiers<'a> = x509::Asn1ReadableOrWritable< - 'a, - asn1::SequenceOf<'a, PolicyQualifierInfo<'a>>, - asn1::SequenceOfWriter<'a, PolicyQualifierInfo<'a>, Vec>>, ->; - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) struct PolicyInformation<'a> { - pub policy_identifier: asn1::ObjectIdentifier, - pub policy_qualifiers: Option>, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) struct PolicyQualifierInfo<'a> { - pub policy_qualifier_id: asn1::ObjectIdentifier, - pub qualifier: Qualifier<'a>, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) enum Qualifier<'a> { - CpsUri(asn1::IA5String<'a>), - UserNotice(UserNotice<'a>), -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) struct UserNotice<'a> { - pub notice_ref: Option>, - pub explicit_text: Option>, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) struct NoticeReference<'a> { - pub organization: DisplayText<'a>, - pub notice_numbers: x509::Asn1ReadableOrWritable< - 'a, - asn1::SequenceOf<'a, asn1::BigUint<'a>>, - asn1::SequenceOfWriter<'a, asn1::BigUint<'a>, Vec>>, - >, -} - -// DisplayText also allows BMPString, which we currently do not support. -#[allow(clippy::enum_variant_names)] -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) enum DisplayText<'a> { - IA5String(asn1::IA5String<'a>), - Utf8String(asn1::Utf8String<'a>), - VisibleString(asn1::VisibleString<'a>), - BmpString(asn1::BMPString<'a>), -} - fn parse_display_text( py: pyo3::Python<'_>, text: DisplayText<'_>, @@ -592,41 +511,6 @@ fn parse_cp(py: pyo3::Python<'_>, ext_data: &[u8]) -> Result = x509::Asn1ReadableOrWritable< - 'a, - asn1::SequenceOf<'a, GeneralSubtree<'a>>, - asn1::SequenceOfWriter<'a, GeneralSubtree<'a>, Vec>>, ->; - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) struct NameConstraints<'a> { - #[implicit(0)] - pub permitted_subtrees: Option>, - - #[implicit(1)] - pub excluded_subtrees: Option>, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) struct GeneralSubtree<'a> { - pub base: x509::GeneralName<'a>, - - #[implicit(0)] - #[default(0u64)] - pub minimum: u64, - - #[implicit(1)] - pub maximum: Option, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) struct MSCertificateTemplate { - pub template_id: asn1::ObjectIdentifier, - pub major_version: Option, - pub minor_version: Option, -} - fn parse_general_subtrees( py: pyo3::Python<'_>, subtrees: SequenceOfSubtrees<'_>, @@ -638,43 +522,6 @@ fn parse_general_subtrees( Ok(gns.to_object(py)) } -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) struct DistributionPoint<'a> { - #[explicit(0)] - pub distribution_point: Option>, - - #[implicit(1)] - pub reasons: crl::ReasonFlags<'a>, - - #[implicit(2)] - pub crl_issuer: Option>, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) enum DistributionPointName<'a> { - #[implicit(0)] - FullName(x509::common::SequenceOfGeneralName<'a>), - - #[implicit(1)] - NameRelativeToCRLIssuer( - x509::Asn1ReadableOrWritable< - 'a, - asn1::SetOf<'a, x509::AttributeTypeValue<'a>>, - asn1::SetOfWriter<'a, x509::AttributeTypeValue<'a>, Vec>>, - >, - ), -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) struct AuthorityKeyIdentifier<'a> { - #[implicit(0)] - pub key_identifier: Option<&'a [u8]>, - #[implicit(1)] - pub authority_cert_issuer: Option>, - #[implicit(2)] - pub authority_cert_serial_number: Option>, -} - pub(crate) fn parse_distribution_point_name( py: pyo3::Python<'_>, dp: DistributionPointName<'_>, @@ -767,21 +614,6 @@ pub(crate) fn encode_distribution_point_reasons( Ok(asn1::OwnedBitString::new(bits, unused_bits).unwrap()) } -#[derive(asn1::Asn1Read, asn1::Asn1Write, pyo3::prelude::FromPyObject)] -pub(crate) struct BasicConstraints { - #[default(false)] - pub ca: bool, - pub path_length: Option, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) struct PolicyConstraints { - #[implicit(0)] - pub require_explicit_policy: Option, - #[implicit(1)] - pub inhibit_policy_mapping: Option, -} - pub(crate) fn parse_authority_key_identifier<'p>( py: pyo3::Python<'p>, ext_data: &[u8], @@ -807,7 +639,7 @@ pub(crate) fn parse_access_descriptions( ) -> Result { let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; let ads = pyo3::types::PyList::empty(py); - let parsed = asn1::parse_single::>(ext_data)?; + let parsed = asn1::parse_single::>(ext_data)?; for access in parsed.unwrap_read().clone() { let py_oid = oid_to_py_oid(py, &access.access_method)?.to_object(py); let gn = x509::parse_general_name(py, access.access_location)?; @@ -829,7 +661,7 @@ pub fn parse_cert_ext<'p>( match oid { oid::SUBJECT_ALTERNATIVE_NAME_OID => { let gn_seq = - asn1::parse_single::>>(ext_data)?; + asn1::parse_single::>>(ext_data)?; let sans = x509::parse_general_names(py, &gn_seq)?; Ok(Some( x509_module @@ -839,7 +671,7 @@ pub fn parse_cert_ext<'p>( } oid::ISSUER_ALTERNATIVE_NAME_OID => { let gn_seq = - asn1::parse_single::>>(ext_data)?; + asn1::parse_single::>>(ext_data)?; let ians = x509::parse_general_names(py, &gn_seq)?; Ok(Some( x509_module @@ -1016,16 +848,18 @@ pub fn parse_cert_ext<'p>( pub(crate) fn time_from_py( py: pyo3::Python<'_>, val: &pyo3::PyAny, -) -> CryptographyResult { +) -> CryptographyResult { let dt = x509::py_to_datetime(py, val)?; time_from_datetime(dt) } -pub(crate) fn time_from_datetime(dt: asn1::DateTime) -> CryptographyResult { +pub(crate) fn time_from_datetime(dt: asn1::DateTime) -> CryptographyResult { if dt.year() >= 2050 { - Ok(x509::Time::GeneralizedTime(asn1::GeneralizedTime::new(dt)?)) + Ok(common::Time::GeneralizedTime(asn1::GeneralizedTime::new( + dt, + )?)) } else { - Ok(x509::Time::UtcTime(asn1::UtcTime::new(dt).unwrap())) + Ok(common::Time::UtcTime(asn1::UtcTime::new(dt).unwrap())) } } @@ -1065,7 +899,7 @@ fn create_x509_certificate( let py_not_before = builder.getattr(pyo3::intern!(py, "_not_valid_before"))?; let py_not_after = builder.getattr(pyo3::intern!(py, "_not_valid_after"))?; - let tbs_cert = TbsCertificate { + let tbs_cert = cryptography_x509::certificate::TbsCertificate { version: builder .getattr(pyo3::intern!(py, "_version"))? .getattr(pyo3::intern!(py, "value"))? @@ -1073,7 +907,7 @@ fn create_x509_certificate( serial: asn1::BigInt::new(py_uint_to_big_endian_bytes(py, py_serial)?).unwrap(), signature_alg: sigalg.clone(), issuer: x509::common::encode_name(py, py_issuer_name)?, - validity: Validity { + validity: cryptography_x509::certificate::Validity { not_before: time_from_py(py, py_not_before)?, not_after: time_from_py(py, py_not_after)?, }, @@ -1090,7 +924,7 @@ fn create_x509_certificate( let tbs_bytes = asn1::write_single(&tbs_cert)?; let signature = x509::sign::sign_data(py, private_key, hash_algorithm, &tbs_bytes)?; - let data = asn1::write_single(&RawCertificate { + let data = asn1::write_single(&cryptography_x509::certificate::Certificate { tbs_cert, signature_alg: sigalg, signature: asn1::BitString::new(signature, 0).unwrap(), diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index 3d4aec39cc71..4d977a921172 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -5,10 +5,14 @@ use crate::asn1::{oid_to_py_oid, py_oid_to_oid}; use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; +use cryptography_x509::common::{Asn1ReadableOrWritable, AttributeTypeValue, RawTlv}; +use cryptography_x509::extensions::{ + AccessDescription, Extension, Extensions, SequenceOfAccessDescriptions, +}; +use cryptography_x509::name::{GeneralName, Name, OtherName, UnvalidatedIA5String}; use pyo3::types::IntoPyDict; use pyo3::ToPyObject; use std::collections::HashSet; -use std::marker::PhantomData; /// Parse all sections in a PEM file and return the first matching section. /// If no matching sections are found, return an error. @@ -26,58 +30,6 @@ pub(crate) fn find_in_pem( }) } -pub(crate) type Name<'a> = Asn1ReadableOrWritable< - 'a, - asn1::SequenceOf<'a, asn1::SetOf<'a, AttributeTypeValue<'a>>>, - asn1::SequenceOfWriter< - 'a, - asn1::SetOfWriter<'a, AttributeTypeValue<'a>, Vec>>, - Vec, Vec>>>, - >, ->; - -#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Eq, Hash, Clone)] -pub(crate) struct AttributeTypeValue<'a> { - pub(crate) type_id: asn1::ObjectIdentifier, - pub(crate) value: RawTlv<'a>, -} - -// Like `asn1::Tlv` but doesn't store `full_data` so it can be constructed from -// an un-encoded tag and value. -#[derive(Hash, PartialEq, Eq, Clone)] -pub(crate) struct RawTlv<'a> { - tag: asn1::Tag, - value: &'a [u8], -} - -impl<'a> RawTlv<'a> { - pub(crate) fn new(tag: asn1::Tag, value: &'a [u8]) -> Self { - RawTlv { tag, value } - } - - pub(crate) fn tag(&self) -> asn1::Tag { - self.tag - } - pub(crate) fn data(&self) -> &'a [u8] { - self.value - } -} -impl<'a> asn1::Asn1Readable<'a> for RawTlv<'a> { - fn parse(parser: &mut asn1::Parser<'a>) -> asn1::ParseResult { - let tlv = parser.read_element::>()?; - Ok(RawTlv::new(tlv.tag(), tlv.data())) - } - - fn can_parse(_tag: asn1::Tag) -> bool { - true - } -} -impl<'a> asn1::Asn1Writable for RawTlv<'a> { - fn write(&self, w: &mut asn1::Writer<'_>) -> asn1::WriteResult { - w.write_tlv(self.tag, move |dest| dest.push_slice(self.value)) - } -} - pub(crate) fn encode_name<'p>( py: pyo3::Python<'p>, py_name: &'p pyo3::PyAny, @@ -145,73 +97,6 @@ fn encode_name_bytes<'p>( Ok(pyo3::types::PyBytes::new(py, &result)) } -/// An IA5String ASN.1 element whose contents is not validated as meeting the -/// requirements (ASCII characters only), and instead is only known to be -/// valid UTF-8. -pub(crate) struct UnvalidatedIA5String<'a>(pub(crate) &'a str); - -impl<'a> asn1::SimpleAsn1Readable<'a> for UnvalidatedIA5String<'a> { - const TAG: asn1::Tag = asn1::IA5String::TAG; - fn parse_data(data: &'a [u8]) -> asn1::ParseResult { - Ok(UnvalidatedIA5String(std::str::from_utf8(data).map_err( - |_| asn1::ParseError::new(asn1::ParseErrorKind::InvalidValue), - )?)) - } -} - -impl<'a> asn1::SimpleAsn1Writable for UnvalidatedIA5String<'a> { - const TAG: asn1::Tag = asn1::IA5String::TAG; - fn write_data(&self, dest: &mut asn1::WriteBuf) -> asn1::WriteResult { - dest.push_slice(self.0.as_bytes()) - } -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash)] -pub(crate) struct OtherName<'a> { - pub(crate) type_id: asn1::ObjectIdentifier, - #[explicit(0, required)] - pub(crate) value: asn1::Tlv<'a>, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) enum GeneralName<'a> { - #[implicit(0)] - OtherName(OtherName<'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), -} - -pub(crate) type SequenceOfGeneralName<'a> = Asn1ReadableOrWritable< - 'a, - asn1::SequenceOf<'a, GeneralName<'a>>, - asn1::SequenceOfWriter<'a, GeneralName<'a>, Vec>>, ->; - pub(crate) fn encode_general_names<'a>( py: pyo3::Python<'a>, py_gns: &'a pyo3::PyAny, @@ -271,18 +156,6 @@ pub(crate) fn encode_general_name<'a>( } } -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) struct AccessDescription<'a> { - pub(crate) access_method: asn1::ObjectIdentifier, - pub(crate) access_location: GeneralName<'a>, -} - -pub(crate) type SequenceOfAccessDescriptions<'a> = Asn1ReadableOrWritable< - 'a, - asn1::SequenceOf<'a, AccessDescription<'a>>, - asn1::SequenceOfWriter<'a, AccessDescription<'a>, Vec>>, ->; - pub(crate) fn encode_access_descriptions<'a>( py: pyo3::Python<'a>, py_ads: &'a pyo3::PyAny, @@ -303,41 +176,6 @@ pub(crate) fn encode_access_descriptions<'a>( )) } -#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash, Clone)] -pub(crate) enum Time { - UtcTime(asn1::UtcTime), - GeneralizedTime(asn1::GeneralizedTime), -} - -impl Time { - pub(crate) fn as_datetime(&self) -> &asn1::DateTime { - match self { - Time::UtcTime(data) => data.as_datetime(), - Time::GeneralizedTime(data) => data.as_datetime(), - } - } -} - -pub(crate) type Extensions<'a> = Asn1ReadableOrWritable< - 'a, - asn1::SequenceOf<'a, Extension<'a>>, - asn1::SequenceOfWriter<'a, Extension<'a>, Vec>>, ->; - -#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash, Clone)] -pub(crate) struct AlgorithmIdentifier<'a> { - pub(crate) oid: asn1::ObjectIdentifier, - pub(crate) params: Option>, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Eq, Hash, Clone)] -pub(crate) struct Extension<'a> { - pub(crate) extn_id: asn1::ObjectIdentifier, - #[default(false)] - pub(crate) critical: bool, - pub(crate) extn_value: &'a [u8], -} - pub(crate) fn parse_name<'p>( py: pyo3::Python<'p>, name: &Name<'_>, @@ -723,77 +561,9 @@ pub(crate) fn datetime_now(py: pyo3::Python<'_>) -> pyo3::PyResult { - Read(T, PhantomData<&'a ()>), - Write(U, PhantomData<&'a ()>), -} - -impl<'a, T, U> Asn1ReadableOrWritable<'a, T, U> { - pub(crate) fn new_read(v: T) -> Self { - Asn1ReadableOrWritable::Read(v, PhantomData) - } - - pub(crate) fn new_write(v: U) -> Self { - Asn1ReadableOrWritable::Write(v, PhantomData) - } - - pub(crate) fn unwrap_read(&self) -> &T { - match self { - Asn1ReadableOrWritable::Read(v, _) => v, - Asn1ReadableOrWritable::Write(_, _) => panic!("unwrap_read called on a Write value"), - } - } -} - -impl<'a, T: asn1::SimpleAsn1Readable<'a>, U> asn1::SimpleAsn1Readable<'a> - for Asn1ReadableOrWritable<'a, T, U> -{ - const TAG: asn1::Tag = T::TAG; - fn parse_data(data: &'a [u8]) -> asn1::ParseResult { - Ok(Self::new_read(T::parse_data(data)?)) - } -} - -impl<'a, T: asn1::SimpleAsn1Writable, U: asn1::SimpleAsn1Writable> asn1::SimpleAsn1Writable - for Asn1ReadableOrWritable<'a, T, U> -{ - const TAG: asn1::Tag = U::TAG; - fn write_data(&self, w: &mut asn1::WriteBuf) -> asn1::WriteResult { - match self { - Asn1ReadableOrWritable::Read(v, _) => T::write_data(v, w), - Asn1ReadableOrWritable::Write(v, _) => U::write_data(v, w), - } - } -} - pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { module.add_wrapped(pyo3::wrap_pyfunction!(encode_extension_value))?; module.add_wrapped(pyo3::wrap_pyfunction!(encode_name_bytes))?; Ok(()) } - -#[cfg(test)] -mod tests { - use super::{Asn1ReadableOrWritable, RawTlv}; - use asn1::Asn1Readable; - - #[test] - #[should_panic] - fn test_asn1_readable_or_writable_unwrap_read() { - Asn1ReadableOrWritable::::new_write(17).unwrap_read(); - } - - #[test] - fn test_asn1_readable_or_writable_write_read_data() { - let v = Asn1ReadableOrWritable::::new_read(17); - assert_eq!(&asn1::write_single(&v).unwrap(), b"\x02\x01\x11"); - } - - #[test] - fn test_raw_tlv_can_parse() { - let t = asn1::Tag::from_bytes(&[0]).unwrap().0; - assert!(RawTlv::can_parse(t)); - } -} diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index f5ab1b0c02da..ea04bb984766 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -7,7 +7,8 @@ use crate::asn1::{ }; use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; -use crate::x509::{certificate, extensions, oid, sign}; +use crate::x509::{certificate, extensions, sign}; +use cryptography_x509::{common, crl, name, oid}; use pyo3::{IntoPy, ToPyObject}; use std::sync::Arc; @@ -16,13 +17,13 @@ fn load_der_x509_crl( py: pyo3::Python<'_>, data: pyo3::Py, ) -> Result { - let raw = OwnedRawCertificateRevocationList::try_new( + let owned = OwnedCertificateRevocationList::try_new( data, |data| asn1::parse_single(data.as_bytes(py)), |_| Ok(pyo3::once_cell::GILOnceCell::new()), )?; - let version = raw.borrow_value().tbs_cert_list.version.unwrap_or(1); + let version = owned.borrow_value().tbs_cert_list.version.unwrap_or(1); if version != 1 { let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; return Err(CryptographyError::from(pyo3::PyErr::from_value( @@ -33,7 +34,7 @@ fn load_der_x509_crl( } Ok(CertificateRevocationList { - raw: Arc::new(raw), + owned: Arc::new(owned), cached_extensions: None, }) } @@ -55,41 +56,41 @@ fn load_pem_x509_crl( } #[ouroboros::self_referencing] -struct OwnedRawCertificateRevocationList { +struct OwnedCertificateRevocationList { data: pyo3::Py, #[borrows(data)] #[covariant] - value: RawCertificateRevocationList<'this>, + value: crl::CertificateRevocationList<'this>, #[borrows(data)] #[not_covariant] - revoked_certs: pyo3::once_cell::GILOnceCell>>, + revoked_certs: pyo3::once_cell::GILOnceCell>>, } #[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")] struct CertificateRevocationList { - raw: Arc, + owned: Arc, cached_extensions: Option, } impl CertificateRevocationList { fn public_bytes_der(&self) -> CryptographyResult> { - Ok(asn1::write_single(self.raw.borrow_value())?) + Ok(asn1::write_single(self.owned.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 owned = try_map_arc_data_crl(&self.owned, |_crl, revoked_certs| { let revoked_certs = revoked_certs.get(py).unwrap(); Ok::<_, pyo3::PyErr>(revoked_certs[idx].clone()) })?; Ok(RevokedCertificate { - raw, + owned, cached_extensions: None, }) } fn len(&self) -> usize { - self.raw + self.owned .borrow_value() .tbs_cert_list .revoked_certificates @@ -106,8 +107,12 @@ impl CertificateRevocationList { op: pyo3::basic::CompareOp, ) -> pyo3::PyResult { match op { - pyo3::basic::CompareOp::Eq => Ok(self.raw.borrow_value() == other.raw.borrow_value()), - pyo3::basic::CompareOp::Ne => Ok(self.raw.borrow_value() != other.raw.borrow_value()), + pyo3::basic::CompareOp::Eq => { + Ok(self.owned.borrow_value() == other.owned.borrow_value()) + } + pyo3::basic::CompareOp::Ne => { + Ok(self.owned.borrow_value() != other.owned.borrow_value()) + } _ => Err(pyo3::exceptions::PyTypeError::new_err( "CRLs cannot be ordered", )), @@ -120,7 +125,7 @@ impl CertificateRevocationList { fn __iter__(&self) -> CRLIterator { CRLIterator { - contents: OwnedCRLIteratorData::try_new(Arc::clone(&self.raw), |v| { + contents: OwnedCRLIteratorData::try_new(Arc::clone(&self.owned), |v| { Ok::<_, ()>( v.borrow_value() .tbs_cert_list @@ -138,7 +143,7 @@ impl CertificateRevocationList { py: pyo3::Python<'_>, idx: &pyo3::PyAny, ) -> pyo3::PyResult { - self.raw.with(|val| { + self.owned.with(|val| { val.revoked_certs.get_or_init(py, || { match &val.value.tbs_cert_list.revoked_certificates { Some(c) => c.unwrap_read().clone().collect(), @@ -186,7 +191,7 @@ impl CertificateRevocationList { #[getter] fn signature_algorithm_oid<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - oid_to_py_oid(py, &self.raw.borrow_value().signature_algorithm.oid) + oid_to_py_oid(py, &self.owned.borrow_value().signature_algorithm.oid) } #[getter] @@ -206,7 +211,7 @@ impl CertificateRevocationList { "UnsupportedAlgorithm", (format!( "Signature algorithm OID:{} not recognized", - self.raw.borrow_value().signature_algorithm.oid + self.owned.borrow_value().signature_algorithm.oid ),), )?)), } @@ -214,7 +219,7 @@ impl CertificateRevocationList { #[getter] fn signature(&self) -> &[u8] { - self.raw.borrow_value().signature_value.as_bytes() + self.owned.borrow_value().signature_value.as_bytes() } #[getter] @@ -222,7 +227,7 @@ impl CertificateRevocationList { &self, py: pyo3::Python<'p>, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - let b = asn1::write_single(&self.raw.borrow_value().tbs_cert_list)?; + let b = asn1::write_single(&self.owned.borrow_value().tbs_cert_list)?; Ok(pyo3::types::PyBytes::new(py, &b)) } @@ -231,7 +236,7 @@ impl CertificateRevocationList { py: pyo3::Python<'p>, encoding: &'p pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - let result = asn1::write_single(self.raw.borrow_value())?; + let result = asn1::write_single(self.owned.borrow_value())?; encode_der_data(py, "X509 CRL".to_string(), result, encoding) } @@ -240,13 +245,13 @@ impl CertificateRevocationList { fn issuer<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { Ok(x509::parse_name( py, - &self.raw.borrow_value().tbs_cert_list.issuer, + &self.owned.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 { + match &self.owned.borrow_value().tbs_cert_list.next_update { Some(t) => x509::datetime_to_py(py, t.as_datetime()), None => Ok(py.None().into_ref(py)), } @@ -256,7 +261,7 @@ impl CertificateRevocationList { fn last_update<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { x509::datetime_to_py( py, - self.raw + self.owned .borrow_value() .tbs_cert_list .this_update @@ -270,7 +275,7 @@ impl CertificateRevocationList { x509::parse_and_cache_extensions( py, &mut self.cached_extensions, - &self.raw.borrow_value().tbs_cert_list.crl_extensions, + &self.owned.borrow_value().tbs_cert_list.crl_extensions, |oid, ext_data| match *oid { oid::CRL_NUMBER_OID => { let bignum = asn1::parse_single::>(ext_data)?; @@ -291,7 +296,7 @@ impl CertificateRevocationList { )) } oid::ISSUER_ALTERNATIVE_NAME_OID => { - let gn_seq = asn1::parse_single::>>( + let gn_seq = asn1::parse_single::>>( ext_data, )?; let ians = x509::parse_general_names(py, &gn_seq)?; @@ -313,7 +318,7 @@ impl CertificateRevocationList { certificate::parse_authority_key_identifier(py, ext_data)?, )), oid::ISSUING_DISTRIBUTION_POINT_OID => { - let idp = asn1::parse_single::>(ext_data)?; + let idp = asn1::parse_single::>(ext_data)?; let (full_name, relative_name) = match idp.distribution_point { Some(data) => certificate::parse_distribution_point_name(py, data)?, None => (py.None(), py.None()), @@ -359,7 +364,7 @@ impl CertificateRevocationList { 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 owned = OwnedRevokedCertificate::try_new(Arc::clone(&self.owned), |v| { let certs = match &v.borrow_value().tbs_cert_list.revoked_certificates { Some(certs) => certs.unwrap_read().clone(), None => return Err(()), @@ -375,7 +380,7 @@ impl CertificateRevocationList { }); match owned { Ok(o) => Ok(Some(RevokedCertificate { - raw: o, + owned: o, cached_extensions: None, })), Err(()) => Ok(None), @@ -387,8 +392,8 @@ impl CertificateRevocationList { py: pyo3::Python<'p>, public_key: &'p pyo3::PyAny, ) -> CryptographyResult { - if slf.raw.borrow_value().tbs_cert_list.signature - != slf.raw.borrow_value().signature_algorithm + if slf.owned.borrow_value().tbs_cert_list.signature + != slf.owned.borrow_value().signature_algorithm { return Ok(false); }; @@ -400,9 +405,9 @@ impl CertificateRevocationList { Ok(sign::verify_signature_with_oid( py, public_key, - &slf.raw.borrow_value().signature_algorithm.oid, - slf.raw.borrow_value().signature_value.as_bytes(), - &asn1::write_single(&slf.raw.borrow_value().tbs_cert_list)?, + &slf.owned.borrow_value().signature_algorithm.oid, + slf.owned.borrow_value().signature_value.as_bytes(), + &asn1::write_single(&slf.owned.borrow_value().tbs_cert_list)?, ) .is_ok()) } @@ -410,10 +415,10 @@ impl CertificateRevocationList { #[ouroboros::self_referencing] struct OwnedCRLIteratorData { - data: Arc, + data: Arc, #[borrows(data)] #[covariant] - value: Option>>, + value: Option>>, } #[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")] @@ -424,13 +429,13 @@ struct CRLIterator { // Open-coded implementation of the API discussed in // https://github.com/joshua-maros/ouroboros/issues/38 fn try_map_arc_data_crl( - crl: &Arc, + crl: &Arc, f: impl for<'this> FnOnce( - &'this OwnedRawCertificateRevocationList, - &pyo3::once_cell::GILOnceCell>>, - ) -> Result, E>, -) -> Result { - OwnedRawRevokedCertificate::try_new(Arc::clone(crl), |inner_crl| { + &'this OwnedCertificateRevocationList, + &pyo3::once_cell::GILOnceCell>>, + ) -> Result, E>, +) -> Result { + OwnedRevokedCertificate::try_new(Arc::clone(crl), |inner_crl| { crl.with(|value| { f(inner_crl, unsafe { std::mem::transmute(value.revoked_certs) @@ -441,11 +446,11 @@ fn try_map_arc_data_crl( 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| { + &'this OwnedCertificateRevocationList, + &mut Option>>, + ) -> Result, E>, +) -> Result { + OwnedRevokedCertificate::try_new(Arc::clone(it.borrow_data()), |inner_it| { it.with_value_mut(|value| f(inner_it, unsafe { std::mem::transmute(value) })) }) } @@ -470,57 +475,23 @@ impl CRLIterator { }) .ok()?; Some(RevokedCertificate { - raw: revoked, + owned: revoked, cached_extensions: None, }) } } -#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash)] -struct RawCertificateRevocationList<'a> { - tbs_cert_list: TBSCertList<'a>, - signature_algorithm: x509::AlgorithmIdentifier<'a>, - signature_value: asn1::BitString<'a>, -} - -type RevokedCertificates<'a> = Option< - x509::Asn1ReadableOrWritable< - 'a, - asn1::SequenceOf<'a, RawRevokedCertificate<'a>>, - asn1::SequenceOfWriter<'a, RawRevokedCertificate<'a>, Vec>>, - >, ->; - -#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash)] -struct TBSCertList<'a> { - version: Option, - signature: x509::AlgorithmIdentifier<'a>, - issuer: x509::Name<'a>, - this_update: x509::Time, - next_update: Option, - revoked_certificates: RevokedCertificates<'a>, - #[explicit(0)] - crl_extensions: Option>, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash, Clone)] -struct RawRevokedCertificate<'a> { - user_certificate: asn1::BigUint<'a>, - revocation_date: x509::Time, - crl_entry_extensions: Option>, -} - #[ouroboros::self_referencing] -struct OwnedRawRevokedCertificate { - data: Arc, +struct OwnedRevokedCertificate { + data: Arc, #[borrows(data)] #[covariant] - value: RawRevokedCertificate<'this>, + value: crl::RevokedCertificate<'this>, } #[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")] struct RevokedCertificate { - raw: OwnedRawRevokedCertificate, + owned: OwnedRevokedCertificate, cached_extensions: Option, } @@ -528,12 +499,12 @@ struct RevokedCertificate { impl RevokedCertificate { #[getter] fn serial_number<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - big_byte_slice_to_py_int(py, self.raw.borrow_value().user_certificate.as_bytes()) + big_byte_slice_to_py_int(py, self.owned.borrow_value().user_certificate.as_bytes()) } #[getter] fn revocation_date<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - x509::datetime_to_py(py, self.raw.borrow_value().revocation_date.as_datetime()) + x509::datetime_to_py(py, self.owned.borrow_value().revocation_date.as_datetime()) } #[getter] @@ -541,45 +512,15 @@ impl RevokedCertificate { x509::parse_and_cache_extensions( py, &mut self.cached_extensions, - &self.raw.borrow_value().crl_entry_extensions, + &self.owned.borrow_value().crl_entry_extensions, |oid, ext_data| parse_crl_entry_ext(py, oid.clone(), ext_data), ) } } -pub(crate) type ReasonFlags<'a> = - Option, asn1::OwnedBitString>>; - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) struct IssuingDistributionPoint<'a> { - #[explicit(0)] - pub distribution_point: Option>, - - #[implicit(1)] - #[default(false)] - pub only_contains_user_certs: bool, - - #[implicit(2)] - #[default(false)] - pub only_contains_ca_certs: bool, - - #[implicit(3)] - pub only_some_reasons: ReasonFlags<'a>, - - #[implicit(4)] - #[default(false)] - pub indirect_crl: bool, - - #[implicit(5)] - #[default(false)] - pub only_contains_attribute_certs: bool, -} - -pub(crate) type CRLReason = asn1::Enumerated; - pub(crate) fn parse_crl_reason_flags<'p>( py: pyo3::Python<'p>, - reason: &CRLReason, + reason: &crl::CRLReason, ) -> CryptographyResult<&'p pyo3::PyAny> { let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; let flag_name = match reason.value() { @@ -615,7 +556,7 @@ pub fn parse_crl_entry_ext<'p>( let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; match oid { oid::CRL_REASON_OID => { - let flags = parse_crl_reason_flags(py, &asn1::parse_single::(data)?)?; + let flags = parse_crl_reason_flags(py, &asn1::parse_single::(data)?)?; Ok(Some( x509_module .getattr(pyo3::intern!(py, "CRLReason"))? @@ -623,7 +564,7 @@ pub fn parse_crl_entry_ext<'p>( )) } oid::CERTIFICATE_ISSUER_OID => { - let gn_seq = asn1::parse_single::>>(data)?; + let gn_seq = asn1::parse_single::>>(data)?; let gns = x509::parse_general_names(py, &gn_seq)?; Ok(Some( x509_module @@ -663,7 +604,7 @@ fn create_x509_crl( .getattr(pyo3::intern!(py, "serial_number"))? .extract()?; let py_revocation_date = py_revoked_cert.getattr(pyo3::intern!(py, "revocation_date"))?; - revoked_certs.push(RawRevokedCertificate { + revoked_certs.push(crl::RevokedCertificate { user_certificate: asn1::BigUint::new(py_uint_to_big_endian_bytes(py, serial_number)?) .unwrap(), revocation_date: x509::certificate::time_from_py(py, py_revocation_date)?, @@ -678,7 +619,7 @@ fn create_x509_crl( let py_issuer_name = builder.getattr(pyo3::intern!(py, "_issuer_name"))?; let py_this_update = builder.getattr(pyo3::intern!(py, "_last_update"))?; let py_next_update = builder.getattr(pyo3::intern!(py, "_next_update"))?; - let tbs_cert_list = TBSCertList { + let tbs_cert_list = crl::TBSCertList { version: Some(1), signature: sigalg.clone(), issuer: x509::common::encode_name(py, py_issuer_name)?, @@ -687,7 +628,7 @@ fn create_x509_crl( revoked_certificates: if revoked_certs.is_empty() { None } else { - Some(x509::Asn1ReadableOrWritable::new_write( + Some(common::Asn1ReadableOrWritable::new_write( asn1::SequenceOfWriter::new(revoked_certs), )) }, @@ -700,7 +641,7 @@ fn create_x509_crl( let tbs_bytes = asn1::write_single(&tbs_cert_list)?; let signature = x509::sign::sign_data(py, private_key, hash_algorithm, &tbs_bytes)?; - let data = asn1::write_single(&RawCertificateRevocationList { + let data = asn1::write_single(&crl::CertificateRevocationList { tbs_cert_list, signature_algorithm: sigalg, signature_value: asn1::BitString::new(signature, 0).unwrap(), diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index 2122018e069c..6de3667ae4fd 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -5,83 +5,25 @@ use crate::asn1::{encode_der_data, oid_to_py_oid, py_oid_to_oid}; use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; -use crate::x509::{certificate, oid, sign}; +use crate::x509::{certificate, sign}; use asn1::SimpleAsn1Readable; +use cryptography_x509::csr::{check_attribute_length, Attribute, CertificationRequestInfo, Csr}; +use cryptography_x509::{common, oid}; use pyo3::IntoPy; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -struct RawCsr<'a> { - csr_info: CertificationRequestInfo<'a>, - signature_alg: x509::AlgorithmIdentifier<'a>, - signature: asn1::BitString<'a>, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -struct CertificationRequestInfo<'a> { - version: u8, - subject: x509::Name<'a>, - spki: certificate::SubjectPublicKeyInfo<'a>, - #[implicit(0, required)] - attributes: Attributes<'a>, -} - -pub(crate) type Attributes<'a> = x509::Asn1ReadableOrWritable< - 'a, - asn1::SetOf<'a, Attribute<'a>>, - asn1::SetOfWriter<'a, Attribute<'a>, Vec>>, ->; - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) struct Attribute<'a> { - pub(crate) type_id: asn1::ObjectIdentifier, - pub(crate) values: x509::Asn1ReadableOrWritable< - 'a, - asn1::SetOf<'a, asn1::Tlv<'a>>, - asn1::SetOfWriter<'a, x509::common::RawTlv<'a>, [x509::common::RawTlv<'a>; 1]>, - >, -} - -fn check_attribute_length<'a>( - values: asn1::SetOf<'a, asn1::Tlv<'a>>, -) -> Result<(), CryptographyError> { - if values.count() > 1 { - Err(CryptographyError::from( - pyo3::exceptions::PyValueError::new_err("Only single-valued attributes are supported"), - )) - } else { - Ok(()) - } -} - -impl CertificationRequestInfo<'_> { - fn get_extension_attribute(&self) -> Result>, CryptographyError> { - for attribute in self.attributes.unwrap_read().clone() { - if attribute.type_id == oid::EXTENSION_REQUEST - || attribute.type_id == oid::MS_EXTENSION_REQUEST - { - check_attribute_length(attribute.values.unwrap_read().clone())?; - let val = attribute.values.unwrap_read().clone().next().unwrap(); - let exts = asn1::parse_single(val.full_data())?; - return Ok(Some(exts)); - } - } - Ok(None) - } -} - #[ouroboros::self_referencing] -struct OwnedRawCsr { +struct OwnedCsr { data: pyo3::Py, #[borrows(data)] #[covariant] - value: RawCsr<'this>, + value: Csr<'this>, } #[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")] struct CertificateSigningRequest { - raw: OwnedRawCsr, + raw: OwnedCsr, cached_extensions: Option, } @@ -212,7 +154,11 @@ impl CertificateSigningRequest { .clone() { if rust_oid == attribute.type_id { - check_attribute_length(attribute.values.unwrap_read().clone())?; + check_attribute_length(attribute.values.unwrap_read().clone()).map_err(|_| { + pyo3::exceptions::PyValueError::new_err( + "Only single-valued attributes are supported", + ) + })?; let val = attribute.values.unwrap_read().clone().next().unwrap(); // We allow utf8string, printablestring, and ia5string at this time if val.tag() == asn1::Utf8String::TAG @@ -248,7 +194,11 @@ impl CertificateSigningRequest { .unwrap_read() .clone() { - check_attribute_length(attribute.values.unwrap_read().clone())?; + check_attribute_length(attribute.values.unwrap_read().clone()).map_err(|_| { + pyo3::exceptions::PyValueError::new_err( + "Only single-valued attributes are supported", + ) + })?; let oid = oid_to_py_oid(py, &attribute.type_id)?; let val = attribute.values.unwrap_read().clone().next().unwrap(); let serialized = pyo3::types::PyBytes::new(py, val.data()); @@ -268,7 +218,16 @@ impl CertificateSigningRequest { #[getter] fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult { - let exts = self.raw.borrow_value().csr_info.get_extension_attribute()?; + let exts = self + .raw + .borrow_value() + .csr_info + .get_extension_attribute() + .map_err(|_| { + pyo3::exceptions::PyValueError::new_err( + "Only single-valued attributes are supported", + ) + })?; x509::parse_and_cache_extensions(py, &mut self.cached_extensions, &exts, |oid, ext_data| { certificate::parse_cert_ext(py, oid.clone(), ext_data) @@ -314,7 +273,7 @@ fn load_der_x509_csr( py: pyo3::Python<'_>, data: pyo3::Py, ) -> CryptographyResult { - let raw = OwnedRawCsr::try_new(data, |data| asn1::parse_single(data.as_bytes(py)))?; + let raw = OwnedCsr::try_new(data, |data| asn1::parse_single(data.as_bytes(py)))?; let version = raw.borrow_value().csr_info.version; if version != 0 { @@ -369,7 +328,7 @@ fn create_x509_csr( ext_bytes = asn1::write_single(&exts)?; attrs.push(Attribute { type_id: (oid::EXTENSION_REQUEST).clone(), - values: x509::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ + values: common::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ asn1::parse_single(&ext_bytes)?, ])), }) @@ -393,8 +352,8 @@ fn create_x509_csr( attrs.push(Attribute { type_id: oid, - values: x509::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ - x509::common::RawTlv::new(tag, value), + values: common::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ + common::RawTlv::new(tag, value), ])), }) } @@ -405,12 +364,12 @@ fn create_x509_csr( version: 0, subject: x509::common::encode_name(py, py_subject_name)?, spki: asn1::parse_single(spki_bytes)?, - attributes: x509::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new(attrs)), + attributes: common::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new(attrs)), }; let tbs_bytes = asn1::write_single(&csr_info)?; let signature = x509::sign::sign_data(py, private_key, hash_algorithm, &tbs_bytes)?; - let data = asn1::write_single(&RawCsr { + let data = asn1::write_single(&Csr { csr_info, signature_alg: sigalg, signature: asn1::BitString::new(signature, 0).unwrap(), diff --git a/src/rust/src/x509/extensions.rs b/src/rust/src/x509/extensions.rs index 84009b0c7c48..08e112cbbcf5 100644 --- a/src/rust/src/x509/extensions.rs +++ b/src/rust/src/x509/extensions.rs @@ -5,25 +5,26 @@ use crate::asn1::{py_oid_to_oid, py_uint_to_big_endian_bytes}; use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; -use crate::x509::{certificate, crl, oid, sct}; +use crate::x509::{certificate, sct}; +use cryptography_x509::{common, crl, extensions, oid}; fn encode_general_subtrees<'a>( py: pyo3::Python<'a>, subtrees: &'a pyo3::PyAny, -) -> Result>, CryptographyError> { +) -> Result>, CryptographyError> { if subtrees.is_none() { Ok(None) } else { let mut subtree_seq = vec![]; for name in subtrees.iter()? { let gn = x509::common::encode_general_name(py, name?)?; - subtree_seq.push(certificate::GeneralSubtree { + subtree_seq.push(extensions::GeneralSubtree { base: gn, minimum: 0, maximum: None, }); } - Ok(Some(x509::Asn1ReadableOrWritable::new_write( + Ok(Some(common::Asn1ReadableOrWritable::new_write( asn1::SequenceOfWriter::new(subtree_seq), ))) } @@ -32,7 +33,7 @@ fn encode_general_subtrees<'a>( pub(crate) fn encode_authority_key_identifier<'a>( py: pyo3::Python<'a>, py_aki: &'a pyo3::PyAny, -) -> pyo3::PyResult> { +) -> pyo3::PyResult> { #[derive(pyo3::prelude::FromPyObject)] struct PyAuthorityKeyIdentifier<'a> { key_identifier: Option<&'a [u8]>, @@ -42,7 +43,7 @@ pub(crate) fn encode_authority_key_identifier<'a>( let aki = py_aki.extract::>()?; let authority_cert_issuer = if let Some(authority_cert_issuer) = aki.authority_cert_issuer { let gns = x509::common::encode_general_names(py, authority_cert_issuer)?; - Some(x509::Asn1ReadableOrWritable::new_write( + Some(common::Asn1ReadableOrWritable::new_write( asn1::SequenceOfWriter::new(gns), )) } else { @@ -55,7 +56,7 @@ pub(crate) fn encode_authority_key_identifier<'a>( } else { None }; - Ok(certificate::AuthorityKeyIdentifier { + Ok(extensions::AuthorityKeyIdentifier { authority_cert_issuer, authority_cert_serial_number, key_identifier: aki.key_identifier, @@ -65,7 +66,7 @@ pub(crate) fn encode_authority_key_identifier<'a>( pub(crate) fn encode_distribution_points<'p>( py: pyo3::Python<'p>, py_dps: &'p pyo3::PyAny, -) -> pyo3::PyResult>> { +) -> pyo3::PyResult>> { #[derive(pyo3::prelude::FromPyObject)] struct PyDistributionPoint<'a> { crl_issuer: Option<&'a pyo3::PyAny>, @@ -80,7 +81,7 @@ pub(crate) fn encode_distribution_points<'p>( let crl_issuer = if let Some(py_crl_issuer) = py_dp.crl_issuer { let gns = x509::common::encode_general_names(py, py_crl_issuer)?; - Some(x509::Asn1ReadableOrWritable::new_write( + Some(common::Asn1ReadableOrWritable::new_write( asn1::SequenceOfWriter::new(gns), )) } else { @@ -88,27 +89,27 @@ pub(crate) fn encode_distribution_points<'p>( }; let distribution_point = if let Some(py_full_name) = py_dp.full_name { let gns = x509::common::encode_general_names(py, py_full_name)?; - Some(certificate::DistributionPointName::FullName( - x509::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new(gns)), + Some(extensions::DistributionPointName::FullName( + common::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new(gns)), )) } else if let Some(py_relative_name) = py_dp.relative_name { let mut name_entries = vec![]; for py_name_entry in py_relative_name.iter()? { name_entries.push(x509::common::encode_name_entry(py, py_name_entry?)?); } - Some(certificate::DistributionPointName::NameRelativeToCRLIssuer( - x509::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new(name_entries)), + Some(extensions::DistributionPointName::NameRelativeToCRLIssuer( + common::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new(name_entries)), )) } else { None }; let reasons = if let Some(py_reasons) = py_dp.reasons { let reasons = certificate::encode_distribution_point_reasons(py, py_reasons)?; - Some(x509::Asn1ReadableOrWritable::new_write(reasons)) + Some(common::Asn1ReadableOrWritable::new_write(reasons)) } else { None }; - dps.push(certificate::DistributionPoint { + dps.push(extensions::DistributionPoint { crl_issuer, distribution_point, reasons, @@ -124,7 +125,16 @@ pub(crate) fn encode_extension( ) -> CryptographyResult>> { match oid { &oid::BASIC_CONSTRAINTS_OID => { - let bc = ext.extract::()?; + #[derive(pyo3::prelude::FromPyObject)] + struct PyBasicConstraints { + ca: bool, + path_length: Option, + } + let pybc = ext.extract::()?; + let bc = extensions::BasicConstraints { + ca: pybc.ca, + path_length: pybc.path_length, + }; Ok(Some(asn1::write_single(&bc)?)) } &oid::SUBJECT_KEY_IDENTIFIER_OID => { @@ -232,9 +242,9 @@ pub(crate) fn encode_extension( .into()) } }; - certificate::PolicyQualifierInfo { + extensions::PolicyQualifierInfo { policy_qualifier_id: (oid::CP_CPS_URI_OID).clone(), - qualifier: certificate::Qualifier::CpsUri(cps_uri), + qualifier: extensions::Qualifier::CpsUri(cps_uri), } } else { let py_notice = @@ -250,15 +260,15 @@ pub(crate) fn encode_extension( notice_numbers.push(asn1::BigUint::new(bytes).unwrap()); } - Some(certificate::NoticeReference { - organization: certificate::DisplayText::Utf8String( + Some(extensions::NoticeReference { + organization: extensions::DisplayText::Utf8String( asn1::Utf8String::new( py_notice .getattr(pyo3::intern!(py, "organization"))? .extract()?, ), ), - notice_numbers: x509::Asn1ReadableOrWritable::new_write( + notice_numbers: common::Asn1ReadableOrWritable::new_write( asn1::SequenceOfWriter::new(notice_numbers), ), }) @@ -268,17 +278,17 @@ pub(crate) fn encode_extension( let py_explicit_text = py_qualifier.getattr(pyo3::intern!(py, "explicit_text"))?; let explicit_text = if py_explicit_text.is_true()? { - Some(certificate::DisplayText::Utf8String(asn1::Utf8String::new( + Some(extensions::DisplayText::Utf8String(asn1::Utf8String::new( py_explicit_text.extract()?, ))) } else { None }; - certificate::PolicyQualifierInfo { + extensions::PolicyQualifierInfo { policy_qualifier_id: (oid::CP_USER_NOTICE_OID).clone(), - qualifier: certificate::Qualifier::UserNotice( - certificate::UserNotice { + qualifier: extensions::Qualifier::UserNotice( + extensions::UserNotice { notice_ref, explicit_text, }, @@ -287,7 +297,7 @@ pub(crate) fn encode_extension( }; qualifiers.push(qualifier); } - Some(x509::Asn1ReadableOrWritable::new_write( + Some(common::Asn1ReadableOrWritable::new_write( asn1::SequenceOfWriter::new(qualifiers), )) } else { @@ -295,7 +305,7 @@ pub(crate) fn encode_extension( }; let py_policy_id = py_policy_info.getattr(pyo3::intern!(py, "policy_identifier"))?; - policy_informations.push(certificate::PolicyInformation { + policy_informations.push(extensions::PolicyInformation { policy_identifier: py_oid_to_oid(py_policy_id)?, policy_qualifiers: qualifiers, }); @@ -305,7 +315,7 @@ pub(crate) fn encode_extension( ))?)) } &oid::POLICY_CONSTRAINTS_OID => { - let pc = certificate::PolicyConstraints { + let pc = extensions::PolicyConstraints { require_explicit_policy: ext .getattr(pyo3::intern!(py, "require_explicit_policy"))? .extract()?, @@ -318,7 +328,7 @@ pub(crate) fn encode_extension( &oid::NAME_CONSTRAINTS_OID => { let permitted = ext.getattr(pyo3::intern!(py, "permitted_subtrees"))?; let excluded = ext.getattr(pyo3::intern!(py, "excluded_subtrees"))?; - let nc = certificate::NameConstraints { + let nc = extensions::NameConstraints { permitted_subtrees: encode_general_subtrees(ext.py(), permitted)?, excluded_subtrees: encode_general_subtrees(ext.py(), excluded)?, }; @@ -412,23 +422,23 @@ pub(crate) fn encode_extension( { let py_reasons = ext.getattr(pyo3::intern!(py, "only_some_reasons"))?; let reasons = certificate::encode_distribution_point_reasons(ext.py(), py_reasons)?; - Some(x509::Asn1ReadableOrWritable::new_write(reasons)) + Some(common::Asn1ReadableOrWritable::new_write(reasons)) } else { None }; let distribution_point = if ext.getattr(pyo3::intern!(py, "full_name"))?.is_true()? { let py_full_name = ext.getattr(pyo3::intern!(py, "full_name"))?; let gns = x509::common::encode_general_names(ext.py(), py_full_name)?; - Some(certificate::DistributionPointName::FullName( - x509::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new(gns)), + Some(extensions::DistributionPointName::FullName( + common::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new(gns)), )) } else if ext.getattr(pyo3::intern!(py, "relative_name"))?.is_true()? { let mut name_entries = vec![]; for py_name_entry in ext.getattr(pyo3::intern!(py, "relative_name"))?.iter()? { name_entries.push(x509::common::encode_name_entry(ext.py(), py_name_entry?)?); } - Some(certificate::DistributionPointName::NameRelativeToCRLIssuer( - x509::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new(name_entries)), + Some(extensions::DistributionPointName::NameRelativeToCRLIssuer( + common::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new(name_entries)), )) } else { None @@ -458,7 +468,7 @@ pub(crate) fn encode_extension( } &oid::MS_CERTIFICATE_TEMPLATE => { let py_template_id = ext.getattr(pyo3::intern!(py, "template_id"))?; - let mstpl = certificate::MSCertificateTemplate { + let mstpl = extensions::MSCertificateTemplate { template_id: py_oid_to_oid(py_template_id)?, major_version: ext.getattr(pyo3::intern!(py, "major_version"))?.extract()?, minor_version: ext.getattr(pyo3::intern!(py, "minor_version"))?.extract()?, diff --git a/src/rust/src/x509/mod.rs b/src/rust/src/x509/mod.rs index 2ad15c6e6dbc..c43bf9023e71 100644 --- a/src/rust/src/x509/mod.rs +++ b/src/rust/src/x509/mod.rs @@ -10,13 +10,10 @@ pub(crate) mod extensions; pub(crate) mod ocsp; pub(crate) mod ocsp_req; pub(crate) mod ocsp_resp; -pub(crate) mod oid; pub(crate) mod sct; pub(crate) mod sign; -pub(crate) use certificate::Certificate; pub(crate) use common::{ datetime_to_py, find_in_pem, parse_and_cache_extensions, parse_general_name, - parse_general_names, parse_name, parse_rdn, py_to_datetime, AlgorithmIdentifier, - Asn1ReadableOrWritable, AttributeTypeValue, Extensions, GeneralName, Name, Time, + parse_general_names, parse_name, parse_rdn, py_to_datetime, }; diff --git a/src/rust/src/x509/ocsp.rs b/src/rust/src/x509/ocsp.rs index e3568ca9df8b..b362ef326d8d 100644 --- a/src/rust/src/x509/ocsp.rs +++ b/src/rust/src/x509/ocsp.rs @@ -4,7 +4,9 @@ use crate::error::CryptographyResult; use crate::x509; -use crate::x509::oid; +use crate::x509::certificate::Certificate; +use cryptography_x509::ocsp_req::CertID; +use cryptography_x509::{common, oid}; use once_cell::sync::Lazy; use std::collections::HashMap; @@ -28,69 +30,59 @@ pub(crate) static HASH_NAME_TO_OIDS: Lazy h }); -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -pub(crate) struct CertID<'a> { - pub(crate) hash_algorithm: x509::AlgorithmIdentifier<'a>, - pub(crate) issuer_name_hash: &'a [u8], - pub(crate) issuer_key_hash: &'a [u8], - pub(crate) serial_number: asn1::BigInt<'a>, -} - -impl CertID<'_> { - pub(crate) fn new<'p>( - py: pyo3::Python<'p>, - cert: &'p x509::Certificate, - issuer: &'p x509::Certificate, - hash_algorithm: &'p pyo3::PyAny, - ) -> CryptographyResult> { - let issuer_der = asn1::write_single(&cert.raw.borrow_value_public().tbs_cert.issuer)?; - let issuer_name_hash = hash_data(py, hash_algorithm, &issuer_der)?; - let issuer_key_hash = hash_data( - py, - hash_algorithm, - issuer - .raw - .borrow_value_public() - .tbs_cert - .spki - .subject_public_key - .as_bytes(), - )?; +pub(crate) fn certid_new<'p>( + py: pyo3::Python<'p>, + cert: &'p Certificate, + issuer: &'p Certificate, + hash_algorithm: &'p pyo3::PyAny, +) -> CryptographyResult> { + let issuer_der = asn1::write_single(&cert.raw.borrow_value_public().tbs_cert.issuer)?; + let issuer_name_hash = hash_data(py, hash_algorithm, &issuer_der)?; + let issuer_key_hash = hash_data( + py, + hash_algorithm, + issuer + .raw + .borrow_value_public() + .tbs_cert + .spki + .subject_public_key + .as_bytes(), + )?; - Ok(CertID { - hash_algorithm: x509::AlgorithmIdentifier { - oid: HASH_NAME_TO_OIDS[hash_algorithm - .getattr(pyo3::intern!(py, "name"))? - .extract::<&str>()?] - .clone(), - params: Some(*x509::sign::NULL_TLV), - }, - issuer_name_hash, - issuer_key_hash, - serial_number: cert.raw.borrow_value_public().tbs_cert.serial, - }) - } + Ok(CertID { + hash_algorithm: common::AlgorithmIdentifier { + oid: HASH_NAME_TO_OIDS[hash_algorithm + .getattr(pyo3::intern!(py, "name"))? + .extract::<&str>()?] + .clone(), + params: Some(*x509::sign::NULL_TLV), + }, + issuer_name_hash, + issuer_key_hash, + serial_number: cert.raw.borrow_value_public().tbs_cert.serial, + }) +} - pub(crate) fn new_from_hash<'p>( - py: pyo3::Python<'p>, - issuer_name_hash: &'p [u8], - issuer_key_hash: &'p [u8], - serial_number: asn1::BigInt<'p>, - hash_algorithm: &'p pyo3::PyAny, - ) -> CryptographyResult> { - Ok(CertID { - hash_algorithm: x509::AlgorithmIdentifier { - oid: HASH_NAME_TO_OIDS[hash_algorithm - .getattr(pyo3::intern!(py, "name"))? - .extract::<&str>()?] - .clone(), - params: Some(*x509::sign::NULL_TLV), - }, - issuer_name_hash, - issuer_key_hash, - serial_number, - }) - } +pub(crate) fn certid_new_from_hash<'p>( + py: pyo3::Python<'p>, + issuer_name_hash: &'p [u8], + issuer_key_hash: &'p [u8], + serial_number: asn1::BigInt<'p>, + hash_algorithm: &'p pyo3::PyAny, +) -> CryptographyResult> { + Ok(CertID { + hash_algorithm: common::AlgorithmIdentifier { + oid: HASH_NAME_TO_OIDS[hash_algorithm + .getattr(pyo3::intern!(py, "name"))? + .extract::<&str>()?] + .clone(), + params: Some(*x509::sign::NULL_TLV), + }, + issuer_name_hash, + issuer_key_hash, + serial_number, + }) } pub(crate) fn hash_data<'p>( diff --git a/src/rust/src/x509/ocsp_req.rs b/src/rust/src/x509/ocsp_req.rs index afd939d478f4..856c60c93d9a 100644 --- a/src/rust/src/x509/ocsp_req.rs +++ b/src/rust/src/x509/ocsp_req.rs @@ -5,15 +5,16 @@ use crate::asn1::{big_byte_slice_to_py_int, oid_to_py_oid, py_uint_to_big_endian_bytes}; use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; -use crate::x509::{extensions, ocsp, oid}; +use crate::x509::{extensions, ocsp}; +use cryptography_x509::{common, ocsp_req, oid}; use pyo3::IntoPy; #[ouroboros::self_referencing] -struct OwnedRawOCSPRequest { +struct OwnedOCSPRequest { data: pyo3::Py, #[borrows(data)] #[covariant] - value: RawOCSPRequest<'this>, + value: ocsp_req::OCSPRequest<'this>, } #[pyo3::prelude::pyfunction] @@ -21,7 +22,7 @@ fn load_der_ocsp_request( py: pyo3::Python<'_>, data: pyo3::Py, ) -> CryptographyResult { - let raw = OwnedRawOCSPRequest::try_new(data, |data| asn1::parse_single(data.as_bytes(py)))?; + let raw = OwnedOCSPRequest::try_new(data, |data| asn1::parse_single(data.as_bytes(py)))?; if raw .borrow_value() @@ -46,13 +47,13 @@ fn load_der_ocsp_request( #[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.ocsp")] struct OCSPRequest { - raw: OwnedRawOCSPRequest, + raw: OwnedOCSPRequest, cached_extensions: Option, } impl OCSPRequest { - fn cert_id(&self) -> ocsp::CertID<'_> { + fn cert_id(&self) -> ocsp_req::CertID<'_> { self.raw .borrow_value() .tbs_request @@ -174,39 +175,6 @@ impl OCSPRequest { } } -#[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, - #[explicit(1)] - requestor_name: Option>, - request_list: x509::Asn1ReadableOrWritable< - 'a, - asn1::SequenceOf<'a, Request<'a>>, - asn1::SequenceOfWriter<'a, Request<'a>>, - >, - #[explicit(2)] - request_extensions: Option>, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -struct Request<'a> { - req_cert: ocsp::CertID<'a>, - #[explicit(0)] - single_request_extensions: Option>, -} - #[pyo3::prelude::pyfunction] fn create_ocsp_request( py: pyo3::Python<'_>, @@ -216,20 +184,20 @@ fn create_ocsp_request( // Declare outside the if-block so the lifetimes are right. let (py_cert, py_issuer, py_hash): ( - pyo3::PyRef<'_, x509::Certificate>, - pyo3::PyRef<'_, x509::Certificate>, + pyo3::PyRef<'_, x509::certificate::Certificate>, + pyo3::PyRef<'_, x509::certificate::Certificate>, &pyo3::PyAny, ); let req_cert = if !builder_request.is_none() { let tuple = builder_request.extract::<( - pyo3::PyRef<'_, x509::Certificate>, - pyo3::PyRef<'_, x509::Certificate>, + pyo3::PyRef<'_, x509::certificate::Certificate>, + pyo3::PyRef<'_, x509::certificate::Certificate>, &pyo3::PyAny, )>()?; py_cert = tuple.0; py_issuer = tuple.1; py_hash = tuple.2; - ocsp::CertID::new(py, &py_cert, &py_issuer, py_hash)? + ocsp::certid_new(py, &py_cert, &py_issuer, py_hash)? } else { let (issuer_name_hash, issuer_key_hash, py_serial, py_hash): ( &[u8], @@ -240,7 +208,7 @@ fn create_ocsp_request( .getattr(pyo3::intern!(py, "_request_hash"))? .extract()?; let serial_number = asn1::BigInt::new(py_uint_to_big_endian_bytes(py, py_serial)?).unwrap(); - ocsp::CertID::new_from_hash( + ocsp::certid_new_from_hash( py, issuer_name_hash, issuer_key_hash, @@ -254,15 +222,15 @@ fn create_ocsp_request( builder.getattr(pyo3::intern!(py, "_extensions"))?, extensions::encode_extension, )?; - let reqs = [Request { + let reqs = [ocsp_req::Request { req_cert, single_request_extensions: None, }]; - let ocsp_req = RawOCSPRequest { - tbs_request: TBSRequest { + let ocsp_req = ocsp_req::OCSPRequest { + tbs_request: ocsp_req::TBSRequest { version: 0, requestor_name: None, - request_list: x509::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new( + request_list: common::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new( &reqs, )), request_extensions: extensions, diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index 0b2cab5f0b07..ffbf9c88af46 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -5,7 +5,10 @@ use crate::asn1::{big_byte_slice_to_py_int, oid_to_py_oid}; use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; -use crate::x509::{certificate, crl, extensions, ocsp, oid, py_to_datetime, sct}; +use crate::x509::{certificate, crl, extensions, ocsp, py_to_datetime, sct}; +use cryptography_x509::crl::CRLReason; +use cryptography_x509::extensions::Extensions; +use cryptography_x509::{common, name, ocsp_req, oid}; use pyo3::IntoPy; use std::sync::Arc; @@ -233,7 +236,7 @@ impl OCSPResponse { }); py_certs.append(pyo3::PyCell::new( py, - x509::Certificate { + x509::certificate::Certificate { raw: raw_cert, cached_extensions: None, }, @@ -407,9 +410,9 @@ fn map_arc_data_ocsp_response( f: impl for<'this> FnOnce( &'this [u8], &RawOCSPResponse<'this>, - ) -> certificate::RawCertificate<'this>, -) -> certificate::OwnedRawCertificate { - certificate::OwnedRawCertificate::new_public(it.borrow_data().clone_ref(py), |inner_it| { + ) -> cryptography_x509::certificate::Certificate<'this>, +) -> certificate::OwnedCertificate { + certificate::OwnedCertificate::new_public(it.borrow_data().clone_ref(py), |inner_it| { it.with(|value| { f(inner_it.as_bytes(py), unsafe { std::mem::transmute(value.value) @@ -443,13 +446,13 @@ struct ResponseBytes<'a> { } type OCSPCerts<'a> = Option< - x509::Asn1ReadableOrWritable< + common::Asn1ReadableOrWritable< 'a, - asn1::SequenceOf<'a, certificate::RawCertificate<'a>>, + asn1::SequenceOf<'a, cryptography_x509::certificate::Certificate<'a>>, asn1::SequenceOfWriter< 'a, - certificate::RawCertificate<'a>, - Vec>, + cryptography_x509::certificate::Certificate<'a>, + Vec>, >, >, >; @@ -457,7 +460,7 @@ type OCSPCerts<'a> = Option< #[derive(asn1::Asn1Read, asn1::Asn1Write)] struct BasicOCSPResponse<'a> { tbs_response_data: ResponseData<'a>, - signature_algorithm: x509::AlgorithmIdentifier<'a>, + signature_algorithm: common::AlgorithmIdentifier<'a>, signature: asn1::BitString<'a>, #[explicit(0)] certs: OCSPCerts<'a>, @@ -488,32 +491,32 @@ struct ResponseData<'a> { version: u8, responder_id: ResponderId<'a>, produced_at: asn1::GeneralizedTime, - responses: x509::Asn1ReadableOrWritable< + responses: common::Asn1ReadableOrWritable< 'a, asn1::SequenceOf<'a, SingleResponse<'a>>, asn1::SequenceOfWriter<'a, SingleResponse<'a>, Vec>>, >, #[explicit(1)] - response_extensions: Option>, + response_extensions: Option>, } #[derive(asn1::Asn1Read, asn1::Asn1Write)] enum ResponderId<'a> { #[explicit(1)] - ByName(x509::Name<'a>), + ByName(name::Name<'a>), #[explicit(2)] ByKey(&'a [u8]), } #[derive(asn1::Asn1Read, asn1::Asn1Write)] struct SingleResponse<'a> { - cert_id: ocsp::CertID<'a>, + cert_id: ocsp_req::CertID<'a>, cert_status: CertStatus, this_update: asn1::GeneralizedTime, #[explicit(0)] next_update: Option, #[explicit(1)] - single_extensions: Option>, + single_extensions: Option>, } impl SingleResponse<'_> { @@ -601,7 +604,7 @@ enum CertStatus { struct RevokedInfo { revocation_time: asn1::GeneralizedTime, #[explicit(0)] - revocation_reason: Option, + revocation_reason: Option, } #[pyo3::prelude::pyfunction] @@ -616,10 +619,10 @@ fn create_ocsp_response( .getattr(pyo3::intern!(py, "value"))? .extract::()?; - let py_cert: pyo3::PyRef<'_, x509::Certificate>; - let py_issuer: pyo3::PyRef<'_, x509::Certificate>; + let py_cert: pyo3::PyRef<'_, x509::certificate::Certificate>; + let py_issuer: pyo3::PyRef<'_, x509::certificate::Certificate>; let borrowed_cert; - let py_certs: Option>>; + let py_certs: Option>>; let response_bytes = if response_status == SUCCESSFUL_RESPONSE { let ocsp_mod = py.import(pyo3::intern!(py, "cryptography.x509.ocsp"))?; @@ -631,10 +634,12 @@ fn create_ocsp_response( .getattr(pyo3::intern!(py, "_issuer"))? .extract()?; let py_cert_hash_algorithm = py_single_resp.getattr(pyo3::intern!(py, "_algorithm"))?; - let (responder_cert, responder_encoding): (&pyo3::PyCell, &pyo3::PyAny) = - builder - .getattr(pyo3::intern!(py, "_responder_id"))? - .extract()?; + let (responder_cert, responder_encoding): ( + &pyo3::PyCell, + &pyo3::PyAny, + ) = builder + .getattr(pyo3::intern!(py, "_responder_id"))? + .extract()?; let py_cert_status = py_single_resp.getattr(pyo3::intern!(py, "_cert_status"))?; let cert_status = if py_cert_status.is(ocsp_mod @@ -690,7 +695,7 @@ fn create_ocsp_response( let this_update = asn1::GeneralizedTime::new(py_to_datetime(py, py_this_update)?)?; let responses = vec![SingleResponse { - cert_id: ocsp::CertID::new(py, &py_cert, &py_issuer, py_cert_hash_algorithm)?, + cert_id: ocsp::certid_new(py, &py_cert, &py_issuer, py_cert_hash_algorithm)?, cert_status, next_update, this_update, @@ -732,7 +737,7 @@ fn create_ocsp_response( version: 0, produced_at: asn1::GeneralizedTime::new(x509::common::datetime_now(py)?)?, responder_id, - responses: x509::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new( + responses: common::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new( responses, )), response_extensions: x509::common::encode_extensions( @@ -759,7 +764,7 @@ fn create_ocsp_response( py_certs = builder.getattr(pyo3::intern!(py, "_certs"))?.extract()?; let certs = py_certs.as_ref().map(|py_certs| { - x509::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new( + common::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new( py_certs .iter() .map(|c| c.raw.borrow_value_public().clone()) diff --git a/src/rust/src/x509/oid.rs b/src/rust/src/x509/oid.rs deleted file mode 100644 index b2e3a36acd3e..000000000000 --- a/src/rust/src/x509/oid.rs +++ /dev/null @@ -1,101 +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. - -pub(crate) const EXTENSION_REQUEST: asn1::ObjectIdentifier = - asn1::oid!(1, 2, 840, 113549, 1, 9, 14); -pub(crate) const MS_EXTENSION_REQUEST: asn1::ObjectIdentifier = - asn1::oid!(1, 3, 6, 1, 4, 1, 311, 2, 1, 14); -pub(crate) const MS_CERTIFICATE_TEMPLATE: asn1::ObjectIdentifier = - asn1::oid!(1, 3, 6, 1, 4, 1, 311, 21, 7); -pub(crate) const PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS_OID: asn1::ObjectIdentifier = - asn1::oid!(1, 3, 6, 1, 4, 1, 11129, 2, 4, 2); -pub(crate) const PRECERT_POISON_OID: asn1::ObjectIdentifier = - asn1::oid!(1, 3, 6, 1, 4, 1, 11129, 2, 4, 3); -pub(crate) const SIGNED_CERTIFICATE_TIMESTAMPS_OID: asn1::ObjectIdentifier = - asn1::oid!(1, 3, 6, 1, 4, 1, 11129, 2, 4, 5); -pub(crate) const AUTHORITY_INFORMATION_ACCESS_OID: asn1::ObjectIdentifier = - asn1::oid!(1, 3, 6, 1, 5, 5, 7, 1, 1); -pub(crate) const SUBJECT_INFORMATION_ACCESS_OID: asn1::ObjectIdentifier = - asn1::oid!(1, 3, 6, 1, 5, 5, 7, 1, 11); -pub(crate) const TLS_FEATURE_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 5, 5, 7, 1, 24); -pub(crate) const CP_CPS_URI_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 5, 5, 7, 2, 1); -pub(crate) const CP_USER_NOTICE_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 5, 5, 7, 2, 2); -pub(crate) const NONCE_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 6, 1, 5, 5, 7, 48, 1, 2); -pub(crate) const OCSP_NO_CHECK_OID: asn1::ObjectIdentifier = - asn1::oid!(1, 3, 6, 1, 5, 5, 7, 48, 1, 5); -pub(crate) const SUBJECT_KEY_IDENTIFIER_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 14); -pub(crate) const KEY_USAGE_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 15); -pub(crate) const SUBJECT_ALTERNATIVE_NAME_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 17); -pub(crate) const ISSUER_ALTERNATIVE_NAME_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 18); -pub(crate) const BASIC_CONSTRAINTS_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 19); -pub(crate) const CRL_NUMBER_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 20); -pub(crate) const CRL_REASON_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 21); -pub(crate) const INVALIDITY_DATE_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 24); -pub(crate) const DELTA_CRL_INDICATOR_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 27); -pub(crate) const ISSUING_DISTRIBUTION_POINT_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 28); -pub(crate) const CERTIFICATE_ISSUER_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 29); -pub(crate) const NAME_CONSTRAINTS_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 30); -pub(crate) const CRL_DISTRIBUTION_POINTS_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 31); -pub(crate) const CERTIFICATE_POLICIES_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 32); -pub(crate) const AUTHORITY_KEY_IDENTIFIER_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 35); -pub(crate) const POLICY_CONSTRAINTS_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 36); -pub(crate) const EXTENDED_KEY_USAGE_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 37); -pub(crate) const FRESHEST_CRL_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 46); -pub(crate) const INHIBIT_ANY_POLICY_OID: asn1::ObjectIdentifier = asn1::oid!(2, 5, 29, 54); -pub(crate) const ACCEPTABLE_RESPONSES_OID: asn1::ObjectIdentifier = - asn1::oid!(1, 3, 6, 1, 5, 5, 7, 48, 1, 4); - -// Signing methods -pub(crate) const ECDSA_WITH_SHA224_OID: asn1::ObjectIdentifier = - asn1::oid!(1, 2, 840, 10045, 4, 3, 1); -pub(crate) const ECDSA_WITH_SHA256_OID: asn1::ObjectIdentifier = - asn1::oid!(1, 2, 840, 10045, 4, 3, 2); -pub(crate) const ECDSA_WITH_SHA384_OID: asn1::ObjectIdentifier = - asn1::oid!(1, 2, 840, 10045, 4, 3, 3); -pub(crate) const ECDSA_WITH_SHA512_OID: asn1::ObjectIdentifier = - asn1::oid!(1, 2, 840, 10045, 4, 3, 4); -pub(crate) const ECDSA_WITH_SHA3_224_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 9); -pub(crate) const ECDSA_WITH_SHA3_256_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 10); -pub(crate) const ECDSA_WITH_SHA3_384_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 11); -pub(crate) const ECDSA_WITH_SHA3_512_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 12); - -pub(crate) const RSA_WITH_SHA224_OID: asn1::ObjectIdentifier = - asn1::oid!(1, 2, 840, 113549, 1, 1, 14); -pub(crate) const RSA_WITH_SHA256_OID: asn1::ObjectIdentifier = - asn1::oid!(1, 2, 840, 113549, 1, 1, 11); -pub(crate) const RSA_WITH_SHA384_OID: asn1::ObjectIdentifier = - asn1::oid!(1, 2, 840, 113549, 1, 1, 12); -pub(crate) const RSA_WITH_SHA512_OID: asn1::ObjectIdentifier = - asn1::oid!(1, 2, 840, 113549, 1, 1, 13); -pub(crate) const RSA_WITH_SHA3_224_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 13); -pub(crate) const RSA_WITH_SHA3_256_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 14); -pub(crate) const RSA_WITH_SHA3_384_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 15); -pub(crate) const RSA_WITH_SHA3_512_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 16); - -pub(crate) const DSA_WITH_SHA224_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 1); -pub(crate) const DSA_WITH_SHA256_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 2); -pub(crate) const DSA_WITH_SHA384_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 3); -pub(crate) const DSA_WITH_SHA512_OID: asn1::ObjectIdentifier = - asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 4); - -pub(crate) const ED25519_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 101, 112); -pub(crate) const ED448_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 101, 113); - -// Hashes -pub(crate) const SHA1_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 14, 3, 2, 26); -pub(crate) const SHA224_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 4); -pub(crate) const SHA256_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 1); -pub(crate) const SHA384_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 2); -pub(crate) const SHA512_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 3); diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index 4be023bb2331..12579b35e4c0 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -3,8 +3,7 @@ // for complete details. use crate::error::{CryptographyError, CryptographyResult}; -use crate::x509; -use crate::x509::oid; +use cryptography_x509::{common, oid}; use once_cell::sync::Lazy; @@ -138,16 +137,16 @@ pub(crate) fn compute_signature_algorithm<'p>( py: pyo3::Python<'p>, private_key: &'p pyo3::PyAny, hash_algorithm: &'p pyo3::PyAny, -) -> pyo3::PyResult> { +) -> pyo3::PyResult> { let key_type = identify_key_type(py, private_key)?; let hash_type = identify_hash_type(py, hash_algorithm)?; match (key_type, hash_type) { - (KeyType::Ed25519, HashType::None) => Ok(x509::AlgorithmIdentifier { + (KeyType::Ed25519, HashType::None) => Ok(common::AlgorithmIdentifier { oid: (oid::ED25519_OID).clone(), params: None, }), - (KeyType::Ed448, HashType::None) => Ok(x509::AlgorithmIdentifier { + (KeyType::Ed448, HashType::None) => Ok(common::AlgorithmIdentifier { oid: (oid::ED448_OID).clone(), params: None, }), @@ -155,85 +154,85 @@ pub(crate) fn compute_signature_algorithm<'p>( "Algorithm must be None when signing via ed25519 or ed448", )), - (KeyType::Ec, HashType::Sha224) => Ok(x509::AlgorithmIdentifier { + (KeyType::Ec, HashType::Sha224) => Ok(common::AlgorithmIdentifier { oid: (oid::ECDSA_WITH_SHA224_OID).clone(), params: None, }), - (KeyType::Ec, HashType::Sha256) => Ok(x509::AlgorithmIdentifier { + (KeyType::Ec, HashType::Sha256) => Ok(common::AlgorithmIdentifier { oid: (oid::ECDSA_WITH_SHA256_OID).clone(), params: None, }), - (KeyType::Ec, HashType::Sha384) => Ok(x509::AlgorithmIdentifier { + (KeyType::Ec, HashType::Sha384) => Ok(common::AlgorithmIdentifier { oid: (oid::ECDSA_WITH_SHA384_OID).clone(), params: None, }), - (KeyType::Ec, HashType::Sha512) => Ok(x509::AlgorithmIdentifier { + (KeyType::Ec, HashType::Sha512) => Ok(common::AlgorithmIdentifier { oid: (oid::ECDSA_WITH_SHA512_OID).clone(), params: None, }), - (KeyType::Ec, HashType::Sha3_224) => Ok(x509::AlgorithmIdentifier { + (KeyType::Ec, HashType::Sha3_224) => Ok(common::AlgorithmIdentifier { oid: (oid::ECDSA_WITH_SHA3_224_OID).clone(), params: None, }), - (KeyType::Ec, HashType::Sha3_256) => Ok(x509::AlgorithmIdentifier { + (KeyType::Ec, HashType::Sha3_256) => Ok(common::AlgorithmIdentifier { oid: (oid::ECDSA_WITH_SHA3_256_OID).clone(), params: None, }), - (KeyType::Ec, HashType::Sha3_384) => Ok(x509::AlgorithmIdentifier { + (KeyType::Ec, HashType::Sha3_384) => Ok(common::AlgorithmIdentifier { oid: (oid::ECDSA_WITH_SHA3_384_OID).clone(), params: None, }), - (KeyType::Ec, HashType::Sha3_512) => Ok(x509::AlgorithmIdentifier { + (KeyType::Ec, HashType::Sha3_512) => Ok(common::AlgorithmIdentifier { oid: (oid::ECDSA_WITH_SHA3_512_OID).clone(), params: None, }), - (KeyType::Rsa, HashType::Sha224) => Ok(x509::AlgorithmIdentifier { + (KeyType::Rsa, HashType::Sha224) => Ok(common::AlgorithmIdentifier { oid: (oid::RSA_WITH_SHA224_OID).clone(), params: Some(*NULL_TLV), }), - (KeyType::Rsa, HashType::Sha256) => Ok(x509::AlgorithmIdentifier { + (KeyType::Rsa, HashType::Sha256) => Ok(common::AlgorithmIdentifier { oid: (oid::RSA_WITH_SHA256_OID).clone(), params: Some(*NULL_TLV), }), - (KeyType::Rsa, HashType::Sha384) => Ok(x509::AlgorithmIdentifier { + (KeyType::Rsa, HashType::Sha384) => Ok(common::AlgorithmIdentifier { oid: (oid::RSA_WITH_SHA384_OID).clone(), params: Some(*NULL_TLV), }), - (KeyType::Rsa, HashType::Sha512) => Ok(x509::AlgorithmIdentifier { + (KeyType::Rsa, HashType::Sha512) => Ok(common::AlgorithmIdentifier { oid: (oid::RSA_WITH_SHA512_OID).clone(), params: Some(*NULL_TLV), }), - (KeyType::Rsa, HashType::Sha3_224) => Ok(x509::AlgorithmIdentifier { + (KeyType::Rsa, HashType::Sha3_224) => Ok(common::AlgorithmIdentifier { oid: (oid::RSA_WITH_SHA3_224_OID).clone(), params: Some(*NULL_TLV), }), - (KeyType::Rsa, HashType::Sha3_256) => Ok(x509::AlgorithmIdentifier { + (KeyType::Rsa, HashType::Sha3_256) => Ok(common::AlgorithmIdentifier { oid: (oid::RSA_WITH_SHA3_256_OID).clone(), params: Some(*NULL_TLV), }), - (KeyType::Rsa, HashType::Sha3_384) => Ok(x509::AlgorithmIdentifier { + (KeyType::Rsa, HashType::Sha3_384) => Ok(common::AlgorithmIdentifier { oid: (oid::RSA_WITH_SHA3_384_OID).clone(), params: Some(*NULL_TLV), }), - (KeyType::Rsa, HashType::Sha3_512) => Ok(x509::AlgorithmIdentifier { + (KeyType::Rsa, HashType::Sha3_512) => Ok(common::AlgorithmIdentifier { oid: (oid::RSA_WITH_SHA3_512_OID).clone(), params: Some(*NULL_TLV), }), - (KeyType::Dsa, HashType::Sha224) => Ok(x509::AlgorithmIdentifier { + (KeyType::Dsa, HashType::Sha224) => Ok(common::AlgorithmIdentifier { oid: (oid::DSA_WITH_SHA224_OID).clone(), params: None, }), - (KeyType::Dsa, HashType::Sha256) => Ok(x509::AlgorithmIdentifier { + (KeyType::Dsa, HashType::Sha256) => Ok(common::AlgorithmIdentifier { oid: (oid::DSA_WITH_SHA256_OID).clone(), params: None, }), - (KeyType::Dsa, HashType::Sha384) => Ok(x509::AlgorithmIdentifier { + (KeyType::Dsa, HashType::Sha384) => Ok(common::AlgorithmIdentifier { oid: (oid::DSA_WITH_SHA384_OID).clone(), params: None, }), - (KeyType::Dsa, HashType::Sha512) => Ok(x509::AlgorithmIdentifier { + (KeyType::Dsa, HashType::Sha512) => Ok(common::AlgorithmIdentifier { oid: (oid::DSA_WITH_SHA512_OID).clone(), params: None, }), @@ -456,7 +455,7 @@ fn identify_key_hash_type_for_oid( #[cfg(test)] mod tests { use super::{identify_key_hash_type_for_oid, py_hash_name_from_hash_type, HashType, KeyType}; - use crate::x509::oid; + use cryptography_x509::oid; #[test] fn test_identify_key_hash_type_for_oid() { From b358a7d805058795518f34fc44276ab388849005 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 17 Apr 2023 07:39:55 +0800 Subject: [PATCH 126/316] port OCSP responses to the new crate (#8742) --- src/rust/cryptography-x509/src/lib.rs | 1 + src/rust/cryptography-x509/src/ocsp_resp.rs | 87 +++++ src/rust/src/x509/ocsp_resp.rs | 363 ++++++++------------ 3 files changed, 239 insertions(+), 212 deletions(-) create mode 100644 src/rust/cryptography-x509/src/ocsp_resp.rs diff --git a/src/rust/cryptography-x509/src/lib.rs b/src/rust/cryptography-x509/src/lib.rs index 3f8878772dd1..897e0f6c0229 100644 --- a/src/rust/cryptography-x509/src/lib.rs +++ b/src/rust/cryptography-x509/src/lib.rs @@ -11,4 +11,5 @@ pub mod csr; pub mod extensions; pub mod name; pub mod ocsp_req; +pub mod ocsp_resp; pub mod oid; diff --git a/src/rust/cryptography-x509/src/ocsp_resp.rs b/src/rust/cryptography-x509/src/ocsp_resp.rs new file mode 100644 index 000000000000..f7620f6aa601 --- /dev/null +++ b/src/rust/cryptography-x509/src/ocsp_resp.rs @@ -0,0 +1,87 @@ +// 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::{certificate, common, crl, extensions, name, ocsp_req}; + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct OCSPResponse<'a> { + pub response_status: asn1::Enumerated, + #[explicit(0)] + pub response_bytes: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct ResponseBytes<'a> { + pub response_type: asn1::ObjectIdentifier, + pub response: asn1::OctetStringEncoded>, +} + +pub type OCSPCerts<'a> = Option< + common::Asn1ReadableOrWritable< + 'a, + asn1::SequenceOf<'a, certificate::Certificate<'a>>, + asn1::SequenceOfWriter<'a, certificate::Certificate<'a>, Vec>>, + >, +>; + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct BasicOCSPResponse<'a> { + pub tbs_response_data: ResponseData<'a>, + pub signature_algorithm: common::AlgorithmIdentifier<'a>, + pub signature: asn1::BitString<'a>, + #[explicit(0)] + pub certs: OCSPCerts<'a>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct ResponseData<'a> { + #[explicit(0)] + #[default(0)] + pub version: u8, + pub responder_id: ResponderId<'a>, + pub produced_at: asn1::GeneralizedTime, + pub responses: common::Asn1ReadableOrWritable< + 'a, + asn1::SequenceOf<'a, SingleResponse<'a>>, + asn1::SequenceOfWriter<'a, SingleResponse<'a>, Vec>>, + >, + #[explicit(1)] + pub response_extensions: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub enum ResponderId<'a> { + #[explicit(1)] + ByName(name::Name<'a>), + #[explicit(2)] + ByKey(&'a [u8]), +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct SingleResponse<'a> { + pub cert_id: ocsp_req::CertID<'a>, + pub cert_status: CertStatus, + pub this_update: asn1::GeneralizedTime, + #[explicit(0)] + pub next_update: Option, + #[explicit(1)] + pub single_extensions: Option>, +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub enum CertStatus { + #[implicit(0)] + Good(()), + #[implicit(1)] + Revoked(RevokedInfo), + #[implicit(2)] + Unknown(()), +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct RevokedInfo { + pub revocation_time: asn1::GeneralizedTime, + #[explicit(0)] + pub revocation_reason: Option, +} diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index ffbf9c88af46..3344867ba186 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -6,9 +6,8 @@ use crate::asn1::{big_byte_slice_to_py_int, oid_to_py_oid}; use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; use crate::x509::{certificate, crl, extensions, ocsp, py_to_datetime, sct}; -use cryptography_x509::crl::CRLReason; -use cryptography_x509::extensions::Extensions; -use cryptography_x509::{common, name, ocsp_req, oid}; +use cryptography_x509::ocsp_resp::SingleResponse; +use cryptography_x509::{common, ocsp_resp, oid}; use pyo3::IntoPy; use std::sync::Arc; @@ -19,7 +18,7 @@ fn load_der_ocsp_response( py: pyo3::Python<'_>, data: pyo3::Py, ) -> Result { - let raw = OwnedRawOCSPResponse::try_new(data, |data| asn1::parse_single(data.as_bytes(py)))?; + let raw = OwnedOCSPResponse::try_new(data, |data| asn1::parse_single(data.as_bytes(py)))?; let response = raw.borrow_value(); match response.response_status.value() { @@ -60,23 +59,23 @@ fn load_der_ocsp_response( } #[ouroboros::self_referencing] -struct OwnedRawOCSPResponse { +struct OwnedOCSPResponse { data: pyo3::Py, #[borrows(data)] #[covariant] - value: RawOCSPResponse<'this>, + value: ocsp_resp::OCSPResponse<'this>, } #[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.ocsp")] struct OCSPResponse { - raw: Arc, + raw: Arc, cached_extensions: Option, cached_single_extensions: Option, } impl OCSPResponse { - fn requires_successful_response(&self) -> pyo3::PyResult<&BasicOCSPResponse<'_>> { + fn requires_successful_response(&self) -> pyo3::PyResult<&ocsp_resp::BasicOCSPResponse<'_>> { match self.raw.borrow_value().response_bytes.as_ref() { Some(b) => Ok(b.response.get()), None => Err(pyo3::exceptions::PyValueError::new_err( @@ -144,8 +143,8 @@ impl OCSPResponse { fn responder_name<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let resp = self.requires_successful_response()?; match resp.tbs_response_data.responder_id { - ResponderId::ByName(ref name) => Ok(x509::parse_name(py, name)?), - ResponderId::ByKey(_) => Ok(py.None().into_ref(py)), + ocsp_resp::ResponderId::ByName(ref name) => Ok(x509::parse_name(py, name)?), + ocsp_resp::ResponderId::ByKey(_) => Ok(py.None().into_ref(py)), } } @@ -153,8 +152,10 @@ impl OCSPResponse { fn responder_key_hash<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let resp = self.requires_successful_response()?; match resp.tbs_response_data.responder_id { - ResponderId::ByKey(key_hash) => Ok(pyo3::types::PyBytes::new(py, key_hash).as_ref()), - ResponderId::ByName(_) => Ok(py.None().into_ref(py)), + ocsp_resp::ResponderId::ByKey(key_hash) => { + Ok(pyo3::types::PyBytes::new(py, key_hash).as_ref()) + } + ocsp_resp::ResponderId::ByName(_) => Ok(py.None().into_ref(py)), } } @@ -248,21 +249,21 @@ impl OCSPResponse { #[getter] fn serial_number<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let resp = self.requires_successful_response()?; - let single_resp = resp.single_response()?; - single_resp.py_serial_number(py) + let single_resp = single_response(resp)?; + singleresp_py_serial_number(&single_resp, py) } #[getter] fn issuer_key_hash(&self) -> Result<&[u8], CryptographyError> { let resp = self.requires_successful_response()?; - let single_resp = resp.single_response()?; + let single_resp = single_response(resp)?; Ok(single_resp.cert_id.issuer_key_hash) } #[getter] fn issuer_name_hash(&self) -> Result<&[u8], CryptographyError> { let resp = self.requires_successful_response()?; - let single_resp = resp.single_response()?; + let single_resp = single_response(resp)?; Ok(single_resp.cert_id.issuer_name_hash) } @@ -272,42 +273,43 @@ impl OCSPResponse { py: pyo3::Python<'p>, ) -> Result<&'p pyo3::PyAny, CryptographyError> { let resp = self.requires_successful_response()?; - let single_resp = resp.single_response()?; - single_resp.py_hash_algorithm(py) + let single_resp = single_response(resp)?; + singleresp_py_hash_algorithm(&single_resp, py) } #[getter] fn certificate_status<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let resp = self.requires_successful_response()?; - resp.single_response()?.py_certificate_status(py) + let single_resp = single_response(resp)?; + singleresp_py_certificate_status(&single_resp, py) } #[getter] fn revocation_time<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let resp = self.requires_successful_response()?; - let single_resp = resp.single_response()?; - single_resp.py_revocation_time(py) + let single_resp = single_response(resp)?; + singleresp_py_revocation_time(&single_resp, py) } #[getter] fn revocation_reason<'p>(&self, py: pyo3::Python<'p>) -> CryptographyResult<&'p pyo3::PyAny> { let resp = self.requires_successful_response()?; - let single_resp = resp.single_response()?; - single_resp.py_revocation_reason(py) + let single_resp = single_response(resp)?; + singleresp_py_revocation_reason(&single_resp, py) } #[getter] fn this_update<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let resp = self.requires_successful_response()?; - let single_resp = resp.single_response()?; - single_resp.py_this_update(py) + let single_resp = single_response(resp)?; + singleresp_py_this_update(&single_resp, py) } #[getter] fn next_update<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let resp = self.requires_successful_response()?; - let single_resp = resp.single_response()?; - single_resp.py_next_update(py) + let single_resp = single_response(resp)?; + singleresp_py_next_update(&single_resp, py) } #[getter] @@ -350,15 +352,15 @@ impl OCSPResponse { #[getter] fn single_extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult { self.requires_successful_response()?; - let single_resp = self - .raw - .borrow_value() - .response_bytes - .as_ref() - .unwrap() - .response - .get() - .single_response()?; + let single_resp = single_response( + self.raw + .borrow_value() + .response_bytes + .as_ref() + .unwrap() + .response + .get(), + )?; let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; x509::parse_and_cache_extensions( py, @@ -406,10 +408,10 @@ impl OCSPResponse { // https://github.com/joshua-maros/ouroboros/issues/38 fn map_arc_data_ocsp_response( py: pyo3::Python<'_>, - it: &OwnedRawOCSPResponse, + it: &OwnedOCSPResponse, f: impl for<'this> FnOnce( &'this [u8], - &RawOCSPResponse<'this>, + &ocsp_resp::OCSPResponse<'this>, ) -> cryptography_x509::certificate::Certificate<'this>, ) -> certificate::OwnedCertificate { certificate::OwnedCertificate::new_public(it.borrow_data().clone_ref(py), |inner_it| { @@ -423,190 +425,121 @@ fn map_arc_data_ocsp_response( fn try_map_arc_data_mut_ocsp_response_iterator( it: &mut OwnedOCSPResponseIteratorData, f: impl for<'this> FnOnce( - &'this OwnedRawOCSPResponse, - &mut asn1::SequenceOf<'this, SingleResponse<'this>>, - ) -> Result, E>, + &'this OwnedOCSPResponse, + &mut asn1::SequenceOf<'this, ocsp_resp::SingleResponse<'this>>, + ) -> Result, E>, ) -> Result { OwnedSingleResponse::try_new(Arc::clone(it.borrow_data()), |inner_it| { it.with_value_mut(|value| f(inner_it, unsafe { std::mem::transmute(value) })) }) } -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -struct RawOCSPResponse<'a> { - response_status: asn1::Enumerated, - #[explicit(0)] - response_bytes: Option>, -} +fn single_response<'a>( + resp: &ocsp_resp::BasicOCSPResponse<'a>, +) -> Result, CryptographyError> { + let responses = resp.tbs_response_data.responses.unwrap_read(); + let num_responses = responses.len(); + + if num_responses != 1 { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err(format!( + "OCSP response contains {} SINGLERESP structures. Use .response_iter to iterate through them", + num_responses + )) + )); + } -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -struct ResponseBytes<'a> { - response_type: asn1::ObjectIdentifier, - response: asn1::OctetStringEncoded>, + Ok(responses.clone().next().unwrap()) } -type OCSPCerts<'a> = Option< - common::Asn1ReadableOrWritable< - 'a, - asn1::SequenceOf<'a, cryptography_x509::certificate::Certificate<'a>>, - asn1::SequenceOfWriter< - 'a, - cryptography_x509::certificate::Certificate<'a>, - Vec>, - >, - >, ->; - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -struct BasicOCSPResponse<'a> { - tbs_response_data: ResponseData<'a>, - signature_algorithm: common::AlgorithmIdentifier<'a>, - signature: asn1::BitString<'a>, - #[explicit(0)] - certs: OCSPCerts<'a>, +fn singleresp_py_serial_number<'p>( + resp: &ocsp_resp::SingleResponse<'_>, + py: pyo3::Python<'p>, +) -> pyo3::PyResult<&'p pyo3::PyAny> { + big_byte_slice_to_py_int(py, resp.cert_id.serial_number.as_bytes()) } -impl BasicOCSPResponse<'_> { - fn single_response(&self) -> Result, CryptographyError> { - let responses = self.tbs_response_data.responses.unwrap_read(); - let num_responses = responses.len(); +fn singleresp_py_certificate_status<'p>( + resp: &ocsp_resp::SingleResponse<'_>, + py: pyo3::Python<'p>, +) -> pyo3::PyResult<&'p pyo3::PyAny> { + let attr = match resp.cert_status { + ocsp_resp::CertStatus::Good(_) => "GOOD", + ocsp_resp::CertStatus::Revoked(_) => "REVOKED", + ocsp_resp::CertStatus::Unknown(_) => "UNKNOWN", + }; + py.import(pyo3::intern!(py, "cryptography.x509.ocsp"))? + .getattr(pyo3::intern!(py, "OCSPCertStatus"))? + .getattr(attr) +} - if num_responses != 1 { - return Err(CryptographyError::from( - pyo3::exceptions::PyValueError::new_err(format!( - "OCSP response contains {} SINGLERESP structures. Use .response_iter to iterate through them", - num_responses - )) - )); +fn singleresp_py_hash_algorithm<'p>( + resp: &ocsp_resp::SingleResponse<'_>, + py: pyo3::Python<'p>, +) -> Result<&'p pyo3::PyAny, CryptographyError> { + let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; + match ocsp::OIDS_TO_HASH.get(&resp.cert_id.hash_algorithm.oid) { + Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), + None => { + let exceptions = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; + Err(CryptographyError::from(pyo3::PyErr::from_value( + exceptions + .getattr(pyo3::intern!(py, "UnsupportedAlgorithm"))? + .call1((format!( + "Signature algorithm OID: {} not recognized", + resp.cert_id.hash_algorithm.oid + ),))?, + ))) } - - Ok(responses.clone().next().unwrap()) } } -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -struct ResponseData<'a> { - #[explicit(0)] - #[default(0)] - version: u8, - responder_id: ResponderId<'a>, - produced_at: asn1::GeneralizedTime, - responses: common::Asn1ReadableOrWritable< - 'a, - asn1::SequenceOf<'a, SingleResponse<'a>>, - asn1::SequenceOfWriter<'a, SingleResponse<'a>, Vec>>, - >, - #[explicit(1)] - response_extensions: Option>, -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -enum ResponderId<'a> { - #[explicit(1)] - ByName(name::Name<'a>), - #[explicit(2)] - ByKey(&'a [u8]), +fn singleresp_py_this_update<'p>( + resp: &ocsp_resp::SingleResponse<'_>, + py: pyo3::Python<'p>, +) -> pyo3::PyResult<&'p pyo3::PyAny> { + x509::datetime_to_py(py, resp.this_update.as_datetime()) } -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -struct SingleResponse<'a> { - cert_id: ocsp_req::CertID<'a>, - cert_status: CertStatus, - this_update: asn1::GeneralizedTime, - #[explicit(0)] - next_update: Option, - #[explicit(1)] - single_extensions: Option>, -} - -impl SingleResponse<'_> { - fn py_serial_number<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - big_byte_slice_to_py_int(py, self.cert_id.serial_number.as_bytes()) - } - - fn py_certificate_status<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - let attr = match self.cert_status { - CertStatus::Good(_) => "GOOD", - CertStatus::Revoked(_) => "REVOKED", - CertStatus::Unknown(_) => "UNKNOWN", - }; - py.import(pyo3::intern!(py, "cryptography.x509.ocsp"))? - .getattr(pyo3::intern!(py, "OCSPCertStatus"))? - .getattr(attr) - } - - fn py_hash_algorithm<'p>( - &self, - py: pyo3::Python<'p>, - ) -> Result<&'p pyo3::PyAny, CryptographyError> { - let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; - match ocsp::OIDS_TO_HASH.get(&self.cert_id.hash_algorithm.oid) { - Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), - None => { - let exceptions = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; - Err(CryptographyError::from(pyo3::PyErr::from_value( - exceptions - .getattr(pyo3::intern!(py, "UnsupportedAlgorithm"))? - .call1((format!( - "Signature algorithm OID: {} not recognized", - self.cert_id.hash_algorithm.oid - ),))?, - ))) - } - } - } - - fn py_this_update<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - x509::datetime_to_py(py, self.this_update.as_datetime()) +fn singleresp_py_next_update<'p>( + resp: &ocsp_resp::SingleResponse<'_>, + py: pyo3::Python<'p>, +) -> pyo3::PyResult<&'p pyo3::PyAny> { + match &resp.next_update { + Some(v) => x509::datetime_to_py(py, v.as_datetime()), + None => Ok(py.None().into_ref(py)), } +} - fn py_next_update<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - match &self.next_update { - Some(v) => x509::datetime_to_py(py, v.as_datetime()), +fn singleresp_py_revocation_reason<'p>( + resp: &ocsp_resp::SingleResponse<'_>, + py: pyo3::Python<'p>, +) -> CryptographyResult<&'p pyo3::PyAny> { + match &resp.cert_status { + ocsp_resp::CertStatus::Revoked(revoked_info) => match revoked_info.revocation_reason { + Some(ref v) => crl::parse_crl_reason_flags(py, v), None => Ok(py.None().into_ref(py)), + }, + ocsp_resp::CertStatus::Good(_) | ocsp_resp::CertStatus::Unknown(_) => { + Ok(py.None().into_ref(py)) } } +} - fn py_revocation_reason<'p>( - &self, - py: pyo3::Python<'p>, - ) -> CryptographyResult<&'p pyo3::PyAny> { - match &self.cert_status { - CertStatus::Revoked(revoked_info) => match revoked_info.revocation_reason { - Some(ref v) => crl::parse_crl_reason_flags(py, v), - None => Ok(py.None().into_ref(py)), - }, - CertStatus::Good(_) | CertStatus::Unknown(_) => Ok(py.None().into_ref(py)), +fn singleresp_py_revocation_time<'p>( + resp: &ocsp_resp::SingleResponse<'_>, + py: pyo3::Python<'p>, +) -> pyo3::PyResult<&'p pyo3::PyAny> { + match &resp.cert_status { + ocsp_resp::CertStatus::Revoked(revoked_info) => { + x509::datetime_to_py(py, revoked_info.revocation_time.as_datetime()) } - } - - fn py_revocation_time<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - match &self.cert_status { - CertStatus::Revoked(revoked_info) => { - x509::datetime_to_py(py, revoked_info.revocation_time.as_datetime()) - } - CertStatus::Good(_) | CertStatus::Unknown(_) => Ok(py.None().into_ref(py)), + ocsp_resp::CertStatus::Good(_) | ocsp_resp::CertStatus::Unknown(_) => { + Ok(py.None().into_ref(py)) } } } -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -enum CertStatus { - #[implicit(0)] - Good(()), - #[implicit(1)] - Revoked(RevokedInfo), - #[implicit(2)] - Unknown(()), -} - -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -struct RevokedInfo { - revocation_time: asn1::GeneralizedTime, - #[explicit(0)] - revocation_reason: Option, -} - #[pyo3::prelude::pyfunction] fn create_ocsp_response( py: pyo3::Python<'_>, @@ -646,12 +579,12 @@ fn create_ocsp_response( .getattr(pyo3::intern!(py, "OCSPCertStatus"))? .getattr(pyo3::intern!(py, "GOOD"))?) { - CertStatus::Good(()) + ocsp_resp::CertStatus::Good(()) } else if py_cert_status.is(ocsp_mod .getattr(pyo3::intern!(py, "OCSPCertStatus"))? .getattr(pyo3::intern!(py, "UNKNOWN"))?) { - CertStatus::Unknown(()) + ocsp_resp::CertStatus::Unknown(()) } else { let revocation_reason = if !py_single_resp .getattr(pyo3::intern!(py, "_revocation_reason"))? @@ -674,7 +607,7 @@ fn create_ocsp_response( py_single_resp.getattr(pyo3::intern!(py, "_revocation_time"))?; let revocation_time = asn1::GeneralizedTime::new(py_to_datetime(py, py_revocation_time)?)?; - CertStatus::Revoked(RevokedInfo { + ocsp_resp::CertStatus::Revoked(ocsp_resp::RevokedInfo { revocation_time, revocation_reason, }) @@ -711,7 +644,7 @@ fn create_ocsp_response( .import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))? .getattr(pyo3::intern!(py, "SHA1"))? .call0()?; - ResponderId::ByKey(ocsp::hash_data( + ocsp_resp::ResponderId::ByKey(ocsp::hash_data( py, sha1, borrowed_cert @@ -723,7 +656,7 @@ fn create_ocsp_response( .as_bytes(), )?) } else { - ResponderId::ByName( + ocsp_resp::ResponderId::ByName( borrowed_cert .raw .borrow_value_public() @@ -733,7 +666,7 @@ fn create_ocsp_response( ) }; - let tbs_response_data = ResponseData { + let tbs_response_data = ocsp_resp::ResponseData { version: 0, produced_at: asn1::GeneralizedTime::new(x509::common::datetime_now(py)?)?, responder_id, @@ -772,13 +705,13 @@ fn create_ocsp_response( )) }); - let basic_resp = BasicOCSPResponse { + let basic_resp = ocsp_resp::BasicOCSPResponse { tbs_response_data, signature: asn1::BitString::new(signature, 0).unwrap(), signature_algorithm: sigalg, certs, }; - Some(ResponseBytes { + Some(ocsp_resp::ResponseBytes { response_type: (BASIC_RESPONSE_OID).clone(), response: asn1::OctetStringEncoded::new(basic_resp), }) @@ -786,7 +719,7 @@ fn create_ocsp_response( None }; - let resp = RawOCSPResponse { + let resp = ocsp_resp::OCSPResponse { response_status: asn1::Enumerated::new(response_status), response_bytes, }; @@ -803,7 +736,7 @@ pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult< #[ouroboros::self_referencing] struct OwnedOCSPResponseIteratorData { - data: Arc, + data: Arc, #[borrows(data)] #[covariant] value: asn1::SequenceOf<'this, SingleResponse<'this>>, @@ -835,10 +768,10 @@ impl OCSPResponseIterator { #[ouroboros::self_referencing] struct OwnedSingleResponse { - data: Arc, + data: Arc, #[borrows(data)] #[covariant] - value: SingleResponse<'this>, + value: ocsp_resp::SingleResponse<'this>, } #[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.ocsp")] @@ -856,7 +789,7 @@ impl OCSPSingleResponse { impl OCSPSingleResponse { #[getter] fn serial_number<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - self.single_response().py_serial_number(py) + singleresp_py_serial_number(self.single_response(), py) } #[getter] @@ -876,31 +809,37 @@ impl OCSPSingleResponse { &self, py: pyo3::Python<'p>, ) -> Result<&'p pyo3::PyAny, CryptographyError> { - self.single_response().py_hash_algorithm(py) + let single_resp = self.single_response(); + singleresp_py_hash_algorithm(single_resp, py) } #[getter] fn certificate_status<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - self.single_response().py_certificate_status(py) + let single_resp = self.single_response(); + singleresp_py_certificate_status(single_resp, py) } #[getter] fn revocation_time<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - self.single_response().py_revocation_time(py) + let single_resp = self.single_response(); + singleresp_py_revocation_time(single_resp, py) } #[getter] fn revocation_reason<'p>(&self, py: pyo3::Python<'p>) -> CryptographyResult<&'p pyo3::PyAny> { - self.single_response().py_revocation_reason(py) + let single_resp = self.single_response(); + singleresp_py_revocation_reason(single_resp, py) } #[getter] fn this_update<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - self.single_response().py_this_update(py) + let single_resp = self.single_response(); + singleresp_py_this_update(single_resp, py) } #[getter] fn next_update<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - self.single_response().py_next_update(py) + let single_resp = self.single_response(); + singleresp_py_next_update(single_resp, py) } } From 8f7313f67320f7699903c7eb9d512f7b7632f111 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 00:17:10 +0000 Subject: [PATCH 127/316] Bump BoringSSL and/or OpenSSL in CI (#8744) Co-authored-by: pyca-boringbot[bot] --- .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 5ee7a8595905..7c50e3d801c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,8 +43,8 @@ jobs: - {VERSION: "3.12-dev", NOXSESSION: "tests"} # Latest commit on the BoringSSL master branch, as of Apr 15, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "d3acd45456450f7e8091f0f56084bc2da93e48fe"}} - # Latest commit on the OpenSSL master branch, as of Apr 15, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "7eab7680ee61c64b2ae7acd9dd199ab6734f3d1f"}} + # Latest commit on the OpenSSL master branch, as of Apr 17, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "8835940db58229fc467cdea1eebf3f064352a086"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 15c05ca10096db4ecb7a853bbc971896c0a8f4f3 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 16 Apr 2023 20:37:51 -0400 Subject: [PATCH 128/316] Intern more strings (#8743) --- src/rust/src/x509/ocsp_resp.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index 3344867ba186..717be9565b7a 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -464,9 +464,9 @@ fn singleresp_py_certificate_status<'p>( py: pyo3::Python<'p>, ) -> pyo3::PyResult<&'p pyo3::PyAny> { let attr = match resp.cert_status { - ocsp_resp::CertStatus::Good(_) => "GOOD", - ocsp_resp::CertStatus::Revoked(_) => "REVOKED", - ocsp_resp::CertStatus::Unknown(_) => "UNKNOWN", + ocsp_resp::CertStatus::Good(_) => pyo3::intern!(py, "GOOD"), + ocsp_resp::CertStatus::Revoked(_) => pyo3::intern!(py, "REVOKED"), + ocsp_resp::CertStatus::Unknown(_) => pyo3::intern!(py, "UNKNOWN"), }; py.import(pyo3::intern!(py, "cryptography.x509.ocsp"))? .getattr(pyo3::intern!(py, "OCSPCertStatus"))? From ee1a3076157f9c7586d4f533594daeea3a10c8ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 09:27:47 -0400 Subject: [PATCH 129/316] Bump attrs from 22.2.0 to 23.1.0 (#8746) Bumps [attrs](https://github.com/python-attrs/attrs) from 22.2.0 to 23.1.0. - [Release notes](https://github.com/python-attrs/attrs/releases) - [Changelog](https://github.com/python-attrs/attrs/blob/main/CHANGELOG.md) - [Commits](https://github.com/python-attrs/attrs/compare/22.2.0...23.1.0) --- updated-dependencies: - dependency-name: attrs dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 4f00c537256f..4a8d9d262c38 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -9,7 +9,7 @@ alabaster==0.7.13 # via sphinx argcomplete==2.1.2 # via nox -attrs==22.2.0 +attrs==23.1.0 # via # pytest babel==2.12.1 From 2373401d1a6f2c2658150d0f932d952bb04d7d2e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 17 Apr 2023 16:18:59 -0400 Subject: [PATCH 130/316] Simplify Rust build script (#8745) Rather than spawn a python and pass the script on stdin, just use `-c` --- src/rust/build.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/rust/build.rs b/src/rust/build.rs index d315ec62d869..7b63b95d5d24 100644 --- a/src/rust/build.rs +++ b/src/rust/build.rs @@ -1,7 +1,6 @@ use std::env; -use std::io::Write; use std::path::Path; -use std::process::{Command, Stdio}; +use std::process::Command; #[allow(clippy::unusual_byte_groupings)] fn main() { @@ -91,18 +90,9 @@ fn run_python_script(interpreter: impl AsRef, script: &str) -> Result Err(format!( From 2f917b0e9b17828d7f5c9203f6d52416d4bca475 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 20:30:01 -0400 Subject: [PATCH 131/316] Bump BoringSSL and/or OpenSSL in CI (#8748) Co-authored-by: pyca-boringbot[bot] --- .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 7c50e3d801c7..b9bf5d294002 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 15, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "d3acd45456450f7e8091f0f56084bc2da93e48fe"}} - # Latest commit on the OpenSSL master branch, as of Apr 17, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "8835940db58229fc467cdea1eebf3f064352a086"}} + # Latest commit on the BoringSSL master branch, as of Apr 18, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "c466222febf86ef8e12c7926d5544354c905fce5"}} + # Latest commit on the OpenSSL master branch, as of Apr 18, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "dcfeb617477dd957f69e713cbc61fd4dca0f2db4"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 3f00e4d8c618b363bc8421aae586c897602f5af5 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 17 Apr 2023 23:01:25 -0400 Subject: [PATCH 132/316] Switch to an allow-list (#8747) Right now the rust subdirectory gets processed for packages, which never exist. This can break some development workflows. --- pyproject.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8024179a9738..8cf73cc44922 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,10 +60,7 @@ package-dir = {"" = "src"} [tool.setuptools.packages.find] where = ["src"] -exclude = [ - "_cffi_src", - "_cffi_src.*", -] +include = ["cryptography*"] [tool.setuptools.dynamic] version = {attr = "cryptography.__version__"} From f584cfe8662616a625344fcc4358c53048738cc7 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Wed, 19 Apr 2023 00:16:24 +0000 Subject: [PATCH 133/316] Bump BoringSSL and/or OpenSSL in CI (#8750) Co-authored-by: pyca-boringbot[bot] --- .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 b9bf5d294002..8b736add6cd8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 18, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "c466222febf86ef8e12c7926d5544354c905fce5"}} - # Latest commit on the OpenSSL master branch, as of Apr 18, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "dcfeb617477dd957f69e713cbc61fd4dca0f2db4"}} + # Latest commit on the BoringSSL master branch, as of Apr 19, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "6776d5cd8fcdf6c5e05bae2d655076dbeaa56103"}} + # Latest commit on the OpenSSL master branch, as of Apr 19, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "04e0abc8bb1c24534d16cc930b611ac1d03bc9bf"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 1d8375fcaa86ae65b499869d3936936dc9970e9e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 18 Apr 2023 22:54:40 -0400 Subject: [PATCH 134/316] Don't build boringssl rust bindings (#8751) rust-openssl isn't actually using them --- .github/workflows/build_openssl.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build_openssl.sh b/.github/workflows/build_openssl.sh index 704e29b41931..42357abae9fc 100755 --- a/.github/workflows/build_openssl.sh +++ b/.github/workflows/build_openssl.sh @@ -74,8 +74,7 @@ elif [[ "${TYPE}" == "boringssl" ]]; then git checkout "${VERSION}" mkdir build pushd build - # Find the default rust target based on what rustc is built for - cmake .. -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DRUST_BINDINGS="$(rustc -V --verbose | grep 'host: ' | sed 's/host: //')" -DCMAKE_INSTALL_PREFIX="${OSSL_PATH}" + cmake .. -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX="${OSSL_PATH}" make -j"$(nproc)" make install # delete binaries we don't need From 3e02d4d57387a6ab12db2300abbd7522ef830ac4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Apr 2023 13:12:14 +0000 Subject: [PATCH 135/316] Bump filelock from 3.11.0 to 3.12.0 (#8753) Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.11.0 to 3.12.0. - [Release notes](https://github.com/tox-dev/py-filelock/releases) - [Changelog](https://github.com/tox-dev/py-filelock/blob/main/docs/changelog.rst) - [Commits](https://github.com/tox-dev/py-filelock/compare/3.11.0...3.12.0) --- updated-dependencies: - dependency-name: filelock 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 4a8d9d262c38..71b4b9c0f180 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -43,7 +43,7 @@ exceptiongroup==1.1.1 # via pytest execnet==1.9.0 # via pytest-xdist -filelock==3.11.0 +filelock==3.12.0 # via virtualenv idna==3.4 # via requests From 278fc87a0b77444fab1b1eb9a36dc48b0d95f0df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Apr 2023 13:14:11 +0000 Subject: [PATCH 136/316] Bump pygments from 2.15.0 to 2.15.1 (#8754) Bumps [pygments](https://github.com/pygments/pygments) from 2.15.0 to 2.15.1. - [Release notes](https://github.com/pygments/pygments/releases) - [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES) - [Commits](https://github.com/pygments/pygments/compare/2.15.0...2.15.1) --- updated-dependencies: - dependency-name: pygments 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 71b4b9c0f180..60b04b364b84 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -98,7 +98,7 @@ pyenchant==3.2.2 # via # cryptography (pyproject.toml) # sphinxcontrib-spelling -pygments==2.15.0 +pygments==2.15.1 # via # readme-renderer # rich From fe6f5d4d6db20e37429d62eba98de3d23c40cf84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Apr 2023 21:50:14 +0000 Subject: [PATCH 137/316] Bump virtualenv from 20.21.0 to 20.21.1 (#8756) Bumps [virtualenv](https://github.com/pypa/virtualenv) from 20.21.0 to 20.21.1. - [Release notes](https://github.com/pypa/virtualenv/releases) - [Changelog](https://github.com/pypa/virtualenv/blob/main/docs/changelog.rst) - [Commits](https://github.com/pypa/virtualenv/compare/20.21.0...20.21.1) --- updated-dependencies: - dependency-name: virtualenv 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 60b04b364b84..74e323871056 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -180,7 +180,7 @@ urllib3==1.26.15 # via # requests # twine -virtualenv==20.21.0 +virtualenv==20.21.1 # via nox webencodings==0.5.1 # via bleach From de67d0c7201c6e107a7f69f36f80fda2f21e9e00 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Apr 2023 21:53:33 +0000 Subject: [PATCH 138/316] Bump ruff from 0.0.261 to 0.0.262 (#8757) Bumps [ruff](https://github.com/charliermarsh/ruff) from 0.0.261 to 0.0.262. - [Release notes](https://github.com/charliermarsh/ruff/releases) - [Changelog](https://github.com/charliermarsh/ruff/blob/main/BREAKING_CHANGES.md) - [Commits](https://github.com/charliermarsh/ruff/compare/v0.0.261...v0.0.262) --- updated-dependencies: - dependency-name: ruff 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 74e323871056..e960c623765d 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -133,7 +133,7 @@ rfc3986==2.0.0 # via twine rich==13.3.4 # via twine -ruff==0.0.261 +ruff==0.0.262 # via cryptography (pyproject.toml) six==1.16.0 # via bleach From ec5d5d77f3eb6f49dbd4d6c8b210d2c46481076b Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 20 Apr 2023 17:14:25 -0600 Subject: [PATCH 139/316] Fix CI (#8766) * Bump BoringSSL and/or OpenSSL in CI * Bump openssl from 0.10.50 to 0.10.51 in /src/rust Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.50 to 0.10.51. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.50...openssl-v0.10.51) --- updated-dependencies: - dependency-name: openssl dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Pin pyasn1 on twisted --------- Signed-off-by: dependabot[bot] Co-authored-by: pyca-boringbot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/downstream.d/twisted.sh | 2 +- .github/workflows/ci.yml | 8 ++++---- src/rust/Cargo.lock | 8 ++++---- src/rust/Cargo.toml | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/downstream.d/twisted.sh b/.github/downstream.d/twisted.sh index 9fc195ba7552..f8f294970507 100755 --- a/.github/downstream.d/twisted.sh +++ b/.github/downstream.d/twisted.sh @@ -5,7 +5,7 @@ case "${1}" in git clone --depth=1 https://github.com/twisted/twisted cd twisted git rev-parse HEAD - pip install ".[all_non_platform]" + pip install ".[all_non_platform]" "pyasn1!=0.5.0" ;; run) cd twisted diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b736add6cd8..d236722b194d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 19, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "6776d5cd8fcdf6c5e05bae2d655076dbeaa56103"}} - # Latest commit on the OpenSSL master branch, as of Apr 19, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "04e0abc8bb1c24534d16cc930b611ac1d03bc9bf"}} + # Latest commit on the BoringSSL master branch, as of Apr 20, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "bcecc7d834fc44ad257b2f23f88e1cf597ab2736"}} + # Latest commit on the OpenSSL master branch, as of Apr 20, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "c8093347f736c7991350d26048b680d0e64974a0"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 1fc04cecd0dc..38656b24ca9f 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -141,9 +141,9 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "openssl" -version = "0.10.50" +version = "0.10.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e30d8bc91859781f0a943411186324d580f2bbeb71b452fe91ae344806af3f1" +checksum = "97ea2d98598bf9ada7ea6ee8a30fb74f9156b63bbe495d64ec2b87c269d2dda3" dependencies = [ "bitflags", "cfg-if", @@ -167,9 +167,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.85" +version = "0.9.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d3d193fb1488ad46ffe3aaabc912cc931d02ee8518fe2959aea8ef52718b0c0" +checksum = "992bac49bdbab4423199c654a5515bd2a6c6a23bf03f2dd3bdb7e5ae6259bc69" dependencies = [ "cc", "libc", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index e96b1fc2b505..588d742bdeb7 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -14,7 +14,7 @@ asn1 = { version = "0.14.0", default-features = false } cryptography-x509 = { path = "cryptography-x509" } pem = "1.1" ouroboros = "0.15" -openssl = "0.10.50" +openssl = "0.10.51" openssl-sys = "0.9.85" foreign-types-shared = "0.1" From 3534a9c3a24aff0f18d5f1c359760dc237526710 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Apr 2023 17:37:22 -0600 Subject: [PATCH 140/316] Bump libc from 0.2.141 to 0.2.142 in /src/rust (#8765) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.141 to 0.2.142. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.141...0.2.142) --- 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 38656b24ca9f..7fdd8b92be21 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -110,9 +110,9 @@ checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" [[package]] name = "libc" -version = "0.2.141" +version = "0.2.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" [[package]] name = "lock_api" From f26dcee04d7c58cb452c2625d97bb7b005f837bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Apr 2023 23:50:30 +0000 Subject: [PATCH 141/316] Bump actions/setup-python from 4.5.0 to 4.6.0 (#8759) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.5.0 to 4.6.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v4.5.0...v4.6.0) --- updated-dependencies: - dependency-name: actions/setup-python 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/benchmark.yml | 2 +- .github/workflows/ci.yml | 14 +++++++------- .github/workflows/linkcheck.yml | 2 +- .github/workflows/wheel-builder.yml | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 09745aa48ca8..f121370e67df 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -35,7 +35,7 @@ jobs: - name: Setup python id: setup-python - uses: actions/setup-python@v4.5.0 + uses: actions/setup-python@v4.6.0 with: python-version: "3.11" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d236722b194d..84e46c70b0e7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/mtime-fix - name: Setup python id: setup-python - uses: actions/setup-python@v4.5.0 + uses: actions/setup-python@v4.6.0 with: python-version: ${{ matrix.PYTHON.VERSION }} - name: Clone wycheproof @@ -222,7 +222,7 @@ jobs: with: key: ${{ matrix.RUST }} - name: Setup python - uses: actions/setup-python@v4.5.0 + uses: actions/setup-python@v4.6.0 with: python-version: ${{ matrix.PYTHON }} - uses: dtolnay/rust-toolchain@52e69531e6f69a396bc9d1226284493a5db969ff @@ -297,7 +297,7 @@ jobs: ~/.cargo/bin/rust-size ~/.cargo/bin/rust-strip - name: Setup python - uses: actions/setup-python@v4.5.0 + uses: actions/setup-python@v4.6.0 with: python-version: ${{ matrix.PYTHON }} - run: cargo install cargo-binutils @@ -382,7 +382,7 @@ jobs: key: ${{ matrix.PYTHON.NOXSESSION }}-${{ matrix.PYTHON.VERSION }} - name: Setup python - uses: actions/setup-python@v4.5.0 + uses: actions/setup-python@v4.6.0 with: python-version: ${{ matrix.PYTHON.VERSION }} architecture: 'x64' # we force this right now so that it will install the universal2 on arm64 @@ -441,7 +441,7 @@ jobs: uses: ./.github/actions/mtime-fix - name: Setup python id: setup-python - uses: actions/setup-python@v4.5.0 + uses: actions/setup-python@v4.6.0 with: python-version: ${{ matrix.PYTHON.VERSION }} architecture: ${{ matrix.WINDOWS.ARCH }} @@ -516,7 +516,7 @@ jobs: uses: ./.github/actions/cache timeout-minutes: 2 - name: Setup python - uses: actions/setup-python@v4.5.0 + uses: actions/setup-python@v4.6.0 with: python-version: ${{ matrix.PYTHON }} - run: ./.github/downstream.d/${{ matrix.DOWNSTREAM }}.sh install @@ -558,7 +558,7 @@ jobs: jobs: ${{ toJSON(needs) }} - name: Setup python if: ${{ always() }} - uses: actions/setup-python@v4.5.0 + uses: actions/setup-python@v4.6.0 with: python-version: '3.11' - run: pip install -c ci-constraints-requirements.txt coverage[toml] diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml index 02457ec7bf18..8adca7075078 100644 --- a/.github/workflows/linkcheck.yml +++ b/.github/workflows/linkcheck.yml @@ -26,7 +26,7 @@ jobs: uses: ./.github/actions/mtime-fix - name: Setup python id: setup-python - uses: actions/setup-python@v4.5.0 + uses: actions/setup-python@v4.6.0 with: python-version: 3.11 - name: Cache rust and pip diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 83fe53d3aa4f..9306ce7415e7 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -190,7 +190,7 @@ jobs: PYTHON_DOWNLOAD_URL: ${{ matrix.PYTHON.DOWNLOAD_URL }} if: contains(matrix.PYTHON.VERSION, 'pypy') == false - name: Setup pypy - uses: actions/setup-python@v4.5.0 + uses: actions/setup-python@v4.6.0 with: python-version: ${{ matrix.PYTHON.VERSION }} if: contains(matrix.PYTHON.VERSION, 'pypy') @@ -264,7 +264,7 @@ jobs: name: cryptography-sdist - name: Setup python - uses: actions/setup-python@v4.5.0 + uses: actions/setup-python@v4.6.0 with: python-version: ${{ matrix.PYTHON.VERSION }} architecture: ${{ matrix.WINDOWS.ARCH }} From 7af92f2ffb3f3191c1ea3f61fa5c3d3666e5443a Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 20 Apr 2023 18:17:26 -0600 Subject: [PATCH 142/316] modify cache keys to incorporate rust version (#8762) * modify cache keys to incorporate rust version * Update .github/actions/cache/action.yml Co-authored-by: Alex Gaynor --------- Co-authored-by: Alex Gaynor --- .github/actions/cache/action.yml | 6 +++++- .github/workflows/ci.yml | 4 +--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/actions/cache/action.yml b/.github/actions/cache/action.yml index 67e6cd437030..3e8c300d03e1 100644 --- a/.github/actions/cache/action.yml +++ b/.github/actions/cache/action.yml @@ -19,6 +19,10 @@ runs: using: "composite" steps: + - name: Get rust version + id: rust-version + run: echo "version=$(rustc --version | sha256sum | cut -d ' ' -f 1)" >> $GITHUB_OUTPUT + shell: bash - name: Get pip cache dir id: pip-cache run: | @@ -39,7 +43,7 @@ runs: ~/.cargo/registry/cache/ src/rust/target/ ${{ inputs.additional-paths }} - key: cargo-pip-${{ runner.os }}-${{ runner.arch }}-${{ inputs.key }}-3-${{ hashFiles('**/Cargo.lock') }} + key: cargo-pip-${{ runner.os }}-${{ runner.arch }}-${{ inputs.key }}-3-${{ hashFiles('**/Cargo.lock') }}-${{ steps.rust-version.version }} - name: Size of cache items run: | du -sh ~/.cargo/registry/index/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 84e46c70b0e7..8037e9a3bfcc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -219,8 +219,6 @@ jobs: - name: Cache rust and pip uses: ./.github/actions/cache timeout-minutes: 2 - with: - key: ${{ matrix.RUST }} - name: Setup python uses: actions/setup-python@v4.6.0 with: @@ -275,7 +273,7 @@ jobs: uses: ./.github/actions/cache timeout-minutes: 2 with: - key: ${{ steps.rust-toolchain.outputs.cachekey }}-coverage + key: coverage additional-paths: | ~/.cargo/bin/cargo-cov ~/.cargo/bin/cargo-nm From 48f4bde6690020880a0b2dfa714d8a5ab6d46f19 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Thu, 20 Apr 2023 18:17:46 -0600 Subject: [PATCH 143/316] Bump BoringSSL and/or OpenSSL in CI (#8767) Co-authored-by: pyca-boringbot[bot] --- .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 8037e9a3bfcc..6617011f4ffe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,8 +43,8 @@ jobs: - {VERSION: "3.12-dev", NOXSESSION: "tests"} # Latest commit on the BoringSSL master branch, as of Apr 20, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "bcecc7d834fc44ad257b2f23f88e1cf597ab2736"}} - # Latest commit on the OpenSSL master branch, as of Apr 20, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "c8093347f736c7991350d26048b680d0e64974a0"}} + # Latest commit on the OpenSSL master branch, as of Apr 21, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "a901b31e99442f087051ae7efdcbc9ad6e6a5b33"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 15c622eae0819c1f4cc092b7276fb495cc354c9a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 21 Apr 2023 08:53:01 -0600 Subject: [PATCH 144/316] Don't try to compute coverage for anything in ~/.cargo (#8771) This way it'll exclude ~/.cargo/git as well --- .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 6617011f4ffe..62ef4f959d53 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -336,13 +336,13 @@ jobs: cargo cov -- export \ ../../.nox/tests/lib/python${{ matrix.PYTHON }}/site-packages/cryptography/hazmat/bindings/_rust.abi3.so \ -instr-profile=pytest-rust-cov.profdata \ - --ignore-filename-regex='/.cargo/registry' \ + --ignore-filename-regex='/.cargo/' \ --ignore-filename-regex='/rustc/' \ --ignore-filename-regex='/.rustup/toolchains/' --format=lcov > ../../${COV_UUID}-1.lcov cargo cov -- export \ $(env RUSTFLAGS="-Cinstrument-coverage" cargo test --no-default-features --all --tests --no-run --message-format=json | jq -r "select(.profile.test == true) | .filenames[]") \ -instr-profile=cargo-test-rust-cov.profdata \ - --ignore-filename-regex='/.cargo/registry' \ + --ignore-filename-regex='/.cargo/' \ --ignore-filename-regex='/rustc/' \ --ignore-filename-regex='/.rustup/toolchains/' --format=lcov > ../../${COV_UUID}-2.lcov From 34edbb2e17f4c633caa54615668738bc03c081f5 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 21 Apr 2023 11:16:35 -0600 Subject: [PATCH 145/316] Update FAQ (#8773) Add a Q on the scope of our issue tracker, and remove a legacy Q. --- docs/faq.rst | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/docs/faq.rst b/docs/faq.rst index 1bbf5eb4b7a9..ac7f4152c731 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -1,6 +1,22 @@ Frequently asked questions ========================== +What issues can you help with in your issue tracker? +---------------------------------------------------- + +The primary purpose of our issue tracker is to enable us to identify and +resolve bugs and feature requests in ``cryptography``, so any time a user +files a bug, we start by asking: Is this a ``cryptography`` bug, or is it a +bug somewhere else? + +That said, we do our best to help users to debug issues that are in their code +or environments. Please note, however, that there's a limit to our ability to +assist users in resolving problems that are specific to their environments, +particularly when we have no way to reproduce the issue. + +Lastly, we're not able to provide support for general Python or Python +packaging issues. + .. _faq-howto-handle-deprecation-warning: I cannot suppress the deprecation warning that ``cryptography`` emits on import @@ -102,15 +118,6 @@ If you have no other libraries using OpenSSL in your process, or they do not appear to be at fault, it's possible that this is a bug in ``cryptography``. Please file an `issue`_ with instructions on how to reproduce it. -error: ``-Werror=sign-conversion``: No option ``-Wsign-conversion`` during installation ---------------------------------------------------------------------------------------- - -The compiler you are using is too old and not supported by ``cryptography``. -Please upgrade to a more recent version. If you are running OpenBSD 6.1 or -earlier the default compiler is extremely old. Use ``pkg_add`` to install a -newer ``gcc`` and then install ``cryptography`` using -``CC=/path/to/newer/gcc pip install cryptography``. - Installing cryptography with OpenSSL 0.9.8, 1.0.0, 1.0.1, 1.0.2, 1.1.0 fails ---------------------------------------------------------------------------- @@ -154,7 +161,7 @@ Why can't I import my PEM file? ------------------------------- PEM is a format (defined by several RFCs, but originally :rfc:`1421`) for -encoding keys, certificates and others cryptographic data into a regular form. +encoding keys, certificates, and others cryptographic data into a regular form. The data is encoded as base64 and wrapped with a header and footer. If you are having trouble importing PEM files, make sure your file fits From 923fe070bad8880d55dee26cc10fd521f30e1e40 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 21 Apr 2023 11:40:19 -0600 Subject: [PATCH 146/316] Added a benchmark for hashing (#8774) --- tests/bench/test_hashes.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/bench/test_hashes.py diff --git a/tests/bench/test_hashes.py b/tests/bench/test_hashes.py new file mode 100644 index 000000000000..49ca5be30d6b --- /dev/null +++ b/tests/bench/test_hashes.py @@ -0,0 +1,14 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives import hashes + + +def test_sha256(benchmark): + def bench(): + h = hashes.Hash(hashes.SHA256()) + h.update(b"I love hashing. So much. The best.") + return h.finalize() + + benchmark(bench) From 8397cd2a05692a4f54cf6335befe36ea19e5e11b Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 21 Apr 2023 14:06:41 -0600 Subject: [PATCH 147/316] Convert hashes to Rust (#8775) --- .../hazmat/backends/openssl/backend.py | 6 - .../hazmat/backends/openssl/hashes.py | 88 ---------- .../bindings/_rust/openssl/__init__.pyi | 2 + .../hazmat/bindings/_rust/openssl/hashes.pyi | 17 ++ src/cryptography/hazmat/primitives/hashes.py | 76 ++++----- src/rust/src/backend/hashes.rs | 154 ++++++++++++++++++ src/rust/src/backend/mod.rs | 3 + tests/hazmat/primitives/utils.py | 1 - 8 files changed, 205 insertions(+), 142 deletions(-) delete mode 100644 src/cryptography/hazmat/backends/openssl/hashes.py create mode 100644 src/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi create mode 100644 src/rust/src/backend/hashes.rs diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 71215e6b4c24..6176d16d97fd 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -30,7 +30,6 @@ _EllipticCurvePrivateKey, _EllipticCurvePublicKey, ) -from cryptography.hazmat.backends.openssl.hashes import _HashContext from cryptography.hazmat.backends.openssl.hmac import _HMACContext from cryptography.hazmat.backends.openssl.poly1305 import ( _POLY1305_KEY_SIZE, @@ -274,11 +273,6 @@ def hmac_supported(self, algorithm: hashes.HashAlgorithm) -> bool: return self.hash_supported(algorithm) - def create_hash_ctx( - self, algorithm: hashes.HashAlgorithm - ) -> hashes.HashContext: - return _HashContext(self, algorithm) - def cipher_supported(self, cipher: CipherAlgorithm, mode: Mode) -> bool: if self._fips_enabled: # FIPS mode requires AES. TripleDES is disallowed/deprecated in diff --git a/src/cryptography/hazmat/backends/openssl/hashes.py b/src/cryptography/hazmat/backends/openssl/hashes.py deleted file mode 100644 index 370407aac58d..000000000000 --- a/src/cryptography/hazmat/backends/openssl/hashes.py +++ /dev/null @@ -1,88 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.primitives import hashes - -if typing.TYPE_CHECKING: - from cryptography.hazmat.backends.openssl.backend import Backend - - -class _HashContext(hashes.HashContext): - def __init__( - self, backend: Backend, algorithm: hashes.HashAlgorithm, ctx=None - ) -> None: - self._algorithm = algorithm - - self._backend = backend - - if ctx is None: - ctx = self._backend._lib.EVP_MD_CTX_new() - ctx = self._backend._ffi.gc( - ctx, self._backend._lib.EVP_MD_CTX_free - ) - evp_md = self._backend._evp_md_from_algorithm(algorithm) - if evp_md == self._backend._ffi.NULL: - raise UnsupportedAlgorithm( - "{} is not a supported hash on this backend.".format( - algorithm.name - ), - _Reasons.UNSUPPORTED_HASH, - ) - res = self._backend._lib.EVP_DigestInit_ex( - ctx, evp_md, self._backend._ffi.NULL - ) - self._backend.openssl_assert(res != 0) - - self._ctx = ctx - - @property - def algorithm(self) -> hashes.HashAlgorithm: - return self._algorithm - - def copy(self) -> _HashContext: - copied_ctx = self._backend._lib.EVP_MD_CTX_new() - copied_ctx = self._backend._ffi.gc( - copied_ctx, self._backend._lib.EVP_MD_CTX_free - ) - res = self._backend._lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx) - self._backend.openssl_assert(res != 0) - return _HashContext(self._backend, self.algorithm, ctx=copied_ctx) - - def update(self, data: bytes) -> None: - data_ptr = self._backend._ffi.from_buffer(data) - res = self._backend._lib.EVP_DigestUpdate( - self._ctx, data_ptr, len(data) - ) - self._backend.openssl_assert(res != 0) - - def finalize(self) -> bytes: - if isinstance(self.algorithm, hashes.ExtendableOutputFunction): - # extendable output functions use a different finalize - return self._finalize_xof() - else: - buf = self._backend._ffi.new( - "unsigned char[]", self._backend._lib.EVP_MAX_MD_SIZE - ) - outlen = self._backend._ffi.new("unsigned int *") - res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen) - self._backend.openssl_assert(res != 0) - self._backend.openssl_assert( - outlen[0] == self.algorithm.digest_size - ) - return self._backend._ffi.buffer(buf)[: outlen[0]] - - def _finalize_xof(self) -> bytes: - buf = self._backend._ffi.new( - "unsigned char[]", self.algorithm.digest_size - ) - res = self._backend._lib.EVP_DigestFinalXOF( - self._ctx, buf, self.algorithm.digest_size - ) - self._backend.openssl_assert(res != 0) - return self._backend._ffi.buffer(buf)[: self.algorithm.digest_size] diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi index aceb859c63c7..07fa9d7b9320 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -7,6 +7,7 @@ import typing from cryptography.hazmat.bindings._rust.openssl import ( ed448, ed25519, + hashes, x448, x25519, ) @@ -14,6 +15,7 @@ from cryptography.hazmat.bindings._rust.openssl import ( __all__ = [ "openssl_version", "raise_openssl_error", + "hashes", "ed448", "ed25519", "x448", diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi new file mode 100644 index 000000000000..ca5f42a00615 --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi @@ -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 typing + +from cryptography.hazmat.primitives import hashes + +class Hash(hashes.HashContext): + def __init__( + self, algorithm: hashes.HashAlgorithm, backend: typing.Any = None + ) -> None: ... + @property + def algorithm(self) -> hashes.HashAlgorithm: ... + def update(self, data: bytes) -> None: ... + def finalize(self) -> bytes: ... + def copy(self) -> Hash: ... diff --git a/src/cryptography/hazmat/primitives/hashes.py b/src/cryptography/hazmat/primitives/hashes.py index c4b7d1060ada..b6a7ff140e68 100644 --- a/src/cryptography/hazmat/primitives/hashes.py +++ b/src/cryptography/hazmat/primitives/hashes.py @@ -7,8 +7,31 @@ import abc import typing -from cryptography import utils -from cryptography.exceptions import AlreadyFinalized +from cryptography.hazmat.bindings._rust import openssl as rust_openssl + +__all__ = [ + "HashAlgorithm", + "HashContext", + "Hash", + "ExtendableOutputFunction", + "SHA1", + "SHA512_224", + "SHA512_256", + "SHA224", + "SHA256", + "SHA384", + "SHA512", + "SHA3_224", + "SHA3_256", + "SHA3_384", + "SHA3_512", + "SHAKE128", + "SHAKE256", + "MD5", + "BLAKE2b", + "BLAKE2s", + "SM3", +] class HashAlgorithm(metaclass=abc.ABCMeta): @@ -62,57 +85,16 @@ def copy(self) -> HashContext: """ +Hash = rust_openssl.hashes.Hash +HashContext.register(Hash) + + class ExtendableOutputFunction(metaclass=abc.ABCMeta): """ An interface for extendable output functions. """ -class Hash(HashContext): - _ctx: typing.Optional[HashContext] - - def __init__( - self, - algorithm: HashAlgorithm, - backend: typing.Any = None, - ctx: typing.Optional[HashContext] = None, - ) -> None: - if not isinstance(algorithm, HashAlgorithm): - raise TypeError("Expected instance of hashes.HashAlgorithm.") - self._algorithm = algorithm - - if ctx is None: - from cryptography.hazmat.backends.openssl.backend import ( - backend as ossl, - ) - - self._ctx = ossl.create_hash_ctx(self.algorithm) - else: - self._ctx = ctx - - @property - def algorithm(self) -> HashAlgorithm: - return self._algorithm - - def update(self, data: bytes) -> None: - if self._ctx is None: - raise AlreadyFinalized("Context was already finalized.") - utils._check_byteslike("data", data) - self._ctx.update(data) - - def copy(self) -> Hash: - if self._ctx is None: - raise AlreadyFinalized("Context was already finalized.") - return Hash(self.algorithm, ctx=self._ctx.copy()) - - def finalize(self) -> bytes: - if self._ctx is None: - raise AlreadyFinalized("Context was already finalized.") - digest = self._ctx.finalize() - self._ctx = None - return digest - - class SHA1(HashAlgorithm): name = "sha1" digest_size = 20 diff --git a/src/rust/src/backend/hashes.rs b/src/rust/src/backend/hashes.rs new file mode 100644 index 000000000000..807890365265 --- /dev/null +++ b/src/rust/src/backend/hashes.rs @@ -0,0 +1,154 @@ +// This file is dual licensed under the terms of the Apache License, Version +// 2.0, and the BSD License. See the LICENSE file in the root of this repository +// for complete details. + +use crate::buf::CffiBuf; +use crate::error::{CryptographyError, CryptographyResult}; +use std::borrow::Cow; + +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.hashes")] +struct Hash { + #[pyo3(get)] + algorithm: pyo3::Py, + ctx: Option, +} + +impl Hash { + fn get_ctx(&self, py: pyo3::Python<'_>) -> CryptographyResult<&openssl::hash::Hasher> { + if let Some(ctx) = self.ctx.as_ref() { + return Ok(ctx); + }; + Err(CryptographyError::from(pyo3::PyErr::from_value( + py.import(pyo3::intern!(py, "cryptography.exceptions"))? + .call_method1( + pyo3::intern!(py, "AlreadyFinalized"), + ("Context was already finalized.",), + )?, + ))) + } + + fn get_mut_ctx( + &mut self, + py: pyo3::Python<'_>, + ) -> CryptographyResult<&mut openssl::hash::Hasher> { + if let Some(ctx) = self.ctx.as_mut() { + return Ok(ctx); + } + Err(CryptographyError::from(pyo3::PyErr::from_value( + py.import(pyo3::intern!(py, "cryptography.exceptions"))? + .call_method1( + pyo3::intern!(py, "AlreadyFinalized"), + ("Context was already finalized.",), + )?, + ))) + } +} + +#[pyo3::pymethods] +impl Hash { + #[new] + #[pyo3(signature = (algorithm, backend=None))] + fn new( + py: pyo3::Python<'_>, + algorithm: &pyo3::PyAny, + backend: Option<&pyo3::PyAny>, + ) -> CryptographyResult { + let _ = backend; + let hash_algorithm_class = py + .import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))? + .getattr(pyo3::intern!(py, "HashAlgorithm"))?; + if !algorithm.is_instance(hash_algorithm_class)? { + return Err(CryptographyError::from( + pyo3::exceptions::PyTypeError::new_err( + "Expected instance of hashes.HashAlgorithm.", + ), + )); + } + + let name = algorithm + .getattr(pyo3::intern!(py, "name"))? + .extract::<&str>()?; + let openssl_name = if name == "blake2b" || name == "blake2s" { + let digest_size = algorithm + .getattr(pyo3::intern!(py, "digest_size"))? + .extract::()?; + Cow::Owned(format!("{}{}", name, digest_size * 8)) + } else { + Cow::Borrowed(name) + }; + + let md = match openssl::hash::MessageDigest::from_name(&openssl_name) { + Some(md) => md, + None => { + let exceptions_module = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; + let reason = exceptions_module + .getattr(pyo3::intern!(py, "_Reasons"))? + .getattr(pyo3::intern!(py, "UNSUPPORTED_HASH"))?; + return Err(CryptographyError::from(pyo3::PyErr::from_value( + exceptions_module.call_method1( + pyo3::intern!(py, "UnsupportedAlgorithm"), + ( + format!("{} is not a supported hash on this backend", name), + reason, + ), + )?, + ))); + } + }; + let ctx = openssl::hash::Hasher::new(md)?; + + Ok(Hash { + algorithm: algorithm.into(), + ctx: Some(ctx), + }) + } + + fn update(&mut self, py: pyo3::Python<'_>, data: CffiBuf<'_>) -> CryptographyResult<()> { + self.get_mut_ctx(py)?.update(data.as_bytes())?; + Ok(()) + } + + fn finalize<'p>( + &mut self, + py: pyo3::Python<'p>, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + #[cfg(not(any(CRYPTOGRAPHY_IS_LIBRESSL, CRYPTOGRAPHY_IS_BORINGSSL)))] + { + let xof_class = py + .import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))? + .getattr(pyo3::intern!(py, "ExtendableOutputFunction"))?; + let algorithm = self.algorithm.clone_ref(py); + let algorithm = algorithm.as_ref(py); + if algorithm.is_instance(xof_class)? { + let ctx = self.get_mut_ctx(py)?; + let digest_size = algorithm + .getattr(pyo3::intern!(py, "digest_size"))? + .extract::()?; + let result = pyo3::types::PyBytes::new_with(py, digest_size, |b| { + ctx.finish_xof(b).unwrap(); + Ok(()) + })?; + self.ctx = None; + return Ok(result); + } + } + + let data = self.get_mut_ctx(py)?.finish()?; + self.ctx = None; + Ok(pyo3::types::PyBytes::new(py, &data)) + } + + fn copy(&self, py: pyo3::Python<'_>) -> CryptographyResult { + Ok(Hash { + algorithm: self.algorithm.clone_ref(py), + ctx: Some(self.get_ctx(py)?.clone()), + }) + } +} + +pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let m = pyo3::prelude::PyModule::new(py, "hashes")?; + m.add_class::()?; + + Ok(m) +} diff --git a/src/rust/src/backend/mod.rs b/src/rust/src/backend/mod.rs index d2d8cd478548..c4095a03d5f9 100644 --- a/src/rust/src/backend/mod.rs +++ b/src/rust/src/backend/mod.rs @@ -6,6 +6,7 @@ pub(crate) mod ed25519; #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] pub(crate) mod ed448; +pub(crate) mod hashes; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] pub(crate) mod utils; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] @@ -24,5 +25,7 @@ pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult< #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] module.add_submodule(x448::create_module(module.py())?)?; + module.add_submodule(hashes::create_module(module.py())?)?; + Ok(()) } diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 282744e80eaa..637c1eaa67f2 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -209,7 +209,6 @@ def base_hash_test(backend, algorithm, digest_size): assert m.algorithm.digest_size == digest_size m_copy = m.copy() assert m != m_copy - assert m._ctx != m_copy._ctx m.update(b"abc") copy = m.copy() From 1bc46c7298bb4e309afb765552a7e155e9d02b90 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 21 Apr 2023 15:24:11 -0600 Subject: [PATCH 148/316] Added a benchmark for hmac (#8776) --- tests/bench/test_hmac.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/bench/test_hmac.py diff --git a/tests/bench/test_hmac.py b/tests/bench/test_hmac.py new file mode 100644 index 000000000000..b5b1e33bd8b9 --- /dev/null +++ b/tests/bench/test_hmac.py @@ -0,0 +1,14 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives import hashes, hmac + + +def test_hmac_sha256(benchmark): + def bench(): + h = hmac.HMAC(b"my extremely secure key", hashes.SHA256()) + h.update(b"I love hashing. So much. The best.") + return h.finalize() + + benchmark(bench) From 49dee344a1ae64c91398f6586a92f9b05a0c1961 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 21 Apr 2023 17:04:45 -0500 Subject: [PATCH 149/316] update MAC docs (#8777) * Update hmac.rst * Update poly1305.rst --- docs/hazmat/primitives/mac/hmac.rst | 2 +- docs/hazmat/primitives/mac/poly1305.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/hazmat/primitives/mac/hmac.rst b/docs/hazmat/primitives/mac/hmac.rst index c94b7902dfa6..bce8538d1bfd 100644 --- a/docs/hazmat/primitives/mac/hmac.rst +++ b/docs/hazmat/primitives/mac/hmac.rst @@ -54,7 +54,7 @@ of a message. ... cryptography.exceptions.InvalidSignature: Signature did not match digest. - :param key: Secret key as ``bytes``. + :param key: The secret key. :type key: :term:`bytes-like` :param algorithm: An :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` diff --git a/docs/hazmat/primitives/mac/poly1305.rst b/docs/hazmat/primitives/mac/poly1305.rst index 7504a076e81b..e3240f5baccf 100644 --- a/docs/hazmat/primitives/mac/poly1305.rst +++ b/docs/hazmat/primitives/mac/poly1305.rst @@ -48,7 +48,7 @@ messages allows an attacker to forge tags. Poly1305 is described in ... cryptography.exceptions.InvalidSignature: Value did not match computed tag. - :param key: Secret key as ``bytes``. + :param key: The secret key. :type key: :term:`bytes-like` :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the version of OpenSSL ``cryptography`` is compiled against does not From c7cbfeccac42e434a5c67578054b9b5df50659bb Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 21 Apr 2023 16:29:54 -0600 Subject: [PATCH 150/316] Remove now unused bindings (#8778) --- src/_cffi_src/openssl/evp.py | 12 ------------ src/_cffi_src/openssl/nid.py | 1 - 2 files changed, 13 deletions(-) diff --git a/src/_cffi_src/openssl/evp.py b/src/_cffi_src/openssl/evp.py index aa92f1ddb968..b22c2ac0f9fa 100644 --- a/src/_cffi_src/openssl/evp.py +++ b/src/_cffi_src/openssl/evp.py @@ -58,10 +58,6 @@ void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *); int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *, int); -int EVP_MD_CTX_copy_ex(EVP_MD_CTX *, const EVP_MD_CTX *); -int EVP_DigestInit_ex(EVP_MD_CTX *, const EVP_MD *, ENGINE *); -int EVP_DigestUpdate(EVP_MD_CTX *, const void *, size_t); -int EVP_DigestFinal_ex(EVP_MD_CTX *, unsigned char *, unsigned int *); int EVP_DigestFinalXOF(EVP_MD_CTX *, unsigned char *, size_t); const EVP_MD *EVP_get_digestbyname(const char *); @@ -91,13 +87,9 @@ ENGINE *, EVP_PKEY *); int EVP_DigestSignUpdate(EVP_MD_CTX *, const void *, size_t); int EVP_DigestSignFinal(EVP_MD_CTX *, unsigned char *, size_t *); -int EVP_DigestVerifyInit(EVP_MD_CTX *, EVP_PKEY_CTX **, const EVP_MD *, - ENGINE *, EVP_PKEY *); - EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *, ENGINE *); -EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int, ENGINE *); void EVP_PKEY_CTX_free(EVP_PKEY_CTX *); int EVP_PKEY_sign_init(EVP_PKEY_CTX *); int EVP_PKEY_sign(EVP_PKEY_CTX *, unsigned char *, size_t *, @@ -117,8 +109,6 @@ int EVP_PKEY_cmp(const EVP_PKEY *, const EVP_PKEY *); -int EVP_PKEY_keygen_init(EVP_PKEY_CTX *); -int EVP_PKEY_keygen(EVP_PKEY_CTX *, EVP_PKEY **); int EVP_PKEY_derive_init(EVP_PKEY_CTX *); int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *, EVP_PKEY *); int EVP_PKEY_derive_set_peer_ex(EVP_PKEY_CTX *, EVP_PKEY *, int); @@ -131,8 +121,6 @@ int EVP_DigestSign(EVP_MD_CTX *, unsigned char *, size_t *, const unsigned char *, size_t); -int EVP_DigestVerify(EVP_MD_CTX *, const unsigned char *, size_t, - const unsigned char *, size_t); int EVP_PKEY_bits(const EVP_PKEY *); diff --git a/src/_cffi_src/openssl/nid.py b/src/_cffi_src/openssl/nid.py index 8933c95d82f0..7f6cb62303af 100644 --- a/src/_cffi_src/openssl/nid.py +++ b/src/_cffi_src/openssl/nid.py @@ -16,7 +16,6 @@ static const int NID_undef; static const int NID_aes_256_cbc; static const int NID_pbe_WithSHA1And3_Key_TripleDES_CBC; -static const int NID_X448; static const int NID_ED25519; static const int NID_ED448; static const int NID_poly1305; From 5d843986ce5e40a59f6578f2937d57aae30d3dd0 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 21 Apr 2023 17:41:36 -0600 Subject: [PATCH 151/316] Do sigstore signatures when uploading to pypi (#8779) * Do sigstore signatures when uploading to pypi * Update .github/workflows/pypi-publish.yml Co-authored-by: Paul Kehrer --------- Co-authored-by: Paul Kehrer --- .github/workflows/pypi-publish.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml index e873b579b58f..eed42830ecc7 100644 --- a/.github/workflows/pypi-publish.yml +++ b/.github/workflows/pypi-publish.yml @@ -29,7 +29,7 @@ jobs: with: path: dist/ run_id: ${{ github.event.inputs.run_id || github.event.workflow_run.id }} - - run: pip install twine requests + - run: pip install twine requests sigstore - run: | echo "OIDC_AUDIENCE=pypi" >> $GITHUB_ENV @@ -67,3 +67,10 @@ jobs: shell: python - run: twine upload --skip-existing $(find dist/ -type f -name 'cryptography*') + + # Do not perform sigstore signatures for things for TestPyPI. This is + # because there's nothing that would prevent a malicious PyPI from + # serving a signed TestPyPI asset in place of a release intended for + # PyPI. + - run: sigstore sign $(find dist/ -type f -name 'cryptography*') + if: env.TWINE_REPOSITORY == 'pypi' From 30525e82c77b91963c4f2e8931d2b0257689d364 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Sat, 22 Apr 2023 00:16:16 +0000 Subject: [PATCH 152/316] Bump BoringSSL and/or OpenSSL in CI (#8780) Co-authored-by: pyca-boringbot[bot] --- .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 62ef4f959d53..bb9e0ca5195e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 20, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "bcecc7d834fc44ad257b2f23f88e1cf597ab2736"}} - # Latest commit on the OpenSSL master branch, as of Apr 21, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "a901b31e99442f087051ae7efdcbc9ad6e6a5b33"}} + # Latest commit on the BoringSSL master branch, as of Apr 22, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "b0b1f9dfc583c96d5f91b7f8cdb7efabcf22793b"}} + # Latest commit on the OpenSSL master branch, as of Apr 22, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "c04e78f0c69201226430fed14c291c281da47f2d"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 40a3c07703d11a951b74d1b2bdd36a3a03763e80 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 22 Apr 2023 11:29:11 -0600 Subject: [PATCH 153/316] Simplify CI config, and require less duplication (#8782) --- .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 bb9e0ca5195e..d872dfaaaf6d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -330,7 +330,7 @@ jobs: set -xe cd src/rust/ cargo profdata -- merge -sparse ../../rust-cov/*.profraw -o pytest-rust-cov.profdata - cargo profdata -- merge -sparse rust-cov/*.profraw cryptography-x509/rust-cov/*.profraw -o cargo-test-rust-cov.profdata + cargo profdata -- merge -sparse $(find . -iname "*.profraw") -o cargo-test-rust-cov.profdata COV_UUID=$(python3 -c "import uuid; print(uuid.uuid4())") cargo cov -- export \ From e107518f1e534aae8562281624cef8a8ee7aad61 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 22 Apr 2023 11:56:38 -0600 Subject: [PATCH 154/316] Attempt to consolidate rust cov invocations (#8783) --- .github/workflows/ci.yml | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d872dfaaaf6d..2ae0092ef535 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -329,24 +329,18 @@ jobs: run: | set -xe cd src/rust/ - cargo profdata -- merge -sparse ../../rust-cov/*.profraw -o pytest-rust-cov.profdata - cargo profdata -- merge -sparse $(find . -iname "*.profraw") -o cargo-test-rust-cov.profdata + cargo profdata -- merge -sparse $(find ../.. -iname "*.profraw") -o rust-cov.profdata COV_UUID=$(python3 -c "import uuid; print(uuid.uuid4())") cargo cov -- export \ ../../.nox/tests/lib/python${{ matrix.PYTHON }}/site-packages/cryptography/hazmat/bindings/_rust.abi3.so \ - -instr-profile=pytest-rust-cov.profdata \ + $(env RUSTFLAGS="-Cinstrument-coverage" cargo test --no-default-features --all --tests --no-run --message-format=json | jq -r "select(.profile.test == true) | .filenames[]" | awk '{print "-object " $0}') \ + -instr-profile=rust-cov.profdata \ --ignore-filename-regex='/.cargo/' \ --ignore-filename-regex='/rustc/' \ - --ignore-filename-regex='/.rustup/toolchains/' --format=lcov > ../../${COV_UUID}-1.lcov - cargo cov -- export \ - $(env RUSTFLAGS="-Cinstrument-coverage" cargo test --no-default-features --all --tests --no-run --message-format=json | jq -r "select(.profile.test == true) | .filenames[]") \ - -instr-profile=cargo-test-rust-cov.profdata \ - --ignore-filename-regex='/.cargo/' \ - --ignore-filename-regex='/rustc/' \ - --ignore-filename-regex='/.rustup/toolchains/' --format=lcov > ../../${COV_UUID}-2.lcov + --ignore-filename-regex='/.rustup/toolchains/' --format=lcov > "../../${COV_UUID}.lcov" - sed -E -i 's/SF:(.*)\/src\/rust\/(.*)/SF:src\/rust\/\2/g' ../../*.lcov + sed -E -i 's/SF:(.*)\/src\/rust\/(.*)/SF:src\/rust\/\2/g' "../../${COV_UUID}.lcov" - uses: ./.github/actions/upload-coverage macos: From 8d616959f964a0aec6382ef4816990bef6e84619 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 22 Apr 2023 12:20:57 -0600 Subject: [PATCH 155/316] Convert HMAC to Rust (#8781) --- .../hazmat/backends/openssl/backend.py | 6 - .../hazmat/backends/openssl/hmac.py | 86 -------------- .../bindings/_rust/openssl/__init__.pyi | 2 + .../hazmat/bindings/_rust/openssl/hmac.pyi | 21 ++++ src/cryptography/hazmat/primitives/hmac.py | 66 +---------- src/rust/Cargo.lock | 11 ++ src/rust/Cargo.toml | 3 +- src/rust/cryptography-openssl/Cargo.toml | 14 +++ src/rust/cryptography-openssl/src/hmac.rs | 93 +++++++++++++++ src/rust/cryptography-openssl/src/lib.rs | 36 ++++++ src/rust/src/backend/hashes.rs | 112 +++++++++--------- src/rust/src/backend/hmac.rs | 104 ++++++++++++++++ src/rust/src/backend/mod.rs | 2 + tests/hazmat/primitives/test_hmac.py | 5 + tests/hazmat/primitives/utils.py | 1 - 15 files changed, 353 insertions(+), 209 deletions(-) delete mode 100644 src/cryptography/hazmat/backends/openssl/hmac.py create mode 100644 src/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi create mode 100644 src/rust/cryptography-openssl/Cargo.toml create mode 100644 src/rust/cryptography-openssl/src/hmac.rs create mode 100644 src/rust/cryptography-openssl/src/lib.rs create mode 100644 src/rust/src/backend/hmac.rs diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 6176d16d97fd..04b25f471a76 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -30,7 +30,6 @@ _EllipticCurvePrivateKey, _EllipticCurvePublicKey, ) -from cryptography.hazmat.backends.openssl.hmac import _HMACContext from cryptography.hazmat.backends.openssl.poly1305 import ( _POLY1305_KEY_SIZE, _Poly1305Context, @@ -223,11 +222,6 @@ def openssl_version_text(self) -> str: def openssl_version_number(self) -> int: return self._lib.OpenSSL_version_num() - def create_hmac_ctx( - self, key: bytes, algorithm: hashes.HashAlgorithm - ) -> _HMACContext: - return _HMACContext(self, key, algorithm) - def _evp_md_from_algorithm(self, algorithm: hashes.HashAlgorithm): if algorithm.name == "blake2b" or algorithm.name == "blake2s": alg = "{}{}".format( diff --git a/src/cryptography/hazmat/backends/openssl/hmac.py b/src/cryptography/hazmat/backends/openssl/hmac.py deleted file mode 100644 index 669f380705e1..000000000000 --- a/src/cryptography/hazmat/backends/openssl/hmac.py +++ /dev/null @@ -1,86 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography.exceptions import ( - InvalidSignature, - UnsupportedAlgorithm, - _Reasons, -) -from cryptography.hazmat.primitives import constant_time, hashes - -if typing.TYPE_CHECKING: - from cryptography.hazmat.backends.openssl.backend import Backend - - -class _HMACContext(hashes.HashContext): - def __init__( - self, - backend: Backend, - key: bytes, - algorithm: hashes.HashAlgorithm, - ctx=None, - ): - self._algorithm = algorithm - self._backend = backend - - if ctx is None: - ctx = self._backend._lib.HMAC_CTX_new() - self._backend.openssl_assert(ctx != self._backend._ffi.NULL) - ctx = self._backend._ffi.gc(ctx, self._backend._lib.HMAC_CTX_free) - evp_md = self._backend._evp_md_from_algorithm(algorithm) - if evp_md == self._backend._ffi.NULL: - raise UnsupportedAlgorithm( - "{} is not a supported hash on this backend".format( - algorithm.name - ), - _Reasons.UNSUPPORTED_HASH, - ) - key_ptr = self._backend._ffi.from_buffer(key) - res = self._backend._lib.HMAC_Init_ex( - ctx, key_ptr, len(key), evp_md, self._backend._ffi.NULL - ) - self._backend.openssl_assert(res != 0) - - self._ctx = ctx - self._key = key - - @property - def algorithm(self) -> hashes.HashAlgorithm: - return self._algorithm - - def copy(self) -> _HMACContext: - copied_ctx = self._backend._lib.HMAC_CTX_new() - self._backend.openssl_assert(copied_ctx != self._backend._ffi.NULL) - copied_ctx = self._backend._ffi.gc( - copied_ctx, self._backend._lib.HMAC_CTX_free - ) - res = self._backend._lib.HMAC_CTX_copy(copied_ctx, self._ctx) - self._backend.openssl_assert(res != 0) - return _HMACContext( - self._backend, self._key, self.algorithm, ctx=copied_ctx - ) - - def update(self, data: bytes) -> None: - data_ptr = self._backend._ffi.from_buffer(data) - res = self._backend._lib.HMAC_Update(self._ctx, data_ptr, len(data)) - self._backend.openssl_assert(res != 0) - - def finalize(self) -> bytes: - buf = self._backend._ffi.new( - "unsigned char[]", self._backend._lib.EVP_MAX_MD_SIZE - ) - outlen = self._backend._ffi.new("unsigned int *") - res = self._backend._lib.HMAC_Final(self._ctx, buf, outlen) - self._backend.openssl_assert(res != 0) - self._backend.openssl_assert(outlen[0] == self.algorithm.digest_size) - return self._backend._ffi.buffer(buf)[: outlen[0]] - - def verify(self, signature: bytes) -> None: - digest = self.finalize() - if not constant_time.bytes_eq(digest, signature): - raise InvalidSignature("Signature did not match digest.") diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi index 07fa9d7b9320..3e8d894cdb51 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -8,6 +8,7 @@ from cryptography.hazmat.bindings._rust.openssl import ( ed448, ed25519, hashes, + hmac, x448, x25519, ) @@ -16,6 +17,7 @@ __all__ = [ "openssl_version", "raise_openssl_error", "hashes", + "hmac", "ed448", "ed25519", "x448", diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi new file mode 100644 index 000000000000..e38d9b54d01b --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi @@ -0,0 +1,21 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives import hashes + +class HMAC(hashes.HashContext): + def __init__( + self, + key: bytes, + algorithm: hashes.HashAlgorithm, + backend: typing.Any = None, + ) -> None: ... + @property + def algorithm(self) -> hashes.HashAlgorithm: ... + def update(self, data: bytes) -> None: ... + def finalize(self) -> bytes: ... + def verify(self, signature: bytes) -> None: ... + def copy(self) -> HMAC: ... diff --git a/src/cryptography/hazmat/primitives/hmac.py b/src/cryptography/hazmat/primitives/hmac.py index 6627f57499ec..a9442d59ab47 100644 --- a/src/cryptography/hazmat/primitives/hmac.py +++ b/src/cryptography/hazmat/primitives/hmac.py @@ -4,68 +4,10 @@ from __future__ import annotations -import typing - -from cryptography import utils -from cryptography.exceptions import AlreadyFinalized -from cryptography.hazmat.backends.openssl.hmac import _HMACContext +from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives import hashes +__all__ = ["HMAC"] -class HMAC(hashes.HashContext): - _ctx: typing.Optional[_HMACContext] - - def __init__( - self, - key: bytes, - algorithm: hashes.HashAlgorithm, - backend: typing.Any = None, - ctx=None, - ): - if not isinstance(algorithm, hashes.HashAlgorithm): - raise TypeError("Expected instance of hashes.HashAlgorithm.") - self._algorithm = algorithm - - self._key = key - if ctx is None: - from cryptography.hazmat.backends.openssl.backend import ( - backend as ossl, - ) - - self._ctx = ossl.create_hmac_ctx(key, self.algorithm) - else: - self._ctx = ctx - - @property - def algorithm(self) -> hashes.HashAlgorithm: - return self._algorithm - - def update(self, data: bytes) -> None: - if self._ctx is None: - raise AlreadyFinalized("Context was already finalized.") - utils._check_byteslike("data", data) - self._ctx.update(data) - - def copy(self) -> HMAC: - if self._ctx is None: - raise AlreadyFinalized("Context was already finalized.") - return HMAC( - self._key, - self.algorithm, - ctx=self._ctx.copy(), - ) - - def finalize(self) -> bytes: - if self._ctx is None: - raise AlreadyFinalized("Context was already finalized.") - digest = self._ctx.finalize() - self._ctx = None - return digest - - def verify(self, signature: bytes) -> None: - utils._check_bytes("signature", signature) - if self._ctx is None: - raise AlreadyFinalized("Context was already finalized.") - - ctx, self._ctx = self._ctx, None - ctx.verify(signature) +HMAC = rust_openssl.hmac.HMAC +hashes.HashContext.register(HMAC) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 7fdd8b92be21..c7bc163a11a6 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -64,12 +64,23 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cryptography-openssl" +version = "0.1.0" +dependencies = [ + "foreign-types", + "foreign-types-shared", + "openssl", + "openssl-sys", +] + [[package]] name = "cryptography-rust" version = "0.1.0" dependencies = [ "asn1", "cc", + "cryptography-openssl", "cryptography-x509", "foreign-types-shared", "once_cell", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 588d742bdeb7..e97f800b7108 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -12,6 +12,7 @@ once_cell = "1" pyo3 = { version = "0.18" } asn1 = { version = "0.14.0", default-features = false } cryptography-x509 = { path = "cryptography-x509" } +cryptography-openssl = { path = "cryptography-openssl" } pem = "1.1" ouroboros = "0.15" openssl = "0.10.51" @@ -34,4 +35,4 @@ lto = "thin" overflow-checks = true [workspace] -members = ["cryptography-x509"] +members = ["cryptography-openssl", "cryptography-x509"] diff --git a/src/rust/cryptography-openssl/Cargo.toml b/src/rust/cryptography-openssl/Cargo.toml new file mode 100644 index 000000000000..31927129e234 --- /dev/null +++ b/src/rust/cryptography-openssl/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "cryptography-openssl" +version = "0.1.0" +authors = ["The cryptography developers "] +edition = "2021" +publish = false +# This specifies the MSRV +rust-version = "1.56.0" + +[dependencies] +openssl = "0.10.51" +ffi = { package = "openssl-sys", version = "0.9.85" } +foreign-types = "0.3" +foreign-types-shared = "0.1" diff --git a/src/rust/cryptography-openssl/src/hmac.rs b/src/rust/cryptography-openssl/src/hmac.rs new file mode 100644 index 000000000000..b30de478688d --- /dev/null +++ b/src/rust/cryptography-openssl/src/hmac.rs @@ -0,0 +1,93 @@ +// 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::{cvt, cvt_p, OpenSSLResult}; +use foreign_types_shared::{ForeignType, ForeignTypeRef}; +use std::ptr; + +foreign_types::foreign_type! { + type CType = ffi::HMAC_CTX; + fn drop = ffi::HMAC_CTX_free; + + pub struct Hmac; + pub struct HmacRef; +} + +unsafe impl Sync for Hmac {} +unsafe impl Send for Hmac {} + +impl Hmac { + pub fn new(key: &[u8], md: openssl::hash::MessageDigest) -> OpenSSLResult { + unsafe { + let h = Hmac::from_ptr(cvt_p(ffi::HMAC_CTX_new())?); + cvt(ffi::HMAC_Init_ex( + h.as_ptr(), + key.as_ptr().cast(), + key.len() + .try_into() + .expect("Key too long for OpenSSL's length type"), + md.as_ptr(), + ptr::null_mut(), + ))?; + Ok(h) + } + } +} + +impl HmacRef { + pub fn update(&mut self, data: &[u8]) -> OpenSSLResult<()> { + unsafe { + cvt(ffi::HMAC_Update(self.as_ptr(), data.as_ptr(), data.len()))?; + } + Ok(()) + } + + pub fn finish(&mut self) -> OpenSSLResult { + let mut buf = [0; ffi::EVP_MAX_MD_SIZE as usize]; + let mut len = ffi::EVP_MAX_MD_SIZE as std::os::raw::c_uint; + unsafe { + cvt(ffi::HMAC_Final(self.as_ptr(), buf.as_mut_ptr(), &mut len))?; + } + Ok(DigestBytes { + buf, + len: len.try_into().unwrap(), + }) + } + + pub fn copy(&self) -> OpenSSLResult { + unsafe { + let h = Hmac::from_ptr(cvt_p(ffi::HMAC_CTX_new())?); + cvt(ffi::HMAC_CTX_copy(h.as_ptr(), self.as_ptr()))?; + Ok(h) + } + } +} + +pub struct DigestBytes { + buf: [u8; ffi::EVP_MAX_MD_SIZE as usize], + len: usize, +} + +impl std::ops::Deref for DigestBytes { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + &self.buf[..self.len] + } +} + +#[cfg(test)] +mod tests { + use super::DigestBytes; + + #[test] + fn test_digest_bytes() { + let d = DigestBytes { + buf: [19; ffi::EVP_MAX_MD_SIZE as usize], + len: 12, + }; + assert_eq!(&*d, b"\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13"); + } +} diff --git a/src/rust/cryptography-openssl/src/lib.rs b/src/rust/cryptography-openssl/src/lib.rs new file mode 100644 index 000000000000..fcc2ff1a585b --- /dev/null +++ b/src/rust/cryptography-openssl/src/lib.rs @@ -0,0 +1,36 @@ +// This file is dual licensed under the terms of the Apache License, Version +// 2.0, and the BSD License. See the LICENSE file in the root of this repository +// for complete details. + +pub mod hmac; + +pub type OpenSSLResult = Result; + +#[inline] +fn cvt(r: std::os::raw::c_int) -> Result { + if r <= 0 { + Err(openssl::error::ErrorStack::get()) + } else { + Ok(r) + } +} + +#[inline] +fn cvt_p(r: *mut T) -> Result<*mut T, openssl::error::ErrorStack> { + if r.is_null() { + Err(openssl::error::ErrorStack::get()) + } else { + Ok(r) + } +} + +#[cfg(test)] +mod tests { + use std::ptr; + + #[test] + fn test_cvt() { + assert!(crate::cvt(-1).is_err()); + assert!(crate::cvt_p(ptr::null_mut::<()>()).is_err()); + } +} diff --git a/src/rust/src/backend/hashes.rs b/src/rust/src/backend/hashes.rs index 807890365265..14af3906aa8f 100644 --- a/src/rust/src/backend/hashes.rs +++ b/src/rust/src/backend/hashes.rs @@ -13,18 +13,24 @@ struct Hash { ctx: Option, } +pub(crate) fn already_finalized_error( + py: pyo3::Python<'_>, +) -> CryptographyResult { + Ok(CryptographyError::from(pyo3::PyErr::from_value( + py.import(pyo3::intern!(py, "cryptography.exceptions"))? + .call_method1( + pyo3::intern!(py, "AlreadyFinalized"), + ("Context was already finalized.",), + )?, + ))) +} + impl Hash { fn get_ctx(&self, py: pyo3::Python<'_>) -> CryptographyResult<&openssl::hash::Hasher> { if let Some(ctx) = self.ctx.as_ref() { return Ok(ctx); }; - Err(CryptographyError::from(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1( - pyo3::intern!(py, "AlreadyFinalized"), - ("Context was already finalized.",), - )?, - ))) + Err(already_finalized_error(py)?) } fn get_mut_ctx( @@ -34,13 +40,52 @@ impl Hash { if let Some(ctx) = self.ctx.as_mut() { return Ok(ctx); } - Err(CryptographyError::from(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1( - pyo3::intern!(py, "AlreadyFinalized"), - ("Context was already finalized.",), + Err(already_finalized_error(py)?) + } +} + +pub(crate) fn message_digest_from_algorithm( + py: pyo3::Python<'_>, + algorithm: &pyo3::PyAny, +) -> CryptographyResult { + let hash_algorithm_class = py + .import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))? + .getattr(pyo3::intern!(py, "HashAlgorithm"))?; + if !algorithm.is_instance(hash_algorithm_class)? { + return Err(CryptographyError::from( + pyo3::exceptions::PyTypeError::new_err("Expected instance of hashes.HashAlgorithm."), + )); + } + + let name = algorithm + .getattr(pyo3::intern!(py, "name"))? + .extract::<&str>()?; + let openssl_name = if name == "blake2b" || name == "blake2s" { + let digest_size = algorithm + .getattr(pyo3::intern!(py, "digest_size"))? + .extract::()?; + Cow::Owned(format!("{}{}", name, digest_size * 8)) + } else { + Cow::Borrowed(name) + }; + + match openssl::hash::MessageDigest::from_name(&openssl_name) { + Some(md) => Ok(md), + None => { + let exceptions_module = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; + let reason = exceptions_module + .getattr(pyo3::intern!(py, "_Reasons"))? + .getattr(pyo3::intern!(py, "UNSUPPORTED_HASH"))?; + Err(CryptographyError::from(pyo3::PyErr::from_value( + exceptions_module.call_method1( + pyo3::intern!(py, "UnsupportedAlgorithm"), + ( + format!("{} is not a supported hash on this backend", name), + reason, + ), )?, - ))) + ))) + } } } @@ -54,47 +99,8 @@ impl Hash { backend: Option<&pyo3::PyAny>, ) -> CryptographyResult { let _ = backend; - let hash_algorithm_class = py - .import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))? - .getattr(pyo3::intern!(py, "HashAlgorithm"))?; - if !algorithm.is_instance(hash_algorithm_class)? { - return Err(CryptographyError::from( - pyo3::exceptions::PyTypeError::new_err( - "Expected instance of hashes.HashAlgorithm.", - ), - )); - } - let name = algorithm - .getattr(pyo3::intern!(py, "name"))? - .extract::<&str>()?; - let openssl_name = if name == "blake2b" || name == "blake2s" { - let digest_size = algorithm - .getattr(pyo3::intern!(py, "digest_size"))? - .extract::()?; - Cow::Owned(format!("{}{}", name, digest_size * 8)) - } else { - Cow::Borrowed(name) - }; - - let md = match openssl::hash::MessageDigest::from_name(&openssl_name) { - Some(md) => md, - None => { - let exceptions_module = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; - let reason = exceptions_module - .getattr(pyo3::intern!(py, "_Reasons"))? - .getattr(pyo3::intern!(py, "UNSUPPORTED_HASH"))?; - return Err(CryptographyError::from(pyo3::PyErr::from_value( - exceptions_module.call_method1( - pyo3::intern!(py, "UnsupportedAlgorithm"), - ( - format!("{} is not a supported hash on this backend", name), - reason, - ), - )?, - ))); - } - }; + let md = message_digest_from_algorithm(py, algorithm)?; let ctx = openssl::hash::Hasher::new(md)?; Ok(Hash { diff --git a/src/rust/src/backend/hmac.rs b/src/rust/src/backend/hmac.rs new file mode 100644 index 000000000000..f483f48efd71 --- /dev/null +++ b/src/rust/src/backend/hmac.rs @@ -0,0 +1,104 @@ +// 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::backend::hashes::{already_finalized_error, message_digest_from_algorithm}; +use crate::buf::CffiBuf; +use crate::error::{CryptographyError, CryptographyResult}; + +#[pyo3::prelude::pyclass( + module = "cryptography.hazmat.bindings._rust.openssl.hmac", + name = "HMAC" +)] +struct Hmac { + #[pyo3(get)] + algorithm: pyo3::Py, + ctx: Option, +} + +impl Hmac { + fn get_ctx( + &self, + py: pyo3::Python<'_>, + ) -> CryptographyResult<&cryptography_openssl::hmac::Hmac> { + if let Some(ctx) = self.ctx.as_ref() { + return Ok(ctx); + }; + Err(already_finalized_error(py)?) + } + + fn get_mut_ctx( + &mut self, + py: pyo3::Python<'_>, + ) -> CryptographyResult<&mut cryptography_openssl::hmac::Hmac> { + if let Some(ctx) = self.ctx.as_mut() { + return Ok(ctx); + } + Err(already_finalized_error(py)?) + } +} + +#[pyo3::pymethods] +impl Hmac { + #[new] + #[pyo3(signature = (key, algorithm, backend=None))] + fn new( + py: pyo3::Python<'_>, + key: CffiBuf<'_>, + algorithm: &pyo3::PyAny, + backend: Option<&pyo3::PyAny>, + ) -> CryptographyResult { + let _ = backend; + + let md = message_digest_from_algorithm(py, algorithm)?; + let ctx = cryptography_openssl::hmac::Hmac::new(key.as_bytes(), md)?; + + Ok(Hmac { + ctx: Some(ctx), + algorithm: algorithm.into(), + }) + } + + fn update(&mut self, py: pyo3::Python<'_>, data: CffiBuf<'_>) -> CryptographyResult<()> { + self.get_mut_ctx(py)?.update(data.as_bytes())?; + Ok(()) + } + + fn finalize<'p>( + &mut self, + py: pyo3::Python<'p>, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let data = self.get_mut_ctx(py)?.finish()?; + self.ctx = None; + Ok(pyo3::types::PyBytes::new(py, &data)) + } + + fn verify(&mut self, py: pyo3::Python<'_>, signature: &[u8]) -> CryptographyResult<()> { + let actual = self.finalize(py)?.as_bytes(); + if actual.len() != signature.len() || !openssl::memcmp::eq(actual, signature) { + return Err(CryptographyError::from(pyo3::PyErr::from_value( + py.import(pyo3::intern!(py, "cryptography.exceptions"))? + .call_method1( + pyo3::intern!(py, "InvalidSignature"), + ("Signature did not match digest.",), + )?, + ))); + } + + Ok(()) + } + + fn copy(&self, py: pyo3::Python<'_>) -> CryptographyResult { + Ok(Hmac { + ctx: Some(self.get_ctx(py)?.copy()?), + algorithm: self.algorithm.clone_ref(py), + }) + } +} + +pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let m = pyo3::prelude::PyModule::new(py, "hmac")?; + m.add_class::()?; + + Ok(m) +} diff --git a/src/rust/src/backend/mod.rs b/src/rust/src/backend/mod.rs index c4095a03d5f9..b48f2089a991 100644 --- a/src/rust/src/backend/mod.rs +++ b/src/rust/src/backend/mod.rs @@ -7,6 +7,7 @@ pub(crate) mod ed25519; #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] pub(crate) mod ed448; pub(crate) mod hashes; +pub(crate) mod hmac; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] pub(crate) mod utils; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] @@ -26,6 +27,7 @@ pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult< module.add_submodule(x448::create_module(module.py())?)?; module.add_submodule(hashes::create_module(module.py())?)?; + module.add_submodule(hmac::create_module(module.py())?)?; Ok(()) } diff --git a/tests/hazmat/primitives/test_hmac.py b/tests/hazmat/primitives/test_hmac.py index 818ff2a7d829..78bb26254d9b 100644 --- a/tests/hazmat/primitives/test_hmac.py +++ b/tests/hazmat/primitives/test_hmac.py @@ -88,3 +88,8 @@ def test_buffer_protocol(self, backend): assert h.finalize() == binascii.unhexlify( b"a1bf7169c56a501c6585190ff4f07cad6e492a3ee187c0372614fb444b9fc3f0" ) + + def test_algorithm(self): + alg = hashes.SHA256() + h = hmac.HMAC(b"123456", alg) + assert h.algorithm is alg diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py index 637c1eaa67f2..056b31ee55c8 100644 --- a/tests/hazmat/primitives/utils.py +++ b/tests/hazmat/primitives/utils.py @@ -229,7 +229,6 @@ def base_hmac_test(backend, algorithm): h = hmac.HMAC(binascii.unhexlify(key), algorithm, backend=backend) h_copy = h.copy() assert h != h_copy - assert h._ctx != h_copy._ctx def generate_hmac_test(param_loader, path, file_names, algorithm): From 2ca57be0c4845d40992cbe7d13435df552e631f0 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 22 Apr 2023 13:32:59 -0600 Subject: [PATCH 156/316] Use pyo3's facilities for exceptions (#8785) --- src/cryptography/exceptions.py | 17 ++-------- .../hazmat/bindings/_rust/exceptions.pyi | 17 ++++++++++ src/rust/src/backend/hashes.rs | 22 ++++--------- src/rust/src/exceptions.rs | 33 +++++++++++++++++++ src/rust/src/lib.rs | 2 ++ src/rust/src/x509/certificate.rs | 18 ++++------ src/rust/src/x509/crl.rs | 14 +++----- src/rust/src/x509/csr.rs | 18 ++++------ src/rust/src/x509/ocsp_req.rs | 19 ++++------- src/rust/src/x509/ocsp_resp.rs | 26 ++++++--------- src/rust/src/x509/sign.rs | 23 ++++--------- tests/utils.py | 2 +- 12 files changed, 105 insertions(+), 106 deletions(-) create mode 100644 src/cryptography/hazmat/bindings/_rust/exceptions.pyi create mode 100644 src/rust/src/exceptions.rs diff --git a/src/cryptography/exceptions.py b/src/cryptography/exceptions.py index 59c7ebaff43c..47fdd18eeeb2 100644 --- a/src/cryptography/exceptions.py +++ b/src/cryptography/exceptions.py @@ -6,25 +6,12 @@ import typing -from cryptography import utils +from cryptography.hazmat.bindings._rust import exceptions as rust_exceptions if typing.TYPE_CHECKING: from cryptography.hazmat.bindings._rust import openssl as rust_openssl - -class _Reasons(utils.Enum): - BACKEND_MISSING_INTERFACE = 0 - UNSUPPORTED_HASH = 1 - UNSUPPORTED_CIPHER = 2 - UNSUPPORTED_PADDING = 3 - UNSUPPORTED_MGF = 4 - UNSUPPORTED_PUBLIC_KEY_ALGORITHM = 5 - UNSUPPORTED_ELLIPTIC_CURVE = 6 - UNSUPPORTED_SERIALIZATION = 7 - UNSUPPORTED_X509 = 8 - UNSUPPORTED_EXCHANGE_ALGORITHM = 9 - UNSUPPORTED_DIFFIE_HELLMAN = 10 - UNSUPPORTED_MAC = 11 +_Reasons = rust_exceptions._Reasons class UnsupportedAlgorithm(Exception): diff --git a/src/cryptography/hazmat/bindings/_rust/exceptions.pyi b/src/cryptography/hazmat/bindings/_rust/exceptions.pyi new file mode 100644 index 000000000000..09f46b1e817f --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/exceptions.pyi @@ -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. + +class _Reasons: + BACKEND_MISSING_INTERFACE: _Reasons + UNSUPPORTED_HASH: _Reasons + UNSUPPORTED_CIPHER: _Reasons + UNSUPPORTED_PADDING: _Reasons + UNSUPPORTED_MGF: _Reasons + UNSUPPORTED_PUBLIC_KEY_ALGORITHM: _Reasons + UNSUPPORTED_ELLIPTIC_CURVE: _Reasons + UNSUPPORTED_SERIALIZATION: _Reasons + UNSUPPORTED_X509: _Reasons + UNSUPPORTED_EXCHANGE_ALGORITHM: _Reasons + UNSUPPORTED_DIFFIE_HELLMAN: _Reasons + UNSUPPORTED_MAC: _Reasons diff --git a/src/rust/src/backend/hashes.rs b/src/rust/src/backend/hashes.rs index 14af3906aa8f..6543094ee24a 100644 --- a/src/rust/src/backend/hashes.rs +++ b/src/rust/src/backend/hashes.rs @@ -4,6 +4,7 @@ use crate::buf::CffiBuf; use crate::error::{CryptographyError, CryptographyResult}; +use crate::exceptions; use std::borrow::Cow; #[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.hashes")] @@ -71,21 +72,12 @@ pub(crate) fn message_digest_from_algorithm( match openssl::hash::MessageDigest::from_name(&openssl_name) { Some(md) => Ok(md), - None => { - let exceptions_module = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; - let reason = exceptions_module - .getattr(pyo3::intern!(py, "_Reasons"))? - .getattr(pyo3::intern!(py, "UNSUPPORTED_HASH"))?; - Err(CryptographyError::from(pyo3::PyErr::from_value( - exceptions_module.call_method1( - pyo3::intern!(py, "UnsupportedAlgorithm"), - ( - format!("{} is not a supported hash on this backend", name), - reason, - ), - )?, - ))) - } + None => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(( + format!("{} is not a supported hash on this backend", name), + exceptions::Reasons::UNSUPPORTED_HASH, + )), + )), } } diff --git a/src/rust/src/exceptions.rs b/src/rust/src/exceptions.rs new file mode 100644 index 000000000000..be59a6351bfa --- /dev/null +++ b/src/rust/src/exceptions.rs @@ -0,0 +1,33 @@ +// 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. + +#[pyo3::prelude::pyclass( + module = "cryptography.hazmat.bindings._rust.exceptions", + name = "_Reasons" +)] +#[allow(non_camel_case_types)] +pub(crate) enum Reasons { + BACKEND_MISSING_INTERFACE, + UNSUPPORTED_HASH, + UNSUPPORTED_CIPHER, + UNSUPPORTED_PADDING, + UNSUPPORTED_MGF, + UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + UNSUPPORTED_ELLIPTIC_CURVE, + UNSUPPORTED_SERIALIZATION, + UNSUPPORTED_X509, + UNSUPPORTED_EXCHANGE_ALGORITHM, + UNSUPPORTED_DIFFIE_HELLMAN, + UNSUPPORTED_MAC, +} + +pyo3::import_exception!(cryptography.exceptions, UnsupportedAlgorithm); + +pub(crate) fn create_submodule(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let submod = pyo3::prelude::PyModule::new(py, "exceptions")?; + + submod.add_class::()?; + + Ok(submod) +} diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 74989350bad7..f39762c88a09 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -13,6 +13,7 @@ mod asn1; mod backend; mod buf; mod error; +mod exceptions; pub(crate) mod oid; mod pkcs7; mod pool; @@ -156,6 +157,7 @@ fn _rust(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> m.add_submodule(asn1::create_submodule(py)?)?; m.add_submodule(pkcs7::create_submodule(py)?)?; + m.add_submodule(exceptions::create_submodule(py)?)?; let x509_mod = pyo3::prelude::PyModule::new(py, "x509")?; crate::x509::certificate::add_to_module(x509_mod)?; diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index a20e3fe5ff1a..889878972d1d 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -6,8 +6,8 @@ use crate::asn1::{ big_byte_slice_to_py_int, encode_der_data, oid_to_py_oid, py_uint_to_big_endian_bytes, }; use crate::error::{CryptographyError, CryptographyResult}; -use crate::x509; use crate::x509::{extensions, sct, sign}; +use crate::{exceptions, x509}; use cryptography_x509::common::Asn1ReadableOrWritable; use cryptography_x509::extensions::{ AuthorityKeyIdentifier, BasicConstraints, DisplayText, DistributionPoint, @@ -244,16 +244,12 @@ impl Certificate { let hash_alg = sig_oids_to_hash.get_item(self.signature_algorithm_oid(py)?); match hash_alg { Ok(data) => Ok(data), - Err(_) => Err(CryptographyError::from(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1( - "UnsupportedAlgorithm", - (format!( - "Signature algorithm OID: {} not recognized", - self.raw.borrow_value().signature_alg.oid - ),), - )?, - ))), + Err(_) => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + self.raw.borrow_value().signature_alg.oid + )), + )), } } diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index ea04bb984766..dcf09c731385 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -6,8 +6,8 @@ use crate::asn1::{ big_byte_slice_to_py_int, encode_der_data, oid_to_py_oid, py_uint_to_big_endian_bytes, }; use crate::error::{CryptographyError, CryptographyResult}; -use crate::x509; use crate::x509::{certificate, extensions, sign}; +use crate::{exceptions, x509}; use cryptography_x509::{common, crl, name, oid}; use pyo3::{IntoPy, ToPyObject}; use std::sync::Arc; @@ -201,19 +201,15 @@ impl CertificateRevocationList { ) -> pyo3::PyResult<&'p pyo3::PyAny> { let oid = self.signature_algorithm_oid(py)?; let oid_module = py.import(pyo3::intern!(py, "cryptography.hazmat._oid"))?; - let exceptions_module = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; match oid_module .getattr(pyo3::intern!(py, "_SIG_OIDS_TO_HASH"))? .get_item(oid) { Ok(v) => Ok(v), - Err(_) => Err(pyo3::PyErr::from_value(exceptions_module.call_method1( - "UnsupportedAlgorithm", - (format!( - "Signature algorithm OID:{} not recognized", - self.owned.borrow_value().signature_algorithm.oid - ),), - )?)), + Err(_) => Err(exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + self.owned.borrow_value().signature_algorithm.oid + ))), } } diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index 6de3667ae4fd..f376b9fed31a 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -4,8 +4,8 @@ use crate::asn1::{encode_der_data, oid_to_py_oid, py_oid_to_oid}; use crate::error::{CryptographyError, CryptographyResult}; -use crate::x509; use crate::x509::{certificate, sign}; +use crate::{exceptions, x509}; use asn1::SimpleAsn1Readable; use cryptography_x509::csr::{check_attribute_length, Attribute, CertificationRequestInfo, Csr}; use cryptography_x509::{common, oid}; @@ -102,16 +102,12 @@ impl CertificateSigningRequest { let hash_alg = sig_oids_to_hash.get_item(self.signature_algorithm_oid(py)?); match hash_alg { Ok(data) => Ok(data), - Err(_) => Err(CryptographyError::from(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1( - "UnsupportedAlgorithm", - (format!( - "Signature algorithm OID: {} not recognized", - self.raw.borrow_value().signature_alg.oid - ),), - )?, - ))), + Err(_) => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + self.raw.borrow_value().signature_alg.oid + )), + )), } } diff --git a/src/rust/src/x509/ocsp_req.rs b/src/rust/src/x509/ocsp_req.rs index 856c60c93d9a..701868e89395 100644 --- a/src/rust/src/x509/ocsp_req.rs +++ b/src/rust/src/x509/ocsp_req.rs @@ -4,8 +4,8 @@ use crate::asn1::{big_byte_slice_to_py_int, oid_to_py_oid, py_uint_to_big_endian_bytes}; use crate::error::{CryptographyError, CryptographyResult}; -use crate::x509; use crate::x509::{extensions, ocsp}; +use crate::{exceptions, x509}; use cryptography_x509::{common, ocsp_req, oid}; use pyo3::IntoPy; @@ -88,17 +88,12 @@ impl OCSPRequest { let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; match ocsp::OIDS_TO_HASH.get(&cert_id.hash_algorithm.oid) { Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), - None => { - let exceptions = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; - Err(CryptographyError::from(pyo3::PyErr::from_value( - exceptions - .getattr(pyo3::intern!(py, "UnsupportedAlgorithm"))? - .call1((format!( - "Signature algorithm OID: {} not recognized", - cert_id.hash_algorithm.oid - ),))?, - ))) - } + None => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + cert_id.hash_algorithm.oid + )), + )), } } diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index 717be9565b7a..103b610ec51f 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -4,8 +4,8 @@ use crate::asn1::{big_byte_slice_to_py_int, oid_to_py_oid}; use crate::error::{CryptographyError, CryptographyResult}; -use crate::x509; use crate::x509::{certificate, crl, extensions, ocsp, py_to_datetime, sct}; +use crate::{exceptions, x509}; use cryptography_x509::ocsp_resp::SingleResponse; use cryptography_x509::{common, ocsp_resp, oid}; use pyo3::IntoPy; @@ -187,10 +187,9 @@ impl OCSPResponse { "Signature algorithm OID: {} not recognized", self.requires_successful_response()?.signature_algorithm.oid ); - Err(CryptographyError::from(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1(pyo3::intern!(py, "UnsupportedAlgorithm"), (exc_messsage,))?, - ))) + Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(exc_messsage), + )) } } } @@ -480,17 +479,12 @@ fn singleresp_py_hash_algorithm<'p>( let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; match ocsp::OIDS_TO_HASH.get(&resp.cert_id.hash_algorithm.oid) { Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), - None => { - let exceptions = py.import(pyo3::intern!(py, "cryptography.exceptions"))?; - Err(CryptographyError::from(pyo3::PyErr::from_value( - exceptions - .getattr(pyo3::intern!(py, "UnsupportedAlgorithm"))? - .call1((format!( - "Signature algorithm OID: {} not recognized", - resp.cert_id.hash_algorithm.oid - ),))?, - ))) - } + None => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + resp.cert_id.hash_algorithm.oid + )), + )), } } diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index 12579b35e4c0..187dc54db986 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -3,6 +3,7 @@ // for complete details. use crate::error::{CryptographyError, CryptographyResult}; +use crate::exceptions; use cryptography_x509::{common, oid}; use once_cell::sync::Lazy; @@ -120,16 +121,10 @@ fn identify_hash_type( "sha3-256" => Ok(HashType::Sha3_256), "sha3-384" => Ok(HashType::Sha3_384), "sha3-512" => Ok(HashType::Sha3_512), - name => Err(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1( - "UnsupportedAlgorithm", - (format!( - "Hash algorithm {:?} not supported for signatures", - name - ),), - )?, - )), + name => Err(exceptions::UnsupportedAlgorithm::new_err(format!( + "Hash algorithm {:?} not supported for signatures", + name + ))), } } @@ -239,12 +234,8 @@ pub(crate) fn compute_signature_algorithm<'p>( ( KeyType::Dsa, HashType::Sha3_224 | HashType::Sha3_256 | HashType::Sha3_384 | HashType::Sha3_512, - ) => Err(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1( - "UnsupportedAlgorithm", - ("SHA3 hashes are not supported with DSA keys",), - )?, + ) => Err(exceptions::UnsupportedAlgorithm::new_err( + "SHA3 hashes are not supported with DSA keys", )), (_, HashType::None) => Err(pyo3::exceptions::PyTypeError::new_err( "Algorithm must be a registered hash algorithm, not None.", diff --git a/tests/utils.py b/tests/utils.py index c87df65c1507..bad0f87da164 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -33,7 +33,7 @@ def raises_unsupported_algorithm(reason): with pytest.raises(UnsupportedAlgorithm) as exc_info: yield exc_info - assert exc_info.value._reason is reason + assert exc_info.value._reason == reason T = typing.TypeVar("T") From 82ad1bd4eff6f62179afcd255d292bfae70a0e5e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 22 Apr 2023 13:59:13 -0600 Subject: [PATCH 157/316] Finish adopting pyo3's exceptio facilities (#8786) --- src/rust/src/backend/ed25519.rs | 15 +++++--------- src/rust/src/backend/ed448.rs | 15 +++++--------- src/rust/src/backend/hashes.rs | 35 ++++++++++++-------------------- src/rust/src/backend/hmac.rs | 33 +++++++++++------------------- src/rust/src/error.rs | 21 ++++++------------- src/rust/src/exceptions.rs | 7 +++++++ src/rust/src/x509/certificate.rs | 11 +++++----- src/rust/src/x509/common.rs | 26 ++++++++++-------------- src/rust/src/x509/crl.rs | 12 +++++------ src/rust/src/x509/csr.rs | 23 +++++++++------------ 10 files changed, 81 insertions(+), 117 deletions(-) diff --git a/src/rust/src/backend/ed25519.rs b/src/rust/src/backend/ed25519.rs index 09ed9ac10eff..003a5e913275 100644 --- a/src/rust/src/backend/ed25519.rs +++ b/src/rust/src/backend/ed25519.rs @@ -5,6 +5,7 @@ use crate::backend::utils; use crate::buf::CffiBuf; use crate::error::{CryptographyError, CryptographyResult}; +use crate::exceptions; use foreign_types_shared::ForeignTypeRef; #[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.ed25519")] @@ -117,20 +118,14 @@ impl Ed25519PrivateKey { #[pyo3::prelude::pymethods] impl Ed25519PublicKey { - fn verify( - &self, - py: pyo3::Python<'_>, - signature: &[u8], - data: &[u8], - ) -> CryptographyResult<()> { + fn verify(&self, signature: &[u8], data: &[u8]) -> CryptographyResult<()> { let valid = openssl::sign::Verifier::new_without_digest(&self.pkey)? .verify_oneshot(signature, data)?; if !valid { - return Err(CryptographyError::from(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1(pyo3::intern!(py, "InvalidSignature"), ())?, - ))); + return Err(CryptographyError::from( + exceptions::InvalidSignature::new_err(()), + )); } Ok(()) diff --git a/src/rust/src/backend/ed448.rs b/src/rust/src/backend/ed448.rs index db17a7062bfe..72fd6fd588a7 100644 --- a/src/rust/src/backend/ed448.rs +++ b/src/rust/src/backend/ed448.rs @@ -5,6 +5,7 @@ use crate::backend::utils; use crate::buf::CffiBuf; use crate::error::{CryptographyError, CryptographyResult}; +use crate::exceptions; use foreign_types_shared::ForeignTypeRef; #[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.ed448")] @@ -115,20 +116,14 @@ impl Ed448PrivateKey { #[pyo3::prelude::pymethods] impl Ed448PublicKey { - fn verify( - &self, - py: pyo3::Python<'_>, - signature: &[u8], - data: &[u8], - ) -> CryptographyResult<()> { + fn verify(&self, signature: &[u8], data: &[u8]) -> CryptographyResult<()> { let valid = openssl::sign::Verifier::new_without_digest(&self.pkey)? .verify_oneshot(signature, data)?; if !valid { - return Err(CryptographyError::from(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1(pyo3::intern!(py, "InvalidSignature"), ())?, - ))); + return Err(CryptographyError::from( + exceptions::InvalidSignature::new_err(()), + )); } Ok(()) diff --git a/src/rust/src/backend/hashes.rs b/src/rust/src/backend/hashes.rs index 6543094ee24a..d9157d6e8a18 100644 --- a/src/rust/src/backend/hashes.rs +++ b/src/rust/src/backend/hashes.rs @@ -14,34 +14,25 @@ struct Hash { ctx: Option, } -pub(crate) fn already_finalized_error( - py: pyo3::Python<'_>, -) -> CryptographyResult { - Ok(CryptographyError::from(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1( - pyo3::intern!(py, "AlreadyFinalized"), - ("Context was already finalized.",), - )?, - ))) +pub(crate) fn already_finalized_error() -> CryptographyError { + CryptographyError::from(exceptions::AlreadyFinalized::new_err( + "Context was already finalized.", + )) } impl Hash { - fn get_ctx(&self, py: pyo3::Python<'_>) -> CryptographyResult<&openssl::hash::Hasher> { + fn get_ctx(&self) -> CryptographyResult<&openssl::hash::Hasher> { if let Some(ctx) = self.ctx.as_ref() { return Ok(ctx); }; - Err(already_finalized_error(py)?) + Err(already_finalized_error()) } - fn get_mut_ctx( - &mut self, - py: pyo3::Python<'_>, - ) -> CryptographyResult<&mut openssl::hash::Hasher> { + fn get_mut_ctx(&mut self) -> CryptographyResult<&mut openssl::hash::Hasher> { if let Some(ctx) = self.ctx.as_mut() { return Ok(ctx); } - Err(already_finalized_error(py)?) + Err(already_finalized_error()) } } @@ -101,8 +92,8 @@ impl Hash { }) } - fn update(&mut self, py: pyo3::Python<'_>, data: CffiBuf<'_>) -> CryptographyResult<()> { - self.get_mut_ctx(py)?.update(data.as_bytes())?; + fn update(&mut self, data: CffiBuf<'_>) -> CryptographyResult<()> { + self.get_mut_ctx()?.update(data.as_bytes())?; Ok(()) } @@ -118,7 +109,7 @@ impl Hash { let algorithm = self.algorithm.clone_ref(py); let algorithm = algorithm.as_ref(py); if algorithm.is_instance(xof_class)? { - let ctx = self.get_mut_ctx(py)?; + let ctx = self.get_mut_ctx()?; let digest_size = algorithm .getattr(pyo3::intern!(py, "digest_size"))? .extract::()?; @@ -131,7 +122,7 @@ impl Hash { } } - let data = self.get_mut_ctx(py)?.finish()?; + let data = self.get_mut_ctx()?.finish()?; self.ctx = None; Ok(pyo3::types::PyBytes::new(py, &data)) } @@ -139,7 +130,7 @@ impl Hash { fn copy(&self, py: pyo3::Python<'_>) -> CryptographyResult { Ok(Hash { algorithm: self.algorithm.clone_ref(py), - ctx: Some(self.get_ctx(py)?.clone()), + ctx: Some(self.get_ctx()?.clone()), }) } } diff --git a/src/rust/src/backend/hmac.rs b/src/rust/src/backend/hmac.rs index f483f48efd71..d37b97277fdd 100644 --- a/src/rust/src/backend/hmac.rs +++ b/src/rust/src/backend/hmac.rs @@ -5,6 +5,7 @@ use crate::backend::hashes::{already_finalized_error, message_digest_from_algorithm}; use crate::buf::CffiBuf; use crate::error::{CryptographyError, CryptographyResult}; +use crate::exceptions; #[pyo3::prelude::pyclass( module = "cryptography.hazmat.bindings._rust.openssl.hmac", @@ -17,24 +18,18 @@ struct Hmac { } impl Hmac { - fn get_ctx( - &self, - py: pyo3::Python<'_>, - ) -> CryptographyResult<&cryptography_openssl::hmac::Hmac> { + fn get_ctx(&self) -> CryptographyResult<&cryptography_openssl::hmac::Hmac> { if let Some(ctx) = self.ctx.as_ref() { return Ok(ctx); }; - Err(already_finalized_error(py)?) + Err(already_finalized_error()) } - fn get_mut_ctx( - &mut self, - py: pyo3::Python<'_>, - ) -> CryptographyResult<&mut cryptography_openssl::hmac::Hmac> { + fn get_mut_ctx(&mut self) -> CryptographyResult<&mut cryptography_openssl::hmac::Hmac> { if let Some(ctx) = self.ctx.as_mut() { return Ok(ctx); } - Err(already_finalized_error(py)?) + Err(already_finalized_error()) } } @@ -59,8 +54,8 @@ impl Hmac { }) } - fn update(&mut self, py: pyo3::Python<'_>, data: CffiBuf<'_>) -> CryptographyResult<()> { - self.get_mut_ctx(py)?.update(data.as_bytes())?; + fn update(&mut self, data: CffiBuf<'_>) -> CryptographyResult<()> { + self.get_mut_ctx()?.update(data.as_bytes())?; Ok(()) } @@ -68,7 +63,7 @@ impl Hmac { &mut self, py: pyo3::Python<'p>, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - let data = self.get_mut_ctx(py)?.finish()?; + let data = self.get_mut_ctx()?.finish()?; self.ctx = None; Ok(pyo3::types::PyBytes::new(py, &data)) } @@ -76,13 +71,9 @@ impl Hmac { fn verify(&mut self, py: pyo3::Python<'_>, signature: &[u8]) -> CryptographyResult<()> { let actual = self.finalize(py)?.as_bytes(); if actual.len() != signature.len() || !openssl::memcmp::eq(actual, signature) { - return Err(CryptographyError::from(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.exceptions"))? - .call_method1( - pyo3::intern!(py, "InvalidSignature"), - ("Signature did not match digest.",), - )?, - ))); + return Err(CryptographyError::from( + exceptions::InvalidSignature::new_err(("Signature did not match digest.",)), + )); } Ok(()) @@ -90,7 +81,7 @@ impl Hmac { fn copy(&self, py: pyo3::Python<'_>) -> CryptographyResult { Ok(Hmac { - ctx: Some(self.get_ctx(py)?.copy()?), + ctx: Some(self.get_ctx()?.copy()?), algorithm: self.algorithm.clone_ref(py), }) } diff --git a/src/rust/src/error.rs b/src/rust/src/error.rs index e484993cced7..689ae613e8bb 100644 --- a/src/rust/src/error.rs +++ b/src/rust/src/error.rs @@ -2,7 +2,8 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::OpenSSLError; +use crate::{exceptions, OpenSSLError}; +use pyo3::ToPyObject; pub enum CryptographyError { Asn1Parse(asn1::ParseError), @@ -63,12 +64,6 @@ impl From for pyo3::PyErr { } CryptographyError::Py(py_error) => py_error, CryptographyError::OpenSSL(error_stack) => pyo3::Python::with_gil(|py| { - let internal_error = py - .import(pyo3::intern!(py, "cryptography.exceptions")) - .expect("Failed to import cryptography module") - .getattr(pyo3::intern!(py, "InternalError")) - .expect("Failed to get InternalError attribute"); - let errors = pyo3::types::PyList::empty(py); for e in error_stack.errors() { errors @@ -78,20 +73,16 @@ impl From for pyo3::PyErr { ) .expect("Failed to append to list"); } - pyo3::PyErr::from_value( - internal_error - .call1(( - "Unknown OpenSSL error. This error is commonly encountered + exceptions::InternalError::new_err(( + "Unknown OpenSSL error. This error is commonly encountered when another library is not cleaning up the OpenSSL error stack. If you are using cryptography with another library that uses OpenSSL try disabling it before reporting a bug. Otherwise please file an issue at https://github.com/pyca/cryptography/issues with information on how to reproduce this.", - errors, - )) - .expect("Failed to create InternalError"), - ) + errors.to_object(py), + )) }), } } diff --git a/src/rust/src/exceptions.rs b/src/rust/src/exceptions.rs index be59a6351bfa..ec1e18c7ff9c 100644 --- a/src/rust/src/exceptions.rs +++ b/src/rust/src/exceptions.rs @@ -22,7 +22,14 @@ pub(crate) enum Reasons { UNSUPPORTED_MAC, } +pyo3::import_exception!(cryptography.exceptions, AlreadyFinalized); +pyo3::import_exception!(cryptography.exceptions, InternalError); +pyo3::import_exception!(cryptography.exceptions, InvalidSignature); pyo3::import_exception!(cryptography.exceptions, UnsupportedAlgorithm); +pyo3::import_exception!(cryptography.x509, AttributeNotFound); +pyo3::import_exception!(cryptography.x509, DuplicateExtension); +pyo3::import_exception!(cryptography.x509, UnsupportedGeneralNameType); +pyo3::import_exception!(cryptography.x509, InvalidVersion); pub(crate) fn create_submodule(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let submod = pyo3::prelude::PyModule::new(py, "exceptions")?; diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 889878972d1d..b8d281014ff6 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -327,11 +327,12 @@ fn cert_version(py: pyo3::Python<'_>, version: u8) -> Result<&pyo3::PyAny, Crypt 2 => Ok(x509_module .getattr(pyo3::intern!(py, "Version"))? .get_item(pyo3::intern!(py, "v3"))?), - _ => Err(CryptographyError::from(pyo3::PyErr::from_value( - x509_module - .getattr(pyo3::intern!(py, "InvalidVersion"))? - .call1((format!("{} is not a valid X509 version", version), version))?, - ))), + _ => Err(CryptographyError::from( + exceptions::InvalidVersion::new_err(( + format!("{} is not a valid X509 version", version), + version, + )), + )), } } diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index 4d977a921172..e81d52a0020c 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -4,14 +4,14 @@ use crate::asn1::{oid_to_py_oid, py_oid_to_oid}; use crate::error::{CryptographyError, CryptographyResult}; -use crate::x509; +use crate::{exceptions, x509}; use cryptography_x509::common::{Asn1ReadableOrWritable, AttributeTypeValue, RawTlv}; use cryptography_x509::extensions::{ AccessDescription, Extension, Extensions, SequenceOfAccessDescriptions, }; use cryptography_x509::name::{GeneralName, Name, OtherName, UnvalidatedIA5String}; use pyo3::types::IntoPyDict; -use pyo3::ToPyObject; +use pyo3::{IntoPy, ToPyObject}; use std::collections::HashSet; /// Parse all sections in a PEM file and return the first matching section. @@ -308,12 +308,11 @@ pub(crate) fn parse_general_name( .to_object(py) } _ => { - return Err(CryptographyError::from(pyo3::PyErr::from_value( - x509_module.call_method1( - "UnsupportedGeneralNameType", - ("x400Address/EDIPartyName are not supported types",), - )?, - ))) + return Err(CryptographyError::from( + exceptions::UnsupportedGeneralNameType::new_err( + "x400Address/EDIPartyName are not supported types", + ), + )) } }; Ok(py_gn) @@ -411,13 +410,10 @@ pub(crate) fn parse_and_cache_extensions< let oid_obj = oid_to_py_oid(py, &raw_ext.extn_id)?; if seen_oids.contains(&raw_ext.extn_id) { - return Err(pyo3::PyErr::from_value(x509_module.call_method1( - "DuplicateExtension", - ( - format!("Duplicate {} extension found", raw_ext.extn_id), - oid_obj, - ), - )?)); + return Err(exceptions::DuplicateExtension::new_err(( + format!("Duplicate {} extension found", raw_ext.extn_id), + oid_obj.into_py(py), + ))); } let extn_value = match parse_ext(&raw_ext.extn_id, raw_ext.extn_value)? { diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index dcf09c731385..079122f2c392 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -25,12 +25,12 @@ fn load_der_x509_crl( let version = owned.borrow_value().tbs_cert_list.version.unwrap_or(1); if version != 1 { - let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; - return Err(CryptographyError::from(pyo3::PyErr::from_value( - x509_module - .getattr(pyo3::intern!(py, "InvalidVersion"))? - .call1((format!("{} is not a valid CRL version", version), version))?, - ))); + return Err(CryptographyError::from( + exceptions::InvalidVersion::new_err(( + format!("{} is not a valid CRL version", version), + version, + )), + )); } Ok(CertificateRevocationList { diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index f376b9fed31a..2d734681910a 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -170,13 +170,10 @@ impl CertificateSigningRequest { ))); } } - Err(pyo3::PyErr::from_value( - py.import(pyo3::intern!(py, "cryptography.x509"))? - .call_method1( - "AttributeNotFound", - (format!("No {} attribute was found", oid), oid), - )?, - )) + Err(exceptions::AttributeNotFound::new_err(( + format!("No {} attribute was found", oid), + oid.into_py(py), + ))) } #[getter] @@ -273,12 +270,12 @@ fn load_der_x509_csr( let version = raw.borrow_value().csr_info.version; if version != 0 { - let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; - return Err(CryptographyError::from(pyo3::PyErr::from_value( - x509_module - .getattr(pyo3::intern!(py, "InvalidVersion"))? - .call1((format!("{} is not a valid CSR version", version), version))?, - ))); + return Err(CryptographyError::from( + exceptions::InvalidVersion::new_err(( + format!("{} is not a valid CSR version", version), + version, + )), + )); } Ok(CertificateSigningRequest { From 2530fa1999468185a368f5a4ea3cf21b486b3518 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 23 Apr 2023 03:31:57 +0000 Subject: [PATCH 158/316] Bump nox from 2022.11.21 to 2023.4.22 (#8790) Bumps [nox](https://github.com/wntrblm/nox) from 2022.11.21 to 2023.4.22. - [Release notes](https://github.com/wntrblm/nox/releases) - [Changelog](https://github.com/wntrblm/nox/blob/main/CHANGELOG.md) - [Commits](https://github.com/wntrblm/nox/compare/2022.11.21...2023.04.22) --- updated-dependencies: - dependency-name: nox dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index e960c623765d..50b8353b2d59 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -71,7 +71,7 @@ mypy-extensions==1.0.0 # via # black # mypy -nox==2022.11.21 +nox==2023.4.22 # via cryptography (pyproject.toml) packaging==23.1 # via From e3ae04d9c580623307a6dcc906aed4d327c7bbdb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 23 Apr 2023 03:42:09 +0000 Subject: [PATCH 159/316] Bump argcomplete from 2.1.2 to 3.0.6 (#8784) Bumps [argcomplete](https://github.com/kislyuk/argcomplete) from 2.1.2 to 3.0.6. - [Release notes](https://github.com/kislyuk/argcomplete/releases) - [Changelog](https://github.com/kislyuk/argcomplete/blob/develop/Changes.rst) - [Commits](https://github.com/kislyuk/argcomplete/compare/v2.1.2...v3.0.6) --- updated-dependencies: - dependency-name: argcomplete dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 50b8353b2d59..8562db7ff388 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -7,7 +7,7 @@ alabaster==0.7.13 # via sphinx -argcomplete==2.1.2 +argcomplete==3.0.6 # via nox attrs==23.1.0 # via From 9e7aa16b656e5eb9955493b60106ebf8a86fc348 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 23 Apr 2023 03:52:50 +0000 Subject: [PATCH 160/316] Bump virtualenv from 20.21.1 to 20.22.0 (#8760) Bumps [virtualenv](https://github.com/pypa/virtualenv) from 20.21.1 to 20.22.0. - [Release notes](https://github.com/pypa/virtualenv/releases) - [Changelog](https://github.com/pypa/virtualenv/blob/main/docs/changelog.rst) - [Commits](https://github.com/pypa/virtualenv/compare/20.21.1...20.22.0) --- updated-dependencies: - dependency-name: virtualenv 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 8562db7ff388..e48ac8e5ce70 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -180,7 +180,7 @@ urllib3==1.26.15 # via # requests # twine -virtualenv==20.21.1 +virtualenv==20.22.0 # via nox webencodings==0.5.1 # via bleach From a7caf592648f0021f1c53a4a7858717364dca73d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 22 Apr 2023 22:13:58 -0600 Subject: [PATCH 161/316] Remove attrs from ci-constraints-requirements.txt (#8791) It's now unused in pytest: https://github.com/pytest-dev/pytest/commit/310b67b2271cb05f575054c1cdd2ece2412c89a2 --- ci-constraints-requirements.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index e48ac8e5ce70..2e53429ed18e 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -9,9 +9,6 @@ alabaster==0.7.13 # via sphinx argcomplete==3.0.6 # via nox -attrs==23.1.0 - # via - # pytest babel==2.12.1 # via sphinx black==23.3.0 From e9183cae405b5f2c99b8b715ed18bacb91fb273c Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 23 Apr 2023 09:36:10 -0600 Subject: [PATCH 162/316] Re-pin importlib-metadata (#8792) --- ci-constraints-requirements.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 2e53429ed18e..97e8c71d6025 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -46,6 +46,10 @@ idna==3.4 # via requests imagesize==1.4.1 # via sphinx +importlib-metadata==6.6.0 + # via + # keyring + # twine iniconfig==2.0.0 # via pytest jaraco-classes==3.2.3 From 3b4a5e27916371e1708f7baedb4e19cf9bb2cc8d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 23 Apr 2023 11:10:24 -0600 Subject: [PATCH 163/316] Bump syn (#8793) dependabot is not currently updating it because of: https://github.com/dependabot/dependabot-core/issues/2064 --- 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 c7bc163a11a6..79d5fd721e44 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -31,7 +31,7 @@ checksum = "ee4d9abdcc064cc9568bff2599089bb497a7de2c4b59608de35e3380b496617a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.15", ] [[package]] @@ -173,7 +173,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.15", ] [[package]] @@ -385,9 +385,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.12" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" dependencies = [ "proc-macro2", "quote", From ca7bcf492c5d1b792e0fffe4ef07a3f0154318b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 23 Apr 2023 19:17:32 +0000 Subject: [PATCH 164/316] Bump asn1 from 0.14.0 to 0.15.0 in /src/rust (#8796) Bumps [asn1](https://github.com/alex/rust-asn1) from 0.14.0 to 0.15.0. - [Release notes](https://github.com/alex/rust-asn1/releases) - [Commits](https://github.com/alex/rust-asn1/compare/0.14.0...0.15.0) --- updated-dependencies: - dependency-name: asn1 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 | 8 ++++---- src/rust/Cargo.toml | 2 +- src/rust/cryptography-x509/Cargo.toml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 79d5fd721e44..eb9290607fe9 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -16,18 +16,18 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" [[package]] name = "asn1" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48a34f02cde9e43d380b3c72f3deb14b9ef8bf262bd3c92426437b21e74a509a" +checksum = "fa66f5a3e8407b8d3dd8fefc2a62a1aba9539a1d8f856024643c2ae0a8e541ed" dependencies = [ "asn1_derive", ] [[package]] name = "asn1_derive" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4d9abdcc064cc9568bff2599089bb497a7de2c4b59608de35e3380b496617a" +checksum = "a6365c8b2b1a059ca234d1b69ba501cfa98f1cfd342b95c75611895f1cb0fb81" dependencies = [ "proc-macro2", "quote", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index e97f800b7108..b928e55d2221 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -10,7 +10,7 @@ rust-version = "1.56.0" [dependencies] once_cell = "1" pyo3 = { version = "0.18" } -asn1 = { version = "0.14.0", default-features = false } +asn1 = { version = "0.15.0", default-features = false } cryptography-x509 = { path = "cryptography-x509" } cryptography-openssl = { path = "cryptography-openssl" } pem = "1.1" diff --git a/src/rust/cryptography-x509/Cargo.toml b/src/rust/cryptography-x509/Cargo.toml index b062ddbbfb57..398473471733 100644 --- a/src/rust/cryptography-x509/Cargo.toml +++ b/src/rust/cryptography-x509/Cargo.toml @@ -8,4 +8,4 @@ publish = false rust-version = "1.56.0" [dependencies] -asn1 = { version = "0.14.0", default-features = false } +asn1 = { version = "0.15.0", default-features = false } From 5f3871e4dfb9bc8f4da9f2317d656538223ad400 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 23 Apr 2023 14:51:35 -0500 Subject: [PATCH 165/316] add two RSA PSS certificate vectors that have invalid encodings (#8797) * add two RSA PSS certificate vectors that have invalid encodings The signatures on these vectors are not valid. * spelling --- docs/development/test-vectors.rst | 5 +++++ docs/spelling_wordlist.txt | 1 + .../x509/custom/rsa_pss_cert_invalid_mgf.der | Bin 0 -> 891 bytes .../x509/custom/rsa_pss_cert_no_sig_params.der | Bin 0 -> 842 bytes 4 files changed, 6 insertions(+) create mode 100644 vectors/cryptography_vectors/x509/custom/rsa_pss_cert_invalid_mgf.der create mode 100644 vectors/cryptography_vectors/x509/custom/rsa_pss_cert_no_sig_params.der diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index c042eb9bf331..e86f27afde75 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -478,6 +478,11 @@ Custom X.509 Vectors are longer than 2 characters. * ``rsa_pss_cert.pem`` - A self-signed certificate with an RSA PSS signature with ``asymmetric/PKCS8/rsa_pss_2048.pem`` as its key. +* ``rsa_pss_cert_invalid_mgf.der`` - A self-signed certificate with an invalid + RSA PSS signature that has a non-MGF1 OID for its mask generation function in the + signature algorithm. +* ``rsa_pss_cert_no_sig_params.der`` - A self-signed certificate with an invalid + RSA PSS signature algorithm that is missing signature parameters for PSS. * ``long-form-name-attribute.pem`` - A certificate with ``subject`` and ``issuer`` names containing attributes whose value's tag is encoded in long-form. * ``mismatch_inner_outer_sig_algorithm.der`` - A leaf certificate derived from diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index d581d3d4c490..62a62fb96e34 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -77,6 +77,7 @@ Koblitz Lange logins metadata +MGF Monterey Mozilla multi diff --git a/vectors/cryptography_vectors/x509/custom/rsa_pss_cert_invalid_mgf.der b/vectors/cryptography_vectors/x509/custom/rsa_pss_cert_invalid_mgf.der new file mode 100644 index 0000000000000000000000000000000000000000..3141976caed07ba59251fe06bae85d819fd89fee GIT binary patch literal 891 zcmXqLVlFpmVlr63%*4pVBx2w2|Jioo@6~q`k{@nZ{;zfWnm;oPoY*+E+C196^D;7W z8JI5MH{fOCOlb39Ol4+aVq|4lC}SXnP{DyFyNHE}iQ%4sl%a%y7#nja3o{RYa#3YL zNq%}!VnIfwUS__5oH(zMk%5V^fsui+p`k^TIIpp>fr%kd49vx=w~0}~fE!^u7jqLM zKZ8LNBNtN>BO}B1h?jY-8fLQ`Ls!oERbY3<<7r?01KTaGTz}SAiq|CV)%>iRHZ9{+ z>=D)2gXcre2``$#8n@ungvRSf=6HwC+q7{XS3vrf`BG^u-WpFQPHA#Dq15=rgoRO)m_v2m(SJYJvnu6X-Tipx+^;Knyceqa3A&HpLle9Z{!!Pb$qRBV)_ZrWb zta}+fCWrp$Dn7DzcPc29Eqzenyvn-b(ofYBS5`_W6*svbcK%+YT3m0iXTm!Fo#K~# zPCtB?!Xa0~!qE4E>2RGfJNT literal 0 HcmV?d00001 diff --git a/vectors/cryptography_vectors/x509/custom/rsa_pss_cert_no_sig_params.der b/vectors/cryptography_vectors/x509/custom/rsa_pss_cert_no_sig_params.der new file mode 100644 index 0000000000000000000000000000000000000000..33df2ec52f188624d18bd4b77e9aeb6d81461454 GIT binary patch literal 842 zcmXqLVsfr%kd49vx=w~0}~fE!^u7jqLM zKZ8LNBNtN>BO}B1h?jY-8fLQ`Ls!oERbY3<<7r?01KTaGTz}SAiq|CV)%>iRHZ9{+ z>=D)2gXcre2``$#8n@ungvRSf=6HwC+q7{XS3vrf`BG^u-WpFQPHA#Dq15=rgoRO)m_v2m(SJYJvnu6X-Tipx+^;Knyceqa3Al|}tN6&?-Kn5Zw)8=P z^D66#OFvalTv;ihRNUl#*!g>nYH_{6o(b#xcZy%~IsNcm3Wr<`3q#)vrq}hhT2WcY z(@ME`)EIUoE1k2ED%MoC&ks)C`SQG#d@T#oX0t@Gv*+*gR;YSA@q}>Tg@s0sJH*a5 y)c!SJee0g&2bNVUwEy@$)4s_#i>t^?G-Rju&0o`-d?y6HvN@gCwp05aqcH$9U_z7t literal 0 HcmV?d00001 From 9425d2376b3601e625556d7d3f07e8ba1cd2800a Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 23 Apr 2023 15:22:50 -0500 Subject: [PATCH 166/316] add one more RSA PSS invalid test vector (#8798) --- docs/development/test-vectors.rst | 2 ++ .../custom/rsa_pss_cert_unsupported_mgf_hash.der | Bin 0 -> 891 bytes 2 files changed, 2 insertions(+) create mode 100644 vectors/cryptography_vectors/x509/custom/rsa_pss_cert_unsupported_mgf_hash.der diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index e86f27afde75..1916c57c4098 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -483,6 +483,8 @@ Custom X.509 Vectors signature algorithm. * ``rsa_pss_cert_no_sig_params.der`` - A self-signed certificate with an invalid RSA PSS signature algorithm that is missing signature parameters for PSS. +* ``rsa_pss_cert_unsupported_mgf_hash.der`` - A self-signed certificate with an + unsupported MGF1 hash algorithm in the signature algorithm. * ``long-form-name-attribute.pem`` - A certificate with ``subject`` and ``issuer`` names containing attributes whose value's tag is encoded in long-form. * ``mismatch_inner_outer_sig_algorithm.der`` - A leaf certificate derived from diff --git a/vectors/cryptography_vectors/x509/custom/rsa_pss_cert_unsupported_mgf_hash.der b/vectors/cryptography_vectors/x509/custom/rsa_pss_cert_unsupported_mgf_hash.der new file mode 100644 index 0000000000000000000000000000000000000000..d6276d09886695d703095a9102a18fe52db41bec GIT binary patch literal 891 zcmXqLVlFpmVlr63%*4pVBx2w2|Jioo@6~q`k{@nZ{;zfWnm;oPoY*+E+C196^D;7W z8JI5MH{fOCOlb39Ol4+aVq|4lC}SXnP{DyFyNHE}iQ%4sl%a%y7#nja3o{RYa#3YL zNq%}!VnIfwUS__5oH(zMk%5V^fsui+p`k^TIIpp>fr%kd49vx=w~0}~fE!^u7jqLM zKZ8LNBNtN>BO}B1h?jY-8fLQ`Ls!oERbY3<<7r?01KTaGTz}SAiq|CV)%>iRHZ9{+ z>=D)2gXcre2``$#8n@ungvRSf=6HwC+q7{XS3vrf`BG^u-WpFQPHA#Dq15=rgoRO)m_v2m(SJYJvnu6X-Tipx+^;Knyceqa3AoSz>zch>|D@3}u7PPEwiagy*P?GE1Xi@TR- z@=g7{#xo}CUPh0}p+CBckL=x@3JPUQ9~3yRvaY!FQ}x7^l@dzDP40)Czt^Z1*Bk7a zu+D#{_$8my58tJ5$knhg^u1tuU2m%um32I=l#54=VMnskIUA{BO=bK1;N)E{mON|$ zfo17WR3jd?{63j9;c#@soF{Kz9=oj3p_|K4cxHBov2kdV=;MV2#)S-$`5~7t&s)jY zvLJ0XOB6eM{yuMos<#tQ2nSwRX!N*4>}*5rU-Q+s?n!=NS+zp@kKZ%xn~bx#ip)eq Zc6#6ZHNDAqLf|W#(|K(>weK++0{~X}ONRge literal 0 HcmV?d00001 From a7abb5b2f684eb019e837bd8ec50a1adccfc841f Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 23 Apr 2023 15:41:31 -0600 Subject: [PATCH 167/316] Rewrite how we cached RevokedCertificates (#8799) This removes the use of non_covariant, which is a blocker for considering self_cell. --- src/rust/src/x509/crl.rs | 70 +++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index 079122f2c392..db4fd0394afd 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -17,11 +17,9 @@ fn load_der_x509_crl( py: pyo3::Python<'_>, data: pyo3::Py, ) -> Result { - let owned = OwnedCertificateRevocationList::try_new( - data, - |data| asn1::parse_single(data.as_bytes(py)), - |_| Ok(pyo3::once_cell::GILOnceCell::new()), - )?; + let owned = OwnedCertificateRevocationList::try_new(data, |data| { + asn1::parse_single(data.as_bytes(py)) + })?; let version = owned.borrow_value().tbs_cert_list.version.unwrap_or(1); if version != 1 { @@ -35,6 +33,7 @@ fn load_der_x509_crl( Ok(CertificateRevocationList { owned: Arc::new(owned), + revoked_certs: pyo3::once_cell::GILOnceCell::new(), cached_extensions: None, }) } @@ -61,15 +60,13 @@ struct OwnedCertificateRevocationList { #[borrows(data)] #[covariant] value: crl::CertificateRevocationList<'this>, - #[borrows(data)] - #[not_covariant] - revoked_certs: pyo3::once_cell::GILOnceCell>>, } #[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")] struct CertificateRevocationList { owned: Arc, + revoked_certs: pyo3::once_cell::GILOnceCell>, cached_extensions: Option, } @@ -78,15 +75,11 @@ impl CertificateRevocationList { Ok(asn1::write_single(self.owned.borrow_value())?) } - fn revoked_cert(&self, py: pyo3::Python<'_>, idx: usize) -> pyo3::PyResult { - let owned = try_map_arc_data_crl(&self.owned, |_crl, revoked_certs| { - let revoked_certs = revoked_certs.get(py).unwrap(); - Ok::<_, pyo3::PyErr>(revoked_certs[idx].clone()) - })?; - Ok(RevokedCertificate { - owned, + fn revoked_cert(&self, py: pyo3::Python<'_>, idx: usize) -> RevokedCertificate { + RevokedCertificate { + owned: self.revoked_certs.get(py).unwrap()[idx].clone(), cached_extensions: None, - }) + } } fn len(&self) -> usize { @@ -143,13 +136,13 @@ impl CertificateRevocationList { py: pyo3::Python<'_>, idx: &pyo3::PyAny, ) -> pyo3::PyResult { - self.owned.with(|val| { - val.revoked_certs.get_or_init(py, || { - match &val.value.tbs_cert_list.revoked_certificates { - Some(c) => c.unwrap_read().clone().collect(), - None => vec![], - } - }); + self.revoked_certs.get_or_init(py, || { + let mut revoked_certs = vec![]; + let mut it = self.__iter__(); + while let Some(c) = it.__next__() { + revoked_certs.push(c.owned); + } + revoked_certs }); if idx.is_instance_of::()? { @@ -158,7 +151,7 @@ impl CertificateRevocationList { .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::new(py, self.revoked_cert(py, i as usize)?)?; + let revoked_cert = pyo3::PyCell::new(py, self.revoked_cert(py, i as usize))?; result.append(revoked_cert)?; } Ok(result.to_object(py)) @@ -170,7 +163,7 @@ impl CertificateRevocationList { if idx >= (self.len() as isize) || idx < 0 { return Err(pyo3::exceptions::PyIndexError::new_err(())); } - Ok(pyo3::PyCell::new(py, self.revoked_cert(py, idx as usize)?)?.to_object(py)) + Ok(pyo3::PyCell::new(py, self.revoked_cert(py, idx as usize))?.to_object(py)) } } @@ -424,21 +417,6 @@ struct CRLIterator { // 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 OwnedCertificateRevocationList, - &pyo3::once_cell::GILOnceCell>>, - ) -> Result, E>, -) -> Result { - OwnedRevokedCertificate::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( @@ -485,6 +463,18 @@ struct OwnedRevokedCertificate { value: crl::RevokedCertificate<'this>, } +impl Clone for OwnedRevokedCertificate { + fn clone(&self) -> OwnedRevokedCertificate { + // This is safe because `Arc::clone` ensures the data is alive, but + // Rust doesn't understand the lifetime relationship it produces. + // Open-coded implementation of the API discussed in + // https://github.com/joshua-maros/ouroboros/issues/38 + OwnedRevokedCertificate::new(Arc::clone(self.borrow_data()), |_| unsafe { + std::mem::transmute(self.borrow_value().clone()) + }) + } +} + #[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.x509")] struct RevokedCertificate { owned: OwnedRevokedCertificate, From 085c373fb6e610f0939223c62f32f9eb643f7ab2 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 23 Apr 2023 16:27:01 -0600 Subject: [PATCH 168/316] Remove HMAC bindings (#8801) --- src/_cffi_src/build_openssl.py | 1 - src/_cffi_src/openssl/hmac.py | 26 -------------------------- 2 files changed, 27 deletions(-) delete mode 100644 src/_cffi_src/openssl/hmac.py diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py index 3ff1332e2772..e199329db606 100644 --- a/src/_cffi_src/build_openssl.py +++ b/src/_cffi_src/build_openssl.py @@ -36,7 +36,6 @@ "err", "evp", "fips", - "hmac", "nid", "objects", "opensslv", diff --git a/src/_cffi_src/openssl/hmac.py b/src/_cffi_src/openssl/hmac.py deleted file mode 100644 index 8fbc2b411608..000000000000 --- a/src/_cffi_src/openssl/hmac.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. - -from __future__ import annotations - -INCLUDES = """ -#include -""" - -TYPES = """ -typedef ... HMAC_CTX; -""" - -FUNCTIONS = """ -int HMAC_Init_ex(HMAC_CTX *, const void *, int, const EVP_MD *, ENGINE *); -int HMAC_Update(HMAC_CTX *, const unsigned char *, size_t); -int HMAC_Final(HMAC_CTX *, unsigned char *, unsigned int *); -int HMAC_CTX_copy(HMAC_CTX *, HMAC_CTX *); - -HMAC_CTX *HMAC_CTX_new(void); -void HMAC_CTX_free(HMAC_CTX *ctx); -""" - -CUSTOMIZATIONS = """ -""" From cad9499ea01cbbd7196569b660f147d52e2e6e87 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 24 Apr 2023 07:15:54 -0600 Subject: [PATCH 169/316] De-duplicate SPKI struct (#8803) --- src/rust/src/asn1.rs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index cad48a73f174..d412bb8b77f5 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -3,6 +3,7 @@ // for complete details. use crate::error::{CryptographyError, CryptographyResult}; +use cryptography_x509::common::SubjectPublicKeyInfo; use cryptography_x509::name::Name; use pyo3::basic::CompareOp; use pyo3::types::IntoPyDict; @@ -23,29 +24,17 @@ pub(crate) fn oid_to_py_oid<'p>( Ok(pyo3::Py::new(py, crate::oid::ObjectIdentifier { oid: oid.clone() })?.into_ref(py)) } -#[derive(asn1::Asn1Read)] -struct AlgorithmIdentifier<'a> { - _oid: asn1::ObjectIdentifier, - _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], ) -> Result { - let spki = asn1::parse_single::>(data)?; - if spki.data.padding_bits() != 0 { + let spki = asn1::parse_single::>(data)?; + if spki.subject_public_key.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)) + Ok(pyo3::types::PyBytes::new(py, spki.subject_public_key.as_bytes()).to_object(py)) } #[derive(asn1::Asn1Read, asn1::Asn1Write)] From 342fa03ffde73c967bf6af731f18a6de44e6c8c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 13:17:16 +0000 Subject: [PATCH 170/316] Bump argcomplete from 3.0.6 to 3.0.8 (#8805) Bumps [argcomplete](https://github.com/kislyuk/argcomplete) from 3.0.6 to 3.0.8. - [Release notes](https://github.com/kislyuk/argcomplete/releases) - [Changelog](https://github.com/kislyuk/argcomplete/blob/develop/Changes.rst) - [Commits](https://github.com/kislyuk/argcomplete/compare/v3.0.6...v3.0.8) --- updated-dependencies: - dependency-name: argcomplete 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 97e8c71d6025..3f7b5f352a24 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -7,7 +7,7 @@ alabaster==0.7.13 # via sphinx -argcomplete==3.0.6 +argcomplete==3.0.8 # via nox babel==2.12.1 # via sphinx From eb995fed64dd733db6340fd729de8b927452689a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 24 Apr 2023 07:23:15 -0600 Subject: [PATCH 171/316] modernize intersphinx_mapping configuration (#8806) --- docs/conf.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 0d8f866362a3..e67b03b6597e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -183,8 +183,7 @@ ), ] -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {"https://docs.python.org/3": None} +intersphinx_mapping = {"python": ("https://docs.python.org/3", None)} epub_theme = "epub" From 8edeed4392302cd5302465e8472786935842ae28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 13:36:57 +0000 Subject: [PATCH 172/316] Bump sphinx from 6.1.3 to 6.2.0 (#8804) Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 6.1.3 to 6.2.0. - [Release notes](https://github.com/sphinx-doc/sphinx/releases) - [Changelog](https://github.com/sphinx-doc/sphinx/blob/master/CHANGES) - [Commits](https://github.com/sphinx-doc/sphinx/compare/v6.1.3...v6.2.0) --- updated-dependencies: - dependency-name: sphinx 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 3f7b5f352a24..c57e536353f7 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -140,7 +140,7 @@ six==1.16.0 # via bleach snowballstemmer==2.2.0 # via sphinx -sphinx==6.1.3 +sphinx==6.2.0 # via # cryptography (pyproject.toml) # sphinx-rtd-theme From 963d6c456bfa7b0beeead2d3016fab77abf42c61 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 24 Apr 2023 08:30:29 -0600 Subject: [PATCH 173/316] Remove duplicative test certificate structure (#8807) --- src/rust/src/asn1.rs | 60 +++++++++++--------------------------------- 1 file changed, 15 insertions(+), 45 deletions(-) diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index d412bb8b77f5..01b4aff19015 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -3,7 +3,9 @@ // for complete details. use crate::error::{CryptographyError, CryptographyResult}; -use cryptography_x509::common::SubjectPublicKeyInfo; +use asn1::SimpleAsn1Readable; +use cryptography_x509::certificate::Certificate; +use cryptography_x509::common::{SubjectPublicKeyInfo, Time}; use cryptography_x509::name::Name; use pyo3::basic::CompareOp; use pyo3::types::IntoPyDict; @@ -152,39 +154,6 @@ struct TestCertificate { subject_value_tags: Vec, } -#[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>, -} - -#[derive(asn1::Asn1Read)] -struct Validity<'a> { - not_before: asn1::Tlv<'a>, - not_after: asn1::Tlv<'a>, -} - fn parse_name_value_tags(rdns: &mut Name<'_>) -> Vec { let mut tags = vec![]; for rdn in rdns.unwrap_read().clone() { @@ -196,21 +165,22 @@ fn parse_name_value_tags(rdns: &mut Name<'_>) -> Vec { tags } +fn time_tag(t: &Time) -> u8 { + match t { + Time::UtcTime(_) => asn1::UtcTime::TAG.as_u8().unwrap(), + Time::GeneralizedTime(_) => asn1::GeneralizedTime::TAG.as_u8().unwrap(), + } +} + #[pyo3::prelude::pyfunction] fn test_parse_certificate(data: &[u8]) -> Result { - let mut asn1_cert = asn1::parse_single::>(data)?; + let mut cert = asn1::parse_single::>(data)?; Ok(TestCertificate { - not_before_tag: asn1_cert - .tbs_cert - .validity - .not_before - .tag() - .as_u8() - .unwrap(), - not_after_tag: asn1_cert.tbs_cert.validity.not_after.tag().as_u8().unwrap(), - 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), + not_before_tag: time_tag(&cert.tbs_cert.validity.not_before), + not_after_tag: time_tag(&cert.tbs_cert.validity.not_after), + issuer_value_tags: parse_name_value_tags(&mut cert.tbs_cert.issuer), + subject_value_tags: parse_name_value_tags(&mut cert.tbs_cert.subject), }) } From 33fb461ad9275edd5c5a028b18acaf14a93e6102 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 24 Apr 2023 09:14:43 -0600 Subject: [PATCH 174/316] Refactor build so cffi compilation is in its own crate (#8809) --- src/rust/Cargo.lock | 10 ++ src/rust/Cargo.toml | 3 +- src/rust/build.rs | 123 +------------------------ src/rust/cryptography-cffi/Cargo.toml | 15 +++ src/rust/cryptography-cffi/build.rs | 126 ++++++++++++++++++++++++++ src/rust/cryptography-cffi/src/lib.rs | 31 +++++++ src/rust/src/lib.rs | 25 +---- 7 files changed, 189 insertions(+), 144 deletions(-) create mode 100644 src/rust/cryptography-cffi/Cargo.toml create mode 100644 src/rust/cryptography-cffi/build.rs create mode 100644 src/rust/cryptography-cffi/src/lib.rs diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index eb9290607fe9..e00d244cd4bb 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -64,6 +64,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cryptography-cffi" +version = "0.1.0" +dependencies = [ + "cc", + "openssl-sys", + "pyo3", +] + [[package]] name = "cryptography-openssl" version = "0.1.0" @@ -80,6 +89,7 @@ version = "0.1.0" dependencies = [ "asn1", "cc", + "cryptography-cffi", "cryptography-openssl", "cryptography-x509", "foreign-types-shared", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index b928e55d2221..dae85cef1d25 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -11,6 +11,7 @@ rust-version = "1.56.0" once_cell = "1" pyo3 = { version = "0.18" } asn1 = { version = "0.15.0", default-features = false } +cryptography-cffi = { path = "cryptography-cffi" } cryptography-x509 = { path = "cryptography-x509" } cryptography-openssl = { path = "cryptography-openssl" } pem = "1.1" @@ -35,4 +36,4 @@ lto = "thin" overflow-checks = true [workspace] -members = ["cryptography-openssl", "cryptography-x509"] +members = ["cryptography-cffi", "cryptography-openssl", "cryptography-x509"] diff --git a/src/rust/build.rs b/src/rust/build.rs index 7b63b95d5d24..574560394d88 100644 --- a/src/rust/build.rs +++ b/src/rust/build.rs @@ -1,77 +1,11 @@ +// 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 std::env; -use std::path::Path; -use std::process::Command; #[allow(clippy::unusual_byte_groupings)] fn main() { - let target = env::var("TARGET").unwrap(); - let openssl_static = env::var("OPENSSL_STATIC") - .map(|x| x == "1") - .unwrap_or(false); - if target.contains("apple") && openssl_static { - // On (older) OSX we need to link against the clang runtime, - // which is hidden in some non-default path. - // - // More details at https://github.com/alexcrichton/curl-rust/issues/279. - if let Some(path) = macos_link_search_path() { - println!("cargo:rustc-link-lib=clang_rt.osx"); - println!("cargo:rustc-link-search={}", path); - } - } - - let out_dir = env::var("OUT_DIR").unwrap(); - // FIXME: maybe pyo3-build-config should provide a way to do this? - let python = env::var("PYO3_PYTHON").unwrap_or_else(|_| "python3".to_string()); - println!("cargo:rerun-if-changed=../_cffi_src/"); - let output = Command::new(&python) - .env("OUT_DIR", &out_dir) - .arg("../_cffi_src/build_openssl.py") - .output() - .expect("failed to execute build_openssl.py"); - if !output.status.success() { - panic!( - "failed to run build_openssl.py, stdout: \n{}\nstderr: \n{}\n", - String::from_utf8(output.stdout).unwrap(), - String::from_utf8(output.stderr).unwrap() - ); - } - - let python_impl = run_python_script( - &python, - "import platform; print(platform.python_implementation(), end='')", - ) - .unwrap(); - println!("cargo:rustc-cfg=python_implementation=\"{}\"", python_impl); - let python_include = run_python_script( - &python, - "import sysconfig; print(sysconfig.get_path('include'), end='')", - ) - .unwrap(); - let openssl_include = - std::env::var_os("DEP_OPENSSL_INCLUDE").expect("unable to find openssl include path"); - let openssl_c = Path::new(&out_dir).join("_openssl.c"); - - let mut build = cc::Build::new(); - build - .file(openssl_c) - .include(python_include) - .include(openssl_include) - .flag_if_supported("-Wconversion") - .flag_if_supported("-Wno-error=sign-conversion") - .flag_if_supported("-Wno-unused-parameter"); - - // Enable abi3 mode if we're not using PyPy. - if python_impl != "PyPy" { - // cp37 (Python 3.7 to help our grep when we some day drop 3.7 support) - build.define("Py_LIMITED_API", "0x030700f0"); - } - - if cfg!(windows) { - build.define("WIN32_LEAN_AND_MEAN", None); - } - - build.compile("_openssl.a"); - if let Ok(version) = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") { let version = u64::from_str_radix(&version, 16).unwrap(); @@ -84,52 +18,3 @@ fn main() { println!("cargo:rustc-cfg=CRYPTOGRAPHY_IS_BORINGSSL"); } } - -/// Run a python script using the specified interpreter binary. -fn run_python_script(interpreter: impl AsRef, script: &str) -> Result { - let interpreter = interpreter.as_ref(); - let out = Command::new(interpreter) - .env("PYTHONIOENCODING", "utf-8") - .arg("-c") - .arg(script) - .output(); - - match out { - Err(err) => Err(format!( - "failed to run the Python interpreter at {}: {}", - interpreter.display(), - err - )), - Ok(ok) if !ok.status.success() => Err(format!( - "Python script failed: {}", - String::from_utf8(ok.stderr).expect("failed to parse Python script stderr as utf-8") - )), - Ok(ok) => Ok( - String::from_utf8(ok.stdout).expect("failed to parse Python script stdout as utf-8") - ), - } -} - -fn macos_link_search_path() -> Option { - let output = Command::new("clang") - .arg("--print-search-dirs") - .output() - .ok()?; - if !output.status.success() { - println!( - "failed to run 'clang --print-search-dirs', continuing without a link search path" - ); - return None; - } - - let stdout = String::from_utf8_lossy(&output.stdout); - for line in stdout.lines() { - if line.contains("libraries: =") { - let path = line.split('=').nth(1)?; - return Some(format!("{}/lib/darwin", path)); - } - } - - println!("failed to determine link search path, continuing without it"); - None -} diff --git a/src/rust/cryptography-cffi/Cargo.toml b/src/rust/cryptography-cffi/Cargo.toml new file mode 100644 index 000000000000..0c5655b170cc --- /dev/null +++ b/src/rust/cryptography-cffi/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "cryptography-cffi" +version = "0.1.0" +authors = ["The cryptography developers "] +edition = "2021" +publish = false +# This specifies the MSRV +rust-version = "1.56.0" + +[dependencies] +pyo3 = { version = "0.18" } +openssl-sys = "0.9.85" + +[build-dependencies] +cc = "1.0.72" diff --git a/src/rust/cryptography-cffi/build.rs b/src/rust/cryptography-cffi/build.rs new file mode 100644 index 000000000000..9a93b50bc438 --- /dev/null +++ b/src/rust/cryptography-cffi/build.rs @@ -0,0 +1,126 @@ +// 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 std::env; +use std::path::Path; +use std::process::Command; + +fn main() { + let target = env::var("TARGET").unwrap(); + let openssl_static = env::var("OPENSSL_STATIC") + .map(|x| x == "1") + .unwrap_or(false); + if target.contains("apple") && openssl_static { + // On (older) OSX we need to link against the clang runtime, + // which is hidden in some non-default path. + // + // More details at https://github.com/alexcrichton/curl-rust/issues/279. + if let Some(path) = macos_link_search_path() { + println!("cargo:rustc-link-lib=clang_rt.osx"); + println!("cargo:rustc-link-search={}", path); + } + } + + let out_dir = env::var("OUT_DIR").unwrap(); + // FIXME: maybe pyo3-build-config should provide a way to do this? + let python = env::var("PYO3_PYTHON").unwrap_or_else(|_| "python3".to_string()); + println!("cargo:rerun-if-changed=../../_cffi_src/"); + let output = Command::new(&python) + .env("OUT_DIR", &out_dir) + .arg("../../_cffi_src/build_openssl.py") + .output() + .expect("failed to execute build_openssl.py"); + if !output.status.success() { + panic!( + "failed to run build_openssl.py, stdout: \n{}\nstderr: \n{}\n", + String::from_utf8(output.stdout).unwrap(), + String::from_utf8(output.stderr).unwrap() + ); + } + + let python_impl = run_python_script( + &python, + "import platform; print(platform.python_implementation(), end='')", + ) + .unwrap(); + println!("cargo:rustc-cfg=python_implementation=\"{}\"", python_impl); + let python_include = run_python_script( + &python, + "import sysconfig; print(sysconfig.get_path('include'), end='')", + ) + .unwrap(); + let openssl_include = + std::env::var_os("DEP_OPENSSL_INCLUDE").expect("unable to find openssl include path"); + let openssl_c = Path::new(&out_dir).join("_openssl.c"); + + let mut build = cc::Build::new(); + build + .file(openssl_c) + .include(python_include) + .include(openssl_include) + .flag_if_supported("-Wconversion") + .flag_if_supported("-Wno-error=sign-conversion") + .flag_if_supported("-Wno-unused-parameter"); + + // Enable abi3 mode if we're not using PyPy. + if python_impl != "PyPy" { + // cp37 (Python 3.7 to help our grep when we some day drop 3.7 support) + build.define("Py_LIMITED_API", "0x030700f0"); + } + + if cfg!(windows) { + build.define("WIN32_LEAN_AND_MEAN", None); + } + + build.compile("_openssl.a"); +} + +/// Run a python script using the specified interpreter binary. +fn run_python_script(interpreter: impl AsRef, script: &str) -> Result { + let interpreter = interpreter.as_ref(); + let out = Command::new(interpreter) + .env("PYTHONIOENCODING", "utf-8") + .arg("-c") + .arg(script) + .output(); + + match out { + Err(err) => Err(format!( + "failed to run the Python interpreter at {}: {}", + interpreter.display(), + err + )), + Ok(ok) if !ok.status.success() => Err(format!( + "Python script failed: {}", + String::from_utf8(ok.stderr).expect("failed to parse Python script stderr as utf-8") + )), + Ok(ok) => Ok( + String::from_utf8(ok.stdout).expect("failed to parse Python script stdout as utf-8") + ), + } +} + +fn macos_link_search_path() -> Option { + let output = Command::new("clang") + .arg("--print-search-dirs") + .output() + .ok()?; + if !output.status.success() { + println!( + "failed to run 'clang --print-search-dirs', continuing without a link search path" + ); + return None; + } + + let stdout = String::from_utf8_lossy(&output.stdout); + for line in stdout.lines() { + if line.contains("libraries: =") { + let path = line.split('=').nth(1)?; + return Some(format!("{}/lib/darwin", path)); + } + } + + println!("failed to determine link search path, continuing without it"); + None +} diff --git a/src/rust/cryptography-cffi/src/lib.rs b/src/rust/cryptography-cffi/src/lib.rs new file mode 100644 index 000000000000..e263d53d8769 --- /dev/null +++ b/src/rust/cryptography-cffi/src/lib.rs @@ -0,0 +1,31 @@ +// 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. + +#[cfg(not(python_implementation = "PyPy"))] +use pyo3::FromPyPointer; + +#[cfg(python_implementation = "PyPy")] +extern "C" { + fn Cryptography_make_openssl_module() -> std::os::raw::c_int; +} +#[cfg(not(python_implementation = "PyPy"))] +extern "C" { + fn PyInit__openssl() -> *mut pyo3::ffi::PyObject; +} + +pub fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::types::PyModule> { + #[cfg(python_implementation = "PyPy")] + let openssl_mod = unsafe { + let res = Cryptography_make_openssl_module(); + assert_eq!(res, 0); + pyo3::types::PyModule::import(py, "_openssl")? + }; + #[cfg(not(python_implementation = "PyPy"))] + let openssl_mod = unsafe { + let ptr = PyInit__openssl(); + pyo3::types::PyModule::from_owned_ptr(py, ptr) + }; + + Ok(openssl_mod) +} diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index f39762c88a09..3d04f93c9b72 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -19,18 +19,6 @@ mod pkcs7; mod pool; mod x509; -#[cfg(not(python_implementation = "PyPy"))] -use pyo3::FromPyPointer; - -#[cfg(python_implementation = "PyPy")] -extern "C" { - fn Cryptography_make_openssl_module() -> std::os::raw::c_int; -} -#[cfg(not(python_implementation = "PyPy"))] -extern "C" { - fn PyInit__openssl() -> *mut pyo3::ffi::PyObject; -} - /// 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 { @@ -172,18 +160,7 @@ fn _rust(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> crate::x509::ocsp_resp::add_to_module(ocsp_mod)?; m.add_submodule(ocsp_mod)?; - #[cfg(python_implementation = "PyPy")] - let openssl_mod = unsafe { - let res = Cryptography_make_openssl_module(); - assert_eq!(res, 0); - pyo3::types::PyModule::import(py, "_openssl")? - }; - #[cfg(not(python_implementation = "PyPy"))] - let openssl_mod = unsafe { - let ptr = PyInit__openssl(); - pyo3::types::PyModule::from_owned_ptr(py, ptr) - }; - m.add_submodule(openssl_mod)?; + m.add_submodule(cryptography_cffi::create_module(py)?)?; let openssl_mod = pyo3::prelude::PyModule::new(py, "openssl")?; openssl_mod.add_function(pyo3::wrap_pyfunction!(openssl_version, m)?)?; From 9b0133c4dcb0282124745e211d497ed025a91045 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 24 Apr 2023 09:18:51 -0600 Subject: [PATCH 175/316] Remove clippy ignore that's no longer required (#8808) --- src/rust/src/backend/ed25519.rs | 4 ++-- src/rust/src/backend/ed448.rs | 4 ++-- src/rust/src/backend/x25519.rs | 4 ++-- src/rust/src/backend/x448.rs | 4 ++-- src/rust/src/lib.rs | 5 ----- 5 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/rust/src/backend/ed25519.rs b/src/rust/src/backend/ed25519.rs index 003a5e913275..f10d12db23f9 100644 --- a/src/rust/src/backend/ed25519.rs +++ b/src/rust/src/backend/ed25519.rs @@ -106,7 +106,7 @@ impl Ed25519PrivateKey { ) -> CryptographyResult<&'p pyo3::types::PyBytes> { utils::pkey_private_bytes( py, - &*slf, + slf, &slf.borrow().pkey, encoding, format, @@ -145,7 +145,7 @@ impl Ed25519PublicKey { encoding: &pyo3::PyAny, format: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - utils::pkey_public_bytes(py, &*slf, &slf.borrow().pkey, encoding, format, true) + utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, true) } fn __richcmp__( diff --git a/src/rust/src/backend/ed448.rs b/src/rust/src/backend/ed448.rs index 72fd6fd588a7..44e0240a1fa5 100644 --- a/src/rust/src/backend/ed448.rs +++ b/src/rust/src/backend/ed448.rs @@ -104,7 +104,7 @@ impl Ed448PrivateKey { ) -> CryptographyResult<&'p pyo3::types::PyBytes> { utils::pkey_private_bytes( py, - &*slf, + slf, &slf.borrow().pkey, encoding, format, @@ -143,7 +143,7 @@ impl Ed448PublicKey { encoding: &pyo3::PyAny, format: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - utils::pkey_public_bytes(py, &*slf, &slf.borrow().pkey, encoding, format, true) + utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, true) } fn __richcmp__( diff --git a/src/rust/src/backend/x25519.rs b/src/rust/src/backend/x25519.rs index 409f28c87a18..0a62182b1be8 100644 --- a/src/rust/src/backend/x25519.rs +++ b/src/rust/src/backend/x25519.rs @@ -108,7 +108,7 @@ impl X25519PrivateKey { ) -> CryptographyResult<&'p pyo3::types::PyBytes> { utils::pkey_private_bytes( py, - &*slf, + slf, &slf.borrow().pkey, encoding, format, @@ -134,7 +134,7 @@ impl X25519PublicKey { encoding: &pyo3::PyAny, format: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - utils::pkey_public_bytes(py, &*slf, &slf.borrow().pkey, encoding, format, false) + utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, false) } fn __richcmp__( diff --git a/src/rust/src/backend/x448.rs b/src/rust/src/backend/x448.rs index acfc9f2a0945..0eb44b8fe8fc 100644 --- a/src/rust/src/backend/x448.rs +++ b/src/rust/src/backend/x448.rs @@ -107,7 +107,7 @@ impl X448PrivateKey { ) -> CryptographyResult<&'p pyo3::types::PyBytes> { utils::pkey_private_bytes( py, - &*slf, + slf, &slf.borrow().pkey, encoding, format, @@ -133,7 +133,7 @@ impl X448PublicKey { encoding: &pyo3::PyAny, format: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - utils::pkey_public_bytes(py, &*slf, &slf.borrow().pkey, encoding, format, false) + utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, false) } fn __richcmp__( diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 3d04f93c9b72..95df2fa3c852 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -3,11 +3,6 @@ // for complete details. #![deny(rust_2018_idioms)] -// Temporarily allow `clippy::borrow_deref_ref` until we can upgrade to the -// latest pyo3: https://github.com/PyO3/pyo3/pull/2503 -// -// `unknown_lints` is required until GHA upgrades their rustc. -#![allow(unknown_lints, clippy::borrow_deref_ref)] mod asn1; mod backend; From a62a62ac76dde25c568542717ad92058f2ea145a Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 24 Apr 2023 09:32:30 -0600 Subject: [PATCH 176/316] move more structs into cryptography-x509 (#8810) --- src/rust/cryptography-x509/src/common.rs | 6 ++ src/rust/cryptography-x509/src/lib.rs | 1 + src/rust/cryptography-x509/src/pkcs7.rs | 60 +++++++++++++++++ src/rust/src/asn1.rs | 8 +-- src/rust/src/pkcs7.rs | 86 +++++------------------- 5 files changed, 83 insertions(+), 78 deletions(-) create mode 100644 src/rust/cryptography-x509/src/pkcs7.rs diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs index 13fcb3368243..edae5d4a40bd 100644 --- a/src/rust/cryptography-x509/src/common.rs +++ b/src/rust/cryptography-x509/src/common.rs @@ -117,6 +117,12 @@ impl<'a, T: asn1::SimpleAsn1Writable, U: asn1::SimpleAsn1Writable> asn1::SimpleA } } +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct DssSignature<'a> { + pub r: asn1::BigUint<'a>, + pub s: asn1::BigUint<'a>, +} + #[cfg(test)] mod tests { use super::{Asn1ReadableOrWritable, RawTlv}; diff --git a/src/rust/cryptography-x509/src/lib.rs b/src/rust/cryptography-x509/src/lib.rs index 897e0f6c0229..548e073b13e5 100644 --- a/src/rust/cryptography-x509/src/lib.rs +++ b/src/rust/cryptography-x509/src/lib.rs @@ -13,3 +13,4 @@ pub mod name; pub mod ocsp_req; pub mod ocsp_resp; pub mod oid; +pub mod pkcs7; diff --git a/src/rust/cryptography-x509/src/pkcs7.rs b/src/rust/cryptography-x509/src/pkcs7.rs new file mode 100644 index 000000000000..c5b7a9e3f650 --- /dev/null +++ b/src/rust/cryptography-x509/src/pkcs7.rs @@ -0,0 +1,60 @@ +// 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::{certificate, common, csr, name}; + +pub const PKCS7_DATA_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 7, 1); +pub const PKCS7_SIGNED_DATA_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 7, 2); + +#[derive(asn1::Asn1Write)] +pub struct ContentInfo<'a> { + pub _content_type: asn1::DefinedByMarker, + + #[defined_by(_content_type)] + pub content: Content<'a>, +} + +#[derive(asn1::Asn1DefinedByWrite)] +pub enum Content<'a> { + #[defined_by(PKCS7_SIGNED_DATA_OID)] + SignedData(asn1::Explicit<'a, Box>, 0>), + #[defined_by(PKCS7_DATA_OID)] + Data(Option>), +} + +#[derive(asn1::Asn1Write)] +pub struct SignedData<'a> { + pub version: u8, + pub digest_algorithms: asn1::SetOfWriter<'a, common::AlgorithmIdentifier<'a>>, + pub content_info: ContentInfo<'a>, + #[implicit(0)] + pub certificates: Option>>, + + // We don't ever supply any of these, so for now, don't fill out the fields. + #[implicit(1)] + pub crls: Option>>, + + pub signer_infos: asn1::SetOfWriter<'a, SignerInfo<'a>>, +} + +#[derive(asn1::Asn1Write)] +pub struct SignerInfo<'a> { + pub version: u8, + pub issuer_and_serial_number: IssuerAndSerialNumber<'a>, + pub digest_algorithm: common::AlgorithmIdentifier<'a>, + #[implicit(0)] + pub authenticated_attributes: Option>, + + pub digest_encryption_algorithm: common::AlgorithmIdentifier<'a>, + pub encrypted_digest: &'a [u8], + + #[implicit(1)] + pub unauthenticated_attributes: Option>, +} + +#[derive(asn1::Asn1Write)] +pub struct IssuerAndSerialNumber<'a> { + pub issuer: name::Name<'a>, + pub serial_number: asn1::BigInt<'a>, +} diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 01b4aff19015..96e44e93ae93 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -5,7 +5,7 @@ use crate::error::{CryptographyError, CryptographyResult}; use asn1::SimpleAsn1Readable; use cryptography_x509::certificate::Certificate; -use cryptography_x509::common::{SubjectPublicKeyInfo, Time}; +use cryptography_x509::common::{DssSignature, SubjectPublicKeyInfo, Time}; use cryptography_x509::name::Name; use pyo3::basic::CompareOp; use pyo3::types::IntoPyDict; @@ -39,12 +39,6 @@ fn parse_spki_for_data( Ok(pyo3::types::PyBytes::new(py, spki.subject_public_key.as_bytes()).to_object(py)) } -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -struct DssSignature<'a> { - r: asn1::BigUint<'a>, - s: asn1::BigUint<'a>, -} - pub(crate) fn big_byte_slice_to_py_int<'p>( py: pyo3::Python<'p>, v: &'_ [u8], diff --git a/src/rust/src/pkcs7.rs b/src/rust/src/pkcs7.rs index 2fdb610e3e82..236976bf4046 100644 --- a/src/rust/src/pkcs7.rs +++ b/src/rust/src/pkcs7.rs @@ -6,17 +6,14 @@ use crate::asn1::encode_der_data; use crate::buf::CffiBuf; use crate::error::CryptographyResult; use crate::x509; -use cryptography_x509::csr::{Attribute, Attributes}; -use cryptography_x509::{common, name, oid}; +use cryptography_x509::csr::Attribute; +use cryptography_x509::{common, oid, pkcs7}; use once_cell::sync::Lazy; use std::borrow::Cow; use std::collections::HashMap; use std::ops::Deref; -const PKCS7_DATA_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 7, 1); -const PKCS7_SIGNED_DATA_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 7, 2); - const PKCS7_CONTENT_TYPE_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 9, 3); const PKCS7_MESSAGE_DIGEST_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 9, 4); const PKCS7_SIGNING_TIME_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 9, 5); @@ -35,59 +32,6 @@ static OIDS_TO_MIC_NAME: Lazy> = Lazy::ne h }); -#[derive(asn1::Asn1Write)] -struct ContentInfo<'a> { - _content_type: asn1::DefinedByMarker, - - #[defined_by(_content_type)] - content: Content<'a>, -} - -#[derive(asn1::Asn1DefinedByWrite)] -enum Content<'a> { - #[defined_by(PKCS7_SIGNED_DATA_OID)] - SignedData(asn1::Explicit<'a, Box>, 0>), - #[defined_by(PKCS7_DATA_OID)] - Data(Option>), -} - -#[derive(asn1::Asn1Write)] -struct SignedData<'a> { - version: u8, - digest_algorithms: asn1::SetOfWriter<'a, common::AlgorithmIdentifier<'a>>, - content_info: ContentInfo<'a>, - #[implicit(0)] - certificates: - Option>>, - - // We don't ever supply any of these, so for now, don't fill out the fields. - #[implicit(1)] - crls: Option>>, - - signer_infos: asn1::SetOfWriter<'a, SignerInfo<'a>>, -} - -#[derive(asn1::Asn1Write)] -struct SignerInfo<'a> { - version: u8, - issuer_and_serial_number: IssuerAndSerialNumber<'a>, - digest_algorithm: common::AlgorithmIdentifier<'a>, - #[implicit(0)] - authenticated_attributes: Option>, - - digest_encryption_algorithm: common::AlgorithmIdentifier<'a>, - encrypted_digest: &'a [u8], - - #[implicit(1)] - unauthenticated_attributes: Option>, -} - -#[derive(asn1::Asn1Write)] -struct IssuerAndSerialNumber<'a> { - issuer: name::Name<'a>, - serial_number: asn1::BigInt<'a>, -} - #[pyo3::prelude::pyfunction] fn serialize_certificates<'p>( py: pyo3::Python<'p>, @@ -106,21 +50,21 @@ fn serialize_certificates<'p>( .map(|c| c.raw.borrow_value_public()) .collect::>(); - let signed_data = SignedData { + let signed_data = pkcs7::SignedData { version: 1, digest_algorithms: asn1::SetOfWriter::new(&[]), - content_info: ContentInfo { + content_info: pkcs7::ContentInfo { _content_type: asn1::DefinedByMarker::marker(), - content: Content::Data(Some(asn1::Explicit::new(b""))), + content: pkcs7::Content::Data(Some(asn1::Explicit::new(b""))), }, certificates: Some(asn1::SetOfWriter::new(&raw_certs)), crls: None, signer_infos: asn1::SetOfWriter::new(&[]), }; - let content_info = ContentInfo { + let content_info = pkcs7::ContentInfo { _content_type: asn1::DefinedByMarker::marker(), - content: Content::SignedData(asn1::Explicit::new(Box::new(signed_data))), + content: pkcs7::Content::SignedData(asn1::Explicit::new(Box::new(signed_data))), }; let content_info_bytes = asn1::write_single(&content_info)?; @@ -153,7 +97,7 @@ fn sign_and_serialize<'p>( smime_canonicalize(raw_data.as_bytes(), text_mode) }; - let content_type_bytes = asn1::write_single(&PKCS7_DATA_OID)?; + let content_type_bytes = asn1::write_single(&pkcs7::PKCS7_DATA_OID)?; let now = x509::common::datetime_now(py)?; let signing_time_bytes = asn1::write_single(&x509::certificate::time_from_datetime(now)?)?; let smime_cap_bytes = asn1::write_single(&asn1::SequenceOfWriter::new([ @@ -249,9 +193,9 @@ fn sign_and_serialize<'p>( } certs.push(cert.raw.borrow_value_public()); - signer_infos.push(SignerInfo { + signer_infos.push(pkcs7::SignerInfo { version: 1, - issuer_and_serial_number: IssuerAndSerialNumber { + issuer_and_serial_number: pkcs7::IssuerAndSerialNumber { issuer: cert.raw.borrow_value_public().tbs_cert.issuer.clone(), serial_number: cert.raw.borrow_value_public().tbs_cert.serial, }, @@ -276,12 +220,12 @@ fn sign_and_serialize<'p>( Some(asn1::parse_single(&data_tlv_bytes).unwrap()) }; - let signed_data = SignedData { + let signed_data = pkcs7::SignedData { version: 1, digest_algorithms: asn1::SetOfWriter::new(&digest_algs), - content_info: ContentInfo { + content_info: pkcs7::ContentInfo { _content_type: asn1::DefinedByMarker::marker(), - content: Content::Data(content.map(asn1::Explicit::new)), + content: pkcs7::Content::Data(content.map(asn1::Explicit::new)), }, certificates: if options.contains(pkcs7_options.getattr(pyo3::intern!(py, "NoCerts"))?)? { None @@ -292,9 +236,9 @@ fn sign_and_serialize<'p>( signer_infos: asn1::SetOfWriter::new(&signer_infos), }; - let content_info = ContentInfo { + let content_info = pkcs7::ContentInfo { _content_type: asn1::DefinedByMarker::marker(), - content: Content::SignedData(asn1::Explicit::new(Box::new(signed_data))), + content: pkcs7::Content::SignedData(asn1::Explicit::new(Box::new(signed_data))), }; let ci_bytes = asn1::write_single(&content_info)?; From 4ecb62c5006894fa2d925795916ceec810588248 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 24 Apr 2023 12:23:34 -0600 Subject: [PATCH 177/316] Refactor encode_extensions so that the largest extensions aren't inline (#8813) --- src/rust/src/x509/extensions.rs | 435 +++++++++++++++++--------------- 1 file changed, 228 insertions(+), 207 deletions(-) diff --git a/src/rust/src/x509/extensions.rs b/src/rust/src/x509/extensions.rs index 08e112cbbcf5..e12c320a0c47 100644 --- a/src/rust/src/x509/extensions.rs +++ b/src/rust/src/x509/extensions.rs @@ -118,6 +118,226 @@ pub(crate) fn encode_distribution_points<'p>( Ok(dps) } +fn encode_basic_constraints(ext: &pyo3::PyAny) -> CryptographyResult> { + #[derive(pyo3::prelude::FromPyObject)] + struct PyBasicConstraints { + ca: bool, + path_length: Option, + } + let pybc = ext.extract::()?; + let bc = extensions::BasicConstraints { + ca: pybc.ca, + path_length: pybc.path_length, + }; + Ok(asn1::write_single(&bc)?) +} + +fn encode_key_usage(py: pyo3::Python<'_>, ext: &pyo3::PyAny) -> CryptographyResult> { + let mut bs = [0, 0]; + certificate::set_bit( + &mut bs, + 0, + ext.getattr(pyo3::intern!(py, "digital_signature"))? + .is_true()?, + ); + certificate::set_bit( + &mut bs, + 1, + ext.getattr(pyo3::intern!(py, "content_commitment"))? + .is_true()?, + ); + certificate::set_bit( + &mut bs, + 2, + ext.getattr(pyo3::intern!(py, "key_encipherment"))? + .is_true()?, + ); + certificate::set_bit( + &mut bs, + 3, + ext.getattr(pyo3::intern!(py, "data_encipherment"))? + .is_true()?, + ); + certificate::set_bit( + &mut bs, + 4, + ext.getattr(pyo3::intern!(py, "key_agreement"))?.is_true()?, + ); + certificate::set_bit( + &mut bs, + 5, + ext.getattr(pyo3::intern!(py, "key_cert_sign"))?.is_true()?, + ); + certificate::set_bit( + &mut bs, + 6, + ext.getattr(pyo3::intern!(py, "crl_sign"))?.is_true()?, + ); + if ext.getattr(pyo3::intern!(py, "key_agreement"))?.is_true()? { + certificate::set_bit( + &mut bs, + 7, + ext.getattr(pyo3::intern!(py, "encipher_only"))?.is_true()?, + ); + certificate::set_bit( + &mut bs, + 8, + ext.getattr(pyo3::intern!(py, "decipher_only"))?.is_true()?, + ); + } + let (bits, unused_bits) = if bs[1] == 0 { + if bs[0] == 0 { + (&[][..], 0) + } else { + (&bs[..1], bs[0].trailing_zeros() as u8) + } + } else { + (&bs[..], bs[1].trailing_zeros() as u8) + }; + let v = asn1::BitString::new(bits, unused_bits).unwrap(); + Ok(asn1::write_single(&v)?) +} + +fn encode_certificate_policies( + py: pyo3::Python<'_>, + ext: &pyo3::PyAny, +) -> CryptographyResult> { + let mut policy_informations = vec![]; + for py_policy_info in ext.iter()? { + let py_policy_info = py_policy_info?; + let py_policy_qualifiers = + py_policy_info.getattr(pyo3::intern!(py, "policy_qualifiers"))?; + let qualifiers = if py_policy_qualifiers.is_true()? { + let mut qualifiers = vec![]; + for py_qualifier in py_policy_qualifiers.iter()? { + let py_qualifier = py_qualifier?; + let qualifier = if py_qualifier.is_instance_of::()? { + let cps_uri = match asn1::IA5String::new(py_qualifier.extract()?) { + Some(s) => s, + None => { + return Err(pyo3::exceptions::PyValueError::new_err( + "Qualifier must be an ASCII-string.", + ) + .into()) + } + }; + extensions::PolicyQualifierInfo { + policy_qualifier_id: (oid::CP_CPS_URI_OID).clone(), + qualifier: extensions::Qualifier::CpsUri(cps_uri), + } + } else { + let py_notice = py_qualifier.getattr(pyo3::intern!(py, "notice_reference"))?; + let notice_ref = if py_notice.is_true()? { + let mut notice_numbers = vec![]; + for py_num in py_notice + .getattr(pyo3::intern!(py, "notice_numbers"))? + .iter()? + { + let bytes = py_uint_to_big_endian_bytes(ext.py(), py_num?.downcast()?)?; + notice_numbers.push(asn1::BigUint::new(bytes).unwrap()); + } + + Some(extensions::NoticeReference { + organization: extensions::DisplayText::Utf8String( + asn1::Utf8String::new( + py_notice + .getattr(pyo3::intern!(py, "organization"))? + .extract()?, + ), + ), + notice_numbers: common::Asn1ReadableOrWritable::new_write( + asn1::SequenceOfWriter::new(notice_numbers), + ), + }) + } else { + None + }; + let py_explicit_text = + py_qualifier.getattr(pyo3::intern!(py, "explicit_text"))?; + let explicit_text = if py_explicit_text.is_true()? { + Some(extensions::DisplayText::Utf8String(asn1::Utf8String::new( + py_explicit_text.extract()?, + ))) + } else { + None + }; + + extensions::PolicyQualifierInfo { + policy_qualifier_id: (oid::CP_USER_NOTICE_OID).clone(), + qualifier: extensions::Qualifier::UserNotice(extensions::UserNotice { + notice_ref, + explicit_text, + }), + } + }; + qualifiers.push(qualifier); + } + Some(common::Asn1ReadableOrWritable::new_write( + asn1::SequenceOfWriter::new(qualifiers), + )) + } else { + None + }; + let py_policy_id = py_policy_info.getattr(pyo3::intern!(py, "policy_identifier"))?; + policy_informations.push(extensions::PolicyInformation { + policy_identifier: py_oid_to_oid(py_policy_id)?, + policy_qualifiers: qualifiers, + }); + } + Ok(asn1::write_single(&asn1::SequenceOfWriter::new( + policy_informations, + ))?) +} + +fn encode_issuing_distribution_point( + py: pyo3::Python<'_>, + ext: &pyo3::PyAny, +) -> CryptographyResult> { + let only_some_reasons = if ext + .getattr(pyo3::intern!(py, "only_some_reasons"))? + .is_true()? + { + let py_reasons = ext.getattr(pyo3::intern!(py, "only_some_reasons"))?; + let reasons = certificate::encode_distribution_point_reasons(ext.py(), py_reasons)?; + Some(common::Asn1ReadableOrWritable::new_write(reasons)) + } else { + None + }; + let distribution_point = if ext.getattr(pyo3::intern!(py, "full_name"))?.is_true()? { + let py_full_name = ext.getattr(pyo3::intern!(py, "full_name"))?; + let gns = x509::common::encode_general_names(ext.py(), py_full_name)?; + Some(extensions::DistributionPointName::FullName( + common::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new(gns)), + )) + } else if ext.getattr(pyo3::intern!(py, "relative_name"))?.is_true()? { + let mut name_entries = vec![]; + for py_name_entry in ext.getattr(pyo3::intern!(py, "relative_name"))?.iter()? { + name_entries.push(x509::common::encode_name_entry(ext.py(), py_name_entry?)?); + } + Some(extensions::DistributionPointName::NameRelativeToCRLIssuer( + common::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new(name_entries)), + )) + } else { + None + }; + + let idp = crl::IssuingDistributionPoint { + distribution_point, + indirect_crl: ext.getattr(pyo3::intern!(py, "indirect_crl"))?.extract()?, + only_contains_attribute_certs: ext + .getattr(pyo3::intern!(py, "only_contains_attribute_certs"))? + .extract()?, + only_contains_ca_certs: ext + .getattr(pyo3::intern!(py, "only_contains_ca_certs"))? + .extract()?, + only_contains_user_certs: ext + .getattr(pyo3::intern!(py, "only_contains_user_certs"))? + .extract()?, + only_some_reasons, + }; + Ok(asn1::write_single(&idp)?) +} + pub(crate) fn encode_extension( py: pyo3::Python<'_>, oid: &asn1::ObjectIdentifier, @@ -125,17 +345,8 @@ pub(crate) fn encode_extension( ) -> CryptographyResult>> { match oid { &oid::BASIC_CONSTRAINTS_OID => { - #[derive(pyo3::prelude::FromPyObject)] - struct PyBasicConstraints { - ca: bool, - path_length: Option, - } - let pybc = ext.extract::()?; - let bc = extensions::BasicConstraints { - ca: pybc.ca, - path_length: pybc.path_length, - }; - Ok(Some(asn1::write_single(&bc)?)) + let der = encode_basic_constraints(ext)?; + Ok(Some(der)) } &oid::SUBJECT_KEY_IDENTIFIER_OID => { let digest = ext @@ -144,69 +355,8 @@ pub(crate) fn encode_extension( Ok(Some(asn1::write_single(&digest)?)) } &oid::KEY_USAGE_OID => { - let mut bs = [0, 0]; - certificate::set_bit( - &mut bs, - 0, - ext.getattr(pyo3::intern!(py, "digital_signature"))? - .is_true()?, - ); - certificate::set_bit( - &mut bs, - 1, - ext.getattr(pyo3::intern!(py, "content_commitment"))? - .is_true()?, - ); - certificate::set_bit( - &mut bs, - 2, - ext.getattr(pyo3::intern!(py, "key_encipherment"))? - .is_true()?, - ); - certificate::set_bit( - &mut bs, - 3, - ext.getattr(pyo3::intern!(py, "data_encipherment"))? - .is_true()?, - ); - certificate::set_bit( - &mut bs, - 4, - ext.getattr(pyo3::intern!(py, "key_agreement"))?.is_true()?, - ); - certificate::set_bit( - &mut bs, - 5, - ext.getattr(pyo3::intern!(py, "key_cert_sign"))?.is_true()?, - ); - certificate::set_bit( - &mut bs, - 6, - ext.getattr(pyo3::intern!(py, "crl_sign"))?.is_true()?, - ); - if ext.getattr(pyo3::intern!(py, "key_agreement"))?.is_true()? { - certificate::set_bit( - &mut bs, - 7, - ext.getattr(pyo3::intern!(py, "encipher_only"))?.is_true()?, - ); - certificate::set_bit( - &mut bs, - 8, - ext.getattr(pyo3::intern!(py, "decipher_only"))?.is_true()?, - ); - } - let (bits, unused_bits) = if bs[1] == 0 { - if bs[0] == 0 { - (&[][..], 0) - } else { - (&bs[..1], bs[0].trailing_zeros() as u8) - } - } else { - (&bs[..], bs[1].trailing_zeros() as u8) - }; - let v = asn1::BitString::new(bits, unused_bits).unwrap(); - Ok(Some(asn1::write_single(&v)?)) + let der = encode_key_usage(py, ext)?; + Ok(Some(der)) } &oid::AUTHORITY_INFORMATION_ACCESS_OID | &oid::SUBJECT_INFORMATION_ACCESS_OID => { let ads = x509::common::encode_access_descriptions(ext.py(), ext)?; @@ -223,96 +373,8 @@ pub(crate) fn encode_extension( ))?)) } &oid::CERTIFICATE_POLICIES_OID => { - let mut policy_informations = vec![]; - for py_policy_info in ext.iter()? { - let py_policy_info = py_policy_info?; - let py_policy_qualifiers = - py_policy_info.getattr(pyo3::intern!(py, "policy_qualifiers"))?; - let qualifiers = if py_policy_qualifiers.is_true()? { - let mut qualifiers = vec![]; - for py_qualifier in py_policy_qualifiers.iter()? { - let py_qualifier = py_qualifier?; - let qualifier = if py_qualifier.is_instance_of::()? { - let cps_uri = match asn1::IA5String::new(py_qualifier.extract()?) { - Some(s) => s, - None => { - return Err(pyo3::exceptions::PyValueError::new_err( - "Qualifier must be an ASCII-string.", - ) - .into()) - } - }; - extensions::PolicyQualifierInfo { - policy_qualifier_id: (oid::CP_CPS_URI_OID).clone(), - qualifier: extensions::Qualifier::CpsUri(cps_uri), - } - } else { - let py_notice = - py_qualifier.getattr(pyo3::intern!(py, "notice_reference"))?; - let notice_ref = if py_notice.is_true()? { - let mut notice_numbers = vec![]; - for py_num in py_notice - .getattr(pyo3::intern!(py, "notice_numbers"))? - .iter()? - { - let bytes = - py_uint_to_big_endian_bytes(ext.py(), py_num?.downcast()?)?; - notice_numbers.push(asn1::BigUint::new(bytes).unwrap()); - } - - Some(extensions::NoticeReference { - organization: extensions::DisplayText::Utf8String( - asn1::Utf8String::new( - py_notice - .getattr(pyo3::intern!(py, "organization"))? - .extract()?, - ), - ), - notice_numbers: common::Asn1ReadableOrWritable::new_write( - asn1::SequenceOfWriter::new(notice_numbers), - ), - }) - } else { - None - }; - let py_explicit_text = - py_qualifier.getattr(pyo3::intern!(py, "explicit_text"))?; - let explicit_text = if py_explicit_text.is_true()? { - Some(extensions::DisplayText::Utf8String(asn1::Utf8String::new( - py_explicit_text.extract()?, - ))) - } else { - None - }; - - extensions::PolicyQualifierInfo { - policy_qualifier_id: (oid::CP_USER_NOTICE_OID).clone(), - qualifier: extensions::Qualifier::UserNotice( - extensions::UserNotice { - notice_ref, - explicit_text, - }, - ), - } - }; - qualifiers.push(qualifier); - } - Some(common::Asn1ReadableOrWritable::new_write( - asn1::SequenceOfWriter::new(qualifiers), - )) - } else { - None - }; - let py_policy_id = - py_policy_info.getattr(pyo3::intern!(py, "policy_identifier"))?; - policy_informations.push(extensions::PolicyInformation { - policy_identifier: py_oid_to_oid(py_policy_id)?, - policy_qualifiers: qualifiers, - }); - } - Ok(Some(asn1::write_single(&asn1::SequenceOfWriter::new( - policy_informations, - ))?)) + let der = encode_certificate_policies(py, ext)?; + Ok(Some(der)) } &oid::POLICY_CONSTRAINTS_OID => { let pc = extensions::PolicyConstraints { @@ -416,49 +478,8 @@ pub(crate) fn encode_extension( )?)) } &oid::ISSUING_DISTRIBUTION_POINT_OID => { - let only_some_reasons = if ext - .getattr(pyo3::intern!(py, "only_some_reasons"))? - .is_true()? - { - let py_reasons = ext.getattr(pyo3::intern!(py, "only_some_reasons"))?; - let reasons = certificate::encode_distribution_point_reasons(ext.py(), py_reasons)?; - Some(common::Asn1ReadableOrWritable::new_write(reasons)) - } else { - None - }; - let distribution_point = if ext.getattr(pyo3::intern!(py, "full_name"))?.is_true()? { - let py_full_name = ext.getattr(pyo3::intern!(py, "full_name"))?; - let gns = x509::common::encode_general_names(ext.py(), py_full_name)?; - Some(extensions::DistributionPointName::FullName( - common::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new(gns)), - )) - } else if ext.getattr(pyo3::intern!(py, "relative_name"))?.is_true()? { - let mut name_entries = vec![]; - for py_name_entry in ext.getattr(pyo3::intern!(py, "relative_name"))?.iter()? { - name_entries.push(x509::common::encode_name_entry(ext.py(), py_name_entry?)?); - } - Some(extensions::DistributionPointName::NameRelativeToCRLIssuer( - common::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new(name_entries)), - )) - } else { - None - }; - - let idp = crl::IssuingDistributionPoint { - distribution_point, - indirect_crl: ext.getattr(pyo3::intern!(py, "indirect_crl"))?.extract()?, - only_contains_attribute_certs: ext - .getattr(pyo3::intern!(py, "only_contains_attribute_certs"))? - .extract()?, - only_contains_ca_certs: ext - .getattr(pyo3::intern!(py, "only_contains_ca_certs"))? - .extract()?, - only_contains_user_certs: ext - .getattr(pyo3::intern!(py, "only_contains_user_certs"))? - .extract()?, - only_some_reasons, - }; - Ok(Some(asn1::write_single(&idp)?)) + let der = encode_issuing_distribution_point(py, ext)?; + Ok(Some(der)) } &oid::NONCE_OID => { let nonce = ext From 9bea7fe5f01853746bbb0b1911430652e89bfe34 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 24 Apr 2023 13:24:37 -0600 Subject: [PATCH 178/316] Factor out a few more extension encodings (#8814) --- src/rust/src/x509/common.rs | 10 +--- src/rust/src/x509/extensions.rs | 99 +++++++++++++++++++-------------- 2 files changed, 59 insertions(+), 50 deletions(-) diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index e81d52a0020c..571963e36b63 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -6,9 +6,7 @@ use crate::asn1::{oid_to_py_oid, py_oid_to_oid}; use crate::error::{CryptographyError, CryptographyResult}; use crate::{exceptions, x509}; use cryptography_x509::common::{Asn1ReadableOrWritable, AttributeTypeValue, RawTlv}; -use cryptography_x509::extensions::{ - AccessDescription, Extension, Extensions, SequenceOfAccessDescriptions, -}; +use cryptography_x509::extensions::{AccessDescription, Extension, Extensions}; use cryptography_x509::name::{GeneralName, Name, OtherName, UnvalidatedIA5String}; use pyo3::types::IntoPyDict; use pyo3::{IntoPy, ToPyObject}; @@ -159,7 +157,7 @@ pub(crate) fn encode_general_name<'a>( pub(crate) fn encode_access_descriptions<'a>( py: pyo3::Python<'a>, py_ads: &'a pyo3::PyAny, -) -> Result, CryptographyError> { +) -> CryptographyResult> { let mut ads = vec![]; for py_ad in py_ads.iter()? { let py_ad = py_ad?; @@ -171,9 +169,7 @@ pub(crate) fn encode_access_descriptions<'a>( access_location, }); } - Ok(Asn1ReadableOrWritable::new_write( - asn1::SequenceOfWriter::new(ads), - )) + Ok(asn1::write_single(&asn1::SequenceOfWriter::new(ads))?) } pub(crate) fn parse_name<'p>( diff --git a/src/rust/src/x509/extensions.rs b/src/rust/src/x509/extensions.rs index e12c320a0c47..98d1bd63b910 100644 --- a/src/rust/src/x509/extensions.rs +++ b/src/rust/src/x509/extensions.rs @@ -33,7 +33,7 @@ fn encode_general_subtrees<'a>( pub(crate) fn encode_authority_key_identifier<'a>( py: pyo3::Python<'a>, py_aki: &'a pyo3::PyAny, -) -> pyo3::PyResult> { +) -> CryptographyResult> { #[derive(pyo3::prelude::FromPyObject)] struct PyAuthorityKeyIdentifier<'a> { key_identifier: Option<&'a [u8]>, @@ -56,17 +56,17 @@ pub(crate) fn encode_authority_key_identifier<'a>( } else { None }; - Ok(extensions::AuthorityKeyIdentifier { + Ok(asn1::write_single(&extensions::AuthorityKeyIdentifier { authority_cert_issuer, authority_cert_serial_number, key_identifier: aki.key_identifier, - }) + })?) } pub(crate) fn encode_distribution_points<'p>( py: pyo3::Python<'p>, py_dps: &'p pyo3::PyAny, -) -> pyo3::PyResult>> { +) -> CryptographyResult> { #[derive(pyo3::prelude::FromPyObject)] struct PyDistributionPoint<'a> { crl_issuer: Option<&'a pyo3::PyAny>, @@ -115,7 +115,7 @@ pub(crate) fn encode_distribution_points<'p>( reasons, }); } - Ok(dps) + Ok(asn1::write_single(&asn1::SequenceOfWriter::new(dps))?) } fn encode_basic_constraints(ext: &pyo3::PyAny) -> CryptographyResult> { @@ -338,6 +338,45 @@ fn encode_issuing_distribution_point( Ok(asn1::write_single(&idp)?) } +fn encode_oid_sequence(ext: &pyo3::PyAny) -> CryptographyResult> { + let mut oids = vec![]; + for el in ext.iter()? { + let oid = py_oid_to_oid(el?)?; + oids.push(oid); + } + Ok(asn1::write_single(&asn1::SequenceOfWriter::new(oids))?) +} + +fn encode_tls_features(py: pyo3::Python<'_>, ext: &pyo3::PyAny) -> CryptographyResult> { + // 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(pyo3::intern!(py, "value"))?.extract::()?); + } + + Ok(asn1::write_single(&asn1::SequenceOfWriter::new(els))?) +} + +fn encode_scts(ext: &pyo3::PyAny) -> CryptographyResult> { + let mut length = 0; + for sct in ext.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 ext.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(asn1::write_single(&result.as_slice())?) +} + pub(crate) fn encode_extension( py: pyo3::Python<'_>, oid: &asn1::ObjectIdentifier, @@ -359,18 +398,12 @@ pub(crate) fn encode_extension( Ok(Some(der)) } &oid::AUTHORITY_INFORMATION_ACCESS_OID | &oid::SUBJECT_INFORMATION_ACCESS_OID => { - let ads = x509::common::encode_access_descriptions(ext.py(), ext)?; - Ok(Some(asn1::write_single(&ads)?)) + let der = x509::common::encode_access_descriptions(ext.py(), ext)?; + Ok(Some(der)) } &oid::EXTENDED_KEY_USAGE_OID | &oid::ACCEPTABLE_RESPONSES_OID => { - let mut oids = vec![]; - for el in ext.iter()? { - let oid = py_oid_to_oid(el?)?; - oids.push(oid); - } - Ok(Some(asn1::write_single(&asn1::SequenceOfWriter::new( - oids, - ))?)) + let der = encode_oid_sequence(ext)?; + Ok(Some(der)) } &oid::CERTIFICATE_POLICIES_OID => { let der = encode_certificate_policies(py, ext)?; @@ -410,43 +443,23 @@ pub(crate) fn encode_extension( Ok(Some(asn1::write_single(&asn1::SequenceOfWriter::new(gns))?)) } &oid::AUTHORITY_KEY_IDENTIFIER_OID => { - let aki = encode_authority_key_identifier(ext.py(), ext)?; - Ok(Some(asn1::write_single(&aki)?)) + let der = encode_authority_key_identifier(ext.py(), ext)?; + Ok(Some(der)) } &oid::FRESHEST_CRL_OID | &oid::CRL_DISTRIBUTION_POINTS_OID => { - let dps = encode_distribution_points(ext.py(), ext)?; - Ok(Some(asn1::write_single(&asn1::SequenceOfWriter::new(dps))?)) + let der = encode_distribution_points(ext.py(), ext)?; + Ok(Some(der)) } &oid::OCSP_NO_CHECK_OID => Ok(Some(asn1::write_single(&())?)), &oid::TLS_FEATURE_OID => { - // 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(pyo3::intern!(py, "value"))?.extract::()?); - } - - Ok(Some(asn1::write_single(&asn1::SequenceOfWriter::new(els))?)) + let der = encode_tls_features(py, ext)?; + Ok(Some(der)) } &oid::PRECERT_POISON_OID => Ok(Some(asn1::write_single(&())?)), &oid::PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS_OID | &oid::SIGNED_CERTIFICATE_TIMESTAMPS_OID => { - let mut length = 0; - for sct in ext.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 ext.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(Some(asn1::write_single(&result.as_slice())?)) + let der = encode_scts(ext)?; + Ok(Some(der)) } &oid::CRL_REASON_OID => { let value = ext From 6bb5578f352a290f3222ece8533e713f5e786193 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 23:22:45 +0000 Subject: [PATCH 179/316] Bump openssl-sys from 0.9.86 to 0.9.87 in /src/rust (#8817) Bumps [openssl-sys](https://github.com/sfackler/rust-openssl) from 0.9.86 to 0.9.87. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.86...openssl-sys-v0.9.87) --- updated-dependencies: - dependency-name: openssl-sys 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 | 4 ++-- src/rust/Cargo.toml | 2 +- src/rust/cryptography-cffi/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index e00d244cd4bb..88d95551d302 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -188,9 +188,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.86" +version = "0.9.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "992bac49bdbab4423199c654a5515bd2a6c6a23bf03f2dd3bdb7e5ae6259bc69" +checksum = "8e17f59264b2809d77ae94f0e1ebabc434773f370d6ca667bd223ea10e06cc7e" dependencies = [ "cc", "libc", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index dae85cef1d25..abbff3324a8a 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -17,7 +17,7 @@ cryptography-openssl = { path = "cryptography-openssl" } pem = "1.1" ouroboros = "0.15" openssl = "0.10.51" -openssl-sys = "0.9.85" +openssl-sys = "0.9.87" foreign-types-shared = "0.1" [build-dependencies] diff --git a/src/rust/cryptography-cffi/Cargo.toml b/src/rust/cryptography-cffi/Cargo.toml index 0c5655b170cc..f9ae6bc2ed43 100644 --- a/src/rust/cryptography-cffi/Cargo.toml +++ b/src/rust/cryptography-cffi/Cargo.toml @@ -9,7 +9,7 @@ rust-version = "1.56.0" [dependencies] pyo3 = { version = "0.18" } -openssl-sys = "0.9.85" +openssl-sys = "0.9.87" [build-dependencies] cc = "1.0.72" From 001345861e422fd3df51362502f66469651ab1e3 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 24 Apr 2023 17:28:28 -0600 Subject: [PATCH 180/316] Switch to using python -m build in wheel-builder (#8816) --- .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 9306ce7415e7..90e29c960d92 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -35,11 +35,11 @@ jobs: - run: python -m venv .venv - name: Install Python dependencies - run: .venv/bin/pip install -U pip wheel cffi setuptools-rust + run: .venv/bin/pip install -U pip build - name: Make sdist (cryptography) - run: .venv/bin/python setup.py sdist + run: .venv/bin/python -m build --sdist - name: Make sdist and wheel (vectors) - run: cd vectors/ && ../.venv/bin/python setup.py sdist bdist_wheel + run: cd vectors/ && ../.venv/bin/python -m build - uses: actions/upload-artifact@v3.1.2 with: name: "cryptography-sdist" From c315920795d98b29d79cf7de728d383c984580f9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 23:37:48 +0000 Subject: [PATCH 181/316] Bump target-lexicon from 0.12.6 to 0.12.7 in /src/rust (#8818) Bumps [target-lexicon](https://github.com/bytecodealliance/target-lexicon) from 0.12.6 to 0.12.7. - [Release notes](https://github.com/bytecodealliance/target-lexicon/releases) - [Commits](https://github.com/bytecodealliance/target-lexicon/compare/v0.12.6...v0.12.7) --- updated-dependencies: - dependency-name: target-lexicon 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 88d95551d302..bcf5884f0e34 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -406,9 +406,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.6" +version = "0.12.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" +checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" [[package]] name = "unicode-ident" From 9108d82a284a2996aa1fcbc2f318bf657c53049c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Apr 2023 23:49:00 +0000 Subject: [PATCH 182/316] Bump openssl from 0.10.51 to 0.10.52 in /src/rust (#8819) Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.51 to 0.10.52. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.51...openssl-v0.10.52) --- updated-dependencies: - dependency-name: openssl 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 | 4 ++-- src/rust/Cargo.toml | 2 +- src/rust/cryptography-openssl/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index bcf5884f0e34..e63a2e1ef0bf 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -162,9 +162,9 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "openssl" -version = "0.10.51" +version = "0.10.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ea2d98598bf9ada7ea6ee8a30fb74f9156b63bbe495d64ec2b87c269d2dda3" +checksum = "01b8574602df80f7b85fdfc5392fa884a4e3b3f4f35402c070ab34c3d3f78d56" dependencies = [ "bitflags", "cfg-if", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index abbff3324a8a..bb8f74a849b0 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -16,7 +16,7 @@ cryptography-x509 = { path = "cryptography-x509" } cryptography-openssl = { path = "cryptography-openssl" } pem = "1.1" ouroboros = "0.15" -openssl = "0.10.51" +openssl = "0.10.52" openssl-sys = "0.9.87" foreign-types-shared = "0.1" diff --git a/src/rust/cryptography-openssl/Cargo.toml b/src/rust/cryptography-openssl/Cargo.toml index 31927129e234..bd153edc40d5 100644 --- a/src/rust/cryptography-openssl/Cargo.toml +++ b/src/rust/cryptography-openssl/Cargo.toml @@ -8,7 +8,7 @@ publish = false rust-version = "1.56.0" [dependencies] -openssl = "0.10.51" +openssl = "0.10.52" ffi = { package = "openssl-sys", version = "0.9.85" } foreign-types = "0.3" foreign-types-shared = "0.1" From 392835b8a42d1555a04aa02408b3cdbd045f75d8 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 02:08:49 +0000 Subject: [PATCH 183/316] Bump BoringSSL and/or OpenSSL in CI (#8821) Co-authored-by: pyca-boringbot[bot] --- .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 2ae0092ef535..f37af412e70e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 22, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "b0b1f9dfc583c96d5f91b7f8cdb7efabcf22793b"}} - # Latest commit on the OpenSSL master branch, as of Apr 22, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "c04e78f0c69201226430fed14c291c281da47f2d"}} + # Latest commit on the BoringSSL master branch, as of Apr 25, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "de2d610a341f5a4b8c222425890537cb84c91400"}} + # Latest commit on the OpenSSL master branch, as of Apr 25, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "24a322544373f7acda05e19f64a6c3120d459d5b"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 9d70b87ff5371078ba53c01e27673fa9f0298f21 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 24 Apr 2023 20:10:54 -0600 Subject: [PATCH 184/316] Don't use setup.py in doc tests (#8820) --- ci-constraints-requirements.txt | 6 ++++-- noxfile.py | 2 +- pyproject.toml | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index c57e536353f7..2a38918e676d 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -1,7 +1,7 @@ # This is named ambigiously, but it's a pip constraints file, named like a # requirements file so dependabot will update the pins. # It was originally generated with; -# pip-compile --extra=docs --extra=docstest --extra=pep8test --extra=test --extra=test-randomorder --extra=nox --resolver=backtracking --strip-extras --unsafe-package=cffi --unsafe-package=pycparser --unsafe-package=setuptools pyproject.toml +# pip-compile --extra=docs --extra=docstest --extra=pep8test --extra=test --extra=test-randomorder --extra=nox --extra=sdist --resolver=backtracking --strip-extras --unsafe-package=cffi --unsafe-package=pycparser --unsafe-package=setuptools pyproject.toml # and then manually massaged to add version specifiers to packages whose # versions vary by Python version @@ -16,7 +16,9 @@ black==23.3.0 bleach==6.0.0 # via readme-renderer build==0.10.0 - # via check-manifest + # via + # check-manifest + # cryptography (pyproject.toml) certifi==2022.12.7 # via requests charset-normalizer==3.1.0 diff --git a/noxfile.py b/noxfile.py index b60d6a602e63..8f1b94a500fb 100644 --- a/noxfile.py +++ b/noxfile.py @@ -106,7 +106,7 @@ def docs(session: nox.Session) -> None: # This is in the docs job because `twine check` verifies that the README # is valid reStructuredText. - session.run("python", "setup.py", "sdist") + session.run("python", "-m", "build", "--sdist") session.run("twine", "check", "dist/*") diff --git a/pyproject.toml b/pyproject.toml index 8cf73cc44922..c66e0a38da40 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,7 +80,7 @@ test = [ test-randomorder = ["pytest-randomly"] docs = ["sphinx >=5.3.0", "sphinx-rtd-theme >=1.1.1"] docstest = ["pyenchant >=1.6.11", "twine >=1.12.0", "sphinxcontrib-spelling >=4.0.1"] -sdist = ["setuptools_rust >=0.11.4"] +sdist = ["build"] pep8test = ["black", "ruff", "mypy", "check-manifest"] [tool.black] From b5c25a91dac63fba15335eb8c72c444b70ffeeac Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 24 Apr 2023 21:22:11 -0600 Subject: [PATCH 185/316] Migrate DH to Rust (#8768) --- .../hazmat/backends/openssl/backend.py | 176 +------ .../hazmat/backends/openssl/dh.py | 331 ------------- .../bindings/_rust/openssl/__init__.pyi | 2 + .../hazmat/bindings/_rust/openssl/dh.pyi | 22 + .../hazmat/primitives/asymmetric/dh.py | 11 +- src/rust/src/backend/dh.rs | 443 ++++++++++++++++++ src/rust/src/backend/mod.rs | 4 +- src/rust/src/backend/utils.rs | 49 +- tests/hazmat/backends/test_openssl.py | 33 +- tests/hazmat/primitives/test_dh.py | 5 +- tests/hazmat/primitives/test_ed25519.py | 11 +- tests/hazmat/primitives/test_ed448.py | 11 +- tests/hazmat/primitives/test_serialization.py | 8 + tests/hazmat/primitives/test_x25519.py | 11 +- tests/hazmat/primitives/test_x448.py | 11 +- 15 files changed, 585 insertions(+), 543 deletions(-) delete mode 100644 src/cryptography/hazmat/backends/openssl/dh.py create mode 100644 src/cryptography/hazmat/bindings/_rust/openssl/dh.pyi create mode 100644 src/rust/src/backend/dh.rs diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 04b25f471a76..c8e1b81a218c 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -15,12 +15,6 @@ from cryptography.hazmat.backends.openssl import aead from cryptography.hazmat.backends.openssl.ciphers import _CipherContext from cryptography.hazmat.backends.openssl.cmac import _CMACContext -from cryptography.hazmat.backends.openssl.dh import ( - _dh_params_dup, - _DHParameters, - _DHPrivateKey, - _DHPublicKey, -) from cryptography.hazmat.backends.openssl.dsa import ( _DSAParameters, _DSAPrivateKey, @@ -609,10 +603,9 @@ def _evp_pkey_to_private_key( ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) elif key_type in self._dh_types: - dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey) - self.openssl_assert(dh_cdata != self._ffi.NULL) - dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) - return _DHPrivateKey(self, dh_cdata, evp_pkey) + return rust_openssl.dh.private_key_from_ptr( + int(self._ffi.cast("uintptr_t", evp_pkey)) + ) elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): # EVP_PKEY_ED25519 is not present in CRYPTOGRAPHY_IS_LIBRESSL return rust_openssl.ed25519.private_key_from_ptr( @@ -674,10 +667,9 @@ def _evp_pkey_to_public_key(self, evp_pkey) -> PublicKeyTypes: ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) elif key_type in self._dh_types: - dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey) - self.openssl_assert(dh_cdata != self._ffi.NULL) - dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) - return _DHPublicKey(self, dh_cdata, evp_pkey) + return rust_openssl.dh.public_key_from_ptr( + int(self._ffi.cast("uintptr_t", evp_pkey)) + ) elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): # EVP_PKEY_ED25519 is not present in CRYPTOGRAPHY_IS_LIBRESSL return rust_openssl.ed25519.public_key_from_ptr( @@ -925,16 +917,7 @@ def load_pem_public_key(self, data: bytes) -> PublicKeyTypes: self._handle_key_loading_error() def load_pem_parameters(self, data: bytes) -> dh.DHParameters: - mem_bio = self._bytes_to_bio(data) - # only DH is supported currently - dh_cdata = self._lib.PEM_read_bio_DHparams( - mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL - ) - if dh_cdata != self._ffi.NULL: - dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) - return _DHParameters(self, dh_cdata) - else: - self._handle_key_loading_error() + return rust_openssl.dh.from_pem_parameters(data) def load_der_private_key( self, @@ -1000,22 +983,7 @@ def load_der_public_key(self, data: bytes) -> PublicKeyTypes: self._handle_key_loading_error() def load_der_parameters(self, data: bytes) -> dh.DHParameters: - mem_bio = self._bytes_to_bio(data) - dh_cdata = self._lib.d2i_DHparams_bio(mem_bio.bio, self._ffi.NULL) - if dh_cdata != self._ffi.NULL: - dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) - return _DHParameters(self, dh_cdata) - elif self._lib.Cryptography_HAS_EVP_PKEY_DHX: - # We check to see if the is dhx. - self._consume_errors() - res = self._lib.BIO_reset(mem_bio.bio) - self.openssl_assert(res == 1) - dh_cdata = self._lib.d2i_DHxparams_bio(mem_bio.bio, self._ffi.NULL) - if dh_cdata != self._ffi.NULL: - dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) - return _DHParameters(self, dh_cdata) - - self._handle_key_loading_error() + return rust_openssl.dh.from_der_parameters(data) def _cert2ossl(self, cert: x509.Certificate) -> typing.Any: data = cert.public_bytes(serialization.Encoding.DER) @@ -1611,48 +1579,12 @@ def dh_supported(self) -> bool: def generate_dh_parameters( self, generator: int, key_size: int ) -> dh.DHParameters: - if key_size < dh._MIN_MODULUS_SIZE: - raise ValueError( - "DH key_size must be at least {} bits".format( - dh._MIN_MODULUS_SIZE - ) - ) - - if generator not in (2, 5): - raise ValueError("DH generator must be 2 or 5") - - dh_param_cdata = self._lib.DH_new() - self.openssl_assert(dh_param_cdata != self._ffi.NULL) - dh_param_cdata = self._ffi.gc(dh_param_cdata, self._lib.DH_free) - - res = self._lib.DH_generate_parameters_ex( - dh_param_cdata, key_size, generator, self._ffi.NULL - ) - if res != 1: - errors = self._consume_errors() - raise ValueError("Unable to generate DH parameters", errors) - - return _DHParameters(self, dh_param_cdata) - - def _dh_cdata_to_evp_pkey(self, dh_cdata): - evp_pkey = self._create_evp_pkey_gc() - res = self._lib.EVP_PKEY_set1_DH(evp_pkey, dh_cdata) - self.openssl_assert(res == 1) - return evp_pkey + return rust_openssl.dh.generate_parameters(generator, key_size) def generate_dh_private_key( self, parameters: dh.DHParameters ) -> dh.DHPrivateKey: - dh_key_cdata = _dh_params_dup( - parameters._dh_cdata, self # type: ignore[attr-defined] - ) - - res = self._lib.DH_generate_key(dh_key_cdata) - self.openssl_assert(res == 1) - - evp_pkey = self._dh_cdata_to_evp_pkey(dh_key_cdata) - - return _DHPrivateKey(self, dh_key_cdata, evp_pkey) + return parameters.generate_private_key() def generate_dh_private_key_and_parameters( self, generator: int, key_size: int @@ -1664,99 +1596,17 @@ def generate_dh_private_key_and_parameters( def load_dh_private_numbers( self, numbers: dh.DHPrivateNumbers ) -> dh.DHPrivateKey: - parameter_numbers = numbers.public_numbers.parameter_numbers - - dh_cdata = self._lib.DH_new() - self.openssl_assert(dh_cdata != self._ffi.NULL) - dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) - - p = self._int_to_bn(parameter_numbers.p) - g = self._int_to_bn(parameter_numbers.g) - - if parameter_numbers.q is not None: - q = self._int_to_bn(parameter_numbers.q) - else: - q = self._ffi.NULL - - pub_key = self._int_to_bn(numbers.public_numbers.y) - priv_key = self._int_to_bn(numbers.x) - - res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) - self.openssl_assert(res == 1) - - res = self._lib.DH_set0_key(dh_cdata, pub_key, priv_key) - self.openssl_assert(res == 1) - - codes = self._ffi.new("int[]", 1) - res = self._lib.DH_check(dh_cdata, codes) - self.openssl_assert(res == 1) - - # DH_check will return DH_NOT_SUITABLE_GENERATOR if p % 24 does not - # equal 11 when the generator is 2 (a quadratic nonresidue). - # We want to ignore that error because p % 24 == 23 is also fine. - # Specifically, g is then a quadratic residue. Within the context of - # Diffie-Hellman this means it can only generate half the possible - # values. That sounds bad, but quadratic nonresidues leak a bit of - # the key to the attacker in exchange for having the full key space - # available. See: https://crypto.stackexchange.com/questions/12961 - if codes[0] != 0 and not ( - parameter_numbers.g == 2 - and codes[0] ^ self._lib.DH_NOT_SUITABLE_GENERATOR == 0 - ): - raise ValueError("DH private numbers did not pass safety checks.") - - evp_pkey = self._dh_cdata_to_evp_pkey(dh_cdata) - - return _DHPrivateKey(self, dh_cdata, evp_pkey) + return rust_openssl.dh.from_private_numbers(numbers) def load_dh_public_numbers( self, numbers: dh.DHPublicNumbers ) -> dh.DHPublicKey: - dh_cdata = self._lib.DH_new() - self.openssl_assert(dh_cdata != self._ffi.NULL) - dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) - - parameter_numbers = numbers.parameter_numbers - - p = self._int_to_bn(parameter_numbers.p) - g = self._int_to_bn(parameter_numbers.g) - - if parameter_numbers.q is not None: - q = self._int_to_bn(parameter_numbers.q) - else: - q = self._ffi.NULL - - pub_key = self._int_to_bn(numbers.y) - - res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) - self.openssl_assert(res == 1) - - res = self._lib.DH_set0_key(dh_cdata, pub_key, self._ffi.NULL) - self.openssl_assert(res == 1) - - evp_pkey = self._dh_cdata_to_evp_pkey(dh_cdata) - - return _DHPublicKey(self, dh_cdata, evp_pkey) + return rust_openssl.dh.from_public_numbers(numbers) def load_dh_parameter_numbers( self, numbers: dh.DHParameterNumbers ) -> dh.DHParameters: - dh_cdata = self._lib.DH_new() - self.openssl_assert(dh_cdata != self._ffi.NULL) - dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) - - p = self._int_to_bn(numbers.p) - g = self._int_to_bn(numbers.g) - - if numbers.q is not None: - q = self._int_to_bn(numbers.q) - else: - q = self._ffi.NULL - - res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) - self.openssl_assert(res == 1) - - return _DHParameters(self, dh_cdata) + return rust_openssl.dh.from_parameter_numbers(numbers) def dh_parameters_supported( self, p: int, g: int, q: typing.Optional[int] = None diff --git a/src/cryptography/hazmat/backends/openssl/dh.py b/src/cryptography/hazmat/backends/openssl/dh.py deleted file mode 100644 index 42a92bcc1cd6..000000000000 --- a/src/cryptography/hazmat/backends/openssl/dh.py +++ /dev/null @@ -1,331 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography.exceptions import UnsupportedAlgorithm, _Reasons -from cryptography.hazmat.primitives import serialization -from cryptography.hazmat.primitives.asymmetric import dh - -if typing.TYPE_CHECKING: - from cryptography.hazmat.backends.openssl.backend import Backend - - -def _dh_params_dup(dh_cdata, backend: Backend): - lib = backend._lib - ffi = backend._ffi - - param_cdata = lib.DHparams_dup(dh_cdata) - backend.openssl_assert(param_cdata != ffi.NULL) - param_cdata = ffi.gc(param_cdata, lib.DH_free) - if lib.CRYPTOGRAPHY_IS_LIBRESSL: - # In libressl DHparams_dup don't copy q - q = ffi.new("BIGNUM **") - lib.DH_get0_pqg(dh_cdata, ffi.NULL, q, ffi.NULL) - q_dup = lib.BN_dup(q[0]) - res = lib.DH_set0_pqg(param_cdata, ffi.NULL, q_dup, ffi.NULL) - backend.openssl_assert(res == 1) - - return param_cdata - - -def _dh_cdata_to_parameters(dh_cdata, backend: Backend) -> _DHParameters: - param_cdata = _dh_params_dup(dh_cdata, backend) - return _DHParameters(backend, param_cdata) - - -class _DHParameters(dh.DHParameters): - def __init__(self, backend: Backend, dh_cdata): - self._backend = backend - self._dh_cdata = dh_cdata - - def parameter_numbers(self) -> dh.DHParameterNumbers: - p = self._backend._ffi.new("BIGNUM **") - g = self._backend._ffi.new("BIGNUM **") - q = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) - self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) - self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) - q_val: typing.Optional[int] - if q[0] == self._backend._ffi.NULL: - q_val = None - else: - q_val = self._backend._bn_to_int(q[0]) - return dh.DHParameterNumbers( - p=self._backend._bn_to_int(p[0]), - g=self._backend._bn_to_int(g[0]), - q=q_val, - ) - - def generate_private_key(self) -> dh.DHPrivateKey: - return self._backend.generate_dh_private_key(self) - - def parameter_bytes( - self, - encoding: serialization.Encoding, - format: serialization.ParameterFormat, - ) -> bytes: - if encoding is serialization.Encoding.OpenSSH: - raise TypeError("OpenSSH encoding is not supported") - - if format is not serialization.ParameterFormat.PKCS3: - raise ValueError("Only PKCS3 serialization is supported") - - q = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DH_get0_pqg( - self._dh_cdata, self._backend._ffi.NULL, q, self._backend._ffi.NULL - ) - if ( - q[0] != self._backend._ffi.NULL - and not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX - ): - raise UnsupportedAlgorithm( - "DH X9.42 serialization is not supported", - _Reasons.UNSUPPORTED_SERIALIZATION, - ) - - if encoding is serialization.Encoding.PEM: - if q[0] != self._backend._ffi.NULL: - write_bio = self._backend._lib.PEM_write_bio_DHxparams - else: - write_bio = self._backend._lib.PEM_write_bio_DHparams - elif encoding is serialization.Encoding.DER: - if q[0] != self._backend._ffi.NULL: - write_bio = self._backend._lib.i2d_DHxparams_bio - else: - write_bio = self._backend._lib.i2d_DHparams_bio - else: - raise TypeError("encoding must be an item from the Encoding enum") - - bio = self._backend._create_mem_bio_gc() - res = write_bio(bio, self._dh_cdata) - self._backend.openssl_assert(res == 1) - return self._backend._read_mem_bio(bio) - - -def _get_dh_num_bits(backend, dh_cdata) -> int: - p = backend._ffi.new("BIGNUM **") - backend._lib.DH_get0_pqg(dh_cdata, p, backend._ffi.NULL, backend._ffi.NULL) - backend.openssl_assert(p[0] != backend._ffi.NULL) - return backend._lib.BN_num_bits(p[0]) - - -class _DHPrivateKey(dh.DHPrivateKey): - def __init__(self, backend: Backend, dh_cdata, evp_pkey): - self._backend = backend - self._dh_cdata = dh_cdata - self._evp_pkey = evp_pkey - self._key_size_bytes = self._backend._lib.DH_size(dh_cdata) - - @property - def key_size(self) -> int: - return _get_dh_num_bits(self._backend, self._dh_cdata) - - def private_numbers(self) -> dh.DHPrivateNumbers: - p = self._backend._ffi.new("BIGNUM **") - g = self._backend._ffi.new("BIGNUM **") - q = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) - self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) - self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) - if q[0] == self._backend._ffi.NULL: - q_val = None - else: - q_val = self._backend._bn_to_int(q[0]) - pub_key = self._backend._ffi.new("BIGNUM **") - priv_key = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DH_get0_key(self._dh_cdata, pub_key, priv_key) - self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) - self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL) - return dh.DHPrivateNumbers( - public_numbers=dh.DHPublicNumbers( - parameter_numbers=dh.DHParameterNumbers( - p=self._backend._bn_to_int(p[0]), - g=self._backend._bn_to_int(g[0]), - q=q_val, - ), - y=self._backend._bn_to_int(pub_key[0]), - ), - x=self._backend._bn_to_int(priv_key[0]), - ) - - def exchange(self, peer_public_key: dh.DHPublicKey) -> bytes: - 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(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) - - 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: bool) -> None: - if not ok: - errors = self._backend._consume_errors() - raise ValueError( - "Error computing shared key.", - errors, - ) - - def public_key(self) -> dh.DHPublicKey: - dh_cdata = _dh_params_dup(self._dh_cdata, self._backend) - pub_key = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DH_get0_key( - self._dh_cdata, pub_key, self._backend._ffi.NULL - ) - self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) - pub_key_dup = self._backend._lib.BN_dup(pub_key[0]) - self._backend.openssl_assert(pub_key_dup != self._backend._ffi.NULL) - - res = self._backend._lib.DH_set0_key( - dh_cdata, pub_key_dup, self._backend._ffi.NULL - ) - self._backend.openssl_assert(res == 1) - evp_pkey = self._backend._dh_cdata_to_evp_pkey(dh_cdata) - return _DHPublicKey(self._backend, dh_cdata, evp_pkey) - - def parameters(self) -> dh.DHParameters: - return _dh_cdata_to_parameters(self._dh_cdata, self._backend) - - def private_bytes( - self, - encoding: serialization.Encoding, - format: serialization.PrivateFormat, - encryption_algorithm: serialization.KeySerializationEncryption, - ) -> bytes: - if format is not serialization.PrivateFormat.PKCS8: - raise ValueError( - "DH private keys support only PKCS8 serialization" - ) - if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX: - q = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DH_get0_pqg( - self._dh_cdata, - self._backend._ffi.NULL, - q, - self._backend._ffi.NULL, - ) - if q[0] != self._backend._ffi.NULL: - raise UnsupportedAlgorithm( - "DH X9.42 serialization is not supported", - _Reasons.UNSUPPORTED_SERIALIZATION, - ) - - return self._backend._private_key_bytes( - encoding, - format, - encryption_algorithm, - self, - self._evp_pkey, - self._dh_cdata, - ) - - -class _DHPublicKey(dh.DHPublicKey): - def __init__(self, backend: Backend, dh_cdata, evp_pkey): - self._backend = backend - self._dh_cdata = dh_cdata - self._evp_pkey = evp_pkey - self._key_size_bits = _get_dh_num_bits(self._backend, self._dh_cdata) - - @property - def key_size(self) -> int: - return self._key_size_bits - - def __eq__(self, other: object) -> bool: - if not isinstance(other, _DHPublicKey): - return NotImplemented - - res = self._backend._lib.EVP_PKEY_cmp(self._evp_pkey, other._evp_pkey) - if res < 0: - # DH public keys have two types (DH, DHX) that OpenSSL - # considers different types but we do not. Mismatched types - # push an error on the stack, so we need to consume it. - self._backend._consume_errors() - return res == 1 - - def public_numbers(self) -> dh.DHPublicNumbers: - p = self._backend._ffi.new("BIGNUM **") - g = self._backend._ffi.new("BIGNUM **") - q = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) - self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) - self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) - if q[0] == self._backend._ffi.NULL: - q_val = None - else: - q_val = self._backend._bn_to_int(q[0]) - pub_key = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DH_get0_key( - self._dh_cdata, pub_key, self._backend._ffi.NULL - ) - self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) - return dh.DHPublicNumbers( - parameter_numbers=dh.DHParameterNumbers( - p=self._backend._bn_to_int(p[0]), - g=self._backend._bn_to_int(g[0]), - q=q_val, - ), - y=self._backend._bn_to_int(pub_key[0]), - ) - - def parameters(self) -> dh.DHParameters: - return _dh_cdata_to_parameters(self._dh_cdata, self._backend) - - def public_bytes( - self, - encoding: serialization.Encoding, - format: serialization.PublicFormat, - ) -> bytes: - if format is not serialization.PublicFormat.SubjectPublicKeyInfo: - raise ValueError( - "DH public keys support only " - "SubjectPublicKeyInfo serialization" - ) - - if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX: - q = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DH_get0_pqg( - self._dh_cdata, - self._backend._ffi.NULL, - q, - self._backend._ffi.NULL, - ) - if q[0] != self._backend._ffi.NULL: - raise UnsupportedAlgorithm( - "DH X9.42 serialization is not supported", - _Reasons.UNSUPPORTED_SERIALIZATION, - ) - - return self._backend._public_key_bytes( - encoding, format, self, self._evp_pkey, None - ) diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi index 3e8d894cdb51..bfa641259854 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -5,6 +5,7 @@ import typing from cryptography.hazmat.bindings._rust.openssl import ( + dh, ed448, ed25519, hashes, @@ -16,6 +17,7 @@ from cryptography.hazmat.bindings._rust.openssl import ( __all__ = [ "openssl_version", "raise_openssl_error", + "dh", "hashes", "hmac", "ed448", diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/dh.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/dh.pyi new file mode 100644 index 000000000000..bfd005d99fec --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/openssl/dh.pyi @@ -0,0 +1,22 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives.asymmetric import dh + +MIN_MODULUS_SIZE: int + +class DHPrivateKey: ... +class DHPublicKey: ... +class DHParameters: ... + +def generate_parameters(generator: int, key_size: int) -> dh.DHParameters: ... +def private_key_from_ptr(ptr: int) -> dh.DHPrivateKey: ... +def public_key_from_ptr(ptr: int) -> dh.DHPublicKey: ... +def from_pem_parameters(data: bytes) -> dh.DHParameters: ... +def from_der_parameters(data: bytes) -> dh.DHParameters: ... +def from_private_numbers(numbers: dh.DHPrivateNumbers) -> dh.DHPrivateKey: ... +def from_public_numbers(numbers: dh.DHPublicNumbers) -> dh.DHPublicKey: ... +def from_parameter_numbers( + numbers: dh.DHParameterNumbers, +) -> dh.DHParameters: ... diff --git a/src/cryptography/hazmat/primitives/asymmetric/dh.py b/src/cryptography/hazmat/primitives/asymmetric/dh.py index 02feb5f2ed4c..751bcc402e94 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/dh.py +++ b/src/cryptography/hazmat/primitives/asymmetric/dh.py @@ -7,10 +7,9 @@ import abc import typing +from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives import _serialization -_MIN_MODULUS_SIZE = 512 - def generate_parameters( generator: int, key_size: int, backend: typing.Any = None @@ -30,9 +29,10 @@ def __init__(self, p: int, g: int, q: typing.Optional[int] = None) -> None: if g < 2: raise ValueError("DH generator must be 2 or greater") - if p.bit_length() < _MIN_MODULUS_SIZE: + if p.bit_length() < rust_openssl.dh.MIN_MODULUS_SIZE: raise ValueError( - f"p (modulus) must be at least {_MIN_MODULUS_SIZE}-bit" + f"p (modulus) must be at least " + f"{rust_openssl.dh.MIN_MODULUS_SIZE}-bit" ) self._p = p @@ -168,6 +168,7 @@ def parameter_numbers(self) -> DHParameterNumbers: DHParametersWithSerialization = DHParameters +DHParameters.register(rust_openssl.dh.DHParameters) class DHPublicKey(metaclass=abc.ABCMeta): @@ -208,6 +209,7 @@ def __eq__(self, other: object) -> bool: DHPublicKeyWithSerialization = DHPublicKey +DHPublicKey.register(rust_openssl.dh.DHPublicKey) class DHPrivateKey(metaclass=abc.ABCMeta): @@ -256,3 +258,4 @@ def private_bytes( DHPrivateKeyWithSerialization = DHPrivateKey +DHPrivateKey.register(rust_openssl.dh.DHPrivateKey) diff --git a/src/rust/src/backend/dh.rs b/src/rust/src/backend/dh.rs new file mode 100644 index 000000000000..33e94f1c204d --- /dev/null +++ b/src/rust/src/backend/dh.rs @@ -0,0 +1,443 @@ +// 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::encode_der_data; +use crate::backend::utils; +use crate::error::{CryptographyError, CryptographyResult}; +use crate::x509; +use foreign_types_shared::ForeignTypeRef; + +const MIN_MODULUS_SIZE: u32 = 512; + +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.dh")] +struct DHPrivateKey { + pkey: openssl::pkey::PKey, +} + +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.dh")] +struct DHPublicKey { + pkey: openssl::pkey::PKey, +} + +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.dh")] +struct DHParameters { + dh: openssl::dh::Dh, +} + +#[pyo3::prelude::pyfunction] +fn generate_parameters(generator: u32, key_size: u32) -> CryptographyResult { + if key_size < MIN_MODULUS_SIZE { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err(format!( + "DH key_size must be at least {} bits", + MIN_MODULUS_SIZE + )), + )); + } + if generator != 2 && generator != 5 { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err("DH generator must be 2 or 5"), + )); + } + + let dh = openssl::dh::Dh::generate_params(key_size, generator) + .map_err(|_| pyo3::exceptions::PyValueError::new_err("Unable to generate DH parameters"))?; + Ok(DHParameters { dh }) +} + +#[pyo3::prelude::pyfunction] +fn private_key_from_ptr(ptr: usize) -> DHPrivateKey { + let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; + DHPrivateKey { + pkey: pkey.to_owned(), + } +} + +#[pyo3::prelude::pyfunction] +fn public_key_from_ptr(ptr: usize) -> DHPublicKey { + let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; + DHPublicKey { + pkey: pkey.to_owned(), + } +} + +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +struct ASN1DHParams<'a> { + p: asn1::BigUint<'a>, + g: asn1::BigUint<'a>, + q: Option>, +} + +#[pyo3::prelude::pyfunction] +fn from_der_parameters(data: &[u8]) -> CryptographyResult { + let asn1_params = asn1::parse_single::>(data)?; + + let p = openssl::bn::BigNum::from_slice(asn1_params.p.as_bytes())?; + let q = asn1_params + .q + .map(|q| openssl::bn::BigNum::from_slice(q.as_bytes())) + .transpose()?; + let g = openssl::bn::BigNum::from_slice(asn1_params.g.as_bytes())?; + + Ok(DHParameters { + dh: openssl::dh::Dh::from_pqg(p, q, g)?, + }) +} + +#[pyo3::prelude::pyfunction] +fn from_pem_parameters(data: &[u8]) -> CryptographyResult { + let parsed = x509::find_in_pem( + data, + |p| p.tag == "DH PARAMETERS" || p.tag == "X9.42 DH PARAMETERS", + "Valid PEM but no BEGIN DH PARAMETERS/END DH PARAMETERS delimiters. Are you sure this is a DH parameters?", + )?; + + from_der_parameters(&parsed.contents) +} + +fn dh_parameters_from_numbers( + py: pyo3::Python<'_>, + numbers: &pyo3::PyAny, +) -> CryptographyResult> { + let p = utils::py_int_to_bn(py, numbers.getattr(pyo3::intern!(py, "p"))?)?; + let q = numbers + .getattr(pyo3::intern!(py, "q"))? + .extract::>()? + .map(|v| utils::py_int_to_bn(py, v)) + .transpose()?; + let g = utils::py_int_to_bn(py, numbers.getattr(pyo3::intern!(py, "g"))?)?; + + let dh = openssl::dh::Dh::from_pqg(p, q, g)?; + if !dh.check_key()? { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err( + "DH private numbers did not pass safety checks.", + ), + )); + } + + Ok(dh) +} + +#[pyo3::prelude::pyfunction] +fn from_private_numbers( + py: pyo3::Python<'_>, + numbers: &pyo3::PyAny, +) -> CryptographyResult { + let public_numbers = numbers.getattr(pyo3::intern!(py, "public_numbers"))?; + let parameter_numbers = public_numbers.getattr(pyo3::intern!(py, "parameter_numbers"))?; + + let dh = dh_parameters_from_numbers(py, parameter_numbers)?; + + let pub_key = utils::py_int_to_bn(py, public_numbers.getattr(pyo3::intern!(py, "y"))?)?; + let priv_key = utils::py_int_to_bn(py, numbers.getattr(pyo3::intern!(py, "x"))?)?; + + let pkey = openssl::pkey::PKey::from_dh(dh.set_key(pub_key, priv_key)?)?; + Ok(DHPrivateKey { pkey }) +} + +#[pyo3::prelude::pyfunction] +fn from_public_numbers( + py: pyo3::Python<'_>, + numbers: &pyo3::PyAny, +) -> CryptographyResult { + let parameter_numbers = numbers.getattr(pyo3::intern!(py, "parameter_numbers"))?; + let dh = dh_parameters_from_numbers(py, parameter_numbers)?; + + let pub_key = utils::py_int_to_bn(py, numbers.getattr(pyo3::intern!(py, "y"))?)?; + + let pkey = openssl::pkey::PKey::from_dh(dh.set_public_key(pub_key)?)?; + + Ok(DHPublicKey { pkey }) +} + +#[pyo3::prelude::pyfunction] +fn from_parameter_numbers( + py: pyo3::Python<'_>, + numbers: &pyo3::PyAny, +) -> CryptographyResult { + let dh = dh_parameters_from_numbers(py, numbers)?; + Ok(DHParameters { dh }) +} + +fn clone_dh( + dh: &openssl::dh::Dh, +) -> CryptographyResult> { + let p = dh.prime_p().to_owned()?; + let q = dh.prime_q().map(|q| q.to_owned()).transpose()?; + let g = dh.generator().to_owned()?; + Ok(openssl::dh::Dh::from_pqg(p, q, g)?) +} + +#[pyo3::prelude::pymethods] +impl DHPrivateKey { + #[getter] + fn key_size(&self) -> i32 { + self.pkey.dh().unwrap().prime_p().num_bits() + } + + fn exchange<'p>( + &self, + py: pyo3::Python<'p>, + public_key: &DHPublicKey, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let mut deriver = openssl::derive::Deriver::new(&self.pkey)?; + deriver + .set_peer(&public_key.pkey) + .map_err(|_| pyo3::exceptions::PyValueError::new_err("Error computing shared key."))?; + + Ok(pyo3::types::PyBytes::new_with(py, deriver.len()?, |b| { + let n = deriver.derive(b).unwrap(); + + let pad = b.len() - n; + if pad > 0 { + b.copy_within(0..n, pad); + for c in b.iter_mut().take(pad) { + *c = 0; + } + } + Ok(()) + })?) + } + + fn private_numbers<'p>(&self, py: pyo3::Python<'p>) -> CryptographyResult<&'p pyo3::PyAny> { + let dh = self.pkey.dh().unwrap(); + + let py_p = utils::bn_to_py_int(py, dh.prime_p())?; + let py_q = dh + .prime_q() + .map(|q| utils::bn_to_py_int(py, q)) + .transpose()?; + let py_g = utils::bn_to_py_int(py, dh.generator())?; + + let py_pub_key = utils::bn_to_py_int(py, dh.public_key())?; + let py_private_key = utils::bn_to_py_int(py, dh.private_key())?; + + let dh_mod = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.dh" + ))?; + + let parameter_numbers = + dh_mod.call_method1(pyo3::intern!(py, "DHParameterNumbers"), (py_p, py_g, py_q))?; + let public_numbers = dh_mod.call_method1( + pyo3::intern!(py, "DHPublicNumbers"), + (py_pub_key, parameter_numbers), + )?; + + Ok(dh_mod.call_method1( + pyo3::intern!(py, "DHPrivateNumbers"), + (py_private_key, public_numbers), + )?) + } + + fn public_key(&self) -> CryptographyResult { + let orig_dh = self.pkey.dh().unwrap(); + let dh = clone_dh(&orig_dh)?; + + let pkey = + openssl::pkey::PKey::from_dh(dh.set_public_key(orig_dh.public_key().to_owned()?)?)?; + + Ok(DHPublicKey { pkey }) + } + + fn parameters(&self) -> CryptographyResult { + Ok(DHParameters { + dh: clone_dh(&self.pkey.dh().unwrap())?, + }) + } + + fn private_bytes<'p>( + slf: &pyo3::PyCell, + py: pyo3::Python<'p>, + encoding: &pyo3::PyAny, + format: &pyo3::PyAny, + encryption_algorithm: &pyo3::PyAny, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let private_format_class = py + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization" + ))? + .getattr(pyo3::intern!(py, "PrivateFormat"))?; + if !format.is(private_format_class.getattr(pyo3::intern!(py, "PKCS8"))?) { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err( + "DH private keys support only PKCS8 serialization", + ), + )); + } + + utils::pkey_private_bytes( + py, + slf, + &slf.borrow().pkey, + encoding, + format, + encryption_algorithm, + true, + ) + } +} + +#[pyo3::prelude::pymethods] +impl DHPublicKey { + #[getter] + fn key_size(&self) -> i32 { + self.pkey.dh().unwrap().prime_p().num_bits() + } + + fn public_bytes<'p>( + slf: &pyo3::PyCell, + py: pyo3::Python<'p>, + encoding: &pyo3::PyAny, + format: &pyo3::PyAny, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let public_format_class = py + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization" + ))? + .getattr(pyo3::intern!(py, "PublicFormat"))?; + if !format.is(public_format_class.getattr(pyo3::intern!(py, "SubjectPublicKeyInfo"))?) { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err( + "DH public keys support only SubjectPublicKeyInfo serialization", + ), + )); + } + + utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, true) + } + + fn parameters(&self) -> CryptographyResult { + Ok(DHParameters { + dh: clone_dh(&self.pkey.dh().unwrap())?, + }) + } + + fn public_numbers<'p>(&self, py: pyo3::Python<'p>) -> CryptographyResult<&'p pyo3::PyAny> { + let dh = self.pkey.dh().unwrap(); + + let py_p = utils::bn_to_py_int(py, dh.prime_p())?; + let py_q = dh + .prime_q() + .map(|q| utils::bn_to_py_int(py, q)) + .transpose()?; + let py_g = utils::bn_to_py_int(py, dh.generator())?; + + let py_pub_key = utils::bn_to_py_int(py, dh.public_key())?; + + let dh_mod = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.dh" + ))?; + + let parameter_numbers = + dh_mod.call_method1(pyo3::intern!(py, "DHParameterNumbers"), (py_p, py_g, py_q))?; + + Ok(dh_mod.call_method1( + pyo3::intern!(py, "DHPublicNumbers"), + (py_pub_key, parameter_numbers), + )?) + } + + fn __richcmp__( + &self, + other: pyo3::PyRef<'_, DHPublicKey>, + op: pyo3::basic::CompareOp, + ) -> pyo3::PyResult { + match op { + pyo3::basic::CompareOp::Eq => Ok(self.pkey.public_eq(&other.pkey)), + pyo3::basic::CompareOp::Ne => Ok(!self.pkey.public_eq(&other.pkey)), + _ => Err(pyo3::exceptions::PyTypeError::new_err("Cannot be ordered")), + } + } +} + +#[pyo3::prelude::pymethods] +impl DHParameters { + fn generate_private_key(&self) -> CryptographyResult { + let dh = clone_dh(&self.dh)?.generate_key()?; + Ok(DHPrivateKey { + pkey: openssl::pkey::PKey::from_dh(dh)?, + }) + } + + fn parameter_numbers<'p>(&self, py: pyo3::Python<'p>) -> CryptographyResult<&'p pyo3::PyAny> { + let py_p = utils::bn_to_py_int(py, self.dh.prime_p())?; + let py_q = self + .dh + .prime_q() + .map(|q| utils::bn_to_py_int(py, q)) + .transpose()?; + let py_g = utils::bn_to_py_int(py, self.dh.generator())?; + + Ok(py + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.dh" + ))? + .call_method1(pyo3::intern!(py, "DHParameterNumbers"), (py_p, py_g, py_q))?) + } + + fn parameter_bytes<'p>( + &self, + py: pyo3::Python<'p>, + encoding: &'p pyo3::PyAny, + format: &pyo3::PyAny, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let parameter_format_class = py + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.serialization" + ))? + .getattr(pyo3::intern!(py, "ParameterFormat"))?; + if !format.is(parameter_format_class.getattr(pyo3::intern!(py, "PKCS3"))?) { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err("Only PKCS3 serialization is supported"), + )); + } + + let p_bytes = utils::bn_to_big_endian_bytes(self.dh.prime_p())?; + let q_bytes = self + .dh + .prime_q() + .map(utils::bn_to_big_endian_bytes) + .transpose()?; + let g_bytes = utils::bn_to_big_endian_bytes(self.dh.generator())?; + let asn1dh_params = ASN1DHParams { + p: asn1::BigUint::new(&p_bytes).unwrap(), + q: q_bytes.as_ref().map(|q| asn1::BigUint::new(q).unwrap()), + g: asn1::BigUint::new(&g_bytes).unwrap(), + }; + let data = asn1::write_single(&asn1dh_params)?; + let tag = if q_bytes.is_none() { + "DH PARAMETERS" + } else { + "X9.42 DH PARAMETERS" + }; + encode_der_data(py, tag.to_string(), data, encoding) + } +} + +pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let m = pyo3::prelude::PyModule::new(py, "dh")?; + m.add_wrapped(pyo3::wrap_pyfunction!(generate_parameters))?; + m.add_wrapped(pyo3::wrap_pyfunction!(private_key_from_ptr))?; + m.add_wrapped(pyo3::wrap_pyfunction!(public_key_from_ptr))?; + m.add_wrapped(pyo3::wrap_pyfunction!(from_der_parameters))?; + m.add_wrapped(pyo3::wrap_pyfunction!(from_pem_parameters))?; + m.add_wrapped(pyo3::wrap_pyfunction!(from_private_numbers))?; + m.add_wrapped(pyo3::wrap_pyfunction!(from_public_numbers))?; + m.add_wrapped(pyo3::wrap_pyfunction!(from_parameter_numbers))?; + + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + + m.add("MIN_MODULUS_SIZE", MIN_MODULUS_SIZE)?; + + Ok(m) +} diff --git a/src/rust/src/backend/mod.rs b/src/rust/src/backend/mod.rs index b48f2089a991..a38d39287ee2 100644 --- a/src/rust/src/backend/mod.rs +++ b/src/rust/src/backend/mod.rs @@ -2,13 +2,13 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. +pub(crate) mod dh; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] pub(crate) mod ed25519; #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] pub(crate) mod ed448; pub(crate) mod hashes; pub(crate) mod hmac; -#[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] pub(crate) mod utils; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] pub(crate) mod x25519; @@ -16,6 +16,8 @@ pub(crate) mod x25519; pub(crate) mod x448; pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { + module.add_submodule(dh::create_module(module.py())?)?; + #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] module.add_submodule(ed25519::create_module(module.py())?)?; #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] diff --git a/src/rust/src/backend/utils.rs b/src/rust/src/backend/utils.rs index 25b7a5b9f87e..072a80f5f73d 100644 --- a/src/rust/src/backend/utils.rs +++ b/src/rust/src/backend/utils.rs @@ -4,6 +4,39 @@ use crate::error::{CryptographyError, CryptographyResult}; +pub(crate) fn py_int_to_bn( + py: pyo3::Python<'_>, + v: &pyo3::PyAny, +) -> CryptographyResult { + let n = v + .call_method0(pyo3::intern!(py, "bit_length"))? + .extract::()? + / 8 + + 1; + let bytes: &[u8] = v + .call_method1(pyo3::intern!(py, "to_bytes"), (n, pyo3::intern!(py, "big")))? + .extract()?; + + Ok(openssl::bn::BigNum::from_slice(bytes)?) +} + +pub(crate) fn bn_to_py_int<'p>( + py: pyo3::Python<'p>, + b: &openssl::bn::BigNumRef, +) -> CryptographyResult<&'p pyo3::PyAny> { + assert!(!b.is_negative()); + + let int_type = py.get_type::(); + Ok(int_type.call_method1( + pyo3::intern!(py, "from_bytes"), + (b.to_vec(), pyo3::intern!(py, "big")), + )?) +} + +pub(crate) fn bn_to_big_endian_bytes(b: &openssl::bn::BigNumRef) -> CryptographyResult> { + Ok(b.to_vec_padded(b.num_bits() / 8 + 1)?) +} + pub(crate) fn pkey_private_bytes<'p>( py: pyo3::Python<'p>, key_obj: &pyo3::PyAny, @@ -23,6 +56,9 @@ pub(crate) fn pkey_private_bytes<'p>( let private_format_class: &pyo3::types::PyType = serialization_mod .getattr(pyo3::intern!(py, "PrivateFormat"))? .extract()?; + let key_serialization_encryption_class: &pyo3::types::PyType = serialization_mod + .getattr(pyo3::intern!(py, "KeySerializationEncryption"))? + .extract()?; let no_encryption_class: &pyo3::types::PyType = serialization_mod .getattr(pyo3::intern!(py, "NoEncryption"))? .extract()?; @@ -44,7 +80,15 @@ pub(crate) fn pkey_private_bytes<'p>( ), )); } + if !encryption_algorithm.is_instance(key_serialization_encryption_class)? { + return Err(CryptographyError::from( + pyo3::exceptions::PyTypeError::new_err( + "Encryption algorithm must be a KeySerializationEncryption instance", + ), + )); + } + #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] if encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) || format.is(private_format_class.getattr(pyo3::intern!(py, "Raw"))?) { @@ -68,9 +112,7 @@ pub(crate) fn pkey_private_bytes<'p>( .extract::<&[u8]>()? } else { return Err(CryptographyError::from( - pyo3::exceptions::PyTypeError::new_err( - "Encryption algorithm must be a KeySerializationEncryption instance", - ), + pyo3::exceptions::PyValueError::new_err("Unsupported encryption type"), )); }; @@ -170,6 +212,7 @@ pub(crate) fn pkey_public_bytes<'p>( )); } + #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] if encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) || format.is(public_format_class.getattr(pyo3::intern!(py, "Raw"))?) { diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 27a0b95286ce..c8fa1efa21f5 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -13,7 +13,7 @@ from cryptography.hazmat.backends.openssl.backend import backend from cryptography.hazmat.backends.openssl.ec import _sn_to_elliptic_curve from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import dh, padding +from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import CBC @@ -27,7 +27,6 @@ ) from ...hazmat.primitives.test_rsa import rsa_key_512, rsa_key_2048 from ...utils import ( - load_nist_vectors, load_vectors_from_file, raises_unsupported_algorithm, ) @@ -373,36 +372,6 @@ def test_password_length_limit(self, rsa_key_2048): skip_message="Requires DH support", ) class TestOpenSSLDHSerialization: - @pytest.mark.parametrize( - "vector", - load_vectors_from_file( - os.path.join("asymmetric", "DH", "RFC5114.txt"), load_nist_vectors - ), - ) - def test_dh_serialization_with_q_unsupported(self, backend, vector): - parameters = dh.DHParameterNumbers( - int(vector["p"], 16), int(vector["g"], 16), int(vector["q"], 16) - ) - public = dh.DHPublicNumbers(int(vector["ystatcavs"], 16), parameters) - private = dh.DHPrivateNumbers(int(vector["xstatcavs"], 16), public) - private_key = private.private_key(backend) - public_key = private_key.public_key() - with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): - private_key.private_bytes( - serialization.Encoding.PEM, - serialization.PrivateFormat.PKCS8, - serialization.NoEncryption(), - ) - with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): - public_key.public_bytes( - serialization.Encoding.PEM, - serialization.PublicFormat.SubjectPublicKeyInfo, - ) - with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): - parameters.parameters(backend).parameter_bytes( - serialization.Encoding.PEM, serialization.ParameterFormat.PKCS3 - ) - @pytest.mark.parametrize( ("key_path", "loader_func"), [ diff --git a/tests/hazmat/primitives/test_dh.py b/tests/hazmat/primitives/test_dh.py index d47739ac07e8..098d6e142b24 100644 --- a/tests/hazmat/primitives/test_dh.py +++ b/tests/hazmat/primitives/test_dh.py @@ -148,7 +148,7 @@ def test_unsupported_generator_generate_dh(self, backend): with pytest.raises(ValueError): dh.generate_parameters(7, 512, backend) - def test_large_key_generate_dh(self): + def test_large_key_generate_dh(self, backend): with pytest.raises(ValueError): dh.generate_parameters(2, 1 << 30) @@ -486,6 +486,9 @@ def test_public_key_equality(self, backend): assert key1 != key3 assert key1 != object() + with pytest.raises(TypeError): + key1 < key2 # type: ignore[operator] + @pytest.mark.supported( only_if=lambda backend: backend.dh_supported(), diff --git a/tests/hazmat/primitives/test_ed25519.py b/tests/hazmat/primitives/test_ed25519.py index 7f847078c345..4b47e0a1657f 100644 --- a/tests/hazmat/primitives/test_ed25519.py +++ b/tests/hazmat/primitives/test_ed25519.py @@ -15,6 +15,7 @@ Ed25519PublicKey, ) +from ...doubles import DummyKeySerializationEncryption from ...utils import load_vectors_from_file, raises_unsupported_algorithm @@ -156,18 +157,24 @@ def test_invalid_length_from_private_bytes(self, backend): def test_invalid_private_bytes(self, backend): key = Ed25519PrivateKey.generate() - with pytest.raises(ValueError): + with pytest.raises(TypeError): key.private_bytes( serialization.Encoding.Raw, serialization.PrivateFormat.Raw, None, # type: ignore[arg-type] ) + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.Raw, + serialization.PrivateFormat.Raw, + DummyKeySerializationEncryption(), + ) with pytest.raises(ValueError): key.private_bytes( serialization.Encoding.Raw, serialization.PrivateFormat.PKCS8, - None, # type: ignore[arg-type] + DummyKeySerializationEncryption(), ) with pytest.raises(ValueError): diff --git a/tests/hazmat/primitives/test_ed448.py b/tests/hazmat/primitives/test_ed448.py index e88d3dce2ccc..650cdda7997c 100644 --- a/tests/hazmat/primitives/test_ed448.py +++ b/tests/hazmat/primitives/test_ed448.py @@ -15,6 +15,7 @@ Ed448PublicKey, ) +from ...doubles import DummyKeySerializationEncryption from ...utils import ( load_nist_vectors, load_vectors_from_file, @@ -192,18 +193,24 @@ def test_invalid_length_from_private_bytes(self, backend): def test_invalid_private_bytes(self, backend): key = Ed448PrivateKey.generate() - with pytest.raises(ValueError): + with pytest.raises(TypeError): key.private_bytes( serialization.Encoding.Raw, serialization.PrivateFormat.Raw, None, # type: ignore[arg-type] ) + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.Raw, + serialization.PrivateFormat.Raw, + DummyKeySerializationEncryption(), + ) with pytest.raises(ValueError): key.private_bytes( serialization.Encoding.Raw, serialization.PrivateFormat.PKCS8, - None, # type: ignore[arg-type] + DummyKeySerializationEncryption(), ) with pytest.raises(ValueError): diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 59a141d3395a..58693a4912d2 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -395,6 +395,10 @@ def test_load_ec_public_key(self, backend): assert key.curve.name == "secp256r1" assert key.curve.key_size == 256 + @pytest.mark.supported( + only_if=lambda backend: backend.dh_supported(), + skip_message="DH not supported", + ) def test_wrong_parameters_format(self, backend): param_data = b"---- NOT A KEY ----\n" @@ -734,6 +738,10 @@ def test_wrong_public_format(self, backend): with pytest.raises(ValueError): load_pem_public_key(key_data, backend) + @pytest.mark.supported( + only_if=lambda backend: backend.dh_supported(), + skip_message="DH not supported", + ) def test_wrong_parameters_format(self, backend): param_data = b"---- NOT A KEY ----\n" diff --git a/tests/hazmat/primitives/test_x25519.py b/tests/hazmat/primitives/test_x25519.py index 21cc55edfc03..ae4f382bc487 100644 --- a/tests/hazmat/primitives/test_x25519.py +++ b/tests/hazmat/primitives/test_x25519.py @@ -15,6 +15,7 @@ X25519PublicKey, ) +from ...doubles import DummyKeySerializationEncryption from ...utils import ( load_nist_vectors, load_vectors_from_file, @@ -195,18 +196,24 @@ def test_invalid_length_from_private_bytes(self, backend): def test_invalid_private_bytes(self, backend): key = X25519PrivateKey.generate() - with pytest.raises(ValueError): + with pytest.raises(TypeError): key.private_bytes( serialization.Encoding.Raw, serialization.PrivateFormat.Raw, None, # type: ignore[arg-type] ) + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.Raw, + serialization.PrivateFormat.Raw, + DummyKeySerializationEncryption(), + ) with pytest.raises(ValueError): key.private_bytes( serialization.Encoding.Raw, serialization.PrivateFormat.PKCS8, - None, # type: ignore[arg-type] + DummyKeySerializationEncryption(), ) with pytest.raises(ValueError): diff --git a/tests/hazmat/primitives/test_x448.py b/tests/hazmat/primitives/test_x448.py index c9d92112b698..e2f840fa82fb 100644 --- a/tests/hazmat/primitives/test_x448.py +++ b/tests/hazmat/primitives/test_x448.py @@ -15,6 +15,7 @@ X448PublicKey, ) +from ...doubles import DummyKeySerializationEncryption from ...utils import ( load_nist_vectors, load_vectors_from_file, @@ -200,18 +201,24 @@ def test_invalid_length_from_private_bytes(self, backend): def test_invalid_private_bytes(self, backend): key = X448PrivateKey.generate() - with pytest.raises(ValueError): + with pytest.raises(TypeError): key.private_bytes( serialization.Encoding.Raw, serialization.PrivateFormat.Raw, None, # type: ignore[arg-type] ) + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.Raw, + serialization.PrivateFormat.Raw, + DummyKeySerializationEncryption(), + ) with pytest.raises(ValueError): key.private_bytes( serialization.Encoding.Raw, serialization.PrivateFormat.PKCS8, - None, # type: ignore[arg-type] + DummyKeySerializationEncryption(), ) with pytest.raises(ValueError): From bb16b2a7d74978c4d02cfb43823a413b1ec79410 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 24 Apr 2023 21:36:01 -0600 Subject: [PATCH 186/316] Convert KDFs to Rust (#8787) --- .../hazmat/backends/openssl/backend.py | 60 ------------------- .../bindings/_rust/openssl/__init__.pyi | 2 + .../hazmat/bindings/_rust/openssl/kdf.pyi | 22 +++++++ .../hazmat/primitives/kdf/pbkdf2.py | 10 ++-- .../hazmat/primitives/kdf/scrypt.py | 12 +++- src/rust/src/backend/kdf.rs | 60 +++++++++++++++++++ src/rust/src/backend/mod.rs | 2 + 7 files changed, 99 insertions(+), 69 deletions(-) create mode 100644 src/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi create mode 100644 src/rust/src/backend/kdf.rs diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index c8e1b81a218c..9360fee7ab31 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -85,7 +85,6 @@ XTS, Mode, ) -from cryptography.hazmat.primitives.kdf import scrypt from cryptography.hazmat.primitives.serialization import ssh from cryptography.hazmat.primitives.serialization.pkcs12 import ( PBES, @@ -365,30 +364,6 @@ def create_symmetric_decryption_ctx( def pbkdf2_hmac_supported(self, algorithm: hashes.HashAlgorithm) -> bool: return self.hmac_supported(algorithm) - def derive_pbkdf2_hmac( - self, - algorithm: hashes.HashAlgorithm, - length: int, - salt: bytes, - iterations: int, - key_material: bytes, - ) -> bytes: - buf = self._ffi.new("unsigned char[]", length) - evp_md = self._evp_md_non_null_from_algorithm(algorithm) - key_material_ptr = self._ffi.from_buffer(key_material) - res = self._lib.PKCS5_PBKDF2_HMAC( - key_material_ptr, - len(key_material), - salt, - len(salt), - iterations, - evp_md, - length, - buf, - ) - self.openssl_assert(res == 1) - return self._ffi.buffer(buf)[:] - def _consume_errors(self) -> typing.List[rust_openssl.OpenSSLError]: return rust_openssl.capture_error_stack() @@ -1703,41 +1678,6 @@ def ed448_load_private_bytes(self, data: bytes) -> ed448.Ed448PrivateKey: def ed448_generate_key(self) -> ed448.Ed448PrivateKey: return rust_openssl.ed448.generate_key() - def derive_scrypt( - self, - key_material: bytes, - salt: bytes, - length: int, - n: int, - r: int, - p: int, - ) -> bytes: - buf = self._ffi.new("unsigned char[]", length) - key_material_ptr = self._ffi.from_buffer(key_material) - res = self._lib.EVP_PBE_scrypt( - key_material_ptr, - len(key_material), - salt, - len(salt), - n, - r, - p, - scrypt._MEM_LIMIT, - buf, - length, - ) - if res != 1: - errors = self._consume_errors() - # memory required formula explained here: - # https://blog.filippo.io/the-scrypt-parameters/ - min_memory = 128 * n * r // (1024**2) - raise MemoryError( - "Not enough memory to derive key. These parameters require" - " {} MB of memory.".format(min_memory), - errors, - ) - return self._ffi.buffer(buf)[:] - def aead_cipher_supported(self, cipher) -> bool: cipher_name = aead._aead_cipher_name(cipher) if self._fips_enabled and cipher_name not in self._fips_aead: diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi index bfa641259854..3b43036ce15d 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -10,6 +10,7 @@ from cryptography.hazmat.bindings._rust.openssl import ( ed25519, hashes, hmac, + kdf, x448, x25519, ) @@ -20,6 +21,7 @@ __all__ = [ "dh", "hashes", "hmac", + "kdf", "ed448", "ed25519", "x448", diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi new file mode 100644 index 000000000000..034a8fed2e78 --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi @@ -0,0 +1,22 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives.hashes import HashAlgorithm + +def derive_pbkdf2_hmac( + key_material: bytes, + algorithm: HashAlgorithm, + salt: bytes, + iterations: int, + length: int, +) -> bytes: ... +def derive_scrypt( + key_material: bytes, + salt: bytes, + n: int, + r: int, + p: int, + max_mem: int, + length: int, +) -> bytes: ... diff --git a/src/cryptography/hazmat/primitives/kdf/pbkdf2.py b/src/cryptography/hazmat/primitives/kdf/pbkdf2.py index 2caa50e80a19..623e1ca7f9eb 100644 --- a/src/cryptography/hazmat/primitives/kdf/pbkdf2.py +++ b/src/cryptography/hazmat/primitives/kdf/pbkdf2.py @@ -13,6 +13,7 @@ UnsupportedAlgorithm, _Reasons, ) +from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives import constant_time, hashes from cryptography.hazmat.primitives.kdf import KeyDerivationFunction @@ -49,15 +50,12 @@ def derive(self, key_material: bytes) -> bytes: raise AlreadyFinalized("PBKDF2 instances can only be used once.") self._used = True - utils._check_byteslike("key_material", key_material) - from cryptography.hazmat.backends.openssl.backend import backend - - return backend.derive_pbkdf2_hmac( + return rust_openssl.kdf.derive_pbkdf2_hmac( + key_material, self._algorithm, - self._length, self._salt, self._iterations, - key_material, + self._length, ) def verify(self, key_material: bytes, expected_key: bytes) -> None: diff --git a/src/cryptography/hazmat/primitives/kdf/scrypt.py b/src/cryptography/hazmat/primitives/kdf/scrypt.py index 6443832aa382..05a4f675b6ab 100644 --- a/src/cryptography/hazmat/primitives/kdf/scrypt.py +++ b/src/cryptography/hazmat/primitives/kdf/scrypt.py @@ -13,6 +13,7 @@ InvalidKey, UnsupportedAlgorithm, ) +from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives import constant_time from cryptography.hazmat.primitives.kdf import KeyDerivationFunction @@ -62,10 +63,15 @@ def derive(self, key_material: bytes) -> bytes: self._used = True utils._check_byteslike("key_material", key_material) - from cryptography.hazmat.backends.openssl.backend import backend - return backend.derive_scrypt( - key_material, self._salt, self._length, self._n, self._r, self._p + return rust_openssl.kdf.derive_scrypt( + key_material, + self._salt, + self._n, + self._r, + self._p, + _MEM_LIMIT, + self._length, ) def verify(self, key_material: bytes, expected_key: bytes) -> None: diff --git a/src/rust/src/backend/kdf.rs b/src/rust/src/backend/kdf.rs new file mode 100644 index 000000000000..5bd5606c9f1b --- /dev/null +++ b/src/rust/src/backend/kdf.rs @@ -0,0 +1,60 @@ +// 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::backend::hashes; +use crate::buf::CffiBuf; +use crate::error::CryptographyResult; + +#[pyo3::prelude::pyfunction] +fn derive_pbkdf2_hmac<'p>( + py: pyo3::Python<'p>, + key_material: CffiBuf<'_>, + algorithm: &pyo3::PyAny, + salt: &[u8], + iterations: usize, + length: usize, +) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let md = hashes::message_digest_from_algorithm(py, algorithm)?; + + Ok(pyo3::types::PyBytes::new_with(py, length, |b| { + openssl::pkcs5::pbkdf2_hmac(key_material.as_bytes(), salt, iterations, md, b).unwrap(); + Ok(()) + })?) +} + +#[cfg(not(CRYPTOGRAPHY_IS_LIBRESSL))] +#[pyo3::prelude::pyfunction] +#[allow(clippy::too_many_arguments)] +fn derive_scrypt<'p>( + py: pyo3::Python<'p>, + key_material: CffiBuf<'_>, + salt: &[u8], + n: u64, + r: u64, + p: u64, + max_mem: u64, + length: usize, +) -> CryptographyResult<&'p pyo3::types::PyBytes> { + Ok(pyo3::types::PyBytes::new_with(py, length, |b| { + openssl::pkcs5::scrypt(key_material.as_bytes(), salt, n, r, p, max_mem, b).map_err(|_| { + // memory required formula explained here: + // https://blog.filippo.io/the-scrypt-parameters/ + let min_memory = 128 * n * r / (1024 * 1024); + pyo3::exceptions::PyMemoryError::new_err(format!( + "Not enough memory to derive key. These parameters require {}MB of memory.", + min_memory + )) + }) + })?) +} + +pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let m = pyo3::prelude::PyModule::new(py, "kdf")?; + + m.add_wrapped(pyo3::wrap_pyfunction!(derive_pbkdf2_hmac))?; + #[cfg(not(CRYPTOGRAPHY_IS_LIBRESSL))] + m.add_wrapped(pyo3::wrap_pyfunction!(derive_scrypt))?; + + Ok(m) +} diff --git a/src/rust/src/backend/mod.rs b/src/rust/src/backend/mod.rs index a38d39287ee2..e52b149e38ef 100644 --- a/src/rust/src/backend/mod.rs +++ b/src/rust/src/backend/mod.rs @@ -9,6 +9,7 @@ pub(crate) mod ed25519; pub(crate) mod ed448; pub(crate) mod hashes; pub(crate) mod hmac; +pub(crate) mod kdf; pub(crate) mod utils; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] pub(crate) mod x25519; @@ -30,6 +31,7 @@ pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult< module.add_submodule(hashes::create_module(module.py())?)?; module.add_submodule(hmac::create_module(module.py())?)?; + module.add_submodule(kdf::create_module(module.py())?)?; Ok(()) } From 6bd393ea837ee062acdc1d66eca6c12c91fc76e6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 24 Apr 2023 21:51:05 -0600 Subject: [PATCH 187/316] Move is_fips logic to Rust (#8822) --- .../hazmat/backends/openssl/backend.py | 19 ++--------- .../bindings/_rust/openssl/__init__.pyi | 1 + src/rust/cryptography-openssl/build.rs | 24 ++++++++++++++ src/rust/cryptography-openssl/src/fips.rs | 32 +++++++++++++++++++ src/rust/cryptography-openssl/src/lib.rs | 1 + src/rust/src/lib.rs | 6 ++++ 6 files changed, 67 insertions(+), 16 deletions(-) create mode 100644 src/rust/cryptography-openssl/build.rs create mode 100644 src/rust/cryptography-openssl/src/fips.rs diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 9360fee7ab31..28f75cb94f88 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -156,7 +156,7 @@ def __init__(self) -> None: self._binding = binding.Binding() self._ffi = self._binding.ffi self._lib = self._binding.lib - self._fips_enabled = self._is_fips_enabled() + self._fips_enabled = rust_openssl.is_fips_enabled() self._cipher_registry: typing.Dict[ typing.Tuple[typing.Type[CipherAlgorithm], typing.Type[Mode]], @@ -181,25 +181,12 @@ def openssl_assert( ) -> None: return binding._openssl_assert(self._lib, ok, errors=errors) - def _is_fips_enabled(self) -> bool: - if self._lib.Cryptography_HAS_300_FIPS: - mode = self._lib.EVP_default_properties_is_fips_enabled( - self._ffi.NULL - ) - else: - mode = self._lib.FIPS_mode() - - 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) -> None: # 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() + assert rust_openssl.is_fips_enabled() + self._fips_enabled = rust_openssl.is_fips_enabled() def openssl_version_text(self) -> str: """ diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi index 3b43036ce15d..6712fff2755b 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -31,6 +31,7 @@ __all__ = [ def openssl_version() -> int: ... def raise_openssl_error() -> typing.NoReturn: ... def capture_error_stack() -> typing.List[OpenSSLError]: ... +def is_fips_enabled() -> bool: ... class OpenSSLError: @property diff --git a/src/rust/cryptography-openssl/build.rs b/src/rust/cryptography-openssl/build.rs new file mode 100644 index 000000000000..a0b4566a753c --- /dev/null +++ b/src/rust/cryptography-openssl/build.rs @@ -0,0 +1,24 @@ +// 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 std::env; + +#[allow(clippy::unusual_byte_groupings)] +fn main() { + if let Ok(version) = env::var("DEP_OPENSSL_VERSION_NUMBER") { + let version = u64::from_str_radix(&version, 16).unwrap(); + + if version >= 0x3_00_00_00_0 { + println!("cargo:rustc-cfg=CRYPTOGRAPHY_OPENSSL_300_OR_GREATER"); + } + } + + if env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER").is_ok() { + println!("cargo:rustc-cfg=CRYPTOGRAPHY_IS_LIBRESSL"); + } + + if env::var("DEP_OPENSSL_BORINGSSL").is_ok() { + println!("cargo:rustc-cfg=CRYPTOGRAPHY_IS_BORINGSSL"); + } +} diff --git a/src/rust/cryptography-openssl/src/fips.rs b/src/rust/cryptography-openssl/src/fips.rs new file mode 100644 index 000000000000..29c4c789d838 --- /dev/null +++ b/src/rust/cryptography-openssl/src/fips.rs @@ -0,0 +1,32 @@ +// 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. + +#[cfg(all( + CRYPTOGRAPHY_OPENSSL_300_OR_GREATER, + not(any(CRYPTOGRAPHY_IS_LIBRESSL, CRYPTOGRAPHY_IS_BORINGSSL)) +))] +use std::ptr; + +pub fn is_enabled() -> bool { + #[cfg(any(CRYPTOGRAPHY_IS_LIBRESSL, CRYPTOGRAPHY_IS_BORINGSSL))] + { + return false; + } + + #[cfg(all( + CRYPTOGRAPHY_OPENSSL_300_OR_GREATER, + not(any(CRYPTOGRAPHY_IS_LIBRESSL, CRYPTOGRAPHY_IS_BORINGSSL)) + ))] + unsafe { + ffi::EVP_default_properties_is_fips_enabled(ptr::null_mut()) == 1 + } + + #[cfg(all( + not(CRYPTOGRAPHY_OPENSSL_300_OR_GREATER), + not(any(CRYPTOGRAPHY_IS_LIBRESSL, CRYPTOGRAPHY_IS_BORINGSSL)) + ))] + { + return openssl::fips::enabled(); + } +} diff --git a/src/rust/cryptography-openssl/src/lib.rs b/src/rust/cryptography-openssl/src/lib.rs index fcc2ff1a585b..0a2b48149e0f 100644 --- a/src/rust/cryptography-openssl/src/lib.rs +++ b/src/rust/cryptography-openssl/src/lib.rs @@ -2,6 +2,7 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. +pub mod fips; pub mod hmac; pub type OpenSSLResult = Result; diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 95df2fa3c852..4d88e2813b50 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -131,6 +131,11 @@ fn capture_error_stack(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::types::PyL Ok(errs) } +#[pyo3::prelude::pyfunction] +fn is_fips_enabled() -> bool { + cryptography_openssl::fips::is_enabled() +} + #[pyo3::prelude::pymodule] fn _rust(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { m.add_function(pyo3::wrap_pyfunction!(check_pkcs7_padding, m)?)?; @@ -161,6 +166,7 @@ fn _rust(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> openssl_mod.add_function(pyo3::wrap_pyfunction!(openssl_version, m)?)?; openssl_mod.add_function(pyo3::wrap_pyfunction!(raise_openssl_error, m)?)?; openssl_mod.add_function(pyo3::wrap_pyfunction!(capture_error_stack, m)?)?; + openssl_mod.add_function(pyo3::wrap_pyfunction!(is_fips_enabled, m)?)?; openssl_mod.add_class::()?; crate::backend::add_to_module(openssl_mod)?; m.add_submodule(openssl_mod)?; From cebbe78b1fa2a52c51f2abb8885447e8475d4400 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 13:11:05 +0000 Subject: [PATCH 188/316] Bump ruff from 0.0.262 to 0.0.263 (#8824) Bumps [ruff](https://github.com/charliermarsh/ruff) from 0.0.262 to 0.0.263. - [Release notes](https://github.com/charliermarsh/ruff/releases) - [Changelog](https://github.com/charliermarsh/ruff/blob/main/BREAKING_CHANGES.md) - [Commits](https://github.com/charliermarsh/ruff/compare/v0.0.262...v0.0.263) --- updated-dependencies: - dependency-name: ruff 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 2a38918e676d..843ed02a6d5e 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -136,7 +136,7 @@ rfc3986==2.0.0 # via twine rich==13.3.4 # via twine -ruff==0.0.262 +ruff==0.0.263 # via cryptography (pyproject.toml) six==1.16.0 # via bleach From e03d583dcb29c653074c160169c890ce01400511 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 13:12:11 +0000 Subject: [PATCH 189/316] Bump sphinx from 6.2.0 to 6.2.1 (#8825) Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 6.2.0 to 6.2.1. - [Release notes](https://github.com/sphinx-doc/sphinx/releases) - [Changelog](https://github.com/sphinx-doc/sphinx/blob/master/CHANGES) - [Commits](https://github.com/sphinx-doc/sphinx/compare/v6.2.0...v6.2.1) --- updated-dependencies: - dependency-name: sphinx 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 843ed02a6d5e..264417db4518 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -142,7 +142,7 @@ six==1.16.0 # via bleach snowballstemmer==2.2.0 # via sphinx -sphinx==6.2.0 +sphinx==6.2.1 # via # cryptography (pyproject.toml) # sphinx-rtd-theme From bb91e8b44950e909c6cfa56b9339ccbcc6c66bfe Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 25 Apr 2023 07:23:57 -0600 Subject: [PATCH 190/316] See if we can always enable abi3 (#8823) Previously it wasn't because pypy doesn't support abi3, but maybe the pyo3 feature works. --- setup.py | 6 ------ src/rust/Cargo.toml | 2 +- src/rust/cryptography-cffi/Cargo.toml | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index b05dc2f129c3..4fe0c027c17c 100644 --- a/setup.py +++ b/setup.py @@ -54,12 +54,6 @@ "cryptography.hazmat.bindings._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-py37"] - ), rust_version=">=1.56.0", ) ], diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index bb8f74a849b0..614bd9967e0a 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -9,7 +9,7 @@ rust-version = "1.56.0" [dependencies] once_cell = "1" -pyo3 = { version = "0.18" } +pyo3 = { version = "0.18", features = ["abi3-py37"] } asn1 = { version = "0.15.0", default-features = false } cryptography-cffi = { path = "cryptography-cffi" } cryptography-x509 = { path = "cryptography-x509" } diff --git a/src/rust/cryptography-cffi/Cargo.toml b/src/rust/cryptography-cffi/Cargo.toml index f9ae6bc2ed43..652e621e10a0 100644 --- a/src/rust/cryptography-cffi/Cargo.toml +++ b/src/rust/cryptography-cffi/Cargo.toml @@ -8,7 +8,7 @@ publish = false rust-version = "1.56.0" [dependencies] -pyo3 = { version = "0.18" } +pyo3 = { version = "0.18", features = ["abi3-py37"] } openssl-sys = "0.9.87" [build-dependencies] From 62ac9c2d474f157bc91f7dc9dee9551380e41bde Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 25 Apr 2023 12:58:06 -0600 Subject: [PATCH 191/316] Stop invoking setup.py in wheel builder (#8826) --- .github/workflows/wheel-builder.yml | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 90e29c960d92..f6040de26c84 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -105,16 +105,15 @@ jobs: - run: /opt/python/${{ matrix.PYTHON.VERSION }}/bin/python -m venv .venv - name: Install Python dependencies run: .venv/bin/pip install -U pip wheel cffi setuptools-rust - - run: tar zxvf cryptography*.tar.gz && rm cryptography*.tar.gz && mkdir tmpwheelhouse + - run: mkdir tmpwheelhouse - name: Build the wheel run: | if [ -n "${{ matrix.PYTHON.ABI_VERSION }}" ]; then - PY_LIMITED_API="--py-limited-api=${{ matrix.PYTHON.ABI_VERSION }}" + PY_LIMITED_API="--config-settings=--build-option=--py-limited-api=${{ matrix.PYTHON.ABI_VERSION }} --no-build-isolation" fi - cd cryptography* OPENSSL_DIR="/opt/pyca/cryptography/openssl" \ OPENSSL_STATIC=1 \ - ../.venv/bin/python setup.py bdist_wheel $PY_LIMITED_API && mv dist/cryptography*.whl ../tmpwheelhouse + .venv/bin/python -m pip wheel -v $PY_LIMITED_API cryptograph*.tar.gz -w dist/ && mv dist/cryptography*.whl tmpwheelhouse env: RUSTUP_HOME: /root/.rustup - run: auditwheel repair --plat ${{ matrix.MANYLINUX.NAME }} tmpwheelhouse/cryptograph*.whl -w wheelhouse/ @@ -211,18 +210,21 @@ jobs: - run: ${{ matrix.PYTHON.BIN_PATH }} -m venv venv - run: venv/bin/pip install -U pip wheel cffi setuptools-rust - - run: tar zxvf cryptography*.tar.gz && mkdir wheelhouse + - run: mkdir wheelhouse - name: Build the wheel run: | - cd cryptography* - OPENSSL_DIR="$(readlink -f ../../openssl-macos-universal2/)" \ + if [ -n "${{ matrix.PYTHON.ABI_VERSION }}" ]; then + PY_LIMITED_API="--config-settings=--build-option=--py-limited-api=${{ matrix.PYTHON.ABI_VERSION }} --no-build-isolation" + fi + + OPENSSL_DIR="$(readlink -f ../openssl-macos-universal2/)" \ OPENSSL_STATIC=1 \ - ../venv/bin/python setup.py bdist_wheel --py-limited-api=${{ matrix.PYTHON.ABI_VERSION }} && mv dist/cryptography*.whl ../wheelhouse + venv/bin/python -m pip wheel -v $PY_LIMITED_API cryptograph*.tar.gz -w dist/ && mv dist/cryptography*.whl wheelhouse env: MACOSX_DEPLOYMENT_TARGET: ${{ matrix.PYTHON.DEPLOYMENT_TARGET }} ARCHFLAGS: ${{ matrix.PYTHON.ARCHFLAGS }} _PYTHON_HOST_PLATFORM: ${{ matrix.PYTHON._PYTHON_HOST_PLATFORM }} - - run: venv/bin/pip install -f wheelhouse --no-index cryptography + - run: venv/bin/pip install -f wheelhouse/ --no-index cryptography - name: Show the wheel's minimum macOS SDK and architectures run: | find venv/lib/*/site-packages/cryptography/hazmat/bindings -name '*.so' -exec vtool -show {} \; @@ -290,9 +292,14 @@ jobs: - run: python -m pip install -U pip wheel - run: python -m pip install cffi setuptools-rust - - run: tar zxvf cryptography*.tar.gz && mkdir wheelhouse + - run: mkdir wheelhouse + - run: | + if [ -n "${{ matrix.PYTHON.ABI_VERSION }}" ]; then + PY_LIMITED_API="--config-settings=--build-option=--py-limited-api=${{ matrix.PYTHON.ABI_VERSION }} --no-build-isolation" + fi + + python -m pip wheel -v cryptography*.tar.gz $PY_LIMITED_API -w dist/ && mv dist/cryptography*.whl wheelhouse/ shell: bash - - run: cd cryptography* && python setup.py bdist_wheel --py-limited-api=${{ matrix.PYTHON.ABI_VERSION }} && mv dist/cryptography*.whl ../wheelhouse - run: pip install -f wheelhouse --no-index cryptography - name: Print the OpenSSL we built and linked against run: | From ea46011d713e7c539ac2e883eff20501eceb7725 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 25 Apr 2023 17:40:15 -0600 Subject: [PATCH 192/316] update macos wheel builder to use latest 3.11.x (#8827) --- .github/workflows/wheel-builder.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index f6040de26c84..c3e145a99a9f 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -146,7 +146,7 @@ jobs: - VERSION: '3.11' ABI_VERSION: 'cp37' # Despite the name, this is built for the macOS 11 SDK on arm64 and 10.9+ on intel - DOWNLOAD_URL: 'https://www.python.org/ftp/python/3.11.2/python-3.11.2-macos11.pkg' + DOWNLOAD_URL: 'https://www.python.org/ftp/python/3.11.3/python-3.11.3-macos11.pkg' BIN_PATH: '/Library/Frameworks/Python.framework/Versions/3.11/bin/python3' DEPLOYMENT_TARGET: '10.12' # This archflags is default, but let's be explicit @@ -157,7 +157,7 @@ jobs: _PYTHON_HOST_PLATFORM: 'macosx-10.9-universal2' - VERSION: '3.11' ABI_VERSION: 'cp37' - DOWNLOAD_URL: 'https://www.python.org/ftp/python/3.11.2/python-3.11.2-macos11.pkg' + DOWNLOAD_URL: 'https://www.python.org/ftp/python/3.11.3/python-3.11.3-macos11.pkg' BIN_PATH: '/Library/Frameworks/Python.framework/Versions/3.11/bin/python3' DEPLOYMENT_TARGET: '10.12' # We continue to build a non-universal2 for a bit to see metrics on From 3cb5ca7d4a16b9b15b462cbdb86b638f24c0e945 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Wed, 26 Apr 2023 00:15:36 +0000 Subject: [PATCH 193/316] Bump BoringSSL and/or OpenSSL in CI (#8829) Co-authored-by: pyca-boringbot[bot] --- .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 f37af412e70e..8835b2144d24 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 25, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "de2d610a341f5a4b8c222425890537cb84c91400"}} - # Latest commit on the OpenSSL master branch, as of Apr 25, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "24a322544373f7acda05e19f64a6c3120d459d5b"}} + # Latest commit on the BoringSSL master branch, as of Apr 26, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "d5f3a9e82fc6735eff5733f51b892d776f4a84eb"}} + # Latest commit on the OpenSSL master branch, as of Apr 26, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "fc374a087e7fc5a5bd243ea42ce9879e8432b20e"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From cd23d7ab13ff66e339dd357d0cdbb9b2ddb63bdb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Apr 2023 08:15:42 -0500 Subject: [PATCH 194/316] Bump platformdirs from 3.2.0 to 3.3.0 (#8831) Bumps [platformdirs](https://github.com/platformdirs/platformdirs) from 3.2.0 to 3.3.0. - [Release notes](https://github.com/platformdirs/platformdirs/releases) - [Changelog](https://github.com/platformdirs/platformdirs/blob/main/CHANGES.rst) - [Commits](https://github.com/platformdirs/platformdirs/compare/3.2.0...3.3.0) --- updated-dependencies: - dependency-name: platformdirs 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 264417db4518..12c6805fc382 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -87,7 +87,7 @@ pathspec==0.11.1 # via black pkginfo==1.9.6 # via twine -platformdirs==3.2.0 +platformdirs==3.3.0 # via # black # virtualenv From d78ecb8dc1095ae9101d32671183d7a9bed13acd Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 26 Apr 2023 09:17:14 -0400 Subject: [PATCH 195/316] Remove a bunch of unused bindings (#8830) Also replace one DH function with a simpler implementation --- src/_cffi_src/openssl/dh.py | 21 --------------- src/_cffi_src/openssl/evp.py | 11 -------- src/_cffi_src/openssl/pem.py | 5 ---- .../hazmat/backends/openssl/backend.py | 26 +++++-------------- .../hazmat/bindings/openssl/_conditional.py | 9 ------- 5 files changed, 7 insertions(+), 65 deletions(-) diff --git a/src/_cffi_src/openssl/dh.py b/src/_cffi_src/openssl/dh.py index 1a75b6d22879..b4a42e7f6058 100644 --- a/src/_cffi_src/openssl/dh.py +++ b/src/_cffi_src/openssl/dh.py @@ -15,29 +15,8 @@ """ FUNCTIONS = """ -DH *DH_new(void); void DH_free(DH *); -int DH_size(const DH *); -int DH_generate_key(DH *); -DH *DHparams_dup(DH *); - -void DH_get0_pqg(const DH *, const BIGNUM **, const BIGNUM **, - const BIGNUM **); -int DH_set0_pqg(DH *, BIGNUM *, BIGNUM *, BIGNUM *); -void DH_get0_key(const DH *, const BIGNUM **, const BIGNUM **); -int DH_set0_key(DH *, BIGNUM *, BIGNUM *); - -int DH_check(const DH *, int *); -int DH_generate_parameters_ex(DH *, int, int, BN_GENCB *); -DH *d2i_DHparams_bio(BIO *, DH **); -int i2d_DHparams_bio(BIO *, DH *); -DH *d2i_DHxparams_bio(BIO *, DH **); -int i2d_DHxparams_bio(BIO *, DH *); """ CUSTOMIZATIONS = """ -#if !(defined(EVP_PKEY_DHX) && EVP_PKEY_DHX != -1) -DH *(*d2i_DHxparams_bio)(BIO *bp, DH **x) = NULL; -int (*i2d_DHxparams_bio)(BIO *bp, DH *x) = NULL; -#endif """ diff --git a/src/_cffi_src/openssl/evp.py b/src/_cffi_src/openssl/evp.py index b22c2ac0f9fa..f1c367010398 100644 --- a/src/_cffi_src/openssl/evp.py +++ b/src/_cffi_src/openssl/evp.py @@ -67,7 +67,6 @@ int EVP_PKEY_size(EVP_PKEY *); RSA *EVP_PKEY_get1_RSA(EVP_PKEY *); DSA *EVP_PKEY_get1_DSA(EVP_PKEY *); -DH *EVP_PKEY_get1_DH(EVP_PKEY *); int EVP_PKEY_encrypt(EVP_PKEY_CTX *, unsigned char *, size_t *, const unsigned char *, size_t); @@ -131,15 +130,8 @@ int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *, int, int, void *); -int PKCS5_PBKDF2_HMAC(const char *, int, const unsigned char *, int, int, - const EVP_MD *, int, unsigned char *); - int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *, const EVP_MD *); -int EVP_PBE_scrypt(const char *, size_t, const unsigned char *, size_t, - uint64_t, uint64_t, uint64_t, uint64_t, unsigned char *, - size_t); - EVP_PKEY *EVP_PKEY_new_raw_private_key(int, ENGINE *, const unsigned char *, size_t); EVP_PKEY *EVP_PKEY_new_raw_public_key(int, ENGINE *, const unsigned char *, @@ -161,9 +153,6 @@ #if CRYPTOGRAPHY_IS_LIBRESSL || defined(OPENSSL_NO_SCRYPT) static const long Cryptography_HAS_SCRYPT = 0; -int (*EVP_PBE_scrypt)(const char *, size_t, const unsigned char *, size_t, - uint64_t, uint64_t, uint64_t, uint64_t, unsigned char *, - size_t) = NULL; #else static const long Cryptography_HAS_SCRYPT = 1; #endif diff --git a/src/_cffi_src/openssl/pem.py b/src/_cffi_src/openssl/pem.py index aac77ac71111..07f267199ad8 100644 --- a/src/_cffi_src/openssl/pem.py +++ b/src/_cffi_src/openssl/pem.py @@ -63,12 +63,7 @@ int PEM_write_bio_ECPrivateKey(BIO *, EC_KEY *, const EVP_CIPHER *, unsigned char *, int, pem_password_cb *, void *); -int PEM_write_bio_DHparams(BIO *, DH *); -int PEM_write_bio_DHxparams(BIO *, DH *); """ CUSTOMIZATIONS = """ -#if !defined(EVP_PKEY_DHX) || EVP_PKEY_DHX == -1 -int (*PEM_write_bio_DHxparams)(BIO *, DH *) = NULL; -#endif """ diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 28f75cb94f88..62b4659c87bf 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -1573,26 +1573,14 @@ def load_dh_parameter_numbers( def dh_parameters_supported( self, p: int, g: int, q: typing.Optional[int] = None ) -> bool: - dh_cdata = self._lib.DH_new() - self.openssl_assert(dh_cdata != self._ffi.NULL) - dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) - - p = self._int_to_bn(p) - g = self._int_to_bn(g) - - if q is not None: - q = self._int_to_bn(q) + try: + rust_openssl.dh.from_parameter_numbers( + dh.DHParameterNumbers(p=p, g=g, q=q) + ) + except ValueError: + return False else: - q = self._ffi.NULL - - res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) - self.openssl_assert(res == 1) - - codes = self._ffi.new("int[]", 1) - res = self._lib.DH_check(dh_cdata, codes) - self.openssl_assert(res == 1) - - return codes[0] == 0 + return True def dh_x942_serialization_supported(self) -> bool: return self._lib.Cryptography_HAS_EVP_PKEY_DHX == 1 diff --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py index 3130edd490ff..c09c9531280b 100644 --- a/src/cryptography/hazmat/bindings/openssl/_conditional.py +++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py @@ -30,17 +30,9 @@ def cryptography_has_tls_st() -> typing.List[str]: ] -def cryptography_has_scrypt() -> typing.List[str]: - return [ - "EVP_PBE_scrypt", - ] - - def cryptography_has_evp_pkey_dhx() -> typing.List[str]: return [ "EVP_PKEY_DHX", - "d2i_DHxparams_bio", - "i2d_DHxparams_bio", ] @@ -279,7 +271,6 @@ def cryptography_has_evp_pkey_set_peer_ex() -> typing.List[str]: "Cryptography_HAS_SET_CERT_CB": cryptography_has_set_cert_cb, "Cryptography_HAS_SSL_ST": cryptography_has_ssl_st, "Cryptography_HAS_TLS_ST": cryptography_has_tls_st, - "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_X509_STORE_CTX_GET_ISSUER": ( From 9d06775cb1db57ea4389dfeb95e9657d926cb81b Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 26 Apr 2023 09:21:39 -0400 Subject: [PATCH 196/316] Automate the version bump (#8828) --- docs/doing-a-release.rst | 5 ++-- pyproject.toml | 7 +++--- release.py | 47 +++++++++++++++++++++++++++++++++-- src/cryptography/__about__.py | 1 + 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/docs/doing-a-release.rst b/docs/doing-a-release.rst index c1571226e990..48e253ea4960 100644 --- a/docs/doing-a-release.rst +++ b/docs/doing-a-release.rst @@ -40,8 +40,7 @@ Bumping the version number The next step in doing a release is bumping the version number in the software. -* Update the version number in ``src/cryptography/__about__.py``. -* Update the version number in ``vectors/cryptography_vectors/__about__.py``. +* Run ``python release.py bump-version {new_version}`` * Set the release date in the :doc:`/changelog`. * Do a commit indicating this. * Send a pull request with this. @@ -54,7 +53,7 @@ The commit that merged the version number bump is now the official release commit for this release. You will need to have ``gpg`` installed and a ``gpg`` key in order to do a release. Once this has happened: -* Run ``python release.py {version}``. +* Run ``python release.py release {version}``. The release should now be available on PyPI and a tag should be available in the repository. diff --git a/pyproject.toml b/pyproject.toml index c66e0a38da40..782e6da4f5bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,6 +11,9 @@ build-backend = "setuptools.build_meta" [project] name = "cryptography" +version = "41.0.0.dev1" + + authors = [ {name = "The Python Cryptographic Authority and individual contributors", email = "cryptography-dev@python.org"} ] @@ -45,7 +48,6 @@ dependencies = [ # Must be kept in sync with `build-system.requires` "cffi >=1.12", ] -dynamic = ["version"] [project.urls] homepage = "https://github.com/pyca/cryptography" @@ -62,9 +64,6 @@ package-dir = {"" = "src"} where = ["src"] include = ["cryptography*"] -[tool.setuptools.dynamic] -version = {attr = "cryptography.__version__"} - [project.optional-dependencies] ssh = ["bcrypt >=3.1.5"] diff --git a/release.py b/release.py index 339eb0610a8c..9f41a82ec2e1 100644 --- a/release.py +++ b/release.py @@ -2,6 +2,8 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +import pathlib +import re import subprocess import click @@ -12,7 +14,12 @@ def run(*args: str) -> None: subprocess.check_call(list(args)) -@click.command() +@click.group() +def cli(): + pass + + +@cli.command() @click.argument("version") def release(version: str) -> None: """ @@ -23,5 +30,41 @@ def release(version: str) -> None: run("git", "push", "--tags") +def replace_version( + p: pathlib.Path, variable_name: str, new_version: str +) -> None: + with p.open() as f: + content = f.read() + + pattern = rf"^{variable_name}\s*=\s*.*$" + match = re.search(pattern, content, re.MULTILINE) + assert match is not None + + start, end = match.span() + new_content = ( + content[:start] + f'{variable_name} = "{new_version}"' + content[end:] + ) + + # Write back to file + with p.open("w") as f: + f.write(new_content) + + +@cli.command() +@click.argument("new_version") +def bump_version(new_version: str) -> None: + base_dir = pathlib.Path(__file__).parent + + replace_version(base_dir / "pyproject.toml", "version", new_version) + replace_version( + base_dir / "src/cryptography/__about__.py", "__version__", new_version + ) + replace_version( + base_dir / "vectors/cryptography_vectors/__about__.py", + "__version__", + new_version, + ) + + if __name__ == "__main__": - release() + cli() diff --git a/src/cryptography/__about__.py b/src/cryptography/__about__.py index 9ab3785b18f7..5a31e0ff9a59 100644 --- a/src/cryptography/__about__.py +++ b/src/cryptography/__about__.py @@ -12,5 +12,6 @@ __version__ = "41.0.0.dev1" + __author__ = "The Python Cryptographic Authority and individual contributors" __copyright__ = f"Copyright 2013-2023 {__author__}" From 0131d543bd6b8b9b2b724fa177d51f2bd48f57db Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 00:18:10 +0000 Subject: [PATCH 197/316] Bump BoringSSL and/or OpenSSL in CI (#8832) Co-authored-by: pyca-boringbot[bot] --- .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 8835b2144d24..d1e4ee9b2de5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 26, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "d5f3a9e82fc6735eff5733f51b892d776f4a84eb"}} - # Latest commit on the OpenSSL master branch, as of Apr 26, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "fc374a087e7fc5a5bd243ea42ce9879e8432b20e"}} + # Latest commit on the BoringSSL master branch, as of Apr 27, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "a02b7435ca52b81c7cce656d577c8423b1cc4bb3"}} + # Latest commit on the OpenSSL master branch, as of Apr 27, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "c48cc764ed57e49456d5b90a7d885e8af196df78"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 95019ef296a82de04b12811a3112afdc7bea9b73 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 15:39:41 +0200 Subject: [PATCH 198/316] Bump requests from 2.28.2 to 2.29.0 (#8836) Bumps [requests](https://github.com/psf/requests) from 2.28.2 to 2.29.0. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.28.2...v2.29.0) --- updated-dependencies: - dependency-name: requests 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 12c6805fc382..72953297476f 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -125,7 +125,7 @@ pytest-xdist==3.2.1 # via cryptography (pyproject.toml) readme-renderer==37.3 # via twine -requests==2.28.2 +requests==2.29.0 # via # requests-toolbelt # sphinx From 4956f31e2da3fb573e0a7e2b8324df6a55f53b82 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 15:40:54 +0200 Subject: [PATCH 199/316] Bump platformdirs from 3.3.0 to 3.4.0 (#8834) Bumps [platformdirs](https://github.com/platformdirs/platformdirs) from 3.3.0 to 3.4.0. - [Release notes](https://github.com/platformdirs/platformdirs/releases) - [Changelog](https://github.com/platformdirs/platformdirs/blob/main/CHANGES.rst) - [Commits](https://github.com/platformdirs/platformdirs/compare/3.3.0...3.4.0) --- updated-dependencies: - dependency-name: platformdirs 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 72953297476f..f27c88508aec 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -87,7 +87,7 @@ pathspec==0.11.1 # via black pkginfo==1.9.6 # via twine -platformdirs==3.3.0 +platformdirs==3.4.0 # via # black # virtualenv From a06e52e7d8499857c390629117ba5ff9c6eb9950 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 23:06:58 -0400 Subject: [PATCH 200/316] Bump BoringSSL and/or OpenSSL in CI (#8837) Co-authored-by: pyca-boringbot[bot] --- .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 d1e4ee9b2de5..b03206523e4d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,8 +43,8 @@ jobs: - {VERSION: "3.12-dev", NOXSESSION: "tests"} # Latest commit on the BoringSSL master branch, as of Apr 27, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "a02b7435ca52b81c7cce656d577c8423b1cc4bb3"}} - # Latest commit on the OpenSSL master branch, as of Apr 27, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "c48cc764ed57e49456d5b90a7d885e8af196df78"}} + # Latest commit on the OpenSSL master branch, as of Apr 28, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "57582450318e955632d8fb09f42bd90f2ed5d3b4"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From ad4c9031078657dded5bc6e32f110b1f4b993e11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Apr 2023 13:17:08 +0000 Subject: [PATCH 201/316] Bump virtualenv from 20.22.0 to 20.23.0 (#8838) Bumps [virtualenv](https://github.com/pypa/virtualenv) from 20.22.0 to 20.23.0. - [Release notes](https://github.com/pypa/virtualenv/releases) - [Changelog](https://github.com/pypa/virtualenv/blob/main/docs/changelog.rst) - [Commits](https://github.com/pypa/virtualenv/compare/20.22.0...20.23.0) --- updated-dependencies: - dependency-name: virtualenv 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index f27c88508aec..7aaf9827353e 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -183,7 +183,7 @@ urllib3==1.26.15 # via # requests # twine -virtualenv==20.22.0 +virtualenv==20.23.0 # via nox webencodings==0.5.1 # via bleach From f0bb028b9d86074255f5d4e1305cec45aea1f550 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Apr 2023 13:17:18 +0000 Subject: [PATCH 202/316] Bump coverage from 7.2.3 to 7.2.4 (#8840) Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.2.3 to 7.2.4. - [Release notes](https://github.com/nedbat/coveragepy/releases) - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst) - [Commits](https://github.com/nedbat/coveragepy/compare/7.2.3...7.2.4) --- updated-dependencies: - dependency-name: coverage 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 7aaf9827353e..4839099fb4ad 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -29,7 +29,7 @@ click==8.1.3 # via black colorlog==6.7.0 # via nox -coverage==7.2.3 +coverage==7.2.4 # via pytest-cov distlib==0.3.6 # via virtualenv From 752d912298275a7405c9aea9b03d518e0dfb40ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Apr 2023 13:17:29 +0000 Subject: [PATCH 203/316] Bump platformdirs from 3.4.0 to 3.5.0 (#8839) Bumps [platformdirs](https://github.com/platformdirs/platformdirs) from 3.4.0 to 3.5.0. - [Release notes](https://github.com/platformdirs/platformdirs/releases) - [Changelog](https://github.com/platformdirs/platformdirs/blob/main/CHANGES.rst) - [Commits](https://github.com/platformdirs/platformdirs/compare/3.4.0...3.5.0) --- updated-dependencies: - dependency-name: platformdirs 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 4839099fb4ad..16ad28848334 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -87,7 +87,7 @@ pathspec==0.11.1 # via black pkginfo==1.9.6 # via twine -platformdirs==3.4.0 +platformdirs==3.5.0 # via # black # virtualenv From d34d05c2104fc6913f4c58fa2fd52b8ffec0604c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Apr 2023 13:34:19 +0000 Subject: [PATCH 204/316] Bump rich from 13.3.4 to 13.3.5 (#8841) Bumps [rich](https://github.com/Textualize/rich) from 13.3.4 to 13.3.5. - [Release notes](https://github.com/Textualize/rich/releases) - [Changelog](https://github.com/Textualize/rich/blob/master/CHANGELOG.md) - [Commits](https://github.com/Textualize/rich/compare/v13.3.4...v13.3.5) --- updated-dependencies: - dependency-name: rich 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 16ad28848334..4a0b58c320de 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -134,7 +134,7 @@ requests-toolbelt==0.10.1 # via twine rfc3986==2.0.0 # via twine -rich==13.3.4 +rich==13.3.5 # via twine ruff==0.0.263 # via cryptography (pyproject.toml) From a703aaa14576ddd9d07fa0af6abd76b331f54625 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Fri, 28 Apr 2023 20:47:19 -0400 Subject: [PATCH 205/316] Bump BoringSSL and/or OpenSSL in CI (#8843) Co-authored-by: pyca-boringbot[bot] --- .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 b03206523e4d..20229b2b1be3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 27, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "a02b7435ca52b81c7cce656d577c8423b1cc4bb3"}} - # Latest commit on the OpenSSL master branch, as of Apr 28, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "57582450318e955632d8fb09f42bd90f2ed5d3b4"}} + # Latest commit on the BoringSSL master branch, as of Apr 29, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "9939e14cffc66f9b9f3374fb52c97bd8bfb0bfbe"}} + # Latest commit on the OpenSSL master branch, as of Apr 29, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "b5a635dc2113e1bc807ea358a670146c813df989"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From ac939ffb493667d00cb5d3f8233234df45f8770c Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 29 Apr 2023 15:19:52 +0200 Subject: [PATCH 206/316] move ASN1DHParams to cryptography_x509::common (#8844) --- src/rust/cryptography-x509/src/common.rs | 7 +++++++ src/rust/src/backend/dh.rs | 12 +++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs index edae5d4a40bd..122b37b6a7e6 100644 --- a/src/rust/cryptography-x509/src/common.rs +++ b/src/rust/cryptography-x509/src/common.rs @@ -123,6 +123,13 @@ pub struct DssSignature<'a> { pub s: asn1::BigUint<'a>, } +#[derive(asn1::Asn1Read, asn1::Asn1Write)] +pub struct DHParams<'a> { + pub p: asn1::BigUint<'a>, + pub g: asn1::BigUint<'a>, + pub q: Option>, +} + #[cfg(test)] mod tests { use super::{Asn1ReadableOrWritable, RawTlv}; diff --git a/src/rust/src/backend/dh.rs b/src/rust/src/backend/dh.rs index 33e94f1c204d..2daff9dcb656 100644 --- a/src/rust/src/backend/dh.rs +++ b/src/rust/src/backend/dh.rs @@ -6,6 +6,7 @@ use crate::asn1::encode_der_data; use crate::backend::utils; use crate::error::{CryptographyError, CryptographyResult}; use crate::x509; +use cryptography_x509::common; use foreign_types_shared::ForeignTypeRef; const MIN_MODULUS_SIZE: u32 = 512; @@ -62,16 +63,9 @@ fn public_key_from_ptr(ptr: usize) -> DHPublicKey { } } -#[derive(asn1::Asn1Read, asn1::Asn1Write)] -struct ASN1DHParams<'a> { - p: asn1::BigUint<'a>, - g: asn1::BigUint<'a>, - q: Option>, -} - #[pyo3::prelude::pyfunction] fn from_der_parameters(data: &[u8]) -> CryptographyResult { - let asn1_params = asn1::parse_single::>(data)?; + let asn1_params = asn1::parse_single::>(data)?; let p = openssl::bn::BigNum::from_slice(asn1_params.p.as_bytes())?; let q = asn1_params @@ -407,7 +401,7 @@ impl DHParameters { .map(utils::bn_to_big_endian_bytes) .transpose()?; let g_bytes = utils::bn_to_big_endian_bytes(self.dh.generator())?; - let asn1dh_params = ASN1DHParams { + let asn1dh_params = common::DHParams { p: asn1::BigUint::new(&p_bytes).unwrap(), q: q_bytes.as_ref().map(|q| asn1::BigUint::new(q).unwrap()), g: asn1::BigUint::new(&g_bytes).unwrap(), From 828bcf36d624c2de3ed30da9445741c8369d2b7f Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 30 Apr 2023 02:11:30 -0400 Subject: [PATCH 207/316] Remove pointless newlines that snuck in (#8845) --- pyproject.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 782e6da4f5bd..9c01f84e3b5a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,8 +12,6 @@ build-backend = "setuptools.build_meta" [project] name = "cryptography" version = "41.0.0.dev1" - - authors = [ {name = "The Python Cryptographic Authority and individual contributors", email = "cryptography-dev@python.org"} ] From be18c839856a9b2af4381fef70694d581b1262fb Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 30 Apr 2023 12:14:28 -0400 Subject: [PATCH 208/316] Switch from check-manifest to check-sdist (#8846) The latter will work with non-setuptools build backends. --- ci-constraints-requirements.txt | 9 +++++---- noxfile.py | 2 +- pyproject.toml | 11 ++++++++++- src/_cffi_src/build_openssl.py | 2 +- src/_cffi_src/utils.py | 13 +++++++------ 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 4a0b58c320de..3bae95b92635 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -17,13 +17,13 @@ bleach==6.0.0 # via readme-renderer build==0.10.0 # via - # check-manifest + # check-sdist # cryptography (pyproject.toml) certifi==2022.12.7 # via requests charset-normalizer==3.1.0 # via requests -check-manifest==0.49 +check-sdist==0.1.2 # via cryptography (pyproject.toml) click==8.1.3 # via black @@ -84,7 +84,9 @@ packaging==23.1 # pytest # sphinx pathspec==0.11.1 - # via black + # via + # black + # check-sdist pkginfo==1.9.6 # via twine platformdirs==3.5.0 @@ -193,4 +195,3 @@ zipp==3.15.0 # The following packages are considered to be unsafe in a requirements file: # cffi # pycparser -# setuptools diff --git a/noxfile.py b/noxfile.py index 8f1b94a500fb..8c9cc218b56b 100644 --- a/noxfile.py +++ b/noxfile.py @@ -125,7 +125,7 @@ def flake(session: nox.Session) -> None: session.run("ruff", ".") session.run("black", "--check", ".") - session.run("check-manifest") + session.run("check-sdist") session.run( "mypy", "src/cryptography/", diff --git a/pyproject.toml b/pyproject.toml index 9c01f84e3b5a..6f786bdb7e9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,7 +78,7 @@ test-randomorder = ["pytest-randomly"] docs = ["sphinx >=5.3.0", "sphinx-rtd-theme >=1.1.1"] docstest = ["pyenchant >=1.6.11", "twine >=1.12.0", "sphinxcontrib-spelling >=4.0.1"] sdist = ["build"] -pep8test = ["black", "ruff", "mypy", "check-manifest"] +pep8test = ["black", "ruff", "mypy", "check-sdist"] [tool.black] line-length = 79 @@ -143,3 +143,12 @@ line-length = 79 [tool.ruff.isort] known-first-party = ["cryptography", "cryptography_vectors", "tests"] + +[tool.check-sdist] +git-only = [ + "vectors/*", + "release.py", + "ci-constraints-requirements.txt", + ".gitattributes", + ".gitignore", +] \ No newline at end of file diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py index e199329db606..019789441431 100644 --- a/src/_cffi_src/build_openssl.py +++ b/src/_cffi_src/build_openssl.py @@ -54,7 +54,7 @@ ) if __name__ == "__main__": - out_dir = os.getenv("OUT_DIR") + out_dir = os.environ["OUT_DIR"] module_name, source, source_extension, kwds = ffi._assigned_source c_file = os.path.join(out_dir, module_name + source_extension) if platform.python_implementation() == "PyPy": diff --git a/src/_cffi_src/utils.py b/src/_cffi_src/utils.py index 9eb782686eae..b5fba37091d9 100644 --- a/src/_cffi_src/utils.py +++ b/src/_cffi_src/utils.py @@ -7,6 +7,7 @@ import os import platform import sys +import typing from cffi import FFI @@ -18,9 +19,9 @@ def build_ffi_for_binding( - module_name, - module_prefix, - modules, + module_name: str, + module_prefix: str, + modules: typing.List[str], ): """ Modules listed in ``modules`` should have the following attributes: @@ -54,9 +55,9 @@ def build_ffi_for_binding( def build_ffi( - module_name, - cdef_source, - verify_source, + module_name: str, + cdef_source: str, + verify_source: str, ): ffi = FFI() # Always add the CRYPTOGRAPHY_PACKAGE_VERSION to the shared object From e71d269a9a4f5e3859298ba9b9db686f334f2f5a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 30 Apr 2023 16:45:19 -0400 Subject: [PATCH 209/316] Remove manual fix for twisted in CI (#8847) --- .github/downstream.d/twisted.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/downstream.d/twisted.sh b/.github/downstream.d/twisted.sh index f8f294970507..9fc195ba7552 100755 --- a/.github/downstream.d/twisted.sh +++ b/.github/downstream.d/twisted.sh @@ -5,7 +5,7 @@ case "${1}" in git clone --depth=1 https://github.com/twisted/twisted cd twisted git rev-parse HEAD - pip install ".[all_non_platform]" "pyasn1!=0.5.0" + pip install ".[all_non_platform]" ;; run) cd twisted From 11a01d4392fd4dd82fbafd4d11d8178c39bf043b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 May 2023 02:41:41 +0000 Subject: [PATCH 210/316] Bump coverage from 7.2.4 to 7.2.5 (#8848) Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.2.4 to 7.2.5. - [Release notes](https://github.com/nedbat/coveragepy/releases) - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst) - [Commits](https://github.com/nedbat/coveragepy/compare/7.2.4...7.2.5) --- updated-dependencies: - dependency-name: coverage 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 3bae95b92635..bec914a8c939 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -29,7 +29,7 @@ click==8.1.3 # via black colorlog==6.7.0 # via nox -coverage==7.2.4 +coverage==7.2.5 # via pytest-cov distlib==0.3.6 # via virtualenv From 12e0f0bcc64d31a830c0c158dfe71dbf4df70564 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 May 2023 11:34:59 +0000 Subject: [PATCH 211/316] Bump requests-toolbelt from 0.10.1 to 1.0.0 (#8851) Bumps [requests-toolbelt](https://github.com/requests/toolbelt) from 0.10.1 to 1.0.0. - [Release notes](https://github.com/requests/toolbelt/releases) - [Changelog](https://github.com/requests/toolbelt/blob/master/HISTORY.rst) - [Commits](https://github.com/requests/toolbelt/compare/0.10.1...1.0.0) --- updated-dependencies: - dependency-name: requests-toolbelt dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index bec914a8c939..f1eb0318d594 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -132,7 +132,7 @@ requests==2.29.0 # requests-toolbelt # sphinx # twine -requests-toolbelt==0.10.1 +requests-toolbelt==1.0.0 # via twine rfc3986==2.0.0 # via twine From ac2060b57174f0791f639aa9bf3f382217239b68 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 00:20:32 +0000 Subject: [PATCH 212/316] Bump BoringSSL and/or OpenSSL in CI (#8852) Co-authored-by: pyca-boringbot[bot] --- .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 20229b2b1be3..0b9658163e06 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of Apr 29, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "9939e14cffc66f9b9f3374fb52c97bd8bfb0bfbe"}} - # Latest commit on the OpenSSL master branch, as of Apr 29, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "b5a635dc2113e1bc807ea358a670146c813df989"}} + # Latest commit on the BoringSSL master branch, as of May 02, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "86ada1ea2f51ff41baa2919337e5d721bd27f764"}} + # Latest commit on the OpenSSL master branch, as of May 02, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "1009940c14716ac03d5f161bdb4ae626ec6fe729"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 07dc182728f2dc25dc31ff3c1053f5b118ba6ca1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 13:12:55 +0000 Subject: [PATCH 213/316] Bump peter-evans/create-pull-request from 5.0.0 to 5.0.1 (#8856) Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 5.0.0 to 5.0.1. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/5b4a9f6a9e2af26e5f02351490b90d01eb8ec1e5...284f54f989303d2699d373481a0cfa13ad5a6666) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request 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/boring-open-version-bump.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/boring-open-version-bump.yml b/.github/workflows/boring-open-version-bump.yml index c2625a51b801..0c0036e11cac 100644 --- a/.github/workflows/boring-open-version-bump.yml +++ b/.github/workflows/boring-open-version-bump.yml @@ -58,7 +58,7 @@ jobs: private_key: ${{ secrets.BORINGBOT_PRIVATE_KEY }} if: steps.check-sha-boring.outputs.COMMIT_SHA || steps.check-sha-openssl.outputs.COMMIT_SHA - name: Create Pull Request - uses: peter-evans/create-pull-request@5b4a9f6a9e2af26e5f02351490b90d01eb8ec1e5 + uses: peter-evans/create-pull-request@284f54f989303d2699d373481a0cfa13ad5a6666 with: commit-message: "Bump BoringSSL and/or OpenSSL in CI" title: "Bump BoringSSL and/or OpenSSL in CI" From 0c0c3fabf2a2bd66e38d6551e7ea277a1bed69ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 13:28:10 +0000 Subject: [PATCH 214/316] Bump ruff from 0.0.263 to 0.0.264 (#8857) Bumps [ruff](https://github.com/charliermarsh/ruff) from 0.0.263 to 0.0.264. - [Release notes](https://github.com/charliermarsh/ruff/releases) - [Changelog](https://github.com/charliermarsh/ruff/blob/main/BREAKING_CHANGES.md) - [Commits](https://github.com/charliermarsh/ruff/compare/v0.0.263...v0.0.264) --- updated-dependencies: - dependency-name: ruff 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index f1eb0318d594..3ea980358c40 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -138,7 +138,7 @@ rfc3986==2.0.0 # via twine rich==13.3.5 # via twine -ruff==0.0.263 +ruff==0.0.264 # via cryptography (pyproject.toml) six==1.16.0 # via bleach From f0f9c9cf6f4f63e295cd86dcd19f7557e8486370 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 2 May 2023 10:09:19 -0400 Subject: [PATCH 215/316] Switch the vectors pacakge to use modern pyproject.toml (#8853) --- .github/workflows/wheel-builder.yml | 2 +- docs/doing-a-release.rst | 5 ++--- release.py | 5 +++++ vectors/pyproject.toml | 22 ++++++++++++++++++++++ vectors/setup.cfg | 18 ------------------ vectors/setup.py | 9 --------- 6 files changed, 30 insertions(+), 31 deletions(-) create mode 100644 vectors/pyproject.toml delete mode 100644 vectors/setup.cfg delete mode 100644 vectors/setup.py diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index c3e145a99a9f..b64828ab61dc 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -17,7 +17,7 @@ on: - .github/workflows/wheel-builder.yml - setup.py - pyproject.toml - - src/cryptography/__about__.py + - vectors/pyproject.toml env: CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse diff --git a/docs/doing-a-release.rst b/docs/doing-a-release.rst index 48e253ea4960..c7e82ffb4df2 100644 --- a/docs/doing-a-release.rst +++ b/docs/doing-a-release.rst @@ -86,9 +86,8 @@ Post-release tasks * Close the `milestone`_ for the previous release on GitHub. * For major version releases, send a pull request to pyOpenSSL increasing the maximum ``cryptography`` version pin and perform a pyOpenSSL release. -* Update the version number to the next major (e.g. ``0.5.dev1``) in - ``src/cryptography/__about__.py`` and - ``vectors/cryptography_vectors/__about__.py``. +* Update the version number to the next major (e.g. ``0.5.dev1``) with + ``python release.py bump-version {new_version}``. * Add new :doc:`/changelog` entry with next version and note that it is under active development * Send a pull request with these items diff --git a/release.py b/release.py index 9f41a82ec2e1..b4844a12a5e5 100644 --- a/release.py +++ b/release.py @@ -59,6 +59,11 @@ def bump_version(new_version: str) -> None: replace_version( base_dir / "src/cryptography/__about__.py", "__version__", new_version ) + replace_version( + base_dir / "vectors/pyproject.toml", + "version", + new_version, + ) replace_version( base_dir / "vectors/cryptography_vectors/__about__.py", "__version__", diff --git a/vectors/pyproject.toml b/vectors/pyproject.toml new file mode 100644 index 000000000000..f3da68b11abe --- /dev/null +++ b/vectors/pyproject.toml @@ -0,0 +1,22 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "cryptography_vectors" +version = "41.0.0.dev1" +authors = [ + {name = "The Python Cryptographic Authority and individual contributors", email = "cryptography-dev@python.org"} +] +description = "Test vectors for the cryptography package." +license = {text = "Apache-2.0 OR BSD-3-Clause"} + +[project.urls] +homepage = "https://github.com/pyca/cryptography" + +[tool.setuptools] +zip-safe = false +include-package-data = true + +[tool.distutils.bdist_wheel] +universal = true diff --git a/vectors/setup.cfg b/vectors/setup.cfg deleted file mode 100644 index 99faeffba83b..000000000000 --- a/vectors/setup.cfg +++ /dev/null @@ -1,18 +0,0 @@ -[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 deleted file mode 100644 index 88d88a75d8b0..000000000000 --- a/vectors/setup.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python - -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from setuptools import setup - -setup() From d484a8b1052fc1db920da36129a1de9ac0f9ff09 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Wed, 3 May 2023 00:20:13 +0000 Subject: [PATCH 216/316] Bump BoringSSL and/or OpenSSL in CI (#8861) Co-authored-by: pyca-boringbot[bot] --- .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 0b9658163e06..30acdf8bc338 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of May 02, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "86ada1ea2f51ff41baa2919337e5d721bd27f764"}} - # Latest commit on the OpenSSL master branch, as of May 02, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "1009940c14716ac03d5f161bdb4ae626ec6fe729"}} + # Latest commit on the BoringSSL master branch, as of May 03, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "4c8bcf0da2951cacd8ed8eaa7fd2df4b22fca23b"}} + # Latest commit on the OpenSSL master branch, as of May 03, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "56547da9d3fa24f54b439497d322b12beb004c80"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 8d772f51907af4b00857c3a89ad9e73a2f48ccb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 May 2023 13:07:10 +0000 Subject: [PATCH 217/316] Bump pkg-config from 0.3.26 to 0.3.27 in /src/rust (#8862) Bumps [pkg-config](https://github.com/rust-lang/pkg-config-rs) from 0.3.26 to 0.3.27. - [Release notes](https://github.com/rust-lang/pkg-config-rs/releases) - [Changelog](https://github.com/rust-lang/pkg-config-rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/pkg-config-rs/compare/0.3.26...0.3.27) --- updated-dependencies: - dependency-name: pkg-config 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 e63a2e1ef0bf..b2f1b99d7dad 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -255,9 +255,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "proc-macro-error" From bbea31b68d12a3f4cc43b4f6ca9f6fa5ea751d25 Mon Sep 17 00:00:00 2001 From: Harmin Parra Rueda Date: Wed, 3 May 2023 23:34:54 +0200 Subject: [PATCH 218/316] Fix for #8854 (#8855) * Fix for #8854 Fix for issue #8854 * Fix for issue #8854 Fix for issue #8854 * versionadded --------- Co-authored-by: Paul Kehrer --- docs/x509/reference.rst | 6 ++++++ src/cryptography/hazmat/_oid.py | 1 + 2 files changed, 7 insertions(+) diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index 2f7040ebfa12..71a6eb1799b5 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -3034,6 +3034,12 @@ instances. The following common OIDs are available as constants. Corresponds to the dotted string ``"2.5.4.12"``. + .. attribute:: INITIALS + + .. versionadded:: 41.0.0 + + Corresponds to the dotted string ``"2.5.4.43"``. + .. attribute:: GENERATION_QUALIFIER Corresponds to the dotted string ``"2.5.4.44"``. diff --git a/src/cryptography/hazmat/_oid.py b/src/cryptography/hazmat/_oid.py index 908f6206db3f..01d4b3406062 100644 --- a/src/cryptography/hazmat/_oid.py +++ b/src/cryptography/hazmat/_oid.py @@ -66,6 +66,7 @@ class NameOID: SURNAME = ObjectIdentifier("2.5.4.4") GIVEN_NAME = ObjectIdentifier("2.5.4.42") TITLE = ObjectIdentifier("2.5.4.12") + INITIALS = ObjectIdentifier("2.5.4.43") GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44") X500_UNIQUE_IDENTIFIER = ObjectIdentifier("2.5.4.45") DN_QUALIFIER = ObjectIdentifier("2.5.4.46") From e72f353cb14be5f6524ea81d7cd300d599df49c5 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Thu, 4 May 2023 00:16:08 +0000 Subject: [PATCH 219/316] Bump BoringSSL and/or OpenSSL in CI (#8863) Co-authored-by: pyca-boringbot[bot] --- .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 30acdf8bc338..cf907fd1a2f8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of May 03, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "4c8bcf0da2951cacd8ed8eaa7fd2df4b22fca23b"}} - # Latest commit on the OpenSSL master branch, as of May 03, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "56547da9d3fa24f54b439497d322b12beb004c80"}} + # Latest commit on the BoringSSL master branch, as of May 04, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "85e6453cc3b940b2151681f55e698b625be0d723"}} + # Latest commit on the OpenSSL master branch, as of May 04, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "010333be5362a07508888124c83efac35b28760f"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 032845a0d68f670eeb848e8c4f1abf257c6c2106 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Thu, 4 May 2023 20:56:45 -0400 Subject: [PATCH 220/316] Bump BoringSSL and/or OpenSSL in CI (#8866) Co-authored-by: pyca-boringbot[bot] --- .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 cf907fd1a2f8..c27b0c72daaa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of May 04, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "85e6453cc3b940b2151681f55e698b625be0d723"}} - # Latest commit on the OpenSSL master branch, as of May 04, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "010333be5362a07508888124c83efac35b28760f"}} + # Latest commit on the BoringSSL master branch, as of May 05, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "5e988c40553f6afe38971d4a32f5c4b7b48ac972"}} + # Latest commit on the OpenSSL master branch, as of May 05, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "42a6a25ba4ddb40333e92e6e2fc57625d9567090"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From faa09a42ce42dd9943680000b519ccdf253fb8b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 May 2023 13:09:25 +0000 Subject: [PATCH 221/316] Bump requests from 2.29.0 to 2.30.0 (#8868) Bumps [requests](https://github.com/psf/requests) from 2.29.0 to 2.30.0. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.29.0...v2.30.0) --- updated-dependencies: - dependency-name: requests 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 3ea980358c40..7a758256295b 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -127,7 +127,7 @@ pytest-xdist==3.2.1 # via cryptography (pyproject.toml) readme-renderer==37.3 # via twine -requests==2.29.0 +requests==2.30.0 # via # requests-toolbelt # sphinx From 947cf632e1502c1f0aa6bd032238f1bef80657ec Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 May 2023 13:27:54 +0000 Subject: [PATCH 222/316] Bump urllib3 from 1.26.15 to 2.0.2 (#8869) Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.26.15 to 2.0.2. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/1.26.15...2.0.2) --- updated-dependencies: - dependency-name: urllib3 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 7a758256295b..5f6b56b99e90 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -181,7 +181,7 @@ twine==4.0.2 # via cryptography (pyproject.toml) typing-extensions==4.5.0 # via mypy -urllib3==1.26.15 +urllib3==2.0.2 # via # requests # twine From b0dc9b0a09744a52137157b5e7920d88c36bbb5d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 May 2023 16:40:30 +0000 Subject: [PATCH 223/316] Bump asn1 from 0.15.0 to 0.15.1 in /src/rust (#8871) Bumps [asn1](https://github.com/alex/rust-asn1) from 0.15.0 to 0.15.1. - [Commits](https://github.com/alex/rust-asn1/compare/0.15.0...0.15.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 +- src/rust/cryptography-x509/Cargo.toml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index b2f1b99d7dad..cb554bb9763e 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -16,18 +16,18 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" [[package]] name = "asn1" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa66f5a3e8407b8d3dd8fefc2a62a1aba9539a1d8f856024643c2ae0a8e541ed" +checksum = "de3ffc84e382cf516922078c67853a781fdb4363cf364594df8eab5ef5485553" dependencies = [ "asn1_derive", ] [[package]] name = "asn1_derive" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6365c8b2b1a059ca234d1b69ba501cfa98f1cfd342b95c75611895f1cb0fb81" +checksum = "7124c4d563619518d0ad454032967d5645627033d4b6e4e17bb7ac0237241c81" dependencies = [ "proc-macro2", "quote", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 614bd9967e0a..52e179a4c42e 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -10,7 +10,7 @@ rust-version = "1.56.0" [dependencies] once_cell = "1" pyo3 = { version = "0.18", features = ["abi3-py37"] } -asn1 = { version = "0.15.0", default-features = false } +asn1 = { version = "0.15.1", default-features = false } cryptography-cffi = { path = "cryptography-cffi" } cryptography-x509 = { path = "cryptography-x509" } cryptography-openssl = { path = "cryptography-openssl" } diff --git a/src/rust/cryptography-x509/Cargo.toml b/src/rust/cryptography-x509/Cargo.toml index 398473471733..8c4d20537435 100644 --- a/src/rust/cryptography-x509/Cargo.toml +++ b/src/rust/cryptography-x509/Cargo.toml @@ -8,4 +8,4 @@ publish = false rust-version = "1.56.0" [dependencies] -asn1 = { version = "0.15.0", default-features = false } +asn1 = { version = "0.15.1", default-features = false } From 8ae2b3fc2d4abd840c0fd7722e5bd01436db8027 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 5 May 2023 13:37:10 -0400 Subject: [PATCH 224/316] Switch AlgorithmIdentifier to use rust-asn1's native defined by support (#8870) --- src/rust/cryptography-x509/src/common.rs | 24 ++++- src/rust/src/pkcs7.rs | 16 +-- src/rust/src/x509/certificate.rs | 6 +- src/rust/src/x509/crl.rs | 6 +- src/rust/src/x509/csr.rs | 6 +- src/rust/src/x509/ocsp.rs | 26 +++-- src/rust/src/x509/ocsp_req.rs | 4 +- src/rust/src/x509/ocsp_resp.rs | 10 +- src/rust/src/x509/sign.rs | 124 +++++++++++++++-------- 9 files changed, 144 insertions(+), 78 deletions(-) diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs index 122b37b6a7e6..7835c3a5a3f3 100644 --- a/src/rust/cryptography-x509/src/common.rs +++ b/src/rust/cryptography-x509/src/common.rs @@ -2,12 +2,32 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. +use crate::oid; +use asn1::Asn1DefinedByWritable; use std::marker::PhantomData; #[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash, Clone)] pub struct AlgorithmIdentifier<'a> { - pub oid: asn1::ObjectIdentifier, - pub params: Option>, + pub oid: asn1::DefinedByMarker, + #[defined_by(oid)] + pub params: AlgorithmParameters<'a>, +} + +impl AlgorithmIdentifier<'_> { + pub fn oid(&self) -> &asn1::ObjectIdentifier { + self.params.item() + } +} + +#[derive(asn1::Asn1DefinedByRead, asn1::Asn1DefinedByWrite, PartialEq, Hash, Clone)] +pub enum AlgorithmParameters<'a> { + #[defined_by(oid::ED25519_OID)] + Ed25519, + #[defined_by(oid::ED448_OID)] + Ed448, + + #[default] + Other(asn1::ObjectIdentifier, Option>), } #[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Clone)] diff --git a/src/rust/src/pkcs7.rs b/src/rust/src/pkcs7.rs index 236976bf4046..589be56738d5 100644 --- a/src/rust/src/pkcs7.rs +++ b/src/rust/src/pkcs7.rs @@ -8,7 +8,6 @@ use crate::error::CryptographyResult; use crate::x509; use cryptography_x509::csr::Attribute; use cryptography_x509::{common, oid, pkcs7}; - use once_cell::sync::Lazy; use std::borrow::Cow; use std::collections::HashMap; @@ -181,11 +180,14 @@ fn sign_and_serialize<'p>( }; let digest_alg = common::AlgorithmIdentifier { - oid: x509::ocsp::HASH_NAME_TO_OIDS[py_hash_alg - .getattr(pyo3::intern!(py, "name"))? - .extract::<&str>()?] - .clone(), - params: Some(*x509::sign::NULL_TLV), + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other( + x509::ocsp::HASH_NAME_TO_OIDS[py_hash_alg + .getattr(pyo3::intern!(py, "name"))? + .extract::<&str>()?] + .clone(), + Some(*x509::sign::NULL_TLV), + ), }; // Technically O(n^2), but no one will have that many signers. if !digest_algs.contains(&digest_alg) { @@ -252,7 +254,7 @@ fn sign_and_serialize<'p>( if encoding.is(encoding_class.getattr(pyo3::intern!(py, "SMIME"))?) { let mic_algs = digest_algs .iter() - .map(|d| OIDS_TO_MIC_NAME[&d.oid]) + .map(|d| OIDS_TO_MIC_NAME[&d.oid()]) .collect::>() .join(","); let smime_encode = py diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index b8d281014ff6..949c4e10f1ce 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -247,7 +247,7 @@ impl Certificate { Err(_) => Err(CryptographyError::from( exceptions::UnsupportedAlgorithm::new_err(format!( "Signature algorithm OID: {} not recognized", - self.raw.borrow_value().signature_alg.oid + self.raw.borrow_value().signature_alg.oid(), )), )), } @@ -255,7 +255,7 @@ impl Certificate { #[getter] fn signature_algorithm_oid<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - oid_to_py_oid(py, &self.raw.borrow_value().signature_alg.oid) + oid_to_py_oid(py, self.raw.borrow_value().signature_alg.oid()) } #[getter] @@ -311,7 +311,7 @@ impl Certificate { sign::verify_signature_with_oid( py, issuer.public_key(py)?, - &self.raw.borrow_value().signature_alg.oid, + self.raw.borrow_value().signature_alg.oid(), self.raw.borrow_value().signature.as_bytes(), &asn1::write_single(&self.raw.borrow_value().tbs_cert)?, ) diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index db4fd0394afd..b6529ebf3cb3 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -184,7 +184,7 @@ impl CertificateRevocationList { #[getter] fn signature_algorithm_oid<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - oid_to_py_oid(py, &self.owned.borrow_value().signature_algorithm.oid) + oid_to_py_oid(py, self.owned.borrow_value().signature_algorithm.oid()) } #[getter] @@ -201,7 +201,7 @@ impl CertificateRevocationList { Ok(v) => Ok(v), Err(_) => Err(exceptions::UnsupportedAlgorithm::new_err(format!( "Signature algorithm OID: {} not recognized", - self.owned.borrow_value().signature_algorithm.oid + self.owned.borrow_value().signature_algorithm.oid(), ))), } } @@ -394,7 +394,7 @@ impl CertificateRevocationList { Ok(sign::verify_signature_with_oid( py, public_key, - &slf.owned.borrow_value().signature_algorithm.oid, + slf.owned.borrow_value().signature_algorithm.oid(), slf.owned.borrow_value().signature_value.as_bytes(), &asn1::write_single(&slf.owned.borrow_value().tbs_cert_list)?, ) diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index 2d734681910a..c4a69ebb53f0 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -105,7 +105,7 @@ impl CertificateSigningRequest { Err(_) => Err(CryptographyError::from( exceptions::UnsupportedAlgorithm::new_err(format!( "Signature algorithm OID: {} not recognized", - self.raw.borrow_value().signature_alg.oid + self.raw.borrow_value().signature_alg.oid() )), )), } @@ -113,7 +113,7 @@ impl CertificateSigningRequest { #[getter] fn signature_algorithm_oid<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { - oid_to_py_oid(py, &self.raw.borrow_value().signature_alg.oid) + oid_to_py_oid(py, self.raw.borrow_value().signature_alg.oid()) } fn public_bytes<'p>( @@ -235,7 +235,7 @@ impl CertificateSigningRequest { Ok(sign::verify_signature_with_oid( py, slf.public_key(py)?, - &slf.raw.borrow_value().signature_alg.oid, + slf.raw.borrow_value().signature_alg.oid(), slf.raw.borrow_value().signature.as_bytes(), &asn1::write_single(&slf.raw.borrow_value().csr_info)?, ) diff --git a/src/rust/src/x509/ocsp.rs b/src/rust/src/x509/ocsp.rs index b362ef326d8d..0ea5555c12f1 100644 --- a/src/rust/src/x509/ocsp.rs +++ b/src/rust/src/x509/ocsp.rs @@ -52,11 +52,14 @@ pub(crate) fn certid_new<'p>( Ok(CertID { hash_algorithm: common::AlgorithmIdentifier { - oid: HASH_NAME_TO_OIDS[hash_algorithm - .getattr(pyo3::intern!(py, "name"))? - .extract::<&str>()?] - .clone(), - params: Some(*x509::sign::NULL_TLV), + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other( + HASH_NAME_TO_OIDS[hash_algorithm + .getattr(pyo3::intern!(py, "name"))? + .extract::<&str>()?] + .clone(), + Some(*x509::sign::NULL_TLV), + ), }, issuer_name_hash, issuer_key_hash, @@ -73,11 +76,14 @@ pub(crate) fn certid_new_from_hash<'p>( ) -> CryptographyResult> { Ok(CertID { hash_algorithm: common::AlgorithmIdentifier { - oid: HASH_NAME_TO_OIDS[hash_algorithm - .getattr(pyo3::intern!(py, "name"))? - .extract::<&str>()?] - .clone(), - params: Some(*x509::sign::NULL_TLV), + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other( + HASH_NAME_TO_OIDS[hash_algorithm + .getattr(pyo3::intern!(py, "name"))? + .extract::<&str>()?] + .clone(), + Some(*x509::sign::NULL_TLV), + ), }, issuer_name_hash, issuer_key_hash, diff --git a/src/rust/src/x509/ocsp_req.rs b/src/rust/src/x509/ocsp_req.rs index 701868e89395..b8faedb09dc2 100644 --- a/src/rust/src/x509/ocsp_req.rs +++ b/src/rust/src/x509/ocsp_req.rs @@ -86,12 +86,12 @@ impl OCSPRequest { let cert_id = self.cert_id(); let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; - match ocsp::OIDS_TO_HASH.get(&cert_id.hash_algorithm.oid) { + match ocsp::OIDS_TO_HASH.get(&cert_id.hash_algorithm.oid()) { Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), None => Err(CryptographyError::from( exceptions::UnsupportedAlgorithm::new_err(format!( "Signature algorithm OID: {} not recognized", - cert_id.hash_algorithm.oid + cert_id.hash_algorithm.oid() )), )), } diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index 103b610ec51f..15cf99d9fe55 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -168,7 +168,7 @@ impl OCSPResponse { #[getter] fn signature_algorithm_oid<'p>(&self, py: pyo3::Python<'p>) -> pyo3::PyResult<&'p pyo3::PyAny> { let resp = self.requires_successful_response()?; - oid_to_py_oid(py, &resp.signature_algorithm.oid) + oid_to_py_oid(py, resp.signature_algorithm.oid()) } #[getter] @@ -185,7 +185,9 @@ impl OCSPResponse { Err(_) => { let exc_messsage = format!( "Signature algorithm OID: {} not recognized", - self.requires_successful_response()?.signature_algorithm.oid + self.requires_successful_response()? + .signature_algorithm + .oid() ); Err(CryptographyError::from( exceptions::UnsupportedAlgorithm::new_err(exc_messsage), @@ -477,12 +479,12 @@ fn singleresp_py_hash_algorithm<'p>( py: pyo3::Python<'p>, ) -> Result<&'p pyo3::PyAny, CryptographyError> { let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; - match ocsp::OIDS_TO_HASH.get(&resp.cert_id.hash_algorithm.oid) { + match ocsp::OIDS_TO_HASH.get(&resp.cert_id.hash_algorithm.oid()) { Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), None => Err(CryptographyError::from( exceptions::UnsupportedAlgorithm::new_err(format!( "Signature algorithm OID: {} not recognized", - resp.cert_id.hash_algorithm.oid + resp.cert_id.hash_algorithm.oid() )), )), } diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index 187dc54db986..c4c01c9737fc 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -138,98 +138,134 @@ pub(crate) fn compute_signature_algorithm<'p>( match (key_type, hash_type) { (KeyType::Ed25519, HashType::None) => Ok(common::AlgorithmIdentifier { - oid: (oid::ED25519_OID).clone(), - params: None, + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Ed25519, }), (KeyType::Ed448, HashType::None) => Ok(common::AlgorithmIdentifier { - oid: (oid::ED448_OID).clone(), - params: None, + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Ed448, }), (KeyType::Ed25519 | KeyType::Ed448, _) => Err(pyo3::exceptions::PyValueError::new_err( "Algorithm must be None when signing via ed25519 or ed448", )), (KeyType::Ec, HashType::Sha224) => Ok(common::AlgorithmIdentifier { - oid: (oid::ECDSA_WITH_SHA224_OID).clone(), - params: None, + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other((oid::ECDSA_WITH_SHA224_OID).clone(), None), }), (KeyType::Ec, HashType::Sha256) => Ok(common::AlgorithmIdentifier { - oid: (oid::ECDSA_WITH_SHA256_OID).clone(), - params: None, + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other((oid::ECDSA_WITH_SHA256_OID).clone(), None), }), (KeyType::Ec, HashType::Sha384) => Ok(common::AlgorithmIdentifier { - oid: (oid::ECDSA_WITH_SHA384_OID).clone(), - params: None, + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other((oid::ECDSA_WITH_SHA384_OID).clone(), None), }), (KeyType::Ec, HashType::Sha512) => Ok(common::AlgorithmIdentifier { - oid: (oid::ECDSA_WITH_SHA512_OID).clone(), - params: None, + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other((oid::ECDSA_WITH_SHA512_OID).clone(), None), }), (KeyType::Ec, HashType::Sha3_224) => Ok(common::AlgorithmIdentifier { - oid: (oid::ECDSA_WITH_SHA3_224_OID).clone(), - params: None, + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other( + (oid::ECDSA_WITH_SHA3_224_OID).clone(), + None, + ), }), (KeyType::Ec, HashType::Sha3_256) => Ok(common::AlgorithmIdentifier { - oid: (oid::ECDSA_WITH_SHA3_256_OID).clone(), - params: None, + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other( + (oid::ECDSA_WITH_SHA3_256_OID).clone(), + None, + ), }), (KeyType::Ec, HashType::Sha3_384) => Ok(common::AlgorithmIdentifier { - oid: (oid::ECDSA_WITH_SHA3_384_OID).clone(), - params: None, + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other( + (oid::ECDSA_WITH_SHA3_384_OID).clone(), + None, + ), }), (KeyType::Ec, HashType::Sha3_512) => Ok(common::AlgorithmIdentifier { - oid: (oid::ECDSA_WITH_SHA3_512_OID).clone(), - params: None, + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other( + (oid::ECDSA_WITH_SHA3_512_OID).clone(), + None, + ), }), (KeyType::Rsa, HashType::Sha224) => Ok(common::AlgorithmIdentifier { - oid: (oid::RSA_WITH_SHA224_OID).clone(), - params: Some(*NULL_TLV), + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other( + (oid::RSA_WITH_SHA224_OID).clone(), + Some(*NULL_TLV), + ), }), (KeyType::Rsa, HashType::Sha256) => Ok(common::AlgorithmIdentifier { - oid: (oid::RSA_WITH_SHA256_OID).clone(), - params: Some(*NULL_TLV), + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other( + (oid::RSA_WITH_SHA256_OID).clone(), + Some(*NULL_TLV), + ), }), (KeyType::Rsa, HashType::Sha384) => Ok(common::AlgorithmIdentifier { - oid: (oid::RSA_WITH_SHA384_OID).clone(), - params: Some(*NULL_TLV), + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other( + (oid::RSA_WITH_SHA384_OID).clone(), + Some(*NULL_TLV), + ), }), (KeyType::Rsa, HashType::Sha512) => Ok(common::AlgorithmIdentifier { - oid: (oid::RSA_WITH_SHA512_OID).clone(), - params: Some(*NULL_TLV), + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other( + (oid::RSA_WITH_SHA512_OID).clone(), + Some(*NULL_TLV), + ), }), (KeyType::Rsa, HashType::Sha3_224) => Ok(common::AlgorithmIdentifier { - oid: (oid::RSA_WITH_SHA3_224_OID).clone(), - params: Some(*NULL_TLV), + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other( + (oid::RSA_WITH_SHA3_224_OID).clone(), + Some(*NULL_TLV), + ), }), (KeyType::Rsa, HashType::Sha3_256) => Ok(common::AlgorithmIdentifier { - oid: (oid::RSA_WITH_SHA3_256_OID).clone(), - params: Some(*NULL_TLV), + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other( + (oid::RSA_WITH_SHA3_256_OID).clone(), + Some(*NULL_TLV), + ), }), (KeyType::Rsa, HashType::Sha3_384) => Ok(common::AlgorithmIdentifier { - oid: (oid::RSA_WITH_SHA3_384_OID).clone(), - params: Some(*NULL_TLV), + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other( + (oid::RSA_WITH_SHA3_384_OID).clone(), + Some(*NULL_TLV), + ), }), (KeyType::Rsa, HashType::Sha3_512) => Ok(common::AlgorithmIdentifier { - oid: (oid::RSA_WITH_SHA3_512_OID).clone(), - params: Some(*NULL_TLV), + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other( + (oid::RSA_WITH_SHA3_512_OID).clone(), + Some(*NULL_TLV), + ), }), (KeyType::Dsa, HashType::Sha224) => Ok(common::AlgorithmIdentifier { - oid: (oid::DSA_WITH_SHA224_OID).clone(), - params: None, + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other((oid::DSA_WITH_SHA224_OID).clone(), None), }), (KeyType::Dsa, HashType::Sha256) => Ok(common::AlgorithmIdentifier { - oid: (oid::DSA_WITH_SHA256_OID).clone(), - params: None, + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other((oid::DSA_WITH_SHA256_OID).clone(), None), }), (KeyType::Dsa, HashType::Sha384) => Ok(common::AlgorithmIdentifier { - oid: (oid::DSA_WITH_SHA384_OID).clone(), - params: None, + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other((oid::DSA_WITH_SHA384_OID).clone(), None), }), (KeyType::Dsa, HashType::Sha512) => Ok(common::AlgorithmIdentifier { - oid: (oid::DSA_WITH_SHA512_OID).clone(), - params: None, + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Other((oid::DSA_WITH_SHA512_OID).clone(), None), }), ( KeyType::Dsa, From 141bcc588098773690c04917da654f1d475c4939 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 5 May 2023 15:57:50 -0400 Subject: [PATCH 225/316] Use defined_by for RSA signature AlgorithmIdentifiers (#8874) I had hoped the parameters would just be Null (no Option<>), but a review of the RFC (3447, 4055) indicates that both should be allowed, though the WebPKI enforces greater constraints. --- src/rust/cryptography-x509/src/common.rs | 18 +++++++++++ src/rust/src/x509/sign.rs | 40 +++++------------------- 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs index 7835c3a5a3f3..2a878db23cbf 100644 --- a/src/rust/cryptography-x509/src/common.rs +++ b/src/rust/cryptography-x509/src/common.rs @@ -26,6 +26,24 @@ pub enum AlgorithmParameters<'a> { #[defined_by(oid::ED448_OID)] Ed448, + #[defined_by(oid::RSA_WITH_SHA224_OID)] + RsaWithSha224(Option), + #[defined_by(oid::RSA_WITH_SHA256_OID)] + RsaWithSha256(Option), + #[defined_by(oid::RSA_WITH_SHA384_OID)] + RsaWithSha384(Option), + #[defined_by(oid::RSA_WITH_SHA512_OID)] + RsaWithSha512(Option), + + #[defined_by(oid::RSA_WITH_SHA3_224_OID)] + RsaWithSha3_224(Option), + #[defined_by(oid::RSA_WITH_SHA3_256_OID)] + RsaWithSha3_256(Option), + #[defined_by(oid::RSA_WITH_SHA3_384_OID)] + RsaWithSha3_384(Option), + #[defined_by(oid::RSA_WITH_SHA3_512_OID)] + RsaWithSha3_512(Option), + #[default] Other(asn1::ObjectIdentifier, Option>), } diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index c4c01c9737fc..07668621feab 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -196,59 +196,35 @@ pub(crate) fn compute_signature_algorithm<'p>( (KeyType::Rsa, HashType::Sha224) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other( - (oid::RSA_WITH_SHA224_OID).clone(), - Some(*NULL_TLV), - ), + params: common::AlgorithmParameters::RsaWithSha224(Some(())), }), (KeyType::Rsa, HashType::Sha256) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other( - (oid::RSA_WITH_SHA256_OID).clone(), - Some(*NULL_TLV), - ), + params: common::AlgorithmParameters::RsaWithSha256(Some(())), }), (KeyType::Rsa, HashType::Sha384) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other( - (oid::RSA_WITH_SHA384_OID).clone(), - Some(*NULL_TLV), - ), + params: common::AlgorithmParameters::RsaWithSha384(Some(())), }), (KeyType::Rsa, HashType::Sha512) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other( - (oid::RSA_WITH_SHA512_OID).clone(), - Some(*NULL_TLV), - ), + params: common::AlgorithmParameters::RsaWithSha512(Some(())), }), (KeyType::Rsa, HashType::Sha3_224) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other( - (oid::RSA_WITH_SHA3_224_OID).clone(), - Some(*NULL_TLV), - ), + params: common::AlgorithmParameters::RsaWithSha3_224(Some(())), }), (KeyType::Rsa, HashType::Sha3_256) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other( - (oid::RSA_WITH_SHA3_256_OID).clone(), - Some(*NULL_TLV), - ), + params: common::AlgorithmParameters::RsaWithSha3_256(Some(())), }), (KeyType::Rsa, HashType::Sha3_384) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other( - (oid::RSA_WITH_SHA3_384_OID).clone(), - Some(*NULL_TLV), - ), + params: common::AlgorithmParameters::RsaWithSha3_384(Some(())), }), (KeyType::Rsa, HashType::Sha3_512) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other( - (oid::RSA_WITH_SHA3_512_OID).clone(), - Some(*NULL_TLV), - ), + params: common::AlgorithmParameters::RsaWithSha3_512(Some(())), }), (KeyType::Dsa, HashType::Sha224) => Ok(common::AlgorithmIdentifier { From 10688d1ba27e0899812f2eb12be0d8a2a352ba85 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 5 May 2023 16:19:29 -0400 Subject: [PATCH 226/316] Use defined_by for (EC)DSA signature AlgorithmIdentifiers (#8875) Also fix a test that had an incorrect parameters for an OID. The test had deliberately been constructed to be invalid, but in a _different_ respect. --- src/rust/cryptography-x509/src/common.rs | 27 +++++++++++++ src/rust/src/x509/sign.rs | 36 ++++++------------ .../mismatch_inner_outer_sig_algorithm.der | Bin 1473 -> 1471 bytes 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs index 2a878db23cbf..4dd83d926e61 100644 --- a/src/rust/cryptography-x509/src/common.rs +++ b/src/rust/cryptography-x509/src/common.rs @@ -26,6 +26,24 @@ pub enum AlgorithmParameters<'a> { #[defined_by(oid::ED448_OID)] Ed448, + #[defined_by(oid::ECDSA_WITH_SHA224_OID)] + EcDsaWithSha224, + #[defined_by(oid::ECDSA_WITH_SHA256_OID)] + EcDsaWithSha256, + #[defined_by(oid::ECDSA_WITH_SHA384_OID)] + EcDsaWithSha384, + #[defined_by(oid::ECDSA_WITH_SHA512_OID)] + EcDsaWithSha512, + + #[defined_by(oid::ECDSA_WITH_SHA3_224_OID)] + EcDsaWithSha3_224, + #[defined_by(oid::ECDSA_WITH_SHA3_256_OID)] + EcDsaWithSha3_256, + #[defined_by(oid::ECDSA_WITH_SHA3_384_OID)] + EcDsaWithSha3_384, + #[defined_by(oid::ECDSA_WITH_SHA3_512_OID)] + EcDsaWithSha3_512, + #[defined_by(oid::RSA_WITH_SHA224_OID)] RsaWithSha224(Option), #[defined_by(oid::RSA_WITH_SHA256_OID)] @@ -44,6 +62,15 @@ pub enum AlgorithmParameters<'a> { #[defined_by(oid::RSA_WITH_SHA3_512_OID)] RsaWithSha3_512(Option), + #[defined_by(oid::DSA_WITH_SHA224_OID)] + DsaWithSha224, + #[defined_by(oid::DSA_WITH_SHA256_OID)] + DsaWithSha256, + #[defined_by(oid::DSA_WITH_SHA384_OID)] + DsaWithSha384, + #[defined_by(oid::DSA_WITH_SHA512_OID)] + DsaWithSha512, + #[default] Other(asn1::ObjectIdentifier, Option>), } diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index 07668621feab..d30a270643c2 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -151,47 +151,35 @@ pub(crate) fn compute_signature_algorithm<'p>( (KeyType::Ec, HashType::Sha224) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other((oid::ECDSA_WITH_SHA224_OID).clone(), None), + params: common::AlgorithmParameters::EcDsaWithSha224, }), (KeyType::Ec, HashType::Sha256) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other((oid::ECDSA_WITH_SHA256_OID).clone(), None), + params: common::AlgorithmParameters::EcDsaWithSha256, }), (KeyType::Ec, HashType::Sha384) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other((oid::ECDSA_WITH_SHA384_OID).clone(), None), + params: common::AlgorithmParameters::EcDsaWithSha384, }), (KeyType::Ec, HashType::Sha512) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other((oid::ECDSA_WITH_SHA512_OID).clone(), None), + params: common::AlgorithmParameters::EcDsaWithSha512, }), (KeyType::Ec, HashType::Sha3_224) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other( - (oid::ECDSA_WITH_SHA3_224_OID).clone(), - None, - ), + params: common::AlgorithmParameters::EcDsaWithSha3_224, }), (KeyType::Ec, HashType::Sha3_256) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other( - (oid::ECDSA_WITH_SHA3_256_OID).clone(), - None, - ), + params: common::AlgorithmParameters::EcDsaWithSha3_256, }), (KeyType::Ec, HashType::Sha3_384) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other( - (oid::ECDSA_WITH_SHA3_384_OID).clone(), - None, - ), + params: common::AlgorithmParameters::EcDsaWithSha3_384, }), (KeyType::Ec, HashType::Sha3_512) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other( - (oid::ECDSA_WITH_SHA3_512_OID).clone(), - None, - ), + params: common::AlgorithmParameters::EcDsaWithSha3_512, }), (KeyType::Rsa, HashType::Sha224) => Ok(common::AlgorithmIdentifier { @@ -229,19 +217,19 @@ pub(crate) fn compute_signature_algorithm<'p>( (KeyType::Dsa, HashType::Sha224) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other((oid::DSA_WITH_SHA224_OID).clone(), None), + params: common::AlgorithmParameters::DsaWithSha224, }), (KeyType::Dsa, HashType::Sha256) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other((oid::DSA_WITH_SHA256_OID).clone(), None), + params: common::AlgorithmParameters::DsaWithSha256, }), (KeyType::Dsa, HashType::Sha384) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other((oid::DSA_WITH_SHA384_OID).clone(), None), + params: common::AlgorithmParameters::DsaWithSha384, }), (KeyType::Dsa, HashType::Sha512) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other((oid::DSA_WITH_SHA512_OID).clone(), None), + params: common::AlgorithmParameters::DsaWithSha512, }), ( KeyType::Dsa, diff --git a/vectors/cryptography_vectors/x509/custom/mismatch_inner_outer_sig_algorithm.der b/vectors/cryptography_vectors/x509/custom/mismatch_inner_outer_sig_algorithm.der index ff4e7fb557e59043edc751aedd92dc1fe5438a0f..bf7a473f31d7eb53881321d1fd9aaa6097d31c4e 100644 GIT binary patch delta 39 vcmX@ey`Njopow+2K@-d31t*7 From 4da2e580a9cb6544cdaf32787677f16513bb6f6d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 5 May 2023 17:25:04 -0400 Subject: [PATCH 227/316] Use defined_by for hash AlgorithmIdentifiers (#8876) --- src/rust/cryptography-x509/src/common.rs | 11 ++++ src/rust/src/pkcs7.rs | 14 ++--- src/rust/src/x509/ocsp.rs | 79 +++++++++++++++--------- src/rust/src/x509/sign.rs | 9 --- 4 files changed, 64 insertions(+), 49 deletions(-) diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs index 4dd83d926e61..f44308a8579e 100644 --- a/src/rust/cryptography-x509/src/common.rs +++ b/src/rust/cryptography-x509/src/common.rs @@ -21,6 +21,17 @@ impl AlgorithmIdentifier<'_> { #[derive(asn1::Asn1DefinedByRead, asn1::Asn1DefinedByWrite, PartialEq, Hash, Clone)] pub enum AlgorithmParameters<'a> { + #[defined_by(oid::SHA1_OID)] + Sha1(asn1::Null), + #[defined_by(oid::SHA224_OID)] + Sha224(asn1::Null), + #[defined_by(oid::SHA256_OID)] + Sha256(asn1::Null), + #[defined_by(oid::SHA384_OID)] + Sha384(asn1::Null), + #[defined_by(oid::SHA512_OID)] + Sha512(asn1::Null), + #[defined_by(oid::ED25519_OID)] Ed25519, #[defined_by(oid::ED448_OID)] diff --git a/src/rust/src/pkcs7.rs b/src/rust/src/pkcs7.rs index 589be56738d5..6bc90173fade 100644 --- a/src/rust/src/pkcs7.rs +++ b/src/rust/src/pkcs7.rs @@ -179,16 +179,10 @@ fn sign_and_serialize<'p>( ) }; - let digest_alg = common::AlgorithmIdentifier { - oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other( - x509::ocsp::HASH_NAME_TO_OIDS[py_hash_alg - .getattr(pyo3::intern!(py, "name"))? - .extract::<&str>()?] - .clone(), - Some(*x509::sign::NULL_TLV), - ), - }; + let digest_alg = x509::ocsp::HASH_NAME_TO_ALGORITHM_IDENTIFIERS[py_hash_alg + .getattr(pyo3::intern!(py, "name"))? + .extract::<&str>()?] + .clone(); // Technically O(n^2), but no one will have that many signers. if !digest_algs.contains(&digest_alg) { digest_algs.push(digest_alg.clone()); diff --git a/src/rust/src/x509/ocsp.rs b/src/rust/src/x509/ocsp.rs index 0ea5555c12f1..53a0f2c4ed8b 100644 --- a/src/rust/src/x509/ocsp.rs +++ b/src/rust/src/x509/ocsp.rs @@ -19,16 +19,47 @@ pub(crate) static OIDS_TO_HASH: Lazy> = L h.insert(&oid::SHA512_OID, "SHA512"); h }); -pub(crate) static HASH_NAME_TO_OIDS: Lazy> = - Lazy::new(|| { - let mut h = HashMap::new(); - h.insert("sha1", &oid::SHA1_OID); - h.insert("sha224", &oid::SHA224_OID); - h.insert("sha256", &oid::SHA256_OID); - h.insert("sha384", &oid::SHA384_OID); - h.insert("sha512", &oid::SHA512_OID); - h - }); +pub(crate) static HASH_NAME_TO_ALGORITHM_IDENTIFIERS: Lazy< + HashMap<&str, common::AlgorithmIdentifier<'_>>, +> = Lazy::new(|| { + let mut h = HashMap::new(); + h.insert( + "sha1", + common::AlgorithmIdentifier { + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Sha1(()), + }, + ); + h.insert( + "sha224", + common::AlgorithmIdentifier { + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Sha224(()), + }, + ); + h.insert( + "sha256", + common::AlgorithmIdentifier { + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Sha256(()), + }, + ); + h.insert( + "sha384", + common::AlgorithmIdentifier { + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Sha384(()), + }, + ); + h.insert( + "sha512", + common::AlgorithmIdentifier { + oid: asn1::DefinedByMarker::marker(), + params: common::AlgorithmParameters::Sha512(()), + }, + ); + h +}); pub(crate) fn certid_new<'p>( py: pyo3::Python<'p>, @@ -51,16 +82,10 @@ pub(crate) fn certid_new<'p>( )?; Ok(CertID { - hash_algorithm: common::AlgorithmIdentifier { - oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other( - HASH_NAME_TO_OIDS[hash_algorithm - .getattr(pyo3::intern!(py, "name"))? - .extract::<&str>()?] - .clone(), - Some(*x509::sign::NULL_TLV), - ), - }, + hash_algorithm: x509::ocsp::HASH_NAME_TO_ALGORITHM_IDENTIFIERS[hash_algorithm + .getattr(pyo3::intern!(py, "name"))? + .extract::<&str>()?] + .clone(), issuer_name_hash, issuer_key_hash, serial_number: cert.raw.borrow_value_public().tbs_cert.serial, @@ -75,16 +100,10 @@ pub(crate) fn certid_new_from_hash<'p>( hash_algorithm: &'p pyo3::PyAny, ) -> CryptographyResult> { Ok(CertID { - hash_algorithm: common::AlgorithmIdentifier { - oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Other( - HASH_NAME_TO_OIDS[hash_algorithm - .getattr(pyo3::intern!(py, "name"))? - .extract::<&str>()?] - .clone(), - Some(*x509::sign::NULL_TLV), - ), - }, + hash_algorithm: x509::ocsp::HASH_NAME_TO_ALGORITHM_IDENTIFIERS[hash_algorithm + .getattr(pyo3::intern!(py, "name"))? + .extract::<&str>()?] + .clone(), issuer_name_hash, issuer_key_hash, serial_number, diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index d30a270643c2..c2dc3e651755 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -6,15 +6,6 @@ use crate::error::{CryptographyError, CryptographyResult}; use crate::exceptions; use cryptography_x509::{common, oid}; -use once_cell::sync::Lazy; - -static NULL_DER: Lazy> = Lazy::new(|| { - // TODO: kind of verbose way to say "\x05\x00". - asn1::write_single(&()).unwrap() -}); -pub(crate) static NULL_TLV: Lazy> = - Lazy::new(|| asn1::parse_single(&NULL_DER).unwrap()); - #[derive(Debug, PartialEq)] pub(crate) enum KeyType { Rsa, From 0e5e0030abebc6656629fea6bb9ac10ff8cb8295 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Fri, 5 May 2023 19:33:15 -0500 Subject: [PATCH 228/316] Bump BoringSSL and/or OpenSSL in CI (#8877) Co-authored-by: pyca-boringbot[bot] --- .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 c27b0c72daaa..9a97b41f1d49 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of May 05, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "5e988c40553f6afe38971d4a32f5c4b7b48ac972"}} - # Latest commit on the OpenSSL master branch, as of May 05, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "42a6a25ba4ddb40333e92e6e2fc57625d9567090"}} + # Latest commit on the BoringSSL master branch, as of May 06, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "b1c6f45f1fe6d808555d04a41bb44b322e4f4c1d"}} + # Latest commit on the OpenSSL master branch, as of May 06, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "6aeb42eca97227c8235af0986d1525ee4a916504"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 1f67bb4266ff192fb04602e0d9b8bed1a9dac9e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 6 May 2023 13:42:53 +0000 Subject: [PATCH 229/316] Bump ruff from 0.0.264 to 0.0.265 (#8879) Bumps [ruff](https://github.com/charliermarsh/ruff) from 0.0.264 to 0.0.265. - [Release notes](https://github.com/charliermarsh/ruff/releases) - [Changelog](https://github.com/charliermarsh/ruff/blob/main/BREAKING_CHANGES.md) - [Commits](https://github.com/charliermarsh/ruff/compare/v0.0.264...v0.0.265) --- updated-dependencies: - dependency-name: ruff 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 5f6b56b99e90..38ba5288477f 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -138,7 +138,7 @@ rfc3986==2.0.0 # via twine rich==13.3.5 # via twine -ruff==0.0.264 +ruff==0.0.265 # via cryptography (pyproject.toml) six==1.16.0 # via bleach From 4a3c4407e42f13c6d08ad6863c10962f3f52b230 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 6 May 2023 08:51:03 -0500 Subject: [PATCH 230/316] Check for sigalg by type rather than OID (#8878) --- src/rust/src/x509/certificate.rs | 2 +- src/rust/src/x509/crl.rs | 2 +- src/rust/src/x509/csr.rs | 2 +- src/rust/src/x509/sign.rs | 179 +++++++++++++++++++++---------- 4 files changed, 128 insertions(+), 57 deletions(-) diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 949c4e10f1ce..58dcf2d5d3f2 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -311,7 +311,7 @@ impl Certificate { sign::verify_signature_with_oid( py, issuer.public_key(py)?, - self.raw.borrow_value().signature_alg.oid(), + &self.raw.borrow_value().signature_alg, self.raw.borrow_value().signature.as_bytes(), &asn1::write_single(&self.raw.borrow_value().tbs_cert)?, ) diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index b6529ebf3cb3..e2c4b9c09b9e 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -394,7 +394,7 @@ impl CertificateRevocationList { Ok(sign::verify_signature_with_oid( py, public_key, - slf.owned.borrow_value().signature_algorithm.oid(), + &slf.owned.borrow_value().signature_algorithm, slf.owned.borrow_value().signature_value.as_bytes(), &asn1::write_single(&slf.owned.borrow_value().tbs_cert_list)?, ) diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index c4a69ebb53f0..35aee5c9e501 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -235,7 +235,7 @@ impl CertificateSigningRequest { Ok(sign::verify_signature_with_oid( py, slf.public_key(py)?, - slf.raw.borrow_value().signature_alg.oid(), + &slf.raw.borrow_value().signature_alg, slf.raw.borrow_value().signature.as_bytes(), &asn1::write_single(&slf.raw.borrow_value().csr_info)?, ) diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index c2dc3e651755..5c69ecedf4fe 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -4,7 +4,7 @@ use crate::error::{CryptographyError, CryptographyResult}; use crate::exceptions; -use cryptography_x509::{common, oid}; +use cryptography_x509::common; #[derive(Debug, PartialEq)] pub(crate) enum KeyType { @@ -290,12 +290,13 @@ fn py_hash_name_from_hash_type(hash_type: HashType) -> Option<&'static str> { pub(crate) fn verify_signature_with_oid<'p>( py: pyo3::Python<'p>, issuer_public_key: &'p pyo3::PyAny, - signature_oid: &asn1::ObjectIdentifier, + signature_algorithm: &common::AlgorithmIdentifier<'_>, signature: &[u8], data: &[u8], ) -> CryptographyResult<()> { let key_type = identify_public_key_type(py, issuer_public_key)?; - let (sig_key_type, sig_hash_type) = identify_key_hash_type_for_oid(signature_oid)?; + let (sig_key_type, sig_hash_type) = + identify_key_hash_type_for_algorithm_params(&signature_algorithm.params)?; if key_type != sig_key_type { return Err(CryptographyError::from( pyo3::exceptions::PyValueError::new_err( @@ -402,32 +403,32 @@ pub(crate) fn identify_public_key_type( } } -fn identify_key_hash_type_for_oid( - oid: &asn1::ObjectIdentifier, +fn identify_key_hash_type_for_algorithm_params( + params: &common::AlgorithmParameters<'_>, ) -> pyo3::PyResult<(KeyType, HashType)> { - match *oid { - oid::RSA_WITH_SHA224_OID => Ok((KeyType::Rsa, HashType::Sha224)), - oid::RSA_WITH_SHA256_OID => Ok((KeyType::Rsa, HashType::Sha256)), - oid::RSA_WITH_SHA384_OID => Ok((KeyType::Rsa, HashType::Sha384)), - oid::RSA_WITH_SHA512_OID => Ok((KeyType::Rsa, HashType::Sha512)), - oid::RSA_WITH_SHA3_224_OID => Ok((KeyType::Rsa, HashType::Sha3_224)), - oid::RSA_WITH_SHA3_256_OID => Ok((KeyType::Rsa, HashType::Sha3_256)), - oid::RSA_WITH_SHA3_384_OID => Ok((KeyType::Rsa, HashType::Sha3_384)), - oid::RSA_WITH_SHA3_512_OID => Ok((KeyType::Rsa, HashType::Sha3_512)), - oid::ECDSA_WITH_SHA224_OID => Ok((KeyType::Ec, HashType::Sha224)), - oid::ECDSA_WITH_SHA256_OID => Ok((KeyType::Ec, HashType::Sha256)), - oid::ECDSA_WITH_SHA384_OID => Ok((KeyType::Ec, HashType::Sha384)), - oid::ECDSA_WITH_SHA512_OID => Ok((KeyType::Ec, HashType::Sha512)), - oid::ECDSA_WITH_SHA3_224_OID => Ok((KeyType::Ec, HashType::Sha3_224)), - oid::ECDSA_WITH_SHA3_256_OID => Ok((KeyType::Ec, HashType::Sha3_256)), - oid::ECDSA_WITH_SHA3_384_OID => Ok((KeyType::Ec, HashType::Sha3_384)), - oid::ECDSA_WITH_SHA3_512_OID => Ok((KeyType::Ec, HashType::Sha3_512)), - oid::ED25519_OID => Ok((KeyType::Ed25519, HashType::None)), - oid::ED448_OID => Ok((KeyType::Ed448, HashType::None)), - oid::DSA_WITH_SHA224_OID => Ok((KeyType::Dsa, HashType::Sha224)), - oid::DSA_WITH_SHA256_OID => Ok((KeyType::Dsa, HashType::Sha256)), - oid::DSA_WITH_SHA384_OID => Ok((KeyType::Dsa, HashType::Sha384)), - oid::DSA_WITH_SHA512_OID => Ok((KeyType::Dsa, HashType::Sha512)), + match params { + common::AlgorithmParameters::RsaWithSha224(..) => Ok((KeyType::Rsa, HashType::Sha224)), + common::AlgorithmParameters::RsaWithSha256(..) => Ok((KeyType::Rsa, HashType::Sha256)), + common::AlgorithmParameters::RsaWithSha384(..) => Ok((KeyType::Rsa, HashType::Sha384)), + common::AlgorithmParameters::RsaWithSha512(..) => Ok((KeyType::Rsa, HashType::Sha512)), + common::AlgorithmParameters::RsaWithSha3_224(..) => Ok((KeyType::Rsa, HashType::Sha3_224)), + common::AlgorithmParameters::RsaWithSha3_256(..) => Ok((KeyType::Rsa, HashType::Sha3_256)), + common::AlgorithmParameters::RsaWithSha3_384(..) => Ok((KeyType::Rsa, HashType::Sha3_384)), + common::AlgorithmParameters::RsaWithSha3_512(..) => Ok((KeyType::Rsa, HashType::Sha3_512)), + common::AlgorithmParameters::EcDsaWithSha224 => Ok((KeyType::Ec, HashType::Sha224)), + common::AlgorithmParameters::EcDsaWithSha256 => Ok((KeyType::Ec, HashType::Sha256)), + common::AlgorithmParameters::EcDsaWithSha384 => Ok((KeyType::Ec, HashType::Sha384)), + common::AlgorithmParameters::EcDsaWithSha512 => Ok((KeyType::Ec, HashType::Sha512)), + common::AlgorithmParameters::EcDsaWithSha3_224 => Ok((KeyType::Ec, HashType::Sha3_224)), + common::AlgorithmParameters::EcDsaWithSha3_256 => Ok((KeyType::Ec, HashType::Sha3_256)), + common::AlgorithmParameters::EcDsaWithSha3_384 => Ok((KeyType::Ec, HashType::Sha3_384)), + common::AlgorithmParameters::EcDsaWithSha3_512 => Ok((KeyType::Ec, HashType::Sha3_512)), + common::AlgorithmParameters::Ed25519 => Ok((KeyType::Ed25519, HashType::None)), + common::AlgorithmParameters::Ed448 => Ok((KeyType::Ed448, HashType::None)), + common::AlgorithmParameters::DsaWithSha224 => Ok((KeyType::Dsa, HashType::Sha224)), + common::AlgorithmParameters::DsaWithSha256 => Ok((KeyType::Dsa, HashType::Sha256)), + common::AlgorithmParameters::DsaWithSha384 => Ok((KeyType::Dsa, HashType::Sha384)), + common::AlgorithmParameters::DsaWithSha512 => Ok((KeyType::Dsa, HashType::Sha512)), _ => Err(pyo3::exceptions::PyValueError::new_err( "Unsupported signature algorithm", )), @@ -436,100 +437,170 @@ fn identify_key_hash_type_for_oid( #[cfg(test)] mod tests { - use super::{identify_key_hash_type_for_oid, py_hash_name_from_hash_type, HashType, KeyType}; - use cryptography_x509::oid; + use super::{ + identify_key_hash_type_for_algorithm_params, py_hash_name_from_hash_type, HashType, KeyType, + }; + use cryptography_x509::{common, oid}; #[test] - fn test_identify_key_hash_type_for_oid() { + fn test_identify_key_hash_type_for_algorithm_params() { assert_eq!( - identify_key_hash_type_for_oid(&oid::RSA_WITH_SHA224_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::RsaWithSha224(Some(())) + ) + .unwrap(), (KeyType::Rsa, HashType::Sha224) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::RSA_WITH_SHA256_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::RsaWithSha256(Some(())) + ) + .unwrap(), (KeyType::Rsa, HashType::Sha256) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::RSA_WITH_SHA384_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::RsaWithSha384(Some(())) + ) + .unwrap(), (KeyType::Rsa, HashType::Sha384) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::RSA_WITH_SHA512_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::RsaWithSha512(Some(())) + ) + .unwrap(), (KeyType::Rsa, HashType::Sha512) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::RSA_WITH_SHA3_224_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::RsaWithSha3_224(Some(())) + ) + .unwrap(), (KeyType::Rsa, HashType::Sha3_224) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::RSA_WITH_SHA3_256_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::RsaWithSha3_256(Some(())) + ) + .unwrap(), (KeyType::Rsa, HashType::Sha3_256) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::RSA_WITH_SHA3_384_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::RsaWithSha3_384(Some(())) + ) + .unwrap(), (KeyType::Rsa, HashType::Sha3_384) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::RSA_WITH_SHA3_512_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::RsaWithSha3_512(Some(())) + ) + .unwrap(), (KeyType::Rsa, HashType::Sha3_512) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::ECDSA_WITH_SHA224_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::EcDsaWithSha224 + ) + .unwrap(), (KeyType::Ec, HashType::Sha224) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::ECDSA_WITH_SHA256_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::EcDsaWithSha256 + ) + .unwrap(), (KeyType::Ec, HashType::Sha256) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::ECDSA_WITH_SHA384_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::EcDsaWithSha384 + ) + .unwrap(), (KeyType::Ec, HashType::Sha384) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::ECDSA_WITH_SHA512_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::EcDsaWithSha512 + ) + .unwrap(), (KeyType::Ec, HashType::Sha512) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::ECDSA_WITH_SHA3_224_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::EcDsaWithSha3_224 + ) + .unwrap(), (KeyType::Ec, HashType::Sha3_224) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::ECDSA_WITH_SHA3_256_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::EcDsaWithSha3_256 + ) + .unwrap(), (KeyType::Ec, HashType::Sha3_256) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::ECDSA_WITH_SHA3_384_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::EcDsaWithSha3_384 + ) + .unwrap(), (KeyType::Ec, HashType::Sha3_384) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::ECDSA_WITH_SHA3_512_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::EcDsaWithSha3_512 + ) + .unwrap(), (KeyType::Ec, HashType::Sha3_512) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::ED25519_OID).unwrap(), + identify_key_hash_type_for_algorithm_params(&common::AlgorithmParameters::Ed25519) + .unwrap(), (KeyType::Ed25519, HashType::None) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::ED448_OID).unwrap(), + identify_key_hash_type_for_algorithm_params(&common::AlgorithmParameters::Ed448) + .unwrap(), (KeyType::Ed448, HashType::None) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::DSA_WITH_SHA224_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::DsaWithSha224 + ) + .unwrap(), (KeyType::Dsa, HashType::Sha224) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::DSA_WITH_SHA256_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::DsaWithSha256 + ) + .unwrap(), (KeyType::Dsa, HashType::Sha256) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::DSA_WITH_SHA384_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::DsaWithSha384 + ) + .unwrap(), (KeyType::Dsa, HashType::Sha384) ); assert_eq!( - identify_key_hash_type_for_oid(&oid::DSA_WITH_SHA512_OID).unwrap(), + identify_key_hash_type_for_algorithm_params( + &common::AlgorithmParameters::DsaWithSha512 + ) + .unwrap(), (KeyType::Dsa, HashType::Sha512) ); - assert!(identify_key_hash_type_for_oid(&oid::TLS_FEATURE_OID).is_err()); + assert!( + identify_key_hash_type_for_algorithm_params(&common::AlgorithmParameters::Other( + oid::TLS_FEATURE_OID, + None + )) + .is_err() + ); } #[test] From d60796a38fe7b08b84e62203e91945c87b6d1a8e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 7 May 2023 08:27:29 -0500 Subject: [PATCH 231/316] Use parameters instead of oids in another place (#8880) --- src/rust/cryptography-x509/src/common.rs | 2 +- src/rust/src/x509/ocsp.rs | 17 ++++++++++------- src/rust/src/x509/ocsp_req.rs | 2 +- src/rust/src/x509/ocsp_resp.rs | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs index f44308a8579e..65e583f113a2 100644 --- a/src/rust/cryptography-x509/src/common.rs +++ b/src/rust/cryptography-x509/src/common.rs @@ -19,7 +19,7 @@ impl AlgorithmIdentifier<'_> { } } -#[derive(asn1::Asn1DefinedByRead, asn1::Asn1DefinedByWrite, PartialEq, Hash, Clone)] +#[derive(asn1::Asn1DefinedByRead, asn1::Asn1DefinedByWrite, PartialEq, Eq, Hash, Clone)] pub enum AlgorithmParameters<'a> { #[defined_by(oid::SHA1_OID)] Sha1(asn1::Null), diff --git a/src/rust/src/x509/ocsp.rs b/src/rust/src/x509/ocsp.rs index 53a0f2c4ed8b..afa0b026ed1e 100644 --- a/src/rust/src/x509/ocsp.rs +++ b/src/rust/src/x509/ocsp.rs @@ -5,20 +5,23 @@ use crate::error::CryptographyResult; use crate::x509; use crate::x509::certificate::Certificate; +use cryptography_x509::common; use cryptography_x509::ocsp_req::CertID; -use cryptography_x509::{common, oid}; use once_cell::sync::Lazy; use std::collections::HashMap; -pub(crate) static OIDS_TO_HASH: Lazy> = Lazy::new(|| { +pub(crate) static ALGORITHM_PARAMETERS_TO_HASH: Lazy< + HashMap, &str>, +> = Lazy::new(|| { let mut h = HashMap::new(); - h.insert(&oid::SHA1_OID, "SHA1"); - h.insert(&oid::SHA224_OID, "SHA224"); - h.insert(&oid::SHA256_OID, "SHA256"); - h.insert(&oid::SHA384_OID, "SHA384"); - h.insert(&oid::SHA512_OID, "SHA512"); + h.insert(common::AlgorithmParameters::Sha1(()), "SHA1"); + h.insert(common::AlgorithmParameters::Sha224(()), "SHA224"); + h.insert(common::AlgorithmParameters::Sha256(()), "SHA256"); + h.insert(common::AlgorithmParameters::Sha384(()), "SHA384"); + h.insert(common::AlgorithmParameters::Sha512(()), "SHA512"); h }); + pub(crate) static HASH_NAME_TO_ALGORITHM_IDENTIFIERS: Lazy< HashMap<&str, common::AlgorithmIdentifier<'_>>, > = Lazy::new(|| { diff --git a/src/rust/src/x509/ocsp_req.rs b/src/rust/src/x509/ocsp_req.rs index b8faedb09dc2..235ac6ee10c5 100644 --- a/src/rust/src/x509/ocsp_req.rs +++ b/src/rust/src/x509/ocsp_req.rs @@ -86,7 +86,7 @@ impl OCSPRequest { let cert_id = self.cert_id(); let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; - match ocsp::OIDS_TO_HASH.get(&cert_id.hash_algorithm.oid()) { + match ocsp::ALGORITHM_PARAMETERS_TO_HASH.get(&cert_id.hash_algorithm.params) { Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), None => Err(CryptographyError::from( exceptions::UnsupportedAlgorithm::new_err(format!( diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index 15cf99d9fe55..942822b48168 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -479,7 +479,7 @@ fn singleresp_py_hash_algorithm<'p>( py: pyo3::Python<'p>, ) -> Result<&'p pyo3::PyAny, CryptographyError> { let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; - match ocsp::OIDS_TO_HASH.get(&resp.cert_id.hash_algorithm.oid()) { + match ocsp::ALGORITHM_PARAMETERS_TO_HASH.get(&resp.cert_id.hash_algorithm.params) { Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), None => Err(CryptographyError::from( exceptions::UnsupportedAlgorithm::new_err(format!( From b284ff959183aeaa8f986700ef119d0f08dd6af0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 7 May 2023 14:12:35 +0000 Subject: [PATCH 232/316] Bump certifi from 2022.12.7 to 2023.5.7 (#8881) Bumps [certifi](https://github.com/certifi/python-certifi) from 2022.12.7 to 2023.5.7. - [Commits](https://github.com/certifi/python-certifi/compare/2022.12.07...2023.05.07) --- updated-dependencies: - dependency-name: certifi dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 38ba5288477f..12b2f942e703 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -19,7 +19,7 @@ build==0.10.0 # via # check-sdist # cryptography (pyproject.toml) -certifi==2022.12.7 +certifi==2023.5.7 # via requests charset-normalizer==3.1.0 # via requests From 47b5ea6a9a914585a52bebe3d1e6be328a551734 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 7 May 2023 14:18:52 +0000 Subject: [PATCH 233/316] Bump libc from 0.2.142 to 0.2.143 in /src/rust (#8882) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.142 to 0.2.143. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.142...0.2.143) --- 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 cb554bb9763e..c7e79503c469 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -131,9 +131,9 @@ checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" [[package]] name = "libc" -version = "0.2.142" +version = "0.2.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" +checksum = "edc207893e85c5d6be840e969b496b53d94cec8be2d501b214f50daa97fa8024" [[package]] name = "lock_api" From 8ab4d1a58e6128f8c32981ee3f667e89d09c758b Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 7 May 2023 09:58:41 -0500 Subject: [PATCH 234/316] Try using the default LTO (#8883) --- src/rust/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 52e179a4c42e..d221cb17a9b9 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -32,7 +32,6 @@ name = "cryptography_rust" crate-type = ["cdylib"] [profile.release] -lto = "thin" overflow-checks = true [workspace] From 0f2b72bb12b698e5787241a54ea9132837a1ec9c Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 7 May 2023 11:01:33 -0500 Subject: [PATCH 235/316] invalid visible string support (#8884) * invalid visible string support this allows utf8 in visiblestring, which is not valid DER. we raise a warning when this happens, but allow it since belgian eIDs, among others, have encoding errors. Belgium fixed this by 2021 (and possibly earlier), but their eID certificates have 10 year validity. * review comments * clippy --- docs/development/test-vectors.rst | 2 + src/cryptography/utils.py | 1 + src/rust/cryptography-x509/src/common.rs | 37 ++++++++++++++++++- src/rust/cryptography-x509/src/extensions.rs | 3 +- src/rust/src/x509/certificate.rs | 11 ++++++ tests/x509/test_x509.py | 19 ++++++++++ .../belgian-eid-invalid-visiblestring.pem | 37 +++++++++++++++++++ 7 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 vectors/cryptography_vectors/x509/belgian-eid-invalid-visiblestring.pem diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 1916c57c4098..c84bdeff49fb 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -287,6 +287,8 @@ X.509 a subject DN with a bit string type. * ``cryptography-scts-tbs-precert.der`` - The "to-be-signed" pre-certificate bytes from ``cryptography-scts.pem``, with the SCT list extension removed. +* ``belgian-eid-invalid-visiblestring.pem`` - A certificate with UTF-8 + bytes in a ``VisibleString`` type. Custom X.509 Vectors ~~~~~~~~~~~~~~~~~~~~ diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index 651e8509acf4..719168168440 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -23,6 +23,7 @@ class CryptographyDeprecationWarning(UserWarning): DeprecatedIn36 = CryptographyDeprecationWarning DeprecatedIn37 = CryptographyDeprecationWarning DeprecatedIn40 = CryptographyDeprecationWarning +DeprecatedIn41 = CryptographyDeprecationWarning def _check_bytes(name: str, value: bytes) -> None: diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs index 65e583f113a2..9668ae237703 100644 --- a/src/rust/cryptography-x509/src/common.rs +++ b/src/rust/cryptography-x509/src/common.rs @@ -206,11 +206,46 @@ pub struct DHParams<'a> { pub q: Option>, } +/// A VisibleString ASN.1 element whose contents is not validated as meeting the +/// requirements (visible characters of IA5), and instead is only known to be +/// valid UTF-8. +pub struct UnvalidatedVisibleString<'a>(pub &'a str); + +impl<'a> UnvalidatedVisibleString<'a> { + pub fn as_str(&self) -> &'a str { + self.0 + } +} + +impl<'a> asn1::SimpleAsn1Readable<'a> for UnvalidatedVisibleString<'a> { + const TAG: asn1::Tag = asn1::VisibleString::TAG; + fn parse_data(data: &'a [u8]) -> asn1::ParseResult { + Ok(UnvalidatedVisibleString( + std::str::from_utf8(data) + .map_err(|_| asn1::ParseError::new(asn1::ParseErrorKind::InvalidValue))?, + )) + } +} + +impl<'a> asn1::SimpleAsn1Writable for UnvalidatedVisibleString<'a> { + const TAG: asn1::Tag = asn1::VisibleString::TAG; + fn write_data(&self, _: &mut asn1::WriteBuf) -> asn1::WriteResult { + unimplemented!(); + } +} + #[cfg(test)] mod tests { - use super::{Asn1ReadableOrWritable, RawTlv}; + use super::{Asn1ReadableOrWritable, RawTlv, UnvalidatedVisibleString}; use asn1::Asn1Readable; + #[test] + #[should_panic] + fn test_unvalidated_visible_string_write() { + let v = UnvalidatedVisibleString("foo"); + asn1::write_single(&v).unwrap(); + } + #[test] #[should_panic] fn test_asn1_readable_or_writable_unwrap_read() { diff --git a/src/rust/cryptography-x509/src/extensions.rs b/src/rust/cryptography-x509/src/extensions.rs index 11c6e54a4d34..0728633d4adb 100644 --- a/src/rust/cryptography-x509/src/extensions.rs +++ b/src/rust/cryptography-x509/src/extensions.rs @@ -87,7 +87,8 @@ pub struct NoticeReference<'a> { pub enum DisplayText<'a> { IA5String(asn1::IA5String<'a>), Utf8String(asn1::Utf8String<'a>), - VisibleString(asn1::VisibleString<'a>), + // Not validated due to certificates with UTF-8 in VisibleString. See PR #8884 + VisibleString(common::UnvalidatedVisibleString<'a>), BmpString(asn1::BMPString<'a>), } diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 58dcf2d5d3f2..98f1a073fef7 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -412,6 +412,17 @@ fn parse_display_text( DisplayText::IA5String(o) => Ok(pyo3::types::PyString::new(py, o.as_str()).to_object(py)), DisplayText::Utf8String(o) => Ok(pyo3::types::PyString::new(py, o.as_str()).to_object(py)), DisplayText::VisibleString(o) => { + if asn1::VisibleString::new(o.as_str()).is_none() { + let cryptography_warning = py + .import(pyo3::intern!(py, "cryptography.utils"))? + .getattr(pyo3::intern!(py, "DeprecatedIn41"))?; + pyo3::PyErr::warn( + py, + cryptography_warning, + "Invalid ASN.1 (UTF-8 characters in a VisibleString) in the explicit text and/or notice reference of the certificate policies extension. In a future version of cryptography, an exception will be raised.", + 1, + )?; + } Ok(pyo3::types::PyString::new(py, o.as_str()).to_object(py)) } DisplayText::BmpString(o) => { diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 4a3fb26c63ad..1de45192b550 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -1250,6 +1250,25 @@ def test_invalid_version_cert(self, backend): assert exc.value.parsed_version == 7 + def test_invalid_visiblestring_in_explicit_text(self, backend): + cert = _load_cert( + os.path.join( + "x509", + "belgian-eid-invalid-visiblestring.pem", + ), + x509.load_pem_x509_certificate, + ) + with pytest.warns(utils.DeprecatedIn41): + cp = cert.extensions.get_extension_for_class( + x509.CertificatePolicies + ).value + assert isinstance(cp, x509.CertificatePolicies) + assert cp[0].policy_qualifiers[1].explicit_text == ( + "Gebruik onderworpen aan aansprakelijkheidsbeperkingen, zie CPS " + "- Usage soumis à des limitations de responsabilité, voir CPS - " + "Verwendung unterliegt Haftungsbeschränkungen, gemäss CPS" + ) + def test_eq(self, backend): cert = _load_cert( os.path.join("x509", "custom", "post2000utctime.pem"), diff --git a/vectors/cryptography_vectors/x509/belgian-eid-invalid-visiblestring.pem b/vectors/cryptography_vectors/x509/belgian-eid-invalid-visiblestring.pem new file mode 100644 index 000000000000..17650782f99f --- /dev/null +++ b/vectors/cryptography_vectors/x509/belgian-eid-invalid-visiblestring.pem @@ -0,0 +1,37 @@ +-----BEGIN CERTIFICATE----- +MIIGYzCCBEugAwIBAgIQEAAAAAAAdQQMgK5bRTyOHTANBgkqhkiG9w0BAQsFADAz +MQswCQYDVQQGEwJCRTETMBEGA1UEAxMKQ2l0aXplbiBDQTEPMA0GA1UEBRMGMjAx +NjIzMB4XDTE2MDgyOTA5NDcwMFoXDTI2MDgyNDIzNTk1OVowbzELMAkGA1UEBhMC +QkUxIjAgBgNVBAMTGUVsc2UgRGUgUHJvZnQgKFNpZ25hdHVyZSkxETAPBgNVBAQT +CERlIFByb2Z0MRMwEQYDVQQqEwpFbHNlIEZyYW5zMRQwEgYDVQQFEws2OTA3MDMz +ODg1MDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANSMFzc0v5Fr5GM3 +1cvaF7obKH1mNUR5cAcNPdLbC8U8SzOIvArBIKToYJRQIxgy7S/XOPs7p/cnidQe +5yVNoIZlxWyB1nbbCR2c4rZJjzUz8bAXPKILjY7C+Q+Zxp6+8C6igDfd+n+eYuhU +u1kxPvGiZ+m+DuKTfjzhQAqG0kZteqwwlipJkt7FDsLxsgcxPBpMDm02sVL5pTme +rkY7mQpXZ5fpT2n2nzuNerxlfExeSdROAD/EZAxTAkuOgURWXmFBHPm0A9cipDYO +foyPcMO5/7JUPv7LWhRoMr+XrTBOVmkFxccJ8EXRtNxNVujwbjeUJp7Z+20ST1h/ +rDyNOKMCAwEAAaOCAjUwggIxMB8GA1UdIwQYMBaAFIIiihHTwEk9pIiqBydUoV6f +KmxqMHAGCCsGAQUFBwEBBGQwYjA2BggrBgEFBQcwAoYqaHR0cDovL2NlcnRzLmVp +ZC5iZWxnaXVtLmJlL2JlbGdpdW1yczQuY3J0MCgGCCsGAQUFBzABhhxodHRwOi8v +b2NzcC5laWQuYmVsZ2l1bS5iZS8yMIIBGAYDVR0gBIIBDzCCAQswggEHBgdgOAwB +AQIBMIH7MCwGCCsGAQUFBwIBFiBodHRwOi8vcmVwb3NpdG9yeS5laWQuYmVsZ2l1 +bS5iZTCBygYIKwYBBQUHAgIwgb0agbpHZWJydWlrIG9uZGVyd29ycGVuIGFhbiBh +YW5zcHJha2VsaWpraGVpZHNiZXBlcmtpbmdlbiwgemllIENQUyAtIFVzYWdlIHNv +dW1pcyDDoCBkZXMgbGltaXRhdGlvbnMgZGUgcmVzcG9uc2FiaWxpdMOpLCB2b2ly +IENQUyAtIFZlcndlbmR1bmcgdW50ZXJsaWVndCBIYWZ0dW5nc2Jlc2NocsOkbmt1 +bmdlbiwgZ2Vtw6RzcyBDUFMwOQYDVR0fBDIwMDAuoCygKoYoaHR0cDovL2NybC5l +aWQuYmVsZ2l1bS5iZS9laWRjMjAxNjIzLmNybDAOBgNVHQ8BAf8EBAMCBkAwEQYJ +YIZIAYb4QgEBBAQDAgUgMCIGCCsGAQUFBwEDBBYwFDAIBgYEAI5GAQEwCAYGBACO +RgEEMA0GCSqGSIb3DQEBCwUAA4ICAQABNGZci7JGuvzXfk5MJCX/2Py3M9//R9iN +E/b8brMP6aCHJuDnEW7RcGAyleQQJYrTQnizWqoHRnkQ4BjQCZCpTEhERvCJz9KC +J0L9+9M3TNDGLMY14Tu/h8Uga6vThXoxI4VK2Y3gEP5qWV0tMdbu+dLSLZ+O2qkj +vtk8apYLn/2MGQ/srbu6HOLATvAKMtkF2za6zY0VL1Se9gHaHQdI9nnXKA3YD/7n +C4UrqozruMqGRNCpWhD/fRgdHotRaD4ZDuC7hUZH2b+ldFII4tsZiXcVhX6RN7KF +h5Ji/F2K9vqA0TbMWUEfiULSQfNc86LOd4riJ5VeVYtUl5kcrfVWMGBPQaq7c3OG +G2L2x4rkB8mvRTeQZCU5ENuEZX34jZuKnv7pabdntzowE5VQWjLgFGQ7UyTFbImZ +cR+H5djrrzO3Uvnu6a9v0ILGCLqES06pgH/apwtpHQPhvCWA8KBqf2aTgpZ8GsFI +qTraP819yyr+GOOp/NO8EvcOsyjgWwzDvtpoLty3/wMXC5DBNoUb3W/uMju5MJ3E +2dthCxnP7ES2PbdGTDK8Jtbgp5sJtfV6GCjgHDsIL5XGy6CagDghEG84TrYvKxTG +PlmUThXhFRVjwv2tbpgFC7z/RwARqcNYxZKFKAHXCx6hWgSQbuEN5j6JFQh3ZUL+ +R2V64/XeBQ== +-----END CERTIFICATE----- From e129a1ddbcb359393bb2e45e00d2cfcf64336e39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 7 May 2023 20:03:37 +0000 Subject: [PATCH 236/316] Bump asn1 from 0.15.1 to 0.15.2 in /src/rust (#8886) Bumps [asn1](https://github.com/alex/rust-asn1) from 0.15.1 to 0.15.2. - [Commits](https://github.com/alex/rust-asn1/compare/0.15.1...0.15.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 +- src/rust/cryptography-x509/Cargo.toml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index c7e79503c469..0c044d097de6 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -16,18 +16,18 @@ checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" [[package]] name = "asn1" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3ffc84e382cf516922078c67853a781fdb4363cf364594df8eab5ef5485553" +checksum = "28c19b9324de5b815b6487e0f8098312791b09de0dbf3d5c2db1fe2d95bab973" dependencies = [ "asn1_derive", ] [[package]] name = "asn1_derive" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7124c4d563619518d0ad454032967d5645627033d4b6e4e17bb7ac0237241c81" +checksum = "a045c3ccad89f244a86bd1e6cf1a7bf645296e7692698b056399b6efd4639407" dependencies = [ "proc-macro2", "quote", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index d221cb17a9b9..3efbf1334343 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -10,7 +10,7 @@ rust-version = "1.56.0" [dependencies] once_cell = "1" pyo3 = { version = "0.18", features = ["abi3-py37"] } -asn1 = { version = "0.15.1", default-features = false } +asn1 = { version = "0.15.2", default-features = false } cryptography-cffi = { path = "cryptography-cffi" } cryptography-x509 = { path = "cryptography-x509" } cryptography-openssl = { path = "cryptography-openssl" } diff --git a/src/rust/cryptography-x509/Cargo.toml b/src/rust/cryptography-x509/Cargo.toml index 8c4d20537435..017d51dd44a3 100644 --- a/src/rust/cryptography-x509/Cargo.toml +++ b/src/rust/cryptography-x509/Cargo.toml @@ -8,4 +8,4 @@ publish = false rust-version = "1.56.0" [dependencies] -asn1 = { version = "0.15.1", default-features = false } +asn1 = { version = "0.15.2", default-features = false } From 8834b590ede72c79532ccd34857a6904c48d3634 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 7 May 2023 15:20:26 -0500 Subject: [PATCH 237/316] Print more rust dirs for debugging in mtime-fix (#8887) --- .github/actions/mtime-fix/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/mtime-fix/action.yml b/.github/actions/mtime-fix/action.yml index 0690132db689..42779037ce87 100644 --- a/.github/actions/mtime-fix/action.yml +++ b/.github/actions/mtime-fix/action.yml @@ -11,7 +11,7 @@ runs: echo "The git available is probably too old so checkout didn't create a real git clone, skipping mtime fix" exit 0 fi - ls -Rla src/rust/src src/_cffi_src + ls -Rla src/rust src/_cffi_src echo "Verifying commits are monotonic because if they're not caching gets wrecked" COMMIT_ORDER=$(git log --pretty=format:%cd --date=format-local:%Y%m%d%H%M.%S -5) SORTED_COMMIT_ORDER=$(git log --pretty=format:%cd --date=format-local:%Y%m%d%H%M.%S -5 | sort -rn) @@ -22,5 +22,5 @@ runs: echo "Setting mtimes for dirs" for f in $(git ls-tree -t -r --name-only HEAD src/rust src/_cffi_src); do touch -t $(git log --pretty=format:%cd --date=format-local:%Y%m%d%H%M.%S -1 HEAD -- "$f") "$f"; done echo "Done" - ls -Rla src/rust/src src/_cffi_src + ls -Rla src/rust src/_cffi_src shell: bash From b436fafa7cf43c96f66d50162ac495c99ade1f39 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 7 May 2023 15:26:45 -0500 Subject: [PATCH 238/316] add signature_algorithm_parameters to certificate (#8795) this allows easier verification of cert signatures, but more specifically allows PSS signature verification --- CHANGELOG.rst | 3 + docs/x509/reference.rst | 52 +++++++++ src/cryptography/x509/base.py | 10 ++ src/rust/cryptography-x509/src/common.rs | 57 +++++++++- src/rust/cryptography-x509/src/oid.rs | 13 +++ src/rust/src/x509/certificate.rs | 130 +++++++++++++++++++++-- tests/x509/test_x509.py | 92 ++++++++++++++-- 7 files changed, 338 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fcc6f28cbc47..d4fd576242b0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -20,6 +20,9 @@ Changelog * Implemented support for equality checks on all asymmetric public key types. * Added support for ``aes256-gcm@openssh.com`` encrypted keys in :func:`~cryptography.hazmat.primitives.serialization.load_ssh_private_key`. +* Added support for obtaining X.509 certificate signature algorithm parameters + (including PSS) via + :meth:`~cryptography.x509.Certificate.signature_algorithm_parameters`. .. _v40-0-2: diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index 71a6eb1799b5..647666c5c67e 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -146,6 +146,30 @@ X.509 Reference -----END CERTIFICATE----- """.strip() + rsa_pss_pem_cert = b""" + -----BEGIN CERTIFICATE----- + MIIDfTCCAjCgAwIBAgIUP4D/5rcT93vdYGPhsKf+hbes/JgwQgYJKoZIhvcNAQEK + MDWgDzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEF + AKIEAgIA3jAaMRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wHhcNMjIwNDMwMjAz + MTE4WhcNMzMwNDEyMjAzMTE4WjAaMRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8w + ggEgMAsGCSqGSIb3DQEBCgOCAQ8AMIIBCgKCAQEAt1jpboUoNppBVamc+nA+zEjl + jn/gPbRFCvyveRd8Yr0p8y1mlmjKXcQlXcHPVM4TopgFXqDykIHXxJxLV56ysb4K + UGe0nxpmhEso5ZGUgkDIIoH0NAQAsS8rS2ZzNJcLrLGrMY6DRgFsa+G6h2DvMwgl + nsX++a8FIm7Vu+OZnfWpDEuhJU4TRtHVviJSYkFMckyYBB48k1MU+0b4pezHconZ + mMEisBFFbwarNvowf2i/tRESe3myKXfiJsZZ2UzdE3FqycSgw1tx8qV/Z8myozUW + uihIdw8TGbbsJhEeVFxQEP/DVzC6HHDI3EVpr2jPYeIE60hhZwM7jUmQscLerQID + AQABo1MwUTAdBgNVHQ4EFgQUb1QD8QEIQn5DALIAujTDATssNcQwHwYDVR0jBBgw + FoAUb1QD8QEIQn5DALIAujTDATssNcQwDwYDVR0TAQH/BAUwAwEB/zBCBgkqhkiG + 9w0BAQowNaAPMA0GCWCGSAFlAwQCAQUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFl + AwQCAQUAogQCAgDeA4IBAQAvKBXlx07tdmtfhNTPn16dupBIS5344ZE4tfGSE5Ir + iA1X0bukKQ6V+6xJXGreaIw0wvwtIeI/R0JwcR114HBDqjt40vklyNSpGCJzgkfD + Q/d8JXN/MLyQrk+5F9JMy+HuZAgefAQAjugC6389Klpqx2Z1CgwmALhjIs48GnMp + Iz9vU2O6RDkMBlBRdmfkJVjhhPvJYpDDW1ic5O3pxtMoiC1tAHHMm4gzM1WCFeOh + cDNxABlvVNPTnqkOhKBmmwRaBwdvvksgeu2RyBNR0KEy44gWzYB9/Ter2t4Z8ASq + qCv8TuYr2QGaCnI2FVS5S9n6l4JNkFHqPMtuhrkr3gEz + -----END CERTIFICATE----- + """.strip() + Loading Certificates ~~~~~~~~~~~~~~~~~~~~ @@ -413,6 +437,34 @@ X.509 Certificate Object >>> cert.signature_algorithm_oid + .. attribute:: signature_algorithm_parameters + + .. versionadded:: 41.0.0 + + Returns the parameters of the signature algorithm used to sign the + certificate. For RSA signatures it will return either a + :class:`~cryptography.hazmat.primitives.asymmetric.padding.PKCS1v15` or + :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS` object. + + For ECDSA signatures it will + return an :class:`~cryptography.hazmat.primitives.asymmetric.ec.ECDSA`. + + For EdDSA and DSA signatures it will return ``None``. + + These objects can be used to verify signatures on the certificate. + + :returns: None, + :class:`~cryptography.hazmat.primitives.asymmetric.padding.PKCS1v15`, + :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS`, or + :class:`~cryptography.hazmat.primitives.asymmetric.ec.ECDSA` + + .. doctest:: + + >>> from cryptography.hazmat.primitives.asymmetric import padding + >>> pss_cert = x509.load_pem_x509_certificate(rsa_pss_pem_cert) + >>> isinstance(pss_cert.signature_algorithm_parameters, padding.PSS) + True + .. attribute:: extensions :type: :class:`Extensions` diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index 63eaa6bd4013..64453eb70aa5 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -17,6 +17,7 @@ ec, ed448, ed25519, + padding, rsa, x448, x25519, @@ -232,6 +233,15 @@ def signature_algorithm_oid(self) -> ObjectIdentifier: Returns the ObjectIdentifier of the signature algorithm. """ + @property + @abc.abstractmethod + def signature_algorithm_parameters( + self, + ) -> typing.Union[None, padding.PSS, padding.PKCS1v15, ec.ECDSA]: + """ + Returns the signature algorithm parameters. + """ + @property @abc.abstractmethod def extensions(self) -> Extensions: diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs index 9668ae237703..d099716599ea 100644 --- a/src/rust/cryptography-x509/src/common.rs +++ b/src/rust/cryptography-x509/src/common.rs @@ -6,7 +6,7 @@ use crate::oid; use asn1::Asn1DefinedByWritable; use std::marker::PhantomData; -#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash, Clone)] +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash, Clone, Eq)] pub struct AlgorithmIdentifier<'a> { pub oid: asn1::DefinedByMarker, #[defined_by(oid)] @@ -55,6 +55,11 @@ pub enum AlgorithmParameters<'a> { #[defined_by(oid::ECDSA_WITH_SHA3_512_OID)] EcDsaWithSha3_512, + #[defined_by(oid::RSA_WITH_SHA1_OID)] + RsaWithSha1(Option), + #[defined_by(oid::RSA_WITH_SHA1_ALT_OID)] + RsaWithSha1Alt(Option), + #[defined_by(oid::RSA_WITH_SHA224_OID)] RsaWithSha224(Option), #[defined_by(oid::RSA_WITH_SHA256_OID)] @@ -73,6 +78,12 @@ pub enum AlgorithmParameters<'a> { #[defined_by(oid::RSA_WITH_SHA3_512_OID)] RsaWithSha3_512(Option), + // RsaPssParameters must be present in Certificate::tbs_cert::signature_alg::params + // and Certificate::signature_alg::params, but Certificate::tbs_cert::spki::algorithm::oid + // also uses RSASSA_PSS_OID and the params field is omitted since it has no meaning there. + #[defined_by(oid::RSASSA_PSS_OID)] + RsaPss(Option>>), + #[defined_by(oid::DSA_WITH_SHA224_OID)] DsaWithSha224, #[defined_by(oid::DSA_WITH_SHA256_OID)] @@ -205,6 +216,50 @@ pub struct DHParams<'a> { pub g: asn1::BigUint<'a>, pub q: Option>, } +// RSA-PSS ASN.1 default hash algorithm +pub const PSS_SHA1_HASH_ALG: AlgorithmIdentifier<'_> = AlgorithmIdentifier { + oid: asn1::DefinedByMarker::marker(), + params: AlgorithmParameters::Sha1(()), +}; + +// This is defined as an AlgorithmIdentifier in RFC 4055, +// but the mask generation algorithm **must** contain an AlgorithmIdentifier +// in its params, so we define it this way. +#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, Clone, PartialEq, Eq)] +pub struct MaskGenAlgorithm<'a> { + pub oid: asn1::ObjectIdentifier, + pub params: AlgorithmIdentifier<'a>, +} + +// RSA-PSS ASN.1 default mask gen algorithm +pub const PSS_SHA1_MASK_GEN_ALG: MaskGenAlgorithm<'_> = MaskGenAlgorithm { + oid: oid::MGF1_OID, + params: PSS_SHA1_HASH_ALG, +}; + +// From RFC 4055 section 3.1: +// RSASSA-PSS-params ::= SEQUENCE { +// hashAlgorithm [0] HashAlgorithm DEFAULT +// sha1Identifier, +// maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT +// mgf1SHA1Identifier, +// saltLength [2] INTEGER DEFAULT 20, +// trailerField [3] INTEGER DEFAULT 1 } +#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, Clone, PartialEq, Eq)] +pub struct RsaPssParameters<'a> { + #[explicit(0)] + #[default(PSS_SHA1_HASH_ALG)] + pub hash_algorithm: AlgorithmIdentifier<'a>, + #[explicit(1)] + #[default(PSS_SHA1_MASK_GEN_ALG)] + pub mask_gen_algorithm: MaskGenAlgorithm<'a>, + #[explicit(2)] + #[default(20u16)] + pub salt_length: u16, + #[explicit(3)] + #[default(1u8)] + _trailer_field: u8, +} /// A VisibleString ASN.1 element whose contents is not validated as meeting the /// requirements (visible characters of IA5), and instead is only known to be diff --git a/src/rust/cryptography-x509/src/oid.rs b/src/rust/cryptography-x509/src/oid.rs index b2d22ebddb1c..ac80b9a31365 100644 --- a/src/rust/cryptography-x509/src/oid.rs +++ b/src/rust/cryptography-x509/src/oid.rs @@ -57,6 +57,8 @@ pub const ECDSA_WITH_SHA3_384_OID: asn1::ObjectIdentifier = pub const ECDSA_WITH_SHA3_512_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 3, 12); +pub const RSA_WITH_SHA1_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 5); +pub const RSA_WITH_SHA1_ALT_OID: asn1::ObjectIdentifier = asn1::oid!(1, 3, 14, 3, 2, 29); pub const RSA_WITH_SHA224_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 14); pub const RSA_WITH_SHA256_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 11); pub const RSA_WITH_SHA384_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 12); @@ -84,3 +86,14 @@ pub const SHA224_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, pub const SHA256_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 1); pub const SHA384_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 2); pub const SHA512_OID: asn1::ObjectIdentifier = asn1::oid!(2, 16, 840, 1, 101, 3, 4, 2, 3); +pub const SHA3_224_OID: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 224); +pub const SHA3_256_OID: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 256); +pub const SHA3_384_OID: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 384); +pub const SHA3_512_OID: asn1::ObjectIdentifier = + asn1::oid!(1, 3, 6, 1, 4, 1, 37476, 3, 2, 1, 99, 7, 512); + +pub const MGF1_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 8); +pub const RSASSA_PSS_OID: asn1::ObjectIdentifier = asn1::oid!(1, 2, 840, 113549, 1, 1, 10); diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 98f1a073fef7..03d8ae883256 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -17,10 +17,28 @@ use cryptography_x509::extensions::{ }; use cryptography_x509::extensions::{Extension, Extensions}; use cryptography_x509::{common, name, oid}; +use once_cell::sync::Lazy; use pyo3::{IntoPy, ToPyObject}; use std::collections::hash_map::DefaultHasher; +use std::collections::HashMap; use std::hash::{Hash, Hasher}; +// This is similar to a hashmap in ocsp.rs but contains more hash algorithms +// that aren't allowable in OCSP +static HASH_OIDS_TO_HASH: Lazy> = Lazy::new(|| { + let mut h = HashMap::new(); + h.insert(&oid::SHA1_OID, "SHA1"); + h.insert(&oid::SHA224_OID, "SHA224"); + h.insert(&oid::SHA256_OID, "SHA256"); + h.insert(&oid::SHA384_OID, "SHA384"); + h.insert(&oid::SHA512_OID, "SHA512"); + h.insert(&oid::SHA3_224_OID, "SHA3_224"); + h.insert(&oid::SHA3_256_OID, "SHA3_256"); + h.insert(&oid::SHA3_384_OID, "SHA3_384"); + h.insert(&oid::SHA3_512_OID, "SHA3_512"); + h +}); + #[ouroboros::self_referencing] pub(crate) struct OwnedCertificate { data: pyo3::Py, @@ -241,15 +259,25 @@ impl Certificate { let sig_oids_to_hash = py .import(pyo3::intern!(py, "cryptography.hazmat._oid"))? .getattr(pyo3::intern!(py, "_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(CryptographyError::from( - exceptions::UnsupportedAlgorithm::new_err(format!( - "Signature algorithm OID: {} not recognized", - self.raw.borrow_value().signature_alg.oid(), - )), - )), + match &self.raw.borrow_value().signature_alg.params { + common::AlgorithmParameters::RsaPss(opt_pss) => { + let pss = opt_pss.as_ref().ok_or_else(|| { + pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters") + })?; + hash_oid_py_hash(py, pss.hash_algorithm.oid().clone()) + } + _ => { + let hash_alg = sig_oids_to_hash.get_item(self.signature_algorithm_oid(py)?); + match hash_alg { + Ok(data) => Ok(data), + Err(_) => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + self.raw.borrow_value().signature_alg.oid() + )), + )), + } + } } } @@ -258,6 +286,74 @@ impl Certificate { oid_to_py_oid(py, self.raw.borrow_value().signature_alg.oid()) } + #[getter] + fn signature_algorithm_parameters<'p>( + &'p self, + py: pyo3::Python<'p>, + ) -> CryptographyResult<&'p pyo3::PyAny> { + match &self.raw.borrow_value().signature_alg.params { + common::AlgorithmParameters::RsaPss(opt_pss) => { + let pss = opt_pss.as_ref().ok_or_else(|| { + pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters") + })?; + if pss.mask_gen_algorithm.oid != oid::MGF1_OID { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err(format!( + "Unsupported mask generation OID: {}", + pss.mask_gen_algorithm.oid + )), + )); + } + let py_mask_gen_hash_alg = + hash_oid_py_hash(py, pss.mask_gen_algorithm.params.oid().clone())?; + let padding = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.padding" + ))?; + let py_mgf = padding + .getattr(pyo3::intern!(py, "MGF1"))? + .call1((py_mask_gen_hash_alg,))?; + Ok(padding + .getattr(pyo3::intern!(py, "PSS"))? + .call1((py_mgf, pss.salt_length))?) + } + common::AlgorithmParameters::RsaWithSha1(_) + | common::AlgorithmParameters::RsaWithSha1Alt(_) + | common::AlgorithmParameters::RsaWithSha224(_) + | common::AlgorithmParameters::RsaWithSha256(_) + | common::AlgorithmParameters::RsaWithSha384(_) + | common::AlgorithmParameters::RsaWithSha512(_) + | common::AlgorithmParameters::RsaWithSha3_224(_) + | common::AlgorithmParameters::RsaWithSha3_256(_) + | common::AlgorithmParameters::RsaWithSha3_384(_) + | common::AlgorithmParameters::RsaWithSha3_512(_) => { + let pkcs = py + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.padding" + ))? + .getattr(pyo3::intern!(py, "PKCS1v15"))? + .call0()?; + Ok(pkcs) + } + common::AlgorithmParameters::EcDsaWithSha224 + | common::AlgorithmParameters::EcDsaWithSha256 + | common::AlgorithmParameters::EcDsaWithSha384 + | common::AlgorithmParameters::EcDsaWithSha512 + | common::AlgorithmParameters::EcDsaWithSha3_224 + | common::AlgorithmParameters::EcDsaWithSha3_256 + | common::AlgorithmParameters::EcDsaWithSha3_384 + | common::AlgorithmParameters::EcDsaWithSha3_512 => Ok(py + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.ec" + ))? + .getattr(pyo3::intern!(py, "ECDSA"))? + .call1((self.signature_hash_algorithm(py)?,))?), + _ => Ok(py.None().into_ref(py)), + } + } + #[getter] fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult { let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; @@ -853,6 +949,22 @@ pub fn parse_cert_ext<'p>( } } +fn hash_oid_py_hash( + py: pyo3::Python<'_>, + oid: asn1::ObjectIdentifier, +) -> CryptographyResult<&pyo3::PyAny> { + let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; + match HASH_OIDS_TO_HASH.get(&oid) { + Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), + None => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + &oid + )), + )), + } +} + pub(crate) fn time_from_py( py: pyo3::Python<'_>, val: &pyo3::PyAny, diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 1de45192b550..a32dfca930cf 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -729,15 +729,15 @@ def test_get_revoked_certificate_doesnt_reorder( assert crl[2].serial_number == 3 +@pytest.mark.supported( + only_if=lambda backend: ( + not backend._lib.CRYPTOGRAPHY_IS_LIBRESSL + and not backend._lib.CRYPTOGRAPHY_IS_BORINGSSL + and not backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111E + ), + skip_message="Does not support RSA PSS loading", +) class TestRSAPSSCertificate: - @pytest.mark.supported( - only_if=lambda backend: ( - not backend._lib.CRYPTOGRAPHY_IS_LIBRESSL - and not backend._lib.CRYPTOGRAPHY_IS_BORINGSSL - and not backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111E - ), - skip_message="Does not support RSA PSS loading", - ) def test_load_cert_pub_key(self, backend): cert = _load_cert( os.path.join("x509", "custom", "rsa_pss_cert.pem"), @@ -751,7 +751,47 @@ def test_load_cert_pub_key(self, backend): assert isinstance(expected_pub_key, rsa.RSAPublicKey) pub_key = cert.public_key() assert isinstance(pub_key, rsa.RSAPublicKey) - assert pub_key.public_numbers() == expected_pub_key.public_numbers() + assert pub_key == expected_pub_key + pss = cert.signature_algorithm_parameters + assert isinstance(pss, padding.PSS) + assert isinstance(pss._mgf, padding.MGF1) + assert isinstance(pss._mgf._algorithm, hashes.SHA256) + assert pss._salt_length == 222 + assert isinstance(cert.signature_hash_algorithm, hashes.SHA256) + pub_key.verify( + cert.signature, + cert.tbs_certificate_bytes, + pss, + cert.signature_hash_algorithm, + ) + + def test_invalid_mgf(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "rsa_pss_cert_invalid_mgf.der"), + x509.load_der_x509_certificate, + ) + with pytest.raises(ValueError): + cert.signature_algorithm_parameters + + def test_unsupported_mgf_hash(self, backend): + cert = _load_cert( + os.path.join( + "x509", "custom", "rsa_pss_cert_unsupported_mgf_hash.der" + ), + x509.load_der_x509_certificate, + ) + with pytest.raises(UnsupportedAlgorithm): + cert.signature_algorithm_parameters + + def test_no_sig_params(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "rsa_pss_cert_no_sig_params.der"), + x509.load_der_x509_certificate, + ) + with pytest.raises(ValueError): + cert.signature_algorithm_parameters + with pytest.raises(ValueError): + cert.signature_hash_algorithm class TestRSACertificate: @@ -768,6 +808,28 @@ def test_load_pem_cert(self, backend): assert ( cert.signature_algorithm_oid == SignatureAlgorithmOID.RSA_WITH_SHA1 ) + assert isinstance( + cert.signature_algorithm_parameters, padding.PKCS1v15 + ) + + def test_check_pkcs1_signature_algorithm_parameters(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "ca", "rsa_ca.pem"), + x509.load_pem_x509_certificate, + ) + assert isinstance(cert, x509.Certificate) + assert isinstance( + cert.signature_algorithm_parameters, padding.PKCS1v15 + ) + pk = cert.public_key() + assert isinstance(pk, rsa.RSAPublicKey) + assert cert.signature_hash_algorithm is not None + pk.verify( + cert.signature, + cert.tbs_certificate_bytes, + cert.signature_algorithm_parameters, + cert.signature_hash_algorithm, + ) def test_load_legacy_pem_header(self, backend): cert = _load_cert( @@ -4599,6 +4661,7 @@ def test_load_dsa_cert(self, backend): assert isinstance(cert.signature_hash_algorithm, hashes.SHA1) public_key = cert.public_key() assert isinstance(public_key, dsa.DSAPublicKey) + assert cert.signature_algorithm_parameters is None num = public_key.public_numbers() assert num.y == int( "4c08bfe5f2d76649c80acf7d431f6ae2124b217abc8c9f6aca776ddfa94" @@ -4847,6 +4910,15 @@ def test_load_ecdsa_cert(self, backend): 16, ) assert isinstance(num.curve, ec.SECP384R1) + assert isinstance(cert.signature_algorithm_parameters, ec.ECDSA) + assert isinstance( + cert.signature_algorithm_parameters.algorithm, hashes.SHA384 + ) + public_key.verify( + cert.signature, + cert.tbs_certificate_bytes, + cert.signature_algorithm_parameters, + ) def test_load_bitstring_dn(self, backend): cert = _load_cert( @@ -5590,6 +5662,7 @@ def test_load_pem_cert(self, backend): assert cert.serial_number == 9579446940964433301 assert cert.signature_hash_algorithm is None assert cert.signature_algorithm_oid == SignatureAlgorithmOID.ED25519 + assert cert.signature_algorithm_parameters is None def test_deepcopy(self, backend): cert = _load_cert( @@ -5635,6 +5708,7 @@ def test_load_pem_cert(self, backend): assert cert.serial_number == 448 assert cert.signature_hash_algorithm is None assert cert.signature_algorithm_oid == SignatureAlgorithmOID.ED448 + assert cert.signature_algorithm_parameters is None def test_verify_directly_issued_by_ed448(self, backend): issuer_private_key = ed448.Ed448PrivateKey.generate() From 8cd2765d13da03aec5bfea87d922c63e56277e03 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 13:22:29 +0000 Subject: [PATCH 239/316] Bump libc from 0.2.143 to 0.2.144 in /src/rust (#8891) Bumps [libc](https://github.com/rust-lang/libc) from 0.2.143 to 0.2.144. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.143...0.2.144) --- 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 0c044d097de6..d76c498485ba 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -131,9 +131,9 @@ checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" [[package]] name = "libc" -version = "0.2.143" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc207893e85c5d6be840e969b496b53d94cec8be2d501b214f50daa97fa8024" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "lock_api" From 81916ba1b9ca55133adfc233980e3a80b60addff Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 23:03:06 -0400 Subject: [PATCH 240/316] Bump BoringSSL and/or OpenSSL in CI (#8893) Co-authored-by: pyca-boringbot[bot] --- .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 9a97b41f1d49..e066969acb8d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of May 06, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "b1c6f45f1fe6d808555d04a41bb44b322e4f4c1d"}} - # Latest commit on the OpenSSL master branch, as of May 06, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "6aeb42eca97227c8235af0986d1525ee4a916504"}} + # Latest commit on the BoringSSL master branch, as of May 09, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "2aae3f58b42e75690f28853f712a2e204857b7f6"}} + # Latest commit on the OpenSSL master branch, as of May 09, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3868807d2fe5a72aa897ce5f7f7ba7e9cc3c09cb"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 6bb05529a49a0ce532b7e4bf65ac6246d4d57e91 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 03:37:12 +0000 Subject: [PATCH 241/316] Bump quote from 1.0.26 to 1.0.27 in /src/rust (#8894) Bumps [quote](https://github.com/dtolnay/quote) from 1.0.26 to 1.0.27. - [Release notes](https://github.com/dtolnay/quote/releases) - [Commits](https://github.com/dtolnay/quote/compare/1.0.26...1.0.27) --- updated-dependencies: - dependency-name: quote 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 d76c498485ba..9fdd2313155b 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -354,9 +354,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" dependencies = [ "proc-macro2", ] From 3b8cb2b7337a7dc3a004555fd4bfa032e35a34af Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 9 May 2023 02:29:16 -0400 Subject: [PATCH 242/316] Don't install coverage, it's not needed (#8895) --- .github/workflows/ci.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e066969acb8d..b06ae9771f57 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -105,7 +105,7 @@ jobs: # pypy3-3.8 and pypy3-3.9 -- both of them show up as 7.3.11. key: ${{ matrix.PYTHON.VERSION }}-${{ steps.setup-python.outputs.python-version }}-${{ matrix.PYTHON.NOXSESSION }}-${{ env.OPENSSL_HASH }} - - run: python -m pip install -c ci-constraints-requirements.txt 'nox' coverage[toml] + - run: python -m pip install -c ci-constraints-requirements.txt 'nox' - name: Create nox environment run: | nox -v --install-only @@ -182,7 +182,7 @@ jobs: - run: | echo "OPENSSL_FORCE_FIPS_MODE=1" >> $GITHUB_ENV if: matrix.IMAGE.FIPS - - run: /venv/bin/python -m pip install -c ci-constraints-requirements.txt 'nox' coverage + - run: /venv/bin/python -m pip install -c ci-constraints-requirements.txt 'nox' - run: '/venv/bin/nox -v --install-only -s tests' env: RUSTUP_HOME: /root/.rustup @@ -229,7 +229,7 @@ jobs: - name: Clone wycheproof timeout-minutes: 2 uses: ./.github/actions/wycheproof - - run: python -m pip install -c ci-constraints-requirements.txt 'nox' coverage[toml] + - run: python -m pip install -c ci-constraints-requirements.txt 'nox' - name: Create nox environment run: nox -v --install-only -s tests env: @@ -304,7 +304,7 @@ jobs: - name: Clone wycheproof timeout-minutes: 2 uses: ./.github/actions/wycheproof - - run: python -m pip install -c ci-constraints-requirements.txt 'nox' coverage[toml] cffi + - run: python -m pip install -c ci-constraints-requirements.txt 'nox' cffi - name: Create nox environment run: nox -v --install-only -s tests env: @@ -379,7 +379,7 @@ jobs: python-version: ${{ matrix.PYTHON.VERSION }} architecture: 'x64' # we force this right now so that it will install the universal2 on arm64 - - run: python -m pip install -c ci-constraints-requirements.txt 'nox' coverage[toml] + - run: python -m pip install -c ci-constraints-requirements.txt 'nox' - name: Clone wycheproof timeout-minutes: 2 @@ -442,7 +442,7 @@ jobs: timeout-minutes: 2 with: key: ${{ matrix.PYTHON.NOXSESSION }}-${{ matrix.WINDOWS.ARCH }}-${{ steps.setup-python.outputs.python-version }} - - run: python -m pip install -c ci-constraints-requirements.txt "nox" coverage[toml] + - run: python -m pip install -c ci-constraints-requirements.txt "nox" - uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 with: From 1f883568e5ab88fa34a6d041195d368bff5dc702 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Wed, 10 May 2023 00:17:59 +0000 Subject: [PATCH 243/316] Bump BoringSSL and/or OpenSSL in CI (#8897) Co-authored-by: pyca-boringbot[bot] --- .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 b06ae9771f57..41fac5d7beff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,8 +43,8 @@ jobs: - {VERSION: "3.12-dev", NOXSESSION: "tests"} # Latest commit on the BoringSSL master branch, as of May 09, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "2aae3f58b42e75690f28853f712a2e204857b7f6"}} - # Latest commit on the OpenSSL master branch, as of May 09, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3868807d2fe5a72aa897ce5f7f7ba7e9cc3c09cb"}} + # Latest commit on the OpenSSL master branch, as of May 10, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "8c63b14296f117b07781509ced529a8955d78fb9"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 9dfb1200948523046d6996f0cd81c7fec2060ab6 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 9 May 2023 20:25:05 -0400 Subject: [PATCH 244/316] Added a missing rerun-if stanza (#8899) --- src/rust/cryptography-cffi/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rust/cryptography-cffi/build.rs b/src/rust/cryptography-cffi/build.rs index 9a93b50bc438..4a40990b9da4 100644 --- a/src/rust/cryptography-cffi/build.rs +++ b/src/rust/cryptography-cffi/build.rs @@ -25,6 +25,7 @@ fn main() { let out_dir = env::var("OUT_DIR").unwrap(); // FIXME: maybe pyo3-build-config should provide a way to do this? let python = env::var("PYO3_PYTHON").unwrap_or_else(|_| "python3".to_string()); + println!("cargo:rerun-if-env-changed=PYO3_PYTHON"); println!("cargo:rerun-if-changed=../../_cffi_src/"); let output = Command::new(&python) .env("OUT_DIR", &out_dir) From c6887af98236de1343def4544282812b60b3a383 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 10 May 2023 09:25:18 +0900 Subject: [PATCH 245/316] update cache key to reflect all rust files, not just cargo.lock (#8898) rust uses mtime to determine if files are fresh or not. However, if the mtime of a file in main is newer than the mtime of a commit in a PR then it will load the cache and there will be weird errors since it thinks the cache is new enough but in reality the code has changed. This change ties our cache keys to all our rust files, not just our cargo.lock, and should resolve this issue. --- .github/actions/cache/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/cache/action.yml b/.github/actions/cache/action.yml index 3e8c300d03e1..37b9cc81bd37 100644 --- a/.github/actions/cache/action.yml +++ b/.github/actions/cache/action.yml @@ -43,11 +43,11 @@ runs: ~/.cargo/registry/cache/ src/rust/target/ ${{ inputs.additional-paths }} - key: cargo-pip-${{ runner.os }}-${{ runner.arch }}-${{ inputs.key }}-3-${{ hashFiles('**/Cargo.lock') }}-${{ steps.rust-version.version }} + key: cargo-pip-${{ runner.os }}-${{ runner.arch }}-${{ inputs.key }}-3-${{ hashFiles('**/Cargo.lock', '**/*.rs') }}-${{ steps.rust-version.version }} - name: Size of cache items run: | du -sh ~/.cargo/registry/index/ du -sh ~/.cargo/registry/cache/ du -sh src/rust/target/ shell: bash - if: ${{ steps.cache.outputs.cache-hit }} \ No newline at end of file + if: ${{ steps.cache.outputs.cache-hit }} From 1ff6208ec739b27ae2826d866f4d2bd3db77fd87 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Wed, 10 May 2023 07:14:49 -0400 Subject: [PATCH 246/316] certificate: add a `get_extension` helper (#8892) * certificate: add a `get_extension` helper Signed-off-by: William Woodruff * certificate: OID by ref Signed-off-by: William Woodruff * certificate: syntax Signed-off-by: William Woodruff * x509, src: `check_duplicate_extensions` Signed-off-by: William Woodruff * src: simplify Signed-off-by: William Woodruff * src: everyone loves newtypes Signed-off-by: William Woodruff * rust: refactor-o-rama Signed-off-by: William Woodruff * src: look upon my works Signed-off-by: William Woodruff * src: continue blasting the code Signed-off-by: William Woodruff * src/rust: actually commit my changes Signed-off-by: William Woodruff * src: clippage Signed-off-by: William Woodruff * relocate Signed-off-by: William Woodruff * src: dedupe Signed-off-by: William Woodruff * src: cleanup Signed-off-by: William Woodruff * clippage Signed-off-by: William Woodruff * src: dedupe Signed-off-by: William Woodruff * common: cleanup Signed-off-by: William Woodruff * src: unused impls Signed-off-by: William Woodruff * more deletion Signed-off-by: William Woodruff * clippage Signed-off-by: William Woodruff * extensions: add a `get_extension` test Signed-off-by: William Woodruff * extensions: unused derives Signed-off-by: William Woodruff * tests/x509: dup ext check for tbs_precertificate_bytes Signed-off-by: William Woodruff * certificate: remove `extensions()` Signed-off-by: William Woodruff * extensions: docs Signed-off-by: William Woodruff * extensions: newtype Signed-off-by: William Woodruff * rust: better error types, dedupe Signed-off-by: William Woodruff extensions: unwrap -> expect Signed-off-by: William Woodruff * Revert "rust: better error types, dedupe" This reverts commit 212b75ff2f69a3b3cfc9d6a55949f23877f8f618. --------- Signed-off-by: William Woodruff --- src/rust/cryptography-x509/src/certificate.rs | 9 +- src/rust/cryptography-x509/src/crl.rs | 10 ++- src/rust/cryptography-x509/src/csr.rs | 2 +- src/rust/cryptography-x509/src/extensions.rs | 83 ++++++++++++++++++- src/rust/cryptography-x509/src/ocsp_req.rs | 10 ++- src/rust/cryptography-x509/src/ocsp_resp.rs | 10 ++- src/rust/src/x509/certificate.rs | 28 ++++--- src/rust/src/x509/common.rs | 31 +++---- src/rust/src/x509/crl.rs | 10 ++- src/rust/src/x509/csr.rs | 11 ++- src/rust/src/x509/ocsp_req.rs | 6 +- src/rust/src/x509/ocsp_resp.rs | 29 ++++--- tests/x509/test_x509.py | 14 ++++ 13 files changed, 193 insertions(+), 60 deletions(-) diff --git a/src/rust/cryptography-x509/src/certificate.rs b/src/rust/cryptography-x509/src/certificate.rs index bb9a666f5f78..59960242b202 100644 --- a/src/rust/cryptography-x509/src/certificate.rs +++ b/src/rust/cryptography-x509/src/certificate.rs @@ -4,6 +4,7 @@ use crate::common; use crate::extensions; +use crate::extensions::Extensions; use crate::name; #[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Clone)] @@ -31,7 +32,13 @@ pub struct TbsCertificate<'a> { #[implicit(2)] pub subject_unique_id: Option>, #[explicit(3)] - pub extensions: Option>, + pub raw_extensions: Option>, +} + +impl<'a> TbsCertificate<'a> { + pub fn extensions(&'a self) -> Result>, asn1::ObjectIdentifier> { + Extensions::from_raw_extensions(self.raw_extensions.as_ref()) + } } #[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, PartialEq, Clone)] diff --git a/src/rust/cryptography-x509/src/crl.rs b/src/rust/cryptography-x509/src/crl.rs index 3a47e0a37727..c81a3c4a95fd 100644 --- a/src/rust/cryptography-x509/src/crl.rs +++ b/src/rust/cryptography-x509/src/crl.rs @@ -2,7 +2,11 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::{common, extensions, name}; +use crate::{ + common, + extensions::{self}, + name, +}; pub type ReasonFlags<'a> = Option, asn1::OwnedBitString>>; @@ -31,14 +35,14 @@ pub struct TBSCertList<'a> { pub next_update: Option, pub revoked_certificates: RevokedCertificates<'a>, #[explicit(0)] - pub crl_extensions: Option>, + pub raw_crl_extensions: Option>, } #[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash, Clone)] pub struct RevokedCertificate<'a> { pub user_certificate: asn1::BigUint<'a>, pub revocation_date: common::Time, - pub crl_entry_extensions: Option>, + pub raw_crl_entry_extensions: Option>, } #[derive(asn1::Asn1Read, asn1::Asn1Write)] diff --git a/src/rust/cryptography-x509/src/csr.rs b/src/rust/cryptography-x509/src/csr.rs index c23d22d0fd11..d2cf9b5e2739 100644 --- a/src/rust/cryptography-x509/src/csr.rs +++ b/src/rust/cryptography-x509/src/csr.rs @@ -26,7 +26,7 @@ pub struct CertificationRequestInfo<'a> { impl CertificationRequestInfo<'_> { pub fn get_extension_attribute( &self, - ) -> Result>, asn1::ParseError> { + ) -> Result>, asn1::ParseError> { for attribute in self.attributes.unwrap_read().clone() { if attribute.type_id == oid::EXTENSION_REQUEST || attribute.type_id == oid::MS_EXTENSION_REQUEST diff --git a/src/rust/cryptography-x509/src/extensions.rs b/src/rust/cryptography-x509/src/extensions.rs index 0728633d4adb..b1138fec206e 100644 --- a/src/rust/cryptography-x509/src/extensions.rs +++ b/src/rust/cryptography-x509/src/extensions.rs @@ -2,16 +2,62 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. +use std::collections::HashSet; + use crate::common; use crate::crl; use crate::name; -pub type Extensions<'a> = common::Asn1ReadableOrWritable< +pub type RawExtensions<'a> = common::Asn1ReadableOrWritable< 'a, asn1::SequenceOf<'a, Extension<'a>>, asn1::SequenceOfWriter<'a, Extension<'a>, Vec>>, >; +/// An invariant-enforcing wrapper for `RawExtensions`. +/// +/// In particular, an `Extensions` cannot be constructed from a `RawExtensions` +/// that contains duplicated extensions (by OID). +pub struct Extensions<'a>(RawExtensions<'a>); + +impl<'a> Extensions<'a> { + /// Create an `Extensions` from the given `RawExtensions`. + /// + /// Returns an `Err` variant containing the first duplicated extension's + /// OID, if there are any duplicates. + pub fn from_raw_extensions( + raw: Option<&RawExtensions<'a>>, + ) -> Result, asn1::ObjectIdentifier> { + match raw { + Some(raw_exts) => { + let mut seen_oids = HashSet::new(); + + for ext in raw_exts.unwrap_read().clone() { + if !seen_oids.insert(ext.extn_id.clone()) { + return Err(ext.extn_id); + } + } + + Ok(Some(Self(raw_exts.clone()))) + } + None => Ok(None), + } + } + + /// Retrieves the extension identified by the given OID, + /// or None if the extension is not present (or no extensions are present). + pub fn get_extension(&self, oid: &asn1::ObjectIdentifier) -> Option { + let mut extensions = self.0.unwrap_read().clone(); + + extensions.find(|ext| &ext.extn_id == oid) + } + + /// Returns a reference to the underlying extensions. + pub fn as_raw(&self) -> &RawExtensions<'_> { + &self.0 + } +} + #[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Eq, Hash, Clone)] pub struct Extension<'a> { pub extn_id: asn1::ObjectIdentifier, @@ -174,3 +220,38 @@ pub struct BasicConstraints { pub ca: bool, pub path_length: Option, } + +#[cfg(test)] +mod tests { + use asn1::SequenceOfWriter; + + use crate::oid::{AUTHORITY_KEY_IDENTIFIER_OID, BASIC_CONSTRAINTS_OID}; + + use super::{BasicConstraints, Extension, Extensions}; + + #[test] + fn test_get_extension() { + let extension_value = BasicConstraints { + ca: true, + path_length: Some(3), + }; + let extension = Extension { + extn_id: BASIC_CONSTRAINTS_OID, + critical: true, + extn_value: &asn1::write_single(&extension_value).unwrap(), + }; + let extensions = SequenceOfWriter::new(vec![extension]); + + let der = asn1::write_single(&extensions).unwrap(); + + let extensions: Extensions = + Extensions::from_raw_extensions(Some(&asn1::parse_single(&der).unwrap())) + .unwrap() + .unwrap(); + + assert!(&extensions.get_extension(&BASIC_CONSTRAINTS_OID).is_some()); + assert!(&extensions + .get_extension(&AUTHORITY_KEY_IDENTIFIER_OID) + .is_none()); + } +} diff --git a/src/rust/cryptography-x509/src/ocsp_req.rs b/src/rust/cryptography-x509/src/ocsp_req.rs index 1e096e71f1da..ba54d391f506 100644 --- a/src/rust/cryptography-x509/src/ocsp_req.rs +++ b/src/rust/cryptography-x509/src/ocsp_req.rs @@ -2,7 +2,11 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::{common, extensions, name}; +use crate::{ + common, + extensions::{self}, + name, +}; #[derive(asn1::Asn1Read, asn1::Asn1Write)] pub struct TBSRequest<'a> { @@ -17,14 +21,14 @@ pub struct TBSRequest<'a> { asn1::SequenceOfWriter<'a, Request<'a>>, >, #[explicit(2)] - pub request_extensions: Option>, + pub raw_request_extensions: Option>, } #[derive(asn1::Asn1Read, asn1::Asn1Write)] pub struct Request<'a> { pub req_cert: CertID<'a>, #[explicit(0)] - pub single_request_extensions: Option>, + pub single_request_extensions: Option>, } #[derive(asn1::Asn1Read, asn1::Asn1Write)] diff --git a/src/rust/cryptography-x509/src/ocsp_resp.rs b/src/rust/cryptography-x509/src/ocsp_resp.rs index f7620f6aa601..21f01e2c7375 100644 --- a/src/rust/cryptography-x509/src/ocsp_resp.rs +++ b/src/rust/cryptography-x509/src/ocsp_resp.rs @@ -2,7 +2,11 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. -use crate::{certificate, common, crl, extensions, name, ocsp_req}; +use crate::{ + certificate, common, crl, + extensions::{self}, + name, ocsp_req, +}; #[derive(asn1::Asn1Read, asn1::Asn1Write)] pub struct OCSPResponse<'a> { @@ -47,7 +51,7 @@ pub struct ResponseData<'a> { asn1::SequenceOfWriter<'a, SingleResponse<'a>, Vec>>, >, #[explicit(1)] - pub response_extensions: Option>, + pub raw_response_extensions: Option>, } #[derive(asn1::Asn1Read, asn1::Asn1Write)] @@ -66,7 +70,7 @@ pub struct SingleResponse<'a> { #[explicit(0)] pub next_update: Option, #[explicit(1)] - pub single_extensions: Option>, + pub raw_single_extensions: Option>, } #[derive(asn1::Asn1Read, asn1::Asn1Write)] diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 03d8ae883256..3784b1c9a4b0 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -9,13 +9,13 @@ use crate::error::{CryptographyError, CryptographyResult}; use crate::x509::{extensions, sct, sign}; use crate::{exceptions, x509}; use cryptography_x509::common::Asn1ReadableOrWritable; +use cryptography_x509::extensions::Extension; use cryptography_x509::extensions::{ AuthorityKeyIdentifier, BasicConstraints, DisplayText, DistributionPoint, DistributionPointName, MSCertificateTemplate, NameConstraints, PolicyConstraints, - PolicyInformation, PolicyQualifierInfo, Qualifier, SequenceOfAccessDescriptions, + PolicyInformation, PolicyQualifierInfo, Qualifier, RawExtensions, SequenceOfAccessDescriptions, SequenceOfSubtrees, UserNotice, }; -use cryptography_x509::extensions::{Extension, Extensions}; use cryptography_x509::{common, name, oid}; use once_cell::sync::Lazy; use pyo3::{IntoPy, ToPyObject}; @@ -193,9 +193,9 @@ impl Certificate { let val = self.raw.borrow_value(); let mut tbs_precert = val.tbs_cert.clone(); // Remove the SCT list extension - match tbs_precert.extensions { - Some(extensions) => { - let readable_extensions = extensions.unwrap_read().clone(); + match val.tbs_cert.extensions() { + Ok(Some(extensions)) => { + let readable_extensions = extensions.as_raw().unwrap_read().clone(); let ext_count = readable_extensions.len(); let filtered_extensions: Vec> = readable_extensions .filter(|x| x.extn_id != oid::PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS_OID) @@ -207,18 +207,26 @@ impl Certificate { ), )); } - let filtered_extensions: Extensions<'_> = Asn1ReadableOrWritable::new_write( + let filtered_extensions: RawExtensions<'_> = Asn1ReadableOrWritable::new_write( asn1::SequenceOfWriter::new(filtered_extensions), ); - tbs_precert.extensions = Some(filtered_extensions); + tbs_precert.raw_extensions = Some(filtered_extensions); let result = asn1::write_single(&tbs_precert)?; Ok(pyo3::types::PyBytes::new(py, &result)) } - None => Err(CryptographyError::from( + Ok(None) => Err(CryptographyError::from( pyo3::exceptions::PyValueError::new_err( "Could not find any extensions in TBS certificate", ), )), + Err(oid) => { + let oid_obj = oid_to_py_oid(py, &oid)?; + Err(exceptions::DuplicateExtension::new_err(( + format!("Duplicate {} extension found", oid), + oid_obj.into_py(py), + )) + .into()) + } } } @@ -360,7 +368,7 @@ impl Certificate { x509::parse_and_cache_extensions( py, &mut self.cached_extensions, - &self.raw.borrow_value().tbs_cert.extensions, + &self.raw.borrow_value().tbs_cert.raw_extensions, |oid, ext_data| match *oid { oid::PRECERT_POISON_OID => { asn1::parse_single::<()>(ext_data)?; @@ -1035,7 +1043,7 @@ fn create_x509_certificate( spki: asn1::parse_single(spki_bytes)?, issuer_unique_id: None, subject_unique_id: None, - extensions: x509::common::encode_extensions( + raw_extensions: x509::common::encode_extensions( py, builder.getattr(pyo3::intern!(py, "_extensions"))?, extensions::encode_extension, diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index 571963e36b63..94ae58d386c5 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -6,11 +6,10 @@ use crate::asn1::{oid_to_py_oid, py_oid_to_oid}; use crate::error::{CryptographyError, CryptographyResult}; use crate::{exceptions, x509}; use cryptography_x509::common::{Asn1ReadableOrWritable, AttributeTypeValue, RawTlv}; -use cryptography_x509::extensions::{AccessDescription, Extension, Extensions}; +use cryptography_x509::extensions::{AccessDescription, Extension, Extensions, RawExtensions}; use cryptography_x509::name::{GeneralName, Name, OtherName, UnvalidatedIA5String}; use pyo3::types::IntoPyDict; use pyo3::{IntoPy, ToPyObject}; -use std::collections::HashSet; /// Parse all sections in a PEM file and return the first matching section. /// If no matching sections are found, return an error. @@ -391,27 +390,30 @@ pub(crate) fn parse_and_cache_extensions< >( py: pyo3::Python<'p>, cached_extensions: &mut Option, - raw_exts: &Option>, + raw_extensions: &Option>, parse_ext: F, ) -> pyo3::PyResult { if let Some(cached) = cached_extensions { return Ok(cached.clone_ref(py)); } + let extensions = match Extensions::from_raw_extensions(raw_extensions.as_ref()) { + Ok(extensions) => extensions, + Err(oid) => { + let oid_obj = oid_to_py_oid(py, &oid)?; + return Err(exceptions::DuplicateExtension::new_err(( + format!("Duplicate {} extension found", oid), + oid_obj.into_py(py), + ))); + } + }; + let x509_module = py.import(pyo3::intern!(py, "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.unwrap_read().clone() { + if let Some(extensions) = extensions { + for raw_ext in extensions.as_raw().unwrap_read().clone() { let oid_obj = oid_to_py_oid(py, &raw_ext.extn_id)?; - if seen_oids.contains(&raw_ext.extn_id) { - return Err(exceptions::DuplicateExtension::new_err(( - format!("Duplicate {} extension found", raw_ext.extn_id), - oid_obj.into_py(py), - ))); - } - let extn_value = match parse_ext(&raw_ext.extn_id, raw_ext.extn_value)? { Some(e) => e, None => x509_module.call_method1( @@ -424,7 +426,6 @@ pub(crate) fn parse_and_cache_extensions< (oid_obj, raw_ext.critical, extn_value), )?; exts.append(ext_obj)?; - seen_oids.insert(raw_ext.extn_id); } } let extensions = x509_module @@ -445,7 +446,7 @@ pub(crate) fn encode_extensions< py: pyo3::Python<'p>, py_exts: &'p pyo3::PyAny, encode_ext: F, -) -> pyo3::PyResult>> { +) -> pyo3::PyResult>> { let unrecognized_extension_type: &pyo3::types::PyType = py .import(pyo3::intern!(py, "cryptography.x509"))? .getattr(pyo3::intern!(py, "UnrecognizedExtension"))? diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index e2c4b9c09b9e..6bb08779a0a2 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -260,11 +260,13 @@ impl CertificateRevocationList { #[getter] fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult { + let tbs_cert_list = &self.owned.borrow_value().tbs_cert_list; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; x509::parse_and_cache_extensions( py, &mut self.cached_extensions, - &self.owned.borrow_value().tbs_cert_list.crl_extensions, + &tbs_cert_list.raw_crl_extensions, |oid, ext_data| match *oid { oid::CRL_NUMBER_OID => { let bignum = asn1::parse_single::>(ext_data)?; @@ -498,7 +500,7 @@ impl RevokedCertificate { x509::parse_and_cache_extensions( py, &mut self.cached_extensions, - &self.owned.borrow_value().crl_entry_extensions, + &self.owned.borrow_value().raw_crl_entry_extensions, |oid, ext_data| parse_crl_entry_ext(py, oid.clone(), ext_data), ) } @@ -594,7 +596,7 @@ fn create_x509_crl( user_certificate: asn1::BigUint::new(py_uint_to_big_endian_bytes(py, serial_number)?) .unwrap(), revocation_date: x509::certificate::time_from_py(py, py_revocation_date)?, - crl_entry_extensions: x509::common::encode_extensions( + raw_crl_entry_extensions: x509::common::encode_extensions( py, py_revoked_cert.getattr(pyo3::intern!(py, "extensions"))?, extensions::encode_extension, @@ -618,7 +620,7 @@ fn create_x509_crl( asn1::SequenceOfWriter::new(revoked_certs), )) }, - crl_extensions: x509::common::encode_extensions( + raw_crl_extensions: x509::common::encode_extensions( py, builder.getattr(pyo3::intern!(py, "_extensions"))?, extensions::encode_extension, diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index 35aee5c9e501..7ceed3511daa 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -211,7 +211,7 @@ impl CertificateSigningRequest { #[getter] fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult { - let exts = self + let raw_exts = self .raw .borrow_value() .csr_info @@ -222,9 +222,12 @@ impl CertificateSigningRequest { ) })?; - x509::parse_and_cache_extensions(py, &mut self.cached_extensions, &exts, |oid, ext_data| { - certificate::parse_cert_ext(py, oid.clone(), ext_data) - }) + x509::parse_and_cache_extensions( + py, + &mut self.cached_extensions, + &raw_exts, + |oid, ext_data| certificate::parse_cert_ext(py, oid.clone(), ext_data), + ) } #[getter] diff --git a/src/rust/src/x509/ocsp_req.rs b/src/rust/src/x509/ocsp_req.rs index 235ac6ee10c5..bd5aecad0ec7 100644 --- a/src/rust/src/x509/ocsp_req.rs +++ b/src/rust/src/x509/ocsp_req.rs @@ -108,11 +108,13 @@ impl OCSPRequest { #[getter] fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult { + let tbs_request = &self.raw.borrow_value().tbs_request; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; x509::parse_and_cache_extensions( py, &mut self.cached_extensions, - &self.raw.borrow_value().tbs_request.request_extensions, + &tbs_request.raw_request_extensions, |oid, value| { match *oid { oid::NONCE_OID => { @@ -228,7 +230,7 @@ fn create_ocsp_request( request_list: common::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new( &reqs, )), - request_extensions: extensions, + raw_request_extensions: extensions, }, optional_signature: None, }; diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index 942822b48168..728eb92cef38 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -316,20 +316,22 @@ impl OCSPResponse { #[getter] fn extensions(&mut self, py: pyo3::Python<'_>) -> pyo3::PyResult { self.requires_successful_response()?; + + let response_data = &self + .raw + .borrow_value() + .response_bytes + .as_ref() + .unwrap() + .response + .get() + .tbs_response_data; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; x509::parse_and_cache_extensions( py, &mut self.cached_extensions, - &self - .raw - .borrow_value() - .response_bytes - .as_ref() - .unwrap() - .response - .get() - .tbs_response_data - .response_extensions, + &response_data.raw_response_extensions, |oid, ext_data| { match oid { &oid::NONCE_OID => { @@ -362,11 +364,12 @@ impl OCSPResponse { .response .get(), )?; + let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; x509::parse_and_cache_extensions( py, &mut self.cached_single_extensions, - &single_resp.single_extensions, + &single_resp.raw_single_extensions, |oid, ext_data| match oid { &oid::SIGNED_CERTIFICATE_TIMESTAMPS_OID => { let contents = asn1::parse_single::<&[u8]>(ext_data)?; @@ -628,7 +631,7 @@ fn create_ocsp_response( cert_status, next_update, this_update, - single_extensions: None, + raw_single_extensions: None, }]; borrowed_cert = responder_cert.borrow(); @@ -669,7 +672,7 @@ fn create_ocsp_response( responses: common::Asn1ReadableOrWritable::new_write(asn1::SequenceOfWriter::new( responses, )), - response_extensions: x509::common::encode_extensions( + raw_response_extensions: x509::common::encode_extensions( py, builder.getattr(pyo3::intern!(py, "_extensions"))?, extensions::encode_extension, diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index a32dfca930cf..b33e09ce518f 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -1000,6 +1000,20 @@ def test_tbs_certificate_bytes(self, backend): cert.signature_hash_algorithm, ) + def test_tbs_precertificate_bytes_duplicate_extensions_raises( + self, backend + ): + cert = _load_cert( + os.path.join("x509", "custom", "two_basic_constraints.pem"), + x509.load_pem_x509_certificate, + ) + + with pytest.raises( + x509.DuplicateExtension, + match="Duplicate 2.5.29.19 extension found", + ): + cert.tbs_precertificate_bytes + def test_tbs_precertificate_bytes_no_extensions_raises(self, backend): cert = _load_cert( os.path.join("x509", "v1_cert.pem"), From a8aaf19c3eb8d2ee7855d6b2c09ebe32f86aa7d5 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 10 May 2023 15:20:23 -0400 Subject: [PATCH 247/316] Make Extensions contain an optional RawExtensions (#8900) This matter models how x.509 represents these things, and will make it easier to make Extensions an iterator in the future --- src/rust/cryptography-x509/src/certificate.rs | 2 +- src/rust/cryptography-x509/src/extensions.rs | 20 +++++++++---------- src/rust/src/x509/certificate.rs | 19 +++++++++++------- src/rust/src/x509/common.rs | 4 ++-- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/rust/cryptography-x509/src/certificate.rs b/src/rust/cryptography-x509/src/certificate.rs index 59960242b202..2a5616e93ef9 100644 --- a/src/rust/cryptography-x509/src/certificate.rs +++ b/src/rust/cryptography-x509/src/certificate.rs @@ -36,7 +36,7 @@ pub struct TbsCertificate<'a> { } impl<'a> TbsCertificate<'a> { - pub fn extensions(&'a self) -> Result>, asn1::ObjectIdentifier> { + pub fn extensions(&'a self) -> Result, asn1::ObjectIdentifier> { Extensions::from_raw_extensions(self.raw_extensions.as_ref()) } } diff --git a/src/rust/cryptography-x509/src/extensions.rs b/src/rust/cryptography-x509/src/extensions.rs index b1138fec206e..51c283af352c 100644 --- a/src/rust/cryptography-x509/src/extensions.rs +++ b/src/rust/cryptography-x509/src/extensions.rs @@ -18,7 +18,7 @@ pub type RawExtensions<'a> = common::Asn1ReadableOrWritable< /// /// In particular, an `Extensions` cannot be constructed from a `RawExtensions` /// that contains duplicated extensions (by OID). -pub struct Extensions<'a>(RawExtensions<'a>); +pub struct Extensions<'a>(Option>); impl<'a> Extensions<'a> { /// Create an `Extensions` from the given `RawExtensions`. @@ -27,7 +27,7 @@ impl<'a> Extensions<'a> { /// OID, if there are any duplicates. pub fn from_raw_extensions( raw: Option<&RawExtensions<'a>>, - ) -> Result, asn1::ObjectIdentifier> { + ) -> Result { match raw { Some(raw_exts) => { let mut seen_oids = HashSet::new(); @@ -38,22 +38,22 @@ impl<'a> Extensions<'a> { } } - Ok(Some(Self(raw_exts.clone()))) + Ok(Self(Some(raw_exts.clone()))) } - None => Ok(None), + None => Ok(Self(None)), } } /// Retrieves the extension identified by the given OID, /// or None if the extension is not present (or no extensions are present). pub fn get_extension(&self, oid: &asn1::ObjectIdentifier) -> Option { - let mut extensions = self.0.unwrap_read().clone(); - - extensions.find(|ext| &ext.extn_id == oid) + self.0 + .as_ref() + .and_then(|exts| exts.unwrap_read().clone().find(|ext| &ext.extn_id == oid)) } /// Returns a reference to the underlying extensions. - pub fn as_raw(&self) -> &RawExtensions<'_> { + pub fn as_raw(&self) -> &Option> { &self.0 } } @@ -245,9 +245,7 @@ mod tests { let der = asn1::write_single(&extensions).unwrap(); let extensions: Extensions = - Extensions::from_raw_extensions(Some(&asn1::parse_single(&der).unwrap())) - .unwrap() - .unwrap(); + Extensions::from_raw_extensions(Some(&asn1::parse_single(&der).unwrap())).unwrap(); assert!(&extensions.get_extension(&BASIC_CONSTRAINTS_OID).is_some()); assert!(&extensions diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 3784b1c9a4b0..dbe761fb9b19 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -194,8 +194,17 @@ impl Certificate { let mut tbs_precert = val.tbs_cert.clone(); // Remove the SCT list extension match val.tbs_cert.extensions() { - Ok(Some(extensions)) => { - let readable_extensions = extensions.as_raw().unwrap_read().clone(); + Ok(extensions) => { + let readable_extensions = match extensions.as_raw() { + Some(raw_exts) => raw_exts.unwrap_read().clone(), + None => { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err( + "Could not find any extensions in TBS certificate", + ), + )) + } + }; let ext_count = readable_extensions.len(); let filtered_extensions: Vec> = readable_extensions .filter(|x| x.extn_id != oid::PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS_OID) @@ -210,15 +219,11 @@ impl Certificate { let filtered_extensions: RawExtensions<'_> = Asn1ReadableOrWritable::new_write( asn1::SequenceOfWriter::new(filtered_extensions), ); + tbs_precert.raw_extensions = Some(filtered_extensions); let result = asn1::write_single(&tbs_precert)?; Ok(pyo3::types::PyBytes::new(py, &result)) } - Ok(None) => Err(CryptographyError::from( - pyo3::exceptions::PyValueError::new_err( - "Could not find any extensions in TBS certificate", - ), - )), Err(oid) => { let oid_obj = oid_to_py_oid(py, &oid)?; Err(exceptions::DuplicateExtension::new_err(( diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index 94ae58d386c5..3c42f0c5d31e 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -410,8 +410,8 @@ pub(crate) fn parse_and_cache_extensions< let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; let exts = pyo3::types::PyList::empty(py); - if let Some(extensions) = extensions { - for raw_ext in extensions.as_raw().unwrap_read().clone() { + if let Some(extensions) = extensions.as_raw() { + for raw_ext in extensions.unwrap_read().clone() { let oid_obj = oid_to_py_oid(py, &raw_ext.extn_id)?; let extn_value = match parse_ext(&raw_ext.extn_id, raw_ext.extn_value)? { From 998e86659ae750562ecc0bcf0eabd1828fd5c9ed Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Thu, 11 May 2023 00:17:31 +0000 Subject: [PATCH 248/316] Bump BoringSSL and/or OpenSSL in CI (#8905) Co-authored-by: pyca-boringbot[bot] --- .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 41fac5d7beff..521295b9d9f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of May 09, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "2aae3f58b42e75690f28853f712a2e204857b7f6"}} - # Latest commit on the OpenSSL master branch, as of May 10, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "8c63b14296f117b07781509ced529a8955d78fb9"}} + # Latest commit on the BoringSSL master branch, as of May 11, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "c6dd304d2c628277b710ab50ce9eed660696756d"}} + # Latest commit on the OpenSSL master branch, as of May 11, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "20d4dc8898edc12806ead2100ac09b907662aff6"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From cfee3c85a7d7e9c60f8041678c3070380ac3ca3d Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 11 May 2023 08:29:39 +0800 Subject: [PATCH 249/316] add RSA PSS SHA1 hash algorithm + SHA1 MGF1 test vector (#8906) --- docs/development/test-vectors.rst | 2 ++ .../x509/ee-pss-sha1-cert.pem | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 vectors/cryptography_vectors/x509/ee-pss-sha1-cert.pem diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index c84bdeff49fb..2a90eb30bedf 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -289,6 +289,8 @@ X.509 bytes from ``cryptography-scts.pem``, with the SCT list extension removed. * ``belgian-eid-invalid-visiblestring.pem`` - A certificate with UTF-8 bytes in a ``VisibleString`` type. +* ``ee-pss-sha1-cert.pem`` - An RSA PSS certificate using a SHA1 signature and + SHA1 for MGF1 from the OpenSSL test suite. Custom X.509 Vectors ~~~~~~~~~~~~~~~~~~~~ diff --git a/vectors/cryptography_vectors/x509/ee-pss-sha1-cert.pem b/vectors/cryptography_vectors/x509/ee-pss-sha1-cert.pem new file mode 100644 index 000000000000..b504aea5813a --- /dev/null +++ b/vectors/cryptography_vectors/x509/ee-pss-sha1-cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDFDCCAfygAwIBAgIBAjANBgkqhkiG9w0BAQowADANMQswCQYDVQQDDAJDQTAg +Fw0xNzA0MjQyMTE5NDlaGA8yMTE3MDQyNTIxMTk0OVowEzERMA8GA1UEAwwIUFNT +LVNIQTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCo/4lYYYWu3tss +D9Vz++K3qBt6dWAr1H08c3a1rt6TL38kkG3JHPSKOM2fooAWVsu0LLuT5Rcf/w3G +Q/4xNPgo2HXpo7uIgu+jcuJTYgVFTeAxl++qnRDSWA2eBp4yuxsIVl1lDz9mjsI2 +oBH/wFk1/Ukc3RxCMwZ4rgQ4I+XndWfTlK1aqUAfrFkQ9QzBZK1KxMY1U7OWaoIb +FYvRmavknm+UqtKW5Vf7jJFkijwkFsbSGb6CYBM7YrDtPh2zyvlr3zG5ep5LR2in +Kcc/SuIiJ7TvkGPX79ByST5brbkb1Ctvhmjd1XMSuEPJ3EEPoqNGT4tniIQPYf55 +NB9KiR+3AgMBAAGjdzB1MB0GA1UdDgQWBBTnm+IqrYpsOst2UeWOB5gil+FzojAf +BgNVHSMEGDAWgBS0ETPx1+Je91OeICIQT4YGvx/JXjAJBgNVHRMEAjAAMBMGA1Ud +JQQMMAoGCCsGAQUFBwMBMBMGA1UdEQQMMAqCCFBTUy1TSEExMA0GCSqGSIb3DQEB +CjAAA4IBAQCC4qIOu7FVYMvRx13IrvzviF+RFRRfAD5NZSPFw5+riLMeRlA4Pdw/ +vCctNIpqjDaSFu8BRTUuyHPXSIvPo0Rl64TsfQNHP1Ut1/8XCecYCEBx/ROJHbM5 +YjoHMCAy+mR3f4BK1827Mp5U/wRJ6ljvE5EbALQ06ZEuIO6zqEAO6AROUCjWSyFd +z9fkEHS0XmploIywH4QXR7X+ueWOE3n76x+vziM4qoGsYxy0sxePfTWM1DscT1Kt +l5skZdZEKo6J8m8ImxfmtLutky2/tw5cdeWbovX3xfipabjPqpzO9Tf9aa4iblJa +AEQwRss+D6ixFO1rNKs1fjFva7A+9lrO +-----END CERTIFICATE----- From 1ef3cdb616c7a304e75c89ad458e49c1fbd5943f Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 11 May 2023 09:09:56 +0800 Subject: [PATCH 250/316] support X.509 certificate PSS signing (#8888) * support X.509 certificate PSS signing no CSR, CRL, etc * handle PSS.(MAX_LENGTH, DIGEST_LENGTH), review feedback * name the kwarg * test improvements * skip if sha3 isn't supported --- CHANGELOG.rst | 3 + docs/x509/reference.rst | 18 +- .../hazmat/bindings/_rust/x509.pyi | 2 + src/cryptography/x509/base.py | 14 +- src/rust/cryptography-x509/src/common.rs | 18 +- src/rust/src/pkcs7.rs | 17 +- src/rust/src/x509/certificate.rs | 7 +- src/rust/src/x509/crl.rs | 16 +- src/rust/src/x509/csr.rs | 15 +- src/rust/src/x509/ocsp_resp.rs | 15 +- src/rust/src/x509/sign.rs | 145 ++++++++++++++-- tests/x509/test_x509.py | 163 ++++++++++++++++++ 12 files changed, 405 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d4fd576242b0..5073ce32b98e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -23,6 +23,9 @@ Changelog * Added support for obtaining X.509 certificate signature algorithm parameters (including PSS) via :meth:`~cryptography.x509.Certificate.signature_algorithm_parameters`. +* Support signing :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS` + X.509 certificates via the new keyword-only argument ``rsa_padding`` on + :meth:`~cryptography.x509.CertificateBuilder.sign`. .. _v40-0-2: diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index 647666c5c67e..e14c8ffc1093 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -872,7 +872,7 @@ X.509 Certificate Builder :param critical: Set to ``True`` if the extension must be understood and handled by whoever reads the certificate. - .. method:: sign(private_key, algorithm) + .. method:: sign(private_key, algorithm, *, rsa_padding=None) Sign the certificate using the CA's private key. @@ -891,6 +891,22 @@ X.509 Certificate Builder :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` otherwise. + :param rsa_padding: + + .. versionadded:: 41.0.0 + + This is a keyword-only argument. If ``private_key`` is an + ``RSAPrivateKey`` then this can be set to either + :class:`~cryptography.hazmat.primitives.asymmetric.padding.PKCS1v15` or + :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS` to sign + with those respective paddings. If this is ``None`` then RSA + keys will default to ``PKCS1v15`` padding. All other key types **must** + not pass a value other than ``None``. + + :type rsa_padding: ``None``, + :class:`~cryptography.hazmat.primitives.asymmetric.padding.PKCS1v15`, + or :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS` + :returns: :class:`~cryptography.x509.Certificate` diff --git a/src/cryptography/hazmat/bindings/_rust/x509.pyi b/src/cryptography/hazmat/bindings/_rust/x509.pyi index 71c8d5c22c3e..24b2f5e3a78c 100644 --- a/src/cryptography/hazmat/bindings/_rust/x509.pyi +++ b/src/cryptography/hazmat/bindings/_rust/x509.pyi @@ -6,6 +6,7 @@ import typing from cryptography import x509 from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric.padding import PSS, PKCS1v15 from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes def load_pem_x509_certificate(data: bytes) -> x509.Certificate: ... @@ -23,6 +24,7 @@ def create_x509_certificate( builder: x509.CertificateBuilder, private_key: PrivateKeyTypes, hash_algorithm: typing.Optional[hashes.HashAlgorithm], + padding: typing.Optional[typing.Union[PKCS1v15, PSS]], ) -> x509.Certificate: ... def create_x509_csr( builder: x509.CertificateSigningRequestBuilder, diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index 64453eb70aa5..576385e088d8 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -924,6 +924,10 @@ def sign( private_key: CertificateIssuerPrivateKeyTypes, algorithm: typing.Optional[_AllowedHashTypes], backend: typing.Any = None, + *, + rsa_padding: typing.Optional[ + typing.Union[padding.PSS, padding.PKCS1v15] + ] = None, ) -> Certificate: """ Signs the certificate using the CA's private key. @@ -946,7 +950,15 @@ def sign( if self._public_key is None: raise ValueError("A certificate must have a public key") - return rust_x509.create_x509_certificate(self, private_key, algorithm) + if rsa_padding is not None: + if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): + raise TypeError("Padding must be PSS or PKCS1v15") + if not isinstance(private_key, rsa.RSAPrivateKey): + raise TypeError("Padding is only supported for RSA keys") + + return rust_x509.create_x509_certificate( + self, private_key, algorithm, rsa_padding + ) class CertificateRevocationListBuilder: diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs index d099716599ea..60856b7efd03 100644 --- a/src/rust/cryptography-x509/src/common.rs +++ b/src/rust/cryptography-x509/src/common.rs @@ -6,7 +6,7 @@ use crate::oid; use asn1::Asn1DefinedByWritable; use std::marker::PhantomData; -#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash, Clone, Eq)] +#[derive(asn1::Asn1Read, asn1::Asn1Write, PartialEq, Hash, Clone, Eq, Debug)] pub struct AlgorithmIdentifier<'a> { pub oid: asn1::DefinedByMarker, #[defined_by(oid)] @@ -19,7 +19,7 @@ impl AlgorithmIdentifier<'_> { } } -#[derive(asn1::Asn1DefinedByRead, asn1::Asn1DefinedByWrite, PartialEq, Eq, Hash, Clone)] +#[derive(asn1::Asn1DefinedByRead, asn1::Asn1DefinedByWrite, PartialEq, Eq, Hash, Clone, Debug)] pub enum AlgorithmParameters<'a> { #[defined_by(oid::SHA1_OID)] Sha1(asn1::Null), @@ -31,6 +31,14 @@ pub enum AlgorithmParameters<'a> { Sha384(asn1::Null), #[defined_by(oid::SHA512_OID)] Sha512(asn1::Null), + #[defined_by(oid::SHA3_224_OID)] + Sha3_224(asn1::Null), + #[defined_by(oid::SHA3_256_OID)] + Sha3_256(asn1::Null), + #[defined_by(oid::SHA3_384_OID)] + Sha3_384(asn1::Null), + #[defined_by(oid::SHA3_512_OID)] + Sha3_512(asn1::Null), #[defined_by(oid::ED25519_OID)] Ed25519, @@ -225,7 +233,7 @@ pub const PSS_SHA1_HASH_ALG: AlgorithmIdentifier<'_> = AlgorithmIdentifier { // This is defined as an AlgorithmIdentifier in RFC 4055, // but the mask generation algorithm **must** contain an AlgorithmIdentifier // in its params, so we define it this way. -#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, Clone, PartialEq, Eq)] +#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, Clone, PartialEq, Eq, Debug)] pub struct MaskGenAlgorithm<'a> { pub oid: asn1::ObjectIdentifier, pub params: AlgorithmIdentifier<'a>, @@ -245,7 +253,7 @@ pub const PSS_SHA1_MASK_GEN_ALG: MaskGenAlgorithm<'_> = MaskGenAlgorithm { // mgf1SHA1Identifier, // saltLength [2] INTEGER DEFAULT 20, // trailerField [3] INTEGER DEFAULT 1 } -#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, Clone, PartialEq, Eq)] +#[derive(asn1::Asn1Read, asn1::Asn1Write, Hash, Clone, PartialEq, Eq, Debug)] pub struct RsaPssParameters<'a> { #[explicit(0)] #[default(PSS_SHA1_HASH_ALG)] @@ -258,7 +266,7 @@ pub struct RsaPssParameters<'a> { pub salt_length: u16, #[explicit(3)] #[default(1u8)] - _trailer_field: u8, + pub _trailer_field: u8, } /// A VisibleString ASN.1 element whose contents is not validated as meeting the diff --git a/src/rust/src/pkcs7.rs b/src/rust/src/pkcs7.rs index 6bc90173fade..17a83fd16bb2 100644 --- a/src/rust/src/pkcs7.rs +++ b/src/rust/src/pkcs7.rs @@ -130,7 +130,13 @@ fn sign_and_serialize<'p>( { ( None, - x509::sign::sign_data(py, py_private_key, py_hash_alg, &data_with_header)?, + x509::sign::sign_data( + py, + py_private_key, + py_hash_alg, + py.None().into_ref(py), + &data_with_header, + )?, ) } else { let mut authenticated_attrs = vec![]; @@ -175,7 +181,13 @@ fn sign_and_serialize<'p>( Some(common::Asn1ReadableOrWritable::new_write( asn1::SetOfWriter::new(authenticated_attrs), )), - x509::sign::sign_data(py, py_private_key, py_hash_alg, &signed_data)?, + x509::sign::sign_data( + py, + py_private_key, + py_hash_alg, + py.None().into_ref(py), + &signed_data, + )?, ) }; @@ -201,6 +213,7 @@ fn sign_and_serialize<'p>( py, py_private_key, py_hash_alg, + py.None().into_ref(py), )?, encrypted_digest: signature, unauthenticated_attributes: None, diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index dbe761fb9b19..f77f141faadb 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -1002,8 +1002,10 @@ fn create_x509_certificate( builder: &pyo3::PyAny, private_key: &pyo3::PyAny, hash_algorithm: &pyo3::PyAny, + rsa_padding: &pyo3::PyAny, ) -> CryptographyResult { - let sigalg = x509::sign::compute_signature_algorithm(py, private_key, hash_algorithm)?; + let sigalg = + x509::sign::compute_signature_algorithm(py, private_key, hash_algorithm, rsa_padding)?; let serialization_mod = py.import(pyo3::intern!( py, "cryptography.hazmat.primitives.serialization" @@ -1056,7 +1058,8 @@ fn create_x509_certificate( }; let tbs_bytes = asn1::write_single(&tbs_cert)?; - let signature = x509::sign::sign_data(py, private_key, hash_algorithm, &tbs_bytes)?; + let signature = + x509::sign::sign_data(py, private_key, hash_algorithm, rsa_padding, &tbs_bytes)?; let data = asn1::write_single(&cryptography_x509::certificate::Certificate { tbs_cert, signature_alg: sigalg, diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index 6bb08779a0a2..1331d3377cba 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -580,8 +580,12 @@ fn create_x509_crl( private_key: &pyo3::PyAny, hash_algorithm: &pyo3::PyAny, ) -> CryptographyResult { - let sigalg = x509::sign::compute_signature_algorithm(py, private_key, hash_algorithm)?; - + let sigalg = x509::sign::compute_signature_algorithm( + py, + private_key, + hash_algorithm, + py.None().into_ref(py), + )?; let mut revoked_certs = vec![]; for py_revoked_cert in builder .getattr(pyo3::intern!(py, "_revoked_certificates"))? @@ -628,7 +632,13 @@ fn create_x509_crl( }; let tbs_bytes = asn1::write_single(&tbs_cert_list)?; - let signature = x509::sign::sign_data(py, private_key, hash_algorithm, &tbs_bytes)?; + let signature = x509::sign::sign_data( + py, + private_key, + hash_algorithm, + py.None().into_ref(py), + &tbs_bytes, + )?; let data = asn1::write_single(&crl::CertificateRevocationList { tbs_cert_list, signature_algorithm: sigalg, diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index 7ceed3511daa..110acf3a1937 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -294,7 +294,12 @@ fn create_x509_csr( private_key: &pyo3::PyAny, hash_algorithm: &pyo3::PyAny, ) -> CryptographyResult { - let sigalg = x509::sign::compute_signature_algorithm(py, private_key, hash_algorithm)?; + let sigalg = x509::sign::compute_signature_algorithm( + py, + private_key, + hash_algorithm, + py.None().into_ref(py), + )?; let serialization_mod = py.import(pyo3::intern!( py, "cryptography.hazmat.primitives.serialization" @@ -364,7 +369,13 @@ fn create_x509_csr( }; let tbs_bytes = asn1::write_single(&csr_info)?; - let signature = x509::sign::sign_data(py, private_key, hash_algorithm, &tbs_bytes)?; + let signature = x509::sign::sign_data( + py, + private_key, + hash_algorithm, + py.None().into_ref(py), + &tbs_bytes, + )?; let data = asn1::write_single(&Csr { csr_info, signature_alg: sigalg, diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index 728eb92cef38..f2a86241e4fd 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -679,9 +679,20 @@ fn create_ocsp_response( )?, }; - let sigalg = x509::sign::compute_signature_algorithm(py, private_key, hash_algorithm)?; + let sigalg = x509::sign::compute_signature_algorithm( + py, + private_key, + hash_algorithm, + py.None().into_ref(py), + )?; let tbs_bytes = asn1::write_single(&tbs_response_data)?; - let signature = x509::sign::sign_data(py, private_key, hash_algorithm, &tbs_bytes)?; + let signature = x509::sign::sign_data( + py, + private_key, + hash_algorithm, + py.None().into_ref(py), + &tbs_bytes, + )?; if !responder_cert .call_method0(pyo3::intern!(py, "public_key"))? diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index 5c69ecedf4fe..c0b0ec5de3fe 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -4,7 +4,7 @@ use crate::error::{CryptographyError, CryptographyResult}; use crate::exceptions; -use cryptography_x509::common; +use cryptography_x509::{common, oid}; #[derive(Debug, PartialEq)] pub(crate) enum KeyType { @@ -119,14 +119,88 @@ fn identify_hash_type( } } +fn compute_pss_salt_length<'p>( + py: pyo3::Python<'p>, + private_key: &'p pyo3::PyAny, + hash_algorithm: &'p pyo3::PyAny, + rsa_padding: &'p pyo3::PyAny, +) -> pyo3::PyResult { + let padding_mod = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.padding" + ))?; + let maxlen = padding_mod.getattr(pyo3::intern!(py, "_MaxLength"))?; + let digestlen = padding_mod.getattr(pyo3::intern!(py, "_DigestLength"))?; + let py_saltlen = rsa_padding.getattr(pyo3::intern!(py, "_salt_length"))?; + if py_saltlen.is_instance(maxlen)? { + padding_mod + .getattr(pyo3::intern!(py, "calculate_max_pss_salt_length"))? + .call1((private_key, hash_algorithm))? + .extract::() + } else if py_saltlen.is_instance(digestlen)? { + hash_algorithm + .getattr(pyo3::intern!(py, "digest_size"))? + .extract::() + } else if py_saltlen.is_instance(py.get_type::())? { + py_saltlen.extract::() + } else { + Err(pyo3::exceptions::PyTypeError::new_err( + "salt_length must be an int, MaxLength, or DigestLength.", + )) + } +} + pub(crate) fn compute_signature_algorithm<'p>( py: pyo3::Python<'p>, private_key: &'p pyo3::PyAny, hash_algorithm: &'p pyo3::PyAny, + rsa_padding: &'p pyo3::PyAny, ) -> pyo3::PyResult> { let key_type = identify_key_type(py, private_key)?; let hash_type = identify_hash_type(py, hash_algorithm)?; + let pss_type: &pyo3::types::PyType = py + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.padding" + ))? + .getattr(pyo3::intern!(py, "PSS"))? + .extract()?; + // If this is RSA-PSS we need to compute the signature algorithm from the + // parameters provided in rsa_padding. + if !rsa_padding.is_none() && rsa_padding.is_instance(pss_type)? { + let hash_alg_params = identify_alg_params_for_hash_type(hash_type)?; + let hash_algorithm_id = common::AlgorithmIdentifier { + oid: asn1::DefinedByMarker::marker(), + params: hash_alg_params, + }; + let salt_length = compute_pss_salt_length(py, private_key, hash_algorithm, rsa_padding)?; + let py_mgf_alg = rsa_padding + .getattr(pyo3::intern!(py, "_mgf"))? + .getattr(pyo3::intern!(py, "_algorithm"))?; + let mgf_hash_type = identify_hash_type(py, py_mgf_alg)?; + let mgf_alg = common::AlgorithmIdentifier { + oid: asn1::DefinedByMarker::marker(), + params: identify_alg_params_for_hash_type(mgf_hash_type)?, + }; + let params = + common::AlgorithmParameters::RsaPss(Some(Box::new(common::RsaPssParameters { + hash_algorithm: hash_algorithm_id, + mask_gen_algorithm: common::MaskGenAlgorithm { + oid: oid::MGF1_OID, + params: mgf_alg, + }, + salt_length, + _trailer_field: 1, + }))); + + return Ok(common::AlgorithmIdentifier { + oid: asn1::DefinedByMarker::marker(), + params, + }); + } + // It's not an RSA PSS signature, so we compute the signature algorithm from + // the union of key type and hash type. match (key_type, hash_type) { (KeyType::Ed25519, HashType::None) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), @@ -238,6 +312,7 @@ pub(crate) fn sign_data<'p>( py: pyo3::Python<'p>, private_key: &'p pyo3::PyAny, hash_algorithm: &'p pyo3::PyAny, + rsa_padding: &'p pyo3::PyAny, data: &[u8], ) -> pyo3::PyResult<&'p [u8]> { let key_type = identify_key_type(py, private_key)?; @@ -257,14 +332,17 @@ pub(crate) fn sign_data<'p>( private_key.call_method1(pyo3::intern!(py, "sign"), (data, ecdsa))? } KeyType::Rsa => { - let padding_mod = py.import(pyo3::intern!( - py, - "cryptography.hazmat.primitives.asymmetric.padding" - ))?; - let pkcs1v15 = padding_mod - .getattr(pyo3::intern!(py, "PKCS1v15"))? - .call0()?; - private_key.call_method1(pyo3::intern!(py, "sign"), (data, pkcs1v15, hash_algorithm))? + let mut padding = rsa_padding; + if padding.is_none() { + let padding_mod = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.padding" + ))?; + padding = padding_mod + .getattr(pyo3::intern!(py, "PKCS1v15"))? + .call0()?; + } + private_key.call_method1(pyo3::intern!(py, "sign"), (data, padding, hash_algorithm))? } KeyType::Dsa => { private_key.call_method1(pyo3::intern!(py, "sign"), (data, hash_algorithm))? @@ -435,10 +513,29 @@ fn identify_key_hash_type_for_algorithm_params( } } +fn identify_alg_params_for_hash_type( + hash_type: HashType, +) -> pyo3::PyResult> { + match hash_type { + HashType::Sha224 => Ok(common::AlgorithmParameters::Sha224(())), + HashType::Sha256 => Ok(common::AlgorithmParameters::Sha256(())), + HashType::Sha384 => Ok(common::AlgorithmParameters::Sha384(())), + HashType::Sha512 => Ok(common::AlgorithmParameters::Sha512(())), + HashType::Sha3_224 => Ok(common::AlgorithmParameters::Sha3_224(())), + HashType::Sha3_256 => Ok(common::AlgorithmParameters::Sha3_256(())), + HashType::Sha3_384 => Ok(common::AlgorithmParameters::Sha3_384(())), + HashType::Sha3_512 => Ok(common::AlgorithmParameters::Sha3_512(())), + HashType::None => Err(pyo3::exceptions::PyTypeError::new_err( + "Algorithm must be a registered hash algorithm, not None.", + )), + } +} + #[cfg(test)] mod tests { use super::{ - identify_key_hash_type_for_algorithm_params, py_hash_name_from_hash_type, HashType, KeyType, + identify_alg_params_for_hash_type, identify_key_hash_type_for_algorithm_params, + py_hash_name_from_hash_type, HashType, KeyType, }; use cryptography_x509::{common, oid}; @@ -603,6 +700,34 @@ mod tests { ); } + #[test] + fn test_identify_alg_params_for_hash_type() { + for (hash, params) in [ + (HashType::Sha224, common::AlgorithmParameters::Sha224(())), + (HashType::Sha256, common::AlgorithmParameters::Sha256(())), + (HashType::Sha384, common::AlgorithmParameters::Sha384(())), + (HashType::Sha512, common::AlgorithmParameters::Sha512(())), + ( + HashType::Sha3_224, + common::AlgorithmParameters::Sha3_224(()), + ), + ( + HashType::Sha3_256, + common::AlgorithmParameters::Sha3_256(()), + ), + ( + HashType::Sha3_384, + common::AlgorithmParameters::Sha3_384(()), + ), + ( + HashType::Sha3_512, + common::AlgorithmParameters::Sha3_512(()), + ), + ] { + assert_eq!(identify_alg_params_for_hash_type(hash).unwrap(), params); + } + } + #[test] fn test_py_hash_name_from_hash_type() { for (hash, name) in [ diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index b33e09ce518f..19a854e24a98 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -765,6 +765,21 @@ def test_load_cert_pub_key(self, backend): cert.signature_hash_algorithm, ) + def test_load_pss_sha1_mgf1_sha1(self, backend): + cert = _load_cert( + os.path.join("x509", "ee-pss-sha1-cert.pem"), + x509.load_pem_x509_certificate, + ) + assert isinstance(cert, x509.Certificate) + pub_key = cert.public_key() + assert isinstance(pub_key, rsa.RSAPublicKey) + pss = cert.signature_algorithm_parameters + assert isinstance(pss, padding.PSS) + assert isinstance(pss._mgf, padding.MGF1) + assert isinstance(pss._mgf._algorithm, hashes.SHA1) + assert pss._salt_length == 20 + assert isinstance(cert.signature_hash_algorithm, hashes.SHA1) + def test_invalid_mgf(self, backend): cert = _load_cert( os.path.join("x509", "custom", "rsa_pss_cert_invalid_mgf.der"), @@ -2404,6 +2419,154 @@ def test_extreme_times( # GENERALIZED TIME assert parsed.not_after_tag == 0x18 + @pytest.mark.parametrize( + ("alg", "mgf_alg"), + [ + (hashes.SHA512(), hashes.SHA256()), + (hashes.SHA3_512(), hashes.SHA3_256()), + ], + ) + def test_sign_pss( + self, rsa_key_2048: rsa.RSAPrivateKey, alg, mgf_alg, backend + ): + if not backend.signature_hash_supported(alg): + pytest.skip(f"{alg} signature not supported") + builder = ( + x509.CertificateBuilder() + .subject_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) + ) + .issuer_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) + ) + .public_key(rsa_key_2048.public_key()) + .serial_number(777) + .not_valid_before(datetime.datetime(2020, 1, 1)) + .not_valid_after(datetime.datetime(2038, 1, 1)) + ) + pss = padding.PSS( + mgf=padding.MGF1(mgf_alg), salt_length=alg.digest_size + ) + cert = builder.sign(rsa_key_2048, alg, rsa_padding=pss) + pk = cert.public_key() + assert isinstance(pk, rsa.RSAPublicKey) + assert isinstance(cert.signature_hash_algorithm, type(alg)) + cert_params = cert.signature_algorithm_parameters + assert isinstance(cert_params, padding.PSS) + assert cert_params._salt_length == pss._salt_length + assert isinstance(cert_params._mgf, padding.MGF1) + assert isinstance(cert_params._mgf._algorithm, type(mgf_alg)) + pk.verify( + cert.signature, + cert.tbs_certificate_bytes, + cert_params, + alg, + ) + + @pytest.mark.parametrize( + ("padding_len", "computed_len"), + [ + (padding.PSS.MAX_LENGTH, 222), + (padding.PSS.DIGEST_LENGTH, 32), + ], + ) + def test_sign_pss_length_options( + self, + rsa_key_2048: rsa.RSAPrivateKey, + padding_len, + computed_len, + backend, + ): + builder = ( + x509.CertificateBuilder() + .subject_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) + ) + .issuer_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) + ) + .public_key(rsa_key_2048.public_key()) + .serial_number(777) + .not_valid_before(datetime.datetime(2020, 1, 1)) + .not_valid_after(datetime.datetime(2038, 1, 1)) + ) + pss = padding.PSS( + mgf=padding.MGF1(hashes.SHA256()), salt_length=padding_len + ) + cert = builder.sign(rsa_key_2048, hashes.SHA256(), rsa_padding=pss) + assert isinstance(cert.signature_algorithm_parameters, padding.PSS) + assert cert.signature_algorithm_parameters._salt_length == computed_len + + def test_sign_pss_auto_unsupported( + self, rsa_key_2048: rsa.RSAPrivateKey, backend + ): + builder = ( + x509.CertificateBuilder() + .subject_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) + ) + .issuer_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) + ) + .public_key(rsa_key_2048.public_key()) + .serial_number(777) + .not_valid_before(datetime.datetime(2020, 1, 1)) + .not_valid_after(datetime.datetime(2038, 1, 1)) + ) + pss = padding.PSS( + mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.AUTO + ) + with pytest.raises(TypeError): + builder.sign(rsa_key_2048, hashes.SHA256(), rsa_padding=pss) + + def test_sign_invalid_padding( + self, rsa_key_2048: rsa.RSAPrivateKey, backend + ): + builder = ( + x509.CertificateBuilder() + .subject_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) + ) + .issuer_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) + ) + .public_key(rsa_key_2048.public_key()) + .serial_number(777) + .not_valid_before(datetime.datetime(2020, 1, 1)) + .not_valid_after(datetime.datetime(2038, 1, 1)) + ) + with pytest.raises(TypeError): + builder.sign( + rsa_key_2048, + hashes.SHA256(), + rsa_padding=b"notapadding", # type: ignore[arg-type] + ) + eckey = ec.generate_private_key(ec.SECP256R1()) + with pytest.raises(TypeError): + builder.sign( + eckey, hashes.SHA256(), rsa_padding=padding.PKCS1v15() + ) + + def test_sign_pss_hash_none( + self, rsa_key_2048: rsa.RSAPrivateKey, backend + ): + builder = ( + x509.CertificateBuilder() + .subject_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) + ) + .issuer_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, "US")]) + ) + .public_key(rsa_key_2048.public_key()) + .serial_number(777) + .not_valid_before(datetime.datetime(2020, 1, 1)) + .not_valid_after(datetime.datetime(2038, 1, 1)) + ) + pss = padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=32) + with pytest.raises(TypeError): + builder.sign(rsa_key_2048, None, rsa_padding=pss) + def test_no_subject_name(self, rsa_key_2048: rsa.RSAPrivateKey, backend): subject_private_key = rsa_key_2048 builder = ( From 9a14c88898e5a002dc1633df81b87e3e33382979 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 May 2023 13:12:12 +0000 Subject: [PATCH 251/316] Bump mypy from 1.2.0 to 1.3.0 (#8910) Bumps [mypy](https://github.com/python/mypy) from 1.2.0 to 1.3.0. - [Commits](https://github.com/python/mypy/compare/v1.2.0...v1.3.0) --- updated-dependencies: - dependency-name: mypy 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 12b2f942e703..05a0fedd6cd3 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -68,7 +68,7 @@ mdurl==0.1.2 # via markdown-it-py more-itertools==9.1.0 # via jaraco-classes -mypy==1.2.0 +mypy==1.3.0 # via cryptography (pyproject.toml) mypy-extensions==1.0.0 # via From 46eb804a3d27643c8923a1f331ef8b81095af9af Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Thu, 11 May 2023 20:20:01 -0400 Subject: [PATCH 252/316] Bump BoringSSL and/or OpenSSL in CI (#8911) Co-authored-by: pyca-boringbot[bot] --- .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 521295b9d9f4..5034759188d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of May 11, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "c6dd304d2c628277b710ab50ce9eed660696756d"}} - # Latest commit on the OpenSSL master branch, as of May 11, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "20d4dc8898edc12806ead2100ac09b907662aff6"}} + # Latest commit on the BoringSSL master branch, as of May 12, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "e24491a09cbae08cccd1ad894455d547218d89c8"}} + # Latest commit on the OpenSSL master branch, as of May 12, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "13069d0144096ef8cecc82fb7fcd1a1eed93d7a8"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 0fd6cc2929e9a98c6d8d236f96ee81af40db638e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 May 2023 13:13:57 +0000 Subject: [PATCH 253/316] Bump platformdirs from 3.5.0 to 3.5.1 (#8914) Bumps [platformdirs](https://github.com/platformdirs/platformdirs) from 3.5.0 to 3.5.1. - [Release notes](https://github.com/platformdirs/platformdirs/releases) - [Changelog](https://github.com/platformdirs/platformdirs/blob/main/CHANGES.rst) - [Commits](https://github.com/platformdirs/platformdirs/compare/3.5.0...3.5.1) --- updated-dependencies: - dependency-name: platformdirs 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 05a0fedd6cd3..ce17bc0fe6a4 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -89,7 +89,7 @@ pathspec==0.11.1 # check-sdist pkginfo==1.9.6 # via twine -platformdirs==3.5.0 +platformdirs==3.5.1 # via # black # virtualenv From cc4555394d594c2dc114f7ee5086caaa5e07f69e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 12 May 2023 15:38:54 -0400 Subject: [PATCH 254/316] Remove linkcheck skip (#8915) It now has a trusted issuer --- docs/conf.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index e67b03b6597e..4cbbde37b7ce 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -198,8 +198,6 @@ 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", - # Cert is issued from an untrusted root - r"https://e-trust.gosuslugi.ru", # Incomplete cert chain r"https://www.oscca.gov.cn", # Cloudflare returns 403s for all non-browser requests From 1dc587285c863d09a45129e68836181e70e15244 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 12 May 2023 15:40:15 -0400 Subject: [PATCH 255/316] Use pyo3's add_function instead of add_wrapped (#8913) Turns out the docs encourage this. --- src/rust/src/asn1.rs | 8 ++++---- src/rust/src/backend/dh.rs | 16 ++++++++-------- src/rust/src/backend/ed25519.rs | 10 +++++----- src/rust/src/backend/ed448.rs | 10 +++++----- src/rust/src/backend/kdf.rs | 4 ++-- src/rust/src/backend/x25519.rs | 10 +++++----- src/rust/src/backend/x448.rs | 10 +++++----- src/rust/src/pkcs7.rs | 4 ++-- src/rust/src/x509/certificate.rs | 8 ++++---- src/rust/src/x509/common.rs | 4 ++-- src/rust/src/x509/crl.rs | 6 +++--- src/rust/src/x509/csr.rs | 6 +++--- src/rust/src/x509/ocsp_req.rs | 4 ++-- src/rust/src/x509/ocsp_resp.rs | 4 ++-- 14 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs index 96e44e93ae93..bf17a5952f29 100644 --- a/src/rust/src/asn1.rs +++ b/src/rust/src/asn1.rs @@ -180,12 +180,12 @@ fn test_parse_certificate(data: &[u8]) -> Result) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let submod = pyo3::prelude::PyModule::new(py, "asn1")?; - submod.add_wrapped(pyo3::wrap_pyfunction!(parse_spki_for_data))?; + submod.add_function(pyo3::wrap_pyfunction!(parse_spki_for_data, submod)?)?; - submod.add_wrapped(pyo3::wrap_pyfunction!(decode_dss_signature))?; - submod.add_wrapped(pyo3::wrap_pyfunction!(encode_dss_signature))?; + submod.add_function(pyo3::wrap_pyfunction!(decode_dss_signature, submod)?)?; + submod.add_function(pyo3::wrap_pyfunction!(encode_dss_signature, submod)?)?; - submod.add_wrapped(pyo3::wrap_pyfunction!(test_parse_certificate))?; + submod.add_function(pyo3::wrap_pyfunction!(test_parse_certificate, submod)?)?; Ok(submod) } diff --git a/src/rust/src/backend/dh.rs b/src/rust/src/backend/dh.rs index 2daff9dcb656..b4dbaf5dded5 100644 --- a/src/rust/src/backend/dh.rs +++ b/src/rust/src/backend/dh.rs @@ -418,14 +418,14 @@ impl DHParameters { pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let m = pyo3::prelude::PyModule::new(py, "dh")?; - m.add_wrapped(pyo3::wrap_pyfunction!(generate_parameters))?; - m.add_wrapped(pyo3::wrap_pyfunction!(private_key_from_ptr))?; - m.add_wrapped(pyo3::wrap_pyfunction!(public_key_from_ptr))?; - m.add_wrapped(pyo3::wrap_pyfunction!(from_der_parameters))?; - m.add_wrapped(pyo3::wrap_pyfunction!(from_pem_parameters))?; - m.add_wrapped(pyo3::wrap_pyfunction!(from_private_numbers))?; - m.add_wrapped(pyo3::wrap_pyfunction!(from_public_numbers))?; - m.add_wrapped(pyo3::wrap_pyfunction!(from_parameter_numbers))?; + m.add_function(pyo3::wrap_pyfunction!(generate_parameters, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(private_key_from_ptr, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(public_key_from_ptr, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_der_parameters, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_pem_parameters, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_private_numbers, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_public_numbers, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_parameter_numbers, m)?)?; m.add_class::()?; m.add_class::()?; diff --git a/src/rust/src/backend/ed25519.rs b/src/rust/src/backend/ed25519.rs index f10d12db23f9..8cad193c7a92 100644 --- a/src/rust/src/backend/ed25519.rs +++ b/src/rust/src/backend/ed25519.rs @@ -163,11 +163,11 @@ impl Ed25519PublicKey { pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let m = pyo3::prelude::PyModule::new(py, "ed25519")?; - m.add_wrapped(pyo3::wrap_pyfunction!(generate_key))?; - m.add_wrapped(pyo3::wrap_pyfunction!(private_key_from_ptr))?; - m.add_wrapped(pyo3::wrap_pyfunction!(public_key_from_ptr))?; - m.add_wrapped(pyo3::wrap_pyfunction!(from_private_bytes))?; - m.add_wrapped(pyo3::wrap_pyfunction!(from_public_bytes))?; + m.add_function(pyo3::wrap_pyfunction!(generate_key, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(private_key_from_ptr, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(public_key_from_ptr, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_private_bytes, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_public_bytes, m)?)?; m.add_class::()?; m.add_class::()?; diff --git a/src/rust/src/backend/ed448.rs b/src/rust/src/backend/ed448.rs index 44e0240a1fa5..925a9fdb14f2 100644 --- a/src/rust/src/backend/ed448.rs +++ b/src/rust/src/backend/ed448.rs @@ -161,11 +161,11 @@ impl Ed448PublicKey { pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let m = pyo3::prelude::PyModule::new(py, "ed448")?; - m.add_wrapped(pyo3::wrap_pyfunction!(generate_key))?; - m.add_wrapped(pyo3::wrap_pyfunction!(private_key_from_ptr))?; - m.add_wrapped(pyo3::wrap_pyfunction!(public_key_from_ptr))?; - m.add_wrapped(pyo3::wrap_pyfunction!(from_private_bytes))?; - m.add_wrapped(pyo3::wrap_pyfunction!(from_public_bytes))?; + m.add_function(pyo3::wrap_pyfunction!(generate_key, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(private_key_from_ptr, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(public_key_from_ptr, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_private_bytes, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_public_bytes, m)?)?; m.add_class::()?; m.add_class::()?; diff --git a/src/rust/src/backend/kdf.rs b/src/rust/src/backend/kdf.rs index 5bd5606c9f1b..de527f4671da 100644 --- a/src/rust/src/backend/kdf.rs +++ b/src/rust/src/backend/kdf.rs @@ -52,9 +52,9 @@ fn derive_scrypt<'p>( pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let m = pyo3::prelude::PyModule::new(py, "kdf")?; - m.add_wrapped(pyo3::wrap_pyfunction!(derive_pbkdf2_hmac))?; + m.add_function(pyo3::wrap_pyfunction!(derive_pbkdf2_hmac, m)?)?; #[cfg(not(CRYPTOGRAPHY_IS_LIBRESSL))] - m.add_wrapped(pyo3::wrap_pyfunction!(derive_scrypt))?; + m.add_function(pyo3::wrap_pyfunction!(derive_scrypt, m)?)?; Ok(m) } diff --git a/src/rust/src/backend/x25519.rs b/src/rust/src/backend/x25519.rs index 0a62182b1be8..faf21ffddfe9 100644 --- a/src/rust/src/backend/x25519.rs +++ b/src/rust/src/backend/x25519.rs @@ -152,11 +152,11 @@ impl X25519PublicKey { pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let m = pyo3::prelude::PyModule::new(py, "x25519")?; - m.add_wrapped(pyo3::wrap_pyfunction!(generate_key))?; - m.add_wrapped(pyo3::wrap_pyfunction!(private_key_from_ptr))?; - m.add_wrapped(pyo3::wrap_pyfunction!(public_key_from_ptr))?; - m.add_wrapped(pyo3::wrap_pyfunction!(from_private_bytes))?; - m.add_wrapped(pyo3::wrap_pyfunction!(from_public_bytes))?; + m.add_function(pyo3::wrap_pyfunction!(generate_key, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(private_key_from_ptr, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(public_key_from_ptr, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_private_bytes, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_public_bytes, m)?)?; m.add_class::()?; m.add_class::()?; diff --git a/src/rust/src/backend/x448.rs b/src/rust/src/backend/x448.rs index 0eb44b8fe8fc..456e7fa52ab8 100644 --- a/src/rust/src/backend/x448.rs +++ b/src/rust/src/backend/x448.rs @@ -151,11 +151,11 @@ impl X448PublicKey { pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let m = pyo3::prelude::PyModule::new(py, "x448")?; - m.add_wrapped(pyo3::wrap_pyfunction!(generate_key))?; - m.add_wrapped(pyo3::wrap_pyfunction!(private_key_from_ptr))?; - m.add_wrapped(pyo3::wrap_pyfunction!(public_key_from_ptr))?; - m.add_wrapped(pyo3::wrap_pyfunction!(from_private_bytes))?; - m.add_wrapped(pyo3::wrap_pyfunction!(from_public_bytes))?; + m.add_function(pyo3::wrap_pyfunction!(generate_key, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(private_key_from_ptr, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(public_key_from_ptr, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_private_bytes, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_public_bytes, m)?)?; m.add_class::()?; m.add_class::()?; diff --git a/src/rust/src/pkcs7.rs b/src/rust/src/pkcs7.rs index 17a83fd16bb2..6a49acf98c7b 100644 --- a/src/rust/src/pkcs7.rs +++ b/src/rust/src/pkcs7.rs @@ -316,8 +316,8 @@ fn smime_canonicalize(data: &[u8], text_mode: bool) -> (Cow<'_, [u8]>, Cow<'_, [ pub(crate) fn create_submodule(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { let submod = pyo3::prelude::PyModule::new(py, "pkcs7")?; - submod.add_wrapped(pyo3::wrap_pyfunction!(serialize_certificates))?; - submod.add_wrapped(pyo3::wrap_pyfunction!(sign_and_serialize))?; + submod.add_function(pyo3::wrap_pyfunction!(serialize_certificates, submod)?)?; + submod.add_function(pyo3::wrap_pyfunction!(sign_and_serialize, submod)?)?; Ok(submod) } diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index f77f141faadb..92ef6c9678bc 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -1077,10 +1077,10 @@ pub(crate) fn set_bit(vals: &mut [u8], n: usize, set: bool) { } pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { - module.add_wrapped(pyo3::wrap_pyfunction!(load_der_x509_certificate))?; - module.add_wrapped(pyo3::wrap_pyfunction!(load_pem_x509_certificate))?; - module.add_wrapped(pyo3::wrap_pyfunction!(load_pem_x509_certificates))?; - module.add_wrapped(pyo3::wrap_pyfunction!(create_x509_certificate))?; + module.add_function(pyo3::wrap_pyfunction!(load_der_x509_certificate, module)?)?; + module.add_function(pyo3::wrap_pyfunction!(load_pem_x509_certificate, module)?)?; + module.add_function(pyo3::wrap_pyfunction!(load_pem_x509_certificates, module)?)?; + module.add_function(pyo3::wrap_pyfunction!(create_x509_certificate, module)?)?; module.add_class::()?; diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index 3c42f0c5d31e..bc26dace3fa9 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -555,8 +555,8 @@ pub(crate) fn datetime_now(py: pyo3::Python<'_>) -> pyo3::PyResult pyo3::PyResult<()> { - module.add_wrapped(pyo3::wrap_pyfunction!(encode_extension_value))?; - module.add_wrapped(pyo3::wrap_pyfunction!(encode_name_bytes))?; + module.add_function(pyo3::wrap_pyfunction!(encode_extension_value, module)?)?; + module.add_function(pyo3::wrap_pyfunction!(encode_name_bytes, module)?)?; Ok(()) } diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index 1331d3377cba..9dc63aa8d6e8 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -648,9 +648,9 @@ fn create_x509_crl( } pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { - module.add_wrapped(pyo3::wrap_pyfunction!(load_der_x509_crl))?; - module.add_wrapped(pyo3::wrap_pyfunction!(load_pem_x509_crl))?; - module.add_wrapped(pyo3::wrap_pyfunction!(create_x509_crl))?; + module.add_function(pyo3::wrap_pyfunction!(load_der_x509_crl, module)?)?; + module.add_function(pyo3::wrap_pyfunction!(load_pem_x509_crl, module)?)?; + module.add_function(pyo3::wrap_pyfunction!(create_x509_crl, module)?)?; module.add_class::()?; module.add_class::()?; diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index 110acf3a1937..28ec67ed2075 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -385,9 +385,9 @@ fn create_x509_csr( } pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { - module.add_wrapped(pyo3::wrap_pyfunction!(load_der_x509_csr))?; - module.add_wrapped(pyo3::wrap_pyfunction!(load_pem_x509_csr))?; - module.add_wrapped(pyo3::wrap_pyfunction!(create_x509_csr))?; + module.add_function(pyo3::wrap_pyfunction!(load_der_x509_csr, module)?)?; + module.add_function(pyo3::wrap_pyfunction!(load_pem_x509_csr, module)?)?; + module.add_function(pyo3::wrap_pyfunction!(create_x509_csr, module)?)?; module.add_class::()?; diff --git a/src/rust/src/x509/ocsp_req.rs b/src/rust/src/x509/ocsp_req.rs index bd5aecad0ec7..1571524edfeb 100644 --- a/src/rust/src/x509/ocsp_req.rs +++ b/src/rust/src/x509/ocsp_req.rs @@ -239,8 +239,8 @@ fn create_ocsp_request( } pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { - module.add_wrapped(pyo3::wrap_pyfunction!(load_der_ocsp_request))?; - module.add_wrapped(pyo3::wrap_pyfunction!(create_ocsp_request))?; + module.add_function(pyo3::wrap_pyfunction!(load_der_ocsp_request, module)?)?; + module.add_function(pyo3::wrap_pyfunction!(create_ocsp_request, module)?)?; Ok(()) } diff --git a/src/rust/src/x509/ocsp_resp.rs b/src/rust/src/x509/ocsp_resp.rs index f2a86241e4fd..721e0313a613 100644 --- a/src/rust/src/x509/ocsp_resp.rs +++ b/src/rust/src/x509/ocsp_resp.rs @@ -738,8 +738,8 @@ fn create_ocsp_response( } pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { - module.add_wrapped(pyo3::wrap_pyfunction!(load_der_ocsp_response))?; - module.add_wrapped(pyo3::wrap_pyfunction!(create_ocsp_response))?; + module.add_function(pyo3::wrap_pyfunction!(load_der_ocsp_response, module)?)?; + module.add_function(pyo3::wrap_pyfunction!(create_ocsp_response, module)?)?; Ok(()) } From 35ce702c9c2a5a0ceaaaf77bf8e9e7871511ce73 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Sat, 13 May 2023 00:18:10 +0000 Subject: [PATCH 256/316] Bump BoringSSL and/or OpenSSL in CI (#8917) Co-authored-by: pyca-boringbot[bot] --- .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 5034759188d8..3a3d8e587d95 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of May 12, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "e24491a09cbae08cccd1ad894455d547218d89c8"}} - # Latest commit on the OpenSSL master branch, as of May 12, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "13069d0144096ef8cecc82fb7fcd1a1eed93d7a8"}} + # Latest commit on the BoringSSL master branch, as of May 13, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "c215ce7e8230786e0d4ec463d95a9e44af513e6a"}} + # Latest commit on the OpenSSL master branch, as of May 13, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "2b5a546ce1960883febc51f5d2a71a8b7c1b3ab9"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 2eeb3396d3c40774f782ff2d68960f4871d812d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 May 2023 14:23:48 +0000 Subject: [PATCH 257/316] Bump ruff from 0.0.265 to 0.0.267 (#8919) Bumps [ruff](https://github.com/charliermarsh/ruff) from 0.0.265 to 0.0.267. - [Release notes](https://github.com/charliermarsh/ruff/releases) - [Changelog](https://github.com/charliermarsh/ruff/blob/main/BREAKING_CHANGES.md) - [Commits](https://github.com/charliermarsh/ruff/compare/v0.0.265...v0.0.267) --- updated-dependencies: - dependency-name: ruff 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index ce17bc0fe6a4..f6bea11e3112 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -138,7 +138,7 @@ rfc3986==2.0.0 # via twine rich==13.3.5 # via twine -ruff==0.0.265 +ruff==0.0.267 # via cryptography (pyproject.toml) six==1.16.0 # via bleach From 05900ddc6e3860af3517b0e351bc841f46732f1a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 May 2023 14:25:44 +0000 Subject: [PATCH 258/316] Bump pytest-xdist from 3.2.1 to 3.3.0 (#8920) Bumps [pytest-xdist](https://github.com/pytest-dev/pytest-xdist) from 3.2.1 to 3.3.0. - [Changelog](https://github.com/pytest-dev/pytest-xdist/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest-xdist/compare/v3.2.1...v3.3.0) --- updated-dependencies: - dependency-name: pytest-xdist 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index f6bea11e3112..fff8548b798b 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -123,7 +123,7 @@ pytest-cov==4.0.0 # via cryptography (pyproject.toml) pytest-randomly==3.12.0 # via cryptography (pyproject.toml) -pytest-xdist==3.2.1 +pytest-xdist==3.3.0 # via cryptography (pyproject.toml) readme-renderer==37.3 # via twine From 6cac7bcaf743d56215dd68a88f121c0811cfeb2b Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 14 May 2023 08:07:26 +0800 Subject: [PATCH 259/316] refactor signature algorithm parameters into a separate function (#8921) * refactor signature algorithm parameters into a separate function this will be used in the verify_directly_issued_by PR * fix coverage with more refactoring --- src/rust/src/x509/certificate.rs | 188 +++++++++++++++++-------------- 1 file changed, 104 insertions(+), 84 deletions(-) diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 92ef6c9678bc..4c0725023f6e 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -269,29 +269,7 @@ impl Certificate { &self, py: pyo3::Python<'p>, ) -> Result<&'p pyo3::PyAny, CryptographyError> { - let sig_oids_to_hash = py - .import(pyo3::intern!(py, "cryptography.hazmat._oid"))? - .getattr(pyo3::intern!(py, "_SIG_OIDS_TO_HASH"))?; - match &self.raw.borrow_value().signature_alg.params { - common::AlgorithmParameters::RsaPss(opt_pss) => { - let pss = opt_pss.as_ref().ok_or_else(|| { - pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters") - })?; - hash_oid_py_hash(py, pss.hash_algorithm.oid().clone()) - } - _ => { - let hash_alg = sig_oids_to_hash.get_item(self.signature_algorithm_oid(py)?); - match hash_alg { - Ok(data) => Ok(data), - Err(_) => Err(CryptographyError::from( - exceptions::UnsupportedAlgorithm::new_err(format!( - "Signature algorithm OID: {} not recognized", - self.raw.borrow_value().signature_alg.oid() - )), - )), - } - } - } + identify_signature_hash_algorithm(py, &self.raw.borrow_value().signature_alg) } #[getter] @@ -304,67 +282,7 @@ impl Certificate { &'p self, py: pyo3::Python<'p>, ) -> CryptographyResult<&'p pyo3::PyAny> { - match &self.raw.borrow_value().signature_alg.params { - common::AlgorithmParameters::RsaPss(opt_pss) => { - let pss = opt_pss.as_ref().ok_or_else(|| { - pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters") - })?; - if pss.mask_gen_algorithm.oid != oid::MGF1_OID { - return Err(CryptographyError::from( - pyo3::exceptions::PyValueError::new_err(format!( - "Unsupported mask generation OID: {}", - pss.mask_gen_algorithm.oid - )), - )); - } - let py_mask_gen_hash_alg = - hash_oid_py_hash(py, pss.mask_gen_algorithm.params.oid().clone())?; - let padding = py.import(pyo3::intern!( - py, - "cryptography.hazmat.primitives.asymmetric.padding" - ))?; - let py_mgf = padding - .getattr(pyo3::intern!(py, "MGF1"))? - .call1((py_mask_gen_hash_alg,))?; - Ok(padding - .getattr(pyo3::intern!(py, "PSS"))? - .call1((py_mgf, pss.salt_length))?) - } - common::AlgorithmParameters::RsaWithSha1(_) - | common::AlgorithmParameters::RsaWithSha1Alt(_) - | common::AlgorithmParameters::RsaWithSha224(_) - | common::AlgorithmParameters::RsaWithSha256(_) - | common::AlgorithmParameters::RsaWithSha384(_) - | common::AlgorithmParameters::RsaWithSha512(_) - | common::AlgorithmParameters::RsaWithSha3_224(_) - | common::AlgorithmParameters::RsaWithSha3_256(_) - | common::AlgorithmParameters::RsaWithSha3_384(_) - | common::AlgorithmParameters::RsaWithSha3_512(_) => { - let pkcs = py - .import(pyo3::intern!( - py, - "cryptography.hazmat.primitives.asymmetric.padding" - ))? - .getattr(pyo3::intern!(py, "PKCS1v15"))? - .call0()?; - Ok(pkcs) - } - common::AlgorithmParameters::EcDsaWithSha224 - | common::AlgorithmParameters::EcDsaWithSha256 - | common::AlgorithmParameters::EcDsaWithSha384 - | common::AlgorithmParameters::EcDsaWithSha512 - | common::AlgorithmParameters::EcDsaWithSha3_224 - | common::AlgorithmParameters::EcDsaWithSha3_256 - | common::AlgorithmParameters::EcDsaWithSha3_384 - | common::AlgorithmParameters::EcDsaWithSha3_512 => Ok(py - .import(pyo3::intern!( - py, - "cryptography.hazmat.primitives.asymmetric.ec" - ))? - .getattr(pyo3::intern!(py, "ECDSA"))? - .call1((self.signature_hash_algorithm(py)?,))?), - _ => Ok(py.None().into_ref(py)), - } + identify_signature_algorithm_parameters(py, &self.raw.borrow_value().signature_alg) } #[getter] @@ -1076,6 +994,108 @@ pub(crate) fn set_bit(vals: &mut [u8], n: usize, set: bool) { } } +pub(crate) fn identify_signature_hash_algorithm<'p>( + py: pyo3::Python<'p>, + signature_algorithm: &common::AlgorithmIdentifier<'_>, +) -> CryptographyResult<&'p pyo3::PyAny> { + let sig_oids_to_hash = py + .import(pyo3::intern!(py, "cryptography.hazmat._oid"))? + .getattr(pyo3::intern!(py, "_SIG_OIDS_TO_HASH"))?; + match &signature_algorithm.params { + common::AlgorithmParameters::RsaPss(opt_pss) => { + let pss = opt_pss.as_ref().ok_or_else(|| { + pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters") + })?; + hash_oid_py_hash(py, pss.hash_algorithm.oid().clone()) + } + _ => { + let py_sig_alg_oid = oid_to_py_oid(py, signature_algorithm.oid())?; + let hash_alg = sig_oids_to_hash.get_item(py_sig_alg_oid); + match hash_alg { + Ok(data) => Ok(data), + Err(_) => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + signature_algorithm.oid() + )), + )), + } + } + } +} + +pub(crate) fn identify_signature_algorithm_parameters<'p>( + py: pyo3::Python<'p>, + signature_algorithm: &common::AlgorithmIdentifier<'_>, +) -> CryptographyResult<&'p pyo3::PyAny> { + match &signature_algorithm.params { + common::AlgorithmParameters::RsaPss(opt_pss) => { + let pss = opt_pss.as_ref().ok_or_else(|| { + pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters") + })?; + if pss.mask_gen_algorithm.oid != oid::MGF1_OID { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err(format!( + "Unsupported mask generation OID: {}", + pss.mask_gen_algorithm.oid + )), + )); + } + let py_mask_gen_hash_alg = + hash_oid_py_hash(py, pss.mask_gen_algorithm.params.oid().clone())?; + let padding = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.padding" + ))?; + let py_mgf = padding + .getattr(pyo3::intern!(py, "MGF1"))? + .call1((py_mask_gen_hash_alg,))?; + Ok(padding + .getattr(pyo3::intern!(py, "PSS"))? + .call1((py_mgf, pss.salt_length))?) + } + common::AlgorithmParameters::RsaWithSha1(_) + | common::AlgorithmParameters::RsaWithSha1Alt(_) + | common::AlgorithmParameters::RsaWithSha224(_) + | common::AlgorithmParameters::RsaWithSha256(_) + | common::AlgorithmParameters::RsaWithSha384(_) + | common::AlgorithmParameters::RsaWithSha512(_) + | common::AlgorithmParameters::RsaWithSha3_224(_) + | common::AlgorithmParameters::RsaWithSha3_256(_) + | common::AlgorithmParameters::RsaWithSha3_384(_) + | common::AlgorithmParameters::RsaWithSha3_512(_) => { + let pkcs = py + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.padding" + ))? + .getattr(pyo3::intern!(py, "PKCS1v15"))? + .call0()?; + Ok(pkcs) + } + common::AlgorithmParameters::EcDsaWithSha224 + | common::AlgorithmParameters::EcDsaWithSha256 + | common::AlgorithmParameters::EcDsaWithSha384 + | common::AlgorithmParameters::EcDsaWithSha512 + | common::AlgorithmParameters::EcDsaWithSha3_224 + | common::AlgorithmParameters::EcDsaWithSha3_256 + | common::AlgorithmParameters::EcDsaWithSha3_384 + | common::AlgorithmParameters::EcDsaWithSha3_512 => { + let signature_hash_algorithm = + identify_signature_hash_algorithm(py, signature_algorithm)?; + + Ok(py + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.ec" + ))? + .getattr(pyo3::intern!(py, "ECDSA"))? + .call1((signature_hash_algorithm,))?) + } + _ => Ok(py.None().into_ref(py)), + } +} + pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { module.add_function(pyo3::wrap_pyfunction!(load_der_x509_certificate, module)?)?; module.add_function(pyo3::wrap_pyfunction!(load_pem_x509_certificate, module)?)?; From 2a1f42976206a39d0196786857b8d21a877ca42b Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 14 May 2023 20:54:23 +0800 Subject: [PATCH 260/316] support PSS signatures in verify_directly_issued_by (#8908) --- src/rust/src/x509/certificate.rs | 2 +- src/rust/src/x509/crl.rs | 2 +- src/rust/src/x509/csr.rs | 5 +- src/rust/src/x509/sign.rs | 347 +++++++++---------------------- tests/x509/test_x509.py | 44 ++++ 5 files changed, 152 insertions(+), 248 deletions(-) diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 4c0725023f6e..34e9ec0ec4b3 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -335,7 +335,7 @@ impl Certificate { ), )); }; - sign::verify_signature_with_oid( + sign::verify_signature_with_signature_algorithm( py, issuer.public_key(py)?, &self.raw.borrow_value().signature_alg, diff --git a/src/rust/src/x509/crl.rs b/src/rust/src/x509/crl.rs index 9dc63aa8d6e8..92301503563f 100644 --- a/src/rust/src/x509/crl.rs +++ b/src/rust/src/x509/crl.rs @@ -393,7 +393,7 @@ impl CertificateRevocationList { // being an invalid signature. sign::identify_public_key_type(py, public_key)?; - Ok(sign::verify_signature_with_oid( + Ok(sign::verify_signature_with_signature_algorithm( py, public_key, &slf.owned.borrow_value().signature_algorithm, diff --git a/src/rust/src/x509/csr.rs b/src/rust/src/x509/csr.rs index 28ec67ed2075..2e7797f49baa 100644 --- a/src/rust/src/x509/csr.rs +++ b/src/rust/src/x509/csr.rs @@ -235,9 +235,10 @@ impl CertificateSigningRequest { slf: pyo3::PyRef<'_, Self>, py: pyo3::Python<'_>, ) -> CryptographyResult { - Ok(sign::verify_signature_with_oid( + let public_key = slf.public_key(py)?; + Ok(sign::verify_signature_with_signature_algorithm( py, - slf.public_key(py)?, + public_key, &slf.raw.borrow_value().signature_alg, slf.raw.borrow_value().signature.as_bytes(), &asn1::write_single(&slf.raw.borrow_value().csr_info)?, diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index c0b0ec5de3fe..0543004201e9 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -4,6 +4,7 @@ use crate::error::{CryptographyError, CryptographyResult}; use crate::exceptions; +use crate::x509::certificate; use cryptography_x509::{common, oid}; #[derive(Debug, PartialEq)] @@ -15,7 +16,6 @@ pub(crate) enum KeyType { Ed448, } -#[derive(Debug, PartialEq)] enum HashType { None, Sha224, @@ -351,21 +351,7 @@ pub(crate) fn sign_data<'p>( signature.extract() } -fn py_hash_name_from_hash_type(hash_type: HashType) -> Option<&'static str> { - match hash_type { - HashType::None => None, - HashType::Sha224 => Some("SHA224"), - HashType::Sha256 => Some("SHA256"), - HashType::Sha384 => Some("SHA384"), - HashType::Sha512 => Some("SHA512"), - HashType::Sha3_224 => Some("SHA3_224"), - HashType::Sha3_256 => Some("SHA3_256"), - HashType::Sha3_384 => Some("SHA3_384"), - HashType::Sha3_512 => Some("SHA3_512"), - } -} - -pub(crate) fn verify_signature_with_oid<'p>( +pub(crate) fn verify_signature_with_signature_algorithm<'p>( py: pyo3::Python<'p>, issuer_public_key: &'p pyo3::PyAny, signature_algorithm: &common::AlgorithmIdentifier<'_>, @@ -373,8 +359,7 @@ pub(crate) fn verify_signature_with_oid<'p>( data: &[u8], ) -> CryptographyResult<()> { let key_type = identify_public_key_type(py, issuer_public_key)?; - let (sig_key_type, sig_hash_type) = - identify_key_hash_type_for_algorithm_params(&signature_algorithm.params)?; + let sig_key_type = identify_key_type_for_algorithm_params(&signature_algorithm.params)?; if key_type != sig_key_type { return Err(CryptographyError::from( pyo3::exceptions::PyValueError::new_err( @@ -382,43 +367,30 @@ pub(crate) fn verify_signature_with_oid<'p>( ), )); } - let sig_hash_name = py_hash_name_from_hash_type(sig_hash_type); - let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; - let signature_hash = match sig_hash_name { - Some(data) => hashes.getattr(data)?.call0()?, - None => py.None().into_ref(py), - }; - + let py_signature_algorithm_parameters = + certificate::identify_signature_algorithm_parameters(py, signature_algorithm)?; + let py_signature_hash_algorithm = + certificate::identify_signature_hash_algorithm(py, signature_algorithm)?; match key_type { KeyType::Ed25519 | KeyType::Ed448 => { issuer_public_key.call_method1(pyo3::intern!(py, "verify"), (signature, data))? } - KeyType::Ec => { - let ec_mod = py.import(pyo3::intern!( - py, - "cryptography.hazmat.primitives.asymmetric.ec" - ))?; - let ecdsa = ec_mod - .getattr(pyo3::intern!(py, "ECDSA"))? - .call1((signature_hash,))?; - issuer_public_key.call_method1(pyo3::intern!(py, "verify"), (signature, data, ecdsa))? - } - KeyType::Rsa => { - let padding_mod = py.import(pyo3::intern!( - py, - "cryptography.hazmat.primitives.asymmetric.padding" - ))?; - let pkcs1v15 = padding_mod - .getattr(pyo3::intern!(py, "PKCS1v15"))? - .call0()?; - issuer_public_key.call_method1( - pyo3::intern!(py, "verify"), - (signature, data, pkcs1v15, signature_hash), - )? - } + KeyType::Ec => issuer_public_key.call_method1( + pyo3::intern!(py, "verify"), + (signature, data, py_signature_algorithm_parameters), + )?, + KeyType::Rsa => issuer_public_key.call_method1( + pyo3::intern!(py, "verify"), + ( + signature, + data, + py_signature_algorithm_parameters, + py_signature_hash_algorithm, + ), + )?, KeyType::Dsa => issuer_public_key.call_method1( pyo3::intern!(py, "verify"), - (signature, data, signature_hash), + (signature, data, py_signature_hash_algorithm), )?, }; Ok(()) @@ -481,32 +453,33 @@ pub(crate) fn identify_public_key_type( } } -fn identify_key_hash_type_for_algorithm_params( +fn identify_key_type_for_algorithm_params( params: &common::AlgorithmParameters<'_>, -) -> pyo3::PyResult<(KeyType, HashType)> { +) -> pyo3::PyResult { match params { - common::AlgorithmParameters::RsaWithSha224(..) => Ok((KeyType::Rsa, HashType::Sha224)), - common::AlgorithmParameters::RsaWithSha256(..) => Ok((KeyType::Rsa, HashType::Sha256)), - common::AlgorithmParameters::RsaWithSha384(..) => Ok((KeyType::Rsa, HashType::Sha384)), - common::AlgorithmParameters::RsaWithSha512(..) => Ok((KeyType::Rsa, HashType::Sha512)), - common::AlgorithmParameters::RsaWithSha3_224(..) => Ok((KeyType::Rsa, HashType::Sha3_224)), - common::AlgorithmParameters::RsaWithSha3_256(..) => Ok((KeyType::Rsa, HashType::Sha3_256)), - common::AlgorithmParameters::RsaWithSha3_384(..) => Ok((KeyType::Rsa, HashType::Sha3_384)), - common::AlgorithmParameters::RsaWithSha3_512(..) => Ok((KeyType::Rsa, HashType::Sha3_512)), - common::AlgorithmParameters::EcDsaWithSha224 => Ok((KeyType::Ec, HashType::Sha224)), - common::AlgorithmParameters::EcDsaWithSha256 => Ok((KeyType::Ec, HashType::Sha256)), - common::AlgorithmParameters::EcDsaWithSha384 => Ok((KeyType::Ec, HashType::Sha384)), - common::AlgorithmParameters::EcDsaWithSha512 => Ok((KeyType::Ec, HashType::Sha512)), - common::AlgorithmParameters::EcDsaWithSha3_224 => Ok((KeyType::Ec, HashType::Sha3_224)), - common::AlgorithmParameters::EcDsaWithSha3_256 => Ok((KeyType::Ec, HashType::Sha3_256)), - common::AlgorithmParameters::EcDsaWithSha3_384 => Ok((KeyType::Ec, HashType::Sha3_384)), - common::AlgorithmParameters::EcDsaWithSha3_512 => Ok((KeyType::Ec, HashType::Sha3_512)), - common::AlgorithmParameters::Ed25519 => Ok((KeyType::Ed25519, HashType::None)), - common::AlgorithmParameters::Ed448 => Ok((KeyType::Ed448, HashType::None)), - common::AlgorithmParameters::DsaWithSha224 => Ok((KeyType::Dsa, HashType::Sha224)), - common::AlgorithmParameters::DsaWithSha256 => Ok((KeyType::Dsa, HashType::Sha256)), - common::AlgorithmParameters::DsaWithSha384 => Ok((KeyType::Dsa, HashType::Sha384)), - common::AlgorithmParameters::DsaWithSha512 => Ok((KeyType::Dsa, HashType::Sha512)), + common::AlgorithmParameters::RsaWithSha224(..) + | common::AlgorithmParameters::RsaWithSha256(..) + | common::AlgorithmParameters::RsaWithSha384(..) + | common::AlgorithmParameters::RsaWithSha512(..) + | common::AlgorithmParameters::RsaWithSha3_224(..) + | common::AlgorithmParameters::RsaWithSha3_256(..) + | common::AlgorithmParameters::RsaWithSha3_384(..) + | common::AlgorithmParameters::RsaWithSha3_512(..) + | common::AlgorithmParameters::RsaPss(..) => Ok(KeyType::Rsa), + common::AlgorithmParameters::EcDsaWithSha224 + | common::AlgorithmParameters::EcDsaWithSha256 + | common::AlgorithmParameters::EcDsaWithSha384 + | common::AlgorithmParameters::EcDsaWithSha512 + | common::AlgorithmParameters::EcDsaWithSha3_224 + | common::AlgorithmParameters::EcDsaWithSha3_256 + | common::AlgorithmParameters::EcDsaWithSha3_384 + | common::AlgorithmParameters::EcDsaWithSha3_512 => Ok(KeyType::Ec), + common::AlgorithmParameters::Ed25519 => Ok(KeyType::Ed25519), + common::AlgorithmParameters::Ed448 => Ok(KeyType::Ed448), + common::AlgorithmParameters::DsaWithSha224 + | common::AlgorithmParameters::DsaWithSha256 + | common::AlgorithmParameters::DsaWithSha384 + | common::AlgorithmParameters::DsaWithSha512 => Ok(KeyType::Dsa), _ => Err(pyo3::exceptions::PyValueError::new_err( "Unsupported signature algorithm", )), @@ -534,165 +507,68 @@ fn identify_alg_params_for_hash_type( #[cfg(test)] mod tests { use super::{ - identify_alg_params_for_hash_type, identify_key_hash_type_for_algorithm_params, - py_hash_name_from_hash_type, HashType, KeyType, + identify_alg_params_for_hash_type, identify_key_type_for_algorithm_params, HashType, + KeyType, }; use cryptography_x509::{common, oid}; #[test] - fn test_identify_key_hash_type_for_algorithm_params() { - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::RsaWithSha224(Some(())) - ) - .unwrap(), - (KeyType::Rsa, HashType::Sha224) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::RsaWithSha256(Some(())) - ) - .unwrap(), - (KeyType::Rsa, HashType::Sha256) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::RsaWithSha384(Some(())) - ) - .unwrap(), - (KeyType::Rsa, HashType::Sha384) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::RsaWithSha512(Some(())) - ) - .unwrap(), - (KeyType::Rsa, HashType::Sha512) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::RsaWithSha3_224(Some(())) - ) - .unwrap(), - (KeyType::Rsa, HashType::Sha3_224) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::RsaWithSha3_256(Some(())) - ) - .unwrap(), - (KeyType::Rsa, HashType::Sha3_256) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::RsaWithSha3_384(Some(())) - ) - .unwrap(), - (KeyType::Rsa, HashType::Sha3_384) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::RsaWithSha3_512(Some(())) - ) - .unwrap(), - (KeyType::Rsa, HashType::Sha3_512) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::EcDsaWithSha224 - ) - .unwrap(), - (KeyType::Ec, HashType::Sha224) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::EcDsaWithSha256 - ) - .unwrap(), - (KeyType::Ec, HashType::Sha256) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::EcDsaWithSha384 - ) - .unwrap(), - (KeyType::Ec, HashType::Sha384) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::EcDsaWithSha512 - ) - .unwrap(), - (KeyType::Ec, HashType::Sha512) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::EcDsaWithSha3_224 - ) - .unwrap(), - (KeyType::Ec, HashType::Sha3_224) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::EcDsaWithSha3_256 - ) - .unwrap(), - (KeyType::Ec, HashType::Sha3_256) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::EcDsaWithSha3_384 - ) - .unwrap(), - (KeyType::Ec, HashType::Sha3_384) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::EcDsaWithSha3_512 - ) - .unwrap(), - (KeyType::Ec, HashType::Sha3_512) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params(&common::AlgorithmParameters::Ed25519) - .unwrap(), - (KeyType::Ed25519, HashType::None) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params(&common::AlgorithmParameters::Ed448) - .unwrap(), - (KeyType::Ed448, HashType::None) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::DsaWithSha224 - ) - .unwrap(), - (KeyType::Dsa, HashType::Sha224) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::DsaWithSha256 - ) - .unwrap(), - (KeyType::Dsa, HashType::Sha256) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::DsaWithSha384 - ) - .unwrap(), - (KeyType::Dsa, HashType::Sha384) - ); - assert_eq!( - identify_key_hash_type_for_algorithm_params( - &common::AlgorithmParameters::DsaWithSha512 - ) - .unwrap(), - (KeyType::Dsa, HashType::Sha512) - ); + fn test_identify_key_type_for_algorithm_params() { + for (params, keytype) in [ + ( + &common::AlgorithmParameters::RsaWithSha224(Some(())), + KeyType::Rsa, + ), + ( + &common::AlgorithmParameters::RsaWithSha256(Some(())), + KeyType::Rsa, + ), + ( + &common::AlgorithmParameters::RsaWithSha384(Some(())), + KeyType::Rsa, + ), + ( + &common::AlgorithmParameters::RsaWithSha512(Some(())), + KeyType::Rsa, + ), + ( + &common::AlgorithmParameters::RsaWithSha3_224(Some(())), + KeyType::Rsa, + ), + ( + &common::AlgorithmParameters::RsaWithSha3_256(Some(())), + KeyType::Rsa, + ), + ( + &common::AlgorithmParameters::RsaWithSha3_384(Some(())), + KeyType::Rsa, + ), + ( + &common::AlgorithmParameters::RsaWithSha3_512(Some(())), + KeyType::Rsa, + ), + (&common::AlgorithmParameters::EcDsaWithSha224, KeyType::Ec), + (&common::AlgorithmParameters::EcDsaWithSha256, KeyType::Ec), + (&common::AlgorithmParameters::EcDsaWithSha384, KeyType::Ec), + (&common::AlgorithmParameters::EcDsaWithSha512, KeyType::Ec), + (&common::AlgorithmParameters::EcDsaWithSha3_224, KeyType::Ec), + (&common::AlgorithmParameters::EcDsaWithSha3_256, KeyType::Ec), + (&common::AlgorithmParameters::EcDsaWithSha3_384, KeyType::Ec), + (&common::AlgorithmParameters::EcDsaWithSha3_512, KeyType::Ec), + (&common::AlgorithmParameters::Ed25519, KeyType::Ed25519), + (&common::AlgorithmParameters::Ed448, KeyType::Ed448), + (&common::AlgorithmParameters::DsaWithSha224, KeyType::Dsa), + (&common::AlgorithmParameters::DsaWithSha256, KeyType::Dsa), + (&common::AlgorithmParameters::DsaWithSha384, KeyType::Dsa), + (&common::AlgorithmParameters::DsaWithSha512, KeyType::Dsa), + ] { + assert_eq!( + identify_key_type_for_algorithm_params(params).unwrap(), + keytype + ); + } assert!( - identify_key_hash_type_for_algorithm_params(&common::AlgorithmParameters::Other( + identify_key_type_for_algorithm_params(&common::AlgorithmParameters::Other( oid::TLS_FEATURE_OID, None )) @@ -727,21 +603,4 @@ mod tests { assert_eq!(identify_alg_params_for_hash_type(hash).unwrap(), params); } } - - #[test] - fn test_py_hash_name_from_hash_type() { - for (hash, name) in [ - (HashType::Sha224, "SHA224"), - (HashType::Sha256, "SHA256"), - (HashType::Sha384, "SHA384"), - (HashType::Sha512, "SHA512"), - (HashType::Sha3_224, "SHA3_224"), - (HashType::Sha3_256, "SHA3_256"), - (HashType::Sha3_384, "SHA3_384"), - (HashType::Sha3_512, "SHA3_512"), - ] { - let hash_str = py_hash_name_from_hash_type(hash).unwrap(); - assert_eq!(hash_str, name); - } - } } diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 19a854e24a98..5fd5265b7f4e 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -1558,6 +1558,50 @@ def test_parse_tls_feature_extension(self, backend): [x509.TLSFeatureType.status_request] ) + def test_verify_directly_issued_by_rsa_pss( + self, rsa_key_2048: rsa.RSAPrivateKey + ): + subject_private_key = RSA_KEY_2048_ALT.private_key( + unsafe_skip_rsa_key_validation=True + ) + + builder = ( + x509.CertificateBuilder() + .subject_name( + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "PyCA CA")]) + ) + .issuer_name( + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "PyCA CA")]) + ) + .public_key(rsa_key_2048.public_key()) + .serial_number(1) + .not_valid_before(datetime.datetime(2020, 1, 1)) + .not_valid_after(datetime.datetime(2030, 1, 1)) + ) + ca = builder.sign(rsa_key_2048, hashes.SHA256()) + builder = ( + x509.CertificateBuilder() + .subject_name( + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "leaf")]) + ) + .issuer_name( + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "PyCA CA")]) + ) + .public_key(subject_private_key.public_key()) + .serial_number(100) + .not_valid_before(datetime.datetime(2020, 1, 1)) + .not_valid_after(datetime.datetime(2025, 1, 1)) + ) + cert = builder.sign( + rsa_key_2048, + hashes.SHA256(), + rsa_padding=padding.PSS( + padding.MGF1(hashes.SHA256()), + salt_length=padding.PSS.DIGEST_LENGTH, + ), + ) + cert.verify_directly_issued_by(ca) + def test_verify_directly_issued_by_rsa( self, rsa_key_2048: rsa.RSAPrivateKey ): From cff3c8fee74ba08cc0ce4b67bbb635f73270f8b3 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 14 May 2023 16:36:57 -0400 Subject: [PATCH 261/316] There are wheels for basically all linux distros now (#8923) --- docs/installation.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 896baf8f6d1d..f35f270effea 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -79,11 +79,10 @@ 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``! + You should **upgrade pip** and attempt to install ``cryptography`` again + before following the instructions to compile it below. Most Linux + 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.3** or above running on a ``manylinux2014`` From 4fc8e9aaa12f0b69fca0f36c544543aefb9c5d03 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 14 May 2023 16:37:20 -0400 Subject: [PATCH 262/316] Move code to sign.rs (#8922) --- src/rust/src/x509/certificate.rs | 140 +----------------------------- src/rust/src/x509/sign.rs | 143 ++++++++++++++++++++++++++++++- 2 files changed, 141 insertions(+), 142 deletions(-) diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 34e9ec0ec4b3..3446bbbbb604 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -17,28 +17,10 @@ use cryptography_x509::extensions::{ SequenceOfSubtrees, UserNotice, }; use cryptography_x509::{common, name, oid}; -use once_cell::sync::Lazy; use pyo3::{IntoPy, ToPyObject}; use std::collections::hash_map::DefaultHasher; -use std::collections::HashMap; use std::hash::{Hash, Hasher}; -// This is similar to a hashmap in ocsp.rs but contains more hash algorithms -// that aren't allowable in OCSP -static HASH_OIDS_TO_HASH: Lazy> = Lazy::new(|| { - let mut h = HashMap::new(); - h.insert(&oid::SHA1_OID, "SHA1"); - h.insert(&oid::SHA224_OID, "SHA224"); - h.insert(&oid::SHA256_OID, "SHA256"); - h.insert(&oid::SHA384_OID, "SHA384"); - h.insert(&oid::SHA512_OID, "SHA512"); - h.insert(&oid::SHA3_224_OID, "SHA3_224"); - h.insert(&oid::SHA3_256_OID, "SHA3_256"); - h.insert(&oid::SHA3_384_OID, "SHA3_384"); - h.insert(&oid::SHA3_512_OID, "SHA3_512"); - h -}); - #[ouroboros::self_referencing] pub(crate) struct OwnedCertificate { data: pyo3::Py, @@ -269,7 +251,7 @@ impl Certificate { &self, py: pyo3::Python<'p>, ) -> Result<&'p pyo3::PyAny, CryptographyError> { - identify_signature_hash_algorithm(py, &self.raw.borrow_value().signature_alg) + sign::identify_signature_hash_algorithm(py, &self.raw.borrow_value().signature_alg) } #[getter] @@ -282,7 +264,7 @@ impl Certificate { &'p self, py: pyo3::Python<'p>, ) -> CryptographyResult<&'p pyo3::PyAny> { - identify_signature_algorithm_parameters(py, &self.raw.borrow_value().signature_alg) + sign::identify_signature_algorithm_parameters(py, &self.raw.borrow_value().signature_alg) } #[getter] @@ -880,22 +862,6 @@ pub fn parse_cert_ext<'p>( } } -fn hash_oid_py_hash( - py: pyo3::Python<'_>, - oid: asn1::ObjectIdentifier, -) -> CryptographyResult<&pyo3::PyAny> { - let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; - match HASH_OIDS_TO_HASH.get(&oid) { - Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), - None => Err(CryptographyError::from( - exceptions::UnsupportedAlgorithm::new_err(format!( - "Signature algorithm OID: {} not recognized", - &oid - )), - )), - } -} - pub(crate) fn time_from_py( py: pyo3::Python<'_>, val: &pyo3::PyAny, @@ -994,108 +960,6 @@ pub(crate) fn set_bit(vals: &mut [u8], n: usize, set: bool) { } } -pub(crate) fn identify_signature_hash_algorithm<'p>( - py: pyo3::Python<'p>, - signature_algorithm: &common::AlgorithmIdentifier<'_>, -) -> CryptographyResult<&'p pyo3::PyAny> { - let sig_oids_to_hash = py - .import(pyo3::intern!(py, "cryptography.hazmat._oid"))? - .getattr(pyo3::intern!(py, "_SIG_OIDS_TO_HASH"))?; - match &signature_algorithm.params { - common::AlgorithmParameters::RsaPss(opt_pss) => { - let pss = opt_pss.as_ref().ok_or_else(|| { - pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters") - })?; - hash_oid_py_hash(py, pss.hash_algorithm.oid().clone()) - } - _ => { - let py_sig_alg_oid = oid_to_py_oid(py, signature_algorithm.oid())?; - let hash_alg = sig_oids_to_hash.get_item(py_sig_alg_oid); - match hash_alg { - Ok(data) => Ok(data), - Err(_) => Err(CryptographyError::from( - exceptions::UnsupportedAlgorithm::new_err(format!( - "Signature algorithm OID: {} not recognized", - signature_algorithm.oid() - )), - )), - } - } - } -} - -pub(crate) fn identify_signature_algorithm_parameters<'p>( - py: pyo3::Python<'p>, - signature_algorithm: &common::AlgorithmIdentifier<'_>, -) -> CryptographyResult<&'p pyo3::PyAny> { - match &signature_algorithm.params { - common::AlgorithmParameters::RsaPss(opt_pss) => { - let pss = opt_pss.as_ref().ok_or_else(|| { - pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters") - })?; - if pss.mask_gen_algorithm.oid != oid::MGF1_OID { - return Err(CryptographyError::from( - pyo3::exceptions::PyValueError::new_err(format!( - "Unsupported mask generation OID: {}", - pss.mask_gen_algorithm.oid - )), - )); - } - let py_mask_gen_hash_alg = - hash_oid_py_hash(py, pss.mask_gen_algorithm.params.oid().clone())?; - let padding = py.import(pyo3::intern!( - py, - "cryptography.hazmat.primitives.asymmetric.padding" - ))?; - let py_mgf = padding - .getattr(pyo3::intern!(py, "MGF1"))? - .call1((py_mask_gen_hash_alg,))?; - Ok(padding - .getattr(pyo3::intern!(py, "PSS"))? - .call1((py_mgf, pss.salt_length))?) - } - common::AlgorithmParameters::RsaWithSha1(_) - | common::AlgorithmParameters::RsaWithSha1Alt(_) - | common::AlgorithmParameters::RsaWithSha224(_) - | common::AlgorithmParameters::RsaWithSha256(_) - | common::AlgorithmParameters::RsaWithSha384(_) - | common::AlgorithmParameters::RsaWithSha512(_) - | common::AlgorithmParameters::RsaWithSha3_224(_) - | common::AlgorithmParameters::RsaWithSha3_256(_) - | common::AlgorithmParameters::RsaWithSha3_384(_) - | common::AlgorithmParameters::RsaWithSha3_512(_) => { - let pkcs = py - .import(pyo3::intern!( - py, - "cryptography.hazmat.primitives.asymmetric.padding" - ))? - .getattr(pyo3::intern!(py, "PKCS1v15"))? - .call0()?; - Ok(pkcs) - } - common::AlgorithmParameters::EcDsaWithSha224 - | common::AlgorithmParameters::EcDsaWithSha256 - | common::AlgorithmParameters::EcDsaWithSha384 - | common::AlgorithmParameters::EcDsaWithSha512 - | common::AlgorithmParameters::EcDsaWithSha3_224 - | common::AlgorithmParameters::EcDsaWithSha3_256 - | common::AlgorithmParameters::EcDsaWithSha3_384 - | common::AlgorithmParameters::EcDsaWithSha3_512 => { - let signature_hash_algorithm = - identify_signature_hash_algorithm(py, signature_algorithm)?; - - Ok(py - .import(pyo3::intern!( - py, - "cryptography.hazmat.primitives.asymmetric.ec" - ))? - .getattr(pyo3::intern!(py, "ECDSA"))? - .call1((signature_hash_algorithm,))?) - } - _ => Ok(py.None().into_ref(py)), - } -} - pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { module.add_function(pyo3::wrap_pyfunction!(load_der_x509_certificate, module)?)?; module.add_function(pyo3::wrap_pyfunction!(load_pem_x509_certificate, module)?)?; diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index 0543004201e9..16db5a587f90 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -2,10 +2,28 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. +use crate::asn1::oid_to_py_oid; use crate::error::{CryptographyError, CryptographyResult}; use crate::exceptions; -use crate::x509::certificate; use cryptography_x509::{common, oid}; +use once_cell::sync::Lazy; +use std::collections::HashMap; + +// This is similar to a hashmap in ocsp.rs but contains more hash algorithms +// that aren't allowable in OCSP +static HASH_OIDS_TO_HASH: Lazy> = Lazy::new(|| { + let mut h = HashMap::new(); + h.insert(&oid::SHA1_OID, "SHA1"); + h.insert(&oid::SHA224_OID, "SHA224"); + h.insert(&oid::SHA256_OID, "SHA256"); + h.insert(&oid::SHA384_OID, "SHA384"); + h.insert(&oid::SHA512_OID, "SHA512"); + h.insert(&oid::SHA3_224_OID, "SHA3_224"); + h.insert(&oid::SHA3_256_OID, "SHA3_256"); + h.insert(&oid::SHA3_384_OID, "SHA3_384"); + h.insert(&oid::SHA3_512_OID, "SHA3_512"); + h +}); #[derive(Debug, PartialEq)] pub(crate) enum KeyType { @@ -368,9 +386,8 @@ pub(crate) fn verify_signature_with_signature_algorithm<'p>( )); } let py_signature_algorithm_parameters = - certificate::identify_signature_algorithm_parameters(py, signature_algorithm)?; - let py_signature_hash_algorithm = - certificate::identify_signature_hash_algorithm(py, signature_algorithm)?; + identify_signature_algorithm_parameters(py, signature_algorithm)?; + let py_signature_hash_algorithm = identify_signature_hash_algorithm(py, signature_algorithm)?; match key_type { KeyType::Ed25519 | KeyType::Ed448 => { issuer_public_key.call_method1(pyo3::intern!(py, "verify"), (signature, data))? @@ -504,6 +521,124 @@ fn identify_alg_params_for_hash_type( } } +fn hash_oid_py_hash( + py: pyo3::Python<'_>, + oid: asn1::ObjectIdentifier, +) -> CryptographyResult<&pyo3::PyAny> { + let hashes = py.import(pyo3::intern!(py, "cryptography.hazmat.primitives.hashes"))?; + match HASH_OIDS_TO_HASH.get(&oid) { + Some(alg_name) => Ok(hashes.getattr(*alg_name)?.call0()?), + None => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + &oid + )), + )), + } +} + +pub(crate) fn identify_signature_hash_algorithm<'p>( + py: pyo3::Python<'p>, + signature_algorithm: &common::AlgorithmIdentifier<'_>, +) -> CryptographyResult<&'p pyo3::PyAny> { + let sig_oids_to_hash = py + .import(pyo3::intern!(py, "cryptography.hazmat._oid"))? + .getattr(pyo3::intern!(py, "_SIG_OIDS_TO_HASH"))?; + match &signature_algorithm.params { + common::AlgorithmParameters::RsaPss(opt_pss) => { + let pss = opt_pss.as_ref().ok_or_else(|| { + pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters") + })?; + hash_oid_py_hash(py, pss.hash_algorithm.oid().clone()) + } + _ => { + let py_sig_alg_oid = oid_to_py_oid(py, signature_algorithm.oid())?; + let hash_alg = sig_oids_to_hash.get_item(py_sig_alg_oid); + match hash_alg { + Ok(data) => Ok(data), + Err(_) => Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(format!( + "Signature algorithm OID: {} not recognized", + signature_algorithm.oid() + )), + )), + } + } + } +} + +pub(crate) fn identify_signature_algorithm_parameters<'p>( + py: pyo3::Python<'p>, + signature_algorithm: &common::AlgorithmIdentifier<'_>, +) -> CryptographyResult<&'p pyo3::PyAny> { + match &signature_algorithm.params { + common::AlgorithmParameters::RsaPss(opt_pss) => { + let pss = opt_pss.as_ref().ok_or_else(|| { + pyo3::exceptions::PyValueError::new_err("Invalid RSA PSS parameters") + })?; + if pss.mask_gen_algorithm.oid != oid::MGF1_OID { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err(format!( + "Unsupported mask generation OID: {}", + pss.mask_gen_algorithm.oid + )), + )); + } + let py_mask_gen_hash_alg = + hash_oid_py_hash(py, pss.mask_gen_algorithm.params.oid().clone())?; + let padding = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.padding" + ))?; + let py_mgf = padding + .getattr(pyo3::intern!(py, "MGF1"))? + .call1((py_mask_gen_hash_alg,))?; + Ok(padding + .getattr(pyo3::intern!(py, "PSS"))? + .call1((py_mgf, pss.salt_length))?) + } + common::AlgorithmParameters::RsaWithSha1(_) + | common::AlgorithmParameters::RsaWithSha1Alt(_) + | common::AlgorithmParameters::RsaWithSha224(_) + | common::AlgorithmParameters::RsaWithSha256(_) + | common::AlgorithmParameters::RsaWithSha384(_) + | common::AlgorithmParameters::RsaWithSha512(_) + | common::AlgorithmParameters::RsaWithSha3_224(_) + | common::AlgorithmParameters::RsaWithSha3_256(_) + | common::AlgorithmParameters::RsaWithSha3_384(_) + | common::AlgorithmParameters::RsaWithSha3_512(_) => { + let pkcs = py + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.padding" + ))? + .getattr(pyo3::intern!(py, "PKCS1v15"))? + .call0()?; + Ok(pkcs) + } + common::AlgorithmParameters::EcDsaWithSha224 + | common::AlgorithmParameters::EcDsaWithSha256 + | common::AlgorithmParameters::EcDsaWithSha384 + | common::AlgorithmParameters::EcDsaWithSha512 + | common::AlgorithmParameters::EcDsaWithSha3_224 + | common::AlgorithmParameters::EcDsaWithSha3_256 + | common::AlgorithmParameters::EcDsaWithSha3_384 + | common::AlgorithmParameters::EcDsaWithSha3_512 => { + let signature_hash_algorithm = + identify_signature_hash_algorithm(py, signature_algorithm)?; + + Ok(py + .import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.ec" + ))? + .getattr(pyo3::intern!(py, "ECDSA"))? + .call1((signature_hash_algorithm,))?) + } + _ => Ok(py.None().into_ref(py)), + } +} + #[cfg(test)] mod tests { use super::{ From 7a7aa67abcbf6a2c968d3479383d57ebc47a1f29 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Sun, 14 May 2023 20:51:18 -0400 Subject: [PATCH 263/316] Bump BoringSSL and/or OpenSSL in CI (#8926) Co-authored-by: pyca-boringbot[bot] --- .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 3a3d8e587d95..c11defdbb54a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,8 +41,8 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of May 13, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "c215ce7e8230786e0d4ec463d95a9e44af513e6a"}} + # Latest commit on the BoringSSL master branch, as of May 15, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "c1f5d795c2e5778254c94ca115fb89ff56624b73"}} # Latest commit on the OpenSSL master branch, as of May 13, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "2b5a546ce1960883febc51f5d2a71a8b7c1b3ab9"}} timeout-minutes: 15 From 24c582a1dc0bc07da4247b938cf293a04010c0a9 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 14 May 2023 21:11:24 -0400 Subject: [PATCH 264/316] Pass --all to cargo test (#8925) --- noxfile.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index 8c9cc218b56b..c70b1c333e63 100644 --- a/noxfile.py +++ b/noxfile.py @@ -143,4 +143,6 @@ def rust(session: nox.Session) -> None: with session.chdir("src/rust/"): session.run("cargo", "fmt", "--all", "--", "--check", external=True) session.run("cargo", "clippy", "--", "-D", "warnings", external=True) - session.run("cargo", "test", "--no-default-features", external=True) + session.run( + "cargo", "test", "--no-default-features", "--all", external=True + ) From d7996dc01fb23cc737678d67f322b1b62a034cd2 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 14 May 2023 21:48:31 -0400 Subject: [PATCH 265/316] Run full nox rust env in coverage jobs (#8924) * Run full nox rust env in coverage jobs * Update ci.yml * Update ci.yml * fix 1.60 clippy warnings * warning name changed --- .github/workflows/ci.yml | 15 ++++---------- src/rust/cryptography-x509/src/lib.rs | 2 ++ src/rust/src/pkcs7.rs | 28 +++++++++++++-------------- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c11defdbb54a..d50e8f1d0f9c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -267,7 +267,7 @@ jobs: id: rust-toolchain with: toolchain: ${{ matrix.RUST }} - components: llvm-tools-preview + components: llvm-tools-preview,rustfmt,clippy - name: Cache rust and pip id: cargo-cache uses: ./.github/actions/cache @@ -304,27 +304,20 @@ jobs: - name: Clone wycheproof timeout-minutes: 2 uses: ./.github/actions/wycheproof - - run: python -m pip install -c ci-constraints-requirements.txt 'nox' cffi + - run: python -m pip install -c ci-constraints-requirements.txt 'nox' - name: Create nox environment - run: nox -v --install-only -s tests + run: nox -v --install-only -s tests rust env: CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} RUSTFLAGS: "-Cinstrument-coverage" LLVM_PROFILE_FILE: "rust-cov/cov-%p.profraw" - name: Tests - run: nox --no-install -s tests -- --color=yes --wycheproof-root=wycheproof + run: nox --no-install -s tests rust -- --color=yes --wycheproof-root=wycheproof env: COLUMNS: 80 CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} RUSTFLAGS: "-Cinstrument-coverage" LLVM_PROFILE_FILE: "rust-cov/cov-%p.profraw" - - name: Rust Tests - run: | - cd src/rust - cargo test --no-default-features --all - env: - RUSTFLAGS: "-Cinstrument-coverage" - LLVM_PROFILE_FILE: "rust-cov/cov-%m-%p.profraw" - name: Process coverage data run: | set -xe diff --git a/src/rust/cryptography-x509/src/lib.rs b/src/rust/cryptography-x509/src/lib.rs index 548e073b13e5..131c3fd156eb 100644 --- a/src/rust/cryptography-x509/src/lib.rs +++ b/src/rust/cryptography-x509/src/lib.rs @@ -3,6 +3,8 @@ // for complete details. #![forbid(unsafe_code)] +// These can be removed once our MSRV is >1.60 +#![allow(renamed_and_removed_lints, clippy::eval_order_dependence)] pub mod certificate; pub mod common; diff --git a/src/rust/src/pkcs7.rs b/src/rust/src/pkcs7.rs index 6a49acf98c7b..d2c500a72de7 100644 --- a/src/rust/src/pkcs7.rs +++ b/src/rust/src/pkcs7.rs @@ -139,20 +139,20 @@ fn sign_and_serialize<'p>( )?, ) } else { - let mut authenticated_attrs = vec![]; - - authenticated_attrs.push(Attribute { - type_id: PKCS7_CONTENT_TYPE_OID, - values: common::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ - asn1::parse_single(&content_type_bytes).unwrap(), - ])), - }); - authenticated_attrs.push(Attribute { - type_id: PKCS7_SIGNING_TIME_OID, - values: common::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ - asn1::parse_single(&signing_time_bytes).unwrap(), - ])), - }); + let mut authenticated_attrs = vec![ + Attribute { + type_id: PKCS7_CONTENT_TYPE_OID, + values: common::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ + asn1::parse_single(&content_type_bytes).unwrap(), + ])), + }, + Attribute { + type_id: PKCS7_SIGNING_TIME_OID, + values: common::Asn1ReadableOrWritable::new_write(asn1::SetOfWriter::new([ + asn1::parse_single(&signing_time_bytes).unwrap(), + ])), + }, + ]; let digest = asn1::write_single(&x509::ocsp::hash_data(py, py_hash_alg, &data_with_header)?)?; From d6586fdbeab4e15e111e55790d8ed789c97757ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 May 2023 11:02:21 +0000 Subject: [PATCH 266/316] Bump proc-macro2 from 1.0.56 to 1.0.57 in /src/rust (#8928) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.56 to 1.0.57. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.56...1.0.57) --- 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 9fdd2313155b..fd51294d9bba 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -285,9 +285,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "c4ec6d5fe0b140acb27c9a0444118cf55bfbb4e0b259739429abb4521dd67c16" dependencies = [ "unicode-ident", ] From e26a4207037f7e76dbb1913c52907c5342937ec8 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 15 May 2023 07:42:16 -0400 Subject: [PATCH 267/316] Move slightly more of the rust coverage logic into noxfile.py (#8927) --- .github/workflows/ci.yml | 46 +++++++++++++++++++--------------------- noxfile.py | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 24 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d50e8f1d0f9c..291d5c6acb67 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -130,22 +130,22 @@ jobs: fail-fast: false matrix: IMAGE: - - {IMAGE: "rhel8", RUNNER: "ubuntu-latest"} - - {IMAGE: "rhel8-fips", RUNNER: "ubuntu-latest", FIPS: true} - - {IMAGE: "buster", RUNNER: "ubuntu-latest"} - - {IMAGE: "bullseye", RUNNER: "ubuntu-latest"} - - {IMAGE: "bookworm", RUNNER: "ubuntu-latest"} - - {IMAGE: "sid", RUNNER: "ubuntu-latest"} - - {IMAGE: "ubuntu-focal", RUNNER: "ubuntu-latest"} - - {IMAGE: "ubuntu-jammy", RUNNER: "ubuntu-latest"} - - {IMAGE: "ubuntu-rolling", RUNNER: "ubuntu-latest"} - - {IMAGE: "fedora", RUNNER: "ubuntu-latest"} - - {IMAGE: "alpine", RUNNER: "ubuntu-latest"} - - {IMAGE: "centos-stream9", RUNNER: "ubuntu-latest"} - - {IMAGE: "centos-stream9-fips", RUNNER: "ubuntu-latest", FIPS: true} + - {IMAGE: "rhel8", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} + - {IMAGE: "rhel8-fips", NOXSESSION: "tests", RUNNER: "ubuntu-latest", FIPS: true} + - {IMAGE: "buster", NOXSESSION: "tests-nocoverage", RUNNER: "ubuntu-latest"} + - {IMAGE: "bullseye", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} + - {IMAGE: "bookworm", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} + - {IMAGE: "sid", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} + - {IMAGE: "ubuntu-focal", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} + - {IMAGE: "ubuntu-jammy", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} + - {IMAGE: "ubuntu-rolling", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} + - {IMAGE: "fedora", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} + - {IMAGE: "alpine", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} + - {IMAGE: "centos-stream9", NOXSESSION: "tests", RUNNER: "ubuntu-latest"} + - {IMAGE: "centos-stream9-fips", NOXSESSION: "tests", RUNNER: "ubuntu-latest", FIPS: true} - - {IMAGE: "ubuntu-jammy:aarch64", RUNNER: [self-hosted, Linux, ARM64]} - - {IMAGE: "alpine:aarch64", RUNNER: [self-hosted, Linux, ARM64]} + - {IMAGE: "ubuntu-jammy:aarch64", NOXSESSION: "tests", RUNNER: [self-hosted, Linux, ARM64]} + - {IMAGE: "alpine:aarch64", NOXSESSION: "tests-nocoverage", RUNNER: [self-hosted, Linux, ARM64]} timeout-minutes: 15 steps: - name: Ridiculous alpine workaround for actions support on arm64 @@ -183,17 +183,19 @@ jobs: echo "OPENSSL_FORCE_FIPS_MODE=1" >> $GITHUB_ENV if: matrix.IMAGE.FIPS - run: /venv/bin/python -m pip install -c ci-constraints-requirements.txt 'nox' - - run: '/venv/bin/nox -v --install-only -s tests' + - run: '/venv/bin/nox -v --install-only' env: RUSTUP_HOME: /root/.rustup CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} # OPENSSL_ENABLE_SHA1_SIGNATURES is for CentOS 9 Stream OPENSSL_ENABLE_SHA1_SIGNATURES: 1 - - run: '/venv/bin/nox --no-install -s tests -- --color=yes --wycheproof-root="wycheproof"' + NOXSESSION: ${{ matrix.IMAGE.NOXSESSION }} + - run: '/venv/bin/nox --no-install -- --color=yes --wycheproof-root="wycheproof"' env: COLUMNS: 80 # OPENSSL_ENABLE_SHA1_SIGNATURES is for CentOS 9 Stream OPENSSL_ENABLE_SHA1_SIGNATURES: 1 + NOXSESSION: ${{ matrix.IMAGE.NOXSESSION }} - uses: ./.github/actions/upload-coverage linux-rust: @@ -231,11 +233,11 @@ jobs: uses: ./.github/actions/wycheproof - run: python -m pip install -c ci-constraints-requirements.txt 'nox' - name: Create nox environment - run: nox -v --install-only -s tests + run: nox -v --install-only -s tests-nocoverage env: CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - name: Tests - run: nox --no-install -s tests -- --color=yes --wycheproof-root=wycheproof + run: nox --no-install -s tests-nocoverage -- --color=yes --wycheproof-root=wycheproof env: COLUMNS: 80 - uses: ./.github/actions/upload-coverage @@ -309,15 +311,11 @@ jobs: run: nox -v --install-only -s tests rust env: CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - RUSTFLAGS: "-Cinstrument-coverage" - LLVM_PROFILE_FILE: "rust-cov/cov-%p.profraw" - name: Tests run: nox --no-install -s tests rust -- --color=yes --wycheproof-root=wycheproof env: COLUMNS: 80 CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - RUSTFLAGS: "-Cinstrument-coverage" - LLVM_PROFILE_FILE: "rust-cov/cov-%p.profraw" - name: Process coverage data run: | set -xe @@ -327,7 +325,7 @@ jobs: cargo cov -- export \ ../../.nox/tests/lib/python${{ matrix.PYTHON }}/site-packages/cryptography/hazmat/bindings/_rust.abi3.so \ - $(env RUSTFLAGS="-Cinstrument-coverage" cargo test --no-default-features --all --tests --no-run --message-format=json | jq -r "select(.profile.test == true) | .filenames[]" | awk '{print "-object " $0}') \ + $(cat ../../rust-tests.txt | awk '{print "-object " $0}') \ -instr-profile=rust-cov.profdata \ --ignore-filename-regex='/.cargo/' \ --ignore-filename-regex='/rustc/' \ diff --git a/noxfile.py b/noxfile.py index c70b1c333e63..93b10cd33f84 100644 --- a/noxfile.py +++ b/noxfile.py @@ -4,6 +4,8 @@ from __future__ import annotations +import json + import nox nox.options.reuse_existing_virtualenvs = True @@ -30,6 +32,15 @@ def tests(session: nox.Session) -> None: if session.name == "tests-randomorder": extras += ",test-randomorder" + if session.name != "tests-nocoverage": + session.env.update( + { + "RUSTFLAGS": "-Cinstrument-coverage " + + session.env.get("RUSTFLAGS", ""), + "LLVM_PROFILE_FILE": ".rust-cov/cov-%p.profraw", + } + ) + install(session, f".[{extras}]") install(session, "-e", "./vectors") @@ -138,11 +149,43 @@ def flake(session: nox.Session) -> None: @nox.session def rust(session: nox.Session) -> None: + session.env.update( + { + "RUSTFLAGS": "-Cinstrument-coverage " + + session.env.get("RUSTFLAGS", ""), + "LLVM_PROFILE_FILE": ".rust-cov/cov-%p.profraw", + } + ) + install(session, ".") with session.chdir("src/rust/"): session.run("cargo", "fmt", "--all", "--", "--check", external=True) session.run("cargo", "clippy", "--", "-D", "warnings", external=True) + + build_output = session.run( + "cargo", + "test", + "--no-default-features", + "--all", + "--no-run", + "-q", + "--message-format=json", + external=True, + silent=True, + ) session.run( "cargo", "test", "--no-default-features", "--all", external=True ) + + # It's None on install-only invocations + if build_output is not None: + assert isinstance(build_output, str) + rust_tests = [] + for line in build_output.splitlines(): + data = json.loads(line) + if data.get("profile", {}).get("test", False): + rust_tests.extend(data["filenames"]) + + with open("rust-tests.txt", "w") as f: + f.write("\n".join(rust_tests)) From 16fbebd345460fa173d851b226ecbf74abf9c3ec Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Tue, 16 May 2023 08:33:17 +0800 Subject: [PATCH 268/316] Bump BoringSSL and/or OpenSSL in CI (#8932) Co-authored-by: pyca-boringbot[bot] --- .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 291d5c6acb67..53fe7c385fb5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of May 15, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "c1f5d795c2e5778254c94ca115fb89ff56624b73"}} - # Latest commit on the OpenSSL master branch, as of May 13, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "2b5a546ce1960883febc51f5d2a71a8b7c1b3ab9"}} + # Latest commit on the BoringSSL master branch, as of May 16, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "dd9ee6068667ca58c8d6f1c1cea617fd69452ecf"}} + # Latest commit on the OpenSSL master branch, as of May 16, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "43d5dac9d00ac486823d949f85ee3ad650b62af8"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 4b8187f8bc8265ca5aba76994ca8963b845c0705 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 16 May 2023 08:38:15 +0800 Subject: [PATCH 269/316] don't use a set (#8931) * don't use a set We don't need one here and it creates ordering instability when iterating over an RDN * add a test --- src/rust/src/x509/common.rs | 4 ++-- tests/x509/test_x509.py | 41 +++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/rust/src/x509/common.rs b/src/rust/src/x509/common.rs index bc26dace3fa9..8ceb518846d1 100644 --- a/src/rust/src/x509/common.rs +++ b/src/rust/src/x509/common.rs @@ -238,10 +238,10 @@ pub(crate) fn parse_rdn<'a>( rdn: &asn1::SetOf<'a, AttributeTypeValue<'a>>, ) -> Result { let x509_module = py.import(pyo3::intern!(py, "cryptography.x509"))?; - let py_attrs = pyo3::types::PySet::empty(py)?; + let py_attrs = pyo3::types::PyList::empty(py); for attribute in rdn.clone() { let na = parse_name_attribute(py, attribute)?; - py_attrs.add(na)?; + py_attrs.append(na)?; } Ok(x509_module .call_method1(pyo3::intern!(py, "RelativeDistinguishedName"), (py_attrs,))? diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 5fd5265b7f4e..88be1a1763a2 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -2463,6 +2463,47 @@ def test_extreme_times( # GENERALIZED TIME assert parsed.not_after_tag == 0x18 + def test_rdns_preserve_iteration_order( + self, rsa_key_2048: rsa.RSAPrivateKey, backend + ): + """ + This test checks that RDN ordering is consistent when loading + data from a certificate. Since the underlying RDN is an ASN.1 + set these values get lexicographically ordered on encode and + the parsed value won't necessarily be in the same order as + the originally provided list. However, we want to make sure + that the order is always consistent since it confuses people + when it isn't. + """ + name = x509.Name( + [ + x509.RelativeDistinguishedName( + [ + x509.NameAttribute(NameOID.TITLE, "Test"), + x509.NameAttribute(NameOID.COMMON_NAME, "Multivalue"), + x509.NameAttribute(NameOID.SURNAME, "RDNs"), + ] + ), + ] + ) + + cert = ( + x509.CertificateBuilder() + .serial_number(1) + .issuer_name(name) + .subject_name(name) + .public_key(rsa_key_2048.public_key()) + .not_valid_before(datetime.datetime(2020, 1, 1)) + .not_valid_after(datetime.datetime(2038, 1, 1)) + .sign(rsa_key_2048, hashes.SHA256(), backend) + ) + loaded_cert = x509.load_pem_x509_certificate( + cert.public_bytes(encoding=serialization.Encoding.PEM) + ) + assert next(iter(loaded_cert.subject.rdns[0])) == x509.NameAttribute( + NameOID.SURNAME, "RDNs" + ) + @pytest.mark.parametrize( ("alg", "mgf_alg"), [ From 983b4617fe9668d03f6c58de56fadd1cbc296e64 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 15 May 2023 22:14:49 -0400 Subject: [PATCH 270/316] Cache slightly less in rust-coverage jobs (#8934) * Cache slightly less in rust-coverage jobs * Trigger CI to test cache --- .github/actions/cache/action.yml | 2 +- .github/workflows/ci.yml | 15 --------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/.github/actions/cache/action.yml b/.github/actions/cache/action.yml index 37b9cc81bd37..47414c0f4f11 100644 --- a/.github/actions/cache/action.yml +++ b/.github/actions/cache/action.yml @@ -43,7 +43,7 @@ runs: ~/.cargo/registry/cache/ src/rust/target/ ${{ inputs.additional-paths }} - key: cargo-pip-${{ runner.os }}-${{ runner.arch }}-${{ inputs.key }}-3-${{ hashFiles('**/Cargo.lock', '**/*.rs') }}-${{ steps.rust-version.version }} + key: cargo-pip-${{ runner.os }}-${{ runner.arch }}-${{ inputs.key }}-4-${{ hashFiles('**/Cargo.lock', '**/*.rs') }}-${{ steps.rust-version.version }} - name: Size of cache items run: | du -sh ~/.cargo/registry/index/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 53fe7c385fb5..af52faacc78d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -278,24 +278,9 @@ jobs: key: coverage additional-paths: | ~/.cargo/bin/cargo-cov - ~/.cargo/bin/cargo-nm - ~/.cargo/bin/cargo-objcopy - ~/.cargo/bin/cargo-objdump ~/.cargo/bin/cargo-profdata - ~/.cargo/bin/cargo-readobj - ~/.cargo/bin/cargo-size - ~/.cargo/bin/cargo-strip - ~/.cargo/bin/rust-ar ~/.cargo/bin/rust-cov - ~/.cargo/bin/rust-ld - ~/.cargo/bin/rust-lld - ~/.cargo/bin/rust-nm - ~/.cargo/bin/rust-objcopy - ~/.cargo/bin/rust-objdump ~/.cargo/bin/rust-profdata - ~/.cargo/bin/rust-readobj - ~/.cargo/bin/rust-size - ~/.cargo/bin/rust-strip - name: Setup python uses: actions/setup-python@v4.6.0 with: From fb0606fd74d01efd319d9f98e0221bed1b45fa2a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 15 May 2023 22:46:54 -0400 Subject: [PATCH 271/316] Stop using cargo-binutils (#8935) Just find the copy of llvm-profdata/llvm-cov from rustc itself --- .github/actions/cache/action.yml | 2 +- .github/workflows/ci.yml | 20 ++++++-------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/.github/actions/cache/action.yml b/.github/actions/cache/action.yml index 47414c0f4f11..4581770f93d5 100644 --- a/.github/actions/cache/action.yml +++ b/.github/actions/cache/action.yml @@ -43,7 +43,7 @@ runs: ~/.cargo/registry/cache/ src/rust/target/ ${{ inputs.additional-paths }} - key: cargo-pip-${{ runner.os }}-${{ runner.arch }}-${{ inputs.key }}-4-${{ hashFiles('**/Cargo.lock', '**/*.rs') }}-${{ steps.rust-version.version }} + key: cargo-pip-${{ runner.os }}-${{ runner.arch }}-${{ inputs.key }}-5-${{ hashFiles('**/Cargo.lock', '**/*.rs') }}-${{ steps.rust-version.version }} - name: Size of cache items run: | du -sh ~/.cargo/registry/index/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af52faacc78d..cbd679da08c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -276,17 +276,10 @@ jobs: timeout-minutes: 2 with: key: coverage - additional-paths: | - ~/.cargo/bin/cargo-cov - ~/.cargo/bin/cargo-profdata - ~/.cargo/bin/rust-cov - ~/.cargo/bin/rust-profdata - name: Setup python uses: actions/setup-python@v4.6.0 with: python-version: ${{ matrix.PYTHON }} - - run: cargo install cargo-binutils - if: steps.cargo-cache.outputs.cache-hit != 'true' - name: Clone wycheproof timeout-minutes: 2 @@ -304,19 +297,18 @@ jobs: - name: Process coverage data run: | set -xe - cd src/rust/ - cargo profdata -- merge -sparse $(find ../.. -iname "*.profraw") -o rust-cov.profdata + "$(rustc --print target-libdir)/../bin/llvm-profdata" merge -sparse $(find . -iname "*.profraw") -o rust-cov.profdata COV_UUID=$(python3 -c "import uuid; print(uuid.uuid4())") - cargo cov -- export \ - ../../.nox/tests/lib/python${{ matrix.PYTHON }}/site-packages/cryptography/hazmat/bindings/_rust.abi3.so \ - $(cat ../../rust-tests.txt | awk '{print "-object " $0}') \ + "$(rustc --print target-libdir)/../bin/llvm-cov" export \ + .nox/tests/lib/python${{ matrix.PYTHON }}/site-packages/cryptography/hazmat/bindings/_rust.abi3.so \ + $(cat rust-tests.txt | awk '{print "-object " $0}') \ -instr-profile=rust-cov.profdata \ --ignore-filename-regex='/.cargo/' \ --ignore-filename-regex='/rustc/' \ - --ignore-filename-regex='/.rustup/toolchains/' --format=lcov > "../../${COV_UUID}.lcov" + --ignore-filename-regex='/.rustup/toolchains/' --format=lcov > "${COV_UUID}.lcov" - sed -E -i 's/SF:(.*)\/src\/rust\/(.*)/SF:src\/rust\/\2/g' "../../${COV_UUID}.lcov" + sed -E -i 's/SF:(.*)\/src\/rust\/(.*)/SF:src\/rust\/\2/g' "${COV_UUID}.lcov" - uses: ./.github/actions/upload-coverage macos: From 1de2c14fb203808c647e1e8734e79c17ef7dc123 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Wed, 17 May 2023 00:16:57 +0000 Subject: [PATCH 272/316] Bump BoringSSL and/or OpenSSL in CI (#8937) Co-authored-by: pyca-boringbot[bot] --- .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 cbd679da08c0..273d5d8082fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,8 +41,8 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of May 16, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "dd9ee6068667ca58c8d6f1c1cea617fd69452ecf"}} + # Latest commit on the BoringSSL master branch, as of May 17, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "dd5219451c3ce26221762a15d867edf43b463bb2"}} # Latest commit on the OpenSSL master branch, as of May 16, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "43d5dac9d00ac486823d949f85ee3ad650b62af8"}} timeout-minutes: 15 From 5b7dd82561760a6d3545b0f6bc62d434c257e49e Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 16 May 2023 20:39:18 -0400 Subject: [PATCH 273/316] Fix gitlab URLs for linkcheck (#8938) --- docs/development/test-vectors.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 2a90eb30bedf..67440fd4b18a 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -1016,13 +1016,13 @@ header format (substituting the correct information): .. _`Specification repository`: https://github.com/fernet/spec .. _`errata`: https://www.rfc-editor.org/errata_search.php?rfc=6238 .. _`OpenSSL example key`: https://github.com/openssl/openssl/blob/d02b48c63a58ea4367a0e905979f140b7d090f86/test/testrsa.pem -.. _`GnuTLS key parsing tests`: https://gitlab.com/gnutls/gnutls/commit/f16ef39ef0303b02d7fa590a37820440c466ce8d +.. _`GnuTLS key parsing tests`: https://gitlab.com/gnutls/gnutls/-/commit/f16ef39ef0303b02d7fa590a37820440c466ce8d .. _`enc-rsa-pkcs8.pem`: https://gitlab.com/gnutls/gnutls/blob/f8d943b38bf74eaaa11d396112daf43cb8aa82ae/tests/pkcs8-decode/encpkcs8.pem .. _`enc2-rsa-pkcs8.pem`: https://gitlab.com/gnutls/gnutls/blob/f8d943b38bf74eaaa11d396112daf43cb8aa82ae/tests/pkcs8-decode/enc2pkcs8.pem .. _`unenc-rsa-pkcs8.pem`: https://gitlab.com/gnutls/gnutls/blob/f8d943b38bf74eaaa11d396112daf43cb8aa82ae/tests/pkcs8-decode/unencpkcs8.pem .. _`pkcs12_s2k_pem.c`: https://gitlab.com/gnutls/gnutls/blob/f8d943b38bf74eaaa11d396112daf43cb8aa82ae/tests/pkcs12_s2k_pem.c .. _`Botan's ECC private keys`: https://github.com/randombit/botan/tree/4917f26a2b154e841cd27c1bcecdd41d2bdeb6ce/src/tests/data/ecc -.. _`GnuTLS example keys`: https://gitlab.com/gnutls/gnutls/commit/ad2061deafdd7db78fd405f9d143b0a7c579da7b +.. _`GnuTLS example keys`: https://gitlab.com/gnutls/gnutls/-/commit/ad2061deafdd7db78fd405f9d143b0a7c579da7b .. _`NESSIE IDEA vectors`: https://www.cosic.esat.kuleuven.be/nessie/testvectors/bc/idea/Idea-128-64.verified.test-vectors .. _`NESSIE`: https://en.wikipedia.org/wiki/NESSIE .. _`Ed25519 website`: https://ed25519.cr.yp.to/software.html From 736df2dc357ed36b0f602eb64ee278f9e3b7f041 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 17 May 2023 07:58:47 -0400 Subject: [PATCH 274/316] Move the remainder of the Rust coverage logic into the noxfile (#8936) --- .github/workflows/ci.yml | 21 +++------- .gitignore | 1 + noxfile.py | 88 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 90 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 273d5d8082fd..261ccdb7aa5e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,6 +59,7 @@ jobs: uses: actions/setup-python@v4.6.0 with: python-version: ${{ matrix.PYTHON.VERSION }} + - run: rustup component add llvm-tools-preview - name: Clone wycheproof timeout-minutes: 2 uses: ./.github/actions/wycheproof @@ -147,6 +148,8 @@ jobs: - {IMAGE: "ubuntu-jammy:aarch64", NOXSESSION: "tests", RUNNER: [self-hosted, Linux, ARM64]} - {IMAGE: "alpine:aarch64", NOXSESSION: "tests-nocoverage", RUNNER: [self-hosted, Linux, ARM64]} timeout-minutes: 15 + env: + RUSTUP_HOME: /root/.rustup steps: - name: Ridiculous alpine workaround for actions support on arm64 run: | @@ -185,7 +188,6 @@ jobs: - run: /venv/bin/python -m pip install -c ci-constraints-requirements.txt 'nox' - run: '/venv/bin/nox -v --install-only' env: - RUSTUP_HOME: /root/.rustup CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} # OPENSSL_ENABLE_SHA1_SIGNATURES is for CentOS 9 Stream OPENSSL_ENABLE_SHA1_SIGNATURES: 1 @@ -294,21 +296,6 @@ jobs: env: COLUMNS: 80 CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - - name: Process coverage data - run: | - set -xe - "$(rustc --print target-libdir)/../bin/llvm-profdata" merge -sparse $(find . -iname "*.profraw") -o rust-cov.profdata - COV_UUID=$(python3 -c "import uuid; print(uuid.uuid4())") - - "$(rustc --print target-libdir)/../bin/llvm-cov" export \ - .nox/tests/lib/python${{ matrix.PYTHON }}/site-packages/cryptography/hazmat/bindings/_rust.abi3.so \ - $(cat rust-tests.txt | awk '{print "-object " $0}') \ - -instr-profile=rust-cov.profdata \ - --ignore-filename-regex='/.cargo/' \ - --ignore-filename-regex='/rustc/' \ - --ignore-filename-regex='/.rustup/toolchains/' --format=lcov > "${COV_UUID}.lcov" - - sed -E -i 's/SF:(.*)\/src\/rust\/(.*)/SF:src\/rust\/\2/g' "${COV_UUID}.lcov" - uses: ./.github/actions/upload-coverage macos: @@ -346,6 +333,7 @@ jobs: with: python-version: ${{ matrix.PYTHON.VERSION }} architecture: 'x64' # we force this right now so that it will install the universal2 on arm64 + - run: rustup component add llvm-tools-preview - run: python -m pip install -c ci-constraints-requirements.txt 'nox' @@ -405,6 +393,7 @@ jobs: with: python-version: ${{ matrix.PYTHON.VERSION }} architecture: ${{ matrix.WINDOWS.ARCH }} + - run: rustup component add llvm-tools-preview - name: Cache rust and pip uses: ./.github/actions/cache timeout-minutes: 2 diff --git a/.gitignore b/.gitignore index 7a00ba471236..035b15ccd025 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ htmlcov/ *.py[cdo] .hypothesis/ target/ +.rust-cov/ \ No newline at end of file diff --git a/noxfile.py b/noxfile.py index 93b10cd33f84..86a6a68b61a8 100644 --- a/noxfile.py +++ b/noxfile.py @@ -4,7 +4,14 @@ from __future__ import annotations +import glob +import itertools import json +import pathlib +import re +import sys +import typing +import uuid import nox @@ -32,12 +39,15 @@ def tests(session: nox.Session) -> None: if session.name == "tests-randomorder": extras += ",test-randomorder" + prof_location = ( + pathlib.Path(".") / ".rust-cov" / str(uuid.uuid4()) + ).absolute() if session.name != "tests-nocoverage": session.env.update( { "RUSTFLAGS": "-Cinstrument-coverage " + session.env.get("RUSTFLAGS", ""), - "LLVM_PROFILE_FILE": ".rust-cov/cov-%p.profraw", + "LLVM_PROFILE_FILE": str(prof_location / "cov-%p.profraw"), } ) @@ -65,6 +75,13 @@ def tests(session: nox.Session) -> None: "tests/", ) + if session.name != "tests-nocoverage": + [rust_so] = glob.glob( + f"{session.virtualenv.location}/**/cryptography/hazmat/bindings/_rust.*", + recursive=True, + ) + process_rust_coverage(session, [rust_so], prof_location) + @nox.session def docs(session: nox.Session) -> None: @@ -149,11 +166,14 @@ def flake(session: nox.Session) -> None: @nox.session def rust(session: nox.Session) -> None: + prof_location = ( + pathlib.Path(".") / ".rust-cov" / str(uuid.uuid4()) + ).absolute() session.env.update( { "RUSTFLAGS": "-Cinstrument-coverage " + session.env.get("RUSTFLAGS", ""), - "LLVM_PROFILE_FILE": ".rust-cov/cov-%p.profraw", + "LLVM_PROFILE_FILE": str(prof_location / "cov-%p.profraw"), } ) @@ -187,5 +207,65 @@ def rust(session: nox.Session) -> None: if data.get("profile", {}).get("test", False): rust_tests.extend(data["filenames"]) - with open("rust-tests.txt", "w") as f: - f.write("\n".join(rust_tests)) + process_rust_coverage(session, rust_tests, prof_location) + + +LCOV_SOURCEFILE_RE = re.compile( + r"^SF:.*[\\/]src[\\/]rust[\\/](.*)$", flags=re.MULTILINE +) +BIN_EXT = ".exe" if sys.platform == "win32" else "" + + +def process_rust_coverage( + session: nox.Session, + rust_binaries: typing.List[str], + prof_raw_location: pathlib.Path, +) -> None: + # Hitting weird issues merging Windows and Linux Rust coverage, so just + # say the hell with it. + if sys.platform == "win32": + return + + target_libdir = session.run( + "rustc", "--print", "target-libdir", external=True, silent=True + ) + if target_libdir is not None: + target_bindir = pathlib.Path(target_libdir).parent / "bin" + + profraws = [ + str(prof_raw_location / p) + for p in prof_raw_location.glob("*.profraw") + ] + session.run( + str(target_bindir / ("llvm-profdata" + BIN_EXT)), + "merge", + "-sparse", + *profraws, + "-o", + "rust-cov.profdata", + external=True, + ) + + lcov_data = session.run( + str(target_bindir / ("llvm-cov" + BIN_EXT)), + "export", + rust_binaries[0], + *itertools.chain.from_iterable( + ["-object", b] for b in rust_binaries[1:] + ), + "-instr-profile=rust-cov.profdata", + "--ignore-filename-regex=[/\\].cargo[/\\]", + "--ignore-filename-regex=[/\\]rustc[/\\]", + "--ignore-filename-regex=[/\\].rustup[/\\]toolchains[/\\]", + "--ignore-filename-regex=[/\\]target[/\\]", + "--format=lcov", + silent=True, + external=True, + ) + assert isinstance(lcov_data, str) + lcov_data = LCOV_SOURCEFILE_RE.sub( + lambda m: "SF:src/rust/" + m.group(1).replace("\\", "/"), + lcov_data.replace("\r\n", "\n"), + ) + with open(f"{uuid.uuid4()}.lcov", "w") as f: + f.write(lcov_data) From c1ff39ff5cb0a179cd9a8fa44dd94482487e2fa5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 May 2023 13:05:45 +0000 Subject: [PATCH 275/316] Bump proc-macro2 from 1.0.57 to 1.0.58 in /src/rust (#8940) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.57 to 1.0.58. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.57...1.0.58) --- 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 fd51294d9bba..957b228a0082 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -285,9 +285,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4ec6d5fe0b140acb27c9a0444118cf55bfbb4e0b259739429abb4521dd67c16" +checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" dependencies = [ "unicode-ident", ] From c7146f9ed3830a9c3120722bc99dda81ce77037d Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Wed, 17 May 2023 20:32:29 -0400 Subject: [PATCH 276/316] Bump BoringSSL and/or OpenSSL in CI (#8942) Co-authored-by: pyca-boringbot[bot] --- .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 261ccdb7aa5e..721b13c70081 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,8 +43,8 @@ jobs: - {VERSION: "3.12-dev", NOXSESSION: "tests"} # Latest commit on the BoringSSL master branch, as of May 17, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "dd5219451c3ce26221762a15d867edf43b463bb2"}} - # Latest commit on the OpenSSL master branch, as of May 16, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "43d5dac9d00ac486823d949f85ee3ad650b62af8"}} + # Latest commit on the OpenSSL master branch, as of May 18, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "219db5e43c4f030a1c9c4a2f28249fd89b05ea0d"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From cbe719157ef89868413273da4bea379b75baf4be Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 20 May 2023 10:46:27 +0800 Subject: [PATCH 277/316] work around a centos9 fips bug in tests (#8947) filed as https://bugzilla.redhat.com/show_bug.cgi?id=2208724 --- tests/hazmat/bindings/test_openssl.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py index c061c9bf11b0..2c54c6612131 100644 --- a/tests/hazmat/bindings/test_openssl.py +++ b/tests/hazmat/bindings/test_openssl.py @@ -21,13 +21,16 @@ def test_binding_loads(self): assert binding.lib assert binding.ffi - def test_ssl_ctx_options(self): + def test_ssl_ctx_options(self, backend): # Test that we're properly handling 32-bit unsigned on all platforms. b = Binding() # SSL_OP_ALL is 0 on BoringSSL if not b.lib.CRYPTOGRAPHY_IS_BORINGSSL: assert b.lib.SSL_OP_ALL > 0 ctx = b.lib.SSL_CTX_new(b.lib.TLS_method()) + # work around a bug in CentOS 9 stream FIPS + # https://bugzilla.redhat.com/show_bug.cgi?id=2208724 + backend._consume_errors() assert ctx != b.ffi.NULL ctx = b.ffi.gc(ctx, b.lib.SSL_CTX_free) current_options = b.lib.SSL_CTX_get_options(ctx) @@ -36,7 +39,7 @@ def test_ssl_ctx_options(self): assert resp == expected_options assert b.lib.SSL_CTX_get_options(ctx) == expected_options - def test_ssl_options(self): + def test_ssl_options(self, backend): # Test that we're properly handling 32-bit unsigned on all platforms. b = Binding() # SSL_OP_ALL is 0 on BoringSSL @@ -46,6 +49,9 @@ def test_ssl_options(self): assert ctx != b.ffi.NULL ctx = b.ffi.gc(ctx, b.lib.SSL_CTX_free) ssl = b.lib.SSL_new(ctx) + # work around a bug in CentOS 9 stream FIPS + # https://bugzilla.redhat.com/show_bug.cgi?id=2208724 + backend._consume_errors() ssl = b.ffi.gc(ssl, b.lib.SSL_free) current_options = b.lib.SSL_get_options(ssl) resp = b.lib.SSL_set_options(ssl, b.lib.SSL_OP_ALL) From 41156b1f7e8ec3fa22657b7cf036014327a503d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 May 2023 22:57:50 -0400 Subject: [PATCH 278/316] Bump pytest-xdist from 3.3.0 to 3.3.1 (#8945) Bumps [pytest-xdist](https://github.com/pytest-dev/pytest-xdist) from 3.3.0 to 3.3.1. - [Changelog](https://github.com/pytest-dev/pytest-xdist/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest-xdist/compare/v3.3.0...v3.3.1) --- updated-dependencies: - dependency-name: pytest-xdist 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index fff8548b798b..5783051ead7e 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -123,7 +123,7 @@ pytest-cov==4.0.0 # via cryptography (pyproject.toml) pytest-randomly==3.12.0 # via cryptography (pyproject.toml) -pytest-xdist==3.3.0 +pytest-xdist==3.3.1 # via cryptography (pyproject.toml) readme-renderer==37.3 # via twine From ceb527963949da2d77eaf846f419ae7a276f6b25 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 20 May 2023 02:59:27 +0000 Subject: [PATCH 279/316] Bump ruff from 0.0.267 to 0.0.269 (#8944) Bumps [ruff](https://github.com/charliermarsh/ruff) from 0.0.267 to 0.0.269. - [Release notes](https://github.com/charliermarsh/ruff/releases) - [Changelog](https://github.com/charliermarsh/ruff/blob/main/BREAKING_CHANGES.md) - [Commits](https://github.com/charliermarsh/ruff/compare/v0.0.267...v0.0.269) --- updated-dependencies: - dependency-name: ruff 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 5783051ead7e..be0d48cbd5a8 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -138,7 +138,7 @@ rfc3986==2.0.0 # via twine rich==13.3.5 # via twine -ruff==0.0.267 +ruff==0.0.269 # via cryptography (pyproject.toml) six==1.16.0 # via bleach From eb09444b9317e392d75029d6d40128598836d98d Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Sat, 20 May 2023 03:09:41 +0000 Subject: [PATCH 280/316] Bump BoringSSL and/or OpenSSL in CI (#8943) Co-authored-by: pyca-boringbot[bot] --- .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 721b13c70081..53bc416e84af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of May 17, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "dd5219451c3ce26221762a15d867edf43b463bb2"}} - # Latest commit on the OpenSSL master branch, as of May 18, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "219db5e43c4f030a1c9c4a2f28249fd89b05ea0d"}} + # Latest commit on the BoringSSL master branch, as of May 20, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "8abcb6fb41cbb29e93ed82048bb3d59bc8e6717f"}} + # Latest commit on the OpenSSL master branch, as of May 20, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "56a51b5a1ecd54eadc80bed4bfe5044a340787c1"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 4d03a47015888db37058e1717f155dc0ad1195e0 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Tue, 23 May 2023 00:18:08 +0000 Subject: [PATCH 281/316] Bump BoringSSL and/or OpenSSL in CI (#8948) Co-authored-by: pyca-boringbot[bot] --- .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 53bc416e84af..e729388f0baf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,8 +43,8 @@ jobs: - {VERSION: "3.12-dev", NOXSESSION: "tests"} # Latest commit on the BoringSSL master branch, as of May 20, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "8abcb6fb41cbb29e93ed82048bb3d59bc8e6717f"}} - # Latest commit on the OpenSSL master branch, as of May 20, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "56a51b5a1ecd54eadc80bed4bfe5044a340787c1"}} + # Latest commit on the OpenSSL master branch, as of May 23, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "ab17dd8fa3db3e1be82dabfc9fde5dc6181e3f49"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 68f8545c6b8c82cebea30e4356e4c693821d41fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 May 2023 00:27:53 +0000 Subject: [PATCH 282/316] Bump requests from 2.30.0 to 2.31.0 (#8949) Bumps [requests](https://github.com/psf/requests) from 2.30.0 to 2.31.0. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.30.0...v2.31.0) --- updated-dependencies: - dependency-name: requests dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index be0d48cbd5a8..e2107e05df8a 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -127,7 +127,7 @@ pytest-xdist==3.3.1 # via cryptography (pyproject.toml) readme-renderer==37.3 # via twine -requests==2.30.0 +requests==2.31.0 # via # requests-toolbelt # sphinx From 3bab5f80538a9d00c2282f1fa407764b610a483d Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 23 May 2023 12:38:02 +0900 Subject: [PATCH 283/316] Revert "work around a centos9 fips bug in tests (#8947)" (#8950) This reverts commit cbe719157ef89868413273da4bea379b75baf4be. With the correct CentOS invocations we can properly set up FIPS in that environment so these errors don't occur. see: https://github.com/pyca/infra/pull/484 --- tests/hazmat/bindings/test_openssl.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py index 2c54c6612131..c061c9bf11b0 100644 --- a/tests/hazmat/bindings/test_openssl.py +++ b/tests/hazmat/bindings/test_openssl.py @@ -21,16 +21,13 @@ def test_binding_loads(self): assert binding.lib assert binding.ffi - def test_ssl_ctx_options(self, backend): + def test_ssl_ctx_options(self): # Test that we're properly handling 32-bit unsigned on all platforms. b = Binding() # SSL_OP_ALL is 0 on BoringSSL if not b.lib.CRYPTOGRAPHY_IS_BORINGSSL: assert b.lib.SSL_OP_ALL > 0 ctx = b.lib.SSL_CTX_new(b.lib.TLS_method()) - # work around a bug in CentOS 9 stream FIPS - # https://bugzilla.redhat.com/show_bug.cgi?id=2208724 - backend._consume_errors() assert ctx != b.ffi.NULL ctx = b.ffi.gc(ctx, b.lib.SSL_CTX_free) current_options = b.lib.SSL_CTX_get_options(ctx) @@ -39,7 +36,7 @@ def test_ssl_ctx_options(self, backend): assert resp == expected_options assert b.lib.SSL_CTX_get_options(ctx) == expected_options - def test_ssl_options(self, backend): + def test_ssl_options(self): # Test that we're properly handling 32-bit unsigned on all platforms. b = Binding() # SSL_OP_ALL is 0 on BoringSSL @@ -49,9 +46,6 @@ def test_ssl_options(self, backend): assert ctx != b.ffi.NULL ctx = b.ffi.gc(ctx, b.lib.SSL_CTX_free) ssl = b.lib.SSL_new(ctx) - # work around a bug in CentOS 9 stream FIPS - # https://bugzilla.redhat.com/show_bug.cgi?id=2208724 - backend._consume_errors() ssl = b.ffi.gc(ssl, b.lib.SSL_free) current_options = b.lib.SSL_get_options(ssl) resp = b.lib.SSL_set_options(ssl, b.lib.SSL_OP_ALL) From f33cde87ec6cb0f1571560bf1b7790d22eb59c39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 May 2023 09:52:49 -0400 Subject: [PATCH 284/316] Bump sphinx-rtd-theme from 1.2.0 to 1.2.1 (#8951) Bumps [sphinx-rtd-theme](https://github.com/readthedocs/sphinx_rtd_theme) from 1.2.0 to 1.2.1. - [Changelog](https://github.com/readthedocs/sphinx_rtd_theme/blob/master/docs/changelog.rst) - [Commits](https://github.com/readthedocs/sphinx_rtd_theme/compare/1.2.0...1.2.1) --- updated-dependencies: - dependency-name: sphinx-rtd-theme 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index e2107e05df8a..1f763f1d4838 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -150,7 +150,7 @@ sphinx==6.2.1 # sphinx-rtd-theme # sphinxcontrib-jquery # sphinxcontrib-spelling -sphinx-rtd-theme==1.2.0 +sphinx-rtd-theme==1.2.1 # via cryptography (pyproject.toml) sphinxcontrib-applehelp==1.0.4 # via sphinx From 61708b5770799d2cdb33c986eb8b103bebfbf065 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 May 2023 13:58:04 +0000 Subject: [PATCH 285/316] Bump typing-extensions from 4.5.0 to 4.6.0 (#8952) Bumps [typing-extensions](https://github.com/python/typing_extensions) from 4.5.0 to 4.6.0. - [Changelog](https://github.com/python/typing_extensions/blob/main/CHANGELOG.md) - [Commits](https://github.com/python/typing_extensions/compare/4.5.0...4.6.0) --- updated-dependencies: - dependency-name: typing-extensions 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 1f763f1d4838..5f1ca526e945 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -179,7 +179,7 @@ tomli==2.0.1 # pytest twine==4.0.2 # via cryptography (pyproject.toml) -typing-extensions==4.5.0 +typing-extensions==4.6.0 # via mypy urllib3==2.0.2 # via From c4ec7aca54e6ecec930a0d348a246b2afa45d18c Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Tue, 23 May 2023 20:39:58 -0400 Subject: [PATCH 286/316] Bump BoringSSL and/or OpenSSL in CI (#8954) Co-authored-by: pyca-boringbot[bot] --- .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 e729388f0baf..1a582aa85ef0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of May 20, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "8abcb6fb41cbb29e93ed82048bb3d59bc8e6717f"}} - # Latest commit on the OpenSSL master branch, as of May 23, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "ab17dd8fa3db3e1be82dabfc9fde5dc6181e3f49"}} + # Latest commit on the BoringSSL master branch, as of May 24, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "7e56051791944efa303930690a2089805385c983"}} + # Latest commit on the OpenSSL master branch, as of May 24, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "b501df3cefebcdaaeb7d6480b7a7b82d68927873"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 7ed71eb7818099b9d19d3898fccf8b1018504f69 Mon Sep 17 00:00:00 2001 From: Facundo Tuesca Date: Wed, 24 May 2023 04:00:09 +0200 Subject: [PATCH 287/316] Add support for ChaCha20-Poly1305 with BoringSSL (#8946) * Add bindings for BoringSSL's EVP_AEAD API * Add support for ChaCha20-Poly1305 with BoringSSL Since BoringSSL supports this cipher through a different API than OpenSSL (EVP_AEAD vs EVP), this change splits the AEAD backend into two: the original OpenSSL backend (`_aead_openssl.py`) and the new BoringSSL backend (`_aead_boringssl.py`). The AEAD backend functions used by other modules (`aead._encrypt()`, `aead._decrypt()`, etc.) are now exposed through `aead/__init__.py` as wrappers. These wrappers select at runtime which backend to use. Currently only ChaCha20-Poly1305 + BoringSSL uses the BoringSSL backend. * EVP_AEAD: fixup cffi defs, add to _conditional Signed-off-by: William Woodruff evp_aead: fix initialization on BoringSSL Signed-off-by: William Woodruff _conditional: fatfingering Signed-off-by: William Woodruff backends/openssl: make an AEAD helper private Signed-off-by: William Woodruff openssl: collapse aead module Signed-off-by: William Woodruff openssl/aead: experimenting Signed-off-by: William Woodruff openssl/aead: use Cryptography_HAS_EVP_AEAD Signed-off-by: William Woodruff openssl/aead: group things Signed-off-by: William Woodruff Revert "openssl: collapse aead module" This reverts commit 558b8d57f469b6abf51e70e68f5cf330b7ae6414. aead: tweak feature test Signed-off-by: William Woodruff evp_aead: stupidness Signed-off-by: William Woodruff Revert "aead: tweak feature test" This reverts commit aa2eea648fed3e7460cfa358bf89c646e56f310d. Revert "Revert "openssl: collapse aead module"" This reverts commit 44a68c48b52dc0d243d23016999e7fafd580e48b. Revert "Revert "Revert "openssl: collapse aead module""" This reverts commit c35bb37f6c9b4a56f88d36402c8e13ab6396156b. Revert "Revert "aead: tweak feature test"" This reverts commit 78c0dc5ed298c0fde236b8137cb2b0795e905edc. openssl/aead: try to migrate more incrementally Signed-off-by: William Woodruff aead: lintage Signed-off-by: William Woodruff openssl/aead: more incremental rewriting Signed-off-by: William Woodruff openssl/aead: rename _OpenSSL -> _EVPCIPHER Signed-off-by: William Woodruff openssl/aead: collapse module Signed-off-by: William Woodruff * _conditional: undo accidental change Signed-off-by: William Woodruff * openssl/aead: remove _EVPAEAD Signed-off-by: William Woodruff * openssl/aead: remove _EVPCIPHER Signed-off-by: William Woodruff --------- Signed-off-by: William Woodruff Co-authored-by: William Woodruff --- src/_cffi_src/build_openssl.py | 1 + src/_cffi_src/openssl/evp_aead.py | 88 ++++++ .../hazmat/backends/openssl/aead.py | 281 ++++++++++++++++-- .../hazmat/backends/openssl/backend.py | 13 +- .../hazmat/bindings/openssl/_conditional.py | 12 + 5 files changed, 350 insertions(+), 45 deletions(-) create mode 100644 src/_cffi_src/openssl/evp_aead.py diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py index 019789441431..6c4fd90e143b 100644 --- a/src/_cffi_src/build_openssl.py +++ b/src/_cffi_src/build_openssl.py @@ -35,6 +35,7 @@ "engine", "err", "evp", + "evp_aead", "fips", "nid", "objects", diff --git a/src/_cffi_src/openssl/evp_aead.py b/src/_cffi_src/openssl/evp_aead.py new file mode 100644 index 000000000000..a748bcd7a6a8 --- /dev/null +++ b/src/_cffi_src/openssl/evp_aead.py @@ -0,0 +1,88 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +INCLUDES = """ +#if CRYPTOGRAPHY_IS_BORINGSSL +#include +#endif +""" + +TYPES = """ +typedef ... EVP_AEAD; +typedef ... EVP_AEAD_CTX; +static const size_t EVP_AEAD_DEFAULT_TAG_LENGTH; + +static const long Cryptography_HAS_EVP_AEAD; +""" + +FUNCTIONS = """ +const EVP_AEAD *EVP_aead_chacha20_poly1305(void); +void EVP_AEAD_CTX_free(EVP_AEAD_CTX *); +int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *, uint8_t *, size_t *, size_t, + const uint8_t *, size_t, const uint8_t *, size_t, + const uint8_t *, size_t); +int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *, uint8_t *, size_t *, size_t, + const uint8_t *, size_t, const uint8_t *, size_t, + const uint8_t *, size_t); +size_t EVP_AEAD_max_overhead(const EVP_AEAD *); +/* The function EVP_AEAD_CTX_NEW() has different signatures in BoringSSL and + LibreSSL, so we cannot declare it here. We define a wrapper for it instead. +*/ +EVP_AEAD_CTX *Cryptography_EVP_AEAD_CTX_new(const EVP_AEAD *, + const uint8_t *, size_t, + size_t); +""" + +CUSTOMIZATIONS = """ +#if CRYPTOGRAPHY_IS_BORINGSSL || CRYPTOGRAPHY_IS_LIBRESSL +static const long Cryptography_HAS_EVP_AEAD = 1; +#else +static const long Cryptography_HAS_EVP_AEAD = 0; +#endif + +#if CRYPTOGRAPHY_IS_BORINGSSL +EVP_AEAD_CTX *Cryptography_EVP_AEAD_CTX_new(const EVP_AEAD *aead, + const uint8_t *key, + size_t key_len, size_t tag_len) { + return EVP_AEAD_CTX_new(aead, key, key_len, tag_len); +} +#elif CRYPTOGRAPHY_IS_LIBRESSL +EVP_AEAD_CTX *Cryptography_EVP_AEAD_CTX_new(const EVP_AEAD *aead, + const uint8_t *key, + size_t key_len, size_t tag_len) { + EVP_AEAD_CTX *ctx = EVP_AEAD_CTX_new(); + if (ctx == NULL) { + return NULL; + } + + /* This mimics BoringSSL's behavior: any error here is pushed onto + the stack. + */ + int result = EVP_AEAD_CTX_init(ctx, aead, key, key_len, tag_len, NULL); + if (result != 1) { + return NULL; + } + + return ctx; +} +#else +typedef void EVP_AEAD; +typedef void EVP_AEAD_CTX; +static const size_t EVP_AEAD_DEFAULT_TAG_LENGTH = 0; +const EVP_AEAD *(*EVP_aead_chacha20_poly1305)(void) = NULL; +void (*EVP_AEAD_CTX_free)(EVP_AEAD_CTX *) = NULL; +int (*EVP_AEAD_CTX_seal)(const EVP_AEAD_CTX *, uint8_t *, size_t *, size_t, + const uint8_t *, size_t, const uint8_t *, size_t, + const uint8_t *, size_t) = NULL; +int (*EVP_AEAD_CTX_open)(const EVP_AEAD_CTX *, uint8_t *, size_t *, size_t, + const uint8_t *, size_t, const uint8_t *, size_t, + const uint8_t *, size_t) = NULL; +size_t (*EVP_AEAD_max_overhead)(const EVP_AEAD *) = NULL; +EVP_AEAD_CTX *(*Cryptography_EVP_AEAD_CTX_new)(const EVP_AEAD *, + const uint8_t *, size_t, + size_t) = NULL; +#endif +""" diff --git a/src/cryptography/hazmat/backends/openssl/aead.py b/src/cryptography/hazmat/backends/openssl/aead.py index 7361f227914d..b36f535f3f8f 100644 --- a/src/cryptography/hazmat/backends/openssl/aead.py +++ b/src/cryptography/hazmat/backends/openssl/aead.py @@ -22,11 +22,211 @@ AESCCM, AESGCM, AESOCB3, AESSIV, ChaCha20Poly1305 ] + +def _is_evp_aead_supported_cipher( + backend: Backend, cipher: _AEADTypes +) -> bool: + """ + Checks whether the given cipher is supported through + EVP_AEAD rather than the normal OpenSSL EVP_CIPHER API. + """ + from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 + + return backend._lib.Cryptography_HAS_EVP_AEAD and isinstance( + cipher, ChaCha20Poly1305 + ) + + +def _aead_cipher_supported(backend: Backend, cipher: _AEADTypes) -> bool: + if _is_evp_aead_supported_cipher(backend, cipher): + return True + else: + cipher_name = _evp_cipher_cipher_name(cipher) + if backend._fips_enabled and cipher_name not in backend._fips_aead: + return False + # SIV isn't loaded through get_cipherbyname but instead a new fetch API + # only available in 3.0+. But if we know we're on 3.0+ then we know + # it's supported. + if cipher_name.endswith(b"-siv"): + return backend._lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER == 1 + else: + return ( + backend._lib.EVP_get_cipherbyname(cipher_name) + != backend._ffi.NULL + ) + + +def _aead_create_ctx( + backend: Backend, + cipher: _AEADTypes, + key: bytes, +): + if _is_evp_aead_supported_cipher(backend, cipher): + return _evp_aead_create_ctx(backend, cipher, key) + else: + return _evp_cipher_create_ctx(backend, cipher, key) + + +def _encrypt( + backend: Backend, + cipher: _AEADTypes, + nonce: bytes, + data: bytes, + associated_data: typing.List[bytes], + tag_length: int, + ctx: typing.Any = None, +) -> bytes: + if _is_evp_aead_supported_cipher(backend, cipher): + return _evp_aead_encrypt( + backend, cipher, nonce, data, associated_data, tag_length, ctx + ) + else: + return _evp_cipher_encrypt( + backend, cipher, nonce, data, associated_data, tag_length, ctx + ) + + +def _decrypt( + backend: Backend, + cipher: _AEADTypes, + nonce: bytes, + data: bytes, + associated_data: typing.List[bytes], + tag_length: int, + ctx: typing.Any = None, +) -> bytes: + if _is_evp_aead_supported_cipher(backend, cipher): + return _evp_aead_decrypt( + backend, cipher, nonce, data, associated_data, tag_length, ctx + ) + else: + return _evp_cipher_decrypt( + backend, cipher, nonce, data, associated_data, tag_length, ctx + ) + + +def _evp_aead_create_ctx( + backend: Backend, + cipher: _AEADTypes, + key: bytes, + tag_len: typing.Optional[int] = None, +): + aead_cipher = _evp_aead_get_cipher(backend, cipher) + assert aead_cipher is not None + key_ptr = backend._ffi.from_buffer(key) + tag_len = ( + backend._lib.EVP_AEAD_DEFAULT_TAG_LENGTH + if tag_len is None + else tag_len + ) + ctx = backend._lib.Cryptography_EVP_AEAD_CTX_new( + aead_cipher, key_ptr, len(key), tag_len + ) + backend.openssl_assert(ctx != backend._ffi.NULL) + ctx = backend._ffi.gc(ctx, backend._lib.EVP_AEAD_CTX_free) + return ctx + + +def _evp_aead_get_cipher(backend: Backend, cipher: _AEADTypes): + from cryptography.hazmat.primitives.ciphers.aead import ( + ChaCha20Poly1305, + ) + + # Currently only ChaCha20-Poly1305 is supported using this API + assert isinstance(cipher, ChaCha20Poly1305) + return backend._lib.EVP_aead_chacha20_poly1305() + + +def _evp_aead_encrypt( + backend: Backend, + cipher: _AEADTypes, + nonce: bytes, + data: bytes, + associated_data: typing.List[bytes], + tag_length: int, + ctx: typing.Any, +) -> bytes: + assert ctx is not None + + aead_cipher = _evp_aead_get_cipher(backend, cipher) + assert aead_cipher is not None + + out_len = backend._ffi.new("size_t *") + # max_out_len should be in_len plus the result of + # EVP_AEAD_max_overhead. + max_out_len = len(data) + backend._lib.EVP_AEAD_max_overhead(aead_cipher) + out_buf = backend._ffi.new("uint8_t[]", max_out_len) + data_ptr = backend._ffi.from_buffer(data) + nonce_ptr = backend._ffi.from_buffer(nonce) + aad = b"".join(associated_data) + aad_ptr = backend._ffi.from_buffer(aad) + + res = backend._lib.EVP_AEAD_CTX_seal( + ctx, + out_buf, + out_len, + max_out_len, + nonce_ptr, + len(nonce), + data_ptr, + len(data), + aad_ptr, + len(aad), + ) + backend.openssl_assert(res == 1) + encrypted_data = backend._ffi.buffer(out_buf, out_len[0])[:] + return encrypted_data + + +def _evp_aead_decrypt( + backend: Backend, + cipher: _AEADTypes, + nonce: bytes, + data: bytes, + associated_data: typing.List[bytes], + tag_length: int, + ctx: typing.Any, +) -> bytes: + if len(data) < tag_length: + raise InvalidTag + + assert ctx is not None + + out_len = backend._ffi.new("size_t *") + # max_out_len should at least in_len + max_out_len = len(data) + out_buf = backend._ffi.new("uint8_t[]", max_out_len) + data_ptr = backend._ffi.from_buffer(data) + nonce_ptr = backend._ffi.from_buffer(nonce) + aad = b"".join(associated_data) + aad_ptr = backend._ffi.from_buffer(aad) + + res = backend._lib.EVP_AEAD_CTX_open( + ctx, + out_buf, + out_len, + max_out_len, + nonce_ptr, + len(nonce), + data_ptr, + len(data), + aad_ptr, + len(aad), + ) + + if res == 0: + backend._consume_errors() + raise InvalidTag + + decrypted_data = backend._ffi.buffer(out_buf, out_len[0])[:] + return decrypted_data + + _ENCRYPT = 1 _DECRYPT = 0 -def _aead_cipher_name(cipher: _AEADTypes) -> bytes: +def _evp_cipher_cipher_name(cipher: _AEADTypes) -> bytes: from cryptography.hazmat.primitives.ciphers.aead import ( AESCCM, AESGCM, @@ -64,7 +264,7 @@ def _evp_cipher(cipher_name: bytes, backend: Backend): return evp_cipher -def _aead_create_ctx( +def _evp_cipher_create_ctx( backend: Backend, cipher: _AEADTypes, key: bytes, @@ -72,7 +272,7 @@ def _aead_create_ctx( ctx = backend._lib.EVP_CIPHER_CTX_new() backend.openssl_assert(ctx != backend._ffi.NULL) ctx = backend._ffi.gc(ctx, backend._lib.EVP_CIPHER_CTX_free) - cipher_name = _aead_cipher_name(cipher) + cipher_name = _evp_cipher_cipher_name(cipher) evp_cipher = _evp_cipher(cipher_name, backend) key_ptr = backend._ffi.from_buffer(key) res = backend._lib.EVP_CipherInit_ex( @@ -87,7 +287,7 @@ def _aead_create_ctx( return ctx -def _aead_setup( +def _evp_cipher_aead_setup( backend: Backend, cipher_name: bytes, key: bytes, @@ -118,10 +318,13 @@ def _aead_setup( backend.openssl_assert(res != 0) if operation == _DECRYPT: assert tag is not None - _set_tag(backend, ctx, tag) + _evp_cipher_set_tag(backend, ctx, tag) elif cipher_name.endswith(b"-ccm"): res = backend._lib.EVP_CIPHER_CTX_ctrl( - ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, tag_len, backend._ffi.NULL + ctx, + backend._lib.EVP_CTRL_AEAD_SET_TAG, + tag_len, + backend._ffi.NULL, ) backend.openssl_assert(res != 0) @@ -139,7 +342,7 @@ def _aead_setup( return ctx -def _set_tag(backend, ctx, tag: bytes) -> None: +def _evp_cipher_set_tag(backend, ctx, tag: bytes) -> None: tag_ptr = backend._ffi.from_buffer(tag) res = backend._lib.EVP_CIPHER_CTX_ctrl( ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, len(tag), tag_ptr @@ -147,7 +350,9 @@ def _set_tag(backend, ctx, tag: bytes) -> None: backend.openssl_assert(res != 0) -def _set_nonce_operation(backend, ctx, nonce: bytes, operation: int) -> None: +def _evp_cipher_set_nonce_operation( + backend, ctx, nonce: bytes, operation: int +) -> None: nonce_ptr = backend._ffi.from_buffer(nonce) res = backend._lib.EVP_CipherInit_ex( ctx, @@ -160,7 +365,7 @@ def _set_nonce_operation(backend, ctx, nonce: bytes, operation: int) -> None: backend.openssl_assert(res != 0) -def _set_length(backend: Backend, ctx, data_len: int) -> None: +def _evp_cipher_set_length(backend: Backend, ctx, data_len: int) -> None: intptr = backend._ffi.new("int *") res = backend._lib.EVP_CipherUpdate( ctx, backend._ffi.NULL, intptr, backend._ffi.NULL, data_len @@ -168,7 +373,9 @@ def _set_length(backend: Backend, ctx, data_len: int) -> None: backend.openssl_assert(res != 0) -def _process_aad(backend: Backend, ctx, associated_data: bytes) -> None: +def _evp_cipher_process_aad( + backend: Backend, ctx, associated_data: bytes +) -> None: outlen = backend._ffi.new("int *") a_data_ptr = backend._ffi.from_buffer(associated_data) res = backend._lib.EVP_CipherUpdate( @@ -177,7 +384,7 @@ def _process_aad(backend: Backend, ctx, associated_data: bytes) -> None: backend.openssl_assert(res != 0) -def _process_data(backend: Backend, ctx, data: bytes) -> bytes: +def _evp_cipher_process_data(backend: Backend, ctx, data: bytes) -> bytes: outlen = backend._ffi.new("int *") buf = backend._ffi.new("unsigned char[]", len(data)) data_ptr = backend._ffi.from_buffer(data) @@ -189,7 +396,7 @@ def _process_data(backend: Backend, ctx, data: bytes) -> bytes: return backend._ffi.buffer(buf, outlen[0])[:] -def _encrypt( +def _evp_cipher_encrypt( backend: Backend, cipher: _AEADTypes, nonce: bytes, @@ -201,8 +408,8 @@ def _encrypt( from cryptography.hazmat.primitives.ciphers.aead import AESCCM, AESSIV if ctx is None: - cipher_name = _aead_cipher_name(cipher) - ctx = _aead_setup( + cipher_name = _evp_cipher_cipher_name(cipher) + ctx = _evp_cipher_aead_setup( backend, cipher_name, cipher._key, @@ -212,16 +419,17 @@ def _encrypt( _ENCRYPT, ) else: - _set_nonce_operation(backend, ctx, nonce, _ENCRYPT) + _evp_cipher_set_nonce_operation(backend, ctx, nonce, _ENCRYPT) - # CCM requires us to pass the length of the data before processing anything + # CCM requires us to pass the length of the data before processing + # anything. # However calling this with any other AEAD results in an error if isinstance(cipher, AESCCM): - _set_length(backend, ctx, len(data)) + _evp_cipher_set_length(backend, ctx, len(data)) for ad in associated_data: - _process_aad(backend, ctx, ad) - processed_data = _process_data(backend, ctx, data) + _evp_cipher_process_aad(backend, ctx, ad) + processed_data = _evp_cipher_process_data(backend, ctx, data) outlen = backend._ffi.new("int *") # All AEADs we support besides OCB are streaming so they return nothing # in finalization. OCB can return up to (16 byte block - 1) bytes so @@ -238,8 +446,8 @@ def _encrypt( tag = backend._ffi.buffer(tag_buf)[:] if isinstance(cipher, AESSIV): - # RFC 5297 defines the output as IV || C, where the tag we generate is - # the "IV" and C is the ciphertext. This is the opposite of our + # RFC 5297 defines the output as IV || C, where the tag we generate + # is the "IV" and C is the ciphertext. This is the opposite of our # other AEADs, which are Ciphertext || Tag backend.openssl_assert(len(tag) == 16) return tag + processed_data @@ -247,7 +455,7 @@ def _encrypt( return processed_data + tag -def _decrypt( +def _evp_cipher_decrypt( backend: Backend, cipher: _AEADTypes, nonce: bytes, @@ -262,8 +470,8 @@ def _decrypt( raise InvalidTag if isinstance(cipher, AESSIV): - # RFC 5297 defines the output as IV || C, where the tag we generate is - # the "IV" and C is the ciphertext. This is the opposite of our + # RFC 5297 defines the output as IV || C, where the tag we generate + # is the "IV" and C is the ciphertext. This is the opposite of our # other AEADs, which are Ciphertext || Tag tag = data[:tag_length] data = data[tag_length:] @@ -271,21 +479,28 @@ def _decrypt( tag = data[-tag_length:] data = data[:-tag_length] if ctx is None: - cipher_name = _aead_cipher_name(cipher) - ctx = _aead_setup( - backend, cipher_name, cipher._key, nonce, tag, tag_length, _DECRYPT + cipher_name = _evp_cipher_cipher_name(cipher) + ctx = _evp_cipher_aead_setup( + backend, + cipher_name, + cipher._key, + nonce, + tag, + tag_length, + _DECRYPT, ) else: - _set_nonce_operation(backend, ctx, nonce, _DECRYPT) - _set_tag(backend, ctx, tag) + _evp_cipher_set_nonce_operation(backend, ctx, nonce, _DECRYPT) + _evp_cipher_set_tag(backend, ctx, tag) - # CCM requires us to pass the length of the data before processing anything + # CCM requires us to pass the length of the data before processing + # anything. # However calling this with any other AEAD results in an error if isinstance(cipher, AESCCM): - _set_length(backend, ctx, len(data)) + _evp_cipher_set_length(backend, ctx, len(data)) for ad in associated_data: - _process_aad(backend, ctx, ad) + _evp_cipher_process_aad(backend, ctx, ad) # CCM has a different error path if the tag doesn't match. Errors are # raised in Update and Final is irrelevant. if isinstance(cipher, AESCCM): @@ -299,7 +514,7 @@ def _decrypt( processed_data = backend._ffi.buffer(buf, outlen[0])[:] else: - processed_data = _process_data(backend, ctx, data) + processed_data = _evp_cipher_process_data(backend, ctx, data) outlen = backend._ffi.new("int *") # OCB can return up to 15 bytes (16 byte block - 1) in finalization buf = backend._ffi.new("unsigned char[]", 16) diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 62b4659c87bf..00834f8cc04d 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -1654,18 +1654,7 @@ def ed448_generate_key(self) -> ed448.Ed448PrivateKey: return rust_openssl.ed448.generate_key() def aead_cipher_supported(self, cipher) -> bool: - cipher_name = aead._aead_cipher_name(cipher) - if self._fips_enabled and cipher_name not in self._fips_aead: - return False - # SIV isn't loaded through get_cipherbyname but instead a new fetch API - # only available in 3.0+. But if we know we're on 3.0+ then we know - # it's supported. - if cipher_name.endswith(b"-siv"): - return self._lib.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER == 1 - else: - return ( - self._lib.EVP_get_cipherbyname(cipher_name) != self._ffi.NULL - ) + return aead._aead_cipher_supported(self, cipher) def _zero_data(self, data, length: int) -> None: # We clear things this way because at the moment we're not diff --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py index c09c9531280b..5e8ecd04182c 100644 --- a/src/cryptography/hazmat/bindings/openssl/_conditional.py +++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py @@ -262,6 +262,17 @@ def cryptography_has_evp_pkey_set_peer_ex() -> typing.List[str]: return ["EVP_PKEY_derive_set_peer_ex"] +def cryptography_has_evp_aead() -> typing.List[str]: + return [ + "EVP_aead_chacha20_poly1305", + "EVP_AEAD_CTX_free", + "EVP_AEAD_CTX_seal", + "EVP_AEAD_CTX_open", + "EVP_AEAD_max_overhead", + "Cryptography_EVP_AEAD_CTX_new", + ] + + # 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 @@ -314,4 +325,5 @@ def cryptography_has_evp_pkey_set_peer_ex() -> typing.List[str]: "Cryptography_HAS_EVP_PKEY_SET_PEER_EX": ( cryptography_has_evp_pkey_set_peer_ex ), + "Cryptography_HAS_EVP_AEAD": (cryptography_has_evp_aead), } From 0a28f48998cbcf3f3e594ebab01182e235c046dc Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Tue, 23 May 2023 22:13:54 -0400 Subject: [PATCH 288/316] CHANGELOG: record ChaCha20Poly1305 changes (#8955) Signed-off-by: William Woodruff --- CHANGELOG.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5073ce32b98e..1811f801cbf5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -26,6 +26,9 @@ Changelog * Support signing :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS` X.509 certificates via the new keyword-only argument ``rsa_padding`` on :meth:`~cryptography.x509.CertificateBuilder.sign`. +* Added support for + :class:`~cryptography.hazmat.primitives.ciphers.aead.ChaCha20Poly1305` + on BoringSSL. .. _v40-0-2: From 69d7676135745cb8f9f6f8502d68177d30e42dcd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 May 2023 13:14:36 +0000 Subject: [PATCH 289/316] Bump typing-extensions from 4.6.0 to 4.6.1 (#8957) Bumps [typing-extensions](https://github.com/python/typing_extensions) from 4.6.0 to 4.6.1. - [Changelog](https://github.com/python/typing_extensions/blob/main/CHANGELOG.md) - [Commits](https://github.com/python/typing_extensions/compare/4.6.0...4.6.1) --- updated-dependencies: - dependency-name: typing-extensions 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 5f1ca526e945..84928b1e3f4e 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -179,7 +179,7 @@ tomli==2.0.1 # pytest twine==4.0.2 # via cryptography (pyproject.toml) -typing-extensions==4.6.0 +typing-extensions==4.6.1 # via mypy urllib3==2.0.2 # via From bc2b14ca5542a6f631ae018481145826e90a5259 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 May 2023 13:26:38 +0000 Subject: [PATCH 290/316] Bump coverage from 7.2.5 to 7.2.6 (#8958) Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.2.5 to 7.2.6. - [Release notes](https://github.com/nedbat/coveragepy/releases) - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst) - [Commits](https://github.com/nedbat/coveragepy/compare/7.2.5...7.2.6) --- updated-dependencies: - dependency-name: coverage 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 84928b1e3f4e..d3a30cf238ce 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -29,7 +29,7 @@ click==8.1.3 # via black colorlog==6.7.0 # via nox -coverage==7.2.5 +coverage==7.2.6 # via pytest-cov distlib==0.3.6 # via virtualenv From 9e3b2af68fbb2ab3db3d735c62f173ecca6cb572 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 May 2023 23:40:34 +0000 Subject: [PATCH 291/316] Bump unicode-ident from 1.0.8 to 1.0.9 in /src/rust (#8960) Bumps [unicode-ident](https://github.com/dtolnay/unicode-ident) from 1.0.8 to 1.0.9. - [Release notes](https://github.com/dtolnay/unicode-ident/releases) - [Commits](https://github.com/dtolnay/unicode-ident/compare/1.0.8...1.0.9) --- updated-dependencies: - dependency-name: unicode-ident 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 957b228a0082..757bf69e3ea3 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -412,9 +412,9 @@ checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unindent" From 3ebe5701abd2e3670c71b81613774180db10e92d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 May 2023 23:44:09 +0000 Subject: [PATCH 292/316] Bump actions/setup-python from 4.6.0 to 4.6.1 (#8961) Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.6.0 to 4.6.1. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v4.6.0...v4.6.1) --- updated-dependencies: - dependency-name: actions/setup-python 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/benchmark.yml | 2 +- .github/workflows/ci.yml | 14 +++++++------- .github/workflows/linkcheck.yml | 2 +- .github/workflows/wheel-builder.yml | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index f121370e67df..1643a283b934 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -35,7 +35,7 @@ jobs: - name: Setup python id: setup-python - uses: actions/setup-python@v4.6.0 + uses: actions/setup-python@v4.6.1 with: python-version: "3.11" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a582aa85ef0..2e664a12cd62 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,7 +56,7 @@ jobs: uses: ./.github/actions/mtime-fix - name: Setup python id: setup-python - uses: actions/setup-python@v4.6.0 + uses: actions/setup-python@v4.6.1 with: python-version: ${{ matrix.PYTHON.VERSION }} - run: rustup component add llvm-tools-preview @@ -224,7 +224,7 @@ jobs: uses: ./.github/actions/cache timeout-minutes: 2 - name: Setup python - uses: actions/setup-python@v4.6.0 + uses: actions/setup-python@v4.6.1 with: python-version: ${{ matrix.PYTHON }} - uses: dtolnay/rust-toolchain@52e69531e6f69a396bc9d1226284493a5db969ff @@ -279,7 +279,7 @@ jobs: with: key: coverage - name: Setup python - uses: actions/setup-python@v4.6.0 + uses: actions/setup-python@v4.6.1 with: python-version: ${{ matrix.PYTHON }} @@ -329,7 +329,7 @@ jobs: key: ${{ matrix.PYTHON.NOXSESSION }}-${{ matrix.PYTHON.VERSION }} - name: Setup python - uses: actions/setup-python@v4.6.0 + uses: actions/setup-python@v4.6.1 with: python-version: ${{ matrix.PYTHON.VERSION }} architecture: 'x64' # we force this right now so that it will install the universal2 on arm64 @@ -389,7 +389,7 @@ jobs: uses: ./.github/actions/mtime-fix - name: Setup python id: setup-python - uses: actions/setup-python@v4.6.0 + uses: actions/setup-python@v4.6.1 with: python-version: ${{ matrix.PYTHON.VERSION }} architecture: ${{ matrix.WINDOWS.ARCH }} @@ -465,7 +465,7 @@ jobs: uses: ./.github/actions/cache timeout-minutes: 2 - name: Setup python - uses: actions/setup-python@v4.6.0 + uses: actions/setup-python@v4.6.1 with: python-version: ${{ matrix.PYTHON }} - run: ./.github/downstream.d/${{ matrix.DOWNSTREAM }}.sh install @@ -507,7 +507,7 @@ jobs: jobs: ${{ toJSON(needs) }} - name: Setup python if: ${{ always() }} - uses: actions/setup-python@v4.6.0 + uses: actions/setup-python@v4.6.1 with: python-version: '3.11' - run: pip install -c ci-constraints-requirements.txt coverage[toml] diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml index 8adca7075078..9a11f2a9fc70 100644 --- a/.github/workflows/linkcheck.yml +++ b/.github/workflows/linkcheck.yml @@ -26,7 +26,7 @@ jobs: uses: ./.github/actions/mtime-fix - name: Setup python id: setup-python - uses: actions/setup-python@v4.6.0 + uses: actions/setup-python@v4.6.1 with: python-version: 3.11 - name: Cache rust and pip diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index b64828ab61dc..677319b3fa5a 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -189,7 +189,7 @@ jobs: PYTHON_DOWNLOAD_URL: ${{ matrix.PYTHON.DOWNLOAD_URL }} if: contains(matrix.PYTHON.VERSION, 'pypy') == false - name: Setup pypy - uses: actions/setup-python@v4.6.0 + uses: actions/setup-python@v4.6.1 with: python-version: ${{ matrix.PYTHON.VERSION }} if: contains(matrix.PYTHON.VERSION, 'pypy') @@ -266,7 +266,7 @@ jobs: name: cryptography-sdist - name: Setup python - uses: actions/setup-python@v4.6.0 + uses: actions/setup-python@v4.6.1 with: python-version: ${{ matrix.PYTHON.VERSION }} architecture: ${{ matrix.WINDOWS.ARCH }} From b4e355926096c0dea91e3e255694d2dceed931cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 May 2023 23:45:05 +0000 Subject: [PATCH 293/316] Bump ruff from 0.0.269 to 0.0.270 (#8962) Bumps [ruff](https://github.com/charliermarsh/ruff) from 0.0.269 to 0.0.270. - [Release notes](https://github.com/charliermarsh/ruff/releases) - [Changelog](https://github.com/charliermarsh/ruff/blob/main/BREAKING_CHANGES.md) - [Commits](https://github.com/charliermarsh/ruff/compare/v0.0.269...v0.0.270) --- updated-dependencies: - dependency-name: ruff 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index d3a30cf238ce..e5cc4624d828 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -138,7 +138,7 @@ rfc3986==2.0.0 # via twine rich==13.3.5 # via twine -ruff==0.0.269 +ruff==0.0.270 # via cryptography (pyproject.toml) six==1.16.0 # via bleach From b426e6bc0c7a6b44e541fb2d86f37680780a0c9d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 May 2023 23:48:27 +0000 Subject: [PATCH 294/316] Bump pytest-cov from 4.0.0 to 4.1.0 (#8963) Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 4.0.0 to 4.1.0. - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest-cov/compare/v4.0.0...v4.1.0) --- updated-dependencies: - dependency-name: pytest-cov 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index e5cc4624d828..676df1435f04 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -119,7 +119,7 @@ pytest==7.3.1 # pytest-xdist pytest-benchmark==4.0.0 # via cryptography (pyproject.toml) -pytest-cov==4.0.0 +pytest-cov==4.1.0 # via cryptography (pyproject.toml) pytest-randomly==3.12.0 # via cryptography (pyproject.toml) From a30aa509b61b62926f779cd35d467dc48308c11b Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Thu, 25 May 2023 00:18:07 +0000 Subject: [PATCH 295/316] Bump BoringSSL and/or OpenSSL in CI (#8965) Co-authored-by: pyca-boringbot[bot] --- .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 2e664a12cd62..8a7f9bff5d8e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,10 +41,10 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of May 24, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "7e56051791944efa303930690a2089805385c983"}} - # Latest commit on the OpenSSL master branch, as of May 24, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "b501df3cefebcdaaeb7d6480b7a7b82d68927873"}} + # Latest commit on the BoringSSL master branch, as of May 25, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "5fcd47d137f9b556edc7a392035dc2d2f43282ca"}} + # Latest commit on the OpenSSL master branch, as of May 25, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "674b61ebd982d6a6564ac1f90d8cde22371564bc"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From e34373bfebb18c8e00034c3c7881871c314d68de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 May 2023 22:14:16 +0000 Subject: [PATCH 296/316] Bump quote from 1.0.27 to 1.0.28 in /src/rust (#8967) Bumps [quote](https://github.com/dtolnay/quote) from 1.0.27 to 1.0.28. - [Release notes](https://github.com/dtolnay/quote/releases) - [Commits](https://github.com/dtolnay/quote/compare/1.0.27...1.0.28) --- updated-dependencies: - dependency-name: quote 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 757bf69e3ea3..65040081c844 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -354,9 +354,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] From 13991ac2f4cc871ce93c842543ddd8be0574acc5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 May 2023 22:19:50 +0000 Subject: [PATCH 297/316] Bump typing-extensions from 4.6.1 to 4.6.2 (#8969) Bumps [typing-extensions](https://github.com/python/typing_extensions) from 4.6.1 to 4.6.2. - [Changelog](https://github.com/python/typing_extensions/blob/main/CHANGELOG.md) - [Commits](https://github.com/python/typing_extensions/compare/4.6.1...4.6.2) --- updated-dependencies: - dependency-name: typing-extensions 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 676df1435f04..2c91aecac0da 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -179,7 +179,7 @@ tomli==2.0.1 # pytest twine==4.0.2 # via cryptography (pyproject.toml) -typing-extensions==4.6.1 +typing-extensions==4.6.2 # via mypy urllib3==2.0.2 # via From 3a46372a9425d958b07aba969f437d4c3d21c04c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 May 2023 22:32:35 +0000 Subject: [PATCH 298/316] Bump proc-macro2 from 1.0.58 to 1.0.59 in /src/rust (#8968) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.58 to 1.0.59. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.58...1.0.59) --- 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 65040081c844..1d1c76d6bca8 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -285,9 +285,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.58" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" +checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" dependencies = [ "unicode-ident", ] From c9fd1d04a1dc3757852e81a1bae61f2f45662e65 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Fri, 26 May 2023 00:24:14 -0400 Subject: [PATCH 299/316] Bump BoringSSL and/or OpenSSL in CI (#8970) Co-authored-by: pyca-boringbot[bot] --- .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 8a7f9bff5d8e..b34dc312238f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,8 +43,8 @@ jobs: - {VERSION: "3.12-dev", NOXSESSION: "tests"} # Latest commit on the BoringSSL master branch, as of May 25, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "5fcd47d137f9b556edc7a392035dc2d2f43282ca"}} - # Latest commit on the OpenSSL master branch, as of May 25, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "674b61ebd982d6a6564ac1f90d8cde22371564bc"}} + # Latest commit on the OpenSSL master branch, as of May 26, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "0bf7e94c10f1b00510b8a36cdcbedc02a66468be"}} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 From 965e04996f79f76e00148c0193f868e258f42ae5 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 26 May 2023 14:09:53 -0400 Subject: [PATCH 300/316] Consolidate CI jobs (#8964) --- .github/actions/cache/action.yml | 6 +- .github/workflows/ci.yml | 114 ++++--------------------------- 2 files changed, 20 insertions(+), 100 deletions(-) diff --git a/.github/actions/cache/action.yml b/.github/actions/cache/action.yml index 4581770f93d5..6d254d398299 100644 --- a/.github/actions/cache/action.yml +++ b/.github/actions/cache/action.yml @@ -34,6 +34,10 @@ runs: echo "dir=$(python -m pip cache dir)" >> $GITHUB_OUTPUT fi shell: bash + - name: Normalize key + id: normalized-key + run: echo "key=$(echo "${{ inputs.key }}" | tr -d ',')" >> $GITHUB_OUTPUT + shell: bash - uses: actions/cache@v3.3.1 id: cache with: @@ -43,7 +47,7 @@ runs: ~/.cargo/registry/cache/ src/rust/target/ ${{ inputs.additional-paths }} - key: cargo-pip-${{ runner.os }}-${{ runner.arch }}-${{ inputs.key }}-5-${{ hashFiles('**/Cargo.lock', '**/*.rs') }}-${{ steps.rust-version.version }} + key: cargo-pip-${{ runner.os }}-${{ runner.arch }}-${{ steps.normalized-key.outputs.key }}-5-${{ hashFiles('**/Cargo.lock', '**/*.rs') }}-${{ steps.rust-version.version }} - name: Size of cache items run: | du -sh ~/.cargo/registry/index/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b34dc312238f..b2dd1ba58ea4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,6 +45,13 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "5fcd47d137f9b556edc7a392035dc2d2f43282ca"}} # Latest commit on the OpenSSL master branch, as of May 26, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "0bf7e94c10f1b00510b8a36cdcbedc02a66468be"}} + # Builds with various Rust versions. Includes MSRV and potential + # future MSRV: + # 1.60 - pem 2.0.1 + - {VERSION: "3.11", NOXSESSION: "tests-nocoverage", RUST: "1.56.0"} + - {VERSION: "3.11", NOXSESSION: "rust,tests", RUST: "1.60.0"} + - {VERSION: "3.11", NOXSESSION: "rust,tests", RUST: "beta"} + - {VERSION: "3.11", NOXSESSION: "rust,tests", RUST: "nightly"} timeout-minutes: 15 steps: - uses: actions/checkout@v3.5.2 @@ -59,6 +66,13 @@ jobs: uses: actions/setup-python@v4.6.1 with: python-version: ${{ matrix.PYTHON.VERSION }} + - name: Setup rust + uses: dtolnay/rust-toolchain@52e69531e6f69a396bc9d1226284493a5db969ff + with: + toolchain: ${{ matrix.PYTHON.RUST }} + components: rustfmt,clippy + if: matrix.PYTHON.RUST + - run: rustup component add llvm-tools-preview - name: Clone wycheproof timeout-minutes: 2 @@ -200,104 +214,6 @@ jobs: NOXSESSION: ${{ matrix.IMAGE.NOXSESSION }} - uses: ./.github/actions/upload-coverage - linux-rust: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - PYTHON: - - "3.11" - RUST: - # Cover MSRV. 1.60+ and beta/nightly are in the linux-rust-coverage section. - - 1.56.0 - name: "${{ matrix.PYTHON }} with Rust ${{ matrix.RUST }}" - timeout-minutes: 15 - steps: - - uses: actions/checkout@v3.5.2 - timeout-minutes: 3 - with: - persist-credentials: false - fetch-depth: 0 - - name: set mtimes for rust dirs - uses: ./.github/actions/mtime-fix - - name: Cache rust and pip - uses: ./.github/actions/cache - timeout-minutes: 2 - - name: Setup python - uses: actions/setup-python@v4.6.1 - with: - python-version: ${{ matrix.PYTHON }} - - uses: dtolnay/rust-toolchain@52e69531e6f69a396bc9d1226284493a5db969ff - with: - toolchain: ${{ matrix.RUST }} - - name: Clone wycheproof - timeout-minutes: 2 - uses: ./.github/actions/wycheproof - - run: python -m pip install -c ci-constraints-requirements.txt 'nox' - - name: Create nox environment - run: nox -v --install-only -s tests-nocoverage - env: - CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - - name: Tests - run: nox --no-install -s tests-nocoverage -- --color=yes --wycheproof-root=wycheproof - env: - COLUMNS: 80 - - uses: ./.github/actions/upload-coverage - - linux-rust-coverage: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - PYTHON: - - "3.11" - RUST: - # Potential future MSRVs: - # 1.60 - pem 2.0.1 - - 1.60.0 - - beta - - nightly - name: "Rust Coverage" - timeout-minutes: 15 - steps: - - uses: actions/checkout@v3.5.2 - timeout-minutes: 3 - with: - persist-credentials: false - fetch-depth: 0 - - name: set mtimes for rust dirs - uses: ./.github/actions/mtime-fix - - uses: dtolnay/rust-toolchain@52e69531e6f69a396bc9d1226284493a5db969ff - id: rust-toolchain - with: - toolchain: ${{ matrix.RUST }} - components: llvm-tools-preview,rustfmt,clippy - - name: Cache rust and pip - id: cargo-cache - uses: ./.github/actions/cache - timeout-minutes: 2 - with: - key: coverage - - name: Setup python - uses: actions/setup-python@v4.6.1 - with: - python-version: ${{ matrix.PYTHON }} - - - name: Clone wycheproof - timeout-minutes: 2 - uses: ./.github/actions/wycheproof - - run: python -m pip install -c ci-constraints-requirements.txt 'nox' - - name: Create nox environment - run: nox -v --install-only -s tests rust - env: - CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - - name: Tests - run: nox --no-install -s tests rust -- --color=yes --wycheproof-root=wycheproof - env: - COLUMNS: 80 - CARGO_TARGET_DIR: ${{ format('{0}/src/rust/target/', github.workspace) }} - - uses: ./.github/actions/upload-coverage - macos: runs-on: ${{ matrix.RUNNER.OS }} strategy: @@ -494,7 +410,7 @@ jobs: all-green: # https://github.community/t/is-it-possible-to-require-all-github-actions-tasks-to-pass-without-enumerating-them/117957/4?u=graingert runs-on: ubuntu-latest - needs: [linux, distros, linux-rust, linux-rust-coverage, macos, windows, linux-downstream] + needs: [linux, distros, macos, windows, linux-downstream] if: ${{ always() }} steps: - uses: actions/checkout@v3.5.2 From b3030dd161e1e6ab6a194effa47774db9d2c12d9 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 26 May 2023 14:14:47 -0400 Subject: [PATCH 301/316] Convert Poly1305 to Rust (#8788) --- .../hazmat/backends/openssl/backend.py | 11 -- .../hazmat/backends/openssl/poly1305.py | 69 ---------- .../bindings/_rust/openssl/__init__.pyi | 2 + .../bindings/_rust/openssl/poly1305.pyi | 13 ++ .../hazmat/primitives/poly1305.py | 57 +------- src/rust/src/backend/hmac.rs | 2 +- src/rust/src/backend/mod.rs | 3 + src/rust/src/backend/poly1305.rs | 127 ++++++++++++++++++ 8 files changed, 149 insertions(+), 135 deletions(-) delete mode 100644 src/cryptography/hazmat/backends/openssl/poly1305.py create mode 100644 src/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi create mode 100644 src/rust/src/backend/poly1305.rs diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 00834f8cc04d..f2e381a15d61 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -24,10 +24,6 @@ _EllipticCurvePrivateKey, _EllipticCurvePublicKey, ) -from cryptography.hazmat.backends.openssl.poly1305 import ( - _POLY1305_KEY_SIZE, - _Poly1305Context, -) from cryptography.hazmat.backends.openssl.rsa import ( _RSAPrivateKey, _RSAPublicKey, @@ -1938,13 +1934,6 @@ def poly1305_supported(self) -> bool: return False return self._lib.Cryptography_HAS_POLY1305 == 1 - def create_poly1305_ctx(self, key: bytes) -> _Poly1305Context: - utils._check_byteslike("key", key) - if len(key) != _POLY1305_KEY_SIZE: - raise ValueError("A poly1305 key is 32 bytes long") - - return _Poly1305Context(self, key) - def pkcs7_supported(self) -> bool: return not self._lib.CRYPTOGRAPHY_IS_BORINGSSL diff --git a/src/cryptography/hazmat/backends/openssl/poly1305.py b/src/cryptography/hazmat/backends/openssl/poly1305.py deleted file mode 100644 index bb0c3738b667..000000000000 --- a/src/cryptography/hazmat/backends/openssl/poly1305.py +++ /dev/null @@ -1,69 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography.exceptions import InvalidSignature -from cryptography.hazmat.primitives import constant_time - -_POLY1305_TAG_SIZE = 16 -_POLY1305_KEY_SIZE = 32 - - -if typing.TYPE_CHECKING: - from cryptography.hazmat.backends.openssl.backend import Backend - - -class _Poly1305Context: - def __init__(self, backend: Backend, key: bytes) -> None: - self._backend = backend - - key_ptr = self._backend._ffi.from_buffer(key) - # This function copies the key into OpenSSL-owned memory so we don't - # need to retain it ourselves - evp_pkey = self._backend._lib.EVP_PKEY_new_raw_private_key( - self._backend._lib.NID_poly1305, - self._backend._ffi.NULL, - key_ptr, - len(key), - ) - self._backend.openssl_assert(evp_pkey != self._backend._ffi.NULL) - self._evp_pkey = self._backend._ffi.gc( - evp_pkey, self._backend._lib.EVP_PKEY_free - ) - ctx = self._backend._lib.EVP_MD_CTX_new() - self._backend.openssl_assert(ctx != self._backend._ffi.NULL) - self._ctx = self._backend._ffi.gc( - ctx, self._backend._lib.EVP_MD_CTX_free - ) - res = self._backend._lib.EVP_DigestSignInit( - self._ctx, - self._backend._ffi.NULL, - self._backend._ffi.NULL, - self._backend._ffi.NULL, - self._evp_pkey, - ) - self._backend.openssl_assert(res == 1) - - def update(self, data: bytes) -> None: - data_ptr = self._backend._ffi.from_buffer(data) - res = self._backend._lib.EVP_DigestSignUpdate( - self._ctx, data_ptr, len(data) - ) - self._backend.openssl_assert(res != 0) - - def finalize(self) -> bytes: - buf = self._backend._ffi.new("unsigned char[]", _POLY1305_TAG_SIZE) - outlen = self._backend._ffi.new("size_t *", _POLY1305_TAG_SIZE) - res = self._backend._lib.EVP_DigestSignFinal(self._ctx, buf, outlen) - self._backend.openssl_assert(res != 0) - self._backend.openssl_assert(outlen[0] == _POLY1305_TAG_SIZE) - return self._backend._ffi.buffer(buf)[: outlen[0]] - - def verify(self, tag: bytes) -> None: - mac = self.finalize() - if not constant_time.bytes_eq(mac, tag): - raise InvalidSignature("Value did not match computed tag.") diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi index 6712fff2755b..9ab4e6c98cd6 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -11,6 +11,7 @@ from cryptography.hazmat.bindings._rust.openssl import ( hashes, hmac, kdf, + poly1305, x448, x25519, ) @@ -24,6 +25,7 @@ __all__ = [ "kdf", "ed448", "ed25519", + "poly1305", "x448", "x25519", ] diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi new file mode 100644 index 000000000000..2e9b0a9e1254 --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi @@ -0,0 +1,13 @@ +# 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. + +class Poly1305: + def __init__(self, key: bytes) -> None: ... + @staticmethod + def generate_tag(key: bytes, data: bytes) -> bytes: ... + @staticmethod + def verify_tag(key: bytes, data: bytes, tag: bytes) -> None: ... + def update(self, data: bytes) -> None: ... + def finalize(self) -> bytes: ... + def verify(self, tag: bytes) -> None: ... diff --git a/src/cryptography/hazmat/primitives/poly1305.py b/src/cryptography/hazmat/primitives/poly1305.py index 77df07f02e68..7f5a77a576fd 100644 --- a/src/cryptography/hazmat/primitives/poly1305.py +++ b/src/cryptography/hazmat/primitives/poly1305.py @@ -4,59 +4,8 @@ from __future__ import annotations -import typing +from cryptography.hazmat.bindings._rust import openssl as rust_openssl -from cryptography import utils -from cryptography.exceptions import ( - AlreadyFinalized, - UnsupportedAlgorithm, - _Reasons, -) -from cryptography.hazmat.backends.openssl.poly1305 import _Poly1305Context +__all__ = ["Poly1305"] - -class Poly1305: - _ctx: typing.Optional[_Poly1305Context] - - def __init__(self, key: bytes): - from cryptography.hazmat.backends.openssl.backend import backend - - if not backend.poly1305_supported(): - raise UnsupportedAlgorithm( - "poly1305 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_MAC, - ) - self._ctx = backend.create_poly1305_ctx(key) - - def update(self, data: bytes) -> None: - if self._ctx is None: - raise AlreadyFinalized("Context was already finalized.") - utils._check_byteslike("data", data) - self._ctx.update(data) - - def finalize(self) -> bytes: - if self._ctx is None: - raise AlreadyFinalized("Context was already finalized.") - mac = self._ctx.finalize() - self._ctx = None - return mac - - def verify(self, tag: bytes) -> None: - utils._check_bytes("tag", tag) - if self._ctx is None: - raise AlreadyFinalized("Context was already finalized.") - - ctx, self._ctx = self._ctx, None - ctx.verify(tag) - - @classmethod - def generate_tag(cls, key: bytes, data: bytes) -> bytes: - p = Poly1305(key) - p.update(data) - return p.finalize() - - @classmethod - def verify_tag(cls, key: bytes, data: bytes, tag: bytes) -> None: - p = Poly1305(key) - p.update(data) - p.verify(tag) +Poly1305 = rust_openssl.poly1305.Poly1305 diff --git a/src/rust/src/backend/hmac.rs b/src/rust/src/backend/hmac.rs index d37b97277fdd..13509b859024 100644 --- a/src/rust/src/backend/hmac.rs +++ b/src/rust/src/backend/hmac.rs @@ -72,7 +72,7 @@ impl Hmac { let actual = self.finalize(py)?.as_bytes(); if actual.len() != signature.len() || !openssl::memcmp::eq(actual, signature) { return Err(CryptographyError::from( - exceptions::InvalidSignature::new_err(("Signature did not match digest.",)), + exceptions::InvalidSignature::new_err("Signature did not match digest."), )); } diff --git a/src/rust/src/backend/mod.rs b/src/rust/src/backend/mod.rs index e52b149e38ef..970571193d15 100644 --- a/src/rust/src/backend/mod.rs +++ b/src/rust/src/backend/mod.rs @@ -10,6 +10,7 @@ pub(crate) mod ed448; pub(crate) mod hashes; pub(crate) mod hmac; pub(crate) mod kdf; +pub(crate) mod poly1305; pub(crate) mod utils; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] pub(crate) mod x25519; @@ -29,6 +30,8 @@ pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult< #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] module.add_submodule(x448::create_module(module.py())?)?; + module.add_submodule(poly1305::create_module(module.py())?)?; + module.add_submodule(hashes::create_module(module.py())?)?; module.add_submodule(hmac::create_module(module.py())?)?; module.add_submodule(kdf::create_module(module.py())?)?; diff --git a/src/rust/src/backend/poly1305.rs b/src/rust/src/backend/poly1305.rs new file mode 100644 index 000000000000..17d279a4023f --- /dev/null +++ b/src/rust/src/backend/poly1305.rs @@ -0,0 +1,127 @@ +// 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::backend::hashes::already_finalized_error; +use crate::buf::CffiBuf; +use crate::error::{CryptographyError, CryptographyResult}; +use crate::exceptions; + +#[pyo3::prelude::pyclass(module = "cryptography.hazmat.bindings._rust.openssl.poly1305")] +struct Poly1305 { + signer: Option>, +} + +impl Poly1305 { + fn get_mut_signer(&mut self) -> CryptographyResult<&mut openssl::sign::Signer<'static>> { + if let Some(signer) = self.signer.as_mut() { + return Ok(signer); + }; + Err(already_finalized_error()) + } +} + +#[pyo3::pymethods] +impl Poly1305 { + #[new] + fn new(key: CffiBuf<'_>) -> CryptographyResult { + #[cfg(any(CRYPTOGRAPHY_IS_LIBRESSL, CRYPTOGRAPHY_IS_BORINGSSL))] + { + return Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(( + "poly1305 is not supported by this version of OpenSSL.", + exceptions::Reasons::UNSUPPORTED_MAC, + )), + )); + } + + #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] + { + if cryptography_openssl::fips::is_enabled() { + return Err(CryptographyError::from( + exceptions::UnsupportedAlgorithm::new_err(( + "poly1305 is not supported by this version of OpenSSL.", + exceptions::Reasons::UNSUPPORTED_MAC, + )), + )); + } + + let pkey = openssl::pkey::PKey::private_key_from_raw_bytes( + key.as_bytes(), + openssl::pkey::Id::POLY1305, + ) + .map_err(|_| { + pyo3::exceptions::PyValueError::new_err("A poly1305 key is 32 bytes long") + })?; + + Ok(Poly1305 { + signer: Some( + openssl::sign::Signer::new_without_digest(&pkey).map_err(|_| { + pyo3::exceptions::PyValueError::new_err("A poly1305 key is 32 bytes long") + })?, + ), + }) + } + } + + #[staticmethod] + fn generate_tag<'p>( + py: pyo3::Python<'p>, + key: CffiBuf<'_>, + data: CffiBuf<'_>, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let mut p = Poly1305::new(key)?; + p.update(data)?; + p.finalize(py) + } + + #[staticmethod] + fn verify_tag( + py: pyo3::Python<'_>, + key: CffiBuf<'_>, + data: CffiBuf<'_>, + tag: &[u8], + ) -> CryptographyResult<()> { + let mut p = Poly1305::new(key)?; + p.update(data)?; + p.verify(py, tag) + } + + fn update(&mut self, data: CffiBuf<'_>) -> CryptographyResult<()> { + self.get_mut_signer()?.update(data.as_bytes())?; + Ok(()) + } + + fn finalize<'p>( + &mut self, + py: pyo3::Python<'p>, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let signer = self.get_mut_signer()?; + let result = pyo3::types::PyBytes::new_with(py, signer.len()?, |b| { + let n = signer.sign(b).unwrap(); + assert_eq!(n, b.len()); + Ok(()) + })?; + self.signer = None; + Ok(result) + } + + fn verify(&mut self, py: pyo3::Python<'_>, signature: &[u8]) -> CryptographyResult<()> { + let actual = self.finalize(py)?.as_bytes(); + if actual.len() != signature.len() || !openssl::memcmp::eq(actual, signature) { + return Err(CryptographyError::from( + exceptions::InvalidSignature::new_err("Value did not match computed tag."), + )); + } + + Ok(()) + } +} + +pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let m = pyo3::prelude::PyModule::new(py, "poly1305")?; + + m.add_class::()?; + + Ok(m) +} From 9c0dfde80a65bb92d1e5b981e2ea29ce20f9c828 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Sat, 27 May 2023 00:15:49 +0000 Subject: [PATCH 302/316] Bump BoringSSL and/or OpenSSL in CI (#8973) Co-authored-by: pyca-boringbot[bot] --- .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 b2dd1ba58ea4..b1afc783626c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,8 +41,8 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} - # Latest commit on the BoringSSL master branch, as of May 25, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "5fcd47d137f9b556edc7a392035dc2d2f43282ca"}} + # Latest commit on the BoringSSL master branch, as of May 27, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "b0a026f8541c551854efd617021bb276f1fe5c23"}} # Latest commit on the OpenSSL master branch, as of May 26, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "0bf7e94c10f1b00510b8a36cdcbedc02a66468be"}} # Builds with various Rust versions. Includes MSRV and potential From 288c302b5041c45dbdb1a567885f50cf953519a7 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 27 May 2023 00:32:26 -0400 Subject: [PATCH 303/316] Remove unused bindings (#8972) --- src/_cffi_src/openssl/evp.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/_cffi_src/openssl/evp.py b/src/_cffi_src/openssl/evp.py index f1c367010398..d5875f7d09b0 100644 --- a/src/_cffi_src/openssl/evp.py +++ b/src/_cffi_src/openssl/evp.py @@ -82,11 +82,6 @@ int EVP_VerifyFinal(EVP_MD_CTX *, const unsigned char *, unsigned int, EVP_PKEY *); -int EVP_DigestSignInit(EVP_MD_CTX *, EVP_PKEY_CTX **, const EVP_MD *, - ENGINE *, EVP_PKEY *); -int EVP_DigestSignUpdate(EVP_MD_CTX *, const void *, size_t); -int EVP_DigestSignFinal(EVP_MD_CTX *, unsigned char *, size_t *); - EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *, ENGINE *); void EVP_PKEY_CTX_free(EVP_PKEY_CTX *); @@ -118,9 +113,6 @@ EVP_MD_CTX *EVP_MD_CTX_new(void); void EVP_MD_CTX_free(EVP_MD_CTX *); -int EVP_DigestSign(EVP_MD_CTX *, unsigned char *, size_t *, - const unsigned char *, size_t); - int EVP_PKEY_bits(const EVP_PKEY *); int EVP_PKEY_assign_RSA(EVP_PKEY *, RSA *); From 93c96b777acffd6b1fab17077397e5c5a73c4c71 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 27 May 2023 16:07:20 +0200 Subject: [PATCH 304/316] allow null params in AlgorithmIdentifiers with SHA hash function OIDs (#8974) RFC 4055 section 2.1 states "All implementations MUST accept both NULL and absent parameters as legal and equivalent encodings". It also makes some somewhat conflicting statements after that, but LibreSSL omits the null params for PSS, and OpenSSL parses this without issue so tolerance it is. --- docs/development/test-vectors.rst | 3 ++ src/rust/cryptography-x509/src/common.rs | 20 ++++----- src/rust/src/x509/ocsp.rs | 20 ++++----- src/rust/src/x509/sign.rs | 44 ++++++++++++------- tests/x509/test_x509.py | 17 +++++++ .../x509/custom/rsa_pss_sha256_no_null.pem | 20 +++++++++ 6 files changed, 88 insertions(+), 36 deletions(-) create mode 100644 vectors/cryptography_vectors/x509/custom/rsa_pss_sha256_no_null.pem diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 67440fd4b18a..56bc9361c555 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -496,6 +496,9 @@ Custom X.509 Vectors OID to not match the outer signature algorithm OID. * ``ms-certificate-template.pem`` - A certificate with a ``msCertificateTemplate`` extension. +* ``rsa_pss_sha256_no_null.pem`` - A certificate with an RSA PSS signature + with no encoded ``NULL`` for the PSS hash algorithm parameters. This certificate + was generated by LibreSSL. Custom X.509 Request Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs index 60856b7efd03..466d4b5bd179 100644 --- a/src/rust/cryptography-x509/src/common.rs +++ b/src/rust/cryptography-x509/src/common.rs @@ -22,23 +22,23 @@ impl AlgorithmIdentifier<'_> { #[derive(asn1::Asn1DefinedByRead, asn1::Asn1DefinedByWrite, PartialEq, Eq, Hash, Clone, Debug)] pub enum AlgorithmParameters<'a> { #[defined_by(oid::SHA1_OID)] - Sha1(asn1::Null), + Sha1(Option), #[defined_by(oid::SHA224_OID)] - Sha224(asn1::Null), + Sha224(Option), #[defined_by(oid::SHA256_OID)] - Sha256(asn1::Null), + Sha256(Option), #[defined_by(oid::SHA384_OID)] - Sha384(asn1::Null), + Sha384(Option), #[defined_by(oid::SHA512_OID)] - Sha512(asn1::Null), + Sha512(Option), #[defined_by(oid::SHA3_224_OID)] - Sha3_224(asn1::Null), + Sha3_224(Option), #[defined_by(oid::SHA3_256_OID)] - Sha3_256(asn1::Null), + Sha3_256(Option), #[defined_by(oid::SHA3_384_OID)] - Sha3_384(asn1::Null), + Sha3_384(Option), #[defined_by(oid::SHA3_512_OID)] - Sha3_512(asn1::Null), + Sha3_512(Option), #[defined_by(oid::ED25519_OID)] Ed25519, @@ -227,7 +227,7 @@ pub struct DHParams<'a> { // RSA-PSS ASN.1 default hash algorithm pub const PSS_SHA1_HASH_ALG: AlgorithmIdentifier<'_> = AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: AlgorithmParameters::Sha1(()), + params: AlgorithmParameters::Sha1(Some(())), }; // This is defined as an AlgorithmIdentifier in RFC 4055, diff --git a/src/rust/src/x509/ocsp.rs b/src/rust/src/x509/ocsp.rs index afa0b026ed1e..05ea096078bb 100644 --- a/src/rust/src/x509/ocsp.rs +++ b/src/rust/src/x509/ocsp.rs @@ -14,11 +14,11 @@ pub(crate) static ALGORITHM_PARAMETERS_TO_HASH: Lazy< HashMap, &str>, > = Lazy::new(|| { let mut h = HashMap::new(); - h.insert(common::AlgorithmParameters::Sha1(()), "SHA1"); - h.insert(common::AlgorithmParameters::Sha224(()), "SHA224"); - h.insert(common::AlgorithmParameters::Sha256(()), "SHA256"); - h.insert(common::AlgorithmParameters::Sha384(()), "SHA384"); - h.insert(common::AlgorithmParameters::Sha512(()), "SHA512"); + h.insert(common::AlgorithmParameters::Sha1(Some(())), "SHA1"); + h.insert(common::AlgorithmParameters::Sha224(Some(())), "SHA224"); + h.insert(common::AlgorithmParameters::Sha256(Some(())), "SHA256"); + h.insert(common::AlgorithmParameters::Sha384(Some(())), "SHA384"); + h.insert(common::AlgorithmParameters::Sha512(Some(())), "SHA512"); h }); @@ -30,35 +30,35 @@ pub(crate) static HASH_NAME_TO_ALGORITHM_IDENTIFIERS: Lazy< "sha1", common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Sha1(()), + params: common::AlgorithmParameters::Sha1(Some(())), }, ); h.insert( "sha224", common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Sha224(()), + params: common::AlgorithmParameters::Sha224(Some(())), }, ); h.insert( "sha256", common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Sha256(()), + params: common::AlgorithmParameters::Sha256(Some(())), }, ); h.insert( "sha384", common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Sha384(()), + params: common::AlgorithmParameters::Sha384(Some(())), }, ); h.insert( "sha512", common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::Sha512(()), + params: common::AlgorithmParameters::Sha512(Some(())), }, ); h diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index 16db5a587f90..b3a799b8cb01 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -507,14 +507,14 @@ fn identify_alg_params_for_hash_type( hash_type: HashType, ) -> pyo3::PyResult> { match hash_type { - HashType::Sha224 => Ok(common::AlgorithmParameters::Sha224(())), - HashType::Sha256 => Ok(common::AlgorithmParameters::Sha256(())), - HashType::Sha384 => Ok(common::AlgorithmParameters::Sha384(())), - HashType::Sha512 => Ok(common::AlgorithmParameters::Sha512(())), - HashType::Sha3_224 => Ok(common::AlgorithmParameters::Sha3_224(())), - HashType::Sha3_256 => Ok(common::AlgorithmParameters::Sha3_256(())), - HashType::Sha3_384 => Ok(common::AlgorithmParameters::Sha3_384(())), - HashType::Sha3_512 => Ok(common::AlgorithmParameters::Sha3_512(())), + HashType::Sha224 => Ok(common::AlgorithmParameters::Sha224(Some(()))), + HashType::Sha256 => Ok(common::AlgorithmParameters::Sha256(Some(()))), + HashType::Sha384 => Ok(common::AlgorithmParameters::Sha384(Some(()))), + HashType::Sha512 => Ok(common::AlgorithmParameters::Sha512(Some(()))), + HashType::Sha3_224 => Ok(common::AlgorithmParameters::Sha3_224(Some(()))), + HashType::Sha3_256 => Ok(common::AlgorithmParameters::Sha3_256(Some(()))), + HashType::Sha3_384 => Ok(common::AlgorithmParameters::Sha3_384(Some(()))), + HashType::Sha3_512 => Ok(common::AlgorithmParameters::Sha3_512(Some(()))), HashType::None => Err(pyo3::exceptions::PyTypeError::new_err( "Algorithm must be a registered hash algorithm, not None.", )), @@ -714,25 +714,37 @@ mod tests { #[test] fn test_identify_alg_params_for_hash_type() { for (hash, params) in [ - (HashType::Sha224, common::AlgorithmParameters::Sha224(())), - (HashType::Sha256, common::AlgorithmParameters::Sha256(())), - (HashType::Sha384, common::AlgorithmParameters::Sha384(())), - (HashType::Sha512, common::AlgorithmParameters::Sha512(())), + ( + HashType::Sha224, + common::AlgorithmParameters::Sha224(Some(())), + ), + ( + HashType::Sha256, + common::AlgorithmParameters::Sha256(Some(())), + ), + ( + HashType::Sha384, + common::AlgorithmParameters::Sha384(Some(())), + ), + ( + HashType::Sha512, + common::AlgorithmParameters::Sha512(Some(())), + ), ( HashType::Sha3_224, - common::AlgorithmParameters::Sha3_224(()), + common::AlgorithmParameters::Sha3_224(Some(())), ), ( HashType::Sha3_256, - common::AlgorithmParameters::Sha3_256(()), + common::AlgorithmParameters::Sha3_256(Some(())), ), ( HashType::Sha3_384, - common::AlgorithmParameters::Sha3_384(()), + common::AlgorithmParameters::Sha3_384(Some(())), ), ( HashType::Sha3_512, - common::AlgorithmParameters::Sha3_512(()), + common::AlgorithmParameters::Sha3_512(Some(())), ), ] { assert_eq!(identify_alg_params_for_hash_type(hash).unwrap(), params); diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 88be1a1763a2..662cb9af2b8e 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -765,6 +765,23 @@ def test_load_cert_pub_key(self, backend): cert.signature_hash_algorithm, ) + def test_load_pss_cert_no_null(self, backend): + """ + This test verifies that PSS certs where the hash algorithm + identifiers have no trailing null still load properly. LibreSSL + generates certs like this. + """ + cert = _load_cert( + os.path.join("x509", "custom", "rsa_pss_sha256_no_null.pem"), + x509.load_pem_x509_certificate, + ) + assert isinstance(cert, x509.Certificate) + pss = cert.signature_algorithm_parameters + assert isinstance(pss, padding.PSS) + assert isinstance(pss._mgf, padding.MGF1) + assert isinstance(pss._mgf._algorithm, hashes.SHA256) + assert isinstance(cert.signature_hash_algorithm, hashes.SHA256) + def test_load_pss_sha1_mgf1_sha1(self, backend): cert = _load_cert( os.path.join("x509", "ee-pss-sha1-cert.pem"), diff --git a/vectors/cryptography_vectors/x509/custom/rsa_pss_sha256_no_null.pem b/vectors/cryptography_vectors/x509/custom/rsa_pss_sha256_no_null.pem new file mode 100644 index 000000000000..3780fe0d56e4 --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/rsa_pss_sha256_no_null.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDADCCAbgCCQDEHaWKEwyb7zA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQC +AaEaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIBIDASMRAwDgYDVQQDDAd0 +ZXN0aW5nMB4XDTIzMDUyNzA2NDExOVoXDTMzMDUyNDA2NDExOVowEjEQMA4GA1UE +AwwHdGVzdGluZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM2INK8b +04HqQ1ZYt94tDO0lFPOeCswGhKJQ9SRzTNpNB1XaJvrzz999gimmedUwgwVXHRdt +9WS/QXuyKzyeHcQFN8IPVylIMNGS9IEVa9NGNXzLVMIJYzDlwrEhQm6O4fUW8VtE +U85BXEw0yTEgeQxfuR688kjp/1bjkYsvLE/ID9EMgnXXmzunuqYxG+nmonfIYTgR +NpmXJJgp096sJHKaRkDaC7eApl6776kueFRRSiAIHY10wHqgOL0pBwIMSd/F/EKv +G0weUBLqjzus7G/+LdC6UoGWgV4EybvYlisH4SnLbNdvFilLWaNbgbD2R07hVaHs +8010rCq5RT766dcCAwEAATA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEa +MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIBIAOCAQEAdKmJnR+UZaMi9RSI +ZBTN5SRv0nTJCwX/citYo8MMcsJ+DOLxR4tC9haYhRD9mIjks1NXcEKN+LqW9hDF +C5ptas03HeEY1NByS3wFSDRHggNFxpwmvX4hGp/8fjaf8EOb1rzh0TsJEgcv4h4Z +KeeSYvCtk5pMe+2lDgLfSegM22RFgXBj/wcI5JDxkGJ4M56++IM55HdXTY1cy7KY +woTtP8G6xzmKdVC+E8XGjBAbyzyommMpAI6aUnjW6oa4fD4ev1X17+/CQb1VyAYs +7nz4uBV1FTNAiUzjrf95KV5p2ir6YcOdspwuRbUJwGP+/1nXeN1pksnh56Fe3J5b +8Zw4cw== +-----END CERTIFICATE----- + From f639144ba7d49547422f3d91c9b3bfe6537d5334 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 28 May 2023 03:23:12 -0400 Subject: [PATCH 305/316] Remove a few more unused bindings (#8977) --- src/_cffi_src/openssl/bignum.py | 2 -- src/_cffi_src/openssl/ec.py | 1 - src/_cffi_src/openssl/pem.py | 1 - src/_cffi_src/openssl/pkcs7.py | 2 -- src/_cffi_src/openssl/ssl.py | 4 ---- src/_cffi_src/openssl/x509name.py | 1 - 6 files changed, 11 deletions(-) diff --git a/src/_cffi_src/openssl/bignum.py b/src/_cffi_src/openssl/bignum.py index 9ea729001433..999e10cd031b 100644 --- a/src/_cffi_src/openssl/bignum.py +++ b/src/_cffi_src/openssl/bignum.py @@ -61,8 +61,6 @@ int BN_num_bytes(const BIGNUM *); -int BN_mod(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); - /* The following 3 prime methods are exposed for Tribler. */ int BN_generate_prime_ex(BIGNUM *, int, int, const BIGNUM *, const BIGNUM *, BN_GENCB *); diff --git a/src/_cffi_src/openssl/ec.py b/src/_cffi_src/openssl/ec.py index e745b3efcd14..0e3604d1d29a 100644 --- a/src/_cffi_src/openssl/ec.py +++ b/src/_cffi_src/openssl/ec.py @@ -35,7 +35,6 @@ size_t EC_get_builtin_curves(EC_builtin_curve *, size_t); -EC_KEY *EC_KEY_new(void); void EC_KEY_free(EC_KEY *); EC_KEY *EC_KEY_new_by_curve_name(int); diff --git a/src/_cffi_src/openssl/pem.py b/src/_cffi_src/openssl/pem.py index 07f267199ad8..950bd3780c9c 100644 --- a/src/_cffi_src/openssl/pem.py +++ b/src/_cffi_src/openssl/pem.py @@ -42,7 +42,6 @@ int PEM_write_bio_X509_CRL(BIO *, X509_CRL *); PKCS7 *PEM_read_bio_PKCS7(BIO *, PKCS7 **, pem_password_cb *, void *); -int PEM_write_bio_PKCS7(BIO *, PKCS7 *); DH *PEM_read_bio_DHparams(BIO *, DH **, pem_password_cb *, void *); diff --git a/src/_cffi_src/openssl/pkcs7.py b/src/_cffi_src/openssl/pkcs7.py index 60741bbac19d..ef75157a80da 100644 --- a/src/_cffi_src/openssl/pkcs7.py +++ b/src/_cffi_src/openssl/pkcs7.py @@ -48,8 +48,6 @@ FUNCTIONS = """ void PKCS7_free(PKCS7 *); -PKCS7 *PKCS7_sign(X509 *, EVP_PKEY *, Cryptography_STACK_OF_X509 *, - BIO *, int); int SMIME_write_PKCS7(BIO *, PKCS7 *, BIO *, int); int PEM_write_bio_PKCS7_stream(BIO *, PKCS7 *, BIO *, int); PKCS7_SIGNER_INFO *PKCS7_sign_add_signer(PKCS7 *, X509 *, EVP_PKEY *, diff --git a/src/_cffi_src/openssl/ssl.py b/src/_cffi_src/openssl/ssl.py index c836be4f9f6d..dfab7f651341 100644 --- a/src/_cffi_src/openssl/ssl.py +++ b/src/_cffi_src/openssl/ssl.py @@ -12,7 +12,6 @@ static const long Cryptography_HAS_SSL_ST; static const long Cryptography_HAS_TLS_ST; static const long Cryptography_HAS_TLSv1_3_FUNCTIONS; -static const long Cryptography_HAS_DTLS; static const long Cryptography_HAS_SIGALGS; static const long Cryptography_HAS_PSK; static const long Cryptography_HAS_PSK_TLSv1_3; @@ -336,8 +335,6 @@ const char *SSL_get_version(const SSL *); int SSL_version(const SSL *); -void *SSL_get_ex_data(const SSL *, int); - void SSL_set_tlsext_host_name(SSL *, char *); void SSL_CTX_set_tlsext_servername_callback( SSL_CTX *, @@ -498,7 +495,6 @@ 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, long *ptv_usec) { diff --git a/src/_cffi_src/openssl/x509name.py b/src/_cffi_src/openssl/x509name.py index 876af17f2d5e..5e0349e4846a 100644 --- a/src/_cffi_src/openssl/x509name.py +++ b/src/_cffi_src/openssl/x509name.py @@ -39,7 +39,6 @@ ASN1_OBJECT *X509_NAME_ENTRY_get_object(const X509_NAME_ENTRY *); ASN1_STRING *X509_NAME_ENTRY_get_data(const X509_NAME_ENTRY *); -int X509_NAME_add_entry(X509_NAME *, X509_NAME_ENTRY *, int, int); int X509_NAME_add_entry_by_NID(X509_NAME *, int, int, const unsigned char *, int, int, int); From 5efbc110905230f771d5bde918c059cd3d029e22 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 29 May 2023 02:04:28 -0400 Subject: [PATCH 306/316] Bump syn (#8979) Dependabot doesn't currently update it because of https://github.com/dependabot/dependabot-core/issues/2064 --- 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 1d1c76d6bca8..9f4f5b36f8ec 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -31,7 +31,7 @@ checksum = "a045c3ccad89f244a86bd1e6cf1a7bf645296e7692698b056399b6efd4639407" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] @@ -183,7 +183,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] @@ -395,9 +395,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" dependencies = [ "proc-macro2", "quote", From 3e24e44527a69884ca0c3247e1b5e9c8bbf590c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 May 2023 13:07:44 +0000 Subject: [PATCH 307/316] Bump once_cell from 1.17.1 to 1.17.2 in /src/rust (#8982) Bumps [once_cell](https://github.com/matklad/once_cell) from 1.17.1 to 1.17.2. - [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md) - [Commits](https://github.com/matklad/once_cell/compare/v1.17.1...v1.17.2) --- updated-dependencies: - dependency-name: once_cell 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 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 9f4f5b36f8ec..b66d30259a2c 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -156,9 +156,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" [[package]] name = "openssl" From 88e8c288975709228005e70301644034463d9823 Mon Sep 17 00:00:00 2001 From: "pyca-boringbot[bot]" <106132319+pyca-boringbot[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 00:23:34 +0000 Subject: [PATCH 308/316] Bump BoringSSL and/or OpenSSL in CI (#8983) Co-authored-by: pyca-boringbot[bot] --- .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 b1afc783626c..899b5515c39c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,8 +43,8 @@ jobs: - {VERSION: "3.12-dev", NOXSESSION: "tests"} # Latest commit on the BoringSSL master branch, as of May 27, 2023. - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "boringssl", VERSION: "b0a026f8541c551854efd617021bb276f1fe5c23"}} - # Latest commit on the OpenSSL master branch, as of May 26, 2023. - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "0bf7e94c10f1b00510b8a36cdcbedc02a66468be"}} + # Latest commit on the OpenSSL master branch, as of May 30, 2023. + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "36424806d699233b9a90a3a97fff3011828e2548"}} # Builds with various Rust versions. Includes MSRV and potential # future MSRV: # 1.60 - pem 2.0.1 From 730a5ce11a91f40c1bb0f881ab22bc52d6cecef6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 02:01:47 +0000 Subject: [PATCH 309/316] Bump openssl-sys from 0.9.87 to 0.9.88 in /src/rust (#8984) Bumps [openssl-sys](https://github.com/sfackler/rust-openssl) from 0.9.87 to 0.9.88. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.87...openssl-sys-v0.9.88) --- updated-dependencies: - dependency-name: openssl-sys 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 | 4 ++-- src/rust/Cargo.toml | 2 +- src/rust/cryptography-cffi/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index b66d30259a2c..49806893962c 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -188,9 +188,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.87" +version = "0.9.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e17f59264b2809d77ae94f0e1ebabc434773f370d6ca667bd223ea10e06cc7e" +checksum = "c2ce0f250f34a308dcfdbb351f511359857d4ed2134ba715a4eadd46e1ffd617" dependencies = [ "cc", "libc", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 3efbf1334343..30c1b44ccfef 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -17,7 +17,7 @@ cryptography-openssl = { path = "cryptography-openssl" } pem = "1.1" ouroboros = "0.15" openssl = "0.10.52" -openssl-sys = "0.9.87" +openssl-sys = "0.9.88" foreign-types-shared = "0.1" [build-dependencies] diff --git a/src/rust/cryptography-cffi/Cargo.toml b/src/rust/cryptography-cffi/Cargo.toml index 652e621e10a0..65051c2a4627 100644 --- a/src/rust/cryptography-cffi/Cargo.toml +++ b/src/rust/cryptography-cffi/Cargo.toml @@ -9,7 +9,7 @@ rust-version = "1.56.0" [dependencies] pyo3 = { version = "0.18", features = ["abi3-py37"] } -openssl-sys = "0.9.87" +openssl-sys = "0.9.88" [build-dependencies] cc = "1.0.72" From 0918c7236c94c29272e0790ba0227cfa9401943b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 02:10:26 +0000 Subject: [PATCH 310/316] Bump coverage from 7.2.6 to 7.2.7 (#8985) Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.2.6 to 7.2.7. - [Release notes](https://github.com/nedbat/coveragepy/releases) - [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst) - [Commits](https://github.com/nedbat/coveragepy/compare/7.2.6...7.2.7) --- updated-dependencies: - dependency-name: coverage 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> --- ci-constraints-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-constraints-requirements.txt b/ci-constraints-requirements.txt index 2c91aecac0da..009faa5e0bdc 100644 --- a/ci-constraints-requirements.txt +++ b/ci-constraints-requirements.txt @@ -29,7 +29,7 @@ click==8.1.3 # via black colorlog==6.7.0 # via nox -coverage==7.2.6 +coverage==7.2.7 # via pytest-cov distlib==0.3.6 # via virtualenv From 851d8ccb340bfc93c827b9e80af939a216b34925 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 May 2023 02:14:28 +0000 Subject: [PATCH 311/316] Bump openssl from 0.10.52 to 0.10.53 in /src/rust (#8986) Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.52 to 0.10.53. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.52...openssl-v0.10.53) --- updated-dependencies: - dependency-name: openssl 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 | 4 ++-- src/rust/Cargo.toml | 2 +- src/rust/cryptography-openssl/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 49806893962c..47d972ff46ff 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -162,9 +162,9 @@ checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" [[package]] name = "openssl" -version = "0.10.52" +version = "0.10.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b8574602df80f7b85fdfc5392fa884a4e3b3f4f35402c070ab34c3d3f78d56" +checksum = "12df40a956736488b7b44fe79fe12d4f245bb5b3f5a1f6095e499760015be392" dependencies = [ "bitflags", "cfg-if", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 30c1b44ccfef..2ca1d79d6802 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -16,7 +16,7 @@ cryptography-x509 = { path = "cryptography-x509" } cryptography-openssl = { path = "cryptography-openssl" } pem = "1.1" ouroboros = "0.15" -openssl = "0.10.52" +openssl = "0.10.53" openssl-sys = "0.9.88" foreign-types-shared = "0.1" diff --git a/src/rust/cryptography-openssl/Cargo.toml b/src/rust/cryptography-openssl/Cargo.toml index bd153edc40d5..587a85909565 100644 --- a/src/rust/cryptography-openssl/Cargo.toml +++ b/src/rust/cryptography-openssl/Cargo.toml @@ -8,7 +8,7 @@ publish = false rust-version = "1.56.0" [dependencies] -openssl = "0.10.52" +openssl = "0.10.53" ffi = { package = "openssl-sys", version = "0.9.85" } foreign-types = "0.3" foreign-types-shared = "0.1" From f302d28b81607aab28d22b653da78d564824f267 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 29 May 2023 22:17:09 -0400 Subject: [PATCH 312/316] Update CI for new LibreSSL releases (#8975) --- .github/workflows/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 899b5515c39c..4f79786f3470 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,8 +37,9 @@ jobs: - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct no-psk"}} - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0", CONFIG_FLAGS: "no-legacy", NO_LEGACY: "1"}} - {VERSION: "3.11", NOXSESSION: "tests", NOXARGS: "--enable-fips=1", OPENSSL: {TYPE: "openssl", CONFIG_FLAGS: "enable-fips", VERSION: "3.1.0"}} - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.6.2"}} - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.2"}} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.6.3"}} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.3"}} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.8.0"}} - {VERSION: "3.11", NOXSESSION: "tests-randomorder"} - {VERSION: "3.12-dev", NOXSESSION: "tests"} # Latest commit on the BoringSSL master branch, as of May 27, 2023. From 91e41898e6d1d2a9a6e980c39e2f8baa2fa8a1f8 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Mon, 29 May 2023 22:32:12 -0400 Subject: [PATCH 313/316] Port DSA to Rust (#8978) --- src/_cffi_src/openssl/bignum.py | 2 - src/_cffi_src/openssl/dsa.py | 3 - src/_cffi_src/openssl/evp.py | 1 - .../hazmat/backends/openssl/backend.py | 117 +----- .../hazmat/backends/openssl/dsa.py | 246 ------------- .../bindings/_rust/openssl/__init__.pyi | 2 + .../hazmat/bindings/_rust/openssl/dsa.pyi | 20 ++ .../hazmat/primitives/asymmetric/dsa.py | 4 + src/rust/src/backend/dh.rs | 3 +- src/rust/src/backend/dsa.rs | 333 ++++++++++++++++++ src/rust/src/backend/ed25519.rs | 3 +- src/rust/src/backend/ed448.rs | 3 +- src/rust/src/backend/mod.rs | 2 + src/rust/src/backend/utils.rs | 40 ++- src/rust/src/backend/x25519.rs | 3 +- src/rust/src/backend/x448.rs | 3 +- src/rust/src/error.rs | 7 +- tests/hazmat/primitives/test_dsa.py | 6 + tests/hazmat/primitives/test_x25519.py | 7 + tests/x509/test_x509_crlbuilder.py | 4 + 20 files changed, 445 insertions(+), 364 deletions(-) delete mode 100644 src/cryptography/hazmat/backends/openssl/dsa.py create mode 100644 src/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi create mode 100644 src/rust/src/backend/dsa.rs diff --git a/src/_cffi_src/openssl/bignum.py b/src/_cffi_src/openssl/bignum.py index 999e10cd031b..044403325582 100644 --- a/src/_cffi_src/openssl/bignum.py +++ b/src/_cffi_src/openssl/bignum.py @@ -39,8 +39,6 @@ int BN_MONT_CTX_set(BN_MONT_CTX *, const BIGNUM *, BN_CTX *); void BN_MONT_CTX_free(BN_MONT_CTX *); -BIGNUM *BN_dup(const BIGNUM *); - int BN_set_word(BIGNUM *, BN_ULONG); char *BN_bn2hex(const BIGNUM *); diff --git a/src/_cffi_src/openssl/dsa.py b/src/_cffi_src/openssl/dsa.py index 04478a0e577b..d91076393582 100644 --- a/src/_cffi_src/openssl/dsa.py +++ b/src/_cffi_src/openssl/dsa.py @@ -23,10 +23,7 @@ int DSA_verify(int, const unsigned char *, int, const unsigned char *, int, DSA *); -void DSA_get0_pqg(const DSA *, const BIGNUM **, const BIGNUM **, - const BIGNUM **); int DSA_set0_pqg(DSA *, BIGNUM *, BIGNUM *, BIGNUM *); -void DSA_get0_key(const DSA *, const BIGNUM **, const BIGNUM **); int DSA_set0_key(DSA *, BIGNUM *, BIGNUM *); int DSA_generate_parameters_ex(DSA *, int, unsigned char *, int, int *, unsigned long *, BN_GENCB *); diff --git a/src/_cffi_src/openssl/evp.py b/src/_cffi_src/openssl/evp.py index d5875f7d09b0..ce54fd9fe931 100644 --- a/src/_cffi_src/openssl/evp.py +++ b/src/_cffi_src/openssl/evp.py @@ -66,7 +66,6 @@ int EVP_PKEY_type(int); int EVP_PKEY_size(EVP_PKEY *); RSA *EVP_PKEY_get1_RSA(EVP_PKEY *); -DSA *EVP_PKEY_get1_DSA(EVP_PKEY *); int EVP_PKEY_encrypt(EVP_PKEY_CTX *, unsigned char *, size_t *, const unsigned char *, size_t); diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index f2e381a15d61..02d51094cfe5 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -15,11 +15,6 @@ from cryptography.hazmat.backends.openssl import aead from cryptography.hazmat.backends.openssl.ciphers import _CipherContext from cryptography.hazmat.backends.openssl.cmac import _CMACContext -from cryptography.hazmat.backends.openssl.dsa import ( - _DSAParameters, - _DSAPrivateKey, - _DSAPublicKey, -) from cryptography.hazmat.backends.openssl.ec import ( _EllipticCurvePrivateKey, _EllipticCurvePublicKey, @@ -551,10 +546,9 @@ def _evp_pkey_to_private_key( unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation, ) 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) - dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) - return _DSAPrivateKey(self, dsa_cdata, evp_pkey) + return rust_openssl.dsa.private_key_from_ptr( + int(self._ffi.cast("uintptr_t", evp_pkey)) + ) elif key_type == self._lib.EVP_PKEY_EC: ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) self.openssl_assert(ec_cdata != self._ffi.NULL) @@ -613,10 +607,9 @@ def _evp_pkey_to_public_key(self, evp_pkey) -> PublicKeyTypes: self.openssl_assert(res == 1) return self.load_der_public_key(self._read_mem_bio(bio)) 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) - dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) - return _DSAPublicKey(self, dsa_cdata, evp_pkey) + return rust_openssl.dsa.public_key_from_ptr( + int(self._ffi.cast("uintptr_t", evp_pkey)) + ) elif key_type == self._lib.EVP_PKEY_EC: ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) if ec_cdata == self._ffi.NULL: @@ -696,36 +689,12 @@ def generate_dsa_parameters(self, key_size: int) -> dsa.DSAParameters: "Key size must be 1024, 2048, 3072, or 4096 bits." ) - ctx = self._lib.DSA_new() - self.openssl_assert(ctx != self._ffi.NULL) - ctx = self._ffi.gc(ctx, self._lib.DSA_free) - - res = self._lib.DSA_generate_parameters_ex( - ctx, - key_size, - self._ffi.NULL, - 0, - self._ffi.NULL, - self._ffi.NULL, - self._ffi.NULL, - ) - - self.openssl_assert(res == 1) - - return _DSAParameters(self, ctx) + return rust_openssl.dsa.generate_parameters(key_size) def generate_dsa_private_key( self, parameters: dsa.DSAParameters ) -> dsa.DSAPrivateKey: - ctx = self._lib.DSAparams_dup( - parameters._dsa_cdata # type: ignore[attr-defined] - ) - self.openssl_assert(ctx != self._ffi.NULL) - ctx = self._ffi.gc(ctx, self._lib.DSA_free) - self._lib.DSA_generate_key(ctx) - evp_pkey = self._dsa_cdata_to_evp_pkey(ctx) - - return _DSAPrivateKey(self, ctx, evp_pkey) + return parameters.generate_private_key() def generate_dsa_private_key_and_parameters( self, key_size: int @@ -733,78 +702,28 @@ def generate_dsa_private_key_and_parameters( parameters = self.generate_dsa_parameters(key_size) return self.generate_dsa_private_key(parameters) - def _dsa_cdata_set_values( - self, dsa_cdata, p, q, g, pub_key, priv_key - ) -> None: - res = self._lib.DSA_set0_pqg(dsa_cdata, p, q, g) - self.openssl_assert(res == 1) - res = self._lib.DSA_set0_key(dsa_cdata, pub_key, priv_key) - self.openssl_assert(res == 1) - def load_dsa_private_numbers( self, numbers: dsa.DSAPrivateNumbers ) -> dsa.DSAPrivateKey: dsa._check_dsa_private_numbers(numbers) - parameter_numbers = numbers.public_numbers.parameter_numbers - - dsa_cdata = self._lib.DSA_new() - self.openssl_assert(dsa_cdata != self._ffi.NULL) - dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) - - p = self._int_to_bn(parameter_numbers.p) - q = self._int_to_bn(parameter_numbers.q) - g = self._int_to_bn(parameter_numbers.g) - pub_key = self._int_to_bn(numbers.public_numbers.y) - priv_key = self._int_to_bn(numbers.x) - self._dsa_cdata_set_values(dsa_cdata, p, q, g, pub_key, priv_key) - - evp_pkey = self._dsa_cdata_to_evp_pkey(dsa_cdata) - - return _DSAPrivateKey(self, dsa_cdata, evp_pkey) + return rust_openssl.dsa.from_private_numbers(numbers) def load_dsa_public_numbers( self, numbers: dsa.DSAPublicNumbers ) -> dsa.DSAPublicKey: dsa._check_dsa_parameters(numbers.parameter_numbers) - dsa_cdata = self._lib.DSA_new() - self.openssl_assert(dsa_cdata != self._ffi.NULL) - dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) - - p = self._int_to_bn(numbers.parameter_numbers.p) - q = self._int_to_bn(numbers.parameter_numbers.q) - g = self._int_to_bn(numbers.parameter_numbers.g) - pub_key = self._int_to_bn(numbers.y) - priv_key = self._ffi.NULL - self._dsa_cdata_set_values(dsa_cdata, p, q, g, pub_key, priv_key) - - evp_pkey = self._dsa_cdata_to_evp_pkey(dsa_cdata) - - return _DSAPublicKey(self, dsa_cdata, evp_pkey) + return rust_openssl.dsa.from_public_numbers(numbers) def load_dsa_parameter_numbers( self, numbers: dsa.DSAParameterNumbers ) -> dsa.DSAParameters: dsa._check_dsa_parameters(numbers) - dsa_cdata = self._lib.DSA_new() - self.openssl_assert(dsa_cdata != self._ffi.NULL) - dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) - - p = self._int_to_bn(numbers.p) - q = self._int_to_bn(numbers.q) - g = self._int_to_bn(numbers.g) - res = self._lib.DSA_set0_pqg(dsa_cdata, p, q, g) - self.openssl_assert(res == 1) - - return _DSAParameters(self, dsa_cdata) - - def _dsa_cdata_to_evp_pkey(self, dsa_cdata): - evp_pkey = self._create_evp_pkey_gc() - res = self._lib.EVP_PKEY_set1_DSA(evp_pkey, dsa_cdata) - self.openssl_assert(res == 1) - return evp_pkey + return rust_openssl.dsa.from_parameter_numbers(numbers) def dsa_supported(self) -> bool: - return not self._fips_enabled + return ( + not self._lib.CRYPTOGRAPHY_IS_BORINGSSL and not self._fips_enabled + ) def dsa_hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: if not self.dsa_supported(): @@ -1409,8 +1328,6 @@ def _private_key_bytes( if encoding is serialization.Encoding.PEM: if key_type == self._lib.EVP_PKEY_RSA: write_bio = self._lib.PEM_write_bio_RSAPrivateKey - elif key_type == self._lib.EVP_PKEY_DSA: - write_bio = self._lib.PEM_write_bio_DSAPrivateKey else: assert key_type == self._lib.EVP_PKEY_EC write_bio = self._lib.PEM_write_bio_ECPrivateKey @@ -1426,11 +1343,9 @@ def _private_key_bytes( ) if key_type == self._lib.EVP_PKEY_RSA: write_bio = self._lib.i2d_RSAPrivateKey_bio - elif key_type == self._lib.EVP_PKEY_EC: - write_bio = self._lib.i2d_ECPrivateKey_bio else: - assert key_type == self._lib.EVP_PKEY_DSA - write_bio = self._lib.i2d_DSAPrivateKey_bio + assert key_type == self._lib.EVP_PKEY_EC + write_bio = self._lib.i2d_ECPrivateKey_bio return self._bio_func_output(write_bio, cdata) raise ValueError("Unsupported encoding for TraditionalOpenSSL") diff --git a/src/cryptography/hazmat/backends/openssl/dsa.py b/src/cryptography/hazmat/backends/openssl/dsa.py deleted file mode 100644 index 411a80820e85..000000000000 --- a/src/cryptography/hazmat/backends/openssl/dsa.py +++ /dev/null @@ -1,246 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import annotations - -import typing - -from cryptography.exceptions import InvalidSignature -from cryptography.hazmat.backends.openssl.utils import ( - _calculate_digest_and_algorithm, -) -from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import dsa -from cryptography.hazmat.primitives.asymmetric import utils as asym_utils - -if typing.TYPE_CHECKING: - from cryptography.hazmat.backends.openssl.backend import Backend - - -def _dsa_sig_sign( - backend: Backend, private_key: _DSAPrivateKey, data: bytes -) -> bytes: - sig_buf_len = backend._lib.DSA_size(private_key._dsa_cdata) - sig_buf = backend._ffi.new("unsigned char[]", sig_buf_len) - buflen = backend._ffi.new("unsigned int *") - - # The first parameter passed to DSA_sign is unused by OpenSSL but - # must be an integer. - res = backend._lib.DSA_sign( - 0, data, len(data), sig_buf, buflen, private_key._dsa_cdata - ) - backend.openssl_assert(res == 1) - backend.openssl_assert(buflen[0]) - - return backend._ffi.buffer(sig_buf)[: buflen[0]] - - -def _dsa_sig_verify( - backend: Backend, - public_key: _DSAPublicKey, - signature: bytes, - data: bytes, -) -> None: - # The first parameter passed to DSA_verify is unused by OpenSSL but - # must be an integer. - res = backend._lib.DSA_verify( - 0, data, len(data), signature, len(signature), public_key._dsa_cdata - ) - - if res != 1: - backend._consume_errors() - raise InvalidSignature - - -class _DSAParameters(dsa.DSAParameters): - def __init__(self, backend: Backend, dsa_cdata): - self._backend = backend - self._dsa_cdata = dsa_cdata - - def parameter_numbers(self) -> dsa.DSAParameterNumbers: - p = self._backend._ffi.new("BIGNUM **") - q = self._backend._ffi.new("BIGNUM **") - g = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g) - self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) - self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) - self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) - return dsa.DSAParameterNumbers( - p=self._backend._bn_to_int(p[0]), - q=self._backend._bn_to_int(q[0]), - g=self._backend._bn_to_int(g[0]), - ) - - def generate_private_key(self) -> dsa.DSAPrivateKey: - return self._backend.generate_dsa_private_key(self) - - -class _DSAPrivateKey(dsa.DSAPrivateKey): - _key_size: int - - def __init__(self, backend: Backend, dsa_cdata, evp_pkey): - self._backend = backend - self._dsa_cdata = dsa_cdata - self._evp_pkey = evp_pkey - - p = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DSA_get0_pqg( - dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL - ) - self._backend.openssl_assert(p[0] != backend._ffi.NULL) - self._key_size = self._backend._lib.BN_num_bits(p[0]) - - @property - def key_size(self) -> int: - return self._key_size - - def private_numbers(self) -> dsa.DSAPrivateNumbers: - p = self._backend._ffi.new("BIGNUM **") - q = self._backend._ffi.new("BIGNUM **") - g = self._backend._ffi.new("BIGNUM **") - pub_key = self._backend._ffi.new("BIGNUM **") - priv_key = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g) - self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) - self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) - self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) - self._backend._lib.DSA_get0_key(self._dsa_cdata, pub_key, priv_key) - self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) - self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL) - return dsa.DSAPrivateNumbers( - public_numbers=dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=self._backend._bn_to_int(p[0]), - q=self._backend._bn_to_int(q[0]), - g=self._backend._bn_to_int(g[0]), - ), - y=self._backend._bn_to_int(pub_key[0]), - ), - x=self._backend._bn_to_int(priv_key[0]), - ) - - def public_key(self) -> dsa.DSAPublicKey: - dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata) - self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL) - dsa_cdata = self._backend._ffi.gc( - dsa_cdata, self._backend._lib.DSA_free - ) - pub_key = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DSA_get0_key( - self._dsa_cdata, pub_key, self._backend._ffi.NULL - ) - self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) - pub_key_dup = self._backend._lib.BN_dup(pub_key[0]) - res = self._backend._lib.DSA_set0_key( - dsa_cdata, pub_key_dup, self._backend._ffi.NULL - ) - self._backend.openssl_assert(res == 1) - evp_pkey = self._backend._dsa_cdata_to_evp_pkey(dsa_cdata) - return _DSAPublicKey(self._backend, dsa_cdata, evp_pkey) - - def parameters(self) -> dsa.DSAParameters: - dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata) - self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL) - dsa_cdata = self._backend._ffi.gc( - dsa_cdata, self._backend._lib.DSA_free - ) - return _DSAParameters(self._backend, dsa_cdata) - - def private_bytes( - self, - encoding: serialization.Encoding, - format: serialization.PrivateFormat, - encryption_algorithm: serialization.KeySerializationEncryption, - ) -> bytes: - return self._backend._private_key_bytes( - encoding, - format, - encryption_algorithm, - self, - self._evp_pkey, - self._dsa_cdata, - ) - - def sign( - self, - data: bytes, - algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], - ) -> bytes: - data, _ = _calculate_digest_and_algorithm(data, algorithm) - return _dsa_sig_sign(self._backend, self, data) - - -class _DSAPublicKey(dsa.DSAPublicKey): - _key_size: int - - def __init__(self, backend: Backend, dsa_cdata, evp_pkey): - self._backend = backend - self._dsa_cdata = dsa_cdata - self._evp_pkey = evp_pkey - p = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DSA_get0_pqg( - dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL - ) - self._backend.openssl_assert(p[0] != backend._ffi.NULL) - self._key_size = self._backend._lib.BN_num_bits(p[0]) - - @property - def key_size(self) -> int: - return self._key_size - - def __eq__(self, other: object) -> bool: - if not isinstance(other, _DSAPublicKey): - return NotImplemented - - return ( - self._backend._lib.EVP_PKEY_cmp(self._evp_pkey, other._evp_pkey) - == 1 - ) - - def public_numbers(self) -> dsa.DSAPublicNumbers: - p = self._backend._ffi.new("BIGNUM **") - q = self._backend._ffi.new("BIGNUM **") - g = self._backend._ffi.new("BIGNUM **") - pub_key = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g) - self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) - self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) - self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) - self._backend._lib.DSA_get0_key( - self._dsa_cdata, pub_key, self._backend._ffi.NULL - ) - self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) - return dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers( - p=self._backend._bn_to_int(p[0]), - q=self._backend._bn_to_int(q[0]), - g=self._backend._bn_to_int(g[0]), - ), - y=self._backend._bn_to_int(pub_key[0]), - ) - - def parameters(self) -> dsa.DSAParameters: - dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata) - dsa_cdata = self._backend._ffi.gc( - dsa_cdata, self._backend._lib.DSA_free - ) - return _DSAParameters(self._backend, dsa_cdata) - - def public_bytes( - self, - encoding: serialization.Encoding, - format: serialization.PublicFormat, - ) -> bytes: - return self._backend._public_key_bytes( - encoding, format, self, self._evp_pkey, None - ) - - def verify( - self, - signature: bytes, - data: bytes, - algorithm: typing.Union[asym_utils.Prehashed, hashes.HashAlgorithm], - ) -> None: - data, _ = _calculate_digest_and_algorithm(data, algorithm) - return _dsa_sig_verify(self._backend, self, signature, data) diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi index 9ab4e6c98cd6..82f30d20b0ab 100644 --- a/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +++ b/src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -6,6 +6,7 @@ import typing from cryptography.hazmat.bindings._rust.openssl import ( dh, + dsa, ed448, ed25519, hashes, @@ -20,6 +21,7 @@ __all__ = [ "openssl_version", "raise_openssl_error", "dh", + "dsa", "hashes", "hmac", "kdf", diff --git a/src/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi b/src/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi new file mode 100644 index 000000000000..5a56f256d52d --- /dev/null +++ b/src/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi @@ -0,0 +1,20 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives.asymmetric import dsa + +class DSAPrivateKey: ... +class DSAPublicKey: ... +class DSAParameters: ... + +def generate_parameters(key_size: int) -> dsa.DSAParameters: ... +def private_key_from_ptr(ptr: int) -> dsa.DSAPrivateKey: ... +def public_key_from_ptr(ptr: int) -> dsa.DSAPublicKey: ... +def from_private_numbers( + numbers: dsa.DSAPrivateNumbers, +) -> dsa.DSAPrivateKey: ... +def from_public_numbers(numbers: dsa.DSAPublicNumbers) -> dsa.DSAPublicKey: ... +def from_parameter_numbers( + numbers: dsa.DSAParameterNumbers, +) -> dsa.DSAParameters: ... diff --git a/src/cryptography/hazmat/primitives/asymmetric/dsa.py b/src/cryptography/hazmat/primitives/asymmetric/dsa.py index 1ebfcd52ad13..a8c52de4fb49 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/dsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -7,6 +7,7 @@ import abc import typing +from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives import _serialization, hashes from cryptography.hazmat.primitives.asymmetric import utils as asym_utils @@ -26,6 +27,7 @@ def parameter_numbers(self) -> DSAParameterNumbers: DSAParametersWithNumbers = DSAParameters +DSAParameters.register(rust_openssl.dsa.DSAParameters) class DSAPrivateKey(metaclass=abc.ABCMeta): @@ -77,6 +79,7 @@ def private_bytes( DSAPrivateKeyWithSerialization = DSAPrivateKey +DSAPrivateKey.register(rust_openssl.dsa.DSAPrivateKey) class DSAPublicKey(metaclass=abc.ABCMeta): @@ -128,6 +131,7 @@ def __eq__(self, other: object) -> bool: DSAPublicKeyWithSerialization = DSAPublicKey +DSAPublicKey.register(rust_openssl.dsa.DSAPublicKey) class DSAParameterNumbers: diff --git a/src/rust/src/backend/dh.rs b/src/rust/src/backend/dh.rs index b4dbaf5dded5..7f523c09e594 100644 --- a/src/rust/src/backend/dh.rs +++ b/src/rust/src/backend/dh.rs @@ -271,6 +271,7 @@ impl DHPrivateKey { format, encryption_algorithm, true, + false, ) } } @@ -302,7 +303,7 @@ impl DHPublicKey { )); } - utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, true) + utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, true, false) } fn parameters(&self) -> CryptographyResult { diff --git a/src/rust/src/backend/dsa.rs b/src/rust/src/backend/dsa.rs new file mode 100644 index 000000000000..59a5a676d5d5 --- /dev/null +++ b/src/rust/src/backend/dsa.rs @@ -0,0 +1,333 @@ +// 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::backend::utils; +use crate::error::{CryptographyError, CryptographyResult}; +use crate::exceptions; +use foreign_types_shared::ForeignTypeRef; + +#[pyo3::prelude::pyclass( + module = "cryptography.hazmat.bindings._rust.openssl.dsa", + name = "DSAPrivateKey" +)] +struct DsaPrivateKey { + pkey: openssl::pkey::PKey, +} + +#[pyo3::prelude::pyclass( + module = "cryptography.hazmat.bindings._rust.openssl.dsa", + name = "DSAPublicKey" +)] +struct DsaPublicKey { + pkey: openssl::pkey::PKey, +} + +#[pyo3::prelude::pyclass( + module = "cryptography.hazmat.bindings._rust.openssl.dsa", + name = "DSAParameters" +)] +struct DsaParameters { + dsa: openssl::dsa::Dsa, +} + +#[pyo3::prelude::pyfunction] +fn private_key_from_ptr(ptr: usize) -> DsaPrivateKey { + let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; + DsaPrivateKey { + pkey: pkey.to_owned(), + } +} + +#[pyo3::prelude::pyfunction] +fn public_key_from_ptr(ptr: usize) -> DsaPublicKey { + let pkey = unsafe { openssl::pkey::PKeyRef::from_ptr(ptr as *mut _) }; + DsaPublicKey { + pkey: pkey.to_owned(), + } +} + +#[pyo3::prelude::pyfunction] +fn generate_parameters(key_size: u32) -> CryptographyResult { + let dsa = openssl::dsa::Dsa::generate_params(key_size)?; + Ok(DsaParameters { dsa }) +} + +#[pyo3::prelude::pyfunction] +fn from_private_numbers( + py: pyo3::Python<'_>, + numbers: &pyo3::PyAny, +) -> CryptographyResult { + let public_numbers = numbers.getattr(pyo3::intern!(py, "public_numbers"))?; + let parameter_numbers = public_numbers.getattr(pyo3::intern!(py, "parameter_numbers"))?; + + let dsa = openssl::dsa::Dsa::from_private_components( + utils::py_int_to_bn(py, parameter_numbers.getattr(pyo3::intern!(py, "p"))?)?, + utils::py_int_to_bn(py, parameter_numbers.getattr(pyo3::intern!(py, "q"))?)?, + utils::py_int_to_bn(py, parameter_numbers.getattr(pyo3::intern!(py, "g"))?)?, + utils::py_int_to_bn(py, numbers.getattr(pyo3::intern!(py, "x"))?)?, + utils::py_int_to_bn(py, public_numbers.getattr(pyo3::intern!(py, "y"))?)?, + ) + .unwrap(); + let pkey = openssl::pkey::PKey::from_dsa(dsa)?; + Ok(DsaPrivateKey { pkey }) +} + +#[pyo3::prelude::pyfunction] +fn from_public_numbers( + py: pyo3::Python<'_>, + numbers: &pyo3::PyAny, +) -> CryptographyResult { + let parameter_numbers = numbers.getattr(pyo3::intern!(py, "parameter_numbers"))?; + + let dsa = openssl::dsa::Dsa::from_public_components( + utils::py_int_to_bn(py, parameter_numbers.getattr(pyo3::intern!(py, "p"))?)?, + utils::py_int_to_bn(py, parameter_numbers.getattr(pyo3::intern!(py, "q"))?)?, + utils::py_int_to_bn(py, parameter_numbers.getattr(pyo3::intern!(py, "g"))?)?, + utils::py_int_to_bn(py, numbers.getattr(pyo3::intern!(py, "y"))?)?, + ) + .unwrap(); + let pkey = openssl::pkey::PKey::from_dsa(dsa)?; + Ok(DsaPublicKey { pkey }) +} + +#[pyo3::prelude::pyfunction] +fn from_parameter_numbers( + py: pyo3::Python<'_>, + numbers: &pyo3::PyAny, +) -> CryptographyResult { + let dsa = openssl::dsa::Dsa::from_pqg( + utils::py_int_to_bn(py, numbers.getattr(pyo3::intern!(py, "p"))?)?, + utils::py_int_to_bn(py, numbers.getattr(pyo3::intern!(py, "q"))?)?, + utils::py_int_to_bn(py, numbers.getattr(pyo3::intern!(py, "g"))?)?, + ) + .unwrap(); + Ok(DsaParameters { dsa }) +} + +fn clone_dsa_params( + d: &openssl::dsa::Dsa, +) -> Result, openssl::error::ErrorStack> { + openssl::dsa::Dsa::from_pqg(d.p().to_owned()?, d.q().to_owned()?, d.g().to_owned()?) +} + +#[pyo3::prelude::pymethods] +impl DsaPrivateKey { + fn sign<'p>( + &self, + py: pyo3::Python<'p>, + data: &pyo3::types::PyBytes, + algorithm: &pyo3::PyAny, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + let (data, _): (&[u8], &pyo3::PyAny) = py + .import(pyo3::intern!( + py, + "cryptography.hazmat.backends.openssl.utils" + ))? + .call_method1( + pyo3::intern!(py, "_calculate_digest_and_algorithm"), + (data, algorithm), + )? + .extract()?; + + let mut signer = openssl::pkey_ctx::PkeyCtx::new(&self.pkey)?; + signer.sign_init()?; + let mut sig = vec![]; + signer.sign_to_vec(data, &mut sig)?; + Ok(pyo3::types::PyBytes::new(py, &sig)) + } + + #[getter] + fn key_size(&self) -> i32 { + self.pkey.dsa().unwrap().p().num_bits() + } + + fn public_key(&self) -> CryptographyResult { + let priv_dsa = self.pkey.dsa()?; + let pub_dsa = openssl::dsa::Dsa::from_public_components( + priv_dsa.p().to_owned()?, + priv_dsa.q().to_owned()?, + priv_dsa.g().to_owned()?, + priv_dsa.pub_key().to_owned()?, + ) + .unwrap(); + let pkey = openssl::pkey::PKey::from_dsa(pub_dsa)?; + Ok(DsaPublicKey { pkey }) + } + + fn parameters(&self) -> CryptographyResult { + let dsa = clone_dsa_params(&self.pkey.dsa().unwrap())?; + Ok(DsaParameters { dsa }) + } + + fn private_numbers<'p>(&self, py: pyo3::Python<'p>) -> CryptographyResult<&'p pyo3::PyAny> { + let dsa = self.pkey.dsa().unwrap(); + + let py_p = utils::bn_to_py_int(py, dsa.p())?; + let py_q = utils::bn_to_py_int(py, dsa.q())?; + let py_g = utils::bn_to_py_int(py, dsa.g())?; + + let py_pub_key = utils::bn_to_py_int(py, dsa.pub_key())?; + let py_private_key = utils::bn_to_py_int(py, dsa.priv_key())?; + + let dsa_mod = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.dsa" + ))?; + + let parameter_numbers = + dsa_mod.call_method1(pyo3::intern!(py, "DSAParameterNumbers"), (py_p, py_q, py_g))?; + let public_numbers = dsa_mod.call_method1( + pyo3::intern!(py, "DSAPublicNumbers"), + (py_pub_key, parameter_numbers), + )?; + + Ok(dsa_mod.call_method1( + pyo3::intern!(py, "DSAPrivateNumbers"), + (py_private_key, public_numbers), + )?) + } + + fn private_bytes<'p>( + slf: &pyo3::PyCell, + py: pyo3::Python<'p>, + encoding: &pyo3::PyAny, + format: &pyo3::PyAny, + encryption_algorithm: &pyo3::PyAny, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + utils::pkey_private_bytes( + py, + slf, + &slf.borrow().pkey, + encoding, + format, + encryption_algorithm, + true, + false, + ) + } +} + +#[pyo3::prelude::pymethods] +impl DsaPublicKey { + fn verify( + &self, + py: pyo3::Python<'_>, + signature: &[u8], + data: &pyo3::types::PyBytes, + algorithm: &pyo3::PyAny, + ) -> CryptographyResult<()> { + let (data, _): (&[u8], &pyo3::PyAny) = py + .import(pyo3::intern!( + py, + "cryptography.hazmat.backends.openssl.utils" + ))? + .call_method1( + pyo3::intern!(py, "_calculate_digest_and_algorithm"), + (data, algorithm), + )? + .extract()?; + + let mut verifier = openssl::pkey_ctx::PkeyCtx::new(&self.pkey)?; + verifier.verify_init()?; + let valid = verifier.verify(data, signature).unwrap_or(false); + if !valid { + return Err(CryptographyError::from( + exceptions::InvalidSignature::new_err(()), + )); + } + + Ok(()) + } + + #[getter] + fn key_size(&self) -> i32 { + self.pkey.dsa().unwrap().p().num_bits() + } + + fn parameters(&self) -> CryptographyResult { + let dsa = clone_dsa_params(&self.pkey.dsa().unwrap())?; + Ok(DsaParameters { dsa }) + } + + fn public_numbers<'p>(&self, py: pyo3::Python<'p>) -> CryptographyResult<&'p pyo3::PyAny> { + let dsa = self.pkey.dsa().unwrap(); + + let py_p = utils::bn_to_py_int(py, dsa.p())?; + let py_q = utils::bn_to_py_int(py, dsa.q())?; + let py_g = utils::bn_to_py_int(py, dsa.g())?; + + let py_pub_key = utils::bn_to_py_int(py, dsa.pub_key())?; + + let dsa_mod = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.dsa" + ))?; + + let parameter_numbers = + dsa_mod.call_method1(pyo3::intern!(py, "DSAParameterNumbers"), (py_p, py_q, py_g))?; + Ok(dsa_mod.call_method1( + pyo3::intern!(py, "DSAPublicNumbers"), + (py_pub_key, parameter_numbers), + )?) + } + + fn public_bytes<'p>( + slf: &pyo3::PyCell, + py: pyo3::Python<'p>, + encoding: &pyo3::PyAny, + format: &pyo3::PyAny, + ) -> CryptographyResult<&'p pyo3::types::PyBytes> { + utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, true, false) + } + + fn __richcmp__( + &self, + other: pyo3::PyRef<'_, DsaPublicKey>, + op: pyo3::basic::CompareOp, + ) -> pyo3::PyResult { + match op { + pyo3::basic::CompareOp::Eq => Ok(self.pkey.public_eq(&other.pkey)), + pyo3::basic::CompareOp::Ne => Ok(!self.pkey.public_eq(&other.pkey)), + _ => Err(pyo3::exceptions::PyTypeError::new_err("Cannot be ordered")), + } + } +} + +#[pyo3::prelude::pymethods] +impl DsaParameters { + fn generate_private_key(&self) -> CryptographyResult { + let dsa = clone_dsa_params(&self.dsa)?.generate_key()?; + let pkey = openssl::pkey::PKey::from_dsa(dsa)?; + Ok(DsaPrivateKey { pkey }) + } + + fn parameter_numbers<'p>(&self, py: pyo3::Python<'p>) -> CryptographyResult<&'p pyo3::PyAny> { + let py_p = utils::bn_to_py_int(py, self.dsa.p())?; + let py_q = utils::bn_to_py_int(py, self.dsa.q())?; + let py_g = utils::bn_to_py_int(py, self.dsa.g())?; + + let dsa_mod = py.import(pyo3::intern!( + py, + "cryptography.hazmat.primitives.asymmetric.dsa" + ))?; + + Ok(dsa_mod.call_method1(pyo3::intern!(py, "DSAParameterNumbers"), (py_p, py_q, py_g))?) + } +} + +pub(crate) fn create_module(py: pyo3::Python<'_>) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let m = pyo3::prelude::PyModule::new(py, "dsa")?; + m.add_function(pyo3::wrap_pyfunction!(private_key_from_ptr, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(public_key_from_ptr, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(generate_parameters, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_private_numbers, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_public_numbers, m)?)?; + m.add_function(pyo3::wrap_pyfunction!(from_parameter_numbers, m)?)?; + + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + + Ok(m) +} diff --git a/src/rust/src/backend/ed25519.rs b/src/rust/src/backend/ed25519.rs index 8cad193c7a92..7bee88104482 100644 --- a/src/rust/src/backend/ed25519.rs +++ b/src/rust/src/backend/ed25519.rs @@ -112,6 +112,7 @@ impl Ed25519PrivateKey { format, encryption_algorithm, true, + true, ) } } @@ -145,7 +146,7 @@ impl Ed25519PublicKey { encoding: &pyo3::PyAny, format: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, true) + utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, true, true) } fn __richcmp__( diff --git a/src/rust/src/backend/ed448.rs b/src/rust/src/backend/ed448.rs index 925a9fdb14f2..c0c621a321c3 100644 --- a/src/rust/src/backend/ed448.rs +++ b/src/rust/src/backend/ed448.rs @@ -110,6 +110,7 @@ impl Ed448PrivateKey { format, encryption_algorithm, true, + true, ) } } @@ -143,7 +144,7 @@ impl Ed448PublicKey { encoding: &pyo3::PyAny, format: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, true) + utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, true, true) } fn __richcmp__( diff --git a/src/rust/src/backend/mod.rs b/src/rust/src/backend/mod.rs index 970571193d15..765b0ab199f4 100644 --- a/src/rust/src/backend/mod.rs +++ b/src/rust/src/backend/mod.rs @@ -3,6 +3,7 @@ // for complete details. pub(crate) mod dh; +pub(crate) mod dsa; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] pub(crate) mod ed25519; #[cfg(all(not(CRYPTOGRAPHY_IS_LIBRESSL), not(CRYPTOGRAPHY_IS_BORINGSSL)))] @@ -19,6 +20,7 @@ pub(crate) mod x448; pub(crate) fn add_to_module(module: &pyo3::prelude::PyModule) -> pyo3::PyResult<()> { module.add_submodule(dh::create_module(module.py())?)?; + module.add_submodule(dsa::create_module(module.py())?)?; #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] module.add_submodule(ed25519::create_module(module.py())?)?; diff --git a/src/rust/src/backend/utils.rs b/src/rust/src/backend/utils.rs index 072a80f5f73d..dea36117182b 100644 --- a/src/rust/src/backend/utils.rs +++ b/src/rust/src/backend/utils.rs @@ -37,6 +37,7 @@ pub(crate) fn bn_to_big_endian_bytes(b: &openssl::bn::BigNumRef) -> Cryptography Ok(b.to_vec_padded(b.num_bits() / 8 + 1)?) } +#[allow(clippy::too_many_arguments)] pub(crate) fn pkey_private_bytes<'p>( py: pyo3::Python<'p>, key_obj: &pyo3::PyAny, @@ -45,6 +46,7 @@ pub(crate) fn pkey_private_bytes<'p>( format: &pyo3::PyAny, encryption_algorithm: &pyo3::PyAny, openssh_allowed: bool, + raw_allowed: bool, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { let serialization_mod = py.import(pyo3::intern!( py, @@ -89,8 +91,9 @@ pub(crate) fn pkey_private_bytes<'p>( } #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] - if encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) - || format.is(private_format_class.getattr(pyo3::intern!(py, "Raw"))?) + if raw_allowed + && (encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) + || format.is(private_format_class.getattr(pyo3::intern!(py, "Raw"))?)) { if !encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) || !format.is(private_format_class.getattr(pyo3::intern!(py, "Raw"))?) @@ -151,6 +154,33 @@ pub(crate) fn pkey_private_bytes<'p>( )); } + if format.is(private_format_class.getattr(pyo3::intern!(py, "TraditionalOpenSSL"))?) { + if let Ok(dsa) = pkey.dsa() { + if encoding.is(encoding_class.getattr(pyo3::intern!(py, "PEM"))?) { + let pem_bytes = if password.is_empty() { + dsa.private_key_to_pem()? + } else { + dsa.private_key_to_pem_passphrase( + openssl::symm::Cipher::aes_256_cbc(), + password, + )? + }; + return Ok(pyo3::types::PyBytes::new(py, &pem_bytes)); + } else if encoding.is(encoding_class.getattr(pyo3::intern!(py, "DER"))?) { + if !password.is_empty() { + return Err(CryptographyError::from( + pyo3::exceptions::PyValueError::new_err( + "Encryption is not supported for DER encoded traditional OpenSSL keys", + ), + )); + } + + let der_bytes = dsa.private_key_to_der()?; + return Ok(pyo3::types::PyBytes::new(py, &der_bytes)); + } + } + } + // OpenSSH + PEM if openssh_allowed && format.is(private_format_class.getattr(pyo3::intern!(py, "OpenSSH"))?) { if encoding.is(encoding_class.getattr(pyo3::intern!(py, "PEM"))?) { @@ -185,6 +215,7 @@ pub(crate) fn pkey_public_bytes<'p>( encoding: &pyo3::PyAny, format: &pyo3::PyAny, openssh_allowed: bool, + raw_allowed: bool, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { let serialization_mod = py.import(pyo3::intern!( py, @@ -213,8 +244,9 @@ pub(crate) fn pkey_public_bytes<'p>( } #[cfg(any(not(CRYPTOGRAPHY_IS_LIBRESSL), CRYPTOGRAPHY_LIBRESSL_370_OR_GREATER))] - if encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) - || format.is(public_format_class.getattr(pyo3::intern!(py, "Raw"))?) + if raw_allowed + && (encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) + || format.is(public_format_class.getattr(pyo3::intern!(py, "Raw"))?)) { if !encoding.is(encoding_class.getattr(pyo3::intern!(py, "Raw"))?) || !format.is(public_format_class.getattr(pyo3::intern!(py, "Raw"))?) diff --git a/src/rust/src/backend/x25519.rs b/src/rust/src/backend/x25519.rs index faf21ffddfe9..f27c0594ab3c 100644 --- a/src/rust/src/backend/x25519.rs +++ b/src/rust/src/backend/x25519.rs @@ -114,6 +114,7 @@ impl X25519PrivateKey { format, encryption_algorithm, false, + true, ) } } @@ -134,7 +135,7 @@ impl X25519PublicKey { encoding: &pyo3::PyAny, format: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, false) + utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, false, true) } fn __richcmp__( diff --git a/src/rust/src/backend/x448.rs b/src/rust/src/backend/x448.rs index 456e7fa52ab8..97e52ee6cc95 100644 --- a/src/rust/src/backend/x448.rs +++ b/src/rust/src/backend/x448.rs @@ -113,6 +113,7 @@ impl X448PrivateKey { format, encryption_algorithm, false, + true, ) } } @@ -133,7 +134,7 @@ impl X448PublicKey { encoding: &pyo3::PyAny, format: &pyo3::PyAny, ) -> CryptographyResult<&'p pyo3::types::PyBytes> { - utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, false) + utils::pkey_public_bytes(py, slf, &slf.borrow().pkey, encoding, format, false, true) } fn __richcmp__( diff --git a/src/rust/src/error.rs b/src/rust/src/error.rs index 689ae613e8bb..6699520cb397 100644 --- a/src/rust/src/error.rs +++ b/src/rust/src/error.rs @@ -74,13 +74,16 @@ impl From for pyo3::PyErr { .expect("Failed to append to list"); } exceptions::InternalError::new_err(( - "Unknown OpenSSL error. This error is commonly encountered + format!( + "Unknown OpenSSL error. This error is commonly encountered when another library is not cleaning up the OpenSSL error stack. If you are using cryptography with another library that uses OpenSSL try disabling it before reporting a bug. Otherwise please file an issue at https://github.com/pyca/cryptography/issues with - information on how to reproduce this.", + information on how to reproduce this. ({:?})", + errors + ), errors.to_object(py), )) }), diff --git a/tests/hazmat/primitives/test_dsa.py b/tests/hazmat/primitives/test_dsa.py index b97d7634396e..00920868fc65 100644 --- a/tests/hazmat/primitives/test_dsa.py +++ b/tests/hazmat/primitives/test_dsa.py @@ -395,6 +395,8 @@ def test_public_key_equality(self, backend): assert key1 == key2 assert key1 != key3 assert key1 != object() + with pytest.raises(TypeError): + key1 < key2 # type: ignore[operator] @pytest.mark.supported( @@ -711,6 +713,10 @@ def test_private_bytes_encrypted_pem(self, backend, fmt, password): (serialization.Encoding.DER, serialization.PrivateFormat.Raw), (serialization.Encoding.Raw, serialization.PrivateFormat.Raw), (serialization.Encoding.X962, serialization.PrivateFormat.PKCS8), + ( + serialization.Encoding.SMIME, + serialization.PrivateFormat.TraditionalOpenSSL, + ), ], ) def test_private_bytes_rejects_invalid(self, encoding, fmt, backend): diff --git a/tests/hazmat/primitives/test_x25519.py b/tests/hazmat/primitives/test_x25519.py index ae4f382bc487..2b86d3d5e22b 100644 --- a/tests/hazmat/primitives/test_x25519.py +++ b/tests/hazmat/primitives/test_x25519.py @@ -254,6 +254,13 @@ def test_invalid_private_bytes(self, backend): serialization.NoEncryption(), ) + with pytest.raises(ValueError): + key.private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.TraditionalOpenSSL, + serialization.NoEncryption(), + ) + def test_invalid_public_bytes(self, backend): key = X25519PrivateKey.generate().public_key() with pytest.raises(ValueError): diff --git a/tests/x509/test_x509_crlbuilder.py b/tests/x509/test_x509_crlbuilder.py index 8633f8abba22..95c0677bb777 100644 --- a/tests/x509/test_x509_crlbuilder.py +++ b/tests/x509/test_x509_crlbuilder.py @@ -524,6 +524,10 @@ def test_sign_with_invalid_hash_ed448(self, backend): with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256(), backend) + @pytest.mark.supported( + only_if=lambda backend: backend.dsa_supported(), + skip_message="Requires OpenSSL with DSA support", + ) def test_sign_dsa_key(self, backend): private_key = DSA_KEY_2048.private_key(backend) invalidity_date = x509.InvalidityDate( From 31436a486661cd863d4c77e40facf93fbb2d9f54 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 30 May 2023 11:32:57 +0900 Subject: [PATCH 314/316] admit to the existence of nuance in HKDF (#8987) * admit to the existence of nuance in HKDF * Update docs/hazmat/primitives/key-derivation-functions.rst Co-authored-by: Alex Gaynor --------- Co-authored-by: Alex Gaynor --- docs/hazmat/primitives/key-derivation-functions.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/hazmat/primitives/key-derivation-functions.rst b/docs/hazmat/primitives/key-derivation-functions.rst index ff9a5ba0ffe7..7c5c643e2218 100644 --- a/docs/hazmat/primitives/key-derivation-functions.rst +++ b/docs/hazmat/primitives/key-derivation-functions.rst @@ -460,7 +460,8 @@ HKDF to be secret, but may cause stronger security guarantees if secret; see :rfc:`5869` and the `HKDF paper`_ for more details. If ``None`` is explicitly passed a default salt of ``algorithm.digest_size // 8`` null - bytes will be used. + bytes will be used. See `understanding HKDF`_ for additional detail about + the salt and info parameters. :param bytes info: Application specific context information. If ``None`` is explicitly passed an empty byte string will be used. @@ -1037,3 +1038,4 @@ Interface .. _`here`: https://stackoverflow.com/a/30308723/1170681 .. _`recommends`: https://tools.ietf.org/html/rfc7914#section-2 .. _`The scrypt paper`: https://www.tarsnap.com/scrypt/scrypt.pdf +.. _`understanding HKDF`: https://soatok.blog/2021/11/17/understanding-hkdf/ From 8708245ccdeaff21d65eea68a4f8d2a7c5949a22 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 31 May 2023 05:45:23 +0900 Subject: [PATCH 315/316] new openssl day (#8990) --- .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 4f79786f3470..c0fe786454e4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,15 +28,15 @@ jobs: PYTHON: - {VERSION: "3.11", NOXSESSION: "flake"} - {VERSION: "3.11", NOXSESSION: "rust"} - - {VERSION: "3.11", NOXSESSION: "docs", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0"}} + - {VERSION: "3.11", NOXSESSION: "docs", OPENSSL: {TYPE: "openssl", VERSION: "3.1.1"}} - {VERSION: "pypy-3.8", NOXSESSION: "tests-nocoverage"} - {VERSION: "pypy-3.9", NOXSESSION: "tests-nocoverage"} - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1t"}} - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.0.8"}} - - {VERSION: "3.11", NOXSESSION: "tests-ssh", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0"}} - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct no-psk"}} - - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.1.0", CONFIG_FLAGS: "no-legacy", NO_LEGACY: "1"}} - - {VERSION: "3.11", NOXSESSION: "tests", NOXARGS: "--enable-fips=1", OPENSSL: {TYPE: "openssl", CONFIG_FLAGS: "enable-fips", VERSION: "3.1.0"}} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1u"}} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.0.9"}} + - {VERSION: "3.11", NOXSESSION: "tests-ssh", OPENSSL: {TYPE: "openssl", VERSION: "3.1.1"}} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.1.1", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct no-psk"}} + - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.1.1", CONFIG_FLAGS: "no-legacy", NO_LEGACY: "1"}} + - {VERSION: "3.11", NOXSESSION: "tests", NOXARGS: "--enable-fips=1", OPENSSL: {TYPE: "openssl", CONFIG_FLAGS: "enable-fips", VERSION: "3.1.1"}} - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.6.3"}} - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.7.3"}} - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "libressl", VERSION: "3.8.0"}} From c4d494fd3ee907316bd846e90cbf4a8df75a25ac Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 31 May 2023 06:33:32 +0900 Subject: [PATCH 316/316] 41.0.0 version bump (#8991) * 41.0.0 version bump * bust cache since we don't currently compute cache key including version --- .github/actions/cache/action.yml | 2 +- CHANGELOG.rst | 7 +++---- pyproject.toml | 2 +- src/cryptography/__about__.py | 2 +- vectors/cryptography_vectors/__about__.py | 2 +- vectors/pyproject.toml | 2 +- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/actions/cache/action.yml b/.github/actions/cache/action.yml index 6d254d398299..9b0c9271300d 100644 --- a/.github/actions/cache/action.yml +++ b/.github/actions/cache/action.yml @@ -47,7 +47,7 @@ runs: ~/.cargo/registry/cache/ src/rust/target/ ${{ inputs.additional-paths }} - key: cargo-pip-${{ runner.os }}-${{ runner.arch }}-${{ steps.normalized-key.outputs.key }}-5-${{ hashFiles('**/Cargo.lock', '**/*.rs') }}-${{ steps.rust-version.version }} + key: cargo-pip-${{ runner.os }}-${{ runner.arch }}-${{ steps.normalized-key.outputs.key }}-6-${{ hashFiles('**/Cargo.lock', '**/*.rs') }}-${{ steps.rust-version.version }} - name: Size of cache items run: | du -sh ~/.cargo/registry/index/ diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1811f801cbf5..95e2ab25c0d9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,16 +3,15 @@ Changelog .. _v41-0-0: -41.0.0 - `main`_ -~~~~~~~~~~~~~~~~ - -.. note:: This version is not yet released and is under active development. +41.0.0 - 2023-05-30 +~~~~~~~~~~~~~~~~~~~ * **BACKWARDS INCOMPATIBLE:** Support for OpenSSL less than 1.1.1d has been removed. Users on older version of OpenSSL will need to upgrade. * **BACKWARDS INCOMPATIBLE:** Support for Python 3.6 has been removed. * **BACKWARDS INCOMPATIBLE:** Dropped support for LibreSSL < 3.6. * Updated the minimum supported Rust version (MSRV) to 1.56.0, from 1.48.0. +* Updated Windows, macOS, and Linux wheels to be compiled with OpenSSL 3.1.1. * Added support for the :class:`~cryptography.x509.OCSPAcceptableResponses` OCSP extension. * Added support for the :class:`~cryptography.x509.MSCertificateTemplate` diff --git a/pyproject.toml b/pyproject.toml index 6f786bdb7e9a..c9de27381328 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ build-backend = "setuptools.build_meta" [project] name = "cryptography" -version = "41.0.0.dev1" +version = "41.0.0" authors = [ {name = "The Python Cryptographic Authority and individual contributors", email = "cryptography-dev@python.org"} ] diff --git a/src/cryptography/__about__.py b/src/cryptography/__about__.py index 5a31e0ff9a59..b66e23c606ba 100644 --- a/src/cryptography/__about__.py +++ b/src/cryptography/__about__.py @@ -10,7 +10,7 @@ "__copyright__", ] -__version__ = "41.0.0.dev1" +__version__ = "41.0.0" __author__ = "The Python Cryptographic Authority and individual contributors" diff --git a/vectors/cryptography_vectors/__about__.py b/vectors/cryptography_vectors/__about__.py index 24340ac421e4..6030fab339b0 100644 --- a/vectors/cryptography_vectors/__about__.py +++ b/vectors/cryptography_vectors/__about__.py @@ -6,4 +6,4 @@ "__version__", ] -__version__ = "41.0.0.dev1" +__version__ = "41.0.0" diff --git a/vectors/pyproject.toml b/vectors/pyproject.toml index f3da68b11abe..44d517f0560e 100644 --- a/vectors/pyproject.toml +++ b/vectors/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "cryptography_vectors" -version = "41.0.0.dev1" +version = "41.0.0" authors = [ {name = "The Python Cryptographic Authority and individual contributors", email = "cryptography-dev@python.org"} ]