diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000000..dab8975ebb06 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.pem text eol=lf diff --git a/.github/ISSUE_TEMPLATE.rst b/.github/ISSUE_TEMPLATE.rst index 2fb07b1b937b..011d571c9f19 100644 --- a/.github/ISSUE_TEMPLATE.rst +++ b/.github/ISSUE_TEMPLATE.rst @@ -12,3 +12,7 @@ your bug report: you're using * How you installed ``cryptography`` * Clear steps for reproducing your bug + +Please do not report security issues on Github! Follow the instructions in our +documentation for reporting security issues: +https://cryptography.io/en/latest/security/ diff --git a/.github/ISSUE_TEMPLATE/openssl-release.md b/.github/ISSUE_TEMPLATE/openssl-release.md index 6167739f16a5..336953722fb2 100644 --- a/.github/ISSUE_TEMPLATE/openssl-release.md +++ b/.github/ISSUE_TEMPLATE/openssl-release.md @@ -1,9 +1,7 @@ -- [ ] Windows - - [ ] Run the `openssl-release-1.1` Jenkins job - - [ ] Copy the resulting artifacts to the Windows builders and unzip them in the root of the file system -- [ ] macOS - - [ ] Send a pull request to `homebrew` upgrading the `openssl@1.1` formula +- [ ] Windows, macOS, `manylinux` + - [ ] Send a pull request to `pyca/infra` updating the [version and hash](https://github.com/pyca/infra/blob/master/cryptography-manylinux/openssl-version.sh) - [ ] Wait for it to be merged - - [ ] Run the `update-brew-openssl` Jenkins job -- [ ] manylinux1 - - [ ] Send a pull request to `pyca/infra` updating the [version and hash](https://github.com/pyca/infra/blob/master/cryptography-manylinux1/install_openssl.sh#L5-L6) + - [ ] Wait for the Github Actions job to complete +- [ ] Changelog entry +- [ ] Release +- [ ] Forward port changelog entry (if releasing from release branch) \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000000..123014908beb --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000000..b55266721e95 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,102 @@ +name: CI +on: + pull_request: {} + push: + branches: + - master + - '*.*.x' + tags: + - '*.*' + - '*.*.*' + +jobs: + macos: + runs-on: macos-latest + strategy: + matrix: + PYTHON: + - {VERSION: "2.7", TOXENV: "py27", EXTRA_CFLAGS: ""} + - {VERSION: "3.5", TOXENV: "py35", EXTRA_CFLAGS: ""} + - {VERSION: "3.9", TOXENV: "py39", EXTRA_CFLAGS: "-DUSE_OSRANDOM_RNG_FOR_TESTING"} + name: "Python ${{ matrix.PYTHON.VERSION }} on macOS" + steps: + - uses: actions/checkout@v2 + - name: Setup python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.PYTHON.VERSION }} + + - run: python -m pip install tox requests coverage + + - run: git clone https://github.com/google/wycheproof + + - name: Download OpenSSL + run: | + python .github/workflows/download_openssl.py macos openssl-macos + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Tests + run: | + CRYPTOGRAPHY_SUPPRESS_LINK_FLAGS=1 \ + LDFLAGS="${HOME}/openssl-macos/lib/libcrypto.a ${HOME}/openssl-macos/lib/libssl.a" \ + CFLAGS="-I${HOME}/openssl-macos/include -Werror -Wno-error=deprecated-declarations -Wno-error=incompatible-pointer-types-discards-qualifiers -Wno-error=unused-function -Wno-error=unused-command-line-argument -mmacosx-version-min=10.10 -march=core2 $EXTRA_CFLAGS" \ + tox -r -- --color=yes --wycheproof-root=wycheproof + env: + TOXENV: ${{ matrix.PYTHON.TOXENV }} + EXTRA_CFLAGS: ${{ matrix.PYTHON.EXTRA_CFLAGS }} + + - name: Upload coverage + run: | + curl -o codecov.sh -f https://codecov.io/bash || curl -o codecov.sh -f https://codecov.io/bash || curl -o codecov.sh -f https://codecov.io/bash + bash codecov.sh -n "Python ${{ matrix.PYTHON.VERSION }} on macOS" + + windows: + runs-on: windows-latest + strategy: + matrix: + WINDOWS: + - {ARCH: 'x86', WINDOWS: 'win32'} + - {ARCH: 'x64', WINDOWS: 'win64'} + PYTHON: + - {VERSION: "2.7", TOXENV: "py27", MSVC_VERSION: "2010", CL_FLAGS: ""} + - {VERSION: "3.5", TOXENV: "py35", MSVC_VERSION: "2019", CL_FLAGS: ""} + - {VERSION: "3.6", TOXENV: "py36", MSVC_VERSION: "2019", CL_FLAGS: ""} + - {VERSION: "3.7", TOXENV: "py37", MSVC_VERSION: "2019", CL_FLAGS: ""} + - {VERSION: "3.8", TOXENV: "py38", MSVC_VERSION: "2019", CL_FLAGS: ""} + - {VERSION: "3.9", TOXENV: "py39", MSVC_VERSION: "2019", CL_FLAGS: "/D USE_OSRANDOM_RNG_FOR_TESTING"} + name: "Python ${{ matrix.PYTHON.VERSION }} on ${{ matrix.WINDOWS.WINDOWS }}" + steps: + - uses: actions/checkout@v2 + - name: Setup python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.PYTHON.VERSION }} + architecture: ${{ matrix.WINDOWS.ARCH }} + + - name: Install MSVC for Python 2.7 + run: | + Invoke-WebRequest -Uri https://download.microsoft.com/download/7/9/6/796EF2E4-801B-4FC4-AB28-B59FBF6D907B/VCForPython27.msi -OutFile VCForPython27.msi + Start-Process msiexec -Wait -ArgumentList @('/i', 'VCForPython27.msi', '/qn', 'ALLUSERS=1') + Remove-Item VCForPython27.msi -Force + shell: powershell + if: matrix.PYTHON.VERSION == '2.7' + - run: python -m pip install tox requests coverage + - name: Download OpenSSL + run: | + python .github/workflows/download_openssl.py windows openssl-${{ matrix.WINDOWS.WINDOWS }}-${{ matrix.PYTHON.MSVC_VERSION }} + echo "INCLUDE=C:/openssl-${{ matrix.WINDOWS.WINDOWS }}-${{ matrix.PYTHON.MSVC_VERSION }}/include;$INCLUDE" >> $GITHUB_ENV + echo "LIB=C:/openssl-${{ matrix.WINDOWS.WINDOWS }}-${{ matrix.PYTHON.MSVC_VERSION }}/lib;$LIB" >> $GITHUB_ENV + echo "CL=${{ matrix.PYTHON.CL_FLAGS }}" >> $GITHUB_ENV + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + shell: bash + - run: git clone https://github.com/google/wycheproof + + - run: tox -r -- --color=yes --wycheproof-root=wycheproof + env: + TOXENV: ${{ matrix.PYTHON.TOXENV }} + + - name: Upload coverage + run: | + curl -o codecov.sh -f https://codecov.io/bash || curl -o codecov.sh -f https://codecov.io/bash || curl -o codecov.sh -f https://codecov.io/bash + bash codecov.sh -n "Python ${{ matrix.PYTHON.VERSION }} on ${{ matrix.WINDOWS.WINDOWS }}" diff --git a/.github/workflows/download_openssl.py b/.github/workflows/download_openssl.py new file mode 100644 index 000000000000..1d5e3bfb471a --- /dev/null +++ b/.github/workflows/download_openssl.py @@ -0,0 +1,73 @@ +import io +import os +import sys +import time +import zipfile + +import requests + +from urllib3.util.retry import Retry + + +def get_response(session, url, token): + # Retry on non-502s + for i in range(5): + response = session.get( + url, headers={"Authorization": "token " + token} + ) + if response.status_code != 200: + print( + "HTTP error ({}) fetching {}, retrying".format( + response.status_code, url + ) + ) + time.sleep(2) + continue + return response + response = session.get(url, headers={"Authorization": "token " + token}) + if response.status_code != 200: + raise ValueError( + "Got HTTP {} fetching {}: ".format(response.status_code, url) + ) + return response + + +def main(platform, target): + if platform == "windows": + workflow = "build-windows-openssl.yml" + path = "C:/" + elif platform == "macos": + workflow = "build-macos-openssl.yml" + path = os.environ["HOME"] + else: + raise ValueError("Invalid platform") + + session = requests.Session() + adapter = requests.adapters.HTTPAdapter(max_retries=Retry()) + session.mount("https://", adapter) + session.mount("http://", adapter) + + token = os.environ["GITHUB_TOKEN"] + print("Looking for: {}".format(target)) + runs_url = ( + "https://api.github.com/repos/pyca/infra/actions/workflows/" + "{}/runs?branch=master&status=success".format(workflow) + ) + + response = get_response(session, runs_url, token).json() + artifacts_url = response["workflow_runs"][0]["artifacts_url"] + response = get_response(session, artifacts_url, token).json() + for artifact in response["artifacts"]: + if artifact["name"] == target: + print("Found artifact") + response = get_response( + session, artifact["archive_download_url"], token + ) + zipfile.ZipFile(io.BytesIO(response.content)).extractall( + os.path.join(path, artifact["name"]) + ) + return + + +if __name__ == "__main__": + main(sys.argv[1], sys.argv[2]) diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml new file mode 100644 index 000000000000..7356bd4af3f9 --- /dev/null +++ b/.github/workflows/lock.yml @@ -0,0 +1,14 @@ +name: Lock Issues +on: + schedule: + - cron: '0 0 * * *' + +jobs: + lock: + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@v2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + issue-lock-inactive-days: 90 + pr-lock-inactive-days: 90 diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml new file mode 100644 index 000000000000..74012f09b53a --- /dev/null +++ b/.github/workflows/wheel-builder.yml @@ -0,0 +1,165 @@ +name: Wheel Builder +on: + workflow_dispatch: + inputs: + version: + required: true + +jobs: + manylinux: + runs-on: ubuntu-latest + container: ${{ matrix.MANYLINUX.CONTAINER }} + strategy: + matrix: + PYTHON: ["cp27-cp27m", "cp27-cp27mu", "cp35-cp35m"] + MANYLINUX: + - NAME: manylinux1_x86_64 + CONTAINER: "pyca/cryptography-manylinux1:x86_64" + - NAME: manylinux2010_x86_64 + CONTAINER: "pyca/cryptography-manylinux2010:x86_64" + name: "${{ matrix.PYTHON }} for ${{ matrix.MANYLINUX.NAME }}" + steps: + - run: /opt/python/${{ matrix.PYTHON }}/bin/python -m virtualenv .venv + - name: Install Python dependencies + run: .venv/bin/pip install -U pip wheel cffi six ipaddress "enum34; python_version < '3'" + - run: .venv/bin/pip download cryptography==${{ github.event.inputs.version }} --no-deps --no-binary cryptography && tar zxvf cryptography*.tar.gz && mkdir tmpwheelhouse + - run: | + REGEX="cp3([0-9])*" + if [[ "${{ matrix.PYTHON }}" =~ $REGEX ]]; then + PY_LIMITED_API="--py-limited-api=cp3${BASH_REMATCH[1]}" + fi + cd cryptography* + LDFLAGS="-L/opt/pyca/cryptography/openssl/lib" \ + CFLAGS="-I/opt/pyca/cryptography/openssl/include -Wl,--exclude-libs,ALL" \ + ../.venv/bin/python setup.py bdist_wheel $PY_LIMITED_API && mv dist/cryptography*.whl ../tmpwheelhouse + - run: auditwheel repair --plat ${{ matrix.MANYLINUX.NAME }} tmpwheelhouse/cryptograph*.whl -w wheelhouse/ + - run: unzip wheelhouse/*.whl -d execstack.check + - run: | + results=$(execstack execstack.check/cryptography/hazmat/bindings/*.so) + count=$(echo "$results" | grep -c '^X' || true) + if [ "$count" -ne 0 ]; then + exit 1 + else + exit 0 + fi + - run: .venv/bin/pip install cryptography --no-index -f wheelhouse/ + - run: | + .venv/bin/python -c "from cryptography.hazmat.backends.openssl.backend import backend;print('Loaded: ' + backend.openssl_version_text());print('Linked Against: ' + backend._ffi.string(backend._lib.OPENSSL_VERSION_TEXT).decode('ascii'))" + - run: mkdir cryptography-wheelhouse + - run: mv wheelhouse/cryptography*.whl cryptography-wheelhouse/ + - uses: actions/upload-artifact@v2.2.0 + with: + name: "cryptography-${{ github.event.inputs.version }}-${{ matrix.MANYLINUX.NAME }}-${{ matrix.PYTHON }}" + path: cryptography-wheelhouse/ + + macos: + runs-on: macos-latest + strategy: + matrix: + PYTHON: + - VERSION: '2.7' + ABI_VERSION: '2.7' + DOWNLOAD_URL: 'https://www.python.org/ftp/python/2.7.17/python-2.7.17-macosx10.9.pkg' + BIN_PATH: '/Library/Frameworks/Python.framework/Versions/2.7/bin/python' + - VERSION: '3.8' + ABI_VERSION: '3.5' + DOWNLOAD_URL: 'https://www.python.org/ftp/python/3.8.2/python-3.8.2-macosx10.9.pkg' + BIN_PATH: '/Library/Frameworks/Python.framework/Versions/3.8/bin/python3' + name: "${{ matrix.PYTHON.VERSION }} ABI ${{ matrix.PYTHON.ABI_VERSION }} macOS" + steps: + - uses: actions/checkout@v2 + - run: | + curl "$PYTHON_DOWNLOAD_URL" -o python.pkg + sudo installer -pkg python.pkg -target / + env: + PYTHON_DOWNLOAD_URL: ${{ matrix.PYTHON.DOWNLOAD_URL }} + - run: ${{ matrix.PYTHON.BIN_PATH }} -m pip install -U virtualenv requests + - name: Download OpenSSL + run: | + ${{ matrix.PYTHON.BIN_PATH }} .github/workflows/download_openssl.py macos openssl-macos + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - run: ${{ matrix.PYTHON.BIN_PATH }} -m virtualenv venv + - run: venv/bin/pip install -U pip wheel cffi six ipaddress "enum34; python_version < '3'" + - run: venv/bin/pip download cryptography==${{ github.event.inputs.version }} --no-deps --no-binary cryptography && tar zxvf cryptography*.tar.gz && mkdir wheelhouse + - name: Build the wheel + run: | + REGEX="3\.([0-9])*" + if [[ "${{ matrix.PYTHON.ABI_VERSION }}" =~ $REGEX ]]; then + PY_LIMITED_API="--py-limited-api=cp3${BASH_REMATCH[1]}" + fi + + cd cryptography* + CRYPTOGRAPHY_SUPPRESS_LINK_FLAGS="1" \ + LDFLAGS="${HOME}/openssl-macos/lib/libcrypto.a ${HOME}/openssl-macos/lib/libssl.a" \ + CFLAGS="-I${HOME}/openssl-macos/include -mmacosx-version-min=10.10 -march=core2" \ + ../venv/bin/python setup.py bdist_wheel $PY_LIMITED_API && mv dist/cryptography*.whl ../wheelhouse + - run: venv/bin/pip install -f wheelhouse --no-index cryptography + - run: | + venv/bin/python -c "from cryptography.hazmat.backends.openssl.backend import backend;print('Loaded: ' + backend.openssl_version_text());print('Linked Against: ' + backend._ffi.string(backend._lib.OPENSSL_VERSION_TEXT).decode('ascii'))" + + - run: mkdir cryptography-wheelhouse + - run: mv wheelhouse/cryptography*.whl cryptography-wheelhouse/ + - uses: actions/upload-artifact@v2.2.0 + with: + name: "cryptography-${{ github.event.inputs.version }}-macOS-${{ matrix.PYTHON.ABI_VERSION }}" + path: cryptography-wheelhouse/ + + windows: + runs-on: windows-latest + strategy: + matrix: + WINDOWS: + - {ARCH: 'x86', WINDOWS: 'win32'} + - {ARCH: 'x64', WINDOWS: 'win64'} + PYTHON: + - {VERSION: "2.7", MSVC_VERSION: "2010"} + - {VERSION: "3.5", MSVC_VERSION: "2019"} + - {VERSION: "3.6", MSVC_VERSION: "2019"} + - {VERSION: "3.7", MSVC_VERSION: "2019"} + - {VERSION: "3.8", MSVC_VERSION: "2019"} + - {VERSION: "3.8", MSVC_VERSION: "2019", "USE_ABI3": "true", "ABI_VERSION": "cp36"} + name: "${{ matrix.PYTHON.VERSION }} ${{ matrix.WINDOWS.WINDOWS }} ${{ matrix.PYTHON.ABI_VERSION }}" + steps: + - uses: actions/checkout@v2 + - name: Setup python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.PYTHON.VERSION }} + architecture: ${{ matrix.WINDOWS.ARCH }} + - name: Install MSVC for Python 2.7 + run: | + Invoke-WebRequest -Uri https://download.microsoft.com/download/7/9/6/796EF2E4-801B-4FC4-AB28-B59FBF6D907B/VCForPython27.msi -OutFile VCForPython27.msi + Start-Process msiexec -Wait -ArgumentList @('/i', 'VCForPython27.msi', '/qn', 'ALLUSERS=1') + Remove-Item VCForPython27.msi -Force + shell: powershell + if: matrix.PYTHON.VERSION == '2.7' + - run: pip install requests + - name: Download OpenSSL + run: | + python .github/workflows/download_openssl.py windows openssl-${{ matrix.WINDOWS.WINDOWS }}-${{ matrix.PYTHON.MSVC_VERSION }} + echo "INCLUDE=C:/openssl-${{ matrix.WINDOWS.WINDOWS }}-${{ matrix.PYTHON.MSVC_VERSION }}/include;$INCLUDE" >> $GITHUB_ENV + echo "LIB=C:/openssl-${{ matrix.WINDOWS.WINDOWS }}-${{ matrix.PYTHON.MSVC_VERSION }}/lib;$LIB" >> $GITHUB_ENV + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + shell: bash + + - run: python -m pip install -U pip wheel cffi six ipaddress "enum34; python_version < '3'" + - run: pip download cryptography==${{ github.event.inputs.version }} --no-deps --no-binary cryptography && tar zxvf cryptography*.tar.gz && mkdir wheelhouse + shell: bash + - run: cd cryptography* && python setup.py bdist_wheel && mv dist/cryptography*.whl ../wheelhouse + if: matrix.PYTHON.USE_ABI3 != 'true' + - run: cd cryptography* && python setup.py bdist_wheel --py-limited-api=${{ matrix.PYTHON.ABI_VERSION }} && mv dist/cryptography*.whl ../wheelhouse + if: matrix.PYTHON.USE_ABI3 == 'true' + - run: pip install -f wheelhouse --no-index cryptography + - name: Print the OpenSSL we built and linked against + run: | + python -c "from cryptography.hazmat.backends.openssl.backend import backend;print('Loaded: ' + backend.openssl_version_text());print('Linked Against: ' + backend._ffi.string(backend._lib.OPENSSL_VERSION_TEXT).decode('ascii'))" + + - run: mkdir cryptography-wheelhouse + - run: move wheelhouse\cryptography*.whl cryptography-wheelhouse\ + - uses: actions/upload-artifact@v2.2.0 + with: + name: "cryptography-${{ github.event.inputs.version }}-${{ matrix.WINDOWS.WINDOWS }}-${{ matrix.PYTHON.VERSION }}-${{ matrix.PYTHON.ABI_VERSION}}" + path: cryptography-wheelhouse\ diff --git a/.jenkins/Jenkinsfile-OpenSSL-1.1 b/.jenkins/Jenkinsfile-OpenSSL-1.1 deleted file mode 100644 index 62ec956001c9..000000000000 --- a/.jenkins/Jenkinsfile-OpenSSL-1.1 +++ /dev/null @@ -1,86 +0,0 @@ -def configs = [ - [ - label: "windows2012-openssl", arch: "x86", "vsversion": 2010 - ], - [ - label: "windows2012-openssl", arch: "x86_64", "vsversion": 2010 - ], - [ - label: "windows2012-openssl", arch: "x86", "vsversion": 2015 - ], - [ - label: "windows2012-openssl", arch: "x86_64", "vsversion": 2015 - ], -] - -script = """ - wmic qfe - powershell "[Net.ServicePointManager]::SecurityProtocol = 'tls12'; wget 'https://www.openssl.org/source/openssl-1.1.1-latest.tar.gz' -OutFile 'openssl-latest.tar.gz'" - REM Next decompress the tarball using winrar. INUL disables error msgs, which are GUI prompts and therefore undesirable - "C:\\Program Files\\WinRAR\\WinRAR.exe" -INUL x openssl-latest.tar.gz - cd openssl-1* - REM The next line determines the name of the current directory. Batch is great. - FOR %%I IN (.) DO @SET CURRENTDIR=%%~nI%%~xI - if "%BUILDARCH%" == "x86" ( - @SET BUILDARCHFLAG=x86 - @SET OPENSSLARCHFLAG="VC-WIN32" - ) else ( - @SET BUILDARCHFLAG=amd64 - @SET OPENSSLARCHFLAG="VC-WIN64A" - ) - if "%BUILDVSVERSION%" == "2010" ( - call "C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\vcvarsall.bat" %BUILDARCHFLAG% - echo "Building with VS 2010" - ) else ( - call "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat" %BUILDARCHFLAG% - echo "Building with VS 2015" - ) - SET - perl Configure no-comp no-shared %OPENSSLARCHFLAG% - nmake - nmake test - - if "%BUILDARCH%" == "x86" ( - @SET FINALDIR="openssl-win32-%BUILDVSVERSION%" - ) else ( - @SET FINALDIR="openssl-win64-%BUILDVSVERSION%" - ) - mkdir %FINALDIR% - mkdir %FINALDIR%\\lib - move include %FINALDIR%\\include - move libcrypto.lib %FINALDIR%\\lib\\ - move libssl.lib %FINALDIR%\\lib\\ - "C:\\Program Files\\WinRAR\\WinRAR.exe" -INUL a %CURRENTDIR%-%BUILDVSVERSION%-%BUILDARCH%.zip %FINALDIR%\\include %FINALDIR%\\lib\\libcrypto.lib %FINALDIR%\\lib\\libssl.lib -""" - -def build(label, vsversion, arch) { - node(label) { - try { - timeout(time: 30, unit: 'MINUTES') { - stage("Compile") { - withEnv(["BUILDARCH=$arch", "BUILDVSVERSION=$vsversion"]) { - bat script - } - } - stage("Archive") { - archiveArtifacts artifacts: "**/openssl-*.zip" - } - } - } finally { - deleteDir() - } - } -} - -def builders = [:] - -for (config in configs) { - def vsversion = config["vsversion"] - def arch = config["arch"] - def label = config["label"] - builders["${vsversion}-${arch}"] = { - build(label, vsversion, arch) - } -} - -parallel builders diff --git a/.jenkins/Jenkinsfile-Update-Homebrew-OpenSSL b/.jenkins/Jenkinsfile-Update-Homebrew-OpenSSL deleted file mode 100644 index 75beee82afeb..000000000000 --- a/.jenkins/Jenkinsfile-Update-Homebrew-OpenSSL +++ /dev/null @@ -1,33 +0,0 @@ -def configs = ["sierra", "yosemite"] - -def _build(label) { - node(label) { - try { - timeout(time: 30, unit: 'MINUTES') { - stage("Compile") { - sh """ - set -xe - - /usr/local/bin/brew update - /usr/local/bin/brew reinstall openssl@1.1 --build-bottle - """ - } - } - } finally { - deleteDir() - } - } -} - -def builders = [:] - -for (_label in configs) { - def label = _label - builders[label] = { - _build(label) - } -} - -parallel builders - -build job: 'pyca/cryptography/master', wait: false diff --git a/.jenkins/Jenkinsfile-cryptography-wheel-builder b/.jenkins/Jenkinsfile-cryptography-wheel-builder deleted file mode 100644 index 5f98276ca467..000000000000 --- a/.jenkins/Jenkinsfile-cryptography-wheel-builder +++ /dev/null @@ -1,203 +0,0 @@ -properties([ - parameters([ - string(defaultValue: '', description: 'The version from PyPI to build', name: 'BUILD_VERSION') - ]), - pipelineTriggers([]) -]) - -def configs = [ - [ - label: 'windows', - versions: ['py27', 'py34', 'py35', 'py36', 'py37'], - ], - [ - label: 'windows64', - versions: ['py27', 'py34', 'py35', 'py36', 'py37'], - ], - [ - label: 'sierra', - // The py3x version listed here corresponds to the minimum ABI version - // the wheels will support. e.g. py34 supports py34+ - versions: ['py27', 'py34'], - ], - [ - label: 'docker', - imageName: 'pyca/cryptography-manylinux1:i686', - // The py3x version listed here corresponds to the minimum ABI version - // the wheels will support. e.g. cp34-cp34m supports py34+ - versions: [ - 'cp27-cp27m', 'cp27-cp27mu', 'cp34-cp34m', - ], - ], - [ - label: 'docker', - imageName: 'pyca/cryptography-manylinux1:x86_64', - // The py3x version listed here corresponds to the minimum ABI version - // the wheels will support. e.g. cp34-cp34m supports py34+ - versions: [ - 'cp27-cp27m', 'cp27-cp27mu', 'cp34-cp34m', - ], - ], -] - - -def build(version, label, imageName) { - try { - timeout(time: 30, unit: 'MINUTES') { - if (label.contains("windows")) { - def pythonPath = [ - py27: "C:\\Python27\\python.exe", - py34: "C:\\Python34\\python.exe", - py35: "C:\\Python35\\python.exe", - py36: "C:\\Python36\\python.exe", - py37: "C:\\Python37\\python.exe" - ] - if (version == "py35" || version == "py36" || version == "py37") { - opensslPaths = [ - "windows": [ - "include": "C:\\OpenSSL-Win32-2015\\include", - "lib": "C:\\OpenSSL-Win32-2015\\lib" - ], - "windows64": [ - "include": "C:\\OpenSSL-Win64-2015\\include", - "lib": "C:\\OpenSSL-Win64-2015\\lib" - ] - ] - } else { - opensslPaths = [ - "windows": [ - "include": "C:\\OpenSSL-Win32-2010\\include", - "lib": "C:\\OpenSSL-Win32-2010\\lib" - ], - "windows64": [ - "include": "C:\\OpenSSL-Win64-2010\\include", - "lib": "C:\\OpenSSL-Win64-2010\\lib" - ] - ] - } - bat """ - wmic qfe - @set PATH="C:\\Python27";"C:\\Python27\\Scripts";%PATH% - @set PYTHON="${pythonPath[version]}" - - @set INCLUDE="${opensslPaths[label]['include']}";%INCLUDE% - @set LIB="${opensslPaths[label]['lib']}";%LIB% - virtualenv -p %PYTHON% .release - call .release\\Scripts\\activate - pip install wheel virtualenv - pip wheel cryptography==$BUILD_VERSION --wheel-dir=wheelhouse --no-binary cryptography - pip install -f wheelhouse cryptography --no-index - python -c "from cryptography.hazmat.backends.openssl.backend import backend;print('Loaded: ' + backend.openssl_version_text());print('Linked Against: ' + backend._ffi.string(backend._lib.OPENSSL_VERSION_TEXT).decode('ascii'))" - """ - } else if (label.contains("sierra")) { - def pythonPath = [ - py27: "/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7", - py34: "/Library/Frameworks/Python.framework/Versions/3.4/bin/python3.4", - ] - ansiColor { - sh """#!/usr/bin/env bash - set -xe - # output the list of things we've installed as a point in time check of how up - # to date the builder is - /usr/sbin/system_profiler SPInstallHistoryDataType - - # Jenkins logs in as a non-interactive shell, so we don't even have /usr/local/bin in PATH - export PATH="/usr/local/bin:\${PATH}" - export PATH="/Users/jenkins/.pyenv/shims:\${PATH}" - - printenv - - virtualenv .venv -p ${pythonPath[version]} - source .venv/bin/activate - pip install -U wheel # upgrade wheel to latest before we use it to build the wheel - pip install cffi six idna asn1crypto ipaddress enum34 - REGEX="py3([0-9])*" - if [[ "${version}" =~ \$REGEX ]]; then - PY_LIMITED_API="--build-option --py-limited-api=cp3\${BASH_REMATCH[1]}" - fi - CRYPTOGRAPHY_SUPPRESS_LINK_FLAGS="1" \ - LDFLAGS="/usr/local/opt/openssl@1.1/lib/libcrypto.a /usr/local/opt/openssl@1.1/lib/libssl.a" \ - CFLAGS="-I/usr/local/opt/openssl@1.1/include -mmacosx-version-min=10.9" \ - pip wheel cryptography==$BUILD_VERSION --wheel-dir=wheelhouse --no-binary cryptography --no-deps \$PY_LIMITED_API - pip install -f wheelhouse cryptography --no-index - python -c "from cryptography.hazmat.backends.openssl.backend import backend;print('Loaded: ' + backend.openssl_version_text());print('Linked Against: ' + backend._ffi.string(backend._lib.OPENSSL_VERSION_TEXT).decode('ascii'))" - otool -L `find .venv -name '_openssl*.so'` - lipo -info `find .venv -name '*.so'` - otool -L `find .venv -name '_openssl*.so'` | grep -vG "libcrypto\\|libssl" - """ - } - } else if (label.contains("docker")) { - linux32 = "" - if (imageName.contains("i686")) { - linux32 = "linux32" - } - sh """#!/usr/bin/env bash - set -x -e - - $linux32 /opt/python/$version/bin/pip install cffi six idna asn1crypto ipaddress enum34 - # Because we are doing this as root in the container, but we write to a mounted dir that is outside the container - # we need to make sure we set these files writable such that the jenkins user can delete them afterwards - mkdir -p tmpwheelhouse - mkdir -p wheelhouse - chmod -R 777 tmpwheelhouse - chmod -R 777 wheelhouse - - REGEX="cp3([0-9])*" - if [[ "${version}" =~ \$REGEX ]]; then - PY_LIMITED_API="--build-option --py-limited-api=cp3\${BASH_REMATCH[1]}" - fi - LDFLAGS="-L/opt/pyca/cryptography/openssl/lib" \ - CFLAGS="-I/opt/pyca/cryptography/openssl/include -Wl,--exclude-libs,ALL" \ - $linux32 /opt/python/$version/bin/pip wheel cryptography==$BUILD_VERSION --no-binary cryptography --no-deps --wheel-dir=tmpwheelhouse \$PY_LIMITED_API - $linux32 auditwheel repair tmpwheelhouse/cryptography*.whl -w wheelhouse/ - unzip wheelhouse/*.whl -d execstack.check - chmod -R 777 execstack.check - (execstack execstack.check/cryptography/hazmat/bindings/*.so | grep '^X') && exit 1 - $linux32 /opt/python/$version/bin/pip install cryptography==$BUILD_VERSION --no-index -f wheelhouse/ - $linux32 /opt/python/$version/bin/python -c "from cryptography.hazmat.backends.openssl.backend import backend;print('Loaded: ' + backend.openssl_version_text());print('Linked Against: ' + backend._ffi.string(backend._lib.OPENSSL_VERSION_TEXT).decode('ascii'))" - """ - } - archiveArtifacts artifacts: "wheelhouse/cryptography*.whl" - } - } finally { - deleteDir() - } - -} - -def builders = [:] -for (config in configs) { - def label = config["label"] - def versions = config["versions"] - - for (_version in versions) { - def version = _version - - if (label.contains("docker")) { - def imageName = config["imageName"] - def combinedName = "${imageName}-${version}" - builders[combinedName] = { - node(label) { - stage(combinedName) { - def buildImage = docker.image(imageName) - buildImage.pull() - buildImage.inside("-u root") { - build(version, label, imageName) - } - } - } - } - } else { - def combinedName = "${label}-${version}" - builders[combinedName] = { - node(label) { - stage(combinedName) { - build(version, label, "") - } - } - } - } - } -} - -parallel builders diff --git a/.travis.yml b/.travis.yml index 7ed660a8e975..b0f0fe78d6e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ sudo: true -dist: xenial +dist: focal language: python @@ -13,65 +13,61 @@ cache: branches: only: - master - - /\d+\.\d+\.x/ - - /\d+\.\d+(\.\d+)?/ + - /^\d+\.\d+\.x$/ + - /^\d+\.\d+(\.\d+)?$/ matrix: include: - # these are just to make travis's UI a bit prettier - - python: 2.7 - env: TOXENV=py27 - - python: 3.4 - env: TOXENV=py34 - - python: 3.5 - env: TOXENV=py35 + - python: 3.8 + env: TOXENV=pep8,packaging + # Setting 'python' is just to make travis's UI a bit prettier - python: 3.6 env: TOXENV=py36 - - python: 3.7 - env: TOXENV=py37 - - python: 3.7 - env: TOXENV=py37-idna - - python: pypy-5.4 - env: TOXENV=pypy-nocoverage - # PyPy 5.4 isn't available for xenial - dist: trusty - - python: pypy2.7-5.10.0 + - python: 3.9-dev + env: TOXENV=py39 + # Travis lists available Pythons (including PyPy) by arch and distro here: + # https://docs.travis-ci.com/user/languages/python/#python-versions + - python: pypy2.7-7.3.1 env: TOXENV=pypy-nocoverage - - python: pypy3.5-5.10.1 + - python: pypy3.6-7.3.1 env: TOXENV=pypy3-nocoverage - - python: 2.7 - env: TOXENV=py27 OPENSSL=1.0.1u - - python: 3.7 - env: TOXENV=py37 OPENSSL=1.0.1u - - python: 2.7 - env: TOXENV=py27 OPENSSL=1.1.0j - - python: 3.5 - env: TOXENV=py35 OPENSSL=1.1.0j - - python: 2.7 - env: TOXENV=py27 OPENSSL=1.1.1a - - python: 3.7 - env: TOXENV=py37 OPENSSL=1.1.1a - - python: 3.7 - env: TOXENV=py37 LIBRESSL=2.6.5 - - python: 3.7 - env: TOXENV=py37 LIBRESSL=2.7.5 - - python: 3.7 - env: TOXENV=py37 LIBRESSL=2.8.3 - - python: 3.7 - env: TOXENV=py37 LIBRESSL=2.9.0 + - python: 3.8 + env: TOXENV=py38 OPENSSL=1.0.2u + - python: 2.7 + env: TOXENV=py27 OPENSSL=1.1.0l + - python: 2.7 + env: TOXENV=py27-ssh OPENSSL=1.1.0l + - python: 3.8 + env: TOXENV=py38 OPENSSL=1.1.0l + - python: 2.7 + env: TOXENV=py27 OPENSSL=1.1.1h + - python: 3.8 + env: TOXENV=py38 OPENSSL=1.1.1h + - python: 3.8 + env: TOXENV=py38 OPENSSL=1.1.1h OPENSSL_CONFIG_FLAGS="no-engine no-rc2 no-srtp no-ct" + - python: 3.8 + env: TOXENV=py38-ssh OPENSSL=1.1.1h + - python: 3.8 + env: TOXENV=py38 LIBRESSL=2.9.2 + - python: 3.8 + env: TOXENV=py38 LIBRESSL=3.0.2 + - python: 3.8 + env: TOXENV=py38 LIBRESSL=3.1.4 + - python: 3.8 + env: TOXENV=py38 LIBRESSL=3.2.2 - python: 2.7 services: docker env: TOXENV=py27 DOCKER=pyca/cryptography-runner-centos7 - python: 2.7 services: docker - env: TOXENV=py27 DOCKER=pyca/cryptography-runner-wheezy - - python: 2.7 + env: TOXENV=py27 DOCKER=pyca/cryptography-runner-centos8 + - python: 3.6 services: docker - env: TOXENV=py27 DOCKER=pyca/cryptography-runner-jessie - - python: 3.4 + env: TOXENV=py36 DOCKER=pyca/cryptography-runner-centos8 + - python: 3.6 services: docker - env: TOXENV=py34 DOCKER=pyca/cryptography-runner-jessie + env: TOXENV=py36 OPENSSL_FORCE_FIPS_MODE=1 DOCKER=pyca/cryptography-runner-centos8-fips - python: 2.7 services: docker env: TOXENV=py27 DOCKER=pyca/cryptography-runner-stretch @@ -81,59 +77,61 @@ matrix: - python: 3.7 services: docker env: TOXENV=py37 DOCKER=pyca/cryptography-runner-buster - - python: 3.7 + - python: 3.8 services: docker - env: TOXENV=py37 DOCKER=pyca/cryptography-runner-sid - - python: 2.7 + env: TOXENV=py38 DOCKER=pyca/cryptography-runner-bullseye + - python: 3.8 services: docker - env: TOXENV=py27 DOCKER=pyca/cryptography-runner-ubuntu-rolling + env: TOXENV=py38 DOCKER=pyca/cryptography-runner-sid - python: 3.6 services: docker - env: TOXENV=py36 DOCKER=pyca/cryptography-runner-ubuntu-rolling - - python: 2.7 + env: TOXENV=py36 DOCKER=pyca/cryptography-runner-ubuntu-bionic + - python: 3.8 services: docker - env: TOXENV=randomorder DOCKER=pyca/cryptography-runner-ubuntu-rolling + env: TOXENV=py38 DOCKER=pyca/cryptography-runner-ubuntu-focal - python: 2.7 services: docker - env: TOXENV=py27 DOCKER=pyca/cryptography-runner-fedora - - python: 3.7 + env: TOXENV=py27 DOCKER=pyca/cryptography-runner-ubuntu-rolling + - python: 3.8 services: docker - env: TOXENV=py37 DOCKER=pyca/cryptography-runner-fedora - - python: 3.6 + env: TOXENV=py38 DOCKER=pyca/cryptography-runner-ubuntu-rolling + - python: 3.8 + services: docker + env: TOXENV=py38-randomorder DOCKER=pyca/cryptography-runner-ubuntu-rolling + - python: 3.8 services: docker - env: TOXENV=py36 DOCKER=pyca/cryptography-runner-alpine:latest + env: TOXENV=py38 DOCKER=pyca/cryptography-runner-fedora + - python: 3.8 + services: docker + env: TOXENV=py38 DOCKER=pyca/cryptography-runner-alpine:latest - - python: 3.6 - env: TOXENV=docs OPENSSL=1.1.1a + - python: 3.8 + env: TOXENV=docs OPENSSL=1.1.1h addons: apt: packages: - libenchant-dev - - python: 2.7 + - python: 3.8 services: docker env: TOXENV=docs-linkcheck DOCKER=pyca/cryptography-runner-buster - if: branch = master AND type != pull_request - - python: 3.4 - env: TOXENV=pep8 + if: (branch = master AND type != pull_request) OR commit_message =~ /linkcheck/ - - python: 2.7 + - python: 3.8 env: DOWNSTREAM=pyopenssl - - python: 2.7 - env: DOWNSTREAM=twisted - - python: 2.7 + - python: 3.7 + env: DOWNSTREAM=twisted OPENSSL=1.1.1h + - python: 3.7 env: DOWNSTREAM=paramiko - - python: 2.7 + - python: 3.7 env: DOWNSTREAM=aws-encryption-sdk - - python: 2.7 + - python: 3.7 # BOTO_CONFIG works around this boto issue on travis: # https://github.com/boto/boto/issues/3717 - env: DOWNSTREAM=dynamodb-encryption-sdk OPENSSL=1.1.0j BOTO_CONFIG=/dev/null - - python: 2.7 - env: DOWNSTREAM=certbot OPENSSL=1.1.0j - - python: 2.7 + env: DOWNSTREAM=dynamodb-encryption-sdk BOTO_CONFIG=/dev/null + - python: 3.8 + env: DOWNSTREAM=certbot + - python: 3.8 env: DOWNSTREAM=certbot-josepy - - python: 2.7 - env: DOWNSTREAM=urllib3 install: - ./.travis/install.sh diff --git a/.travis/downstream.d/aws-encryption-sdk.sh b/.travis/downstream.d/aws-encryption-sdk.sh index d986c7490382..276d47eee559 100755 --- a/.travis/downstream.d/aws-encryption-sdk.sh +++ b/.travis/downstream.d/aws-encryption-sdk.sh @@ -6,7 +6,7 @@ case "${1}" in cd aws-encryption-sdk-python git rev-parse HEAD pip install -e . - pip install -r test/upstream-requirements-py27.txt + pip install -r test/upstream-requirements-py37.txt ;; run) cd aws-encryption-sdk-python diff --git a/.travis/downstream.d/certbot-josepy.sh b/.travis/downstream.d/certbot-josepy.sh index 0acf9547390d..2253edc1e9a6 100755 --- a/.travis/downstream.d/certbot-josepy.sh +++ b/.travis/downstream.d/certbot-josepy.sh @@ -5,7 +5,7 @@ case "${1}" in git clone --depth=1 https://github.com/certbot/josepy cd josepy git rev-parse HEAD - pip install -e ".[tests]" + pip install -e ".[tests]" -c constraints.txt ;; run) cd josepy diff --git a/.travis/downstream.d/certbot.sh b/.travis/downstream.d/certbot.sh index 6061e31076fd..e2890a3a100c 100755 --- a/.travis/downstream.d/certbot.sh +++ b/.travis/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 - pip install -e acme[dev] - pip install -e .[dev] + tools/pip_install_editable.py ./acme[dev] + tools/pip_install_editable.py ./certbot[dev] ;; run) cd certbot diff --git a/.travis/downstream.d/dynamodb-encryption-sdk.sh b/.travis/downstream.d/dynamodb-encryption-sdk.sh index 7ceff16d319f..60bbecf36afd 100755 --- a/.travis/downstream.d/dynamodb-encryption-sdk.sh +++ b/.travis/downstream.d/dynamodb-encryption-sdk.sh @@ -6,7 +6,7 @@ case "${1}" in cd aws-dynamodb-encryption-python git rev-parse HEAD pip install -e . - pip install -r test/upstream-requirements-py27.txt + pip install -r test/upstream-requirements-py37.txt ;; run) cd aws-dynamodb-encryption-python diff --git a/.travis/downstream.d/twisted.sh b/.travis/downstream.d/twisted.sh index 9b98d82b0525..522e763ec3b7 100755 --- a/.travis/downstream.d/twisted.sh +++ b/.travis/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 -e ".[tls,conch,http2]" + pip install ".[all_non_platform]" ;; run) cd twisted diff --git a/.travis/downstream.d/urllib3.sh b/.travis/downstream.d/urllib3.sh deleted file mode 100755 index dad06159846f..000000000000 --- a/.travis/downstream.d/urllib3.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -ex - -case "${1}" in - install) - git clone --depth 1 https://github.com/shazow/urllib3 - cd urllib3 - git rev-parse HEAD - pip install -r ./dev-requirements.txt - pip install -e ".[socks]" - ;; - run) - cd urllib3 - pytest test - ;; - *) - exit 1 - ;; -esac diff --git a/.travis/install.sh b/.travis/install.sh index a4bc3c978fdd..91df42285cdb 100755 --- a/.travis/install.sh +++ b/.travis/install.sh @@ -3,6 +3,8 @@ set -e set -x +SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}") + shlib_sed() { # modify the shlib version to a unique one to make sure the dynamic # linker doesn't load the system one. @@ -14,20 +16,20 @@ shlib_sed() { # download, compile, and install if it's not already present via travis # cache if [ -n "${OPENSSL}" ]; then - OPENSSL_DIR="ossl-2/${OPENSSL}" + . "$SCRIPT_DIR/openssl_config.sh" if [[ ! -f "$HOME/$OPENSSL_DIR/bin/openssl" ]]; then curl -O "https://www.openssl.org/source/openssl-${OPENSSL}.tar.gz" tar zxf "openssl-${OPENSSL}.tar.gz" pushd "openssl-${OPENSSL}" - ./config shared no-ssl2 no-ssl3 -fPIC --prefix="$HOME/$OPENSSL_DIR" + ./config $OPENSSL_CONFIG_FLAGS -fPIC --prefix="$HOME/$OPENSSL_DIR" shlib_sed make depend make -j"$(nproc)" - if [[ "${OPENSSL}" =~ 1.0.1 ]]; then - # OpenSSL 1.0.1 doesn't support installing without the docs. + # CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 + if [ "${OPENSSL}" == "1.0.2u" ]; then make install else - # avoid installing the docs + # avoid installing the docs on versions of OpenSSL that aren't ancient. # https://github.com/openssl/openssl/issues/6685#issuecomment-403838728 make install_sw install_ssldirs fi @@ -58,9 +60,10 @@ if [ -z "${DOWNSTREAM}" ]; then git clone --depth=1 https://github.com/google/wycheproof "$HOME/wycheproof" fi +pip install -U pip pip install virtualenv python -m virtualenv ~/.venv source ~/.venv/bin/activate -# If we pin coverage it must be kept in sync with tox.ini and Jenkinsfile -pip install tox codecov coverage +# If we pin coverage it must be kept in sync with tox.ini and .github/workflows/ci.yml +pip install tox coverage diff --git a/.travis/openssl_config.sh b/.travis/openssl_config.sh new file mode 100755 index 000000000000..83f16d2bfea8 --- /dev/null +++ b/.travis/openssl_config.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -e +set -x + +DEFAULT_CONFIG_FLAGS="shared no-ssl2 no-ssl3" +if [ -n "${OPENSSL_CONFIG_FLAGS}" ]; then + OPENSSL_CONFIG_FLAGS="$DEFAULT_CONFIG_FLAGS $OPENSSL_CONFIG_FLAGS" +else + OPENSSL_CONFIG_FLAGS=$DEFAULT_CONFIG_FLAGS +fi +CONFIG_HASH=$(echo "$OPENSSL_CONFIG_FLAGS" | sha1sum | sed 's/ .*$//') +OPENSSL_DIR="ossl-2/${OPENSSL}${CONFIG_HASH}" diff --git a/.travis/run.sh b/.travis/run.sh index 8f8dd6871bd4..01605c2717d4 100755 --- a/.travis/run.sh +++ b/.travis/run.sh @@ -1,18 +1,16 @@ #!/bin/bash -ex -if [[ "${TOXENV}" == "pypy" ]]; then - PYENV_ROOT="$HOME/.pyenv" - PATH="$PYENV_ROOT/bin:$PATH" - eval "$(pyenv init -)" -fi +SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}") + if [ -n "${LIBRESSL}" ]; then - OPENSSL=$LIBRESSL - export CFLAGS="-Werror -Wno-error=deprecated-declarations -Wno-error=discarded-qualifiers -Wno-error=unused-function" + LIBRESSL_DIR="ossl-2/${LIBRESSL}" + export CFLAGS="-Werror -Wno-error=deprecated-declarations -Wno-error=discarded-qualifiers -Wno-error=unused-function -I$HOME/$LIBRESSL_DIR/include" + export PATH="$HOME/$LIBRESSL_DIR/bin:$PATH" + export LDFLAGS="-L$HOME/$LIBRESSL_DIR/lib -Wl,-rpath=$HOME/$LIBRESSL_DIR/lib" fi if [ -n "${OPENSSL}" ]; then - OPENSSL_DIR="ossl-2/${OPENSSL}" - + . "$SCRIPT_DIR/openssl_config.sh" export PATH="$HOME/$OPENSSL_DIR/bin:$PATH" export CFLAGS="${CFLAGS} -I$HOME/$OPENSSL_DIR/include" # rpath on linux will cause it to use an absolute path so we don't need to @@ -23,12 +21,11 @@ fi source ~/.venv/bin/activate if [ -n "${DOCKER}" ]; then - # We will be able to drop the -u once we switch the default container user in the - # dockerfiles. - docker run --rm -u 2000:2000 \ + docker run --rm \ -v "${TRAVIS_BUILD_DIR}":"${TRAVIS_BUILD_DIR}" \ -v "${HOME}/wycheproof":/wycheproof \ -w "${TRAVIS_BUILD_DIR}" \ + -e OPENSSL_FORCE_FIPS_MODE \ -e TOXENV "${DOCKER}" \ /bin/sh -c "tox -- --wycheproof-root='/wycheproof'" elif [ -n "${TOXENV}" ]; then diff --git a/.travis/upload_coverage.sh b/.travis/upload_coverage.sh index 2f2cb3c180e0..2999bb7e6b25 100755 --- a/.travis/upload_coverage.sh +++ b/.travis/upload_coverage.sh @@ -6,12 +6,16 @@ set -x if [ -n "${TOXENV}" ]; then case "${TOXENV}" in pypy-nocoverage);; + pypy3-nocoverage);; pep8);; py3pep8);; docs);; *) source ~/.venv/bin/activate - codecov --env TRAVIS_OS_NAME,TOXENV,OPENSSL,DOCKER + curl -o codecov.sh -f https://codecov.io/bash || curl -o codecov.sh -f https://codecov.io/bash || curl -o codecov.sh -f https://codecov.io/bash + + bash codecov.sh -Z -e TRAVIS_OS_NAME,TOXENV,OPENSSL,DOCKER,OPENSSL_FORCE_FIPS_MODE || \ + bash codecov.sh -Z -e TRAVIS_OS_NAME,TOXENV,OPENSSL,DOCKER,OPENSSL_FORCE_FIPS_MODE ;; esac fi diff --git a/.zuul.d/jobs.yaml b/.zuul.d/jobs.yaml new file mode 100644 index 000000000000..1430b0c31510 --- /dev/null +++ b/.zuul.d/jobs.yaml @@ -0,0 +1,68 @@ +- job: + name: pyca-cryptography-base + abstract: true + description: Run pyca/cryptography unit testing + run: .zuul.playbooks/playbooks/tox/main.yaml + +- job: + name: pyca-cryptography-ubuntu-focal-py38-arm64 + parent: pyca-cryptography-base + nodeset: ubuntu-focal-arm64 + vars: + tox_envlist: py38 + +- job: + name: pyca-cryptography-ubuntu-bionic-py36-arm64 + parent: pyca-cryptography-base + nodeset: ubuntu-bionic-arm64 + vars: + tox_envlist: py36 + +- job: + name: pyca-cryptography-centos-8-py36-arm64 + parent: pyca-cryptography-base + nodeset: centos-8-arm64 + vars: + tox_envlist: py36 + +- job: + name: pyca-cryptography-centos-8-py27-arm64 + parent: pyca-cryptography-base + nodeset: centos-8-arm64 + vars: + tox_envlist: py27 + +- job: + name: pyca-cryptography-build-wheel + abstract: true + run: .zuul.playbooks/playbooks/wheel/main.yaml + +- job: + name: pyca-cryptography-build-wheel-arm64 + parent: pyca-cryptography-build-wheel + nodeset: ubuntu-bionic-arm64 + vars: + wheel_builds: + - platform: manylinux2014_aarch64 + image: pyca/cryptography-manylinux2014_aarch64 + pythons: + - cp35-cp35m + +- job: + name: pyca-cryptography-build-wheel-x86_64 + parent: pyca-cryptography-build-wheel + nodeset: ubuntu-bionic + vars: + wheel_builds: + - platform: manylinux1_x86_64 + image: pyca/cryptography-manylinux1:x86_64 + pythons: + - cp27-cp27m + - cp27-cp27mu + - cp35-cp35m + - platform: manylinux2010_x86_64 + image: pyca/cryptography-manylinux2010:x86_64 + pythons: + - cp27-cp27m + - cp27-cp27mu + - cp35-cp35m diff --git a/.zuul.d/project.yaml b/.zuul.d/project.yaml new file mode 100644 index 000000000000..3cda2ff87d00 --- /dev/null +++ b/.zuul.d/project.yaml @@ -0,0 +1,13 @@ +- project: + check: + jobs: + - pyca-cryptography-build-wheel-arm64 + - pyca-cryptography-build-wheel-x86_64 + - pyca-cryptography-ubuntu-focal-py38-arm64 + - pyca-cryptography-ubuntu-bionic-py36-arm64 + - pyca-cryptography-centos-8-py36-arm64 + - pyca-cryptography-centos-8-py27-arm64 + release: + jobs: + - pyca-cryptography-build-wheel-arm64 + - pyca-cryptography-build-wheel-x86_64 diff --git a/.zuul.playbooks/playbooks/tox/main.yaml b/.zuul.playbooks/playbooks/tox/main.yaml new file mode 100644 index 000000000000..fc92398ffa62 --- /dev/null +++ b/.zuul.playbooks/playbooks/tox/main.yaml @@ -0,0 +1,41 @@ +- hosts: all + tasks: + + - name: Install tox + include_role: + name: ensure-tox + + - name: Install required packages + package: + name: + - build-essential + - libssl-dev + - libffi-dev + - python3-dev + become: yes + when: ansible_distribution in ['Debian', 'Ubuntu'] + + - name: Install required packages + package: + name: + - redhat-rpm-config + - gcc + - libffi-devel + - openssl-devel + - python3-devel + - python2-devel + become: yes + when: ansible_distribution == 'CentOS' + + - name: Clone wycheproof + git: + repo: https://github.com/google/wycheproof + dest: "{{ ansible_facts.env['HOME'] }}/wycheproof" + depth: 1 + + - name: Run tox + include_role: + name: tox + vars: + tox_extra_args: "-- --wycheproof-root={{ ansible_facts.env['HOME'] }}/wycheproof/" + diff --git a/.zuul.playbooks/playbooks/wheel/main.yaml b/.zuul.playbooks/playbooks/wheel/main.yaml new file mode 100644 index 000000000000..7fcdd82efe2b --- /dev/null +++ b/.zuul.playbooks/playbooks/wheel/main.yaml @@ -0,0 +1,6 @@ +- hosts: all + tasks: + + - name: Build wheel + include_role: + name: build-wheel-manylinux diff --git a/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/README.rst b/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/README.rst new file mode 100644 index 000000000000..13c22d2cbaca --- /dev/null +++ b/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/README.rst @@ -0,0 +1 @@ +Build manylinux wheels for cryptography diff --git a/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/files/build-wheels.sh b/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/files/build-wheels.sh new file mode 100644 index 000000000000..65a8201823ca --- /dev/null +++ b/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/files/build-wheels.sh @@ -0,0 +1,51 @@ +#!/bin/bash -ex + +# Compile wheels +cd /io + +mkdir -p wheelhouse.final + +for P in ${PYTHONS}; do + + PYBIN=/opt/python/${P}/bin + + "${PYBIN}"/python -m virtualenv .venv + + .venv/bin/pip install cffi six ipaddress "enum34; python_version < '3'" + + REGEX="cp3([0-9])*" + if [[ "${PYBIN}" =~ $REGEX ]]; then + PY_LIMITED_API="--py-limited-api=cp3${BASH_REMATCH[1]}" + fi + + LDFLAGS="-L/opt/pyca/cryptography/openssl/lib" \ + CFLAGS="-I/opt/pyca/cryptography/openssl/include -Wl,--exclude-libs,ALL" \ + .venv/bin/python setup.py bdist_wheel $PY_LIMITED_API + + auditwheel repair --plat ${PLAT} -w wheelhouse/ dist/cryptography*.whl + + # Sanity checks + # NOTE(ianw) : no execstack on aarch64, comes from + # prelink, which was never supported. CentOS 8 does + # have it separate, skip for now. + if [[ "${PLAT}" != "manylinux2014_aarch64" ]]; then + for f in wheelhouse/*.whl; do + unzip $f -d execstack.check + + results=$(execstack execstack.check/cryptography/hazmat/bindings/*.so) + count=$(echo "$results" | grep -c '^X' || true) + if [ "$count" -ne 0 ]; then + exit 1 + fi + rm -rf execstack.check + done + fi + + .venv/bin/pip install cryptography --no-index -f wheelhouse/ + .venv/bin/python -c "from cryptography.hazmat.backends.openssl.backend import backend;print('Loaded: ' + backend.openssl_version_text());print('Linked Against: ' + backend._ffi.string(backend._lib.OPENSSL_VERSION_TEXT).decode('ascii'))" + + # Cleanup + mv wheelhouse/* wheelhouse.final + rm -rf .venv dist wheelhouse + +done diff --git a/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/tasks/main.yaml b/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/tasks/main.yaml new file mode 100644 index 000000000000..aebf7d6b7fbb --- /dev/null +++ b/.zuul.playbooks/playbooks/wheel/roles/build-wheel-manylinux/tasks/main.yaml @@ -0,0 +1,145 @@ +# Wheel builds is a list of dicts, with keys +# +# platform: the manylinux platform name +# image: the docker image to build in +# pythons: list of pythons in the image to build wheels for +- name: Sanity check build list + assert: + that: wheel_builds is defined + +- name: Ensure pip installed + include_role: + name: ensure-pip + +- name: Run ensure-docker + include_role: + name: ensure-docker + +- name: Workaround Linaro aarch64 cloud MTU issues + # NOTE(ianw) : Docker default networking, the Linaro NAT setup and + # *insert random things here* cause PMTU issues, resulting in hung + # connections, particularly to fastly CDN (particularly annoying + # because pypi and pythonhosted live behind that). Can remove after + # upstream changes merge, or we otherwise find a solution in the + # upstream cloud. + # https://review.opendev.org/747062 + # https://review.opendev.org/746833 + # https://review.opendev.org/747064 + when: ansible_architecture == 'aarch64' + block: + - name: Install jq + package: + name: jq + state: present + become: yes + + - name: Reset docker MTU + shell: | + jq --arg mtu 1400 '. + {mtu: $mtu|tonumber}' /etc/docker/daemon.json > /etc/docker/daemon.json.new + cat /etc/docker/daemon.json.new + mv /etc/docker/daemon.json.new /etc/docker/daemon.json + service docker restart + become: yes + +# We build an sdist of the checkout, and then build wheels from the +# sdist. This ensures that nothing is left out of the sdist. +- name: Install sdist required packages + package: + name: + - build-essential + - libssl-dev + - libffi-dev + - python3-dev + become: yes + when: ansible_distribution in ['Debian', 'Ubuntu'] + +- name: Create sdist + command: | + python3 setup.py sdist + args: + chdir: '{{ ansible_user_dir }}/{{ zuul.project.src_dir }}' + +- name: Find output file + find: + paths: '{{ ansible_user_dir }}/{{ zuul.project.src_dir }}/dist' + file_type: file + patterns: "*.tar.gz" + register: _sdist + +- assert: + that: + - _sdist.matched == 1 + +- name: Create a build area + file: + path: '{{ ansible_user_dir }}/build' + state: directory + +- name: Create build area from sdist + unarchive: + src: '{{ _sdist.files[0].path }}' + dest: '{{ ansible_user_dir }}/build' + remote_src: yes + +- name: Find cryptography subdir from sdist build dir + set_fact: + _build_dir: "{{ ansible_user_dir }}/build/{{ _sdist.files[0].path | basename | replace('.tar.gz', '') }}" + +- name: Show _build_dir + debug: + var: _build_dir + +- name: Install build script + copy: + src: build-wheels.sh + dest: '{{ _build_dir }}' + mode: 0755 + +- name: Pre-pull containers + command: >- + docker pull {{ item.image }} + become: yes + loop: '{{ wheel_builds }}' + +- name: Run builds + command: | + docker run --rm \ + -e PLAT={{ item.platform }} \ + -e PYTHONS="{{ item.pythons | join(' ') }}" \ + -v {{ _build_dir }}:/io \ + {{ item.image }} \ + /io/build-wheels.sh + become: yes + loop: '{{ wheel_builds }}' + +- name: Copy sdist to output + synchronize: + src: '{{ _sdist.files[0].path }}' + dest: '{{ zuul.executor.log_root }}' + mode: pull + +- name: Return sdist artifact + zuul_return: + data: + zuul: + artifacts: + - name: '{{ _sdist.files[0].path | basename }}' + url: 'sdist/{{ _sdist.files[0].path }}' + metadata: + type: sdist + +- name: Copy wheels to output + synchronize: + src: '{{ _build_dir }}/wheelhouse.final/' + dest: '{{ zuul.executor.log_root }}/wheelhouse' + mode: pull + +- name: Return wheelhouse artifact + zuul_return: + data: + zuul: + artifacts: + - name: "Wheelhouse" + url: "wheelhouse" + metadata: + type: wheelhouse diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7ee6d4d93d59..007f802006d1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,244 @@ Changelog ========= +.. _v3-2: + +3.2 - 2020-10-25 +~~~~~~~~~~~~~~~~ + +* **SECURITY ISSUE:** Attempted to make RSA PKCS#1v1.5 decryption more constant + time, to protect against Bleichenbacher vulnerabilities. Due to limitations + imposed by our API, we cannot completely mitigate this vulnerability and a + future release will contain a new API which is designed to be resilient to + these for contexts where it is required. Credit to **Hubert Kario** for + reporting the issue. *CVE-2020-25659* +* Support for OpenSSL 1.0.2 has been removed. Users on older version of OpenSSL + will need to upgrade. +* Added basic support for PKCS7 signing (including SMIME) via + :class:`~cryptography.hazmat.primitives.serialization.pkcs7.PKCS7SignatureBuilder`. + +.. _v3-1-1: + +3.1.1 - 2020-09-22 +~~~~~~~~~~~~~~~~~~ + +* Updated Windows, macOS, and ``manylinux`` wheels to be compiled with + OpenSSL 1.1.1h. + +.. _v3-1: + +3.1 - 2020-08-26 +~~~~~~~~~~~~~~~~ + +* **BACKWARDS INCOMPATIBLE:** Removed support for ``idna`` based + :term:`U-label` parsing in various X.509 classes. This support was originally + deprecated in version 2.1 and moved to an extra in 2.5. +* Deprecated OpenSSL 1.0.2 support. OpenSSL 1.0.2 is no longer supported by + the OpenSSL project. The next version of ``cryptography`` will drop support + for it. +* Deprecated support for Python 3.5. This version sees very little use and will + be removed in the next release. +* ``backend`` arguments to functions are no longer required and the + default backend will automatically be selected if no ``backend`` is provided. +* Added initial support for parsing certificates from PKCS7 files with + :func:`~cryptography.hazmat.primitives.serialization.pkcs7.load_pem_pkcs7_certificates` + and + :func:`~cryptography.hazmat.primitives.serialization.pkcs7.load_der_pkcs7_certificates` + . +* Calling ``update`` or ``update_into`` on + :class:`~cryptography.hazmat.primitives.ciphers.CipherContext` with ``data`` + longer than 2\ :sup:`31` bytes no longer raises an ``OverflowError``. This + also resolves the same issue in :doc:`/fernet`. + +.. _v3-0: + +3.0 - 2020-07-20 +~~~~~~~~~~~~~~~~ + +* **BACKWARDS INCOMPATIBLE:** Removed support for passing an + :class:`~cryptography.x509.Extension` instance to + :meth:`~cryptography.x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier`, + as per our deprecation policy. +* **BACKWARDS INCOMPATIBLE:** Support for LibreSSL 2.7.x, 2.8.x, and 2.9.0 has + been removed (2.9.1+ is still supported). +* **BACKWARDS INCOMPATIBLE:** Dropped support for macOS 10.9, macOS users must + upgrade to 10.10 or newer. +* **BACKWARDS INCOMPATIBLE:** RSA + :meth:`~cryptography.hazmat.primitives.asymmetric.rsa.generate_private_key` + no longer accepts ``public_exponent`` values except 65537 and 3 (the latter + for legacy purposes). +* **BACKWARDS INCOMPATIBLE:** X.509 certificate parsing now enforces that the + ``version`` field contains a valid value, rather than deferring this check + until :attr:`~cryptography.x509.Certificate.version` is accessed. +* Deprecated support for Python 2. At the time there is no time table for + actually dropping support, however we strongly encourage all users to upgrade + their Python, as Python 2 no longer receives support from the Python core + team. + + If you have trouble suppressing this warning in tests view the :ref:`FAQ + entry addressing this issue `. + +* Added support for ``OpenSSH`` serialization format for + ``ec``, ``ed25519``, ``rsa`` and ``dsa`` private keys: + :func:`~cryptography.hazmat.primitives.serialization.load_ssh_private_key` + for loading and + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.OpenSSH` + for writing. +* Added support for ``OpenSSH`` certificates to + :func:`~cryptography.hazmat.primitives.serialization.load_ssh_public_key`. +* Added :meth:`~cryptography.fernet.Fernet.encrypt_at_time` and + :meth:`~cryptography.fernet.Fernet.decrypt_at_time` to + :class:`~cryptography.fernet.Fernet`. +* Added support for the :class:`~cryptography.x509.SubjectInformationAccess` + X.509 extension. +* Added support for parsing + :class:`~cryptography.x509.SignedCertificateTimestamps` in OCSP responses. +* Added support for parsing attributes in certificate signing requests via + :meth:`~cryptography.x509.CertificateSigningRequest.get_attribute_for_oid`. +* Added support for encoding attributes in certificate signing requests via + :meth:`~cryptography.x509.CertificateSigningRequestBuilder.add_attribute`. +* On OpenSSL 1.1.1d and higher ``cryptography`` now uses OpenSSL's + built-in CSPRNG instead of its own OS random engine because these versions of + OpenSSL properly reseed on fork. +* Added initial support for creating PKCS12 files with + :func:`~cryptography.hazmat.primitives.serialization.pkcs12.serialize_key_and_certificates`. + +.. _v2-9-2: + +2.9.2 - 2020-04-22 +~~~~~~~~~~~~~~~~~~ + +* Updated the macOS wheel to fix an issue where it would not run on macOS + versions older than 10.15. + +.. _v2-9-1: + +2.9.1 - 2020-04-21 +~~~~~~~~~~~~~~~~~~ + +* Updated Windows, macOS, and ``manylinux`` wheels to be compiled with + OpenSSL 1.1.1g. + +.. _v2-9: + +2.9 - 2020-04-02 +~~~~~~~~~~~~~~~~ + +* **BACKWARDS INCOMPATIBLE:** Support for Python 3.4 has been removed due to + low usage and maintenance burden. +* **BACKWARDS INCOMPATIBLE:** Support for OpenSSL 1.0.1 has been removed. + Users on older version of OpenSSL will need to upgrade. +* **BACKWARDS INCOMPATIBLE:** Support for LibreSSL 2.6.x has been removed. +* Removed support for calling + :meth:`~cryptography.hazmat.primitives.asymmetric.x25519.X25519PublicKey.public_bytes` + with no arguments, as per our deprecation policy. You must now pass + ``encoding`` and ``format``. +* **BACKWARDS INCOMPATIBLE:** Reversed the order in which + :meth:`~cryptography.x509.Name.rfc4514_string` returns the RDNs + as required by :rfc:`4514`. +* Updated Windows, macOS, and ``manylinux`` wheels to be compiled with + OpenSSL 1.1.1f. +* Added support for parsing + :attr:`~cryptography.x509.ocsp.OCSPResponse.single_extensions` in an OCSP + response. +* :class:`~cryptography.x509.NameAttribute` values can now be empty strings. + +.. _v2-8: + +2.8 - 2019-10-16 +~~~~~~~~~~~~~~~~ + +* Updated Windows, macOS, and ``manylinux`` wheels to be compiled with + OpenSSL 1.1.1d. +* Added support for Python 3.8. +* Added class methods + :meth:`Poly1305.generate_tag + ` + and + :meth:`Poly1305.verify_tag + ` + for Poly1305 sign and verify operations. +* Deprecated support for OpenSSL 1.0.1. Support will be removed in + ``cryptography`` 2.9. +* We now ship ``manylinux2010`` wheels in addition to our ``manylinux1`` + wheels. +* Added support for ``ed25519`` and ``ed448`` keys in the + :class:`~cryptography.x509.CertificateBuilder`, + :class:`~cryptography.x509.CertificateSigningRequestBuilder`, + :class:`~cryptography.x509.CertificateRevocationListBuilder` and + :class:`~cryptography.x509.ocsp.OCSPResponseBuilder`. +* ``cryptography`` no longer depends on ``asn1crypto``. +* :class:`~cryptography.x509.FreshestCRL` is now allowed as a + :class:`~cryptography.x509.CertificateRevocationList` extension. + +.. _v2-7: + +2.7 - 2019-05-30 +~~~~~~~~~~~~~~~~ + +* **BACKWARDS INCOMPATIBLE:** We no longer distribute 32-bit ``manylinux1`` + wheels. Continuing to produce them was a maintenance burden. +* **BACKWARDS INCOMPATIBLE:** Removed the + ``cryptography.hazmat.primitives.mac.MACContext`` interface. The ``CMAC`` and + ``HMAC`` APIs have not changed, but they are no longer registered as + ``MACContext`` instances. +* Updated Windows, macOS, and ``manylinux1`` wheels to be compiled with + OpenSSL 1.1.1c. +* Removed support for running our tests with ``setup.py test``. Users + interested in running our tests can continue to follow the directions in our + :doc:`development documentation`. +* Add support for :class:`~cryptography.hazmat.primitives.poly1305.Poly1305` + when using OpenSSL 1.1.1 or newer. +* Support serialization with ``Encoding.OpenSSH`` and ``PublicFormat.OpenSSH`` + in + :meth:`Ed25519PublicKey.public_bytes + ` + . +* Correctly allow passing a ``SubjectKeyIdentifier`` to + :meth:`~cryptography.x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier` + and deprecate passing an ``Extension`` object. The documentation always + required ``SubjectKeyIdentifier`` but the implementation previously + required an ``Extension``. + +.. _v2-6-1: + +2.6.1 - 2019-02-27 +~~~~~~~~~~~~~~~~~~ + +* Resolved an error in our build infrastructure that broke our Python3 wheels + for macOS and Linux. + +.. _v2-6: + +2.6 - 2019-02-27 +~~~~~~~~~~~~~~~~ + +* **BACKWARDS INCOMPATIBLE:** Removed + ``cryptography.hazmat.primitives.asymmetric.utils.encode_rfc6979_signature`` + and + ``cryptography.hazmat.primitives.asymmetric.utils.decode_rfc6979_signature``, + which had been deprecated for nearly 4 years. Use + :func:`~cryptography.hazmat.primitives.asymmetric.utils.encode_dss_signature` + and + :func:`~cryptography.hazmat.primitives.asymmetric.utils.decode_dss_signature` + instead. +* **BACKWARDS INCOMPATIBLE**: Removed ``cryptography.x509.Certificate.serial``, + which had been deprecated for nearly 3 years. Use + :attr:`~cryptography.x509.Certificate.serial_number` instead. +* Updated Windows, macOS, and ``manylinux1`` wheels to be compiled with + OpenSSL 1.1.1b. +* Added support for :doc:`/hazmat/primitives/asymmetric/ed448` when using + OpenSSL 1.1.1b or newer. +* Added support for :doc:`/hazmat/primitives/asymmetric/ed25519` when using + OpenSSL 1.1.1b or newer. +* :func:`~cryptography.hazmat.primitives.serialization.load_ssh_public_key` can + now load ``ed25519`` public keys. +* Add support for easily mapping an object identifier to its elliptic curve + class via + :func:`~cryptography.hazmat.primitives.asymmetric.ec.get_curve_for_oid`. +* Add support for OpenSSL when compiled with the ``no-engine`` + (``OPENSSL_NO_ENGINE``) flag. + .. _v2-5: 2.5 - 2019-01-22 @@ -1099,8 +1337,8 @@ Changelog :class:`~cryptography.fernet.MultiFernet`. * More bit-lengths are now supported for ``p`` and ``q`` when loading DSA keys from numbers. -* Added :class:`~cryptography.hazmat.primitives.mac.MACContext` as a - common interface for CMAC and HMAC and deprecated ``CMACContext``. +* Added ``MACContext`` as a common interface for CMAC and HMAC and + deprecated ``CMACContext``. * Added support for encoding and decoding :rfc:`6979` signatures in :doc:`/hazmat/primitives/asymmetric/utils`. * Added diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index 14a1ed7fd37c..000000000000 --- a/Jenkinsfile +++ /dev/null @@ -1,247 +0,0 @@ -if (env.BRANCH_NAME == "master") { - properties([pipelineTriggers([cron('@daily')])]) -} - -def configs = [ - [ - label: 'windows', - toxenvs: ['py27', 'py34', 'py35', 'py36', 'py37'], - ], - [ - label: 'windows64', - toxenvs: ['py27', 'py34', 'py35', 'py36', 'py37'], - ], - [ - label: 'sierra', - toxenvs: ['py27', 'py36'], - ], - [ - label: 'yosemite', - toxenvs: ['py27'], - ], - [ - label: 'docker', - imageName: 'pyca/cryptography-runner-sid', - toxenvs: ['docs'], - artifacts: 'cryptography/docs/_build/html/**', - artifactExcludes: '**/*.doctree', - ], -] - -def checkout_git(label) { - retry(3) { - def script = "" - if (env.BRANCH_NAME.startsWith('PR-')) { - script = """ - git clone --depth=1 https://github.com/pyca/cryptography - cd cryptography - git fetch origin +refs/pull/${env.CHANGE_ID}/merge: - git checkout -qf FETCH_HEAD - """ - if (label.contains("windows")) { - bat script - } else { - sh """#!/bin/sh - set -xe - ${script} - """ - } - } else { - checkout([ - $class: 'GitSCM', - branches: [[name: "*/${env.BRANCH_NAME}"]], - doGenerateSubmoduleConfigurations: false, - extensions: [[ - $class: 'RelativeTargetDirectory', - relativeTargetDir: 'cryptography' - ]], - submoduleCfg: [], - userRemoteConfigs: [[ - 'url': 'https://github.com/pyca/cryptography' - ]] - ]) - } - } - if (label.contains("windows")) { - bat """ - cd cryptography - git rev-parse HEAD - """ - } else { - sh """ - cd cryptography - git rev-parse HEAD - """ - } -} -def build(toxenv, label, imageName, artifacts, artifactExcludes) { - try { - timeout(time: 30, unit: 'MINUTES') { - - checkout_git(label) - checkout([ - $class: 'GitSCM', - extensions: [[ - $class: 'RelativeTargetDirectory', - relativeTargetDir: 'wycheproof', - ]], - userRemoteConfigs: [[ - 'url': 'https://github.com/google/wycheproof', - ]] - ]) - - withCredentials([string(credentialsId: 'cryptography-codecov-token', variable: 'CODECOV_TOKEN')]) { - withEnv(["LABEL=$label", "TOXENV=$toxenv", "IMAGE_NAME=$imageName"]) { - if (label.contains("windows")) { - def pythonPath = [ - py27: "C:\\Python27\\python.exe", - py34: "C:\\Python34\\python.exe", - py35: "C:\\Python35\\python.exe", - py36: "C:\\Python36\\python.exe", - py37: "C:\\Python37\\python.exe" - ] - if (toxenv == "py35" || toxenv == "py36" || toxenv == "py37") { - opensslPaths = [ - "windows": [ - "include": "C:\\OpenSSL-Win32-2015\\include", - "lib": "C:\\OpenSSL-Win32-2015\\lib" - ], - "windows64": [ - "include": "C:\\OpenSSL-Win64-2015\\include", - "lib": "C:\\OpenSSL-Win64-2015\\lib" - ] - ] - } else { - opensslPaths = [ - "windows": [ - "include": "C:\\OpenSSL-Win32-2010\\include", - "lib": "C:\\OpenSSL-Win32-2010\\lib" - ], - "windows64": [ - "include": "C:\\OpenSSL-Win64-2010\\include", - "lib": "C:\\OpenSSL-Win64-2010\\lib" - ] - ] - } - bat """ - cd cryptography - @set PATH="C:\\Python27";"C:\\Python27\\Scripts";%PATH% - @set PYTHON="${pythonPath[toxenv]}" - - @set INCLUDE="${opensslPaths[label]['include']}";%INCLUDE% - @set LIB="${opensslPaths[label]['lib']}";%LIB% - tox -r -- --wycheproof-root=../wycheproof - IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL% - virtualenv .codecov - call .codecov/Scripts/activate - REM this pin must be kept in sync with tox.ini - pip install coverage - pip install codecov - codecov -e JOB_BASE_NAME,LABEL,TOXENV - """ - } else if (label.contains("sierra") || label.contains("yosemite")) { - ansiColor { - sh """#!/usr/bin/env bash - set -xe - # Jenkins logs in as a non-interactive shell, so we don't even have /usr/local/bin in PATH - export PATH="/usr/local/bin:\${PATH}" - export PATH="/Users/jenkins/.pyenv/shims:\${PATH}" - cd cryptography - CRYPTOGRAPHY_SUPPRESS_LINK_FLAGS=1 \ - LDFLAGS="/usr/local/opt/openssl\\@1.1/lib/libcrypto.a /usr/local/opt/openssl\\@1.1/lib/libssl.a" \ - CFLAGS="-I/usr/local/opt/openssl\\@1.1/include -Werror -Wno-error=deprecated-declarations -Wno-error=incompatible-pointer-types-discards-qualifiers -Wno-error=unused-function -Wno-error=unused-command-line-argument -mmacosx-version-min=10.9" \ - tox -r -- --color=yes --wycheproof-root=../wycheproof - virtualenv .venv - source .venv/bin/activate - # This pin must be kept in sync with tox.ini - pip install coverage - bash <(curl -s https://codecov.io/bash) -e JOB_BASE_NAME,LABEL,TOXENV - """ - } - } else { - ansiColor { - sh """#!/usr/bin/env bash - set -xe - cd cryptography - tox -r -- --color=yes --wycheproof-root=../wycheproof - virtualenv .venv - source .venv/bin/activate - # This pin must be kept in sync with tox.ini - pip install coverage - bash <(curl -s https://codecov.io/bash) -e JOB_BASE_NAME,LABEL,TOXENV,IMAGE_NAME - """ - } - if (artifacts) { - archiveArtifacts artifacts: artifacts, excludes: artifactExcludes - } - } - } - } - } - } finally { - deleteDir() - } - -} - -def builders = [:] -for (config in configs) { - def label = config["label"] - def toxenvs = config["toxenvs"] - def artifacts = config["artifacts"] - def artifactExcludes = config["artifactExcludes"] - - for (_toxenv in toxenvs) { - def toxenv = _toxenv - - if (label.contains("docker")) { - def imageName = config["imageName"] - def combinedName = "${imageName}-${toxenv}" - builders[combinedName] = { - node(label) { - stage(combinedName) { - def buildImage = docker.image(imageName) - buildImage.pull() - buildImage.inside { - build(toxenv, label, imageName, artifacts, artifactExcludes) - } - } - } - } - } else { - def combinedName = "${label}-${toxenv}" - builders[combinedName] = { - node(label) { - stage(combinedName) { - build(toxenv, label, '', null, null) - } - } - } - } - } -} - -/* Add the python setup.py test builder */ -builders["setup.py-test"] = { - node("docker") { - stage("python setup.py test") { - docker.image("pyca/cryptography-runner-ubuntu-rolling").inside { - try { - checkout_git("docker") - sh """#!/usr/bin/env bash - set -xe - cd cryptography - virtualenv .venv - source .venv/bin/activate - python setup.py test - """ - } finally { - deleteDir() - } - - } - } - } -} - -parallel builders diff --git a/MANIFEST.in b/MANIFEST.in index 373c242023b8..7e97167a1b63 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,6 +4,7 @@ include CONTRIBUTING.rst include LICENSE include LICENSE.APACHE include LICENSE.BSD +include LICENSE.PSF include README.rst include pyproject.toml @@ -12,4 +13,14 @@ recursive-include docs * recursive-include src/_cffi_src *.py *.c *.h prune docs/_build recursive-include tests *.py +exclude vectors recursive-exclude vectors * + +exclude .travis.yml .travis +recursive-exclude .travis * +recursive-exclude .github * + +exclude release.py .coveragerc codecov.yml dev-requirements.txt rtd-requirements.txt tox.ini + +recursive-exclude .zuul.d * +recursive-exclude .zuul.playbooks * diff --git a/README.rst b/README.rst index 13f2d7d11189..fddde9878581 100644 --- a/README.rst +++ b/README.rst @@ -12,13 +12,16 @@ pyca/cryptography .. image:: https://travis-ci.org/pyca/cryptography.svg?branch=master :target: https://travis-ci.org/pyca/cryptography +.. image:: https://github.com/pyca/cryptography/workflows/CI/badge.svg?branch=master + :target: https://github.com/pyca/cryptography/actions?query=workflow%3ACI+branch%3Amaster + .. image:: https://codecov.io/github/pyca/cryptography/coverage.svg?branch=master :target: https://codecov.io/github/pyca/cryptography?branch=master ``cryptography`` is a package which provides cryptographic recipes and primitives to Python developers. Our goal is for it to be your "cryptographic -standard library". It supports Python 2.7, Python 3.4+, and PyPy 5.3+. +standard library". It supports Python 2.7, Python 3.5+, and PyPy 5.4+. ``cryptography`` includes both high level recipes and low level interfaces to common cryptographic algorithms such as symmetric ciphers, message digests, and diff --git a/dev-requirements.txt b/dev-requirements.txt index 58827ed47f35..333faaddf8fe 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,7 +1,5 @@ click -clint coverage -requests tox >= 2.4.1 twine >= 1.8.0 -e .[test,docs,docstest,pep8test] diff --git a/docs/conf.py b/docs/conf.py index 4349b0587ea3..87e2b5869c6c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -35,7 +35,7 @@ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath(".")) # -- General configuration ---------------------------------------------------- @@ -45,33 +45,33 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.intersphinx', - 'sphinx.ext.viewcode', - 'cryptography-docs', + "sphinx.ext.autodoc", + "sphinx.ext.doctest", + "sphinx.ext.intersphinx", + "sphinx.ext.viewcode", + "cryptography-docs", ] if spelling is not None: - extensions.append('sphinxcontrib.spelling') + extensions.append("sphinxcontrib.spelling") # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] nitpicky = True # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = 'Cryptography' -copyright = '2013-2017, Individual Contributors' +project = "Cryptography" +copyright = "2013-2020, 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 @@ -81,7 +81,7 @@ base_dir = os.path.join(os.path.dirname(__file__), os.pardir) about = {} with open(os.path.join(base_dir, "src", "cryptography", "__about__.py")) as f: - exec(f.read(), about) + exec (f.read(), about) version = release = about["__version__"] @@ -97,7 +97,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = ['_build'] +exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all documents # default_role = None @@ -114,7 +114,7 @@ # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # -- Options for HTML output -------------------------------------------------- @@ -130,22 +130,26 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Output file base name for HTML help builder. -htmlhelp_basename = 'Cryptographydoc' +htmlhelp_basename = "Cryptographydoc" # -- Options for LaTeX output ------------------------------------------------- -latex_elements = { -} +latex_elements = {} # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]) latex_documents = [ - ('index', 'Cryptography.tex', 'Cryptography Documentation', - 'Individual Contributors', 'manual'), + ( + "index", + "Cryptography.tex", + "Cryptography Documentation", + "Individual Contributors", + "manual", + ), ] # -- Options for manual page output ------------------------------------------- @@ -153,8 +157,13 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'cryptography', 'Cryptography Documentation', - ['Individual Contributors'], 1) + ( + "index", + "cryptography", + "Cryptography Documentation", + ["Individual Contributors"], + 1, + ) ] # -- Options for Texinfo output ----------------------------------------------- @@ -163,22 +172,35 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'Cryptography', 'Cryptography Documentation', - 'Individual Contributors', 'Cryptography', - 'One line description of project.', - 'Miscellaneous'), + ( + "index", + "Cryptography", + "Cryptography Documentation", + "Individual Contributors", + "Cryptography", + "One line description of project.", + "Miscellaneous", + ), ] # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/3': None} +intersphinx_mapping = {"https://docs.python.org/3": None} -epub_theme = 'epub' +epub_theme = "epub" # Retry requests in the linkcheck builder so that we're resillient against # transient network errors. linkcheck_retries = 10 +linkcheck_timeout = 5 + linkcheck_ignore = [ # Small DH key results in a TLS failure on modern OpenSSL - "https://info.isl.ntt.co.jp/crypt/eng/camellia/", + 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", + # 403ing from Travis + r"https://devblogs.microsoft.com/oldnewthing/\?p=4223", + # Incomplete cert chain + r"https://cveform.mitre.org/", ] diff --git a/docs/development/c-bindings.rst b/docs/development/c-bindings.rst index 1b58dab6290f..efc21ca0a8f5 100644 --- a/docs/development/c-bindings.rst +++ b/docs/development/c-bindings.rst @@ -5,7 +5,7 @@ C bindings are bindings to C libraries, using cffi_ whenever possible. .. _cffi: https://cffi.readthedocs.io -Bindings live in :py:mod:`cryptography.hazmat.bindings`. +Bindings live in ``cryptography.hazmat.bindings``. When modifying the bindings you will need to recompile the C extensions to test the changes. This can be accomplished with ``pip install -e .`` in the diff --git a/docs/development/custom-vectors/arc4/generate_arc4.py b/docs/development/custom-vectors/arc4/generate_arc4.py index 3dee44a305a4..2ca85c98dbe7 100644 --- a/docs/development/custom-vectors/arc4/generate_arc4.py +++ b/docs/development/custom-vectors/arc4/generate_arc4.py @@ -12,10 +12,14 @@ _RFC6229_KEY_MATERIALS = [ - (True, - 8 * '0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20'), - (False, - 8 * '1ada31d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a') + ( + True, + 8 * "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", + ), + ( + False, + 8 * "1ada31d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a", + ), ] @@ -37,42 +41,43 @@ 3056, 3072, 4080, - 4096 + 4096, ] -_SIZES_TO_GENERATE = [ - 160 -] +_SIZES_TO_GENERATE = [160] def _key_for_size(size, keyinfo): msb, key = keyinfo if msb: - return key[:size // 4] + return key[: size // 4] else: - return key[-size // 4:] + return key[-size // 4 :] def _build_vectors(): count = 0 output = [] key = None - plaintext = binascii.unhexlify(32 * '0') + plaintext = binascii.unhexlify(32 * "0") for size in _SIZES_TO_GENERATE: for keyinfo in _RFC6229_KEY_MATERIALS: key = _key_for_size(size, keyinfo) cipher = ciphers.Cipher( algorithms.ARC4(binascii.unhexlify(key)), None, - default_backend()) + default_backend(), + ) encryptor = cipher.encryptor() current_offset = 0 for offset in _RFC6229_OFFSETS: if offset % 16 != 0: raise ValueError( - "Offset {} is not evenly divisible by 16" - .format(offset)) + "Offset {} is not evenly divisible by 16".format( + offset + ) + ) while current_offset < offset: encryptor.update(plaintext) current_offset += len(plaintext) @@ -80,19 +85,23 @@ def _build_vectors(): count += 1 output.append("KEY = {}".format(key)) output.append("OFFSET = {}".format(offset)) - output.append("PLAINTEXT = {}".format( - binascii.hexlify(plaintext))) - output.append("CIPHERTEXT = {}".format( - binascii.hexlify(encryptor.update(plaintext)))) + output.append( + "PLAINTEXT = {}".format(binascii.hexlify(plaintext)) + ) + output.append( + "CIPHERTEXT = {}".format( + binascii.hexlify(encryptor.update(plaintext)) + ) + ) current_offset += len(plaintext) assert not encryptor.finalize() return "\n".join(output) def _write_file(data, filename): - with open(filename, 'w') as f: + with open(filename, "w") as f: f.write(data) -if __name__ == '__main__': - _write_file(_build_vectors(), 'arc4.txt') +if __name__ == "__main__": + _write_file(_build_vectors(), "arc4.txt") diff --git a/docs/development/custom-vectors/cast5/generate_cast5.py b/docs/development/custom-vectors/cast5/generate_cast5.py index a0e28e36e266..5208b90d8440 100644 --- a/docs/development/custom-vectors/cast5/generate_cast5.py +++ b/docs/development/custom-vectors/cast5/generate_cast5.py @@ -14,7 +14,7 @@ def encrypt(mode, key, iv, plaintext): cipher = base.Cipher( algorithms.CAST5(binascii.unhexlify(key)), mode(binascii.unhexlify(iv)), - default_backend() + default_backend(), ) encryptor = cipher.encryptor() ct = encryptor.update(binascii.unhexlify(plaintext)) @@ -23,33 +23,36 @@ def encrypt(mode, key, iv, plaintext): def build_vectors(mode, filename): - vector_file = open(filename, "r") - count = 0 output = [] key = None iv = None plaintext = None - for line in vector_file: - line = line.strip() - if line.startswith("KEY"): - if count != 0: - output.append("CIPHERTEXT = {}".format( - encrypt(mode, key, iv, plaintext)) - ) - output.append("\nCOUNT = {}".format(count)) - count += 1 - name, key = line.split(" = ") - output.append("KEY = {}".format(key)) - elif line.startswith("IV"): - name, iv = line.split(" = ") - iv = iv[0:16] - output.append("IV = {}".format(iv)) - elif line.startswith("PLAINTEXT"): - name, plaintext = line.split(" = ") - output.append("PLAINTEXT = {}".format(plaintext)) - output.append("CIPHERTEXT = {}".format(encrypt(mode, key, iv, plaintext))) + with open(filename, "r") as vector_file: + for line in vector_file: + line = line.strip() + if line.startswith("KEY"): + if count != 0: + output.append( + "CIPHERTEXT = {}".format( + encrypt(mode, key, iv, plaintext) + ) + ) + output.append("\nCOUNT = {}".format(count)) + count += 1 + name, key = line.split(" = ") + output.append("KEY = {}".format(key)) + elif line.startswith("IV"): + name, iv = line.split(" = ") + iv = iv[0:16] + output.append("IV = {}".format(iv)) + elif line.startswith("PLAINTEXT"): + name, plaintext = line.split(" = ") + output.append("PLAINTEXT = {}".format(plaintext)) + output.append( + "CIPHERTEXT = {}".format(encrypt(mode, key, iv, plaintext)) + ) return "\n".join(output) diff --git a/docs/development/custom-vectors/hkdf/generate_hkdf.py b/docs/development/custom-vectors/hkdf/generate_hkdf.py index 767aedd835ee..aa2fc274f9ae 100644 --- a/docs/development/custom-vectors/hkdf/generate_hkdf.py +++ b/docs/development/custom-vectors/hkdf/generate_hkdf.py @@ -13,27 +13,31 @@ IKM = binascii.unhexlify(b"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") L = 1200 OKM = HKDF( - algorithm=hashes.SHA256(), length=L, salt=None, info=None, - backend=default_backend() + algorithm=hashes.SHA256(), + length=L, + salt=None, + info=None, + backend=default_backend(), ).derive(IKM) def _build_vectors(): - output = [] - output.append("COUNT = 0") - output.append("Hash = SHA-256") - output.append("IKM = " + binascii.hexlify(IKM).decode("ascii")) - output.append("salt = ") - output.append("info = ") - output.append("L = {}".format(L)) - output.append("OKM = " + binascii.hexlify(OKM).decode("ascii")) + output = [ + "COUNT = 0", + "Hash = SHA-256", + "IKM = " + binascii.hexlify(IKM).decode("ascii"), + "salt = ", + "info = ", + "L = {}".format(L), + "OKM = " + binascii.hexlify(OKM).decode("ascii"), + ] return "\n".join(output) def _write_file(data, filename): - with open(filename, 'w') as f: + with open(filename, "w") as f: f.write(data) -if __name__ == '__main__': - _write_file(_build_vectors(), 'hkdf.txt') +if __name__ == "__main__": + _write_file(_build_vectors(), "hkdf.txt") diff --git a/docs/development/custom-vectors/idea/generate_idea.py b/docs/development/custom-vectors/idea/generate_idea.py index 2eb6996ef651..00309567b959 100644 --- a/docs/development/custom-vectors/idea/generate_idea.py +++ b/docs/development/custom-vectors/idea/generate_idea.py @@ -8,7 +8,7 @@ def encrypt(mode, key, iv, plaintext): cipher = base.Cipher( algorithms.IDEA(binascii.unhexlify(key)), mode(binascii.unhexlify(iv)), - backend + backend, ) encryptor = cipher.encryptor() ct = encryptor.update(binascii.unhexlify(plaintext)) @@ -29,8 +29,10 @@ def build_vectors(mode, filename): line = line.strip() if line.startswith("KEY"): if count != 0: - output.append("CIPHERTEXT = {0}".format( - encrypt(mode, key, iv, plaintext)) + output.append( + "CIPHERTEXT = {0}".format( + encrypt(mode, key, iv, plaintext) + ) ) output.append("\nCOUNT = {0}".format(count)) count += 1 diff --git a/docs/development/custom-vectors/idea/verify_idea.py b/docs/development/custom-vectors/idea/verify_idea.py index 89713c801dba..d356de0ba7f3 100644 --- a/docs/development/custom-vectors/idea/verify_idea.py +++ b/docs/development/custom-vectors/idea/verify_idea.py @@ -8,11 +8,13 @@ def encrypt(mode, key, iv, plaintext): - encryptor = botan.Cipher("IDEA/{0}/NoPadding".format(mode), "encrypt", - binascii.unhexlify(key)) + encryptor = botan.Cipher( + "IDEA/{0}/NoPadding".format(mode), "encrypt", binascii.unhexlify(key) + ) - cipher_text = encryptor.cipher(binascii.unhexlify(plaintext), - binascii.unhexlify(iv)) + cipher_text = encryptor.cipher( + binascii.unhexlify(plaintext), binascii.unhexlify(iv) + ) return binascii.hexlify(cipher_text) @@ -22,12 +24,7 @@ def verify_vectors(mode, filename): vectors = load_nist_vectors(vector_file) for vector in vectors: - ct = encrypt( - mode, - vector["key"], - vector["iv"], - vector["plaintext"] - ) + ct = encrypt(mode, vector["key"], vector["iv"], vector["plaintext"]) assert ct == vector["ciphertext"] diff --git a/docs/development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py b/docs/development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py index bd5148f54cbd..a43e1506d53d 100644 --- a/docs/development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py +++ b/docs/development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py @@ -62,9 +62,8 @@ def build_vectors(mgf1alg, hashalg, filename): dmq1=private["dmq1"], iqmp=private["iqmp"], public_numbers=rsa.RSAPublicNumbers( - e=private["public_exponent"], - n=private["modulus"] - ) + e=private["public_exponent"], n=private["modulus"] + ), ).private_key(backend) count = 1 @@ -74,8 +73,8 @@ def build_vectors(mgf1alg, hashalg, filename): padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), - label=None - ) + label=None, + ), ) assert message == binascii.unhexlify(example["message"]) ct = pkey.encrypt( @@ -83,8 +82,8 @@ def build_vectors(mgf1alg, hashalg, filename): padding.OAEP( mgf=padding.MGF1(algorithm=mgf1alg), algorithm=hashalg, - label=None - ) + label=None, + ), ) output.append( b"# OAEP Example {0} alg={1} mgf1={2}".format( @@ -116,13 +115,12 @@ def write_file(data, filename): hashes.SHA512(), ] for hashtuple in itertools.product(hashalgs, hashalgs): - if ( - isinstance(hashtuple[0], hashes.SHA1) and - isinstance(hashtuple[1], hashes.SHA1) + if isinstance(hashtuple[0], hashes.SHA1) and isinstance( + hashtuple[1], hashes.SHA1 ): continue write_file( build_vectors(hashtuple[0], hashtuple[1], oaep_path), - "oaep-{0}-{1}.txt".format(hashtuple[0].name, hashtuple[1].name) + "oaep-{0}-{1}.txt".format(hashtuple[0].name, hashtuple[1].name), ) diff --git a/docs/development/custom-vectors/secp256k1/generate_secp256k1.py b/docs/development/custom-vectors/secp256k1/generate_secp256k1.py index d6a2071ac22c..bfb150ba6fcc 100644 --- a/docs/development/custom-vectors/secp256k1/generate_secp256k1.py +++ b/docs/development/custom-vectors/secp256k1/generate_secp256k1.py @@ -10,9 +10,7 @@ from cryptography_vectors import open_vector_file -from tests.utils import ( - load_fips_ecdsa_signing_vectors, load_vectors_from_file -) +from tests.utils import load_fips_ecdsa_signing_vectors, load_vectors_from_file HASHLIB_HASH_TYPES = { "SHA-1": hashlib.sha1, @@ -32,13 +30,13 @@ def __call__(self, data): return self def digest(self): - return self.hasher.digest()[:256 // 8] + return self.hasher.digest()[: 256 // 8] def build_vectors(fips_vectors): vectors = defaultdict(list) for vector in fips_vectors: - vectors[vector['digest_algorithm']].append(vector['message']) + vectors[vector["digest_algorithm"]].append(vector["message"]) for digest_algorithm, messages in vectors.items(): if digest_algorithm not in HASHLIB_HASH_TYPES: @@ -55,8 +53,9 @@ def build_vectors(fips_vectors): # Sign the message using warner/ecdsa secret_key = SigningKey.generate(curve=SECP256k1) public_key = secret_key.get_verifying_key() - signature = secret_key.sign(message, hashfunc=hash_func, - sigencode=sigencode_der) + signature = secret_key.sign( + message, hashfunc=hash_func, sigencode=sigencode_der + ) r, s = sigdecode_der(signature, None) @@ -79,12 +78,8 @@ def write_file(lines, dest): dest_path = os.path.join("asymmetric", "ECDSA", "SECP256K1", "SigGen.txt") fips_vectors = load_vectors_from_file( - source_path, - load_fips_ecdsa_signing_vectors + source_path, load_fips_ecdsa_signing_vectors ) with open_vector_file(dest_path, "w") as dest_file: - write_file( - build_vectors(fips_vectors), - dest_file - ) + write_file(build_vectors(fips_vectors), dest_file) diff --git a/docs/development/custom-vectors/secp256k1/verify_secp256k1.py b/docs/development/custom-vectors/secp256k1/verify_secp256k1.py index b236d77fcf07..f721b0001213 100644 --- a/docs/development/custom-vectors/secp256k1/verify_secp256k1.py +++ b/docs/development/custom-vectors/secp256k1/verify_secp256k1.py @@ -6,12 +6,10 @@ from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.asymmetric.utils import ( - encode_dss_signature + encode_dss_signature, ) -from tests.utils import ( - load_fips_ecdsa_signing_vectors, load_vectors_from_file -) +from tests.utils import load_fips_ecdsa_signing_vectors, load_vectors_from_file CRYPTOGRAPHY_HASH_TYPES = { "SHA-1": hashes.SHA1, @@ -23,37 +21,32 @@ def verify_one_vector(vector): - digest_algorithm = vector['digest_algorithm'] - message = vector['message'] - x = vector['x'] - y = vector['y'] - signature = encode_dss_signature(vector['r'], vector['s']) - - numbers = ec.EllipticCurvePublicNumbers( - x, y, - ec.SECP256K1() - ) + digest_algorithm = vector["digest_algorithm"] + message = vector["message"] + x = vector["x"] + y = vector["y"] + signature = encode_dss_signature(vector["r"], vector["s"]) + + numbers = ec.EllipticCurvePublicNumbers(x, y, ec.SECP256K1()) key = numbers.public_key(default_backend()) verifier = key.verifier( - signature, - ec.ECDSA(CRYPTOGRAPHY_HASH_TYPES[digest_algorithm]()) + signature, ec.ECDSA(CRYPTOGRAPHY_HASH_TYPES[digest_algorithm]()) ) verifier.update(message) - return verifier.verify() + verifier.verify() def verify_vectors(vectors): for vector in vectors: - assert verify_one_vector(vector) + verify_one_vector(vector) vector_path = os.path.join("asymmetric", "ECDSA", "SECP256K1", "SigGen.txt") secp256k1_vectors = load_vectors_from_file( - vector_path, - load_fips_ecdsa_signing_vectors + vector_path, load_fips_ecdsa_signing_vectors ) verify_vectors(secp256k1_vectors) diff --git a/docs/development/custom-vectors/seed/generate_seed.py b/docs/development/custom-vectors/seed/generate_seed.py index 5c62d6713398..046fcfb87b48 100644 --- a/docs/development/custom-vectors/seed/generate_seed.py +++ b/docs/development/custom-vectors/seed/generate_seed.py @@ -8,7 +8,7 @@ def encrypt(mode, key, iv, plaintext): cipher = base.Cipher( algorithms.SEED(binascii.unhexlify(key)), mode(binascii.unhexlify(iv)), - backend + backend, ) encryptor = cipher.encryptor() ct = encryptor.update(binascii.unhexlify(plaintext)) @@ -29,8 +29,10 @@ def build_vectors(mode, filename): line = line.strip() if line.startswith("KEY"): if count != 0: - output.append("CIPHERTEXT = {0}".format( - encrypt(mode, key, iv, plaintext)) + output.append( + "CIPHERTEXT = {0}".format( + encrypt(mode, key, iv, plaintext) + ) ) output.append("\nCOUNT = {0}".format(count)) count += 1 diff --git a/docs/development/custom-vectors/seed/verify_seed.py b/docs/development/custom-vectors/seed/verify_seed.py index e626428cb0c2..252088d083e1 100644 --- a/docs/development/custom-vectors/seed/verify_seed.py +++ b/docs/development/custom-vectors/seed/verify_seed.py @@ -6,11 +6,13 @@ def encrypt(mode, key, iv, plaintext): - encryptor = botan.Cipher("SEED/{0}/NoPadding".format(mode), "encrypt", - binascii.unhexlify(key)) + encryptor = botan.Cipher( + "SEED/{0}/NoPadding".format(mode), "encrypt", binascii.unhexlify(key) + ) - cipher_text = encryptor.cipher(binascii.unhexlify(plaintext), - binascii.unhexlify(iv)) + cipher_text = encryptor.cipher( + binascii.unhexlify(plaintext), binascii.unhexlify(iv) + ) return binascii.hexlify(cipher_text) @@ -20,12 +22,7 @@ def verify_vectors(mode, filename): vectors = load_nist_vectors(vector_file) for vector in vectors: - ct = encrypt( - mode, - vector["key"], - vector["iv"], - vector["plaintext"] - ) + ct = encrypt(mode, vector["key"], vector["iv"], vector["plaintext"]) assert ct == vector["ciphertext"] diff --git a/docs/development/getting-started.rst b/docs/development/getting-started.rst index cc333e4d3898..1d939a9c3786 100644 --- a/docs/development/getting-started.rst +++ b/docs/development/getting-started.rst @@ -81,7 +81,7 @@ each supported Python version and run the tests. For example: ... py27: commands succeeded ERROR: pypy: InterpreterNotFound: pypy - py34: commands succeeded + py38: commands succeeded docs: commands succeeded pep8: commands succeeded diff --git a/docs/development/reviewing-patches.rst b/docs/development/reviewing-patches.rst index bd3ee96ac84d..084461830be3 100644 --- a/docs/development/reviewing-patches.rst +++ b/docs/development/reviewing-patches.rst @@ -7,18 +7,18 @@ review is our opportunity to share knowledge, design ideas and make friends. When reviewing a patch try to keep each of these concepts in mind: -Architecture ------------- - -* Is the proposed change being made in the correct place? Is it a fix in a - backend when it should be in the primitives? - Intent ------ * What is the change being proposed? * Do we want this feature or is the bug they're fixing really a bug? +Architecture +------------ + +* Is the proposed change being made in the correct place? Is it a fix in a + backend when it should be in the primitives? + Implementation -------------- diff --git a/docs/development/submitting-patches.rst b/docs/development/submitting-patches.rst index ec00aa528650..b4ed175e6adb 100644 --- a/docs/development/submitting-patches.rst +++ b/docs/development/submitting-patches.rst @@ -19,9 +19,10 @@ Code ---- When in doubt, refer to :pep:`8` for Python code. You can check if your code -meets our automated requirements by running ``flake8`` 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 pep8``. +meets our automated requirements by formatting it with ``black`` and running +``flake8`` 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 pep8``. `Write comments as complete sentences.`_ @@ -80,10 +81,9 @@ Every recipe should include a version or algorithmic marker of some sort in its output in order to allow transparent upgrading of the algorithms in use, as the algorithms or parameters needed to achieve a given security margin evolve. -APIs at the :doc:`/hazmat/primitives/index` layer should always take an -explicit backend, APIs at the recipes layer should automatically use the -:func:`~cryptography.hazmat.backends.default_backend`, but optionally allow -specifying a different backend. +APIs at the :doc:`/hazmat/primitives/index` and recipes layer should +automatically use the :func:`~cryptography.hazmat.backends.default_backend`, +but optionally allow specifying a different backend. C bindings ~~~~~~~~~~ @@ -156,6 +156,6 @@ So, specifically: .. _`Write comments as complete sentences.`: https://nedbatchelder.com/blog/201401/comments_should_be_sentences.html .. _`syntax`: https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#info-field-lists -.. _`Studies have shown`: https://smartbear.com/SmartBear/media/pdfs/11_Best_Practices_for_Peer_Code_Review.pdf +.. _`Studies have shown`: https://smartbear.com/learn/code-review/best-practices-for-peer-code-review/ .. _`our mailing list`: https://mail.python.org/mailman/listinfo/cryptography-dev .. _`doc8`: https://github.com/openstack/doc8 diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index df1ecfa20505..6146c9c139b9 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -23,7 +23,7 @@ for various cryptographic algorithms. These are not included in the repository continuous integration environments. We have ensured all test vectors are used as of commit -``c313761979d74b0417230eddd0f87d0cfab2b46b``. +``2196000605e45d91097147c9c71f26b72af58003``. Asymmetric ciphers ~~~~~~~~~~~~~~~~~~ @@ -78,6 +78,8 @@ Custom asymmetric vectors * ``asymmetric/PEM_Serialization/rsa_public_key.pem`` and ``asymmetric/DER_Serialization/rsa_public_key.der``- Contains an RSA 2048 bit public generated using OpenSSL from ``rsa_private_key.pem``. +* ``asymmetric/PEM_Serialization/dsa_4096.pem`` - Contains a 4096-bit DSA + private key generated using OpenSSL. * ``asymmetric/PEM_Serialization/dsaparam.pem`` - Contains 2048-bit DSA parameters generated using OpenSSL; contains no keys. * ``asymmetric/PEM_Serialization/dsa_private_key.pem`` - Contains a DSA 2048 @@ -86,6 +88,11 @@ Custom asymmetric vectors * ``asymmetric/PEM_Serialization/dsa_public_key.pem`` and ``asymmetric/DER_Serialization/dsa_public_key.der`` - Contains a DSA 2048 bit key generated using OpenSSL from ``dsa_private_key.pem``. +* ``asymmetric/DER_Serialization/dsa_public_key_no_params.der`` - Contains a + DSA public key with the optional parameters removed. +* ``asymmetric/DER_Serialization/dsa_public_key_invalid_bit_string.der`` - + Contains a DSA public key with the bit string padding value set to 2 rather + than the required 0. * ``asymmetric/PKCS8/unenc-dsa-pkcs8.pem`` and ``asymmetric/DER_Serialization/unenc-dsa-pkcs8.der`` - Contains a DSA 1024 bit key generated using OpenSSL. @@ -102,6 +109,8 @@ Custom asymmetric vectors * ``x509/custom/ca/ca_key.pem`` - An unencrypted PCKS8 ``secp256r1`` key. It is the private key for the certificate ``x509/custom/ca/ca.pem``. This key is encoded in several of the PKCS12 custom vectors. +* ``x509/custom/ca/rsa_key.pem`` - An unencrypted PCKS8 4096 bit RSA key. It is + the private key for the certificate ``x509/custom/ca/rsa_ca.pem``. * ``asymmetric/EC/compressed_points.txt`` - Contains compressed public points generated using OpenSSL. * ``asymmetric/X448/x448-pkcs8-enc.pem`` and @@ -111,6 +120,13 @@ Custom asymmetric vectors contain an unencrypted X448 key. * ``asymmetric/X448/x448-pub.pem`` and ``asymmetric/X448/x448-pub.der`` contain an X448 public key. +* ``asymmetric/Ed25519/ed25519-pkcs8-enc.pem`` and + ``asymmetric/Ed25519/ed25519-pkcs8-enc.der`` contain an Ed25519 key encrypted + with AES 256 CBC with the password ``password``. +* ``asymmetric/Ed25519/ed25519-pkcs8.pem`` and + ``asymmetric/Ed25519/ed25519-pkcs8.der`` contain an unencrypted Ed25519 key. +* ``asymmetric/Ed25519/ed25519-pub.pem`` and + ``asymmetric/Ed25519/ed25519-pub.der`` contain an Ed25519 public key. * ``asymmetric/X25519/x25519-pkcs8-enc.pem`` and ``asymmetric/X25519/x25519-pkcs8-enc.der`` contain an X25519 key encrypted with AES 256 CBC with the password ``password``. @@ -118,6 +134,13 @@ Custom asymmetric vectors ``asymmetric/X25519/x25519-pkcs8.der`` contain an unencrypted X25519 key. * ``asymmetric/X25519/x25519-pub.pem`` and ``asymmetric/X25519/x25519-pub.der`` contain an X25519 public key. +* ``asymmetric/Ed448/ed448-pkcs8-enc.pem`` and + ``asymmetric/Ed448/ed448-pkcs8-enc.der`` contain an Ed448 key encrypted + with AES 256 CBC with the password ``password``. +* ``asymmetric/Ed448/ed448-pkcs8.pem`` and + ``asymmetric/Ed448/ed448-pkcs8.der`` contain an unencrypted Ed448 key. +* ``asymmetric/Ed448/ed448-pub.pem`` and ``asymmetric/Ed448/ed448-pub.der`` + contain an Ed448 public key. Key exchange @@ -217,6 +240,17 @@ X.509 UTCTime in its validity->not_after. * ``letsencryptx3.pem`` - A subordinate certificate used by Let's Encrypt to issue end entity certificates. +* ``ed25519-rfc8410.pem`` - A certificate containing an X25519 public key with + an ``ed25519`` signature taken from :rfc:`8410`. +* ``root-ed25519.pem`` - An ``ed25519`` root certificate (``ed25519`` signature + with ``ed25519`` public key) from the OpenSSL test suite. + (`root-ed25519.pem`_) +* ``server-ed25519-cert.pem`` - An ``ed25519`` server certificate (RSA + signature with ``ed25519`` public key) from the OpenSSL test suite. + (`server-ed25519-cert.pem`_) +* ``server-ed448-cert.pem`` - An ``ed448`` server certificate (RSA + signature with ``ed448`` public key) from the OpenSSL test suite. + (`server-ed448-cert.pem`_) Custom X.509 Vectors ~~~~~~~~~~~~~~~~~~~~ @@ -371,9 +405,19 @@ Custom X.509 Vectors a ``policyConstraints`` extension with a ``requireExplicitPolicy`` value. * ``freshestcrl.pem`` - A self-signed certificate containing a ``freshestCRL`` extension. +* ``sia.pem`` - An RSA 2048 bit self-signed certificate containing a subject + information access extension with both a CA repository entry and a custom + OID entry. * ``ca/ca.pem`` - A self-signed certificate with ``basicConstraints`` set to true. Its private key is ``ca/ca_key.pem``. This certificate is encoded in several of the PKCS12 custom vectors. +* ``negative_serial.pem`` - A certificate with a serial number that is a + negative number. +* ``rsa_pss.pem`` - A certificate with an RSA PSS signature. +* ``root-ed448.pem`` - An ``ed448`` self-signed CA certificate + using ``ed448-pkcs8.pem`` as key. +* ``ca/rsa_ca.pem`` - A self-signed RSA certificate with ``basicConstraints`` + set to true. Its private key is ``ca/rsa_key.pem``. Custom X.509 Request Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -406,6 +450,14 @@ Custom X.509 Request Vectors critical. * ``invalid_signature.pem`` - A certificate signing request for an RSA 1024 bit key containing an invalid signature with correct padding. +* ``challenge.pem`` - A certificate signing request for an RSA 2048 bit key + containing a challenge password. +* ``challenge-invalid.der`` - A certificate signing request for an RSA 2048 bit + key containing a challenge password attribute that has been encoded as an + ASN.1 integer rather than a string. +* ``challenge-unstructured.pem`` - A certificate signing request for an RSA + 2048 bit key containing a challenge password attribute and an unstructured + name attribute. Custom X.509 Certificate Revocation List Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -480,6 +532,12 @@ X.509 OCSP Test Vectors contains a revoked certificate and no ``nextUpdate`` value. * ``x509/ocsp/resp-invalid-signature-oid.der`` - An OCSP response that was modified to contain an MD2 signature algorithm object identifier. +* ``x509/ocsp/resp-single-extension-reason.der`` - An OCSP response that + contains a ``CRLReason`` single extension. +* ``x509/ocsp/resp-sct-extension.der`` - An OCSP response containing a + ``CT Certificate SCTs`` single extension, from the SwissSign OCSP responder. +* ``x509/ocsp/ocsp-army.deps.mil-resp.der`` - An OCSP response containing + multiple ``SINGLERESP`` values. Custom X.509 OCSP Test Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -515,6 +573,49 @@ Custom PKCS12 Test Vectors (``x509/custom/ca/ca.pem``) encrypted via AES 256 CBC with the password ``cryptography`` and no private key. +Custom PKCS7 Test Vectors +~~~~~~~~~~~~~~~~~~~~~~~~~ +* ``pkcs7/isrg.pem`` - A PEM encoded PKCS7 file containing the ISRG X1 root + CA. +* ``pkcs7/amazon-roots.p7b`` - A DER encoded PCKS7 file containing Amazon Root + CA 2 and 3. +* ``pkcs7/enveloped.pem`` - A PEM encoded PKCS7 file with enveloped data. + +Custom OpenSSH Test Vectors +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Generated by +``asymmetric/OpenSSH/gen.sh`` +using command-line tools from OpenSSH_7.6p1 package. + +* ``dsa-nopsw.key``, ``dsa-nopsw.key.pub``, ``dsa-nopsw.key-cert.pub`` - + DSA-1024 private key; and corresponding public key in plain format + and with self-signed certificate. +* ``dsa-psw.key``, ``dsa-psw.key.pub`` - + Password-protected DSA-1024 private key and corresponding public key. + Password is "password". +* ``ecdsa-nopsw.key``, ``ecdsa-nopsw.key.pub``, + ``ecdsa-nopsw.key-cert.pub`` - + SECP256R1 private key; and corresponding public key in plain format + and with self-signed certificate. +* ``ecdsa-psw.key``, ``ecdsa-psw.key.pub`` - + Password-protected SECP384R1 private key and corresponding public key. + Password is "password". +* ``ed25519-nopsw.key``, ``ed25519-nopsw.key.pub``, + ``ed25519-nopsw.key-cert.pub`` - + Ed25519 private key; and corresponding public key in plain format + and with self-signed certificate. +* ``ed25519-psw.key``, ``ed25519-psw.key.pub`` - + Password-protected Ed25519 private key and corresponding public key. + Password is "password". +* ``rsa-nopsw.key``, ``rsa-nopsw.key.pub``, + ``rsa-nopsw.key-cert.pub`` - + RSA-2048 private key; and corresponding public key in plain format + and with self-signed certificate. +* ``rsa-psw.key``, ``rsa-psw.key.pub`` - + Password-protected RSA-2048 private key and corresponding public key. + Password is "password". + Hashes ~~~~~~ @@ -593,6 +694,11 @@ CMAC * AES-128, AES-192, AES-256, 3DES from `NIST SP-800-38B`_ +Poly1305 +~~~~~~~~ + +* Test vectors from :rfc:`7539`. + Creating test vectors --------------------- @@ -629,7 +735,7 @@ header format (substituting the correct information): .. _`IETF`: https://www.ietf.org/ .. _`Project Wycheproof`: https://github.com/google/wycheproof .. _`NIST CAVP`: https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program -.. _`Bruce Schneier's vectors`: https://www.schneier.com/code/vectors.txt +.. _`Bruce Schneier's vectors`: https://www.schneier.com/wp-content/uploads/2015/12/vectors-2.txt .. _`Camellia page`: https://info.isl.ntt.co.jp/crypt/eng/camellia/ .. _`CRYPTREC`: https://www.cryptrec.go.jp .. _`OpenSSL's test vectors`: https://github.com/openssl/openssl/blob/97cf1f6c2854a3a955fd7dd3a1f113deba00c9ef/crypto/evp/evptests.txt#L232 @@ -654,13 +760,16 @@ header format (substituting the correct information): .. _`NIST SP-800-38B`: https://csrc.nist.gov/publications/detail/sp/800-38b/archive/2005-05-01 .. _`NIST PKI Testing`: https://csrc.nist.gov/Projects/PKI-Testing .. _`testx509.pem`: https://github.com/openssl/openssl/blob/master/test/testx509.pem -.. _`DigiCert Global Root G3`: https://cacerts.digicert.com/DigiCertGlobalRootG3.crt +.. _`DigiCert Global Root G3`: http://cacerts.digicert.com/DigiCertGlobalRootG3.crt .. _`root data`: https://hg.mozilla.org/projects/nss/file/25b2922cc564/security/nss/lib/ckfw/builtins/certdata.txt#l2053 .. _`asymmetric/public/PKCS1/dsa.pub.pem`: https://github.com/ruby/ruby/blob/4ccb387f3bc436a08fc6d72c4931994f5de95110/test/openssl/test_pkey_dsa.rb#L53 .. _`Mozilla bug`: https://bugzilla.mozilla.org/show_bug.cgi?id=233586 -.. _`Russian CA`: https://e-trust.gosuslugi.ru/MainCA +.. _`Russian CA`: https://e-trust.gosuslugi.ru/ .. _`test/evptests.txt`: https://github.com/openssl/openssl/blob/2d0b44126763f989a4cbffbffe9d0c7518158bb7/test/evptests.txt .. _`unknown signature OID`: https://bugzilla.mozilla.org/show_bug.cgi?id=405966 .. _`botan`: https://github.com/randombit/botan/blob/57789bdfc55061002b2727d0b32587612829a37c/src/tests/data/pubkey/dh.vec .. _`DHKE`: https://sandilands.info/sgordon/diffie-hellman-secret-key-exchange-with-openssl .. _`Botan's key wrap vectors`: https://github.com/randombit/botan/blob/737f33c09a18500e044dca3e2ae13bd2c08bafdd/src/tests/data/keywrap/nist_key_wrap.vec +.. _`root-ed25519.pem`: https://github.com/openssl/openssl/blob/2a1e2fe145c6eb8e75aa2e1b3a8c3a49384b2852/test/certs/root-ed25519.pem +.. _`server-ed25519-cert.pem`: https://github.com/openssl/openssl/blob/2a1e2fe145c6eb8e75aa2e1b3a8c3a49384b2852/test/certs/server-ed25519-cert.pem +.. _`server-ed448-cert.pem`: https://github.com/openssl/openssl/blob/2a1e2fe145c6eb8e75aa2e1b3a8c3a49384b2852/test/certs/server-ed448-cert.pem diff --git a/docs/doing-a-release.rst b/docs/doing-a-release.rst index e7ee88fa0c12..043d52d28da6 100644 --- a/docs/doing-a-release.rst +++ b/docs/doing-a-release.rst @@ -21,10 +21,10 @@ Verifying OpenSSL version ------------------------- The release process creates wheels bundling OpenSSL for Windows, macOS, and -Linux. Check that the Windows and macOS Jenkins builders have the latest -version of OpenSSL installed and verify that the latest version is present in -the ``pyca/cryptography-manylinux1`` docker containers. If anything is out -of date follow the instructions for upgrading OpenSSL. +Linux. Check that the Windows, macOS, and Linux builders (both +``pyca/cryptography-manylinux1`` and ``pyca/cryptography-manylinux2010``) have +the latest OpenSSL. If anything is out of date follow the instructions for +upgrading OpenSSL. Upgrading OpenSSL ----------------- diff --git a/docs/faq.rst b/docs/faq.rst index 6d876610f7fe..33c5417d12db 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -1,6 +1,33 @@ Frequently asked questions ========================== +.. _faq-howto-handle-deprecation-warning: + +I cannot suppress the deprecation warning that ``cryptography`` emits on import +------------------------------------------------------------------------------- + +.. hint:: + + The deprecation warning emitted on import does not inherit + :py:exc:`DeprecationWarning` but inherits :py:exc:`UserWarning` + instead. + +If your pytest setup follows the best practices of failing on +emitted warnings (``filterwarnings = error``), you may ignore it +by adding the following line at the end of the list:: + + ignore:Python 2 is no longer supported by the Python core team. Support for it is now deprecated in cryptography, and will be removed in a future release.:UserWarning:cryptography + +**Note:** Using ``cryptography.utils.CryptographyDeprecationWarning`` +is not possible here because specifying it triggers +``import cryptography`` internally that emits the warning before +the ignore rule even kicks in. + +Ref: https://github.com/pytest-dev/pytest/issues/7524 + +The same applies when you use :py:func:`~warnings.filterwarnings` in +your code or invoke CPython with :std:option:`-W` command line option. + ``cryptography`` failed to install! ----------------------------------- @@ -82,35 +109,36 @@ Your ``pip`` and/or ``setuptools`` are outdated. Please upgrade to the latest versions with ``pip install -U pip setuptools`` (or on Windows ``python -m pip install -U pip setuptools``). -Installing cryptography with OpenSSL 0.9.8 or 1.0.0 fails ---------------------------------------------------------- +Importing cryptography causes a ``RuntimeError`` about OpenSSL 1.0.2 +-------------------------------------------------------------------- + +The OpenSSL project has dropped support for the 1.0.2 release series. Since it +is no longer receiving security patches from upstream, ``cryptography`` is also +dropping support for it. To fix this issue you should upgrade to a newer +version of OpenSSL (1.1.0 or later). This may require you to upgrade to a newer +operating system. -The OpenSSL project has dropped support for the 0.9.8 and 1.0.0 release series. -Since they are no longer receiving security patches from upstream, +For the 3.2 release, you can set the ``CRYPTOGRAPHY_ALLOW_OPENSSL_102`` +environment variable. Please note that this is *temporary* and will be removed +in ``cryptography`` 3.3. + +Installing cryptography with OpenSSL 0.9.8, 1.0.0, 1.0.1 fails +-------------------------------------------------------------- + +The OpenSSL project has dropped support for the 0.9.8, 1.0.0, and 1.0.1 release +series. Since they are no longer receiving security patches from upstream, ``cryptography`` is also dropping support for them. To fix this issue you should upgrade to a newer version of OpenSSL (1.0.2 or later). This may require you to upgrade to a newer operating system. -Why are there no wheels for Python 3.5+ on Linux or macOS? +Why are there no wheels for Python 3.6+ on Linux or macOS? ---------------------------------------------------------- Our Python3 wheels, for macOS and Linux, are ``abi3`` wheels. This means they -support multiple versions of Python. The Python 3.4 ``abi3`` wheel can be used -with any version of Python greater than or equal to 3.4. Recent versions of +support multiple versions of Python. The Python 3.5 ``abi3`` wheel can be used +with any version of Python greater than or equal to 3.5. Recent versions of ``pip`` will automatically install ``abi3`` wheels. -``ImportError``: ``idna`` is not installed ------------------------------------------- - -``cryptography`` deprecated passing :term:`U-label` strings to various X.509 -constructors in version 2.1 and in version 2.5 moved the ``idna`` dependency -to a ``setuptools`` extra. If you see this exception you should upgrade your -software so that it no longer depends on this deprecated feature. If that is -not yet possible you can also install ``cryptography`` with -``pip install cryptography[idna]`` to automatically install the missing -dependency. This workaround will be available until the feature is fully -removed. - Why can't I import my PEM file? ------------------------------- diff --git a/docs/fernet.rst b/docs/fernet.rst index 9b95621ef888..960f47137850 100644 --- a/docs/fernet.rst +++ b/docs/fernet.rst @@ -23,9 +23,10 @@ has support for implementing key rotation via :class:`MultiFernet`. >>> f.decrypt(token) b'my deep dark secret' - :param bytes key: A URL-safe base64-encoded 32-byte key. This **must** be - kept secret. Anyone with this key is able to create and - read messages. + :param key: A URL-safe base64-encoded 32-byte key. This **must** be + kept secret. Anyone with this key is able to create and + read messages. + :type key: bytes or str .. classmethod:: generate_key() @@ -53,6 +54,28 @@ has support for implementing key rotation via :class:`MultiFernet`. generated in *plaintext*, the time a message was created will therefore be visible to a possible attacker. + .. method:: encrypt_at_time(data, current_time) + + .. versionadded:: 3.0 + + Encrypts data passed using explicitly passed current time. See + :meth:`encrypt` for the documentation of the ``data`` parameter, the + return type and the exceptions raised. + + The motivation behind this method is for the client code to be able to + test token expiration. Since this method can be used in an insecure + manner one should make sure the correct time (``int(time.time())``) + is passed as ``current_time`` outside testing. + + :param int current_time: The current time. + + .. note:: + + Similarly to :meth:`encrypt` the encrypted message contains the + timestamp in *plaintext*, in this case the timestamp is the value + of the ``current_time`` parameter. + + .. method:: decrypt(token, ttl=None) Decrypts a Fernet token. If successfully decrypted you will receive the @@ -80,6 +103,23 @@ has support for implementing key rotation via :class:`MultiFernet`. :raises TypeError: This exception is raised if ``token`` is not ``bytes``. + .. method:: decrypt_at_time(token, ttl, current_time) + + .. versionadded:: 3.0 + + Decrypts a token using explicitly passed current time. See + :meth:`decrypt` for the documentation of the ``token`` and ``ttl`` + parameters (``ttl`` is required here), the return type and the exceptions + raised. + + The motivation behind this method is for the client code to be able to + test token expiration. Since this method can be used in an insecure + manner one should make sure the correct time (``int(time.time())``) + is passed as ``current_time`` outside testing. + + :param int current_time: The current time. + + .. method:: extract_timestamp(token) .. versionadded:: 2.3 @@ -189,7 +229,6 @@ password through a key derivation function such as >>> import base64 >>> import os >>> from cryptography.fernet import Fernet - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC >>> password = b"password" @@ -199,7 +238,6 @@ password through a key derivation function such as ... length=32, ... salt=salt, ... iterations=100000, - ... backend=default_backend() ... ) >>> key = base64.urlsafe_b64encode(kdf.derive(password)) >>> f = Fernet(key) diff --git a/docs/hazmat/backends/index.rst b/docs/hazmat/backends/index.rst index a8a1ff301f09..97dbc869b8ce 100644 --- a/docs/hazmat/backends/index.rst +++ b/docs/hazmat/backends/index.rst @@ -8,10 +8,13 @@ Getting a backend .. currentmodule:: cryptography.hazmat.backends -``cryptography`` was originally designed to support multiple backends, but -this design has been deprecated. +``cryptography`` was designed to support multiple cryptographic backends, but +consumers rarely need this flexibility. Starting with version 3.1 ``backend`` +arguments are optional and the default backend will automatically be selected +if none is specified. -You can get the default backend by calling :func:`~default_backend`. +On older versions you can get the default backend by calling +:func:`~default_backend`. .. function:: default_backend() diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst index 2c2d70ec8140..36dd3a7a5a1e 100644 --- a/docs/hazmat/backends/interfaces.rst +++ b/docs/hazmat/backends/interfaces.rst @@ -159,14 +159,13 @@ A specific ``backend`` may provide one or more of these interfaces. .. method:: create_cmac_ctx(algorithm) Create a - :class:`~cryptography.hazmat.primitives.mac.MACContext` that + context that uses the specified ``algorithm`` to calculate a message authentication code. :param algorithm: An instance of :class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm`. - :returns: - :class:`~cryptography.hazmat.primitives.mac.MACContext` + :returns: CMAC object. .. class:: PBKDF2HMACBackend diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst index 07ae74a27469..0e695279dbe4 100644 --- a/docs/hazmat/backends/openssl.rst +++ b/docs/hazmat/backends/openssl.rst @@ -3,7 +3,7 @@ OpenSSL backend =============== -The `OpenSSL`_ C library. Cryptography supports OpenSSL version 1.0.1 and +The `OpenSSL`_ C library. Cryptography supports OpenSSL version 1.0.2 and greater. .. data:: cryptography.hazmat.backends.openssl.backend @@ -68,6 +68,12 @@ greater. 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 + these versions. + 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 @@ -106,7 +112,7 @@ seeded from the same pool as ``/dev/random``. +------------------------------------------+------------------------------+ | Windows | ``CryptGenRandom()`` | +------------------------------------------+------------------------------+ -| Linux >= 3.17 with working | ``getrandom(GRND_NONBLOCK)`` | +| Linux >= 3.17 with working | ``getrandom()`` | | ``SYS_getrandom`` syscall | | +------------------------------------------+------------------------------+ | OpenBSD >= 5.6 | ``getentropy()`` | diff --git a/docs/hazmat/bindings/index.rst b/docs/hazmat/bindings/index.rst deleted file mode 100644 index 655f4620d492..000000000000 --- a/docs/hazmat/bindings/index.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. hazmat:: - -Bindings -======== - -.. module:: cryptography.hazmat.bindings - -``cryptography`` aims to provide low-level CFFI based bindings to multiple -native C libraries. These provide no automatic initialization of the library -and may not provide complete wrappers for its API. - -Using these functions directly is likely to require you to be careful in -managing memory allocation, locking and other resources. - - -Individual bindings -------------------- - -.. toctree:: - :maxdepth: 1 - - openssl diff --git a/docs/hazmat/bindings/openssl.rst b/docs/hazmat/bindings/openssl.rst deleted file mode 100644 index ac65aa97b09b..000000000000 --- a/docs/hazmat/bindings/openssl.rst +++ /dev/null @@ -1,48 +0,0 @@ -.. hazmat:: - -OpenSSL binding -=============== - -.. currentmodule:: cryptography.hazmat.bindings.openssl.binding - -These are `CFFI`_ bindings to the `OpenSSL`_ C library. Cryptography supports -OpenSSL version 1.0.1 and greater. - -.. class:: cryptography.hazmat.bindings.openssl.binding.Binding() - - This is the exposed API for the OpenSSL bindings. It has two public - attributes: - - .. attribute:: ffi - - This is a ``cffi.FFI`` instance. It can be used to allocate and - otherwise manipulate OpenSSL structures. - - .. attribute:: lib - - This is a ``cffi`` library. It can be used to call OpenSSL functions, - and access constants. - - .. classmethod:: init_static_locks - - Enables the best available locking callback for OpenSSL. - See :ref:`openssl-threading`. - -.. _openssl-threading: - -Threading ---------- - -``cryptography`` enables OpenSSLs `thread safety facilities`_ in two different -ways depending on the configuration of your system. Normally the locking -callbacks provided by your Python implementation specifically for OpenSSL will -be used. However, if you have linked ``cryptography`` to a different version of -OpenSSL than that used by your Python implementation we enable an alternative -locking callback. This version is implemented in Python and so may result in -lower performance in some situations. In particular parallelism is reduced -because it has to acquire the GIL whenever any lock operations occur within -OpenSSL. - -.. _`CFFI`: https://cffi.readthedocs.io -.. _`OpenSSL`: https://www.openssl.org/ -.. _`thread safety facilities`: https://www.openssl.org/docs/man1.0.2/crypto/threads.html diff --git a/docs/hazmat/primitives/asymmetric/dh.rst b/docs/hazmat/primitives/asymmetric/dh.rst index edfe614362a4..6b47da089378 100644 --- a/docs/hazmat/primitives/asymmetric/dh.rst +++ b/docs/hazmat/primitives/asymmetric/dh.rst @@ -31,13 +31,11 @@ present. .. code-block:: pycon - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric import dh >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF >>> # Generate some parameters. These can be reused. - >>> parameters = dh.generate_parameters(generator=2, key_size=2048, - ... backend=default_backend()) + >>> parameters = dh.generate_parameters(generator=2, key_size=2048) >>> # Generate a private key for use in the exchange. >>> server_private_key = parameters.generate_private_key() >>> # In a real handshake the peer is a remote client. For this @@ -51,7 +49,6 @@ present. ... length=32, ... salt=None, ... info=b'handshake data', - ... backend=default_backend() ... ).derive(shared_key) >>> # And now we can demonstrate that the handshake performed in the >>> # opposite direction gives the same final value @@ -63,7 +60,6 @@ present. ... length=32, ... salt=None, ... info=b'handshake data', - ... backend=default_backend() ... ).derive(same_shared_key) >>> derived_key == same_derived_key @@ -75,13 +71,11 @@ example of the ephemeral form: .. code-block:: pycon - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric import dh >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF >>> # Generate some parameters. These can be reused. - >>> parameters = dh.generate_parameters(generator=2, key_size=2048, - ... backend=default_backend()) + >>> parameters = dh.generate_parameters(generator=2, key_size=2048) >>> # Generate a private key for use in the exchange. >>> private_key = parameters.generate_private_key() >>> # In a real handshake the peer_public_key will be received from the @@ -96,7 +90,6 @@ example of the ephemeral form: ... length=32, ... salt=None, ... info=b'handshake data', - ... backend=default_backend() ... ).derive(shared_key) >>> # For the next handshake we MUST generate another private key, but >>> # we can reuse the parameters. @@ -108,7 +101,6 @@ example of the ephemeral form: ... length=32, ... salt=None, ... info=b'handshake data', - ... backend=default_backend() ... ).derive(shared_key_2) To assemble a :class:`~DHParameters` and a :class:`~DHPublicKey` from @@ -118,9 +110,9 @@ example, if **p**, **g**, and **y** are :class:`int` objects received from a peer:: pn = dh.DHParameterNumbers(p, g) - parameters = pn.parameters(default_backend()) + parameters = pn.parameters() peer_public_numbers = dh.DHPublicNumbers(y, pn) - peer_public_key = peer_public_numbers.public_key(default_backend()) + peer_public_key = peer_public_numbers.public_key() See also the :class:`~cryptography.hazmat.backends.interfaces.DHBackend` @@ -129,7 +121,7 @@ API for additional functionality. Group parameters ~~~~~~~~~~~~~~~~ -.. function:: generate_parameters(generator, key_size, backend) +.. function:: generate_parameters(generator, key_size, backend=None) .. versionadded:: 1.7 @@ -140,7 +132,7 @@ Group parameters :param key_size: The bit length of the prime modulus to generate. - :param backend: A + :param backend: An optional :class:`~cryptography.hazmat.backends.interfaces.DHBackend` instance. @@ -349,11 +341,11 @@ Numbers p subgroup order value. - .. method:: parameters(backend) + .. method:: parameters(backend=None) .. versionadded:: 1.7 - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.DHBackend`. :returns: A new instance of :class:`DHParameters`. @@ -377,11 +369,11 @@ Numbers The private value. - .. method:: private_key(backend) + .. method:: private_key(backend=None) .. versionadded:: 1.7 - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.DHBackend`. :returns: A new instance of :class:`DHPrivateKey`. @@ -405,11 +397,11 @@ Numbers The public value. - .. method:: public_key(backend) + .. method:: public_key(backend=None) .. versionadded:: 1.7 - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.DHBackend`. :returns: A new instance of :class:`DHPublicKey`. diff --git a/docs/hazmat/primitives/asymmetric/dsa.rst b/docs/hazmat/primitives/asymmetric/dsa.rst index 7b0598693f3c..788e4270b886 100644 --- a/docs/hazmat/primitives/asymmetric/dsa.rst +++ b/docs/hazmat/primitives/asymmetric/dsa.rst @@ -5,26 +5,36 @@ DSA .. module:: cryptography.hazmat.primitives.asymmetric.dsa +.. note:: + + DSA is a **legacy algorithm** and should generally be avoided in favor of + choices like + :doc:`EdDSA using curve25519` or + :doc:`ECDSA`. + `DSA`_ is a `public-key`_ algorithm for signing messages. Generation ~~~~~~~~~~ -.. function:: generate_private_key(key_size, backend) +.. function:: generate_private_key(key_size, backend=None) .. versionadded:: 0.5 + .. versionchanged:: 3.0 + + Added support for 4096-bit keys for some legacy applications that + continue to use DSA despite the wider cryptographic community's + `ongoing protestations`_. + Generate a DSA private key from the given key size. This function will generate a new set of parameters and key in one step. :param int key_size: The length of the modulus in :term:`bits`. It should - be either 1024, 2048 or 3072. For keys generated in 2015 this should - be `at least 2048`_ (See page 41). Note that some applications - (such as SSH) have not yet gained support for larger key sizes - specified in FIPS 186-3 and are still restricted to only the - 1024-bit keys specified in FIPS 186-2. + be either 1024, 2048, 3072, or 4096. For keys generated in 2015 this + should be `at least 2048`_ (See page 41). - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.DSABackend`. :return: An instance of @@ -34,20 +44,23 @@ Generation the provided ``backend`` does not implement :class:`~cryptography.hazmat.backends.interfaces.DSABackend` -.. function:: generate_parameters(key_size, backend) +.. function:: generate_parameters(key_size, backend=None) .. versionadded:: 0.5 + .. versionchanged:: 3.0 + + Added support for 4096-bit keys for some legacy applications that + continue to use DSA despite the wider cryptographic community's + `ongoing protestations`_. + Generate DSA parameters using the provided ``backend``. :param int key_size: The length of :attr:`~DSAParameterNumbers.q`. It - should be either 1024, 2048 or 3072. For keys generated in 2015 this - should be `at least 2048`_ (See page 41). Note that some applications - (such as SSH) have not yet gained support for larger key sizes - specified in FIPS 186-3 and are still restricted to only the - 1024-bit keys specified in FIPS 186-2. + should be either 1024, 2048, 3072, or 4096. For keys generated in 2015 + this should be `at least 2048`_ (See page 41). - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.DSABackend`. :return: An instance of @@ -65,12 +78,10 @@ instance. .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric import dsa >>> private_key = dsa.generate_private_key( ... key_size=1024, - ... backend=default_backend() ... ) >>> data = b"this is some data I'd like to sign" >>> signature = private_key.sign( @@ -90,7 +101,7 @@ separately and pass that value using >>> from cryptography.hazmat.primitives.asymmetric import utils >>> chosen_hash = hashes.SHA256() - >>> hasher = hashes.Hash(chosen_hash, default_backend()) + >>> hasher = hashes.Hash(chosen_hash) >>> hasher.update(b"data & ") >>> hasher.update(b"more data") >>> digest = hasher.finalize() @@ -133,7 +144,7 @@ separately and pass that value using .. doctest:: >>> chosen_hash = hashes.SHA256() - >>> hasher = hashes.Hash(chosen_hash, default_backend()) + >>> hasher = hashes.Hash(chosen_hash) >>> hasher.update(b"data & ") >>> hasher.update(b"more data") >>> digest = hasher.finalize() @@ -170,9 +181,9 @@ Numbers The generator. - .. method:: parameters(backend) + .. method:: parameters(backend=None) - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.DSABackend`. :returns: A new instance of @@ -197,9 +208,9 @@ Numbers The :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAParameterNumbers` associated with the public key. - .. method:: public_key(backend) + .. method:: public_key(backend=None) - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.DSABackend`. :returns: A new instance of @@ -229,9 +240,9 @@ Numbers The :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers` associated with the private key. - .. method:: private_key(backend) + .. method:: private_key(backend=None) - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.DSABackend`. :returns: A new instance of @@ -344,7 +355,8 @@ Key interfaces :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM` or :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`), format ( - :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.TraditionalOpenSSL` + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.TraditionalOpenSSL`, + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.OpenSSH` or :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`) and encryption algorithm (such as @@ -445,3 +457,4 @@ Key interfaces .. _`public-key`: https://en.wikipedia.org/wiki/Public-key_cryptography .. _`FIPS 186-4`: https://csrc.nist.gov/publications/detail/fips/186/4/final .. _`at least 2048`: https://www.cosic.esat.kuleuven.be/ecrypt/ecrypt2/documents/D.SPA.20.pdf +.. _`ongoing protestations`: https://buttondown.email/cryptography-dispatches/archive/cryptography-dispatches-dsa-is-past-its-prime/ diff --git a/docs/hazmat/primitives/asymmetric/ec.rst b/docs/hazmat/primitives/asymmetric/ec.rst index d89fde3da505..5691560f3c76 100644 --- a/docs/hazmat/primitives/asymmetric/ec.rst +++ b/docs/hazmat/primitives/asymmetric/ec.rst @@ -6,7 +6,7 @@ Elliptic curve cryptography .. module:: cryptography.hazmat.primitives.asymmetric.ec -.. function:: generate_private_key(curve, backend) +.. function:: generate_private_key(curve, backend=None) .. versionadded:: 0.5 @@ -14,13 +14,13 @@ Elliptic curve cryptography :param curve: An instance of :class:`EllipticCurve`. - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`. :returns: A new instance of :class:`EllipticCurvePrivateKey`. -.. function:: derive_private_key(private_value, curve, backend) +.. function:: derive_private_key(private_value, curve, backend=None) .. versionadded:: 1.6 @@ -31,7 +31,7 @@ Elliptic curve cryptography :param curve: An instance of :class:`EllipticCurve`. - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`. :returns: A new instance of :class:`EllipticCurvePrivateKey`. @@ -47,16 +47,19 @@ Elliptic Curve Signature Algorithms The ECDSA signature algorithm first standardized in NIST publication `FIPS 186-3`_, and later in `FIPS 186-4`_. + Note that while elliptic curve keys can be used for both signing and key + exchange, this is `bad cryptographic practice`_. Instead, users should + generate separate signing and ECDH keys. + :param algorithm: An instance of :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric import ec >>> private_key = ec.generate_private_key( - ... ec.SECP384R1(), default_backend() + ... ec.SECP384R1() ... ) >>> data = b"this is some data I'd like to sign" >>> signature = private_key.sign( @@ -64,7 +67,7 @@ Elliptic Curve Signature Algorithms ... ec.ECDSA(hashes.SHA256()) ... ) - The ``signature`` is a ``bytes`` object, whose contents is DER encoded as + The ``signature`` is a ``bytes`` object, whose contents are DER encoded as described in :rfc:`3279`. This can be decoded using :func:`~cryptography.hazmat.primitives.asymmetric.utils.decode_dss_signature`. @@ -76,7 +79,7 @@ Elliptic Curve Signature Algorithms >>> from cryptography.hazmat.primitives.asymmetric import utils >>> chosen_hash = hashes.SHA256() - >>> hasher = hashes.Hash(chosen_hash, default_backend()) + >>> hasher = hashes.Hash(chosen_hash) >>> hasher.update(b"data & ") >>> hasher.update(b"more data") >>> digest = hasher.finalize() @@ -86,13 +89,18 @@ Elliptic Curve Signature Algorithms ... ) - Verification requires the public key, the signature itself, the signed - data, and knowledge of the hashing algorithm that was used when producing - the signature: + Verification requires the public key, the DER-encoded signature itself, the + signed data, and knowledge of the hashing algorithm that was used when + producing the signature: >>> public_key = private_key.public_key() >>> public_key.verify(signature, data, ec.ECDSA(hashes.SHA256())) + As above, the ``signature`` is a ``bytes`` object whose contents are DER + encoded as described in :rfc:`3279`. It can be created from a raw ``(r,s)`` + pair by using + :func:`~cryptography.hazmat.primitives.asymmetric.utils.encode_dss_signature`. + If the signature is not valid, an :class:`~cryptography.exceptions.InvalidSignature` exception will be raised. @@ -103,7 +111,7 @@ Elliptic Curve Signature Algorithms .. doctest:: >>> chosen_hash = hashes.SHA256() - >>> hasher = hashes.Hash(chosen_hash, default_backend()) + >>> hasher = hashes.Hash(chosen_hash) >>> hasher.update(b"data & ") >>> hasher.update(b"more data") >>> digest = hasher.finalize() @@ -139,12 +147,12 @@ Elliptic Curve Signature Algorithms The private value. - .. method:: private_key(backend) + .. method:: private_key(backend=None) Convert a collection of numbers into a private key suitable for doing actual cryptographic operations. - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`. :returns: A new instance of :class:`EllipticCurvePrivateKey`. @@ -181,12 +189,12 @@ Elliptic Curve Signature Algorithms The affine y component of the public point used for verifying. - .. method:: public_key(backend) + .. method:: public_key(backend=None) Convert a collection of numbers into a public key suitable for doing actual cryptographic operations. - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend`. :raises ValueError: Raised if the point is invalid for the curve. @@ -249,6 +257,10 @@ Elliptic Curve Key Exchange algorithm key, derivation of multiple keys, and destroys any structure that may be present. + Note that while elliptic curve keys can be used for both signing and key + exchange, this is `bad cryptographic practice`_. Instead, users should + generate separate signing and ECDH keys. + .. warning:: This example does not give `forward secrecy`_ and is only provided as a @@ -257,18 +269,17 @@ Elliptic Curve Key Exchange algorithm .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric import ec >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF >>> # Generate a private key for use in the exchange. >>> server_private_key = ec.generate_private_key( - ... ec.SECP384R1(), default_backend() + ... ec.SECP384R1() ... ) >>> # In a real handshake the peer is a remote client. For this >>> # example we'll generate another local private key though. >>> peer_private_key = ec.generate_private_key( - ... ec.SECP384R1(), default_backend() + ... ec.SECP384R1() ... ) >>> shared_key = server_private_key.exchange( ... ec.ECDH(), peer_private_key.public_key()) @@ -278,7 +289,6 @@ Elliptic Curve Key Exchange algorithm ... length=32, ... salt=None, ... info=b'handshake data', - ... backend=default_backend() ... ).derive(shared_key) >>> # And now we can demonstrate that the handshake performed in the >>> # opposite direction gives the same final value @@ -290,7 +300,6 @@ Elliptic Curve Key Exchange algorithm ... length=32, ... salt=None, ... info=b'handshake data', - ... backend=default_backend() ... ).derive(same_shared_key) >>> derived_key == same_derived_key True @@ -303,19 +312,18 @@ Elliptic Curve Key Exchange algorithm .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric import ec >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF >>> # Generate a private key for use in the exchange. >>> private_key = ec.generate_private_key( - ... ec.SECP384R1(), default_backend() + ... ec.SECP384R1() ... ) >>> # In a real handshake the peer_public_key will be received from the >>> # other party. For this example we'll generate another private key >>> # and get a public key from that. >>> peer_public_key = ec.generate_private_key( - ... ec.SECP384R1(), default_backend() + ... ec.SECP384R1() ... ).public_key() >>> shared_key = private_key.exchange(ec.ECDH(), peer_public_key) >>> # Perform key derivation. @@ -324,14 +332,13 @@ Elliptic Curve Key Exchange algorithm ... length=32, ... salt=None, ... info=b'handshake data', - ... backend=default_backend() ... ).derive(shared_key) >>> # For the next handshake we MUST generate another private key. >>> private_key_2 = ec.generate_private_key( - ... ec.SECP384R1(), default_backend() + ... ec.SECP384R1() ... ) >>> peer_public_key_2 = ec.generate_private_key( - ... ec.SECP384R1(), default_backend() + ... ec.SECP384R1() ... ).public_key() >>> shared_key_2 = private_key_2.exchange(ec.ECDH(), peer_public_key_2) >>> derived_key_2 = HKDF( @@ -339,7 +346,6 @@ Elliptic Curve Key Exchange algorithm ... length=32, ... salt=None, ... info=b'handshake data', - ... backend=default_backend() ... ).derive(shared_key_2) Elliptic Curves @@ -601,7 +607,16 @@ Key Interfaces :param signature_algorithm: An instance of :class:`EllipticCurveSignatureAlgorithm`, such as :class:`ECDSA`. - :return bytes: Signature. + :return bytes: The signature as a ``bytes`` object, whose contents are + DER encoded as described in :rfc:`3279`. This can be decoded using + :func:`~cryptography.hazmat.primitives.asymmetric.utils.decode_dss_signature`, + which returns the decoded tuple ``(r, s)``. + + .. attribute:: curve + + :type: :class:`EllipticCurve` + + The EllipticCurve that this key is on. .. attribute:: key_size @@ -633,7 +648,8 @@ Key Interfaces :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM` or :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`), format ( - :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.TraditionalOpenSSL` + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.TraditionalOpenSSL`, + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.OpenSSH` or :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`) and encryption algorithm (such as @@ -704,7 +720,10 @@ Key Interfaces Verify one block of data was signed by the private key associated with this public key. - :param bytes signature: The signature to verify. + :param bytes signature: The DER-encoded signature to verify. + A raw signature may be DER-encoded by splitting it into the ``r`` + and ``s`` components and passing them into + :func:`~cryptography.hazmat.primitives.asymmetric.utils.encode_dss_signature`. :param bytes data: The message string that was signed. @@ -761,12 +780,10 @@ This sample demonstrates how to generate a private key and serialize it. .. doctest:: - >>> from cryptography.hazmat.backends import default_backend - >>> from cryptography.hazmat.primitives import hashes - >>> from cryptography.hazmat.primitives.asymmetric import ec >>> from cryptography.hazmat.primitives import serialization + >>> from cryptography.hazmat.primitives.asymmetric import ec - >>> private_key = ec.generate_private_key(ec.SECP384R1(), default_backend()) + >>> private_key = ec.generate_private_key(ec.SECP384R1()) >>> serialized_private = private_key.private_bytes( ... encoding=serialization.Encoding.PEM, @@ -806,14 +823,12 @@ in PEM format. >>> loaded_public_key = serialization.load_pem_public_key( ... serialized_public, - ... backend=default_backend() ... ) >>> loaded_private_key = serialization.load_pem_private_key( ... serialized_private, ... # or password=None, if in plain text ... password=b'testpassword', - ... backend=default_backend() ... ) @@ -926,6 +941,21 @@ Elliptic Curve Object Identifiers Corresponds to the dotted string ``"1.3.132.0.39"``. +.. function:: get_curve_for_oid(oid) + + .. versionadded:: 2.6 + + A function that takes an :class:`~cryptography.x509.ObjectIdentifier` + and returns the associated elliptic curve class. + + :param oid: An instance of + :class:`~cryptography.x509.ObjectIdentifier`. + + :returns: The matching elliptic curve class. The returned class conforms + to the :class:`EllipticCurve` interface. + + :raises LookupError: Raised if no elliptic curve is found that matches + the provided object identifier. .. _`FIPS 186-3`: https://csrc.nist.gov/csrc/media/publications/fips/186/3/archive/2009-06-25/documents/fips_186-3.pdf .. _`FIPS 186-4`: https://csrc.nist.gov/publications/detail/fips/186/4/final @@ -939,4 +969,5 @@ Elliptic Curve Object Identifiers .. _`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`: http://www.secg.org/sec1-v2.pdf +.. _`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/ed25519.rst b/docs/hazmat/primitives/asymmetric/ed25519.rst new file mode 100644 index 000000000000..47d95ec1b9da --- /dev/null +++ b/docs/hazmat/primitives/asymmetric/ed25519.rst @@ -0,0 +1,168 @@ +.. hazmat:: + +Ed25519 signing +=============== + +.. currentmodule:: cryptography.hazmat.primitives.asymmetric.ed25519 + + +Ed25519 is an elliptic curve signing algorithm using `EdDSA`_ and +`Curve25519`_. If you do not have legacy interoperability concerns then you +should strongly consider using this signature algorithm. + + +Signing & Verification +~~~~~~~~~~~~~~~~~~~~~~ + +.. doctest:: + + >>> from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey + >>> private_key = Ed25519PrivateKey.generate() + >>> signature = private_key.sign(b"my authenticated message") + >>> public_key = private_key.public_key() + >>> # Raises InvalidSignature if verification fails + >>> public_key.verify(signature, b"my authenticated message") + +Key interfaces +~~~~~~~~~~~~~~ + +.. class:: Ed25519PrivateKey + + .. versionadded:: 2.6 + + .. classmethod:: generate() + + Generate an Ed25519 private key. + + :returns: :class:`Ed25519PrivateKey` + + .. classmethod:: from_private_bytes(data) + + :param data: 32 byte private key. + :type data: :term:`bytes-like` + + :returns: :class:`Ed25519PrivateKey` + + .. doctest:: + + >>> from cryptography.hazmat.primitives import serialization + >>> from cryptography.hazmat.primitives.asymmetric import ed25519 + >>> private_key = ed25519.Ed25519PrivateKey.generate() + >>> private_bytes = private_key.private_bytes( + ... encoding=serialization.Encoding.Raw, + ... format=serialization.PrivateFormat.Raw, + ... encryption_algorithm=serialization.NoEncryption() + ... ) + >>> loaded_private_key = ed25519.Ed25519PrivateKey.from_private_bytes(private_bytes) + + + .. method:: public_key() + + :returns: :class:`Ed25519PublicKey` + + .. method:: sign(data) + + :param bytes data: The data to sign. + + :returns bytes: The 64 byte signature. + + .. method:: private_bytes(encoding, format, encryption_algorithm) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`, + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.OpenSSH` + or + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + ) are chosen to define the exact serialization. + + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.PrivateFormat` + enum. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8` or + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.OpenSSH`. + + :param encryption_algorithm: An instance of an object conforming to the + :class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption` + interface. + + :return bytes: Serialized key. + +.. class:: Ed25519PublicKey + + .. versionadded:: 2.6 + + .. classmethod:: from_public_bytes(data) + + :param bytes data: 32 byte public key. + + :returns: :class:`Ed25519PublicKey` + + .. doctest:: + + >>> from cryptography.hazmat.primitives import serialization + >>> from cryptography.hazmat.primitives.asymmetric import ed25519 + >>> private_key = ed25519.Ed25519PrivateKey.generate() + >>> public_key = private_key.public_key() + >>> public_bytes = public_key.public_bytes( + ... encoding=serialization.Encoding.Raw, + ... format=serialization.PublicFormat.Raw + ... ) + >>> loaded_public_key = ed25519.Ed25519PublicKey.from_public_bytes(public_bytes) + + .. method:: public_bytes(encoding, format) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.OpenSSH`, + or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`, + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.OpenSSH` + , or + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + ) are chosen to define the exact serialization. + + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.PublicFormat` + enum. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw`. + If ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.OpenSSH` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.OpenSSH`. + In all other cases ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`. + + :returns bytes: The public key bytes. + + .. method:: verify(signature, data) + + :param bytes signature: The signature to verify. + + :param bytes data: The data to verify. + + :raises cryptography.exceptions.InvalidSignature: Raised when the + signature cannot be verified. + + + +.. _`EdDSA`: https://en.wikipedia.org/wiki/EdDSA +.. _`Curve25519`: https://en.wikipedia.org/wiki/Curve25519 diff --git a/docs/hazmat/primitives/asymmetric/ed448.rst b/docs/hazmat/primitives/asymmetric/ed448.rst new file mode 100644 index 000000000000..fb79dcb61ba3 --- /dev/null +++ b/docs/hazmat/primitives/asymmetric/ed448.rst @@ -0,0 +1,131 @@ +.. hazmat:: + +Ed448 signing +============= + +.. currentmodule:: cryptography.hazmat.primitives.asymmetric.ed448 + + +Ed448 is an elliptic curve signing algorithm using `EdDSA`_. + + +Signing & Verification +~~~~~~~~~~~~~~~~~~~~~~ + +.. doctest:: + + >>> from cryptography.hazmat.primitives.asymmetric.ed448 import Ed448PrivateKey + >>> private_key = Ed448PrivateKey.generate() + >>> signature = private_key.sign(b"my authenticated message") + >>> public_key = private_key.public_key() + >>> # Raises InvalidSignature if verification fails + >>> public_key.verify(signature, b"my authenticated message") + +Key interfaces +~~~~~~~~~~~~~~ + +.. class:: Ed448PrivateKey + + .. versionadded:: 2.6 + + .. classmethod:: generate() + + Generate an Ed448 private key. + + :returns: :class:`Ed448PrivateKey` + + .. classmethod:: from_private_bytes(data) + + :param data: 57 byte private key. + :type data: :term:`bytes-like` + + :returns: :class:`Ed448PrivateKey` + + .. method:: public_key() + + :returns: :class:`Ed448PublicKey` + + .. method:: sign(data) + + :param bytes data: The data to sign. + + :returns bytes: The 114 byte signature. + + .. method:: private_bytes(encoding, format, encryption_algorithm) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8` + or + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + ) are chosen to define the exact serialization. + + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.PrivateFormat` + enum. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`. + + :param encryption_algorithm: An instance of an object conforming to the + :class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption` + interface. + + :return bytes: Serialized key. + +.. class:: Ed448PublicKey + + .. versionadded:: 2.6 + + .. classmethod:: from_public_bytes(data) + + :param bytes data: 57 byte public key. + + :returns: :class:`Ed448PublicKey` + + .. method:: public_bytes(encoding, format) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo` + or + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + ) are chosen to define the exact serialization. + + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.PublicFormat` + enum. If the ``encoding`` is + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.Raw` + then ``format`` must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.Raw` + , otherwise it must be + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`. + + :returns bytes: The public key bytes. + + .. method:: verify(signature, data) + + :param bytes signature: The signature to verify. + + :param bytes data: The data to verify. + + :raises cryptography.exceptions.InvalidSignature: Raised when the + signature cannot be verified. + + + +.. _`EdDSA`: https://en.wikipedia.org/wiki/EdDSA diff --git a/docs/hazmat/primitives/asymmetric/index.rst b/docs/hazmat/primitives/asymmetric/index.rst index 1561c59f1be0..c27e1781e46e 100644 --- a/docs/hazmat/primitives/asymmetric/index.rst +++ b/docs/hazmat/primitives/asymmetric/index.rst @@ -23,7 +23,9 @@ private key is able to decrypt it. .. toctree:: :maxdepth: 1 + ed25519 x25519 + ed448 x448 ec rsa diff --git a/docs/hazmat/primitives/asymmetric/rsa.rst b/docs/hazmat/primitives/asymmetric/rsa.rst index dab909646795..b8060e4740fd 100644 --- a/docs/hazmat/primitives/asymmetric/rsa.rst +++ b/docs/hazmat/primitives/asymmetric/rsa.rst @@ -14,10 +14,14 @@ Unlike symmetric cryptography, where the key is typically just a random series of bytes, RSA keys have a complex internal structure with `specific mathematical properties`_. -.. function:: generate_private_key(public_exponent, key_size, backend) +.. function:: generate_private_key(public_exponent, key_size, backend=None) .. versionadded:: 0.5 + .. versionchanged:: 3.0 + + Tightened restrictions on ``public_exponent``. + Generates a new RSA private key using the provided ``backend``. ``key_size`` describes how many :term:`bits` long the key should be. Larger keys provide more security; currently ``1024`` and below are considered @@ -28,24 +32,22 @@ mathematical properties`_. .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives.asymmetric import rsa >>> private_key = rsa.generate_private_key( ... public_exponent=65537, ... key_size=2048, - ... backend=default_backend() ... ) :param int public_exponent: The public exponent of the new key. - Usually one of the small Fermat primes 3, 5, 17, 257, 65537. If in - doubt you should `use 65537`_. + Either 65537 or 3 (for legacy purposes). Almost everyone should + `use 65537`_. :param int key_size: The length of the modulus in :term:`bits`. For keys generated in 2015 it is strongly recommended to be `at least 2048`_ (See page 41). It must not be less than 512. Some backends may have additional limitations. - :param backend: A backend which implements + :param backend: An optional backend which implements :class:`~cryptography.hazmat.backends.interfaces.RSABackend`. :return: An instance of @@ -64,14 +66,12 @@ markers), you can load it: .. code-block:: pycon - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import serialization >>> with open("path/to/key.pem", "rb") as key_file: ... private_key = serialization.load_pem_private_key( ... key_file.read(), ... password=None, - ... backend=default_backend() ... ) Serialized keys may optionally be encrypted on disk using a password. In this @@ -167,7 +167,7 @@ separately and pass that value using >>> from cryptography.hazmat.primitives.asymmetric import utils >>> chosen_hash = hashes.SHA256() - >>> hasher = hashes.Hash(chosen_hash, default_backend()) + >>> hasher = hashes.Hash(chosen_hash) >>> hasher.update(b"data & ") >>> hasher.update(b"more data") >>> digest = hasher.finalize() @@ -217,7 +217,7 @@ separately and pass that value using .. doctest:: >>> chosen_hash = hashes.SHA256() - >>> hasher = hashes.Hash(chosen_hash, default_backend()) + >>> hasher = hashes.Hash(chosen_hash) >>> hasher.update(b"data & ") >>> hasher.update(b"more data") >>> digest = hasher.finalize() @@ -399,9 +399,9 @@ is unavailable. The public exponent. - .. method:: public_key(backend) + .. method:: public_key(backend=None) - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.RSABackend`. :returns: A new instance of @@ -466,9 +466,9 @@ is unavailable. A `Chinese remainder theorem`_ coefficient used to speed up RSA operations. Calculated as: q\ :sup:`-1` mod p - .. method:: private_key(backend) + .. method:: private_key(backend=None) - :param backend: A new instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.RSABackend`. :returns: An instance of @@ -607,7 +607,8 @@ Key interfaces :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM` or :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`), format ( - :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.TraditionalOpenSSL` + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.TraditionalOpenSSL`, + :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.OpenSSH` or :attr:`~cryptography.hazmat.primitives.serialization.PrivateFormat.PKCS8`) and encryption algorithm (such as diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index dbb2bb63eb22..6b2e858db9af 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -88,10 +88,9 @@ methods. .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives.asymmetric import dsa, rsa >>> from cryptography.hazmat.primitives.serialization import load_pem_private_key - >>> key = load_pem_private_key(pem_data, password=None, backend=default_backend()) + >>> key = load_pem_private_key(pem_data, password=None) >>> if isinstance(key, rsa.RSAPrivateKey): ... signature = sign_with_rsa_key(key, message) ... elif isinstance(key, dsa.DSAPrivateKey): @@ -126,7 +125,7 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END extract the public key with :meth:`Certificate.public_key `. -.. function:: load_pem_private_key(data, password, backend) +.. function:: load_pem_private_key(data, password, backend=None) .. versionadded:: 0.6 @@ -140,7 +139,7 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END be ``None`` if the private key is not encrypted. :type data: :term:`bytes-like` - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend`. :returns: One of @@ -162,7 +161,7 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END is of a type that is not supported by the backend or if the key is encrypted with a symmetric cipher that is not supported by the backend. -.. function:: load_pem_public_key(data, backend) +.. function:: load_pem_public_key(data, backend=None) .. versionadded:: 0.6 @@ -173,13 +172,13 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END .. doctest:: >>> from cryptography.hazmat.primitives.serialization import load_pem_public_key - >>> key = load_pem_public_key(public_pem_data, backend=default_backend()) + >>> key = load_pem_public_key(public_pem_data) >>> isinstance(key, rsa.RSAPublicKey) True :param bytes data: The PEM encoded key data. - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend`. @@ -197,7 +196,7 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END :raises cryptography.exceptions.UnsupportedAlgorithm: If the serialized key is of a type that is not supported by the backend. -.. function:: load_pem_parameters(data, backend) +.. function:: load_pem_parameters(data, backend=None) .. versionadded:: 2.0 @@ -208,13 +207,13 @@ all begin with ``-----BEGIN {format}-----`` and end with ``-----END >>> from cryptography.hazmat.primitives.serialization import load_pem_parameters >>> from cryptography.hazmat.primitives.asymmetric import dh - >>> parameters = load_pem_parameters(parameters_pem_data, backend=default_backend()) + >>> parameters = load_pem_parameters(parameters_pem_data) >>> isinstance(parameters, dh.DHParameters) True :param bytes data: The PEM encoded parameters data. - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.PEMSerializationBackend`. @@ -236,7 +235,7 @@ data is binary. DER keys may be in a variety of formats, but as long as you know whether it is a public or private key the loading functions will handle the rest. -.. function:: load_der_private_key(data, password, backend) +.. function:: load_der_private_key(data, password, backend=None) .. versionadded:: 0.8 @@ -250,7 +249,7 @@ the rest. be ``None`` if the private key is not encrypted. :type password: :term:`bytes-like` - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend`. :returns: One of @@ -274,14 +273,13 @@ the rest. .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives.asymmetric import rsa >>> from cryptography.hazmat.primitives.serialization import load_der_private_key - >>> key = load_der_private_key(der_data, password=None, backend=default_backend()) + >>> key = load_der_private_key(der_data, password=None) >>> isinstance(key, rsa.RSAPrivateKey) True -.. function:: load_der_public_key(data, backend) +.. function:: load_der_public_key(data, backend=None) .. versionadded:: 0.8 @@ -291,7 +289,7 @@ the rest. :param bytes data: The DER encoded key data. - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend`. :returns: One of @@ -310,14 +308,13 @@ the rest. .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives.asymmetric import rsa >>> from cryptography.hazmat.primitives.serialization import load_der_public_key - >>> key = load_der_public_key(public_der_data, backend=default_backend()) + >>> key = load_der_public_key(public_der_data) >>> isinstance(key, rsa.RSAPublicKey) True -.. function:: load_der_parameters(data, backend) +.. function:: load_der_parameters(data, backend=None) .. versionadded:: 2.0 @@ -326,7 +323,7 @@ the rest. :param bytes data: The DER encoded parameters data. - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.DERSerializationBackend`. :returns: Currently only @@ -341,10 +338,9 @@ the rest. .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives.asymmetric import dh >>> from cryptography.hazmat.primitives.serialization import load_der_parameters - >>> parameters = load_der_parameters(parameters_der_data, backend=default_backend()) + >>> parameters = load_der_parameters(parameters_der_data) >>> isinstance(parameters, dh.DHParameters) True @@ -369,20 +365,18 @@ DSA keys look almost identical but begin with ``ssh-dss`` rather than ``ssh-rsa``. ECDSA keys have a slightly different format, they begin with ``ecdsa-sha2-{curve}``. -.. function:: load_ssh_public_key(data, backend) +.. function:: load_ssh_public_key(data, backend=None) .. versionadded:: 0.7 - Deserialize a public key from OpenSSH (:rfc:`4253`) encoded data to an + Deserialize a public key from OpenSSH (:rfc:`4253` and + `PROTOCOL.certkeys`_) encoded data to an instance of the public key type for the specified backend. - .. note:: - - Currently Ed25519 keys are not supported. - - :param bytes data: The OpenSSH encoded key data. + :param data: The OpenSSH encoded key data. + :type data: :term:`bytes-like` - :param backend: A backend which implements + :param backend: An optional backend which implements :class:`~cryptography.hazmat.backends.interfaces.RSABackend`, :class:`~cryptography.hazmat.backends.interfaces.DSABackend`, or :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend` @@ -391,8 +385,9 @@ DSA keys look almost identical but begin with ``ssh-dss`` rather than :returns: One of :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, - or :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` + , or + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey`, depending on the contents of ``data``. :raises ValueError: If the OpenSSH data could not be properly decoded or @@ -401,6 +396,58 @@ DSA keys look almost identical but begin with ``ssh-dss`` rather than :raises cryptography.exceptions.UnsupportedAlgorithm: If the serialized key is of a type that is not supported. +OpenSSH Private Key +~~~~~~~~~~~~~~~~~~~ + +The format used by OpenSSH to store private keys, as approximately specified +in `PROTOCOL.key`_. + +An example ECDSA key in OpenSSH format:: + + -----BEGIN OPENSSH PRIVATE KEY----- + b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS + 1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQRI0fWnI1CxX7qYqp0ih6bxjhGmUrZK + /Axf8vhM8Db3oH7CFR+JdL715lUdu4XCWvQZKVf60/h3kBFhuxQC23XjAAAAqKPzVaOj81 + WjAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEjR9acjULFfupiq + nSKHpvGOEaZStkr8DF/y+EzwNvegfsIVH4l0vvXmVR27hcJa9BkpV/rT+HeQEWG7FALbde + MAAAAga/VGV2asRlL3kXXao0aochQ59nXHA2xEGeAoQd952r0AAAAJbWFya29AdmZmAQID + BAUGBw== + -----END OPENSSH PRIVATE KEY----- + +.. function:: load_ssh_private_key(data, password, backend=None) + + .. versionadded:: 3.0 + + Deserialize a private key from OpenSSH encoded data to an + instance of the private key type for the specified backend. + + :param data: The PEM encoded OpenSSH private key data. + :type data: :term:`bytes-like` + + :param bytes password: Password bytes to use to decrypt + password-protected key. Or ``None`` if not needed. + + :param backend: An optional backend which implements + :class:`~cryptography.hazmat.backends.interfaces.RSABackend`, + :class:`~cryptography.hazmat.backends.interfaces.DSABackend`, or + :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend` + depending on the key's type. + + :returns: One of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` + or + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey`, + depending on the contents of ``data``. + + :raises ValueError: If the OpenSSH data could not be properly decoded, + if the key is not in the proper format or the incorrect password + was provided. + + :raises cryptography.exceptions.UnsupportedAlgorithm: If the serialized + key is of a type that is not supported. + PKCS12 ~~~~~~ @@ -415,7 +462,7 @@ file suffix. ``cryptography`` only supports a single private key and associated certificates when parsing PKCS12 files at this time. -.. function:: load_key_and_certificates(data, password, backend) +.. function:: load_key_and_certificates(data, password, backend=None) .. versionadded:: 2.5 @@ -428,7 +475,7 @@ file suffix. if the PKCS12 is not encrypted. :type password: :term:`bytes-like` - :param backend: A backend instance. + :param backend: An optional backend instance. :returns: A tuple of ``(private_key, certificate, additional_certificates)``. @@ -438,6 +485,235 @@ file suffix. ``additional_certificates`` is a list of all other :class:`~cryptography.x509.Certificate` instances in the PKCS12 object. +.. function:: serialize_key_and_certificates(name, key, cert, cas, encryption_algorithm) + + .. versionadded:: 3.0 + + .. warning:: + + PKCS12 encryption is not secure and should not be used as a security + mechanism. Wrap a PKCS12 blob in a more secure envelope if you need + to store or send it safely. Encryption is provided for compatibility + reasons only. + + Serialize a PKCS12 blob. + + :param name: The friendly name to use for the supplied certificate and key. + :type name: bytes + + :param key: The private key to include in the structure. + :type key: An + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKeyWithSerialization` + , + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization` + , or + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization` + object. + + :param cert: The certificate associated with the private key. + :type cert: :class:`~cryptography.x509.Certificate` or ``None`` + + :param cas: An optional set of certificates to also include in the structure. + :type cas: list of :class:`~cryptography.x509.Certificate` or ``None`` + + :param encryption_algorithm: The encryption algorithm that should be used + for the key and certificate. An instance of an object conforming to the + :class:`~cryptography.hazmat.primitives.serialization.KeySerializationEncryption` + interface. PKCS12 encryption is **very weak** and should not be used + as a security boundary. + + :return bytes: Serialized PKCS12. + +PKCS7 +~~~~~ + +.. currentmodule:: cryptography.hazmat.primitives.serialization.pkcs7 + +PKCS7 is a format described in :rfc:`2315`, among other specifications. It can +contain certificates, CRLs, and much more. PKCS7 files commonly have a ``p7b``, +``p7m``, or ``p7s`` file suffix but other suffixes are also seen in the wild. + +.. note:: + + ``cryptography`` only supports parsing certificates from PKCS7 files at + this time. + +.. function:: load_pem_pkcs7_certificates(data) + + .. versionadded:: 3.1 + + Deserialize a PEM encoded PKCS7 blob to a list of certificates. PKCS7 can + contain many other types of data, including CRLs, but this function will + ignore everything except certificates. + + :param data: The data. + :type data: bytes + + :returns: A list of :class:`~cryptography.x509.Certificate`. + + :raises ValueError: If the PKCS7 data could not be loaded. + + :raises cryptography.exceptions.UnsupportedAlgorithm: If the PKCS7 data + is of a type that is not supported. + +.. function:: load_der_pkcs7_certificates(data) + + .. versionadded:: 3.1 + + Deserialize a DER encoded PKCS7 blob to a list of certificates. PKCS7 can + contain many other types of data, including CRLs, but this function will + ignore everything except certificates. + + :param data: The data. + :type data: bytes + + :returns: A list of :class:`~cryptography.x509.Certificate`. + + :raises ValueError: If the PKCS7 data could not be loaded. + + :raises cryptography.exceptions.UnsupportedAlgorithm: If the PKCS7 data + is of a type that is not supported. + +.. testsetup:: + + ca_key = b""" + -----BEGIN PRIVATE KEY----- + MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgA8Zqz5vLeR0ePZUe + jBfdyMmnnI4U5uAJApWTsMn/RuWhRANCAAQY/8+7+Tm49d3D7sBAiwZ1BqtPzdgs + UiROH+AQRme1XxW5Yr07zwxvvhr3tKEPtLnLboazUPlsUb/Bgte+xfkF + -----END PRIVATE KEY----- + """.strip() + + ca_cert = b""" + -----BEGIN CERTIFICATE----- + MIIBUTCB96ADAgECAgIDCTAKBggqhkjOPQQDAjAnMQswCQYDVQQGEwJVUzEYMBYG + A1UEAwwPY3J5cHRvZ3JhcGh5IENBMB4XDTE3MDEwMTEyMDEwMFoXDTM4MTIzMTA4 + MzAwMFowJzELMAkGA1UEBhMCVVMxGDAWBgNVBAMMD2NyeXB0b2dyYXBoeSBDQTBZ + MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBj/z7v5Obj13cPuwECLBnUGq0/N2CxS + JE4f4BBGZ7VfFblivTvPDG++Gve0oQ+0uctuhrNQ+WxRv8GC177F+QWjEzARMA8G + A1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSQAwRgIhANES742XWm64tkGnz8Dn + pG6u2lHkZFQr3oaVvPcemvlbAiEA0WGGzmYx5C9UvfXIK7NEziT4pQtyESE0uRVK + Xw4nMqk= + -----END CERTIFICATE----- + """.strip() + + +.. class:: PKCS7SignatureBuilder + + The PKCS7 signature builder can create both basic PKCS7 signed messages as + well as S/MIME messages, which are commonly used in email. S/MIME has + multiple versions, but this implements a subset of :rfc:`2632`, also known + as S/MIME Version 3. + + .. versionadded:: 3.2 + + .. doctest:: + + >>> from cryptography import x509 + >>> from cryptography.hazmat.primitives import hashes, serialization + >>> from cryptography.hazmat.primitives.serialization import pkcs7 + >>> cert = x509.load_pem_x509_certificate(ca_cert) + >>> key = serialization.load_pem_private_key(ca_key, None) + >>> options = [pkcs7.PKCS7Options.DetachedSignature] + >>> pkcs7.PKCS7SignatureBuilder().set_data( + ... b"data to sign" + ... ).add_signer( + ... cert, key, hashes.SHA256() + ... ).sign( + ... serialization.Encoding.SMIME, options + ... ) + b'...' + + .. method:: set_data(data) + + :param data: The data to be hashed and signed. + :type data: :term:`bytes-like` + + .. method:: add_signer(certificate, private_key, hash_algorithm) + + :param certificate: The :class:`~cryptography.x509.Certificate`. + + :param private_key: The + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` + associated with the certificate provided. + + :param hash_algorithm: The + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` that + will be used to generate the signature. This must be an instance of + :class:`~cryptography.hazmat.primitives.hashes.SHA1`, + :class:`~cryptography.hazmat.primitives.hashes.SHA224`, + :class:`~cryptography.hazmat.primitives.hashes.SHA256`, + :class:`~cryptography.hazmat.primitives.hashes.SHA384`, or + :class:`~cryptography.hazmat.primitives.hashes.SHA512`. + + .. method:: add_certificate(certificate) + + Add an additional certificate (typically used to help build a + verification chain) to the PKCS7 structure. This method may + be called multiple times to add as many certificates as desired. + + :param certificate: The :class:`~cryptography.x509.Certificate` to add. + + .. method:: sign(encoding, options, backend=None) + + :param encoding: :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM`, + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`, + or :attr:`~cryptography.hazmat.primitives.serialization.Encoding.SMIME`. + + :param options: A list of + :class:`~cryptography.hazmat.primitives.serialization.pkcs7.PKCS7Options`. + + :return bytes: The signed PKCS7 message. + + :param backend: An optional backend. + + +.. class:: PKCS7Options + + .. versionadded:: 3.2 + + An enumeration of options for PKCS7 signature creation. + + .. attribute:: Text + + The text option adds ``text/plain`` headers to an S/MIME message when + serializing to + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.SMIME`. + This option is disallowed with ``DER`` serialization. + + .. attribute:: Binary + + Signing normally converts line endings (LF to CRLF). When + passing this option the data will not be converted. + + .. attribute:: DetachedSignature + + Don't embed the signed data within the ASN.1. When signing with + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.SMIME` + this also results in the data being added as clear text before the + PEM encoded structure. + + .. attribute:: NoCapabilities + + PKCS7 structures contain a ``MIMECapabilities`` section inside the + ``authenticatedAttributes``. Passing this as an option removes + ``MIMECapabilities``. + + .. attribute:: NoAttributes + + PKCS7 structures contain an ``authenticatedAttributes`` section. + Passing this as an option removes that section. Note that if you + pass ``NoAttributes`` you can't pass ``NoCapabilities`` since + ``NoAttributes`` removes ``MIMECapabilities`` and more. + + .. attribute:: NoCerts + + Don't include the signer's certificate in the PKCS7 structure. This can + reduce the size of the signature but requires that the recipient can + obtain the signer's certificate by other means (for example from a + previously signed message). + Serialization Formats ~~~~~~~~~~~~~~~~~~~~~ @@ -486,6 +762,22 @@ Serialization Formats A raw format used by :doc:`/hazmat/primitives/asymmetric/x448`. It is a binary format and is invalid for other key types. + .. attribute:: OpenSSH + + .. versionadded:: 3.0 + + Custom private key format for OpenSSH, internals are based on SSH protocol + and not ASN1. Requires + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM` + encoding. + + A PEM encoded OpenSSH key will look like:: + + -----BEGIN OPENSSH PRIVATE KEY----- + ... + -----END OPENSSH PRIVATE KEY----- + + .. class:: PublicFormat .. versionadded:: 0.8 @@ -615,6 +907,12 @@ Serialization Encodings The format used by elliptic curve point encodings. This is a binary format. + .. attribute:: SMIME + + .. versionadded:: 3.2 + + An output format used for PKCS7. This is a text format. + Serialization Encryption Types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -647,4 +945,6 @@ Serialization Encryption Types .. _`PKCS3`: https://www.teletrust.de/fileadmin/files/oid/oid_pkcs-3v1-4.pdf -.. _`SEC 1 v2.0`: http://www.secg.org/sec1-v2.pdf +.. _`SEC 1 v2.0`: https://www.secg.org/sec1-v2.pdf +.. _`PROTOCOL.key`: https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key +.. _`PROTOCOL.certkeys`: https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.certkeys diff --git a/docs/hazmat/primitives/asymmetric/utils.rst b/docs/hazmat/primitives/asymmetric/utils.rst index f46acb2ec081..487926e91256 100644 --- a/docs/hazmat/primitives/asymmetric/utils.rst +++ b/docs/hazmat/primitives/asymmetric/utils.rst @@ -57,7 +57,6 @@ Asymmetric Utilities .. doctest:: >>> import hashlib - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric import ( ... padding, rsa, utils @@ -65,7 +64,6 @@ Asymmetric Utilities >>> private_key = rsa.generate_private_key( ... public_exponent=65537, ... key_size=2048, - ... backend=default_backend() ... ) >>> prehashed_msg = hashlib.sha256(b"A message I want to sign").digest() >>> signature = private_key.sign( diff --git a/docs/hazmat/primitives/asymmetric/x25519.rst b/docs/hazmat/primitives/asymmetric/x25519.rst index ea01fbaa08e7..014f3d01d5d3 100644 --- a/docs/hazmat/primitives/asymmetric/x25519.rst +++ b/docs/hazmat/primitives/asymmetric/x25519.rst @@ -21,7 +21,6 @@ present. .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF @@ -39,7 +38,6 @@ present. ... length=32, ... salt=None, ... info=b'handshake data', - ... backend=default_backend() ... ).derive(shared_key) >>> # For the next handshake we MUST generate another private key. >>> private_key_2 = X25519PrivateKey.generate() @@ -50,7 +48,6 @@ present. ... length=32, ... salt=None, ... info=b'handshake data', - ... backend=default_backend() ... ).derive(shared_key_2) Key interfaces diff --git a/docs/hazmat/primitives/asymmetric/x448.rst b/docs/hazmat/primitives/asymmetric/x448.rst index 4e1f0421f542..f166355b83fa 100644 --- a/docs/hazmat/primitives/asymmetric/x448.rst +++ b/docs/hazmat/primitives/asymmetric/x448.rst @@ -21,7 +21,6 @@ present. .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric.x448 import X448PrivateKey >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF @@ -39,7 +38,6 @@ present. ... length=32, ... salt=None, ... info=b'handshake data', - ... backend=default_backend() ... ).derive(shared_key) >>> # For the next handshake we MUST generate another private key. >>> private_key_2 = X448PrivateKey.generate() @@ -50,7 +48,6 @@ present. ... length=32, ... salt=None, ... info=b'handshake data', - ... backend=default_backend() ... ).derive(shared_key_2) Key interfaces diff --git a/docs/hazmat/primitives/cryptographic-hashes.rst b/docs/hazmat/primitives/cryptographic-hashes.rst index 24cc70b5e436..4cdc034a6b84 100644 --- a/docs/hazmat/primitives/cryptographic-hashes.rst +++ b/docs/hazmat/primitives/cryptographic-hashes.rst @@ -5,7 +5,7 @@ Message digests (Hashing) .. module:: cryptography.hazmat.primitives.hashes -.. class:: Hash(algorithm, backend) +.. class:: Hash(algorithm, backend=None) A cryptographic hash function takes an arbitrary block of data and calculates a fixed-size bit string (a digest), such that different data @@ -20,9 +20,8 @@ Message digests (Hashing) .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes - >>> digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) + >>> digest = hashes.Hash(hashes.SHA256()) >>> digest.update(b"abc") >>> digest.update(b"123") >>> digest.finalize() @@ -42,7 +41,7 @@ Message digests (Hashing) :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` instance such as those described in :ref:`below `. - :param backend: A + :param backend: An optional :class:`~cryptography.hazmat.backends.interfaces.HashBackend` instance. diff --git a/docs/hazmat/primitives/key-derivation-functions.rst b/docs/hazmat/primitives/key-derivation-functions.rst index be03b19cb8c7..62457b28490c 100644 --- a/docs/hazmat/primitives/key-derivation-functions.rst +++ b/docs/hazmat/primitives/key-derivation-functions.rst @@ -26,9 +26,17 @@ Different KDFs are suitable for different tasks such as: Ideal password storage KDFs will be demanding on both computational and memory resources. + +Variable cost algorithms +~~~~~~~~~~~~~~~~~~~~~~~~ + + +PBKDF2 +------ + .. currentmodule:: cryptography.hazmat.primitives.kdf.pbkdf2 -.. class:: PBKDF2HMAC(algorithm, length, salt, iterations, backend) +.. class:: PBKDF2HMAC(algorithm, length, salt, iterations, backend=None) .. versionadded:: 0.2 @@ -47,8 +55,6 @@ Different KDFs are suitable for different tasks such as: >>> import os >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC - >>> from cryptography.hazmat.backends import default_backend - >>> backend = default_backend() >>> # Salts should be randomly generated >>> salt = os.urandom(16) >>> # derive @@ -57,7 +63,6 @@ Different KDFs are suitable for different tasks such as: ... length=32, ... salt=salt, ... iterations=100000, - ... backend=backend ... ) >>> key = kdf.derive(b"my great password") >>> # verify @@ -66,7 +71,6 @@ Different KDFs are suitable for different tasks such as: ... length=32, ... salt=salt, ... iterations=100000, - ... backend=backend ... ) >>> kdf.verify(b"my great password", key) @@ -79,9 +83,9 @@ Different KDFs are suitable for different tasks such as: :param int iterations: The number of iterations to perform of the hash function. This can be used to control the length of time the operation takes. Higher numbers help mitigate brute force attacks against derived - keys. See OWASP's `Password Storage Cheat Sheet`_ for more - detailed recommendations if you intend to use this for password storage. - :param backend: An instance of + keys. A `more detailed description`_ can be consulted for additional + information. + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.PBKDF2HMACBackend`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the @@ -130,172 +134,91 @@ Different KDFs are suitable for different tasks such as: key. -.. currentmodule:: cryptography.hazmat.primitives.kdf.hkdf +Scrypt +------ -.. class:: HKDF(algorithm, length, salt, info, backend) +.. currentmodule:: cryptography.hazmat.primitives.kdf.scrypt - .. versionadded:: 0.2 +.. class:: Scrypt(salt, length, n, r, p, backend=None) - `HKDF`_ (HMAC-based Extract-and-Expand Key Derivation Function) is suitable - for deriving keys of a fixed size used for other cryptographic operations. + .. versionadded:: 1.6 - .. warning:: + Scrypt is a KDF designed for password storage by Colin Percival to be + resistant against hardware-assisted attackers by having a tunable memory + cost. It is described in :rfc:`7914`. - HKDF should not be used for password storage. + This class conforms to the + :class:`~cryptography.hazmat.primitives.kdf.KeyDerivationFunction` + interface. .. doctest:: >>> import os - >>> from cryptography.hazmat.primitives import hashes - >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF - >>> from cryptography.hazmat.backends import default_backend - >>> backend = default_backend() + >>> from cryptography.hazmat.primitives.kdf.scrypt import Scrypt >>> salt = os.urandom(16) - >>> info = b"hkdf-example" - >>> hkdf = HKDF( - ... algorithm=hashes.SHA256(), - ... length=32, + >>> # derive + >>> kdf = Scrypt( ... salt=salt, - ... info=info, - ... backend=backend - ... ) - >>> key = hkdf.derive(b"input key") - >>> hkdf = HKDF( - ... algorithm=hashes.SHA256(), ... length=32, + ... n=2**14, + ... r=8, + ... p=1, + ... ) + >>> key = kdf.derive(b"my great password") + >>> # verify + >>> kdf = Scrypt( ... salt=salt, - ... info=info, - ... backend=backend + ... length=32, + ... n=2**14, + ... r=8, + ... p=1, ... ) - >>> hkdf.verify(b"input key", key) - - :param algorithm: An instance of - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. - - :param int length: The desired length of the derived key in bytes. Maximum - is ``255 * (algorithm.digest_size // 8)``. + >>> kdf.verify(b"my great password", key) - :param bytes salt: A salt. Randomizes the KDF's output. Optional, but - highly recommended. Ideally as many bits of entropy as the security - level of the hash: often that means cryptographically random and as - long as the hash output. Worse (shorter, less entropy) salt values can - still meaningfully contribute to security. May be reused. Does not have - 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. + :param bytes salt: A salt. + :param int length: The desired length of the derived key in bytes. + :param int n: CPU/Memory cost parameter. It must be larger than 1 and be a + power of 2. + :param int r: Block size parameter. + :param int p: Parallelization parameter. + :param backend: An optional instance of + :class:`~cryptography.hazmat.backends.interfaces.ScryptBackend`. - :param bytes info: Application specific context information. If ``None`` - is explicitly passed an empty byte string will be used. + The computational and memory cost of Scrypt can be adjusted by manipulating + the 3 parameters: ``n``, ``r``, and ``p``. In general, the memory cost of + Scrypt is affected by the values of both ``n`` and ``r``, while ``n`` also + determines the number of iterations performed. ``p`` increases the + computational cost without affecting memory usage. A more in-depth + explanation of the 3 parameters can be found `here`_. - :param backend: An instance of - :class:`~cryptography.hazmat.backends.interfaces.HMACBackend`. + :rfc:`7914` `recommends`_ values of ``r=8`` and ``p=1`` while scaling ``n`` + to a number appropriate for your system. `The scrypt paper`_ suggests a + minimum value of ``n=2**14`` for interactive logins (t < 100ms), or + ``n=2**20`` for more sensitive files (t < 5s). :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the provided ``backend`` does not implement - :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` + :class:`~cryptography.hazmat.backends.interfaces.ScryptBackend` - :raises TypeError: This exception is raised if ``salt`` or ``info`` is not - ``bytes``. + :raises TypeError: This exception is raised if ``salt`` is not ``bytes``. + :raises ValueError: This exception is raised if ``n`` is less than 2, if + ``n`` is not a power of 2, if ``r`` is less than 1 or if ``p`` is less + than 1. .. method:: derive(key_material) :param key_material: The input key material. :type key_material: :term:`bytes-like` - :return bytes: The derived key. + :return bytes: the derived key. :raises TypeError: This exception is raised if ``key_material`` is not ``bytes``. - - Derives a new key from the input key material by performing both the - extract and expand operations. - - .. method:: verify(key_material, expected_key) - - :param bytes key_material: The input key material. This is the same as - ``key_material`` in :meth:`derive`. - :param bytes expected_key: The expected result of deriving a new key, - this is the same as the return value of - :meth:`derive`. - :raises cryptography.exceptions.InvalidKey: This is raised when the - derived key does not match - the expected key. :raises cryptography.exceptions.AlreadyFinalized: This is raised when :meth:`derive` or :meth:`verify` is called more than once. - This checks whether deriving a new key from the supplied - ``key_material`` generates the same key as the ``expected_key``, and - raises an exception if they do not match. - - -.. class:: HKDFExpand(algorithm, length, info, backend) - - .. versionadded:: 0.5 - - HKDF consists of two stages, extract and expand. This class exposes an - expand only version of HKDF that is suitable when the key material is - already cryptographically strong. - - .. warning:: - - HKDFExpand should only be used if the key material is - cryptographically strong. You should use - :class:`~cryptography.hazmat.primitives.kdf.hkdf.HKDF` if - you are unsure. - - .. doctest:: - - >>> import os - >>> from cryptography.hazmat.primitives import hashes - >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDFExpand - >>> from cryptography.hazmat.backends import default_backend - >>> backend = default_backend() - >>> info = b"hkdf-example" - >>> key_material = os.urandom(16) - >>> hkdf = HKDFExpand( - ... algorithm=hashes.SHA256(), - ... length=32, - ... info=info, - ... backend=backend - ... ) - >>> key = hkdf.derive(key_material) - >>> hkdf = HKDFExpand( - ... algorithm=hashes.SHA256(), - ... length=32, - ... info=info, - ... backend=backend - ... ) - >>> hkdf.verify(key_material, key) - - :param algorithm: An instance of - :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. - - :param int length: The desired length of the derived key in bytes. Maximum - is ``255 * (algorithm.digest_size // 8)``. - - :param bytes info: Application specific context information. If ``None`` - is explicitly passed an empty byte string will be used. - - :param backend: An instance of - :class:`~cryptography.hazmat.backends.interfaces.HMACBackend`. - - :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the - provided ``backend`` does not implement - :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` - :raises TypeError: This exception is raised if ``info`` is not ``bytes``. - - .. method:: derive(key_material) - - :param bytes key_material: The input key material. - :return bytes: The derived key. - - :raises TypeError: This exception is raised if ``key_material`` is not - ``bytes``. - - Derives a new key from the input key material by performing both the - extract and expand operations. + This generates and returns a new key from the supplied password. .. method:: verify(key_material, expected_key) @@ -312,16 +235,23 @@ Different KDFs are suitable for different tasks such as: :meth:`verify` is called more than once. - :raises TypeError: This is raised if the provided ``key_material`` is - a ``unicode`` object This checks whether deriving a new key from the supplied ``key_material`` generates the same key as the ``expected_key``, and - raises an exception if they do not match. + raises an exception if they do not match. This can be used for + checking whether the password a user provides matches the stored derived + key. + +Fixed cost algorithms +~~~~~~~~~~~~~~~~~~~~~ + + +ConcatKDF +--------- .. currentmodule:: cryptography.hazmat.primitives.kdf.concatkdf -.. class:: ConcatKDFHash(algorithm, length, otherinfo, backend) +.. class:: ConcatKDFHash(algorithm, length, otherinfo, backend=None) .. versionadded:: 1.0 @@ -338,21 +268,17 @@ Different KDFs are suitable for different tasks such as: >>> import os >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.kdf.concatkdf import ConcatKDFHash - >>> from cryptography.hazmat.backends import default_backend - >>> backend = default_backend() >>> otherinfo = b"concatkdf-example" >>> ckdf = ConcatKDFHash( ... algorithm=hashes.SHA256(), ... length=32, ... otherinfo=otherinfo, - ... backend=backend ... ) >>> key = ckdf.derive(b"input key") >>> ckdf = ConcatKDFHash( ... algorithm=hashes.SHA256(), ... length=32, ... otherinfo=otherinfo, - ... backend=backend ... ) >>> ckdf.verify(b"input key", key) @@ -365,7 +291,7 @@ Different KDFs are suitable for different tasks such as: :param bytes otherinfo: Application specific context information. If ``None`` is explicitly passed an empty byte string will be used. - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.HashBackend`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised @@ -382,6 +308,11 @@ Different KDFs are suitable for different tasks such as: :return bytes: The derived key. :raises TypeError: This exception is raised if ``key_material`` is not ``bytes``. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. Derives a new key from the input key material. @@ -406,7 +337,7 @@ Different KDFs are suitable for different tasks such as: raises an exception if they do not match. -.. class:: ConcatKDFHMAC(algorithm, length, salt, otherinfo, backend) +.. class:: ConcatKDFHMAC(algorithm, length, salt, otherinfo, backend=None) .. versionadded:: 1.0 @@ -421,8 +352,6 @@ Different KDFs are suitable for different tasks such as: >>> import os >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.kdf.concatkdf import ConcatKDFHMAC - >>> from cryptography.hazmat.backends import default_backend - >>> backend = default_backend() >>> salt = os.urandom(16) >>> otherinfo = b"concatkdf-example" >>> ckdf = ConcatKDFHMAC( @@ -430,7 +359,6 @@ Different KDFs are suitable for different tasks such as: ... length=32, ... salt=salt, ... otherinfo=otherinfo, - ... backend=backend ... ) >>> key = ckdf.derive(b"input key") >>> ckdf = ConcatKDFHMAC( @@ -438,7 +366,6 @@ Different KDFs are suitable for different tasks such as: ... length=32, ... salt=salt, ... otherinfo=otherinfo, - ... backend=backend ... ) >>> ckdf.verify(b"input key", key) @@ -459,7 +386,7 @@ Different KDFs are suitable for different tasks such as: :param bytes otherinfo: Application specific context information. If ``None`` is explicitly passed an empty byte string will be used. - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.HMACBackend`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the @@ -475,6 +402,11 @@ Different KDFs are suitable for different tasks such as: :return bytes: The derived key. :raises TypeError: This exception is raised if ``key_material`` is not ``bytes``. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. Derives a new key from the input key material. @@ -498,78 +430,178 @@ Different KDFs are suitable for different tasks such as: ``key_material`` generates the same key as the ``expected_key``, and raises an exception if they do not match. -.. currentmodule:: cryptography.hazmat.primitives.kdf.x963kdf -.. class:: X963KDF(algorithm, length, otherinfo, backend) +HKDF +---- - .. versionadded:: 1.1 +.. currentmodule:: cryptography.hazmat.primitives.kdf.hkdf - X963KDF (ANSI X9.63 Key Derivation Function) is defined by ANSI - in the `ANSI X9.63:2001`_ document, to be used to derive keys for use - after a Key Exchange negotiation operation. +.. class:: HKDF(algorithm, length, salt, info, backend=None) - SECG in `SEC 1 v2.0`_ recommends that - :class:`~cryptography.hazmat.primitives.kdf.concatkdf.ConcatKDFHash` be - used for new projects. This KDF should only be used for backwards - compatibility with pre-existing protocols. + .. versionadded:: 0.2 + `HKDF`_ (HMAC-based Extract-and-Expand Key Derivation Function) is suitable + for deriving keys of a fixed size used for other cryptographic operations. .. warning:: - X963KDF should not be used for password storage. + HKDF should not be used for password storage. .. doctest:: >>> import os >>> from cryptography.hazmat.primitives import hashes - >>> from cryptography.hazmat.primitives.kdf.x963kdf import X963KDF - >>> from cryptography.hazmat.backends import default_backend - >>> backend = default_backend() - >>> sharedinfo = b"ANSI X9.63 Example" - >>> xkdf = X963KDF( + >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDF + >>> salt = os.urandom(16) + >>> info = b"hkdf-example" + >>> hkdf = HKDF( ... algorithm=hashes.SHA256(), ... length=32, - ... sharedinfo=sharedinfo, - ... backend=backend + ... salt=salt, + ... info=info, ... ) - >>> key = xkdf.derive(b"input key") - >>> xkdf = X963KDF( + >>> key = hkdf.derive(b"input key") + >>> hkdf = HKDF( ... algorithm=hashes.SHA256(), ... length=32, - ... sharedinfo=sharedinfo, - ... backend=backend + ... salt=salt, + ... info=info, ... ) - >>> xkdf.verify(b"input key", key) + >>> hkdf.verify(b"input key", key) :param algorithm: An instance of :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. - :param int length: The desired length of the derived key in bytes. - Maximum is ``hashlen * (2^32 -1)``. + :param int length: The desired length of the derived key in bytes. Maximum + is ``255 * (algorithm.digest_size // 8)``. - :param bytes sharedinfo: Application specific context information. - If ``None`` is explicitly passed an empty byte string will be used. + :param bytes salt: A salt. Randomizes the KDF's output. Optional, but + highly recommended. Ideally as many bits of entropy as the security + level of the hash: often that means cryptographically random and as + long as the hash output. Worse (shorter, less entropy) salt values can + still meaningfully contribute to security. May be reused. Does not have + 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. - :param backend: A cryptography backend - :class:`~cryptography.hazmat.backends.interfaces.HashBackend` - instance. + :param bytes info: Application specific context information. If ``None`` + is explicitly passed an empty byte string will be used. - :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised - if the provided ``backend`` does not implement - :class:`~cryptography.hazmat.backends.interfaces.HashBackend` + :param backend: An optional instance of + :class:`~cryptography.hazmat.backends.interfaces.HMACBackend`. - :raises TypeError: This exception is raised if ``sharedinfo`` is not - ``bytes``. + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the + provided ``backend`` does not implement + :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` + + :raises TypeError: This exception is raised if ``salt`` or ``info`` is not + ``bytes``. .. method:: derive(key_material) :param key_material: The input key material. :type key_material: :term:`bytes-like` :return bytes: The derived key. - :raises TypeError: This exception is raised if ``key_material`` is - not ``bytes``. + :raises TypeError: This exception is raised if ``key_material`` is not + ``bytes``. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. - Derives a new key from the input key material. + Derives a new key from the input key material by performing both the + extract and expand operations. + + .. method:: verify(key_material, expected_key) + + :param bytes key_material: The input key material. This is the same as + ``key_material`` in :meth:`derive`. + :param bytes expected_key: The expected result of deriving a new key, + this is the same as the return value of + :meth:`derive`. + :raises cryptography.exceptions.InvalidKey: This is raised when the + derived key does not match + the expected key. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. + + This checks whether deriving a new key from the supplied + ``key_material`` generates the same key as the ``expected_key``, and + raises an exception if they do not match. + + +.. class:: HKDFExpand(algorithm, length, info, backend=None) + + .. versionadded:: 0.5 + + HKDF consists of two stages, extract and expand. This class exposes an + expand only version of HKDF that is suitable when the key material is + already cryptographically strong. + + .. warning:: + + HKDFExpand should only be used if the key material is + cryptographically strong. You should use + :class:`~cryptography.hazmat.primitives.kdf.hkdf.HKDF` if + you are unsure. + + .. doctest:: + + >>> import os + >>> from cryptography.hazmat.primitives import hashes + >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDFExpand + >>> info = b"hkdf-example" + >>> key_material = os.urandom(16) + >>> hkdf = HKDFExpand( + ... algorithm=hashes.SHA256(), + ... length=32, + ... info=info, + ... ) + >>> key = hkdf.derive(key_material) + >>> hkdf = HKDFExpand( + ... algorithm=hashes.SHA256(), + ... length=32, + ... info=info, + ... ) + >>> hkdf.verify(key_material, key) + + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. + + :param int length: The desired length of the derived key in bytes. Maximum + is ``255 * (algorithm.digest_size // 8)``. + + :param bytes info: Application specific context information. If ``None`` + is explicitly passed an empty byte string will be used. + + :param backend: An optional instance of + :class:`~cryptography.hazmat.backends.interfaces.HMACBackend`. + + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the + provided ``backend`` does not implement + :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` + :raises TypeError: This exception is raised if ``info`` is not ``bytes``. + + .. method:: derive(key_material) + + :param bytes key_material: The input key material. + :return bytes: The derived key. + + :raises TypeError: This exception is raised if ``key_material`` is not + ``bytes``. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. + + Derives a new key from the input key material by performing both the + extract and expand operations. .. method:: verify(key_material, expected_key) @@ -586,16 +618,21 @@ Different KDFs are suitable for different tasks such as: :meth:`verify` is called more than once. + :raises TypeError: This is raised if the provided ``key_material`` is + a ``unicode`` object This checks whether deriving a new key from the supplied ``key_material`` generates the same key as the ``expected_key``, and raises an exception if they do not match. +KBKDF +----- + .. currentmodule:: cryptography.hazmat.primitives.kdf.kbkdf .. class:: KBKDFHMAC(algorithm, mode, length, rlen, llen, location,\ - label, context, fixed, backend) + label, context, fixed, backend=None) .. versionadded:: 1.4 @@ -615,8 +652,6 @@ Different KDFs are suitable for different tasks such as: >>> from cryptography.hazmat.primitives.kdf.kbkdf import ( ... CounterLocation, KBKDFHMAC, Mode ... ) - >>> from cryptography.hazmat.backends import default_backend - >>> backend = default_backend() >>> label = b"KBKDF HMAC Label" >>> context = b"KBKDF HMAC Context" >>> kdf = KBKDFHMAC( @@ -629,7 +664,6 @@ Different KDFs are suitable for different tasks such as: ... label=label, ... context=context, ... fixed=None, - ... backend=backend ... ) >>> key = kdf.derive(b"input key") >>> kdf = KBKDFHMAC( @@ -642,7 +676,6 @@ Different KDFs are suitable for different tasks such as: ... label=label, ... context=context, ... fixed=None, - ... backend=backend ... ) >>> kdf.verify(b"input key", key) @@ -673,13 +706,12 @@ Different KDFs are suitable for different tasks such as: may supply your own fixed data. If ``fixed`` is specified, ``label`` and ``context`` is ignored. - :param backend: A cryptography backend - :class:`~cryptography.hazmat.backends.interfaces.HashBackend` - instance. + :param backend: An optional instance of + :class:`~cryptography.hazmat.backends.interfaces.HMACBackend`. :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the provided ``backend`` does not implement - :class:`~cryptography.hazmat.backends.interfaces.HashBackend` + :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` :raises TypeError: This exception is raised if ``label`` or ``context`` is not ``bytes``. Also raised if ``rlen`` or ``llen`` is not ``int``. @@ -695,6 +727,11 @@ Different KDFs are suitable for different tasks such as: :return bytes: The derived key. :raises TypeError: This exception is raised if ``key_material`` is not ``bytes``. + :raises cryptography.exceptions.AlreadyFinalized: This is raised when + :meth:`derive` or + :meth:`verify` is + called more than + once. Derives a new key from the input key material. @@ -741,93 +778,82 @@ Different KDFs are suitable for different tasks such as: The counter iteration variable will be concatenated after the fixed input data. -.. currentmodule:: cryptography.hazmat.primitives.kdf.scrypt -.. class:: Scrypt(salt, length, n, r, p, backend) +X963KDF +------- - .. versionadded:: 1.6 +.. currentmodule:: cryptography.hazmat.primitives.kdf.x963kdf - Scrypt is a KDF designed for password storage by Colin Percival to be - resistant against hardware-assisted attackers by having a tunable memory - cost. It is described in :rfc:`7914`. +.. class:: X963KDF(algorithm, length, otherinfo, backend=None) - This class conforms to the - :class:`~cryptography.hazmat.primitives.kdf.KeyDerivationFunction` - interface. + .. versionadded:: 1.1 + + X963KDF (ANSI X9.63 Key Derivation Function) is defined by ANSI + in the `ANSI X9.63:2001`_ document, to be used to derive keys for use + after a Key Exchange negotiation operation. + + SECG in `SEC 1 v2.0`_ recommends that + :class:`~cryptography.hazmat.primitives.kdf.concatkdf.ConcatKDFHash` be + used for new projects. This KDF should only be used for backwards + compatibility with pre-existing protocols. + + + .. warning:: + + X963KDF should not be used for password storage. .. doctest:: >>> import os - >>> from cryptography.hazmat.primitives.kdf.scrypt import Scrypt - >>> from cryptography.hazmat.backends import default_backend - >>> backend = default_backend() - >>> salt = os.urandom(16) - >>> # derive - >>> kdf = Scrypt( - ... salt=salt, + >>> from cryptography.hazmat.primitives import hashes + >>> from cryptography.hazmat.primitives.kdf.x963kdf import X963KDF + >>> sharedinfo = b"ANSI X9.63 Example" + >>> xkdf = X963KDF( + ... algorithm=hashes.SHA256(), ... length=32, - ... n=2**14, - ... r=8, - ... p=1, - ... backend=backend + ... sharedinfo=sharedinfo, ... ) - >>> key = kdf.derive(b"my great password") - >>> # verify - >>> kdf = Scrypt( - ... salt=salt, + >>> key = xkdf.derive(b"input key") + >>> xkdf = X963KDF( + ... algorithm=hashes.SHA256(), ... length=32, - ... n=2**14, - ... r=8, - ... p=1, - ... backend=backend + ... sharedinfo=sharedinfo, ... ) - >>> kdf.verify(b"my great password", key) + >>> xkdf.verify(b"input key", key) - :param bytes salt: A salt. - :param int length: The desired length of the derived key in bytes. - :param int n: CPU/Memory cost parameter. It must be larger than 1 and be a - power of 2. - :param int r: Block size parameter. - :param int p: Parallelization parameter. + :param algorithm: An instance of + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm`. - The computational and memory cost of Scrypt can be adjusted by manipulating - the 3 parameters: ``n``, ``r``, and ``p``. In general, the memory cost of - Scrypt is affected by the values of both ``n`` and ``r``, while ``n`` also - determines the number of iterations performed. ``p`` increases the - computational cost without affecting memory usage. A more in-depth - explanation of the 3 parameters can be found `here`_. + :param int length: The desired length of the derived key in bytes. + Maximum is ``hashlen * (2^32 -1)``. - :rfc:`7914` `recommends`_ values of ``r=8`` and ``p=1`` while scaling ``n`` - to a number appropriate for your system. `The scrypt paper`_ suggests a - minimum value of ``n=2**14`` for interactive logins (t < 100ms), or - ``n=2**20`` for more sensitive files (t < 5s). + :param bytes sharedinfo: Application specific context information. + If ``None`` is explicitly passed an empty byte string will be used. - :param backend: An instance of - :class:`~cryptography.hazmat.backends.interfaces.ScryptBackend`. + :param backend: An optional instance of + :class:`~cryptography.hazmat.backends.interfaces.HashBackend`. - :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the - provided ``backend`` does not implement - :class:`~cryptography.hazmat.backends.interfaces.ScryptBackend` + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised + if the provided ``backend`` does not implement + :class:`~cryptography.hazmat.backends.interfaces.HashBackend` - :raises TypeError: This exception is raised if ``salt`` is not ``bytes``. - :raises ValueError: This exception is raised if ``n`` is less than 2, if - ``n`` is not a power of 2, if ``r`` is less than 1 or if ``p`` is less - than 1. + :raises TypeError: This exception is raised if ``sharedinfo`` is not + ``bytes``. .. method:: derive(key_material) :param key_material: The input key material. :type key_material: :term:`bytes-like` - :return bytes: the derived key. - :raises TypeError: This exception is raised if ``key_material`` is not - ``bytes``. + :return bytes: The derived key. + :raises TypeError: This exception is raised if ``key_material`` is + not ``bytes``. :raises cryptography.exceptions.AlreadyFinalized: This is raised when :meth:`derive` or :meth:`verify` is called more than once. - This generates and returns a new key from the supplied password. + Derives a new key from the input key material. .. method:: verify(key_material, expected_key) @@ -847,9 +873,8 @@ Different KDFs are suitable for different tasks such as: This checks whether deriving a new key from the supplied ``key_material`` generates the same key as the ``expected_key``, and - raises an exception if they do not match. This can be used for - checking whether the password a user provides matches the stored derived - key. + raises an exception if they do not match. + Interface ~~~~~~~~~ @@ -904,8 +929,8 @@ Interface .. _`NIST SP 800-108`: https://csrc.nist.gov/publications/detail/sp/800-108/final .. _`NIST SP 800-56Ar2`: https://csrc.nist.gov/publications/detail/sp/800-56a/rev-2/final .. _`ANSI X9.63:2001`: https://webstore.ansi.org -.. _`SEC 1 v2.0`: http://www.secg.org/sec1-v2.pdf -.. _`Password Storage Cheat Sheet`: https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet +.. _`SEC 1 v2.0`: https://www.secg.org/sec1-v2.pdf +.. _`more detailed description`: https://security.stackexchange.com/a/3993/43116 .. _`PBKDF2`: https://en.wikipedia.org/wiki/PBKDF2 .. _`key stretching`: https://en.wikipedia.org/wiki/Key_stretching .. _`HKDF`: https://en.wikipedia.org/wiki/HKDF diff --git a/docs/hazmat/primitives/keywrap.rst b/docs/hazmat/primitives/keywrap.rst index 1c15f9d19475..9d8abbd09171 100644 --- a/docs/hazmat/primitives/keywrap.rst +++ b/docs/hazmat/primitives/keywrap.rst @@ -11,7 +11,7 @@ to protect keys at rest or transmit them over insecure networks. Many of the protections offered by key wrapping are also offered by using authenticated :doc:`symmetric encryption `. -.. function:: aes_key_wrap(wrapping_key, key_to_wrap, backend) +.. function:: aes_key_wrap(wrapping_key, key_to_wrap, backend=None) .. versionadded:: 1.1 @@ -22,14 +22,14 @@ protections offered by key wrapping are also offered by using authenticated :param bytes key_to_wrap: The key to wrap. - :param backend: A + :param backend: An optional :class:`~cryptography.hazmat.backends.interfaces.CipherBackend` instance that supports :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES`. :return bytes: The wrapped key as bytes. -.. function:: aes_key_unwrap(wrapping_key, wrapped_key, backend) +.. function:: aes_key_unwrap(wrapping_key, wrapped_key, backend=None) .. versionadded:: 1.1 @@ -40,7 +40,7 @@ protections offered by key wrapping are also offered by using authenticated :param bytes wrapped_key: The wrapped key. - :param backend: A + :param backend: An optional :class:`~cryptography.hazmat.backends.interfaces.CipherBackend` instance that supports :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES`. @@ -50,7 +50,7 @@ protections offered by key wrapping are also offered by using authenticated :raises cryptography.hazmat.primitives.keywrap.InvalidUnwrap: This is raised if the key is not successfully unwrapped. -.. function:: aes_key_wrap_with_padding(wrapping_key, key_to_wrap, backend) +.. function:: aes_key_wrap_with_padding(wrapping_key, key_to_wrap, backend=None) .. versionadded:: 2.2 @@ -61,14 +61,14 @@ protections offered by key wrapping are also offered by using authenticated :param bytes key_to_wrap: The key to wrap. - :param backend: A + :param backend: An optional :class:`~cryptography.hazmat.backends.interfaces.CipherBackend` instance that supports :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES`. :return bytes: The wrapped key as bytes. -.. function:: aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend) +.. function:: aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend=None) .. versionadded:: 2.2 @@ -79,7 +79,7 @@ protections offered by key wrapping are also offered by using authenticated :param bytes wrapped_key: The wrapped key. - :param backend: A + :param backend: An optional :class:`~cryptography.hazmat.backends.interfaces.CipherBackend` instance that supports :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES`. diff --git a/docs/hazmat/primitives/mac/cmac.rst b/docs/hazmat/primitives/mac/cmac.rst index a5b13caf71d2..b40a90a82aa9 100644 --- a/docs/hazmat/primitives/mac/cmac.rst +++ b/docs/hazmat/primitives/mac/cmac.rst @@ -17,7 +17,7 @@ of a message. A subset of CMAC with the AES-128 algorithm is described in :rfc:`4493`. -.. class:: CMAC(algorithm, backend) +.. class:: CMAC(algorithm, backend=None) .. versionadded:: 0.4 @@ -26,10 +26,9 @@ A subset of CMAC with the AES-128 algorithm is described in :rfc:`4493`. .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import cmac >>> from cryptography.hazmat.primitives.ciphers import algorithms - >>> c = cmac.CMAC(algorithms.AES(key), backend=default_backend()) + >>> c = cmac.CMAC(algorithms.AES(key)) >>> c.update(b"message to authenticate") >>> c.finalize() b'CT\x1d\xc8\x0e\x15\xbe4e\xdb\xb6\x84\xca\xd9Xk' @@ -47,7 +46,7 @@ A subset of CMAC with the AES-128 algorithm is described in :rfc:`4493`. .. doctest:: - >>> c = cmac.CMAC(algorithms.AES(key), backend=default_backend()) + >>> c = cmac.CMAC(algorithms.AES(key)) >>> c.update(b"message to authenticate") >>> c.verify(b"an incorrect signature") Traceback (most recent call last): @@ -56,7 +55,7 @@ A subset of CMAC with the AES-128 algorithm is described in :rfc:`4493`. :param algorithm: An instance of :class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm`. - :param backend: An instance of + :param backend: An optional instance of :class:`~cryptography.hazmat.backends.interfaces.CMACBackend`. :raises TypeError: This is raised if the provided ``algorithm`` is not an instance of :class:`~cryptography.hazmat.primitives.ciphers.BlockCipherAlgorithm` diff --git a/docs/hazmat/primitives/mac/hmac.rst b/docs/hazmat/primitives/mac/hmac.rst index 9d11694bd569..3695270b7ab2 100644 --- a/docs/hazmat/primitives/mac/hmac.rst +++ b/docs/hazmat/primitives/mac/hmac.rst @@ -15,7 +15,7 @@ message authentication codes using a cryptographic hash function coupled with a secret key. You can use an HMAC to verify both the integrity and authenticity of a message. -.. class:: HMAC(key, algorithm, backend) +.. class:: HMAC(key, algorithm, backend=None) HMAC objects take a ``key`` and a :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` instance. @@ -27,9 +27,8 @@ of a message. .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes, hmac - >>> h = hmac.HMAC(key, hashes.SHA256(), backend=default_backend()) + >>> h = hmac.HMAC(key, hashes.SHA256()) >>> h.update(b"message to hash") >>> h.finalize() b'#F\xdaI\x8b"e\xc4\xf1\xbb\x9a\x8fc\xff\xf5\xdex.\xbc\xcd/+\x8a\x86\x1d\x84\'\xc3\xa6\x1d\xd8J' @@ -47,7 +46,7 @@ of a message. .. doctest:: - >>> h = hmac.HMAC(key, hashes.SHA256(), backend=default_backend()) + >>> h = hmac.HMAC(key, hashes.SHA256()) >>> h.update(b"message to hash") >>> h.verify(b"an incorrect signature") Traceback (most recent call last): @@ -60,7 +59,7 @@ of a message. :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` instance such as those described in :ref:`Cryptographic Hashes `. - :param backend: An + :param backend: An optional :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` instance. diff --git a/docs/hazmat/primitives/mac/index.rst b/docs/hazmat/primitives/mac/index.rst index 86c407c43456..8bfe29e30bdf 100644 --- a/docs/hazmat/primitives/mac/index.rst +++ b/docs/hazmat/primitives/mac/index.rst @@ -3,48 +3,17 @@ Message authentication codes ============================ -While cryptography supports both the CMAC and HMAC algorithms, we strongly -recommend that HMAC should be used unless you have a good reason otherwise. +While cryptography supports multiple MAC algorithms, we strongly +recommend that HMAC should be used unless you have a very specific need. For more information on why HMAC is preferred, see `Use cases for CMAC vs. HMAC?`_ -HMAC and CMAC both use the ``MACContext`` interface: - -.. currentmodule:: cryptography.hazmat.primitives.mac - -.. class:: MACContext - - .. versionadded:: 0.7 - - .. method:: update(data) - - :param bytes data: The data you want to authenticate. - - .. method:: finalize() - - :return: The message authentication code. - - .. method:: copy() - - :return: A - :class:`~cryptography.hazmat.primitives.mac.MACContext` that - is a copy of the current context. - - .. method:: verify(signature) - - :param bytes signature: The signature to verify. - - :raises cryptography.exceptions.InvalidSignature: This is raised when - the provided signature does not match the expected signature. - - - -.. _`CMAC`: https://en.wikipedia.org/wiki/CMAC -.. _`Use cases for CMAC vs. HMAC?`: https://crypto.stackexchange.com/questions/15721/use-cases-for-cmac-vs-hmac - .. toctree:: :maxdepth: 1 cmac hmac + poly1305 + +.. _`Use cases for CMAC vs. HMAC?`: https://crypto.stackexchange.com/questions/15721/use-cases-for-cmac-vs-hmac diff --git a/docs/hazmat/primitives/mac/poly1305.rst b/docs/hazmat/primitives/mac/poly1305.rst new file mode 100644 index 000000000000..7504a076e81b --- /dev/null +++ b/docs/hazmat/primitives/mac/poly1305.rst @@ -0,0 +1,132 @@ +.. hazmat:: + +Poly1305 +======== + +.. currentmodule:: cryptography.hazmat.primitives.poly1305 + +.. testsetup:: + + key = b"\x01" * 32 + +Poly1305 is an authenticator that takes a 32-byte key and a message and +produces a 16-byte tag. This tag is used to authenticate the message. Each key +**must** only be used once. Using the same key to generate tags for multiple +messages allows an attacker to forge tags. Poly1305 is described in +:rfc:`7539`. + +.. class:: Poly1305(key) + + .. versionadded:: 2.7 + + .. warning:: + + Using the same key to generate tags for multiple messages allows an + attacker to forge tags. Always generate a new key per message you want + to authenticate. If you are using this as a MAC for + symmetric encryption please use + :class:`~cryptography.hazmat.primitives.ciphers.aead.ChaCha20Poly1305` + instead. + + .. doctest:: + + >>> from cryptography.hazmat.primitives import poly1305 + >>> p = poly1305.Poly1305(key) + >>> p.update(b"message to authenticate") + >>> p.finalize() + b'T\xae\xff3\xbdW\xef\xd5r\x01\xe2n=\xb7\xd2h' + + To check that a given tag is correct use the :meth:`verify` method. + You will receive an exception if the tag is wrong: + + .. doctest:: + + >>> p = poly1305.Poly1305(key) + >>> p.update(b"message to authenticate") + >>> p.verify(b"an incorrect tag") + Traceback (most recent call last): + ... + cryptography.exceptions.InvalidSignature: Value did not match computed tag. + + :param key: Secret key as ``bytes``. + :type key: :term:`bytes-like` + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if + the version of OpenSSL ``cryptography`` is compiled against does not + support this algorithm. + + .. method:: update(data) + + :param data: The bytes to hash and authenticate. + :type data: :term:`bytes-like` + :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize` + :raises TypeError: This exception is raised if ``data`` is not ``bytes``. + + .. method:: verify(tag) + + Finalize the current context and securely compare the MAC to + ``tag``. + + :param bytes tag: The bytes to compare against. + :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize` + :raises cryptography.exceptions.InvalidSignature: If tag does not + match. + :raises TypeError: This exception is raised if ``tag`` is not + ``bytes``. + + .. method:: finalize() + + Finalize the current context and return the message authentication code + as bytes. + + After ``finalize`` has been called this object can no longer be used + and :meth:`update`, :meth:`verify`, and :meth:`finalize` + will raise an :class:`~cryptography.exceptions.AlreadyFinalized` + exception. + + :return bytes: The message authentication code as bytes. + :raises cryptography.exceptions.AlreadyFinalized: + + .. classmethod:: generate_tag(key, data) + + A single step alternative to do sign operations. Returns the message + authentication code as ``bytes`` for the given ``key`` and ``data``. + + :param key: Secret key as ``bytes``. + :type key: :term:`bytes-like` + :param data: The bytes to hash and authenticate. + :type data: :term:`bytes-like` + :return bytes: The message authentication code as bytes. + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if + the version of OpenSSL ``cryptography`` is compiled against does not + support this algorithm. + :raises TypeError: This exception is raised if ``key`` or ``data`` are + not ``bytes``. + + .. doctest:: + + >>> poly1305.Poly1305.generate_tag(key, b"message to authenticate") + b'T\xae\xff3\xbdW\xef\xd5r\x01\xe2n=\xb7\xd2h' + + .. classmethod:: verify_tag(key, data, tag) + + A single step alternative to do verify operations. Securely compares the + MAC to ``tag``, using the given ``key`` and ``data``. + + :param key: Secret key as ``bytes``. + :type key: :term:`bytes-like` + :param data: The bytes to hash and authenticate. + :type data: :term:`bytes-like` + :param bytes tag: The bytes to compare against. + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if + the version of OpenSSL ``cryptography`` is compiled against does not + support this algorithm. + :raises TypeError: This exception is raised if ``key``, ``data`` or + ``tag`` are not ``bytes``. + :raises cryptography.exceptions.InvalidSignature: If tag does not match. + + .. doctest:: + + >>> poly1305.Poly1305.verify_tag(key, b"message to authenticate", b"an incorrect tag") + Traceback (most recent call last): + ... + cryptography.exceptions.InvalidSignature: Value did not match computed tag. diff --git a/docs/hazmat/primitives/padding.rst b/docs/hazmat/primitives/padding.rst index 9581df88bd70..99d500a05b68 100644 --- a/docs/hazmat/primitives/padding.rst +++ b/docs/hazmat/primitives/padding.rst @@ -107,7 +107,8 @@ multiple of the block size. .. method:: update(data) - :param bytes data: The data you wish to pass into the context. + :param data: The data you wish to pass into the context. + :type data: :term:`bytes-like` :return bytes: Returns the data that was padded or unpadded. :raises TypeError: Raised if data is not bytes. :raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`. diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst index 21d12a385104..8551acb2693f 100644 --- a/docs/hazmat/primitives/symmetric-encryption.rst +++ b/docs/hazmat/primitives/symmetric-encryption.rst @@ -11,7 +11,8 @@ where the sender and receiver both use the same secret key. Note that symmetric encryption is **not** sufficient for most applications because it only provides secrecy but not authenticity. That means an attacker can't see the message but an attacker can create bogus messages and force the application to -decrypt them. +decrypt them. In many contexts, a lack of authentication on encrypted messages +can result in a loss of secrecy as well. For this reason it is **strongly** recommended to combine encryption with a message authentication code, such as :doc:`HMAC `, @@ -20,7 +21,7 @@ in an "encrypt-then-MAC" formulation as `described by Colin Percival`_. **To minimize the risk of security issues you should evaluate Fernet to see if it fits your needs before implementing anything using this module.** -.. class:: Cipher(algorithm, mode, backend) +.. class:: Cipher(algorithm, mode, backend=None) Cipher objects combine an algorithm such as :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES` with a @@ -33,25 +34,23 @@ it fits your needs before implementing anything using this module.** >>> import os >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes - >>> from cryptography.hazmat.backends import default_backend - >>> backend = default_backend() >>> key = os.urandom(32) >>> iv = os.urandom(16) - >>> cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend) + >>> cipher = Cipher(algorithms.AES(key), modes.CBC(iv)) >>> encryptor = cipher.encryptor() >>> ct = encryptor.update(b"a secret message") + encryptor.finalize() >>> decryptor = cipher.decryptor() >>> decryptor.update(ct) + decryptor.finalize() b'a secret message' - :param algorithms: A + :param algorithm: A :class:`~cryptography.hazmat.primitives.ciphers.CipherAlgorithm` instance such as those described :ref:`below `. :param mode: A :class:`~cryptography.hazmat.primitives.ciphers.modes.Mode` instance such as those described :ref:`below `. - :param backend: A + :param backend: An optional :class:`~cryptography.hazmat.backends.interfaces.CipherBackend` instance. @@ -147,10 +146,9 @@ Algorithms .. doctest:: >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes - >>> from cryptography.hazmat.backends import default_backend >>> nonce = os.urandom(16) >>> algorithm = algorithms.ChaCha20(key, nonce) - >>> cipher = Cipher(algorithm, mode=None, backend=default_backend()) + >>> cipher = Cipher(algorithm, mode=None) >>> encryptor = cipher.encryptor() >>> ct = encryptor.update(b"a secret message") >>> decryptor = cipher.decryptor() @@ -231,9 +229,8 @@ Weak ciphers .. doctest:: >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes - >>> from cryptography.hazmat.backends import default_backend >>> algorithm = algorithms.ARC4(key) - >>> cipher = Cipher(algorithm, mode=None, backend=default_backend()) + >>> cipher = Cipher(algorithm, mode=None) >>> encryptor = cipher.encryptor() >>> ct = encryptor.update(b"a secret message") >>> decryptor = cipher.decryptor() @@ -418,9 +415,6 @@ Modes :raises ValueError: This is raised if ``len(tag) < min_tag_length`` or the ``initialization_vector`` is too short. - :raises NotImplementedError: This is raised if the version of the OpenSSL - backend used is 1.0.1 or earlier. - An example of securely encrypting and decrypting data with ``AES`` in the ``GCM`` mode looks like: @@ -428,7 +422,6 @@ Modes import os - from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.ciphers import ( Cipher, algorithms, modes ) @@ -442,7 +435,6 @@ Modes encryptor = Cipher( algorithms.AES(key), modes.GCM(iv), - backend=default_backend() ).encryptor() # associated_data will be authenticated but not encrypted, @@ -461,7 +453,6 @@ Modes decryptor = Cipher( algorithms.AES(key), modes.GCM(iv, tag), - backend=default_backend() ).decryptor() # We put associated_data back in or the tag will fail to verify @@ -598,11 +589,9 @@ Interfaces >>> import os >>> from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes - >>> from cryptography.hazmat.backends import default_backend - >>> backend = default_backend() >>> key = os.urandom(32) >>> iv = os.urandom(16) - >>> cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend) + >>> cipher = Cipher(algorithms.AES(key), modes.CBC(iv)) >>> encryptor = cipher.encryptor() >>> # the buffer needs to be at least len(data) + n - 1 where n is cipher/mode block size in bytes >>> buf = bytearray(31) @@ -681,18 +670,12 @@ Interfaces .. method:: finalize_with_tag(tag) - .. note:: - - This method is not supported when compiled against OpenSSL 1.0.1. - :param bytes tag: The tag bytes to verify after decryption. :return bytes: Returns the remainder of the data. :raises ValueError: This is raised when the data provided isn't a multiple of the algorithm's block size, if ``min_tag_length`` is less than 4, or if ``len(tag) < min_tag_length``. ``min_tag_length`` is an argument to the ``GCM`` constructor. - :raises NotImplementedError: This is raised if the version of the - OpenSSL backend used is 1.0.1 or earlier. If the authentication tag was not already supplied to the constructor of the :class:`~cryptography.hazmat.primitives.ciphers.modes.GCM` mode @@ -828,7 +811,7 @@ Exceptions .. _`Communications Security Establishment`: https://www.cse-cst.gc.ca .. _`encrypt`: https://ssd.eff.org/en/module/what-should-i-know-about-encryption .. _`CRYPTREC`: https://www.cryptrec.go.jp/english/ -.. _`significant patterns in the output`: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29 +.. _`significant patterns in the output`: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_(ECB) .. _`International Data Encryption Algorithm`: https://en.wikipedia.org/wiki/International_Data_Encryption_Algorithm .. _`OpenPGP`: https://www.openpgp.org/ .. _`disk encryption`: https://en.wikipedia.org/wiki/Disk_encryption_theory#XTS diff --git a/docs/hazmat/primitives/twofactor.rst b/docs/hazmat/primitives/twofactor.rst index 51625dfc28e2..1d2ab452ce0a 100644 --- a/docs/hazmat/primitives/twofactor.rst +++ b/docs/hazmat/primitives/twofactor.rst @@ -18,7 +18,7 @@ codes (HMAC). .. currentmodule:: cryptography.hazmat.primitives.twofactor.hotp -.. class:: HOTP(key, length, algorithm, backend, enforce_key_length=True) +.. class:: HOTP(key, length, algorithm, backend=None, enforce_key_length=True) .. versionadded:: 0.3 @@ -33,11 +33,10 @@ codes (HMAC). .. doctest:: >>> import os - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives.twofactor.hotp import HOTP >>> from cryptography.hazmat.primitives.hashes import SHA1 >>> key = os.urandom(20) - >>> hotp = HOTP(key, 6, SHA1(), backend=default_backend()) + >>> hotp = HOTP(key, 6, SHA1()) >>> hotp_value = hotp.generate(0) >>> hotp.verify(hotp_value, 0) @@ -49,15 +48,15 @@ codes (HMAC). :param cryptography.hazmat.primitives.hashes.HashAlgorithm algorithm: A :class:`~cryptography.hazmat.primitives.hashes` instance. - :param backend: A + :param backend: An optional :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` instance. :param enforce_key_length: A boolean flag defaulting to True that toggles whether a minimum key length of 128 :term:`bits` is enforced. This exists to work around the fact that as documented in `Issue #2915`_, the Google Authenticator PAM module by default generates 80 bit keys. - If this flag is set to False, the application develop should implement - additional checks of the key length before passing it into + If this flag is set to False, the application developer should + implement additional checks of the key length before passing it into :class:`~cryptography.hazmat.primitives.twofactor.hotp.HOTP`. .. versionadded:: 1.5 @@ -129,7 +128,7 @@ similar to the following code. assert look_ahead >= 0 correct_counter = None - otp = HOTP(key, 6, default_backend()) + otp = HOTP(key, 6) for count in range(counter, counter + look_ahead): try: otp.verify(hotp, count) @@ -141,7 +140,7 @@ similar to the following code. .. currentmodule:: cryptography.hazmat.primitives.twofactor.totp -.. class:: TOTP(key, length, algorithm, time_step, backend, enforce_key_length=True) +.. class:: TOTP(key, length, algorithm, time_step, backend=None, enforce_key_length=True) TOTP objects take a ``key``, ``length``, ``algorithm`` and ``time_step`` parameter. The ``key`` should be :doc:`randomly generated bytes @@ -155,11 +154,10 @@ similar to the following code. >>> import os >>> import time - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives.twofactor.totp import TOTP >>> from cryptography.hazmat.primitives.hashes import SHA1 >>> key = os.urandom(20) - >>> totp = TOTP(key, 8, SHA1(), 30, backend=default_backend()) + >>> totp = TOTP(key, 8, SHA1(), 30) >>> time_value = time.time() >>> totp_value = totp.generate(time_value) >>> totp.verify(totp_value, time_value) @@ -173,7 +171,7 @@ similar to the following code. :class:`~cryptography.hazmat.primitives.hashes` instance. :param int time_step: The time step size. The recommended size is 30. - :param backend: A + :param backend: An optional :class:`~cryptography.hazmat.backends.interfaces.HMACBackend` instance. :param enforce_key_length: A boolean flag defaulting to True that toggles diff --git a/docs/index.rst b/docs/index.rst index 9ff8664e17c5..ec3913f41d8c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -19,7 +19,8 @@ key derivation functions. For example, to encrypt something with 'A really secret message. Not for prying eyes.' If you are interested in learning more about the field of cryptography, we -recommend `Crypto 101, by Laurens Van Houtven`_. +recommend `Crypto 101, by Laurens Van Houtven`_ and `The Cryptopals Crypto +Challenges`_. Installation ------------ @@ -67,7 +68,6 @@ hazmat layer only when necessary. exceptions random-numbers hazmat/backends/index - hazmat/bindings/index .. toctree:: :maxdepth: 2 @@ -92,3 +92,4 @@ hazmat layer only when necessary. :doc:`get in touch `. .. _`Crypto 101, by Laurens Van Houtven`: https://www.crypto101.io/ +.. _`The Cryptopals Crypto Challenges`: https://cryptopals.com/ diff --git a/docs/installation.rst b/docs/installation.rst index 5b2854d96b87..c773fdce5d69 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -10,29 +10,31 @@ You can install ``cryptography`` with ``pip``: Supported platforms ------------------- -Currently we test ``cryptography`` on Python 2.7, 3.4+, and -PyPy 5.4+ on these operating systems. +Currently we test ``cryptography`` on Python 2.7, 3.5+, +PyPy 7.3.1, and PyPy3 7.3.1 on these operating systems. * x86-64 CentOS 7.x -* macOS 10.12 Sierra, 10.11 El Capitan -* x86-64 Ubuntu 14.04, 16.04, and rolling -* x86-64 Debian Wheezy (7.x), Jessie (8.x), Stretch (9.x), and Sid (unstable) +* x86-64 & AArch64 CentOS 8.x +* x86-64 Fedora (latest) +* x86-64 macOS 10.15 Catalina +* x86-64 & AArch64 Ubuntu 18.04, 20.04 +* x86-64 Ubuntu rolling +* x86-64 Debian Stretch (9.x), Buster (10.x), Bullseye (11.x), and Sid + (unstable) * x86-64 Alpine (latest) -* 32-bit and 64-bit Python on 64-bit Windows Server 2012 +* 32-bit and 64-bit Python on 64-bit Windows Server 2019 We test compiling with ``clang`` as well as ``gcc`` and use the following OpenSSL releases: -* ``OpenSSL 1.0.1`` -* ``OpenSSL 1.0.1e-fips`` (``RHEL/CentOS 7``) -* ``OpenSSL 1.0.1f`` * ``OpenSSL 1.0.2-latest`` * ``OpenSSL 1.1.0-latest`` * ``OpenSSL 1.1.1-latest`` .. warning:: - Cryptography 2.4 has deprecated support for OpenSSL 1.0.1. + Cryptography 3.2 has dropped support for OpenSSL 1.0.2, see the + :doc:`FAQ ` for more details Building cryptography on Windows -------------------------------- @@ -46,12 +48,11 @@ just run $ pip install cryptography If you prefer to compile it yourself you'll need to have OpenSSL installed. -You can compile OpenSSL yourself as well or use the binaries we build for our -release infrastructure (`openssl-release`_). Be sure to download the proper -version for your architecture and Python (2010 works for Python 2.7, 3.3, -and 3.4 while 2015 is required for 3.5 and above). Wherever you place your copy -of OpenSSL you'll need to set the ``LIB`` and ``INCLUDE`` environment variables -to include the proper locations. For example: +You can compile OpenSSL yourself as well or use `a binary distribution`_. +Be sure to download the proper version for your architecture and Python +(VC2010 works for Python 2.7 while VC2015 is required for 3.5 and above). +Wherever you place your copy of OpenSSL you'll need to set the ``LIB`` and ``INCLUDE`` +environment variables to include the proper locations. For example: .. code-block:: console @@ -74,10 +75,10 @@ local `wheel cache`_. Building cryptography on Linux ------------------------------ -``cryptography`` ships a ``manylinux1`` wheel (as of 2.0) so all dependencies -are included. For users on pip 8.1 or above running on a ``manylinux1`` -compatible distribution (almost everything except Alpine) all you should -need to do is: +``cryptography`` ships ``manylinux`` wheels (as of 2.0) so all dependencies +are included. For users on pip 8.1 or above running on a ``manylinux1`` or +``manylinux2010`` compatible distribution (almost everything except Alpine) +all you should need to do is: .. code-block:: console @@ -121,8 +122,8 @@ Building ~~~~~~~~ You should now be able to build and install cryptography. To avoid getting -the pre-built wheel on ``manylinux1`` distributions you'll need to use -``--no-binary``. +the pre-built wheel on ``manylinux`` compatible distributions you'll need to +use ``--no-binary``. .. code-block:: console @@ -162,9 +163,9 @@ Static Wheels ~~~~~~~~~~~~~ Cryptography ships statically-linked wheels for macOS, Windows, and Linux (via -``manylinux1``). This allows compatible environments to use the most recent +``manylinux``). This allows compatible environments to use the most recent OpenSSL, regardless of what is shipped by default on those platforms. Some -Linux distributions (most notably Alpine) are not ``manylinux1`` compatible so +Linux distributions (most notably Alpine) are not ``manylinux`` compatible so we cannot distribute wheels for them. However, you can build your own statically-linked wheels that will work on your @@ -228,7 +229,7 @@ users with pip 8 or above you only need one step: If you want to build cryptography yourself or are on an older macOS version, cryptography requires the presence of a C compiler, development headers, and the proper libraries. On macOS much of this is provided by Apple's Xcode -development tools. To install the Xcode command line tools (on macOS 10.9+) +development tools. To install the Xcode command line tools (on macOS 10.10+) open a terminal window and run: .. code-block:: console @@ -279,7 +280,7 @@ local `wheel cache`_. .. _`Homebrew`: https://brew.sh .. _`MacPorts`: https://www.macports.org -.. _`openssl-release`: https://ci.cryptography.io/job/cryptography-support-jobs/job/openssl-release-1.1/ +.. _`a binary distribution`: https://wiki.openssl.org/index.php/Binaries .. _virtualenv: https://virtualenv.pypa.io/en/latest/ .. _openssl.org: https://www.openssl.org/source/ .. _`wheel cache`: https://pip.pypa.io/en/stable/reference/pip_install/#caching diff --git a/docs/limitations.rst b/docs/limitations.rst index 503bdfe48c87..092d8a7cff91 100644 --- a/docs/limitations.rst +++ b/docs/limitations.rst @@ -1,19 +1,24 @@ Known security limitations --------------------------- +========================== -Lack of secure memory wiping -============================ +Secure memory wiping +-------------------- `Memory wiping`_ is used to protect secret data or key material from attackers -with access to uninitialized memory. This can be either because the attacker -has some kind of local user access or because of how other software uses -uninitialized memory. +with access to deallocated memory. This is a defense-in-depth measure against +vulnerabilities that leak application memory. -Python exposes no API for us to implement this reliably and as such almost all -software in Python is potentially vulnerable to this attack. The +Many ``cryptography`` APIs which accept ``bytes`` also accept types which +implement the buffer interface. Thus, users wishing to do so can pass +``memoryview`` or another mutable type to ``cryptography`` APIs, and overwrite +the contents once the data is no longer needed. + +However, ``cryptography`` does not clear memory by default, as there is no way +to clear immutable structures such as ``bytes``. As a result, ``cryptography``, +like almost all software in Python is potentially vulnerable to this attack. The `CERT secure coding guidelines`_ assesses this issue as "Severity: medium, Likelihood: unlikely, Remediation Cost: expensive to repair" and we do not consider this a high risk for most users. -.. _`Memory wiping`: https://blogs.msdn.microsoft.com/oldnewthing/20130529-00/?p=4223/ -.. _`CERT secure coding guidelines`: https://www.securecoding.cert.org/confluence/display/c/MEM03-C.+Clear+sensitive+information+stored+in+reusable+resources +.. _`Memory wiping`: https://devblogs.microsoft.com/oldnewthing/?p=4223 +.. _`CERT secure coding guidelines`: https://wiki.sei.cmu.edu/confluence/display/c/MEM03-C.+Clear+sensitive+information+stored+in+reusable+resources diff --git a/docs/security.rst b/docs/security.rst index 01845a48cc27..8cdd2d114d9a 100644 --- a/docs/security.rst +++ b/docs/security.rst @@ -9,9 +9,9 @@ Infrastructure -------------- In addition to ``cryptography``'s code, we're also concerned with the security -of the infrastructure we run (primarily ``cryptography.io`` and -``ci.cryptography.io``). If you discover a security vulnerability in our -infrastructure, we ask you to report it using the same procedure. +of the infrastructure we run (primarily ``cryptography.io``). If you discover +a security vulnerability in our infrastructure, we ask you to report it using +the same procedure. What is a security issue? ------------------------- @@ -72,9 +72,9 @@ New releases for OpenSSL updates -------------------------------- As of versions 0.5, 1.0.1, and 2.0.0, ``cryptography`` statically links OpenSSL -on Windows, macOS, and Linux respectively, to ease installation. Due to this, -``cryptography`` will release a new version whenever OpenSSL has a security or -bug fix release to avoid shipping insecure software. +in binary distributions for Windows, macOS, and Linux respectively, to ease +installation. Due to this, ``cryptography`` will release a new version whenever +OpenSSL has a security or bug fix release to avoid shipping insecure software. Like all our other releases, this will be announced on the mailing list and we strongly recommend that you upgrade as soon as possible. diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index 7e08f1241342..c8c275142ff7 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -1,14 +1,18 @@ +AArch accessor affine Authenticator +authenticator backend Backends backends bcrypt +Bleichenbacher Blowfish boolean Botan Brainpool +Bullseye Capitan changelog Changelog @@ -17,11 +21,13 @@ codebook committer committers conda +CPython Cryptanalysis crypto cryptographic cryptographically Debian +deallocated decrypt decrypts Decrypts @@ -50,9 +56,9 @@ Google hazmat Homebrew hostname -idna indistinguishability initialisms +interoperability interoperable introspectability invariants @@ -76,6 +82,7 @@ Parallelization personalization pickleable plaintext +Poly pre precompute preprocessor @@ -83,6 +90,7 @@ preprocessors presentational pseudorandom pyOpenSSL +pytest relicensed responder runtime diff --git a/docs/x509/ocsp.rst b/docs/x509/ocsp.rst index d3815d6f3a32..0c2d07aef852 100644 --- a/docs/x509/ocsp.rst +++ b/docs/x509/ocsp.rst @@ -167,12 +167,11 @@ Creating Requests .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import serialization >>> from cryptography.hazmat.primitives.hashes import SHA1 >>> from cryptography.x509 import load_pem_x509_certificate, ocsp - >>> cert = load_pem_x509_certificate(pem_cert, default_backend()) - >>> issuer = load_pem_x509_certificate(pem_issuer, default_backend()) + >>> cert = load_pem_x509_certificate(pem_cert) + >>> issuer = load_pem_x509_certificate(pem_issuer) >>> builder = ocsp.OCSPRequestBuilder() >>> # SHA1 is in this example because RFC 5019 mandates its use. >>> builder = builder.add_certificate(cert, issuer, SHA1()) @@ -292,27 +291,35 @@ Creating Responses :attr:`~cryptography.x509.ocsp.OCSPResponseStatus.SUCCESSFUL` response. :param private_key: The - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey` - or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, + :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. :param algorithm: The :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` that - will be used to generate the signature. + will be used to generate the signature. This must be ``None`` if + the ``private_key`` is an + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey` + or an + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey` + and an instance of a + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + otherwise. :returns: A new :class:`~cryptography.x509.ocsp.OCSPResponse`. .. doctest:: >>> import datetime - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes, serialization >>> from cryptography.x509 import load_pem_x509_certificate, ocsp - >>> cert = load_pem_x509_certificate(pem_cert, default_backend()) - >>> issuer = load_pem_x509_certificate(pem_issuer, default_backend()) - >>> responder_cert = load_pem_x509_certificate(pem_responder_cert, default_backend()) - >>> responder_key = serialization.load_pem_private_key(pem_responder_key, None, default_backend()) + >>> cert = load_pem_x509_certificate(pem_cert) + >>> issuer = load_pem_x509_certificate(pem_issuer) + >>> responder_cert = load_pem_x509_certificate(pem_responder_cert) + >>> responder_key = serialization.load_pem_private_key(pem_responder_key, None) >>> builder = ocsp.OCSPResponseBuilder() >>> # SHA1 is in this example because RFC 5019 mandates its use. >>> builder = builder.add_response( @@ -341,7 +348,6 @@ Creating Responses .. doctest:: - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes, serialization >>> from cryptography.x509 import load_pem_x509_certificate, ocsp >>> response = ocsp.OCSPResponseBuilder.build_unsuccessful( @@ -434,7 +440,10 @@ Interfaces Returns the :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` which - was used in signing this response. + was used in signing this response. Can be ``None`` if signature + did not use separate hash + (:attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED25519`, + :attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED448`). .. attribute:: signature @@ -589,6 +598,14 @@ Interfaces The extensions encoded in the response. + .. attribute:: single_extensions + + .. versionadded:: 2.9 + + :type: :class:`~cryptography.x509.Extensions` + + The single extensions encoded in the response. + .. method:: public_bytes(encoding) :param encoding: The encoding to use. Only diff --git a/docs/x509/reference.rst b/docs/x509/reference.rst index b2278d57f768..a46c5d623238 100644 --- a/docs/x509/reference.rst +++ b/docs/x509/reference.rst @@ -22,22 +22,20 @@ X.509 Reference pem_req_data = b""" -----BEGIN CERTIFICATE REQUEST----- - MIIC0zCCAbsCAQAwWTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAw - DgYDVQQHDAdDaGljYWdvMREwDwYDVQQKDAhyNTA5IExMQzESMBAGA1UEAwwJaGVs - bG8uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqhZx+Mo9VRd9 - vsnWWa6NBCws21rZ0+1B/JGgB4hDsZS7iDE4Bj5z4idheFRtl8bBbdjPknq7BfoF - 8v15Zq/Zv7i2xMSDL+LUrTBZezRd4bRTGqCm6YJ5EYkhqdcqeZleHCFImguHoq1J - Fh0+kObQrTHXw3ZP57a3o1IvyIUA3nNoCBL0QQhwBXaDXOojMKNR+bqB5ve8GS1y - Elr0AM/+cJsfaIahNQUgFKx3Eu3GeEOMKYOAG1lycgdQdmTUybLrT3U7vkClTseM - xHg1r5En7ALjONIhqRuq3rddYahrP8HXozb3zUy3cJ7P6IeaosuvNzvMXOX9P6HD - Ha9urDAJ1wIDAQABoDUwMwYJKoZIhvcNAQkOMSYwJDAiBgNVHREEGzAZggl3b3Js - ZC5jb22CDHdoYXRldmVyLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEAS4Ro6h+z52SK - YSLCYARpnEu/rmh4jdqndt8naqcNb6uLx9mlKZ2W9on9XDjnSdQD9q+ZP5aZfESw - R0+rJhW9ZrNa/g1pt6M24ihclHYDAxYMWxT1z/TXXGM3TmZZ6gfYlNE1kkBuODHa - UYsR/1Ht1E1EsmmUimt2n+zQR2K8T9Coa+boaUW/GsTEuz1aaJAkj5ZvTDiIhRG4 - AOCqFZOLAQmCCNgJnnspD9hDz/Ons085LF5wnYjN4/Nsk5tS6AGs3xjZ3jPoOGGn - 82WQ9m4dBGoVDZXsobVTaN592JEYwN5iu72zRn7Einb4V4H5y3yD2dD4yWPlt4pk - 5wFkeYsZEA== + MIICcDCCAVgCAQAwDTELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IB + DwAwggEKAoIBAQCb+ec0zYAYLzk/MDdDJYvzdvEO2ZUrBYM6z1r8NedwpJfxUWqC + hvK1cpc9EbQeCwS1eooTIGoNveeCrwL+pWdmf1sh6gz7SsxdN/07nyhSM8M6Xkec + +tGrjyi1H/N1afwWXox3WcvBNbxu3Df5RKLDb0yt9aqhmJylbl/tbvgJesXymwmp + Rc1vXL0fOedUtuAJ3xQ15M0pgLF8qDn4lySJz25x76pMYPeN5/a7x+SR/jj81kep + VaVpuh/2hePV5uwUX3uWoj5sAkrBCifi4NPge0Npd6KeKVvXytLOymH/4+WvV719 + wCO+MyrkhpdHSakJDTIaQIxsqVeVVKdPLAPJAgMBAAGgHjAcBgkqhkiG9w0BCQcx + DwwNY2hhbGxlbmdlIG1lITANBgkqhkiG9w0BAQsFAAOCAQEAMmgeSa8szbjPFD/4 + vcPBr/vBEROFGgL8mX3o5pF9gpr7nRjhLKBkgJvlRm6Ma3Xvdfc/r5Hp2ZBTA7sZ + ZYhyeezGfCQN/Qhda1v+sCwG58IjvGfCSS7Y5tGlEBQ4MDf0Q7PYPSxaNUEBH7vo + +M7U+nFuNSmyWlt6SFBSkohZkWoVSGx3KsAO+SAHYZ7JtqsAS/dm7Dflp8KxeDg7 + wzGBDQRpGF4CpI1VQjGSJQXSEdD+J7mtvBEOD34abRfV6zOUGzOOo3NWE6wNpYgt + 0A7gVlzSYpdwqjBdvACfXR2r/mu+4KkAvYh8WwCiTcYgGjl2pT1bO4hEmcJ0RSWy + /fGD8Q== -----END CERTIFICATE REQUEST----- """.strip() @@ -151,7 +149,7 @@ X.509 Reference Loading Certificates ~~~~~~~~~~~~~~~~~~~~ -.. function:: load_pem_x509_certificate(data, backend) +.. function:: load_pem_x509_certificate(data, backend=None) .. versionadded:: 0.7 @@ -161,7 +159,7 @@ Loading Certificates :param bytes data: The PEM encoded certificate data. - :param backend: A backend supporting the + :param backend: An optional backend supporting the :class:`~cryptography.hazmat.backends.interfaces.X509Backend` interface. @@ -170,12 +168,11 @@ Loading Certificates .. doctest:: >>> from cryptography import x509 - >>> from cryptography.hazmat.backends import default_backend - >>> cert = x509.load_pem_x509_certificate(pem_data, default_backend()) + >>> cert = x509.load_pem_x509_certificate(pem_data) >>> cert.serial_number 2 -.. function:: load_der_x509_certificate(data, backend) +.. function:: load_der_x509_certificate(data, backend=None) .. versionadded:: 0.7 @@ -185,7 +182,7 @@ Loading Certificates :param bytes data: The DER encoded certificate data. - :param backend: A backend supporting the + :param backend: An optional backend supporting the :class:`~cryptography.hazmat.backends.interfaces.X509Backend` interface. @@ -194,7 +191,7 @@ Loading Certificates Loading Certificate Revocation Lists ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. function:: load_pem_x509_crl(data, backend) +.. function:: load_pem_x509_crl(data, backend=None) .. versionadded:: 1.1 @@ -204,7 +201,7 @@ Loading Certificate Revocation Lists :param bytes data: The PEM encoded request data. - :param backend: A backend supporting the + :param backend: An optional backend supporting the :class:`~cryptography.hazmat.backends.interfaces.X509Backend` interface. @@ -214,13 +211,12 @@ Loading Certificate Revocation Lists .. doctest:: >>> from cryptography import x509 - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes - >>> crl = x509.load_pem_x509_crl(pem_crl_data, default_backend()) + >>> crl = x509.load_pem_x509_crl(pem_crl_data) >>> isinstance(crl.signature_hash_algorithm, hashes.SHA256) True -.. function:: load_der_x509_crl(data, backend) +.. function:: load_der_x509_crl(data, backend=None) .. versionadded:: 1.1 @@ -229,7 +225,7 @@ Loading Certificate Revocation Lists :param bytes data: The DER encoded request data. - :param backend: A backend supporting the + :param backend: An optional backend supporting the :class:`~cryptography.hazmat.backends.interfaces.X509Backend` interface. @@ -239,7 +235,7 @@ Loading Certificate Revocation Lists Loading Certificate Signing Requests ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. function:: load_pem_x509_csr(data, backend) +.. function:: load_pem_x509_csr(data, backend=None) .. versionadded:: 0.9 @@ -250,7 +246,7 @@ Loading Certificate Signing Requests :param bytes data: The PEM encoded request data. - :param backend: A backend supporting the + :param backend: An optional backend supporting the :class:`~cryptography.hazmat.backends.interfaces.X509Backend` interface. @@ -260,13 +256,12 @@ Loading Certificate Signing Requests .. doctest:: >>> from cryptography import x509 - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes - >>> csr = x509.load_pem_x509_csr(pem_req_data, default_backend()) - >>> isinstance(csr.signature_hash_algorithm, hashes.SHA1) + >>> csr = x509.load_pem_x509_csr(pem_req_data) + >>> isinstance(csr.signature_hash_algorithm, hashes.SHA256) True -.. function:: load_der_x509_csr(data, backend) +.. function:: load_der_x509_csr(data, backend=None) .. versionadded:: 0.9 @@ -275,7 +270,7 @@ Loading Certificate Signing Requests :param bytes data: The DER encoded request data. - :param backend: A backend supporting the + :param backend: An optional backend supporting the :class:`~cryptography.hazmat.backends.interfaces.X509Backend` interface. @@ -335,10 +330,12 @@ X.509 Certificate Object The public key associated with the certificate. - :returns: - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` + :returns: One of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PublicKey` .. doctest:: @@ -393,7 +390,10 @@ X.509 Certificate Object Returns the :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` which - was used in signing this certificate. + was used in signing this certificate. Can be ``None`` if signature + did not use separate hash + (:attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED25519`, + :attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED448`). .. doctest:: @@ -429,16 +429,13 @@ X.509 Certificate Object :raises cryptography.x509.UnsupportedGeneralNameType: If an extension contains a general name that is not supported. - :raises UnicodeError: If an extension contains IDNA encoding that is - invalid or not compliant with IDNA 2008. - .. doctest:: >>> for ext in cert.extensions: ... print(ext) , critical=False, value=)> , critical=False, value=)> - , critical=True, value=)> + , critical=True, value=)> , critical=False, value=, policy_qualifiers=None)>])>)> , critical=True, value=)> @@ -474,8 +471,8 @@ X.509 Certificate Object >>> from cryptography.hazmat.primitives.serialization import load_pem_public_key >>> from cryptography.hazmat.primitives.asymmetric import padding - >>> issuer_public_key = load_pem_public_key(pem_issuer_public_key, default_backend()) - >>> cert_to_check = x509.load_pem_x509_certificate(pem_data_to_check, default_backend()) + >>> issuer_public_key = load_pem_public_key(pem_issuer_public_key) + >>> cert_to_check = x509.load_pem_x509_certificate(pem_data_to_check) >>> issuer_public_key.verify( ... cert_to_check.signature, ... cert_to_check.tbs_certificate_bytes, @@ -551,7 +548,10 @@ X.509 CRL (Certificate Revocation List) Object Returns the :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` which - was used in signing this CRL. + was used in signing this CRL. Can be ``None`` if signature + did not use separate hash + (:attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED25519`, + :attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED448`). .. doctest:: @@ -601,7 +601,7 @@ X.509 CRL (Certificate Revocation List) Object :type: :class:`datetime.datetime` - A naïve datetime representing when the this CRL was last updated. + A naïve datetime representing when this CRL was last updated. .. doctest:: @@ -668,7 +668,6 @@ X.509 Certificate Builder .. doctest:: >>> from cryptography import x509 - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric import rsa >>> from cryptography.x509.oid import NameOID @@ -677,7 +676,6 @@ X.509 Certificate Builder >>> private_key = rsa.generate_private_key( ... public_exponent=65537, ... key_size=2048, - ... backend=default_backend() ... ) >>> public_key = private_key.public_key() >>> builder = x509.CertificateBuilder() @@ -702,7 +700,6 @@ X.509 Certificate Builder ... ) >>> certificate = builder.sign( ... private_key=private_key, algorithm=hashes.SHA256(), - ... backend=default_backend() ... ) >>> isinstance(certificate, x509.Certificate) True @@ -727,8 +724,10 @@ X.509 Certificate Builder :param public_key: The subject's public key. This can be one of :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PublicKey`. .. method:: serial_number(serial_number) @@ -775,21 +774,30 @@ 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, backend) + .. method:: sign(private_key, algorithm, backend=None) Sign the certificate using the CA's private key. :param private_key: The :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, + :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. :param algorithm: The :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` that - will be used to generate the signature. + will be used to generate the signature. This must be ``None`` if + the ``private_key`` is an + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey` + or an + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey` + and an instance of a + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + otherwise. - :param backend: Backend that will be used to build the certificate. + :param backend: An optional backend used to build the certificate. Must support the :class:`~cryptography.hazmat.backends.interfaces.X509Backend` interface. @@ -808,10 +816,12 @@ X.509 CSR (Certificate Signing Request) Object The public key associated with the request. - :returns: - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey` + :returns: One of + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PublicKey`. .. doctest:: @@ -832,12 +842,15 @@ X.509 CSR (Certificate Signing Request) Object Returns the :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` which - was used in signing this request. + was used in signing this request. Can be ``None`` if signature + did not use separate hash + (:attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED25519`, + :attr:`~cryptography.x509.oid.SignatureAlgorithmOID.ED448`). .. doctest:: >>> from cryptography.hazmat.primitives import hashes - >>> isinstance(csr.signature_hash_algorithm, hashes.SHA1) + >>> isinstance(csr.signature_hash_algorithm, hashes.SHA256) True .. attribute:: signature_algorithm_oid @@ -853,7 +866,7 @@ X.509 CSR (Certificate Signing Request) Object .. doctest:: >>> csr.signature_algorithm_oid - + .. attribute:: extensions @@ -867,9 +880,17 @@ X.509 CSR (Certificate Signing Request) Object :raises cryptography.x509.UnsupportedGeneralNameType: If an extension contains a general name that is not supported. - :raises UnicodeError: If an extension contains IDNA encoding that is - invalid or not compliant with IDNA 2008. + .. method:: get_attribute_for_oid(oid) + .. versionadded:: 3.0 + + :param oid: An :class:`ObjectIdentifier` instance. + + :returns: The bytes value of the attribute or an exception if not + found. + + :raises cryptography.x509.AttributeNotFound: If the request does + not have the attribute requested. .. method:: public_bytes(encoding) @@ -918,7 +939,6 @@ X.509 Certificate Revocation List Builder .. doctest:: >>> from cryptography import x509 - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric import rsa >>> from cryptography.x509.oid import NameOID @@ -927,7 +947,6 @@ X.509 Certificate Revocation List Builder >>> private_key = rsa.generate_private_key( ... public_exponent=65537, ... key_size=2048, - ... backend=default_backend() ... ) >>> builder = x509.CertificateRevocationListBuilder() >>> builder = builder.issuer_name(x509.Name([ @@ -939,11 +958,10 @@ X.509 Certificate Revocation List Builder ... 333 ... ).revocation_date( ... datetime.datetime.today() - ... ).build(default_backend()) + ... ).build() >>> builder = builder.add_revoked_certificate(revoked_cert) >>> crl = builder.sign( ... private_key=private_key, algorithm=hashes.SHA256(), - ... backend=default_backend() ... ) >>> len(crl) 1 @@ -994,21 +1012,30 @@ X.509 Certificate Revocation List Builder obtained from an existing CRL or created with :class:`~cryptography.x509.RevokedCertificateBuilder`. - .. method:: sign(private_key, algorithm, backend) + .. method:: sign(private_key, algorithm, backend=None) Sign this CRL using the CA's private key. :param private_key: The :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, + :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. :param algorithm: The :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` that will be used to generate the signature. + This must be ``None`` if the ``private_key`` is an + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey` + or an + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey` + and an instance of a + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + otherwise. - :param backend: Backend that will be used to build the CRL. + :param backend: An optional backend used to build the CRL. Must support the :class:`~cryptography.hazmat.backends.interfaces.X509Backend` interface. @@ -1071,12 +1098,11 @@ X.509 Revoked Certificate Builder .. doctest:: >>> from cryptography import x509 - >>> from cryptography.hazmat.backends import default_backend >>> import datetime >>> builder = x509.RevokedCertificateBuilder() >>> builder = builder.revocation_date(datetime.datetime.today()) >>> builder = builder.serial_number(3333) - >>> revoked_certificate = builder.build(default_backend()) + >>> revoked_certificate = builder.build() >>> isinstance(revoked_certificate, x509.RevokedCertificate) True @@ -1104,11 +1130,11 @@ X.509 Revoked Certificate Builder :param critical: Set to ``True`` if the extension must be understood and handled. - .. method:: build(backend) + .. method:: build(backend=None) Create a revoked certificate object using the provided backend. - :param backend: Backend that will be used to build the revoked + :param backend: An optional backend used to build the revoked certificate. Must support the :class:`~cryptography.hazmat.backends.interfaces.X509Backend` interface. @@ -1125,14 +1151,12 @@ X.509 CSR (Certificate Signing Request) Builder Object .. doctest:: >>> from cryptography import x509 - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes >>> from cryptography.hazmat.primitives.asymmetric import rsa - >>> from cryptography.x509.oid import NameOID + >>> from cryptography.x509.oid import AttributeOID, NameOID >>> private_key = rsa.generate_private_key( ... public_exponent=65537, ... key_size=2048, - ... backend=default_backend() ... ) >>> builder = x509.CertificateSigningRequestBuilder() >>> builder = builder.subject_name(x509.Name([ @@ -1141,8 +1165,11 @@ X.509 CSR (Certificate Signing Request) Builder Object >>> builder = builder.add_extension( ... x509.BasicConstraints(ca=False, path_length=None), critical=True, ... ) + >>> builder = builder.add_attribute( + ... AttributeOID.CHALLENGE_PASSWORD, b"changeit" + ... ) >>> request = builder.sign( - ... private_key, hashes.SHA256(), default_backend() + ... private_key, hashes.SHA256() ... ) >>> isinstance(request, x509.CertificateSigningRequest) True @@ -1163,17 +1190,29 @@ X.509 CSR (Certificate Signing Request) Builder Object :returns: A new :class:`~cryptography.x509.CertificateSigningRequestBuilder`. - .. method:: sign(private_key, algorithm, backend) + .. method:: add_attribute(oid, value) - :param backend: Backend that will be used to sign the request. + .. versionadded:: 3.0 + + :param oid: An :class:`ObjectIdentifier` instance. + :param value: The value of the attribute. + :type value: bytes + :returns: A new + :class:`~cryptography.x509.CertificateSigningRequestBuilder`. + + .. method:: sign(private_key, algorithm, backend=None) + + :param backend: An optional backend used to sign the request. Must support the :class:`~cryptography.hazmat.backends.interfaces.X509Backend` interface. :param private_key: The :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey`, - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey` or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey` + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKey`, + :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 request. When the request is signed by a certificate authority, the private key's associated public key will be stored in the resulting certificate. @@ -1181,6 +1220,13 @@ X.509 CSR (Certificate Signing Request) Builder Object :param algorithm: The :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` that will be used to generate the request signature. + This must be ``None`` if the ``private_key`` is an + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey` + or an + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PrivateKey` + and an instance of a + :class:`~cryptography.hazmat.primitives.hashes.HashAlgorithm` + otherwise. :returns: A new :class:`~cryptography.x509.CertificateSigningRequest`. @@ -1236,11 +1282,11 @@ X.509 CSR (Certificate Signing Request) Builder Object >>> cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME) [, value='Good CA')>] - .. method:: public_bytes(backend) + .. method:: public_bytes(backend=None) .. versionadded:: 1.6 - :param backend: A backend supporting the + :param backend: An optional backend supporting the :class:`~cryptography.hazmat.backends.interfaces.X509Backend` interface. @@ -1348,17 +1394,10 @@ General Name Classes .. versionadded:: 0.9 - .. versionchanged:: 2.1 - - .. warning:: - - Starting with version 2.1 :term:`U-label` input is deprecated. If - passing an internationalized domain name (IDN) you should first IDNA - encode the value and then pass the result as a string. Accessing - ``value`` will return the :term:`A-label` encoded form even if you pass - a U-label. This breaks backwards compatibility, but only for - internationalized domain names. + .. versionchanged:: 3.1 + :term:`U-label` support has been removed. Encode them to + :term:`A-label` before use. This corresponds to an email address. For example, ``user@example.com``. @@ -1366,6 +1405,8 @@ General Name Classes internationalized domain name then it must be encoded to an :term:`A-label` string before being passed. + :raises ValueError: If the provided string is not an :term:`A-label`. + .. attribute:: value :type: :term:`text` @@ -1374,16 +1415,10 @@ General Name Classes .. versionadded:: 0.9 - .. versionchanged:: 2.1 + .. versionchanged:: 3.1 - .. warning:: - - Starting with version 2.1 :term:`U-label` input is deprecated. If - passing an internationalized domain name (IDN) you should first IDNA - encode the value and then pass the result as a string. Accessing - ``value`` will return the :term:`A-label` encoded form even if you pass - a U-label. This breaks backwards compatibility, but only for - internationalized domain names. + :term:`U-label` support has been removed. Encode them to + :term:`A-label` before use. This corresponds to a domain name. For example, ``cryptography.io``. @@ -1391,6 +1426,8 @@ General Name Classes name then it must be encoded to an :term:`A-label` string before being passed. + :raises ValueError: If the provided string is not an :term:`A-label`. + :type: :term:`text` .. attribute:: value @@ -1411,16 +1448,10 @@ General Name Classes .. versionadded:: 0.9 - .. versionchanged:: 2.1 - - .. warning:: + .. versionchanged:: 3.1 - Starting with version 2.1 :term:`U-label` input is deprecated. If - passing an internationalized domain name (IDN) you should first IDNA - encode the value and then pass the result as a string. Accessing - ``value`` will return the :term:`A-label` encoded form even if you pass - a U-label. This breaks backwards compatibility, but only for - internationalized domain names. + :term:`U-label` support has been removed. Encode them to + :term:`A-label` before use. This corresponds to a uniform resource identifier. For example, ``https://cryptography.io``. @@ -1429,6 +1460,8 @@ General Name Classes name then it must be encoded to an :term:`A-label` string before being passed. + :raises ValueError: If the provided string is not an :term:`A-label`. + .. attribute:: value :type: :term:`text` @@ -1821,7 +1854,7 @@ X.509 Extensions :type: A list of :class:`GeneralName` instances or None - The :class:`Name` of the issuer's issuer. + The :class:`GeneralName` (one or multiple) of the issuer's issuer. .. attribute:: authority_cert_serial_number @@ -1853,17 +1886,16 @@ X.509 Extensions section 4.2.1.2. :param public_key: One of - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey` - , - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` - , or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`. + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PublicKey`. .. doctest:: >>> from cryptography import x509 - >>> from cryptography.hazmat.backends import default_backend - >>> issuer_cert = x509.load_pem_x509_certificate(pem_data, default_backend()) + >>> issuer_cert = x509.load_pem_x509_certificate(pem_data) >>> x509.AuthorityKeyIdentifier.from_issuer_public_key(issuer_cert.public_key()) @@ -1892,10 +1924,9 @@ X.509 Extensions .. doctest:: >>> from cryptography import x509 - >>> from cryptography.hazmat.backends import default_backend - >>> issuer_cert = x509.load_pem_x509_certificate(pem_data, default_backend()) - >>> ski = issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier) - >>> x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(ski) + >>> issuer_cert = x509.load_pem_x509_certificate(pem_data) + >>> ski_ext = issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier) + >>> x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(ski_ext.value) .. class:: SubjectKeyIdentifier(digest) @@ -1931,19 +1962,18 @@ X.509 Extensions recommendation in :rfc:`5280` section 4.2.1.2. :param public_key: One of - :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey` - , - :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey` - , or - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`. + :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`, + :class:`~cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PublicKey` or + :class:`~cryptography.hazmat.primitives.asymmetric.ed448.Ed448PublicKey`. .. doctest:: >>> from cryptography import x509 - >>> from cryptography.hazmat.backends import default_backend - >>> csr = x509.load_pem_x509_csr(pem_req_data, default_backend()) + >>> csr = x509.load_pem_x509_csr(pem_req_data) >>> x509.SubjectKeyIdentifier.from_public_key(csr.public_key()) - + .. class:: SubjectAlternativeName(general_names) @@ -1976,9 +2006,8 @@ X.509 Extensions .. doctest:: >>> from cryptography import x509 - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import hashes - >>> cert = x509.load_pem_x509_certificate(cryptography_cert_pem, default_backend()) + >>> cert = x509.load_pem_x509_certificate(cryptography_cert_pem) >>> # Get the subjectAltName extension from the certificate >>> ext = cert.extensions.get_extension_for_oid(ExtensionOID.SUBJECT_ALTERNATIVE_NAME) >>> # Get the dNSName entries from the SAN extension @@ -2057,6 +2086,33 @@ X.509 Extensions Returns :attr:`~cryptography.x509.oid.ExtensionOID.PRECERT_POISON`. +.. class:: SignedCertificateTimestamps(scts) + + .. versionadded:: 3.0 + + This extension contains + :class:`~cryptography.x509.certificate_transparency.SignedCertificateTimestamp` + instances. These can be used to verify that the certificate is included + in a public Certificate Transparency log. This extension is only found + in OCSP responses. For SCTs in an X.509 certificate see + :class:`~cryptography.x509.PrecertificateSignedCertificateTimestamps`. + + It is an iterable containing one or more + :class:`~cryptography.x509.certificate_transparency.SignedCertificateTimestamp` + objects. + + :param list scts: A ``list`` of + :class:`~cryptography.x509.certificate_transparency.SignedCertificateTimestamp` + objects. + + .. attribute:: oid + + :type: :class:`ObjectIdentifier` + + Returns + :attr:`~cryptography.x509.oid.ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS`. + + .. class:: DeltaCRLIndicator(crl_number) .. versionadded:: 2.1 @@ -2104,6 +2160,29 @@ X.509 Extensions :attr:`~cryptography.x509.oid.ExtensionOID.AUTHORITY_INFORMATION_ACCESS`. +.. class:: SubjectInformationAccess(descriptions) + + .. versionadded:: 3.0 + + The subject information access extension indicates how to access + information and services for the subject of the certificate in which + the extension appears. When the subject is a CA, information and + services may include certificate validation services and CA policy + data. When the subject is an end entity, the information describes + the type of services offered and how to access them. It is an iterable, + containing one or more :class:`~cryptography.x509.AccessDescription` + instances. + + :param list descriptions: A list of :class:`AccessDescription` objects. + + .. attribute:: oid + + :type: :class:`ObjectIdentifier` + + Returns + :attr:`~cryptography.x509.oid.ExtensionOID.SUBJECT_INFORMATION_ACCESS`. + + .. class:: AccessDescription(access_method, access_location) .. versionadded:: 0.9 @@ -2113,16 +2192,23 @@ X.509 Extensions :type: :class:`ObjectIdentifier` The access method defines what the ``access_location`` means. It must - be either + be :attr:`~cryptography.x509.oid.AuthorityInformationAccessOID.OCSP` or - :attr:`~cryptography.x509.oid.AuthorityInformationAccessOID.CA_ISSUERS`. + :attr:`~cryptography.x509.oid.AuthorityInformationAccessOID.CA_ISSUERS` + when used with :class:`~cryptography.x509.AuthorityInformationAccess` + or + :attr:`~cryptography.x509.oid.SubjectInformationAccessOID.CA_REPOSITORY` + when used with :class:`~cryptography.x509.SubjectInformationAccess`. + If it is :attr:`~cryptography.x509.oid.AuthorityInformationAccessOID.OCSP` the access location will be where to obtain OCSP information for the certificate. If it is :attr:`~cryptography.x509.oid.AuthorityInformationAccessOID.CA_ISSUERS` the access location will provide additional information about the - issuing certificate. + issuing certificate. Finally, if it is + :attr:`~cryptography.x509.oid.SubjectInformationAccessOID.CA_REPOSITORY` + the access location will be the location of the CA's repository. .. attribute:: access_location @@ -2418,7 +2504,9 @@ X.509 Extensions .. versionadded:: 1.2 A generic extension class used to hold the raw value of extensions that - ``cryptography`` does not know how to parse. + ``cryptography`` does not know how to parse. This can also be used when + creating new certificates, CRLs, or OCSP requests and responses to encode + extensions that ``cryptography`` does not know how to generate. .. attribute:: oid @@ -2441,6 +2529,18 @@ X.509 Extensions :param list policies: A list of :class:`PolicyInformation` instances. + As an example of how ``CertificatePolicies`` might be used, if you wanted + to check if a certificated contained the CAB Forum's "domain-validated" + policy, you might write code like: + + .. code-block:: python + + def contains_domain_validated(policies): + return any( + policy.oid.dotted_string == "2.23.140.1.2.1" + for policy in policies + ) + .. attribute:: oid .. versionadded:: 1.0 @@ -2752,6 +2852,12 @@ instances. The following common OIDs are available as constants. Corresponds to the dotted string ``"2.5.4.17"``. + .. attribute:: UNSTRUCTURED_NAME + + .. versionadded:: 3.0 + + Corresponds to the dotted string ``"1.2.840.113549.1.9.2"``. + .. class:: SignatureAlgorithmOID @@ -2836,6 +2942,20 @@ instances. The following common OIDs are available as constants. Corresponds to the dotted string ``"2.16.840.1.101.3.4.3.2"``. This is a SHA256 digest signed by a DSA key. + .. attribute:: ED25519 + + .. versionadded:: 2.8 + + Corresponds to the dotted string ``"1.3.101.112"``. This is a signature + using an ed25519 key. + + .. attribute:: ED448 + + .. versionadded:: 2.8 + + Corresponds to the dotted string ``"1.3.101.113"``. This is a signature + using an ed448 key. + .. class:: ExtendedKeyUsageOID @@ -2878,7 +2998,12 @@ instances. The following common OIDs are available as constants. .. versionadded:: 2.0 Corresponds to the dotted string ``"2.5.29.37.0"``. This is used to - denote that a certificate may be used for _any_ purposes. + denote that a certificate may be used for _any_ purposes. However, + :rfc:`5280` additionally notes that applications that require the + presence of a particular purpose _MAY_ reject certificates that include + the ``anyExtendedKeyUsage`` OID but not the particular OID expected for + the application. Therefore, the presence of this OID does not mean a + given application will accept the certificate for all purposes. .. class:: AuthorityInformationAccessOID @@ -2898,6 +3023,17 @@ instances. The following common OIDs are available as constants. :class:`~cryptography.x509.AccessDescription` objects. +.. class:: SubjectInformationAccessOID + + .. versionadded:: 3.0 + + .. attribute:: CA_REPOSITORY + + Corresponds to the dotted string ``"1.3.6.1.5.5.7.48.5"``. Used as the + identifier for CA repository data in + :class:`~cryptography.x509.AccessDescription` objects. + + .. class:: CertificatePoliciesOID .. versionadded:: 1.0 @@ -2975,6 +3111,14 @@ instances. The following common OIDs are available as constants. for the :class:`~cryptography.x509.AuthorityInformationAccess` extension type. + .. attribute:: SUBJECT_INFORMATION_ACCESS + + .. versionadded:: 3.0 + + Corresponds to the dotted string ``"1.3.6.1.5.5.7.1.11"``. The + identifier for the :class:`~cryptography.x509.SubjectInformationAccess` + extension type. + .. attribute:: INHIBIT_ANY_POLICY Corresponds to the dotted string ``"2.5.29.54"``. The identifier @@ -3018,6 +3162,12 @@ instances. The following common OIDs are available as constants. Corresponds to the dotted string ``"1.3.6.1.4.1.11129.2.4.3"``. + .. attribute:: SIGNED_CERTIFICATE_TIMESTAMPS + + .. versionadded:: 3.0 + + Corresponds to the dotted string ``"1.3.6.1.4.1.11129.2.4.5"``. + .. attribute:: POLICY_CONSTRAINTS Corresponds to the dotted string ``"2.5.29.36"``. The identifier for the @@ -3060,6 +3210,19 @@ instances. The following common OIDs are available as constants. Corresponds to the dotted string ``"1.3.6.1.5.5.7.48.1.2"``. + +.. class:: AttributeOID + + .. versionadded:: 3.0 + + .. attribute:: CHALLENGE_PASSWORD + + Corresponds to the dotted string ``"1.2.840.113549.1.9.7"``. + + .. attribute:: UNSTRUCTURED_NAME + + Corresponds to the dotted string ``"1.2.840.113549.1.9.2"``. + Helper Functions ~~~~~~~~~~~~~~~~ .. currentmodule:: cryptography.x509 @@ -3107,6 +3270,18 @@ Exceptions Returns the OID. +.. class:: AttributeNotFound + + This is raised when calling + :meth:`CertificateSigningRequest.get_attribute_for_oid` with + an attribute OID that is not present in the request. + + .. attribute:: oid + + :type: :class:`ObjectIdentifier` + + Returns the OID. + .. class:: UnsupportedGeneralNameType This is raised when a certificate contains an unsupported general name diff --git a/docs/x509/tutorial.rst b/docs/x509/tutorial.rst index d34b3504384d..f5ca416ceb9f 100644 --- a/docs/x509/tutorial.rst +++ b/docs/x509/tutorial.rst @@ -27,14 +27,12 @@ are the most common types of keys on the web right now): .. code-block:: pycon - >>> from cryptography.hazmat.backends import default_backend >>> from cryptography.hazmat.primitives import serialization >>> from cryptography.hazmat.primitives.asymmetric import rsa >>> # Generate our key >>> key = rsa.generate_private_key( ... public_exponent=65537, ... key_size=2048, - ... backend=default_backend() ... ) >>> # Write our key to disk for safe keeping >>> with open("path/to/store/key.pem", "wb") as f: @@ -63,7 +61,7 @@ a few details: >>> csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([ ... # Provide various details about who we are. ... x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), - ... x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"CA"), + ... x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"California"), ... x509.NameAttribute(NameOID.LOCALITY_NAME, u"San Francisco"), ... x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"My Company"), ... x509.NameAttribute(NameOID.COMMON_NAME, u"mysite.com"), @@ -76,7 +74,7 @@ a few details: ... ]), ... critical=False, ... # Sign the CSR with our private key. - ... ).sign(key, hashes.SHA256(), default_backend()) + ... ).sign(key, hashes.SHA256()) >>> # Write our CSR out to disk. >>> with open("path/to/csr.pem", "wb") as f: ... f.write(csr.public_bytes(serialization.Encoding.PEM)) @@ -105,7 +103,6 @@ Like generating a CSR, we start with creating a new private key: >>> key = rsa.generate_private_key( ... public_exponent=65537, ... key_size=2048, - ... backend=default_backend() ... ) >>> # Write our key to disk for safe keeping >>> with open("path/to/store/key.pem", "wb") as f: @@ -123,7 +120,7 @@ Then we generate the certificate itself: >>> # subject and issuer are always the same. >>> subject = issuer = x509.Name([ ... x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), - ... x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"CA"), + ... x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"California"), ... x509.NameAttribute(NameOID.LOCALITY_NAME, u"San Francisco"), ... x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"My Company"), ... x509.NameAttribute(NameOID.COMMON_NAME, u"mysite.com"), @@ -145,7 +142,7 @@ Then we generate the certificate itself: ... x509.SubjectAlternativeName([x509.DNSName(u"localhost")]), ... critical=False, ... # Sign our certificate with our private key - ... ).sign(key, hashes.SHA256(), default_backend()) + ... ).sign(key, hashes.SHA256()) >>> # Write our certificate out to disk. >>> with open("path/to/certificate.pem", "wb") as f: ... f.write(cert.public_bytes(serialization.Encoding.PEM)) diff --git a/pyproject.toml b/pyproject.toml index 7d64f993a3ec..957b1fd04bb0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,14 @@ [build-system] -# Must be kept in sync with `setup_requirements` in `setup.py` requires = [ - "setuptools>=18.5", + # The minimum setuptools version is specific to the PEP 517 backend, + # and may be stricter than the version required in `setup.py` + "setuptools>=40.6.0", "wheel", - "cffi>=1.8,!=1.11.3; python_implementation != 'PyPy'", + # Must be kept in sync with the `setup_requirements` in `setup.py` + "cffi>=1.8,!=1.11.3; platform_python_implementation != 'PyPy'", ] +build-backend = "setuptools.build_meta" + +[tool.black] +line-length = 79 +target-version = ["py27"] diff --git a/release.py b/release.py index d7c18d1050fd..5f3f251d17bd 100644 --- a/release.py +++ b/release.py @@ -7,122 +7,136 @@ import getpass import glob import io +import json import os import subprocess import time +import zipfile import click -from clint.textui.progress import Bar as ProgressBar - import requests -JENKINS_URL = ( - "https://ci.cryptography.io/job/cryptography-support-jobs/" - "job/wheel-builder" -) - - def run(*args, **kwargs): print("[running] {0}".format(list(args))) subprocess.check_call(list(args), **kwargs) -def wait_for_build_completed(session): - # Wait 20 seconds before actually checking if the build is complete, to - # ensure that it had time to really start. - time.sleep(20) +def wait_for_build_complete_github_actions(session, token, run_url): while True: response = session.get( - "{0}/lastBuild/api/json/".format(JENKINS_URL), + run_url, headers={ - "Accept": "application/json", - } + "Content-Type": "application/json", + "Authorization": "token {}".format(token), + }, ) response.raise_for_status() - if not response.json()["building"]: - assert response.json()["result"] == "SUCCESS" + if response.json()["conclusion"] is not None: break - time.sleep(0.1) + time.sleep(3) -def download_artifacts(session): +def download_artifacts_github_actions(session, token, run_url): response = session.get( - "{0}/lastBuild/api/json/".format(JENKINS_URL), + run_url, headers={ - "Accept": "application/json" - } + "Content-Type": "application/json", + "Authorization": "token {}".format(token), + }, ) response.raise_for_status() - json_response = response.json() - assert not json_response["building"] - assert json_response["result"] == "SUCCESS" + response = session.get( + response.json()["artifacts_url"], + headers={ + "Content-Type": "application/json", + "Authorization": "token {}".format(token), + }, + ) + response.raise_for_status() paths = [] - - for artifact in json_response["artifacts"]: + for artifact in response.json()["artifacts"]: response = session.get( - "{0}artifact/{1}".format( - json_response["url"], artifact["relativePath"] - ), stream=True - ) - assert response.headers["content-length"] - print("Downloading {0}".format(artifact["fileName"])) - bar = ProgressBar( - expected_size=int(response.headers["content-length"]), - filled_char="=" - ) - content = io.BytesIO() - for data in response.iter_content(chunk_size=8192): - content.write(data) - bar.show(content.tell()) - assert bar.expected_size == content.tell() - bar.done() - out_path = os.path.join( - os.path.dirname(__file__), - "dist", - artifact["fileName"], + artifact["archive_download_url"], + headers={ + "Content-Type": "application/json", + "Authorization": "token {}".format(token), + }, ) - with open(out_path, "wb") as f: - f.write(content.getvalue()) - paths.append(out_path) + with zipfile.ZipFile(io.BytesIO(response.content)) as z: + for name in z.namelist(): + if not name.endswith(".whl"): + continue + p = z.open(name) + out_path = os.path.join( + os.path.dirname(__file__), + "dist", + os.path.basename(name), + ) + with open(out_path, "wb") as f: + f.write(p.read()) + paths.append(out_path) return paths +def build_github_actions_wheels(token, version): + session = requests.Session() + + response = session.post( + "https://api.github.com/repos/pyca/cryptography/actions/workflows/" + "wheel-builder.yml/dispatches", + headers={ + "Content-Type": "application/json", + "Accept": "application/vnd.github.v3+json", + "Authorization": "token {}".format(token), + }, + data=json.dumps({"ref": "master", "inputs": {"version": version}}), + ) + response.raise_for_status() + + # Give it a few seconds for the run to kick off. + time.sleep(5) + response = session.get( + ( + "https://api.github.com/repos/pyca/cryptography/actions/workflows/" + "wheel-builder.yml/runs?event=workflow_dispatch" + ), + headers={ + "Content-Type": "application/json", + "Authorization": "token {}".format(token), + }, + ) + response.raise_for_status() + run_url = response.json()["workflow_runs"][0]["url"] + wait_for_build_complete_github_actions(session, token, run_url) + return download_artifacts_github_actions(session, token, run_url) + + @click.command() @click.argument("version") def release(version): """ ``version`` should be a string like '0.4' or '1.0'. """ + github_token = getpass.getpass("Github person access token: ") + run("git", "tag", "-s", version, "-m", "{0} release".format(version)) run("git", "push", "--tags") run("python", "setup.py", "sdist") run("python", "setup.py", "sdist", "bdist_wheel", cwd="vectors/") - packages = ( - glob.glob("dist/cryptography-{0}*".format(version)) + - glob.glob("vectors/dist/cryptography_vectors-{0}*".format(version)) + packages = glob.glob("dist/cryptography-{0}*".format(version)) + glob.glob( + "vectors/dist/cryptography_vectors-{0}*".format(version) ) run("twine", "upload", "-s", *packages) - session = requests.Session() - - token = getpass.getpass("Input the Jenkins token: ") - response = session.get( - "{0}/buildWithParameters".format(JENKINS_URL), - params={ - "token": token, - "BUILD_VERSION": version, - "cause": "Building wheels for {0}".format(version) - } + github_actions_wheel_paths = build_github_actions_wheels( + github_token, version ) - response.raise_for_status() - wait_for_build_completed(session) - paths = download_artifacts(session) - run("twine", "upload", *paths) + run("twine", "upload", *github_actions_wheel_paths) if __name__ == "__main__": diff --git a/setup.py b/setup.py index 5b29d32e636f..82800a96e59b 100644 --- a/setup.py +++ b/setup.py @@ -8,22 +8,17 @@ import os import platform -import subprocess import sys -from distutils.command.build import build import pkg_resources import setuptools from setuptools import find_packages, setup -from setuptools.command.install import install -from setuptools.command.test import test -if ( - pkg_resources.parse_version(setuptools.__version__) < - pkg_resources.parse_version("18.5") -): +if pkg_resources.parse_version( + setuptools.__version__ +) < pkg_resources.parse_version("18.5"): raise RuntimeError( "cryptography requires setuptools 18.5 or newer, please upgrade to a " "newer version of setuptools" @@ -38,11 +33,9 @@ about = {} with open(os.path.join(src_dir, "cryptography", "__about__.py")) as f: - exec(f.read(), about) + exec (f.read(), about) -VECTORS_DEPENDENCY = "cryptography_vectors=={0}".format(about['__version__']) - # `setup_requirements` must be kept in sync with `pyproject.toml` setup_requirements = ["cffi>=1.8,!=1.11.3"] @@ -53,192 +46,6 @@ "PyPy to use this library." ) -test_requirements = [ - "pytest>=3.6.0,!=3.9.0,!=3.9.1,!=3.9.2", - "pretend", - "iso8601", - "pytz", - "hypothesis>=1.11.4,!=3.79.2", -] - - -# If there's no vectors locally that probably means we are in a tarball and -# need to go and get the matching vectors package from PyPi -if not os.path.exists(os.path.join(base_dir, "vectors/setup.py")): - test_requirements.append(VECTORS_DEPENDENCY) - - -class PyTest(test): - def finalize_options(self): - test.finalize_options(self) - self.test_args = [] - self.test_suite = True - - # This means there's a vectors/ folder with the package in here. - # cd into it, install the vectors package and then refresh sys.path - if VECTORS_DEPENDENCY not in test_requirements: - subprocess.check_call( - [sys.executable, "setup.py", "install"], cwd="vectors" - ) - pkg_resources.get_distribution("cryptography_vectors").activate() - - def run_tests(self): - # Import here because in module scope the eggs are not loaded. - import pytest - test_args = [os.path.join(base_dir, "tests")] - errno = pytest.main(test_args) - sys.exit(errno) - - -def keywords_with_side_effects(argv): - """ - Get a dictionary with setup keywords that (can) have side effects. - - :param argv: A list of strings with command line arguments. - :returns: A dictionary with keyword arguments for the ``setup()`` function. - - This setup.py script uses the setuptools 'setup_requires' feature because - this is required by the cffi package to compile extension modules. The - purpose of ``keywords_with_side_effects()`` is to avoid triggering the cffi - build process as a result of setup.py invocations that don't need the cffi - module to be built (setup.py serves the dual purpose of exposing package - metadata). - - All of the options listed by ``python setup.py --help`` that print - information should be recognized here. The commands ``clean``, - ``egg_info``, ``register``, ``sdist`` and ``upload`` are also recognized. - Any combination of these options and commands is also supported. - - This function was originally based on the `setup.py script`_ of SciPy (see - also the discussion in `pip issue #25`_). - - .. _pip issue #25: https://github.com/pypa/pip/issues/25 - .. _setup.py script: https://github.com/scipy/scipy/blob/master/setup.py - """ - no_setup_requires_arguments = ( - '-h', '--help', - '-n', '--dry-run', - '-q', '--quiet', - '-v', '--verbose', - '-V', '--version', - '--author', - '--author-email', - '--classifiers', - '--contact', - '--contact-email', - '--description', - '--egg-base', - '--fullname', - '--help-commands', - '--keywords', - '--licence', - '--license', - '--long-description', - '--maintainer', - '--maintainer-email', - '--name', - '--no-user-cfg', - '--obsoletes', - '--platforms', - '--provides', - '--requires', - '--url', - 'clean', - 'egg_info', - 'register', - 'sdist', - 'upload', - ) - - def is_short_option(argument): - """Check whether a command line argument is a short option.""" - return len(argument) >= 2 and argument[0] == '-' and argument[1] != '-' - - def expand_short_options(argument): - """Expand combined short options into canonical short options.""" - return ('-' + char for char in argument[1:]) - - def argument_without_setup_requirements(argv, i): - """Check whether a command line argument needs setup requirements.""" - if argv[i] in no_setup_requires_arguments: - # Simple case: An argument which is either an option or a command - # which doesn't need setup requirements. - return True - elif (is_short_option(argv[i]) and - all(option in no_setup_requires_arguments - for option in expand_short_options(argv[i]))): - # Not so simple case: Combined short options none of which need - # setup requirements. - return True - elif argv[i - 1:i] == ['--egg-base']: - # Tricky case: --egg-info takes an argument which should not make - # us use setup_requires (defeating the purpose of this code). - return True - else: - return False - - if all(argument_without_setup_requirements(argv, i) - for i in range(1, len(argv))): - return { - "cmdclass": { - "build": DummyBuild, - "install": DummyInstall, - "test": DummyPyTest, - } - } - else: - cffi_modules = [ - "src/_cffi_src/build_openssl.py:ffi", - "src/_cffi_src/build_constant_time.py:ffi", - "src/_cffi_src/build_padding.py:ffi", - ] - - return { - "setup_requires": setup_requirements, - "cmdclass": { - "test": PyTest, - }, - "cffi_modules": cffi_modules - } - - -setup_requires_error = ("Requested setup command that needs 'setup_requires' " - "while command line arguments implied a side effect " - "free command or option.") - - -class DummyBuild(build): - """ - This class makes it very obvious when ``keywords_with_side_effects()`` has - incorrectly interpreted the command line arguments to ``setup.py build`` as - one of the 'side effect free' commands or options. - """ - - def run(self): - raise RuntimeError(setup_requires_error) - - -class DummyInstall(install): - """ - This class makes it very obvious when ``keywords_with_side_effects()`` has - incorrectly interpreted the command line arguments to ``setup.py install`` - as one of the 'side effect free' commands or options. - """ - - def run(self): - raise RuntimeError(setup_requires_error) - - -class DummyPyTest(test): - """ - This class makes it very obvious when ``keywords_with_side_effects()`` has - incorrectly interpreted the command line arguments to ``setup.py test`` as - one of the 'side effect free' commands or options. - """ - - def run_tests(self): - raise RuntimeError(setup_requires_error) - with open(os.path.join(base_dir, "README.rst")) as f: long_description = f.read() @@ -247,15 +54,13 @@ def run_tests(self): setup( name=about["__title__"], version=about["__version__"], - description=about["__summary__"], long_description=long_description, + long_description_content_type="text/x-rst", license=about["__license__"], url=about["__uri__"], - author=about["__author__"], author_email=about["__email__"], - classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", @@ -271,32 +76,31 @@ def run_tests(self): "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Security :: Cryptography", ], - package_dir={"": "src"}, packages=find_packages(where="src", exclude=["_cffi_src", "_cffi_src.*"]), include_package_data=True, - - python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*', - - install_requires=[ - "asn1crypto >= 0.21.0", - "six >= 1.4.1", - ] + setup_requirements, - tests_require=test_requirements, + python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*", + install_requires=["six >= 1.4.1"] + setup_requirements, + setup_requires=setup_requirements, extras_require={ ":python_version < '3'": ["enum34", "ipaddress"], - - "test": test_requirements, + "test": [ + "pytest>=3.6.0,!=3.9.0,!=3.9.1,!=3.9.2", + "pretend", + "iso8601", + "pytz", + "hypothesis>=1.11.4,!=3.79.2", + ], "docs": [ - "sphinx >= 1.6.5,!=1.8.0", + "sphinx >= 1.6.5,!=1.8.0,!=3.1.0,!=3.1.1", "sphinx_rtd_theme", ], "docstest": [ @@ -305,21 +109,16 @@ def run_tests(self): "twine >= 1.12.0", "sphinxcontrib-spelling >= 4.0.1", ], - "pep8test": [ - "flake8", - "flake8-import-order", - "pep8-naming", - ], - # This extra is for the U-label support that was deprecated in - # cryptography 2.1. If you need this deprecated path install with - # pip install cryptography[idna] - "idna": [ - "idna >= 2.1", - ] + "pep8test": ["black", "flake8", "flake8-import-order", "pep8-naming"], + # This extra is for OpenSSH private keys that use bcrypt KDF + # Versions: v3.1.3 - ignore_few_rounds, v3.1.5 - abi3 + "ssh": ["bcrypt >= 3.1.5"], }, - # for cffi zip_safe=False, ext_package="cryptography.hazmat.bindings", - **keywords_with_side_effects(sys.argv) + cffi_modules=[ + "src/_cffi_src/build_openssl.py:ffi", + "src/_cffi_src/build_padding.py:ffi", + ], ) diff --git a/src/_cffi_src/build_constant_time.py b/src/_cffi_src/build_constant_time.py deleted file mode 100644 index 7a11f7b581e5..000000000000 --- a/src/_cffi_src/build_constant_time.py +++ /dev/null @@ -1,27 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import absolute_import, division, print_function - -import os - -from _cffi_src.utils import build_ffi, compiler_type, extra_link_args - - -with open(os.path.join( - os.path.dirname(__file__), "hazmat_src/constant_time.h" -)) as f: - types = f.read() - -with open(os.path.join( - os.path.dirname(__file__), "hazmat_src/constant_time.c" -)) as f: - functions = f.read() - -ffi = build_ffi( - module_name="_constant_time", - cdef_source=types, - verify_source=functions, - extra_link_args=extra_link_args(compiler_type()), -) diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py index 456b8692604d..35ccd6b9be0a 100644 --- a/src/_cffi_src/build_openssl.py +++ b/src/_cffi_src/build_openssl.py @@ -6,9 +6,14 @@ import os import sys +from distutils import dist +from distutils.ccompiler import get_default_compiler +from distutils.command.config import config from _cffi_src.utils import ( - build_ffi_for_binding, compiler_type, extra_link_args + build_ffi_for_binding, + compiler_type, + extra_link_args, ) @@ -22,6 +27,7 @@ def _get_openssl_libraries(platform): ) if windows_link_legacy_openssl is None: # Link against the 1.1.0 names + # CRYPTOGRAPHY_OPENSSL_110_OR_GREATER libs = ["libssl", "libcrypto"] else: # Link against the 1.0.2 and lower names @@ -33,7 +39,13 @@ def _get_openssl_libraries(platform): # specified on the linker command-line is significant; # libssl must come before libcrypto # (https://marc.info/?l=openssl-users&m=135361825921871) - return ["ssl", "crypto"] + # -lpthread required due to usage of pthread an potential + # existance 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): @@ -46,7 +58,20 @@ def _extra_compile_args(platform): When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 we can revisit this. """ - if platform not in ["win32", "hp-ux11", "sunos5"]: + # 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 [] @@ -58,7 +83,6 @@ def _extra_compile_args(platform): modules=[ # This goes first so we can define some cryptography-wide symbols. "cryptography", - "aes", "asn1", "bignum", diff --git a/src/_cffi_src/build_padding.py b/src/_cffi_src/build_padding.py index 4c5096a19435..207f4a658ea2 100644 --- a/src/_cffi_src/build_padding.py +++ b/src/_cffi_src/build_padding.py @@ -9,14 +9,14 @@ from _cffi_src.utils import build_ffi, compiler_type, extra_link_args -with open(os.path.join( - os.path.dirname(__file__), "hazmat_src/padding.h" -)) as f: +with open( + os.path.join(os.path.dirname(__file__), "hazmat_src/padding.h") +) as f: types = f.read() -with open(os.path.join( - os.path.dirname(__file__), "hazmat_src/padding.c" -)) as f: +with open( + os.path.join(os.path.dirname(__file__), "hazmat_src/padding.c") +) as f: functions = f.read() ffi = build_ffi( diff --git a/src/_cffi_src/hazmat_src/constant_time.c b/src/_cffi_src/hazmat_src/constant_time.c deleted file mode 100644 index 0a48fe83a462..000000000000 --- a/src/_cffi_src/hazmat_src/constant_time.c +++ /dev/null @@ -1,22 +0,0 @@ -// This file is dual licensed under the terms of the Apache License, Version -// 2.0, and the BSD License. See the LICENSE file in the root of this -// repository for complete details. - -uint8_t Cryptography_constant_time_bytes_eq(uint8_t *a, size_t len_a, - uint8_t *b, size_t len_b) { - size_t i = 0; - uint8_t mismatch = 0; - if (len_a != len_b) { - return 0; - } - for (i = 0; i < len_a; i++) { - mismatch |= a[i] ^ b[i]; - } - - /* Make sure any bits set are copied to the lowest bit */ - mismatch |= mismatch >> 4; - mismatch |= mismatch >> 2; - mismatch |= mismatch >> 1; - /* Now check the low bit to see if it's set */ - return (mismatch & 1) == 0; -} diff --git a/src/_cffi_src/hazmat_src/constant_time.h b/src/_cffi_src/hazmat_src/constant_time.h deleted file mode 100644 index 593479f66ca5..000000000000 --- a/src/_cffi_src/hazmat_src/constant_time.h +++ /dev/null @@ -1,6 +0,0 @@ -// This file is dual licensed under the terms of the Apache License, Version -// 2.0, and the BSD License. See the LICENSE file in the root of this -// repository for complete details. - -uint8_t Cryptography_constant_time_bytes_eq(uint8_t *, size_t, uint8_t *, - size_t); diff --git a/src/_cffi_src/openssl/aes.py b/src/_cffi_src/openssl/aes.py index 028c92ce222a..25ef3ec0e3cb 100644 --- a/src/_cffi_src/openssl/aes.py +++ b/src/_cffi_src/openssl/aes.py @@ -9,18 +9,10 @@ """ TYPES = """ -static const int Cryptography_HAS_AES_WRAP; - -struct aes_key_st { - ...; -}; -typedef struct aes_key_st AES_KEY; +typedef ... AES_KEY; """ FUNCTIONS = """ -int AES_set_encrypt_key(const unsigned char *, const int, AES_KEY *); -int AES_set_decrypt_key(const unsigned char *, const int, AES_KEY *); - int AES_wrap_key(AES_KEY *, const unsigned char *, unsigned char *, const unsigned char *, unsigned int); int AES_unwrap_key(AES_KEY *, const unsigned char *, unsigned char *, @@ -28,5 +20,4 @@ """ CUSTOMIZATIONS = """ -static const long Cryptography_HAS_AES_WRAP = 1; """ diff --git a/src/_cffi_src/openssl/asn1.py b/src/_cffi_src/openssl/asn1.py index 82bf79792fe2..da55b670e041 100644 --- a/src/_cffi_src/openssl/asn1.py +++ b/src/_cffi_src/openssl/asn1.py @@ -27,7 +27,10 @@ typedef ... ASN1_OBJECT; typedef struct asn1_string_st ASN1_STRING; typedef struct asn1_string_st ASN1_UTF8STRING; -typedef ... ASN1_TYPE; +typedef struct { + int type; + ...; +} ASN1_TYPE; typedef ... ASN1_GENERALIZEDTIME; typedef ... ASN1_ENUMERATED; typedef ... ASN1_NULL; @@ -59,7 +62,6 @@ /* ASN1 TIME */ ASN1_TIME *ASN1_TIME_new(void); void ASN1_TIME_free(ASN1_TIME *); -ASN1_TIME *ASN1_TIME_set(ASN1_TIME *, time_t); int ASN1_TIME_set_string(ASN1_TIME *, const char *); /* ASN1 GENERALIZEDTIME */ diff --git a/src/_cffi_src/openssl/bignum.py b/src/_cffi_src/openssl/bignum.py index a352f5a87cd1..751018391d94 100644 --- a/src/_cffi_src/openssl/bignum.py +++ b/src/_cffi_src/openssl/bignum.py @@ -52,6 +52,7 @@ int BN_num_bits(const BIGNUM *); int BN_cmp(const BIGNUM *, const BIGNUM *); +int BN_is_negative(const BIGNUM *); int BN_add(BIGNUM *, const BIGNUM *, const BIGNUM *); int BN_sub(BIGNUM *, const BIGNUM *, const BIGNUM *); int BN_nnmod(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); diff --git a/src/_cffi_src/openssl/bio.py b/src/_cffi_src/openssl/bio.py index d65775a09c0e..8f5a3e6a2b6f 100644 --- a/src/_cffi_src/openssl/bio.py +++ b/src/_cffi_src/openssl/bio.py @@ -15,6 +15,7 @@ FUNCTIONS = """ int BIO_free(BIO *); +void BIO_free_all(BIO *); BIO *BIO_new_file(const char *, const char *); BIO *BIO_new_dgram(int, int); size_t BIO_ctrl_pending(BIO *); @@ -40,7 +41,7 @@ """ CUSTOMIZATIONS = """ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL int BIO_up_ref(BIO *b) { CRYPTO_add(&b->references, 1, CRYPTO_LOCK_BIO); return 1; diff --git a/src/_cffi_src/openssl/callbacks.py b/src/_cffi_src/openssl/callbacks.py index 75c620165209..33ebf4df400f 100644 --- a/src/_cffi_src/openssl/callbacks.py +++ b/src/_cffi_src/openssl/callbacks.py @@ -20,6 +20,10 @@ #include #include #endif + +#ifdef __MVS__ +#include +#endif """ TYPES = """ @@ -66,11 +70,23 @@ perror("Fatal error in callback initialization: " #call); \ abort(); \ } +#ifdef __MVS__ +/* When pthread_mutex_init is called more than once on the same mutex, + on z/OS this throws an EBUSY error. +*/ +#define ASSERT_STATUS_INIT(call) \ + if ((call) != 0 && errno != EBUSY) { \ + perror("Fatal error in callback initialization: " #call); \ + abort(); \ + } +#else +#define ASSERT_STATUS_INIT ASSERT_STATUS +#endif static inline void cryptography_mutex_init(Cryptography_mutex *mutex) { #if !defined(pthread_mutexattr_default) # define pthread_mutexattr_default ((pthread_mutexattr_t *)NULL) #endif - ASSERT_STATUS(pthread_mutex_init(mutex, pthread_mutexattr_default)); + ASSERT_STATUS_INIT(pthread_mutex_init(mutex, pthread_mutexattr_default)); } static inline void cryptography_mutex_lock(Cryptography_mutex *mutex) { ASSERT_STATUS(pthread_mutex_lock(mutex)); @@ -81,7 +97,7 @@ #endif -static unsigned int _ssl_locks_count = 0; +static int _ssl_locks_count = 0; static Cryptography_mutex *_ssl_locks = NULL; static void _ssl_thread_locking_function(int mode, int n, const char *file, @@ -101,7 +117,7 @@ */ if ((_ssl_locks == NULL) || - (n < 0) || ((unsigned)n >= _ssl_locks_count)) { + (n < 0) || (n >= _ssl_locks_count)) { return; } diff --git a/src/_cffi_src/openssl/cmac.py b/src/_cffi_src/openssl/cmac.py index f976647f7585..557abd1ca8f9 100644 --- a/src/_cffi_src/openssl/cmac.py +++ b/src/_cffi_src/openssl/cmac.py @@ -11,7 +11,6 @@ """ TYPES = """ -static const int Cryptography_HAS_CMAC; typedef ... CMAC_CTX; """ @@ -25,5 +24,4 @@ """ CUSTOMIZATIONS = """ -static const long Cryptography_HAS_CMAC = 1; """ diff --git a/src/_cffi_src/openssl/crypto.py b/src/_cffi_src/openssl/crypto.py index 03672d55ed49..f3623b21f146 100644 --- a/src/_cffi_src/openssl/crypto.py +++ b/src/_cffi_src/openssl/crypto.py @@ -23,26 +23,13 @@ static const int OPENSSL_BUILT_ON; static const int OPENSSL_PLATFORM; static const int OPENSSL_DIR; -static const int CRYPTO_MEM_CHECK_ON; -static const int CRYPTO_MEM_CHECK_OFF; -static const int CRYPTO_MEM_CHECK_ENABLE; -static const int CRYPTO_MEM_CHECK_DISABLE; -static const int CRYPTO_LOCK; -static const int CRYPTO_UNLOCK; -static const int CRYPTO_READ; -static const int CRYPTO_LOCK_SSL; """ FUNCTIONS = """ -int CRYPTO_mem_ctrl(int); - -void CRYPTO_cleanup_all_ex_data(void); void OPENSSL_cleanup(void); -/* as of 1.1.0 OpenSSL does its own locking *angelic chorus*. These functions - have become macros that are no ops */ -int CRYPTO_num_locks(void); -void CRYPTO_set_locking_callback(void(*)(int, int, const char *, int)); +/* as of 1.1.0 OpenSSL does its own locking *angelic chorus*. This function + is now a noop macro. We can delete this once we drop 1.0.2 support. */ void (*CRYPTO_get_locking_callback(void))(int, int, const char *, int); /* SSLeay was removed in 1.1.0 */ @@ -56,8 +43,6 @@ void *OPENSSL_malloc(size_t); void OPENSSL_free(void *); -/* This was removed in 1.1.0 */ -void CRYPTO_lock(int, int, const char *, int); /* Signature changed significantly in 1.1.0, only expose there for sanity */ int Cryptography_CRYPTO_set_mem_functions( @@ -98,19 +83,6 @@ static const long Cryptography_HAS_LOCKING_CALLBACKS = 1; #else static const long Cryptography_HAS_LOCKING_CALLBACKS = 0; -#if !defined(CRYPTO_LOCK) -static const long CRYPTO_LOCK = 0; -#endif -#if !defined(CRYPTO_UNLOCK) -static const long CRYPTO_UNLOCK = 0; -#endif -#if !defined(CRYPTO_READ) -static const long CRYPTO_READ = 0; -#endif -#if !defined(CRYPTO_LOCK_SSL) -static const long CRYPTO_LOCK_SSL = 0; -#endif -void (*CRYPTO_lock)(int, int, const char *, int) = NULL; #endif #if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 diff --git a/src/_cffi_src/openssl/cryptography.py b/src/_cffi_src/openssl/cryptography.py index e16fc57d91a1..d9d4a9ea0f41 100644 --- a/src/_cffi_src/openssl/cryptography.py +++ b/src/_cffi_src/openssl/cryptography.py @@ -33,20 +33,15 @@ #include #endif -#define CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER \ - (CRYPTOGRAPHY_IS_LIBRESSL && LIBRESSL_VERSION_NUMBER >= 0x2070000fL) - -#define CRYPTOGRAPHY_OPENSSL_102_OR_GREATER \ - (OPENSSL_VERSION_NUMBER >= 0x10002000 && !CRYPTOGRAPHY_IS_LIBRESSL) #define CRYPTOGRAPHY_OPENSSL_102L_OR_GREATER \ (OPENSSL_VERSION_NUMBER >= 0x100020cf && !CRYPTOGRAPHY_IS_LIBRESSL) +#define CRYPTOGRAPHY_OPENSSL_102U_OR_GREATER \ + (OPENSSL_VERSION_NUMBER >= 0x1000215fL && !CRYPTOGRAPHY_IS_LIBRESSL) #define CRYPTOGRAPHY_OPENSSL_110_OR_GREATER \ (OPENSSL_VERSION_NUMBER >= 0x10100000 && !CRYPTOGRAPHY_IS_LIBRESSL) #define CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER \ (OPENSSL_VERSION_NUMBER >= 0x1010006f && !CRYPTOGRAPHY_IS_LIBRESSL) -#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 \ - (OPENSSL_VERSION_NUMBER < 0x10002000 || CRYPTOGRAPHY_IS_LIBRESSL) #define CRYPTOGRAPHY_OPENSSL_LESS_THAN_102I \ (OPENSSL_VERSION_NUMBER < 0x1000209f || CRYPTOGRAPHY_IS_LIBRESSL) #define CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 \ @@ -55,16 +50,29 @@ (OPENSSL_VERSION_NUMBER < 0x101000af || CRYPTOGRAPHY_IS_LIBRESSL) #define CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 \ (OPENSSL_VERSION_NUMBER < 0x10101000 || CRYPTOGRAPHY_IS_LIBRESSL) +#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B \ + (OPENSSL_VERSION_NUMBER < 0x10101020 || CRYPTOGRAPHY_IS_LIBRESSL) +#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_111D \ + (OPENSSL_VERSION_NUMBER < 0x10101040 || CRYPTOGRAPHY_IS_LIBRESSL) +#if (CRYPTOGRAPHY_OPENSSL_LESS_THAN_111D && !defined(OPENSSL_NO_ENGINE)) || \ + defined(USE_OSRANDOM_RNG_FOR_TESTING) +#define CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE 1 +#else +#define CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE 0 +#endif """ TYPES = """ static const int CRYPTOGRAPHY_OPENSSL_102L_OR_GREATER; +static const int CRYPTOGRAPHY_OPENSSL_102U_OR_GREATER; static const int CRYPTOGRAPHY_OPENSSL_110_OR_GREATER; static const int CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER; static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_102I; -static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_102; +static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_110; static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_111; +static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B; +static const int CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE; static const int CRYPTOGRAPHY_IS_LIBRESSL; """ diff --git a/src/_cffi_src/openssl/ct.py b/src/_cffi_src/openssl/ct.py index 71125dd17e09..162004a8da73 100644 --- a/src/_cffi_src/openssl/ct.py +++ b/src/_cffi_src/openssl/ct.py @@ -5,7 +5,7 @@ from __future__ import absolute_import, division, print_function INCLUDES = """ -#if CRYPTOGRAPHY_OPENSSL_110_OR_GREATER +#if CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER && !defined(OPENSSL_NO_CT) #include typedef STACK_OF(SCT) Cryptography_STACK_OF_SCT; @@ -65,7 +65,7 @@ """ CUSTOMIZATIONS = """ -#if CRYPTOGRAPHY_OPENSSL_110_OR_GREATER +#if CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER && !defined(OPENSSL_NO_CT) static const long Cryptography_HAS_SCT = 1; #else static const long Cryptography_HAS_SCT = 0; @@ -85,7 +85,12 @@ SCT_SOURCE_X509V3_EXTENSION, SCT_SOURCE_OCSP_STAPLED_RESPONSE } sct_source_t; + +/* OpenSSL compiled with `no-ct` still defines the `SCT` struct. */ +#if !defined(OPENSSL_NO_CT) typedef void SCT; +#endif + typedef void Cryptography_STACK_OF_SCT; sct_version_t (*SCT_get_version)(const SCT *) = NULL; diff --git a/src/_cffi_src/openssl/dh.py b/src/_cffi_src/openssl/dh.py index b0fd21f54079..0e1df23a6ac9 100644 --- a/src/_cffi_src/openssl/dh.py +++ b/src/_cffi_src/openssl/dh.py @@ -18,15 +18,8 @@ DH *DH_new(void); void DH_free(DH *); int DH_size(const DH *); -int DH_check_pub_key(const DH *, const BIGNUM *, int *); int DH_generate_key(DH *); int DH_compute_key(unsigned char *, const BIGNUM *, DH *); -int DH_set_ex_data(DH *, int, void *); -void *DH_get_ex_data(DH *, int); -DH *d2i_DHparams(DH **, const unsigned char **, long); -int i2d_DHparams(const DH *, unsigned char **); -int DHparams_print_fp(FILE *, const DH *); -int DHparams_print(BIO *, const DH *); DH *DHparams_dup(DH *); /* added in 1.1.0 when the DH struct was opaqued */ @@ -46,7 +39,7 @@ CUSTOMIZATIONS = """ /* These functions were added in OpenSSL 1.1.0 */ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) { diff --git a/src/_cffi_src/openssl/dsa.py b/src/_cffi_src/openssl/dsa.py index a4a87c3660e4..938c18fcf1b1 100644 --- a/src/_cffi_src/openssl/dsa.py +++ b/src/_cffi_src/openssl/dsa.py @@ -35,7 +35,7 @@ CUSTOMIZATIONS = """ /* These functions were added in OpenSSL 1.1.0 */ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) { diff --git a/src/_cffi_src/openssl/ec.py b/src/_cffi_src/openssl/ec.py index 66bcadc2372d..6432fc22e9e0 100644 --- a/src/_cffi_src/openssl/ec.py +++ b/src/_cffi_src/openssl/ec.py @@ -10,9 +10,7 @@ """ TYPES = """ -static const int Cryptography_HAS_EC; static const int Cryptography_HAS_EC2M; -static const int Cryptography_HAS_EC_1_0_2; static const int OPENSSL_EC_NAMED_CURVE; @@ -106,11 +104,11 @@ int EC_METHOD_get_field_type(const EC_METHOD *); const char *EC_curve_nid2nist(int); + +int EC_GROUP_get_asn1_flag(const EC_GROUP *); """ CUSTOMIZATIONS = """ -static const long Cryptography_HAS_EC = 1; - #if defined(OPENSSL_NO_EC2M) static const long Cryptography_HAS_EC2M = 0; @@ -125,11 +123,4 @@ #else static const long Cryptography_HAS_EC2M = 1; #endif - -#if (!CRYPTOGRAPHY_IS_LIBRESSL && CRYPTOGRAPHY_OPENSSL_LESS_THAN_102) -static const long Cryptography_HAS_EC_1_0_2 = 0; -const char *(*EC_curve_nid2nist)(int) = NULL; -#else -static const long Cryptography_HAS_EC_1_0_2 = 1; -#endif """ diff --git a/src/_cffi_src/openssl/ecdh.py b/src/_cffi_src/openssl/ecdh.py index 043635c41a1e..c73cc9f36fdd 100644 --- a/src/_cffi_src/openssl/ecdh.py +++ b/src/_cffi_src/openssl/ecdh.py @@ -9,8 +9,6 @@ """ TYPES = """ -static const int Cryptography_HAS_ECDH; -static const int Cryptography_HAS_SET_ECDH_AUTO; """ FUNCTIONS = """ @@ -20,12 +18,4 @@ """ CUSTOMIZATIONS = """ -static const long Cryptography_HAS_ECDH = 1; - -#ifndef SSL_CTX_set_ecdh_auto -static const long Cryptography_HAS_SET_ECDH_AUTO = 0; -long (*SSL_CTX_set_ecdh_auto)(SSL_CTX *, int) = NULL; -#else -static const long Cryptography_HAS_SET_ECDH_AUTO = 1; -#endif """ diff --git a/src/_cffi_src/openssl/ecdsa.py b/src/_cffi_src/openssl/ecdsa.py index 44a778a68690..3134e24b61d4 100644 --- a/src/_cffi_src/openssl/ecdsa.py +++ b/src/_cffi_src/openssl/ecdsa.py @@ -9,8 +9,6 @@ """ TYPES = """ -static const int Cryptography_HAS_ECDSA; - typedef ... ECDSA_SIG; typedef ... CRYPTO_EX_new; @@ -19,12 +17,6 @@ """ FUNCTIONS = """ -ECDSA_SIG *ECDSA_SIG_new(); -void ECDSA_SIG_free(ECDSA_SIG *); -int i2d_ECDSA_SIG(const ECDSA_SIG *, unsigned char **); -ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **s, const unsigned char **, long); -ECDSA_SIG *ECDSA_do_sign(const unsigned char *, int, EC_KEY *); -int ECDSA_do_verify(const unsigned char *, int, const ECDSA_SIG *, EC_KEY *); int ECDSA_sign(int, const unsigned char *, int, unsigned char *, unsigned int *, EC_KEY *); int ECDSA_verify(int, const unsigned char *, int, const unsigned char *, int, @@ -34,5 +26,4 @@ """ CUSTOMIZATIONS = """ -static const long Cryptography_HAS_ECDSA = 1; """ diff --git a/src/_cffi_src/openssl/engine.py b/src/_cffi_src/openssl/engine.py index 45ce952691a1..24cdd42a8393 100644 --- a/src/_cffi_src/openssl/engine.py +++ b/src/_cffi_src/openssl/engine.py @@ -10,124 +10,56 @@ TYPES = """ typedef ... ENGINE; -typedef ... RSA_METHOD; -typedef ... DSA_METHOD; -typedef ... DH_METHOD; -typedef struct { - int (*bytes)(unsigned char *, int); - int (*pseudorand)(unsigned char *, int); - int (*status)(); - ...; -} RAND_METHOD; -typedef int (*ENGINE_GEN_INT_FUNC_PTR)(ENGINE *); -typedef ... *ENGINE_CTRL_FUNC_PTR; -typedef ... *ENGINE_LOAD_KEY_PTR; -typedef ... *ENGINE_CIPHERS_PTR; -typedef ... *ENGINE_DIGESTS_PTR; -typedef ... ENGINE_CMD_DEFN; typedef ... UI_METHOD; -static const unsigned int ENGINE_METHOD_RSA; -static const unsigned int ENGINE_METHOD_DSA; -static const unsigned int ENGINE_METHOD_RAND; -static const unsigned int ENGINE_METHOD_CIPHERS; -static const unsigned int ENGINE_METHOD_DIGESTS; -static const unsigned int ENGINE_METHOD_ALL; -static const unsigned int ENGINE_METHOD_NONE; - -static const int ENGINE_R_CONFLICTING_ENGINE_ID; +static const long Cryptography_HAS_ENGINE; """ FUNCTIONS = """ -ENGINE *ENGINE_get_first(void); -ENGINE *ENGINE_get_last(void); -ENGINE *ENGINE_get_next(ENGINE *); -ENGINE *ENGINE_get_prev(ENGINE *); -int ENGINE_add(ENGINE *); -int ENGINE_remove(ENGINE *); ENGINE *ENGINE_by_id(const char *); int ENGINE_init(ENGINE *); int ENGINE_finish(ENGINE *); -void ENGINE_load_builtin_engines(void); -ENGINE *ENGINE_get_default_RSA(void); -ENGINE *ENGINE_get_default_DSA(void); -ENGINE *ENGINE_get_default_DH(void); ENGINE *ENGINE_get_default_RAND(void); -ENGINE *ENGINE_get_cipher_engine(int); -ENGINE *ENGINE_get_digest_engine(int); -int ENGINE_set_default_RSA(ENGINE *); -int ENGINE_set_default_DSA(ENGINE *); -int ENGINE_set_default_DH(ENGINE *); int ENGINE_set_default_RAND(ENGINE *); -int ENGINE_set_default_ciphers(ENGINE *); -int ENGINE_set_default_digests(ENGINE *); -int ENGINE_set_default_string(ENGINE *, const char *); -int ENGINE_set_default(ENGINE *, unsigned int); -unsigned int ENGINE_get_table_flags(void); -void ENGINE_set_table_flags(unsigned int); -int ENGINE_register_RSA(ENGINE *); -void ENGINE_unregister_RSA(ENGINE *); -void ENGINE_register_all_RSA(void); -int ENGINE_register_DSA(ENGINE *); -void ENGINE_unregister_DSA(ENGINE *); -void ENGINE_register_all_DSA(void); -int ENGINE_register_DH(ENGINE *); -void ENGINE_unregister_DH(ENGINE *); -void ENGINE_register_all_DH(void); -int ENGINE_register_RAND(ENGINE *); void ENGINE_unregister_RAND(ENGINE *); -void ENGINE_register_all_RAND(void); -int ENGINE_register_ciphers(ENGINE *); -void ENGINE_unregister_ciphers(ENGINE *); -void ENGINE_register_all_ciphers(void); -int ENGINE_register_digests(ENGINE *); -void ENGINE_unregister_digests(ENGINE *); -void ENGINE_register_all_digests(void); -int ENGINE_register_complete(ENGINE *); -int ENGINE_register_all_complete(void); -int ENGINE_ctrl(ENGINE *, int, long, void *, void (*)(void)); -int ENGINE_cmd_is_executable(ENGINE *, int); int ENGINE_ctrl_cmd(ENGINE *, const char *, long, void *, void (*)(void), int); -int ENGINE_ctrl_cmd_string(ENGINE *, const char *, const char *, int); - -ENGINE *ENGINE_new(void); int ENGINE_free(ENGINE *); -int ENGINE_up_ref(ENGINE *); -int ENGINE_set_id(ENGINE *, const char *); -int ENGINE_set_name(ENGINE *, const char *); -int ENGINE_set_RSA(ENGINE *, const RSA_METHOD *); -int ENGINE_set_DSA(ENGINE *, const DSA_METHOD *); -int ENGINE_set_DH(ENGINE *, const DH_METHOD *); -int ENGINE_set_RAND(ENGINE *, const RAND_METHOD *); -int ENGINE_set_destroy_function(ENGINE *, ENGINE_GEN_INT_FUNC_PTR); -int ENGINE_set_init_function(ENGINE *, ENGINE_GEN_INT_FUNC_PTR); -int ENGINE_set_finish_function(ENGINE *, ENGINE_GEN_INT_FUNC_PTR); -int ENGINE_set_ctrl_function(ENGINE *, ENGINE_CTRL_FUNC_PTR); -int ENGINE_set_load_privkey_function(ENGINE *, ENGINE_LOAD_KEY_PTR); -int ENGINE_set_load_pubkey_function(ENGINE *, ENGINE_LOAD_KEY_PTR); -int ENGINE_set_ciphers(ENGINE *, ENGINE_CIPHERS_PTR); -int ENGINE_set_digests(ENGINE *, ENGINE_DIGESTS_PTR); -int ENGINE_set_flags(ENGINE *, int); -int ENGINE_set_cmd_defns(ENGINE *, const ENGINE_CMD_DEFN *); -const char *ENGINE_get_id(const ENGINE *); const char *ENGINE_get_name(const ENGINE *); -const RSA_METHOD *ENGINE_get_RSA(const ENGINE *); -const DSA_METHOD *ENGINE_get_DSA(const ENGINE *); -const DH_METHOD *ENGINE_get_DH(const ENGINE *); -const RAND_METHOD *ENGINE_get_RAND(const ENGINE *); -const EVP_CIPHER *ENGINE_get_cipher(ENGINE *, int); -const EVP_MD *ENGINE_get_digest(ENGINE *, int); -int ENGINE_get_flags(const ENGINE *); -const ENGINE_CMD_DEFN *ENGINE_get_cmd_defns(const ENGINE *); +// These bindings are unused by cryptography or pyOpenSSL but are present +// for advanced users who need them. +int ENGINE_ctrl_cmd_string(ENGINE *, const char *, const char *, int); +void ENGINE_load_builtin_engines(void); EVP_PKEY *ENGINE_load_private_key(ENGINE *, const char *, UI_METHOD *, void *); EVP_PKEY *ENGINE_load_public_key(ENGINE *, const char *, UI_METHOD *, void *); -void ENGINE_add_conf_module(void); -/* these became macros in 1.1.0 */ -void ENGINE_load_openssl(void); -void ENGINE_load_dynamic(void); -void ENGINE_cleanup(void); """ CUSTOMIZATIONS = """ +#ifdef OPENSSL_NO_ENGINE +static const long Cryptography_HAS_ENGINE = 0; + +ENGINE *(*ENGINE_by_id)(const char *) = NULL; +int (*ENGINE_init)(ENGINE *) = NULL; +int (*ENGINE_finish)(ENGINE *) = NULL; +ENGINE *(*ENGINE_get_default_RAND)(void) = NULL; +int (*ENGINE_set_default_RAND)(ENGINE *) = NULL; +void (*ENGINE_unregister_RAND)(ENGINE *) = NULL; +int (*ENGINE_ctrl_cmd)(ENGINE *, const char *, long, void *, + void (*)(void), int) = NULL; + +int (*ENGINE_free)(ENGINE *) = NULL; +const char *(*ENGINE_get_id)(const ENGINE *) = NULL; +const char *(*ENGINE_get_name)(const ENGINE *) = NULL; + +int (*ENGINE_ctrl_cmd_string)(ENGINE *, const char *, const char *, + int) = NULL; +void (*ENGINE_load_builtin_engines)(void) = NULL; +EVP_PKEY *(*ENGINE_load_private_key)(ENGINE *, const char *, UI_METHOD *, + void *) = NULL; +EVP_PKEY *(*ENGINE_load_public_key)(ENGINE *, const char *, + UI_METHOD *, void *) = NULL; + +#else +static const long Cryptography_HAS_ENGINE = 1; +#endif """ diff --git a/src/_cffi_src/openssl/err.py b/src/_cffi_src/openssl/err.py index d4033f5a48e8..0dd7414674fe 100644 --- a/src/_cffi_src/openssl/err.py +++ b/src/_cffi_src/openssl/err.py @@ -9,141 +9,24 @@ """ TYPES = """ -static const int Cryptography_HAS_EC_CODES; -static const int Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR; -static const int Cryptography_HAS_EVP_R_MEMORY_LIMIT_EXCEEDED; - -static const int ERR_LIB_DH; -static const int ERR_LIB_EVP; -static const int ERR_LIB_EC; -static const int ERR_LIB_PEM; -static const int ERR_LIB_ASN1; -static const int ERR_LIB_RSA; -static const int ERR_LIB_PKCS12; -static const int ERR_LIB_SSL; -static const int ERR_LIB_X509; - -static const int ERR_R_MALLOC_FAILURE; -static const int EVP_R_MEMORY_LIMIT_EXCEEDED; - -static const int ASN1_R_BOOLEAN_IS_WRONG_LENGTH; -static const int ASN1_R_BUFFER_TOO_SMALL; -static const int ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER; -static const int ASN1_R_DATA_IS_WRONG; -static const int ASN1_R_DECODE_ERROR; -static const int ASN1_R_DEPTH_EXCEEDED; -static const int ASN1_R_ENCODE_ERROR; -static const int ASN1_R_ERROR_GETTING_TIME; -static const int ASN1_R_ERROR_LOADING_SECTION; -static const int ASN1_R_MSTRING_WRONG_TAG; -static const int ASN1_R_NESTED_ASN1_STRING; -static const int ASN1_R_NO_MATCHING_CHOICE_TYPE; -static const int ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM; -static const int ASN1_R_UNKNOWN_OBJECT_TYPE; -static const int ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE; -static const int ASN1_R_UNKNOWN_TAG; -static const int ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE; -static const int ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE; -static const int ASN1_R_UNSUPPORTED_TYPE; -static const int ASN1_R_WRONG_TAG; -static const int ASN1_R_NO_CONTENT_TYPE; -static const int ASN1_R_NO_MULTIPART_BODY_FAILURE; -static const int ASN1_R_NO_MULTIPART_BOUNDARY; -static const int ASN1_R_HEADER_TOO_LONG; - -static const int DH_R_INVALID_PUBKEY; - static const int EVP_F_EVP_ENCRYPTFINAL_EX; - -static const int EVP_R_AES_KEY_SETUP_FAILED; -static const int EVP_R_BAD_DECRYPT; -static const int EVP_R_CIPHER_PARAMETER_ERROR; -static const int EVP_R_CTRL_NOT_IMPLEMENTED; -static const int EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED; static const int EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH; -static const int EVP_R_DECODE_ERROR; -static const int EVP_R_DIFFERENT_KEY_TYPES; -static const int EVP_R_INITIALIZATION_ERROR; -static const int EVP_R_INPUT_NOT_INITIALIZED; -static const int EVP_R_INVALID_KEY_LENGTH; -static const int EVP_R_KEYGEN_FAILURE; -static const int EVP_R_MISSING_PARAMETERS; -static const int EVP_R_NO_CIPHER_SET; -static const int EVP_R_NO_DIGEST_SET; -static const int EVP_R_PUBLIC_KEY_NOT_RSA; -static const int EVP_R_UNKNOWN_PBE_ALGORITHM; -static const int EVP_R_UNSUPPORTED_CIPHER; -static const int EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION; -static const int EVP_R_UNSUPPORTED_KEYLENGTH; -static const int EVP_R_UNSUPPORTED_SALT_TYPE; +static const int EVP_R_BAD_DECRYPT; static const int EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM; -static const int EVP_R_WRONG_FINAL_BLOCK_LENGTH; -static const int EVP_R_CAMELLIA_KEY_SETUP_FAILED; - -static const int EC_R_UNKNOWN_GROUP; - -static const int PEM_R_BAD_BASE64_DECODE; -static const int PEM_R_BAD_DECRYPT; -static const int PEM_R_BAD_END_LINE; -static const int PEM_R_BAD_IV_CHARS; -static const int PEM_R_BAD_PASSWORD_READ; -static const int PEM_R_ERROR_CONVERTING_PRIVATE_KEY; -static const int PEM_R_NO_START_LINE; -static const int PEM_R_NOT_DEK_INFO; -static const int PEM_R_NOT_ENCRYPTED; -static const int PEM_R_NOT_PROC_TYPE; -static const int PEM_R_PROBLEMS_GETTING_PASSWORD; -static const int PEM_R_READ_KEY; -static const int PEM_R_SHORT_HEADER; -static const int PEM_R_UNSUPPORTED_CIPHER; -static const int PEM_R_UNSUPPORTED_ENCRYPTION; - static const int PKCS12_R_PKCS12_CIPHERFINAL_ERROR; +static const int PEM_R_UNSUPPORTED_ENCRYPTION; +static const int EVP_R_UNKNOWN_PBE_ALGORITHM; -static const int RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE; -static const int RSA_R_DATA_TOO_LARGE_FOR_MODULUS; -static const int RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY; -static const int RSA_R_BLOCK_TYPE_IS_NOT_01; -static const int RSA_R_BLOCK_TYPE_IS_NOT_02; -static const int RSA_R_PKCS_DECODING_ERROR; -static const int RSA_R_OAEP_DECODING_ERROR; +static const int ERR_LIB_EVP; +static const int ERR_LIB_PEM; +static const int ERR_LIB_ASN1; +static const int ERR_LIB_PKCS12; static const int SSL_TLSEXT_ERR_OK; -static const int SSL_TLSEXT_ERR_ALERT_WARNING; static const int SSL_TLSEXT_ERR_ALERT_FATAL; static const int SSL_TLSEXT_ERR_NOACK; -static const int SSL_AD_CLOSE_NOTIFY; -static const int SSL_AD_UNEXPECTED_MESSAGE; -static const int SSL_AD_BAD_RECORD_MAC; -static const int SSL_AD_RECORD_OVERFLOW; -static const int SSL_AD_DECOMPRESSION_FAILURE; -static const int SSL_AD_HANDSHAKE_FAILURE; -static const int SSL_AD_BAD_CERTIFICATE; -static const int SSL_AD_UNSUPPORTED_CERTIFICATE; -static const int SSL_AD_CERTIFICATE_REVOKED; -static const int SSL_AD_CERTIFICATE_EXPIRED; -static const int SSL_AD_CERTIFICATE_UNKNOWN; -static const int SSL_AD_ILLEGAL_PARAMETER; -static const int SSL_AD_UNKNOWN_CA; -static const int SSL_AD_ACCESS_DENIED; -static const int SSL_AD_DECODE_ERROR; -static const int SSL_AD_DECRYPT_ERROR; -static const int SSL_AD_PROTOCOL_VERSION; -static const int SSL_AD_INSUFFICIENT_SECURITY; -static const int SSL_AD_INTERNAL_ERROR; -static const int SSL_AD_USER_CANCELLED; -static const int SSL_AD_NO_RENEGOTIATION; - -static const int SSL_AD_UNSUPPORTED_EXTENSION; -static const int SSL_AD_CERTIFICATE_UNOBTAINABLE; -static const int SSL_AD_UNRECOGNIZED_NAME; -static const int SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE; -static const int SSL_AD_BAD_CERTIFICATE_HASH_VALUE; -static const int SSL_AD_UNKNOWN_PSK_IDENTITY; - static const int X509_R_CERT_ALREADY_IN_HASH_TABLE; -static const int X509_R_KEY_VALUES_MISMATCH; """ FUNCTIONS = """ @@ -153,7 +36,6 @@ const char *ERR_reason_error_string(unsigned long); unsigned long ERR_get_error(void); unsigned long ERR_peek_error(void); -unsigned long ERR_peek_last_error(void); void ERR_clear_error(void); void ERR_put_error(int, int, int, const char *, int); @@ -164,19 +46,4 @@ """ CUSTOMIZATIONS = """ -static const long Cryptography_HAS_EC_CODES = 1; - -#ifdef RSA_R_PKCS_DECODING_ERROR -static const long Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR = 1; -#else -static const long Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR = 0; -static const long RSA_R_PKCS_DECODING_ERROR = 0; -#endif - -#ifdef EVP_R_MEMORY_LIMIT_EXCEEDED -static const long Cryptography_HAS_EVP_R_MEMORY_LIMIT_EXCEEDED = 1; -#else -static const long EVP_R_MEMORY_LIMIT_EXCEEDED = 0; -static const long Cryptography_HAS_EVP_R_MEMORY_LIMIT_EXCEEDED = 0; -#endif """ diff --git a/src/_cffi_src/openssl/evp.py b/src/_cffi_src/openssl/evp.py index 9ae6025a4057..d7ac93e603fc 100644 --- a/src/_cffi_src/openssl/evp.py +++ b/src/_cffi_src/openssl/evp.py @@ -25,14 +25,12 @@ static const int EVP_PKEY_ED25519; static const int EVP_PKEY_X448; static const int EVP_PKEY_ED448; +static const int EVP_PKEY_POLY1305; static const int EVP_MAX_MD_SIZE; static const int EVP_CTRL_AEAD_SET_IVLEN; static const int EVP_CTRL_AEAD_GET_TAG; static const int EVP_CTRL_AEAD_SET_TAG; -static const int Cryptography_HAS_GCM; -static const int Cryptography_HAS_PBKDF2_HMAC; -static const int Cryptography_HAS_PKEY_CTX; static const int Cryptography_HAS_SCRYPT; static const int Cryptography_HAS_EVP_PKEY_DHX; static const int Cryptography_HAS_EVP_PKEY_get_set_tls_encodedpoint; @@ -43,23 +41,12 @@ FUNCTIONS = """ const EVP_CIPHER *EVP_get_cipherbyname(const char *); -int EVP_EncryptInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *, - const unsigned char *, const unsigned char *); int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *, int); -int EVP_EncryptUpdate(EVP_CIPHER_CTX *, unsigned char *, int *, - const unsigned char *, int); -int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *); -int EVP_DecryptInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *, - const unsigned char *, const unsigned char *); -int EVP_DecryptUpdate(EVP_CIPHER_CTX *, unsigned char *, int *, - const unsigned char *, int); -int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *); int EVP_CipherInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *, const unsigned char *, const unsigned char *, int); int EVP_CipherUpdate(EVP_CIPHER_CTX *, unsigned char *, int *, const unsigned char *, int); int EVP_CipherFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *); -int EVP_CIPHER_block_size(const EVP_CIPHER *); int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *); EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void); void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *); @@ -72,8 +59,6 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *, unsigned char *, unsigned int *); int EVP_DigestFinalXOF(EVP_MD_CTX *, unsigned char *, size_t); const EVP_MD *EVP_get_digestbyname(const char *); -const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *); -int EVP_MD_size(const EVP_MD *); EVP_PKEY *EVP_PKEY_new(void); void EVP_PKEY_free(EVP_PKEY *); @@ -97,22 +82,14 @@ int EVP_VerifyFinal(EVP_MD_CTX *, const unsigned char *, unsigned int, EVP_PKEY *); -const EVP_MD *EVP_md5(void); -const EVP_MD *EVP_sha1(void); -const EVP_MD *EVP_ripemd160(void); -const EVP_MD *EVP_sha224(void); -const EVP_MD *EVP_sha256(void); -const EVP_MD *EVP_sha384(void); -const EVP_MD *EVP_sha512(void); - int EVP_DigestSignInit(EVP_MD_CTX *, EVP_PKEY_CTX **, const EVP_MD *, ENGINE *, EVP_PKEY *); +int EVP_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 *); -int PKCS5_PBKDF2_HMAC_SHA1(const char *, int, const unsigned char *, int, int, - int, unsigned char *); EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *, ENGINE *); EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int, ENGINE *); @@ -131,18 +108,6 @@ int EVP_PKEY_set1_DSA(EVP_PKEY *, DSA *); int EVP_PKEY_set1_DH(EVP_PKEY *, DH *); -int EVP_PKEY_get_attr_count(const EVP_PKEY *); -int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *, int, int); -X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *, int); -X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *, int); -int EVP_PKEY_add1_attr(EVP_PKEY *, X509_ATTRIBUTE *); -int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *, const ASN1_OBJECT *, int, - const unsigned char *, int); -int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *, int, int, - const unsigned char *, int); -int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *, const char *, int, - const unsigned char *, int); - int EVP_PKEY_cmp(const EVP_PKEY *, const EVP_PKEY *); int EVP_PKEY_keygen_init(EVP_PKEY_CTX *); @@ -170,25 +135,15 @@ int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *, const unsigned char *, size_t); -/* PKCS8_PRIV_KEY_INFO * became const in 1.1.0 */ -EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *); - /* EVP_PKEY * became const in 1.1.0 */ int EVP_PKEY_bits(EVP_PKEY *); -/* became a macro in 1.1.0 */ -void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *); - void OpenSSL_add_all_algorithms(void); int EVP_PKEY_assign_RSA(EVP_PKEY *, RSA *); -int EVP_PKEY_assign_DSA(EVP_PKEY *, DSA *); -int EVP_PKEY_assign_EC_KEY(EVP_PKEY *, EC_KEY *); EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *); int EVP_PKEY_set1_EC_KEY(EVP_PKEY *, EC_KEY *); -int EVP_MD_CTX_block_size(const EVP_MD_CTX *); -int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *); int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *, int, int, void *); int PKCS5_PBKDF2_HMAC(const char *, int, const unsigned char *, int, int, @@ -209,11 +164,6 @@ """ CUSTOMIZATIONS = """ -const long Cryptography_HAS_GCM = 1; - -const long Cryptography_HAS_PBKDF2_HMAC = 1; -const long Cryptography_HAS_PKEY_CTX = 1; - #ifdef EVP_PKEY_DHX const long Cryptography_HAS_EVP_PKEY_DHX = 1; #else @@ -317,4 +267,10 @@ #ifndef EVP_PKEY_ED448 #define EVP_PKEY_ED448 NID_ED448 #endif + +/* This is tied to poly1305 support so we reuse the Cryptography_HAS_POLY1305 + conditional to remove it. */ +#ifndef EVP_PKEY_POLY1305 +#define EVP_PKEY_POLY1305 NID_poly1305 +#endif """ diff --git a/src/_cffi_src/openssl/hmac.py b/src/_cffi_src/openssl/hmac.py index b006e642d33c..2bc70068ed6b 100644 --- a/src/_cffi_src/openssl/hmac.py +++ b/src/_cffi_src/openssl/hmac.py @@ -37,7 +37,7 @@ void Cryptography_HMAC_CTX_free(HMAC_CTX *ctx) { #if CRYPTOGRAPHY_OPENSSL_110_OR_GREATER - return HMAC_CTX_free(ctx); + HMAC_CTX_free(ctx); #else if (ctx != NULL) { HMAC_CTX_cleanup(ctx); diff --git a/src/_cffi_src/openssl/nid.py b/src/_cffi_src/openssl/nid.py index 4117b933a151..aecdc9c0f4ed 100644 --- a/src/_cffi_src/openssl/nid.py +++ b/src/_cffi_src/openssl/nid.py @@ -13,220 +13,20 @@ static const int Cryptography_HAS_X448; static const int Cryptography_HAS_ED448; static const int Cryptography_HAS_ED25519; +static const int Cryptography_HAS_POLY1305; static const int NID_undef; -static const int NID_dsa; -static const int NID_dsaWithSHA; -static const int NID_dsaWithSHA1; -static const int NID_md2; -static const int NID_md4; -static const int NID_md5; -static const int NID_mdc2; -static const int NID_ripemd160; -static const int NID_sha; -static const int NID_sha1; -static const int NID_sha256; -static const int NID_sha384; -static const int NID_sha512; -static const int NID_sha224; -static const int NID_sha; -static const int NID_ecdsa_with_SHA1; -static const int NID_ecdsa_with_SHA224; -static const int NID_ecdsa_with_SHA256; -static const int NID_ecdsa_with_SHA384; -static const int NID_ecdsa_with_SHA512; static const int NID_pbe_WithSHA1And3_Key_TripleDES_CBC; -static const int NID_X9_62_c2pnb163v1; -static const int NID_X9_62_c2pnb163v2; -static const int NID_X9_62_c2pnb163v3; -static const int NID_X9_62_c2pnb176v1; -static const int NID_X9_62_c2tnb191v1; -static const int NID_X9_62_c2tnb191v2; -static const int NID_X9_62_c2tnb191v3; -static const int NID_X9_62_c2onb191v4; -static const int NID_X9_62_c2onb191v5; -static const int NID_X9_62_c2pnb208w1; -static const int NID_X9_62_c2tnb239v1; -static const int NID_X9_62_c2tnb239v2; -static const int NID_X9_62_c2tnb239v3; -static const int NID_X9_62_c2onb239v4; -static const int NID_X9_62_c2onb239v5; -static const int NID_X9_62_c2pnb272w1; -static const int NID_X9_62_c2pnb304w1; -static const int NID_X9_62_c2tnb359v1; -static const int NID_X9_62_c2pnb368w1; -static const int NID_X9_62_c2tnb431r1; -static const int NID_X9_62_prime192v1; -static const int NID_X9_62_prime192v2; -static const int NID_X9_62_prime192v3; -static const int NID_X9_62_prime239v1; -static const int NID_X9_62_prime239v2; -static const int NID_X9_62_prime239v3; -static const int NID_X9_62_prime256v1; -static const int NID_secp112r1; -static const int NID_secp112r2; -static const int NID_secp128r1; -static const int NID_secp128r2; -static const int NID_secp160k1; -static const int NID_secp160r1; -static const int NID_secp160r2; -static const int NID_sect163k1; -static const int NID_sect163r1; -static const int NID_sect163r2; -static const int NID_secp192k1; -static const int NID_secp224k1; -static const int NID_secp224r1; -static const int NID_secp256k1; -static const int NID_secp384r1; -static const int NID_secp521r1; -static const int NID_sect113r1; -static const int NID_sect113r2; -static const int NID_sect131r1; -static const int NID_sect131r2; -static const int NID_sect193r1; -static const int NID_sect193r2; -static const int NID_sect233k1; -static const int NID_sect233r1; -static const int NID_sect239k1; -static const int NID_sect283k1; -static const int NID_sect283r1; -static const int NID_sect409k1; -static const int NID_sect409r1; -static const int NID_sect571k1; -static const int NID_sect571r1; static const int NID_X25519; static const int NID_X448; static const int NID_ED25519; static const int NID_ED448; -static const int NID_wap_wsg_idm_ecid_wtls1; -static const int NID_wap_wsg_idm_ecid_wtls3; -static const int NID_wap_wsg_idm_ecid_wtls4; -static const int NID_wap_wsg_idm_ecid_wtls5; -static const int NID_wap_wsg_idm_ecid_wtls6; -static const int NID_wap_wsg_idm_ecid_wtls7; -static const int NID_wap_wsg_idm_ecid_wtls8; -static const int NID_wap_wsg_idm_ecid_wtls9; -static const int NID_wap_wsg_idm_ecid_wtls10; -static const int NID_wap_wsg_idm_ecid_wtls11; -static const int NID_wap_wsg_idm_ecid_wtls12; -static const int NID_ipsec3; -static const int NID_ipsec4; -static const char *const SN_X9_62_c2pnb163v1; -static const char *const SN_X9_62_c2pnb163v2; -static const char *const SN_X9_62_c2pnb163v3; -static const char *const SN_X9_62_c2pnb176v1; -static const char *const SN_X9_62_c2tnb191v1; -static const char *const SN_X9_62_c2tnb191v2; -static const char *const SN_X9_62_c2tnb191v3; -static const char *const SN_X9_62_c2onb191v4; -static const char *const SN_X9_62_c2onb191v5; -static const char *const SN_X9_62_c2pnb208w1; -static const char *const SN_X9_62_c2tnb239v1; -static const char *const SN_X9_62_c2tnb239v2; -static const char *const SN_X9_62_c2tnb239v3; -static const char *const SN_X9_62_c2onb239v4; -static const char *const SN_X9_62_c2onb239v5; -static const char *const SN_X9_62_c2pnb272w1; -static const char *const SN_X9_62_c2pnb304w1; -static const char *const SN_X9_62_c2tnb359v1; -static const char *const SN_X9_62_c2pnb368w1; -static const char *const SN_X9_62_c2tnb431r1; -static const char *const SN_X9_62_prime192v1; -static const char *const SN_X9_62_prime192v2; -static const char *const SN_X9_62_prime192v3; -static const char *const SN_X9_62_prime239v1; -static const char *const SN_X9_62_prime239v2; -static const char *const SN_X9_62_prime239v3; -static const char *const SN_X9_62_prime256v1; -static const char *const SN_secp112r1; -static const char *const SN_secp112r2; -static const char *const SN_secp128r1; -static const char *const SN_secp128r2; -static const char *const SN_secp160k1; -static const char *const SN_secp160r1; -static const char *const SN_secp160r2; -static const char *const SN_sect163k1; -static const char *const SN_sect163r1; -static const char *const SN_sect163r2; -static const char *const SN_secp192k1; -static const char *const SN_secp224k1; -static const char *const SN_secp224r1; -static const char *const SN_secp256k1; -static const char *const SN_secp384r1; -static const char *const SN_secp521r1; -static const char *const SN_sect113r1; -static const char *const SN_sect113r2; -static const char *const SN_sect131r1; -static const char *const SN_sect131r2; -static const char *const SN_sect193r1; -static const char *const SN_sect193r2; -static const char *const SN_sect233k1; -static const char *const SN_sect233r1; -static const char *const SN_sect239k1; -static const char *const SN_sect283k1; -static const char *const SN_sect283r1; -static const char *const SN_sect409k1; -static const char *const SN_sect409r1; -static const char *const SN_sect571k1; -static const char *const SN_sect571r1; -static const char *const SN_wap_wsg_idm_ecid_wtls1; -static const char *const SN_wap_wsg_idm_ecid_wtls3; -static const char *const SN_wap_wsg_idm_ecid_wtls4; -static const char *const SN_wap_wsg_idm_ecid_wtls5; -static const char *const SN_wap_wsg_idm_ecid_wtls6; -static const char *const SN_wap_wsg_idm_ecid_wtls7; -static const char *const SN_wap_wsg_idm_ecid_wtls8; -static const char *const SN_wap_wsg_idm_ecid_wtls9; -static const char *const SN_wap_wsg_idm_ecid_wtls10; -static const char *const SN_wap_wsg_idm_ecid_wtls11; -static const char *const SN_wap_wsg_idm_ecid_wtls12; -static const char *const SN_ipsec3; -static const char *const SN_ipsec4; +static const int NID_poly1305; -static const int NID_subject_key_identifier; -static const int NID_authority_key_identifier; -static const int NID_policy_constraints; -static const int NID_ext_key_usage; -static const int NID_info_access; -static const int NID_key_usage; static const int NID_subject_alt_name; -static const int NID_issuer_alt_name; -static const int NID_basic_constraints; -static const int NID_issuing_distribution_point; -static const int NID_certificate_issuer; -static const int NID_name_constraints; -static const int NID_crl_distribution_points; -static const int NID_certificate_policies; -static const int NID_inhibit_any_policy; - -static const int NID_private_key_usage_period; -static const int NID_crl_number; static const int NID_crl_reason; -static const int NID_invalidity_date; -static const int NID_delta_crl; -static const int NID_any_policy; -static const int NID_policy_mappings; -static const int NID_target_information; -static const int NID_no_rev_avail; - -static const int NID_commonName; -static const int NID_countryName; -static const int NID_localityName; -static const int NID_stateOrProvinceName; -static const int NID_organizationName; -static const int NID_organizationalUnitName; -static const int NID_serialNumber; -static const int NID_surname; -static const int NID_givenName; -static const int NID_title; -static const int NID_generationQualifier; -static const int NID_dnQualifier; -static const int NID_pseudonym; -static const int NID_domainComponent; -static const int NID_pkcs9_emailAddress; -static const int NID_ad_OCSP; -static const int NID_ad_ca_issuers; +static const int NID_pkcs7_signed; """ FUNCTIONS = """ @@ -257,4 +57,10 @@ #else static const long Cryptography_HAS_ED448 = 1; #endif +#ifndef NID_poly1305 +static const long Cryptography_HAS_POLY1305 = 0; +static const int NID_poly1305 = 0; +#else +static const long Cryptography_HAS_POLY1305 = 1; +#endif """ diff --git a/src/_cffi_src/openssl/objects.py b/src/_cffi_src/openssl/objects.py index 265ac75c0905..236903d986a9 100644 --- a/src/_cffi_src/openssl/objects.py +++ b/src/_cffi_src/openssl/objects.py @@ -20,21 +20,13 @@ """ FUNCTIONS = """ -ASN1_OBJECT *OBJ_nid2obj(int); const char *OBJ_nid2ln(int); const char *OBJ_nid2sn(int); int OBJ_obj2nid(const ASN1_OBJECT *); -int OBJ_ln2nid(const char *); int OBJ_sn2nid(const char *); int OBJ_txt2nid(const char *); ASN1_OBJECT *OBJ_txt2obj(const char *, int); int OBJ_obj2txt(char *, int, const ASN1_OBJECT *, int); -int OBJ_cmp(const ASN1_OBJECT *, const ASN1_OBJECT *); -ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *); -int OBJ_create(const char *, const char *, const char *); -void OBJ_NAME_do_all(int, void (*) (const OBJ_NAME *, void *), void *); -/* OBJ_cleanup became a macro in 1.1.0 */ -void OBJ_cleanup(void); """ CUSTOMIZATIONS = """ diff --git a/src/_cffi_src/openssl/ocsp.py b/src/_cffi_src/openssl/ocsp.py index 829314a32563..f1a8bf617941 100644 --- a/src/_cffi_src/openssl/ocsp.py +++ b/src/_cffi_src/openssl/ocsp.py @@ -46,8 +46,6 @@ X509_EXTENSION *OCSP_REQUEST_get_ext(OCSP_REQUEST *, int); int OCSP_request_onereq_count(OCSP_REQUEST *); OCSP_ONEREQ *OCSP_request_onereq_get0(OCSP_REQUEST *, int); -int OCSP_ONEREQ_get_ext_count(OCSP_ONEREQ *); -X509_EXTENSION *OCSP_ONEREQ_get_ext(OCSP_ONEREQ *, int); OCSP_CERTID *OCSP_onereq_get0_id(OCSP_ONEREQ *); OCSP_ONEREQ *OCSP_request_add0_id(OCSP_REQUEST *, OCSP_CERTID *); OCSP_CERTID *OCSP_cert_to_id(const EVP_MD *, const X509 *, const X509 *); @@ -59,7 +57,6 @@ OCSP_SINGLERESP *OCSP_basic_add1_status(OCSP_BASICRESP *, OCSP_CERTID *, int, int, ASN1_TIME *, ASN1_TIME *, ASN1_TIME *); -int OCSP_basic_add1_nonce(OCSP_BASICRESP *, unsigned char *, int); int OCSP_basic_add1_cert(OCSP_BASICRESP *, X509 *); int OCSP_BASICRESP_add_ext(OCSP_BASICRESP *, X509_EXTENSION *, int); int OCSP_basic_sign(OCSP_BASICRESP *, X509 *, EVP_PKEY *, const EVP_MD *, @@ -69,7 +66,6 @@ OCSP_REQUEST *OCSP_REQUEST_new(void); void OCSP_REQUEST_free(OCSP_REQUEST *); -int OCSP_request_add1_nonce(OCSP_REQUEST *, unsigned char *, int); int OCSP_REQUEST_add_ext(OCSP_REQUEST *, X509_EXTENSION *, int); int OCSP_id_get0_info(ASN1_OCTET_STRING **, ASN1_OBJECT **, ASN1_OCTET_STRING **, ASN1_INTEGER **, OCSP_CERTID *); diff --git a/src/_cffi_src/openssl/pem.py b/src/_cffi_src/openssl/pem.py index 55519bb1bbcd..3f279c4fffa9 100644 --- a/src/_cffi_src/openssl/pem.py +++ b/src/_cffi_src/openssl/pem.py @@ -24,13 +24,9 @@ int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *, char *, int, pem_password_cb *, void *); -int PEM_write_bio_PKCS8PrivateKey_nid(BIO *, EVP_PKEY *, int, char *, int, - pem_password_cb *, void *); int i2d_PKCS8PrivateKey_bio(BIO *, EVP_PKEY *, const EVP_CIPHER *, char *, int, pem_password_cb *, void *); -int i2d_PKCS8PrivateKey_nid_bio(BIO *, EVP_PKEY *, int, - char *, int, pem_password_cb *, void *); int i2d_PKCS7_bio(BIO *, PKCS7 *); PKCS7 *d2i_PKCS7_bio(BIO *, PKCS7 **); @@ -46,17 +42,11 @@ int PEM_write_bio_X509_CRL(BIO *, X509_CRL *); -X509 *PEM_read_bio_X509_AUX(BIO *, X509 **, pem_password_cb *, void *); - PKCS7 *PEM_read_bio_PKCS7(BIO *, PKCS7 **, pem_password_cb *, void *); int PEM_write_bio_PKCS7(BIO *, PKCS7 *); DH *PEM_read_bio_DHparams(BIO *, DH **, pem_password_cb *, void *); -DSA *PEM_read_bio_DSAPrivateKey(BIO *, DSA **, pem_password_cb *, void *); - -RSA *PEM_read_bio_RSAPrivateKey(BIO *, RSA **, pem_password_cb *, void *); - int PEM_write_bio_DSAPrivateKey(BIO *, DSA *, const EVP_CIPHER *, unsigned char *, int, pem_password_cb *, void *); @@ -65,12 +55,8 @@ unsigned char *, int, pem_password_cb *, void *); -DSA *PEM_read_bio_DSA_PUBKEY(BIO *, DSA **, pem_password_cb *, void *); - RSA *PEM_read_bio_RSAPublicKey(BIO *, RSA **, pem_password_cb *, void *); -int PEM_write_bio_DSA_PUBKEY(BIO *, DSA *); - int PEM_write_bio_RSAPublicKey(BIO *, const RSA *); EVP_PKEY *PEM_read_bio_PUBKEY(BIO *, EVP_PKEY **, pem_password_cb *, void *); diff --git a/src/_cffi_src/openssl/pkcs7.py b/src/_cffi_src/openssl/pkcs7.py index 1bece5b7ef09..c22263dfe6c1 100644 --- a/src/_cffi_src/openssl/pkcs7.py +++ b/src/_cffi_src/openssl/pkcs7.py @@ -24,6 +24,7 @@ typedef ... PKCS7_DIGEST; typedef ... PKCS7_ENCRYPT; typedef ... PKCS7_ENVELOPE; +typedef ... PKCS7_SIGNER_INFO; typedef struct { ASN1_OBJECT *type; @@ -51,33 +52,28 @@ static const int PKCS7_NOVERIFY; static const int PKCS7_STREAM; static const int PKCS7_TEXT; +static const int PKCS7_PARTIAL; """ FUNCTIONS = """ -PKCS7 *SMIME_read_PKCS7(BIO *, BIO **); -int SMIME_write_PKCS7(BIO *, PKCS7 *, BIO *, int); - void PKCS7_free(PKCS7 *); - PKCS7 *PKCS7_sign(X509 *, EVP_PKEY *, Cryptography_STACK_OF_X509 *, - BIO *, int); + 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 *, + const EVP_MD *, int); +int PKCS7_final(PKCS7 *, BIO *, int); +/* Included verify due to external consumer, see + https://github.com/pyca/cryptography/issues/5433 */ int PKCS7_verify(PKCS7 *, Cryptography_STACK_OF_X509 *, X509_STORE *, BIO *, BIO *, int); -Cryptography_STACK_OF_X509 *PKCS7_get0_signers(PKCS7 *, - Cryptography_STACK_OF_X509 *, - int); - -PKCS7 *PKCS7_encrypt(Cryptography_STACK_OF_X509 *, BIO *, - const EVP_CIPHER *, int); -int PKCS7_decrypt(PKCS7 *, EVP_PKEY *, X509 *, BIO *, int); +PKCS7 *SMIME_read_PKCS7(BIO *, BIO **); -BIO *PKCS7_dataInit(PKCS7 *, BIO *); -int PKCS7_type_is_encrypted(PKCS7 *); int PKCS7_type_is_signed(PKCS7 *); int PKCS7_type_is_enveloped(PKCS7 *); int PKCS7_type_is_signedAndEnveloped(PKCS7 *); int PKCS7_type_is_data(PKCS7 *); -int PKCS7_type_is_digest(PKCS7 *); """ CUSTOMIZATIONS = "" diff --git a/src/_cffi_src/openssl/rand.py b/src/_cffi_src/openssl/rand.py index 6865392790ee..c0cd68365960 100644 --- a/src/_cffi_src/openssl/rand.py +++ b/src/_cffi_src/openssl/rand.py @@ -9,10 +9,13 @@ """ TYPES = """ +typedef ... RAND_METHOD; + static const long Cryptography_HAS_EGD; """ 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); @@ -21,9 +24,6 @@ 1 we'll just lie about the signature to preserve compatibility for pyOpenSSL (which calls this in its rand.py as of mid-2016) */ void ERR_load_RAND_strings(void); - -/* RAND_cleanup became a macro in 1.1.0 */ -void RAND_cleanup(void); """ CUSTOMIZATIONS = """ diff --git a/src/_cffi_src/openssl/rsa.py b/src/_cffi_src/openssl/rsa.py index 216e633abb79..765498fbc9ef 100644 --- a/src/_cffi_src/openssl/rsa.py +++ b/src/_cffi_src/openssl/rsa.py @@ -25,19 +25,10 @@ FUNCTIONS = """ RSA *RSA_new(void); void RSA_free(RSA *); -int RSA_size(const RSA *); int RSA_generate_key_ex(RSA *, int, BIGNUM *, BN_GENCB *); int RSA_check_key(const RSA *); RSA *RSAPublicKey_dup(RSA *); int RSA_blinding_on(RSA *, BN_CTX *); -int RSA_public_encrypt(int, const unsigned char *, unsigned char *, - RSA *, int); -int RSA_private_encrypt(int, const unsigned char *, unsigned char *, - RSA *, int); -int RSA_public_decrypt(int, const unsigned char *, unsigned char *, - RSA *, int); -int RSA_private_decrypt(int, const unsigned char *, unsigned char *, - RSA *, int); int RSA_print(BIO *, const RSA *, int); /* added in 1.1.0 when the RSA struct was opaqued */ @@ -76,7 +67,7 @@ #endif /* These functions were added in OpenSSL 1.1.0 */ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) { /* If the fields n and e in r are NULL, the corresponding input diff --git a/src/_cffi_src/openssl/src/osrandom_engine.c b/src/_cffi_src/openssl/src/osrandom_engine.c index 697381c853d9..a84857b86df4 100644 --- a/src/_cffi_src/openssl/src/osrandom_engine.c +++ b/src/_cffi_src/openssl/src/osrandom_engine.c @@ -17,6 +17,9 @@ #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"; /**************************************************************************** @@ -94,7 +97,18 @@ static struct { ino_t st_ino; } urandom_cache = { -1 }; -static int set_cloexec(int fd) { +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; @@ -102,7 +116,8 @@ static int set_cloexec(int fd) { if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { return -1; } - return 0; +#endif + return fd; } #ifdef __linux__ @@ -114,13 +129,10 @@ static int set_cloexec(int fd) { static int wait_on_devrandom(void) { struct pollfd pfd = {}; int ret = 0; - int random_fd = open("/dev/random", O_RDONLY); + int random_fd = open_cloexec("/dev/random"); if (random_fd < 0) { return -1; } - if (set_cloexec(random_fd) < 0) { - return -1; - } pfd.fd = random_fd; pfd.events = POLLIN; pfd.revents = 0; @@ -154,13 +166,10 @@ static int dev_urandom_fd(void) { } #endif - fd = open("/dev/urandom", O_RDONLY); + fd = open_cloexec("/dev/urandom"); if (fd < 0) { goto error; } - if (set_cloexec(fd) < 0) { - goto error; - } if (fstat(fd, &st)) { goto error; } @@ -243,7 +252,7 @@ static int osrandom_init(ENGINE *e) { #if !defined(__APPLE__) getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS; #else - if (&getentropy != NULL) { + if (__builtin_available(macOS 10.12, *)) { getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS; } else { getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK; @@ -269,7 +278,11 @@ static int osrandom_rand_bytes(unsigned char *buffer, int size) { while (size > 0) { /* OpenBSD and macOS restrict maximum buffer size to 256. */ len = size > 256 ? 256 : size; +/* on mac, availability is already checked using `__builtin_available` above */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" res = getentropy(buffer, (size_t)len); +#pragma clang diagnostic pop if (res < 0) { ERR_Cryptography_OSRandom_error( CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES, @@ -516,7 +529,7 @@ static int osrandom_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_INVALID_ARGUMENT); return 0; } - strncpy((char *)p, name, len); + strcpy((char *)p, name); return (int)len; default: ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED); @@ -632,3 +645,16 @@ int Cryptography_add_osrandom_engine(void) { 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 index 53f957fa6f18..93d918b88bf5 100644 --- a/src/_cffi_src/openssl/src/osrandom_engine.h +++ b/src/_cffi_src/openssl/src/osrandom_engine.h @@ -1,10 +1,14 @@ +#ifndef OPENSSL_NO_ENGINE +/* OpenSSL has ENGINE support so include all of this. */ #ifdef _WIN32 #include #else #include #include /* for defined(BSD) */ - #include + #ifndef __MVS__ + #include + #endif #ifdef BSD /* for SYS_getentropy */ @@ -24,6 +28,20 @@ #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 */ @@ -97,3 +115,4 @@ static void ERR_Cryptography_OSRandom_error(int function, int reason, #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/_cffi_src/openssl/ssl.py b/src/_cffi_src/openssl/ssl.py index 2218095cca9b..c38e309a1835 100644 --- a/src/_cffi_src/openssl/ssl.py +++ b/src/_cffi_src/openssl/ssl.py @@ -19,18 +19,16 @@ static const long Cryptography_HAS_TLSv1_2; static const long Cryptography_HAS_TLSv1_3; static const long Cryptography_HAS_SECURE_RENEGOTIATION; -static const long Cryptography_HAS_COMPRESSION; static const long Cryptography_HAS_TLSEXT_STATUS_REQ_CB; static const long Cryptography_HAS_STATUS_REQ_OCSP_RESP; static const long Cryptography_HAS_TLSEXT_STATUS_REQ_TYPE; -static const long Cryptography_HAS_GET_SERVER_TMP_KEY; -static const long Cryptography_HAS_SSL_CTX_SET_CLIENT_CERT_ENGINE; static const long Cryptography_HAS_SSL_CTX_CLEAR_OPTIONS; static const long Cryptography_HAS_DTLS; -static const long Cryptography_HAS_GENERIC_DTLS_METHOD; static const long Cryptography_HAS_SIGALGS; static const long Cryptography_HAS_PSK; static const long Cryptography_HAS_CIPHER_DETAILS; +static const long Cryptography_HAS_VERIFIED_CHAIN; +static const long Cryptography_HAS_KEYLOG; /* Internally invented symbol to tell us if SNI is supported */ static const long Cryptography_HAS_TLSEXT_HOSTNAME; @@ -51,6 +49,7 @@ static const long Cryptography_HAS_NEXTPROTONEG; static const long Cryptography_HAS_SET_CERT_CB; static const long Cryptography_HAS_CUSTOM_EXT; +static const long Cryptography_HAS_SRTP; static const long SSL_FILETYPE_PEM; static const long SSL_FILETYPE_ASN1; @@ -139,8 +138,6 @@ static const long TLS_ST_BEFORE; static const long TLS_ST_OK; -static const long OPENSSL_NPN_NEGOTIATED; - typedef ... SSL_METHOD; typedef ... SSL_CTX; @@ -153,7 +150,6 @@ typedef ... SSL_CIPHER; typedef ... Cryptography_STACK_OF_SSL_CIPHER; -typedef ... COMP_METHOD; typedef struct { const char *name; @@ -166,20 +162,10 @@ const char *SSL_state_string_long(const SSL *); SSL_SESSION *SSL_get1_session(SSL *); int SSL_set_session(SSL *, SSL_SESSION *); -int SSL_get_verify_mode(const SSL *); -void SSL_set_verify(SSL *, int, int (*)(int, X509_STORE_CTX *)); -void SSL_set_verify_depth(SSL *, int); -int SSL_get_verify_depth(const SSL *); -int (*SSL_get_verify_callback(const SSL *))(int, X509_STORE_CTX *); -void SSL_set_info_callback(SSL *ssl, void (*)(const SSL *, int, int)); -void (*SSL_get_info_callback(const SSL *))(const SSL *, int, int); SSL *SSL_new(SSL_CTX *); void SSL_free(SSL *); int SSL_set_fd(SSL *, int); -SSL_CTX *SSL_get_SSL_CTX(const SSL *); SSL_CTX *SSL_set_SSL_CTX(SSL *, SSL_CTX *); -BIO *SSL_get_rbio(const SSL *); -BIO *SSL_get_wbio(const SSL *); void SSL_set_bio(SSL *, BIO *, BIO *); void SSL_set_connect_state(SSL *); void SSL_set_accept_state(SSL *); @@ -195,28 +181,22 @@ /* Added in 1.0.2 */ X509_VERIFY_PARAM *SSL_get0_param(SSL *); - -int SSL_use_certificate(SSL *, X509 *); -int SSL_use_certificate_ASN1(SSL *, const unsigned char *, int); -int SSL_use_certificate_file(SSL *, const char *, int); -int SSL_use_PrivateKey(SSL *, EVP_PKEY *); -int SSL_use_PrivateKey_ASN1(int, SSL *, const unsigned char *, long); -int SSL_use_PrivateKey_file(SSL *, const char *, int); -int SSL_check_private_key(const SSL *); +X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *); int SSL_get_sigalgs(SSL *, int, int *, int *, int *, unsigned char *, unsigned char *); Cryptography_STACK_OF_X509 *SSL_get_peer_cert_chain(const SSL *); +Cryptography_STACK_OF_X509 *SSL_get0_verified_chain(const SSL *); Cryptography_STACK_OF_X509_NAME *SSL_get_client_CA_list(const SSL *); int SSL_get_error(const SSL *, int); +long SSL_get_verify_result(const SSL *ssl); int SSL_do_handshake(SSL *); int SSL_shutdown(SSL *); int SSL_renegotiate(SSL *); int SSL_renegotiate_pending(SSL *); const char *SSL_get_cipher_list(const SSL *, int); -Cryptography_STACK_OF_SSL_CIPHER *SSL_get_ciphers(const SSL *); /* context */ void SSL_CTX_free(SSL_CTX *); @@ -224,7 +204,6 @@ int SSL_CTX_set_default_verify_paths(SSL_CTX *); void SSL_CTX_set_verify(SSL_CTX *, int, int (*)(int, X509_STORE_CTX *)); void SSL_CTX_set_verify_depth(SSL_CTX *, int); -int (*SSL_CTX_get_verify_callback(const SSL_CTX *))(int, X509_STORE_CTX *); int SSL_CTX_get_verify_mode(const SSL_CTX *); int SSL_CTX_get_verify_depth(const SSL_CTX *); int SSL_CTX_set_cipher_list(SSL_CTX *, const char *); @@ -232,11 +211,9 @@ void SSL_CTX_set_default_passwd_cb(SSL_CTX *, pem_password_cb *); void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *, void *); int SSL_CTX_use_certificate(SSL_CTX *, X509 *); -int SSL_CTX_use_certificate_ASN1(SSL_CTX *, int, const unsigned char *); int SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int); int SSL_CTX_use_certificate_chain_file(SSL_CTX *, const char *); int SSL_CTX_use_PrivateKey(SSL_CTX *, EVP_PKEY *); -int SSL_CTX_use_PrivateKey_ASN1(int, SSL_CTX *, const unsigned char *, long); int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int); int SSL_CTX_check_private_key(const SSL_CTX *); void SSL_CTX_set_cert_verify_callback(SSL_CTX *, @@ -282,6 +259,10 @@ void SSL_CTX_set_info_callback(SSL_CTX *, void (*)(const SSL *, int, int)); void (*SSL_CTX_get_info_callback(SSL_CTX *))(const SSL *, int, int); +void SSL_CTX_set_keylog_callback(SSL_CTX *, + void (*)(const SSL *, const char *)); +void (*SSL_CTX_get_keylog_callback(SSL_CTX *))(const SSL *, const char *); + long SSL_CTX_set1_sigalgs_list(SSL_CTX *, const char *); /* SSL_SESSION */ @@ -326,26 +307,13 @@ int SSL_SESSION_has_ticket(const SSL_SESSION *); long SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *); -/* not a macro, but older OpenSSLs don't pass the args as const */ -char *SSL_CIPHER_description(const SSL_CIPHER *, char *, int); -int SSL_SESSION_print(BIO *, const SSL_SESSION *); - -/* not macros, but will be conditionally bound so can't live in functions */ -const COMP_METHOD *SSL_get_current_compression(SSL *); -const COMP_METHOD *SSL_get_current_expansion(SSL *); -const char *SSL_COMP_get_name(const COMP_METHOD *); -int SSL_CTX_set_client_cert_engine(SSL_CTX *, ENGINE *); - unsigned long SSL_set_mode(SSL *, unsigned long); +unsigned long SSL_clear_mode(SSL *, unsigned long); unsigned long SSL_get_mode(SSL *); unsigned long SSL_set_options(SSL *, unsigned long); unsigned long SSL_get_options(SSL *); -void SSL_set_app_data(SSL *, char *); -char * SSL_get_app_data(SSL *); -void SSL_set_read_ahead(SSL *, int); - int SSL_want_read(const SSL *); int SSL_want_write(const SSL *); @@ -358,6 +326,7 @@ unsigned long SSL_CTX_clear_options(SSL_CTX *, unsigned long); unsigned long SSL_CTX_get_options(SSL_CTX *); unsigned long SSL_CTX_set_mode(SSL_CTX *, unsigned long); +unsigned long SSL_CTX_clear_mode(SSL_CTX *, unsigned long); unsigned long SSL_CTX_get_mode(SSL_CTX *); unsigned long SSL_CTX_set_session_cache_mode(SSL_CTX *, unsigned long); unsigned long SSL_CTX_get_session_cache_mode(SSL_CTX *); @@ -432,25 +401,9 @@ long SSL_session_reused(SSL *); -void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *, - int (*)(SSL *, - const unsigned char **, - unsigned int *, - void *), - void *); -void SSL_CTX_set_next_proto_select_cb(SSL_CTX *, - int (*)(SSL *, - unsigned char **, - unsigned char *, - const unsigned char *, - unsigned int, - void *), - void *); int SSL_select_next_proto(unsigned char **, unsigned char *, const unsigned char *, unsigned int, const unsigned char *, unsigned int); -void SSL_get0_next_proto_negotiated(const SSL *, - const unsigned char **, unsigned *); int sk_SSL_CIPHER_num(Cryptography_STACK_OF_SSL_CIPHER *); const SSL_CIPHER *sk_SSL_CIPHER_value(Cryptography_STACK_OF_SSL_CIPHER *, int); @@ -478,9 +431,6 @@ void SSL_CTX_set_cert_cb(SSL_CTX *, int (*)(SSL *, void *), void *); void SSL_set_cert_cb(SSL *, int (*)(SSL *, void *), void *); -/* Added in 1.0.2 */ -const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *); - int SSL_SESSION_set1_id_context(SSL_SESSION *, const unsigned char *, unsigned int); /* Added in 1.1.0 for the great opaquing of structs */ @@ -551,18 +501,29 @@ """ CUSTOMIZATIONS = """ -/* Added in 1.0.2 but we need it in all versions now due to the great - opaquing. */ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 -/* from ssl/ssl_lib.c */ -const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx) { - return ctx->method; -} +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 +static const long Cryptography_HAS_VERIFIED_CHAIN = 0; +Cryptography_STACK_OF_X509 *(*SSL_get0_verified_chain)(const SSL *) = NULL; +#else +static const long Cryptography_HAS_VERIFIED_CHAIN = 1; +#endif + +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 +static const long Cryptography_HAS_KEYLOG = 0; +void (*SSL_CTX_set_keylog_callback)(SSL_CTX *, + void (*) (const SSL *, const char *) + ) = NULL; +void (*(*SSL_CTX_get_keylog_callback)(SSL_CTX *))( + const SSL *, + const char * + ) = NULL; +#else +static const long Cryptography_HAS_KEYLOG = 1; #endif /* Added in 1.1.0 in the great opaquing, but we need to define it for older OpenSSLs. Such is our burden. */ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL /* from ssl/ssl_lib.c */ size_t SSL_get_client_random(const SSL *ssl, unsigned char *out, size_t outlen) { @@ -640,38 +601,10 @@ static const long Cryptography_HAS_SSL_OP_MSIE_SSLV2_RSA_PADDING = 1; static const long Cryptography_HAS_SSL_OP_NO_TICKET = 1; static const long Cryptography_HAS_SSL_SET_SSL_CTX = 1; -static const long Cryptography_HAS_NEXTPROTONEG = 1; - -/* SSL_get0_param was added in OpenSSL 1.0.2. */ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER -X509_VERIFY_PARAM *(*SSL_get0_param)(SSL *) = NULL; -#else -#endif - -/* ALPN was added in OpenSSL 1.0.2. */ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 && !CRYPTOGRAPHY_IS_LIBRESSL -int (*SSL_CTX_set_alpn_protos)(SSL_CTX *, - const unsigned char *, - unsigned) = NULL; -int (*SSL_set_alpn_protos)(SSL *, const unsigned char *, unsigned) = NULL; -void (*SSL_CTX_set_alpn_select_cb)(SSL_CTX *, - int (*) (SSL *, - const unsigned char **, - unsigned char *, - const unsigned char *, - unsigned int, - void *), - void *) = NULL; -void (*SSL_get0_alpn_selected)(const SSL *, - const unsigned char **, - unsigned *) = NULL; -static const long Cryptography_HAS_ALPN = 0; -#else +static const long Cryptography_HAS_NEXTPROTONEG = 0; static const long Cryptography_HAS_ALPN = 1; -#endif -/* SSL_CTX_set_cert_cb was added in OpenSSL 1.0.2. */ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 +#if CRYPTOGRAPHY_IS_LIBRESSL void (*SSL_CTX_set_cert_cb)(SSL_CTX *, int (*)(SSL *, void *), void *) = NULL; void (*SSL_set_cert_cb)(SSL *, int (*)(SSL *, void *), void *) = NULL; static const long Cryptography_HAS_SET_CERT_CB = 0; @@ -679,26 +612,6 @@ static const long Cryptography_HAS_SET_CERT_CB = 1; #endif - -/* In OpenSSL 1.0.2i+ the handling of COMP_METHOD when OPENSSL_NO_COMP was - changed and we no longer need to typedef void */ -#if (defined(OPENSSL_NO_COMP) && CRYPTOGRAPHY_OPENSSL_LESS_THAN_102I) || \ - CRYPTOGRAPHY_IS_LIBRESSL -static const long Cryptography_HAS_COMPRESSION = 0; -typedef void COMP_METHOD; -#else -static const long Cryptography_HAS_COMPRESSION = 1; -#endif - -#if defined(SSL_CTRL_GET_SERVER_TMP_KEY) -static const long Cryptography_HAS_GET_SERVER_TMP_KEY = 1; -#else -static const long Cryptography_HAS_GET_SERVER_TMP_KEY = 0; -long (*SSL_get_server_tmp_key)(SSL *, EVP_PKEY **) = NULL; -#endif - -static const long Cryptography_HAS_SSL_CTX_SET_CLIENT_CERT_ENGINE = 1; - static const long Cryptography_HAS_SSL_CTX_CLEAR_OPTIONS = 1; /* in OpenSSL 1.1.0 the SSL_ST values were renamed to TLS_ST and several were @@ -720,17 +633,11 @@ static const long TLS_ST_OK = 0; #endif -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 -static const long Cryptography_HAS_GENERIC_DTLS_METHOD = 0; -const SSL_METHOD *(*DTLS_method)(void) = NULL; -const SSL_METHOD *(*DTLS_server_method)(void) = NULL; -const SSL_METHOD *(*DTLS_client_method)(void) = NULL; +#if CRYPTOGRAPHY_IS_LIBRESSL static const long SSL_OP_NO_DTLSv1 = 0; static const long SSL_OP_NO_DTLSv1_2 = 0; long (*DTLS_set_link_mtu)(SSL *, long) = NULL; long (*DTLS_get_link_min_mtu)(SSL *) = NULL; -#else -static const long Cryptography_HAS_GENERIC_DTLS_METHOD = 1; #endif static const long Cryptography_HAS_DTLS = 1; @@ -753,7 +660,7 @@ return r; } -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 +#if CRYPTOGRAPHY_IS_LIBRESSL static const long Cryptography_HAS_SIGALGS = 0; const int (*SSL_get_sigalgs)(SSL *, int, int *, int *, int *, unsigned char *, unsigned char *) = NULL; @@ -785,45 +692,44 @@ static const long Cryptography_HAS_PSK = 1; #endif -/* - * Custom extensions were added in 1.0.2. 1.1.1 is adding a more general - * SSL_CTX_add_custom_ext function, but we're not binding that yet. - */ -#if CRYPTOGRAPHY_OPENSSL_102_OR_GREATER +#if !CRYPTOGRAPHY_IS_LIBRESSL static const long Cryptography_HAS_CUSTOM_EXT = 1; #else static const long Cryptography_HAS_CUSTOM_EXT = 0; - typedef int (*custom_ext_add_cb)(SSL *, unsigned int, const unsigned char **, size_t *, int *, void *); - typedef void (*custom_ext_free_cb)(SSL *, unsigned int, const unsigned char *, void *); - typedef int (*custom_ext_parse_cb)(SSL *, unsigned int, const unsigned char *, size_t, int *, void *); - int (*SSL_CTX_add_client_custom_ext)(SSL_CTX *, unsigned int, custom_ext_add_cb, custom_ext_free_cb, void *, custom_ext_parse_cb, void *) = NULL; - int (*SSL_CTX_add_server_custom_ext)(SSL_CTX *, unsigned int, custom_ext_add_cb, custom_ext_free_cb, void *, custom_ext_parse_cb, void *) = NULL; - int (*SSL_extension_supported)(unsigned int) = NULL; #endif -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER +#ifndef OPENSSL_NO_SRTP +static const long Cryptography_HAS_SRTP = 1; +#else +static const long Cryptography_HAS_SRTP = 0; +int (*SSL_CTX_set_tlsext_use_srtp)(SSL_CTX *, const char *) = NULL; +int (*SSL_set_tlsext_use_srtp)(SSL *, const char *) = NULL; +SRTP_PROTECTION_PROFILE * (*SSL_get_selected_srtp_profile)(SSL *) = NULL; +#endif + +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL int (*SSL_CIPHER_is_aead)(const SSL_CIPHER *) = NULL; int (*SSL_CIPHER_get_cipher_nid)(const SSL_CIPHER *) = NULL; int (*SSL_CIPHER_get_digest_nid)(const SSL_CIPHER *) = NULL; diff --git a/src/_cffi_src/openssl/x509.py b/src/_cffi_src/openssl/x509.py index 748c6c8c72d0..b88daa1f213d 100644 --- a/src/_cffi_src/openssl/x509.py +++ b/src/_cffi_src/openssl/x509.py @@ -30,13 +30,10 @@ } X509_ALGOR; typedef ... X509_ATTRIBUTE; -typedef ... X509_CINF; typedef ... X509_EXTENSION; typedef ... X509_EXTENSIONS; typedef ... X509_REQ; -typedef ... X509_REQ_INFO; typedef ... X509_REVOKED; -typedef ... X509_CRL_INFO; typedef ... X509_CRL; typedef ... X509; @@ -44,39 +41,6 @@ typedef ... PKCS8_PRIV_KEY_INFO; -static const int X509_FLAG_COMPAT; -static const int X509_FLAG_NO_HEADER; -static const int X509_FLAG_NO_VERSION; -static const int X509_FLAG_NO_SERIAL; -static const int X509_FLAG_NO_SIGNAME; -static const int X509_FLAG_NO_ISSUER; -static const int X509_FLAG_NO_VALIDITY; -static const int X509_FLAG_NO_SUBJECT; -static const int X509_FLAG_NO_PUBKEY; -static const int X509_FLAG_NO_EXTENSIONS; -static const int X509_FLAG_NO_SIGDUMP; -static const int X509_FLAG_NO_AUX; -static const int X509_FLAG_NO_ATTRIBUTES; - -static const int XN_FLAG_SEP_MASK; -static const int XN_FLAG_COMPAT; -static const int XN_FLAG_SEP_COMMA_PLUS; -static const int XN_FLAG_SEP_CPLUS_SPC; -static const int XN_FLAG_SEP_SPLUS_SPC; -static const int XN_FLAG_SEP_MULTILINE; -static const int XN_FLAG_DN_REV; -static const int XN_FLAG_FN_MASK; -static const int XN_FLAG_FN_SN; -static const int XN_FLAG_FN_LN; -static const int XN_FLAG_FN_OID; -static const int XN_FLAG_FN_NONE; -static const int XN_FLAG_SPC_EQ; -static const int XN_FLAG_DUMP_UNKNOWN_FIELDS; -static const int XN_FLAG_FN_ALIGN; -static const int XN_FLAG_RFC2253; -static const int XN_FLAG_ONELINE; -static const int XN_FLAG_MULTILINE; - typedef void (*sk_X509_EXTENSION_freefunc)(X509_EXTENSION *); """ @@ -108,14 +72,11 @@ int X509_set_issuer_name(X509 *, X509_NAME *); int X509_add_ext(X509 *, X509_EXTENSION *, int); -X509_EXTENSION *X509_delete_ext(X509 *, int); X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *); ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *); void X509_EXTENSION_free(X509_EXTENSION *); -int i2d_X509(X509 *, unsigned char **); - int X509_REQ_set_version(X509_REQ *, long); X509_REQ *X509_REQ_new(void); void X509_REQ_free(X509_REQ *); @@ -123,13 +84,17 @@ int X509_REQ_set_subject_name(X509_REQ *, X509_NAME *); int X509_REQ_sign(X509_REQ *, EVP_PKEY *, const EVP_MD *); int X509_REQ_verify(X509_REQ *, EVP_PKEY *); -int X509_REQ_digest(const X509_REQ *, const EVP_MD *, - unsigned char *, unsigned int *); EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *); -int X509_REQ_print(BIO *, X509_REQ *); int X509_REQ_print_ex(BIO *, X509_REQ *, unsigned long, unsigned long); int X509_REQ_add_extensions(X509_REQ *, X509_EXTENSIONS *); X509_EXTENSIONS *X509_REQ_get_extensions(X509_REQ *); +X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *, int); +int X509_REQ_get_attr_by_OBJ(const X509_REQ *, const ASN1_OBJECT *, int); +void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *, int, int, void *); +ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *, int); +int X509_ATTRIBUTE_count(const X509_ATTRIBUTE *); +int X509_REQ_add1_attr_by_OBJ(X509_REQ *, const ASN1_OBJECT *, + int, const unsigned char *, int); int X509V3_EXT_print(BIO *, X509_EXTENSION *, unsigned long, int); ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *); @@ -186,40 +151,19 @@ const char *X509_verify_cert_error_string(long); -const char *X509_get_default_cert_area(void); const char *X509_get_default_cert_dir(void); const char *X509_get_default_cert_file(void); const char *X509_get_default_cert_dir_env(void); const char *X509_get_default_cert_file_env(void); -const char *X509_get_default_private_dir(void); - -int i2d_RSA_PUBKEY(RSA *, unsigned char **); -RSA *d2i_RSA_PUBKEY(RSA **, const unsigned char **, long); -RSA *d2i_RSAPublicKey(RSA **, const unsigned char **, long); -RSA *d2i_RSAPrivateKey(RSA **, const unsigned char **, long); -int i2d_DSA_PUBKEY(DSA *, unsigned char **); -DSA *d2i_DSA_PUBKEY(DSA **, const unsigned char **, long); -DSA *d2i_DSAPublicKey(DSA **, const unsigned char **, long); -DSA *d2i_DSAPrivateKey(DSA **, const unsigned char **, long); - -RSA *d2i_RSAPrivateKey_bio(BIO *, RSA **); + int i2d_RSAPrivateKey_bio(BIO *, RSA *); RSA *d2i_RSAPublicKey_bio(BIO *, RSA **); int i2d_RSAPublicKey_bio(BIO *, RSA *); -RSA *d2i_RSA_PUBKEY_bio(BIO *, RSA **); -int i2d_RSA_PUBKEY_bio(BIO *, RSA *); -DSA *d2i_DSA_PUBKEY_bio(BIO *, DSA **); -int i2d_DSA_PUBKEY_bio(BIO *, DSA *); -DSA *d2i_DSAPrivateKey_bio(BIO *, DSA **); int i2d_DSAPrivateKey_bio(BIO *, DSA *); -PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *, - PKCS8_PRIV_KEY_INFO **); -void PKCS8_PRIV_KEY_INFO_free(PKCS8_PRIV_KEY_INFO *); /* These became const X509 in 1.1.0 */ int X509_get_ext_count(X509 *); X509_EXTENSION *X509_get_ext(X509 *, int); -int X509_get_ext_by_NID(X509 *, int, int); X509_NAME *X509_get_subject_name(X509 *); X509_NAME *X509_get_issuer_name(X509 *); @@ -242,18 +186,9 @@ int X509_CRL_get0_by_serial(X509_CRL *, X509_REVOKED **, ASN1_INTEGER *); -/* these CRYPTO_EX_DATA functions became macros in 1.1.0 */ -int X509_get_ex_new_index(long, void *, CRYPTO_EX_new *, CRYPTO_EX_dup *, - CRYPTO_EX_free *); -int X509_set_ex_data(X509 *, int, void *); -void *X509_get_ex_data(X509 *, int); - +X509_REVOKED *X509_REVOKED_dup(X509_REVOKED *); X509_REVOKED *Cryptography_X509_REVOKED_dup(X509_REVOKED *); -int i2d_X509_CINF(X509_CINF *, unsigned char **); -int i2d_X509_CRL_INFO(X509_CRL_INFO *, unsigned char **); -int i2d_X509_REQ_INFO(X509_REQ_INFO *, unsigned char **); - /* new in 1.0.2 */ int i2d_re_X509_tbs(X509 *, unsigned char **); int X509_get_signature_nid(const X509 *); @@ -267,6 +202,8 @@ ASN1_TIME *X509_get_notBefore(X509 *); ASN1_TIME *X509_get_notAfter(X509 *); +ASN1_TIME *X509_getm_notBefore(X509 *); +ASN1_TIME *X509_getm_notAfter(X509 *); long X509_REQ_get_version(X509_REQ *); X509_NAME *X509_REQ_get_subject_name(X509_REQ *); @@ -295,11 +232,6 @@ int sk_X509_CRL_push(Cryptography_STACK_OF_X509_CRL *, X509_CRL *); X509_CRL *sk_X509_CRL_value(Cryptography_STACK_OF_X509_CRL *, int); -int i2d_RSAPublicKey(RSA *, unsigned char **); -int i2d_RSAPrivateKey(RSA *, unsigned char **); -int i2d_DSAPublicKey(DSA *, unsigned char **); -int i2d_DSAPrivateKey(DSA *, unsigned char **); - long X509_CRL_get_version(X509_CRL *); ASN1_TIME *X509_CRL_get_lastUpdate(X509_CRL *); ASN1_TIME *X509_CRL_get_nextUpdate(X509_CRL *); @@ -311,19 +243,14 @@ int X509_CRL_set_nextUpdate(X509_CRL *, ASN1_TIME *); int X509_set_notBefore(X509 *, ASN1_TIME *); int X509_set_notAfter(X509 *, ASN1_TIME *); +int X509_set1_notBefore(X509 *, ASN1_TIME *); +int X509_set1_notAfter(X509 *, ASN1_TIME *); -int i2d_EC_PUBKEY(EC_KEY *, unsigned char **); -EC_KEY *d2i_EC_PUBKEY(EC_KEY **, const unsigned char **, long); EC_KEY *d2i_EC_PUBKEY_bio(BIO *, EC_KEY **); int i2d_EC_PUBKEY_bio(BIO *, EC_KEY *); -EC_KEY *d2i_ECPrivateKey(EC_KEY **, const unsigned char **, long); EC_KEY *d2i_ECPrivateKey_bio(BIO *, EC_KEY **); -int i2d_ECPrivateKey(EC_KEY *, unsigned char **); int i2d_ECPrivateKey_bio(BIO *, EC_KEY *); -EC_KEY *o2i_ECPublicKey(EC_KEY **, const unsigned char **, long); -int i2o_ECPublicKey(EC_KEY *, unsigned char **); - // declared in safestack int sk_ASN1_OBJECT_num(Cryptography_STACK_OF_ASN1_OBJECT *); ASN1_OBJECT *sk_ASN1_OBJECT_value(Cryptography_STACK_OF_ASN1_OBJECT *, int); @@ -343,30 +270,7 @@ """ CUSTOMIZATIONS = """ -/* Added in 1.0.2 beta but we need it in all versions now due to the great - opaquing. */ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER -/* from x509/x_x509.c version 1.0.2 */ -void X509_get0_signature(const ASN1_BIT_STRING **psig, - const X509_ALGOR **palg, const X509 *x) -{ - if (psig) - *psig = x->signature; - if (palg) - *palg = x->sig_alg; -} - -int X509_get_signature_nid(const X509 *x) -{ - return OBJ_obj2nid(x->sig_alg->algorithm); -} - -#endif - -/* Added in 1.0.2 but we need it in all versions now due to the great - opaquing. */ -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 -/* from x509/x_x509.c */ +#if CRYPTOGRAPHY_IS_LIBRESSL int i2d_re_X509_tbs(X509 *x, unsigned char **pp) { /* in 1.0.2+ this function also sets x->cert_info->enc.modified = 1 @@ -378,17 +282,10 @@ } #endif -/* X509_REVOKED_dup only exists on 1.0.2+. It is implemented using - IMPLEMENT_ASN1_DUP_FUNCTION. The below is the equivalent so we have - it available on all OpenSSLs. */ +/* Being kept around for pyOpenSSL */ X509_REVOKED *Cryptography_X509_REVOKED_dup(X509_REVOKED *rev) { -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 - return ASN1_item_dup(ASN1_ITEM_rptr(X509_REVOKED), rev); -#else return X509_REVOKED_dup(rev); -#endif } - /* Added in 1.1.0 but we need it in all versions now due to the great opaquing. */ #if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 @@ -402,7 +299,7 @@ return i2d_X509_CRL_INFO(crl->crl, pp); } -#if !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER +#if !CRYPTOGRAPHY_IS_LIBRESSL int X509_up_ref(X509 *x) { return CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); } @@ -437,6 +334,11 @@ { return x->serialNumber; } + +#define X509_set1_notBefore X509_set_notBefore +#define X509_set1_notAfter X509_set_notAfter +#define X509_getm_notAfter X509_get_notAfter +#define X509_getm_notBefore X509_get_notBefore #endif #endif """ diff --git a/src/_cffi_src/openssl/x509_vfy.py b/src/_cffi_src/openssl/x509_vfy.py index 42da3b1e1132..d2bc5f4ec6e1 100644 --- a/src/_cffi_src/openssl/x509_vfy.py +++ b/src/_cffi_src/openssl/x509_vfy.py @@ -19,11 +19,8 @@ """ TYPES = """ -static const long Cryptography_HAS_102_VERIFICATION_ERROR_CODES; -static const long Cryptography_HAS_102_VERIFICATION_PARAMS; +static const long Cryptography_HAS_102_VERIFICATION; static const long Cryptography_HAS_110_VERIFICATION_PARAMS; -static const long Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST; -static const long Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN; static const long Cryptography_HAS_X509_STORE_CTX_GET_ISSUER; typedef ... Cryptography_STACK_OF_ASN1_OBJECT; @@ -222,64 +219,19 @@ """ CUSTOMIZATIONS = """ -/* OpenSSL 1.0.2+ verification parameters and error codes */ -#if CRYPTOGRAPHY_OPENSSL_102_OR_GREATER -static const long Cryptography_HAS_102_VERIFICATION_ERROR_CODES = 1; -static const long Cryptography_HAS_102_VERIFICATION_PARAMS = 1; +#if !CRYPTOGRAPHY_IS_LIBRESSL +static const long Cryptography_HAS_102_VERIFICATION = 1; #else -static const long Cryptography_HAS_102_VERIFICATION_ERROR_CODES = 0; -static const long Cryptography_HAS_102_VERIFICATION_PARAMS = 0; - +static const long Cryptography_HAS_102_VERIFICATION = 0; static const long X509_V_ERR_SUITE_B_INVALID_VERSION = 0; static const long X509_V_ERR_SUITE_B_INVALID_ALGORITHM = 0; static const long X509_V_ERR_SUITE_B_INVALID_CURVE = 0; static const long X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM = 0; static const long X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED = 0; static const long X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 = 0; -/* These 3 defines are unavailable in LibreSSL 2.5.x, but may be added - in the future... */ -#ifndef X509_V_ERR_HOSTNAME_MISMATCH -static const long X509_V_ERR_HOSTNAME_MISMATCH = 0; -#endif -#ifndef X509_V_ERR_EMAIL_MISMATCH -static const long X509_V_ERR_EMAIL_MISMATCH = 0; -#endif -#ifndef X509_V_ERR_IP_ADDRESS_MISMATCH -static const long X509_V_ERR_IP_ADDRESS_MISMATCH = 0; -#endif -#ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT -static const long X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT = 0; -#endif -#ifndef X509_CHECK_FLAG_NO_WILDCARDS -static const long X509_CHECK_FLAG_NO_WILDCARDS = 0; -#endif -#ifndef X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS -static const long X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS = 0; -#endif -#ifndef X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS -static const long X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS = 0; -#endif -#ifndef X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS -static const long X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS = 0; -#endif - -/* X509_V_FLAG_TRUSTED_FIRST is also new in 1.0.2+, but it is added separately - below because it shows up in some earlier 3rd party OpenSSL packages. */ static const long X509_V_FLAG_SUITEB_128_LOS_ONLY = 0; static const long X509_V_FLAG_SUITEB_192_LOS = 0; static const long X509_V_FLAG_SUITEB_128_LOS = 0; - -#if !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER -int (*X509_VERIFY_PARAM_set1_host)(X509_VERIFY_PARAM *, const char *, - size_t) = NULL; -int (*X509_VERIFY_PARAM_set1_email)(X509_VERIFY_PARAM *, const char *, - size_t) = NULL; -int (*X509_VERIFY_PARAM_set1_ip)(X509_VERIFY_PARAM *, const unsigned char *, - size_t) = NULL; -int (*X509_VERIFY_PARAM_set1_ip_asc)(X509_VERIFY_PARAM *, const char *) = NULL; -void (*X509_VERIFY_PARAM_set_hostflags)(X509_VERIFY_PARAM *, - unsigned int) = NULL; -#endif #endif #if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 || CRYPTOGRAPHY_IS_LIBRESSL @@ -291,23 +243,7 @@ static const long Cryptography_HAS_110_VERIFICATION_PARAMS = 1; #endif -/* OpenSSL 1.0.2+ or Solaris's backport */ -#ifdef X509_V_FLAG_PARTIAL_CHAIN -static const long Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN = 1; -#else -static const long Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN = 0; -static const long X509_V_FLAG_PARTIAL_CHAIN = 0; -#endif - -/* OpenSSL 1.0.2+, *or* Fedora 20's flavor of OpenSSL 1.0.1e... */ -#ifdef X509_V_FLAG_TRUSTED_FIRST -static const long Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST = 1; -#else -static const long Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST = 0; -static const long X509_V_FLAG_TRUSTED_FIRST = 0; -#endif - -#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_LIBRESSL_27_OR_GREATER +#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL Cryptography_STACK_OF_X509_OBJECT *X509_STORE_get0_objects(X509_STORE *ctx) { return ctx->objs; } diff --git a/src/_cffi_src/openssl/x509v3.py b/src/_cffi_src/openssl/x509v3.py index 193d2e233bde..59681206524b 100644 --- a/src/_cffi_src/openssl/x509v3.py +++ b/src/_cffi_src/openssl/x509v3.py @@ -177,6 +177,7 @@ typedef void (*sk_GENERAL_NAME_freefunc)(GENERAL_NAME *); typedef void (*sk_DIST_POINT_freefunc)(DIST_POINT *); typedef void (*sk_POLICYINFO_freefunc)(POLICYINFO *); +typedef void (*sk_ACCESS_DESCRIPTION_freefunc)(ACCESS_DESCRIPTION *); """ @@ -228,6 +229,8 @@ Cryptography_STACK_OF_ACCESS_DESCRIPTION *, int ); void sk_ACCESS_DESCRIPTION_free(Cryptography_STACK_OF_ACCESS_DESCRIPTION *); +void sk_ACCESS_DESCRIPTION_pop_free(Cryptography_STACK_OF_ACCESS_DESCRIPTION *, + sk_ACCESS_DESCRIPTION_freefunc); int sk_ACCESS_DESCRIPTION_push(Cryptography_STACK_OF_ACCESS_DESCRIPTION *, ACCESS_DESCRIPTION *); diff --git a/src/_cffi_src/utils.py b/src/_cffi_src/utils.py index d3dd18a4ea91..56745a3e5b2e 100644 --- a/src/_cffi_src/utils.py +++ b/src/_cffi_src/utils.py @@ -4,6 +4,7 @@ from __future__ import absolute_import, division, print_function +import os import sys from distutils.ccompiler import new_compiler from distutils.dist import Distribution @@ -11,8 +12,21 @@ from cffi import FFI -def build_ffi_for_binding(module_name, module_prefix, modules, libraries=[], - extra_compile_args=[], extra_link_args=[]): +# Load the cryptography __about__ to get the current package version +base_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +about = {} +with open(os.path.join(base_src, "cryptography", "__about__.py")) as f: + exec (f.read(), about) + + +def build_ffi_for_binding( + module_name, + module_prefix, + modules, + libraries=[], + extra_compile_args=[], + extra_link_args=[], +): """ Modules listed in ``modules`` should have the following attributes: @@ -36,10 +50,7 @@ def build_ffi_for_binding(module_name, module_prefix, modules, libraries=[], includes.append(module.INCLUDES) customizations.append(module.CUSTOMIZATIONS) - verify_source = "\n".join( - includes + - customizations - ) + verify_source = "\n".join(includes + customizations) ffi = build_ffi( module_name, cdef_source="\n".join(types + functions), @@ -52,9 +63,20 @@ def build_ffi_for_binding(module_name, module_prefix, modules, libraries=[], return ffi -def build_ffi(module_name, cdef_source, verify_source, libraries=[], - extra_compile_args=[], extra_link_args=[]): +def build_ffi( + module_name, + cdef_source, + verify_source, + libraries=[], + extra_compile_args=[], + extra_link_args=[], +): ffi = FFI() + # Always add the CRYPTOGRAPHY_PACKAGE_VERSION to the shared object + cdef_source += "\nstatic const char *const CRYPTOGRAPHY_PACKAGE_VERSION;" + verify_source += '\n#define CRYPTOGRAPHY_PACKAGE_VERSION "{}"'.format( + about["__version__"] + ) ffi.cdef(cdef_source) ffi.set_source( module_name, @@ -67,10 +89,10 @@ def build_ffi(module_name, cdef_source, verify_source, libraries=[], def extra_link_args(compiler_type): - if compiler_type == 'msvc': + if compiler_type == "msvc": # Enable NX and ASLR for Windows builds on MSVC. These are enabled by # default on Python 3.3+ but not on 2.x. - return ['/NXCOMPAT', '/DYNAMICBASE'] + return ["/NXCOMPAT", "/DYNAMICBASE"] else: return [] @@ -82,7 +104,7 @@ def compiler_type(): """ dist = Distribution() dist.parse_config_files() - cmd = dist.get_command_obj('build') + cmd = dist.get_command_obj("build") cmd.ensure_finalized() compiler = new_compiler(compiler=cmd.compiler) return compiler.compiler_type diff --git a/src/cryptography/__about__.py b/src/cryptography/__about__.py index 02f81f6e8ed1..b960f7ed1af5 100644 --- a/src/cryptography/__about__.py +++ b/src/cryptography/__about__.py @@ -5,19 +5,27 @@ from __future__ import absolute_import, division, print_function __all__ = [ - "__title__", "__summary__", "__uri__", "__version__", "__author__", - "__email__", "__license__", "__copyright__", + "__title__", + "__summary__", + "__uri__", + "__version__", + "__author__", + "__email__", + "__license__", + "__copyright__", ] __title__ = "cryptography" -__summary__ = ("cryptography is a package which provides cryptographic recipes" - " and primitives to Python developers.") +__summary__ = ( + "cryptography is a package which provides cryptographic recipes" + " and primitives to Python developers." +) __uri__ = "https://github.com/pyca/cryptography" -__version__ = "2.5" +__version__ = "3.2" __author__ = "The cryptography developers" __email__ = "cryptography-dev@python.org" __license__ = "BSD or Apache License, Version 2.0" -__copyright__ = "Copyright 2013-2017 {0}".format(__author__) +__copyright__ = "Copyright 2013-2019 {}".format(__author__) diff --git a/src/cryptography/__init__.py b/src/cryptography/__init__.py index 6da0b3830d2b..7211614d7f4a 100644 --- a/src/cryptography/__init__.py +++ b/src/cryptography/__init__.py @@ -4,13 +4,45 @@ from __future__ import absolute_import, division, print_function +import sys +import warnings + from cryptography.__about__ import ( - __author__, __copyright__, __email__, __license__, __summary__, __title__, - __uri__, __version__ + __author__, + __copyright__, + __email__, + __license__, + __summary__, + __title__, + __uri__, + __version__, ) +from cryptography.utils import CryptographyDeprecationWarning __all__ = [ - "__title__", "__summary__", "__uri__", "__version__", "__author__", - "__email__", "__license__", "__copyright__", + "__title__", + "__summary__", + "__uri__", + "__version__", + "__author__", + "__email__", + "__license__", + "__copyright__", ] + +if sys.version_info[0] == 2: + warnings.warn( + "Python 2 is no longer supported by the Python core team. Support for " + "it is now deprecated in cryptography, and will be removed in a " + "future release.", + CryptographyDeprecationWarning, + stacklevel=2, + ) +if sys.version_info[:2] == (3, 5): + warnings.warn( + "Python 3.5 support will be dropped in the next release of " + "cryptography. Please upgrade your Python.", + CryptographyDeprecationWarning, + stacklevel=2, + ) diff --git a/src/cryptography/exceptions.py b/src/cryptography/exceptions.py index 648cf9dfe6bc..1d52d7dcfc5e 100644 --- a/src/cryptography/exceptions.py +++ b/src/cryptography/exceptions.py @@ -19,6 +19,7 @@ class _Reasons(Enum): UNSUPPORTED_X509 = 8 UNSUPPORTED_EXCHANGE_ALGORITHM = 9 UNSUPPORTED_DIFFIE_HELLMAN = 10 + UNSUPPORTED_MAC = 11 class UnsupportedAlgorithm(Exception): diff --git a/src/cryptography/fernet.py b/src/cryptography/fernet.py index b990defaaf88..00c25286715a 100644 --- a/src/cryptography/fernet.py +++ b/src/cryptography/fernet.py @@ -14,7 +14,7 @@ from cryptography import utils from cryptography.exceptions import InvalidSignature -from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.primitives import hashes, padding from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.hmac import HMAC @@ -29,8 +29,7 @@ class InvalidToken(Exception): class Fernet(object): def __init__(self, key, backend=None): - if backend is None: - backend = default_backend() + backend = _get_backend(backend) key = base64.urlsafe_b64decode(key) if len(key) != 32: @@ -47,7 +46,9 @@ def generate_key(cls): return base64.urlsafe_b64encode(os.urandom(32)) def encrypt(self, data): - current_time = int(time.time()) + return self.encrypt_at_time(data, int(time.time())) + + def encrypt_at_time(self, data, current_time): iv = os.urandom(16) return self._encrypt_from_parts(data, current_time, iv) @@ -72,7 +73,15 @@ def _encrypt_from_parts(self, data, current_time, iv): def decrypt(self, token, ttl=None): timestamp, data = Fernet._get_unverified_token_data(token) - return self._decrypt_data(data, timestamp, ttl) + return self._decrypt_data(data, timestamp, ttl, int(time.time())) + + def decrypt_at_time(self, token, ttl, current_time): + if ttl is None: + raise ValueError( + "decrypt_at_time() can only be used with a non-None ttl" + ) + timestamp, data = Fernet._get_unverified_token_data(token) + return self._decrypt_data(data, timestamp, ttl, current_time) def extract_timestamp(self, token): timestamp, data = Fernet._get_unverified_token_data(token) @@ -92,7 +101,7 @@ def _get_unverified_token_data(token): raise InvalidToken try: - timestamp, = struct.unpack(">Q", data[1:9]) + (timestamp,) = struct.unpack(">Q", data[1:9]) except struct.error: raise InvalidToken return timestamp, data @@ -105,8 +114,7 @@ def _verify_signature(self, data): except InvalidSignature: raise InvalidToken - def _decrypt_data(self, data, timestamp, ttl): - current_time = int(time.time()) + def _decrypt_data(self, data, timestamp, ttl, current_time): if ttl is not None: if timestamp + ttl < current_time: raise InvalidToken @@ -146,13 +154,16 @@ def __init__(self, fernets): self._fernets = fernets def encrypt(self, msg): - return self._fernets[0].encrypt(msg) + return self.encrypt_at_time(msg, int(time.time())) + + def encrypt_at_time(self, msg, current_time): + return self._fernets[0].encrypt_at_time(msg, current_time) def rotate(self, msg): timestamp, data = Fernet._get_unverified_token_data(msg) for f in self._fernets: try: - p = f._decrypt_data(data, timestamp, None) + p = f._decrypt_data(data, timestamp, None, None) break except InvalidToken: pass @@ -169,3 +180,11 @@ def decrypt(self, msg, ttl=None): except InvalidToken: pass raise InvalidToken + + def decrypt_at_time(self, msg, ttl, current_time): + for f in self._fernets: + try: + return f.decrypt_at_time(msg, ttl, current_time) + except InvalidToken: + pass + raise InvalidToken diff --git a/src/cryptography/hazmat/_der.py b/src/cryptography/hazmat/_der.py new file mode 100644 index 000000000000..462b911b4532 --- /dev/null +++ b/src/cryptography/hazmat/_der.py @@ -0,0 +1,156 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import six + +from cryptography.utils import int_from_bytes, int_to_bytes + + +# This module contains a lightweight DER encoder and decoder. See X.690 for the +# specification. This module intentionally does not implement the more complex +# BER encoding, only DER. +# +# Note this implementation treats an element's constructed bit as part of the +# tag. This is fine for DER, where the bit is always computable from the type. + + +CONSTRUCTED = 0x20 +CONTEXT_SPECIFIC = 0x80 + +INTEGER = 0x02 +BIT_STRING = 0x03 +OCTET_STRING = 0x04 +NULL = 0x05 +OBJECT_IDENTIFIER = 0x06 +SEQUENCE = 0x10 | CONSTRUCTED +SET = 0x11 | CONSTRUCTED +PRINTABLE_STRING = 0x13 +UTC_TIME = 0x17 +GENERALIZED_TIME = 0x18 + + +class DERReader(object): + def __init__(self, data): + self.data = memoryview(data) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + if exc_value is None: + self.check_empty() + + def is_empty(self): + return len(self.data) == 0 + + def check_empty(self): + if not self.is_empty(): + raise ValueError("Invalid DER input: trailing data") + + def read_byte(self): + if len(self.data) < 1: + raise ValueError("Invalid DER input: insufficient data") + ret = six.indexbytes(self.data, 0) + self.data = self.data[1:] + return ret + + def read_bytes(self, n): + if len(self.data) < n: + raise ValueError("Invalid DER input: insufficient data") + ret = self.data[:n] + self.data = self.data[n:] + return ret + + def read_any_element(self): + tag = self.read_byte() + # Tag numbers 31 or higher are stored in multiple bytes. No supported + # ASN.1 types use such tags, so reject these. + if tag & 0x1F == 0x1F: + raise ValueError("Invalid DER input: unexpected high tag number") + length_byte = self.read_byte() + if length_byte & 0x80 == 0: + # If the high bit is clear, the first length byte is the length. + length = length_byte + else: + # If the high bit is set, the first length byte encodes the length + # of the length. + length_byte &= 0x7F + if length_byte == 0: + raise ValueError( + "Invalid DER input: indefinite length form is not allowed " + "in DER" + ) + length = 0 + for i in range(length_byte): + length <<= 8 + length |= self.read_byte() + if length == 0: + raise ValueError( + "Invalid DER input: length was not minimally-encoded" + ) + if length < 0x80: + # If the length could have been encoded in short form, it must + # not use long form. + raise ValueError( + "Invalid DER input: length was not minimally-encoded" + ) + body = self.read_bytes(length) + return tag, DERReader(body) + + def read_element(self, expected_tag): + tag, body = self.read_any_element() + if tag != expected_tag: + raise ValueError("Invalid DER input: unexpected tag") + return body + + def read_single_element(self, expected_tag): + with self: + return self.read_element(expected_tag) + + def read_optional_element(self, expected_tag): + if len(self.data) > 0 and six.indexbytes(self.data, 0) == expected_tag: + return self.read_element(expected_tag) + return None + + def as_integer(self): + if len(self.data) == 0: + raise ValueError("Invalid DER input: empty integer contents") + first = six.indexbytes(self.data, 0) + if first & 0x80 == 0x80: + raise ValueError("Negative DER integers are not supported") + # The first 9 bits must not all be zero or all be ones. Otherwise, the + # encoding should have been one byte shorter. + if len(self.data) > 1: + second = six.indexbytes(self.data, 1) + if first == 0 and second & 0x80 == 0: + raise ValueError( + "Invalid DER input: integer not minimally-encoded" + ) + return int_from_bytes(self.data, "big") + + +def encode_der_integer(x): + if not isinstance(x, six.integer_types): + raise ValueError("Value must be an integer") + if x < 0: + raise ValueError("Negative integers are not supported") + n = x.bit_length() // 8 + 1 + return int_to_bytes(x, n) + + +def encode_der(tag, *children): + length = 0 + for child in children: + length += len(child) + chunks = [six.int2byte(tag)] + if length < 0x80: + chunks.append(six.int2byte(length)) + else: + length_bytes = int_to_bytes(length) + chunks.append(six.int2byte(0x80 | len(length_bytes))) + chunks.append(length_bytes) + chunks.extend(children) + return b"".join(chunks) diff --git a/src/cryptography/hazmat/_oid.py b/src/cryptography/hazmat/_oid.py index cfe906cd3e84..de2771a7379a 100644 --- a/src/cryptography/hazmat/_oid.py +++ b/src/cryptography/hazmat/_oid.py @@ -19,26 +19,36 @@ def __init__(self, dotted_string): # range 0..39. All nodes must be integers. for node in nodes: try: - intnodes.append(int(node, 0)) + node_value = int(node, 10) except ValueError: raise ValueError( - "Malformed OID: %s (non-integer nodes)" % ( - self._dotted_string)) + "Malformed OID: %s (non-integer nodes)" + % (self._dotted_string) + ) + if node_value < 0: + raise ValueError( + "Malformed OID: %s (negative-integer nodes)" + % (self._dotted_string) + ) + intnodes.append(node_value) if len(nodes) < 2: raise ValueError( - "Malformed OID: %s (insufficient number of nodes)" % ( - self._dotted_string)) + "Malformed OID: %s (insufficient number of nodes)" + % (self._dotted_string) + ) if intnodes[0] > 2: raise ValueError( - "Malformed OID: %s (first node outside valid range)" % ( - self._dotted_string)) + "Malformed OID: %s (first node outside valid range)" + % (self._dotted_string) + ) if intnodes[0] < 2 and intnodes[1] >= 40: raise ValueError( - "Malformed OID: %s (second node outside valid range)" % ( - self._dotted_string)) + "Malformed OID: %s (second node outside valid range)" + % (self._dotted_string) + ) def __eq__(self, other): if not isinstance(other, ObjectIdentifier): @@ -50,9 +60,8 @@ def __ne__(self, other): return not self == other def __repr__(self): - return "".format( - self.dotted_string, - self._name + return "".format( + self.dotted_string, self._name ) def __hash__(self): @@ -62,6 +71,7 @@ def __hash__(self): def _name(self): # Lazy import to avoid an import cycle from cryptography.x509.oid import _OID_NAMES + return _OID_NAMES.get(self, "Unknown OID") dotted_string = utils.read_only_property("_dotted_string") diff --git a/src/cryptography/hazmat/backends/__init__.py b/src/cryptography/hazmat/backends/__init__.py index 565bde788bab..1563936dde6e 100644 --- a/src/cryptography/hazmat/backends/__init__.py +++ b/src/cryptography/hazmat/backends/__init__.py @@ -13,6 +13,14 @@ def default_backend(): if _default_backend is None: from cryptography.hazmat.backends.openssl.backend import backend + _default_backend = backend return _default_backend + + +def _get_backend(backend): + if backend is None: + return default_backend() + else: + return backend diff --git a/src/cryptography/hazmat/backends/interfaces.py b/src/cryptography/hazmat/backends/interfaces.py index 0a476b991c74..418980a34e0d 100644 --- a/src/cryptography/hazmat/backends/interfaces.py +++ b/src/cryptography/hazmat/backends/interfaces.py @@ -57,7 +57,7 @@ def hmac_supported(self, algorithm): @abc.abstractmethod def create_hmac_ctx(self, key, algorithm): """ - Create a MACContext for calculating a message authentication code. + Create a context for calculating a message authentication code. """ @@ -72,7 +72,7 @@ def cmac_algorithm_supported(self, algorithm): @abc.abstractmethod def create_cmac_ctx(self, algorithm): """ - Create a MACContext for calculating a message authentication code. + Create a context for calculating a message authentication code. """ @@ -86,8 +86,9 @@ def pbkdf2_hmac_supported(self, algorithm): """ @abc.abstractmethod - def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations, - key_material): + def derive_pbkdf2_hmac( + self, algorithm, length, salt, iterations, key_material + ): """ Return length bytes derived from provided PBKDF2 parameters. """ diff --git a/src/cryptography/hazmat/backends/openssl/aead.py b/src/cryptography/hazmat/backends/openssl/aead.py index 73195ff3e265..4494916852ae 100644 --- a/src/cryptography/hazmat/backends/openssl/aead.py +++ b/src/cryptography/hazmat/backends/openssl/aead.py @@ -13,15 +13,18 @@ def _aead_cipher_name(cipher): from cryptography.hazmat.primitives.ciphers.aead import ( - AESCCM, AESGCM, ChaCha20Poly1305 + AESCCM, + AESGCM, + ChaCha20Poly1305, ) + if isinstance(cipher, ChaCha20Poly1305): return b"chacha20-poly1305" elif isinstance(cipher, AESCCM): - return "aes-{0}-ccm".format(len(cipher._key) * 8).encode("ascii") + return "aes-{}-ccm".format(len(cipher._key) * 8).encode("ascii") else: assert isinstance(cipher, AESGCM) - return "aes-{0}-gcm".format(len(cipher._key) * 8).encode("ascii") + return "aes-{}-gcm".format(len(cipher._key) * 8).encode("ascii") def _aead_setup(backend, cipher_name, key, nonce, tag, tag_len, operation): @@ -30,18 +33,21 @@ def _aead_setup(backend, cipher_name, key, nonce, tag, tag_len, operation): ctx = backend._lib.EVP_CIPHER_CTX_new() ctx = backend._ffi.gc(ctx, backend._lib.EVP_CIPHER_CTX_free) res = backend._lib.EVP_CipherInit_ex( - ctx, evp_cipher, + ctx, + evp_cipher, backend._ffi.NULL, backend._ffi.NULL, backend._ffi.NULL, - int(operation == _ENCRYPT) + int(operation == _ENCRYPT), ) backend.openssl_assert(res != 0) res = backend._lib.EVP_CIPHER_CTX_set_key_length(ctx, len(key)) backend.openssl_assert(res != 0) res = backend._lib.EVP_CIPHER_CTX_ctrl( - ctx, backend._lib.EVP_CTRL_AEAD_SET_IVLEN, len(nonce), - backend._ffi.NULL + ctx, + backend._lib.EVP_CTRL_AEAD_SET_IVLEN, + len(nonce), + backend._ffi.NULL, ) backend.openssl_assert(res != 0) if operation == _DECRYPT: @@ -49,10 +55,11 @@ def _aead_setup(backend, cipher_name, key, nonce, tag, tag_len, operation): ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, len(tag), tag ) backend.openssl_assert(res != 0) - else: + 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 ) + backend.openssl_assert(res != 0) nonce_ptr = backend._ffi.from_buffer(nonce) key_ptr = backend._ffi.from_buffer(key) @@ -62,7 +69,7 @@ def _aead_setup(backend, cipher_name, key, nonce, tag, tag_len, operation): backend._ffi.NULL, key_ptr, nonce_ptr, - int(operation == _ENCRYPT) + int(operation == _ENCRYPT), ) backend.openssl_assert(res != 0) return ctx @@ -71,11 +78,7 @@ def _aead_setup(backend, cipher_name, key, nonce, tag, tag_len, operation): def _set_length(backend, ctx, data_len): intptr = backend._ffi.new("int *") res = backend._lib.EVP_CipherUpdate( - ctx, - backend._ffi.NULL, - intptr, - backend._ffi.NULL, - data_len + ctx, backend._ffi.NULL, intptr, backend._ffi.NULL, data_len ) backend.openssl_assert(res != 0) @@ -98,6 +101,7 @@ def _process_data(backend, ctx, data): def _encrypt(backend, cipher, nonce, data, associated_data, tag_length): from cryptography.hazmat.primitives.ciphers.aead import AESCCM + cipher_name = _aead_cipher_name(cipher) ctx = _aead_setup( backend, cipher_name, cipher._key, nonce, None, tag_length, _ENCRYPT @@ -125,6 +129,7 @@ def _encrypt(backend, cipher, nonce, data, associated_data, tag_length): def _decrypt(backend, cipher, nonce, data, associated_data, tag_length): from cryptography.hazmat.primitives.ciphers.aead import AESCCM + if len(data) < tag_length: raise InvalidTag tag = data[-tag_length:] diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 0a9bc53aebdb..b7757e333d9e 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -4,84 +4,165 @@ from __future__ import absolute_import, division, print_function -import base64 import collections import contextlib import itertools +import warnings from contextlib import contextmanager -import asn1crypto.core - import six from six.moves import range from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat._der import ( + INTEGER, + NULL, + SEQUENCE, + encode_der, + encode_der_integer, +) from cryptography.hazmat.backends.interfaces import ( - CMACBackend, CipherBackend, DERSerializationBackend, DHBackend, DSABackend, - EllipticCurveBackend, HMACBackend, HashBackend, PBKDF2HMACBackend, - PEMSerializationBackend, RSABackend, ScryptBackend, X509Backend + CMACBackend, + CipherBackend, + DERSerializationBackend, + DHBackend, + DSABackend, + EllipticCurveBackend, + HMACBackend, + HashBackend, + PBKDF2HMACBackend, + PEMSerializationBackend, + RSABackend, + ScryptBackend, + X509Backend, ) from cryptography.hazmat.backends.openssl import aead from cryptography.hazmat.backends.openssl.ciphers import _CipherContext from cryptography.hazmat.backends.openssl.cmac import _CMACContext from cryptography.hazmat.backends.openssl.decode_asn1 import ( - _CRL_ENTRY_REASON_ENUM_TO_CODE, _Integers + _CRL_ENTRY_REASON_ENUM_TO_CODE, + _CRL_EXTENSION_HANDLERS, + _EXTENSION_HANDLERS_BASE, + _EXTENSION_HANDLERS_SCT, + _OCSP_BASICRESP_EXTENSION_HANDLERS, + _OCSP_REQ_EXTENSION_HANDLERS, + _OCSP_SINGLERESP_EXTENSION_HANDLERS_SCT, + _REVOKED_EXTENSION_HANDLERS, + _X509ExtensionParser, ) from cryptography.hazmat.backends.openssl.dh import ( - _DHParameters, _DHPrivateKey, _DHPublicKey, _dh_params_dup + _DHParameters, + _DHPrivateKey, + _DHPublicKey, + _dh_params_dup, ) from cryptography.hazmat.backends.openssl.dsa import ( - _DSAParameters, _DSAPrivateKey, _DSAPublicKey + _DSAParameters, + _DSAPrivateKey, + _DSAPublicKey, ) from cryptography.hazmat.backends.openssl.ec import ( - _EllipticCurvePrivateKey, _EllipticCurvePublicKey + _EllipticCurvePrivateKey, + _EllipticCurvePublicKey, +) +from cryptography.hazmat.backends.openssl.ed25519 import ( + _Ed25519PrivateKey, + _Ed25519PublicKey, +) +from cryptography.hazmat.backends.openssl.ed448 import ( + _ED448_KEY_SIZE, + _Ed448PrivateKey, + _Ed448PublicKey, ) from cryptography.hazmat.backends.openssl.encode_asn1 import ( _CRL_ENTRY_EXTENSION_ENCODE_HANDLERS, - _CRL_EXTENSION_ENCODE_HANDLERS, _EXTENSION_ENCODE_HANDLERS, + _CRL_EXTENSION_ENCODE_HANDLERS, + _EXTENSION_ENCODE_HANDLERS, _OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS, _OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS, - _encode_asn1_int_gc, _encode_asn1_str_gc, _encode_name_gc, _txt2obj_gc, + _encode_asn1_int_gc, + _encode_asn1_str_gc, + _encode_name_gc, + _txt2obj_gc, ) from cryptography.hazmat.backends.openssl.hashes import _HashContext from cryptography.hazmat.backends.openssl.hmac import _HMACContext from cryptography.hazmat.backends.openssl.ocsp import ( - _OCSPRequest, _OCSPResponse + _OCSPRequest, + _OCSPResponse, +) +from cryptography.hazmat.backends.openssl.poly1305 import ( + _POLY1305_KEY_SIZE, + _Poly1305Context, ) from cryptography.hazmat.backends.openssl.rsa import ( - _RSAPrivateKey, _RSAPublicKey + _RSAPrivateKey, + _RSAPublicKey, ) from cryptography.hazmat.backends.openssl.x25519 import ( - _X25519PrivateKey, _X25519PublicKey + _X25519PrivateKey, + _X25519PublicKey, ) from cryptography.hazmat.backends.openssl.x448 import ( - _X448PrivateKey, _X448PublicKey + _X448PrivateKey, + _X448PublicKey, ) from cryptography.hazmat.backends.openssl.x509 import ( - _Certificate, _CertificateRevocationList, - _CertificateSigningRequest, _RevokedCertificate + _Certificate, + _CertificateRevocationList, + _CertificateSigningRequest, + _RevokedCertificate, ) from cryptography.hazmat.bindings.openssl import binding from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa +from cryptography.hazmat.primitives.asymmetric import ( + dsa, + ec, + ed25519, + ed448, + rsa, +) from cryptography.hazmat.primitives.asymmetric.padding import ( - MGF1, OAEP, PKCS1v15, PSS + MGF1, + OAEP, + PKCS1v15, + PSS, ) from cryptography.hazmat.primitives.ciphers.algorithms import ( - AES, ARC4, Blowfish, CAST5, Camellia, ChaCha20, IDEA, SEED, TripleDES + AES, + ARC4, + Blowfish, + CAST5, + Camellia, + ChaCha20, + IDEA, + SEED, + TripleDES, ) from cryptography.hazmat.primitives.ciphers.modes import ( - CBC, CFB, CFB8, CTR, ECB, GCM, OFB, XTS + CBC, + CFB, + CFB8, + CTR, + ECB, + GCM, + OFB, + XTS, ) from cryptography.hazmat.primitives.kdf import scrypt -from cryptography.hazmat.primitives.serialization import ssh +from cryptography.hazmat.primitives.serialization import pkcs7, ssh from cryptography.x509 import ocsp _MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"]) +# Not actually supported, just used as a marker for some serialization tests. +class _RC2(object): + pass + + @utils.register_interface(CipherBackend) @utils.register_interface(CMACBackend) @utils.register_interface(DERSerializationBackend) @@ -101,39 +182,93 @@ class Backend(object): """ OpenSSL API binding interfaces. """ + name = "openssl" + # FIPS has opinions about acceptable algorithms and key sizes, but the + # disallowed algorithms are still present in OpenSSL. They just error if + # you try to use them. To avoid that we allowlist the algorithms in + # FIPS 140-3. This isn't ideal, but FIPS 140-3 is trash so here we are. + _fips_aead = { + b"aes-128-ccm", + b"aes-192-ccm", + b"aes-256-ccm", + b"aes-128-gcm", + b"aes-192-gcm", + b"aes-256-gcm", + } + _fips_ciphers = (AES, TripleDES) + _fips_hashes = ( + hashes.SHA1, + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + hashes.SHA512_224, + hashes.SHA512_256, + hashes.SHA3_224, + hashes.SHA3_256, + hashes.SHA3_384, + hashes.SHA3_512, + hashes.SHAKE128, + hashes.SHAKE256, + ) + _fips_rsa_min_key_size = 2048 + _fips_rsa_min_public_exponent = 65537 + _fips_dsa_min_modulus = 1 << 2048 + _fips_dh_min_key_size = 2048 + _fips_dh_min_modulus = 1 << _fips_dh_min_key_size + def __init__(self): self._binding = binding.Binding() self._ffi = self._binding.ffi self._lib = self._binding.lib + self._fips_enabled = self._is_fips_enabled() self._cipher_registry = {} self._register_default_ciphers() - self.activate_osrandom_engine() + self._register_x509_ext_parsers() + self._register_x509_encoders() + 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) - def openssl_assert(self, ok): - return binding._openssl_assert(self._lib, ok) + def openssl_assert(self, ok, errors=None): + return binding._openssl_assert(self._lib, ok, errors=errors) + + def _is_fips_enabled(self): + fips_mode = getattr(self._lib, "FIPS_mode", lambda: 0) + mode = fips_mode() + if mode == 0: + # OpenSSL without FIPS pushes an error on the error stack + self._lib.ERR_clear_error() + return bool(mode) def activate_builtin_random(self): - # Obtain a new structural reference. - e = self._lib.ENGINE_get_default_RAND() - if e != self._ffi.NULL: - self._lib.ENGINE_unregister_RAND(e) - # Reset the RNG to use the new engine. - self._lib.RAND_cleanup() - # decrement the structural reference from get_default_RAND - res = self._lib.ENGINE_finish(e) - self.openssl_assert(res == 1) + if self._lib.CRYPTOGRAPHY_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._binding._osrandom_engine_id) + e = self._lib.ENGINE_by_id(self._lib.Cryptography_osrandom_engine_id) self.openssl_assert(e != self._ffi.NULL) # Initialize the engine for use. This adds a functional reference. res = self._lib.ENGINE_init(e) @@ -150,30 +285,32 @@ def _get_osurandom_engine(self): self.openssl_assert(res == 1) def activate_osrandom_engine(self): - # Unregister and free the current engine. - self.activate_builtin_random() - with self._get_osurandom_engine() as e: - # Set the engine as the default RAND provider. - res = self._lib.ENGINE_set_default_RAND(e) + 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) - # Reset the RNG to use the new engine. - self._lib.RAND_cleanup() def osrandom_engine_implementation(self): 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) + 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') + return self._ffi.string(buf).decode("ascii") def openssl_version_text(self): """ Friendly string name of the loaded OpenSSL library. This is not necessarily the same version as it was compiled against. - Example: OpenSSL 1.0.1e 11 Feb 2013 + Example: OpenSSL 1.1.1d 10 Sep 2019 """ return self._ffi.string( self._lib.OpenSSL_version(self._lib.OPENSSL_VERSION) @@ -187,7 +324,7 @@ def create_hmac_ctx(self, key, algorithm): def _evp_md_from_algorithm(self, algorithm): if algorithm.name == "blake2b" or algorithm.name == "blake2s": - alg = "{0}{1}".format( + alg = "{}{}".format( algorithm.name, algorithm.digest_size * 8 ).encode("ascii") else: @@ -202,6 +339,9 @@ def _evp_md_non_null_from_algorithm(self, algorithm): return evp_md def hash_supported(self, algorithm): + if self._fips_enabled and not isinstance(algorithm, self._fips_hashes): + return False + evp_md = self._evp_md_from_algorithm(algorithm) return evp_md != self._ffi.NULL @@ -212,6 +352,8 @@ def create_hash_ctx(self, algorithm): return _HashContext(self, algorithm) def cipher_supported(self, cipher, mode): + if self._fips_enabled and not isinstance(cipher, self._fips_ciphers): + return False try: adapter = self._cipher_registry[type(cipher), type(mode)] except KeyError: @@ -221,8 +363,10 @@ def cipher_supported(self, cipher, mode): def register_cipher_adapter(self, cipher_cls, mode_cls, adapter): if (cipher_cls, mode_cls) in self._cipher_registry: - raise ValueError("Duplicate registration for: {0} {1}.".format( - cipher_cls, mode_cls) + raise ValueError( + "Duplicate registration for: {} {}.".format( + cipher_cls, mode_cls + ) ) self._cipher_registry[cipher_cls, mode_cls] = adapter @@ -231,36 +375,28 @@ def _register_default_ciphers(self): self.register_cipher_adapter( AES, mode_cls, - GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}") + GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}"), ) for mode_cls in [CBC, CTR, ECB, OFB, CFB]: self.register_cipher_adapter( Camellia, mode_cls, - GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}") + GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}"), ) for mode_cls in [CBC, CFB, CFB8, OFB]: self.register_cipher_adapter( - TripleDES, - mode_cls, - GetCipherByName("des-ede3-{mode.name}") + TripleDES, mode_cls, GetCipherByName("des-ede3-{mode.name}") ) self.register_cipher_adapter( - TripleDES, - ECB, - GetCipherByName("des-ede3") + TripleDES, ECB, GetCipherByName("des-ede3") ) for mode_cls in [CBC, CFB, OFB, ECB]: self.register_cipher_adapter( - Blowfish, - mode_cls, - GetCipherByName("bf-{mode.name}") + Blowfish, mode_cls, GetCipherByName("bf-{mode.name}") ) for mode_cls in [CBC, CFB, OFB, ECB]: self.register_cipher_adapter( - SEED, - mode_cls, - GetCipherByName("seed-{mode.name}") + SEED, mode_cls, GetCipherByName("seed-{mode.name}") ) for cipher_cls, mode_cls in itertools.product( [CAST5, IDEA], @@ -269,20 +405,84 @@ def _register_default_ciphers(self): self.register_cipher_adapter( cipher_cls, mode_cls, - GetCipherByName("{cipher.name}-{mode.name}") + GetCipherByName("{cipher.name}-{mode.name}"), ) + self.register_cipher_adapter(ARC4, type(None), GetCipherByName("rc4")) + # We don't actually support RC2, this is just used by some tests. + self.register_cipher_adapter(_RC2, type(None), GetCipherByName("rc2")) self.register_cipher_adapter( - ARC4, - type(None), - GetCipherByName("rc4") - ) - self.register_cipher_adapter( - ChaCha20, - type(None), - GetCipherByName("chacha20") + ChaCha20, type(None), GetCipherByName("chacha20") ) self.register_cipher_adapter(AES, XTS, _get_xts_cipher) + def _register_x509_ext_parsers(self): + ext_handlers = _EXTENSION_HANDLERS_BASE.copy() + # All revoked extensions are valid single response extensions, see: + # https://tools.ietf.org/html/rfc6960#section-4.4.5 + singleresp_handlers = _REVOKED_EXTENSION_HANDLERS.copy() + + if self._lib.Cryptography_HAS_SCT: + ext_handlers.update(_EXTENSION_HANDLERS_SCT) + singleresp_handlers.update(_OCSP_SINGLERESP_EXTENSION_HANDLERS_SCT) + + self._certificate_extension_parser = _X509ExtensionParser( + self, + ext_count=self._lib.X509_get_ext_count, + get_ext=self._lib.X509_get_ext, + handlers=ext_handlers, + ) + self._csr_extension_parser = _X509ExtensionParser( + self, + ext_count=self._lib.sk_X509_EXTENSION_num, + get_ext=self._lib.sk_X509_EXTENSION_value, + handlers=ext_handlers, + ) + self._revoked_cert_extension_parser = _X509ExtensionParser( + self, + ext_count=self._lib.X509_REVOKED_get_ext_count, + get_ext=self._lib.X509_REVOKED_get_ext, + handlers=_REVOKED_EXTENSION_HANDLERS, + ) + self._crl_extension_parser = _X509ExtensionParser( + self, + ext_count=self._lib.X509_CRL_get_ext_count, + get_ext=self._lib.X509_CRL_get_ext, + handlers=_CRL_EXTENSION_HANDLERS, + ) + self._ocsp_req_ext_parser = _X509ExtensionParser( + self, + ext_count=self._lib.OCSP_REQUEST_get_ext_count, + get_ext=self._lib.OCSP_REQUEST_get_ext, + handlers=_OCSP_REQ_EXTENSION_HANDLERS, + ) + self._ocsp_basicresp_ext_parser = _X509ExtensionParser( + self, + ext_count=self._lib.OCSP_BASICRESP_get_ext_count, + get_ext=self._lib.OCSP_BASICRESP_get_ext, + handlers=_OCSP_BASICRESP_EXTENSION_HANDLERS, + ) + self._ocsp_singleresp_ext_parser = _X509ExtensionParser( + self, + ext_count=self._lib.OCSP_SINGLERESP_get_ext_count, + get_ext=self._lib.OCSP_SINGLERESP_get_ext, + handlers=singleresp_handlers, + ) + + def _register_x509_encoders(self): + self._extension_encode_handlers = _EXTENSION_ENCODE_HANDLERS.copy() + self._crl_extension_encode_handlers = ( + _CRL_EXTENSION_ENCODE_HANDLERS.copy() + ) + self._crl_entry_extension_encode_handlers = ( + _CRL_ENTRY_EXTENSION_ENCODE_HANDLERS.copy() + ) + self._ocsp_request_extension_encode_handlers = ( + _OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS.copy() + ) + self._ocsp_basicresp_extension_encode_handlers = ( + _OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS.copy() + ) + def create_symmetric_encryption_ctx(self, cipher, mode): return _CipherContext(self, cipher, mode, _CipherContext._ENCRYPT) @@ -292,8 +492,9 @@ def create_symmetric_decryption_ctx(self, cipher, mode): def pbkdf2_hmac_supported(self, algorithm): return self.hmac_supported(algorithm) - def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations, - key_material): + def derive_pbkdf2_hmac( + self, algorithm, length, salt, iterations, key_material + ): 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) @@ -305,7 +506,7 @@ def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations, iterations, evp_md, length, - buf + buf, ) self.openssl_assert(res == 1) return self._ffi.buffer(buf)[:] @@ -313,6 +514,9 @@ def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations, def _consume_errors(self): return binding._consume_errors(self._lib) + def _consume_errors_with_text(self): + return binding._consume_errors_with_text(self._lib) + def _bn_to_int(self, bn): assert bn != self._ffi.NULL @@ -323,7 +527,10 @@ def _bn_to_int(self, bn): bin_len = self._lib.BN_bn2bin(bn, bin_ptr) # A zero length means the BN has value 0 self.openssl_assert(bin_len >= 0) - return int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big") + val = int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big") + if self._lib.BN_is_negative(bn): + val = -val + return val else: # Under Python 2 the best we can do is hex() hex_cdata = self._lib.BN_bn2hex(bn) @@ -382,8 +589,11 @@ def generate_rsa_private_key(self, public_exponent, key_size): return _RSAPrivateKey(self, rsa_cdata, evp_pkey) def generate_rsa_parameters_supported(self, public_exponent, key_size): - return (public_exponent >= 3 and public_exponent & 1 != 0 and - key_size >= 512) + return ( + public_exponent >= 3 + and public_exponent & 1 != 0 + and key_size >= 512 + ) def load_rsa_private_numbers(self, numbers): rsa._check_private_key_components( @@ -394,7 +604,7 @@ def load_rsa_private_numbers(self, numbers): numbers.dmq1, numbers.iqmp, numbers.public_numbers.e, - numbers.public_numbers.n + numbers.public_numbers.n, ) rsa_cdata = self._lib.RSA_new() self.openssl_assert(rsa_cdata != self._ffi.NULL) @@ -413,8 +623,6 @@ def load_rsa_private_numbers(self, numbers): self.openssl_assert(res == 1) res = self._lib.RSA_set0_crt_params(rsa_cdata, dmp1, dmq1, iqmp) self.openssl_assert(res == 1) - res = self._lib.RSA_blinding_on(rsa_cdata, self._ffi.NULL) - self.openssl_assert(res == 1) evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) return _RSAPrivateKey(self, rsa_cdata, evp_pkey) @@ -452,9 +660,7 @@ def _bytes_to_bio(self, data): BIO is finished with. """ data_ptr = self._ffi.from_buffer(data) - bio = self._lib.BIO_new_mem_buf( - data_ptr, len(data) - ) + bio = self._lib.BIO_new_mem_buf(data_ptr, len(data)) self.openssl_assert(bio != self._ffi.NULL) return _MemoryBIO(self._ffi.gc(bio, self._lib.BIO_free), data_ptr) @@ -509,12 +715,18 @@ def _evp_pkey_to_private_key(self, 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) + elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): + # EVP_PKEY_ED25519 is not present in OpenSSL < 1.1.1 + return _Ed25519PrivateKey(self, evp_pkey) elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): # EVP_PKEY_X448 is not present in OpenSSL < 1.1.1 return _X448PrivateKey(self, evp_pkey) elif key_type == getattr(self._lib, "EVP_PKEY_X25519", None): # EVP_PKEY_X25519 is not present in OpenSSL < 1.1.0 return _X25519PrivateKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): + # EVP_PKEY_ED448 is not present in OpenSSL < 1.1.1 + return _Ed448PrivateKey(self, evp_pkey) else: raise UnsupportedAlgorithm("Unsupported key type.") @@ -546,25 +758,32 @@ def _evp_pkey_to_public_key(self, 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) + elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): + # EVP_PKEY_ED25519 is not present in OpenSSL < 1.1.1 + return _Ed25519PublicKey(self, evp_pkey) elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): # EVP_PKEY_X448 is not present in OpenSSL < 1.1.1 return _X448PublicKey(self, evp_pkey) elif key_type == getattr(self._lib, "EVP_PKEY_X25519", None): # EVP_PKEY_X25519 is not present in OpenSSL < 1.1.0 return _X25519PublicKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): + # EVP_PKEY_X25519 is not present in OpenSSL < 1.1.1 + return _Ed448PublicKey(self, evp_pkey) else: raise UnsupportedAlgorithm("Unsupported key type.") def _oaep_hash_supported(self, algorithm): if self._lib.Cryptography_HAS_RSA_OAEP_MD: return isinstance( - algorithm, ( + algorithm, + ( hashes.SHA1, hashes.SHA224, hashes.SHA256, hashes.SHA384, hashes.SHA512, - ) + ), ) else: return isinstance(algorithm, hashes.SHA1) @@ -576,27 +795,34 @@ def rsa_padding_supported(self, padding): return self.hash_supported(padding._mgf._algorithm) elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1): return ( - self._oaep_hash_supported(padding._mgf._algorithm) and - self._oaep_hash_supported(padding._algorithm) and - ( - (padding._label is None or len(padding._label) == 0) or - self._lib.Cryptography_HAS_RSA_OAEP_LABEL == 1 + self._oaep_hash_supported(padding._mgf._algorithm) + and self._oaep_hash_supported(padding._algorithm) + and ( + (padding._label is None or len(padding._label) == 0) + or self._lib.Cryptography_HAS_RSA_OAEP_LABEL == 1 ) ) else: return False def generate_dsa_parameters(self, key_size): - if key_size not in (1024, 2048, 3072): - raise ValueError("Key size must be 1024 or 2048 or 3072 bits.") + if key_size not in (1024, 2048, 3072, 4096): + raise ValueError( + "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 + ctx, + key_size, + self._ffi.NULL, + 0, + self._ffi.NULL, + self._ffi.NULL, + self._ffi.NULL, ) self.openssl_assert(res == 1) @@ -692,20 +918,37 @@ def cmac_algorithm_supported(self, algorithm): def create_cmac_ctx(self, algorithm): return _CMACContext(self, algorithm) - def create_x509_csr(self, builder, private_key, algorithm): - if not isinstance(algorithm, hashes.HashAlgorithm): - raise TypeError('Algorithm must be a registered hash algorithm.') - - if ( - isinstance(algorithm, hashes.MD5) and not - isinstance(private_key, rsa.RSAPrivateKey) + def _x509_check_signature_params(self, private_key, algorithm): + if isinstance( + private_key, (ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey) + ): + if algorithm is not None: + raise ValueError( + "algorithm must be None when signing via ed25519 or ed448" + ) + elif not isinstance( + private_key, + (rsa.RSAPrivateKey, dsa.DSAPrivateKey, ec.EllipticCurvePrivateKey), + ): + raise TypeError( + "Key must be an rsa, dsa, ec, ed25519, or ed448 private key." + ) + elif not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Algorithm must be a registered hash algorithm.") + elif isinstance(algorithm, hashes.MD5) and not isinstance( + private_key, rsa.RSAPrivateKey ): raise ValueError( - "MD5 is not a supported hash algorithm for EC/DSA CSRs" + "MD5 hash algorithm is only supported with RSA keys" ) + def create_x509_csr(self, builder, private_key, algorithm): + if not isinstance(builder, x509.CertificateSigningRequestBuilder): + raise TypeError("Builder type mismatch.") + self._x509_check_signature_params(private_key, algorithm) + # Resolve the signature algorithm. - evp_md = self._evp_md_non_null_from_algorithm(algorithm) + evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm) # Create an empty request. x509_req = self._lib.X509_REQ_new() @@ -724,9 +967,7 @@ def create_x509_csr(self, builder, private_key, algorithm): # Set subject public key. public_key = private_key.public_key() - res = self._lib.X509_REQ_set_pubkey( - x509_req, public_key._evp_pkey - ) + res = self._lib.X509_REQ_set_pubkey(x509_req, public_key._evp_pkey) self.openssl_assert(res == 1) # Add extensions. @@ -735,60 +976,55 @@ def create_x509_csr(self, builder, private_key, algorithm): sk_extension = self._ffi.gc( sk_extension, lambda x: self._lib.sk_X509_EXTENSION_pop_free( - x, self._ffi.addressof( + x, + self._ffi.addressof( self._lib._original_lib, "X509_EXTENSION_free" - ) - ) + ), + ), ) # Don't GC individual extensions because the memory is owned by # sk_extensions and will be freed along with it. self._create_x509_extensions( extensions=builder._extensions, - handlers=_EXTENSION_ENCODE_HANDLERS, + handlers=self._extension_encode_handlers, x509_obj=sk_extension, add_func=self._lib.sk_X509_EXTENSION_insert, - gc=False + gc=False, ) res = self._lib.X509_REQ_add_extensions(x509_req, sk_extension) self.openssl_assert(res == 1) - # Sign the request using the requester's private key. - res = self._lib.X509_REQ_sign( - x509_req, private_key._evp_pkey, evp_md - ) - if res == 0: - errors = self._consume_errors() - self.openssl_assert( - errors[0]._lib_reason_match( - self._lib.ERR_LIB_RSA, - self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY - ) + # Add attributes (all bytes encoded as ASN1 UTF8_STRING) + for attr_oid, attr_val in builder._attributes: + obj = _txt2obj_gc(self, attr_oid.dotted_string) + res = self._lib.X509_REQ_add1_attr_by_OBJ( + x509_req, + obj, + x509.name._ASN1Type.UTF8String.value, + attr_val, + len(attr_val), ) + self.openssl_assert(res == 1) - raise ValueError("Digest too big for RSA key") + # Sign the request using the requester's private key. + res = self._lib.X509_REQ_sign(x509_req, private_key._evp_pkey, evp_md) + if res == 0: + errors = self._consume_errors_with_text() + raise ValueError("Signing failed", errors) return _CertificateSigningRequest(self, x509_req) def create_x509_certificate(self, builder, private_key, algorithm): if not isinstance(builder, x509.CertificateBuilder): - raise TypeError('Builder type mismatch.') - if not isinstance(algorithm, hashes.HashAlgorithm): - raise TypeError('Algorithm must be a registered hash algorithm.') - - if ( - isinstance(algorithm, hashes.MD5) and not - isinstance(private_key, rsa.RSAPrivateKey) - ): - raise ValueError( - "MD5 is not a supported hash algorithm for EC/DSA certificates" - ) + raise TypeError("Builder type mismatch.") + self._x509_check_signature_params(private_key, algorithm) # Resolve the signature algorithm. - evp_md = self._evp_md_non_null_from_algorithm(algorithm) + evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm) # Create an empty certificate. x509_cert = self._lib.X509_new() - x509_cert = self._ffi.gc(x509_cert, backend._lib.X509_free) + x509_cert = self._ffi.gc(x509_cert, self._lib.X509_free) # Set the x509 version. res = self._lib.X509_set_version(x509_cert, builder._version.value) @@ -813,21 +1049,21 @@ def create_x509_certificate(self, builder, private_key, algorithm): # Set the "not before" time. self._set_asn1_time( - self._lib.X509_get_notBefore(x509_cert), builder._not_valid_before + self._lib.X509_getm_notBefore(x509_cert), builder._not_valid_before ) # Set the "not after" time. self._set_asn1_time( - self._lib.X509_get_notAfter(x509_cert), builder._not_valid_after + self._lib.X509_getm_notAfter(x509_cert), builder._not_valid_after ) # Add extensions. self._create_x509_extensions( extensions=builder._extensions, - handlers=_EXTENSION_ENCODE_HANDLERS, + handlers=self._extension_encode_handlers, x509_obj=x509_cert, add_func=self._lib.X509_add_ext, - gc=True + gc=True, ) # Set the issuer name. @@ -837,26 +1073,27 @@ def create_x509_certificate(self, builder, private_key, algorithm): self.openssl_assert(res == 1) # Sign the certificate with the issuer's private key. - res = self._lib.X509_sign( - x509_cert, private_key._evp_pkey, evp_md - ) + res = self._lib.X509_sign(x509_cert, private_key._evp_pkey, evp_md) if res == 0: - errors = self._consume_errors() - self.openssl_assert( - errors[0]._lib_reason_match( - self._lib.ERR_LIB_RSA, - self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY - ) - ) - raise ValueError("Digest too big for RSA key") + errors = self._consume_errors_with_text() + raise ValueError("Signing failed", errors) return _Certificate(self, x509_cert) + def _evp_md_x509_null_if_eddsa(self, private_key, algorithm): + if isinstance( + private_key, (ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey) + ): + # OpenSSL requires us to pass NULL for EVP_MD for ed25519/ed448 + return self._ffi.NULL + else: + return self._evp_md_non_null_from_algorithm(algorithm) + def _set_asn1_time(self, asn1_time, time): if time.year >= 2050: - asn1_str = time.strftime('%Y%m%d%H%M%SZ').encode('ascii') + asn1_str = time.strftime("%Y%m%d%H%M%SZ").encode("ascii") else: - asn1_str = time.strftime('%y%m%d%H%M%SZ').encode('ascii') + asn1_str = time.strftime("%y%m%d%H%M%SZ").encode("ascii") res = self._lib.ASN1_TIME_set_string(asn1_time, asn1_str) self.openssl_assert(res == 1) @@ -869,23 +1106,14 @@ def _create_asn1_time(self, time): def create_x509_crl(self, builder, private_key, algorithm): if not isinstance(builder, x509.CertificateRevocationListBuilder): - raise TypeError('Builder type mismatch.') - if not isinstance(algorithm, hashes.HashAlgorithm): - raise TypeError('Algorithm must be a registered hash algorithm.') + raise TypeError("Builder type mismatch.") + self._x509_check_signature_params(private_key, algorithm) - if ( - isinstance(algorithm, hashes.MD5) and not - isinstance(private_key, rsa.RSAPrivateKey) - ): - raise ValueError( - "MD5 is not a supported hash algorithm for EC/DSA CRLs" - ) - - evp_md = self._evp_md_non_null_from_algorithm(algorithm) + evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm) # Create an empty CRL. x509_crl = self._lib.X509_CRL_new() - x509_crl = self._ffi.gc(x509_crl, backend._lib.X509_CRL_free) + x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free) # Set the x509 CRL version. We only support v2 (integer value 1). res = self._lib.X509_CRL_set_version(x509_crl, 1) @@ -910,44 +1138,33 @@ def create_x509_crl(self, builder, private_key, algorithm): # Add extensions. self._create_x509_extensions( extensions=builder._extensions, - handlers=_CRL_EXTENSION_ENCODE_HANDLERS, + handlers=self._crl_extension_encode_handlers, x509_obj=x509_crl, add_func=self._lib.X509_CRL_add_ext, - gc=True + gc=True, ) # add revoked certificates for revoked_cert in builder._revoked_certificates: # Duplicating because the X509_CRL takes ownership and will free # this memory when X509_CRL_free is called. - revoked = self._lib.Cryptography_X509_REVOKED_dup( - revoked_cert._x509_revoked - ) + revoked = self._lib.X509_REVOKED_dup(revoked_cert._x509_revoked) self.openssl_assert(revoked != self._ffi.NULL) res = self._lib.X509_CRL_add0_revoked(x509_crl, revoked) self.openssl_assert(res == 1) - res = self._lib.X509_CRL_sign( - x509_crl, private_key._evp_pkey, evp_md - ) + res = self._lib.X509_CRL_sign(x509_crl, private_key._evp_pkey, evp_md) if res == 0: - errors = self._consume_errors() - self.openssl_assert( - errors[0]._lib_reason_match( - self._lib.ERR_LIB_RSA, - self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY - ) - ) - raise ValueError("Digest too big for RSA key") + errors = self._consume_errors_with_text() + raise ValueError("Signing failed", errors) return _CertificateRevocationList(self, x509_crl) - def _create_x509_extensions(self, extensions, handlers, x509_obj, - add_func, gc): + def _create_x509_extensions( + self, extensions, handlers, x509_obj, add_func, gc + ): for i, extension in enumerate(extensions): - x509_extension = self._create_x509_extension( - handlers, extension - ) + x509_extension = self._create_x509_extension(handlers, extension) self.openssl_assert(x509_extension != self._ffi.NULL) if gc: @@ -968,33 +1185,38 @@ def _create_x509_extension(self, handlers, extension): value = _encode_asn1_str_gc(self, extension.value.value) return self._create_raw_x509_extension(extension, value) elif isinstance(extension.value, x509.TLSFeature): - asn1 = _Integers([x.value for x in extension.value]).dump() + asn1 = encode_der( + SEQUENCE, + *[ + encode_der(INTEGER, encode_der_integer(x.value)) + for x in extension.value + ] + ) value = _encode_asn1_str_gc(self, asn1) return self._create_raw_x509_extension(extension, value) elif isinstance(extension.value, x509.PrecertPoison): - asn1 = asn1crypto.core.Null().dump() - value = _encode_asn1_str_gc(self, asn1) + value = _encode_asn1_str_gc(self, encode_der(NULL)) return self._create_raw_x509_extension(extension, value) else: try: encode = handlers[extension.oid] except KeyError: raise NotImplementedError( - 'Extension not supported: {0}'.format(extension.oid) + "Extension not supported: {}".format(extension.oid) ) ext_struct = encode(self, extension.value) nid = self._lib.OBJ_txt2nid( extension.oid.dotted_string.encode("ascii") ) - backend.openssl_assert(nid != self._lib.NID_undef) + self.openssl_assert(nid != self._lib.NID_undef) return self._lib.X509V3_EXT_i2d( nid, 1 if extension.critical else 0, ext_struct ) def create_x509_revoked_certificate(self, builder): if not isinstance(builder, x509.RevokedCertificateBuilder): - raise TypeError('Builder type mismatch.') + raise TypeError("Builder type mismatch.") x509_revoked = self._lib.X509_REVOKED_new() self.openssl_assert(x509_revoked != self._ffi.NULL) @@ -1010,10 +1232,10 @@ def create_x509_revoked_certificate(self, builder): # add CRL entry extensions self._create_x509_extensions( extensions=builder._extensions, - handlers=_CRL_ENTRY_EXTENSION_ENCODE_HANDLERS, + handlers=self._crl_entry_extension_encode_handlers, x509_obj=x509_revoked, add_func=self._lib.X509_REVOKED_add_ext, - gc=True + gc=True, ) return _RevokedCertificate(self, None, x509_revoked) @@ -1054,7 +1276,8 @@ def load_pem_parameters(self, data): 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) + 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) @@ -1119,9 +1342,7 @@ def load_der_public_key(self, data): def load_der_parameters(self, data): mem_bio = self._bytes_to_bio(data) - dh_cdata = self._lib.d2i_DHparams_bio( - mem_bio.bio, self._ffi.NULL - ) + 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) @@ -1244,7 +1465,7 @@ def _load_key(self, openssl_read_func, convert_func, data, password): else: assert userdata.error == -2 raise ValueError( - "Passwords longer than {0} bytes are not supported " + "Passwords longer than {} bytes are not supported " "by this backend.".format(userdata.maxsize - 1) ) else: @@ -1254,12 +1475,12 @@ def _load_key(self, openssl_read_func, convert_func, data, password): if password is not None and userdata.called == 0: raise TypeError( - "Password was given but private key is not encrypted.") + "Password was given but private key is not encrypted." + ) assert ( - (password is not None and userdata.called == 1) or - password is None - ) + password is not None and userdata.called == 1 + ) or password is None return convert_func(evp_pkey) @@ -1269,32 +1490,28 @@ def _handle_key_loading_error(self): if not errors: raise ValueError("Could not deserialize key data.") - elif ( - errors[0]._lib_reason_match( - self._lib.ERR_LIB_EVP, self._lib.EVP_R_BAD_DECRYPT - ) or errors[0]._lib_reason_match( - self._lib.ERR_LIB_PKCS12, - self._lib.PKCS12_R_PKCS12_CIPHERFINAL_ERROR - ) + elif errors[0]._lib_reason_match( + self._lib.ERR_LIB_EVP, self._lib.EVP_R_BAD_DECRYPT + ) or errors[0]._lib_reason_match( + self._lib.ERR_LIB_PKCS12, + self._lib.PKCS12_R_PKCS12_CIPHERFINAL_ERROR, ): raise ValueError("Bad decrypt. Incorrect password?") - elif ( - errors[0]._lib_reason_match( - self._lib.ERR_LIB_EVP, self._lib.EVP_R_UNKNOWN_PBE_ALGORITHM - ) or errors[0]._lib_reason_match( - self._lib.ERR_LIB_PEM, self._lib.PEM_R_UNSUPPORTED_ENCRYPTION - ) + elif errors[0]._lib_reason_match( + self._lib.ERR_LIB_EVP, self._lib.EVP_R_UNKNOWN_PBE_ALGORITHM + ) or errors[0]._lib_reason_match( + self._lib.ERR_LIB_PEM, self._lib.PEM_R_UNSUPPORTED_ENCRYPTION ): raise UnsupportedAlgorithm( "PEM data is encrypted with an unsupported cipher", - _Reasons.UNSUPPORTED_CIPHER + _Reasons.UNSUPPORTED_CIPHER, ) elif any( error._lib_reason_match( self._lib.ERR_LIB_EVP, - self._lib.EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM + self._lib.EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM, ) for error in errors ): @@ -1317,14 +1534,7 @@ def elliptic_curve_supported(self, curve): group = self._lib.EC_GROUP_new_by_curve_name(curve_nid) if group == self._ffi.NULL: - errors = self._consume_errors() - self.openssl_assert( - curve_nid == self._lib.NID_undef or - errors[0]._lib_reason_match( - self._lib.ERR_LIB_EC, - self._lib.EC_R_UNKNOWN_GROUP - ) - ) + self._consume_errors() return False else: self.openssl_assert(curve_nid != self._lib.NID_undef) @@ -1356,8 +1566,8 @@ def generate_elliptic_curve_private_key(self, curve): return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) else: raise UnsupportedAlgorithm( - "Backend object does not support {0}.".format(curve.name), - _Reasons.UNSUPPORTED_ELLIPTIC_CURVE + "Backend object does not support {}.".format(curve.name), + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE, ) def load_elliptic_curve_private_numbers(self, numbers): @@ -1372,7 +1582,8 @@ def load_elliptic_curve_private_numbers(self, numbers): self.openssl_assert(res == 1) ec_cdata = self._ec_key_set_public_key_affine_coordinates( - ec_cdata, public.x, public.y) + ec_cdata, public.x, public.y + ) evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) @@ -1381,7 +1592,8 @@ def load_elliptic_curve_private_numbers(self, numbers): def load_elliptic_curve_public_numbers(self, numbers): ec_cdata = self._ec_key_new_by_curve(numbers.curve) ec_cdata = self._ec_key_set_public_key_affine_coordinates( - ec_cdata, numbers.x, numbers.y) + ec_cdata, numbers.x, numbers.y + ) evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) @@ -1419,8 +1631,9 @@ def derive_elliptic_curve_private_key(self, private_value, curve): value = self._ffi.gc(value, self._lib.BN_clear_free) with self._tmp_bn_ctx() as bn_ctx: - res = self._lib.EC_POINT_mul(group, point, value, self._ffi.NULL, - self._ffi.NULL, bn_ctx) + res = self._lib.EC_POINT_mul( + group, point, value, self._ffi.NULL, self._ffi.NULL, bn_ctx + ) self.openssl_assert(res == 1) bn_x = self._lib.BN_CTX_get(bn_ctx) @@ -1442,8 +1655,19 @@ def derive_elliptic_curve_private_key(self, private_value, curve): def _ec_key_new_by_curve(self, curve): curve_nid = self._elliptic_curve_to_nid(curve) + return self._ec_key_new_by_curve_nid(curve_nid) + + def _ec_key_new_by_curve_nid(self, curve_nid): ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) self.openssl_assert(ec_cdata != self._ffi.NULL) + # Setting the ASN.1 flag to OPENSSL_EC_NAMED_CURVE is + # only necessary on OpenSSL 1.0.2t/u. Once we drop support for 1.0.2 + # we can remove this as it's done automatically when getting an EC_KEY + # from new_by_curve_name + # CRYPTOGRAPHY_OPENSSL_102U_OR_GREATER + self._lib.EC_KEY_set_asn1_flag( + ec_cdata, backend._lib.OPENSSL_EC_NAMED_CURVE + ) return self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) def load_der_ocsp_request(self, data): @@ -1472,15 +1696,13 @@ def create_ocsp_request(self, builder): ocsp_req = self._ffi.gc(ocsp_req, self._lib.OCSP_REQUEST_free) cert, issuer, algorithm = builder._request evp_md = self._evp_md_non_null_from_algorithm(algorithm) - certid = self._lib.OCSP_cert_to_id( - evp_md, cert._x509, issuer._x509 - ) + certid = self._lib.OCSP_cert_to_id(evp_md, cert._x509, issuer._x509) self.openssl_assert(certid != self._ffi.NULL) onereq = self._lib.OCSP_request_add0_id(ocsp_req, certid) self.openssl_assert(onereq != self._ffi.NULL) self._create_x509_extensions( extensions=builder._extensions, - handlers=_OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS, + handlers=self._ocsp_request_extension_encode_handlers, x509_obj=ocsp_req, add_func=self._lib.OCSP_REQUEST_add_ext, gc=True, @@ -1488,6 +1710,8 @@ def create_ocsp_request(self, builder): return _OCSPRequest(self, ocsp_req) def _create_ocsp_basic_response(self, builder, private_key, algorithm): + self._x509_check_signature_params(private_key, algorithm) + basic = self._lib.OCSP_BASICRESP_new() self.openssl_assert(basic != self._ffi.NULL) basic = self._ffi.gc(basic, self._lib.OCSP_BASICRESP_free) @@ -1495,8 +1719,9 @@ def _create_ocsp_basic_response(self, builder, private_key, algorithm): builder._response._algorithm ) certid = self._lib.OCSP_cert_to_id( - evp_md, builder._response._cert._x509, - builder._response._issuer._x509 + evp_md, + builder._response._cert._x509, + builder._response._issuer._x509, ) self.openssl_assert(certid != self._ffi.NULL) certid = self._ffi.gc(certid, self._lib.OCSP_CERTID_free) @@ -1528,11 +1753,11 @@ def _create_ocsp_basic_response(self, builder, private_key, algorithm): reason, rev_time, this_update, - next_update + next_update, ) self.openssl_assert(res != self._ffi.NULL) # okay, now sign the basic structure - evp_md = self._evp_md_non_null_from_algorithm(algorithm) + evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm) responder_cert, responder_encoding = builder._responder_id flags = self._lib.OCSP_NOCERTS if responder_encoding is ocsp.OCSPResponderEncoding.HASH: @@ -1545,30 +1770,33 @@ def _create_ocsp_basic_response(self, builder, private_key, algorithm): self._create_x509_extensions( extensions=builder._extensions, - handlers=_OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS, + handlers=self._ocsp_basicresp_extension_encode_handlers, x509_obj=basic, add_func=self._lib.OCSP_BASICRESP_add_ext, gc=True, ) res = self._lib.OCSP_basic_sign( - basic, responder_cert._x509, private_key._evp_pkey, - evp_md, self._ffi.NULL, flags + basic, + responder_cert._x509, + private_key._evp_pkey, + evp_md, + self._ffi.NULL, + flags, ) if res != 1: - errors = self._consume_errors() - self.openssl_assert( - errors[0]._lib_reason_match( - self._lib.ERR_LIB_X509, - self._lib.X509_R_KEY_VALUES_MISMATCH - ) + errors = self._consume_errors_with_text() + raise ValueError( + "Error while signing. responder_cert must be signed " + "by private_key", + errors, ) - raise ValueError("responder_cert must be signed by private_key") return basic - def create_ocsp_response(self, response_status, builder, private_key, - algorithm): + def create_ocsp_response( + self, response_status, builder, private_key, algorithm + ): if response_status is ocsp.OCSPResponseStatus.SUCCESSFUL: basic = self._create_ocsp_basic_response( builder, private_key, algorithm @@ -1584,9 +1812,8 @@ def create_ocsp_response(self, response_status, builder, private_key, return _OCSPResponse(self, ocsp_resp) def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve): - return ( - self.elliptic_curve_supported(curve) and - isinstance(algorithm, ec.ECDH) + return self.elliptic_curve_supported(curve) and isinstance( + algorithm, ec.ECDH ) def _ec_cdata_to_evp_pkey(self, ec_cdata): @@ -1600,18 +1827,15 @@ def _elliptic_curve_to_nid(self, curve): Get the NID for a curve name. """ - curve_aliases = { - "secp192r1": "prime192v1", - "secp256r1": "prime256v1" - } + curve_aliases = {"secp192r1": "prime192v1", "secp256r1": "prime256v1"} curve_name = curve_aliases.get(curve.name, curve.name) curve_nid = self._lib.OBJ_sn2nid(curve_name.encode()) if curve_nid == self._lib.NID_undef: raise UnsupportedAlgorithm( - "{0} is not a supported elliptic curve".format(curve.name), - _Reasons.UNSUPPORTED_ELLIPTIC_CURVE + "{} is not a supported elliptic curve".format(curve.name), + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE, ) return curve_nid @@ -1674,47 +1898,32 @@ def _ec_key_set_public_key_affine_coordinates(self, ctx, x, y): return ctx - def _private_key_bytes(self, encoding, format, encryption_algorithm, - evp_pkey, cdata): + def _private_key_bytes( + self, encoding, format, encryption_algorithm, key, evp_pkey, cdata + ): + # validate argument types + if not isinstance(encoding, serialization.Encoding): + raise TypeError("encoding must be an item from the Encoding enum") if not isinstance(format, serialization.PrivateFormat): raise TypeError( "format must be an item from the PrivateFormat enum" ) - - # X9.62 encoding is only valid for EC public keys - if encoding is serialization.Encoding.X962: - raise ValueError("X9.62 format is only valid for EC public keys") - - # Raw format and encoding are only valid for X25519, Ed25519, X448, and - # Ed448 keys. We capture those cases before this method is called so if - # we see those enum values here it means the caller has passed them to - # a key that doesn't support raw type - if format is serialization.PrivateFormat.Raw: - raise ValueError("raw format is invalid with this key or encoding") - - if encoding is serialization.Encoding.Raw: - raise ValueError("raw encoding is invalid with this key or format") - - if not isinstance(encryption_algorithm, - serialization.KeySerializationEncryption): + if not isinstance( + encryption_algorithm, serialization.KeySerializationEncryption + ): raise TypeError( "Encryption algorithm must be a KeySerializationEncryption " "instance" ) + # validate password if isinstance(encryption_algorithm, serialization.NoEncryption): password = b"" - passlen = 0 - evp_cipher = self._ffi.NULL - elif isinstance(encryption_algorithm, - serialization.BestAvailableEncryption): - # This is a curated value that we will update over time. - evp_cipher = self._lib.EVP_get_cipherbyname( - b"aes-256-cbc" - ) + elif isinstance( + encryption_algorithm, serialization.BestAvailableEncryption + ): password = encryption_algorithm.password - passlen = len(password) - if passlen > 1023: + if len(password) > 1023: raise ValueError( "Passwords longer than 1023 bytes are not supported by " "this backend" @@ -1722,183 +1931,156 @@ def _private_key_bytes(self, encoding, format, encryption_algorithm, else: raise ValueError("Unsupported encryption type") - key_type = self._lib.EVP_PKEY_id(evp_pkey) - if encoding is serialization.Encoding.PEM: - if format is serialization.PrivateFormat.PKCS8: + # PKCS8 + PEM/DER + if format is serialization.PrivateFormat.PKCS8: + if encoding is serialization.Encoding.PEM: write_bio = self._lib.PEM_write_bio_PKCS8PrivateKey - key = evp_pkey + elif encoding is serialization.Encoding.DER: + write_bio = self._lib.i2d_PKCS8PrivateKey_bio else: - assert format is serialization.PrivateFormat.TraditionalOpenSSL + raise ValueError("Unsupported encoding for PKCS8") + return self._private_key_bytes_via_bio( + write_bio, evp_pkey, password + ) + + # TraditionalOpenSSL + PEM/DER + if format is serialization.PrivateFormat.TraditionalOpenSSL: + if self._fips_enabled and not isinstance( + encryption_algorithm, serialization.NoEncryption + ): + raise ValueError( + "Encrypted traditional OpenSSL format is not " + "supported in FIPS mode." + ) + key_type = self._lib.EVP_PKEY_id(evp_pkey) + + 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 + elif key_type == self._lib.EVP_PKEY_EC: write_bio = self._lib.PEM_write_bio_ECPrivateKey + else: + raise ValueError( + "Unsupported key type for TraditionalOpenSSL" + ) + return self._private_key_bytes_via_bio( + write_bio, cdata, password + ) - key = cdata - elif encoding is serialization.Encoding.DER: - if format is serialization.PrivateFormat.TraditionalOpenSSL: - if not isinstance( - encryption_algorithm, serialization.NoEncryption - ): + if encoding is serialization.Encoding.DER: + if password: raise ValueError( "Encryption is not supported for DER encoded " "traditional OpenSSL keys" ) + 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 + elif key_type == self._lib.EVP_PKEY_DSA: + write_bio = self._lib.i2d_DSAPrivateKey_bio + else: + raise ValueError( + "Unsupported key type for TraditionalOpenSSL" + ) + return self._bio_func_output(write_bio, cdata) - return self._private_key_bytes_traditional_der(key_type, cdata) - else: - assert format is serialization.PrivateFormat.PKCS8 - write_bio = self._lib.i2d_PKCS8PrivateKey_bio - key = evp_pkey + raise ValueError("Unsupported encoding for TraditionalOpenSSL") + + # OpenSSH + PEM + if format is serialization.PrivateFormat.OpenSSH: + if encoding is serialization.Encoding.PEM: + return ssh.serialize_ssh_private_key(key, password) + + raise ValueError( + "OpenSSH private key format can only be used" + " with PEM encoding" + ) + + # Anything that key-specific code was supposed to handle earlier, + # like Raw. + raise ValueError("format is invalid with this key") + + def _private_key_bytes_via_bio(self, write_bio, evp_pkey, password): + if not password: + evp_cipher = self._ffi.NULL else: - raise TypeError("encoding must be Encoding.PEM or Encoding.DER") + # This is a curated value that we will update over time. + evp_cipher = self._lib.EVP_get_cipherbyname(b"aes-256-cbc") - bio = self._create_mem_bio_gc() - res = write_bio( - bio, - key, + return self._bio_func_output( + write_bio, + evp_pkey, evp_cipher, password, - passlen, + len(password), + self._ffi.NULL, self._ffi.NULL, - self._ffi.NULL ) - self.openssl_assert(res == 1) - return self._read_mem_bio(bio) - - def _private_key_bytes_traditional_der(self, key_type, cdata): - 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: - self.openssl_assert(key_type == self._lib.EVP_PKEY_DSA) - write_bio = self._lib.i2d_DSAPrivateKey_bio + def _bio_func_output(self, write_bio, *args): bio = self._create_mem_bio_gc() - res = write_bio(bio, cdata) + res = write_bio(bio, *args) self.openssl_assert(res == 1) return self._read_mem_bio(bio) def _public_key_bytes(self, encoding, format, key, evp_pkey, cdata): if not isinstance(encoding, serialization.Encoding): raise TypeError("encoding must be an item from the Encoding enum") + if not isinstance(format, serialization.PublicFormat): + raise TypeError( + "format must be an item from the PublicFormat enum" + ) - # Compressed/UncompressedPoint are only valid for EC keys and those - # cases are handled by the ECPublicKey public_bytes method before this - # method is called - if format in (serialization.PublicFormat.UncompressedPoint, - serialization.PublicFormat.CompressedPoint): - raise ValueError("Point formats are not valid for this key type") - - # Raw format and encoding are only valid for X25519, Ed25519, X448, and - # Ed448 keys. We capture those cases before this method is called so if - # we see those enum values here it means the caller has passed them to - # a key that doesn't support raw type - if format is serialization.PublicFormat.Raw: - raise ValueError("raw format is invalid with this key or encoding") - - if encoding is serialization.Encoding.Raw: - raise ValueError("raw encoding is invalid with this key or format") - - if ( - format is serialization.PublicFormat.OpenSSH or - encoding is serialization.Encoding.OpenSSH - ): - if ( - format is not serialization.PublicFormat.OpenSSH or - encoding is not serialization.Encoding.OpenSSH - ): - raise ValueError( - "OpenSSH format must be used with OpenSSH encoding" - ) - return self._openssh_public_key_bytes(key) - elif format is serialization.PublicFormat.SubjectPublicKeyInfo: + # SubjectPublicKeyInfo + PEM/DER + if format is serialization.PublicFormat.SubjectPublicKeyInfo: if encoding is serialization.Encoding.PEM: write_bio = self._lib.PEM_write_bio_PUBKEY - else: - assert encoding is serialization.Encoding.DER + elif encoding is serialization.Encoding.DER: write_bio = self._lib.i2d_PUBKEY_bio + else: + raise ValueError( + "SubjectPublicKeyInfo works only with PEM or DER encoding" + ) + return self._bio_func_output(write_bio, evp_pkey) - key = evp_pkey - elif format is serialization.PublicFormat.PKCS1: + # PKCS1 + PEM/DER + if format is serialization.PublicFormat.PKCS1: # Only RSA is supported here. - assert self._lib.EVP_PKEY_id(evp_pkey) == self._lib.EVP_PKEY_RSA + key_type = self._lib.EVP_PKEY_id(evp_pkey) + if key_type != self._lib.EVP_PKEY_RSA: + raise ValueError("PKCS1 format is supported only for RSA keys") + if encoding is serialization.Encoding.PEM: write_bio = self._lib.PEM_write_bio_RSAPublicKey - else: - assert encoding is serialization.Encoding.DER + elif encoding is serialization.Encoding.DER: write_bio = self._lib.i2d_RSAPublicKey_bio + else: + raise ValueError("PKCS1 works only with PEM or DER encoding") + return self._bio_func_output(write_bio, cdata) - key = cdata - else: - raise TypeError( - "format must be an item from the PublicFormat enum" - ) - - bio = self._create_mem_bio_gc() - res = write_bio(bio, key) - self.openssl_assert(res == 1) - return self._read_mem_bio(bio) + # OpenSSH + OpenSSH + if format is serialization.PublicFormat.OpenSSH: + if encoding is serialization.Encoding.OpenSSH: + return ssh.serialize_ssh_public_key(key) - def _openssh_public_key_bytes(self, key): - if isinstance(key, rsa.RSAPublicKey): - public_numbers = key.public_numbers() - return b"ssh-rsa " + base64.b64encode( - ssh._ssh_write_string(b"ssh-rsa") + - ssh._ssh_write_mpint(public_numbers.e) + - ssh._ssh_write_mpint(public_numbers.n) - ) - elif isinstance(key, dsa.DSAPublicKey): - public_numbers = key.public_numbers() - parameter_numbers = public_numbers.parameter_numbers - return b"ssh-dss " + base64.b64encode( - ssh._ssh_write_string(b"ssh-dss") + - ssh._ssh_write_mpint(parameter_numbers.p) + - ssh._ssh_write_mpint(parameter_numbers.q) + - ssh._ssh_write_mpint(parameter_numbers.g) + - ssh._ssh_write_mpint(public_numbers.y) + raise ValueError( + "OpenSSH format must be used with OpenSSH encoding" ) - else: - assert isinstance(key, ec.EllipticCurvePublicKey) - public_numbers = key.public_numbers() - try: - curve_name = { - ec.SECP256R1: b"nistp256", - ec.SECP384R1: b"nistp384", - ec.SECP521R1: b"nistp521", - }[type(public_numbers.curve)] - except KeyError: - raise ValueError( - "Only SECP256R1, SECP384R1, and SECP521R1 curves are " - "supported by the SSH public key format" - ) - point = key.public_bytes( - serialization.Encoding.X962, - serialization.PublicFormat.UncompressedPoint - ) - return b"ecdsa-sha2-" + curve_name + b" " + base64.b64encode( - ssh._ssh_write_string(b"ecdsa-sha2-" + curve_name) + - ssh._ssh_write_string(curve_name) + - ssh._ssh_write_string(point) - ) + # Anything that key-specific code was supposed to handle earlier, + # like Raw, CompressedPoint, UncompressedPoint + raise ValueError("format is invalid with this key") def _parameter_bytes(self, encoding, format, cdata): if encoding is serialization.Encoding.OpenSSH: - raise TypeError( - "OpenSSH encoding is not supported" - ) + raise TypeError("OpenSSH encoding is not supported") # Only DH is supported here currently. q = self._ffi.new("BIGNUM **") - self._lib.DH_get0_pqg(cdata, - self._ffi.NULL, - q, - self._ffi.NULL) + self._lib.DH_get0_pqg(cdata, self._ffi.NULL, q, self._ffi.NULL) if encoding is serialization.Encoding.PEM: if q[0] != self._ffi.NULL: write_bio = self._lib.PEM_write_bio_DHxparams @@ -1929,10 +2111,7 @@ def generate_dh_parameters(self, generator, key_size): 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 + dh_param_cdata, key_size, generator, self._ffi.NULL ) self.openssl_assert(res == 1) @@ -1956,7 +2135,8 @@ def generate_dh_private_key(self, parameters): def generate_dh_private_key_and_parameters(self, generator, key_size): return self.generate_dh_private_key( - self.generate_dh_parameters(generator, key_size)) + self.generate_dh_parameters(generator, key_size) + ) def load_dh_private_numbers(self, numbers): parameter_numbers = numbers.public_numbers.parameter_numbers @@ -1995,12 +2175,10 @@ def load_dh_private_numbers(self, numbers): # 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 + parameter_numbers.g == 2 + and codes[0] ^ self._lib.DH_NOT_SUITABLE_GENERATOR == 0 ): - raise ValueError( - "DH private numbers did not pass safety checks." - ) + raise ValueError("DH private numbers did not pass safety checks.") evp_pkey = self._dh_cdata_to_evp_pkey(dh_cdata) @@ -2095,11 +2273,11 @@ def x25519_load_public_bytes(self, data): evp_pkey = self._create_evp_pkey_gc() res = self._lib.EVP_PKEY_set_type(evp_pkey, self._lib.NID_X25519) - backend.openssl_assert(res == 1) + self.openssl_assert(res == 1) res = self._lib.EVP_PKEY_set1_tls_encodedpoint( evp_pkey, data, len(data) ) - backend.openssl_assert(res == 1) + self.openssl_assert(res == 1) return _X25519PublicKey(self, evp_pkey) def x25519_load_private_bytes(self, data): @@ -2127,7 +2305,7 @@ def x25519_load_private_bytes(self, data): ba[0:16] = pkcs8_prefix ba[16:] = data bio = self._bytes_to_bio(ba) - evp_pkey = backend._lib.d2i_PrivateKey_bio(bio.bio, self._ffi.NULL) + evp_pkey = self._lib.d2i_PrivateKey_bio(bio.bio, self._ffi.NULL) self.openssl_assert(evp_pkey != self._ffi.NULL) evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) @@ -2154,6 +2332,8 @@ def x25519_generate_key(self): return _X25519PrivateKey(self, evp_pkey) def x25519_supported(self): + if self._fips_enabled: + return False return self._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER def x448_load_public_bytes(self, data): @@ -2184,44 +2364,115 @@ def x448_generate_key(self): return _X448PrivateKey(self, evp_pkey) def x448_supported(self): + if self._fips_enabled: + return False return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 + def ed25519_supported(self): + if self._fips_enabled: + return False + return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B + + def ed25519_load_public_bytes(self, data): + utils._check_bytes("data", data) + + if len(data) != ed25519._ED25519_KEY_SIZE: + raise ValueError("An Ed25519 public key is 32 bytes long") + + evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( + self._lib.NID_ED25519, self._ffi.NULL, data, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed25519PublicKey(self, evp_pkey) + + def ed25519_load_private_bytes(self, data): + if len(data) != ed25519._ED25519_KEY_SIZE: + raise ValueError("An Ed25519 private key is 32 bytes long") + + utils._check_byteslike("data", data) + data_ptr = self._ffi.from_buffer(data) + evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( + self._lib.NID_ED25519, self._ffi.NULL, data_ptr, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed25519PrivateKey(self, evp_pkey) + + def ed25519_generate_key(self): + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED25519) + return _Ed25519PrivateKey(self, evp_pkey) + + def ed448_supported(self): + if self._fips_enabled: + return False + return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B + + def ed448_load_public_bytes(self, data): + utils._check_bytes("data", data) + if len(data) != _ED448_KEY_SIZE: + raise ValueError("An Ed448 public key is 57 bytes long") + + evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( + self._lib.NID_ED448, self._ffi.NULL, data, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed448PublicKey(self, evp_pkey) + + def ed448_load_private_bytes(self, data): + utils._check_byteslike("data", data) + if len(data) != _ED448_KEY_SIZE: + raise ValueError("An Ed448 private key is 57 bytes long") + + data_ptr = self._ffi.from_buffer(data) + evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( + self._lib.NID_ED448, self._ffi.NULL, data_ptr, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed448PrivateKey(self, evp_pkey) + + def ed448_generate_key(self): + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED448) + return _Ed448PrivateKey(self, evp_pkey) + def derive_scrypt(self, key_material, salt, length, n, r, p): buf = self._ffi.new("unsigned char[]", length) key_material_ptr = self._ffi.from_buffer(key_material) res = self._lib.EVP_PBE_scrypt( - key_material_ptr, len(key_material), salt, len(salt), n, r, p, - scrypt._MEM_LIMIT, buf, length + key_material_ptr, + len(key_material), + salt, + len(salt), + n, + r, + p, + scrypt._MEM_LIMIT, + buf, + length, ) if res != 1: - errors = self._consume_errors() - if not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111: - # This error is only added to the stack in 1.1.1+ - self.openssl_assert( - errors[0]._lib_reason_match( - self._lib.ERR_LIB_EVP, - self._lib.ERR_R_MALLOC_FAILURE - ) or - errors[0]._lib_reason_match( - self._lib.ERR_LIB_EVP, - self._lib.EVP_R_MEMORY_LIMIT_EXCEEDED - ) - ) - + errors = self._consume_errors_with_text() # memory required formula explained here: # https://blog.filippo.io/the-scrypt-parameters/ - min_memory = 128 * n * r // (1024**2) + min_memory = 128 * n * r // (1024 ** 2) raise MemoryError( "Not enough memory to derive key. These parameters require" - " {} MB of memory.".format(min_memory) + " {} MB of memory.".format(min_memory), + errors, ) return self._ffi.buffer(buf)[:] def aead_cipher_supported(self, cipher): cipher_name = aead._aead_cipher_name(cipher) - return ( - self._lib.EVP_get_cipherbyname(cipher_name) != self._ffi.NULL - ) + if self._fips_enabled and cipher_name not in self._fips_aead: + return False + return self._lib.EVP_get_cipherbyname(cipher_name) != self._ffi.NULL @contextlib.contextmanager def _zeroed_bytearray(self, length): @@ -2306,12 +2557,216 @@ def load_key_and_certificates_from_pkcs12(self, data, password): num = self._lib.sk_X509_num(sk_x509_ptr[0]) for i in range(num): x509 = self._lib.sk_X509_value(sk_x509, i) - x509 = self._ffi.gc(x509, self._lib.X509_free) self.openssl_assert(x509 != self._ffi.NULL) + x509 = self._ffi.gc(x509, self._lib.X509_free) additional_certificates.append(_Certificate(self, x509)) return (key, cert, additional_certificates) + def serialize_key_and_certificates_to_pkcs12( + self, name, key, cert, cas, encryption_algorithm + ): + password = None + if name is not None: + utils._check_bytes("name", name) + + if isinstance(encryption_algorithm, serialization.NoEncryption): + nid_cert = -1 + nid_key = -1 + pkcs12_iter = 0 + mac_iter = 0 + elif isinstance( + encryption_algorithm, serialization.BestAvailableEncryption + ): + # PKCS12 encryption is hopeless trash and can never be fixed. + # This is the least terrible option. + nid_cert = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC + nid_key = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC + # At least we can set this higher than OpenSSL's default + pkcs12_iter = 20000 + # mac_iter chosen for compatibility reasons, see: + # https://www.openssl.org/docs/man1.1.1/man3/PKCS12_create.html + # Did we mention how lousy PKCS12 encryption is? + mac_iter = 1 + password = encryption_algorithm.password + else: + raise ValueError("Unsupported key encryption type") + + if cas is None or len(cas) == 0: + sk_x509 = self._ffi.NULL + else: + sk_x509 = self._lib.sk_X509_new_null() + sk_x509 = self._ffi.gc(sk_x509, self._lib.sk_X509_free) + + # reverse the list when building the stack so that they're encoded + # in the order they were originally provided. it is a mystery + for ca in reversed(cas): + res = self._lib.sk_X509_push(sk_x509, ca._x509) + backend.openssl_assert(res >= 1) + + with self._zeroed_null_terminated_buf(password) as password_buf: + with self._zeroed_null_terminated_buf(name) as name_buf: + p12 = self._lib.PKCS12_create( + password_buf, + name_buf, + key._evp_pkey if key else self._ffi.NULL, + cert._x509 if cert else self._ffi.NULL, + sk_x509, + nid_key, + nid_cert, + pkcs12_iter, + mac_iter, + 0, + ) + + self.openssl_assert(p12 != self._ffi.NULL) + p12 = self._ffi.gc(p12, self._lib.PKCS12_free) + + bio = self._create_mem_bio_gc() + res = self._lib.i2d_PKCS12_bio(bio, p12) + self.openssl_assert(res > 0) + return self._read_mem_bio(bio) + + def poly1305_supported(self): + if self._fips_enabled: + return False + return self._lib.Cryptography_HAS_POLY1305 == 1 + + def create_poly1305_ctx(self, key): + 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 load_pem_pkcs7_certificates(self, data): + utils._check_bytes("data", data) + bio = self._bytes_to_bio(data) + p7 = self._lib.PEM_read_bio_PKCS7( + bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if p7 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to parse PKCS7 data") + + p7 = self._ffi.gc(p7, self._lib.PKCS7_free) + return self._load_pkcs7_certificates(p7) + + def load_der_pkcs7_certificates(self, data): + utils._check_bytes("data", data) + bio = self._bytes_to_bio(data) + p7 = self._lib.d2i_PKCS7_bio(bio.bio, self._ffi.NULL) + if p7 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to parse PKCS7 data") + + p7 = self._ffi.gc(p7, self._lib.PKCS7_free) + return self._load_pkcs7_certificates(p7) + + def _load_pkcs7_certificates(self, p7): + nid = self._lib.OBJ_obj2nid(p7.type) + self.openssl_assert(nid != self._lib.NID_undef) + if nid != self._lib.NID_pkcs7_signed: + raise UnsupportedAlgorithm( + "Only basic signed structures are currently supported. NID" + " for this data was {}".format(nid), + _Reasons.UNSUPPORTED_SERIALIZATION, + ) + + sk_x509 = p7.d.sign.cert + num = self._lib.sk_X509_num(sk_x509) + certs = [] + for i in range(num): + x509 = self._lib.sk_X509_value(sk_x509, i) + self.openssl_assert(x509 != self._ffi.NULL) + res = self._lib.X509_up_ref(x509) + # When OpenSSL is less than 1.1.0 up_ref returns the current + # refcount. On 1.1.0+ it returns 1 for success. + self.openssl_assert(res >= 1) + x509 = self._ffi.gc(x509, self._lib.X509_free) + certs.append(_Certificate(self, x509)) + + return certs + + def pkcs7_sign(self, builder, encoding, options): + bio = self._bytes_to_bio(builder._data) + init_flags = self._lib.PKCS7_PARTIAL + final_flags = 0 + + if len(builder._additional_certs) == 0: + certs = self._ffi.NULL + else: + certs = self._lib.sk_X509_new_null() + certs = self._ffi.gc(certs, self._lib.sk_X509_free) + for cert in builder._additional_certs: + res = self._lib.sk_X509_push(certs, cert._x509) + self.openssl_assert(res >= 1) + + if pkcs7.PKCS7Options.DetachedSignature in options: + # Don't embed the data in the PKCS7 structure + init_flags |= self._lib.PKCS7_DETACHED + final_flags |= self._lib.PKCS7_DETACHED + + # This just inits a structure for us. However, there + # are flags we need to set, joy. + p7 = self._lib.PKCS7_sign( + self._ffi.NULL, + self._ffi.NULL, + certs, + self._ffi.NULL, + init_flags, + ) + self.openssl_assert(p7 != self._ffi.NULL) + p7 = self._ffi.gc(p7, self._lib.PKCS7_free) + signer_flags = 0 + # These flags are configurable on a per-signature basis + # but we've deliberately chosen to make the API only allow + # setting it across all signatures for now. + if pkcs7.PKCS7Options.NoCapabilities in options: + signer_flags |= self._lib.PKCS7_NOSMIMECAP + elif pkcs7.PKCS7Options.NoAttributes in options: + signer_flags |= self._lib.PKCS7_NOATTR + + if pkcs7.PKCS7Options.NoCerts in options: + signer_flags |= self._lib.PKCS7_NOCERTS + + for certificate, private_key, hash_algorithm in builder._signers: + md = self._evp_md_non_null_from_algorithm(hash_algorithm) + p7signerinfo = self._lib.PKCS7_sign_add_signer( + p7, certificate._x509, private_key._evp_pkey, md, signer_flags + ) + self.openssl_assert(p7signerinfo != self._ffi.NULL) + + for option in options: + # DetachedSignature, NoCapabilities, and NoAttributes are already + # handled so we just need to check these last two options. + if option is pkcs7.PKCS7Options.Text: + final_flags |= self._lib.PKCS7_TEXT + elif option is pkcs7.PKCS7Options.Binary: + final_flags |= self._lib.PKCS7_BINARY + + bio_out = self._create_mem_bio_gc() + if encoding is serialization.Encoding.SMIME: + # This finalizes the structure + res = self._lib.SMIME_write_PKCS7( + bio_out, p7, bio.bio, final_flags + ) + elif encoding is serialization.Encoding.PEM: + res = self._lib.PKCS7_final(p7, bio.bio, final_flags) + self.openssl_assert(res == 1) + res = self._lib.PEM_write_bio_PKCS7_stream( + bio_out, p7, bio.bio, final_flags + ) + else: + assert encoding is serialization.Encoding.DER + # We need to call finalize here becauase i2d_PKCS7_bio does not + # finalize. + res = self._lib.PKCS7_final(p7, bio.bio, final_flags) + self.openssl_assert(res == 1) + res = self._lib.i2d_PKCS7_bio(bio_out, p7) + self.openssl_assert(res == 1) + return self._read_mem_bio(bio_out) + class GetCipherByName(object): def __init__(self, fmt): @@ -2323,7 +2778,7 @@ def __call__(self, backend, cipher, mode): def _get_xts_cipher(backend, cipher, mode): - cipher_name = "aes-{0}-xts".format(cipher.key_size // 2) + cipher_name = "aes-{}-xts".format(cipher.key_size // 2) return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) diff --git a/src/cryptography/hazmat/backends/openssl/ciphers.py b/src/cryptography/hazmat/backends/openssl/ciphers.py index 66ac5fd69aa6..1e805d235aa2 100644 --- a/src/cryptography/hazmat/backends/openssl/ciphers.py +++ b/src/cryptography/hazmat/backends/openssl/ciphers.py @@ -17,6 +17,7 @@ class _CipherContext(object): _ENCRYPT = 1 _DECRYPT = 0 + _MAX_CHUNK_SIZE = 2 ** 31 - 1 def __init__(self, backend, cipher, mode, operation): self._backend = backend @@ -40,10 +41,11 @@ def __init__(self, backend, cipher, mode, operation): adapter = registry[type(cipher), type(mode)] except KeyError: raise UnsupportedAlgorithm( - "cipher {0} in {1} mode is not supported " + "cipher {} in {} mode is not supported " "by this backend.".format( - cipher.name, mode.name if mode else mode), - _Reasons.UNSUPPORTED_CIPHER + cipher.name, mode.name if mode else mode + ), + _Reasons.UNSUPPORTED_CIPHER, ) evp_cipher = adapter(self._backend, cipher, mode) @@ -53,7 +55,7 @@ def __init__(self, backend, cipher, mode, operation): msg += "in {0.name} mode ".format(mode) msg += ( "is not supported by this backend (Your version of OpenSSL " - "may be too old. Current version: {0}.)" + "may be too old. Current version: {}.)" ).format(self._backend.openssl_version_text()) raise UnsupportedAlgorithm(msg, _Reasons.UNSUPPORTED_CIPHER) @@ -70,11 +72,14 @@ def __init__(self, backend, cipher, mode, operation): else: iv_nonce = self._backend._ffi.NULL # begin init with cipher and operation type - res = self._backend._lib.EVP_CipherInit_ex(ctx, evp_cipher, - self._backend._ffi.NULL, - self._backend._ffi.NULL, - self._backend._ffi.NULL, - operation) + res = self._backend._lib.EVP_CipherInit_ex( + ctx, + evp_cipher, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + operation, + ) self._backend.openssl_assert(res != 0) # set the key length to handle variable key ciphers res = self._backend._lib.EVP_CIPHER_CTX_set_key_length( @@ -83,26 +88,21 @@ def __init__(self, backend, cipher, mode, operation): self._backend.openssl_assert(res != 0) if isinstance(mode, modes.GCM): res = self._backend._lib.EVP_CIPHER_CTX_ctrl( - ctx, self._backend._lib.EVP_CTRL_AEAD_SET_IVLEN, - len(iv_nonce), self._backend._ffi.NULL + ctx, + self._backend._lib.EVP_CTRL_AEAD_SET_IVLEN, + len(iv_nonce), + self._backend._ffi.NULL, ) self._backend.openssl_assert(res != 0) if mode.tag is not None: res = self._backend._lib.EVP_CIPHER_CTX_ctrl( - ctx, self._backend._lib.EVP_CTRL_AEAD_SET_TAG, - len(mode.tag), mode.tag + ctx, + self._backend._lib.EVP_CTRL_AEAD_SET_TAG, + len(mode.tag), + mode.tag, ) self._backend.openssl_assert(res != 0) self._tag = mode.tag - elif ( - self._operation == self._DECRYPT and - self._backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and - not self._backend._lib.CRYPTOGRAPHY_IS_LIBRESSL - ): - raise NotImplementedError( - "delayed passing of GCM tag requires OpenSSL >= 1.0.2." - " To use this feature please update OpenSSL" - ) # pass key/iv res = self._backend._lib.EVP_CipherInit_ex( @@ -111,7 +111,7 @@ def __init__(self, backend, cipher, mode, operation): self._backend._ffi.NULL, self._backend._ffi.from_buffer(cipher.key), iv_nonce, - operation + operation, ) self._backend.openssl_assert(res != 0) # We purposely disable padding here as it's handled higher up in the @@ -125,36 +125,38 @@ def update(self, data): return bytes(buf[:n]) def update_into(self, data, buf): - if len(buf) < (len(data) + self._block_size_bytes - 1): + total_data_len = len(data) + if len(buf) < (total_data_len + self._block_size_bytes - 1): raise ValueError( - "buffer must be at least {0} bytes for this " + "buffer must be at least {} bytes for this " "payload".format(len(data) + self._block_size_bytes - 1) ) - buf = self._backend._ffi.cast( - "unsigned char *", self._backend._ffi.from_buffer(buf) - ) + data_processed = 0 + total_out = 0 outlen = self._backend._ffi.new("int *") - res = self._backend._lib.EVP_CipherUpdate( - self._ctx, buf, outlen, - self._backend._ffi.from_buffer(data), len(data) - ) - self._backend.openssl_assert(res != 0) - return outlen[0] + baseoutbuf = self._backend._ffi.from_buffer(buf) + baseinbuf = self._backend._ffi.from_buffer(data) - def finalize(self): - # OpenSSL 1.0.1 on Ubuntu 12.04 (and possibly other distributions) - # appears to have a bug where you must make at least one call to update - # even if you are only using authenticate_additional_data or the - # GCM tag will be wrong. An (empty) call to update resolves this - # and is harmless for all other versions of OpenSSL. - if isinstance(self._mode, modes.GCM): - self.update(b"") + while data_processed != total_data_len: + outbuf = baseoutbuf + total_out + inbuf = baseinbuf + data_processed + inlen = min(self._MAX_CHUNK_SIZE, total_data_len - data_processed) + res = self._backend._lib.EVP_CipherUpdate( + self._ctx, outbuf, outlen, inbuf, inlen + ) + self._backend.openssl_assert(res != 0) + data_processed += inlen + total_out += outlen[0] + + return total_out + + def finalize(self): if ( - self._operation == self._DECRYPT and - isinstance(self._mode, modes.ModeWithAuthenticationTag) and - self.tag is None + self._operation == self._DECRYPT + and isinstance(self._mode, modes.ModeWithAuthenticationTag) + and self.tag is None ): raise ValueError( "Authentication tag must be provided when decrypting." @@ -172,47 +174,44 @@ def finalize(self): self._backend.openssl_assert( errors[0]._lib_reason_match( self._backend._lib.ERR_LIB_EVP, - self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH - ) + self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH, + ), + errors=errors, ) raise ValueError( "The length of the provided data is not a multiple of " "the block length." ) - if (isinstance(self._mode, modes.GCM) and - self._operation == self._ENCRYPT): + if ( + isinstance(self._mode, modes.GCM) + and self._operation == self._ENCRYPT + ): tag_buf = self._backend._ffi.new( "unsigned char[]", self._block_size_bytes ) res = self._backend._lib.EVP_CIPHER_CTX_ctrl( - self._ctx, self._backend._lib.EVP_CTRL_AEAD_GET_TAG, - self._block_size_bytes, tag_buf + self._ctx, + self._backend._lib.EVP_CTRL_AEAD_GET_TAG, + self._block_size_bytes, + tag_buf, ) self._backend.openssl_assert(res != 0) self._tag = self._backend._ffi.buffer(tag_buf)[:] res = self._backend._lib.EVP_CIPHER_CTX_cleanup(self._ctx) self._backend.openssl_assert(res == 1) - return self._backend._ffi.buffer(buf)[:outlen[0]] + return self._backend._ffi.buffer(buf)[: outlen[0]] def finalize_with_tag(self, tag): - if ( - self._backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and - not self._backend._lib.CRYPTOGRAPHY_IS_LIBRESSL - ): - raise NotImplementedError( - "finalize_with_tag requires OpenSSL >= 1.0.2. To use this " - "method please update OpenSSL" - ) if len(tag) < self._mode._min_tag_length: raise ValueError( - "Authentication tag must be {0} bytes or longer.".format( - self._mode._min_tag_length) + "Authentication tag must be {} bytes or longer.".format( + self._mode._min_tag_length + ) ) res = self._backend._lib.EVP_CIPHER_CTX_ctrl( - self._ctx, self._backend._lib.EVP_CTRL_AEAD_SET_TAG, - len(tag), tag + self._ctx, self._backend._lib.EVP_CTRL_AEAD_SET_TAG, len(tag), tag ) self._backend.openssl_assert(res != 0) self._tag = tag @@ -221,8 +220,11 @@ def finalize_with_tag(self, tag): def authenticate_additional_data(self, data): outlen = self._backend._ffi.new("int *") res = self._backend._lib.EVP_CipherUpdate( - self._ctx, self._backend._ffi.NULL, outlen, - self._backend._ffi.from_buffer(data), len(data) + self._ctx, + self._backend._ffi.NULL, + outlen, + self._backend._ffi.from_buffer(data), + len(data), ) self._backend.openssl_assert(res != 0) diff --git a/src/cryptography/hazmat/backends/openssl/cmac.py b/src/cryptography/hazmat/backends/openssl/cmac.py index bc88f3364495..195fc230f2b2 100644 --- a/src/cryptography/hazmat/backends/openssl/cmac.py +++ b/src/cryptography/hazmat/backends/openssl/cmac.py @@ -7,18 +7,21 @@ from cryptography import utils from cryptography.exceptions import ( - InvalidSignature, UnsupportedAlgorithm, _Reasons + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, ) -from cryptography.hazmat.primitives import constant_time, mac +from cryptography.hazmat.primitives import constant_time from cryptography.hazmat.primitives.ciphers.modes import CBC -@utils.register_interface(mac.MACContext) class _CMACContext(object): def __init__(self, backend, algorithm, ctx=None): if not backend.cmac_algorithm_supported(algorithm): - raise UnsupportedAlgorithm("This backend does not support CMAC.", - _Reasons.UNSUPPORTED_CIPHER) + raise UnsupportedAlgorithm( + "This backend does not support CMAC.", + _Reasons.UNSUPPORTED_CIPHER, + ) self._backend = backend self._key = algorithm.key @@ -38,8 +41,11 @@ def __init__(self, backend, algorithm, ctx=None): key_ptr = self._backend._ffi.from_buffer(self._key) res = self._backend._lib.CMAC_Init( - ctx, key_ptr, len(self._key), - evp_cipher, self._backend._ffi.NULL + ctx, + key_ptr, + len(self._key), + evp_cipher, + self._backend._ffi.NULL, ) self._backend.openssl_assert(res == 1) @@ -54,9 +60,7 @@ def update(self, data): def finalize(self): buf = self._backend._ffi.new("unsigned char[]", self._output_length) length = self._backend._ffi.new("size_t *", self._output_length) - res = self._backend._lib.CMAC_Final( - self._ctx, buf, length - ) + res = self._backend._lib.CMAC_Final(self._ctx, buf, length) self._backend.openssl_assert(res == 1) self._ctx = None @@ -68,13 +72,9 @@ def copy(self): copied_ctx = self._backend._ffi.gc( copied_ctx, self._backend._lib.CMAC_CTX_free ) - res = self._backend._lib.CMAC_CTX_copy( - copied_ctx, self._ctx - ) + res = self._backend._lib.CMAC_CTX_copy(copied_ctx, self._ctx) self._backend.openssl_assert(res == 1) - return _CMACContext( - self._backend, self._algorithm, ctx=copied_ctx - ) + return _CMACContext(self._backend, self._algorithm, ctx=copied_ctx) def verify(self, signature): digest = self.finalize() diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index 007675d4e6eb..279b00ca5c10 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -7,23 +7,20 @@ import datetime import ipaddress -import asn1crypto.core - import six from cryptography import x509 +from cryptography.hazmat._der import DERReader, INTEGER, NULL, SEQUENCE from cryptography.x509.extensions import _TLS_FEATURE_TYPE_TO_ENUM from cryptography.x509.name import _ASN1_TYPE_TO_ENUM from cryptography.x509.oid import ( - CRLEntryExtensionOID, CertificatePoliciesOID, ExtensionOID, + CRLEntryExtensionOID, + CertificatePoliciesOID, + ExtensionOID, OCSPExtensionOID, ) -class _Integers(asn1crypto.core.SequenceOf): - _child_spec = asn1crypto.core.Integer - - def _obj2txt(backend, obj): # Set to 80 on the recommendation of # https://www.openssl.org/docs/crypto/OBJ_nid2ln.html#return_values @@ -69,7 +66,7 @@ def _decode_x509_name(backend, x509_name): attribute = _decode_x509_name_entry(backend, entry) set_id = backend._lib.Cryptography_X509_NAME_ENTRY_set(entry) if set_id != prev_set_id: - attributes.append(set([attribute])) + attributes.append({attribute}) else: # is in the same RDN a previous entry attributes[-1].add(attribute) @@ -124,10 +121,10 @@ def _decode_general_name(backend, gn): # netmask. To handle this we convert the netmask to integer, then # find the first 0 bit, which will be the prefix. If another 1 # bit is present after that the netmask is invalid. - base = ipaddress.ip_address(data[:data_len // 2]) - netmask = ipaddress.ip_address(data[data_len // 2:]) + base = ipaddress.ip_address(data[: data_len // 2]) + netmask = ipaddress.ip_address(data[data_len // 2 :]) bits = bin(int(netmask))[2:] - prefix = bits.find('0') + prefix = bits.find("0") # If no 0 bits are found it is a /32 or /128 if prefix == -1: prefix = len(bits) @@ -135,7 +132,7 @@ def _decode_general_name(backend, gn): if "1" in bits[prefix:]: raise ValueError("Invalid netmask") - ip = ipaddress.ip_network(base.exploded + u"/{0}".format(prefix)) + ip = ipaddress.ip_network(base.exploded + u"/{}".format(prefix)) else: ip = ipaddress.ip_address(data) @@ -160,10 +157,10 @@ def _decode_general_name(backend, gn): else: # x400Address or ediPartyName raise x509.UnsupportedGeneralNameType( - "{0} is not a supported type".format( + "{} is not a supported type".format( x509._GENERAL_NAMES.get(gn.type, gn.type) ), - gn.type + gn.type, ) @@ -184,48 +181,57 @@ def _decode_delta_crl_indicator(backend, ext): class _X509ExtensionParser(object): - def __init__(self, ext_count, get_ext, handlers): + def __init__(self, backend, ext_count, get_ext, handlers): self.ext_count = ext_count self.get_ext = get_ext self.handlers = handlers + self._backend = backend - def parse(self, backend, x509_obj): + def parse(self, x509_obj): extensions = [] seen_oids = set() - for i in range(self.ext_count(backend, x509_obj)): - ext = self.get_ext(backend, x509_obj, i) - backend.openssl_assert(ext != backend._ffi.NULL) - crit = backend._lib.X509_EXTENSION_get_critical(ext) + for i in range(self.ext_count(x509_obj)): + ext = self.get_ext(x509_obj, i) + self._backend.openssl_assert(ext != self._backend._ffi.NULL) + crit = self._backend._lib.X509_EXTENSION_get_critical(ext) critical = crit == 1 oid = x509.ObjectIdentifier( - _obj2txt(backend, backend._lib.X509_EXTENSION_get_object(ext)) + _obj2txt( + self._backend, + self._backend._lib.X509_EXTENSION_get_object(ext), + ) ) if oid in seen_oids: raise x509.DuplicateExtension( - "Duplicate {0} extension found".format(oid), oid + "Duplicate {} extension found".format(oid), oid ) # These OIDs are only supported in OpenSSL 1.1.0+ but we want # to support them in all versions of OpenSSL so we decode them # ourselves. if oid == ExtensionOID.TLS_FEATURE: - data = backend._lib.X509_EXTENSION_get_data(ext) - parsed = _Integers.load(_asn1_string_to_bytes(backend, data)) + # The extension contents are a SEQUENCE OF INTEGERs. + data = self._backend._lib.X509_EXTENSION_get_data(ext) + data_bytes = _asn1_string_to_bytes(self._backend, data) + features = DERReader(data_bytes).read_single_element(SEQUENCE) + parsed = [] + while not features.is_empty(): + parsed.append(features.read_element(INTEGER).as_integer()) + # Map the features to their enum value. value = x509.TLSFeature( - [_TLS_FEATURE_TYPE_TO_ENUM[x.native] for x in parsed] + [_TLS_FEATURE_TYPE_TO_ENUM[x] for x in parsed] ) extensions.append(x509.Extension(oid, critical, value)) seen_oids.add(oid) continue elif oid == ExtensionOID.PRECERT_POISON: - data = backend._lib.X509_EXTENSION_get_data(ext) - parsed = asn1crypto.core.Null.load( - _asn1_string_to_bytes(backend, data) + data = self._backend._lib.X509_EXTENSION_get_data(ext) + # The contents of the extension must be an ASN.1 NULL. + reader = DERReader(_asn1_string_to_bytes(self._backend, data)) + reader.read_single_element(NULL).check_empty() + extensions.append( + x509.Extension(oid, critical, x509.PrecertPoison()) ) - assert parsed == asn1crypto.core.Null() - extensions.append(x509.Extension( - oid, critical, x509.PrecertPoison() - )) seen_oids.add(oid) continue @@ -233,23 +239,21 @@ def parse(self, backend, x509_obj): handler = self.handlers[oid] except KeyError: # Dump the DER payload into an UnrecognizedExtension object - data = backend._lib.X509_EXTENSION_get_data(ext) - backend.openssl_assert(data != backend._ffi.NULL) - der = backend._ffi.buffer(data.data, data.length)[:] + data = self._backend._lib.X509_EXTENSION_get_data(ext) + self._backend.openssl_assert(data != self._backend._ffi.NULL) + der = self._backend._ffi.buffer(data.data, data.length)[:] unrecognized = x509.UnrecognizedExtension(oid, der) - extensions.append( - x509.Extension(oid, critical, unrecognized) - ) + extensions.append(x509.Extension(oid, critical, unrecognized)) else: - ext_data = backend._lib.X509V3_EXT_d2i(ext) - if ext_data == backend._ffi.NULL: - backend._consume_errors() + ext_data = self._backend._lib.X509V3_EXT_d2i(ext) + if ext_data == self._backend._ffi.NULL: + self._backend._consume_errors() raise ValueError( - "The {0} extension is invalid and can't be " + "The {} extension is invalid and can't be " "parsed".format(oid) ) - value = handler(backend, ext_data) + value = handler(self._backend, ext_data) extensions.append(x509.Extension(oid, critical, value)) seen_oids.add(oid) @@ -271,16 +275,12 @@ def _decode_certificate_policies(backend, cp): qnum = backend._lib.sk_POLICYQUALINFO_num(pi.qualifiers) qualifiers = [] for j in range(qnum): - pqi = backend._lib.sk_POLICYQUALINFO_value( - pi.qualifiers, j - ) - pqualid = x509.ObjectIdentifier( - _obj2txt(backend, pqi.pqualid) - ) + pqi = backend._lib.sk_POLICYQUALINFO_value(pi.qualifiers, j) + pqualid = x509.ObjectIdentifier(_obj2txt(backend, pqi.pqualid)) if pqualid == CertificatePoliciesOID.CPS_QUALIFIER: cpsuri = backend._ffi.buffer( pqi.d.cpsuri.data, pqi.d.cpsuri.length - )[:].decode('ascii') + )[:].decode("ascii") qualifiers.append(cpsuri) else: assert pqualid == CertificatePoliciesOID.CPS_USER_NOTICE @@ -289,9 +289,7 @@ def _decode_certificate_policies(backend, cp): ) qualifiers.append(user_notice) - certificate_policies.append( - x509.PolicyInformation(oid, qualifiers) - ) + certificate_policies.append(x509.PolicyInformation(oid, qualifiers)) return x509.CertificatePolicies(certificate_policies) @@ -304,13 +302,9 @@ def _decode_user_notice(backend, un): explicit_text = _asn1_string_to_utf8(backend, un.exptext) if un.noticeref != backend._ffi.NULL: - organization = _asn1_string_to_utf8( - backend, un.noticeref.organization - ) + organization = _asn1_string_to_utf8(backend, un.noticeref.organization) - num = backend._lib.sk_ASN1_INTEGER_num( - un.noticeref.noticenos - ) + num = backend._lib.sk_ASN1_INTEGER_num(un.noticeref.noticenos) notice_numbers = [] for i in range(num): asn1_int = backend._lib.sk_ASN1_INTEGER_value( @@ -319,9 +313,7 @@ def _decode_user_notice(backend, un): notice_num = _asn1_integer_to_int(backend, asn1_int) notice_numbers.append(notice_num) - notice_reference = x509.NoticeReference( - organization, notice_numbers - ) + notice_reference = x509.NoticeReference(organization, notice_numbers) return x509.UserNotice(notice_reference, explicit_text) @@ -364,9 +356,7 @@ def _decode_authority_key_identifier(backend, akid): )[:] if akid.issuer != backend._ffi.NULL: - authority_cert_issuer = _decode_general_names( - backend, akid.issuer - ) + authority_cert_issuer = _decode_general_names(backend, akid.issuer) authority_cert_serial_number = _asn1_integer_to_int_or_none( backend, akid.serial @@ -377,22 +367,40 @@ def _decode_authority_key_identifier(backend, akid): ) -def _decode_authority_information_access(backend, aia): - aia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia) - aia = backend._ffi.gc(aia, backend._lib.sk_ACCESS_DESCRIPTION_free) - num = backend._lib.sk_ACCESS_DESCRIPTION_num(aia) +def _decode_information_access(backend, ia): + ia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", ia) + ia = backend._ffi.gc( + ia, + lambda x: backend._lib.sk_ACCESS_DESCRIPTION_pop_free( + x, + backend._ffi.addressof( + backend._lib._original_lib, "ACCESS_DESCRIPTION_free" + ), + ), + ) + num = backend._lib.sk_ACCESS_DESCRIPTION_num(ia) access_descriptions = [] for i in range(num): - ad = backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i) + ad = backend._lib.sk_ACCESS_DESCRIPTION_value(ia, i) backend.openssl_assert(ad.method != backend._ffi.NULL) oid = x509.ObjectIdentifier(_obj2txt(backend, ad.method)) backend.openssl_assert(ad.location != backend._ffi.NULL) gn = _decode_general_name(backend, ad.location) access_descriptions.append(x509.AccessDescription(oid, gn)) + return access_descriptions + + +def _decode_authority_information_access(backend, aia): + access_descriptions = _decode_information_access(backend, aia) return x509.AuthorityInformationAccess(access_descriptions) +def _decode_subject_information_access(backend, aia): + access_descriptions = _decode_information_access(backend, aia) + return x509.SubjectInformationAccess(access_descriptions) + + def _decode_key_usage(backend, bit_string): bit_string = backend._ffi.cast("ASN1_BIT_STRING *", bit_string) bit_string = backend._ffi.gc(bit_string, backend._lib.ASN1_BIT_STRING_free) @@ -415,7 +423,7 @@ def _decode_key_usage(backend, bit_string): key_cert_sign, crl_sign, encipher_only, - decipher_only + decipher_only, ) @@ -483,8 +491,13 @@ def _decode_issuing_dist_point(backend, idp): only_some_reasons = None return x509.IssuingDistributionPoint( - full_name, relative_name, only_user, only_ca, only_some_reasons, - indirect_crl, only_attr + full_name, + relative_name, + only_user, + only_ca, + only_some_reasons, + indirect_crl, + only_attr, ) @@ -605,13 +618,9 @@ def _decode_distpoint(backend, distpoint): rnum = backend._lib.sk_X509_NAME_ENTRY_num(rns) attributes = set() for i in range(rnum): - rn = backend._lib.sk_X509_NAME_ENTRY_value( - rns, i - ) + rn = backend._lib.sk_X509_NAME_ENTRY_value(rns, i) backend.openssl_assert(rn != backend._ffi.NULL) - attributes.add( - _decode_x509_name_entry(backend, rn) - ) + attributes.add(_decode_x509_name_entry(backend, rn)) relative_name = x509.RelativeDistinguishedName(attributes) @@ -635,10 +644,11 @@ def _decode_inhibit_any_policy(backend, asn1_int): return x509.InhibitAnyPolicy(skip_certs) -def _decode_precert_signed_certificate_timestamps(backend, asn1_scts): +def _decode_scts(backend, asn1_scts): from cryptography.hazmat.backends.openssl.x509 import ( - _SignedCertificateTimestamp + _SignedCertificateTimestamp, ) + asn1_scts = backend._ffi.cast("Cryptography_STACK_OF_SCT *", asn1_scts) asn1_scts = backend._ffi.gc(asn1_scts, backend._lib.SCT_LIST_free) @@ -647,7 +657,17 @@ def _decode_precert_signed_certificate_timestamps(backend, asn1_scts): sct = backend._lib.sk_SCT_value(asn1_scts, i) scts.append(_SignedCertificateTimestamp(backend, asn1_scts, sct)) - return x509.PrecertificateSignedCertificateTimestamps(scts) + return scts + + +def _decode_precert_signed_certificate_timestamps(backend, asn1_scts): + return x509.PrecertificateSignedCertificateTimestamps( + _decode_scts(backend, asn1_scts) + ) + + +def _decode_signed_certificate_timestamps(backend, asn1_scts): + return x509.SignedCertificateTimestamps(_decode_scts(backend, asn1_scts)) # CRLReason ::= ENUMERATED { @@ -686,7 +706,7 @@ def _decode_precert_signed_certificate_timestamps(backend, asn1_scts): x509.ReasonFlags.certificate_hold: 6, x509.ReasonFlags.remove_from_crl: 8, x509.ReasonFlags.privilege_withdrawn: 9, - x509.ReasonFlags.aa_compromise: 10 + x509.ReasonFlags.aa_compromise: 10, } @@ -698,13 +718,11 @@ def _decode_crl_reason(backend, enum): try: return x509.CRLReason(_CRL_ENTRY_REASON_CODE_TO_ENUM[code]) except KeyError: - raise ValueError("Unsupported reason code: {0}".format(code)) + raise ValueError("Unsupported reason code: {}".format(code)) def _decode_invalidity_date(backend, inv_date): - generalized_time = backend._ffi.cast( - "ASN1_GENERALIZEDTIME *", inv_date - ) + generalized_time = backend._ffi.cast("ASN1_GENERALIZEDTIME *", inv_date) generalized_time = backend._ffi.gc( generalized_time, backend._lib.ASN1_GENERALIZEDTIME_free ) @@ -758,14 +776,14 @@ def _asn1_string_to_utf8(backend, asn1_string): res = backend._lib.ASN1_STRING_to_UTF8(buf, asn1_string) if res == -1: raise ValueError( - "Unsupported ASN1 string type. Type: {0}".format(asn1_string.type) + "Unsupported ASN1 string type. Type: {}".format(asn1_string.type) ) backend.openssl_assert(buf[0] != backend._ffi.NULL) buf = backend._ffi.gc( buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0]) ) - return backend._ffi.buffer(buf[0], res)[:].decode('utf8') + return backend._ffi.buffer(buf[0], res)[:].decode("utf8") def _parse_asn1_time(backend, asn1_time): @@ -799,7 +817,7 @@ def _decode_nonce(backend, nonce): return x509.OCSPNonce(_asn1_string_to_bytes(backend, nonce)) -_EXTENSION_HANDLERS_NO_SCT = { +_EXTENSION_HANDLERS_BASE = { ExtensionOID.BASIC_CONSTRAINTS: _decode_basic_constraints, ExtensionOID.SUBJECT_KEY_IDENTIFIER: _decode_subject_key_identifier, ExtensionOID.KEY_USAGE: _decode_key_usage, @@ -809,6 +827,9 @@ def _decode_nonce(backend, nonce): ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( _decode_authority_information_access ), + ExtensionOID.SUBJECT_INFORMATION_ACCESS: ( + _decode_subject_information_access + ), ExtensionOID.CERTIFICATE_POLICIES: _decode_certificate_policies, ExtensionOID.CRL_DISTRIBUTION_POINTS: _decode_crl_distribution_points, ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, @@ -818,11 +839,11 @@ def _decode_nonce(backend, nonce): ExtensionOID.NAME_CONSTRAINTS: _decode_name_constraints, ExtensionOID.POLICY_CONSTRAINTS: _decode_policy_constraints, } -_EXTENSION_HANDLERS = _EXTENSION_HANDLERS_NO_SCT.copy() -_EXTENSION_HANDLERS[ - ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS -] = _decode_precert_signed_certificate_timestamps - +_EXTENSION_HANDLERS_SCT = { + ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: ( + _decode_precert_signed_certificate_timestamps + ) +} _REVOKED_EXTENSION_HANDLERS = { CRLEntryExtensionOID.CRL_REASON: _decode_crl_reason, @@ -839,6 +860,7 @@ def _decode_nonce(backend, nonce): _decode_authority_information_access ), ExtensionOID.ISSUING_DISTRIBUTION_POINT: _decode_issuing_dist_point, + ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, } _OCSP_REQ_EXTENSION_HANDLERS = { @@ -849,44 +871,8 @@ def _decode_nonce(backend, nonce): OCSPExtensionOID.NONCE: _decode_nonce, } -_CERTIFICATE_EXTENSION_PARSER_NO_SCT = _X509ExtensionParser( - ext_count=lambda backend, x: backend._lib.X509_get_ext_count(x), - get_ext=lambda backend, x, i: backend._lib.X509_get_ext(x, i), - handlers=_EXTENSION_HANDLERS_NO_SCT -) - -_CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser( - ext_count=lambda backend, x: backend._lib.X509_get_ext_count(x), - get_ext=lambda backend, x, i: backend._lib.X509_get_ext(x, i), - handlers=_EXTENSION_HANDLERS -) - -_CSR_EXTENSION_PARSER = _X509ExtensionParser( - ext_count=lambda backend, x: backend._lib.sk_X509_EXTENSION_num(x), - get_ext=lambda backend, x, i: backend._lib.sk_X509_EXTENSION_value(x, i), - handlers=_EXTENSION_HANDLERS -) - -_REVOKED_CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser( - ext_count=lambda backend, x: backend._lib.X509_REVOKED_get_ext_count(x), - get_ext=lambda backend, x, i: backend._lib.X509_REVOKED_get_ext(x, i), - handlers=_REVOKED_EXTENSION_HANDLERS, -) - -_CRL_EXTENSION_PARSER = _X509ExtensionParser( - ext_count=lambda backend, x: backend._lib.X509_CRL_get_ext_count(x), - get_ext=lambda backend, x, i: backend._lib.X509_CRL_get_ext(x, i), - handlers=_CRL_EXTENSION_HANDLERS, -) - -_OCSP_REQ_EXT_PARSER = _X509ExtensionParser( - ext_count=lambda backend, x: backend._lib.OCSP_REQUEST_get_ext_count(x), - get_ext=lambda backend, x, i: backend._lib.OCSP_REQUEST_get_ext(x, i), - handlers=_OCSP_REQ_EXTENSION_HANDLERS, -) - -_OCSP_BASICRESP_EXT_PARSER = _X509ExtensionParser( - ext_count=lambda backend, x: backend._lib.OCSP_BASICRESP_get_ext_count(x), - get_ext=lambda backend, x, i: backend._lib.OCSP_BASICRESP_get_ext(x, i), - handlers=_OCSP_BASICRESP_EXTENSION_HANDLERS, -) +_OCSP_SINGLERESP_EXTENSION_HANDLERS_SCT = { + ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS: ( + _decode_signed_certificate_timestamps + ) +} diff --git a/src/cryptography/hazmat/backends/openssl/dh.py b/src/cryptography/hazmat/backends/openssl/dh.py index 095f062339e6..2862676c65ea 100644 --- a/src/cryptography/hazmat/backends/openssl/dh.py +++ b/src/cryptography/hazmat/backends/openssl/dh.py @@ -17,8 +17,8 @@ def _dh_params_dup(dh_cdata, backend): 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_OPENSSL_LESS_THAN_102: - # In OpenSSL versions < 1.0.2 or libressl DHparams_dup don't copy q + 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]) @@ -53,7 +53,7 @@ def parameter_numbers(self): return dh.DHParameterNumbers( p=self._backend._bn_to_int(p[0]), g=self._backend._bn_to_int(g[0]), - q=q_val + q=q_val, ) def generate_private_key(self): @@ -61,44 +61,27 @@ def generate_private_key(self): def parameter_bytes(self, encoding, format): if format is not serialization.ParameterFormat.PKCS3: - raise ValueError( - "Only PKCS3 serialization is supported" - ) + raise ValueError("Only PKCS3 serialization is supported") 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) + 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) + _Reasons.UNSUPPORTED_SERIALIZATION, + ) - return self._backend._parameter_bytes( - encoding, - format, - self._dh_cdata - ) - - -def _handle_dh_compute_key_error(errors, backend): - lib = backend._lib - - backend.openssl_assert( - errors[0]._lib_reason_match( - lib.ERR_LIB_DH, lib.DH_R_INVALID_PUBKEY - ) - ) - - raise ValueError("Public key value is invalid for this exchange.") + return self._backend._parameter_bytes(encoding, format, self._dh_cdata) def _get_dh_num_bits(backend, dh_cdata): p = backend._ffi.new("BIGNUM **") - backend._lib.DH_get0_pqg(dh_cdata, p, - backend._ffi.NULL, - backend._ffi.NULL) + 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]) @@ -136,29 +119,32 @@ def private_numbers(self): parameter_numbers=dh.DHParameterNumbers( p=self._backend._bn_to_int(p[0]), g=self._backend._bn_to_int(g[0]), - q=q_val + q=q_val, ), - y=self._backend._bn_to_int(pub_key[0]) + y=self._backend._bn_to_int(pub_key[0]), ), - x=self._backend._bn_to_int(priv_key[0]) + x=self._backend._bn_to_int(priv_key[0]), ) def exchange(self, peer_public_key): buf = self._backend._ffi.new("unsigned char[]", self._key_size_bytes) pub_key = self._backend._ffi.new("BIGNUM **") - self._backend._lib.DH_get0_key(peer_public_key._dh_cdata, pub_key, - self._backend._ffi.NULL) + self._backend._lib.DH_get0_key( + peer_public_key._dh_cdata, pub_key, self._backend._ffi.NULL + ) self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) res = self._backend._lib.DH_compute_key( - buf, - pub_key[0], - self._dh_cdata + buf, pub_key[0], self._dh_cdata ) if res == -1: - errors = self._backend._consume_errors() - return _handle_dh_compute_key_error(errors, self._backend) + errors_with_text = self._backend._consume_errors_with_text() + raise ValueError( + "Error computing shared key. Public key is likely invalid " + "for this exchange.", + errors_with_text, + ) else: self._backend.openssl_assert(res >= 1) @@ -173,15 +159,16 @@ def exchange(self, peer_public_key): def public_key(self): 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._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) + 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) @@ -196,21 +183,25 @@ def private_bytes(self, encoding, format, encryption_algorithm): ) 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) + 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) + _Reasons.UNSUPPORTED_SERIALIZATION, + ) return self._backend._private_key_bytes( encoding, format, encryption_algorithm, + self, self._evp_pkey, - self._dh_cdata + self._dh_cdata, ) @@ -238,16 +229,17 @@ def public_numbers(self): 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._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 + q=q_val, ), - y=self._backend._bn_to_int(pub_key[0]) + y=self._backend._bn_to_int(pub_key[0]), ) def parameters(self): @@ -262,19 +254,18 @@ def public_bytes(self, encoding, format): 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) + 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) + _Reasons.UNSUPPORTED_SERIALIZATION, + ) return self._backend._public_key_bytes( - encoding, - format, - self, - self._evp_pkey, - None + encoding, format, self, self._evp_pkey, None ) diff --git a/src/cryptography/hazmat/backends/openssl/dsa.py b/src/cryptography/hazmat/backends/openssl/dsa.py index de61f08949ba..0c5faba18ac9 100644 --- a/src/cryptography/hazmat/backends/openssl/dsa.py +++ b/src/cryptography/hazmat/backends/openssl/dsa.py @@ -7,12 +7,15 @@ from cryptography import utils from cryptography.exceptions import InvalidSignature from cryptography.hazmat.backends.openssl.utils import ( - _calculate_digest_and_algorithm, _check_not_prehashed, - _warn_sign_verify_deprecated + _calculate_digest_and_algorithm, + _check_not_prehashed, + _warn_sign_verify_deprecated, ) -from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ( - AsymmetricSignatureContext, AsymmetricVerificationContext, dsa + AsymmetricSignatureContext, + AsymmetricVerificationContext, + dsa, ) @@ -29,7 +32,7 @@ def _dsa_sig_sign(backend, private_key, data): backend.openssl_assert(res == 1) backend.openssl_assert(buflen[0]) - return backend._ffi.buffer(sig_buf)[:buflen[0]] + return backend._ffi.buffer(sig_buf)[: buflen[0]] def _dsa_sig_verify(backend, public_key, signature, data): @@ -98,7 +101,7 @@ def parameter_numbers(self): 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]) + g=self._backend._bn_to_int(g[0]), ) def generate_private_key(self): @@ -144,11 +147,11 @@ def private_numbers(self): 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]) + g=self._backend._bn_to_int(g[0]), ), - y=self._backend._bn_to_int(pub_key[0]) + y=self._backend._bn_to_int(pub_key[0]), ), - x=self._backend._bn_to_int(priv_key[0]) + x=self._backend._bn_to_int(priv_key[0]), ) def public_key(self): @@ -183,8 +186,9 @@ def private_bytes(self, encoding, format, encryption_algorithm): encoding, format, encryption_algorithm, + self, self._evp_pkey, - self._dsa_cdata + self._dsa_cdata, ) def sign(self, data, algorithm): @@ -235,9 +239,9 @@ def public_numbers(self): 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]) + g=self._backend._bn_to_int(g[0]), ), - y=self._backend._bn_to_int(pub_key[0]) + y=self._backend._bn_to_int(pub_key[0]), ) def parameters(self): @@ -248,17 +252,8 @@ def parameters(self): return _DSAParameters(self._backend, dsa_cdata) def public_bytes(self, encoding, format): - if format is serialization.PublicFormat.PKCS1: - raise ValueError( - "DSA public keys do not support PKCS1 serialization" - ) - return self._backend._public_key_bytes( - encoding, - format, - self, - self._evp_pkey, - None + encoding, format, self, self._evp_pkey, None ) def verify(self, signature, data, algorithm): diff --git a/src/cryptography/hazmat/backends/openssl/ec.py b/src/cryptography/hazmat/backends/openssl/ec.py index a8d69bdf9f84..bf61bcf16b20 100644 --- a/src/cryptography/hazmat/backends/openssl/ec.py +++ b/src/cryptography/hazmat/backends/openssl/ec.py @@ -6,15 +6,20 @@ from cryptography import utils from cryptography.exceptions import ( - InvalidSignature, UnsupportedAlgorithm, _Reasons + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, ) from cryptography.hazmat.backends.openssl.utils import ( - _calculate_digest_and_algorithm, _check_not_prehashed, - _warn_sign_verify_deprecated + _calculate_digest_and_algorithm, + _check_not_prehashed, + _warn_sign_verify_deprecated, ) from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ( - AsymmetricSignatureContext, AsymmetricVerificationContext, ec + AsymmetricSignatureContext, + AsymmetricVerificationContext, + ec, ) @@ -22,7 +27,8 @@ def _check_signature_algorithm(signature_algorithm): if not isinstance(signature_algorithm, ec.ECDSA): raise UnsupportedAlgorithm( "Unsupported elliptic curve signature algorithm.", - _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM) + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) def _ec_key_curve_sn(backend, ec_key): @@ -34,14 +40,24 @@ def _ec_key_curve_sn(backend, ec_key): # an error for now. if nid == backend._lib.NID_undef: raise NotImplementedError( - "ECDSA certificates with unnamed curves are unsupported " - "at this time" + "ECDSA keys with unnamed curves are unsupported " "at this time" + ) + + # This is like the above check, but it also catches the case where you + # explicitly encoded a curve with the same parameters as a named curve. + # Don't do that. + if ( + backend._lib.CRYPTOGRAPHY_OPENSSL_102U_OR_GREATER + and backend._lib.EC_GROUP_get_asn1_flag(group) == 0 + ): + raise NotImplementedError( + "ECDSA keys with unnamed curves are unsupported " "at this time" ) curve_name = backend._lib.OBJ_nid2sn(nid) backend.openssl_assert(curve_name != backend._ffi.NULL) - sn = backend._ffi.string(curve_name).decode('ascii') + sn = backend._ffi.string(curve_name).decode("ascii") return sn @@ -62,8 +78,8 @@ def _sn_to_elliptic_curve(backend, sn): return ec._CURVE_TYPES[sn]() except KeyError: raise UnsupportedAlgorithm( - "{0} is not a supported elliptic curve".format(sn), - _Reasons.UNSUPPORTED_ELLIPTIC_CURVE + "{} is not a supported elliptic curve".format(sn), + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE, ) @@ -77,7 +93,7 @@ def _ecdsa_sig_sign(backend, private_key, data): 0, data, len(data), sigbuf, siglen_ptr, private_key._ec_key ) backend.openssl_assert(res == 1) - return backend._ffi.buffer(sigbuf)[:siglen_ptr[0]] + return backend._ffi.buffer(sigbuf)[: siglen_ptr[0]] def _ecdsa_sig_verify(backend, public_key, signature, data): @@ -127,12 +143,12 @@ def verify(self): class _EllipticCurvePrivateKey(object): def __init__(self, backend, ec_key_cdata, evp_pkey): self._backend = backend - _mark_asn1_named_ec_curve(backend, ec_key_cdata) self._ec_key = ec_key_cdata self._evp_pkey = evp_pkey sn = _ec_key_curve_sn(backend, ec_key_cdata) self._curve = _sn_to_elliptic_curve(backend, sn) + _mark_asn1_named_ec_curve(backend, ec_key_cdata) curve = utils.read_only_property("_curve") @@ -156,7 +172,7 @@ def exchange(self, algorithm, peer_public_key): ): raise UnsupportedAlgorithm( "This backend does not support the ECDH algorithm.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, ) if peer_public_key.curve.name != self.curve.name: @@ -183,12 +199,7 @@ def public_key(self): self._backend.openssl_assert(group != self._backend._ffi.NULL) curve_nid = self._backend._lib.EC_GROUP_get_curve_name(group) - - public_ec_key = self._backend._lib.EC_KEY_new_by_curve_name(curve_nid) - self._backend.openssl_assert(public_ec_key != self._backend._ffi.NULL) - public_ec_key = self._backend._ffi.gc( - public_ec_key, self._backend._lib.EC_KEY_free - ) + public_ec_key = self._backend._ec_key_new_by_curve_nid(curve_nid) point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) self._backend.openssl_assert(point != self._backend._ffi.NULL) @@ -205,7 +216,7 @@ def private_numbers(self): private_value = self._backend._bn_to_int(bn) return ec.EllipticCurvePrivateNumbers( private_value=private_value, - public_numbers=self.public_key().public_numbers() + public_numbers=self.public_key().public_numbers(), ) def private_bytes(self, encoding, format, encryption_algorithm): @@ -213,8 +224,9 @@ def private_bytes(self, encoding, format, encryption_algorithm): encoding, format, encryption_algorithm, + self, self._evp_pkey, - self._ec_key + self._ec_key, ) def sign(self, data, signature_algorithm): @@ -229,12 +241,12 @@ def sign(self, data, signature_algorithm): class _EllipticCurvePublicKey(object): def __init__(self, backend, ec_key_cdata, evp_pkey): self._backend = backend - _mark_asn1_named_ec_curve(backend, ec_key_cdata) self._ec_key = ec_key_cdata self._evp_pkey = evp_pkey sn = _ec_key_curve_sn(backend, ec_key_cdata) self._curve = _sn_to_elliptic_curve(backend, sn) + _mark_asn1_named_ec_curve(backend, ec_key_cdata) curve = utils.read_only_property("_curve") @@ -253,8 +265,8 @@ def verifier(self, signature, signature_algorithm): ) def public_numbers(self): - get_func, group = ( - self._backend._ec_key_determine_group_get_func(self._ec_key) + get_func, group = self._backend._ec_key_determine_group_get_func( + self._ec_key ) point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) self._backend.openssl_assert(point != self._backend._ffi.NULL) @@ -269,11 +281,7 @@ def public_numbers(self): x = self._backend._bn_to_int(bn_x) y = self._backend._bn_to_int(bn_y) - return ec.EllipticCurvePublicNumbers( - x=x, - y=y, - curve=self._curve - ) + return ec.EllipticCurvePublicNumbers(x=x, y=y, curve=self._curve) def _encode_point(self, format): if format is serialization.PublicFormat.CompressedPoint: @@ -300,22 +308,15 @@ def _encode_point(self, format): return self._backend._ffi.buffer(buf)[:] def public_bytes(self, encoding, format): - if format is serialization.PublicFormat.PKCS1: - raise ValueError( - "EC public keys do not support PKCS1 serialization" - ) if ( - encoding is serialization.Encoding.X962 or - format is serialization.PublicFormat.CompressedPoint or - format is serialization.PublicFormat.UncompressedPoint + encoding is serialization.Encoding.X962 + or format is serialization.PublicFormat.CompressedPoint + or format is serialization.PublicFormat.UncompressedPoint ): - if ( - encoding is not serialization.Encoding.X962 or - format not in ( - serialization.PublicFormat.CompressedPoint, - serialization.PublicFormat.UncompressedPoint - ) + if encoding is not serialization.Encoding.X962 or format not in ( + serialization.PublicFormat.CompressedPoint, + serialization.PublicFormat.UncompressedPoint, ): raise ValueError( "X962 encoding must be used with CompressedPoint or " @@ -325,11 +326,7 @@ def public_bytes(self, encoding, format): return self._encode_point(format) else: return self._backend._public_key_bytes( - encoding, - format, - self, - self._evp_pkey, - None + encoding, format, self, self._evp_pkey, None ) def verify(self, signature, data, signature_algorithm): diff --git a/src/cryptography/hazmat/backends/openssl/ed25519.py b/src/cryptography/hazmat/backends/openssl/ed25519.py new file mode 100644 index 000000000000..75653373b3cf --- /dev/null +++ b/src/cryptography/hazmat/backends/openssl/ed25519.py @@ -0,0 +1,145 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import exceptions, utils +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.ed25519 import ( + Ed25519PrivateKey, + Ed25519PublicKey, + _ED25519_KEY_SIZE, + _ED25519_SIG_SIZE, +) + + +@utils.register_interface(Ed25519PublicKey) +class _Ed25519PublicKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes(self, encoding, format): + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw + or format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:] + + def verify(self, signature, data): + evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestVerifyInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + res = self._backend._lib.EVP_DigestVerify( + evp_md_ctx, signature, len(signature), data, len(data) + ) + if res != 1: + self._backend._consume_errors() + raise exceptions.InvalidSignature + + +@utils.register_interface(Ed25519PrivateKey) +class _Ed25519PrivateKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self): + buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) + public_bytes = self._backend._ffi.buffer(buf)[:] + return self._backend.ed25519_load_public_bytes(public_bytes) + + def sign(self, data): + evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestSignInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + buf = self._backend._ffi.new("unsigned char[]", _ED25519_SIG_SIZE) + buflen = self._backend._ffi.new("size_t *", len(buf)) + res = self._backend._lib.EVP_DigestSign( + evp_md_ctx, buf, buflen, data, len(data) + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_SIG_SIZE) + return self._backend._ffi.buffer(buf, buflen[0])[:] + + def private_bytes(self, encoding, format, encryption_algorithm): + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw + or encoding is not serialization.Encoding.Raw + or not isinstance( + encryption_algorithm, serialization.NoEncryption + ) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption()" + ) + + return self._raw_private_bytes() + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self, self._evp_pkey, None + ) + + def _raw_private_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_private_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:] diff --git a/src/cryptography/hazmat/backends/openssl/ed448.py b/src/cryptography/hazmat/backends/openssl/ed448.py new file mode 100644 index 000000000000..4a8dab1a8115 --- /dev/null +++ b/src/cryptography/hazmat/backends/openssl/ed448.py @@ -0,0 +1,146 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import exceptions, utils +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.ed448 import ( + Ed448PrivateKey, + Ed448PublicKey, +) + +_ED448_KEY_SIZE = 57 +_ED448_SIG_SIZE = 114 + + +@utils.register_interface(Ed448PublicKey) +class _Ed448PublicKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes(self, encoding, format): + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw + or format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:] + + def verify(self, signature, data): + evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestVerifyInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + res = self._backend._lib.EVP_DigestVerify( + evp_md_ctx, signature, len(signature), data, len(data) + ) + if res != 1: + self._backend._consume_errors() + raise exceptions.InvalidSignature + + +@utils.register_interface(Ed448PrivateKey) +class _Ed448PrivateKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self): + buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) + public_bytes = self._backend._ffi.buffer(buf)[:] + return self._backend.ed448_load_public_bytes(public_bytes) + + def sign(self, data): + evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestSignInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + buf = self._backend._ffi.new("unsigned char[]", _ED448_SIG_SIZE) + buflen = self._backend._ffi.new("size_t *", len(buf)) + res = self._backend._lib.EVP_DigestSign( + evp_md_ctx, buf, buflen, data, len(data) + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_SIG_SIZE) + return self._backend._ffi.buffer(buf, buflen[0])[:] + + def private_bytes(self, encoding, format, encryption_algorithm): + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw + or encoding is not serialization.Encoding.Raw + or not isinstance( + encryption_algorithm, serialization.NoEncryption + ) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption()" + ) + + return self._raw_private_bytes() + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self, self._evp_pkey, None + ) + + def _raw_private_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_private_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:] diff --git a/src/cryptography/hazmat/backends/openssl/encode_asn1.py b/src/cryptography/hazmat/backends/openssl/encode_asn1.py index 3557576241fd..88d709d21457 100644 --- a/src/cryptography/hazmat/backends/openssl/encode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/encode_asn1.py @@ -11,12 +11,15 @@ from cryptography import utils, x509 from cryptography.hazmat.backends.openssl.decode_asn1 import ( - _CRL_ENTRY_REASON_ENUM_TO_CODE, _DISTPOINT_TYPE_FULLNAME, - _DISTPOINT_TYPE_RELATIVENAME + _CRL_ENTRY_REASON_ENUM_TO_CODE, + _DISTPOINT_TYPE_FULLNAME, + _DISTPOINT_TYPE_RELATIVENAME, ) from cryptography.x509.name import _ASN1Type from cryptography.x509.oid import ( - CRLEntryExtensionOID, ExtensionOID, OCSPExtensionOID, + CRLEntryExtensionOID, + ExtensionOID, + OCSPExtensionOID, ) @@ -94,7 +97,8 @@ def _encode_name(backend, name): name_entry, backend._lib.X509_NAME_ENTRY_free ) res = backend._lib.X509_NAME_add_entry( - subject, name_entry, -1, set_flag) + subject, name_entry, -1, set_flag + ) backend.openssl_assert(res == 1) set_flag = -1 return subject @@ -120,9 +124,11 @@ def _encode_sk_name_entry(backend, attributes): def _encode_name_entry(backend, attribute): if attribute._type is _ASN1Type.BMPString: - value = attribute.value.encode('utf_16_be') + value = attribute.value.encode("utf_16_be") + elif attribute._type is _ASN1Type.UniversalString: + value = attribute.value.encode("utf_32_be") else: - value = attribute.value.encode('utf8') + value = attribute.value.encode("utf8") obj = _txt2obj_gc(backend, attribute.oid.dotted_string) @@ -172,9 +178,8 @@ def _encode_crl_reason(backend, crl_reason): def _encode_invalidity_date(backend, invalidity_date): time = backend._lib.ASN1_GENERALIZEDTIME_set( - backend._ffi.NULL, calendar.timegm( - invalidity_date.invalidity_date.timetuple() - ) + backend._ffi.NULL, + calendar.timegm(invalidity_date.invalidity_date.timetuple()), ) backend.openssl_assert(time != backend._ffi.NULL) time = backend._ffi.gc(time, backend._lib.ASN1_GENERALIZEDTIME_free) @@ -255,7 +260,7 @@ def _txt2obj(backend, name): Converts a Python string with an ASN.1 object ID in dotted form to a ASN1_OBJECT. """ - name = name.encode('ascii') + name = name.encode("ascii") obj = backend._lib.OBJ_txt2obj(name, 1) backend.openssl_assert(obj != backend._ffi.NULL) return obj @@ -341,20 +346,27 @@ def _encode_basic_constraints(backend, basic_constraints): return constraints -def _encode_authority_information_access(backend, authority_info_access): +def _encode_information_access(backend, info_access): aia = backend._lib.sk_ACCESS_DESCRIPTION_new_null() backend.openssl_assert(aia != backend._ffi.NULL) aia = backend._ffi.gc( - aia, backend._lib.sk_ACCESS_DESCRIPTION_free + aia, + lambda x: backend._lib.sk_ACCESS_DESCRIPTION_pop_free( + x, + backend._ffi.addressof( + backend._lib._original_lib, "ACCESS_DESCRIPTION_free" + ), + ), ) - for access_description in authority_info_access: + for access_description in info_access: ad = backend._lib.ACCESS_DESCRIPTION_new() method = _txt2obj( backend, access_description.access_method.dotted_string ) - gn = _encode_general_name(backend, access_description.access_location) + _encode_general_name_preallocated( + backend, access_description.access_location, ad.location + ) ad.method = method - ad.location = gn res = backend._lib.sk_ACCESS_DESCRIPTION_push(aia, ad) backend.openssl_assert(res >= 1) @@ -385,8 +397,13 @@ def _encode_subject_key_identifier(backend, ski): def _encode_general_name(backend, name): + gn = backend._lib.GENERAL_NAME_new() + _encode_general_name_preallocated(backend, name, gn) + return gn + + +def _encode_general_name_preallocated(backend, name, gn): if isinstance(name, x509.DNSName): - gn = backend._lib.GENERAL_NAME_new() backend.openssl_assert(gn != backend._ffi.NULL) gn.type = backend._lib.GEN_DNS @@ -400,32 +417,27 @@ def _encode_general_name(backend, name): backend.openssl_assert(res == 1) gn.d.dNSName = ia5 elif isinstance(name, x509.RegisteredID): - gn = backend._lib.GENERAL_NAME_new() backend.openssl_assert(gn != backend._ffi.NULL) gn.type = backend._lib.GEN_RID obj = backend._lib.OBJ_txt2obj( - name.value.dotted_string.encode('ascii'), 1 + name.value.dotted_string.encode("ascii"), 1 ) backend.openssl_assert(obj != backend._ffi.NULL) gn.d.registeredID = obj elif isinstance(name, x509.DirectoryName): - gn = backend._lib.GENERAL_NAME_new() backend.openssl_assert(gn != backend._ffi.NULL) dir_name = _encode_name(backend, name.value) gn.type = backend._lib.GEN_DIRNAME gn.d.directoryName = dir_name elif isinstance(name, x509.IPAddress): - gn = backend._lib.GENERAL_NAME_new() backend.openssl_assert(gn != backend._ffi.NULL) if isinstance(name.value, ipaddress.IPv4Network): - packed = ( - name.value.network_address.packed + - utils.int_to_bytes(((1 << 32) - name.value.num_addresses), 4) + packed = name.value.network_address.packed + utils.int_to_bytes( + ((1 << 32) - name.value.num_addresses), 4 ) elif isinstance(name.value, ipaddress.IPv6Network): - packed = ( - name.value.network_address.packed + - utils.int_to_bytes((1 << 128) - name.value.num_addresses, 16) + packed = name.value.network_address.packed + utils.int_to_bytes( + (1 << 128) - name.value.num_addresses, 16 ) else: packed = name.value.packed @@ -433,13 +445,12 @@ def _encode_general_name(backend, name): gn.type = backend._lib.GEN_IPADD gn.d.iPAddress = ipaddr elif isinstance(name, x509.OtherName): - gn = backend._lib.GENERAL_NAME_new() backend.openssl_assert(gn != backend._ffi.NULL) other_name = backend._lib.OTHERNAME_new() backend.openssl_assert(other_name != backend._ffi.NULL) type_id = backend._lib.OBJ_txt2obj( - name.type_id.dotted_string.encode('ascii'), 1 + name.type_id.dotted_string.encode("ascii"), 1 ) backend.openssl_assert(type_id != backend._ffi.NULL) data = backend._ffi.new("unsigned char[]", name.value) @@ -456,7 +467,6 @@ def _encode_general_name(backend, name): gn.type = backend._lib.GEN_OTHERNAME gn.d.otherName = other_name elif isinstance(name, x509.RFC822Name): - gn = backend._lib.GENERAL_NAME_new() backend.openssl_assert(gn != backend._ffi.NULL) # ia5strings are supposed to be ITU T.50 but to allow round-tripping # of broken certs that encode utf8 we'll encode utf8 here too. @@ -465,7 +475,6 @@ def _encode_general_name(backend, name): gn.type = backend._lib.GEN_EMAIL gn.d.rfc822Name = asn1_str elif isinstance(name, x509.UniformResourceIdentifier): - gn = backend._lib.GENERAL_NAME_new() backend.openssl_assert(gn != backend._ffi.NULL) # ia5strings are supposed to be ITU T.50 but to allow round-tripping # of broken certs that encode utf8 we'll encode utf8 here too. @@ -474,11 +483,7 @@ def _encode_general_name(backend, name): gn.type = backend._lib.GEN_URI gn.d.uniformResourceIdentifier = asn1_str else: - raise ValueError( - "{0} is an unknown GeneralName type".format(name) - ) - - return gn + raise ValueError("{} is an unknown GeneralName type".format(name)) def _encode_extended_key_usage(backend, extended_key_usage): @@ -617,9 +622,8 @@ def _encode_nonce(backend, nonce): ExtensionOID.EXTENDED_KEY_USAGE: _encode_extended_key_usage, ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _encode_authority_key_identifier, ExtensionOID.CERTIFICATE_POLICIES: _encode_certificate_policies, - ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( - _encode_authority_information_access - ), + ExtensionOID.AUTHORITY_INFORMATION_ACCESS: _encode_information_access, + ExtensionOID.SUBJECT_INFORMATION_ACCESS: _encode_information_access, ExtensionOID.CRL_DISTRIBUTION_POINTS: _encode_cdps_freshest_crl, ExtensionOID.FRESHEST_CRL: _encode_cdps_freshest_crl, ExtensionOID.INHIBIT_ANY_POLICY: _encode_inhibit_any_policy, @@ -631,12 +635,11 @@ def _encode_nonce(backend, nonce): _CRL_EXTENSION_ENCODE_HANDLERS = { ExtensionOID.ISSUER_ALTERNATIVE_NAME: _encode_alt_name, ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _encode_authority_key_identifier, - ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( - _encode_authority_information_access - ), + ExtensionOID.AUTHORITY_INFORMATION_ACCESS: _encode_information_access, ExtensionOID.CRL_NUMBER: _encode_crl_number_delta_crl_indicator, ExtensionOID.DELTA_CRL_INDICATOR: _encode_crl_number_delta_crl_indicator, ExtensionOID.ISSUING_DISTRIBUTION_POINT: _encode_issuing_dist_point, + ExtensionOID.FRESHEST_CRL: _encode_cdps_freshest_crl, } _CRL_ENTRY_EXTENSION_ENCODE_HANDLERS = { diff --git a/src/cryptography/hazmat/backends/openssl/hashes.py b/src/cryptography/hazmat/backends/openssl/hashes.py index 549fa2bf5dee..44033993e166 100644 --- a/src/cryptography/hazmat/backends/openssl/hashes.py +++ b/src/cryptography/hazmat/backends/openssl/hashes.py @@ -25,12 +25,14 @@ def __init__(self, backend, algorithm, ctx=None): evp_md = self._backend._evp_md_from_algorithm(algorithm) if evp_md == self._backend._ffi.NULL: raise UnsupportedAlgorithm( - "{0} is not a supported hash on this backend.".format( - algorithm.name), - _Reasons.UNSUPPORTED_HASH + "{} 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) + res = self._backend._lib.EVP_DigestInit_ex( + ctx, evp_md, self._backend._ffi.NULL + ) self._backend.openssl_assert(res != 0) self._ctx = ctx @@ -58,21 +60,23 @@ def finalize(self): # 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) + 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]] + return self._backend._ffi.buffer(buf)[: outlen[0]] def _finalize_xof(self): - buf = self._backend._ffi.new("unsigned char[]", - self.algorithm.digest_size) + 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] + return self._backend._ffi.buffer(buf)[: self.algorithm.digest_size] diff --git a/src/cryptography/hazmat/backends/openssl/hmac.py b/src/cryptography/hazmat/backends/openssl/hmac.py index b23ac6498cbf..5024223b219b 100644 --- a/src/cryptography/hazmat/backends/openssl/hmac.py +++ b/src/cryptography/hazmat/backends/openssl/hmac.py @@ -7,12 +7,13 @@ from cryptography import utils from cryptography.exceptions import ( - InvalidSignature, UnsupportedAlgorithm, _Reasons + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, ) -from cryptography.hazmat.primitives import constant_time, hashes, mac +from cryptography.hazmat.primitives import constant_time, hashes -@utils.register_interface(mac.MACContext) @utils.register_interface(hashes.HashContext) class _HMACContext(object): def __init__(self, backend, key, algorithm, ctx=None): @@ -28,9 +29,10 @@ def __init__(self, backend, key, algorithm, ctx=None): evp_md = self._backend._evp_md_from_algorithm(algorithm) if evp_md == self._backend._ffi.NULL: raise UnsupportedAlgorithm( - "{0} is not a supported hash on this backend".format( - algorithm.name), - _Reasons.UNSUPPORTED_HASH + "{} 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( @@ -61,13 +63,14 @@ def update(self, data): self._backend.openssl_assert(res != 0) def finalize(self): - buf = self._backend._ffi.new("unsigned char[]", - self._backend._lib.EVP_MAX_MD_SIZE) + 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]] + return self._backend._ffi.buffer(buf)[: outlen[0]] def verify(self, signature): digest = self.finalize() diff --git a/src/cryptography/hazmat/backends/openssl/ocsp.py b/src/cryptography/hazmat/backends/openssl/ocsp.py index 16dbbc2ae0a9..50c02e7a8018 100644 --- a/src/cryptography/hazmat/backends/openssl/ocsp.py +++ b/src/cryptography/hazmat/backends/openssl/ocsp.py @@ -9,16 +9,23 @@ from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm from cryptography.hazmat.backends.openssl.decode_asn1 import ( - _CRL_ENTRY_REASON_CODE_TO_ENUM, _OCSP_BASICRESP_EXT_PARSER, - _OCSP_REQ_EXT_PARSER, _asn1_integer_to_int, - _asn1_string_to_bytes, _decode_x509_name, _obj2txt, + _CRL_ENTRY_REASON_CODE_TO_ENUM, + _asn1_integer_to_int, + _asn1_string_to_bytes, + _decode_x509_name, + _obj2txt, _parse_asn1_generalized_time, ) from cryptography.hazmat.backends.openssl.x509 import _Certificate from cryptography.hazmat.primitives import serialization from cryptography.x509.ocsp import ( - OCSPCertStatus, OCSPRequest, OCSPResponse, OCSPResponseStatus, - _CERT_STATUS_TO_ENUM, _OIDS_TO_HASH, _RESPONSE_STATUS_TO_ENUM, + OCSPCertStatus, + OCSPRequest, + OCSPResponse, + OCSPResponseStatus, + _CERT_STATUS_TO_ENUM, + _OIDS_TO_HASH, + _RESPONSE_STATUS_TO_ENUM, ) @@ -39,8 +46,11 @@ def wrapper(self, *args): def _issuer_key_hash(backend, cert_id): key_hash = backend._ffi.new("ASN1_OCTET_STRING **") res = backend._lib.OCSP_id_get0_info( - backend._ffi.NULL, backend._ffi.NULL, - key_hash, backend._ffi.NULL, cert_id + backend._ffi.NULL, + backend._ffi.NULL, + key_hash, + backend._ffi.NULL, + cert_id, ) backend.openssl_assert(res == 1) backend.openssl_assert(key_hash[0] != backend._ffi.NULL) @@ -50,8 +60,11 @@ def _issuer_key_hash(backend, cert_id): def _issuer_name_hash(backend, cert_id): name_hash = backend._ffi.new("ASN1_OCTET_STRING **") res = backend._lib.OCSP_id_get0_info( - name_hash, backend._ffi.NULL, - backend._ffi.NULL, backend._ffi.NULL, cert_id + name_hash, + backend._ffi.NULL, + backend._ffi.NULL, + backend._ffi.NULL, + cert_id, ) backend.openssl_assert(res == 1) backend.openssl_assert(name_hash[0] != backend._ffi.NULL) @@ -61,8 +74,7 @@ def _issuer_name_hash(backend, cert_id): def _serial_number(backend, cert_id): num = backend._ffi.new("ASN1_INTEGER **") res = backend._lib.OCSP_id_get0_info( - backend._ffi.NULL, backend._ffi.NULL, - backend._ffi.NULL, num, cert_id + backend._ffi.NULL, backend._ffi.NULL, backend._ffi.NULL, num, cert_id ) backend.openssl_assert(res == 1) backend.openssl_assert(num[0] != backend._ffi.NULL) @@ -72,8 +84,11 @@ def _serial_number(backend, cert_id): def _hash_algorithm(backend, cert_id): asn1obj = backend._ffi.new("ASN1_OBJECT **") res = backend._lib.OCSP_id_get0_info( - backend._ffi.NULL, asn1obj, - backend._ffi.NULL, backend._ffi.NULL, cert_id + backend._ffi.NULL, + asn1obj, + backend._ffi.NULL, + backend._ffi.NULL, + cert_id, ) backend.openssl_assert(res == 1) backend.openssl_assert(asn1obj[0] != backend._ffi.NULL) @@ -82,7 +97,7 @@ def _hash_algorithm(backend, cert_id): return _OIDS_TO_HASH[oid] except KeyError: raise UnsupportedAlgorithm( - "Signature algorithm OID: {0} not recognized".format(oid) + "Signature algorithm OID: {} not recognized".format(oid) ) @@ -102,9 +117,13 @@ def __init__(self, backend, ocsp_response): self._basic = self._backend._ffi.gc( basic, self._backend._lib.OCSP_BASICRESP_free ) - self._backend.openssl_assert( - self._backend._lib.OCSP_resp_count(self._basic) == 1 - ) + num_resp = self._backend._lib.OCSP_resp_count(self._basic) + if num_resp != 1: + raise ValueError( + "OCSP response contains more than one SINGLERESP structure" + ", which this library does not support. " + "{} found".format(num_resp) + ) self._single = self._backend._lib.OCSP_resp_get0(self._basic, 0) self._backend.openssl_assert( self._single != self._backend._ffi.NULL @@ -134,7 +153,7 @@ def signature_hash_algorithm(self): return x509._SIG_OIDS_TO_HASH[oid] except KeyError: raise UnsupportedAlgorithm( - "Signature algorithm OID:{0} not recognized".format(oid) + "Signature algorithm OID:{} not recognized".format(oid) ) @property @@ -317,13 +336,16 @@ def serial_number(self): @utils.cached_property @_requires_successful_response def extensions(self): - return _OCSP_BASICRESP_EXT_PARSER.parse(self._backend, self._basic) + return self._backend._ocsp_basicresp_ext_parser.parse(self._basic) + + @utils.cached_property + @_requires_successful_response + def single_extensions(self): + return self._backend._ocsp_singleresp_ext_parser.parse(self._single) def public_bytes(self, encoding): if encoding is not serialization.Encoding.DER: - raise ValueError( - "The only allowed encoding value is Encoding.DER" - ) + raise ValueError("The only allowed encoding value is Encoding.DER") bio = self._backend._create_mem_bio_gc() res = self._backend._lib.i2d_OCSP_RESPONSE_bio( @@ -338,7 +360,7 @@ class _OCSPRequest(object): def __init__(self, backend, ocsp_request): if backend._lib.OCSP_request_onereq_count(ocsp_request) > 1: raise NotImplementedError( - 'OCSP request contains more than one request' + "OCSP request contains more than one request" ) self._backend = backend self._ocsp_request = ocsp_request @@ -367,13 +389,11 @@ def hash_algorithm(self): @utils.cached_property def extensions(self): - return _OCSP_REQ_EXT_PARSER.parse(self._backend, self._ocsp_request) + return self._backend._ocsp_req_ext_parser.parse(self._ocsp_request) def public_bytes(self, encoding): if encoding is not serialization.Encoding.DER: - raise ValueError( - "The only allowed encoding value is Encoding.DER" - ) + raise ValueError("The only allowed encoding value is Encoding.DER") bio = self._backend._create_mem_bio_gc() res = self._backend._lib.i2d_OCSP_REQUEST_bio(bio, self._ocsp_request) diff --git a/src/cryptography/hazmat/backends/openssl/poly1305.py b/src/cryptography/hazmat/backends/openssl/poly1305.py new file mode 100644 index 000000000000..17493ca60ce8 --- /dev/null +++ b/src/cryptography/hazmat/backends/openssl/poly1305.py @@ -0,0 +1,65 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.primitives import constant_time + + +_POLY1305_TAG_SIZE = 16 +_POLY1305_KEY_SIZE = 32 + + +class _Poly1305Context(object): + def __init__(self, backend, key): + 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.Cryptography_EVP_MD_CTX_new() + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + self._ctx = self._backend._ffi.gc( + ctx, self._backend._lib.Cryptography_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): + 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): + buf = self._backend._ffi.new("unsigned char[]", _POLY1305_TAG_SIZE) + outlen = self._backend._ffi.new("size_t *") + 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): + 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/backends/openssl/rsa.py b/src/cryptography/hazmat/backends/openssl/rsa.py index 30d59bd80787..66b37224e443 100644 --- a/src/cryptography/hazmat/backends/openssl/rsa.py +++ b/src/cryptography/hazmat/backends/openssl/rsa.py @@ -4,25 +4,34 @@ from __future__ import absolute_import, division, print_function -import math - from cryptography import utils from cryptography.exceptions import ( - InvalidSignature, UnsupportedAlgorithm, _Reasons + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, ) from cryptography.hazmat.backends.openssl.utils import ( - _calculate_digest_and_algorithm, _check_not_prehashed, - _warn_sign_verify_deprecated + _calculate_digest_and_algorithm, + _check_not_prehashed, + _warn_sign_verify_deprecated, ) from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ( - AsymmetricSignatureContext, AsymmetricVerificationContext, rsa + AsymmetricSignatureContext, + AsymmetricVerificationContext, + rsa, ) from cryptography.hazmat.primitives.asymmetric.padding import ( - AsymmetricPadding, MGF1, OAEP, PKCS1v15, PSS, calculate_max_pss_salt_length + AsymmetricPadding, + MGF1, + OAEP, + PKCS1v15, + PSS, + calculate_max_pss_salt_length, ) from cryptography.hazmat.primitives.asymmetric.rsa import ( - RSAPrivateKeyWithSerialization, RSAPublicKeyWithSerialization + RSAPrivateKeyWithSerialization, + RSAPublicKeyWithSerialization, ) @@ -47,22 +56,20 @@ def _enc_dec_rsa(backend, key, data, padding): if not isinstance(padding._mgf, MGF1): raise UnsupportedAlgorithm( "Only MGF1 is supported by this backend.", - _Reasons.UNSUPPORTED_MGF + _Reasons.UNSUPPORTED_MGF, ) if not backend.rsa_padding_supported(padding): raise UnsupportedAlgorithm( "This combination of padding and hash algorithm is not " "supported by this backend.", - _Reasons.UNSUPPORTED_PADDING + _Reasons.UNSUPPORTED_PADDING, ) else: raise UnsupportedAlgorithm( - "{0} is not supported by this backend.".format( - padding.name - ), - _Reasons.UNSUPPORTED_PADDING + "{} is not supported by this backend.".format(padding.name), + _Reasons.UNSUPPORTED_PADDING, ) return _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding) @@ -76,24 +83,19 @@ def _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding): init = backend._lib.EVP_PKEY_decrypt_init crypt = backend._lib.EVP_PKEY_decrypt - pkey_ctx = backend._lib.EVP_PKEY_CTX_new( - key._evp_pkey, backend._ffi.NULL - ) + pkey_ctx = backend._lib.EVP_PKEY_CTX_new(key._evp_pkey, backend._ffi.NULL) backend.openssl_assert(pkey_ctx != backend._ffi.NULL) pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free) res = init(pkey_ctx) backend.openssl_assert(res == 1) - res = backend._lib.EVP_PKEY_CTX_set_rsa_padding( - pkey_ctx, padding_enum) + res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding_enum) backend.openssl_assert(res > 0) buf_size = backend._lib.EVP_PKEY_size(key._evp_pkey) backend.openssl_assert(buf_size > 0) - if ( - isinstance(padding, OAEP) and - backend._lib.Cryptography_HAS_RSA_OAEP_MD - ): + if isinstance(padding, OAEP) and backend._lib.Cryptography_HAS_RSA_OAEP_MD: mgf1_md = backend._evp_md_non_null_from_algorithm( - padding._mgf._algorithm) + padding._mgf._algorithm + ) res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md) backend.openssl_assert(res > 0) oaep_md = backend._evp_md_non_null_from_algorithm(padding._algorithm) @@ -101,9 +103,9 @@ def _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding): backend.openssl_assert(res > 0) if ( - isinstance(padding, OAEP) and - padding._label is not None and - len(padding._label) > 0 + isinstance(padding, OAEP) + and padding._label is not None + and len(padding._label) > 0 ): # set0_rsa_oaep_label takes ownership of the char * so we need to # copy it into some new memory @@ -117,40 +119,19 @@ def _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding): outlen = backend._ffi.new("size_t *", buf_size) buf = backend._ffi.new("unsigned char[]", buf_size) + # Everything from this line onwards is written with the goal of being as + # constant-time as is practical given the constraints of Python and our + # API. See Bleichenbacher's '98 attack on RSA, and its many many variants. + # As such, you should not attempt to change this (particularly to "clean it + # up") without understanding why it was written this way (see + # Chesterton's Fence), and without measuring to verify you have not + # introduced observable time differences. res = crypt(pkey_ctx, buf, outlen, data, len(data)) + resbuf = backend._ffi.buffer(buf)[: outlen[0]] + backend._lib.ERR_clear_error() if res <= 0: - _handle_rsa_enc_dec_error(backend, key) - - return backend._ffi.buffer(buf)[:outlen[0]] - - -def _handle_rsa_enc_dec_error(backend, key): - errors = backend._consume_errors() - backend.openssl_assert(errors) - backend.openssl_assert(errors[0].lib == backend._lib.ERR_LIB_RSA) - if isinstance(key, _RSAPublicKey): - backend.openssl_assert( - errors[0].reason == backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE - ) - raise ValueError( - "Data too long for key size. Encrypt less data or use a " - "larger key size." - ) - else: - decoding_errors = [ - backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_01, - backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_02, - backend._lib.RSA_R_OAEP_DECODING_ERROR, - # Though this error looks similar to the - # RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE, this occurs on decrypts, - # rather than on encrypts - backend._lib.RSA_R_DATA_TOO_LARGE_FOR_MODULUS, - ] - if backend._lib.Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR: - decoding_errors.append(backend._lib.RSA_R_PKCS_DECODING_ERROR) - - backend.openssl_assert(errors[0].reason in decoding_errors) - raise ValueError("Decryption failed.") + raise ValueError("Encryption/decryption failed.") + return resbuf def _rsa_sig_determine_padding(backend, key, padding, algorithm): @@ -166,20 +147,22 @@ def _rsa_sig_determine_padding(backend, key, padding, algorithm): if not isinstance(padding._mgf, MGF1): raise UnsupportedAlgorithm( "Only MGF1 is supported by this backend.", - _Reasons.UNSUPPORTED_MGF + _Reasons.UNSUPPORTED_MGF, ) # Size of key in bytes - 2 is the maximum # PSS signature length (salt length is checked later) if pkey_size - algorithm.digest_size - 2 < 0: - raise ValueError("Digest too large for key size. Use a larger " - "key or different digest.") + raise ValueError( + "Digest too large for key size. Use a larger " + "key or different digest." + ) padding_enum = backend._lib.RSA_PKCS1_PSS_PADDING else: raise UnsupportedAlgorithm( - "{0} is not supported by this backend.".format(padding.name), - _Reasons.UNSUPPORTED_PADDING + "{} is not supported by this backend.".format(padding.name), + _Reasons.UNSUPPORTED_PADDING, ) return padding_enum @@ -197,10 +180,10 @@ def _rsa_sig_setup(backend, padding, algorithm, key, data, init_func): if res == 0: backend._consume_errors() raise UnsupportedAlgorithm( - "{0} is not supported by this backend for RSA signing.".format( + "{} is not supported by this backend for RSA signing.".format( algorithm.name ), - _Reasons.UNSUPPORTED_HASH + _Reasons.UNSUPPORTED_HASH, ) res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding_enum) backend.openssl_assert(res > 0) @@ -211,7 +194,8 @@ def _rsa_sig_setup(backend, padding, algorithm, key, data, init_func): backend.openssl_assert(res > 0) mgf1_md = backend._evp_md_non_null_from_algorithm( - padding._mgf._algorithm) + padding._mgf._algorithm + ) res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md) backend.openssl_assert(res > 0) @@ -220,45 +204,39 @@ def _rsa_sig_setup(backend, padding, algorithm, key, data, init_func): def _rsa_sig_sign(backend, padding, algorithm, private_key, data): pkey_ctx = _rsa_sig_setup( - backend, padding, algorithm, private_key, data, - backend._lib.EVP_PKEY_sign_init + backend, + padding, + algorithm, + private_key, + data, + backend._lib.EVP_PKEY_sign_init, ) buflen = backend._ffi.new("size_t *") res = backend._lib.EVP_PKEY_sign( - pkey_ctx, - backend._ffi.NULL, - buflen, - data, - len(data) + pkey_ctx, backend._ffi.NULL, buflen, data, len(data) ) backend.openssl_assert(res == 1) buf = backend._ffi.new("unsigned char[]", buflen[0]) - res = backend._lib.EVP_PKEY_sign( - pkey_ctx, buf, buflen, data, len(data)) + res = backend._lib.EVP_PKEY_sign(pkey_ctx, buf, buflen, data, len(data)) if res != 1: - errors = backend._consume_errors() - backend.openssl_assert(errors[0].lib == backend._lib.ERR_LIB_RSA) - if ( - errors[0].reason == - backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE - ): - reason = ("Salt length too long for key size. Try using " - "MAX_LENGTH instead.") - else: - backend.openssl_assert( - errors[0].reason == - backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY - ) - reason = "Digest too large for key size. Use a larger key." - raise ValueError(reason) + errors = backend._consume_errors_with_text() + raise ValueError( + "Digest or salt length too long for key size. Use a larger key " + "or shorter salt length if you are specifying a PSS salt", + errors, + ) return backend._ffi.buffer(buf)[:] def _rsa_sig_verify(backend, padding, algorithm, public_key, signature, data): pkey_ctx = _rsa_sig_setup( - backend, padding, algorithm, public_key, data, - backend._lib.EVP_PKEY_verify_init + backend, + padding, + algorithm, + public_key, + data, + backend._lib.EVP_PKEY_verify_init, ) res = backend._lib.EVP_PKEY_verify( pkey_ctx, signature, len(signature), data, len(data) @@ -295,7 +273,7 @@ def finalize(self): self._padding, self._algorithm, self._private_key, - self._hash_ctx.finalize() + self._hash_ctx.finalize(), ) @@ -325,21 +303,33 @@ def verify(self): self._algorithm, self._public_key, self._signature, - self._hash_ctx.finalize() + self._hash_ctx.finalize(), ) @utils.register_interface(RSAPrivateKeyWithSerialization) class _RSAPrivateKey(object): def __init__(self, backend, rsa_cdata, evp_pkey): + res = backend._lib.RSA_check_key(rsa_cdata) + if res != 1: + errors = backend._consume_errors_with_text() + raise ValueError("Invalid private key", errors) + + # Blinding is on by default in many versions of OpenSSL, but let's + # just be conservative here. + res = backend._lib.RSA_blinding_on(rsa_cdata, backend._ffi.NULL) + backend.openssl_assert(res == 1) + self._backend = backend self._rsa_cdata = rsa_cdata self._evp_pkey = evp_pkey n = self._backend._ffi.new("BIGNUM **") self._backend._lib.RSA_get0_key( - self._rsa_cdata, n, self._backend._ffi.NULL, - self._backend._ffi.NULL + self._rsa_cdata, + n, + self._backend._ffi.NULL, + self._backend._ffi.NULL, ) self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) self._key_size = self._backend._lib.BN_num_bits(n[0]) @@ -352,7 +342,7 @@ def signer(self, padding, algorithm): return _RSASignatureContext(self._backend, self, padding, algorithm) def decrypt(self, ciphertext, padding): - key_size_bytes = int(math.ceil(self.key_size / 8.0)) + key_size_bytes = (self.key_size + 7) // 8 if key_size_bytes != len(ciphertext): raise ValueError("Ciphertext length must be equal to key size.") @@ -362,8 +352,6 @@ def public_key(self): ctx = self._backend._lib.RSAPublicKey_dup(self._rsa_cdata) self._backend.openssl_assert(ctx != self._backend._ffi.NULL) ctx = self._backend._ffi.gc(ctx, self._backend._lib.RSA_free) - res = self._backend._lib.RSA_blinding_on(ctx, self._backend._ffi.NULL) - self._backend.openssl_assert(res == 1) evp_pkey = self._backend._rsa_cdata_to_evp_pkey(ctx) return _RSAPublicKey(self._backend, ctx, evp_pkey) @@ -399,7 +387,7 @@ def private_numbers(self): public_numbers=rsa.RSAPublicNumbers( e=self._backend._bn_to_int(e[0]), n=self._backend._bn_to_int(n[0]), - ) + ), ) def private_bytes(self, encoding, format, encryption_algorithm): @@ -407,8 +395,9 @@ def private_bytes(self, encoding, format, encryption_algorithm): encoding, format, encryption_algorithm, + self, self._evp_pkey, - self._rsa_cdata + self._rsa_cdata, ) def sign(self, data, padding, algorithm): @@ -421,14 +410,21 @@ def sign(self, data, padding, algorithm): @utils.register_interface(RSAPublicKeyWithSerialization) class _RSAPublicKey(object): def __init__(self, backend, rsa_cdata, evp_pkey): + # Blinding is on by default in many versions of OpenSSL, but let's + # just be conservative here. + res = backend._lib.RSA_blinding_on(rsa_cdata, backend._ffi.NULL) + backend.openssl_assert(res == 1) + self._backend = backend self._rsa_cdata = rsa_cdata self._evp_pkey = evp_pkey n = self._backend._ffi.new("BIGNUM **") self._backend._lib.RSA_get0_key( - self._rsa_cdata, n, self._backend._ffi.NULL, - self._backend._ffi.NULL + self._rsa_cdata, + n, + self._backend._ffi.NULL, + self._backend._ffi.NULL, ) self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) self._key_size = self._backend._lib.BN_num_bits(n[0]) @@ -462,11 +458,7 @@ def public_numbers(self): def public_bytes(self, encoding, format): return self._backend._public_key_bytes( - encoding, - format, - self, - self._evp_pkey, - self._rsa_cdata + encoding, format, self, self._evp_pkey, self._rsa_cdata ) def verify(self, signature, data, padding, algorithm): diff --git a/src/cryptography/hazmat/backends/openssl/utils.py b/src/cryptography/hazmat/backends/openssl/utils.py index 363f3d2c25db..ec0b947a44c6 100644 --- a/src/cryptography/hazmat/backends/openssl/utils.py +++ b/src/cryptography/hazmat/backends/openssl/utils.py @@ -17,9 +17,7 @@ def _evp_pkey_derive(backend, evp_pkey, peer_public_key): ctx = backend._ffi.gc(ctx, backend._lib.EVP_PKEY_CTX_free) res = backend._lib.EVP_PKEY_derive_init(ctx) backend.openssl_assert(res == 1) - res = backend._lib.EVP_PKEY_derive_set_peer( - ctx, peer_public_key._evp_pkey - ) + res = backend._lib.EVP_PKEY_derive_set_peer(ctx, peer_public_key._evp_pkey) backend.openssl_assert(res == 1) keylen = backend._ffi.new("size_t *") res = backend._lib.EVP_PKEY_derive(ctx, backend._ffi.NULL, keylen) @@ -28,9 +26,7 @@ def _evp_pkey_derive(backend, evp_pkey, peer_public_key): buf = backend._ffi.new("unsigned char[]", keylen[0]) res = backend._lib.EVP_PKEY_derive(ctx, buf, keylen) if res != 1: - raise ValueError( - "Null shared key derived from public/private pair." - ) + raise ValueError("Null shared key derived from public/private pair.") return backend._ffi.buffer(buf, keylen[0])[:] @@ -64,6 +60,6 @@ def _warn_sign_verify_deprecated(): warnings.warn( "signer and verifier have been deprecated. Please use sign " "and verify instead.", - utils.PersistentlyDeprecated, - stacklevel=3 + utils.PersistentlyDeprecated2017, + stacklevel=3, ) diff --git a/src/cryptography/hazmat/backends/openssl/x25519.py b/src/cryptography/hazmat/backends/openssl/x25519.py index 914f59413a2d..4971c5481402 100644 --- a/src/cryptography/hazmat/backends/openssl/x25519.py +++ b/src/cryptography/hazmat/backends/openssl/x25519.py @@ -4,13 +4,12 @@ from __future__ import absolute_import, division, print_function -import warnings - from cryptography import utils from cryptography.hazmat.backends.openssl.utils import _evp_pkey_derive from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric.x25519 import ( - X25519PrivateKey, X25519PublicKey + X25519PrivateKey, + X25519PublicKey, ) @@ -23,26 +22,14 @@ def __init__(self, backend, evp_pkey): self._backend = backend self._evp_pkey = evp_pkey - def public_bytes(self, encoding=None, format=None): - if encoding is None or format is None: - if encoding is not None or format is not None: - raise ValueError("Both encoding and format are required") - else: - warnings.warn( - "public_bytes now requires encoding and format arguments. " - "Support for calling without arguments will be removed in " - "cryptography 2.7", - utils.DeprecatedIn25, - ) - encoding = serialization.Encoding.Raw - format = serialization.PublicFormat.Raw + def public_bytes(self, encoding, format): if ( - encoding is serialization.Encoding.Raw or - format is serialization.PublicFormat.Raw + 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 + 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" @@ -50,15 +37,6 @@ def public_bytes(self, encoding=None, format=None): return self._raw_public_bytes() - if ( - encoding in serialization._PEM_DER and - format is not serialization.PublicFormat.SubjectPublicKeyInfo - ): - raise ValueError( - "format must be SubjectPublicKeyInfo when encoding is PEM or " - "DER" - ) - return self._backend._public_key_bytes( encoding, format, self, self._evp_pkey, None ) @@ -99,37 +77,29 @@ def exchange(self, peer_public_key): if not isinstance(peer_public_key, X25519PublicKey): raise TypeError("peer_public_key must be X25519PublicKey.") - return _evp_pkey_derive( - self._backend, self._evp_pkey, peer_public_key - ) + return _evp_pkey_derive(self._backend, self._evp_pkey, peer_public_key) def private_bytes(self, encoding, format, encryption_algorithm): if ( - encoding is serialization.Encoding.Raw or - format is serialization.PublicFormat.Raw + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw ): if ( - format is not serialization.PrivateFormat.Raw or - encoding is not serialization.Encoding.Raw or not - isinstance(encryption_algorithm, serialization.NoEncryption) + 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" + "and encryption_algorithm must be NoEncryption()" ) return self._raw_private_bytes() - if ( - encoding in serialization._PEM_DER and - format is not serialization.PrivateFormat.PKCS8 - ): - raise ValueError( - "format must be PKCS8 when encoding is PEM or DER" - ) - return self._backend._private_key_bytes( - encoding, format, encryption_algorithm, self._evp_pkey, None + encoding, format, encryption_algorithm, self, self._evp_pkey, None ) def _raw_private_bytes(self): @@ -139,9 +109,13 @@ def _raw_private_bytes(self): # using the last 32 bytes, which is the key itself. bio = self._backend._create_mem_bio_gc() res = self._backend._lib.i2d_PKCS8PrivateKey_bio( - bio, self._evp_pkey, - self._backend._ffi.NULL, self._backend._ffi.NULL, - 0, self._backend._ffi.NULL, self._backend._ffi.NULL + bio, + self._evp_pkey, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + 0, + self._backend._ffi.NULL, + self._backend._ffi.NULL, ) self._backend.openssl_assert(res == 1) pkcs8 = self._backend._read_mem_bio(bio) diff --git a/src/cryptography/hazmat/backends/openssl/x448.py b/src/cryptography/hazmat/backends/openssl/x448.py index 13e4ce15e01b..7ebcdf84bcc2 100644 --- a/src/cryptography/hazmat/backends/openssl/x448.py +++ b/src/cryptography/hazmat/backends/openssl/x448.py @@ -8,7 +8,8 @@ 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 + X448PrivateKey, + X448PublicKey, ) _X448_KEY_SIZE = 56 @@ -22,12 +23,12 @@ def __init__(self, backend, evp_pkey): def public_bytes(self, encoding, format): if ( - encoding is serialization.Encoding.Raw or - format is serialization.PublicFormat.Raw + 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 + 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" @@ -35,15 +36,6 @@ def public_bytes(self, encoding, format): return self._raw_public_bytes() - if ( - encoding in serialization._PEM_DER and - format is not serialization.PublicFormat.SubjectPublicKeyInfo - ): - raise ValueError( - "format must be SubjectPublicKeyInfo when encoding is PEM or " - "DER" - ) - return self._backend._public_key_bytes( encoding, format, self, self._evp_pkey, None ) @@ -79,37 +71,29 @@ def exchange(self, peer_public_key): if not isinstance(peer_public_key, X448PublicKey): raise TypeError("peer_public_key must be X448PublicKey.") - return _evp_pkey_derive( - self._backend, self._evp_pkey, peer_public_key - ) + return _evp_pkey_derive(self._backend, self._evp_pkey, peer_public_key) def private_bytes(self, encoding, format, encryption_algorithm): if ( - encoding is serialization.Encoding.Raw or - format is serialization.PublicFormat.Raw + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw ): if ( - format is not serialization.PrivateFormat.Raw or - encoding is not serialization.Encoding.Raw or not - isinstance(encryption_algorithm, serialization.NoEncryption) + 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" + "and encryption_algorithm must be NoEncryption()" ) return self._raw_private_bytes() - if ( - encoding in serialization._PEM_DER and - format is not serialization.PrivateFormat.PKCS8 - ): - raise ValueError( - "format must be PKCS8 when encoding is PEM or DER" - ) - return self._backend._private_key_bytes( - encoding, format, encryption_algorithm, self._evp_pkey, None + encoding, format, encryption_algorithm, self, self._evp_pkey, None ) def _raw_private_bytes(self): diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index ac1838c6d131..4d0dac7649a6 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -6,31 +6,43 @@ import datetime import operator -import warnings from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm from cryptography.hazmat.backends.openssl.decode_asn1 import ( - _CERTIFICATE_EXTENSION_PARSER, _CERTIFICATE_EXTENSION_PARSER_NO_SCT, - _CRL_EXTENSION_PARSER, _CSR_EXTENSION_PARSER, - _REVOKED_CERTIFICATE_EXTENSION_PARSER, _asn1_integer_to_int, - _asn1_string_to_bytes, _decode_x509_name, _obj2txt, _parse_asn1_time + _asn1_integer_to_int, + _asn1_string_to_bytes, + _decode_x509_name, + _obj2txt, + _parse_asn1_time, ) from cryptography.hazmat.backends.openssl.encode_asn1 import ( - _encode_asn1_int_gc + _encode_asn1_int_gc, + _txt2obj_gc, ) from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa +from cryptography.x509.name import _ASN1Type @utils.register_interface(x509.Certificate) class _Certificate(object): - def __init__(self, backend, x509): + def __init__(self, backend, x509_cert): self._backend = backend - self._x509 = x509 + self._x509 = x509_cert + + version = self._backend._lib.X509_get_version(self._x509) + if version == 0: + self._version = x509.Version.v1 + elif version == 2: + self._version = x509.Version.v3 + else: + raise x509.InvalidVersion( + "{} is not a valid X509 version".format(version), version + ) def __repr__(self): - return "".format(self.subject) + return "".format(self.subject) def __eq__(self, other): if not isinstance(other, x509.Certificate): @@ -45,31 +57,15 @@ def __ne__(self, other): def __hash__(self): return hash(self.public_bytes(serialization.Encoding.DER)) + def __deepcopy__(self, memo): + return self + def fingerprint(self, algorithm): h = hashes.Hash(algorithm, self._backend) h.update(self.public_bytes(serialization.Encoding.DER)) return h.finalize() - @property - def version(self): - version = self._backend._lib.X509_get_version(self._x509) - if version == 0: - return x509.Version.v1 - elif version == 2: - return x509.Version.v3 - else: - raise x509.InvalidVersion( - "{0} is not a valid X509 version".format(version), version - ) - - @property - def serial(self): - warnings.warn( - "Certificate serial is deprecated, use serial_number instead.", - utils.PersistentlyDeprecated, - stacklevel=2 - ) - return self.serial_number + version = utils.read_only_property("_version") @property def serial_number(self): @@ -90,12 +86,12 @@ def public_key(self): @property def not_valid_before(self): - asn1_time = self._backend._lib.X509_get_notBefore(self._x509) + asn1_time = self._backend._lib.X509_getm_notBefore(self._x509) return _parse_asn1_time(self._backend, asn1_time) @property def not_valid_after(self): - asn1_time = self._backend._lib.X509_get_notAfter(self._x509) + asn1_time = self._backend._lib.X509_getm_notAfter(self._x509) return _parse_asn1_time(self._backend, asn1_time) @property @@ -117,7 +113,7 @@ def signature_hash_algorithm(self): return x509._SIG_OIDS_TO_HASH[oid] except KeyError: raise UnsupportedAlgorithm( - "Signature algorithm OID:{0} not recognized".format(oid) + "Signature algorithm OID:{} not recognized".format(oid) ) @property @@ -132,14 +128,7 @@ def signature_algorithm_oid(self): @utils.cached_property def extensions(self): - if self._backend._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER: - return _CERTIFICATE_EXTENSION_PARSER.parse( - self._backend, self._x509 - ) - else: - return _CERTIFICATE_EXTENSION_PARSER_NO_SCT.parse( - self._backend, self._x509 - ) + return self._backend._certificate_extension_parser.parse(self._x509) @property def signature(self): @@ -201,13 +190,13 @@ def revocation_date(self): self._backend, self._backend._lib.X509_REVOKED_get0_revocationDate( self._x509_revoked - ) + ), ) @utils.cached_property def extensions(self): - return _REVOKED_CERTIFICATE_EXTENSION_PARSER.parse( - self._backend, self._x509_revoked + return self._backend._revoked_cert_extension_parser.parse( + self._x509_revoked ) @@ -230,9 +219,7 @@ def __ne__(self, other): def fingerprint(self, algorithm): h = hashes.Hash(algorithm, self._backend) bio = self._backend._create_mem_bio_gc() - res = self._backend._lib.i2d_X509_CRL_bio( - bio, self._x509_crl - ) + res = self._backend._lib.i2d_X509_CRL_bio(bio, self._x509_crl) self._backend.openssl_assert(res == 1) der = self._backend._read_mem_bio(bio) h.update(der) @@ -257,9 +244,7 @@ def get_revoked_certificate_by_serial_number(self, serial_number): if res == 0: return None else: - self._backend.openssl_assert( - revoked[0] != self._backend._ffi.NULL - ) + self._backend.openssl_assert(revoked[0] != self._backend._ffi.NULL) return _RevokedCertificate( self._backend, self._sorted_crl, revoked[0] ) @@ -271,7 +256,7 @@ def signature_hash_algorithm(self): return x509._SIG_OIDS_TO_HASH[oid] except KeyError: raise UnsupportedAlgorithm( - "Signature algorithm OID:{0} not recognized".format(oid) + "Signature algorithm OID:{} not recognized".format(oid) ) @property @@ -366,13 +351,17 @@ def __len__(self): @utils.cached_property def extensions(self): - return _CRL_EXTENSION_PARSER.parse(self._backend, self._x509_crl) + return self._backend._crl_extension_parser.parse(self._x509_crl) def is_signature_valid(self, public_key): - if not isinstance(public_key, (dsa.DSAPublicKey, rsa.RSAPublicKey, - ec.EllipticCurvePublicKey)): - raise TypeError('Expecting one of DSAPublicKey, RSAPublicKey,' - ' or EllipticCurvePublicKey.') + if not isinstance( + public_key, + (dsa.DSAPublicKey, rsa.RSAPublicKey, ec.EllipticCurvePublicKey), + ): + raise TypeError( + "Expecting one of DSAPublicKey, RSAPublicKey," + " or EllipticCurvePublicKey." + ) res = self._backend._lib.X509_CRL_verify( self._x509_crl, public_key._evp_pkey ) @@ -423,7 +412,7 @@ def signature_hash_algorithm(self): return x509._SIG_OIDS_TO_HASH[oid] except KeyError: raise UnsupportedAlgorithm( - "Signature algorithm OID:{0} not recognized".format(oid) + "Signature algorithm OID:{} not recognized".format(oid) ) @property @@ -442,12 +431,13 @@ def extensions(self): x509_exts = self._backend._ffi.gc( x509_exts, lambda x: self._backend._lib.sk_X509_EXTENSION_pop_free( - x, self._backend._ffi.addressof( + x, + self._backend._ffi.addressof( self._backend._lib._original_lib, "X509_EXTENSION_free" - ) - ) + ), + ), ) - return _CSR_EXTENSION_PARSER.parse(self._backend, x509_exts) + return self._backend._csr_extension_parser.parse(x509_exts) def public_bytes(self, encoding): bio = self._backend._create_mem_bio_gc() @@ -495,6 +485,47 @@ def is_signature_valid(self): return True + def get_attribute_for_oid(self, oid): + obj = _txt2obj_gc(self._backend, oid.dotted_string) + pos = self._backend._lib.X509_REQ_get_attr_by_OBJ( + self._x509_req, obj, -1 + ) + if pos == -1: + raise x509.AttributeNotFound( + "No {} attribute was found".format(oid), oid + ) + + attr = self._backend._lib.X509_REQ_get_attr(self._x509_req, pos) + self._backend.openssl_assert(attr != self._backend._ffi.NULL) + # We don't support multiple valued attributes for now. + self._backend.openssl_assert( + self._backend._lib.X509_ATTRIBUTE_count(attr) == 1 + ) + asn1_type = self._backend._lib.X509_ATTRIBUTE_get0_type(attr, 0) + self._backend.openssl_assert(asn1_type != self._backend._ffi.NULL) + # We need this to ensure that our C type cast is safe. + # Also this should always be a sane string type, but we'll see if + # that is true in the real world... + if asn1_type.type not in ( + _ASN1Type.UTF8String.value, + _ASN1Type.PrintableString.value, + _ASN1Type.IA5String.value, + ): + raise ValueError( + "OID {} has a disallowed ASN.1 type: {}".format( + oid, asn1_type.type + ) + ) + + data = self._backend._lib.X509_ATTRIBUTE_get0_data( + attr, 0, asn1_type.type, self._backend._ffi.NULL + ) + self._backend.openssl_assert(data != self._backend._ffi.NULL) + # This cast is safe iff we assert on the type above to ensure + # that it is always a type of ASN1_STRING + data = self._backend._ffi.cast("ASN1_STRING *", data) + return _asn1_string_to_bytes(self._backend, data) + @utils.register_interface( x509.certificate_transparency.SignedCertificateTimestamp @@ -523,9 +554,9 @@ def log_id(self): def timestamp(self): timestamp = self._backend._lib.SCT_get_timestamp(self._sct) milliseconds = timestamp % 1000 - return datetime.datetime.utcfromtimestamp( - timestamp // 1000 - ).replace(microsecond=milliseconds * 1000) + return datetime.datetime.utcfromtimestamp(timestamp // 1000).replace( + microsecond=milliseconds * 1000 + ) @property def entry_type(self): diff --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py index c0238dcc2028..cdc18eab6848 100644 --- a/src/cryptography/hazmat/bindings/openssl/_conditional.py +++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py @@ -13,24 +13,6 @@ def cryptography_has_ec2m(): ] -def cryptography_has_ec_1_0_2(): - return [ - "EC_curve_nid2nist", - ] - - -def cryptography_has_set_ecdh_auto(): - return [ - "SSL_CTX_set_ecdh_auto", - ] - - -def cryptography_has_rsa_r_pkcs_decoding_error(): - return [ - "RSA_R_PKCS_DECODING_ERROR" - ] - - def cryptography_has_rsa_oaep_md(): return [ "EVP_PKEY_CTX_set_rsa_oaep_md", @@ -51,78 +33,22 @@ def cryptography_has_ssl3_method(): ] -def cryptography_has_alpn(): - return [ - "SSL_CTX_set_alpn_protos", - "SSL_set_alpn_protos", - "SSL_CTX_set_alpn_select_cb", - "SSL_get0_alpn_selected", - ] - - -def cryptography_has_compression(): - return [ - "SSL_get_current_compression", - "SSL_get_current_expansion", - "SSL_COMP_get_name", - ] - - -def cryptography_has_get_server_tmp_key(): - return [ - "SSL_get_server_tmp_key", - ] - - -def cryptography_has_102_verification_error_codes(): - return [ - 'X509_V_ERR_SUITE_B_INVALID_VERSION', - 'X509_V_ERR_SUITE_B_INVALID_ALGORITHM', - 'X509_V_ERR_SUITE_B_INVALID_CURVE', - 'X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM', - 'X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED', - 'X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256', - 'X509_V_ERR_HOSTNAME_MISMATCH', - 'X509_V_ERR_EMAIL_MISMATCH', - 'X509_V_ERR_IP_ADDRESS_MISMATCH' - ] - - -def cryptography_has_102_verification_params(): +def cryptography_has_102_verification(): return [ + "X509_V_ERR_SUITE_B_INVALID_VERSION", + "X509_V_ERR_SUITE_B_INVALID_ALGORITHM", + "X509_V_ERR_SUITE_B_INVALID_CURVE", + "X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM", + "X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED", + "X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256", "X509_V_FLAG_SUITEB_128_LOS_ONLY", "X509_V_FLAG_SUITEB_192_LOS", "X509_V_FLAG_SUITEB_128_LOS", - "X509_VERIFY_PARAM_set1_host", - "X509_VERIFY_PARAM_set1_email", - "X509_VERIFY_PARAM_set1_ip", - "X509_VERIFY_PARAM_set1_ip_asc", - "X509_VERIFY_PARAM_set_hostflags", - "SSL_get0_param", - "X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT", - "X509_CHECK_FLAG_NO_WILDCARDS", - "X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS", - "X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS", - "X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS" ] def cryptography_has_110_verification_params(): - return [ - "X509_CHECK_FLAG_NEVER_CHECK_SUBJECT" - ] - - -def cryptography_has_x509_v_flag_trusted_first(): - return [ - "X509_V_FLAG_TRUSTED_FIRST", - ] - - -def cryptography_has_x509_v_flag_partial_chain(): - return [ - "X509_V_FLAG_PARTIAL_CHAIN", - ] + return ["X509_CHECK_FLAG_NEVER_CHECK_SUBJECT"] def cryptography_has_set_cert_cb(): @@ -150,11 +76,6 @@ def cryptography_has_tls_st(): def cryptography_has_locking_callbacks(): return [ - "CRYPTO_LOCK", - "CRYPTO_UNLOCK", - "CRYPTO_READ", - "CRYPTO_LOCK_SSL", - "CRYPTO_lock", "Cryptography_setup_ssl_threads", ] @@ -165,18 +86,6 @@ def cryptography_has_scrypt(): ] -def cryptography_has_generic_dtls_method(): - return [ - "DTLS_method", - "DTLS_server_method", - "DTLS_client_method", - "SSL_OP_NO_DTLSv1", - "SSL_OP_NO_DTLSv1_2", - "DTLS_set_link_mtu", - "DTLS_get_link_min_mtu", - ] - - def cryptography_has_evp_pkey_dhx(): return [ "EVP_PKEY_DHX", @@ -245,6 +154,13 @@ def cryptography_has_ed25519(): ] +def cryptography_has_poly1305(): + return [ + "NID_poly1305", + "EVP_PKEY_POLY1305", + ] + + def cryptography_has_oneshot_evp_digest_sign_verify(): return [ "EVP_DigestSign", @@ -267,7 +183,7 @@ def cryptography_has_evp_pkey_get_set_tls_encodedpoint(): def cryptography_has_fips(): return [ - "FIPS_set_mode", + "FIPS_mode_set", "FIPS_mode", ] @@ -326,6 +242,13 @@ def cryptography_has_tlsv13(): ] +def cryptography_has_keylog(): + return [ + "SSL_CTX_set_keylog_callback", + "SSL_CTX_get_keylog_callback", + ] + + def cryptography_has_raw_key(): return [ "EVP_PKEY_new_raw_private_key", @@ -335,9 +258,36 @@ def cryptography_has_raw_key(): ] -def cryptography_has_evp_r_memory_limit_exceeded(): +def cryptography_has_engine(): + return [ + "ENGINE_by_id", + "ENGINE_init", + "ENGINE_finish", + "ENGINE_get_default_RAND", + "ENGINE_set_default_RAND", + "ENGINE_unregister_RAND", + "ENGINE_ctrl_cmd", + "ENGINE_free", + "ENGINE_get_name", + "Cryptography_add_osrandom_engine", + "ENGINE_ctrl_cmd_string", + "ENGINE_load_builtin_engines", + "ENGINE_load_private_key", + "ENGINE_load_public_key", + ] + + +def cryptography_has_verified_chain(): + return [ + "SSL_get0_verified_chain", + ] + + +def cryptography_has_srtp(): return [ - "EVP_R_MEMORY_LIMIT_EXCEEDED", + "SSL_CTX_set_tlsext_use_srtp", + "SSL_set_tlsext_use_srtp", + "SSL_get_selected_srtp_profile", ] @@ -348,40 +298,18 @@ def cryptography_has_evp_r_memory_limit_exceeded(): # lists so we can use coverage to measure which are used. CONDITIONAL_NAMES = { "Cryptography_HAS_EC2M": cryptography_has_ec2m, - "Cryptography_HAS_EC_1_0_2": cryptography_has_ec_1_0_2, - "Cryptography_HAS_SET_ECDH_AUTO": cryptography_has_set_ecdh_auto, - "Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR": ( - cryptography_has_rsa_r_pkcs_decoding_error - ), "Cryptography_HAS_RSA_OAEP_MD": cryptography_has_rsa_oaep_md, "Cryptography_HAS_RSA_OAEP_LABEL": cryptography_has_rsa_oaep_label, "Cryptography_HAS_SSL3_METHOD": cryptography_has_ssl3_method, - "Cryptography_HAS_ALPN": cryptography_has_alpn, - "Cryptography_HAS_COMPRESSION": cryptography_has_compression, - "Cryptography_HAS_GET_SERVER_TMP_KEY": cryptography_has_get_server_tmp_key, - "Cryptography_HAS_102_VERIFICATION_ERROR_CODES": ( - cryptography_has_102_verification_error_codes - ), - "Cryptography_HAS_102_VERIFICATION_PARAMS": ( - cryptography_has_102_verification_params - ), + "Cryptography_HAS_102_VERIFICATION": cryptography_has_102_verification, "Cryptography_HAS_110_VERIFICATION_PARAMS": ( cryptography_has_110_verification_params ), - "Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST": ( - cryptography_has_x509_v_flag_trusted_first - ), - "Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN": ( - cryptography_has_x509_v_flag_partial_chain - ), "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_LOCKING_CALLBACKS": cryptography_has_locking_callbacks, "Cryptography_HAS_SCRYPT": cryptography_has_scrypt, - "Cryptography_HAS_GENERIC_DTLS_METHOD": ( - cryptography_has_generic_dtls_method - ), "Cryptography_HAS_EVP_PKEY_DHX": cryptography_has_evp_pkey_dhx, "Cryptography_HAS_MEM_FUNCTIONS": cryptography_has_mem_functions, "Cryptography_HAS_SCT": cryptography_has_sct, @@ -392,6 +320,7 @@ def cryptography_has_evp_r_memory_limit_exceeded(): "Cryptography_HAS_X448": cryptography_has_x448, "Cryptography_HAS_ED448": cryptography_has_ed448, "Cryptography_HAS_ED25519": cryptography_has_ed25519, + "Cryptography_HAS_POLY1305": cryptography_has_poly1305, "Cryptography_HAS_ONESHOT_EVP_DIGEST_SIGN_VERIFY": ( cryptography_has_oneshot_evp_digest_sign_verify ), @@ -405,11 +334,12 @@ def cryptography_has_evp_r_memory_limit_exceeded(): "Cryptography_HAS_OPENSSL_CLEANUP": cryptography_has_openssl_cleanup, "Cryptography_HAS_CIPHER_DETAILS": cryptography_has_cipher_details, "Cryptography_HAS_TLSv1_3": cryptography_has_tlsv13, + "Cryptography_HAS_KEYLOG": cryptography_has_keylog, "Cryptography_HAS_RAW_KEY": cryptography_has_raw_key, "Cryptography_HAS_EVP_DIGESTFINAL_XOF": ( cryptography_has_evp_digestfinal_xof ), - "Cryptography_HAS_EVP_R_MEMORY_LIMIT_EXCEEDED": ( - cryptography_has_evp_r_memory_limit_exceeded - ), + "Cryptography_HAS_ENGINE": cryptography_has_engine, + "Cryptography_HAS_VERIFIED_CHAIN": cryptography_has_verified_chain, + "Cryptography_HAS_SRTP": cryptography_has_srtp, } diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py index 0824ea88c994..f6bf93729118 100644 --- a/src/cryptography/hazmat/bindings/openssl/binding.py +++ b/src/cryptography/hazmat/bindings/openssl/binding.py @@ -5,10 +5,12 @@ from __future__ import absolute_import, division, print_function import collections +import os import threading import types import warnings +import cryptography from cryptography import utils from cryptography.exceptions import InternalError from cryptography.hazmat.bindings._openssl import ffi, lib @@ -51,20 +53,31 @@ def _consume_errors(lib): return errors -def _openssl_assert(lib, ok): - if not ok: - errors = _consume_errors(lib) - errors_with_text = [] - for err in errors: - buf = ffi.new("char[]", 256) - lib.ERR_error_string_n(err.code, buf, len(buf)) - err_text_reason = ffi.string(buf) - - errors_with_text.append( - _OpenSSLErrorWithText( - err.code, err.lib, err.func, err.reason, err_text_reason - ) +def _errors_with_text(errors): + errors_with_text = [] + for err in errors: + buf = ffi.new("char[]", 256) + lib.ERR_error_string_n(err.code, buf, len(buf)) + err_text_reason = ffi.string(buf) + + errors_with_text.append( + _OpenSSLErrorWithText( + err.code, err.lib, err.func, err.reason, err_text_reason ) + ) + + return errors_with_text + + +def _consume_errors_with_text(lib): + return _errors_with_text(_consume_errors(lib)) + + +def _openssl_assert(lib, ok, errors=None): + if not ok: + if errors is None: + errors = _consume_errors(lib) + errors_with_text = _errors_with_text(errors) raise InternalError( "Unknown OpenSSL error. This error is commonly encountered when " @@ -74,7 +87,7 @@ def _openssl_assert(lib, ok): "please file an issue at https://github.com/pyca/cryptography/" "issues with information on how to reproduce " "this. ({0!r})".format(errors_with_text), - errors_with_text + errors_with_text, ) @@ -97,6 +110,7 @@ class Binding(object): """ OpenSSL API wrapper. """ + lib = None ffi = ffi _lib_loaded = False @@ -114,10 +128,9 @@ def _register_osrandom_engine(cls): # reliably clear the error queue. Once we clear it here we will # error on any subsequent unexpected item in the stack. cls.lib.ERR_clear_error() - cls._osrandom_engine_id = cls.lib.Cryptography_osrandom_engine_id - cls._osrandom_engine_name = cls.lib.Cryptography_osrandom_engine_name - result = cls.lib.Cryptography_add_osrandom_engine() - _openssl_assert(cls.lib, result in (1, 2)) + if cls.lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: + result = cls.lib.Cryptography_add_osrandom_engine() + _openssl_assert(cls.lib, result in (1, 2)) @classmethod def _ensure_ffi_initialized(cls): @@ -141,8 +154,10 @@ def init_static_locks(cls): # the setup for this. __import__("_ssl") - if (not cls.lib.Cryptography_HAS_LOCKING_CALLBACKS or - cls.lib.CRYPTO_get_locking_callback() != cls.ffi.NULL): + if ( + not cls.lib.Cryptography_HAS_LOCKING_CALLBACKS + or cls.lib.CRYPTO_get_locking_callback() != cls.ffi.NULL + ): return # If nothing else has setup a locking callback already, we set up @@ -153,17 +168,50 @@ def init_static_locks(cls): def _verify_openssl_version(lib): if ( - lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and - not lib.CRYPTOGRAPHY_IS_LIBRESSL + lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 + and not lib.CRYPTOGRAPHY_IS_LIBRESSL ): - warnings.warn( - "OpenSSL version 1.0.1 is no longer supported by the OpenSSL " - "project, please upgrade. A future version of cryptography will " - "drop support for it.", - utils.CryptographyDeprecationWarning + if os.environ.get("CRYPTOGRAPHY_ALLOW_OPENSSL_102"): + warnings.warn( + "OpenSSL version 1.0.2 is no longer supported by the OpenSSL " + "project, please upgrade. The next version of cryptography " + "will completely remove support for it.", + utils.CryptographyDeprecationWarning, + ) + else: + raise RuntimeError( + "You are linking against OpenSSL 1.0.2, which is no longer " + "supported by the OpenSSL project. To use this version of " + "cryptography you need to upgrade to a newer version of " + "OpenSSL. For this version only you can also set the " + "environment variable CRYPTOGRAPHY_ALLOW_OPENSSL_102 to " + "allow OpenSSL 1.0.2." + ) + + +def _verify_package_version(version): + # Occasionally we run into situations where the version of the Python + # package does not match the version of the shared object that is loaded. + # This may occur in environments where multiple versions of cryptography + # are installed and available in the python path. To avoid errors cropping + # up later this code checks that the currently imported package and the + # shared object that were loaded have the same version and raise an + # ImportError if they do not + so_package_version = ffi.string(lib.CRYPTOGRAPHY_PACKAGE_VERSION) + if version.encode("ascii") != so_package_version: + raise ImportError( + "The version of cryptography does not match the loaded " + "shared object. This can happen if you have multiple copies of " + "cryptography installed in your Python path. Please try creating " + "a new virtual environment to resolve this issue. " + "Loaded python version: {}, shared object version: {}".format( + version, so_package_version + ) ) +_verify_package_version(cryptography.__version__) + # OpenSSL is not thread safe until the locks are initialized. We call this # method in module scope so that it executes with the import lock. On # Pythons < 3.4 this import lock is a global lock, which can prevent a race diff --git a/src/cryptography/hazmat/primitives/asymmetric/dh.py b/src/cryptography/hazmat/primitives/asymmetric/dh.py index 4fc995245d95..cd9fbfab4600 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/dh.py +++ b/src/cryptography/hazmat/primitives/asymmetric/dh.py @@ -9,9 +9,11 @@ import six from cryptography import utils +from cryptography.hazmat.backends import _get_backend -def generate_parameters(generator, key_size, backend): +def generate_parameters(generator, key_size, backend=None): + backend = _get_backend(backend) return backend.generate_dh_parameters(generator, key_size) @@ -21,8 +23,9 @@ def __init__(self, x, public_numbers): raise TypeError("x must be an integer.") if not isinstance(public_numbers, DHPublicNumbers): - raise TypeError("public_numbers must be an instance of " - "DHPublicNumbers.") + raise TypeError( + "public_numbers must be an instance of " "DHPublicNumbers." + ) self._x = x self._public_numbers = public_numbers @@ -32,14 +35,15 @@ def __eq__(self, other): return NotImplemented return ( - self._x == other._x and - self._public_numbers == other._public_numbers + self._x == other._x + and self._public_numbers == other._public_numbers ) def __ne__(self, other): return not self == other - def private_key(self, backend): + def private_key(self, backend=None): + backend = _get_backend(backend) return backend.load_dh_private_numbers(self) public_numbers = utils.read_only_property("_public_numbers") @@ -53,7 +57,8 @@ def __init__(self, y, parameter_numbers): if not isinstance(parameter_numbers, DHParameterNumbers): raise TypeError( - "parameters must be an instance of DHParameterNumbers.") + "parameters must be an instance of DHParameterNumbers." + ) self._y = y self._parameter_numbers = parameter_numbers @@ -63,14 +68,15 @@ def __eq__(self, other): return NotImplemented return ( - self._y == other._y and - self._parameter_numbers == other._parameter_numbers + self._y == other._y + and self._parameter_numbers == other._parameter_numbers ) def __ne__(self, other): return not self == other - def public_key(self, backend): + def public_key(self, backend=None): + backend = _get_backend(backend) return backend.load_dh_public_numbers(self) y = utils.read_only_property("_y") @@ -79,9 +85,8 @@ def public_key(self, backend): class DHParameterNumbers(object): def __init__(self, p, g, q=None): - if ( - not isinstance(p, six.integer_types) or - not isinstance(g, six.integer_types) + if not isinstance(p, six.integer_types) or not isinstance( + g, six.integer_types ): raise TypeError("p and g must be integers") if q is not None and not isinstance(q, six.integer_types): @@ -99,15 +104,14 @@ def __eq__(self, other): return NotImplemented return ( - self._p == other._p and - self._g == other._g and - self._q == other._q + self._p == other._p and self._g == other._g and self._q == other._q ) def __ne__(self, other): return not self == other - def parameters(self, backend): + def parameters(self, backend=None): + backend = _get_backend(backend) return backend.load_dh_parameter_numbers(self) p = utils.read_only_property("_p") diff --git a/src/cryptography/hazmat/primitives/asymmetric/dsa.py b/src/cryptography/hazmat/primitives/asymmetric/dsa.py index e380a441f1ff..8ccc66665f36 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/dsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -9,6 +9,7 @@ import six from cryptography import utils +from cryptography.hazmat.backends import _get_backend @six.add_metaclass(abc.ABCMeta) @@ -119,17 +120,21 @@ def verify(self, signature, data, algorithm): DSAPublicKeyWithSerialization = DSAPublicKey -def generate_parameters(key_size, backend): +def generate_parameters(key_size, backend=None): + backend = _get_backend(backend) return backend.generate_dsa_parameters(key_size) -def generate_private_key(key_size, backend): +def generate_private_key(key_size, backend=None): + backend = _get_backend(backend) return backend.generate_dsa_private_key_and_parameters(key_size) def _check_dsa_parameters(parameters): - if parameters.p.bit_length() not in [1024, 2048, 3072]: - raise ValueError("p must be exactly 1024, 2048, or 3072 bits long") + if parameters.p.bit_length() not in [1024, 2048, 3072, 4096]: + raise ValueError( + "p must be exactly 1024, 2048, 3072, or 4096 bits long" + ) if parameters.q.bit_length() not in [160, 224, 256]: raise ValueError("q must be exactly 160, 224, or 256 bits long") @@ -150,9 +155,9 @@ def _check_dsa_private_numbers(numbers): class DSAParameterNumbers(object): def __init__(self, p, q, g): if ( - not isinstance(p, six.integer_types) or - not isinstance(q, six.integer_types) or - not isinstance(g, six.integer_types) + not isinstance(p, six.integer_types) + or not isinstance(q, six.integer_types) + or not isinstance(g, six.integer_types) ): raise TypeError( "DSAParameterNumbers p, q, and g arguments must be integers." @@ -166,7 +171,8 @@ def __init__(self, p, q, g): q = utils.read_only_property("_q") g = utils.read_only_property("_g") - def parameters(self, backend): + def parameters(self, backend=None): + backend = _get_backend(backend) return backend.load_dsa_parameter_numbers(self) def __eq__(self, other): @@ -180,9 +186,8 @@ def __ne__(self, other): def __repr__(self): return ( - "".format( - self=self - ) + "".format(self=self) ) @@ -202,7 +207,8 @@ def __init__(self, y, parameter_numbers): y = utils.read_only_property("_y") parameter_numbers = utils.read_only_property("_parameter_numbers") - def public_key(self, backend): + def public_key(self, backend=None): + backend = _get_backend(backend) return backend.load_dsa_public_numbers(self) def __eq__(self, other): @@ -210,8 +216,8 @@ def __eq__(self, other): return NotImplemented return ( - self.y == other.y and - self.parameter_numbers == other.parameter_numbers + self.y == other.y + and self.parameter_numbers == other.parameter_numbers ) def __ne__(self, other): @@ -239,7 +245,8 @@ def __init__(self, x, public_numbers): x = utils.read_only_property("_x") public_numbers = utils.read_only_property("_public_numbers") - def private_key(self, backend): + def private_key(self, backend=None): + backend = _get_backend(backend) return backend.load_dsa_private_numbers(self) def __eq__(self, other): diff --git a/src/cryptography/hazmat/primitives/asymmetric/ec.py b/src/cryptography/hazmat/primitives/asymmetric/ec.py index 1de0976a60b5..c7e694fc5615 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ec.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ec.py @@ -11,6 +11,7 @@ from cryptography import utils from cryptography.hazmat._oid import ObjectIdentifier +from cryptography.hazmat.backends import _get_backend class EllipticCurveOID(object): @@ -166,6 +167,7 @@ def from_encoded_point(cls, curve, data): raise ValueError("Unsupported elliptic curve point type") from cryptography.hazmat.backends.openssl.backend import backend + return backend.load_elliptic_curve_public_bytes(curve, data) @@ -289,26 +291,22 @@ class BrainpoolP512R1(object): _CURVE_TYPES = { "prime192v1": SECP192R1, "prime256v1": SECP256R1, - "secp192r1": SECP192R1, "secp224r1": SECP224R1, "secp256r1": SECP256R1, "secp384r1": SECP384R1, "secp521r1": SECP521R1, "secp256k1": SECP256K1, - "sect163k1": SECT163K1, "sect233k1": SECT233K1, "sect283k1": SECT283K1, "sect409k1": SECT409K1, "sect571k1": SECT571K1, - "sect163r2": SECT163R2, "sect233r1": SECT233R1, "sect283r1": SECT283R1, "sect409r1": SECT409R1, "sect571r1": SECT571R1, - "brainpoolP256r1": BrainpoolP256R1, "brainpoolP384r1": BrainpoolP384R1, "brainpoolP512r1": BrainpoolP512R1, @@ -323,11 +321,13 @@ def __init__(self, algorithm): algorithm = utils.read_only_property("_algorithm") -def generate_private_key(curve, backend): +def generate_private_key(curve, backend=None): + backend = _get_backend(backend) return backend.generate_elliptic_curve_private_key(curve) -def derive_private_key(private_value, curve, backend): +def derive_private_key(private_value, curve, backend=None): + backend = _get_backend(backend) if not isinstance(private_value, six.integer_types): raise TypeError("private_value must be an integer type.") @@ -342,9 +342,8 @@ def derive_private_key(private_value, curve, backend): class EllipticCurvePublicNumbers(object): def __init__(self, x, y, curve): - if ( - not isinstance(x, six.integer_types) or - not isinstance(y, six.integer_types) + if not isinstance(x, six.integer_types) or not isinstance( + y, six.integer_types ): raise TypeError("x and y must be integers.") @@ -355,7 +354,8 @@ def __init__(self, x, y, curve): self._x = x self._curve = curve - def public_key(self, backend): + def public_key(self, backend=None): + backend = _get_backend(backend) return backend.load_elliptic_curve_public_numbers(self) def encode_point(self): @@ -364,14 +364,15 @@ def encode_point(self): " and will be removed in a future version. Please use " "EllipticCurvePublicKey.public_bytes to obtain both " "compressed and uncompressed point encoding.", - utils.DeprecatedIn25, + utils.PersistentlyDeprecated2019, stacklevel=2, ) # key_size is in bits. Convert to bytes and round up byte_length = (self.curve.key_size + 7) // 8 return ( - b'\x04' + utils.int_to_bytes(self.x, byte_length) + - utils.int_to_bytes(self.y, byte_length) + b"\x04" + + utils.int_to_bytes(self.x, byte_length) + + utils.int_to_bytes(self.y, byte_length) ) @classmethod @@ -383,21 +384,21 @@ def from_encoded_point(cls, curve, data): "Support for unsafe construction of public numbers from " "encoded data will be removed in a future version. " "Please use EllipticCurvePublicKey.from_encoded_point", - utils.DeprecatedIn25, + utils.PersistentlyDeprecated2019, stacklevel=2, ) - if data.startswith(b'\x04'): + if data.startswith(b"\x04"): # key_size is in bits. Convert to bytes and round up byte_length = (curve.key_size + 7) // 8 if len(data) == 2 * byte_length + 1: - x = utils.int_from_bytes(data[1:byte_length + 1], 'big') - y = utils.int_from_bytes(data[byte_length + 1:], 'big') + x = utils.int_from_bytes(data[1 : byte_length + 1], "big") + y = utils.int_from_bytes(data[byte_length + 1 :], "big") return cls(x, y, curve) else: - raise ValueError('Invalid elliptic curve point data length') + raise ValueError("Invalid elliptic curve point data length") else: - raise ValueError('Unsupported elliptic curve point type') + raise ValueError("Unsupported elliptic curve point type") curve = utils.read_only_property("_curve") x = utils.read_only_property("_x") @@ -408,10 +409,10 @@ def __eq__(self, other): return NotImplemented return ( - self.x == other.x and - self.y == other.y and - self.curve.name == other.curve.name and - self.curve.key_size == other.curve.key_size + self.x == other.x + and self.y == other.y + and self.curve.name == other.curve.name + and self.curve.key_size == other.curve.key_size ) def __ne__(self, other): @@ -441,7 +442,8 @@ def __init__(self, private_value, public_numbers): self._private_value = private_value self._public_numbers = public_numbers - def private_key(self, backend): + def private_key(self, backend=None): + backend = _get_backend(backend) return backend.load_elliptic_curve_private_numbers(self) private_value = utils.read_only_property("_private_value") @@ -452,8 +454,8 @@ def __eq__(self, other): return NotImplemented return ( - self.private_value == other.private_value and - self.public_numbers == other.public_numbers + self.private_value == other.private_value + and self.public_numbers == other.public_numbers ) def __ne__(self, other): @@ -465,3 +467,36 @@ def __hash__(self): class ECDH(object): pass + + +_OID_TO_CURVE = { + EllipticCurveOID.SECP192R1: SECP192R1, + EllipticCurveOID.SECP224R1: SECP224R1, + EllipticCurveOID.SECP256K1: SECP256K1, + EllipticCurveOID.SECP256R1: SECP256R1, + EllipticCurveOID.SECP384R1: SECP384R1, + EllipticCurveOID.SECP521R1: SECP521R1, + EllipticCurveOID.BRAINPOOLP256R1: BrainpoolP256R1, + EllipticCurveOID.BRAINPOOLP384R1: BrainpoolP384R1, + EllipticCurveOID.BRAINPOOLP512R1: BrainpoolP512R1, + EllipticCurveOID.SECT163K1: SECT163K1, + EllipticCurveOID.SECT163R2: SECT163R2, + EllipticCurveOID.SECT233K1: SECT233K1, + EllipticCurveOID.SECT233R1: SECT233R1, + EllipticCurveOID.SECT283K1: SECT283K1, + EllipticCurveOID.SECT283R1: SECT283R1, + EllipticCurveOID.SECT409K1: SECT409K1, + EllipticCurveOID.SECT409R1: SECT409R1, + EllipticCurveOID.SECT571K1: SECT571K1, + EllipticCurveOID.SECT571R1: SECT571R1, +} + + +def get_curve_for_oid(oid): + try: + return _OID_TO_CURVE[oid] + except KeyError: + raise LookupError( + "The provided object identifier has no matching elliptic " + "curve class" + ) diff --git a/src/cryptography/hazmat/primitives/asymmetric/ed25519.py b/src/cryptography/hazmat/primitives/asymmetric/ed25519.py new file mode 100644 index 000000000000..2d07a029bc73 --- /dev/null +++ b/src/cryptography/hazmat/primitives/asymmetric/ed25519.py @@ -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. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons + + +_ED25519_KEY_SIZE = 32 +_ED25519_SIG_SIZE = 64 + + +@six.add_metaclass(abc.ABCMeta) +class Ed25519PublicKey(object): + @classmethod + def from_public_bytes(cls, data): + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.ed25519_supported(): + raise UnsupportedAlgorithm( + "ed25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return backend.ed25519_load_public_bytes(data) + + @abc.abstractmethod + def public_bytes(self, encoding, format): + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def verify(self, signature, data): + """ + Verify the signature. + """ + + +@six.add_metaclass(abc.ABCMeta) +class Ed25519PrivateKey(object): + @classmethod + def generate(cls): + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.ed25519_supported(): + raise UnsupportedAlgorithm( + "ed25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return backend.ed25519_generate_key() + + @classmethod + def from_private_bytes(cls, data): + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.ed25519_supported(): + raise UnsupportedAlgorithm( + "ed25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return backend.ed25519_load_private_bytes(data) + + @abc.abstractmethod + def public_key(self): + """ + The Ed25519PublicKey derived from the private key. + """ + + @abc.abstractmethod + def private_bytes(self, encoding, format, encryption_algorithm): + """ + The serialized bytes of the private key. + """ + + @abc.abstractmethod + def sign(self, data): + """ + Signs the data. + """ diff --git a/src/cryptography/hazmat/primitives/asymmetric/ed448.py b/src/cryptography/hazmat/primitives/asymmetric/ed448.py new file mode 100644 index 000000000000..520ffcbcbcb6 --- /dev/null +++ b/src/cryptography/hazmat/primitives/asymmetric/ed448.py @@ -0,0 +1,82 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons + + +@six.add_metaclass(abc.ABCMeta) +class Ed448PublicKey(object): + @classmethod + def from_public_bytes(cls, data): + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.ed448_supported(): + raise UnsupportedAlgorithm( + "ed448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return backend.ed448_load_public_bytes(data) + + @abc.abstractmethod + def public_bytes(self, encoding, format): + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def verify(self, signature, data): + """ + Verify the signature. + """ + + +@six.add_metaclass(abc.ABCMeta) +class Ed448PrivateKey(object): + @classmethod + def generate(cls): + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.ed448_supported(): + raise UnsupportedAlgorithm( + "ed448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + return backend.ed448_generate_key() + + @classmethod + def from_private_bytes(cls, data): + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.ed448_supported(): + raise UnsupportedAlgorithm( + "ed448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return backend.ed448_load_private_bytes(data) + + @abc.abstractmethod + def public_key(self): + """ + The Ed448PublicKey derived from the private key. + """ + + @abc.abstractmethod + def sign(self, data): + """ + Signs the data. + """ + + @abc.abstractmethod + def private_bytes(self, encoding, format, encryption_algorithm): + """ + The serialized bytes of the private key. + """ diff --git a/src/cryptography/hazmat/primitives/asymmetric/padding.py b/src/cryptography/hazmat/primitives/asymmetric/padding.py index a37c3f90ca72..fc8f6e26a917 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/padding.py +++ b/src/cryptography/hazmat/primitives/asymmetric/padding.py @@ -5,7 +5,6 @@ from __future__ import absolute_import, division, print_function import abc -import math import six @@ -36,8 +35,10 @@ class PSS(object): def __init__(self, mgf, salt_length): self._mgf = mgf - if (not isinstance(salt_length, six.integer_types) and - salt_length is not self.MAX_LENGTH): + if ( + not isinstance(salt_length, six.integer_types) + and salt_length is not self.MAX_LENGTH + ): raise TypeError("salt_length must be an integer.") if salt_length is not self.MAX_LENGTH and salt_length < 0: @@ -73,7 +74,7 @@ def calculate_max_pss_salt_length(key, hash_algorithm): if not isinstance(key, (rsa.RSAPrivateKey, rsa.RSAPublicKey)): raise TypeError("key must be an RSA public or private key") # bit length - 1 per RFC 3447 - emlen = int(math.ceil((key.key_size - 1) / 8.0)) + emlen = (key.key_size + 6) // 8 salt_length = emlen - hash_algorithm.digest_size - 2 assert salt_length >= 0 return salt_length diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py index 27db671af8cb..d8b8ddd914cc 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function import abc + try: # Only available in math in 3.5+ from math import gcd @@ -15,6 +16,7 @@ from cryptography import utils from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import RSABackend @@ -108,11 +110,12 @@ def verify(self, signature, data, padding, algorithm): RSAPublicKeyWithSerialization = RSAPublicKey -def generate_private_key(public_exponent, key_size, backend): +def generate_private_key(public_exponent, key_size, backend=None): + backend = _get_backend(backend) if not isinstance(backend, RSABackend): raise UnsupportedAlgorithm( "Backend object does not implement RSABackend.", - _Reasons.BACKEND_MISSING_INTERFACE + _Reasons.BACKEND_MISSING_INTERFACE, ) _verify_rsa_parameters(public_exponent, key_size) @@ -120,18 +123,19 @@ def generate_private_key(public_exponent, key_size, backend): def _verify_rsa_parameters(public_exponent, key_size): - if public_exponent < 3: - raise ValueError("public_exponent must be >= 3.") - - if public_exponent & 1 == 0: - raise ValueError("public_exponent must be odd.") + if public_exponent not in (3, 65537): + raise ValueError( + "public_exponent must be either 3 (for legacy compatibility) or " + "65537. Almost everyone should choose 65537 here!" + ) if key_size < 512: raise ValueError("key_size must be at least 512-bits.") -def _check_private_key_components(p, q, private_exponent, dmp1, dmq1, iqmp, - public_exponent, modulus): +def _check_private_key_components( + p, q, private_exponent, dmp1, dmq1, iqmp, public_exponent, modulus +): if modulus < 3: raise ValueError("modulus must be >= 3.") @@ -184,12 +188,12 @@ def _modinv(e, m): """ Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1 """ - x1, y1, x2, y2 = 1, 0, 0, 1 + x1, x2 = 1, 0 a, b = e, m while b > 0: q, r = divmod(a, b) - xn, yn = x1 - q * x2, y1 - q * y2 - a, b, x1, y1, x2, y2 = b, r, x2, y2, xn, yn + xn = x1 - q * x2 + a, b, x1, x2 = b, r, x2, xn return x1 % m @@ -266,15 +270,14 @@ def rsa_recover_prime_factors(n, e, d): class RSAPrivateNumbers(object): - def __init__(self, p, q, d, dmp1, dmq1, iqmp, - public_numbers): + def __init__(self, p, q, d, dmp1, dmq1, iqmp, public_numbers): if ( - not isinstance(p, six.integer_types) or - not isinstance(q, six.integer_types) or - not isinstance(d, six.integer_types) or - not isinstance(dmp1, six.integer_types) or - not isinstance(dmq1, six.integer_types) or - not isinstance(iqmp, six.integer_types) + not isinstance(p, six.integer_types) + or not isinstance(q, six.integer_types) + or not isinstance(d, six.integer_types) + or not isinstance(dmp1, six.integer_types) + or not isinstance(dmq1, six.integer_types) + or not isinstance(iqmp, six.integer_types) ): raise TypeError( "RSAPrivateNumbers p, q, d, dmp1, dmq1, iqmp arguments must" @@ -303,7 +306,8 @@ def __init__(self, p, q, d, dmp1, dmq1, iqmp, iqmp = utils.read_only_property("_iqmp") public_numbers = utils.read_only_property("_public_numbers") - def private_key(self, backend): + def private_key(self, backend=None): + backend = _get_backend(backend) return backend.load_rsa_private_numbers(self) def __eq__(self, other): @@ -311,35 +315,36 @@ def __eq__(self, other): return NotImplemented return ( - self.p == other.p and - self.q == other.q and - self.d == other.d and - self.dmp1 == other.dmp1 and - self.dmq1 == other.dmq1 and - self.iqmp == other.iqmp and - self.public_numbers == other.public_numbers + self.p == other.p + and self.q == other.q + and self.d == other.d + and self.dmp1 == other.dmp1 + and self.dmq1 == other.dmq1 + and self.iqmp == other.iqmp + and self.public_numbers == other.public_numbers ) def __ne__(self, other): return not self == other def __hash__(self): - return hash(( - self.p, - self.q, - self.d, - self.dmp1, - self.dmq1, - self.iqmp, - self.public_numbers, - )) + return hash( + ( + self.p, + self.q, + self.d, + self.dmp1, + self.dmq1, + self.iqmp, + self.public_numbers, + ) + ) class RSAPublicNumbers(object): def __init__(self, e, n): - if ( - not isinstance(e, six.integer_types) or - not isinstance(n, six.integer_types) + if not isinstance(e, six.integer_types) or not isinstance( + n, six.integer_types ): raise TypeError("RSAPublicNumbers arguments must be integers.") @@ -349,7 +354,8 @@ def __init__(self, e, n): e = utils.read_only_property("_e") n = utils.read_only_property("_n") - def public_key(self, backend): + def public_key(self, backend=None): + backend = _get_backend(backend) return backend.load_rsa_public_numbers(self) def __repr__(self): diff --git a/src/cryptography/hazmat/primitives/asymmetric/utils.py b/src/cryptography/hazmat/primitives/asymmetric/utils.py index ef1e7eb928d9..5f9b677868db 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/utils.py +++ b/src/cryptography/hazmat/primitives/asymmetric/utils.py @@ -4,49 +4,30 @@ from __future__ import absolute_import, division, print_function -import warnings - -from asn1crypto.algos import DSASignature - -import six - from cryptography import utils +from cryptography.hazmat._der import ( + DERReader, + INTEGER, + SEQUENCE, + encode_der, + encode_der_integer, +) from cryptography.hazmat.primitives import hashes -def decode_rfc6979_signature(signature): - warnings.warn( - "decode_rfc6979_signature is deprecated and will " - "be removed in a future version, use decode_dss_signature instead.", - utils.PersistentlyDeprecated, - stacklevel=2 - ) - return decode_dss_signature(signature) - - def decode_dss_signature(signature): - data = DSASignature.load(signature, strict=True).native - return data['r'], data['s'] - - -def encode_rfc6979_signature(r, s): - warnings.warn( - "encode_rfc6979_signature is deprecated and will " - "be removed in a future version, use encode_dss_signature instead.", - utils.PersistentlyDeprecated, - stacklevel=2 - ) - return encode_dss_signature(r, s) + with DERReader(signature).read_single_element(SEQUENCE) as seq: + r = seq.read_element(INTEGER).as_integer() + s = seq.read_element(INTEGER).as_integer() + return r, s def encode_dss_signature(r, s): - if ( - not isinstance(r, six.integer_types) or - not isinstance(s, six.integer_types) - ): - raise ValueError("Both r and s must be integers") - - return DSASignature({'r': r, 's': s}).dump() + return encode_der( + SEQUENCE, + encode_der(INTEGER, encode_der_integer(r)), + encode_der(INTEGER, encode_der_integer(s)), + ) class Prehashed(object): diff --git a/src/cryptography/hazmat/primitives/asymmetric/x25519.py b/src/cryptography/hazmat/primitives/asymmetric/x25519.py index 4e8badf43344..fc63691536e9 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/x25519.py +++ b/src/cryptography/hazmat/primitives/asymmetric/x25519.py @@ -16,16 +16,17 @@ class X25519PublicKey(object): @classmethod def from_public_bytes(cls, data): from cryptography.hazmat.backends.openssl.backend import backend + if not backend.x25519_supported(): raise UnsupportedAlgorithm( "X25519 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, ) return backend.x25519_load_public_bytes(data) @abc.abstractmethod - def public_bytes(self, encoding=None, format=None): + def public_bytes(self, encoding, format): """ The serialized bytes of the public key. """ @@ -36,20 +37,22 @@ class X25519PrivateKey(object): @classmethod def generate(cls): from cryptography.hazmat.backends.openssl.backend import backend + if not backend.x25519_supported(): raise UnsupportedAlgorithm( "X25519 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, ) return backend.x25519_generate_key() @classmethod def from_private_bytes(cls, data): from cryptography.hazmat.backends.openssl.backend import backend + if not backend.x25519_supported(): raise UnsupportedAlgorithm( "X25519 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, ) return backend.x25519_load_private_bytes(data) diff --git a/src/cryptography/hazmat/primitives/asymmetric/x448.py b/src/cryptography/hazmat/primitives/asymmetric/x448.py index 475e678ff98c..3ac067bfd5e0 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/x448.py +++ b/src/cryptography/hazmat/primitives/asymmetric/x448.py @@ -16,10 +16,11 @@ class X448PublicKey(object): @classmethod def from_public_bytes(cls, data): from cryptography.hazmat.backends.openssl.backend import backend + if not backend.x448_supported(): raise UnsupportedAlgorithm( "X448 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, ) return backend.x448_load_public_bytes(data) @@ -36,20 +37,22 @@ class X448PrivateKey(object): @classmethod def generate(cls): from cryptography.hazmat.backends.openssl.backend import backend + if not backend.x448_supported(): raise UnsupportedAlgorithm( "X448 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, ) return backend.x448_generate_key() @classmethod def from_private_bytes(cls, data): from cryptography.hazmat.backends.openssl.backend import backend + if not backend.x448_supported(): raise UnsupportedAlgorithm( "X448 is not supported by this version of OpenSSL.", - _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, ) return backend.x448_load_private_bytes(data) diff --git a/src/cryptography/hazmat/primitives/ciphers/__init__.py b/src/cryptography/hazmat/primitives/ciphers/__init__.py index 171b1c693b31..4380f72b2e2e 100644 --- a/src/cryptography/hazmat/primitives/ciphers/__init__.py +++ b/src/cryptography/hazmat/primitives/ciphers/__init__.py @@ -5,8 +5,13 @@ from __future__ import absolute_import, division, print_function from cryptography.hazmat.primitives.ciphers.base import ( - AEADCipherContext, AEADDecryptionContext, AEADEncryptionContext, - BlockCipherAlgorithm, Cipher, CipherAlgorithm, CipherContext + AEADCipherContext, + AEADDecryptionContext, + AEADEncryptionContext, + BlockCipherAlgorithm, + Cipher, + CipherAlgorithm, + CipherContext, ) diff --git a/src/cryptography/hazmat/primitives/ciphers/aead.py b/src/cryptography/hazmat/primitives/ciphers/aead.py index 42e19adb11d2..4eddc1ee6e37 100644 --- a/src/cryptography/hazmat/primitives/ciphers/aead.py +++ b/src/cryptography/hazmat/primitives/ciphers/aead.py @@ -18,7 +18,7 @@ def __init__(self, key): if not backend.aead_cipher_supported(self): raise exceptions.UnsupportedAlgorithm( "ChaCha20Poly1305 is not supported by this version of OpenSSL", - exceptions._Reasons.UNSUPPORTED_CIPHER + exceptions._Reasons.UNSUPPORTED_CIPHER, ) utils._check_byteslike("key", key) @@ -42,18 +42,14 @@ def encrypt(self, nonce, data, associated_data): ) self._check_params(nonce, data, associated_data) - return aead._encrypt( - backend, self, nonce, data, associated_data, 16 - ) + return aead._encrypt(backend, self, nonce, data, associated_data, 16) def decrypt(self, nonce, data, associated_data): if associated_data is None: associated_data = b"" self._check_params(nonce, data, associated_data) - return aead._decrypt( - backend, self, nonce, data, associated_data, 16 - ) + return aead._decrypt(backend, self, nonce, data, associated_data, 16) def _check_params(self, nonce, data, associated_data): utils._check_byteslike("nonce", nonce) @@ -80,12 +76,6 @@ def __init__(self, key, tag_length=16): self._tag_length = tag_length - if not backend.aead_cipher_supported(self): - raise exceptions.UnsupportedAlgorithm( - "AESCCM is not supported by this version of OpenSSL", - exceptions._Reasons.UNSUPPORTED_CIPHER - ) - @classmethod def generate_key(cls, bit_length): if not isinstance(bit_length, int): @@ -126,7 +116,7 @@ def _validate_lengths(self, nonce, data_len): # https://tools.ietf.org/html/rfc3610#section-2.1 l_val = 15 - len(nonce) if 2 ** (8 * l_val) < data_len: - raise ValueError("Nonce too long for data") + raise ValueError("Data too long for nonce") def _check_params(self, nonce, data, associated_data): utils._check_byteslike("nonce", nonce) @@ -167,18 +157,14 @@ def encrypt(self, nonce, data, associated_data): ) self._check_params(nonce, data, associated_data) - return aead._encrypt( - backend, self, nonce, data, associated_data, 16 - ) + return aead._encrypt(backend, self, nonce, data, associated_data, 16) def decrypt(self, nonce, data, associated_data): if associated_data is None: associated_data = b"" self._check_params(nonce, data, associated_data) - return aead._decrypt( - backend, self, nonce, data, associated_data, 16 - ) + return aead._decrypt(backend, self, nonce, data, associated_data, 16) def _check_params(self, nonce, data, associated_data): utils._check_byteslike("nonce", nonce) diff --git a/src/cryptography/hazmat/primitives/ciphers/algorithms.py b/src/cryptography/hazmat/primitives/ciphers/algorithms.py index 1f49fd9dedbd..8072cedd1714 100644 --- a/src/cryptography/hazmat/primitives/ciphers/algorithms.py +++ b/src/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -6,7 +6,8 @@ from cryptography import utils from cryptography.hazmat.primitives.ciphers import ( - BlockCipherAlgorithm, CipherAlgorithm + BlockCipherAlgorithm, + CipherAlgorithm, ) from cryptography.hazmat.primitives.ciphers.modes import ModeWithNonce @@ -17,9 +18,11 @@ def _verify_key_size(algorithm, key): # Verify that the key size matches the expected key size if len(key) * 8 not in algorithm.key_sizes: - raise ValueError("Invalid key size ({0}) for {1}.".format( - len(key) * 8, algorithm.name - )) + raise ValueError( + "Invalid key size ({}) for {}.".format( + len(key) * 8, algorithm.name + ) + ) return key diff --git a/src/cryptography/hazmat/primitives/ciphers/base.py b/src/cryptography/hazmat/primitives/ciphers/base.py index f85704142126..dae425a2993d 100644 --- a/src/cryptography/hazmat/primitives/ciphers/base.py +++ b/src/cryptography/hazmat/primitives/ciphers/base.py @@ -10,9 +10,13 @@ from cryptography import utils from cryptography.exceptions import ( - AlreadyFinalized, AlreadyUpdated, NotYetFinalized, UnsupportedAlgorithm, - _Reasons + AlreadyFinalized, + AlreadyUpdated, + NotYetFinalized, + UnsupportedAlgorithm, + _Reasons, ) +from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import modes @@ -94,11 +98,12 @@ def tag(self): class Cipher(object): - def __init__(self, algorithm, mode, backend): + def __init__(self, algorithm, mode, backend=None): + backend = _get_backend(backend) if not isinstance(backend, CipherBackend): raise UnsupportedAlgorithm( "Backend object does not implement CipherBackend.", - _Reasons.BACKEND_MISSING_INTERFACE + _Reasons.BACKEND_MISSING_INTERFACE, ) if not isinstance(algorithm, CipherAlgorithm): @@ -179,7 +184,7 @@ def _check_limit(self, data_size): self._bytes_processed += data_size if self._bytes_processed > self._ctx._mode._MAX_ENCRYPTED_BYTES: raise ValueError( - "{0} has a maximum encrypted byte limit of {1}".format( + "{} has a maximum encrypted byte limit of {}".format( self._ctx._mode.name, self._ctx._mode._MAX_ENCRYPTED_BYTES ) ) @@ -217,7 +222,7 @@ def authenticate_additional_data(self, data): self._aad_bytes_processed += len(data) if self._aad_bytes_processed > self._ctx._mode._MAX_AAD_BYTES: raise ValueError( - "{0} has a maximum AAD byte limit of {1}".format( + "{} has a maximum AAD byte limit of {}".format( self._ctx._mode.name, self._ctx._mode._MAX_AAD_BYTES ) ) @@ -230,6 +235,7 @@ class _AEADEncryptionContext(_AEADCipherContext): @property def tag(self): if self._ctx is not None: - raise NotYetFinalized("You must finalize encryption before " - "getting the tag.") + raise NotYetFinalized( + "You must finalize encryption before " "getting the tag." + ) return self._tag diff --git a/src/cryptography/hazmat/primitives/ciphers/modes.py b/src/cryptography/hazmat/primitives/ciphers/modes.py index ad91a6e142cb..dcb24444214f 100644 --- a/src/cryptography/hazmat/primitives/ciphers/modes.py +++ b/src/cryptography/hazmat/primitives/ciphers/modes.py @@ -72,9 +72,11 @@ def _check_aes_key_length(self, algorithm): def _check_iv_length(self, algorithm): if len(self.initialization_vector) * 8 != algorithm.block_size: - raise ValueError("Invalid IV size ({0}) for {1}.".format( - len(self.initialization_vector), self.name - )) + raise ValueError( + "Invalid IV size ({}) for {}.".format( + len(self.initialization_vector), self.name + ) + ) def _check_iv_and_key_length(self, algorithm): @@ -178,9 +180,11 @@ def __init__(self, nonce): def validate_for_algorithm(self, algorithm): _check_aes_key_length(self, algorithm) if len(self.nonce) * 8 != algorithm.block_size: - raise ValueError("Invalid nonce size ({0}) for {1}.".format( - len(self.nonce), self.name - )) + raise ValueError( + "Invalid nonce size ({}) for {}.".format( + len(self.nonce), self.name + ) + ) @utils.register_interface(Mode) @@ -205,8 +209,9 @@ def __init__(self, initialization_vector, tag=None, min_tag_length=16): raise ValueError("min_tag_length must be >= 4") if len(tag) < min_tag_length: raise ValueError( - "Authentication tag must be {0} bytes or longer.".format( - min_tag_length) + "Authentication tag must be {} bytes or longer.".format( + min_tag_length + ) ) self._tag = tag self._min_tag_length = min_tag_length diff --git a/src/cryptography/hazmat/primitives/cmac.py b/src/cryptography/hazmat/primitives/cmac.py index 1404eac3db35..bf962c906908 100644 --- a/src/cryptography/hazmat/primitives/cmac.py +++ b/src/cryptography/hazmat/primitives/cmac.py @@ -6,25 +6,26 @@ from cryptography import utils from cryptography.exceptions import ( - AlreadyFinalized, UnsupportedAlgorithm, _Reasons + AlreadyFinalized, + UnsupportedAlgorithm, + _Reasons, ) +from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import CMACBackend -from cryptography.hazmat.primitives import ciphers, mac +from cryptography.hazmat.primitives import ciphers -@utils.register_interface(mac.MACContext) class CMAC(object): - def __init__(self, algorithm, backend, ctx=None): + def __init__(self, algorithm, backend=None, ctx=None): + backend = _get_backend(backend) if not isinstance(backend, CMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement CMACBackend.", - _Reasons.BACKEND_MISSING_INTERFACE + _Reasons.BACKEND_MISSING_INTERFACE, ) if not isinstance(algorithm, ciphers.BlockCipherAlgorithm): - raise TypeError( - "Expected instance of BlockCipherAlgorithm." - ) + raise TypeError("Expected instance of BlockCipherAlgorithm.") self._algorithm = algorithm self._backend = backend @@ -59,7 +60,5 @@ def copy(self): if self._ctx is None: raise AlreadyFinalized("Context was already finalized.") return CMAC( - self._algorithm, - backend=self._backend, - ctx=self._ctx.copy() + self._algorithm, backend=self._backend, ctx=self._ctx.copy() ) diff --git a/src/cryptography/hazmat/primitives/constant_time.py b/src/cryptography/hazmat/primitives/constant_time.py index 0e987ea75864..7f41b9efa5f7 100644 --- a/src/cryptography/hazmat/primitives/constant_time.py +++ b/src/cryptography/hazmat/primitives/constant_time.py @@ -5,31 +5,10 @@ from __future__ import absolute_import, division, print_function import hmac -import warnings -from cryptography import utils -from cryptography.hazmat.bindings._constant_time import lib +def bytes_eq(a, b): + if not isinstance(a, bytes) or not isinstance(b, bytes): + raise TypeError("a and b must be bytes.") -if hasattr(hmac, "compare_digest"): - def bytes_eq(a, b): - if not isinstance(a, bytes) or not isinstance(b, bytes): - raise TypeError("a and b must be bytes.") - - return hmac.compare_digest(a, b) - -else: - warnings.warn( - "Support for your Python version is deprecated. The next version of " - "cryptography will remove support. Please upgrade to a 2.7.x " - "release that supports hmac.compare_digest as soon as possible.", - utils.DeprecatedIn23, - ) - - def bytes_eq(a, b): - if not isinstance(a, bytes) or not isinstance(b, bytes): - raise TypeError("a and b must be bytes.") - - return lib.Cryptography_constant_time_bytes_eq( - a, len(a), b, len(b) - ) == 1 + return hmac.compare_digest(a, b) diff --git a/src/cryptography/hazmat/primitives/hashes.py b/src/cryptography/hazmat/primitives/hashes.py index 9be2b60090a5..18e2bab36340 100644 --- a/src/cryptography/hazmat/primitives/hashes.py +++ b/src/cryptography/hazmat/primitives/hashes.py @@ -10,8 +10,11 @@ from cryptography import utils from cryptography.exceptions import ( - AlreadyFinalized, UnsupportedAlgorithm, _Reasons + AlreadyFinalized, + UnsupportedAlgorithm, + _Reasons, ) +from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import HashBackend @@ -66,11 +69,12 @@ class ExtendableOutputFunction(object): @utils.register_interface(HashContext) class Hash(object): - def __init__(self, algorithm, backend, ctx=None): + def __init__(self, algorithm, backend=None, ctx=None): + backend = _get_backend(backend) if not isinstance(backend, HashBackend): raise UnsupportedAlgorithm( "Backend object does not implement HashBackend.", - _Reasons.BACKEND_MISSING_INTERFACE + _Reasons.BACKEND_MISSING_INTERFACE, ) if not isinstance(algorithm, HashAlgorithm): diff --git a/src/cryptography/hazmat/primitives/hmac.py b/src/cryptography/hazmat/primitives/hmac.py index f7f401d2b6f6..8c421dc68df9 100644 --- a/src/cryptography/hazmat/primitives/hmac.py +++ b/src/cryptography/hazmat/primitives/hmac.py @@ -6,20 +6,23 @@ from cryptography import utils from cryptography.exceptions import ( - AlreadyFinalized, UnsupportedAlgorithm, _Reasons + AlreadyFinalized, + UnsupportedAlgorithm, + _Reasons, ) +from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import HMACBackend -from cryptography.hazmat.primitives import hashes, mac +from cryptography.hazmat.primitives import hashes -@utils.register_interface(mac.MACContext) @utils.register_interface(hashes.HashContext) class HMAC(object): - def __init__(self, key, algorithm, backend, ctx=None): + def __init__(self, key, algorithm, backend=None, ctx=None): + backend = _get_backend(backend) if not isinstance(backend, HMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement HMACBackend.", - _Reasons.BACKEND_MISSING_INTERFACE + _Reasons.BACKEND_MISSING_INTERFACE, ) if not isinstance(algorithm, hashes.HashAlgorithm): @@ -48,7 +51,7 @@ def copy(self): self._key, self.algorithm, backend=self._backend, - ctx=self._ctx.copy() + ctx=self._ctx.copy(), ) def finalize(self): diff --git a/src/cryptography/hazmat/primitives/kdf/concatkdf.py b/src/cryptography/hazmat/primitives/kdf/concatkdf.py index 65b25cdc2329..7cc0324fc4f5 100644 --- a/src/cryptography/hazmat/primitives/kdf/concatkdf.py +++ b/src/cryptography/hazmat/primitives/kdf/concatkdf.py @@ -8,8 +8,12 @@ from cryptography import utils from cryptography.exceptions import ( - AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons + AlreadyFinalized, + InvalidKey, + UnsupportedAlgorithm, + _Reasons, ) +from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.backends.interfaces import HashBackend from cryptography.hazmat.primitives import constant_time, hashes, hmac @@ -17,16 +21,15 @@ def _int_to_u32be(n): - return struct.pack('>I', n) + return struct.pack(">I", n) def _common_args_checks(algorithm, length, otherinfo): max_length = algorithm.digest_size * (2 ** 32 - 1) if length > max_length: raise ValueError( - "Can not derive keys larger than {0} bits.".format( - max_length - )) + "Can not derive keys larger than {} bits.".format(max_length) + ) if otherinfo is not None: utils._check_bytes("otherinfo", otherinfo) @@ -37,7 +40,7 @@ def _concatkdf_derive(key_material, length, auxfn, otherinfo): outlen = 0 counter = 1 - while (length > outlen): + while length > outlen: h = auxfn() h.update(_int_to_u32be(counter)) h.update(key_material) @@ -51,7 +54,8 @@ def _concatkdf_derive(key_material, length, auxfn, otherinfo): @utils.register_interface(KeyDerivationFunction) class ConcatKDFHash(object): - def __init__(self, algorithm, length, otherinfo, backend): + def __init__(self, algorithm, length, otherinfo, backend=None): + backend = _get_backend(backend) _common_args_checks(algorithm, length, otherinfo) self._algorithm = algorithm @@ -63,7 +67,7 @@ def __init__(self, algorithm, length, otherinfo, backend): if not isinstance(backend, HashBackend): raise UnsupportedAlgorithm( "Backend object does not implement HashBackend.", - _Reasons.BACKEND_MISSING_INTERFACE + _Reasons.BACKEND_MISSING_INTERFACE, ) self._backend = backend self._used = False @@ -75,8 +79,9 @@ def derive(self, key_material): if self._used: raise AlreadyFinalized self._used = True - return _concatkdf_derive(key_material, self._length, - self._hash, self._otherinfo) + return _concatkdf_derive( + key_material, self._length, self._hash, self._otherinfo + ) def verify(self, key_material, expected_key): if not constant_time.bytes_eq(self.derive(key_material), expected_key): @@ -85,7 +90,8 @@ def verify(self, key_material, expected_key): @utils.register_interface(KeyDerivationFunction) class ConcatKDFHMAC(object): - def __init__(self, algorithm, length, salt, otherinfo, backend): + def __init__(self, algorithm, length, salt, otherinfo, backend=None): + backend = _get_backend(backend) _common_args_checks(algorithm, length, otherinfo) self._algorithm = algorithm @@ -104,7 +110,7 @@ def __init__(self, algorithm, length, salt, otherinfo, backend): if not isinstance(backend, HMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement HMACBackend.", - _Reasons.BACKEND_MISSING_INTERFACE + _Reasons.BACKEND_MISSING_INTERFACE, ) self._backend = backend self._used = False @@ -116,8 +122,9 @@ def derive(self, key_material): if self._used: raise AlreadyFinalized self._used = True - return _concatkdf_derive(key_material, self._length, - self._hmac, self._otherinfo) + return _concatkdf_derive( + key_material, self._length, self._hmac, self._otherinfo + ) def verify(self, key_material, expected_key): if not constant_time.bytes_eq(self.derive(key_material), expected_key): diff --git a/src/cryptography/hazmat/primitives/kdf/hkdf.py b/src/cryptography/hazmat/primitives/kdf/hkdf.py index 307f91cca777..9bb6bc213253 100644 --- a/src/cryptography/hazmat/primitives/kdf/hkdf.py +++ b/src/cryptography/hazmat/primitives/kdf/hkdf.py @@ -8,8 +8,12 @@ from cryptography import utils from cryptography.exceptions import ( - AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons + AlreadyFinalized, + InvalidKey, + UnsupportedAlgorithm, + _Reasons, ) +from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import constant_time, hmac from cryptography.hazmat.primitives.kdf import KeyDerivationFunction @@ -17,11 +21,12 @@ @utils.register_interface(KeyDerivationFunction) class HKDF(object): - def __init__(self, algorithm, length, salt, info, backend): + def __init__(self, algorithm, length, salt, info, backend=None): + backend = _get_backend(backend) if not isinstance(backend, HMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement HMACBackend.", - _Reasons.BACKEND_MISSING_INTERFACE + _Reasons.BACKEND_MISSING_INTERFACE, ) self._algorithm = algorithm @@ -53,11 +58,12 @@ def verify(self, key_material, expected_key): @utils.register_interface(KeyDerivationFunction) class HKDFExpand(object): - def __init__(self, algorithm, length, info, backend): + def __init__(self, algorithm, length, info, backend=None): + backend = _get_backend(backend) if not isinstance(backend, HMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement HMACBackend.", - _Reasons.BACKEND_MISSING_INTERFACE + _Reasons.BACKEND_MISSING_INTERFACE, ) self._algorithm = algorithm @@ -68,9 +74,8 @@ def __init__(self, algorithm, length, info, backend): if length > max_length: raise ValueError( - "Can not derive keys larger than {0} octets.".format( - max_length - )) + "Can not derive keys larger than {} octets.".format(max_length) + ) self._length = length @@ -95,7 +100,7 @@ def _expand(self, key_material): output.append(h.finalize()) counter += 1 - return b"".join(output)[:self._length] + return b"".join(output)[: self._length] def derive(self, key_material): utils._check_byteslike("key_material", key_material) diff --git a/src/cryptography/hazmat/primitives/kdf/kbkdf.py b/src/cryptography/hazmat/primitives/kdf/kbkdf.py index 56783a85cc5d..864337001c89 100644 --- a/src/cryptography/hazmat/primitives/kdf/kbkdf.py +++ b/src/cryptography/hazmat/primitives/kdf/kbkdf.py @@ -10,8 +10,12 @@ from cryptography import utils from cryptography.exceptions import ( - AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons + AlreadyFinalized, + InvalidKey, + UnsupportedAlgorithm, + _Reasons, ) +from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import constant_time, hashes, hmac from cryptography.hazmat.primitives.kdf import KeyDerivationFunction @@ -28,24 +32,36 @@ class CounterLocation(Enum): @utils.register_interface(KeyDerivationFunction) class KBKDFHMAC(object): - def __init__(self, algorithm, mode, length, rlen, llen, - location, label, context, fixed, backend): + def __init__( + self, + algorithm, + mode, + length, + rlen, + llen, + location, + label, + context, + fixed, + backend=None, + ): + backend = _get_backend(backend) if not isinstance(backend, HMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement HMACBackend.", - _Reasons.BACKEND_MISSING_INTERFACE + _Reasons.BACKEND_MISSING_INTERFACE, ) if not isinstance(algorithm, hashes.HashAlgorithm): raise UnsupportedAlgorithm( "Algorithm supplied is not a supported hash algorithm.", - _Reasons.UNSUPPORTED_HASH + _Reasons.UNSUPPORTED_HASH, ) if not backend.hmac_supported(algorithm): raise UnsupportedAlgorithm( "Algorithm supplied is not a supported hmac algorithm.", - _Reasons.UNSUPPORTED_HASH + _Reasons.UNSUPPORTED_HASH, ) if not isinstance(mode, Mode): @@ -55,8 +71,9 @@ def __init__(self, algorithm, mode, length, rlen, llen, raise TypeError("location must be of type CounterLocation") if (label or context) and fixed: - raise ValueError("When supplying fixed data, " - "label and context are ignored.") + raise ValueError( + "When supplying fixed data, " "label and context are ignored." + ) if rlen is None or not self._valid_byte_length(rlen): raise ValueError("rlen must be between 1 and 4") @@ -68,10 +85,10 @@ def __init__(self, algorithm, mode, length, rlen, llen, raise TypeError("llen must be an integer") if label is None: - label = b'' + label = b"" if context is None: - context = b'' + context = b"" utils._check_bytes("label", label) utils._check_bytes("context", context) @@ -89,7 +106,7 @@ def __init__(self, algorithm, mode, length, rlen, llen, def _valid_byte_length(self, value): if not isinstance(value, int): - raise TypeError('value must be of type int') + raise TypeError("value must be of type int") value_bin = utils.int_to_bytes(1, value) if not 1 <= len(value_bin) <= 4: @@ -106,7 +123,7 @@ def derive(self, key_material): # inverse floor division (equivalent to ceiling) rounds = -(-self._length // self._algorithm.digest_size) - output = [b''] + output = [b""] # For counter mode, the number of iterations shall not be # larger than 2^r-1, where r <= 32 is the binary length of the counter @@ -114,7 +131,7 @@ def derive(self, key_material): # PRF will not repeat during a particular call to the KDF function. r_bin = utils.int_to_bytes(1, self._rlen) if rounds > pow(2, len(r_bin) * 8) - 1: - raise ValueError('There are too many iterations.') + raise ValueError("There are too many iterations.") for i in range(1, rounds + 1): h = hmac.HMAC(key_material, self._algorithm, backend=self._backend) @@ -130,7 +147,7 @@ def derive(self, key_material): output.append(h.finalize()) - return b''.join(output)[:self._length] + return b"".join(output)[: self._length] def _generate_fixed_input(self): if self._fixed_data and isinstance(self._fixed_data, bytes): diff --git a/src/cryptography/hazmat/primitives/kdf/pbkdf2.py b/src/cryptography/hazmat/primitives/kdf/pbkdf2.py index a47b7bbcb6bb..5b67d48bbab6 100644 --- a/src/cryptography/hazmat/primitives/kdf/pbkdf2.py +++ b/src/cryptography/hazmat/primitives/kdf/pbkdf2.py @@ -6,8 +6,12 @@ from cryptography import utils from cryptography.exceptions import ( - AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons + AlreadyFinalized, + InvalidKey, + UnsupportedAlgorithm, + _Reasons, ) +from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import PBKDF2HMACBackend from cryptography.hazmat.primitives import constant_time from cryptography.hazmat.primitives.kdf import KeyDerivationFunction @@ -15,18 +19,20 @@ @utils.register_interface(KeyDerivationFunction) class PBKDF2HMAC(object): - def __init__(self, algorithm, length, salt, iterations, backend): + def __init__(self, algorithm, length, salt, iterations, backend=None): + backend = _get_backend(backend) if not isinstance(backend, PBKDF2HMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement PBKDF2HMACBackend.", - _Reasons.BACKEND_MISSING_INTERFACE + _Reasons.BACKEND_MISSING_INTERFACE, ) if not backend.pbkdf2_hmac_supported(algorithm): raise UnsupportedAlgorithm( - "{0} is not supported for PBKDF2 by this backend.".format( - algorithm.name), - _Reasons.UNSUPPORTED_HASH + "{} is not supported for PBKDF2 by this backend.".format( + algorithm.name + ), + _Reasons.UNSUPPORTED_HASH, ) self._used = False self._algorithm = algorithm @@ -47,7 +53,7 @@ def derive(self, key_material): self._length, self._salt, self._iterations, - key_material + key_material, ) def verify(self, key_material, expected_key): diff --git a/src/cryptography/hazmat/primitives/kdf/scrypt.py b/src/cryptography/hazmat/primitives/kdf/scrypt.py index df9745e68917..f028646aa02d 100644 --- a/src/cryptography/hazmat/primitives/kdf/scrypt.py +++ b/src/cryptography/hazmat/primitives/kdf/scrypt.py @@ -8,8 +8,12 @@ from cryptography import utils from cryptography.exceptions import ( - AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons + AlreadyFinalized, + InvalidKey, + UnsupportedAlgorithm, + _Reasons, ) +from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import ScryptBackend from cryptography.hazmat.primitives import constant_time from cryptography.hazmat.primitives.kdf import KeyDerivationFunction @@ -22,11 +26,12 @@ @utils.register_interface(KeyDerivationFunction) class Scrypt(object): - def __init__(self, salt, length, n, r, p, backend): + def __init__(self, salt, length, n, r, p, backend=None): + backend = _get_backend(backend) if not isinstance(backend, ScryptBackend): raise UnsupportedAlgorithm( "Backend object does not implement ScryptBackend.", - _Reasons.BACKEND_MISSING_INTERFACE + _Reasons.BACKEND_MISSING_INTERFACE, ) self._length = length diff --git a/src/cryptography/hazmat/primitives/kdf/x963kdf.py b/src/cryptography/hazmat/primitives/kdf/x963kdf.py index fd9d125e79c7..1898d526a48f 100644 --- a/src/cryptography/hazmat/primitives/kdf/x963kdf.py +++ b/src/cryptography/hazmat/primitives/kdf/x963kdf.py @@ -8,25 +8,31 @@ from cryptography import utils from cryptography.exceptions import ( - AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons + AlreadyFinalized, + InvalidKey, + UnsupportedAlgorithm, + _Reasons, ) +from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import HashBackend from cryptography.hazmat.primitives import constant_time, hashes from cryptography.hazmat.primitives.kdf import KeyDerivationFunction def _int_to_u32be(n): - return struct.pack('>I', n) + return struct.pack(">I", n) @utils.register_interface(KeyDerivationFunction) class X963KDF(object): - def __init__(self, algorithm, length, sharedinfo, backend): + def __init__(self, algorithm, length, sharedinfo, backend=None): + backend = _get_backend(backend) max_len = algorithm.digest_size * (2 ** 32 - 1) if length > max_len: raise ValueError( - "Can not derive keys larger than {0} bits.".format(max_len)) + "Can not derive keys larger than {} bits.".format(max_len) + ) if sharedinfo is not None: utils._check_bytes("sharedinfo", sharedinfo) @@ -37,7 +43,7 @@ def __init__(self, algorithm, length, sharedinfo, backend): if not isinstance(backend, HashBackend): raise UnsupportedAlgorithm( "Backend object does not implement HashBackend.", - _Reasons.BACKEND_MISSING_INTERFACE + _Reasons.BACKEND_MISSING_INTERFACE, ) self._backend = backend self._used = False @@ -61,7 +67,7 @@ def derive(self, key_material): outlen += len(output[-1]) counter += 1 - return b"".join(output)[:self._length] + return b"".join(output)[: self._length] def verify(self, key_material, expected_key): if not constant_time.bytes_eq(self.derive(key_material), expected_key): diff --git a/src/cryptography/hazmat/primitives/keywrap.py b/src/cryptography/hazmat/primitives/keywrap.py index f55c519cff33..2439cafe6d59 100644 --- a/src/cryptography/hazmat/primitives/keywrap.py +++ b/src/cryptography/hazmat/primitives/keywrap.py @@ -6,6 +6,7 @@ import struct +from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.hazmat.primitives.ciphers.algorithms import AES from cryptography.hazmat.primitives.ciphers.modes import ECB @@ -33,7 +34,8 @@ def _wrap_core(wrapping_key, a, r, backend): return a + b"".join(r) -def aes_key_wrap(wrapping_key, key_to_wrap, backend): +def aes_key_wrap(wrapping_key, key_to_wrap, backend=None): + backend = _get_backend(backend) if len(wrapping_key) not in [16, 24, 32]: raise ValueError("The wrapping key must be a valid AES key length") @@ -44,7 +46,7 @@ def aes_key_wrap(wrapping_key, key_to_wrap, backend): raise ValueError("The key to wrap must be a multiple of 8 bytes") a = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6" - r = [key_to_wrap[i:i + 8] for i in range(0, len(key_to_wrap), 8)] + r = [key_to_wrap[i : i + 8] for i in range(0, len(key_to_wrap), 8)] return _wrap_core(wrapping_key, a, r, backend) @@ -55,9 +57,12 @@ def _unwrap_core(wrapping_key, a, r, backend): for j in reversed(range(6)): for i in reversed(range(n)): # pack/unpack are safe as these are always 64-bit chunks - atr = struct.pack( - ">Q", struct.unpack(">Q", a)[0] ^ ((n * j) + i + 1) - ) + r[i] + atr = ( + struct.pack( + ">Q", struct.unpack(">Q", a)[0] ^ ((n * j) + i + 1) + ) + + r[i] + ) # every decryption operation is a discrete 16 byte chunk so # it is safe to reuse the decryptor for the entire operation b = decryptor.update(atr) @@ -68,7 +73,8 @@ def _unwrap_core(wrapping_key, a, r, backend): return a, r -def aes_key_wrap_with_padding(wrapping_key, key_to_wrap, backend): +def aes_key_wrap_with_padding(wrapping_key, key_to_wrap, backend=None): + backend = _get_backend(backend) if len(wrapping_key) not in [16, 24, 32]: raise ValueError("The wrapping key must be a valid AES key length") @@ -83,11 +89,12 @@ def aes_key_wrap_with_padding(wrapping_key, key_to_wrap, backend): assert encryptor.finalize() == b"" return b else: - r = [key_to_wrap[i:i + 8] for i in range(0, len(key_to_wrap), 8)] + r = [key_to_wrap[i : i + 8] for i in range(0, len(key_to_wrap), 8)] return _wrap_core(wrapping_key, aiv, r, backend) -def aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend): +def aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend=None): + backend = _get_backend(backend) if len(wrapped_key) < 16: raise InvalidUnwrap("Must be at least 16 bytes") @@ -103,7 +110,7 @@ def aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend): data = b[8:] n = 1 else: - r = [wrapped_key[i:i + 8] for i in range(0, len(wrapped_key), 8)] + r = [wrapped_key[i : i + 8] for i in range(0, len(wrapped_key), 8)] encrypted_aiv = r.pop(0) n = len(r) a, r = _unwrap_core(wrapping_key, encrypted_aiv, r, backend) @@ -117,10 +124,9 @@ def aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend): (mli,) = struct.unpack(">I", a[4:]) b = (8 * n) - mli if ( - not bytes_eq(a[:4], b"\xa6\x59\x59\xa6") or not - 8 * (n - 1) < mli <= 8 * n or ( - b != 0 and not bytes_eq(data[-b:], b"\x00" * b) - ) + not bytes_eq(a[:4], b"\xa6\x59\x59\xa6") + or not 8 * (n - 1) < mli <= 8 * n + or (b != 0 and not bytes_eq(data[-b:], b"\x00" * b)) ): raise InvalidUnwrap() @@ -130,7 +136,8 @@ def aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend): return data[:-b] -def aes_key_unwrap(wrapping_key, wrapped_key, backend): +def aes_key_unwrap(wrapping_key, wrapped_key, backend=None): + backend = _get_backend(backend) if len(wrapped_key) < 24: raise InvalidUnwrap("Must be at least 24 bytes") @@ -141,7 +148,7 @@ def aes_key_unwrap(wrapping_key, wrapped_key, backend): raise ValueError("The wrapping key must be a valid AES key length") aiv = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6" - r = [wrapped_key[i:i + 8] for i in range(0, len(wrapped_key), 8)] + r = [wrapped_key[i : i + 8] for i in range(0, len(wrapped_key), 8)] a = r.pop(0) a, r = _unwrap_core(wrapping_key, a, r, backend) if not bytes_eq(a, aiv): diff --git a/src/cryptography/hazmat/primitives/mac.py b/src/cryptography/hazmat/primitives/mac.py deleted file mode 100644 index 4c95190ba110..000000000000 --- a/src/cryptography/hazmat/primitives/mac.py +++ /dev/null @@ -1,37 +0,0 @@ -# This file is dual licensed under the terms of the Apache License, Version -# 2.0, and the BSD License. See the LICENSE file in the root of this repository -# for complete details. - -from __future__ import absolute_import, division, print_function - -import abc - -import six - - -@six.add_metaclass(abc.ABCMeta) -class MACContext(object): - @abc.abstractmethod - def update(self, data): - """ - Processes the provided bytes. - """ - - @abc.abstractmethod - def finalize(self): - """ - Returns the message authentication code as bytes. - """ - - @abc.abstractmethod - def copy(self): - """ - Return a MACContext that is a copy of the current context. - """ - - @abc.abstractmethod - def verify(self, signature): - """ - Checks if the generated message authentication code matches the - signature. - """ diff --git a/src/cryptography/hazmat/primitives/padding.py b/src/cryptography/hazmat/primitives/padding.py index 170c80218b12..d3dc7093ae51 100644 --- a/src/cryptography/hazmat/primitives/padding.py +++ b/src/cryptography/hazmat/primitives/padding.py @@ -40,14 +40,14 @@ def _byte_padding_update(buffer_, data, block_size): if buffer_ is None: raise AlreadyFinalized("Context was already finalized.") - utils._check_bytes("data", data) + utils._check_byteslike("data", data) - buffer_ += data + buffer_ += bytes(data) finished_blocks = len(buffer_) // (block_size // 8) - result = buffer_[:finished_blocks * (block_size // 8)] - buffer_ = buffer_[finished_blocks * (block_size // 8):] + result = buffer_[: finished_blocks * (block_size // 8)] + buffer_ = buffer_[finished_blocks * (block_size // 8) :] return buffer_, result @@ -64,14 +64,14 @@ def _byte_unpadding_update(buffer_, data, block_size): if buffer_ is None: raise AlreadyFinalized("Context was already finalized.") - utils._check_bytes("data", data) + utils._check_byteslike("data", data) - buffer_ += data + buffer_ += bytes(data) finished_blocks = max(len(buffer_) // (block_size // 8) - 1, 0) - result = buffer_[:finished_blocks * (block_size // 8)] - buffer_ = buffer_[finished_blocks * (block_size // 8):] + result = buffer_[: finished_blocks * (block_size // 8)] + buffer_ = buffer_[finished_blocks * (block_size // 8) :] return buffer_, result @@ -113,7 +113,8 @@ def __init__(self, block_size): def update(self, data): self._buffer, result = _byte_padding_update( - self._buffer, data, self.block_size) + self._buffer, data, self.block_size + ) return result def _padding(self, size): @@ -121,7 +122,8 @@ def _padding(self, size): def finalize(self): result = _byte_padding_pad( - self._buffer, self.block_size, self._padding) + self._buffer, self.block_size, self._padding + ) self._buffer = None return result @@ -135,13 +137,14 @@ def __init__(self, block_size): def update(self, data): self._buffer, result = _byte_unpadding_update( - self._buffer, data, self.block_size) + self._buffer, data, self.block_size + ) return result def finalize(self): result = _byte_unpadding_check( - self._buffer, self.block_size, - lib.Cryptography_check_pkcs7_padding) + self._buffer, self.block_size, lib.Cryptography_check_pkcs7_padding + ) self._buffer = None return result @@ -167,7 +170,8 @@ def __init__(self, block_size): def update(self, data): self._buffer, result = _byte_padding_update( - self._buffer, data, self.block_size) + self._buffer, data, self.block_size + ) return result def _padding(self, size): @@ -175,7 +179,8 @@ def _padding(self, size): def finalize(self): result = _byte_padding_pad( - self._buffer, self.block_size, self._padding) + self._buffer, self.block_size, self._padding + ) self._buffer = None return result @@ -189,12 +194,15 @@ def __init__(self, block_size): def update(self, data): self._buffer, result = _byte_unpadding_update( - self._buffer, data, self.block_size) + self._buffer, data, self.block_size + ) return result def finalize(self): result = _byte_unpadding_check( - self._buffer, self.block_size, - lib.Cryptography_check_ansix923_padding) + self._buffer, + self.block_size, + lib.Cryptography_check_ansix923_padding, + ) self._buffer = None return result diff --git a/src/cryptography/hazmat/primitives/poly1305.py b/src/cryptography/hazmat/primitives/poly1305.py new file mode 100644 index 000000000000..6439686202de --- /dev/null +++ b/src/cryptography/hazmat/primitives/poly1305.py @@ -0,0 +1,58 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + + +from cryptography import utils +from cryptography.exceptions import ( + AlreadyFinalized, + UnsupportedAlgorithm, + _Reasons, +) + + +class Poly1305(object): + def __init__(self, key): + 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): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + utils._check_byteslike("data", data) + self._ctx.update(data) + + def finalize(self): + if self._ctx is None: + raise AlreadyFinalized("Context was already finalized.") + mac = self._ctx.finalize() + self._ctx = None + return mac + + def verify(self, tag): + 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, data): + p = Poly1305(key) + p.update(data) + return p.finalize() + + @classmethod + def verify_tag(cls, key, data, tag): + p = Poly1305(key) + p.update(data) + p.verify(tag) diff --git a/src/cryptography/hazmat/primitives/serialization/__init__.py b/src/cryptography/hazmat/primitives/serialization/__init__.py index f6d4ce9942fb..c2f9b014a62d 100644 --- a/src/cryptography/hazmat/primitives/serialization/__init__.py +++ b/src/cryptography/hazmat/primitives/serialization/__init__.py @@ -5,22 +5,40 @@ from __future__ import absolute_import, division, print_function from cryptography.hazmat.primitives.serialization.base import ( - BestAvailableEncryption, Encoding, KeySerializationEncryption, - NoEncryption, ParameterFormat, PrivateFormat, PublicFormat, - load_der_parameters, load_der_private_key, load_der_public_key, - load_pem_parameters, load_pem_private_key, load_pem_public_key, + BestAvailableEncryption, + Encoding, + KeySerializationEncryption, + NoEncryption, + ParameterFormat, + PrivateFormat, + PublicFormat, + load_der_parameters, + load_der_private_key, + load_der_public_key, + load_pem_parameters, + load_pem_private_key, + load_pem_public_key, ) from cryptography.hazmat.primitives.serialization.ssh import ( - load_ssh_public_key + load_ssh_private_key, + load_ssh_public_key, ) -_PEM_DER = (Encoding.PEM, Encoding.DER) - __all__ = [ - "load_der_parameters", "load_der_private_key", "load_der_public_key", - "load_pem_parameters", "load_pem_private_key", "load_pem_public_key", - "load_ssh_public_key", "Encoding", "PrivateFormat", "PublicFormat", - "ParameterFormat", "KeySerializationEncryption", "BestAvailableEncryption", + "load_der_parameters", + "load_der_private_key", + "load_der_public_key", + "load_pem_parameters", + "load_pem_private_key", + "load_pem_public_key", + "load_ssh_private_key", + "load_ssh_public_key", + "Encoding", + "PrivateFormat", + "PublicFormat", + "ParameterFormat", + "KeySerializationEncryption", + "BestAvailableEncryption", "NoEncryption", ] diff --git a/src/cryptography/hazmat/primitives/serialization/base.py b/src/cryptography/hazmat/primitives/serialization/base.py index 4218ea8244ee..fc27235c5cf2 100644 --- a/src/cryptography/hazmat/primitives/serialization/base.py +++ b/src/cryptography/hazmat/primitives/serialization/base.py @@ -10,29 +10,36 @@ import six from cryptography import utils +from cryptography.hazmat.backends import _get_backend -def load_pem_private_key(data, password, backend): +def load_pem_private_key(data, password, backend=None): + backend = _get_backend(backend) return backend.load_pem_private_key(data, password) -def load_pem_public_key(data, backend): +def load_pem_public_key(data, backend=None): + backend = _get_backend(backend) return backend.load_pem_public_key(data) -def load_pem_parameters(data, backend): +def load_pem_parameters(data, backend=None): + backend = _get_backend(backend) return backend.load_pem_parameters(data) -def load_der_private_key(data, password, backend): +def load_der_private_key(data, password, backend=None): + backend = _get_backend(backend) return backend.load_der_private_key(data, password) -def load_der_public_key(data, backend): +def load_der_public_key(data, backend=None): + backend = _get_backend(backend) return backend.load_der_public_key(data) -def load_der_parameters(data, backend): +def load_der_parameters(data, backend=None): + backend = _get_backend(backend) return backend.load_der_parameters(data) @@ -42,12 +49,14 @@ class Encoding(Enum): OpenSSH = "OpenSSH" Raw = "Raw" X962 = "ANSI X9.62" + SMIME = "S/MIME" class PrivateFormat(Enum): PKCS8 = "PKCS8" TraditionalOpenSSL = "TraditionalOpenSSL" Raw = "Raw" + OpenSSH = "OpenSSH" class PublicFormat(Enum): diff --git a/src/cryptography/hazmat/primitives/serialization/pkcs12.py b/src/cryptography/hazmat/primitives/serialization/pkcs12.py index 98161d57a330..201f32941c1f 100644 --- a/src/cryptography/hazmat/primitives/serialization/pkcs12.py +++ b/src/cryptography/hazmat/primitives/serialization/pkcs12.py @@ -4,6 +4,47 @@ from __future__ import absolute_import, division, print_function +from cryptography import x509 +from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa -def load_key_and_certificates(data, password, backend): + +def load_key_and_certificates(data, password, backend=None): + backend = _get_backend(backend) return backend.load_key_and_certificates_from_pkcs12(data, password) + + +def serialize_key_and_certificates(name, key, cert, cas, encryption_algorithm): + if key is not None and not isinstance( + key, + ( + rsa.RSAPrivateKeyWithSerialization, + dsa.DSAPrivateKeyWithSerialization, + ec.EllipticCurvePrivateKeyWithSerialization, + ), + ): + raise TypeError("Key must be RSA, DSA, or EllipticCurve private key.") + if cert is not None and not isinstance(cert, x509.Certificate): + raise TypeError("cert must be a certificate") + + if cas is not None: + cas = list(cas) + if not all(isinstance(val, x509.Certificate) for val in cas): + raise TypeError("all values in cas must be certificates") + + if not isinstance( + encryption_algorithm, serialization.KeySerializationEncryption + ): + raise TypeError( + "Key encryption algorithm must be a " + "KeySerializationEncryption instance" + ) + + if key is None and cert is None and not cas: + raise ValueError("You must supply at least one of key, cert, or cas") + + backend = _get_backend(None) + return backend.serialize_key_and_certificates_to_pkcs12( + name, key, cert, cas, encryption_algorithm + ) diff --git a/src/cryptography/hazmat/primitives/serialization/pkcs7.py b/src/cryptography/hazmat/primitives/serialization/pkcs7.py new file mode 100644 index 000000000000..1e11e28ef5b3 --- /dev/null +++ b/src/cryptography/hazmat/primitives/serialization/pkcs7.py @@ -0,0 +1,132 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from enum import Enum + +from cryptography import x509 +from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ec, rsa +from cryptography.utils import _check_byteslike + + +def load_pem_pkcs7_certificates(data): + backend = _get_backend(None) + return backend.load_pem_pkcs7_certificates(data) + + +def load_der_pkcs7_certificates(data): + backend = _get_backend(None) + return backend.load_der_pkcs7_certificates(data) + + +class PKCS7SignatureBuilder(object): + def __init__(self, data=None, signers=[], additional_certs=[]): + self._data = data + self._signers = signers + self._additional_certs = additional_certs + + def set_data(self, data): + _check_byteslike("data", data) + if self._data is not None: + raise ValueError("data may only be set once") + + return PKCS7SignatureBuilder(data, self._signers) + + def add_signer(self, certificate, private_key, hash_algorithm): + if not isinstance( + hash_algorithm, + ( + hashes.SHA1, + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + ), + ): + raise TypeError( + "hash_algorithm must be one of hashes.SHA1, SHA224, " + "SHA256, SHA384, or SHA512" + ) + if not isinstance(certificate, x509.Certificate): + raise TypeError("certificate must be a x509.Certificate") + + if not isinstance( + private_key, (rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey) + ): + raise TypeError("Only RSA & EC keys are supported at this time.") + + return PKCS7SignatureBuilder( + self._data, + self._signers + [(certificate, private_key, hash_algorithm)], + ) + + def add_certificate(self, certificate): + if not isinstance(certificate, x509.Certificate): + raise TypeError("certificate must be a x509.Certificate") + + return PKCS7SignatureBuilder( + self._data, self._signers, self._additional_certs + [certificate] + ) + + def sign(self, encoding, options, backend=None): + if len(self._signers) == 0: + raise ValueError("Must have at least one signer") + if self._data is None: + raise ValueError("You must add data to sign") + options = list(options) + if not all(isinstance(x, PKCS7Options) for x in options): + raise ValueError("options must be from the PKCS7Options enum") + if encoding not in ( + serialization.Encoding.PEM, + serialization.Encoding.DER, + serialization.Encoding.SMIME, + ): + raise ValueError( + "Must be PEM, DER, or SMIME from the Encoding enum" + ) + + # Text is a meaningless option unless it is accompanied by + # DetachedSignature + if ( + PKCS7Options.Text in options + and PKCS7Options.DetachedSignature not in options + ): + raise ValueError( + "When passing the Text option you must also pass " + "DetachedSignature" + ) + + if PKCS7Options.Text in options and encoding in ( + serialization.Encoding.DER, + serialization.Encoding.PEM, + ): + raise ValueError( + "The Text option is only available for SMIME serialization" + ) + + # No attributes implies no capabilities so we'll error if you try to + # pass both. + if ( + PKCS7Options.NoAttributes in options + and PKCS7Options.NoCapabilities in options + ): + raise ValueError( + "NoAttributes is a superset of NoCapabilities. Do not pass " + "both values." + ) + + backend = _get_backend(backend) + return backend.pkcs7_sign(self, encoding, options) + + +class PKCS7Options(Enum): + Text = "Add text/plain MIME type" + Binary = "Don't translate input data into canonical MIME format" + DetachedSignature = "Don't embed data in the PKCS7 structure" + NoCapabilities = "Don't embed SMIME capabilities" + NoAttributes = "Don't embed authenticatedAttributes" + NoCerts = "Don't embed signer certificate" diff --git a/src/cryptography/hazmat/primitives/serialization/ssh.py b/src/cryptography/hazmat/primitives/serialization/ssh.py index cb838927d33d..5ecae59f8aa6 100644 --- a/src/cryptography/hazmat/primitives/serialization/ssh.py +++ b/src/cryptography/hazmat/primitives/serialization/ssh.py @@ -4,139 +4,680 @@ from __future__ import absolute_import, division, print_function -import base64 +import binascii +import os +import re import struct import six from cryptography import utils from cryptography.exceptions import UnsupportedAlgorithm -from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa - - -def load_ssh_public_key(data, backend): - key_parts = data.split(b' ', 2) - - if len(key_parts) < 2: - raise ValueError( - 'Key is not in the proper format or contains extra data.') - - key_type = key_parts[0] - - if key_type == b'ssh-rsa': - loader = _load_ssh_rsa_public_key - elif key_type == b'ssh-dss': - loader = _load_ssh_dss_public_key - elif key_type in [ - b'ecdsa-sha2-nistp256', b'ecdsa-sha2-nistp384', b'ecdsa-sha2-nistp521', - ]: - loader = _load_ssh_ecdsa_public_key - else: - raise UnsupportedAlgorithm('Key type is not supported.') - - key_body = key_parts[1] - - try: - decoded_data = base64.b64decode(key_body) - except TypeError: - raise ValueError('Key is not in the proper format.') - - inner_key_type, rest = _ssh_read_next_string(decoded_data) - - if inner_key_type != key_type: +from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.primitives.asymmetric import dsa, ec, ed25519, rsa +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives.serialization import ( + Encoding, + NoEncryption, + PrivateFormat, + PublicFormat, +) + +try: + from bcrypt import kdf as _bcrypt_kdf + + _bcrypt_supported = True +except ImportError: + _bcrypt_supported = False + + def _bcrypt_kdf(*args, **kwargs): + raise UnsupportedAlgorithm("Need bcrypt module") + + +try: + from base64 import encodebytes as _base64_encode +except ImportError: + from base64 import encodestring as _base64_encode + +_SSH_ED25519 = b"ssh-ed25519" +_SSH_RSA = b"ssh-rsa" +_SSH_DSA = b"ssh-dss" +_ECDSA_NISTP256 = b"ecdsa-sha2-nistp256" +_ECDSA_NISTP384 = b"ecdsa-sha2-nistp384" +_ECDSA_NISTP521 = b"ecdsa-sha2-nistp521" +_CERT_SUFFIX = b"-cert-v01@openssh.com" + +_SSH_PUBKEY_RC = re.compile(br"\A(\S+)[ \t]+(\S+)") +_SK_MAGIC = b"openssh-key-v1\0" +_SK_START = b"-----BEGIN OPENSSH PRIVATE KEY-----" +_SK_END = b"-----END OPENSSH PRIVATE KEY-----" +_BCRYPT = b"bcrypt" +_NONE = b"none" +_DEFAULT_CIPHER = b"aes256-ctr" +_DEFAULT_ROUNDS = 16 +_MAX_PASSWORD = 72 + +# re is only way to work on bytes-like data +_PEM_RC = re.compile(_SK_START + b"(.*?)" + _SK_END, re.DOTALL) + +# padding for max blocksize +_PADDING = memoryview(bytearray(range(1, 1 + 16))) + +# ciphers that are actually used in key wrapping +_SSH_CIPHERS = { + b"aes256-ctr": (algorithms.AES, 32, modes.CTR, 16), + b"aes256-cbc": (algorithms.AES, 32, modes.CBC, 16), +} + +# map local curve name to key type +_ECDSA_KEY_TYPE = { + "secp256r1": _ECDSA_NISTP256, + "secp384r1": _ECDSA_NISTP384, + "secp521r1": _ECDSA_NISTP521, +} + +_U32 = struct.Struct(b">I") +_U64 = struct.Struct(b">Q") + + +def _ecdsa_key_type(public_key): + """Return SSH key_type and curve_name for private key.""" + curve = public_key.curve + if curve.name not in _ECDSA_KEY_TYPE: raise ValueError( - 'Key header and key body contain different key type values.' + "Unsupported curve for ssh private key: %r" % curve.name ) - - return loader(key_type, rest, backend) + return _ECDSA_KEY_TYPE[curve.name] -def _load_ssh_rsa_public_key(key_type, decoded_data, backend): - e, rest = _ssh_read_next_mpint(decoded_data) - n, rest = _ssh_read_next_mpint(rest) +def _ssh_pem_encode(data, prefix=_SK_START + b"\n", suffix=_SK_END + b"\n"): + return b"".join([prefix, _base64_encode(data), suffix]) - if rest: - raise ValueError('Key body contains extra bytes.') - return rsa.RSAPublicNumbers(e, n).public_key(backend) +def _check_block_size(data, block_len): + """Require data to be full blocks""" + if not data or len(data) % block_len != 0: + raise ValueError("Corrupt data: missing padding") -def _load_ssh_dss_public_key(key_type, decoded_data, backend): - p, rest = _ssh_read_next_mpint(decoded_data) - q, rest = _ssh_read_next_mpint(rest) - g, rest = _ssh_read_next_mpint(rest) - y, rest = _ssh_read_next_mpint(rest) +def _check_empty(data): + """All data should have been parsed.""" + if data: + raise ValueError("Corrupt data: unparsed data") - if rest: - raise ValueError('Key body contains extra bytes.') - parameter_numbers = dsa.DSAParameterNumbers(p, q, g) - public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers) +def _init_cipher(ciphername, password, salt, rounds, backend): + """Generate key + iv and return cipher.""" + if not password: + raise ValueError("Key is password-protected.") - return public_numbers.public_key(backend) + 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:]), backend) -def _load_ssh_ecdsa_public_key(expected_key_type, decoded_data, backend): - curve_name, rest = _ssh_read_next_string(decoded_data) - data, rest = _ssh_read_next_string(rest) +def _get_u32(data): + """Uint32""" + if len(data) < 4: + raise ValueError("Invalid data") + return _U32.unpack(data[:4])[0], data[4:] + + +def _get_u64(data): + """Uint64""" + if len(data) < 8: + raise ValueError("Invalid data") + return _U64.unpack(data[:8])[0], data[8:] + + +def _get_sshstr(data): + """Bytes with u32 length prefix""" + n, data = _get_u32(data) + if n > len(data): + raise ValueError("Invalid data") + return data[:n], data[n:] + + +def _get_mpint(data): + """Big integer.""" + val, data = _get_sshstr(data) + if val and six.indexbytes(val, 0) > 0x7F: + raise ValueError("Invalid data") + return utils.int_from_bytes(val, "big"), data + + +def _to_mpint(val): + """Storage format for signed bigint.""" + if val < 0: + raise ValueError("negative mpint not allowed") + if not val: + return b"" + nbytes = (val.bit_length() + 8) // 8 + return utils.int_to_bytes(val, nbytes) + + +class _FragList(object): + """Build recursive structure without data copy.""" + + def __init__(self, init=None): + self.flist = [] + if init: + self.flist.extend(init) + + def put_raw(self, val): + """Add plain bytes""" + self.flist.append(val) + + def put_u32(self, val): + """Big-endian uint32""" + self.flist.append(_U32.pack(val)) + + def put_sshstr(self, val): + """Bytes prefixed with u32 length""" + if isinstance(val, (bytes, memoryview, bytearray)): + self.put_u32(len(val)) + self.flist.append(val) + else: + self.put_u32(val.size()) + self.flist.extend(val.flist) + + def put_mpint(self, val): + """Big-endian bigint prefixed with u32 length""" + self.put_sshstr(_to_mpint(val)) + + def size(self): + """Current number of bytes""" + return sum(map(len, self.flist)) + + def render(self, dstbuf, pos=0): + """Write into bytearray""" + for frag in self.flist: + flen = len(frag) + start, pos = pos, pos + flen + dstbuf[start:pos] = frag + return pos + + def tobytes(self): + """Return as bytes""" + buf = memoryview(bytearray(self.size())) + self.render(buf) + return buf.tobytes() + + +class _SSHFormatRSA(object): + """Format for RSA keys. + + Public: + mpint e, n + Private: + mpint n, e, d, iqmp, p, q + """ - if expected_key_type != b"ecdsa-sha2-" + curve_name: - raise ValueError( - 'Key header and key body contain different key type values.' + def get_public(self, data): + """RSA public fields""" + e, data = _get_mpint(data) + n, data = _get_mpint(data) + return (e, n), data + + def load_public(self, key_type, data, backend): + """Make RSA public key from data.""" + (e, n), data = self.get_public(data) + public_numbers = rsa.RSAPublicNumbers(e, n) + public_key = public_numbers.public_key(backend) + return public_key, data + + def load_private(self, data, pubfields, backend): + """Make RSA private key from data.""" + n, data = _get_mpint(data) + e, data = _get_mpint(data) + d, data = _get_mpint(data) + iqmp, data = _get_mpint(data) + p, data = _get_mpint(data) + q, data = _get_mpint(data) + + if (e, n) != pubfields: + raise ValueError("Corrupt data: rsa field mismatch") + dmp1 = rsa.rsa_crt_dmp1(d, p) + dmq1 = rsa.rsa_crt_dmq1(d, q) + public_numbers = rsa.RSAPublicNumbers(e, n) + private_numbers = rsa.RSAPrivateNumbers( + p, q, d, dmp1, dmq1, iqmp, public_numbers ) + private_key = private_numbers.private_key(backend) + return private_key, data - if rest: - raise ValueError('Key body contains extra bytes.') + def encode_public(self, public_key, f_pub): + """Write RSA public key""" + pubn = public_key.public_numbers() + f_pub.put_mpint(pubn.e) + f_pub.put_mpint(pubn.n) - curve = { - b"nistp256": ec.SECP256R1, - b"nistp384": ec.SECP384R1, - b"nistp521": ec.SECP521R1, - }[curve_name]() + def encode_private(self, private_key, f_priv): + """Write RSA private key""" + private_numbers = private_key.private_numbers() + public_numbers = private_numbers.public_numbers - if six.indexbytes(data, 0) != 4: - raise NotImplementedError( - "Compressed elliptic curve points are not supported" - ) + f_priv.put_mpint(public_numbers.n) + f_priv.put_mpint(public_numbers.e) + + f_priv.put_mpint(private_numbers.d) + f_priv.put_mpint(private_numbers.iqmp) + f_priv.put_mpint(private_numbers.p) + f_priv.put_mpint(private_numbers.q) - return ec.EllipticCurvePublicKey.from_encoded_point(curve, data) +class _SSHFormatDSA(object): + """Format for DSA keys. -def _ssh_read_next_string(data): + Public: + mpint p, q, g, y + Private: + mpint p, q, g, y, x """ - Retrieves the next RFC 4251 string value from the data. - While the RFC calls these strings, in Python they are bytes objects. + def get_public(self, data): + """DSA public fields""" + p, data = _get_mpint(data) + q, data = _get_mpint(data) + g, data = _get_mpint(data) + y, data = _get_mpint(data) + return (p, q, g, y), data + + def load_public(self, key_type, data, backend): + """Make DSA public key from data.""" + (p, q, g, y), data = self.get_public(data) + parameter_numbers = dsa.DSAParameterNumbers(p, q, g) + public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers) + self._validate(public_numbers) + public_key = public_numbers.public_key(backend) + return public_key, data + + def load_private(self, data, pubfields, backend): + """Make DSA private key from data.""" + (p, q, g, y), data = self.get_public(data) + x, data = _get_mpint(data) + + if (p, q, g, y) != pubfields: + raise ValueError("Corrupt data: dsa field mismatch") + parameter_numbers = dsa.DSAParameterNumbers(p, q, g) + public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers) + self._validate(public_numbers) + private_numbers = dsa.DSAPrivateNumbers(x, public_numbers) + private_key = private_numbers.private_key(backend) + return private_key, data + + def encode_public(self, public_key, f_pub): + """Write DSA public key""" + public_numbers = public_key.public_numbers() + parameter_numbers = public_numbers.parameter_numbers + self._validate(public_numbers) + + f_pub.put_mpint(parameter_numbers.p) + f_pub.put_mpint(parameter_numbers.q) + f_pub.put_mpint(parameter_numbers.g) + f_pub.put_mpint(public_numbers.y) + + def encode_private(self, private_key, f_priv): + """Write DSA private key""" + self.encode_public(private_key.public_key(), f_priv) + f_priv.put_mpint(private_key.private_numbers().x) + + def _validate(self, public_numbers): + parameter_numbers = public_numbers.parameter_numbers + if parameter_numbers.p.bit_length() != 1024: + raise ValueError("SSH supports only 1024 bit DSA keys") + + +class _SSHFormatECDSA(object): + """Format for ECDSA keys. + + Public: + str curve + bytes point + Private: + str curve + bytes point + mpint secret """ - if len(data) < 4: - raise ValueError("Key is not in the proper format") - str_len, = struct.unpack('>I', data[:4]) - if len(data) < str_len + 4: - raise ValueError("Key is not in the proper format") + def __init__(self, ssh_curve_name, curve): + self.ssh_curve_name = ssh_curve_name + self.curve = curve + + def get_public(self, data): + """ECDSA public fields""" + curve, data = _get_sshstr(data) + point, data = _get_sshstr(data) + if curve != self.ssh_curve_name: + raise ValueError("Curve name mismatch") + if six.indexbytes(point, 0) != 4: + raise NotImplementedError("Need uncompressed point") + return (curve, point), data + + def load_public(self, key_type, data, backend): + """Make ECDSA public key from data.""" + (curve_name, point), data = self.get_public(data) + public_key = ec.EllipticCurvePublicKey.from_encoded_point( + self.curve, point.tobytes() + ) + return public_key, data + + def load_private(self, data, pubfields, backend): + """Make ECDSA private key from data.""" + (curve_name, point), data = self.get_public(data) + secret, data = _get_mpint(data) + + if (curve_name, point) != pubfields: + raise ValueError("Corrupt data: ecdsa field mismatch") + private_key = ec.derive_private_key(secret, self.curve, backend) + return private_key, data + + def encode_public(self, public_key, f_pub): + """Write ECDSA public key""" + point = public_key.public_bytes( + Encoding.X962, PublicFormat.UncompressedPoint + ) + f_pub.put_sshstr(self.ssh_curve_name) + f_pub.put_sshstr(point) - return data[4:4 + str_len], data[4 + str_len:] + def encode_private(self, private_key, f_priv): + """Write ECDSA private key""" + public_key = private_key.public_key() + private_numbers = private_key.private_numbers() + self.encode_public(public_key, f_priv) + f_priv.put_mpint(private_numbers.private_value) -def _ssh_read_next_mpint(data): - """ - Reads the next mpint from the data. - Currently, all mpints are interpreted as unsigned. +class _SSHFormatEd25519(object): + """Format for Ed25519 keys. + + Public: + bytes point + Private: + bytes point + bytes secret_and_point """ - mpint_data, rest = _ssh_read_next_string(data) - return ( - utils.int_from_bytes(mpint_data, byteorder='big', signed=False), rest - ) + def get_public(self, data): + """Ed25519 public fields""" + point, data = _get_sshstr(data) + return (point,), data + def load_public(self, key_type, data, backend): + """Make Ed25519 public key from data.""" + (point,), data = self.get_public(data) + public_key = ed25519.Ed25519PublicKey.from_public_bytes( + point.tobytes() + ) + return public_key, data + + def load_private(self, data, pubfields, backend): + """Make Ed25519 private key from data.""" + (point,), data = self.get_public(data) + keypair, data = _get_sshstr(data) + + secret = keypair[:32] + point2 = keypair[32:] + if point != point2 or (point,) != pubfields: + raise ValueError("Corrupt data: ed25519 field mismatch") + private_key = ed25519.Ed25519PrivateKey.from_private_bytes(secret) + return private_key, data + + def encode_public(self, public_key, f_pub): + """Write Ed25519 public key""" + raw_public_key = public_key.public_bytes( + Encoding.Raw, PublicFormat.Raw + ) + f_pub.put_sshstr(raw_public_key) -def _ssh_write_string(data): - return struct.pack(">I", len(data)) + data + def encode_private(self, private_key, f_priv): + """Write Ed25519 private key""" + public_key = private_key.public_key() + raw_private_key = private_key.private_bytes( + Encoding.Raw, PrivateFormat.Raw, NoEncryption() + ) + raw_public_key = public_key.public_bytes( + Encoding.Raw, PublicFormat.Raw + ) + f_keypair = _FragList([raw_private_key, raw_public_key]) + + self.encode_public(public_key, f_priv) + f_priv.put_sshstr(f_keypair) + + +_KEY_FORMATS = { + _SSH_RSA: _SSHFormatRSA(), + _SSH_DSA: _SSHFormatDSA(), + _SSH_ED25519: _SSHFormatEd25519(), + _ECDSA_NISTP256: _SSHFormatECDSA(b"nistp256", ec.SECP256R1()), + _ECDSA_NISTP384: _SSHFormatECDSA(b"nistp384", ec.SECP384R1()), + _ECDSA_NISTP521: _SSHFormatECDSA(b"nistp521", ec.SECP521R1()), +} + + +def _lookup_kformat(key_type): + """Return valid format or throw error""" + if not isinstance(key_type, bytes): + key_type = memoryview(key_type).tobytes() + if key_type in _KEY_FORMATS: + return _KEY_FORMATS[key_type] + raise UnsupportedAlgorithm("Unsupported key type: %r" % key_type) + + +def load_ssh_private_key(data, password, backend=None): + """Load private key from OpenSSH custom encoding.""" + utils._check_byteslike("data", data) + backend = _get_backend(backend) + if password is not None: + utils._check_bytes("password", password) + + m = _PEM_RC.search(data) + if not m: + raise ValueError("Not OpenSSH private key format") + p1 = m.start(1) + p2 = m.end(1) + data = binascii.a2b_base64(memoryview(data)[p1:p2]) + if not data.startswith(_SK_MAGIC): + raise ValueError("Not OpenSSH private key format") + data = memoryview(data)[len(_SK_MAGIC) :] + + # parse header + ciphername, data = _get_sshstr(data) + kdfname, data = _get_sshstr(data) + kdfoptions, data = _get_sshstr(data) + nkeys, data = _get_u32(data) + if nkeys != 1: + raise ValueError("Only one key supported") + + # load public key data + pubdata, data = _get_sshstr(data) + pub_key_type, pubdata = _get_sshstr(pubdata) + kformat = _lookup_kformat(pub_key_type) + 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 = ciphername.tobytes() + if ciphername not in _SSH_CIPHERS: + raise UnsupportedAlgorithm("Unsupported cipher: %r" % ciphername) + if kdfname != _BCRYPT: + raise UnsupportedAlgorithm("Unsupported KDF: %r" % kdfname) + blklen = _SSH_CIPHERS[ciphername][3] + _check_block_size(edata, blklen) + salt, kbuf = _get_sshstr(kdfoptions) + rounds, kbuf = _get_u32(kbuf) + _check_empty(kbuf) + ciph = _init_cipher( + ciphername, password, salt.tobytes(), rounds, backend + ) + edata = memoryview(ciph.decryptor().update(edata)) + else: + blklen = 8 + _check_block_size(edata, blklen) + ck1, edata = _get_u32(edata) + ck2, edata = _get_u32(edata) + if ck1 != ck2: + raise ValueError("Corrupt data: broken checksum") + + # load per-key struct + key_type, edata = _get_sshstr(edata) + if key_type != pub_key_type: + raise ValueError("Corrupt data: key type mismatch") + private_key, edata = kformat.load_private(edata, pubfields, backend) + comment, edata = _get_sshstr(edata) + + # yes, SSH does padding check *after* all other parsing is done. + # need to follow as it writes zero-byte padding too. + if edata != _PADDING[: len(edata)]: + raise ValueError("Corrupt data: invalid padding") + + return private_key + + +def serialize_ssh_private_key(private_key, password=None): + """Serialize private key with OpenSSH custom encoding.""" + if password is not None: + utils._check_bytes("password", password) + if password and len(password) > _MAX_PASSWORD: + raise ValueError( + "Passwords longer than 72 bytes are not supported by " + "OpenSSH private key format" + ) + + if isinstance(private_key, ec.EllipticCurvePrivateKey): + key_type = _ecdsa_key_type(private_key.public_key()) + elif isinstance(private_key, rsa.RSAPrivateKey): + key_type = _SSH_RSA + elif isinstance(private_key, dsa.DSAPrivateKey): + key_type = _SSH_DSA + elif isinstance(private_key, ed25519.Ed25519PrivateKey): + key_type = _SSH_ED25519 + else: + raise ValueError("Unsupported key type") + kformat = _lookup_kformat(key_type) + + # setup parameters + f_kdfoptions = _FragList() + if password: + ciphername = _DEFAULT_CIPHER + blklen = _SSH_CIPHERS[ciphername][3] + kdfname = _BCRYPT + rounds = _DEFAULT_ROUNDS + salt = os.urandom(16) + f_kdfoptions.put_sshstr(salt) + f_kdfoptions.put_u32(rounds) + backend = _get_backend(None) + ciph = _init_cipher(ciphername, password, salt, rounds, backend) + else: + ciphername = kdfname = _NONE + blklen = 8 + ciph = None + nkeys = 1 + checkval = os.urandom(4) + comment = b"" + + # encode public and private parts together + f_public_key = _FragList() + f_public_key.put_sshstr(key_type) + kformat.encode_public(private_key.public_key(), f_public_key) + + f_secrets = _FragList([checkval, checkval]) + f_secrets.put_sshstr(key_type) + kformat.encode_private(private_key, f_secrets) + f_secrets.put_sshstr(comment) + f_secrets.put_raw(_PADDING[: blklen - (f_secrets.size() % blklen)]) + + # top-level structure + f_main = _FragList() + f_main.put_raw(_SK_MAGIC) + f_main.put_sshstr(ciphername) + f_main.put_sshstr(kdfname) + f_main.put_sshstr(f_kdfoptions) + f_main.put_u32(nkeys) + f_main.put_sshstr(f_public_key) + f_main.put_sshstr(f_secrets) + + # copy result info bytearray + slen = f_secrets.size() + mlen = f_main.size() + buf = memoryview(bytearray(mlen + blklen)) + f_main.render(buf) + ofs = mlen - slen + + # encrypt in-place + if ciph is not None: + ciph.encryptor().update_into(buf[ofs:mlen], buf[ofs:]) + + txt = _ssh_pem_encode(buf[:mlen]) + buf[ofs:mlen] = bytearray(slen) + return txt + + +def load_ssh_public_key(data, backend=None): + """Load public key from OpenSSH one-line format.""" + backend = _get_backend(backend) + utils._check_byteslike("data", data) + + m = _SSH_PUBKEY_RC.match(data) + if not m: + raise ValueError("Invalid line format") + key_type = orig_key_type = m.group(1) + key_body = m.group(2) + with_cert = False + if _CERT_SUFFIX == key_type[-len(_CERT_SUFFIX) :]: + with_cert = True + key_type = key_type[: -len(_CERT_SUFFIX)] + kformat = _lookup_kformat(key_type) + + try: + data = memoryview(binascii.a2b_base64(key_body)) + except (TypeError, binascii.Error): + raise ValueError("Invalid key format") + + inner_key_type, data = _get_sshstr(data) + if inner_key_type != orig_key_type: + raise ValueError("Invalid key format") + if with_cert: + nonce, data = _get_sshstr(data) + public_key, data = kformat.load_public(key_type, data, backend) + if with_cert: + serial, data = _get_u64(data) + cctype, data = _get_u32(data) + key_id, data = _get_sshstr(data) + principals, data = _get_sshstr(data) + valid_after, data = _get_u64(data) + valid_before, data = _get_u64(data) + crit_options, data = _get_sshstr(data) + extensions, data = _get_sshstr(data) + reserved, data = _get_sshstr(data) + sig_key, data = _get_sshstr(data) + signature, data = _get_sshstr(data) + _check_empty(data) + return public_key + + +def serialize_ssh_public_key(public_key): + """One-line public key format for OpenSSH""" + if isinstance(public_key, ec.EllipticCurvePublicKey): + key_type = _ecdsa_key_type(public_key) + elif isinstance(public_key, rsa.RSAPublicKey): + key_type = _SSH_RSA + elif isinstance(public_key, dsa.DSAPublicKey): + key_type = _SSH_DSA + elif isinstance(public_key, ed25519.Ed25519PublicKey): + key_type = _SSH_ED25519 + else: + raise ValueError("Unsupported key type") + kformat = _lookup_kformat(key_type) + f_pub = _FragList() + f_pub.put_sshstr(key_type) + kformat.encode_public(public_key, f_pub) -def _ssh_write_mpint(value): - data = utils.int_to_bytes(value) - if six.indexbytes(data, 0) & 0x80: - data = b"\x00" + data - return _ssh_write_string(data) + pub = binascii.b2a_base64(f_pub.tobytes()).strip() + return b"".join([key_type, b" ", pub]) diff --git a/src/cryptography/hazmat/primitives/twofactor/hotp.py b/src/cryptography/hazmat/primitives/twofactor/hotp.py index 4ad1bdc2f08d..c00eec0e548b 100644 --- a/src/cryptography/hazmat/primitives/twofactor/hotp.py +++ b/src/cryptography/hazmat/primitives/twofactor/hotp.py @@ -8,9 +8,8 @@ import six -from cryptography.exceptions import ( - UnsupportedAlgorithm, _Reasons -) +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import constant_time, hmac from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512 @@ -19,12 +18,14 @@ class HOTP(object): - def __init__(self, key, length, algorithm, backend, - enforce_key_length=True): + def __init__( + self, key, length, algorithm, backend=None, enforce_key_length=True + ): + backend = _get_backend(backend) if not isinstance(backend, HMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement HMACBackend.", - _Reasons.BACKEND_MISSING_INTERFACE + _Reasons.BACKEND_MISSING_INTERFACE, ) if len(key) < 16 and enforce_key_length is True: @@ -59,10 +60,10 @@ def _dynamic_truncate(self, counter): hmac_value = ctx.finalize() offset = six.indexbytes(hmac_value, len(hmac_value) - 1) & 0b1111 - p = hmac_value[offset:offset + 4] - return struct.unpack(">I", p)[0] & 0x7fffffff + p = hmac_value[offset : offset + 4] + return struct.unpack(">I", p)[0] & 0x7FFFFFFF def get_provisioning_uri(self, account_name, counter, issuer): - return _generate_uri(self, "hotp", account_name, issuer, [ - ("counter", int(counter)), - ]) + return _generate_uri( + self, "hotp", account_name, issuer, [("counter", int(counter))] + ) diff --git a/src/cryptography/hazmat/primitives/twofactor/totp.py b/src/cryptography/hazmat/primitives/twofactor/totp.py index 499f2824a8e9..d59539b3f9db 100644 --- a/src/cryptography/hazmat/primitives/twofactor/totp.py +++ b/src/cryptography/hazmat/primitives/twofactor/totp.py @@ -4,9 +4,8 @@ from __future__ import absolute_import, division, print_function -from cryptography.exceptions import ( - UnsupportedAlgorithm, _Reasons -) +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import constant_time from cryptography.hazmat.primitives.twofactor import InvalidToken @@ -15,12 +14,20 @@ class TOTP(object): - def __init__(self, key, length, algorithm, time_step, backend, - enforce_key_length=True): + def __init__( + self, + key, + length, + algorithm, + time_step, + backend=None, + enforce_key_length=True, + ): + backend = _get_backend(backend) if not isinstance(backend, HMACBackend): raise UnsupportedAlgorithm( "Backend object does not implement HMACBackend.", - _Reasons.BACKEND_MISSING_INTERFACE + _Reasons.BACKEND_MISSING_INTERFACE, ) self._time_step = time_step @@ -35,6 +42,10 @@ def verify(self, totp, time): raise InvalidToken("Supplied TOTP value does not match.") def get_provisioning_uri(self, account_name, issuer): - return _generate_uri(self._hotp, "totp", account_name, issuer, [ - ("period", int(self._time_step)), - ]) + return _generate_uri( + self._hotp, + "totp", + account_name, + issuer, + [("period", int(self._time_step))], + ) diff --git a/src/cryptography/hazmat/primitives/twofactor/utils.py b/src/cryptography/hazmat/primitives/twofactor/utils.py index 0ed8c4c89d57..0afa1ccc04b0 100644 --- a/src/cryptography/hazmat/primitives/twofactor/utils.py +++ b/src/cryptography/hazmat/primitives/twofactor/utils.py @@ -23,8 +23,11 @@ def _generate_uri(hotp, type_name, account_name, issuer, extra_parameters): uriparts = { "type": type_name, - "label": ("%s:%s" % (quote(issuer), quote(account_name)) if issuer - else quote(account_name)), + "label": ( + "%s:%s" % (quote(issuer), quote(account_name)) + if issuer + else quote(account_name) + ), "parameters": urlencode(parameters), } return "otpauth://{type}/{label}?{parameters}".format(**uriparts) diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index cbbae3a79355..bdb3dbf4776f 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -20,22 +20,20 @@ class CryptographyDeprecationWarning(UserWarning): # Several APIs were deprecated with no specific end-of-life date because of the # ubiquity of their use. They should not be removed until we agree on when that # cycle ends. -PersistentlyDeprecated = CryptographyDeprecationWarning -DeprecatedIn21 = CryptographyDeprecationWarning -DeprecatedIn23 = CryptographyDeprecationWarning -DeprecatedIn25 = CryptographyDeprecationWarning +PersistentlyDeprecated2017 = CryptographyDeprecationWarning +PersistentlyDeprecated2019 = CryptographyDeprecationWarning def _check_bytes(name, value): if not isinstance(value, bytes): - raise TypeError("{0} must be bytes".format(name)) + raise TypeError("{} must be bytes".format(name)) def _check_byteslike(name, value): try: memoryview(value) except TypeError: - raise TypeError("{0} must be bytes-like".format(name)) + raise TypeError("{} must be bytes-like".format(name)) def read_only_property(name): @@ -47,6 +45,7 @@ def register_decorator(klass): verify_interface(iface, klass) iface.register(klass) return klass + return register_decorator @@ -56,27 +55,33 @@ def register_decorator(klass): verify_interface(iface, klass) iface.register(klass) return klass + return register_decorator if hasattr(int, "from_bytes"): int_from_bytes = int.from_bytes else: + def int_from_bytes(data, byteorder, signed=False): - assert byteorder == 'big' + assert byteorder == "big" assert not signed return int(binascii.hexlify(data), 16) if hasattr(int, "to_bytes"): + def int_to_bytes(integer, length=None): return integer.to_bytes( - length or (integer.bit_length() + 7) // 8 or 1, 'big' + length or (integer.bit_length() + 7) // 8 or 1, "big" ) + + else: + def int_to_bytes(integer, length=None): - hex_string = '%x' % integer + hex_string = "%x" % integer if length is None: n = len(hex_string) else: @@ -98,7 +103,7 @@ def verify_interface(iface, klass): for method in iface.__abstractmethods__: if not hasattr(klass, method): raise InterfaceNotImplemented( - "{0} is missing a {1!r} method".format(klass, method) + "{} is missing a {!r} method".format(klass, method) ) if isinstance(getattr(iface, method), abc.abstractproperty): # Can't properly verify these yet. @@ -107,19 +112,11 @@ def verify_interface(iface, klass): actual = signature(getattr(klass, method)) if sig != actual: raise InterfaceNotImplemented( - "{0}.{1}'s signature differs from the expected. Expected: " - "{2!r}. Received: {3!r}".format( - klass, method, sig, actual - ) + "{}.{}'s signature differs from the expected. Expected: " + "{!r}. Received: {!r}".format(klass, method, sig, actual) ) -# No longer needed as of 2.2, but retained because we have external consumers -# who use it. -def bit_length(x): - return x.bit_length() - - class _DeprecatedValue(object): def __init__(self, value, message, warning_class): self.value = value @@ -160,7 +157,7 @@ def deprecated(value, module_name, message, warning_class): def cached_property(func): - cached_name = "_cached_{0}".format(func) + cached_name = "_cached_{}".format(func) sentinel = object() def inner(instance): @@ -170,4 +167,5 @@ def inner(instance): result = func(instance) setattr(instance, cached_name, result) return result + return property(inner) diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py index b761e264aaca..69630e4cba8b 100644 --- a/src/cryptography/x509/__init__.py +++ b/src/cryptography/x509/__init__.py @@ -6,39 +6,95 @@ from cryptography.x509 import certificate_transparency from cryptography.x509.base import ( - Certificate, CertificateBuilder, CertificateRevocationList, + AttributeNotFound, + Certificate, + CertificateBuilder, + CertificateRevocationList, CertificateRevocationListBuilder, - CertificateSigningRequest, CertificateSigningRequestBuilder, - InvalidVersion, RevokedCertificate, RevokedCertificateBuilder, - Version, load_der_x509_certificate, load_der_x509_crl, load_der_x509_csr, - load_pem_x509_certificate, load_pem_x509_crl, load_pem_x509_csr, + CertificateSigningRequest, + CertificateSigningRequestBuilder, + InvalidVersion, + RevokedCertificate, + RevokedCertificateBuilder, + Version, + load_der_x509_certificate, + load_der_x509_crl, + load_der_x509_csr, + load_pem_x509_certificate, + load_pem_x509_crl, + load_pem_x509_csr, random_serial_number, ) from cryptography.x509.extensions import ( - AccessDescription, AuthorityInformationAccess, - AuthorityKeyIdentifier, BasicConstraints, CRLDistributionPoints, - CRLNumber, CRLReason, CertificateIssuer, CertificatePolicies, - DeltaCRLIndicator, DistributionPoint, DuplicateExtension, ExtendedKeyUsage, - Extension, ExtensionNotFound, ExtensionType, Extensions, FreshestCRL, - GeneralNames, InhibitAnyPolicy, InvalidityDate, IssuerAlternativeName, - IssuingDistributionPoint, KeyUsage, NameConstraints, NoticeReference, - OCSPNoCheck, OCSPNonce, PolicyConstraints, PolicyInformation, - PrecertPoison, PrecertificateSignedCertificateTimestamps, ReasonFlags, - SubjectAlternativeName, SubjectKeyIdentifier, TLSFeature, TLSFeatureType, - UnrecognizedExtension, UserNotice + AccessDescription, + AuthorityInformationAccess, + AuthorityKeyIdentifier, + BasicConstraints, + CRLDistributionPoints, + CRLNumber, + CRLReason, + CertificateIssuer, + CertificatePolicies, + DeltaCRLIndicator, + DistributionPoint, + DuplicateExtension, + ExtendedKeyUsage, + Extension, + ExtensionNotFound, + ExtensionType, + Extensions, + FreshestCRL, + GeneralNames, + InhibitAnyPolicy, + InvalidityDate, + IssuerAlternativeName, + IssuingDistributionPoint, + KeyUsage, + NameConstraints, + NoticeReference, + OCSPNoCheck, + OCSPNonce, + PolicyConstraints, + PolicyInformation, + PrecertPoison, + PrecertificateSignedCertificateTimestamps, + ReasonFlags, + SignedCertificateTimestamps, + SubjectAlternativeName, + SubjectInformationAccess, + SubjectKeyIdentifier, + TLSFeature, + TLSFeatureType, + UnrecognizedExtension, + UserNotice, ) from cryptography.x509.general_name import ( - DNSName, DirectoryName, GeneralName, IPAddress, OtherName, RFC822Name, - RegisteredID, UniformResourceIdentifier, UnsupportedGeneralNameType, - _GENERAL_NAMES + DNSName, + DirectoryName, + GeneralName, + IPAddress, + OtherName, + RFC822Name, + RegisteredID, + UniformResourceIdentifier, + UnsupportedGeneralNameType, + _GENERAL_NAMES, ) from cryptography.x509.name import ( - Name, NameAttribute, RelativeDistinguishedName + Name, + NameAttribute, + RelativeDistinguishedName, ) from cryptography.x509.oid import ( - AuthorityInformationAccessOID, CRLEntryExtensionOID, - CertificatePoliciesOID, ExtendedKeyUsageOID, ExtensionOID, NameOID, - ObjectIdentifier, SignatureAlgorithmOID, _SIG_OIDS_TO_HASH + AuthorityInformationAccessOID, + CRLEntryExtensionOID, + CertificatePoliciesOID, + ExtendedKeyUsageOID, + ExtensionOID, + NameOID, + ObjectIdentifier, + SignatureAlgorithmOID, + _SIG_OIDS_TO_HASH, ) @@ -120,6 +176,7 @@ "load_pem_x509_crl", "load_der_x509_crl", "random_serial_number", + "AttributeNotFound", "InvalidVersion", "DeltaCRLIndicator", "DuplicateExtension", @@ -142,6 +199,7 @@ "CRLNumber", "KeyUsage", "AuthorityInformationAccess", + "SubjectInformationAccess", "AccessDescription", "CertificatePolicies", "PolicyInformation", @@ -186,4 +244,5 @@ "PrecertificateSignedCertificateTimestamps", "PrecertPoison", "OCSPNonce", + "SignedCertificateTimestamps", ] diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index 63c2e3c6343e..f3bc872b9456 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -12,19 +12,40 @@ import six from cryptography import utils -from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa +from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.primitives.asymmetric import ( + dsa, + ec, + ed25519, + ed448, + rsa, +) from cryptography.x509.extensions import Extension, ExtensionType from cryptography.x509.name import Name +from cryptography.x509.oid import ObjectIdentifier _EARLIEST_UTC_TIME = datetime.datetime(1950, 1, 1) +class AttributeNotFound(Exception): + def __init__(self, msg, oid): + super(AttributeNotFound, self).__init__(msg) + self.oid = oid + + def _reject_duplicate_extension(extension, extensions): # This is quadratic in the number of extensions for e in extensions: if e.oid == extension.oid: - raise ValueError('This extension has already been set.') + raise ValueError("This extension has already been set.") + + +def _reject_duplicate_attribute(oid, attributes): + # This is quadratic in the number of attributes + for attr_oid, _ in attributes: + if attr_oid == oid: + raise ValueError("This attribute has already been set.") def _convert_to_naive_utc_time(time): @@ -46,27 +67,33 @@ class Version(Enum): v3 = 2 -def load_pem_x509_certificate(data, backend): +def load_pem_x509_certificate(data, backend=None): + backend = _get_backend(backend) return backend.load_pem_x509_certificate(data) -def load_der_x509_certificate(data, backend): +def load_der_x509_certificate(data, backend=None): + backend = _get_backend(backend) return backend.load_der_x509_certificate(data) -def load_pem_x509_csr(data, backend): +def load_pem_x509_csr(data, backend=None): + backend = _get_backend(backend) return backend.load_pem_x509_csr(data) -def load_der_x509_csr(data, backend): +def load_der_x509_csr(data, backend=None): + backend = _get_backend(backend) return backend.load_der_x509_csr(data) -def load_pem_x509_crl(data, backend): +def load_pem_x509_crl(data, backend=None): + backend = _get_backend(backend) return backend.load_pem_x509_crl(data) -def load_der_x509_crl(data, backend): +def load_der_x509_crl(data, backend=None): + backend = _get_backend(backend) return backend.load_der_x509_crl(data) @@ -365,6 +392,12 @@ def is_signature_valid(self): Verifies signature of signing request. """ + @abc.abstractproperty + def get_attribute_for_oid(self): + """ + Get the attribute value for a given OID. + """ + @six.add_metaclass(abc.ABCMeta) class RevokedCertificate(object): @@ -388,22 +421,25 @@ def extensions(self): class CertificateSigningRequestBuilder(object): - def __init__(self, subject_name=None, extensions=[]): + def __init__(self, subject_name=None, extensions=[], attributes=[]): """ Creates an empty X.509 certificate request (v1). """ self._subject_name = subject_name self._extensions = extensions + self._attributes = attributes def subject_name(self, name): """ Sets the certificate requestor's distinguished name. """ if not isinstance(name, Name): - raise TypeError('Expecting x509.Name object.') + raise TypeError("Expecting x509.Name object.") if self._subject_name is not None: - raise ValueError('The subject name may only be set once.') - return CertificateSigningRequestBuilder(name, self._extensions) + raise ValueError("The subject name may only be set once.") + return CertificateSigningRequestBuilder( + name, self._extensions, self._attributes + ) def add_extension(self, extension, critical): """ @@ -416,22 +452,50 @@ def add_extension(self, extension, critical): _reject_duplicate_extension(extension, self._extensions) return CertificateSigningRequestBuilder( - self._subject_name, self._extensions + [extension] + self._subject_name, + self._extensions + [extension], + self._attributes, ) - def sign(self, private_key, algorithm, backend): + def add_attribute(self, oid, value): + """ + Adds an X.509 attribute with an OID and associated value. + """ + if not isinstance(oid, ObjectIdentifier): + raise TypeError("oid must be an ObjectIdentifier") + + if not isinstance(value, bytes): + raise TypeError("value must be bytes") + + _reject_duplicate_attribute(oid, self._attributes) + + return CertificateSigningRequestBuilder( + self._subject_name, + self._extensions, + self._attributes + [(oid, value)], + ) + + def sign(self, private_key, algorithm, backend=None): """ Signs the request using the requestor's private key. """ + backend = _get_backend(backend) if self._subject_name is None: raise ValueError("A CertificateSigningRequest must have a subject") return backend.create_x509_csr(self, private_key, algorithm) class CertificateBuilder(object): - def __init__(self, issuer_name=None, subject_name=None, - public_key=None, serial_number=None, not_valid_before=None, - not_valid_after=None, extensions=[]): + def __init__( + self, + issuer_name=None, + subject_name=None, + public_key=None, + serial_number=None, + not_valid_before=None, + not_valid_after=None, + extensions=[], + ): self._version = Version.v3 self._issuer_name = issuer_name self._subject_name = subject_name @@ -446,13 +510,17 @@ def issuer_name(self, name): Sets the CA's distinguished name. """ if not isinstance(name, Name): - raise TypeError('Expecting x509.Name object.') + raise TypeError("Expecting x509.Name object.") if self._issuer_name is not None: - raise ValueError('The issuer name may only be set once.') + raise ValueError("The issuer name may only be set once.") return CertificateBuilder( - name, self._subject_name, self._public_key, - self._serial_number, self._not_valid_before, - self._not_valid_after, self._extensions + name, + self._subject_name, + self._public_key, + self._serial_number, + self._not_valid_before, + self._not_valid_after, + self._extensions, ) def subject_name(self, name): @@ -460,29 +528,48 @@ def subject_name(self, name): Sets the requestor's distinguished name. """ if not isinstance(name, Name): - raise TypeError('Expecting x509.Name object.') + raise TypeError("Expecting x509.Name object.") if self._subject_name is not None: - raise ValueError('The subject name may only be set once.') + raise ValueError("The subject name may only be set once.") return CertificateBuilder( - self._issuer_name, name, self._public_key, - self._serial_number, self._not_valid_before, - self._not_valid_after, self._extensions + self._issuer_name, + name, + self._public_key, + self._serial_number, + self._not_valid_before, + self._not_valid_after, + self._extensions, ) def public_key(self, key): """ Sets the requestor's public key (as found in the signing request). """ - if not isinstance(key, (dsa.DSAPublicKey, rsa.RSAPublicKey, - ec.EllipticCurvePublicKey)): - raise TypeError('Expecting one of DSAPublicKey, RSAPublicKey,' - ' or EllipticCurvePublicKey.') + if not isinstance( + key, + ( + dsa.DSAPublicKey, + rsa.RSAPublicKey, + ec.EllipticCurvePublicKey, + ed25519.Ed25519PublicKey, + ed448.Ed448PublicKey, + ), + ): + raise TypeError( + "Expecting one of DSAPublicKey, RSAPublicKey," + " EllipticCurvePublicKey, Ed25519PublicKey or" + " Ed448PublicKey." + ) if self._public_key is not None: - raise ValueError('The public key may only be set once.') + raise ValueError("The public key may only be set once.") return CertificateBuilder( - self._issuer_name, self._subject_name, key, - self._serial_number, self._not_valid_before, - self._not_valid_after, self._extensions + self._issuer_name, + self._subject_name, + key, + self._serial_number, + self._not_valid_before, + self._not_valid_after, + self._extensions, ) def serial_number(self, number): @@ -490,21 +577,26 @@ def serial_number(self, number): Sets the certificate serial number. """ if not isinstance(number, six.integer_types): - raise TypeError('Serial number must be of integral type.') + raise TypeError("Serial number must be of integral type.") if self._serial_number is not None: - raise ValueError('The serial number may only be set once.') + raise ValueError("The serial number may only be set once.") if number <= 0: - raise ValueError('The serial number should be positive.') + raise ValueError("The serial number should be positive.") # ASN.1 integers are always signed, so most significant bit must be # zero. if number.bit_length() >= 160: # As defined in RFC 5280 - raise ValueError('The serial number should not be more than 159 ' - 'bits.') + raise ValueError( + "The serial number should not be more than 159 " "bits." + ) return CertificateBuilder( - self._issuer_name, self._subject_name, - self._public_key, number, self._not_valid_before, - self._not_valid_after, self._extensions + self._issuer_name, + self._subject_name, + self._public_key, + number, + self._not_valid_before, + self._not_valid_after, + self._extensions, ) def not_valid_before(self, time): @@ -512,22 +604,28 @@ def not_valid_before(self, time): Sets the certificate activation time. """ if not isinstance(time, datetime.datetime): - raise TypeError('Expecting datetime object.') + raise TypeError("Expecting datetime object.") if self._not_valid_before is not None: - raise ValueError('The not valid before may only be set once.') + raise ValueError("The not valid before may only be set once.") time = _convert_to_naive_utc_time(time) if time < _EARLIEST_UTC_TIME: - raise ValueError('The not valid before date must be on or after' - ' 1950 January 1).') + raise ValueError( + "The not valid before date must be on or after" + " 1950 January 1)." + ) if self._not_valid_after is not None and time > self._not_valid_after: raise ValueError( - 'The not valid before date must be before the not valid after ' - 'date.' + "The not valid before date must be before the not valid after " + "date." ) return CertificateBuilder( - self._issuer_name, self._subject_name, - self._public_key, self._serial_number, time, - self._not_valid_after, self._extensions + self._issuer_name, + self._subject_name, + self._public_key, + self._serial_number, + time, + self._not_valid_after, + self._extensions, ) def not_valid_after(self, time): @@ -535,23 +633,31 @@ def not_valid_after(self, time): Sets the certificate expiration time. """ if not isinstance(time, datetime.datetime): - raise TypeError('Expecting datetime object.') + raise TypeError("Expecting datetime object.") if self._not_valid_after is not None: - raise ValueError('The not valid after may only be set once.') + raise ValueError("The not valid after may only be set once.") time = _convert_to_naive_utc_time(time) if time < _EARLIEST_UTC_TIME: - raise ValueError('The not valid after date must be on or after' - ' 1950 January 1.') - if (self._not_valid_before is not None and - time < self._not_valid_before): raise ValueError( - 'The not valid after date must be after the not valid before ' - 'date.' + "The not valid after date must be on or after" + " 1950 January 1." + ) + if ( + self._not_valid_before is not None + and time < self._not_valid_before + ): + raise ValueError( + "The not valid after date must be after the not valid before " + "date." ) return CertificateBuilder( - self._issuer_name, self._subject_name, - self._public_key, self._serial_number, self._not_valid_before, - time, self._extensions + self._issuer_name, + self._subject_name, + self._public_key, + self._serial_number, + self._not_valid_before, + time, + self._extensions, ) def add_extension(self, extension, critical): @@ -565,15 +671,20 @@ def add_extension(self, extension, critical): _reject_duplicate_extension(extension, self._extensions) return CertificateBuilder( - self._issuer_name, self._subject_name, - self._public_key, self._serial_number, self._not_valid_before, - self._not_valid_after, self._extensions + [extension] + self._issuer_name, + self._subject_name, + self._public_key, + self._serial_number, + self._not_valid_before, + self._not_valid_after, + self._extensions + [extension], ) - def sign(self, private_key, algorithm, backend): + def sign(self, private_key, algorithm, backend=None): """ Signs the certificate using the CA's private key. """ + backend = _get_backend(backend) if self._subject_name is None: raise ValueError("A certificate must have a subject name") @@ -596,8 +707,14 @@ def sign(self, private_key, algorithm, backend): class CertificateRevocationListBuilder(object): - def __init__(self, issuer_name=None, last_update=None, next_update=None, - extensions=[], revoked_certificates=[]): + def __init__( + self, + issuer_name=None, + last_update=None, + next_update=None, + extensions=[], + revoked_certificates=[], + ): self._issuer_name = issuer_name self._last_update = last_update self._next_update = next_update @@ -606,48 +723,59 @@ def __init__(self, issuer_name=None, last_update=None, next_update=None, def issuer_name(self, issuer_name): if not isinstance(issuer_name, Name): - raise TypeError('Expecting x509.Name object.') + raise TypeError("Expecting x509.Name object.") if self._issuer_name is not None: - raise ValueError('The issuer name may only be set once.') + raise ValueError("The issuer name may only be set once.") return CertificateRevocationListBuilder( - issuer_name, self._last_update, self._next_update, - self._extensions, self._revoked_certificates + issuer_name, + self._last_update, + self._next_update, + self._extensions, + self._revoked_certificates, ) def last_update(self, last_update): if not isinstance(last_update, datetime.datetime): - raise TypeError('Expecting datetime object.') + raise TypeError("Expecting datetime object.") if self._last_update is not None: - raise ValueError('Last update may only be set once.') + raise ValueError("Last update may only be set once.") last_update = _convert_to_naive_utc_time(last_update) if last_update < _EARLIEST_UTC_TIME: - raise ValueError('The last update date must be on or after' - ' 1950 January 1.') + raise ValueError( + "The last update date must be on or after" " 1950 January 1." + ) if self._next_update is not None and last_update > self._next_update: raise ValueError( - 'The last update date must be before the next update date.' + "The last update date must be before the next update date." ) return CertificateRevocationListBuilder( - self._issuer_name, last_update, self._next_update, - self._extensions, self._revoked_certificates + self._issuer_name, + last_update, + self._next_update, + self._extensions, + self._revoked_certificates, ) def next_update(self, next_update): if not isinstance(next_update, datetime.datetime): - raise TypeError('Expecting datetime object.') + raise TypeError("Expecting datetime object.") if self._next_update is not None: - raise ValueError('Last update may only be set once.') + raise ValueError("Last update may only be set once.") next_update = _convert_to_naive_utc_time(next_update) if next_update < _EARLIEST_UTC_TIME: - raise ValueError('The last update date must be on or after' - ' 1950 January 1.') + raise ValueError( + "The last update date must be on or after" " 1950 January 1." + ) if self._last_update is not None and next_update < self._last_update: raise ValueError( - 'The next update date must be after the last update date.' + "The next update date must be after the last update date." ) return CertificateRevocationListBuilder( - self._issuer_name, self._last_update, next_update, - self._extensions, self._revoked_certificates + self._issuer_name, + self._last_update, + next_update, + self._extensions, + self._revoked_certificates, ) def add_extension(self, extension, critical): @@ -660,8 +788,11 @@ def add_extension(self, extension, critical): extension = Extension(extension.oid, critical, extension) _reject_duplicate_extension(extension, self._extensions) return CertificateRevocationListBuilder( - self._issuer_name, self._last_update, self._next_update, - self._extensions + [extension], self._revoked_certificates + self._issuer_name, + self._last_update, + self._next_update, + self._extensions + [extension], + self._revoked_certificates, ) def add_revoked_certificate(self, revoked_certificate): @@ -672,12 +803,15 @@ def add_revoked_certificate(self, revoked_certificate): raise TypeError("Must be an instance of RevokedCertificate") return CertificateRevocationListBuilder( - self._issuer_name, self._last_update, - self._next_update, self._extensions, - self._revoked_certificates + [revoked_certificate] + self._issuer_name, + self._last_update, + self._next_update, + self._extensions, + self._revoked_certificates + [revoked_certificate], ) - def sign(self, private_key, algorithm, backend): + def sign(self, private_key, algorithm, backend=None): + backend = _get_backend(backend) if self._issuer_name is None: raise ValueError("A CRL must have an issuer name") @@ -691,38 +825,41 @@ def sign(self, private_key, algorithm, backend): class RevokedCertificateBuilder(object): - def __init__(self, serial_number=None, revocation_date=None, - extensions=[]): + def __init__( + self, serial_number=None, revocation_date=None, extensions=[] + ): self._serial_number = serial_number self._revocation_date = revocation_date self._extensions = extensions def serial_number(self, number): if not isinstance(number, six.integer_types): - raise TypeError('Serial number must be of integral type.') + raise TypeError("Serial number must be of integral type.") if self._serial_number is not None: - raise ValueError('The serial number may only be set once.') + raise ValueError("The serial number may only be set once.") if number <= 0: - raise ValueError('The serial number should be positive') + raise ValueError("The serial number should be positive") # ASN.1 integers are always signed, so most significant bit must be # zero. if number.bit_length() >= 160: # As defined in RFC 5280 - raise ValueError('The serial number should not be more than 159 ' - 'bits.') + raise ValueError( + "The serial number should not be more than 159 " "bits." + ) return RevokedCertificateBuilder( number, self._revocation_date, self._extensions ) def revocation_date(self, time): if not isinstance(time, datetime.datetime): - raise TypeError('Expecting datetime object.') + raise TypeError("Expecting datetime object.") if self._revocation_date is not None: - raise ValueError('The revocation date may only be set once.') + raise ValueError("The revocation date may only be set once.") time = _convert_to_naive_utc_time(time) if time < _EARLIEST_UTC_TIME: - raise ValueError('The revocation date must be on or after' - ' 1950 January 1.') + raise ValueError( + "The revocation date must be on or after" " 1950 January 1." + ) return RevokedCertificateBuilder( self._serial_number, time, self._extensions ) @@ -734,11 +871,13 @@ def add_extension(self, extension, critical): extension = Extension(extension.oid, critical, extension) _reject_duplicate_extension(extension, self._extensions) return RevokedCertificateBuilder( - self._serial_number, self._revocation_date, - self._extensions + [extension] + self._serial_number, + self._revocation_date, + self._extensions + [extension], ) - def build(self, backend): + def build(self, backend=None): + backend = _get_backend(backend) if self._serial_number is None: raise ValueError("A revoked certificate must have a serial number") if self._revocation_date is None: diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 88afa3100774..130ba69b8769 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -10,21 +10,28 @@ import ipaddress from enum import Enum -from asn1crypto.keys import PublicKeyInfo - import six from cryptography import utils +from cryptography.hazmat._der import ( + BIT_STRING, + DERReader, + OBJECT_IDENTIFIER, + SEQUENCE, +) from cryptography.hazmat.primitives import constant_time, serialization from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey from cryptography.x509.certificate_transparency import ( - SignedCertificateTimestamp + SignedCertificateTimestamp, ) from cryptography.x509.general_name import GeneralName, IPAddress, OtherName from cryptography.x509.name import RelativeDistinguishedName from cryptography.x509.oid import ( - CRLEntryExtensionOID, ExtensionOID, OCSPExtensionOID, ObjectIdentifier, + CRLEntryExtensionOID, + ExtensionOID, + OCSPExtensionOID, + ObjectIdentifier, ) @@ -37,20 +44,50 @@ def _key_identifier_from_public_key(public_key): elif isinstance(public_key, EllipticCurvePublicKey): data = public_key.public_bytes( serialization.Encoding.X962, - serialization.PublicFormat.UncompressedPoint + serialization.PublicFormat.UncompressedPoint, ) else: # This is a very slow way to do this. serialized = public_key.public_bytes( serialization.Encoding.DER, - serialization.PublicFormat.SubjectPublicKeyInfo + serialization.PublicFormat.SubjectPublicKeyInfo, ) - data = bytes(PublicKeyInfo.load(serialized)['public_key']) + reader = DERReader(serialized) + with reader.read_single_element(SEQUENCE) as public_key_info: + algorithm = public_key_info.read_element(SEQUENCE) + public_key = public_key_info.read_element(BIT_STRING) + + # Double-check the algorithm structure. + with algorithm: + algorithm.read_element(OBJECT_IDENTIFIER) + if not algorithm.is_empty(): + # Skip the optional parameters field. + algorithm.read_any_element() + + # BIT STRING contents begin with the number of padding bytes added. It + # must be zero for SubjectPublicKeyInfo structures. + if public_key.read_byte() != 0: + raise ValueError("Invalid public key encoding") + + data = public_key.data return hashlib.sha1(data).digest() +def _make_sequence_methods(field_name): + def len_method(self): + return len(getattr(self, field_name)) + + def iter_method(self): + return iter(getattr(self, field_name)) + + def getitem_method(self, idx): + return getattr(self, field_name)[idx] + + return len_method, iter_method, getitem_method + + class DuplicateExtension(Exception): def __init__(self, msg, oid): super(DuplicateExtension, self).__init__(msg) @@ -81,7 +118,7 @@ def get_extension_for_oid(self, oid): if ext.oid == oid: return ext - raise ExtensionNotFound("No {0} extension was found".format(oid), oid) + raise ExtensionNotFound("No {} extension was found".format(oid), oid) def get_extension_for_class(self, extclass): if extclass is UnrecognizedExtension: @@ -96,22 +133,13 @@ def get_extension_for_class(self, extclass): return ext raise ExtensionNotFound( - "No {0} extension was found".format(extclass), extclass.oid + "No {} extension was found".format(extclass), extclass.oid ) - def __iter__(self): - return iter(self._extensions) - - def __len__(self): - return len(self._extensions) - - def __getitem__(self, idx): - return self._extensions[idx] + __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions") def __repr__(self): - return ( - "".format(self._extensions) - ) + return "".format(self._extensions) @utils.register_interface(ExtensionType) @@ -137,7 +165,7 @@ def __hash__(self): return hash(self.crl_number) def __repr__(self): - return "".format(self.crl_number) + return "".format(self.crl_number) crl_number = utils.read_only_property("_crl_number") @@ -146,8 +174,12 @@ def __repr__(self): class AuthorityKeyIdentifier(object): oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER - def __init__(self, key_identifier, authority_cert_issuer, - authority_cert_serial_number): + def __init__( + self, + key_identifier, + authority_cert_issuer, + authority_cert_serial_number, + ): if (authority_cert_issuer is None) != ( authority_cert_serial_number is None ): @@ -169,9 +201,7 @@ def __init__(self, key_identifier, authority_cert_issuer, if authority_cert_serial_number is not None and not isinstance( authority_cert_serial_number, six.integer_types ): - raise TypeError( - "authority_cert_serial_number must be an integer" - ) + raise TypeError("authority_cert_serial_number must be an integer") self._key_identifier = key_identifier self._authority_cert_issuer = authority_cert_issuer @@ -183,15 +213,15 @@ def from_issuer_public_key(cls, public_key): return cls( key_identifier=digest, authority_cert_issuer=None, - authority_cert_serial_number=None + authority_cert_serial_number=None, ) @classmethod def from_issuer_subject_key_identifier(cls, ski): return cls( - key_identifier=ski.value.digest, + key_identifier=ski.digest, authority_cert_issuer=None, - authority_cert_serial_number=None + authority_cert_serial_number=None, ) def __repr__(self): @@ -207,10 +237,10 @@ def __eq__(self, other): return NotImplemented return ( - self.key_identifier == other.key_identifier and - self.authority_cert_issuer == other.authority_cert_issuer and - self.authority_cert_serial_number == - other.authority_cert_serial_number + self.key_identifier == other.key_identifier + and self.authority_cert_issuer == other.authority_cert_issuer + and self.authority_cert_serial_number + == other.authority_cert_serial_number ) def __ne__(self, other): @@ -221,9 +251,9 @@ def __hash__(self): aci = None else: aci = tuple(self.authority_cert_issuer) - return hash(( - self.key_identifier, aci, self.authority_cert_serial_number - )) + return hash( + (self.key_identifier, aci, self.authority_cert_serial_number) + ) key_identifier = utils.read_only_property("_key_identifier") authority_cert_issuer = utils.read_only_property("_authority_cert_issuer") @@ -275,14 +305,10 @@ def __init__(self, descriptions): self._descriptions = descriptions - def __iter__(self): - return iter(self._descriptions) - - def __len__(self): - return len(self._descriptions) + __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") def __repr__(self): - return "".format(self._descriptions) + return "".format(self._descriptions) def __eq__(self, other): if not isinstance(other, AuthorityInformationAccess): @@ -293,8 +319,37 @@ def __eq__(self, other): def __ne__(self, other): return not self == other - def __getitem__(self, idx): - return self._descriptions[idx] + def __hash__(self): + return hash(tuple(self._descriptions)) + + +@utils.register_interface(ExtensionType) +class SubjectInformationAccess(object): + oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS + + def __init__(self, descriptions): + descriptions = list(descriptions) + if not all(isinstance(x, AccessDescription) for x in descriptions): + raise TypeError( + "Every item in the descriptions list must be an " + "AccessDescription" + ) + + self._descriptions = descriptions + + __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") + + def __repr__(self): + return "".format(self._descriptions) + + def __eq__(self, other): + if not isinstance(other, SubjectInformationAccess): + return NotImplemented + + return self._descriptions == other._descriptions + + def __ne__(self, other): + return not self == other def __hash__(self): return hash(tuple(self._descriptions)) @@ -322,8 +377,8 @@ def __eq__(self, other): return NotImplemented return ( - self.access_method == other.access_method and - self.access_location == other.access_location + self.access_method == other.access_method + and self.access_location == other.access_location ) def __ne__(self, other): @@ -347,9 +402,8 @@ def __init__(self, ca, path_length): if path_length is not None and not ca: raise ValueError("path_length must be None when ca is False") - if ( - path_length is not None and - (not isinstance(path_length, six.integer_types) or path_length < 0) + if path_length is not None and ( + not isinstance(path_length, six.integer_types) or path_length < 0 ): raise TypeError( "path_length must be a non-negative integer or None" @@ -362,8 +416,9 @@ def __init__(self, ca, path_length): path_length = utils.read_only_property("_path_length") def __repr__(self): - return ("").format(self) + return ( + "" + ).format(self) def __eq__(self, other): if not isinstance(other, BasicConstraints): @@ -422,14 +477,12 @@ def __init__(self, distribution_points): self._distribution_points = distribution_points - def __iter__(self): - return iter(self._distribution_points) - - def __len__(self): - return len(self._distribution_points) + __len__, __iter__, __getitem__ = _make_sequence_methods( + "_distribution_points" + ) def __repr__(self): - return "".format(self._distribution_points) + return "".format(self._distribution_points) def __eq__(self, other): if not isinstance(other, CRLDistributionPoints): @@ -440,9 +493,6 @@ def __eq__(self, other): def __ne__(self, other): return not self == other - def __getitem__(self, idx): - return self._distribution_points[idx] - def __hash__(self): return hash(tuple(self._distribution_points)) @@ -463,14 +513,12 @@ def __init__(self, distribution_points): self._distribution_points = distribution_points - def __iter__(self): - return iter(self._distribution_points) - - def __len__(self): - return len(self._distribution_points) + __len__, __iter__, __getitem__ = _make_sequence_methods( + "_distribution_points" + ) def __repr__(self): - return "".format(self._distribution_points) + return "".format(self._distribution_points) def __eq__(self, other): if not isinstance(other, FreshestCRL): @@ -481,9 +529,6 @@ def __eq__(self, other): def __ne__(self, other): return not self == other - def __getitem__(self, idx): - return self._distribution_points[idx] - def __hash__(self): return hash(tuple(self._distribution_points)) @@ -516,14 +561,15 @@ def __init__(self, full_name, relative_name, reasons, crl_issuer): "crl_issuer must be None or a list of general names" ) - if reasons and (not isinstance(reasons, frozenset) or not all( - isinstance(x, ReasonFlags) for x in reasons - )): + if reasons and ( + not isinstance(reasons, frozenset) + or not all(isinstance(x, ReasonFlags) for x in reasons) + ): raise TypeError("reasons must be None or frozenset of ReasonFlags") if reasons and ( - ReasonFlags.unspecified in reasons or - ReasonFlags.remove_from_crl in reasons + ReasonFlags.unspecified in reasons + or ReasonFlags.remove_from_crl in reasons ): raise ValueError( "unspecified and remove_from_crl are not valid reasons in a " @@ -544,8 +590,8 @@ def __init__(self, full_name, relative_name, reasons, crl_issuer): def __repr__(self): return ( "" - .format(self) + "tive_name}, reasons={0.reasons}, " + "crl_issuer={0.crl_issuer})>".format(self) ) def __eq__(self, other): @@ -553,10 +599,10 @@ def __eq__(self, other): return NotImplemented return ( - self.full_name == other.full_name and - self.relative_name == other.relative_name and - self.reasons == other.reasons and - self.crl_issuer == other.crl_issuer + self.full_name == other.full_name + and self.relative_name == other.relative_name + and self.reasons == other.reasons + and self.crl_issuer == other.crl_issuer ) def __ne__(self, other): @@ -635,8 +681,8 @@ def __eq__(self, other): return NotImplemented return ( - self.require_explicit_policy == other.require_explicit_policy and - self.inhibit_policy_mapping == other.inhibit_policy_mapping + self.require_explicit_policy == other.require_explicit_policy + and self.inhibit_policy_mapping == other.inhibit_policy_mapping ) def __ne__(self, other): @@ -669,14 +715,10 @@ def __init__(self, policies): self._policies = policies - def __iter__(self): - return iter(self._policies) - - def __len__(self): - return len(self._policies) + __len__, __iter__, __getitem__ = _make_sequence_methods("_policies") def __repr__(self): - return "".format(self._policies) + return "".format(self._policies) def __eq__(self, other): if not isinstance(other, CertificatePolicies): @@ -687,9 +729,6 @@ def __eq__(self, other): def __ne__(self, other): return not self == other - def __getitem__(self, idx): - return self._policies[idx] - def __hash__(self): return hash(tuple(self._policies)) @@ -704,8 +743,8 @@ def __init__(self, policy_identifier, policy_qualifiers): if policy_qualifiers: policy_qualifiers = list(policy_qualifiers) if not all( - isinstance(x, (six.text_type, UserNotice)) - for x in policy_qualifiers + isinstance(x, (six.text_type, UserNotice)) + for x in policy_qualifiers ): raise TypeError( "policy_qualifiers must be a list of strings and/or " @@ -725,8 +764,8 @@ def __eq__(self, other): return NotImplemented return ( - self.policy_identifier == other.policy_identifier and - self.policy_qualifiers == other.policy_qualifiers + self.policy_identifier == other.policy_identifier + and self.policy_qualifiers == other.policy_qualifiers ) def __ne__(self, other): @@ -767,8 +806,8 @@ def __eq__(self, other): return NotImplemented return ( - self.notice_reference == other.notice_reference and - self.explicit_text == other.explicit_text + self.notice_reference == other.notice_reference + and self.explicit_text == other.explicit_text ) def __ne__(self, other): @@ -786,9 +825,7 @@ def __init__(self, organization, notice_numbers): self._organization = organization notice_numbers = list(notice_numbers) if not all(isinstance(x, int) for x in notice_numbers): - raise TypeError( - "notice_numbers must be a list of integers" - ) + raise TypeError("notice_numbers must be a list of integers") self._notice_numbers = notice_numbers @@ -803,8 +840,8 @@ def __eq__(self, other): return NotImplemented return ( - self.organization == other.organization and - self.notice_numbers == other.notice_numbers + self.organization == other.organization + and self.notice_numbers == other.notice_numbers ) def __ne__(self, other): @@ -830,14 +867,10 @@ def __init__(self, usages): self._usages = usages - def __iter__(self): - return iter(self._usages) - - def __len__(self): - return len(self._usages) + __len__, __iter__, __getitem__ = _make_sequence_methods("_usages") def __repr__(self): - return "".format(self._usages) + return "".format(self._usages) def __eq__(self, other): if not isinstance(other, ExtendedKeyUsage): @@ -856,11 +889,41 @@ def __hash__(self): class OCSPNoCheck(object): oid = ExtensionOID.OCSP_NO_CHECK + def __eq__(self, other): + if not isinstance(other, OCSPNoCheck): + return NotImplemented + + return True + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(OCSPNoCheck) + + def __repr__(self): + return "" + @utils.register_interface(ExtensionType) class PrecertPoison(object): oid = ExtensionOID.PRECERT_POISON + def __eq__(self, other): + if not isinstance(other, PrecertPoison): + return NotImplemented + + return True + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(PrecertPoison) + + def __repr__(self): + return "" + @utils.register_interface(ExtensionType) class TLSFeature(object): @@ -869,8 +932,8 @@ class TLSFeature(object): def __init__(self, features): features = list(features) if ( - not all(isinstance(x, TLSFeatureType) for x in features) or - len(features) == 0 + not all(isinstance(x, TLSFeatureType) for x in features) + or len(features) == 0 ): raise TypeError( "features must be a list of elements from the TLSFeatureType " @@ -879,11 +942,7 @@ def __init__(self, features): self._features = features - def __iter__(self): - return iter(self._features) - - def __len__(self): - return len(self._features) + __len__, __iter__, __getitem__ = _make_sequence_methods("_features") def __repr__(self): return "".format(self) @@ -894,9 +953,6 @@ def __eq__(self, other): return self._features == other._features - def __getitem__(self, idx): - return self._features[idx] - def __ne__(self, other): return not self == other @@ -915,7 +971,7 @@ class TLSFeatureType(Enum): status_request_v2 = 17 -_TLS_FEATURE_TYPE_TO_ENUM = dict((x.value, x) for x in TLSFeatureType) +_TLS_FEATURE_TYPE_TO_ENUM = {x.value: x for x in TLSFeatureType} @utils.register_interface(ExtensionType) @@ -953,9 +1009,18 @@ def __hash__(self): class KeyUsage(object): oid = ExtensionOID.KEY_USAGE - def __init__(self, digital_signature, content_commitment, key_encipherment, - data_encipherment, key_agreement, key_cert_sign, crl_sign, - encipher_only, decipher_only): + def __init__( + self, + digital_signature, + content_commitment, + key_encipherment, + data_encipherment, + key_agreement, + key_cert_sign, + crl_sign, + encipher_only, + decipher_only, + ): if not key_agreement and (encipher_only or decipher_only): raise ValueError( "encipher_only and decipher_only can only be true when " @@ -1003,45 +1068,55 @@ def __repr__(self): encipher_only = self.encipher_only decipher_only = self.decipher_only except ValueError: - encipher_only = None - decipher_only = None - - return ("").format( - self, encipher_only, decipher_only) + # Users found None confusing because even though encipher/decipher + # have no meaning unless key_agreement is true, to construct an + # instance of the class you still need to pass False. + encipher_only = False + decipher_only = False + + return ( + "" + ).format(self, encipher_only, decipher_only) def __eq__(self, other): if not isinstance(other, KeyUsage): return NotImplemented return ( - self.digital_signature == other.digital_signature and - self.content_commitment == other.content_commitment and - self.key_encipherment == other.key_encipherment and - self.data_encipherment == other.data_encipherment and - self.key_agreement == other.key_agreement and - self.key_cert_sign == other.key_cert_sign and - self.crl_sign == other.crl_sign and - self._encipher_only == other._encipher_only and - self._decipher_only == other._decipher_only + self.digital_signature == other.digital_signature + and self.content_commitment == other.content_commitment + and self.key_encipherment == other.key_encipherment + and self.data_encipherment == other.data_encipherment + and self.key_agreement == other.key_agreement + and self.key_cert_sign == other.key_cert_sign + and self.crl_sign == other.crl_sign + and self._encipher_only == other._encipher_only + and self._decipher_only == other._decipher_only ) def __ne__(self, other): return not self == other def __hash__(self): - return hash(( - self.digital_signature, self.content_commitment, - self.key_encipherment, self.data_encipherment, - self.key_agreement, self.key_cert_sign, - self.crl_sign, self._encipher_only, - self._decipher_only - )) + return hash( + ( + self.digital_signature, + self.content_commitment, + self.key_encipherment, + self.data_encipherment, + self.key_agreement, + self.key_cert_sign, + self.crl_sign, + self._encipher_only, + self._decipher_only, + ) + ) @utils.register_interface(ExtensionType) @@ -1051,9 +1126,7 @@ class NameConstraints(object): def __init__(self, permitted_subtrees, excluded_subtrees): if permitted_subtrees is not None: permitted_subtrees = list(permitted_subtrees) - if not all( - isinstance(x, GeneralName) for x in permitted_subtrees - ): + if not all(isinstance(x, GeneralName) for x in permitted_subtrees): raise TypeError( "permitted_subtrees must be a list of GeneralName objects " "or None" @@ -1063,9 +1136,7 @@ def __init__(self, permitted_subtrees, excluded_subtrees): if excluded_subtrees is not None: excluded_subtrees = list(excluded_subtrees) - if not all( - isinstance(x, GeneralName) for x in excluded_subtrees - ): + if not all(isinstance(x, GeneralName) for x in excluded_subtrees): raise TypeError( "excluded_subtrees must be a list of GeneralName objects " "or None" @@ -1087,17 +1158,21 @@ def __eq__(self, other): return NotImplemented return ( - self.excluded_subtrees == other.excluded_subtrees and - self.permitted_subtrees == other.permitted_subtrees + self.excluded_subtrees == other.excluded_subtrees + and self.permitted_subtrees == other.permitted_subtrees ) def __ne__(self, other): return not self == other def _validate_ip_name(self, tree): - if any(isinstance(name, IPAddress) and not isinstance( - name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network) - ) for name in tree): + if any( + isinstance(name, IPAddress) + and not isinstance( + name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network) + ) + for name in tree + ): raise TypeError( "IPAddress name constraints must be an IPv4Network or" " IPv6Network object" @@ -1145,17 +1220,19 @@ def __init__(self, oid, critical, value): value = utils.read_only_property("_value") def __repr__(self): - return ("").format(self) + return ( + "" + ).format(self) def __eq__(self, other): if not isinstance(other, Extension): return NotImplemented return ( - self.oid == other.oid and - self.critical == other.critical and - self.value == other.value + self.oid == other.oid + and self.critical == other.critical + and self.value == other.value ) def __ne__(self, other): @@ -1176,11 +1253,7 @@ def __init__(self, general_names): self._general_names = general_names - def __iter__(self): - return iter(self._general_names) - - def __len__(self): - return len(self._general_names) + __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") def get_values_for_type(self, type): # Return the value of each GeneralName, except for OtherName instances @@ -1192,7 +1265,7 @@ def get_values_for_type(self, type): return list(objs) def __repr__(self): - return "".format(self._general_names) + return "".format(self._general_names) def __eq__(self, other): if not isinstance(other, GeneralNames): @@ -1203,9 +1276,6 @@ def __eq__(self, other): def __ne__(self, other): return not self == other - def __getitem__(self, idx): - return self._general_names[idx] - def __hash__(self): return hash(tuple(self._general_names)) @@ -1217,17 +1287,13 @@ class SubjectAlternativeName(object): def __init__(self, general_names): self._general_names = GeneralNames(general_names) - def __iter__(self): - return iter(self._general_names) - - def __len__(self): - return len(self._general_names) + __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") def get_values_for_type(self, type): return self._general_names.get_values_for_type(type) def __repr__(self): - return "".format(self._general_names) + return "".format(self._general_names) def __eq__(self, other): if not isinstance(other, SubjectAlternativeName): @@ -1235,9 +1301,6 @@ def __eq__(self, other): return self._general_names == other._general_names - def __getitem__(self, idx): - return self._general_names[idx] - def __ne__(self, other): return not self == other @@ -1252,17 +1315,13 @@ class IssuerAlternativeName(object): def __init__(self, general_names): self._general_names = GeneralNames(general_names) - def __iter__(self): - return iter(self._general_names) - - def __len__(self): - return len(self._general_names) + __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") def get_values_for_type(self, type): return self._general_names.get_values_for_type(type) def __repr__(self): - return "".format(self._general_names) + return "".format(self._general_names) def __eq__(self, other): if not isinstance(other, IssuerAlternativeName): @@ -1273,9 +1332,6 @@ def __eq__(self, other): def __ne__(self, other): return not self == other - def __getitem__(self, idx): - return self._general_names[idx] - def __hash__(self): return hash(self._general_names) @@ -1287,17 +1343,13 @@ class CertificateIssuer(object): def __init__(self, general_names): self._general_names = GeneralNames(general_names) - def __iter__(self): - return iter(self._general_names) - - def __len__(self): - return len(self._general_names) + __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") def get_values_for_type(self, type): return self._general_names.get_values_for_type(type) def __repr__(self): - return "".format(self._general_names) + return "".format(self._general_names) def __eq__(self, other): if not isinstance(other, CertificateIssuer): @@ -1308,9 +1360,6 @@ def __eq__(self, other): def __ne__(self, other): return not self == other - def __getitem__(self, idx): - return self._general_names[idx] - def __hash__(self): return hash(self._general_names) @@ -1326,7 +1375,7 @@ def __init__(self, reason): self._reason = reason def __repr__(self): - return "".format(self._reason) + return "".format(self._reason) def __eq__(self, other): if not isinstance(other, CRLReason): @@ -1354,7 +1403,7 @@ def __init__(self, invalidity_date): self._invalidity_date = invalidity_date def __repr__(self): - return "".format( + return "".format( self._invalidity_date ) @@ -1389,32 +1438,64 @@ def __init__(self, signed_certificate_timestamps): ) self._signed_certificate_timestamps = signed_certificate_timestamps - def __iter__(self): - return iter(self._signed_certificate_timestamps) + __len__, __iter__, __getitem__ = _make_sequence_methods( + "_signed_certificate_timestamps" + ) - def __len__(self): - return len(self._signed_certificate_timestamps) + def __repr__(self): + return "".format( + list(self) + ) - def __getitem__(self, idx): - return self._signed_certificate_timestamps[idx] + def __hash__(self): + return hash(tuple(self._signed_certificate_timestamps)) + + def __eq__(self, other): + if not isinstance(other, PrecertificateSignedCertificateTimestamps): + return NotImplemented - def __repr__(self): return ( - "".format( - list(self) - ) + self._signed_certificate_timestamps + == other._signed_certificate_timestamps ) + def __ne__(self, other): + return not self == other + + +@utils.register_interface(ExtensionType) +class SignedCertificateTimestamps(object): + oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS + + def __init__(self, signed_certificate_timestamps): + signed_certificate_timestamps = list(signed_certificate_timestamps) + if not all( + isinstance(sct, SignedCertificateTimestamp) + for sct in signed_certificate_timestamps + ): + raise TypeError( + "Every item in the signed_certificate_timestamps list must be " + "a SignedCertificateTimestamp" + ) + self._signed_certificate_timestamps = signed_certificate_timestamps + + __len__, __iter__, __getitem__ = _make_sequence_methods( + "_signed_certificate_timestamps" + ) + + def __repr__(self): + return "".format(list(self)) + def __hash__(self): return hash(tuple(self._signed_certificate_timestamps)) def __eq__(self, other): - if not isinstance(other, PrecertificateSignedCertificateTimestamps): + if not isinstance(other, SignedCertificateTimestamps): return NotImplemented return ( - self._signed_certificate_timestamps == - other._signed_certificate_timestamps + self._signed_certificate_timestamps + == other._signed_certificate_timestamps ) def __ne__(self, other): @@ -1453,23 +1534,27 @@ def __repr__(self): class IssuingDistributionPoint(object): oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT - def __init__(self, full_name, relative_name, only_contains_user_certs, - only_contains_ca_certs, only_some_reasons, indirect_crl, - only_contains_attribute_certs): - if ( - only_some_reasons and ( - not isinstance(only_some_reasons, frozenset) or not all( - isinstance(x, ReasonFlags) for x in only_some_reasons - ) - ) + def __init__( + self, + full_name, + relative_name, + only_contains_user_certs, + only_contains_ca_certs, + only_some_reasons, + indirect_crl, + only_contains_attribute_certs, + ): + if only_some_reasons and ( + not isinstance(only_some_reasons, frozenset) + or not all(isinstance(x, ReasonFlags) for x in only_some_reasons) ): raise TypeError( "only_some_reasons must be None or frozenset of ReasonFlags" ) if only_some_reasons and ( - ReasonFlags.unspecified in only_some_reasons or - ReasonFlags.remove_from_crl in only_some_reasons + ReasonFlags.unspecified in only_some_reasons + or ReasonFlags.remove_from_crl in only_some_reasons ): raise ValueError( "unspecified and remove_from_crl are not valid reasons in an " @@ -1477,10 +1562,10 @@ def __init__(self, full_name, relative_name, only_contains_user_certs, ) if not ( - isinstance(only_contains_user_certs, bool) and - isinstance(only_contains_ca_certs, bool) and - isinstance(indirect_crl, bool) and - isinstance(only_contains_attribute_certs, bool) + isinstance(only_contains_user_certs, bool) + and isinstance(only_contains_ca_certs, bool) + and isinstance(indirect_crl, bool) + and isinstance(only_contains_attribute_certs, bool) ): raise TypeError( "only_contains_user_certs, only_contains_ca_certs, " @@ -1489,8 +1574,10 @@ def __init__(self, full_name, relative_name, only_contains_user_certs, ) crl_constraints = [ - only_contains_user_certs, only_contains_ca_certs, - indirect_crl, only_contains_attribute_certs + only_contains_user_certs, + only_contains_ca_certs, + indirect_crl, + only_contains_attribute_certs, ] if len([x for x in crl_constraints if x]) > 1: @@ -1500,12 +1587,16 @@ def __init__(self, full_name, relative_name, only_contains_user_certs, "indirect_crl, only_contains_attribute_certs" ) - if ( - not any([ - only_contains_user_certs, only_contains_ca_certs, - indirect_crl, only_contains_attribute_certs, full_name, - relative_name, only_some_reasons - ]) + if not any( + [ + only_contains_user_certs, + only_contains_ca_certs, + indirect_crl, + only_contains_attribute_certs, + full_name, + relative_name, + only_some_reasons, + ] ): raise ValueError( "Cannot create empty extension: " @@ -1540,29 +1631,31 @@ def __eq__(self, other): return NotImplemented return ( - self.full_name == other.full_name and - self.relative_name == other.relative_name and - self.only_contains_user_certs == other.only_contains_user_certs and - self.only_contains_ca_certs == other.only_contains_ca_certs and - self.only_some_reasons == other.only_some_reasons and - self.indirect_crl == other.indirect_crl and - self.only_contains_attribute_certs == - other.only_contains_attribute_certs + self.full_name == other.full_name + and self.relative_name == other.relative_name + and self.only_contains_user_certs == other.only_contains_user_certs + and self.only_contains_ca_certs == other.only_contains_ca_certs + and self.only_some_reasons == other.only_some_reasons + and self.indirect_crl == other.indirect_crl + and self.only_contains_attribute_certs + == other.only_contains_attribute_certs ) def __ne__(self, other): return not self == other def __hash__(self): - return hash(( - self.full_name, - self.relative_name, - self.only_contains_user_certs, - self.only_contains_ca_certs, - self.only_some_reasons, - self.indirect_crl, - self.only_contains_attribute_certs, - )) + return hash( + ( + self.full_name, + self.relative_name, + self.only_contains_user_certs, + self.only_contains_ca_certs, + self.only_some_reasons, + self.indirect_crl, + self.only_contains_attribute_certs, + ) + ) full_name = utils.read_only_property("_full_name") relative_name = utils.read_only_property("_relative_name") @@ -1592,9 +1685,8 @@ def __init__(self, oid, value): def __repr__(self): return ( - "".format( - self - ) + "".format(self) ) def __eq__(self, other): diff --git a/src/cryptography/x509/general_name.py b/src/cryptography/x509/general_name.py index 1b0f8c8f9bcf..9be9d8c991e1 100644 --- a/src/cryptography/x509/general_name.py +++ b/src/cryptography/x509/general_name.py @@ -6,11 +6,9 @@ import abc import ipaddress -import warnings from email.utils import parseaddr import six -from six.moves import urllib_parse from cryptography import utils from cryptography.x509.name import Name @@ -30,20 +28,6 @@ } -def _lazy_import_idna(): - # Import idna lazily becase it allocates a decent amount of memory, and - # we're only using it in deprecated paths. - try: - import idna - return idna - except ImportError: - raise ImportError( - "idna is not installed, but a deprecated feature that requires it" - " was used. See: https://cryptography.io/en/latest/faq/#importe" - "rror-idna-is-not-installed" - ) - - class UnsupportedGeneralNameType(Exception): def __init__(self, msg, type): super(UnsupportedGeneralNameType, self).__init__(msg) @@ -66,14 +50,10 @@ def __init__(self, value): try: value.encode("ascii") except UnicodeEncodeError: - value = self._idna_encode(value) - warnings.warn( + raise ValueError( "RFC822Name values should be passed as an A-label string. " "This means unicode characters should be encoded via " - "idna. Support for passing unicode strings (aka U-label) " - "will be removed in a future version.", - utils.DeprecatedIn21, - stacklevel=2, + "a library like idna." ) else: raise TypeError("value must be string") @@ -94,12 +74,6 @@ def _init_without_validation(cls, value): instance._value = value return instance - def _idna_encode(self, value): - idna = _lazy_import_idna() - _, address = parseaddr(value) - parts = address.split(u"@") - return parts[0] + "@" + idna.encode(parts[1]).decode("ascii") - def __repr__(self): return "".format(self.value) @@ -116,16 +90,6 @@ def __hash__(self): return hash(self.value) -def _idna_encode(value): - idna = _lazy_import_idna() - # Retain prefixes '*.' for common/alt names and '.' for name constraints - for prefix in ['*.', '.']: - if value.startswith(prefix): - value = value[len(prefix):] - return prefix + idna.encode(value).decode("ascii") - return idna.encode(value).decode("ascii") - - @utils.register_interface(GeneralName) class DNSName(object): def __init__(self, value): @@ -133,14 +97,10 @@ def __init__(self, value): try: value.encode("ascii") except UnicodeEncodeError: - value = _idna_encode(value) - warnings.warn( + raise ValueError( "DNSName values should be passed as an A-label string. " "This means unicode characters should be encoded via " - "idna. Support for passing unicode strings (aka U-label) " - "will be removed in a future version.", - utils.DeprecatedIn21, - stacklevel=2, + "a library like idna." ) else: raise TypeError("value must be string") @@ -178,14 +138,10 @@ def __init__(self, value): try: value.encode("ascii") except UnicodeEncodeError: - value = self._idna_encode(value) - warnings.warn( + raise ValueError( "URI values should be passed as an A-label string. " "This means unicode characters should be encoded via " - "idna. Support for passing unicode strings (aka U-label) " - " will be removed in a future version.", - utils.DeprecatedIn21, - stacklevel=2, + "a library like idna." ) else: raise TypeError("value must be string") @@ -200,29 +156,6 @@ def _init_without_validation(cls, value): instance._value = value return instance - def _idna_encode(self, value): - idna = _lazy_import_idna() - parsed = urllib_parse.urlparse(value) - if parsed.port: - netloc = ( - idna.encode(parsed.hostname) + - ":{0}".format(parsed.port).encode("ascii") - ).decode("ascii") - else: - netloc = idna.encode(parsed.hostname).decode("ascii") - - # Note that building a URL in this fashion means it should be - # semantically indistinguishable from the original but is not - # guaranteed to be exactly the same. - return urllib_parse.urlunparse(( - parsed.scheme, - netloc, - parsed.path, - parsed.params, - parsed.query, - parsed.fragment - )) - def __repr__(self): return "".format(self.value) @@ -250,7 +183,7 @@ def __init__(self, value): value = utils.read_only_property("_value") def __repr__(self): - return "".format(self.value) + return "".format(self.value) def __eq__(self, other): if not isinstance(other, DirectoryName): @@ -276,7 +209,7 @@ def __init__(self, value): value = utils.read_only_property("_value") def __repr__(self): - return "".format(self.value) + return "".format(self.value) def __eq__(self, other): if not isinstance(other, RegisteredID): @@ -300,8 +233,8 @@ def __init__(self, value): ipaddress.IPv4Address, ipaddress.IPv6Address, ipaddress.IPv4Network, - ipaddress.IPv6Network - ) + ipaddress.IPv6Network, + ), ): raise TypeError( "value must be an instance of ipaddress.IPv4Address, " @@ -314,7 +247,7 @@ def __init__(self, value): value = utils.read_only_property("_value") def __repr__(self): - return "".format(self.value) + return "".format(self.value) def __eq__(self, other): if not isinstance(other, IPAddress): @@ -344,8 +277,9 @@ def __init__(self, type_id, value): value = utils.read_only_property("_value") def __repr__(self): - return "".format( - self.type_id, self.value) + return "".format( + self.type_id, self.value + ) def __eq__(self, other): if not isinstance(other, OtherName): diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py index 026b79c2cae2..0be876a0ed6c 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -9,6 +9,7 @@ import six from cryptography import utils +from cryptography.hazmat.backends import _get_backend from cryptography.x509.oid import NameOID, ObjectIdentifier @@ -25,7 +26,7 @@ class _ASN1Type(Enum): BMPString = 30 -_ASN1_TYPE_TO_ENUM = dict((i.value, i) for i in _ASN1Type) +_ASN1_TYPE_TO_ENUM = {i.value: i for i in _ASN1Type} _SENTINEL = object() _NAMEOID_DEFAULT_TYPE = { NameOID.COUNTRY_NAME: _ASN1Type.PrintableString, @@ -39,35 +40,38 @@ class _ASN1Type(Enum): #: Short attribute names from RFC 4514: #: https://tools.ietf.org/html/rfc4514#page-7 _NAMEOID_TO_NAME = { - NameOID.COMMON_NAME: 'CN', - NameOID.LOCALITY_NAME: 'L', - NameOID.STATE_OR_PROVINCE_NAME: 'ST', - NameOID.ORGANIZATION_NAME: 'O', - NameOID.ORGANIZATIONAL_UNIT_NAME: 'OU', - NameOID.COUNTRY_NAME: 'C', - NameOID.STREET_ADDRESS: 'STREET', - NameOID.DOMAIN_COMPONENT: 'DC', - NameOID.USER_ID: 'UID', + NameOID.COMMON_NAME: "CN", + NameOID.LOCALITY_NAME: "L", + NameOID.STATE_OR_PROVINCE_NAME: "ST", + NameOID.ORGANIZATION_NAME: "O", + NameOID.ORGANIZATIONAL_UNIT_NAME: "OU", + NameOID.COUNTRY_NAME: "C", + NameOID.STREET_ADDRESS: "STREET", + NameOID.DOMAIN_COMPONENT: "DC", + NameOID.USER_ID: "UID", } def _escape_dn_value(val): """Escape special characters in RFC4514 Distinguished Name value.""" + if not val: + return "" + # See https://tools.ietf.org/html/rfc4514#section-2.4 - val = val.replace('\\', '\\\\') + val = val.replace("\\", "\\\\") val = val.replace('"', '\\"') - val = val.replace('+', '\\+') - val = val.replace(',', '\\,') - val = val.replace(';', '\\;') - val = val.replace('<', '\\<') - val = val.replace('>', '\\>') - val = val.replace('\0', '\\00') - - if val[0] in ('#', ' '): - val = '\\' + val - if val[-1] == ' ': - val = val[:-1] + '\\ ' + val = val.replace("+", "\\+") + val = val.replace(",", "\\,") + val = val.replace(";", "\\;") + val = val.replace("<", "\\<") + val = val.replace(">", "\\>") + val = val.replace("\0", "\\00") + + if val[0] in ("#", " "): + val = "\\" + val + if val[-1] == " ": + val = val[:-1] + "\\ " return val @@ -80,22 +84,17 @@ def __init__(self, oid, value, _type=_SENTINEL): ) if not isinstance(value, six.text_type): - raise TypeError( - "value argument must be a text type." - ) + raise TypeError("value argument must be a text type.") if ( - oid == NameOID.COUNTRY_NAME or - oid == NameOID.JURISDICTION_COUNTRY_NAME + oid == NameOID.COUNTRY_NAME + or oid == NameOID.JURISDICTION_COUNTRY_NAME ): if len(value.encode("utf8")) != 2: raise ValueError( "Country name must be a 2 character country code" ) - if len(value) == 0: - raise ValueError("Value cannot be an empty string") - # The appropriate ASN1 string type varies by OID and is defined across # multiple RFCs including 2459, 3280, and 5280. In general UTF8String # is preferred (2459), but 3280 and 5280 specify several OIDs with @@ -123,16 +122,13 @@ def rfc4514_string(self): dotted string. """ key = _NAMEOID_TO_NAME.get(self.oid, self.oid.dotted_string) - return '%s=%s' % (key, _escape_dn_value(self.value)) + return "%s=%s" % (key, _escape_dn_value(self.value)) def __eq__(self, other): if not isinstance(other, NameAttribute): return NotImplemented - return ( - self.oid == other.oid and - self.value == other.value - ) + return self.oid == other.oid and self.value == other.value def __ne__(self, other): return not self == other @@ -169,7 +165,7 @@ def rfc4514_string(self): Within each RDN, attributes are joined by '+', although that is rarely used in certificates. """ - return '+'.join(attr.rfc4514_string() for attr in self._attributes) + return "+".join(attr.rfc4514_string() for attr in self._attributes) def __eq__(self, other): if not isinstance(other, RelativeDistinguishedName): @@ -190,7 +186,7 @@ def __len__(self): return len(self._attributes) def __repr__(self): - return "".format(self.rfc4514_string()) + return "".format(self.rfc4514_string()) class Name(object): @@ -216,9 +212,12 @@ def rfc4514_string(self): An X.509 name is a two-level structure: a list of sets of attributes. Each list element is separated by ',' and within each list element, set elements are separated by '+'. The latter is almost never used in - real world certificates. + real world certificates. According to RFC4514 section 2.1 the + RDNSequence must be reversed when converting to string representation. """ - return ','.join(attr.rfc4514_string() for attr in self._attributes) + return ",".join( + attr.rfc4514_string() for attr in reversed(self._attributes) + ) def get_attributes_for_oid(self, oid): return [i for i in self if i.oid == oid] @@ -227,7 +226,8 @@ def get_attributes_for_oid(self, oid): def rdns(self): return self._attributes - def public_bytes(self, backend): + def public_bytes(self, backend=None): + backend = _get_backend(backend) return backend.x509_name_bytes(self) def __eq__(self, other): @@ -253,4 +253,9 @@ def __len__(self): return sum(len(rdn) for rdn in self._attributes) def __repr__(self): - return "".format(self.rfc4514_string()) + rdns = ",".join(attr.rfc4514_string() for attr in self._attributes) + + if six.PY2: + return "".format(rdns.encode("utf8")) + else: + return "".format(rdns) diff --git a/src/cryptography/x509/ocsp.py b/src/cryptography/x509/ocsp.py index aae9b626260c..f8e27224ecaf 100644 --- a/src/cryptography/x509/ocsp.py +++ b/src/cryptography/x509/ocsp.py @@ -13,7 +13,9 @@ from cryptography import x509 from cryptography.hazmat.primitives import hashes from cryptography.x509.base import ( - _EARLIEST_UTC_TIME, _convert_to_naive_utc_time, _reject_duplicate_extension + _EARLIEST_UTC_TIME, + _convert_to_naive_utc_time, + _reject_duplicate_extension, ) @@ -40,10 +42,13 @@ class OCSPResponseStatus(Enum): UNAUTHORIZED = 6 -_RESPONSE_STATUS_TO_ENUM = dict((x.value, x) for x in OCSPResponseStatus) +_RESPONSE_STATUS_TO_ENUM = {x.value: x for x in OCSPResponseStatus} _ALLOWED_HASHES = ( - hashes.SHA1, hashes.SHA224, hashes.SHA256, - hashes.SHA384, hashes.SHA512 + hashes.SHA1, + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, ) @@ -60,16 +65,18 @@ class OCSPCertStatus(Enum): UNKNOWN = 2 -_CERT_STATUS_TO_ENUM = dict((x.value, x) for x in OCSPCertStatus) +_CERT_STATUS_TO_ENUM = {x.value: x for x in OCSPCertStatus} def load_der_ocsp_request(data): from cryptography.hazmat.backends.openssl.backend import backend + return backend.load_der_ocsp_request(data) def load_der_ocsp_response(data): from cryptography.hazmat.backends.openssl.backend import backend + return backend.load_der_ocsp_response(data) @@ -83,9 +90,8 @@ def add_certificate(self, cert, issuer, algorithm): raise ValueError("Only one certificate can be added to a request") _verify_algorithm(algorithm) - if ( - not isinstance(cert, x509.Certificate) or - not isinstance(issuer, x509.Certificate) + if not isinstance(cert, x509.Certificate) or not isinstance( + issuer, x509.Certificate ): raise TypeError("cert and issuer must be a Certificate") @@ -104,6 +110,7 @@ def add_extension(self, extension, critical): def build(self): from cryptography.hazmat.backends.openssl.backend import backend + if self._request is None: raise ValueError("You must add a certificate before building") @@ -111,20 +118,27 @@ def build(self): class _SingleResponse(object): - def __init__(self, cert, issuer, algorithm, cert_status, this_update, - next_update, revocation_time, revocation_reason): - if ( - not isinstance(cert, x509.Certificate) or - not isinstance(issuer, x509.Certificate) + def __init__( + self, + cert, + issuer, + algorithm, + cert_status, + this_update, + next_update, + revocation_time, + revocation_reason, + ): + if not isinstance(cert, x509.Certificate) or not isinstance( + issuer, x509.Certificate ): raise TypeError("cert and issuer must be a Certificate") _verify_algorithm(algorithm) if not isinstance(this_update, datetime.datetime): raise TypeError("this_update must be a datetime object") - if ( - next_update is not None and - not isinstance(next_update, datetime.datetime) + if next_update is not None and not isinstance( + next_update, datetime.datetime ): raise TypeError("next_update must be a datetime object or None") @@ -155,12 +169,13 @@ def __init__(self, cert, issuer, algorithm, cert_status, this_update, revocation_time = _convert_to_naive_utc_time(revocation_time) if revocation_time < _EARLIEST_UTC_TIME: - raise ValueError('The revocation_time must be on or after' - ' 1950 January 1.') + raise ValueError( + "The revocation_time must be on or after" + " 1950 January 1." + ) - if ( - revocation_reason is not None and - not isinstance(revocation_reason, x509.ReasonFlags) + if revocation_reason is not None and not isinstance( + revocation_reason, x509.ReasonFlags ): raise TypeError( "revocation_reason must be an item from the ReasonFlags " @@ -173,25 +188,43 @@ def __init__(self, cert, issuer, algorithm, cert_status, this_update, class OCSPResponseBuilder(object): - def __init__(self, response=None, responder_id=None, certs=None, - extensions=[]): + def __init__( + self, response=None, responder_id=None, certs=None, extensions=[] + ): self._response = response self._responder_id = responder_id self._certs = certs self._extensions = extensions - def add_response(self, cert, issuer, algorithm, cert_status, this_update, - next_update, revocation_time, revocation_reason): + def add_response( + self, + cert, + issuer, + algorithm, + cert_status, + this_update, + next_update, + revocation_time, + revocation_reason, + ): if self._response is not None: raise ValueError("Only one response per OCSPResponse.") singleresp = _SingleResponse( - cert, issuer, algorithm, cert_status, this_update, next_update, - revocation_time, revocation_reason + cert, + issuer, + algorithm, + cert_status, + this_update, + next_update, + revocation_time, + revocation_reason, ) return OCSPResponseBuilder( - singleresp, self._responder_id, - self._certs, self._extensions, + singleresp, + self._responder_id, + self._certs, + self._extensions, ) def responder_id(self, encoding, responder_cert): @@ -205,8 +238,10 @@ def responder_id(self, encoding, responder_cert): ) return OCSPResponseBuilder( - self._response, (responder_cert, encoding), - self._certs, self._extensions, + self._response, + (responder_cert, encoding), + self._certs, + self._extensions, ) def certificates(self, certs): @@ -218,8 +253,10 @@ def certificates(self, certs): if not all(isinstance(x, x509.Certificate) for x in certs): raise TypeError("certs must be a list of Certificates") return OCSPResponseBuilder( - self._response, self._responder_id, - certs, self._extensions, + self._response, + self._responder_id, + certs, + self._extensions, ) def add_extension(self, extension, critical): @@ -230,20 +267,20 @@ def add_extension(self, extension, critical): _reject_duplicate_extension(extension, self._extensions) return OCSPResponseBuilder( - self._response, self._responder_id, - self._certs, self._extensions + [extension], + self._response, + self._responder_id, + self._certs, + self._extensions + [extension], ) def sign(self, private_key, algorithm): from cryptography.hazmat.backends.openssl.backend import backend + if self._response is None: raise ValueError("You must add a response before signing") if self._responder_id is None: raise ValueError("You must add a responder_id before signing") - if not isinstance(algorithm, hashes.HashAlgorithm): - raise TypeError("Algorithm must be a registered hash algorithm.") - return backend.create_ocsp_response( OCSPResponseStatus.SUCCESSFUL, self, private_key, algorithm ) @@ -251,6 +288,7 @@ def sign(self, private_key, algorithm): @classmethod def build_unsuccessful(cls, response_status): from cryptography.hazmat.backends.openssl.backend import backend + if not isinstance(response_status, OCSPResponseStatus): raise TypeError( "response_status must be an item from OCSPResponseStatus" @@ -286,6 +324,7 @@ def serial_number(self): """ The serial number of the cert whose status is being checked """ + @abc.abstractmethod def public_bytes(self, encoding): """ @@ -420,3 +459,9 @@ def extensions(self): """ The list of response extensions. Not single response extensions. """ + + @abc.abstractproperty + def single_extensions(self): + """ + The list of single response extensions. Not response extensions. + """ diff --git a/src/cryptography/x509/oid.py b/src/cryptography/x509/oid.py index ec19007fe322..2bf606e50d6b 100644 --- a/src/cryptography/x509/oid.py +++ b/src/cryptography/x509/oid.py @@ -31,12 +31,11 @@ class ExtensionOID(object): TLS_FEATURE = ObjectIdentifier("1.3.6.1.5.5.7.1.24") CRL_NUMBER = ObjectIdentifier("2.5.29.20") DELTA_CRL_INDICATOR = ObjectIdentifier("2.5.29.27") - PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS = ( - ObjectIdentifier("1.3.6.1.4.1.11129.2.4.2") - ) - PRECERT_POISON = ( - ObjectIdentifier("1.3.6.1.4.1.11129.2.4.3") + PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier( + "1.3.6.1.4.1.11129.2.4.2" ) + PRECERT_POISON = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.3") + SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.5") class OCSPExtensionOID(object): @@ -76,6 +75,10 @@ class NameOID(object): BUSINESS_CATEGORY = ObjectIdentifier("2.5.4.15") POSTAL_ADDRESS = ObjectIdentifier("2.5.4.16") POSTAL_CODE = ObjectIdentifier("2.5.4.17") + INN = ObjectIdentifier("1.2.643.3.131.1.1") + OGRN = ObjectIdentifier("1.2.643.100.1") + SNILS = ObjectIdentifier("1.2.643.100.3") + UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") class SignatureAlgorithmOID(object): @@ -96,6 +99,11 @@ class SignatureAlgorithmOID(object): DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3") DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1") DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2") + ED25519 = ObjectIdentifier("1.3.101.112") + ED448 = ObjectIdentifier("1.3.101.113") + GOSTR3411_94_WITH_3410_2001 = ObjectIdentifier("1.2.643.2.2.3") + GOSTR3410_2012_WITH_3411_2012_256 = ObjectIdentifier("1.2.643.7.1.1.3.2") + GOSTR3410_2012_WITH_3411_2012_512 = ObjectIdentifier("1.2.643.7.1.1.3.3") _SIG_OIDS_TO_HASH = { @@ -113,7 +121,12 @@ class SignatureAlgorithmOID(object): SignatureAlgorithmOID.ECDSA_WITH_SHA512: hashes.SHA512(), SignatureAlgorithmOID.DSA_WITH_SHA1: hashes.SHA1(), SignatureAlgorithmOID.DSA_WITH_SHA224: hashes.SHA224(), - SignatureAlgorithmOID.DSA_WITH_SHA256: hashes.SHA256() + SignatureAlgorithmOID.DSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.ED25519: None, + SignatureAlgorithmOID.ED448: None, + SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: None, + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: None, + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: None, } @@ -132,12 +145,21 @@ class AuthorityInformationAccessOID(object): OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1") +class SubjectInformationAccessOID(object): + CA_REPOSITORY = ObjectIdentifier("1.3.6.1.5.5.7.48.5") + + class CertificatePoliciesOID(object): CPS_QUALIFIER = ObjectIdentifier("1.3.6.1.5.5.7.2.1") CPS_USER_NOTICE = ObjectIdentifier("1.3.6.1.5.5.7.2.2") ANY_POLICY = ObjectIdentifier("2.5.29.32.0") +class AttributeOID(object): + CHALLENGE_PASSWORD = ObjectIdentifier("1.2.840.113549.1.9.7") + UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") + + _OID_NAMES = { NameOID.COMMON_NAME: "commonName", NameOID.COUNTRY_NAME: "countryName", @@ -165,7 +187,10 @@ class CertificatePoliciesOID(object): NameOID.BUSINESS_CATEGORY: "businessCategory", NameOID.POSTAL_ADDRESS: "postalAddress", NameOID.POSTAL_CODE: "postalCode", - + NameOID.INN: "INN", + NameOID.OGRN: "OGRN", + NameOID.SNILS: "SNILS", + NameOID.UNSTRUCTURED_NAME: "unstructuredName", SignatureAlgorithmOID.RSA_WITH_MD5: "md5WithRSAEncryption", SignatureAlgorithmOID.RSA_WITH_SHA1: "sha1WithRSAEncryption", SignatureAlgorithmOID.RSA_WITH_SHA224: "sha224WithRSAEncryption", @@ -181,6 +206,17 @@ class CertificatePoliciesOID(object): SignatureAlgorithmOID.DSA_WITH_SHA1: "dsa-with-sha1", SignatureAlgorithmOID.DSA_WITH_SHA224: "dsa-with-sha224", SignatureAlgorithmOID.DSA_WITH_SHA256: "dsa-with-sha256", + SignatureAlgorithmOID.ED25519: "ed25519", + SignatureAlgorithmOID.ED448: "ed448", + SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: ( + "GOST R 34.11-94 with GOST R 34.10-2001" + ), + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: ( + "GOST R 34.10-2012 with GOST R 34.11-2012 (256 bit)" + ), + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: ( + "GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)" + ), ExtendedKeyUsageOID.SERVER_AUTH: "serverAuth", ExtendedKeyUsageOID.CLIENT_AUTH: "clientAuth", ExtendedKeyUsageOID.CODE_SIGNING: "codeSigning", @@ -196,6 +232,10 @@ class CertificatePoliciesOID(object): ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: ( "signedCertificateTimestampList" ), + ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS: ( + "signedCertificateTimestampList" + ), + ExtensionOID.PRECERT_POISON: "ctPoison", CRLEntryExtensionOID.CRL_REASON: "cRLReason", CRLEntryExtensionOID.INVALIDITY_DATE: "invalidityDate", CRLEntryExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer", @@ -208,9 +248,7 @@ class CertificatePoliciesOID(object): ExtensionOID.EXTENDED_KEY_USAGE: "extendedKeyUsage", ExtensionOID.FRESHEST_CRL: "freshestCRL", ExtensionOID.INHIBIT_ANY_POLICY: "inhibitAnyPolicy", - ExtensionOID.ISSUING_DISTRIBUTION_POINT: ( - "issuingDistributionPoint" - ), + ExtensionOID.ISSUING_DISTRIBUTION_POINT: ("issuingDistributionPoint"), ExtensionOID.AUTHORITY_INFORMATION_ACCESS: "authorityInfoAccess", ExtensionOID.SUBJECT_INFORMATION_ACCESS: "subjectInfoAccess", ExtensionOID.OCSP_NO_CHECK: "OCSPNoCheck", @@ -219,7 +257,9 @@ class CertificatePoliciesOID(object): ExtensionOID.TLS_FEATURE: "TLSFeature", AuthorityInformationAccessOID.OCSP: "OCSP", AuthorityInformationAccessOID.CA_ISSUERS: "caIssuers", + SubjectInformationAccessOID.CA_REPOSITORY: "caRepository", CertificatePoliciesOID.CPS_QUALIFIER: "id-qt-cps", CertificatePoliciesOID.CPS_USER_NOTICE: "id-qt-unotice", OCSPExtensionOID.NONCE: "OCSPNonce", + AttributeOID.CHALLENGE_PASSWORD: "challengePassword", } diff --git a/tests/conftest.py b/tests/conftest.py index d858b4f7011e..4e3124fa76ea 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,12 +9,19 @@ from cryptography.hazmat.backends.openssl import backend as openssl_backend from .utils import ( - check_backend_support, load_wycheproof_tests, skip_if_wycheproof_none + check_backend_support, + load_wycheproof_tests, + skip_if_wycheproof_none, ) def pytest_report_header(config): - return "OpenSSL: {0}".format(openssl_backend.openssl_version_text()) + return "\n".join( + [ + "OpenSSL: {}".format(openssl_backend.openssl_version_text()), + "FIPS Enabled: {}".format(openssl_backend._fips_enabled), + ] + ) def pytest_addoption(parser): @@ -33,6 +40,12 @@ def pytest_generate_tests(metafunc): metafunc.parametrize("wycheproof", testcases) +def pytest_runtest_setup(item): + if openssl_backend._fips_enabled: + for marker in item.iter_markers(name="skip_fips"): + pytest.skip(marker.kwargs["reason"]) + + @pytest.fixture() def backend(request): required_interfaces = [ @@ -43,7 +56,7 @@ def backend(request): isinstance(openssl_backend, iface) for iface in required_interfaces ): pytest.skip( - "OpenSSL doesn't implement required interfaces: {0}".format( + "OpenSSL doesn't implement required interfaces: {}".format( required_interfaces ) ) diff --git a/tests/hazmat/backends/test_no_backend.py b/tests/hazmat/backends/test_no_backend.py new file mode 100644 index 000000000000..67866929e71d --- /dev/null +++ b/tests/hazmat/backends/test_no_backend.py @@ -0,0 +1,16 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography.hazmat.backends import _get_backend, default_backend + + +def test_get_backend_no_backend(): + assert _get_backend(None) is default_backend() + + +def test_get_backend(): + faux_backend = object() + assert _get_backend(faux_backend) is faux_backend diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py index 0aa72d8904f7..2f7e7bebfd0c 100644 --- a/tests/hazmat/backends/test_openssl.py +++ b/tests/hazmat/backends/test_openssl.py @@ -10,16 +10,12 @@ import sys import textwrap -from pkg_resources import parse_version - import pytest from cryptography import x509 from cryptography.exceptions import InternalError, _Reasons from cryptography.hazmat.backends.interfaces import DHBackend, RSABackend -from cryptography.hazmat.backends.openssl.backend import ( - Backend, backend -) +from cryptography.hazmat.backends.openssl.backend import Backend, 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, dsa, padding @@ -29,16 +25,21 @@ from ..primitives.fixtures_rsa import RSA_KEY_2048, RSA_KEY_512 from ...doubles import ( - DummyAsymmetricPadding, DummyCipherAlgorithm, DummyHashAlgorithm, DummyMode + DummyAsymmetricPadding, + DummyCipherAlgorithm, + DummyHashAlgorithm, + DummyMode, ) from ...utils import ( - load_nist_vectors, load_vectors_from_file, raises_unsupported_algorithm + load_nist_vectors, + load_vectors_from_file, + raises_unsupported_algorithm, ) from ...x509.test_x509 import _load_cert def skip_if_libre_ssl(openssl_version): - if u'LibreSSL' in openssl_version: + if u"LibreSSL" in openssl_version: pytest.skip("LibreSSL hard-codes RAND_bytes to use arc4random.") @@ -68,10 +69,9 @@ def test_openssl_version_text(self): if it starts with OpenSSL or LibreSSL as that appears to be true for every OpenSSL-alike. """ - assert ( - backend.openssl_version_text().startswith("OpenSSL") or - backend.openssl_version_text().startswith("LibreSSL") - ) + assert backend.openssl_version_text().startswith( + "OpenSSL" + ) or backend.openssl_version_text().startswith("LibreSSL") def test_openssl_version_number(self): assert backend.openssl_version_number() > 0 @@ -89,10 +89,12 @@ def test_nonexistent_cipher(self, mode): b.register_cipher_adapter( DummyCipherAlgorithm, type(mode), - lambda backend, cipher, mode: backend._ffi.NULL + lambda backend, cipher, mode: backend._ffi.NULL, ) cipher = Cipher( - DummyCipherAlgorithm(), mode, backend=b, + DummyCipherAlgorithm(), + mode, + backend=b, ) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER): cipher.encryptor() @@ -104,8 +106,9 @@ def test_openssl_assert(self): def test_consume_errors(self): for i in range(10): - backend._lib.ERR_put_error(backend._lib.ERR_LIB_EVP, 0, 0, - b"test_openssl.py", -1) + backend._lib.ERR_put_error( + backend._lib.ERR_LIB_EVP, 0, 0, b"test_openssl.py", -1 + ) assert backend._lib.ERR_peek_error() != 0 @@ -133,8 +136,7 @@ def test_unknown_error_in_cipher_finalize(self): cipher = Cipher(AES(b"\0" * 16), CBC(b"\0" * 16), backend=backend) enc = cipher.encryptor() enc.update(b"\0") - backend._lib.ERR_put_error(0, 0, 1, - b"test_openssl.py", -1) + backend._lib.ERR_put_error(0, 0, 1, b"test_openssl.py", -1) with pytest.raises(InternalError): enc.finalize() @@ -170,6 +172,11 @@ 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(object): def setup(self): # The default RAND engine is global and shared between @@ -178,7 +185,7 @@ def setup(self): # that engine in teardown. current_default = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(current_default) - assert name == backend._binding._osrandom_engine_name + assert name == backend._lib.Cryptography_osrandom_engine_name def teardown(self): # we need to reset state to being default. backend is a shared global @@ -186,10 +193,11 @@ def teardown(self): backend.activate_osrandom_engine() current_default = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(current_default) - assert name == backend._binding._osrandom_engine_name + assert name == backend._lib.Cryptography_osrandom_engine_name - @pytest.mark.skipif(sys.executable is None, - reason="No Python interpreter available.") + @pytest.mark.skipif( + sys.executable is None, reason="No Python interpreter available." + ) def test_osrandom_engine_is_default(self, tmpdir): engine_printer = textwrap.dedent( """ @@ -203,7 +211,7 @@ def test_osrandom_engine_is_default(self, tmpdir): assert res == 1 """ ) - engine_name = tmpdir.join('engine_name') + 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 @@ -214,7 +222,7 @@ def test_osrandom_engine_is_default(self, tmpdir): env = os.environ.copy() env["PYTHONPATH"] = os.pathsep.join(sys.path) - with engine_name.open('w') as out: + with engine_name.open("w") as out: subprocess.check_call( [sys.executable, "-c", engine_printer], env=env, @@ -223,10 +231,10 @@ def test_osrandom_engine_is_default(self, tmpdir): ) osrandom_engine_name = backend._ffi.string( - backend._binding._osrandom_engine_name + backend._lib.Cryptography_osrandom_engine_name ) - assert engine_name.read().encode('ascii') == osrandom_engine_name + assert engine_name.read().encode("ascii") == osrandom_engine_name def test_osrandom_sanity_check(self): # This test serves as a check against catastrophic failure. @@ -242,7 +250,7 @@ def test_activate_osrandom_no_default(self): backend.activate_osrandom_engine() e = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(e) - assert name == backend._binding._osrandom_engine_name + assert name == backend._lib.Cryptography_osrandom_engine_name res = backend._lib.ENGINE_free(e) assert res == 1 @@ -250,7 +258,7 @@ 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._binding._osrandom_engine_name + assert name == backend._lib.Cryptography_osrandom_engine_name res = backend._lib.ENGINE_free(e) assert res == 1 backend.activate_builtin_random() @@ -267,33 +275,55 @@ def test_activate_builtin_random_already_active(self): 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': - # macOS 10.12+ supports getentropy - if parse_version(os.uname()[2]) >= parse_version("16.0"): - assert name == 'getentropy' - else: - assert name == '/dev/urandom' - if sys.platform == 'win32': - assert name == 'CryptGenRandom' + 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", "/dev/urandom"] + if sys.platform == "win32": + assert name == "CryptGenRandom" def test_activate_osrandom_already_default(self): e = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(e) - assert name == backend._binding._osrandom_engine_name + assert name == backend._lib.Cryptography_osrandom_engine_name res = backend._lib.ENGINE_free(e) assert res == 1 backend.activate_osrandom_engine() e = backend._lib.ENGINE_get_default_RAND() name = backend._lib.ENGINE_get_name(e) - assert name == backend._binding._osrandom_engine_name + assert name == backend._lib.Cryptography_osrandom_engine_name res = backend._lib.ENGINE_free(e) assert res == 1 +@pytest.mark.skipif( + backend._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE, + reason="Requires OpenSSL without ENGINE support or OpenSSL >=1.1.1d", +) +class TestOpenSSLNoEngine(object): + def test_no_engine_support(self): + assert ( + backend._ffi.string(backend._lib.Cryptography_osrandom_engine_id) + == b"no-engine-support" + ) + assert ( + backend._ffi.string(backend._lib.Cryptography_osrandom_engine_name) + == b"osrandom_engine disabled" + ) + + def test_activate_builtin_random_does_nothing(self): + backend.activate_builtin_random() + + def test_activate_osrandom_does_nothing(self): + backend.activate_osrandom_engine() + + class TestOpenSSLRSA(object): def test_generate_rsa_parameters_supported(self): assert backend.generate_rsa_parameters_supported(1, 1024) is False @@ -310,17 +340,24 @@ def test_generate_bad_public_exponent(self): def test_cant_generate_insecure_tiny_key(self): with pytest.raises(ValueError): - backend.generate_rsa_private_key(public_exponent=65537, - key_size=511) + backend.generate_rsa_private_key( + public_exponent=65537, key_size=511 + ) with pytest.raises(ValueError): - backend.generate_rsa_private_key(public_exponent=65537, - key_size=256) + backend.generate_rsa_private_key( + public_exponent=65537, key_size=256 + ) def test_rsa_padding_unsupported_pss_mgf1_hash(self): - assert backend.rsa_padding_supported( - padding.PSS(mgf=padding.MGF1(DummyHashAlgorithm()), salt_length=0) - ) is False + assert ( + backend.rsa_padding_supported( + padding.PSS( + mgf=padding.MGF1(DummyHashAlgorithm()), salt_length=0 + ) + ) + is False + ) def test_rsa_padding_unsupported(self): assert backend.rsa_padding_supported(DummyAsymmetricPadding()) is False @@ -329,22 +366,28 @@ def test_rsa_padding_supported_pkcs1v15(self): assert backend.rsa_padding_supported(padding.PKCS1v15()) is True def test_rsa_padding_supported_pss(self): - assert backend.rsa_padding_supported( - padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0) - ) is True + assert ( + backend.rsa_padding_supported( + padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0) + ) + is True + ) def test_rsa_padding_supported_oaep(self): - assert backend.rsa_padding_supported( - padding.OAEP( - mgf=padding.MGF1(algorithm=hashes.SHA1()), - algorithm=hashes.SHA1(), - label=None - ), - ) is True + assert ( + backend.rsa_padding_supported( + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA1()), + algorithm=hashes.SHA1(), + label=None, + ), + ) + is True + ) @pytest.mark.skipif( backend._lib.Cryptography_HAS_RSA_OAEP_MD == 0, - reason="Requires OpenSSL with rsa_oaep_md (1.0.2+)" + reason="Requires OpenSSL with rsa_oaep_md (1.0.2+)", ) def test_rsa_padding_supported_oaep_sha2_combinations(self): hashalgs = [ @@ -355,30 +398,37 @@ def test_rsa_padding_supported_oaep_sha2_combinations(self): hashes.SHA512(), ] for mgf1alg, oaepalg in itertools.product(hashalgs, hashalgs): - assert backend.rsa_padding_supported( - padding.OAEP( - mgf=padding.MGF1(algorithm=mgf1alg), - algorithm=oaepalg, - label=None - ), - ) is True + assert ( + backend.rsa_padding_supported( + padding.OAEP( + mgf=padding.MGF1(algorithm=mgf1alg), + algorithm=oaepalg, + label=None, + ), + ) + is True + ) def test_rsa_padding_unsupported_mgf(self): - assert backend.rsa_padding_supported( - padding.OAEP( - mgf=DummyMGF(), - algorithm=hashes.SHA1(), - label=None - ), - ) is False + assert ( + backend.rsa_padding_supported( + padding.OAEP( + mgf=DummyMGF(), algorithm=hashes.SHA1(), label=None + ), + ) + is False + ) - assert backend.rsa_padding_supported( - padding.PSS(mgf=DummyMGF(), salt_length=0) - ) is False + assert ( + backend.rsa_padding_supported( + padding.PSS(mgf=DummyMGF(), salt_length=0) + ) + is False + ) @pytest.mark.skipif( backend._lib.Cryptography_HAS_RSA_OAEP_MD == 1, - reason="Requires OpenSSL without rsa_oaep_md (< 1.0.2)" + reason="Requires OpenSSL without rsa_oaep_md (< 1.0.2)", ) def test_unsupported_mgf1_hash_algorithm_decrypt(self): private_key = RSA_KEY_512.private_key(backend) @@ -388,13 +438,13 @@ def test_unsupported_mgf1_hash_algorithm_decrypt(self): padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA1(), - label=None - ) + label=None, + ), ) @pytest.mark.skipif( backend._lib.Cryptography_HAS_RSA_OAEP_MD == 1, - reason="Requires OpenSSL without rsa_oaep_md (< 1.0.2)" + reason="Requires OpenSSL without rsa_oaep_md (< 1.0.2)", ) def test_unsupported_oaep_hash_algorithm_decrypt(self): private_key = RSA_KEY_512.private_key(backend) @@ -404,8 +454,8 @@ def test_unsupported_oaep_hash_algorithm_decrypt(self): padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA256(), - label=None - ) + label=None, + ), ) def test_unsupported_mgf1_hash_algorithm_md5_decrypt(self): @@ -416,8 +466,8 @@ def test_unsupported_mgf1_hash_algorithm_md5_decrypt(self): padding.OAEP( mgf=padding.MGF1(algorithm=hashes.MD5()), algorithm=hashes.MD5(), - label=None - ) + label=None, + ), ) @@ -437,6 +487,16 @@ def test_requires_certificate_builder(self): ) +class TestOpenSSLSignX509CSR(object): + def test_requires_csr_builder(self): + private_key = RSA_KEY_2048.private_key(backend) + + with pytest.raises(TypeError): + backend.create_x509_csr( + object(), private_key, DummyHashAlgorithm() + ) + + class TestOpenSSLSignX509CertificateRevocationList(object): def test_invalid_builder(self): private_key = RSA_KEY_2048.private_key(backend) @@ -492,14 +552,15 @@ def test_very_long_pem_serialization_password(self): with pytest.raises(ValueError): load_vectors_from_file( os.path.join( - "asymmetric", "Traditional_OpenSSL_Serialization", - "key1.pem" + "asymmetric", + "Traditional_OpenSSL_Serialization", + "key1.pem", ), lambda pemfile: ( backend.load_pem_private_key( pemfile.read().encode(), password ) - ) + ), ) @@ -518,7 +579,7 @@ def test_password_length_limit(self): key.private_bytes( serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, - serialization.BestAvailableEncryption(password) + serialization.BestAvailableEncryption(password), ) @@ -527,7 +588,7 @@ def test_numeric_string_x509_name_entry(self): cert = _load_cert( os.path.join("x509", "e-trust.ru.der"), x509.load_der_x509_certificate, - backend + backend, ) if backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102I: with pytest.raises(ValueError) as exc: @@ -538,42 +599,49 @@ def test_numeric_string_x509_name_entry(self): # erroneously pass. assert str(exc.value) == "Unsupported ASN1 string type. Type: 18" else: - assert cert.subject.get_attributes_for_oid( - x509.ObjectIdentifier("1.2.643.3.131.1.1") - )[0].value == "007710474375" + assert ( + cert.subject.get_attributes_for_oid( + x509.ObjectIdentifier("1.2.643.3.131.1.1") + )[0].value + == "007710474375" + ) @pytest.mark.skipif( backend._lib.Cryptography_HAS_EVP_PKEY_DHX == 1, - reason="Requires OpenSSL without EVP_PKEY_DHX (< 1.0.2)") + reason="Requires OpenSSL without EVP_PKEY_DHX (< 1.0.2)", +) @pytest.mark.requires_backend_interface(interface=DHBackend) class TestOpenSSLDHSerialization(object): - @pytest.mark.parametrize( "vector", load_vectors_from_file( - os.path.join("asymmetric", "DH", "RFC5114.txt"), - load_nist_vectors)) + 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)) + 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()) + 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) + serialization.PublicFormat.SubjectPublicKeyInfo, + ) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): parameters.parameters(backend).parameter_bytes( - serialization.Encoding.PEM, - serialization.ParameterFormat.PKCS3) + serialization.Encoding.PEM, serialization.ParameterFormat.PKCS3 + ) @pytest.mark.parametrize( ("key_path", "loader_func"), @@ -585,14 +653,14 @@ def test_dh_serialization_with_q_unsupported(self, backend, vector): ( os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.der"), serialization.load_der_private_key, - ) - ] + ), + ], ) - def test_private_load_dhx_unsupported(self, key_path, loader_func, - backend): + def test_private_load_dhx_unsupported( + self, key_path, loader_func, backend + ): key_bytes = load_vectors_from_file( - key_path, - lambda pemfile: pemfile.read(), mode="rb" + key_path, lambda pemfile: pemfile.read(), mode="rb" ) with pytest.raises(ValueError): loader_func(key_bytes, None, backend) @@ -607,14 +675,12 @@ def test_private_load_dhx_unsupported(self, key_path, loader_func, ( os.path.join("asymmetric", "DH", "dhpub_rfc5114_2.der"), serialization.load_der_public_key, - ) - ] + ), + ], ) - def test_public_load_dhx_unsupported(self, key_path, loader_func, - backend): + def test_public_load_dhx_unsupported(self, key_path, loader_func, backend): key_bytes = load_vectors_from_file( - key_path, - lambda pemfile: pemfile.read(), mode="rb" + key_path, lambda pemfile: pemfile.read(), mode="rb" ) with pytest.raises(ValueError): loader_func(key_bytes, backend) diff --git a/tests/hazmat/backends/test_openssl_memleak.py b/tests/hazmat/backends/test_openssl_memleak.py index 1db103b5e77b..d8bc8660a830 100644 --- a/tests/hazmat/backends/test_openssl_memleak.py +++ b/tests/hazmat/backends/test_openssl_memleak.py @@ -128,7 +128,9 @@ def assert_no_memory_leaks(s, argv=[]): env = os.environ.copy() env["PYTHONPATH"] = os.pathsep.join(sys.path) argv = [ - sys.executable, "-c", "{0}\n\n{1}".format(s, MEMORY_LEAK_SCRIPT) + sys.executable, + "-c", + "{}\n\n{}".format(s, MEMORY_LEAK_SCRIPT), ] + argv # Shell out to a fresh Python process because OpenSSL does not allow you to # install new memory hooks after the first malloc/free occurs. @@ -156,62 +158,86 @@ def assert_no_memory_leaks(s, argv=[]): def skip_if_memtesting_not_supported(): return pytest.mark.skipif( not Binding().lib.Cryptography_HAS_MEM_FUNCTIONS, - reason="Requires OpenSSL memory functions (>=1.1.0)" + reason="Requires OpenSSL memory functions (>=1.1.0)", ) +@pytest.mark.skip_fips(reason="FIPS self-test sets allow_customize = 0") @skip_if_memtesting_not_supported() class TestAssertNoMemoryLeaks(object): def test_no_leak_no_malloc(self): - assert_no_memory_leaks(textwrap.dedent(""" + assert_no_memory_leaks( + textwrap.dedent( + """ def func(): pass - """)) + """ + ) + ) def test_no_leak_free(self): - assert_no_memory_leaks(textwrap.dedent(""" + assert_no_memory_leaks( + textwrap.dedent( + """ def func(): from cryptography.hazmat.bindings.openssl.binding import Binding b = Binding() name = b.lib.X509_NAME_new() b.lib.X509_NAME_free(name) - """)) + """ + ) + ) def test_no_leak_gc(self): - assert_no_memory_leaks(textwrap.dedent(""" + assert_no_memory_leaks( + textwrap.dedent( + """ def func(): from cryptography.hazmat.bindings.openssl.binding import Binding b = Binding() name = b.lib.X509_NAME_new() b.ffi.gc(name, b.lib.X509_NAME_free) - """)) + """ + ) + ) def test_leak(self): with pytest.raises(AssertionError): - assert_no_memory_leaks(textwrap.dedent(""" + assert_no_memory_leaks( + textwrap.dedent( + """ def func(): from cryptography.hazmat.bindings.openssl.binding import ( Binding ) b = Binding() b.lib.X509_NAME_new() - """)) + """ + ) + ) def test_errors(self): with pytest.raises(ValueError): - assert_no_memory_leaks(textwrap.dedent(""" + assert_no_memory_leaks( + textwrap.dedent( + """ def func(): raise ZeroDivisionError - """)) + """ + ) + ) +@pytest.mark.skip_fips(reason="FIPS self-test sets allow_customize = 0") @skip_if_memtesting_not_supported() class TestOpenSSLMemoryLeaks(object): - @pytest.mark.parametrize("path", [ - "x509/PKITS_data/certs/ValidcRLIssuerTest28EE.crt", - ]) - def test_x509_certificate_extensions(self, path): - assert_no_memory_leaks(textwrap.dedent(""" + @pytest.mark.parametrize( + "path", ["x509/PKITS_data/certs/ValidcRLIssuerTest28EE.crt"] + ) + def test_der_x509_certificate_extensions(self, path): + assert_no_memory_leaks( + textwrap.dedent( + """ def func(path): from cryptography import x509 from cryptography.hazmat.backends.openssl import backend @@ -224,10 +250,37 @@ def func(path): ) cert.extensions - """), [path]) + """ + ), + [path], + ) + + @pytest.mark.parametrize("path", ["x509/cryptography.io.pem"]) + def test_pem_x509_certificate_extensions(self, path): + assert_no_memory_leaks( + textwrap.dedent( + """ + def func(path): + from cryptography import x509 + from cryptography.hazmat.backends.openssl import backend + + import cryptography_vectors + + with cryptography_vectors.open_vector_file(path, "rb") as f: + cert = x509.load_pem_x509_certificate( + f.read(), backend + ) + + cert.extensions + """ + ), + [path], + ) def test_x509_csr_extensions(self): - assert_no_memory_leaks(textwrap.dedent(""" + assert_no_memory_leaks( + textwrap.dedent( + """ def func(): from cryptography import x509 from cryptography.hazmat.backends.openssl import backend @@ -244,10 +297,14 @@ def func(): ).sign(private_key, hashes.SHA256(), backend) cert.extensions - """)) + """ + ) + ) def test_ec_private_numbers_private_key(self): - assert_no_memory_leaks(textwrap.dedent(""" + assert_no_memory_leaks( + textwrap.dedent( + """ def func(): from cryptography.hazmat.backends.openssl import backend from cryptography.hazmat.primitives.asymmetric import ec @@ -269,26 +326,38 @@ def func(): ) ) ).private_key(backend) - """)) + """ + ) + ) def test_ec_derive_private_key(self): - assert_no_memory_leaks(textwrap.dedent(""" + assert_no_memory_leaks( + textwrap.dedent( + """ def func(): from cryptography.hazmat.backends.openssl import backend from cryptography.hazmat.primitives.asymmetric import ec ec.derive_private_key(1, ec.SECP256R1(), backend) - """)) + """ + ) + ) def test_x25519_pubkey_from_private_key(self): - assert_no_memory_leaks(textwrap.dedent(""" + assert_no_memory_leaks( + textwrap.dedent( + """ def func(): from cryptography.hazmat.primitives.asymmetric import x25519 private_key = x25519.X25519PrivateKey.generate() private_key.public_key() - """)) + """ + ) + ) def test_create_ocsp_request(self): - assert_no_memory_leaks(textwrap.dedent(""" + assert_no_memory_leaks( + textwrap.dedent( + """ def func(): from cryptography import x509 from cryptography.hazmat.backends.openssl import backend @@ -306,14 +375,18 @@ def func(): cert, cert, hashes.SHA1() ).add_extension(x509.OCSPNonce(b"0000"), False) req = builder.build() - """)) + """ + ) + ) - @pytest.mark.parametrize("path", [ - "pkcs12/cert-aes256cbc-no-key.p12", - "pkcs12/cert-key-aes256cbc.p12", - ]) + @pytest.mark.parametrize( + "path", + ["pkcs12/cert-aes256cbc-no-key.p12", "pkcs12/cert-key-aes256cbc.p12"], + ) def test_load_pkcs12_key_and_certificates(self, path): - assert_no_memory_leaks(textwrap.dedent(""" + assert_no_memory_leaks( + textwrap.dedent( + """ def func(path): from cryptography import x509 from cryptography.hazmat.backends.openssl import backend @@ -324,10 +397,15 @@ def func(path): pkcs12.load_key_and_certificates( f.read(), b"cryptography", backend ) - """), [path]) + """ + ), + [path], + ) def test_create_crl_with_idp(self): - assert_no_memory_leaks(textwrap.dedent(""" + assert_no_memory_leaks( + textwrap.dedent( + """ def func(): import datetime from cryptography import x509 @@ -369,4 +447,109 @@ def func(): crl.extensions.get_extension_for_class( x509.IssuingDistributionPoint ) - """)) + """ + ) + ) + + def test_create_certificate_with_extensions(self): + assert_no_memory_leaks( + textwrap.dedent( + """ + def func(): + import datetime + + from cryptography import x509 + from cryptography.hazmat.backends.openssl import backend + from cryptography.hazmat.primitives import hashes + from cryptography.hazmat.primitives.asymmetric import ec + from cryptography.x509.oid import ( + AuthorityInformationAccessOID, ExtendedKeyUsageOID, NameOID + ) + + private_key = ec.generate_private_key(ec.SECP256R1(), backend) + + not_valid_before = datetime.datetime.now() + not_valid_after = not_valid_before + datetime.timedelta(days=365) + + aia = x509.AuthorityInformationAccess([ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") + ) + ]) + sans = [u'*.example.org', u'foobar.example.net'] + san = x509.SubjectAlternativeName(list(map(x509.DNSName, sans))) + + ski = x509.SubjectKeyIdentifier.from_public_key( + private_key.public_key() + ) + eku = x509.ExtendedKeyUsage([ + ExtendedKeyUsageOID.CLIENT_AUTH, + ExtendedKeyUsageOID.SERVER_AUTH, + ExtendedKeyUsageOID.CODE_SIGNING, + ]) + + builder = x509.CertificateBuilder().serial_number( + 777 + ).issuer_name(x509.Name([ + x509.NameAttribute(NameOID.COUNTRY_NAME, u'US'), + ])).subject_name(x509.Name([ + x509.NameAttribute(NameOID.COUNTRY_NAME, u'US'), + ])).public_key( + private_key.public_key() + ).add_extension( + aia, critical=False + ).not_valid_before( + not_valid_before + ).not_valid_after( + not_valid_after + ) + + cert = builder.sign(private_key, hashes.SHA256(), backend) + cert.extensions + """ + ) + ) + + def test_write_pkcs12_key_and_certificates(self): + assert_no_memory_leaks( + textwrap.dedent( + """ + def func(): + import os + from cryptography import x509 + from cryptography.hazmat.backends.openssl import backend + from cryptography.hazmat.primitives import serialization + from cryptography.hazmat.primitives.serialization import pkcs12 + import cryptography_vectors + + path = os.path.join('x509', 'custom', 'ca', 'ca.pem') + with cryptography_vectors.open_vector_file(path, "rb") as f: + cert = x509.load_pem_x509_certificate( + f.read(), backend + ) + path2 = os.path.join('x509', 'custom', 'dsa_selfsigned_ca.pem') + with cryptography_vectors.open_vector_file(path2, "rb") as f: + cert2 = x509.load_pem_x509_certificate( + f.read(), backend + ) + path3 = os.path.join('x509', 'letsencryptx3.pem') + with cryptography_vectors.open_vector_file(path3, "rb") as f: + cert3 = x509.load_pem_x509_certificate( + f.read(), backend + ) + key_path = os.path.join("x509", "custom", "ca", "ca_key.pem") + with cryptography_vectors.open_vector_file(key_path, "rb") as f: + key = serialization.load_pem_private_key( + f.read(), None, backend + ) + encryption = serialization.NoEncryption() + pkcs12.serialize_key_and_certificates( + b"name", key, cert, [cert2, cert3], encryption) + """ + ) + ) diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py index fb1e62fa9b3d..ecee34091dc7 100644 --- a/tests/hazmat/bindings/test_openssl.py +++ b/tests/hazmat/bindings/test_openssl.py @@ -4,11 +4,17 @@ from __future__ import absolute_import, division, print_function +import pretend + import pytest from cryptography.exceptions import InternalError from cryptography.hazmat.bindings.openssl.binding import ( - Binding, _consume_errors, _openssl_assert + Binding, + _consume_errors, + _openssl_assert, + _verify_openssl_version, + _verify_package_version, ) @@ -95,7 +101,7 @@ def test_openssl_assert_error_on_stack(self): b.lib.EVP_F_EVP_ENCRYPTFINAL_EX, b.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH, b"", - -1 + -1, ) with pytest.raises(InternalError) as exc_info: _openssl_assert(b.lib, False) @@ -114,7 +120,20 @@ def test_check_startup_errors_are_allowed(self): b.lib.EVP_F_EVP_ENCRYPTFINAL_EX, b.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH, b"", - -1 + -1, ) b._register_osrandom_engine() assert _consume_errors(b.lib) == [] + + def test_version_mismatch(self): + with pytest.raises(ImportError): + _verify_package_version("nottherightversion") + + def test_verify_openssl_version(self, monkeypatch): + monkeypatch.delenv("CRYPTOGRAPHY_ALLOW_OPENSSL_102", raising=False) + lib = pretend.stub( + CRYPTOGRAPHY_OPENSSL_LESS_THAN_110=True, + CRYPTOGRAPHY_IS_LIBRESSL=False, + ) + with pytest.raises(RuntimeError): + _verify_openssl_version(lib) diff --git a/tests/hazmat/primitives/fixtures_dh.py b/tests/hazmat/primitives/fixtures_dh.py new file mode 100644 index 000000000000..b766c4265837 --- /dev/null +++ b/tests/hazmat/primitives/fixtures_dh.py @@ -0,0 +1,26 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography.hazmat.primitives.asymmetric import dh + +FFDH3072_P = dh.DHParameterNumbers( + p=int( + "ffffffffffffffffadf85458a2bb4a9aafdc5620273d3cf1d8b9c583ce2d3695a9e" + "13641146433fbcc939dce249b3ef97d2fe363630c75d8f681b202aec4617ad3df1e" + "d5d5fd65612433f51f5f066ed0856365553ded1af3b557135e7f57c935984f0c70e" + "0e68b77e2a689daf3efe8721df158a136ade73530acca4f483a797abc0ab182b324" + "fb61d108a94bb2c8e3fbb96adab760d7f4681d4f42a3de394df4ae56ede76372bb1" + "90b07a7c8ee0a6d709e02fce1cdf7e2ecc03404cd28342f619172fe9ce98583ff8e" + "4f1232eef28183c3fe3b1b4c6fad733bb5fcbc2ec22005c58ef1837d1683b2c6f34" + "a26c1b2effa886b4238611fcfdcde355b3b6519035bbc34f4def99c023861b46fc9" + "d6e6c9077ad91d2691f7f7ee598cb0fac186d91caefe130985139270b4130c93bc4" + "37944f4fd4452e2d74dd364f2e21e71f54bff5cae82ab9c9df69ee86d2bc522363a" + "0dabc521979b0deada1dbf9a42d5c4484e0abcd06bfa53ddef3c1b20ee3fd59d7c2" + "5e41d2b66c62e37ffffffffffffffff", + 16, + ), + g=2, +) diff --git a/tests/hazmat/primitives/fixtures_dsa.py b/tests/hazmat/primitives/fixtures_dsa.py index dd947ae82257..d4568ead7306 100644 --- a/tests/hazmat/primitives/fixtures_dsa.py +++ b/tests/hazmat/primitives/fixtures_dsa.py @@ -5,7 +5,9 @@ from __future__ import absolute_import, division, print_function from cryptography.hazmat.primitives.asymmetric.dsa import ( - DSAParameterNumbers, DSAPrivateNumbers, DSAPublicNumbers + DSAParameterNumbers, + DSAPrivateNumbers, + DSAPublicNumbers, ) @@ -13,140 +15,147 @@ public_numbers=DSAPublicNumbers( parameter_numbers=DSAParameterNumbers( p=int( - 'd38311e2cd388c3ed698e82fdf88eb92b5a9a483dc88005d4b725ef34' - '1eabb47cf8a7a8a41e792a156b7ce97206c4f9c5ce6fc5ae7912102b6' - 'b502e59050b5b21ce263dddb2044b652236f4d42ab4b5d6aa73189cef' - '1ace778d7845a5c1c1c7147123188f8dc551054ee162b634d60f097f7' - '19076640e20980a0093113a8bd73', 16 + "d38311e2cd388c3ed698e82fdf88eb92b5a9a483dc88005d4b725ef34" + "1eabb47cf8a7a8a41e792a156b7ce97206c4f9c5ce6fc5ae7912102b6" + "b502e59050b5b21ce263dddb2044b652236f4d42ab4b5d6aa73189cef" + "1ace778d7845a5c1c1c7147123188f8dc551054ee162b634d60f097f7" + "19076640e20980a0093113a8bd73", + 16, ), - q=int('96c5390a8b612c0e422bb2b0ea194a3ec935a281', 16), + q=int("96c5390a8b612c0e422bb2b0ea194a3ec935a281", 16), g=int( - '06b7861abbd35cc89e79c52f68d20875389b127361ca66822138ce499' - '1d2b862259d6b4548a6495b195aa0e0b6137ca37eb23b94074d3c3d30' - '0042bdf15762812b6333ef7b07ceba78607610fcc9ee68491dbc1e34c' - 'd12615474e52b18bc934fb00c61d39e7da8902291c4434a4e2224c3f4' - 'fd9f93cd6f4f17fc076341a7e7d9', 16 - ) + "06b7861abbd35cc89e79c52f68d20875389b127361ca66822138ce499" + "1d2b862259d6b4548a6495b195aa0e0b6137ca37eb23b94074d3c3d30" + "0042bdf15762812b6333ef7b07ceba78607610fcc9ee68491dbc1e34c" + "d12615474e52b18bc934fb00c61d39e7da8902291c4434a4e2224c3f4" + "fd9f93cd6f4f17fc076341a7e7d9", + 16, + ), ), y=int( - '6f26d98d41de7d871b6381851c9d91fa03942092ab6097e76422070edb71d' - 'b44ff568280fdb1709f8fc3feab39f1f824adaeb2a298088156ac31af1aa0' - '4bf54f475bdcfdcf2f8a2dd973e922d83e76f016558617603129b21c70bf7' - 'd0e5dc9e68fe332e295b65876eb9a12fe6fca9f1a1ce80204646bf99b5771' - 'd249a6fea627', 16 - ) + "6f26d98d41de7d871b6381851c9d91fa03942092ab6097e76422070edb71d" + "b44ff568280fdb1709f8fc3feab39f1f824adaeb2a298088156ac31af1aa0" + "4bf54f475bdcfdcf2f8a2dd973e922d83e76f016558617603129b21c70bf7" + "d0e5dc9e68fe332e295b65876eb9a12fe6fca9f1a1ce80204646bf99b5771" + "d249a6fea627", + 16, + ), ), - x=int('8185fee9cc7c0e91fd85503274f1cd5a3fd15a49', 16) + x=int("8185fee9cc7c0e91fd85503274f1cd5a3fd15a49", 16), ) DSA_KEY_2048 = DSAPrivateNumbers( public_numbers=DSAPublicNumbers( parameter_numbers=DSAParameterNumbers( p=int( - 'ea1fb1af22881558ef93be8a5f8653c5a559434c49c8c2c12ace5e9c4' - '1434c9cf0a8e9498acb0f4663c08b4484eace845f6fb17dac62c98e70' - '6af0fc74e4da1c6c2b3fbf5a1d58ff82fc1a66f3e8b12252c40278fff' - '9dd7f102eed2cb5b7323ebf1908c234d935414dded7f8d244e54561b0' - 'dca39b301de8c49da9fb23df33c6182e3f983208c560fb5119fbf78eb' - 'e3e6564ee235c6a15cbb9ac247baba5a423bc6582a1a9d8a2b4f0e9e3' - 'd9dbac122f750dd754325135257488b1f6ecabf21bff2947fe0d3b2cb' - '7ffe67f4e7fcdf1214f6053e72a5bb0dd20a0e9fe6db2df0a908c36e9' - '5e60bf49ca4368b8b892b9c79f61ef91c47567c40e1f80ac5aa66ef7', - 16 + "ea1fb1af22881558ef93be8a5f8653c5a559434c49c8c2c12ace5e9c4" + "1434c9cf0a8e9498acb0f4663c08b4484eace845f6fb17dac62c98e70" + "6af0fc74e4da1c6c2b3fbf5a1d58ff82fc1a66f3e8b12252c40278fff" + "9dd7f102eed2cb5b7323ebf1908c234d935414dded7f8d244e54561b0" + "dca39b301de8c49da9fb23df33c6182e3f983208c560fb5119fbf78eb" + "e3e6564ee235c6a15cbb9ac247baba5a423bc6582a1a9d8a2b4f0e9e3" + "d9dbac122f750dd754325135257488b1f6ecabf21bff2947fe0d3b2cb" + "7ffe67f4e7fcdf1214f6053e72a5bb0dd20a0e9fe6db2df0a908c36e9" + "5e60bf49ca4368b8b892b9c79f61ef91c47567c40e1f80ac5aa66ef7", + 16, ), q=int( - '8ec73f3761caf5fdfe6e4e82098bf10f898740dcb808204bf6b18f507' - '192c19d', 16 + "8ec73f3761caf5fdfe6e4e82098bf10f898740dcb808204bf6b18f507" + "192c19d", + 16, ), g=int( - 'e4c4eca88415b23ecf811c96e48cd24200fe916631a68a684e6ccb6b1' - '913413d344d1d8d84a333839d88eee431521f6e357c16e6a93be111a9' - '8076739cd401bab3b9d565bf4fb99e9d185b1e14d61c93700133f908b' - 'ae03e28764d107dcd2ea7674217622074bb19efff482f5f5c1a86d555' - '1b2fc68d1c6e9d8011958ef4b9c2a3a55d0d3c882e6ad7f9f0f3c6156' - '8f78d0706b10a26f23b4f197c322b825002284a0aca91807bba98ece9' - '12b80e10cdf180cf99a35f210c1655fbfdd74f13b1b5046591f840387' - '3d12239834dd6c4eceb42bf7482e1794a1601357b629ddfa971f2ed27' - '3b146ec1ca06d0adf55dd91d65c37297bda78c6d210c0bc26e558302', - 16 - ) + "e4c4eca88415b23ecf811c96e48cd24200fe916631a68a684e6ccb6b1" + "913413d344d1d8d84a333839d88eee431521f6e357c16e6a93be111a9" + "8076739cd401bab3b9d565bf4fb99e9d185b1e14d61c93700133f908b" + "ae03e28764d107dcd2ea7674217622074bb19efff482f5f5c1a86d555" + "1b2fc68d1c6e9d8011958ef4b9c2a3a55d0d3c882e6ad7f9f0f3c6156" + "8f78d0706b10a26f23b4f197c322b825002284a0aca91807bba98ece9" + "12b80e10cdf180cf99a35f210c1655fbfdd74f13b1b5046591f840387" + "3d12239834dd6c4eceb42bf7482e1794a1601357b629ddfa971f2ed27" + "3b146ec1ca06d0adf55dd91d65c37297bda78c6d210c0bc26e558302", + 16, + ), ), y=int( - '6b32e31ab9031dc4dd0b5039a78d07826687ab087ae6de4736f5b0434e125' - '3092e8a0b231f9c87f3fc8a4cb5634eb194bf1b638b7a7889620ce6711567' - 'e36aa36cda4604cfaa601a45918371d4ccf68d8b10a50a0460eb1dc0fff62' - 'ef5e6ee4d473e18ea4a66c196fb7e677a49b48241a0b4a97128eff30fa437' - '050501a584f8771e7280d26d5af30784039159c11ebfea10b692fd0a58215' - 'eeb18bff117e13f08db792ed4151a218e4bed8dddfb0793225bd1e9773505' - '166f4bd8cedbb286ea28232972da7bae836ba97329ba6b0a36508e50a52a7' - '675e476d4d4137eae13f22a9d2fefde708ba8f34bf336c6e76331761e4b06' - '17633fe7ec3f23672fb19d27', 16 - ) + "6b32e31ab9031dc4dd0b5039a78d07826687ab087ae6de4736f5b0434e125" + "3092e8a0b231f9c87f3fc8a4cb5634eb194bf1b638b7a7889620ce6711567" + "e36aa36cda4604cfaa601a45918371d4ccf68d8b10a50a0460eb1dc0fff62" + "ef5e6ee4d473e18ea4a66c196fb7e677a49b48241a0b4a97128eff30fa437" + "050501a584f8771e7280d26d5af30784039159c11ebfea10b692fd0a58215" + "eeb18bff117e13f08db792ed4151a218e4bed8dddfb0793225bd1e9773505" + "166f4bd8cedbb286ea28232972da7bae836ba97329ba6b0a36508e50a52a7" + "675e476d4d4137eae13f22a9d2fefde708ba8f34bf336c6e76331761e4b06" + "17633fe7ec3f23672fb19d27", + 16, + ), ), x=int( - '405772da6e90d809e77d5de796562a2dd4dfd10ef00a83a3aba6bd818a0348a1', - 16 - ) + "405772da6e90d809e77d5de796562a2dd4dfd10ef00a83a3aba6bd818a0348a1", 16 + ), ) DSA_KEY_3072 = DSAPrivateNumbers( public_numbers=DSAPublicNumbers( parameter_numbers=DSAParameterNumbers( p=int( - 'f335666dd1339165af8b9a5e3835adfe15c158e4c3c7bd53132e7d582' - '8c352f593a9a787760ce34b789879941f2f01f02319f6ae0b756f1a84' - '2ba54c85612ed632ee2d79ef17f06b77c641b7b080aff52a03fc2462e' - '80abc64d223723c236deeb7d201078ec01ca1fbc1763139e25099a84e' - 'c389159c409792080736bd7caa816b92edf23f2c351f90074aa5ea265' - '1b372f8b58a0a65554db2561d706a63685000ac576b7e4562e262a142' - '85a9c6370b290e4eb7757527d80b6c0fd5df831d36f3d1d35f12ab060' - '548de1605fd15f7c7aafed688b146a02c945156e284f5b71282045aba' - '9844d48b5df2e9e7a5887121eae7d7b01db7cdf6ff917cd8eb50c6bf1' - 'd54f90cce1a491a9c74fea88f7e7230b047d16b5a6027881d6f154818' - 'f06e513faf40c8814630e4e254f17a47bfe9cb519b98289935bf17673' - 'ae4c8033504a20a898d0032ee402b72d5986322f3bdfb27400561f747' - '6cd715eaabb7338b854e51fc2fa026a5a579b6dcea1b1c0559c13d3c1' - '136f303f4b4d25ad5b692229957', 16 + "f335666dd1339165af8b9a5e3835adfe15c158e4c3c7bd53132e7d582" + "8c352f593a9a787760ce34b789879941f2f01f02319f6ae0b756f1a84" + "2ba54c85612ed632ee2d79ef17f06b77c641b7b080aff52a03fc2462e" + "80abc64d223723c236deeb7d201078ec01ca1fbc1763139e25099a84e" + "c389159c409792080736bd7caa816b92edf23f2c351f90074aa5ea265" + "1b372f8b58a0a65554db2561d706a63685000ac576b7e4562e262a142" + "85a9c6370b290e4eb7757527d80b6c0fd5df831d36f3d1d35f12ab060" + "548de1605fd15f7c7aafed688b146a02c945156e284f5b71282045aba" + "9844d48b5df2e9e7a5887121eae7d7b01db7cdf6ff917cd8eb50c6bf1" + "d54f90cce1a491a9c74fea88f7e7230b047d16b5a6027881d6f154818" + "f06e513faf40c8814630e4e254f17a47bfe9cb519b98289935bf17673" + "ae4c8033504a20a898d0032ee402b72d5986322f3bdfb27400561f747" + "6cd715eaabb7338b854e51fc2fa026a5a579b6dcea1b1c0559c13d3c1" + "136f303f4b4d25ad5b692229957", + 16, ), q=int( - 'd3eba6521240694015ef94412e08bf3cf8d635a455a398d6f210f6169' - '041653b', 16 + "d3eba6521240694015ef94412e08bf3cf8d635a455a398d6f210f6169" + "041653b", + 16, ), g=int( - 'ce84b30ddf290a9f787a7c2f1ce92c1cbf4ef400e3cd7ce4978db2104' - 'd7394b493c18332c64cec906a71c3778bd93341165dee8e6cd4ca6f13' - 'afff531191194ada55ecf01ff94d6cf7c4768b82dd29cd131aaf202ae' - 'fd40e564375285c01f3220af4d70b96f1395420d778228f1461f5d0b8' - 'e47357e87b1fe3286223b553e3fc9928f16ae3067ded6721bedf1d1a0' - '1bfd22b9ae85fce77820d88cdf50a6bde20668ad77a707d1c60fcc5d5' - '1c9de488610d0285eb8ff721ff141f93a9fb23c1d1f7654c07c46e588' - '36d1652828f71057b8aff0b0778ef2ca934ea9d0f37daddade2d823a4' - 'd8e362721082e279d003b575ee59fd050d105dfd71cd63154efe431a0' - '869178d9811f4f231dc5dcf3b0ec0f2b0f9896c32ec6c7ee7d60aa971' - '09e09224907328d4e6acd10117e45774406c4c947da8020649c3168f6' - '90e0bd6e91ac67074d1d436b58ae374523deaf6c93c1e6920db4a080b' - '744804bb073cecfe83fa9398cf150afa286dc7eb7949750cf5001ce10' - '4e9187f7e16859afa8fd0d775ae', 16 - ) + "ce84b30ddf290a9f787a7c2f1ce92c1cbf4ef400e3cd7ce4978db2104" + "d7394b493c18332c64cec906a71c3778bd93341165dee8e6cd4ca6f13" + "afff531191194ada55ecf01ff94d6cf7c4768b82dd29cd131aaf202ae" + "fd40e564375285c01f3220af4d70b96f1395420d778228f1461f5d0b8" + "e47357e87b1fe3286223b553e3fc9928f16ae3067ded6721bedf1d1a0" + "1bfd22b9ae85fce77820d88cdf50a6bde20668ad77a707d1c60fcc5d5" + "1c9de488610d0285eb8ff721ff141f93a9fb23c1d1f7654c07c46e588" + "36d1652828f71057b8aff0b0778ef2ca934ea9d0f37daddade2d823a4" + "d8e362721082e279d003b575ee59fd050d105dfd71cd63154efe431a0" + "869178d9811f4f231dc5dcf3b0ec0f2b0f9896c32ec6c7ee7d60aa971" + "09e09224907328d4e6acd10117e45774406c4c947da8020649c3168f6" + "90e0bd6e91ac67074d1d436b58ae374523deaf6c93c1e6920db4a080b" + "744804bb073cecfe83fa9398cf150afa286dc7eb7949750cf5001ce10" + "4e9187f7e16859afa8fd0d775ae", + 16, + ), ), y=int( - '814824e435e1e6f38daa239aad6dad21033afce6a3ebd35c1359348a0f241' - '8871968c2babfc2baf47742148828f8612183178f126504da73566b6bab33' - 'ba1f124c15aa461555c2451d86c94ee21c3e3fc24c55527e01b1f03adcdd8' - 'ec5cb08082803a7b6a829c3e99eeb332a2cf5c035b0ce0078d3d414d31fa4' - '7e9726be2989b8d06da2e6cd363f5a7d1515e3f4925e0b32adeae3025cc5a' - '996f6fd27494ea408763de48f3bb39f6a06514b019899b312ec570851637b' - '8865cff3a52bf5d54ad5a19e6e400a2d33251055d0a440b50d53f4791391d' - 'c754ad02b9eab74c46b4903f9d76f824339914db108057af7cde657d41766' - 'a99991ac8787694f4185d6f91d7627048f827b405ec67bf2fe56141c4c581' - 'd8c317333624e073e5879a82437cb0c7b435c0ce434e15965db1315d64895' - '991e6bbe7dac040c42052408bbc53423fd31098248a58f8a67da3a39895cd' - '0cc927515d044c1e3cb6a3259c3d0da354cce89ea3552c59609db10ee9899' - '86527436af21d9485ddf25f90f7dff6d2bae', 16 - ) + "814824e435e1e6f38daa239aad6dad21033afce6a3ebd35c1359348a0f241" + "8871968c2babfc2baf47742148828f8612183178f126504da73566b6bab33" + "ba1f124c15aa461555c2451d86c94ee21c3e3fc24c55527e01b1f03adcdd8" + "ec5cb08082803a7b6a829c3e99eeb332a2cf5c035b0ce0078d3d414d31fa4" + "7e9726be2989b8d06da2e6cd363f5a7d1515e3f4925e0b32adeae3025cc5a" + "996f6fd27494ea408763de48f3bb39f6a06514b019899b312ec570851637b" + "8865cff3a52bf5d54ad5a19e6e400a2d33251055d0a440b50d53f4791391d" + "c754ad02b9eab74c46b4903f9d76f824339914db108057af7cde657d41766" + "a99991ac8787694f4185d6f91d7627048f827b405ec67bf2fe56141c4c581" + "d8c317333624e073e5879a82437cb0c7b435c0ce434e15965db1315d64895" + "991e6bbe7dac040c42052408bbc53423fd31098248a58f8a67da3a39895cd" + "0cc927515d044c1e3cb6a3259c3d0da354cce89ea3552c59609db10ee9899" + "86527436af21d9485ddf25f90f7dff6d2bae", + 16, + ), ), x=int( - 'b2764c46113983777d3e7e97589f1303806d14ad9f2f1ef033097de954b17706', - 16 - ) + "b2764c46113983777d3e7e97589f1303806d14ad9f2f1ef033097de954b17706", 16 + ), ) diff --git a/tests/hazmat/primitives/fixtures_ec.py b/tests/hazmat/primitives/fixtures_ec.py index 21c6903173e1..d1d0a46ffe25 100644 --- a/tests/hazmat/primitives/fixtures_ec.py +++ b/tests/hazmat/primitives/fixtures_ec.py @@ -9,288 +9,272 @@ EC_KEY_SECT571R1 = ec.EllipticCurvePrivateNumbers( private_value=int( - '213997069697108634621868251335076179190383272087548888968788698953' - '131928375431570122753130054966269038244076049869476736547896549201' - '7388482714521707824160638375437887802901' + "213997069697108634621868251335076179190383272087548888968788698953" + "131928375431570122753130054966269038244076049869476736547896549201" + "7388482714521707824160638375437887802901" ), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECT571R1(), x=int( - '42585672410900520895287019432267514156432686681290164230262278' - '54789182447139054594501570747809649335533486119017169439209005' - '883737780433424425566023654583165324498640038089' + "42585672410900520895287019432267514156432686681290164230262278" + "54789182447139054594501570747809649335533486119017169439209005" + "883737780433424425566023654583165324498640038089" ), y=int( - '13822523320209387572500458104799806851658024537477228250738334' - '46977851514777531296572763848253279034733550774927720436494321' - '97281333379623823457479233585424800362717541750' - ) - ) + "13822523320209387572500458104799806851658024537477228250738334" + "46977851514777531296572763848253279034733550774927720436494321" + "97281333379623823457479233585424800362717541750" + ), + ), ) EC_KEY_SECT409R1 = ec.EllipticCurvePrivateNumbers( private_value=int( - '604993237916498765317587097853603474519114726157206838874832379003' - '281871982139714656205843929472002062791572217653118715727' + "604993237916498765317587097853603474519114726157206838874832379003" + "281871982139714656205843929472002062791572217653118715727" ), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECT409R1(), x=int( - '76237701339268928039087238870073679814646664010783544301589269' - '2272579213400205907766385199643053767195204247826349822350081' + "76237701339268928039087238870073679814646664010783544301589269" + "2272579213400205907766385199643053767195204247826349822350081" ), y=int( - '10056668929618383045204866060110626563392345494925302478351744' - '01475129090774493235522729123877384838835703483224447476728811' - ) - ) + "10056668929618383045204866060110626563392345494925302478351744" + "01475129090774493235522729123877384838835703483224447476728811" + ), + ), ) EC_KEY_SECT283R1 = ec.EllipticCurvePrivateNumbers( private_value=int( - '589705077255658434962118789801402573495547207239917043241273753671' - '0603230261342427657' + "589705077255658434962118789801402573495547207239917043241273753671" + "0603230261342427657" ), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECT283R1(), x=int( - '10694213430317013187241490088760888472172922291550831393222973' - '531614941756901942108493' + "10694213430317013187241490088760888472172922291550831393222973" + "531614941756901942108493" ), y=int( - '11461553100313943515373601367527399649593366728262918214942116' - '4359557613202950705170' - ) - ) + "11461553100313943515373601367527399649593366728262918214942116" + "4359557613202950705170" + ), + ), ) EC_KEY_SECT233R1 = ec.EllipticCurvePrivateNumbers( private_value=int( - '343470067105388144757135261232658742142830154753739648095101899829' - '8288' + "343470067105388144757135261232658742142830154753739648095101899829" + "8288" ), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECT233R1(), x=int( - '74494951569151557692195071465128140646140765188698294062550374' - '71118267' + "74494951569151557692195071465128140646140765188698294062550374" + "71118267" ), y=int( - '48699150823022962508544923825876164485917001162461401797511748' - '44872205' - ) - ) + "48699150823022962508544923825876164485917001162461401797511748" + "44872205" + ), + ), ) EC_KEY_SECT163R2 = ec.EllipticCurvePrivateNumbers( - private_value=int( - '11788436193853888218177032687141056784083668635' - ), + private_value=int("11788436193853888218177032687141056784083668635"), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECT163R2(), - x=int( - '5247234453330640212490501030772203801908103222463' - ), - y=int( - '3172513801099088785224248292142866317754124455206' - ) - ) + x=int("5247234453330640212490501030772203801908103222463"), + y=int("3172513801099088785224248292142866317754124455206"), + ), ) EC_KEY_SECT571K1 = ec.EllipticCurvePrivateNumbers( private_value=int( - '592811051234886966121888758661314648311634839499582476726008738218' - '165015048237934517672316204181933804884636855291118594744334592153' - '883208936227914544246799490897169723387' + "592811051234886966121888758661314648311634839499582476726008738218" + "165015048237934517672316204181933804884636855291118594744334592153" + "883208936227914544246799490897169723387" ), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECT571K1(), x=int( - '81362471461936552203898455874182916939857774872643607884250052' - '29301336524105230729653881789373412990921493551253481866317181' - '50644729351721577822595637058949405764944491655' + "81362471461936552203898455874182916939857774872643607884250052" + "29301336524105230729653881789373412990921493551253481866317181" + "50644729351721577822595637058949405764944491655" ), y=int( - '14058041260812945396067821061063618047896814719828637241661260' - '31235681542401975593036630733881695595289523801041910183736211' - '587294494888450327374439795428519848065589000434' - ) - ) + "14058041260812945396067821061063618047896814719828637241661260" + "31235681542401975593036630733881695595289523801041910183736211" + "587294494888450327374439795428519848065589000434" + ), + ), ) EC_KEY_SECT409K1 = ec.EllipticCurvePrivateNumbers( private_value=int( - '110321743150399087059465162400463719641470113494908091197354523708' - '934106732952992153105338671368548199643686444619485307877' + "110321743150399087059465162400463719641470113494908091197354523708" + "934106732952992153105338671368548199643686444619485307877" ), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECT409K1(), x=int( - '62280214209410363493525178797944995742119600145953755916426161' - '0790364158569265348038207313261547476506319796469776797725796' + "62280214209410363493525178797944995742119600145953755916426161" + "0790364158569265348038207313261547476506319796469776797725796" ), y=int( - '46653883749102474289095010108777579907422472804577185369332018' - '7318642669590280811057512951467298158275464566214288556375885' - ) - ) + "46653883749102474289095010108777579907422472804577185369332018" + "7318642669590280811057512951467298158275464566214288556375885" + ), + ), ) EC_KEY_SECT283K1 = ec.EllipticCurvePrivateNumbers( private_value=int( - '182508394415444014156574733141549331538128234395356466108310015130' - '3868915489347291850' + "182508394415444014156574733141549331538128234395356466108310015130" + "3868915489347291850" ), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECT283K1(), x=int( - '31141647206111886426350703123670451554123180910379592764773885' - '2959123367428352287032' + "31141647206111886426350703123670451554123180910379592764773885" + "2959123367428352287032" ), y=int( - '71787460144483665964585187837283963089964760704065205376175384' - '58957627834444017112582' - ) - ) + "71787460144483665964585187837283963089964760704065205376175384" + "58957627834444017112582" + ), + ), ) EC_KEY_SECT233K1 = ec.EllipticCurvePrivateNumbers( private_value=int( - '172670089647474613734091436081960550801254775902629891892394471086' - '2070' + "172670089647474613734091436081960550801254775902629891892394471086" + "2070" ), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECT233K1(), x=int( - '55693911474339510991521579392202889561373678973929426354737048' - '68129172' + "55693911474339510991521579392202889561373678973929426354737048" + "68129172" ), y=int( - '11025856248546376145959939911850923631416718241836051344384802' - '737277815' - ) - ) + "11025856248546376145959939911850923631416718241836051344384802" + "737277815" + ), + ), ) EC_KEY_SECT163K1 = ec.EllipticCurvePrivateNumbers( - private_value=int( - '3699303791425402204035307605170569820290317991287' - ), + private_value=int("3699303791425402204035307605170569820290317991287"), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECT163K1(), - x=int( - '4479755902310063321544063130576409926980094120721' - ), - y=int( - '3051218481937171839039826690648109285113977745779' - ) - ) + x=int("4479755902310063321544063130576409926980094120721"), + y=int("3051218481937171839039826690648109285113977745779"), + ), ) EC_KEY_SECP521R1 = ec.EllipticCurvePrivateNumbers( private_value=int( - '662751235215460886290293902658128847495347691199214706697089140769' - '672273950767961331442265530524063943548846724348048614239791498442' - '5997823106818915698960565' + "662751235215460886290293902658128847495347691199214706697089140769" + "672273950767961331442265530524063943548846724348048614239791498442" + "5997823106818915698960565" ), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECP521R1(), x=int( - '12944742826257420846659527752683763193401384271391513286022917' - '29910013082920512632908350502247952686156279140016049549948975' - '670668730618745449113644014505462' + "12944742826257420846659527752683763193401384271391513286022917" + "29910013082920512632908350502247952686156279140016049549948975" + "670668730618745449113644014505462" ), y=int( - '10784108810271976186737587749436295782985563640368689081052886' - '16296815984553198866894145509329328086635278430266482551941240' - '591605833440825557820439734509311' - ) - ) + "10784108810271976186737587749436295782985563640368689081052886" + "16296815984553198866894145509329328086635278430266482551941240" + "591605833440825557820439734509311" + ), + ), ) EC_KEY_SECP384R1 = ec.EllipticCurvePrivateNumbers( private_value=int( - '280814107134858470598753916394807521398239633534281633982576099083' - '35787109896602102090002196616273211495718603965098' + "280814107134858470598753916394807521398239633534281633982576099083" + "35787109896602102090002196616273211495718603965098" ), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECP384R1(), x=int( - '10036914308591746758780165503819213553101287571902957054148542' - '504671046744460374996612408381962208627004841444205030' + "10036914308591746758780165503819213553101287571902957054148542" + "504671046744460374996612408381962208627004841444205030" ), y=int( - '17337335659928075994560513699823544906448896792102247714689323' - '575406618073069185107088229463828921069465902299522926' - ) - ) + "17337335659928075994560513699823544906448896792102247714689323" + "575406618073069185107088229463828921069465902299522926" + ), + ), ) EC_KEY_SECP256R1 = ec.EllipticCurvePrivateNumbers( private_value=int( - '271032978511595617649844168316234344656921218699414461240502635010' - '25776962849' + "271032978511595617649844168316234344656921218699414461240502635010" + "25776962849" ), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECP256R1(), x=int( - '49325986169170464532722748935508337546545346352733747948730305' - '442770101441241' + "49325986169170464532722748935508337546545346352733747948730305" + "442770101441241" ), y=int( - '51709162888529903487188595007092772817469799707382623884187518' - '455962250433661' - ) - ) + "51709162888529903487188595007092772817469799707382623884187518" + "455962250433661" + ), + ), ) EC_KEY_SECP256K1 = ec.EllipticCurvePrivateNumbers( private_value=int( - '683341569008473593765879222774207677458810362976327530563215318048' - '64380736732' + "683341569008473593765879222774207677458810362976327530563215318048" + "64380736732" ), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECP256K1(), x=int( - '59251322975795306609293064274738085741081547489119277536110995' - '120127593127884' + "59251322975795306609293064274738085741081547489119277536110995" + "120127593127884" ), y=int( - '10334192001480392039227801832201340147605940717841294644187071' - '8261641142297801' - ) - ) + "10334192001480392039227801832201340147605940717841294644187071" + "8261641142297801" + ), + ), ) EC_KEY_SECP224R1 = ec.EllipticCurvePrivateNumbers( private_value=int( - '234854340492774342642505519082413233282383066880756900834047566251' - '50' + "234854340492774342642505519082413233282383066880756900834047566251" + "50" ), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECP224R1(), x=int( - '51165676638271204691095081341581621487998422645261573824239666' - '1214' + "51165676638271204691095081341581621487998422645261573824239666" + "1214" ), y=int( - '14936601450555711309158397172719963843891926209168533453717969' - '1265' - ) - ) + "14936601450555711309158397172719963843891926209168533453717969" + "1265" + ), + ), ) EC_KEY_SECP192R1 = ec.EllipticCurvePrivateNumbers( private_value=int( - '4534766128536179420071447168915990251715442361606049349869' + "4534766128536179420071447168915990251715442361606049349869" ), public_numbers=ec.EllipticCurvePublicNumbers( curve=ec.SECP192R1(), - x=int( - '5415069751170397888083674339683360671310515485781457536999' - ), - y=int( - '18671605334415960797751252911958331304288357195986572776' - ) - ) + x=int("5415069751170397888083674339683360671310515485781457536999"), + y=int("18671605334415960797751252911958331304288357195986572776"), + ), ) diff --git a/tests/hazmat/primitives/fixtures_rsa.py b/tests/hazmat/primitives/fixtures_rsa.py index a531783e5847..2c0627282130 100644 --- a/tests/hazmat/primitives/fixtures_rsa.py +++ b/tests/hazmat/primitives/fixtures_rsa.py @@ -5,7 +5,8 @@ from __future__ import absolute_import, division, print_function from cryptography.hazmat.primitives.asymmetric.rsa import ( - RSAPrivateNumbers, RSAPublicNumbers + RSAPrivateNumbers, + RSAPublicNumbers, ) @@ -18,7 +19,8 @@ ), d=int( "272869352cacf9c866c4e107acc95d4c608ca91460a93d28588d51cfccc07f449" - "18bbe7660f9f16adc2b4ed36ca310ef3d63b79bd447456e3505736a45a6ed21", 16 + "18bbe7660f9f16adc2b4ed36ca310ef3d63b79bd447456e3505736a45a6ed21", + 16, ), dmp1=int( "addff2ec7564c6b64bc670d250b6f24b0b8db6b2810099813b7e7658cecf5c39", 16 @@ -34,178 +36,239 @@ n=int( "ae5411f963c50e3267fafcf76381c8b1e5f7b741fdb2a544bcf48bd607b10c991" "90caeb8011dc22cf83d921da55ec32bd05cac3ee02ca5e1dbef93952850b525", - 16 + 16, ), - ) + ), ) RSA_KEY_512_ALT = RSAPrivateNumbers( p=int( - "febe19c29a0b50fefa4f7b1832f84df1caf9be8242da25c9d689e18226e67ce5", - 16), + "febe19c29a0b50fefa4f7b1832f84df1caf9be8242da25c9d689e18226e67ce5", 16 + ), q=int( - "eb616c639dd999feda26517e1c77b6878f363fe828c4e6670ec1787f28b1e731", - 16), + "eb616c639dd999feda26517e1c77b6878f363fe828c4e6670ec1787f28b1e731", 16 + ), d=int( "80edecfde704a806445a4cc782b85d3f36f17558f385654ea767f006470fdfcbda5e2" - "206839289d3f419b4e4fb8e1acee1b4fb9c591f69b64ec83937f5829241", 16), + "206839289d3f419b4e4fb8e1acee1b4fb9c591f69b64ec83937f5829241", + 16, + ), dmp1=int( - "7f4fa06e2a3077a54691cc5216bf13ad40a4b9fa3dd0ea4bca259487484baea5", - 16), + "7f4fa06e2a3077a54691cc5216bf13ad40a4b9fa3dd0ea4bca259487484baea5", 16 + ), dmq1=int( - "35eaa70d5a8711c352ed1c15ab27b0e3f46614d575214535ae279b166597fac1", - 16), + "35eaa70d5a8711c352ed1c15ab27b0e3f46614d575214535ae279b166597fac1", 16 + ), iqmp=int( - "cc1f272de6846851ec80cb89a02dbac78f44b47bc08f53b67b4651a3acde8b19", - 16), + "cc1f272de6846851ec80cb89a02dbac78f44b47bc08f53b67b4651a3acde8b19", 16 + ), public_numbers=RSAPublicNumbers( e=65537, n=int( "ea397388b999ef0f7e7416fa000367efd9a0ba0deddd3f8160d1c36d62267f210" "fbd9c97abeb6654450ff03e7601b8caa6c6f4cba18f0b52c179d17e8f258ad5", - 16), - ) + 16, + ), + ), ) RSA_KEY_522 = RSAPrivateNumbers( p=int( "1a8aab9a069f92b52fdf05824f2846223dc27adfc806716a247a77d4c36885e4bf", - 16), + 16, + ), q=int( "19e8d620d177ec54cdb733bb1915e72ef644b1202b889ceb524613efa49c07eb4f", - 16), + 16, + ), d=int( "10b8a7c0a92c1ae2d678097d69db3bfa966b541fb857468291d48d1b52397ea2bac0d" - "4370c159015c7219e3806a01bbafaffdd46f86e3da1e2d1fe80a0369ccd745", 16), + "4370c159015c7219e3806a01bbafaffdd46f86e3da1e2d1fe80a0369ccd745", + 16, + ), dmp1=int( - "3eb6277f66e6e2dcf89f1b8529431f730839dbd9a3e49555159bc8470eee886e5", - 16), + "3eb6277f66e6e2dcf89f1b8529431f730839dbd9a3e49555159bc8470eee886e5", 16 + ), dmq1=int( "184b4d74aa54c361e51eb23fee4eae5e4786b37b11b6e0447af9c0b9c4e4953c5b", - 16), + 16, + ), iqmp=int( - "f80e9ab4fa7b35d0d232ef51c4736d1f2dcf2c7b1dd8716211b1bf1337e74f8ae", - 16), + "f80e9ab4fa7b35d0d232ef51c4736d1f2dcf2c7b1dd8716211b1bf1337e74f8ae", 16 + ), public_numbers=RSAPublicNumbers( e=65537, n=int( "2afaea0e0bb6fca037da7d190b5270a6c665bc18e7a456f7e69beaac4433db748" "ba99acdd14697e453bca596eb35b47f2d48f1f85ef08ce5109dad557a9cf85ebf" - "1", 16), + "1", + 16, + ), ), ) RSA_KEY_599 = RSAPrivateNumbers( p=int( "cf95d20be0c7af69f4b3d909f65d858c26d1a7ef34da8e3977f4fa230580e58814b54" - "24be99", 16), + "24be99", + 16, + ), q=int( "6052be4b28debd4265fe12ace5aa4a0c4eb8d63ff8853c66824b35622161eb48a3bc8" - "c3ada5", 16), + "c3ada5", + 16, + ), d=int( "69d9adc465e61585d3142d7cc8dd30605e8d1cbbf31009bc2cd5538dc40528d5d68ee" "fe6a42d23674b6ec76e192351bf368c8968f0392110bf1c2825dbcff071270b80adcc" - "fa1d19d00a1", 16), + "fa1d19d00a1", + 16, + ), dmp1=int( "a86d10edde456687fba968b1f298d2e07226adb1221b2a466a93f3d83280f0bb46c20" - "2b6811", 16), + "2b6811", + 16, + ), dmq1=int( "40d570e08611e6b1da94b95d46f8e7fe80be48f7a5ff8838375b08039514a399b11c2" - "80735", 16), + "80735", + 16, + ), iqmp=int( "cd051cb0ea68b88765c041262ace2ec4db11dab14afd192742e34d5da3328637fabdf" - "bae26e", 16), + "bae26e", + 16, + ), public_numbers=RSAPublicNumbers( e=65537, n=int( "4e1b470fe00642426f3808e74c959632dd67855a4c503c5b7876ccf4dc7f6a1a4" "9107b90d26daf0a7879a6858218345fbc6e59f01cd095ca5647c27c25265e6c47" - "4fea89537191c7073d9d", 16), - ) + "4fea89537191c7073d9d", + 16, + ), + ), ) RSA_KEY_745 = RSAPrivateNumbers( p=int( "1c5a0cfe9a86debd19eca33ba961f15bc598aa7983a545ce775b933afc89eb51bcf90" - "836257fdd060d4b383240241d", 16 + "836257fdd060d4b383240241d", + 16, ), q=int( "fb2634f657f82ee6b70553382c4e2ed26b947c97ce2f0016f1b282cf2998184ad0527" - "a9eead826dd95fe06b57a025", 16 + "a9eead826dd95fe06b57a025", + 16, ), d=int( "402f30f976bc07d15ff0779abff127b20a8b6b1d0024cc2ad8b6762d38f174f81e792" "3b49d80bdbdd80d9675cbc7b2793ec199a0430eb5c84604dacfdb29259ae6a1a44676" - "22f0b23d4cb0f5cb1db4b8173c8d9d3e57a74dbd200d2141", 16), + "22f0b23d4cb0f5cb1db4b8173c8d9d3e57a74dbd200d2141", + 16, + ), dmp1=int( "e5e95b7751a6649f199be21bef7a51c9e49821d945b6fc5f538b4a670d8762c375b00" - "8e70f31d52b3ea2bd14c3101", 16), + "8e70f31d52b3ea2bd14c3101", + 16, + ), dmq1=int( "12b85d5843645f72990fcf8d2f58408b34b3a3b9d9078dd527fceb5d2fb7839008092" - "dd4aca2a1fb00542801dcef5", 16), + "dd4aca2a1fb00542801dcef5", + 16, + ), iqmp=int( "5672740d947f621fc7969e3a44ec26736f3f819863d330e63e9409e139d20753551ac" - "c16544dd2bdadb9dee917440", 16), + "c16544dd2bdadb9dee917440", + 16, + ), public_numbers=RSAPublicNumbers( e=65537, n=int( "1bd085f92237774d34013b477ceebbb2f2feca71118db9b7429341477947e7b1d" "04e8c43ede3c52bb25781af58d4ff81289f301eac62dc3bcd7dafd7a4d5304e9f" - "308e766952fbf2b62373e66611fa53189987dbef9f7243dcbbeb25831", 16), - ) + "308e766952fbf2b62373e66611fa53189987dbef9f7243dcbbeb25831", + 16, + ), + ), ) RSA_KEY_768 = RSAPrivateNumbers( p=int( "f80c0061b607f93206b68e208906498d68c6e396faf457150cf975c8f849848465869" - "7ecd402313397088044c4c2071b", 16), + "7ecd402313397088044c4c2071b", + 16, + ), q=int( "e5b5dbecc93c6d306fc14e6aa9737f9be2728bc1a326a8713d2849b34c1cb54c63468" - "3a68abb1d345dbf15a3c492cf55", 16), + "3a68abb1d345dbf15a3c492cf55", + 16, + ), d=int( "d44601442255ffa331212c60385b5e898555c75c0272632ff42d57c4b16ca97dbca9f" "d6d99cd2c9fd298df155ed5141b4be06c651934076133331d4564d73faed7ce98e283" - "2f7ce3949bc183be7e7ca34f6dd04a9098b6c73649394b0a76c541", 16), + "2f7ce3949bc183be7e7ca34f6dd04a9098b6c73649394b0a76c541", + 16, + ), dmp1=int( "a5763406fa0b65929661ce7b2b8c73220e43a5ebbfe99ff15ddf464fd238105ad4f2a" - "c83818518d70627d8908703bb03", 16), + "c83818518d70627d8908703bb03", + 16, + ), dmq1=int( "cb467a9ef899a39a685aecd4d0ad27b0bfdc53b68075363c373d8eb2bed8eccaf3533" - "42f4db735a9e087b7539c21ba9d", 16), + "42f4db735a9e087b7539c21ba9d", + 16, + ), iqmp=int( "5fe86bd3aee0c4d09ef11e0530a78a4534c9b833422813b5c934a450c8e564d8097a0" - "6fd74f1ebe2d5573782093f587a", 16), + "6fd74f1ebe2d5573782093f587a", + 16, + ), public_numbers=RSAPublicNumbers( e=65537, n=int( "de92f1eb5f4abf426b6cac9dd1e9bf57132a4988b4ed3f8aecc15e251028bd6df" "46eb97c711624af7db15e6430894d1b640c13929329241ee094f5a4fe1a20bc9b" "75232320a72bc567207ec54d6b48dccb19737cf63acc1021abb337f19130f7", - 16), - ) + 16, + ), + ), ) RSA_KEY_1024 = RSAPrivateNumbers( p=int( "ea4d9d9a1a068be44b9a5f8f6de0512b2c5ba1fb804a4655babba688e6e890b347c1a" - "7426685a929337f513ae4256f0b7e5022d642237f960c5b24b96bee8e51", 16), + "7426685a929337f513ae4256f0b7e5022d642237f960c5b24b96bee8e51", + 16, + ), q=int( "cffb33e400d6f08b410d69deb18a85cf0ed88fcca9f32d6f2f66c62143d49aff92c11" - "4de937d4f1f62d4635ee89af99ce86d38a2b05310f3857c7b5d586ac8f9", 16), + "4de937d4f1f62d4635ee89af99ce86d38a2b05310f3857c7b5d586ac8f9", + 16, + ), d=int( "3d12d46d04ce942fb99be7bf30587b8cd3e21d75a2720e7bda1b867f1d418d91d8b9f" "e1c00181fdde94f2faf33b4e6f800a1b3ae3b972ccb6d5079dcb6c794070ac8306d59" "c00b58b7a9a81122a6b055832de7c72334a07494d8e7c9fbeed2cc37e011d9e6bfc6e" - "9bcddbef7f0f5771d9cf82cd4b268c97ec684575c24b6c881", 16), + "9bcddbef7f0f5771d9cf82cd4b268c97ec684575c24b6c881", + 16, + ), dmp1=int( "470f2b11257b7ec9ca34136f487f939e6861920ad8a9ae132a02e74af5dceaa5b4c98" - "2949ccb44b67e2bcad2f58674db237fe250e0d62b47b28fa1dfaa603b41", 16), + "2949ccb44b67e2bcad2f58674db237fe250e0d62b47b28fa1dfaa603b41", + 16, + ), dmq1=int( "c616e8317d6b3ae8272973709b80e8397256697ff14ea03389de454f619f99915a617" - "45319fefbe154ec1d49441a772c2f63f7d15c478199afc60469bfd0d561", 16), + "45319fefbe154ec1d49441a772c2f63f7d15c478199afc60469bfd0d561", + 16, + ), iqmp=int( "d15e7c9ad357dfcd5dbdc8427680daf1006761bcfba93a7f86589ad88832a8d564b1c" - "d4291a658c96fbaea7ca588795820902d85caebd49c2d731e3fe0243130", 16), + "d4291a658c96fbaea7ca588795820902d85caebd49c2d731e3fe0243130", + 16, + ), public_numbers=RSAPublicNumbers( e=65537, n=int( @@ -213,31 +276,44 @@ "ede07be3bed0e355d48e0dfab1e4fb5187adf42d7d3fb0401c082acb8481bf17f" "0e871f8877be04c3a1197d40aa260e2e0c48ed3fd2b93dc3fc0867591f67f3cd6" "0a77adee1d68a8c3730a5702485f6ac9ede7f0fd2918e037ee4cc1fc1b4c9", - 16), - ) + 16, + ), + ), ) RSA_KEY_1025 = RSAPrivateNumbers( p=int( "18e9bfb7071725da04d31c103fa3563648c69def43a204989214eb57b0c8b299f9ef3" - "5dda79a62d8d67fd2a9b69fbd8d0490aa2edc1e111a2b8eb7c737bb691a5", 16), + "5dda79a62d8d67fd2a9b69fbd8d0490aa2edc1e111a2b8eb7c737bb691a5", + 16, + ), q=int( "d8eccaeeb95815f3079d13685f3f72ca2bf2550b349518049421375df88ca9bbb4ba8" - "cb0e3502203c9eeae174112509153445d251313e4711a102818c66fcbb7", 16), + "cb0e3502203c9eeae174112509153445d251313e4711a102818c66fcbb7", + 16, + ), d=int( "fe9ac54910b8b1bc948a03511c54cab206a1d36d50d591124109a48abb7480977ccb0" "47b4d4f1ce7b0805df2d4fa3fe425f49b78535a11f4b87a4eba0638b3340c23d4e6b2" "1ecebe9d5364ea6ead2d47b27836019e6ecb407000a50dc95a8614c9d0031a6e3a524" - "d2345cfb76e15c1f69d5ba35bdfb6ec63bcb115a757ef79d9", 16), + "d2345cfb76e15c1f69d5ba35bdfb6ec63bcb115a757ef79d9", + 16, + ), dmp1=int( "18537e81006a68ea76d590cc88e73bd26bc38d09c977959748e5265c0ce21c0b5fd26" - "53d975f97ef759b809f791487a8fff1264bf561627fb4527a3f0bbb72c85", 16), + "53d975f97ef759b809f791487a8fff1264bf561627fb4527a3f0bbb72c85", + 16, + ), dmq1=int( "c807eac5a1f1e1239f04b04dd16eff9a00565127a91046fa89e1eb5d6301cace85447" - "4d1f47b0332bd35b4214b66e9166953241538f761f30d969272ee214f17", 16), + "4d1f47b0332bd35b4214b66e9166953241538f761f30d969272ee214f17", + 16, + ), iqmp=int( "133aa74dd41fe70fa244f07d0c4091a22f8c8f0134fe6aea9ec8b55383b758fefe358" - "2beec36eca91715eee7d21931f24fa9e97e8e3a50f9cd0f731574a5eafcc", 16), + "2beec36eca91715eee7d21931f24fa9e97e8e3a50f9cd0f731574a5eafcc", + 16, + ), public_numbers=RSAPublicNumbers( e=65537, n=int( @@ -245,31 +321,44 @@ "bf276fe3523f38f5ddaf3ea9aa88486a9d8760ff732489075862bee0e599de5c5" "f509b4519f4f446521bad15cd279a498fe1e89107ce0d237e3103d7c5eb801666" "42e2924b152aebff97b71fdd2d68ebb45034cc784e2e822ff6d1edf98af3f3", - 16), - ) + 16, + ), + ), ) RSA_KEY_1026 = RSAPrivateNumbers( p=int( "1fcbfb8719c5bdb5fe3eb0937c76bb096e750b9442dfe31d6a877a13aed2a6a4e9f79" - "40f815f1c307dd6bc2b4b207bb6fe5be3a15bd2875a957492ce197cdedb1", 16), + "40f815f1c307dd6bc2b4b207bb6fe5be3a15bd2875a957492ce197cdedb1", + 16, + ), q=int( "1f704a0f6b8966dd52582fdc08227dd3dbaeaa781918b41144b692711091b4ca4eb62" - "985c3513853828ce8739001dfba9a9a7f1a23cbcaf74280be925e2e7b50d", 16), + "985c3513853828ce8739001dfba9a9a7f1a23cbcaf74280be925e2e7b50d", + 16, + ), d=int( "c67975e35a1d0d0b3ebfca736262cf91990cb31cf4ac473c0c816f3bc2720bcba2475" "e8d0de8535d257816c0fc53afc1b597eada8b229069d6ef2792fc23f59ffb4dc6c3d9" "0a3c462082025a4cba7561296dd3d8870c4440d779406f00879afe2c681e7f5ee055e" - "ff829e6e55883ec20830c72300762e6e3a333d94b4dbe4501", 16), + "ff829e6e55883ec20830c72300762e6e3a333d94b4dbe4501", + 16, + ), dmp1=int( "314730ca7066c55d086a9fbdf3670ef7cef816b9efea8b514b882ae9d647217cf41d7" - "e9989269dc9893d02e315cb81f058c49043c2cac47adea58bdf5e20e841", 16), + "e9989269dc9893d02e315cb81f058c49043c2cac47adea58bdf5e20e841", + 16, + ), dmq1=int( "1da28a9d687ff7cfeebc2439240de7505a8796376968c8ec723a2b669af8ce53d9c88" - "af18540bd78b2da429014923fa435f22697ac60812d7ca9c17a557f394cd", 16), + "af18540bd78b2da429014923fa435f22697ac60812d7ca9c17a557f394cd", + 16, + ), iqmp=int( "727947b57b8a36acd85180522f1b381bce5fdbd962743b3b14af98a36771a80f58ddd" - "62675d72a5935190da9ddc6fd6d6d5e9e9f805a2e92ab8d56b820493cdf", 16), + "62675d72a5935190da9ddc6fd6d6d5e9e9f805a2e92ab8d56b820493cdf", + 16, + ), public_numbers=RSAPublicNumbers( e=65537, n=int( @@ -277,31 +366,44 @@ "9cfae6ab0446da18e26f33e1d753bc1cc03585c100cf0ab5ef056695706fc8b0c" "9c710cd73fe6e5beda70f515a96fabd3cc5ac49efcb2594b220ff3b603fcd927f" "6a0838ef04bf52f3ed9eab801f09e5aed1613ddeb946ed0fbb02060b3a36fd", - 16), - ) + 16, + ), + ), ) RSA_KEY_1027 = RSAPrivateNumbers( p=int( "30135e54cfb072c3d3eaf2000f3ed92ceafc85efc867b9d4bf5612f2978c432040093" - "4829f741c0f002b54af2a4433ff872b6321ef00ff1e72cba4e0ced937c7d", 16), + "4829f741c0f002b54af2a4433ff872b6321ef00ff1e72cba4e0ced937c7d", + 16, + ), q=int( "1d01a8aead6f86b78c875f18edd74214e06535d65da054aeb8e1851d6f3319b4fb6d8" - "6b01e07d19f8261a1ded7dc08116345509ab9790e3f13e65c037e5bb7e27", 16), + "6b01e07d19f8261a1ded7dc08116345509ab9790e3f13e65c037e5bb7e27", + 16, + ), d=int( "21cf4477df79561c7818731da9b9c88cd793f1b4b8e175bd0bfb9c0941a4dc648ecf1" "6d96b35166c9ea116f4c2eb33ce1c231e641a37c25e54c17027bdec08ddafcb83642e" "795a0dd133155ccc5eed03b6e745930d9ac7cfe91f9045149f33295af03a2198c660f" - "08d8150d13ce0e2eb02f21ac75d63b55822f77bd5be8d07619", 16), + "08d8150d13ce0e2eb02f21ac75d63b55822f77bd5be8d07619", + 16, + ), dmp1=int( "173fb695931e845179511c18b546b265cb79b517c135902377281bdf9f34205e1f399" - "4603ad63e9f6e7885ea73a929f03fa0d6bed943051ce76cddde2d89d434d", 16), + "4603ad63e9f6e7885ea73a929f03fa0d6bed943051ce76cddde2d89d434d", + 16, + ), dmq1=int( "10956b387b2621327da0c3c8ffea2af8be967ee25163222746c28115a406e632a7f12" - "5a9397224f1fa5c116cd3a313e5c508d31db2deb83b6e082d213e33f7fcf", 16), + "5a9397224f1fa5c116cd3a313e5c508d31db2deb83b6e082d213e33f7fcf", + 16, + ), iqmp=int( "234f833949f2c0d797bc6a0e906331e17394fa8fbc8449395766d3a8d222cf6167c48" - "8e7fe1fe9721d3e3b699a595c8e6f063d92bd840dbc84d763b2b37002109", 16), + "8e7fe1fe9721d3e3b699a595c8e6f063d92bd840dbc84d763b2b37002109", + 16, + ), public_numbers=RSAPublicNumbers( e=65537, n=int( @@ -309,31 +411,44 @@ "0a5ae9f579ef1fd7e42937f921eb3123c4a045cc47a2159fbbf904783e654954c" "42294c30a95c15db7c7b91f136244e548f62474b137087346c5522e54f226f49d" "6c93bc58cb39972e41bde452bb3ae9d60eb93e5e1ce91d222138d9890c7d0b", - 16), - ) + 16, + ), + ), ) RSA_KEY_1028 = RSAPrivateNumbers( p=int( "359d17378fae8e9160097daee78a206bd52efe1b757c12a6da8026cc4fc4bb2620f12" - "b8254f4db6aed8228be8ee3e5a27ec7d31048602f01edb00befd209e8c75", 16), + "b8254f4db6aed8228be8ee3e5a27ec7d31048602f01edb00befd209e8c75", + 16, + ), q=int( "33a2e70b93d397c46e63b273dcd3dcfa64291342a6ce896e1ec8f1c0edc44106550f3" - "c06e7d3ca6ea29eccf3f6ab5ac6235c265313d6ea8e8767e6a343f616581", 16), + "c06e7d3ca6ea29eccf3f6ab5ac6235c265313d6ea8e8767e6a343f616581", + 16, + ), d=int( "880640088d331aa5c0f4cf2887809a420a2bc086e671e6ffe4e47a8c80792c038a314" "9a8e45ef9a72816ab45b36e3af6800351067a6b2751843d4232413146bb575491463a" "8addd06ce3d1bcf7028ec6c5d938c545a20f0a40214b5c574ca7e840062b2b5f8ed49" - "4b144bb2113677c4b10519177fee1d4f5fb8a1c159b0b47c01", 16), + "4b144bb2113677c4b10519177fee1d4f5fb8a1c159b0b47c01", + 16, + ), dmp1=int( "75f8c52dad2c1cea26b8bba63236ee4059489e3d2db766136098bcc6b67fde8f77cd3" - "640035107bfb1ffc6480983cfb84fe0c3be008424ebc968a7db7e01f005", 16), + "640035107bfb1ffc6480983cfb84fe0c3be008424ebc968a7db7e01f005", + 16, + ), dmq1=int( "3893c59469e4ede5cd0e6ff9837ca023ba9b46ff40c60ccf1bec10f7d38db5b1ba817" - "6c41a3f750ec4203b711455aca06d1e0adffc5cffa42bb92c7cb77a6c01", 16), + "6c41a3f750ec4203b711455aca06d1e0adffc5cffa42bb92c7cb77a6c01", + 16, + ), iqmp=int( "ad32aafae3c962ac25459856dc8ef1f733c3df697eced29773677f435d186cf759d1a" - "5563dd421ec47b4d7e7f12f29647c615166d9c43fc49001b29089344f65", 16), + "5563dd421ec47b4d7e7f12f29647c615166d9c43fc49001b29089344f65", + 16, + ), public_numbers=RSAPublicNumbers( e=65537, n=int( @@ -341,31 +456,44 @@ "e3510c68073954d3ba4deb38643e7a820a4cf06e75f7f82eca545d412bd637819" "45c28d406e95a6cced5ae924a8bfa4f3def3e0250d91246c269ec40c89c93a85a" "cd3770ba4d2e774732f43abe94394de43fb57f93ca25f7a59d75d400a3eff5", - 16), - ) + 16, + ), + ), ) RSA_KEY_1029 = RSAPrivateNumbers( p=int( "66f33e513c0b6b6adbf041d037d9b1f0ebf8de52812a3ac397a963d3f71ba64b3ad04" - "e4d4b5e377e6fa22febcac292c907dc8dcfe64c807fd9a7e3a698850d983", 16), + "e4d4b5e377e6fa22febcac292c907dc8dcfe64c807fd9a7e3a698850d983", + 16, + ), q=int( "3b47a89a19022461dcc2d3c05b501ee76955e8ce3cf821beb4afa85a21a26fd7203db" - "deb8941f1c60ada39fd6799f6c07eb8554113f1020460ec40e93cd5f6b21", 16), + "deb8941f1c60ada39fd6799f6c07eb8554113f1020460ec40e93cd5f6b21", + 16, + ), d=int( "280c42af8b1c719821f2f6e2bf5f3dd53c81b1f3e1e7cc4fce6e2f830132da0665bde" "bc1e307106b112b52ad5754867dddd028116cf4471bc14a58696b99524b1ad8f05b31" "cf47256e54ab4399b6a073b2c0452441438dfddf47f3334c13c5ec86ece4d33409056" - "139328fafa992fb5f5156f25f9b21d3e1c37f156d963d97e41", 16), + "139328fafa992fb5f5156f25f9b21d3e1c37f156d963d97e41", + 16, + ), dmp1=int( "198c7402a4ec10944c50ab8488d7b5991c767e75eb2817bd427dff10335ae141fa2e8" - "7c016dc22d975cac229b9ffdf7d943ddfd3a04b8bf82e83c3b32c5698b11", 16), + "7c016dc22d975cac229b9ffdf7d943ddfd3a04b8bf82e83c3b32c5698b11", + 16, + ), dmq1=int( "15fd30c7687b68ef7c2a30cdeb913ec56c4757c218cf9a04d995470797ee5f3a17558" - "fbb6d00af245d2631d893b382da48a72bc8a613024289895952ab245b0c1", 16), + "fbb6d00af245d2631d893b382da48a72bc8a613024289895952ab245b0c1", + 16, + ), iqmp=int( "4f8fde17e84557a3f4e242d889e898545ab55a1a8e075c9bb0220173ccffe84659abe" - "a235104f82e32750309389d4a52af57dbb6e48d831917b6efeb190176570", 16), + "a235104f82e32750309389d4a52af57dbb6e48d831917b6efeb190176570", + 16, + ), public_numbers=RSAPublicNumbers( e=65537, n=int( @@ -373,31 +501,44 @@ "99a9f74981c3eeaaf947d5c2d64a1a80f5c5108a49a715c3f7be95a016b8d3300" "965ead4a4df76e642d761526803e9434d4ec61b10cb50526d4dcaef02593085de" "d8c331c1b27b200a45628403065efcb2c0a0ca1f75d648d40a007fbfbf2cae3", - 16), - ) + 16, + ), + ), ) RSA_KEY_1030 = RSAPrivateNumbers( p=int( "6f4ac8a8172ef1154cf7f80b5e91de723c35a4c512860bfdbafcc3b994a2384bf7796" - "3a2dd0480c7e04d5d418629651a0de8979add6f47b23da14c27a682b69c9", 16), + "3a2dd0480c7e04d5d418629651a0de8979add6f47b23da14c27a682b69c9", + 16, + ), q=int( "65a9f83e07dea5b633e036a9dccfb32c46bf53c81040a19c574c3680838fc6d28bde9" - "55c0ff18b30481d4ab52a9f5e9f835459b1348bbb563ad90b15a682fadb3", 16), + "55c0ff18b30481d4ab52a9f5e9f835459b1348bbb563ad90b15a682fadb3", + 16, + ), d=int( "290db707b3e1a96445ae8ea93af55a9f211a54ebe52995c2eb28085d1e3f09c986e73" "a00010c8e4785786eaaa5c85b98444bd93b585d0c24363ccc22c482e150a3fd900176" "86968e4fa20423ae72823b0049defceccb39bb34aa4ef64e6b14463b76d6a871c859e" - "37285455b94b8e1527d1525b1682ac6f7c8fd79d576c55318c1", 16), + "37285455b94b8e1527d1525b1682ac6f7c8fd79d576c55318c1", + 16, + ), dmp1=int( "23f7fa84010225dea98297032dac5d45745a2e07976605681acfe87e0920a8ab3caf5" - "9d9602f3d63dc0584f75161fd8fff20c626c21c5e02a85282276a74628a9", 16), + "9d9602f3d63dc0584f75161fd8fff20c626c21c5e02a85282276a74628a9", + 16, + ), dmq1=int( "18ebb657765464a8aa44bf019a882b72a2110a77934c54915f70e6375088b10331982" - "962bce1c7edd8ef9d3d95aa2566d2a99da6ebab890b95375919408d00f33", 16), + "962bce1c7edd8ef9d3d95aa2566d2a99da6ebab890b95375919408d00f33", + 16, + ), iqmp=int( "3d59d208743c74054151002d77dcdfc55af3d41357e89af88d7eef2767be54c290255" - "9258d85cf2a1083c035a33e65a1ca46dc8b706847c1c6434cef7b71a9dae", 16), + "9258d85cf2a1083c035a33e65a1ca46dc8b706847c1c6434cef7b71a9dae", + 16, + ), public_numbers=RSAPublicNumbers( e=65537, n=int( @@ -405,31 +546,44 @@ "8fcdbb6b4e12168304f587999f9d96a421fc80cb933a490df85d25883e6a88750" "d6bd8b3d4117251eee8f45e70e6daac7dbbd92a9103c623a09355cf00e3f16168" "e38b9c4cb5b368deabbed8df466bc6835eaba959bc1c2f4ec32a09840becc8b", - 16), - ) + 16, + ), + ), ) RSA_KEY_1031 = RSAPrivateNumbers( p=int( "c0958c08e50137db989fb7cc93abf1984543e2f955d4f43fb2967f40105e79274c852" - "293fa06ce63ca8436155e475ed6d1f73fea4c8e2516cc79153e3dc83e897", 16), + "293fa06ce63ca8436155e475ed6d1f73fea4c8e2516cc79153e3dc83e897", + 16, + ), q=int( "78cae354ea5d6862e5d71d20273b7cddb8cdfab25478fe865180676b04250685c4d03" - "30c216574f7876a7b12dfe69f1661d3b0cea6c2c0dcfb84050f817afc28d", 16), + "30c216574f7876a7b12dfe69f1661d3b0cea6c2c0dcfb84050f817afc28d", + 16, + ), d=int( "1d55cc02b17a5d25bfb39f2bc58389004d0d7255051507f75ef347cdf5519d1a00f4b" "d235ce4171bfab7bdb7a6dcfae1cf41433fb7da5923cc84f15a675c0b83492c95dd99" "a9fc157aea352ffdcbb5d59dbc3662171d5838d69f130678ee27841a79ef64f679ce9" - "3821fa69c03f502244c04b737edad8967def8022a144feaab29", 16), + "3821fa69c03f502244c04b737edad8967def8022a144feaab29", + 16, + ), dmp1=int( "5b1c2504ec3a984f86b4414342b5bcf59a0754f13adf25b2a0edbc43f5ba8c3cc061d" - "80b03e5866d059968f0d10a98deaeb4f7830436d76b22cf41f2914e13eff", 16), + "80b03e5866d059968f0d10a98deaeb4f7830436d76b22cf41f2914e13eff", + 16, + ), dmq1=int( "6c361e1819691ab5d67fb2a8f65c958d301cdf24d90617c68ec7005edfb4a7b638cde" - "79d4b61cfba5c86e8c0ccf296bc7f611cb8d4ae0e072a0f68552ec2d5995", 16), + "79d4b61cfba5c86e8c0ccf296bc7f611cb8d4ae0e072a0f68552ec2d5995", + 16, + ), iqmp=int( "b7d61945fdc8b92e075b15554bab507fa8a18edd0a18da373ec6c766c71eece61136a" - "84b90b6d01741d40458bfad17a9bee9d4a8ed2f6e270782dc3bf5d58b56e", 16), + "84b90b6d01741d40458bfad17a9bee9d4a8ed2f6e270782dc3bf5d58b56e", + 16, + ), public_numbers=RSAPublicNumbers( e=65537, n=int( @@ -437,38 +591,51 @@ "9f73da0690581691626d8a7cf5d972cced9c2091ccf999024b23b4e6dc6d99f80" "a454737dec0caffaebe4a3fac250ed02079267c8f39620b5ae3e125ca35338522" "dc9353ecac19cb2fe3b9e3a9291619dbb1ea3a7c388e9ee6469fbf5fb22892b", - 16), - ) + 16, + ), + ), ) RSA_KEY_1536 = RSAPrivateNumbers( p=int( "f1a65fa4e2aa6e7e2b560251e8a4cd65b625ad9f04f6571785782d1c213d91c961637" "0c572f2783caf2899f7fb690cf99a0184257fbd4b071b212c88fb348279a5387e61f1" - "17e9c62980c45ea863fa9292087c0f66ecdcde6443d5a37268bf71", 16), + "17e9c62980c45ea863fa9292087c0f66ecdcde6443d5a37268bf71", + 16, + ), q=int( "e54c2cbc3839b1da6ae6fea45038d986d6f523a3ae76051ba20583aab711ea5965cf5" "3cf54128cc9573f7460bba0fd6758a57aaf240c391790fb38ab473d83ef735510c53d" - "1d10c31782e8fd7da42615e33565745c30a5e6ceb2a3ae0666cc35", 16), + "1d10c31782e8fd7da42615e33565745c30a5e6ceb2a3ae0666cc35", + 16, + ), d=int( "7bcad87e23da2cb2a8c328883fabce06e1f8e9b776c8bf253ad9884e6200e3bd9bd3b" "a2cbe87d3854527bf005ba5d878c5b0fa20cfb0a2a42884ae95ca12bf7304285e9214" "5e992f7006c7c0ae839ad550da495b143bec0f4806c7f44caed45f3ccc6dc44cfaf30" "7abdb757e3d28e41c2d21366835c0a41e50a95af490ac03af061d2feb36ac0afb87be" "a13fb0f0c5a410727ebedb286c77f9469473fae27ef2c836da6071ef7efc1647f1233" - "4009a89eecb09a8287abc8c2afd1ddd9a1b0641", 16), + "4009a89eecb09a8287abc8c2afd1ddd9a1b0641", + 16, + ), dmp1=int( "a845366cd6f9df1f34861bef7594ed025aa83a12759e245f58adaa9bdff9c3befb760" "75d3701e90038e888eec9bf092df63400152cb25fc07effc6c74c45f0654ccbde15cd" - "90dd5504298a946fa5cf22a956072da27a6602e6c6e5c97f2db9c1", 16), + "90dd5504298a946fa5cf22a956072da27a6602e6c6e5c97f2db9c1", + 16, + ), dmq1=int( "28b0c1e78cdac03310717992d321a3888830ec6829978c048156152d805b4f8919c61" "70b5dd204e5ddf3c6c53bc6aff15d0bd09faff7f351b94abb9db980b31f150a6d7573" - "08eb66938f89a5225cb4dd817a824c89e7a0293b58fc2eefb7e259", 16), + "08eb66938f89a5225cb4dd817a824c89e7a0293b58fc2eefb7e259", + 16, + ), iqmp=int( "6c1536c0e16e42a094b6caaf50231ba81916871497d73dcbbbd4bdeb9e60cae0413b3" "8143b5d680275b29ed7769fe5577e4f9b3647ddb064941120914526d64d80016d2eb7" - "dc362da7c569623157f3d7cff8347f11494bf5c048d77e28d3f515", 16), + "dc362da7c569623157f3d7cff8347f11494bf5c048d77e28d3f515", + 16, + ), public_numbers=RSAPublicNumbers( e=65537, n=int( @@ -477,8 +644,10 @@ "c248ceef4050160705c188043c8559bf6dbfb6c4bb382eda4e9547575a8227d5b" "3c0a7088391364cf9f018d8bea053b226ec65e8cdbeaf48a071d0074860a734b1" "cb7d2146d43014b20776dea42f7853a54690e6cbbf3331a9f43763cfe2a51c329" - "3bea3b2eebec0d8e43eb317a443afe541107d886e5243c096091543ae65", 16), - ) + "3bea3b2eebec0d8e43eb317a443afe541107d886e5243c096091543ae65", + 16, + ), + ), ) RSA_KEY_2048 = RSAPrivateNumbers( @@ -486,12 +655,16 @@ "e14202e58c5f7446648d75e5dc465781f661f6b73000c080368afcfb21377f4ef19da" "845d4ef9bc6b151f6d9f34629103f2e57615f9ba0a3a2fbb035069e1d63b4bb0e78ad" "dad1ec3c6f87e25c877a1c4c1972098e09158ef7b9bc163852a18d44a70b7b31a03dc" - "2614fd9ab7bf002cba79054544af3bfbdb6aed06c7b24e6ab", 16), + "2614fd9ab7bf002cba79054544af3bfbdb6aed06c7b24e6ab", + 16, + ), q=int( "dbe2bea1ff92599bd19f9d045d6ce62250c05cfeac5117f3cf3e626cb696e3d886379" "557d5a57b7476f9cf886accfd40508a805fe3b45a78e1a8a125e516cda91640ee6398" "ec5a39d3e6b177ef12ab00d07907a17640e4ca454fd8487da3c4ffa0d5c2a5edb1221" - "1c8e33c7ee9fa6753771fd111ec04b8317f86693eb2928c89", 16), + "1c8e33c7ee9fa6753771fd111ec04b8317f86693eb2928c89", + 16, + ), d=int( "aef17f80f2653bc30539f26dd4c82ed6abc1d1b53bc0abcdbee47e9a8ab433abde865" "9fcfae1244d22de6ad333c95aee7d47f30b6815065ac3322744d3ea75058002cd1b29" @@ -500,22 +673,30 @@ "c8263ce2802a769a090e993fd49abc50c3d3c78c29bee2de0c98055d2f102f1c5684b" "8dddee611d5205392d8e8dd61a15bf44680972a87f040a611a149271eeb2573f8bf6f" "627dfa70e77def2ee6584914fa0290e041349ea0999cdff3e493365885b906cbcf195" - "843345809a85098cca90fea014a21", 16), + "843345809a85098cca90fea014a21", + 16, + ), dmp1=int( "9ba56522ffcfa5244eae805c87cc0303461f82be29691b9a7c15a5a050df6c143c575" "7c288d3d7ab7f32c782e9d9fcddc10a604e6425c0e5d0e46069035d95a923646d276d" "d9d95b8696fa29ab0de18e53f6f119310f8dd9efca62f0679291166fed8cbd5f18fe1" - "3a5f1ead1d71d8c90f40382818c18c8d069be793dbc094f69", 16), + "3a5f1ead1d71d8c90f40382818c18c8d069be793dbc094f69", + 16, + ), dmq1=int( "a8d4a0aaa2212ccc875796a81353da1fdf00d46676c88d2b96a4bfcdd924622d8e607" "f3ac1c01dda7ebfb0a97dd7875c2a7b2db6728fb827b89c519f5716fb3228f4121647" "04b30253c17de2289e9cce3343baa82eb404f789e094a094577a9b0c5314f1725fdf5" - "8e87611ad20da331bd30b8aebc7dc97d0e9a9ba8579772c9", 16), + "8e87611ad20da331bd30b8aebc7dc97d0e9a9ba8579772c9", + 16, + ), iqmp=int( "17bd5ef638c49440d1853acb3fa63a5aca28cb7f94ed350db7001c8445da8943866a7" "0936e1ee2716c98b484e357cc054d82fbbd98d42f880695d38a1dd4eb096f629b9417" "aca47e6de5da9f34e60e8a0ffd7e35be74deeef67298d94b3e0db73fc4b7a4cb360c8" - "9d2117a0bfd9434d37dc7c027d6b01e5295c875015510917d", 16), + "9d2117a0bfd9434d37dc7c027d6b01e5295c875015510917d", + 16, + ), public_numbers=RSAPublicNumbers( e=65537, n=int( @@ -526,8 +707,10 @@ "c29e53635e24c87a5b2c4215968063cdeb68a972babbc1e3cff00fb9a80e372a4" "d0c2c920d1e8cee333ce470dc2e8145adb05bf29aee1d24f141e8cc784989c587" "fc6fbacd979f3f2163c1d7299b365bc72ffe2848e967aed1e48dcc515b3a50ed4" - "de04fd053846ca10a223b10cc841cc80fdebee44f3114c13e886af583", 16), - ) + "de04fd053846ca10a223b10cc841cc80fdebee44f3114c13e886af583", + 16, + ), + ), ) RSA_KEY_2048_ALT = RSAPrivateNumbers( @@ -598,6 +781,36 @@ "715070507278514207864914944621214574162116786377990456375" "964817771730371110612100247262908550409785456157505694419" "00451152778245269283276012328748538414051025541" - ) - ) + ), + ), ) + +RSA_KEY_CORRUPTED = b""" +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAuYE4k09MAsi1yjMrXekMe6sT9bEt3ko47dnmN8YBgO8DiiCc +226TnQPvuX3FGxU+Y1zTJpcvVL3L37UOvh4CSb9zKyrFK9/x/UcCfK3Eq8JdS98P +CVeGpkp5E+vwIKY72rc1RSSSCs0PtFdYbSn4trwf5BjPxIqXwIOS3R7zC7cLPHY4 +YdsM4gLGVOP17uXJr/MPoAtWTBVm5zx4bHm6Xclzgf86sbPdL3LxNs0fz4HqJZgA +6EUtyl6Qypq2LjXbdmm2i3vC+MxW6nEPItPqgComhq0zBmVonsiEO87rEtD548Yq +DKvxwHhlcODcVkAYebJ+W5L6PPJBNYA3t5wYyQIDAQABAoIBAAbHkg5msftpGt5Z +Vb3yUuepem7hWTF5YFlIRw5l2wNcURNpbswEhOVNJbuG+KCple7Dw4TuDmhHs/zr +BRqpDhXldhrUtb2uc3ihqWiVFJbieqE4jUbGvMJusvtXXeDwU6wGWzV/V4qndCrk +u4PGypk4Cbbq6ZP2oufPryQ3D4Ff1TA06RSWdP3Cg673VqwLtkXwsRDhymAviiqU +hxQg8bRNiD7mYoUKyLVeV7YRDLTBugfiFmy54yC99NJclLkYmzCgRt1EuoW0Hixx +EIQFEOLftgpc+sKpbbiOileMsc/stytHXXqfgozhBxDNeSzdNYfwEpkLJpLZSUNV +EhS4X1cCgYEAz+7DkXksWw9zLqYniMIcvcBnHQcy3Anqbcu8Zbw+I9wOwzNt44Bo +f88i2idvWvMsRq/LX4WD4jjPB4Z3wAzGBCq+2cy0GrWByMu+VbpwCrntRBkS5huY +IIf1nr1+BuySNt8TL6nZNKz0D8+5c8wT+VbVdPH//4MzfDrK81PPnesCgYEA5GMy +ji4l+8zO33LFMlWQGYgfSMd4jGMQD0VCvfhlosK0Py0AfZj/GKEGHduo/37KVVvb +6XdJqYgB7OxPmdEqbMGeYPKv7pKkG1jXRuEtmXXJ9hS1t0oIvXJLHJnQrOOoRRAR ++xJZbI7WjemY+ZCMOAPT1tm97pxjs81WgSJ6ExsCgYEAze5ADfEeNskkYAz6lnz4 +jgzhkmQwwK+pVzgxy9g8brNkg3qJ2Iix9fKlJ71qkX7IWPF9z4qhxQhSMbfBHZkI ++9OB1J7huJoOgVkXliwIbvcYvxq+Fts5XO6KGb699AmT/XgMvmXO0lbAGLC3kLGL +DqQrH3kU+m9sLBrmKPrWYiUCgYEA3/8etW4zmMvd1jAFkoFyzGfCbyocZGxAcwm2 +FQYMAN8/03p6sbSd9XTwv9YR4Uxke+WURkjVuW2IneuDgtQv6QCFKob74Jx4Uc4H +jiAKDioFg9H6C6OUAOKZIpsFnJvIDLxfNkVf6WYKrrL+cz6/F61BVsbGTsGZ094/ +ynWbDyMCgYEAh44C/wkebe0zz/llG+KTRGENsw1c7+pm0/l3wPYAlH02ewbyRjFf +OKPfyyBtBkoD5rG3IbLyPxsbd3wWwyUzSYq02qRJq43XqyMZhRnNlYhEnNu/Gr5H +sN1f13zqkKoRxxbIjyh4RDYlAv4Sehk27z2Q3gBe9bI5xKkoQ/VfF2w= +-----END RSA PRIVATE KEY----- +""" diff --git a/tests/hazmat/primitives/test_3des.py b/tests/hazmat/primitives/test_3des.py index f281ba2887b2..d14dcad9f71f 100644 --- a/tests/hazmat/primitives/test_3des.py +++ b/tests/hazmat/primitives/test_3des.py @@ -28,7 +28,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestTripleDESModeCBC(object): - test_KAT = generate_encrypt_test( + test_kat = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "CBC"), [ @@ -42,14 +42,10 @@ class TestTripleDESModeCBC(object): lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)), ) - test_MMT = generate_encrypt_test( + test_mmt = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "CBC"), - [ - "TCBCMMT1.rsp", - "TCBCMMT2.rsp", - "TCBCMMT3.rsp", - ], + ["TCBCMMT1.rsp", "TCBCMMT2.rsp", "TCBCMMT3.rsp"], lambda key1, key2, key3, **kwargs: algorithms.TripleDES( binascii.unhexlify(key1 + key2 + key3) ), @@ -65,7 +61,7 @@ class TestTripleDESModeCBC(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestTripleDESModeOFB(object): - test_KAT = generate_encrypt_test( + test_kat = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "OFB"), [ @@ -79,14 +75,10 @@ class TestTripleDESModeOFB(object): lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)), ) - test_MMT = generate_encrypt_test( + test_mmt = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "OFB"), - [ - "TOFBMMT1.rsp", - "TOFBMMT2.rsp", - "TOFBMMT3.rsp", - ], + ["TOFBMMT1.rsp", "TOFBMMT2.rsp", "TOFBMMT3.rsp"], lambda key1, key2, key3, **kwargs: algorithms.TripleDES( binascii.unhexlify(key1 + key2 + key3) ), @@ -102,7 +94,7 @@ class TestTripleDESModeOFB(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestTripleDESModeCFB(object): - test_KAT = generate_encrypt_test( + test_kat = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "CFB"), [ @@ -116,14 +108,10 @@ class TestTripleDESModeCFB(object): lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)), ) - test_MMT = generate_encrypt_test( + test_mmt = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "CFB"), - [ - "TCFB64MMT1.rsp", - "TCFB64MMT2.rsp", - "TCFB64MMT3.rsp", - ], + ["TCFB64MMT1.rsp", "TCFB64MMT2.rsp", "TCFB64MMT3.rsp"], lambda key1, key2, key3, **kwargs: algorithms.TripleDES( binascii.unhexlify(key1 + key2 + key3) ), @@ -139,7 +127,7 @@ class TestTripleDESModeCFB(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestTripleDESModeCFB8(object): - test_KAT = generate_encrypt_test( + test_kat = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "CFB"), [ @@ -153,14 +141,10 @@ class TestTripleDESModeCFB8(object): lambda iv, **kwargs: modes.CFB8(binascii.unhexlify(iv)), ) - test_MMT = generate_encrypt_test( + test_mmt = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "CFB"), - [ - "TCFB8MMT1.rsp", - "TCFB8MMT2.rsp", - "TCFB8MMT3.rsp", - ], + ["TCFB8MMT1.rsp", "TCFB8MMT2.rsp", "TCFB8MMT3.rsp"], lambda key1, key2, key3, **kwargs: algorithms.TripleDES( binascii.unhexlify(key1 + key2 + key3) ), @@ -176,7 +160,7 @@ class TestTripleDESModeCFB8(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestTripleDESModeECB(object): - test_KAT = generate_encrypt_test( + test_kat = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "ECB"), [ @@ -190,14 +174,10 @@ class TestTripleDESModeECB(object): lambda **kwargs: modes.ECB(), ) - test_MMT = generate_encrypt_test( + test_mmt = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "3DES", "ECB"), - [ - "TECBMMT1.rsp", - "TECBMMT2.rsp", - "TECBMMT3.rsp", - ], + ["TECBMMT1.rsp", "TECBMMT2.rsp", "TECBMMT3.rsp"], lambda key1, key2, key3, **kwargs: algorithms.TripleDES( binascii.unhexlify(key1 + key2 + key3) ), diff --git a/tests/hazmat/primitives/test_aead.py b/tests/hazmat/primitives/test_aead.py index e1a17a974461..753c7c192bc9 100644 --- a/tests/hazmat/primitives/test_aead.py +++ b/tests/hazmat/primitives/test_aead.py @@ -12,13 +12,17 @@ from cryptography.exceptions import InvalidTag, UnsupportedAlgorithm, _Reasons from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers.aead import ( - AESCCM, AESGCM, ChaCha20Poly1305 + AESCCM, + AESGCM, + ChaCha20Poly1305, ) from .utils import _load_all_params from ...utils import ( - load_nist_ccm_vectors, load_nist_vectors, load_vectors_from_file, - raises_unsupported_algorithm + load_nist_ccm_vectors, + load_nist_vectors, + load_vectors_from_file, + raises_unsupported_algorithm, ) @@ -37,7 +41,7 @@ def _aead_supported(cls): @pytest.mark.skipif( _aead_supported(ChaCha20Poly1305), - reason="Requires OpenSSL without ChaCha20Poly1305 support" + reason="Requires OpenSSL without ChaCha20Poly1305 support", ) @pytest.mark.requires_backend_interface(interface=CipherBackend) def test_chacha20poly1305_unsupported_on_older_openssl(backend): @@ -47,7 +51,7 @@ def test_chacha20poly1305_unsupported_on_older_openssl(backend): @pytest.mark.skipif( not _aead_supported(ChaCha20Poly1305), - reason="Does not support ChaCha20Poly1305" + reason="Does not support ChaCha20Poly1305", ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestChaCha20Poly1305(object): @@ -78,11 +82,12 @@ def test_bad_key(self, backend): [ [object(), b"data", b""], [b"0" * 12, object(), b""], - [b"0" * 12, b"data", object()] - ] + [b"0" * 12, b"data", object()], + ], ) - def test_params_not_bytes_encrypt(self, nonce, data, associated_data, - backend): + def test_params_not_bytes_encrypt( + self, nonce, data, associated_data, backend + ): key = ChaCha20Poly1305.generate_key() chacha = ChaCha20Poly1305(key) with pytest.raises(TypeError): @@ -121,8 +126,8 @@ def test_associated_data_none_equal_to_empty_bytestring(self, backend): "vector", load_vectors_from_file( os.path.join("ciphers", "ChaCha20Poly1305", "openssl.txt"), - load_nist_vectors - ) + load_nist_vectors, + ), ) def test_openssl_vectors(self, vector, backend): key = binascii.unhexlify(vector["key"]) @@ -145,8 +150,8 @@ def test_openssl_vectors(self, vector, backend): "vector", load_vectors_from_file( os.path.join("ciphers", "ChaCha20Poly1305", "boringssl.txt"), - load_nist_vectors - ) + load_nist_vectors, + ), ) def test_boringssl_vectors(self, vector, backend): key = binascii.unhexlify(vector["key"]) @@ -183,20 +188,6 @@ def test_buffer_protocol(self, backend): assert computed_pt2 == pt -@pytest.mark.skipif( - _aead_supported(AESCCM), - reason="Requires OpenSSL without AES-CCM support" -) -@pytest.mark.requires_backend_interface(interface=CipherBackend) -def test_aesccm_unsupported_on_older_openssl(backend): - with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER): - AESCCM(AESCCM.generate_key(128)) - - -@pytest.mark.skipif( - not _aead_supported(AESCCM), - reason="Does not support AESCCM" -) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESCCM(object): def test_data_too_large(self): @@ -245,22 +236,30 @@ def test_invalid_nonce_length(self, backend): _load_all_params( os.path.join("ciphers", "AES", "CCM"), [ - "DVPT128.rsp", "DVPT192.rsp", "DVPT256.rsp", - "VADT128.rsp", "VADT192.rsp", "VADT256.rsp", - "VNT128.rsp", "VNT192.rsp", "VNT256.rsp", - "VPT128.rsp", "VPT192.rsp", "VPT256.rsp", + "DVPT128.rsp", + "DVPT192.rsp", + "DVPT256.rsp", + "VADT128.rsp", + "VADT192.rsp", + "VADT256.rsp", + "VNT128.rsp", + "VNT192.rsp", + "VNT256.rsp", + "VPT128.rsp", + "VPT192.rsp", + "VPT256.rsp", ], - load_nist_ccm_vectors - ) + load_nist_ccm_vectors, + ), ) def test_vectors(self, vector, backend): key = binascii.unhexlify(vector["key"]) nonce = binascii.unhexlify(vector["nonce"]) - adata = binascii.unhexlify(vector["adata"])[:vector["alen"]] + adata = binascii.unhexlify(vector["adata"])[: vector["alen"]] ct = binascii.unhexlify(vector["ct"]) - pt = binascii.unhexlify(vector["payload"])[:vector["plen"]] + pt = binascii.unhexlify(vector["payload"])[: vector["plen"]] aesccm = AESCCM(key, vector["tlen"]) - if vector.get('fail'): + if vector.get("fail"): with pytest.raises(InvalidTag): aesccm.decrypt(nonce, ct, adata) else: @@ -293,7 +292,7 @@ def test_nonce_too_long(self, backend): [object(), b"data", b""], [b"0" * 12, object(), b""], [b"0" * 12, b"data", object()], - ] + ], ) def test_params_not_bytes(self, nonce, data, associated_data, backend): key = AESCCM.generate_key(128) @@ -359,7 +358,7 @@ def _load_gcm_vectors(): "gcmEncryptExtIV192.rsp", "gcmEncryptExtIV256.rsp", ], - load_nist_vectors + load_nist_vectors, ) return [x for x in vectors if len(x["tag"]) == 32] @@ -378,9 +377,15 @@ def test_data_too_large(self): aesgcm.encrypt(nonce, b"", FakeData()) @pytest.mark.parametrize("vector", _load_gcm_vectors()) - def test_vectors(self, vector): - key = binascii.unhexlify(vector["key"]) + def test_vectors(self, backend, vector): nonce = binascii.unhexlify(vector["iv"]) + + if backend._fips_enabled and len(nonce) != 12: + # Red Hat disables non-96-bit IV support as part of its FIPS + # patches. + pytest.skip("Non-96-bit IVs unsupported in FIPS mode.") + + key = binascii.unhexlify(vector["key"]) aad = binascii.unhexlify(vector["aad"]) ct = binascii.unhexlify(vector["ct"]) pt = binascii.unhexlify(vector.get("pt", b"")) @@ -401,8 +406,8 @@ def test_vectors(self, vector): [ [object(), b"data", b""], [b"0" * 12, object(), b""], - [b"0" * 12, b"data", object()] - ] + [b"0" * 12, b"data", object()], + ], ) def test_params_not_bytes(self, nonce, data, associated_data, backend): key = AESGCM.generate_key(128) diff --git a/tests/hazmat/primitives/test_aes.py b/tests/hazmat/primitives/test_aes.py index 90a6b3b0a067..f98ba6fddff8 100644 --- a/tests/hazmat/primitives/test_aes.py +++ b/tests/hazmat/primitives/test_aes.py @@ -12,7 +12,8 @@ from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import algorithms, base, modes -from .utils import _load_all_params, generate_aead_test, generate_encrypt_test +from .utils import _load_all_params, generate_encrypt_test +from ...doubles import DummyMode from ...utils import load_nist_vectors @@ -30,11 +31,15 @@ class TestAESModeXTS(object): # data unit length that is divisible by 8. The NIST vectors include # tests for implementations that support encryption of data that is # not divisible modulo 8, but OpenSSL is not such an implementation. - [x for x in _load_all_params( - os.path.join("ciphers", "AES", "XTS", "tweak-128hexstr"), - ["XTSGenAES128.rsp", "XTSGenAES256.rsp"], - load_nist_vectors - ) if int(x["dataunitlen"]) / 8.0 == int(x["dataunitlen"]) // 8] + [ + x + for x in _load_all_params( + os.path.join("ciphers", "AES", "XTS", "tweak-128hexstr"), + ["XTSGenAES128.rsp", "XTSGenAES256.rsp"], + load_nist_vectors, + ) + if int(x["dataunitlen"]) / 8.0 == int(x["dataunitlen"]) // 8 + ], ) def test_xts_vectors(self, vector, backend): key = binascii.unhexlify(vector["key"]) @@ -58,7 +63,7 @@ def test_xts_vectors(self, vector, backend): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeCBC(object): - test_CBC = generate_encrypt_test( + test_cbc = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "AES", "CBC"), [ @@ -91,7 +96,7 @@ class TestAESModeCBC(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeECB(object): - test_ECB = generate_encrypt_test( + test_ecb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "AES", "ECB"), [ @@ -124,7 +129,7 @@ class TestAESModeECB(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeOFB(object): - test_OFB = generate_encrypt_test( + test_ofb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "AES", "OFB"), [ @@ -157,7 +162,7 @@ class TestAESModeOFB(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeCFB(object): - test_CFB = generate_encrypt_test( + test_cfb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "AES", "CFB"), [ @@ -190,7 +195,7 @@ class TestAESModeCFB(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeCFB8(object): - test_CFB8 = generate_encrypt_test( + test_cfb8 = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "AES", "CFB"), [ @@ -223,7 +228,7 @@ class TestAESModeCFB8(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESModeCTR(object): - test_CTR = generate_encrypt_test( + test_ctr = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "AES", "CTR"), ["aes-128-ctr.txt", "aes-192-ctr.txt", "aes-256-ctr.txt"], @@ -232,249 +237,6 @@ class TestAESModeCTR(object): ) -@pytest.mark.supported( - only_if=lambda backend: backend.cipher_supported( - algorithms.AES(b"\x00" * 16), modes.GCM(b"\x00" * 12) - ), - skip_message="Does not support AES GCM", -) -@pytest.mark.requires_backend_interface(interface=CipherBackend) -class TestAESModeGCM(object): - test_GCM = generate_aead_test( - load_nist_vectors, - os.path.join("ciphers", "AES", "GCM"), - [ - "gcmDecrypt128.rsp", - "gcmDecrypt192.rsp", - "gcmDecrypt256.rsp", - "gcmEncryptExtIV128.rsp", - "gcmEncryptExtIV192.rsp", - "gcmEncryptExtIV256.rsp", - ], - algorithms.AES, - modes.GCM, - ) - - def test_gcm_tag_with_only_aad(self, backend): - key = binascii.unhexlify(b"5211242698bed4774a090620a6ca56f3") - iv = binascii.unhexlify(b"b1e1349120b6e832ef976f5d") - aad = binascii.unhexlify(b"b6d729aab8e6416d7002b9faa794c410d8d2f193") - tag = binascii.unhexlify(b"0f247e7f9c2505de374006738018493b") - - cipher = base.Cipher( - algorithms.AES(key), - modes.GCM(iv), - backend=backend - ) - encryptor = cipher.encryptor() - encryptor.authenticate_additional_data(aad) - encryptor.finalize() - assert encryptor.tag == tag - - def test_gcm_ciphertext_with_no_aad(self, backend): - key = binascii.unhexlify(b"e98b72a9881a84ca6b76e0f43e68647a") - iv = binascii.unhexlify(b"8b23299fde174053f3d652ba") - ct = binascii.unhexlify(b"5a3c1cf1985dbb8bed818036fdd5ab42") - tag = binascii.unhexlify(b"23c7ab0f952b7091cd324835043b5eb5") - pt = binascii.unhexlify(b"28286a321293253c3e0aa2704a278032") - - cipher = base.Cipher( - algorithms.AES(key), - modes.GCM(iv), - backend=backend - ) - encryptor = cipher.encryptor() - computed_ct = encryptor.update(pt) + encryptor.finalize() - assert computed_ct == ct - assert encryptor.tag == tag - - def test_gcm_ciphertext_limit(self, backend): - encryptor = base.Cipher( - algorithms.AES(b"\x00" * 16), - modes.GCM(b"\x01" * 16), - backend=backend - ).encryptor() - encryptor._bytes_processed = modes.GCM._MAX_ENCRYPTED_BYTES - 16 - encryptor.update(b"0" * 16) - assert ( - encryptor._bytes_processed == modes.GCM._MAX_ENCRYPTED_BYTES - ) - with pytest.raises(ValueError): - encryptor.update(b"0") - - def test_gcm_aad_limit(self, backend): - encryptor = base.Cipher( - algorithms.AES(b"\x00" * 16), - modes.GCM(b"\x01" * 16), - backend=backend - ).encryptor() - encryptor._aad_bytes_processed = modes.GCM._MAX_AAD_BYTES - 16 - encryptor.authenticate_additional_data(b"0" * 16) - assert encryptor._aad_bytes_processed == modes.GCM._MAX_AAD_BYTES - with pytest.raises(ValueError): - encryptor.authenticate_additional_data(b"0") - - def test_gcm_ciphertext_increments(self, backend): - encryptor = base.Cipher( - algorithms.AES(b"\x00" * 16), - modes.GCM(b"\x01" * 16), - backend=backend - ).encryptor() - encryptor.update(b"0" * 8) - assert encryptor._bytes_processed == 8 - encryptor.update(b"0" * 7) - assert encryptor._bytes_processed == 15 - encryptor.update(b"0" * 18) - assert encryptor._bytes_processed == 33 - - def test_gcm_aad_increments(self, backend): - encryptor = base.Cipher( - algorithms.AES(b"\x00" * 16), - modes.GCM(b"\x01" * 16), - backend=backend - ).encryptor() - encryptor.authenticate_additional_data(b"0" * 8) - assert encryptor._aad_bytes_processed == 8 - encryptor.authenticate_additional_data(b"0" * 18) - assert encryptor._aad_bytes_processed == 26 - - def test_gcm_tag_decrypt_none(self, backend): - key = binascii.unhexlify(b"5211242698bed4774a090620a6ca56f3") - iv = binascii.unhexlify(b"b1e1349120b6e832ef976f5d") - aad = binascii.unhexlify(b"b6d729aab8e6416d7002b9faa794c410d8d2f193") - - encryptor = base.Cipher( - algorithms.AES(key), - modes.GCM(iv), - backend=backend - ).encryptor() - encryptor.authenticate_additional_data(aad) - encryptor.finalize() - - if ( - backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and - not backend._lib.CRYPTOGRAPHY_IS_LIBRESSL - ): - with pytest.raises(NotImplementedError): - decryptor = base.Cipher( - algorithms.AES(key), - modes.GCM(iv), - backend=backend - ).decryptor() - else: - decryptor = base.Cipher( - algorithms.AES(key), - modes.GCM(iv), - backend=backend - ).decryptor() - decryptor.authenticate_additional_data(aad) - with pytest.raises(ValueError): - decryptor.finalize() - - def test_gcm_tag_decrypt_mode(self, backend): - key = binascii.unhexlify(b"5211242698bed4774a090620a6ca56f3") - iv = binascii.unhexlify(b"b1e1349120b6e832ef976f5d") - aad = binascii.unhexlify(b"b6d729aab8e6416d7002b9faa794c410d8d2f193") - - encryptor = base.Cipher( - algorithms.AES(key), - modes.GCM(iv), - backend=backend - ).encryptor() - encryptor.authenticate_additional_data(aad) - encryptor.finalize() - tag = encryptor.tag - - decryptor = base.Cipher( - algorithms.AES(key), - modes.GCM(iv, tag), - backend=backend - ).decryptor() - decryptor.authenticate_additional_data(aad) - decryptor.finalize() - - def test_gcm_tag_decrypt_finalize(self, backend): - key = binascii.unhexlify(b"5211242698bed4774a090620a6ca56f3") - iv = binascii.unhexlify(b"b1e1349120b6e832ef976f5d") - aad = binascii.unhexlify(b"b6d729aab8e6416d7002b9faa794c410d8d2f193") - - encryptor = base.Cipher( - algorithms.AES(key), - modes.GCM(iv), - backend=backend - ).encryptor() - encryptor.authenticate_additional_data(aad) - encryptor.finalize() - tag = encryptor.tag - - if ( - backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and - not backend._lib.CRYPTOGRAPHY_IS_LIBRESSL - ): - with pytest.raises(NotImplementedError): - decryptor = base.Cipher( - algorithms.AES(key), - modes.GCM(iv), - backend=backend - ).decryptor() - decryptor = base.Cipher( - algorithms.AES(key), - modes.GCM(iv, tag=encryptor.tag), - backend=backend - ).decryptor() - else: - decryptor = base.Cipher( - algorithms.AES(key), - modes.GCM(iv), - backend=backend - ).decryptor() - decryptor.authenticate_additional_data(aad) - - if ( - backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and - not backend._lib.CRYPTOGRAPHY_IS_LIBRESSL - ): - with pytest.raises(NotImplementedError): - decryptor.finalize_with_tag(tag) - decryptor.finalize() - else: - decryptor.finalize_with_tag(tag) - - @pytest.mark.supported( - only_if=lambda backend: ( - not backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 or - backend._lib.CRYPTOGRAPHY_IS_LIBRESSL - ), - skip_message="Not supported on OpenSSL 1.0.1", - ) - def test_gcm_tag_decrypt_finalize_tag_length(self, backend): - decryptor = base.Cipher( - algorithms.AES(b"0" * 16), - modes.GCM(b"0" * 12), - backend=backend - ).decryptor() - with pytest.raises(ValueError): - decryptor.finalize_with_tag(b"tagtooshort") - - def test_buffer_protocol(self, backend): - data = bytearray(b"helloworld") - enc = base.Cipher( - algorithms.AES(bytearray(b"\x00" * 16)), - modes.GCM(bytearray(b"\x00" * 12)), - backend - ).encryptor() - enc.authenticate_additional_data(bytearray(b"foo")) - ct = enc.update(data) + enc.finalize() - dec = base.Cipher( - algorithms.AES(bytearray(b"\x00" * 16)), - modes.GCM(bytearray(b"\x00" * 12), enc.tag), - backend - ).decryptor() - dec.authenticate_additional_data(bytearray(b"foo")) - pt = dec.update(ct) + dec.finalize() - assert pt == data - - @pytest.mark.parametrize( "mode", [ @@ -484,14 +246,17 @@ def test_buffer_protocol(self, backend): modes.CFB(bytearray(b"\x00" * 16)), modes.CFB8(bytearray(b"\x00" * 16)), modes.XTS(bytearray(b"\x00" * 16)), - ] + # Add a dummy mode for coverage of the cipher_supported check. + DummyMode(), + ], ) @pytest.mark.requires_backend_interface(interface=CipherBackend) def test_buffer_protocol_alternate_modes(mode, backend): data = bytearray(b"sixteen_byte_msg") - cipher = base.Cipher( - algorithms.AES(bytearray(b"\x00" * 32)), mode, backend - ) + key = algorithms.AES(bytearray(os.urandom(32))) + if not backend.cipher_supported(key, mode): + pytest.skip("AES in {} mode not supported".format(mode.name)) + cipher = base.Cipher(key, mode, backend) enc = cipher.encryptor() ct = enc.update(data) + enc.finalize() dec = cipher.decryptor() diff --git a/tests/hazmat/primitives/test_aes_gcm.py b/tests/hazmat/primitives/test_aes_gcm.py new file mode 100644 index 000000000000..f289f18b11cc --- /dev/null +++ b/tests/hazmat/primitives/test_aes_gcm.py @@ -0,0 +1,197 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii +import os + +import pytest + +from cryptography.hazmat.backends.interfaces import CipherBackend +from cryptography.hazmat.primitives.ciphers import algorithms, base, modes + +from .utils import generate_aead_test +from ...utils import load_nist_vectors + + +@pytest.mark.supported( + only_if=lambda backend: backend.cipher_supported( + algorithms.AES(b"\x00" * 16), modes.GCM(b"\x00" * 12) + ), + skip_message="Does not support AES GCM", +) +@pytest.mark.requires_backend_interface(interface=CipherBackend) +class TestAESModeGCM(object): + test_gcm = generate_aead_test( + load_nist_vectors, + os.path.join("ciphers", "AES", "GCM"), + [ + "gcmDecrypt128.rsp", + "gcmDecrypt192.rsp", + "gcmDecrypt256.rsp", + "gcmEncryptExtIV128.rsp", + "gcmEncryptExtIV192.rsp", + "gcmEncryptExtIV256.rsp", + ], + algorithms.AES, + modes.GCM, + ) + + def test_gcm_tag_with_only_aad(self, backend): + key = binascii.unhexlify(b"5211242698bed4774a090620a6ca56f3") + iv = binascii.unhexlify(b"b1e1349120b6e832ef976f5d") + aad = binascii.unhexlify(b"b6d729aab8e6416d7002b9faa794c410d8d2f193") + tag = binascii.unhexlify(b"0f247e7f9c2505de374006738018493b") + + cipher = base.Cipher( + algorithms.AES(key), modes.GCM(iv), backend=backend + ) + encryptor = cipher.encryptor() + encryptor.authenticate_additional_data(aad) + encryptor.finalize() + assert encryptor.tag == tag + + def test_gcm_ciphertext_with_no_aad(self, backend): + key = binascii.unhexlify(b"e98b72a9881a84ca6b76e0f43e68647a") + iv = binascii.unhexlify(b"8b23299fde174053f3d652ba") + ct = binascii.unhexlify(b"5a3c1cf1985dbb8bed818036fdd5ab42") + tag = binascii.unhexlify(b"23c7ab0f952b7091cd324835043b5eb5") + pt = binascii.unhexlify(b"28286a321293253c3e0aa2704a278032") + + cipher = base.Cipher( + algorithms.AES(key), modes.GCM(iv), backend=backend + ) + encryptor = cipher.encryptor() + computed_ct = encryptor.update(pt) + encryptor.finalize() + assert computed_ct == ct + assert encryptor.tag == tag + + def test_gcm_ciphertext_limit(self, backend): + encryptor = base.Cipher( + algorithms.AES(b"\x00" * 16), + modes.GCM(b"\x01" * 16), + backend=backend, + ).encryptor() + encryptor._bytes_processed = modes.GCM._MAX_ENCRYPTED_BYTES - 16 + encryptor.update(b"0" * 16) + assert encryptor._bytes_processed == modes.GCM._MAX_ENCRYPTED_BYTES + with pytest.raises(ValueError): + encryptor.update(b"0") + + def test_gcm_aad_limit(self, backend): + encryptor = base.Cipher( + algorithms.AES(b"\x00" * 16), + modes.GCM(b"\x01" * 16), + backend=backend, + ).encryptor() + encryptor._aad_bytes_processed = modes.GCM._MAX_AAD_BYTES - 16 + encryptor.authenticate_additional_data(b"0" * 16) + assert encryptor._aad_bytes_processed == modes.GCM._MAX_AAD_BYTES + with pytest.raises(ValueError): + encryptor.authenticate_additional_data(b"0") + + def test_gcm_ciphertext_increments(self, backend): + encryptor = base.Cipher( + algorithms.AES(b"\x00" * 16), + modes.GCM(b"\x01" * 16), + backend=backend, + ).encryptor() + encryptor.update(b"0" * 8) + assert encryptor._bytes_processed == 8 + encryptor.update(b"0" * 7) + assert encryptor._bytes_processed == 15 + encryptor.update(b"0" * 18) + assert encryptor._bytes_processed == 33 + + def test_gcm_aad_increments(self, backend): + encryptor = base.Cipher( + algorithms.AES(b"\x00" * 16), + modes.GCM(b"\x01" * 16), + backend=backend, + ).encryptor() + encryptor.authenticate_additional_data(b"0" * 8) + assert encryptor._aad_bytes_processed == 8 + encryptor.authenticate_additional_data(b"0" * 18) + assert encryptor._aad_bytes_processed == 26 + + def test_gcm_tag_decrypt_none(self, backend): + key = binascii.unhexlify(b"5211242698bed4774a090620a6ca56f3") + iv = binascii.unhexlify(b"b1e1349120b6e832ef976f5d") + aad = binascii.unhexlify(b"b6d729aab8e6416d7002b9faa794c410d8d2f193") + + encryptor = base.Cipher( + algorithms.AES(key), modes.GCM(iv), backend=backend + ).encryptor() + encryptor.authenticate_additional_data(aad) + encryptor.finalize() + + decryptor = base.Cipher( + algorithms.AES(key), modes.GCM(iv), backend=backend + ).decryptor() + decryptor.authenticate_additional_data(aad) + with pytest.raises(ValueError): + decryptor.finalize() + + def test_gcm_tag_decrypt_mode(self, backend): + key = binascii.unhexlify(b"5211242698bed4774a090620a6ca56f3") + iv = binascii.unhexlify(b"b1e1349120b6e832ef976f5d") + aad = binascii.unhexlify(b"b6d729aab8e6416d7002b9faa794c410d8d2f193") + + encryptor = base.Cipher( + algorithms.AES(key), modes.GCM(iv), backend=backend + ).encryptor() + encryptor.authenticate_additional_data(aad) + encryptor.finalize() + tag = encryptor.tag + + decryptor = base.Cipher( + algorithms.AES(key), modes.GCM(iv, tag), backend=backend + ).decryptor() + decryptor.authenticate_additional_data(aad) + decryptor.finalize() + + def test_gcm_tag_decrypt_finalize(self, backend): + key = binascii.unhexlify(b"5211242698bed4774a090620a6ca56f3") + iv = binascii.unhexlify(b"b1e1349120b6e832ef976f5d") + aad = binascii.unhexlify(b"b6d729aab8e6416d7002b9faa794c410d8d2f193") + + encryptor = base.Cipher( + algorithms.AES(key), modes.GCM(iv), backend=backend + ).encryptor() + encryptor.authenticate_additional_data(aad) + encryptor.finalize() + tag = encryptor.tag + + decryptor = base.Cipher( + algorithms.AES(key), modes.GCM(iv), backend=backend + ).decryptor() + decryptor.authenticate_additional_data(aad) + + decryptor.finalize_with_tag(tag) + + def test_gcm_tag_decrypt_finalize_tag_length(self, backend): + decryptor = base.Cipher( + algorithms.AES(b"0" * 16), modes.GCM(b"0" * 12), backend=backend + ).decryptor() + with pytest.raises(ValueError): + decryptor.finalize_with_tag(b"tagtooshort") + + def test_buffer_protocol(self, backend): + data = bytearray(b"helloworld") + enc = base.Cipher( + algorithms.AES(bytearray(b"\x00" * 16)), + modes.GCM(bytearray(b"\x00" * 12)), + backend, + ).encryptor() + enc.authenticate_additional_data(bytearray(b"foo")) + ct = enc.update(data) + enc.finalize() + dec = base.Cipher( + algorithms.AES(bytearray(b"\x00" * 16)), + modes.GCM(bytearray(b"\x00" * 12), enc.tag), + backend, + ).decryptor() + dec.authenticate_additional_data(bytearray(b"foo")) + pt = dec.update(ct) + dec.finalize() + assert pt == data diff --git a/tests/hazmat/primitives/test_arc4.py b/tests/hazmat/primitives/test_arc4.py index 1a1734443704..de20b7098ae7 100644 --- a/tests/hazmat/primitives/test_arc4.py +++ b/tests/hazmat/primitives/test_arc4.py @@ -35,7 +35,7 @@ class TestARC4(object): "rfc-6229-128.txt", "rfc-6229-192.txt", "rfc-6229-256.txt", - "arc4.txt" + "arc4.txt", ], lambda key, **kwargs: algorithms.ARC4(binascii.unhexlify(key)), ) diff --git a/tests/hazmat/primitives/test_asym_utils.py b/tests/hazmat/primitives/test_asym_utils.py index fc9e9fd886b2..70bff012fbcb 100644 --- a/tests/hazmat/primitives/test_asym_utils.py +++ b/tests/hazmat/primitives/test_asym_utils.py @@ -7,19 +7,10 @@ import pytest from cryptography.hazmat.primitives.asymmetric.utils import ( - Prehashed, decode_dss_signature, decode_rfc6979_signature, - encode_dss_signature, encode_rfc6979_signature, + Prehashed, + decode_dss_signature, + encode_dss_signature, ) -from cryptography.utils import CryptographyDeprecationWarning - - -def test_deprecated_rfc6979_signature(): - with pytest.warns(CryptographyDeprecationWarning): - sig = encode_rfc6979_signature(1, 1) - assert sig == b"0\x06\x02\x01\x01\x02\x01\x01" - with pytest.warns(CryptographyDeprecationWarning): - decoded = decode_rfc6979_signature(sig) - assert decoded == (1, 1) def test_dss_signature(): @@ -29,11 +20,11 @@ def test_dss_signature(): r_s1 = ( 1037234182290683143945502320610861668562885151617, - 559776156650501990899426031439030258256861634312 + 559776156650501990899426031439030258256861634312, ) sig2 = encode_dss_signature(*r_s1) assert sig2 == ( - b'0-\x02\x15\x00\xb5\xaf0xg\xfb\x8bT9\x00\x13\xccg\x02\r\xdf\x1f,\x0b' + b"0-\x02\x15\x00\xb5\xaf0xg\xfb\x8bT9\x00\x13\xccg\x02\r\xdf\x1f,\x0b" b'\x81\x02\x14b\r;"\xabP1D\x0c>5\xea\xb6\xf4\x81)\x8f\x9e\x9f\x08' ) assert decode_dss_signature(sig2) == r_s1 @@ -42,10 +33,6 @@ def test_dss_signature(): assert sig3 == b"0\x06\x02\x01\x00\x02\x01\x00" assert decode_dss_signature(sig3) == (0, 0) - sig4 = encode_dss_signature(-1, 0) - assert sig4 == b"0\x06\x02\x01\xFF\x02\x01\x00" - assert decode_dss_signature(sig4) == (-1, 0) - def test_encode_dss_non_integer(): with pytest.raises(ValueError): @@ -64,6 +51,11 @@ def test_encode_dss_non_integer(): encode_dss_signature("hello", "world") +def test_encode_dss_negative(): + with pytest.raises(ValueError): + encode_dss_signature(-1, 0) + + def test_decode_dss_trailing_bytes(): with pytest.raises(ValueError): decode_dss_signature(b"0\x06\x02\x01\x01\x02\x01\x01\x00\x00\x00") diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py index 37158f153c7a..593199315a06 100644 --- a/tests/hazmat/primitives/test_block.py +++ b/tests/hazmat/primitives/test_block.py @@ -8,16 +8,18 @@ import pytest -from cryptography.exceptions import ( - AlreadyFinalized, _Reasons -) +from cryptography.exceptions import AlreadyFinalized, _Reasons from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives.ciphers import ( - Cipher, algorithms, base, modes + Cipher, + algorithms, + base, + modes, ) from .utils import ( - generate_aead_exception_test, generate_aead_tag_exception_test + generate_aead_exception_test, + generate_aead_tag_exception_test, ) from ...doubles import DummyCipherAlgorithm, DummyMode from ...utils import raises_unsupported_algorithm @@ -29,7 +31,7 @@ def test_creates_encryptor(self, backend): cipher = Cipher( algorithms.AES(binascii.unhexlify(b"0" * 32)), modes.CBC(binascii.unhexlify(b"0" * 32)), - backend + backend, ) assert isinstance(cipher.encryptor(), base.CipherContext) @@ -37,7 +39,7 @@ def test_creates_decryptor(self, backend): cipher = Cipher( algorithms.AES(binascii.unhexlify(b"0" * 32)), modes.CBC(binascii.unhexlify(b"0" * 32)), - backend + backend, ) assert isinstance(cipher.decryptor(), base.CipherContext) @@ -53,7 +55,7 @@ def test_use_after_finalize(self, backend): cipher = Cipher( algorithms.AES(binascii.unhexlify(b"0" * 32)), modes.CBC(binascii.unhexlify(b"0" * 32)), - backend + backend, ) encryptor = cipher.encryptor() encryptor.update(b"a" * 16) @@ -74,7 +76,7 @@ def test_use_update_into_after_finalize(self, backend): cipher = Cipher( algorithms.AES(binascii.unhexlify(b"0" * 32)), modes.CBC(binascii.unhexlify(b"0" * 32)), - backend + backend, ) encryptor = cipher.encryptor() encryptor.update(b"a" * 16) @@ -85,9 +87,7 @@ def test_use_update_into_after_finalize(self, backend): def test_unaligned_block_encryption(self, backend): cipher = Cipher( - algorithms.AES(binascii.unhexlify(b"0" * 32)), - modes.ECB(), - backend + algorithms.AES(binascii.unhexlify(b"0" * 32)), modes.ECB(), backend ) encryptor = cipher.encryptor() ct = encryptor.update(b"a" * 15) @@ -105,9 +105,7 @@ def test_unaligned_block_encryption(self, backend): @pytest.mark.parametrize("mode", [DummyMode(), None]) def test_nonexistent_cipher(self, backend, mode): - cipher = Cipher( - DummyCipherAlgorithm(), mode, backend - ) + cipher = Cipher(DummyCipherAlgorithm(), mode, backend) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER): cipher.encryptor() @@ -116,9 +114,7 @@ def test_nonexistent_cipher(self, backend, mode): def test_incorrectly_padded(self, backend): cipher = Cipher( - algorithms.AES(b"\x00" * 16), - modes.CBC(b"\x00" * 16), - backend + algorithms.AES(b"\x00" * 16), modes.CBC(b"\x00" * 16), backend ) encryptor = cipher.encryptor() encryptor.update(b"1") diff --git a/tests/hazmat/primitives/test_blowfish.py b/tests/hazmat/primitives/test_blowfish.py index 0c38b9816e4f..5f7480ec9234 100644 --- a/tests/hazmat/primitives/test_blowfish.py +++ b/tests/hazmat/primitives/test_blowfish.py @@ -24,7 +24,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestBlowfishModeECB(object): - test_ECB = generate_encrypt_test( + test_ecb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "Blowfish"), ["bf-ecb.txt"], @@ -41,7 +41,7 @@ class TestBlowfishModeECB(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestBlowfishModeCBC(object): - test_CBC = generate_encrypt_test( + test_cbc = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "Blowfish"), ["bf-cbc.txt"], @@ -58,7 +58,7 @@ class TestBlowfishModeCBC(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestBlowfishModeOFB(object): - test_OFB = generate_encrypt_test( + test_ofb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "Blowfish"), ["bf-ofb.txt"], @@ -75,7 +75,7 @@ class TestBlowfishModeOFB(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestBlowfishModeCFB(object): - test_CFB = generate_encrypt_test( + test_cfb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "Blowfish"), ["bf-cfb.txt"], diff --git a/tests/hazmat/primitives/test_camellia.py b/tests/hazmat/primitives/test_camellia.py index 87fcfe3d1072..b752345d3e44 100644 --- a/tests/hazmat/primitives/test_camellia.py +++ b/tests/hazmat/primitives/test_camellia.py @@ -13,9 +13,7 @@ from cryptography.hazmat.primitives.ciphers import algorithms, modes from .utils import generate_encrypt_test -from ...utils import ( - load_cryptrec_vectors, load_nist_vectors -) +from ...utils import load_cryptrec_vectors, load_nist_vectors @pytest.mark.supported( @@ -26,13 +24,13 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCamelliaModeECB(object): - test_ECB = generate_encrypt_test( + test_ecb = generate_encrypt_test( load_cryptrec_vectors, os.path.join("ciphers", "Camellia"), [ "camellia-128-ecb.txt", "camellia-192-ecb.txt", - "camellia-256-ecb.txt" + "camellia-256-ecb.txt", ], lambda key, **kwargs: algorithms.Camellia(binascii.unhexlify(key)), lambda **kwargs: modes.ECB(), @@ -47,7 +45,7 @@ class TestCamelliaModeECB(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCamelliaModeCBC(object): - test_CBC = generate_encrypt_test( + test_cbc = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "Camellia"), ["camellia-cbc.txt"], @@ -64,7 +62,7 @@ class TestCamelliaModeCBC(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCamelliaModeOFB(object): - test_OFB = generate_encrypt_test( + test_ofb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "Camellia"), ["camellia-ofb.txt"], @@ -81,7 +79,7 @@ class TestCamelliaModeOFB(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCamelliaModeCFB(object): - test_CFB = generate_encrypt_test( + test_cfb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "Camellia"), ["camellia-cfb.txt"], diff --git a/tests/hazmat/primitives/test_cast5.py b/tests/hazmat/primitives/test_cast5.py index ec51659d07ad..eff5d252f594 100644 --- a/tests/hazmat/primitives/test_cast5.py +++ b/tests/hazmat/primitives/test_cast5.py @@ -24,7 +24,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCAST5ModeECB(object): - test_ECB = generate_encrypt_test( + test_ecb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "CAST5"), ["cast5-ecb.txt"], @@ -41,12 +41,12 @@ class TestCAST5ModeECB(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCAST5ModeCBC(object): - test_CBC = generate_encrypt_test( + test_cbc = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "CAST5"), ["cast5-cbc.txt"], lambda key, **kwargs: algorithms.CAST5(binascii.unhexlify((key))), - lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)) + lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)), ) @@ -58,12 +58,12 @@ class TestCAST5ModeCBC(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCAST5ModeOFB(object): - test_OFB = generate_encrypt_test( + test_ofb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "CAST5"), ["cast5-ofb.txt"], lambda key, **kwargs: algorithms.CAST5(binascii.unhexlify((key))), - lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)) + lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)), ) @@ -75,10 +75,10 @@ class TestCAST5ModeOFB(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestCAST5ModeCFB(object): - test_CFB = generate_encrypt_test( + test_cfb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "CAST5"), ["cast5-cfb.txt"], lambda key, **kwargs: algorithms.CAST5(binascii.unhexlify((key))), - lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)) + lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)), ) diff --git a/tests/hazmat/primitives/test_chacha20.py b/tests/hazmat/primitives/test_chacha20.py index 7c475c0f70a1..cb12d3c91ae2 100644 --- a/tests/hazmat/primitives/test_chacha20.py +++ b/tests/hazmat/primitives/test_chacha20.py @@ -30,8 +30,8 @@ class TestChaCha20(object): _load_all_params( os.path.join("ciphers", "ChaCha20"), ["rfc7539.txt"], - load_nist_vectors - ) + load_nist_vectors, + ), ) def test_vectors(self, vector, backend): key = binascii.unhexlify(vector["key"]) @@ -47,9 +47,7 @@ def test_vectors(self, vector, backend): def test_buffer_protocol(self, backend): key = bytearray(os.urandom(32)) nonce = bytearray(os.urandom(16)) - cipher = Cipher( - algorithms.ChaCha20(key, nonce), None, backend - ) + cipher = Cipher(algorithms.ChaCha20(key, nonce), None, backend) enc = cipher.encryptor() ct = enc.update(bytearray(b"hello")) + enc.finalize() dec = cipher.decryptor() diff --git a/tests/hazmat/primitives/test_ciphers.py b/tests/hazmat/primitives/test_ciphers.py index f29ba9a916a1..4d82f0c13f42 100644 --- a/tests/hazmat/primitives/test_ciphers.py +++ b/tests/hazmat/primitives/test_ciphers.py @@ -14,20 +14,28 @@ from cryptography.hazmat.primitives import ciphers from cryptography.hazmat.primitives.ciphers import modes from cryptography.hazmat.primitives.ciphers.algorithms import ( - AES, ARC4, Blowfish, CAST5, Camellia, IDEA, SEED, TripleDES + AES, + ARC4, + Blowfish, + CAST5, + Camellia, + IDEA, + SEED, + TripleDES, ) from ...utils import ( - load_nist_vectors, load_vectors_from_file, raises_unsupported_algorithm + load_nist_vectors, + load_vectors_from_file, + raises_unsupported_algorithm, ) class TestAES(object): - @pytest.mark.parametrize(("key", "keysize"), [ - (b"0" * 32, 128), - (b"0" * 48, 192), - (b"0" * 64, 256), - ]) + @pytest.mark.parametrize( + ("key", "keysize"), + [(b"0" * 32, 128), (b"0" * 48, 192), (b"0" * 64, 256)], + ) def test_key_size(self, key, keysize): cipher = AES(binascii.unhexlify(key)) assert cipher.key_size == keysize @@ -44,8 +52,7 @@ def test_invalid_key_type(self): class TestAESXTS(object): @pytest.mark.requires_backend_interface(interface=CipherBackend) @pytest.mark.parametrize( - "mode", - (modes.CBC, modes.CTR, modes.CFB, modes.CFB8, modes.OFB) + "mode", (modes.CBC, modes.CTR, modes.CFB, modes.CFB8, modes.OFB) ) def test_invalid_key_size_with_mode(self, mode, backend): with pytest.raises(ValueError): @@ -66,11 +73,10 @@ def test_xts_wrong_key_size(self, backend): class TestCamellia(object): - @pytest.mark.parametrize(("key", "keysize"), [ - (b"0" * 32, 128), - (b"0" * 48, 192), - (b"0" * 64, 256), - ]) + @pytest.mark.parametrize( + ("key", "keysize"), + [(b"0" * 32, 128), (b"0" * 48, 192), (b"0" * 64, 256)], + ) def test_key_size(self, key, keysize): cipher = Camellia(binascii.unhexlify(key)) assert cipher.key_size == keysize @@ -85,11 +91,7 @@ def test_invalid_key_type(self): class TestTripleDES(object): - @pytest.mark.parametrize("key", [ - b"0" * 16, - b"0" * 32, - b"0" * 48, - ]) + @pytest.mark.parametrize("key", [b"0" * 16, b"0" * 32, b"0" * 48]) def test_key_size(self, key): cipher = TripleDES(binascii.unhexlify(key)) assert cipher.key_size == 192 @@ -104,9 +106,10 @@ def test_invalid_key_type(self): class TestBlowfish(object): - @pytest.mark.parametrize(("key", "keysize"), [ - (b"0" * (keysize // 4), keysize) for keysize in range(32, 449, 8) - ]) + @pytest.mark.parametrize( + ("key", "keysize"), + [(b"0" * (keysize // 4), keysize) for keysize in range(32, 449, 8)], + ) def test_key_size(self, key, keysize): cipher = Blowfish(binascii.unhexlify(key)) assert cipher.key_size == keysize @@ -121,9 +124,10 @@ def test_invalid_key_type(self): class TestCAST5(object): - @pytest.mark.parametrize(("key", "keysize"), [ - (b"0" * (keysize // 4), keysize) for keysize in range(40, 129, 8) - ]) + @pytest.mark.parametrize( + ("key", "keysize"), + [(b"0" * (keysize // 4), keysize) for keysize in range(40, 129, 8)], + ) def test_key_size(self, key, keysize): cipher = CAST5(binascii.unhexlify(key)) assert cipher.key_size == keysize @@ -138,15 +142,18 @@ def test_invalid_key_type(self): class TestARC4(object): - @pytest.mark.parametrize(("key", "keysize"), [ - (b"0" * 10, 40), - (b"0" * 14, 56), - (b"0" * 16, 64), - (b"0" * 20, 80), - (b"0" * 32, 128), - (b"0" * 48, 192), - (b"0" * 64, 256), - ]) + @pytest.mark.parametrize( + ("key", "keysize"), + [ + (b"0" * 10, 40), + (b"0" * 14, 56), + (b"0" * 16, 64), + (b"0" * 20, 80), + (b"0" * 32, 128), + (b"0" * 48, 192), + (b"0" * 64, 256), + ], + ) def test_key_size(self, key, keysize): cipher = ARC4(binascii.unhexlify(key)) assert cipher.key_size == keysize @@ -207,8 +214,8 @@ class TestCipherUpdateInto(object): "params", load_vectors_from_file( os.path.join("ciphers", "AES", "ECB", "ECBGFSbox128.rsp"), - load_nist_vectors - ) + load_nist_vectors, + ), ) def test_update_into(self, params, backend): key = binascii.unhexlify(params["key"]) @@ -272,8 +279,8 @@ def test_finalize_with_tag_already_finalized(self, backend): "params", load_vectors_from_file( os.path.join("ciphers", "AES", "ECB", "ECBGFSbox128.rsp"), - load_nist_vectors - ) + load_nist_vectors, + ), ) def test_update_into_multiple_calls(self, params, backend): key = binascii.unhexlify(params["key"]) @@ -309,3 +316,29 @@ def test_update_into_buffer_too_small_gcm(self, backend): buf = bytearray(5) with pytest.raises(ValueError): encryptor.update_into(b"testing", buf) + + def test_update_into_auto_chunking(self, backend, monkeypatch): + key = b"\x00" * 16 + c = ciphers.Cipher(AES(key), modes.ECB(), backend) + encryptor = c.encryptor() + # Lower max chunk size so we can test chunking + monkeypatch.setattr(encryptor._ctx, "_MAX_CHUNK_SIZE", 40) + buf = bytearray(527) + pt = b"abcdefghijklmnopqrstuvwxyz012345" * 16 # 512 bytes + processed = encryptor.update_into(pt, buf) + assert processed == 512 + decryptor = c.decryptor() + # Change max chunk size to verify alternate boundaries don't matter + monkeypatch.setattr(decryptor._ctx, "_MAX_CHUNK_SIZE", 73) + decbuf = bytearray(527) + decprocessed = decryptor.update_into(buf[:processed], decbuf) + assert decbuf[:decprocessed] == pt + + def test_max_chunk_size_fits_in_int32(self, backend): + # max chunk must fit in signed int32 or else a call large enough to + # cause chunking will result in the very OverflowError we want to + # avoid with chunking. + key = b"\x00" * 16 + c = ciphers.Cipher(AES(key), modes.ECB(), backend) + encryptor = c.encryptor() + backend._ffi.new("int *", encryptor._ctx._MAX_CHUNK_SIZE) diff --git a/tests/hazmat/primitives/test_cmac.py b/tests/hazmat/primitives/test_cmac.py index e319396d6865..e4a35df621fd 100644 --- a/tests/hazmat/primitives/test_cmac.py +++ b/tests/hazmat/primitives/test_cmac.py @@ -9,32 +9,42 @@ import pytest from cryptography.exceptions import ( - AlreadyFinalized, InvalidSignature, _Reasons + AlreadyFinalized, + InvalidSignature, + _Reasons, ) from cryptography.hazmat.backends.interfaces import CMACBackend from cryptography.hazmat.primitives.ciphers.algorithms import ( - AES, ARC4, TripleDES + AES, + ARC4, + TripleDES, ) from cryptography.hazmat.primitives.cmac import CMAC from ...utils import ( - load_nist_vectors, load_vectors_from_file, raises_unsupported_algorithm + load_nist_vectors, + load_vectors_from_file, + raises_unsupported_algorithm, ) vectors_aes128 = load_vectors_from_file( - "CMAC/nist-800-38b-aes128.txt", load_nist_vectors) + "CMAC/nist-800-38b-aes128.txt", load_nist_vectors +) vectors_aes192 = load_vectors_from_file( - "CMAC/nist-800-38b-aes192.txt", load_nist_vectors) + "CMAC/nist-800-38b-aes192.txt", load_nist_vectors +) vectors_aes256 = load_vectors_from_file( - "CMAC/nist-800-38b-aes256.txt", load_nist_vectors) + "CMAC/nist-800-38b-aes256.txt", load_nist_vectors +) vectors_aes = vectors_aes128 + vectors_aes192 + vectors_aes256 vectors_3des = load_vectors_from_file( - "CMAC/nist-800-38b-3des.txt", load_nist_vectors) + "CMAC/nist-800-38b-3des.txt", load_nist_vectors +) fake_key = b"\x00" * 16 @@ -43,8 +53,9 @@ class TestCMAC(object): @pytest.mark.supported( only_if=lambda backend: backend.cmac_algorithm_supported( - AES(fake_key)), - skip_message="Does not support CMAC." + AES(fake_key) + ), + skip_message="Does not support CMAC.", ) @pytest.mark.parametrize("params", vectors_aes) def test_aes_generate(self, backend, params): @@ -58,8 +69,9 @@ def test_aes_generate(self, backend, params): @pytest.mark.supported( only_if=lambda backend: backend.cmac_algorithm_supported( - AES(fake_key)), - skip_message="Does not support CMAC." + AES(fake_key) + ), + skip_message="Does not support CMAC.", ) @pytest.mark.parametrize("params", vectors_aes) def test_aes_verify(self, backend, params): @@ -73,8 +85,9 @@ def test_aes_verify(self, backend, params): @pytest.mark.supported( only_if=lambda backend: backend.cmac_algorithm_supported( - TripleDES(fake_key)), - skip_message="Does not support CMAC." + TripleDES(fake_key) + ), + skip_message="Does not support CMAC.", ) @pytest.mark.parametrize("params", vectors_3des) def test_3des_generate(self, backend, params): @@ -93,8 +106,9 @@ def test_3des_generate(self, backend, params): @pytest.mark.supported( only_if=lambda backend: backend.cmac_algorithm_supported( - TripleDES(fake_key)), - skip_message="Does not support CMAC." + TripleDES(fake_key) + ), + skip_message="Does not support CMAC.", ) @pytest.mark.parametrize("params", vectors_3des) def test_3des_verify(self, backend, params): @@ -113,8 +127,9 @@ def test_3des_verify(self, backend, params): @pytest.mark.supported( only_if=lambda backend: backend.cmac_algorithm_supported( - AES(fake_key)), - skip_message="Does not support CMAC." + AES(fake_key) + ), + skip_message="Does not support CMAC.", ) def test_invalid_verify(self, backend): key = b"2b7e151628aed2a6abf7158809cf4f3c" @@ -125,9 +140,8 @@ def test_invalid_verify(self, backend): cmac.verify(b"foobar") @pytest.mark.supported( - only_if=lambda backend: backend.cipher_supported( - ARC4(fake_key), None), - skip_message="Does not support CMAC." + only_if=lambda backend: backend.cipher_supported(ARC4(fake_key), None), + skip_message="Does not support CMAC.", ) def test_invalid_algorithm(self, backend): key = b"0102030405" @@ -136,8 +150,9 @@ def test_invalid_algorithm(self, backend): @pytest.mark.supported( only_if=lambda backend: backend.cmac_algorithm_supported( - AES(fake_key)), - skip_message="Does not support CMAC." + AES(fake_key) + ), + skip_message="Does not support CMAC.", ) def test_raises_after_finalize(self, backend): key = b"2b7e151628aed2a6abf7158809cf4f3c" @@ -158,23 +173,25 @@ def test_raises_after_finalize(self, backend): @pytest.mark.supported( only_if=lambda backend: backend.cmac_algorithm_supported( - AES(fake_key)), - skip_message="Does not support CMAC." + AES(fake_key) + ), + skip_message="Does not support CMAC.", ) def test_verify_reject_unicode(self, backend): key = b"2b7e151628aed2a6abf7158809cf4f3c" cmac = CMAC(AES(key), backend) with pytest.raises(TypeError): - cmac.update(u'') + cmac.update(u"") with pytest.raises(TypeError): - cmac.verify(u'') + cmac.verify(u"") @pytest.mark.supported( only_if=lambda backend: backend.cmac_algorithm_supported( - AES(fake_key)), - skip_message="Does not support CMAC." + AES(fake_key) + ), + skip_message="Does not support CMAC.", ) def test_copy_with_backend(self, backend): key = b"2b7e151628aed2a6abf7158809cf4f3c" @@ -185,8 +202,9 @@ def test_copy_with_backend(self, backend): @pytest.mark.supported( only_if=lambda backend: backend.cmac_algorithm_supported( - AES(fake_key)), - skip_message="Does not support CMAC." + AES(fake_key) + ), + skip_message="Does not support CMAC.", ) def test_buffer_protocol(self, backend): key = bytearray(b"2b7e151628aed2a6abf7158809cf4f3c") diff --git a/tests/hazmat/primitives/test_concatkdf.py b/tests/hazmat/primitives/test_concatkdf.py index 673150999865..271e01175d30 100644 --- a/tests/hazmat/primitives/test_concatkdf.py +++ b/tests/hazmat/primitives/test_concatkdf.py @@ -8,9 +8,7 @@ import pytest -from cryptography.exceptions import ( - AlreadyFinalized, InvalidKey, _Reasons -) +from cryptography.exceptions import AlreadyFinalized, InvalidKey, _Reasons from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.backends.interfaces import HashBackend from cryptography.hazmat.primitives import hashes @@ -102,38 +100,26 @@ def test_invalid_verify(self, backend): def test_unicode_typeerror(self, backend): with pytest.raises(TypeError): ConcatKDFHash( - hashes.SHA256(), - 16, - otherinfo=u"foo", - backend=backend + hashes.SHA256(), 16, otherinfo=u"foo", backend=backend ) with pytest.raises(TypeError): ckdf = ConcatKDFHash( - hashes.SHA256(), - 16, - otherinfo=None, - backend=backend + hashes.SHA256(), 16, otherinfo=None, backend=backend ) ckdf.derive(u"foo") with pytest.raises(TypeError): ckdf = ConcatKDFHash( - hashes.SHA256(), - 16, - otherinfo=None, - backend=backend + hashes.SHA256(), 16, otherinfo=None, backend=backend ) ckdf.verify(u"foo", b"bar") with pytest.raises(TypeError): ckdf = ConcatKDFHash( - hashes.SHA256(), - 16, - otherinfo=None, - backend=backend + hashes.SHA256(), 16, otherinfo=None, backend=backend ) ckdf.verify(b"foo", u"bar") @@ -162,8 +148,10 @@ def test_derive(self, backend): b"8f0af7fce1d045edbc5790931e8d5ca79c73" ) - okm = binascii.unhexlify(b"64ce901db10d558661f10b6836a122a7" - b"605323ce2f39bf27eaaac8b34cf89f2f") + okm = binascii.unhexlify( + b"64ce901db10d558661f10b6836a122a7" + b"605323ce2f39bf27eaaac8b34cf89f2f" + ) oinfo = binascii.unhexlify( b"a1b2c3d4e55e600be5f367e0e8a465f4bf2704db00c9325c" @@ -181,8 +169,10 @@ def test_buffer_protocol(self, backend): b"8f0af7fce1d045edbc5790931e8d5ca79c73" ) - okm = binascii.unhexlify(b"64ce901db10d558661f10b6836a122a7" - b"605323ce2f39bf27eaaac8b34cf89f2f") + okm = binascii.unhexlify( + b"64ce901db10d558661f10b6836a122a7" + b"605323ce2f39bf27eaaac8b34cf89f2f" + ) oinfo = binascii.unhexlify( b"a1b2c3d4e55e600be5f367e0e8a465f4bf2704db00c9325c" @@ -200,8 +190,10 @@ def test_derive_explicit_salt(self, backend): b"8f0af7fce1d045edbc5790931e8d5ca79c73" ) - okm = binascii.unhexlify(b"64ce901db10d558661f10b6836a122a7" - b"605323ce2f39bf27eaaac8b34cf89f2f") + okm = binascii.unhexlify( + b"64ce901db10d558661f10b6836a122a7" + b"605323ce2f39bf27eaaac8b34cf89f2f" + ) oinfo = binascii.unhexlify( b"a1b2c3d4e55e600be5f367e0e8a465f4bf2704db00c9325c" @@ -221,8 +213,10 @@ def test_verify(self, backend): b"8f0af7fce1d045edbc5790931e8d5ca79c73" ) - okm = binascii.unhexlify(b"64ce901db10d558661f10b6836a122a7" - b"605323ce2f39bf27eaaac8b34cf89f2f") + okm = binascii.unhexlify( + b"64ce901db10d558661f10b6836a122a7" + b"605323ce2f39bf27eaaac8b34cf89f2f" + ) oinfo = binascii.unhexlify( b"a1b2c3d4e55e600be5f367e0e8a465f4bf2704db00c9325c" @@ -254,45 +248,38 @@ def test_unicode_typeerror(self, backend): with pytest.raises(TypeError): ConcatKDFHMAC( hashes.SHA256(), - 16, salt=u"foo", + 16, + salt=u"foo", otherinfo=None, - backend=backend + backend=backend, ) with pytest.raises(TypeError): ConcatKDFHMAC( hashes.SHA256(), - 16, salt=None, + 16, + salt=None, otherinfo=u"foo", - backend=backend + backend=backend, ) with pytest.raises(TypeError): ckdf = ConcatKDFHMAC( - hashes.SHA256(), - 16, salt=None, - otherinfo=None, - backend=backend + hashes.SHA256(), 16, salt=None, otherinfo=None, backend=backend ) ckdf.derive(u"foo") with pytest.raises(TypeError): ckdf = ConcatKDFHMAC( - hashes.SHA256(), - 16, salt=None, - otherinfo=None, - backend=backend + hashes.SHA256(), 16, salt=None, otherinfo=None, backend=backend ) ckdf.verify(u"foo", b"bar") with pytest.raises(TypeError): ckdf = ConcatKDFHMAC( - hashes.SHA256(), - 16, salt=None, - otherinfo=None, - backend=backend + hashes.SHA256(), 16, salt=None, otherinfo=None, backend=backend ) ckdf.verify(b"foo", u"bar") diff --git a/tests/hazmat/primitives/test_dh.py b/tests/hazmat/primitives/test_dh.py index c667cd16e1a6..63a7c642ef7a 100644 --- a/tests/hazmat/primitives/test_dh.py +++ b/tests/hazmat/primitives/test_dh.py @@ -11,11 +11,15 @@ import pytest from cryptography.hazmat.backends.interfaces import ( - DERSerializationBackend, DHBackend, PEMSerializationBackend) + DERSerializationBackend, + DHBackend, + PEMSerializationBackend, +) from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import dh from cryptography.utils import int_from_bytes +from .fixtures_dh import FFDH3072_P from ...doubles import DummyKeySerializationEncryption from ...utils import load_nist_vectors, load_vectors_from_file @@ -24,100 +28,72 @@ def _skip_dhx_unsupported(backend, is_dhx): if not is_dhx: return if not backend.dh_x942_serialization_supported(): - pytest.skip( - "DH x9.42 serialization is not supported" - ) + pytest.skip("DH x9.42 serialization is not supported") def test_dh_parameternumbers(): - params = dh.DHParameterNumbers( - 65537, 2 - ) + params = dh.DHParameterNumbers(65537, 2) assert params.p == 65537 assert params.g == 2 with pytest.raises(TypeError): - dh.DHParameterNumbers( - None, 2 - ) + dh.DHParameterNumbers(None, 2) with pytest.raises(TypeError): - dh.DHParameterNumbers( - 65537, None - ) + dh.DHParameterNumbers(65537, None) with pytest.raises(TypeError): - dh.DHParameterNumbers( - None, None - ) + dh.DHParameterNumbers(None, None) with pytest.raises(ValueError): - dh.DHParameterNumbers( - 65537, 1 - ) + dh.DHParameterNumbers(65537, 1) - params = dh.DHParameterNumbers( - 65537, 7, 1245 - ) + params = dh.DHParameterNumbers(65537, 7, 1245) assert params.p == 65537 assert params.g == 7 assert params.q == 1245 with pytest.raises(TypeError): - dh.DHParameterNumbers( - 65537, 2, "hello" - ) + dh.DHParameterNumbers(65537, 2, "hello") def test_dh_numbers(): - params = dh.DHParameterNumbers( - 65537, 2 - ) + params = dh.DHParameterNumbers(65537, 2) - public = dh.DHPublicNumbers( - 1, params - ) + public = dh.DHPublicNumbers(1, params) assert public.parameter_numbers is params assert public.y == 1 with pytest.raises(TypeError): - dh.DHPublicNumbers( - 1, None - ) + dh.DHPublicNumbers(1, None) with pytest.raises(TypeError): - dh.DHPublicNumbers( - None, params - ) + dh.DHPublicNumbers(None, params) - private = dh.DHPrivateNumbers( - 1, public - ) + private = dh.DHPrivateNumbers(1, public) assert private.public_numbers is public assert private.x == 1 with pytest.raises(TypeError): - dh.DHPrivateNumbers( - 1, None - ) + dh.DHPrivateNumbers(1, None) with pytest.raises(TypeError): - dh.DHPrivateNumbers( - None, public - ) + dh.DHPrivateNumbers(None, public) def test_dh_parameter_numbers_equality(): assert dh.DHParameterNumbers(65537, 2) == dh.DHParameterNumbers(65537, 2) assert dh.DHParameterNumbers(65537, 7, 12345) == dh.DHParameterNumbers( - 65537, 7, 12345) + 65537, 7, 12345 + ) assert dh.DHParameterNumbers(6, 2) != dh.DHParameterNumbers(65537, 2) assert dh.DHParameterNumbers(65537, 2, 123) != dh.DHParameterNumbers( - 65537, 2, 456) + 65537, 2, 456 + ) assert dh.DHParameterNumbers(65537, 5) != dh.DHParameterNumbers(65537, 2) assert dh.DHParameterNumbers(65537, 2) != object() @@ -157,18 +133,25 @@ def test_unsupported_generator_generate_dh(self, backend): dh.generate_parameters(7, 512, backend) def test_dh_parameters_supported(self, backend): - assert backend.dh_parameters_supported(23, 5) - assert not backend.dh_parameters_supported(23, 18) + valid_p = int( + b"907c7211ae61aaaba1825ff53b6cb71ac6df9f1a424c033f4a0a41ac42fad3a9" + b"bcfc7f938a269710ed69e330523e4039029b7900977c740990d46efed79b9bbe" + b"73505ae878808944ce4d9c6c52daecc0a87dc889c53499be93db8551ee685f30" + b"349bf1b443d4ebaee0d5e8b441a40d4e8178f8f612f657a5eb91e0a8e" + b"107755f", + 16, + ) + assert backend.dh_parameters_supported(valid_p, 5) + assert not backend.dh_parameters_supported(23, 22) @pytest.mark.parametrize( "vector", load_vectors_from_file( - os.path.join("asymmetric", "DH", "rfc3526.txt"), - load_nist_vectors - ) + os.path.join("asymmetric", "DH", "rfc3526.txt"), load_nist_vectors + ), ) def test_dh_parameters_allows_rfc3526_groups(self, backend, vector): - p = int_from_bytes(binascii.unhexlify(vector["p"]), 'big') + p = int_from_bytes(binascii.unhexlify(vector["p"]), "big") params = dh.DHParameterNumbers(p, int(vector["g"])) param = params.parameters(backend) key = param.generate_private_key() @@ -181,19 +164,22 @@ def test_dh_parameters_allows_rfc3526_groups(self, backend, vector): @pytest.mark.parametrize( "vector", load_vectors_from_file( - os.path.join("asymmetric", "DH", "RFC5114.txt"), - load_nist_vectors)) + os.path.join("asymmetric", "DH", "RFC5114.txt"), load_nist_vectors + ), + ) def test_dh_parameters_supported_with_q(self, backend, vector): - assert backend.dh_parameters_supported(int(vector["p"], 16), - int(vector["g"], 16), - int(vector["q"], 16)) + assert backend.dh_parameters_supported( + int(vector["p"], 16), int(vector["g"], 16), int(vector["q"], 16) + ) + @pytest.mark.skip_fips(reason="modulus too small for FIPS") @pytest.mark.parametrize("with_q", [False, True]) def test_convert_to_numbers(self, backend, with_q): if with_q: vector = load_vectors_from_file( os.path.join("asymmetric", "DH", "RFC5114.txt"), - load_nist_vectors)[0] + load_nist_vectors, + )[0] p = int(vector["p"], 16) g = int(vector["g"], 16) q = int(vector["q"], 16) @@ -214,12 +200,13 @@ def test_convert_to_numbers(self, backend, with_q): deserialized_public = public.public_key(backend) deserialized_private = private.private_key(backend) - assert isinstance(deserialized_params, - dh.DHParametersWithSerialization) - assert isinstance(deserialized_public, - dh.DHPublicKeyWithSerialization) - assert isinstance(deserialized_private, - dh.DHPrivateKeyWithSerialization) + assert isinstance( + deserialized_params, dh.DHParametersWithSerialization + ) + assert isinstance(deserialized_public, dh.DHPublicKeyWithSerialization) + assert isinstance( + deserialized_private, dh.DHPrivateKeyWithSerialization + ) def test_numbers_unsupported_parameters(self, backend): # p is set to 21 because when calling private_key we want it to @@ -234,12 +221,14 @@ def test_numbers_unsupported_parameters(self, backend): with pytest.raises(ValueError): private.private_key(backend) + @pytest.mark.skip_fips(reason="FIPS requires key size >= 2048") @pytest.mark.parametrize("with_q", [False, True]) def test_generate_dh(self, backend, with_q): if with_q: vector = load_vectors_from_file( os.path.join("asymmetric", "DH", "RFC5114.txt"), - load_nist_vectors)[0] + load_nist_vectors, + )[0] p = int(vector["p"], 16) g = int(vector["g"], 16) q = int(vector["q"], 16) @@ -274,7 +263,7 @@ def test_generate_dh(self, backend, with_q): assert isinstance(key.parameters(), dh.DHParameters) def test_exchange(self, backend): - parameters = dh.generate_parameters(2, 512, backend) + parameters = FFDH3072_P.parameters(backend) assert isinstance(parameters, dh.DHParameters) key1 = parameters.generate_private_key() @@ -282,65 +271,82 @@ def test_exchange(self, backend): symkey1 = key1.exchange(key2.public_key()) assert symkey1 - assert len(symkey1) == 512 // 8 + assert len(symkey1) == 3072 // 8 symkey2 = key2.exchange(key1.public_key()) assert symkey1 == symkey2 def test_exchange_algorithm(self, backend): - parameters = dh.generate_parameters(2, 512, backend) - + parameters = FFDH3072_P.parameters(backend) key1 = parameters.generate_private_key() key2 = parameters.generate_private_key() shared_key_bytes = key2.exchange(key1.public_key()) - symkey = int_from_bytes(shared_key_bytes, 'big') + symkey = int_from_bytes(shared_key_bytes, "big") - symkey_manual = pow(key1.public_key().public_numbers().y, - key2.private_numbers().x, - parameters.parameter_numbers().p) + symkey_manual = pow( + key1.public_key().public_numbers().y, + key2.private_numbers().x, + parameters.parameter_numbers().p, + ) assert symkey == symkey_manual + @pytest.mark.skip_fips(reason="key_size too small for FIPS") def test_symmetric_key_padding(self, backend): """ This test has specific parameters that produce a symmetric key In length 63 bytes instead 64. We make sure here that we add padding to the key. """ - p = int("11859949538425015739337467917303613431031019140213666" - "129025407300654026585086345323066284800963463204246390" - "256567934582260424238844463330887962689642467123") + p = int( + "11859949538425015739337467917303613431031019140213666" + "129025407300654026585086345323066284800963463204246390" + "256567934582260424238844463330887962689642467123" + ) g = 2 - y = int("32155788395534640648739966373159697798396966919821525" - "72238852825117261342483718574508213761865276905503199" - "969908098203345481366464874759377454476688391248") - x = int("409364065449673443397833358558926598469347813468816037" - "268451847116982490733450463194921405069999008617231539" - "7147035896687401350877308899732826446337707128") + y = int( + "32155788395534640648739966373159697798396966919821525" + "72238852825117261342483718574508213761865276905503199" + "969908098203345481366464874759377454476688391248" + ) + x = int( + "409364065449673443397833358558926598469347813468816037" + "268451847116982490733450463194921405069999008617231539" + "7147035896687401350877308899732826446337707128" + ) parameters = dh.DHParameterNumbers(p, g) public = dh.DHPublicNumbers(y, parameters) private = dh.DHPrivateNumbers(x, public) key = private.private_key(backend) symkey = key.exchange(public.public_key(backend)) assert len(symkey) == 512 // 8 - assert symkey[:1] == b'\x00' + assert symkey[:1] == b"\x00" @pytest.mark.parametrize( "vector", load_vectors_from_file( os.path.join("asymmetric", "DH", "bad_exchange.txt"), - load_nist_vectors)) + load_nist_vectors, + ), + ) def test_bad_exchange(self, backend, vector): - parameters1 = dh.DHParameterNumbers(int(vector["p1"]), - int(vector["g"])) + if ( + backend._fips_enabled + and int(vector["p1"]) < backend._fips_dh_min_modulus + ): + pytest.skip("modulus too small for FIPS mode") + parameters1 = dh.DHParameterNumbers( + int(vector["p1"]), int(vector["g"]) + ) public1 = dh.DHPublicNumbers(int(vector["y1"]), parameters1) private1 = dh.DHPrivateNumbers(int(vector["x1"]), public1) key1 = private1.private_key(backend) pub_key1 = key1.public_key() - parameters2 = dh.DHParameterNumbers(int(vector["p2"]), - int(vector["g"])) + parameters2 = dh.DHParameterNumbers( + int(vector["p2"]), int(vector["g"]) + ) public2 = dh.DHPublicNumbers(int(vector["y2"]), parameters2) private2 = dh.DHPrivateNumbers(int(vector["x2"]), public2) key2 = private2.private_key(backend) @@ -360,27 +366,33 @@ def test_bad_exchange(self, backend, vector): @pytest.mark.parametrize( "vector", load_vectors_from_file( - os.path.join("asymmetric", "DH", "vec.txt"), - load_nist_vectors)) + os.path.join("asymmetric", "DH", "vec.txt"), load_nist_vectors + ), + ) def test_dh_vectors(self, backend, vector): - parameters = dh.DHParameterNumbers(int(vector["p"]), - int(vector["g"])) + if ( + backend._fips_enabled + and int(vector["p"]) < backend._fips_dh_min_modulus + ): + pytest.skip("modulus too small for FIPS mode") + parameters = dh.DHParameterNumbers(int(vector["p"]), int(vector["g"])) public = dh.DHPublicNumbers(int(vector["y"]), parameters) private = dh.DHPrivateNumbers(int(vector["x"]), public) key = private.private_key(backend) symkey = key.exchange(public.public_key(backend)) - assert int_from_bytes(symkey, 'big') == int(vector["k"], 16) + assert int_from_bytes(symkey, "big") == int(vector["k"], 16) @pytest.mark.parametrize( "vector", load_vectors_from_file( - os.path.join("asymmetric", "DH", "RFC5114.txt"), - load_nist_vectors)) + os.path.join("asymmetric", "DH", "RFC5114.txt"), load_nist_vectors + ), + ) def test_dh_vectors_with_q(self, backend, vector): - parameters = dh.DHParameterNumbers(int(vector["p"], 16), - int(vector["g"], 16), - int(vector["q"], 16)) + parameters = dh.DHParameterNumbers( + int(vector["p"], 16), int(vector["g"], 16), int(vector["q"], 16) + ) public1 = dh.DHPublicNumbers(int(vector["ystatcavs"], 16), parameters) private1 = dh.DHPrivateNumbers(int(vector["xstatcavs"], 16), public1) public2 = dh.DHPublicNumbers(int(vector["ystatiut"], 16), parameters) @@ -390,35 +402,28 @@ def test_dh_vectors_with_q(self, backend, vector): symkey1 = key1.exchange(public2.public_key(backend)) symkey2 = key2.exchange(public1.public_key(backend)) - assert int_from_bytes(symkey1, 'big') == int(vector["z"], 16) - assert int_from_bytes(symkey2, 'big') == int(vector["z"], 16) + assert int_from_bytes(symkey1, "big") == int(vector["z"], 16) + assert int_from_bytes(symkey2, "big") == int(vector["z"], 16) @pytest.mark.requires_backend_interface(interface=DHBackend) @pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) @pytest.mark.requires_backend_interface(interface=DERSerializationBackend) class TestDHPrivateKeySerialization(object): - @pytest.mark.parametrize( ("encoding", "loader_func"), [ - [ - serialization.Encoding.PEM, - serialization.load_pem_private_key - ], - [ - serialization.Encoding.DER, - serialization.load_der_private_key - ], - ] + [serialization.Encoding.PEM, serialization.load_pem_private_key], + [serialization.Encoding.DER, serialization.load_der_private_key], + ], ) - def test_private_bytes_unencrypted(self, backend, encoding, - loader_func): - parameters = dh.generate_parameters(2, 512, backend) + def test_private_bytes_unencrypted(self, backend, encoding, loader_func): + parameters = FFDH3072_P.parameters(backend) key = parameters.generate_private_key() serialized = key.private_bytes( - encoding, serialization.PrivateFormat.PKCS8, - serialization.NoEncryption() + encoding, + serialization.PrivateFormat.PKCS8, + serialization.NoEncryption(), ) loaded_key = loader_func(serialized, None, backend) loaded_priv_num = loaded_key.private_numbers() @@ -432,10 +437,10 @@ def test_private_bytes_unencrypted(self, backend, encoding, (serialization.Encoding.DER, serialization.PrivateFormat.Raw), (serialization.Encoding.Raw, serialization.PrivateFormat.Raw), (serialization.Encoding.X962, serialization.PrivateFormat.PKCS8), - ] + ], ) def test_private_bytes_rejects_invalid(self, encoding, fmt, backend): - parameters = dh.generate_parameters(2, 512, backend) + parameters = FFDH3072_P.parameters(backend) key = parameters.generate_private_key() with pytest.raises(ValueError): key.private_bytes(encoding, fmt, serialization.NoEncryption()) @@ -448,35 +453,39 @@ def test_private_bytes_rejects_invalid(self, encoding, fmt, backend): serialization.load_pem_private_key, serialization.Encoding.PEM, False, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhkey.der"), serialization.load_der_private_key, serialization.Encoding.DER, False, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.pem"), serialization.load_pem_private_key, serialization.Encoding.PEM, True, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.der"), serialization.load_der_private_key, serialization.Encoding.DER, True, - ) - ] + ), + ], ) - def test_private_bytes_match(self, key_path, loader_func, - encoding, is_dhx, backend): + def test_private_bytes_match( + self, key_path, loader_func, encoding, is_dhx, backend + ): _skip_dhx_unsupported(backend, is_dhx) key_bytes = load_vectors_from_file( - key_path, - lambda pemfile: pemfile.read(), mode="rb" + key_path, lambda pemfile: pemfile.read(), mode="rb" ) key = loader_func(key_bytes, None, backend) serialized = key.private_bytes( - encoding, serialization.PrivateFormat.PKCS8, - serialization.NoEncryption() + encoding, + serialization.PrivateFormat.PKCS8, + serialization.NoEncryption(), ) assert serialized == key_bytes @@ -488,30 +497,33 @@ def test_private_bytes_match(self, key_path, loader_func, serialization.load_pem_private_key, os.path.join("asymmetric", "DH", "dhkey.txt"), False, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhkey.der"), serialization.load_der_private_key, os.path.join("asymmetric", "DH", "dhkey.txt"), False, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.pem"), serialization.load_pem_private_key, os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.txt"), True, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.der"), serialization.load_der_private_key, os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.txt"), True, - ) - ] + ), + ], ) - def test_private_bytes_values(self, key_path, loader_func, - vec_path, is_dhx, backend): + def test_private_bytes_values( + self, key_path, loader_func, vec_path, is_dhx, backend + ): _skip_dhx_unsupported(backend, is_dhx) key_bytes = load_vectors_from_file( - key_path, - lambda pemfile: pemfile.read(), mode="rb" + key_path, lambda pemfile: pemfile.read(), mode="rb" ) vec = load_vectors_from_file(vec_path, load_nist_vectors)[0] key = loader_func(key_bytes, None, backend) @@ -519,63 +531,66 @@ def test_private_bytes_values(self, key_path, loader_func, assert private_numbers.x == int(vec["x"], 16) assert private_numbers.public_numbers.y == int(vec["y"], 16) assert private_numbers.public_numbers.parameter_numbers.g == int( - vec["g"], 16) + vec["g"], 16 + ) assert private_numbers.public_numbers.parameter_numbers.p == int( - vec["p"], 16) + vec["p"], 16 + ) if "q" in vec: assert private_numbers.public_numbers.parameter_numbers.q == int( - vec["q"], 16) + vec["q"], 16 + ) else: assert private_numbers.public_numbers.parameter_numbers.q is None def test_private_bytes_traditional_openssl_invalid(self, backend): - parameters = dh.generate_parameters(2, 512, backend) + parameters = FFDH3072_P.parameters(backend) key = parameters.generate_private_key() with pytest.raises(ValueError): key.private_bytes( serialization.Encoding.PEM, serialization.PrivateFormat.TraditionalOpenSSL, - serialization.NoEncryption() + serialization.NoEncryption(), ) def test_private_bytes_invalid_encoding(self, backend): - parameters = dh.generate_parameters(2, 512, backend) + parameters = FFDH3072_P.parameters(backend) key = parameters.generate_private_key() with pytest.raises(TypeError): key.private_bytes( "notencoding", serialization.PrivateFormat.PKCS8, - serialization.NoEncryption() + serialization.NoEncryption(), ) def test_private_bytes_invalid_format(self, backend): - parameters = dh.generate_parameters(2, 512, backend) + parameters = FFDH3072_P.parameters(backend) key = parameters.generate_private_key() with pytest.raises(ValueError): key.private_bytes( serialization.Encoding.PEM, "invalidformat", - serialization.NoEncryption() + serialization.NoEncryption(), ) def test_private_bytes_invalid_encryption_algorithm(self, backend): - parameters = dh.generate_parameters(2, 512, backend) + parameters = FFDH3072_P.parameters(backend) key = parameters.generate_private_key() with pytest.raises(TypeError): key.private_bytes( serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, - "notanencalg" + "notanencalg", ) def test_private_bytes_unsupported_encryption_type(self, backend): - parameters = dh.generate_parameters(2, 512, backend) + parameters = FFDH3072_P.parameters(backend) key = parameters.generate_private_key() with pytest.raises(ValueError): key.private_bytes( serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, - DummyKeySerializationEncryption() + DummyKeySerializationEncryption(), ) @@ -583,23 +598,15 @@ def test_private_bytes_unsupported_encryption_type(self, backend): @pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) @pytest.mark.requires_backend_interface(interface=DERSerializationBackend) class TestDHPublicKeySerialization(object): - @pytest.mark.parametrize( ("encoding", "loader_func"), [ - [ - serialization.Encoding.PEM, - serialization.load_pem_public_key - ], - [ - serialization.Encoding.DER, - serialization.load_der_public_key - ], - ] + [serialization.Encoding.PEM, serialization.load_pem_public_key], + [serialization.Encoding.DER, serialization.load_der_public_key], + ], ) - def test_public_bytes(self, backend, encoding, - loader_func): - parameters = dh.generate_parameters(2, 512, backend) + def test_public_bytes(self, backend, encoding, loader_func): + parameters = FFDH3072_P.parameters(backend) key = parameters.generate_private_key().public_key() serialized = key.public_bytes( encoding, serialization.PublicFormat.SubjectPublicKeyInfo @@ -617,30 +624,33 @@ def test_public_bytes(self, backend, encoding, serialization.load_pem_public_key, serialization.Encoding.PEM, False, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhpub.der"), serialization.load_der_public_key, serialization.Encoding.DER, False, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhpub_rfc5114_2.pem"), serialization.load_pem_public_key, serialization.Encoding.PEM, True, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhpub_rfc5114_2.der"), serialization.load_der_public_key, serialization.Encoding.DER, True, - ) - ] + ), + ], ) - def test_public_bytes_match(self, key_path, loader_func, - encoding, is_dhx, backend): + def test_public_bytes_match( + self, key_path, loader_func, encoding, is_dhx, backend + ): _skip_dhx_unsupported(backend, is_dhx) key_bytes = load_vectors_from_file( - key_path, - lambda pemfile: pemfile.read(), mode="rb" + key_path, lambda pemfile: pemfile.read(), mode="rb" ) pub_key = loader_func(key_bytes, backend) serialized = pub_key.public_bytes( @@ -657,30 +667,33 @@ def test_public_bytes_match(self, key_path, loader_func, serialization.load_pem_public_key, os.path.join("asymmetric", "DH", "dhkey.txt"), False, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhpub.der"), serialization.load_der_public_key, os.path.join("asymmetric", "DH", "dhkey.txt"), False, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhpub_rfc5114_2.pem"), serialization.load_pem_public_key, os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.txt"), True, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhpub_rfc5114_2.der"), serialization.load_der_public_key, os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.txt"), True, - ) - ] + ), + ], ) - def test_public_bytes_values(self, key_path, loader_func, - vec_path, is_dhx, backend): + def test_public_bytes_values( + self, key_path, loader_func, vec_path, is_dhx, backend + ): _skip_dhx_unsupported(backend, is_dhx) key_bytes = load_vectors_from_file( - key_path, - lambda pemfile: pemfile.read(), mode="rb" + key_path, lambda pemfile: pemfile.read(), mode="rb" ) vec = load_vectors_from_file(vec_path, load_nist_vectors)[0] pub_key = loader_func(key_bytes, backend) @@ -694,16 +707,15 @@ def test_public_bytes_values(self, key_path, loader_func, assert public_numbers.parameter_numbers.q is None def test_public_bytes_invalid_encoding(self, backend): - parameters = dh.generate_parameters(2, 512, backend) + parameters = FFDH3072_P.parameters(backend) key = parameters.generate_private_key().public_key() with pytest.raises(TypeError): key.public_bytes( - "notencoding", - serialization.PublicFormat.SubjectPublicKeyInfo + "notencoding", serialization.PublicFormat.SubjectPublicKeyInfo ) def test_public_bytes_pkcs1_unsupported(self, backend): - parameters = dh.generate_parameters(2, 512, backend) + parameters = FFDH3072_P.parameters(backend) key = parameters.generate_private_key().public_key() with pytest.raises(ValueError): key.public_bytes( @@ -715,23 +727,15 @@ def test_public_bytes_pkcs1_unsupported(self, backend): @pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) @pytest.mark.requires_backend_interface(interface=DERSerializationBackend) class TestDHParameterSerialization(object): - @pytest.mark.parametrize( ("encoding", "loader_func"), [ - [ - serialization.Encoding.PEM, - serialization.load_pem_parameters - ], - [ - serialization.Encoding.DER, - serialization.load_der_parameters - ], - ] + [serialization.Encoding.PEM, serialization.load_pem_parameters], + [serialization.Encoding.DER, serialization.load_der_parameters], + ], ) - def test_parameter_bytes(self, backend, encoding, - loader_func): - parameters = dh.generate_parameters(2, 512, backend) + def test_parameter_bytes(self, backend, encoding, loader_func): + parameters = FFDH3072_P.parameters(backend) serialized = parameters.parameter_bytes( encoding, serialization.ParameterFormat.PKCS3 ) @@ -747,30 +751,33 @@ def test_parameter_bytes(self, backend, encoding, serialization.load_pem_parameters, serialization.Encoding.PEM, False, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhp.der"), serialization.load_der_parameters, serialization.Encoding.DER, False, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhp_rfc5114_2.pem"), serialization.load_pem_parameters, serialization.Encoding.PEM, True, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhp_rfc5114_2.der"), serialization.load_der_parameters, serialization.Encoding.DER, True, - ) - ] + ), + ], ) - def test_parameter_bytes_match(self, param_path, loader_func, - encoding, backend, is_dhx): + def test_parameter_bytes_match( + self, param_path, loader_func, encoding, backend, is_dhx + ): _skip_dhx_unsupported(backend, is_dhx) param_bytes = load_vectors_from_file( - param_path, - lambda pemfile: pemfile.read(), mode="rb" + param_path, lambda pemfile: pemfile.read(), mode="rb" ) parameters = loader_func(param_bytes, backend) serialized = parameters.parameter_bytes( @@ -787,30 +794,33 @@ def test_parameter_bytes_match(self, param_path, loader_func, serialization.load_pem_parameters, os.path.join("asymmetric", "DH", "dhkey.txt"), False, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhp.der"), serialization.load_der_parameters, os.path.join("asymmetric", "DH", "dhkey.txt"), False, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhp_rfc5114_2.pem"), serialization.load_pem_parameters, os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.txt"), True, - ), ( + ), + ( os.path.join("asymmetric", "DH", "dhp_rfc5114_2.der"), serialization.load_der_parameters, os.path.join("asymmetric", "DH", "dhkey_rfc5114_2.txt"), True, - ) - ] + ), + ], ) - def test_public_bytes_values(self, param_path, loader_func, - vec_path, backend, is_dhx): + def test_public_bytes_values( + self, param_path, loader_func, vec_path, backend, is_dhx + ): _skip_dhx_unsupported(backend, is_dhx) key_bytes = load_vectors_from_file( - param_path, - lambda pemfile: pemfile.read(), mode="rb" + param_path, lambda pemfile: pemfile.read(), mode="rb" ) vec = load_vectors_from_file(vec_path, load_nist_vectors)[0] parameters = loader_func(key_bytes, backend) @@ -827,49 +837,48 @@ def test_public_bytes_values(self, param_path, loader_func, [ ( serialization.Encoding.Raw, - serialization.PublicFormat.SubjectPublicKeyInfo + serialization.PublicFormat.SubjectPublicKeyInfo, ), (serialization.Encoding.Raw, serialization.PublicFormat.PKCS1), - ] + list(itertools.product( - [ - serialization.Encoding.Raw, - serialization.Encoding.X962, - serialization.Encoding.PEM, - serialization.Encoding.DER - ], - [ - serialization.PublicFormat.Raw, - serialization.PublicFormat.UncompressedPoint, - serialization.PublicFormat.CompressedPoint - ] - )) + ] + + list( + itertools.product( + [ + serialization.Encoding.Raw, + serialization.Encoding.X962, + serialization.Encoding.PEM, + serialization.Encoding.DER, + ], + [ + serialization.PublicFormat.Raw, + serialization.PublicFormat.UncompressedPoint, + serialization.PublicFormat.CompressedPoint, + ], + ) + ), ) def test_public_bytes_rejects_invalid(self, encoding, fmt, backend): - parameters = dh.generate_parameters(2, 512, backend) + parameters = FFDH3072_P.parameters(backend) key = parameters.generate_private_key().public_key() with pytest.raises(ValueError): key.public_bytes(encoding, fmt) def test_parameter_bytes_invalid_encoding(self, backend): - parameters = dh.generate_parameters(2, 512, backend) + parameters = FFDH3072_P.parameters(backend) with pytest.raises(TypeError): parameters.parameter_bytes( - "notencoding", - serialization.ParameterFormat.PKCS3 + "notencoding", serialization.ParameterFormat.PKCS3 ) def test_parameter_bytes_invalid_format(self, backend): - parameters = dh.generate_parameters(2, 512, backend) + parameters = FFDH3072_P.parameters(backend) with pytest.raises(ValueError): - parameters.parameter_bytes( - serialization.Encoding.PEM, - "notformat" - ) + parameters.parameter_bytes(serialization.Encoding.PEM, "notformat") def test_parameter_bytes_openssh_unsupported(self, backend): - parameters = dh.generate_parameters(2, 512, backend) + parameters = FFDH3072_P.parameters(backend) with pytest.raises(TypeError): parameters.parameter_bytes( serialization.Encoding.OpenSSH, - serialization.ParameterFormat.PKCS3 + serialization.ParameterFormat.PKCS3, ) diff --git a/tests/hazmat/primitives/test_dsa.py b/tests/hazmat/primitives/test_dsa.py index efd2239c162d..bda275064ea2 100644 --- a/tests/hazmat/primitives/test_dsa.py +++ b/tests/hazmat/primitives/test_dsa.py @@ -11,32 +11,33 @@ from cryptography.exceptions import AlreadyFinalized, InvalidSignature from cryptography.hazmat.backends.interfaces import ( - DSABackend, PEMSerializationBackend + DSABackend, + PEMSerializationBackend, ) from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import dsa from cryptography.hazmat.primitives.asymmetric.utils import ( - Prehashed, encode_dss_signature + Prehashed, + encode_dss_signature, ) from cryptography.utils import CryptographyDeprecationWarning -from .fixtures_dsa import ( - DSA_KEY_1024, DSA_KEY_2048, DSA_KEY_3072 -) +from .fixtures_dsa import DSA_KEY_1024, DSA_KEY_2048, DSA_KEY_3072 +from .utils import skip_fips_traditional_openssl from ...doubles import DummyHashAlgorithm, DummyKeySerializationEncryption from ...utils import ( - load_fips_dsa_key_pair_vectors, load_fips_dsa_sig_vectors, + load_fips_dsa_key_pair_vectors, + load_fips_dsa_sig_vectors, load_vectors_from_file, ) def _skip_if_dsa_not_supported(backend, algorithm, p, q, g): - if ( - not backend.dsa_parameters_supported(p, q, g) or - not backend.dsa_hash_supported(algorithm) - ): + if not backend.dsa_parameters_supported( + p, q, g + ) or not backend.dsa_hash_supported(algorithm): pytest.skip( - "{0} does not support the provided parameters".format(backend) + "{} does not support the provided parameters".format(backend) ) @@ -49,7 +50,7 @@ def test_skip_if_dsa_not_supported(backend): @pytest.mark.requires_backend_interface(interface=DSABackend) class TestDSA(object): def test_generate_dsa_parameters(self, backend): - parameters = dsa.generate_parameters(1024, backend) + parameters = dsa.generate_parameters(2048, backend) assert isinstance(parameters, dsa.DSAParameters) def test_generate_invalid_dsa_parameters(self, backend): @@ -59,16 +60,18 @@ def test_generate_invalid_dsa_parameters(self, backend): @pytest.mark.parametrize( "vector", load_vectors_from_file( - os.path.join( - "asymmetric", "DSA", "FIPS_186-3", "KeyPair.rsp"), - load_fips_dsa_key_pair_vectors - ) + os.path.join("asymmetric", "DSA", "FIPS_186-3", "KeyPair.rsp"), + load_fips_dsa_key_pair_vectors, + ), ) def test_generate_dsa_keys(self, vector, backend): + if ( + backend._fips_enabled + and vector["p"] < backend._fips_dsa_min_modulus + ): + pytest.skip("Small modulus blocked in FIPS mode") parameters = dsa.DSAParameterNumbers( - p=vector['p'], - q=vector['q'], - g=vector['g'] + p=vector["p"], q=vector["q"], g=vector["g"] ).parameters(backend) skey = parameters.generate_private_key() numbers = skey.private_numbers() @@ -79,10 +82,10 @@ def test_generate_dsa_keys(self, vector, backend): assert parameter_numbers.p == skey_parameters.p assert parameter_numbers.q == skey_parameters.q assert parameter_numbers.g == skey_parameters.g - assert skey_parameters.p == vector['p'] - assert skey_parameters.q == vector['q'] - assert skey_parameters.g == vector['g'] - assert skey.key_size == vector['p'].bit_length() + assert skey_parameters.p == vector["p"] + assert skey_parameters.q == vector["q"] + assert skey_parameters.g == vector["g"] + assert skey.key_size == vector["p"].bit_length() assert pkey.key_size == skey.key_size public_numbers = pkey.public_numbers() assert numbers.public_numbers.y == public_numbers.y @@ -91,7 +94,7 @@ def test_generate_dsa_keys(self, vector, backend): ) def test_generate_dsa_private_key_and_parameters(self, backend): - skey = dsa.generate_private_key(1024, backend) + skey = dsa.generate_private_key(2048, backend) assert skey numbers = skey.private_numbers() skey_parameters = numbers.public_numbers.parameter_numbers @@ -130,7 +133,7 @@ def test_generate_dsa_private_key_and_parameters(self, backend): ( DSA_KEY_2048.public_numbers.parameter_numbers.p, 2 ** 250, - DSA_KEY_2048.public_numbers.parameter_numbers.g + DSA_KEY_2048.public_numbers.parameter_numbers.g, ), ( DSA_KEY_3072.public_numbers.parameter_numbers.p, @@ -140,19 +143,19 @@ def test_generate_dsa_private_key_and_parameters(self, backend): ( DSA_KEY_1024.public_numbers.parameter_numbers.p, DSA_KEY_1024.public_numbers.parameter_numbers.q, - 0 + 0, ), ( DSA_KEY_1024.public_numbers.parameter_numbers.p, DSA_KEY_1024.public_numbers.parameter_numbers.q, - 1 + 1, ), ( DSA_KEY_1024.public_numbers.parameter_numbers.p, DSA_KEY_1024.public_numbers.parameter_numbers.q, - 2 ** 1200 + 2 ** 1200, ), - ] + ], ) def test_invalid_parameters_values(self, p, q, g, backend): with pytest.raises(ValueError): @@ -264,17 +267,18 @@ def test_invalid_parameters_values(self, p, q, g, backend): DSA_KEY_1024.public_numbers.parameter_numbers.q, DSA_KEY_1024.public_numbers.parameter_numbers.g, 2 ** 100, - DSA_KEY_1024.x + DSA_KEY_1024.x, ), - ] + ], ) def test_invalid_dsa_private_key_arguments(self, p, q, g, y, x, backend): with pytest.raises(ValueError): dsa.DSAPrivateNumbers( public_numbers=dsa.DSAPublicNumbers( parameter_numbers=dsa.DSAParameterNumbers(p=p, q=q, g=g), - y=y - ), x=x + y=y, + ), + x=x, ).private_key(backend) @pytest.mark.parametrize( @@ -340,72 +344,95 @@ def test_invalid_dsa_private_key_arguments(self, p, q, g, y, x, backend): 2 ** 1200, DSA_KEY_1024.public_numbers.y, ), - ] + ], ) def test_invalid_dsa_public_key_arguments(self, p, q, g, y, backend): with pytest.raises(ValueError): dsa.DSAPublicNumbers( - parameter_numbers=dsa.DSAParameterNumbers(p=p, q=q, g=g), - y=y + parameter_numbers=dsa.DSAParameterNumbers(p=p, q=q, g=g), y=y ).public_key(backend) + def test_large_p(self, backend): + key = load_vectors_from_file( + os.path.join("asymmetric", "PEM_Serialization", "dsa_4096.pem"), + lambda pemfile: serialization.load_pem_private_key( + pemfile.read(), None, backend + ), + mode="rb", + ) + pn = key.private_numbers() + assert pn.public_numbers.parameter_numbers.p.bit_length() == 4096 + # Turn it back into a key to confirm that values this large pass + # verification + dsa.DSAPrivateNumbers( + public_numbers=dsa.DSAPublicNumbers( + parameter_numbers=dsa.DSAParameterNumbers( + p=pn.public_numbers.parameter_numbers.p, + q=pn.public_numbers.parameter_numbers.q, + g=pn.public_numbers.parameter_numbers.g, + ), + y=pn.public_numbers.y, + ), + x=pn.x, + ).private_key(backend) + @pytest.mark.requires_backend_interface(interface=DSABackend) class TestDSAVerification(object): _algorithms_dict = { - 'SHA1': hashes.SHA1, - 'SHA224': hashes.SHA224, - 'SHA256': hashes.SHA256, - 'SHA384': hashes.SHA384, - 'SHA512': hashes.SHA512 + "SHA1": hashes.SHA1, + "SHA224": hashes.SHA224, + "SHA256": hashes.SHA256, + "SHA384": hashes.SHA384, + "SHA512": hashes.SHA512, } @pytest.mark.parametrize( "vector", load_vectors_from_file( - os.path.join( - "asymmetric", "DSA", "FIPS_186-3", "SigVer.rsp"), - load_fips_dsa_sig_vectors - ) + os.path.join("asymmetric", "DSA", "FIPS_186-3", "SigVer.rsp"), + load_fips_dsa_sig_vectors, + ), ) def test_dsa_verification(self, vector, backend): - digest_algorithm = vector['digest_algorithm'].replace("-", "") + digest_algorithm = vector["digest_algorithm"].replace("-", "") algorithm = self._algorithms_dict[digest_algorithm] _skip_if_dsa_not_supported( - backend, algorithm, vector['p'], vector['q'], vector['g'] + backend, algorithm, vector["p"], vector["q"], vector["g"] ) public_key = dsa.DSAPublicNumbers( parameter_numbers=dsa.DSAParameterNumbers( - vector['p'], vector['q'], vector['g'] + vector["p"], vector["q"], vector["g"] ), - y=vector['y'] + y=vector["y"], ).public_key(backend) - sig = encode_dss_signature(vector['r'], vector['s']) + sig = encode_dss_signature(vector["r"], vector["s"]) - if vector['result'] == "F": + if vector["result"] == "F": with pytest.raises(InvalidSignature): - public_key.verify(sig, vector['msg'], algorithm()) + public_key.verify(sig, vector["msg"], algorithm()) else: - public_key.verify(sig, vector['msg'], algorithm()) + public_key.verify(sig, vector["msg"], algorithm()) def test_dsa_verify_invalid_asn1(self, backend): public_key = DSA_KEY_1024.public_numbers.public_key(backend) with pytest.raises(InvalidSignature): - public_key.verify(b'fakesig', b'fakemsg', hashes.SHA1()) + public_key.verify(b"fakesig", b"fakemsg", hashes.SHA1()) def test_signature_not_bytes(self, backend): public_key = DSA_KEY_1024.public_numbers.public_key(backend) - with pytest.raises(TypeError), \ - pytest.warns(CryptographyDeprecationWarning): + with pytest.raises(TypeError), pytest.warns( + CryptographyDeprecationWarning + ): public_key.verifier(1234, hashes.SHA1()) def test_use_after_finalize(self, backend): public_key = DSA_KEY_1024.public_numbers.public_key(backend) with pytest.warns(CryptographyDeprecationWarning): - verifier = public_key.verifier(b'fakesig', hashes.SHA1()) - verifier.update(b'irrelevant') + verifier = public_key.verifier(b"fakesig", hashes.SHA1()) + verifier.update(b"irrelevant") with pytest.raises(InvalidSignature): verifier.verify() with pytest.raises(AlreadyFinalized): @@ -445,57 +472,57 @@ def test_prehashed_digest_mismatch(self, backend): def test_prehashed_unsupported_in_signer_ctx(self, backend): private_key = DSA_KEY_1024.private_key(backend) - with pytest.raises(TypeError), \ - pytest.warns(CryptographyDeprecationWarning): + with pytest.raises(TypeError), pytest.warns( + CryptographyDeprecationWarning + ): private_key.signer(Prehashed(hashes.SHA1())) def test_prehashed_unsupported_in_verifier_ctx(self, backend): public_key = DSA_KEY_1024.private_key(backend).public_key() - with pytest.raises(TypeError), \ - pytest.warns(CryptographyDeprecationWarning): - public_key.verifier( - b"0" * 64, Prehashed(hashes.SHA1()) - ) + with pytest.raises(TypeError), pytest.warns( + CryptographyDeprecationWarning + ): + public_key.verifier(b"0" * 64, Prehashed(hashes.SHA1())) @pytest.mark.requires_backend_interface(interface=DSABackend) class TestDSASignature(object): _algorithms_dict = { - 'SHA1': hashes.SHA1, - 'SHA224': hashes.SHA224, - 'SHA256': hashes.SHA256, - 'SHA384': hashes.SHA384, - 'SHA512': hashes.SHA512} + "SHA1": hashes.SHA1, + "SHA224": hashes.SHA224, + "SHA256": hashes.SHA256, + "SHA384": hashes.SHA384, + "SHA512": hashes.SHA512, + } @pytest.mark.parametrize( "vector", load_vectors_from_file( - os.path.join( - "asymmetric", "DSA", "FIPS_186-3", "SigGen.txt"), - load_fips_dsa_sig_vectors - ) + os.path.join("asymmetric", "DSA", "FIPS_186-3", "SigGen.txt"), + load_fips_dsa_sig_vectors, + ), ) def test_dsa_signing(self, vector, backend): - digest_algorithm = vector['digest_algorithm'].replace("-", "") + digest_algorithm = vector["digest_algorithm"].replace("-", "") algorithm = self._algorithms_dict[digest_algorithm] _skip_if_dsa_not_supported( - backend, algorithm, vector['p'], vector['q'], vector['g'] + backend, algorithm, vector["p"], vector["q"], vector["g"] ) private_key = dsa.DSAPrivateNumbers( public_numbers=dsa.DSAPublicNumbers( parameter_numbers=dsa.DSAParameterNumbers( - vector['p'], vector['q'], vector['g'] + vector["p"], vector["q"], vector["g"] ), - y=vector['y'] + y=vector["y"], ), - x=vector['x'] + x=vector["x"], ).private_key(backend) - signature = private_key.sign(vector['msg'], algorithm()) + signature = private_key.sign(vector["msg"], algorithm()) assert signature - private_key.public_key().verify(signature, vector['msg'], algorithm()) + private_key.public_key().verify(signature, vector["msg"], algorithm()) def test_use_after_finalize(self, backend): private_key = DSA_KEY_1024.private_key(backend) @@ -558,8 +585,7 @@ def test_dsa_parameter_numbers_invalid_types(self): def test_dsa_public_numbers(self): parameter_numbers = dsa.DSAParameterNumbers(p=1, q=2, g=3) public_numbers = dsa.DSAPublicNumbers( - y=4, - parameter_numbers=parameter_numbers + y=4, parameter_numbers=parameter_numbers ) assert public_numbers.y == 4 assert public_numbers.parameter_numbers == parameter_numbers @@ -575,12 +601,10 @@ def test_dsa_public_numbers_invalid_types(self): def test_dsa_private_numbers(self): parameter_numbers = dsa.DSAParameterNumbers(p=1, q=2, g=3) public_numbers = dsa.DSAPublicNumbers( - y=4, - parameter_numbers=parameter_numbers + y=4, parameter_numbers=parameter_numbers ) private_numbers = dsa.DSAPrivateNumbers( - x=5, - public_numbers=public_numbers + x=5, public_numbers=public_numbers ) assert private_numbers.x == 5 assert private_numbers.public_numbers == public_numbers @@ -588,8 +612,7 @@ def test_dsa_private_numbers(self): def test_dsa_private_numbers_invalid_types(self): parameter_numbers = dsa.DSAParameterNumbers(p=1, q=2, g=3) public_numbers = dsa.DSAPublicNumbers( - y=4, - parameter_numbers=parameter_numbers + y=4, parameter_numbers=parameter_numbers ) with pytest.raises(TypeError): dsa.DSAPrivateNumbers(x=4, public_numbers=None) @@ -604,8 +627,7 @@ def test_repr(self): ) public_numbers = dsa.DSAPublicNumbers( - y=4, - parameter_numbers=parameter_numbers + y=4, parameter_numbers=parameter_numbers ) assert repr(public_numbers) == ( " the group order. It should be + # rejected to prevent signature malleability issues. This test can + # be removed when wycheproof grows ed448 vectors + public_bytes = binascii.unhexlify( + "fedb02a658d74990244d9d10cf338e977565cbbda6b24c716829ed6ee1e4f28cf" + "2620c052db8d878f6243bffc22242816c1aaa67d2f3603600" + ) + signature = binascii.unhexlify( + "0cc16ba24d69277f927c1554b0f08a2a711bbdd20b058ccc660d00ca13542a3ce" + "f9e5c44c54ab23a2eb14f947e167b990b080863e28b399380f30db6e54d5d1406" + "d23378ffde11b1fb81b2b438a3b8e8aa7f7f4e1befcc905023fab5a5465053844" + "f04cf0c1b51d84760f869588687f57500" + ) + key = Ed448PublicKey.from_public_bytes(public_bytes) + with pytest.raises(InvalidSignature): + key.verify(signature, b"8") diff --git a/tests/hazmat/primitives/test_hash_vectors.py b/tests/hazmat/primitives/test_hash_vectors.py index 5225a00be87b..9301b6217101 100644 --- a/tests/hazmat/primitives/test_hash_vectors.py +++ b/tests/hazmat/primitives/test_hash_vectors.py @@ -22,13 +22,10 @@ ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA1(object): - test_SHA1 = generate_hash_test( + test_sha1 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA1"), - [ - "SHA1LongMsg.rsp", - "SHA1ShortMsg.rsp", - ], + ["SHA1LongMsg.rsp", "SHA1ShortMsg.rsp"], hashes.SHA1(), ) @@ -39,13 +36,10 @@ class TestSHA1(object): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA224(object): - test_SHA224 = generate_hash_test( + test_sha224 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA2"), - [ - "SHA224LongMsg.rsp", - "SHA224ShortMsg.rsp", - ], + ["SHA224LongMsg.rsp", "SHA224ShortMsg.rsp"], hashes.SHA224(), ) @@ -56,13 +50,10 @@ class TestSHA224(object): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA256(object): - test_SHA256 = generate_hash_test( + test_sha256 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA2"), - [ - "SHA256LongMsg.rsp", - "SHA256ShortMsg.rsp", - ], + ["SHA256LongMsg.rsp", "SHA256ShortMsg.rsp"], hashes.SHA256(), ) @@ -73,13 +64,10 @@ class TestSHA256(object): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA384(object): - test_SHA384 = generate_hash_test( + test_sha384 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA2"), - [ - "SHA384LongMsg.rsp", - "SHA384ShortMsg.rsp", - ], + ["SHA384LongMsg.rsp", "SHA384ShortMsg.rsp"], hashes.SHA384(), ) @@ -90,13 +78,10 @@ class TestSHA384(object): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA512(object): - test_SHA512 = generate_hash_test( + test_sha512 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA2"), - [ - "SHA512LongMsg.rsp", - "SHA512ShortMsg.rsp", - ], + ["SHA512LongMsg.rsp", "SHA512ShortMsg.rsp"], hashes.SHA512(), ) @@ -107,13 +92,10 @@ class TestSHA512(object): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA512224(object): - test_SHA512_224 = generate_hash_test( + test_sha512_224 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA2"), - [ - "SHA512_224LongMsg.rsp", - "SHA512_224ShortMsg.rsp", - ], + ["SHA512_224LongMsg.rsp", "SHA512_224ShortMsg.rsp"], hashes.SHA512_224(), ) @@ -124,13 +106,10 @@ class TestSHA512224(object): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA512256(object): - test_SHA512_256 = generate_hash_test( + test_sha512_256 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA2"), - [ - "SHA512_256LongMsg.rsp", - "SHA512_256ShortMsg.rsp", - ], + ["SHA512_256LongMsg.rsp", "SHA512_256ShortMsg.rsp"], hashes.SHA512_256(), ) @@ -144,16 +123,15 @@ class TestMD5(object): test_md5 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "MD5"), - [ - "rfc-1321.txt", - ], + ["rfc-1321.txt"], hashes.MD5(), ) @pytest.mark.supported( only_if=lambda backend: backend.hash_supported( - hashes.BLAKE2b(digest_size=64)), + hashes.BLAKE2b(digest_size=64) + ), skip_message="Does not support BLAKE2b", ) @pytest.mark.requires_backend_interface(interface=HashBackend) @@ -161,16 +139,15 @@ class TestBLAKE2b(object): test_b2b = generate_hash_test( load_hash_vectors, os.path.join("hashes", "blake2"), - [ - "blake2b.txt", - ], + ["blake2b.txt"], hashes.BLAKE2b(digest_size=64), ) @pytest.mark.supported( only_if=lambda backend: backend.hash_supported( - hashes.BLAKE2s(digest_size=32)), + hashes.BLAKE2s(digest_size=32) + ), skip_message="Does not support BLAKE2s", ) @pytest.mark.requires_backend_interface(interface=HashBackend) @@ -178,9 +155,7 @@ class TestBLAKE2s256(object): test_b2s = generate_hash_test( load_hash_vectors, os.path.join("hashes", "blake2"), - [ - "blake2s.txt", - ], + ["blake2s.txt"], hashes.BLAKE2s(digest_size=32), ) @@ -191,13 +166,10 @@ class TestBLAKE2s256(object): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA3224(object): - test_SHA3_224 = generate_hash_test( + test_sha3_224 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA3"), - [ - "SHA3_224LongMsg.rsp", - "SHA3_224ShortMsg.rsp", - ], + ["SHA3_224LongMsg.rsp", "SHA3_224ShortMsg.rsp"], hashes.SHA3_224(), ) @@ -208,13 +180,10 @@ class TestSHA3224(object): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA3256(object): - test_SHA3_256 = generate_hash_test( + test_sha3_256 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA3"), - [ - "SHA3_256LongMsg.rsp", - "SHA3_256ShortMsg.rsp", - ], + ["SHA3_256LongMsg.rsp", "SHA3_256ShortMsg.rsp"], hashes.SHA3_256(), ) @@ -225,13 +194,10 @@ class TestSHA3256(object): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA3384(object): - test_SHA3_384 = generate_hash_test( + test_sha3_384 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA3"), - [ - "SHA3_384LongMsg.rsp", - "SHA3_384ShortMsg.rsp", - ], + ["SHA3_384LongMsg.rsp", "SHA3_384ShortMsg.rsp"], hashes.SHA3_384(), ) @@ -242,20 +208,18 @@ class TestSHA3384(object): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA3512(object): - test_SHA3_512 = generate_hash_test( + test_sha3_512 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHA3"), - [ - "SHA3_512LongMsg.rsp", - "SHA3_512ShortMsg.rsp", - ], + ["SHA3_512LongMsg.rsp", "SHA3_512ShortMsg.rsp"], hashes.SHA3_512(), ) @pytest.mark.supported( only_if=lambda backend: backend.hash_supported( - hashes.SHAKE128(digest_size=16)), + hashes.SHAKE128(digest_size=16) + ), skip_message="Does not support SHAKE128", ) @pytest.mark.requires_backend_interface(interface=HashBackend) @@ -263,10 +227,7 @@ class TestSHAKE128(object): test_shake128 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHAKE"), - [ - "SHAKE128LongMsg.rsp", - "SHAKE128ShortMsg.rsp", - ], + ["SHAKE128LongMsg.rsp", "SHAKE128ShortMsg.rsp"], hashes.SHAKE128(digest_size=16), ) @@ -274,24 +235,23 @@ class TestSHAKE128(object): "vector", _load_all_params( os.path.join("hashes", "SHAKE"), - [ - "SHAKE128VariableOut.rsp", - ], + ["SHAKE128VariableOut.rsp"], load_nist_vectors, - ) + ), ) def test_shake128_variable(self, vector, backend): - output_length = int(vector['outputlen']) // 8 - msg = binascii.unhexlify(vector['msg']) + output_length = int(vector["outputlen"]) // 8 + msg = binascii.unhexlify(vector["msg"]) shake = hashes.SHAKE128(digest_size=output_length) m = hashes.Hash(shake, backend=backend) m.update(msg) - assert m.finalize() == binascii.unhexlify(vector['output']) + assert m.finalize() == binascii.unhexlify(vector["output"]) @pytest.mark.supported( only_if=lambda backend: backend.hash_supported( - hashes.SHAKE256(digest_size=32)), + hashes.SHAKE256(digest_size=32) + ), skip_message="Does not support SHAKE256", ) @pytest.mark.requires_backend_interface(interface=HashBackend) @@ -299,10 +259,7 @@ class TestSHAKE256(object): test_shake256 = generate_hash_test( load_hash_vectors, os.path.join("hashes", "SHAKE"), - [ - "SHAKE256LongMsg.rsp", - "SHAKE256ShortMsg.rsp", - ], + ["SHAKE256LongMsg.rsp", "SHAKE256ShortMsg.rsp"], hashes.SHAKE256(digest_size=32), ) @@ -310,16 +267,14 @@ class TestSHAKE256(object): "vector", _load_all_params( os.path.join("hashes", "SHAKE"), - [ - "SHAKE256VariableOut.rsp", - ], + ["SHAKE256VariableOut.rsp"], load_nist_vectors, - ) + ), ) def test_shake256_variable(self, vector, backend): - output_length = int(vector['outputlen']) // 8 - msg = binascii.unhexlify(vector['msg']) + output_length = int(vector["outputlen"]) // 8 + msg = binascii.unhexlify(vector["msg"]) shake = hashes.SHAKE256(digest_size=output_length) m = hashes.Hash(shake, backend=backend) m.update(msg) - assert m.finalize() == binascii.unhexlify(vector['output']) + assert m.finalize() == binascii.unhexlify(vector["output"]) diff --git a/tests/hazmat/primitives/test_hashes.py b/tests/hazmat/primitives/test_hashes.py index b10fadcdcc75..eadd0febf25f 100644 --- a/tests/hazmat/primitives/test_hashes.py +++ b/tests/hazmat/primitives/test_hashes.py @@ -52,7 +52,7 @@ def test_unsupported_hash(self, backend): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA1(object): - test_SHA1 = generate_base_hash_test( + test_sha1 = generate_base_hash_test( hashes.SHA1(), digest_size=20, ) @@ -64,7 +64,7 @@ class TestSHA1(object): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA224(object): - test_SHA224 = generate_base_hash_test( + test_sha224 = generate_base_hash_test( hashes.SHA224(), digest_size=28, ) @@ -76,7 +76,7 @@ class TestSHA224(object): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA256(object): - test_SHA256 = generate_base_hash_test( + test_sha256 = generate_base_hash_test( hashes.SHA256(), digest_size=32, ) @@ -88,7 +88,7 @@ class TestSHA256(object): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA384(object): - test_SHA384 = generate_base_hash_test( + test_sha384 = generate_base_hash_test( hashes.SHA384(), digest_size=48, ) @@ -100,7 +100,7 @@ class TestSHA384(object): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestSHA512(object): - test_SHA512 = generate_base_hash_test( + test_sha512 = generate_base_hash_test( hashes.SHA512(), digest_size=64, ) @@ -112,7 +112,7 @@ class TestSHA512(object): ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestMD5(object): - test_MD5 = generate_base_hash_test( + test_md5 = generate_base_hash_test( hashes.MD5(), digest_size=16, ) @@ -120,12 +120,13 @@ class TestMD5(object): @pytest.mark.supported( only_if=lambda backend: backend.hash_supported( - hashes.BLAKE2b(digest_size=64)), + hashes.BLAKE2b(digest_size=64) + ), skip_message="Does not support BLAKE2b", ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestBLAKE2b(object): - test_BLAKE2b = generate_base_hash_test( + test_blake2b = generate_base_hash_test( hashes.BLAKE2b(digest_size=64), digest_size=64, ) @@ -143,12 +144,13 @@ def test_invalid_digest_size(self, backend): @pytest.mark.supported( only_if=lambda backend: backend.hash_supported( - hashes.BLAKE2s(digest_size=32)), + hashes.BLAKE2s(digest_size=32) + ), skip_message="Does not support BLAKE2s", ) @pytest.mark.requires_backend_interface(interface=HashBackend) class TestBLAKE2s(object): - test_BLAKE2s = generate_base_hash_test( + test_blake2s = generate_base_hash_test( hashes.BLAKE2s(digest_size=32), digest_size=32, ) @@ -182,18 +184,12 @@ def test_buffer_protocol_hash(backend): class TestSHAKE(object): - @pytest.mark.parametrize( - "xof", - [hashes.SHAKE128, hashes.SHAKE256] - ) + @pytest.mark.parametrize("xof", [hashes.SHAKE128, hashes.SHAKE256]) def test_invalid_digest_type(self, xof): with pytest.raises(TypeError): xof(digest_size=object()) - @pytest.mark.parametrize( - "xof", - [hashes.SHAKE128, hashes.SHAKE256] - ) + @pytest.mark.parametrize("xof", [hashes.SHAKE128, hashes.SHAKE256]) def test_invalid_digest_size(self, xof): with pytest.raises(ValueError): xof(digest_size=-5) diff --git a/tests/hazmat/primitives/test_hkdf.py b/tests/hazmat/primitives/test_hkdf.py index 195bfb3a4f71..1d7de6c472ee 100644 --- a/tests/hazmat/primitives/test_hkdf.py +++ b/tests/hazmat/primitives/test_hkdf.py @@ -9,15 +9,15 @@ import pytest -from cryptography.exceptions import ( - AlreadyFinalized, InvalidKey, _Reasons -) +from cryptography.exceptions import AlreadyFinalized, InvalidKey, _Reasons from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.hkdf import HKDF, HKDFExpand from ...utils import ( - load_nist_vectors, load_vectors_from_file, raises_unsupported_algorithm + load_nist_vectors, + load_vectors_from_file, + raises_unsupported_algorithm, ) @@ -32,127 +32,67 @@ def test_length_limit(self, backend): big_length, salt=None, info=None, - backend=backend + backend=backend, ) def test_already_finalized(self, backend): - hkdf = HKDF( - hashes.SHA256(), - 16, - salt=None, - info=None, - backend=backend - ) + hkdf = HKDF(hashes.SHA256(), 16, salt=None, info=None, backend=backend) hkdf.derive(b"\x01" * 16) with pytest.raises(AlreadyFinalized): hkdf.derive(b"\x02" * 16) - hkdf = HKDF( - hashes.SHA256(), - 16, - salt=None, - info=None, - backend=backend - ) + hkdf = HKDF(hashes.SHA256(), 16, salt=None, info=None, backend=backend) hkdf.verify(b"\x01" * 16, b"gJ\xfb{\xb1Oi\xc5sMC\xb7\xe4@\xf7u") with pytest.raises(AlreadyFinalized): hkdf.verify(b"\x02" * 16, b"gJ\xfb{\xb1Oi\xc5sMC\xb7\xe4@\xf7u") - hkdf = HKDF( - hashes.SHA256(), - 16, - salt=None, - info=None, - backend=backend - ) + hkdf = HKDF(hashes.SHA256(), 16, salt=None, info=None, backend=backend) def test_verify(self, backend): - hkdf = HKDF( - hashes.SHA256(), - 16, - salt=None, - info=None, - backend=backend - ) + hkdf = HKDF(hashes.SHA256(), 16, salt=None, info=None, backend=backend) hkdf.verify(b"\x01" * 16, b"gJ\xfb{\xb1Oi\xc5sMC\xb7\xe4@\xf7u") def test_verify_invalid(self, backend): - hkdf = HKDF( - hashes.SHA256(), - 16, - salt=None, - info=None, - backend=backend - ) + hkdf = HKDF(hashes.SHA256(), 16, salt=None, info=None, backend=backend) with pytest.raises(InvalidKey): hkdf.verify(b"\x02" * 16, b"gJ\xfb{\xb1Oi\xc5sMC\xb7\xe4@\xf7u") def test_unicode_typeerror(self, backend): with pytest.raises(TypeError): - HKDF( - hashes.SHA256(), - 16, - salt=u"foo", - info=None, - backend=backend - ) + HKDF(hashes.SHA256(), 16, salt=u"foo", info=None, backend=backend) with pytest.raises(TypeError): - HKDF( - hashes.SHA256(), - 16, - salt=None, - info=u"foo", - backend=backend - ) + HKDF(hashes.SHA256(), 16, salt=None, info=u"foo", backend=backend) with pytest.raises(TypeError): hkdf = HKDF( - hashes.SHA256(), - 16, - salt=None, - info=None, - backend=backend + hashes.SHA256(), 16, salt=None, info=None, backend=backend ) hkdf.derive(u"foo") with pytest.raises(TypeError): hkdf = HKDF( - hashes.SHA256(), - 16, - salt=None, - info=None, - backend=backend + hashes.SHA256(), 16, salt=None, info=None, backend=backend ) hkdf.verify(u"foo", b"bar") with pytest.raises(TypeError): hkdf = HKDF( - hashes.SHA256(), - 16, - salt=None, - info=None, - backend=backend + hashes.SHA256(), 16, salt=None, info=None, backend=backend ) hkdf.verify(b"foo", u"bar") def test_derive_short_output(self, backend): - hkdf = HKDF( - hashes.SHA256(), - 4, - salt=None, - info=None, - backend=backend - ) + hkdf = HKDF(hashes.SHA256(), 4, salt=None, info=None, backend=backend) assert hkdf.derive(b"\x01" * 16) == b"gJ\xfb{" @@ -165,7 +105,7 @@ def test_derive_long_output(self, backend): int(vector["l"]), salt=vector["salt"], info=vector["info"], - backend=backend + backend=backend, ) ikm = binascii.unhexlify(vector["ikm"]) @@ -180,7 +120,7 @@ def test_buffer_protocol(self, backend): int(vector["l"]), salt=vector["salt"], info=vector["info"], - backend=backend + backend=backend, ) ikm = bytearray(binascii.unhexlify(vector["ikm"])) @@ -194,8 +134,10 @@ def test_derive(self, backend): b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5" ) - okm = (b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c" - b"5bf34007208d5b887185865") + okm = ( + b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c" + b"5bf34007208d5b887185865" + ) info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9") hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend) @@ -203,12 +145,17 @@ def test_derive(self, backend): assert binascii.hexlify(hkdf.derive(prk)) == okm def test_buffer_protocol(self, backend): - prk = bytearray(binascii.unhexlify( - b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5" - )) + prk = bytearray( + binascii.unhexlify( + b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2" + b"b3e5" + ) + ) - okm = (b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c" - b"5bf34007208d5b887185865") + okm = ( + b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c" + b"5bf34007208d5b887185865" + ) info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9") hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend) @@ -220,8 +167,10 @@ def test_verify(self, backend): b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5" ) - okm = (b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c" - b"5bf34007208d5b887185865") + okm = ( + b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c" + b"5bf34007208d5b887185865" + ) info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9") hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend) diff --git a/tests/hazmat/primitives/test_hkdf_vectors.py b/tests/hazmat/primitives/test_hkdf_vectors.py index 74bf9291bc5d..97385e203c19 100644 --- a/tests/hazmat/primitives/test_hkdf_vectors.py +++ b/tests/hazmat/primitives/test_hkdf_vectors.py @@ -17,27 +17,27 @@ @pytest.mark.supported( only_if=lambda backend: backend.hmac_supported(hashes.SHA1()), - skip_message="Does not support SHA1." + skip_message="Does not support SHA1.", ) @pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHKDFSHA1(object): - test_HKDFSHA1 = generate_hkdf_test( + test_hkdfsha1 = generate_hkdf_test( load_nist_vectors, os.path.join("KDF"), ["rfc-5869-HKDF-SHA1.txt"], - hashes.SHA1() + hashes.SHA1(), ) @pytest.mark.supported( only_if=lambda backend: backend.hmac_supported(hashes.SHA256()), - skip_message="Does not support SHA256." + skip_message="Does not support SHA256.", ) @pytest.mark.requires_backend_interface(interface=HMACBackend) class TestHKDFSHA256(object): - test_HKDFSHA1 = generate_hkdf_test( + test_hkdfsha256 = generate_hkdf_test( load_nist_vectors, os.path.join("KDF"), ["rfc-5869-HKDF-SHA256.txt"], - hashes.SHA256() + hashes.SHA256(), ) diff --git a/tests/hazmat/primitives/test_hmac.py b/tests/hazmat/primitives/test_hmac.py index 0e2fe688ac82..7ea931aca4db 100644 --- a/tests/hazmat/primitives/test_hmac.py +++ b/tests/hazmat/primitives/test_hmac.py @@ -9,7 +9,9 @@ import pytest from cryptography.exceptions import ( - AlreadyFinalized, InvalidSignature, _Reasons + AlreadyFinalized, + InvalidSignature, + _Reasons, ) from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import hashes, hmac @@ -55,27 +57,27 @@ def test_raises_after_finalize(self, backend): h.finalize() def test_verify(self, backend): - h = hmac.HMAC(b'', hashes.SHA1(), backend=backend) + h = hmac.HMAC(b"", hashes.SHA1(), backend=backend) digest = h.finalize() - h = hmac.HMAC(b'', hashes.SHA1(), backend=backend) + h = hmac.HMAC(b"", hashes.SHA1(), backend=backend) h.verify(digest) with pytest.raises(AlreadyFinalized): - h.verify(b'') + h.verify(b"") def test_invalid_verify(self, backend): - h = hmac.HMAC(b'', hashes.SHA1(), backend=backend) + h = hmac.HMAC(b"", hashes.SHA1(), backend=backend) with pytest.raises(InvalidSignature): - h.verify(b'') + h.verify(b"") with pytest.raises(AlreadyFinalized): - h.verify(b'') + h.verify(b"") def test_verify_reject_unicode(self, backend): - h = hmac.HMAC(b'', hashes.SHA1(), backend=backend) + h = hmac.HMAC(b"", hashes.SHA1(), backend=backend) with pytest.raises(TypeError): - h.verify(u'') + h.verify(u"") def test_unsupported_hash(self, backend): with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_HASH): diff --git a/tests/hazmat/primitives/test_hmac_vectors.py b/tests/hazmat/primitives/test_hmac_vectors.py index 6ff71fe38508..b39df1a75e7c 100644 --- a/tests/hazmat/primitives/test_hmac_vectors.py +++ b/tests/hazmat/primitives/test_hmac_vectors.py @@ -24,9 +24,7 @@ class TestHMACMD5(object): test_hmac_md5 = generate_hmac_test( load_hash_vectors, "HMAC", - [ - "rfc-2202-md5.txt", - ], + ["rfc-2202-md5.txt"], hashes.MD5(), ) @@ -40,9 +38,7 @@ class TestHMACSHA1(object): test_hmac_sha1 = generate_hmac_test( load_hash_vectors, "HMAC", - [ - "rfc-2202-sha1.txt", - ], + ["rfc-2202-sha1.txt"], hashes.SHA1(), ) @@ -56,9 +52,7 @@ class TestHMACSHA224(object): test_hmac_sha224 = generate_hmac_test( load_hash_vectors, "HMAC", - [ - "rfc-4231-sha224.txt", - ], + ["rfc-4231-sha224.txt"], hashes.SHA224(), ) @@ -72,9 +66,7 @@ class TestHMACSHA256(object): test_hmac_sha256 = generate_hmac_test( load_hash_vectors, "HMAC", - [ - "rfc-4231-sha256.txt", - ], + ["rfc-4231-sha256.txt"], hashes.SHA256(), ) @@ -88,9 +80,7 @@ class TestHMACSHA384(object): test_hmac_sha384 = generate_hmac_test( load_hash_vectors, "HMAC", - [ - "rfc-4231-sha384.txt", - ], + ["rfc-4231-sha384.txt"], hashes.SHA384(), ) @@ -104,17 +94,15 @@ class TestHMACSHA512(object): test_hmac_sha512 = generate_hmac_test( load_hash_vectors, "HMAC", - [ - "rfc-4231-sha512.txt", - ], + ["rfc-4231-sha512.txt"], hashes.SHA512(), ) @pytest.mark.supported( - only_if=lambda backend: backend.hmac_supported(hashes.BLAKE2b( - digest_size=64 - )), + only_if=lambda backend: backend.hmac_supported( + hashes.BLAKE2b(digest_size=64) + ), skip_message="Does not support BLAKE2", ) @pytest.mark.requires_backend_interface(interface=HMACBackend) diff --git a/tests/hazmat/primitives/test_idea.py b/tests/hazmat/primitives/test_idea.py index 75116dc1866a..1f766def082a 100644 --- a/tests/hazmat/primitives/test_idea.py +++ b/tests/hazmat/primitives/test_idea.py @@ -24,7 +24,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestIDEAModeECB(object): - test_ECB = generate_encrypt_test( + test_ecb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "IDEA"), ["idea-ecb.txt"], @@ -41,12 +41,12 @@ class TestIDEAModeECB(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestIDEAModeCBC(object): - test_CBC = generate_encrypt_test( + test_cbc = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "IDEA"), ["idea-cbc.txt"], lambda key, **kwargs: algorithms.IDEA(binascii.unhexlify((key))), - lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)) + lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)), ) @@ -58,12 +58,12 @@ class TestIDEAModeCBC(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestIDEAModeOFB(object): - test_OFB = generate_encrypt_test( + test_ofb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "IDEA"), ["idea-ofb.txt"], lambda key, **kwargs: algorithms.IDEA(binascii.unhexlify((key))), - lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)) + lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)), ) @@ -75,10 +75,10 @@ class TestIDEAModeOFB(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestIDEAModeCFB(object): - test_CFB = generate_encrypt_test( + test_cfb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "IDEA"), ["idea-cfb.txt"], lambda key, **kwargs: algorithms.IDEA(binascii.unhexlify((key))), - lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)) + lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)), ) diff --git a/tests/hazmat/primitives/test_kbkdf.py b/tests/hazmat/primitives/test_kbkdf.py index a16f1768dd50..5ff5d74ea871 100644 --- a/tests/hazmat/primitives/test_kbkdf.py +++ b/tests/hazmat/primitives/test_kbkdf.py @@ -6,13 +6,13 @@ import pytest -from cryptography.exceptions import ( - AlreadyFinalized, InvalidKey, _Reasons -) +from cryptography.exceptions import AlreadyFinalized, InvalidKey, _Reasons from cryptography.hazmat.backends.interfaces import HMACBackend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.kbkdf import ( - CounterLocation, KBKDFHMAC, Mode + CounterLocation, + KBKDFHMAC, + Mode, ) from ...doubles import DummyHashAlgorithm @@ -22,137 +22,316 @@ @pytest.mark.requires_backend_interface(interface=HMACBackend) class TestKBKDFHMAC(object): def test_invalid_key(self, backend): - kdf = KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, - CounterLocation.BeforeFixed, b'label', b'context', - None, backend=backend) + kdf = KBKDFHMAC( + hashes.SHA256(), + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) key = kdf.derive(b"material") - kdf = KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, - CounterLocation.BeforeFixed, b'label', b'context', - None, backend=backend) + kdf = KBKDFHMAC( + hashes.SHA256(), + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) with pytest.raises(InvalidKey): kdf.verify(b"material2", key) def test_already_finalized(self, backend): - kdf = KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, - CounterLocation.BeforeFixed, b'label', b'context', - None, backend=backend) - - kdf.derive(b'material') + kdf = KBKDFHMAC( + hashes.SHA256(), + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + + kdf.derive(b"material") with pytest.raises(AlreadyFinalized): - kdf.derive(b'material2') - - kdf = KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, - CounterLocation.BeforeFixed, b'label', b'context', - None, backend=backend) + kdf.derive(b"material2") + + kdf = KBKDFHMAC( + hashes.SHA256(), + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) - key = kdf.derive(b'material') + key = kdf.derive(b"material") with pytest.raises(AlreadyFinalized): - kdf.verify(b'material', key) + kdf.verify(b"material", key) - kdf = KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, - CounterLocation.BeforeFixed, b'label', b'context', - None, backend=backend) - kdf.verify(b'material', key) + kdf = KBKDFHMAC( + hashes.SHA256(), + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + kdf.verify(b"material", key) with pytest.raises(AlreadyFinalized): kdf.verify(b"material", key) def test_key_length(self, backend): - kdf = KBKDFHMAC(hashes.SHA1(), Mode.CounterMode, 85899345920, 4, 4, - CounterLocation.BeforeFixed, b'label', b'context', - None, backend=backend) + kdf = KBKDFHMAC( + hashes.SHA1(), + Mode.CounterMode, + 85899345920, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) with pytest.raises(ValueError): - kdf.derive(b'material') + kdf.derive(b"material") def test_rlen(self, backend): with pytest.raises(ValueError): - KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 5, 4, - CounterLocation.BeforeFixed, b'label', b'context', - None, backend=backend) + KBKDFHMAC( + hashes.SHA256(), + Mode.CounterMode, + 32, + 5, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) def test_r_type(self, backend): with pytest.raises(TypeError): - KBKDFHMAC(hashes.SHA1(), Mode.CounterMode, 32, b'r', 4, - CounterLocation.BeforeFixed, b'label', b'context', - None, backend=backend) + KBKDFHMAC( + hashes.SHA1(), + Mode.CounterMode, + 32, + b"r", + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) def test_l_type(self, backend): with pytest.raises(TypeError): - KBKDFHMAC(hashes.SHA1(), Mode.CounterMode, 32, 4, b'l', - CounterLocation.BeforeFixed, b'label', b'context', - None, backend=backend) + KBKDFHMAC( + hashes.SHA1(), + Mode.CounterMode, + 32, + 4, + b"l", + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) def test_l(self, backend): with pytest.raises(ValueError): - KBKDFHMAC(hashes.SHA1(), Mode.CounterMode, 32, 4, None, - CounterLocation.BeforeFixed, b'label', b'context', - None, backend=backend) + KBKDFHMAC( + hashes.SHA1(), + Mode.CounterMode, + 32, + 4, + None, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) def test_unsupported_mode(self, backend): with pytest.raises(TypeError): - KBKDFHMAC(hashes.SHA256(), None, 32, 4, 4, - CounterLocation.BeforeFixed, b'label', b'context', - None, backend=backend) + KBKDFHMAC( + hashes.SHA256(), + None, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) def test_unsupported_location(self, backend): with pytest.raises(TypeError): - KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, - None, b'label', b'context', None, - backend=backend) + KBKDFHMAC( + hashes.SHA256(), + Mode.CounterMode, + 32, + 4, + 4, + None, + b"label", + b"context", + None, + backend=backend, + ) def test_unsupported_parameters(self, backend): with pytest.raises(ValueError): - KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, - CounterLocation.BeforeFixed, b'label', b'context', - b'fixed', backend=backend) + KBKDFHMAC( + hashes.SHA256(), + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + b"fixed", + backend=backend, + ) def test_unsupported_hash(self, backend): with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_HASH): - KBKDFHMAC(object(), Mode.CounterMode, 32, 4, 4, - CounterLocation.BeforeFixed, b'label', b'context', - None, backend=backend) + KBKDFHMAC( + object(), + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) def test_unsupported_algorithm(self, backend): with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_HASH): - KBKDFHMAC(DummyHashAlgorithm(), Mode.CounterMode, 32, 4, 4, - CounterLocation.BeforeFixed, b'label', b'context', - None, backend=backend) + KBKDFHMAC( + DummyHashAlgorithm(), + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) def test_invalid_backend(self, backend): with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): - KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, - CounterLocation.BeforeFixed, b'label', b'context', - None, backend=object()) + KBKDFHMAC( + hashes.SHA256(), + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=object(), + ) def test_unicode_error_label(self, backend): with pytest.raises(TypeError): - KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, - CounterLocation.BeforeFixed, u'label', b'context', - backend=backend) + KBKDFHMAC( + hashes.SHA256(), + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + u"label", + b"context", + backend=backend, + ) def test_unicode_error_context(self, backend): with pytest.raises(TypeError): - KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, - CounterLocation.BeforeFixed, b'label', u'context', - None, backend=backend) + KBKDFHMAC( + hashes.SHA256(), + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + u"context", + None, + backend=backend, + ) def test_unicode_error_key_material(self, backend): with pytest.raises(TypeError): - kdf = KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 32, 4, 4, - CounterLocation.BeforeFixed, b'label', - b'context', None, backend=backend) - kdf.derive(u'material') + kdf = KBKDFHMAC( + hashes.SHA256(), + Mode.CounterMode, + 32, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) + kdf.derive(u"material") def test_buffer_protocol(self, backend): - kdf = KBKDFHMAC(hashes.SHA256(), Mode.CounterMode, 10, 4, 4, - CounterLocation.BeforeFixed, b'label', b'context', - None, backend=backend) + kdf = KBKDFHMAC( + hashes.SHA256(), + Mode.CounterMode, + 10, + 4, + 4, + CounterLocation.BeforeFixed, + b"label", + b"context", + None, + backend=backend, + ) key = kdf.derive(bytearray(b"material")) - assert key == b'\xb7\x01\x05\x98\xf5\x1a\x12L\xc7.' + assert key == b"\xb7\x01\x05\x98\xf5\x1a\x12L\xc7." diff --git a/tests/hazmat/primitives/test_kbkdf_vectors.py b/tests/hazmat/primitives/test_kbkdf_vectors.py index c8263e2b2716..462e04ec5a87 100644 --- a/tests/hazmat/primitives/test_kbkdf_vectors.py +++ b/tests/hazmat/primitives/test_kbkdf_vectors.py @@ -16,8 +16,8 @@ @pytest.mark.requires_backend_interface(interface=HMACBackend) class TestCounterKDFCounterMode(object): - test_HKDFSHA1 = generate_kbkdf_counter_mode_test( + test_kbkdfctr = generate_kbkdf_counter_mode_test( load_nist_kbkdf_vectors, os.path.join("KDF"), - ["nist-800-108-KBKDF-CTR.txt"] + ["nist-800-108-KBKDF-CTR.txt"], ) diff --git a/tests/hazmat/primitives/test_keywrap.py b/tests/hazmat/primitives/test_keywrap.py index c74b144b66fc..9b91ccf36b33 100644 --- a/tests/hazmat/primitives/test_keywrap.py +++ b/tests/hazmat/primitives/test_keywrap.py @@ -24,15 +24,15 @@ class TestAESKeyWrap(object): _load_all_params( os.path.join("keywrap", "kwtestvectors"), ["KW_AE_128.txt", "KW_AE_192.txt", "KW_AE_256.txt"], - load_nist_vectors - ) + load_nist_vectors, + ), ) @pytest.mark.supported( only_if=lambda backend: backend.cipher_supported( algorithms.AES(b"\x00" * 16), modes.ECB() ), skip_message="Does not support AES key wrap (RFC 3394) because AES-ECB" - " is unsupported", + " is unsupported", ) def test_wrap(self, backend, params): wrapping_key = binascii.unhexlify(params["k"]) @@ -45,15 +45,15 @@ def test_wrap(self, backend, params): _load_all_params( os.path.join("keywrap", "kwtestvectors"), ["KW_AD_128.txt", "KW_AD_192.txt", "KW_AD_256.txt"], - load_nist_vectors - ) + load_nist_vectors, + ), ) @pytest.mark.supported( only_if=lambda backend: backend.cipher_supported( algorithms.AES(b"\x00" * 16), modes.ECB() ), skip_message="Does not support AES key wrap (RFC 3394) because AES-ECB" - " is unsupported", + " is unsupported", ) def test_unwrap(self, backend, params): wrapping_key = binascii.unhexlify(params["k"]) @@ -72,7 +72,7 @@ def test_unwrap(self, backend, params): algorithms.AES(b"\x00" * 16), modes.ECB() ), skip_message="Does not support AES key wrap (RFC 3394) because AES-ECB" - " is unsupported", + " is unsupported", ) def test_wrap_invalid_key_length(self, backend): # The wrapping key must be of length [16, 24, 32] @@ -84,7 +84,7 @@ def test_wrap_invalid_key_length(self, backend): algorithms.AES(b"\x00" * 16), modes.ECB() ), skip_message="Does not support AES key wrap (RFC 3394) because AES-ECB" - " is unsupported", + " is unsupported", ) def test_unwrap_invalid_key_length(self, backend): with pytest.raises(ValueError): @@ -95,7 +95,7 @@ def test_unwrap_invalid_key_length(self, backend): algorithms.AES(b"\x00" * 16), modes.ECB() ), skip_message="Does not support AES key wrap (RFC 3394) because AES-ECB" - " is unsupported", + " is unsupported", ) def test_wrap_invalid_key_to_wrap_length(self, backend): # Keys to wrap must be at least 16 bytes long @@ -121,7 +121,7 @@ def test_unwrap_invalid_wrapped_key_length(self, backend): algorithms.AES(b"\x00" * 16), modes.ECB() ), skip_message="Does not support AES key wrap (RFC 5649) because AES-ECB" - " is unsupported", + " is unsupported", ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestAESKeyWrapWithPadding(object): @@ -130,8 +130,8 @@ class TestAESKeyWrapWithPadding(object): _load_all_params( os.path.join("keywrap", "kwtestvectors"), ["KWP_AE_128.txt", "KWP_AE_192.txt", "KWP_AE_256.txt"], - load_nist_vectors - ) + load_nist_vectors, + ), ) def test_wrap(self, backend, params): wrapping_key = binascii.unhexlify(params["k"]) @@ -143,7 +143,7 @@ def test_wrap(self, backend, params): @pytest.mark.parametrize( "params", - _load_all_params("keywrap", ["kwp_botan.txt"], load_nist_vectors) + _load_all_params("keywrap", ["kwp_botan.txt"], load_nist_vectors), ) def test_wrap_additional_vectors(self, backend, params): wrapping_key = binascii.unhexlify(params["key"]) @@ -158,8 +158,8 @@ def test_wrap_additional_vectors(self, backend, params): _load_all_params( os.path.join("keywrap", "kwtestvectors"), ["KWP_AD_128.txt", "KWP_AD_192.txt", "KWP_AD_256.txt"], - load_nist_vectors - ) + load_nist_vectors, + ), ) def test_unwrap(self, backend, params): wrapping_key = binascii.unhexlify(params["k"]) @@ -177,7 +177,7 @@ def test_unwrap(self, backend, params): @pytest.mark.parametrize( "params", - _load_all_params("keywrap", ["kwp_botan.txt"], load_nist_vectors) + _load_all_params("keywrap", ["kwp_botan.txt"], load_nist_vectors), ) def test_unwrap_additional_vectors(self, backend, params): wrapping_key = binascii.unhexlify(params["key"]) @@ -190,18 +190,18 @@ def test_unwrap_additional_vectors(self, backend, params): def test_unwrap_invalid_wrapped_key_length(self, backend): # Keys to unwrap must be at least 16 bytes with pytest.raises( - keywrap.InvalidUnwrap, match='Must be at least 16 bytes' + keywrap.InvalidUnwrap, match="Must be at least 16 bytes" ): keywrap.aes_key_unwrap_with_padding( b"sixteen_byte_key", b"\x00" * 15, backend ) def test_wrap_invalid_key_length(self, backend): - with pytest.raises(ValueError, match='must be a valid AES key length'): + with pytest.raises(ValueError, match="must be a valid AES key length"): keywrap.aes_key_wrap_with_padding(b"badkey", b"\x00", backend) def test_unwrap_invalid_key_length(self, backend): - with pytest.raises(ValueError, match='must be a valid AES key length'): + with pytest.raises(ValueError, match="must be a valid AES key length"): keywrap.aes_key_unwrap_with_padding( b"badkey", b"\x00" * 16, backend ) diff --git a/tests/hazmat/primitives/test_padding.py b/tests/hazmat/primitives/test_padding.py index fb72a794b5ee..bf5379730131 100644 --- a/tests/hazmat/primitives/test_padding.py +++ b/tests/hazmat/primitives/test_padding.py @@ -18,14 +18,17 @@ def test_invalid_block_size(self, size): with pytest.raises(ValueError): padding.PKCS7(size) - @pytest.mark.parametrize(("size", "padded"), [ - (128, b"1111"), - (128, b"1111111111111111"), - (128, b"111111111111111\x06"), - (128, b""), - (128, b"\x06" * 6), - (128, b"\x00" * 16), - ]) + @pytest.mark.parametrize( + ("size", "padded"), + [ + (128, b"1111"), + (128, b"1111111111111111"), + (128, b"111111111111111\x06"), + (128, b""), + (128, b"\x06" * 6), + (128, b"\x00" * 16), + ], + ) def test_invalid_padding(self, size, padded): unpadder = padding.PKCS7(size).unpadder() with pytest.raises(ValueError): @@ -40,46 +43,36 @@ def test_non_bytes(self): with pytest.raises(TypeError): unpadder.update(u"abc") - @pytest.mark.parametrize(("size", "unpadded", "padded"), [ - ( - 128, - b"1111111111", - b"1111111111\x06\x06\x06\x06\x06\x06", - ), - ( - 128, - b"111111111111111122222222222222", - b"111111111111111122222222222222\x02\x02", - ), - ( - 128, - b"1" * 16, - b"1" * 16 + b"\x10" * 16, - ), - ( - 128, - b"1" * 17, - b"1" * 17 + b"\x0F" * 15, - ) - ]) + @pytest.mark.parametrize( + ("size", "unpadded", "padded"), + [ + (128, b"1111111111", b"1111111111\x06\x06\x06\x06\x06\x06"), + ( + 128, + b"111111111111111122222222222222", + b"111111111111111122222222222222\x02\x02", + ), + (128, b"1" * 16, b"1" * 16 + b"\x10" * 16), + (128, b"1" * 17, b"1" * 17 + b"\x0F" * 15), + ], + ) def test_pad(self, size, unpadded, padded): padder = padding.PKCS7(size).padder() result = padder.update(unpadded) result += padder.finalize() assert result == padded - @pytest.mark.parametrize(("size", "unpadded", "padded"), [ - ( - 128, - b"1111111111", - b"1111111111\x06\x06\x06\x06\x06\x06", - ), - ( - 128, - b"111111111111111122222222222222", - b"111111111111111122222222222222\x02\x02", - ), - ]) + @pytest.mark.parametrize( + ("size", "unpadded", "padded"), + [ + (128, b"1111111111", b"1111111111\x06\x06\x06\x06\x06\x06"), + ( + 128, + b"111111111111111122222222222222", + b"111111111111111122222222222222\x02\x02", + ), + ], + ) def test_unpad(self, size, unpadded, padded): unpadder = padding.PKCS7(size).unpadder() result = unpadder.update(padded) @@ -116,6 +109,18 @@ def test_large_padding(self): assert data == b"" + def test_bytearray(self): + padder = padding.PKCS7(128).padder() + unpadded = bytearray(b"t" * 38) + padded = ( + padder.update(unpadded) + + padder.update(unpadded) + + padder.finalize() + ) + unpadder = padding.PKCS7(128).unpadder() + final = unpadder.update(padded) + unpadder.finalize() + assert final == unpadded + unpadded + class TestANSIX923(object): @pytest.mark.parametrize("size", [127, 4096, -2]) @@ -123,15 +128,18 @@ def test_invalid_block_size(self, size): with pytest.raises(ValueError): padding.ANSIX923(size) - @pytest.mark.parametrize(("size", "padded"), [ - (128, b"1111"), - (128, b"1111111111111111"), - (128, b"111111111111111\x06"), - (128, b"1111111111\x06\x06\x06\x06\x06\x06"), - (128, b""), - (128, b"\x06" * 6), - (128, b"\x00" * 16), - ]) + @pytest.mark.parametrize( + ("size", "padded"), + [ + (128, b"1111"), + (128, b"1111111111111111"), + (128, b"111111111111111\x06"), + (128, b"1111111111\x06\x06\x06\x06\x06\x06"), + (128, b""), + (128, b"\x06" * 6), + (128, b"\x00" * 16), + ], + ) def test_invalid_padding(self, size, padded): unpadder = padding.ANSIX923(size).unpadder() with pytest.raises(ValueError): @@ -146,46 +154,36 @@ def test_non_bytes(self): with pytest.raises(TypeError): unpadder.update(u"abc") - @pytest.mark.parametrize(("size", "unpadded", "padded"), [ - ( - 128, - b"1111111111", - b"1111111111\x00\x00\x00\x00\x00\x06", - ), - ( - 128, - b"111111111111111122222222222222", - b"111111111111111122222222222222\x00\x02", - ), - ( - 128, - b"1" * 16, - b"1" * 16 + b"\x00" * 15 + b"\x10", - ), - ( - 128, - b"1" * 17, - b"1" * 17 + b"\x00" * 14 + b"\x0F", - ) - ]) + @pytest.mark.parametrize( + ("size", "unpadded", "padded"), + [ + (128, b"1111111111", b"1111111111\x00\x00\x00\x00\x00\x06"), + ( + 128, + b"111111111111111122222222222222", + b"111111111111111122222222222222\x00\x02", + ), + (128, b"1" * 16, b"1" * 16 + b"\x00" * 15 + b"\x10"), + (128, b"1" * 17, b"1" * 17 + b"\x00" * 14 + b"\x0F"), + ], + ) def test_pad(self, size, unpadded, padded): padder = padding.ANSIX923(size).padder() result = padder.update(unpadded) result += padder.finalize() assert result == padded - @pytest.mark.parametrize(("size", "unpadded", "padded"), [ - ( - 128, - b"1111111111", - b"1111111111\x00\x00\x00\x00\x00\x06", - ), - ( - 128, - b"111111111111111122222222222222", - b"111111111111111122222222222222\x00\x02", - ), - ]) + @pytest.mark.parametrize( + ("size", "unpadded", "padded"), + [ + (128, b"1111111111", b"1111111111\x00\x00\x00\x00\x00\x06"), + ( + 128, + b"111111111111111122222222222222", + b"111111111111111122222222222222\x00\x02", + ), + ], + ) def test_unpad(self, size, unpadded, padded): unpadder = padding.ANSIX923(size).unpadder() result = unpadder.update(padded) @@ -207,3 +205,15 @@ def test_use_after_finalize(self): unpadder.update(b"") with pytest.raises(AlreadyFinalized): unpadder.finalize() + + def test_bytearray(self): + padder = padding.ANSIX923(128).padder() + unpadded = bytearray(b"t" * 38) + padded = ( + padder.update(unpadded) + + padder.update(unpadded) + + padder.finalize() + ) + unpadder = padding.ANSIX923(128).unpadder() + final = unpadder.update(padded) + unpadder.finalize() + assert final == unpadded + unpadded diff --git a/tests/hazmat/primitives/test_pbkdf2hmac.py b/tests/hazmat/primitives/test_pbkdf2hmac.py index 0254b2168313..34fd25cf47e5 100644 --- a/tests/hazmat/primitives/test_pbkdf2hmac.py +++ b/tests/hazmat/primitives/test_pbkdf2hmac.py @@ -6,10 +6,7 @@ import pytest -from cryptography.exceptions import ( - AlreadyFinalized, InvalidKey, _Reasons -) -from cryptography.hazmat.backends import default_backend +from cryptography.exceptions import AlreadyFinalized, InvalidKey, _Reasons from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC @@ -18,47 +15,45 @@ class TestPBKDF2HMAC(object): - def test_already_finalized(self): - kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, default_backend()) + def test_already_finalized(self, backend): + kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, backend) kdf.derive(b"password") with pytest.raises(AlreadyFinalized): kdf.derive(b"password2") - kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, default_backend()) + kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, backend) key = kdf.derive(b"password") with pytest.raises(AlreadyFinalized): kdf.verify(b"password", key) - kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, default_backend()) + kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, backend) kdf.verify(b"password", key) with pytest.raises(AlreadyFinalized): kdf.verify(b"password", key) - def test_unsupported_algorithm(self): + def test_unsupported_algorithm(self, backend): with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_HASH): - PBKDF2HMAC( - DummyHashAlgorithm(), 20, b"salt", 10, default_backend() - ) + PBKDF2HMAC(DummyHashAlgorithm(), 20, b"salt", 10, backend) - def test_invalid_key(self): - kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, default_backend()) + def test_invalid_key(self, backend): + kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, backend) key = kdf.derive(b"password") - kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, default_backend()) + kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, backend) with pytest.raises(InvalidKey): kdf.verify(b"password2", key) - def test_unicode_error_with_salt(self): + def test_unicode_error_with_salt(self, backend): with pytest.raises(TypeError): - PBKDF2HMAC(hashes.SHA1(), 20, u"salt", 10, default_backend()) + PBKDF2HMAC(hashes.SHA1(), 20, u"salt", 10, backend) - def test_unicode_error_with_key_material(self): - kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, default_backend()) + def test_unicode_error_with_key_material(self, backend): + kdf = PBKDF2HMAC(hashes.SHA1(), 20, b"salt", 10, backend) with pytest.raises(TypeError): kdf.derive(u"unicode here") def test_buffer_protocol(self, backend): - kdf = PBKDF2HMAC(hashes.SHA1(), 10, b"salt", 10, default_backend()) + kdf = PBKDF2HMAC(hashes.SHA1(), 10, b"salt", 10, backend) data = bytearray(b"data") assert kdf.derive(data) == b"\xe9n\xaa\x81\xbbt\xa4\xf6\x08\xce" diff --git a/tests/hazmat/primitives/test_pbkdf2hmac_vectors.py b/tests/hazmat/primitives/test_pbkdf2hmac_vectors.py index fe51f543804a..4b97b0d13a97 100644 --- a/tests/hazmat/primitives/test_pbkdf2hmac_vectors.py +++ b/tests/hazmat/primitives/test_pbkdf2hmac_vectors.py @@ -22,8 +22,6 @@ class TestPBKDF2HMACSHA1(object): test_pbkdf2_sha1 = generate_pbkdf2_test( load_nist_vectors, "KDF", - [ - "rfc-6070-PBKDF2-SHA1.txt", - ], + ["rfc-6070-PBKDF2-SHA1.txt"], hashes.SHA1(), ) diff --git a/tests/hazmat/primitives/test_pkcs12.py b/tests/hazmat/primitives/test_pkcs12.py index f084d578c44f..297483e2f99d 100644 --- a/tests/hazmat/primitives/test_pkcs12.py +++ b/tests/hazmat/primitives/test_pkcs12.py @@ -10,61 +10,85 @@ from cryptography import x509 from cryptography.hazmat.backends.interfaces import DERSerializationBackend +from cryptography.hazmat.backends.openssl.backend import _RC2 +from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.serialization import load_pem_private_key from cryptography.hazmat.primitives.serialization.pkcs12 import ( - load_key_and_certificates + load_key_and_certificates, + serialize_key_and_certificates, ) from .utils import load_vectors_from_file +from ...doubles import DummyKeySerializationEncryption @pytest.mark.requires_backend_interface(interface=DERSerializationBackend) -class TestPKCS12(object): - @pytest.mark.parametrize( - ("filename", "password"), - [ - ("cert-key-aes256cbc.p12", b"cryptography"), - ("cert-none-key-none.p12", b"cryptography"), - ("cert-rc2-key-3des.p12", b"cryptography"), - ("no-password.p12", None), - ] - ) - def test_load_pkcs12_ec_keys(self, filename, password, backend): +class TestPKCS12Loading(object): + def _test_load_pkcs12_ec_keys(self, filename, password, backend): cert = load_vectors_from_file( os.path.join("x509", "custom", "ca", "ca.pem"), lambda pemfile: x509.load_pem_x509_certificate( pemfile.read(), backend - ), mode="rb" + ), + mode="rb", ) key = load_vectors_from_file( os.path.join("x509", "custom", "ca", "ca_key.pem"), lambda pemfile: load_pem_private_key( pemfile.read(), None, backend - ), mode="rb" + ), + mode="rb", ) parsed_key, parsed_cert, parsed_more_certs = load_vectors_from_file( os.path.join("pkcs12", filename), lambda derfile: load_key_and_certificates( derfile.read(), password, backend - ), mode="rb" + ), + mode="rb", ) assert parsed_cert == cert assert parsed_key.private_numbers() == key.private_numbers() assert parsed_more_certs == [] + @pytest.mark.parametrize( + ("filename", "password"), + [ + ("cert-key-aes256cbc.p12", b"cryptography"), + ("cert-none-key-none.p12", b"cryptography"), + ], + ) + def test_load_pkcs12_ec_keys(self, filename, password, backend): + self._test_load_pkcs12_ec_keys(filename, password, backend) + + @pytest.mark.parametrize( + ("filename", "password"), + [ + ("cert-rc2-key-3des.p12", b"cryptography"), + ("no-password.p12", None), + ], + ) + @pytest.mark.supported( + only_if=lambda backend: backend.cipher_supported(_RC2(), None), + skip_message="Does not support RC2", + ) + @pytest.mark.skip_fips(reason="Unsupported algorithm in FIPS mode") + def test_load_pkcs12_ec_keys_rc2(self, filename, password, backend): + self._test_load_pkcs12_ec_keys(filename, password, backend) + def test_load_pkcs12_cert_only(self, backend): cert = load_vectors_from_file( os.path.join("x509", "custom", "ca", "ca.pem"), lambda pemfile: x509.load_pem_x509_certificate( pemfile.read(), backend - ), mode="rb" + ), + mode="rb", ) parsed_key, parsed_cert, parsed_more_certs = load_vectors_from_file( os.path.join("pkcs12", "cert-aes256cbc-no-key.p12"), lambda data: load_key_and_certificates( data.read(), b"cryptography", backend ), - mode="rb" + mode="rb", ) assert parsed_cert is None assert parsed_key is None @@ -75,14 +99,15 @@ def test_load_pkcs12_key_only(self, backend): os.path.join("x509", "custom", "ca", "ca_key.pem"), lambda pemfile: load_pem_private_key( pemfile.read(), None, backend - ), mode="rb" + ), + mode="rb", ) parsed_key, parsed_cert, parsed_more_certs = load_vectors_from_file( os.path.join("pkcs12", "no-cert-key-aes256cbc.p12"), lambda data: load_key_and_certificates( data.read(), b"cryptography", backend ), - mode="rb" + mode="rb", ) assert parsed_key.private_numbers() == key.private_numbers() assert parsed_cert is None @@ -90,15 +115,11 @@ def test_load_pkcs12_key_only(self, backend): def test_non_bytes(self, backend): with pytest.raises(TypeError): - load_key_and_certificates( - b"irrelevant", object(), backend - ) + load_key_and_certificates(b"irrelevant", object(), backend) def test_not_a_pkcs12(self, backend): with pytest.raises(ValueError): - load_key_and_certificates( - b"invalid", b"pass", backend - ) + load_key_and_certificates(b"invalid", b"pass", backend) def test_invalid_password(self, backend): with pytest.raises(ValueError): @@ -106,13 +127,15 @@ def test_invalid_password(self, backend): os.path.join("pkcs12", "cert-key-aes256cbc.p12"), lambda derfile: load_key_and_certificates( derfile.read(), b"invalid", backend - ), mode="rb" + ), + mode="rb", ) def test_buffer_protocol(self, backend): p12 = load_vectors_from_file( os.path.join("pkcs12", "cert-key-aes256cbc.p12"), - lambda derfile: derfile.read(), mode="rb" + lambda derfile: derfile.read(), + mode="rb", ) p12buffer = bytearray(p12) parsed_key, parsed_cert, parsed_more_certs = load_key_and_certificates( @@ -121,3 +144,128 @@ def test_buffer_protocol(self, backend): assert parsed_key is not None assert parsed_cert is not None assert parsed_more_certs == [] + + +def _load_cert(backend, path): + return load_vectors_from_file( + path, + lambda pemfile: x509.load_pem_x509_certificate( + pemfile.read(), backend + ), + mode="rb", + ) + + +def _load_ca(backend): + cert = _load_cert(backend, os.path.join("x509", "custom", "ca", "ca.pem")) + key = load_vectors_from_file( + os.path.join("x509", "custom", "ca", "ca_key.pem"), + lambda pemfile: load_pem_private_key(pemfile.read(), None, backend), + mode="rb", + ) + return cert, key + + +class TestPKCS12Creation(object): + @pytest.mark.parametrize("name", [None, b"name"]) + @pytest.mark.parametrize( + ("encryption_algorithm", "password"), + [ + (serialization.BestAvailableEncryption(b"password"), b"password"), + (serialization.NoEncryption(), None), + ], + ) + def test_generate(self, backend, name, encryption_algorithm, password): + cert, key = _load_ca(backend) + p12 = serialize_key_and_certificates( + name, key, cert, None, encryption_algorithm + ) + + parsed_key, parsed_cert, parsed_more_certs = load_key_and_certificates( + p12, password, backend + ) + assert parsed_cert == cert + assert parsed_key.private_numbers() == key.private_numbers() + assert parsed_more_certs == [] + + def test_generate_with_cert_key_ca(self, backend): + cert, key = _load_ca(backend) + cert2 = _load_cert( + backend, os.path.join("x509", "custom", "dsa_selfsigned_ca.pem") + ) + cert3 = _load_cert(backend, os.path.join("x509", "letsencryptx3.pem")) + encryption = serialization.NoEncryption() + p12 = serialize_key_and_certificates( + None, key, cert, [cert2, cert3], encryption + ) + + parsed_key, parsed_cert, parsed_more_certs = load_key_and_certificates( + p12, None, backend + ) + assert parsed_cert == cert + assert parsed_key.private_numbers() == key.private_numbers() + assert parsed_more_certs == [cert2, cert3] + + def test_generate_wrong_types(self, backend): + cert, key = _load_ca(backend) + cert2 = _load_cert(backend, os.path.join("x509", "letsencryptx3.pem")) + encryption = serialization.NoEncryption() + with pytest.raises(TypeError) as exc: + serialize_key_and_certificates( + b"name", cert, cert, None, encryption + ) + assert ( + str(exc.value) + == "Key must be RSA, DSA, or EllipticCurve private key." + ) + + with pytest.raises(TypeError) as exc: + serialize_key_and_certificates(b"name", key, key, None, encryption) + assert str(exc.value) == "cert must be a certificate" + + with pytest.raises(TypeError) as exc: + serialize_key_and_certificates(b"name", key, cert, None, key) + assert str(exc.value) == ( + "Key encryption algorithm must be a " + "KeySerializationEncryption instance" + ) + + with pytest.raises(TypeError) as exc: + serialize_key_and_certificates(None, key, cert, cert2, encryption) + + with pytest.raises(TypeError) as exc: + serialize_key_and_certificates(None, key, cert, [key], encryption) + assert str(exc.value) == "all values in cas must be certificates" + + def test_generate_no_cert(self, backend): + _, key = _load_ca(backend) + p12 = serialize_key_and_certificates( + None, key, None, None, serialization.NoEncryption() + ) + parsed_key, parsed_cert, parsed_more_certs = load_key_and_certificates( + p12, None, backend + ) + assert parsed_cert is None + assert parsed_key.private_numbers() == key.private_numbers() + assert parsed_more_certs == [] + + def test_must_supply_something(self): + with pytest.raises(ValueError) as exc: + serialize_key_and_certificates( + None, None, None, None, serialization.NoEncryption() + ) + assert str(exc.value) == ( + "You must supply at least one of key, cert, or cas" + ) + + def test_generate_unsupported_encryption_type(self, backend): + cert, key = _load_ca(backend) + with pytest.raises(ValueError) as exc: + serialize_key_and_certificates( + None, + key, + cert, + None, + DummyKeySerializationEncryption(), + ) + assert str(exc.value) == "Unsupported key encryption type" diff --git a/tests/hazmat/primitives/test_pkcs7.py b/tests/hazmat/primitives/test_pkcs7.py new file mode 100644 index 000000000000..8b93cb6334ba --- /dev/null +++ b/tests/hazmat/primitives/test_pkcs7.py @@ -0,0 +1,675 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import os + +import pytest + +from cryptography import x509 +from cryptography.exceptions import _Reasons +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ed25519 +from cryptography.hazmat.primitives.serialization import pkcs7 + +from .utils import load_vectors_from_file +from ...utils import raises_unsupported_algorithm + + +class TestPKCS7Loading(object): + def test_load_invalid_der_pkcs7(self): + with pytest.raises(ValueError): + pkcs7.load_der_pkcs7_certificates(b"nonsense") + + def test_load_invalid_pem_pkcs7(self): + with pytest.raises(ValueError): + pkcs7.load_pem_pkcs7_certificates(b"nonsense") + + def test_not_bytes_der(self): + with pytest.raises(TypeError): + pkcs7.load_der_pkcs7_certificates(38) + + def test_not_bytes_pem(self): + with pytest.raises(TypeError): + pkcs7.load_pem_pkcs7_certificates(38) + + def test_load_pkcs7_pem(self): + certs = load_vectors_from_file( + os.path.join("pkcs7", "isrg.pem"), + lambda pemfile: pkcs7.load_pem_pkcs7_certificates(pemfile.read()), + mode="rb", + ) + assert len(certs) == 1 + assert certs[0].subject.get_attributes_for_oid( + x509.oid.NameOID.COMMON_NAME + ) == [ + x509.NameAttribute(x509.oid.NameOID.COMMON_NAME, u"ISRG Root X1") + ] + + def test_load_pkcs7_der(self): + certs = load_vectors_from_file( + os.path.join("pkcs7", "amazon-roots.p7b"), + lambda derfile: pkcs7.load_der_pkcs7_certificates(derfile.read()), + mode="rb", + ) + assert len(certs) == 2 + assert certs[0].subject.get_attributes_for_oid( + x509.oid.NameOID.COMMON_NAME + ) == [ + x509.NameAttribute( + x509.oid.NameOID.COMMON_NAME, u"Amazon Root CA 3" + ) + ] + assert certs[1].subject.get_attributes_for_oid( + x509.oid.NameOID.COMMON_NAME + ) == [ + x509.NameAttribute( + x509.oid.NameOID.COMMON_NAME, u"Amazon Root CA 2" + ) + ] + + def test_load_pkcs7_unsupported_type(self): + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_SERIALIZATION): + load_vectors_from_file( + os.path.join("pkcs7", "enveloped.pem"), + lambda pemfile: pkcs7.load_pem_pkcs7_certificates( + pemfile.read() + ), + mode="rb", + ) + + +# We have no public verification API and won't be adding one until we get +# some requirements from users so this function exists to give us basic +# verification for the signing tests. +def _pkcs7_verify(encoding, sig, msg, certs, options, backend): + sig_bio = backend._bytes_to_bio(sig) + if encoding is serialization.Encoding.DER: + p7 = backend._lib.d2i_PKCS7_bio(sig_bio.bio, backend._ffi.NULL) + elif encoding is serialization.Encoding.PEM: + p7 = backend._lib.PEM_read_bio_PKCS7( + sig_bio.bio, + backend._ffi.NULL, + backend._ffi.NULL, + backend._ffi.NULL, + ) + else: + p7 = backend._lib.SMIME_read_PKCS7(sig_bio.bio, backend._ffi.NULL) + backend.openssl_assert(p7 != backend._ffi.NULL) + p7 = backend._ffi.gc(p7, backend._lib.PKCS7_free) + flags = 0 + for option in options: + if option is pkcs7.PKCS7Options.Text: + flags |= backend._lib.PKCS7_TEXT + store = backend._lib.X509_STORE_new() + backend.openssl_assert(store != backend._ffi.NULL) + store = backend._ffi.gc(store, backend._lib.X509_STORE_free) + for cert in certs: + res = backend._lib.X509_STORE_add_cert(store, cert._x509) + backend.openssl_assert(res == 1) + if msg is None: + res = backend._lib.PKCS7_verify( + p7, + backend._ffi.NULL, + store, + backend._ffi.NULL, + backend._ffi.NULL, + flags, + ) + else: + msg_bio = backend._bytes_to_bio(msg) + res = backend._lib.PKCS7_verify( + p7, backend._ffi.NULL, store, msg_bio.bio, backend._ffi.NULL, flags + ) + backend.openssl_assert(res == 1) + + +def _load_cert_key(): + key = load_vectors_from_file( + os.path.join("x509", "custom", "ca", "ca_key.pem"), + lambda pemfile: serialization.load_pem_private_key( + pemfile.read(), None + ), + mode="rb", + ) + cert = load_vectors_from_file( + os.path.join("x509", "custom", "ca", "ca.pem"), + loader=lambda pemfile: x509.load_pem_x509_certificate(pemfile.read()), + mode="rb", + ) + return cert, key + + +class TestPKCS7Builder(object): + def test_invalid_data(self): + builder = pkcs7.PKCS7SignatureBuilder() + with pytest.raises(TypeError): + builder.set_data(u"not bytes") + + def test_set_data_twice(self): + builder = pkcs7.PKCS7SignatureBuilder().set_data(b"test") + with pytest.raises(ValueError): + builder.set_data(b"test") + + def test_sign_no_signer(self): + builder = pkcs7.PKCS7SignatureBuilder().set_data(b"test") + with pytest.raises(ValueError): + builder.sign(serialization.Encoding.SMIME, []) + + def test_sign_no_data(self): + cert, key = _load_cert_key() + builder = pkcs7.PKCS7SignatureBuilder().add_signer( + cert, key, hashes.SHA256() + ) + with pytest.raises(ValueError): + builder.sign(serialization.Encoding.SMIME, []) + + def test_unsupported_hash_alg(self): + cert, key = _load_cert_key() + with pytest.raises(TypeError): + pkcs7.PKCS7SignatureBuilder().add_signer( + cert, key, hashes.SHA512_256() + ) + + def test_not_a_cert(self): + cert, key = _load_cert_key() + with pytest.raises(TypeError): + pkcs7.PKCS7SignatureBuilder().add_signer( + b"notacert", key, hashes.SHA256() + ) + + @pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Does not support ed25519.", + ) + def test_unsupported_key_type(self, backend): + cert, _ = _load_cert_key() + key = ed25519.Ed25519PrivateKey.generate() + with pytest.raises(TypeError): + pkcs7.PKCS7SignatureBuilder().add_signer( + cert, key, hashes.SHA256() + ) + + def test_sign_invalid_options(self): + cert, key = _load_cert_key() + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(b"test") + .add_signer(cert, key, hashes.SHA256()) + ) + with pytest.raises(ValueError): + builder.sign(serialization.Encoding.SMIME, [b"invalid"]) + + def test_sign_invalid_encoding(self): + cert, key = _load_cert_key() + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(b"test") + .add_signer(cert, key, hashes.SHA256()) + ) + with pytest.raises(ValueError): + builder.sign(serialization.Encoding.Raw, []) + + def test_sign_invalid_options_text_no_detached(self): + cert, key = _load_cert_key() + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(b"test") + .add_signer(cert, key, hashes.SHA256()) + ) + options = [pkcs7.PKCS7Options.Text] + with pytest.raises(ValueError): + builder.sign(serialization.Encoding.SMIME, options) + + def test_sign_invalid_options_text_der_encoding(self): + cert, key = _load_cert_key() + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(b"test") + .add_signer(cert, key, hashes.SHA256()) + ) + options = [ + pkcs7.PKCS7Options.Text, + pkcs7.PKCS7Options.DetachedSignature, + ] + with pytest.raises(ValueError): + builder.sign(serialization.Encoding.DER, options) + + def test_sign_invalid_options_no_attrs_and_no_caps(self): + cert, key = _load_cert_key() + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(b"test") + .add_signer(cert, key, hashes.SHA256()) + ) + options = [ + pkcs7.PKCS7Options.NoAttributes, + pkcs7.PKCS7Options.NoCapabilities, + ] + with pytest.raises(ValueError): + builder.sign(serialization.Encoding.SMIME, options) + + def test_smime_sign_detached(self, backend): + data = b"hello world" + cert, key = _load_cert_key() + options = [pkcs7.PKCS7Options.DetachedSignature] + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hashes.SHA256()) + ) + + sig = builder.sign(serialization.Encoding.SMIME, options) + sig_binary = builder.sign(serialization.Encoding.DER, options) + # We don't have a generic ASN.1 parser available to us so we instead + # will assert on specific byte sequences being present based on the + # parameters chosen above. + assert b"sha-256" in sig + # Detached signature means that the signed data is *not* embedded into + # the PKCS7 structure itself, but is present in the SMIME serialization + # as a separate section before the PKCS7 data. So we should expect to + # have data in sig but not in sig_binary + assert data in sig + _pkcs7_verify( + serialization.Encoding.SMIME, sig, data, [cert], options, backend + ) + assert data not in sig_binary + _pkcs7_verify( + serialization.Encoding.DER, + sig_binary, + data, + [cert], + options, + backend, + ) + + def test_sign_byteslike(self): + data = bytearray(b"hello world") + cert, key = _load_cert_key() + options = [pkcs7.PKCS7Options.DetachedSignature] + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hashes.SHA256()) + ) + + sig = builder.sign(serialization.Encoding.SMIME, options) + assert bytes(data) in sig + + def test_sign_pem(self, backend): + data = b"hello world" + cert, key = _load_cert_key() + options = [] + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hashes.SHA256()) + ) + + sig = builder.sign(serialization.Encoding.PEM, options) + _pkcs7_verify( + serialization.Encoding.PEM, + sig, + None, + [cert], + options, + backend, + ) + + @pytest.mark.parametrize( + ("hash_alg", "expected_value"), + [ + (hashes.SHA1(), b"\x06\x05+\x0e\x03\x02\x1a"), + (hashes.SHA256(), b"\x06\t`\x86H\x01e\x03\x04\x02\x01"), + (hashes.SHA384(), b"\x06\t`\x86H\x01e\x03\x04\x02\x02"), + (hashes.SHA512(), b"\x06\t`\x86H\x01e\x03\x04\x02\x03"), + ], + ) + def test_sign_alternate_digests_der( + self, hash_alg, expected_value, backend + ): + data = b"hello world" + cert, key = _load_cert_key() + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hash_alg) + ) + options = [] + sig = builder.sign(serialization.Encoding.DER, options) + assert expected_value in sig + _pkcs7_verify( + serialization.Encoding.DER, sig, None, [cert], options, backend + ) + + @pytest.mark.parametrize( + ("hash_alg", "expected_value"), + [ + (hashes.SHA1(), b"sha1"), + (hashes.SHA256(), b"sha-256"), + (hashes.SHA384(), b"sha-384"), + (hashes.SHA512(), b"sha-512"), + ], + ) + def test_sign_alternate_digests_detached(self, hash_alg, expected_value): + data = b"hello world" + cert, key = _load_cert_key() + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hash_alg) + ) + options = [pkcs7.PKCS7Options.DetachedSignature] + sig = builder.sign(serialization.Encoding.SMIME, options) + # When in detached signature mode the hash algorithm is stored as a + # byte string like "sha-384". + assert expected_value in sig + + def test_sign_attached(self, backend): + data = b"hello world" + cert, key = _load_cert_key() + options = [] + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hashes.SHA256()) + ) + + sig_binary = builder.sign(serialization.Encoding.DER, options) + # When not passing detached signature the signed data is embedded into + # the PKCS7 structure itself + assert data in sig_binary + _pkcs7_verify( + serialization.Encoding.DER, + sig_binary, + None, + [cert], + options, + backend, + ) + + def test_sign_binary(self, backend): + data = b"hello\nworld" + cert, key = _load_cert_key() + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hashes.SHA256()) + ) + options = [] + sig_no_binary = builder.sign(serialization.Encoding.DER, options) + sig_binary = builder.sign( + serialization.Encoding.DER, [pkcs7.PKCS7Options.Binary] + ) + # Binary prevents translation of LF to CR+LF (SMIME canonical form) + # so data should not be present in sig_no_binary, but should be present + # in sig_binary + assert data not in sig_no_binary + _pkcs7_verify( + serialization.Encoding.DER, + sig_no_binary, + None, + [cert], + options, + backend, + ) + assert data in sig_binary + _pkcs7_verify( + serialization.Encoding.DER, + sig_binary, + None, + [cert], + options, + backend, + ) + + def test_sign_smime_canonicalization(self, backend): + data = b"hello\nworld" + cert, key = _load_cert_key() + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hashes.SHA256()) + ) + + options = [] + sig_binary = builder.sign(serialization.Encoding.DER, options) + # LF gets converted to CR+LF (SMIME canonical form) + # so data should not be present in the sig + assert data not in sig_binary + assert b"hello\r\nworld" in sig_binary + _pkcs7_verify( + serialization.Encoding.DER, + sig_binary, + None, + [cert], + options, + backend, + ) + + def test_sign_text(self, backend): + data = b"hello world" + cert, key = _load_cert_key() + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hashes.SHA256()) + ) + + options = [ + pkcs7.PKCS7Options.Text, + pkcs7.PKCS7Options.DetachedSignature, + ] + sig_pem = builder.sign(serialization.Encoding.SMIME, options) + # The text option adds text/plain headers to the S/MIME message + # These headers are only relevant in SMIME mode, not binary, which is + # just the PKCS7 structure itself. + assert b"text/plain" in sig_pem + # When passing the Text option the header is prepended so the actual + # signed data is this. + signed_data = b"Content-Type: text/plain\r\n\r\nhello world" + _pkcs7_verify( + serialization.Encoding.SMIME, + sig_pem, + signed_data, + [cert], + options, + backend, + ) + + def test_sign_no_capabilities(self, backend): + data = b"hello world" + cert, key = _load_cert_key() + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hashes.SHA256()) + ) + + options = [pkcs7.PKCS7Options.NoCapabilities] + sig_binary = builder.sign(serialization.Encoding.DER, options) + # NoCapabilities removes the SMIMECapabilities attribute from the + # PKCS7 structure. This is an ASN.1 sequence with the + # OID 1.2.840.113549.1.9.15. It does NOT remove all authenticated + # attributes, so we verify that by looking for the signingTime OID. + + # 1.2.840.113549.1.9.15 SMIMECapabilities as an ASN.1 DER encoded OID + assert b"\x06\t*\x86H\x86\xf7\r\x01\t\x0f" not in sig_binary + # 1.2.840.113549.1.9.5 signingTime as an ASN.1 DER encoded OID + assert b"\x06\t*\x86H\x86\xf7\r\x01\t\x05" in sig_binary + _pkcs7_verify( + serialization.Encoding.DER, + sig_binary, + None, + [cert], + options, + backend, + ) + + def test_sign_no_attributes(self, backend): + data = b"hello world" + cert, key = _load_cert_key() + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hashes.SHA256()) + ) + + options = [pkcs7.PKCS7Options.NoAttributes] + sig_binary = builder.sign(serialization.Encoding.DER, options) + # NoAttributes removes all authenticated attributes, so we shouldn't + # find SMIMECapabilities or signingTime. + + # 1.2.840.113549.1.9.15 SMIMECapabilities as an ASN.1 DER encoded OID + assert b"\x06\t*\x86H\x86\xf7\r\x01\t\x0f" not in sig_binary + # 1.2.840.113549.1.9.5 signingTime as an ASN.1 DER encoded OID + assert b"\x06\t*\x86H\x86\xf7\r\x01\t\x05" not in sig_binary + _pkcs7_verify( + serialization.Encoding.DER, + sig_binary, + None, + [cert], + options, + backend, + ) + + def test_sign_no_certs(self, backend): + data = b"hello world" + cert, key = _load_cert_key() + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hashes.SHA256()) + ) + + options = [] + sig = builder.sign(serialization.Encoding.DER, options) + assert sig.count(cert.public_bytes(serialization.Encoding.DER)) == 1 + + options = [pkcs7.PKCS7Options.NoCerts] + sig_no = builder.sign(serialization.Encoding.DER, options) + assert sig_no.count(cert.public_bytes(serialization.Encoding.DER)) == 0 + + def test_multiple_signers(self, backend): + data = b"hello world" + cert, key = _load_cert_key() + rsa_key = load_vectors_from_file( + os.path.join("x509", "custom", "ca", "rsa_key.pem"), + lambda pemfile: serialization.load_pem_private_key( + pemfile.read(), None + ), + mode="rb", + ) + rsa_cert = load_vectors_from_file( + os.path.join("x509", "custom", "ca", "rsa_ca.pem"), + loader=lambda pemfile: x509.load_pem_x509_certificate( + pemfile.read() + ), + mode="rb", + ) + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hashes.SHA512()) + .add_signer(rsa_cert, rsa_key, hashes.SHA512()) + ) + options = [] + sig = builder.sign(serialization.Encoding.DER, options) + # There should be three SHA512 OIDs in this structure + assert sig.count(b"\x06\t`\x86H\x01e\x03\x04\x02\x03") == 3 + _pkcs7_verify( + serialization.Encoding.DER, + sig, + None, + [cert, rsa_cert], + options, + backend, + ) + + def test_multiple_signers_different_hash_algs(self, backend): + data = b"hello world" + cert, key = _load_cert_key() + rsa_key = load_vectors_from_file( + os.path.join("x509", "custom", "ca", "rsa_key.pem"), + lambda pemfile: serialization.load_pem_private_key( + pemfile.read(), None + ), + mode="rb", + ) + rsa_cert = load_vectors_from_file( + os.path.join("x509", "custom", "ca", "rsa_ca.pem"), + loader=lambda pemfile: x509.load_pem_x509_certificate( + pemfile.read() + ), + mode="rb", + ) + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hashes.SHA384()) + .add_signer(rsa_cert, rsa_key, hashes.SHA512()) + ) + options = [] + sig = builder.sign(serialization.Encoding.DER, options) + # There should be two SHA384 and two SHA512 OIDs in this structure + assert sig.count(b"\x06\t`\x86H\x01e\x03\x04\x02\x02") == 2 + assert sig.count(b"\x06\t`\x86H\x01e\x03\x04\x02\x03") == 2 + _pkcs7_verify( + serialization.Encoding.DER, + sig, + None, + [cert, rsa_cert], + options, + backend, + ) + + def test_add_additional_cert_not_a_cert(self, backend): + with pytest.raises(TypeError): + pkcs7.PKCS7SignatureBuilder().add_certificate(b"notacert") + + def test_add_additional_cert(self, backend): + data = b"hello world" + cert, key = _load_cert_key() + rsa_cert = load_vectors_from_file( + os.path.join("x509", "custom", "ca", "rsa_ca.pem"), + loader=lambda pemfile: x509.load_pem_x509_certificate( + pemfile.read() + ), + mode="rb", + ) + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hashes.SHA384()) + .add_certificate(rsa_cert) + ) + options = [] + sig = builder.sign(serialization.Encoding.DER, options) + assert ( + sig.count(rsa_cert.public_bytes(serialization.Encoding.DER)) == 1 + ) + + def test_add_multiple_additional_certs(self, backend): + data = b"hello world" + cert, key = _load_cert_key() + rsa_cert = load_vectors_from_file( + os.path.join("x509", "custom", "ca", "rsa_ca.pem"), + loader=lambda pemfile: x509.load_pem_x509_certificate( + pemfile.read() + ), + mode="rb", + ) + builder = ( + pkcs7.PKCS7SignatureBuilder() + .set_data(data) + .add_signer(cert, key, hashes.SHA384()) + .add_certificate(rsa_cert) + .add_certificate(rsa_cert) + ) + options = [] + sig = builder.sign(serialization.Encoding.DER, options) + assert ( + sig.count(rsa_cert.public_bytes(serialization.Encoding.DER)) == 2 + ) diff --git a/tests/hazmat/primitives/test_poly1305.py b/tests/hazmat/primitives/test_poly1305.py new file mode 100644 index 000000000000..8779484ac9aa --- /dev/null +++ b/tests/hazmat/primitives/test_poly1305.py @@ -0,0 +1,156 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii +import os + +import pytest + +from cryptography.exceptions import ( + AlreadyFinalized, + InvalidSignature, + _Reasons, +) +from cryptography.hazmat.primitives.poly1305 import Poly1305 + +from ...utils import ( + load_nist_vectors, + load_vectors_from_file, + raises_unsupported_algorithm, +) + + +@pytest.mark.supported( + only_if=lambda backend: not backend.poly1305_supported(), + skip_message="Requires OpenSSL without poly1305 support", +) +def test_poly1305_unsupported(backend): + with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_MAC): + Poly1305(b"0" * 32) + + +@pytest.mark.supported( + only_if=lambda backend: backend.poly1305_supported(), + skip_message="Requires OpenSSL with poly1305 support", +) +class TestPoly1305(object): + @pytest.mark.parametrize( + "vector", + load_vectors_from_file( + os.path.join("poly1305", "rfc7539.txt"), load_nist_vectors + ), + ) + def test_vectors(self, vector, backend): + key = binascii.unhexlify(vector["key"]) + msg = binascii.unhexlify(vector["msg"]) + tag = binascii.unhexlify(vector["tag"]) + poly = Poly1305(key) + poly.update(msg) + assert poly.finalize() == tag + + assert Poly1305.generate_tag(key, msg) == tag + Poly1305.verify_tag(key, msg, tag) + + def test_key_with_no_additional_references(self, backend): + poly = Poly1305(os.urandom(32)) + assert len(poly.finalize()) == 16 + + def test_raises_after_finalize(self, backend): + poly = Poly1305(b"0" * 32) + poly.finalize() + + with pytest.raises(AlreadyFinalized): + poly.update(b"foo") + + with pytest.raises(AlreadyFinalized): + poly.finalize() + + def test_reject_unicode(self, backend): + poly = Poly1305(b"0" * 32) + with pytest.raises(TypeError): + poly.update(u"") + + with pytest.raises(TypeError): + Poly1305.generate_tag(b"0" * 32, u"") + + def test_verify(self, backend): + poly = Poly1305(b"0" * 32) + poly.update(b"msg") + tag = poly.finalize() + + with pytest.raises(AlreadyFinalized): + poly.verify(b"") + + poly2 = Poly1305(b"0" * 32) + poly2.update(b"msg") + poly2.verify(tag) + + Poly1305.verify_tag(b"0" * 32, b"msg", tag) + + def test_invalid_verify(self, backend): + poly = Poly1305(b"0" * 32) + poly.update(b"msg") + with pytest.raises(InvalidSignature): + poly.verify(b"") + + p2 = Poly1305(b"0" * 32) + p2.update(b"msg") + with pytest.raises(InvalidSignature): + p2.verify(b"\x00" * 16) + + with pytest.raises(InvalidSignature): + Poly1305.verify_tag(b"0" * 32, b"msg", b"\x00" * 16) + + def test_verify_reject_unicode(self, backend): + poly = Poly1305(b"0" * 32) + with pytest.raises(TypeError): + poly.verify(u"") + + with pytest.raises(TypeError): + Poly1305.verify_tag(b"0" * 32, b"msg", u"") + + def test_invalid_key_type(self, backend): + with pytest.raises(TypeError): + Poly1305(object()) + + with pytest.raises(TypeError): + Poly1305.generate_tag(object(), b"msg") + + def test_invalid_key_length(self, backend): + with pytest.raises(ValueError): + Poly1305(b"0" * 31) + + with pytest.raises(ValueError): + Poly1305.generate_tag(b"0" * 31, b"msg") + + with pytest.raises(ValueError): + Poly1305(b"0" * 33) + + with pytest.raises(ValueError): + Poly1305.generate_tag(b"0" * 33, b"msg") + + def test_buffer_protocol(self, backend): + key = binascii.unhexlify( + b"1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cb" + b"c207075c0" + ) + msg = binascii.unhexlify( + b"2754776173206272696c6c69672c20616e642074686520736c69746" + b"87920746f7665730a446964206779726520616e642067696d626c65" + b"20696e2074686520776162653a0a416c6c206d696d7379207765726" + b"52074686520626f726f676f7665732c0a416e6420746865206d6f6d" + b"65207261746873206f757467726162652e" + ) + key = bytearray(key) + poly = Poly1305(key) + poly.update(bytearray(msg)) + assert poly.finalize() == binascii.unhexlify( + b"4541669a7eaaee61e708dc7cbcc5eb62" + ) + + assert Poly1305.generate_tag(key, msg) == binascii.unhexlify( + b"4541669a7eaaee61e708dc7cbcc5eb62" + ) diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py index 65d88f547f82..d7fa7744f493 100644 --- a/tests/hazmat/primitives/test_rsa.py +++ b/tests/hazmat/primitives/test_rsa.py @@ -6,41 +6,67 @@ import binascii import itertools -import math import os import pytest from cryptography.exceptions import ( - AlreadyFinalized, InvalidSignature, _Reasons + AlreadyFinalized, + InvalidSignature, + _Reasons, ) from cryptography.hazmat.backends.interfaces import ( - PEMSerializationBackend, RSABackend + PEMSerializationBackend, + RSABackend, ) from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ( - padding, rsa, utils as asym_utils + padding, + rsa, + utils as asym_utils, ) from cryptography.hazmat.primitives.asymmetric.rsa import ( - RSAPrivateNumbers, RSAPublicNumbers + RSAPrivateNumbers, + RSAPublicNumbers, ) from cryptography.utils import CryptographyDeprecationWarning from .fixtures_rsa import ( - RSA_KEY_1024, RSA_KEY_1025, RSA_KEY_1026, RSA_KEY_1027, RSA_KEY_1028, - RSA_KEY_1029, RSA_KEY_1030, RSA_KEY_1031, RSA_KEY_1536, RSA_KEY_2048, - RSA_KEY_2048_ALT, RSA_KEY_512, RSA_KEY_512_ALT, RSA_KEY_522, RSA_KEY_599, - RSA_KEY_745, RSA_KEY_768, + RSA_KEY_1024, + RSA_KEY_1025, + RSA_KEY_1026, + RSA_KEY_1027, + RSA_KEY_1028, + RSA_KEY_1029, + RSA_KEY_1030, + RSA_KEY_1031, + RSA_KEY_1536, + RSA_KEY_2048, + RSA_KEY_2048_ALT, + RSA_KEY_512, + RSA_KEY_512_ALT, + RSA_KEY_522, + RSA_KEY_599, + RSA_KEY_745, + RSA_KEY_768, + RSA_KEY_CORRUPTED, ) from .utils import ( - _check_rsa_private_numbers, generate_rsa_verification_test + _check_rsa_private_numbers, + generate_rsa_verification_test, + skip_fips_traditional_openssl, ) from ...doubles import ( - DummyAsymmetricPadding, DummyHashAlgorithm, DummyKeySerializationEncryption + DummyAsymmetricPadding, + DummyHashAlgorithm, + DummyKeySerializationEncryption, ) from ...utils import ( - load_nist_vectors, load_pkcs1_vectors, load_rsa_nist_vectors, - load_vectors_from_file, raises_unsupported_algorithm + load_nist_vectors, + load_pkcs1_vectors, + load_rsa_nist_vectors, + load_vectors_from_file, + raises_unsupported_algorithm, ) @@ -89,11 +115,9 @@ def _build_oaep_sha2_vectors(): load_vectors_from_file( os.path.join( base_path, - "oaep-{0}-{1}.txt".format( - mgf1alg.name, oaepalg.name - ) + "oaep-{}-{}.txt".format(mgf1alg.name, oaepalg.name), ), - load_pkcs1_vectors + load_pkcs1_vectors, ) ) # We've loaded the files, but the loaders don't give us any information @@ -107,12 +131,11 @@ def _build_oaep_sha2_vectors(): def _skip_pss_hash_algorithm_unsupported(backend, hash_alg): if not backend.rsa_padding_supported( padding.PSS( - mgf=padding.MGF1(hash_alg), - salt_length=padding.PSS.MAX_LENGTH + mgf=padding.MGF1(hash_alg), salt_length=padding.PSS.MAX_LENGTH ) ): pytest.skip( - "Does not support {0} in MGF1 using PSS.".format(hash_alg.name) + "Does not support {} in MGF1 using PSS.".format(hash_alg.name) ) @@ -127,19 +150,22 @@ def test_modular_inverse(): "d1f9f6c09fd3d38987f7970247b85a6da84907753d42ec52bc23b745093f4fff5cff3" "617ce43d00121a9accc0051f519c76e08cf02fc18acfe4c9e6aea18da470a2b611d2e" "56a7b35caa2c0239bc041a53cc5875ca0b668ae6377d4b23e932d8c995fd1e58ecfd8" - "c4b73259c0d8a54d691cca3f6fb85c8a5c1baf588e898d481", 16 + "c4b73259c0d8a54d691cca3f6fb85c8a5c1baf588e898d481", + 16, ) q = int( "d1519255eb8f678c86cfd06802d1fbef8b664441ac46b73d33d13a8404580a33a8e74" "cb2ea2e2963125b3d454d7a922cef24dd13e55f989cbabf64255a736671f4629a47b5" "b2347cfcd669133088d1c159518531025297c2d67c9da856a12e80222cd03b4c6ec0f" - "86c957cb7bb8de7a127b645ec9e820aa94581e4762e209f01", 16 + "86c957cb7bb8de7a127b645ec9e820aa94581e4762e209f01", + 16, ) assert rsa._modinv(q, p) == int( "0275e06afa722999315f8f322275483e15e2fb46d827b17800f99110b269a6732748f" "624a382fa2ed1ec68c99f7fc56fb60e76eea51614881f497ba7034c17dde955f92f15" "772f8b2b41f3e56d88b1e096cdd293eba4eae1e82db815e0fadea0c4ec971bc6fd875" - "c20e67e48c31a611e98d32c6213ae4c4d7b53023b2f80c538", 16 + "c20e67e48c31a611e98d32c6213ae4c4d7b53023b2f80c538", + 16, ) @@ -148,11 +174,18 @@ class TestRSA(object): @pytest.mark.parametrize( ("public_exponent", "key_size"), itertools.product( - (3, 5, 65537), - (1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1536, 2048) - ) + (3, 65537), + (1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1536, 2048), + ), ) def test_generate_rsa_keys(self, backend, public_exponent, key_size): + if backend._fips_enabled: + if key_size < backend._fips_rsa_min_key_size: + pytest.skip("Key size not FIPS compliant: {}".format(key_size)) + if public_exponent < backend._fips_rsa_min_public_exponent: + pytest.skip( + "Exponent not FIPS compliant: {}".format(public_exponent) + ) skey = rsa.generate_private_key(public_exponent, key_size, backend) assert skey.key_size == key_size @@ -162,33 +195,39 @@ def test_generate_rsa_keys(self, backend, public_exponent, key_size): def test_generate_bad_public_exponent(self, backend): with pytest.raises(ValueError): - rsa.generate_private_key(public_exponent=1, - key_size=2048, - backend=backend) + rsa.generate_private_key( + public_exponent=1, key_size=2048, backend=backend + ) with pytest.raises(ValueError): - rsa.generate_private_key(public_exponent=4, - key_size=2048, - backend=backend) + rsa.generate_private_key( + public_exponent=4, key_size=2048, backend=backend + ) + + with pytest.raises(ValueError): + rsa.generate_private_key( + public_exponent=65535, key_size=2048, backend=backend + ) def test_cant_generate_insecure_tiny_key(self, backend): with pytest.raises(ValueError): - rsa.generate_private_key(public_exponent=65537, - key_size=511, - backend=backend) + rsa.generate_private_key( + public_exponent=65537, key_size=511, backend=backend + ) with pytest.raises(ValueError): - rsa.generate_private_key(public_exponent=65537, - key_size=256, - backend=backend) + rsa.generate_private_key( + public_exponent=65537, key_size=256, backend=backend + ) @pytest.mark.parametrize( "pkcs1_example", load_vectors_from_file( os.path.join( - "asymmetric", "RSA", "pkcs-1v2-1d2-vec", "pss-vect.txt"), - load_pkcs1_vectors - ) + "asymmetric", "RSA", "pkcs-1v2-1d2-vec", "pss-vect.txt" + ), + load_pkcs1_vectors, + ), ) def test_load_pss_vect_example_keys(self, pkcs1_example): secret, public = pkcs1_example @@ -201,15 +240,13 @@ def test_load_pss_vect_example_keys(self, pkcs1_example): dmq1=secret["dmq1"], iqmp=secret["iqmp"], public_numbers=rsa.RSAPublicNumbers( - e=secret["public_exponent"], - n=secret["modulus"] - ) + e=secret["public_exponent"], n=secret["modulus"] + ), ) _check_rsa_private_numbers(private_num) public_num = rsa.RSAPublicNumbers( - e=public["public_exponent"], - n=public["modulus"] + e=public["public_exponent"], n=public["modulus"] ) assert public_num @@ -223,17 +260,18 @@ def test_load_pss_vect_example_keys(self, pkcs1_example): "vector", load_vectors_from_file( os.path.join("asymmetric", "RSA", "oaep-label.txt"), - load_nist_vectors) + load_nist_vectors, + ), ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), - label=b"label" + label=b"label", ) ), - skip_message="Does not support RSA OAEP labels" + skip_message="Does not support RSA OAEP labels", ) def test_oaep_label_decrypt(self, vector, backend): private_key = serialization.load_der_private_key( @@ -245,8 +283,8 @@ def test_oaep_label_decrypt(self, vector, backend): padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA512()), algorithm=hashes.SHA512(), - label=binascii.unhexlify(vector["oaeplabel"]) - ) + label=binascii.unhexlify(vector["oaeplabel"]), + ), ) assert vector["output"][1:-1] == decrypted @@ -255,17 +293,17 @@ def test_oaep_label_decrypt(self, vector, backend): [ (b"amazing encrypted msg", b"some label"), (b"amazing encrypted msg", b""), - ] + ], ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), - label=b"label" + label=b"label", ) ), - skip_message="Does not support RSA OAEP labels" + skip_message="Does not support RSA OAEP labels", ) def test_oaep_label_roundtrip(self, msg, label, backend): private_key = RSA_KEY_2048.private_key(backend) @@ -274,54 +312,52 @@ def test_oaep_label_roundtrip(self, msg, label, backend): padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), - label=label - ) + label=label, + ), ) pt = private_key.decrypt( ct, padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), - label=label - ) + label=label, + ), ) assert pt == msg @pytest.mark.parametrize( ("enclabel", "declabel"), - [ - (b"label1", b"label2"), - (b"label3", b""), - (b"", b"label4"), - ] + [(b"label1", b"label2"), (b"label3", b""), (b"", b"label4")], ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), - label=b"label" + label=b"label", ) ), - skip_message="Does not support RSA OAEP labels" + skip_message="Does not support RSA OAEP labels", ) def test_oaep_wrong_label(self, enclabel, declabel, backend): private_key = RSA_KEY_2048.private_key(backend) msg = b"test" ct = private_key.public_key().encrypt( - msg, padding.OAEP( + msg, + padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), - label=enclabel - ) + label=enclabel, + ), ) with pytest.raises(ValueError): private_key.decrypt( - ct, padding.OAEP( + ct, + padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), - label=declabel - ) + label=declabel, + ), ) @pytest.mark.supported( @@ -329,10 +365,10 @@ def test_oaep_wrong_label(self, enclabel, declabel, backend): padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), - label=b"label" + label=b"label", ) ), - skip_message="Requires backend without RSA OAEP label support" + skip_message="Requires backend without RSA OAEP label support", ) def test_unsupported_oaep_label_decrypt(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -342,8 +378,8 @@ def test_unsupported_oaep_label_decrypt(self, backend): padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), - label=b"label" - ) + label=b"label", + ), ) @@ -360,15 +396,16 @@ class TestRSASignature(object): only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) @pytest.mark.parametrize( "pkcs1_example", - _flatten_pkcs1_examples(load_vectors_from_file( - os.path.join( - "asymmetric", "RSA", "pkcs1v15sign-vectors.txt"), - load_pkcs1_vectors - )) + _flatten_pkcs1_examples( + load_vectors_from_file( + os.path.join("asymmetric", "RSA", "pkcs1v15sign-vectors.txt"), + load_pkcs1_vectors, + ) + ), ) def test_pkcs1v15_signing(self, pkcs1_example, backend): private, public, example = pkcs1_example @@ -380,14 +417,13 @@ def test_pkcs1v15_signing(self, pkcs1_example, backend): dmq1=private["dmq1"], iqmp=private["iqmp"], public_numbers=rsa.RSAPublicNumbers( - e=private["public_exponent"], - n=private["modulus"] - ) + e=private["public_exponent"], n=private["modulus"] + ), ).private_key(backend) signature = private_key.sign( binascii.unhexlify(example["message"]), padding.PKCS1v15(), - hashes.SHA1() + hashes.SHA1(), ) assert binascii.hexlify(signature) == example["signature"] @@ -395,18 +431,21 @@ def test_pkcs1v15_signing(self, pkcs1_example, backend): only_if=lambda backend: backend.rsa_padding_supported( padding.PSS( mgf=padding.MGF1(hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ) ), - skip_message="Does not support PSS." + skip_message="Does not support PSS.", ) @pytest.mark.parametrize( "pkcs1_example", - _flatten_pkcs1_examples(load_vectors_from_file( - os.path.join( - "asymmetric", "RSA", "pkcs-1v2-1d2-vec", "pss-vect.txt"), - load_pkcs1_vectors - )) + _flatten_pkcs1_examples( + load_vectors_from_file( + os.path.join( + "asymmetric", "RSA", "pkcs-1v2-1d2-vec", "pss-vect.txt" + ), + load_pkcs1_vectors, + ) + ), ) def test_pss_signing(self, pkcs1_example, backend): private, public, example = pkcs1_example @@ -418,23 +457,21 @@ def test_pss_signing(self, pkcs1_example, backend): dmq1=private["dmq1"], iqmp=private["iqmp"], public_numbers=rsa.RSAPublicNumbers( - e=private["public_exponent"], - n=private["modulus"] - ) + e=private["public_exponent"], n=private["modulus"] + ), ).private_key(backend) public_key = rsa.RSAPublicNumbers( - e=public["public_exponent"], - n=public["modulus"] + e=public["public_exponent"], n=public["modulus"] ).public_key(backend) signature = private_key.sign( binascii.unhexlify(example["message"]), padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ), - hashes.SHA1() + hashes.SHA1(), ) - assert len(signature) == math.ceil(private_key.key_size / 8.0) + assert len(signature) == (private_key.key_size + 7) // 8 # PSS signatures contain randomness so we can't do an exact # signature check. Instead we'll verify that the signature created # successfully verifies. @@ -443,22 +480,21 @@ def test_pss_signing(self, pkcs1_example, backend): binascii.unhexlify(example["message"]), padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ), hashes.SHA1(), ) @pytest.mark.parametrize( "hash_alg", - [hashes.SHA224(), hashes.SHA256(), hashes.SHA384(), hashes.SHA512()] + [hashes.SHA224(), hashes.SHA256(), hashes.SHA384(), hashes.SHA512()], ) def test_pss_signing_sha2(self, hash_alg, backend): _skip_pss_hash_algorithm_unsupported(backend, hash_alg) private_key = RSA_KEY_768.private_key(backend) public_key = private_key.public_key() pss = padding.PSS( - mgf=padding.MGF1(hash_alg), - salt_length=padding.PSS.MAX_LENGTH + mgf=padding.MGF1(hash_alg), salt_length=padding.PSS.MAX_LENGTH ) msg = b"testing signature" signature = private_key.sign(msg, pss, hash_alg) @@ -466,15 +502,15 @@ def test_pss_signing_sha2(self, hash_alg, backend): @pytest.mark.supported( only_if=lambda backend: ( - backend.hash_supported(hashes.SHA512()) and - backend.rsa_padding_supported( + backend.hash_supported(hashes.SHA512()) + and backend.rsa_padding_supported( padding.PSS( mgf=padding.MGF1(hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ) ) ), - skip_message="Does not support SHA512." + skip_message="Does not support SHA512.", ) def test_pss_minimum_key_size_for_digest(self, backend): private_key = RSA_KEY_522.private_key(backend) @@ -482,23 +518,23 @@ def test_pss_minimum_key_size_for_digest(self, backend): b"no failure", padding.PSS( mgf=padding.MGF1(hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ), - hashes.SHA512() + hashes.SHA512(), ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PSS( mgf=padding.MGF1(hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ) ), - skip_message="Does not support PSS." + skip_message="Does not support PSS.", ) @pytest.mark.supported( only_if=lambda backend: backend.hash_supported(hashes.SHA512()), - skip_message="Does not support SHA512." + skip_message="Does not support SHA512.", ) def test_pss_signing_digest_too_large_for_key_size(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -507,19 +543,19 @@ def test_pss_signing_digest_too_large_for_key_size(self, backend): b"msg", padding.PSS( mgf=padding.MGF1(hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ), - hashes.SHA512() + hashes.SHA512(), ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PSS( mgf=padding.MGF1(hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ) ), - skip_message="Does not support PSS." + skip_message="Does not support PSS.", ) def test_pss_signing_salt_length_too_long(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -527,17 +563,16 @@ def test_pss_signing_salt_length_too_long(self, backend): private_key.sign( b"failure coming", padding.PSS( - mgf=padding.MGF1(hashes.SHA1()), - salt_length=1000000 + mgf=padding.MGF1(hashes.SHA1()), salt_length=1000000 ), - hashes.SHA1() + hashes.SHA1(), ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) def test_use_after_finalize(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -564,7 +599,7 @@ def test_padding_incorrect_type(self, backend): only_if=lambda backend: backend.rsa_padding_supported( padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0) ), - skip_message="Does not support PSS." + skip_message="Does not support PSS.", ) def test_unsupported_pss_mgf(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -572,40 +607,33 @@ def test_unsupported_pss_mgf(self, backend): private_key.sign( b"msg", padding.PSS( - mgf=DummyMGF(), - salt_length=padding.PSS.MAX_LENGTH + mgf=DummyMGF(), salt_length=padding.PSS.MAX_LENGTH ), - hashes.SHA1() + hashes.SHA1(), ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) def test_pkcs1_digest_too_large_for_key_size(self, backend): private_key = RSA_KEY_599.private_key(backend) with pytest.raises(ValueError): private_key.sign( - b"failure coming", - padding.PKCS1v15(), - hashes.SHA512() + b"failure coming", padding.PKCS1v15(), hashes.SHA512() ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) def test_pkcs1_minimum_key_size(self, backend): private_key = RSA_KEY_745.private_key(backend) - private_key.sign( - b"no failure", - padding.PKCS1v15(), - hashes.SHA512() - ) + private_key.sign(b"no failure", padding.PKCS1v15(), hashes.SHA512()) def test_sign(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -620,7 +648,7 @@ def test_sign(self, backend): only_if=lambda backend: backend.rsa_padding_supported( padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0) ), - skip_message="Does not support PSS." + skip_message="Does not support PSS.", ) def test_prehashed_sign(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -636,14 +664,15 @@ def test_prehashed_sign(self, backend): @pytest.mark.supported( only_if=lambda backend: backend.hash_supported( - hashes.BLAKE2s(digest_size=32)), + hashes.BLAKE2s(digest_size=32) + ), skip_message="Does not support BLAKE2s", ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0) ), - skip_message="Does not support PSS." + skip_message="Does not support PSS.", ) def test_unsupported_hash(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -656,7 +685,7 @@ def test_unsupported_hash(self, backend): only_if=lambda backend: backend.rsa_padding_supported( padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0) ), - skip_message="Does not support PSS." + skip_message="Does not support PSS.", ) def test_prehashed_digest_mismatch(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -673,31 +702,38 @@ def test_prehashed_digest_mismatch(self, backend): only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) def test_prehashed_unsupported_in_signer_ctx(self, backend): private_key = RSA_KEY_512.private_key(backend) - with pytest.raises(TypeError), \ - pytest.warns(CryptographyDeprecationWarning): + with pytest.raises(TypeError), pytest.warns( + CryptographyDeprecationWarning + ): private_key.signer( - padding.PKCS1v15(), - asym_utils.Prehashed(hashes.SHA1()) + padding.PKCS1v15(), asym_utils.Prehashed(hashes.SHA1()) ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) def test_prehashed_unsupported_in_verifier_ctx(self, backend): public_key = RSA_KEY_512.private_key(backend).public_key() - with pytest.raises(TypeError), \ - pytest.warns(CryptographyDeprecationWarning): + with pytest.raises(TypeError), pytest.warns( + CryptographyDeprecationWarning + ): public_key.verifier( b"0" * 64, padding.PKCS1v15(), - asym_utils.Prehashed(hashes.SHA1()) + asym_utils.Prehashed(hashes.SHA1()), + ) + + def test_corrupted_private_key(self, backend): + with pytest.raises(ValueError): + serialization.load_pem_private_key( + RSA_KEY_CORRUPTED, password=None, backend=backend ) @@ -707,34 +743,34 @@ class TestRSAVerification(object): only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) @pytest.mark.parametrize( "pkcs1_example", - _flatten_pkcs1_examples(load_vectors_from_file( - os.path.join( - "asymmetric", "RSA", "pkcs1v15sign-vectors.txt"), - load_pkcs1_vectors - )) + _flatten_pkcs1_examples( + load_vectors_from_file( + os.path.join("asymmetric", "RSA", "pkcs1v15sign-vectors.txt"), + load_pkcs1_vectors, + ) + ), ) def test_pkcs1v15_verification(self, pkcs1_example, backend): private, public, example = pkcs1_example public_key = rsa.RSAPublicNumbers( - e=public["public_exponent"], - n=public["modulus"] + e=public["public_exponent"], n=public["modulus"] ).public_key(backend) public_key.verify( binascii.unhexlify(example["signature"]), binascii.unhexlify(example["message"]), padding.PKCS1v15(), - hashes.SHA1() + hashes.SHA1(), ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) def test_invalid_pkcs1v15_signature_wrong_data(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -744,10 +780,7 @@ def test_invalid_pkcs1v15_signature_wrong_data(self, backend): ) with pytest.raises(InvalidSignature): public_key.verify( - signature, - b"incorrect data", - padding.PKCS1v15(), - hashes.SHA1() + signature, b"incorrect data", padding.PKCS1v15(), hashes.SHA1() ) def test_invalid_signature_sequence_removed(self, backend): @@ -782,14 +815,14 @@ def test_invalid_signature_sequence_removed(self, backend): sig, binascii.unhexlify(b"313233343030"), padding.PKCS1v15(), - hashes.SHA256() + hashes.SHA256(), ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) def test_invalid_pkcs1v15_signature_wrong_key(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -804,54 +837,53 @@ def test_invalid_pkcs1v15_signature_wrong_key(self, backend): @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( - padding.PSS( - mgf=padding.MGF1(hashes.SHA1()), - salt_length=20 - ) + padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=20) ), - skip_message="Does not support PSS." + skip_message="Does not support PSS.", ) @pytest.mark.parametrize( "pkcs1_example", - _flatten_pkcs1_examples(load_vectors_from_file( - os.path.join( - "asymmetric", "RSA", "pkcs-1v2-1d2-vec", "pss-vect.txt"), - load_pkcs1_vectors - )) + _flatten_pkcs1_examples( + load_vectors_from_file( + os.path.join( + "asymmetric", "RSA", "pkcs-1v2-1d2-vec", "pss-vect.txt" + ), + load_pkcs1_vectors, + ) + ), ) def test_pss_verification(self, pkcs1_example, backend): private, public, example = pkcs1_example public_key = rsa.RSAPublicNumbers( - e=public["public_exponent"], - n=public["modulus"] + e=public["public_exponent"], n=public["modulus"] ).public_key(backend) public_key.verify( binascii.unhexlify(example["signature"]), binascii.unhexlify(example["message"]), padding.PSS( - mgf=padding.MGF1(algorithm=hashes.SHA1()), - salt_length=20 + mgf=padding.MGF1(algorithm=hashes.SHA1()), salt_length=20 ), - hashes.SHA1() + hashes.SHA1(), ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PSS( mgf=padding.MGF1(hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ) ), - skip_message="Does not support PSS." + skip_message="Does not support PSS.", ) def test_invalid_pss_signature_wrong_data(self, backend): public_key = rsa.RSAPublicNumbers( n=int( b"dffc2137d5e810cde9e4b4612f5796447218bab913b3fa98bdf7982e4fa6" b"ec4d6653ef2b29fb1642b095befcbea6decc178fb4bed243d3c3592c6854" - b"6af2d3f3", 16 + b"6af2d3f3", + 16, ), - e=65537 + e=65537, ).public_key(backend) signature = binascii.unhexlify( b"0e68c3649df91c5bc3665f96e157efa75b71934aaa514d91e94ca8418d100f45" @@ -863,19 +895,19 @@ def test_invalid_pss_signature_wrong_data(self, backend): b"incorrect data", padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ), - hashes.SHA1() + hashes.SHA1(), ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PSS( mgf=padding.MGF1(hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ) ), - skip_message="Does not support PSS." + skip_message="Does not support PSS.", ) def test_invalid_pss_signature_wrong_key(self, backend): signature = binascii.unhexlify( @@ -888,9 +920,10 @@ def test_invalid_pss_signature_wrong_key(self, backend): b"5a95441be90866a14c4d2e139cd16db540ec6c7abab13ffff91443fd46a8" b"960cbb7658ded26a5c95c86f6e40384e1c1239c63e541ba221191c4dd303" b"231b42e33c6dbddf5ec9a746f09bf0c25d0f8d27f93ee0ae5c0d723348f4" - b"030d3581e13522e1", 16 + b"030d3581e13522e1", + 16, ), - e=65537 + e=65537, ).public_key(backend) with pytest.raises(InvalidSignature): public_key.verify( @@ -898,51 +931,50 @@ def test_invalid_pss_signature_wrong_key(self, backend): b"sign me", padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ), - hashes.SHA1() + hashes.SHA1(), ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PSS( mgf=padding.MGF1(hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ) ), - skip_message="Does not support PSS." + skip_message="Does not support PSS.", ) def test_invalid_pss_signature_data_too_large_for_modulus(self, backend): + # 2048 bit PSS signature signature = binascii.unhexlify( - b"cb43bde4f7ab89eb4a79c6e8dd67e0d1af60715da64429d90c716a490b799c29" - b"194cf8046509c6ed851052367a74e2e92d9b38947ed74332acb115a03fcc0222" - ) - public_key = rsa.RSAPublicNumbers( - n=int( - b"381201f4905d67dfeb3dec131a0fbea773489227ec7a1448c3109189ac68" - b"5a95441be90866a14c4d2e139cd16db540ec6c7abab13ffff91443fd46a8" - b"960cbb7658ded26a5c95c86f6e40384e1c1239c63e541ba221191c4dd303" - b"231b42e33c6dbddf5ec9a746f09bf0c25d0f8d27f93ee0ae5c0d723348f4" - b"030d3581e13522", 16 - ), - e=65537 - ).public_key(backend) + b"58750fc3d2f560d1f3e37c8e28bc8da6d3e93f5d58f8becd25b1c931eea30fea" + b"54cb17d44b90104a0aacb7fe9ffa2a59c5788435911d63de78178d21eb875ccd" + b"0b07121b641ed4fe6bcb1ca5060322765507b4f24bdba8a698a8e4e07e6bf2c4" + b"7a736abe5a912e85cd32f648f3e043b4385e8b612dcce342c5fddf18c524deb5" + b"6295b95f6dfa759b2896b793628a90f133e74c1ff7d3af43e3f7ee792df2e5b6" + b"a19e996ac3676884354899a437b3ae4e3ac91976c336c332a3b1db0d172b19cb" + b"40ad3d871296cfffb3c889ce74a179a3e290852c35d59525afe4b39dc907fad2" + b"ac462c50a488dca486031a3dc8c4cdbbc53e9f71d64732e1533a5d1249b833ce" + ) + # 1024 bit key + public_key = RSA_KEY_1024.private_key(backend).public_key() with pytest.raises(InvalidSignature): public_key.verify( signature, b"sign me", padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ), - hashes.SHA1() + hashes.SHA1(), ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) def test_use_after_finalize(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -953,9 +985,7 @@ def test_use_after_finalize(self, backend): with pytest.warns(CryptographyDeprecationWarning): verifier = public_key.verifier( - signature, - padding.PKCS1v15(), - hashes.SHA1() + signature, padding.PKCS1v15(), hashes.SHA1() ) verifier.update(b"sign me") verifier.verify() @@ -976,19 +1006,16 @@ def test_unsupported_padding(self, backend): only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) def test_signature_not_bytes(self, backend): public_key = RSA_KEY_512.public_numbers.public_key(backend) signature = 1234 - with pytest.raises(TypeError), \ - pytest.warns(CryptographyDeprecationWarning): - public_key.verifier( - signature, - padding.PKCS1v15(), - hashes.SHA1() - ) + with pytest.raises(TypeError), pytest.warns( + CryptographyDeprecationWarning + ): + public_key.verifier(signature, padding.PKCS1v15(), hashes.SHA1()) def test_padding_incorrect_type(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -1000,7 +1027,7 @@ def test_padding_incorrect_type(self, backend): only_if=lambda backend: backend.rsa_padding_supported( padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=0) ), - skip_message="Does not support PSS." + skip_message="Does not support PSS.", ) def test_unsupported_pss_mgf(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -1010,24 +1037,23 @@ def test_unsupported_pss_mgf(self, backend): b"sig", b"msg", padding.PSS( - mgf=DummyMGF(), - salt_length=padding.PSS.MAX_LENGTH + mgf=DummyMGF(), salt_length=padding.PSS.MAX_LENGTH ), - hashes.SHA1() + hashes.SHA1(), ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PSS( mgf=padding.MGF1(hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ) ), - skip_message="Does not support PSS." + skip_message="Does not support PSS.", ) @pytest.mark.supported( only_if=lambda backend: backend.hash_supported(hashes.SHA512()), - skip_message="Does not support SHA512." + skip_message="Does not support SHA512.", ) def test_pss_verify_digest_too_large_for_key_size(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -1042,19 +1068,19 @@ def test_pss_verify_digest_too_large_for_key_size(self, backend): b"msg doesn't matter", padding.PSS( mgf=padding.MGF1(algorithm=hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ), - hashes.SHA512() + hashes.SHA512(), ) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PSS( mgf=padding.MGF1(hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ) ), - skip_message="Does not support PSS." + skip_message="Does not support PSS.", ) def test_pss_verify_salt_length_too_long(self, backend): signature = binascii.unhexlify( @@ -1065,9 +1091,10 @@ def test_pss_verify_salt_length_too_long(self, backend): n=int( b"d309e4612809437548b747d7f9eb9cd3340f54fe42bb3f84a36933b0839c" b"11b0c8b7f67e11f7252370161e31159c49c784d4bc41c42a78ce0f0b40a3" - b"ca8ffb91", 16 + b"ca8ffb91", + 16, ), - e=65537 + e=65537, ).public_key(backend) with pytest.raises(InvalidSignature): public_key.verify( @@ -1077,9 +1104,9 @@ def test_pss_verify_salt_length_too_long(self, backend): mgf=padding.MGF1( algorithm=hashes.SHA1(), ), - salt_length=1000000 + salt_length=1000000, ), - hashes.SHA1() + hashes.SHA1(), ) def test_verify(self, backend): @@ -1121,219 +1148,239 @@ class TestRSAPSSMGF1Verification(object): only_if=lambda backend: backend.rsa_padding_supported( padding.PSS( mgf=padding.MGF1(hashes.SHA1()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ) ), - skip_message="Does not support PSS using MGF1 with SHA1." - )(generate_rsa_verification_test( - load_rsa_nist_vectors, - os.path.join("asymmetric", "RSA", "FIPS_186-2"), - [ - "SigGenPSS_186-2.rsp", - "SigGenPSS_186-3.rsp", - "SigVerPSS_186-3.rsp", - ], - hashes.SHA1(), - lambda params, hash_alg: padding.PSS( - mgf=padding.MGF1( - algorithm=hash_alg, + skip_message="Does not support PSS using MGF1 with SHA1.", + )( + generate_rsa_verification_test( + load_rsa_nist_vectors, + os.path.join("asymmetric", "RSA", "FIPS_186-2"), + [ + "SigGenPSS_186-2.rsp", + "SigGenPSS_186-3.rsp", + "SigVerPSS_186-3.rsp", + ], + hashes.SHA1(), + lambda params, hash_alg: padding.PSS( + mgf=padding.MGF1( + algorithm=hash_alg, + ), + salt_length=params["salt_length"], ), - salt_length=params["salt_length"] ) - )) + ) test_rsa_pss_mgf1_sha224 = pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PSS( mgf=padding.MGF1(hashes.SHA224()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ) ), - skip_message="Does not support PSS using MGF1 with SHA224." - )(generate_rsa_verification_test( - load_rsa_nist_vectors, - os.path.join("asymmetric", "RSA", "FIPS_186-2"), - [ - "SigGenPSS_186-2.rsp", - "SigGenPSS_186-3.rsp", - "SigVerPSS_186-3.rsp", - ], - hashes.SHA224(), - lambda params, hash_alg: padding.PSS( - mgf=padding.MGF1( - algorithm=hash_alg, + skip_message="Does not support PSS using MGF1 with SHA224.", + )( + generate_rsa_verification_test( + load_rsa_nist_vectors, + os.path.join("asymmetric", "RSA", "FIPS_186-2"), + [ + "SigGenPSS_186-2.rsp", + "SigGenPSS_186-3.rsp", + "SigVerPSS_186-3.rsp", + ], + hashes.SHA224(), + lambda params, hash_alg: padding.PSS( + mgf=padding.MGF1( + algorithm=hash_alg, + ), + salt_length=params["salt_length"], ), - salt_length=params["salt_length"] ) - )) + ) test_rsa_pss_mgf1_sha256 = pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PSS( mgf=padding.MGF1(hashes.SHA256()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ) ), - skip_message="Does not support PSS using MGF1 with SHA256." - )(generate_rsa_verification_test( - load_rsa_nist_vectors, - os.path.join("asymmetric", "RSA", "FIPS_186-2"), - [ - "SigGenPSS_186-2.rsp", - "SigGenPSS_186-3.rsp", - "SigVerPSS_186-3.rsp", - ], - hashes.SHA256(), - lambda params, hash_alg: padding.PSS( - mgf=padding.MGF1( - algorithm=hash_alg, + skip_message="Does not support PSS using MGF1 with SHA256.", + )( + generate_rsa_verification_test( + load_rsa_nist_vectors, + os.path.join("asymmetric", "RSA", "FIPS_186-2"), + [ + "SigGenPSS_186-2.rsp", + "SigGenPSS_186-3.rsp", + "SigVerPSS_186-3.rsp", + ], + hashes.SHA256(), + lambda params, hash_alg: padding.PSS( + mgf=padding.MGF1( + algorithm=hash_alg, + ), + salt_length=params["salt_length"], ), - salt_length=params["salt_length"] ) - )) + ) test_rsa_pss_mgf1_sha384 = pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PSS( mgf=padding.MGF1(hashes.SHA384()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ) ), - skip_message="Does not support PSS using MGF1 with SHA384." - )(generate_rsa_verification_test( - load_rsa_nist_vectors, - os.path.join("asymmetric", "RSA", "FIPS_186-2"), - [ - "SigGenPSS_186-2.rsp", - "SigGenPSS_186-3.rsp", - "SigVerPSS_186-3.rsp", - ], - hashes.SHA384(), - lambda params, hash_alg: padding.PSS( - mgf=padding.MGF1( - algorithm=hash_alg, + skip_message="Does not support PSS using MGF1 with SHA384.", + )( + generate_rsa_verification_test( + load_rsa_nist_vectors, + os.path.join("asymmetric", "RSA", "FIPS_186-2"), + [ + "SigGenPSS_186-2.rsp", + "SigGenPSS_186-3.rsp", + "SigVerPSS_186-3.rsp", + ], + hashes.SHA384(), + lambda params, hash_alg: padding.PSS( + mgf=padding.MGF1( + algorithm=hash_alg, + ), + salt_length=params["salt_length"], ), - salt_length=params["salt_length"] ) - )) + ) test_rsa_pss_mgf1_sha512 = pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PSS( mgf=padding.MGF1(hashes.SHA512()), - salt_length=padding.PSS.MAX_LENGTH + salt_length=padding.PSS.MAX_LENGTH, ) ), - skip_message="Does not support PSS using MGF1 with SHA512." - )(generate_rsa_verification_test( - load_rsa_nist_vectors, - os.path.join("asymmetric", "RSA", "FIPS_186-2"), - [ - "SigGenPSS_186-2.rsp", - "SigGenPSS_186-3.rsp", - "SigVerPSS_186-3.rsp", - ], - hashes.SHA512(), - lambda params, hash_alg: padding.PSS( - mgf=padding.MGF1( - algorithm=hash_alg, + skip_message="Does not support PSS using MGF1 with SHA512.", + )( + generate_rsa_verification_test( + load_rsa_nist_vectors, + os.path.join("asymmetric", "RSA", "FIPS_186-2"), + [ + "SigGenPSS_186-2.rsp", + "SigGenPSS_186-3.rsp", + "SigVerPSS_186-3.rsp", + ], + hashes.SHA512(), + lambda params, hash_alg: padding.PSS( + mgf=padding.MGF1( + algorithm=hash_alg, + ), + salt_length=params["salt_length"], ), - salt_length=params["salt_length"] ) - )) + ) @pytest.mark.requires_backend_interface(interface=RSABackend) class TestRSAPKCS1Verification(object): test_rsa_pkcs1v15_verify_sha1 = pytest.mark.supported( only_if=lambda backend: ( - backend.hash_supported(hashes.SHA1()) and - backend.rsa_padding_supported(padding.PKCS1v15()) + backend.hash_supported(hashes.SHA1()) + and backend.rsa_padding_supported(padding.PKCS1v15()) ), - skip_message="Does not support SHA1 and PKCS1v1.5." - )(generate_rsa_verification_test( - load_rsa_nist_vectors, - os.path.join("asymmetric", "RSA", "FIPS_186-2"), - [ - "SigGen15_186-2.rsp", - "SigGen15_186-3.rsp", - "SigVer15_186-3.rsp", - ], - hashes.SHA1(), - lambda params, hash_alg: padding.PKCS1v15() - )) + skip_message="Does not support SHA1 and PKCS1v1.5.", + )( + generate_rsa_verification_test( + load_rsa_nist_vectors, + os.path.join("asymmetric", "RSA", "FIPS_186-2"), + [ + "SigGen15_186-2.rsp", + "SigGen15_186-3.rsp", + "SigVer15_186-3.rsp", + ], + hashes.SHA1(), + lambda params, hash_alg: padding.PKCS1v15(), + ) + ) test_rsa_pkcs1v15_verify_sha224 = pytest.mark.supported( only_if=lambda backend: ( - backend.hash_supported(hashes.SHA224()) and - backend.rsa_padding_supported(padding.PKCS1v15()) + backend.hash_supported(hashes.SHA224()) + and backend.rsa_padding_supported(padding.PKCS1v15()) ), - skip_message="Does not support SHA224 and PKCS1v1.5." - )(generate_rsa_verification_test( - load_rsa_nist_vectors, - os.path.join("asymmetric", "RSA", "FIPS_186-2"), - [ - "SigGen15_186-2.rsp", - "SigGen15_186-3.rsp", - "SigVer15_186-3.rsp", - ], - hashes.SHA224(), - lambda params, hash_alg: padding.PKCS1v15() - )) + skip_message="Does not support SHA224 and PKCS1v1.5.", + )( + generate_rsa_verification_test( + load_rsa_nist_vectors, + os.path.join("asymmetric", "RSA", "FIPS_186-2"), + [ + "SigGen15_186-2.rsp", + "SigGen15_186-3.rsp", + "SigVer15_186-3.rsp", + ], + hashes.SHA224(), + lambda params, hash_alg: padding.PKCS1v15(), + ) + ) test_rsa_pkcs1v15_verify_sha256 = pytest.mark.supported( only_if=lambda backend: ( - backend.hash_supported(hashes.SHA256()) and - backend.rsa_padding_supported(padding.PKCS1v15()) + backend.hash_supported(hashes.SHA256()) + and backend.rsa_padding_supported(padding.PKCS1v15()) ), - skip_message="Does not support SHA256 and PKCS1v1.5." - )(generate_rsa_verification_test( - load_rsa_nist_vectors, - os.path.join("asymmetric", "RSA", "FIPS_186-2"), - [ - "SigGen15_186-2.rsp", - "SigGen15_186-3.rsp", - "SigVer15_186-3.rsp", - ], - hashes.SHA256(), - lambda params, hash_alg: padding.PKCS1v15() - )) + skip_message="Does not support SHA256 and PKCS1v1.5.", + )( + generate_rsa_verification_test( + load_rsa_nist_vectors, + os.path.join("asymmetric", "RSA", "FIPS_186-2"), + [ + "SigGen15_186-2.rsp", + "SigGen15_186-3.rsp", + "SigVer15_186-3.rsp", + ], + hashes.SHA256(), + lambda params, hash_alg: padding.PKCS1v15(), + ) + ) test_rsa_pkcs1v15_verify_sha384 = pytest.mark.supported( only_if=lambda backend: ( - backend.hash_supported(hashes.SHA384()) and - backend.rsa_padding_supported(padding.PKCS1v15()) + backend.hash_supported(hashes.SHA384()) + and backend.rsa_padding_supported(padding.PKCS1v15()) ), - skip_message="Does not support SHA384 and PKCS1v1.5." - )(generate_rsa_verification_test( - load_rsa_nist_vectors, - os.path.join("asymmetric", "RSA", "FIPS_186-2"), - [ - "SigGen15_186-2.rsp", - "SigGen15_186-3.rsp", - "SigVer15_186-3.rsp", - ], - hashes.SHA384(), - lambda params, hash_alg: padding.PKCS1v15() - )) + skip_message="Does not support SHA384 and PKCS1v1.5.", + )( + generate_rsa_verification_test( + load_rsa_nist_vectors, + os.path.join("asymmetric", "RSA", "FIPS_186-2"), + [ + "SigGen15_186-2.rsp", + "SigGen15_186-3.rsp", + "SigVer15_186-3.rsp", + ], + hashes.SHA384(), + lambda params, hash_alg: padding.PKCS1v15(), + ) + ) test_rsa_pkcs1v15_verify_sha512 = pytest.mark.supported( only_if=lambda backend: ( - backend.hash_supported(hashes.SHA512()) and - backend.rsa_padding_supported(padding.PKCS1v15()) + backend.hash_supported(hashes.SHA512()) + and backend.rsa_padding_supported(padding.PKCS1v15()) ), - skip_message="Does not support SHA512 and PKCS1v1.5." - )(generate_rsa_verification_test( - load_rsa_nist_vectors, - os.path.join("asymmetric", "RSA", "FIPS_186-2"), - [ - "SigGen15_186-2.rsp", - "SigGen15_186-3.rsp", - "SigVer15_186-3.rsp", - ], - hashes.SHA512(), - lambda params, hash_alg: padding.PKCS1v15() - )) + skip_message="Does not support SHA512 and PKCS1v1.5.", + )( + generate_rsa_verification_test( + load_rsa_nist_vectors, + os.path.join("asymmetric", "RSA", "FIPS_186-2"), + [ + "SigGen15_186-2.rsp", + "SigGen15_186-3.rsp", + "SigVer15_186-3.rsp", + ], + hashes.SHA512(), + lambda params, hash_alg: padding.PKCS1v15(), + ) + ) class TestPSS(object): @@ -1344,20 +1391,12 @@ def test_calculate_max_pss_salt_length(self): def test_invalid_salt_length_not_integer(self): with pytest.raises(TypeError): padding.PSS( - mgf=padding.MGF1( - hashes.SHA1() - ), - salt_length=b"not_a_length" + mgf=padding.MGF1(hashes.SHA1()), salt_length=b"not_a_length" ) def test_invalid_salt_length_negative_integer(self): with pytest.raises(ValueError): - padding.PSS( - mgf=padding.MGF1( - hashes.SHA1() - ), - salt_length=-1 - ) + padding.PSS(mgf=padding.MGF1(hashes.SHA1()), salt_length=-1) def test_valid_pss_parameters(self): algorithm = hashes.SHA1() @@ -1390,11 +1429,7 @@ class TestOAEP(object): def test_invalid_algorithm(self): mgf = padding.MGF1(hashes.SHA1()) with pytest.raises(TypeError): - padding.OAEP( - mgf=mgf, - algorithm=b"", - label=None - ) + padding.OAEP(mgf=mgf, algorithm=b"", label=None) @pytest.mark.requires_backend_interface(interface=RSABackend) @@ -1403,15 +1438,16 @@ class TestRSADecryption(object): only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) @pytest.mark.parametrize( "vector", - _flatten_pkcs1_examples(load_vectors_from_file( - os.path.join( - "asymmetric", "RSA", "pkcs1v15crypt-vectors.txt"), - load_pkcs1_vectors - )) + _flatten_pkcs1_examples( + load_vectors_from_file( + os.path.join("asymmetric", "RSA", "pkcs1v15crypt-vectors.txt"), + load_pkcs1_vectors, + ) + ), ) def test_decrypt_pkcs1v15_vectors(self, vector, backend): private, public, example = vector @@ -1423,12 +1459,11 @@ def test_decrypt_pkcs1v15_vectors(self, vector, backend): dmq1=private["dmq1"], iqmp=private["iqmp"], public_numbers=rsa.RSAPublicNumbers( - e=private["public_exponent"], - n=private["modulus"] - ) + e=private["public_exponent"], n=private["modulus"] + ), ).private_key(backend) ciphertext = binascii.unhexlify(example["encryption"]) - assert len(ciphertext) == math.ceil(skey.key_size / 8.0) + assert len(ciphertext) == (skey.key_size + 7) // 8 message = skey.decrypt(ciphertext, padding.PKCS1v15()) assert message == binascii.unhexlify(example["message"]) @@ -1441,35 +1476,29 @@ def test_unsupported_padding(self, backend): only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) def test_decrypt_invalid_decrypt(self, backend): private_key = RSA_KEY_512.private_key(backend) with pytest.raises(ValueError): - private_key.decrypt( - b"\x00" * 64, - padding.PKCS1v15() - ) + private_key.decrypt(b"\x00" * 64, padding.PKCS1v15()) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) def test_decrypt_ciphertext_too_large(self, backend): private_key = RSA_KEY_512.private_key(backend) with pytest.raises(ValueError): - private_key.decrypt( - b"\x00" * 65, - padding.PKCS1v15() - ) + private_key.decrypt(b"\x00" * 65, padding.PKCS1v15()) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) def test_decrypt_ciphertext_too_small(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -1478,28 +1507,28 @@ def test_decrypt_ciphertext_too_small(self, backend): b"69d210f2b9bdfb48b12f9ea05009c77da257cc600ccefe3a6283789d8ea0" ) with pytest.raises(ValueError): - private_key.decrypt( - ct, - padding.PKCS1v15() - ) + private_key.decrypt(ct, padding.PKCS1v15()) @pytest.mark.supported( only_if=lambda backend: backend.rsa_padding_supported( padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), - label=None + label=None, ) ), - skip_message="Does not support OAEP." + skip_message="Does not support OAEP.", ) @pytest.mark.parametrize( "vector", - _flatten_pkcs1_examples(load_vectors_from_file( - os.path.join( - "asymmetric", "RSA", "pkcs-1v2-1d2-vec", "oaep-vect.txt"), - load_pkcs1_vectors - )) + _flatten_pkcs1_examples( + load_vectors_from_file( + os.path.join( + "asymmetric", "RSA", "pkcs-1v2-1d2-vec", "oaep-vect.txt" + ), + load_pkcs1_vectors, + ) + ), ) def test_decrypt_oaep_vectors(self, vector, backend): private, public, example = vector @@ -1511,17 +1540,16 @@ def test_decrypt_oaep_vectors(self, vector, backend): dmq1=private["dmq1"], iqmp=private["iqmp"], public_numbers=rsa.RSAPublicNumbers( - e=private["public_exponent"], - n=private["modulus"] - ) + e=private["public_exponent"], n=private["modulus"] + ), ).private_key(backend) message = skey.decrypt( binascii.unhexlify(example["encryption"]), padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), - label=None - ) + label=None, + ), ) assert message == binascii.unhexlify(example["message"]) @@ -1530,15 +1558,14 @@ def test_decrypt_oaep_vectors(self, vector, backend): padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA224()), algorithm=hashes.SHA224(), - label=None + label=None, ) ), - skip_message="Does not support OAEP using SHA224 MGF1 and SHA224 hash." - ) - @pytest.mark.parametrize( - "vector", - _build_oaep_sha2_vectors() + skip_message=( + "Does not support OAEP using SHA224 MGF1 and SHA224 hash." + ), ) + @pytest.mark.parametrize("vector", _build_oaep_sha2_vectors()) def test_decrypt_oaep_sha2_vectors(self, vector, backend): private, public, example, mgf1_alg, hash_alg = vector skey = rsa.RSAPrivateNumbers( @@ -1549,17 +1576,16 @@ def test_decrypt_oaep_sha2_vectors(self, vector, backend): dmq1=private["dmq1"], iqmp=private["iqmp"], public_numbers=rsa.RSAPublicNumbers( - e=private["public_exponent"], - n=private["modulus"] - ) + e=private["public_exponent"], n=private["modulus"] + ), ).private_key(backend) message = skey.decrypt( binascii.unhexlify(example["encryption"]), padding.OAEP( mgf=padding.MGF1(algorithm=mgf1_alg), algorithm=hash_alg, - label=None - ) + label=None, + ), ) assert message == binascii.unhexlify(example["message"]) @@ -1568,24 +1594,24 @@ def test_decrypt_oaep_sha2_vectors(self, vector, backend): padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), - label=None + label=None, ) ), - skip_message="Does not support OAEP." + skip_message="Does not support OAEP.", ) def test_invalid_oaep_decryption(self, backend): - # More recent versions of OpenSSL may raise RSA_R_OAEP_DECODING_ERROR - # This test triggers it and confirms that we properly handle it. Other - # backends should also return the proper ValueError. + # More recent versions of OpenSSL may raise different errors. + # This test triggers a failure and confirms that we properly handle + # it. private_key = RSA_KEY_512.private_key(backend) ciphertext = private_key.public_key().encrypt( - b'secure data', + b"secure data", padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), - label=None - ) + label=None, + ), ) private_key_alt = RSA_KEY_512_ALT.private_key(backend) @@ -1596,8 +1622,8 @@ def test_invalid_oaep_decryption(self, backend): padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), - label=None - ) + label=None, + ), ) @pytest.mark.supported( @@ -1605,27 +1631,27 @@ def test_invalid_oaep_decryption(self, backend): padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), - label=None + label=None, ) ), - skip_message="Does not support OAEP." + skip_message="Does not support OAEP.", ) def test_invalid_oaep_decryption_data_to_large_for_modulus(self, backend): key = RSA_KEY_2048_ALT.private_key(backend) ciphertext = ( - b'\xb1ph\xc0\x0b\x1a|\xe6\xda\xea\xb5\xd7%\x94\x07\xf96\xfb\x96' - b'\x11\x9b\xdc4\xea.-\x91\x80\x13S\x94\x04m\xe9\xc5/F\x1b\x9b:\\' - b'\x1d\x04\x16ML\xae\xb32J\x01yuA\xbb\x83\x1c\x8f\xf6\xa5\xdbp\xcd' - b'\nx\xc7\xf6\x15\xb2/\xdcH\xae\xe7\x13\x13by\r4t\x99\x0fc\x1f\xc1' - b'\x1c\xb1\xdd\xc5\x08\xd1\xee\xa1XQ\xb8H@L5v\xc3\xaf\xf2\r\x97' - b'\xed\xaa\xe7\xf1\xd4xai\xd3\x83\xd9\xaa9\xbfx\xe1\x87F \x01\xff' - b'L\xccv}ae\xb3\xfa\xf2B\xb8\xf9\x04H\x94\x85\xcb\x86\xbb\\ghx!W31' - b'\xc7;t\na_E\xc2\x16\xb0;\xa1\x18\t\x1b\xe1\xdb\x80>)\x15\xc6\x12' - b'\xcb\xeeg`\x8b\x9b\x1b\x05y4\xb0\x84M6\xcd\xa1\x827o\xfd\x96\xba' - b'Z#\x8d\xae\x01\xc9\xf2\xb6\xde\x89{8&eQ\x1e8\x03\x01#?\xb66\\' - b'\xad.\xe9\xfa!\x95 c{\xcaz\xe0*\tP\r\x91\x9a)B\xb5\xadN\xf4$\x83' - b'\t\xb5u\xab\x19\x99' + b"\xb1ph\xc0\x0b\x1a|\xe6\xda\xea\xb5\xd7%\x94\x07\xf96\xfb\x96" + b"\x11\x9b\xdc4\xea.-\x91\x80\x13S\x94\x04m\xe9\xc5/F\x1b\x9b:\\" + b"\x1d\x04\x16ML\xae\xb32J\x01yuA\xbb\x83\x1c\x8f\xf6\xa5\xdbp\xcd" + b"\nx\xc7\xf6\x15\xb2/\xdcH\xae\xe7\x13\x13by\r4t\x99\x0fc\x1f\xc1" + b"\x1c\xb1\xdd\xc5\x08\xd1\xee\xa1XQ\xb8H@L5v\xc3\xaf\xf2\r\x97" + b"\xed\xaa\xe7\xf1\xd4xai\xd3\x83\xd9\xaa9\xbfx\xe1\x87F \x01\xff" + b"L\xccv}ae\xb3\xfa\xf2B\xb8\xf9\x04H\x94\x85\xcb\x86\xbb\\ghx!W31" + b"\xc7;t\na_E\xc2\x16\xb0;\xa1\x18\t\x1b\xe1\xdb\x80>)\x15\xc6\x12" + b"\xcb\xeeg`\x8b\x9b\x1b\x05y4\xb0\x84M6\xcd\xa1\x827o\xfd\x96\xba" + b"Z#\x8d\xae\x01\xc9\xf2\xb6\xde\x89{8&eQ\x1e8\x03\x01#?\xb66\\" + b"\xad.\xe9\xfa!\x95 c{\xcaz\xe0*\tP\r\x91\x9a)B\xb5\xadN\xf4$\x83" + b"\t\xb5u\xab\x19\x99" ) with pytest.raises(ValueError): @@ -1634,8 +1660,8 @@ def test_invalid_oaep_decryption_data_to_large_for_modulus(self, backend): padding.OAEP( algorithm=hashes.SHA1(), mgf=padding.MGF1(hashes.SHA1()), - label=None - ) + label=None, + ), ) def test_unsupported_oaep_mgf(self, backend): @@ -1644,10 +1670,8 @@ def test_unsupported_oaep_mgf(self, backend): private_key.decrypt( b"0" * 64, padding.OAEP( - mgf=DummyMGF(), - algorithm=hashes.SHA1(), - label=None - ) + mgf=DummyMGF(), algorithm=hashes.SHA1(), label=None + ), ) @@ -1658,25 +1682,34 @@ class TestRSAEncryption(object): padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), - label=None + label=None, ) ), - skip_message="Does not support OAEP." + skip_message="Does not support OAEP.", ) @pytest.mark.parametrize( ("key_data", "pad"), itertools.product( - (RSA_KEY_1024, RSA_KEY_1025, RSA_KEY_1026, RSA_KEY_1027, - RSA_KEY_1028, RSA_KEY_1029, RSA_KEY_1030, RSA_KEY_1031, - RSA_KEY_1536, RSA_KEY_2048), + ( + RSA_KEY_1024, + RSA_KEY_1025, + RSA_KEY_1026, + RSA_KEY_1027, + RSA_KEY_1028, + RSA_KEY_1029, + RSA_KEY_1030, + RSA_KEY_1031, + RSA_KEY_1536, + RSA_KEY_2048, + ), [ padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), - label=None + label=None, ) - ] - ) + ], + ), ) def test_rsa_encrypt_oaep(self, key_data, pad, backend): private_key = key_data.private_key(backend) @@ -1684,7 +1717,7 @@ def test_rsa_encrypt_oaep(self, key_data, pad, backend): public_key = private_key.public_key() ct = public_key.encrypt(pt, pad) assert ct != pt - assert len(ct) == math.ceil(public_key.key_size / 8.0) + assert len(ct) == (public_key.key_size + 7) // 8 recovered_pt = private_key.decrypt(ct, pad) assert recovered_pt == pt @@ -1693,39 +1726,44 @@ def test_rsa_encrypt_oaep(self, key_data, pad, backend): padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA512(), - label=None + label=None, ) ), - skip_message="Does not support OAEP using SHA256 MGF1 and SHA512 hash." + skip_message=( + "Does not support OAEP using SHA256 MGF1 and SHA512 hash." + ), ) @pytest.mark.parametrize( ("mgf1hash", "oaephash"), - itertools.product([ - hashes.SHA1(), - hashes.SHA224(), - hashes.SHA256(), - hashes.SHA384(), - hashes.SHA512(), - ], [ - hashes.SHA1(), - hashes.SHA224(), - hashes.SHA256(), - hashes.SHA384(), - hashes.SHA512(), - ]) + itertools.product( + [ + hashes.SHA1(), + hashes.SHA224(), + hashes.SHA256(), + hashes.SHA384(), + hashes.SHA512(), + ], + [ + hashes.SHA1(), + hashes.SHA224(), + hashes.SHA256(), + hashes.SHA384(), + hashes.SHA512(), + ], + ), ) def test_rsa_encrypt_oaep_sha2(self, mgf1hash, oaephash, backend): pad = padding.OAEP( mgf=padding.MGF1(algorithm=mgf1hash), algorithm=oaephash, - label=None + label=None, ) private_key = RSA_KEY_2048.private_key(backend) pt = b"encrypt me using sha2 hashes!" public_key = private_key.public_key() ct = public_key.encrypt(pt, pad) assert ct != pt - assert len(ct) == math.ceil(public_key.key_size / 8.0) + assert len(ct) == (public_key.key_size + 7) // 8 recovered_pt = private_key.decrypt(ct, pad) assert recovered_pt == pt @@ -1733,16 +1771,25 @@ def test_rsa_encrypt_oaep_sha2(self, mgf1hash, oaephash, backend): only_if=lambda backend: backend.rsa_padding_supported( padding.PKCS1v15() ), - skip_message="Does not support PKCS1v1.5." + skip_message="Does not support PKCS1v1.5.", ) @pytest.mark.parametrize( ("key_data", "pad"), itertools.product( - (RSA_KEY_1024, RSA_KEY_1025, RSA_KEY_1026, RSA_KEY_1027, - RSA_KEY_1028, RSA_KEY_1029, RSA_KEY_1030, RSA_KEY_1031, - RSA_KEY_1536, RSA_KEY_2048), - [padding.PKCS1v15()] - ) + ( + RSA_KEY_1024, + RSA_KEY_1025, + RSA_KEY_1026, + RSA_KEY_1027, + RSA_KEY_1028, + RSA_KEY_1029, + RSA_KEY_1030, + RSA_KEY_1031, + RSA_KEY_1536, + RSA_KEY_2048, + ), + [padding.PKCS1v15()], + ), ) def test_rsa_encrypt_pkcs1v15(self, key_data, pad, backend): private_key = key_data.private_key(backend) @@ -1750,42 +1797,45 @@ def test_rsa_encrypt_pkcs1v15(self, key_data, pad, backend): public_key = private_key.public_key() ct = public_key.encrypt(pt, pad) assert ct != pt - assert len(ct) == math.ceil(public_key.key_size / 8.0) + assert len(ct) == (public_key.key_size + 7) // 8 recovered_pt = private_key.decrypt(ct, pad) assert recovered_pt == pt @pytest.mark.parametrize( ("key_data", "pad"), itertools.product( - (RSA_KEY_1024, RSA_KEY_1025, RSA_KEY_1026, RSA_KEY_1027, - RSA_KEY_1028, RSA_KEY_1029, RSA_KEY_1030, RSA_KEY_1031, - RSA_KEY_1536, RSA_KEY_2048), + ( + RSA_KEY_1024, + RSA_KEY_1025, + RSA_KEY_1026, + RSA_KEY_1027, + RSA_KEY_1028, + RSA_KEY_1029, + RSA_KEY_1030, + RSA_KEY_1031, + RSA_KEY_1536, + RSA_KEY_2048, + ), ( padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA1()), algorithm=hashes.SHA1(), - label=None + label=None, ), - padding.PKCS1v15() - ) - ) + padding.PKCS1v15(), + ), + ), ) def test_rsa_encrypt_key_too_small(self, key_data, pad, backend): private_key = key_data.private_key(backend) public_key = private_key.public_key() # Slightly smaller than the key size but not enough for padding. with pytest.raises(ValueError): - public_key.encrypt( - b"\x00" * (private_key.key_size // 8 - 1), - pad - ) + public_key.encrypt(b"\x00" * (private_key.key_size // 8 - 1), pad) # Larger than the key size. with pytest.raises(ValueError): - public_key.encrypt( - b"\x00" * (private_key.key_size // 8 + 5), - pad - ) + public_key.encrypt(b"\x00" * (private_key.key_size // 8 + 5), pad) def test_unsupported_padding(self, backend): private_key = RSA_KEY_512.private_key(backend) @@ -1804,10 +1854,8 @@ def test_unsupported_oaep_mgf(self, backend): public_key.encrypt( b"ciphertext", padding.OAEP( - mgf=DummyMGF(), - algorithm=hashes.SHA1(), - label=None - ) + mgf=DummyMGF(), algorithm=hashes.SHA1(), label=None + ), ) @@ -1827,7 +1875,7 @@ def test_rsa_private_numbers(self): dmp1=1, dmq1=1, iqmp=2, - public_numbers=public_numbers + public_numbers=public_numbers, ) assert private_numbers.p == 3 @@ -1863,18 +1911,20 @@ def test_public_numbers_invalid_types(self): (3, 5, 1, 1, None, 2, rsa.RSAPublicNumbers(e=1, n=15)), (3, 5, 1, 1, 1, None, rsa.RSAPublicNumbers(e=1, n=15)), (3, 5, 1, 1, 1, 2, None), - ] + ], ) - def test_private_numbers_invalid_types(self, p, q, d, dmp1, dmq1, iqmp, - public_numbers): + def test_private_numbers_invalid_types( + self, p, q, d, dmp1, dmq1, iqmp, public_numbers + ): with pytest.raises(TypeError): rsa.RSAPrivateNumbers( - p=p, q=q, + p=p, + q=q, d=d, dmp1=dmp1, dmq1=dmq1, iqmp=iqmp, - public_numbers=public_numbers + public_numbers=public_numbers, ) @pytest.mark.parametrize( @@ -1884,7 +1934,7 @@ def test_private_numbers_invalid_types(self, p, q, d, dmp1, dmq1, iqmp, (1, 15), # public_exponent < 3 (17, 15), # public_exponent > modulus (14, 15), # public_exponent not odd - ] + ], ) def test_invalid_public_numbers_argument_values(self, e, n, backend): # Start with public_exponent=7, modulus=15. Then change one value at a @@ -1909,10 +1959,11 @@ def test_invalid_public_numbers_argument_values(self, e, n, backend): (3, 11, 3, 1, 3, 2, 6, 33), # public_exponent is not odd (3, 11, 3, 2, 3, 2, 7, 33), # dmp1 is not odd (3, 11, 3, 1, 4, 2, 7, 33), # dmq1 is not odd - ] + ], ) - def test_invalid_private_numbers_argument_values(self, p, q, d, dmp1, dmq1, - iqmp, e, n, backend): + def test_invalid_private_numbers_argument_values( + self, p, q, d, dmp1, dmq1, iqmp, e, n, backend + ): # Start with p=3, q=11, private_exponent=3, public_exponent=7, # modulus=33, dmp1=1, dmq1=3, iqmp=2. Then change one value at # a time to test the bounds. @@ -1925,10 +1976,7 @@ def test_invalid_private_numbers_argument_values(self, p, q, d, dmp1, dmq1, dmp1=dmp1, dmq1=dmq1, iqmp=iqmp, - public_numbers=rsa.RSAPublicNumbers( - e=e, - n=n - ) + public_numbers=rsa.RSAPublicNumbers(e=e, n=n), ).private_key(backend) def test_public_number_repr(self): @@ -2004,18 +2052,19 @@ def test_private_numbers_hash(self): class TestRSAPrimeFactorRecovery(object): @pytest.mark.parametrize( "vector", - _flatten_pkcs1_examples(load_vectors_from_file( - os.path.join( - "asymmetric", "RSA", "pkcs1v15crypt-vectors.txt"), - load_pkcs1_vectors - )) + _flatten_pkcs1_examples( + load_vectors_from_file( + os.path.join("asymmetric", "RSA", "pkcs1v15crypt-vectors.txt"), + load_pkcs1_vectors, + ) + ), ) def test_recover_prime_factors(self, vector): private, public, example = vector p, q = rsa.rsa_recover_prime_factors( private["modulus"], private["public_exponent"], - private["private_exponent"] + private["private_exponent"], ) # Unfortunately there is no convention on which prime should be p # and which one q. The function we use always makes p > q, but the @@ -2037,22 +2086,23 @@ class TestRSAPrivateKeySerialization(object): itertools.product( [ serialization.PrivateFormat.TraditionalOpenSSL, - serialization.PrivateFormat.PKCS8 + serialization.PrivateFormat.PKCS8, ], [ b"s", b"longerpassword", b"!*$&(@#$*&($T@%_somesymbols", b"\x01" * 1000, - ] - ) + ], + ), ) def test_private_bytes_encrypted_pem(self, backend, fmt, password): + skip_fips_traditional_openssl(backend, fmt) key = RSA_KEY_2048.private_key(backend) serialized = key.private_bytes( serialization.Encoding.PEM, fmt, - serialization.BestAvailableEncryption(password) + serialization.BestAvailableEncryption(password), ) loaded_key = serialization.load_pem_private_key( serialized, password, backend @@ -2068,7 +2118,7 @@ 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), - ] + ], ) def test_private_bytes_rejects_invalid(self, encoding, fmt, backend): key = RSA_KEY_2048.private_key(backend) @@ -2081,15 +2131,15 @@ def test_private_bytes_rejects_invalid(self, encoding, fmt, backend): [serialization.PrivateFormat.PKCS8, b"s"], [serialization.PrivateFormat.PKCS8, b"longerpassword"], [serialization.PrivateFormat.PKCS8, b"!*$&(@#$*&($T@%_somesymbol"], - [serialization.PrivateFormat.PKCS8, b"\x01" * 1000] - ] + [serialization.PrivateFormat.PKCS8, b"\x01" * 1000], + ], ) def test_private_bytes_encrypted_der(self, backend, fmt, password): key = RSA_KEY_2048.private_key(backend) serialized = key.private_bytes( serialization.Encoding.DER, fmt, - serialization.BestAvailableEncryption(password) + serialization.BestAvailableEncryption(password), ) loaded_key = serialization.load_der_private_key( serialized, password, backend @@ -2104,27 +2154,28 @@ def test_private_bytes_encrypted_der(self, backend, fmt, password): [ serialization.Encoding.PEM, serialization.PrivateFormat.TraditionalOpenSSL, - serialization.load_pem_private_key + serialization.load_pem_private_key, ], [ serialization.Encoding.DER, serialization.PrivateFormat.TraditionalOpenSSL, - serialization.load_der_private_key + serialization.load_der_private_key, ], [ serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, - serialization.load_pem_private_key + serialization.load_pem_private_key, ], [ serialization.Encoding.DER, serialization.PrivateFormat.PKCS8, - serialization.load_der_private_key + serialization.load_der_private_key, ], - ] + ], ) - def test_private_bytes_unencrypted(self, backend, encoding, fmt, - loader_func): + def test_private_bytes_unencrypted( + self, backend, encoding, fmt, loader_func + ): key = RSA_KEY_2048.private_key(backend) serialized = key.private_bytes( encoding, fmt, serialization.NoEncryption() @@ -2134,6 +2185,9 @@ def test_private_bytes_unencrypted(self, backend, encoding, fmt, priv_num = key.private_numbers() assert loaded_priv_num == priv_num + @pytest.mark.skip_fips( + reason="Traditional OpenSSL key format is not supported in FIPS mode." + ) @pytest.mark.parametrize( ("key_path", "encoding", "loader_func"), [ @@ -2141,17 +2195,17 @@ def test_private_bytes_unencrypted(self, backend, encoding, fmt, os.path.join( "asymmetric", "Traditional_OpenSSL_Serialization", - "testrsa.pem" + "testrsa.pem", ), serialization.Encoding.PEM, - serialization.load_pem_private_key + serialization.load_pem_private_key, ], [ os.path.join("asymmetric", "DER_Serialization", "testrsa.der"), serialization.Encoding.DER, - serialization.load_der_private_key + serialization.load_der_private_key, ], - ] + ], ) def test_private_bytes_traditional_openssl_unencrypted( self, backend, key_path, encoding, loader_func @@ -2163,7 +2217,7 @@ def test_private_bytes_traditional_openssl_unencrypted( serialized = key.private_bytes( encoding, serialization.PrivateFormat.TraditionalOpenSSL, - serialization.NoEncryption() + serialization.NoEncryption(), ) assert serialized == key_bytes @@ -2173,7 +2227,7 @@ def test_private_bytes_traditional_der_encrypted_invalid(self, backend): key.private_bytes( serialization.Encoding.DER, serialization.PrivateFormat.TraditionalOpenSSL, - serialization.BestAvailableEncryption(b"password") + serialization.BestAvailableEncryption(b"password"), ) def test_private_bytes_invalid_encoding(self, backend): @@ -2182,7 +2236,7 @@ def test_private_bytes_invalid_encoding(self, backend): key.private_bytes( "notencoding", serialization.PrivateFormat.PKCS8, - serialization.NoEncryption() + serialization.NoEncryption(), ) def test_private_bytes_invalid_format(self, backend): @@ -2191,7 +2245,7 @@ def test_private_bytes_invalid_format(self, backend): key.private_bytes( serialization.Encoding.PEM, "invalidformat", - serialization.NoEncryption() + serialization.NoEncryption(), ) def test_private_bytes_invalid_encryption_algorithm(self, backend): @@ -2200,7 +2254,7 @@ def test_private_bytes_invalid_encryption_algorithm(self, backend): key.private_bytes( serialization.Encoding.PEM, serialization.PrivateFormat.TraditionalOpenSSL, - "notanencalg" + "notanencalg", ) def test_private_bytes_unsupported_encryption_type(self, backend): @@ -2209,7 +2263,7 @@ def test_private_bytes_unsupported_encryption_type(self, backend): key.private_bytes( serialization.Encoding.PEM, serialization.PrivateFormat.TraditionalOpenSSL, - DummyKeySerializationEncryption() + DummyKeySerializationEncryption(), ) @@ -2224,30 +2278,34 @@ class TestRSAPEMPublicKeySerialization(object): serialization.load_pem_public_key, serialization.Encoding.PEM, serialization.PublicFormat.PKCS1, - ), ( + ), + ( os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.der"), serialization.load_der_public_key, serialization.Encoding.DER, serialization.PublicFormat.PKCS1, - ), ( + ), + ( os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"), serialization.load_pem_public_key, serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo, - ), ( + ), + ( os.path.join( "asymmetric", "DER_Serialization", - "unenc-rsa-pkcs8.pub.der" + "unenc-rsa-pkcs8.pub.der", ), serialization.load_der_public_key, serialization.Encoding.DER, serialization.PublicFormat.SubjectPublicKeyInfo, - ) - ] + ), + ], ) - def test_public_bytes_match(self, key_path, loader_func, encoding, format, - backend): + def test_public_bytes_match( + self, key_path, loader_func, encoding, format, backend + ): key_bytes = load_vectors_from_file( key_path, lambda pemfile: pemfile.read(), mode="rb" ) @@ -2258,7 +2316,8 @@ def test_public_bytes_match(self, key_path, loader_func, encoding, format, def test_public_bytes_openssh(self, backend): key_bytes = load_vectors_from_file( os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.pem"), - lambda pemfile: pemfile.read(), mode="rb" + lambda pemfile: pemfile.read(), + mode="rb", ) key = serialization.load_pem_public_key(key_bytes, backend) @@ -2306,22 +2365,25 @@ def test_public_bytes_invalid_format(self, backend): [ ( serialization.Encoding.Raw, - serialization.PublicFormat.SubjectPublicKeyInfo + serialization.PublicFormat.SubjectPublicKeyInfo, ), (serialization.Encoding.Raw, serialization.PublicFormat.PKCS1), - ] + list(itertools.product( - [ - serialization.Encoding.Raw, - serialization.Encoding.X962, - serialization.Encoding.PEM, - serialization.Encoding.DER - ], - [ - serialization.PublicFormat.Raw, - serialization.PublicFormat.UncompressedPoint, - serialization.PublicFormat.CompressedPoint - ] - )) + ] + + list( + itertools.product( + [ + serialization.Encoding.Raw, + serialization.Encoding.X962, + serialization.Encoding.PEM, + serialization.Encoding.DER, + ], + [ + serialization.PublicFormat.Raw, + serialization.PublicFormat.UncompressedPoint, + serialization.PublicFormat.CompressedPoint, + ], + ) + ), ) def test_public_bytes_rejects_invalid(self, encoding, fmt, backend): key = RSA_KEY_2048.private_key(backend).public_key() diff --git a/tests/hazmat/primitives/test_scrypt.py b/tests/hazmat/primitives/test_scrypt.py index 8f3a14edc569..52e7e153802a 100644 --- a/tests/hazmat/primitives/test_scrypt.py +++ b/tests/hazmat/primitives/test_scrypt.py @@ -10,7 +10,9 @@ import pytest from cryptography.exceptions import ( - AlreadyFinalized, InvalidKey, UnsupportedAlgorithm + AlreadyFinalized, + InvalidKey, + UnsupportedAlgorithm, ) from cryptography.hazmat.backends.interfaces import ScryptBackend from cryptography.hazmat.primitives.kdf.scrypt import Scrypt, _MEM_LIMIT @@ -18,7 +20,8 @@ from tests.utils import load_nist_vectors, load_vectors_from_file vectors = load_vectors_from_file( - os.path.join("KDF", "scrypt.txt"), load_nist_vectors) + os.path.join("KDF", "scrypt.txt"), load_nist_vectors +) def _skip_if_memory_limited(memory_limit, params): @@ -29,8 +32,10 @@ def _skip_if_memory_limited(memory_limit, params): vlen = 32 * int(params["r"]) * (int(params["n"]) + 2) * 4 memory_required = blen + vlen if memory_limit < memory_required: - pytest.skip("Test exceeds Scrypt memory limit. " - "This is likely a 32-bit platform.") + pytest.skip( + "Test exceeds Scrypt memory limit. " + "This is likely a 32-bit platform." + ) def test_memory_limit_skip(): @@ -53,8 +58,14 @@ def test_derive(self, backend, params): salt = params["salt"] derived_key = params["derived_key"] - scrypt = Scrypt(salt, length, work_factor, block_size, - parallelization_factor, backend) + scrypt = Scrypt( + salt, + length, + work_factor, + block_size, + parallelization_factor, + backend, + ) assert binascii.hexlify(scrypt.derive(password)) == derived_key def test_unsupported_backend(self): @@ -66,8 +77,14 @@ def test_unsupported_backend(self): backend = object() with pytest.raises(UnsupportedAlgorithm): - Scrypt(salt, length, work_factor, block_size, - parallelization_factor, backend) + Scrypt( + salt, + length, + work_factor, + block_size, + parallelization_factor, + backend, + ) def test_salt_not_bytes(self, backend): work_factor = 1024 @@ -77,8 +94,14 @@ def test_salt_not_bytes(self, backend): salt = 1 with pytest.raises(TypeError): - Scrypt(salt, length, work_factor, block_size, - parallelization_factor, backend) + Scrypt( + salt, + length, + work_factor, + block_size, + parallelization_factor, + backend, + ) def test_scrypt_malloc_failure(self, backend): password = b"NaCl" @@ -88,8 +111,14 @@ def test_scrypt_malloc_failure(self, backend): length = 64 salt = b"NaCl" - scrypt = Scrypt(salt, length, work_factor, block_size, - parallelization_factor, backend) + scrypt = Scrypt( + salt, + length, + work_factor, + block_size, + parallelization_factor, + backend, + ) with pytest.raises(MemoryError): scrypt.derive(password) @@ -102,8 +131,14 @@ def test_password_not_bytes(self, backend): length = 64 salt = b"NaCl" - scrypt = Scrypt(salt, length, work_factor, block_size, - parallelization_factor, backend) + scrypt = Scrypt( + salt, + length, + work_factor, + block_size, + parallelization_factor, + backend, + ) with pytest.raises(TypeError): scrypt.derive(password) @@ -116,10 +151,16 @@ def test_buffer_protocol(self, backend): length = 10 salt = b"NaCl" - scrypt = Scrypt(salt, length, work_factor, block_size, - parallelization_factor, backend) + scrypt = Scrypt( + salt, + length, + work_factor, + block_size, + parallelization_factor, + backend, + ) - assert scrypt.derive(password) == b'\xf4\x92\x86\xb2\x06\x0c\x848W\x87' + assert scrypt.derive(password) == b"\xf4\x92\x86\xb2\x06\x0c\x848W\x87" @pytest.mark.parametrize("params", vectors) def test_verify(self, backend, params): @@ -132,8 +173,14 @@ def test_verify(self, backend, params): salt = params["salt"] derived_key = params["derived_key"] - scrypt = Scrypt(salt, length, work_factor, block_size, - parallelization_factor, backend) + scrypt = Scrypt( + salt, + length, + work_factor, + block_size, + parallelization_factor, + backend, + ) assert scrypt.verify(password, binascii.unhexlify(derived_key)) is None def test_invalid_verify(self, backend): @@ -145,8 +192,14 @@ def test_invalid_verify(self, backend): salt = b"NaCl" derived_key = b"fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e773" - scrypt = Scrypt(salt, length, work_factor, block_size, - parallelization_factor, backend) + scrypt = Scrypt( + salt, + length, + work_factor, + block_size, + parallelization_factor, + backend, + ) with pytest.raises(InvalidKey): scrypt.verify(password, binascii.unhexlify(derived_key)) @@ -159,8 +212,14 @@ def test_already_finalized(self, backend): length = 64 salt = b"NaCl" - scrypt = Scrypt(salt, length, work_factor, block_size, - parallelization_factor, backend) + scrypt = Scrypt( + salt, + length, + work_factor, + block_size, + parallelization_factor, + backend, + ) scrypt.derive(password) with pytest.raises(AlreadyFinalized): scrypt.derive(password) diff --git a/tests/hazmat/primitives/test_seed.py b/tests/hazmat/primitives/test_seed.py index 29cae4fe9f36..66da97836a0a 100644 --- a/tests/hazmat/primitives/test_seed.py +++ b/tests/hazmat/primitives/test_seed.py @@ -24,7 +24,7 @@ ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSEEDModeECB(object): - test_ECB = generate_encrypt_test( + test_ecb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "SEED"), ["rfc-4269.txt"], @@ -41,12 +41,12 @@ class TestSEEDModeECB(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSEEDModeCBC(object): - test_CBC = generate_encrypt_test( + test_cbc = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "SEED"), ["rfc-4196.txt"], lambda key, **kwargs: algorithms.SEED(binascii.unhexlify((key))), - lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)) + lambda iv, **kwargs: modes.CBC(binascii.unhexlify(iv)), ) @@ -58,12 +58,12 @@ class TestSEEDModeCBC(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSEEDModeOFB(object): - test_OFB = generate_encrypt_test( + test_ofb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "SEED"), ["seed-ofb.txt"], lambda key, **kwargs: algorithms.SEED(binascii.unhexlify((key))), - lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)) + lambda iv, **kwargs: modes.OFB(binascii.unhexlify(iv)), ) @@ -75,10 +75,10 @@ class TestSEEDModeOFB(object): ) @pytest.mark.requires_backend_interface(interface=CipherBackend) class TestSEEDModeCFB(object): - test_CFB = generate_encrypt_test( + test_cfb = generate_encrypt_test( load_nist_vectors, os.path.join("ciphers", "SEED"), ["seed-cfb.txt"], lambda key, **kwargs: algorithms.SEED(binascii.unhexlify((key))), - lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)) + lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)), ) diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 5dd724894c5c..2f56711d5dab 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -11,29 +11,61 @@ import pytest +import six + from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.hazmat.backends.interfaces import ( - DERSerializationBackend, DSABackend, EllipticCurveBackend, - PEMSerializationBackend, RSABackend + DERSerializationBackend, + DSABackend, + EllipticCurveBackend, + PEMSerializationBackend, + RSABackend, +) +from cryptography.hazmat.primitives.asymmetric import ( + dsa, + ec, + ed25519, + ed448, + rsa, + x25519, + x448, ) -from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa from cryptography.hazmat.primitives.serialization import ( - BestAvailableEncryption, Encoding, NoEncryption, - PrivateFormat, PublicFormat, - load_der_parameters, load_der_private_key, - load_der_public_key, load_pem_parameters, load_pem_private_key, - load_pem_public_key, load_ssh_public_key + BestAvailableEncryption, + Encoding, + NoEncryption, + PrivateFormat, + PublicFormat, + load_der_parameters, + load_der_private_key, + load_der_public_key, + load_pem_parameters, + load_pem_private_key, + load_pem_public_key, + load_ssh_private_key, + load_ssh_public_key, + ssh, ) from .test_ec import _skip_curve_unsupported from .utils import ( - _check_dsa_private_numbers, _check_rsa_private_numbers, - load_vectors_from_file + _check_dsa_private_numbers, + _check_rsa_private_numbers, + load_vectors_from_file, ) +from ...doubles import DummyKeySerializationEncryption from ...utils import raises_unsupported_algorithm +def _skip_fips_format(key_path, password, backend): + if backend._fips_enabled: + if key_path[0] == "Traditional_OpenSSL_Serialization": + pytest.skip("Traditional OpenSSL format blocked in FIPS mode") + if key_path[0] == "PEM_Serialization" and password is not None: + pytest.skip("Encrypted PEM_Serialization blocked in FIPS mode") + + class TestBufferProtocolSerialization(object): @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.parametrize( @@ -43,12 +75,13 @@ class TestBufferProtocolSerialization(object): (["DER_Serialization", "enc2-rsa-pkcs8.der"], bytearray(b"baz")), (["DER_Serialization", "unenc-rsa-pkcs8.der"], None), (["DER_Serialization", "testrsa.der"], None), - ] + ], ) def test_load_der_rsa_private_key(self, key_path, password, backend): data = load_vectors_from_file( os.path.join("asymmetric", *key_path), - lambda derfile: derfile.read(), mode="rb" + lambda derfile: derfile.read(), + mode="rb", ) key = load_der_private_key(bytearray(data), password, backend) assert key @@ -61,21 +94,23 @@ def test_load_der_rsa_private_key(self, key_path, password, backend): [ ( ["PEM_Serialization", "rsa_private_key.pem"], - bytearray(b"123456") + bytearray(b"123456"), ), (["PKCS8", "unenc-rsa-pkcs8.pem"], None), (["PKCS8", "enc-rsa-pkcs8.pem"], bytearray(b"foobar")), (["PKCS8", "enc2-rsa-pkcs8.pem"], bytearray(b"baz")), ( ["Traditional_OpenSSL_Serialization", "key1.pem"], - bytearray(b"123456") + bytearray(b"123456"), ), - ] + ], ) def test_load_pem_rsa_private_key(self, key_path, password, backend): + _skip_fips_format(key_path, password, backend) data = load_vectors_from_file( os.path.join("asymmetric", *key_path), - lambda pemfile: pemfile.read(), mode="rb" + lambda pemfile: pemfile.read(), + mode="rb", ) key = load_pem_private_key(bytearray(data), password, backend) assert key @@ -93,7 +128,7 @@ class TestDERSerialization(object): (["DER_Serialization", "enc2-rsa-pkcs8.der"], b"baz"), (["DER_Serialization", "unenc-rsa-pkcs8.der"], None), (["DER_Serialization", "testrsa.der"], None), - ] + ], ) def test_load_der_rsa_private_key(self, key_path, password, backend): key = load_vectors_from_file( @@ -101,7 +136,7 @@ def test_load_der_rsa_private_key(self, key_path, password, backend): lambda derfile: load_der_private_key( derfile.read(), password, backend ), - mode="rb" + mode="rb", ) assert key assert isinstance(key, rsa.RSAPrivateKey) @@ -115,7 +150,7 @@ def test_load_der_rsa_private_key(self, key_path, password, backend): (["DER_Serialization", "dsa.1024.der"], None), (["DER_Serialization", "dsa.2048.der"], None), (["DER_Serialization", "dsa.3072.der"], None), - ] + ], ) def test_load_der_dsa_private_key(self, key_path, password, backend): key = load_vectors_from_file( @@ -123,17 +158,14 @@ def test_load_der_dsa_private_key(self, key_path, password, backend): lambda derfile: load_der_private_key( derfile.read(), password, backend ), - mode="rb" + mode="rb", ) assert key assert isinstance(key, dsa.DSAPrivateKey) _check_dsa_private_numbers(key.private_numbers()) @pytest.mark.parametrize( - "key_path", - [ - ["DER_Serialization", "enc-rsa-pkcs8.der"], - ] + "key_path", [["DER_Serialization", "enc-rsa-pkcs8.der"]] ) @pytest.mark.requires_backend_interface(interface=RSABackend) def test_password_not_bytes(self, key_path, backend): @@ -146,7 +178,7 @@ def test_password_not_bytes(self, key_path, backend): lambda derfile: load_der_private_key( derfile.read(), password, backend ), - mode="rb" + mode="rb", ) @pytest.mark.parametrize( @@ -154,7 +186,7 @@ def test_password_not_bytes(self, key_path, backend): [ (["DER_Serialization", "ec_private_key.der"], None), (["DER_Serialization", "ec_private_key_encrypted.der"], b"123456"), - ] + ], ) @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_load_der_ec_private_key(self, key_path, password, backend): @@ -164,7 +196,7 @@ def test_load_der_ec_private_key(self, key_path, password, backend): lambda derfile: load_der_private_key( derfile.read(), password, backend ), - mode="rb" + mode="rb", ) assert key @@ -173,10 +205,7 @@ def test_load_der_ec_private_key(self, key_path, password, backend): assert key.curve.key_size == 256 @pytest.mark.parametrize( - "key_path", - [ - ["DER_Serialization", "enc-rsa-pkcs8.der"], - ] + "key_path", [["DER_Serialization", "enc-rsa-pkcs8.der"]] ) @pytest.mark.requires_backend_interface(interface=RSABackend) def test_wrong_password(self, key_path, backend): @@ -189,14 +218,11 @@ def test_wrong_password(self, key_path, backend): lambda derfile: load_der_private_key( derfile.read(), password, backend ), - mode="rb" + mode="rb", ) @pytest.mark.parametrize( - "key_path", - [ - ["DER_Serialization", "unenc-rsa-pkcs8.der"] - ] + "key_path", [["DER_Serialization", "unenc-rsa-pkcs8.der"]] ) @pytest.mark.requires_backend_interface(interface=RSABackend) def test_unused_password(self, key_path, backend): @@ -209,17 +235,14 @@ def test_unused_password(self, key_path, backend): lambda derfile: load_der_private_key( derfile.read(), password, backend ), - mode="rb" + mode="rb", ) @pytest.mark.parametrize( ("key_path", "password"), itertools.product( - [ - ["DER_Serialization", "enc-rsa-pkcs8.der"], - ], - [b"", None] - ) + [["DER_Serialization", "enc-rsa-pkcs8.der"]], [b"", None] + ), ) @pytest.mark.requires_backend_interface(interface=RSABackend) def test_missing_password(self, key_path, password, backend): @@ -231,16 +254,14 @@ def test_missing_password(self, key_path, password, backend): lambda derfile: load_der_private_key( derfile.read(), password, backend ), - mode="rb" + mode="rb", ) def test_wrong_format(self, backend): key_data = b"---- NOT A KEY ----\n" with pytest.raises(ValueError): - load_der_private_key( - key_data, None, backend - ) + load_der_private_key(key_data, None, backend) with pytest.raises(ValueError): load_der_private_key( @@ -249,7 +270,8 @@ def test_wrong_format(self, backend): def test_corrupt_der_pkcs8(self, backend): # unenc-rsa-pkcs8 with a bunch of data missing. - key_data = textwrap.dedent("""\ + key_data = textwrap.dedent( + """\ MIICdQIBADALBgkqhkiG9w0BAQEEggJhMIICXQIBAAKBgQC7JHoJfg6yNzLMOWet 8Z49a4KD0dCspMAYvo2YAMB7/wdEycocujbhJ2n/seONi+5XqTqqFkM5VBl8rmkk FPZk/7x0xmdsTPECSWnHK+HhoaNDFPR3j8jQhVo1laxiqcEhAHegi5cwtFosuJAv @@ -263,13 +285,12 @@ def test_corrupt_der_pkcs8(self, backend): z+KOpdpPRR5TQmbEMEspjsFpFymMiuYPgmihQbO2cJl1qScY5OkCQQCJ6m5tcN8l Xxg/SNpjEIv+qAyUD96XVlOJlOIeLHQ8kYE0C6ZA+MsqYIzgAreJk88Yn0lU/X0/ mu/UpE/BRZmR - """).encode() + """ + ).encode() bad_der = base64.b64decode(b"".join(key_data.splitlines())) with pytest.raises(ValueError): - load_der_private_key( - bad_der, None, backend - ) + load_der_private_key(bad_der, None, backend) with pytest.raises(ValueError): load_der_private_key( @@ -278,14 +299,16 @@ def test_corrupt_der_pkcs8(self, backend): def test_corrupt_traditional_format_der(self, backend): # privkey with a bunch of data missing. - key_data = textwrap.dedent("""\ + key_data = textwrap.dedent( + """\ MIIBPAIBAAJBAKrbeqkuRk8VcRmWFmtP+LviMB3+6dizWW3DwaffznyHGAFwUJ/I Tv0XtbsCyl3QoyKGhrOAy3RvPK5M38iuXT0CAwEAAQJAZ3cnzaHXM/bxGaR5CR1R rD1qFBAVfoQFiOH9uPJgMaoAuoQEisPHVcZDKcOv4wEg6/TInAIXBnEigtqvRzuy mvcpHZwQJdmdHHkGKAs37Dfxi67HbkUCIQCeZGliHXFa071Fp06ZeWlR2ADonTZz rJBhdTe0v5pCeQIhAIZfkiGgGBX4cIuuckzEm43g9WMUjxP/0GlK39vIyihxAiEA mymehFRT0MvqW5xAKAx7Pgkt8HVKwVhc2LwGKHE0DZM= - """).encode() + """ + ).encode() bad_der = base64.b64decode(b"".join(key_data.splitlines())) with pytest.raises(ValueError): @@ -300,20 +323,20 @@ def test_corrupt_traditional_format_der(self, backend): "key_file", [ os.path.join( - "asymmetric", "DER_Serialization", "unenc-rsa-pkcs8.pub.der"), + "asymmetric", "DER_Serialization", "unenc-rsa-pkcs8.pub.der" + ), os.path.join( - "asymmetric", "DER_Serialization", "rsa_public_key.der"), + "asymmetric", "DER_Serialization", "rsa_public_key.der" + ), os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.der"), - ] + ], ) @pytest.mark.requires_backend_interface(interface=RSABackend) def test_load_der_rsa_public_key(self, key_file, backend): key = load_vectors_from_file( key_file, - lambda derfile: load_der_public_key( - derfile.read(), backend - ), - mode="rb" + lambda derfile: load_der_public_key(derfile.read(), backend), + mode="rb", ) assert key assert isinstance(key, rsa.RSAPublicKey) @@ -328,19 +351,19 @@ def test_load_der_invalid_public_key(self, backend): "key_file", [ os.path.join( - "asymmetric", "DER_Serialization", "unenc-dsa-pkcs8.pub.der"), + "asymmetric", "DER_Serialization", "unenc-dsa-pkcs8.pub.der" + ), os.path.join( - "asymmetric", "DER_Serialization", "dsa_public_key.der"), - ] + "asymmetric", "DER_Serialization", "dsa_public_key.der" + ), + ], ) @pytest.mark.requires_backend_interface(interface=DSABackend) def test_load_der_dsa_public_key(self, key_file, backend): key = load_vectors_from_file( key_file, - lambda derfile: load_der_public_key( - derfile.read(), backend - ), - mode="rb" + lambda derfile: load_der_public_key(derfile.read(), backend), + mode="rb", ) assert key assert isinstance(key, dsa.DSAPublicKey) @@ -350,12 +373,10 @@ def test_load_ec_public_key(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) key = load_vectors_from_file( os.path.join( - "asymmetric", "DER_Serialization", - "ec_public_key.der"), - lambda derfile: load_der_public_key( - derfile.read(), backend + "asymmetric", "DER_Serialization", "ec_public_key.der" ), - mode="rb" + lambda derfile: load_der_public_key(derfile.read(), backend), + mode="rb", ) assert key assert isinstance(key, ec.EllipticCurvePublicKey) @@ -366,9 +387,7 @@ def test_wrong_parameters_format(self, backend): param_data = b"---- NOT A KEY ----\n" with pytest.raises(ValueError): - load_der_parameters( - param_data, backend - ) + load_der_parameters(param_data, backend) @pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) @@ -393,16 +412,19 @@ class TestPEMSerialization(object): (["Traditional_OpenSSL_Serialization", "key1.pem"], b"123456"), (["Traditional_OpenSSL_Serialization", "key2.pem"], b"a123456"), (["Traditional_OpenSSL_Serialization", "testrsa.pem"], None), - (["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"], - b"password"), - ] + ( + ["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"], + b"password", + ), + ], ) def test_load_pem_rsa_private_key(self, key_file, password, backend): + _skip_fips_format(key_file, password, backend) key = load_vectors_from_file( os.path.join("asymmetric", *key_file), lambda pemfile: load_pem_private_key( pemfile.read().encode(), password, backend - ) + ), ) assert key @@ -417,14 +439,15 @@ def test_load_pem_rsa_private_key(self, key_file, password, backend): (["Traditional_OpenSSL_Serialization", "dsa.3072.pem"], None), (["PKCS8", "unenc-dsa-pkcs8.pem"], None), (["PEM_Serialization", "dsa_private_key.pem"], b"123456"), - ] + ], ) def test_load_dsa_private_key(self, key_path, password, backend): + _skip_fips_format(key_path, password, backend) key = load_vectors_from_file( os.path.join("asymmetric", *key_path), lambda pemfile: load_pem_private_key( pemfile.read().encode(), password, backend - ) + ), ) assert key assert isinstance(key, dsa.DSAPrivateKey) @@ -437,16 +460,17 @@ def test_load_dsa_private_key(self, key_path, password, backend): (["PKCS8", "ec_private_key_encrypted.pem"], b"123456"), (["PEM_Serialization", "ec_private_key.pem"], None), (["PEM_Serialization", "ec_private_key_encrypted.pem"], b"123456"), - ] + ], ) @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) def test_load_pem_ec_private_key(self, key_path, password, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) + _skip_fips_format(key_path, password, backend) key = load_vectors_from_file( os.path.join("asymmetric", *key_path), lambda pemfile: load_pem_private_key( pemfile.read().encode(), password, backend - ) + ), ) assert key @@ -459,16 +483,17 @@ def test_load_pem_ec_private_key(self, key_path, password, backend): [ os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"), os.path.join( - "asymmetric", "PEM_Serialization", "rsa_public_key.pem"), + "asymmetric", "PEM_Serialization", "rsa_public_key.pem" + ), os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.pem"), - ] + ], ) def test_load_pem_rsa_public_key(self, key_file, backend): key = load_vectors_from_file( key_file, lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend - ) + ), ) assert key assert isinstance(key, rsa.RSAPublicKey) @@ -480,16 +505,16 @@ def test_load_pem_rsa_public_key(self, key_file, backend): [ os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), os.path.join( - "asymmetric", "PEM_Serialization", - "dsa_public_key.pem"), - ] + "asymmetric", "PEM_Serialization", "dsa_public_key.pem" + ), + ], ) def test_load_pem_dsa_public_key(self, key_file, backend): key = load_vectors_from_file( key_file, lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend - ) + ), ) assert key assert isinstance(key, dsa.DSAPublicKey) @@ -499,66 +524,70 @@ def test_load_ec_public_key(self, backend): _skip_curve_unsupported(backend, ec.SECP256R1()) key = load_vectors_from_file( os.path.join( - "asymmetric", "PEM_Serialization", - "ec_public_key.pem"), + "asymmetric", "PEM_Serialization", "ec_public_key.pem" + ), lambda pemfile: load_pem_public_key( pemfile.read().encode(), backend - ) + ), ) assert key assert isinstance(key, ec.EllipticCurvePublicKey) assert key.curve.name == "secp256r1" assert key.curve.key_size == 256 + @pytest.mark.skip_fips( + reason="Traditional OpenSSL format blocked in FIPS mode" + ) def test_rsa_traditional_encrypted_values(self, backend): pkey = load_vectors_from_file( os.path.join( - "asymmetric", "Traditional_OpenSSL_Serialization", "key1.pem"), + "asymmetric", "Traditional_OpenSSL_Serialization", "key1.pem" + ), lambda pemfile: load_pem_private_key( pemfile.read().encode(), b"123456", backend - ) + ), ) assert pkey numbers = pkey.private_numbers() assert numbers.p == int( "fb7d316fc51531b36d93adaefaf52db6ad5beb793d37c4cf9dfc1ddd17cfbafb", - 16 + 16, ) assert numbers.q == int( "df98264e646de9a0fbeab094e31caad5bc7adceaaae3c800ca0275dd4bb307f5", - 16 + 16, ) assert numbers.d == int( "db4848c36f478dd5d38f35ae519643b6b810d404bcb76c00e44015e56ca1cab0" "7bb7ae91f6b4b43fcfc82a47d7ed55b8c575152116994c2ce5325ec24313b911", - 16 + 16, ) assert numbers.dmp1 == int( "ce997f967192c2bcc3853186f1559fd355c190c58ddc15cbf5de9b6df954c727", - 16 + 16, ) assert numbers.dmq1 == int( "b018a57ab20ffaa3862435445d863369b852cf70a67c55058213e3fe10e3848d", - 16 + 16, ) assert numbers.iqmp == int( "6a8d830616924f5cf2d1bc1973f97fde6b63e052222ac7be06aa2532d10bac76", - 16 + 16, ) assert numbers.public_numbers.e == 65537 assert numbers.public_numbers.n == int( "dba786074f2f0350ce1d99f5aed5b520cfe0deb5429ec8f2a88563763f566e77" "9814b7c310e5326edae31198eed439b845dd2db99eaa60f5c16a43f4be6bcf37", - 16 + 16, ) @pytest.mark.parametrize( "key_path", [ ["Traditional_OpenSSL_Serialization", "testrsa.pem"], - ["PKCS8", "unenc-rsa-pkcs8.pem"] - ] + ["PKCS8", "unenc-rsa-pkcs8.pem"], + ], ) def test_unused_password(self, key_path, backend): key_file = os.path.join("asymmetric", *key_path) @@ -569,15 +598,33 @@ def test_unused_password(self, key_path, backend): key_file, lambda pemfile: load_pem_private_key( pemfile.read().encode(), password, backend - ) + ), ) + def test_invalid_encoding_with_traditional(self, backend): + key_file = os.path.join( + "asymmetric", "Traditional_OpenSSL_Serialization", "testrsa.pem" + ) + key = load_vectors_from_file( + key_file, + lambda pemfile: load_pem_private_key( + pemfile.read(), None, backend + ), + mode="rb", + ) + + for enc in (Encoding.OpenSSH, Encoding.Raw, Encoding.X962): + with pytest.raises(ValueError): + key.private_bytes( + enc, PrivateFormat.TraditionalOpenSSL, NoEncryption() + ) + @pytest.mark.parametrize( "key_path", [ ["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"], - ["PKCS8", "enc-rsa-pkcs8.pem"] - ] + ["PKCS8", "enc-rsa-pkcs8.pem"], + ], ) def test_password_not_bytes(self, key_path, backend): key_file = os.path.join("asymmetric", *key_path) @@ -588,15 +635,15 @@ def test_password_not_bytes(self, key_path, backend): key_file, lambda pemfile: load_pem_private_key( pemfile.read().encode(), password, backend - ) + ), ) @pytest.mark.parametrize( "key_path", [ ["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"], - ["PKCS8", "enc-rsa-pkcs8.pem"] - ] + ["PKCS8", "enc-rsa-pkcs8.pem"], + ], ) def test_wrong_password(self, key_path, backend): key_file = os.path.join("asymmetric", *key_path) @@ -607,19 +654,18 @@ def test_wrong_password(self, key_path, backend): key_file, lambda pemfile: load_pem_private_key( pemfile.read().encode(), password, backend - ) + ), ) @pytest.mark.parametrize( ("key_path", "password"), itertools.product( [ - ["Traditional_OpenSSL_Serialization", - "testrsa-encrypted.pem"], + ["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"], ["PKCS8", "enc-rsa-pkcs8.pem"], ], - [b"", None] - ) + [b"", None], + ), ) def test_missing_password(self, key_path, password, backend): key_file = os.path.join("asymmetric", *key_path) @@ -629,16 +675,14 @@ def test_missing_password(self, key_path, password, backend): key_file, lambda pemfile: load_pem_private_key( pemfile.read().encode(), password, backend - ) + ), ) def test_wrong_private_format(self, backend): key_data = b"---- NOT A KEY ----\n" with pytest.raises(ValueError): - load_pem_private_key( - key_data, None, backend - ) + load_pem_private_key(key_data, None, backend) with pytest.raises(ValueError): load_pem_private_key( @@ -659,7 +703,8 @@ def test_wrong_parameters_format(self, backend): def test_corrupt_traditional_format(self, backend): # privkey.pem with a bunch of data missing. - key_data = textwrap.dedent("""\ + key_data = textwrap.dedent( + """\ -----BEGIN RSA PRIVATE KEY----- MIIBPAIBAAJBAKrbeqkuRk8VcRmWFmtP+LviMB3+6dizWW3DwaffznyHGAFwUJ/I Tv0XtbsCyl3QoyKGhrOAy3RvPK5M38iuXT0CAwEAAQJAZ3cnzaHXM/bxGaR5CR1R @@ -668,12 +713,11 @@ def test_corrupt_traditional_format(self, backend): rJBhdTe0v5pCeQIhAIZfkiGgGBX4cIuuckzEm43g9WMUjxP/0GlK39vIyihxAiEA mymehFRT0MvqW5xAKAx7Pgkt8HVKwVhc2LwGKHE0DZM= -----END RSA PRIVATE KEY----- - """).encode() + """ + ).encode() with pytest.raises(ValueError): - load_pem_private_key( - key_data, None, backend - ) + load_pem_private_key(key_data, None, backend) with pytest.raises(ValueError): load_pem_private_key( @@ -682,7 +726,8 @@ def test_corrupt_traditional_format(self, backend): def test_traditional_encrypted_corrupt_format(self, backend): # privkey.pem with a single bit flipped - key_data = textwrap.dedent("""\ + key_data = textwrap.dedent( + """\ -----BEGIN RSA PRIVATE KEY----- Proc-Type: <,ENCRYPTED DEK-Info: AES-128-CBC,5E22A2BD85A653FB7A3ED20DE84F54CD @@ -695,22 +740,20 @@ def test_traditional_encrypted_corrupt_format(self, backend): 5A295jD9BQp9CY0nNFSsy+qiXWToq2xT3y5zVNEStmN0SCGNaIlUnJzL9IHW+oMI kPmXZMnAYBWeeCF1gf3J3aE5lZInegHNfEI0+J0LazC2aNU5Dg/BNqrmRqKWEIo/ -----END RSA PRIVATE KEY----- - """).encode() + """ + ).encode() password = b"this password is wrong" with pytest.raises(ValueError): - load_pem_private_key( - key_data, None, backend - ) + load_pem_private_key(key_data, None, backend) with pytest.raises(ValueError): - load_pem_private_key( - key_data, password, backend - ) + load_pem_private_key(key_data, password, backend) def test_unsupported_key_encryption(self, backend): - key_data = textwrap.dedent("""\ + key_data = textwrap.dedent( + """\ -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: FAKE-123,5E22A2BD85A653FB7A3ED20DE84F54CD @@ -723,18 +766,18 @@ def test_unsupported_key_encryption(self, backend): 5A295jD9BQp9CY0nNFSsy+qiXWToq2xT3y5zVNEStmN0SCGNaIlUnJzL9IHW+oMI kPmXZMnAYBWeeCF1gf3J3aE5lZInegHNfEI0+J0LazC2aNU5Dg/BNqrmRqKWEIo/ -----END RSA PRIVATE KEY----- - """).encode() + """ + ).encode() password = b"password" with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER): - load_pem_private_key( - key_data, password, backend - ) + load_pem_private_key(key_data, password, backend) def test_corrupt_pkcs8_format(self, backend): # unenc-rsa-pkcs8.pem with a bunch of data missing. - key_data = textwrap.dedent("""\ + key_data = textwrap.dedent( + """\ -----BEGIN PRIVATE KEY----- MIICdQIBADALBgkqhkiG9w0BAQEEggJhMIICXQIBAAKBgQC7JHoJfg6yNzLMOWet 8Z49a4KD0dCspMAYvo2YAMB7/wdEycocujbhJ2n/seONi+5XqTqqFkM5VBl8rmkk @@ -750,12 +793,11 @@ def test_corrupt_pkcs8_format(self, backend): Xxg/SNpjEIv+qAyUD96XVlOJlOIeLHQ8kYE0C6ZA+MsqYIzgAreJk88Yn0lU/X0/ mu/UpE/BRZmR -----END PRIVATE KEY----- - """).encode() + """ + ).encode() with pytest.raises(ValueError): - load_pem_private_key( - key_data, None, backend - ) + load_pem_private_key(key_data, None, backend) with pytest.raises(ValueError): load_pem_private_key( @@ -764,7 +806,8 @@ def test_corrupt_pkcs8_format(self, backend): def test_pks8_encrypted_corrupt_format(self, backend): # enc-rsa-pkcs8.pem with some bits flipped. - key_data = textwrap.dedent("""\ + key_data = textwrap.dedent( + """\ -----BEGIN ENCRYPTED PRIVATE KEY----- MIICojAcBgoqhkiG9w0BDAEDMA4ECHK0M0+QuEL9AgIBIcSCAoDRq+KRY+0XP0tO lwBTzViiXSXoyNnKAZKt5r5K/fGNntv22g/1s/ZNCetrqsJDC5eMUPPacz06jFq/ @@ -782,27 +825,23 @@ def test_pks8_encrypted_corrupt_format(self, backend): 6JLgl8FrvdfjHwIvmSOO1YMNmILBq000Q8WDqyErBDs4hsvtO6VQ4LeqJj6gClX3 qeJNaJFu -----END ENCRYPTED PRIVATE KEY----- - """).encode() + """ + ).encode() password = b"this password is wrong" with pytest.raises(ValueError): - load_pem_private_key( - key_data, None, backend - ) + load_pem_private_key(key_data, None, backend) with pytest.raises(ValueError): - load_pem_private_key( - key_data, password, backend - ) + load_pem_private_key(key_data, password, backend) def test_rsa_pkcs8_encrypted_values(self, backend): pkey = load_vectors_from_file( - os.path.join( - "asymmetric", "PKCS8", "enc-rsa-pkcs8.pem"), + os.path.join("asymmetric", "PKCS8", "enc-rsa-pkcs8.pem"), lambda pemfile: load_pem_private_key( pemfile.read().encode(), b"foobar", backend - ) + ), ) assert pkey @@ -813,7 +852,8 @@ def test_rsa_pkcs8_encrypted_values(self, backend): "376a7fe5b19f95b35ca358ea5c8abd7ae051d49cd2f1e45969a1ae945460" "3c14b278664a0e414ebc8913acb6203626985525e17a600611b028542dd0" "562aad787fb4f1650aa318cdcff751e1b187cbf6785fbe164e9809491b95" - "dd68480567c99b1a57", 16 + "dd68480567c99b1a57", + 16, ) assert numbers.public_numbers.e == 65537 @@ -823,37 +863,43 @@ def test_rsa_pkcs8_encrypted_values(self, backend): "f3d9785c3a2c09e4c8090909fb3721e19a3009ec21221523a729265707a5" "8f13063671c42a4096cad378ef2510cb59e23071489d8893ac4934dd149f" "34f2d094bea57f1c8027c3a77248ac9b91218737d0c3c3dfa7d7829e6977" - "cf7d995688c86c81", 16 + "cf7d995688c86c81", + 16, ) assert numbers.p == int( "00db122ac857b2c0437d7616daa98e597bb75ca9ad3a47a70bec10c10036" "03328794b225c8e3eee6ffd3fd6d2253d28e071fe27d629ab072faa14377" - "ce6118cb67", 16 + "ce6118cb67", + 16, ) assert numbers.q == int( "00df1b8aa8506fcbbbb9d00257f2975e38b33d2698fd0f37e82d7ef38c56" "f21b6ced63c825383782a7115cfcc093300987dbd2853b518d1c8f26382a" - "2d2586d391", 16 + "2d2586d391", + 16, ) assert numbers.dmp1 == int( "00be18aca13e60712fdf5daa85421eb10d86d654b269e1255656194fb0c4" "2dd01a1070ea12c19f5c39e09587af02f7b1a1030d016a9ffabf3b36d699" - "ceaf38d9bf", 16 + "ceaf38d9bf", + 16, ) assert numbers.dmq1 == int( "71aa8978f90a0c050744b77cf1263725b203ac9f730606d8ae1d289dce4a" "28b8d534e9ea347aeb808c73107e583eb80c546d2bddadcdb3c82693a4c1" - "3d863451", 16 + "3d863451", + 16, ) assert numbers.iqmp == int( "136b7b1afac6e6279f71b24217b7083485a5e827d156024609dae39d48a6" "bdb55af2f062cc4a3b077434e6fffad5faa29a2b5dba2bed3e4621e478c0" - "97ccfe7f", 16 + "97ccfe7f", + 16, ) def test_load_pem_dsa_private_key(self, backend): @@ -861,7 +907,7 @@ def test_load_pem_dsa_private_key(self, backend): os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"), lambda pemfile: load_pem_private_key( pemfile.read().encode(), None, backend - ) + ), ) assert key assert isinstance(key, dsa.DSAPrivateKey) @@ -872,15 +918,14 @@ def test_load_pem_dsa_private_key(self, backend): num = key.private_numbers() pub = num.public_numbers parameter_numbers = pub.parameter_numbers - assert num.x == int("00a535a8e1d0d91beafc8bee1d9b2a3a8de3311203", - 16) + assert num.x == int("00a535a8e1d0d91beafc8bee1d9b2a3a8de3311203", 16) assert pub.y == int( "2b260ea97dc6a12ae932c640e7df3d8ff04a8a05a0324f8d5f1b23f15fa1" "70ff3f42061124eff2586cb11b49a82dcdc1b90fc6a84fb10109cb67db5d" "2da971aeaf17be5e37284563e4c64d9e5fc8480258b319f0de29d54d8350" "70d9e287914d77df81491f4423b62da984eb3f45eb2a29fcea5dae525ac6" "ab6bcce04bfdf5b6", - 16 + 16, ) assert parameter_numbers.p == int( @@ -889,11 +934,12 @@ def test_load_pem_dsa_private_key(self, backend): "071d4dceb2782794ad393cc08a4d4ada7f68d6e839a5fcd34b4e402d82cb" "8a8cb40fec31911bf9bd360b034caacb4c5e947992573c9e90099c1b0f05" "940cabe5d2de49a167", - 16 + 16, ) assert parameter_numbers.q == int( - "00adc0e869b36f0ac013a681fdf4d4899d69820451", 16) + "00adc0e869b36f0ac013a681fdf4d4899d69820451", 16 + ) assert parameter_numbers.g == int( "008c6b4589afa53a4d1048bfc346d1f386ca75521ccf72ddaa251286880e" @@ -901,69 +947,61 @@ def test_load_pem_dsa_private_key(self, backend): "e71141ba324f5b93131929182c88a9fa4062836066cebe74b5c6690c7d10" "1106c240ab7ebd54e4e3301fd086ce6adac922fb2713a2b0887cba13b9bc" "68ce5cfff241cd3246", - 16 + 16, ) @pytest.mark.parametrize( - ("key_file", "password"), - [ - ("bad-oid-dsa-key.pem", None), - ] + ("key_file", "password"), [("bad-oid-dsa-key.pem", None)] ) def test_load_bad_oid_key(self, key_file, password, backend): with pytest.raises(ValueError): load_vectors_from_file( - os.path.join( - "asymmetric", "PKCS8", key_file), + os.path.join("asymmetric", "PKCS8", key_file), lambda pemfile: load_pem_private_key( pemfile.read().encode(), password, backend - ) + ), ) @pytest.mark.parametrize( - ("key_file", "password"), - [ - ("bad-encryption-oid.pem", b"password"), - ] + ("key_file", "password"), [("bad-encryption-oid.pem", b"password")] ) def test_load_bad_encryption_oid_key(self, key_file, password, backend): with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER): load_vectors_from_file( - os.path.join( - "asymmetric", "PKCS8", key_file), + os.path.join("asymmetric", "PKCS8", key_file), lambda pemfile: load_pem_private_key( pemfile.read().encode(), password, backend - ) + ), ) @pytest.mark.requires_backend_interface(interface=RSABackend) class TestRSASSHSerialization(object): def test_load_ssh_public_key_unsupported(self, backend): - ssh_key = b'ecdsa-sha2-junk AAAAE2VjZHNhLXNoYTItbmlzdHAyNTY=' + ssh_key = b"ecdsa-sha2-junk AAAAE2VjZHNhLXNoYTItbmlzdHAyNTY=" with pytest.raises(UnsupportedAlgorithm): load_ssh_public_key(ssh_key, backend) def test_load_ssh_public_key_bad_format(self, backend): - ssh_key = b'ssh-rsa not-a-real-key' + ssh_key = b"ssh-rsa not-a-real-key" with pytest.raises(ValueError): load_ssh_public_key(ssh_key, backend) def test_load_ssh_public_key_rsa_too_short(self, backend): - ssh_key = b'ssh-rsa' + ssh_key = b"ssh-rsa" with pytest.raises(ValueError): load_ssh_public_key(ssh_key, backend) def test_load_ssh_public_key_truncated_int(self, backend): - ssh_key = b'ssh-rsa AAAAB3NzaC1yc2EAAAA=' + ssh_key = b"ssh-rsa AAAAB3NzaC1yc2EAAAA=" with pytest.raises(ValueError): load_ssh_public_key(ssh_key, backend) - ssh_key = b'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAACKr+IHXo' + ssh_key = b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAACKr+IHXo" with pytest.raises(ValueError): load_ssh_public_key(ssh_key, backend) @@ -1032,16 +1070,18 @@ def test_load_ssh_public_key_rsa(self, backend): expected_e = 0x10001 expected_n = int( - '00C3BBF5D13F59322BA0A0B77EA0B6CF570241628AE24B5BA454D' - '23DCA295652B3523B67752653DFFD69587FAD9578DD6406F23691' - 'EA491C3F8B2D391D0312D9653C303B651067ADF887A5241843CEF' - '8019680A088E092FEC305FB04EA070340BB9BD0F1635B2AD84142' - '61B4E2D010ABD8FC6D2FB768912F78EE6B05A60857532B75B75EF' - 'C007601A4EF58BA947B7E75E38F3443CDD87E7C138A1DAD9D9FB3' - '19FF69DA43A9F6F6B0CD243F042CD1A5AFAEB286BD46AEB2D922B' - 'D01385D6892167074A0907F94A2BF08A54ABB2FFFFC89920861D0' - '46F8706AB88DDADBD9E8204D48B87789081E074024C8996783B31' - '7076A98ABF0A2D8550EAF2097D8CCC7BE76EF', 16) + "00C3BBF5D13F59322BA0A0B77EA0B6CF570241628AE24B5BA454D" + "23DCA295652B3523B67752653DFFD69587FAD9578DD6406F23691" + "EA491C3F8B2D391D0312D9653C303B651067ADF887A5241843CEF" + "8019680A088E092FEC305FB04EA070340BB9BD0F1635B2AD84142" + "61B4E2D010ABD8FC6D2FB768912F78EE6B05A60857532B75B75EF" + "C007601A4EF58BA947B7E75E38F3443CDD87E7C138A1DAD9D9FB3" + "19FF69DA43A9F6F6B0CD243F042CD1A5AFAEB286BD46AEB2D922B" + "D01385D6892167074A0907F94A2BF08A54ABB2FFFFC89920861D0" + "46F8706AB88DDADBD9E8204D48B87789081E074024C8996783B31" + "7076A98ABF0A2D8550EAF2097D8CCC7BE76EF", + 16, + ) expected = rsa.RSAPublicNumbers(expected_e, expected_n) @@ -1051,7 +1091,7 @@ def test_load_ssh_public_key_rsa(self, backend): @pytest.mark.requires_backend_interface(interface=DSABackend) class TestDSSSSHSerialization(object): def test_load_ssh_public_key_dss_too_short(self, backend): - ssh_key = b'ssh-dss' + ssh_key = b"ssh-dss" with pytest.raises(ValueError): load_ssh_public_key(ssh_key, backend) @@ -1134,14 +1174,16 @@ def test_load_ssh_public_key_dss(self, backend): "96a7032c01cdd8485b5cbfb73a46bb04708f98a18bc88d4c7812b284da8f900" "6e473e89897f9bc9125c69bbfd8ef691c0e76c1c34e6c843b8fe240e6e5aeb3" "13486e5fa917ab1288ff1a6ebcf9dcdeed3c5fc88474e30476f53a5ec816ef6" - "9f4", 16 + "9f4", + 16, ) expected_p = int( "b9b052d7f07630148d4d838b17790ef4f43437238ebebd5032ea483fd7b7902" "5ec3dc65ebd563ab586a633b4344f6acd10af31353bcf29111fa5e3b8d5c1e8" "7befe3c65f9b8be69c740716698c8366c8ef925b9cec1dcd69e73d926b554e2" "b4b6ddd1453eab39ba0f846e1555adcc33c5a8637128c9ed61104a45505a748" - "f6db", 16 + "f6db", + 16, ) expected_q = 1230879958723280233885494314531920096931919647917 expected_g = int( @@ -1149,11 +1191,12 @@ def test_load_ssh_public_key_dss(self, backend): "7bc249b6cf8f5f5c5022afefd4df5bf9d13bbdf182df5af2a5c5d1dc7604185" "7d5b0e4b22b856c300f850a3b00bac394b728755b8b7a56522eefc491573967" "debb5982fc94d6a8c291f758feae63ad769a5621947221522a2dc31d18ede6f" - "b656", 16 + "b656", + 16, ) expected = dsa.DSAPublicNumbers( expected_y, - dsa.DSAParameterNumbers(expected_p, expected_q, expected_g) + dsa.DSAParameterNumbers(expected_p, expected_q, expected_g), ) assert numbers == expected @@ -1174,17 +1217,32 @@ def test_load_ssh_public_key_ecdsa_nist_p256(self, backend): expected_x = int( "44196257377740326295529888716212621920056478823906609851236662550" - "785814128027", 10 + "785814128027", + 10, ) expected_y = int( "12257763433170736656417248739355923610241609728032203358057767672" - "925775019611", 10 + "925775019611", + 10, ) assert key.public_numbers() == ec.EllipticCurvePublicNumbers( expected_x, expected_y, ec.SECP256R1() ) + def test_load_ssh_public_key_byteslike(self, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + + ssh_key = ( + b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy" + b"NTYAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5" + b"teIg1TO03/FD9hbpBFgBeix3NrCFPls= root@cloud-server-01" + ) + assert load_ssh_public_key(bytearray(ssh_key), backend) + if six.PY3: + assert load_ssh_public_key(memoryview(ssh_key), backend) + assert load_ssh_public_key(memoryview(bytearray(ssh_key)), backend) + def test_load_ssh_public_key_ecdsa_nist_p384(self, backend): _skip_curve_unsupported(backend, ec.SECP384R1()) ssh_key = ( @@ -1197,11 +1255,13 @@ def test_load_ssh_public_key_ecdsa_nist_p384(self, backend): expected_x = int( "31541830871345183397582554827482786756220448716666815789487537666" - "592636882822352575507883817901562613492450642523901", 10 + "592636882822352575507883817901562613492450642523901", + 10, ) expected_y = int( "15111413269431823234030344298767984698884955023183354737123929430" - "995703524272335782455051101616329050844273733614670", 10 + "995703524272335782455051101616329050844273733614670", + 10, ) assert key.public_numbers() == ec.EllipticCurvePublicNumbers( @@ -1222,12 +1282,14 @@ def test_load_ssh_public_key_ecdsa_nist_p521(self, backend): expected_x = int( "54124123120178189598842622575230904027376313369742467279346415219" "77809037378785192537810367028427387173980786968395921877911964629" - "142163122798974160187785455", 10 + "142163122798974160187785455", + 10, ) expected_y = int( "16111775122845033200938694062381820957441843014849125660011303579" "15284560361402515564433711416776946492019498546572162801954089916" - "006665939539407104638103918", 10 + "006665939539407104638103918", + 10, ) assert key.public_numbers() == ec.EllipticCurvePublicNumbers( @@ -1274,6 +1336,51 @@ def test_load_ssh_public_key_ecdsa_nist_p256_bad_curve_name(self, backend): load_ssh_public_key(ssh_key, backend) +@pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support", +) +class TestEd25519SSHSerialization(object): + def test_load_ssh_public_key(self, backend): + ssh_key = ( + b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG2fgpmpYO61qeAxGd0wgRaN/E4" + b"GR+xWvBmvxjxrB1vG user@chiron.local" + ) + key = load_ssh_public_key(ssh_key, backend) + assert isinstance(key, ed25519.Ed25519PublicKey) + assert key.public_bytes(Encoding.Raw, PublicFormat.Raw) == ( + b"m\x9f\x82\x99\xa9`\xee\xb5\xa9\xe01\x19\xdd0\x81\x16\x8d\xfc" + b"N\x06G\xecV\xbc\x19\xaf\xc6 - """).splitlines() + """ + ).splitlines() vectors = tuple(load_pkcs1_vectors(vector_data)) expected = ( ( { - 'modulus': int( - '495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f77' - '8a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e58' - '2de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218' - 'f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a' - '2b8efab0561b0810344739ada0733f', 16), - 'public_exponent': int('10001', 16), - 'private_exponent': int( - '6c66ffe98980c38fcdeab5159898836165f4b4b817c4f6a8d486ee4ea' - '9130fe9b9092bd136d184f95f504a607eac565846d2fdd6597a8967c7' - '396ef95a6eeebb4578a643966dca4d8ee3de842de63279c618159c1ab' - '54a89437b6a6120e4930afb52a4ba6ced8a4947ac64b30a3497cbe701' - 'c2d6266d517219ad0ec6d347dbe9', 16), - 'p': int( - '8dad7f11363faa623d5d6d5e8a319328d82190d7127d2846c439b0ab7' - '2619b0a43a95320e4ec34fc3a9cea876422305bd76c5ba7be9e2f410c' - '8060645a1d29edb', 16), - 'q': int( - '847e732376fc7900f898ea82eb2b0fc418565fdae62f7d9ec4ce2217b' - '97990dd272db157f99f63c0dcbb9fbacdbd4c4dadb6df67756358ca41' - '74825b48f49706d', 16), - 'dmp1': int( - '05c2a83c124b3621a2aa57ea2c3efe035eff4560f33ddebb7adab81fc' - 'e69a0c8c2edc16520dda83d59a23be867963ac65f2cc710bbcfb96ee1' - '03deb771d105fd85', 16), - 'dmq1': int( - '04cae8aa0d9faa165c87b682ec140b8ed3b50b24594b7a3b2c220b366' - '9bb819f984f55310a1ae7823651d4a02e99447972595139363434e5e3' - '0a7e7d241551e1b9', 16), - 'iqmp': int( - '07d3e47bf686600b11ac283ce88dbb3f6051e8efd04680e44c171ef53' - '1b80b2b7c39fc766320e2cf15d8d99820e96ff30dc69691839c4b40d7' - 'b06e45307dc91f3f', 16), - 'examples': [ + "modulus": int( + "495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f77" + "8a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e58" + "2de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218" + "f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a" + "2b8efab0561b0810344739ada0733f", + 16, + ), + "public_exponent": int("10001", 16), + "private_exponent": int( + "6c66ffe98980c38fcdeab5159898836165f4b4b817c4f6a8d486ee4ea" + "9130fe9b9092bd136d184f95f504a607eac565846d2fdd6597a8967c7" + "396ef95a6eeebb4578a643966dca4d8ee3de842de63279c618159c1ab" + "54a89437b6a6120e4930afb52a4ba6ced8a4947ac64b30a3497cbe701" + "c2d6266d517219ad0ec6d347dbe9", + 16, + ), + "p": int( + "8dad7f11363faa623d5d6d5e8a319328d82190d7127d2846c439b0ab7" + "2619b0a43a95320e4ec34fc3a9cea876422305bd76c5ba7be9e2f410c" + "8060645a1d29edb", + 16, + ), + "q": int( + "847e732376fc7900f898ea82eb2b0fc418565fdae62f7d9ec4ce2217b" + "97990dd272db157f99f63c0dcbb9fbacdbd4c4dadb6df67756358ca41" + "74825b48f49706d", + 16, + ), + "dmp1": int( + "05c2a83c124b3621a2aa57ea2c3efe035eff4560f33ddebb7adab81fc" + "e69a0c8c2edc16520dda83d59a23be867963ac65f2cc710bbcfb96ee1" + "03deb771d105fd85", + 16, + ), + "dmq1": int( + "04cae8aa0d9faa165c87b682ec140b8ed3b50b24594b7a3b2c220b366" + "9bb819f984f55310a1ae7823651d4a02e99447972595139363434e5e3" + "0a7e7d241551e1b9", + 16, + ), + "iqmp": int( + "07d3e47bf686600b11ac283ce88dbb3f6051e8efd04680e44c171ef53" + "1b80b2b7c39fc766320e2cf15d8d99820e96ff30dc69691839c4b40d7" + "b06e45307dc91f3f", + 16, + ), + "examples": [ { - 'message': b'81332f4be62948415ea1d899792eeacf6c6e1db1d' - b'a8be13b5cea41db2fed467092e1ff398914c71425' - b'9775f595f8547f735692a575e6923af78f22c6997' - b'ddb90fb6f72d7bb0dd5744a31decd3dc368584983' - b'6ed34aec596304ad11843c4f88489f209735f5fb7' - b'fdaf7cec8addc5818168f880acbf490d51005b7a8' - b'e84e43e54287977571dd99eea4b161eb2df1f5108' - b'f12a4142a83322edb05a75487a3435c9a78ce53ed' - b'93bc550857d7a9fb', - 'salt': b'1d65491d79c864b373009be6f6f2467bac4c78fa', - 'signature': b'0262ac254bfa77f3c1aca22c5179f8f040422b3' - b'c5bafd40a8f21cf0fa5a667ccd5993d42dbafb4' - b'09c520e25fce2b1ee1e716577f1efa17f3da280' - b'52f40f0419b23106d7845aaf01125b698e7a4df' - b'e92d3967bb00c4d0d35ba3552ab9a8b3eef07c7' - b'fecdbc5424ac4db1e20cb37d0b2744769940ea9' - b'07e17fbbca673b20522380c5' - }, { - 'message': b'e2f96eaf0e05e7ba326ecca0ba7fd2f7c02356f3c' - b'ede9d0faabf4fcc8e60a973e5595fd9ea08', - 'salt': b'435c098aa9909eb2377f1248b091b68987ff1838', - 'signature': b'2707b9ad5115c58c94e932e8ec0a280f56339e4' - b'4a1b58d4ddcff2f312e5f34dcfe39e89c6a94dc' - b'ee86dbbdae5b79ba4e0819a9e7bfd9d982e7ee6' - b'c86ee68396e8b3a14c9c8f34b178eb741f9d3f1' - b'21109bf5c8172fada2e768f9ea1433032c004a8' - b'aa07eb990000a48dc94c8bac8aabe2b09b1aa46' - b'c0a2aa0e12f63fbba775ba7e' - } - ] + "message": b"81332f4be62948415ea1d899792eeacf6c6e1db1d" + b"a8be13b5cea41db2fed467092e1ff398914c71425" + b"9775f595f8547f735692a575e6923af78f22c6997" + b"ddb90fb6f72d7bb0dd5744a31decd3dc368584983" + b"6ed34aec596304ad11843c4f88489f209735f5fb7" + b"fdaf7cec8addc5818168f880acbf490d51005b7a8" + b"e84e43e54287977571dd99eea4b161eb2df1f5108" + b"f12a4142a83322edb05a75487a3435c9a78ce53ed" + b"93bc550857d7a9fb", + "salt": b"1d65491d79c864b373009be6f6f2467bac4c78fa", + "signature": b"0262ac254bfa77f3c1aca22c5179f8f040422b3" + b"c5bafd40a8f21cf0fa5a667ccd5993d42dbafb4" + b"09c520e25fce2b1ee1e716577f1efa17f3da280" + b"52f40f0419b23106d7845aaf01125b698e7a4df" + b"e92d3967bb00c4d0d35ba3552ab9a8b3eef07c7" + b"fecdbc5424ac4db1e20cb37d0b2744769940ea9" + b"07e17fbbca673b20522380c5", + }, + { + "message": b"e2f96eaf0e05e7ba326ecca0ba7fd2f7c02356f3c" + b"ede9d0faabf4fcc8e60a973e5595fd9ea08", + "salt": b"435c098aa9909eb2377f1248b091b68987ff1838", + "signature": b"2707b9ad5115c58c94e932e8ec0a280f56339e4" + b"4a1b58d4ddcff2f312e5f34dcfe39e89c6a94dc" + b"ee86dbbdae5b79ba4e0819a9e7bfd9d982e7ee6" + b"c86ee68396e8b3a14c9c8f34b178eb741f9d3f1" + b"21109bf5c8172fada2e768f9ea1433032c004a8" + b"aa07eb990000a48dc94c8bac8aabe2b09b1aa46" + b"c0a2aa0e12f63fbba775ba7e", + }, + ], }, - { - 'modulus': int( - '495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f77' - '8a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e58' - '2de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218' - 'f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a' - '2b8efab0561b0810344739ada0733f', 16), - 'public_exponent': int('10001', 16) - } + "modulus": int( + "495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f77" + "8a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e58" + "2de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218" + "f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a" + "2b8efab0561b0810344739ada0733f", + 16, + ), + "public_exponent": int("10001", 16), + }, ), ( { - 'modulus': int( - 'e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd0' - '6c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee31' - '5ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b' - '1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddb' - 'c2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8d' - 'e3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6f' - 'd4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b', 16), - 'public_exponent': int('10001', 16), - 'private_exponent': int( - '6a7fd84fb85fad073b34406db74f8d61a6abc12196a961dd79565e9da' - '6e5187bce2d980250f7359575359270d91590bb0e427c71460b55d514' - '10b191bcf309fea131a92c8e702738fa719f1e0041f52e40e91f229f4' - 'd96a1e6f172e15596b4510a6daec26105f2bebc53316b87bdf2131166' - '6070e8dfee69d52c71a976caae79c72b68d28580dc686d9f5129d225f' - '82b3d615513a882b3db91416b48ce08888213e37eeb9af800d81cab32' - '8ce420689903c00c7b5fd31b75503a6d419684d629', 16), - 'p': int( - 'f8eb97e98df12664eefdb761596a69ddcd0e76daece6ed4bf5a1b50ac' - '086f7928a4d2f8726a77e515b74da41988f220b1cc87aa1fc810ce99a' - '82f2d1ce821edced794c6941f42c7a1a0b8c4d28c75ec60b652279f61' - '54a762aed165d47dee367', 16), - 'q': int( - 'ed4d71d0a6e24b93c2e5f6b4bbe05f5fb0afa042d204fe3378d365c2f' - '288b6a8dad7efe45d153eef40cacc7b81ff934002d108994b94a5e472' - '8cd9c963375ae49965bda55cbf0efed8d6553b4027f2d86208a6e6b48' - '9c176128092d629e49d3d', 16), - 'dmp1': int( - '2bb68bddfb0c4f56c8558bffaf892d8043037841e7fa81cfa61a38c5e' - '39b901c8ee71122a5da2227bd6cdeeb481452c12ad3d61d5e4f776a0a' - 'b556591befe3e59e5a7fddb8345e1f2f35b9f4cee57c32414c086aec9' - '93e9353e480d9eec6289f', 16), - 'dmq1': int( - '4ff897709fad079746494578e70fd8546130eeab5627c49b080f05ee4' - 'ad9f3e4b7cba9d6a5dff113a41c3409336833f190816d8a6bc42e9bec' - '56b7567d0f3c9c696db619b245d901dd856db7c8092e77e9a1cccd56e' - 'e4dba42c5fdb61aec2669', 16), - 'iqmp': int( - '77b9d1137b50404a982729316efafc7dfe66d34e5a182600d5f30a0a8' - '512051c560d081d4d0a1835ec3d25a60f4e4d6aa948b2bf3dbb5b124c' - 'bbc3489255a3a948372f6978496745f943e1db4f18382ceaa505dfc65' - '757bb3f857a58dce52156', 16), - 'examples': [ + "modulus": int( + "e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd0" + "6c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee31" + "5ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b" + "1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddb" + "c2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8d" + "e3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6f" + "d4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b", + 16, + ), + "public_exponent": int("10001", 16), + "private_exponent": int( + "6a7fd84fb85fad073b34406db74f8d61a6abc12196a961dd79565e9da" + "6e5187bce2d980250f7359575359270d91590bb0e427c71460b55d514" + "10b191bcf309fea131a92c8e702738fa719f1e0041f52e40e91f229f4" + "d96a1e6f172e15596b4510a6daec26105f2bebc53316b87bdf2131166" + "6070e8dfee69d52c71a976caae79c72b68d28580dc686d9f5129d225f" + "82b3d615513a882b3db91416b48ce08888213e37eeb9af800d81cab32" + "8ce420689903c00c7b5fd31b75503a6d419684d629", + 16, + ), + "p": int( + "f8eb97e98df12664eefdb761596a69ddcd0e76daece6ed4bf5a1b50ac" + "086f7928a4d2f8726a77e515b74da41988f220b1cc87aa1fc810ce99a" + "82f2d1ce821edced794c6941f42c7a1a0b8c4d28c75ec60b652279f61" + "54a762aed165d47dee367", + 16, + ), + "q": int( + "ed4d71d0a6e24b93c2e5f6b4bbe05f5fb0afa042d204fe3378d365c2f" + "288b6a8dad7efe45d153eef40cacc7b81ff934002d108994b94a5e472" + "8cd9c963375ae49965bda55cbf0efed8d6553b4027f2d86208a6e6b48" + "9c176128092d629e49d3d", + 16, + ), + "dmp1": int( + "2bb68bddfb0c4f56c8558bffaf892d8043037841e7fa81cfa61a38c5e" + "39b901c8ee71122a5da2227bd6cdeeb481452c12ad3d61d5e4f776a0a" + "b556591befe3e59e5a7fddb8345e1f2f35b9f4cee57c32414c086aec9" + "93e9353e480d9eec6289f", + 16, + ), + "dmq1": int( + "4ff897709fad079746494578e70fd8546130eeab5627c49b080f05ee4" + "ad9f3e4b7cba9d6a5dff113a41c3409336833f190816d8a6bc42e9bec" + "56b7567d0f3c9c696db619b245d901dd856db7c8092e77e9a1cccd56e" + "e4dba42c5fdb61aec2669", + 16, + ), + "iqmp": int( + "77b9d1137b50404a982729316efafc7dfe66d34e5a182600d5f30a0a8" + "512051c560d081d4d0a1835ec3d25a60f4e4d6aa948b2bf3dbb5b124c" + "bbc3489255a3a948372f6978496745f943e1db4f18382ceaa505dfc65" + "757bb3f857a58dce52156", + 16, + ), + "examples": [ { - 'message': b'06add75ab689de067744e69a2ebd4b90fa9383003' - b'cd05ff536cbf294cd215f0923b7fc9004f0aa1852' - b'71a1d0061fd0e9777ad1ec0c71591f578bf7b8e5a' - b'1', - 'signature': b'4514210e541d5bad7dd60ae549b943acc44f213' - b'90df5b61318455a17610df5b74d84aed232f17e' - b'59d91dd2659922f812dbd49681690384b954e9a' - b'dfb9b1a968c0cbff763eceed62750c59164b5e0' - b'80a8fef3d55bfe2acfad2752a6a8459fa1fab49' - b'ad378c6964b23ee97fd1034610c5cc14c61e0eb' - b'fb1711f8ade96fe6557b38' + "message": b"06add75ab689de067744e69a2ebd4b90fa9383003" + b"cd05ff536cbf294cd215f0923b7fc9004f0aa1852" + b"71a1d0061fd0e9777ad1ec0c71591f578bf7b8e5a" + b"1", + "signature": b"4514210e541d5bad7dd60ae549b943acc44f213" + b"90df5b61318455a17610df5b74d84aed232f17e" + b"59d91dd2659922f812dbd49681690384b954e9a" + b"dfb9b1a968c0cbff763eceed62750c59164b5e0" + b"80a8fef3d55bfe2acfad2752a6a8459fa1fab49" + b"ad378c6964b23ee97fd1034610c5cc14c61e0eb" + b"fb1711f8ade96fe6557b38", } - ] + ], }, - { - 'modulus': int( - 'e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd0' - '6c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee31' - '5ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b' - '1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddb' - 'c2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8d' - 'e3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6f' - 'd4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b', 16), - 'public_exponent': int('10001', 16) - } - ) + "modulus": int( + "e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd0" + "6c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee31" + "5ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b" + "1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddb" + "c2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8d" + "e3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6f" + "d4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b", + 16, + ), + "public_exponent": int("10001", 16), + }, + ), ) assert vectors == expected def test_load_pkcs1_oaep_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ Test vectors for RSA-OAEP ========================= @@ -1083,88 +1160,106 @@ def test_load_pkcs1_oaep_vectors(): 15 91 2d f6 96 ff e0 70 29 32 94 6d 71 49 2b 44 # ============================================= - """).splitlines() + """ + ).splitlines() vectors = load_pkcs1_vectors(vector_data) expected = [ ( { - 'modulus': int( - 'a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae481' - '1a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6' - 'c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb' - '662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616' - 'd4f5ba10d4cfd226de88d39f16fb', 16), - 'public_exponent': int('10001', 16), - 'private_exponent': int( - '53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4' - 'f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b' - '8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3' - 'd3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d' - '0cf539e9cfcdd3de653729ead5d1', 16), - 'p': int( - 'd32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262864a9' - 'cb9f30af38be448598d413a172efb802c21acf1c11c520c2f26a471dc' - 'ad212eac7ca39d', 16), - 'q': int( - 'cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb33d3e3' - 'd5cc93c4765703d1dd791642f1f116a0dd852be2419b2af72bfe9a030' - 'e860b0288b5d77', 16), - 'dmp1': int( - '0e12bf1718e9cef5599ba1c3882fe8046a90874eefce8f2ccc20e4f27' - '41fb0a33a3848aec9c9305fbecbd2d76819967d4671acc6431e403796' - '8db37878e695c1', 16), - 'dmq1': int( - '95297b0f95a2fa67d00707d609dfd4fc05c89dafc2ef6d6ea55bec771' - 'ea333734d9251e79082ecda866efef13c459e1a631386b7e354c899f5' - 'f112ca85d71583', 16), - 'iqmp': int( - '4f456c502493bdc0ed2ab756a3a6ed4d67352a697d4216e93212b127a' - '63d5411ce6fa98d5dbefd73263e3728142743818166ed7dd63687dd2a' - '8ca1d2f4fbd8e1', 16), - 'examples': [ + "modulus": int( + "a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae481" + "1a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6" + "c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb" + "662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616" + "d4f5ba10d4cfd226de88d39f16fb", + 16, + ), + "public_exponent": int("10001", 16), + "private_exponent": int( + "53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4" + "f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b" + "8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3" + "d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d" + "0cf539e9cfcdd3de653729ead5d1", + 16, + ), + "p": int( + "d32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262864a9" + "cb9f30af38be448598d413a172efb802c21acf1c11c520c2f26a471dc" + "ad212eac7ca39d", + 16, + ), + "q": int( + "cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb33d3e3" + "d5cc93c4765703d1dd791642f1f116a0dd852be2419b2af72bfe9a030" + "e860b0288b5d77", + 16, + ), + "dmp1": int( + "0e12bf1718e9cef5599ba1c3882fe8046a90874eefce8f2ccc20e4f27" + "41fb0a33a3848aec9c9305fbecbd2d76819967d4671acc6431e403796" + "8db37878e695c1", + 16, + ), + "dmq1": int( + "95297b0f95a2fa67d00707d609dfd4fc05c89dafc2ef6d6ea55bec771" + "ea333734d9251e79082ecda866efef13c459e1a631386b7e354c899f5" + "f112ca85d71583", + 16, + ), + "iqmp": int( + "4f456c502493bdc0ed2ab756a3a6ed4d67352a697d4216e93212b127a" + "63d5411ce6fa98d5dbefd73263e3728142743818166ed7dd63687dd2a" + "8ca1d2f4fbd8e1", + 16, + ), + "examples": [ { - 'message': b'6628194e12073db03ba94cda9ef9532397d50dba7' - b'9b987004afefe34', - 'seed': b'18b776ea21069d69776a33e96bad48e1dda0a5ef', - 'encryption': b'354fe67b4a126d5d35fe36c777791a3f7ba13d' - b'ef484e2d3908aff722fad468fb21696de95d0b' - b'e911c2d3174f8afcc201035f7b6d8e69402de5' - b'451618c21a535fa9d7bfc5b8dd9fc243f8cf92' - b'7db31322d6e881eaa91a996170e657a05a2664' - b'26d98c88003f8477c1227094a0d9fa1e8c4024' - b'309ce1ecccb5210035d47ac72e8a' - }, { - 'message': b'750c4047f547e8e41411856523298ac9bae245efa' - b'f1397fbe56f9dd5', - 'seed': b'0cc742ce4a9b7f32f951bcb251efd925fe4fe35f', - 'encryption': b'640db1acc58e0568fe5407e5f9b701dff8c3c9' - b'1e716c536fc7fcec6cb5b71c1165988d4a279e' - b'1577d730fc7a29932e3f00c81515236d8d8e31' - b'017a7a09df4352d904cdeb79aa583adcc31ea6' - b'98a4c05283daba9089be5491f67c1a4ee48dc7' - b'4bbbe6643aef846679b4cb395a352d5ed11591' - b'2df696ffe0702932946d71492b44' - } - ] + "message": b"6628194e12073db03ba94cda9ef9532397d50dba7" + b"9b987004afefe34", + "seed": b"18b776ea21069d69776a33e96bad48e1dda0a5ef", + "encryption": b"354fe67b4a126d5d35fe36c777791a3f7ba13d" + b"ef484e2d3908aff722fad468fb21696de95d0b" + b"e911c2d3174f8afcc201035f7b6d8e69402de5" + b"451618c21a535fa9d7bfc5b8dd9fc243f8cf92" + b"7db31322d6e881eaa91a996170e657a05a2664" + b"26d98c88003f8477c1227094a0d9fa1e8c4024" + b"309ce1ecccb5210035d47ac72e8a", + }, + { + "message": b"750c4047f547e8e41411856523298ac9bae245efa" + b"f1397fbe56f9dd5", + "seed": b"0cc742ce4a9b7f32f951bcb251efd925fe4fe35f", + "encryption": b"640db1acc58e0568fe5407e5f9b701dff8c3c9" + b"1e716c536fc7fcec6cb5b71c1165988d4a279e" + b"1577d730fc7a29932e3f00c81515236d8d8e31" + b"017a7a09df4352d904cdeb79aa583adcc31ea6" + b"98a4c05283daba9089be5491f67c1a4ee48dc7" + b"4bbbe6643aef846679b4cb395a352d5ed11591" + b"2df696ffe0702932946d71492b44", + }, + ], }, - { - 'modulus': int( - 'a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae481' - '1a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6' - 'c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb' - '662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616' - 'd4f5ba10d4cfd226de88d39f16fb', 16), - 'public_exponent': int('10001', 16), - } + "modulus": int( + "a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae481" + "1a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6" + "c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb" + "662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616" + "d4f5ba10d4cfd226de88d39f16fb", + 16, + ), + "public_exponent": int("10001", 16), + }, ) ] assert vectors == expected def test_load_hotp_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # HOTP Test Vectors # RFC 4226 Appendix D @@ -1197,7 +1292,8 @@ def test_load_hotp_vectors(): TRUNCATED = 66ef7655 HOTP = 969429 SECRET = 12345678901234567890 - """).splitlines() + """ + ).splitlines() assert load_nist_vectors(vector_data) == [ { @@ -1232,7 +1328,8 @@ def test_load_hotp_vectors(): def test_load_totp_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # TOTP Test Vectors # RFC 6238 Appendix B @@ -1253,7 +1350,8 @@ def test_load_totp_vectors(): TOTP = 90693936 MODE = SHA512 SECRET = 12345678901234567890 - """).splitlines() + """ + ).splitlines() assert load_nist_vectors(vector_data) == [ { @@ -1278,7 +1376,8 @@ def test_load_totp_vectors(): def test_load_rsa_nist_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # CAVS 11.4 # "SigGen PKCS#1 RSASSA-PSS" information # Mod sizes selected: 1024 1536 2048 3072 4096 @@ -1307,33 +1406,40 @@ def test_load_rsa_nist_vectors(): SHAAlg = SHA512 Msg = 3456781293fab829 S = deadbeef0000 - """).splitlines() + """ + ).splitlines() vectors = load_rsa_nist_vectors(vector_data) assert vectors == [ { - "modulus": int("bcb47b2e0dafcba81ff2a2b5cb115ca7e757184c9d72bcdcda" - "707a146b3b4e29989d", 16), + "modulus": int( + "bcb47b2e0dafcba81ff2a2b5cb115ca7e757184c9d72bcdcda" + "707a146b3b4e29989d", + 16, + ), "public_exponent": 65537, "algorithm": "SHA1", "salt_length": 20, "msg": b"1248f62a4389f42f7b4bb131053d6c88a994db2075b912ccbe3ea7dc6" - b"11714f14e", + b"11714f14e", "s": b"682cf53c1145d22a50caa9eb1a9ba70670c5915e0fdfde6457a765de2a8" - b"fe12de97", - "fail": False + b"fe12de97", + "fail": False, }, { - "modulus": int("bcb47b2e0dafcba81ff2a2b5cb115ca7e757184c9d72bcdcda" - "707a146b3b4e29989d", 16), + "modulus": int( + "bcb47b2e0dafcba81ff2a2b5cb115ca7e757184c9d72bcdcda" + "707a146b3b4e29989d", + 16, + ), "public_exponent": 65537, "algorithm": "SHA384", "salt_length": 20, "msg": b"e511903c2f1bfba245467295ac95413ac4746c984c3750a728c388aa6" - b"28b0ebf", + b"28b0ebf", "s": b"9c748702bbcc1f9468864cd360c8c39d007b2d8aaee833606c70f7593cf" - b"0d1519", - "fail": False + b"0d1519", + "fail": False, }, { "modulus": 78187493520, @@ -1342,13 +1448,14 @@ def test_load_rsa_nist_vectors(): "salt_length": 20, "msg": b"3456781293fab829", "s": b"deadbeef0000", - "fail": False + "fail": False, }, ] def test_load_rsa_nist_pkcs1v15_verification_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # CAVS 11.0 # "SigVer PKCS#1 Ver 1.5" information # Mod sizes selected: 1024 1536 2048 3072 4096 @@ -1377,50 +1484,73 @@ def test_load_rsa_nist_pkcs1v15_verification_vectors(): S = 2b91c6ae2b3c46ff18d5b7abe239634cb752d0acb53eea0ccd8ea8483036a50e8faf SaltVal = 11223344555432167890 Result = P - """).splitlines() + """ + ).splitlines() vectors = load_rsa_nist_vectors(vector_data) assert vectors == [ { - "modulus": int("be499b5e7f06c83fa0293e31465c8eb6b58af920bae52a7b5b" - "9bfeb7aa72db126411", 16), - "p": int("e7a80c5d211c06acb900939495f26d365fc2b4825b75e356f89003ea" - "a5931e6be5c3", 16), - "q": int("d248aa248000f720258742da67b711940c8f76e1ecd52b67a6ffe1e4" - "9354d66ff84f", 16), + "modulus": int( + "be499b5e7f06c83fa0293e31465c8eb6b58af920bae52a7b5b" + "9bfeb7aa72db126411", + 16, + ), + "p": int( + "e7a80c5d211c06acb900939495f26d365fc2b4825b75e356f89003ea" + "a5931e6be5c3", + 16, + ), + "q": int( + "d248aa248000f720258742da67b711940c8f76e1ecd52b67a6ffe1e4" + "9354d66ff84f", + 16, + ), "public_exponent": 17, "algorithm": "SHA1", - "private_exponent": int("0d0f17362bdad181db4e1fe03e8de1a3208989914" - "e14bf269558826bfa20faf4b68d", 16), + "private_exponent": int( + "0d0f17362bdad181db4e1fe03e8de1a3208989914" + "e14bf269558826bfa20faf4b68d", + 16, + ), "msg": b"6b9cfac0ba1c7890b13e381ce752195cc1375237db2afcf6a9dcd1f95" - b"ec733a80c", + b"ec733a80c", "s": b"562d87b5781c01d166fef3972669a0495c145b898a17df4743fbefb0a15" - b"82bd6ba9d", + b"82bd6ba9d", "saltval": b"11223344555432167890", - "fail": True + "fail": True, }, { - "modulus": int("be499b5e7f06c83fa0293e31465c8eb6b58af920bae52a7b5b" - "9bfeb7aa72db126411", 16), - "p": int("e7a80c5d211c06acb900939495f26d365fc2b4825b75e356f89003ea" - "a5931e6be5c3", 16), - "q": int("d248aa248000f720258742da67b711940c8f76e1ecd52b67a6ffe1e4" - "9354d66ff84f", 16), + "modulus": int( + "be499b5e7f06c83fa0293e31465c8eb6b58af920bae52a7b5b" + "9bfeb7aa72db126411", + 16, + ), + "p": int( + "e7a80c5d211c06acb900939495f26d365fc2b4825b75e356f89003ea" + "a5931e6be5c3", + 16, + ), + "q": int( + "d248aa248000f720258742da67b711940c8f76e1ecd52b67a6ffe1e4" + "9354d66ff84f", + 16, + ), "public_exponent": 3, "algorithm": "SHA1", "private_exponent": int("bfa20faf4b68d", 16), "msg": b"2a67c70ff14f9b34ddb42e6f89d5971057a0da980fc9ae70c81a84da0" - b"c0ac42737", + b"c0ac42737", "s": b"2b91c6ae2b3c46ff18d5b7abe239634cb752d0acb53eea0ccd8ea848303" - b"6a50e8faf", + b"6a50e8faf", "saltval": b"11223344555432167890", - "fail": False + "fail": False, }, ] def test_load_rsa_nist_pss_verification_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # CAVS 11.0 # "SigVer PKCS#1 RSASSA-PSS" information # Mod sizes selected: 1024 1536 2048 3072 4096 @@ -1450,7 +1580,8 @@ def test_load_rsa_nist_pss_verification_vectors(): S = 2b91c6ae2b3c46ff18d5b7abe239634cb7 SaltVal = 11223344555432167890 Result = P - """).splitlines() + """ + ).splitlines() vectors = load_rsa_nist_vectors(vector_data) assert vectors == [ @@ -1465,7 +1596,7 @@ def test_load_rsa_nist_pss_verification_vectors(): "s": b"562d87b5781c01d166fef3972669a0495c", "saltval": b"11223344555432167890", "salt_length": 10, - "fail": True + "fail": True, }, { "modulus": int("be499b5e7f06c83fa0293e31465c8eb6b5", 16), @@ -1478,13 +1609,14 @@ def test_load_rsa_nist_pss_verification_vectors(): "s": b"2b91c6ae2b3c46ff18d5b7abe239634cb7", "saltval": b"11223344555432167890", "salt_length": 10, - "fail": False + "fail": False, }, ] def test_load_fips_dsa_key_pair_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # CAVS 11.1 # "KeyPair" information # Mod sizes selected: L=1024, N=160:: L=2048, N=224 :: L=2048, N=256 :: L @@ -1599,213 +1731,303 @@ def test_load_fips_dsa_key_pair_vectors(): 623399b473ce712a2184cf2da1861706c41466806aefe41b497db82aca6c31c8f4aa68c17d1d9e\ 380b57998917655783ec96e5234a131f7299398d36f1f5f84297a55ff292f1f060958c358fed34\ 6db2de45127ca728a9417b2c54203e33e53b9a061d924395b09afab8daf3e8dd7eedcec3ac - """).splitlines() + """ + ).splitlines() expected = [ - {'g': int('06b7861abbd35cc89e79c52f68d20875389b127361ca66822138ce499' - '1d2b862259d6b4548a6495b195aa0e0b6137ca37eb23b94074d3c3d3000' - '42bdf15762812b6333ef7b07ceba78607610fcc9ee68491dbc1e34cd12' - '615474e52b18bc934fb00c61d39e7da8902291c4434a4e2224c3f' - '4fd9f93cd6f4f17fc076341a7e7d9', 16), - 'p': int('d38311e2cd388c3ed698e82fdf88eb92b5a9a483dc88005d4b725e' - 'f341eabb47cf8a7a8a41e792a156b7ce97206c4f9c5ce6fc5ae791210' - '2b6b502e59050b5b21ce263dddb2044b652236f4d42ab4b5d6aa73189c' - 'ef1ace778d7845a5c1c1c7147123188f8dc551054ee162b634d60f097f7' - '19076640e20980a0093113a8bd73', 16), - 'q': int('96c5390a8b612c0e422bb2b0ea194a3ec935a281', 16), - 'x': int('8185fee9cc7c0e91fd85503274f1cd5a3fd15a49', 16), - 'y': int('6f26d98d41de7d871b6381851c9d91fa03942092ab6097e76422' - '070edb71db44ff568280fdb1709f8fc3feab39f1f824adaeb2a29808815' - '6ac31af1aa04bf54f475bdcfdcf2f8a2dd973e922d83e76f01655861760' - '3129b21c70bf7d0e5dc9e68fe332e295b65876eb9a12fe6fca9f1a1ce80' - '204646bf99b5771d249a6fea627', 16)}, - {'g': int('06b7861abbd35cc89e79c52f68d20875389b127361ca66822138ce4991d' - '2b862259d6b4548a6495b195aa0e0b6137ca37eb23b94074d3c3d30004' - '2bdf15762812b6333ef7b07ceba78607610fcc9ee68491dbc1e34cd126' - '15474e52b18bc934fb00c61d39e7da8902291c4434a4e2224c3f4fd9' - 'f93cd6f4f17fc076341a7e7d9', 16), - 'p': int('d38311e2cd388c3ed698e82fdf88eb92b5a9a483dc88005d4b725ef341e' - 'abb47cf8a7a8a41e792a156b7ce97206c4f9c5ce6fc5ae7912102b6b50' - '2e59050b5b21ce263dddb2044b652236f4d42ab4b5d6aa73189cef1a' - 'ce778d7845a5c1c1c7147123188f8dc551054ee162b634d6' - '0f097f719076640e20980a0093113a8bd73', 16), - 'q': int('96c5390a8b612c0e422bb2b0ea194a3ec935a281', 16), - 'x': int('85322d6ea73083064376099ca2f65f56e8522d9b', 16), - 'y': int('21f8690f717c9f4dcb8f4b6971de2f15b9231fcf41b7eeb997d781f240' - 'bfdddfd2090d22083c26cca39bf37c9caf1ec89518ea64845a50d747b49' - '131ffff6a2fd11ea7bacbb93c7d05137383a06365af82225dd3713c' - 'a5a45006316f53bd12b0e260d5f79795e5a4c9f353f12867a1d3' - '202394673ada8563b71555e53f415254', 16)}, - - {'g': int('e4c4eca88415b23ecf811c96e48cd24200fe916631a68a684e6ccb6b191' - '3413d344d1d8d84a333839d88eee431521f6e357c16e6a93be111a9807' - '6739cd401bab3b9d565bf4fb99e9d185b1e14d61c93700133f908bae0' - '3e28764d107dcd2ea7674217622074bb19efff482f5f5c1a86d5551b2' - 'fc68d1c6e9d8011958ef4b9c2a3a55d0d3c882e6ad7f9f0f3c61568f78' - 'd0706b10a26f23b4f197c322b825002284a0aca91807bba98ece912' - 'b80e10cdf180cf99a35f210c1655fbfdd74f13b1b5046591f8403873d' - '12239834dd6c4eceb42bf7482e1794a1601357b629ddfa971f2ed273b1' - '46ec1ca06d0adf55dd91d65c37297bda78c6d210c0bc26e558302', 16), - 'p': int('ea1fb1af22881558ef93be8a5f8653c5a559434c49c8c2c12ace' - '5e9c41434c9cf0a8e9498acb0f4663c08b4484eace845f6fb17d' - 'ac62c98e706af0fc74e4da1c6c2b3fbf5a1d58ff82fc1a66f3e8b122' - '52c40278fff9dd7f102eed2cb5b7323ebf1908c234d935414dded7f8d2' - '44e54561b0dca39b301de8c49da9fb23df33c6182e3f983208c560fb5' - '119fbf78ebe3e6564ee235c6a15cbb9ac247baba5a423bc6582a1a9d8a' - '2b4f0e9e3d9dbac122f750dd754325135257488b1f6ecabf21bff2947' - 'fe0d3b2cb7ffe67f4e7fcdf1214f6053e72a5bb0dd20a0e9fe6db2df0a' - '908c36e95e60bf49ca4368b8b892b9c79f61ef91c47567c40e1f80ac' - '5aa66ef7', 16), - 'q': int('8ec73f3761caf5fdfe6e4e82098bf10f898740dcb808204bf6b1' - '8f507192c19d', 16), - 'x': int('405772da6e90d809e77d5de796562a2dd4dfd10ef00a83a3aba6' - 'bd818a0348a1', 16), - 'y': int('6b32e31ab9031dc4dd0b5039a78d07826687ab087ae6de4736f5' - 'b0434e1253092e8a0b231f9c87f3fc8a4cb5634eb194bf1b638' - 'b7a7889620ce6711567e36aa36cda4604cfaa601a45918371d' - '4ccf68d8b10a50a0460eb1dc0fff62ef5e6ee4d473e18ea4a6' - '6c196fb7e677a49b48241a0b4a97128eff30fa437050501a584' - 'f8771e7280d26d5af30784039159c11ebfea10b692fd0a58215ee' - 'b18bff117e13f08db792ed4151a218e4bed8dddfb0793225bd1e97' - '73505166f4bd8cedbb286ea28232972da7bae836ba97329ba6b0a36508' - 'e50a52a7675e476d4d4137eae13f22a9d2fefde708ba8f34bf336c6e7' - '6331761e4b0617633fe7ec3f23672fb19d27', 16)}, - {'g': int('e4c4eca88415b23ecf811c96e48cd24200fe916631a68a684e6ccb6b191' - '3413d344d1d8d84a333839d88eee431521f6e357c16e6a93be111a9807' - '6739cd401bab3b9d565bf4fb99e9d185b1e14d61c93700133f908bae0' - '3e28764d107dcd2ea7674217622074bb19efff482f5f5c1a86d5551b2' - 'fc68d1c6e9d8011958ef4b9c2a3a55d0d3c882e6ad7f9f0f3c61568f78' - 'd0706b10a26f23b4f197c322b825002284a0aca91807bba98ece912' - 'b80e10cdf180cf99a35f210c1655fbfdd74f13b1b5046591f8403873d' - '12239834dd6c4eceb42bf7482e1794a1601357b629ddfa971f2ed273b1' - '46ec1ca06d0adf55dd91d65c37297bda78c6d210c0bc26e558302', 16), - 'p': int('ea1fb1af22881558ef93be8a5f8653c5a559434c49c8c2c12ace' - '5e9c41434c9cf0a8e9498acb0f4663c08b4484eace845f6fb17d' - 'ac62c98e706af0fc74e4da1c6c2b3fbf5a1d58ff82fc1a66f3e8b122' - '52c40278fff9dd7f102eed2cb5b7323ebf1908c234d935414dded7f8d2' - '44e54561b0dca39b301de8c49da9fb23df33c6182e3f983208c560fb5' - '119fbf78ebe3e6564ee235c6a15cbb9ac247baba5a423bc6582a1a9d8a' - '2b4f0e9e3d9dbac122f750dd754325135257488b1f6ecabf21bff2947' - 'fe0d3b2cb7ffe67f4e7fcdf1214f6053e72a5bb0dd20a0e9fe6db2df0a' - '908c36e95e60bf49ca4368b8b892b9c79f61ef91c47567c40e1f80ac' - '5aa66ef7', 16), - 'q': int('8ec73f3761caf5fdfe6e4e82098bf10f898740dcb808204bf6b1' - '8f507192c19d', 16), - 'x': int('0e0b95e31fda3f888059c46c3002ef8f2d6be112d0209aeb9e95' - '45da67aeea80', 16), - 'y': int('778082b77ddba6f56597cc74c3a612abf2ddbd85cc81430c99ab' - '843c1f630b9db0139965f563978164f9bf3a8397256be714625' - 'cd41cd7fa0067d94ea66d7e073f7125af692ad01371d4a17f45' - '50590378f2b074030c20e36911598a1018772f61be3b24de4be' - '5a388ccc09e15a92819c31dec50de9fde105b49eaa097b9d13d' - '9219eeb33b628facfd1c78a7159c8430d0647c506e7e3de74763c' - 'b351eada72c00bef3c9641881e6254870c1e6599f8ca2f1bbb74f' - '39a905e3a34e4544168e6e50c9e3305fd09cab6ed4aff6fda6e0d' - '5bf375c81ac9054406d9193b003c89272f1bd83d48250134b65c77' - 'c2b6332d38d34d9016f0e8975536ad6c348a1faedb0', 16)}, - - {'g': int('ce84b30ddf290a9f787a7c2f1ce92c1cbf4ef400e3cd7ce4978d' - 'b2104d7394b493c18332c64cec906a71c3778bd93341165dee8' - 'e6cd4ca6f13afff531191194ada55ecf01ff94d6cf7c4768b82' - 'dd29cd131aaf202aefd40e564375285c01f3220af4d70b96f1' - '395420d778228f1461f5d0b8e47357e87b1fe3286223b553e3' - 'fc9928f16ae3067ded6721bedf1d1a01bfd22b9ae85fce77820d88cdf' - '50a6bde20668ad77a707d1c60fcc5d51c9de488610d0285eb8ff721f' - 'f141f93a9fb23c1d1f7654c07c46e58836d1652828f71057b8aff0b077' - '8ef2ca934ea9d0f37daddade2d823a4d8e362721082e279d003b575ee' - '59fd050d105dfd71cd63154efe431a0869178d9811f4f231dc5dcf3b' - '0ec0f2b0f9896c32ec6c7ee7d60aa97109e09224907328d4e6acd1011' - '7e45774406c4c947da8020649c3168f690e0bd6e91ac67074d1d436b' - '58ae374523deaf6c93c1e6920db4a080b744804bb073cecfe83fa939' - '8cf150afa286dc7eb7949750cf5001ce104e9187f7e16859afa8fd0d' - '775ae', 16), - 'p': int('f335666dd1339165af8b9a5e3835adfe15c158e4c3c7bd53132e7d5828' - 'c352f593a9a787760ce34b789879941f2f01f02319f6ae0b756f1a842' - 'ba54c85612ed632ee2d79ef17f06b77c641b7b080aff52a03fc2462e8' - '0abc64d223723c236deeb7d201078ec01ca1fbc1763139e25099a84ec' - '389159c409792080736bd7caa816b92edf23f2c351f90074aa5ea2651' - 'b372f8b58a0a65554db2561d706a63685000ac576b7e4562e262a1428' - '5a9c6370b290e4eb7757527d80b6c0fd5df831d36f3d1d35f12ab0605' - '48de1605fd15f7c7aafed688b146a02c945156e284f5b71282045aba9' - '844d48b5df2e9e7a5887121eae7d7b01db7cdf6ff917cd8eb50c6bf1d' - '54f90cce1a491a9c74fea88f7e7230b047d16b5a6027881d6f154818f' - '06e513faf40c8814630e4e254f17a47bfe9cb519b98289935bf17673a' - 'e4c8033504a20a898d0032ee402b72d5986322f3bdfb27400561f7476' - 'cd715eaabb7338b854e51fc2fa026a5a579b6dcea1b1c0559c13d3c11' - '36f303f4b4d25ad5b692229957', 16), - 'q': int('d3eba6521240694015ef94412e08bf3cf8d635a455a398d6f210' - 'f6169041653b', 16), - 'x': int('b2764c46113983777d3e7e97589f1303806d14ad9f2f1ef03309' - '7de954b17706', 16), - 'y': int('814824e435e1e6f38daa239aad6dad21033afce6a3ebd35c1359348a0f2' - '418871968c2babfc2baf47742148828f8612183178f126504da73566b6' - 'bab33ba1f124c15aa461555c2451d86c94ee21c3e3fc24c55527e' - '01b1f03adcdd8ec5cb08082803a7b6a829c3e99eeb332a2cf5c035b0c' - 'e0078d3d414d31fa47e9726be2989b8d06da2e6cd363f5a7d1515e3f4' - '925e0b32adeae3025cc5a996f6fd27494ea408763de48f3bb39f6a06' - '514b019899b312ec570851637b8865cff3a52bf5d54ad5a19e6e400' - 'a2d33251055d0a440b50d53f4791391dc754ad02b9eab74c46b4903' - 'f9d76f824339914db108057af7cde657d41766a99991ac8787694f' - '4185d6f91d7627048f827b405ec67bf2fe56141c4c581d8c317333' - '624e073e5879a82437cb0c7b435c0ce434e15965db1315d648959' - '91e6bbe7dac040c42052408bbc53423fd31098248a58f8a67da3a' - '39895cd0cc927515d044c1e3cb6a3259c3d0da354cce89ea3552c' - '59609db10ee989986527436af21d9485ddf25f90f7dff6d2bae', 16)}, - {'g': int('ce84b30ddf290a9f787a7c2f1ce92c1cbf4ef400e3cd7ce4978d' - 'b2104d7394b493c18332c64cec906a71c3778bd93341165dee8' - 'e6cd4ca6f13afff531191194ada55ecf01ff94d6cf7c4768b82' - 'dd29cd131aaf202aefd40e564375285c01f3220af4d70b96f1' - '395420d778228f1461f5d0b8e47357e87b1fe3286223b553e3' - 'fc9928f16ae3067ded6721bedf1d1a01bfd22b9ae85fce77820d88cdf' - '50a6bde20668ad77a707d1c60fcc5d51c9de488610d0285eb8ff721f' - 'f141f93a9fb23c1d1f7654c07c46e58836d1652828f71057b8aff0b077' - '8ef2ca934ea9d0f37daddade2d823a4d8e362721082e279d003b575ee' - '59fd050d105dfd71cd63154efe431a0869178d9811f4f231dc5dcf3b' - '0ec0f2b0f9896c32ec6c7ee7d60aa97109e09224907328d4e6acd1011' - '7e45774406c4c947da8020649c3168f690e0bd6e91ac67074d1d436b' - '58ae374523deaf6c93c1e6920db4a080b744804bb073cecfe83fa939' - '8cf150afa286dc7eb7949750cf5001ce104e9187f7e16859afa8fd0d' - '775ae', 16), - 'p': int('f335666dd1339165af8b9a5e3835adfe15c158e4c3c7bd53132e7d5828' - 'c352f593a9a787760ce34b789879941f2f01f02319f6ae0b756f1a842' - 'ba54c85612ed632ee2d79ef17f06b77c641b7b080aff52a03fc2462e8' - '0abc64d223723c236deeb7d201078ec01ca1fbc1763139e25099a84ec' - '389159c409792080736bd7caa816b92edf23f2c351f90074aa5ea2651' - 'b372f8b58a0a65554db2561d706a63685000ac576b7e4562e262a1428' - '5a9c6370b290e4eb7757527d80b6c0fd5df831d36f3d1d35f12ab0605' - '48de1605fd15f7c7aafed688b146a02c945156e284f5b71282045aba9' - '844d48b5df2e9e7a5887121eae7d7b01db7cdf6ff917cd8eb50c6bf1d' - '54f90cce1a491a9c74fea88f7e7230b047d16b5a6027881d6f154818f' - '06e513faf40c8814630e4e254f17a47bfe9cb519b98289935bf17673a' - 'e4c8033504a20a898d0032ee402b72d5986322f3bdfb27400561f7476' - 'cd715eaabb7338b854e51fc2fa026a5a579b6dcea1b1c0559c13d3c11' - '36f303f4b4d25ad5b692229957', 16), - 'q': int('d3eba6521240694015ef94412e08bf3cf8d635a455a398d6f210' - 'f6169041653b', 16), - 'x': int('52e3e040efb30e1befd909a0bdbcfd140d005b1bff094af97186' - '080262f1904d', 16), - 'y': int('a5ae6e8f9b7a68ab0516dad4d7b7d002126f811d5a52e3d35c6d' - '387fcb43fd19bf7792362f9c98f8348aa058bb62376685f3d0c3' - '66c520d697fcd8416947151d4bbb6f32b53528a016479e99d2cd' - '48d1fc679027c15f0042f207984efe05c1796bca8eba678dfdd0' - '0b80418e3ea840557e73b09e003882f9a68edba3431d351d1ca0' - '7a8150b018fdbdf6c2f1ab475792a3ccaa6594472a45f8dc777b' - '60bf67de3e0f65c20d11b7d59faedf83fbce52617f500d9e5149' - '47c455274c6e900464767fb56599b81344cf6d12c25cb2b7d038' - 'd7b166b6cf30534811c15d0e8ab880a2ac06786ae2ddde61329a' - '78d526f65245380ce877e979c5b50de66c9c30d66382c8f25465' - '3d25a1eb1d3a4897d7623399b473ce712a2184cf2da1861706c4' - '1466806aefe41b497db82aca6c31c8f4aa68c17d1d9e380b5799' - '8917655783ec96e5234a131f7299398d36f1f5f84297a55ff292' - 'f1f060958c358fed346db2de45127ca728a9417b2c54203e33e5' - '3b9a061d924395b09afab8daf3e8dd7eedcec3ac', 16)} + { + "g": int( + "06b7861abbd35cc89e79c52f68d20875389b127361ca66822138ce499" + "1d2b862259d6b4548a6495b195aa0e0b6137ca37eb23b94074d3c3d3000" + "42bdf15762812b6333ef7b07ceba78607610fcc9ee68491dbc1e34cd12" + "615474e52b18bc934fb00c61d39e7da8902291c4434a4e2224c3f" + "4fd9f93cd6f4f17fc076341a7e7d9", + 16, + ), + "p": int( + "d38311e2cd388c3ed698e82fdf88eb92b5a9a483dc88005d4b725e" + "f341eabb47cf8a7a8a41e792a156b7ce97206c4f9c5ce6fc5ae791210" + "2b6b502e59050b5b21ce263dddb2044b652236f4d42ab4b5d6aa73189c" + "ef1ace778d7845a5c1c1c7147123188f8dc551054ee162b634d60f097f7" + "19076640e20980a0093113a8bd73", + 16, + ), + "q": int("96c5390a8b612c0e422bb2b0ea194a3ec935a281", 16), + "x": int("8185fee9cc7c0e91fd85503274f1cd5a3fd15a49", 16), + "y": int( + "6f26d98d41de7d871b6381851c9d91fa03942092ab6097e76422" + "070edb71db44ff568280fdb1709f8fc3feab39f1f824adaeb2a29808815" + "6ac31af1aa04bf54f475bdcfdcf2f8a2dd973e922d83e76f01655861760" + "3129b21c70bf7d0e5dc9e68fe332e295b65876eb9a12fe6fca9f1a1ce80" + "204646bf99b5771d249a6fea627", + 16, + ), + }, + { + "g": int( + "06b7861abbd35cc89e79c52f68d20875389b127361ca66822138ce4991d" + "2b862259d6b4548a6495b195aa0e0b6137ca37eb23b94074d3c3d30004" + "2bdf15762812b6333ef7b07ceba78607610fcc9ee68491dbc1e34cd126" + "15474e52b18bc934fb00c61d39e7da8902291c4434a4e2224c3f4fd9" + "f93cd6f4f17fc076341a7e7d9", + 16, + ), + "p": int( + "d38311e2cd388c3ed698e82fdf88eb92b5a9a483dc88005d4b725ef341e" + "abb47cf8a7a8a41e792a156b7ce97206c4f9c5ce6fc5ae7912102b6b50" + "2e59050b5b21ce263dddb2044b652236f4d42ab4b5d6aa73189cef1a" + "ce778d7845a5c1c1c7147123188f8dc551054ee162b634d6" + "0f097f719076640e20980a0093113a8bd73", + 16, + ), + "q": int("96c5390a8b612c0e422bb2b0ea194a3ec935a281", 16), + "x": int("85322d6ea73083064376099ca2f65f56e8522d9b", 16), + "y": int( + "21f8690f717c9f4dcb8f4b6971de2f15b9231fcf41b7eeb997d781f240" + "bfdddfd2090d22083c26cca39bf37c9caf1ec89518ea64845a50d747b49" + "131ffff6a2fd11ea7bacbb93c7d05137383a06365af82225dd3713c" + "a5a45006316f53bd12b0e260d5f79795e5a4c9f353f12867a1d3" + "202394673ada8563b71555e53f415254", + 16, + ), + }, + { + "g": int( + "e4c4eca88415b23ecf811c96e48cd24200fe916631a68a684e6ccb6b191" + "3413d344d1d8d84a333839d88eee431521f6e357c16e6a93be111a9807" + "6739cd401bab3b9d565bf4fb99e9d185b1e14d61c93700133f908bae0" + "3e28764d107dcd2ea7674217622074bb19efff482f5f5c1a86d5551b2" + "fc68d1c6e9d8011958ef4b9c2a3a55d0d3c882e6ad7f9f0f3c61568f78" + "d0706b10a26f23b4f197c322b825002284a0aca91807bba98ece912" + "b80e10cdf180cf99a35f210c1655fbfdd74f13b1b5046591f8403873d" + "12239834dd6c4eceb42bf7482e1794a1601357b629ddfa971f2ed273b1" + "46ec1ca06d0adf55dd91d65c37297bda78c6d210c0bc26e558302", + 16, + ), + "p": int( + "ea1fb1af22881558ef93be8a5f8653c5a559434c49c8c2c12ace" + "5e9c41434c9cf0a8e9498acb0f4663c08b4484eace845f6fb17d" + "ac62c98e706af0fc74e4da1c6c2b3fbf5a1d58ff82fc1a66f3e8b122" + "52c40278fff9dd7f102eed2cb5b7323ebf1908c234d935414dded7f8d2" + "44e54561b0dca39b301de8c49da9fb23df33c6182e3f983208c560fb5" + "119fbf78ebe3e6564ee235c6a15cbb9ac247baba5a423bc6582a1a9d8a" + "2b4f0e9e3d9dbac122f750dd754325135257488b1f6ecabf21bff2947" + "fe0d3b2cb7ffe67f4e7fcdf1214f6053e72a5bb0dd20a0e9fe6db2df0a" + "908c36e95e60bf49ca4368b8b892b9c79f61ef91c47567c40e1f80ac" + "5aa66ef7", + 16, + ), + "q": int( + "8ec73f3761caf5fdfe6e4e82098bf10f898740dcb808204bf6b1" + "8f507192c19d", + 16, + ), + "x": int( + "405772da6e90d809e77d5de796562a2dd4dfd10ef00a83a3aba6" + "bd818a0348a1", + 16, + ), + "y": int( + "6b32e31ab9031dc4dd0b5039a78d07826687ab087ae6de4736f5" + "b0434e1253092e8a0b231f9c87f3fc8a4cb5634eb194bf1b638" + "b7a7889620ce6711567e36aa36cda4604cfaa601a45918371d" + "4ccf68d8b10a50a0460eb1dc0fff62ef5e6ee4d473e18ea4a6" + "6c196fb7e677a49b48241a0b4a97128eff30fa437050501a584" + "f8771e7280d26d5af30784039159c11ebfea10b692fd0a58215ee" + "b18bff117e13f08db792ed4151a218e4bed8dddfb0793225bd1e97" + "73505166f4bd8cedbb286ea28232972da7bae836ba97329ba6b0a36508" + "e50a52a7675e476d4d4137eae13f22a9d2fefde708ba8f34bf336c6e7" + "6331761e4b0617633fe7ec3f23672fb19d27", + 16, + ), + }, + { + "g": int( + "e4c4eca88415b23ecf811c96e48cd24200fe916631a68a684e6ccb6b191" + "3413d344d1d8d84a333839d88eee431521f6e357c16e6a93be111a9807" + "6739cd401bab3b9d565bf4fb99e9d185b1e14d61c93700133f908bae0" + "3e28764d107dcd2ea7674217622074bb19efff482f5f5c1a86d5551b2" + "fc68d1c6e9d8011958ef4b9c2a3a55d0d3c882e6ad7f9f0f3c61568f78" + "d0706b10a26f23b4f197c322b825002284a0aca91807bba98ece912" + "b80e10cdf180cf99a35f210c1655fbfdd74f13b1b5046591f8403873d" + "12239834dd6c4eceb42bf7482e1794a1601357b629ddfa971f2ed273b1" + "46ec1ca06d0adf55dd91d65c37297bda78c6d210c0bc26e558302", + 16, + ), + "p": int( + "ea1fb1af22881558ef93be8a5f8653c5a559434c49c8c2c12ace" + "5e9c41434c9cf0a8e9498acb0f4663c08b4484eace845f6fb17d" + "ac62c98e706af0fc74e4da1c6c2b3fbf5a1d58ff82fc1a66f3e8b122" + "52c40278fff9dd7f102eed2cb5b7323ebf1908c234d935414dded7f8d2" + "44e54561b0dca39b301de8c49da9fb23df33c6182e3f983208c560fb5" + "119fbf78ebe3e6564ee235c6a15cbb9ac247baba5a423bc6582a1a9d8a" + "2b4f0e9e3d9dbac122f750dd754325135257488b1f6ecabf21bff2947" + "fe0d3b2cb7ffe67f4e7fcdf1214f6053e72a5bb0dd20a0e9fe6db2df0a" + "908c36e95e60bf49ca4368b8b892b9c79f61ef91c47567c40e1f80ac" + "5aa66ef7", + 16, + ), + "q": int( + "8ec73f3761caf5fdfe6e4e82098bf10f898740dcb808204bf6b1" + "8f507192c19d", + 16, + ), + "x": int( + "0e0b95e31fda3f888059c46c3002ef8f2d6be112d0209aeb9e95" + "45da67aeea80", + 16, + ), + "y": int( + "778082b77ddba6f56597cc74c3a612abf2ddbd85cc81430c99ab" + "843c1f630b9db0139965f563978164f9bf3a8397256be714625" + "cd41cd7fa0067d94ea66d7e073f7125af692ad01371d4a17f45" + "50590378f2b074030c20e36911598a1018772f61be3b24de4be" + "5a388ccc09e15a92819c31dec50de9fde105b49eaa097b9d13d" + "9219eeb33b628facfd1c78a7159c8430d0647c506e7e3de74763c" + "b351eada72c00bef3c9641881e6254870c1e6599f8ca2f1bbb74f" + "39a905e3a34e4544168e6e50c9e3305fd09cab6ed4aff6fda6e0d" + "5bf375c81ac9054406d9193b003c89272f1bd83d48250134b65c77" + "c2b6332d38d34d9016f0e8975536ad6c348a1faedb0", + 16, + ), + }, + { + "g": int( + "ce84b30ddf290a9f787a7c2f1ce92c1cbf4ef400e3cd7ce4978d" + "b2104d7394b493c18332c64cec906a71c3778bd93341165dee8" + "e6cd4ca6f13afff531191194ada55ecf01ff94d6cf7c4768b82" + "dd29cd131aaf202aefd40e564375285c01f3220af4d70b96f1" + "395420d778228f1461f5d0b8e47357e87b1fe3286223b553e3" + "fc9928f16ae3067ded6721bedf1d1a01bfd22b9ae85fce77820d88cdf" + "50a6bde20668ad77a707d1c60fcc5d51c9de488610d0285eb8ff721f" + "f141f93a9fb23c1d1f7654c07c46e58836d1652828f71057b8aff0b077" + "8ef2ca934ea9d0f37daddade2d823a4d8e362721082e279d003b575ee" + "59fd050d105dfd71cd63154efe431a0869178d9811f4f231dc5dcf3b" + "0ec0f2b0f9896c32ec6c7ee7d60aa97109e09224907328d4e6acd1011" + "7e45774406c4c947da8020649c3168f690e0bd6e91ac67074d1d436b" + "58ae374523deaf6c93c1e6920db4a080b744804bb073cecfe83fa939" + "8cf150afa286dc7eb7949750cf5001ce104e9187f7e16859afa8fd0d" + "775ae", + 16, + ), + "p": int( + "f335666dd1339165af8b9a5e3835adfe15c158e4c3c7bd53132e7d5828" + "c352f593a9a787760ce34b789879941f2f01f02319f6ae0b756f1a842" + "ba54c85612ed632ee2d79ef17f06b77c641b7b080aff52a03fc2462e8" + "0abc64d223723c236deeb7d201078ec01ca1fbc1763139e25099a84ec" + "389159c409792080736bd7caa816b92edf23f2c351f90074aa5ea2651" + "b372f8b58a0a65554db2561d706a63685000ac576b7e4562e262a1428" + "5a9c6370b290e4eb7757527d80b6c0fd5df831d36f3d1d35f12ab0605" + "48de1605fd15f7c7aafed688b146a02c945156e284f5b71282045aba9" + "844d48b5df2e9e7a5887121eae7d7b01db7cdf6ff917cd8eb50c6bf1d" + "54f90cce1a491a9c74fea88f7e7230b047d16b5a6027881d6f154818f" + "06e513faf40c8814630e4e254f17a47bfe9cb519b98289935bf17673a" + "e4c8033504a20a898d0032ee402b72d5986322f3bdfb27400561f7476" + "cd715eaabb7338b854e51fc2fa026a5a579b6dcea1b1c0559c13d3c11" + "36f303f4b4d25ad5b692229957", + 16, + ), + "q": int( + "d3eba6521240694015ef94412e08bf3cf8d635a455a398d6f210" + "f6169041653b", + 16, + ), + "x": int( + "b2764c46113983777d3e7e97589f1303806d14ad9f2f1ef03309" + "7de954b17706", + 16, + ), + "y": int( + "814824e435e1e6f38daa239aad6dad21033afce6a3ebd35c1359348a0f2" + "418871968c2babfc2baf47742148828f8612183178f126504da73566b6" + "bab33ba1f124c15aa461555c2451d86c94ee21c3e3fc24c55527e" + "01b1f03adcdd8ec5cb08082803a7b6a829c3e99eeb332a2cf5c035b0c" + "e0078d3d414d31fa47e9726be2989b8d06da2e6cd363f5a7d1515e3f4" + "925e0b32adeae3025cc5a996f6fd27494ea408763de48f3bb39f6a06" + "514b019899b312ec570851637b8865cff3a52bf5d54ad5a19e6e400" + "a2d33251055d0a440b50d53f4791391dc754ad02b9eab74c46b4903" + "f9d76f824339914db108057af7cde657d41766a99991ac8787694f" + "4185d6f91d7627048f827b405ec67bf2fe56141c4c581d8c317333" + "624e073e5879a82437cb0c7b435c0ce434e15965db1315d648959" + "91e6bbe7dac040c42052408bbc53423fd31098248a58f8a67da3a" + "39895cd0cc927515d044c1e3cb6a3259c3d0da354cce89ea3552c" + "59609db10ee989986527436af21d9485ddf25f90f7dff6d2bae", + 16, + ), + }, + { + "g": int( + "ce84b30ddf290a9f787a7c2f1ce92c1cbf4ef400e3cd7ce4978d" + "b2104d7394b493c18332c64cec906a71c3778bd93341165dee8" + "e6cd4ca6f13afff531191194ada55ecf01ff94d6cf7c4768b82" + "dd29cd131aaf202aefd40e564375285c01f3220af4d70b96f1" + "395420d778228f1461f5d0b8e47357e87b1fe3286223b553e3" + "fc9928f16ae3067ded6721bedf1d1a01bfd22b9ae85fce77820d88cdf" + "50a6bde20668ad77a707d1c60fcc5d51c9de488610d0285eb8ff721f" + "f141f93a9fb23c1d1f7654c07c46e58836d1652828f71057b8aff0b077" + "8ef2ca934ea9d0f37daddade2d823a4d8e362721082e279d003b575ee" + "59fd050d105dfd71cd63154efe431a0869178d9811f4f231dc5dcf3b" + "0ec0f2b0f9896c32ec6c7ee7d60aa97109e09224907328d4e6acd1011" + "7e45774406c4c947da8020649c3168f690e0bd6e91ac67074d1d436b" + "58ae374523deaf6c93c1e6920db4a080b744804bb073cecfe83fa939" + "8cf150afa286dc7eb7949750cf5001ce104e9187f7e16859afa8fd0d" + "775ae", + 16, + ), + "p": int( + "f335666dd1339165af8b9a5e3835adfe15c158e4c3c7bd53132e7d5828" + "c352f593a9a787760ce34b789879941f2f01f02319f6ae0b756f1a842" + "ba54c85612ed632ee2d79ef17f06b77c641b7b080aff52a03fc2462e8" + "0abc64d223723c236deeb7d201078ec01ca1fbc1763139e25099a84ec" + "389159c409792080736bd7caa816b92edf23f2c351f90074aa5ea2651" + "b372f8b58a0a65554db2561d706a63685000ac576b7e4562e262a1428" + "5a9c6370b290e4eb7757527d80b6c0fd5df831d36f3d1d35f12ab0605" + "48de1605fd15f7c7aafed688b146a02c945156e284f5b71282045aba9" + "844d48b5df2e9e7a5887121eae7d7b01db7cdf6ff917cd8eb50c6bf1d" + "54f90cce1a491a9c74fea88f7e7230b047d16b5a6027881d6f154818f" + "06e513faf40c8814630e4e254f17a47bfe9cb519b98289935bf17673a" + "e4c8033504a20a898d0032ee402b72d5986322f3bdfb27400561f7476" + "cd715eaabb7338b854e51fc2fa026a5a579b6dcea1b1c0559c13d3c11" + "36f303f4b4d25ad5b692229957", + 16, + ), + "q": int( + "d3eba6521240694015ef94412e08bf3cf8d635a455a398d6f210" + "f6169041653b", + 16, + ), + "x": int( + "52e3e040efb30e1befd909a0bdbcfd140d005b1bff094af97186" + "080262f1904d", + 16, + ), + "y": int( + "a5ae6e8f9b7a68ab0516dad4d7b7d002126f811d5a52e3d35c6d" + "387fcb43fd19bf7792362f9c98f8348aa058bb62376685f3d0c3" + "66c520d697fcd8416947151d4bbb6f32b53528a016479e99d2cd" + "48d1fc679027c15f0042f207984efe05c1796bca8eba678dfdd0" + "0b80418e3ea840557e73b09e003882f9a68edba3431d351d1ca0" + "7a8150b018fdbdf6c2f1ab475792a3ccaa6594472a45f8dc777b" + "60bf67de3e0f65c20d11b7d59faedf83fbce52617f500d9e5149" + "47c455274c6e900464767fb56599b81344cf6d12c25cb2b7d038" + "d7b166b6cf30534811c15d0e8ab880a2ac06786ae2ddde61329a" + "78d526f65245380ce877e979c5b50de66c9c30d66382c8f25465" + "3d25a1eb1d3a4897d7623399b473ce712a2184cf2da1861706c4" + "1466806aefe41b497db82aca6c31c8f4aa68c17d1d9e380b5799" + "8917655783ec96e5234a131f7299398d36f1f5f84297a55ff292" + "f1f060958c358fed346db2de45127ca728a9417b2c54203e33e5" + "3b9a061d924395b09afab8daf3e8dd7eedcec3ac", + 16, + ), + }, ] assert expected == load_fips_dsa_key_pair_vectors(vector_data) def test_load_fips_dsa_sig_ver_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # CAVS 11.0 # "SigVer" information # Mod sizes selected: SHA-1 L=1024, N=160,SHA-384 L=2048, N=256 @@ -1902,166 +2124,236 @@ def test_load_fips_dsa_sig_ver_vectors(): R = 343ea0a9e66277380f604d5880fca686bffab69ca97bfba015a102a7e23dce0e S = 6258488c770e0f5ad7b9da8bade5023fc0d17c6ec517bd08d53e6dc01ac5c2b3 Result = P - """).splitlines() + """ + ).splitlines() expected = [ { - 'p': int('dc5bf3a88b2d99e4c95cdd7a0501cc38630d425cf5c390af3429cff1' - 'f35147b795caea923f0d3577158f8a0c89dabd1962c2c453306b5d70' - 'cacfb01430aceb54e5a5fa6f9340d3bd2da612fceeb76b0ec1ebfae6' - '35a56ab141b108e00dc76eefe2edd0c514c21c457457c39065dba9d0' - 'ecb7569c247172d8438ad2827b60435b', 16), - 'q': int('e956602b83d195dbe945b3ac702fc61f81571f1d', 16), - 'g': int('d7eb9ca20a3c7a079606bafc4c9261ccaba303a5dc9fe9953f197dfe' - '548c234895baa77f441ee6a2d97b909cbbd26ff7b869d24cae51b5c6' - 'edb127a4b5d75cd8b46608bfa148249dffdb59807c5d7dde3fe3080c' - 'a3a2d28312142becb1fa8e24003e21c7287108174b95d5bc711e1c8d' - '9b1076784f5dc37a964a5e51390da713', 16), - 'digest_algorithm': 'SHA-1', - 'msg': binascii.unhexlify( - b'0fe1bfee500bdb76026099b1d37553f6bdfe48c82094ef98cb309dd77733' - b'0bedfaa2f94c823ef74ef4074b50d8706041ac0e371c7c22dcf70263b8d6' - b'0e17a86c7c379cfda8f22469e0df9d49d59439fc99891873628fff25dda5' - b'fac5ac794e948babdde968143ba05f1128f34fdad5875edc4cd71c6c24ba' - b'2060ffbd439ce2b3'), - 'x': int('1d93010c29ecfc432188942f46f19f44f0e1bb5d', 16), - 'y': int('6240ea0647117c38fe705106d56db578f3e10130928452d4f3587881' - 'b8a2bc6873a8befc3237f20914e2a91c7f07a928ee22adeed23d74ab' - '7f82ea11f70497e578f7a9b4cbd6f10226222b0b4da2ea1e49813d6b' - 'b9882fbf675c0846bb80cc891857b89b0ef1beb6cce3378a9aab5d66' - 'ad4cb9277cf447dfe1e64434749432fb', 16), - 'r': int('b5af307867fb8b54390013cc67020ddf1f2c0b81', 16), - 's': int('620d3b22ab5031440c3e35eab6f481298f9e9f08', 16), - 'result': 'P'}, - { - 'p': int('dc5bf3a88b2d99e4c95cdd7a0501cc38630d425cf5c390af3429cff1' - 'f35147b795caea923f0d3577158f8a0c89dabd1962c2c453306b5d70' - 'cacfb01430aceb54e5a5fa6f9340d3bd2da612fceeb76b0ec1ebfae6' - '35a56ab141b108e00dc76eefe2edd0c514c21c457457c39065dba9d0' - 'ecb7569c247172d8438ad2827b60435b', 16), - 'q': int('e956602b83d195dbe945b3ac702fc61f81571f1d', 16), - 'g': int('d7eb9ca20a3c7a079606bafc4c9261ccaba303a5dc9fe9953f197dfe' - '548c234895baa77f441ee6a2d97b909cbbd26ff7b869d24cae51b5c6' - 'edb127a4b5d75cd8b46608bfa148249dffdb59807c5d7dde3fe3080c' - 'a3a2d28312142becb1fa8e24003e21c7287108174b95d5bc711e1c8d' - '9b1076784f5dc37a964a5e51390da713', 16), - 'digest_algorithm': 'SHA-1', - 'msg': binascii.unhexlify( - b'97d50898025d2f9ba633866e968ca75e969d394edba6517204cb3dd537c2' - b'ba38778a2dc9dbc685a915e5676fcd43bc3726bc59ce3d7a9fae35565082' - b'a069c139fa37c90d922b126933db3fa6c5ef6b1edf00d174a51887bb7690' - b'9c6a94fe994ecc7b7fc8f26113b17f30f9d01693df99a125b4f17e184331' - b'c6b6e8ca00f54f3a'), - 'x': int('350e13534692a7e0c4b7d58836046c436fbb2322', 16), - 'y': int('69974de550fe6bd3099150faea1623ad3fb6d9bf23a07215093f3197' - '25ad0877accffd291b6da18eb0cbe51676ceb0977504eb97c27c0b19' - '1883f72fb2710a9fbd8bcf13be0bf854410b32f42b33ec89d3cc1cf8' - '92bcd536c4195ca9ada302ad600c3408739935d77dc247529ca47f84' - '4cc86f5016a2fe962c6e20ca7c4d4e8f', 16), - 'r': int('b5d05faa7005764e8dae0327c5bf1972ff7681b9', 16), - 's': int('18ea15bd9f00475b25204cbc23f8c23e01588015', 16), - 'result': 'F'}, - { - 'p': int('e7c1c86125db9ef417da1ced7ea0861bdad629216a3f3c745df42a4' - '6b989e59f4d98425ee3c932fa3c2b6f637bdb6545bec526faa037e1' - '1f5578a4363b9fca5eba60d6a9cbaa2befd04141d989c7356285132' - 'c2eaf74f2d868521cdc0a17ae9a2546ef863027d3f8cc7949631fd0' - 'e2971417a912c8b8c5c989730db6ea6e8baee0e667850429038093c' - '851ccb6fb173bb081e0efe0bd7450e0946888f89f75e443ab93ef2d' - 'a293a01622cf43c6dd79625d41ba8f9ef7e3086ab39134283d8e96c' - '89249488120fd061e4a87d34af41069c0b4fd3934c31b589cbe85b6' - '8b912718d5dab859fda7082511fad1d152044905005546e19b14aa9' - '6585a55269bf2b831', 16), - 'q': int('8e056ec9d4b7acb580087a6ed9ba3478711bb025d5b8d9c731ef9b3' - '8bd43db2f', 16), - 'g': int('dc2bfb9776786ad310c8b0cdcbba3062402613c67e6959a8d8d1b05' - 'aab636528b7b1fe9cd33765f853d6dbe13d09f2681f8c7b1ed7886a' - 'aed70c7bd76dbe858ffb8bd86235ddf759244678f428c6519af593d' - 'c94eeadbd9852ba2b3d61664e8d58c29d2039af3c3d6d16f90988f6' - 'a8c824569f3d48050e30896a9e17cd0232ef01ab8790008f6973b84' - 'c763a72f4ae8b485abfb7e8efeb86808fa2b281d3e5d65d28f5992a' - '34c077c5aa8026cb2fbc34a45f7e9bd216b10e6f12ecb172e9a6eb8' - 'f2e91316905b6add1fd22e83bc2f089f1d5e6a6e6707c18ff55ddcb' - '7954e8bceaf0efc4e8314910c03b0e51175f344faafee476a373ac9' - '5743cec712b72cf2e', 16), - 'digest_algorithm': 'SHA-384', - 'msg': binascii.unhexlify( - b'6cd6ccfd66bcd832189c5f0c77994210e3bf2c43416f0fe77c4e92f31c5' - b'369538dc2c003f146c5ac79df43194ccf3c44d470d9f1083bd15b99b5bc' - b'f88c32d8a9021f09ea2288d7b3bf345a12aef3949c1e121b9fb371a67c2' - b'd1377364206ac839dd78483561426bda0303f285aa12e9c45d3cdfc6bea' - b'e3549703b187deeb3296'), - 'x': int('56c897b5938ad5b3d437d7e4826da586a6b3be15e893fa1aaa946f2' - '0a028b6b3', 16), - 'y': int('38ad44489e1a5778b9689f4dcf40e2acf23840fb954e987d6e8cb62' - '9106328ac64e1f3c3eba48b21176ad4afe3b733bead382ee1597e1b' - '83e4b43424f2daaba04e5bd79e1436693ac2bddb79a298f026e57e2' - '00a252efd1e848a4a2e90be6e78f5242b468b9c0c6d2615047a5a40' - 'b9ae7e57a519114db55bf3bed65e580f894b094630ca9c217f6accd' - '091e72d2f22da620044ff372d7273f9445017fad492959e59600b74' - '94dbe766a03e40125d4e6747c76f68a5b0cdc0e7d7cee12d08c6fb7' - 'd0fb049e420a33405075ed4463296345ca695fb7feab7c1b5333ae5' - '19fcd4bb6a043f4555378969114743d4face96cad31c0e0089da4e3' - 'f61b6d7dabc088ab7', 16), - 'r': int('3b85b17be240ed658beb3652c9d93e8e9eea160d35ee24596143058' - '02963374e', 16), - 's': int('726800a5174a53b56dce86064109c0273cd11fcfa3c92c5cd6aa910' - '260c0e3c7', 16), - 'result': 'F'}, - { - 'p': int('e7c1c86125db9ef417da1ced7ea0861bdad629216a3f3c745df42a4' - '6b989e59f4d98425ee3c932fa3c2b6f637bdb6545bec526faa037e1' - '1f5578a4363b9fca5eba60d6a9cbaa2befd04141d989c7356285132' - 'c2eaf74f2d868521cdc0a17ae9a2546ef863027d3f8cc7949631fd0' - 'e2971417a912c8b8c5c989730db6ea6e8baee0e667850429038093c' - '851ccb6fb173bb081e0efe0bd7450e0946888f89f75e443ab93ef2d' - 'a293a01622cf43c6dd79625d41ba8f9ef7e3086ab39134283d8e96c' - '89249488120fd061e4a87d34af41069c0b4fd3934c31b589cbe85b6' - '8b912718d5dab859fda7082511fad1d152044905005546e19b14aa9' - '6585a55269bf2b831', 16), - 'q': int('8e056ec9d4b7acb580087a6ed9ba3478711bb025d5b8d9c731ef9b3' - '8bd43db2f', 16), - 'g': int('dc2bfb9776786ad310c8b0cdcbba3062402613c67e6959a8d8d1b05' - 'aab636528b7b1fe9cd33765f853d6dbe13d09f2681f8c7b1ed7886a' - 'aed70c7bd76dbe858ffb8bd86235ddf759244678f428c6519af593d' - 'c94eeadbd9852ba2b3d61664e8d58c29d2039af3c3d6d16f90988f6' - 'a8c824569f3d48050e30896a9e17cd0232ef01ab8790008f6973b84' - 'c763a72f4ae8b485abfb7e8efeb86808fa2b281d3e5d65d28f5992a' - '34c077c5aa8026cb2fbc34a45f7e9bd216b10e6f12ecb172e9a6eb8' - 'f2e91316905b6add1fd22e83bc2f089f1d5e6a6e6707c18ff55ddcb' - '7954e8bceaf0efc4e8314910c03b0e51175f344faafee476a373ac9' - '5743cec712b72cf2e', 16), - 'digest_algorithm': 'SHA-384', - 'msg': binascii.unhexlify( - b'3ad6b0884f358dea09c31a9abc40c45a6000611fc2b907b30eac00413fd' - b'2819de7015488a411609d46c499b8f7afa1b78b352ac7f8535bd805b8ff' - b'2a5eae557098c668f7ccd73af886d6823a6d456c29931ee864ed46d7673' - b'82785728c2a83fcff5271007d2a67d06fa205fd7b9d1a42ea5d6dc76e5e' - b'18a9eb148cd1e8b262ae'), - 'x': int('2faf566a9f057960f1b50c69508f483d9966d6e35743591f3a677a9' - 'dc40e1555', 16), - 'y': int('926425d617babe87c442b03903e32ba5bbf0cd9d602b59c4df791a4d' - '64a6d4333ca0c0d370552539197d327dcd1bbf8c454f24b03fc7805f' - '862db34c7b066ddfddbb11dbd010b27123062d028fe041cb56a2e774' - '88348ae0ab6705d87aac4d4e9e6600e9e706326d9979982cffa839be' - 'b9eacc3963bcca455a507e80c1c37ad4e765b2c9c0477a075e9bc584' - 'feacdf3a35a9391d4711f14e197c54022282bfed9a191213d64127f1' - '7a9c5affec26e0c71f15d3a5b16098fec118c45bf8bb2f3b1560df09' - '49254c1c0aeb0a16d5a95a40fab8521fbe8ea77c51169b587cc3360e' - '5733e6a23b9fded8c40724ea1f9e93614b3a6c9b4f8dbbe915b79449' - '7227ba62', 16), - 'r': int('343ea0a9e66277380f604d5880fca686bffab69ca97bfba015a102a' - '7e23dce0e', 16), - 's': int('6258488c770e0f5ad7b9da8bade5023fc0d17c6ec517bd08d53e6dc' - '01ac5c2b3', 16), - 'result': 'P'} + "p": int( + "dc5bf3a88b2d99e4c95cdd7a0501cc38630d425cf5c390af3429cff1" + "f35147b795caea923f0d3577158f8a0c89dabd1962c2c453306b5d70" + "cacfb01430aceb54e5a5fa6f9340d3bd2da612fceeb76b0ec1ebfae6" + "35a56ab141b108e00dc76eefe2edd0c514c21c457457c39065dba9d0" + "ecb7569c247172d8438ad2827b60435b", + 16, + ), + "q": int("e956602b83d195dbe945b3ac702fc61f81571f1d", 16), + "g": int( + "d7eb9ca20a3c7a079606bafc4c9261ccaba303a5dc9fe9953f197dfe" + "548c234895baa77f441ee6a2d97b909cbbd26ff7b869d24cae51b5c6" + "edb127a4b5d75cd8b46608bfa148249dffdb59807c5d7dde3fe3080c" + "a3a2d28312142becb1fa8e24003e21c7287108174b95d5bc711e1c8d" + "9b1076784f5dc37a964a5e51390da713", + 16, + ), + "digest_algorithm": "SHA-1", + "msg": binascii.unhexlify( + b"0fe1bfee500bdb76026099b1d37553f6bdfe48c82094ef98cb309dd77733" + b"0bedfaa2f94c823ef74ef4074b50d8706041ac0e371c7c22dcf70263b8d6" + b"0e17a86c7c379cfda8f22469e0df9d49d59439fc99891873628fff25dda5" + b"fac5ac794e948babdde968143ba05f1128f34fdad5875edc4cd71c6c24ba" + b"2060ffbd439ce2b3" + ), + "x": int("1d93010c29ecfc432188942f46f19f44f0e1bb5d", 16), + "y": int( + "6240ea0647117c38fe705106d56db578f3e10130928452d4f3587881" + "b8a2bc6873a8befc3237f20914e2a91c7f07a928ee22adeed23d74ab" + "7f82ea11f70497e578f7a9b4cbd6f10226222b0b4da2ea1e49813d6b" + "b9882fbf675c0846bb80cc891857b89b0ef1beb6cce3378a9aab5d66" + "ad4cb9277cf447dfe1e64434749432fb", + 16, + ), + "r": int("b5af307867fb8b54390013cc67020ddf1f2c0b81", 16), + "s": int("620d3b22ab5031440c3e35eab6f481298f9e9f08", 16), + "result": "P", + }, + { + "p": int( + "dc5bf3a88b2d99e4c95cdd7a0501cc38630d425cf5c390af3429cff1" + "f35147b795caea923f0d3577158f8a0c89dabd1962c2c453306b5d70" + "cacfb01430aceb54e5a5fa6f9340d3bd2da612fceeb76b0ec1ebfae6" + "35a56ab141b108e00dc76eefe2edd0c514c21c457457c39065dba9d0" + "ecb7569c247172d8438ad2827b60435b", + 16, + ), + "q": int("e956602b83d195dbe945b3ac702fc61f81571f1d", 16), + "g": int( + "d7eb9ca20a3c7a079606bafc4c9261ccaba303a5dc9fe9953f197dfe" + "548c234895baa77f441ee6a2d97b909cbbd26ff7b869d24cae51b5c6" + "edb127a4b5d75cd8b46608bfa148249dffdb59807c5d7dde3fe3080c" + "a3a2d28312142becb1fa8e24003e21c7287108174b95d5bc711e1c8d" + "9b1076784f5dc37a964a5e51390da713", + 16, + ), + "digest_algorithm": "SHA-1", + "msg": binascii.unhexlify( + b"97d50898025d2f9ba633866e968ca75e969d394edba6517204cb3dd537c2" + b"ba38778a2dc9dbc685a915e5676fcd43bc3726bc59ce3d7a9fae35565082" + b"a069c139fa37c90d922b126933db3fa6c5ef6b1edf00d174a51887bb7690" + b"9c6a94fe994ecc7b7fc8f26113b17f30f9d01693df99a125b4f17e184331" + b"c6b6e8ca00f54f3a" + ), + "x": int("350e13534692a7e0c4b7d58836046c436fbb2322", 16), + "y": int( + "69974de550fe6bd3099150faea1623ad3fb6d9bf23a07215093f3197" + "25ad0877accffd291b6da18eb0cbe51676ceb0977504eb97c27c0b19" + "1883f72fb2710a9fbd8bcf13be0bf854410b32f42b33ec89d3cc1cf8" + "92bcd536c4195ca9ada302ad600c3408739935d77dc247529ca47f84" + "4cc86f5016a2fe962c6e20ca7c4d4e8f", + 16, + ), + "r": int("b5d05faa7005764e8dae0327c5bf1972ff7681b9", 16), + "s": int("18ea15bd9f00475b25204cbc23f8c23e01588015", 16), + "result": "F", + }, + { + "p": int( + "e7c1c86125db9ef417da1ced7ea0861bdad629216a3f3c745df42a4" + "6b989e59f4d98425ee3c932fa3c2b6f637bdb6545bec526faa037e1" + "1f5578a4363b9fca5eba60d6a9cbaa2befd04141d989c7356285132" + "c2eaf74f2d868521cdc0a17ae9a2546ef863027d3f8cc7949631fd0" + "e2971417a912c8b8c5c989730db6ea6e8baee0e667850429038093c" + "851ccb6fb173bb081e0efe0bd7450e0946888f89f75e443ab93ef2d" + "a293a01622cf43c6dd79625d41ba8f9ef7e3086ab39134283d8e96c" + "89249488120fd061e4a87d34af41069c0b4fd3934c31b589cbe85b6" + "8b912718d5dab859fda7082511fad1d152044905005546e19b14aa9" + "6585a55269bf2b831", + 16, + ), + "q": int( + "8e056ec9d4b7acb580087a6ed9ba3478711bb025d5b8d9c731ef9b3" + "8bd43db2f", + 16, + ), + "g": int( + "dc2bfb9776786ad310c8b0cdcbba3062402613c67e6959a8d8d1b05" + "aab636528b7b1fe9cd33765f853d6dbe13d09f2681f8c7b1ed7886a" + "aed70c7bd76dbe858ffb8bd86235ddf759244678f428c6519af593d" + "c94eeadbd9852ba2b3d61664e8d58c29d2039af3c3d6d16f90988f6" + "a8c824569f3d48050e30896a9e17cd0232ef01ab8790008f6973b84" + "c763a72f4ae8b485abfb7e8efeb86808fa2b281d3e5d65d28f5992a" + "34c077c5aa8026cb2fbc34a45f7e9bd216b10e6f12ecb172e9a6eb8" + "f2e91316905b6add1fd22e83bc2f089f1d5e6a6e6707c18ff55ddcb" + "7954e8bceaf0efc4e8314910c03b0e51175f344faafee476a373ac9" + "5743cec712b72cf2e", + 16, + ), + "digest_algorithm": "SHA-384", + "msg": binascii.unhexlify( + b"6cd6ccfd66bcd832189c5f0c77994210e3bf2c43416f0fe77c4e92f31c5" + b"369538dc2c003f146c5ac79df43194ccf3c44d470d9f1083bd15b99b5bc" + b"f88c32d8a9021f09ea2288d7b3bf345a12aef3949c1e121b9fb371a67c2" + b"d1377364206ac839dd78483561426bda0303f285aa12e9c45d3cdfc6bea" + b"e3549703b187deeb3296" + ), + "x": int( + "56c897b5938ad5b3d437d7e4826da586a6b3be15e893fa1aaa946f2" + "0a028b6b3", + 16, + ), + "y": int( + "38ad44489e1a5778b9689f4dcf40e2acf23840fb954e987d6e8cb62" + "9106328ac64e1f3c3eba48b21176ad4afe3b733bead382ee1597e1b" + "83e4b43424f2daaba04e5bd79e1436693ac2bddb79a298f026e57e2" + "00a252efd1e848a4a2e90be6e78f5242b468b9c0c6d2615047a5a40" + "b9ae7e57a519114db55bf3bed65e580f894b094630ca9c217f6accd" + "091e72d2f22da620044ff372d7273f9445017fad492959e59600b74" + "94dbe766a03e40125d4e6747c76f68a5b0cdc0e7d7cee12d08c6fb7" + "d0fb049e420a33405075ed4463296345ca695fb7feab7c1b5333ae5" + "19fcd4bb6a043f4555378969114743d4face96cad31c0e0089da4e3" + "f61b6d7dabc088ab7", + 16, + ), + "r": int( + "3b85b17be240ed658beb3652c9d93e8e9eea160d35ee24596143058" + "02963374e", + 16, + ), + "s": int( + "726800a5174a53b56dce86064109c0273cd11fcfa3c92c5cd6aa910" + "260c0e3c7", + 16, + ), + "result": "F", + }, + { + "p": int( + "e7c1c86125db9ef417da1ced7ea0861bdad629216a3f3c745df42a4" + "6b989e59f4d98425ee3c932fa3c2b6f637bdb6545bec526faa037e1" + "1f5578a4363b9fca5eba60d6a9cbaa2befd04141d989c7356285132" + "c2eaf74f2d868521cdc0a17ae9a2546ef863027d3f8cc7949631fd0" + "e2971417a912c8b8c5c989730db6ea6e8baee0e667850429038093c" + "851ccb6fb173bb081e0efe0bd7450e0946888f89f75e443ab93ef2d" + "a293a01622cf43c6dd79625d41ba8f9ef7e3086ab39134283d8e96c" + "89249488120fd061e4a87d34af41069c0b4fd3934c31b589cbe85b6" + "8b912718d5dab859fda7082511fad1d152044905005546e19b14aa9" + "6585a55269bf2b831", + 16, + ), + "q": int( + "8e056ec9d4b7acb580087a6ed9ba3478711bb025d5b8d9c731ef9b3" + "8bd43db2f", + 16, + ), + "g": int( + "dc2bfb9776786ad310c8b0cdcbba3062402613c67e6959a8d8d1b05" + "aab636528b7b1fe9cd33765f853d6dbe13d09f2681f8c7b1ed7886a" + "aed70c7bd76dbe858ffb8bd86235ddf759244678f428c6519af593d" + "c94eeadbd9852ba2b3d61664e8d58c29d2039af3c3d6d16f90988f6" + "a8c824569f3d48050e30896a9e17cd0232ef01ab8790008f6973b84" + "c763a72f4ae8b485abfb7e8efeb86808fa2b281d3e5d65d28f5992a" + "34c077c5aa8026cb2fbc34a45f7e9bd216b10e6f12ecb172e9a6eb8" + "f2e91316905b6add1fd22e83bc2f089f1d5e6a6e6707c18ff55ddcb" + "7954e8bceaf0efc4e8314910c03b0e51175f344faafee476a373ac9" + "5743cec712b72cf2e", + 16, + ), + "digest_algorithm": "SHA-384", + "msg": binascii.unhexlify( + b"3ad6b0884f358dea09c31a9abc40c45a6000611fc2b907b30eac00413fd" + b"2819de7015488a411609d46c499b8f7afa1b78b352ac7f8535bd805b8ff" + b"2a5eae557098c668f7ccd73af886d6823a6d456c29931ee864ed46d7673" + b"82785728c2a83fcff5271007d2a67d06fa205fd7b9d1a42ea5d6dc76e5e" + b"18a9eb148cd1e8b262ae" + ), + "x": int( + "2faf566a9f057960f1b50c69508f483d9966d6e35743591f3a677a9" + "dc40e1555", + 16, + ), + "y": int( + "926425d617babe87c442b03903e32ba5bbf0cd9d602b59c4df791a4d" + "64a6d4333ca0c0d370552539197d327dcd1bbf8c454f24b03fc7805f" + "862db34c7b066ddfddbb11dbd010b27123062d028fe041cb56a2e774" + "88348ae0ab6705d87aac4d4e9e6600e9e706326d9979982cffa839be" + "b9eacc3963bcca455a507e80c1c37ad4e765b2c9c0477a075e9bc584" + "feacdf3a35a9391d4711f14e197c54022282bfed9a191213d64127f1" + "7a9c5affec26e0c71f15d3a5b16098fec118c45bf8bb2f3b1560df09" + "49254c1c0aeb0a16d5a95a40fab8521fbe8ea77c51169b587cc3360e" + "5733e6a23b9fded8c40724ea1f9e93614b3a6c9b4f8dbbe915b79449" + "7227ba62", + 16, + ), + "r": int( + "343ea0a9e66277380f604d5880fca686bffab69ca97bfba015a102a" + "7e23dce0e", + 16, + ), + "s": int( + "6258488c770e0f5ad7b9da8bade5023fc0d17c6ec517bd08d53e6dc" + "01ac5c2b3", + 16, + ), + "result": "P", + }, ] assert expected == load_fips_dsa_sig_vectors(vector_data) def test_load_fips_dsa_sig_gen_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # CAVS 11.2 # "SigGen" information for "dsa2_values" # Mod sizes selected: SHA-1 L=1024, N=160, SHA-256 L=2048, N=256 @@ -2145,155 +2437,219 @@ def test_load_fips_dsa_sig_gen_vectors(): 60bc1dc46f78ceaaa2c02f5375dd82e708744aa40b15799eb81d7e5b1a R = bcd490568c0a89ba311bef88ea4f4b03d273e793722722327095a378dd6f3522 S = 74498fc43091fcdd2d1ef0775f8286945a01cd72b805256b0451f9cbd943cf82 - """).splitlines() + """ + ).splitlines() expected = [ { - 'p': int('a8f9cd201e5e35d892f85f80e4db2599a5676a3b1d4f190330ed325' - '6b26d0e80a0e49a8fffaaad2a24f472d2573241d4d6d6c7480c80b4' - 'c67bb4479c15ada7ea8424d2502fa01472e760241713dab025ae1b0' - '2e1703a1435f62ddf4ee4c1b664066eb22f2e3bf28bb70a2a76e4fd' - '5ebe2d1229681b5b06439ac9c7e9d8bde283', 16), - 'q': int('f85f0f83ac4df7ea0cdf8f469bfeeaea14156495', 16), - 'g': int('2b3152ff6c62f14622b8f48e59f8af46883b38e79b8c74deeae9df1' - '31f8b856e3ad6c8455dab87cc0da8ac973417ce4f7878557d6cdf40' - 'b35b4a0ca3eb310c6a95d68ce284ad4e25ea28591611ee08b8444bd' - '64b25f3f7c572410ddfb39cc728b9c936f85f419129869929cdb909' - 'a6a3a99bbe089216368171bd0ba81de4fe33', 16), - 'digest_algorithm': 'SHA-1', - 'msg': binascii.unhexlify( - b'3b46736d559bd4e0c2c1b2553a33ad3c6cf23cac998d3d0c0e8fa4b19bc' - b'a06f2f386db2dcff9dca4f40ad8f561ffc308b46c5f31a7735b5fa7e0f9' - b'e6cb512e63d7eea05538d66a75cd0d4234b5ccf6c1715ccaaf9cdc0a222' - b'8135f716ee9bdee7fc13ec27a03a6d11c5c5b3685f51900b1337153bc6c' - b'4e8f52920c33fa37f4e7'), - 'y': int('313fd9ebca91574e1c2eebe1517c57e0c21b0209872140c5328761b' - 'bb2450b33f1b18b409ce9ab7c4cd8fda3391e8e34868357c199e16a' - '6b2eba06d6749def791d79e95d3a4d09b24c392ad89dbf100995ae1' - '9c01062056bb14bce005e8731efde175f95b975089bdcdaea562b32' - '786d96f5a31aedf75364008ad4fffebb970b', 16), - 'r': int('50ed0e810e3f1c7cb6ac62332058448bd8b284c0', 16), - 's': int('c6aded17216b46b7e4b6f2a97c1ad7cc3da83fde', 16)}, - { - 'p': int('a8f9cd201e5e35d892f85f80e4db2599a5676a3b1d4f190330ed325' - '6b26d0e80a0e49a8fffaaad2a24f472d2573241d4d6d6c7480c80b4' - 'c67bb4479c15ada7ea8424d2502fa01472e760241713dab025ae1b0' - '2e1703a1435f62ddf4ee4c1b664066eb22f2e3bf28bb70a2a76e4fd' - '5ebe2d1229681b5b06439ac9c7e9d8bde283', 16), - 'q': int('f85f0f83ac4df7ea0cdf8f469bfeeaea14156495', 16), - 'g': int('2b3152ff6c62f14622b8f48e59f8af46883b38e79b8c74deeae9df1' - '31f8b856e3ad6c8455dab87cc0da8ac973417ce4f7878557d6cdf40' - 'b35b4a0ca3eb310c6a95d68ce284ad4e25ea28591611ee08b8444bd' - '64b25f3f7c572410ddfb39cc728b9c936f85f419129869929cdb909' - 'a6a3a99bbe089216368171bd0ba81de4fe33', 16), - 'digest_algorithm': 'SHA-1', - 'msg': binascii.unhexlify( - b'd2bcb53b044b3e2e4b61ba2f91c0995fb83a6a97525e66441a3b489d959' - b'4238bc740bdeea0f718a769c977e2de003877b5d7dc25b182ae533db33e' - b'78f2c3ff0645f2137abc137d4e7d93ccf24f60b18a820bc07c7b4b5fe08' - b'b4f9e7d21b256c18f3b9d49acc4f93e2ce6f3754c7807757d2e11760426' - b'12cb32fc3f4f70700e25'), - 'y': int('29bdd759aaa62d4bf16b4861c81cf42eac2e1637b9ecba512bdbc13' - 'ac12a80ae8de2526b899ae5e4a231aef884197c944c732693a634d7' - '659abc6975a773f8d3cd5a361fe2492386a3c09aaef12e4a7e73ad7' - 'dfc3637f7b093f2c40d6223a195c136adf2ea3fbf8704a675aa7817' - 'aa7ec7f9adfb2854d4e05c3ce7f76560313b', 16), - 'r': int('a26c00b5750a2d27fe7435b93476b35438b4d8ab', 16), - 's': int('61c9bfcb2938755afa7dad1d1e07c6288617bf70', 16)}, - { - 'p': int('a8adb6c0b4cf9588012e5deff1a871d383e0e2a85b5e8e03d814fe1' - '3a059705e663230a377bf7323a8fa117100200bfd5adf857393b0bb' - 'd67906c081e585410e38480ead51684dac3a38f7b64c9eb109f1973' - '9a4517cd7d5d6291e8af20a3fbf17336c7bf80ee718ee087e322ee4' - '1047dabefbcc34d10b66b644ddb3160a28c0639563d71993a26543e' - 'adb7718f317bf5d9577a6156561b082a10029cd44012b18de684450' - '9fe058ba87980792285f2750969fe89c2cd6498db3545638d5379d1' - '25dccf64e06c1af33a6190841d223da1513333a7c9d78462abaab31' - 'b9f96d5f34445ceb6309f2f6d2c8dde06441e87980d303ef9a1ff00' - '7e8be2f0be06cc15f', 16), - 'q': int('e71f8567447f42e75f5ef85ca20fe557ab0343d37ed09edc3f6e686' - '04d6b9dfb', 16), - 'g': int('5ba24de9607b8998e66ce6c4f812a314c6935842f7ab54cd82b19fa' - '104abfb5d84579a623b2574b37d22ccae9b3e415e48f5c0f9bcbdff' - '8071d63b9bb956e547af3a8df99e5d3061979652ff96b765cb3ee49' - '3643544c75dbe5bb39834531952a0fb4b0378b3fcbb4c8b5800a533' - '0392a2a04e700bb6ed7e0b85795ea38b1b962741b3f33b9dde2f4ec' - '1354f09e2eb78e95f037a5804b6171659f88715ce1a9b0cc90c27f3' - '5ef2f10ff0c7c7a2bb0154d9b8ebe76a3d764aa879af372f4240de8' - '347937e5a90cec9f41ff2f26b8da9a94a225d1a913717d73f10397d' - '2183f1ba3b7b45a68f1ff1893caf69a827802f7b6a48d51da6fbefb' - '64fd9a6c5b75c4561', 16), - 'digest_algorithm': 'SHA-256', - 'msg': binascii.unhexlify( - b'4e3a28bcf90d1d2e75f075d9fbe55b36c5529b17bc3a9ccaba6935c9e20' - b'548255b3dfae0f91db030c12f2c344b3a29c4151c5b209f5e319fdf1c23' - b'b190f64f1fe5b330cb7c8fa952f9d90f13aff1cb11d63181da9efc6f7e1' - b'5bfed4862d1a62c7dcf3ba8bf1ff304b102b1ec3f1497dddf09712cf323' - b'f5610a9d10c3d9132659'), - 'y': int('5a55dceddd1134ee5f11ed85deb4d634a3643f5f36dc3a706892564' - '69a0b651ad22880f14ab85719434f9c0e407e60ea420e2a0cd29422' - 'c4899c416359dbb1e592456f2b3cce233259c117542fd05f31ea25b' - '015d9121c890b90e0bad033be1368d229985aac7226d1c8c2eab325' - 'ef3b2cd59d3b9f7de7dbc94af1a9339eb430ca36c26c46ecfa6c548' - '1711496f624e188ad7540ef5df26f8efacb820bd17a1f618acb50c9' - 'bc197d4cb7ccac45d824a3bf795c234b556b06aeb92917345325208' - '4003f69fe98045fe74002ba658f93475622f76791d9b2623d1b5fff' - '2cc16844746efd2d30a6a8134bfc4c8cc80a46107901fb973c28fc5' - '53130f3286c1489da', 16), - 'r': int('633055e055f237c38999d81c397848c38cce80a55b649d9e7905c29' - '8e2a51447', 16), - 's': int('2bbf68317660ec1e4b154915027b0bc00ee19cfc0bf75d01930504f' - '2ce10a8b0', 16)}, - { - 'p': int('a8adb6c0b4cf9588012e5deff1a871d383e0e2a85b5e8e03d814fe1' - '3a059705e663230a377bf7323a8fa117100200bfd5adf857393b0bb' - 'd67906c081e585410e38480ead51684dac3a38f7b64c9eb109f1973' - '9a4517cd7d5d6291e8af20a3fbf17336c7bf80ee718ee087e322ee4' - '1047dabefbcc34d10b66b644ddb3160a28c0639563d71993a26543e' - 'adb7718f317bf5d9577a6156561b082a10029cd44012b18de684450' - '9fe058ba87980792285f2750969fe89c2cd6498db3545638d5379d1' - '25dccf64e06c1af33a6190841d223da1513333a7c9d78462abaab31' - 'b9f96d5f34445ceb6309f2f6d2c8dde06441e87980d303ef9a1ff00' - '7e8be2f0be06cc15f', 16), - 'q': int('e71f8567447f42e75f5ef85ca20fe557ab0343d37ed09edc3f6e686' - '04d6b9dfb', 16), - 'g': int('5ba24de9607b8998e66ce6c4f812a314c6935842f7ab54cd82b19fa' - '104abfb5d84579a623b2574b37d22ccae9b3e415e48f5c0f9bcbdff' - '8071d63b9bb956e547af3a8df99e5d3061979652ff96b765cb3ee49' - '3643544c75dbe5bb39834531952a0fb4b0378b3fcbb4c8b5800a533' - '0392a2a04e700bb6ed7e0b85795ea38b1b962741b3f33b9dde2f4ec' - '1354f09e2eb78e95f037a5804b6171659f88715ce1a9b0cc90c27f3' - '5ef2f10ff0c7c7a2bb0154d9b8ebe76a3d764aa879af372f4240de8' - '347937e5a90cec9f41ff2f26b8da9a94a225d1a913717d73f10397d' - '2183f1ba3b7b45a68f1ff1893caf69a827802f7b6a48d51da6fbefb' - '64fd9a6c5b75c4561', 16), - 'digest_algorithm': 'SHA-256', - 'msg': binascii.unhexlify( - b'a733b3f588d5ac9b9d4fe2f804df8c256403a9f8eef6f191fc48e1267fb' - b'5b4d546ba11e77b667844e489bf0d5f72990aeb061d01ccd7949a23def7' - b'4a803b7d92d51abfadeb4885ffd8ffd58ab87548a15c087a39b8993b2fa' - b'64c9d31a594eeb7512da16955834336a234435c5a9d0dd9b15a94e11615' - b'4dea63fdc8dd7a512181'), - 'y': int('356ed47537fbf02cb30a8cee0537f300dff1d0c467399ce70b87a87' - '58d5ec9dd256246fccaeb9dfe109f2a984f2ddaa87aad54ce0d31f9' - '07e504521baf4207d7073b0a4a9fc67d8ddda99f87aed6e0367cec2' - '7f9c608af743bf1ee6e11d55a182d43b024ace534029b866f642282' - '8bb81a39aae9601ee81c7f81dd358e69f4e2edfa4654d8a65bc6431' - '1dc86aac4abc1fc7a3f65159661a0d8e288eb8d665cb0adf5ac3d6b' - 'a8e9453facf7542393ae24fd50451d3828086558f7ec528e284935a' - '53f67a1aa8e25d8ad5c4ad55d83aef883a4d9eeb6297e6a53f65049' - 'ba9e2c6b7953a760bc1dc46f78ceaaa2c02f5375dd82e708744aa40' - 'b15799eb81d7e5b1a', 16), - 'r': int('bcd490568c0a89ba311bef88ea4f4b03d273e793722722327095a37' - '8dd6f3522', 16), - 's': int('74498fc43091fcdd2d1ef0775f8286945a01cd72b805256b0451f9c' - 'bd943cf82', 16)} + "p": int( + "a8f9cd201e5e35d892f85f80e4db2599a5676a3b1d4f190330ed325" + "6b26d0e80a0e49a8fffaaad2a24f472d2573241d4d6d6c7480c80b4" + "c67bb4479c15ada7ea8424d2502fa01472e760241713dab025ae1b0" + "2e1703a1435f62ddf4ee4c1b664066eb22f2e3bf28bb70a2a76e4fd" + "5ebe2d1229681b5b06439ac9c7e9d8bde283", + 16, + ), + "q": int("f85f0f83ac4df7ea0cdf8f469bfeeaea14156495", 16), + "g": int( + "2b3152ff6c62f14622b8f48e59f8af46883b38e79b8c74deeae9df1" + "31f8b856e3ad6c8455dab87cc0da8ac973417ce4f7878557d6cdf40" + "b35b4a0ca3eb310c6a95d68ce284ad4e25ea28591611ee08b8444bd" + "64b25f3f7c572410ddfb39cc728b9c936f85f419129869929cdb909" + "a6a3a99bbe089216368171bd0ba81de4fe33", + 16, + ), + "digest_algorithm": "SHA-1", + "msg": binascii.unhexlify( + b"3b46736d559bd4e0c2c1b2553a33ad3c6cf23cac998d3d0c0e8fa4b19bc" + b"a06f2f386db2dcff9dca4f40ad8f561ffc308b46c5f31a7735b5fa7e0f9" + b"e6cb512e63d7eea05538d66a75cd0d4234b5ccf6c1715ccaaf9cdc0a222" + b"8135f716ee9bdee7fc13ec27a03a6d11c5c5b3685f51900b1337153bc6c" + b"4e8f52920c33fa37f4e7" + ), + "y": int( + "313fd9ebca91574e1c2eebe1517c57e0c21b0209872140c5328761b" + "bb2450b33f1b18b409ce9ab7c4cd8fda3391e8e34868357c199e16a" + "6b2eba06d6749def791d79e95d3a4d09b24c392ad89dbf100995ae1" + "9c01062056bb14bce005e8731efde175f95b975089bdcdaea562b32" + "786d96f5a31aedf75364008ad4fffebb970b", + 16, + ), + "r": int("50ed0e810e3f1c7cb6ac62332058448bd8b284c0", 16), + "s": int("c6aded17216b46b7e4b6f2a97c1ad7cc3da83fde", 16), + }, + { + "p": int( + "a8f9cd201e5e35d892f85f80e4db2599a5676a3b1d4f190330ed325" + "6b26d0e80a0e49a8fffaaad2a24f472d2573241d4d6d6c7480c80b4" + "c67bb4479c15ada7ea8424d2502fa01472e760241713dab025ae1b0" + "2e1703a1435f62ddf4ee4c1b664066eb22f2e3bf28bb70a2a76e4fd" + "5ebe2d1229681b5b06439ac9c7e9d8bde283", + 16, + ), + "q": int("f85f0f83ac4df7ea0cdf8f469bfeeaea14156495", 16), + "g": int( + "2b3152ff6c62f14622b8f48e59f8af46883b38e79b8c74deeae9df1" + "31f8b856e3ad6c8455dab87cc0da8ac973417ce4f7878557d6cdf40" + "b35b4a0ca3eb310c6a95d68ce284ad4e25ea28591611ee08b8444bd" + "64b25f3f7c572410ddfb39cc728b9c936f85f419129869929cdb909" + "a6a3a99bbe089216368171bd0ba81de4fe33", + 16, + ), + "digest_algorithm": "SHA-1", + "msg": binascii.unhexlify( + b"d2bcb53b044b3e2e4b61ba2f91c0995fb83a6a97525e66441a3b489d959" + b"4238bc740bdeea0f718a769c977e2de003877b5d7dc25b182ae533db33e" + b"78f2c3ff0645f2137abc137d4e7d93ccf24f60b18a820bc07c7b4b5fe08" + b"b4f9e7d21b256c18f3b9d49acc4f93e2ce6f3754c7807757d2e11760426" + b"12cb32fc3f4f70700e25" + ), + "y": int( + "29bdd759aaa62d4bf16b4861c81cf42eac2e1637b9ecba512bdbc13" + "ac12a80ae8de2526b899ae5e4a231aef884197c944c732693a634d7" + "659abc6975a773f8d3cd5a361fe2492386a3c09aaef12e4a7e73ad7" + "dfc3637f7b093f2c40d6223a195c136adf2ea3fbf8704a675aa7817" + "aa7ec7f9adfb2854d4e05c3ce7f76560313b", + 16, + ), + "r": int("a26c00b5750a2d27fe7435b93476b35438b4d8ab", 16), + "s": int("61c9bfcb2938755afa7dad1d1e07c6288617bf70", 16), + }, + { + "p": int( + "a8adb6c0b4cf9588012e5deff1a871d383e0e2a85b5e8e03d814fe1" + "3a059705e663230a377bf7323a8fa117100200bfd5adf857393b0bb" + "d67906c081e585410e38480ead51684dac3a38f7b64c9eb109f1973" + "9a4517cd7d5d6291e8af20a3fbf17336c7bf80ee718ee087e322ee4" + "1047dabefbcc34d10b66b644ddb3160a28c0639563d71993a26543e" + "adb7718f317bf5d9577a6156561b082a10029cd44012b18de684450" + "9fe058ba87980792285f2750969fe89c2cd6498db3545638d5379d1" + "25dccf64e06c1af33a6190841d223da1513333a7c9d78462abaab31" + "b9f96d5f34445ceb6309f2f6d2c8dde06441e87980d303ef9a1ff00" + "7e8be2f0be06cc15f", + 16, + ), + "q": int( + "e71f8567447f42e75f5ef85ca20fe557ab0343d37ed09edc3f6e686" + "04d6b9dfb", + 16, + ), + "g": int( + "5ba24de9607b8998e66ce6c4f812a314c6935842f7ab54cd82b19fa" + "104abfb5d84579a623b2574b37d22ccae9b3e415e48f5c0f9bcbdff" + "8071d63b9bb956e547af3a8df99e5d3061979652ff96b765cb3ee49" + "3643544c75dbe5bb39834531952a0fb4b0378b3fcbb4c8b5800a533" + "0392a2a04e700bb6ed7e0b85795ea38b1b962741b3f33b9dde2f4ec" + "1354f09e2eb78e95f037a5804b6171659f88715ce1a9b0cc90c27f3" + "5ef2f10ff0c7c7a2bb0154d9b8ebe76a3d764aa879af372f4240de8" + "347937e5a90cec9f41ff2f26b8da9a94a225d1a913717d73f10397d" + "2183f1ba3b7b45a68f1ff1893caf69a827802f7b6a48d51da6fbefb" + "64fd9a6c5b75c4561", + 16, + ), + "digest_algorithm": "SHA-256", + "msg": binascii.unhexlify( + b"4e3a28bcf90d1d2e75f075d9fbe55b36c5529b17bc3a9ccaba6935c9e20" + b"548255b3dfae0f91db030c12f2c344b3a29c4151c5b209f5e319fdf1c23" + b"b190f64f1fe5b330cb7c8fa952f9d90f13aff1cb11d63181da9efc6f7e1" + b"5bfed4862d1a62c7dcf3ba8bf1ff304b102b1ec3f1497dddf09712cf323" + b"f5610a9d10c3d9132659" + ), + "y": int( + "5a55dceddd1134ee5f11ed85deb4d634a3643f5f36dc3a706892564" + "69a0b651ad22880f14ab85719434f9c0e407e60ea420e2a0cd29422" + "c4899c416359dbb1e592456f2b3cce233259c117542fd05f31ea25b" + "015d9121c890b90e0bad033be1368d229985aac7226d1c8c2eab325" + "ef3b2cd59d3b9f7de7dbc94af1a9339eb430ca36c26c46ecfa6c548" + "1711496f624e188ad7540ef5df26f8efacb820bd17a1f618acb50c9" + "bc197d4cb7ccac45d824a3bf795c234b556b06aeb92917345325208" + "4003f69fe98045fe74002ba658f93475622f76791d9b2623d1b5fff" + "2cc16844746efd2d30a6a8134bfc4c8cc80a46107901fb973c28fc5" + "53130f3286c1489da", + 16, + ), + "r": int( + "633055e055f237c38999d81c397848c38cce80a55b649d9e7905c29" + "8e2a51447", + 16, + ), + "s": int( + "2bbf68317660ec1e4b154915027b0bc00ee19cfc0bf75d01930504f" + "2ce10a8b0", + 16, + ), + }, + { + "p": int( + "a8adb6c0b4cf9588012e5deff1a871d383e0e2a85b5e8e03d814fe1" + "3a059705e663230a377bf7323a8fa117100200bfd5adf857393b0bb" + "d67906c081e585410e38480ead51684dac3a38f7b64c9eb109f1973" + "9a4517cd7d5d6291e8af20a3fbf17336c7bf80ee718ee087e322ee4" + "1047dabefbcc34d10b66b644ddb3160a28c0639563d71993a26543e" + "adb7718f317bf5d9577a6156561b082a10029cd44012b18de684450" + "9fe058ba87980792285f2750969fe89c2cd6498db3545638d5379d1" + "25dccf64e06c1af33a6190841d223da1513333a7c9d78462abaab31" + "b9f96d5f34445ceb6309f2f6d2c8dde06441e87980d303ef9a1ff00" + "7e8be2f0be06cc15f", + 16, + ), + "q": int( + "e71f8567447f42e75f5ef85ca20fe557ab0343d37ed09edc3f6e686" + "04d6b9dfb", + 16, + ), + "g": int( + "5ba24de9607b8998e66ce6c4f812a314c6935842f7ab54cd82b19fa" + "104abfb5d84579a623b2574b37d22ccae9b3e415e48f5c0f9bcbdff" + "8071d63b9bb956e547af3a8df99e5d3061979652ff96b765cb3ee49" + "3643544c75dbe5bb39834531952a0fb4b0378b3fcbb4c8b5800a533" + "0392a2a04e700bb6ed7e0b85795ea38b1b962741b3f33b9dde2f4ec" + "1354f09e2eb78e95f037a5804b6171659f88715ce1a9b0cc90c27f3" + "5ef2f10ff0c7c7a2bb0154d9b8ebe76a3d764aa879af372f4240de8" + "347937e5a90cec9f41ff2f26b8da9a94a225d1a913717d73f10397d" + "2183f1ba3b7b45a68f1ff1893caf69a827802f7b6a48d51da6fbefb" + "64fd9a6c5b75c4561", + 16, + ), + "digest_algorithm": "SHA-256", + "msg": binascii.unhexlify( + b"a733b3f588d5ac9b9d4fe2f804df8c256403a9f8eef6f191fc48e1267fb" + b"5b4d546ba11e77b667844e489bf0d5f72990aeb061d01ccd7949a23def7" + b"4a803b7d92d51abfadeb4885ffd8ffd58ab87548a15c087a39b8993b2fa" + b"64c9d31a594eeb7512da16955834336a234435c5a9d0dd9b15a94e11615" + b"4dea63fdc8dd7a512181" + ), + "y": int( + "356ed47537fbf02cb30a8cee0537f300dff1d0c467399ce70b87a87" + "58d5ec9dd256246fccaeb9dfe109f2a984f2ddaa87aad54ce0d31f9" + "07e504521baf4207d7073b0a4a9fc67d8ddda99f87aed6e0367cec2" + "7f9c608af743bf1ee6e11d55a182d43b024ace534029b866f642282" + "8bb81a39aae9601ee81c7f81dd358e69f4e2edfa4654d8a65bc6431" + "1dc86aac4abc1fc7a3f65159661a0d8e288eb8d665cb0adf5ac3d6b" + "a8e9453facf7542393ae24fd50451d3828086558f7ec528e284935a" + "53f67a1aa8e25d8ad5c4ad55d83aef883a4d9eeb6297e6a53f65049" + "ba9e2c6b7953a760bc1dc46f78ceaaa2c02f5375dd82e708744aa40" + "b15799eb81d7e5b1a", + 16, + ), + "r": int( + "bcd490568c0a89ba311bef88ea4f4b03d273e793722722327095a37" + "8dd6f3522", + 16, + ), + "s": int( + "74498fc43091fcdd2d1ef0775f8286945a01cd72b805256b0451f9c" + "bd943cf82", + 16, + ), + }, ] assert expected == load_fips_dsa_sig_vectors(vector_data) def test_load_fips_ecdsa_key_pair_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # CAVS 11.0 # "Key Pair" information # Curves selected: P-192 K-233 B-571 @@ -2346,67 +2702,97 @@ def test_load_fips_ecdsa_key_pair_vectors(): 7d6289980819292a719eb247195529ea60ad62862de0a26c72bfc49ecc81c2f9ed704e3168f Qy = 0721496cf16f988b1aabef3368450441df8439a0ca794170f270ead56203d675b57f5\ a4090a3a2f602a77ff3bac1417f7e25a683f667b3b91f105016a47afad46a0367b18e2bdf0c - """).splitlines() + """ + ).splitlines() expected = [ { "curve": "secp192r1", "d": int("e5ce89a34adddf25ff3bf1ffe6803f57d0220de3118798ea", 16), "x": int("8abf7b3ceb2b02438af19543d3e5b1d573fa9ac60085840f", 16), - "y": int("a87f80182dcd56a6a061f81f7da393e7cffd5e0738c6b245", 16) + "y": int("a87f80182dcd56a6a061f81f7da393e7cffd5e0738c6b245", 16), }, - { "curve": "secp192r1", "d": int("7d14435714ad13ff23341cb567cc91198ff8617cc39751b2", 16), "x": int("39dc723b19527daa1e80425209c56463481b9b47c51f8cbd", 16), "y": int("432a3e84f2a16418834fabaf6b7d2341669512951f1672ad", 16), }, - { "curve": "sect233k1", - "d": int("1da7422b50e3ff051f2aaaed10acea6cbf6110c517da2f4e" - "aca8b5b87", 16), - "x": int("1c7475da9a161e4b3f7d6b086494063543a979e34b8d7ac4" - "4204d47bf9f", 16), - "y": int("131cbd433f112871cc175943991b6a1350bf0cdd57ed8c83" - "1a2a7710c92", 16), + "d": int( + "1da7422b50e3ff051f2aaaed10acea6cbf6110c517da2f4e" "aca8b5b87", + 16, + ), + "x": int( + "1c7475da9a161e4b3f7d6b086494063543a979e34b8d7ac4" + "4204d47bf9f", + 16, + ), + "y": int( + "131cbd433f112871cc175943991b6a1350bf0cdd57ed8c83" + "1a2a7710c92", + 16, + ), }, - { "curve": "sect233k1", - "d": int("530951158f7b1586978c196603c12d25607d2cb0557efadb" - "23cd0ce8", 16), - "x": int("d37500a0391d98d3070d493e2b392a2c79dc736c097ed24b" - "7dd5ddec44", 16), - "y": int("1d996cc79f37d8dba143d4a8ad9a8a60ed7ea760aae1ddba" - "34d883f65d9", 16), + "d": int( + "530951158f7b1586978c196603c12d25607d2cb0557efadb" "23cd0ce8", + 16, + ), + "x": int( + "d37500a0391d98d3070d493e2b392a2c79dc736c097ed24b" + "7dd5ddec44", + 16, + ), + "y": int( + "1d996cc79f37d8dba143d4a8ad9a8a60ed7ea760aae1ddba" + "34d883f65d9", + 16, + ), }, - { "curve": "sect571r1", - "d": int("1443e93c7ef6802655f641ecbe95e75f1f15b02d2e172f49" - "a32e22047d5c00ebe1b3ff0456374461360667dbf07bc67f" - "7d6135ee0d1d46a226a530fefe8ebf3b926e9fbad8d57a6", 16), - "x": int("53e3710d8e7d4138db0a369c97e5332c1be38a20a4a84c36" - "f5e55ea9fd6f34545b864ea64f319e74b5ee9e4e1fa1b7c5" - "b2db0e52467518f8c45b658824871d5d4025a6320ca06f8", 16), - "y": int("3a22cfd370c4a449b936ae97ab97aab11c57686cca99d14e" - "f184f9417fad8bedae4df8357e3710bcda1833b30e297d4b" - "f637938b995d231e557d13f062e81e830af5ab052208ead", 16), + "d": int( + "1443e93c7ef6802655f641ecbe95e75f1f15b02d2e172f49" + "a32e22047d5c00ebe1b3ff0456374461360667dbf07bc67f" + "7d6135ee0d1d46a226a530fefe8ebf3b926e9fbad8d57a6", + 16, + ), + "x": int( + "53e3710d8e7d4138db0a369c97e5332c1be38a20a4a84c36" + "f5e55ea9fd6f34545b864ea64f319e74b5ee9e4e1fa1b7c5" + "b2db0e52467518f8c45b658824871d5d4025a6320ca06f8", + 16, + ), + "y": int( + "3a22cfd370c4a449b936ae97ab97aab11c57686cca99d14e" + "f184f9417fad8bedae4df8357e3710bcda1833b30e297d4b" + "f637938b995d231e557d13f062e81e830af5ab052208ead", + 16, + ), }, - { "curve": "sect571r1", - "d": int("3d2bd44ca9eeee8c860a4873ed55a54bdfdf5dab4060df72" - "92877960b85d1fd496aa33c587347213d7f6bf208a6ab4b4" - "30546e7b6ffbc3135bd12f44a28517867ca3c83a821d6f8", 16), - "x": int("7a7af10f6617090bade18b2e092d0dfdc87cd616db7f2db1" - "33477a82bfe3ea421ebb7d6289980819292a719eb2471955" - "29ea60ad62862de0a26c72bfc49ecc81c2f9ed704e3168f", 16), - "y": int("721496cf16f988b1aabef3368450441df8439a0ca794170f" - "270ead56203d675b57f5a4090a3a2f602a77ff3bac1417f7" - "e25a683f667b3b91f105016a47afad46a0367b18e2bdf0c", 16), + "d": int( + "3d2bd44ca9eeee8c860a4873ed55a54bdfdf5dab4060df72" + "92877960b85d1fd496aa33c587347213d7f6bf208a6ab4b4" + "30546e7b6ffbc3135bd12f44a28517867ca3c83a821d6f8", + 16, + ), + "x": int( + "7a7af10f6617090bade18b2e092d0dfdc87cd616db7f2db1" + "33477a82bfe3ea421ebb7d6289980819292a719eb2471955" + "29ea60ad62862de0a26c72bfc49ecc81c2f9ed704e3168f", + 16, + ), + "y": int( + "721496cf16f988b1aabef3368450441df8439a0ca794170f" + "270ead56203d675b57f5a4090a3a2f602a77ff3bac1417f7" + "e25a683f667b3b91f105016a47afad46a0367b18e2bdf0c", + 16, + ), }, ] @@ -2414,7 +2800,8 @@ def test_load_fips_ecdsa_key_pair_vectors(): def test_load_fips_ecdsa_signing_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # CAVS 11.2 # "SigVer" information for "ecdsa_values" # Curves/SHAs selected: P-192, B-571,SHA-512 @@ -2481,7 +2868,8 @@ def test_load_fips_ecdsa_signing_vectors(): bdcf3035f6829ede041b745955d219dc5d30ddd8b37f6ba0f6d2857504cdc68a1ed812a10 S = 34db9998dc53527114518a7ce3783d674ca8cced823fa05e2942e7a0a20b3cc583dcd9\ 30c43f9b93079c5ee18a1f5a66e7c3527c18610f9b47a4da7e245ef803e0662e4d2ad721c - """).splitlines() + """ + ).splitlines() expected = [ { @@ -2499,7 +2887,7 @@ def test_load_fips_ecdsa_signing_vectors(): "y": int("76fab681d00b414ea636ba215de26d98c41bd7f2e4d65477", 16), "r": int("6994d962bdd0d793ffddf855ec5bf2f91a9698b46258a63e", 16), "s": int("02ba6465a234903744ab02bc8521405b73cf5fc00e1a9f41", 16), - "fail": True + "fail": True, }, { "curve": "secp192r1", @@ -2527,22 +2915,37 @@ def test_load_fips_ecdsa_signing_vectors(): b"d74e38983b24c0748618e2f92ef7cac257ff4bd1f41113f2891eb13c4793" b"0e69ddbe91f270fb" ), - "d": int("3e1b03ffca4399d5b439fac8f87a5cb06930f00d304193d7daf83d59" - "47d0c1e293f74aef8e56849f16147133c37a6b3d1b1883e5d61d6b87" - "1ea036c5291d9a74541f28878cb986", 16), - "x": int("3b236fc135d849d50140fdaae1045e6ae35ef61091e98f5059b30eb1" - "6acdd0deb2bc0d3544bc3a666e0014e50030134fe5466a9e4d3911ed" - "580e28851f3747c0010888e819d3d1f", 16), - "y": int("3a8b6627a587d289032bd76374d16771188d7ff281c39542c8977f68" - "72fa932e5daa14e13792dea9ffe8e9f68d6b525ec99b81a5a60cfb05" - "90cc6f297cfff8d7ba1a8bb81fe2e16", 16), - "r": int("2eb1c5c1fc93cf3c8babed12c031cf1504e094174fd335104cbe4a2a" - "bd210b5a14b1c3a455579f1ed0517c31822340e4dd3c1f967e1b4b9d" - "071a1072afc1a199f8c548cd449a634", 16), - "s": int("22f97bb48641235826cf4e597fa8de849402d6bd6114ad2d7fbcf53a" - "08247e5ee921f1bd5994dffee36eedff5592bb93b8bb148214da3b7b" - "aebffbd96b4f86c55b3f6bbac142442", 16), - "fail": False + "d": int( + "3e1b03ffca4399d5b439fac8f87a5cb06930f00d304193d7daf83d59" + "47d0c1e293f74aef8e56849f16147133c37a6b3d1b1883e5d61d6b87" + "1ea036c5291d9a74541f28878cb986", + 16, + ), + "x": int( + "3b236fc135d849d50140fdaae1045e6ae35ef61091e98f5059b30eb1" + "6acdd0deb2bc0d3544bc3a666e0014e50030134fe5466a9e4d3911ed" + "580e28851f3747c0010888e819d3d1f", + 16, + ), + "y": int( + "3a8b6627a587d289032bd76374d16771188d7ff281c39542c8977f68" + "72fa932e5daa14e13792dea9ffe8e9f68d6b525ec99b81a5a60cfb05" + "90cc6f297cfff8d7ba1a8bb81fe2e16", + 16, + ), + "r": int( + "2eb1c5c1fc93cf3c8babed12c031cf1504e094174fd335104cbe4a2a" + "bd210b5a14b1c3a455579f1ed0517c31822340e4dd3c1f967e1b4b9d" + "071a1072afc1a199f8c548cd449a634", + 16, + ), + "s": int( + "22f97bb48641235826cf4e597fa8de849402d6bd6114ad2d7fbcf53a" + "08247e5ee921f1bd5994dffee36eedff5592bb93b8bb148214da3b7b" + "aebffbd96b4f86c55b3f6bbac142442", + 16, + ), + "fail": False, }, { "curve": "sect571r1", @@ -2554,28 +2957,44 @@ def test_load_fips_ecdsa_signing_vectors(): b"0f10bc31c249b7b46edd2462a55f85560d99bde9d5b06b97817d1dbe0a67" b"c701d6e6e7878272" ), - "d": int("2e09ffd8b434bb7f67d1d3ccf482164f1653c6e4ec64dec2517aa21b" - "7a93b2b21ea1eebb54734882f29303e489f02e3b741a87287e2dcdf3" - "858eb6d2ec668f8b5b26f442ce513a2", 16), - "x": int("36f1be8738dd7dae4486b86a08fe90424f3673e76b10e739442e15f3" - "bfafaf841842ac98e490521b7e7bb94c127529f6ec6a42cc6f06fc80" - "606f1210fe020ff508148f93301c9d3", 16), - "y": int("4d39666ebe99fe214336ad440d776c88eb916f2f4a3433548b87d2ae" - "bed840b424d15c8341b4a0a657bf6a234d4fe78631c8e07ac1f4dc74" - "74cd6b4545d536b7b17c160db4562d9", 16), - "r": int("3d8105f87fe3166046c08e80a28acc98a80b8b7a729623053c2a9e80" - "afd06756edfe09bdcf3035f6829ede041b745955d219dc5d30ddd8b3" - "7f6ba0f6d2857504cdc68a1ed812a10", 16), - "s": int("34db9998dc53527114518a7ce3783d674ca8cced823fa05e2942e7a0" - "a20b3cc583dcd930c43f9b93079c5ee18a1f5a66e7c3527c18610f9b" - "47a4da7e245ef803e0662e4d2ad721c", 16) - } + "d": int( + "2e09ffd8b434bb7f67d1d3ccf482164f1653c6e4ec64dec2517aa21b" + "7a93b2b21ea1eebb54734882f29303e489f02e3b741a87287e2dcdf3" + "858eb6d2ec668f8b5b26f442ce513a2", + 16, + ), + "x": int( + "36f1be8738dd7dae4486b86a08fe90424f3673e76b10e739442e15f3" + "bfafaf841842ac98e490521b7e7bb94c127529f6ec6a42cc6f06fc80" + "606f1210fe020ff508148f93301c9d3", + 16, + ), + "y": int( + "4d39666ebe99fe214336ad440d776c88eb916f2f4a3433548b87d2ae" + "bed840b424d15c8341b4a0a657bf6a234d4fe78631c8e07ac1f4dc74" + "74cd6b4545d536b7b17c160db4562d9", + 16, + ), + "r": int( + "3d8105f87fe3166046c08e80a28acc98a80b8b7a729623053c2a9e80" + "afd06756edfe09bdcf3035f6829ede041b745955d219dc5d30ddd8b3" + "7f6ba0f6d2857504cdc68a1ed812a10", + 16, + ), + "s": int( + "34db9998dc53527114518a7ce3783d674ca8cced823fa05e2942e7a0" + "a20b3cc583dcd930c43f9b93079c5ee18a1f5a66e7c3527c18610f9b" + "47a4da7e245ef803e0662e4d2ad721c", + 16, + ), + }, ] assert expected == load_fips_ecdsa_signing_vectors(vector_data) def test_load_kasvs_dh_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ [SHA(s) supported (Used for hashing Z): SHA256 ] # Generated on Thu Mar 17 20:44:26 2011 @@ -2745,70 +3164,83 @@ def test_load_kasvs_dh_vectors(): d518475576730ed528779366568e46b7dd4ed787cb72d0733c93 CAVSHashZZ = 17dbbaa7a20c1390cd8cb3d31ee947bf9dde87739e067b9861ffeea9 Result = P (0 - Correct) - """).splitlines() + """ + ).splitlines() expected = [ { - 'fail_agree': False, - 'fail_z': False, - 'g': int( + "fail_agree": False, + "fail_z": False, + "g": int( "a51883e9ac0539859df3d25c716437008bb4bd8ec4786eb4bc643299daef5" "e3e5af5863a6ac40a597b83a27583f6a658d408825105b16d31b6ed088fc6" "23f648fd6d95e9cefcb0745763cddf564c87bcf4ba7928e74fd6a3080481f" "588d535e4c026b58a21e1e5ec412ff241b436043e29173f1dc6cb943c0974" - "2de989547288", 16), - 'p': int( + "2de989547288", + 16, + ), + "p": int( "da3a8085d372437805de95b88b675122f575df976610c6a844de99f1df82a" "06848bf7a42f18895c97402e81118e01a00d0855d51922f434c022350861d" "58ddf60d65bc6941fc6064b147071a4c30426d82fc90d888f94990267c64b" "eef8c304a4b2b26fb93724d6a9472fa16bc50c5b9b8b59afb62cfe9ea3ba0" - "42c73a6ade35", 16), - 'q': 1386090807861091316803998193774751098153687863463, - 'x1': 381229709512864262422021151581620734547375903702, - 'x2': 479735944608461101114916716909067001453470352916, - 'y1': int( + "42c73a6ade35", + 16, + ), + "q": 1386090807861091316803998193774751098153687863463, + "x1": 381229709512864262422021151581620734547375903702, + "x2": 479735944608461101114916716909067001453470352916, + "y1": int( "5a7890f6d20ee9c7162cd84222cb0c7cb5b4f29244a58fc95327fc41045f4" "76fb3da42fca76a1dd59222a7a7c3872d5af7d8dc254e003eccdb38f29161" "9c51911df2b6ed67d0b459f4bc25819c0078777b9a1a24c72e7c037a3720a" "1edad5863ef5ac75ce816869c820859558d5721089ddbe331f55bef741396" - "a3bbf85c6c1a", 16), - 'y2': int( + "a3bbf85c6c1a", + 16, + ), + "y2": int( "b92af0468b841ea5de4ca91d895b5e922245421de57ed7a88d2de41610b20" "8e8e233705f17b2e9eb91914bad2fa87f0a58519a7da2980bc06e7411c925" "a6050526bd86e621505e6f610b63fdcd9afcfaa96bd087afca44d9197cc35" "b559f731357a5b979250c0f3a254bb8165f5072156e3fd6f9a6e69bcf4b45" - "78f78b3bde7", 16), - 'z': binascii.unhexlify( + "78f78b3bde7", + 16, + ), + "z": binascii.unhexlify( b"8d8f4175e16e15a42eb9099b11528af88741cc206a088971d3064bb291ed" b"a608d1600bff829624db258fd15e95d96d3e74c6be3232afe5c855b9c596" b"81ce13b7aea9ff2b16707e4c02f0e82bf6dadf2149ac62630f6c62dea0e5" b"05e3279404da5ffd5a088e8474ae0c8726b8189cb3d2f04baffe700be849" b"df9f91567fc2ebb8" - ) + ), }, { - 'fail_agree': False, - 'fail_z': False, - 'g': int( + "fail_agree": False, + "fail_z": False, + "g": int( "a51883e9ac0539859df3d25c716437008bb4bd8ec4786eb4bc643299daef5" "e3e5af5863a6ac40a597b83a27583f6a658d408825105b16d31b6ed088fc6" "23f648fd6d95e9cefcb0745763cddf564c87bcf4ba7928e74fd6a3080481f" "588d535e4c026b58a21e1e5ec412ff241b436043e29173f1dc6cb943c0974" - "2de989547288", 16), - 'p': int( + "2de989547288", + 16, + ), + "p": int( "da3a8085d372437805de95b88b675122f575df976610c6a844de99f1df82a" "06848bf7a42f18895c97402e81118e01a00d0855d51922f434c022350861d" "58ddf60d65bc6941fc6064b147071a4c30426d82fc90d888f94990267c64b" "eef8c304a4b2b26fb93724d6a9472fa16bc50c5b9b8b59afb62cfe9ea3ba0" - "42c73a6ade35", 16), - 'q': 1386090807861091316803998193774751098153687863463, - 'x1': int( - "32e642683d745a23dccf4f12f989d8dfd1fd9894c422930950cb4c71", - 16), - 'x2': int( - "7d8ae93df3bc09d399a4157ec562126acf51092c3269ab27f60a3a2b", - 16), - 'y1': int( + "42c73a6ade35", + 16, + ), + "q": 1386090807861091316803998193774751098153687863463, + "x1": int( + "32e642683d745a23dccf4f12f989d8dfd1fd9894c422930950cb4c71", 16 + ), + "x2": int( + "7d8ae93df3bc09d399a4157ec562126acf51092c3269ab27f60a3a2b", 16 + ), + "y1": int( "8cd371363b32fcc2e936e345f2278b77001f2efdf78512c3ee75c12f88507" "e2d5c0e5cdded3bb78435506c8028a3f4d6f028c0f49a0d61f1285795197e" "56deac80279e723f2b3746e213ac8ec60f1cefc2308ff17a7e9e2efab537e" @@ -2817,8 +3249,10 @@ def test_load_kasvs_dh_vectors(): "3e1c450c5798dc05f8265ad9e35095ff112af9e889f00315fa337a76a4506" "70866eca12cc6ad0778576962eb9cdc12721d3c15e4d87b67488a145d4002" "40670eb26695a42879cd3940a55087f6527667277e1212a202dbe455c45c6" - "4b9be4a38153557bbb8fd755", 16), - 'y2': int( + "4b9be4a38153557bbb8fd755", + 16, + ), + "y2": int( "22127e9728e906ea4b1512c8b1e80474b58446210c23ccfc800f83c2c15da" "8159940e494b235266f6a9d5f80529067794f1a9edd566755d23d0a3060fe" "074c5a10122df3e472973bba39ea3a988e8387f5f0491e590b6b5edc299b4" @@ -2827,8 +3261,10 @@ def test_load_kasvs_dh_vectors(): "6c3d75d9bcf83f4b8d1ed39408bd8d973b4ea81e8e832eac361dcd5307133" "88a60971ea9f8b1e69c1e99df1cca12bdaf293dacfa1419c5692ceffa9198" "8aef3321ac8cbc2efae6c4337c8808310fb5a240395a98e6004fe613c39e8" - "4f4177341746d9e388dcb2e8", 16), - 'z': binascii.unhexlify( + "4f4177341746d9e388dcb2e8", + 16, + ), + "z": binascii.unhexlify( b"0efeaa399a182e0a603baf0dd95aa0fae5289ebd47d5f0f60c86bc936839" b"c31c9f7f37bf04f76ab02f4094a8ab10ed907ec7291585cc085c3e8981df" b"2bd46a01c19ec9a2f66709df1d4fefbeb48c8263554e46890f59eb642bf9" @@ -2838,31 +3274,35 @@ def test_load_kasvs_dh_vectors(): b"ce2a585eb9e8f308b48cf4e29593b6f7a02e8625e1e8bff1ea1405f8c8c3" b"4b8339a9a99c7c9de4eb9895df7719ccda9394f53080eff1226f6b9c7ae0" b"a38941e18b1a137aabbb62308eb35ba2" - ) + ), }, { - 'fail_agree': False, - 'fail_z': True, - 'g': int( + "fail_agree": False, + "fail_z": True, + "g": int( "a51883e9ac0539859df3d25c716437008bb4bd8ec4786eb4bc643299daef5" "e3e5af5863a6ac40a597b83a27583f6a658d408825105b16d31b6ed088fc6" "23f648fd6d95e9cefcb0745763cddf564c87bcf4ba7928e74fd6a3080481f" "588d535e4c026b58a21e1e5ec412ff241b436043e29173f1dc6cb943c0974" - "2de989547288", 16), - 'p': int( + "2de989547288", + 16, + ), + "p": int( "da3a8085d372437805de95b88b675122f575df976610c6a844de99f1df82a" "06848bf7a42f18895c97402e81118e01a00d0855d51922f434c022350861d" "58ddf60d65bc6941fc6064b147071a4c30426d82fc90d888f94990267c64b" "eef8c304a4b2b26fb93724d6a9472fa16bc50c5b9b8b59afb62cfe9ea3ba0" - "42c73a6ade35", 16), - 'q': 1386090807861091316803998193774751098153687863463, - 'x1': int( - "66502429aba271e2f2ee2197a2b336e5f0467f192aa28b60dcbf1194", - 16), - 'x2': int( - "106b358be4f068348ac240ecbb454e5c39ca80b078cb0fafd856e9c5", - 16), - 'y1': int( + "42c73a6ade35", + 16, + ), + "q": 1386090807861091316803998193774751098153687863463, + "x1": int( + "66502429aba271e2f2ee2197a2b336e5f0467f192aa28b60dcbf1194", 16 + ), + "x2": int( + "106b358be4f068348ac240ecbb454e5c39ca80b078cb0fafd856e9c5", 16 + ), + "y1": int( "dfb001294215423d7146a2453cdb8598ccef01e1d931a913c3e4ed4a3cf38" "a912066c28e4eaf77dd80ff07183a6160bd95932f513402f864dcf7a70cbe" "dc9b60bbfbc67f72a83d5f6463a2b5a4fc906d3e921f5e1069126113265b4" @@ -2871,8 +3311,10 @@ def test_load_kasvs_dh_vectors(): "51043d351bb74a952e6a694e6e7456f714c47d7c8eeeb4fd83ad93c86b784" "45f9393fdfd65c7dbd7fd6eba9794ddf183901b1d213321fd0ab3f7588ab0" "f6b3692f365a87131eda0e062505861988f6ce63150207545ecf9678e0971" - "330253dfb7cfd546c5346fec", 16), - 'y2': int( + "330253dfb7cfd546c5346fec", + 16, + ), + "y2": int( "715d0781975b7b03162f4401c1eda343fd9bf1140006034573b31828a618c" "356163554cd27da956f7179a69e860fb6efeaa2e2aa9f1261506a8344c492" "9953621381b13d6426e152c0f2f94bfcd2b758eca24923596d427ed8f957e" @@ -2881,8 +3323,10 @@ def test_load_kasvs_dh_vectors(): "ad5c5bd490ea600e04379232fb1077fbf394f4579accdbe352714e25b8891" "6dca8d8f7e0c4ed9594f7693f656a235a2e88ebda48b0d557e32da9f12d2a" "4c3180f05b16b4fba9bec79278a3971b77f9223b5ab78b857e0376c500821" - "1592c8c72d521373ee3b22b8", 16), - 'z': binascii.unhexlify( + "1592c8c72d521373ee3b22b8", + 16, + ), + "z": binascii.unhexlify( b"cf879ebd107bb877457809c3fc410218b7acba3c5967495a8f1c3370d57f" b"038a48dd69f9f69b9f4dd855e7c58a1e4ec32646a978266eb314db468ea1" b"dfcee8a85a1644a5732498c4fbcdf85098c6ed0ce12e431e99142fd23353" @@ -2892,12 +3336,12 @@ def test_load_kasvs_dh_vectors(): b"665095490056287e4fc49e6cb3181cb2bf06444fd0040150271c9ce1f61c" b"13ecd5dd022194a2dbf3e1c7fbc6bd19497c7b888b4da613d28fa6f378a4" b"3369cb8795a1c823f7d6cf4d84bba578" - ) + ), }, { - 'fail_agree': True, - 'fail_z': False, - 'g': int( + "fail_agree": True, + "fail_z": False, + "g": int( "35513ec441402b78353ab1bba550b21c76c89973885a627170262ef52497d" "5d137b8927a212aaab2f051198c90bb81dffd9eb10b36b7ca3b63565b4c10" "25aea3b5e9c4a348c9cfa17f3907a1e4469701c0dedb8a4b9e96c5965b1fb" @@ -2906,8 +3350,10 @@ def test_load_kasvs_dh_vectors(): "65bb4e1e9474993fe382fd23480dc875861be152997a621fdb7aef977ea5b" "4d3d74486b162dc28f95a64cf65587a919a57eef92934fc9410df7f09fa82" "f975328ed82ff29cc3e15a971f56f4ac2dcb289252575e02a6cdb7fcc6cdd" - "d7b0dca9c422e63eb2b8f05", 16), - 'p': int( + "d7b0dca9c422e63eb2b8f05", + 16, + ), + "p": int( "f3722b9b911c6aede9eaeeaa406283de66a097f39a7225df6c3c916e57920" "d356e50478d307dbfd146bfb91b6f68ecbbcf54b3d19c33a4b17293fea3e3" "d6bff8ac4cca93a805386f062a8a27ae906ef5da94d279fd7b3d7289e0095" @@ -2916,17 +3362,19 @@ def test_load_kasvs_dh_vectors(): "3c3dfda8de8429e087c5be97fc5c9db9526031ad3a218bd9916fb4a3c2796" "6d208b1e360014c01e95530c148fb3cd27e6a7250d3c3b81dcd220ca14548" "dbccf99ebb9e334db6bcd14e632c98dd3f9860af7ae450f1b7809b45f0ec1" - "0e6f27672beebc9963befc73", 16), - 'q': int( - "a9a17de95a29091bf8e07dab53ea1aba9403be3c61027c6c8f48bac5", - 16), - 'x1': int( - "1610eaa4e0ccc8857e2b53149e008492b1fbd9025a6e8d95aaee9c0f", - 16), - 'x2': int( - "c4c83d75b27864b052cadc556e500e25aabf0c9d1bc01f0e1fe3862", - 16), - 'y1': int( + "0e6f27672beebc9963befc73", + 16, + ), + "q": int( + "a9a17de95a29091bf8e07dab53ea1aba9403be3c61027c6c8f48bac5", 16 + ), + "x1": int( + "1610eaa4e0ccc8857e2b53149e008492b1fbd9025a6e8d95aaee9c0f", 16 + ), + "x2": int( + "c4c83d75b27864b052cadc556e500e25aabf0c9d1bc01f0e1fe3862", 16 + ), + "y1": int( "51ee21cd9f97015180f258fad5c94ff5a458806b1412087236bf77fe87aae" "1a36735816ed6e2160a731159814b6ae1f3f52c478dd9207094adfb62f766" "7d5c366327e66d23096395e938504db330953a708015f861fe9d948761109" @@ -2935,8 +3383,10 @@ def test_load_kasvs_dh_vectors(): "a6f14ccdb29db02f64911bd83bfdcdfc843dd14a4cab9acb0bda8b293d2f5" "f7050768e57533cbc415a29e6f31cc365e107f91ae3722484e2c7329a85af" "69055a5a104da37e810878896d1b247b02b75234ecff82b1958f42d7b0316" - "22e9394c98b5229112f7f620", 16), - 'y2': int( + "22e9394c98b5229112f7f620", + 16, + ), + "y2": int( "467a857337a82472a1307a64dccc8e9994c5c63ec4312936885d17be41905" "1a5f037fbb052d7010ebe01634d9e8b8b522d9ab4749fdc274f465369b89e" "360df8f70b7865a3c71d2dbcd2df19e9293dab1153d3d63fcb7deb559b684" @@ -2945,8 +3395,10 @@ def test_load_kasvs_dh_vectors(): "c193f460dcd0be7e6e06e546da7653770dc5859df87029e722dbe81361030" "569148d1636988926bf0dcfe47c9d8a54698c08b3b5c70afe86b5c6f64346" "3f8f34889d27d6cfd2d478c2d7b3d008a985c7380f0b43f10024b59c35438" - "80883c42d0e7e0a07326ba3a", 16), - 'z': binascii.unhexlify( + "80883c42d0e7e0a07326ba3a", + 16, + ), + "z": binascii.unhexlify( b"10a30bacab82e652415376baffdbc008c7eb2e5a3aa68bc10ce486ca8498" b"3fd89b1b027bb40e75333406361005f5e756526a95fe01202df9217d81b1" b"713d5187c368fdd4c9c2433d9e6c18844769479b725c4140c92a304ee1bc" @@ -2956,41 +3408,47 @@ def test_load_kasvs_dh_vectors(): b"68c90178974a0602436cd186748bcc63a629edc3a0db59415cccd37a6513" b"0ea477c89da92d41371f5972891cf41f9c7f0e75ccbff9893225384db30d" b"aa5e310f08e3e0fad98bcdf8ecf35fe5" - ) + ), }, { - 'fail_agree': False, - 'fail_z': False, - 'g': int("35513ec441402b78353ab1bba550b21c76c89973885a627170262ef5" - "2497d5d137b8927a212aaab2f051198c90bb81dffd9eb10b36b7ca3b" - "63565b4c1025aea3b5e9c4a348c9cfa17f3907a1e4469701c0dedb8a" - "4b9e96c5965b1fb8c229b0c34baac774bf9dda4fc5ee8764358b3c84" - "812878aab7464bc09e97aecab7d7e3fbb4870e2a3b89667a4158bf1e" - "d1a90dfaf47019fbb52b1b96365bb4e1e9474993fe382fd23480dc87" - "5861be152997a621fdb7aef977ea5b4d3d74486b162dc28f95a64cf6" - "5587a919a57eef92934fc9410df7f09fa82f975328ed82ff29cc3e15" - "a971f56f4ac2dcb289252575e02a6cdb7fcc6cddd7b0dca9c422e63e" - "b2b8f05", 16), - 'p': int("f3722b9b911c6aede9eaeeaa406283de66a097f39a7225df6c3c916e" - "57920d356e50478d307dbfd146bfb91b6f68ecbbcf54b3d19c33a4b1" - "7293fea3e3d6bff8ac4cca93a805386f062a8a27ae906ef5da94d279" - "fd7b3d7289e00956f76bae9c0d2b8d11742ca5809630632aae58f9c6" - "dce00c7380581deffde2187b022f83c6ceaeaadb0844a17fcbb04039" - "ca6843c91f0c9058b22434b263c3dfda8de8429e087c5be97fc5c9db" - "9526031ad3a218bd9916fb4a3c27966d208b1e360014c01e95530c14" - "8fb3cd27e6a7250d3c3b81dcd220ca14548dbccf99ebb9e334db6bcd" - "14e632c98dd3f9860af7ae450f1b7809b45f0ec10e6f27672beebc99" - "63befc73", 16), - 'q': int( - "a9a17de95a29091bf8e07dab53ea1aba9403be3c61027c6c8f48bac5", - 16), - 'x1': int( - "9ee22ac51664e40e0a24dbb94142dba40605e2b6eeaaa0268a0f6847", - 16), - 'x2': int( - "438093a468236658821bf64eb08456139963d4fb27121c3ed6c55876", - 16), - 'y1': int( + "fail_agree": False, + "fail_z": False, + "g": int( + "35513ec441402b78353ab1bba550b21c76c89973885a627170262ef5" + "2497d5d137b8927a212aaab2f051198c90bb81dffd9eb10b36b7ca3b" + "63565b4c1025aea3b5e9c4a348c9cfa17f3907a1e4469701c0dedb8a" + "4b9e96c5965b1fb8c229b0c34baac774bf9dda4fc5ee8764358b3c84" + "812878aab7464bc09e97aecab7d7e3fbb4870e2a3b89667a4158bf1e" + "d1a90dfaf47019fbb52b1b96365bb4e1e9474993fe382fd23480dc87" + "5861be152997a621fdb7aef977ea5b4d3d74486b162dc28f95a64cf6" + "5587a919a57eef92934fc9410df7f09fa82f975328ed82ff29cc3e15" + "a971f56f4ac2dcb289252575e02a6cdb7fcc6cddd7b0dca9c422e63e" + "b2b8f05", + 16, + ), + "p": int( + "f3722b9b911c6aede9eaeeaa406283de66a097f39a7225df6c3c916e" + "57920d356e50478d307dbfd146bfb91b6f68ecbbcf54b3d19c33a4b1" + "7293fea3e3d6bff8ac4cca93a805386f062a8a27ae906ef5da94d279" + "fd7b3d7289e00956f76bae9c0d2b8d11742ca5809630632aae58f9c6" + "dce00c7380581deffde2187b022f83c6ceaeaadb0844a17fcbb04039" + "ca6843c91f0c9058b22434b263c3dfda8de8429e087c5be97fc5c9db" + "9526031ad3a218bd9916fb4a3c27966d208b1e360014c01e95530c14" + "8fb3cd27e6a7250d3c3b81dcd220ca14548dbccf99ebb9e334db6bcd" + "14e632c98dd3f9860af7ae450f1b7809b45f0ec10e6f27672beebc99" + "63befc73", + 16, + ), + "q": int( + "a9a17de95a29091bf8e07dab53ea1aba9403be3c61027c6c8f48bac5", 16 + ), + "x1": int( + "9ee22ac51664e40e0a24dbb94142dba40605e2b6eeaaa0268a0f6847", 16 + ), + "x2": int( + "438093a468236658821bf64eb08456139963d4fb27121c3ed6c55876", 16 + ), + "y1": int( "c2630c9d38ed5c825d1c6a3eba7143f3fc8a049c8bcd1efc212d2af64eca9" "94308208691d330aa8f27fc4a1e55de4e512113996d21375a667f8c26d76d" "ee2f6809b15432a33fb735aca5c2263940f58712bded08f55443dee300b94" @@ -2999,8 +3457,10 @@ def test_load_kasvs_dh_vectors(): "d43c4ffc9a605addbdcce0cb3790c6db846156bb857a7b3df40dc6ed04d19" "cc9eaebb6bbc034e77c3d882a1a62317cce25b6130f0803e3bc49b5e36768" "260073a617034872be0b50bed32740224beaf582d67fbcfef3b3ecc18f9c7" - "1c782e9a68495ef31dc7986e", 16), - 'y2': int( + "1c782e9a68495ef31dc7986e", + 16, + ), + "y2": int( "e192da8e1244e27221c1765344a5bb379dce741d427a734b4bdb6c4d16b24" "90bd37564d745008e63ae46ef332331d79887ac63298ce143e125f8b320c0" "f859b7f5f2c1e0053e4a7a16997e6143ff702300c9863ae7caef5c1dfca0e" @@ -3009,8 +3469,10 @@ def test_load_kasvs_dh_vectors(): "a56431cd48579bf53c903bbe066dd78b23c0996ef3a880f0d91315104366a" "82f01abdecce96fd371f94e8420f8bc5b896c801df573554f749b03d0d28b" "1e1a990bc61c7e9659342ac7e268e9c0b7c40fdaab394f29cf0a54f780022" - "f9a03b0bd28eb7db8b0b1b47", 16), - 'z': binascii.unhexlify( + "f9a03b0bd28eb7db8b0b1b47", + 16, + ), + "z": binascii.unhexlify( b"56f8f40fa4b8f3580f9014b30d60a42933a53a62182a690142f458dc275c" b"3b2f0e721bc5ee6e890b14516419110f5252ff1cceea8e274b2987aa78e3" b"bae90c1935b276b7a1f1c944f79d4774b7a85b3355bdf25cb02bddfbda4e" @@ -3020,8 +3482,8 @@ def test_load_kasvs_dh_vectors(): b"b75d049d4c82097af8a5ce353e14416b3eeb31ba9bc4f6f3dbd846c5299f" b"b5c0043a1b95b9149b39d14df9e6a69547abf8a4d518475576730ed52877" b"9366568e46b7dd4ed787cb72d0733c93" - ) - } + ), + }, ] assert expected == load_kasvs_dh_vectors(vector_data) @@ -3032,7 +3494,8 @@ def test_load_kasvs_ecdh_vectors_empty_vector_data(): def test_load_kasvs_ecdh_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # CAVS 11.0 # Parameter set(s) supported: EA EB EC ED EE # CAVSid: CAVSid (in hex: 434156536964) @@ -3183,148 +3646,291 @@ def test_load_kasvs_ecdh_vectors(): - """).splitlines() + """ + ).splitlines() expected = [ - {'errno': 0, - 'fail': False, - 'COUNT': 0, - 'CAVS': { - 'd': int("f70c297a683d6b7ef82b5af7349606c4447c8b4fc6fa5e80", 16), - 'x': int("f7b5061fb557e516c50abf541d97dbfd76ca7172b22cf590", 16), - 'y': int("135e15e21f9e85c76205fd148a92ac19f9e6243ddab322d1", 16)}, - 'IUT': { - 'd': int("a5b4bbad57f101ca48021cb7440cd681a9d40cd51b99d917", 16), - 'x': int("79a77fcb18a32cdb59ed5d87740f29e8565d649dbf01ce86", 16), - 'y': int("f7187efaa0b1573f1fb00905d46810b880bf738b4c720bb7", 16)}, - 'Z': int("26382468d721761e14a87dc3bee67340095c6455962d1ba3", 16), - 'curve': 'secp192r1'}, - - {'errno': 8, - 'fail': True, - 'COUNT': 2, - 'CAVS': { - 'd': int("5f909dcb0ccce58c82fada748c47297579e6a981b5518a96", 16), - 'x': int("537f1ecfda0e366de393a9bc8188fcc280311bffefe21ecf", 16), - 'y': int("a1fa1f98498d65f2754caff4e5303a4066a5ff89fde95381", 16)}, - 'IUT': { - 'd': int("3357aa7f47f3e09421602cc12cdce4434c68e330d44de05e", 16), - 'x': int("6a33d43d9c72173eabc7a771a5687748c4774c62762e96ec", 16), - 'y': int("8033f238b3abc69470aad4be8dbe4f60a2fd50207626c56a", 16)}, - 'Z': int("3153034f6617326f19c35be8c99a0585431adf09d2f8e0fd", 16), - 'curve': 'secp192r1'}, - - {'errno': 13, - 'fail': False, - 'COUNT': 8, - 'CAVS': { - 'd': int("8fcfaf0524cc868fad20e50410a2205319f1327308d98dc8", 16), - 'x': int("9b0243d80a9e328738080fb4d46bc450243d0efb7ead0c92", 16), - 'y': int("ad5bebad7f03849693071537f60ef858cad214123beee7c7", 16)}, - 'IUT': { - 'd': int("bba95dac90289cb68ca2b006f9757219b70579c299ad7a7d", 16), - 'x': int("7733dc0cb365cd6312724196b9b4eb491fd4d2e31b9afdb1", 16), - 'y': int("92ffa3722acc5b94d772258ba2d471b06c0f53f56fcd8662", 16)}, - 'Z': int("0f3c6e4a29a08296ae730f56a1ebf819ea2edfa6f0434e40", 16), - 'curve': 'secp192r1'}, - - {'errno': 0, - 'fail': False, - 'COUNT': 0, - 'CAVS': { - 'd': int("e53a88af7cf8ce6bf13c8b9ad191494e37a6acc1368c71f4" - "306e39e5", 16), - 'x': int("3a24217c4b957fea922eec9d9ac52d5cb4b3fcd95efde1e4" - "fa0dd6e2", 16), - 'y': int("775b94025a808eb6f4af14ea4b57dca576c35373c6dc198b" - "15b981df", 16)}, - 'IUT': { - 'd': int("09f51e302c6a0fe6ff48f34c208c6af91e70f65f88102e6f" - "cab9af4a", 16), - 'x': int("c5d5706ccd7424c74fd616e699865af96e56f39adea6aa05" - "9e5092b5", 16), - 'y': int("f0729077bb602404d56d2f7e2ba5bb2f383df4a542556788" - "1ff0165d", 16)}, - 'Z': int("b1259ceedfb663d9515089cf727e7024fb3d86cbcec611b4" - "ba0b4ab6", 16), - 'curve': 'secp224r1'}, - - {'errno': 2, - 'fail': True, - 'COUNT': 0, - 'CAVS': { - 'd': int("305dfb4a8850cc59280891147baf457bfe5e2bae98457163" - "4a77dc8d3472fa9b", 16), - 'x': int("202cb5a224e6c2a84e624094486edf04116c8d68ec1f4a0e" - "0ed9ee090e1a900b", 16), - 'y': int("cacf3a5789bb33954be600425d62d9eae5371f90f8816725" - "8814213e4a4f4b1a", 16)}, - 'IUT': { - 'd': int("72cc52808f294b64b6f7233c3d2f5d96cc1d29287320e39e" - "1c151deef0bc14eb", 16), - 'x': int("49a768c9a4ca56e374f685dd76a461b1016c59dcded2c8d8" - "cbd9f23ca453831f", 16), - 'y': int("b1e3bb9b5f12a3b5ae788535d4554bd8c46e0e6130075e4e" - "437d3854cf8f1c34", 16)}, - 'Z': int("c0147c3c2691b450b5edc08b51aea224d9f4359ff67aab6d" - "a3146f396dbceaea", 16), - 'curve': 'secp256r1'}, - - {'errno': 0, - 'fail': False, - 'COUNT': 0, - 'CAVS': { - 'd': int("0e5c98ff2d2a3aab14ad0067b60dbe64e4f541ab5bed11c5" - "a0c55ae1e60b51ff5faaf377837977d80cbfdc33c2ff542b", 16), - 'x': int("d1bf2ac21637d66d6398aac01dcd56ac6f065fb45d1f6f16" - "747bab9e9b01b4630b59b20927aea147355bf41838acb482", 16), - 'y': int("4c9e23f1c5a41647d094086bf4ed31708651f21d996c4778" - "0688ac10f77deee2e43b5241b6caecd2fd5444bc50472e0e", 16)}, - 'IUT': { - 'd': int("f865418473e5bf7d2e1bbcd9bd5a9270c003a9dd35e77813" - "3ca59fcab4bb64fe24d6800e7047bdd033abc8bfa8db35b5", 16), - 'x': int("32b72ab9b558249dcbc6cbade234f58e4f7aa5d3f6420ea9" - "9a5f997e8c2a91fb7fd83779d0d2169428683771c745fd1a", 16), - 'y': int("c749e02a3719bb56bf1dfc4ba3820309c01ab6e84cb29db7" - "cdd80f127233f5295687f8178f3a8704c1063b84c2ee472f", 16)}, - 'Z': int("a781430e6078a179df3f9ee27cd8fdc6188f161b6c4ccc40" - "53ef6c6ca6fc222946883a53c06db08f0a020023ced055aa", 16), - 'curve': 'secp384r1'}, - - {'errno': 7, - 'fail': True, - 'COUNT': 0, - 'CAVS': { - 'd': int("0000002fef62381162942889a6094a6bb9ac1f4ddf66d9cd" - "a9f618232d31b90c50d7da78a47ed91d40cae946898571db" - "972dc294b109815f38feee9eaac0d5f7c3250728", 16), - 'x': int("0000004b05ffa025113390797f2736174aa1c784f4dd34e7" - "64ee40d40e4d2442677ebea3498086c9473e5c92789cbdb0" - "2bb327bbd61d58690f6a83d9ca73bccbde37dec4", 16), - 'y': int("0000004da67cffc98070b82af61feba78787efefb13bd810" - "d80ff92304788e49a4e5b634b3565474a8ecb1615d7b1b77" - "a7a27875adb73a8a5d8f3f84e5e8b744cda250b0", 16)}, - 'IUT': { - 'd': int("00000311a5e520e238141527671a38cb6f776d96a9f82ef7" - "0dffa11dc0895f4060f1abbb9ad6fd259e4a7beaf5f7266e" - "a1bb45bcbfebfda2705e5c551e710fb1d745f57e", 16), - 'x': int("0000010ba3778cb2cc965834c0a9593adc6a222692656d65" - "7fb0d15293edf0ab33762384a96a16fddea7540b7ccbcca4" - "6ec4ac9bcf95fdb5aa18e158aab4d91981bd733e", 16), - 'y': int("0000018522df93ddd636e5bc94daecdc600fa241686ec186" - "34fd30b7cbdfdc9ffba1166ac08df34a31896f6fad191414" - "929261ebd7187afb72919f8a0c926be37f99c1e5", 16)}, - 'Z': int("01a5e4b31be4b1346e53906b6767b1fe94ec1a8a5abc28fb" - "6f01518c056959af3bc9335dddab178b52318cc551255993" - "1b8dc18de0ce810c2c7f15769d7ce70e719c", 16), - 'curve': 'secp521r1'} + { + "errno": 0, + "fail": False, + "COUNT": 0, + "CAVS": { + "d": int( + "f70c297a683d6b7ef82b5af7349606c4447c8b4fc6fa5e80", 16 + ), + "x": int( + "f7b5061fb557e516c50abf541d97dbfd76ca7172b22cf590", 16 + ), + "y": int( + "135e15e21f9e85c76205fd148a92ac19f9e6243ddab322d1", 16 + ), + }, + "IUT": { + "d": int( + "a5b4bbad57f101ca48021cb7440cd681a9d40cd51b99d917", 16 + ), + "x": int( + "79a77fcb18a32cdb59ed5d87740f29e8565d649dbf01ce86", 16 + ), + "y": int( + "f7187efaa0b1573f1fb00905d46810b880bf738b4c720bb7", 16 + ), + }, + "Z": int("26382468d721761e14a87dc3bee67340095c6455962d1ba3", 16), + "curve": "secp192r1", + }, + { + "errno": 8, + "fail": True, + "COUNT": 2, + "CAVS": { + "d": int( + "5f909dcb0ccce58c82fada748c47297579e6a981b5518a96", 16 + ), + "x": int( + "537f1ecfda0e366de393a9bc8188fcc280311bffefe21ecf", 16 + ), + "y": int( + "a1fa1f98498d65f2754caff4e5303a4066a5ff89fde95381", 16 + ), + }, + "IUT": { + "d": int( + "3357aa7f47f3e09421602cc12cdce4434c68e330d44de05e", 16 + ), + "x": int( + "6a33d43d9c72173eabc7a771a5687748c4774c62762e96ec", 16 + ), + "y": int( + "8033f238b3abc69470aad4be8dbe4f60a2fd50207626c56a", 16 + ), + }, + "Z": int("3153034f6617326f19c35be8c99a0585431adf09d2f8e0fd", 16), + "curve": "secp192r1", + }, + { + "errno": 13, + "fail": False, + "COUNT": 8, + "CAVS": { + "d": int( + "8fcfaf0524cc868fad20e50410a2205319f1327308d98dc8", 16 + ), + "x": int( + "9b0243d80a9e328738080fb4d46bc450243d0efb7ead0c92", 16 + ), + "y": int( + "ad5bebad7f03849693071537f60ef858cad214123beee7c7", 16 + ), + }, + "IUT": { + "d": int( + "bba95dac90289cb68ca2b006f9757219b70579c299ad7a7d", 16 + ), + "x": int( + "7733dc0cb365cd6312724196b9b4eb491fd4d2e31b9afdb1", 16 + ), + "y": int( + "92ffa3722acc5b94d772258ba2d471b06c0f53f56fcd8662", 16 + ), + }, + "Z": int("0f3c6e4a29a08296ae730f56a1ebf819ea2edfa6f0434e40", 16), + "curve": "secp192r1", + }, + { + "errno": 0, + "fail": False, + "COUNT": 0, + "CAVS": { + "d": int( + "e53a88af7cf8ce6bf13c8b9ad191494e37a6acc1368c71f4" + "306e39e5", + 16, + ), + "x": int( + "3a24217c4b957fea922eec9d9ac52d5cb4b3fcd95efde1e4" + "fa0dd6e2", + 16, + ), + "y": int( + "775b94025a808eb6f4af14ea4b57dca576c35373c6dc198b" + "15b981df", + 16, + ), + }, + "IUT": { + "d": int( + "09f51e302c6a0fe6ff48f34c208c6af91e70f65f88102e6f" + "cab9af4a", + 16, + ), + "x": int( + "c5d5706ccd7424c74fd616e699865af96e56f39adea6aa05" + "9e5092b5", + 16, + ), + "y": int( + "f0729077bb602404d56d2f7e2ba5bb2f383df4a542556788" + "1ff0165d", + 16, + ), + }, + "Z": int( + "b1259ceedfb663d9515089cf727e7024fb3d86cbcec611b4" "ba0b4ab6", + 16, + ), + "curve": "secp224r1", + }, + { + "errno": 2, + "fail": True, + "COUNT": 0, + "CAVS": { + "d": int( + "305dfb4a8850cc59280891147baf457bfe5e2bae98457163" + "4a77dc8d3472fa9b", + 16, + ), + "x": int( + "202cb5a224e6c2a84e624094486edf04116c8d68ec1f4a0e" + "0ed9ee090e1a900b", + 16, + ), + "y": int( + "cacf3a5789bb33954be600425d62d9eae5371f90f8816725" + "8814213e4a4f4b1a", + 16, + ), + }, + "IUT": { + "d": int( + "72cc52808f294b64b6f7233c3d2f5d96cc1d29287320e39e" + "1c151deef0bc14eb", + 16, + ), + "x": int( + "49a768c9a4ca56e374f685dd76a461b1016c59dcded2c8d8" + "cbd9f23ca453831f", + 16, + ), + "y": int( + "b1e3bb9b5f12a3b5ae788535d4554bd8c46e0e6130075e4e" + "437d3854cf8f1c34", + 16, + ), + }, + "Z": int( + "c0147c3c2691b450b5edc08b51aea224d9f4359ff67aab6d" + "a3146f396dbceaea", + 16, + ), + "curve": "secp256r1", + }, + { + "errno": 0, + "fail": False, + "COUNT": 0, + "CAVS": { + "d": int( + "0e5c98ff2d2a3aab14ad0067b60dbe64e4f541ab5bed11c5" + "a0c55ae1e60b51ff5faaf377837977d80cbfdc33c2ff542b", + 16, + ), + "x": int( + "d1bf2ac21637d66d6398aac01dcd56ac6f065fb45d1f6f16" + "747bab9e9b01b4630b59b20927aea147355bf41838acb482", + 16, + ), + "y": int( + "4c9e23f1c5a41647d094086bf4ed31708651f21d996c4778" + "0688ac10f77deee2e43b5241b6caecd2fd5444bc50472e0e", + 16, + ), + }, + "IUT": { + "d": int( + "f865418473e5bf7d2e1bbcd9bd5a9270c003a9dd35e77813" + "3ca59fcab4bb64fe24d6800e7047bdd033abc8bfa8db35b5", + 16, + ), + "x": int( + "32b72ab9b558249dcbc6cbade234f58e4f7aa5d3f6420ea9" + "9a5f997e8c2a91fb7fd83779d0d2169428683771c745fd1a", + 16, + ), + "y": int( + "c749e02a3719bb56bf1dfc4ba3820309c01ab6e84cb29db7" + "cdd80f127233f5295687f8178f3a8704c1063b84c2ee472f", + 16, + ), + }, + "Z": int( + "a781430e6078a179df3f9ee27cd8fdc6188f161b6c4ccc40" + "53ef6c6ca6fc222946883a53c06db08f0a020023ced055aa", + 16, + ), + "curve": "secp384r1", + }, + { + "errno": 7, + "fail": True, + "COUNT": 0, + "CAVS": { + "d": int( + "0000002fef62381162942889a6094a6bb9ac1f4ddf66d9cd" + "a9f618232d31b90c50d7da78a47ed91d40cae946898571db" + "972dc294b109815f38feee9eaac0d5f7c3250728", + 16, + ), + "x": int( + "0000004b05ffa025113390797f2736174aa1c784f4dd34e7" + "64ee40d40e4d2442677ebea3498086c9473e5c92789cbdb0" + "2bb327bbd61d58690f6a83d9ca73bccbde37dec4", + 16, + ), + "y": int( + "0000004da67cffc98070b82af61feba78787efefb13bd810" + "d80ff92304788e49a4e5b634b3565474a8ecb1615d7b1b77" + "a7a27875adb73a8a5d8f3f84e5e8b744cda250b0", + 16, + ), + }, + "IUT": { + "d": int( + "00000311a5e520e238141527671a38cb6f776d96a9f82ef7" + "0dffa11dc0895f4060f1abbb9ad6fd259e4a7beaf5f7266e" + "a1bb45bcbfebfda2705e5c551e710fb1d745f57e", + 16, + ), + "x": int( + "0000010ba3778cb2cc965834c0a9593adc6a222692656d65" + "7fb0d15293edf0ab33762384a96a16fddea7540b7ccbcca4" + "6ec4ac9bcf95fdb5aa18e158aab4d91981bd733e", + 16, + ), + "y": int( + "0000018522df93ddd636e5bc94daecdc600fa241686ec186" + "34fd30b7cbdfdc9ffba1166ac08df34a31896f6fad191414" + "929261ebd7187afb72919f8a0c926be37f99c1e5", + 16, + ), + }, + "Z": int( + "01a5e4b31be4b1346e53906b6767b1fe94ec1a8a5abc28fb" + "6f01518c056959af3bc9335dddab178b52318cc551255993" + "1b8dc18de0ce810c2c7f15769d7ce70e719c", + 16, + ), + "curve": "secp521r1", + }, ] assert expected == load_kasvs_ecdh_vectors(vector_data) def test_load_kasvs_ecdh_kdf_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # Parameter set(s) supported: EB EC ED EE # CAVSid: CAVSid (in hex: 434156536964) # IUTid: In hex: a1b2c3d4e5 @@ -3361,39 +3967,68 @@ def test_load_kasvs_ecdh_kdf_vectors(): ffdfa60dd7 DKM = ad65fa2d12541c3a21f3cd223efb Result = F (12 - Tag changed ) - """).splitlines() + """ + ).splitlines() expected = [ - {'errno': 12, - 'fail': True, - 'COUNT': 50, - 'CAVS': { - 'd': int("540904b67b3716823dd621ed72ad3dbc615887b4f56f910b" - "78a57199", 16), - 'x': int("28e5f3a72d8f6b8499dd1bcdfceafcecec68a0d715789bcf" - "4b55fe15", 16), - 'y': int("8c8006a7da7c1a19f5328d7e865522b0c0dfb9a29b2c46dc" - "96590d2a", 16)}, - 'IUT': { - 'd': int("5e717ae889fc8d67be11c2ebe1a7d3550051448d68a040b2" - "dee8e327", 16), - 'x': int("ae7f3db340b647d61713f5374c019f1be2b28573cb6219bb" - "7b747223", 16), - 'y': int("800e6bffcf97c15864ec6e5673fb83359b45f89b8a26a27f" - "6f3dfbff", 16)}, - 'OI': int("a1b2c3d4e5bb7f1b40d14ebd70443393990b574341565369" - "645b1582daab9cc6c30d61fdcf1cdfc7e9a304651e0fdb", 16), - 'Z': int("43f23b2c760d686fc99cc008b63aea92f866e224265af60d" - "2d8ae540", 16), - 'DKM': int("ad65fa2d12541c3a21f3cd223efb", 16), - 'curve': 'secp224r1'} + { + "errno": 12, + "fail": True, + "COUNT": 50, + "CAVS": { + "d": int( + "540904b67b3716823dd621ed72ad3dbc615887b4f56f910b" + "78a57199", + 16, + ), + "x": int( + "28e5f3a72d8f6b8499dd1bcdfceafcecec68a0d715789bcf" + "4b55fe15", + 16, + ), + "y": int( + "8c8006a7da7c1a19f5328d7e865522b0c0dfb9a29b2c46dc" + "96590d2a", + 16, + ), + }, + "IUT": { + "d": int( + "5e717ae889fc8d67be11c2ebe1a7d3550051448d68a040b2" + "dee8e327", + 16, + ), + "x": int( + "ae7f3db340b647d61713f5374c019f1be2b28573cb6219bb" + "7b747223", + 16, + ), + "y": int( + "800e6bffcf97c15864ec6e5673fb83359b45f89b8a26a27f" + "6f3dfbff", + 16, + ), + }, + "OI": int( + "a1b2c3d4e5bb7f1b40d14ebd70443393990b574341565369" + "645b1582daab9cc6c30d61fdcf1cdfc7e9a304651e0fdb", + 16, + ), + "Z": int( + "43f23b2c760d686fc99cc008b63aea92f866e224265af60d" "2d8ae540", + 16, + ), + "DKM": int("ad65fa2d12541c3a21f3cd223efb", 16), + "curve": "secp224r1", + } ] assert expected == load_kasvs_ecdh_vectors(vector_data) def test_load_x963_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # CAVS 12.0 # 'ANS X9.63-2001' information for sample @@ -3443,37 +4078,48 @@ def test_load_x963_vectors(): d6e4dd2a599acceb3ea54a6217ce0b50eef4f6b40a5c30250a5a8eeee208002267089dbf351f3f\ 5022aa9638bf1ee419dea9c4ff745a25ac27bda33ca08bd56dd1a59b4106cf2dbbc0ab2aa8e2ef\ a7b17902d34276951ceccab87f9661c3e8816 - """).splitlines() + """ + ).splitlines() assert load_x963_vectors(vector_data) == [ - {"hash": "SHA-1", "count": 0, - "shared_secret_length": 192, - "Z": "1c7d7b5f0597b03d06a018466ed1a93e30ed4b04dc64ccdd", - "sharedinfo_length": 0, - "key_data_length": 128, - "key_data": "bf71dffd8f4d99223936beb46fee8ccc"}, - {"hash": "SHA-1", "count": 1, - "shared_secret_length": 192, - "Z": "5ed096510e3fcf782ceea98e9737993e2b21370f6cda2ab1", - "sharedinfo_length": 0, - "key_data_length": 128, - "key_data": "ec3e224446bfd7b3be1df404104af953"}, - {"hash": "SHA-512", "count": 0, - "shared_secret_length": 521, - "Z": "00aa5bb79b33e389fa58ceadc047197f14e73712f452caa9fc4c9adb369348b\ + { + "hash": "SHA-1", + "count": 0, + "shared_secret_length": 192, + "Z": "1c7d7b5f0597b03d06a018466ed1a93e30ed4b04dc64ccdd", + "sharedinfo_length": 0, + "key_data_length": 128, + "key_data": "bf71dffd8f4d99223936beb46fee8ccc", + }, + { + "hash": "SHA-1", + "count": 1, + "shared_secret_length": 192, + "Z": "5ed096510e3fcf782ceea98e9737993e2b21370f6cda2ab1", + "sharedinfo_length": 0, + "key_data_length": 128, + "key_data": "ec3e224446bfd7b3be1df404104af953", + }, + { + "hash": "SHA-512", + "count": 0, + "shared_secret_length": 521, + "Z": "00aa5bb79b33e389fa58ceadc047197f14e73712f452caa9fc4c9adb369348b\ 81507392f1a86ddfdb7c4ff8231c4bd0f44e44a1b55b1404747a9e2e753f55ef05a2d", - "sharedinfo_length": 128, - "sharedinfo": "e3b5b4c1b0d5cf1d2b3a2f9937895d31", - "key_data_length": 1024, - "key_data": "4463f869f3cc18769b52264b0112b5858f7ad32a5a2d96d8cffabf7f\ + "sharedinfo_length": 128, + "sharedinfo": "e3b5b4c1b0d5cf1d2b3a2f9937895d31", + "key_data_length": 1024, + "key_data": "4463f869f3cc18769b52264b0112b5858f7ad32a5a2d96d8cffabf7f\ a733633d6e4dd2a599acceb3ea54a6217ce0b50eef4f6b40a5c30250a5a8eeee208002267089db\ f351f3f5022aa9638bf1ee419dea9c4ff745a25ac27bda33ca08bd56dd1a59b4106cf2dbbc0ab2\ -aa8e2efa7b17902d34276951ceccab87f9661c3e8816"}, +aa8e2efa7b17902d34276951ceccab87f9661c3e8816", + }, ] def test_load_kbkdf_vectors(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # CAVS 14.4 # "SP800-108 - KDF" information for "test1" # KDF Mode Supported: Counter Mode @@ -3523,50 +4169,58 @@ def test_load_kbkdf_vectors(): instring = 7f50fc1f77c3ac752443154c1577d3c47b86fccffe82ff43aa1b91eeb5\ 730d7e9e6aab78374d854aecb7143faba6b1eb90d3d9e7a2f6d78dd9a6c4a701 KO = b8894c6133a46701909b5c8a84322dec - """).splitlines() + """ + ).splitlines() assert load_nist_kbkdf_vectors(vector_data) == [ - {'prf': 'hmac_sha1', - 'ctrlocation': 'before_fixed', - 'rlen': 8, - 'l': 128, - 'ki': b'00a39bd547fb88b2d98727cf64c195c61e1cad6c', - 'fixedinputdatabytelen': b'60', - 'fixedinputdata': b'98132c1ffaf59ae5cbc0a3133d84c551bb97e0c75ecaddfc\ -30056f6876f59803009bffc7d75c4ed46f40b8f80426750d15bc1ddb14ac5dcb69a68242', - 'binary rep of i': b'01', - 'instring': b'0198132c1ffaf59ae5cbc0a3133d84c551bb97e0c75ecaddfc3005\ -6f6876f59803009bffc7d75c4ed46f40b8f80426750d15bc1ddb14ac5dcb69a68242', - 'ko': b'0611e1903609b47ad7a5fc2c82e47702'}, - {'prf': 'hmac_sha1', - 'ctrlocation': 'before_fixed', - 'rlen': 8, - 'l': 128, - 'ki': b'a39bdf744ed7e33fdec060c8736e9725179885a8', - 'fixedinputdatabytelen': b'60', - 'fixedinputdata': b'af71b44940acff98949ad17f1ca20e8fdb3957cacdcd41e9\ -c591e18235019f90b9f8ee6e75700bcab2f8407525a104799b3e9725e27d738a9045e832', - 'binary rep of i': b'01', - 'instring': b'01af71b44940acff98949ad17f1ca20e8fdb3957cacdcd41e9c591\ -e18235019f90b9f8ee6e75700bcab2f8407525a104799b3e9725e27d738a9045e832', - 'ko': b'51dc4668947e3685099bc3b5f8527468'}, - {'prf': 'hmac_sha224', - 'ctrlocation': 'after_fixed', - 'rlen': 8, - 'l': 128, - 'ki': b'ab56556b107a3a79fe084df0f1bb3ad049a6cc1490f20da4b3df282c', - 'fixedinputdatabytelen': b'60', - 'fixedinputdata': b'7f50fc1f77c3ac752443154c1577d3c47b86fccffe82ff43\ -aa1b91eeb5730d7e9e6aab78374d854aecb7143faba6b1eb90d3d9e7a2f6d78dd9a6c4a7', - 'binary rep of i': b'01', - 'instring': b'7f50fc1f77c3ac752443154c1577d3c47b86fccffe82ff43aa1b91\ -eeb5730d7e9e6aab78374d854aecb7143faba6b1eb90d3d9e7a2f6d78dd9a6c4a701', - 'ko': b'b8894c6133a46701909b5c8a84322dec'} + { + "prf": "hmac_sha1", + "ctrlocation": "before_fixed", + "rlen": 8, + "l": 128, + "ki": b"00a39bd547fb88b2d98727cf64c195c61e1cad6c", + "fixedinputdatabytelen": b"60", + "fixedinputdata": b"98132c1ffaf59ae5cbc0a3133d84c551bb97e0c75ecaddfc\ +30056f6876f59803009bffc7d75c4ed46f40b8f80426750d15bc1ddb14ac5dcb69a68242", + "binary rep of i": b"01", + "instring": b"0198132c1ffaf59ae5cbc0a3133d84c551bb97e0c75ecaddfc3005\ +6f6876f59803009bffc7d75c4ed46f40b8f80426750d15bc1ddb14ac5dcb69a68242", + "ko": b"0611e1903609b47ad7a5fc2c82e47702", + }, + { + "prf": "hmac_sha1", + "ctrlocation": "before_fixed", + "rlen": 8, + "l": 128, + "ki": b"a39bdf744ed7e33fdec060c8736e9725179885a8", + "fixedinputdatabytelen": b"60", + "fixedinputdata": b"af71b44940acff98949ad17f1ca20e8fdb3957cacdcd41e9\ +c591e18235019f90b9f8ee6e75700bcab2f8407525a104799b3e9725e27d738a9045e832", + "binary rep of i": b"01", + "instring": b"01af71b44940acff98949ad17f1ca20e8fdb3957cacdcd41e9c591\ +e18235019f90b9f8ee6e75700bcab2f8407525a104799b3e9725e27d738a9045e832", + "ko": b"51dc4668947e3685099bc3b5f8527468", + }, + { + "prf": "hmac_sha224", + "ctrlocation": "after_fixed", + "rlen": 8, + "l": 128, + "ki": b"ab56556b107a3a79fe084df0f1bb3ad049a6cc1490f20da4b3df282c", + "fixedinputdatabytelen": b"60", + "fixedinputdata": b"7f50fc1f77c3ac752443154c1577d3c47b86fccffe82ff43\ +aa1b91eeb5730d7e9e6aab78374d854aecb7143faba6b1eb90d3d9e7a2f6d78dd9a6c4a7", + "binary rep of i": b"01", + "instring": b"7f50fc1f77c3ac752443154c1577d3c47b86fccffe82ff43aa1b91\ +eeb5730d7e9e6aab78374d854aecb7143faba6b1eb90d3d9e7a2f6d78dd9a6c4a701", + "ko": b"b8894c6133a46701909b5c8a84322dec", + }, ] def test_load_nist_ccm_vectors_dvpt(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # CAVS 11.0 # "CCM-DVPT" information # AES Keylen: 128 @@ -3606,61 +4260,63 @@ def test_load_nist_ccm_vectors_dvpt(): Adata = 00 CT = 3a65e03af37b81d05acc7ec1bc39deb0 Result = Fail - """).splitlines() + """ + ).splitlines() assert load_nist_ccm_vectors(vector_data) == [ { - 'key': b'4ae701103c63deca5b5a3939d7d05992', - 'alen': 0, - 'plen': 0, - 'nlen': 7, - 'tlen': 4, - 'nonce': b'5a8aa485c316e9', - 'adata': b'00', - 'ct': b'02209f55', - 'fail': False, - 'payload': b'00' - }, - { - 'key': b'4ae701103c63deca5b5a3939d7d05992', - 'alen': 0, - 'plen': 0, - 'nlen': 7, - 'tlen': 4, - 'nonce': b'3796cf51b87266', - 'adata': b'00', - 'ct': b'9a04c241', - 'fail': True, - 'payload': b'00' - }, - { - 'key': b'4bb3c4a4f893ad8c9bdc833c325d62b3', - 'alen': 0, - 'plen': 0, - 'nlen': 7, - 'tlen': 16, - 'nonce': b'5a8aa485c316e9', - 'adata': b'00', - 'ct': b'75d582db43ce9b13ab4b6f7f14341330', - 'fail': False, - 'payload': b'00' - }, - { - 'key': b'4bb3c4a4f893ad8c9bdc833c325d62b3', - 'alen': 0, - 'plen': 0, - 'nlen': 7, - 'tlen': 16, - 'nonce': b'3796cf51b87266', - 'adata': b'00', - 'ct': b'3a65e03af37b81d05acc7ec1bc39deb0', - 'fail': True, - 'payload': b'00' - } + "key": b"4ae701103c63deca5b5a3939d7d05992", + "alen": 0, + "plen": 0, + "nlen": 7, + "tlen": 4, + "nonce": b"5a8aa485c316e9", + "adata": b"00", + "ct": b"02209f55", + "fail": False, + "payload": b"00", + }, + { + "key": b"4ae701103c63deca5b5a3939d7d05992", + "alen": 0, + "plen": 0, + "nlen": 7, + "tlen": 4, + "nonce": b"3796cf51b87266", + "adata": b"00", + "ct": b"9a04c241", + "fail": True, + "payload": b"00", + }, + { + "key": b"4bb3c4a4f893ad8c9bdc833c325d62b3", + "alen": 0, + "plen": 0, + "nlen": 7, + "tlen": 16, + "nonce": b"5a8aa485c316e9", + "adata": b"00", + "ct": b"75d582db43ce9b13ab4b6f7f14341330", + "fail": False, + "payload": b"00", + }, + { + "key": b"4bb3c4a4f893ad8c9bdc833c325d62b3", + "alen": 0, + "plen": 0, + "nlen": 7, + "tlen": 16, + "nonce": b"3796cf51b87266", + "adata": b"00", + "ct": b"3a65e03af37b81d05acc7ec1bc39deb0", + "fail": True, + "payload": b"00", + }, ] def test_load_nist_ccm_vectors_vadt(): - vector_data = textwrap.dedent(""" + vector_data = textwrap.dedent( + """ # CAVS 11.0 # "CCM-VADT" information # AES Keylen: 128 @@ -3700,52 +4356,53 @@ def test_load_nist_ccm_vectors_vadt(): Adata = c5 Payload = 032fee9dbffccc751e6a1ee6d07bb218b3a7ec6bf5740ead CT = f0828917020651c085e42459c544ec52e99372005362baf308ebe - """).splitlines() + """ + ).splitlines() assert load_nist_ccm_vectors(vector_data) == [ { - 'plen': 24, - 'nlen': 13, - 'tlen': 16, - 'alen': 0, - 'key': b'd24a3d3dde8c84830280cb87abad0bb3', - 'nonce': b'f1100035bb24a8d26004e0e24b', - 'adata': b'00', - 'payload': b'7c86135ed9c2a515aaae0e9a208133897269220f30870006', - 'ct': b'1faeb0ee2ca2cd52f0aa3966578344f24e69b742c4ab37ab11233' - }, - { - 'plen': 24, - 'nlen': 13, - 'tlen': 16, - 'alen': 0, - 'key': b'd24a3d3dde8c84830280cb87abad0bb3', - 'nonce': b'f1100035bb24a8d26004e0e24b', - 'adata': b'00', - 'payload': b'48df73208cdc63d716752df7794807b1b2a80794a2433455', - 'ct': b'642145210f947bc4a0b1e678fd8c990c2c1d89d4110a95c954d61' - }, - { - 'plen': 24, - 'nlen': 13, - 'tlen': 16, - 'alen': 1, - 'key': b'08b0da255d2083808a1b4d367090bacc', - 'nonce': b'777828b13679a9e2ca89568233', - 'adata': b'dd', - 'payload': b'1b156d7e2bf7c9a25ad91cff7b0b02161cb78ff9162286b0', - 'ct': b'e8b80af4960d5417c15726406e345c5c46831192b03432eed16b6' - }, - { - 'plen': 24, - 'nlen': 13, - 'tlen': 16, - 'alen': 1, - 'key': b'08b0da255d2083808a1b4d367090bacc', - 'nonce': b'777828b13679a9e2ca89568233', - 'adata': b'c5', - 'payload': b'032fee9dbffccc751e6a1ee6d07bb218b3a7ec6bf5740ead', - 'ct': b'f0828917020651c085e42459c544ec52e99372005362baf308ebe' - } + "plen": 24, + "nlen": 13, + "tlen": 16, + "alen": 0, + "key": b"d24a3d3dde8c84830280cb87abad0bb3", + "nonce": b"f1100035bb24a8d26004e0e24b", + "adata": b"00", + "payload": b"7c86135ed9c2a515aaae0e9a208133897269220f30870006", + "ct": b"1faeb0ee2ca2cd52f0aa3966578344f24e69b742c4ab37ab11233", + }, + { + "plen": 24, + "nlen": 13, + "tlen": 16, + "alen": 0, + "key": b"d24a3d3dde8c84830280cb87abad0bb3", + "nonce": b"f1100035bb24a8d26004e0e24b", + "adata": b"00", + "payload": b"48df73208cdc63d716752df7794807b1b2a80794a2433455", + "ct": b"642145210f947bc4a0b1e678fd8c990c2c1d89d4110a95c954d61", + }, + { + "plen": 24, + "nlen": 13, + "tlen": 16, + "alen": 1, + "key": b"08b0da255d2083808a1b4d367090bacc", + "nonce": b"777828b13679a9e2ca89568233", + "adata": b"dd", + "payload": b"1b156d7e2bf7c9a25ad91cff7b0b02161cb78ff9162286b0", + "ct": b"e8b80af4960d5417c15726406e345c5c46831192b03432eed16b6", + }, + { + "plen": 24, + "nlen": 13, + "tlen": 16, + "alen": 1, + "key": b"08b0da255d2083808a1b4d367090bacc", + "nonce": b"777828b13679a9e2ca89568233", + "adata": b"c5", + "payload": b"032fee9dbffccc751e6a1ee6d07bb218b3a7ec6bf5740ead", + "ct": b"f0828917020651c085e42459c544ec52e99372005362baf308ebe", + }, ] @@ -3767,16 +4424,15 @@ def test_raises_unsupported_algorithm_wrong_reason(): # Check that it fails if the wrong reason code is raised. with pytest.raises(AssertionError): with raises_unsupported_algorithm(None): - raise UnsupportedAlgorithm("An error.", - _Reasons.BACKEND_MISSING_INTERFACE) + raise UnsupportedAlgorithm( + "An error.", _Reasons.BACKEND_MISSING_INTERFACE + ) def test_raises_unsupported_no_exc(): # Check that it fails if no exception is raised. with pytest.raises(pytest.fail.Exception): - with raises_unsupported_algorithm( - _Reasons.BACKEND_MISSING_INTERFACE - ): + with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE): pass @@ -3785,6 +4441,7 @@ def test_raises_unsupported_algorithm(): with raises_unsupported_algorithm( _Reasons.BACKEND_MISSING_INTERFACE ) as exc_info: - raise UnsupportedAlgorithm("An error.", - _Reasons.BACKEND_MISSING_INTERFACE) + raise UnsupportedAlgorithm( + "An error.", _Reasons.BACKEND_MISSING_INTERFACE + ) assert exc_info.type is UnsupportedAlgorithm diff --git a/tests/test_warnings.py b/tests/test_warnings.py index d27e757fc845..073c699bc084 100644 --- a/tests/test_warnings.py +++ b/tests/test_warnings.py @@ -21,7 +21,7 @@ def test_deprecated(self, monkeypatch): value=1, module_name=mod.__name__, message="deprecated message text", - warning_class=DeprecationWarning + warning_class=DeprecationWarning, ) mod.Y = deprecated( value=2, @@ -55,7 +55,7 @@ def test_deleting_deprecated_members(self, monkeypatch): value=1, module_name=mod.__name__, message="deprecated message text", - warning_class=DeprecationWarning + warning_class=DeprecationWarning, ) mod.Y = deprecated( value=2, diff --git a/tests/utils.py b/tests/utils.py index b48128083fda..5d98af00e337 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -7,7 +7,6 @@ import binascii import collections import json -import math import os import re from contextlib import contextmanager @@ -30,9 +29,7 @@ def check_backend_support(backend, item): for mark in item.node.iter_markers("supported"): if not mark.kwargs["only_if"](backend): - pytest.skip("{0} ({1})".format( - mark.kwargs["skip_message"], backend - )) + pytest.skip("{} ({})".format(mark.kwargs["skip_message"], backend)) @contextmanager @@ -56,8 +53,11 @@ def load_nist_vectors(vector_data): line = line.strip() # Blank lines, comments, and section headers are ignored - if not line or line.startswith("#") or (line.startswith("[") and - line.endswith("]")): + if ( + not line + or line.startswith("#") + or (line.startswith("[") and line.endswith("]")) + ): continue if line.strip() == "FAIL": @@ -102,11 +102,9 @@ def load_cryptrec_vectors(vector_data): ct = line.split(" : ")[1].replace(" ", "").encode("ascii") # after a C is found the K+P+C tuple is complete # there are many P+C pairs for each K - cryptrec_list.append({ - "key": key, - "plaintext": pt, - "ciphertext": ct - }) + cryptrec_list.append( + {"key": key, "plaintext": pt, "ciphertext": ct} + ) else: raise ValueError("Invalid line in file '{}'".format(line)) return cryptrec_list @@ -164,9 +162,9 @@ def load_pkcs1_vectors(vector_data): vectors = [] for line in vector_data: if ( - line.startswith("# PSS Example") or - line.startswith("# OAEP Example") or - line.startswith("# PKCS#1 v1.5") + line.startswith("# PSS Example") + or line.startswith("# OAEP Example") + or line.startswith("# PKCS#1 v1.5") ): if example_vector: for key, value in six.iteritems(example_vector): @@ -192,9 +190,8 @@ def load_pkcs1_vectors(vector_data): elif line.startswith("# Encryption"): attr = "encryption" continue - elif ( - example_vector and - line.startswith("# =============================================") + elif example_vector and line.startswith( + "# =============================================" ): for key, value in six.iteritems(example_vector): hex_str = "".join(value).replace(" ", "").encode("ascii") @@ -209,9 +206,8 @@ def load_pkcs1_vectors(vector_data): example_vector[attr].append(line.strip()) continue - if ( - line.startswith("# Example") or - line.startswith("# =============================================") + if line.startswith("# Example") or line.startswith( + "# =============================================" ): if key: assert private_key_vector @@ -229,18 +225,16 @@ def load_pkcs1_vectors(vector_data): examples = [] assert ( - private_key_vector['public_exponent'] == - public_key_vector['public_exponent'] + private_key_vector["public_exponent"] + == public_key_vector["public_exponent"] ) assert ( - private_key_vector['modulus'] == - public_key_vector['modulus'] + private_key_vector["modulus"] + == public_key_vector["modulus"] ) - vectors.append( - (private_key_vector, public_key_vector) - ) + vectors.append((private_key_vector, public_key_vector)) public_key_vector = collections.defaultdict(list) private_key_vector = collections.defaultdict(list) @@ -322,15 +316,10 @@ def load_rsa_nist_vectors(vector_data): "public_exponent": e, "salt_length": salt_length, "algorithm": value, - "fail": False + "fail": False, } else: - test_data = { - "modulus": n, - "p": p, - "q": q, - "algorithm": value - } + test_data = {"modulus": n, "p": p, "q": q, "algorithm": value} if salt_length is not None: test_data["salt_length"] = salt_length data.append(test_data) @@ -360,21 +349,24 @@ def load_fips_dsa_key_pair_vectors(vector_data): continue if line.startswith("P"): - vectors.append({'p': int(line.split("=")[1], 16)}) + vectors.append({"p": int(line.split("=")[1], 16)}) elif line.startswith("Q"): - vectors[-1]['q'] = int(line.split("=")[1], 16) + vectors[-1]["q"] = int(line.split("=")[1], 16) elif line.startswith("G"): - vectors[-1]['g'] = int(line.split("=")[1], 16) - elif line.startswith("X") and 'x' not in vectors[-1]: - vectors[-1]['x'] = int(line.split("=")[1], 16) - elif line.startswith("X") and 'x' in vectors[-1]: - vectors.append({'p': vectors[-1]['p'], - 'q': vectors[-1]['q'], - 'g': vectors[-1]['g'], - 'x': int(line.split("=")[1], 16) - }) + vectors[-1]["g"] = int(line.split("=")[1], 16) + elif line.startswith("X") and "x" not in vectors[-1]: + vectors[-1]["x"] = int(line.split("=")[1], 16) + elif line.startswith("X") and "x" in vectors[-1]: + vectors.append( + { + "p": vectors[-1]["p"], + "q": vectors[-1]["q"], + "g": vectors[-1]["g"], + "x": int(line.split("=")[1], 16), + } + ) elif line.startswith("Y"): - vectors[-1]['y'] = int(line.split("=")[1], 16) + vectors[-1]["y"] = int(line.split("=")[1], 16) return vectors @@ -396,7 +388,7 @@ def load_fips_dsa_sig_vectors(vector_data): sha_match = sha_regex.match(line) if sha_match: - digest_algorithm = "SHA-{0}".format(sha_match.group("sha")) + digest_algorithm = "SHA-{}".format(sha_match.group("sha")) if line.startswith("[mod"): continue @@ -404,33 +396,37 @@ def load_fips_dsa_sig_vectors(vector_data): name, value = [c.strip() for c in line.split("=")] if name == "P": - vectors.append({'p': int(value, 16), - 'digest_algorithm': digest_algorithm}) + vectors.append( + {"p": int(value, 16), "digest_algorithm": digest_algorithm} + ) elif name == "Q": - vectors[-1]['q'] = int(value, 16) + vectors[-1]["q"] = int(value, 16) elif name == "G": - vectors[-1]['g'] = int(value, 16) - elif name == "Msg" and 'msg' not in vectors[-1]: + vectors[-1]["g"] = int(value, 16) + elif name == "Msg" and "msg" not in vectors[-1]: hexmsg = value.strip().encode("ascii") - vectors[-1]['msg'] = binascii.unhexlify(hexmsg) - elif name == "Msg" and 'msg' in vectors[-1]: + vectors[-1]["msg"] = binascii.unhexlify(hexmsg) + elif name == "Msg" and "msg" in vectors[-1]: hexmsg = value.strip().encode("ascii") - vectors.append({'p': vectors[-1]['p'], - 'q': vectors[-1]['q'], - 'g': vectors[-1]['g'], - 'digest_algorithm': - vectors[-1]['digest_algorithm'], - 'msg': binascii.unhexlify(hexmsg)}) + vectors.append( + { + "p": vectors[-1]["p"], + "q": vectors[-1]["q"], + "g": vectors[-1]["g"], + "digest_algorithm": vectors[-1]["digest_algorithm"], + "msg": binascii.unhexlify(hexmsg), + } + ) elif name == "X": - vectors[-1]['x'] = int(value, 16) + vectors[-1]["x"] = int(value, 16) elif name == "Y": - vectors[-1]['y'] = int(value, 16) + vectors[-1]["y"] = int(value, 16) elif name == "R": - vectors[-1]['r'] = int(value, 16) + vectors[-1]["r"] = int(value, 16) elif name == "S": - vectors[-1]['s'] = int(value, 16) + vectors[-1]["s"] = int(value, 16) elif name == "Result": - vectors[-1]['result'] = value.split("(")[0].strip() + vectors[-1]["result"] = value.split("(")[0].strip() return vectors @@ -442,14 +438,12 @@ def load_fips_dsa_sig_vectors(vector_data): "P-256": "secp256r1", "P-384": "secp384r1", "P-521": "secp521r1", - "K-163": "sect163k1", "K-233": "sect233k1", "K-256": "secp256k1", "K-283": "sect283k1", "K-409": "sect409k1", "K-571": "sect571k1", - "B-163": "sect163r2", "B-233": "sect233r1", "B-283": "sect283r1", @@ -477,10 +471,7 @@ def load_fips_ecdsa_key_pair_vectors(vector_data): if key_data is not None: vectors.append(key_data) - key_data = { - "curve": curve_name, - "d": int(line.split("=")[1], 16) - } + key_data = {"curve": curve_name, "d": int(line.split("=")[1], 16)} elif key_data is not None: if line.startswith("Qx = "): @@ -511,7 +502,7 @@ def load_fips_ecdsa_signing_vectors(vector_data): curve_match = curve_rx.match(line) if curve_match: curve_name = _ECDSA_CURVE_NAMES[curve_match.group("curve")] - digest_name = "SHA-{0}".format(curve_match.group("sha")) + digest_name = "SHA-{}".format(curve_match.group("sha")) elif line.startswith("Msg = "): if data is not None: @@ -522,7 +513,7 @@ def load_fips_ecdsa_signing_vectors(vector_data): data = { "curve": curve_name, "digest_algorithm": digest_name, - "message": binascii.unhexlify(hexmsg) + "message": binascii.unhexlify(hexmsg), } elif data is not None: @@ -552,10 +543,7 @@ def load_kasvs_dh_vectors(vector_data): result_rx = re.compile(r"([FP]) \(([0-9]+) -") vectors = [] - data = { - "fail_z": False, - "fail_agree": False - } + data = {"fail_z": False, "fail_agree": False} for line in vector_data: line = line.strip() @@ -597,7 +585,7 @@ def load_kasvs_dh_vectors(vector_data): "q": data["q"], "g": data["g"], "fail_z": False, - "fail_agree": False + "fail_agree": False, } return vectors @@ -647,7 +635,7 @@ def load_kasvs_ecdh_vectors(vector_data): tag = line curve = None elif line.startswith("[Curve selected:"): - curve = curve_name_map[line.split(':')[1].strip()[:-1]] + curve = curve_name_map[line.split(":")[1].strip()[:-1]] if tag is not None and curve is not None: sets[tag.strip("[]")] = curve @@ -744,15 +732,15 @@ def load_x963_vectors(vector_data): vector["key_data_length"] = key_data_len elif line.startswith("Z"): vector["Z"] = line.split("=")[1].strip() - assert math.ceil(shared_secret_len / 8) * 2 == len(vector["Z"]) + assert ((shared_secret_len + 7) // 8) * 2 == len(vector["Z"]) elif line.startswith("SharedInfo"): if shared_info_len != 0: vector["sharedinfo"] = line.split("=")[1].strip() silen = len(vector["sharedinfo"]) - assert math.ceil(shared_info_len / 8) * 2 == silen + assert ((shared_info_len + 7) // 8) * 2 == silen elif line.startswith("key_data"): vector["key_data"] = line.split("=")[1].strip() - assert math.ceil(key_data_len / 8) * 2 == len(vector["key_data"]) + assert ((key_data_len + 7) // 8) * 2 == len(vector["key_data"]) vectors.append(vector) vector = {} @@ -776,14 +764,14 @@ def load_nist_kbkdf_vectors(vector_data): if line.startswith("[") and line.endswith("]"): tag_data = line[1:-1] name, value = [c.strip() for c in tag_data.split("=")] - if value.endswith('_BITS'): - value = int(value.split('_')[0]) + if value.endswith("_BITS"): + value = int(value.split("_")[0]) tag.update({name.lower(): value}) continue tag.update({name.lower(): value.lower()}) elif line.startswith("COUNT="): - test_data = dict() + test_data = {} test_data.update(tag) vectors.append(test_data) elif line.startswith("L"): @@ -799,17 +787,19 @@ def load_nist_kbkdf_vectors(vector_data): def load_ed25519_vectors(vector_data): data = [] for line in vector_data: - secret_key, public_key, message, signature, _ = line.split(':') + secret_key, public_key, message, signature, _ = line.split(":") # In the vectors the first element is secret key + public key secret_key = secret_key[0:64] # In the vectors the signature section is signature + message signature = signature[0:128] - data.append({ - "secret_key": secret_key, - "public_key": public_key, - "message": message, - "signature": signature - }) + data.append( + { + "secret_key": secret_key, + "public_key": public_key, + "message": message, + "signature": signature, + } + ) return data @@ -887,13 +877,17 @@ def load_nist_ccm_vectors(vector_data): class WycheproofTest(object): - def __init__(self, testgroup, testcase): + def __init__(self, testfiledata, testgroup, testcase): + self.testfiledata = testfiledata self.testgroup = testgroup self.testcase = testcase def __repr__(self): - return "".format( - self.testgroup, self.testcase, self.testcase["tcId"], + return "".format( + self.testfiledata, + self.testgroup, + self.testcase, + self.testcase["tcId"], ) @property @@ -923,7 +917,7 @@ def load_wycheproof_tests(wycheproof, test_file): path = os.path.join(wycheproof, "testvectors", test_file) with open(path) as f: data = json.load(f) - for group in data["testGroups"]: + for group in data.pop("testGroups"): cases = group.pop("tests") for c in cases: - yield WycheproofTest(group, c) + yield WycheproofTest(data, group, c) diff --git a/tests/wycheproof/test_aes.py b/tests/wycheproof/test_aes.py index 55e454546c44..e33c01e99f54 100644 --- a/tests/wycheproof/test_aes.py +++ b/tests/wycheproof/test_aes.py @@ -11,9 +11,7 @@ from cryptography.exceptions import InvalidTag from cryptography.hazmat.backends.interfaces import CipherBackend from cryptography.hazmat.primitives import padding -from cryptography.hazmat.primitives.ciphers import ( - Cipher, algorithms, modes -) +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.ciphers.aead import AESCCM, AESGCM from ..hazmat.primitives.test_aead import _aead_supported @@ -31,8 +29,9 @@ def test_aes_cbc_pkcs5(backend, wycheproof): cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend) enc = cipher.encryptor() - computed_ct = enc.update( - padder.update(msg) + padder.finalize()) + enc.finalize() + computed_ct = ( + enc.update(padder.update(msg) + padder.finalize()) + enc.finalize() + ) dec = cipher.decryptor() padded_msg = dec.update(ct) + dec.finalize() unpadder = padding.PKCS7(128).unpadder() @@ -55,6 +54,10 @@ def test_aes_gcm(backend, wycheproof): msg = binascii.unhexlify(wycheproof.testcase["msg"]) ct = binascii.unhexlify(wycheproof.testcase["ct"]) tag = binascii.unhexlify(wycheproof.testcase["tag"]) + if backend._fips_enabled and len(iv) != 12: + # Red Hat disables non-96-bit IV support as part of its FIPS + # patches. + pytest.skip("Non-96-bit IVs unsupported in FIPS mode.") if wycheproof.valid or wycheproof.acceptable: enc = Cipher(algorithms.AES(key), modes.GCM(iv), backend).encryptor() enc.authenticate_additional_data(aad) @@ -65,7 +68,7 @@ def test_aes_gcm(backend, wycheproof): dec = Cipher( algorithms.AES(key), modes.GCM(iv, tag, min_tag_length=len(tag)), - backend + backend, ).decryptor() dec.authenticate_additional_data(aad) computed_msg = dec.update(ct) + dec.finalize() @@ -77,7 +80,7 @@ def test_aes_gcm(backend, wycheproof): dec = Cipher( algorithms.AES(key), modes.GCM(iv, tag, min_tag_length=len(tag)), - backend + backend, ).decryptor() dec.authenticate_additional_data(aad) dec.update(ct) @@ -94,6 +97,10 @@ def test_aes_gcm_aead_api(backend, wycheproof): msg = binascii.unhexlify(wycheproof.testcase["msg"]) ct = binascii.unhexlify(wycheproof.testcase["ct"]) tag = binascii.unhexlify(wycheproof.testcase["tag"]) + if backend._fips_enabled and len(iv) != 12: + # Red Hat disables non-96-bit IV support as part of its FIPS + # patches. + pytest.skip("Non-96-bit IVs unsupported in FIPS mode.") aesgcm = AESGCM(key) if wycheproof.valid or wycheproof.acceptable: computed_ct = aesgcm.encrypt(iv, msg, aad) @@ -123,8 +130,8 @@ def test_aes_ccm_aead_api(backend, wycheproof): tag = binascii.unhexlify(wycheproof.testcase["tag"]) if ( - wycheproof.invalid and - wycheproof.testcase["comment"] == "Invalid tag size" + wycheproof.invalid + and wycheproof.testcase["comment"] == "Invalid tag size" ): with pytest.raises(ValueError): AESCCM(key, tag_length=wycheproof.testgroup["tagSize"] // 8) diff --git a/tests/wycheproof/test_chacha20poly1305.py b/tests/wycheproof/test_chacha20poly1305.py index deef5a0a7dfe..48023ca63d70 100644 --- a/tests/wycheproof/test_chacha20poly1305.py +++ b/tests/wycheproof/test_chacha20poly1305.py @@ -17,7 +17,7 @@ @pytest.mark.skipif( not _aead_supported(ChaCha20Poly1305), - reason="Requires OpenSSL with ChaCha20Poly1305 support" + reason="Requires OpenSSL with ChaCha20Poly1305 support", ) @pytest.mark.requires_backend_interface(interface=CipherBackend) @pytest.mark.wycheproof_tests("chacha20_poly1305_test.json") diff --git a/tests/wycheproof/test_dsa.py b/tests/wycheproof/test_dsa.py index 3dc3056e1ab7..9185b3e2f4e0 100644 --- a/tests/wycheproof/test_dsa.py +++ b/tests/wycheproof/test_dsa.py @@ -23,6 +23,10 @@ @pytest.mark.requires_backend_interface(interface=DSABackend) @pytest.mark.wycheproof_tests( "dsa_test.json", + "dsa_2048_224_sha224_test.json", + "dsa_2048_224_sha256_test.json", + "dsa_2048_256_sha256_test.json", + "dsa_3072_256_sha256_test.json", ) def test_dsa_signature(backend, wycheproof): key = serialization.load_der_public_key( @@ -30,10 +34,8 @@ def test_dsa_signature(backend, wycheproof): ) digest = _DIGESTS[wycheproof.testgroup["sha"]] - if ( - wycheproof.valid or ( - wycheproof.acceptable and not wycheproof.has_flag("NoLeadingZero") - ) + if wycheproof.valid or ( + wycheproof.acceptable and not wycheproof.has_flag("NoLeadingZero") ): key.verify( binascii.unhexlify(wycheproof.testcase["sig"]), diff --git a/tests/wycheproof/test_ecdh.py b/tests/wycheproof/test_ecdh.py index 5fcc45b76273..b89dc68ce7fc 100644 --- a/tests/wycheproof/test_ecdh.py +++ b/tests/wycheproof/test_ecdh.py @@ -21,6 +21,7 @@ "secp256r1": ec.SECP256R1(), "secp384r1": ec.SECP384R1(), "secp521r1": ec.SECP521R1(), + "secp224k1": None, "secp256k1": ec.SECP256K1(), "brainpoolP224r1": None, "brainpoolP256r1": ec.BrainpoolP256R1(), diff --git a/tests/wycheproof/test_ecdsa.py b/tests/wycheproof/test_ecdsa.py index 5214052ec661..802bb9f00b3e 100644 --- a/tests/wycheproof/test_ecdsa.py +++ b/tests/wycheproof/test_ecdsa.py @@ -20,6 +20,10 @@ "SHA-256": hashes.SHA256(), "SHA-384": hashes.SHA384(), "SHA-512": hashes.SHA512(), + "SHA3-224": hashes.SHA3_224(), + "SHA3-256": hashes.SHA3_256(), + "SHA3-384": hashes.SHA3_384(), + "SHA3-512": hashes.SHA3_512(), } @@ -34,13 +38,23 @@ "ecdsa_secp224r1_sha224_test.json", "ecdsa_secp224r1_sha256_test.json", "ecdsa_secp224r1_sha512_test.json", + "ecdsa_secp224r1_sha3_224_test.json", + "ecdsa_secp224r1_sha3_256_test.json", + "ecdsa_secp224r1_sha3_512_test.json", "ecdsa_secp256k1_sha256_test.json", "ecdsa_secp256k1_sha512_test.json", + "ecdsa_secp256k1_sha3_256_test.json", + "ecdsa_secp256k1_sha3_512_test.json", "ecdsa_secp256r1_sha256_test.json", "ecdsa_secp256r1_sha512_test.json", + "ecdsa_secp256r1_sha3_256_test.json", + "ecdsa_secp256r1_sha3_512_test.json", "ecdsa_secp384r1_sha384_test.json", "ecdsa_secp384r1_sha512_test.json", + "ecdsa_secp384r1_sha3_384_test.json", + "ecdsa_secp384r1_sha3_512_test.json", "ecdsa_secp521r1_sha512_test.json", + "ecdsa_secp521r1_sha3_512_test.json", ) def test_ecdsa_signature(backend, wycheproof): try: @@ -48,9 +62,9 @@ def test_ecdsa_signature(backend, wycheproof): binascii.unhexlify(wycheproof.testgroup["keyDer"]), backend ) except (UnsupportedAlgorithm, ValueError): - # In OpenSSL 1.0.1, some keys fail to load with ValueError, instead of - # Unsupported Algorithm. We can remove handling for that exception - # when we drop support. + # In some OpenSSL 1.0.2s, some keys fail to load with ValueError, + # instead of Unsupported Algorithm. We can remove handling for that + # exception when we drop support. pytest.skip( "unable to load key (curve {})".format( wycheproof.testgroup["key"]["curve"] @@ -58,9 +72,11 @@ def test_ecdsa_signature(backend, wycheproof): ) digest = _DIGESTS[wycheproof.testgroup["sha"]] - if ( - wycheproof.valid or - (wycheproof.acceptable and not wycheproof.has_flag("MissingZero")) + if not backend.hash_supported(digest): + pytest.skip("Hash {} not supported".format(digest)) + + if wycheproof.valid or ( + wycheproof.acceptable and not wycheproof.has_flag("MissingZero") ): key.verify( binascii.unhexlify(wycheproof.testcase["sig"]), diff --git a/tests/wycheproof/test_eddsa.py b/tests/wycheproof/test_eddsa.py new file mode 100644 index 000000000000..42c1498afff1 --- /dev/null +++ b/tests/wycheproof/test_eddsa.py @@ -0,0 +1,63 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +import pytest + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey +from cryptography.hazmat.primitives.asymmetric.ed448 import Ed448PublicKey + + +@pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support", +) +@pytest.mark.wycheproof_tests("eddsa_test.json") +def test_ed25519_signature(backend, wycheproof): + # We want to fail if/when wycheproof adds more edwards curve tests + # so we can add them as well. + assert wycheproof.testgroup["key"]["curve"] == "edwards25519" + + key = Ed25519PublicKey.from_public_bytes( + binascii.unhexlify(wycheproof.testgroup["key"]["pk"]) + ) + + if wycheproof.valid or wycheproof.acceptable: + key.verify( + binascii.unhexlify(wycheproof.testcase["sig"]), + binascii.unhexlify(wycheproof.testcase["msg"]), + ) + else: + with pytest.raises(InvalidSignature): + key.verify( + binascii.unhexlify(wycheproof.testcase["sig"]), + binascii.unhexlify(wycheproof.testcase["msg"]), + ) + + +@pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support", +) +@pytest.mark.wycheproof_tests("ed448_test.json") +def test_ed448_signature(backend, wycheproof): + key = Ed448PublicKey.from_public_bytes( + binascii.unhexlify(wycheproof.testgroup["key"]["pk"]) + ) + + if wycheproof.valid or wycheproof.acceptable: + key.verify( + binascii.unhexlify(wycheproof.testcase["sig"]), + binascii.unhexlify(wycheproof.testcase["msg"]), + ) + else: + with pytest.raises(InvalidSignature): + key.verify( + binascii.unhexlify(wycheproof.testcase["sig"]), + binascii.unhexlify(wycheproof.testcase["msg"]), + ) diff --git a/tests/wycheproof/test_hkdf.py b/tests/wycheproof/test_hkdf.py new file mode 100644 index 000000000000..3e1687ea3105 --- /dev/null +++ b/tests/wycheproof/test_hkdf.py @@ -0,0 +1,50 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +import pytest + +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.kdf.hkdf import HKDF + + +_HASH_ALGORITHMS = { + "HKDF-SHA-1": hashes.SHA1(), + "HKDF-SHA-256": hashes.SHA256(), + "HKDF-SHA-384": hashes.SHA384(), + "HKDF-SHA-512": hashes.SHA512(), +} + + +@pytest.mark.wycheproof_tests( + "hkdf_sha1_test.json", + "hkdf_sha256_test.json", + "hkdf_sha384_test.json", + "hkdf_sha512_test.json", +) +def test_hkdf(backend, wycheproof): + hash_algo = _HASH_ALGORITHMS[wycheproof.testfiledata["algorithm"]] + if wycheproof.invalid: + with pytest.raises(ValueError): + HKDF( + algorithm=hash_algo, + length=wycheproof.testcase["size"], + salt=binascii.unhexlify(wycheproof.testcase["salt"]), + info=binascii.unhexlify(wycheproof.testcase["info"]), + backend=backend, + ) + return + + h = HKDF( + algorithm=hash_algo, + length=wycheproof.testcase["size"], + salt=binascii.unhexlify(wycheproof.testcase["salt"]), + info=binascii.unhexlify(wycheproof.testcase["info"]), + backend=backend, + ) + result = h.derive(binascii.unhexlify(wycheproof.testcase["ikm"])) + assert result == binascii.unhexlify(wycheproof.testcase["okm"]) diff --git a/tests/wycheproof/test_hmac.py b/tests/wycheproof/test_hmac.py new file mode 100644 index 000000000000..0cf908fe90c1 --- /dev/null +++ b/tests/wycheproof/test_hmac.py @@ -0,0 +1,66 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +import pytest + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.primitives import hashes, hmac + + +_HMAC_ALGORITHMS = { + "HMACSHA1": hashes.SHA1(), + "HMACSHA224": hashes.SHA224(), + "HMACSHA256": hashes.SHA256(), + "HMACSHA384": hashes.SHA384(), + "HMACSHA512": hashes.SHA512(), + "HMACSHA3-224": hashes.SHA3_224(), + "HMACSHA3-256": hashes.SHA3_256(), + "HMACSHA3-384": hashes.SHA3_384(), + "HMACSHA3-512": hashes.SHA3_512(), +} + + +@pytest.mark.wycheproof_tests( + "hmac_sha1_test.json", + "hmac_sha224_test.json", + "hmac_sha256_test.json", + "hmac_sha384_test.json", + "hmac_sha3_224_test.json", + "hmac_sha3_256_test.json", + "hmac_sha3_384_test.json", + "hmac_sha3_512_test.json", + "hmac_sha512_test.json", +) +def test_hmac(backend, wycheproof): + hash_algo = _HMAC_ALGORITHMS[wycheproof.testfiledata["algorithm"]] + if wycheproof.testgroup["tagSize"] // 8 != hash_algo.digest_size: + pytest.skip("Truncated HMAC not supported") + if not backend.hash_supported(hash_algo): + pytest.skip("Hash {} not supported".format(hash_algo.name)) + + h = hmac.HMAC( + key=binascii.unhexlify(wycheproof.testcase["key"]), + algorithm=hash_algo, + backend=backend, + ) + h.update(binascii.unhexlify(wycheproof.testcase["msg"])) + + if wycheproof.invalid: + with pytest.raises(InvalidSignature): + h.verify(binascii.unhexlify(wycheproof.testcase["tag"])) + else: + tag = h.finalize() + assert tag == binascii.unhexlify(wycheproof.testcase["tag"]) + + h = hmac.HMAC( + key=binascii.unhexlify(wycheproof.testcase["key"]), + algorithm=hash_algo, + backend=backend, + ) + h.update(binascii.unhexlify(wycheproof.testcase["msg"])) + h.verify(binascii.unhexlify(wycheproof.testcase["tag"])) diff --git a/tests/wycheproof/test_keywrap.py b/tests/wycheproof/test_keywrap.py index 5f694e4d3346..9c7d522e61e0 100644 --- a/tests/wycheproof/test_keywrap.py +++ b/tests/wycheproof/test_keywrap.py @@ -44,11 +44,9 @@ def test_keywrap(backend, wycheproof): key_to_wrap = binascii.unhexlify(wycheproof.testcase["msg"]) expected = binascii.unhexlify(wycheproof.testcase["ct"]) - if ( - wycheproof.valid or ( - wycheproof.acceptable and - wycheproof.testcase["comment"] != "invalid size of wrapped key" - ) + if wycheproof.valid or ( + wycheproof.acceptable + and wycheproof.testcase["comment"] != "invalid size of wrapped key" ): result = keywrap.aes_key_wrap(wrapping_key, key_to_wrap, backend) assert result == expected diff --git a/tests/wycheproof/test_rsa.py b/tests/wycheproof/test_rsa.py index 3d35f42d7cad..1262b58853d3 100644 --- a/tests/wycheproof/test_rsa.py +++ b/tests/wycheproof/test_rsa.py @@ -20,6 +20,13 @@ "SHA-256": hashes.SHA256(), "SHA-384": hashes.SHA384(), "SHA-512": hashes.SHA512(), + # Not supported by OpenSSL for RSA signing + "SHA-512/224": None, + "SHA-512/256": None, + "SHA3-224": hashes.SHA3_224(), + "SHA3-256": hashes.SHA3_256(), + "SHA3-384": hashes.SHA3_384(), + "SHA3-512": hashes.SHA3_512(), } @@ -29,9 +36,9 @@ def should_verify(backend, wycheproof): if wycheproof.acceptable: if ( - backend._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER and - wycheproof.has_flag("MissingNull") - ): + backend._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER + or backend._lib.CRYPTOGRAPHY_IS_LIBRESSL + ) and wycheproof.has_flag("MissingNull"): return False return True @@ -39,28 +46,28 @@ def should_verify(backend, wycheproof): @pytest.mark.requires_backend_interface(interface=RSABackend) -@pytest.mark.supported( - only_if=lambda backend: ( - # TODO: this also skips on LibreSSL, which is ok for now, since these - # don't pass on Libre, but we'll need to fix this when LibreSSL 2.8 is - # released. - not backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 - ), - skip_message=( - "Many of these tests fail on OpenSSL < 1.0.2 and since upstream isn't" - " maintaining it, they'll never be fixed." - ), -) @pytest.mark.wycheproof_tests( "rsa_signature_test.json", "rsa_signature_2048_sha224_test.json", "rsa_signature_2048_sha256_test.json", + "rsa_signature_2048_sha384_test.json", "rsa_signature_2048_sha512_test.json", + "rsa_signature_2048_sha512_224_test.json", + "rsa_signature_2048_sha512_256_test.json", + "rsa_signature_2048_sha3_224_test.json", + "rsa_signature_2048_sha3_256_test.json", + "rsa_signature_2048_sha3_384_test.json", + "rsa_signature_2048_sha3_512_test.json", "rsa_signature_3072_sha256_test.json", "rsa_signature_3072_sha384_test.json", "rsa_signature_3072_sha512_test.json", + "rsa_signature_3072_sha512_256_test.json", + "rsa_signature_3072_sha3_256_test.json", + "rsa_signature_3072_sha3_384_test.json", + "rsa_signature_3072_sha3_512_test.json", "rsa_signature_4096_sha384_test.json", "rsa_signature_4096_sha512_test.json", + "rsa_signature_4096_sha512_256_test.json", ) def test_rsa_pkcs1v15_signature(backend, wycheproof): key = serialization.load_der_public_key( @@ -68,6 +75,11 @@ def test_rsa_pkcs1v15_signature(backend, wycheproof): ) digest = _DIGESTS[wycheproof.testgroup["sha"]] + if digest is None or not backend.hash_supported(digest): + pytest.skip( + "Hash {} not supported".format(wycheproof.testgroup["sha"]) + ) + if should_verify(backend, wycheproof): key.verify( binascii.unhexlify(wycheproof.testcase["sig"]), @@ -85,11 +97,30 @@ def test_rsa_pkcs1v15_signature(backend, wycheproof): ) +@pytest.mark.wycheproof_tests("rsa_sig_gen_misc_test.json") +def test_rsa_pkcs1v15_signature_generation(backend, wycheproof): + key = serialization.load_pem_private_key( + wycheproof.testgroup["privateKeyPem"].encode(), + password=None, + backend=backend, + ) + digest = _DIGESTS[wycheproof.testgroup["sha"]] + + sig = key.sign( + binascii.unhexlify(wycheproof.testcase["msg"]), + padding.PKCS1v15(), + digest, + ) + assert sig == binascii.unhexlify(wycheproof.testcase["sig"]) + + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.wycheproof_tests( "rsa_pss_2048_sha1_mgf1_20_test.json", "rsa_pss_2048_sha256_mgf1_0_test.json", "rsa_pss_2048_sha256_mgf1_32_test.json", + "rsa_pss_2048_sha512_256_mgf1_28_test.json", + "rsa_pss_2048_sha512_256_mgf1_32_test.json", "rsa_pss_3072_sha256_mgf1_32_test.json", "rsa_pss_4096_sha256_mgf1_32_test.json", "rsa_pss_4096_sha512_mgf1_32_test.json", @@ -102,15 +133,23 @@ def test_rsa_pss_signature(backend, wycheproof): digest = _DIGESTS[wycheproof.testgroup["sha"]] mgf_digest = _DIGESTS[wycheproof.testgroup["mgfSha"]] + if digest is None or mgf_digest is None: + pytest.skip( + "PSS with digest={} and MGF digest={} not supported".format( + wycheproof.testgroup["sha"], + wycheproof.testgroup["mgfSha"], + ) + ) + if wycheproof.valid or wycheproof.acceptable: key.verify( binascii.unhexlify(wycheproof.testcase["sig"]), binascii.unhexlify(wycheproof.testcase["msg"]), padding.PSS( mgf=padding.MGF1(mgf_digest), - salt_length=wycheproof.testgroup["sLen"] + salt_length=wycheproof.testgroup["sLen"], ), - digest + digest, ) else: with pytest.raises(InvalidSignature): @@ -119,7 +158,98 @@ def test_rsa_pss_signature(backend, wycheproof): binascii.unhexlify(wycheproof.testcase["msg"]), padding.PSS( mgf=padding.MGF1(mgf_digest), - salt_length=wycheproof.testgroup["sLen"] + salt_length=wycheproof.testgroup["sLen"], ), - digest + digest, + ) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.supported( + only_if=lambda backend: ( + backend._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER + or backend._lib.CRYPTOGRAPHY_IS_LIBRESSL + ), + skip_message=( + "A handful of these tests fail on OpenSSL 1.0.2 and since upstream " + "isn't maintaining it, they'll never be fixed." + ), +) +@pytest.mark.wycheproof_tests( + "rsa_oaep_2048_sha1_mgf1sha1_test.json", + "rsa_oaep_2048_sha224_mgf1sha1_test.json", + "rsa_oaep_2048_sha224_mgf1sha224_test.json", + "rsa_oaep_2048_sha256_mgf1sha1_test.json", + "rsa_oaep_2048_sha256_mgf1sha256_test.json", + "rsa_oaep_2048_sha384_mgf1sha1_test.json", + "rsa_oaep_2048_sha384_mgf1sha384_test.json", + "rsa_oaep_2048_sha512_mgf1sha1_test.json", + "rsa_oaep_2048_sha512_mgf1sha512_test.json", + "rsa_oaep_3072_sha256_mgf1sha1_test.json", + "rsa_oaep_3072_sha256_mgf1sha256_test.json", + "rsa_oaep_3072_sha512_mgf1sha1_test.json", + "rsa_oaep_3072_sha512_mgf1sha512_test.json", + "rsa_oaep_4096_sha256_mgf1sha1_test.json", + "rsa_oaep_4096_sha256_mgf1sha256_test.json", + "rsa_oaep_4096_sha512_mgf1sha1_test.json", + "rsa_oaep_4096_sha512_mgf1sha512_test.json", + "rsa_oaep_misc_test.json", +) +def test_rsa_oaep_encryption(backend, wycheproof): + key = serialization.load_pem_private_key( + wycheproof.testgroup["privateKeyPem"].encode("ascii"), + password=None, + backend=backend, + ) + digest = _DIGESTS[wycheproof.testgroup["sha"]] + mgf_digest = _DIGESTS[wycheproof.testgroup["mgfSha"]] + + padding_algo = padding.OAEP( + mgf=padding.MGF1(algorithm=mgf_digest), + algorithm=digest, + label=binascii.unhexlify(wycheproof.testcase["label"]), + ) + + if not backend.rsa_padding_supported(padding_algo): + pytest.skip( + "OAEP with digest={} and MGF digest={} not supported".format( + wycheproof.testgroup["sha"], + wycheproof.testgroup["mgfSha"], + ) + ) + + if wycheproof.valid or wycheproof.acceptable: + pt = key.decrypt( + binascii.unhexlify(wycheproof.testcase["ct"]), padding_algo + ) + assert pt == binascii.unhexlify(wycheproof.testcase["msg"]) + else: + with pytest.raises(ValueError): + key.decrypt( + binascii.unhexlify(wycheproof.testcase["ct"]), padding_algo + ) + + +@pytest.mark.wycheproof_tests( + "rsa_pkcs1_2048_test.json", + "rsa_pkcs1_3072_test.json", + "rsa_pkcs1_4096_test.json", +) +def test_rsa_pkcs1_encryption(backend, wycheproof): + key = serialization.load_pem_private_key( + wycheproof.testgroup["privateKeyPem"].encode("ascii"), + password=None, + backend=backend, + ) + + if wycheproof.valid: + pt = key.decrypt( + binascii.unhexlify(wycheproof.testcase["ct"]), padding.PKCS1v15() + ) + assert pt == binascii.unhexlify(wycheproof.testcase["msg"]) + else: + with pytest.raises(ValueError): + key.decrypt( + binascii.unhexlify(wycheproof.testcase["ct"]), + padding.PKCS1v15(), ) diff --git a/tests/wycheproof/test_utils.py b/tests/wycheproof/test_utils.py index 82c0a3596396..2cf3be08e97c 100644 --- a/tests/wycheproof/test_utils.py +++ b/tests/wycheproof/test_utils.py @@ -10,8 +10,8 @@ def test_wycheproof_test_repr(): - wycheproof = WycheproofTest({}, {"tcId": 3}) - assert repr(wycheproof) == "" + wycheproof = WycheproofTest({}, {}, {"tcId": 3}) + assert repr(wycheproof) == "" def test_skip_if_wycheproof_none(): diff --git a/tests/wycheproof/test_x25519.py b/tests/wycheproof/test_x25519.py index 0727ec39de2e..ce2a965e3a42 100644 --- a/tests/wycheproof/test_x25519.py +++ b/tests/wycheproof/test_x25519.py @@ -8,20 +8,22 @@ import pytest -from cryptography.hazmat.backends.interfaces import DHBackend from cryptography.hazmat.primitives.asymmetric.x25519 import ( - X25519PrivateKey, X25519PublicKey + X25519PrivateKey, + X25519PublicKey, ) @pytest.mark.supported( only_if=lambda backend: backend.x25519_supported(), - skip_message="Requires OpenSSL with X25519 support" + skip_message="Requires OpenSSL with X25519 support", ) -@pytest.mark.requires_backend_interface(interface=DHBackend) @pytest.mark.wycheproof_tests("x25519_test.json") def test_x25519(backend, wycheproof): - assert list(wycheproof.testgroup.items()) == [("curve", "curve25519")] + assert set(wycheproof.testgroup.items()) == { + ("curve", "curve25519"), + ("type", "XdhComp"), + } private_key = X25519PrivateKey.from_private_bytes( binascii.unhexlify(wycheproof.testcase["private"]) diff --git a/tests/wycheproof/test_x448.py b/tests/wycheproof/test_x448.py new file mode 100644 index 000000000000..fcac80996f74 --- /dev/null +++ b/tests/wycheproof/test_x448.py @@ -0,0 +1,50 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +import pytest + +from cryptography.hazmat.primitives.asymmetric.x448 import ( + X448PrivateKey, + X448PublicKey, +) + + +@pytest.mark.supported( + only_if=lambda backend: backend.x448_supported(), + skip_message="Requires OpenSSL with X448 support", +) +@pytest.mark.wycheproof_tests("x448_test.json") +def test_x448(backend, wycheproof): + assert set(wycheproof.testgroup.items()) == { + ("curve", "curve448"), + ("type", "XdhComp"), + } + + private_key = X448PrivateKey.from_private_bytes( + binascii.unhexlify(wycheproof.testcase["private"]) + ) + public_key_bytes = binascii.unhexlify(wycheproof.testcase["public"]) + if len(public_key_bytes) == 57: + assert wycheproof.acceptable + assert wycheproof.has_flag("NonCanonicalPublic") + with pytest.raises(ValueError): + X448PublicKey.from_public_bytes(public_key_bytes) + return + + public_key = X448PublicKey.from_public_bytes(public_key_bytes) + + assert wycheproof.valid or wycheproof.acceptable + + expected = binascii.unhexlify(wycheproof.testcase["shared"]) + if expected == b"\x00" * 56: + assert wycheproof.acceptable + # OpenSSL returns an error on all zeros shared key + with pytest.raises(ValueError): + private_key.exchange(public_key) + else: + assert private_key.exchange(public_key) == expected diff --git a/tests/x509/test_ocsp.py b/tests/x509/test_ocsp.py index 3abaff506a8a..b64940242905 100644 --- a/tests/x509/test_ocsp.py +++ b/tests/x509/test_ocsp.py @@ -13,7 +13,7 @@ from cryptography import x509 from cryptography.exceptions import UnsupportedAlgorithm from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.asymmetric import ec, ed25519, ed448 from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15 from cryptography.x509 import ocsp @@ -24,51 +24,52 @@ def _load_data(filename, loader): return load_vectors_from_file( - filename=filename, - loader=lambda data: loader(data.read()), - mode="rb" + filename=filename, loader=lambda data: loader(data.read()), mode="rb" ) def _cert_and_issuer(): from cryptography.hazmat.backends.openssl.backend import backend + cert = _load_cert( os.path.join("x509", "cryptography.io.pem"), x509.load_pem_x509_certificate, - backend + backend, ) issuer = _load_cert( os.path.join("x509", "rapidssl_sha256_ca_g3.pem"), x509.load_pem_x509_certificate, - backend + backend, ) return cert, issuer -def _generate_root(): +def _generate_root(private_key=None, algorithm=hashes.SHA256()): from cryptography.hazmat.backends.openssl.backend import backend - private_key = EC_KEY_SECP256R1.private_key(backend) - subject = x509.Name([ - x509.NameAttribute(x509.NameOID.COUNTRY_NAME, u'US'), - x509.NameAttribute(x509.NameOID.COMMON_NAME, u'Cryptography CA'), - ]) - - builder = x509.CertificateBuilder().serial_number( - 123456789 - ).issuer_name( - subject - ).subject_name( - subject - ).public_key( - private_key.public_key() - ).not_valid_before( - datetime.datetime.now() - ).not_valid_after( - datetime.datetime.now() + datetime.timedelta(days=3650) + if private_key is None: + private_key = EC_KEY_SECP256R1.private_key(backend) + + subject = x509.Name( + [ + x509.NameAttribute(x509.NameOID.COUNTRY_NAME, u"US"), + x509.NameAttribute(x509.NameOID.COMMON_NAME, u"Cryptography CA"), + ] ) - cert = builder.sign(private_key, hashes.SHA256(), backend) + builder = ( + x509.CertificateBuilder() + .serial_number(123456789) + .issuer_name(subject) + .subject_name(subject) + .public_key(private_key.public_key()) + .not_valid_before(datetime.datetime.now()) + .not_valid_after( + datetime.datetime.now() + datetime.timedelta(days=3650) + ) + ) + + cert = builder.sign(private_key, algorithm, backend) return cert, private_key @@ -82,10 +83,12 @@ def test_load_request(self): os.path.join("x509", "ocsp", "req-sha1.der"), ocsp.load_der_ocsp_request, ) - assert req.issuer_name_hash == (b"8\xcaF\x8c\x07D\x8d\xf4\x81\x96" - b"\xc7mmLpQ\x9e`\xa7\xbd") - assert req.issuer_key_hash == (b"yu\xbb\x84:\xcb,\xdez\t\xbe1" - b"\x1bC\xbc\x1c*MSX") + assert req.issuer_name_hash == ( + b"8\xcaF\x8c\x07D\x8d\xf4\x81\x96" b"\xc7mmLpQ\x9e`\xa7\xbd" + ) + assert req.issuer_key_hash == ( + b"yu\xbb\x84:\xcb,\xdez\t\xbe1" b"\x1bC\xbc\x1c*MSX" + ) assert isinstance(req.hash_algorithm, hashes.SHA1) assert req.serial_number == int( "98D9E5C0B4C373552DF77C5D0F1EB5128E4945F9", 16 @@ -123,7 +126,7 @@ def test_serialize_request(self): req_bytes = load_vectors_from_file( filename=os.path.join("x509", "ocsp", "req-sha1.der"), loader=lambda data: data.read(), - mode="rb" + mode="rb", ) req = ocsp.load_der_ocsp_request(req_bytes) assert req.public_bytes(serialization.Encoding.DER) == req_bytes @@ -194,16 +197,14 @@ def test_create_ocsp_request(self): [ [x509.OCSPNonce(b"0000"), False], [x509.OCSPNonce(b"\x00\x01\x02"), True], - ] + ], ) def test_create_ocsp_request_with_extension(self, ext, critical): cert, issuer = _cert_and_issuer() builder = ocsp.OCSPRequestBuilder() builder = builder.add_certificate( cert, issuer, hashes.SHA1() - ).add_extension( - ext, critical - ) + ).add_extension(ext, critical) req = builder.build() assert len(req.extensions) == 1 assert req.extensions[0].value == ext @@ -217,13 +218,25 @@ def test_add_response_twice(self): time = datetime.datetime.now() builder = ocsp.OCSPResponseBuilder() builder = builder.add_response( - cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, time, - time, None, None + cert, + issuer, + hashes.SHA256(), + ocsp.OCSPCertStatus.GOOD, + time, + time, + None, + None, ) with pytest.raises(ValueError): builder.add_response( - cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, time, - time, None, None + cert, + issuer, + hashes.SHA256(), + ocsp.OCSPCertStatus.GOOD, + time, + time, + None, + None, ) def test_invalid_add_response(self): @@ -233,28 +246,58 @@ def test_invalid_add_response(self): builder = ocsp.OCSPResponseBuilder() with pytest.raises(TypeError): builder.add_response( - 'bad', issuer, hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, - time, time, None, None + "bad", + issuer, + hashes.SHA256(), + ocsp.OCSPCertStatus.GOOD, + time, + time, + None, + None, ) with pytest.raises(TypeError): builder.add_response( - cert, 'bad', hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, - time, time, None, None + cert, + "bad", + hashes.SHA256(), + ocsp.OCSPCertStatus.GOOD, + time, + time, + None, + None, ) with pytest.raises(ValueError): builder.add_response( - cert, issuer, 'notahash', ocsp.OCSPCertStatus.GOOD, - time, time, None, None + cert, + issuer, + "notahash", + ocsp.OCSPCertStatus.GOOD, + time, + time, + None, + None, ) with pytest.raises(TypeError): builder.add_response( - cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, - 'bad', time, None, None + cert, + issuer, + hashes.SHA256(), + ocsp.OCSPCertStatus.GOOD, + "bad", + time, + None, + None, ) with pytest.raises(TypeError): builder.add_response( - cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, - time, 'bad', None, None + cert, + issuer, + hashes.SHA256(), + ocsp.OCSPCertStatus.GOOD, + time, + "bad", + None, + None, ) with pytest.raises(TypeError): @@ -263,28 +306,58 @@ def test_invalid_add_response(self): ) with pytest.raises(ValueError): builder.add_response( - cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, - time, time, time, None + cert, + issuer, + hashes.SHA256(), + ocsp.OCSPCertStatus.GOOD, + time, + time, + time, + None, ) with pytest.raises(ValueError): builder.add_response( - cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.GOOD, - time, time, None, reason + cert, + issuer, + hashes.SHA256(), + ocsp.OCSPCertStatus.GOOD, + time, + time, + None, + reason, ) with pytest.raises(TypeError): builder.add_response( - cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.REVOKED, - time, time, None, reason + cert, + issuer, + hashes.SHA256(), + ocsp.OCSPCertStatus.REVOKED, + time, + time, + None, + reason, ) with pytest.raises(TypeError): builder.add_response( - cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.REVOKED, - time, time, time, 0 + cert, + issuer, + hashes.SHA256(), + ocsp.OCSPCertStatus.REVOKED, + time, + time, + time, + 0, ) with pytest.raises(ValueError): builder.add_response( - cert, issuer, hashes.SHA256(), ocsp.OCSPCertStatus.REVOKED, - time, time, time - datetime.timedelta(days=36500), None + cert, + issuer, + hashes.SHA256(), + ocsp.OCSPCertStatus.REVOKED, + time, + time, + time - datetime.timedelta(days=36500), + None, ) def test_invalid_certificates(self): @@ -292,9 +365,9 @@ def test_invalid_certificates(self): with pytest.raises(ValueError): builder.certificates([]) with pytest.raises(TypeError): - builder.certificates(['notacert']) + builder.certificates(["notacert"]) with pytest.raises(TypeError): - builder.certificates('invalid') + builder.certificates("invalid") _, issuer = _cert_and_issuer() builder = builder.certificates([issuer]) @@ -305,9 +378,9 @@ def test_invalid_responder_id(self): builder = ocsp.OCSPResponseBuilder() cert, _ = _cert_and_issuer() with pytest.raises(TypeError): - builder.responder_id(ocsp.OCSPResponderEncoding.HASH, 'invalid') + builder.responder_id(ocsp.OCSPResponderEncoding.HASH, "invalid") with pytest.raises(TypeError): - builder.responder_id('notanenum', cert) + builder.responder_id("notanenum", cert) builder = builder.responder_id(ocsp.OCSPResponderEncoding.NAME, cert) with pytest.raises(ValueError): @@ -335,8 +408,14 @@ def test_sign_no_responder_id(self): this_update = current_time - datetime.timedelta(days=1) next_update = this_update + datetime.timedelta(days=7) builder = builder.add_response( - cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.GOOD, this_update, - next_update, None, None + cert, + issuer, + hashes.SHA1(), + ocsp.OCSPCertStatus.GOOD, + this_update, + next_update, + None, + None, ) with pytest.raises(ValueError): builder.sign(private_key, hashes.SHA256()) @@ -351,11 +430,17 @@ def test_sign_invalid_hash_algorithm(self): builder = builder.responder_id( ocsp.OCSPResponderEncoding.NAME, root_cert ).add_response( - cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.GOOD, this_update, - next_update, None, None + cert, + issuer, + hashes.SHA1(), + ocsp.OCSPCertStatus.GOOD, + this_update, + next_update, + None, + None, ) with pytest.raises(TypeError): - builder.sign(private_key, 'notahash') + builder.sign(private_key, "notahash") def test_sign_good_cert(self): builder = ocsp.OCSPResponseBuilder() @@ -367,15 +452,23 @@ def test_sign_good_cert(self): builder = builder.responder_id( ocsp.OCSPResponderEncoding.NAME, root_cert ).add_response( - cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.GOOD, this_update, - next_update, None, None + cert, + issuer, + hashes.SHA1(), + ocsp.OCSPCertStatus.GOOD, + this_update, + next_update, + None, + None, ) resp = builder.sign(private_key, hashes.SHA256()) assert resp.responder_name == root_cert.subject assert resp.responder_key_hash is None assert (current_time - resp.produced_at).total_seconds() < 10 - assert (resp.signature_algorithm_oid == - x509.SignatureAlgorithmOID.ECDSA_WITH_SHA256) + assert ( + resp.signature_algorithm_oid + == x509.SignatureAlgorithmOID.ECDSA_WITH_SHA256 + ) assert resp.certificate_status == ocsp.OCSPCertStatus.GOOD assert resp.revocation_time is None assert resp.revocation_reason is None @@ -396,8 +489,14 @@ def test_sign_revoked_cert(self): builder = builder.responder_id( ocsp.OCSPResponderEncoding.NAME, root_cert ).add_response( - cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.REVOKED, - this_update, next_update, revoked_date, None + cert, + issuer, + hashes.SHA1(), + ocsp.OCSPCertStatus.REVOKED, + this_update, + next_update, + revoked_date, + None, ) resp = builder.sign(private_key, hashes.SHA256()) assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED @@ -416,13 +515,19 @@ def test_sign_with_appended_certs(self): current_time = datetime.datetime.utcnow().replace(microsecond=0) this_update = current_time - datetime.timedelta(days=1) next_update = this_update + datetime.timedelta(days=7) - builder = builder.responder_id( - ocsp.OCSPResponderEncoding.NAME, root_cert - ).add_response( - cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.GOOD, this_update, - next_update, None, None - ).certificates( - [root_cert] + builder = ( + builder.responder_id(ocsp.OCSPResponderEncoding.NAME, root_cert) + .add_response( + cert, + issuer, + hashes.SHA1(), + ocsp.OCSPCertStatus.GOOD, + this_update, + next_update, + None, + None, + ) + .certificates([root_cert]) ) resp = builder.sign(private_key, hashes.SHA256()) assert resp.certificates == [root_cert] @@ -437,8 +542,14 @@ def test_sign_revoked_no_next_update(self): builder = builder.responder_id( ocsp.OCSPResponderEncoding.NAME, root_cert ).add_response( - cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.REVOKED, - this_update, None, revoked_date, None + cert, + issuer, + hashes.SHA1(), + ocsp.OCSPCertStatus.REVOKED, + this_update, + None, + revoked_date, + None, ) resp = builder.sign(private_key, hashes.SHA256()) assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED @@ -461,9 +572,14 @@ def test_sign_revoked_with_reason(self): builder = builder.responder_id( ocsp.OCSPResponderEncoding.NAME, root_cert ).add_response( - cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.REVOKED, - this_update, next_update, revoked_date, - x509.ReasonFlags.key_compromise + cert, + issuer, + hashes.SHA1(), + ocsp.OCSPCertStatus.REVOKED, + this_update, + next_update, + revoked_date, + x509.ReasonFlags.key_compromise, ) resp = builder.sign(private_key, hashes.SHA256()) assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED @@ -485,13 +601,19 @@ def test_sign_responder_id_key_hash(self): builder = builder.responder_id( ocsp.OCSPResponderEncoding.HASH, root_cert ).add_response( - cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.GOOD, this_update, - next_update, None, None + cert, + issuer, + hashes.SHA1(), + ocsp.OCSPCertStatus.GOOD, + this_update, + next_update, + None, + None, ) resp = builder.sign(private_key, hashes.SHA256()) assert resp.responder_name is None assert resp.responder_key_hash == ( - b'\x8ca\x94\xe0\x948\xed\x89\xd8\xd4N\x89p\t\xd6\xf9^_\xec}' + b"\x8ca\x94\xe0\x948\xed\x89\xd8\xd4N\x89p\t\xd6\xf9^_\xec}" ) private_key.public_key().verify( resp.signature, resp.tbs_response_bytes, ec.ECDSA(hashes.SHA256()) @@ -507,10 +629,17 @@ def test_invalid_sign_responder_cert_does_not_match_private_key(self): builder = builder.responder_id( ocsp.OCSPResponderEncoding.HASH, root_cert ).add_response( - cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.GOOD, this_update, - next_update, None, None + cert, + issuer, + hashes.SHA1(), + ocsp.OCSPCertStatus.GOOD, + this_update, + next_update, + None, + None, ) from cryptography.hazmat.backends.openssl.backend import backend + diff_key = ec.generate_private_key(ec.SECP256R1(), backend) with pytest.raises(ValueError): builder.sign(diff_key, hashes.SHA256()) @@ -522,13 +651,19 @@ def test_sign_with_extension(self): current_time = datetime.datetime.utcnow().replace(microsecond=0) this_update = current_time - datetime.timedelta(days=1) next_update = this_update + datetime.timedelta(days=7) - builder = builder.responder_id( - ocsp.OCSPResponderEncoding.HASH, root_cert - ).add_response( - cert, issuer, hashes.SHA1(), ocsp.OCSPCertStatus.GOOD, this_update, - next_update, None, None - ).add_extension( - x509.OCSPNonce(b"012345"), False + builder = ( + builder.responder_id(ocsp.OCSPResponderEncoding.HASH, root_cert) + .add_response( + cert, + issuer, + hashes.SHA1(), + ocsp.OCSPCertStatus.GOOD, + this_update, + next_update, + None, + None, + ) + .add_extension(x509.OCSPNonce(b"012345"), False) ) resp = builder.sign(private_key, hashes.SHA256()) assert len(resp.extensions) == 1 @@ -546,7 +681,7 @@ def test_sign_with_extension(self): (ocsp.OCSPResponseStatus.TRY_LATER, b"0\x03\n\x01\x03"), (ocsp.OCSPResponseStatus.SIG_REQUIRED, b"0\x03\n\x01\x05"), (ocsp.OCSPResponseStatus.UNAUTHORIZED, b"0\x03\n\x01\x06"), - ] + ], ) def test_build_non_successful_statuses(self, status, der): resp = ocsp.OCSPResponseBuilder.build_unsuccessful(status) @@ -564,6 +699,92 @@ def test_invalid_build_successful_status(self): ) +class TestSignedCertificateTimestampsExtension(object): + def test_init(self): + with pytest.raises(TypeError): + x509.SignedCertificateTimestamps([object()]) + + def test_repr(self): + assert repr(x509.SignedCertificateTimestamps([])) == ( + "" + ) + + @pytest.mark.supported( + only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), + skip_message="Requires CT support", + ) + def test_eq(self, backend): + sct1 = ( + _load_data( + os.path.join("x509", "ocsp", "resp-sct-extension.der"), + ocsp.load_der_ocsp_response, + ) + .single_extensions.get_extension_for_class( + x509.SignedCertificateTimestamps + ) + .value + ) + sct2 = ( + _load_data( + os.path.join("x509", "ocsp", "resp-sct-extension.der"), + ocsp.load_der_ocsp_response, + ) + .single_extensions.get_extension_for_class( + x509.SignedCertificateTimestamps + ) + .value + ) + assert sct1 == sct2 + + @pytest.mark.supported( + only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), + skip_message="Requires CT support", + ) + def test_ne(self, backend): + sct1 = ( + _load_data( + os.path.join("x509", "ocsp", "resp-sct-extension.der"), + ocsp.load_der_ocsp_response, + ) + .single_extensions.get_extension_for_class( + x509.SignedCertificateTimestamps + ) + .value + ) + sct2 = x509.SignedCertificateTimestamps([]) + assert sct1 != sct2 + assert sct1 != object() + + @pytest.mark.supported( + only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), + skip_message="Requires CT support", + ) + def test_hash(self, backend): + sct1 = ( + _load_data( + os.path.join("x509", "ocsp", "resp-sct-extension.der"), + ocsp.load_der_ocsp_response, + ) + .single_extensions.get_extension_for_class( + x509.SignedCertificateTimestamps + ) + .value + ) + sct2 = ( + _load_data( + os.path.join("x509", "ocsp", "resp-sct-extension.der"), + ocsp.load_der_ocsp_response, + ) + .single_extensions.get_extension_for_class( + x509.SignedCertificateTimestamps + ) + .value + ) + sct3 = x509.SignedCertificateTimestamps([]) + assert hash(sct1) == hash(sct2) + assert hash(sct1) != hash(sct3) + + class TestOCSPResponse(object): def test_bad_response(self): with pytest.raises(ValueError): @@ -575,14 +796,17 @@ def test_load_response(self): ocsp.load_der_ocsp_response, ) from cryptography.hazmat.backends.openssl.backend import backend + issuer = _load_cert( os.path.join("x509", "letsencryptx3.pem"), x509.load_pem_x509_certificate, - backend + backend, ) assert resp.response_status == ocsp.OCSPResponseStatus.SUCCESSFUL - assert (resp.signature_algorithm_oid == - x509.SignatureAlgorithmOID.RSA_WITH_SHA256) + assert ( + resp.signature_algorithm_oid + == x509.SignatureAlgorithmOID.RSA_WITH_SHA256 + ) assert isinstance(resp.signature_hash_algorithm, hashes.SHA256) assert resp.signature == base64.b64decode( b"I9KUlyLV/2LbNCVu1BQphxdNlU/jBzXsPYVscPjW5E93pCrSO84GkIWoOJtqsnt" @@ -603,7 +827,7 @@ def test_load_response(self): resp.signature, resp.tbs_response_bytes, PKCS1v15(), - resp.signature_hash_algorithm + resp.signature_hash_algorithm, ) assert resp.certificates == [] assert resp.responder_key_hash is None @@ -615,15 +839,22 @@ def test_load_response(self): assert resp.this_update == datetime.datetime(2018, 8, 30, 11, 0) assert resp.next_update == datetime.datetime(2018, 9, 6, 11, 0) assert resp.issuer_key_hash == ( - b'\xa8Jjc\x04}\xdd\xba\xe6\xd19\xb7\xa6Ee\xef\xf3\xa8\xec\xa1' + b"\xa8Jjc\x04}\xdd\xba\xe6\xd19\xb7\xa6Ee\xef\xf3\xa8\xec\xa1" ) assert resp.issuer_name_hash == ( - b'~\xe6j\xe7r\x9a\xb3\xfc\xf8\xa2 dl\x16\xa1-`q\x08]' + b"~\xe6j\xe7r\x9a\xb3\xfc\xf8\xa2 dl\x16\xa1-`q\x08]" ) assert isinstance(resp.hash_algorithm, hashes.SHA1) assert resp.serial_number == 271024907440004808294641238224534273948400 assert len(resp.extensions) == 0 + def test_load_multi_valued_response(self): + with pytest.raises(ValueError): + _load_data( + os.path.join("x509", "ocsp", "ocsp-army.deps.mil-resp.der"), + ocsp.load_der_ocsp_response, + ) + def test_load_unauthorized(self): resp = _load_data( os.path.join("x509", "ocsp", "resp-unauthorized.der"), @@ -705,7 +936,7 @@ def test_load_responder_key_hash(self): ) assert resp.responder_name is None assert resp.responder_key_hash == ( - b'\x0f\x80a\x1c\x821a\xd5/(\xe7\x8dF8\xb4,\xe1\xc6\xd9\xe2' + b"\x0f\x80a\x1c\x821a\xd5/(\xe7\x8dF8\xb4,\xe1\xc6\xd9\xe2" ) def test_load_revoked_reason(self): @@ -739,7 +970,7 @@ def test_serialize_reponse(self): resp_bytes = load_vectors_from_file( filename=os.path.join("x509", "ocsp", "resp-revoked.der"), loader=lambda data: data.read(), - mode="rb" + mode="rb", ) resp = ocsp.load_der_ocsp_response(resp_bytes) assert resp.public_bytes(serialization.Encoding.DER) == resp_bytes @@ -753,3 +984,161 @@ def test_invalid_serialize_encoding(self): resp.public_bytes("invalid") with pytest.raises(ValueError): resp.public_bytes(serialization.Encoding.PEM) + + @pytest.mark.supported( + only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), + skip_message="Requires CT support", + ) + def test_single_extensions_sct(self, backend): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-sct-extension.der"), + ocsp.load_der_ocsp_response, + ) + assert len(resp.single_extensions) == 1 + ext = resp.single_extensions[0] + assert ext.oid == x509.ObjectIdentifier("1.3.6.1.4.1.11129.2.4.5") + assert len(ext.value) == 4 + log_ids = [base64.b64encode(sct.log_id) for sct in ext.value] + assert log_ids == [ + b"RJRlLrDuzq/EQAfYqP4owNrmgr7YyzG1P9MzlrW2gag=", + b"b1N2rDHwMRnYmQCkURX/dxUcEdkCwQApBo2yCJo32RM=", + b"u9nfvB+KcbWTlCOXqpJ7RzhXlQqrUugakJZkNo4e0YU=", + b"7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/cs=", + ] + + @pytest.mark.supported( + only_if=lambda backend: ( + not backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER + ), + skip_message="Requires OpenSSL < 1.1.0f", + ) + def test_skips_single_extensions_scts_if_unsupported(self, backend): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-sct-extension.der"), + ocsp.load_der_ocsp_response, + ) + with pytest.raises(x509.ExtensionNotFound): + resp.single_extensions.get_extension_for_class( + x509.SignedCertificateTimestamps + ) + + ext = resp.single_extensions.get_extension_for_oid( + x509.ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS + ) + assert isinstance(ext.value, x509.UnrecognizedExtension) + + def test_single_extensions(self, backend): + resp = _load_data( + os.path.join("x509", "ocsp", "resp-single-extension-reason.der"), + ocsp.load_der_ocsp_response, + ) + assert len(resp.single_extensions) == 1 + ext = resp.single_extensions[0] + assert ext.oid == x509.CRLReason.oid + assert ext.value == x509.CRLReason(x509.ReasonFlags.unspecified) + + +class TestOCSPEdDSA(object): + @pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support / OCSP", + ) + def test_invalid_algorithm(self, backend): + builder = ocsp.OCSPResponseBuilder() + cert, issuer = _cert_and_issuer() + private_key = ed25519.Ed25519PrivateKey.generate() + root_cert, _ = _generate_root(private_key, None) + current_time = datetime.datetime.utcnow().replace(microsecond=0) + this_update = current_time - datetime.timedelta(days=1) + next_update = this_update + datetime.timedelta(days=7) + revoked_date = this_update - datetime.timedelta(days=300) + builder = builder.responder_id( + ocsp.OCSPResponderEncoding.NAME, root_cert + ).add_response( + cert, + issuer, + hashes.SHA1(), + ocsp.OCSPCertStatus.REVOKED, + this_update, + next_update, + revoked_date, + x509.ReasonFlags.key_compromise, + ) + with pytest.raises(ValueError): + builder.sign(private_key, hashes.SHA256()) + + @pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support / OCSP", + ) + def test_sign_ed25519(self, backend): + builder = ocsp.OCSPResponseBuilder() + cert, issuer = _cert_and_issuer() + private_key = ed25519.Ed25519PrivateKey.generate() + root_cert, _ = _generate_root(private_key, None) + current_time = datetime.datetime.utcnow().replace(microsecond=0) + this_update = current_time - datetime.timedelta(days=1) + next_update = this_update + datetime.timedelta(days=7) + revoked_date = this_update - datetime.timedelta(days=300) + builder = builder.responder_id( + ocsp.OCSPResponderEncoding.NAME, root_cert + ).add_response( + cert, + issuer, + hashes.SHA1(), + ocsp.OCSPCertStatus.REVOKED, + this_update, + next_update, + revoked_date, + x509.ReasonFlags.key_compromise, + ) + resp = builder.sign(private_key, None) + assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED + assert resp.revocation_time == revoked_date + assert resp.revocation_reason is x509.ReasonFlags.key_compromise + assert resp.this_update == this_update + assert resp.next_update == next_update + assert resp.signature_hash_algorithm is None + assert ( + resp.signature_algorithm_oid == x509.SignatureAlgorithmOID.ED25519 + ) + private_key.public_key().verify( + resp.signature, resp.tbs_response_bytes + ) + + @pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support / OCSP", + ) + def test_sign_ed448(self, backend): + builder = ocsp.OCSPResponseBuilder() + cert, issuer = _cert_and_issuer() + private_key = ed448.Ed448PrivateKey.generate() + root_cert, _ = _generate_root(private_key, None) + current_time = datetime.datetime.utcnow().replace(microsecond=0) + this_update = current_time - datetime.timedelta(days=1) + next_update = this_update + datetime.timedelta(days=7) + revoked_date = this_update - datetime.timedelta(days=300) + builder = builder.responder_id( + ocsp.OCSPResponderEncoding.NAME, root_cert + ).add_response( + cert, + issuer, + hashes.SHA1(), + ocsp.OCSPCertStatus.REVOKED, + this_update, + next_update, + revoked_date, + x509.ReasonFlags.key_compromise, + ) + resp = builder.sign(private_key, None) + assert resp.certificate_status == ocsp.OCSPCertStatus.REVOKED + assert resp.revocation_time == revoked_date + assert resp.revocation_reason is x509.ReasonFlags.key_compromise + assert resp.this_update == this_update + assert resp.next_update == next_update + assert resp.signature_hash_algorithm is None + assert resp.signature_algorithm_oid == x509.SignatureAlgorithmOID.ED448 + private_key.public_key().verify( + resp.signature, resp.tbs_response_bytes + ) diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index c8c863fb0a07..11c80816cff7 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # 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. @@ -5,12 +6,12 @@ from __future__ import absolute_import, division, print_function import binascii +import collections +import copy import datetime import ipaddress import os -from asn1crypto.x509 import Certificate - import pytest import pytz @@ -19,18 +20,45 @@ from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat._der import ( + BIT_STRING, + CONSTRUCTED, + CONTEXT_SPECIFIC, + DERReader, + GENERALIZED_TIME, + INTEGER, + OBJECT_IDENTIFIER, + PRINTABLE_STRING, + SEQUENCE, + SET, + UTC_TIME, +) from cryptography.hazmat.backends.interfaces import ( - DSABackend, EllipticCurveBackend, RSABackend, X509Backend + DSABackend, + EllipticCurveBackend, + RSABackend, + X509Backend, ) from cryptography.hazmat.primitives import hashes, serialization -from cryptography.hazmat.primitives.asymmetric import dsa, ec, padding, rsa +from cryptography.hazmat.primitives.asymmetric import ( + dsa, + ec, + ed25519, + ed448, + padding, + rsa, +) from cryptography.hazmat.primitives.asymmetric.utils import ( - decode_dss_signature + decode_dss_signature, ) from cryptography.x509.name import _ASN1Type from cryptography.x509.oid import ( - AuthorityInformationAccessOID, ExtendedKeyUsageOID, ExtensionOID, - NameOID, SignatureAlgorithmOID + AuthorityInformationAccessOID, + ExtendedKeyUsageOID, + ExtensionOID, + NameOID, + SignatureAlgorithmOID, + SubjectInformationAccessOID, ) from ..hazmat.primitives.fixtures_dsa import DSA_KEY_2048 @@ -57,18 +85,64 @@ def _load_cert(filename, loader, backend): cert = load_vectors_from_file( filename=filename, loader=lambda pemfile: loader(pemfile.read(), backend), - mode="rb" + mode="rb", ) return cert +ParsedCertificate = collections.namedtuple( + "ParsedCertificate", + ["not_before_tag", "not_after_tag", "issuer", "subject"], +) + + +def _parse_cert(der): + # See the Certificate structured, defined in RFC 5280. + with DERReader(der).read_single_element(SEQUENCE) as cert: + tbs_cert = cert.read_element(SEQUENCE) + # Skip outer signature algorithm + _ = cert.read_element(SEQUENCE) + # Skip signature + _ = cert.read_element(BIT_STRING) + + with tbs_cert: + # Skip version + _ = tbs_cert.read_optional_element(CONTEXT_SPECIFIC | CONSTRUCTED | 0) + # Skip serialNumber + _ = tbs_cert.read_element(INTEGER) + # Skip inner signature algorithm + _ = tbs_cert.read_element(SEQUENCE) + issuer = tbs_cert.read_element(SEQUENCE) + validity = tbs_cert.read_element(SEQUENCE) + subject = tbs_cert.read_element(SEQUENCE) + # Skip subjectPublicKeyInfo + _ = tbs_cert.read_element(SEQUENCE) + # Skip issuerUniqueID + _ = tbs_cert.read_optional_element(CONTEXT_SPECIFIC | CONSTRUCTED | 1) + # Skip subjectUniqueID + _ = tbs_cert.read_optional_element(CONTEXT_SPECIFIC | CONSTRUCTED | 2) + # Skip extensions + _ = tbs_cert.read_optional_element(CONTEXT_SPECIFIC | CONSTRUCTED | 3) + + with validity: + not_before_tag, _ = validity.read_any_element() + not_after_tag, _ = validity.read_any_element() + + return ParsedCertificate( + not_before_tag=not_before_tag, + not_after_tag=not_after_tag, + issuer=issuer, + subject=subject, + ) + + @pytest.mark.requires_backend_interface(interface=X509Backend) class TestCertificateRevocationList(object): def test_load_pem_crl(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_all_reasons.pem"), x509.load_pem_x509_crl, - backend + backend, ) assert isinstance(crl, x509.CertificateRevocationList) @@ -76,15 +150,15 @@ def test_load_pem_crl(self, backend): assert fingerprint == b"3234b0cb4c0cedf6423724b736729dcfc9e441ef" assert isinstance(crl.signature_hash_algorithm, hashes.SHA256) assert ( - crl.signature_algorithm_oid == - SignatureAlgorithmOID.RSA_WITH_SHA256 + crl.signature_algorithm_oid + == SignatureAlgorithmOID.RSA_WITH_SHA256 ) def test_load_der_crl(self, backend): crl = _load_cert( os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"), x509.load_der_x509_crl, - backend + backend, ) assert isinstance(crl, x509.CertificateRevocationList) @@ -106,48 +180,48 @@ def test_unknown_signature_algorithm(self, backend): "x509", "custom", "crl_md2_unknown_crit_entry_ext.pem" ), x509.load_pem_x509_crl, - backend + backend, ) with pytest.raises(UnsupportedAlgorithm): - crl.signature_hash_algorithm() + crl.signature_hash_algorithm() def test_issuer(self, backend): crl = _load_cert( os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"), x509.load_der_x509_crl, - backend + backend, ) assert isinstance(crl.issuer, x509.Name) assert list(crl.issuer) == [ - x509.NameAttribute(x509.OID_COUNTRY_NAME, u'US'), + x509.NameAttribute(x509.OID_COUNTRY_NAME, u"US"), x509.NameAttribute( - x509.OID_ORGANIZATION_NAME, u'Test Certificates 2011' + x509.OID_ORGANIZATION_NAME, u"Test Certificates 2011" ), - x509.NameAttribute(x509.OID_COMMON_NAME, u'Good CA') + x509.NameAttribute(x509.OID_COMMON_NAME, u"Good CA"), ] assert crl.issuer.get_attributes_for_oid(x509.OID_COMMON_NAME) == [ - x509.NameAttribute(x509.OID_COMMON_NAME, u'Good CA') + x509.NameAttribute(x509.OID_COMMON_NAME, u"Good CA") ] def test_equality(self, backend): crl1 = _load_cert( os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"), x509.load_der_x509_crl, - backend + backend, ) crl2 = _load_cert( os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"), x509.load_der_x509_crl, - backend + backend, ) crl3 = _load_cert( os.path.join("x509", "custom", "crl_all_reasons.pem"), x509.load_pem_x509_crl, - backend + backend, ) assert crl1 == crl2 @@ -158,7 +232,7 @@ def test_update_dates(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_all_reasons.pem"), x509.load_pem_x509_crl, - backend + backend, ) assert isinstance(crl.next_update, datetime.datetime) @@ -171,7 +245,7 @@ def test_revoked_cert_retrieval(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_all_reasons.pem"), x509.load_pem_x509_crl, - backend + backend, ) for r in crl: @@ -183,9 +257,10 @@ def test_revoked_cert_retrieval(self, backend): def test_get_revoked_certificate_by_serial_number(self, backend): crl = _load_cert( os.path.join( - "x509", "PKITS_data", "crls", "LongSerialNumberCACRL.crl"), + "x509", "PKITS_data", "crls", "LongSerialNumberCACRL.crl" + ), x509.load_der_x509_crl, - backend + backend, ) serial_number = 725064303890588110203033396814564464046290047507 revoked = crl.get_revoked_certificate_by_serial_number(serial_number) @@ -201,7 +276,7 @@ def test_revoked_cert_retrieval_retain_only_revoked(self, backend): revoked = _load_cert( os.path.join("x509", "custom", "crl_all_reasons.pem"), x509.load_pem_x509_crl, - backend + backend, )[11] assert revoked.revocation_date == datetime.datetime(2015, 1, 1, 0, 0) assert revoked.serial_number == 11 @@ -210,7 +285,7 @@ def test_extensions(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_ian_aia_aki.pem"), x509.load_pem_x509_crl, - backend + backend, ) crl_number = crl.extensions.get_extension_for_oid( @@ -228,40 +303,40 @@ def test_extensions(self, backend): assert crl_number.value == x509.CRLNumber(1) assert crl_number.critical is False assert aki.value == x509.AuthorityKeyIdentifier( - key_identifier=( - b'yu\xbb\x84:\xcb,\xdez\t\xbe1\x1bC\xbc\x1c*MSX' - ), + key_identifier=(b"yu\xbb\x84:\xcb,\xdez\t\xbe1\x1bC\xbc\x1c*MSX"), authority_cert_issuer=None, - authority_cert_serial_number=None + authority_cert_serial_number=None, + ) + assert aia.value == x509.AuthorityInformationAccess( + [ + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.DNSName(u"cryptography.io"), + ) + ] + ) + assert ian.value == x509.IssuerAlternativeName( + [x509.UniformResourceIdentifier(u"https://cryptography.io")] ) - assert aia.value == x509.AuthorityInformationAccess([ - x509.AccessDescription( - AuthorityInformationAccessOID.CA_ISSUERS, - x509.DNSName(u"cryptography.io") - ) - ]) - assert ian.value == x509.IssuerAlternativeName([ - x509.UniformResourceIdentifier(u"https://cryptography.io"), - ]) def test_delta_crl_indicator(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_delta_crl_indicator.pem"), x509.load_pem_x509_crl, - backend + backend, ) dci = crl.extensions.get_extension_for_oid( ExtensionOID.DELTA_CRL_INDICATOR ) assert dci.value == x509.DeltaCRLIndicator(12345678901234567890) - assert dci.critical is False + assert dci.critical is True def test_signature(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_all_reasons.pem"), x509.load_pem_x509_crl, - backend + backend, ) assert crl.signature == binascii.unhexlify( @@ -280,31 +355,36 @@ def test_tbs_certlist_bytes(self, backend): crl = _load_cert( os.path.join("x509", "PKITS_data", "crls", "GoodCACRL.crl"), x509.load_der_x509_crl, - backend + backend, ) ca_cert = _load_cert( os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), x509.load_der_x509_certificate, - backend + backend, ) ca_cert.public_key().verify( - crl.signature, crl.tbs_certlist_bytes, - padding.PKCS1v15(), crl.signature_hash_algorithm + crl.signature, + crl.tbs_certlist_bytes, + padding.PKCS1v15(), + crl.signature_hash_algorithm, ) def test_public_bytes_pem(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_empty.pem"), x509.load_pem_x509_crl, - backend + backend, ) # Encode it to PEM and load it back. - crl = x509.load_pem_x509_crl(crl.public_bytes( - encoding=serialization.Encoding.PEM, - ), backend) + crl = x509.load_pem_x509_crl( + crl.public_bytes( + encoding=serialization.Encoding.PEM, + ), + backend, + ) assert len(crl) == 0 assert crl.last_update == datetime.datetime(2015, 12, 20, 23, 44, 47) @@ -314,13 +394,16 @@ def test_public_bytes_der(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_all_reasons.pem"), x509.load_pem_x509_crl, - backend + backend, ) # Encode it to DER and load it back. - crl = x509.load_der_x509_crl(crl.public_bytes( - encoding=serialization.Encoding.DER, - ), backend) + crl = x509.load_der_x509_crl( + crl.public_bytes( + encoding=serialization.Encoding.DER, + ), + backend, + ) assert len(crl) == 12 assert crl.last_update == datetime.datetime(2015, 1, 1, 0, 0, 0) @@ -339,10 +422,11 @@ def test_public_bytes_der(self, backend): x509.load_der_x509_crl, serialization.Encoding.DER, ), - ] + ], ) - def test_public_bytes_match(self, cert_path, loader_func, encoding, - backend): + def test_public_bytes_match( + self, cert_path, loader_func, encoding, backend + ): crl_bytes = load_vectors_from_file( cert_path, lambda pemfile: pemfile.read(), mode="rb" ) @@ -354,22 +438,22 @@ def test_public_bytes_invalid_encoding(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_empty.pem"), x509.load_pem_x509_crl, - backend + backend, ) with pytest.raises(TypeError): - crl.public_bytes('NotAnEncoding') + crl.public_bytes("NotAnEncoding") def test_verify_bad(self, backend): crl = _load_cert( os.path.join("x509", "custom", "invalid_signature.pem"), x509.load_pem_x509_crl, - backend + backend, ) crt = _load_cert( os.path.join("x509", "custom", "invalid_signature.pem"), x509.load_pem_x509_certificate, - backend + backend, ) assert not crl.is_signature_valid(crt.public_key()) @@ -378,12 +462,12 @@ def test_verify_good(self, backend): crl = _load_cert( os.path.join("x509", "custom", "valid_signature.pem"), x509.load_pem_x509_crl, - backend + backend, ) crt = _load_cert( os.path.join("x509", "custom", "valid_signature.pem"), x509.load_pem_x509_certificate, - backend + backend, ) assert crl.is_signature_valid(crt.public_key()) @@ -392,7 +476,7 @@ def test_verify_argument_must_be_a_public_key(self, backend): crl = _load_cert( os.path.join("x509", "custom", "valid_signature.pem"), x509.load_pem_x509_crl, - backend + backend, ) with pytest.raises(TypeError): @@ -408,7 +492,7 @@ def test_revoked_basics(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_all_reasons.pem"), x509.load_pem_x509_crl, - backend + backend, ) for i, rev in enumerate(crl): @@ -424,14 +508,20 @@ def test_revoked_extensions(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_all_reasons.pem"), x509.load_pem_x509_crl, - backend + backend, ) exp_issuer = [ - x509.DirectoryName(x509.Name([ - x509.NameAttribute(x509.OID_COUNTRY_NAME, u"US"), - x509.NameAttribute(x509.OID_COMMON_NAME, u"cryptography.io"), - ])) + x509.DirectoryName( + x509.Name( + [ + x509.NameAttribute(x509.OID_COUNTRY_NAME, u"US"), + x509.NameAttribute( + x509.OID_COMMON_NAME, u"cryptography.io" + ), + ] + ) + ) ] # First revoked cert doesn't have extensions, test if it is handled @@ -451,16 +541,17 @@ def test_revoked_extensions(self, backend): rev1 = crl[1] assert isinstance(rev1.extensions, x509.Extensions) - reason = rev1.extensions.get_extension_for_class( - x509.CRLReason).value + reason = rev1.extensions.get_extension_for_class(x509.CRLReason).value assert reason == x509.CRLReason(x509.ReasonFlags.unspecified) issuer = rev1.extensions.get_extension_for_class( - x509.CertificateIssuer).value + x509.CertificateIssuer + ).value assert issuer == x509.CertificateIssuer(exp_issuer) date = rev1.extensions.get_extension_for_class( - x509.InvalidityDate).value + x509.InvalidityDate + ).value assert date == x509.InvalidityDate(datetime.datetime(2015, 1, 1, 0, 0)) # Check if all reason flags can be found in the CRL. @@ -480,7 +571,7 @@ def test_no_revoked_certs(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_empty.pem"), x509.load_pem_x509_crl, - backend + backend, ) assert len(crl) == 0 @@ -488,7 +579,7 @@ def test_duplicate_entry_ext(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_dup_entry_ext.pem"), x509.load_pem_x509_crl, - backend + backend, ) with pytest.raises(x509.DuplicateExtension): @@ -500,7 +591,7 @@ def test_unsupported_crit_entry_ext(self, backend): "x509", "custom", "crl_md2_unknown_crit_entry_ext.pem" ), x509.load_pem_x509_crl, - backend + backend, ) ext = crl[0].extensions.get_extension_for_oid( @@ -510,11 +601,9 @@ def test_unsupported_crit_entry_ext(self, backend): def test_unsupported_reason(self, backend): crl = _load_cert( - os.path.join( - "x509", "custom", "crl_unsupported_reason.pem" - ), + os.path.join("x509", "custom", "crl_unsupported_reason.pem"), x509.load_pem_x509_crl, - backend + backend, ) with pytest.raises(ValueError): @@ -526,7 +615,7 @@ def test_invalid_cert_issuer_ext(self, backend): "x509", "custom", "crl_inval_cert_issuer_entry_ext.pem" ), x509.load_pem_x509_crl, - backend + backend, ) with pytest.raises(ValueError): @@ -536,7 +625,7 @@ def test_indexing(self, backend): crl = _load_cert( os.path.join("x509", "custom", "crl_all_reasons.pem"), x509.load_pem_x509_crl, - backend + backend, ) with pytest.raises(IndexError): @@ -553,21 +642,27 @@ def test_get_revoked_certificate_doesnt_reorder(self, backend): private_key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) next_update = datetime.datetime(2030, 1, 1, 12, 1) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") - ]) - ).last_update( - last_update - ).next_update( - next_update + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) ) for i in [2, 500, 3, 49, 7, 1]: - revoked_cert = x509.RevokedCertificateBuilder().serial_number( - i - ).revocation_date( - datetime.datetime(2012, 1, 1, 1, 1) - ).build(backend) + revoked_cert = ( + x509.RevokedCertificateBuilder() + .serial_number(i) + .revocation_date(datetime.datetime(2012, 1, 1, 1, 1)) + .build(backend) + ) builder = builder.add_revoked_certificate(revoked_cert) crl = builder.sign(private_key, hashes.SHA256(), backend) assert crl[0].serial_number == 2 @@ -586,7 +681,7 @@ def test_load_pem_cert(self, backend): cert = _load_cert( os.path.join("x509", "custom", "post2000utctime.pem"), x509.load_pem_x509_certificate, - backend + backend, ) assert isinstance(cert, x509.Certificate) assert cert.serial_number == 11559813051657483483 @@ -597,44 +692,31 @@ def test_load_pem_cert(self, backend): cert.signature_algorithm_oid == SignatureAlgorithmOID.RSA_WITH_SHA1 ) + def test_negative_serial_number(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "negative_serial.pem"), + x509.load_pem_x509_certificate, + backend, + ) + assert cert.serial_number == -18008675309 + def test_alternate_rsa_with_sha1_oid(self, backend): cert = _load_cert( os.path.join("x509", "alternate-rsa-sha1-oid.pem"), x509.load_pem_x509_certificate, - backend + backend, ) assert isinstance(cert.signature_hash_algorithm, hashes.SHA1) assert ( - cert.signature_algorithm_oid == - SignatureAlgorithmOID._RSA_WITH_SHA1 - ) - - def test_cert_serial_number(self, backend): - cert = _load_cert( - os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), - x509.load_der_x509_certificate, - backend - ) - - with pytest.warns(utils.CryptographyDeprecationWarning): - assert cert.serial == 2 - assert cert.serial_number == 2 - - def test_cert_serial_warning(self, backend): - cert = _load_cert( - os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), - x509.load_der_x509_certificate, - backend + cert.signature_algorithm_oid + == SignatureAlgorithmOID._RSA_WITH_SHA1 ) - with pytest.warns(utils.CryptographyDeprecationWarning): - cert.serial - def test_load_der_cert(self, backend): cert = _load_cert( os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), x509.load_der_x509_certificate, - backend + backend, ) assert isinstance(cert, x509.Certificate) assert cert.serial_number == 2 @@ -646,7 +728,7 @@ def test_signature(self, backend): cert = _load_cert( os.path.join("x509", "custom", "post2000utctime.pem"), x509.load_pem_x509_certificate, - backend + backend, ) assert cert.signature == binascii.unhexlify( b"8e0f72fcbebe4755abcaf76c8ce0bae17cde4db16291638e1b1ce04a93cdb4c" @@ -665,7 +747,7 @@ def test_tbs_certificate_bytes(self, backend): cert = _load_cert( os.path.join("x509", "custom", "post2000utctime.pem"), x509.load_pem_x509_certificate, - backend + backend, ) assert cert.tbs_certificate_bytes == binascii.unhexlify( b"308202d8a003020102020900a06cb4b955f7f4db300d06092a864886f70d010" @@ -694,132 +776,126 @@ def test_tbs_certificate_bytes(self, backend): b"3040530030101ff" ) cert.public_key().verify( - cert.signature, cert.tbs_certificate_bytes, - padding.PKCS1v15(), cert.signature_hash_algorithm + cert.signature, + cert.tbs_certificate_bytes, + padding.PKCS1v15(), + cert.signature_hash_algorithm, ) def test_issuer(self, backend): cert = _load_cert( os.path.join( - "x509", "PKITS_data", "certs", - "Validpre2000UTCnotBeforeDateTest3EE.crt" + "x509", + "PKITS_data", + "certs", + "Validpre2000UTCnotBeforeDateTest3EE.crt", ), x509.load_der_x509_certificate, - backend + backend, ) issuer = cert.issuer assert isinstance(issuer, x509.Name) assert list(issuer) == [ - x509.NameAttribute(NameOID.COUNTRY_NAME, u'US'), + x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), x509.NameAttribute( - NameOID.ORGANIZATION_NAME, u'Test Certificates 2011' + NameOID.ORGANIZATION_NAME, u"Test Certificates 2011" ), - x509.NameAttribute(NameOID.COMMON_NAME, u'Good CA') + x509.NameAttribute(NameOID.COMMON_NAME, u"Good CA"), ] assert issuer.get_attributes_for_oid(NameOID.COMMON_NAME) == [ - x509.NameAttribute(NameOID.COMMON_NAME, u'Good CA') + x509.NameAttribute(NameOID.COMMON_NAME, u"Good CA") ] def test_all_issuer_name_types(self, backend): cert = _load_cert( - os.path.join( - "x509", "custom", - "all_supported_names.pem" - ), + os.path.join("x509", "custom", "all_supported_names.pem"), x509.load_pem_x509_certificate, - backend + backend, ) issuer = cert.issuer assert isinstance(issuer, x509.Name) assert list(issuer) == [ - x509.NameAttribute(NameOID.COUNTRY_NAME, u'US'), - x509.NameAttribute(NameOID.COUNTRY_NAME, u'CA'), - x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u'Texas'), - x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u'Illinois'), - x509.NameAttribute(NameOID.LOCALITY_NAME, u'Chicago'), - x509.NameAttribute(NameOID.LOCALITY_NAME, u'Austin'), - x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'Zero, LLC'), - x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'One, LLC'), - x509.NameAttribute(NameOID.COMMON_NAME, u'common name 0'), - x509.NameAttribute(NameOID.COMMON_NAME, u'common name 1'), - x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, u'OU 0'), - x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, u'OU 1'), - x509.NameAttribute(NameOID.DN_QUALIFIER, u'dnQualifier0'), - x509.NameAttribute(NameOID.DN_QUALIFIER, u'dnQualifier1'), - x509.NameAttribute(NameOID.SERIAL_NUMBER, u'123'), - x509.NameAttribute(NameOID.SERIAL_NUMBER, u'456'), - x509.NameAttribute(NameOID.TITLE, u'Title 0'), - x509.NameAttribute(NameOID.TITLE, u'Title 1'), - x509.NameAttribute(NameOID.SURNAME, u'Surname 0'), - x509.NameAttribute(NameOID.SURNAME, u'Surname 1'), - x509.NameAttribute(NameOID.GIVEN_NAME, u'Given Name 0'), - x509.NameAttribute(NameOID.GIVEN_NAME, u'Given Name 1'), - x509.NameAttribute(NameOID.PSEUDONYM, u'Incognito 0'), - x509.NameAttribute(NameOID.PSEUDONYM, u'Incognito 1'), - x509.NameAttribute(NameOID.GENERATION_QUALIFIER, u'Last Gen'), - x509.NameAttribute(NameOID.GENERATION_QUALIFIER, u'Next Gen'), - x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u'dc0'), - x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u'dc1'), - x509.NameAttribute(NameOID.EMAIL_ADDRESS, u'test0@test.local'), - x509.NameAttribute(NameOID.EMAIL_ADDRESS, u'test1@test.local'), + x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), + x509.NameAttribute(NameOID.COUNTRY_NAME, u"CA"), + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"Texas"), + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"Illinois"), + x509.NameAttribute(NameOID.LOCALITY_NAME, u"Chicago"), + x509.NameAttribute(NameOID.LOCALITY_NAME, u"Austin"), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"Zero, LLC"), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"One, LLC"), + x509.NameAttribute(NameOID.COMMON_NAME, u"common name 0"), + x509.NameAttribute(NameOID.COMMON_NAME, u"common name 1"), + x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, u"OU 0"), + x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, u"OU 1"), + x509.NameAttribute(NameOID.DN_QUALIFIER, u"dnQualifier0"), + x509.NameAttribute(NameOID.DN_QUALIFIER, u"dnQualifier1"), + x509.NameAttribute(NameOID.SERIAL_NUMBER, u"123"), + x509.NameAttribute(NameOID.SERIAL_NUMBER, u"456"), + x509.NameAttribute(NameOID.TITLE, u"Title 0"), + x509.NameAttribute(NameOID.TITLE, u"Title 1"), + x509.NameAttribute(NameOID.SURNAME, u"Surname 0"), + x509.NameAttribute(NameOID.SURNAME, u"Surname 1"), + x509.NameAttribute(NameOID.GIVEN_NAME, u"Given Name 0"), + x509.NameAttribute(NameOID.GIVEN_NAME, u"Given Name 1"), + x509.NameAttribute(NameOID.PSEUDONYM, u"Incognito 0"), + x509.NameAttribute(NameOID.PSEUDONYM, u"Incognito 1"), + x509.NameAttribute(NameOID.GENERATION_QUALIFIER, u"Last Gen"), + x509.NameAttribute(NameOID.GENERATION_QUALIFIER, u"Next Gen"), + x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u"dc0"), + x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u"dc1"), + x509.NameAttribute(NameOID.EMAIL_ADDRESS, u"test0@test.local"), + x509.NameAttribute(NameOID.EMAIL_ADDRESS, u"test1@test.local"), ] def test_subject(self, backend): cert = _load_cert( os.path.join( - "x509", "PKITS_data", "certs", - "Validpre2000UTCnotBeforeDateTest3EE.crt" + "x509", + "PKITS_data", + "certs", + "Validpre2000UTCnotBeforeDateTest3EE.crt", ), x509.load_der_x509_certificate, - backend + backend, ) subject = cert.subject assert isinstance(subject, x509.Name) assert list(subject) == [ - x509.NameAttribute(NameOID.COUNTRY_NAME, u'US'), + x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), x509.NameAttribute( - NameOID.ORGANIZATION_NAME, u'Test Certificates 2011' + NameOID.ORGANIZATION_NAME, u"Test Certificates 2011" ), x509.NameAttribute( NameOID.COMMON_NAME, - u'Valid pre2000 UTC notBefore Date EE Certificate Test3' - ) + u"Valid pre2000 UTC notBefore Date EE Certificate Test3", + ), ] assert subject.get_attributes_for_oid(NameOID.COMMON_NAME) == [ x509.NameAttribute( NameOID.COMMON_NAME, - u'Valid pre2000 UTC notBefore Date EE Certificate Test3' + u"Valid pre2000 UTC notBefore Date EE Certificate Test3", ) ] def test_unicode_name(self, backend): cert = _load_cert( - os.path.join( - "x509", "custom", - "utf8_common_name.pem" - ), + os.path.join("x509", "custom", "utf8_common_name.pem"), x509.load_pem_x509_certificate, - backend + backend, ) assert cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME) == [ - x509.NameAttribute( - NameOID.COMMON_NAME, - u'We heart UTF8!\u2122' - ) + x509.NameAttribute(NameOID.COMMON_NAME, u"We heart UTF8!\u2122") ] assert cert.issuer.get_attributes_for_oid(NameOID.COMMON_NAME) == [ - x509.NameAttribute( - NameOID.COMMON_NAME, - u'We heart UTF8!\u2122' - ) + x509.NameAttribute(NameOID.COMMON_NAME, u"We heart UTF8!\u2122") ] def test_non_ascii_dns_name(self, backend): cert = _load_cert( os.path.join("x509", "utf8-dnsname.pem"), x509.load_pem_x509_certificate, - backend + backend, ) san = cert.extensions.get_extension_for_class( x509.SubjectAlternativeName @@ -828,64 +904,65 @@ def test_non_ascii_dns_name(self, backend): names = san.get_values_for_type(x509.DNSName) assert names == [ - u'partner.biztositas.hu', u'biztositas.hu', u'*.biztositas.hu', - u'biztos\xedt\xe1s.hu', u'*.biztos\xedt\xe1s.hu', - u'xn--biztosts-fza2j.hu', u'*.xn--biztosts-fza2j.hu' + u"partner.biztositas.hu", + u"biztositas.hu", + u"*.biztositas.hu", + u"biztos\xedt\xe1s.hu", + u"*.biztos\xedt\xe1s.hu", + u"xn--biztosts-fza2j.hu", + u"*.xn--biztosts-fza2j.hu", ] def test_all_subject_name_types(self, backend): cert = _load_cert( - os.path.join( - "x509", "custom", - "all_supported_names.pem" - ), + os.path.join("x509", "custom", "all_supported_names.pem"), x509.load_pem_x509_certificate, - backend + backend, ) subject = cert.subject assert isinstance(subject, x509.Name) assert list(subject) == [ - x509.NameAttribute(NameOID.COUNTRY_NAME, u'AU'), - x509.NameAttribute(NameOID.COUNTRY_NAME, u'DE'), - x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u'California'), - x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u'New York'), - x509.NameAttribute(NameOID.LOCALITY_NAME, u'San Francisco'), - x509.NameAttribute(NameOID.LOCALITY_NAME, u'Ithaca'), - x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'Org Zero, LLC'), - x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'Org One, LLC'), - x509.NameAttribute(NameOID.COMMON_NAME, u'CN 0'), - x509.NameAttribute(NameOID.COMMON_NAME, u'CN 1'), + x509.NameAttribute(NameOID.COUNTRY_NAME, u"AU"), + x509.NameAttribute(NameOID.COUNTRY_NAME, u"DE"), + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"California"), + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u"New York"), + x509.NameAttribute(NameOID.LOCALITY_NAME, u"San Francisco"), + x509.NameAttribute(NameOID.LOCALITY_NAME, u"Ithaca"), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"Org Zero, LLC"), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"Org One, LLC"), + x509.NameAttribute(NameOID.COMMON_NAME, u"CN 0"), + x509.NameAttribute(NameOID.COMMON_NAME, u"CN 1"), x509.NameAttribute( - NameOID.ORGANIZATIONAL_UNIT_NAME, u'Engineering 0' + NameOID.ORGANIZATIONAL_UNIT_NAME, u"Engineering 0" ), x509.NameAttribute( - NameOID.ORGANIZATIONAL_UNIT_NAME, u'Engineering 1' + NameOID.ORGANIZATIONAL_UNIT_NAME, u"Engineering 1" ), - x509.NameAttribute(NameOID.DN_QUALIFIER, u'qualified0'), - x509.NameAttribute(NameOID.DN_QUALIFIER, u'qualified1'), - x509.NameAttribute(NameOID.SERIAL_NUMBER, u'789'), - x509.NameAttribute(NameOID.SERIAL_NUMBER, u'012'), - x509.NameAttribute(NameOID.TITLE, u'Title IX'), - x509.NameAttribute(NameOID.TITLE, u'Title X'), - x509.NameAttribute(NameOID.SURNAME, u'Last 0'), - x509.NameAttribute(NameOID.SURNAME, u'Last 1'), - x509.NameAttribute(NameOID.GIVEN_NAME, u'First 0'), - x509.NameAttribute(NameOID.GIVEN_NAME, u'First 1'), - x509.NameAttribute(NameOID.PSEUDONYM, u'Guy Incognito 0'), - x509.NameAttribute(NameOID.PSEUDONYM, u'Guy Incognito 1'), - x509.NameAttribute(NameOID.GENERATION_QUALIFIER, u'32X'), - x509.NameAttribute(NameOID.GENERATION_QUALIFIER, u'Dreamcast'), - x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u'dc2'), - x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u'dc3'), - x509.NameAttribute(NameOID.EMAIL_ADDRESS, u'test2@test.local'), - x509.NameAttribute(NameOID.EMAIL_ADDRESS, u'test3@test.local'), + x509.NameAttribute(NameOID.DN_QUALIFIER, u"qualified0"), + x509.NameAttribute(NameOID.DN_QUALIFIER, u"qualified1"), + x509.NameAttribute(NameOID.SERIAL_NUMBER, u"789"), + x509.NameAttribute(NameOID.SERIAL_NUMBER, u"012"), + x509.NameAttribute(NameOID.TITLE, u"Title IX"), + x509.NameAttribute(NameOID.TITLE, u"Title X"), + x509.NameAttribute(NameOID.SURNAME, u"Last 0"), + x509.NameAttribute(NameOID.SURNAME, u"Last 1"), + x509.NameAttribute(NameOID.GIVEN_NAME, u"First 0"), + x509.NameAttribute(NameOID.GIVEN_NAME, u"First 1"), + x509.NameAttribute(NameOID.PSEUDONYM, u"Guy Incognito 0"), + x509.NameAttribute(NameOID.PSEUDONYM, u"Guy Incognito 1"), + x509.NameAttribute(NameOID.GENERATION_QUALIFIER, u"32X"), + x509.NameAttribute(NameOID.GENERATION_QUALIFIER, u"Dreamcast"), + x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u"dc2"), + x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u"dc3"), + x509.NameAttribute(NameOID.EMAIL_ADDRESS, u"test2@test.local"), + x509.NameAttribute(NameOID.EMAIL_ADDRESS, u"test3@test.local"), ] def test_load_good_ca_cert(self, backend): cert = _load_cert( os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), x509.load_der_x509_certificate, - backend + backend, ) assert cert.not_valid_before == datetime.datetime(2010, 1, 1, 8, 30) @@ -900,11 +977,13 @@ def test_load_good_ca_cert(self, backend): def test_utc_pre_2000_not_before_cert(self, backend): cert = _load_cert( os.path.join( - "x509", "PKITS_data", "certs", - "Validpre2000UTCnotBeforeDateTest3EE.crt" + "x509", + "PKITS_data", + "certs", + "Validpre2000UTCnotBeforeDateTest3EE.crt", ), x509.load_der_x509_certificate, - backend + backend, ) assert cert.not_valid_before == datetime.datetime(1950, 1, 1, 12, 1) @@ -912,11 +991,13 @@ def test_utc_pre_2000_not_before_cert(self, backend): def test_pre_2000_utc_not_after_cert(self, backend): cert = _load_cert( os.path.join( - "x509", "PKITS_data", "certs", - "Invalidpre2000UTCEEnotAfterDateTest7EE.crt" + "x509", + "PKITS_data", + "certs", + "Invalidpre2000UTCEEnotAfterDateTest7EE.crt", ), x509.load_der_x509_certificate, - backend + backend, ) assert cert.not_valid_after == datetime.datetime(1999, 1, 1, 12, 1) @@ -925,7 +1006,7 @@ def test_post_2000_utc_cert(self, backend): cert = _load_cert( os.path.join("x509", "custom", "post2000utctime.pem"), x509.load_pem_x509_certificate, - backend + backend, ) assert cert.not_valid_before == datetime.datetime( 2014, 11, 26, 21, 41, 20 @@ -937,11 +1018,13 @@ def test_post_2000_utc_cert(self, backend): def test_generalized_time_not_before_cert(self, backend): cert = _load_cert( os.path.join( - "x509", "PKITS_data", "certs", - "ValidGeneralizedTimenotBeforeDateTest4EE.crt" + "x509", + "PKITS_data", + "certs", + "ValidGeneralizedTimenotBeforeDateTest4EE.crt", ), x509.load_der_x509_certificate, - backend + backend, ) assert cert.not_valid_before == datetime.datetime(2002, 1, 1, 12, 1) assert cert.not_valid_after == datetime.datetime(2030, 12, 31, 8, 30) @@ -950,24 +1033,25 @@ def test_generalized_time_not_before_cert(self, backend): def test_generalized_time_not_after_cert(self, backend): cert = _load_cert( os.path.join( - "x509", "PKITS_data", "certs", - "ValidGeneralizedTimenotAfterDateTest8EE.crt" + "x509", + "PKITS_data", + "certs", + "ValidGeneralizedTimenotAfterDateTest8EE.crt", ), x509.load_der_x509_certificate, - backend + backend, ) assert cert.not_valid_before == datetime.datetime(2010, 1, 1, 8, 30) assert cert.not_valid_after == datetime.datetime(2050, 1, 1, 12, 1) assert cert.version is x509.Version.v3 def test_invalid_version_cert(self, backend): - cert = _load_cert( - os.path.join("x509", "custom", "invalid_version.pem"), - x509.load_pem_x509_certificate, - backend - ) with pytest.raises(x509.InvalidVersion) as exc: - cert.version + _load_cert( + os.path.join("x509", "custom", "invalid_version.pem"), + x509.load_pem_x509_certificate, + backend, + ) assert exc.value.parsed_version == 7 @@ -975,12 +1059,12 @@ def test_eq(self, backend): cert = _load_cert( os.path.join("x509", "custom", "post2000utctime.pem"), x509.load_pem_x509_certificate, - backend + backend, ) cert2 = _load_cert( os.path.join("x509", "custom", "post2000utctime.pem"), x509.load_pem_x509_certificate, - backend + backend, ) assert cert == cert2 @@ -988,15 +1072,17 @@ def test_ne(self, backend): cert = _load_cert( os.path.join("x509", "custom", "post2000utctime.pem"), x509.load_pem_x509_certificate, - backend + backend, ) cert2 = _load_cert( os.path.join( - "x509", "PKITS_data", "certs", - "ValidGeneralizedTimenotAfterDateTest8EE.crt" + "x509", + "PKITS_data", + "certs", + "ValidGeneralizedTimenotAfterDateTest8EE.crt", ), x509.load_der_x509_certificate, - backend + backend, ) assert cert != cert2 assert cert != object() @@ -1005,20 +1091,22 @@ def test_hash(self, backend): cert1 = _load_cert( os.path.join("x509", "custom", "post2000utctime.pem"), x509.load_pem_x509_certificate, - backend + backend, ) cert2 = _load_cert( os.path.join("x509", "custom", "post2000utctime.pem"), x509.load_pem_x509_certificate, - backend + backend, ) cert3 = _load_cert( os.path.join( - "x509", "PKITS_data", "certs", - "ValidGeneralizedTimenotAfterDateTest8EE.crt" + "x509", + "PKITS_data", + "certs", + "ValidGeneralizedTimenotAfterDateTest8EE.crt", ), x509.load_der_x509_certificate, - backend + backend, ) assert hash(cert1) == hash(cert2) @@ -1028,7 +1116,7 @@ def test_version_1_cert(self, backend): cert = _load_cert( os.path.join("x509", "v1_cert.pem"), x509.load_pem_x509_certificate, - backend + backend, ) assert cert.version is x509.Version.v1 @@ -1044,7 +1132,7 @@ def test_unsupported_signature_hash_algorithm_cert(self, backend): cert = _load_cert( os.path.join("x509", "verisign_md2_root.pem"), x509.load_pem_x509_certificate, - backend + backend, ) with pytest.raises(UnsupportedAlgorithm): cert.signature_hash_algorithm @@ -1054,13 +1142,16 @@ def test_public_bytes_pem(self, backend): cert = _load_cert( os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), x509.load_der_x509_certificate, - backend + backend, ) # Encode it to PEM and load it back. - cert = x509.load_pem_x509_certificate(cert.public_bytes( - encoding=serialization.Encoding.PEM, - ), backend) + cert = x509.load_pem_x509_certificate( + cert.public_bytes( + encoding=serialization.Encoding.PEM, + ), + backend, + ) # We should recover what we had to start with. assert cert.not_valid_before == datetime.datetime(2010, 1, 1, 8, 30) @@ -1077,13 +1168,16 @@ def test_public_bytes_der(self, backend): cert = _load_cert( os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), x509.load_der_x509_certificate, - backend + backend, ) # Encode it to DER and load it back. - cert = x509.load_der_x509_certificate(cert.public_bytes( - encoding=serialization.Encoding.DER, - ), backend) + cert = x509.load_der_x509_certificate( + cert.public_bytes( + encoding=serialization.Encoding.DER, + ), + backend, + ) # We should recover what we had to start with. assert cert.not_valid_before == datetime.datetime(2010, 1, 1, 8, 30) @@ -1099,11 +1193,11 @@ def test_public_bytes_invalid_encoding(self, backend): cert = _load_cert( os.path.join("x509", "PKITS_data", "certs", "GoodCACert.crt"), x509.load_der_x509_certificate, - backend + backend, ) with pytest.raises(TypeError): - cert.public_bytes('NotAnEncoding') + cert.public_bytes("NotAnEncoding") @pytest.mark.parametrize( ("cert_path", "loader_func", "encoding"), @@ -1118,10 +1212,11 @@ def test_public_bytes_invalid_encoding(self, backend): x509.load_der_x509_certificate, serialization.Encoding.DER, ), - ] + ], ) - def test_public_bytes_match(self, cert_path, loader_func, encoding, - backend): + def test_public_bytes_match( + self, cert_path, loader_func, encoding, backend + ): cert_bytes = load_vectors_from_file( cert_path, lambda pemfile: pemfile.read(), mode="rb" ) @@ -1131,11 +1226,9 @@ def test_public_bytes_match(self, cert_path, loader_func, encoding, def test_certificate_repr(self, backend): cert = _load_cert( - os.path.join( - "x509", "cryptography.io.pem" - ), + os.path.join("x509", "cryptography.io.pem"), x509.load_pem_x509_certificate, - backend + backend, ) assert repr(cert) == ( " 2 bytes with pytest.raises(ValueError): - x509.NameAttribute( - NameOID.COUNTRY_NAME, - u'\U0001F37A\U0001F37A' - ) - - def test_init_empty_value(self): - with pytest.raises(ValueError): - x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'') + x509.NameAttribute(NameOID.COUNTRY_NAME, u"\U0001F37A\U0001F37A") def test_invalid_type(self): with pytest.raises(TypeError): @@ -3915,28 +4795,23 @@ def test_invalid_type(self): def test_eq(self): assert x509.NameAttribute( - x509.ObjectIdentifier('2.999.1'), u'value' - ) == x509.NameAttribute( - x509.ObjectIdentifier('2.999.1'), u'value' - ) + x509.ObjectIdentifier("2.999.1"), u"value" + ) == x509.NameAttribute(x509.ObjectIdentifier("2.999.1"), u"value") def test_ne(self): assert x509.NameAttribute( - x509.ObjectIdentifier('2.5.4.3'), u'value' - ) != x509.NameAttribute( - x509.ObjectIdentifier('2.5.4.5'), u'value' - ) + x509.ObjectIdentifier("2.5.4.3"), u"value" + ) != x509.NameAttribute(x509.ObjectIdentifier("2.5.4.5"), u"value") assert x509.NameAttribute( - x509.ObjectIdentifier('2.999.1'), u'value' - ) != x509.NameAttribute( - x509.ObjectIdentifier('2.999.1'), u'value2' + x509.ObjectIdentifier("2.999.1"), u"value" + ) != x509.NameAttribute(x509.ObjectIdentifier("2.999.1"), u"value2") + assert ( + x509.NameAttribute(x509.ObjectIdentifier("2.999.2"), u"value") + != object() ) - assert x509.NameAttribute( - x509.ObjectIdentifier('2.999.2'), u'value' - ) != object() def test_repr(self): - na = x509.NameAttribute(x509.ObjectIdentifier('2.5.4.3'), u'value') + na = x509.NameAttribute(x509.ObjectIdentifier("2.5.4.3"), u"value") if not six.PY2: assert repr(na) == ( "", + ), + ( + u"Certificación", + u"Certificación", + "", + ), + ], + ) + def test_repr(self, common_name, org_name, expected_repr): + name = x509.Name( + [ + x509.NameAttribute(NameOID.COMMON_NAME, common_name), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, org_name), + ] + ) - assert repr(name) == "" + assert repr(name) == expected_repr def test_rfc4514_string(self): - n = x509.Name([ - x509.RelativeDistinguishedName([ - x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, u'Sales'), - x509.NameAttribute(NameOID.COMMON_NAME, u'J. Smith'), - ]), - x509.RelativeDistinguishedName([ - x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u'example'), - ]), - x509.RelativeDistinguishedName([ - x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u'net'), - ]), - ]) - assert (n.rfc4514_string() == - 'OU=Sales+CN=J. Smith,DC=example,DC=net') + n = x509.Name( + [ + x509.RelativeDistinguishedName( + [x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u"net")] + ), + x509.RelativeDistinguishedName( + [x509.NameAttribute(NameOID.DOMAIN_COMPONENT, u"example")] + ), + x509.RelativeDistinguishedName( + [ + x509.NameAttribute( + NameOID.ORGANIZATIONAL_UNIT_NAME, u"Sales" + ), + x509.NameAttribute(NameOID.COMMON_NAME, u"J. Smith"), + ] + ), + ] + ) + assert n.rfc4514_string() == "OU=Sales+CN=J. Smith,DC=example,DC=net" + + def test_rfc4514_string_empty_values(self): + n = x509.Name( + [ + x509.NameAttribute(NameOID.COUNTRY_NAME, u"US"), + x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, u""), + x509.NameAttribute(NameOID.LOCALITY_NAME, u""), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"PyCA"), + x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io"), + ] + ) + assert n.rfc4514_string() == "CN=cryptography.io,O=PyCA,L=,ST=,C=US" def test_not_nameattribute(self): with pytest.raises(TypeError): @@ -4171,10 +5137,12 @@ def test_not_nameattribute(self): @pytest.mark.requires_backend_interface(interface=X509Backend) def test_bytes(self, backend): - name = x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u'cryptography.io'), - x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'PyCA'), - ]) + name = x509.Name( + [ + x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io"), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"PyCA"), + ] + ) assert name.public_bytes(backend) == binascii.unhexlify( b"30293118301606035504030c0f63727970746f6772617068792e696f310d300" b"b060355040a0c0450794341" @@ -4185,19 +5153,148 @@ def test_bmpstring_bytes(self, backend): # For this test we need an odd length string. BMPString is UCS-2 # encoded so it will always be even length and OpenSSL will error if # you pass an odd length string without encoding it properly first. - name = x509.Name([ - x509.NameAttribute( - NameOID.COMMON_NAME, - u'cryptography.io', - _ASN1Type.BMPString - ), - x509.NameAttribute(NameOID.ORGANIZATION_NAME, u'PyCA'), - ]) + name = x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, + u"cryptography.io", + _ASN1Type.BMPString, + ), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"PyCA"), + ] + ) assert name.public_bytes(backend) == binascii.unhexlify( b"30383127302506035504031e1e00630072007900700074006f00670072006100" b"7000680079002e0069006f310d300b060355040a0c0450794341" ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_universalstring_bytes(self, backend): + # UniversalString is UCS-4 + name = x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, + u"cryptography.io", + _ASN1Type.UniversalString, + ), + x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"PyCA"), + ] + ) + assert name.public_bytes(backend) == binascii.unhexlify( + b"30563145304306035504031c3c00000063000000720000007900000070000000" + b"740000006f000000670000007200000061000000700000006800000079000000" + b"2e000000690000006f310d300b060355040a0c0450794341" + ) + + +@pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support", +) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestEd25519Certificate(object): + def test_load_pem_cert(self, backend): + cert = _load_cert( + os.path.join("x509", "ed25519", "root-ed25519.pem"), + x509.load_pem_x509_certificate, + backend, + ) + # self-signed, so this will work + cert.public_key().verify(cert.signature, cert.tbs_certificate_bytes) + assert isinstance(cert, x509.Certificate) + assert cert.serial_number == 9579446940964433301 + assert cert.signature_hash_algorithm is None + assert cert.signature_algorithm_oid == SignatureAlgorithmOID.ED25519 + + def test_deepcopy(self, backend): + cert = _load_cert( + os.path.join("x509", "ed25519", "root-ed25519.pem"), + x509.load_pem_x509_certificate, + backend, + ) + assert copy.deepcopy(cert) is cert + + +@pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support", +) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestEd448Certificate(object): + def test_load_pem_cert(self, backend): + cert = _load_cert( + os.path.join("x509", "ed448", "root-ed448.pem"), + x509.load_pem_x509_certificate, + backend, + ) + # self-signed, so this will work + cert.public_key().verify(cert.signature, cert.tbs_certificate_bytes) + assert isinstance(cert, x509.Certificate) + assert cert.serial_number == 448 + assert cert.signature_hash_algorithm is None + assert cert.signature_algorithm_oid == SignatureAlgorithmOID.ED448 + + +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestSignatureRejection(object): + """Test if signing rejects DH keys properly.""" + + def load_key(self, backend): + data = load_vectors_from_file( + os.path.join("asymmetric", "DH", "dhkey.pem"), + lambda pemfile: pemfile.read(), + mode="rb", + ) + return serialization.load_pem_private_key(data, None, backend) + + def test_crt_signing_check(self, backend): + issuer_private_key = self.load_key(backend) + public_key = RSA_KEY_2048.private_key(backend).public_key() + not_valid_before = datetime.datetime(2020, 1, 1, 1, 1) + not_valid_after = datetime.datetime(2050, 12, 31, 8, 30) + builder = ( + x509.CertificateBuilder() + .serial_number(777) + .issuer_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u"US")]) + ) + .subject_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u"US")]) + ) + .public_key(public_key) + .not_valid_before(not_valid_before) + .not_valid_after(not_valid_after) + ) + + with pytest.raises(TypeError): + builder.sign(issuer_private_key, hashes.SHA256(), backend) + + def test_csr_signing_check(self, backend): + private_key = self.load_key(backend) + builder = x509.CertificateSigningRequestBuilder().subject_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u"US")]) + ) + + with pytest.raises(TypeError): + builder.sign(private_key, hashes.SHA256(), backend) + + def test_crl_signing_check(self, backend): + private_key = self.load_key(backend) + last_time = datetime.datetime.utcnow().replace(microsecond=0) + next_time = last_time + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u"CA")]) + ) + .last_update(last_time) + .next_update(next_time) + ) + + with pytest.raises(TypeError): + builder.sign(private_key, hashes.SHA256(), backend) + def test_random_serial_number(monkeypatch): sample_data = os.urandom(20) @@ -4210,7 +5307,5 @@ def notrandom(size): serial_number = x509.random_serial_number() - assert ( - serial_number == utils.int_from_bytes(sample_data, "big") >> 1 - ) + assert serial_number == utils.int_from_bytes(sample_data, "big") >> 1 assert serial_number.bit_length() < 160 diff --git a/tests/x509/test_x509_crlbuilder.py b/tests/x509/test_x509_crlbuilder.py index 5f220bcae896..922d24917979 100644 --- a/tests/x509/test_x509_crlbuilder.py +++ b/tests/x509/test_x509_crlbuilder.py @@ -12,11 +12,18 @@ from cryptography import x509 from cryptography.hazmat.backends.interfaces import ( - DSABackend, EllipticCurveBackend, RSABackend, X509Backend + DSABackend, + EllipticCurveBackend, + RSABackend, + X509Backend, ) from cryptography.hazmat.primitives import hashes -from cryptography.hazmat.primitives.asymmetric import ec -from cryptography.x509.oid import AuthorityInformationAccessOID, NameOID +from cryptography.hazmat.primitives.asymmetric import ec, ed25519, ed448 +from cryptography.x509.oid import ( + AuthorityInformationAccessOID, + NameOID, + SignatureAlgorithmOID, +) from ..hazmat.primitives.fixtures_dsa import DSA_KEY_2048 from ..hazmat.primitives.fixtures_ec import EC_KEY_SECP256R1 @@ -32,11 +39,11 @@ def test_issuer_name_invalid(self): def test_set_issuer_name_twice(self): builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u"US")]) ) with pytest.raises(ValueError): builder.issuer_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u"US")]) ) @pytest.mark.requires_backend_interface(interface=RSABackend) @@ -48,11 +55,20 @@ def test_aware_last_update(self, backend): utc_last = datetime.datetime(2012, 1, 17, 6, 43) next_time = datetime.datetime(2022, 1, 17, 6, 43) private_key = RSA_KEY_2048.private_key(backend) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") - ]) - ).last_update(last_time).next_update(next_time) + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_time) + .next_update(next_time) + ) crl = builder.sign(private_key, hashes.SHA256(), backend) assert crl.last_update == utc_last @@ -83,11 +99,20 @@ def test_aware_next_update(self, backend): utc_next = datetime.datetime(2022, 1, 17, 6, 43) last_time = datetime.datetime(2012, 1, 17, 6, 43) private_key = RSA_KEY_2048.private_key(backend) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") - ]) - ).last_update(last_time).next_update(next_time) + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_time) + .next_update(next_time) + ) crl = builder.sign(private_key, hashes.SHA256(), backend) assert crl.next_update == utc_next @@ -112,18 +137,14 @@ def test_set_next_update_twice(self): def test_last_update_after_next_update(self): builder = x509.CertificateRevocationListBuilder() - builder = builder.next_update( - datetime.datetime(2002, 1, 1, 12, 1) - ) + builder = builder.next_update(datetime.datetime(2002, 1, 1, 12, 1)) with pytest.raises(ValueError): builder.last_update(datetime.datetime(2003, 1, 1, 12, 1)) def test_next_update_after_last_update(self): builder = x509.CertificateRevocationListBuilder() - builder = builder.last_update( - datetime.datetime(2002, 1, 1, 12, 1) - ) + builder = builder.last_update(datetime.datetime(2002, 1, 1, 12, 1)) with pytest.raises(ValueError): builder.next_update(datetime.datetime(2001, 1, 1, 12, 1)) @@ -139,9 +160,7 @@ def test_add_invalid_extension(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(TypeError): - builder.add_extension( - object(), False - ) + builder.add_extension(object(), False) def test_add_invalid_revoked_certificate(self): builder = x509.CertificateRevocationListBuilder() @@ -153,10 +172,10 @@ def test_add_invalid_revoked_certificate(self): @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_issuer_name(self, backend): private_key = RSA_KEY_2048.private_key(backend) - builder = x509.CertificateRevocationListBuilder().last_update( - datetime.datetime(2002, 1, 1, 12, 1) - ).next_update( - datetime.datetime(2030, 1, 1, 12, 1) + builder = ( + x509.CertificateRevocationListBuilder() + .last_update(datetime.datetime(2002, 1, 1, 12, 1)) + .next_update(datetime.datetime(2030, 1, 1, 12, 1)) ) with pytest.raises(ValueError): @@ -166,10 +185,12 @@ def test_no_issuer_name(self, backend): @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_last_update(self, backend): private_key = RSA_KEY_2048.private_key(backend) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) - ).next_update( - datetime.datetime(2030, 1, 1, 12, 1) + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u"US")]) + ) + .next_update(datetime.datetime(2030, 1, 1, 12, 1)) ) with pytest.raises(ValueError): @@ -179,10 +200,12 @@ def test_no_last_update(self, backend): @pytest.mark.requires_backend_interface(interface=X509Backend) def test_no_next_update(self, backend): private_key = RSA_KEY_2048.private_key(backend) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) - ).last_update( - datetime.datetime(2030, 1, 1, 12, 1) + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u"US")]) + ) + .last_update(datetime.datetime(2030, 1, 1, 12, 1)) ) with pytest.raises(ValueError): @@ -194,11 +217,20 @@ def test_sign_empty_list(self, backend): private_key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) next_update = datetime.datetime(2030, 1, 1, 12, 1) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") - ]) - ).last_update(last_update).next_update(next_update) + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) + ) crl = builder.sign(private_key, hashes.SHA256(), backend) assert len(crl) == 0 @@ -214,18 +246,20 @@ def test_sign_empty_list(self, backend): b"\xc3\x9c\xf3\xfc\xd3F\x084\xbb\xceF\x7f\xa0|[\xf3\xe2\x08" b"\xcbY", None, - None + None, ), - x509.AuthorityInformationAccess([ - x509.AccessDescription( - AuthorityInformationAccessOID.CA_ISSUERS, - x509.DNSName(u"cryptography.io") - ) - ]), - x509.IssuerAlternativeName([ - x509.UniformResourceIdentifier(u"https://cryptography.io"), - ]) - ] + x509.AuthorityInformationAccess( + [ + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.DNSName(u"cryptography.io"), + ) + ] + ), + x509.IssuerAlternativeName( + [x509.UniformResourceIdentifier(u"https://cryptography.io")] + ), + ], ) @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) @@ -233,16 +267,20 @@ def test_sign_extensions(self, backend, extension): private_key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) next_update = datetime.datetime(2030, 1, 1, 12, 1) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") - ]) - ).last_update( - last_update - ).next_update( - next_update - ).add_extension( - extension, False + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) + .add_extension(extension, False) ) crl = builder.sign(private_key, hashes.SHA256(), backend) @@ -258,22 +296,25 @@ def test_sign_multiple_extensions_critical(self, backend): private_key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) next_update = datetime.datetime(2030, 1, 1, 12, 1) - ian = x509.IssuerAlternativeName([ - x509.UniformResourceIdentifier(u"https://cryptography.io"), - ]) + ian = x509.IssuerAlternativeName( + [x509.UniformResourceIdentifier(u"https://cryptography.io")] + ) crl_number = x509.CRLNumber(13) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") - ]) - ).last_update( - last_update - ).next_update( - next_update - ).add_extension( - crl_number, False - ).add_extension( - ian, True + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) + .add_extension(crl_number, False) + .add_extension(ian, True) ) crl = builder.sign(private_key, hashes.SHA256(), backend) @@ -288,22 +329,68 @@ def test_sign_multiple_extensions_critical(self, backend): assert ext2.critical is True assert ext2.value == ian + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_freshestcrl_extension(self, backend): + private_key = RSA_KEY_2048.private_key(backend) + last_update = datetime.datetime(2002, 1, 1, 12, 1) + next_update = datetime.datetime(2030, 1, 1, 12, 1) + freshest = x509.FreshestCRL( + [ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://d.om/delta")], + None, + None, + None, + ) + ] + ) + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) + .add_extension(freshest, False) + ) + + crl = builder.sign(private_key, hashes.SHA256(), backend) + assert len(crl) == 0 + assert len(crl.extensions) == 1 + ext1 = crl.extensions.get_extension_for_class(x509.FreshestCRL) + assert ext1.critical is False + assert isinstance(ext1.value[0], x509.DistributionPoint) + uri = ext1.value[0].full_name[0] + assert isinstance(uri, x509.UniformResourceIdentifier) + assert uri.value == u"http://d.om/delta" + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_add_unsupported_extension(self, backend): private_key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) next_update = datetime.datetime(2030, 1, 1, 12, 1) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") - ]) - ).last_update( - last_update - ).next_update( - next_update - ).add_extension( - x509.OCSPNoCheck(), False + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) + .add_extension(x509.OCSPNoCheck(), False) ) with pytest.raises(NotImplementedError): builder.sign(private_key, hashes.SHA256(), backend) @@ -314,14 +401,19 @@ def test_sign_rsa_key_too_small(self, backend): private_key = RSA_KEY_512.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) next_update = datetime.datetime(2030, 1, 1, 12, 1) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") - ]) - ).last_update( - last_update - ).next_update( - next_update + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) ) with pytest.raises(ValueError): @@ -333,19 +425,82 @@ def test_sign_with_invalid_hash(self, backend): private_key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) next_update = datetime.datetime(2030, 1, 1, 12, 1) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") - ]) - ).last_update( - last_update - ).next_update( - next_update + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) ) with pytest.raises(TypeError): builder.sign(private_key, object(), backend) + @pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support", + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_sign_with_invalid_hash_ed25519(self, backend): + private_key = ed25519.Ed25519PrivateKey.generate() + last_update = datetime.datetime(2002, 1, 1, 12, 1) + next_update = datetime.datetime(2030, 1, 1, 12, 1) + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) + ) + + with pytest.raises(ValueError): + builder.sign(private_key, object(), backend) + with pytest.raises(ValueError): + builder.sign(private_key, hashes.SHA256(), backend) + + @pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support", + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_sign_with_invalid_hash_ed448(self, backend): + private_key = ed448.Ed448PrivateKey.generate() + last_update = datetime.datetime(2002, 1, 1, 12, 1) + next_update = datetime.datetime(2030, 1, 1, 12, 1) + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) + ) + + with pytest.raises(ValueError): + builder.sign(private_key, object(), backend) + with pytest.raises(ValueError): + builder.sign(private_key, hashes.SHA256(), backend) + @pytest.mark.requires_backend_interface(interface=DSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_sign_dsa_key(self, backend): @@ -353,36 +508,42 @@ def test_sign_dsa_key(self, backend): invalidity_date = x509.InvalidityDate( datetime.datetime(2002, 1, 1, 0, 0) ) - ian = x509.IssuerAlternativeName([ - x509.UniformResourceIdentifier(u"https://cryptography.io"), - ]) - revoked_cert0 = x509.RevokedCertificateBuilder().serial_number( - 2 - ).revocation_date( - datetime.datetime(2012, 1, 1, 1, 1) - ).add_extension( - invalidity_date, False - ).build(backend) + ian = x509.IssuerAlternativeName( + [x509.UniformResourceIdentifier(u"https://cryptography.io")] + ) + revoked_cert0 = ( + x509.RevokedCertificateBuilder() + .serial_number(2) + .revocation_date(datetime.datetime(2012, 1, 1, 1, 1)) + .add_extension(invalidity_date, False) + .build(backend) + ) last_update = datetime.datetime(2002, 1, 1, 12, 1) next_update = datetime.datetime(2030, 1, 1, 12, 1) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") - ]) - ).last_update( - last_update - ).next_update( - next_update - ).add_revoked_certificate( - revoked_cert0 - ).add_extension( - ian, False + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) + .add_revoked_certificate(revoked_cert0) + .add_extension(ian, False) ) crl = builder.sign(private_key, hashes.SHA256(), backend) - assert crl.extensions.get_extension_for_class( - x509.IssuerAlternativeName - ).value == ian + assert ( + crl.extensions.get_extension_for_class( + x509.IssuerAlternativeName + ).value + == ian + ) assert crl[0].serial_number == revoked_cert0.serial_number assert crl[0].revocation_date == revoked_cert0.revocation_date assert len(crl[0].extensions) == 1 @@ -398,36 +559,152 @@ def test_sign_ec_key(self, backend): invalidity_date = x509.InvalidityDate( datetime.datetime(2002, 1, 1, 0, 0) ) - ian = x509.IssuerAlternativeName([ - x509.UniformResourceIdentifier(u"https://cryptography.io"), - ]) - revoked_cert0 = x509.RevokedCertificateBuilder().serial_number( - 2 - ).revocation_date( - datetime.datetime(2012, 1, 1, 1, 1) - ).add_extension( - invalidity_date, False - ).build(backend) + ian = x509.IssuerAlternativeName( + [x509.UniformResourceIdentifier(u"https://cryptography.io")] + ) + revoked_cert0 = ( + x509.RevokedCertificateBuilder() + .serial_number(2) + .revocation_date(datetime.datetime(2012, 1, 1, 1, 1)) + .add_extension(invalidity_date, False) + .build(backend) + ) last_update = datetime.datetime(2002, 1, 1, 12, 1) next_update = datetime.datetime(2030, 1, 1, 12, 1) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") - ]) - ).last_update( - last_update - ).next_update( - next_update - ).add_revoked_certificate( - revoked_cert0 - ).add_extension( - ian, False + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) + .add_revoked_certificate(revoked_cert0) + .add_extension(ian, False) ) crl = builder.sign(private_key, hashes.SHA256(), backend) - assert crl.extensions.get_extension_for_class( - x509.IssuerAlternativeName - ).value == ian + assert ( + crl.extensions.get_extension_for_class( + x509.IssuerAlternativeName + ).value + == ian + ) + assert crl[0].serial_number == revoked_cert0.serial_number + assert crl[0].revocation_date == revoked_cert0.revocation_date + assert len(crl[0].extensions) == 1 + ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate) + assert ext.critical is False + assert ext.value == invalidity_date + + @pytest.mark.supported( + only_if=lambda backend: backend.ed25519_supported(), + skip_message="Requires OpenSSL with Ed25519 support", + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_sign_ed25519_key(self, backend): + private_key = ed25519.Ed25519PrivateKey.generate() + invalidity_date = x509.InvalidityDate( + datetime.datetime(2002, 1, 1, 0, 0) + ) + ian = x509.IssuerAlternativeName( + [x509.UniformResourceIdentifier(u"https://cryptography.io")] + ) + revoked_cert0 = ( + x509.RevokedCertificateBuilder() + .serial_number(2) + .revocation_date(datetime.datetime(2012, 1, 1, 1, 1)) + .add_extension(invalidity_date, False) + .build(backend) + ) + last_update = datetime.datetime(2002, 1, 1, 12, 1) + next_update = datetime.datetime(2030, 1, 1, 12, 1) + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) + .add_revoked_certificate(revoked_cert0) + .add_extension(ian, False) + ) + + crl = builder.sign(private_key, None, backend) + assert crl.signature_hash_algorithm is None + assert crl.signature_algorithm_oid == SignatureAlgorithmOID.ED25519 + assert ( + crl.extensions.get_extension_for_class( + x509.IssuerAlternativeName + ).value + == ian + ) + assert crl[0].serial_number == revoked_cert0.serial_number + assert crl[0].revocation_date == revoked_cert0.revocation_date + assert len(crl[0].extensions) == 1 + ext = crl[0].extensions.get_extension_for_class(x509.InvalidityDate) + assert ext.critical is False + assert ext.value == invalidity_date + + @pytest.mark.supported( + only_if=lambda backend: backend.ed448_supported(), + skip_message="Requires OpenSSL with Ed448 support", + ) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_sign_ed448_key(self, backend): + private_key = ed448.Ed448PrivateKey.generate() + invalidity_date = x509.InvalidityDate( + datetime.datetime(2002, 1, 1, 0, 0) + ) + ian = x509.IssuerAlternativeName( + [x509.UniformResourceIdentifier(u"https://cryptography.io")] + ) + revoked_cert0 = ( + x509.RevokedCertificateBuilder() + .serial_number(2) + .revocation_date(datetime.datetime(2012, 1, 1, 1, 1)) + .add_extension(invalidity_date, False) + .build(backend) + ) + last_update = datetime.datetime(2002, 1, 1, 12, 1) + next_update = datetime.datetime(2030, 1, 1, 12, 1) + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) + .add_revoked_certificate(revoked_cert0) + .add_extension(ian, False) + ) + + crl = builder.sign(private_key, None, backend) + assert crl.signature_hash_algorithm is None + assert crl.signature_algorithm_oid == SignatureAlgorithmOID.ED448 + assert ( + crl.extensions.get_extension_for_class( + x509.IssuerAlternativeName + ).value + == ian + ) assert crl[0].serial_number == revoked_cert0.serial_number assert crl[0].revocation_date == revoked_cert0.revocation_date assert len(crl[0].extensions) == 1 @@ -441,11 +718,20 @@ def test_dsa_key_sign_md5(self, backend): private_key = DSA_KEY_2048.private_key(backend) last_time = datetime.datetime(2012, 1, 16, 22, 43) next_time = datetime.datetime(2022, 1, 17, 6, 43) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") - ]) - ).last_update(last_time).next_update(next_time) + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_time) + .next_update(next_time) + ) with pytest.raises(ValueError): builder.sign(private_key, hashes.MD5(), backend) @@ -457,11 +743,20 @@ def test_ec_key_sign_md5(self, backend): private_key = EC_KEY_SECP256R1.private_key(backend) last_time = datetime.datetime(2012, 1, 16, 22, 43) next_time = datetime.datetime(2022, 1, 17, 6, 43) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") - ]) - ).last_update(last_time).next_update(next_time) + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_time) + .next_update(next_time) + ) with pytest.raises(ValueError): builder.sign(private_key, hashes.MD5(), backend) @@ -475,30 +770,34 @@ def test_sign_with_revoked_certificates(self, backend): invalidity_date = x509.InvalidityDate( datetime.datetime(2002, 1, 1, 0, 0) ) - revoked_cert0 = x509.RevokedCertificateBuilder().serial_number( - 38 - ).revocation_date( - datetime.datetime(2011, 1, 1, 1, 1) - ).build(backend) - revoked_cert1 = x509.RevokedCertificateBuilder().serial_number( - 2 - ).revocation_date( - datetime.datetime(2012, 1, 1, 1, 1) - ).add_extension( - invalidity_date, False - ).build(backend) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") - ]) - ).last_update( - last_update - ).next_update( - next_update - ).add_revoked_certificate( - revoked_cert0 - ).add_revoked_certificate( - revoked_cert1 + revoked_cert0 = ( + x509.RevokedCertificateBuilder() + .serial_number(38) + .revocation_date(datetime.datetime(2011, 1, 1, 1, 1)) + .build(backend) + ) + revoked_cert1 = ( + x509.RevokedCertificateBuilder() + .serial_number(2) + .revocation_date(datetime.datetime(2012, 1, 1, 1, 1)) + .add_extension(invalidity_date, False) + .build(backend) + ) + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) + .add_revoked_certificate(revoked_cert0) + .add_revoked_certificate(revoked_cert1) ) crl = builder.sign(private_key, hashes.SHA256(), backend) diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index 6de105fad272..2cd216fb688a 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -9,53 +9,52 @@ import ipaddress import os +import pretend + import pytest import six -from cryptography import utils, x509 +from cryptography import x509 from cryptography.hazmat.backends.interfaces import ( - DSABackend, EllipticCurveBackend, RSABackend, X509Backend + DSABackend, + EllipticCurveBackend, + RSABackend, + X509Backend, ) from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec from cryptography.x509 import DNSName, NameConstraints, SubjectAlternativeName -from cryptography.x509.general_name import _lazy_import_idna +from cryptography.x509.extensions import _key_identifier_from_public_key from cryptography.x509.oid import ( - AuthorityInformationAccessOID, ExtendedKeyUsageOID, ExtensionOID, - NameOID, ObjectIdentifier + AuthorityInformationAccessOID, + ExtendedKeyUsageOID, + ExtensionOID, + NameOID, + ObjectIdentifier, + SubjectInformationAccessOID, + _OID_NAMES, ) from .test_x509 import _load_cert from ..hazmat.primitives.fixtures_rsa import RSA_KEY_2048 from ..hazmat.primitives.test_ec import _skip_curve_unsupported +from ..utils import load_vectors_from_file def _make_certbuilder(private_key): - name = x509.Name( - [x509.NameAttribute(NameOID.COMMON_NAME, u'example.org')]) + name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u"example.org")]) return ( x509.CertificateBuilder() - .subject_name(name) - .issuer_name(name) - .public_key(private_key.public_key()) - .serial_number(777) - .not_valid_before(datetime.datetime(1999, 1, 1)) - .not_valid_after(datetime.datetime(2020, 1, 1)) + .subject_name(name) + .issuer_name(name) + .public_key(private_key.public_key()) + .serial_number(777) + .not_valid_before(datetime.datetime(1999, 1, 1)) + .not_valid_after(datetime.datetime(2020, 1, 1)) ) -def test_lazy_idna_import(): - try: - __import__("idna") - pytest.skip("idna is installed") - except ImportError: - pass - - with pytest.raises(ImportError): - _lazy_import_idna() - - class TestExtension(object): def test_not_an_oid(self): bc = x509.BasicConstraints(ca=False, path_length=None) @@ -77,26 +76,16 @@ def test_repr(self): ) def test_eq(self): - ext1 = x509.Extension( - x509.ObjectIdentifier('1.2.3.4'), False, 'value' - ) - ext2 = x509.Extension( - x509.ObjectIdentifier('1.2.3.4'), False, 'value' - ) + ext1 = x509.Extension(x509.ObjectIdentifier("1.2.3.4"), False, "value") + ext2 = x509.Extension(x509.ObjectIdentifier("1.2.3.4"), False, "value") assert ext1 == ext2 def test_ne(self): - ext1 = x509.Extension( - x509.ObjectIdentifier('1.2.3.4'), False, 'value' - ) - ext2 = x509.Extension( - x509.ObjectIdentifier('1.2.3.5'), False, 'value' - ) - ext3 = x509.Extension( - x509.ObjectIdentifier('1.2.3.4'), True, 'value' - ) + ext1 = x509.Extension(x509.ObjectIdentifier("1.2.3.4"), False, "value") + ext2 = x509.Extension(x509.ObjectIdentifier("1.2.3.5"), False, "value") + ext3 = x509.Extension(x509.ObjectIdentifier("1.2.3.4"), True, "value") ext4 = x509.Extension( - x509.ObjectIdentifier('1.2.3.4'), False, 'value4' + x509.ObjectIdentifier("1.2.3.4"), False, "value4" ) assert ext1 != ext2 assert ext1 != ext3 @@ -107,17 +96,17 @@ def test_hash(self): ext1 = x509.Extension( ExtensionOID.BASIC_CONSTRAINTS, False, - x509.BasicConstraints(ca=False, path_length=None) + x509.BasicConstraints(ca=False, path_length=None), ) ext2 = x509.Extension( ExtensionOID.BASIC_CONSTRAINTS, False, - x509.BasicConstraints(ca=False, path_length=None) + x509.BasicConstraints(ca=False, path_length=None), ) ext3 = x509.Extension( ExtensionOID.BASIC_CONSTRAINTS, False, - x509.BasicConstraints(ca=True, path_length=None) + x509.BasicConstraints(ca=True, path_length=None), ) assert hash(ext1) == hash(ext2) assert hash(ext1) != hash(ext3) @@ -146,10 +135,12 @@ def test_eq(self): def test_ne(self): ext1 = x509.TLSFeature([x509.TLSFeatureType.status_request]) ext2 = x509.TLSFeature([x509.TLSFeatureType.status_request_v2]) - ext3 = x509.TLSFeature([ - x509.TLSFeatureType.status_request, - x509.TLSFeatureType.status_request_v2 - ]) + ext3 = x509.TLSFeature( + [ + x509.TLSFeatureType.status_request, + x509.TLSFeatureType.status_request_v2, + ] + ) assert ext1 != ext2 assert ext1 != ext3 assert ext1 != object() @@ -157,10 +148,12 @@ def test_ne(self): def test_hash(self): ext1 = x509.TLSFeature([x509.TLSFeatureType.status_request]) ext2 = x509.TLSFeature([x509.TLSFeatureType.status_request]) - ext3 = x509.TLSFeature([ - x509.TLSFeatureType.status_request, - x509.TLSFeatureType.status_request_v2 - ]) + ext3 = x509.TLSFeature( + [ + x509.TLSFeatureType.status_request, + x509.TLSFeatureType.status_request_v2, + ] + ) assert hash(ext1) == hash(ext2) assert hash(ext1) != hash(ext3) @@ -178,10 +171,12 @@ def test_iter(self): assert list(ext2) == ext2_features def test_indexing(self): - ext = x509.TLSFeature([ - x509.TLSFeatureType.status_request, - x509.TLSFeatureType.status_request_v2, - ]) + ext = x509.TLSFeature( + [ + x509.TLSFeatureType.status_request, + x509.TLSFeatureType.status_request_v2, + ] + ) assert ext[-1] == ext[1] assert ext[0] == x509.TLSFeatureType.status_request @@ -245,10 +240,9 @@ def test_hash(self): class TestCertificateIssuer(object): def test_iter_names(self): - ci = x509.CertificateIssuer([ - x509.DNSName(u"cryptography.io"), - x509.DNSName(u"crypto.local"), - ]) + ci = x509.CertificateIssuer( + [x509.DNSName(u"cryptography.io"), x509.DNSName(u"crypto.local")] + ) assert len(ci) == 2 assert list(ci) == [ x509.DNSName(u"cryptography.io"), @@ -256,13 +250,15 @@ def test_iter_names(self): ] def test_indexing(self): - ci = x509.CertificateIssuer([ - x509.DNSName(u"cryptography.io"), - x509.DNSName(u"crypto.local"), - x509.DNSName(u"another.local"), - x509.RFC822Name(u"email@another.local"), - x509.UniformResourceIdentifier(u"http://another.local"), - ]) + ci = x509.CertificateIssuer( + [ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + x509.DNSName(u"another.local"), + x509.RFC822Name(u"email@another.local"), + x509.UniformResourceIdentifier(u"http://another.local"), + ] + ) assert ci[-1] == ci[4] assert ci[2:6:2] == [ci[2], ci[4]] @@ -291,9 +287,7 @@ def test_repr(self): ) def test_get_values_for_type(self): - ci = x509.CertificateIssuer( - [x509.DNSName(u"cryptography.io")] - ) + ci = x509.CertificateIssuer([x509.DNSName(u"cryptography.io")]) names = ci.get_values_for_type(x509.DNSName) assert names == [u"cryptography.io"] @@ -333,9 +327,7 @@ def test_hash(self): def test_repr(self): reason1 = x509.CRLReason(x509.ReasonFlags.unspecified) - assert repr(reason1) == ( - "" - ) + assert repr(reason1) == ("") class TestDeltaCRLIndicator(object): @@ -356,9 +348,7 @@ def test_ne(self): def test_repr(self): delta1 = x509.DeltaCRLIndicator(2) - assert repr(delta1) == ( - "" - ) + assert repr(delta1) == ("") def test_hash(self): delta1 = x509.DeltaCRLIndicator(1) @@ -541,11 +531,11 @@ def test_repr(self): def test_eq(self): pi = x509.PolicyInformation( x509.ObjectIdentifier("1.2.3"), - [u"string", x509.UserNotice(None, u"hi")] + [u"string", x509.UserNotice(None, u"hi")], ) pi2 = x509.PolicyInformation( x509.ObjectIdentifier("1.2.3"), - [u"string", x509.UserNotice(None, u"hi")] + [u"string", x509.UserNotice(None, u"hi")], ) assert pi == pi2 @@ -566,11 +556,11 @@ def test_ne(self): def test_hash(self): pi = x509.PolicyInformation( x509.ObjectIdentifier("1.2.3"), - [u"string", x509.UserNotice(None, u"hi")] + [u"string", x509.UserNotice(None, u"hi")], ) pi2 = x509.PolicyInformation( x509.ObjectIdentifier("1.2.3"), - [u"string", x509.UserNotice(None, u"hi")] + [u"string", x509.UserNotice(None, u"hi")], ) pi3 = x509.PolicyInformation(x509.ObjectIdentifier("1.2.3"), None) assert hash(pi) == hash(pi2) @@ -658,10 +648,9 @@ def test_long_oid(self, backend): cert = _load_cert( os.path.join("x509", "bigoid.pem"), x509.load_pem_x509_certificate, - backend + backend, ) - ext = cert.extensions.get_extension_for_class( - x509.CertificatePolicies) + ext = cert.extensions.get_extension_for_class(x509.CertificatePolicies) oid = x509.ObjectIdentifier( "1.3.6.1.4.1.311.21.8.8950086.10656446.2706058" @@ -694,19 +683,21 @@ def test_cps_uri_policy_qualifier(self, backend): cert = _load_cert( os.path.join("x509", "custom", "cp_cps_uri.pem"), x509.load_pem_x509_certificate, - backend + backend, ) cp = cert.extensions.get_extension_for_oid( ExtensionOID.CERTIFICATE_POLICIES ).value - assert cp == x509.CertificatePolicies([ - x509.PolicyInformation( - x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), - [u"http://other.com/cps"] - ) - ]) + assert cp == x509.CertificatePolicies( + [ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [u"http://other.com/cps"], + ) + ] + ) def test_user_notice_with_notice_reference(self, backend): cert = _load_cert( @@ -714,26 +705,28 @@ def test_user_notice_with_notice_reference(self, backend): "x509", "custom", "cp_user_notice_with_notice_reference.pem" ), x509.load_pem_x509_certificate, - backend + backend, ) cp = cert.extensions.get_extension_for_oid( ExtensionOID.CERTIFICATE_POLICIES ).value - assert cp == x509.CertificatePolicies([ - x509.PolicyInformation( - x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), - [ - u"http://example.com/cps", - u"http://other.com/cps", - x509.UserNotice( - x509.NoticeReference(u"my org", [1, 2, 3, 4]), - u"thing" - ) - ] - ) - ]) + assert cp == x509.CertificatePolicies( + [ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [ + u"http://example.com/cps", + u"http://other.com/cps", + x509.UserNotice( + x509.NoticeReference(u"my org", [1, 2, 3, 4]), + u"thing", + ), + ], + ) + ] + ) def test_user_notice_with_explicit_text(self, backend): cert = _load_cert( @@ -741,19 +734,21 @@ def test_user_notice_with_explicit_text(self, backend): "x509", "custom", "cp_user_notice_with_explicit_text.pem" ), x509.load_pem_x509_certificate, - backend + backend, ) cp = cert.extensions.get_extension_for_oid( ExtensionOID.CERTIFICATE_POLICIES ).value - assert cp == x509.CertificatePolicies([ - x509.PolicyInformation( - x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), - [x509.UserNotice(None, u"thing")] - ) - ]) + assert cp == x509.CertificatePolicies( + [ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [x509.UserNotice(None, u"thing")], + ) + ] + ) def test_user_notice_no_explicit_text(self, backend): cert = _load_cert( @@ -761,24 +756,25 @@ def test_user_notice_no_explicit_text(self, backend): "x509", "custom", "cp_user_notice_no_explicit_text.pem" ), x509.load_pem_x509_certificate, - backend + backend, ) cp = cert.extensions.get_extension_for_oid( ExtensionOID.CERTIFICATE_POLICIES ).value - assert cp == x509.CertificatePolicies([ - x509.PolicyInformation( - x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), - [ - x509.UserNotice( - x509.NoticeReference(u"my org", [1, 2, 3, 4]), - None - ) - ] - ) - ]) + assert cp == x509.CertificatePolicies( + [ + x509.PolicyInformation( + x509.ObjectIdentifier("2.16.840.1.12345.1.2.3.4.1"), + [ + x509.UserNotice( + x509.NoticeReference(u"my org", [1, 2, 3, 4]), None + ) + ], + ) + ] + ) class TestKeyUsage(object): @@ -793,7 +789,7 @@ def test_key_agreement_false_encipher_decipher_true(self): key_cert_sign=False, crl_sign=False, encipher_only=True, - decipher_only=False + decipher_only=False, ) with pytest.raises(ValueError): @@ -806,7 +802,7 @@ def test_key_agreement_false_encipher_decipher_true(self): key_cert_sign=False, crl_sign=False, encipher_only=True, - decipher_only=True + decipher_only=True, ) with pytest.raises(ValueError): @@ -819,7 +815,7 @@ def test_key_agreement_false_encipher_decipher_true(self): key_cert_sign=False, crl_sign=False, encipher_only=False, - decipher_only=True + decipher_only=True, ) def test_properties_key_agreement_true(self): @@ -832,7 +828,7 @@ def test_properties_key_agreement_true(self): key_cert_sign=True, crl_sign=False, encipher_only=False, - decipher_only=False + decipher_only=False, ) assert ku.digital_signature is True assert ku.content_commitment is True @@ -852,7 +848,7 @@ def test_key_agreement_true_properties(self): key_cert_sign=False, crl_sign=False, encipher_only=False, - decipher_only=True + decipher_only=True, ) assert ku.key_agreement is True assert ku.encipher_only is False @@ -868,7 +864,7 @@ def test_key_agreement_false_properties(self): key_cert_sign=False, crl_sign=False, encipher_only=False, - decipher_only=False + decipher_only=False, ) assert ku.key_agreement is False with pytest.raises(ValueError): @@ -887,13 +883,13 @@ def test_repr_key_agreement_false(self): key_cert_sign=True, crl_sign=False, encipher_only=False, - decipher_only=False + decipher_only=False, ) assert repr(ku) == ( "" + "ey_cert_sign=True, crl_sign=False, encipher_only=False, decipher_" + "only=False)>" ) def test_repr_key_agreement_true(self): @@ -906,7 +902,7 @@ def test_repr_key_agreement_true(self): key_cert_sign=True, crl_sign=False, encipher_only=False, - decipher_only=False + decipher_only=False, ) assert repr(ku) == ( ", critical=False, value=)>" + "igest=b'\\t#\\x84\\x93\"0I\\x8b\\xc9\\x80\\xaa\\x80\\x98Eoo" + "\\xf7\\xff:\\xc9')>)>" ) else: assert repr(ext) == ( ", critical=False, value=)>" + "igest='\\t#\\x84\\x93\"0I\\x8b\\xc9\\x80\\xaa\\x80\\x98Eoo" + "\\xf7\\xff:\\xc9')>)>" ) def test_eq(self): @@ -1070,16 +1066,16 @@ def test_authority_cert_issuer_not_generalname(self): def test_authority_cert_serial_number_not_integer(self): dirname = x509.DirectoryName( - x509.Name([ - x509.NameAttribute( - x509.ObjectIdentifier('2.999.1'), - u'value1' - ), - x509.NameAttribute( - x509.ObjectIdentifier('2.999.2'), - u'value2' - ), - ]) + x509.Name( + [ + x509.NameAttribute( + x509.ObjectIdentifier("2.999.1"), u"value1" + ), + x509.NameAttribute( + x509.ObjectIdentifier("2.999.2"), u"value2" + ), + ] + ) ) with pytest.raises(TypeError): x509.AuthorityKeyIdentifier(b"identifier", [dirname], "notanint") @@ -1090,16 +1086,16 @@ def test_authority_issuer_none_serial_not_none(self): def test_authority_issuer_not_none_serial_none(self): dirname = x509.DirectoryName( - x509.Name([ - x509.NameAttribute( - x509.ObjectIdentifier('2.999.1'), - u'value1' - ), - x509.NameAttribute( - x509.ObjectIdentifier('2.999.2'), - u'value2' - ), - ]) + x509.Name( + [ + x509.NameAttribute( + x509.ObjectIdentifier("2.999.1"), u"value1" + ), + x509.NameAttribute( + x509.ObjectIdentifier("2.999.2"), u"value2" + ), + ] + ) ) with pytest.raises(ValueError): x509.AuthorityKeyIdentifier(b"identifier", [dirname], None) @@ -1120,7 +1116,7 @@ def test_authority_cert_serial_zero(self): def test_iter_input(self): dirnames = [ x509.DirectoryName( - x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'myCN')]) + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u"myCN")]) ) ] aki = x509.AuthorityKeyIdentifier(b"digest", iter(dirnames), 1234) @@ -1128,7 +1124,7 @@ def test_iter_input(self): def test_repr(self): dirname = x509.DirectoryName( - x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'myCN')]) + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u"myCN")]) ) aki = x509.AuthorityKeyIdentifier(b"digest", [dirname], 1234) @@ -1147,21 +1143,21 @@ def test_repr(self): def test_eq(self): dirname = x509.DirectoryName( - x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'myCN')]) + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u"myCN")]) ) aki = x509.AuthorityKeyIdentifier(b"digest", [dirname], 1234) dirname2 = x509.DirectoryName( - x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'myCN')]) + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u"myCN")]) ) aki2 = x509.AuthorityKeyIdentifier(b"digest", [dirname2], 1234) assert aki == aki2 def test_ne(self): dirname = x509.DirectoryName( - x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'myCN')]) + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u"myCN")]) ) dirname5 = x509.DirectoryName( - x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'aCN')]) + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u"aCN")]) ) aki = x509.AuthorityKeyIdentifier(b"digest", [dirname], 1234) aki2 = x509.AuthorityKeyIdentifier(b"diges", [dirname], 1234) @@ -1176,7 +1172,7 @@ def test_ne(self): def test_hash(self): dirname = x509.DirectoryName( - x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u'myCN')]) + x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, u"myCN")]) ) aki1 = x509.AuthorityKeyIdentifier(b"digest", [dirname], 1234) aki2 = x509.AuthorityKeyIdentifier(b"digest", [dirname], 1234) @@ -1207,9 +1203,7 @@ def test_path_length_negative(self): def test_repr(self): na = x509.BasicConstraints(ca=True, path_length=None) - assert repr(na) == ( - "" - ) + assert repr(na) == ("") def test_hash(self): na = x509.BasicConstraints(ca=True, path_length=None) @@ -1238,14 +1232,16 @@ def test_not_all_oids(self): x509.ExtendedKeyUsage(["notoid"]) def test_iter_len(self): - eku = x509.ExtendedKeyUsage([ - x509.ObjectIdentifier("1.3.6.1.5.5.7.3.1"), - x509.ObjectIdentifier("1.3.6.1.5.5.7.3.2"), - ]) + eku = x509.ExtendedKeyUsage( + [ + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.1"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.2"), + ] + ) assert len(eku) == 2 assert list(eku) == [ ExtendedKeyUsageOID.SERVER_AUTH, - ExtendedKeyUsageOID.CLIENT_AUTH + ExtendedKeyUsageOID.CLIENT_AUTH, ] def test_iter_input(self): @@ -1257,10 +1253,12 @@ def test_iter_input(self): assert list(aia) == usages def test_repr(self): - eku = x509.ExtendedKeyUsage([ - x509.ObjectIdentifier("1.3.6.1.5.5.7.3.1"), - x509.ObjectIdentifier("1.3.6.1.5.5.7.3.2"), - ]) + eku = x509.ExtendedKeyUsage( + [ + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.1"), + x509.ObjectIdentifier("1.3.6.1.5.5.7.3.2"), + ] + ) assert repr(eku) == ( ", )>" def test_eq(self): - name = x509.Name([ - x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1') - ]) - name2 = x509.Name([ - x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1') - ]) + name = x509.Name( + [x509.NameAttribute(x509.ObjectIdentifier("2.999.1"), u"value1")] + ) + name2 = x509.Name( + [x509.NameAttribute(x509.ObjectIdentifier("2.999.1"), u"value1")] + ) gn = x509.DirectoryName(name) gn2 = x509.DirectoryName(name2) assert gn == gn2 def test_ne(self): - name = x509.Name([ - x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1') - ]) - name2 = x509.Name([ - x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2') - ]) + name = x509.Name( + [x509.NameAttribute(x509.ObjectIdentifier("2.999.1"), u"value1")] + ) + name2 = x509.Name( + [x509.NameAttribute(x509.ObjectIdentifier("2.999.2"), u"value2")] + ) gn = x509.DirectoryName(name) gn2 = x509.DirectoryName(name2) assert gn != gn2 assert gn != object() def test_hash(self): - name = x509.Name([ - x509.NameAttribute(x509.ObjectIdentifier('2.999.1'), u'value1') - ]) - name2 = x509.Name([ - x509.NameAttribute(x509.ObjectIdentifier('2.999.2'), u'value2') - ]) + name = x509.Name( + [x509.NameAttribute(x509.ObjectIdentifier("2.999.1"), u"value1")] + ) + name2 = x509.Name( + [x509.NameAttribute(x509.ObjectIdentifier("2.999.2"), u"value2")] + ) gn = x509.DirectoryName(name) gn2 = x509.DirectoryName(name) gn3 = x509.DirectoryName(name2) @@ -1790,15 +1837,9 @@ def test_single_label(self): gn = x509.RFC822Name(u"administrator") assert gn.value == u"administrator" - def test_idna(self): - pytest.importorskip("idna") - with pytest.warns(utils.DeprecatedIn21): - gn = x509.RFC822Name(u"email@em\xe5\xefl.com") - - assert gn.value == u"email@xn--eml-vla4c.com" - - gn2 = x509.RFC822Name(u"email@xn--eml-vla4c.com") - assert gn2.value == u"email@xn--eml-vla4c.com" + def test_non_a_label(self): + with pytest.raises(ValueError): + x509.RFC822Name(u"email@em\xe5\xefl.com") def test_hash(self): g1 = x509.RFC822Name(u"email@host.com") @@ -1830,41 +1871,16 @@ def test_with_port(self): gn = x509.UniformResourceIdentifier(u"singlelabel:443/test") assert gn.value == u"singlelabel:443/test" - def test_idna_no_port(self): - pytest.importorskip("idna") - with pytest.warns(utils.DeprecatedIn21): - gn = x509.UniformResourceIdentifier( + def test_non_a_label(self): + with pytest.raises(ValueError): + x509.UniformResourceIdentifier( u"http://\u043f\u044b\u043a\u0430.cryptography" ) - assert gn.value == u"http://xn--80ato2c.cryptography" - - def test_idna_with_port(self): - pytest.importorskip("idna") - with pytest.warns(utils.DeprecatedIn21): - gn = x509.UniformResourceIdentifier( - u"gopher://\u043f\u044b\u043a\u0430.cryptography:70/some/path" - ) - - assert gn.value == ( - u"gopher://xn--80ato2c.cryptography:70/some/path" - ) - def test_empty_hostname(self): gn = x509.UniformResourceIdentifier(u"ldap:///some-nonsense") assert gn.value == "ldap:///some-nonsense" - def test_query_and_fragment(self): - pytest.importorskip("idna") - with pytest.warns(utils.DeprecatedIn21): - gn = x509.UniformResourceIdentifier( - u"ldap://\u043f\u044b\u043a\u0430.cryptography:90/path?query=" - u"true#somedata" - ) - assert gn.value == ( - u"ldap://xn--80ato2c.cryptography:90/path?query=true#somedata" - ) - def test_hash(self): g1 = x509.UniformResourceIdentifier(u"http://host.com") g2 = x509.UniformResourceIdentifier(u"http://host.com") @@ -1876,13 +1892,9 @@ def test_hash(self): def test_repr(self): gn = x509.UniformResourceIdentifier(u"string") if not six.PY2: - assert repr(gn) == ( - "" - ) + assert repr(gn) == ("") else: - assert repr(gn) == ( - "" - ) + assert repr(gn) == ("") class TestRegisteredID(object): @@ -2017,17 +2029,14 @@ def test_hash(self): class TestGeneralNames(object): def test_get_values_for_type(self): - gns = x509.GeneralNames( - [x509.DNSName(u"cryptography.io")] - ) + gns = x509.GeneralNames([x509.DNSName(u"cryptography.io")]) names = gns.get_values_for_type(x509.DNSName) assert names == [u"cryptography.io"] def test_iter_names(self): - gns = x509.GeneralNames([ - x509.DNSName(u"cryptography.io"), - x509.DNSName(u"crypto.local"), - ]) + gns = x509.GeneralNames( + [x509.DNSName(u"cryptography.io"), x509.DNSName(u"crypto.local")] + ) assert len(gns) == 2 assert list(gns) == [ x509.DNSName(u"cryptography.io"), @@ -2043,28 +2052,24 @@ def test_iter_input(self): assert list(gns) == names def test_indexing(self): - gn = x509.GeneralNames([ - x509.DNSName(u"cryptography.io"), - x509.DNSName(u"crypto.local"), - x509.DNSName(u"another.local"), - x509.RFC822Name(u"email@another.local"), - x509.UniformResourceIdentifier(u"http://another.local"), - ]) + gn = x509.GeneralNames( + [ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + x509.DNSName(u"another.local"), + x509.RFC822Name(u"email@another.local"), + x509.UniformResourceIdentifier(u"http://another.local"), + ] + ) assert gn[-1] == gn[4] assert gn[2:6:2] == [gn[2], gn[4]] def test_invalid_general_names(self): with pytest.raises(TypeError): - x509.GeneralNames( - [x509.DNSName(u"cryptography.io"), "invalid"] - ) + x509.GeneralNames([x509.DNSName(u"cryptography.io"), "invalid"]) def test_repr(self): - gns = x509.GeneralNames( - [ - x509.DNSName(u"cryptography.io") - ] - ) + gns = x509.GeneralNames([x509.DNSName(u"cryptography.io")]) if not six.PY2: assert repr(gns) == ( "])>" @@ -2075,21 +2080,13 @@ def test_repr(self): ) def test_eq(self): - gns = x509.GeneralNames( - [x509.DNSName(u"cryptography.io")] - ) - gns2 = x509.GeneralNames( - [x509.DNSName(u"cryptography.io")] - ) + gns = x509.GeneralNames([x509.DNSName(u"cryptography.io")]) + gns2 = x509.GeneralNames([x509.DNSName(u"cryptography.io")]) assert gns == gns2 def test_ne(self): - gns = x509.GeneralNames( - [x509.DNSName(u"cryptography.io")] - ) - gns2 = x509.GeneralNames( - [x509.RFC822Name(u"admin@cryptography.io")] - ) + gns = x509.GeneralNames([x509.DNSName(u"cryptography.io")]) + gns2 = x509.GeneralNames([x509.RFC822Name(u"admin@cryptography.io")]) assert gns != gns2 assert gns != object() @@ -2103,17 +2100,14 @@ def test_hash(self): class TestIssuerAlternativeName(object): def test_get_values_for_type(self): - san = x509.IssuerAlternativeName( - [x509.DNSName(u"cryptography.io")] - ) + san = x509.IssuerAlternativeName([x509.DNSName(u"cryptography.io")]) names = san.get_values_for_type(x509.DNSName) assert names == [u"cryptography.io"] def test_iter_names(self): - san = x509.IssuerAlternativeName([ - x509.DNSName(u"cryptography.io"), - x509.DNSName(u"crypto.local"), - ]) + san = x509.IssuerAlternativeName( + [x509.DNSName(u"cryptography.io"), x509.DNSName(u"crypto.local")] + ) assert len(san) == 2 assert list(san) == [ x509.DNSName(u"cryptography.io"), @@ -2121,13 +2115,15 @@ def test_iter_names(self): ] def test_indexing(self): - ian = x509.IssuerAlternativeName([ - x509.DNSName(u"cryptography.io"), - x509.DNSName(u"crypto.local"), - x509.DNSName(u"another.local"), - x509.RFC822Name(u"email@another.local"), - x509.UniformResourceIdentifier(u"http://another.local"), - ]) + ian = x509.IssuerAlternativeName( + [ + x509.DNSName(u"cryptography.io"), + x509.DNSName(u"crypto.local"), + x509.DNSName(u"another.local"), + x509.RFC822Name(u"email@another.local"), + x509.UniformResourceIdentifier(u"http://another.local"), + ] + ) assert ian[-1] == ian[4] assert ian[2:6:2] == [ian[2], ian[4]] @@ -2138,11 +2134,7 @@ def test_invalid_general_names(self): ) def test_repr(self): - san = x509.IssuerAlternativeName( - [ - x509.DNSName(u"cryptography.io") - ] - ) + san = x509.IssuerAlternativeName([x509.DNSName(u"cryptography.io")]) if not six.PY2: assert repr(san) == ( "', u'email ', - u'email ', u'myemail:' + u"email", + u"email ", + u"email ", + u"email ", + u"myemail:", ] def test_other_name(self, backend): cert = _load_cert( - os.path.join( - "x509", "custom", "san_other_name.pem" - ), + os.path.join("x509", "custom", "san_other_name.pem"), x509.load_pem_x509_certificate, - backend + backend, ) ext = cert.extensions.get_extension_for_oid( @@ -2594,8 +2553,9 @@ def test_other_name(self, backend): assert ext is not None assert ext.critical is False - expected = x509.OtherName(x509.ObjectIdentifier("1.2.3.4"), - b'\x16\x0bHello World') + expected = x509.OtherName( + x509.ObjectIdentifier("1.2.3.4"), b"\x16\x0bHello World" + ) assert len(ext.value) == 1 assert list(ext.value)[0] == expected @@ -2603,12 +2563,16 @@ def test_other_name(self, backend): assert othernames == [expected] def test_certbuilder(self, backend): - sans = [u'*.example.org', u'*.xn--4ca7aey.example.com', - u'foobar.example.net'] + sans = [ + u"*.example.org", + u"*.xn--4ca7aey.example.com", + u"foobar.example.net", + ] private_key = RSA_KEY_2048.private_key(backend) builder = _make_certbuilder(private_key) builder = builder.add_extension( - SubjectAlternativeName(list(map(DNSName, sans))), True) + SubjectAlternativeName(list(map(DNSName, sans))), True + ) cert = builder.sign(private_key, hashes.SHA1(), backend) result = [ @@ -2625,11 +2589,9 @@ def test_certbuilder(self, backend): class TestExtendedKeyUsageExtension(object): def test_eku(self, backend): cert = _load_cert( - os.path.join( - "x509", "custom", "extended_key_usage.pem" - ), + os.path.join("x509", "custom", "extended_key_usage.pem"), x509.load_pem_x509_certificate, - backend + backend, ) ext = cert.extensions.get_extension_for_oid( ExtensionOID.EXTENDED_KEY_USAGE @@ -2663,14 +2625,14 @@ def test_invalid_access_location(self): def test_valid_nonstandard_method(self): ad = x509.AccessDescription( ObjectIdentifier("2.999.1"), - x509.UniformResourceIdentifier(u"http://example.com") + x509.UniformResourceIdentifier(u"http://example.com"), ) assert ad is not None def test_repr(self): ad = x509.AccessDescription( AuthorityInformationAccessOID.OCSP, - x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + x509.UniformResourceIdentifier(u"http://ocsp.domain.com"), ) if not six.PY2: assert repr(ad) == ( @@ -2688,26 +2650,26 @@ def test_repr(self): def test_eq(self): ad = x509.AccessDescription( AuthorityInformationAccessOID.OCSP, - x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + x509.UniformResourceIdentifier(u"http://ocsp.domain.com"), ) ad2 = x509.AccessDescription( AuthorityInformationAccessOID.OCSP, - x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + x509.UniformResourceIdentifier(u"http://ocsp.domain.com"), ) assert ad == ad2 def test_ne(self): ad = x509.AccessDescription( AuthorityInformationAccessOID.OCSP, - x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + x509.UniformResourceIdentifier(u"http://ocsp.domain.com"), ) ad2 = x509.AccessDescription( AuthorityInformationAccessOID.CA_ISSUERS, - x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + x509.UniformResourceIdentifier(u"http://ocsp.domain.com"), ) ad3 = x509.AccessDescription( AuthorityInformationAccessOID.OCSP, - x509.UniformResourceIdentifier(u"http://notthesame") + x509.UniformResourceIdentifier(u"http://notthesame"), ) assert ad != ad2 assert ad != ad3 @@ -2716,15 +2678,15 @@ def test_ne(self): def test_hash(self): ad = x509.AccessDescription( AuthorityInformationAccessOID.OCSP, - x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + x509.UniformResourceIdentifier(u"http://ocsp.domain.com"), ) ad2 = x509.AccessDescription( AuthorityInformationAccessOID.OCSP, - x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + x509.UniformResourceIdentifier(u"http://ocsp.domain.com"), ) ad3 = x509.AccessDescription( AuthorityInformationAccessOID.CA_ISSUERS, - x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + x509.UniformResourceIdentifier(u"http://ocsp.domain.com"), ) assert hash(ad) == hash(ad2) assert hash(ad) != hash(ad3) @@ -2779,7 +2741,7 @@ def test_inhibit_policy_mapping(self, backend): cert = _load_cert( os.path.join("x509", "department-of-state-root.pem"), x509.load_pem_x509_certificate, - backend + backend, ) ext = cert.extensions.get_extension_for_oid( ExtensionOID.POLICY_CONSTRAINTS, @@ -2787,21 +2749,23 @@ def test_inhibit_policy_mapping(self, backend): assert ext.critical is True assert ext.value == x509.PolicyConstraints( - require_explicit_policy=None, inhibit_policy_mapping=0, + require_explicit_policy=None, + inhibit_policy_mapping=0, ) def test_require_explicit_policy(self, backend): cert = _load_cert( os.path.join("x509", "custom", "policy_constraints_explicit.pem"), x509.load_pem_x509_certificate, - backend + backend, ) ext = cert.extensions.get_extension_for_oid( ExtensionOID.POLICY_CONSTRAINTS ) assert ext.critical is True assert ext.value == x509.PolicyConstraints( - require_explicit_policy=1, inhibit_policy_mapping=None, + require_explicit_policy=1, + inhibit_policy_mapping=None, ) @@ -2811,49 +2775,57 @@ def test_invalid_descriptions(self): x509.AuthorityInformationAccess(["notanAccessDescription"]) def test_iter_len(self): - aia = x509.AuthorityInformationAccess([ - x509.AccessDescription( - AuthorityInformationAccessOID.OCSP, - x509.UniformResourceIdentifier(u"http://ocsp.domain.com") - ), - x509.AccessDescription( - AuthorityInformationAccessOID.CA_ISSUERS, - x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") - ) - ]) + aia = x509.AuthorityInformationAccess( + [ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com"), + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier( + u"http://domain.com/ca.crt" + ), + ), + ] + ) assert len(aia) == 2 assert list(aia) == [ x509.AccessDescription( AuthorityInformationAccessOID.OCSP, - x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + x509.UniformResourceIdentifier(u"http://ocsp.domain.com"), ), x509.AccessDescription( AuthorityInformationAccessOID.CA_ISSUERS, - x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") - ) + x509.UniformResourceIdentifier(u"http://domain.com/ca.crt"), + ), ] def test_iter_input(self): desc = [ x509.AccessDescription( AuthorityInformationAccessOID.OCSP, - x509.UniformResourceIdentifier(u"http://ocsp.domain.com") + x509.UniformResourceIdentifier(u"http://ocsp.domain.com"), ) ] aia = x509.AuthorityInformationAccess(iter(desc)) assert list(aia) == desc def test_repr(self): - aia = x509.AuthorityInformationAccess([ - x509.AccessDescription( - AuthorityInformationAccessOID.OCSP, - x509.UniformResourceIdentifier(u"http://ocsp.domain.com") - ), - x509.AccessDescription( - AuthorityInformationAccessOID.CA_ISSUERS, - x509.UniformResourceIdentifier(u"http://domain.com/ca.crt") - ) - ]) + aia = x509.AuthorityInformationAccess( + [ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com"), + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier( + u"http://domain.com/ca.crt" + ), + ), + ] + ) if not six.PY2: assert repr(aia) == ( ", access_location=)>])>" + ) + else: + assert repr(sia) == ( + ", access_location=)>])>" + ) + + def test_eq(self): + sia = x509.SubjectInformationAccess( + [ + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca.domain.com"), + ), + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca2.domain.com"), + ), + ] + ) + sia2 = x509.SubjectInformationAccess( + [ + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca.domain.com"), + ), + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca2.domain.com"), + ), + ] + ) + assert sia == sia2 + + def test_ne(self): + sia = x509.SubjectInformationAccess( + [ + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca.domain.com"), + ), + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca2.domain.com"), + ), + ] + ) + sia2 = x509.SubjectInformationAccess( + [ + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca.domain.com"), + ), + ] + ) + + assert sia != sia2 + assert sia != object() + + def test_indexing(self): + sia = x509.SubjectInformationAccess( + [ + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca.domain.com"), + ), + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca2.domain.com"), + ), + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca3.domain.com"), + ), + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca4.domain.com"), + ), + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca5.domain.com"), + ), + ] + ) + assert sia[-1] == sia[4] + assert sia[2:6:2] == [sia[2], sia[4]] + + def test_hash(self): + sia = x509.SubjectInformationAccess( + [ + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca.domain.com"), + ), + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca2.domain.com"), + ), + ] + ) + sia2 = x509.SubjectInformationAccess( + [ + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca.domain.com"), + ), + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca2.domain.com"), + ), + ] + ) + sia3 = x509.SubjectInformationAccess( + [ + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca.domain.com"), + ), + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"http://ca3.domain.com"), + ), + ] + ) + assert hash(sia) == hash(sia2) + assert hash(sia) != hash(sia3) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestSubjectInformationAccessExtension(object): + def test_sia(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "sia.pem"), + x509.load_pem_x509_certificate, + backend, + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.SUBJECT_INFORMATION_ACCESS + ) assert ext is not None assert ext.critical is False - assert ext.value == x509.AuthorityInformationAccess([ - x509.AccessDescription( - AuthorityInformationAccessOID.OCSP, - x509.UniformResourceIdentifier(u"http://ocsp.domain.com") - ), - x509.AccessDescription( - AuthorityInformationAccessOID.OCSP, - x509.UniformResourceIdentifier(u"http://ocsp2.domain.com") - ), - x509.AccessDescription( - AuthorityInformationAccessOID.CA_ISSUERS, - x509.DirectoryName(x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"myCN"), - x509.NameAttribute(NameOID.ORGANIZATION_NAME, - u"some Org"), - ])) - ), - ]) + assert ext.value == x509.SubjectInformationAccess( + [ + x509.AccessDescription( + SubjectInformationAccessOID.CA_REPOSITORY, + x509.UniformResourceIdentifier(u"https://my.ca.issuer/"), + ), + x509.AccessDescription( + x509.ObjectIdentifier("2.999.7"), + x509.UniformResourceIdentifier( + u"gopher://info-mac-archive" + ), + ), + ] + ) + + +@pytest.mark.requires_backend_interface(interface=RSABackend) +@pytest.mark.requires_backend_interface(interface=X509Backend) +class TestAuthorityInformationAccessExtension(object): + def test_aia_ocsp_ca_issuers(self, backend): + cert = _load_cert( + os.path.join("x509", "cryptography.io.pem"), + x509.load_pem_x509_certificate, + backend, + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.AUTHORITY_INFORMATION_ACCESS + ) + assert ext is not None + assert ext.critical is False + + assert ext.value == x509.AuthorityInformationAccess( + [ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://gv.symcd.com"), + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.UniformResourceIdentifier( + u"http://gv.symcb.com/gv.crt" + ), + ), + ] + ) + + def test_aia_multiple_ocsp_ca_issuers(self, backend): + cert = _load_cert( + os.path.join("x509", "custom", "aia_ocsp_ca_issuers.pem"), + x509.load_pem_x509_certificate, + backend, + ) + ext = cert.extensions.get_extension_for_oid( + ExtensionOID.AUTHORITY_INFORMATION_ACCESS + ) + assert ext is not None + assert ext.critical is False + + assert ext.value == x509.AuthorityInformationAccess( + [ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com"), + ), + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp2.domain.com"), + ), + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.DirectoryName( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"myCN" + ), + x509.NameAttribute( + NameOID.ORGANIZATION_NAME, u"some Org" + ), + ] + ) + ), + ), + ] + ) def test_aia_ocsp_only(self, backend): cert = _load_cert( os.path.join("x509", "custom", "aia_ocsp.pem"), x509.load_pem_x509_certificate, - backend + backend, ) ext = cert.extensions.get_extension_for_oid( ExtensionOID.AUTHORITY_INFORMATION_ACCESS @@ -3049,18 +3280,20 @@ def test_aia_ocsp_only(self, backend): assert ext is not None assert ext.critical is False - assert ext.value == x509.AuthorityInformationAccess([ - x509.AccessDescription( - AuthorityInformationAccessOID.OCSP, - x509.UniformResourceIdentifier(u"http://ocsp.domain.com") - ), - ]) + assert ext.value == x509.AuthorityInformationAccess( + [ + x509.AccessDescription( + AuthorityInformationAccessOID.OCSP, + x509.UniformResourceIdentifier(u"http://ocsp.domain.com"), + ), + ] + ) def test_aia_ca_issuers_only(self, backend): cert = _load_cert( os.path.join("x509", "custom", "aia_ca_issuers.pem"), x509.load_pem_x509_certificate, - backend + backend, ) ext = cert.extensions.get_extension_for_oid( ExtensionOID.AUTHORITY_INFORMATION_ACCESS @@ -3068,16 +3301,25 @@ def test_aia_ca_issuers_only(self, backend): assert ext is not None assert ext.critical is False - assert ext.value == x509.AuthorityInformationAccess([ - x509.AccessDescription( - AuthorityInformationAccessOID.CA_ISSUERS, - x509.DirectoryName(x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"myCN"), - x509.NameAttribute(NameOID.ORGANIZATION_NAME, - u"some Org"), - ])) - ), - ]) + assert ext.value == x509.AuthorityInformationAccess( + [ + x509.AccessDescription( + AuthorityInformationAccessOID.CA_ISSUERS, + x509.DirectoryName( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"myCN" + ), + x509.NameAttribute( + NameOID.ORGANIZATION_NAME, u"some Org" + ), + ] + ) + ), + ), + ] + ) @pytest.mark.requires_backend_interface(interface=RSABackend) @@ -3085,11 +3327,9 @@ def test_aia_ca_issuers_only(self, backend): class TestAuthorityKeyIdentifierExtension(object): def test_aki_keyid(self, backend): cert = _load_cert( - os.path.join( - "x509", "cryptography.io.pem" - ), + os.path.join("x509", "cryptography.io.pem"), x509.load_pem_x509_certificate, - backend + backend, ) ext = cert.extensions.get_extension_for_oid( ExtensionOID.AUTHORITY_KEY_IDENTIFIER @@ -3105,11 +3345,9 @@ def test_aki_keyid(self, backend): def test_aki_all_fields(self, backend): cert = _load_cert( - os.path.join( - "x509", "custom", "authority_key_identifier.pem" - ), + os.path.join("x509", "custom", "authority_key_identifier.pem"), x509.load_pem_x509_certificate, - backend + backend, ) ext = cert.extensions.get_extension_for_oid( ExtensionOID.AUTHORITY_KEY_IDENTIFIER @@ -3122,14 +3360,14 @@ def test_aki_all_fields(self, backend): ) assert ext.value.authority_cert_issuer == [ x509.DirectoryName( - x509.Name([ - x509.NameAttribute( - NameOID.ORGANIZATION_NAME, u"PyCA" - ), - x509.NameAttribute( - NameOID.COMMON_NAME, u"cryptography.io" - ) - ]) + x509.Name( + [ + x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"PyCA"), + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io" + ), + ] + ) ) ] assert ext.value.authority_cert_serial_number == 3 @@ -3140,7 +3378,7 @@ def test_aki_no_keyid(self, backend): "x509", "custom", "authority_key_identifier_no_keyid.pem" ), x509.load_pem_x509_certificate, - backend + backend, ) ext = cert.extensions.get_extension_for_oid( ExtensionOID.AUTHORITY_KEY_IDENTIFIER @@ -3151,14 +3389,14 @@ def test_aki_no_keyid(self, backend): assert ext.value.key_identifier is None assert ext.value.authority_cert_issuer == [ x509.DirectoryName( - x509.Name([ - x509.NameAttribute( - NameOID.ORGANIZATION_NAME, u"PyCA" - ), - x509.NameAttribute( - NameOID.COMMON_NAME, u"cryptography.io" - ) - ]) + x509.Name( + [ + x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"PyCA"), + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io" + ), + ] + ) ) ] assert ext.value.authority_cert_serial_number == 3 @@ -3167,12 +3405,12 @@ def test_from_certificate(self, backend): issuer_cert = _load_cert( os.path.join("x509", "rapidssl_sha256_ca_g3.pem"), x509.load_pem_x509_certificate, - backend + backend, ) cert = _load_cert( os.path.join("x509", "cryptography.io.pem"), x509.load_pem_x509_certificate, - backend + backend, ) ext = cert.extensions.get_extension_for_oid( ExtensionOID.AUTHORITY_KEY_IDENTIFIER @@ -3186,21 +3424,21 @@ def test_from_issuer_subject_key_identifier(self, backend): issuer_cert = _load_cert( os.path.join("x509", "rapidssl_sha256_ca_g3.pem"), x509.load_pem_x509_certificate, - backend + backend, ) cert = _load_cert( os.path.join("x509", "cryptography.io.pem"), x509.load_pem_x509_certificate, - backend + backend, ) ext = cert.extensions.get_extension_for_oid( ExtensionOID.AUTHORITY_KEY_IDENTIFIER ) - ski = issuer_cert.extensions.get_extension_for_class( + ski_ext = issuer_cert.extensions.get_extension_for_class( x509.SubjectKeyIdentifier ) aki = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier( - ski + ski_ext.value ) assert ext.value == aki @@ -3212,7 +3450,7 @@ def test_ipaddress_wrong_type(self): permitted_subtrees=[ x509.IPAddress(ipaddress.IPv4Address(u"127.0.0.1")) ], - excluded_subtrees=None + excluded_subtrees=None, ) with pytest.raises(TypeError): @@ -3220,15 +3458,14 @@ def test_ipaddress_wrong_type(self): permitted_subtrees=None, excluded_subtrees=[ x509.IPAddress(ipaddress.IPv4Address(u"127.0.0.1")) - ] + ], ) def test_ipaddress_allowed_type(self): permitted = [x509.IPAddress(ipaddress.IPv4Network(u"192.168.0.0/29"))] excluded = [x509.IPAddress(ipaddress.IPv4Network(u"10.10.0.0/24"))] nc = x509.NameConstraints( - permitted_subtrees=permitted, - excluded_subtrees=excluded + permitted_subtrees=permitted, excluded_subtrees=excluded ) assert nc.permitted_subtrees == permitted assert nc.excluded_subtrees == excluded @@ -3270,8 +3507,7 @@ def test_iter_input(self): def test_repr(self): permitted = [x509.DNSName(u"name.local"), x509.DNSName(u"name2.local")] nc = x509.NameConstraints( - permitted_subtrees=permitted, - excluded_subtrees=None + permitted_subtrees=permitted, excluded_subtrees=None ) if not six.PY2: assert repr(nc) == ( @@ -3289,26 +3525,26 @@ def test_repr(self): def test_eq(self): nc = x509.NameConstraints( permitted_subtrees=[x509.DNSName(u"name.local")], - excluded_subtrees=[x509.DNSName(u"name2.local")] + excluded_subtrees=[x509.DNSName(u"name2.local")], ) nc2 = x509.NameConstraints( permitted_subtrees=[x509.DNSName(u"name.local")], - excluded_subtrees=[x509.DNSName(u"name2.local")] + excluded_subtrees=[x509.DNSName(u"name2.local")], ) assert nc == nc2 def test_ne(self): nc = x509.NameConstraints( permitted_subtrees=[x509.DNSName(u"name.local")], - excluded_subtrees=[x509.DNSName(u"name2.local")] + excluded_subtrees=[x509.DNSName(u"name2.local")], ) nc2 = x509.NameConstraints( permitted_subtrees=[x509.DNSName(u"name.local")], - excluded_subtrees=None + excluded_subtrees=None, ) nc3 = x509.NameConstraints( permitted_subtrees=None, - excluded_subtrees=[x509.DNSName(u"name2.local")] + excluded_subtrees=[x509.DNSName(u"name2.local")], ) assert nc != nc2 @@ -3318,19 +3554,19 @@ def test_ne(self): def test_hash(self): nc = x509.NameConstraints( permitted_subtrees=[x509.DNSName(u"name.local")], - excluded_subtrees=[x509.DNSName(u"name2.local")] + excluded_subtrees=[x509.DNSName(u"name2.local")], ) nc2 = x509.NameConstraints( permitted_subtrees=[x509.DNSName(u"name.local")], - excluded_subtrees=[x509.DNSName(u"name2.local")] + excluded_subtrees=[x509.DNSName(u"name2.local")], ) nc3 = x509.NameConstraints( permitted_subtrees=[x509.DNSName(u"name.local")], - excluded_subtrees=None + excluded_subtrees=None, ) nc4 = x509.NameConstraints( permitted_subtrees=None, - excluded_subtrees=[x509.DNSName(u"name.local")] + excluded_subtrees=[x509.DNSName(u"name.local")], ) assert hash(nc) == hash(nc2) assert hash(nc) != hash(nc3) @@ -3342,51 +3578,43 @@ def test_hash(self): class TestNameConstraintsExtension(object): def test_permitted_excluded(self, backend): cert = _load_cert( - os.path.join( - "x509", "custom", "nc_permitted_excluded_2.pem" - ), + os.path.join("x509", "custom", "nc_permitted_excluded_2.pem"), x509.load_pem_x509_certificate, - backend + backend, ) nc = cert.extensions.get_extension_for_oid( ExtensionOID.NAME_CONSTRAINTS ).value assert nc == x509.NameConstraints( - permitted_subtrees=[ - x509.DNSName(u"zombo.local"), - ], + permitted_subtrees=[x509.DNSName(u"zombo.local")], excluded_subtrees=[ - x509.DirectoryName(x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"zombo") - ])) - ] + x509.DirectoryName( + x509.Name( + [x509.NameAttribute(NameOID.COMMON_NAME, u"zombo")] + ) + ) + ], ) def test_permitted(self, backend): cert = _load_cert( - os.path.join( - "x509", "custom", "nc_permitted_2.pem" - ), + os.path.join("x509", "custom", "nc_permitted_2.pem"), x509.load_pem_x509_certificate, - backend + backend, ) nc = cert.extensions.get_extension_for_oid( ExtensionOID.NAME_CONSTRAINTS ).value assert nc == x509.NameConstraints( - permitted_subtrees=[ - x509.DNSName(u"zombo.local"), - ], - excluded_subtrees=None + permitted_subtrees=[x509.DNSName(u"zombo.local")], + excluded_subtrees=None, ) def test_permitted_with_leading_period(self, backend): cert = _load_cert( - os.path.join( - "x509", "custom", "nc_permitted.pem" - ), + os.path.join("x509", "custom", "nc_permitted.pem"), x509.load_pem_x509_certificate, - backend + backend, ) nc = cert.extensions.get_extension_for_oid( ExtensionOID.NAME_CONSTRAINTS @@ -3394,18 +3622,16 @@ def test_permitted_with_leading_period(self, backend): assert nc == x509.NameConstraints( permitted_subtrees=[ x509.DNSName(u".cryptography.io"), - x509.UniformResourceIdentifier(u"ftp://cryptography.test") + x509.UniformResourceIdentifier(u"ftp://cryptography.test"), ], - excluded_subtrees=None + excluded_subtrees=None, ) def test_excluded_with_leading_period(self, backend): cert = _load_cert( - os.path.join( - "x509", "custom", "nc_excluded.pem" - ), + os.path.join("x509", "custom", "nc_excluded.pem"), x509.load_pem_x509_certificate, - backend + backend, ) nc = cert.extensions.get_extension_for_oid( ExtensionOID.NAME_CONSTRAINTS @@ -3414,17 +3640,15 @@ def test_excluded_with_leading_period(self, backend): permitted_subtrees=None, excluded_subtrees=[ x509.DNSName(u".cryptography.io"), - x509.UniformResourceIdentifier(u"gopher://cryptography.test") - ] + x509.UniformResourceIdentifier(u"gopher://cryptography.test"), + ], ) def test_permitted_excluded_with_ips(self, backend): cert = _load_cert( - os.path.join( - "x509", "custom", "nc_permitted_excluded.pem" - ), + os.path.join("x509", "custom", "nc_permitted_excluded.pem"), x509.load_pem_x509_certificate, - backend + backend, ) nc = cert.extensions.get_extension_for_oid( ExtensionOID.NAME_CONSTRAINTS @@ -3437,16 +3661,14 @@ def test_permitted_excluded_with_ips(self, backend): excluded_subtrees=[ x509.DNSName(u".domain.com"), x509.UniformResourceIdentifier(u"http://test.local"), - ] + ], ) def test_single_ip_netmask(self, backend): cert = _load_cert( - os.path.join( - "x509", "custom", "nc_single_ip_netmask.pem" - ), + os.path.join("x509", "custom", "nc_single_ip_netmask.pem"), x509.load_pem_x509_certificate, - backend + backend, ) nc = cert.extensions.get_extension_for_oid( ExtensionOID.NAME_CONSTRAINTS @@ -3456,16 +3678,14 @@ def test_single_ip_netmask(self, backend): x509.IPAddress(ipaddress.IPv6Network(u"FF:0:0:0:0:0:0:0/128")), x509.IPAddress(ipaddress.IPv4Network(u"192.168.0.1/32")), ], - excluded_subtrees=None + excluded_subtrees=None, ) def test_invalid_netmask(self, backend): cert = _load_cert( - os.path.join( - "x509", "custom", "nc_invalid_ip_netmask.pem" - ), + os.path.join("x509", "custom", "nc_invalid_ip_netmask.pem"), x509.load_pem_x509_certificate, - backend + backend, ) with pytest.raises(ValueError): cert.extensions.get_extension_for_oid( @@ -3473,13 +3693,20 @@ def test_invalid_netmask(self, backend): ) def test_certbuilder(self, backend): - permitted = [u'.example.org', u'.xn--4ca7aey.example.com', - u'foobar.example.net'] + permitted = [ + u".example.org", + u".xn--4ca7aey.example.com", + u"foobar.example.net", + ] private_key = RSA_KEY_2048.private_key(backend) builder = _make_certbuilder(private_key) builder = builder.add_extension( - NameConstraints(permitted_subtrees=list(map(DNSName, permitted)), - excluded_subtrees=[]), True) + NameConstraints( + permitted_subtrees=list(map(DNSName, permitted)), + excluded_subtrees=[], + ), + True, + ) cert = builder.sign(private_key, hashes.SHA1(), backend) result = [ @@ -3514,7 +3741,7 @@ def test_reason_not_reasonflags(self): [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], None, frozenset(["notreasonflags"]), - None + None, ) def test_reason_not_frozenset(self): @@ -3523,7 +3750,7 @@ def test_reason_not_frozenset(self): [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], None, [x509.ReasonFlags.ca_compromise], - None + None, ) def test_disallowed_reasons(self): @@ -3532,7 +3759,7 @@ def test_disallowed_reasons(self): [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], None, frozenset([x509.ReasonFlags.unspecified]), - None + None, ) with pytest.raises(ValueError): @@ -3540,16 +3767,13 @@ def test_disallowed_reasons(self): [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], None, frozenset([x509.ReasonFlags.remove_from_crl]), - None + None, ) def test_reason_only(self): with pytest.raises(ValueError): x509.DistributionPoint( - None, - None, - frozenset([x509.ReasonFlags.aa_compromise]), - None + None, None, frozenset([x509.ReasonFlags.aa_compromise]), None ) def test_eq(self): @@ -3559,11 +3783,13 @@ def test_eq(self): frozenset([x509.ReasonFlags.superseded]), [ x509.DirectoryName( - x509.Name([ - x509.NameAttribute( - NameOID.COMMON_NAME, u"Important CA" - ) - ]) + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"Important CA" + ) + ] + ) ) ], ) @@ -3573,11 +3799,13 @@ def test_eq(self): frozenset([x509.ReasonFlags.superseded]), [ x509.DirectoryName( - x509.Name([ - x509.NameAttribute( - NameOID.COMMON_NAME, u"Important CA" - ) - ]) + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"Important CA" + ) + ] + ) ) ], ) @@ -3590,11 +3818,13 @@ def test_ne(self): frozenset([x509.ReasonFlags.superseded]), [ x509.DirectoryName( - x509.Name([ - x509.NameAttribute( - NameOID.COMMON_NAME, u"Important CA" - ) - ]) + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"Important CA" + ) + ] + ) ) ], ) @@ -3602,7 +3832,7 @@ def test_ne(self): [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], None, None, - None + None, ) assert dp != dp2 assert dp != object() @@ -3611,9 +3841,9 @@ def test_iter_input(self): name = [x509.UniformResourceIdentifier(u"http://crypt.og/crl")] issuer = [ x509.DirectoryName( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"Important CA") - ]) + x509.Name( + [x509.NameAttribute(NameOID.COMMON_NAME, u"Important CA")] + ) ) ] dp = x509.DistributionPoint( @@ -3628,17 +3858,19 @@ def test_iter_input(self): def test_repr(self): dp = x509.DistributionPoint( None, - x509.RelativeDistinguishedName([ - x509.NameAttribute(NameOID.COMMON_NAME, u"myCN") - ]), + x509.RelativeDistinguishedName( + [x509.NameAttribute(NameOID.COMMON_NAME, u"myCN")] + ), frozenset([x509.ReasonFlags.ca_compromise]), [ x509.DirectoryName( - x509.Name([ - x509.NameAttribute( - NameOID.COMMON_NAME, u"Important CA" - ) - ]) + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"Important CA" + ) + ] + ) ) ], ) @@ -3664,11 +3896,13 @@ def test_hash(self): frozenset([x509.ReasonFlags.superseded]), [ x509.DirectoryName( - x509.Name([ - x509.NameAttribute( - NameOID.COMMON_NAME, u"Important CA" - ) - ]) + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"Important CA" + ) + ] + ) ) ], ) @@ -3678,19 +3912,21 @@ def test_hash(self): frozenset([x509.ReasonFlags.superseded]), [ x509.DirectoryName( - x509.Name([ - x509.NameAttribute( - NameOID.COMMON_NAME, u"Important CA" - ) - ]) + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"Important CA" + ) + ] + ) ) ], ) dp3 = x509.DistributionPoint( None, - x509.RelativeDistinguishedName([ - x509.NameAttribute(NameOID.COMMON_NAME, u"myCN") - ]), + x509.RelativeDistinguishedName( + [x509.NameAttribute(NameOID.COMMON_NAME, u"myCN")] + ), None, None, ) @@ -3704,17 +3940,23 @@ def test_invalid_distribution_points(self): x509.FreshestCRL(["notadistributionpoint"]) def test_iter_len(self): - fcrl = x509.FreshestCRL([ - x509.DistributionPoint( - [x509.UniformResourceIdentifier(u"http://domain")], - None, None, None - ), - ]) + fcrl = x509.FreshestCRL( + [ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://domain")], + None, + None, + None, + ), + ] + ) assert len(fcrl) == 1 assert list(fcrl) == [ x509.DistributionPoint( [x509.UniformResourceIdentifier(u"http://domain")], - None, None, None + None, + None, + None, ), ] @@ -3722,21 +3964,25 @@ def test_iter_input(self): points = [ x509.DistributionPoint( [x509.UniformResourceIdentifier(u"http://domain")], - None, None, None + None, + None, + None, ), ] fcrl = x509.FreshestCRL(iter(points)) assert list(fcrl) == points def test_repr(self): - fcrl = x509.FreshestCRL([ - x509.DistributionPoint( - [x509.UniformResourceIdentifier(u"ftp://domain")], - None, - frozenset([x509.ReasonFlags.key_compromise]), - None - ), - ]) + fcrl = x509.FreshestCRL( + [ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + None, + frozenset([x509.ReasonFlags.key_compromise]), + None, + ), + ] + ) if not six.PY2: assert repr(fcrl) == ( "" + class TestInhibitAnyPolicy(object): def test_not_int(self): @@ -4429,11 +4848,9 @@ def test_hash(self): class TestInhibitAnyPolicyExtension(object): def test_inhibit_any_policy(self, backend): cert = _load_cert( - os.path.join( - "x509", "custom", "inhibit_any_policy_5.pem" - ), + os.path.join("x509", "custom", "inhibit_any_policy_5.pem"), x509.load_pem_x509_certificate, - backend + backend, ) iap = cert.extensions.get_extension_for_oid( ExtensionOID.INHIBIT_ANY_POLICY @@ -4450,7 +4867,8 @@ class TestIssuingDistributionPointExtension(object): x509.IssuingDistributionPoint( full_name=[ x509.UniformResourceIdentifier( - u"http://myhost.com/myca.crl") + u"http://myhost.com/myca.crl" + ) ], relative_name=None, only_contains_user_certs=False, @@ -4458,14 +4876,15 @@ class TestIssuingDistributionPointExtension(object): only_some_reasons=None, indirect_crl=True, only_contains_attribute_certs=False, - ) + ), ), ( "crl_idp_fullname_only.pem", x509.IssuingDistributionPoint( full_name=[ x509.UniformResourceIdentifier( - u"http://myhost.com/myca.crl") + u"http://myhost.com/myca.crl" + ) ], relative_name=None, only_contains_user_certs=False, @@ -4473,14 +4892,15 @@ class TestIssuingDistributionPointExtension(object): only_some_reasons=None, indirect_crl=False, only_contains_attribute_certs=False, - ) + ), ), ( "crl_idp_fullname_only_aa.pem", x509.IssuingDistributionPoint( full_name=[ x509.UniformResourceIdentifier( - u"http://myhost.com/myca.crl") + u"http://myhost.com/myca.crl" + ) ], relative_name=None, only_contains_user_certs=False, @@ -4488,14 +4908,15 @@ class TestIssuingDistributionPointExtension(object): only_some_reasons=None, indirect_crl=False, only_contains_attribute_certs=True, - ) + ), ), ( "crl_idp_fullname_only_user.pem", x509.IssuingDistributionPoint( full_name=[ x509.UniformResourceIdentifier( - u"http://myhost.com/myca.crl") + u"http://myhost.com/myca.crl" + ) ], relative_name=None, only_contains_user_certs=True, @@ -4503,23 +4924,26 @@ class TestIssuingDistributionPointExtension(object): only_some_reasons=None, indirect_crl=False, only_contains_attribute_certs=False, - ) + ), ), ( "crl_idp_only_ca.pem", x509.IssuingDistributionPoint( full_name=None, - relative_name=x509.RelativeDistinguishedName([ - x509.NameAttribute( - oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" - ) - ]), + relative_name=x509.RelativeDistinguishedName( + [ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, + value=u"PyCA", + ) + ] + ), only_contains_user_certs=False, only_contains_ca_certs=True, only_some_reasons=None, indirect_crl=False, only_contains_attribute_certs=False, - ) + ), ), ( "crl_idp_reasons_only.pem", @@ -4528,62 +4952,71 @@ class TestIssuingDistributionPointExtension(object): relative_name=None, only_contains_user_certs=False, only_contains_ca_certs=False, - only_some_reasons=frozenset([ - x509.ReasonFlags.key_compromise - ]), + only_some_reasons=frozenset( + [x509.ReasonFlags.key_compromise] + ), indirect_crl=False, only_contains_attribute_certs=False, - ) + ), ), ( "crl_idp_relative_user_all_reasons.pem", x509.IssuingDistributionPoint( full_name=None, - relative_name=x509.RelativeDistinguishedName([ - x509.NameAttribute( - oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" - ) - ]), + relative_name=x509.RelativeDistinguishedName( + [ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, + value=u"PyCA", + ) + ] + ), only_contains_user_certs=True, only_contains_ca_certs=False, - only_some_reasons=frozenset([ - x509.ReasonFlags.key_compromise, - x509.ReasonFlags.ca_compromise, - x509.ReasonFlags.affiliation_changed, - x509.ReasonFlags.superseded, - x509.ReasonFlags.cessation_of_operation, - x509.ReasonFlags.certificate_hold, - x509.ReasonFlags.privilege_withdrawn, - x509.ReasonFlags.aa_compromise, - ]), + only_some_reasons=frozenset( + [ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + x509.ReasonFlags.affiliation_changed, + x509.ReasonFlags.superseded, + x509.ReasonFlags.cessation_of_operation, + x509.ReasonFlags.certificate_hold, + x509.ReasonFlags.privilege_withdrawn, + x509.ReasonFlags.aa_compromise, + ] + ), indirect_crl=False, only_contains_attribute_certs=False, - ) + ), ), ( "crl_idp_relativename_only.pem", x509.IssuingDistributionPoint( full_name=None, - relative_name=x509.RelativeDistinguishedName([ - x509.NameAttribute( - oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" - ) - ]), + relative_name=x509.RelativeDistinguishedName( + [ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, + value=u"PyCA", + ) + ] + ), only_contains_user_certs=False, only_contains_ca_certs=False, only_some_reasons=None, indirect_crl=False, only_contains_attribute_certs=False, - ) + ), ), - ] + ], ) @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_vectors(self, filename, expected, backend): crl = _load_cert( os.path.join("x509", "custom", filename), - x509.load_pem_x509_crl, backend + x509.load_pem_x509_crl, + backend, ) idp = crl.extensions.get_extension_for_class( x509.IssuingDistributionPoint @@ -4592,51 +5025,96 @@ def test_vectors(self, filename, expected, backend): @pytest.mark.parametrize( ( - "error", "only_contains_user_certs", "only_contains_ca_certs", - "indirect_crl", "only_contains_attribute_certs", - "only_some_reasons", "full_name", "relative_name" + "error", + "only_contains_user_certs", + "only_contains_ca_certs", + "indirect_crl", + "only_contains_attribute_certs", + "only_some_reasons", + "full_name", + "relative_name", ), [ ( - TypeError, False, False, False, False, 'notafrozenset', None, - None + TypeError, + False, + False, + False, + False, + "notafrozenset", + None, + None, ), ( - TypeError, False, False, False, False, frozenset(['bad']), - None, None + TypeError, + False, + False, + False, + False, + frozenset(["bad"]), + None, + None, ), ( - ValueError, False, False, False, False, - frozenset([x509.ReasonFlags.unspecified]), None, None + ValueError, + False, + False, + False, + False, + frozenset([x509.ReasonFlags.unspecified]), + None, + None, ), ( - ValueError, False, False, False, False, - frozenset([x509.ReasonFlags.remove_from_crl]), None, None + ValueError, + False, + False, + False, + False, + frozenset([x509.ReasonFlags.remove_from_crl]), + None, + None, ), - (TypeError, 'notabool', False, False, False, None, None, None), - (TypeError, False, 'notabool', False, False, None, None, None), - (TypeError, False, False, 'notabool', False, None, None, None), - (TypeError, False, False, False, 'notabool', None, None, None), + (TypeError, "notabool", False, False, False, None, None, None), + (TypeError, False, "notabool", False, False, None, None, None), + (TypeError, False, False, "notabool", False, None, None, None), + (TypeError, False, False, False, "notabool", None, None, None), (ValueError, True, True, False, False, None, None, None), (ValueError, False, False, True, True, None, None, None), (ValueError, False, False, False, False, None, None, None), - ] + ], ) - def test_invalid_init(self, error, only_contains_user_certs, - only_contains_ca_certs, indirect_crl, - only_contains_attribute_certs, only_some_reasons, - full_name, relative_name): + def test_invalid_init( + self, + error, + only_contains_user_certs, + only_contains_ca_certs, + indirect_crl, + only_contains_attribute_certs, + only_some_reasons, + full_name, + relative_name, + ): with pytest.raises(error): x509.IssuingDistributionPoint( - full_name, relative_name, only_contains_user_certs, - only_contains_ca_certs, only_some_reasons, indirect_crl, - only_contains_attribute_certs + full_name, + relative_name, + only_contains_user_certs, + only_contains_ca_certs, + only_some_reasons, + indirect_crl, + only_contains_attribute_certs, ) def test_repr(self): idp = x509.IssuingDistributionPoint( - None, None, False, False, - frozenset([x509.ReasonFlags.key_compromise]), False, False + None, + None, + False, + False, + frozenset([x509.ReasonFlags.key_compromise]), + False, + False, ) if not six.PY2: assert repr(idp) == ( @@ -4663,10 +5141,13 @@ def test_eq(self): only_contains_attribute_certs=False, only_some_reasons=None, full_name=None, - relative_name=x509.RelativeDistinguishedName([ - x509.NameAttribute( - oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") - ]) + relative_name=x509.RelativeDistinguishedName( + [ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ] + ), ) idp2 = x509.IssuingDistributionPoint( only_contains_user_certs=False, @@ -4675,10 +5156,13 @@ def test_eq(self): only_contains_attribute_certs=False, only_some_reasons=None, full_name=None, - relative_name=x509.RelativeDistinguishedName([ - x509.NameAttribute( - oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") - ]) + relative_name=x509.RelativeDistinguishedName( + [ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ] + ), ) assert idp1 == idp2 @@ -4690,10 +5174,13 @@ def test_ne(self): only_contains_attribute_certs=False, only_some_reasons=None, full_name=None, - relative_name=x509.RelativeDistinguishedName([ - x509.NameAttribute( - oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") - ]) + relative_name=x509.RelativeDistinguishedName( + [ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ] + ), ) idp2 = x509.IssuingDistributionPoint( only_contains_user_certs=True, @@ -4702,10 +5189,13 @@ def test_ne(self): only_contains_attribute_certs=False, only_some_reasons=None, full_name=None, - relative_name=x509.RelativeDistinguishedName([ - x509.NameAttribute( - oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") - ]) + relative_name=x509.RelativeDistinguishedName( + [ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ] + ), ) assert idp1 != idp2 assert idp1 != object() @@ -4719,11 +5209,18 @@ def test_hash(self): ) idp3 = x509.IssuingDistributionPoint( None, - x509.RelativeDistinguishedName([ - x509.NameAttribute( - oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA") - ]), - True, False, None, False, False + x509.RelativeDistinguishedName( + [ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ] + ), + True, + False, + None, + False, + False, ) assert hash(idp1) == hash(idp2) assert hash(idp1) != hash(idp3) @@ -4787,11 +5284,13 @@ def test_hash(self): ), x509.IssuingDistributionPoint( full_name=None, - relative_name=x509.RelativeDistinguishedName([ - x509.NameAttribute( - oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" - ) - ]), + relative_name=x509.RelativeDistinguishedName( + [ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ] + ), only_contains_user_certs=False, only_contains_ca_certs=True, only_some_reasons=None, @@ -4809,53 +5308,65 @@ def test_hash(self): ), x509.IssuingDistributionPoint( full_name=None, - relative_name=x509.RelativeDistinguishedName([ - x509.NameAttribute( - oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA"), - x509.NameAttribute( - oid=x509.NameOID.COMMON_NAME, value=u"cryptography") - ]), + relative_name=x509.RelativeDistinguishedName( + [ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ), + x509.NameAttribute( + oid=x509.NameOID.COMMON_NAME, value=u"cryptography" + ), + ] + ), only_contains_user_certs=True, only_contains_ca_certs=False, - only_some_reasons=frozenset([ - x509.ReasonFlags.key_compromise, - x509.ReasonFlags.ca_compromise, - x509.ReasonFlags.affiliation_changed, - x509.ReasonFlags.privilege_withdrawn, - x509.ReasonFlags.aa_compromise, - ]), + only_some_reasons=frozenset( + [ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + x509.ReasonFlags.affiliation_changed, + x509.ReasonFlags.privilege_withdrawn, + x509.ReasonFlags.aa_compromise, + ] + ), indirect_crl=False, only_contains_attribute_certs=False, ), x509.IssuingDistributionPoint( full_name=None, - relative_name=x509.RelativeDistinguishedName([ - x509.NameAttribute( - oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" - ) - ]), + relative_name=x509.RelativeDistinguishedName( + [ + x509.NameAttribute( + oid=x509.NameOID.ORGANIZATION_NAME, value=u"PyCA" + ) + ] + ), only_contains_user_certs=False, only_contains_ca_certs=False, only_some_reasons=None, indirect_crl=False, only_contains_attribute_certs=False, ), - ] + ], ) def test_generate(self, idp, backend): key = RSA_KEY_2048.private_key(backend) last_update = datetime.datetime(2002, 1, 1, 12, 1) next_update = datetime.datetime(2030, 1, 1, 12, 1) - builder = x509.CertificateRevocationListBuilder().issuer_name( - x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, u"cryptography.io CA") - ]) - ).last_update( - last_update - ).next_update( - next_update - ).add_extension( - idp, True + builder = ( + x509.CertificateRevocationListBuilder() + .issuer_name( + x509.Name( + [ + x509.NameAttribute( + NameOID.COMMON_NAME, u"cryptography.io CA" + ) + ] + ) + ) + .last_update(last_update) + .next_update(next_update) + .add_extension(idp, True) ) crl = builder.sign(key, hashes.SHA256(), backend) @@ -4873,7 +5384,7 @@ def test_load(self, backend): cert = _load_cert( os.path.join("x509", "cryptography.io.precert.pem"), x509.load_pem_x509_certificate, - backend + backend, ) poison = cert.extensions.get_extension_for_oid( ExtensionOID.PRECERT_POISON @@ -4886,90 +5397,142 @@ def test_load(self, backend): def test_generate(self, backend): private_key = RSA_KEY_2048.private_key(backend) - cert = _make_certbuilder(private_key).add_extension( - x509.PrecertPoison(), critical=True - ).sign(private_key, hashes.SHA256(), backend) + cert = ( + _make_certbuilder(private_key) + .add_extension(x509.PrecertPoison(), critical=True) + .sign(private_key, hashes.SHA256(), backend) + ) poison = cert.extensions.get_extension_for_oid( ExtensionOID.PRECERT_POISON ).value assert isinstance(poison, x509.PrecertPoison) + def test_eq(self): + pcp1 = x509.PrecertPoison() + pcp2 = x509.PrecertPoison() + + assert pcp1 == pcp2 + + def test_hash(self): + pcp1 = x509.PrecertPoison() + pcp2 = x509.PrecertPoison() + + assert hash(pcp1) == hash(pcp2) + + def test_ne(self): + pcp1 = x509.PrecertPoison() + pcp2 = x509.PrecertPoison() + + assert pcp1 == pcp2 + assert (pcp1 != pcp2) is False + assert pcp1 != object() + + def test_repr(self): + pcp = x509.PrecertPoison() + + assert repr(pcp) == "" + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) class TestSignedCertificateTimestamps(object): @pytest.mark.supported( - only_if=lambda backend: ( - backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), - skip_message="Requires OpenSSL 1.1.0f+", + only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), + skip_message="Requires CT support", ) def test_eq(self, backend): - sct = _load_cert( - os.path.join("x509", "badssl-sct.pem"), - x509.load_pem_x509_certificate, - backend - ).extensions.get_extension_for_class( - x509.PrecertificateSignedCertificateTimestamps - ).value[0] - sct2 = _load_cert( - os.path.join("x509", "badssl-sct.pem"), - x509.load_pem_x509_certificate, - backend - ).extensions.get_extension_for_class( - x509.PrecertificateSignedCertificateTimestamps - ).value[0] + sct = ( + _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend, + ) + .extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ) + .value[0] + ) + sct2 = ( + _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend, + ) + .extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ) + .value[0] + ) assert sct == sct2 @pytest.mark.supported( - only_if=lambda backend: ( - backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), - skip_message="Requires OpenSSL 1.1.0f+", + only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), + skip_message="Requires CT support", ) def test_ne(self, backend): - sct = _load_cert( - os.path.join("x509", "badssl-sct.pem"), - x509.load_pem_x509_certificate, - backend - ).extensions.get_extension_for_class( - x509.PrecertificateSignedCertificateTimestamps - ).value[0] - sct2 = _load_cert( - os.path.join("x509", "cryptography-scts.pem"), - x509.load_pem_x509_certificate, - backend - ).extensions.get_extension_for_class( - x509.PrecertificateSignedCertificateTimestamps - ).value[0] + sct = ( + _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend, + ) + .extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ) + .value[0] + ) + sct2 = ( + _load_cert( + os.path.join("x509", "cryptography-scts.pem"), + x509.load_pem_x509_certificate, + backend, + ) + .extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ) + .value[0] + ) assert sct != sct2 assert sct != object() @pytest.mark.supported( - only_if=lambda backend: ( - backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), - skip_message="Requires OpenSSL 1.1.0f+", + only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), + skip_message="Requires CT support", ) def test_hash(self, backend): - sct = _load_cert( - os.path.join("x509", "badssl-sct.pem"), - x509.load_pem_x509_certificate, - backend - ).extensions.get_extension_for_class( - x509.PrecertificateSignedCertificateTimestamps - ).value[0] - sct2 = _load_cert( - os.path.join("x509", "badssl-sct.pem"), - x509.load_pem_x509_certificate, - backend - ).extensions.get_extension_for_class( - x509.PrecertificateSignedCertificateTimestamps - ).value[0] - sct3 = _load_cert( - os.path.join("x509", "cryptography-scts.pem"), - x509.load_pem_x509_certificate, - backend - ).extensions.get_extension_for_class( - x509.PrecertificateSignedCertificateTimestamps - ).value[0] + sct = ( + _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend, + ) + .extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ) + .value[0] + ) + sct2 = ( + _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend, + ) + .extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ) + .value[0] + ) + sct3 = ( + _load_cert( + os.path.join("x509", "cryptography-scts.pem"), + x509.load_pem_x509_certificate, + backend, + ) + .extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ) + .value[0] + ) assert hash(sct) == hash(sct2) assert hash(sct) != hash(sct3) @@ -4987,90 +5550,114 @@ def test_repr(self): ) @pytest.mark.supported( - only_if=lambda backend: ( - backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), - skip_message="Requires OpenSSL 1.1.0f+", + only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), + skip_message="Requires CT support", ) def test_eq(self, backend): - psct1 = _load_cert( - os.path.join("x509", "badssl-sct.pem"), - x509.load_pem_x509_certificate, - backend - ).extensions.get_extension_for_class( - x509.PrecertificateSignedCertificateTimestamps - ).value - psct2 = _load_cert( - os.path.join("x509", "badssl-sct.pem"), - x509.load_pem_x509_certificate, - backend - ).extensions.get_extension_for_class( - x509.PrecertificateSignedCertificateTimestamps - ).value + psct1 = ( + _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend, + ) + .extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ) + .value + ) + psct2 = ( + _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend, + ) + .extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ) + .value + ) assert psct1 == psct2 @pytest.mark.supported( - only_if=lambda backend: ( - backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), - skip_message="Requires OpenSSL 1.1.0f+", + only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), + skip_message="Requires CT support", ) def test_ne(self, backend): - psct1 = _load_cert( - os.path.join("x509", "cryptography-scts.pem"), - x509.load_pem_x509_certificate, - backend - ).extensions.get_extension_for_class( - x509.PrecertificateSignedCertificateTimestamps - ).value - psct2 = _load_cert( - os.path.join("x509", "badssl-sct.pem"), - x509.load_pem_x509_certificate, - backend - ).extensions.get_extension_for_class( - x509.PrecertificateSignedCertificateTimestamps - ).value + psct1 = ( + _load_cert( + os.path.join("x509", "cryptography-scts.pem"), + x509.load_pem_x509_certificate, + backend, + ) + .extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ) + .value + ) + psct2 = ( + _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend, + ) + .extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ) + .value + ) assert psct1 != psct2 assert psct1 != object() @pytest.mark.supported( - only_if=lambda backend: ( - backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), - skip_message="Requires OpenSSL 1.1.0f+", + only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), + skip_message="Requires CT support", ) def test_hash(self, backend): - psct1 = _load_cert( - os.path.join("x509", "badssl-sct.pem"), - x509.load_pem_x509_certificate, - backend - ).extensions.get_extension_for_class( - x509.PrecertificateSignedCertificateTimestamps - ).value - psct2 = _load_cert( - os.path.join("x509", "badssl-sct.pem"), - x509.load_pem_x509_certificate, - backend - ).extensions.get_extension_for_class( - x509.PrecertificateSignedCertificateTimestamps - ).value - psct3 = _load_cert( - os.path.join("x509", "cryptography-scts.pem"), - x509.load_pem_x509_certificate, - backend - ).extensions.get_extension_for_class( - x509.PrecertificateSignedCertificateTimestamps - ).value + psct1 = ( + _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend, + ) + .extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ) + .value + ) + psct2 = ( + _load_cert( + os.path.join("x509", "badssl-sct.pem"), + x509.load_pem_x509_certificate, + backend, + ) + .extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ) + .value + ) + psct3 = ( + _load_cert( + os.path.join("x509", "cryptography-scts.pem"), + x509.load_pem_x509_certificate, + backend, + ) + .extensions.get_extension_for_class( + x509.PrecertificateSignedCertificateTimestamps + ) + .value + ) assert hash(psct1) == hash(psct2) assert hash(psct1) != hash(psct3) @pytest.mark.supported( - only_if=lambda backend: ( - backend._lib.CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER), - skip_message="Requires OpenSSL 1.1.0f+", + only_if=lambda backend: (backend._lib.Cryptography_HAS_SCT), + skip_message="Requires CT support", ) def test_simple(self, backend): cert = _load_cert( os.path.join("x509", "badssl-sct.pem"), x509.load_pem_x509_certificate, - backend + backend, ) scts = cert.extensions.get_extension_for_class( x509.PrecertificateSignedCertificateTimestamps @@ -5087,20 +5674,21 @@ def test_simple(self, backend): 2016, 11, 17, 1, 56, 25, 396000 ) assert ( - sct.entry_type == - x509.certificate_transparency.LogEntryType.PRE_CERTIFICATE + sct.entry_type + == x509.certificate_transparency.LogEntryType.PRE_CERTIFICATE ) @pytest.mark.supported( only_if=lambda backend: ( - not backend._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER), + not backend._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER + ), skip_message="Requires OpenSSL < 1.1.0", ) def test_skips_scts_if_unsupported(self, backend): cert = _load_cert( os.path.join("x509", "badssl-sct.pem"), x509.load_pem_x509_certificate, - backend + backend, ) assert len(cert.extensions) == 10 with pytest.raises(x509.ExtensionNotFound): @@ -5119,11 +5707,9 @@ def test_skips_scts_if_unsupported(self, backend): class TestInvalidExtension(object): def test_invalid_certificate_policies_data(self, backend): cert = _load_cert( - os.path.join( - "x509", "custom", "cp_invalid.pem" - ), + os.path.join("x509", "custom", "cp_invalid.pem"), x509.load_pem_x509_certificate, - backend + backend, ) with pytest.raises(ValueError): cert.extensions @@ -5158,3 +5744,10 @@ def test_hash(self): nonce3 = x509.OCSPNonce(b"1" * 5) assert hash(nonce1) == hash(nonce2) assert hash(nonce1) != hash(nonce3) + + +def test_all_extension_oid_members_have_names_defined(): + for oid in dir(ExtensionOID): + if oid.startswith("__"): + continue + assert getattr(ExtensionOID, oid) in _OID_NAMES diff --git a/tests/x509/test_x509_revokedcertbuilder.py b/tests/x509/test_x509_revokedcertbuilder.py index 75c6b2697180..0db6d2a6f7de 100644 --- a/tests/x509/test_x509_revokedcertbuilder.py +++ b/tests/x509/test_x509_revokedcertbuilder.py @@ -30,10 +30,10 @@ def test_serial_number_must_be_positive(self): @pytest.mark.requires_backend_interface(interface=X509Backend) def test_minimal_serial_number(self, backend): revocation_date = datetime.datetime(2002, 1, 1, 12, 1) - builder = x509.RevokedCertificateBuilder().serial_number( - 1 - ).revocation_date( - revocation_date + builder = ( + x509.RevokedCertificateBuilder() + .serial_number(1) + .revocation_date(revocation_date) ) revoked_certificate = builder.build(backend) @@ -42,10 +42,10 @@ def test_minimal_serial_number(self, backend): @pytest.mark.requires_backend_interface(interface=X509Backend) def test_biggest_serial_number(self, backend): revocation_date = datetime.datetime(2002, 1, 1, 12, 1) - builder = x509.RevokedCertificateBuilder().serial_number( - (1 << 159) - 1 - ).revocation_date( - revocation_date + builder = ( + x509.RevokedCertificateBuilder() + .serial_number((1 << 159) - 1) + .revocation_date(revocation_date) ) revoked_certificate = builder.build(backend) @@ -67,10 +67,10 @@ def test_aware_revocation_date(self, backend): time = tz.localize(time) utc_time = datetime.datetime(2012, 1, 17, 6, 43) serial_number = 333 - builder = x509.RevokedCertificateBuilder().serial_number( - serial_number - ).revocation_date( - time + builder = ( + x509.RevokedCertificateBuilder() + .serial_number(serial_number) + .revocation_date(time) ) revoked_certificate = builder.build(backend) @@ -129,10 +129,10 @@ def test_no_revocation_date(self, backend): def test_create_revoked(self, backend): serial_number = 333 revocation_date = datetime.datetime(2002, 1, 1, 12, 1) - builder = x509.RevokedCertificateBuilder().serial_number( - serial_number - ).revocation_date( - revocation_date + builder = ( + x509.RevokedCertificateBuilder() + .serial_number(serial_number) + .revocation_date(revocation_date) ) revoked_certificate = builder.build(backend) @@ -145,21 +145,18 @@ def test_create_revoked(self, backend): [ x509.InvalidityDate(datetime.datetime(2015, 1, 1, 0, 0)), x509.CRLReason(x509.ReasonFlags.ca_compromise), - x509.CertificateIssuer([ - x509.DNSName(u"cryptography.io"), - ]) - ] + x509.CertificateIssuer([x509.DNSName(u"cryptography.io")]), + ], ) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_add_extensions(self, backend, extension): serial_number = 333 revocation_date = datetime.datetime(2002, 1, 1, 12, 1) - builder = x509.RevokedCertificateBuilder().serial_number( - serial_number - ).revocation_date( - revocation_date - ).add_extension( - extension, False + builder = ( + x509.RevokedCertificateBuilder() + .serial_number(serial_number) + .revocation_date(revocation_date) + .add_extension(extension, False) ) revoked_certificate = builder.build(backend) @@ -179,20 +176,17 @@ def test_add_multiple_extensions(self, backend): invalidity_date = x509.InvalidityDate( datetime.datetime(2015, 1, 1, 0, 0) ) - certificate_issuer = x509.CertificateIssuer([ - x509.DNSName(u"cryptography.io"), - ]) + certificate_issuer = x509.CertificateIssuer( + [x509.DNSName(u"cryptography.io")] + ) crl_reason = x509.CRLReason(x509.ReasonFlags.aa_compromise) - builder = x509.RevokedCertificateBuilder().serial_number( - serial_number - ).revocation_date( - revocation_date - ).add_extension( - invalidity_date, True - ).add_extension( - crl_reason, True - ).add_extension( - certificate_issuer, True + builder = ( + x509.RevokedCertificateBuilder() + .serial_number(serial_number) + .revocation_date(revocation_date) + .add_extension(invalidity_date, True) + .add_extension(crl_reason, True) + .add_extension(certificate_issuer, True) ) revoked_certificate = builder.build(backend) diff --git a/tox.ini b/tox.ini index d4c3022bc12e..e94d3c1e0753 100644 --- a/tox.ini +++ b/tox.ini @@ -1,20 +1,24 @@ [tox] minversion = 2.4 -envlist = py27,pypy,py34,py35,py36,py37,docs,pep8,py3pep8 +envlist = py27,pypy,py35,py36,py37,py38,docs,pep8,packaging +isolated_build = True [testenv] extras = - test - idna: idna + test + ssh: ssh deps = - # This must be kept in sync with Jenkinsfile and .travis/install.sh + # This must be kept in sync with .travis/install.sh and .github/workflows/ci.yml coverage ./vectors -passenv = ARCHFLAGS LDFLAGS CFLAGS INCLUDE LIB LD_LIBRARY_PATH USERNAME + randomorder: pytest-randomly +passenv = ARCHFLAGS LDFLAGS CFLAGS INCLUDE LIB LD_LIBRARY_PATH USERNAME PYTHONIOENCODING OPENSSL_FORCE_FIPS_MODE +setenv = + CRYPTOGRAPHY_ALLOW_OPENSSL_102=1 commands = pip list # We use parallel mode and then combine here so that coverage.py will take - # the paths like .tox/py34/lib/python3.4/site-packages/cryptography/__init__.py + # the paths like .tox/py38/lib/python3.8/site-packages/cryptography/__init__.py # and collapse them into src/cryptography/__init__.py. coverage run --parallel-mode -m pytest --capture=no --strict {posargs} coverage combine @@ -42,10 +46,10 @@ extras = docstest basepython = python3 commands = - sphinx-build -j4 -T -W -b html -d {envtmpdir}/doctrees docs docs/_build/html - sphinx-build -j4 -T -W -b latex -d {envtmpdir}/doctrees docs docs/_build/latex - sphinx-build -j4 -T -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html - sphinx-build -j4 -T -W -b spelling docs docs/_build/html + 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 doc8 --allow-long-titles README.rst CHANGELOG.rst docs/ --ignore-path docs/_build/ python setup.py sdist twine check dist/* @@ -53,26 +57,26 @@ commands = [testenv:docs-linkcheck] extras = docs -basepython = python2.7 +basepython = python3 commands = sphinx-build -W -b linkcheck docs docs/_build/html [testenv:pep8] basepython = python3 extras = - pep8test + pep8test commands = flake8 . + black --check . -[testenv:randomorder] +[testenv:packaging] deps = - {[testenv]deps} - pytest-random + check-manifest commands = - pytest --capture=no --strict --random {posargs} + check-manifest [flake8] -ignore = W504 +ignore = E203,E211,W503,W504 exclude = .tox,*.egg,.git,_build,.hypothesis select = E,W,F,N,I application-import-names = cryptography,cryptography_vectors,tests @@ -84,5 +88,6 @@ extensions = rst addopts = -r s markers = requires_backend_interface: this test requires a specific backend interface + skip_fips: this test is not executed in FIPS mode supported: parametrized test requiring only_if and skip_message wycheproof_tests: this test runs a wycheproof fixture diff --git a/vectors/cryptography_vectors/__about__.py b/vectors/cryptography_vectors/__about__.py index 6fcb314e28a0..3b41b82e0ab9 100644 --- a/vectors/cryptography_vectors/__about__.py +++ b/vectors/cryptography_vectors/__about__.py @@ -5,8 +5,14 @@ from __future__ import absolute_import, division, print_function __all__ = [ - "__title__", "__summary__", "__uri__", "__version__", "__author__", - "__email__", "__license__", "__copyright__", + "__title__", + "__summary__", + "__uri__", + "__version__", + "__author__", + "__email__", + "__license__", + "__copyright__", ] __title__ = "cryptography_vectors" @@ -14,10 +20,10 @@ __uri__ = "https://github.com/pyca/cryptography" -__version__ = "2.5" +__version__ = "3.2" __author__ = "The cryptography developers" __email__ = "cryptography-dev@python.org" __license__ = "BSD or Apache License, Version 2.0" -__copyright__ = "Copyright 2013-2017 %s" % __author__ +__copyright__ = "Copyright 2013-2019 %s" % __author__ diff --git a/vectors/cryptography_vectors/__init__.py b/vectors/cryptography_vectors/__init__.py index abcfe14c2f0a..f39ffe03ab0c 100644 --- a/vectors/cryptography_vectors/__init__.py +++ b/vectors/cryptography_vectors/__init__.py @@ -7,14 +7,26 @@ import os from cryptography_vectors.__about__ import ( - __author__, __copyright__, __email__, __license__, __summary__, __title__, - __uri__, __version__ + __author__, + __copyright__, + __email__, + __license__, + __summary__, + __title__, + __uri__, + __version__, ) __all__ = [ - "__title__", "__summary__", "__uri__", "__version__", "__author__", - "__email__", "__license__", "__copyright__", + "__title__", + "__summary__", + "__uri__", + "__version__", + "__author__", + "__email__", + "__license__", + "__copyright__", ] diff --git a/vectors/cryptography_vectors/asymmetric/DER_Serialization/dsa_public_key_invalid_bit_string.der b/vectors/cryptography_vectors/asymmetric/DER_Serialization/dsa_public_key_invalid_bit_string.der new file mode 100644 index 000000000000..7358bc1def8e Binary files /dev/null and b/vectors/cryptography_vectors/asymmetric/DER_Serialization/dsa_public_key_invalid_bit_string.der differ diff --git a/vectors/cryptography_vectors/asymmetric/DER_Serialization/dsa_public_key_no_params.der b/vectors/cryptography_vectors/asymmetric/DER_Serialization/dsa_public_key_no_params.der new file mode 100644 index 000000000000..0270ac158a02 Binary files /dev/null and b/vectors/cryptography_vectors/asymmetric/DER_Serialization/dsa_public_key_no_params.der differ diff --git a/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pkcs8-enc.der b/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pkcs8-enc.der new file mode 100644 index 000000000000..f268ed1bfe1a Binary files /dev/null and b/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pkcs8-enc.der differ diff --git a/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pkcs8-enc.pem b/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pkcs8-enc.pem new file mode 100644 index 000000000000..d4bcdb2a43f8 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pkcs8-enc.pem @@ -0,0 +1,6 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAhDgfwSFbYckgICCAAw +DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEFR6pN0F5UEPFF/Z8RB0maoEQG0i +za5Fgv9/c8H9med7ttjbbh8T73t+Rq2dcFT2kcUM2HJWGrWMvDpTEPEy0hduYFDh +YMcDjtOCKyUTwPovQI0= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pkcs8.der b/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pkcs8.der new file mode 100644 index 000000000000..71783b74d3d4 Binary files /dev/null and b/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pkcs8.der differ diff --git a/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pkcs8.pem b/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pkcs8.pem new file mode 100644 index 000000000000..7cf2b728c969 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pkcs8.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIJ1hsZ3v/VpguoRK9JLsLMREScVpezJpGXA7rAMcrn9g +-----END PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pub.der b/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pub.der new file mode 100644 index 000000000000..5b33e7546de5 Binary files /dev/null and b/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pub.der differ diff --git a/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pub.pem b/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pub.pem new file mode 100644 index 000000000000..9749b691defb --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/Ed25519/ed25519-pub.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEA11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo= +-----END PUBLIC KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pkcs8-enc.der b/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pkcs8-enc.der new file mode 100644 index 000000000000..0ac1c2662160 Binary files /dev/null and b/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pkcs8-enc.der differ diff --git a/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pkcs8-enc.pem b/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pkcs8-enc.pem new file mode 100644 index 000000000000..c1911db52a7c --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pkcs8-enc.pem @@ -0,0 +1,6 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIGrMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAi70Zc5kmb1BQICCAAw +DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEKLz9IxrHtLE/xwZXVFlzxcEUIdP +7Z+POIUbdwM2TT9GsYoh/RoHzbSszd873muKzCE6YclamsDhLL8HCS82tGN9ZzgK +IuNWwcPeskw1i21MLoPJiS76RfncGROVDiz3CKCp +-----END ENCRYPTED PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pkcs8.der b/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pkcs8.der new file mode 100644 index 000000000000..5718a5473444 Binary files /dev/null and b/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pkcs8.der differ diff --git a/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pkcs8.pem b/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pkcs8.pem new file mode 100644 index 000000000000..98af16420ad4 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pkcs8.pem @@ -0,0 +1,4 @@ +-----BEGIN PRIVATE KEY----- +MEcCAQAwBQYDK2VxBDsEOWyCpWLLgI0Q1jK+ichRPr9skp803fqMn2PJlg7240ij +UoyKP8wvBE45o/xblEkvjwMudUmiAJj5Ww== +-----END PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pub.der b/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pub.der new file mode 100644 index 000000000000..bd2a95530bb2 Binary files /dev/null and b/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pub.der differ diff --git a/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pub.pem b/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pub.pem new file mode 100644 index 000000000000..640da6f2be14 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/Ed448/ed448-pub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MEMwBQYDK2VxAzoAX9dEm1m0Yf0s54fsYWrUah2hNCSFpw4fig6nXYDpZ3jt8SR2 +m0bHBhvWeD3x5Q9s0foavq/oJWGA +-----END PUBLIC KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/dsa-nopsw.key b/vectors/cryptography_vectors/asymmetric/OpenSSH/dsa-nopsw.key new file mode 100644 index 000000000000..edb69615f74d --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/dsa-nopsw.key @@ -0,0 +1,21 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsgAAAAdzc2gtZH +NzAAAAgQDRqiBQV8QY6a/5fUvFCs5koeJgXj1v2D6dlSqEBEEu8aRA/sJQZmSx6Xzoi9gl +nvyrS0/Sjf0Y4J5iU1D0gYsNzBhxZFFyrg6LExwSfqMcWWBw8pdcMcOjVfrcWohvqF/Na2 +EnzTZgSOX3WbXA8ikw1Irak5MvD7luNDLX2ZKi7wAAABUA9x8+++PeaLuNjNUvbaDXhvmw +jbcAAACBAKlkeJEdFVDpZDmMG2Ob8KXy8hrqfEwZHR1B0HPWmZoOpw+TpY/oYEwuA9mXSG +0EeDVcQlBIaAtu4ZfmZQnRQ5cZ+cBX8VnxAAR6JUQw5R00U6cbiDSYXDn93sLW+D27f1jn +NShsyz43F66LrsXWTLmoFtMKXw+YBL5cL7Mfk6OcAAAAgHqgOmrZJRmNiRJAY/0ylOB9pc +S0OfYSj3MXIgbkS0qRvR+Llv1QpFCqykzTEFONosZb75Jb3FuIqw1WdZBOM8ZF5dIBdHAs +Q01NoTZiHJRQlFwBqMZ4DCs3txDuM1GZmDaYWIRdzVnrq8USqBSo2t1BvXbZXFLcmHsIyh +xh9CusAAAB6BxKLVkcSi1ZAAAAB3NzaC1kc3MAAACBANGqIFBXxBjpr/l9S8UKzmSh4mBe +PW/YPp2VKoQEQS7xpED+wlBmZLHpfOiL2CWe/KtLT9KN/RjgnmJTUPSBiw3MGHFkUXKuDo +sTHBJ+oxxZYHDyl1wxw6NV+txaiG+oX81rYSfNNmBI5fdZtcDyKTDUitqTky8PuW40MtfZ +kqLvAAAAFQD3Hz77495ou42M1S9toNeG+bCNtwAAAIEAqWR4kR0VUOlkOYwbY5vwpfLyGu +p8TBkdHUHQc9aZmg6nD5Olj+hgTC4D2ZdIbQR4NVxCUEhoC27hl+ZlCdFDlxn5wFfxWfEA +BHolRDDlHTRTpxuINJhcOf3ewtb4Pbt/WOc1KGzLPjcXrouuxdZMuagW0wpfD5gEvlwvsx ++To5wAAACAeqA6atklGY2JEkBj/TKU4H2lxLQ59hKPcxciBuRLSpG9H4uW/VCkUKrKTNMQ +U42ixlvvklvcW4irDVZ1kE4zxkXl0gF0cCxDTU2hNmIclFCUXAGoxngMKze3EO4zUZmYNp +hYhF3NWeurxRKoFKja3UG9dtlcUtyYewjKHGH0K6wAAAAVAMS2BFSZWFdWHlyYZscEHEEv +TkRNAAAADWRzYS1ub3Bzdy5rZXkBAgME +-----END OPENSSH PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/dsa-nopsw.key-cert.pub b/vectors/cryptography_vectors/asymmetric/OpenSSH/dsa-nopsw.key-cert.pub new file mode 100644 index 000000000000..753989db5752 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/dsa-nopsw.key-cert.pub @@ -0,0 +1 @@ +ssh-dss-cert-v01@openssh.com AAAAHHNzaC1kc3MtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgT/srHasDLk3rB8bDZK7rP6miircgVvnVrTghYfkmZsEAAACBANGqIFBXxBjpr/l9S8UKzmSh4mBePW/YPp2VKoQEQS7xpED+wlBmZLHpfOiL2CWe/KtLT9KN/RjgnmJTUPSBiw3MGHFkUXKuDosTHBJ+oxxZYHDyl1wxw6NV+txaiG+oX81rYSfNNmBI5fdZtcDyKTDUitqTky8PuW40MtfZkqLvAAAAFQD3Hz77495ou42M1S9toNeG+bCNtwAAAIEAqWR4kR0VUOlkOYwbY5vwpfLyGup8TBkdHUHQc9aZmg6nD5Olj+hgTC4D2ZdIbQR4NVxCUEhoC27hl+ZlCdFDlxn5wFfxWfEABHolRDDlHTRTpxuINJhcOf3ewtb4Pbt/WOc1KGzLPjcXrouuxdZMuagW0wpfD5gEvlwvsx+To5wAAACAeqA6atklGY2JEkBj/TKU4H2lxLQ59hKPcxciBuRLSpG9H4uW/VCkUKrKTNMQU42ixlvvklvcW4irDVZ1kE4zxkXl0gF0cCxDTU2hNmIclFCUXAGoxngMKze3EO4zUZmYNphYhF3NWeurxRKoFKja3UG9dtlcUtyYewjKHGH0K6wAAAAAAAAAAQAAAAEAAAAEbmFtZQAAAAAAAAAASz3OqAAAAAEFdF0oAAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAbIAAAAHc3NoLWRzcwAAAIEA0aogUFfEGOmv+X1LxQrOZKHiYF49b9g+nZUqhARBLvGkQP7CUGZksel86IvYJZ78q0tP0o39GOCeYlNQ9IGLDcwYcWRRcq4OixMcEn6jHFlgcPKXXDHDo1X63FqIb6hfzWthJ802YEjl91m1wPIpMNSK2pOTLw+5bjQy19mSou8AAAAVAPcfPvvj3mi7jYzVL22g14b5sI23AAAAgQCpZHiRHRVQ6WQ5jBtjm/Cl8vIa6nxMGR0dQdBz1pmaDqcPk6WP6GBMLgPZl0htBHg1XEJQSGgLbuGX5mUJ0UOXGfnAV/FZ8QAEeiVEMOUdNFOnG4g0mFw5/d7C1vg9u39Y5zUobMs+Nxeui67F1ky5qBbTCl8PmAS+XC+zH5OjnAAAAIB6oDpq2SUZjYkSQGP9MpTgfaXEtDn2Eo9zFyIG5EtKkb0fi5b9UKRQqspM0xBTjaLGW++SW9xbiKsNVnWQTjPGReXSAXRwLENNTaE2YhyUUJRcAajGeAwrN7cQ7jNRmZg2mFiEXc1Z66vFEqgUqNrdQb122VxS3Jh7CMocYfQrrAAAADcAAAAHc3NoLWRzcwAAAChGJhskBvKjziUaQuE3Kd3A+3WqQduqROikisQyJqTEmD9CqCrV2tuQ dsa-nopsw.key diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/dsa-nopsw.key.pub b/vectors/cryptography_vectors/asymmetric/OpenSSH/dsa-nopsw.key.pub new file mode 100644 index 000000000000..b50e534c1cba --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/dsa-nopsw.key.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBANGqIFBXxBjpr/l9S8UKzmSh4mBePW/YPp2VKoQEQS7xpED+wlBmZLHpfOiL2CWe/KtLT9KN/RjgnmJTUPSBiw3MGHFkUXKuDosTHBJ+oxxZYHDyl1wxw6NV+txaiG+oX81rYSfNNmBI5fdZtcDyKTDUitqTky8PuW40MtfZkqLvAAAAFQD3Hz77495ou42M1S9toNeG+bCNtwAAAIEAqWR4kR0VUOlkOYwbY5vwpfLyGup8TBkdHUHQc9aZmg6nD5Olj+hgTC4D2ZdIbQR4NVxCUEhoC27hl+ZlCdFDlxn5wFfxWfEABHolRDDlHTRTpxuINJhcOf3ewtb4Pbt/WOc1KGzLPjcXrouuxdZMuagW0wpfD5gEvlwvsx+To5wAAACAeqA6atklGY2JEkBj/TKU4H2lxLQ59hKPcxciBuRLSpG9H4uW/VCkUKrKTNMQU42ixlvvklvcW4irDVZ1kE4zxkXl0gF0cCxDTU2hNmIclFCUXAGoxngMKze3EO4zUZmYNphYhF3NWeurxRKoFKja3UG9dtlcUtyYewjKHGH0K6w= dsa-nopsw.key diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/dsa-psw.key b/vectors/cryptography_vectors/asymmetric/OpenSSH/dsa-psw.key new file mode 100644 index 000000000000..ee6d1e12bb3c --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/dsa-psw.key @@ -0,0 +1,22 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCOodUQio +9QarE9NbbQUAuXAAAAEAAAAAEAAAGyAAAAB3NzaC1kc3MAAACBAMHOI6HG+xy8RLV6C1JS +k3dldozdE3SJjK1n0UTdBFo/r1ZMnnH/IZOk5+TkRXplfkVAcmmH++Zm4yb4SzxiDMY8XB +Tn0COzgPOfJJUV6TKLgAF8QsvlhDrbRgLk1ANPQRY3YIPrVGcF4oUZcyUkIcjl4kycGwMy +E8wm0FckDKitAAAAFQC5WH7VkaACexO69dQapzGy05mb0QAAAIASiv/QUqr9zGVgiLj/Ge +KlF7nZLJNCTRoIYGEdARQM23052a/aPMoxaHk3SKHZZmGU87Gp0vl4z6zwRYTp7pzwLqU3 +6gprOqcrFDrPhEq0xkU8+AKClLZ31BUyxN2u6kpBiwQI4Mme3z3PDLVSME+NMEn+sdZKQp +L0Y0ctXBMtSQAAAIEAmahTrRyoQ32qVX3GKqHElryPfMjWIJsrGByxUNf3hn+IhTs4u858 +oHTiLsZWqrkxFqIGHSSrXclxVkvz9WxKO7D6tcECK7nCqmtEmgXGW+ayVUkeMRlv1VYHKx +ePsLxOOip14A00vqY5MkZJ8zFFrHxFV0Ej8cKaxJ4SLmvAkM0AAAHwvffrsyCVDHxWqAg2 +KQEm+3ebumLdoLkGgDiSaO1jwJr3R1VnzQTtqveg4rm5agmeHKvUmDTd1lTyTWWk6zX6Bx +Ww+63V+c3Byv0DlexJToQKo99ZayioWyJjF0/bRXJE34aIYzbDFCQTJdGQ2pEXAnyWBVOB +j44w/P6VvdhTDvfIYk2ZLpnEPbBi38Hs3n2a2VSp/dNctfE4yfnf2aVntXPoJPRbOYNZs6 +AmcPacbkBXNV2LJeTP2dnXFM4mnReBRVF9Eqd4SsfEXDvC1beBBf9rZN3c/JKXohG97iPi +PO4Bv34xMKVw64+RtyIN8gTE4Sp/ChqgESIGqCo034YQ5PYLlSX7JxzbfOkBZHAcg2MVsO +npL1HizQp/l5JzxNrFhjg9ZtIwa5mmPapQ1T/IWQQ5lrtev5cWcfEYonhyvjn2F9Rd5Eem +jajVfzUS37IGEN2vZaNyLmvMdemJMSkIQwHiHpsdcDfdR7m4hAIWnBYpj2+z5C4WuAFAqE +UeHjiw9PIMNFK6JTo3QbEUddJw5jgdlx9nctM26JWwKBAOYINCOv5f/2gjR13DzkLL5Xca +dSO1zHzdIZzrNpD/SFJFeHxlVuaCg6MefhYRMfxVZUAKYdw0qNhhTLecCfChQL6t2NdEOm +q9f9gN2+a0fnO2lA== +-----END OPENSSH PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/dsa-psw.key.pub b/vectors/cryptography_vectors/asymmetric/OpenSSH/dsa-psw.key.pub new file mode 100644 index 000000000000..a9a8d56599a3 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/dsa-psw.key.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBAMHOI6HG+xy8RLV6C1JSk3dldozdE3SJjK1n0UTdBFo/r1ZMnnH/IZOk5+TkRXplfkVAcmmH++Zm4yb4SzxiDMY8XBTn0COzgPOfJJUV6TKLgAF8QsvlhDrbRgLk1ANPQRY3YIPrVGcF4oUZcyUkIcjl4kycGwMyE8wm0FckDKitAAAAFQC5WH7VkaACexO69dQapzGy05mb0QAAAIASiv/QUqr9zGVgiLj/GeKlF7nZLJNCTRoIYGEdARQM23052a/aPMoxaHk3SKHZZmGU87Gp0vl4z6zwRYTp7pzwLqU36gprOqcrFDrPhEq0xkU8+AKClLZ31BUyxN2u6kpBiwQI4Mme3z3PDLVSME+NMEn+sdZKQpL0Y0ctXBMtSQAAAIEAmahTrRyoQ32qVX3GKqHElryPfMjWIJsrGByxUNf3hn+IhTs4u858oHTiLsZWqrkxFqIGHSSrXclxVkvz9WxKO7D6tcECK7nCqmtEmgXGW+ayVUkeMRlv1VYHKxePsLxOOip14A00vqY5MkZJ8zFFrHxFV0Ej8cKaxJ4SLmvAkM0= dsa-psw.key diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/ecdsa-nopsw.key b/vectors/cryptography_vectors/asymmetric/OpenSSH/ecdsa-nopsw.key new file mode 100644 index 000000000000..4c0a8bf6103f --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/ecdsa-nopsw.key @@ -0,0 +1,9 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS +1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQQmVkbOBmCBxiacl7qr3xRljePXZyUZ +GSSw5Bax3+pjR4SDCN77ay3wmcMT0n5wmFiumKH7LGdRWAOk5FSavF4vAAAAqGb/L/dm/y +/3AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCZWRs4GYIHGJpyX +uqvfFGWN49dnJRkZJLDkFrHf6mNHhIMI3vtrLfCZwxPSfnCYWK6YofssZ1FYA6TkVJq8Xi +8AAAAgcFJtJbq8YCNzbVBuGxtFkMo6E7L6thbRA0FqV4+2MbAAAAAPZWNkc2Etbm9wc3cu +a2V5AQ== +-----END OPENSSH PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/ecdsa-nopsw.key-cert.pub b/vectors/cryptography_vectors/asymmetric/OpenSSH/ecdsa-nopsw.key-cert.pub new file mode 100644 index 000000000000..ce1626bad8ec --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/ecdsa-nopsw.key-cert.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAg7ohu2h3ZSjGNlNGn5wmDHarKBT8q+6Yl23V+s3MNjzEAAAAIbmlzdHAyNTYAAABBBCZWRs4GYIHGJpyXuqvfFGWN49dnJRkZJLDkFrHf6mNHhIMI3vtrLfCZwxPSfnCYWK6YofssZ1FYA6TkVJq8Xi8AAAAAAAAAAAAAAAIAAAAEbmFtZQAAABYAAAAHZG9tYWluMQAAAAdkb21haW4yAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAAGgAAAATZWNkc2Etc2hhMi1uaXN0cDI1NgAAAAhuaXN0cDI1NgAAAEEEJlZGzgZggcYmnJe6q98UZY3j12clGRkksOQWsd/qY0eEgwje+2st8JnDE9J+cJhYrpih+yxnUVgDpORUmrxeLwAAAGMAAAATZWNkc2Etc2hhMi1uaXN0cDI1NgAAAEgAAAAhAOSy1UooQNXaxG4cbZTQVnC7uSJlLuk4w9Z5XvbfzzmSAAAAH2QDu0n+WcXzDEsXeaH6IV0drX99PYLeiabxYeUha/o= ecdsa-nopsw.key diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/ecdsa-nopsw.key.pub b/vectors/cryptography_vectors/asymmetric/OpenSSH/ecdsa-nopsw.key.pub new file mode 100644 index 000000000000..17f28a63556b --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/ecdsa-nopsw.key.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCZWRs4GYIHGJpyXuqvfFGWN49dnJRkZJLDkFrHf6mNHhIMI3vtrLfCZwxPSfnCYWK6YofssZ1FYA6TkVJq8Xi8= ecdsa-nopsw.key diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/ecdsa-psw.key b/vectors/cryptography_vectors/asymmetric/OpenSSH/ecdsa-psw.key new file mode 100644 index 000000000000..35eb8814eff9 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/ecdsa-psw.key @@ -0,0 +1,11 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBNPqCdPL +3HMhcAs6vsUbVEAAAAEAAAAAEAAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlz +dHAzODQAAABhBKoqSCpmO6pLIjBokwga14onc/XOkRZ9WPKfFf/d0Aq6HOjL5Vm4ZxxRP3 +mjyLI/flOjrx5aMVAed5xkX6shh+zN4mb2xajuPTwqbvsVvIyglrFbKKQO3DQnkbbeqBHL +PAAAAOCTdP9vi3Go06Z/wni2pxYNgJK9V8nFfmVceblZYMdAfP0WFAKK/i84Nodl2t72g0 +xAkCOimLPGI7xHL6ZVPe6IOzvaW3wx7L8DSXfoqhKLzJwPVG+iH1m4AyUTU7osswSHzVHv +nZsU+HPcetVahWWfbswLB4hjbyoQpxc2B0qk0UQJ8E1FsPpjMcpgHOtKEWrmbpHChSI9p3 +KyVGlMtL9CII0hTu61KKm1AgcX+WykIFLjqTpG2PY2X/uuW56nhYrDJqPXL4CPYTwxTRCN +MOV9toMiqAQHz1JqadMsbdviEQ== +-----END OPENSSH PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/ecdsa-psw.key.pub b/vectors/cryptography_vectors/asymmetric/OpenSSH/ecdsa-psw.key.pub new file mode 100644 index 000000000000..3ea1b8e5bf7f --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/ecdsa-psw.key.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBKoqSCpmO6pLIjBokwga14onc/XOkRZ9WPKfFf/d0Aq6HOjL5Vm4ZxxRP3mjyLI/flOjrx5aMVAed5xkX6shh+zN4mb2xajuPTwqbvsVvIyglrFbKKQO3DQnkbbeqBHLPA== ecdsa-psw.key diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-nopsw.key b/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-nopsw.key new file mode 100644 index 000000000000..34565dbf8610 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-nopsw.key @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACDdZgztgAFFC7T5PifrUy/kMu0Pnwq1au3vStKHe7FFMAAAAJhNWbUCTVm1 +AgAAAAtzc2gtZWQyNTUxOQAAACDdZgztgAFFC7T5PifrUy/kMu0Pnwq1au3vStKHe7FFMA +AAAECQxzIh6s9TpOOlHcnFpjQIdZWmrhsU3eTq05iGHQejl91mDO2AAUULtPk+J+tTL+Qy +7Q+fCrVq7e9K0od7sUUwAAAAEWVkMjU1MTktbm9wc3cua2V5AQIDBA== +-----END OPENSSH PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-nopsw.key-cert.pub b/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-nopsw.key-cert.pub new file mode 100644 index 000000000000..b0240b366acc --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-nopsw.key-cert.pub @@ -0,0 +1 @@ +ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIJjE7jTtIuJ68m5zBEtn0bCWKUXcMdAOau0hO3FTMpeAAAAAIN1mDO2AAUULtPk+J+tTL+Qy7Q+fCrVq7e9K0od7sUUwAAAAAAAAAAAAAAABAAAABG5hbWUAAAAAAAAAAAAAAAD//////////wAAAAAAAABkAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIN1mDO2AAUULtPk+J+tTL+Qy7Q+fCrVq7e9K0od7sUUwAAAAUwAAAAtzc2gtZWQyNTUxOQAAAEAqewM0LFjD4qQUdGNmF/W512ogcjh5xDchw9h2GjhFstttkQVfEOATyafZ5/vWGegMjSnGWHHTxv1A5bqzA+UE ed25519-nopsw.key diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-nopsw.key.pub b/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-nopsw.key.pub new file mode 100644 index 000000000000..21ead374197d --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-nopsw.key.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN1mDO2AAUULtPk+J+tTL+Qy7Q+fCrVq7e9K0od7sUUw ed25519-nopsw.key diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-psw.key b/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-psw.key new file mode 100644 index 000000000000..f1c75637838c --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-psw.key @@ -0,0 +1,8 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCX39wD02 +J9++SP9d3vlnxuAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIFpz5PWWlJVx/imA +hJjv57fg4eTGFVHf4WcFfbXPNo+/AAAAoM+Bu9OvuVW6elNfhl4AxM/p7Oy02ptuWR+LNV +Y9Sjp/ADM+aTHb77DbZFD8WqzXhioUcOcej1EdAr4NFP7YRC1TIDHuzKgePDjewMMK7lCw +9qZgZbBUYN8q0/V42L9Tc9w8rjkewtd6r5u+5UOLv7Ct7WxSESAAC1KC5TnnU0CCZ1ZFXN +NOsxE0VLn5e+SDyILFF8fGt3mGk0S1D50zVzY= +-----END OPENSSH PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-psw.key.pub b/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-psw.key.pub new file mode 100644 index 000000000000..4c3d949e4cac --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/ed25519-psw.key.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFpz5PWWlJVx/imAhJjv57fg4eTGFVHf4WcFfbXPNo+/ ed25519-psw.key diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/gen.sh b/vectors/cryptography_vectors/asymmetric/OpenSSH/gen.sh new file mode 100755 index 000000000000..b18c338b3803 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/gen.sh @@ -0,0 +1,62 @@ +#! /bin/sh + +rm *.key *.pub + +# avoid having too many files +ecbits="ecbits.txt" +echo 521 > "$ecbits" +getecbits() { + last=$(cat $ecbits) + case "$last" in + 256) last=384;; + 384) last=521;; + 521) last=256;; + esac + echo $last > "$ecbits" + echo $last +} + +genkey() { + fn="$1" + args="-f $fn -C $fn" + case "$fn" in + ecdsa-*) args="$args -t ecdsa -b $(getecbits)" ;; + rsa-*) args="$args -t rsa" ;; + dsa-*) args="$args -t dsa" ;; + ed25519-*) args="$args -t ed25519" ;; + esac + password='' + case "$fn" in + *-psw.*) password="password" ;; + esac + ssh-keygen -q -o $args -N "$password" +} + +# generate private key files +for ktype in rsa dsa ecdsa ed25519; do + for psw in nopsw psw; do + genkey "${ktype}-${psw}.key" + done +done + +# generate public key files +for fn in *.key; do + ssh-keygen -q -y -f "$fn" > /dev/null +done + +rm -f "$ecbits" + +# generate public key files with certificate +ssh-keygen -q -s "dsa-nopsw.key" -I "name" \ + -z 1 -V 20100101123000:21090101123000 \ + "dsa-nopsw.key.pub" +ssh-keygen -q -s "rsa-nopsw.key" -I "name" \ + -z 2 -n user1,user2 -t rsa-sha2-512 \ + "rsa-nopsw.key.pub" +ssh-keygen -q -s "ecdsa-nopsw.key" -I "name" \ + -h -n domain1,domain2 \ + "ecdsa-nopsw.key.pub" +ssh-keygen -q -s "ed25519-nopsw.key" -I "name" \ + -O no-port-forwarding \ + "ed25519-nopsw.key.pub" + diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/rsa-nopsw.key b/vectors/cryptography_vectors/asymmetric/OpenSSH/rsa-nopsw.key new file mode 100644 index 000000000000..9d755e818058 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/rsa-nopsw.key @@ -0,0 +1,27 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn +NhAAAAAwEAAQAAAQEAq2QdSm22QEsm+GtpAwN4qk0exDIxwxUb8jJ6LLLo19KJR9ySQw+d +Ajp9WIUumXM2OPYi0qqtN6JKMsDrVSR87RoK7V2W4lHYljZBODGYA8bfpqaLt5HMvkJpsk +MEBqJkZtwO8G/J3QDOFByiGOxeeL4/2vnM5XwN/ff6SKABxfU60gDmlofFlZqCD9exWO52 +dg5BQ/gN5qJLBKBZmC3jWnAkrblvfPxwfp9WC3gMrFIILytCWvRu9YKM+nQZoqo0yCbzDy +7GRK5XZJlHfw+jV3MWMSXS7GSirOmTtmyygCtkphA3Y8HAQlibhdg+5jZDWRdDXIU2uOET +iHc8qvxM8wAAA8jQzBt60MwbegAAAAdzc2gtcnNhAAABAQCrZB1KbbZASyb4a2kDA3iqTR +7EMjHDFRvyMnossujX0olH3JJDD50COn1YhS6ZczY49iLSqq03okoywOtVJHztGgrtXZbi +UdiWNkE4MZgDxt+mpou3kcy+QmmyQwQGomRm3A7wb8ndAM4UHKIY7F54vj/a+czlfA399/ +pIoAHF9TrSAOaWh8WVmoIP17FY7nZ2DkFD+A3moksEoFmYLeNacCStuW98/HB+n1YLeAys +UggvK0Ja9G71goz6dBmiqjTIJvMPLsZErldkmUd/D6NXcxYxJdLsZKKs6ZO2bLKAK2SmED +djwcBCWJuF2D7mNkNZF0NchTa44ROIdzyq/EzzAAAAAwEAAQAAAQAYxAivfpb9R17EOtEb +zF6dTTOK6i3ioKQ/JSgeWWPn+9Y2ehrwccsgTU9bgTMwnUNSi86QXnVVOrA6EUJwNSuQH1 +lA32s0HNuNKR3XfuMWeKBMtngt+HV7cKFRTvm/86tKabYG7EBhHQKqSVDrBQzJqcQUYlBH +QNvMvQ5/fA+FiSN5RT/Hv0iJy9WFQyqN8W1KwWUnFnXgEw9ZFBlhjugcKDS1l+fyoDN0p8 +/Lm0ojn2I7I9SH9tXKb330zhO3CfXMVtjnpyi8wQALT6nEarfBwzGK6R0xWX3Xm+i2fQBb +sIBDr5r3WWpQlnPnFx1lSntQeoUVLJEimRklQJVL41fhAAAAgG923QGfsC61Fp22Q+rVb8 +0N66qxCfnXnQDbtT7ZdFK7tjXdKVA/GU+vU/pgFarixYcGS5gDKbAJM2R6XLz9cE5UVzaw +TrJab6bHG9bX8xh2kSKcY0GW1/QWp9pv6IWrCQziXiDP7uxDndxolfnHXsjT3QVfNQV+J8 +gtkjP3aCy1AAAAgQDZOcREo87MzWwbEoVAETZ8uVqWspTwJtAvIuqHePvHa1wvc5fWqr1Z +1wUN/Wl/DKhOjydBXQSa/SfKdsIx0JRkia06bYvS1eoL08+y3aHFkIR+WOp6bVYH/p3HzH +9qdMx7IHpAco7ZtBmQ4O2nZamVBRX5FnxkcmkCHccENSh9OwAAAIEAyfvp/f6ka1FH/mW0 +MqRxAhzB8SoUGbvnGhgBxTWgCH7iMbtUwVsi3TbJr0gYBYQoFH61rAGvOfUTb9cd9+bowR +j9m3oBOwSJBJG25hrmsqyFuZQlSMAv/AXjjLNUF1AQkpRZZMcEd6rTffprogiwkGdrRTMe ++tjRZCCgQaN+06kAAAANcnNhLW5vcHN3LmtleQECAwQFBg== +-----END OPENSSH PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/rsa-nopsw.key-cert.pub b/vectors/cryptography_vectors/asymmetric/OpenSSH/rsa-nopsw.key-cert.pub new file mode 100644 index 000000000000..35b0c2bbb075 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/rsa-nopsw.key-cert.pub @@ -0,0 +1 @@ +ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgtL8iJdlD7w2obBZdlxyqu06uLR78fvDASlnR3RRk/eMAAAADAQABAAABAQCrZB1KbbZASyb4a2kDA3iqTR7EMjHDFRvyMnossujX0olH3JJDD50COn1YhS6ZczY49iLSqq03okoywOtVJHztGgrtXZbiUdiWNkE4MZgDxt+mpou3kcy+QmmyQwQGomRm3A7wb8ndAM4UHKIY7F54vj/a+czlfA399/pIoAHF9TrSAOaWh8WVmoIP17FY7nZ2DkFD+A3moksEoFmYLeNacCStuW98/HB+n1YLeAysUggvK0Ja9G71goz6dBmiqjTIJvMPLsZErldkmUd/D6NXcxYxJdLsZKKs6ZO2bLKAK2SmEDdjwcBCWJuF2D7mNkNZF0NchTa44ROIdzyq/EzzAAAAAAAAAAIAAAABAAAABG5hbWUAAAASAAAABXVzZXIxAAAABXVzZXIyAAAAAAAAAAD//////////wAAAAAAAACCAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQCrZB1KbbZASyb4a2kDA3iqTR7EMjHDFRvyMnossujX0olH3JJDD50COn1YhS6ZczY49iLSqq03okoywOtVJHztGgrtXZbiUdiWNkE4MZgDxt+mpou3kcy+QmmyQwQGomRm3A7wb8ndAM4UHKIY7F54vj/a+czlfA399/pIoAHF9TrSAOaWh8WVmoIP17FY7nZ2DkFD+A3moksEoFmYLeNacCStuW98/HB+n1YLeAysUggvK0Ja9G71goz6dBmiqjTIJvMPLsZErldkmUd/D6NXcxYxJdLsZKKs6ZO2bLKAK2SmEDdjwcBCWJuF2D7mNkNZF0NchTa44ROIdzyq/EzzAAABFAAAAAxyc2Etc2hhMi01MTIAAAEAC13gJgpzMrO3fGM7lNpLLBDUa6GxB4Lr/RSHLxG5v9+Ym7z5aIYmneYifbNQ9qIPDxpuBQvN97NgV4ImSMjfIaaQi/PxyHKC+mxMXAonT5c5d+zhZHQ95/uxIt6iba1ej3MRVYw+biQlnIHhOUeJNV3W8UOry0XQlJzjTBR2/1Y+Xk89NbZ3F6QQ9UZpT/FvbERghElBauTz1UhtSlMCrn66tEOGxreVHraoM92pJaygginwb5iVU0SPWhWG3Qyh8P6uKzqSKIr+6BfaiIoWJXOLLEtSfmuK8dTuE8fNeU4PQlkJBqfcWbpD934QsP1dXWhan5Y4iFMK4IjcPNu7iA== rsa-nopsw.key diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/rsa-nopsw.key.pub b/vectors/cryptography_vectors/asymmetric/OpenSSH/rsa-nopsw.key.pub new file mode 100644 index 000000000000..00c01e299395 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/rsa-nopsw.key.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrZB1KbbZASyb4a2kDA3iqTR7EMjHDFRvyMnossujX0olH3JJDD50COn1YhS6ZczY49iLSqq03okoywOtVJHztGgrtXZbiUdiWNkE4MZgDxt+mpou3kcy+QmmyQwQGomRm3A7wb8ndAM4UHKIY7F54vj/a+czlfA399/pIoAHF9TrSAOaWh8WVmoIP17FY7nZ2DkFD+A3moksEoFmYLeNacCStuW98/HB+n1YLeAysUggvK0Ja9G71goz6dBmiqjTIJvMPLsZErldkmUd/D6NXcxYxJdLsZKKs6ZO2bLKAK2SmEDdjwcBCWJuF2D7mNkNZF0NchTa44ROIdzyq/Ezz rsa-nopsw.key diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/rsa-psw.key b/vectors/cryptography_vectors/asymmetric/OpenSSH/rsa-psw.key new file mode 100644 index 000000000000..cd1f38f3c938 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/rsa-psw.key @@ -0,0 +1,28 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABChvLeROo +MQfWAC6b7jds47AAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQCek3p8wNo1 +5l7Ihy4yaGjWScJpjh/Lq7WS7f64KxXKodBe35fLl8lu9Ds4Y06XWeHZdGxC+qp4QoxGYI +Ft2Awm8sz2wRbPY7d322tG9VnT59bQlvKtq77y9ZYefsdVwh2Uf7otdUZOEz6KuKc1CXXb +FfBFY6YB1lZ4YkQ2YHsYau22RHDjaHi55VoFokyk7cVnuhaIXCrppAH5+AMoqVtrAb/48G +2gGdQSo90heqglW7QLXPx2sCijp+62coXzbfViYzARdc5rbcih7zAfxEHMi+1HZmdvNKvd +2Vy+jPFD+FvvHUDl58XChAjJVmgrsqbZanpgIDD4/48dSnHSH0OxAAADwOuiaWL5LLLt5D +8bC7i0soG4LUSlwn0GlYhYyeMTBDswEcm+BGt+S1vgHO6f6oA+v+A/npxgwN7OrCJoq5Ls +iJZ//KCB+GCXXF0wXldwFcNtMoylG2FVo8Gx+Jckm+wSy+Uk73Sk+D+4UiHNGeFuQ85PbX +ceyne4iayry3PkiWHkfCVUy2UgW2L3YKtoDfXZ5QK3JVPxfMvQnDnP47r3L48rVCfvYVVy +SX+YnKgwMJPa4DX6mF8E6MPtntzZoN2MUwIJRlRZl1KqzmsIKl/XWsxsQuosvMT1wdDGIf +uT3uVtabeMyybM4tzPwXdzgnh9Mv2PmcOV15XCmxBFQP81yB8AkuUTWuekEbgypIvppQiL +vlmiSdWsAZvBqYN7lpuIJloRH3PCyzKSBLDJ6gSpb+ysX9s+Z2of3arBo0wAipZzl+S65R +guK7IxZu4fynOKojRjL97w6FN0GpaMOC0QiDNfSIg3wk3FJ8c6DFRjKDgaXSk90aMNEGLX +kOidZ3lQJI3K3KODDt28F9mKfOS6lyUWe9+4CQO+oJkY9EdUgiT3ZSbbQAWjCGSh4A6/Z8 +VHKYb7UCBHYf431VF95yY+2u31Amr76iHuhVZ+G5tcwytvHjuheZQttXSkvvst7J5fxPBT +kLXfm75RUH9ajveDR9mZq4SmJzlOHPkAn8qZ6QeLGvtsp0Lde8dKu6bo2eqtilbVMr6fi1 +9U+il6J+K+DiAcMh1vOAp0nhecstlabMN+NnENnWy2s+zyQYLKMUACYge7vWxbgJ0PFNkF +8RM6vC8/IIP81VSp/ako1Dsjh26uhAF92/HHCkAgFiUeBXACjvDo8/FSFbdbutlyl4bvOE +miKQfSLWqh5lxjDySYOzhGerAivmRCNUviseFTTGP/qE/+s0VZjuMt3afE4H/9baftyt+O +Iz1OGaMKXPD40mWhj4LUdD+opzGtjexojUPCCzYMzKsEz+WFE3//TWmcM3jq6lSDwbgbVI +82MGXf0htD7RtB9Gy3pE793LiRecCMygp/gF0ViPa6mwIxMOTy1mp0F5bCddRsNWGA91kF +XcSjUo/1mpFADMgUcrEsUCK69oxl1D/hPrkvvGEG/U/6z0gS9/cTeIim/6wg+XSULNfOgG +l0Ate1oHdrZ8XVjHq8e05L5VbYvXMvc9ETnB786kxAuJKc+60KPQS5KHZFiZEAvEcFnd7s +vCjY0NEf8s8Ofn0jI50UiMn5Ge0YEhtypQOb11kawG1L9UIgL3HJsm7e8osYdGig3ejFHL +teHHc5kg== +-----END OPENSSH PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/rsa-psw.key.pub b/vectors/cryptography_vectors/asymmetric/OpenSSH/rsa-psw.key.pub new file mode 100644 index 000000000000..ad94f9594102 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/rsa-psw.key.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCek3p8wNo15l7Ihy4yaGjWScJpjh/Lq7WS7f64KxXKodBe35fLl8lu9Ds4Y06XWeHZdGxC+qp4QoxGYIFt2Awm8sz2wRbPY7d322tG9VnT59bQlvKtq77y9ZYefsdVwh2Uf7otdUZOEz6KuKc1CXXbFfBFY6YB1lZ4YkQ2YHsYau22RHDjaHi55VoFokyk7cVnuhaIXCrppAH5+AMoqVtrAb/48G2gGdQSo90heqglW7QLXPx2sCijp+62coXzbfViYzARdc5rbcih7zAfxEHMi+1HZmdvNKvd2Vy+jPFD+FvvHUDl58XChAjJVmgrsqbZanpgIDD4/48dSnHSH0Ox rsa-psw.key diff --git a/vectors/cryptography_vectors/asymmetric/PEM_Serialization/dsa_4096.pem b/vectors/cryptography_vectors/asymmetric/PEM_Serialization/dsa_4096.pem new file mode 100644 index 000000000000..af14d247bf14 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/PEM_Serialization/dsa_4096.pem @@ -0,0 +1,36 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIGVQIBAAKCAgEAy8x5LsdCM2fSykikHtoZZPXcZIRm6ZQQTdpkOHyX9AAqVVpc +kXqUltbd1rLCPLrii/Syg1XBwsna7fUEci13xUHDk/97TLG9Z0qIH7NgdBQSFGTL +GWLRbp83nE1Hc+/b0htaABTT5AV5q54xoDED8AuP1b2l7SxrgJz/uDsvZcmHM0y3 +AxTiFkPCqNM+nHN7w3A5NJmFlvm3pl/8B9DCvLXILqiFYpKwewa4f3RUIqCuKlgJ +y1Yj5BtjiWzJV6153vuAuFaD86G7Pck6VQDEpaY8u0LrjAAgzjaUvD45uDgkw2HT +/sJDAkIWjpyPEEvXNUmgC8Eh52GCeJkT5iG04a83k67VPbbS3dENRgzrfYpmRIlJ +lfoxtIpFEkDT8jpioDIzven7JNIhNND0Y/bs3pxnkIjrs3jPGpW9dtoeP2RYSlle +QGqhu/B8lIEpruy94/Ujz7nVYnNSHZGY/Xk2pLR78B1tzk/mojcgTGtq76GHuY4+ +p2I49qThgWOGBT8b9ysYgI2momHcDkauYDq+l0dLg6h6XPPsXU/8qHL2e5bCW1ub +uMb0T4NwbLwl9rHc2gcKxfdqnK0S4hgfWR5nhDsLyBl04mBqnZaoQ/1Re5Kp1ZPU +a8/CR0oktwh8ZP0TmUbExSd8s/kAUJl49Fp2EGxFX3pF2u+mucbd7iDLVzMCIQC8 +2B6GLZaBrH0OZX2UWz8A10CuSHAqib45GIwrcEqVawKCAgALNtzq+Ap3IPQrjnsv +H9VLVoLx2X37UF6DQbX9ZMcnKNwooVNxkLPXokMIbVPcsegavw1ECgiCu/Ung+aM +Whd5w4iMMxq82I9nd8M2GUvg2QYYz5WOLsbJTk1kcV0WF+MzMrWCAuXiuCfYj90X +/TT4Dhd037fVfktjwzJFtox/NKKAM96/wm1MHfwy4s7L1cTe1IZZocZDB/4l9Ciw +zNAc/VlNfmheAp2RlrdY2waHVCdU/AJt3SNghUqLAn5dJELKyY37Kl9OHxlnWhTl +dTBzC6VFo4Gkro28/C2kY/PYkShEXPT1c8D63lbYdUt5dgnfkDpddjRvgXGLOltJ +1/iogrMq2EKYECoXtNzM7xXu4vxMNERjbyuhWg9qw0mczFgel1R7UWeMAz5a7J5S +fHs2p94/iyQZPHHzR4DEXC/dcuUer5koPJvdIO6hbqMtfcWEusOEdOxRapjrzaLN +bCaL4c33j8y7FOK2JC+FAz4ljI9AIsomt73tyrRK0PFUrlh147cuOKZAGYHQJlaX +z6R/W8z71vO00/VvIZuzHOYiGZQdQ9FUiilQfrhGTF+SOyjBMSSantUUVUoYRC7E +Tc83vQEQnpe5VjX+naSCk/zv1JFGSSpmWn45aDSswmA9EjyKxg1Ae0MrshB8a80M +eqRrfGtlLuGT0KiYKse9z90VTAKCAgBFBTIdD1g7KRadTcyhoXw5+zMv9vVb4kDx +UAyuqPulh3xadD1FUMukQWjCzJDtx8xDSOj1U9Tal/DsUBtzS+MyPAQdsXhs4oYq +ska/OWc8287dtX2U511de2bd5GS9rI++HKLHES9RBkAhuo7l5cc+TGJ8XeFgbmdF +DStjyLy4ABLG0Fkk70nMHIIGal/axBz0kYhSf1W1XO2y2PAY8/sNwdHwI7TimEcL +qxakgneBjLn7L+SO3N5IRI1eLwl/0sj6ZUoaV6ZpPuTNDTo+7PQlMP+OqIL77R/M +2rsJSE186CI8IR99K7PylS2Gk+RWv6NcYnZCOcP4UdXEg7/cECjWaSKqn20q2Jrs +ZuVrRoVF4XsHmcItYj8JyeFcGUgUSlPVNMvO9L11IMvvgo9EQ5OU0UHiBZRoWWu6 +GWx7VqqNU078z2jL+q8MFcqNzqXM64DtVDc1sjdZSLcNzKRWiMrnek4MB+aL1l7G +hXdDRkj3qTRrkvzHBfxDm2u4lpMInFci1Lu0oxgqLEISYAGdyb1we+OMeqR12YUr +QP5/DtJdntE0hKMIWGkAYHvIowu2ZOUPs6mdgJZ/IL3qJsvLG2ZFpe3aBnbL8qj7 +/ezCts5E509IwRiVhvEik6ZKUjSYojkcWL88p4PGZsP1/iG8KQgMnCrPIOjYVTVM +Qs3D7GFsYAIgAhium9LrIx3luKDOsxS4nX9f8xChr+Z1Ej8xgaqp96Y= +-----END DSA PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/ciphers/Blowfish/bf-cbc.txt b/vectors/cryptography_vectors/ciphers/Blowfish/bf-cbc.txt index 184d9565fd98..ad3fa0cf2fe6 100644 --- a/vectors/cryptography_vectors/ciphers/Blowfish/bf-cbc.txt +++ b/vectors/cryptography_vectors/ciphers/Blowfish/bf-cbc.txt @@ -1,4 +1,4 @@ -# Reformatted from https://www.schneier.com/code/vectors.txt +# Reformatted from https://www.schneier.com/wp-content/uploads/2015/12/vectors-2.txt # to look like the NIST vectors [ENCRYPT] diff --git a/vectors/cryptography_vectors/ciphers/Blowfish/bf-cfb.txt b/vectors/cryptography_vectors/ciphers/Blowfish/bf-cfb.txt index 8a326f500d46..cd2f58ff91df 100644 --- a/vectors/cryptography_vectors/ciphers/Blowfish/bf-cfb.txt +++ b/vectors/cryptography_vectors/ciphers/Blowfish/bf-cfb.txt @@ -1,4 +1,4 @@ -# Reformatted from https://www.schneier.com/code/vectors.txt +# Reformatted from https://www.schneier.com/wp-content/uploads/2015/12/vectors-2.txt # to look like the NIST vectors [ENCRYPT] diff --git a/vectors/cryptography_vectors/ciphers/Blowfish/bf-ecb.txt b/vectors/cryptography_vectors/ciphers/Blowfish/bf-ecb.txt index bb18a5a3f1bc..70c1c030803f 100644 --- a/vectors/cryptography_vectors/ciphers/Blowfish/bf-ecb.txt +++ b/vectors/cryptography_vectors/ciphers/Blowfish/bf-ecb.txt @@ -1,4 +1,4 @@ -# Reformatted from https://www.schneier.com/code/vectors.txt +# Reformatted from https://www.schneier.com/wp-content/uploads/2015/12/vectors-2.txt # to look like the NIST vectors [ENCRYPT] diff --git a/vectors/cryptography_vectors/ciphers/Blowfish/bf-ofb.txt b/vectors/cryptography_vectors/ciphers/Blowfish/bf-ofb.txt index 21a7421842f2..f87609a996ca 100644 --- a/vectors/cryptography_vectors/ciphers/Blowfish/bf-ofb.txt +++ b/vectors/cryptography_vectors/ciphers/Blowfish/bf-ofb.txt @@ -1,4 +1,4 @@ -# Reformatted from https://www.schneier.com/code/vectors.txt +# Reformatted from https://www.schneier.com/wp-content/uploads/2015/12/vectors-2.txt # to look like the NIST vectors [ENCRYPT] diff --git a/vectors/cryptography_vectors/hashes/SHA3/SHA3_224LongMsg.rsp b/vectors/cryptography_vectors/hashes/SHA3/SHA3_224LongMsg.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHA3/SHA3_224Monte.rsp b/vectors/cryptography_vectors/hashes/SHA3/SHA3_224Monte.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHA3/SHA3_224ShortMsg.rsp b/vectors/cryptography_vectors/hashes/SHA3/SHA3_224ShortMsg.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHA3/SHA3_256LongMsg.rsp b/vectors/cryptography_vectors/hashes/SHA3/SHA3_256LongMsg.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHA3/SHA3_256Monte.rsp b/vectors/cryptography_vectors/hashes/SHA3/SHA3_256Monte.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHA3/SHA3_256ShortMsg.rsp b/vectors/cryptography_vectors/hashes/SHA3/SHA3_256ShortMsg.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHA3/SHA3_384LongMsg.rsp b/vectors/cryptography_vectors/hashes/SHA3/SHA3_384LongMsg.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHA3/SHA3_384Monte.rsp b/vectors/cryptography_vectors/hashes/SHA3/SHA3_384Monte.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHA3/SHA3_384ShortMsg.rsp b/vectors/cryptography_vectors/hashes/SHA3/SHA3_384ShortMsg.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHA3/SHA3_512LongMsg.rsp b/vectors/cryptography_vectors/hashes/SHA3/SHA3_512LongMsg.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHA3/SHA3_512Monte.rsp b/vectors/cryptography_vectors/hashes/SHA3/SHA3_512Monte.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHA3/SHA3_512ShortMsg.rsp b/vectors/cryptography_vectors/hashes/SHA3/SHA3_512ShortMsg.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHAKE/SHAKE128LongMsg.rsp b/vectors/cryptography_vectors/hashes/SHAKE/SHAKE128LongMsg.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHAKE/SHAKE128Monte.rsp b/vectors/cryptography_vectors/hashes/SHAKE/SHAKE128Monte.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHAKE/SHAKE128ShortMsg.rsp b/vectors/cryptography_vectors/hashes/SHAKE/SHAKE128ShortMsg.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHAKE/SHAKE128VariableOut.rsp b/vectors/cryptography_vectors/hashes/SHAKE/SHAKE128VariableOut.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHAKE/SHAKE256LongMsg.rsp b/vectors/cryptography_vectors/hashes/SHAKE/SHAKE256LongMsg.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHAKE/SHAKE256Monte.rsp b/vectors/cryptography_vectors/hashes/SHAKE/SHAKE256Monte.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHAKE/SHAKE256ShortMsg.rsp b/vectors/cryptography_vectors/hashes/SHAKE/SHAKE256ShortMsg.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/hashes/SHAKE/SHAKE256VariableOut.rsp b/vectors/cryptography_vectors/hashes/SHAKE/SHAKE256VariableOut.rsp old mode 100755 new mode 100644 diff --git a/vectors/cryptography_vectors/pkcs7/amazon-roots.p7b b/vectors/cryptography_vectors/pkcs7/amazon-roots.p7b new file mode 100644 index 000000000000..cb027da5aa53 Binary files /dev/null and b/vectors/cryptography_vectors/pkcs7/amazon-roots.p7b differ diff --git a/vectors/cryptography_vectors/pkcs7/enveloped.pem b/vectors/cryptography_vectors/pkcs7/enveloped.pem new file mode 100644 index 000000000000..7c7d5b75c997 --- /dev/null +++ b/vectors/cryptography_vectors/pkcs7/enveloped.pem @@ -0,0 +1,91 @@ +-----BEGIN PKCS7----- +MIIQjQYJKoZIhvcNAQcDoIIQfjCCEHoCAQAxggLCMIIBXQIBADBFMC0xKzApBgNV +BAMTIlNhbXBsZSBMQU1QUyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkCFCJT7jBtAgsf +As31ycE+Ot95phvCMA0GCSqGSIb3DQEBAQUABIIBAFbDR6j4ZB/Mo9BQygYItwFc +P+4rO4d1ak51hc1DpSqyhiMcGahA3yxDRbZ4W1rbmC/s3d5+OWXKYgs1nNMQJ48F +f45BtNTNslPZ1+NZVbkoVJO8Bxv1rjB8/qWuSUsroqzn9enS8DUBxxPL5aSWKQQN +G2IaH9BUkMXLPUYA46GATly94IS4fZqwBtNNBP5eiIIPc9Ogjy+7At5GG7rVMN0M +G5FL0oq52SYUe1167jp378JI+2dkA1q5+Cru/ZE2Rdw3DrMDAFO5GwC7fWKg4zPm +IHZj92caVj1IyfTmGogT2o5tLMqn61BkptqxZwHDr3FI/aYo4vcHgmlKR/TdbHww +ggFdAgEAMEUwLTErMCkGA1UEAxMiU2FtcGxlIExBTVBTIENlcnRpZmljYXRlIEF1 +dGhvcml0eQIUZ4K0WXNSS8H0cUcZavD9EYqqTAswDQYJKoZIhvcNAQEBBQAEggEA +hXeYVSUsT1EBZ/+AjwyEcnlM0kuFMaNvGlBMhAZzAsy012rrZTWbqWkcA3abgm/M +CuZX7mQL0I79KZdmClGpLx6gQFjLemHaClQV0ZNdX4DxakWuME/kCMqbo4MZXStT +a0MHlKUdoMt72Rz4YBzNQCL7ePaii5w6Nd2KD7yJAirLYUMJEjVweVaMI9y9LmbO +vb0g0iuoUe0vp9B20LRcIX37nN5D1GG4tHLPjBD43gC8iqxZQf0uah2cWD1mAG5R +oBgIDKXPy2eVbcMdSaOirDKYZ49WFe9Lad9q3mHHbFs6K6/yuBm/thMEdCJKZTHo +jiPvYdYF8IJfEd368I+DujCCDa0GCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIsb1a +JX/RU9aAgg2I0VXWfs5fc/Yad2qvawUVNX+LObjA6/+t9WxuV2emOeBYzQGjo7q+ +xaIXQwbbF1ej27efGhxUYDwBNS56c0uI0Ta7jxv5OFZhzQGLRzoFp0bbZ+uVC4eP +bFHarRQiPzlg900XASO0RW+UOtqN5raZ3Ry2lKwXxuStZ0pX666Rz4c8PrmMb4/B +aQYn6iKcT6fDU2TpSbWY9iph6kZczSeewK+pIj9nXfjDKXScs8D2Raezev2ciq/V +ZRpRH8JxieimI2yeBmEzTCq11TDYycDfMHB6reGaiCGX//8kAWtskzRyNlV61unY +ZKSNhVKLwKmCQh1V1Nd3oLApT41EeM2oWedUqNBYqB+XGCD4DUYdm1e+4h73d4dn +JTkCdadxEn+9RRvZ4YMlw3mvT997Dy3rTXT29dj14TstZZf2O63pY0TpYy0HZy6Z +Jug1qoe/vdcJ9SPOSfJE6VWCeVjxB+eGgheFLKqzK8Hs/Bm0/wDKpSFgEpOPnkJ4 +HJ2Uzgn1Emo6gBDJt+qn3s2UnowcMsTgellhKvgzVq59LTyRyWL5U8XMBsXT4qjm +0LkRvDkOIjMQH7kqvWbpPlnWpLKo/VVoxifldEegWAqFVrP7f5Y+nNQttAYV79uk +MXvR+5YFkvmQAerfllPqXBJdbB65ovikSVsy/kAboGpRG1oAZ4ODdwdGyiGIzyyc +lE0x/8+gY8BqWzRtWX4GySKyZ50/+xkJe5ss0IXPCgq/09bdihsRn57v4V4SpdDO +k3g/Dce+LzCRL8uTbUhrhZnjKSjRc3fFaD/BpLYjEDbnGF0ICslN3vb2xWUK1u4M +uUH9r7lH/DCb0+TxIBtxOnP7W02bz8gGJAxEVEqk6pjxxOYqfS9/uBrrAY8P21Y9 +PFLdeHzEdYemq3il+4S7OU3uNUuAYijxmCRs7JQxZ9puA0iaTME9gK1yikzsLtVZ +f+9osk2nYgfXvlL0AiYabd5cU2GNW33TkdDMNBsB7lx77J9erVLZpPKNo4vgHA7b +owrDaYe0AgcZm79fvmR0RdtIZI91MouEhkdhaPiXmypmszjR/M0Ot3Y+oU/ks+yV +Sle0S0h4V8wJRJYG/9VVurm8012ke2U3EGFlVnSv/IYtpssC+U4McRCmakKCrGU7 +OhL5JKBQN/DFTu4pV39IQlLLhg3wzA2FSkyIL5gEbS6sP9GTPo5LlNm2nYfJQX9A +sHKSrfh68dvjSNExxi/8hdmFnnRwbAnUCI/WObGOkKdheOfdQ1AAHtLO7G65X1Cx +RctbAJWa93M+iRUN6qnB+vIbPPnI1Mc7i6mPYzgtPrM9bYqEZz69pQtHcGTfxOrU +tm+/h36CRzJBfXodBZbwQ9mZAzfkKdlArlZYIeBUw3ORQnQ7UlJgG8KsZpUhTxCc +gvMoExtlvkXcYLRUBFfZWyOi6FePzQjuCK1w58OdweJgXprEAWSvyxhmVdg4jUpX +MYKE0tZI9xwujyWjACO0myYqTdmsqyds+BgfBn96XiA9OFUH2C0/GAomhNs8uPSO +T3Gt7Ld/FByxEVrtl9A37X6bAwZO01j5tHmdXFPmMVep0R8zsWtPn3RyGAjcgcq6 +50wJRwhvofdI7wilZ0KUBsAaPj3MK52cRyD19VXKNNwt2bLDV6gcWQ8+QEMusxfp +1Dc9N9DSs+w3lGsFfpoeQ53/fXcVNJm6Bv89bH9anLGYdCdRGvZsvw+xRuglykqb +xLtL2lB6wzlRFREJoWTzCVsdpIZ8znPmk1cB0wDlbMeu6sddHmv+6fpyuvQfQmdj +D8WLRTuyxax94TmBlhJCFYxmO/y4Ivlx5C60GIRTkHpBYL/M0RjrbIszXEqcogzU +bdwjLIhdEnpJ5vy0uXwhltce8BDpenmHE7y1kHvPBiUG3vB7AIXqhohFsJU3AYUj +d1TvFKS2AsizUTLuq0Ydbnz3AxMfmnZe8qYkNu2zRygL2xTa58f/MwsHKakk3OmS +9JFZLrkkVWZKXoARctuahYtWBAsykaWVNnB6zGcdX1MGVccl930Z6QWHyydtZpQc +ivNdEGdGv9B0K7/ngNdVgD5Wd29AMMFnS8+55mLfRZDCjUmshSySaf6Ein4HD9Hr +vk6dJvBPjnI5UjeUPjmH+wcZKIjLHW/aV/6/zoxzBh61rWFlr/daec+CFZE/+epr +LRRYSmv8oY47fF4duDDhoexcvP/CH+A2Hr40OfciL4vKy3nuUDCNa59xO9JWv4NL +n3MQypC9bcaVPkXa7TK3ECq1Jgv8gwfdh5/ovG5OdZA4uIcO+aqcskt/PD252c63 +0Znww3RXXf46KT4GdKO5A377ixkUMkznnCMvottmkPxjnhQjAsQg3bJeQk8EoX8f +Pq0If4i7SRBSDtb2OH1pPmk0RVPtxlRDTVj3vS3Lci4xADFgC09n9nIvPO/55aau +O6StbJtLmpubS5giuDH3uftwuyRiLqm3gtbSKPdoTk+dJhHXbbpBknL4XYTPxSsR +IIaRds6w30vf7/IscyunMcquJlsO929SSa93UevKEIZbqbV9oGIqwkiUMdVZK09g +rW0F//Ts4a5nYdEQth/fq3JnwqeHvvUfKdasK4TtrTnUBX7qZk/K3Y1fZwjKdd/8 +t9t1z7Kb2d9hWwtY7xP8liDluVFTsq8NM54ZC2218X5ViWz1yFmF2LXvRixsmYJv +Tz8lUUnC2B/Etm1kkU4zrYK0/L77EikKVl+B7BXfEqx6ow41j7e1YZYaqmZ9mph+ +UieSdzqVYxhPwT25DrkU3r74iS28gKsbFhUaNklaFOO5iDWsKgBXT+wdZqlYQ6Fo +oPe66025iJMwK8t+d53jEduHezHO2sTMAuf2hpdaZo7+rP/hRTReAR6CmI7nkWhP +z5Kno9S+XhiSP+WTSpsoA4ubx0T94mL8NOVvSZA76TZ3ObVAP5VI/bwv6Grighor +Kpsjt7dhSJRv+RHv95sAWBeW1Fgv8XOPSAZOmpJV2qc3x3Qmj0MXIR+7+3GlUr8+ +Dit3CE1hwtxgOW0tc8kuBTfQD+wNSa9r0eUyFscEBBljpEVbLjgjVdNv4Hc+fsbT +g1JzZuUIDQZoEO2xLjxD+I7vLZKQa0J1JeZ7O+NqmSxsvSnwCWtJEWNMMxYNfwsP +rdj1zPLqn3rzSBqhroNbaDGn86BTwIqfhr+AKbvevxS6bI8IbyKm9u3BFr9cuawx +Sp1QM3NtqNStV67qR4A6U/ZyPUJdO1bxo8F3oRmJqOt7Jc93rFgkhBJ2+eMtrA75 +Om5tB9LBVSl5U5yLP0COO1QE5pqk5yuhJLT9Dyss8bWDRbSWKj83e4YXhPnq71Bm +001czylLVNUlDc69Tf7FXjtIxh2yjvOT3zeLBPXOjU0it+gAma4vgrh8/mMXnNiq +OLsVow8aKqm+Ofd6m13K5riDFgXgNI9lbvPKUSWlEqDMEqXk1oAqD4Nb5NTGSFpQ +Q4G+cHAxJCu7vcXBaZnP8uMP5IAkdg5jIPvvMRwg/aqkl/KbL98oYZ5+1xrOMuKA +LT1uCJ4MMB0lWsa1He4jPe8LneSupw7vAXlbo2VzcOI6oCSY5hV+cGQRY+LjW81q +Cu5nLq8bwgnZMSlPmwr0YrKmvh8YKyGOrmTadxykC5IC+XbrLDsw2Jd9mLIjUQ/V +4ibjeb+e0QGob22WOplCLnHGW/SnYei8KG1dxs/ahS+8vQdrI880ZJx2QJnrz0Ej +ux6tKv4mvUkqYA5hlTFeT3PTr54yA+YLcCLMfBDx4ykPQnYUBj7ONHuNSUYt1CJy +faZ7cWAbhgH+wlTFdVBVeW5D4FRbM8dMTPXyfC5ygwTJOiDu3vQKyyDkmiX7sEaC +P1JN2V55uacyR8ZAG5+Mlc4ZMx83kAIZZXTCdqa1EX8yda31FI2rDHmvW/82bmjL +pvI4Nnn9+zzJtDVCJ0B2VAZ3Edov5GzPikm3un4+mvyhUZpH4sbT0+VhPCsr1+zn +bDJyNw4AswxaaJKh2+7wBiU6h+9TP/lI8SAJHtZL7zHBH8tD10ptksLRWDs9vYqp +/3T86S2vxJL5DvLFJSAZrYOE3InS+keGmTMCdAl9I8zIworC/8uQp0N8ESebEVjA +aHotBk59lj/OW4JZ3tQkcdQWkpnUfW/x9xE2wthacHlRzYDDsFByjEqkQr0MU8VF +EGij9RCC97zyFrhv0xJm1C6wX0pcuEcuPTNBf38WyBTIfmVHHz/I5YKk5cdWG7Hq +fmccV5GKrs2BseR683HM+/u50sq0km9UrqjgFR1DjfDoRKp0guP9PqkJAnwG2nv1 +hmNtXumzkF0otP5LDKLJ84MGP8Wnb006iEdD48Lra+clRAIIuLX4A0wRQjViDp7n +OByI6ZcQd4DTMHnFPRvMkNMLYn13LghD6P9TTjQZ0KCOCwmc2TMCIhJlvzOYX6Cc +wJZYLO1ltgfnHEuh8ijv0u3d/BUpsknYKBSJGUyMEZ9iUtbFPVfXBGSTi3gcWHtl +IrM7wjswJwHWSvZKWUs+YWWJTwj0apG6ViGllwOAqR9C48uLKgFWPbMoTpolnp69 +eiij5ZHxB0i7SI80D+r65b+fqaFzVIJXVEI0zu/mIilbYBnGkhLI/Naw1m2e1qVJ +mi1JBjXLAT3pEJDh8b3Lpgw= +-----END PKCS7----- diff --git a/vectors/cryptography_vectors/pkcs7/isrg.pem b/vectors/cryptography_vectors/pkcs7/isrg.pem new file mode 100644 index 000000000000..63698aa11348 --- /dev/null +++ b/vectors/cryptography_vectors/pkcs7/isrg.pem @@ -0,0 +1,33 @@ +-----BEGIN PKCS7----- +MIIFngYJKoZIhvcNAQcCoIIFjzCCBYsCAQExADAPBgkqhkiG9w0BBwGgAgQAoIIF +bzCCBWswggNToAMCAQICEQCCEM+w0kDjWURj4LtjgosAMA0GCSqGSIb3DQEBCwUA +ME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBTZWN1cml0eSBSZXNl +YXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgxMB4XDTE1MDYwNDExMDQz +OFoXDTM1MDYwNDExMDQzOFowTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVy +bmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3Qg +WDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1co +HIe+3LffOJCMbjzmV6B493XCov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZsh +ftEzPLpI9d1537O4/xLxIZpLwYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+ +lAOf00eXfJlII1PoOK5PCm+DLtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vr +Fk/CjhFLfs8L6P+1dy70sntK4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6s +hweU9GNx7C7ib1uYgeGJXDR5bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98fl +AgeYjzYIlefiN5YNNnWe+w5ysR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81 +LygXbNKYwagJZHduRze6zqxZXmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1 +pzpRboY7nn1ypxIFeFntPlF4FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0 +544fAQjQMNRbcTa0B7rBMDBcSLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K2 +8Kh8hjtGqEgqiNx2mna/H2qlPRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdw +iK1O5tmLOsbdJ1Fu/7xk9TNDTwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUebRZ5nu25eQBc4AIiMgaWPbpm24wDQYJ +KoZIhvcNAQELBQADggIBAFUfWKm8sqhQ0Ayx2BppICcpCKxhdVyKbviC5Wkv1fZW +S7m4cxBZ0yGXfudMcfuy0mCtOagL6hchVoXxUA5Z687gWem6yRXvhp2PhID25OmR +kNwXm2IbRfBmldJ8b8LqO+8fz8vWrifxqbDIrv19fpr6IgTr/9l/6pErIrEXDo/y +ijRbWNj8AclUubgmzIqIM4lMLYQ8gt/ullcFuiy798S3x047gr4xyCJzc5LRwoCk +OTkQMyOCTDyfhrJVmB2+KYaMIpue4ms7VzqCcE3cCceJywoHTWzoXY7J786rx7u1 +K05F1krQJszlcsoIaqWV4xWh96TtySxfpfv/rCgCLr7Xe7vjcXuQFtMHXkZTfDcH +QozTxJac1Zm1KuCVGoBIrkw5B87MR6RSlSu6uPut0jNTfeUdTW3VobHHQm/mQCc1 +XKMotweN540zkOcjn/tQnHlsRtW0FbOWbn6bDJY6uFItP9Zb4fsIwoT+JKijidqs +auEYKrGoQ2Fb0x/cO4128i3ojXXfFzNsPVP7e8tBX//cotBhOOGWuKxdizfXddUz +wJkRrp1BwXJ1hL4CQUJfZyRIlNGbJ74HP7m4T4F0UeF6t+2dI+K+4NUoBBM8MQOe +3Xpsj8YHGMZ/3keOPyieBAbPpVQ0d73siZvpF0PfW9tf/o4eV6LNQJ1+YiLa3hgn +MQA= +-----END PKCS7----- diff --git a/vectors/cryptography_vectors/poly1305/rfc7539.txt b/vectors/cryptography_vectors/poly1305/rfc7539.txt new file mode 100644 index 000000000000..9ad13a5693d2 --- /dev/null +++ b/vectors/cryptography_vectors/poly1305/rfc7539.txt @@ -0,0 +1,56 @@ +# These vectors converted into NIST form from RFC 7539 + +COUNT = 0 +KEY = 0000000000000000000000000000000000000000000000000000000000000000 +MSG = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +TAG = 00000000000000000000000000000000 + +COUNT = 1 +KEY = 0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e +MSG = 416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e7472696275746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e20224945544620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c2073746174656d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c656374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207768696368206172652061646472657373656420746f +TAG = 36e5f6b5c5e06070f0efca96227a863e + +COUNT = 2 +KEY = 36e5f6b5c5e06070f0efca96227a863e00000000000000000000000000000000 +MSG = 416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e7472696275746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e20224945544620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c2073746174656d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c656374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207768696368206172652061646472657373656420746f +TAG = f3477e7cd95417af89a6b8794c310cf0 + +COUNT = 3 +KEY = 1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0 +MSG = 2754776173206272696c6c69672c20616e642074686520736c6974687920746f7665730a446964206779726520616e642067696d626c6520696e2074686520776162653a0a416c6c206d696d737920776572652074686520626f726f676f7665732c0a416e6420746865206d6f6d65207261746873206f757467726162652e +TAG = 4541669a7eaaee61e708dc7cbcc5eb62 + +COUNT = 4 +KEY = 0200000000000000000000000000000000000000000000000000000000000000 +MSG = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +TAG = 03000000000000000000000000000000 + +COUNT = 5 +KEY = 02000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +MSG = 02000000000000000000000000000000 +TAG = 03000000000000000000000000000000 + +COUNT = 6 +KEY = 0100000000000000000000000000000000000000000000000000000000000000 +MSG = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11000000000000000000000000000000 +TAG = 05000000000000000000000000000000 + +COUNT = 7 +KEY = 0100000000000000000000000000000000000000000000000000000000000000 +MSG = FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFEFEFEFEFEFEFEFEFEFEFEFEFEFEFE01010101010101010101010101010101 +TAG = 00000000000000000000000000000000 + +COUNT = 8 +KEY = 0200000000000000000000000000000000000000000000000000000000000000 +MSG = FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +TAG = FAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + +COUNT = 9 +KEY = 0100000000000000040000000000000000000000000000000000000000000000 +MSG = E33594D7505E43B900000000000000003394D7505E4379CD01000000000000000000000000000000000000000000000001000000000000000000000000000000 +TAG = 14000000000000005500000000000000 + +COUNT = 10 +KEY = 0100000000000000040000000000000000000000000000000000000000000000 +MSG = E33594D7505E43B900000000000000003394D7505E4379CD010000000000000000000000000000000000000000000000 +TAG = 13000000000000000000000000000000 diff --git a/vectors/cryptography_vectors/x509/custom/ca/rsa_ca.pem b/vectors/cryptography_vectors/x509/custom/ca/rsa_ca.pem new file mode 100644 index 000000000000..089bcce10e72 --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/ca/rsa_ca.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIExzCCAq+gAwIBAgIJAOcS06ClbtbJMA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNV +BAMMD2NyeXB0b2dyYXBoeSBDQTAeFw0yMDA5MTQyMTQwNDJaFw00ODAxMzEyMTQw +NDJaMBoxGDAWBgNVBAMMD2NyeXB0b2dyYXBoeSBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANBIheRc1HT4MzV5GvUbDk9CFU6DTomRApNqRmizriRq +m6OY4Ht3d71BXog6/IBkqAnZ4/XJQ40G4sVDb52k11oPvfJ/F5pc+6UqPBL+QGzY +GkJoubAqXFpI6ow0qayFNQLv0T9o4yh0QQOoGvgCmv91qmitLrZNXu4U9S76G+Di +GST+QyMkMxj+VsGRsRRBufV1urcnvFWjU6Q2+cr2cp0mMAG96NTyIskYiJ8vL03W +z4DX4klO4X47fPmDnU/OMn4SbvMZ896j1L0J04S+uVThTkxQWcFcqXhX5qM8kzcj +JUmybFlbf150j3WiucW48K/j7fJ0x9q3iUo4Gva0coScglJWcgo/BBCwFDw8NVba +7npxSRMiaS3qTv0dEFcRnvByc+7hyGxxlWdTE9tHisUI1eZVk9P9ziqNOZKscY8Z +X1+/C4M9X69Y7A8I74F5dO27IRycEgOrSo2z1NhfSwbqJr9a2TBtRsFinn8rjKBI +zNn0E5p9jO1WjxtkcjHfXXpLN8FFMvoYI9l/K+ZWDm9sboaF8jrgozSc004AFemA +H79mmCGVRKXn1vDAo4DLC6p3NiBFYQcYbW9V+beGD6srsF6xJtuY/UwtPROLWSzu +CCrZ/4BlmpNsR0ehIFFvzEKjX6rR2yp3YKlguDbMBMKMpfSGxAFwcZ7OiaxR20UH +AgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBADSveDS4 +y2V/N6Li2n9ChGNdCMr/45M0cl+GpL55aA36AWYMRLv0wip7MWV3yOj4mkjGBlTE +awKHH1FtetsE6B4a7M2hHhOXyXE60uUdptEx6ckGrJ1iyqu5cQUX1P+VnXbmOxfF +bl+Ugzjbgirx239rA4ezkDRuOvKcCbDOFV/gw3ZHfJ/IQeRXIQRl/y51wcnFUvFM +JEESYiijeDbEcY8r1/phmVQL0CO7WLMmTxlFj4X/TR3MTZWJQIap9GiLs5+n3QiO +jsZ3GuFOomB8oTebYkXniwbNu5hgLP/seRQzGA7B9VDZryAhCtvGgjtQh0eW2Qxt +sgmDJGOPKnKT3O5U0v3+IPLEYpe8JSzgAhhh6H1rAJRUNwP2gRcO4eOUJSkdl218 +fRNT0ILzosuWxwprER9ciMQF8q0JJKMhcfHRMH0S5mWVJAIkj68KY05oCy2zNyYa +oruopKSWXe0Bzr40znm40P7xIkui2BGQMlDPpbCaEfLsLqyctfbdmMlxac/QgIfY +TltrbqmI3MNy5uqGViGFpWPCB+kD8EsJF9nlKJXlu/i55qgUr/2/2CdeWlZDBP8A +1fdzmpYpWnwhE0KobzLS2z3AwDxiY/RSWUfypLZA0K/lpaEtYB6UHMDZ0/8WqgZV +gNucCuty0cA4Kf7eX1TlAKVwH8hTkVmJc2rX +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/custom/ca/rsa_key.pem b/vectors/cryptography_vectors/x509/custom/ca/rsa_key.pem new file mode 100644 index 000000000000..97e39a501f20 --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/ca/rsa_key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDQSIXkXNR0+DM1 +eRr1Gw5PQhVOg06JkQKTakZos64kapujmOB7d3e9QV6IOvyAZKgJ2eP1yUONBuLF +Q2+dpNdaD73yfxeaXPulKjwS/kBs2BpCaLmwKlxaSOqMNKmshTUC79E/aOModEED +qBr4Apr/daporS62TV7uFPUu+hvg4hkk/kMjJDMY/lbBkbEUQbn1dbq3J7xVo1Ok +NvnK9nKdJjABvejU8iLJGIifLy9N1s+A1+JJTuF+O3z5g51PzjJ+Em7zGfPeo9S9 +CdOEvrlU4U5MUFnBXKl4V+ajPJM3IyVJsmxZW39edI91ornFuPCv4+3ydMfat4lK +OBr2tHKEnIJSVnIKPwQQsBQ8PDVW2u56cUkTImkt6k79HRBXEZ7wcnPu4chscZVn +UxPbR4rFCNXmVZPT/c4qjTmSrHGPGV9fvwuDPV+vWOwPCO+BeXTtuyEcnBIDq0qN +s9TYX0sG6ia/WtkwbUbBYp5/K4ygSMzZ9BOafYztVo8bZHIx3116SzfBRTL6GCPZ +fyvmVg5vbG6GhfI64KM0nNNOABXpgB+/ZpghlUSl59bwwKOAywuqdzYgRWEHGG1v +Vfm3hg+rK7BesSbbmP1MLT0Ti1ks7ggq2f+AZZqTbEdHoSBRb8xCo1+q0dsqd2Cp +YLg2zATCjKX0hsQBcHGezomsUdtFBwIDAQABAoICAQDH6YQRvwPwzTWhkn7MWU6v +xjbbJ+7e3T9CrNOttSBlNanzKU31U6KrFS4dxbgLqBEde3Rwud/LYZuRSPu9rLVC +bS+crF3EPJEQY2xLspu1nOn/abMoolAIHEp7jiR5QVWzXulRWmQFtSed0eEowJ9y +qMaKOAdI1RRToev/TfIqM/l8Z0ubVChzSdONcUAsuDU7ouc22r3K2Lv0Nwwkwc0a +hse3NEdg9JNsvs6LM2fM52w9N3ircjm+xmxatPft3HTcSucREIzg2hDb7K2HkOQj +0ykq2Eh97ml+56eocADBAEvO46FZVxf2WhxEBY8Xdz4VJMmDWJFmnZj5ksZWmrX6 +U5BfFY7DZvE2EpoZ5ph1Fm6dcXrJFkaZEyJLlzFKehXMipVenjCanIPpEEUvIz+p +m0QVoNJRj/GcNyIEZ0BCXedBOUWU4XE1pG4r6oZqwUvcjsVrqXP5kbJMVybiS6Kd +6T8ve+4qsn3ZvGRVKjInqf2WI0Wvum2sTF+4OAkYvFel9dKNjpYnnj4tLFc/EKWz +9+pE/Zz5fMOyMD9qXM6bdVkPjWjy1vXmNW4qFCZljrb395hTvsAPMsO6bbAM+lu6 +YcdOAf8k7awTb79kPMrPcbCygyKSGN9C9T3a/Nhrbr3TPi9SD9hC5Q8bL9uSHcR2 +hgRQcApxsfDRrGwy2lheEQKCAQEA/Hrynao+k6sYtlDc/ueCjb323EzsuhOxPqUZ +fKtGeFkJzKuaKTtymasvVpAAqJBEhTALrptGWlJQ0Y/EVaPpZ9pmk791EWNXdXsX +wwufbHxm6K9aOeogev8cd+B/9wUAQPQVotyRzCcOfbVe7t81cBNktqam5Zb9Y4Zr +qu63gBB1UttdmIF5qitl3JcFztlBjiza2UrqgVdKE+d9vLR84IBRy3dyQIOi6C1c +y37GNgObjx8ZcUVV54/KgvoVvDkvN6TEbUdC9eQz7FW7DA7MMVqyDvWZrSjBzVhK +2bTrd+Pi6S4n/ETvA6XRufHC8af4bdE2hzuq5VZO1kkgH37djwKCAQEA0y/YU0b4 +vCYpZ1MNhBFI6J9346DHD55Zu5dWFRqNkC0PiO6xEMUaUMbG4gxkiQPNT5WvddQs +EbRQTnd4FFdqB7XWoH+wERN7zjbT+BZVrHVC4gxEEy33s5oXGn7/ATxaowo7I4oq +15MwgZu3hBNxVUtuePZ6D9/ePNGOGOUtdMRrusmVX7gZEXxwvlLJXyVepl2V4JV1 +otI8EZCcoRhSfeYNEs4VhN0WmfMSV7ge0eFfVb6Lb+6PCcasYED8S0tBN2vjzvol +zCMv8skPATm7SopqBDoBPcXCHwN/gUFXHf/lrvE6bbeX1ZMxnRYKdQLLNYyQK9cr +nCUJXuNM21tVCQKCAQBapCkFwWDF0t8EVPOB78tG57QAUv2JsBgpzUvhHfwmqJCE +Efc+ZkE2Oea8xOX3nhN7XUxUWxpewr6Q/XQW6smYpye8UzfMDkYPvylAtKN/Zwnq +70kNEainf37Q6qAGJp14tCgwV89f44WoS7zRNQESQ2QczqeMNTCy0kdFDn6CU2ZL +YMWxQopTNVFUaEOFhympySCoceTOmm/VxX22iXVrg6XZzgAOeTO69s4hoFm4eoMW +Vqvjpmi4wT6K1w2GjWEOMPDz6ml3rX2WkxCbu5RDA7R4+mM5bzBkcBYvImyGliGY +ZSGlx3mnbZhlkQ3Tg+IESt+wnRM1Uk7rT0VhCUKxAoIBABWYuPibM2iaRnWoiqNM +2TXgyPPgRzsTqH2ElmsGEiACW6pXLohWf8Bu83u+ZLGWT/Kpjg3wqqkM1YGQuhjq +b49mSxKSvECiy3BlLvwZ3J0MSNCxDG0hsEkPovk0r4NC1soBi9awlH0DMlyuve+l +xVtBoYSBQC5LaICztWJaXXGpfJLXdo0ZWIbvQOBVuv4d5jYBMAiNgEAsW7Q4I6xd +vmHdmsyngo/ZxCvuLZwG2jAAai1slPnXXY1UYeBeBO72PS8bu2o5LpBXsNmVMhGg +A8U1rm3MOMBGbvmY8/sV4YDR4H0pch4yPja7HMHBtUQOCxXoz/2LvYv0RacMe5mb +F3ECggEAWxQZnT8pObxKrISZpHSKi54VxuLYbemS63Tdr4HE/KuiFAvbM6AeZOki +jbiMnqrCTOhJRS/i9HV78zSxRZZyVm961tnsjqMyaamX/S4yD7v3Vzu1mfsdVCa2 +Sl+JUUxsEgs/G3Fu6I/0TsCSn/HgNLM8b3f8TDkbpnOqKX165ddojXqSCfxjuYau +Szih/+jF1dz2/zBye1ARkLRdY/SzlzGl0cVn8bfkE0YEde7wvQ624Biy7r9i1o40 +7cy/8EQBR2FcXpOAZ7UgOqgGLNhXnd4FPsX4ldKOf5De8FErQOFirJ8pCUxFGr0U +fDWXtBuybAb5u+ZaVwHgqaaPCkKkVQ== +-----END PRIVATE KEY----- diff --git a/vectors/cryptography_vectors/x509/custom/crl_delta_crl_indicator.pem b/vectors/cryptography_vectors/x509/custom/crl_delta_crl_indicator.pem index f49da4c8b60a..d919c37061e7 100644 --- a/vectors/cryptography_vectors/x509/custom/crl_delta_crl_indicator.pem +++ b/vectors/cryptography_vectors/x509/custom/crl_delta_crl_indicator.pem @@ -1,11 +1,11 @@ -----BEGIN X509 CRL----- -MIIBfTBnAgEBMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMMEmNyeXB0b2dyYXBo -eS5pbyBDQRcNMDIwMTAxMTIwMTAwWhcNMzAwMTAxMTIwMTAwWqAWMBQwEgYDVR0b -BAsCCQCrVKmM6x8K0jANBgkqhkiG9w0BAQsFAAOCAQEAUEE3Z8rgIZYo1YK0wZ2X -bz9NnnE/X1YZQZ/IO/mSsz/k2d5XhLwa53zMlvX7J3UFEjEp+82b+gCMvgpJzTBq -a/XnifnA8lnFJmPiLB1JgRm2/GsXxkws3ziH5D/6yRdV3MDRQzRg610GayF+LfrF -74kMns0a1TaOfRhw1APiDvJLngElvcutBS3/mgr+SPPdDgFJ++PSrWOdAw4vo4HH -TTxduelWWDag2Bg0L90Td8Cdv57jgbCjSwWPSLqfwq674cDxotYABqtLg1Q5jeg2 -GIzEZqYXWvxMc87pQLRwrxG2+U4p+hDpx3TTIn2uyxDTihXvWKmiqzpOiXJKixe5 -Jw== +MIIBlDB+AgEBMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMMEmNyeXB0b2dyYXBo +eS5pbyBDQRcNMDIwMTAxMTIwMTAwWhcNMzAwMTAxMTIwMTAwWqAtMCswEgYDVR0U +BAsCCQCrVKmM6x8K0zAVBgNVHRsBAf8ECwIJAKtUqYzrHwrSMA0GCSqGSIb3DQEB +CwUAA4IBAQBQQTdnyuAhlijVgrTBnZdvP02ecT9fVhlBn8g7+ZKzP+TZ3leEvBrn +fMyW9fsndQUSMSn7zZv6AIy+CknNMGpr9eeJ+cDyWcUmY+IsHUmBGbb8axfGTCzf +OIfkP/rJF1XcwNFDNGDrXQZrIX4t+sXviQyezRrVNo59GHDUA+IO8kueASW9y60F +Lf+aCv5I890OAUn749KtY50DDi+jgcdNPF256VZYNqDYGDQv3RN3wJ2/nuOBsKNL +BY9Iup/CrrvhwPGi1gAGq0uDVDmN6DYYjMRmphda/ExzzulAtHCvEbb5Tin6EOnH +dNMifa7LENOKFe9YqaKrOk6JckqLF7kn -----END X509 CRL----- diff --git a/vectors/cryptography_vectors/x509/custom/negative_serial.pem b/vectors/cryptography_vectors/x509/custom/negative_serial.pem new file mode 100644 index 000000000000..0994f9a25115 --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/negative_serial.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIELDCCAxSgAwIBAgIF+86ZbBMwDQYJKoZIhvcNAQELBQAwUjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDU1vdGhlciBOYXR1cmUxEzARBgNVBAsTCkV2ZXJ5dGhpbmcx +FjAUBgNVBAMTDU1vdGhlciBOYXR1cmUwHhcNMTYwNzA2MTgzNDA2WhcNMTYwOTE4 +MTgzNDA2WjCBmTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkZMMRQwEgYDVQQHEwtU +YWxsYWhhc3NlZTEcMBoGA1UECRMTMzIxMCBIb2xseSBNaWxsIFJ1bjEOMAwGA1UE +ERMFMzAwNjIxGDAWBgNVBAoTD0V4dHJlbWUgRGlzY29yZDEOMAwGA1UECxMFQ2hh +b3MxDzANBgNVBAMTBmdvdi51czCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMu6VH/JvcG/foNel5R3NHz/OeI9fqHyoPB6d/wQ1k/aVGNotSzVaDCJPY3J +xmr1KCnNjzGmViuaLXyZWZEMum2R8D0+LX1PHBQl2vbrXSOMDu97c323QOdTUwMY +C2LmaFP3fa5SV5Q+8+4f/B97wXExOjp1z5z7VafYj2MoY72GitoSfJ/LrkKEksey +fTflVxKEvZqW3wUN6F2Kj4Jo1N45Ym+lIrz/VQKDOSpc/p0dJ1PghDZZ2d2b3iuj +5rCMTw9533WS3wueYfn70jJY9DKoFj9Ly6AG0AB2o7cqTv8j+3slVfAR3ufwgyx2 +ckUDBWCZaZdnhRxaj/G9MMYGEV0CAwEAAaOBwDCBvTAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdIwQHMAWAAwECAzANBgNVHQ4EBgQEBAMCATAbBgNVHREEFDASgggqLmdv +di51c4IGZ292LnVzMAsGA1UdDwQEAwIBhjAgBgNVHSUBAf8EFjAUBggrBgEFBQcD +AQYIKwYBBQUHAwIwPwYDVR0fAQH/BDUwMzAxoC+gLYYraHR0cDovL2NybC5zdGFy +ZmllbGR0ZWNoLmNvbS9zZmlnMnMxLTE3LmNybDANBgkqhkiG9w0BAQsFAAOCAQEA +bfqYztTkJPRPAJ1WItmU3RZIGRx1VkCABouAor6tVH6wGVCwWgaG8li6AujHMfYv +y6QUPhhIyNjTe21ne72BY1XXd9haGdMwXtUCNfeGBXKsR9EN0kDyOAXGZWj3Fqpu +S9WjluPAjQWHFoRwlQBSxCVuRgIrjXhJndvW9ySAaI51epRAr5kwylvTD7qy363C +xDANx5XVFEktclI25DSrxmiJyawVGFjnwaYBFTe2ZINoZvs68EEl1b18+VGF21e9 +BAQGlcsIfbDAAEQFJ+5A+o8zy9M7CVsNVgw3TRJbjVTZSEg5PAEX+3C5V6wzrQi1 +nqzaNa/5DxGWILelZclgvA== +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/custom/rsa_pss.pem b/vectors/cryptography_vectors/x509/custom/rsa_pss.pem new file mode 100644 index 000000000000..cdbc34d5cbb3 --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/rsa_pss.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDLTCCAhWgAwIBAgIUCD6ZpVYd5vCgzRh5ZIqYupE2VKIwDQYJKoZIhvcNAQEK +MAAwJTESMBAGA1UECgwJYm9vdHN0cmFwMQ8wDQYDVQQDDAZyb290Y2EwHhcNMTYw +MTAxMDAwMDAwWhcNNDAwMTAxMDAwMDAwWjAlMRIwEAYDVQQKDAlib290c3RyYXAx +DzANBgNVBAMMBnJvb3RjYTCCAVYwQQYJKoZIhvcNAQEKMDSgDzANBglghkgBZQME +AgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEFAKIDAgEgA4IBDwAwggEK +AoIBAQCuXwLURTDREKWTeBxUQWQvj/hDVc0+PruZtBF5voNAZCjKSOKHFLasmCDw +JuEHjj7ZHDF1JWZVGUbz3p5P+TiFmO/c1Wgb5IyAxdiDUGZvSVX3uC/X8EG/1MQz +bwcDpqiadoIjL59jUJ0g2BJnx81NvpNgpe0rmK7aU52sPKJme31Ttd/lO8VJ3Mps +lzpH0qzDJEcE3+lBF+AOJf2XDbPTFlbuPvDZHE5tVmdYC2IOad8U0Q/FLOhpMFOX +j0n6tKf+Z14+7+xu7RV3gj/NMm0CXWG3ibTSOSrbyvreI0dHgZL57RdqCSE9scjA +/1tD0a7UINhPBDZc6HaUqQUsQCPhAgMBAAGjITAfMB0GA1UdDgQWBBSpiALqV+wo +zwcvMEvwYFLKe/vDPzANBgkqhkiG9w0BAQowAAOCAQEAEdp7sFyQA9g3Vk1KsrAB +UFKqEe1a0azE4TRz2SRktRCswgv7iae0CiBGtPrzBNS6MlketixTfF1npEi7wuDn +/00XRdgHCBIRGvemATx8oSP4qVrHUud2y/DLZOZBGYiasSHHgybsnikFZppGFp7m +1D3Tti+GEsaANwRH5GW7h8f9hTMluwXlnNwyT/83yKq9Uih0eFEWHtf8hFswpCEK +4swEBwBHUiCZs1O702H36xEnoayOWnIWAkV8ZccEjfbCHs+rnU+nGI5UfXg86VRb +9iqcII7xyzPxb/HZRBusI9Uu/xiiqLjWqmx/ZMeadhiQndCoOj2yR8YT+G1BqcLa +pA== +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/custom/sia.pem b/vectors/cryptography_vectors/x509/custom/sia.pem new file mode 100644 index 000000000000..f745674f99af --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/sia.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC7TCCAdWgAwIBAgICAwkwDQYJKoZIhvcNAQELBQAwDTELMAkGA1UEBhMCVVMw +HhcNMTUwMTAxMDAwMDAwWhcNNDAwMTAxMDAwMDAwWjANMQswCQYDVQQGEwJVUzCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF6/H53R0yqWqgwNhWKP/v3 +tSFoUboiMOXWq/zBxs/vWekj6hMwvFk7c4Aqtgim5KMwZSOjEWulqjlmFFF04Tts +Sem3gGLkSdcu+xD9SekfoIuW0FHngun1q8W1pveYSCetuOc9oA8isu/c23bqtG7a +2Y7WVmJ0P9xsDjNqXQzbqn3CnlNjXiTIelssQhWWgGPN62ipcrq7wePP8A+5qA43 +Kk0MLJINHozuMzzkcNwugUWtsFvymu4dJPFB6Mx4SYnFh/xvus2Xnz8hY8HXKZs2 +W8cv/ihI6Weu0eSNzFFbOlDtTeBP0FOEbKEKIjsQzIQcyA/evuRPMRTBPohq9YMC +AwEAAaNXMFUwUwYIKwYBBQUHAQsERzBFMCEGCCsGAQUFBzAFhhVodHRwczovL215 +LmNhLmlzc3Vlci8wIAYDiDcHhhlnb3BoZXI6Ly9pbmZvLW1hYy1hcmNoaXZlMA0G +CSqGSIb3DQEBCwUAA4IBAQB4AdYx02aXDJURPbZNi3j7FnK3LRVvJcq8vRHaG9b4 +soD/7qA8RJX11WTFNDY7g5OQhYT+WBc8OUinJaqJOPvEzgp5Prgq5AlAtcImvNX7 +dI3lr9esZ5gBWbsMK9saNEERhEZDUCSYW/GRMN4yxdUgTDPsfNr8N6bwfnGRR0xM +EBr+p+fT1xth4uren7J/edYrY9a171y6bMdZQ1iVnFH2dFO25D+3k9sM6FRWWsWu +mmrcg79QAl6jqC/6SkqVzpBPzi7dgGYluaKJjREC8e/cMcpphW1TP+8rZ161BmDk +hk5/PrWguFuguWUyEkPH5oqFqoZuqeM0fULxHh2JiqOx +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/ed25519/ed25519-rfc8410.pem b/vectors/cryptography_vectors/x509/ed25519/ed25519-rfc8410.pem new file mode 100644 index 000000000000..3f4b5b2ac79d --- /dev/null +++ b/vectors/cryptography_vectors/x509/ed25519/ed25519-rfc8410.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBLDCB36ADAgECAghWAUdKKo3DMDAFBgMrZXAwGTEXMBUGA1UEAwwOSUVURiBUZX +N0IERlbW8wHhcNMTYwODAxMTIxOTI0WhcNNDAxMjMxMjM1OTU5WjAZMRcwFQYDVQQD +DA5JRVRGIFRlc3QgRGVtbzAqMAUGAytlbgMhAIUg8AmJMKdUdIt93LQ+91oNvzoNJj +ga9OukqY6qm05qo0UwQzAPBgNVHRMBAf8EBTADAQEAMA4GA1UdDwEBAAQEAwIDCDAg +BgNVHQ4BAQAEFgQUmx9e7e0EM4Xk97xiPFl1uQvIuzswBQYDK2VwA0EAryMB/t3J5v +/BzKc9dNZIpDmAgs3babFOTQbs+BolzlDUwsPrdGxO3YNGhW7Ibz3OGhhlxXrCe1Cg +w1AH9efZBw== +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/ed25519/root-ed25519.pem b/vectors/cryptography_vectors/x509/ed25519/root-ed25519.pem new file mode 100644 index 000000000000..e509d540110f --- /dev/null +++ b/vectors/cryptography_vectors/x509/ed25519/root-ed25519.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBODCB66ADAgECAgkAhPEIPRzjLZUwBQYDK2VwMBkxFzAVBgNVBAMMDklFVEYg +VGVzdCBEZW1vMB4XDTE3MDQxOTIxMzYzOVoXDTQxMDIxMjIxMzYzOVowGTEXMBUG +A1UEAwwOSUVURiBUZXN0IERlbW8wKjAFBgMrZXADIQAZv0QJaYTN/oVBusFn3DuW +yFCGqjC2tssMXDitcDFm4aNQME4wHQYDVR0OBBYEFKKMwfhuWWDT4DrnXJYsl6jU +SCk8MB8GA1UdIwQYMBaAFKKMwfhuWWDT4DrnXJYsl6jUSCk8MAwGA1UdEwQFMAMB +Af8wBQYDK2VwA0EAa6iEoQZBWB1MhCzASv5HuFM7fR5Nz2/KM7GxYjQWsfvK2Ds1 +jaPSG7Lx4uywIndMafp5CoPoFr6yLBkt+NZLAg== +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/ed25519/server-ed25519-cert.pem b/vectors/cryptography_vectors/x509/ed25519/server-ed25519-cert.pem new file mode 100644 index 000000000000..729ccfbd06f1 --- /dev/null +++ b/vectors/cryptography_vectors/x509/ed25519/server-ed25519-cert.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICHTCCAQWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290 +IENBMCAXDTE3MDYxNDIzMzExOVoYDzIxMTcwNjE1MjMzMTE5WjASMRAwDgYDVQQD +DAdFZDI1NTE5MCowBQYDK2VwAyEACkEMj+SRLjZSth3SIrG013cyYVN9frrVnfbN +M2IqaT6jdjB0MB0GA1UdDgQWBBQqd22ipNHF0d+yJjFDgI/Jruq3rjAfBgNVHSME +GDAWgBRwfy6ug2hZmAQjKs3rPhfNJN0BSTAJBgNVHRMEAjAAMBMGA1UdJQQMMAoG +CCsGAQUFBwMBMBIGA1UdEQQLMAmCB0VkMjU1MTkwDQYJKoZIhvcNAQELBQADggEB +AIdNMPRa2sgUW/qtCBWxmi0iVRoazl5pjU35cRl/ahBpI4pL5+fDVYuBzSOgEh7W +6FUVix9mGvY9CK3ZkqrXCGRKeWnKrmdql5jrra5Qew43B+aZqa63639TGWqtm7Rk +rWT14P7gma4K9Ea8eiXcT5NJ8sT7D2BOL0sL2alUmRT+k3YDUxiih7AiTkpo7f2Q +x5l9f8qoRb6Skec+kuMQ4hIjBIe/3C+j4nqq9kDkJs8+VEaW7+7shSQzv0tnzBOl +v5ty89x7LYAbGKvZNi8Z3814AWBWbYTskF0kW2/f6aZDpt239llYDazdErU1dEsS +cc1gKHOG3zgz9wfih55M0dE= +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/ed448/root-ed448.pem b/vectors/cryptography_vectors/x509/ed448/root-ed448.pem new file mode 100644 index 000000000000..d1d4eaa9295b --- /dev/null +++ b/vectors/cryptography_vectors/x509/ed448/root-ed448.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBgDCCAQCgAwIBAgICAcAwBQYDK2VxMBgxFjAUBgNVBAMMDUVkNDQ4IERlbW8g +Q0EwIBcNMTkwODE1MTkzNzU2WhgPMjExOTA3MjIxOTM3NTZaMBgxFjAUBgNVBAMM +DUVkNDQ4IERlbW8gQ0EwQzAFBgMrZXEDOgBf10SbWbRh/Sznh+xhatRqHaE0JIWn +Dh+KDqddgOlneO3xJHabRscGG9Z4PfHlD2zR+hq+r+glYYCjUzBRMB0GA1UdDgQW +BBRt4IpyNR7xrevKLNfx/aaRVK36TzAfBgNVHSMEGDAWgBRt4IpyNR7xrevKLNfx +/aaRVK36TzAPBgNVHRMBAf8EBTADAQH/MAUGAytlcQNzAHx1CfZgc40PRGSiZTWC +P8HQAFgAMwIh34cE4WSrb1m8fxv8/uMG0bIvIez/+PMx/ErKPMtyBC2+ACJCCL0Q +In1OC28cIlpXIcQUFXamiGdg1Pd4NqAYl1BVNGWymHxf1AM/NNBPUhYxs1Qw1ape +dJIjAA== +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/ed448/server-ed448-cert.pem b/vectors/cryptography_vectors/x509/ed448/server-ed448-cert.pem new file mode 100644 index 000000000000..740f27554977 --- /dev/null +++ b/vectors/cryptography_vectors/x509/ed448/server-ed448-cert.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICHTCCAQWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290 +IENBMCAXDTE4MDIyNzE1MDcxM1oYDzIxMTgwMjI4MTUwNzEzWjAQMQ4wDAYDVQQD +DAVFZDQ0ODBDMAUGAytlcQM6ABBicYlhG1s3AoG5BFmY3r50lJzjQoER4zwuieEe +QTvKxLEV06vGh79UWO6yQ5FxqmxvM1F/Xw7RAKNfMF0wHQYDVR0OBBYEFAwa1L4m +3pwA8+IEJ7K/4izrjJIHMB8GA1UdIwQYMBaAFHB/Lq6DaFmYBCMqzes+F80k3QFJ +MAkGA1UdEwQCMAAwEAYDVR0RBAkwB4IFRWQ0NDgwDQYJKoZIhvcNAQELBQADggEB +AAugH2aE6VvArnOVjKBtalqtHlx+NCC3+S65sdWc9A9sNgI1ZiN7dn76TKn5d0T7 +NqV8nY1rwQg6WPGrCD6Eh63qhotytqYIxltppb4MOUJcz/Zf0ZwhB5bUfwNB//Ih +5aZT86FpXVuyMnwUTWPcISJqpZiBv95yzZFMpniHFvecvV445ly4TFW5y6VURh40 +Tg4tMgjPTE7ADw+dX4FvnTWY3blxT1GzGxGvqWW4HgP8dOETnjmAwCzN0nUVmH9s +7ybHORcSljcpe0XH6L/K7mbI+r8mVLsAoIzUeDwUdKKJZ2uGEtdhQDmJBp4EjOXE +3qIn3wEQQ6ax4NIwkZihdLI= +-----END CERTIFICATE----- diff --git a/vectors/cryptography_vectors/x509/ocsp/ocsp-army.deps.mil-resp.der b/vectors/cryptography_vectors/x509/ocsp/ocsp-army.deps.mil-resp.der new file mode 100644 index 000000000000..08125f0a9d48 Binary files /dev/null and b/vectors/cryptography_vectors/x509/ocsp/ocsp-army.deps.mil-resp.der differ diff --git a/vectors/cryptography_vectors/x509/ocsp/resp-sct-extension.der b/vectors/cryptography_vectors/x509/ocsp/resp-sct-extension.der new file mode 100644 index 000000000000..8018e2b82cc4 Binary files /dev/null and b/vectors/cryptography_vectors/x509/ocsp/resp-sct-extension.der differ diff --git a/vectors/cryptography_vectors/x509/ocsp/resp-single-extension-reason.der b/vectors/cryptography_vectors/x509/ocsp/resp-single-extension-reason.der new file mode 100644 index 000000000000..f89060d64577 Binary files /dev/null and b/vectors/cryptography_vectors/x509/ocsp/resp-single-extension-reason.der differ diff --git a/vectors/cryptography_vectors/x509/requests/challenge-invalid.der b/vectors/cryptography_vectors/x509/requests/challenge-invalid.der new file mode 100644 index 000000000000..dfea50244c31 Binary files /dev/null and b/vectors/cryptography_vectors/x509/requests/challenge-invalid.der differ diff --git a/vectors/cryptography_vectors/x509/requests/challenge-unstructured.pem b/vectors/cryptography_vectors/x509/requests/challenge-unstructured.pem new file mode 100644 index 000000000000..95a92ecb0983 --- /dev/null +++ b/vectors/cryptography_vectors/x509/requests/challenge-unstructured.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICljCCAX4CAQAwFDESMBAGA1UEAwwJc29tZXRoaW5nMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEApDAVEIXi90VT6Q8sCYl0sdzZaxIW5fGtk5M8Vmoe +iQbpWJtYZwQzOjOhgo9/+f/+Heg5gUI4+zUWyZMjh90KB5WrdTGO1x0yEUGjT15/ +VARFPmhyVniClEXPj4pANYVR00jMyvlLJuigKZbYR7VBTuE8oKOn2lu3eXuPFf6s +8bLjSHLuTS7t13LDlrO1jh2RvSKeQDwQP7ZHWzjTASW3H6bZla8lSx/6Xhvk5aJQ +JSMcEIYwPp7tP6+HV8E+FNjU19UZ3TsvGm60ZdoaCyFocgRFFju2wNSegmKzm00k +bAum7RR4dcso58vrkUz5AbZchdQ3dh9rRsggxgV/F5lMkwIDAQABoD0wFQYJKoZI +hvcNAQkHMQgMBmJlYXV0eTAkBgkqhkiG9w0BCQIxFwwVYW4gdW5zdHJ1Y3R1cmVk +IGZpZWxkMA0GCSqGSIb3DQEBCwUAA4IBAQA3lwNp3HtDQjzkqxv9SvUCH6C9UEh0 +6+SWklP2ce2IWmoHHnfYW2SyPAhzR1q2gSu7IVZhM3WMEJRoiqN2ZFQed++0b91n +LdUdCnDob8EFuX0AP7I4A9LI7G2bMS6mpzQBDXoo5hAlJV8I7Zq7NIby54bQiTgn +B8cYopnmrLfCn1H8Su8oBgPNg3glOQSAkvZfqhHNTJyAnN+5+boFWpReAe8p/cfr +kZh+fS8TcP7GbSLMnDlNwCAEIYRfAW7MVXJZ0l0tuDo7XdPImQgjjHYCk0tKPbeb +LVyIAPNkMYLu7II79OOi8h1cZfU6wWwUIIhjMzjLpdZBPyhhGnUQzfuZ +-----END CERTIFICATE REQUEST----- + diff --git a/vectors/cryptography_vectors/x509/requests/challenge.pem b/vectors/cryptography_vectors/x509/requests/challenge.pem new file mode 100644 index 000000000000..71ff39f24daa --- /dev/null +++ b/vectors/cryptography_vectors/x509/requests/challenge.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICcDCCAVgCAQAwDTELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQCb+ec0zYAYLzk/MDdDJYvzdvEO2ZUrBYM6z1r8NedwpJfxUWqC +hvK1cpc9EbQeCwS1eooTIGoNveeCrwL+pWdmf1sh6gz7SsxdN/07nyhSM8M6Xkec ++tGrjyi1H/N1afwWXox3WcvBNbxu3Df5RKLDb0yt9aqhmJylbl/tbvgJesXymwmp +Rc1vXL0fOedUtuAJ3xQ15M0pgLF8qDn4lySJz25x76pMYPeN5/a7x+SR/jj81kep +VaVpuh/2hePV5uwUX3uWoj5sAkrBCifi4NPge0Npd6KeKVvXytLOymH/4+WvV719 +wCO+MyrkhpdHSakJDTIaQIxsqVeVVKdPLAPJAgMBAAGgHjAcBgkqhkiG9w0BCQcx +DwwNY2hhbGxlbmdlIG1lITANBgkqhkiG9w0BAQsFAAOCAQEAMmgeSa8szbjPFD/4 +vcPBr/vBEROFGgL8mX3o5pF9gpr7nRjhLKBkgJvlRm6Ma3Xvdfc/r5Hp2ZBTA7sZ +ZYhyeezGfCQN/Qhda1v+sCwG58IjvGfCSS7Y5tGlEBQ4MDf0Q7PYPSxaNUEBH7vo ++M7U+nFuNSmyWlt6SFBSkohZkWoVSGx3KsAO+SAHYZ7JtqsAS/dm7Dflp8KxeDg7 +wzGBDQRpGF4CpI1VQjGSJQXSEdD+J7mtvBEOD34abRfV6zOUGzOOo3NWE6wNpYgt +0A7gVlzSYpdwqjBdvACfXR2r/mu+4KkAvYh8WwCiTcYgGjl2pT1bO4hEmcJ0RSWy +/fGD8Q== +-----END CERTIFICATE REQUEST----- diff --git a/vectors/setup.cfg b/vectors/setup.cfg index 5e4090017a9b..2a9acf13daa9 100644 --- a/vectors/setup.cfg +++ b/vectors/setup.cfg @@ -1,2 +1,2 @@ -[wheel] +[bdist_wheel] universal = 1 diff --git a/vectors/setup.py b/vectors/setup.py index bf02e389fffe..482c01b35a8f 100644 --- a/vectors/setup.py +++ b/vectors/setup.py @@ -15,20 +15,18 @@ about = {} with open(os.path.join(base_dir, "cryptography_vectors", "__about__.py")) as f: - exec(f.read(), about) + exec (f.read(), about) setup( name=about["__title__"], version=about["__version__"], - description=about["__summary__"], license=about["__license__"], url=about["__uri__"], author=about["__author__"], author_email=about["__email__"], - packages=find_packages(), zip_safe=False, - include_package_data=True + include_package_data=True, )