pax_global_header00006660000000000000000000000064146557565670014544gustar00rootroot0000000000000052 comment=25a913ec7867da743bacdbe194b6b5bcc0520437 m2crypto-0.42.0/000077500000000000000000000000001465575656700134065ustar00rootroot00000000000000m2crypto-0.42.0/.build.yml000066400000000000000000000032261465575656700153110ustar00rootroot00000000000000image: fedora/latest oauth: git.sr.ht/REPOSITORIES:RW git.sr.ht/PROFILE:RO packages: - hut - swig - python3 - python3-devel - python3-pip - openssl-devel - openssl - python3-setuptools - python3-twisted - python3-pexpect - python3-docutils environment: CFLAGS: -pthread -Wno-unused-result -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -mtune=generic -D_GNU_SOURCE -fwrapv sources: - https://git.sr.ht/~mcepl/m2crypto secrets: - nickserv_pass tasks: - build: | cd m2crypto export PATH=$PATH:$HOME/.local/bin python3 -mpip install --user -r dev-requirements.txt python3 -mbuild -v . find . -name \*.whl -o -name \*.tar.gz python3 -mpip install -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl - test: | cd m2crypto PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite [ -n "$GIT_REF" ] && REASON="$JOB_ID ($GIT_REF)" [ -n "$PATCHSET_URL" ] && REASON="$JOB_ID ($PATCHSET_URL)" set +x .builds/irc-send mcepl build-bot m2crypto "sourcehut build $REASON finished with the result $? ($JOB_URL)." "$(cat ~/.irc_pass)" set -x - readme: | cd m2crypto printf "GIT_REF: %s\n" "${GIT_REF}" python3 -mdocutils --strict README.rst >/dev/null if [[ "$GIT_REF" =~ master ]] ; then python3 -mdocutils README.rst \ | sed -n '1,//d;/<\/body>/q;p' \ |hut git -r m2crypto update --readme - fi artifacts: # https://is.gd/Z5VJlI # - pygn/dist/pygn-*.tar.gz # - pygn/dist/pygn-*.whl m2crypto-0.42.0/.builds/000077500000000000000000000000001465575656700147465ustar00rootroot00000000000000m2crypto-0.42.0/.builds/irc-send000077500000000000000000000022501465575656700163770ustar00rootroot00000000000000#!/usr/bin/python3 import pexpect import sys SERVER="irc.libera.chat" PORT=6697 USER=sys.argv[1] NICK=sys.argv[2] REAL_NAME="Commit bot" CHANNEL=sys.argv[3] MSG=sys.argv[4] PASS=sys.argv[5] assert len(sys.argv) == 6 client = pexpect.spawn(f"openssl s_client -connect {SERVER}:{PORT:d}") # client.logfile = sys.stdout.buffer # :mercury.libera.chat NOTICE * :*** Found your hostname: nat2.prg.suse.com client.expect("Found your hostname: ") client.sendline(f"NICK {NICK}") client.sendline(f"USER {USER} * * :{REAL_NAME}") # :NickServ!NickServ@services.libera.chat NOTICE build-bot :This nickname is registered. Please choose a different nickname, or identify via /msg NickServ IDENTIFY mcepl client.expect(f"NOTICE {NICK} :This nickname is registered. ") client.sendline(f"PRIVMSG NickServ :IDENTIFY {USER} {PASS}") # build-bot build-bot!~mcepl@nat2.prg.suse.com mcepl :You are now logged in as mcepl client.expect(f"{NICK}.*:You are now logged in as {USER}") # JOIN #m2crypto client.sendline(f"JOIN #{CHANNEL}") # :mercury.libera.chat 366 ceplma #m2crypto :End of /NAMES list. client.expect("End of /NAMES") client.sendline(f"PRIVMSG #{CHANNEL} :{MSG}") client.sendline("QUIT") m2crypto-0.42.0/.gitignore000066400000000000000000000003351465575656700153770ustar00rootroot00000000000000*.pyc *.txt *~ /build /dist /src/M2Crypto/*_m2crypto*.so M2Crypto.egg-info /.eggs/ /EGG-INFO /tests/randpool.dat /tests/sig.p7 /tests/sig.p7s /tests/tmpcert.der MANIFEST *.tap src/SWIG/_m2crypto_wrap.c !*requirements.txt m2crypto-0.42.0/.gitlab-ci-windows.yml000066400000000000000000000054411465575656700175360ustar00rootroot00000000000000# Common steps that install Python, OpenSSL and Swig .setup_script: &setup_script # Install Python and Swig - $CHOCOLATEY_PYTHON_OPTIONS = If ($ARCH -eq "32") {"--forcex86"} Else {""} # Used to force the installation of 32-bit Python - choco install --limitoutput --yes $CHOCOLATEY_PYTHON_OPTIONS python$PYTHON_VERSION - choco install --limitoutput --yes swig # Reload the profile so that the binaries are available in the path - Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1 - refreshenv # Print information for debugging - echo "Python version and architecture:" - python --version - python -c 'import struct; print(struct.calcsize(''P'') * 8)' # Install Python dependencies and OpenSSL - echo "Install dev dependencies"; python -m pip install -r dev-requirements.txt - echo "Install OpenSSL" - curl.exe -o "c:\\$OPENSSL_INSTALLER" -fsSL "https://slproweb.com/download/$OPENSSL_INSTALLER" - Start-Process -FilePath "c:\\$OPENSSL_INSTALLER" -ArgumentList "/silent /verysilent /DIR=$OPENSSL_PATH" -NoNewWindow -Wait - echo "Install pywin32"; python -m pip install pywin32 # Print information for debugging - ls "$OPENSSL_PATH" - echo "Installed SDKs:"; if (Test-Path "C:/Program Files/Microsoft SDKs/Windows") { ls "C:/Program Files/Microsoft SDKs/Windows" } - echo "Installed OpenSSL version:" - Start-Process -FilePath "$OPENSSL_PATH\\bin\\openssl.exe" -ArgumentList "version" -Wait -NoNewWindow - echo "Python OpenSSL version:"; python -c 'import ssl; print(getattr(ssl, ''OPENSSL_VERSION'', None))' build-test-windows: stage: build parallel: matrix: - ARCH: ["32", "64"] PYTHON_VERSION: [ "310", "311", "312" ] variables: OPENSSL_INSTALLER: "Win${ARCH}OpenSSL-1_1_1w.exe" OPENSSL_PATH: "C:\\OpenSSL-1-1-Win${ARCH}" BUNDLEDLLS: 1 tags: - saas-windows-medium-amd64 artifacts: paths: - "dist/*" script: # Setup environment (Python, Swig, OpenSSL, etc) - *setup_script # Build wheel - echo "BUNDLEDLLS is set to $env:BUNDLEDLLS" - python -m pip wheel --verbose --no-build-isolation --no-deps --wheel-dir .\\dist . - ls ".\\dist" # Install wheel - $env:PYTHONPATH_DIR = If ($ARCH -eq "32") {"win32-cpython-$PYTHON_VERSION"} Else {"win-amd64-cpython-$PYTHON_VERSION"} - python -m pip install -v --upgrade --target build/lib.$PYTHONPATH_DIR --no-compile --ignore-installed --no-deps --no-index --find-links dist m2crypto # Run tests - $env:PYTHONPATH = "build/lib.$PYTHONPATH_DIR"; python -m unittest -b -v tests.alltests.suite rules: - if: ($CI_COMMIT_BRANCH == "master" || $CI_COMMIT_BRANCH =~ /^windows.*/) # Run for all changes to master or branches starting with "windows" - if: $CI_COMMIT_TAG =~ /^\d+\.\d+\.\d+$/ # Also run when pushing tags for versions, e.g: 0.40.1 m2crypto-0.42.0/.gitlab-ci.yml000066400000000000000000000174061465575656700160520ustar00rootroot00000000000000stages: - build - deploy include: '/.gitlab-ci-windows.yml' python39: image: python:3.9-alpine when: always stage: build script: - apk update - apk add --no-interactive swig gcc git musl-dev python3-dev python3 py3-pip openssl-dev openssl py3-setuptools py3-twisted py3-docutils py3-wheel - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --break-system-packages --user -r dev-requirements.txt - python3 -mbuild . - python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite python3: image: python:3 when: always stage: build script: - apt-get update -q -y - apt-get install -y swig libssl-dev python3-dev python3-pip openssl python3-setuptools python3-twisted python3-pip - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --break-system-packages --user -r dev-requirements.txt - python3 -mbuild . - python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite alpine-32bit: image: name: i386/alpine entrypoint: ["linux32"] when: always stage: build script: - apk update - apk add --no-interactive swig gcc git musl-dev python3-dev python3 py3-pip openssl-dev openssl py3-setuptools py3-twisted py3-docutils py3-wheel - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --break-system-packages --user -r dev-requirements.txt - python3 -mbuild . - python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite python3-32bit: image: name: i386/debian entrypoint: ["linux32"] when: always stage: build script: - apt-get update -q -y - apt-get install -y swig gcc git libc6-dev python3-dev python3 python3-pip libssl-dev openssl python3-setuptools python3-twisted python3-docutils python3-wheel - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --break-system-packages --user -r dev-requirements.txt - python3 -mbuild . - python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite python3-doctest: image: python:3 when: always stage: build script: - apt-get update -q -y - apt-get install -y swig libssl-dev python3-dev python3-pip openssl python3-setuptools python3-twisted python3-pip - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --break-system-packages --user -r dev-requirements.txt -r doc/requirements.txt - python3 -mbuild . - python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl - cd doc/ - PYTHONPATH=$(readlink -f ../build/lib.*) make doctest fedora: image: fedora:latest when: always stage: build script: - dnf makecache - dnf install -y @development-tools fedora-packager rpmdevtools - dnf install -y swig python3-devel python3-pip openssl-devel openssl python3-setuptools python3-twisted - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --user -r dev-requirements.txt - python3 -mbuild . - python3 -mpip install -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite fedora-rawhide: image: registry.fedoraproject.org/fedora:rawhide when: always stage: build script: - dnf makecache - dnf install -y @development-tools fedora-packager rpmdevtools - dnf install -y swig python3-devel python3-pip openssl-devel openssl python3-setuptools python3-twisted openssl-devel-engine - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --break-system-packages --user -r dev-requirements.txt - python3 -mbuild . - python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite leap: # image: registry.suse.com/bci/bci-base:latest image: opensuse/leap when: always stage: build script: - zypper refresh - zypper install -y pattern:devel_rpm_build pattern:devel_C_C++ osc - zypper install -y swig python3-devel python3-pip libopenssl-devel openssl python3-service_identity python3-setuptools python3-Twisted - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --user -r dev-requirements.txt - python3 -mbuild . - python3 -mpip install -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite opensuse: image: opensuse/tumbleweed when: always stage: build script: - zypper refresh - zypper install -y --force-resolution pattern:devel_rpm_build pattern:devel_C_C++ osc - zypper install -y --force-resolution swig python3-devel python3-pip libopenssl-devel openssl python3-service_identity python3-setuptools python3-Twisted - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --user --break-system-packages -r dev-requirements.txt - python3 -mbuild . - python3 -mpip install -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite build-sdist: image: python:3 when: always stage: build artifacts: paths: - "dist/*.tar.gz" script: - apt-get update -q -y - apt-get install -y swig libssl-dev python3-dev python3-pip openssl python3-setuptools python3-twisted python3-pip - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --break-system-packages --user -r dev-requirements.txt - python3 -mbuild . --sdist release-pypi: stage: deploy image: python:latest dependencies: - build-test-windows - build-sdist id_tokens: PYPI_ID_TOKEN: aud: pypi script: - echo "Built artifacts:" - ls dist/ # Install dependencies - apt update && apt install -y jq - python -m pip install -U twine id # Retrieve the OIDC token from GitLab CI/CD, and exchange it for a PyPI API token - oidc_token=$(python -m id PYPI) - resp=$(curl -X POST https://pypi.org/_/oidc/mint-token -d "{\"token\":\"${oidc_token}\"}") - api_token=$(jq --raw-output '.token' <<< "${resp}") # Upload wheel to PyPI authenticating via the newly-minted token - twine upload -u __token__ -p "${api_token}" dist/* rules: - if: $CI_COMMIT_TAG =~ /^\d+\.\d+\.\d+$/ # Job enabled only when pushing tags for versions, e.g: 0.40.1 when: manual # Can only be triggered manuallym2crypto-0.42.0/.keys/000077500000000000000000000000001465575656700144375ustar00rootroot00000000000000m2crypto-0.42.0/.keys/openpgp/000077500000000000000000000000001465575656700161075ustar00rootroot00000000000000m2crypto-0.42.0/.keys/openpgp/cepl.eu/000077500000000000000000000000001465575656700174425ustar00rootroot00000000000000m2crypto-0.42.0/.keys/openpgp/cepl.eu/mcepl/000077500000000000000000000000001465575656700205425ustar00rootroot00000000000000m2crypto-0.42.0/.keys/openpgp/cepl.eu/mcepl/default000066400000000000000000000214241465575656700221140ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- mQINBFcgpa0BEAC81pv//PpHxEajKRInydtdCrMXUUH7mG7f9crFnz7RQ406hdZg 11v4gBdCtI2FP1600TTssUniYbReHywdmvoMX43Ow5gCSCOT1xLkvnsWtFKUIBLh 0FDg5Y+XAlAmhnv9/OIWnwNlV7U4Bmek8TYmFGg4nVASiSAsqnlfaBkVRxeBFfI2 Oe8617WdvEULqdV8T4vLDeLAHCC0BHwVLKLpIZw4c/mlOjTLgTz5maJVjI0/8RQH Eb4dwBaVpIvFSjUo4TFPaPynPTAlTvbvvEl05j0LHUYGncbLzxAJKvY5Ubr6chN4 aTkeZLoycoqr9Q3rIXMatkxYZPaOGQkjfDB01b3ZMK8pkkhyfDHuCmJjzIYAN/s0 lTIYfklzXkrG+k9PEA8v/cXzOKGtZ+Zzdz3YdbSrVVNJEUixptkFrmMG0+h8Dfxi 4EjHvihT9+vlcm0IK7/M3tLyy9IA28yKPKLwRf1cDni+9+MJytKlR4r3e/FHYJeO 2diI0B3wclxKZYxjPVBu5MvZ6+0gOt8w/oH/yC+o+EYeKAf8IlOPTQY4TVV4uJZS O800UWu/qd+UbZSbZ7jbyq6m8gtFjXVO9YFpZQV8mpOIM3h4q7NMa2J88xezRSWC HGrwk9so+Gdf59dRePcrvQehrrplWmyyZXygwNMYQbn0nSyfP5s1tHc5TwARAQAB tBtNYXTEm2ogQ2VwbCA8bWNlcGxAY2VwbC5ldT6JAoYEEwEIAHACGwMCHgECF4AF CwkIBwMFFQoJCAsFFgIDAQACGQEWIQQ8dqAnykWtcJi1vB15IFgCiAvJ2AUCY3M9 TTQUgAAAAAAQABtwcm9vZkBhcmlhZG5lLmlkaHR0cHM6Ly9mbG9zcy5zb2NpYWwv QG1jZXBsAAoJEHkgWAKIC8nYfmgP/3A8mtVxEBHM8YjdPVgdYIFUtycFHAiZVwk6 L8vOYCztkfe15Tf9iiz1VmQljw72hfycsi/m348uIv0pzLVEp+YeJ7NWFqYkefT/ QQdpwv+f9g2mcMtGrFTFAtIb8HCmnloI54LpmYfr5xEOUwPl6PKT4UbngcrL4x49 OqBdW2gelz7R3iAirWp/72phTV5f27njZJ6M26P9l2gYcD+5zOshumvhpTRs2jIq KR1b3IQHD+sVsmdKKRIDro4Qo6VqMoR51h3GvZ4L4SLhS9/J4mrkQfzKUtsF6cvo 6Yz2Heiv/awYTd2llOHPOzx2mS0azhi4yFpC3qznsRUI9rXvwmwV/oMWcZvADTbJ 7X//RaZia95KoXEVblA04dbHrQD0e1nJRUmJNclVxjX+Z8nR5HhczEqTqSQ929d0 +yvpuU052kRB7q2pXwvmaBS77Gz64HK4hWFeSDL3vzwdgYauVlUFPGiBIad+F4S/ ejCU8MkYw+3GuKpc9DsLbE4N7WCcp4O4I1Cp6UNqtXERmbyVZTe7iHK0fe6XTxRv akzh4uis3uheDUHJkm4GNe1YCeec9pKMF9rwhfwa1l1S57zVZtzl1k0HKq5v8ANj nYoS8A4XNf0fN7/RMz+ILopVncMDo8wV7E66VIeZzcZWW9Js+hCIB+K2ltY+qHaQ nUNTb9K2tB5NYXTEm2ogQ2VwbCA8bWNlcGxAcmVkaGF0LmNvbT6JAjYEMAEIACAW IQQ8dqAnykWtcJi1vB15IFgCiAvJ2AUCY2Zb3gIdIAAKCRB5IFgCiAvJ2KOlEACS BT4WfecoP13LKBbkgAM1IzAvntBxeI4PEBOuFSqO9dOmA8ucf+zaG9w6zBucKbQf ofOQuQYLV+DqoUCeryYv602Sq4NsqLQEZVUUVo1taR+EYCo24nGhap6WasdZMr+K B6o+WXJICBF7KuXHzrHGiF3vb3W1ssBwJD2yc0CTFP2K3RLBMOnzvk/itxVa6ITp Rq9R4EgC0WWOLEjhV1S+8UQ5Rb0fH5u/1WbWBYLvo22nrwaAdFRHPREppMs950HQ 9MY+3s53yFiw6nNtAL4N9Dg1aVkCQku/brH7dFTcvS5TocXHn6qkqPf/dyp2/LN/ jrHQfUX+3AC/BLffbJTr4Bznhmgg2Th5Cs9JYT2J6OkKIx6aEDzxJNrPW952R9I2 jin+7CFGwJBYz6nMacJ6+Pn7hi+a1zI9xX/cQU0wRnAhr/8ddxqnTCRLq9enP9oG QoUmEylxrTKxuQ9bd245aGNau/CIWlGghgcrjpAoYLAw0Ukd1XxCcsGFL4IbK3Q1 049ynsjIDzLspbfDRd3W0VYyLjZ7PiF3fhFUkZrS0ni0ZRC41fBSC279NRchjcqY aQUy3E8UOoCNS4HmQUdpM5An3Qo3jL5zXPsxLF9XuYStkXQsoUNNfhS8UpAikHfx TiXXGaDGKfv5iyhNl7Bida/uFcKLq1HIP3jo960CMrQdTWF0xJtqIENlcGwgPGNl cGxtQHNlem5hbS5jej6JAjkEEwECACMFAlcgqUkCGwMHCwkIBwMCAQYVCAIJCgsE FgIDAQIeAQIXgAAKCRB5IFgCiAvJ2L1ED/wONwIPwD6S8e+aNRd7ZHwqv4IH2Ofp +vukr0CTNJqdt3pw9GhIsIrJ0+29Loe0W/Wg8jqClO8vlzFrbudbbNBG214tTNKJ v7+FwRSrJaHB+/FTg/78+qvs6zdR7/q+k3kBiOc47eNJV3vFuUJ2zwQeunEkPfyo RK7+Sag0VUNgHwwRdjYQzXizr7i+2xMcRyEpfosR6/mOOaA+NzAs7SZQyRs+g9U9 qDPA4vyM7PYurVMkLSZ5IYJYovuFKvBkFwi2KndQ79ZfEo25/K3q67bH7w46dEta +byAgq88gwy61VuYaKZP2fCECeIcAs3UeDiX2pgL7SRqaY9NCfqgGgLK2V0BuaHm PaUcN2vGoq1NzEHC2qZzsq9mMf/GhZQdIfiX0NW6luJKlntvQa/wi0obvAPQ3eHO NJrjgsrfDCFaihwx8YRxNWq7W5q3Rxtxheq3zSsWCeBB1/Ys3kCTRzv8hdrfdbZI Ew+INGrWfCFSzh0bDY1ZOLmUm/tt85qLuvlcF4IJwNEZ+hpvkbzQCfjugcpzpdKu 3TsrJoZBQvMDZJ5QnHp4AuQZqDz87OPVOaYYmS13tNEEEMy0Hqt1EOu1d9zNjm4u 4r3i5BKJBEXA66qdxqKBTklJjLbnTsvxURlZqqZGxLLsI1LALbbmnF21POUXew1Z 7f48IwNJsx31VbQiTWF0xJtqIENlcGwgPG1hdGVqLmNlcGxAZ21haWwuY29tPokC OQQTAQIAIwUCVyCphAIbAwcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEHkg WAKIC8nYZawP/3n6cvEJenA+mhr1f7nlFLWNk2EWrI3HSmPW9r3S+mr4phruKQmF KznlJbpoSK8ppYhUkjcXxgi5+8ApLtcQjSFwAY0HXzwY5kK9sohPyAx8s8kOBYnV faTi/MpQM27/+RXcUDAeQuVOhI/nx10unbCTyT7mOnHmO8h/L+SYsoFLMMJSqYeH aBdse+iHvLQ7Dx9a8nmO44RGMRJ9HG89plfqVZo1v23Mqxvd9TYz0KLy1aGmaqBT TCBAZrdLgAOKY+QXGeLJxFDi8QndyhtBo/Upp8v44L8E2ugVOLs+lc6cdLlyNJUs rvoqKrAaLkjc9LMXTBDci93Bzg5gwV+ipq+hDBm/jj3WfUUPxowLoWzsfmhxM21U LEyo5tu7AAXqimkcrWiirKQUP++REVsSWOSxeETJgeJ8XQmH+9lfbULt6cwQUpTH 3WZuVua8HA8hR1hOa1FhxhvOWG1S2zmJXI0ouNRCkkP7YV7Z0tlZ81X0ZtQGLFI1 5uMWLPm29L2qQgpac5tR1mgLvxZReJfyMSLRRfnpLbiCDSBzaVRhY4UwEiPoksgl lGTKXFOtivc09ReG8+9knAJy6ERxMDo1ltczkvpYI9wHSznf4t+NQlEeFkkrnLRV lXBDT8n0SkBpWQW37GdTZy9yE54lFAWe83cMqa8Ii37oFPGUsfK49lvCtB5NYXTE m2ogQ2VwbCA8bWF0ZWpAY2VwbG92aS5jej6JAjkEEwECACMFAlcgqZUCGwMHCwkI BwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRB5IFgCiAvJ2ERsEACWrK2NMHBTaYw7 tHRrkja4xwnj7qWjc0gO3zb5k+QQIjAYcfV22HZUJo6TjmjvD0/D1FjWQvj/dMOi 5vA+vhT6WtiOVgNYONpkcwPjZEZ9+svTC0Ry5fqnF7UbN44FzS9HNhWG/PBH/28T shrKgMBNkCQlQ+dLma6pugjf/U3Dzixz0curvp6unV14Cp9lf8fbYvxtc/JvGYPS JMMivo9vYXToREq5y7AHyvNv6jAQY9K3bnKrrBjVJ7jnwd+kvsrAp/SymOqX8rFU Fq7w+TPDbI0PURdeDkuBJCtWblhn/bPtfTuecr0OHgFZ0C6Hs+ZBb8zlN48ISQxP 4ZumnbGdYEGcusXVS6odobYEIhcXpD5v5TUpTQda61kLJOJOXqXLVMcCGBXZnhaA h1RHuILM2rm0XytXg7cb/ByXjQ70rQSPWBc8IVweX4Zp1Y6rg0+eVhNKVyn8GhgG oto3iw2xLYtoCb9Bm9TsFa5Yc+eiQnRdHCh+z75T39hrTH7hAmTDzp//6sAM/kjX fcCvYKT+qWupO1yRjIO6J6nilVytJ0XeruZxDyrcasVOt4WpzoOHAYFJbUfkLSHC 5G0QoAiD7vR1QhkqkJX0gufONi5nNU2DWo0gChR15O8umctsLOI0XDb5SJCmHWco ogINtmNJKdrRZi3WeTHRYTjmlX8wj7QbTWF0xJtqIENlcGwgPG1jZXBsQHN1c2Uu ZGU+iQJRBBMBCAA7FiEEPHagJ8pFrXCYtbwdeSBYAogLydgFAmNmW1MCGwMFCwkI BwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQeSBYAogLydhS7RAAnJSCgWvA7S1k kwGr2XmLMZnuBc4pgxdJ3nCCip+92NXXduWuu59eaFLx2s7Qmvlfe+Tbf7Tx9thT grAcVUg0P7bFpJAy86KxCZUzIR4v4QHdgrxV2/I4oJWsB21LiB24wsRVM/ODqSsU GCXrVhbt9x8l/E5GghpzERMQLtRUYNTlNq+xaz/iLNnRGg8x9J30cpua62YOnFXo oHCDc54O3SE1MZEwieVCuQ+J2MDp5XBGk7iT89EphcbIXfdpGUNlk6AEAeEAFAGP trMTrzLUvjqZ1hjvjzTaEck/TFfCNSRrfESI7xSsitlX/Hnm+L9v9BLuzcsqxW1k pDmR7y45iGEbFO3gkQIojguJoF2v943zSfRiyxQeGi60tYmg6MOlApj/GwMxCMmM Gn1j+G2DW88oCOOsPMv9pmnU7vkrgHlim7g8iP4gPR17rQYMMqj7Oy74oAR7aQ5V lGFT8VyCqXUcUxBGAiYF6dwEd+cBJbr1Bj3qKfC2djg1iSPkCQjWaWJ0aEy+RkL6 kwnN0QnwZOGcWKoVabGZshTgstYRW2msn++wE8Z//wlcA9vbVPNQXMM0okseBOEj IvSmuezqNVXhisCiNTHAiaRrICd5cvTMJ5OYhvu9Bt73LNHUNVm+m5fBzmFlgf79 4r2YqwzO8BkzSmdyYHWz/8PRq6LNgce0HE1hdMSbaiBDZXBsIDxtY2VwbEBzdXNl LmNvbT6JAlEEEwEIADsWIQQ8dqAnykWtcJi1vB15IFgCiAvJ2AUCY2ZbagIbAwUL CQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRB5IFgCiAvJ2BkqD/9MrzLKaLtx FQ6e+KedhLetWDuYopCFUBo/+hM1ZgLVLm/FKSdg0Idjz9bQ7K34pabOqtpHsnKP th/Qa0TZ9tJnUuM5JqZ6rCk5tpF0TmsVSND8oaGLwDsAjUavQ02XbuUjsmyLmY+8 X8WCi4TQ/FmFO5Q/9v0O0HZK+O0e4ndEy1S9LfXATu3xIpxwIuuHDflN6PEqzWaR QTcbX05yvjoMcanzkJk+enzJreGC4xtNBAFpp2eZp5//QUTlEzd3DAp6s6/lkNVu as+eZqJVxliRiHDgtqaudv5mphM/59IMvcUaKAwJKeba0Xv/tDTnhNWX1/qPC0Hq 9An2T2c4E4NligbeezB+yMFvTFRwsgZF8vEmlRQ6hgtG5HJTlYsysdi6S1Exfwkv iWKfr1T9XQ3VLv6C0Vm9HI7YRDzea5YwJ4puHCrrE5UVUmhFVWqVZioBeirT2AbE slBZmCy+NUO8lmssKytCY00rwd+BdrCGBibViqB9GJghC8hUb9/FEmE1zSa5PHeE 9UuYV6kiuyodj/xXwj6EztXh1S5ywxOOwD/m9p/GMHW+sRWIdOe4qE1kqnonlcg2 YqVauNu9ZxUhdhN37ca3h2xxjjcmKA1IaMIrmNsQ0CFzVmW/aUZLY+CDjiSPKj3j aDyfvfLT0Nps5/Ep2kbByQWlEqCFnn6aE7QbTWF0xJtqIENlcGwgPG1jZXBsQHN1 c2UuY3o+iQJRBBMBCAA7FiEEPHagJ8pFrXCYtbwdeSBYAogLydgFAmNmW3oCGwMF CwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQeSBYAogLydgsoQ/+KZLiYn0S g5J5nLd5DjqR4TfJDdDx/uGWLeLn+5xn4aP15Bs6dkwwM5F2C9OYN6H+RBxUxfsy 6N9L0yjutxG6xO7Y/eAayKPD/nDakUyTkIZJ1Ga28hOuLMtfJDF5CygHPPAg+dBG XJynE+YaaMY2E2T4ftV21UDqssrCSLn5Xltdvlf5B0DGUQgcqxdwrQVFIHLSVCbC aVc/QM3D5rzvEjvwCvSgfrQNLJOubEh8GXNVpFFr6L+NnbGPlBYy7/pZCqp6iBmW Zqj0UAXHJGDmvYor4kMtLoWl3WHt8MI2AZE54zupoxif3Cf5r1r5eICJzI+nDjHp kO/O5SlcSHI/eD87oJlnZhZe2jX9GBGgsG45iHvmAtL1qET58gSdOfmHFC1DvkzL RiTO2rHJ8pd457a0we0SGzfvIHUry0HZfH1RS2YmvnM1e84oE5h1hbn4cu/1bFZd LwJyPZVEiUyEpc2pwFTSY4FRD14+PQWGgte6neNY0DiMKYkii5QdJ4kKedPWtRXR AnTO49DmUFQWum4P8UWO65YGE7MZ8smIGU2L0BGWIKY13qaHcJRj7LRnJbnDxKpS AVxv2ytXB1xIDOUc+dkEIu/8E9l01Dz9e96Zq/crZdngzwsd3/JORn9FSbCaORdM GMkekQ9xnLClIMDBMw9eQo+sJ5ogKmlqcBS5Ag0EVyClrQEQAK0YMh0hX/ZBuxTJ KsxsuwZG+blEw70tiCh/vAnWuoTyjkkL8h1IDLmoTvqVtzT4Ho+RQKIMpit/llZH OaGgtX2/FuxJmK/Ai4MmODq1Jyqsm8e7KzodvVkFQjlB2E0eY37ChD/LdXq4JWLT OYrknX1PSev+PtYay4qXlB8VVhcn6qR++rKB+w/uvmJKQl1V1EGB02Pt1wUwfawK Kf/tAdjmI9muTxeKYugWelmDb2X2W+LKs+GrpjJ1yCzq1qqNmxQM0pYdRKCA9nJN H80AZPFHN+NFqiYZmxPmeZP4TdGzZAUwYIoU0PaSX0gpMP7t5rw8RiWB894iW6o8 LwrX6FVOw4cgNDK2o065vSzOHinQLRkbKXNKDX8fZuSv0afpGflmBCJXAek1R6cV B0T90ZWMT8lUbDf6ThgPDZ1BeRSg80Y5JfTODJAsnoD7qn2wux+v+v0fGPw2xmvD NBLMQUmaeJ688Bv1CfBIYPXclpCKq2fdgpAxkho3aT/sywgayDWIqWYawKUNKZ7h zmkrnreOKaDFjun5bSlqH7i/7Z9cMMsgpYsHsSaqr6C6O4cFQ7EIsLNo3gldnV74 0Xo+uYw9XAVLJj2nFGzkpJqmMUMBfACp/7c1zXMFX3bLslqdMzt94PRT74eZtMwG PwXEhEW0ZJIQRGnaPjs12XvEJn/tABEBAAGJAh8EGAECAAkFAlcgpa0CGwwACgkQ eSBYAogLydghBw/+IbPaGbq4ZiXxvy6ZuroV7+Ja+8ck2ToUn6FGSfIpwc9S1Dbe RbF5pUp9xCzxk8aCVuXHp38h3Bip1MGJAZ8OKKed5yvmuBsdVHUm9ChAIk7zxP4m J1t7jzIIlXAJwlta+6RBsa1tV7Mb7dGbSsEFknknS8+qzPeJ1r2MlRtyhZEbbI2w Z8X2ReXLfDJFvShRW1CyBCqIWBtsIh6t/h1Ar0yTAr/lL92rXFAPZTJtSUcQJnAk +sOPgHhDCIXv0fDTwxtvdR/u/Mp9aST4I81lfqtPDSwGFQzZOsPUPDeedOwHHH29 uB5aiYdPbph+veSp+YP8i8G6GgCi+z71sUHM4VzCb6earVdcoNRMSvrXPFDkuWfu V8ffkFBU69tc5ltxvKEw9IA9m55Xk8iplLut5I+6jRFlKZ6fgVWvFDE1sRtfMdCn p97ZH6CAwYcGDA5RxD1HU3htbB4TH6nJPTHvuLLwJSR6uyzBakvLB3nf6yP5IfOV N7Bpkt+Mqcc/UsY41yHL3ktAsOPA+48jqFNCyNDRRe8agILZynagRCvnKLdHnssH +5lJmH+kQepUpsSGqUUwfDadrICy5T1oUvjqn0crunlBNhcGiaqwaLUikR3trZNb Rjqet+gtd09sVS4yqapFbwpPIXzONnB8rNcB066eA1e+k2RqtabpH9mrN7M= =/S9/ -----END PGP PUBLIC KEY BLOCK----- m2crypto-0.42.0/.readthedocs.yaml000066400000000000000000000007171465575656700166420ustar00rootroot00000000000000version: 2 build: os: ubuntu-22.04 apt_packages: - swig tools: python: "3.12" sphinx: configuration: doc/conf.py python: install: - requirements: doc/requirements.txt # The autodoc generation needs to be able to import the M2Crypto module. # Since this is only possible when M2Crypto is fully installed (after # the swig bindings have been generated), we manually install it here. - method: pip path: . m2crypto-0.42.0/CHANGES000066400000000000000000001054131465575656700144050ustar00rootroot000000000000000.42.0 - 2024-08-10 ------------------- - allow ASN1_{Integer,String} be initialized directly - minimal infrastructure for type hints for a C extension and some type hints for some basic modules - time_t on 32bit Linux is 32bit (integer) not 64bit (long) - EOS for CentOS 7 - correct checking for OpenSSL version number on Windows - make compatible with Python 3.13 (replace PyEval_CallObject with PyObject_CallObject) - fix typo in extern function signature (and proper type of engine_ctrl_cmd_string()) - move the package to Sorucehut - setup CI to use Sourcehut CI - setup CI on GitLab for Windows as well (remove Appveyor) - initial draft of documentation for migration to pyca/cryptography - fix Read the Docs configuration (contributed kindly by Facundo Tuesca) 0.41.0 - 2024-02-13 ------------------- - fix: test/smime: Rewind BIO before repeadetly invoking verify. - feat: React to the possible error when calling BIO_set_cipher(3). - Return M2Crypto.version_info - Revert 957df43e (workaround for the problem in OpenSSL, which is not needed any more) - Fix Windows builds (fix #319) - feat: Remove py2k constructs in setup.py - Fix mkpath call (compatibility with Python >= 3.2) - Remove generated files from sources - feat!: Remove six and make whole project Py3k only (see #328) - Don't use setup.py commands anymore. - 32bit Python actually has Y2K38 problem, because time_t is long int (see #341) - From TAP back to the standard unittest (gh#python-tap/tappy#136) 0.40.1 - 2023-10-25 ------------------- - Whoops! The problem with ASN1_Time is not a problem of Windows, but of all 32bit architectures. 0.40.0 - 2023-10-24 ------------------- - OK, SO NOT THIS RELEASE, BUT IN THE NEXT RELEASE PYTHON2 WILL TRULY GO! - BREAKING CHANGES: - There are no SWIG generated files (src/SWIG/_m2crytpo_wrap.c) included anymore, so swig must be installed, no exceptions! Also, for compatibility with Python 3.12+, swig 4.0+ is required. - All support for asyncore has been removed, as it has been removed in Python 3.12 as well (which means also removal of contrib/dispatcher.py, M2Crypto/SSL/ssl_dispatcher.py, ZServerSSL). - All use of distutils (including the bundled ones in setuptools) has been removed, so `setup.py clean` is no more. - Excessively complicated and error-prone __init__py has been cleaned and `import M2Crypto` doesn’t include everything anymore. Imports should specified as for example with `from M2Crypto import foo`. - ASN1_Time handling has been mostly rewritten and it almost works even on Windows. - All tests in Gitlab CI (with exceptions of some skipped tests especially on Windows) are now green, tests of Python 2.7 on CentOS 7 have been included. - Introduce m2.err_clear_error() - Make X509_verify_cert() accessible as m2.x509_verify_cert 0.39.0 - 2023-07-04 ------------------- - SUPPORT FOR PYTHON 2 HAS BEEN DEPRECATED AND IT WILL BE COMPLETELY REMOVED IN THE NEXT RELEASE. - Remove dependency on parameterized and use unittest.subTest instead. - Upgrade embedded six.py module to 1.16.0 (really tiny inconsequential changes). - Make tests working on MacOS again (test_bio_membuf: Use fork) - Use OpenSSL_version_num() instead of unrealiable parsing of .h file. - Mitigate the Bleichenbacher timing attacks in the RSA decryption API (CVE-2020-25657) - Add functionality to extract EC key from public key + Update tests - Worked around compatibility issues with OpenSSL 3.* - Support for Twisted has been deprecated (they have their own SSL support anyway). - Generate TAP while testing. - Stop using GitHub for testing. - Accept a small deviation from time in the testsuite (for systems with non-standard HZ kernel parameter). - Use the default BIO.__del__ rather tha overriding in BIO.File (avoid a memleak). - Resolve "X509_Name.as_der() method from X509.py -> class X509_Name caused segmentation fault" 0.38.0 - 2021-06-14 ------------------- - Remove the last use of setup.py test idiom. - Use m2_PyObject_AsReadBuffer instead of PyObject_AsReadBuffer. - Add support for arm64 big endian - Make support of RSA_SSLV23_PADDING optional (it has been deprecated). - Move project to src/ layout - Allow verify_cb_* to be called with ok=True - Be prepared if any of constants in x509_vfy.h is not available. - But we do support 3.8 - We DO NOT support Python 2.6. 0.37.0 - 2020-12-08 ------------------- - Remove support for CentOS 6 and Python 2.6 (remove tests.vendor module). - Remodel CI: - on GitHub switched from Travis-CI to GH Actions - on GitLab-CI: stop testing 2.7 on Fedora, add centos7 - update appveyor.yml - Stop playing with swig in setup.py, we don't support swig 1.* anymore. - Fix dereferencing of pointers (gl#m2crypto/m2crypto#281) - Replace deprecated PyObject_AsReadBuffer with our own shim. - Use parameterized to create parameterized tests (new external dependency). - Only use DigestSign() and DigestUpdate() with OpenSSL >= 1.1.1 - Expose all the X509_V_FLAG - Add support for DigestSign* and DigestVerify* 0.36.0 - 2020-07-13 ------------------- - wrap SocketIO in io.Buffered* for makefile - SSL.Connection.close accepts an argument to force the socket closing - SSL.Connection: make the clientPostConnectionCheck an instance attribute - Fixed bug with usage of unexisting method getreply at SSL_Transport - Add appveyor builds for python 3.7 and 3.8 - Fixed syntax warning on line 44. - Update M2Crypto.six to 1.13.0 - base64.decodestring() was finally removed in Python 3.8. - wrap SocketIO in io.Buffered* for makefile - NULL is legal argument for key and iv paramters of EVP_CipherInit(3) - Expose X509_V_FLAG_ALLOW_PROXY_CERTS verification flag and X509_STORE_SET_FLAGS function - Stop testing for 2.6 and 3.4 on Travis. Start testing 3.8 - Extend test cert validity to 2049 - Revert using typing module in 2.6. It is just not worthy. - Update Debian/stable SSL as well - Make tests pass again. - Stop using string module, which has been deprecated. - Tiny fixes to make pyls more happy - CI: Rework Fedora CI configuration 0.35.2 - 2019-06-10 ------------------- - tests.test_rsa: Fix typo to match for proper exception - Expose CRLs verification flags 0.35.1 - 2019-06-08 ------------------- - Actually, really fix compatibility with OpenSSL 1.1.1c. Thank you, Sebastian Andrzej Siewior from the Debian team for resolving it. 0.34.0 - 2019-05-30 ------------------- - Use more recent version of OpenSSL on Windows - Be resilient against the situation when no erorr happened. - Correct URL of https://www.schneier.com/academic/smime/ - Use shlex.split() for CPP 0.33.0 - 2019-04-26 ------------------- - eb4525c - Stop pretending to support Python 3.4. - 6a89548 - Fix use of urlunsplit (25 hours ago) - 0a5a356 - tests/test_ssl: use -ciphercuites for TLS1.3 cipher in openssl1.1 - 8a0a3e3 - There are apparently multiword CPP variables. Taking that into account. 0.32.0 - 2019-03-04 ------------------- - 471582f - setup.py: use ${CPP} as path to cpp - efb1580 - Bump pipeline OpenSSL from 1.1.0i to 1.1.0j - 35bb71b - Stub wchar_t helpers and ignore unused WCHAR defs - effc7be - Add type comment to setup.py 0.31.0 - 2018-11-08 ------------------- - Compatibility with OpenSSL 1.1.1 (partly workaround, maybe requires further investigation) - Fixes for Windows builds - Fixes of installs on AWS Lambda - Fixes of Mac OS X related failures - Fix Python 2.6 compatibility issues 0.30.1 - 2018-04-29 ------------------- - Fix packaging (missed packaging testing file) 0.30.0 - 2018-04-25 ------------------- - Various small typos (Windows builds, Fix SSL.Connection.__del__) - The project is now Linux-distribution agnostic - Replace all old-style classes with the new ones (it shouldn't cause any problems, but feel free to file an issue, if it does) - Do not by-pass a potential transfer decoding in m2urllib2 - Update M2Crypto.six with 1.11.0 and replace our local workarounds with new functions. - SSLv3 just removed. - Don't support Python 2.6 on Windows anymore. Windows users don't have python as a system package, so they are usually more likely to upgrade anyway. 0.29.0 - 2018-02-23 ------------------- - Fix building on Windows (all tests fix on Win32 and Win64 on all supported combinations of versions of OpenSSL and Python) - Fixes of some small bugs 0.28.0 - 2018-02-08 ------------------- - Mainly port to Python 3 (supporting 2.6, 2.7, 3.3, 3.4, 3.5, 3.6) - Some lame efforts to make setup.py build --openssl work better (needs more real testing on Mac OS X) - Fix licence: it is MIT, not BSD - Fix and add tests for SWIG/_aes.i module - Improve somehow situation on Mac OS X (some testing, improve setup.py, testsuite should fully pass) - Bundle-in unittest2 for Python 2.6 (dealing with the need for specific version of unittest2 package was too complicated) - Remove all PGP modules 0.27.0 - 2017-10-05 ------------------- - Fix licence: it is MIT, not BSD - At least minimal support of SNI in httpslib. - Small bugfixes and cleanups. - More effort to make build system more robust (now should work even on Debian LTS). - Restore m2.rsa_set_e() and m2.rsa_set_n(). - Make sure that every exceptional return throws and exception and vice versa. 0.26.4 - 2017-09-26 ------------------- - Proper fix of deprecation warning for OpenSSL 1.1.0 - Small mostly stylistic bugfixes - Emergency release to fix FTBFS. 0.26.3 - 2017-09-22 ------------------- - Fix a syntax typo. 0.26.2 - 2017-09-20 ------------------- - port to support OpenSSL 1.1.0 API - add generated Sphinx documentation - another set of cleanups 0.26.0 - 2017-03-21 ------------------- - Fix packaging on RHEL-6 - Replace ASN1_UTCTIME with ASN1_TIME which supports both UTCTime and GeneralizedTime - Add possibility to sign PKCS7 with a non-default digest. - Add possibility to set custom callback for X509 verification. - Clean up imports and PEP8ization - A lot of cleanups on the way towards Python 3 - Other small bugfixes 0.25.1 - 2016-07-25 ------------------- - Actually do check, whether we have SSLv2 compiled in, and don't run test for it. 0.25.0 - 2016-03-21 ------------------- - More cleanups, removal of obsolete stuff, and moves towards py3k compatibility. - Add support for EC.get_builtin_curves() and use it for testing. - Enable AES CTR mode - Bundle-in six module v. 1.10.0 - add rand_file_name and rand_status - remove all LHASH fiddling - Extend Travis and GitLab CI configuration to test also py3k (with allowed_failures) and CentOS6 (on GitLab CI). - Add CONTRIBUTORS.rst. Thank you! - Add PEP-484 type hints in comments to all Python files (except for tests) - Use context managers for file handling wherever possible instead of leaking open file descriptors. - Improve defaults handling for SSL_CTX_new(). - Fix PGP tests to actually run 0.24.0 - 2016-03-21 ------------------- - More cleanups, removal of obsolete stuff, and moves towards py3k compatibility. - Add DSA.pub_key_from_params() factory function (and m2.dsa_set_pub()). - Allow import/export of EC public key with binary values - Add EVP.load_key_string_pubkey() function, as well as helper functions - Add EVP.get_digestbyname() functionality. - Convert documentation to rST (and add instructions for building on Mac OS X) - Another round of fixing multiarch building. - Disable tests with weak ciphers on some platforms (Debain) 0.23.0 - 2016-01-29 ------------------- - Add Travis and GitLab CI configurations - Allow building without SSLv2 - More cleanups and removing obsolete code - Fix README - Fix buffer overflow in pkcs5_pbkdf2_hmac_sha1 - First moves towards Python 3 compatibility - Removed rather large and completely unmaintained demo/ subdirectory (now in a separate repo https://gitlab.com/m2crypto/m2crypto_demo) - Automatically generated test data files - Finally fix building on multiarch systems - All objects derived from BIO.BIO now could work as context managers - Switch setup.py to setuptools 0.22.5 - 2015-10-13 ------------------- - Add forgoteen SWIG/*.h among distributed files. 0.22.4 - 2015-10-13 ------------------- - Matěj Cepl takes over leadership of the upstream maintenance - Fedora/RHEL distribution patches merged to the main development (mainly, but not only, upgrading to the more recent versions of OpenSSL, swig which is now at 3.0.5, but anything above 2.0.4 is supported as well, and python which now has to be at least 2.6). - Tons of cleaning up the code for obsolete constructs, PEP8ization, etc. 0.22.3 - 2014-01-22 ------------------- (released by Martin Paljak, later development started on top of 0.21.1 with his improvements cherry picked to the new development branch) 0.21.1 - 2011-01-15 ------------------- - Distribution fix 0.21 - 2011-01-12 ----------------- - Support OpenSSL 1.0. Thanks to Miloslav Trmac for figuring out how to fix test_smime.py - Rename m2.engine_init to engine_init_error so that ENGINE_init and ENGINE_finish can be exposed, thanks to Erlo - 0.20 started releasing Python locks even around some operations that interacted with the Python runtime, potentially causing crashes and other weirdness, fix by Miloslav Trmac - Make httpslib.ProxyHTTPSConnection work with Python 2.3 0.20.2 - 2009-10-06 ------------------- - (Re)Enable configuration and use with OpenSSL 0.9.7g and older by disabling RSA PSS methods when using such old OpenSSL, thanks to Stef Walter 0.20.1 - 2009-08-27 ------------------- - Fix regression in httpslib.ProxyHTTPSConnection, by Miloslav Trmac 0.20 - 2009-08-10 ----------------- - Deprecated M2Crypto.PGP subpackage since nobody seems to be using it nor is it being maintained (if you do use it, please let me know) - Added fedora_setup.sh to help work around differences on Fedora Core -based distributions (RedHat, CentOS, ...); thanks to Miloslav Trmac - Added X509.load_request_bio and load_request_string, by Hartmut Goebel and Pavel Shramov - Added alias X509.Request.set_subject for set_subject_name to match X509.X509, by Pavel Shramov - OBJ_* wrappers did not work properly with OpenSSL 0.9.8a and earlier, fix by Pavel Shramov - Added ASN1_UTCTIME.get_datetime and set_datetime, by Pavel Shramov - Fixed obj_obj2txt, which returned nonsense, fix by Barney Stratford - m2urllib did not close sockets properly, fix by Miloslav Trmac - Allow SSL peer certificate to have subjectAltName without dNSName and use commonName for hostname check, fix by Miloslav Trmac - threading_locking_callback did not block on a lock when the lock was held by another thread, by Miloslav Trmac - Allow more blocking OpenSSL functions to run without GIL, by Miloslav Trmac - Fixed httpslib to send only the path+query+fragment part of the URL when using CONNECT proxy, by James Bowes - SSLServer.__init__ now takes optional bind_and_activate parameter and initializes by calling SocketServer.BaseServer.__init__, which are Python 2.6 compatibility fixes, by Christian - ftpslib now works with Python 2.6, by Theodore A. Roth - httpslib.ProxyHTTPSConnection needs to cast port into integer, by John M. Schanck - Added support for RSASSA-PSS signing and verifying, by Chris Collis - Added support for disabling padding when using RSA encryption, by Chris Collis - ASN1_INTEGERs can now be larger than fits in an int, for example to support X509 certificates with large serial numbers, patch by Mikhail Vorozhtsov and testcase by Barry G. - Reverted a change done in 0.17 to m2urllib2 which changed urls to include host when it should stay as it was - httpslib no longer uses urllib; instead it uses urlparse for url parsing - SMIME.text_crlf and text_crlf_bio were always raising TypeError; fixed - EVP.load_key and load_key_bio fixed to raise EVP.EVPError and BIO.BIOError instead of str (str exceptions not allowed in Python 2.6 and later) - SSL.Session.load_session fixed to raise SSL.SSLError instead of str - SMIME.load_pkcs7, load_pkcs7_bio, smime_load_pkcs7, smime_load_pkcs7_bio, text_crlf, text_crlf_bio fixed to raise BIO.BIOError, SMIME.PKCS7_Error and SMIME.SMIME_Error as appropriate instead of str - Added FIPS mode to unit tests, and used FIPS-compliant key sizes in other tests, by Miloslav Trmac. Note that tests run much slower because of this! - Unit tests cover 80% of the code 0.19.1 - 2008-10-12 ------------------- - Re-enable building when OpenSSL built without EC support, by Miloslav Trmac - Remove shebang from Engine.py since it is not executable, by Miloslav Trmac 0.19 - 2008-10-05 ----------------- - OpenSSL OBJ_* functions wrapped by Pavel Shramov - OpenSSL ENGINE interface wrapped, providing support for smart cards, by Martin Paljak and Pavel Shramov - EVP.PKey.get_rsa() now returns RSA_pub, which fixes segmentation fault when trying to encrypt using public key from X509 certificate, by Ben Timby - httpslib.ProxyHTTPSConnection now sends the required Host header, by Karl Grindley - Use the proxied User-Agent value in CONNECT requests, by James Antill and Miloslav Trmac - Fixed m2urllib.build_opener when optional handlers were in use, affected Python 2.5 and later, by Miloslav Trmac - Reverted the incorrect GIL change done in 0.18 to m2.passphrase_callback, which caused a deadlock when called from mod_python for example. Thanks to Michal Kochel and Keith Jackson. - SSL.Connection.accept() passed wrong certificate to postConnectionCheck callback - httpslib.HTTPSConnection now raises ValueError for illegal keyword argument - m2.pkey_write_pem[_no_cipher] changed to use the recommended (more secure) PEM_write_bio_PKCS8PrivateKey (used by PEM_write_bio_PrivateKey). - X509.load_cert, load_cert_bio, load_cert_der_string, new_stack_from_der, load_request and load_crl now raise X509Error for invalid data. Previously some of these raised a string as an error, some did not raise but caused strange errors later, for example x509.verify() would return -1. - Fixed SSL.Connection.get_socket_read_timeout and set_socket_read_timeout on 64bit platforms by adding SSL.timeout.struct_size() and using it instead of hardcoded size for socket.getsockopt - X509_Store.load_info now returns the value from the underlying m2.x509_store_load_locations call, and in case of error raises X509Error - Fixed SMIME.verify to raise the correct PKCS7_Error (used to raise SMIME_Error) when verification fails with Python 2.6 0.18.2 - 2007-10-12 ------------------- - typedef Py_ssize_t was insufficiently guarded, now follows PEP 353. This prevented building on at least Red Hat Linux and Debian Linux (unstable). 0.18.1 - 2007-10-08 ------------------- - Redo build fix when OpenSSL configured without Elliptic Curves (EC), see also INSTALL file 0.18 - 2007-07-26 ----------------- - Added EVP.pbkdf2 to derive key from password - X509_Store_Context.get1_chain added - Added X509_Name.__iter__, __getitem__, get_entries_by_nid which allow iterating over all X509_Name_Entries or getting just all commonName entries, for example - Added X509_Name_Entry.get_object, get_data, set_data - Added back PKCS7.get0_signers (was removed in 0.16) - X509_Extension.get_value accepts flag and indent parameters. - support multiple dNSName fields in subjectAltName - support multiple commonName fields for SSL peer hostname checking - Checking for erroneous returns from more OpenSSL EVP_* functions, which means that certain things that used to fail silently will now raise an EVP.EVPError; affected m2 functions are: digest_final, cipher_init, cipher_update, cipher_final and sign_update. sign_final will now raise EVP.EVPError instead of SystemError as well. - Fixed Pkey.verify_final to take a sign parameter - If a subjectAltName extension of type dNSName is present in peer certificate, use only the dNSNames when checking peer certificate hostname, as specified by RFC 2818. If no dNSNames are present, use subject commonName. - Fixed memory leaks in m2 functions ec_key_new_by_curve_name, pkey_get_modulus, ecdsa_verify, threading_init and X509.X509.verify, X509.X509_Stack (which manifested for example when calling X509.new_stack_from_der), SSL.Connection (which manifested with some connection errors or when connect was never called), twisted wrapper, SSL.Connection.makefile (in BIO.IOBuffer really) - Fixed threading regressions introduced in 0.16, by Aaron Reizes and Keith Jackson - Added SSL session caching support to HTTPSConnection, by Keith Jackson - Added the ability to save and load DER formatted X509 certificates and certificate requests, by Keith Jackson - m2xmlrpclib.py fixed to work with Python 2.5, by Miloslav Trmac - 64-bit correctness fixes, by Miloslav Trmac - Added X509_Name.as_hash, by Thomas Uram - Moved --openssl option from general setup.py option to build_ext option, meaning you need to do: python setup.py build build_ext --openssl=/path, by Philip Kershaw - Fixed build problem affecting certain systems where OpenSSL was built without EC support - M2CRYPTO_TEST_SSL_SLEEP environment variable controls how long to sleep after starting the test SSL server. Default is 0.5, but 0.1 or even 0.05 might work with modern computers. Makes tests finish significantly faster. 0.17 - 2006-12-20 ----------------- - setup.py has new test command to run unit tests (requires setuptools) - Added m2urllib2, by James Bowes (python 2.4 and later, at least for now) - Added CONNECT proxy for httpslib and m2urllib2, by James Bowes - Added PKey.get_modulus, X509.get_fingerprint, X509_Name.as_der and m2.bn_to_hex, by Thomas Uram - Prevent Connection.makefile from freeing bio redundantly, by Thomas Uram - Added Err.peek_error_code, by Thomas Uram - Fixed m2urllib.open_https to return the response headers, otherwise code that relied on that would break (for example msnlib-3.5), by Arno bakker - Fixed twisted wrapper to work with >16kb BIO buffers, by Martin Paljak - Added support for remaining ECs, by Larry Bugbee - Fixed DSA.save_key and DSA_.save_pub_key, by Larry Bugbee - SSL.Context.load_verify_locations raises ValueError if cafile and capath are both None - Fixed X509.check_purpose() (was always raising exceptions) - smime_read_pkcs7 was changed to automatically call BIO_set_mem_eof_return on memory BIOs because otherwise the read would fail with "SMIME_Error: not enough data" - X509.new_extension('subjectKeyIdentifier', 'hash') raises ValueError instead of crashing Python 0.16 - 2006-07-05 ----------------- - Minimum requirements updated: Python 2.3+, OpenSSL 0.9.7+, SWIG 1.3.24+ - Optional features from OpenSSL 0.9.8 and newer - Enhancements to EVP and X509 to allow proxy certificate handling, by Matt Rodriguez - SSLBio and related additions to help do SSL with BIOs directly, by Matt Rodriguez - Added --openssl option to build command which can be used to specify where OpenSSL is installed, by Matt Rodriguez - Added sign and verify to RSA class, and get_rsa to PKey class, by Matt Rodriguez - ECDSA signatures and ECDH key agreement, requires OpenSSL 0.9.8+, by Arno Bakker - Fix non-hashable type problems in SSL._ctxmap and users, by Michael Weiser - Fixed SSLServer.handle_error to take the correct number of arguments, by Dan Williams - Various DSA enhancements by Larry Bugbee - Added sha224, sha256, sha384 and sha512, by Larry Bugbee - Added serialNumber, SN, surname, GN and givenName fields to X509_Name, by Martin Paljak - m2.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT is the fourth certificate verification error that will be allowed when unknown CAs are allowed - post connection checks in Connection.accept() and connect() fixed (these were broken in 0.15) - Fixed EVP.Cipher to work with aes_* ciphers (used to crash Python). The actual problem was in m2.bytes_to_key. - SMIME methods and functions raise correct exceptions - Raise ValueError instead of AttributeError when a non-existing hash algorithm or SSL version is asked for - ssl_ctx_set_tmp_(dh|rsa) now return value, and the rsa version calls the rsa function instead of the dh function - digest_update and verify_update return type changed to int, which allows better error reporting; EVP.MessageDigest.update and EVP.PKey.verify_update likewise changed - X509_Name and ASN1_String as_text (new for ASN1_String) take optional parameters to control formatting. - Cipher_Stack, X509_Stack and X509_Extension_Stack are iterable - EVP.MessageDigest now properly cleans up the underlying data when the object gets deleted - It is now possible to set and get non-nid values to X509_Name (previously only set worked) - SSL.Connection.set_client_CA_list_from_file now uses the actual implementd function instead of raising exception - Multithreaded SSL no longer uses the SSL_set/get_app_data to set and restore thread state, but uses the standard PyGILState_STATE instead. - m2urllib no longer outputs the HTTP headers (there was an erronous call to set_debuglevel(1)) - Removed RCS_id, RCS_ID and _RCS_id from Python files - All known memory leaks fixed - SWIG and compiler warning fixes - More and better Epydoc formatted docstrings - More than doubled the number of unit tests, also made many demos into tests 0.15 - 2005-08-17 ----------------- - Support OpenSSL 0.9.8, Python 2.4.1, SWIG 1.3.24 - Fixed multiple memory leaks - Twisted integration - Safer defaults for SSL context and post connection check for clients - Eliminated C pointers from interfaces (some may still remain in callbacks) - Many cases where Python interpreter crashed have been fixed - Improved thread safety of many callbacks - And of course more of the OpenSSL API is covered, new docstrings and tests have been written Changes since 0.13 -------------------- - Fixed memory leak due to circular reference in SSL.Connection. Thanks to Michael Dunstan. Oops, patch is ZServerSSL-specific. Andre Reitz provided a generalised fix. Thanks Andre. - Fixed __getattr__ error in DSA. Thanks to Igor Belyi. - Added rand_poll, rand_screen and rand_win32_event functions to M2Crypto.Rand. - Updated ZServerSSL files to match Zope 2.7.0 versions. - Integrated (overlapping) patches by Peter Teniz and Heikki Toivonen covering operations on X.509-related structures that gives M2Crypto PKI functionality. Thanks Peter and Heikki. - Peter Teniz contributed demo2004/pki/x509auth.py. - Created demo2004/ directory that will contain new or updated demos. - Added verify_[init|update|final] in _evp.i. Patch by Zachery Corbiere. Thanks Zac. Changes since 0.12/0.11 ------------------------- - Patches from Artur Frysiak . Thanks Artur. = Allow using a passphrase callback in class SMIME. = Added method get0_signers to class PKCS7, which retrieves signers' certificates from a PKCS7 blob. = Added methods as_pem and save_pem to class X509. = Added file version.py. = Allow SSL.Context.load_verify_locations to accept both 'cafile' and 'capath'. - Fixed BIO.read() not reading until EOF. Thanks to Egil Muller for suggestion. - Honour 'mode' parameter in SSL.Connection.makefile. Thanks again to Egil Muller. - Roger Binns contributed epydoc-generated docs for M2Crypto. Thanks Roger. - Peter Teniz contributed patches to create X.509 requests and certificates. Thanks Peter. - Updated Medusa to 0.54. - Make various OpenSSL bignum functions (written long ago) available to Python. Changes since 0.11 -------------------- - ZServerSSL with client certificate-based authentication rides again. - Created Makefile for Python 2.3. - Modified LICENCE: changed my name to the generic "the author" in the all-caps disclaimer paragraph. - Allow to save RSA key pair in the clear. - ZServerSSL for Zope 2.7. - Excluded RC5. IDEA was taken out several releases ago. This should allow M2Crypto to build with stock OpenSSL on various Linuxen. - Added ssl_set_tmp_dh_callback. - Added ssl_set_tmp_rsa and ssl_set_tmp_rsa_callback to support weak-cipher browsers. - ZServerSSL exports SSL_CIPHER request header (a la mod_ssl) to Zope applications. - Perform distutils's SWIG .i search path tweaking within setup.py. setup.py should now work "out of the box". - Added contrib/smimeplus.py, a high-level S/MIME interface, contributed by Bernard Yue . Thanks Bernard. - Added in long forms of nid's in X509_Name. Thanks to William K Volkman for patch. - Updated Mac OS X build instructions. Thanks to Larry Bugbee Changes since 0.10 -------------------- - Dave Berkeley contributed fixes to SSL.Context-related memory leaks and code to set the size of the SSL session cache. - Brent Chun contributed the following: + Fixes to memory leaks. + Code to expose X.509 certificate chain operations. + Code to expose set/get operations on the SSL session cache. - Changed swig/ to SWIG/, for the convenience of people who don't read INSTALL. Some Makefiles may break because of this. setup.py continues to work, of course. - ZServerSSL tested with Zope 2.6.1. There is now a HOWTO. - Updated README and INSTALL. - Filled doc/ with stuff that went missing in several past releases. Changes since 0.09 -------------------- - Updated to OpenSSL 0.9.7. Thanks to Toby Allsopp for patches. - Added functionality to create a basic certificate request. Also contributed by Toby Allsopp. - Finally, AES! Changes since 0.08 -------------------- - Replaced demo/Zope/ZServer/__init__.py with the correct version for Zope 2.6.0. - Added a sample starts.bat for ZServerSSL. - Incoporated a patch by prashanth@jibe.biz that handled the new-in-Python-2.2.2 "strict" parameter for the various HTTP[S] connection classes in httplib.py. Thanks prashanth. This fixes M2Crypto's XMLRPC support for Python 2.2.2. (Apparently it was working for Python 2.2.1.) - Incorporated some cosmetic patches from Adam Karpierz . Thanks Adam. Changes since 0.07 snapshot #3 -------------------------------- - Updated to SWIG 1.3.17. - Excluded IDEA. - Tested with OpenSSL 0.9.6h. - ZServerSSL rides again for Zope 2.6.0. - setup.py does! - Removed Makefiles for Windows and Unix. (Makefile.osx remains.) - Included in contrib/ Isaac Salzberg's application of Mihai Ibanescu's patch that allows IIS interoperability thru an authenticating proxy. Thanks Isaac. - Included in contrib/ patch by Dave Brueck that has smarter non-blocking behaviour. Thanks Dave. Changes since 0.06 ----------------------- - test_ssl_win.py. (Requires Mark Hammond's Win32 extensions.) - Renamed demo/https to demo/medusa; updated Medusa to 2001 Jun release. - Improved _ssl.i's and M2Crypto.SSL.Connection's accept/connect methods. - M2Crypto.ftpslib for client-side FTP/TLS. - demo/medusa/ftps_server.py for server-side FTP/TLS. - Improved thread-safety. - Cleaned up echo client and servers. - Fixed missing import in m2urllib. - Fixed m2urllib to handle HTTP redirects. - Python 2.2 compatibility. - AuthCookie - secure authenticator cookies. Changes since 0.05 ----------------------- - Handled the cases where Python callbacks raised exceptions. - Fixed a NULL-deref bug in _ssl.i which crashes Medusa https when IE or Opera comes a-calling. - ZServerSSL rides again - a more robust ZServerSSL for Zope 2.3.0. - Added the MIME type 'application/x-x509-ca-cert' to demo/ssl/https_srv.py. This facilitates installing self-generated certificates into your browser. - ZSmime and GuardedFile bundled. - Documentation! A HOWTO on operating your own CA. - Documentation! A HOWTO on S/MIME. Examples are in demo/smime.howto. - Python 2.1 compatibility. - Fixed demo/https/https_server.py's CPU-spinning. (As per ZServerSSL.) - Fixed m2urllib's unexpected eof - demo/ssl/urllib_cli.py now works. - Renamed xmlrpclib2.py to m2xmlrpclib.py. - Kludged SSL.ssl_dispatcher to do blocking connect()'s: see demo/ssl/https_cli_async.py. - SWIG 1.3.6 does! Thanks to Keith Jackson . Changes since 0.04 ----------------------- - Fixed a silly reversed-logic bug in M2Crypto.SSL.Connection.setblocking(). - Fixed yet more memory leaks. Thanks to Ray Suorsa . - Build instructions for Borland BC++ 5.5 free compiler suite. - Bundles the June 2000 unencumbered release of Medusa. - SSL callback thread-safety. Thanks again to Ray Suorsa for insights and patches. - Renamed M2Crypto.M2Crypto to M2Crypto.m2 to prevent package/module loading confusion. - SSL.Session and a demo in demo/ssl/sess.py. - https_srv.py, an enhanced, https version of SimpleHTTPServer.py. - Interface change: SMIME.load_pkcs7_bio() is renamed SMIME.smime_load_pkcs7_bio(), similarly SMIME.load_pkcs7() to SMIME.smime_load_pkcs7(); these load PKCS7 objects generated by S/MIME. - Interface change: SMIME.load_pkcs7_bio() now loads a PKCS7 PEM file, i.e., a file of the format "-----BEGIN PKCS7-----". - Works with both Python 2.0 and Python 1.5.2. - OpenSSL 0.9.6. (Possibly incompatible with earlier OpenSSL releases.) - Unit tests with PyUnit. - Improved C code: = Custom Python exceptions. = Diligent error checking. = Fixed memory leaks. - Renamed M2Crypto.urllib2 to M2Crypto.m2urllib. - HTTPS clients of Python 1.5.2's and Python 2.0's httplib and urllib. Changes since 0.03 ----------------------- - SSL certificate-based authentication with Python callback. - More robust SSL.Connection - raises exceptions, not dumps core. - Fixed (some) memory leaks and multiple-free()s. - Cleaned up EVP.HMAC and EVP.PKey. - More X.509 certificate manipulation. - An interface to create SSL sessions. - Unified SSL read() and write() for synchronous and asynchronous operation. - S/MIME and PKCS #7. - Integrated with OpenSSL 0.9.5. - Enhanced the PRNG interface. Changes since 0.02 ----------------------- 1. Ephemeral DH for SSL. 2. ThreadingSSLServer now does. 3. XMLrpc over https. 4. ZServerSSL for Zope 2.1.3. 5. Encrypting monitor for Zope 2.1.3. 6. Beginnings of PGP2 support. 7. Replaced eval() calls with other (hopefully) safe ones. 8. Miscellaneous enhancements and bug fixes. Changes since 0.01 ----------------------- 1. Beginnings of SSL support. For building servers, blocking i/o: - An SSLServer modeled after SocketServer. - A ForkingSSLServer that seems to work well. - A ThreadingSSLServer that runs one thread at a time. (!) ;-) For building servers, nonblocking i/o: - An ssl_dispatcher modeled after asyncore.dispatcher. A HTTPS server based on Medusa. For client-side web programming: - httpslib - urllib2 2. Support for some BIO objects. 3. Reduced per-module name space pollution. 4. Have Swig check for NULL pointers: reduced .i cut-&-paste. 5. Standardise on MPINT for passing big integers between Python and OpenSSL. 6. Removed MD5, SHA1, RIPEMD160. Just use EVP.MessageDigest. 7. Removed HMAC. Just use EVP.HMAC. m2crypto-0.42.0/CONTRIBUTORS.rst000066400000000000000000000034651465575656700161050ustar00rootroot00000000000000* The original project was created inside of the huge `Chandler project`_ where it was mostly work of Ng Pheng Siong [#]_ . * Then for a log time it was maintained and extended to the large part by Heikki Toivonen. With 247 and 415 commits, respectively, these two first maintainers provided by far the biggest amount of work on the project. Thank you. * An attempt to restart the project was made by Martin Paljak. Although his effort was most mostly discarded in the end, all his suggested changes were reviewed and some of them incorporated in some other form. Just two commits of his remaining in the tree hugely underestimate an effort he made to keep this project alive. Thank you very much for your work. * Plenty of work on keeping this project alive was made by the maintainer of the package inside of RHEL, Martin Trmač. He also helped a lot by advice with this last effort to revive the project, and his pestering me to do proper small commits rather than freaking dumps of my current thoughts helped to make changes to be made a little bit better (and revieweable). * This last hyena-like effort to revive a dead carcas has been started by Matěj Cepl. * I got a lot of help especially with reviewing patches from Hubert Kario. * Craig Rodrigues didn't loose the hope that M2Crypto could be ported to be py3k-compatible, which lead to the renewed effort to do so. He also helped with plenty of patches in this effort. * Casey Deccio helped a lot with fixing EC module. * Remaining contributors could be find in the output of ``git shortlog -s`` command. Thank you to all. .. _`Chandler project`: https://en.wikipedia.org/wiki/Chandler_%28software%29 .. [#] His and everybody else emails can be found in the git log, I won't make spammers even more happy to collect them here. m2crypto-0.42.0/INSTALL.rst000066400000000000000000000143301465575656700152470ustar00rootroot00000000000000Installing M2Crypto =================== .. contents:: Pre-requisites -------------- The following is required to *use* M2Crypto (once installed): - ``Python 3.6`` or newer - ``OpenSSL 1.1.1t`` or newer To *install* M2Crypto, you must be able to compile and link C sources against Python and OpenSSL headers/libraries. For example on a Debian-based system the following packages are needed: - ``build-essential`` - ``python3-dev`` and/or ``python-dev`` - ``libssl-dev`` - ``swig 4.0`` or newer (for compatibility with Python 3.12, for older Pythons the default platform swig should be enough). Installing on Unix-like systems, including Cygwin ------------------------------------------------- (not tested and most likely obsolete, updated information for building with Cygwin are welcome).:: $ tar zxf m2crypto-.tar.gz $ cd m2crypto- $ python setup.py build $ python setup.py install If you have installed setuptools you can also optionally run tests like this::: $ python -munittest discover -v tests This assumes OpenSSL is installed in ``/usr``. You can provide an alternate OpenSSL prefix location with --openssl option to ``build\_ext`` (or ``build``) command. So, for example, if you build your local version of OpenSSL and install it with ``/usr/local`` prefix (your includes are in ``/usr/local/include/openssl`` and libs in ``/usr/local/lib``), then you would add ``--openssl=/usr/local`` to your ``build`` command. Differences when installing on Windows -------------------------------------- (Python 2.6 is not supported on Windows anymore, please, just update to 2.7 if you want to stay on Python 2) (needs updating) Before building from source, you need to install OpenSSL's include files, import libraries and DLLs. OpenSSL 1.1.0 and on are installed by default in ``%ProgramFiles(86)%\OpenSSL`` (32-bit), or in ``%ProgramW6432%\OpenSSL`` (64-bit), or as a last resort, in ``%ProgramFiles%\OpenSSL``. setup.py will look in those locations. OpenSSL before 1.1.0 doesn't have a default install location, so you have to specify its install location explicitely. As with other platforms, you can specify a OpenSSL location with --openssl option to ``build\_ext`` (or ``build``) command. For example, ``--openssl=c:\pkg\openssl`` would specify that the OpenSSL include files can be found in ``c:\pkg\openssl\include`` and the librariesin ``c:\pkg\openssl\lib``. The '--openssl' option will configure swig and the compiler to look in the default locations for headers and libraries. If your OpenSSL is installed in a or you want to modify the default options run the build_ext step with normal distutils options: `--swig-opts`, `--include-dirs`, `--library-dirs`, and `--libraries`. MSVC++ ~\ :sub:`:sub:`:sub:`~``` setup.py is already configured to work with MSVC++ by default. With MSVC++, the OpenSSL pre 1.1.0 DLLs, as built, are named ``libeay32.dll`` and ``ssleay32.dll``. The OpenSSL 1.1.x DLLs are named ``libcrypto-1_1.dll`` and ``libssl-1_1.dll``. Install these somewhere on your PATH; for example in ``c:\bin``, together with ``openssl.exe``. For MSVC++, the import libraries, as built by OpenSSL pre 1.1.0, are named ``libeay32.lib`` and ``ssleay32.lib``. The OpenSSL 1.1.x import libraries are named ``libcrypto.lib`` and ``libssl.lib``. MINGW :sub:`:sub:`:sub:`~``` .. NOTE:: The following instructions for building M2Crypto with MINGW are from M2Crypto 0.12. These instructions should continue to work for this release, although I have not tested them. Read Sebastien Sauvage's webpage:: http://sebsauvage.net/python/mingw.html For mingw32, the OpenSSL pre 1.1.0 import libraries are named ``libeay32.dll.a`` and ``libssl32.dll.a``. You may need to edit setup.py file for these. You'll also need to create ``libpython2[123].a``, depending on your version of Python. OpenSSL pre 1.1.0 DLLs for mingw32 are named ``libeay32.dll`` and ``libssl32.dll``. OpenSSL 1.1.x DLLs are named ``libcrypto-1_1.dll`` and ``libssl-1_1.dll``. Install these somewhere on your PATH; for example in ``c:\bin``, together with ``openssl.exe``. Build M2Crypto:: python setup.py build -cmingw32 python setup.py install BC++ :sub:`:sub:`~``\ ~ .. NOTE:: The following instructions for building M2Crypto with MSVC++ 6.0 and BC++ 5.5 free compiler suite are from M2Crypto 0.10. These instructions should continue to work for this release, although I have not tested them. .. NOTE:: OpenSSL 1.1.x doesn't support BC++. For BC++ these files are created from the MSVC++-built ones using the tool ``coff2omf.exe``. I call them ``libeay32_bc.lib`` and ``ssleay32_bc.lib``, respectively. You will need to edit setup.py file for these. You'll also need Python's import library, e.g., ``python22.lib``, to be the BC++-compatible version; i.e., create ``python22_bc.lib`` from ``python22.lib``, save a copy of ``python22.lib`` (as ``python22_vc.lib``, say), then rename ``python22_bc.lib`` to ``python22.lib``. Now you are ready to build M2Crypto. Do one of the following:: python setup.py build python setup.py build -cbcpp Then,:: python setup.py install MacOSX ------ Apple does not provide on more recent versions of Mac OS X (at least certainly `since 10.11`_) any version of OpenSSL, so it is necessary to use ``brew`` or similar packaging systems to install third party packages. A Mac OS X users suggested, that this series of commands gave him a working copy of M2Crypto on his system:: $ brew install openssl && brew install swig $ brew --prefix openssl /usr/local/opt/openssl $ LDFLAGS="-L$(brew --prefix openssl)/lib" \ CFLAGS="-I$(brew --prefix openssl)/include" \ SWIG_FEATURES="-I$(brew --prefix openssl)/include" \ pip install m2crypto .. _`since 10.11`: https://gitlab.com/m2crypto/m2crypto/merge_requests/7#note_2581821 m2crypto-0.42.0/LICENCE000066400000000000000000000024361465575656700144000ustar00rootroot00000000000000Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. Portions copyright (c) 2004-2006 Open Source Applications Foundation. All rights reserved. Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All rights reserved. Copyright (c) 2008-2010 Heikki Toivonen. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. THE AUTHOR PROVIDES THIS SOFTWARE ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. m2crypto-0.42.0/MANIFEST.in000066400000000000000000000005551465575656700151510ustar00rootroot00000000000000include src/SWIG/*.i include src/SWIG/*.h include src/SWIG/*.def recursive-include tests *.py *.pem *.der *.b64 README *.pgp *.dat *.p7* *.crt *.txt recursive-include doc * recursive-include contrib * recursive-exclude .keys * include INSTALL.rst include README.rst include CHANGES include LICENCE include src/SWIG/_m2crypto_wrap.c include src/M2Crypto/m2crypto.py m2crypto-0.42.0/README.rst000066400000000000000000000052731465575656700151040ustar00rootroot00000000000000======== M2Crypto ======== :Maintainer: Matěj Cepl :Web-Site: https://sr.ht/~mcepl/m2crypto/ :Documentation: https://m2crypto.readthedocs.io/ :Email list: https://lists.sr.ht/~mcepl/m2crypto (`subscribe via email`_) :Issue tracker: https://todo.sr.ht/~mcepl/m2crypto (R/O, please report issues via the email list). M2Crypto = Python + OpenSSL + SWIG ---------------------------------- .. image:: https://builds.sr.ht/~mcepl.svg :target: https://builds.sr.ht/~mcepl? :alt: builds.sr.ht status **NOTE: This library is currently in maintenance mode. We recommend using a more modern alternative such as** `PyCA/cryptography`_. **Examples of how to migrate can be found in** `the documentation`_. M2Crypto is a crypto and SSL toolkit for Python. M2 stands for "me, too!" M2Crypto comes with the following: - **RSA**, **DSA**, **DH**, **HMACs**, **message digests**, **symmetric ciphers** including **AES**, - **TLS** functionality to implement **clients and servers**. - **Example SSL client and server programs**, which are variously **threading**, **forking** or based on **non-blocking socket IO**. - **HTTPS** extensions to Python's **httplib, urllib and xmlrpclib**. - Unforgeable HMAC'ing **AuthCookies** for **web session management**. - **FTP/TLS** client and server. - **S/MIME v2**. - **ZSmime**: An S/MIME messenger for **Zope**. We care a lot about stable API and all Python methods should be preserved, note however that ``m2.`` namespace is considered internal to the library and it doesn't have to be preserved. If however some change to it breaks your app, let us know and we will try to make things working for you. - And much more. M2Crypto is released under a very liberal MIT licence. See LICENCE for details. To install, see the file INSTALL. Look at the tests and demos for example use. Recommended reading before deploying in production is "Network Security with OpenSSL" by John Viega, Matt Messier and Pravir Chandra, ISBN 059600270X. Note these caveats: - Possible memory leaks, because some objects need to be freed on the Python side and other objects on the C side, and these may change between OpenSSL versions. (Multiple free's lead to crashes very quickly, so these should be relatively rare.) - No memory locking/clearing for keys, passphrases, etc. because AFAIK Python does not provide the features needed. On the C (OpenSSL) side things are cleared when the Python objects are deleted. Have fun! Your feedback is welcome. .. _`subscribe via email`: mailto:~mcepl/m2crypto+subscribe@lists.sr.ht .. _`PyCA/cryptography`: https://cryptography.io/en/latest/ .. _`the documentation`: https://m2crypto.readthedocs.io/en/latest/howto.migration.html m2crypto-0.42.0/contrib/000077500000000000000000000000001465575656700150465ustar00rootroot00000000000000m2crypto-0.42.0/contrib/README000066400000000000000000000002151465575656700157240ustar00rootroot00000000000000This directory contains contributions by users of M2Crypto. Some of these may get folded into the main distribution in time. Thanks guys! m2crypto-0.42.0/contrib/SimpleX509create.README000066400000000000000000000001711465575656700207270ustar00rootroot00000000000000Contributed by Peter Teniz as a demonstration of PKI functionality, also contributed by him. m2crypto-0.42.0/contrib/SimpleX509create.py000066400000000000000000000125271465575656700204320ustar00rootroot00000000000000#!/usr/bin/env python # #vim: ts=4 sw=4 nowrap # from __future__ import print_function """PKI demo by Peter Teniz """ from M2Crypto import ASN1, EVP, RSA, X509, m2 MBSTRING_FLAG = 0x1000 MBSTRING_ASC = MBSTRING_FLAG | 1 MBSTRING_BMP = MBSTRING_FLAG | 2 class Cert(object): def __init__ ( self ): self.RsaKey = { 'KeyLength' : 1024, 'PubExponent' : 0x10001, # -> 65537 'keygen_callback' : self.callback } self.KeyPair = None self.PKey = None self.X509Request = None self.X509Certificate = None def callback ( self, *args ): return 'p' def CreatePKey ( self ): self.KeyPair = RSA.gen_key( self.RsaKey['KeyLength'], self.RsaKey['PubExponent'], self.RsaKey['keygen_callback'] ) #PubKey = RSA.new_pub_key( self.KeyPair.pub () ) self.KeyPair.save_key( 'KeyPair.pem', cipher='des_ede3_cbc', callback=self.callback ) self.PKey = EVP.PKey ( md='sha1') self.PKey.assign_rsa ( self.KeyPair ) def CreateX509Request ( self ): # # X509 REQUEST # self.X509Request = X509.Request () # # subject # X509Name = X509.X509_Name () X509Name.add_entry_by_txt ( field='C', type=MBSTRING_ASC, entry='austria', len=-1, loc=-1, set=0 ) # country name X509Name.add_entry_by_txt ( field='SP', type=MBSTRING_ASC, entry='kernten', len=-1, loc=-1, set=0 ) # state of province name X509Name.add_entry_by_txt ( field='L', type=MBSTRING_ASC, entry='stgallen', len=-1, loc=-1, set=0 ) # locality name X509Name.add_entry_by_txt ( field='O', type=MBSTRING_ASC, entry='labor', len=-1, loc=-1, set=0 ) # organization name X509Name.add_entry_by_txt ( field='OU', type=MBSTRING_ASC, entry='it-department', len=-1, loc=-1, set=0 ) # organizational unit name X509Name.add_entry_by_txt ( field='CN', type=MBSTRING_ASC, entry='Certificate client', len=-1, loc=-1, set=0 ) # common name X509Name.add_entry_by_txt ( field='Email', type=MBSTRING_ASC, entry='user@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address X509Name.add_entry_by_txt ( field='emailAddress', type=MBSTRING_ASC, entry='user@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address self.X509Request.set_subject_name( X509Name ) # # publickey # self.X509Request.set_pubkey ( pkey=self.PKey ) self.X509Request.sign ( pkey=self.PKey, md='sha1' ) #print(X509Request.as_text ()) def CreateX509Certificate ( self ): # # X509 CERTIFICATE # self.X509Certificate = X509.X509 () # # version # self.X509Certificate.set_version ( 0 ) # # time notBefore # ASN1 = ASN1.ASN1_TIME () ASN1.set_time ( 500 ) self.X509Certificate.set_not_before( ASN1 ) # # time notAfter # ASN1 = ASN1.ASN1_TIME () ASN1.set_time ( 500 ) self.X509Certificate.set_not_after( ASN1 ) # # public key # self.X509Certificate.set_pubkey ( pkey=self.PKey ) # # subject # X509Name = self.X509Request.get_subject () #print(X509Name.entry_count ()) #print(X509Name.as_text ()) self.X509Certificate.set_subject_name( X509Name ) # # issuer # X509Name = X509.X509_Name ( m2.x509_name_new () ) X509Name.add_entry_by_txt ( field='C', type=MBSTRING_ASC, entry='germany', len=-1, loc=-1, set=0 ) # country name X509Name.add_entry_by_txt ( field='SP', type=MBSTRING_ASC, entry='bavaria', len=-1, loc=-1, set=0 ) # state of province name X509Name.add_entry_by_txt ( field='L', type=MBSTRING_ASC, entry='munich', len=-1, loc=-1, set=0 ) # locality name X509Name.add_entry_by_txt ( field='O', type=MBSTRING_ASC, entry='sbs', len=-1, loc=-1, set=0 ) # organization name X509Name.add_entry_by_txt ( field='OU', type=MBSTRING_ASC, entry='it-department', len=-1, loc=-1, set=0 ) # organizational unit name X509Name.add_entry_by_txt ( field='CN', type=MBSTRING_ASC, entry='Certificate Authority', len=-1, loc=-1, set=0 ) # common name X509Name.add_entry_by_txt ( field='Email', type=MBSTRING_ASC, entry='admin@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address X509Name.add_entry_by_txt ( field='emailAddress', type=MBSTRING_ASC, entry='admin@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address #print(X509Name.entry_count ()) #print(X509Name.as_text ()) self.X509Certificate.set_issuer_name( X509Name ) # # signing # self.X509Certificate.sign( pkey=self.PKey, md='sha1' ) print(self.X509Certificate.as_text ()) if __name__ == '__main__': run = Cert () run.CreatePKey () run.CreateX509Request () run.CreateX509Certificate () m2crypto-0.42.0/contrib/dave.README000066400000000000000000000053051465575656700166470ustar00rootroot00000000000000From dave@pythonapocrypha.com Wed Dec 11 07:57:55 2002 Date: Tue, 10 Dec 2002 15:05:26 -0800 (PST) From: Dave Brueck To: ngps@netmemetic.com Subject: M2Crypto problem with asynch sockets Hi and thanks for M2Crypto - great stuff! I wrote an asynchronous socket layer and decided to use M2Crypto to add SSL support to it. Unfortunately, I've found a small problem in _m2crypto_wrap.c - hopefully I'm just not understanding something. The ssl_connect, ssl_read_nbio, etc. calls don't differentiate between SSL_ERROR_WANT_WRITE and SSL_ERROR_WANT_READ when a non-blocking call couldn't finish. But without this information, I don't know whether the socket needs to do more reading or more writing before a subsequent attempt will work without blocking. The demo applications (e.g. echod-async.py) don't seem to care about this but they get around it by simply trying the operation over and over again, which I can't do for performance reasons. Am I missing something? I thought about just calling SSL_get_error when the above calls return None (indicating WANT_READ or WANT_WRITE), but by then the error has already been removed from the SSL error queue. Any help or suggestions would be appreciated. I'd be happy to submit a patch fixing those calls, but by not returning None they would break existing code. Thanks again for M2Crypto though! -Dave From dave@pythonapocrypha.com Fri Dec 13 00:46:39 2002 Date: Thu, 12 Dec 2002 09:52:08 -0800 (PST) From: Dave Brueck To: ngps@netmemetic.com Subject: Re: M2Crypto problem with asynch sockets Hello again, Here is a patch to M2Crypto's _ssl.i that illustrates the fix I had in mind in my previous message. You might not want to use it as is since it changes the error semantics of the affected functions (they now raise an exception that contains the SSL_WANT_READ or SSL_WANT_WRITE flag instead of returning None or whatever), but if you tell me how you'd like it instead then I'd be happy to fix the patch and send it back to you. Just to refresh your memory, this patch fixes the problem where a non-blocking call to accept/connect/etc results in an SSL_NEED_READ/WRITE; currently there's no way for the caller to know _which_ of the two occurred and so it must try again once the socket has become readable OR writeable, instead of waiting specifically for one or the other. For many people this won't matter because their performance requirements are low enough that trying the ssl_accept/etc call again prematurely won't hurt too much, but for servers with lots of connections or high throughput it's much more critical to wait until you know the SSL call has a better chance of success. Thanks! -Dave Brueck m2crypto-0.42.0/contrib/isaac.README000066400000000000000000000012271465575656700170070ustar00rootroot00000000000000This is Isaac Salzberg's application of Mihai Ibanescu's patch (available on SF) that allows HTTPS tunneling through an authenticating proxy. This one's a double whammy: it works with IIS through the authenticating proxy, whereas the one on SF, which uses Python's built-in SSL, doesn't. This code is not folded into the main distribution because: 1. Apparently Mihai is still working on it. 2. Mihai uses Python's built-in SSL. Isaac patched it to use M2Crypto.SSL. The stuff is essentially #ifdef'ed code. 3. I don't have an authenticating proxy nor an IIS server to test against, so I can't clean up the code. Volunteers welcome. ;-) Thanks Isaac. m2crypto-0.42.0/contrib/isaac.httpslib.py000066400000000000000000000207001465575656700203270ustar00rootroot00000000000000from __future__ import print_function """M2Crypto support for Python 2.x's httplib. Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.""" import string from M2Crypto import SSL from httplib import FakeSocket, HTTP, HTTPConnection, HTTPResponse, HTTPS_PORT class HTTPSConnection(HTTPConnection): """ This class allows communication via SSL using M2Crypto. """ default_port = HTTPS_PORT def __init__(self, host, port=None, **ssl): keys = ssl.keys() try: keys.remove('key_file') except ValueError: pass try: keys.remove('cert_file') except ValueError: pass try: keys.remove('ssl_context') except ValueError: pass if keys: raise ValueError() try: self.ssl_ctx = ssl['ssl_context'] assert isinstance(self.ssl_ctx, SSL.Context) except KeyError: self.ssl_ctx = SSL.Context('sslv23') HTTPConnection.__init__(self, host, port) def connect(self): self.sock = SSL.Connection(self.ssl_ctx) self.sock.connect((self.host, self.port)) def close(self): # This kludges around line 545 of httplib.py, # which closes the connection in this object; # the connection remains open in the response # object. # # M2Crypto doesn't close-here-keep-open-there, # so, in effect, we don't close until the whole # business is over and gc kicks in. # # Long-running callers beware leakage. # # 05-Jan-2002: This module works with Python 2.2, # but I've not investigated if the above conditions # remain. pass class HTTPS(HTTP): _connection_class = HTTPSConnection def __init__(self, host='', port=None, **ssl): HTTP.__init__(self, host, port) try: self.ssl_ctx = ssl['ssl_context'] except KeyError: self.ssl_ctx = SSL.Context('sslv23') # ISS Added. # From here, starts the proxy patch class HTTPProxyConnection(HTTPConnection): """ This class provides HTTP access through (authenticated) proxies. Example: If the HTTP proxy address is proxy.your.org:8080, an authenticated proxy (one which requires a username/password combination in order to serve requests), one can fetch HTTP documents from 'www.webserver.net', port 81: conn = HTTPProxyConnection('proxy.your.org:8080', 'www.webserver.net', port=81, username='username', password='password') conn.connect() conn.request("HEAD", "/index.html", headers={'X-Custom-Header-1' : 'Value-1'}) resp = conn.getresponse() ... """ def __init__(self, proxy, host, port=None, username=None, password=None): # The connection goes through the proxy HTTPConnection.__init__(self, proxy) # save the proxy connection settings self.__proxy, self.__proxy_port = self.host, self.port # self.host and self.port will point to the real host self._set_hostport(host, port) # save the host and port self._host, self._port = self.host, self.port # Authenticated proxies support self.__username = username self.__password = password def connect(self): """Connect to the host and port specified in __init__ (through a proxy).""" # We are connecting to the proxy, so use the proxy settings self._set_hostport(self.__proxy, self.__proxy_port) HTTPConnection.connect(self) # Restore the real host and port self._set_hostport(self._host, self._port) def putrequest(self, method, url): """Send a request to the server. `method' specifies an HTTP request method, e.g. 'GET'. `url' specifies the object being requested, e.g. '/index.html'. """ # The URL has to include the real host hostname = self._host if self._port != self.default_port: hostname = hostname + ':' + str(self._port) newurl = "http://%s%s" % (hostname, url) # Piggyback on the parent class HTTPConnection.putrequest(self, method, newurl) # Add proxy-specific headers self._add_auth_proxy_header() def _add_auth_proxy_header(self): """Adds an HTTP header for authenticated proxies """ if not self.__username: # No username, so assume not an authenticated proxy return # Authenticated proxy import base64 userpass = "%s:%s" % (self.__username, self.__password) enc_userpass = base64.encodestring(userpass).strip() self.putheader("Proxy-Authorization", "Basic %s" % enc_userpass) class HTTPSProxyResponse(HTTPResponse): """ Replacement class for HTTPResponse Proxy responses (made through SSL) have to keep the connection open after the initial request, since the connection is tunneled to the SSL host with the CONNECT method. """ def begin(self): HTTPResponse.begin(self) self.will_close = 0 class HTTPSProxyConnection(HTTPProxyConnection): """This class provides HTTP access through (authenticated) proxies. Example: If the HTTP proxy address is proxy.your.org:8080, an authenticated proxy (one which requires a username/password combination in order to serve requests), one can fetch HTTP documents from 'www.webserver.net', port 81: conn = HTTPProxyConnection('proxy.your.org:8080', 'www.webserver.net', port=81, username='username', password='password') conn.connect() conn.request("HEAD", "/index.html", headers={'X-Custom-Header-1' : 'Value-1'}) resp = conn.getresponse() ... To avoid dealing with multiple inheritance, this class only inherits from HTTPProxyConnection. """ default_port = HTTPSConnection.default_port def __init__(self, proxy, host, port=None, username=None, password=None, **x509): for key in x509.keys(): if key not in ['cert_file', 'key_file', 'ssl_context']: raise ValueError() self.key_file = x509.get('key_file') self.cert_file = x509.get('cert_file') #ISS Added self.ssl_ctx = x509.get('ssl_context') # Piggybacking on HTTPProxyConnection HTTPProxyConnection.__init__(self, proxy, host, port, username, password) def connect(self): """Connect (using SSL) to the host and port specified in __init__ (through a proxy).""" import socket # Set the connection with the proxy HTTPProxyConnection.connect(self) # Use the stock HTTPConnection putrequest host = "%s:%s" % (self._host, self._port) HTTPConnection.putrequest(self, "CONNECT", host) # Add proxy-specific stuff self._add_auth_proxy_header() # And send the request HTTPConnection.endheaders(self) # Save the response class response_class = self.response_class # And replace the response class with our own one, which does not # close the connection self.response_class = HTTPSProxyResponse response = HTTPConnection.getresponse(self) # Restore the response class self.response_class = response_class # Close the response object manually response.close() if response.status != 200: # Close the connection manually self.close() # XXX Find the appropriate error code raise socket.error(1001, response.status, response.value) # NgPS: I haven't read the code recently, but I think it is # reasonable to assume that self.sock is a connected TCP socket at # this point. # Use the real stuff. ;-) if self.ssl_ctx and isinstance(self.ssl_ctx, SSL.Context): self.sock = SSL.Connection(self.ssl_ctx) self.sock.connect((self.host, self.port)) else: # Fake the socket ssl = socket.ssl(self.sock, self.key_file, self.cert_file) self.sock = FakeSocket(self.sock, ssl) if self.debuglevel > 0: print('socket type:', self.sock) def putrequest(self, method, url): """Send a request to the server. `method' specifies an HTTP request method, e.g. 'GET'. `url' specifies the object being requested, e.g. '/index.html'. """ # bypass the parent class's putrequest: use the grandparent's one :-) return HTTPConnection.putrequest(self, method, url) m2crypto-0.42.0/contrib/smimeplus.README000066400000000000000000000002451465575656700177440ustar00rootroot00000000000000Contributed by Bernard Yue: A high level smime interface. "It works for Python 2.2 and above, and requires the email module from Python 2.2.3 to work on Python 2.1. m2crypto-0.42.0/contrib/smimeplus.py000066400000000000000000000125371465575656700174460ustar00rootroot00000000000000import UserDict import os import tempfile from M2Crypto import BIO, Rand, SMIME, X509 from email import Message class smimeplus(object): def __init__(self, cert, privkey, passphrase, cacert, randfile=None): self.cipher = 'des_ede3_cbc' # XXX make it configable?? self.setsender(cert, privkey, passphrase) self.setcacert(cacert) self.randfile = randfile self.__loadrand() def __passcallback(self, v): """private key passphrase callback function""" return self.passphrase def __loadrand(self): """Load random number file""" if self.randfile: Rand.load_file(self.randfile, -1) def __saverand(self): """Save random number file""" if self.randfile: Rand.save_file(self.randfile) def __gettext(self, msg): """Return a string representation of 'msg'""" _data = '' if isinstance(msg, Message.Message): for _p in msg.walk(): _data = _data + _p.as_string() else: _data = str(msg) return _data def __pack(self, msg): """Convert 'msg' to string and put it into an memory buffer for openssl operation""" return BIO.MemoryBuffer(self.__gettext(msg)) def setsender(self, cert=None, privkey=None, passphrase=None): if cert: self.cert = cert if privkey: self.key = privkey if passphrase: self.passphrase = passphrase def setcacert(self, cacert): self.cacert = cacert def sign(self, msg): """Sign a message""" _sender = SMIME.SMIME() _sender.load_key_bio(self.__pack(self.key), self.__pack(self.cert), callback=self.__passcallback) _signed = _sender.sign(self.__pack(msg), SMIME.PKCS7_DETACHED) _out = self.__pack(None) _sender.write(_out, _signed, self.__pack(msg)) return _out.read() def verify(self, smsg, scert): """Verify to see if 'smsg' was signed by 'scert', and scert was issued by cacert of this object. Return message signed if success, None otherwise""" # Load signer's cert. _x509 = X509.load_cert_bio(self.__pack(scert)) _stack = X509.X509_Stack() _stack.push(_x509) # Load CA cert. _tmpfile = persistdata(self.cacert) _store = X509.X509_Store() _store.load_info(_tmpfile) os.remove(_tmpfile) # prepare SMIME object _sender = SMIME.SMIME() _sender.set_x509_stack(_stack) _sender.set_x509_store(_store) # Load signed message, verify it, and return result _p7, _data = SMIME.smime_load_pkcs7_bio(self.__pack(smsg)) try: return _sender.verify(_p7, _data, flags=SMIME.PKCS7_SIGNED) except SMIME.SMIME_Error: return None def encrypt(self, rcert, msg): # Instantiate an SMIME object. _sender = SMIME.SMIME() # Load target cert to encrypt to. _x509 = X509.load_cert_bio(self.__pack(rcert)) _stack = X509.X509_Stack() _stack.push(_x509) _sender.set_x509_stack(_stack) _sender.set_cipher(SMIME.Cipher(self.cipher)) # Encrypt the buffer. _buf = self.__pack(self.__gettext(msg)) _p7 = _sender.encrypt(_buf) # Output p7 in mail-friendly format. _out = self.__pack('') _sender.write(_out, _p7) # Save the PRNG's state. self.__saverand() return _out.read() def decrypt(self, emsg): """decrypt 'msg'. Return decrypt message if success, None otherwise""" # Load private key and cert. _sender = SMIME.SMIME() _sender.load_key_bio(self.__pack(self.key), self.__pack(self.cert), callback=self.__passcallback) # Load the encrypted data. _p7, _data = SMIME.smime_load_pkcs7_bio(self.__pack(emsg)) # Decrypt p7. try: return _sender.decrypt(_p7) except SMIME.SMIME_Error: return None def addHeader(self, rcert, content, subject=''): """Add To, From, Subject Header to 'content'""" _scert = X509.load_cert_bio(self.__pack(self.cert)) _scertsubj = X509_Subject(str(_scert.get_subject())) _rcert = X509.load_cert_bio(self.__pack(rcert)) _rcertsubj = X509_Subject(str(_rcert.get_subject())) _out = 'From: "%(CN)s" <%(emailAddress)s>\n' % _scertsubj _out = _out + 'To: "%(CN)s" <%(emailAddress)s>\n' % _rcertsubj _out = _out + 'Subject: %s\n' % subject _out = _out + content return _out class X509_Subject(UserDict.UserDict): # This class needed to be rewritten or merge with X509_Name def __init__(self, substr): UserDict.UserDict.__init__(self) try: _data = substr.strip().split('/') except AttributeError: pass else: for _i in _data: try: _k, _v = _i.split('=') self[_k] = _v except ValueError: pass def persistdata(data, file=None, isbinary=False): if not file: file = tempfile.mktemp() if isbinary: _flag = 'wb' else: _flag = 'w' _fh = open(file, _flag) _fh.write(data) _fh.close() return file m2crypto-0.42.0/dev-requirements.txt000066400000000000000000000004001465575656700174400ustar00rootroot00000000000000-r requirements.txt twine; sys.platform == 'win32' wheel; sys.platform == 'win32' flake8 typing; python_version < "3.5" # Intentionally not in requirements.txt, because only those use it need # this very specialized module. twisted; python_version > "3.0" m2crypto-0.42.0/doc/000077500000000000000000000000001465575656700141535ustar00rootroot00000000000000m2crypto-0.42.0/doc/HOWTOs.rst000066400000000000000000000001751465575656700157730ustar00rootroot00000000000000HOWTOs ================ Contents: .. toctree:: :maxdepth: 3 howto.ca howto.ssl howto.smime howto.migration m2crypto-0.42.0/doc/M2Crypto.SSL.rst000066400000000000000000000026551465575656700170340ustar00rootroot00000000000000SSL Package =========== :mod:`SSL` Package ------------------ .. automodule:: M2Crypto.SSL :members: :undoc-members: :show-inheritance: :mod:`Checker` Module --------------------- .. automodule:: M2Crypto.SSL.Checker :members: :undoc-members: :show-inheritance: :mod:`Cipher` Module -------------------- .. automodule:: M2Crypto.SSL.Cipher :members: :undoc-members: :show-inheritance: :mod:`Connection` Module ------------------------ .. automodule:: M2Crypto.SSL.Connection :members: :undoc-members: :show-inheritance: :mod:`Context` Module --------------------- .. automodule:: M2Crypto.SSL.Context :members: :undoc-members: :show-inheritance: :mod:`SSLServer` Module ----------------------- .. automodule:: M2Crypto.SSL.SSLServer :members: :undoc-members: :show-inheritance: :mod:`Session` Module --------------------- .. automodule:: M2Crypto.SSL.Session :members: :undoc-members: :show-inheritance: :mod:`TwistedProtocolWrapper` Module ------------------------------------ .. automodule:: M2Crypto.SSL.TwistedProtocolWrapper :members: :undoc-members: :show-inheritance: :mod:`cb` Module ---------------- .. automodule:: M2Crypto.SSL.cb :members: :undoc-members: :show-inheritance: :mod:`timeout` Module --------------------- .. automodule:: M2Crypto.SSL.timeout :members: :undoc-members: :show-inheritance: m2crypto-0.42.0/doc/M2Crypto.rst000066400000000000000000000066551465575656700164000ustar00rootroot00000000000000M2Crypto Package ================ :mod:`M2Crypto` Package ----------------------- .. automodule:: M2Crypto.__init__ :members: :undoc-members: :show-inheritance: :mod:`ASN1` Module ------------------ .. automodule:: M2Crypto.ASN1 :members: :undoc-members: :show-inheritance: :mod:`AuthCookie` Module ------------------------ .. automodule:: M2Crypto.AuthCookie :members: :undoc-members: :show-inheritance: :mod:`BIO` Module ----------------- .. automodule:: M2Crypto.BIO :members: :undoc-members: :show-inheritance: :mod:`BN` Module ---------------- .. automodule:: M2Crypto.BN :members: :undoc-members: :show-inheritance: :mod:`DH` Module ---------------- .. automodule:: M2Crypto.DH :members: :undoc-members: :show-inheritance: :mod:`DSA` Module ----------------- .. automodule:: M2Crypto.DSA :members: :undoc-members: :show-inheritance: :mod:`EC` Module ---------------- .. automodule:: M2Crypto.EC :members: :undoc-members: :show-inheritance: :mod:`EVP` Module ----------------- .. automodule:: M2Crypto.EVP :members: :undoc-members: :show-inheritance: :mod:`Engine` Module -------------------- .. automodule:: M2Crypto.Engine :members: :undoc-members: :show-inheritance: :mod:`Err` Module ----------------- .. automodule:: M2Crypto.Err :members: :undoc-members: :show-inheritance: :mod:`RC4` Module ----------------- .. automodule:: M2Crypto.RC4 :members: :undoc-members: :show-inheritance: :mod:`RSA` Module ----------------- .. automodule:: M2Crypto.RSA :members: :undoc-members: :show-inheritance: :mod:`Rand` Module ------------------ .. automodule:: M2Crypto.Rand :members: :undoc-members: :show-inheritance: :mod:`SMIME` Module ------------------- .. automodule:: M2Crypto.SMIME :members: :undoc-members: :show-inheritance: :mod:`X509` Module ------------------ .. automodule:: M2Crypto.X509 :members: :undoc-members: :show-inheritance: :mod:`callback` Module ---------------------- .. automodule:: M2Crypto.callback :members: :undoc-members: :show-inheritance: :mod:`ftpslib` Module --------------------- .. automodule:: M2Crypto.ftpslib :members: :undoc-members: :show-inheritance: :mod:`httpslib` Module ---------------------- .. automodule:: M2Crypto.httpslib :members: :undoc-members: :show-inheritance: :mod:`m2` Module ---------------- .. automodule:: M2Crypto.m2 :members: :undoc-members: :show-inheritance: :mod:`m2crypto` Module ---------------------- .. automodule:: M2Crypto.m2crypto :members: :undoc-members: :show-inheritance: :mod:`m2urllib` Module ---------------------- .. automodule:: M2Crypto.m2urllib :members: :undoc-members: :show-inheritance: :mod:`m2urllib2` Module ----------------------- .. automodule:: M2Crypto.m2urllib2 :members: :undoc-members: :show-inheritance: :mod:`m2xmlrpclib` Module ------------------------- .. automodule:: M2Crypto.m2xmlrpclib :members: :undoc-members: :show-inheritance: :mod:`threading` Module ----------------------- .. automodule:: M2Crypto.threading :members: :undoc-members: :show-inheritance: :mod:`util` Module ------------------ .. automodule:: M2Crypto.util :members: :undoc-members: :show-inheritance: Subpackages ----------- .. toctree:: M2Crypto.SSL m2crypto-0.42.0/doc/Makefile000066400000000000000000000127151465575656700156210ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = . # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/{doctrees,html} html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/M2Crypto.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/M2Crypto.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/M2Crypto" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/M2Crypto" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." m2crypto-0.42.0/doc/conf.py000066400000000000000000000220021465575656700154460ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # M2Crypto documentation build configuration file, created by # sphinx-quickstart on Thu Apr 20 11:15:12 2017. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # 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(os.path.join('..'))) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # 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.viewcode', 'sphinx_rtd_theme', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'M2Crypto' copyright = u'2017, Matej Cepl ' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '' # The full version, including alpha/beta/rc tags. release = '' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # 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'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'M2Cryptodoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'M2Crypto.tex', u'M2Crypto Documentation', u'Matej Cepl \\textless{}mcepl@cepl.eu\\textgreater{}', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'm2crypto', u'M2Crypto Documentation', [u'Matej Cepl '], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'M2Crypto', u'M2Crypto Documentation', u'Matej Cepl ', 'M2Crypto', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # -- Options for Epub output --------------------------------------------------- # Bibliographic Dublin Core info. epub_title = u'M2Crypto' epub_author = u'Matej Cepl ' epub_publisher = u'Matej Cepl ' epub_copyright = u'2017, Matej Cepl ' # The language of the text. It defaults to the language option # or en if the language is not set. #epub_language = '' # The scheme of the identifier. Typical schemes are ISBN or URL. #epub_scheme = '' # The unique identifier of the text. This can be a ISBN number # or the project homepage. #epub_identifier = '' # A unique identification for the text. #epub_uid = '' # A tuple containing the cover image and cover page html template filenames. #epub_cover = () # HTML files that should be inserted before the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_pre_files = [] # HTML files shat should be inserted after the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_post_files = [] # A list of files that should not be packed into the epub file. #epub_exclude_files = [] # The depth of the table of contents in toc.ncx. #epub_tocdepth = 3 # Allow duplicate toc entries. #epub_tocdup = True m2crypto-0.42.0/doc/howto.ca.rst000066400000000000000000000371231465575656700164350ustar00rootroot00000000000000:orphan: .. _howto-ca: HOWTO: Creating your own CA with OpenSSL ######################################## :author: Pheng Siong Ng :copyright: © 2000, 2001 by Ng Pheng Siong. Introduction ============ This is a HOWTO on creating your own *certification authority* (*CA*) with OpenSSL. I last created a CA about a year ago, when I began work on `M2Crypto `__ and needed certificates for the SSL bits. I accepted the tools' default settings then, e.g., certificate validity of 365 days; this meant that my certificates, including my CA's certificate, have now expired. Since I am using these certificates for M2Crypto's demonstration programs (and I have forgotten the passphrase to the CA's private key), I decided to discard the old CA and start afresh. I also decided to document the process, hence this HOWTO. The Procedure ============= I use ``CA.pl``, a Perl program written by Steve Hanson and bundled with OpenSSL. The following are the steps to create a CA: 1. Choose a directory to do your CA work. All commands are executed within this directory. Let's call the directory ``demo``. 2. Copy ``CA.pl`` and ``openssl.cnf`` into ``demo``. 3. Apply the following patch to ``CA.pl``, which allows it to generate a CA certificate with a validity period of 1095 days, i.e., 3 years:: --- CA.pl.org Sat Mar 31 12:40:13 2001 +++ CA.pl Sat Mar 31 12:41:15 2001 @@ -97,7 +97,7 @@ } else { print "Making CA certificate ...\n"; system ("$REQ -new -x509 -keyout " . - "${CATOP}/private/$CAKEY -out ${CATOP}/$CACERT $DAYS"); + "${CATOP}/private/$CAKEY -out ${CATOP}/$CACERT -days 1095"); $RET=$?; } } 4. Create a new CA like this:: ./CA.pl -newca A certificate filename (or enter to create) Making CA certificate ... Using configuration from openssl.cnf Generating a 1024 bit RSA private key ............++++++ ......................++++++ writing new private key to './demoCA/private/cakey.pem' Enter PEM pass phrase: Verifying password - Enter PEM pass phrase: ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:SG State or Province Name (full name) [Some-State]:. Locality Name (eg, city) []:.. Organization Name (eg, company) [Internet Widgits Pty Ltd]:DemoCA Organizational Unit Name (eg, section) []:. Common Name (eg, YOUR name) []:DemoCA Certificate Master Email Address []:certmaster@democa.dom This creates a new CA in the directory ``demoCA``. The CA's self-signed certificate is in ``demoCA/cacert.pem`` and its RSA key pair is in ``demoCA/private/cakey.pem``. ``demoCA/private/cakey.pem`` looks like this:: cat demoCA/private/cakey.pem -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,19973A9DBBB601BA eOq9WFScNiI4/UWEUaSnGTKpJv2JYuMD3HwQox2Q3Cd4zGqVjJ6gF3exa5126cKf X/bMVnwbPpuFZPiAIvaLyCjT6pYeXTBbSzs7/GQnvEOv+nYnDUFWi0Qm92qLk0uy pFi/M1aWheN3vir2ZlAw+DW0bOOZhj8tC7Co7lMYb0YE271b6/YRPZCwQ3GXAHUJ +aMYxlUDrK45aCUa/1CZDzTgk7h9cDgx2QJSIvYMYytCfI3zsuZMJS8/4OXLL0bI lKmAc1dwB3DqGJt5XK4WJesiNfdxeCNEgAcYtEAgYZTPIApU+kTgTCIxJl2nMW7j ax+Q1z7g+4MpgG20WD633D4z4dTlDdz+dnLi0rvuvxiwt+dUhrqiML1tyi+Z6EBH jU4/cLBWev3rYfrlp4x8J9mDte0YKOk3t0wQOHqRetTsIfdtjnFp/Hu3qDmTCWjD z/g7PPoO/bg/B877J9WBPbL/1hXXFYo88M+2aGlPOgDcFdiOqbLb2DCscohMbbVr A4mgiy2kwWfIE73qiyV7yyG8FlRvr1iib+jbT3LTGf743utYAAs7HNGuOUObhoyt jYvBD7ACn35P5YX7KTqvqErwdijxYCaNBCnvmRtmYSaNw9Kv1UJTxc5Vx7YLwIPk E9KyBgKI7vPOjWBZ27+zOvNycmv1ciNtpALAw4bWtXnhCDVTHaVDy34OkheMzNCg 2cjcBFzOkMIjcI03KbTQXOFIQGlsTWXGzkNf/zBQ+KksT1MCj+zBXSCvlDASMckg kef21pGgUqPF14gKGfWX3sV4bjc1vbrRwq6zlG3nMuYqR5MtJJY9eQ== -----END RSA PRIVATE KEY----- 5. Next, generate a certificate request:: ./CA.pl -newreq Using configuration from openssl.cnf Generating a 1024 bit RSA private key ..........++++++ ..............++++++ writing new private key to 'newreq.pem' Enter PEM pass phrase: Verifying password - Enter PEM pass phrase: ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:SG State or Province Name (full name) [Some-State]:.. Locality Name (eg, city) []:. Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto Organizational Unit Name (eg, section) []:. Common Name (eg, YOUR name) []:localhost Email Address []:admin@server.example.dom Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: Request (and private key) is in newreq.pem \ The certificate request and private key in ``newreq.pem`` looks like this:: cat newreq.pem -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,41B2874DF3D02DD4 mg611EoVkLEooSTv+qTM0Ddmm/M1jE/Jy5RD/sc3LSMhuGu9xc26OgsTJmkQuIAh J/B4lAw8G59VTG6DykeEtrG0rUBx4bggc7PKbFuiN423YjJODWcHvVgnPOzXMQt+ lY4tPl5+217MRHyx2NsWGrpkQNdu3GeSPOVMl3jeQiaXupONbwQ7rj42+X/VtAJP W4D1NNwu8aGCPyShsEXHc/fI1WDpphYWke97pOjIZVQESFZOPty5HjIYZux4U+td W81xODtq2ecJXc8fn2Wpa9y5VD1LT7oJksOuL1+Z04OVaeUe4x0swM17HlBm2kVt fe/C/L6kN27MwZhE331VjtTjSGl4/gknqQDbLOtqT06f3OISsDJETm2itllyhgzv C6Fi3N03rGFmKectijC+tws5k+P+HRG6sai33usk8xPokJqA+HYSWPz1XVlpRmv4 kdjQOdST7ovU62mOTgf3ARcduPPwuzTfxOlYONe5NioO1APVHBrInQwcpLkpOTQR vI4roIN+b75/nihUWGUJn/nbbBa2Yl0N5Gs1Tyiy9Z+CcRT2TfWKBBFlEUIFl7Mb J9fTV3DI+k+akbR4il1NkQ8EcSmCr3WpA0I9n0EHI7ZVpVaHxc0sqaPFl8YGdFHq 1Qk53C/w6+qPpDzT3yKFmG2LZytAAM1czvb6RbNRJJP2ZrpBwn/h99sUTo/yPfxY nueYmFJDm0uVNtG0icXGNUfSfnjKNTtHPAgyKGetRIC3kgJz/bo2w7EI6iEjBAzK l5TRm4x6ZJxwuXXMiJCehMMd8TC8ybwWO4AO19B3ebFFeTVsUgxSGA== -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE REQUEST----- MIIBnTCCAQYCAQAwXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIw EAYDVQQDEwlsb2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5l eGFtcGxlLmRvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAr1nYY1Qrll1r uB/FqlCRrr5nvupdIN+3wF7q915tvEQoc74bnu6b8IbbGRMhzdzmvQ4SzFfVEAuM MuTHeybPq5th7YDrTNizKKxOBnqE2KYuX9X22A1Kh49soJJFg6kPb9MUgiZBiMlv tb7K3CHfgw5WagWnLl8Lb+ccvKZZl+8CAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4GB AHpoRp5YS55CZpy+wdigQEwjL/wSluvo+WjtpvP0YoBMJu4VMKeZi405R7o8oEwi PdlrrliKNknFmHKIaCKTLRcU59ScA6ADEIWUzqmUzP5Cs6jrSRo3NKfg1bd09D1K 9rsQkRc9Urv9mRBIsredGnYECNeRaK5R1yzpOowninXC -----END CERTIFICATE REQUEST----- \ Decoding the certificate request gives the following:: openssl req -text -noout < newreq.pem Using configuration from /usr/local/pkg/openssl/openssl.cnf Certificate Request: Data: Version: 0 (0x0) Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50: 91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e: 6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13: 21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4: c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac: 4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f: 6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9: 6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f: 0b:6f:e7:1c:bc:a6:59:97:ef Exponent: 65537 (0x10001) Attributes: a0:00 Signature Algorithm: md5WithRSAEncryption 7a:68:46:9e:58:4b:9e:42:66:9c:be:c1:d8:a0:40:4c:23:2f: fc:12:96:eb:e8:f9:68:ed:a6:f3:f4:62:80:4c:26:ee:15:30: a7:99:8b:8d:39:47:ba:3c:a0:4c:22:3d:d9:6b:ae:58:8a:36: 49:c5:98:72:88:68:22:93:2d:17:14:e7:d4:9c:03:a0:03:10: 85:94:ce:a9:94:cc:fe:42:b3:a8:eb:49:1a:37:34:a7:e0:d5: b7:74:f4:3d:4a:f6:bb:10:91:17:3d:52:bb:fd:99:10:48:b2: b7:9d:1a:76:04:08:d7:91:68:ae:51:d7:2c:e9:3a:8c:27:8a: 75:c2 6. Now, sign the certificate request:: ./CA.pl -sign Using configuration from openssl.cnf Enter PEM pass phrase: Check that the request matches the signature Signature ok The Subjects Distinguished Name is as follows countryName :PRINTABLE:'SG' organizationName :PRINTABLE:'M2Crypto' commonName :PRINTABLE:'localhost' emailAddress :IA5STRING:'admin@server.example.dom' Certificate is to be certified until Mar 31 02:57:30 2002 GMT (365 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated Signed certificate is in newcert.pem \ ``newcert.pem`` looks like this:: cat newcert.pem Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: md5WithRSAEncryption Issuer: C=SG, O=DemoCA, CN=DemoCA Certificate Master/Email=certmaster@democa.dom Validity Not Before: Mar 31 02:57:30 2001 GMT Not After : Mar 31 02:57:30 2002 GMT Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50: 91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e: 6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13: 21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4: c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac: 4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f: 6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9: 6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f: 0b:6f:e7:1c:bc:a6:59:97:ef Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: md5WithRSAEncryption Issuer: C=SG, O=DemoCA, CN=DemoCA Certificate Master/Email=certmaster@democa.dom Validity Not Before: Mar 31 02:57:30 2001 GMT Not After : Mar 31 02:57:30 2002 GMT Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50: 91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e: 6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13: 21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4: c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac: 4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f: 6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9: 6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f: 0b:6f:e7:1c:bc:a6:59:97:ef Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: B3:D6:89:88:2F:B1:15:40:EC:0A:C0:30:35:3A:B7:DA:72:73:1B:4D X509v3 Authority Key Identifier: keyid:F9:6A:A6:34:97:6B:BC:BB:5A:17:0D:19:FC:62:21:0B:00:B5:0E:29 DirName:/C=SG/O=DemoCA/CN=DemoCA Certificate Master/Email=certmaster@democa.dom serial:00 Signature Algorithm: md5WithRSAEncryption 7. In certain situations, e.g., where your certificate and private key are to be used in an unattended SSL server, you may wish to not encrypt the private key, i.e., leave the key in the clear. This decision should be governed by your site's security policy and threat model, of course:: openssl rsa < newkey.pem > newkey2.pem read RSA key Enter PEM pass phrase: writing RSA key ``newkey2.pem`` looks like this:: cat newkey2.pem -----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQCvWdhjVCuWXWu4H8WqUJGuvme+6l0g37fAXur3Xm28RChzvhue 7pvwhtsZEyHN3Oa9DhLMV9UQC4wy5Md7Js+rm2HtgOtM2LMorE4GeoTYpi5f1fbY DUqHj2ygkkWDqQ9v0xSCJkGIyW+1vsrcId+DDlZqBacuXwtv5xy8plmX7wIDAQAB AoGAbAkU8w3W1Qu15Hle1bJSL7GMReoreqeblOBmMAZz4by0l6sXZXJpjWXo86f/ +dASMYTMPC4ZTYtv06N07AFbjL+kDfqDMTfzQkYMHp1LAq1Ihbq1rHWSBH5n3ekq KiY8JKpv8DR5Po1iKaXJFuDByGDENJwYbSRSpSK3P+vkWWECQQDkEUE/ZPqqqZkQ 2iWRPAsCbEID8SAraQl3DdCLYs/GgARfmmj4yUHEwkys9Jo1H8k4BdxugmaUwNi5 YQ/CVzrXAkEAxNO80ArbGxPUmr11GHG/bGBYj1DUBkHZSc7dgxZdtUCLGNxQnNsg Iwq3n6j1sUzS3UW6abQ8bivYNOUcMKJAqQJBANQxFaLU4b/NQaODQ3aoBZpAfP9L 5eFdvbet+7zjt2r5CpikgkwOfAmDuXEltx/8LevY0CllW+nErx9zJgVrwUsCQQCu 76H5JiznPBDSF2FjgHWqVVdgyW4owY3mU739LHvNBLicN/RN9VPy0Suy8/CqzKT9 lWPBXzf2k3FuUdNkRlFBAkEAmpXoybuiFR2S5Bma/ax96lVs0/VihhfC1zZP/X/F Br77+h9dIul+2DnyOl50zu0Sdzst1/7ay4JSDHyiBCMGSQ== -----END RSA PRIVATE KEY----- That's it! The certificate, ``newcert.pem``, and the private key - ``newkey.pem`` (encrypted) or ``newkey2.pem`` (unencrypted) - are now ready to be used. You may wish to rename the files to more intuitive names. You should also keep the CA's certificate ``demo/cacert.pem`` handy for use when developing and deploying SSL or S/MIME applications. Conclusion ========== We've walked through the basic steps in the creation of a CA and certificates using the tools that come with OpenSSL. We did not cover more advanced topics such as constraining a certificate to be SSL-only or S/MIME-only. There exist several HOWTOs similar to this one on the net. This one is written specifically to facilitate discussions in my other HOWTOs on developing SSL and S/MIME applications in `Python `__ using `M2Crypto `__. m2crypto-0.42.0/doc/howto.migration.rst000066400000000000000000000151201465575656700200340ustar00rootroot00000000000000:orphan: .. _howto-migration: HOWTO: Migrating from M2Crypto to PyCA/cryptography ################################################### Introduction ************ `PyCA/cryptography `__ is a package which provides cryptographic recipes and primitives to Python developers. This document has instructions on how to migrate from M2Crypto to PyCA/cryptography for features that are currently supported. S/MIME ****** Signing ======= If your application does S/MIME signing, it can be migrated to `PyCA/cryptography `__ by using the ``PKCS7`` API, particularly the ``PKCS7SignatureBuilder`` class. Below is an example migration showcasing the equivalent APIs and parameters in `PyCA/cryptography `__. M2Crypto -------- .. testcode:: from M2Crypto import BIO, SMIME s = SMIME.SMIME() s.load_key('../tests/signer_key.pem', '../tests/signer.pem') data = b'data' buf = BIO.MemoryBuffer(data) p7 = s.sign(buf, SMIME.PKCS7_DETACHED) out = BIO.MemoryBuffer() buf = BIO.MemoryBuffer(data) s.write(out, p7, buf) print(out.read()) .. testoutput:: :hide: b'MIME-Version: 1.0\nContent-Type: multipart/signed;... PyCA/cryptography ----------------- .. testcode:: from cryptography.hazmat.primitives.serialization import load_pem_private_key, pkcs7, Encoding from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives import hashes from cryptography.x509 import load_pem_x509_certificate with open('../tests/signer_key.pem', 'rb') as key_data: key = load_pem_private_key(key_data.read(), password=None) with open('../tests/signer.pem', 'rb') as cert_data: cert = load_pem_x509_certificate(cert_data.read()) output = pkcs7.PKCS7SignatureBuilder().set_data( b"data" ).add_signer( cert, key, hashes.SHA512(), rsa_padding=padding.PKCS1v15() ).sign( Encoding.SMIME, [pkcs7.PKCS7Options.DetachedSignature] ) print(output) .. testoutput:: :hide: b'MIME-Version: 1.0\r\nContent-Type: multipart/signed;... RSA *** Following are migration examples for common operations with RSA key pairs. The documentation for the relevant ``PyCA/cryptography`` APIs can be found `here `__. Signing and verifying ===================== M2Crypto -------- .. testcode:: from M2Crypto import RSA import hashlib message = b"This is the message string" digest = hashlib.sha1(message).digest() key = RSA.load_key('../tests/rsa.priv.pem') signature = key.sign(digest, algo='sha1') assert key.verify(digest, signature, algo='sha1') == 1 print(signature.hex()) .. testoutput:: :hide: 79aba937863cd5bfef254... PyCA/cryptography ----------------- .. testcode:: from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import serialization with open('../tests/rsa.priv.pem', 'rb') as key_data: key = load_pem_private_key(key_data.read(), password=None) message = b"This is the message string" signature = key.sign(message, padding.PKCS1v15(), hashes.SHA1()) public_key = key.public_key() public_key.verify(signature, message, padding.PKCS1v15(), hashes.SHA1()) print(signature.hex()) .. testoutput:: :hide: 79aba937863cd5bfef254... Encrypting and decrypting ========================= M2Crypto -------- .. testcode:: from M2Crypto import RSA message = b"This is the message string" key = RSA.load_key('../tests/rsa.priv.pem') cipher_text = key.public_encrypt(message, RSA.pkcs1_padding) plain_text = key.private_decrypt(cipher_text, RSA.pkcs1_padding) assert plain_text == message PyCA/cryptography ----------------- .. testcode:: from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives import serialization with open('../tests/rsa.priv.pem', 'rb') as key_data: key = load_pem_private_key(key_data.read(), password=None) message = b"This is the message string" public_key = key.public_key() cipher_text = public_key.encrypt(message, padding.PKCS1v15()) plain_text = key.decrypt(cipher_text, padding.PKCS1v15()) assert plain_text == message X.509 certificates ****************** Following are migration examples for common operations with X.509 certificates. The documentation for the relevant ``PyCA/cryptography`` APIs can be found `here `__. Loading and examining certificates ================================== M2Crypto -------- .. testcode:: from M2Crypto import X509 cert = X509.load_cert('../tests/x509.pem') print(cert.get_issuer()) print(cert.get_subject()) print(cert.get_not_before()) print(cert.get_not_after()) .. testoutput:: :hide: /C=US/ST=California/O=M2Crypto/CN=Heikki Toivonen /C=US/ST=California/O=M2Crypto/CN=X509 Oct 7 15:12:02 2018 GMT Oct 4 15:12:02 2028 GMT PyCA/cryptography ----------------- .. testcode:: from cryptography import x509 with open('../tests/x509.pem', 'rb') as cert_data: cert = x509.load_pem_x509_certificate(cert_data.read()) print(cert.issuer) print(cert.subject) print(cert.not_valid_before_utc) print(cert.not_valid_after_utc) .. testoutput:: :hide: 2018-10-07 15:12:02+00:00 2028-10-04 15:12:02+00:00 Signature verification ================================== Note that this example only checks that the signature of a certificate matches a public key, as described in `the OpenSSL documentation `__. For complete X.509 path validation see `PyCA/cryptography's X.509 verification module `__. M2Crypto -------- .. testcode:: from M2Crypto import X509 cert = X509.load_cert('../tests/x509.pem') cacert = X509.load_cert("../tests/ca.pem") assert cert.verify(cacert.get_pubkey()) == 1 PyCA/cryptography ----------------- .. testcode:: from cryptography.x509 import load_pem_x509_certificate with open('../tests/ca.pem', 'rb') as cacert_data: cacert = load_pem_x509_certificate(cacert_data.read()) with open('../tests/x509.pem', 'rb') as cert_data: cert = load_pem_x509_certificate(cert_data.read()) cert.verify_directly_issued_by(cacert) m2crypto-0.42.0/doc/howto.smime.rst000066400000000000000000000726101465575656700171640ustar00rootroot00000000000000:orphan: .. _howto-smime: HOWTO: Programming S/MIME in Python with M2Crypto ################################################# :author: Pheng Siong Ng :copyright: © 2000, 2001 by Ng Pheng Siong. Introduction ============ `M2Crypto `__ is a `Python `__ interface to `OpenSSL `__. It makes available to the Python programmer SSL functionality to implement clients and servers, S/MIME v2, RSA, DSA, DH, symmetric ciphers, message digests and HMACs. This document demonstrates programming S/MIME with M2Crypto. S/MIME ====== S/MIME - Secure Multipurpose Internet Mail Extensions [RFC 2311, RFC 2312] - provides a consistent way to send and receive secure MIME data. Based on the popular Internet MIME standard, S/MIME provides the following cryptographic security services for electronic messaging applications - *authentication*, *message integrity* and *non-repudiation of origin* (using *digital signatures*), and *privacy* and *data security* (using *encryption*). Keys and Certificates ===================== To create an S/MIME-signed message, you need an RSA key pair (this consists of a public key and a private key) and an X.509 certificate of said public key. To create an S/MIME-encrypted message, you need an X.509 certificate for each recipient. To create an S/MIME-signed *and* -encrypted message, first create a signed message, then encrypt the signed message with the recipients' certificates. You may generate key pairs and obtain certificates by using a commercial *certification authority* service. You can also do so using freely-available software. For many purposes, e.g., automated S/MIME messaging by system administration processes, this approach is cheap and effective. We now work through using OpenSSL to generate key pairs and certificates. This assumes you have OpenSSL installed properly on your system. First, we generate an X.509 certificate to be used for signing:: openssl req -newkey rsa:1024 -nodes -x509 -days 365 -out signer.pem Using configuration from /usr/local/pkg/openssl/openssl.cnf Generating a 1024 bit RSA private key ..++++++ ....................++++++ writing new private key to 'privkey.pem' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:SG State or Province Name (full name) [Some-State]:. Locality Name (eg, city) []:. Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto Organizational Unit Name (eg, section) []:. Common Name (eg, YOUR name) []:S/MIME Sender Email Address []:sender@example.dom This generates a 1024-bit RSA key pair, unencrypted, into ``privkey.pem``; it also generates a self-signed X.509 certificate for the public key into ``signer.pem``. The certificate is valid for 365 days, i.e., a year. Let's rename ``privkey.pem`` so that we know it is a companion of ``signer.pem``'s:: mv privkey.pem signer_key.pem To verify the content of ``signer.pem``, execute the following:: openssl x509 -noout -text -in signer.pem Certificate: Data: Version: 3 (0x2) Serial Number: 0 (0x0) Signature Algorithm: md5WithRSAEncryption Issuer: C=SG, O=M2Crypto, CN=S/MIME Sender/Email=sender@example.dom Validity Not Before: Mar 24 12:56:16 2001 GMT Not After : Mar 24 12:56:16 2002 GMT Subject: C=SG, O=M2Crypto, CN=S/MIME Sender/Email=sender@example.dom Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:a9:d6:e2:b5:11:3b:ae:3c:e2:17:31:70:e1:6e: 01:f4:19:6d:bd:2a:42:36:2b:37:34:e2:83:1d:0d: 11:2e:b4:99:44:db:10:67:be:97:5f:5b:1a:26:33: 46:23:2f:95:04:7a:35:da:9d:f9:26:88:39:9e:17: cd:3e:eb:a8:19:8d:a8:2a:f1:43:da:55:a9:2e:2c: 65:ed:04:71:42:ce:73:53:b8:ea:7e:c7:f0:23:c6: 63:c5:5e:68:96:64:a7:b4:2a:94:26:76:eb:79:ea: e3:4e:aa:82:09:4f:44:87:4a:12:62:b5:d7:1f:ca: f2:ce:d5:ba:7e:1f:48:fd:b9 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: 29:FB:38:B6:BF:E2:40:BB:FF:D5:71:D7:D5:C4:F0:83:1A:2B:C7:99 X509v3 Authority Key Identifier: keyid:29:FB:38:B6:BF:E2:40:BB:FF:D5:71:D7:D5:C4:F0:83:1A:2B:C7:99 DirName:/C=SG/O=M2Crypto/CN=S/MIME Sender/Email=sender@example.dom serial:00 X509v3 Basic Constraints: CA:TRUE Signature Algorithm: md5WithRSAEncryption 68:c8:6b:1b:fa:7c:9a:39:35:76:18:15:c9:fd:89:97:62:db: 7a:b0:2d:13:dd:97:e8:1b:7a:9f:22:27:83:24:9d:2e:56:ec: 97:89:3c:ef:16:55:80:5a:18:7c:22:d0:f6:bb:e3:a4:e8:59: 30:ff:99:5a:93:3e:ea:bc:ee:7f:8d:d6:7d:37:8c:ac:3d:74: 80:ce:7a:99:ba:27:b9:2a:a3:71:fa:a5:25:ba:47:17:df:07: 56:96:36:fd:60:b9:6c:96:06:e8:e3:7b:9f:4b:6a:95:71:a8: 34:fc:fc:b5:88:8b:c4:3f:1e:24:f6:52:47:b2:7d:44:67:d9: 83:e8 Next, we generate a self-signed X.509 certificate for the recipient. Note that ``privkey.pem`` will be recreated:: openssl req -newkey rsa:1024 -nodes -x509 -days 365 -out recipient.pem Using configuration from /usr/local/pkg/openssl/openssl.cnf Generating a 1024 bit RSA private key .....................................++++++ .................++++++ writing new private key to 'privkey.pem' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:SG State or Province Name (full name) [Some-State]:. Locality Name (eg, city) []:. Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto Organizational Unit Name (eg, section) []:. Common Name (eg, YOUR name) []:S/MIME Recipient Email Address []:recipient@example.dom Again, rename ``privkey.pem``:: mv privkey.pem recipient_key.pem In the examples to follow, S/MIME Sender, ````, shall be the sender of S/MIME messages, while S/MIME Recipient, ````, shall be the recipient of S/MIME messages. Armed with the key pairs and certificates, we are now ready to begin programming S/MIME in Python. **Note:** The private keys generated above are *not passphrase-protected*, i.e., they are *in the clear*. Anyone who has access to such a key can generate S/MIME-signed messages with it, and decrypt S/MIME messages encrypted to it's corresponding public key. We may passphrase-protect the keys, if we so choose. M2Crypto will prompt the user for the passphrase when such a key is being loaded. M2Crypto.SMIME ============== The Python programmer accesses M2Crypto's S/MIME functionality through class ``SMIME`` in the module ``M2Crypto.SMIME``. Typically, an ``SMIME`` object is instantiated; the object is then set up for the intended operation: sign, encrypt, decrypt or verify; finally, the operation is invoked on the object. ``M2Crypto.SMIME`` makes extensive use of ``M2Crypto.BIO``: ``M2Crypto.BIO`` is a Python abstraction of the ``BIO`` abstraction in OpenSSL. A commonly used ``BIO`` abstraction in M2Crypto is ``M2Crypto.BIO.MemoryBuffer``, which implements a memory-based file-like object, similar to Python's own ``StringIO``. Sign ==== The following code demonstrates how to generate an S/MIME-signed message. ``randpool.dat`` contains random data which is used to seed OpenSSL's pseudo-random number generator via M2Crypto:: from M2Crypto import BIO, Rand, SMIME def makebuf(text): return BIO.MemoryBuffer(text) # Make a MemoryBuffer of the message. buf = makebuf('a sign of our times') # Seed the PRNG. Rand.load_file('randpool.dat', -1) # Instantiate an SMIME object; set it up; sign the buffer. s = SMIME.SMIME() s.load_key('signer_key.pem', 'signer.pem') p7 = s.sign(buf, SMIME.PKCS7_DETACHED) ``p7`` now contains a *PKCS #7 signature blob* wrapped in an ``M2Crypto.SMIME.PKCS7`` object. Note that ``buf`` has been consumed by ``sign()`` and has to be recreated if it is to be used again. We may now send the signed message via SMTP. In these examples, we shall not do so; instead, we'll render the S/MIME output in mail-friendly format, and pretend that our messages are sent and received correctly:: # Recreate buf. buf = makebuf('a sign of our times') # Output p7 in mail-friendly format. out = BIO.MemoryBuffer() out.write('From: sender@example.dom\n') out.write('To: recipient@example.dom\n') out.write('Subject: M2Crypto S/MIME testing\n') s.write(out, p7, buf) print(out.read()) # Save the PRNG's state. Rand.save_file('randpool.dat') Here's the output:: From: sender@example.dom To: recipient@example.dom Subject: M2Crypto S/MIME testing MIME-Version: 1.0 Content-Type: multipart/signed ; protocol="application/x-pkcs7-signature" ; micalg=sha1 ; boundary="----3C93156FC7B4EBF49FE9C7DB7F503087" This is an S/MIME signed message ------3C93156FC7B4EBF49FE9C7DB7F503087 a sign of our times ------3C93156FC7B4EBF49FE9C7DB7F503087 Content-Type: application/x-pkcs7-signature; name="smime.p7s" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="smime.p7s" MIIE8AYJKoZIhvcNAQcCoIIE4TCCBN0CAQExCzAJBgUrDgMCGgUAMCIGCSqGSIb3 DQEHAaAVBBNhIHNpZ24gb2Ygb3VyIHRpbWVzoIIC5zCCAuMwggJMoAMCAQICAQAw DQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv MRYwFAYDVQQDEw1TL01JTUUgU2VuZGVyMSEwHwYJKoZIhvcNAQkBFhJzZW5kZXJA ZXhhbXBsZS5kb20wHhcNMDEwMzMxMTE0MDMzWhcNMDIwMzMxMTE0MDMzWjBbMQsw CQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBT ZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbTCBnzANBgkq hkiG9w0BAQEFAAOBjQAwgYkCgYEA5c5Tj1CHTSOxa1q2q0FYiwMWYHptJpJcvtZm UwrgU5sHrA8OnCM0cDXEj0KPf3cfNjHffB8HWMzI4UEgNmFXQNsxoGZ+iqwxLlNj y9Mh7eFW/Bjq5hNXbouSlQ0rWBRkoxV64y+t6lQehb32WfYXQbKFxFJSXzSxOx3R 8YhSPd0CAwEAAaOBtjCBszAdBgNVHQ4EFgQUXOyolL1t4jaBwZFRM7MS8nBLzUow gYMGA1UdIwR8MHqAFFzsqJS9beI2gcGRUTOzEvJwS81KoV+kXTBbMQswCQYDVQQG EwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIx ITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbYIBADAMBgNVHRMEBTAD AQH/MA0GCSqGSIb3DQEBBAUAA4GBAHo3DrCHR86fSTVAvfiXdSswWqKtCEhUHRdC TLFGl4hDk2GyZxaFuqZwiURz/H7nMicymI2wkz8H/wyHFg8G3BIehURpj2v/ZWXY eovbgS7EZALVVkDj4hNl/IIHWd6Gtv1UODf7URbxtl3hQ9/eTWITrefT1heuPnar 8czydsOLMYIBujCCAbYCAQEwYDBbMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJD cnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNl bmRlckBleGFtcGxlLmRvbQIBADAJBgUrDgMCGgUAoIGxMBgGCSqGSIb3DQEJAzEL BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTAxMDMzMTExNDUwMlowIwYJKoZI hvcNAQkEMRYEFOoeRUd8ExIYXfQq8BTFuKWrSP3iMFIGCSqGSIb3DQEJDzFFMEMw CgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsO AwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIGAQpU8hFUtLCF6hO2t ec9EYJ/Imqqiiw+BxWxkUUVT81Vbjwdn9JST6+sztM5JRP2ZW+b4txEjZriYC8f3 kv95YMTGbIsuWkJ93GrbvqoJ/CxO23r9WWRnZEm/1EZN9ZmlrYqzBTxnNRmP3Dhj cW8kzZwH+2/2zz2G7x1HxRWH95A= ------3C93156FC7B4EBF49FE9C7DB7F503087-- Verify ====== Assume the above output has been saved into ``sign.p7``. Let's now verify the signature:: from M2Crypto import SMIME, X509 # Instantiate an SMIME object. s = SMIME.SMIME() # Load the signer's cert. x509 = X509.load_cert('signer.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) # Load the signer's CA cert. In this case, because the signer's # cert is self-signed, it is the signer's cert itself. st = X509.X509_Store() st.load_info('signer.pem') s.set_x509_store(st) # Load the data, verify it. p7, data = SMIME.smime_load_pkcs7('sign.p7') v = s.verify(p7, data) print(v) print(data) print(data.read()) Here's the output of the above program:: a sign of our times a sign of our times Suppose, instead of loading ``signer.pem`` above, we load ``recipient.pem``. That is, we do a global substitution of ``recipient.pem`` for ``signer.pem`` in the above program. Here's the modified program's output:: Traceback (most recent call last): File "./verify.py", line 22, in ? v = s.verify(p7) File "/usr/local/home/ngps/prog/m2/M2Crypto/SMIME.py", line 205, in verify raise SMIME_Error, Err.get_error() M2Crypto.SMIME.SMIME_Error: 312:error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error:pk7_smime.c:213:Verify error:self signed certificate As displayed, the error is generated by line 213 of OpenSSL's ``pk7_smime.c`` (as of OpenSSL 0.9.6); if you are a C programmer, you may wish to look up the C source to explore OpenSSL's S/MIME implementation and understand why the error message is worded thus. Encrypt ======= We now demonstrate how to generate an S/MIME-encrypted message:: from M2Crypto import BIO, Rand, SMIME, X509 def makebuf(text): return BIO.MemoryBuffer(text) # Make a MemoryBuffer of the message. buf = makebuf('a sign of our times') # Seed the PRNG. Rand.load_file('randpool.dat', -1) # Instantiate an SMIME object. s = SMIME.SMIME() # Load target cert to encrypt to. x509 = X509.load_cert('recipient.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) # Set cipher: 3-key triple-DES in CBC mode. s.set_cipher(SMIME.Cipher('des_ede3_cbc')) # Encrypt the buffer. p7 = s.encrypt(buf) # Output p7 in mail-friendly format. out = BIO.MemoryBuffer() out.write('From: sender@example.dom\n') out.write('To: recipient@example.dom\n') out.write('Subject: M2Crypto S/MIME testing\n') s.write(out, p7) print(out.read()) # Save the PRNG's state. Rand.save_file('randpool.dat') Here's the output of the above program:: From: sender@example.dom To: recipient@example.dom Subject: M2Crypto S/MIME testing MIME-Version: 1.0 Content-Disposition: attachment; filename="smime.p7m" Content-Type: application/x-pkcs7-mime; name="smime.p7m" Content-Transfer-Encoding: base64 MIIBVwYJKoZIhvcNAQcDoIIBSDCCAUQCAQAxggEAMIH9AgEAMGYwYTELMAkGA1UE BhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRkwFwYDVQQDExBTL01JTUUgUmVjaXBp ZW50MSQwIgYJKoZIhvcNAQkBFhVyZWNpcGllbnRAZXhhbXBsZS5kb20CAQAwDQYJ KoZIhvcNAQEBBQAEgYCBaXZ+qjpBEZwdP7gjfzfAtQitESyMwo3i+LBOw6sSDir6 FlNDPCnkrTvqDX3Rt6X6vBtTCYOm+qiN7ujPkOU61cN7h8dvHR8YW9+0IPY80/W0 lZ/HihSRgwTNd7LnxUUcPx8YV1id0dlmP0Hz+Lg+mHf6rqaR//JcYhX9vW4XvjA7 BgkqhkiG9w0BBwEwFAYIKoZIhvcNAwcECMN+qya6ADywgBgHr9Jkhwn5Gsdu7BwX nIQfYTYcdL9I5Sk= Decrypt ======= Assume the above output has been saved into ``encrypt.p7``. Decrypt the message thusly:: from M2Crypto import BIO, SMIME, X509 # Instantiate an SMIME object. s = SMIME.SMIME() # Load private key and cert. s.load_key('recipient_key.pem', 'recipient.pem') # Load the encrypted data. p7, data = SMIME.smime_load_pkcs7('encrypt.p7') # Decrypt p7. out = s.decrypt(p7) print(out) Here's the output:: a sign of our times It is also possible to decrypt a message message from a string, without reading it from a file first:: from M2Crypto import SMIME, BIO # Instantiate an SMIME object. s = SMIME.SMIME() # Load private key and cert. s.load_key('private_key.pkcs7.pem', 'public_key.pkcs7.pem') # The Encrypted data data_raw = "MIIBeQYJKoZIhvcNAQcDoIIBajCCAWYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAL3r2KUEnR+Ds7lunkNUAEYWqiyppvZipjoCobD1FFF+WdFoaHcxJ/p18EaHfgXVgQ9tIPmEVfbVnxB406rrVEN9dZIrHyHBszl8G5xGcwQpbiYmQgS9cJc7P9Ya/qSwc7fzKAi4eoUfr7BALl3qWI1X+R2KNShDaUoa21c0XehHu0Qb6d2hScEdTulpGhGUaTkwMN4ZJmA60enG7xhSW8RIyZLTx7glRaaI/hEP0LsfkfI+kpKNQ8u52s816/tih5hiVtvpipWOyBU+L3OHVbGy4uzb9vMGO22KDm7Dev9wYs2EzHQry/u33ygdHzZwYwAM5Dm1js3cnJ5vsJdME5zA8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBC21FrAYYgygBf8j3Qxflb1gBASekTx2RHk+wRH3Gc0KA09" # Add relevant headers, newlines that separate header and data, and trailing newline. data = f"Content-Type: application/x-pkcs7-mime; name=\"smime.p7m\"\n\n{data_raw}\n".encode() # Load data into a BIO. bio = BIO.MemoryBuffer(data) # Load bio data into an SMIME object. p7, _data = SMIME.smime_load_pkcs7_bio(bio) # Decrypt p7. out = s.decrypt(p7) print(out) Sign and Encrypt ================ Here's how to generate an S/MIME-signed/encrypted message:: from M2Crypto import BIO, Rand, SMIME, X509 def makebuf(text): return BIO.MemoryBuffer(text) # Make a MemoryBuffer of the message. buf = makebuf('a sign of our times') # Seed the PRNG. Rand.load_file('randpool.dat', -1) # Instantiate an SMIME object. s = SMIME.SMIME() # Load signer's key and cert. Sign the buffer. s.load_key('signer_key.pem', 'signer.pem') p7 = s.sign(buf) # Load target cert to encrypt the signed message to. x509 = X509.load_cert('recipient.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) # Set cipher: 3-key triple-DES in CBC mode. s.set_cipher(SMIME.Cipher('des_ede3_cbc')) # Create a temporary buffer. tmp = BIO.MemoryBuffer() # Write the signed message into the temporary buffer. s.write(tmp, p7) # Encrypt the temporary buffer. p7 = s.encrypt(tmp) # Output p7 in mail-friendly format. out = BIO.MemoryBuffer() out.write('From: sender@example.dom\n') out.write('To: recipient@example.dom\n') out.write('Subject: M2Crypto S/MIME testing\n') s.write(out, p7) print(out.read()) # Save the PRNG's state. Rand.save_file('randpool.dat') Here's the output of the above program:: From: sender@example.dom To: recipient@example.dom Subject: M2Crypto S/MIME testing MIME-Version: 1.0 Content-Disposition: attachment; filename="smime.p7m" Content-Type: application/x-pkcs7-mime; name="smime.p7m" Content-Transfer-Encoding: base64 MIIIwwYJKoZIhvcNAQcDoIIItDCCCLACAQAxggEAMIH9AgEAMGYwYTELMAkGA1UE BhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRkwFwYDVQQDExBTL01JTUUgUmVjaXBp ZW50MSQwIgYJKoZIhvcNAQkBFhVyZWNpcGllbnRAZXhhbXBsZS5kb20CAQAwDQYJ KoZIhvcNAQEBBQAEgYBlZlGupFphwhsGtIAPvDExN61qisz3oem88xoXkUW0SzoR B9zJFFAuQTWzdNJgrKKYikhWjDojaAc/PFl1K5dYxRgtZLB36ULJD/v/yWmxnjz8 TvtK+Wbal2P/MH2pZ4LVERXa/snTElhCawUlwtiFz/JvY5CiF/dcwd+AwFQq4jCC B6UGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIRF525UfwszaAggeA85RmX6AXQMxb eBDz/LJeCgc3RqU1UwIsbKMquIs1S46Ebbm5nP75izPnujOkJ2hv+LNzqOWADmOl +CnGEq1qxTyduIgUDA2nBgCL/gVyVy+/XC9dtImUUTxtxLgYtB0ujkBNsOaENOlM fv4SGM3jkR+K/xlYG6HHzZGbfYyNGj2Y7yMZ1rL1m8SnRNmkCysKGTrudeNf6wT9 J6wO9DzLTioz3ZnVr3LjsSKIb4tIp4ugqNJaLuW7m3FtZ3MAgxN68hBbJs8TZ8tL V/0jwUqS+grcgZEb9ymfcedxahtDUfHjRkpDpsxZzVVGkSBNcbQu92oByQVnRQ8m wrYLp3/eawM5AvuV7HNpTT5ZR+1t8luishHN9899IMP2Vyg0Ub67FqFypYmM2cm2 sjAI4KpfvT00XFNvgLuYwYEKs9syGTO7hiHNQKcF44F5LYv6nTFwmFQB11dAtY9V ull4D2CLDx9OvyNyKwdEZB5dyV0r/uKIdkhST60V2Q9KegpzgFpoZtSKM/HPYSVH 1Bc9f3Q/GqZCvNZZCMx8UvRjQR8dRWDSmPJ0VXG1+wJ+fCmSPP3AuQ1/VsgPRqx2 56VrpGPpGut40hV8xQFbWIZ2whwWLKPFAHj8B79ZtFUzUrU6Z2rNpvv8inHc/+S/ b6GR5s8/gucRblvd7n3OFNX5UJmPmcw9zWbu/1Dr9DY8l0nAQh21y5FGSS8B1wdE oD2M3Lp7JbwjQbRtnDhImqul2S4yu+m+wDD1aR2K4k3GAI7KKgOBWT0+BDClcn8A 4Ju6/YUbj33YlMPJgnGijLnolFy0hNW7TmWqR+8tSI3wO5eNKg4qwBnarqc3vgCV quVxINAXyGQCO9lzdw6hudk8/+BlweGdqhONaIWbK5z1L/SfQo6LC9MTsj7FJydq bc+kEbfZS8aSq7uc9axW6Ti0eAPJ8EVHtwhSBgZQRweKFBXs6HbbhMIdc4N0M7Oq UiFXaF6s4n2uihVP6TqXtHEjTpZoC7pC+HCYiuKXUJtaqtXBOh+y3KLvHk09YL6D XmTDg+UTiFsh4jKKm/BhdelbR5JbpJcj5AId76Mfr8+F/1g9ePOvsWHpQr/oIQTo xEkaxCmzEgP0b6caMWfMUQrbVGxBBNcqKc/ir9fGGOPHATzzq/xLcQYvK1tZhd/D ah/gpMPndsyvVCEuFPluWyDiM0VkwHgC2/3pJIYFHaxK64IutmPsy393rHMEB4kN AHau6kWK+yL9qEVH1pP2zvswQ12P7gjt3T/G3bGsmvlXkEfztfjkXo6XnjcBNf5y G+974AKLcjnk1gzIgarz+lAMY57Gkw4oNDMrTqVQ2OJQlvOSbllPXzH+aAiavB8W ZPECLLwHxD4B1AuaiAArgKl935u/TOB+yQOR8JgGsUzROyJqHJ/SC51HkebgCkL1 aggtjgPlIBEXLZAlhpWLZ9lAQyrQpvCVJYwaOvfMmvRav4NAFNoZ2/Q7S4Tn1z+U XX+f+GD58P4MPMhU5IKnz4yH4nlHnAiTEvcs85TZUAXze9g/uBOwZITeGtyLi52S aETIr4v7SgXMepX7ThQ1Pv/jddsK/u4j2F34u0XktwCP+UrbfkE2mocdXvdzxbmd tZSznK2qwgVSsPOs9MhUaepbnjmNBFFBrULhrUtSglM/VX/rWNiyh0aw4XYyHhIt 9ZNlfEjKjJ67VEMBxBJ/ieUCouRGCxPYD1j65VT7oB3ZiyPu2F2nlUIcYNqPg1Sd QBCrdaOXdJ0uLwyTAUeVE+wMbgscLvWsfZcCCJHAvw9NHFMUcnrdWxAYMVETNUOn uryVAK7VfOldaz6z3NOSOi6nonNeHpR/sipBa4ik5xCRLT9e0S2QJgRvO9GyfAqz 3DIzHtxIGePFzTiUYUTxS3i2gnMX2PEe3ChTLlYWD3jNeAKz0iOzpDphIF2xHLLQ 1tCAqBmq/vUzALyDFFdFuTIqQZys4z/u4Dmyq9uXs421eN3v2hkVHvDy8uT2Ot29 lg4Q5YezR1EjaW//9guL1BXbcKrTEdtxeNqtem7SpZOMTSwD2lhB8z65GrX90Cyt EMmaRSGYEdf5h1afL1SmKOMskbqxe1D2jG/vsXC7XX7xO/ioy0BdiJcYN1JiMOHJ EOzFol5I20YkiV6j+cenfQFwc/NkaSxEkR8AUHJSbvUmRQRl6r0nnsFpZdR1w7pv wkaT+eOpZynO4mY/ZtF6MpXJsixi6L4ZYXEbS6yHf+XGFfB0okILylmwv2bf6+Mq nqXlmGj3Jwq7X9/+2BDqvfpFFX5lSmItKZAobLdssjFR6roJxOqRsGia2aZ+0+U5 VhgdITtnElgtHBaeZU5rHDswgdeLVBP+rGWnKxpJ+pLtNNi25sPYRcWFL6Erd25u eXiY8GEIr+u7rqBWpc9HR34sAPRs3ubbCUleT748keCbx247ImBtiDctZxcc1O86 +0QjHP6HUT7FSo/FmT7a120S3Gd2jixGh06l/9ij5Z6mJa7Rm7TTbSjup/XISnOT MKWcbI1nfVOhCv3xDq2eLae+s0oVoc041ceRazqFM2TL/Z6UXRME Decrypt and Verify ================== Suppose the above output has been saved into ``se.p7``. The following demonstrates how to decrypt and verify it:: from M2Crypto import BIO, SMIME, X509 # Instantiate an SMIME object. s = SMIME.SMIME() # Load private key and cert. s.load_key('recipient_key.pem', 'recipient.pem') # Load the signed/encrypted data. p7, data = SMIME.smime_load_pkcs7('se.p7') # After the above step, 'data' == None. # Decrypt p7. 'out' now contains a PKCS #7 signed blob. out = s.decrypt(p7) # Load the signer's cert. x509 = X509.load_cert('signer.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) # Load the signer's CA cert. In this case, because the signer's # cert is self-signed, it is the signer's cert itself. st = X509.X509_Store() st.load_info('signer.pem') s.set_x509_store(st) # Recall 'out' contains a PKCS #7 blob. # Transform 'out'; verify the resulting PKCS #7 blob. p7_bio = BIO.MemoryBuffer(out) p7, data = SMIME.smime_load_pkcs7_bio(p7_bio) v = s.verify(p7) print(v) The output is as follows:: a sign of our times Sending S/MIME messages via SMTP ================================ In the above examples, we've assumed that our S/MIME messages are sent and received automagically. The following is a Python function that generates S/MIME-signed/encrypted messages and sends them via SMTP:: from M2Crypto import BIO, SMIME, X509 import smtplib, string, sys def sendsmime(from_addr, to_addrs, subject, msg, from_key, from_cert=None, to_certs=None, smtpd='localhost'): msg_bio = BIO.MemoryBuffer(msg) sign = from_key encrypt = to_certs s = SMIME.SMIME() if sign: s.load_key(from_key, from_cert) if encrypt: p7 = s.sign(msg_bio, flags=SMIME.PKCS7_TEXT) else: p7 = s.sign(msg_bio, flags=SMIME.PKCS7_TEXT|SMIME.PKCS7_DETACHED) msg_bio = BIO.MemoryBuffer(msg) # Recreate coz sign() has consumed it. if encrypt: sk = X509.X509_Stack() for x in to_certs: sk.push(X509.load_cert(x)) s.set_x509_stack(sk) s.set_cipher(SMIME.Cipher('des_ede3_cbc')) tmp_bio = BIO.MemoryBuffer() if sign: s.write(tmp_bio, p7) else: tmp_bio.write(msg) p7 = s.encrypt(tmp_bio) out = BIO.MemoryBuffer() out.write('From: %s\r\n' % from_addr) out.write('To: %s\r\n' % string.join(to_addrs, ", ")) out.write('Subject: %s\r\n' % subject) if encrypt: s.write(out, p7) else: if sign: s.write(out, p7, msg_bio, SMIME.PKCS7_TEXT) else: out.write('\r\n') out.write(msg) out.close() smtp = smtplib.SMTP() smtp.connect(smtpd) smtp.sendmail(from_addr, to_addrs, out.read()) smtp.quit() This function sends plain, S/MIME-signed, S/MIME-encrypted, and S/MIME-signed/encrypted messages, depending on the parameters ``from_key`` and ``to_certs``. The function's output interoperates with Netscape Messenger. Verifying origin of S/MIME messages =================================== In our examples above that decrypt or verify messages, we skipped a step: verifying that the ``from`` address of the message matches the ``email address`` attribute in the sender's certificate. The premise of current X.509 certification practice is that the CA is supposed to verify your identity, and to issue a certificate with ``email address`` that matches your actual mail address. (Verisign's March 2001 failure in identity verification resulting in Microsoft certificates being issued to spoofers notwithstanding.) If you run your own CA, your certification practice is up to you, of course, and it would probably be part of your security policy. Whether your S/MIME messaging application needs to verify the ``from`` addresses of S/MIME messages depends on your security policy and your system's threat model, as always. Interoperating with Netscape Messenger ====================================== Suppose S/MIME Recipient uses Netscape Messenger. To enable Messenger to handle S/MIME messages from S/MIME Sender, S/MIME Recipient needs to configure Messenger with his private key and certificate, as well as S/MIME Sender's certificate. **Note:** Configuring Messenger's POP or IMAP settings so that it retrieves mail correctly is beyond the scope of this HOWTO. The following steps demonstrate how to import S/MIME Recipient's private key and certificate for Messenger: 1. Transform S/MIME Recipient's private key and certificate into *PKCS #12* format:: openssl pkcs12 -export -in recipient.pem -inkey recipient_key.pem \ -name "S/MIME Recipient" -out recipient.p12 Enter Export Password: Verifying password - Enter Export Password: 2. Start Messenger. 3. Click on the (open) "lock" icon at the bottom left corner of Messenger's window. This brings up the "Security Info" dialog box. 4. Click on "Yours" under "Certificates". 5. Select "Import a certificate", then pick ``recipient.p12`` from the ensuing file selection dialog box. Next, you need to import ``signer.pem`` as a CA certificate, so that Messenger will mark messages signed by S/MIME Sender as "trusted": 1. Create a DER encoding of ``signer.pem``:: openssl x509 -inform pem -outform der -in signer.pem -out signer.der 2. Install ``signer.der`` into Messenger as MIME type ``application/x-x509-ca-cert``. You do this by downloading ``signer.der`` via Navigator from a HTTP or HTTPS server, with the correct MIME type mapping. (You may use ``demo/ssl/https_srv.py``, bundled with M2Crypto, for this purpose.) Follow the series of dialog boxes to accept ``signer.der`` as a CA for certifying email users. S/MIME Recipient is now able to decrypt and read S/MIME Sender's messages with Messenger. Messenger will indicate that S/MIME Sender's messages are signed, encrypted, or encrypted *and* signed, as the case may be, via the "stamp" icon on the message window's top right corner. Clicking on the "stamp" icon brings you to the Security Info dialog box. Messenger informs you that the message is, say, encrypted with 168-bit DES-EDE3-CBC and that it is digitally signed by the private key corresponding to the public key contained in the certificate ``signer.pem``. Interoperating with Microsoft Outlook ===================================== I do not know how to do this, as I do not use Outlook. (Nor do I use Netscape Messenger, actually. I use Mutt, top dog of MUAs. ;-) Information on how to configure Outlook with keys and certificates so that it handles S/MIME mail is gratefully accepted. ZSmime ====== ZSmime is a `Zope `__ *product* that enables Zope to generate S/MIME-signed/encrypted messages. ZSmime demonstrates how to invoke M2Crypto in a web application server extension. ZSmime has its own `HOWTO `__ explaining its usage. (That HOWTO has some overlap in content with this document.) Resources ========= - IETF S/MIME Working Group - http://www.imc.org/ietf-smime - S/MIME and OpenPGP - http://www.imc.org/smime-pgpmime.html - S/MIME Freeware Library - http://www.getronicsgov.com/hot/sfl_home.htm - Mozilla Network Security Services - http://www.mozilla.org/projects/security/pkg/nss - S/MIME Cracking Screen Saver - http://www.counterpane.com/smime.html m2crypto-0.42.0/doc/howto.ssl.rst000066400000000000000000000124601465575656700166500ustar00rootroot00000000000000:orphan: .. _howto-ssl: HOWTO: Programming SSL in Python with M2Crypto ############################################## :author: Pheng Siong Ng and Heikki Toivonen (heikki@osafoundation.org) :copyright: © 2000, 2001 by Ng Pheng Siong, portions © 2006 by Open Source Applications Foundation Introduction ============ `M2Crypto `__ is a `Python `__ interface to `OpenSSL `__. It makes available to the Python programmer SSL functionality to implement clients and servers, S/MIME v2, RSA, DSA, DH, symmetric ciphers, message digests and HMACs. This document demonstrates programming HTTPS with M2Crypto. A bit of history ================ M2Crypto was created during the time of Python 1.5, which features a module httplib providing client-side HTTP functionality. M2Crypto sports a httpslib based on httplib. Beginning with version 2.0, Python's socket module provided (rudimentary) SSL support. Also in the same version, httplib was enhanced with class HTTPConnection, which is more sophisticated than the old class HTTP, and HTTPSConnection, which does HTTPS. Subsequently, M2Crypto.httpslib grew a compatible (but not identical) class HTTPSConnection. The primary interface difference between the two HTTPSConnection classes is that M2Crypto's version accepts an M2Crypto.SSL.Context instance as a parameter, whereas Python 2.x's SSL support does not permit Pythonic control of the SSL context. Within the implementations, Python's ``HTTPSConnection`` employs a ``FakeSocket`` object, which collects all input from the SSL connection before returning it to the application as a ``StringIO`` buffer, whereas M2Crypto's ``HTTPSConnection`` uses a buffering ``M2Crypto.BIO.IOBuffer`` object that works over the underlying M2Crypto.SSL.Connection directly. Since then M2Crypto has gained a Twisted wrapper that allows securing Twisted SSL connections with M2Crypto. Secure SSL ========== It is recommended that you read the book Network Security with OpenSSL by John Viega, Matt Messier and Pravir Chandra, ISBN 059600270X. Using M2Crypto does not automatically make an SSL connection secure. There are various steps that need to be made before we can make that claim. Let's see how a simple client can establish a secure connection:: ctx = SSL.Context() ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, depth=9) if ctx.load_verify_locations('ca.pem') != 1: raise Exception('No CA certs') s = SSL.Connection(ctx) s.connect(server_address) # Normal protocol (for example HTTP) commands follow The first line creates an SSL context. The defaults allow any SSL version (except SSL version 2 which has known weaknesses) and sets the allowed ciphers to secure ones. The second line tells M2Crypto to perform certificate validation. The flags shown above are typical for clients, and requires the server to send a certificate. The depth parameter tells how long certificate chains are allowed - 9 is pretty common default, although probably too long in practice. The third line loads the allowed root (certificate authority or CA) certificates. Most Linux distributions come with CA certificates in suitable format. You could also download the `certdata.txt `__ file from the `NSS `__ project and convert it with the little M2Crypto utility script `demo/x509/certdata2pem.py `__. The fourth line creates an SSL connection object with the secure context. The fifth line connects to the server. During this time we perform the last security step: just after connection, but before exchanging any data, we compare the commonName (or subjectAltName DNS field) field in the certificate the server returned to the server address we tried to connect to. This happens automatically with SSL.Connection and the Twisted wrapper class, and anything that uses those. In all other cases you must do the check manually. It is recommended you call the SSL.Checker to do the actual check. SSL servers are different in that they typically do not require the client to send a certificate, so there is usually no certificate checking. Also, it is typically useless to perform host name checking. Code Samples ============ The best samples of how to use the various SSL objects are in the tests directory, and the test\_ssl.py file specifically. There are additional samples in the demo directory, but they are not quaranteed to be up to date. NOTE: The tests and demos may not be secure as is. Use the information above on how to make them secure. ssldump ======= ssldump "is an SSLv3/TLS network protocol analyser. It identifies TCP connections on the chosen network interface and attempts to interpret them as SSLv3/TLS traffic. When it identifies SSLv3/TLS traffic, it decodes the records and displays them in a textual form to stdout. If provided with the appropriate keying material, it will also decrypt the connections and display the application data traffic. If linked with OpenSSL, ssldump can display certificates in decoded form and decrypt traffic (provided that it has the appropriate keying material)." ssldump is written by Eric Rescorla. m2crypto-0.42.0/doc/index.rst000066400000000000000000000003501465575656700160120ustar00rootroot00000000000000Welcome to M2Crypto's documentation! ==================================== Contents: .. toctree:: :maxdepth: 2 M2Crypto HOWTOs Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` m2crypto-0.42.0/doc/make.bat000066400000000000000000000117541465575656700155700ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\M2Crypto.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\M2Crypto.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end m2crypto-0.42.0/doc/requirements.txt000066400000000000000000000001751465575656700174420ustar00rootroot00000000000000cryptography>=42.0.5,==42.* # Needed to run the doctests in the migration docs sphinx==7.2.6 sphinx-rtd-theme==2.0.0 twisted m2crypto-0.42.0/pylintrc000066400000000000000000000205641465575656700152040ustar00rootroot00000000000000# -*- coding: utf-8; mode: conf -*- # lint Python modules using external checkers. # # This is the main checker controlling the other ones and the reports # generation. It is itself both a raw checker and an astng checker in order # to: # * handle message activation / deactivation at the module level # * handle some basic but necessary stats'data (number of classes, methods...) # [MASTER] # Specify a configuration file. #rcfile= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Add to the black list. It should be a base name, not a # path. You may set this option multiple times. ignore=CVS, .git, .svn # Pickle collected data for later comparisons. persistent=yes # Set the cache size for astng objects. cache-size=500 # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins= [MESSAGES CONTROL] # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time. See also the "--disable" option for examples. #enable= # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifiers separated by comma (,) or put this # option multiple times (only on the command line, not in the configuration # file where it should appear only once).You can also use "--disable=all" to # disable everything first and then reenable specific checks. For example, if # you want to run only the similarities checker, you can use "--disable=all # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" disable=C0330, C0103, C0111, C0326, R0901, R0903, R0201, I0011 [REPORTS] # Set the output format. Available formats are text, parseable, colorized, msvs # (visual studio) and html. You can also give a reporter class, eg # mypackage.mymodule.MyReporterClass. output-format=text # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be # written in a file name "pylint_global.[txt|html]". files-output=no # Tells whether to display a full report or only the messages reports=yes # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details msg-template={path}:{line}:[{msg_id}({symbol}),{obj}] {msg} [TYPECHECK] # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # List of classes names for which member attributes should not be checked # (useful for classes with attributes dynamically set). ignored-classes=SQLObject # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E0201 when accessed. Python regular # expressions are accepted. generated-members=REQUEST,acl_users,aq_parent [VARIABLES] # Tells whether we should check for unused import in __init__ files. init-import=no # A regular expression matching the beginning of the name of dummy variables # (i.e. not used). dummy-variables-rgx=_|dummy # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins= [FORMAT] # Maximum number of characters on a single line. max-line-length=120 # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Allow the body of an if to be on the same line as the test if there is no # else. single-line-if-stmt=no # List of optional constructs for which whitespace checking is disabled no-space-check=trailing-comma,dict-separator # Maximum number of lines in a module max-module-lines=2000 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' [BASIC] # List of builtins function names that should not be used, separated by a comma bad-functions=map,filter,apply,input # Regular expression which should only match correct module names # module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ module-rgx=(([a-z_][a-z0-9_]*)|([a-zA-Z0-9]+))$ # Regular expression which should only match correct module level names const-rgx=[f]?[A-Z_][a-zA-Z0-9_]{2,30}$ # Regular expression which should only match correct class names class-rgx=[A-Z_]+[a-zA-Z0-9]+$ # Regular expression which should only match correct function names function-rgx=[a-z_][a-zA-Z0-9_]{2,30}$ # Regular expression which should only match correct method names method-rgx=[a-zA-Z0-9_]{2,30}$ # Regular expression which should only match correct instance attribute names attr-rgx=([a-z_][a-zA-Z0-9_]{2,30}|[A-Z0-9_]{2,30})$ # Regular expression which should only match correct argument names argument-rgx=[a-z_][a-zA-Z0-9_]{2,30}$ # Regular expression which should only match correct variable names variable-rgx=[a-z_][a-zA-Z0-9_]{0,30}$ # Regular expression which should only match correct attribute names in class # bodies class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ # Regular expression which should only match correct list comprehension / # generator expression variable names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Good variable names which should always be accepted, separated by a comma good-names=i,j,k,ex,Run,_ # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=__.*__ # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=-1 [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME,XXX,TODO [SIMILARITIES] # Minimum lines number of a similarity. min-similarity-lines=4 # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no [CLASSES] # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__,__new__,setUp # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=mcs [DESIGN] # Maximum number of arguments for function / method max-args=8 # Argument names that match this expression will be ignored. Default to name # with leading underscore ignored-argument-names=_.* # Maximum number of locals for function / method body max-locals=15 # Maximum number of return / yield for function / method body max-returns=6 # Maximum number of branch for function / method body max-branches=12 # Maximum number of statements in function / method body max-statements=50 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of attributes for a class (see R0902). max-attributes=50 # Minimum number of public methods for a class (see R0903). min-public-methods=2 # Maximum number of public methods for a class (see R0904). max-public-methods=100 [IMPORTS] # Deprecated modules which should not be used, separated by a comma deprecated-modules=regsub,string,TERMIOS,Bastion,rexec # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled) import-graph= # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled) ext-import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled) int-import-graph= [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "Exception" overgeneral-exceptions=Exception m2crypto-0.42.0/pyproject.toml000066400000000000000000000002211465575656700163150ustar00rootroot00000000000000[build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [tool.black] line-length = 70 skip-string-normalization = true m2crypto-0.42.0/requirements.txt000066400000000000000000000001721465575656700166720ustar00rootroot00000000000000build wheel; sys.platform == 'win32' setuptools>=43.0.0; python_version<='3.6' setuptools>=65.6.0; python_version>='3.10' m2crypto-0.42.0/setup.cfg000066400000000000000000000027321465575656700152330ustar00rootroot00000000000000[metadata] name = M2Crypto version = attr: M2Crypto.__version__ author = Ng Pheng Siong author_email = ngps@sandbox.rulemaker.net maintainer = Matej Cepl maintainer_email = mcepl@cepl.eu description = A Python crypto and SSL toolkit long_description = file: README.rst url = https://sr.ht/~mcepl/m2crypto/ keywords = cryptography openssl license = MIT classifiers = Development Status :: 5 - Production/Stable Intended Audience :: Developers License :: OSI Approved :: MIT License Operating System :: OS Independent Programming Language :: C Programming Language :: Python Topic :: Security :: Cryptography Topic :: Software Development :: Libraries :: Python Modules Programming Language :: Python :: 3 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 [options] zip_safe = False include_package_data = True package_dir= =src packages = find: install_requires = importlib-metadata; python_version < "3.8" [options.packages.find] where=src exclude = contrib* docs* tests* [options.package_data] M2Crypto = *.dll [egg_info] tag_build = tag_svn_revision = 0 [flake8] ; ignore = E402,E501,E731,N806,N803,N802,E265 ignore = E402,N806,N803,N802,E501 [pydocstyle] ignore = D10,D203,D213 m2crypto-0.42.0/setup.py000066400000000000000000000251171465575656700151260ustar00rootroot00000000000000#!/usr/bin/env python """ setuptools based installer for M2Crypto. Copyright (c) 1999-2004, Ng Pheng Siong. All rights reserved. Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2004-2007 OSAF. All Rights Reserved. Copyright 2008-2011 Heikki Toivonen. All rights reserved. Copyright 2018 Daniel Wozniak. All rights reserved. """ import ctypes import ctypes.util import glob import logging import os import platform import re import shlex import shutil import subprocess import sys import setuptools from typing import Dict, List if sys.version_info[:2] < (3, 10): from distutils.command import build from distutils.dir_util import mkpath else: from setuptools.command import build from setuptools.command import build_ext logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s', level=logging.DEBUG) log = logging.getLogger('setup') requires_list = [] def _get_additional_includes(): if os.name == 'nt': globmask = os.path.join('C:', os.sep, 'Program Files*', '*Visual*', 'VC', 'include') err = glob.glob(globmask) else: cpp = shlex.split(os.environ.get('CPP', 'cpp')) pid = subprocess.Popen(cpp + ['-Wp,-v', '-'], stdin=open(os.devnull, 'r'), stdout=subprocess.PIPE, stderr=subprocess.PIPE) _, err = pid.communicate() err = [line.lstrip() for line in err.decode('utf8').split('\n') if line and line.startswith(' /')] log.debug('additional includes:\n%s', err) return err def openssl_version(ossldir, req_ver, required=False): # type: (str, int, bool) -> bool """ Compare version of the installed OpenSSL with the maximum required version. :param ossldir: the directory where OpenSSL is installed :param req_ver: required version as integer (e.g. 0x10100000) :param required: whether we want bigger-or-equal or less-than :return: Boolean indicating whether the satisfying version of OpenSSL has been installed. """ ver = None try: if sys.platform == 'win32': found_lib = glob.glob(os.path.join(os.environ.get('OPENSSL_PATH'), 'libcrypto*.dll'))[0] crypt_lib = ctypes.WinDLL(found_lib) else: crypt_lib = ctypes.cdll.LoadLibrary("libssl.so") log.info(f'crypt_lib = {crypt_lib}') except (AttributeError, FileNotFoundError): ver = None file = os.path.join(ossldir, 'include', 'openssl', 'opensslv.h') with open(file) as origin_file: for line in origin_file: m = re.match( r'^# *define *OPENSSL_VERSION_NUMBER *(0x[0-9a-fA-F]*)', line) if m: log.debug('found version number: %s\n', m.group(1)) ver = int(m.group(1), base=16) break if ver is None: raise OSError('Unknown format of file %s\n' % file) else: try: ver = crypt_lib.OpenSSL_version_num() except OSError: pass log.info(f'ctypes: ver = {ver:#0X}') if required: return ver >= req_ver else: return ver < req_ver class _M2CryptoBuildExt(build_ext.build_ext): """Enable swig_opts to inherit any include_dirs settings made elsewhere.""" def initialize_options(self): """Overload to enable custom openssl settings to be picked up.""" build_ext.build_ext.initialize_options(self) def finalize_options(self): # type: (None) -> None """Append custom openssl include file and library linking options.""" build_ext.build_ext.finalize_options(self) self.openssl_path = os.environ.get('OPENSSL_PATH', None) self.bundledlls = os.environ.get('BUNDLEDLLS', None) self.libraries = ['ssl', 'crypto'] if sys.platform == 'win32': self.libraries = ['ssleay32', 'libeay32'] if self.openssl_path and openssl_version(self.openssl_path, 0x10100000, True): self.libraries = ['libssl', 'libcrypto'] self.swig_opts.append('-D_WIN32') # Swig doesn't know the version of MSVC, which causes # errors in e_os2.h trying to import stdint.h. Since # python 2.7 is intimately tied to MSVC 2008, it's # harmless for now to define this. Will come back to # this shortly to come up with a better fix. self.swig_opts.append('-D_MSC_VER=1500') log.debug('self.openssl_path = %s', self.openssl_path) log.debug('self.bundledlls = %s', self.bundledlls) # swig seems to need the default header file directories self.swig_opts.extend(['-I%s' % i for i in _get_additional_includes()]) log.debug('self.include_dirs = %s', self.include_dirs) log.debug('self.library_dirs = %s', self.library_dirs) if self.openssl_path is not None: log.debug('self.openssl_path = %s', self.openssl_path) openssl_library_dir = os.path.join(self.openssl_path, 'lib') openssl_include_dir = os.path.join(self.openssl_path, 'include') self.library_dirs.append(openssl_library_dir) self.include_dirs.append(openssl_include_dir) log.debug('self.include_dirs = %s', self.include_dirs) log.debug('self.library_dirs = %s', self.library_dirs) if platform.system() == "Linux": # For RedHat-based distros, the '-D__{arch}__' option for # Swig needs to be normalized, particularly on i386. mach = platform.machine().lower() if mach in ('i386', 'i486', 'i586', 'i686'): arch = '__i386__' elif mach in ('ppc64', 'powerpc64', 'ppc64le', 'ppc64el'): arch = '__powerpc64__' elif mach in ('ppc', 'powerpc'): arch = '__powerpc__' else: arch = '__%s__' % mach self.swig_opts.append('-D%s' % arch) if mach in ('ppc64le', 'ppc64el'): self.swig_opts.append('-D_CALL_ELF=2') if mach in ('arm64_be'): self.swig_opts.append('-D__AARCH64EB__') self.swig_opts.extend(['-I%s' % i for i in self.include_dirs]) # Some Linux distributor has added the following line in # /usr/include/openssl/opensslconf.h: # # #include "openssl-x85_64.h" # # This is fine with C compilers, because they are smart enough to # handle 'local inclusion' correctly. Swig, on the other hand, is # not as smart, and needs to be told where to find this file... # # Note that this is risky workaround, since it takes away the # namespace that OpenSSL uses. If someone else has similarly # named header files in /usr/include, there will be clashes. if self.openssl_path is None: self.swig_opts.append('-I/usr/include/openssl') else: self.swig_opts.append( '-I' + os.path.join(openssl_include_dir, 'openssl')) self.swig_opts.append('-includeall') self.swig_opts.append('-builtin') build_dir = os.path.join(self.build_lib, 'M2Crypto') os.makedirs(build_dir, exist_ok=True) # These two lines are a workaround for # http://bugs.python.org/issue2624 , hard-coding that we are only # building a single extension with a known path; a proper patch to # distutils would be in the run phase, when extension name and path are # known. self.swig_opts.extend(['-outdir', build_dir]) self.include_dirs.append(os.path.join(os.getcwd(), 'src', 'SWIG')) if sys.platform == 'cygwin' and self.openssl_path is not None: # Cygwin SHOULD work (there's code in distutils), but # if one first starts a Windows command prompt, then bash, # the distutils code does not seem to work. If you start # Cygwin directly, then it would work even without this change. # Someday distutils will be fixed and this won't be needed. self.library_dirs += [os.path.join(self.openssl_path, 'bin')] os.makedirs(os.path.join(self.build_lib, 'M2Crypto'), exist_ok=True) def run(self): """ On Win32 platforms include the openssl dll's in the binary packages """ # Win32 bdist builds must set OPENSSL_PATH before the builds step. if self.bundledlls is None: build_ext.build_ext.run(self) return # self.bundledlls is set if sys.platform == 'win32': ver_part = '' if self.openssl_path and openssl_version(self.openssl_path, 0x10100000, True): ver_part += '-1_1' if sys.maxsize > 2**32: ver_part += '-x64' search = list(self.library_dirs) if self.openssl_path: search = search + [self.openssl_path, os.path.join(self.openssl_path, 'bin')] libs = list(self.libraries) for libname in list(libs): for search_path in search: dll_name = '{0}{1}.dll'.format(libname, ver_part) dll_path = os.path.join(search_path, dll_name) if os.path.exists(dll_path): shutil.copy(dll_path, 'M2Crypto') libs.remove(libname) break if libs: raise Exception("Libs not found {}".format(','.join(libs))) build_ext.build_ext.run(self) x_comp_args = set() # We take care of deprecated functions in OpenSSL with our code, no need # to spam compiler output with it. if sys.platform == 'win32': x_comp_args.update(['-DTHREADING', '-D_CRT_SECURE_NO_WARNINGS']) else: x_comp_args.update(['-DTHREADING', '-Wno-deprecated-declarations']) m2crypto = setuptools.Extension(name='M2Crypto._m2crypto', sources=['src/SWIG/_m2crypto.i'], extra_compile_args=list(x_comp_args), # Uncomment to build Universal Mac binaries # extra_link_args = # ['-Wl,-search_paths_first'], ) setuptools.setup( ext_modules=[m2crypto], cmdclass={ 'build_ext': _M2CryptoBuildExt } ) m2crypto-0.42.0/src/000077500000000000000000000000001465575656700141755ustar00rootroot00000000000000m2crypto-0.42.0/src/M2Crypto/000077500000000000000000000000001465575656700156545ustar00rootroot00000000000000m2crypto-0.42.0/src/M2Crypto/ASN1.py000066400000000000000000000206461465575656700167400ustar00rootroot00000000000000from __future__ import absolute_import """ M2Crypto wrapper for OpenSSL ASN1 API. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2005 OSAF. All Rights Reserved. """ import datetime import time from M2Crypto import BIO, m2, types as C from typing import Optional, Union MBSTRING_FLAG: int = 0x1000 MBSTRING_ASC: int = MBSTRING_FLAG | 1 MBSTRING_BMP: int = MBSTRING_FLAG | 2 class ASN1_Integer: m2_asn1_integer_free = m2.asn1_integer_free def __init__( self, asn1int: Union[C.ASN1_Integer, int], _pyfree: int = 0 ): if isinstance(asn1int, int): self.asn1int: C.ASN1_Integer = m2.asn1_integer_new() m2.asn1_integer_set(self.asn1int, asn1int) else: self.asn1int = asn1int self._pyfree = _pyfree def __cmp__(self, other: "ASN1_Integer") -> int: if not isinstance(other, ASN1_Integer): raise TypeError( "Comparisons supported only between ANS1_Integer objects" ) return m2.asn1_integer_cmp(self.asn1int, other.asn1int) def __del__(self) -> None: if self._pyfree: self.m2_asn1_integer_free(self.asn1int) def __int__(self) -> int: return m2.asn1_integer_get(self.asn1int) class ASN1_String: m2_asn1_string_free = m2.asn1_string_free def __init__( self, asn1str: Union[C.ASN1_String, str, bytes], _pyfree: int = 0 ): if isinstance(asn1str, str): self.asn1str: C.ASN1_String = m2.asn1_string_new() m2.asn1_string_set(self.asn1str, asn1str.encode()) elif isinstance(asn1str, bytes): self.asn1str: C.ASN1_String = m2.asn1_string_new() m2.asn1_string_set(self.asn1str, asn1str) else: self.asn1str = asn1str self._pyfree = _pyfree def __bytes__(self) -> bytes: buf = BIO.MemoryBuffer() m2.asn1_string_print(buf.bio_ptr(), self.asn1str) return buf.read_all() def __str__(self) -> str: return self.__bytes__().decode() def __del__(self) -> None: if getattr(self, '_pyfree', 0): self.m2_asn1_string_free(self.asn1str) def _ptr(self): return self.asn1str def as_text(self, flags: int = 0) -> str: """Output an ASN1_STRING structure according to the set flags. :param flags: determine the format of the output by using predetermined constants, see ASN1_STRING_print_ex(3) manpage for their meaning. :return: output an ASN1_STRING structure. """ buf = BIO.MemoryBuffer() m2.asn1_string_print_ex(buf.bio_ptr(), self.asn1str, flags) return buf.read_all().decode() class ASN1_Object: m2_asn1_object_free = m2.asn1_object_free def __init__( self, asn1obj: C.ASN1_Object, _pyfree: int = 0 ) -> None: self.asn1obj = asn1obj self._pyfree = _pyfree def __del__(self) -> None: if self._pyfree: self.m2_asn1_object_free(self.asn1obj) def _ptr(self): return self.asn1obj class _UTC(datetime.tzinfo): def tzname(self, dt: Optional[datetime.datetime]) -> str: return "UTC" def dst( self, dt: Optional[datetime.datetime] ) -> datetime.timedelta: return datetime.timedelta(0) def utcoffset( self, dt: Optional[datetime.datetime] ) -> datetime.timedelta: return datetime.timedelta(0) def __repr__(self) -> str: return "" % self.tzname(None) UTC: _UTC = _UTC() class LocalTimezone(datetime.tzinfo): """Localtimezone from datetime manual.""" def __init__(self) -> None: self._stdoffset = datetime.timedelta(seconds=-time.timezone) if time.daylight: self._dstoffset = datetime.timedelta( seconds=-time.altzone ) else: self._dstoffset = self._stdoffset self._dstdiff = self._dstoffset - self._stdoffset def utcoffset(self, dt: datetime.datetime) -> datetime.timedelta: if self._isdst(dt): return self._dstoffset else: return self._stdoffset def dst(self, dt: datetime.datetime) -> datetime.timedelta: if self._isdst(dt): return self._dstdiff else: return datetime.timedelta(0) def tzname(self, dt: datetime.datetime) -> str: return time.tzname[self._isdst(dt).real] def _isdst(self, dt: datetime.datetime) -> bool: tt = ( dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1, ) stamp = time.mktime(tt) tt = time.localtime(stamp) return tt.tm_isdst > 0 class ASN1_TIME: _ssl_months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ] m2_asn1_time_free = m2.asn1_time_free def __init__( self, asn1_time: Optional[C.ASN1_Time] = None, _pyfree: int = 0, asn1_utctime: Optional[C.ASN1_Time] = None, ): # handle old keyword parameter if asn1_time is None: asn1_time = asn1_utctime if asn1_time is not None: assert m2.asn1_time_type_check( asn1_time ), "'asn1_time' type error'" self.asn1_time = asn1_time self._pyfree = _pyfree else: # that's (ASN1_TIME*) self.asn1_time: bytes = m2.asn1_time_new() self._pyfree = 1 def __del__(self) -> None: if getattr(self, '_pyfree', 0): self.m2_asn1_time_free(self.asn1_time) def __str__(self) -> str: assert m2.asn1_time_type_check( self.asn1_time ), "'asn1_time' type error'" buf = BIO.MemoryBuffer() m2.asn1_time_print(buf.bio_ptr(), self.asn1_time) return buf.read_all().decode() def _ptr(self): assert m2.asn1_time_type_check( self.asn1_time ), "'asn1_time' type error'" return self.asn1_time def set_string(self, string: bytes) -> int: """ Set time from UTC string. :return: 1 if the time value is successfully set and 0 otherwise """ assert m2.asn1_time_type_check( self.asn1_time ), "'asn1_time' type error'" return m2.asn1_time_set_string(self.asn1_time, string) def set_time(self, time: int) -> C.ASN1_Time: """ Set time from seconds since epoch (int). :return: pointer to a time structure or NULL if an error occurred """ assert m2.asn1_time_type_check( self.asn1_time ), "'asn1_time' type error'" if hasattr(__builtins__, "long"): time = long(time) return m2.asn1_time_set(self.asn1_time, time) def get_datetime(self) -> datetime.datetime: """ Get time as datetime.datetime object :return: always return datetime object :raises: ValueError if anything wrong happens """ date = str(self) timezone = None if ' ' not in date: raise ValueError("Invalid date: %s" % date) month, rest = date.split(' ', 1) if month not in self._ssl_months: raise ValueError( "Invalid date %s: Invalid month: %s" % (date, month) ) if rest.endswith(' GMT'): timezone = UTC rest = rest[:-4] if '.' in rest: dt = datetime.datetime.strptime(rest, "%d %H:%M:%S.%f %Y") else: dt = datetime.datetime.strptime(rest, "%d %H:%M:%S %Y") dt = dt.replace(month=self._ssl_months.index(month) + 1) if timezone: dt = dt.replace(tzinfo=UTC) return dt def set_datetime(self, date: datetime.datetime) -> C.ASN1_Time: """ Set time from datetime.datetime object. :return: pointer to a time structure or NULL if an error occurred """ local = LocalTimezone() if date.tzinfo is None: date = date.replace(tzinfo=local) date = date.astimezone(local) return self.set_time(int(time.mktime(date.timetuple()))) ASN1_UTCTIME = ASN1_TIME m2crypto-0.42.0/src/M2Crypto/AuthCookie.py000066400000000000000000000116701465575656700202660ustar00rootroot00000000000000from __future__ import absolute_import """Secure Authenticator Cookies Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.""" import logging import re import time from http.cookies import SimpleCookie from M2Crypto import Rand, m2, util from typing import Pattern, AnyStr, Optional, Union # noqa _MIX_FORMAT = 'exp=%f&data=%s&digest=' _MIX_RE = re.compile(r'exp=(\d+\.\d+)&data=(.+)&digest=(\S*)') log = logging.getLogger(__name__) def mix(expiry, data, format=_MIX_FORMAT): # type: (float, AnyStr, str) -> AnyStr return format % (expiry, data) def unmix(dough, regex=_MIX_RE): # type: (AnyStr, Pattern) -> object mo = regex.match(dough) if mo: return float(mo.group(1)), mo.group(2) else: return None def unmix3(dough, regex=_MIX_RE): # type: (AnyStr, Pattern) -> Optional[tuple[float, AnyStr, AnyStr]] mo = regex.match(dough) if mo: return float(mo.group(1)), mo.group(2), mo.group(3) else: return None _TOKEN = '_M2AUTH_' # type: str class AuthCookieJar(object): _keylen = 20 # type: int def __init__(self): # type: () -> None self._key = Rand.rand_bytes(self._keylen) def _hmac(self, key, data): # type: (bytes, str) -> str return util.bin_to_hex(m2.hmac(key, data.encode(), m2.sha1())) def makeCookie(self, expiry, data): # type: (float, str) -> AuthCookie """ Make a cookie :param expiry: expiration time (float in seconds) :param data: cookie content :return: AuthCookie object """ if not isinstance(expiry, (int, float)): raise ValueError('Expiration time must be number, not "%s' % expiry) dough = mix(expiry, data) return AuthCookie(expiry, data, dough, self._hmac(self._key, dough)) def isGoodCookie(self, cookie): # type: (AuthCookie) -> Union[bool, int] assert isinstance(cookie, AuthCookie) if cookie.isExpired(): return 0 c = self.makeCookie(cookie._expiry, cookie._data) return (c._expiry == cookie._expiry) \ and (c._data == cookie._data) \ and (c._mac == cookie._mac) \ and (c.output() == cookie.output()) def isGoodCookieString(self, cookie_str, _debug=False): # type: (Union[dict, bytes], bool) -> Union[bool, int] c = SimpleCookie() c.load(cookie_str) if _TOKEN not in c: log.debug('_TOKEN not in c (keys = %s)', dir(c)) return 0 undough = unmix3(c[_TOKEN].value) if undough is None: log.debug('undough is None') return 0 exp, data, mac = undough c2 = self.makeCookie(exp, data) if _debug and (c2._mac == mac): log.error('cookie_str = %s', cookie_str) log.error('c2.isExpired = %s', c2.isExpired()) log.error('mac = %s', mac) log.error('c2._mac = %s', c2._mac) log.error('c2._mac == mac: %s', str(c2._mac == mac)) return (not c2.isExpired()) and (c2._mac == mac) class AuthCookie(object): def __init__(self, expiry, data, dough, mac): # type: (float, str, str, str) -> None """ Create new authentication cookie :param expiry: expiration time (in seconds) :param data: cookie payload (as a string) :param dough: expiry & data concatenated to URL compliant string :param mac: SHA1-based HMAC of dough and random key """ self._expiry = expiry self._data = data self._mac = mac self._cookie = SimpleCookie() self._cookie[_TOKEN] = '%s%s' % (dough, mac) self._name = '%s%s' % (dough, mac) # WebKit only. def expiry(self): # type: () -> float """Return the cookie's expiry time.""" return self._expiry def data(self): # type: () -> str """Return the data portion of the cookie.""" return self._data def mac(self): # type: () -> str """Return the cookie's MAC.""" return self._mac def output(self, header="Set-Cookie:"): # type: (Optional[str]) -> str """Return the cookie's output in "Set-Cookie" format.""" return self._cookie.output(header=header) def value(self): # type: () -> str """Return the cookie's output minus the "Set-Cookie: " portion. """ return self._cookie[_TOKEN].value def isExpired(self): # type: () -> bool """Return 1 if the cookie has expired, 0 otherwise.""" return isinstance(self._expiry, (float, int)) and \ (time.time() > self._expiry) # Following two methods are for WebKit only. # I may wish to push them to WKAuthCookie, but they are part # of the API now. Oh well. def name(self): # type: () -> str return self._name def headerValue(self): # type: () -> str return self.value() m2crypto-0.42.0/src/M2Crypto/BIO.py000066400000000000000000000254571465575656700166540ustar00rootroot00000000000000from __future__ import absolute_import """M2Crypto wrapper for OpenSSL BIO API. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" import io import logging from typing import Any, AnyStr, Callable, Iterable, Optional, Union # noqa from M2Crypto import m2 log = logging.getLogger('BIO') class BIOError(ValueError): pass m2.bio_init(BIOError) class BIO(object): """Abstract object interface to the BIO API.""" m2_bio_free = m2.bio_free def __init__(self, bio=None, _pyfree=0, _close_cb=None): # type: (Optional[BIO], int, Optional[Callable]) -> None self.bio = bio self._pyfree = _pyfree self._close_cb = _close_cb self.closed = 0 self.write_closed = 0 def __del__(self): if self._pyfree: self.m2_bio_free(self.bio) def _ptr(self): return self.bio # Deprecated. bio_ptr = _ptr def fileno(self): # type: () -> int return m2.bio_get_fd(self.bio) def readable(self): # type: () -> bool return not self.closed def read(self, size=None): # type: (Optional[int]) -> Union[bytes, bytearray] if not self.readable(): raise IOError('cannot read') if size is None: buf = bytearray() while 1: data = m2.bio_read(self.bio, 4096) if not data: break buf += data return buf elif size == 0: return b'' elif size < 0: raise ValueError('read count is negative') else: return bytes(m2.bio_read(self.bio, size)) def readline(self, size=4096): # type: (int) -> bytes if not self.readable(): raise IOError('cannot read') buf = m2.bio_gets(self.bio, size) return '' if buf is None else buf def readlines(self, sizehint='ignored'): # type: (Union[AnyStr, int]) -> Iterable[bytes] if not self.readable(): raise IOError('cannot read') lines = [] while 1: buf = m2.bio_gets(self.bio, 4096) if buf is None: break lines.append(buf) return lines def writeable(self): # type: () -> bool return (not self.closed) and (not self.write_closed) def write(self, data): # type: (AnyStr) -> int """Write data to BIO. :return: either data written, or [0, -1] for nothing written, -2 not implemented """ if not self.writeable(): raise IOError('cannot write') if isinstance(data, str): data = data.encode('utf8') return m2.bio_write(self.bio, data) def write_close(self): # type: () -> None self.write_closed = 1 def flush(self): # type: () -> None """Flush the buffers. :return: 1 for success, and 0 or -1 for failure """ m2.bio_flush(self.bio) def reset(self): # type: () -> int """Set the bio to its initial state. :return: 1 for success, and 0 or -1 for failure """ return m2.bio_reset(self.bio) def close(self): # type: () -> None self.closed = 1 if self._close_cb: self._close_cb() def should_retry(self): # type: () -> int """ Can the call be attempted again, or was there an error ie do_handshake """ return m2.bio_should_retry(self.bio) def should_read(self): # type: () -> int """Should we read more data?""" return m2.bio_should_read(self.bio) def should_write(self): # type: () -> int """Should we write more data?""" return m2.bio_should_write(self.bio) def tell(self): """Return the current offset.""" return m2.bio_tell(self.bio) def seek(self, off): """Seek to the specified absolute offset.""" return m2.bio_seek(self.bio, off) def __enter__(self): return self def __exit__(self, *args): # type: (*Any) -> int self.close() class MemoryBuffer(BIO): """Object interface to BIO_s_mem. Empirical testing suggests that this class performs less well than cStringIO, because cStringIO is implemented in C, whereas this class is implemented in Python. Thus, the recommended practice is to use cStringIO for regular work and convert said cStringIO object to a MemoryBuffer object only when necessary. """ def __init__(self, data=None): # type: (Optional[bytes]) -> None super(MemoryBuffer, self).__init__(self) if data is not None and not isinstance(data, bytes): raise TypeError( "data must be bytes or None, not %s" % (type(data).__name__, )) self.bio = m2.bio_new(m2.bio_s_mem()) self._pyfree = 1 if data is not None: m2.bio_write(self.bio, data) def __len__(self): # type: () -> int return m2.bio_ctrl_pending(self.bio) def read(self, size=0): # type: (int) -> bytes m2.err_clear_error(); if not self.readable(): raise IOError('cannot read') if size: return m2.bio_read(self.bio, size) else: return m2.bio_read(self.bio, m2.bio_ctrl_pending(self.bio)) # Backwards-compatibility. getvalue = read_all = read def write_close(self): # type: () -> None super(MemoryBuffer, self).write_close() m2.bio_set_mem_eof_return(self.bio, 0) close = write_close class File(BIO): """Object interface to BIO_s_pyfd. This class interfaces Python to OpenSSL functions that expect BIO. For general file manipulation in Python, use Python's builtin file object. """ def __init__(self, pyfile, close_pyfile=1, mode='rb'): # type: (Union[io.BytesIO, AnyStr], int, AnyStr) -> None super(File, self).__init__(self, _pyfree=1) if isinstance(pyfile, str): pyfile = open(pyfile, mode) # This is for downward compatibility, but I don't think, that it is # good practice to have two handles for the same file. Whats about # concurrent write access? Last write, last wins? Especially since Py3 # has its own buffer management. See: # # https://docs.python.org/3.3/c-api/file.html # pyfile.flush() self.fname = pyfile.name self.pyfile = pyfile # Be wary of https://github.com/openssl/openssl/pull/1925 # BIO_new_fd is NEVER to be used before OpenSSL 1.1.1 if hasattr(m2, "bio_new_pyfd"): self.bio = m2.bio_new_pyfd(pyfile.fileno(), m2.bio_noclose) else: self.bio = m2.bio_new_pyfile(pyfile, m2.bio_noclose) self.close_pyfile = close_pyfile self.closed = False def flush(self): # type: () -> None super(File, self).flush() self.pyfile.flush() def close(self): # type: () -> None self.flush() super(File, self).close() if self.close_pyfile: self.pyfile.close() def reset(self): # type: () -> int """Set the bio to its initial state. :return: 0 for success, and -1 for failure """ return super(File, self).reset() def openfile(filename, mode='rb'): # type: (AnyStr, AnyStr) -> File try: f = open(filename, mode) except IOError as ex: raise BIOError(ex.args) return File(f) class IOBuffer(BIO): """Object interface to BIO_f_buffer. Its principal function is to be BIO_push()'ed on top of a BIO_f_ssl, so that makefile() of said underlying SSL socket works. """ m2_bio_pop = m2.bio_pop m2_bio_free = m2.bio_free def __init__(self, under_bio, mode='rwb', _pyfree=1): # type: (BIO, str, int) -> None super(IOBuffer, self).__init__(self, _pyfree=_pyfree) self.io = m2.bio_new(m2.bio_f_buffer()) self.bio = m2.bio_push(self.io, under_bio._ptr()) # This reference keeps the underlying BIO alive while we're not closed. self._under_bio = under_bio if 'w' in mode: self.write_closed = 0 else: self.write_closed = 1 def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_bio_pop(self.bio) self.m2_bio_free(self.io) def close(self): # type: () -> None BIO.close(self) class CipherStream(BIO): """Object interface to BIO_f_cipher.""" SALT_LEN = m2.PKCS5_SALT_LEN m2_bio_pop = m2.bio_pop m2_bio_free = m2.bio_free def __init__(self, obio): # type: (BIO) -> None super(CipherStream, self).__init__(self, _pyfree=1) self.obio = obio self.bio = m2.bio_new(m2.bio_f_cipher()) self.closed = 0 def __del__(self): # type: () -> None if not getattr(self, 'closed', 1): self.close() def close(self): # type: () -> None self.m2_bio_pop(self.bio) self.m2_bio_free(self.bio) self.closed = 1 def write_close(self): # type: () -> None self.obio.write_close() def set_cipher(self, algo, key, iv, op): # type: (str, AnyStr, AnyStr, int) -> None cipher = getattr(m2, algo, None) if cipher is None: raise ValueError('unknown cipher', algo) else: if not isinstance(key, bytes): key = key.encode('utf8') if not isinstance(iv, bytes): iv = iv.encode('utf8') try: m2.bio_set_cipher(self.bio, cipher(), key, iv, int(op)) except (OSError, ValueError) as ex: raise BIOError("BIOError: {}".format(str(ex))) m2.bio_push(self.bio, self.obio._ptr()) class SSLBio(BIO): """Object interface to BIO_f_ssl.""" def __init__(self, _pyfree=1): # type: (int) -> None super(SSLBio, self).__init__(self, _pyfree=_pyfree) self.bio = m2.bio_new(m2.bio_f_ssl()) self.closed = 0 def set_ssl(self, conn, close_flag=m2.bio_noclose): # type: (Any, int) -> None # conn should actually be SSL.Connection, but we cannot import # it here without getting into some serious circular dependency # business. """ Sets the bio to the SSL pointer which is contained in the connection object. """ self._pyfree = 0 m2.bio_set_ssl(self.bio, conn.ssl, close_flag) if close_flag == m2.bio_noclose: conn.set_ssl_close_flag(m2.bio_close) def do_handshake(self): # type: () -> int """Do the handshake. Return 1 if the handshake completes Return 0 or a negative number if there is a problem """ return m2.bio_do_handshake(self.bio) m2crypto-0.42.0/src/M2Crypto/BN.py000066400000000000000000000031471465575656700165320ustar00rootroot00000000000000from __future__ import absolute_import """ M2Crypto wrapper for OpenSSL BN (BIGNUM) API. Copyright (c) 2005 Open Source Applications Foundation. All rights reserved. """ from M2Crypto import m2 from typing import Optional # noqa def rand(bits, top=-1, bottom=0): # type: (int, int, int) -> Optional[int] """ Generate cryptographically strong random number. :param bits: Length of random number in bits. :param top: If -1, the most significant bit can be 0. If 0, the most significant bit is 1, and if 1, the two most significant bits will be 1. :param bottom: If bottom is true, the number will be odd. """ return m2.bn_rand(bits, top, bottom) def rand_range(range): # type: (int) -> int """ Generate a random number in a range. :param range: Upper limit for range. :return: A random number in the range [0, range) """ return m2.bn_rand_range(range) def randfname(length): # type: (int) -> str """ Return a random filename, which is simply a string where all the characters are from the set [a-zA-Z0-9]. :param length: Length of filename to return. :return: random filename string """ import warnings warnings.warn( "Don't use BN.randfname(), use tempfile methods instead.", DeprecationWarning, stacklevel=2) letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890' lettersLen = len(letters) fname = [] # type: list for x in range(length): fname += [letters[m2.bn_rand_range(lettersLen)]] return ''.join(fname) m2crypto-0.42.0/src/M2Crypto/DH.py000066400000000000000000000055611465575656700165300ustar00rootroot00000000000000from __future__ import absolute_import """M2Crypto wrapper for OpenSSL DH API. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from M2Crypto import BIO, m2 from M2Crypto.util import genparam_callback from typing import AnyStr, Callable, Optional # noqa class DHError(Exception): pass m2.dh_init(DHError) class DH(object): """Object interface to the Diffie-Hellman key exchange protocol. """ m2_dh_free = m2.dh_free def __init__(self, dh, _pyfree=0): # type: (bytes, int) -> None assert m2.dh_type_check(dh) self.dh = dh self._pyfree = _pyfree def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_dh_free(self.dh) def __len__(self): # type: () -> int assert m2.dh_type_check(self.dh), "'dh' type error" return int(m2.dh_size(self.dh)) def __getattr__(self, name): # type: (str) -> bytes if name in ('p', 'g', 'pub', 'priv'): method = getattr(m2, 'dh_get_%s' % (name,)) assert m2.dh_type_check(self.dh), "'dh' type error" return method(self.dh) else: raise AttributeError def __setattr__(self, name, value): # type: (str, bytes) -> bytes if name in ('p', 'g'): raise DHError('set (p, g) via set_params()') elif name in ('pub', 'priv'): raise DHError('generate (pub, priv) via gen_key()') else: self.__dict__[name] = value def _ptr(self): return self.dh def check_params(self): # type: () -> int assert m2.dh_type_check(self.dh), "'dh' type error" return m2.dh_check(self.dh) def gen_key(self): # type: () -> None assert m2.dh_type_check(self.dh), "'dh' type error" m2.dh_generate_key(self.dh) def compute_key(self, pubkey): # type: (bytes) -> bytes assert m2.dh_type_check(self.dh), "'dh' type error" return m2.dh_compute_key(self.dh, pubkey) def print_params(self, bio): # type: (BIO.BIO) -> int assert m2.dh_type_check(self.dh), "'dh' type error" return m2.dhparams_print(bio._ptr(), self.dh) def gen_params(plen, g, callback=genparam_callback): # type: (int, int, Optional[Callable]) -> DH dh_parms = m2.dh_generate_parameters(plen, g, callback) dh_obj = DH(dh_parms, 1) return dh_obj def load_params(file): # type: (AnyStr) -> DH with BIO.openfile(file) as bio: return load_params_bio(bio) def load_params_bio(bio): # type: (BIO.BIO) -> DH return DH(m2.dh_read_parameters(bio._ptr()), 1) def set_params(p, g): # type: (bytes, bytes) -> DH dh = m2.dh_new() m2.dh_set_pg(dh, p, g) return DH(dh, 1) # def free_params(cptr): # m2.dh_free(cptr) DH_GENERATOR_2 = m2.DH_GENERATOR_2 DH_GENERATOR_5 = m2.DH_GENERATOR_5 m2crypto-0.42.0/src/M2Crypto/DSA.py000066400000000000000000000337231465575656700166450ustar00rootroot00000000000000from __future__ import absolute_import, print_function """ M2Crypto wrapper for OpenSSL DSA API. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2004 OSAF. All Rights Reserved. """ from M2Crypto import BIO, m2, util from typing import Any, AnyStr, Callable, Tuple # noqa class DSAError(Exception): pass m2.dsa_init(DSAError) class DSA(object): """ This class is a context supporting DSA key and parameter values, signing and verifying. Simple example:: from M2Crypto import EVP, DSA, util message = 'Kilroy was here!' md = EVP.MessageDigest('sha1') md.update(message) digest = md.final() dsa = DSA.gen_params(1024) dsa.gen_key() r, s = dsa.sign(digest) good = dsa.verify(digest, r, s) if good: print(' ** success **') else: print(' ** verification failed **') """ m2_dsa_free = m2.dsa_free def __init__(self, dsa, _pyfree=0): # type: (bytes, int) -> None """ Use one of the factory functions to create an instance. :param dsa: binary representation of OpenSSL DSA type """ assert m2.dsa_type_check(dsa), "'dsa' type error" self.dsa = dsa self._pyfree = _pyfree def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_dsa_free(self.dsa) def __len__(self): # type: () -> int """ Return the key length. :return: the DSA key length in bits """ assert m2.dsa_type_check(self.dsa), "'dsa' type error" return m2.dsa_keylen(self.dsa) def __getattr__(self, name): # type: (str) -> bytes """ Return specified DSA parameters and key values. :param name: name of variable to be returned. Must be one of 'p', 'q', 'g', 'pub', 'priv'. :return: value of specified variable (a "byte string") """ if name in ['p', 'q', 'g', 'pub', 'priv']: method = getattr(m2, 'dsa_get_%s' % (name,)) assert m2.dsa_type_check(self.dsa), "'dsa' type error" return method(self.dsa) else: raise AttributeError def __setattr__(self, name, value): # type: (str, bytes) -> None if name in ['p', 'q', 'g']: raise DSAError('set (p, q, g) via set_params()') elif name in ['pub', 'priv']: raise DSAError('generate (pub, priv) via gen_key()') else: self.__dict__[name] = value def set_params(self, p, q, g): # type: (bytes, bytes, bytes) -> None """ Set new parameters. :param p: MPI binary representation ... format that consists of the number's length in bytes represented as a 4-byte big-endian number, and the number itself in big-endian format, where the most significant bit signals a negative number (the representation of numbers with the MSB set is prefixed with null byte). :param q: ditto :param g: ditto @warning: This does not change the private key, so it may be unsafe to use this method. It is better to use gen_params function to create a new DSA object. """ m2.dsa_set_pqg(self.dsa, p, q, g) def gen_key(self): # type: () -> None """ Generate a key pair. """ assert m2.dsa_type_check(self.dsa), "'dsa' type error" m2.dsa_gen_key(self.dsa) def save_params(self, filename): # type: (AnyStr) -> int """ Save the DSA parameters to a file. :param filename: Save the DSA parameters to this file. :return: 1 (true) if successful """ with BIO.openfile(filename, 'wb') as bio: ret = m2.dsa_write_params_bio(self.dsa, bio._ptr()) return ret def save_params_bio(self, bio): # type: (BIO.BIO) -> int """ Save DSA parameters to a BIO object. :param bio: Save DSA parameters to this object. :return: 1 (true) if successful """ return m2.dsa_write_params_bio(self.dsa, bio._ptr()) def save_key(self, filename, cipher='aes_128_cbc', callback=util.passphrase_callback): # type: (AnyStr, str, Callable) -> int """ Save the DSA key pair to a file. :param filename: Save the DSA key pair to this file. :param cipher: name of symmetric key algorithm and mode to encrypt the private key. :return: 1 (true) if successful """ with BIO.openfile(filename, 'wb') as bio: ret = self.save_key_bio(bio, cipher, callback) return ret def save_key_bio(self, bio, cipher='aes_128_cbc', callback=util.passphrase_callback): # type: (BIO.BIO, str, Callable) -> int """ Save DSA key pair to a BIO object. :param bio: Save DSA parameters to this object. :param cipher: name of symmetric key algorithm and mode to encrypt the private key. :return: 1 (true) if successful """ if cipher is None: return m2.dsa_write_key_bio_no_cipher(self.dsa, bio._ptr(), callback) else: ciph = getattr(m2, cipher, None) if ciph is None: raise DSAError('no such cipher: %s' % cipher) else: ciph = ciph() return m2.dsa_write_key_bio(self.dsa, bio._ptr(), ciph, callback) def save_pub_key(self, filename): # type: (AnyStr) -> int """ Save the DSA public key (with parameters) to a file. :param filename: Save DSA public key (with parameters) to this file. :return: 1 (true) if successful """ with BIO.openfile(filename, 'wb') as bio: ret = self.save_pub_key_bio(bio) return ret def save_pub_key_bio(self, bio): # type: (BIO.BIO) -> int """ Save DSA public key (with parameters) to a BIO object. :param bio: Save DSA public key (with parameters) to this object. :return: 1 (true) if successful """ return m2.dsa_write_pub_key_bio(self.dsa, bio._ptr()) def sign(self, digest): # type: (bytes) -> Tuple[bytes, bytes] """ Sign the digest. :param digest: SHA-1 hash of message (same as output from MessageDigest, a "byte string") :return: DSA signature, a tuple of two values, r and s, both "byte strings". """ assert self.check_key(), 'key is not initialised' return m2.dsa_sign(self.dsa, digest) def verify(self, digest, r, s): # type: (bytes, bytes, bytes) -> int """ Verify a newly calculated digest against the signature values r and s. :param digest: SHA-1 hash of message (same as output from MessageDigest, a "byte string") :param r: r value of the signature, a "byte string" :param s: s value of the signature, a "byte string" :return: 1 (true) if verify succeeded, 0 if failed """ assert self.check_key(), 'key is not initialised' return m2.dsa_verify(self.dsa, digest, r, s) def sign_asn1(self, digest): assert self.check_key(), 'key is not initialised' return m2.dsa_sign_asn1(self.dsa, digest) def verify_asn1(self, digest, blob): assert self.check_key(), 'key is not initialised' return m2.dsa_verify_asn1(self.dsa, digest, blob) def check_key(self): """ Check to be sure the DSA object has a valid private key. :return: 1 (true) if a valid private key """ assert m2.dsa_type_check(self.dsa), "'dsa' type error" return m2.dsa_check_key(self.dsa) class DSA_pub(DSA): """ This class is a DSA context that only supports a public key and verification. It does NOT support a private key or signing. """ def sign(self, *argv): # type: (*Any) -> None raise DSAError('DSA_pub object has no private key') sign_asn1 = sign def check_key(self): # type: () -> int """ :return: does DSA_pub contain a pub key? """ return m2.dsa_check_pub_key(self.dsa) save_key = DSA.save_pub_key save_key_bio = DSA.save_pub_key_bio # -------------------------------------------------------------- # factories and other functions def gen_params(bits, callback=util.genparam_callback): # type: (int, Callable) -> DSA """ Factory function that generates DSA parameters and instantiates a DSA object from the output. :param bits: The length of the prime to be generated. If 'bits' < 512, it is set to 512. :param callback: A Python callback object that will be invoked during parameter generation; it usual purpose is to provide visual feedback. :return: instance of DSA. """ dsa = m2.dsa_generate_parameters(bits, callback) return DSA(dsa, 1) def set_params(p, q, g): # type: (bytes, bytes, bytes) -> DSA """ Factory function that instantiates a DSA object with DSA parameters. :param p: value of p, a "byte string" :param q: value of q, a "byte string" :param g: value of g, a "byte string" :return: instance of DSA. """ dsa = m2.dsa_new() m2.dsa_set_pqg(dsa, p, q, g) return DSA(dsa, 1) def load_params(file, callback=util.passphrase_callback): # type: (AnyStr, Callable) -> DSA """ Factory function that instantiates a DSA object with DSA parameters from a file. :param file: Names the file (a path) that contains the PEM representation of the DSA parameters. :param callback: A Python callback object that will be invoked if the DSA parameters file is passphrase-protected. :return: instance of DSA. """ with BIO.openfile(file) as bio: ret = load_params_bio(bio, callback) return ret def load_params_bio(bio, callback=util.passphrase_callback): # type: (BIO.BIO, Callable) -> DSA """ Factory function that instantiates a DSA object with DSA parameters from a M2Crypto.BIO object. :param bio: Contains the PEM representation of the DSA parameters. :param callback: A Python callback object that will be invoked if the DSA parameters file is passphrase-protected. :return: instance of DSA. """ dsa = m2.dsa_read_params(bio._ptr(), callback) return DSA(dsa, 1) def load_key(file, callback=util.passphrase_callback): # type: (AnyStr, Callable) -> DSA """ Factory function that instantiates a DSA object from a PEM encoded DSA key pair. :param file: Names the file (a path) that contains the PEM representation of the DSA key pair. :param callback: A Python callback object that will be invoked if the DSA key pair is passphrase-protected. :return: instance of DSA. """ with BIO.openfile(file) as bio: ret = load_key_bio(bio, callback) return ret def load_key_bio(bio, callback=util.passphrase_callback): # type: (BIO.BIO, Callable) -> DSA """ Factory function that instantiates a DSA object from a PEM encoded DSA key pair. :param bio: Contains the PEM representation of the DSA key pair. :param callback: A Python callback object that will be invoked if the DSA key pair is passphrase-protected. :return: instance of DSA. """ dsa = m2.dsa_read_key(bio._ptr(), callback) return DSA(dsa, 1) def pub_key_from_params(p, q, g, pub): # type: (bytes, bytes, bytes, bytes) -> DSA_pub """ Factory function that instantiates a DSA_pub object using the parameters and public key specified. :param p: value of p :param q: value of q :param g: value of g :param pub: value of the public key :return: instance of DSA_pub. """ dsa = m2.dsa_new() m2.dsa_set_pqg(dsa, p, q, g) m2.dsa_set_pub(dsa, pub) return DSA_pub(dsa, 1) def load_pub_key(file, callback=util.passphrase_callback): # type: (AnyStr, Callable) -> DSA_pub """ Factory function that instantiates a DSA_pub object using a DSA public key contained in PEM file. The PEM file must contain the parameters in addition to the public key. :param file: Names the file (a path) that contains the PEM representation of the DSA public key. :param callback: A Python callback object that will be invoked should the DSA public key be passphrase-protected. :return: instance of DSA_pub. """ with BIO.openfile(file) as bio: ret = load_pub_key_bio(bio, callback) return ret def load_pub_key_bio(bio, callback=util.passphrase_callback): # type: (BIO.BIO, Callable) -> DSA_pub """ Factory function that instantiates a DSA_pub object using a DSA public key contained in PEM format. The PEM must contain the parameters in addition to the public key. :param bio: Contains the PEM representation of the DSA public key (with params). :param callback: A Python callback object that will be invoked should the DSA public key be passphrase-protected. :return: instance of DSA_pub. """ dsapub = m2.dsa_read_pub_key(bio._ptr(), callback) return DSA_pub(dsapub, 1) m2crypto-0.42.0/src/M2Crypto/EC.py000066400000000000000000000376361465575656700165340ustar00rootroot00000000000000from __future__ import absolute_import """ M2Crypto wrapper for OpenSSL ECDH/ECDSA API. @requires: OpenSSL 0.9.8 or newer Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All rights reserved.""" from M2Crypto import BIO, Err, m2, util from typing import AnyStr, Callable, Dict, Optional, Tuple, Union # noqa EC_Key = bytes class ECError(Exception): pass m2.ec_init(ECError) # Curve identifier constants NID_secp112r1 = m2.NID_secp112r1 # type: int NID_secp112r2 = m2.NID_secp112r2 # type: int NID_secp128r1 = m2.NID_secp128r1 # type: int NID_secp128r2 = m2.NID_secp128r2 # type: int NID_secp160k1 = m2.NID_secp160k1 # type: int NID_secp160r1 = m2.NID_secp160r1 # type: int NID_secp160r2 = m2.NID_secp160r2 # type: int NID_secp192k1 = m2.NID_secp192k1 # type: int NID_secp224k1 = m2.NID_secp224k1 # type: int NID_secp224r1 = m2.NID_secp224r1 # type: int NID_secp256k1 = m2.NID_secp256k1 # type: int NID_secp384r1 = m2.NID_secp384r1 # type: int NID_secp521r1 = m2.NID_secp521r1 # type: int NID_sect113r1 = m2.NID_sect113r1 # type: int NID_sect113r2 = m2.NID_sect113r2 # type: int NID_sect131r1 = m2.NID_sect131r1 # type: int NID_sect131r2 = m2.NID_sect131r2 # type: int NID_sect163k1 = m2.NID_sect163k1 # type: int NID_sect163r1 = m2.NID_sect163r1 # type: int NID_sect163r2 = m2.NID_sect163r2 # type: int NID_sect193r1 = m2.NID_sect193r1 # type: int NID_sect193r2 = m2.NID_sect193r2 # type: int # default for secg.org TLS test server NID_sect233k1 = m2.NID_sect233k1 # type: int NID_sect233r1 = m2.NID_sect233r1 # type: int NID_sect239k1 = m2.NID_sect239k1 # type: int NID_sect283k1 = m2.NID_sect283k1 # type: int NID_sect283r1 = m2.NID_sect283r1 # type: int NID_sect409k1 = m2.NID_sect409k1 # type: int NID_sect409r1 = m2.NID_sect409r1 # type: int NID_sect571k1 = m2.NID_sect571k1 # type: int NID_sect571r1 = m2.NID_sect571r1 # type: int NID_prime192v1 = m2.NID_X9_62_prime192v1 # type: int NID_prime192v2 = m2.NID_X9_62_prime192v2 # type: int NID_prime192v3 = m2.NID_X9_62_prime192v3 # type: int NID_prime239v1 = m2.NID_X9_62_prime239v1 # type: int NID_prime239v2 = m2.NID_X9_62_prime239v2 # type: int NID_prime239v3 = m2.NID_X9_62_prime239v3 # type: int NID_prime256v1 = m2.NID_X9_62_prime256v1 # type: int NID_c2pnb163v1 = m2.NID_X9_62_c2pnb163v1 # type: int NID_c2pnb163v2 = m2.NID_X9_62_c2pnb163v2 # type: int NID_c2pnb163v3 = m2.NID_X9_62_c2pnb163v3 # type: int NID_c2pnb176v1 = m2.NID_X9_62_c2pnb176v1 # type: int NID_c2tnb191v1 = m2.NID_X9_62_c2tnb191v1 # type: int NID_c2tnb191v2 = m2.NID_X9_62_c2tnb191v2 # type: int NID_c2tnb191v3 = m2.NID_X9_62_c2tnb191v3 # type: int NID_c2pnb208w1 = m2.NID_X9_62_c2pnb208w1 # type: int NID_c2tnb239v1 = m2.NID_X9_62_c2tnb239v1 # type: int NID_c2tnb239v2 = m2.NID_X9_62_c2tnb239v2 # type: int NID_c2tnb239v3 = m2.NID_X9_62_c2tnb239v3 # type: int NID_c2pnb272w1 = m2.NID_X9_62_c2pnb272w1 # type: int NID_c2pnb304w1 = m2.NID_X9_62_c2pnb304w1 # type: int NID_c2tnb359v1 = m2.NID_X9_62_c2tnb359v1 # type: int NID_c2pnb368w1 = m2.NID_X9_62_c2pnb368w1 # type: int NID_c2tnb431r1 = m2.NID_X9_62_c2tnb431r1 # type: int # To preserve compatibility with older names NID_X9_62_prime192v1 = NID_prime192v1 # type: int NID_X9_62_prime192v2 = NID_prime192v2 # type: int NID_X9_62_prime192v3 = NID_prime192v3 # type: int NID_X9_62_prime239v1 = NID_prime239v1 # type: int NID_X9_62_prime239v2 = NID_prime239v2 # type: int NID_X9_62_prime239v3 = NID_prime239v3 # type: int NID_X9_62_prime256v1 = NID_prime256v1 # type: int NID_X9_62_c2pnb163v1 = NID_c2pnb163v1 # type: int NID_X9_62_c2pnb163v2 = NID_c2pnb163v2 # type: int NID_X9_62_c2pnb163v3 = NID_c2pnb163v3 # type: int NID_X9_62_c2pnb176v1 = NID_c2pnb176v1 # type: int NID_X9_62_c2tnb191v1 = NID_c2tnb191v1 # type: int NID_X9_62_c2tnb191v2 = NID_c2tnb191v2 # type: int NID_X9_62_c2tnb191v3 = NID_c2tnb191v3 # type: int NID_X9_62_c2pnb208w1 = NID_c2pnb208w1 # type: int NID_X9_62_c2tnb239v1 = NID_c2tnb239v1 # type: int NID_X9_62_c2tnb239v2 = NID_c2tnb239v2 # type: int NID_X9_62_c2tnb239v3 = NID_c2tnb239v3 # type: int NID_X9_62_c2pnb272w1 = NID_c2pnb272w1 # type: int NID_X9_62_c2pnb304w1 = NID_c2pnb304w1 # type: int NID_X9_62_c2tnb359v1 = NID_c2tnb359v1 # type: int NID_X9_62_c2pnb368w1 = NID_c2pnb368w1 # type: int NID_X9_62_c2tnb431r1 = NID_c2tnb431r1 # type: int NID_wap_wsg_idm_ecid_wtls1 = m2.NID_wap_wsg_idm_ecid_wtls1 # type: int NID_wap_wsg_idm_ecid_wtls3 = m2.NID_wap_wsg_idm_ecid_wtls3 # type: int NID_wap_wsg_idm_ecid_wtls4 = m2.NID_wap_wsg_idm_ecid_wtls4 # type: int NID_wap_wsg_idm_ecid_wtls5 = m2.NID_wap_wsg_idm_ecid_wtls5 # type: int NID_wap_wsg_idm_ecid_wtls6 = m2.NID_wap_wsg_idm_ecid_wtls6 # type: int NID_wap_wsg_idm_ecid_wtls7 = m2.NID_wap_wsg_idm_ecid_wtls7 # type: int NID_wap_wsg_idm_ecid_wtls8 = m2.NID_wap_wsg_idm_ecid_wtls8 # type: int NID_wap_wsg_idm_ecid_wtls9 = m2.NID_wap_wsg_idm_ecid_wtls9 # type: int NID_wap_wsg_idm_ecid_wtls10 = m2.NID_wap_wsg_idm_ecid_wtls10 # type: int NID_wap_wsg_idm_ecid_wtls11 = m2.NID_wap_wsg_idm_ecid_wtls11 # type: int NID_wap_wsg_idm_ecid_wtls12 = m2.NID_wap_wsg_idm_ecid_wtls12 # type: int # The following two curves, according to OpenSSL, have a # "Questionable extension field!" and are not supported by # the OpenSSL inverse function. ECError: no inverse. # As such they cannot be used for signing. They might, # however, be usable for encryption but that has not # been tested. Until thir usefulness can be established, # they are not supported at this time. # NID_ipsec3 = m2.NID_ipsec3 # NID_ipsec4 = m2.NID_ipsec4 class EC(object): """ Object interface to a EC key pair. """ m2_ec_key_free = m2.ec_key_free def __init__(self, ec, _pyfree=0): # type: (EC, int) -> None assert m2.ec_key_type_check(ec), "'ec' type error" self.ec = ec self._pyfree = _pyfree def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_ec_key_free(self.ec) def __len__(self): # type: () -> int assert m2.ec_key_type_check(self.ec), "'ec' type error" return m2.ec_key_keylen(self.ec) def gen_key(self): # type: () -> int """ Generates the key pair from its parameters. Use:: keypair = EC.gen_params(curve) keypair.gen_key() to create an EC key pair. """ assert m2.ec_key_type_check(self.ec), "'ec' type error" m2.ec_key_gen_key(self.ec) def pub(self): # type: () -> EC_pub # Don't let python free return EC_pub(self.ec, 0) def sign_dsa(self, digest): # type: (bytes) -> Tuple[bytes, bytes] """ Sign the given digest using ECDSA. Returns a tuple (r,s), the two ECDSA signature parameters. """ assert self._check_key_type(), "'ec' type error" return m2.ecdsa_sign(self.ec, digest) def verify_dsa(self, digest, r, s): # type: (bytes, bytes, bytes) -> int """ Verify the given digest using ECDSA. r and s are the ECDSA signature parameters. """ assert self._check_key_type(), "'ec' type error" return m2.ecdsa_verify(self.ec, digest, r, s) def sign_dsa_asn1(self, digest): # type: (bytes) -> bytes assert self._check_key_type(), "'ec' type error" return m2.ecdsa_sign_asn1(self.ec, digest) def verify_dsa_asn1(self, digest, blob): assert self._check_key_type(), "'ec' type error" return m2.ecdsa_verify_asn1(self.ec, digest, blob) def compute_dh_key(self, pub_key): # type: (EC) -> Optional[bytes] """ Compute the ECDH shared key of this key pair and the given public key object. They must both use the same curve. Returns the shared key in binary as a buffer object. No Key Derivation Function is applied. """ assert self.check_key(), 'key is not initialised' return m2.ecdh_compute_key(self.ec, pub_key.ec) def save_key_bio(self, bio, cipher='aes_128_cbc', callback=util.passphrase_callback): # type: (BIO.BIO, Optional[str], Callable) -> int """ Save the key pair to an M2Crypto.BIO.BIO object in PEM format. :param bio: M2Crypto.BIO.BIO object to save key to. :param cipher: Symmetric cipher to protect the key. The default cipher is 'aes_128_cbc'. If cipher is None, then the key is saved in the clear. :param callback: A Python callable object that is invoked to acquire a passphrase with which to protect the key. The default is util.passphrase_callback. """ if cipher is None: return m2.ec_key_write_bio_no_cipher(self.ec, bio._ptr(), callback) else: ciph = getattr(m2, cipher, None) if ciph is None: raise ValueError('not such cipher %s' % cipher) return m2.ec_key_write_bio(self.ec, bio._ptr(), ciph(), callback) def save_key(self, file, cipher='aes_128_cbc', callback=util.passphrase_callback): # type: (AnyStr, Optional[str], Callable) -> int """ Save the key pair to a file in PEM format. :param file: Name of filename to save key to. :param cipher: Symmetric cipher to protect the key. The default cipher is 'aes_128_cbc'. If cipher is None, then the key is saved in the clear. :param callback: A Python callable object that is invoked to acquire a passphrase with which to protect the key. The default is util.passphrase_callback. """ with BIO.openfile(file, 'wb') as bio: return self.save_key_bio(bio, cipher, callback) def save_pub_key_bio(self, bio): # type: (BIO.BIO) -> int """ Save the public key to an M2Crypto.BIO.BIO object in PEM format. :param bio: M2Crypto.BIO.BIO object to save key to. """ return m2.ec_key_write_pubkey(self.ec, bio._ptr()) def save_pub_key(self, file): # type: (AnyStr) -> int """ Save the public key to a filename in PEM format. :param file: Name of filename to save key to. """ with BIO.openfile(file, 'wb') as bio: return m2.ec_key_write_pubkey(self.ec, bio._ptr()) def as_pem(self, cipher='aes_128_cbc', callback=util.passphrase_callback): """ Returns the key(pair) as a string in PEM format. If no password is passed and the cipher is set it exits with error """ with BIO.MemoryBuffer() as bio: self.save_key_bio(bio, cipher, callback) return bio.read() def _check_key_type(self): # type: () -> int return m2.ec_key_type_check(self.ec) def check_key(self): # type: () -> int assert m2.ec_key_type_check(self.ec), "'ec' type error" return m2.ec_key_check_key(self.ec) class EC_pub(EC): """ Object interface to an EC public key. ((don't like this implementation inheritance)) """ def __init__(self, ec, _pyfree=0): # type: (EC, int) -> None EC.__init__(self, ec, _pyfree) self.der = None # type: Optional[bytes] def get_der(self): # type: () -> bytes """ Returns the public key in DER format as a buffer object. """ assert self.check_key(), 'key is not initialised' if self.der is None: self.der = m2.ec_key_get_public_der(self.ec) return self.der def get_key(self): # type: () -> bytes """ Returns the public key as a byte string. """ assert self.check_key(), 'key is not initialised' return m2.ec_key_get_public_key(self.ec) def as_pem(self): """ Returns the key(pair) as a string in PEM format. If no password is passed and the cipher is set it exits with error """ with BIO.MemoryBuffer() as bio: self.save_key_bio(bio) return bio.read() save_key = EC.save_pub_key save_key_bio = EC.save_pub_key_bio def gen_params(curve): # type: (int) -> EC """ Factory function that generates EC parameters and instantiates a EC object from the output. :param curve: This is the OpenSSL nid of the curve to use. """ assert curve in [x['NID'] for x in m2.ec_get_builtin_curves()], \ 'Elliptic curve %s is not available on this system.' % \ m2.obj_nid2sn(curve) return EC(m2.ec_key_new_by_curve_name(curve), 1) def load_key(file, callback=util.passphrase_callback): # type: (AnyStr, Callable) -> EC """ Factory function that instantiates a EC object. :param file: Names the filename that contains the PEM representation of the EC key pair. :param callback: Python callback object that will be invoked if the EC key pair is passphrase-protected. """ with BIO.openfile(file) as bio: return load_key_bio(bio, callback) def load_key_string(string, callback=util.passphrase_callback): # type: (str, Callable) -> EC """ Load an EC key pair from a string. :param string: String containing EC key pair in PEM format. :param callback: A Python callable object that is invoked to acquire a passphrase with which to unlock the key. The default is util.passphrase_callback. :return: M2Crypto.EC.EC object. """ with BIO.MemoryBuffer(string) as bio: return load_key_bio(bio, callback) def load_key_bio(bio, callback=util.passphrase_callback): # type: (BIO.BIO, Callable) -> EC """ Factory function that instantiates a EC object. :param bio: M2Crypto.BIO object that contains the PEM representation of the EC key pair. :param callback: Python callback object that will be invoked if the EC key pair is passphrase-protected. """ return EC(m2.ec_key_read_bio(bio._ptr(), callback), 1) def load_pub_key(file): # type: (AnyStr) -> EC_pub """ Load an EC public key from filename. :param file: Name of filename containing EC public key in PEM format. :return: M2Crypto.EC.EC_pub object. """ with BIO.openfile(file) as bio: return load_pub_key_bio(bio) def load_key_string_pubkey(string, callback=util.passphrase_callback): # type: (str, Callable) -> EC.PKey """ Load an M2Crypto.EC.PKey from a public key as a string. :param string: String containing the key in PEM format. :param callback: A Python callable object that is invoked to acquire a passphrase with which to protect the key. :return: M2Crypto.EC.PKey object. """ from M2Crypto.EVP import load_key_bio_pubkey with BIO.MemoryBuffer(string) as bio: return load_key_bio_pubkey(bio, callback) def load_pub_key_bio(bio): # type: (BIO.BIO) -> EC_pub """ Load an EC public key from an M2Crypto.BIO.BIO object. :param bio: M2Crypto.BIO.BIO object containing EC public key in PEM format. :return: M2Crypto.EC.EC_pub object. """ ec = m2.ec_key_read_pubkey(bio._ptr()) if ec is None: ec_error() return EC_pub(ec, 1) def ec_error(): # type: () -> ECError raise ECError(Err.get_error_message()) def pub_key_from_der(der): # type: (bytes) -> EC_pub """ Create EC_pub from DER. """ return EC_pub(m2.ec_key_from_pubkey_der(der), 1) def pub_key_from_params(curve, bytes): # type: (bytes, bytes) -> EC_pub """ Create EC_pub from curve name and octet string. """ return EC_pub(m2.ec_key_from_pubkey_params(curve, bytes), 1) def get_builtin_curves(): # type: () -> Tuple[Dict[str, Union[int, str]]] return m2.ec_get_builtin_curves() m2crypto-0.42.0/src/M2Crypto/EVP.py000066400000000000000000000436151465575656700166710ustar00rootroot00000000000000from __future__ import absolute_import """M2Crypto wrapper for OpenSSL EVP API. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. Portions Copyright (c) 2004-2007 Open Source Applications Foundation. Author: Heikki Toivonen """ import logging from M2Crypto import BIO, Err, RSA, EC, m2, util from typing import AnyStr, Optional, Callable # noqa log = logging.getLogger('EVP') class EVPError(ValueError): pass m2.evp_init(EVPError) def pbkdf2(password, salt, iter, keylen): # type: (bytes, bytes, int, int) -> bytes """ Derive a key from password using PBKDF2 algorithm specified in RFC 2898. :param password: Derive the key from this password. :param salt: Salt. :param iter: Number of iterations to perform. :param keylen: Length of key to produce. :return: Key. """ return m2.pkcs5_pbkdf2_hmac_sha1(password, salt, iter, keylen) class MessageDigest(object): """ Message Digest """ m2_md_ctx_free = m2.md_ctx_free def __init__(self, algo): # type: (str) -> None md = getattr(m2, algo, None) # type: Optional[Callable] if md is None: # if the digest algorithm isn't found as an attribute of the m2 # module, try to look up the digest using get_digestbyname() self.md = m2.get_digestbyname(algo) else: self.md = md() self.ctx = m2.md_ctx_new() m2.digest_init(self.ctx, self.md) def __del__(self): # type: () -> None if getattr(self, 'ctx', None): self.m2_md_ctx_free(self.ctx) def update(self, data): # type: (bytes) -> int """ Add data to be digested. :return: -1 for Python error, 1 for success, 0 for OpenSSL failure. """ return m2.digest_update(self.ctx, data) def final(self): return m2.digest_final(self.ctx) # Deprecated. digest = final class HMAC(object): m2_hmac_ctx_free = m2.hmac_ctx_free def __init__(self, key, algo='sha1'): # type: (bytes, str) -> None md = getattr(m2, algo, None) if md is None: raise ValueError('unknown algorithm', algo) self.md = md() self.ctx = m2.hmac_ctx_new() m2.hmac_init(self.ctx, key, self.md) def __del__(self): # type: () -> None if getattr(self, 'ctx', None): self.m2_hmac_ctx_free(self.ctx) def reset(self, key): # type: (bytes) -> None m2.hmac_init(self.ctx, key, self.md) def update(self, data): # type: (bytes) -> None m2.hmac_update(self.ctx, data) def final(self): # type: () -> bytes return m2.hmac_final(self.ctx) digest = final def hmac(key, data, algo='sha1'): # type: (bytes, bytes, str) -> bytes md = getattr(m2, algo, None) if md is None: raise ValueError('unknown algorithm', algo) return m2.hmac(key, data, md()) class Cipher(object): m2_cipher_ctx_free = m2.cipher_ctx_free def __init__(self, alg, key, iv, op, key_as_bytes=0, d='md5', salt=b'12345678', i=1, padding=1): # type: (str, bytes, bytes, object, int, str, bytes, int, int) -> None cipher = getattr(m2, alg, None) if cipher is None: raise ValueError('unknown cipher', alg) self.cipher = cipher() if key_as_bytes: kmd = getattr(m2, d, None) if kmd is None: raise ValueError('unknown message digest', d) key = m2.bytes_to_key(self.cipher, kmd(), key, salt, iv, i) self.ctx = m2.cipher_ctx_new() m2.cipher_init(self.ctx, self.cipher, key, iv, op) self.set_padding(padding) del key def __del__(self): # type: () -> None if getattr(self, 'ctx', None): self.m2_cipher_ctx_free(self.ctx) def update(self, data): # type: (bytes) -> bytes return m2.cipher_update(self.ctx, data) def final(self): # type: () -> bytes return m2.cipher_final(self.ctx) def set_padding(self, padding=1): # type: (int) -> int """ Actually always return 1 """ return m2.cipher_set_padding(self.ctx, padding) class PKey(object): """ Object to hold diverse types of asymmetric keys (also known as "key pairs"). """ m2_pkey_free = m2.pkey_free m2_md_ctx_free = m2.md_ctx_free def __init__(self, pkey=None, _pyfree=0, md='sha1'): # type: (Optional[bytes], int, str) -> None if pkey is not None: self.pkey = pkey # type: bytes self._pyfree = _pyfree else: self.pkey = m2.pkey_new() self._pyfree = 1 self._set_context(md) def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_pkey_free(self.pkey) if getattr(self, 'ctx', None): self.m2_md_ctx_free(self.ctx) def _ptr(self): return self.pkey def _set_context(self, md): # type: (str) -> None if not md: self.md = None else: mda = getattr(m2, md, None) # type: Optional[Callable] if mda is None: raise ValueError('unknown message digest', md) self.md = mda() self.ctx = m2.md_ctx_new() ## type: Context def reset_context(self, md='sha1'): # type: (str) -> None """ Reset internal message digest context. :param md: The message digest algorithm. """ self._set_context(md) def sign_init(self): # type: () -> None """ Initialise signing operation with self. """ m2.sign_init(self.ctx, self.md) def sign_update(self, data): # type: (bytes) -> None """ Feed data to signing operation. :param data: Data to be signed. """ m2.sign_update(self.ctx, data) def sign_final(self): # type: () -> bytes """ Return signature. :return: The signature. """ return m2.sign_final(self.ctx, self.pkey) # Deprecated update = sign_update final = sign_final def verify_init(self): # type: () -> None """ Initialise signature verification operation with self. """ m2.verify_init(self.ctx, self.md) def verify_update(self, data): # type: (bytes) -> int """ Feed data to verification operation. :param data: Data to be verified. :return: -1 on Python error, 1 for success, 0 for OpenSSL error """ return m2.verify_update(self.ctx, data) def verify_final(self, sign): # type: (bytes) -> int """ Return result of verification. :param sign: Signature to use for verification :return: Result of verification: 1 for success, 0 for failure, -1 on other error. """ return m2.verify_final(self.ctx, sign, self.pkey) def digest_sign_init(self): # type: () -> None """ Initialise digest signing operation with self. """ if self.md is None: m2.digest_sign_init(self.ctx, self.pkey) else: m2.digest_sign_init(self.ctx, None, self.md, None, self.pkey) def digest_sign_update(self, data): # type: (bytes) -> None """ Feed data to digest signing operation. :param data: Data to be signed. """ m2.digest_sign_update(self.ctx, data) def digest_sign_final(self): # type: () -> bytes """ Return signature. :return: The signature. """ return m2.digest_sign_final(self.ctx) def digest_sign(self, data): # type: (bytes) -> bytes """ Return signature. :return: The signature. """ if m2.OPENSSL_VERSION_NUMBER < 0x10101000: raise NotImplemented('This method requires OpenSSL version ' + '1.1.1 or greater.') return m2.digest_sign(self.ctx, data) def digest_verify_init(self): # type: () -> None """ Initialise verification operation with self. """ if self.md is None: m2.digest_verify_init(self.ctx, self.pkey) else: m2.digest_verify_init(self.ctx, None, self.md, None, self.pkey) def digest_verify_update(self, data): # type: (bytes) -> int """ Feed data to verification operation. :param data: Data to be verified. :return: -1 on Python error, 1 for success, 0 for OpenSSL error """ return m2.digest_verify_update(self.ctx, data) def digest_verify_final(self, sign): # type: (bytes) -> int """ Feed data to digest verification operation. :param sign: Signature to use for verification :return: Result of verification: 1 for success, 0 for failure, -1 on other error. """ return m2.digest_verify_final(self.ctx, sign) def digest_verify(self, sign, data): # type: (bytes, bytes) -> int """ Return result of verification. :param sign: Signature to use for verification :param data: Data to be verified. :return: Result of verification: 1 for success, 0 for failure, -1 on other error. """ if m2.OPENSSL_VERSION_NUMBER < 0x10101000: raise NotImplemented('This method requires OpenSSL version ' + '1.1.1 or greater.') return m2.digest_verify(self.ctx, sign, data) def assign_rsa(self, rsa, capture=1): # type: (RSA.RSA, int) -> int """ Assign the RSA key pair to self. :param rsa: M2Crypto.RSA.RSA object to be assigned to self. :param capture: If true (default), this PKey object will own the RSA object, meaning that once the PKey object gets deleted it is no longer safe to use the RSA object. :return: Return 1 for success and 0 for failure. """ if capture: ret = m2.pkey_assign_rsa(self.pkey, rsa.rsa) if ret: rsa._pyfree = 0 else: ret = m2.pkey_set1_rsa(self.pkey, rsa.rsa) return ret def get_rsa(self): # type: () -> RSA.RSA_pub """ Return the underlying RSA key if that is what the EVP instance is holding. """ rsa_ptr = m2.pkey_get1_rsa(self.pkey) rsa = RSA.RSA_pub(rsa_ptr, 1) return rsa def assign_ec(self, ec, capture=1): # type: (EC.EC, int) -> int """ Assign the EC key pair to self. :param ec: M2Crypto.EC.EC object to be assigned to self. :param capture: If true (default), this PKey object will own the EC object, meaning that once the PKey object gets deleted it is no longer safe to use the EC object. :return: Return 1 for success and 0 for failure. """ if capture: ret = m2.pkey_assign_ec(self.pkey, ec.ec) if ret: ec._pyfree = 0 else: ret = m2.pkey_set1_ec(self.pkey, ec.ec) return ret def get_ec(self): # type: () -> EC.EC_pub """ Return the underlying EC key if that is what the EVP instance is holding. """ ec_ptr = m2.pkey_get1_ec(self.pkey) ec = EC.EC_pub(ec_ptr) return ec def save_key(self, file, cipher='aes_128_cbc', callback=util.passphrase_callback): # type: (AnyStr, Optional[str], Callable) -> int """ Save the key pair to a file in PEM format. :param file: Name of file to save key to. :param cipher: Symmetric cipher to protect the key. The default cipher is 'aes_128_cbc'. If cipher is None, then the key is saved in the clear. :param callback: A Python callable object that is invoked to acquire a passphrase with which to protect the key. The default is util.passphrase_callback. """ with BIO.openfile(file, 'wb') as bio: return self.save_key_bio(bio, cipher, callback) def save_key_bio(self, bio, cipher='aes_128_cbc', callback=util.passphrase_callback): # type: (BIO.BIO, Optional[str], Callable) -> int """ Save the key pair to the M2Crypto.BIO object 'bio' in PEM format. :param bio: M2Crypto.BIO object to save key to. :param cipher: Symmetric cipher to protect the key. The default cipher is 'aes_128_cbc'. If cipher is None, then the key is saved in the clear. :param callback: A Python callable object that is invoked to acquire a passphrase with which to protect the key. The default is util.passphrase_callback. """ if cipher is None: return m2.pkey_write_pem_no_cipher(self.pkey, bio._ptr(), callback) else: proto = getattr(m2, cipher, None) if proto is None: raise ValueError('no such cipher %s' % cipher) return m2.pkey_write_pem(self.pkey, bio._ptr(), proto(), callback) def as_pem(self, cipher='aes_128_cbc', callback=util.passphrase_callback): # type: (Optional[str], Callable) -> bytes """ Return key in PEM format in a string. :param cipher: Symmetric cipher to protect the key. The default cipher is ``'aes_128_cbc'``. If cipher is None, then the key is saved in the clear. :param callback: A Python callable object that is invoked to acquire a passphrase with which to protect the key. The default is util.passphrase_callback. """ bio = BIO.MemoryBuffer() self.save_key_bio(bio, cipher, callback) return bio.read_all() def as_der(self): # type: () -> bytes """ Return key in DER format in a string """ buf = m2.pkey_as_der(self.pkey) bio = BIO.MemoryBuffer(buf) return bio.read_all() def size(self): # type: () -> int """ Return the size of the key in bytes. """ return m2.pkey_size(self.pkey) def get_modulus(self): # type: () -> Optional[bytes] """ Return the modulus in hex format. """ return m2.pkey_get_modulus(self.pkey) def load_key(file, callback=util.passphrase_callback): # type: (AnyStr, Callable) -> PKey """ Load an M2Crypto.EVP.PKey from file. :param file: Name of file containing the key in PEM format. :param callback: A Python callable object that is invoked to acquire a passphrase with which to protect the key. :return: M2Crypto.EVP.PKey object. """ with BIO.openfile(file, 'r') as bio: cptr = m2.pkey_read_pem(bio.bio, callback) return PKey(cptr, 1) def load_key_pubkey(file, callback=util.passphrase_callback): # type: (AnyStr, Callable) -> PKey """ Load an M2Crypto.EVP.PKey from a public key as a file. :param file: Name of file containing the key in PEM format. :param callback: A Python callable object that is invoked to acquire a passphrase with which to protect the key. :return: M2Crypto.EVP.PKey object. """ with BIO.openfile(file, 'r') as bio: cptr = m2.pkey_read_pem_pubkey(bio._ptr(), callback) if cptr is None: raise EVPError(Err.get_error()) return PKey(cptr, 1) def load_key_bio(bio, callback=util.passphrase_callback): # type: (BIO.BIO, Callable) -> PKey """ Load an M2Crypto.EVP.PKey from an M2Crypto.BIO object. :param bio: M2Crypto.BIO object containing the key in PEM format. :param callback: A Python callable object that is invoked to acquire a passphrase with which to protect the key. :return: M2Crypto.EVP.PKey object. """ cptr = m2.pkey_read_pem(bio._ptr(), callback) return PKey(cptr, 1) def load_key_bio_pubkey(bio, callback=util.passphrase_callback): # type: (BIO.BIO, Callable) -> PKey """ Load an M2Crypto.EVP.PKey from a public key as a M2Crypto.BIO object. :param bio: M2Crypto.BIO object containing the key in PEM format. :param callback: A Python callable object that is invoked to acquire a passphrase with which to protect the key. :return: M2Crypto.EVP.PKey object. """ cptr = m2.pkey_read_pem_pubkey(bio._ptr(), callback) if cptr is None: raise EVPError(Err.get_error()) return PKey(cptr, 1) def load_key_string(string, callback=util.passphrase_callback): # type: (AnyStr, Callable) -> PKey """ Load an M2Crypto.EVP.PKey from a string. :param string: String containing the key in PEM format. :param callback: A Python callable object that is invoked to acquire a passphrase with which to protect the key. :return: M2Crypto.EVP.PKey object. """ bio = BIO.MemoryBuffer(string) return load_key_bio(bio, callback) def load_key_string_pubkey(string, callback=util.passphrase_callback): # type: (AnyStr, Callable) -> PKey """ Load an M2Crypto.EVP.PKey from a public key as a string. :param string: String containing the key in PEM format. :param callback: A Python callable object that is invoked to acquire a passphrase with which to protect the key. :return: M2Crypto.EVP.PKey object. """ bio = BIO.MemoryBuffer(string) return load_key_bio_pubkey(bio, callback) m2crypto-0.42.0/src/M2Crypto/Engine.py000066400000000000000000000110611465575656700174320ustar00rootroot00000000000000# vim: sts=4 sw=4 et from __future__ import absolute_import """ M2Crypto wrapper for OpenSSL ENGINE API. Pavel Shramov IMEC MSU """ from M2Crypto import EVP, Err, X509, m2 from typing import AnyStr, Callable, Optional # noqa class EngineError(Exception): pass m2.engine_init_error(EngineError) class Engine(object): """Wrapper for ENGINE object.""" m2_engine_free = m2.engine_free def __init__(self, id=None, _ptr=None, _pyfree=1): # type: (Optional[bytes], Optional[bytes], int) -> None """Create new Engine from ENGINE pointer or obtain by id""" if not _ptr and not id: raise ValueError("No engine id specified") self._ptr = _ptr if not self._ptr: self._ptr = m2.engine_by_id(id) if not self._ptr: raise ValueError("Unknown engine: %s" % id) self._pyfree = _pyfree def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_engine_free(self._ptr) def init(self): # type: () -> int """Obtain a functional reference to the engine. :return: 0 on error, non-zero on success.""" return m2.engine_init(self._ptr) def finish(self): # type: () -> int """Release a functional and structural reference to the engine.""" return m2.engine_finish(self._ptr) def ctrl_cmd_string(self, cmd, arg, optional=0): # type: (AnyStr, Optional[AnyStr], int) -> None """Call ENGINE_ctrl_cmd_string""" if isinstance(cmd, bytes): cmd = cmd.decode() if arg is not None and isinstance(arg, bytes): arg = arg.decode() if not m2.engine_ctrl_cmd_string(self._ptr, cmd, arg, optional): raise EngineError(Err.get_error()) def get_name(self): # type: () -> bytes """Return engine name""" return m2.engine_get_name(self._ptr) def get_id(self): # type: () -> bytes """Return engine id""" return m2.engine_get_id(self._ptr) def set_default(self, methods=m2.ENGINE_METHOD_ALL): # type: (int) -> int """ Use this engine as default for methods specified in argument :param methods: Possible values are bitwise OR of m2.ENGINE_METHOD_* """ return m2.engine_set_default(self._ptr, methods) def _engine_load_key(self, func, name, pin=None): # type: (Callable, bytes, Optional[bytes]) -> EVP.PKey """Helper function for loading keys""" ui = m2.ui_openssl() cbd = m2.engine_pkcs11_data_new(pin) try: kptr = func(self._ptr, name, ui, cbd) if not kptr: raise EngineError(Err.get_error()) key = EVP.PKey(kptr, _pyfree=1) finally: m2.engine_pkcs11_data_free(cbd) return key def load_private_key(self, name, pin=None): # type: (bytes, Optional[bytes]) -> X509.X509 """Load private key with engine methods (e.g from smartcard). If pin is not set it will be asked """ return self._engine_load_key(m2.engine_load_private_key, name, pin) def load_public_key(self, name, pin=None): # type: (bytes, Optional[bytes]) -> EVP.PKey """Load public key with engine methods (e.g from smartcard).""" return self._engine_load_key(m2.engine_load_public_key, name, pin) def load_certificate(self, name): # type: (bytes) -> X509.X509 """Load certificate from engine (e.g from smartcard). NOTE: This function may be not implemented by engine!""" cptr = m2.engine_load_certificate(self._ptr, name) if not cptr: raise EngineError("Certificate or card not found") return X509.X509(cptr, _pyfree=1) def load_dynamic_engine(id, sopath): # type: (bytes, AnyStr) -> Engine """Load and return dymanic engine from sopath and assign id to it""" if isinstance(sopath, str): sopath = sopath.encode('utf8') m2.engine_load_dynamic() e = Engine('dynamic') e.ctrl_cmd_string('SO_PATH', sopath) e.ctrl_cmd_string('ID', id) e.ctrl_cmd_string('LIST_ADD', '1') e.ctrl_cmd_string('LOAD', None) return e def load_dynamic(): # type: () -> None """Load dynamic engine""" m2.engine_load_dynamic() def load_openssl(): # type: () -> None """Load openssl engine""" m2.engine_load_openssl() def cleanup(): # type: () -> None """If you load any engines, you need to clean up after your application is finished with the engines.""" m2.engine_cleanup() m2crypto-0.42.0/src/M2Crypto/Err.py000066400000000000000000000034001465575656700167530ustar00rootroot00000000000000from __future__ import absolute_import """M2Crypto wrapper for OpenSSL Error API. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from M2Crypto import BIO, m2, util # noqa from typing import Optional # noqa def get_error(): # type: () -> Optional[str] err = BIO.MemoryBuffer() m2.err_print_errors(err.bio_ptr()) err_msg = err.read() if err_msg: return err_msg.decode() def get_error_code(): # type: () -> int return m2.err_get_error() def peek_error_code(): # type: () -> int return m2.err_peek_error() def get_error_lib(err): # type: (Optional[int]) -> str err_str = m2.err_lib_error_string(err) return err_str.decode() if err_str else '' def get_error_func(err): # type: (Optional[int]) -> str err_str = m2.err_func_error_string(err) return err_str if err_str else '' def get_error_reason(err): # type: (Optional[int]) -> str err_str = m2.err_reason_error_string(err) return err_str if err_str else '' def get_error_message(): # type: () -> str return get_error_reason(get_error_code()) def get_x509_verify_error(err): # type: (Optional[int]) -> str err_str = m2.x509_get_verify_error(err) return err_str if err_str else '' class SSLError(Exception): def __init__(self, err, client_addr): # type: (int, util.AddrType) -> None self.err = err self.client_addr = client_addr def __str__(self): # type: () -> str if not isinstance(self.client_addr, str): s = self.client_addr.decode() else: s = self.client_addr return "%s: %s: %s" % (get_error_func(self.err), s, get_error_reason(self.err)) class M2CryptoError(Exception): pass m2crypto-0.42.0/src/M2Crypto/RC4.py000066400000000000000000000016211465575656700166160ustar00rootroot00000000000000from __future__ import absolute_import """M2Crypto wrapper for OpenSSL RC4 API. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from typing import Optional from M2Crypto.m2 import rc4_free, rc4_new, rc4_set_key, rc4_update class RC4(object): """Object interface to the stream cipher RC4.""" rc4_free = rc4_free def __init__(self, key=None): # type: (Optional[bytes]) -> None self.cipher = rc4_new() if key: rc4_set_key(self.cipher, key) def __del__(self): # type: () -> None if getattr(self, 'cipher', None): self.rc4_free(self.cipher) def set_key(self, key): # type: (bytes) -> None rc4_set_key(self.cipher, key) def update(self, data): # type: (bytes) -> bytes return rc4_update(self.cipher, data) def final(self): # type: () -> str return '' m2crypto-0.42.0/src/M2Crypto/RSA.py000066400000000000000000000342221465575656700166560ustar00rootroot00000000000000from __future__ import absolute_import """M2Crypto wrapper for OpenSSL RSA API. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" import sys from M2Crypto import BIO, Err, m2, util from typing import Any, AnyStr, Callable, IO, Optional, Tuple # noqa class RSAError(Exception): pass m2.rsa_init(RSAError) no_padding = m2.no_padding pkcs1_padding = m2.pkcs1_padding if hasattr(m2, 'sslv23_padding'): sslv23_padding = m2.sslv23_padding pkcs1_oaep_padding = m2.pkcs1_oaep_padding class RSA(object): """ RSA Key Pair. """ m2_rsa_free = m2.rsa_free def __init__(self, rsa, _pyfree=0): # type: (bytes, int) -> None """ :param rsa: binary representation of OpenSSL RSA type """ assert m2.rsa_type_check(rsa), "'rsa' type error" self.rsa = rsa self._pyfree = _pyfree def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_rsa_free(self.rsa) def __len__(self): # type: () -> int return int(m2.rsa_size(self.rsa) << 3) def __getattr__(self, name): # type: (str) -> bytes if name == 'e': return m2.rsa_get_e(self.rsa) elif name == 'n': return m2.rsa_get_n(self.rsa) else: raise AttributeError def pub(self): # type: () -> Tuple[bytes, bytes] assert self.check_key(), 'key is not initialised' return m2.rsa_get_e(self.rsa), m2.rsa_get_n(self.rsa) def public_encrypt(self, data, padding): # type: (bytes, int) -> bytes assert self.check_key(), 'key is not initialised' return m2.rsa_public_encrypt(self.rsa, data, padding) def public_decrypt(self, data, padding): # type: (bytes, int) -> bytes assert self.check_key(), 'key is not initialised' return m2.rsa_public_decrypt(self.rsa, data, padding) def private_encrypt(self, data, padding): # type: (bytes, int) -> bytes assert self.check_key(), 'key is not initialised' return m2.rsa_private_encrypt(self.rsa, data, padding) def private_decrypt(self, data, padding): # type: (bytes, int) -> bytes assert self.check_key(), 'key is not initialised' return m2.rsa_private_decrypt(self.rsa, data, padding) def save_key_bio(self, bio, cipher='aes_128_cbc', callback=util.passphrase_callback): # type: (BIO.BIO, Optional[str], Callable) -> int """ Save the key pair to an M2Crypto.BIO.BIO object in PEM format. :param bio: M2Crypto.BIO.BIO object to save key to. :param cipher: Symmetric cipher to protect the key. The default cipher is 'aes_128_cbc'. If cipher is None, then the key is saved in the clear. :param callback: A Python callable object that is invoked to acquire a passphrase with which to protect the key. The default is util.passphrase_callback. """ if cipher is None: return m2.rsa_write_key_no_cipher(self.rsa, bio._ptr(), callback) else: ciph = getattr(m2, cipher, None) if ciph is None: raise RSAError('not such cipher %s' % cipher) else: ciph = ciph() return m2.rsa_write_key(self.rsa, bio._ptr(), ciph, callback) def save_key(self, file, cipher='aes_128_cbc', callback=util.passphrase_callback): # type: (AnyStr, Optional[str], Callable) -> int """ Save the key pair to a file in PEM format. :param file: Name of file to save key to. :param cipher: Symmetric cipher to protect the key. The default cipher is 'aes_128_cbc'. If cipher is None, then the key is saved in the clear. :param callback: A Python callable object that is invoked to acquire a passphrase with which to protect the key. The default is util.passphrase_callback. """ with BIO.openfile(file, 'wb') as bio: return self.save_key_bio(bio, cipher, callback) save_pem = save_key def as_pem(self, cipher='aes_128_cbc', callback=util.passphrase_callback): # type: (Optional[str], Callable) -> bytes """ Returns the key(pair) as a string in PEM format. """ bio = BIO.MemoryBuffer() self.save_key_bio(bio, cipher, callback) return bio.read() def save_key_der_bio(self, bio): # type: (BIO.BIO) -> int """ Save the key pair to an M2Crypto.BIO.BIO object in DER format. :param bio: M2Crypto.BIO.BIO object to save key to. """ return m2.rsa_write_key_der(self.rsa, bio._ptr()) def save_key_der(self, file): # type: (AnyStr) -> int """ Save the key pair to a file in DER format. :param file: Filename to save key to """ with BIO.openfile(file, 'wb') as bio: return self.save_key_der_bio(bio) def save_pub_key_bio(self, bio): # type: (BIO.BIO) -> int """ Save the public key to an M2Crypto.BIO.BIO object in PEM format. :param bio: M2Crypto.BIO.BIO object to save key to. """ return m2.rsa_write_pub_key(self.rsa, bio._ptr()) def save_pub_key(self, file): # type: (AnyStr) -> int """ Save the public key to a file in PEM format. :param file: Name of file to save key to. """ with BIO.openfile(file, 'wb') as bio: return m2.rsa_write_pub_key(self.rsa, bio._ptr()) def check_key(self): # type: () -> int """ Validate RSA keys. It checks that p and q are in fact prime, and that n = p*q. :return: returns 1 if rsa is a valid RSA key, and 0 otherwise. -1 is returned if an error occurs while checking the key. If the key is invalid or an error occurred, the reason code can be obtained using ERR_get_error(3). """ return m2.rsa_check_key(self.rsa) def sign_rsassa_pss(self, digest, algo='sha1', salt_length=20): # type: (bytes, str, int) -> bytes """ Signs a digest with the private key using RSASSA-PSS :param digest: A digest created by using the digest method :param salt_length: The length of the salt to use :param algo: The hash algorithm to use Legal values like 'sha1','sha224', 'sha256', 'ripemd160', and 'md5'. :return: a string which is the signature """ hash = getattr(m2, algo, None) if hash is None: raise RSAError('not such hash algorithm %s' % algo) signature = m2.rsa_padding_add_pkcs1_pss(self.rsa, digest, hash(), salt_length) return self.private_encrypt(signature, m2.no_padding) def verify_rsassa_pss(self, data, signature, algo='sha1', salt_length=20): # type: (bytes, bytes, str, int) -> int """ Verifies the signature RSASSA-PSS :param data: Data that has been signed :param signature: The signature signed with RSASSA-PSS :param salt_length: The length of the salt that was used :param algo: The hash algorithm to use Legal values are for example 'sha1','sha224', 'sha256', 'ripemd160', and 'md5'. :return: 1 or 0, depending on whether the signature was verified or not. """ hash = getattr(m2, algo, None) if hash is None: raise RSAError('not such hash algorithm %s' % algo) plain_signature = self.public_decrypt(signature, m2.no_padding) return m2.rsa_verify_pkcs1_pss(self.rsa, data, plain_signature, hash(), salt_length) def sign(self, digest, algo='sha1'): # type: (bytes, str) -> bytes """ Signs a digest with the private key :param digest: A digest created by using the digest method :param algo: The method that created the digest. Legal values like 'sha1','sha224', 'sha256', 'ripemd160', and 'md5'. :return: a string which is the signature """ digest_type = getattr(m2, 'NID_' + algo, None) if digest_type is None: raise ValueError('unknown algorithm', algo) return m2.rsa_sign(self.rsa, digest, digest_type) def verify(self, data, signature, algo='sha1'): # type: (bytes, bytes, str) -> int """ Verifies the signature with the public key :param data: Data that has been signed :param signature: The signature signed with the private key :param algo: The method use to create digest from the data before it was signed. Legal values like 'sha1','sha224', 'sha256', 'ripemd160', and 'md5'. :return: 1 or 0, depending on whether the signature was verified or not. """ digest_type = getattr(m2, 'NID_' + algo, None) if digest_type is None: raise ValueError('unknown algorithm', algo) return m2.rsa_verify(self.rsa, data, signature, digest_type) class RSA_pub(RSA): """ Object interface to an RSA public key. """ def __setattr__(self, name, value): # type: (str, bytes) -> None if name in ['e', 'n']: raise RSAError('use factory function new_pub_key() to set (e, n)') else: self.__dict__[name] = value def private_encrypt(self, *argv): # type: (*Any) -> None raise RSAError('RSA_pub object has no private key') def private_decrypt(self, *argv): # type: (*Any) -> None raise RSAError('RSA_pub object has no private key') def save_key(self, file, *args, **kw): # type: (AnyStr, *Any, **Any) -> int """ Save public key to file. """ return self.save_pub_key(file) def save_key_bio(self, bio, *args, **kw): # type: (BIO.BIO, *Any, **Any) -> int """ Save public key to BIO. """ return self.save_pub_key_bio(bio) # save_key_der # save_key_der_bio def check_key(self): # type: () -> int return m2.rsa_check_pub_key(self.rsa) def rsa_error(): # type: () -> None raise RSAError(Err.get_error_message()) def keygen_callback(p, n, out=sys.stdout): # type: (int, Any, IO[str]) -> None """ Default callback for gen_key(). """ ch = ['.', '+', '*', '\n'] out.write(ch[p]) out.flush() def gen_key(bits, e, callback=keygen_callback): # type: (int, int, Callable) -> RSA """ Generate an RSA key pair. :param bits: Key length, in bits. :param e: The RSA public exponent. :param callback: A Python callable object that is invoked during key generation; its usual purpose is to provide visual feedback. The default callback is keygen_callback. :return: M2Crypto.RSA.RSA object. """ return RSA(m2.rsa_generate_key(bits, e, callback), 1) def load_key(file, callback=util.passphrase_callback): # type: (AnyStr, Callable) -> RSA """ Load an RSA key pair from file. :param file: Name of file containing RSA public key in PEM format. :param callback: A Python callable object that is invoked to acquire a passphrase with which to unlock the key. The default is util.passphrase_callback. :return: M2Crypto.RSA.RSA object. """ with BIO.openfile(file) as bio: return load_key_bio(bio, callback) def load_key_bio(bio, callback=util.passphrase_callback): # type: (BIO.BIO, Callable) -> RSA """ Load an RSA key pair from an M2Crypto.BIO.BIO object. :param bio: M2Crypto.BIO.BIO object containing RSA key pair in PEM format. :param callback: A Python callable object that is invoked to acquire a passphrase with which to unlock the key. The default is util.passphrase_callback. :return: M2Crypto.RSA.RSA object. """ rsa = m2.rsa_read_key(bio._ptr(), callback) if rsa is None: rsa_error() return RSA(rsa, 1) def load_key_string(string, callback=util.passphrase_callback): # type: (AnyStr, Callable) -> RSA """ Load an RSA key pair from a string. :param string: String containing RSA key pair in PEM format. :param callback: A Python callable object that is invoked to acquire a passphrase with which to unlock the key. The default is util.passphrase_callback. :return: M2Crypto.RSA.RSA object. """ bio = BIO.MemoryBuffer(string) return load_key_bio(bio, callback) def load_pub_key(file): # type: (AnyStr) -> RSA_pub """ Load an RSA public key from file. :param file: Name of file containing RSA public key in PEM format. :return: M2Crypto.RSA.RSA_pub object. """ with BIO.openfile(file) as bio: return load_pub_key_bio(bio) def load_pub_key_bio(bio): # type: (BIO.BIO) -> RSA_pub """ Load an RSA public key from an M2Crypto.BIO.BIO object. :param bio: M2Crypto.BIO.BIO object containing RSA public key in PEM format. :return: M2Crypto.RSA.RSA_pub object. """ rsa = m2.rsa_read_pub_key(bio._ptr()) if rsa is None: rsa_error() return RSA_pub(rsa, 1) def new_pub_key(e_n): # type: (Tuple[bytes, bytes]) -> RSA_pub """ Instantiate an RSA_pub object from an (e, n) tuple. :param e: The RSA public exponent; it is a string in OpenSSL's MPINT format - 4-byte big-endian bit-count followed by the appropriate number of bits. :param n: The RSA composite of primes; it is a string in OpenSSL's MPINT format - 4-byte big-endian bit-count followed by the appropriate number of bits. :return: M2Crypto.RSA.RSA_pub object. """ (e, n) = e_n rsa = m2.rsa_new() m2.rsa_set_en(rsa, e, n) return RSA_pub(rsa, 1) m2crypto-0.42.0/src/M2Crypto/Rand.py000066400000000000000000000106161465575656700171160ustar00rootroot00000000000000"""M2Crypto wrapper for OpenSSL PRNG. Requires OpenSSL 0.9.5 and above. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. Copyright (c) 2014-2017 Matej Cepl. All rights reserved. See LICENCE for the license information. """ from __future__ import absolute_import from M2Crypto import m2 from typing import AnyStr, Tuple # noqa __all__ = ['rand_seed', 'rand_add', 'load_file', 'save_file', 'rand_bytes', 'rand_pseudo_bytes', 'rand_file_name', 'rand_status'] class RandError(ValueError): pass m2.rand_init(RandError) def rand_add(blob, entropy): # type: (bytes, float) -> None """ Mixes blob into the PRNG state. :param blob: added data :param entropy: (the lower bound of) an estimate of how much randomness is contained in blob, measured in bytes. Thus, if the data at buf are unpredictable to an adversary, this increases the uncertainty about the state and makes the PRNG output less predictable. Suitable input comes from user interaction (random key presses, mouse movements) and certain hardware events. Details about sources of randomness and how to estimate their entropy can be found in the literature, e.g. RFC 1750. """ m2.rand_add(blob, entropy) # pylint: disable=no-member def rand_seed(seed): # type: (bytes) -> None """ Equivalent to rand_add() when len(seed) == entropy. :param seed: added data (see description at rand_add) """ m2.rand_seed(seed) # pylint: disable=no-member def rand_status(): # type: () -> int """ Check whether there is enough entropy in PRNG. :return: 1 if the PRNG has been seeded with enough data, 0 otherwise. """ return m2.rand_status() # pylint: disable=no-member def rand_file_name(): # type: () -> str """ Generate a default path for the random seed file. :return: string with the filename. The seed file is $RANDFILE if that environment variable is set, $HOME/.rnd otherwise. If $HOME is not set either, an error occurs. """ return m2.rand_file_name().decode() # pylint: disable=no-member def load_file(filename, max_bytes): # type: (AnyStr, int) -> int """ Read a number of bytes from file filename and adds them to the PRNG. If max_bytes is non-negative, up to to max_bytes are read; starting with OpenSSL 0.9.5, if max_bytes is -1, the complete file is read. :param filename: :param max_bytes: :return: the number of bytes read. """ filename = filename.decode() if isinstance(filename, bytes) else filename return m2.rand_load_file(filename, max_bytes) # pylint: disable=no-member def save_file(filename): # type: (AnyStr) -> int """ Write a number of random bytes (currently 1024) to file. The file then can be used to initialize the PRNG by calling load_file() in a later session. :param filename: :return: returns the number of bytes written, and -1 if the bytes written were generated without appropriate seed. """ return m2.rand_save_file(filename) # pylint: disable=no-member def rand_bytes(num): # type: (int) -> bytes """ Return n cryptographically strong pseudo-random bytes. An error occurs if the PRNG has not been seeded with enough randomness to ensure an unpredictable byte sequence. :param num: number of bytes to be returned :return: random bytes """ return m2.rand_bytes(num) # pylint: disable=no-member def rand_pseudo_bytes(num): # type: (int) -> Tuple[bytes, int] """ Return num pseudo-random bytes into buf. Pseudo-random byte sequences generated by this method will be unique if they are of sufficient length, but are not necessarily unpredictable. They can be used for non-cryptographic purposes and for certain purposes in cryptographic protocols, but usually not for key generation etc. Output of the function is mixed into the entropy pool before retrieving the new pseudo-random bytes unless disabled at compile time (see FAQ). :param num: number of bytes to be returned :return: random bytes """ import warnings if m2.OPENSSL_VERSION_NUMBER >= 0x10100000: warnings.warn('The underlying OpenSSL method has been ' + 'deprecated. Use Rand.rand_bytes instead.', DeprecationWarning) return m2.rand_pseudo_bytes(num) # pylint: disable=no-member m2crypto-0.42.0/src/M2Crypto/SMIME.py000066400000000000000000000214171465575656700171050ustar00rootroot00000000000000from __future__ import absolute_import """M2Crypto wrapper for OpenSSL S/MIME API. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from M2Crypto import BIO, EVP, Err, X509, m2, util from typing import AnyStr, Callable, Optional # noqa PKCS7_TEXT = m2.PKCS7_TEXT # type: int PKCS7_NOCERTS = m2.PKCS7_NOCERTS # type: int PKCS7_NOSIGS = m2.PKCS7_NOSIGS # type: int PKCS7_NOCHAIN = m2.PKCS7_NOCHAIN # type: int PKCS7_NOINTERN = m2.PKCS7_NOINTERN # type: int PKCS7_NOVERIFY = m2.PKCS7_NOVERIFY # type: int PKCS7_DETACHED = m2.PKCS7_DETACHED # type: int PKCS7_BINARY = m2.PKCS7_BINARY # type: int PKCS7_NOATTR = m2.PKCS7_NOATTR # type: int PKCS7_SIGNED = m2.PKCS7_SIGNED # type: int PKCS7_ENVELOPED = m2.PKCS7_ENVELOPED # type: int PKCS7_SIGNED_ENVELOPED = m2.PKCS7_SIGNED_ENVELOPED # Deprecated PKCS7_DATA = m2.PKCS7_DATA # type: int class PKCS7_Error(Exception): pass m2.pkcs7_init(PKCS7_Error) class PKCS7(object): m2_pkcs7_free = m2.pkcs7_free def __init__(self, pkcs7=None, _pyfree=0): # type: (Optional[bytes], int) -> None """PKCS7 object. :param pkcs7: binary representation of the OpenSSL type PKCS7 """ if pkcs7 is not None: self.pkcs7 = pkcs7 self._pyfree = _pyfree else: self.pkcs7 = m2.pkcs7_new() self._pyfree = 1 def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_pkcs7_free(self.pkcs7) def _ptr(self): return self.pkcs7 def type(self, text_name=0): # type: (int) -> int if text_name: return m2.pkcs7_type_sn(self.pkcs7) else: return m2.pkcs7_type_nid(self.pkcs7) def write(self, bio): # type: (BIO.BIO) -> int return m2.pkcs7_write_bio(self.pkcs7, bio._ptr()) def write_der(self, bio): # type: (BIO.BIO) -> int return m2.pkcs7_write_bio_der(self.pkcs7, bio._ptr()) def get0_signers(self, certs, flags=0): # type: (X509.X509_Stack, int) -> X509.X509_Stack return X509.X509_Stack(m2.pkcs7_get0_signers(self.pkcs7, certs.stack, flags), 1) def load_pkcs7(p7file): # type: (AnyStr) -> PKCS7 with BIO.openfile(p7file, 'r') as bio: p7_ptr = m2.pkcs7_read_bio(bio.bio) return PKCS7(p7_ptr, 1) def load_pkcs7_der(p7file): # type: (AnyStr) -> PKCS7 with BIO.openfile(p7file, 'rb') as bio: p7_ptr = m2.pkcs7_read_bio_der(bio.bio) return PKCS7(p7_ptr, 1) def load_pkcs7_bio(p7_bio): # type: (BIO.BIO) -> PKCS7 p7_ptr = m2.pkcs7_read_bio(p7_bio._ptr()) return PKCS7(p7_ptr, 1) def load_pkcs7_bio_der(p7_bio): # type: (BIO.BIO) -> PKCS7 p7_ptr = m2.pkcs7_read_bio_der(p7_bio._ptr()) return PKCS7(p7_ptr, 1) def smime_load_pkcs7(p7file): # type: (AnyStr) -> PKCS7 bio = m2.bio_new_file(p7file, 'r') try: p7_ptr, bio_ptr = m2.smime_read_pkcs7(bio) finally: m2.bio_free(bio) if bio_ptr is None: return PKCS7(p7_ptr, 1), None else: return PKCS7(p7_ptr, 1), BIO.BIO(bio_ptr, 1) def smime_load_pkcs7_bio(p7_bio): # type: (BIO.BIO) -> PKCS7 p7_ptr, bio_ptr = m2.smime_read_pkcs7(p7_bio._ptr()) if p7_ptr is None: raise SMIME_Error(Err.get_error()) if bio_ptr is None: return PKCS7(p7_ptr, 1), None else: return PKCS7(p7_ptr, 1), BIO.BIO(bio_ptr, 1) class Cipher(object): """Object interface to EVP_CIPHER without all the frills of M2Crypto.EVP.Cipher. """ def __init__(self, algo): # type: (str) -> None cipher = getattr(m2, algo, None) if cipher is None: raise ValueError('unknown cipher', algo) self.cipher = cipher() def _ptr(self): return self.cipher class SMIME_Error(Exception): pass m2.smime_init(SMIME_Error) # FIXME class has no __init__ method class SMIME(object): def load_key(self, keyfile, certfile=None, callback=util.passphrase_callback): # type: (AnyStr, Optional[AnyStr], Callable) -> None if certfile is None: certfile = keyfile self.pkey = EVP.load_key(keyfile, callback) self.x509 = X509.load_cert(certfile) def load_key_bio(self, keybio, certbio=None, callback=util.passphrase_callback): # type: (BIO.BIO, Optional[BIO.BIO], Callable) -> None if certbio is None: certbio = keybio self.pkey = EVP.load_key_bio(keybio, callback) self.x509 = X509.load_cert_bio(certbio) def set_x509_stack(self, stack): # type: (X509.X509_Stack) -> None assert isinstance(stack, X509.X509_Stack) self.x509_stack = stack def set_x509_store(self, store): # type: (X509.X509_Store) -> None assert isinstance(store, X509.X509_Store) self.x509_store = store def set_cipher(self, cipher): # type: (Cipher) -> None assert isinstance(cipher, Cipher) self.cipher = cipher def unset_key(self): # type: () -> None del self.pkey del self.x509 def unset_x509_stack(self): # type: () -> None del self.x509_stack def unset_x509_store(self): # type: () -> None del self.x509_store def unset_cipher(self): # type: () -> None del self.cipher def encrypt(self, data_bio, flags=0): # type: (BIO.BIO, int) -> PKCS7 if not hasattr(self, 'cipher'): raise SMIME_Error('no cipher: use set_cipher()') if not hasattr(self, 'x509_stack'): raise SMIME_Error('no recipient certs: use set_x509_stack()') pkcs7 = m2.pkcs7_encrypt(self.x509_stack._ptr(), data_bio._ptr(), self.cipher._ptr(), flags) return PKCS7(pkcs7, 1) def decrypt(self, pkcs7, flags=0): # type: (PKCS7, int) -> Optional[bytes] if not hasattr(self, 'pkey'): raise SMIME_Error('no private key: use load_key()') if not hasattr(self, 'x509'): raise SMIME_Error('no certificate: load_key() used incorrectly?') blob = m2.pkcs7_decrypt(pkcs7._ptr(), self.pkey._ptr(), self.x509._ptr(), flags) return blob def sign(self, data_bio, flags=0, algo='sha1'): # type: (BIO.BIO, int, Optional[str]) -> PKCS7 if not hasattr(self, 'pkey'): raise SMIME_Error('no private key: use load_key()') hash = getattr(m2, algo, None) if hash is None: raise SMIME_Error('no such hash algorithm %s' % algo) if hasattr(self, 'x509_stack'): pkcs7 = m2.pkcs7_sign1(self.x509._ptr(), self.pkey._ptr(), self.x509_stack._ptr(), data_bio._ptr(), hash(), flags) return PKCS7(pkcs7, 1) else: pkcs7 = m2.pkcs7_sign0(self.x509._ptr(), self.pkey._ptr(), data_bio._ptr(), hash(), flags) return PKCS7(pkcs7, 1) def verify(self, pkcs7, data_bio=None, flags=0): # type: (PKCS7, Optional[BIO.BIO], int) -> Optional[bytes] if not hasattr(self, 'x509_stack'): raise SMIME_Error('no signer certs: use set_x509_stack()') if not hasattr(self, 'x509_store'): raise SMIME_Error('no x509 cert store: use set_x509_store()') assert isinstance(pkcs7, PKCS7), 'pkcs7 not an instance of PKCS7' p7 = pkcs7._ptr() if data_bio is None: blob = m2.pkcs7_verify0(p7, self.x509_stack._ptr(), self.x509_store._ptr(), flags) else: blob = m2.pkcs7_verify1(p7, self.x509_stack._ptr(), self.x509_store._ptr(), data_bio._ptr(), flags) return blob def write(self, out_bio, pkcs7, data_bio=None, flags=0): # type: (BIO.BIO, PKCS7, Optional[BIO.BIO], int) -> int assert isinstance(pkcs7, PKCS7) if data_bio is None: return m2.smime_write_pkcs7(out_bio._ptr(), pkcs7._ptr(), flags) else: return m2.smime_write_pkcs7_multi(out_bio._ptr(), pkcs7._ptr(), data_bio._ptr(), flags) def text_crlf(text): # type: (bytes) -> bytes bio_in = BIO.MemoryBuffer(text) bio_out = BIO.MemoryBuffer() if m2.smime_crlf_copy(bio_in._ptr(), bio_out._ptr()): return bio_out.read() else: raise SMIME_Error(Err.get_error()) def text_crlf_bio(bio_in): # type: (BIO.BIO) -> BIO.BIO bio_out = BIO.MemoryBuffer() if m2.smime_crlf_copy(bio_in._ptr(), bio_out._ptr()): return bio_out else: raise SMIME_Error(Err.get_error()) m2crypto-0.42.0/src/M2Crypto/SSL/000077500000000000000000000000001465575656700163155ustar00rootroot00000000000000m2crypto-0.42.0/src/M2Crypto/SSL/Checker.py000066400000000000000000000253441465575656700202430ustar00rootroot00000000000000""" SSL peer certificate checking routines Copyright (c) 2004-2007 Open Source Applications Foundation. All rights reserved. Copyright 2008 Heikki Toivonen. All rights reserved. """ __all__ = ['SSLVerificationError', 'NoCertificate', 'WrongCertificate', 'WrongHost', 'Checker'] import re import socket from M2Crypto import X509, m2 # noqa from typing import AnyStr, Optional # noqa class SSLVerificationError(Exception): pass class NoCertificate(SSLVerificationError): pass class WrongCertificate(SSLVerificationError): pass class WrongHost(SSLVerificationError): def __init__(self, expectedHost, actualHost, fieldName='commonName'): # type: (str, AnyStr, str) -> None """ This exception will be raised if the certificate returned by the peer was issued for a different host than we tried to connect to. This could be due to a server misconfiguration or an active attack. :param expectedHost: The name of the host we expected to find in the certificate. :param actualHost: The name of the host we actually found in the certificate. :param fieldName: The field name where we noticed the error. This should be either 'commonName' or 'subjectAltName'. """ if fieldName not in ('commonName', 'subjectAltName'): raise ValueError( 'Unknown fieldName, should be either commonName ' + 'or subjectAltName') SSLVerificationError.__init__(self) self.expectedHost = expectedHost self.actualHost = actualHost self.fieldName = fieldName def __str__(self): # type: () -> str return 'Peer certificate %s does not match host, expected %s, got %s' \ % (self.fieldName, self.expectedHost, self.actualHost) class Checker(object): numericIpMatch = re.compile(r'^[0-9]+(\.[0-9]+)*$') def __init__(self, host=None, peerCertHash=None, peerCertDigest='sha1'): # type: (Optional[str], Optional[bytes], str) -> None self.host = host self.fingerprint = peerCertHash self.digest = peerCertDigest # type: str def __call__(self, peerCert, host=None): # type: (X509.X509, Optional[str]) -> bool if peerCert is None: raise NoCertificate('peer did not return certificate') if host is not None: self.host = host # type: str if self.fingerprint: if self.digest not in ('sha1', 'md5'): raise ValueError('unsupported digest "%s"' % self.digest) if self.digest == 'sha1': expected_len = 40 elif self.digest == 'md5': expected_len = 32 else: raise ValueError('Unexpected digest {0}'.format(self.digest)) if len(self.fingerprint) != expected_len: raise WrongCertificate( ('peer certificate fingerprint length does not match\n' + 'fingerprint: {0}\nexpected = {1}\n' + 'observed = {2}').format(self.fingerprint, expected_len, len(self.fingerprint))) expected_fingerprint = self.fingerprint.decode() if isinstance(self.fingerprint, bytes) \ else self.fingerprint observed_fingerprint = peerCert.get_fingerprint(md=self.digest) if observed_fingerprint != expected_fingerprint: raise WrongCertificate( ('peer certificate fingerprint does not match\n' + 'expected = {0},\n' + 'observed = {1}').format(expected_fingerprint, observed_fingerprint)) if self.host: hostValidationPassed = False self.useSubjectAltNameOnly = False # subjectAltName=DNS:somehost[, ...]* try: subjectAltName = peerCert.get_ext('subjectAltName').get_value() if self._splitSubjectAltName(self.host, subjectAltName): hostValidationPassed = True elif self.useSubjectAltNameOnly: raise WrongHost(expectedHost=self.host, actualHost=subjectAltName, fieldName='subjectAltName') except LookupError: pass # commonName=somehost[, ...]* if not hostValidationPassed: hasCommonName = False commonNames = '' for entry in peerCert.get_subject().get_entries_by_nid( m2.NID_commonName): hasCommonName = True commonName = entry.get_data().as_text() if not commonNames: commonNames = commonName else: commonNames += ',' + commonName if self._match(self.host, commonName): hostValidationPassed = True break if not hasCommonName: raise WrongCertificate('no commonName in peer certificate') if not hostValidationPassed: raise WrongHost(expectedHost=self.host, actualHost=commonNames, fieldName='commonName') return True def _splitSubjectAltName(self, host, subjectAltName): # type: (AnyStr, AnyStr) -> bool """ >>> check = Checker() >>> check._splitSubjectAltName(host='my.example.com', ... subjectAltName='DNS:my.example.com') True >>> check._splitSubjectAltName(host='my.example.com', ... subjectAltName='DNS:*.example.com') True >>> check._splitSubjectAltName(host='my.example.com', ... subjectAltName='DNS:m*.example.com') True >>> check._splitSubjectAltName(host='my.example.com', ... subjectAltName='DNS:m*ample.com') False >>> check.useSubjectAltNameOnly True >>> check._splitSubjectAltName(host='my.example.com', ... subjectAltName='DNS:m*ample.com, othername:') False >>> check._splitSubjectAltName(host='my.example.com', ... subjectAltName='DNS:m*ample.com, DNS:my.example.org') False >>> check._splitSubjectAltName(host='my.example.com', ... subjectAltName='DNS:m*ample.com, DNS:my.example.com') True >>> check._splitSubjectAltName(host='my.example.com', ... subjectAltName='DNS:my.example.com, DNS:my.example.org') True >>> check.useSubjectAltNameOnly True >>> check._splitSubjectAltName(host='my.example.com', ... subjectAltName='') False >>> check._splitSubjectAltName(host='my.example.com', ... subjectAltName='othername:') False >>> check.useSubjectAltNameOnly False """ self.useSubjectAltNameOnly = False for certHost in subjectAltName.split(','): certHost = certHost.lower().strip() if certHost[:4] == 'dns:': self.useSubjectAltNameOnly = True if self._match(host, certHost[4:]): return True elif certHost[:11] == 'ip address:': self.useSubjectAltNameOnly = True if self._matchIPAddress(host, certHost[11:]): return True return False def _match(self, host, certHost): # type: (str, str) -> bool """ >>> check = Checker() >>> check._match(host='my.example.com', certHost='my.example.com') True >>> check._match(host='my.example.com', certHost='*.example.com') True >>> check._match(host='my.example.com', certHost='m*.example.com') True >>> check._match(host='my.example.com', certHost='m*.EXAMPLE.com') True >>> check._match(host='my.example.com', certHost='m*ample.com') False >>> check._match(host='my.example.com', certHost='*.*.com') False >>> check._match(host='1.2.3.4', certHost='1.2.3.4') True >>> check._match(host='1.2.3.4', certHost='*.2.3.4') False >>> check._match(host='1234', certHost='1234') True """ # XXX See RFC 2818 and 3280 for matching rules, this is may not # XXX yet be complete. host = host.lower() certHost = certHost.lower() if host == certHost: return True if certHost.count('*') > 1: # Not sure about this, but being conservative return False if self.numericIpMatch.match(host) or \ self.numericIpMatch.match(certHost.replace('*', '')): # Not sure if * allowed in numeric IP, but think not. return False if certHost.find('\\') > -1: # Not sure about this, maybe some encoding might have these. # But being conservative for now, because regex below relies # on this. return False # Massage certHost so that it can be used in regex certHost = certHost.replace('.', '\\.') certHost = certHost.replace('*', '[^\\.]*') if re.compile('^%s$' % certHost).match(host): return True return False def _matchIPAddress(self, host, certHost): # type: (AnyStr, AnyStr) -> bool """ >>> check = Checker() >>> check._matchIPAddress(host='my.example.com', ... certHost='my.example.com') False >>> check._matchIPAddress(host='1.2.3.4', certHost='1.2.3.4') True >>> check._matchIPAddress(host='1.2.3.4', certHost='*.2.3.4') False >>> check._matchIPAddress(host='1.2.3.4', certHost='1.2.3.40') False >>> check._matchIPAddress(host='::1', certHost='::1') True >>> check._matchIPAddress(host='::1', certHost='0:0:0:0:0:0:0:1') True >>> check._matchIPAddress(host='::1', certHost='::2') False """ try: canonical = socket.getaddrinfo(host, 0, 0, socket.SOCK_STREAM, 0, socket.AI_NUMERICHOST) certCanonical = socket.getaddrinfo(certHost, 0, 0, socket.SOCK_STREAM, 0, socket.AI_NUMERICHOST) except: return False return canonical == certCanonical if __name__ == '__main__': import doctest doctest.testmod() m2crypto-0.42.0/src/M2Crypto/SSL/Cipher.py000066400000000000000000000027311465575656700201040ustar00rootroot00000000000000"""SSL Ciphers Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" __all__ = ['Cipher', 'Cipher_Stack'] from M2Crypto import m2 from typing import Iterable # noqa class Cipher(object): def __init__(self, cipher): # type: (str) -> None self.cipher = cipher def __len__(self): # type: () -> int return m2.ssl_cipher_get_bits(self.cipher) def __repr__(self): # type: () -> str return "%s-%s" % (self.name(), len(self)) def __str__(self): # type: () -> str return "%s-%s" % (self.name(), len(self)) def version(self): # type: () -> int return m2.ssl_cipher_get_version(self.cipher) def name(self): # type: () -> str return m2.ssl_cipher_get_name(self.cipher) class Cipher_Stack(object): def __init__(self, stack): # type: (bytes) -> None """ :param stack: binary of the C-type STACK_OF(SSL_CIPHER) """ self.stack = stack def __len__(self): # type: () -> int return m2.sk_ssl_cipher_num(self.stack) def __getitem__(self, idx): # type: (int) -> Cipher if not 0 <= idx < m2.sk_ssl_cipher_num(self.stack): raise IndexError('index out of range') v = m2.sk_ssl_cipher_value(self.stack, idx) return Cipher(v) def __iter__(self): # type: () -> Iterable for i in range(m2.sk_ssl_cipher_num(self.stack)): yield self[i] m2crypto-0.42.0/src/M2Crypto/SSL/Connection.py000066400000000000000000000622531465575656700207760ustar00rootroot00000000000000from __future__ import absolute_import """SSL Connection aka socket Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2004-2007 OSAF. All Rights Reserved. Copyright 2008 Heikki Toivonen. All rights reserved. """ import logging import socket import io from M2Crypto import BIO, Err, X509, m2, util # noqa from M2Crypto.SSL import Checker, Context, timeout # noqa from M2Crypto.SSL import SSLError from M2Crypto.SSL.Cipher import Cipher, Cipher_Stack from M2Crypto.SSL.Session import Session from typing import ( Any, AnyStr, Callable, Optional, Tuple, Union, ) # noqa __all__ = [ 'Connection', 'timeout', # XXX Not really, but for documentation purposes ] log = logging.getLogger(__name__) def _serverPostConnectionCheck(*args, **kw): # type: (*Any, **Any) -> int return 1 class Connection(object): """An SSL connection.""" serverPostConnectionCheck = _serverPostConnectionCheck m2_bio_free = m2.bio_free m2_ssl_free = m2.ssl_free m2_bio_noclose = m2.bio_noclose def __init__(self, ctx, sock=None, family=socket.AF_INET): # type: (Context, Optional[socket.socket], int) -> None """ :param ctx: SSL.Context :param sock: socket to be used :param family: socket family """ # The Checker needs to be an instance attribute # and not a class attribute for thread safety reason self.clientPostConnectionCheck = Checker.Checker() self._bio_freed = False self.ctx = ctx self.ssl = m2.ssl_new(self.ctx.ctx) # type: bytes if sock is not None: self.socket = sock else: self.socket = socket.socket(family, socket.SOCK_STREAM) self.socket.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 ) self._fileno = self.socket.fileno() self._timeout = self.socket.gettimeout() if self._timeout is None: self._timeout = -1.0 self.ssl_close_flag = m2.bio_noclose if self.ctx.post_connection_check is not None: self.set_post_connection_check_callback( self.ctx.post_connection_check ) self.host = None def _free_bio(self): """ Free the sslbio and sockbio, and close the socket. """ # Do not do it twice if not self._bio_freed: if getattr(self, 'sslbio', None): self.m2_bio_free(self.sslbio) if getattr(self, 'sockbio', None): self.m2_bio_free(self.sockbio) if ( self.ssl_close_flag == self.m2_bio_noclose and getattr(self, 'ssl', None) ): self.m2_ssl_free(self.ssl) self.socket.close() self._bio_freed = True def __del__(self): # type: () -> None # Notice that M2Crypto doesn't automatically shuts down the # connection here. You have to call self.close() in your # program, M2Crypto won't do it automatically for you. if getattr(self, 'sslbio', None): self.m2_bio_free(self.sslbio) if getattr(self, 'sockbio', None): self.m2_bio_free(self.sockbio) if self.ssl_close_flag == self.m2_bio_noclose and getattr( self, 'ssl', None ): self.m2_ssl_free(self.ssl) self.socket.close() def close(self, freeBio=False): # type: (Optional[bool]) -> None """ if freeBio is true, call _free_bio """ m2.ssl_shutdown(self.ssl) if freeBio: self._free_bio() def clear(self): # type: () -> int """ If there were errors in this connection, call clear() rather than close() to end it, so that bad sessions will be cleared from cache. """ return m2.ssl_clear(self.ssl) def set_shutdown(self, mode): # type: (int) -> None """Sets the shutdown state of the Connection to mode. The shutdown state of an ssl connection is a bitmask of (use m2.SSL_* constants): 0 No shutdown setting, yet. SSL_SENT_SHUTDOWN A "close notify" shutdown alert was sent to the peer, the connection is being considered closed and the session is closed and correct. SSL_RECEIVED_SHUTDOWN A shutdown alert was received form the peer, either a normal "close notify" or a fatal error. SSL_SENT_SHUTDOWN and SSL_RECEIVED_SHUTDOWN can be set at the same time. :param mode: set the mode bitmask. """ m2.ssl_set_shutdown1(self.ssl, mode) def get_shutdown(self): # type: () -> None """Get the current shutdown mode of the Connection.""" return m2.ssl_get_shutdown(self.ssl) def bind(self, addr): # type: (util.AddrType) -> None self.socket.bind(addr) def listen(self, qlen=5): # type: (int) -> None self.socket.listen(qlen) def ssl_get_error(self, ret): # type: (int) -> int return m2.ssl_get_error(self.ssl, ret) def set_bio(self, readbio, writebio): # type: (BIO.BIO, BIO.BIO) -> None """Explicitly set read and write bios Connects the BIOs for the read and write operations of the TLS/SSL (encrypted) side of ssl. The SSL engine inherits the behaviour of both BIO objects, respectively. If a BIO is non-blocking, the Connection will also have non-blocking behaviour. If there was already a BIO connected to Connection, BIO_free() will be called (for both the reading and writing side, if different). :param readbio: BIO for reading :param writebio: BIO for writing. """ m2.ssl_set_bio(self.ssl, readbio._ptr(), writebio._ptr()) def set_client_CA_list_from_file(self, cafile): # type: (AnyStr) -> None """Set the acceptable client CA list. If the client returns a certificate, it must have been issued by one of the CAs listed in cafile. Makes sense only for servers. :param cafile: Filename from which to load the CA list. :return: 0 A failure while manipulating the STACK_OF(X509_NAME) object occurred or the X509_NAME could not be extracted from cacert. Check the error stack to find out the reason. 1 The operation succeeded. """ m2.ssl_set_client_CA_list_from_file(self.ssl, cafile) def set_client_CA_list_from_context(self): # type: () -> None """ Set the acceptable client CA list. If the client returns a certificate, it must have been issued by one of the CAs listed in context. Makes sense only for servers. """ m2.ssl_set_client_CA_list_from_context(self.ssl, self.ctx.ctx) def setup_addr(self, addr): # type: (util.AddrType) -> None self.addr = addr def set_ssl_close_flag(self, flag): # type: (int) -> None """ By default, SSL struct will be freed in __del__. Call with m2.bio_close to override this default. :param flag: either m2.bio_close or m2.bio_noclose """ if flag not in (m2.bio_close, m2.bio_noclose): raise ValueError( "flag must be m2.bio_close or m2.bio_noclose" ) self.ssl_close_flag = flag def setup_ssl(self): # type: () -> None # Make a BIO_s_socket. self.sockbio = m2.bio_new_socket(self.socket.fileno(), 0) # Link SSL struct with the BIO_socket. m2.ssl_set_bio(self.ssl, self.sockbio, self.sockbio) # Make a BIO_f_ssl. self.sslbio = m2.bio_new(m2.bio_f_ssl()) # Link BIO_f_ssl with the SSL struct. m2.bio_set_ssl(self.sslbio, self.ssl, m2.bio_noclose) def _setup_ssl(self, addr): # type: (util.AddrType) -> None """Deprecated""" self.setup_addr(addr) self.setup_ssl() def set_accept_state(self): # type: () -> None """Sets Connection to work in the server mode.""" m2.ssl_set_accept_state(self.ssl) def accept_ssl(self): # type: () -> Optional[int] """Waits for a TLS/SSL client to initiate the TLS/SSL handshake. The communication channel must already have been set and assigned to the ssl by setting an underlying BIO. :return: 0 The TLS/SSL handshake was not successful but was shut down controlled and by the specifications of the TLS/SSL protocol. Call get_error() with the return value ret to find out the reason. 1 The TLS/SSL handshake was successfully completed, a TLS/SSL connection has been established. <0 The TLS/SSL handshake was not successful because a fatal error occurred either at the protocol level or a connection failure occurred. The shutdown was not clean. It can also occur of action is need to continue the operation for non-blocking BIOs. Call get_error() with the return value ret to find out the reason. """ return m2.ssl_accept(self.ssl, self._timeout) def accept(self): # type: () -> Tuple[Connection, util.AddrType] """Accept an SSL connection. The return value is a pair (ssl, addr) where ssl is a new SSL connection object and addr is the address bound to the other end of the SSL connection. :return: tuple of Connection and addr. Address can take very various forms (see socket documentation), for IPv4 it is tuple(str, int), for IPv6 a tuple of four (host, port, flowinfo, scopeid), where the last two are optional ints. """ sock, addr = self.socket.accept() ssl = Connection(self.ctx, sock) ssl.addr = addr ssl.setup_ssl() ssl.set_accept_state() ssl.accept_ssl() check = getattr( self, 'postConnectionCheck', self.serverPostConnectionCheck, ) if check is not None: if not check(ssl.get_peer_cert(), ssl.addr[0]): raise Checker.SSLVerificationError( 'post connection check failed' ) return ssl, addr def set_connect_state(self): # type: () -> None """Sets Connection to work in the client mode.""" m2.ssl_set_connect_state(self.ssl) def connect_ssl(self): # type: () -> Optional[int] return m2.ssl_connect(self.ssl, self._timeout) def connect(self, addr): # type: (util.AddrType) -> int """Overloading socket.connect() :param addr: addresses have various depending on their type :return:status of ssl_connect() """ self.socket.connect(addr) self.addr = addr self.setup_ssl() self.set_connect_state() ret = self.connect_ssl() check = getattr( self, 'postConnectionCheck', self.clientPostConnectionCheck, ) if check is not None: if not check( self.get_peer_cert(), self.host if self.host else self.addr[0], ): raise Checker.SSLVerificationError( 'post connection check failed' ) return ret def shutdown(self, how): # type: (int) -> None m2.ssl_set_shutdown(self.ssl, how) def renegotiate(self): # type: () -> int """Renegotiate this connection's SSL parameters.""" return m2.ssl_renegotiate(self.ssl) def pending(self): # type: () -> int """Return the numbers of octets that can be read from the connection.""" return m2.ssl_pending(self.ssl) def _write_bio(self, data): # type: (bytes) -> int return m2.ssl_write(self.ssl, data, self._timeout) def _write_nbio(self, data): # type: (bytes) -> int return m2.ssl_write_nbio(self.ssl, data) def _read_bio(self, size=1024): # type: (int) -> bytes if size <= 0: raise ValueError('size <= 0') return m2.ssl_read(self.ssl, size, self._timeout) def _read_nbio(self, size=1024): # type: (int) -> bytes if size <= 0: raise ValueError('size <= 0') return m2.ssl_read_nbio(self.ssl, size) def write(self, data): # type: (bytes) -> int if self._timeout != 0.0: return self._write_bio(data) return self._write_nbio(data) sendall = send = write def _decref_socketios(self): pass def recv_into(self, buff, nbytes=0): # type: (Union[bytearray, memoryview], int) -> int """ A version of recv() that stores its data into a buffer rather than creating a new string. Receive up to nbytes bytes from the socket. If nbytes is not specified (or 0), receive up to the size available in the given buffer. If buff is bytearray, it will have after return length of the actually returned number of bytes. If buff is memoryview, then the size of buff won't change (it cannot), but all bytes after the number of returned bytes will be NULL. :param buffer: a buffer for the received bytes :param nbytes: maximum number of bytes to read :return: number of bytes read See recv() for documentation about the flags. """ n = len(buff) if nbytes == 0 else nbytes if n <= 0: raise ValueError('recv_into: size of buffer <= 0') # buff_bytes are actual bytes returned buff_bytes = m2.ssl_read(self.ssl, n, self._timeout) buflen = len(buff_bytes) # memoryview type has been added in 2.7 if isinstance(buff, memoryview): buff[:buflen] = buff_bytes buff[buflen:] = b'\x00' * (len(buff) - buflen) else: buff[:] = buff_bytes return buflen def read(self, size=1024): # type: (int) -> bytes if self._timeout != 0.0: return self._read_bio(size) return self._read_nbio(size) recv = read def setblocking(self, mode): # type: (int) -> None """Set this connection's underlying socket to _mode_. Set blocking or non-blocking mode of the socket: if flag is 0, the socket is set to non-blocking, else to blocking mode. Initially all sockets are in blocking mode. In non-blocking mode, if a recv() call doesn't find any data, or if a send() call can't immediately dispose of the data, a error exception is raised; in blocking mode, the calls block until they can proceed. s.setblocking(0) is equivalent to s.settimeout(0.0); s.setblocking(1) is equivalent to s.settimeout(None). :param mode: new mode to be set """ self.socket.setblocking(mode) if mode: self._timeout = -1.0 else: self._timeout = 0.0 def settimeout(self, timeout): # type: (float) -> None """Set this connection's underlying socket's timeout to _timeout_.""" self.socket.settimeout(timeout) self._timeout = timeout if self._timeout is None: self._timeout = -1.0 def fileno(self): # type: () -> int return self.socket.fileno() def getsockopt(self, level, optname, buflen=None): # type: (int, int, Optional[int]) -> Union[int, bytes] """Get the value of the given socket option. :param level: level at which the option resides. To manipulate options at the sockets API level, level is specified as socket.SOL_SOCKET. To manipulate options at any other level the protocol number of the appropriate protocol controlling the option is supplied. For example, to indicate that an option is to be interpreted by the TCP protocol, level should be set to the protocol number of socket.SOL_TCP; see getprotoent(3). :param optname: The value of the given socket option is described in the Unix man page getsockopt(2)). The needed symbolic constants (SO_* etc.) are defined in the socket module. :param buflen: If it is absent, an integer option is assumed and its integer value is returned by the function. If buflen is present, it specifies the maximum length of the buffer used to receive the option in, and this buffer is returned as a bytes object. :return: Either integer or bytes value of the option. It is up to the caller to decode the contents of the buffer (see the optional built-in module struct for a way to decode C structures encoded as byte strings). """ return self.socket.getsockopt(level, optname, buflen) def setsockopt(self, level, optname, value=None): # type: (int, int, Union[int, bytes, None]) -> Optional[bytes] """Set the value of the given socket option. :param level: same as with getsockopt() above :param optname: same as with getsockopt() above :param value: an integer or a string representing a buffer. In the latter case it is up to the caller to ensure that the string contains the proper bits (see the optional built-in module struct for a way to encode C structures as strings). :return: None for success or the error handler for failure. """ return self.socket.setsockopt(level, optname, value) def get_context(self): # type: () -> Context """Return the Context object associated with this connection.""" return m2.ssl_get_ssl_ctx(self.ssl) def get_state(self): # type: () -> bytes """Return the SSL state of this connection. During its use, an SSL objects passes several states. The state is internally maintained. Querying the state information is not very informative before or when a connection has been established. It however can be of significant interest during the handshake. :return: 6 letter string indicating the current state of the SSL object ssl. """ return m2.ssl_get_state(self.ssl) def verify_ok(self): # type: () -> bool return m2.ssl_get_verify_result(self.ssl) == m2.X509_V_OK def get_verify_mode(self): # type: () -> int """Return the peer certificate verification mode.""" return m2.ssl_get_verify_mode(self.ssl) def get_verify_depth(self): # type: () -> int """Return the peer certificate verification depth.""" return m2.ssl_get_verify_depth(self.ssl) def get_verify_result(self): # type: () -> int """Return the peer certificate verification result.""" return m2.ssl_get_verify_result(self.ssl) def get_peer_cert(self): # type: () -> X509.X509 """Return the peer certificate. If the peer did not provide a certificate, return None. """ c = m2.ssl_get_peer_cert(self.ssl) if c is None: return None # Need to free the pointer coz OpenSSL doesn't. return X509.X509(c, 1) def get_peer_cert_chain(self): # type: () -> Optional[X509.X509_Stack] """Return the peer certificate chain; if the peer did not provide a certificate chain, return None. :warning: The returned chain will be valid only for as long as the connection object is alive. Once the connection object gets freed, the chain will be freed as well. """ c = m2.ssl_get_peer_cert_chain(self.ssl) if c is None: return None # No need to free the pointer coz OpenSSL does. return X509.X509_Stack(c) def get_cipher(self): # type: () -> Optional[Cipher] """Return an M2Crypto.SSL.Cipher object for this connection; if the connection has not been initialised with a cipher suite, return None. """ c = m2.ssl_get_current_cipher(self.ssl) if c is None: return None return Cipher(c) def get_ciphers(self): # type: () -> Optional[Cipher_Stack] """Return an M2Crypto.SSL.Cipher_Stack object for this connection; if the connection has not been initialised with cipher suites, return None. """ c = m2.ssl_get_ciphers(self.ssl) if c is None: return None return Cipher_Stack(c) def get_cipher_list(self, idx=0): # type: (int) -> str """Return the cipher suites for this connection as a string object.""" return m2.ssl_get_cipher_list(self.ssl, idx) def set_cipher_list(self, cipher_list): # type: (str) -> int """Set the cipher suites for this connection.""" return m2.ssl_set_cipher_list(self.ssl, cipher_list) def makefile(self, mode='rb', bufsize=-1): # type: (AnyStr, int) -> Union[io.BufferedRWPair,io.BufferedReader] raw = socket.SocketIO(self, mode) if 'rw' in mode: return io.BufferedRWPair(raw, raw) return io.BufferedReader(raw, io.DEFAULT_BUFFER_SIZE) def getsockname(self): # type: () -> util.AddrType """Return the socket's own address. This is useful to find out the port number of an IPv4/v6 socket, for instance. (The format of the address returned depends on the address family -- see above.) :return:socket's address as addr type """ return self.socket.getsockname() def getpeername(self): # type: () -> util.AddrType """Return the remote address to which the socket is connected. This is useful to find out the port number of a remote IPv4/v6 socket, for instance. On some systems this function is not supported. :return: """ return self.socket.getpeername() def set_session_id_ctx(self, id): # type: (bytes) -> int ret = m2.ssl_set_session_id_context(self.ssl, id) if not ret: raise SSLError(Err.get_error_message()) def get_session(self): # type: () -> Session sess = m2.ssl_get_session(self.ssl) return Session(sess) def set_session(self, session): # type: (Session) -> None m2.ssl_set_session(self.ssl, session._ptr()) def get_default_session_timeout(self): # type: () -> int return m2.ssl_get_default_session_timeout(self.ssl) def get_socket_read_timeout(self): # type: () -> timeout return timeout.struct_to_timeout( self.socket.getsockopt( socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeout.struct_size(), ) ) @staticmethod def _hexdump(s): assert isinstance(s, bytes) return ":".join(s) def get_socket_write_timeout(self): # type: () -> timeout binstr = self.socket.getsockopt( socket.SOL_SOCKET, socket.SO_SNDTIMEO, timeout.struct_size(), ) timeo = timeout.struct_to_timeout(binstr) # print("Debug: get_socket_write_timeout: " # "get sockopt value: %s -> ret timeout(sec=%r, microsec=%r)" % # (self._hexdump(binstr), timeo.sec, timeo.microsec)) return timeo def set_socket_read_timeout(self, timeo): # type: (timeout) -> None assert isinstance(timeo, timeout.timeout) self.socket.setsockopt( socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeo.pack() ) def set_socket_write_timeout(self, timeo): # type: (timeout) -> None assert isinstance(timeo, timeout.timeout) binstr = timeo.pack() # print("Debug: set_socket_write_timeout: " # "input timeout(sec=%r, microsec=%r) -> set sockopt value: %s" % # (timeo.sec, timeo.microsec, self._hexdump(binstr))) self.socket.setsockopt( socket.SOL_SOCKET, socket.SO_SNDTIMEO, binstr ) def get_version(self): # type: () -> str """Return the TLS/SSL protocol version for this connection.""" return m2.ssl_get_version(self.ssl) def set_post_connection_check_callback( self, postConnectionCheck ): # noqa # type: (Callable) -> None self.postConnectionCheck = postConnectionCheck def set_tlsext_host_name(self, name): # type: (bytes) -> None """Set the requested hostname for the SNI (Server Name Indication) extension. """ m2.ssl_set_tlsext_host_name(self.ssl, name) def set1_host(self, name): # type: (bytes) -> None """Set the requested hostname to check in the server certificate.""" self.host = name m2crypto-0.42.0/src/M2Crypto/SSL/Context.py000066400000000000000000000412221465575656700203140ustar00rootroot00000000000000from __future__ import absolute_import """SSL Context Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" from M2Crypto import BIO, Err, RSA, X509, m2, util # noqa from M2Crypto.SSL import cb # noqa from M2Crypto.SSL.Session import Session # noqa from weakref import WeakValueDictionary from typing import Any, AnyStr, Callable, Optional, Union # noqa __all__ = ['ctxmap', 'Context', 'map'] class _ctxmap(object): singleton = None # type: Optional[_ctxmap] def __init__(self): # type: () -> None """Simple WeakReffed list. """ self._ctxmap = WeakValueDictionary() def __getitem__(self, key): # type: (int) -> Any return self._ctxmap[key] def __setitem__(self, key, value): # type: (int, Any) -> None self._ctxmap[key] = value def __delitem__(self, key): # type: (int) -> None del self._ctxmap[key] def ctxmap(): # type: () -> _ctxmap if _ctxmap.singleton is None: _ctxmap.singleton = _ctxmap() return _ctxmap.singleton # deprecated!!! map = ctxmap class Context(object): """'Context' for SSL connections.""" m2_ssl_ctx_free = m2.ssl_ctx_free def __init__(self, protocol='tls', weak_crypto=None, post_connection_check=None): # type: (str, Optional[int], Optional[Callable]) -> None proto = getattr(m2, protocol + '_method', None) if proto is None: # default is 'sslv23' for older versions of OpenSSL if protocol == 'tls': proto = getattr(m2, 'sslv23_method') else: raise ValueError("no such protocol '%s'" % protocol) self.ctx = m2.ssl_ctx_new(proto()) self.allow_unknown_ca = 0 # type: Union[int, bool] self.post_connection_check = post_connection_check ctxmap()[int(self.ctx)] = self m2.ssl_ctx_set_cache_size(self.ctx, 128) if weak_crypto is None and protocol in ('sslv23', 'tls'): self.set_options(m2.SSL_OP_ALL | m2.SSL_OP_NO_SSLv2 | m2.SSL_OP_NO_SSLv3) def __del__(self): # type: () -> None if getattr(self, 'ctx', None): self.m2_ssl_ctx_free(self.ctx) def close(self): # type: () -> None del ctxmap()[int(self.ctx)] def load_cert(self, certfile, keyfile=None, callback=util.passphrase_callback): # type: (AnyStr, Optional[AnyStr], Callable) -> None """Load certificate and private key into the context. :param certfile: File that contains the PEM-encoded certificate. :param keyfile: File that contains the PEM-encoded private key. Default value of None indicates that the private key is to be found in 'certfile'. :param callback: Callable object to be invoked if the private key is passphrase-protected. Default callback provides a simple terminal-style input for the passphrase. """ m2.ssl_ctx_passphrase_callback(self.ctx, callback) m2.ssl_ctx_use_cert(self.ctx, certfile) if not keyfile: keyfile = certfile m2.ssl_ctx_use_privkey(self.ctx, keyfile) if not m2.ssl_ctx_check_privkey(self.ctx): raise ValueError('public/private key mismatch') def load_cert_chain(self, certchainfile, keyfile=None, callback=util.passphrase_callback): # type: (AnyStr, Optional[AnyStr], Callable) -> None """Load certificate chain and private key into the context. :param certchainfile: File object containing the PEM-encoded certificate chain. :param keyfile: File object containing the PEM-encoded private key. Default value of None indicates that the private key is to be found in 'certchainfile'. :param callback: Callable object to be invoked if the private key is passphrase-protected. Default callback provides a simple terminal-style input for the passphrase. """ m2.ssl_ctx_passphrase_callback(self.ctx, callback) m2.ssl_ctx_use_cert_chain(self.ctx, certchainfile) if not keyfile: keyfile = certchainfile m2.ssl_ctx_use_privkey(self.ctx, keyfile) if not m2.ssl_ctx_check_privkey(self.ctx): raise ValueError('public/private key mismatch') def set_client_CA_list_from_file(self, cafile): # type: (AnyStr) -> None """Load CA certs into the context. These CA certs are sent to the peer during *SSLv3 certificate request*. :param cafile: File object containing one or more PEM-encoded CA certificates concatenated together. """ m2.ssl_ctx_set_client_CA_list_from_file(self.ctx, cafile) # Deprecated. load_client_CA = load_client_ca = set_client_CA_list_from_file def load_verify_locations(self, cafile=None, capath=None): # type: (Optional[AnyStr], Optional[AnyStr]) -> int """Load CA certs into the context. These CA certs are used during verification of the peer's certificate. :param cafile: File containing one or more PEM-encoded CA certificates concatenated together. :param capath: Directory containing PEM-encoded CA certificates (one certificate per file). :return: 0 if the operation failed because CAfile and CApath are NULL or the processing at one of the locations specified failed. Check the error stack to find out the reason. 1 The operation succeeded. """ if cafile is None and capath is None: raise ValueError("cafile and capath can not both be None.") return m2.ssl_ctx_load_verify_locations(self.ctx, cafile, capath) # Deprecated. load_verify_info = load_verify_locations def set_session_id_ctx(self, id): # type: (bytes) -> None """Sets the session id for the SSL.Context w/in a session can be reused. :param id: Sessions are generated within a certain context. When exporting/importing sessions with i2d_SSL_SESSION/d2i_SSL_SESSION it would be possible, to re-import a session generated from another context (e.g. another application), which might lead to malfunctions. Therefore each application must set its own session id context sid_ctx which is used to distinguish the contexts and is stored in exported sessions. The sid_ctx can be any kind of binary data with a given length, it is therefore possible to use e.g. the name of the application and/or the hostname and/or service name. """ ret = m2.ssl_ctx_set_session_id_context(self.ctx, id) if not ret: raise Err.SSLError(Err.get_error_code(), '') def set_default_verify_paths(self): # type: () -> int """ Specifies that the default locations from which CA certs are loaded should be used. There is one default directory and one default file. The default CA certificates directory is called "certs" in the default OpenSSL directory. Alternatively the SSL_CERT_DIR environment variable can be defined to override this location. The default CA certificates file is called "cert.pem" in the default OpenSSL directory. Alternatively the SSL_CERT_FILE environment variable can be defined to override this location. @return 0 if the operation failed. A missing default location is still treated as a success. No error code is set. 1 The operation succeeded. """ ret = m2.ssl_ctx_set_default_verify_paths(self.ctx) if not ret: raise ValueError('Cannot use default SSL certificate store!') def set_allow_unknown_ca(self, ok): # type: (Union[int, bool]) -> None """Set the context to accept/reject a peer certificate if the certificate's CA is unknown. :param ok: True to accept, False to reject. """ self.allow_unknown_ca = ok def get_allow_unknown_ca(self): # type: () -> Union[int, bool] """Get the context's setting that accepts/rejects a peer certificate if the certificate's CA is unknown. FIXME 2Bconverted to bool """ return self.allow_unknown_ca def set_verify(self, mode, depth, callback=None): # type: (int, int, Optional[Callable]) -> None """ Set verify options. Most applications will need to call this method with the right options to make a secure SSL connection. :param mode: The verification mode to use. Typically at least SSL.verify_peer is used. Clients would also typically add SSL.verify_fail_if_no_peer_cert. :param depth: The maximum allowed depth of the certificate chain returned by the peer. :param callback: Callable that can be used to specify custom verification checks. """ if callback is None: m2.ssl_ctx_set_verify_default(self.ctx, mode) else: m2.ssl_ctx_set_verify(self.ctx, mode, callback) m2.ssl_ctx_set_verify_depth(self.ctx, depth) def get_verify_mode(self): # type: () -> int return m2.ssl_ctx_get_verify_mode(self.ctx) def get_verify_depth(self): # type: () -> int """Returns the verification mode currently set in the SSL Context.""" return m2.ssl_ctx_get_verify_depth(self.ctx) def set_tmp_dh(self, dhpfile): # type: (AnyStr) -> int """Load ephemeral DH parameters into the context. :param dhpfile: Filename of the file containing the PEM-encoded DH parameters. """ f = BIO.openfile(dhpfile) dhp = m2.dh_read_parameters(f.bio_ptr()) return m2.ssl_ctx_set_tmp_dh(self.ctx, dhp) def set_tmp_dh_callback(self, callback=None): # type: (Optional[Callable]) -> None """Sets the callback function for SSL.Context. :param callback: Callable to be used when a DH parameters are required. """ if callback is not None: m2.ssl_ctx_set_tmp_dh_callback(self.ctx, callback) def set_tmp_rsa(self, rsa): # type: (RSA.RSA) -> int """Load ephemeral RSA key into the context. :param rsa: RSA.RSA instance. """ if isinstance(rsa, RSA.RSA): return m2.ssl_ctx_set_tmp_rsa(self.ctx, rsa.rsa) else: raise TypeError("Expected an instance of RSA.RSA, got %s." % rsa) def set_tmp_rsa_callback(self, callback=None): # type: (Optional[Callable]) -> None """Sets the callback function to be used when a temporary/ephemeral RSA key is required. """ if callback is not None: m2.ssl_ctx_set_tmp_rsa_callback(self.ctx, callback) def set_info_callback(self, callback=cb.ssl_info_callback): # type: (Callable) -> None """Set a callback function to get state information. It can be used to get state information about the SSL connections that are created from this context. :param callback: Callback function. The default prints information to stderr. """ m2.ssl_ctx_set_info_callback(self.ctx, callback) def set_cipher_list(self, cipher_list): # type: (str) -> int """Sets the list of available ciphers. :param cipher_list: The format of the string is described in ciphers(1). :return: 1 if any cipher could be selected and 0 on complete failure. """ return m2.ssl_ctx_set_cipher_list(self.ctx, cipher_list) def add_session(self, session): # type: (Session) -> int """Add the session to the context. :param session: the session to be added. :return: 0 The operation failed. It was tried to add the same (identical) session twice. 1 The operation succeeded. """ return m2.ssl_ctx_add_session(self.ctx, session._ptr()) def remove_session(self, session): # type: (Session) -> int """Remove the session from the context. :param session: the session to be removed. :return: 0 The operation failed. The session was not found in the cache. 1 The operation succeeded. """ return m2.ssl_ctx_remove_session(self.ctx, session._ptr()) def get_session_timeout(self): # type: () -> int """Get current session timeout. Whenever a new session is created, it is assigned a maximum lifetime. This lifetime is specified by storing the creation time of the session and the timeout value valid at this time. If the actual time is later than creation time plus timeout, the session is not reused. Due to this realization, all sessions behave according to the timeout value valid at the time of the session negotiation. Changes of the timeout value do not affect already established sessions. Expired sessions are removed from the internal session cache, whenever SSL_CTX_flush_sessions(3) is called, either directly by the application or automatically (see SSL_CTX_set_session_cache_mode(3)) The default value for session timeout is decided on a per protocol basis, see SSL_get_default_timeout(3). All currently supported protocols have the same default timeout value of 300 seconds. SSL_CTX_set_timeout() returns the previously set timeout value. :return: the currently set timeout value. """ return m2.ssl_ctx_get_session_timeout(self.ctx) def set_session_timeout(self, timeout): # type: (int) -> int """Set new session timeout. See self.get_session_timeout() for explanation of the session timeouts. :param timeout: new timeout value. :return: the previously set timeout value. """ return m2.ssl_ctx_set_session_timeout(self.ctx, timeout) def set_session_cache_mode(self, mode): # type: (int) -> int """Enables/disables session caching. The mode is set by using m2.SSL_SESS_CACHE_* constants. :param mode: new mode value. :return: the previously set cache mode value. """ return m2.ssl_ctx_set_session_cache_mode(self.ctx, mode) def get_session_cache_mode(self): # type: () -> int """Gets the current session caching. The mode is set to m2.SSL_SESS_CACHE_* constants. :return: the previously set cache mode value. """ return m2.ssl_ctx_get_session_cache_mode(self.ctx) def set_options(self, op): # type: (int) -> int """Adds the options set via bitmask in options to the Context. !!! Options already set before are not cleared! The behaviour of the SSL library can be changed by setting several options. The options are coded as bitmasks and can be combined by a logical or operation (|). SSL.Context.set_options() and SSL.set_options() affect the (external) protocol behaviour of the SSL library. The (internal) behaviour of the API can be changed by using the similar SSL.Context.set_mode() and SSL.set_mode() functions. During a handshake, the option settings of the SSL object are used. When a new SSL object is created from a context using SSL(), the current option setting is copied. Changes to ctx do not affect already created SSL objects. SSL.clear() does not affect the settings. :param op: bitmask of additional options specified in SSL_CTX_set_options(3) manpage. :return: the new options bitmask after adding options. """ return m2.ssl_ctx_set_options(self.ctx, op) def get_cert_store(self): # type: () -> X509.X509 """ Get the certificate store associated with this context. :warning: The store is NOT refcounted, and as such can not be relied to be valid once the context goes away or is changed. """ return X509.X509_Store(m2.ssl_ctx_get_cert_store(self.ctx)) m2crypto-0.42.0/src/M2Crypto/SSL/SSLServer.py000066400000000000000000000037121465575656700205220ustar00rootroot00000000000000from __future__ import absolute_import, print_function """SSLServer Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.""" # M2Crypto from M2Crypto.SSL import SSLError from M2Crypto.SSL.Connection import Connection from M2Crypto.SSL.Context import Context # noqa from M2Crypto import util # noqa from socketserver import (BaseRequestHandler, BaseServer, TCPServer, ThreadingMixIn) import os if os.name != 'nt': from socketserver import ForkingMixIn from socket import socket # noqa from typing import Union # noqa __all__ = ['SSLServer', 'ForkingSSLServer', 'ThreadingSSLServer'] class SSLServer(TCPServer): def __init__(self, server_address, RequestHandlerClass, ssl_context, # noqa bind_and_activate=True): # type: (util.AddrType, BaseRequestHandler, Context, bool) -> None """ Superclass says: Constructor. May be extended, do not override. This class says: Ho-hum. """ BaseServer.__init__(self, server_address, RequestHandlerClass) self.ssl_ctx = ssl_context self.socket = Connection(self.ssl_ctx) if bind_and_activate: self.server_bind() self.server_activate() def handle_request(self): # type: () -> None request = None client_address = None try: request, client_address = self.get_request() if self.verify_request(request, client_address): self.process_request(request, client_address) except SSLError: self.handle_error(request, client_address) def handle_error(self, request, client_address): # type: (Union[socket, Connection], util.AddrType) -> None print('-' * 40) import traceback traceback.print_exc() print('-' * 40) class ThreadingSSLServer(ThreadingMixIn, SSLServer): pass if os.name != 'nt': class ForkingSSLServer(ForkingMixIn, SSLServer): pass m2crypto-0.42.0/src/M2Crypto/SSL/Session.py000066400000000000000000000034011465575656700203100ustar00rootroot00000000000000"""SSL Session Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" __all__ = ['Session', 'load_session'] from M2Crypto import BIO, Err, m2 from M2Crypto.SSL import SSLError from typing import AnyStr # noqa class Session(object): m2_ssl_session_free = m2.ssl_session_free def __init__(self, session, _pyfree=0): # type: (bytes, int) -> None assert session is not None self.session = session self._pyfree = _pyfree def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_ssl_session_free(self.session) def _ptr(self): # type: () -> bytes return self.session def as_text(self): # type: () -> bytes buf = BIO.MemoryBuffer() m2.ssl_session_print(buf.bio_ptr(), self.session) return buf.read_all() def as_der(self): # type: () -> bytes buf = BIO.MemoryBuffer() m2.i2d_ssl_session(buf.bio_ptr(), self.session) return buf.read_all() def write_bio(self, bio): # type: (BIO.BIO) -> int return m2.ssl_session_write_bio(bio.bio_ptr(), self.session) def get_time(self): # type: () -> int return m2.ssl_session_get_time(self.session) def set_time(self, t): # type: (int) -> int return m2.ssl_session_set_time(self.session, t) def get_timeout(self): # type: () -> int return m2.ssl_session_get_timeout(self.session) def set_timeout(self, t): # type: (int) -> int return m2.ssl_session_set_timeout(self.session, t) def load_session(pemfile): # type: (AnyStr) -> Session with BIO.openfile(pemfile) as f: cptr = m2.ssl_session_read_pem(f.bio_ptr()) return Session(cptr, 1) m2crypto-0.42.0/src/M2Crypto/SSL/TwistedProtocolWrapper.py000066400000000000000000000430701465575656700234010ustar00rootroot00000000000000""" Make Twisted use M2Crypto for SSL Copyright (c) 2004-2007 Open Source Applications Foundation. All rights reserved. FIXME THIS HAS NOT BEEN FINISHED. NEITHER PEP484 NOR PORT PYTHON3 HAS BEEN FINISHED. THE FURTHER WORK WILL BE DONE WHEN THE STATUS OF TWISTED IN THE PYTHON 3 (AND ASYNCIO) WORLD WILL BE CLEAR. """ __all__ = ['connectSSL', 'connectTCP', 'listenSSL', 'listenTCP', 'TLSProtocolWrapper'] import logging from functools import partial import twisted.internet.reactor import twisted.protocols.policies as policies from M2Crypto import BIO, X509, m2, util from M2Crypto.SSL.Checker import Checker, SSLVerificationError from twisted.internet.interfaces import ITLSTransport from twisted.protocols.policies import ProtocolWrapper from typing import AnyStr, Callable, Iterable, Optional # noqa from zope.interface import implementer log = logging.getLogger(__name__) def _alwaysSucceedsPostConnectionCheck(peerX509, expectedHost): return 1 def connectSSL(host, port, factory, contextFactory, timeout=30, bindAddress=None, reactor=twisted.internet.reactor, postConnectionCheck=Checker()): # type: (str, int, object, object, int, Optional[str], twisted.internet.reactor, Checker) -> reactor.connectTCP """ A convenience function to start an SSL/TLS connection using Twisted. See IReactorSSL interface in Twisted. """ wrappingFactory = policies.WrappingFactory(factory) wrappingFactory.protocol = lambda factory, wrappedProtocol: \ TLSProtocolWrapper(factory, wrappedProtocol, startPassThrough=0, client=1, contextFactory=contextFactory, postConnectionCheck=postConnectionCheck) return reactor.connectTCP(host, port, wrappingFactory, timeout, bindAddress) def connectTCP(host, port, factory, timeout=30, bindAddress=None, reactor=twisted.internet.reactor, postConnectionCheck=Checker()): # type: (str, int, object, int, Optional[util.AddrType], object, Callable) -> object """ A convenience function to start a TCP connection using Twisted. NOTE: You must call startTLS(ctx) to go into SSL/TLS mode. See IReactorTCP interface in Twisted. """ wrappingFactory = policies.WrappingFactory(factory) wrappingFactory.protocol = lambda factory, wrappedProtocol: \ TLSProtocolWrapper(factory, wrappedProtocol, startPassThrough=1, client=1, contextFactory=None, postConnectionCheck=postConnectionCheck) return reactor.connectTCP(host, port, wrappingFactory, timeout, bindAddress) def listenSSL(port, factory, contextFactory, backlog=5, interface='', reactor=twisted.internet.reactor, postConnectionCheck=_alwaysSucceedsPostConnectionCheck): """ A convenience function to listen for SSL/TLS connections using Twisted. See IReactorSSL interface in Twisted. """ wrappingFactory = policies.WrappingFactory(factory) wrappingFactory.protocol = lambda factory, wrappedProtocol: \ TLSProtocolWrapper(factory, wrappedProtocol, startPassThrough=0, client=0, contextFactory=contextFactory, postConnectionCheck=postConnectionCheck) return reactor.listenTCP(port, wrappingFactory, backlog, interface) def listenTCP(port, factory, backlog=5, interface='', reactor=twisted.internet.reactor, postConnectionCheck=None): """ A convenience function to listen for TCP connections using Twisted. NOTE: You must call startTLS(ctx) to go into SSL/TLS mode. See IReactorTCP interface in Twisted. """ wrappingFactory = policies.WrappingFactory(factory) wrappingFactory.protocol = lambda factory, wrappedProtocol: \ TLSProtocolWrapper(factory, wrappedProtocol, startPassThrough=1, client=0, contextFactory=None, postConnectionCheck=postConnectionCheck) return reactor.listenTCP(port, wrappingFactory, backlog, interface) class _BioProxy(object): """ The purpose of this class is to eliminate the __del__ method from TLSProtocolWrapper, and thus letting it be garbage collected. """ m2_bio_free_all = m2.bio_free_all def __init__(self, bio): self.bio = bio def _ptr(self): return self.bio def __del__(self): if self.bio is not None: self.m2_bio_free_all(self.bio) class _SSLProxy(object): """ The purpose of this class is to eliminate the __del__ method from TLSProtocolWrapper, and thus letting it be garbage collected. """ m2_ssl_free = m2.ssl_free def __init__(self, ssl): self.ssl = ssl def _ptr(self): return self.ssl def __del__(self): if self.ssl is not None: self.m2_ssl_free(self.ssl) @implementer(ITLSTransport) class TLSProtocolWrapper(ProtocolWrapper): """ A SSL/TLS protocol wrapper to be used with Twisted. Typically you would not use this class directly. Use connectTCP, connectSSL, listenTCP, listenSSL functions defined above, which will hook in this class. """ def __init__(self, factory, wrappedProtocol, startPassThrough, client, contextFactory, postConnectionCheck): # type: (policies.WrappingFactory, object, int, int, object, Checker) -> None """ :param factory: :param wrappedProtocol: :param startPassThrough: If true we won't encrypt at all. Need to call startTLS() later to switch to SSL/TLS. :param client: True if this should be a client protocol. :param contextFactory: Factory that creates SSL.Context objects. The called function is getContext(). :param postConnectionCheck: The post connection check callback that will be called just after connection has been established but before any real data has been exchanged. The first argument to this function is an X509 object, the second is the expected host name string. """ # ProtocolWrapper.__init__(self, factory, wrappedProtocol) # XXX: Twisted 2.0 has a new addition where the wrappingFactory is # set as the factory of the wrappedProtocol. This is an issue # as the wrap should be transparent. What we want is # the factory of the wrappedProtocol to be the wrappedFactory and # not the outer wrappingFactory. This is how it was implemented in # Twisted 1.3 self.factory = factory self.wrappedProtocol = wrappedProtocol # wrappedProtocol == client/server instance # factory.wrappedFactory == client/server factory self.data = b'' # Clear text to encrypt and send self.encrypted = b'' # Encrypted data we need to decrypt and pass on self.tlsStarted = 0 # SSL/TLS mode or pass through self.checked = 0 # Post connection check done or not self.isClient = client self.helloDone = 0 # True when hello has been sent if postConnectionCheck is None: self.postConnectionCheck = _alwaysSucceedsPostConnectionCheck else: self.postConnectionCheck = postConnectionCheck if not startPassThrough: self.startTLS(contextFactory.getContext()) def clear(self): """ Clear this instance, after which it is ready for reuse. """ if getattr(self, 'tlsStarted', 0): self.sslBio = None self.ssl = None self.internalBio = None self.networkBio = None self.data = b'' self.encrypted = b'' self.tlsStarted = 0 self.checked = 0 self.isClient = 1 self.helloDone = 0 # We can reuse self.ctx and it will be deleted automatically # when this instance dies def startTLS(self, ctx): """ Start SSL/TLS. If this is not called, this instance just passes data through untouched. """ # NOTE: This method signature must match the startTLS() method Twisted # expects transports to have. This will be called automatically # by Twisted in STARTTLS situations, for example with SMTP. if self.tlsStarted: raise Exception('TLS already started') self.ctx = ctx self.internalBio = m2.bio_new(m2.bio_s_bio()) m2.bio_set_write_buf_size(self.internalBio, 0) self.networkBio = _BioProxy(m2.bio_new(m2.bio_s_bio())) m2.bio_set_write_buf_size(self.networkBio._ptr(), 0) m2.bio_make_bio_pair(self.internalBio, self.networkBio._ptr()) self.sslBio = _BioProxy(m2.bio_new(m2.bio_f_ssl())) self.ssl = _SSLProxy(m2.ssl_new(self.ctx.ctx)) if self.isClient: m2.ssl_set_connect_state(self.ssl._ptr()) else: m2.ssl_set_accept_state(self.ssl._ptr()) m2.ssl_set_bio(self.ssl._ptr(), self.internalBio, self.internalBio) m2.bio_set_ssl(self.sslBio._ptr(), self.ssl._ptr(), m2.bio_noclose) # Need this for writes that are larger than BIO pair buffers mode = m2.ssl_get_mode(self.ssl._ptr()) m2.ssl_set_mode(self.ssl._ptr(), mode | m2.SSL_MODE_ENABLE_PARTIAL_WRITE | m2.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER) self.tlsStarted = 1 def write(self, data): # type: (bytes) -> None if not self.tlsStarted: ProtocolWrapper.write(self, data) return try: encryptedData = self._encrypt(data) ProtocolWrapper.write(self, encryptedData) self.helloDone = 1 except BIO.BIOError as e: # See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS # for the error codes returned by SSL_get_verify_result. e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0]) raise e def writeSequence(self, data): # type: (Iterable[bytes]) -> None if not self.tlsStarted: ProtocolWrapper.writeSequence(self, b''.join(data)) return self.write(b''.join(data)) def loseConnection(self): # XXX Do we need to do m2.ssl_shutdown(self.ssl._ptr())? ProtocolWrapper.loseConnection(self) def connectionMade(self): ProtocolWrapper.connectionMade(self) if self.tlsStarted and self.isClient and not self.helloDone: self._clientHello() def dataReceived(self, data): # type: (bytes) -> None if not self.tlsStarted: ProtocolWrapper.dataReceived(self, data) return self.encrypted += data try: while 1: decryptedData = self._decrypt() self._check() encryptedData = self._encrypt() ProtocolWrapper.write(self, encryptedData) ProtocolWrapper.dataReceived(self, decryptedData) if decryptedData == b'' and encryptedData == b'': break except BIO.BIOError as e: # See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS # for the error codes returned by SSL_get_verify_result. e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0]) raise e def connectionLost(self, reason): # type: (AnyStr) -> None self.clear() ProtocolWrapper.connectionLost(self, reason) def _check(self): if not self.checked and m2.ssl_is_init_finished(self.ssl._ptr()): x509 = m2.ssl_get_peer_cert(self.ssl._ptr()) if x509 is not None: x509 = X509.X509(x509, 1) if self.isClient: host = self.transport.addr[0] else: host = self.transport.getPeer().host if not self.postConnectionCheck(x509, host): raise SSLVerificationError('post connection check') self.checked = 1 def _clientHello(self): try: # We rely on OpenSSL implicitly starting with client hello # when we haven't yet established an SSL connection encryptedData = self._encrypt(clientHello=1) ProtocolWrapper.write(self, encryptedData) self.helloDone = 1 except BIO.BIOError as e: # See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS # for the error codes returned by SSL_get_verify_result. e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0]) raise e # Optimizations to reduce attribute accesses @property def _get_wr_guar_ssl(self): # type: () -> Callable[[], int] """Return max. length of data can be written to the BIO. Writes larger than this value will return a value from BIO_write() less than the amount requested or if the buffer is full request a retry. """ return partial(m2.bio_ctrl_get_write_guarantee, self.sslBio._ptr()) @property def _get_wr_guar_net(self): # type: () -> Callable[[], int] return partial(m2.bio_ctrl_get_write_guarantee, self.networkBio._ptr()) @property def _shoud_retry_ssl(self): # type: () -> Callable[[], int] # BIO_should_retry() is true if the call that produced this # condition should then be retried at a later time. return partial(m2.bio_should_retry, self.sslBio._ptr()) @property def _shoud_retry_net(self): # type: () -> Callable[[], int] return partial(m2.bio_should_retry, self.networkBio._ptr()) @property def _ctrl_pend_ssl(self): # type: () -> Callable[[], int] # size_t BIO_ctrl_pending(BIO *b); # BIO_ctrl_pending() return the number of pending characters in # the BIOs read and write buffers. return partial(m2.bio_ctrl_pending, self.sslBio._ptr()) @property def _ctrl_pend_net(self): # type: () -> Callable[[], int] return partial(m2.bio_ctrl_pending, self.networkBio._ptr()) @property def _write_ssl(self): # type: () -> Callable[[bytes], int] # All these functions return either the amount of data # successfully read or written (if the return value is # positive) or that no data was successfully read or written # if the result is 0 or -1. If the return value is -2 then # the operation is not implemented in the specific BIO type. return partial(m2.bio_write, self.sslBio._ptr()) @property def _write_net(self): # type: () -> Callable[[bytes], int] return partial(m2.bio_write, self.networkBio._ptr()) @property def _read_ssl(self): # type: () -> Callable[[int], Optional[bytes]] return partial(m2.bio_read, self.sslBio._ptr()) @property def _read_net(self): # type: () -> Callable[[int], Optional[bytes]] return partial(m2.bio_read, self.networkBio._ptr()) def _encrypt(self, data=b'', clientHello=0): # type: (bytes, int) -> bytes """ :param data: :param clientHello: :return: """ encryptedData = b'' self.data += data while 1: if (self._get_wr_guar_ssl() > 0 and self.data != b'') or clientHello: r = self._write_ssl(self.data) if r <= 0: if not self._shoud_retry_ssl(): raise IOError( ('Data left to be written to {}, ' + 'but cannot retry SSL connection!').format(self.sslBio)) else: assert self.checked self.data = self.data[r:] pending = self._ctrl_pend_net() if pending: d = self._read_net(pending) if d is not None: # This is strange, but d can be None encryptedData += d else: assert(self._shoud_retry_net()) else: break return encryptedData def _decrypt(self, data=b''): # type: (bytes) -> bytes self.encrypted += data decryptedData = b'' while 1: if self._get_wr_guar_ssl() > 0 and self.encrypted != b'': r = self._write_net(self.encrypted) if r <= 0: if not self._shoud_retry_net(): raise IOError( ('Data left to be written to {}, ' + 'but cannot retry SSL connection!').format(self.networkBio)) else: self.encrypted = self.encrypted[r:] pending = self._ctrl_pend_ssl() if pending: d = self._read_ssl(pending) if d is not None: # This is strange, but d can be None decryptedData += d else: assert(self._shoud_retry_ssl()) else: break return decryptedData m2crypto-0.42.0/src/M2Crypto/SSL/__init__.py000066400000000000000000000023571465575656700204350ustar00rootroot00000000000000from __future__ import absolute_import """M2Crypto SSL services. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" import socket, os # M2Crypto from M2Crypto import _m2crypto as m2 class SSLError(Exception): pass class SSLTimeoutError(SSLError, socket.timeout): pass m2.ssl_init(SSLError, SSLTimeoutError) # M2Crypto.SSL from M2Crypto.SSL.Cipher import Cipher, Cipher_Stack from M2Crypto.SSL.Connection import Connection from M2Crypto.SSL.Context import Context from M2Crypto.SSL.SSLServer import SSLServer, ThreadingSSLServer if os.name != 'nt': from M2Crypto.SSL.SSLServer import ForkingSSLServer from M2Crypto.SSL.timeout import timeout, struct_to_timeout, struct_size verify_none = m2.SSL_VERIFY_NONE # type: int verify_peer = m2.SSL_VERIFY_PEER # type: int verify_fail_if_no_peer_cert = m2.SSL_VERIFY_FAIL_IF_NO_PEER_CERT # type: int verify_client_once = m2.SSL_VERIFY_CLIENT_ONCE # type: int verify_crl_check_chain = m2.VERIFY_CRL_CHECK_CHAIN # type: int verify_crl_check_leaf = m2.VERIFY_CRL_CHECK_LEAF # type: int SSL_SENT_SHUTDOWN = m2.SSL_SENT_SHUTDOWN # type: int SSL_RECEIVED_SHUTDOWN = m2.SSL_RECEIVED_SHUTDOWN # type: int op_all = m2.SSL_OP_ALL # type: int op_no_sslv2 = m2.SSL_OP_NO_SSLv2 # type: int m2crypto-0.42.0/src/M2Crypto/SSL/cb.py000066400000000000000000000052061465575656700172560ustar00rootroot00000000000000from __future__ import absolute_import """SSL callbacks Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" import sys from M2Crypto import m2 from typing import Any # noqa __all__ = ['unknown_issuer', 'ssl_verify_callback_stub', 'ssl_verify_callback', 'ssl_verify_callback_allow_unknown_ca', 'ssl_info_callback'] def ssl_verify_callback_stub(ssl_ctx_ptr, x509_ptr, errnum, errdepth, ok): # Deprecated return ok unknown_issuer = [ m2.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, m2.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, m2.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, m2.X509_V_ERR_CERT_UNTRUSTED, ] def ssl_verify_callback(ssl_ctx_ptr, x509_ptr, errnum, errdepth, ok): # type: (bytes, bytes, int, int, int) -> int # Deprecated from M2Crypto.SSL.Context import Context ssl_ctx = Context.ctxmap()[int(ssl_ctx_ptr)] if errnum in unknown_issuer: if ssl_ctx.get_allow_unknown_ca(): sys.stderr.write("policy: %s: permitted...\n" % (m2.x509_get_verify_error(errnum))) sys.stderr.flush() ok = 1 # CRL checking goes here... if ok: if ssl_ctx.get_verify_depth() >= errdepth: ok = 1 else: ok = 0 return ok def ssl_verify_callback_allow_unknown_ca(ok, store): # type: (int, Any) -> int errnum = store.get_error() if errnum in unknown_issuer: ok = 1 return ok # Cribbed from OpenSSL's apps/s_cb.c. def ssl_info_callback(where, ret, ssl_ptr): # type: (int, int, bytes) -> None w = where & ~m2.SSL_ST_MASK if w & m2.SSL_ST_CONNECT: state = "SSL connect" elif w & m2.SSL_ST_ACCEPT: state = "SSL accept" else: state = "SSL state unknown" if where & m2.SSL_CB_LOOP: sys.stderr.write("LOOP: %s: %s\n" % (state, m2.ssl_get_state_v(ssl_ptr))) sys.stderr.flush() return if where & m2.SSL_CB_EXIT: if not ret: sys.stderr.write("FAILED: %s: %s\n" % (state, m2.ssl_get_state_v(ssl_ptr))) sys.stderr.flush() else: sys.stderr.write("INFO: %s: %s\n" % (state, m2.ssl_get_state_v(ssl_ptr))) sys.stderr.flush() return if where & m2.SSL_CB_ALERT: if where & m2.SSL_CB_READ: w = 'read' else: w = 'write' sys.stderr.write("ALERT: %s: %s: %s\n" % (w, m2.ssl_get_alert_type_v(ret), m2.ssl_get_alert_desc_v(ret))) sys.stderr.flush() return m2crypto-0.42.0/src/M2Crypto/SSL/timeout.py000066400000000000000000000030401465575656700203520ustar00rootroot00000000000000"""Support for SSL socket timeouts. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. Copyright 2008 Heikki Toivonen. All rights reserved. """ __all__ = ['DEFAULT_TIMEOUT', 'timeout', 'struct_to_timeout', 'struct_size'] import sys import struct from M2Crypto.util import is_32bit, is_libc_musl DEFAULT_TIMEOUT = 600 # type: int class timeout(object): def __init__(self, sec=DEFAULT_TIMEOUT, microsec=0): # type: (int, int) -> None self.sec = sec self.microsec = microsec def pack(self): if sys.platform == 'win32': millisec = int(self.sec * 1000 + round(float(self.microsec) / 1000)) binstr = struct.pack('l', millisec) else: if is_32bit() and not is_libc_musl(): binstr = struct.pack('ii', self.sec, self.microsec) else: binstr = struct.pack('ll', self.sec, self.microsec) return binstr def struct_to_timeout(binstr): # type: (bytes) -> timeout if sys.platform == 'win32': millisec = struct.unpack('l', binstr)[0] # On py3, int/int performs exact division and returns float. We want # the whole number portion of the exact division result: sec = int(millisec / 1000) microsec = (millisec % 1000) * 1000 else: (sec, microsec) = struct.unpack('ll', binstr) return timeout(sec, microsec) def struct_size(): # type: () -> int if sys.platform == 'win32': return struct.calcsize('l') else: return struct.calcsize('ll') m2crypto-0.42.0/src/M2Crypto/X509.py000066400000000000000000001322311465575656700166750ustar00rootroot00000000000000from __future__ import absolute_import """M2Crypto wrapper for OpenSSL X509 API. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2004-2007 OSAF. All Rights Reserved. Author: Heikki Toivonen """ import binascii import logging from M2Crypto import ASN1, BIO, EVP, m2 # noqa from typing import AnyStr, List, Optional # noqa FORMAT_DER = 0 FORMAT_PEM = 1 if hasattr(m2, "VERIFY_ALLOW_PROXY_CERTS"): verify_allow_proxy_certs = m2.VERIFY_ALLOW_PROXY_CERTS if hasattr(m2, "VERIFY_CB_ISSUER_CHECK"): verify_cb_issuer_check = m2.VERIFY_CB_ISSUER_CHECK if hasattr(m2, "VERIFY_CHECK_SS_SIGNATURE"): verify_check_ss_signature = m2.VERIFY_CHECK_SS_SIGNATURE if hasattr(m2, "VERIFY_CRL_CHECK"): verify_crl_check = m2.VERIFY_CRL_CHECK if hasattr(m2, "VERIFY_CRL_CHECK_ALL"): verify_crl_check_all = m2.VERIFY_CRL_CHECK_ALL if hasattr(m2, "VERIFY_EXPLICIT_POLICY"): verify_explicit_policy = m2.VERIFY_EXPLICIT_POLICY if hasattr(m2, "VERIFY_EXTENDED_CRL_SUPPORT"): verify_extended_crl_support = m2.VERIFY_EXTENDED_CRL_SUPPORT if hasattr(m2, "VERIFY_IGNORE_CRITICAL"): verify_ignore_critical = m2.VERIFY_IGNORE_CRITICAL if hasattr(m2, "VERIFY_INHIBIT_ANY"): verify_inhibit_any = m2.VERIFY_INHIBIT_ANY if hasattr(m2, "VERIFY_INHIBIT_MAP"): verify_inhibit_map = m2.VERIFY_INHIBIT_MAP if hasattr(m2, "VERIFY_NO_ALT_CHAINS"): verify_no_alt_chains = m2.VERIFY_NO_ALT_CHAINS if hasattr(m2, "VERIFY_NO_CHECK_TIME"): verify_no_check_time = m2.VERIFY_NO_CHECK_TIME if hasattr(m2, "VERIFY_NOTIFY_POLICY"): verify_notify_policy = m2.VERIFY_NOTIFY_POLICY if hasattr(m2, "VERIFY_PARTIAL_CHAIN"): verify_partial_chain = m2.VERIFY_PARTIAL_CHAIN if hasattr(m2, "VERIFY_POLICY_CHECK"): verify_policy_check = m2.VERIFY_POLICY_CHECK if hasattr(m2, "VERIFY_TRUSTED_FIRST"): verify_trusted_first = m2.VERIFY_TRUSTED_FIRST if hasattr(m2, "VERIFY_USE_DELTAS"): verify_use_deltas = m2.VERIFY_USE_DELTAS if hasattr(m2, "VERIFY_X509_STRICT"): verify_x509_strict = m2.VERIFY_X509_STRICT log = logging.getLogger(__name__) class X509Error(ValueError): pass m2.x509_init(X509Error) V_OK = m2.X509_V_OK # type: int def x509_store_default_cb(ok, ctx): # type: (int, X509_Store_Context) -> int return ok def new_extension(name, value, critical=0, _pyfree=1): # type: (str, bytes, int, int) -> X509_Extension """ Create new X509_Extension instance. """ if name == 'subjectKeyIdentifier' and \ value.strip('0123456789abcdefABCDEF:') != '': raise ValueError('value must be precomputed hash') ctx = m2.x509v3_set_nconf() x509_ext_ptr = m2.x509v3_ext_conf(None, ctx, name, value) if x509_ext_ptr is None: raise X509Error( "Cannot create X509_Extension with name '%s' and value '%s'" % (name, value)) x509_ext = X509_Extension(x509_ext_ptr, _pyfree) x509_ext.set_critical(critical) return x509_ext class X509_Extension(object): """ X509 Extension """ m2_x509_extension_free = m2.x509_extension_free def __init__(self, x509_ext_ptr=None, _pyfree=1): # type: (Optional[bytes], int) -> None self.x509_ext = x509_ext_ptr self._pyfree = _pyfree def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0) and self.x509_ext: self.m2_x509_extension_free(self.x509_ext) def _ptr(self): # type: () -> bytes return self.x509_ext def set_critical(self, critical=1): # type: (int) -> int """ Mark this extension critical or noncritical. By default an extension is not critical. :param critical: Nonzero sets this extension as critical. Calling this method without arguments will set this extension to critical. :return: 1 for success, 0 for failure """ return m2.x509_extension_set_critical(self.x509_ext, critical) def get_critical(self): # type: () -> int """ Return whether or not this is a critical extension. :return: Nonzero if this is a critical extension. """ return m2.x509_extension_get_critical(self.x509_ext) def get_name(self): # type: () -> str """ Get the extension name, for example 'subjectAltName'. """ out = m2.x509_extension_get_name(self.x509_ext) return out.decode() if isinstance(out, bytes) else out def get_value(self, flag=0, indent=0): # type: (int, int) -> str """ Get the extension value, for example 'DNS:www.example.com'. :param flag: Flag to control what and how to print. :param indent: How many spaces to print before actual value. """ buf = BIO.MemoryBuffer() m2.x509_ext_print(buf.bio_ptr(), self.x509_ext, flag, indent) out = buf.read_all() return out.decode() if isinstance(out, bytes) else out class X509_Extension_Stack(object): """ X509 Extension Stack :warning: Do not modify the underlying OpenSSL stack except through this interface, or use any OpenSSL functions that do so indirectly. Doing so will get the OpenSSL stack and the internal pystack of this class out of sync, leading to python memory leaks, exceptions or even python crashes! """ m2_sk_x509_extension_free = m2.sk_x509_extension_free def __init__(self, stack=None, _pyfree=0): # type: (Optional[bytes], int) -> None if stack is not None: self.stack = stack self._pyfree = _pyfree num = m2.sk_x509_extension_num(self.stack) for i in range(num): self.pystack.append(X509_Extension( m2.sk_x509_extension_value(self.stack, i), _pyfree=_pyfree)) else: self.stack = m2.sk_x509_extension_new_null() self._pyfree = 1 self.pystack = [] # This must be kept in sync with self.stack def __del__(self): # type: () -> None # see BIO.py - unbalanced __init__ / __del__ if getattr(self, '_pyfree', 0): self.m2_sk_x509_extension_free(self.stack) def __len__(self): # type: () -> int assert m2.sk_x509_extension_num(self.stack) == len(self.pystack) return len(self.pystack) def __getitem__(self, idx): # type: (int) -> X509_Extension return self.pystack[idx] def __iter__(self): return iter(self.pystack) def _ptr(self): # type: () -> bytes return self.stack def push(self, x509_ext): # type: (X509_Extension) -> int """ Push X509_Extension object onto the stack. :param x509_ext: X509_Extension object to be pushed onto the stack. :return: The number of extensions on the stack. """ self.pystack.append(x509_ext) ret = m2.sk_x509_extension_push(self.stack, x509_ext._ptr()) assert ret == len(self.pystack) return ret def pop(self): # type: () -> X509_Extension """ Pop X509_Extension object from the stack. :return: X509_Extension popped """ x509_ext_ptr = m2.sk_x509_extension_pop(self.stack) if x509_ext_ptr is None: assert len(self.pystack) == 0 return None return self.pystack.pop() class X509_Name_Entry(object): """ X509 Name Entry """ m2_x509_name_entry_free = m2.x509_name_entry_free def __init__(self, x509_name_entry, _pyfree=0): # type: (bytes, int) -> None """ :param x509_name_entry: this should be OpenSSL X509_NAME_ENTRY binary :param _pyfree: """ self.x509_name_entry = x509_name_entry self._pyfree = _pyfree def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_x509_name_entry_free(self.x509_name_entry) def _ptr(self): # type: () -> bytes return self.x509_name_entry def set_object(self, asn1obj): # type: (ASN1.ASN1_Object) -> int """ Sets the field name to asn1obj :param asn1obj: :return: 0 on failure, 1 on success """ return m2.x509_name_entry_set_object(self.x509_name_entry, asn1obj._ptr()) def set_data(self, data, type=ASN1.MBSTRING_ASC): # type: (bytes, int) -> int """ Sets the field name to asn1obj :param data: data in a binary form to be set :return: 0 on failure, 1 on success """ return m2.x509_name_entry_set_data(self.x509_name_entry, type, data) def get_object(self): # type: () -> ASN1.ASN1_Object return ASN1.ASN1_Object( m2.x509_name_entry_get_object(self.x509_name_entry)) def get_data(self): # type: () -> ASN1.ASN1_String return ASN1.ASN1_String( m2.x509_name_entry_get_data(self.x509_name_entry)) def create_by_txt(self, field, type, entry, len): return m2.x509_name_entry_create_by_txt(self.x509_name_entry._ptr(), field, type, entry, len) class X509_Name(object): """ X509 Name """ nid = {'C': m2.NID_countryName, 'SP': m2.NID_stateOrProvinceName, 'ST': m2.NID_stateOrProvinceName, 'stateOrProvinceName': m2.NID_stateOrProvinceName, 'L': m2.NID_localityName, 'localityName': m2.NID_localityName, 'O': m2.NID_organizationName, 'organizationName': m2.NID_organizationName, 'OU': m2.NID_organizationalUnitName, 'organizationUnitName': m2.NID_organizationalUnitName, 'CN': m2.NID_commonName, 'commonName': m2.NID_commonName, 'Email': m2.NID_pkcs9_emailAddress, 'emailAddress': m2.NID_pkcs9_emailAddress, 'serialNumber': m2.NID_serialNumber, 'SN': m2.NID_surname, 'surname': m2.NID_surname, 'GN': m2.NID_givenName, 'givenName': m2.NID_givenName } m2_x509_name_free = m2.x509_name_free def __init__(self, x509_name=None, _pyfree=0): # type: (Optional[bytes], int) -> None """ :param x509_name: this should be OpenSSL X509_NAME binary :param _pyfree: """ if x509_name is not None: assert m2.x509_name_type_check(x509_name), "'x509_name' type error" self.x509_name = x509_name self._pyfree = _pyfree else: self.x509_name = m2.x509_name_new() self._pyfree = 1 def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_x509_name_free(self.x509_name) def __str__(self): # type: () -> bytes assert m2.x509_name_type_check(self.x509_name), \ "'x509_name' type error" return m2.x509_name_oneline(self.x509_name) def __getattr__(self, attr): # type: (str) -> str if attr in self.nid: assert m2.x509_name_type_check(self.x509_name), \ "'x509_name' type error" out = m2.x509_name_by_nid(self.x509_name, self.nid[attr]) return out.decode() if isinstance(out, bytes) else out if attr in self.__dict__: return self.__dict__[attr] raise AttributeError(self, attr) def __setattr__(self, attr, value): # type: (str, AnyStr) -> int """ :return: 1 for success of 0 if an error occurred. """ if attr in self.nid: assert m2.x509_name_type_check(self.x509_name), \ "'x509_name' type error" value = value.encode() if isinstance(value, str) else value return m2.x509_name_set_by_nid(self.x509_name, self.nid[attr], value) self.__dict__[attr] = value def __len__(self): # type: () -> int return m2.x509_name_entry_count(self.x509_name) def __getitem__(self, idx): # type: (int) -> X509_Name_Entry if not 0 <= idx < self.entry_count(): raise IndexError("index out of range") return X509_Name_Entry(m2.x509_name_get_entry(self.x509_name, idx)) def __iter__(self): for i in range(self.entry_count()): yield self[i] def _ptr(self): assert m2.x509_name_type_check(self.x509_name), \ "'x509_name' type error" return self.x509_name def add_entry_by_txt(self, field, type, entry, len, loc, set): # entry_type: (str, int, bytes, int, int, int) -> int """ Add X509_Name field whose name is identified by its name. :param field: name of the entry :param type: use MBSTRING_ASC or MBSTRING_UTF8 (or standard ASN1 type like V_ASN1_IA5STRING) :param entry: value :param len: buf_len of the entry (-1 and the length is computed automagically) The ``loc`` and ``set`` parameters determine where a new entry should be added. For almost all applications loc can be set to -1 and set to 0. This adds a new entry to the end of name as a single valued RelativeDistinguishedName (RDN). :param loc: determines the index where the new entry is inserted: if it is -1 it is appended. :param set: determines how the new type is added. If it is zero a new RDN is created. If set is -1 or 1 it is added to the previous or next RDN structure respectively. This will then be a multivalued RDN: since multivalues RDNs are very seldom used set is almost always set to zero. :return: 1 for success of 0 if an error occurred. """ entry = entry.decode() if isinstance(entry, bytes) else entry return m2.x509_name_add_entry_by_txt(self.x509_name, field, type, entry, len, loc, set) def entry_count(self): # type: () -> int return m2.x509_name_entry_count(self.x509_name) def get_entries_by_nid(self, nid): # type: (int) -> List[X509_Name_Entry] """ Retrieve the next index matching nid. :param nid: name of the entry (as m2.NID* constants) :return: list of X509_Name_Entry items """ ret = [] lastpos = -1 while True: lastpos = m2.x509_name_get_index_by_nid(self.x509_name, nid, lastpos) if lastpos == -1: break ret.append(self[lastpos]) return ret def as_text(self, indent=0, flags=m2.XN_FLAG_COMPAT): # type: (int, int) -> str """ as_text returns the name as a string. :param indent: Each line in multiline format is indented by this many spaces. :param flags: Flags that control how the output should be formatted. """ assert m2.x509_name_type_check(self.x509_name), \ "'x509_name' type error" buf = BIO.MemoryBuffer() m2.x509_name_print_ex(buf.bio_ptr(), self.x509_name, indent, flags) out = buf.read_all() return out.decode() if isinstance(out, bytes) else out def as_der(self): # type: () -> bytes assert m2.x509_name_type_check(self.x509_name), \ "'x509_name' type error" return m2.x509_name_get_der(self.x509_name) def as_hash(self): # type: () -> int assert m2.x509_name_type_check(self.x509_name), \ "'x509_name' type error" return m2.x509_name_hash(self.x509_name) class X509(object): """ X.509 Certificate """ m2_x509_free = m2.x509_free def __init__(self, x509=None, _pyfree=0): # type: (Optional[bytes], int) -> None """ :param x509: binary representation of the underlying OpenSSL X509 object. :param _pyfree: """ if x509 is not None: assert m2.x509_type_check(x509), "'x509' type error" self.x509 = x509 self._pyfree = _pyfree else: self.x509 = m2.x509_new() self._pyfree = 1 def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_x509_free(self.x509) def _ptr(self): # type: () -> bytes assert m2.x509_type_check(self.x509), "'x509' type error" return self.x509 def as_text(self): # type: () -> str assert m2.x509_type_check(self.x509), "'x509' type error" buf = BIO.MemoryBuffer() m2.x509_print(buf.bio_ptr(), self.x509) out = buf.read_all() return out.decode() if isinstance(out, bytes) else out def as_der(self): # type: () -> bytes assert m2.x509_type_check(self.x509), "'x509' type error" return m2.i2d_x509(self.x509) def as_pem(self): # type: () -> bytes buf = BIO.MemoryBuffer() m2.x509_write_pem(buf.bio_ptr(), self.x509) return buf.read_all() def save_pem(self, filename): # type: (AnyStr) -> int """ :param filename: name of the file to be loaded :return: 1 for success or 0 for failure """ with BIO.openfile(filename, 'wb') as bio: return m2.x509_write_pem(bio.bio_ptr(), self.x509) def save(self, filename, format=FORMAT_PEM): # type: (AnyStr, int) -> int """ Saves X.509 certificate to a file. Default output format is PEM. :param filename: Name of the file the cert will be saved to. :param format: Controls what output format is used to save the cert. Either FORMAT_PEM or FORMAT_DER to save in PEM or DER format. Raises a ValueError if an unknow format is used. :return: 1 for success or 0 for failure """ with BIO.openfile(filename, 'wb') as bio: if format == FORMAT_PEM: return m2.x509_write_pem(bio.bio_ptr(), self.x509) elif format == FORMAT_DER: return m2.i2d_x509_bio(bio.bio_ptr(), self.x509) else: raise ValueError( "Unknown filetype. Must be either FORMAT_PEM or FORMAT_DER") def set_version(self, version): # type: (int) -> int """ Set version of the certificate. :param version: Version number. :return: Returns 0 on failure. """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_set_version(self.x509, version) def set_not_before(self, asn1_time): # type: (ASN1.ASN1_TIME) -> int """ :return: 1 on success, 0 on failure """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_set_not_before(self.x509, asn1_time._ptr()) def set_not_after(self, asn1_time): # type: (ASN1.ASN1_TIME) -> int """ :return: 1 on success, 0 on failure """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_set_not_after(self.x509, asn1_time._ptr()) def set_subject_name(self, name): # type: (X509_Name) -> int """ :return: 1 on success, 0 on failure """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_set_subject_name(self.x509, name.x509_name) def set_issuer_name(self, name): # type: (X509_Name) -> int """ :return: 1 on success, 0 on failure """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_set_issuer_name(self.x509, name.x509_name) def get_version(self): # type: () -> int assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_get_version(self.x509) def get_serial_number(self): # type: () -> ASN1.ASN1_Integer assert m2.x509_type_check(self.x509), "'x509' type error" asn1_integer = m2.x509_get_serial_number(self.x509) return m2.asn1_integer_get(asn1_integer) def set_serial_number(self, serial): # type: (ASN1.ASN1_Integer) -> int """ Set serial number. :param serial: Serial number. :return 1 for success and 0 for failure. """ assert m2.x509_type_check(self.x509), "'x509' type error" # This "magically" changes serial since asn1_integer # is C pointer to x509's internal serial number. asn1_integer = m2.x509_get_serial_number(self.x509) return m2.asn1_integer_set(asn1_integer, serial) # XXX Or should I do this? # asn1_integer = m2.asn1_integer_new() # m2.asn1_integer_set(asn1_integer, serial) # return m2.x509_set_serial_number(self.x509, asn1_integer) def get_not_before(self): # type: () -> ASN1.ASN1_TIME assert m2.x509_type_check(self.x509), "'x509' type error" # ASN1_TIME_dup() as internal ref. depends on self being referenced ref = ASN1.ASN1_TIME(m2.x509_get_not_before(self.x509)) out = ASN1.ASN1_TIME(_pyfree=1) out.set_datetime(ref.get_datetime()) return out def get_not_after(self): # type: () -> ASN1.ASN1_TIME assert m2.x509_type_check(self.x509), "'x509' type error" # ASN1_TIME_dup() as internal ref. depends on self being referenced ref = ASN1.ASN1_TIME(m2.x509_get_not_after(self.x509)) out = ASN1.ASN1_TIME(_pyfree=1) out.set_datetime(ref.get_datetime()) if 'Bad time value' in str(out): raise X509Error( '''M2Crypto cannot handle dates after year 2050. See RFC 5280 4.1.2.5 for more information. ''') return out def get_pubkey(self): # type: () -> EVP.PKey assert m2.x509_type_check(self.x509), "'x509' type error" return EVP.PKey(m2.x509_get_pubkey(self.x509), _pyfree=1) def set_pubkey(self, pkey): # type: (EVP.PKey) -> int """ Set the public key for the certificate :param pkey: Public key :return 1 for success and 0 for failure """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_set_pubkey(self.x509, pkey.pkey) def get_issuer(self): # type: () -> X509_Name assert m2.x509_type_check(self.x509), "'x509' type error" return X509_Name(m2.x509_get_issuer_name(self.x509)) def set_issuer(self, name): # type: (X509_Name) -> int """ Set issuer name. :param name: subjectName field. :return 1 for success and 0 for failure """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_set_issuer_name(self.x509, name.x509_name) def get_subject(self): # type: () -> X509_Name assert m2.x509_type_check(self.x509), "'x509' type error" return X509_Name(m2.x509_get_subject_name(self.x509)) def set_subject(self, name): # type: (X509_Name) -> int """ Set subject name. :param name: subjectName field. :return 1 for success and 0 for failure """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_set_subject_name(self.x509, name.x509_name) def add_ext(self, ext): # type: (X509_Extension) -> int """ Add X509 extension to this certificate. :param ext: Extension :return 1 for success and 0 for failure """ assert m2.x509_type_check(self.x509), "'x509' type error" return m2.x509_add_ext(self.x509, ext.x509_ext, -1) def get_ext(self, name): # type: (str) -> X509_Extension """ Get X509 extension by name. :param name: Name of the extension :return: X509_Extension """ # Optimizations to reduce attribute accesses m2x509_get_ext = m2.x509_get_ext m2x509_extension_get_name = m2.x509_extension_get_name x509 = self.x509 name = name.encode() if isinstance(name, str) else name for i in range(m2.x509_get_ext_count(x509)): ext_ptr = m2x509_get_ext(x509, i) if m2x509_extension_get_name(ext_ptr) == name: return X509_Extension(ext_ptr, _pyfree=0) raise LookupError def get_ext_at(self, index): # type: (int) -> X509_Extension """ Get X509 extension by index. :param index: Name of the extension :return: X509_Extension """ if index < 0 or index >= self.get_ext_count(): raise IndexError return X509_Extension(m2.x509_get_ext(self.x509, index), _pyfree=0) def get_ext_count(self): # type: () -> int """ Get X509 extension count. """ return m2.x509_get_ext_count(self.x509) def sign(self, pkey, md): # type: (EVP.PKey, str) -> int """ Sign the certificate. :param pkey: Public key :param md: Message digest algorithm to use for signing, for example 'sha1'. :return int """ assert m2.x509_type_check(self.x509), "'x509' type error" mda = getattr(m2, md, None) if mda is None: raise ValueError('unknown message digest', md) return m2.x509_sign(self.x509, pkey.pkey, mda()) def verify(self, pkey=None): # type: (Optional[EVP.PKey]) -> int assert m2.x509_type_check(self.x509), "'x509' type error" if pkey: return m2.x509_verify(self.x509, pkey.pkey) else: return m2.x509_verify(self.x509, self.get_pubkey().pkey) def check_ca(self): # type: () -> int """ Check if the certificate is a Certificate Authority (CA) certificate. :return: 0 if the certificate is not CA, nonzero otherwise. :requires: OpenSSL 0.9.8 or newer """ return m2.x509_check_ca(self.x509) def check_purpose(self, id, ca): # type: (int, int) -> int """ Check if the certificate's purpose matches the asked purpose. :param id: Purpose id. See X509_PURPOSE_* constants. :param ca: 1 if the certificate should be CA, 0 otherwise. :return: 0 if the certificate purpose does not match, nonzero otherwise. """ return m2.x509_check_purpose(self.x509, id, ca) def get_fingerprint(self, md='md5'): # type: (str) -> str """ Get the fingerprint of the certificate. :param md: Message digest algorithm to use. :return: String containing the fingerprint in hex format. """ der = self.as_der() md = EVP.MessageDigest(md) md.update(der) digest = md.final() return binascii.hexlify(digest).upper().decode() def load_cert(file, format=FORMAT_PEM): # type: (AnyStr, int) -> X509 """ Load certificate from file. :param file: Name of file containing certificate in either DER or PEM format. :param format: Describes the format of the file to be loaded, either PEM or DER. :return: M2Crypto.X509.X509 object. """ with BIO.openfile(file) as bio: if format == FORMAT_PEM: return load_cert_bio(bio) elif format == FORMAT_DER: cptr = m2.d2i_x509(bio._ptr()) return X509(cptr, _pyfree=1) else: raise ValueError( "Unknown format. Must be either FORMAT_DER or FORMAT_PEM") def load_cert_bio(bio, format=FORMAT_PEM): # type: (BIO.BIO, int) -> X509 """ Load certificate from a bio. :param bio: BIO pointing at a certificate in either DER or PEM format. :param format: Describes the format of the cert to be loaded, either PEM or DER (via constants FORMAT_PEM and FORMAT_FORMAT_DER) :return: M2Crypto.X509.X509 object. """ if format == FORMAT_PEM: cptr = m2.x509_read_pem(bio._ptr()) elif format == FORMAT_DER: cptr = m2.d2i_x509(bio._ptr()) else: raise ValueError( "Unknown format. Must be either FORMAT_DER or FORMAT_PEM") return X509(cptr, _pyfree=1) def load_cert_string(cert_str, format=FORMAT_PEM): # type: (AnyStr, int) -> X509 """ Load certificate from a cert_str. :param cert_str: String containing a certificate in either DER or PEM format. :param format: Describes the format of the cert to be loaded, either PEM or DER (via constants FORMAT_PEM and FORMAT_FORMAT_DER) :return: M2Crypto.X509.X509 object. """ cert_str = cert_str.encode() if isinstance(cert_str, str) else cert_str bio = BIO.MemoryBuffer(cert_str) return load_cert_bio(bio, format) def load_cert_der_string(cert_str): # type: (AnyStr) -> X509 """ Load certificate from a cert_str. :param cert_str: String containing a certificate in DER format. :return: M2Crypto.X509.X509 object. """ cert_str = cert_str.encode() if isinstance(cert_str, str) else cert_str bio = BIO.MemoryBuffer(cert_str) cptr = m2.d2i_x509(bio._ptr()) return X509(cptr, _pyfree=1) class X509_Store_Context(object): """ X509 Store Context """ m2_x509_store_ctx_free = m2.x509_store_ctx_free def __init__(self, x509_store_ctx, _pyfree=0): # type: (bytes, int) -> None """ :param x509_store_ctx: binary data for OpenSSL X509_STORE_CTX type """ self.ctx = x509_store_ctx self._pyfree = _pyfree def __del__(self): # type: () -> None # see BIO.py - unbalanced __init__ / __del__ if not hasattr(self, '_pyfree'): pass # print("OOPS") elif self._pyfree: self.m2_x509_store_ctx_free(self.ctx) def _ptr(self): return self.ctx def get_current_cert(self): # type: () -> X509 """ Get current X.509 certificate. :warning: The returned certificate is NOT refcounted, so you can not rely on it being valid once the store context goes away or is modified. """ return X509(m2.x509_store_ctx_get_current_cert(self.ctx), _pyfree=0) def get_error(self): # type: () -> int """ Get error code. """ return m2.x509_store_ctx_get_error(self.ctx) def get_error_depth(self): # type: () -> int """ Get error depth. """ return m2.x509_store_ctx_get_error_depth(self.ctx) def get1_chain(self): # type: () -> X509_Stack """ Get certificate chain. :return: Reference counted (i.e. safe to use even after the store context goes away) stack of certificates in the chain. """ return X509_Stack(m2.x509_store_ctx_get1_chain(self.ctx), 1, 1) class X509_Store(object): """ X509 Store """ m2_x509_store_free = m2.x509_store_free def __init__(self, store=None, _pyfree=0): # type: (Optional[bytes], int) -> None """ :param store: binary data for OpenSSL X509_STORE_CTX type. """ if store is not None: self.store = store self._pyfree = _pyfree else: self.store = m2.x509_store_new() self._pyfree = 1 def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_x509_store_free(self.store) def _ptr(self): return self.store def load_info(self, file): # type: (AnyStr) -> int """ :param file: filename :return: 1 on success, 0 on failure """ ret = m2.x509_store_load_locations(self.store, file) return ret load_locations = load_info def add_x509(self, x509): # type: (X509) -> int assert isinstance(x509, X509) return m2.x509_store_add_cert(self.store, x509._ptr()) def set_verify_cb(self, callback=None): # type: (Optional[callable]) -> None """ Set callback which will be called when the store is verified. Wrapper over OpenSSL X509_STORE_set_verify_cb(). :param callback: Callable to specify verification options. Type of the callable must be: (int, X509_Store_Context) -> int. If None: set the standard options. :note: compile-time or run-time errors in the callback would result in mysterious errors during verification, which could be hard to trace. :note: Python exceptions raised in callbacks do not propagate to verify() call. :return: None """ if callback is None: return self.set_verify_cb(x509_store_default_cb) if not callable(callback): raise X509Error("set_verify(): callback is not callable") return m2.x509_store_set_verify_cb(self.store, callback) add_cert = add_x509 def set_flags(self, flags): # type: (int) -> int """ Set the verification flags for the X509Store Wrapper over OpenSSL X509_STORE_set_flags() :param flags: `VERIFICATION FLAGS` section of the X509_VERIFY_PARAM_set_flags man page has a complete description of values the flags parameter can take. Their M2Crypto equivalent is transformed following the pattern: "X509_V_FLAG_XYZ" -> lowercase("VERIFY_XYZ") """ return m2.x509_store_set_flags(self.store, flags) class X509_Stack(object): """ X509 Stack :warning: Do not modify the underlying OpenSSL stack except through this interface, or use any OpenSSL functions that do so indirectly. Doing so will get the OpenSSL stack and the internal pystack of this class out of sync, leading to python memory leaks, exceptions or even python crashes! """ m2_sk_x509_free = m2.sk_x509_free def __init__(self, stack=None, _pyfree=0, _pyfree_x509=0): # type: (Optional[bytes], int, int) -> None if stack is not None: self.stack = stack self._pyfree = _pyfree self.pystack = [] # This must be kept in sync with self.stack num = m2.sk_x509_num(self.stack) for i in range(num): self.pystack.append(X509(m2.sk_x509_value(self.stack, i), _pyfree=_pyfree_x509)) else: self.stack = m2.sk_x509_new_null() self._pyfree = 1 self.pystack = [] # This must be kept in sync with self.stack def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_sk_x509_free(self.stack) def __len__(self): # type: () -> int assert m2.sk_x509_num(self.stack) == len(self.pystack) return len(self.pystack) def __getitem__(self, idx): # type: (int) -> X509 return self.pystack[idx] def __iter__(self): return iter(self.pystack) def _ptr(self): return self.stack def push(self, x509): # type: (X509) -> int """ push an X509 certificate onto the stack. :param x509: X509 object. :return: The number of X509 objects currently on the stack. """ assert isinstance(x509, X509) self.pystack.append(x509) ret = m2.sk_x509_push(self.stack, x509._ptr()) assert ret == len(self.pystack) return ret def pop(self): # type: () -> X509 """ pop a certificate from the stack. :return: X509 object that was popped, or None if there is nothing to pop. """ x509_ptr = m2.sk_x509_pop(self.stack) if x509_ptr is None: assert len(self.pystack) == 0 return None return self.pystack.pop() def as_der(self): # type: () -> bytes """ Return the stack as a DER encoded string """ return m2.get_der_encoding_stack(self.stack) def new_stack_from_der(der_string): # type: (bytes) -> X509_Stack """ Create a new X509_Stack from DER string. :return: X509_Stack """ der_string = der_string.encode() if isinstance(der_string, str) else der_string stack_ptr = m2.make_stack_from_der_sequence(der_string) return X509_Stack(stack_ptr, 1, 1) class Request(object): """ X509 Certificate Request. """ m2_x509_req_free = m2.x509_req_free def __init__(self, req=None, _pyfree=0): # type: (Optional[int], int) -> None if req is not None: self.req = req self._pyfree = _pyfree else: self.req = m2.x509_req_new() m2.x509_req_set_version(self.req, 0) self._pyfree = 1 def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_x509_req_free(self.req) def as_text(self): # type: () -> str buf = BIO.MemoryBuffer() m2.x509_req_print(buf.bio_ptr(), self.req) out = buf.read_all() return out.decode() if isinstance(out, bytes) else out def as_pem(self): # type: () -> bytes buf = BIO.MemoryBuffer() m2.x509_req_write_pem(buf.bio_ptr(), self.req) return buf.read_all() def as_der(self): # type: () -> bytes buf = BIO.MemoryBuffer() m2.i2d_x509_req_bio(buf.bio_ptr(), self.req) return buf.read_all() def save_pem(self, filename): # type: (AnyStr) -> int with BIO.openfile(filename, 'wb') as bio: return m2.x509_req_write_pem(bio.bio_ptr(), self.req) def save(self, filename, format=FORMAT_PEM): # type: (AnyStr, int) -> int """ Saves X.509 certificate request to a file. Default output format is PEM. :param filename: Name of the file the request will be saved to. :param format: Controls what output format is used to save the request. Either FORMAT_PEM or FORMAT_DER to save in PEM or DER format. Raises ValueError if an unknown format is used. :return: 1 for success, 0 for failure. The error code can be obtained by ERR_get_error. """ with BIO.openfile(filename, 'wb') as bio: if format == FORMAT_PEM: return m2.x509_req_write_pem(bio.bio_ptr(), self.req) elif format == FORMAT_DER: return m2.i2d_x509_req_bio(bio.bio_ptr(), self.req) else: raise ValueError( "Unknown filetype. Must be either FORMAT_DER or FORMAT_PEM") def get_pubkey(self): # type: () -> EVP.PKey """ Get the public key for the request. :return: Public key from the request. """ return EVP.PKey(m2.x509_req_get_pubkey(self.req), _pyfree=1) def set_pubkey(self, pkey): # type: (EVP.PKey) -> int """ Set the public key for the request. :param pkey: Public key :return: Return 1 for success and 0 for failure. """ return m2.x509_req_set_pubkey(self.req, pkey.pkey) def get_version(self): # type: () -> int """ Get version. :return: Returns version. """ return m2.x509_req_get_version(self.req) def set_version(self, version): # type: (int) -> int """ Set version. :param version: Version number. :return: Returns 0 on failure. """ return m2.x509_req_set_version(self.req, version) def get_subject(self): # type: () -> X509_Name return X509_Name(m2.x509_req_get_subject_name(self.req)) def set_subject_name(self, name): # type: (X509_Name) -> int """ Set subject name. :param name: subjectName field. :return: 1 for success and 0 for failure """ return m2.x509_req_set_subject_name(self.req, name.x509_name) set_subject = set_subject_name def add_extensions(self, ext_stack): # type: (X509_Extension_Stack) -> int """ Add X509 extensions to this request. :param ext_stack: Stack of extensions to add. :return: 1 for success and 0 for failure """ return m2.x509_req_add_extensions(self.req, ext_stack._ptr()) def verify(self, pkey): # type: (EVP.PKey) -> int """ :param pkey: PKey to be verified :return: 1 for success and 0 for failure """ return m2.x509_req_verify(self.req, pkey.pkey) def sign(self, pkey, md): # type: (EVP.PKey, str) -> int """ :param pkey: PKey to be signed :param md: used algorigthm :return: 1 for success and 0 for failure """ mda = getattr(m2, md, None) if mda is None: raise ValueError('unknown message digest', md) return m2.x509_req_sign(self.req, pkey.pkey, mda()) def load_request(file, format=FORMAT_PEM): # type: (AnyStr, int) -> Request """ Load certificate request from file. :param file: Name of file containing certificate request in either PEM or DER format. :param format: Describes the format of the file to be loaded, either PEM or DER. (using constants FORMAT_PEM and FORMAT_DER) :return: Request object. """ with BIO.openfile(file) as f: if format == FORMAT_PEM: cptr = m2.x509_req_read_pem(f.bio_ptr()) elif format == FORMAT_DER: cptr = m2.d2i_x509_req(f.bio_ptr()) else: raise ValueError( "Unknown filetype. Must be either FORMAT_PEM or FORMAT_DER") return Request(cptr, 1) def load_request_bio(bio, format=FORMAT_PEM): # type: (BIO.BIO, int) -> Request """ Load certificate request from a bio. :param bio: BIO pointing at a certificate request in either DER or PEM format. :param format: Describes the format of the request to be loaded, either PEM or DER. (using constants FORMAT_PEM and FORMAT_DER) :return: M2Crypto.X509.Request object. """ if format == FORMAT_PEM: cptr = m2.x509_req_read_pem(bio._ptr()) elif format == FORMAT_DER: cptr = m2.d2i_x509_req(bio._ptr()) else: raise ValueError( "Unknown format. Must be either FORMAT_DER or FORMAT_PEM") return Request(cptr, _pyfree=1) def load_request_string(cert_str, format=FORMAT_PEM): # type: (AnyStr, int) -> Request """ Load certificate request from a cert_str. :param cert_str: String containing a certificate request in either DER or PEM format. :param format: Describes the format of the request to be loaded, either PEM or DER. (using constants FORMAT_PEM and FORMAT_DER) :return: M2Crypto.X509.Request object. """ cert_str = cert_str.encode() if isinstance(cert_str, str) else cert_str bio = BIO.MemoryBuffer(cert_str) return load_request_bio(bio, format) def load_request_der_string(cert_str): # type: (AnyStr) -> Request """ Load certificate request from a cert_str. :param cert_str: String containing a certificate request in DER format. :return: M2Crypto.X509.Request object. """ cert_str = cert_str.encode() if isinstance(cert_str, str) else cert_str bio = BIO.MemoryBuffer(cert_str) return load_request_bio(bio, FORMAT_DER) class CRL(object): """ X509 Certificate Revocation List """ m2_x509_crl_free = m2.x509_crl_free def __init__(self, crl=None, _pyfree=0): # type: (Optional[bytes], int) -> None """ :param crl: binary representation of the underlying OpenSSL X509_CRL object. """ if crl is not None: self.crl = crl self._pyfree = _pyfree else: self.crl = m2.x509_crl_new() self._pyfree = 1 def __del__(self): # type: () -> None if getattr(self, '_pyfree', 0): self.m2_x509_crl_free(self.crl) def as_text(self): # type: () -> str """ Return CRL in PEM format in a string. :return: String containing the CRL in PEM format. """ buf = BIO.MemoryBuffer() m2.x509_crl_print(buf.bio_ptr(), self.crl) out = buf.read_all() return out.decode() if isinstance(out, bytes) else out def load_crl(file): # type: (AnyStr) -> CRL """ Load CRL from file. :param file: Name of file containing CRL in PEM format. :return: M2Crypto.X509.CRL object. """ with BIO.openfile(file) as f: cptr = m2.x509_crl_read_pem(f.bio_ptr()) return CRL(cptr, 1) m2crypto-0.42.0/src/M2Crypto/__init__.py000066400000000000000000000024401465575656700177650ustar00rootroot00000000000000from __future__ import absolute_import """ M2Crypto is the most complete Python wrapper for OpenSSL featuring RSA, DSA, DH, EC, HMACs, message digests, symmetric ciphers (including AES); SSL functionality to implement clients and servers; HTTPS extensions to Python's httplib, urllib, and xmlrpclib; unforgeable HMAC'ing AuthCookies for web session management; FTP/TLS client and server; and ZSmime: An S/MIME messenger for Zope. M2Crypto can also be used to provide SSL for Twisted. Smartcards supported through the Engine interface. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2004-2007 OSAF. All Rights Reserved. Copyright 2008-2011 Heikki Toivonen. All rights reserved. """ # noqa __version__ = '0.42.0' version = __version__ # type: str try: from distutils.version import StrictVersion as Version except ImportError: try: from packaging.version import Version except ImportError: Version = None if Version is not None: __ver = Version(__version__) if hasattr(__ver, '_version'): version_info = tuple(__ver._version[1]) elif hasattr(__ver, 'version'): version_info = __ver.version from M2Crypto import m2 encrypt = 1 decrypt = 0 m2.lib_init() m2crypto-0.42.0/src/M2Crypto/callback.py000066400000000000000000000004521465575656700177630ustar00rootroot00000000000000from __future__ import absolute_import """Deprecated, use the util module instead. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" import warnings warnings.warn('Use the util module instead', DeprecationWarning) from M2Crypto.util import genparam_callback, passphrase_callback m2crypto-0.42.0/src/M2Crypto/ftpslib.py000066400000000000000000000054121465575656700176730ustar00rootroot00000000000000from __future__ import absolute_import """M2Crypto client-side FTP/TLS. This implementation complies with draft-murray-auth-ftp-ssl-07.txt. Example: >>> from M2Crypto import ftpslib >>> f = ftpslib.FTP_TLS() >>> f.connect('', 9021) '220 spinnaker.dyndns.org M2Crypto (Medusa) FTP/TLS server v0.07 ready.' >>> f.auth_tls() >>> f.set_pasv(0) >>> f.login('ftp', 'ngps@') '230 Ok.' >>> f.retrlines('LIST') -rw-rw-r-- 1 0 198 2326 Jul 3 1996 apache_pb.gif drwxrwxr-x 7 0 198 1536 Oct 10 2000 manual drwxrwxr-x 2 0 198 512 Oct 31 2000 modpy drwxrwxr-x 2 0 198 512 Oct 31 2000 bobo drwxr-xr-x 2 0 198 14336 May 28 15:54 postgresql drwxr-xr-x 4 100 198 512 May 16 17:19 home drwxr-xr-x 7 100 100 3584 Sep 23 2000 openacs drwxr-xr-x 10 0 0 512 Aug 5 2000 python1.5 -rw-r--r-- 1 100 198 326 Jul 29 03:29 index.html drwxr-xr-x 12 0 0 512 May 31 17:08 python2.1 '226 Transfer complete' >>> f.quit() '221 Goodbye.' >>> Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" # We want to import whole stdlib ftplib objects, because our users want # to use them. from ftplib import * # noqa # M2Crypto from M2Crypto import SSL class FTP_TLS(FTP): """Python OO interface to client-side FTP/TLS.""" def __init__(self, host=None, ssl_ctx=None): """Initialise the client. If 'host' is supplied, connect to it.""" if ssl_ctx is not None: self.ssl_ctx = ssl_ctx else: self.ssl_ctx = SSL.Context() FTP.__init__(self, host) self.prot = 0 def auth_tls(self): """Secure the control connection per AUTH TLS, aka AUTH TLS-C.""" self.voidcmd('AUTH TLS') s = SSL.Connection(self.ssl_ctx, self.sock) s.setup_ssl() s.set_connect_state() s.connect_ssl() self.sock = s self.file = self.sock.makefile() def auth_ssl(self): """Secure the control connection per AUTH SSL, aka AUTH TLS-P.""" raise NotImplementedError def prot_p(self): """Set up secure data connection.""" self.voidcmd('PBSZ 0') self.voidcmd('PROT P') self.prot = 1 def prot_c(self): """Set up data connection in the clear.""" self.voidcmd('PROT C') self.prot = 0 def ntransfercmd(self, cmd, rest=None): """Initiate a data transfer.""" conn, size = FTP.ntransfercmd(self, cmd, rest) if self.prot: conn = SSL.Connection(self.ssl_ctx, conn) conn.setup_ssl() conn.set_connect_state() conn.set_session(self.sock.get_session()) conn.connect_ssl() return conn, size m2crypto-0.42.0/src/M2Crypto/httpslib.py000066400000000000000000000241661465575656700200700ustar00rootroot00000000000000from __future__ import absolute_import import warnings """M2Crypto support for Python's httplib. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" import base64 import socket from M2Crypto import SSL from urllib.parse import urlsplit, urlunsplit from http.client import * # noqa # This is not imported with just '*' from http.client import HTTPS_PORT from typing import Any, AnyStr, Callable, Dict, Optional # noqa class HTTPSConnection(HTTPConnection): """ This class allows communication via SSL using M2Crypto. """ default_port = HTTPS_PORT def __init__(self, host, port=None, strict=None, **ssl): # type: (str, Optional[int], Optional[bool], **Any) -> None """ Represents one transaction with an HTTP server over the SSL connection. :param host: host name :param port: port number :param strict: if switched on, it raises BadStatusLine to be raised if the status line can't be parsed as a valid HTTP/1.0 or 1.1 status line. :param ssl: dict with all remaining named real parameters of the function. Specifically, ``ssl_context`` is expected to be included with SSL.Context; if it is not default ``'sslv23'`` is substituted). """ self.session = None # type: bytes self.host = host self.port = port keys = set(ssl.keys()) - set( ('key_file', 'cert_file', 'ssl_context') ) if keys: raise ValueError('unknown keyword argument: %s', keys) try: self.ssl_ctx = ssl['ssl_context'] assert isinstance(self.ssl_ctx, SSL.Context), self.ssl_ctx except KeyError: self.ssl_ctx = SSL.Context() HTTPConnection.__init__(self, host, port, strict) def connect(self): # type: () -> None error = None # We ignore the returned sockaddr because SSL.Connection.connect needs # a host name. for (family, _, _, _, _) in socket.getaddrinfo( self.host, self.port, 0, socket.SOCK_STREAM ): sock = None try: sock = SSL.Connection(self.ssl_ctx, family=family) # set SNI server name since we know it at this point sock.set_tlsext_host_name(self.host) if self.session is not None: sock.set_session(self.session) sock.connect((self.host, self.port)) self.sock = sock sock = None return except socket.error as e: # Other exception are probably SSL-related, in that case we # abort and the exception is forwarded to the caller. error = e finally: if sock is not None: sock.close() if error is None: raise AssertionError("Empty list returned by getaddrinfo") raise error def close(self): # type: () -> None # This kludges around line 545 of httplib.py, # which closes the connection in this object; # the connection remains open in the response # object. # # M2Crypto doesn't close-here-keep-open-there, # so, in effect, we don't close until the whole # business is over and gc kicks in. # # XXX Long-running callers beware leakage. # # XXX 05-Jan-2002: This module works with Python 2.2, # XXX but I've not investigated if the above conditions # XXX remain. pass def get_session(self): # type: () -> SSL.Session.Session return self.sock.get_session() def set_session(self, session): # type: (SSL.Session.Session) -> None self.session = session class ProxyHTTPSConnection(HTTPSConnection): """ An HTTPS Connection that uses a proxy and the CONNECT request. When the connection is initiated, CONNECT is first sent to the proxy (along with authorization headers, if supplied). If successful, an SSL connection will be established over the socket through the proxy and to the target host. Finally, the actual request is sent over the SSL connection tunneling through the proxy. """ _ports = {'http': 80, 'https': 443} _AUTH_HEADER = "Proxy-Authorization" _UA_HEADER = "User-Agent" def __init__( self, host, port=None, strict=None, username=None, password=None, **ssl ): # type: (str, Optional[int], Optional[bool], Optional[AnyStr], Optional[AnyStr], **Any) -> None """ Create the ProxyHTTPSConnection object. :param host: host name of the proxy server :param port: port number of the proxy server :param strict: if switched on, it raises BadStatusLine to be raised if the status line can't be parsed as a valid HTTP/1.0 or 1.1 status line. :param username: username on the proxy server, when required Username can be ``str``, but preferred type is ``bytes``. M2Crypto does some conversion to ``bytes`` when necessary, but it's better when the user of the library does it on its own. :param password: password on the proxy server, when required The same as with ``username``, ``str`` is accepted, but ``bytes`` are preferred. :param ssl: dict with all remaining named real parameters of the function. Specifically, ``ssl_context`` is expected to be included with SSL.Context; if it is not default ``'sslv23'`` is substituted). """ HTTPSConnection.__init__(self, host, port, strict, **ssl) self._username = username.encode('utf8') \ if isinstance(username, (str,)) else username self._password = password.encode('utf8') \ if isinstance(password, (str,)) else password self._proxy_auth = None # type: str self._proxy_UA = None # type: str def putrequest( self, method, url, skip_host=0, skip_accept_encoding=0 ): # type: (AnyStr, AnyStr, int, int) -> None """ putrequest is called before connect, so can interpret url and get real host/port to be used to make CONNECT request to proxy """ proto, netloc, path, query, fragment = urlsplit(url) if not proto: raise ValueError("unknown URL type: %s" % url) # get host & port try: username_password, host_port = netloc.split('@') except ValueError: host_port = netloc try: host, port_s = host_port.split(':') port = int(port_s) except ValueError: host = host_port # try to get port from proto try: port = self._ports[proto] except KeyError: raise ValueError("unknown protocol for: %s" % url) self._real_host = host # type: str self._real_port = port # type: int rest = urlunsplit(('', '', path, query, fragment)) HTTPSConnection.putrequest( self, method, rest, skip_host, skip_accept_encoding ) def putheader(self, header, value): # type: (AnyStr, AnyStr) -> None # Store the auth header if passed in. if header.lower() == self._UA_HEADER.lower(): self._proxy_UA = value if header.lower() == self._AUTH_HEADER.lower(): self._proxy_auth = value else: HTTPSConnection.putheader(self, header, value) def endheaders(self, *args, **kwargs): # type: (*Any, **Any) -> None # We've recieved all of hte headers. Use the supplied username # and password for authorization, possibly overriding the authstring # supplied in the headers. if not self._proxy_auth: self._proxy_auth = self._encode_auth() HTTPSConnection.endheaders(self, *args, **kwargs) def connect(self): # type: () -> None HTTPConnection.connect(self) # send proxy CONNECT request self.sock.sendall(self._get_connect_msg()) response = HTTPResponse(self.sock) response.begin() code = response.status if code != 200: # proxy returned and error, abort connection, and raise exception self.close() raise socket.error("Proxy connection failed: %d" % code) self._start_ssl() def _get_connect_msg(self): # type: () -> bytes """ Return an HTTP CONNECT request to send to the proxy. """ msg = "CONNECT %s:%d HTTP/1.1\r\n" % ( self._real_host, self._real_port, ) msg = msg + "Host: %s:%d\r\n" % ( self._real_host, self._real_port, ) if self._proxy_UA: msg = msg + "%s: %s\r\n" % ( self._UA_HEADER, self._proxy_UA, ) if self._proxy_auth: msg = msg + "%s: %s\r\n" % ( self._AUTH_HEADER, self._proxy_auth, ) msg = msg + "\r\n" return msg.encode() def _start_ssl(self): # type: () -> None """ Make this connection's socket SSL-aware. """ self.sock = SSL.Connection(self.ssl_ctx, self.sock) self.sock.setup_ssl() self.sock.set_connect_state() self.sock.connect_ssl() def _encode_auth(self): # type: () -> Optional[bytes] """ Encode the username and password for use in the auth header. """ if not (self._username and self._password): return None # Authenticated proxy userpass = "%s:%s" % (self._username, self._password) with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) enc_userpass = base64.encodestring(userpass).replace("\n", "") return ("Basic %s" % enc_userpass).encode() m2crypto-0.42.0/src/M2Crypto/m2.py000066400000000000000000000014761465575656700165540ustar00rootroot00000000000000from __future__ import absolute_import """M2Crypto low level OpenSSL wrapper functions. m2 is the low level wrapper for OpenSSL functions. Typically you would not need to use these directly, since these will be called by the higher level objects you should try to use instead. Naming conventions: All functions wrapped by m2 are all lower case, words separated by underscores. Examples: OpenSSL M2Crypto X509_get_version m2.x509_get_version X509_get_notBefore m2.x509_get_not_before X509_REQ_verify m2.x509_req_verify Exceptions to naming rules: XXX TDB Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2004 OSAF. All Rights Reserved. """ from M2Crypto.m2crypto import * lib_init() m2crypto-0.42.0/src/M2Crypto/m2.pyi000066400000000000000000000026451465575656700167240ustar00rootroot00000000000000from typing import Optional from M2Crypto import ASN1, BIO, types as C def asn1_integer_cmp(a1: C.ASN1_Integer, a2: C.ASN1_Integer) -> int: ... def asn1_integer_free(a: C.ASN1_Integer) -> None: ... def asn1_integer_get(a: C.ASN1_Integer) -> Optional[int]: ... def asn1_integer_set(a: C.ASN1_Integer, v: int) -> int: ... def asn1_object_free(a: C.ASN1_Object) -> None: ... def asn1_string_free(a: C.ASN1_String) -> None: ... def asn1_string_print(out: C.BIO, s: C.ASN1_String) -> int: ... def asn1_string_print_ex(out: C.BIO, s: C.ASN1_String, flags: int) -> int: ... def asn1_time_free(a: C.ASN1_TIME) -> None: ... def asn1_time_new() -> C.ASN1_TIME: ... def asn1_time_print(out: C.BIO, s: C.ASN1_TIME) -> int: ... def asn1_time_set(a: C.ASN1_TIME, t: int) -> C.ASN1_TIME: ... def asn1_time_set_string(a: C.ASN1_TIME, s: str) -> int: ... def asn1_time_type_check(a: C.ASN1_TIME) -> int: ... bio_close: int = 0x01 def bio_ctrl_get_write_guarantee(a: C.BIO) -> int: ... def bio_ctrl_pending(a: C.BIO) -> int: ... def bio_do_handshake(a: C.BIO) -> int: ... def bio_f_buffer() -> C.BIO_METHOD: ... # FIXME def bio_f_cipher() -> C.BIO_METHOD: ... # FIXME def bio_flush(b: C.BIO) -> int: ... # See gl#m2crypto/m2crypto#228 and gl#m2crypto/m2cryptor#205 def engine_ctrl_cmd_string(e: Engine.ENGINE, cmd_name: str, arg: str, cmd_optional: int) -> None: ... def x509_free(a: C.X509) -> None: ... def x509_new() -> C.X509: ... m2crypto-0.42.0/src/M2Crypto/m2urllib.py000066400000000000000000000067251465575656700177700ustar00rootroot00000000000000from __future__ import absolute_import, print_function """M2Crypto enhancement to Python's urllib for handling 'https' url's. FIXME: it is questionable whether we need this old-style module at all. urllib (not urllib2) is in Python 3 support just as a legacy API. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" import base64 import warnings from M2Crypto import SSL, httpslib from urllib.response import addinfourl from typing import AnyStr, Optional # noqa from urllib.request import * # noqa for other modules to import from urllib.parse import * # noqa for other modules to import from urllib.error import * # noqa for other modules to import def open_https(self, url, data=None, ssl_context=None): # type: (URLOpener, AnyStr, Optional[bytes], Optional[SSL.Context]) -> addinfourl """ Open URL over the SSL connection. :param url: URL to be opened :param data: data for the POST request :param ssl_context: SSL.Context to be used :return: """ warnings.warn('URLOpener has been deprecated in Py3k', DeprecationWarning) if ssl_context is not None and isinstance(ssl_context, SSL.Context): self.ctx = ssl_context else: self.ctx = SSL.Context() user_passwd = None if isinstance(url, (str,)): # https://docs.python.org/3/library/urllib.parse.html parsed = urlparse(url) host = parsed.hostname if parsed.port: host += ":{0}".format(parsed.port) user_passwd = parsed.password if parsed.password: user_passwd += ":{0}".format(parsed.password) selector = parsed.path else: host, selector = url urltype, rest = splittype(selector) url = rest user_passwd = None if urltype.lower() != 'http': realhost = None else: try: # python 2 realhost, rest = splithost(rest) if realhost: user_passwd, realhost = splituser(realhost) if user_passwd: selector = "%s://%s%s" % (urltype, realhost, rest) except NameError: # python 3 has no splithost parsed = urlparse(rest) host = parsed.hostname if parsed.port: host += ":{0}".format(parsed.port) user_passwd = parsed.username if parsed.password: user_passwd += ":{0}".format(parsed.password) # print("proxy via http:", host, selector) if not host: raise IOError('http error', 'no host given') if user_passwd: auth = base64.encodebytes(user_passwd).strip() else: auth = None # Start here! h = httpslib.HTTPSConnection(host=host, ssl_context=self.ctx) # h.set_debuglevel(1) # Stop here! if data is not None: h.putrequest('POST', selector) h.putheader('Content-type', 'application/x-www-form-urlencoded') h.putheader('Content-length', '%d' % len(data)) else: h.putrequest('GET', selector) if auth: h.putheader('Authorization', 'Basic %s' % auth) for args in self.addheaders: h.putheader(*args) # for python3 - used to use apply h.endheaders() if data is not None: h.send(data + '\r\n') # Here again! resp = h.getresponse() fp = resp.fp return addinfourl(fp, resp.msg, "https:" + url) # Stop again. # Minor brain surgery. URLopener.open_https = open_https m2crypto-0.42.0/src/M2Crypto/m2urllib2.py000066400000000000000000000137451465575656700200520ustar00rootroot00000000000000from __future__ import absolute_import """ M2Crypto enhancement to Python's urllib2 for handling 'https' url's. Code from urllib2 is Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation; All Rights Reserved Summary of changes: - Use an HTTPSProxyConnection if the request is going through a proxy. - Add the SSL context to the https connection when performing https_open. - Add the M2Crypto HTTPSHandler when building a default opener. """ import socket from M2Crypto import SSL, httpslib from urllib.parse import urldefrag, urlparse as url_parse from urllib.response import addinfourl from typing import Optional # noqa from urllib.request import * # noqa other modules want to import from urllib.error import * # noqa other modules want to import try: mother_class = socket._fileobject except AttributeError: mother_class = socket.SocketIO class _closing_fileobject(mother_class): # noqa """socket._fileobject that propagates self.close() to the socket. Python 2.5 provides this as socket._fileobject(sock, close=True). """ # for python 3 try: AbstractHTTPHandler except NameError: # somehow this won't get imported by the import * above import urllib.request AbstractHTTPHandler = urllib.request.AbstractHTTPHandler class HTTPSHandler(AbstractHTTPHandler): def __init__(self, ssl_context=None): # type: (Optional[SSL.Context]) -> None AbstractHTTPHandler.__init__(self) if ssl_context is not None: assert isinstance(ssl_context, SSL.Context), ssl_context self.ctx = ssl_context else: self.ctx = SSL.Context() # Copied from urllib2, so we can set the ssl context. def https_open(self, req): # type: (Request) -> addinfourl """Return an addinfourl object for the request, using http_class. http_class must implement the HTTPConnection API from httplib. The addinfourl return value is a file-like object. It also has methods and attributes including: - info(): return a mimetools.Message object for the headers - geturl(): return the original request URL - code: HTTP status code """ # https://docs.python.org/3.3/library/urllib.request.html#urllib.request.Request.get_host try: # up to python-3.2 host = req.get_host() except AttributeError: # from python-3.3 host = req.host if not host: raise URLError('no host given') # Our change: Check to see if we're using a proxy. # Then create an appropriate ssl-aware connection. full_url = req.get_full_url() target_host = url_parse(full_url)[1] if target_host != host: request_uri = urldefrag(full_url)[0] h = httpslib.ProxyHTTPSConnection(host=host, ssl_context=self.ctx) else: try: # up to python-3.2 request_uri = req.get_selector() except AttributeError: # from python-3.3 request_uri = req.selector h = httpslib.HTTPSConnection(host=host, ssl_context=self.ctx) # End our change h.set_debuglevel(self._debuglevel) headers = dict(req.headers) headers.update(req.unredirected_hdrs) # We want to make an HTTP/1.1 request, but the addinfourl # class isn't prepared to deal with a persistent connection. # It will try to read all remaining data from the socket, # which will block while the server waits for the next request. # So make sure the connection gets closed after the (only) # request. headers["Connection"] = "close" try: h.request(req.get_method(), request_uri, req.data, headers) r = h.getresponse() except socket.error as err: # XXX what error? raise URLError(err) # Pick apart the HTTPResponse object to get the addinfourl # object initialized properly. # Wrap the HTTPResponse object in socket's file object adapter # for Windows. That adapter calls recv(), so delegate recv() # to read(). This weird wrapping allows the returned object to # have readline() and readlines() methods. r.recv = r.read r._decref_socketios = lambda: None r.ssl = h.sock.ssl r._timeout = -1.0 r.recv_into = r.readinto fp = socket.SocketIO(r, 'rb') resp = addinfourl(fp, r.msg, req.get_full_url()) resp.code = r.status resp.msg = r.reason return resp https_request = AbstractHTTPHandler.do_request_ # Copied from urllib2 with modifications for ssl def build_opener(ssl_context=None, *handlers): # type: (Optional[SSL.Context], *object) -> OpenerDirector """Create an opener object from a list of handlers. The opener will use several default handlers, including support for HTTP and FTP. If any of the handlers passed as arguments are subclasses of the default handlers, the default handlers will not be used. """ def isclass(obj): return isinstance(obj, type) or hasattr(obj, "__bases__") opener = OpenerDirector() default_classes = [ProxyHandler, UnknownHandler, HTTPHandler, HTTPDefaultErrorHandler, HTTPRedirectHandler, FTPHandler, FileHandler, HTTPErrorProcessor] skip = [] for klass in default_classes: for check in handlers: if isclass(check): if issubclass(check, klass): skip.append(klass) elif isinstance(check, klass): skip.append(klass) for klass in skip: default_classes.remove(klass) for klass in default_classes: opener.add_handler(klass()) # Add the HTTPS handler with ssl_context if HTTPSHandler not in skip: opener.add_handler(HTTPSHandler(ssl_context)) for h in handlers: if isclass(h): h = h() opener.add_handler(h) return opener m2crypto-0.42.0/src/M2Crypto/m2xmlrpclib.py000066400000000000000000000043451465575656700204670ustar00rootroot00000000000000from __future__ import absolute_import """M2Crypto enhancement to xmlrpclib. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" import base64 from M2Crypto import __version__ as __M2Version from M2Crypto import SSL, httpslib, m2urllib from typing import Any, AnyStr, Callable, Optional # noqa from xmlrpc.client import ProtocolError, Transport from xmlrpc.client import * # noqa __version__ = __M2Version class SSL_Transport(Transport): user_agent = "M2Crypto_XMLRPC/%s - %s" % (__version__, Transport.user_agent) def __init__(self, ssl_context=None, *args, **kw): # type: (Optional[SSL.Context], *Any, **Any) -> None Transport.__init__(self, *args, **kw) if ssl_context is None: self.ssl_ctx = SSL.Context() else: self.ssl_ctx = ssl_context def request(self, host, handler, request_body, verbose=0): # type: (AnyStr, Callable, bytes, int) -> object # Handle username and password. user_passwd, host_port = m2urllib.splituser(host) _host, _port = m2urllib.splitport(host_port) h = httpslib.HTTPSConnection(_host, int(_port), ssl_context=self.ssl_ctx) if verbose: h.set_debuglevel(1) # What follows is as in xmlrpclib.Transport. (Except the authz bit.) h.putrequest("POST", handler) # required by HTTP/1.1 h.putheader("Host", _host) # required by XML-RPC h.putheader("User-Agent", self.user_agent) h.putheader("Content-Type", "text/xml") h.putheader("Content-Length", str(len(request_body))) # Authorisation. if user_passwd is not None: auth = base64.encodestring(user_passwd).strip() h.putheader('Authorization', 'Basic %s' % auth) h.endheaders() if request_body: h.send(request_body) response = h.getresponse() if response.status != 200: raise ProtocolError( host + handler, response.status, response.reason, response.getheaders() ) self.verbose = verbose return self.parse_response(response) m2crypto-0.42.0/src/M2Crypto/threading.py000066400000000000000000000006771465575656700202050ustar00rootroot00000000000000from __future__ import absolute_import """ M2Crypto threading support, required for multithreaded applications. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" # M2Crypto from M2Crypto import m2 def init(): # type: () -> None """ Initialize threading support. """ m2.threading_init() def cleanup(): # type: () -> None """ End and cleanup threading support. """ m2.threading_cleanup() m2crypto-0.42.0/src/M2Crypto/types.py000066400000000000000000000005641465575656700173770ustar00rootroot00000000000000from typing import NewType BIO = NewType('BIO', bytes) BIO_METHOD = NewType('BIO_METHOD', bytes) ASN1_Object = NewType('ASN1_Object', bytes) ASN1_String = NewType('ASN1_String', bytes) ASN1_Integer = NewType('ASN1_Integer', int) ASN1_Time = NewType('ASN1_Time', bytes) Engine = NewType('Engine', bytes) X509 = NewType('X509', bytes) X509_CRL = NewType('X509_CRL', bytes) m2crypto-0.42.0/src/M2Crypto/util.py000066400000000000000000000051601465575656700172050ustar00rootroot00000000000000from __future__ import absolute_import, print_function """ M2Crypto utility routines. NOTHING IN THIS MODULE IS GUARANTEED TO BE STABLE, USED ONLY FOR INTERNAL PURPOSES OF M2CRYPTO. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2004 OSAF. All Rights Reserved. """ import binascii import logging import platform import struct import sys import struct import unittest from M2Crypto import m2 from typing import Any, Optional, TextIO, Tuple, Union # noqa # see https://github.com/python/typeshed/issues/222 AddrType = Union[Tuple[str, int], str] log = logging.getLogger('util') class UtilError(Exception): pass m2.util_init(UtilError) def is_libc_musl(): # This is wrong, but unfortunately Python doesn't give us anything better # gh#python/cpython#87414 return platform.libc_ver() == ("", "") def is_32bit(): # type: () -> bool # or alternatively (slightly slower) # (struct.calcsize("P") * 8) == 32 return not(sys.maxsize > 2**32) def expectedFailureIf(condition): """The test is marked as an expectedFailure if the condition is satisfied.""" def wrapper(func): if condition: return unittest.expectedFailure(func) else: return func return wrapper def pkcs5_pad(data, blklen=8): # type: (str, int) -> str pad = (8 - (len(data) % 8)) return data + chr(pad) * pad def pkcs7_pad(data, blklen): # type: (str, int) -> str if blklen > 255: raise ValueError('illegal block size') pad = (blklen - (len(data) % blklen)) return data + chr(pad) * pad def bin_to_hex(b): # type: (bytes) -> str return binascii.b2a_base64(b)[:-1].decode() def octx_to_num(x): # type: (bytes) -> int return int(binascii.hexlify(x), 16) def genparam_callback(p, n, out=sys.stdout): # type: (int, Any, TextIO) -> None ch = ['.', '+', '*', '\n'] out.write(ch[p]) out.flush() def quiet_genparam_callback(p, n, out): # type: (Any, Any, Any) -> None pass def passphrase_callback(v, prompt1='Enter passphrase:', prompt2='Verify passphrase:'): # type: (bool, str, str) -> Optional[str] from getpass import getpass while 1: try: p1 = getpass(prompt1) if v: p2 = getpass(prompt2) if p1 == p2: break else: break except KeyboardInterrupt: return None return p1 def no_passphrase_callback(*args): # type: (*Any) -> str return '' m2crypto-0.42.0/src/SWIG/000077500000000000000000000000001465575656700147465ustar00rootroot00000000000000m2crypto-0.42.0/src/SWIG/Makefile000066400000000000000000000011631465575656700164070ustar00rootroot00000000000000# $Id$ CFLAGS = -DTHREADING -g INCLUDE = -I/usr/local/include -I. LIBS = -L/usr/local/lib -lssl -lcrypto #if PYTHON_VERSION PYVER = $(PYTHON_VERSION) #else PYVER = 2.3 #endif PYINCLUDE = -DHAVE_CONFIG_H -I/usr/local/include/python$(PYVER) \ -I/usr/local/lib/python$(PYVER)/config PYLIB = /usr/local/lib/python$(PYVER)/config all: _m2crypto _m2crypto: _m2crypto.i swig -python -shadow _m2crypto.i cc -c -fpic $(CFLAGS) $(INCLUDE) $(PYINCLUDE) _m2crypto_wrap.c ld -Bshareable -o _m2crypto.so _m2crypto_wrap.o $(LIBS) cp m2crypto.py _m2crypto.so ../M2Crypto clean: rm -f *_wrap* *.o *.so _*.py *.pyc m2crypto-0.42.0/src/SWIG/_aes.i000066400000000000000000000041421465575656700160300ustar00rootroot00000000000000/* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. */ /* $Id$ */ %{ #include #if OPENSSL_VERSION_NUMBER >= 0x0090800fL #include #endif /* // 2004-10-10, ngps: // CTR mode is not included in the default OpenSSL build. // To use the AES CTR ciphers, link with your own copy of OpenSSL. */ #ifdef HAVE_AES_CTR extern EVP_CIPHER const *EVP_aes_128_ctr(void); extern EVP_CIPHER const *EVP_aes_192_ctr(void); extern EVP_CIPHER const *EVP_aes_256_ctr(void); #endif %} %apply Pointer NONNULL { AES_KEY * }; %constant int AES_BLOCK_SIZE = AES_BLOCK_SIZE; %inline %{ AES_KEY *aes_new(void) { AES_KEY *key; if (!(key = (AES_KEY *)PyMem_Malloc(sizeof(AES_KEY)))) { PyErr_SetString(PyExc_MemoryError, "Insufficient memory for AES key."); return NULL; } return key; } void AES_free(AES_KEY *key) { PyMem_Free((void *)key); } /* // op == 0: encrypt // otherwise: decrypt (Python code will supply the value 1.) */ PyObject *AES_set_key(AES_KEY *key, PyObject *value, int bits, int op) { char *vbuf; Py_ssize_t vlen; if (PyBytes_AsStringAndSize(value, &vbuf, &vlen) == -1) return NULL; if (op == 0) AES_set_encrypt_key((const unsigned char *)vbuf, bits, key); else AES_set_decrypt_key((const unsigned char *)vbuf, bits, key); Py_RETURN_NONE; } /* // op == 0: encrypt // otherwise: decrypt (Python code will supply the value 1.) */ PyObject *AES_crypt(const AES_KEY *key, PyObject *in, int outlen, int op) { char *buf; Py_ssize_t len; unsigned char *out; PyObject *res; if (PyBytes_AsStringAndSize(in, &buf, &len) == -1) return NULL; if (!(out=(unsigned char *)PyMem_Malloc(outlen))) { PyErr_SetString(PyExc_MemoryError, "AES_crypt"); return NULL; } if (op == 0) AES_encrypt((const unsigned char *)buf, out, key); else AES_decrypt((const unsigned char *)buf, out, key); res = PyBytes_FromStringAndSize((char*)out, outlen); PyMem_Free(out); return res; } int AES_type_check(AES_KEY *key) { return 1; } %} m2crypto-0.42.0/src/SWIG/_asn1.i000066400000000000000000000142451465575656700161270ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. */ /* ** Portions created by Open Source Applications Foundation (OSAF) are ** Copyright (C) 2004 OSAF. All Rights Reserved. */ /* $Id$ */ %{ #include #include %} %apply Pointer NONNULL { BIO * }; %apply Pointer NONNULL { ASN1_OBJECT * }; %apply Pointer NONNULL { ASN1_STRING * }; %apply Pointer NONNULL { ASN1_INTEGER * }; %apply Pointer NONNULL { ASN1_TIME * }; %rename(asn1_object_new) ASN1_OBJECT_new; extern ASN1_OBJECT *ASN1_OBJECT_new( void ); %rename(asn1_object_create) ASN1_OBJECT_create; extern ASN1_OBJECT *ASN1_OBJECT_create( int, unsigned char *, int, const char *, const char *); %rename(asn1_object_free) ASN1_OBJECT_free; extern void ASN1_OBJECT_free( ASN1_OBJECT *); %rename(i2d_asn1_object) i2d_ASN1_OBJECT; extern int i2d_ASN1_OBJECT( ASN1_OBJECT *, unsigned char **); %rename(d2i_asn1_object) d2i_ASN1_OBJECT; extern ASN1_OBJECT *d2i_ASN1_OBJECT( ASN1_OBJECT **, const unsigned char **, long); %rename(asn1_bit_string_new) ASN1_BIT_STRING_new; extern ASN1_BIT_STRING *ASN1_BIT_STRING_new( void ); %rename(asn1_string_new) ASN1_STRING_new; extern ASN1_STRING *ASN1_STRING_new( void ); %rename(asn1_string_free) ASN1_STRING_free; extern void ASN1_STRING_free( ASN1_STRING *); %typemap(in) (const void *, int) { if (PyBytes_Check($input)) { Py_ssize_t len; $1 = PyBytes_AsString($input); len = PyBytes_Size($input); if (len > INT_MAX) { PyErr_SetString(PyExc_ValueError, "object too large"); return NULL; } $2 = len; } else { PyErr_SetString(PyExc_TypeError, "expected string"); return NULL; } } %rename(asn1_string_set) ASN1_STRING_set; extern int ASN1_STRING_set( ASN1_STRING *, const void *, int); %typemap(in) (const void *, int); %rename(asn1_string_print) ASN1_STRING_print; %threadallow ASN1_STRING_print; extern int ASN1_STRING_print(BIO *, ASN1_STRING *); %threadallow ASN1_STRING_print_ex; %rename(asn1_string_print_ex) ASN1_STRING_print_ex; extern int ASN1_STRING_print_ex(BIO *, ASN1_STRING *, unsigned long); %rename(asn1_time_new) ASN1_TIME_new; extern ASN1_TIME *ASN1_TIME_new( void ); %rename(asn1_time_free) ASN1_TIME_free; extern void ASN1_TIME_free(ASN1_TIME *); %rename(asn1_time_check) ASN1_TIME_check; extern int ASN1_TIME_check(ASN1_TIME *); %rename(asn1_time_set_string) ASN1_TIME_set_string; extern int ASN1_TIME_set_string(ASN1_TIME *, const char *); %rename(asn1_time_print) ASN1_TIME_print; %threadallow ASN1_TIME_print; extern int ASN1_TIME_print(BIO *, ASN1_TIME *); %rename(asn1_integer_new) ASN1_INTEGER_new; extern ASN1_INTEGER *ASN1_INTEGER_new( void ); %rename(asn1_integer_free) ASN1_INTEGER_free; extern void ASN1_INTEGER_free( ASN1_INTEGER *); %rename(asn1_integer_cmp) ASN1_INTEGER_cmp; extern int ASN1_INTEGER_cmp(ASN1_INTEGER *, ASN1_INTEGER *); %constant int ASN1_STRFLGS_ESC_2253 = 1; %constant int ASN1_STRFLGS_ESC_CTRL = 2; %constant int ASN1_STRFLGS_ESC_MSB = 4; %constant int ASN1_STRFLGS_ESC_QUOTE = 8; %constant int ASN1_STRFLGS_UTF8_CONVERT = 0x10; %constant int ASN1_STRFLGS_IGNORE_TYPE = 0x20; %constant int ASN1_STRFLGS_SHOW_TYPE = 0x40; %constant int ASN1_STRFLGS_DUMP_ALL = 0x80; %constant int ASN1_STRFLGS_DUMP_UNKNOWN = 0x100; %constant int ASN1_STRFLGS_DUMP_DER = 0x200; %constant int ASN1_STRFLGS_RFC2253 = (ASN1_STRFLGS_ESC_2253 | \ ASN1_STRFLGS_ESC_CTRL | \ ASN1_STRFLGS_ESC_MSB | \ ASN1_STRFLGS_UTF8_CONVERT | \ ASN1_STRFLGS_DUMP_UNKNOWN | \ ASN1_STRFLGS_DUMP_DER); %inline %{ /* ASN1_TIME_set_string () is a macro */ int asn1_time_type_check(ASN1_TIME *ASN1_TIME) { return 1; } ASN1_TIME* asn1_time_set(ASN1_TIME *asn1_time, PyObject *time) { long long val; if ((val = PyLong_AsLongLong(time)) >= 0) { ERR_clear_error(); asn1_time = ASN1_TIME_adj(asn1_time, (time_t)0, (int)(val / 86400LL), (long) (val % 86400LL)); return asn1_time; } else { char *errstr = PyMem_Malloc(256); snprintf(errstr, 256, "Error in conversion of PyLong to long (val = %lld)", val); PyErr_SetString(PyExc_OverflowError, errstr); PyMem_Free(errstr); return NULL; } } PyObject *asn1_integer_get(ASN1_INTEGER *asn1) { BIGNUM *bn; PyObject *ret; char *hex; bn = ASN1_INTEGER_to_BN(asn1, NULL); if (!bn){ m2_PyErr_Msg(PyExc_RuntimeError); return NULL; } hex = BN_bn2hex(bn); if (!hex){ m2_PyErr_Msg(PyExc_RuntimeError); BN_free(bn); return NULL; } BN_free(bn); ret = PyLong_FromString(hex, NULL, 16); OPENSSL_free(hex); return ret; } int asn1_integer_set(ASN1_INTEGER *asn1, PyObject *value) { BIGNUM *bn = NULL; PyObject *fmt, *args, *hex; /* Despite all hopes to the contrary, we cannot survive here with * PyLong_AsLong shims as provided in * /usr/include/python2.7/longobject.h. */ long val = PyLong_AsLong(value); if (val >= 0) { return ASN1_INTEGER_set(asn1, val); } else { PyErr_Clear(); } if (!PyLong_Check(value)){ PyErr_SetString(PyExc_TypeError, "expected int or long"); return 0; } fmt = PyUnicode_FromString("%x"); if (!fmt) return 0; args = PyTuple_New(1); if (!args){ Py_DECREF(fmt); PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() failed"); return 0; } Py_INCREF(value); PyTuple_SET_ITEM(args, 0, value); hex = PyUnicode_Format(fmt, args); if (!hex){ PyErr_SetString(PyExc_RuntimeError, "PyString_Format() failed"); Py_DECREF(fmt); Py_DECREF(args); return 0; } Py_DECREF(fmt); Py_DECREF(args); if (BN_hex2bn(&bn, PyUnicode_AsUTF8(hex)) <= 0){ m2_PyErr_Msg(PyExc_RuntimeError); Py_DECREF(hex); return 0; } Py_DECREF(hex); if (!BN_to_ASN1_INTEGER(bn, asn1)){ m2_PyErr_Msg(PyExc_RuntimeError); BN_free(bn); return 0; } BN_free(bn); return 1; } %} m2crypto-0.42.0/src/SWIG/_bio.i000066400000000000000000000315161465575656700160360ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. * * Portions created by Open Source Applications Foundation (OSAF) are * Copyright (C) 2004-2005 OSAF. All Rights Reserved. * Author: Heikki Toivonen * * Copyright 2018 Daniel Wozniak. All Rights Reserved.*/ /* $Id$ */ %{ #include %} %apply Pointer NONNULL { BIO * }; %apply Pointer NONNULL { BIO_METHOD * }; %rename(bio_s_bio) BIO_s_bio; extern BIO_METHOD *BIO_s_bio(void); %rename(bio_s_mem) BIO_s_mem; extern BIO_METHOD *BIO_s_mem(void); %rename(bio_s_socket) BIO_s_socket; extern BIO_METHOD *BIO_s_socket(void); %rename(bio_f_ssl) BIO_f_ssl; extern BIO_METHOD *BIO_f_ssl(void); %rename(bio_f_buffer) BIO_f_buffer; extern BIO_METHOD *BIO_f_buffer(void); %rename(bio_f_cipher) BIO_f_cipher; extern BIO_METHOD *BIO_f_cipher(void); %rename(bio_new) BIO_new; extern BIO *BIO_new(BIO_METHOD *); %rename(bio_new_socket) BIO_new_socket; extern BIO *BIO_new_socket(int, int); %rename(bio_new_fd) BIO_new_pyfd; %rename(bio_new_pyfd) BIO_new_pyfd; %rename(bio_free_all) BIO_free_all; %threadallow BIO_free_all; extern void BIO_free_all(BIO *); %rename(bio_dup_chain) BIO_dup_chain; extern BIO *BIO_dup_chain(BIO *); %rename(bio_push) BIO_push; extern BIO *BIO_push(BIO *, BIO *); %rename(bio_pop) BIO_pop; extern BIO *BIO_pop(BIO *); %rename(bio_eof) BIO_eof; extern int BIO_eof(BIO *); %constant int bio_noclose = BIO_NOCLOSE; %constant int bio_close = BIO_CLOSE; %constant int BIO_FLAGS_READ = 0x01; %constant int BIO_FLAGS_WRITE = 0x02; %constant int BIO_FLAGS_IO_SPECIAL = 0x04; %constant int BIO_FLAGS_RWS = (BIO_FLAGS_READ|BIO_FLAGS_WRITE|BIO_FLAGS_IO_SPECIAL); %constant int BIO_FLAGS_SHOULD_RETRY = 0x08; %constant int BIO_FLAGS_MEM_RDONLY = 0x200; %warnfilter(454) _bio_err; %inline %{ static PyObject *_bio_err; void pyfd_init(void); void bio_init(PyObject *bio_err) { Py_INCREF(bio_err); _bio_err = bio_err; pyfd_init(); } int bio_free(BIO *bio) { int ret; Py_BEGIN_ALLOW_THREADS ret = BIO_free(bio); Py_END_ALLOW_THREADS if (ret == 0) { m2_PyErr_Msg(_bio_err); } return ret; } BIO * bio_new_file(const char *filename, const char *mode) { BIO *ret; Py_BEGIN_ALLOW_THREADS ret = BIO_new_file(filename, mode); Py_END_ALLOW_THREADS if (ret == NULL) { m2_PyErr_Msg(_bio_err); } return ret; } BIO *bio_new_pyfile(PyObject *pyfile, int bio_close) { FILE *fp = NULL; BIO *bio = NULL; fp = PyFile_AsFile(pyfile); bio = BIO_new_fp(fp, bio_close); /* returns NULL if error occurred */ if (bio == NULL) { /* Find out the name of the file so we can have good error * message. */ PyObject *pyname = m2_PyFile_Name(pyfile); char *name = PyBytes_AsString(pyname); if (name == NULL) { PyErr_Format(_bio_err, "Opening of the new BIO on file failed!"); } else { PyErr_Format(_bio_err, "Opening of the new BIO on file %s failed!", name); } Py_DECREF(pyname); } return bio; } PyObject *bio_read(BIO *bio, int num) { PyObject *blob; void *buf; int r; if (!(buf = PyMem_Malloc(num))) { PyErr_SetString(PyExc_MemoryError, "bio_read"); return NULL; } Py_BEGIN_ALLOW_THREADS r = BIO_read(bio, buf, num); Py_END_ALLOW_THREADS if (r < 0) { PyMem_Free(buf); if (ERR_peek_error()) { m2_PyErr_Msg(_bio_err); return NULL; } Py_RETURN_NONE; } blob = PyBytes_FromStringAndSize(buf, r); PyMem_Free(buf); return blob; } PyObject *bio_gets(BIO *bio, int num) { PyObject *blob; void *buf; int r; if (!(buf = PyMem_Malloc(num))) { PyErr_SetString(PyExc_MemoryError, "bio_gets"); return NULL; } Py_BEGIN_ALLOW_THREADS r = BIO_gets(bio, buf, num); Py_END_ALLOW_THREADS if (r < 1) { PyMem_Free(buf); if (ERR_peek_error()) { m2_PyErr_Msg(_bio_err); return NULL; } Py_RETURN_NONE; } blob = PyBytes_FromStringAndSize(buf, r); PyMem_Free(buf); return blob; } int bio_write(BIO *bio, PyObject *from) { const void *fbuf; int flen = 0, ret; if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) return -1; Py_BEGIN_ALLOW_THREADS ret = BIO_write(bio, fbuf, flen); Py_END_ALLOW_THREADS if (ret < 0) { if (ERR_peek_error()) { m2_PyErr_Msg(_bio_err); return -1; } } return ret; } /* XXX Casting size_t to int. */ int bio_ctrl_pending(BIO *bio) { return (int)BIO_ctrl_pending(bio); } int bio_ctrl_wpending(BIO *bio) { return (int)BIO_ctrl_wpending(bio); } int bio_ctrl_get_write_guarantee(BIO *a) { return BIO_ctrl_get_write_guarantee(a); } int bio_reset(BIO *bio) { return (int)BIO_reset(bio); } %} %threadallow bio_flush; %inline %{ int bio_flush(BIO *bio) { return (int)BIO_flush(bio); } int bio_seek(BIO *bio, int offset) { return (int)BIO_seek(bio, offset); } int bio_tell(BIO* bio) { return BIO_tell(bio); } void bio_set_flags(BIO *bio, int flags) { BIO_set_flags(bio, flags); } int bio_get_flags(BIO *bio) { return BIO_get_flags(bio); } /* * sets the cipher of BIO @param b to c using key @param key and IV @iv. * @param enc should be set to 1 for encryption and zero to decryption. * * @return * */ PyObject *bio_set_cipher(BIO *b, EVP_CIPHER *c, PyObject *key, PyObject *iv, int op) { const void *kbuf, *ibuf; Py_ssize_t klen, ilen; if ((m2_PyObject_AsReadBuffer(key, &kbuf, &klen) == -1) || (m2_PyObject_AsReadBuffer(iv, &ibuf, &ilen) == -1)) { PyErr_SetString(PyExc_ValueError, "Reading of key or IV from buffer failed."); return NULL; } #if OPENSSL_VERSION_NUMBER >= 0x30000000L if (!BIO_set_cipher(b, (const EVP_CIPHER *)c, (unsigned char *)kbuf, (unsigned char *)ibuf, op)) { PyErr_SetString(PyExc_OSError, "Setting of cipher failed."); return NULL; } #else // https://www.openssl.org/docs/man1.0.2/man3/BIO_set_cipher.html // BIO_set_cipher in OpenSSL < 3.0 doesn't return any value (error or otherwise). BIO_set_cipher(b, (const EVP_CIPHER *)c, (unsigned char *)kbuf, (unsigned char *)ibuf, op); #endif Py_RETURN_NONE; } int bio_set_mem_eof_return(BIO *b, int v) { return (int)BIO_set_mem_eof_return(b, v); } int bio_get_fd(BIO *bio) { return BIO_get_fd(bio, NULL); } %} %warnfilter(454) methods_fdp; %threadallow bio_do_handshake; %inline %{ int bio_do_handshake(BIO *bio) { return BIO_do_handshake(bio); } /* macro */ int bio_make_bio_pair(BIO* b1, BIO* b2) { return BIO_make_bio_pair(b1, b2); } int bio_set_write_buf_size(BIO* b, size_t size) { return BIO_set_write_buf_size(b, size); } int bio_should_retry(BIO* a) { return BIO_should_retry(a); } int bio_should_read(BIO* a) { return BIO_should_read(a); } int bio_should_write(BIO* a) { return BIO_should_write(a); } /* Macros for things not defined before 1.1.0 */ #if OPENSSL_VERSION_NUMBER < 0x10100000L static BIO_METHOD * BIO_meth_new( int type, const char *name ) { BIO_METHOD *method = malloc( sizeof(BIO_METHOD) ); memset( method, 0, sizeof(BIO_METHOD) ); method->type = type; method->name = name; return method; } static void BIO_meth_free( BIO_METHOD *meth ) { if ( meth == NULL ) { return; } free(meth); } #define BIO_meth_set_write(m, f) (m)->bwrite = (f) #define BIO_meth_set_read(m, f) (m)->bread = (f) #define BIO_meth_set_puts(m, f) (m)->bputs = (f) #define BIO_meth_set_gets(m, f) (m)->bgets = (f) #define BIO_meth_set_ctrl(m, f) (m)->ctrl = (f) #define BIO_meth_set_create(m, f) (m)->create = (f) #define BIO_meth_set_destroy(m, f) (m)->destroy = (f) #define BIO_set_shutdown(b, x) (b)->shutdown = x #define BIO_get_shutdown(b) (b)->shutdown #define BIO_set_init(b, x) b->init = x #define BIO_get_init(b) (b)->init #define BIO_set_data(b, x) b->ptr = x #define BIO_clear_flags(b, x) b->flags &= ~(x) #define BIO_get_data(b) b->ptr #endif /* implment custom BIO_s_pyfd */ #ifdef _WIN32 # define clear_sys_error() SetLastError(0) /* Linux doesn't use underscored calls yet */ # define open(p, f, m) _open(p, f, m) # define read(f, b, n) _read(f, b, n) # define write(f, b, n) _write(f, b, n) # define close(f) _close(f) # define lseek(fd, o, w) _lseek(fd, o, w) #else # define clear_sys_error() errno=0 #endif typedef struct pyfd_struct { int fd; } BIO_PYFD_CTX; /* Setting up methods_fdp */ static BIO_METHOD *methods_fdp; static int pyfd_write(BIO *b, const char *in, int inl) { int ret, fd; if (BIO_get_fd(b, &fd) == -1) { PyErr_SetString(_bio_err, "BIO has not been initialized."); return -1; } clear_sys_error(); ret = write(fd, in, inl); BIO_clear_retry_flags(b); if (ret <= 0) { if (BIO_fd_should_retry(ret)) BIO_set_retry_write(b); } return ret; } static int pyfd_read(BIO *b, char *out, int outl) { int ret = 0, fd; if (BIO_get_fd(b, &fd) == -1) { PyErr_SetString(_bio_err, "BIO has not been initialized."); return -1; } if (out != NULL) { clear_sys_error(); ret = read(fd, out, outl); BIO_clear_retry_flags(b); if (ret <= 0) { if (BIO_fd_should_retry(ret)) BIO_set_retry_read(b); } } return ret; } static int pyfd_puts(BIO *bp, const char *str) { int n, ret; n = strlen(str); ret = pyfd_write(bp, str, n); return ret; } static int pyfd_gets(BIO *bp, char *buf, int size) { int ret = 0; char *ptr = buf; char *end = buf + size - 1; /* See https://github.com/openssl/openssl/pull/3442 We were here just repeating a bug from OpenSSL */ while (ptr < end && pyfd_read(bp, ptr, 1) > 0) { if (*ptr++ == '\n') break; } ptr[0] = '\0'; if (buf[0] != '\0') ret = strlen(buf); return ret; } static int pyfd_new(BIO* b) { BIO_PYFD_CTX* ctx; ctx = OPENSSL_zalloc(sizeof(*ctx)); if (ctx == NULL) return 0; ctx->fd = -1; BIO_set_data(b, ctx); BIO_set_shutdown(b, 0); BIO_set_init(b, 1); return 1; } static int pyfd_free(BIO* b) { BIO_PYFD_CTX* ctx; if (b == 0) return 0; ctx = BIO_get_data(b); if (ctx == NULL) return 0; if (BIO_get_shutdown(b) && BIO_get_init(b)) close(ctx->fd); BIO_set_data(b, NULL); BIO_set_shutdown(b, 0); BIO_set_init(b, 0); OPENSSL_free(ctx); return 1; } static long pyfd_ctrl(BIO *b, int cmd, long num, void *ptr) { BIO_PYFD_CTX* ctx; int *ip; long ret = 1; ctx = BIO_get_data(b); if (ctx == NULL) return 0; switch (cmd) { case BIO_CTRL_RESET: num = 0; case BIO_C_FILE_SEEK: ret = (long)lseek(ctx->fd, num, 0); break; case BIO_C_FILE_TELL: case BIO_CTRL_INFO: ret = (long)lseek(ctx->fd, 0, 1); break; case BIO_C_SET_FD: pyfd_free(b); if (*((int *)ptr) > -1) { if (!pyfd_new(b) || !(ctx = BIO_get_data(b))) return 0; ctx->fd = *((int *)ptr); BIO_set_shutdown(b, (int)num); BIO_set_init(b, 1); } break; case BIO_C_GET_FD: if (BIO_get_init(b)) { ip = (int *)ptr; if (ip != NULL) *ip = ctx->fd; ret = ctx->fd; } else ret = -1; break; case BIO_CTRL_GET_CLOSE: ret = BIO_get_shutdown(b); break; case BIO_CTRL_SET_CLOSE: BIO_set_shutdown(b, (int)num); break; case BIO_CTRL_PENDING: case BIO_CTRL_WPENDING: ret = 0; break; case BIO_CTRL_DUP: case BIO_CTRL_FLUSH: ret = 1; break; default: ret = 0; break; } return ret; } void pyfd_init(void) { #if OPENSSL_VERSION_NUMBER >= 0x10100000L methods_fdp = BIO_meth_new( BIO_get_new_index()|BIO_TYPE_DESCRIPTOR|BIO_TYPE_SOURCE_SINK, "python file descriptor"); #else methods_fdp = BIO_meth_new( 100 |BIO_TYPE_DESCRIPTOR|BIO_TYPE_SOURCE_SINK, "python file descriptor"); #endif BIO_meth_set_write(methods_fdp, pyfd_write); BIO_meth_set_read(methods_fdp, pyfd_read); BIO_meth_set_puts(methods_fdp, pyfd_puts); BIO_meth_set_gets(methods_fdp, pyfd_gets); BIO_meth_set_ctrl(methods_fdp, pyfd_ctrl); BIO_meth_set_create(methods_fdp, pyfd_new); BIO_meth_set_destroy(methods_fdp, pyfd_free); } BIO* BIO_new_pyfd(int fd, int close_flag) { BIO *ret; ret = BIO_new(methods_fdp); BIO_set_fd(ret, fd, close_flag); return ret; } %} m2crypto-0.42.0/src/SWIG/_bn.i000066400000000000000000000057201465575656700156620ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (c) 2005-2006 Open Source Applications Foundation. All rights reserved. */ /* We are converting between the Python arbitrarily long integer and * the BIGNUM arbitrarily long integer by converting to and from * a string representation of the number (in hexadecimal). * Direct manipulation would be a possibility, but would require * tighter integration with the Python and OpenSSL internals. */ %{ #include %} %inline %{ PyObject *bn_rand(int bits, int top, int bottom) { BIGNUM* rnd; PyObject *ret; char *randhex; rnd = BN_new(); if (rnd == NULL) { m2_PyErr_Msg(PyExc_Exception); return NULL; } if (!BN_rand(rnd, bits, top, bottom)) { /*Custom errors?*/ m2_PyErr_Msg(PyExc_Exception); BN_free(rnd); return NULL; } randhex = BN_bn2hex(rnd); if (!randhex) { /*Custom errors?*/ m2_PyErr_Msg(PyExc_Exception); BN_free(rnd); return NULL; } BN_free(rnd); ret = PyLong_FromString(randhex, NULL, 16); OPENSSL_free(randhex); return ret; } PyObject *bn_rand_range(PyObject *range) { BIGNUM* rnd; BIGNUM *rng = NULL; PyObject *ret, *tuple; PyObject *format, *rangePyString; char *randhex; /* PyLong_FromString is unhappy with const */ const char *rangehex; /* Wow, it's a lot of work to convert into a hex string in C! */ format = PyUnicode_FromString("%x"); if (!format) { PyErr_SetString(PyExc_RuntimeError, "Cannot create Python string '%x'"); return NULL; } tuple = PyTuple_New(1); if (!tuple) { Py_DECREF(format); PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails"); return NULL; } Py_INCREF(range); PyTuple_SET_ITEM(tuple, 0, range); rangePyString = PyUnicode_Format(format, tuple); if (!rangePyString) { PyErr_SetString(PyExc_Exception, "String Format failed"); Py_DECREF(format); Py_DECREF(tuple); return NULL; } Py_DECREF(format); Py_DECREF(tuple); rangehex = (const char*)PyUnicode_AsUTF8(rangePyString); if (!BN_hex2bn(&rng, rangehex)) { /*Custom errors?*/ m2_PyErr_Msg(PyExc_Exception); Py_DECREF(rangePyString); return NULL; } Py_DECREF(rangePyString); if (!(rnd = BN_new())) { PyErr_SetString(PyExc_MemoryError, "bn_rand_range"); return NULL; } if (!BN_rand_range(rnd, rng)) { /*Custom errors?*/ m2_PyErr_Msg(PyExc_Exception); BN_free(rnd); BN_free(rng); return NULL; } BN_free(rng); randhex = BN_bn2hex(rnd); if (!randhex) { /*Custom errors?*/ m2_PyErr_Msg(PyExc_Exception); BN_free(rnd); return NULL; } BN_free(rnd); ret = PyLong_FromString(randhex, NULL, 16); OPENSSL_free(randhex); return ret; } %} m2crypto-0.42.0/src/SWIG/_dh.i000066400000000000000000000103631465575656700156550ustar00rootroot00000000000000/* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. */ /* $Id$ */ %{ #include #include #include #include #include %} %apply Pointer NONNULL { DH * }; %rename(dh_new) DH_new; extern DH *DH_new(void); %rename(dh_free) DH_free; extern void DH_free(DH *); %rename(dh_size) DH_size; extern int DH_size(const DH *); %rename(dh_generate_key) DH_generate_key; extern int DH_generate_key(DH *); %rename(dhparams_print) DHparams_print; %threadallow DHparams_print; extern int DHparams_print(BIO *, const DH *); %constant int dh_check_ok = 0; %constant int dh_check_p_not_prime = DH_CHECK_P_NOT_PRIME; %constant int dh_check_p_not_strong = DH_CHECK_P_NOT_STRONG_PRIME; %constant int dh_check_g_failed = DH_UNABLE_TO_CHECK_GENERATOR; %constant int dh_check_bad_g = DH_NOT_SUITABLE_GENERATOR; %constant DH_GENERATOR_2 = 2; %constant DH_GENERATOR_5 = 5; %warnfilter(454) _dh_err; %inline %{ static PyObject *_dh_err; void dh_init(PyObject *dh_err) { Py_INCREF(dh_err); _dh_err = dh_err; } int dh_type_check(DH *dh) { /* Our getting here means we passed Swig's type checking, XXX Still need to check the pointer for sanity? */ return 1; } %} %threadallow dh_read_parameters; %inline %{ DH *dh_read_parameters(BIO *bio) { return PEM_read_bio_DHparams(bio, NULL, NULL, NULL); } DH *dh_generate_parameters(int plen, int g, PyObject *pyfunc) { DH *dh; BN_GENCB *gencb; int ret; if ((gencb=BN_GENCB_new()) == NULL) { m2_PyErr_Msg(_dh_err); return NULL; } if ((dh=DH_new()) == NULL) { m2_PyErr_Msg(_dh_err); BN_GENCB_free(gencb); return NULL; } BN_GENCB_set(gencb, bn_gencb_callback, (void *)pyfunc); Py_INCREF(pyfunc); ret = DH_generate_parameters_ex(dh, plen, g, gencb); Py_DECREF(pyfunc); BN_GENCB_free(gencb); if (ret) return dh; m2_PyErr_Msg(_dh_err); DH_free(dh); return NULL; } /* Note return value shenanigan. */ int dh_check(DH *dh) { int err; return (DH_check(dh, &err)) ? 0 : err; } PyObject *dh_compute_key(DH *dh, PyObject *pubkey) { const void *pkbuf; int pklen = 0, klen; void *key; BIGNUM *pk; PyObject *ret; if (m2_PyObject_AsReadBufferInt(pubkey, &pkbuf, &pklen) == -1) return NULL; if (!(pk = BN_mpi2bn((unsigned char *)pkbuf, pklen, NULL))) { m2_PyErr_Msg(_dh_err); return NULL; } if (!(key = PyMem_Malloc(DH_size(dh)))) { BN_free(pk); PyErr_SetString(PyExc_MemoryError, "dh_compute_key"); return NULL; } if ((klen = DH_compute_key((unsigned char *)key, pk, dh)) == -1) { BN_free(pk); PyMem_Free(key); m2_PyErr_Msg(_dh_err); return NULL; } ret = PyBytes_FromStringAndSize((const char *)key, klen); BN_free(pk); PyMem_Free(key); return ret; } PyObject *dh_get_p(DH *dh) { const BIGNUM* p = NULL; DH_get0_pqg(dh, &p, NULL, NULL); if (!p) { PyErr_SetString(_dh_err, "'p' is unset"); return NULL; } return bn_to_mpi(p); } PyObject *dh_get_g(DH *dh) { const BIGNUM* g = NULL; DH_get0_pqg(dh, NULL, NULL, &g); if (!g) { PyErr_SetString(_dh_err, "'g' is unset"); return NULL; } return bn_to_mpi(g); } PyObject *dh_get_pub(DH *dh) { const BIGNUM* pub_key = NULL; DH_get0_key(dh, &pub_key, NULL); if (!pub_key) { PyErr_SetString(_dh_err, "'pub' is unset"); return NULL; } return bn_to_mpi(pub_key); } PyObject *dh_get_priv(DH *dh) { const BIGNUM* priv_key = NULL; DH_get0_key(dh, NULL, &priv_key); if (!priv_key) { PyErr_SetString(_dh_err, "'priv' is unset"); return NULL; } return bn_to_mpi(priv_key); } PyObject *dh_set_pg(DH *dh, PyObject *pval, PyObject* gval) { BIGNUM* p, *g; if (!(p = m2_PyObject_AsBIGNUM(pval, _dh_err)) || !(g = m2_PyObject_AsBIGNUM(gval, _dh_err))) return NULL; if (!DH_set0_pqg(dh, p, NULL, g)) { PyErr_SetString(_dh_err, "Cannot set prime number or generator of Z_p for DH."); BN_free(p); BN_free(g); return NULL; } Py_RETURN_NONE; } %} m2crypto-0.42.0/src/SWIG/_dsa.i000066400000000000000000000222151465575656700160300ustar00rootroot00000000000000/* Copyright (c) 1999-2000 Ng Pheng Siong. All rights reserved. */ /* $Id$ */ %{ #include #include #include #include PyObject *dsa_sig_get_r(DSA_SIG *dsa_sig) { const BIGNUM* pr; DSA_SIG_get0(dsa_sig, &pr, NULL); return bn_to_mpi(pr); } PyObject *dsa_sig_get_s(DSA_SIG *dsa_sig) { const BIGNUM* qs; DSA_SIG_get0(dsa_sig, NULL, &qs); return bn_to_mpi(qs); } %} %apply Pointer NONNULL { DSA * }; %rename(dsa_new) DSA_new; extern DSA *DSA_new(void); %rename(dsa_free) DSA_free; extern void DSA_free(DSA *); %rename(dsa_size) DSA_size; extern int DSA_size(const DSA *); /* assert(dsa->q); */ %rename(dsa_gen_key) DSA_generate_key; extern int DSA_generate_key(DSA *); %warnfilter(454) _dsa_err; %inline %{ static PyObject *_dsa_err; void dsa_init(PyObject *dsa_err) { Py_INCREF(dsa_err); _dsa_err = dsa_err; } %} %typemap(out) DSA * { PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if ($1 != NULL) $result = SWIG_NewPointerObj($1, $1_descriptor, 0); else { $result = NULL; } } %inline %{ DSA *dsa_generate_parameters(int bits, PyObject *pyfunc) { DSA *dsa; BN_GENCB *gencb; int ret; if ((gencb=BN_GENCB_new()) == NULL) { m2_PyErr_Msg(_dh_err); return NULL; } if ((dsa = DSA_new()) == NULL) { m2_PyErr_Msg(_dsa_err); BN_GENCB_free(gencb); return NULL; } BN_GENCB_set(gencb, bn_gencb_callback, (void *) pyfunc); Py_INCREF(pyfunc); ret = DSA_generate_parameters_ex(dsa, bits, NULL, 0, NULL, NULL, gencb); Py_DECREF(pyfunc); BN_GENCB_free(gencb); if (ret) return dsa; m2_PyErr_Msg(_dsa_err); DSA_free(dsa); return NULL; } DSA *dsa_read_params(BIO *f, PyObject *pyfunc) { DSA *ret; Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS ret = PEM_read_bio_DSAparams(f, NULL, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); if (ret == NULL) { m2_PyErr_Msg(_dsa_err); } return ret; } DSA *dsa_read_key(BIO *f, PyObject *pyfunc) { DSA *ret; Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS ret = PEM_read_bio_DSAPrivateKey(f, NULL, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); if (ret == NULL) { m2_PyErr_Msg(_dsa_err); } return ret; } DSA *dsa_read_pub_key(BIO *f, PyObject *pyfunc) { DSA *ret; Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS ret = PEM_read_bio_DSA_PUBKEY(f, NULL, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); if (ret == NULL) { m2_PyErr_Msg(_dsa_err); } return ret; } %} %typemap(out) DSA * ; %inline %{ PyObject *dsa_get_p(DSA *dsa) { const BIGNUM* p = NULL; DSA_get0_pqg(dsa, &p, NULL, NULL); if (!p) { PyErr_SetString(_dsa_err, "'p' is unset"); return NULL; } return bn_to_mpi(p); } PyObject *dsa_get_q(DSA *dsa) { const BIGNUM* q = NULL; DSA_get0_pqg(dsa, NULL, &q, NULL); if (!q) { PyErr_SetString(_dsa_err, "'q' is unset"); return NULL; } return bn_to_mpi(q); } PyObject *dsa_get_g(DSA *dsa) { const BIGNUM* g = NULL; DSA_get0_pqg(dsa, NULL, NULL, &g); if (!g) { PyErr_SetString(_dsa_err, "'g' is unset"); return NULL; } return bn_to_mpi(g); } PyObject *dsa_get_pub(DSA *dsa) { const BIGNUM* pub_key = NULL; DSA_get0_key(dsa, &pub_key, NULL); if (!pub_key) { PyErr_SetString(_dsa_err, "'pub' is unset"); return NULL; } return bn_to_mpi(pub_key); } PyObject *dsa_get_priv(DSA *dsa) { const BIGNUM* priv_key = NULL; DSA_get0_key(dsa, NULL, &priv_key); if (!priv_key) { PyErr_SetString(_dsa_err, "'priv' is unset"); return NULL; } return bn_to_mpi(priv_key); } PyObject *dsa_set_pqg(DSA *dsa, PyObject *pval, PyObject* qval, PyObject* gval) { BIGNUM* p, *q, *g; if (!(p = m2_PyObject_AsBIGNUM(pval, _dsa_err)) || !(q = m2_PyObject_AsBIGNUM(qval, _dsa_err)) || !(g = m2_PyObject_AsBIGNUM(gval, _dsa_err))) return NULL; if (!DSA_set0_pqg(dsa, p, q, g)) { PyErr_SetString( _dsa_err, "Cannot set prime number, subprime, or generator of subgroup for DSA."); BN_free(p); BN_free(q); BN_free(g); return NULL; } Py_RETURN_NONE; } PyObject *dsa_set_pub(DSA *dsa, PyObject *value) { BIGNUM *bn; const void *vbuf; int vlen = 0; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) { m2_PyErr_Msg(_dsa_err); return NULL; } if (!DSA_set0_key(dsa, bn, NULL)) { BN_free(bn); PyErr_SetString(_dsa_err, "Cannot set private and public key for DSA."); } Py_RETURN_NONE; } %} %threadallow dsa_write_params_bio; %inline %{ int dsa_write_params_bio(DSA* dsa, BIO* f) { return PEM_write_bio_DSAparams(f, dsa); } %} %inline %{ int dsa_write_key_bio(DSA* dsa, BIO* f, EVP_CIPHER *cipher, PyObject *pyfunc) { int ret; Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS ret = PEM_write_bio_DSAPrivateKey(f, dsa, cipher, NULL, 0, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); return ret; } %} %inline %{ int dsa_write_key_bio_no_cipher(DSA* dsa, BIO* f, PyObject *pyfunc) { int ret; Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS ret = PEM_write_bio_DSAPrivateKey(f, dsa, NULL, NULL, 0, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); return ret; } %} %threadallow dsa_write_pub_key_bio; %inline %{ int dsa_write_pub_key_bio(DSA* dsa, BIO* f) { return PEM_write_bio_DSA_PUBKEY(f, dsa); } %} %inline %{ PyObject *dsa_sign(DSA *dsa, PyObject *value) { const void *vbuf; int vlen = 0; PyObject *tuple; DSA_SIG *sig; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; if (!(sig = DSA_do_sign(vbuf, vlen, dsa))) { m2_PyErr_Msg(_dsa_err); return NULL; } if (!(tuple = PyTuple_New(2))) { DSA_SIG_free(sig); PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails"); return NULL; } PyTuple_SET_ITEM(tuple, 0, dsa_sig_get_r(sig)); PyTuple_SET_ITEM(tuple, 1, dsa_sig_get_s(sig)); DSA_SIG_free(sig); return tuple; } int dsa_verify(DSA *dsa, PyObject *value, PyObject *r, PyObject *s) { const void *vbuf, *rbuf, *sbuf; int vlen = 0, rlen = 0, slen = 0; DSA_SIG *sig; BIGNUM* pr, *ps; int ret; if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) || (m2_PyObject_AsReadBufferInt(r, &rbuf, &rlen) == -1) || (m2_PyObject_AsReadBufferInt(s, &sbuf, &slen) == -1)) return -1; if (!(sig = DSA_SIG_new())) { m2_PyErr_Msg(_dsa_err); return -1; } if (!(pr = BN_mpi2bn((unsigned char *)rbuf, rlen, NULL))) { m2_PyErr_Msg(_dsa_err); DSA_SIG_free(sig); return -1; } if (!(ps = BN_mpi2bn((unsigned char *)sbuf, slen, NULL))) { m2_PyErr_Msg(_dsa_err); DSA_SIG_free(sig); BN_free(pr); return -1; } if (!DSA_SIG_set0(sig, pr, ps)) { m2_PyErr_Msg(_dsa_err); DSA_SIG_free(sig); BN_free(pr); BN_free(ps); return -1; } ret = DSA_do_verify(vbuf, vlen, sig, dsa); DSA_SIG_free(sig); if (ret == -1) m2_PyErr_Msg(_dsa_err); return ret; } PyObject *dsa_sign_asn1(DSA *dsa, PyObject *value) { const void *vbuf; int vlen = 0; void *sigbuf; unsigned int siglen; PyObject *ret; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; if (!(sigbuf = PyMem_Malloc(DSA_size(dsa)))) { PyErr_SetString(PyExc_MemoryError, "dsa_sign_asn1"); return NULL; } if (!DSA_sign(0, vbuf, vlen, (unsigned char *)sigbuf, &siglen, dsa)) { m2_PyErr_Msg(_dsa_err); PyMem_Free(sigbuf); return NULL; } ret = PyBytes_FromStringAndSize(sigbuf, siglen); PyMem_Free(sigbuf); return ret; } int dsa_verify_asn1(DSA *dsa, PyObject *value, PyObject *sig) { const void *vbuf; void *sbuf; int vlen = 0, slen = 0, ret = 0; if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) || (m2_PyObject_AsReadBufferInt(sig, (const void **)&sbuf, &slen) == -1)) return -1; if ((ret = DSA_verify(0, vbuf, vlen, sbuf, slen, dsa)) == -1) m2_PyErr_Msg(_dsa_err); return ret; } int dsa_check_key(DSA *dsa) { const BIGNUM* pub_key, *priv_key; DSA_get0_key(dsa, &pub_key, &priv_key); return pub_key != NULL && priv_key != NULL; } int dsa_check_pub_key(DSA *dsa) { const BIGNUM* pub_key; DSA_get0_key(dsa, &pub_key, NULL); return pub_key ? 1 : 0; } int dsa_keylen(DSA *dsa) { const BIGNUM* p; DSA_get0_pqg(dsa, &p, NULL, NULL); return BN_num_bits(p); } int dsa_type_check(DSA *dsa) { return 1; } %} m2crypto-0.42.0/src/SWIG/_ec.i000066400000000000000000000354051465575656700156550ustar00rootroot00000000000000/* Copyright (c) 1999-2000 Ng Pheng Siong. All rights reserved. Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All rights reserved. Most code originally from _dsa.i, _rsa.i and _dh.i and adjusted for EC use. */ %include #if OPENSSL_VERSION_NUMBER < 0x0090800fL || defined(OPENSSL_NO_EC) #undef OPENSSL_NO_EC %constant OPENSSL_NO_EC = 1; #else %constant OPENSSL_NO_EC = 0; %{ #include #include #include #include #include #include %} %apply Pointer NONNULL { EC_KEY * }; %rename(ec_key_new) EC_KEY_new; extern EC_KEY *EC_KEY_new(void); %rename(ec_key_free) EC_KEY_free; extern void EC_KEY_free(EC_KEY *); %rename(ec_key_size) ECDSA_size; extern int ECDSA_size(const EC_KEY *); %rename(ec_key_gen_key) EC_KEY_generate_key; extern int EC_KEY_generate_key(EC_KEY *); %rename(ec_key_check_key) EC_KEY_check_key; extern int EC_KEY_check_key(const EC_KEY *); /* Curve identifier constants from OpenSSL */ %constant int NID_secp112r1 = NID_secp112r1; %constant int NID_secp112r2 = NID_secp112r2; %constant int NID_secp128r1 = NID_secp128r1; %constant int NID_secp128r2 = NID_secp128r2; %constant int NID_secp160k1 = NID_secp160k1; %constant int NID_secp160r1 = NID_secp160r1; %constant int NID_secp160r2 = NID_secp160r2; %constant int NID_secp192k1 = NID_secp192k1; %constant int NID_secp224k1 = NID_secp224k1; %constant int NID_secp224r1 = NID_secp224r1; %constant int NID_secp256k1 = NID_secp256k1; %constant int NID_secp384r1 = NID_secp384r1; %constant int NID_secp521r1 = NID_secp521r1; %constant int NID_sect113r1 = NID_sect113r1; %constant int NID_sect113r2 = NID_sect113r2; %constant int NID_sect131r1 = NID_sect131r1; %constant int NID_sect131r2 = NID_sect131r2; %constant int NID_sect163k1 = NID_sect163k1; %constant int NID_sect163r1 = NID_sect163r1; %constant int NID_sect163r2 = NID_sect163r2; %constant int NID_sect193r1 = NID_sect193r1; %constant int NID_sect193r2 = NID_sect193r2; %constant int NID_sect233k1 = NID_sect233k1; %constant int NID_sect233r1 = NID_sect233r1; %constant int NID_sect239k1 = NID_sect239k1; %constant int NID_sect283k1 = NID_sect283k1; %constant int NID_sect283r1 = NID_sect283r1; %constant int NID_sect409k1 = NID_sect409k1; %constant int NID_sect409r1 = NID_sect409r1; %constant int NID_sect571k1 = NID_sect571k1; %constant int NID_sect571r1 = NID_sect571r1; %constant int NID_X9_62_prime192v1 = NID_X9_62_prime192v1; %constant int NID_X9_62_prime192v2 = NID_X9_62_prime192v2; %constant int NID_X9_62_prime192v3 = NID_X9_62_prime192v3; %constant int NID_X9_62_prime239v1 = NID_X9_62_prime239v1; %constant int NID_X9_62_prime239v2 = NID_X9_62_prime239v2; %constant int NID_X9_62_prime239v3 = NID_X9_62_prime239v3; %constant int NID_X9_62_prime256v1 = NID_X9_62_prime256v1; %constant int NID_X9_62_c2pnb163v1 = NID_X9_62_c2pnb163v1; %constant int NID_X9_62_c2pnb163v2 = NID_X9_62_c2pnb163v2; %constant int NID_X9_62_c2pnb163v3 = NID_X9_62_c2pnb163v3; %constant int NID_X9_62_c2pnb176v1 = NID_X9_62_c2pnb176v1; %constant int NID_X9_62_c2tnb191v1 = NID_X9_62_c2tnb191v1; %constant int NID_X9_62_c2tnb191v2 = NID_X9_62_c2tnb191v2; %constant int NID_X9_62_c2tnb191v3 = NID_X9_62_c2tnb191v3; %constant int NID_X9_62_c2pnb208w1 = NID_X9_62_c2pnb208w1; %constant int NID_X9_62_c2tnb239v1 = NID_X9_62_c2tnb239v1; %constant int NID_X9_62_c2tnb239v2 = NID_X9_62_c2tnb239v2; %constant int NID_X9_62_c2tnb239v3 = NID_X9_62_c2tnb239v3; %constant int NID_X9_62_c2pnb272w1 = NID_X9_62_c2pnb272w1; %constant int NID_X9_62_c2pnb304w1 = NID_X9_62_c2pnb304w1; %constant int NID_X9_62_c2tnb359v1 = NID_X9_62_c2tnb359v1; %constant int NID_X9_62_c2pnb368w1 = NID_X9_62_c2pnb368w1; %constant int NID_X9_62_c2tnb431r1 = NID_X9_62_c2tnb431r1; %constant int NID_wap_wsg_idm_ecid_wtls1 = NID_wap_wsg_idm_ecid_wtls1; %constant int NID_wap_wsg_idm_ecid_wtls3 = NID_wap_wsg_idm_ecid_wtls3; %constant int NID_wap_wsg_idm_ecid_wtls4 = NID_wap_wsg_idm_ecid_wtls4; %constant int NID_wap_wsg_idm_ecid_wtls5 = NID_wap_wsg_idm_ecid_wtls5; %constant int NID_wap_wsg_idm_ecid_wtls6 = NID_wap_wsg_idm_ecid_wtls6; %constant int NID_wap_wsg_idm_ecid_wtls7 = NID_wap_wsg_idm_ecid_wtls7; %constant int NID_wap_wsg_idm_ecid_wtls8 = NID_wap_wsg_idm_ecid_wtls8; %constant int NID_wap_wsg_idm_ecid_wtls9 = NID_wap_wsg_idm_ecid_wtls9; %constant int NID_wap_wsg_idm_ecid_wtls10 = NID_wap_wsg_idm_ecid_wtls10; %constant int NID_wap_wsg_idm_ecid_wtls11 = NID_wap_wsg_idm_ecid_wtls11; %constant int NID_wap_wsg_idm_ecid_wtls12 = NID_wap_wsg_idm_ecid_wtls12; %constant int NID_ipsec3 = NID_ipsec3; %constant int NID_ipsec4 = NID_ipsec4; %warnfilter(454) _ec_err; %inline %{ static PyObject *_ec_err; void ec_init(PyObject *ec_err) { Py_INCREF(ec_err); _ec_err = ec_err; } PyObject *ec_get_builtin_curves(void) { /* size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t * nitems); */ EC_builtin_curve *curves; Py_ssize_t ret_curves = 0; size_t num_curves = EC_get_builtin_curves(NULL, 0); PyObject *ret_tuple = NULL; PyObject *ret_dict = NULL; Py_ssize_t i; const char *comment; const char *sname; if (!(curves = PyMem_Malloc(num_curves * sizeof(EC_builtin_curve)))) { PyErr_SetString(PyExc_MemoryError, "ec_get_builtin_curves"); return NULL; } ret_curves = (Py_ssize_t)EC_get_builtin_curves(curves, num_curves); if (!(ret_tuple = PyTuple_New(ret_curves))) { PyErr_SetString(PyExc_MemoryError, "ec_get_builtin_curves"); return NULL; } for (i = 0; i < ret_curves; i++) { if (!(ret_dict = PyDict_New())) { PyErr_SetString(PyExc_MemoryError, "ec_get_builtin_curves"); return NULL; } comment = curves[i].comment; sname = OBJ_nid2sn(curves[i].nid); if (sname == NULL) sname = ""; PyDict_SetItemString(ret_dict, "NID", PyLong_FromLong((long)curves[i].nid)); PyDict_SetItemString(ret_dict, "sname", PyString_FromString(sname)); PyDict_SetItemString(ret_dict, "comment", PyString_FromString(comment)); PyTuple_SET_ITEM(ret_tuple, i, ret_dict); } PyMem_Free(curves); return ret_tuple; } EC_KEY* ec_key_new_by_curve_name(int nid) { EC_KEY *key; EC_GROUP *group; int ret =0; point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED; int asn1_flag = OPENSSL_EC_NAMED_CURVE; /* If I simply do "return EC_KEY_new_by_curve_name(nid);" * I get large public keys (222 vs 84 bytes for sect233k1 curve). * I don't know why that is, but 'openssl ecparam -genkey ...' sets * the ASN.1 flag and the point conversion form, and gets the * small pub keys. So let's do that too. */ key = EC_KEY_new(); if (!key) { PyErr_SetString(PyExc_MemoryError, "ec_key_new_by_curve_name"); return NULL; } group = EC_GROUP_new_by_curve_name(nid); if (!group) { m2_PyErr_Msg(_ec_err); EC_KEY_free(key); return NULL; } EC_GROUP_set_asn1_flag(group, asn1_flag); EC_GROUP_set_point_conversion_form(group, form); ret = EC_KEY_set_group(key, group); EC_GROUP_free(group); if (ret == 0) { /* EC_KEY_set_group only returns 0 or 1, and does not set error. */ PyErr_SetString(_ec_err, "cannot set key's group"); EC_KEY_free(key); return NULL; } return key; } PyObject *ec_key_get_public_der(EC_KEY *key) { char *src=NULL; int src_len=0; PyObject *pyo=NULL; /* Convert to binary */ src_len = i2d_EC_PUBKEY( key, (unsigned char**)&src ); if (src_len < 0) { m2_PyErr_Msg(_ec_err); return NULL; } /* Create a PyBuffer containing a copy of the binary, * to simplify memory deallocation */ pyo = PyBytes_FromStringAndSize( src, src_len ); OPENSSL_free(src); return pyo; } PyObject *ec_key_get_public_key(EC_KEY *key) { char *src=NULL; int src_len=0; PyObject *pyo=NULL; /* Convert to binary */ src_len = i2o_ECPublicKey(key, (unsigned char**)&src); if (src_len < 0) { m2_PyErr_Msg(_ec_err); return NULL; } pyo = PyBytes_FromStringAndSize( src, src_len ); OPENSSL_free(src); return pyo; } %} %threadallow ec_key_read_pubkey; %inline %{ EC_KEY *ec_key_read_pubkey(BIO *f) { return PEM_read_bio_EC_PUBKEY(f, NULL, NULL, NULL); } %} %threadallow ec_key_write_pubkey; %inline %{ int ec_key_write_pubkey(EC_KEY *key, BIO *f) { return PEM_write_bio_EC_PUBKEY(f, key ); } %} %inline %{ EC_KEY *ec_key_read_bio(BIO *f, PyObject *pyfunc) { EC_KEY *ret; Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS ret = PEM_read_bio_ECPrivateKey(f, NULL, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); return ret; } %} %inline %{ int ec_key_write_bio(EC_KEY *key, BIO *f, EVP_CIPHER *cipher, PyObject *pyfunc) { int ret; Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS ret = PEM_write_bio_ECPrivateKey(f, key, cipher, NULL, 0, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); return ret; } %} %inline %{ int ec_key_write_bio_no_cipher(EC_KEY *key, BIO *f, PyObject *pyfunc) { int ret; Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS ret = PEM_write_bio_ECPrivateKey(f, key, NULL, NULL, 0, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); return ret; } PyObject *ecdsa_sig_get_r(ECDSA_SIG *ecdsa_sig) { const BIGNUM* pr; ECDSA_SIG_get0(ecdsa_sig, &pr, NULL); return bn_to_mpi(pr); } PyObject *ecdsa_sig_get_s(ECDSA_SIG *ecdsa_sig) { const BIGNUM* ps; ECDSA_SIG_get0(ecdsa_sig, NULL, &ps); return bn_to_mpi(ps); } PyObject *ecdsa_sign(EC_KEY *key, PyObject *value) { const void *vbuf; int vlen = 0; PyObject *tuple; ECDSA_SIG *sig; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; if (!(sig = ECDSA_do_sign(vbuf, vlen, key))) { m2_PyErr_Msg(_ec_err); return NULL; } if (!(tuple = PyTuple_New(2))) { ECDSA_SIG_free(sig); PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails"); return NULL; } PyTuple_SET_ITEM(tuple, 0, ecdsa_sig_get_r(sig)); PyTuple_SET_ITEM(tuple, 1, ecdsa_sig_get_s(sig)); ECDSA_SIG_free(sig); return tuple; } int ecdsa_verify(EC_KEY *key, PyObject *value, PyObject *r, PyObject *s) { const void *vbuf, *rbuf, *sbuf; int vlen = 0, rlen = 0, slen = 0; ECDSA_SIG *sig; int ret; BIGNUM* pr, *ps; if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) || (m2_PyObject_AsReadBufferInt(r, &rbuf, &rlen) == -1) || (m2_PyObject_AsReadBufferInt(s, &sbuf, &slen) == -1)) return -1; if (!(pr = BN_mpi2bn((unsigned char *)rbuf, rlen, NULL))) { m2_PyErr_Msg(_ec_err); return -1; } if (!(ps = BN_mpi2bn((unsigned char *)sbuf, slen, NULL))) { m2_PyErr_Msg(_ec_err); BN_free(pr); return -1; } if (!(sig = ECDSA_SIG_new())) { m2_PyErr_Msg(_ec_err); BN_free(pr); BN_free(ps); return -1; } if (!ECDSA_SIG_set0(sig, pr, ps)) { PyErr_SetString(_ec_err, "Cannot set r and s fields of ECDSA_SIG."); ECDSA_SIG_free(sig); BN_free(pr); BN_free(ps); return -1; } ret = ECDSA_do_verify(vbuf, vlen, sig, key); ECDSA_SIG_free(sig); if (ret == -1) m2_PyErr_Msg(_ec_err); return ret; } PyObject *ecdsa_sign_asn1(EC_KEY *key, PyObject *value) { const void *vbuf; int vlen = 0; void *sigbuf; unsigned int siglen; PyObject *ret; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; if (!(sigbuf = PyMem_Malloc(ECDSA_size(key)))) { PyErr_SetString(PyExc_MemoryError, "ecdsa_sign_asn1"); return NULL; } if (!ECDSA_sign(0, vbuf, vlen, (unsigned char *)sigbuf, &siglen, key)) { m2_PyErr_Msg(_ec_err); PyMem_Free(sigbuf); return NULL; } ret = PyBytes_FromStringAndSize(sigbuf, siglen); PyMem_Free(sigbuf); return ret; } int ecdsa_verify_asn1(EC_KEY *key, PyObject *value, PyObject *sig) { const void *vbuf; void *sbuf; int vlen = 0, slen = 0, ret; if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) || (m2_PyObject_AsReadBufferInt(sig, (const void **)&sbuf, &slen) == -1)) return -1; if ((ret = ECDSA_verify(0, vbuf, vlen, sbuf, slen, key)) == -1) m2_PyErr_Msg(_ec_err); return ret; } PyObject *ecdh_compute_key(EC_KEY *keypairA, EC_KEY *pubkeyB) { int sharedkeylen; void *sharedkey; const EC_POINT *pkpointB; PyObject *ret; const EC_GROUP* groupA; if ((pkpointB = EC_KEY_get0_public_key(pubkeyB)) == NULL) { PyErr_SetString(_ec_err, "Cannot get the public key of EC_KEY object."); return NULL; } groupA = EC_KEY_get0_group(keypairA); sharedkeylen = (EC_GROUP_get_degree(groupA) + 7)/8; if (!(sharedkey = PyMem_Malloc(sharedkeylen))) { PyErr_SetString(PyExc_MemoryError, "ecdh_compute_key"); return NULL; } if ((sharedkeylen = ECDH_compute_key((unsigned char *)sharedkey, sharedkeylen, pkpointB, keypairA, NULL)) == -1) { m2_PyErr_Msg(_ec_err); PyMem_Free(sharedkey); return NULL; } ret = PyBytes_FromStringAndSize((const char *)sharedkey, sharedkeylen); PyMem_Free(sharedkey); return ret; } EC_KEY* ec_key_from_pubkey_der(PyObject *pubkey) { const void *keypairbuf; Py_ssize_t keypairbuflen; const unsigned char *tempBuf; EC_KEY *keypair; if (m2_PyObject_AsReadBuffer(pubkey, &keypairbuf, &keypairbuflen) == -1) { return NULL; } tempBuf = (const unsigned char *)keypairbuf; if ((keypair = d2i_EC_PUBKEY( NULL, &tempBuf, keypairbuflen)) == 0) { m2_PyErr_Msg(_ec_err); return NULL; } return keypair; } EC_KEY* ec_key_from_pubkey_params(int nid, PyObject *pubkey) { const void *keypairbuf; Py_ssize_t keypairbuflen; const unsigned char *tempBuf; EC_KEY *keypair; if (m2_PyObject_AsReadBuffer(pubkey, &keypairbuf, &keypairbuflen) == -1) { return NULL; } keypair = ec_key_new_by_curve_name(nid); if (!keypair) { m2_PyErr_Msg(_ec_err); return NULL; } tempBuf = (const unsigned char *)keypairbuf; if ((o2i_ECPublicKey( &keypair, &tempBuf, keypairbuflen)) == 0) { m2_PyErr_Msg(_ec_err); return NULL; } return keypair; } // According to [SEC2] the degree of the group is defined as EC key length int ec_key_keylen(EC_KEY *key) { const EC_GROUP *group = EC_KEY_get0_group(key); return EC_GROUP_get_degree(group); } int ec_key_type_check(EC_KEY *key) { return 1; } %} #endif // if OpenSSL version with EC support m2crypto-0.42.0/src/SWIG/_engine.i000066400000000000000000000125441465575656700165320ustar00rootroot00000000000000/* * -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: syntax=c sts=4 sw=4 * * ENGINE functions from engine(3SSL). * * Pavel Shramov * IMEC MSU */ %{ #include #include #include %} %apply Pointer NONNULL { ENGINE * }; %apply Pointer NONNULL { const ENGINE * }; %apply Pointer NONNULL { const char * }; /* * Functions to load different engines */ %rename(engine_load_builtin_engines) ENGINE_load_builtin_engines; extern void ENGINE_load_builtin_engines(void); %rename(engine_load_dynamic) ENGINE_load_dynamic; extern void ENGINE_load_dynamic(void); %rename(engine_load_openssl) ENGINE_load_openssl; extern void ENGINE_load_openssl(void); %rename(engine_cleanup) ENGINE_cleanup; extern void ENGINE_cleanup(void); /* * Engine allocation functions */ %rename(engine_new) ENGINE_new; extern ENGINE * ENGINE_new(); %rename(engine_by_id) ENGINE_by_id; extern ENGINE * ENGINE_by_id(const char *); %rename(engine_free) ENGINE_free; extern int ENGINE_free(ENGINE *); %rename(engine_init) ENGINE_init; extern int ENGINE_init(ENGINE *); %rename(engine_finish) ENGINE_finish; extern int ENGINE_finish(ENGINE *); /* * Engine id/name functions */ %rename(engine_get_id) ENGINE_get_id; extern const char * ENGINE_get_id(const ENGINE *); %rename(engine_get_name) ENGINE_get_name; extern const char * ENGINE_get_name(const ENGINE *); /* * Engine control functions * Control argument may be NULL (e.g for LOAD command) */ %clear const char *; %rename(engine_ctrl_cmd_string) ENGINE_ctrl_cmd_string; extern int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg, int cmd_optional); %apply Pointer NONNULL { const char * }; /* * UI methods. * XXX: UI_OpenSSL method is static and UI_destroy_method is not needed. */ %rename(ui_openssl) UI_OpenSSL; extern UI_METHOD * UI_OpenSSL(); /* %rename(ui_destroy_method) UI_destroy_method; extern void UI_destroy_method(UI_METHOD *ui_method); */ %clear const char *; %inline %{ /* * Code from engine-pkcs11 1.4.0 in engine-pkcs11.c * 99 static char *get_pin(UI_METHOD * ui_method, void *callback_data, char *sc_pin, 100 int maxlen) 101 { 102 UI *ui; 103 struct { 104 const void *password; 105 const char *prompt_info; 106 } *mycb = callback_data; 107 108 if (mycb->password) { 109 sc_pin = set_pin(mycb->password); 110 return sc_pin; 111 } * * So callback_data need to be always provided and have fixed type. * UI method still may be NULL. * * Following functions allocate and free callback data structure with * optional password set. */ typedef struct { char * password; char * prompt; } _cbd_t; void * engine_pkcs11_data_new(const char *pin) { _cbd_t * cb = (_cbd_t *) PyMem_Malloc(sizeof(_cbd_t)); if (!cb) { PyErr_SetString(PyExc_MemoryError, "engine_pkcs11_data_new"); return NULL; } cb->password = NULL; if (pin) { size_t size = strlen(pin); cb->password = (char *) PyMem_Malloc(size + 1); if (!cb->password) { PyErr_SetString(PyExc_MemoryError, "engine_pkcs11_data_new"); PyMem_Free(cb); return NULL; } memcpy(cb->password, pin, size + 1); } cb->prompt = NULL; return cb; } void engine_pkcs11_data_free(void * vcb) { _cbd_t * cb = (_cbd_t *) vcb; if (!cb) return; if (cb->password) PyMem_Free(cb->password); PyMem_Free(cb); } %} %apply Pointer NONNULL { const char * }; /* * Engine key/cert load functions. * See above notice about callback_data. */ %rename(engine_load_private_key) ENGINE_load_private_key; extern EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id, UI_METHOD *ui_method, void *callback_data); %rename(engine_load_public_key) ENGINE_load_public_key; extern EVP_PKEY *ENGINE_load_public_key(ENGINE *e, const char *key_id, UI_METHOD *ui_method, void *callback_data); /* * This function may be not implemented in engine. * pkcs11 engine has this control. */ %warnfilter(454) _engine_err; %inline %{ static PyObject *_engine_err; void engine_init_error(PyObject *engine_err) { Py_INCREF(engine_err); _engine_err = engine_err; } X509 * engine_load_certificate(ENGINE *e, const char * slot) { struct { const char * slot; X509 * cert; } cbd; cbd.slot = slot; cbd.cert = NULL; if (!ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &cbd, NULL, 0)) { PyErr_SetString(_engine_err, "cannot load certificate"); return NULL; } return cbd.cert; } %} /* These flags are used to control combinations of algorithm (methods) * by bitwise "OR"ing. */ %constant int ENGINE_METHOD_RSA = 0x0001; %constant int ENGINE_METHOD_DSA = 0x0002; %constant int ENGINE_METHOD_DH = 0x0004; %constant int ENGINE_METHOD_RAND = 0x0008; %constant int ENGINE_METHOD_ECDH = 0x0010; %constant int ENGINE_METHOD_ECDSA = 0x0020; %constant int ENGINE_METHOD_CIPHERS = 0x0040; %constant int ENGINE_METHOD_DIGESTS = 0x0080; %constant int ENGINE_METHOD_STORE = 0x0100; /* Obvious all-or-nothing cases. */ %constant int ENGINE_METHOD_ALL = 0xFFFF; %constant int ENGINE_METHOD_NONE = 0x0000; %rename(engine_set_default) ENGINE_set_default; extern int ENGINE_set_default(ENGINE *e, unsigned int flags); m2crypto-0.42.0/src/SWIG/_evp.i000066400000000000000000000602061465575656700160550ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. Portions Copyright (c) 2004-2007 Open Source Applications Foundation. Author: Heikki Toivonen Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved. */ %include %{ #include #include #include #include #include #include #include #if OPENSSL_VERSION_NUMBER < 0x10100000L HMAC_CTX *HMAC_CTX_new(void) { HMAC_CTX *ret = PyMem_Malloc(sizeof(HMAC_CTX)); HMAC_CTX_init(ret); return ret; } #define HMAC_CTX_reset(ctx) HMAC_CTX_init(ctx) #define HMAC_CTX_free(ctx) \ do { \ HMAC_CTX_cleanup(ctx); \ PyMem_Free((void *)ctx); \ } while(0) #define EVP_CIPHER_CTX_reset(ctx) EVP_CIPHER_CTX_init(ctx) #endif %} /* from openssl/crypto/include/internal/evp_int.h struct evp_md_st typedef struct evp_md_st EVP_MD; from openssl/crypto/evp/evp_locl.h evp_md_ctx_st typedef struct evp_md_ctx_st EVP_MD_CTX; */ %apply Pointer NONNULL { EVP_MD_CTX * }; %apply Pointer NONNULL { EVP_MD * }; %apply Pointer NONNULL { EVP_PKEY * }; %apply Pointer NONNULL { HMAC_CTX * }; %apply Pointer NONNULL { EVP_CIPHER_CTX * }; %apply Pointer NONNULL { EVP_CIPHER * }; %apply Pointer NONNULL { RSA * }; %apply Pointer NONNULL { EC_KEY * }; %rename(md5) EVP_md5; extern const EVP_MD *EVP_md5(void); %rename(sha1) EVP_sha1; extern const EVP_MD *EVP_sha1(void); %rename(ripemd160) EVP_ripemd160; extern const EVP_MD *EVP_ripemd160(void); #if OPENSSL_VERSION_NUMBER >= 0x0090800fL %rename(sha224) EVP_sha224; extern const EVP_MD *EVP_sha224(void); %rename(sha256) EVP_sha256; extern const EVP_MD *EVP_sha256(void); %rename(sha384) EVP_sha384; extern const EVP_MD *EVP_sha384(void); %rename(sha512) EVP_sha512; extern const EVP_MD *EVP_sha512(void); #endif %rename(digest_init) EVP_DigestInit; extern int EVP_DigestInit(EVP_MD_CTX *, const EVP_MD *); %rename(des_ecb) EVP_des_ecb; extern const EVP_CIPHER *EVP_des_ecb(void); %rename(des_ede_ecb) EVP_des_ede; extern const EVP_CIPHER *EVP_des_ede(void); %rename(des_ede3_ecb) EVP_des_ede3; extern const EVP_CIPHER *EVP_des_ede3(void); %rename(des_cbc) EVP_des_cbc; extern const EVP_CIPHER *EVP_des_cbc(void); %rename(des_ede_cbc) EVP_des_ede_cbc; extern const EVP_CIPHER *EVP_des_ede_cbc(void); %rename(des_ede3_cbc) EVP_des_ede3_cbc; extern const EVP_CIPHER *EVP_des_ede3_cbc(void); %rename(des_cfb) EVP_des_cfb; extern const EVP_CIPHER *EVP_des_cfb(void); %rename(des_ede_cfb) EVP_des_ede_cfb; extern const EVP_CIPHER *EVP_des_ede_cfb(void); %rename(des_ede3_cfb) EVP_des_ede3_cfb; extern const EVP_CIPHER *EVP_des_ede3_cfb(void); %rename(des_ofb) EVP_des_ofb; extern const EVP_CIPHER *EVP_des_ofb(void); %rename(des_ede_ofb) EVP_des_ede_ofb; extern const EVP_CIPHER *EVP_des_ede_ofb(void); %rename(des_ede3_ofb) EVP_des_ede3_ofb; extern const EVP_CIPHER *EVP_des_ede3_ofb(void); %rename(bf_ecb) EVP_bf_ecb; extern const EVP_CIPHER *EVP_bf_ecb(void); %rename(bf_cbc) EVP_bf_cbc; extern const EVP_CIPHER *EVP_bf_cbc(void); %rename(bf_cfb) EVP_bf_cfb; extern const EVP_CIPHER *EVP_bf_cfb(void); %rename(bf_ofb) EVP_bf_ofb; extern const EVP_CIPHER *EVP_bf_ofb(void); /* %rename(idea_ecb) extern const EVP_CIPHER *EVP_idea_ecb(void); %rename(idea_cbc) extern const EVP_CIPHER *EVP_idea_cbc(void); %rename(idea_cfb) extern const EVP_CIPHER *EVP_idea_cfb(void); %rename(idea_ofb) extern const EVP_CIPHER *EVP_idea_ofb(void); */ %rename(cast5_ecb) EVP_cast5_ecb; extern const EVP_CIPHER *EVP_cast5_ecb(void); %rename(cast5_cbc) EVP_cast5_cbc; extern const EVP_CIPHER *EVP_cast5_cbc(void); %rename(cast5_cfb) EVP_cast5_cfb; extern const EVP_CIPHER *EVP_cast5_cfb(void); %rename(cast5_ofb) EVP_cast5_ofb; extern const EVP_CIPHER *EVP_cast5_ofb(void); /* %rename(rc5_ecb) extern const EVP_CIPHER *EVP_rc5_32_12_16_ecb(void); %rename(rc5_cbc) extern const EVP_CIPHER *EVP_rc5_32_12_16_cbc(void); %rename(rc5_cfb) extern const EVP_CIPHER *EVP_rc5_32_12_16_cfb(void); %rename(rc5_ofb) extern const EVP_CIPHER *EVP_rc5_32_12_16_ofb(void); */ #if !defined(OPENSSL_NO_RC4) %rename(rc4) EVP_rc4; extern const EVP_CIPHER *EVP_rc4(void); #endif #if !defined(OPENSSL_NO_RC2) %rename(rc2_40_cbc) EVP_rc2_40_cbc; extern const EVP_CIPHER *EVP_rc2_40_cbc(void); #endif %rename(aes_128_ecb) EVP_aes_128_ecb; extern const EVP_CIPHER *EVP_aes_128_ecb(void); %rename(aes_128_cbc) EVP_aes_128_cbc; extern const EVP_CIPHER *EVP_aes_128_cbc(void); %rename(aes_128_cfb) EVP_aes_128_cfb; extern const EVP_CIPHER *EVP_aes_128_cfb(void); %rename(aes_128_ofb) EVP_aes_128_ofb; extern const EVP_CIPHER *EVP_aes_128_ofb(void); %rename(aes_128_ctr) EVP_aes_128_ctr; extern const EVP_CIPHER *EVP_aes_128_ctr(void); %rename(aes_192_ecb) EVP_aes_192_ecb; extern const EVP_CIPHER *EVP_aes_192_ecb(void); %rename(aes_192_cbc) EVP_aes_192_cbc; extern const EVP_CIPHER *EVP_aes_192_cbc(void); %rename(aes_192_cfb) EVP_aes_192_cfb; extern const EVP_CIPHER *EVP_aes_192_cfb(void); %rename(aes_192_ofb) EVP_aes_192_ofb; extern const EVP_CIPHER *EVP_aes_192_ofb(void); %rename(aes_192_ctr) EVP_aes_192_ctr; extern const EVP_CIPHER *EVP_aes_192_ctr(void); %rename(aes_256_ecb) EVP_aes_256_ecb; extern const EVP_CIPHER *EVP_aes_256_ecb(void); %rename(aes_256_cbc) EVP_aes_256_cbc; extern const EVP_CIPHER *EVP_aes_256_cbc(void); %rename(aes_256_cfb) EVP_aes_256_cfb; extern const EVP_CIPHER *EVP_aes_256_cfb(void); %rename(aes_256_ofb) EVP_aes_256_ofb; extern const EVP_CIPHER *EVP_aes_256_ofb(void); %rename(aes_256_ctr) EVP_aes_256_ctr; extern EVP_CIPHER const *EVP_aes_256_ctr(void); %rename(cipher_set_padding) EVP_CIPHER_CTX_set_padding; extern int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *, int); %rename(cipher_set_padding) EVP_CIPHER_CTX_set_padding; extern int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *x, int padding); %rename(pkey_free) EVP_PKEY_free; extern void EVP_PKEY_free(EVP_PKEY *); %rename(pkey_assign) EVP_PKEY_assign; extern int EVP_PKEY_assign(EVP_PKEY *, int, char *); #if OPENSSL_VERSION_NUMBER >= 0x0090800fL && !defined(OPENSSL_NO_EC) %rename(pkey_assign_ec) EVP_PKEY_assign_EC_KEY; extern int EVP_PKEY_assign_EC_KEY(EVP_PKEY *, EC_KEY *); %rename(pkey_set1_ec) EVP_PKEY_set1_EC_KEY; extern int EVP_PKEY_set1_EC_KEY(EVP_PKEY *, EC_KEY *); #endif %rename(pkey_set1_rsa) EVP_PKEY_set1_RSA; extern int EVP_PKEY_set1_RSA(EVP_PKEY *, RSA *); %rename(sign_init) EVP_SignInit; extern int EVP_SignInit(EVP_MD_CTX *, const EVP_MD *); %rename(verify_init) EVP_VerifyInit; extern int EVP_VerifyInit(EVP_MD_CTX *, const EVP_MD *); %rename(digest_sign_init) EVP_DigestSignInit; extern int EVP_DigestSignInit(EVP_MD_CTX *, EVP_PKEY_CTX **, const EVP_MD *, ENGINE *, EVP_PKEY *); %rename(digest_verify_init) EVP_DigestVerifyInit; extern int EVP_DigestVerifyInit(EVP_MD_CTX *, EVP_PKEY_CTX **, const EVP_MD *, ENGINE *, EVP_PKEY *); %rename(pkey_size) EVP_PKEY_size; extern int EVP_PKEY_size(EVP_PKEY *); %warnfilter(454) _evp_err; %inline %{ #define PKCS5_SALT_LEN 8 static PyObject *_evp_err; void evp_init(PyObject *evp_err) { Py_INCREF(evp_err); _evp_err = evp_err; } %} %typemap(out) RSA * { PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if ($1 != NULL) $result = SWIG_NewPointerObj($1, $1_descriptor, 0); else { $result = NULL; } } %inline %{ RSA *pkey_get1_rsa(EVP_PKEY *pkey) { RSA *ret = NULL; if ((ret = EVP_PKEY_get1_RSA(pkey)) == NULL) { /* _evp_err now inherits from PyExc_ValueError, so we should * keep API intact. */ PyErr_Format(_evp_err, "Invalid key in function %s.", __FUNCTION__); } return ret; } %} %typemap(out) RSA * ; %typemap(out) EC_KEY * { PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if ($1 != NULL) $result = SWIG_NewPointerObj($1, $1_descriptor, 0); else { $result = NULL; } } %inline %{ EC_KEY *pkey_get1_ec(EVP_PKEY *pkey) { EC_KEY *ret = NULL; if ((ret = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { /* _evp_err now inherits from PyExc_ValueError, so we should * keep API intact. */ PyErr_Format(_evp_err, "Invalid key in function %s.", __FUNCTION__); } return ret; } %} %typemap(out) EC_KEY * ; %inline %{ PyObject *pkcs5_pbkdf2_hmac_sha1(PyObject *pass, PyObject *salt, int iter, int keylen) { unsigned char *key; const void *saltbuf; const void *passbuf; PyObject *ret; int passlen = 0, saltlen = 0; if (m2_PyObject_AsReadBufferInt(pass, &passbuf, &passlen) == -1) return NULL; if (m2_PyObject_AsReadBufferInt(salt, &saltbuf, &saltlen) == -1) return NULL; key = PyMem_Malloc(keylen); if (key == NULL) return PyErr_NoMemory(); PKCS5_PBKDF2_HMAC_SHA1((const char *)passbuf, passlen, (const unsigned char *)saltbuf, saltlen, iter, keylen, key); ret = PyBytes_FromStringAndSize((char*)key, keylen); OPENSSL_cleanse(key, keylen); PyMem_Free(key); return ret; } EVP_MD_CTX *md_ctx_new(void) { EVP_MD_CTX *ctx; if (!(ctx = EVP_MD_CTX_create())) { PyErr_SetString(PyExc_MemoryError, "md_ctx_new"); return NULL; } return ctx; } void md_ctx_free(EVP_MD_CTX *ctx) { EVP_MD_CTX_destroy(ctx); } int digest_update(EVP_MD_CTX *ctx, PyObject *blob) { const void *buf = NULL; Py_ssize_t len; if (m2_PyObject_AsReadBuffer(blob, &buf, &len) == -1) return -1; return EVP_DigestUpdate(ctx, buf, (size_t)len); } PyObject *digest_final(EVP_MD_CTX *ctx) { void *blob; int blen; PyObject *ret; if (!(blob = PyMem_Malloc(EVP_MD_CTX_size(ctx)))) { PyErr_SetString(PyExc_MemoryError, "digest_final"); return NULL; } if (!EVP_DigestFinal(ctx, blob, (unsigned int *)&blen)) { PyMem_Free(blob); m2_PyErr_Msg(_evp_err); return NULL; } ret = PyBytes_FromStringAndSize(blob, blen); PyMem_Free(blob); return ret; } HMAC_CTX *hmac_ctx_new(void) { HMAC_CTX *ctx; if (!(ctx = HMAC_CTX_new())) { PyErr_SetString(PyExc_MemoryError, "hmac_ctx_new"); return NULL; } return ctx; } void hmac_ctx_free(HMAC_CTX *ctx) { HMAC_CTX_free(ctx); } PyObject *hmac_init(HMAC_CTX *ctx, PyObject *key, const EVP_MD *md) { const void *kbuf; int klen = 0; if (m2_PyObject_AsReadBufferInt(key, &kbuf, &klen) == -1) return NULL; if (!HMAC_Init_ex(ctx, kbuf, klen, md, NULL)) { PyErr_SetString(_evp_err, "HMAC_Init failed"); return NULL; } Py_RETURN_NONE; } PyObject *hmac_update(HMAC_CTX *ctx, PyObject *blob) { const void *buf = NULL; Py_ssize_t len; if (m2_PyObject_AsReadBuffer(blob, &buf, &len) == -1) return NULL; if (!HMAC_Update(ctx, (const unsigned char *)buf, (size_t)len)) { PyErr_SetString(_evp_err, "HMAC_Update failed"); return NULL; } Py_RETURN_NONE; } PyObject *hmac_final(HMAC_CTX *ctx) { void *blob; int blen; PyObject *ret; if (!(blob = PyMem_Malloc(HMAC_size(ctx)))) { PyErr_SetString(PyExc_MemoryError, "hmac_final"); return NULL; } if (!HMAC_Final(ctx, blob, (unsigned int *)&blen)) { PyErr_SetString(_evp_err, "HMAC_Final failed"); return NULL; } ret = PyBytes_FromStringAndSize(blob, blen); PyMem_Free(blob); return ret; } PyObject *hmac(PyObject *key, PyObject *data, const EVP_MD *md) { const void *kbuf, *dbuf; void *blob; int klen = 0; unsigned int blen; Py_ssize_t dlen; PyObject *ret; if ((m2_PyObject_AsReadBufferInt(key, &kbuf, &klen) == -1) || (m2_PyObject_AsReadBuffer(data, &dbuf, &dlen) == -1)) return NULL; if (!(blob = PyMem_Malloc(EVP_MAX_MD_SIZE))) { PyErr_SetString(PyExc_MemoryError, "hmac"); return NULL; } HMAC(md, kbuf, klen, (const unsigned char *)dbuf, (size_t)dlen, (unsigned char *)blob, &blen); blob = PyMem_Realloc(blob, blen); ret = PyBytes_FromStringAndSize(blob, blen); PyMem_Free(blob); return ret; } EVP_CIPHER_CTX *cipher_ctx_new(void) { EVP_CIPHER_CTX *ctx; if (!(ctx = EVP_CIPHER_CTX_new())) { PyErr_SetString(PyExc_MemoryError, "cipher_ctx_new"); return NULL; } EVP_CIPHER_CTX_reset(ctx); return ctx; } void cipher_ctx_free(EVP_CIPHER_CTX *ctx) { EVP_CIPHER_CTX_free(ctx); } PyObject *bytes_to_key(const EVP_CIPHER *cipher, EVP_MD *md, PyObject *data, PyObject *salt, PyObject *iv, /* Not used */ int iter) { unsigned char key[EVP_MAX_KEY_LENGTH]; const void *dbuf, *sbuf; int dlen = 0, klen; Py_ssize_t slen; PyObject *ret; if ((m2_PyObject_AsReadBufferInt(data, &dbuf, &dlen) == -1) || (m2_PyObject_AsReadBuffer(salt, &sbuf, &slen) == -1)) return NULL; assert((slen == 8) || (slen == 0)); klen = EVP_BytesToKey(cipher, md, (unsigned char *)sbuf, (unsigned char *)dbuf, dlen, iter, key, NULL); /* Since we are not returning IV no need to derive it */ ret = PyBytes_FromStringAndSize((char*)key, klen); return ret; } PyObject *cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, PyObject *key, PyObject *iv, int mode) { const void *kbuf, *ibuf; Py_ssize_t klen, ilen; if (key == Py_None) kbuf = NULL; else if (m2_PyObject_AsReadBuffer(key, &kbuf, &klen) == -1) return NULL; if (iv == Py_None) ibuf = NULL; else if (m2_PyObject_AsReadBuffer(iv, &ibuf, &ilen) == -1) return NULL; if (!EVP_CipherInit(ctx, cipher, (unsigned char *)kbuf, (unsigned char *)ibuf, mode)) { m2_PyErr_Msg(_evp_err); return NULL; } Py_RETURN_NONE; } PyObject *cipher_update(EVP_CIPHER_CTX *ctx, PyObject *blob) { const void *buf; int len = 0, olen; void *obuf; PyObject *ret; if (m2_PyObject_AsReadBufferInt(blob, &buf, &len) == -1) return NULL; if (!(obuf = PyMem_Malloc(len + EVP_CIPHER_CTX_block_size(ctx) - 1))) { PyErr_SetString(PyExc_MemoryError, "cipher_update"); return NULL; } if (!EVP_CipherUpdate(ctx, obuf, &olen, (unsigned char *)buf, len)) { PyMem_Free(obuf); m2_PyErr_Msg(_evp_err); return NULL; } ret = PyBytes_FromStringAndSize(obuf, olen); PyMem_Free(obuf); return ret; } PyObject *cipher_final(EVP_CIPHER_CTX *ctx) { void *obuf; int olen; PyObject *ret; if (!(obuf = PyMem_Malloc(EVP_CIPHER_CTX_block_size(ctx)))) { PyErr_SetString(PyExc_MemoryError, "cipher_final"); return NULL; } if (!EVP_CipherFinal(ctx, (unsigned char *)obuf, &olen)) { PyMem_Free(obuf); m2_PyErr_Msg(_evp_err); return NULL; } ret = PyBytes_FromStringAndSize(obuf, olen); PyMem_Free(obuf); return ret; } PyObject *sign_update(EVP_MD_CTX *ctx, PyObject *blob) { const void *buf; int len; if (m2_PyObject_AsReadBufferInt(blob, &buf, &len) == -1) return NULL; if (!EVP_SignUpdate(ctx, buf, (Py_ssize_t)len)) { m2_PyErr_Msg(_evp_err); return NULL; } Py_RETURN_NONE; } PyObject *sign_final(EVP_MD_CTX *ctx, EVP_PKEY *pkey) { PyObject *ret; unsigned char *sigbuf; unsigned int siglen = EVP_PKEY_size(pkey); sigbuf = (unsigned char*)OPENSSL_malloc(siglen); if (!sigbuf) { PyErr_SetString(PyExc_MemoryError, "sign_final"); return NULL; } if (!EVP_SignFinal(ctx, sigbuf, &siglen, pkey)) { m2_PyErr_Msg(_evp_err); OPENSSL_cleanse(sigbuf, siglen); OPENSSL_free(sigbuf); return NULL; } ret = PyBytes_FromStringAndSize((char*)sigbuf, siglen); OPENSSL_cleanse(sigbuf, siglen); OPENSSL_free(sigbuf); return ret; } int verify_update(EVP_MD_CTX *ctx, PyObject *blob) { const void *buf; int len; if (m2_PyObject_AsReadBufferInt(blob, &buf, &len) == -1) return -1; return EVP_VerifyUpdate(ctx, buf, (Py_ssize_t)len); } int verify_final(EVP_MD_CTX *ctx, PyObject *blob, EVP_PKEY *pkey) { const void *kbuf = NULL; int len = 0; if (m2_PyObject_AsReadBufferInt(blob, &kbuf, &len) == -1) return -1; return EVP_VerifyFinal(ctx, (const unsigned char *)kbuf, len, pkey); } int digest_sign_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey) { return EVP_DigestSignInit(ctx, NULL, NULL, NULL, pkey); } PyObject *digest_sign_update(EVP_MD_CTX *ctx, PyObject *blob) { const void *buf; int len = 0; if (m2_PyObject_AsReadBufferInt(blob, (const void **)&buf, &len) == -1) return NULL; if (!EVP_DigestSignUpdate(ctx, buf, len)) { m2_PyErr_Msg(_evp_err); return NULL; } Py_RETURN_NONE; } PyObject *digest_sign_final(EVP_MD_CTX *ctx) { PyObject *ret; unsigned char *sigbuf; size_t siglen; if (!EVP_DigestSignFinal(ctx, NULL, &siglen)) { m2_PyErr_Msg(_evp_err); return NULL; } sigbuf = (unsigned char*)OPENSSL_malloc(siglen); if (!sigbuf) { PyErr_SetString(PyExc_MemoryError, "digest_sign_final"); return NULL; } if (!EVP_DigestSignFinal(ctx, sigbuf, &siglen)) { m2_PyErr_Msg(_evp_err); OPENSSL_cleanse(sigbuf, siglen); OPENSSL_free(sigbuf); return NULL; } ret = PyBytes_FromStringAndSize((char*)sigbuf, siglen); OPENSSL_cleanse(sigbuf, siglen); OPENSSL_free(sigbuf); return ret; } #if OPENSSL_VERSION_NUMBER >= 0x10101000L PyObject *digest_sign(EVP_MD_CTX *ctx, PyObject *msg) { PyObject *ret; const void *msgbuf; unsigned char *sigbuf; int msglen = 0; size_t siglen = 0; if (m2_PyObject_AsReadBufferInt(msg, (const void **)&msgbuf, &msglen) == -1) return NULL; if (!EVP_DigestSign(ctx, NULL, &siglen, msgbuf, msglen)) { m2_PyErr_Msg(_evp_err); return NULL; } sigbuf = (unsigned char*)OPENSSL_malloc(siglen); if (!sigbuf) { PyErr_SetString(PyExc_MemoryError, "digest_sign"); return NULL; } if (!EVP_DigestSign(ctx, sigbuf, &siglen, msgbuf, msglen)) { m2_PyErr_Msg(_evp_err); OPENSSL_cleanse(sigbuf, siglen); OPENSSL_free(sigbuf); return NULL; } ret = PyBytes_FromStringAndSize((char*)sigbuf, siglen); OPENSSL_cleanse(sigbuf, siglen); OPENSSL_free(sigbuf); return ret; } #endif int digest_verify_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey) { return EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, pkey); } int digest_verify_update(EVP_MD_CTX *ctx, PyObject *blob) { const void *buf = NULL; int len = 0; if (m2_PyObject_AsReadBufferInt(blob, (const void **)&buf, &len) == -1) return -1; return EVP_DigestVerifyUpdate(ctx, buf, len); } int digest_verify_final(EVP_MD_CTX *ctx, PyObject *blob) { unsigned char *sigbuf = NULL; int len = 0; if (m2_PyObject_AsReadBufferInt(blob, (const void **)&sigbuf, &len) == -1) return -1; return EVP_DigestVerifyFinal(ctx, sigbuf, len); } #if OPENSSL_VERSION_NUMBER >= 0x10101000L int digest_verify(EVP_MD_CTX *ctx, PyObject *sig, PyObject *msg) { unsigned char *sigbuf; unsigned char *msgbuf; int siglen = 0; int msglen = 0; if (m2_PyObject_AsReadBufferInt(sig, (const void **)&sigbuf, &siglen) == -1) return -1; if (m2_PyObject_AsReadBufferInt(msg, (const void **)&msgbuf, &msglen) == -1) return -1; return EVP_DigestVerify(ctx, sigbuf, siglen, msgbuf, msglen); } #endif %} %typemap(out) EVP_MD * { PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if ($1 != NULL) $result = SWIG_NewPointerObj($1, $1_descriptor, 0); else { $result = NULL; } } %inline %{ const EVP_MD *get_digestbyname(const char* name) { const EVP_MD *ret = NULL; if ((ret = EVP_get_digestbyname(name)) == NULL) { m2_PyErr_Msg(_evp_err); } return ret; } %} %typemap(out) EVP_MD *; %inline %{ int pkey_write_pem_no_cipher(EVP_PKEY *pkey, BIO *f, PyObject *pyfunc) { int ret; Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS ret = PEM_write_bio_PKCS8PrivateKey(f, pkey, NULL, NULL, 0, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); return ret; } %} %inline %{ int pkey_write_pem(EVP_PKEY *pkey, BIO *f, EVP_CIPHER *cipher, PyObject *pyfunc) { int ret; Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS ret = PEM_write_bio_PKCS8PrivateKey(f, pkey, cipher, NULL, 0, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); return ret; } %} %typemap(out) EVP_PKEY * { PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if ($1 != NULL) $result = SWIG_NewPointerObj($1, $1_descriptor, 0); else { $result = NULL; } } %inline %{ EVP_PKEY *pkey_new(void) { EVP_PKEY *ret; if ((ret = EVP_PKEY_new()) == NULL) { PyErr_Format(PyExc_MemoryError, "Insufficient memory for new key in function %s.", __FUNCTION__); } return ret; } EVP_PKEY *pkey_read_pem(BIO *f, PyObject *pyfunc) { EVP_PKEY *pk; Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS pk = PEM_read_bio_PrivateKey(f, NULL, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); if (pk == NULL) { PyErr_Format(_evp_err, "Unable to read private key in function %s.", __FUNCTION__); } return pk; } EVP_PKEY *pkey_read_pem_pubkey(BIO *f, PyObject *pyfunc) { EVP_PKEY *pk; Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS pk = PEM_read_bio_PUBKEY(f, NULL, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); if (pk == NULL) { PyErr_Format(_evp_err, "Unable to read public key in function %s.", __FUNCTION__); } return pk; } %} %typemap(out) EVP_PKEY * ; %inline %{ int pkey_assign_rsa(EVP_PKEY *pkey, RSA *rsa) { return EVP_PKEY_assign_RSA(pkey, rsa); } PyObject *pkey_as_der(EVP_PKEY *pkey) { unsigned char * pp = NULL; int len; PyObject * der; len = i2d_PUBKEY(pkey, &pp); if (len < 0){ PyErr_SetString(_evp_err, "EVP_PKEY as DER failed"); return NULL; } der = PyBytes_FromStringAndSize((char*)pp, len); OPENSSL_free(pp); return der; } PyObject *pkey_get_modulus(EVP_PKEY *pkey) { RSA *rsa; DSA *dsa; BIO *bio; BUF_MEM *bptr; PyObject *ret; const BIGNUM* bn; switch (EVP_PKEY_base_id(pkey)) { case EVP_PKEY_RSA: rsa = EVP_PKEY_get1_RSA(pkey); bio = BIO_new(BIO_s_mem()); if (!bio) { RSA_free(rsa); PyErr_SetString(PyExc_MemoryError, "pkey_get_modulus"); return NULL; } RSA_get0_key(rsa, &bn, NULL, NULL); if (!BN_print(bio, bn)) { m2_PyErr_Msg(PyExc_RuntimeError); BIO_free(bio); RSA_free(rsa); return NULL; } BIO_get_mem_ptr(bio, &bptr); ret = PyBytes_FromStringAndSize(bptr->data, bptr->length); (void)BIO_set_close(bio, BIO_CLOSE); BIO_free(bio); RSA_free(rsa); return ret; break; case EVP_PKEY_DSA: dsa = EVP_PKEY_get1_DSA(pkey); bio = BIO_new(BIO_s_mem()); if (!bio) { DSA_free(dsa); PyErr_SetString(PyExc_MemoryError, "pkey_get_modulus"); return NULL; } DSA_get0_key(dsa, &bn, NULL); if (!BN_print(bio, bn)) { m2_PyErr_Msg(PyExc_RuntimeError); BIO_free(bio); DSA_free(dsa); return NULL; } BIO_get_mem_ptr(bio, &bptr); ret = PyBytes_FromStringAndSize(bptr->data, bptr->length); (void)BIO_set_close(bio, BIO_CLOSE); BIO_free(bio); DSA_free(dsa); return ret; break; default: PyErr_SetString(_evp_err, "unsupported key type"); return NULL; } } %} m2crypto-0.42.0/src/SWIG/_lib.h000066400000000000000000000020701465575656700160230ustar00rootroot00000000000000/* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. */ /* $Id$ */ #include typedef struct _blob { unsigned char *data; int len; } Blob; Blob *blob_new(int len, const char *errmsg); Blob *blob_copy(Blob *from, const char *errmsg); void blob_free(Blob *blob); static int m2_PyObject_AsReadBuffer(PyObject *obj, const void **buffer, Py_ssize_t *buffer_len); static int m2_PyObject_AsReadBufferInt(PyObject *obj, const void **buffer, int *buffer_len); static int m2_PyString_AsStringAndSizeInt(PyObject *obj, char **s, int *len); static BIGNUM* m2_PyObject_AsBIGNUM(PyObject* value, PyObject* _py_exc) ; /* Always use these two together, to correctly handle non-memoryview objects. */ static int m2_PyObject_GetBufferInt(PyObject *obj, Py_buffer *view, int flags); static void m2_PyBuffer_Release(PyObject *obj, Py_buffer *view); int bn_gencb_callback(int p, int n, BN_GENCB *gencb); int passphrase_callback(char *buf, int num, int v, void *userdata); void lib_init(void); m2crypto-0.42.0/src/SWIG/_lib.i000066400000000000000000000500131465575656700160240ustar00rootroot00000000000000/* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. */ /* $Id$ */ %{ #include #include #include #include #include #include #include #include #include %} /* OpenSSL 1.1 compatibility shim */ %include _lib11_compat.i /* Python 3 compatibility shim */ %include _py3k_compat.i %{ /* OpenSSL 1.0.2 copmatbility shim */ #if OPENSSL_VERSION_NUMBER < 0x10002000L typedef void (*OPENSSL_sk_freefunc)(void *); typedef void *(*OPENSSL_sk_copyfunc)(const void *); typedef struct stack_st OPENSSL_STACK; # define MIN_NODES 4 # define sk_deep_copy OPENSSL_sk_deep_copy void OPENSSL_sk_free(OPENSSL_STACK *st) { if (st == NULL) return; OPENSSL_free(st->data); OPENSSL_free(st); } OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *sk, OPENSSL_sk_copyfunc copy_func, OPENSSL_sk_freefunc free_func) { OPENSSL_STACK *ret; int i; if (sk->num < 0) return NULL; if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL) return NULL; /* direct structure assignment */ *ret = *sk; ret->num_alloc = sk->num > MIN_NODES ? (size_t)sk->num : MIN_NODES; ret->data = OPENSSL_zalloc(sizeof(*ret->data) * ret->num_alloc); if (ret->data == NULL) { OPENSSL_free(ret); return NULL; } for (i = 0; i < ret->num; ++i) { if (sk->data[i] == NULL) continue; if ((ret->data[i] = copy_func(sk->data[i])) == NULL) { while (--i >= 0) if (ret->data[i] != NULL) free_func((void *)ret->data[i]); OPENSSL_sk_free(ret); return NULL; } } return ret; } #endif /* OpenSSL 1.0.2 copmatbility shim */ /* Blob interface. Deprecated. */ Blob *blob_new(int len, const char *errmsg) { Blob *blob; if (!(blob=(Blob *)PyMem_Malloc(sizeof(Blob)))){ PyErr_SetString(PyExc_MemoryError, errmsg); return NULL; } if (!(blob->data=(unsigned char *)PyMem_Malloc(len))) { PyMem_Free(blob); PyErr_SetString(PyExc_MemoryError, errmsg); return NULL; } blob->len=len; return blob; } Blob *blob_copy(Blob *from, const char *errmsg) { Blob *blob=blob_new(from->len, errmsg); if (!blob) { PyErr_SetString(PyExc_MemoryError, errmsg); return NULL; } memcpy(blob->data, from->data, from->len); return blob; } void blob_free(Blob *blob) { PyMem_Free(blob->data); PyMem_Free(blob); } /* Python helpers. */ %} %ignore PyObject_CheckBuffer; %ignore PyObject_GetBuffer; %ignore PyBuffer_Release; %ignore m2_PyObject_AsReadBuffer; %ignore m2_PyObject_AsReadBufferInt; %ignore m2_PyObject_GetBufferInt; %ignore m2_PyBuffer_Release; %ignore m2_PyString_AsStringAndSizeInt; %newobject mpi_to_bn; %newobject bin_to_bn; %nodefaultctor bignum_st; struct bignum_st {}; typedef struct bignum_st BIGNUM; %extend bignum_st { ~bignum_st() { BN_free($self); } }; %{ static int m2_PyObject_AsReadBuffer(PyObject * obj, const void **buffer, Py_ssize_t * buffer_len) { Py_ssize_t len = 0; Py_buffer view; if (PyObject_CheckBuffer(obj)) { if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) == 0) { *buffer = view.buf; len = view.len; } } else { PyErr_SetString(PyExc_TypeError, "expected a readable buffer object"); return -1; } if (len > INT_MAX) { m2_PyBuffer_Release(obj, &view); PyErr_SetString(PyExc_ValueError, "object too large"); return -1; } *buffer_len = len; m2_PyBuffer_Release(obj, &view); return 0; } static int m2_PyObject_AsReadBufferInt(PyObject * obj, const void **buffer, int *buffer_len) { int ret = 0; Py_ssize_t len = 0; ret = m2_PyObject_AsReadBuffer(obj, buffer, &len); *buffer_len = len; return ret; } static int m2_PyObject_GetBufferInt(PyObject *obj, Py_buffer *view, int flags) { int ret; if (PyObject_CheckBuffer(obj)) ret = PyObject_GetBuffer(obj, view, flags); else { PyErr_SetString(PyExc_TypeError, "expected a readable buffer object"); return -1; } if (ret) return ret; if (view->len > INT_MAX) { PyErr_SetString(PyExc_ValueError, "object too large"); m2_PyBuffer_Release(obj, view); return -1; } return 0; } static BIGNUM* m2_PyObject_AsBIGNUM(PyObject* value, PyObject* _py_exc) { BIGNUM* bn; const void* vbuf; int vlen = 0; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) { PyErr_SetString(_py_exc, ERR_reason_error_string(ERR_get_error())); return NULL; } return bn; } static void m2_PyBuffer_Release(PyObject *obj, Py_buffer *view) { if (PyObject_CheckBuffer(obj)) PyBuffer_Release(view); /* else do nothing, view->buf comes from PyObject_AsReadBuffer */ } static int m2_PyString_AsStringAndSizeInt(PyObject *obj, char **s, int *len) { int ret; Py_ssize_t len2; ret = PyBytes_AsStringAndSize(obj, s, &len2); if (ret) return ret; if (len2 > INT_MAX) { PyErr_SetString(PyExc_ValueError, "string too large"); return -1; } *len = len2; return 0; } /* Works as PyFile_Name, but always returns a new object. */ PyObject *m2_PyFile_Name(PyObject *pyfile) { PyObject *out = NULL; #if PY_MAJOR_VERSION >= 3 out = PyObject_GetAttrString(pyfile, "name"); #else out = PyFile_Name(pyfile); Py_XINCREF(out); #endif return out; } /* Yes, __FUNCTION__ is a non-standard symbol, but it is supported by * both gcc and MSVC. */ #define m2_PyErr_Msg(type) m2_PyErr_Msg_Caller(type, (const char*) __FUNCTION__) static void m2_PyErr_Msg_Caller(PyObject *err_type, const char* caller) { const char *err_reason; const char *data; int flags; /* This max size of a (longer than ours) OpenSSL error string is hardcoded * in OpenSSL's crypto/err/err_prn.c:ERR_print_errors_cb() */ char err_msg[4096]; unsigned long err_code = ERR_get_error_line_data(NULL, NULL, &data, &flags); if (err_code != 0) { err_reason = ERR_reason_error_string(err_code); if (data && (flags & ERR_TXT_STRING)) snprintf(err_msg, sizeof(err_msg), "%s (%s)", err_reason, data); else snprintf(err_msg, sizeof(err_msg), "%s", err_reason); PyErr_SetString(err_type, err_msg); } else { PyErr_Format(err_type, "Unknown error in function %s.", caller); } } /* C callbacks invoked by OpenSSL; these in turn call back into Python. */ int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) { PyObject *argv, *ret; PyObject *_x509_store_ctx_swigptr=0, *_x509_store_ctx_obj=0, *_x509_store_ctx_inst=0, *_klass=0; PyObject *_x509=0, *_ssl_ctx=0; SSL *ssl; SSL_CTX *ssl_ctx; X509 *x509; int errnum, errdepth; int cret; int new_style_callback = 0, warning_raised_exception=0; PyGILState_STATE gilstate; PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ ssl = (SSL *)X509_STORE_CTX_get_app_data(ctx); gilstate = PyGILState_Ensure(); if (PyMethod_Check(ssl_verify_cb_func)) { PyObject *func; PyCodeObject *code; func = PyMethod_Function(ssl_verify_cb_func); code = (PyCodeObject *) PyFunction_GetCode(func); if (code && code->co_argcount == 3) { /* XXX Python internals */ new_style_callback = 1; } } else if (PyFunction_Check(ssl_verify_cb_func)) { PyCodeObject *code = (PyCodeObject *) PyFunction_GetCode(ssl_verify_cb_func); if (code && code->co_argcount == 2) { /* XXX Python internals */ new_style_callback = 1; } } else { /* XXX There are lots of other callable types, but we will assume * XXX that any other type of callable uses the new style callback, * XXX although this is not entirely safe assumption. */ new_style_callback = 1; } if (new_style_callback) { PyObject *x509mod; x509mod = PyDict_GetItemString(PyImport_GetModuleDict(), "M2Crypto.X509"); _klass = PyObject_GetAttrString(x509mod, "X509_Store_Context"); _x509_store_ctx_swigptr = SWIG_NewPointerObj((void *)ctx, SWIGTYPE_p_X509_STORE_CTX, 0); _x509_store_ctx_obj = Py_BuildValue("(Oi)", _x509_store_ctx_swigptr, 0); _x509_store_ctx_inst = PyObject_CallObject(_klass, _x509_store_ctx_obj); argv = Py_BuildValue("(iO)", ok, _x509_store_ctx_inst); } else { if (PyErr_Warn(PyExc_DeprecationWarning, "Old style callback, use cb_func(ok, store) instead")) { warning_raised_exception = 1; } x509 = X509_STORE_CTX_get_current_cert(ctx); errnum = X509_STORE_CTX_get_error(ctx); errdepth = X509_STORE_CTX_get_error_depth(ctx); ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); ssl_ctx = SSL_get_SSL_CTX(ssl); _x509 = SWIG_NewPointerObj((void *)x509, SWIGTYPE_p_X509, 0); _ssl_ctx = SWIG_NewPointerObj((void *)ssl_ctx, SWIGTYPE_p_SSL_CTX, 0); argv = Py_BuildValue("(OOiii)", _ssl_ctx, _x509, errnum, errdepth, ok); } if (!warning_raised_exception) { ret = PyObject_CallObject(ssl_verify_cb_func, argv); } else { ret = 0; } if (!ret) { /* Got an exception in PyObject_CallObject(), let's fail verification * to be safe. */ cret = 0; } else { /* FIXME This is possibly problematic if ret > MAXINT */ cret = (int)PyLong_AsLong(ret); } Py_XDECREF(ret); Py_XDECREF(argv); if (new_style_callback) { Py_XDECREF(_x509_store_ctx_inst); Py_XDECREF(_x509_store_ctx_obj); Py_XDECREF(_x509_store_ctx_swigptr); Py_XDECREF(_klass); } else { Py_XDECREF(_x509); Py_XDECREF(_ssl_ctx); } PyGILState_Release(gilstate); return cret; } int x509_store_verify_callback(int ok, X509_STORE_CTX *ctx) { PyGILState_STATE gilstate; PyObject *argv, *ret; PyObject *_x509_store_ctx_swigptr=0, *_x509_store_ctx_obj=0, *_x509_store_ctx_inst=0, *_klass=0; int cret; PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ PyObject *x509mod; gilstate = PyGILState_Ensure(); /* Below, handle only what is called 'new style callback' in ssl_verify_callback(). TODO: does 'old style callback' exist any more? */ x509mod = PyDict_GetItemString(PyImport_GetModuleDict(), "M2Crypto.X509"); _klass = PyObject_GetAttrString(x509mod, "X509_Store_Context"); _x509_store_ctx_swigptr = SWIG_NewPointerObj((void *)ctx, SWIGTYPE_p_X509_STORE_CTX, 0); _x509_store_ctx_obj = Py_BuildValue("(Oi)", _x509_store_ctx_swigptr, 0); _x509_store_ctx_inst = PyObject_CallObject(_klass, _x509_store_ctx_obj); argv = Py_BuildValue("(iO)", ok, _x509_store_ctx_inst); ret = PyObject_CallObject(x509_store_verify_cb_func, argv); if (!ret) { /* Got an exception in PyObject_CallObject(), let's fail verification * to be safe. */ cret = 0; } else { cret = (int)PyInt_AsLong(ret); } Py_XDECREF(ret); Py_XDECREF(argv); Py_XDECREF(_x509_store_ctx_inst); Py_XDECREF(_x509_store_ctx_obj); Py_XDECREF(_x509_store_ctx_swigptr); Py_XDECREF(_klass); PyGILState_Release(gilstate); return cret; } void ssl_info_callback(const SSL *s, int where, int ret) { PyObject *argv, *retval, *_SSL; PyGILState_STATE gilstate; PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ gilstate = PyGILState_Ensure(); _SSL = SWIG_NewPointerObj((void *)s, SWIGTYPE_p_SSL, 0); argv = Py_BuildValue("(iiO)", where, ret, _SSL); retval = PyObject_CallObject(ssl_info_cb_func, argv); Py_XDECREF(retval); Py_XDECREF(argv); Py_XDECREF(_SSL); PyGILState_Release(gilstate); } DH *ssl_set_tmp_dh_callback(SSL *ssl, int is_export, int keylength) { PyObject *argv, *ret, *_ssl; DH *dh; PyGILState_STATE gilstate; PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ gilstate = PyGILState_Ensure(); _ssl = SWIG_NewPointerObj((void *)ssl, SWIGTYPE_p_SSL, 0); argv = Py_BuildValue("(Oii)", _ssl, is_export, keylength); ret = PyObject_CallObject(ssl_set_tmp_dh_cb_func, argv); if ((SWIG_ConvertPtr(ret, (void **)&dh, SWIGTYPE_p_DH, SWIG_POINTER_EXCEPTION | 0)) == -1) dh = NULL; Py_XDECREF(ret); Py_XDECREF(argv); Py_XDECREF(_ssl); PyGILState_Release(gilstate); return dh; } RSA *ssl_set_tmp_rsa_callback(SSL *ssl, int is_export, int keylength) { PyObject *argv, *ret, *_ssl; RSA *rsa; PyGILState_STATE gilstate; PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ gilstate = PyGILState_Ensure(); _ssl = SWIG_NewPointerObj((void *)ssl, SWIGTYPE_p_SSL, 0); argv = Py_BuildValue("(Oii)", _ssl, is_export, keylength); ret = PyObject_CallObject(ssl_set_tmp_rsa_cb_func, argv); if ((SWIG_ConvertPtr(ret, (void **)&rsa, SWIGTYPE_p_RSA, SWIG_POINTER_EXCEPTION | 0)) == -1) rsa = NULL; Py_XDECREF(ret); Py_XDECREF(argv); Py_XDECREF(_ssl); PyGILState_Release(gilstate); return rsa; } /* Universal callback for dh_generate_parameters, * dsa_generate_parametersm, and rsa_generate_key */ int bn_gencb_callback(int p, int n, BN_GENCB *gencb) { PyObject *argv, *ret, *cbfunc; cbfunc = (PyObject *)BN_GENCB_get_arg(gencb); argv = Py_BuildValue("(ii)", p, n); ret = PyObject_CallObject(cbfunc, argv); PyErr_Clear(); Py_DECREF(argv); Py_XDECREF(ret); return 1; } int passphrase_callback(char *buf, int num, int v, void *arg) { int i; Py_ssize_t len; char *str; PyObject *argv, *ret, *cbfunc; PyGILState_STATE gilstate; gilstate = PyGILState_Ensure(); cbfunc = (PyObject *)arg; argv = Py_BuildValue("(i)", v); /* PyObject_CallObject sets exception, if needed. */ ret = PyObject_CallObject(cbfunc, argv); Py_DECREF(argv); if (ret == NULL) { PyGILState_Release(gilstate); return -1; } if (!PyBytes_Check(ret)) { PyErr_SetString(PyExc_RuntimeError, "Result of callback is not bytes()."); Py_DECREF(ret); PyGILState_Release(gilstate); return -1; } if ((len = PyBytes_Size(ret)) > num) len = num; str = PyBytes_AsString(ret); for (i = 0; i < len; i++) buf[i] = str[i]; Py_DECREF(ret); PyGILState_Release(gilstate); return len; } %} %inline %{ void lib_init() { #if OPENSSL_VERSION_NUMBER < 0x10100000L SSLeay_add_all_algorithms(); ERR_load_ERR_strings(); #endif } /* Bignum routines that aren't not numerous enough to warrant a separate file. */ PyObject *bn_to_mpi(const BIGNUM *bn) { int len = 0; unsigned char *mpi; PyObject *pyo; len = BN_bn2mpi(bn, NULL); if (!(mpi=(unsigned char *)PyMem_Malloc(len))) { m2_PyErr_Msg(PyExc_MemoryError); return NULL; } len=BN_bn2mpi(bn, mpi); pyo=PyBytes_FromStringAndSize((const char *)mpi, len); PyMem_Free(mpi); return pyo; } const BIGNUM *mpi_to_bn(PyObject *value) { const void *vbuf = NULL; int vlen = 0; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; return BN_mpi2bn(vbuf, vlen, NULL); } PyObject *bn_to_bin(BIGNUM *bn) { int len = 0; unsigned char *bin; PyObject *pyo; len = BN_num_bytes(bn); if (!(bin=(unsigned char *)PyMem_Malloc(len))) { PyErr_SetString(PyExc_MemoryError, "bn_to_bin"); return NULL; } BN_bn2bin(bn, bin); pyo=PyBytes_FromStringAndSize((const char *)bin, len); PyMem_Free(bin); return pyo; } const BIGNUM *bin_to_bn(PyObject *value) { const void *vbuf = NULL; int vlen = 0; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; return BN_bin2bn(vbuf, vlen, NULL); } PyObject *bn_to_hex(BIGNUM *bn) { char *hex; PyObject *pyo; Py_ssize_t len = 0; hex = BN_bn2hex(bn); if (!hex) { m2_PyErr_Msg(PyExc_RuntimeError); OPENSSL_free(hex); return NULL; } len = strlen(hex); pyo=PyBytes_FromStringAndSize(hex, len); OPENSSL_free(hex); return pyo; } BIGNUM *hex_to_bn(PyObject *value) { const void *vbuf = NULL; Py_ssize_t vlen = 0; BIGNUM *bn; Py_buffer view; if (PyObject_CheckBuffer(value)) { if (PyObject_GetBuffer(value, &view, PyBUF_SIMPLE) == 0) { vbuf = view.buf; vlen = view.len; } } else { if (m2_PyObject_AsReadBuffer(value, &vbuf, &vlen) == -1) return NULL; } if ((bn=BN_new())==NULL) { m2_PyBuffer_Release(value, &view); PyErr_SetString(PyExc_MemoryError, "hex_to_bn"); return NULL; } if (BN_hex2bn(&bn, (const char *)vbuf) <= 0) { m2_PyBuffer_Release(value, &view); m2_PyErr_Msg(PyExc_RuntimeError); BN_free(bn); return NULL; } m2_PyBuffer_Release(value, &view); return bn; } BIGNUM *dec_to_bn(PyObject *value) { const void *vbuf = NULL; Py_ssize_t vlen = 0; BIGNUM *bn; Py_buffer view; if (PyObject_CheckBuffer(value)) { if (PyObject_GetBuffer(value, &view, PyBUF_SIMPLE) == 0) { vbuf = view.buf; vlen = view.len; } } else { if (m2_PyObject_AsReadBuffer(value, &vbuf, &vlen) == -1) return NULL; } if ((bn=BN_new())==NULL) { m2_PyBuffer_Release(value, &view); PyErr_SetString(PyExc_MemoryError, "dec_to_bn"); return NULL; } if ((BN_dec2bn(&bn, (const char *)vbuf) <= 0)) { m2_PyBuffer_Release(value, &view); m2_PyErr_Msg(PyExc_RuntimeError); BN_free(bn); return NULL; } m2_PyBuffer_Release(value, &view); return bn; } %} /* Various useful typemaps. */ %typemap(in) Blob * { Py_ssize_t len = 0; if (!PyBytes_Check($input)) { PyErr_SetString(PyExc_TypeError, "expected PyString"); return NULL; } len=PyBytes_Size($input); if (len > INT_MAX) { PyErr_SetString(PyExc_ValueError, "object too large"); return NULL; } $1=(Blob *)PyMem_Malloc(sizeof(Blob)); if (!$1) { PyErr_SetString(PyExc_MemoryError, "malloc Blob"); return NULL; } $1->data=(unsigned char *)PyBytes_AsString($input); $1->len=len; } %typemap(out) Blob * { if ($1==NULL) { Py_INCREF(Py_None); $result=Py_None; } else { $result=PyBytes_FromStringAndSize((const char *)$1->data, $1->len); PyMem_Free($1->data); PyMem_Free($1); } } %typemap(in) PyObject *pyfunc { if (!PyCallable_Check($input)) { PyErr_SetString(PyExc_TypeError, "expected PyCallable"); return NULL; } $1=$input; } %typemap(in) PyObject *pyblob { if (!PyBytes_Check($input)) { PyErr_SetString(PyExc_TypeError, "expected PyString"); return NULL; } $1=$input; } %typemap(in) PyObject * { $1=$input; } %typemap(out) PyObject * { $result=$1; } %typemap(out) int { $result=PyLong_FromLong($1); if (PyErr_Occurred()) SWIG_fail; } /* Pointer checks. */ %apply Pointer NONNULL { Blob * }; /* A bunch of "straight-thru" functions. */ %rename(err_print_errors) ERR_print_errors; %threadallow ERR_print_errors; extern void ERR_print_errors(BIO *); %rename(err_clear_error) ERR_clear_error; extern void ERR_clear_error(void); %rename(err_get_error) ERR_get_error; extern unsigned long ERR_get_error(void); %rename(err_peek_error) ERR_peek_error; extern unsigned long ERR_peek_error(void); %rename(err_lib_error_string) ERR_lib_error_string; extern const char *ERR_lib_error_string(unsigned long); %rename(err_func_error_string) ERR_func_error_string; extern const char *ERR_func_error_string(unsigned long); %rename(err_reason_error_string) ERR_reason_error_string; extern const char *ERR_reason_error_string(unsigned long); m2crypto-0.42.0/src/SWIG/_lib11_compat.i000066400000000000000000000230661465575656700175410ustar00rootroot00000000000000/* * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ %{ #if OPENSSL_VERSION_NUMBER < 0x10100000L #include #include # define OPENSSL_zalloc(num) \ CRYPTO_zalloc(num, __FILE__, __LINE__) static void *CRYPTO_zalloc(size_t num, const char *file, int line) { void *ret = CRYPTO_malloc(num, file, line); if (ret != NULL) memset(ret, 0, num); return ret; } #include #ifndef BN_F_BN_GENCB_NEW # define BN_F_BN_GENCB_NEW 143 #endif # define BN_GENCB_get_arg(gencb) ((gencb)->arg) BN_GENCB *BN_GENCB_new(void) { BN_GENCB *ret; if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL) { BNerr(BN_F_BN_GENCB_NEW, ERR_R_MALLOC_FAILURE); return (NULL); } return ret; } void BN_GENCB_free(BN_GENCB *cb) { if (cb == NULL) return; OPENSSL_free(cb); } 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 * parameters MUST be non-NULL for n and e. d may be * left NULL (in case only the public key is used). */ if ((r->n == NULL && n == NULL) || (r->e == NULL && e == NULL)) return 0; if (n != NULL) { BN_free(r->n); r->n = n; } if (e != NULL) { BN_free(r->e); r->e = e; } if (d != NULL) { BN_free(r->d); r->d = d; } return 1; } int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q) { /* If the fields p and q in r are NULL, the corresponding input * parameters MUST be non-NULL. */ if ((r->p == NULL && p == NULL) || (r->q == NULL && q == NULL)) return 0; if (p != NULL) { BN_free(r->p); r->p = p; } if (q != NULL) { BN_free(r->q); r->q = q; } return 1; } int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp) { /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input * parameters MUST be non-NULL. */ if ((r->dmp1 == NULL && dmp1 == NULL) || (r->dmq1 == NULL && dmq1 == NULL) || (r->iqmp == NULL && iqmp == NULL)) return 0; if (dmp1 != NULL) { BN_free(r->dmp1); r->dmp1 = dmp1; } if (dmq1 != NULL) { BN_free(r->dmq1); r->dmq1 = dmq1; } if (iqmp != NULL) { BN_free(r->iqmp); r->iqmp = iqmp; } return 1; } void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) { if (n != NULL) *n = r->n; if (e != NULL) *e = r->e; if (d != NULL) *d = r->d; } void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q) { if (p != NULL) *p = r->p; if (q != NULL) *q = r->q; } void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp) { if (dmp1 != NULL) *dmp1 = r->dmp1; if (dmq1 != NULL) *dmq1 = r->dmq1; if (iqmp != NULL) *iqmp = r->iqmp; } void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) { if (p != NULL) *p = d->p; if (q != NULL) *q = d->q; if (g != NULL) *g = d->g; } int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) { /* If the fields p, q and g in d are NULL, the corresponding input * parameters MUST be non-NULL. */ if ((d->p == NULL && p == NULL) || (d->q == NULL && q == NULL) || (d->g == NULL && g == NULL)) return 0; if (p != NULL) { BN_free(d->p); d->p = p; } if (q != NULL) { BN_free(d->q); d->q = q; } if (g != NULL) { BN_free(d->g); d->g = g; } return 1; } void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key) { if (pub_key != NULL) *pub_key = d->pub_key; if (priv_key != NULL) *priv_key = d->priv_key; } int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) { /* If the field pub_key in d is NULL, the corresponding input * parameters MUST be non-NULL. The priv_key field may * be left NULL. */ if (d->pub_key == NULL && pub_key == NULL) return 0; if (pub_key != NULL) { BN_free(d->pub_key); d->pub_key = pub_key; } if (priv_key != NULL) { BN_free(d->priv_key); d->priv_key = priv_key; } return 1; } void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) { if (pr != NULL) *pr = sig->r; if (ps != NULL) *ps = sig->s; } int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) { if (r == NULL || s == NULL) return 0; BN_clear_free(sig->r); BN_clear_free(sig->s); sig->r = r; sig->s = s; return 1; } void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) { if (pr != NULL) *pr = sig->r; if (ps != NULL) *ps = sig->s; } int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) { if (r == NULL || s == NULL) return 0; BN_clear_free(sig->r); BN_clear_free(sig->s); sig->r = r; sig->s = s; return 1; } void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) { if (p != NULL) *p = dh->p; if (q != NULL) *q = dh->q; if (g != NULL) *g = dh->g; } int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) { /* If the fields p and g in d are NULL, the corresponding input * parameters MUST be non-NULL. q may remain NULL. */ if ((dh->p == NULL && p == NULL) || (dh->g == NULL && g == NULL)) return 0; if (p != NULL) { BN_free(dh->p); dh->p = p; } if (q != NULL) { BN_free(dh->q); dh->q = q; } if (g != NULL) { BN_free(dh->g); dh->g = g; } if (q != NULL) { dh->length = BN_num_bits(q); } return 1; } void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) { if (pub_key != NULL) *pub_key = dh->pub_key; if (priv_key != NULL) *priv_key = dh->priv_key; } int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) { /* If the field pub_key in dh is NULL, the corresponding input * parameters MUST be non-NULL. The priv_key field may * be left NULL. */ if (dh->pub_key == NULL && pub_key == NULL) return 0; if (pub_key != NULL) { BN_free(dh->pub_key); dh->pub_key = pub_key; } if (priv_key != NULL) { BN_free(dh->priv_key); dh->priv_key = priv_key; } return 1; } int DH_set_length(DH *dh, long length) { dh->length = length; return 1; } const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx) { return ctx->iv; } unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx) { return ctx->iv; } EVP_MD_CTX *EVP_MD_CTX_new(void) { return OPENSSL_zalloc(sizeof(EVP_MD_CTX)); } void EVP_MD_CTX_free(EVP_MD_CTX *ctx) { EVP_MD_CTX_cleanup(ctx); OPENSSL_free(ctx); } int RSA_size(const RSA* rsa) { /* BIGNUM* n = NULL; RSA_get0_key(rsa, n, NULL, NULL); */ return BN_num_bytes(rsa->n); } RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth) { RSA_METHOD *ret; ret = OPENSSL_malloc(sizeof(RSA_METHOD)); if (ret != NULL) { memcpy(ret, meth, sizeof(*meth)); ret->name = OPENSSL_strdup(meth->name); if (ret->name == NULL) { OPENSSL_free(ret); return NULL; } } return ret; } int RSA_meth_set1_name(RSA_METHOD *meth, const char *name) { char *tmpname; tmpname = OPENSSL_strdup(name); if (tmpname == NULL) { return 0; } OPENSSL_free((char *)meth->name); meth->name = tmpname; return 1; } int RSA_meth_set_priv_enc(RSA_METHOD *meth, int (*priv_enc) (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)) { meth->rsa_priv_enc = priv_enc; return 1; } int RSA_meth_set_priv_dec(RSA_METHOD *meth, int (*priv_dec) (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)) { meth->rsa_priv_dec = priv_dec; return 1; } int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa)) { meth->finish = finish; return 1; } void RSA_meth_free(RSA_METHOD *meth) { if (meth != NULL) { OPENSSL_free((char *)meth->name); OPENSSL_free(meth); } } int RSA_bits(const RSA *r) { return (BN_num_bits(r->n)); } RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey) { if (pkey->type != EVP_PKEY_RSA) { return NULL; } return pkey->pkey.rsa; } int X509_NAME_get0_der(X509_NAME *nm, const unsigned char **pder, size_t *pderlen) { /* Make sure encoding is valid */ if (i2d_X509_NAME(nm, NULL) <= 0) return 0; if (pder != NULL) *pder = (unsigned char *)nm->bytes->data; if (pderlen != NULL) *pderlen = nm->bytes->length; return 1; } #endif /* OPENSSL_VERSION_NUMBER */ %} m2crypto-0.42.0/src/SWIG/_m2crypto.def000066400000000000000000000000271465575656700173430ustar00rootroot00000000000000EXPORTS init_m2crypto m2crypto-0.42.0/src/SWIG/_m2crypto.i000066400000000000000000000047531465575656700170470ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved. * * Portions created by Open Source Applications Foundation (OSAF) are * Copyright (C) 2004-2006 OSAF. All Rights Reserved. * * Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved. * */ %module(threads=1) m2crypto /* We really don't need threadblock (PyGILState_Ensure() etc.) anywhere. Disable threadallow as well, only enable it for operations likely to block. */ %nothreadblock; %nothreadallow; #if SWIG_VERSION >= 0x030000 #define __WCHAR_MAX__ __WCHAR_MAX #define __WCHAR_MIN__ __WCHAR_MIN #endif /* https://todo.sr.ht/~mcepl/m2crypto/246 */ %ignore WCHAR_MAX; %ignore WCHAR_MIN; /* http://swig.10945.n7.nabble.com/SWIG-AsVal-wchar-t-error-td2264.html */ %{ int SWIG_AsVal_wchar_t(PyObject *p, wchar_t *c) { return SWIG_OK; } PyObject *SWIG_From_wchar_t(wchar_t c) { return SWIG_Py_Void(); } %} %{ #ifdef _WIN32 #define _WINSOCKAPI_ #include #include #pragma comment(lib, "Ws2_32") typedef unsigned __int64 uint64_t; #endif %} %{ #if defined __GNUC__ && __GNUC__ < 5 #pragma GCC diagnostic ignored "-Wunused-label" #pragma GCC diagnostic warning "-Wstrict-prototypes" #endif #include #include #include <_lib.h> #include #include #include "compile.h" static PyObject *ssl_verify_cb_func; static PyObject *ssl_info_cb_func; static PyObject *ssl_set_tmp_dh_cb_func; static PyObject *ssl_set_tmp_rsa_cb_func; static PyObject *x509_store_verify_cb_func; %} %include /* Bring in STACK_OF macro definition */ #ifdef _WIN32 %include #endif %include /* Bring in LHASH_OF macro definition */ /* XXX Can't include lhash.h where LHASH_OF is defined, because it includes XXX stdio.h etc. which we fail to include. So we have to (re)define XXX LHASH_OF here instead. %include */ #if OPENSSL_VERSION_NUMBER >= 0x10000000L #define LHASH_OF(type) struct lhash_st_##type #endif %include constraints.i %include _threads.i %include _lib.i %include _bio.i %include _bn.i %include _rand.i %include _evp.i %include _aes.i %include _rc4.i %include _dh.i %include _rsa.i %include _dsa.i %include _ssl.i %include _x509.i %include _asn1.i %include _pkcs7.i %include _util.i %include _ec.i %include _engine.i %include _objects.i #ifdef SWIG_VERSION %constant int encrypt = 1; %constant int decrypt = 0; #endif m2crypto-0.42.0/src/SWIG/_objects.i000066400000000000000000000054331465575656700167150ustar00rootroot00000000000000/* * -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: syntax=c sts=4 sw=4 * * ASN1_OBJECT manipulation functions from OBJ_obj2txt(3SSL). * * Pavel Shramov * IMEC MSU */ %{ #include %} %apply Pointer NONNULL { ASN1_OBJECT * }; %apply Pointer NONNULL { const char * }; %rename(obj_nid2obj) OBJ_nid2obj; extern ASN1_OBJECT * OBJ_nid2obj(int n); %rename(obj_nid2ln) OBJ_nid2ln; extern const char * OBJ_nid2ln(int n); %rename(obj_nid2sn) OBJ_nid2sn; extern const char * OBJ_nid2sn(int n); %rename(obj_obj2nid) OBJ_obj2nid; extern int OBJ_obj2nid(const ASN1_OBJECT *o); %rename(obj_ln2nid) OBJ_ln2nid; extern int OBJ_ln2nid(const char *ln); %rename(obj_sn2nid) OBJ_sn2nid; extern int OBJ_sn2nid(const char *sn); %rename(obj_txt2nid) OBJ_txt2nid; extern int OBJ_txt2nid(const char *s); %rename(obj_txt2obj) OBJ_txt2obj; extern ASN1_OBJECT * OBJ_txt2obj(const char *s, int no_name); %rename(_obj_obj2txt) OBJ_obj2txt; extern int OBJ_obj2txt(char *, int, const ASN1_OBJECT *, int); %inline %{ /* From the manpage for OBJ_obt2txt (): BUGS OBJ_obj2txt() is awkward and messy to use: it doesn’t follow the convention of other OpenSSL functions where the buffer can be set to NULL to determine the amount of data that should be written. Instead buf must point to a valid buffer and buf_len should be set to a positive value. A buffer length of 80 should be more than enough to handle any OID encountered in practice. The first call to OBJ_obj2txt () therefore passes a non-NULL dummy buffer. This wart is reportedly removed in OpenSSL 0.9.8b, although the manpage has not been updated. OBJ_obj2txt always prints \0 at the end. But the return value is the number of "good" bytes written. So memory is allocated for len + 1 bytes but only len bytes are marshalled to python. */ PyObject *obj_obj2txt(const ASN1_OBJECT *obj, int no_name) { int len; PyObject *ret; char *buf; char dummy[1]; len = OBJ_obj2txt(dummy, 1, obj, no_name); if (len < 0) { m2_PyErr_Msg(PyExc_RuntimeError); return NULL; } else if (len == 0) { /* XXX: For OpenSSL prior to 0.9.8b. Changes between 0.9.8a and 0.9.8b [04 May 2006] ... *) Several fixes and enhancements to the OID generation code. The old code sometimes allowed invalid OIDs (1.X for X >= 40 for example), couldn't handle numbers larger than ULONG_MAX, truncated printing and had a non standard OBJ_obj2txt() behaviour. [Steve Henson] */ len = 80; } buf = PyMem_Malloc(len + 1); len = OBJ_obj2txt(buf, len + 1, obj, no_name); ret = PyBytes_FromStringAndSize(buf, len); PyMem_Free(buf); return ret; } %} m2crypto-0.42.0/src/SWIG/_pkcs7.i000066400000000000000000000162651465575656700163200ustar00rootroot00000000000000/* Copyright (c) 2000 Ng Pheng Siong. All rights reserved. * Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved. */ /* $Id$ */ %{ #include #include #include #include %} %apply Pointer NONNULL { BIO * }; %apply Pointer NONNULL { EVP_CIPHER * }; %apply Pointer NONNULL { EVP_PKEY * }; %apply Pointer NONNULL { PKCS7 * }; %apply Pointer NONNULL { STACK_OF(X509) * }; %apply Pointer NONNULL { X509 * }; %rename(pkcs7_new) PKCS7_new; extern PKCS7 *PKCS7_new(void); %rename(pkcs7_free) PKCS7_free; extern void PKCS7_free(PKCS7 *); %rename(pkcs7_add_certificate) PKCS7_add_certificate; extern void PKCS7_add_certificate(PKCS7 *, X509 *); /* S/MIME operation */ %constant int PKCS7_TEXT = 0x1; %constant int PKCS7_NOCERTS = 0x2; %constant int PKCS7_NOSIGS = 0x4; %constant int PKCS7_NOCHAIN = 0x8; %constant int PKCS7_NOINTERN = 0x10; %constant int PKCS7_NOVERIFY = 0x20; %constant int PKCS7_DETACHED = 0x40; %constant int PKCS7_BINARY = 0x80; %constant int PKCS7_NOATTR = 0x100; %constant int PKCS7_SIGNED = NID_pkcs7_signed; %constant int PKCS7_ENVELOPED = NID_pkcs7_enveloped; %constant int PKCS7_SIGNED_ENVELOPED = NID_pkcs7_signedAndEnveloped; %constant int PKCS7_DATA = NID_pkcs7_data; %warnfilter(454) _pkcs7_err; %warnfilter(454) _smime_err; %inline %{ static PyObject *_pkcs7_err, *_smime_err; void pkcs7_init(PyObject *pkcs7_err) { Py_INCREF(pkcs7_err); _pkcs7_err = pkcs7_err; } void smime_init(PyObject *smime_err) { Py_INCREF(smime_err); _smime_err = smime_err; } %} %inline %{ PyObject *pkcs7_decrypt(PKCS7 *pkcs7, EVP_PKEY *pkey, X509 *cert, int flags) { int outlen; char *outbuf; BIO *bio; PyObject *ret; if (!(bio=BIO_new(BIO_s_mem()))) { PyErr_SetString(PyExc_MemoryError, "pkcs7_decrypt"); return NULL; } if (!PKCS7_decrypt(pkcs7, pkey, cert, bio, flags)) { m2_PyErr_Msg(_pkcs7_err); BIO_free(bio); return NULL; } outlen = BIO_ctrl_pending(bio); if (!(outbuf=(char *)PyMem_Malloc(outlen))) { PyErr_SetString(PyExc_MemoryError, "pkcs7_decrypt"); BIO_free(bio); return NULL; } BIO_read(bio, outbuf, outlen); ret = PyBytes_FromStringAndSize(outbuf, outlen); BIO_free(bio); PyMem_Free(outbuf); return ret; } %} %typemap(out) PKCS7 * { PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if ($1 != NULL) $result = SWIG_NewPointerObj($1, $1_descriptor, 0); else { m2_PyErr_Msg(_smime_err); $result = NULL; } } %threadallow pkcs7_encrypt; %inline %{ PKCS7 *pkcs7_encrypt(STACK_OF(X509) *stack, BIO *bio, EVP_CIPHER *cipher, int flags) { return PKCS7_encrypt(stack, bio, cipher, flags); } %} %threadallow pkcs7_sign1; %inline %{ PKCS7 *pkcs7_sign1(X509 *x509, EVP_PKEY *pkey, STACK_OF(X509) *stack, BIO *bio, EVP_MD *hash, int flags) { PKCS7 *p7 = PKCS7_sign(NULL, NULL, stack, bio, flags | PKCS7_STREAM); if (p7 == NULL) { return NULL; } if (PKCS7_sign_add_signer(p7, x509, pkey, hash, flags) == NULL) { return NULL; } if (PKCS7_final(p7, bio, flags) != 1) { return NULL; } return p7; } %} %threadallow pkcs7_sign0; %inline %{ PKCS7 *pkcs7_sign0(X509 *x509, EVP_PKEY *pkey, BIO *bio, EVP_MD *hash, int flags) { return pkcs7_sign1(x509, pkey, NULL, bio, hash, flags); } %} %typemap(out) PKCS7 * { PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if ($1 != NULL) $result = SWIG_NewPointerObj($1, $1_descriptor, 0); else { m2_PyErr_Msg(_pkcs7_err); $result = NULL; } } %threadallow pkcs7_read_bio; %inline %{ PKCS7 *pkcs7_read_bio(BIO *bio) { return PEM_read_bio_PKCS7(bio, NULL, NULL, NULL); } %} %threadallow pkcs7_read_bio_der; %inline %{ PKCS7 *pkcs7_read_bio_der(BIO *bio) { return d2i_PKCS7_bio(bio, NULL); } %} %typemap(out) PKCS7 * ; %inline %{ PyObject *pkcs7_verify1(PKCS7 *pkcs7, STACK_OF(X509) *stack, X509_STORE *store, BIO *data, int flags) { int res, outlen; char *outbuf; BIO *bio; PyObject *ret; if (!(bio=BIO_new(BIO_s_mem()))) { PyErr_SetString(PyExc_MemoryError, "pkcs7_verify1"); return NULL; } Py_BEGIN_ALLOW_THREADS res = PKCS7_verify(pkcs7, stack, store, data, bio, flags); Py_END_ALLOW_THREADS if (!res) { m2_PyErr_Msg(_pkcs7_err); BIO_free(bio); return NULL; } outlen = BIO_ctrl_pending(bio); if (!(outbuf=(char *)PyMem_Malloc(outlen))) { PyErr_SetString(PyExc_MemoryError, "pkcs7_verify1"); BIO_free(bio); return NULL; } BIO_read(bio, outbuf, outlen); ret = PyBytes_FromStringAndSize(outbuf, outlen); BIO_free(bio); PyMem_Free(outbuf); return ret; } PyObject *pkcs7_verify0(PKCS7 *pkcs7, STACK_OF(X509) *stack, X509_STORE *store, int flags) { return pkcs7_verify1(pkcs7, stack, store, NULL, flags); } %} %threadallow smime_write_pkcs7_multi; %inline %{ int smime_write_pkcs7_multi(BIO *bio, PKCS7 *pkcs7, BIO *data, int flags) { return SMIME_write_PKCS7(bio, pkcs7, data, flags | PKCS7_DETACHED); } %} %threadallow smime_write_pkcs7; %inline %{ int smime_write_pkcs7(BIO *bio, PKCS7 *pkcs7, int flags) { return SMIME_write_PKCS7(bio, pkcs7, NULL, flags); } PyObject *smime_read_pkcs7(BIO *bio) { BIO *bcont = NULL; PKCS7 *p7; PyObject *tuple, *_p7, *_BIO; PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if (BIO_method_type(bio) == BIO_TYPE_MEM) { /* OpenSSL FAQ explains that this is needed for mem BIO to return EOF, * like file BIO does. Might need to do this for more mem BIOs but * not sure if that is safe, so starting with just this single place. */ BIO_set_mem_eof_return(bio, 0); } Py_BEGIN_ALLOW_THREADS p7=SMIME_read_PKCS7(bio, &bcont); Py_END_ALLOW_THREADS if (!p7) { m2_PyErr_Msg(_smime_err); return NULL; } if (!(tuple=PyTuple_New(2))) { PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails"); return NULL; } _p7 = SWIG_NewPointerObj((void *)p7, SWIGTYPE_p_PKCS7, 0); PyTuple_SET_ITEM(tuple, 0, _p7); if (!bcont) { Py_INCREF(Py_None); PyTuple_SET_ITEM(tuple, 1, Py_None); } else { _BIO = SWIG_NewPointerObj((void *)bcont, SWIGTYPE_p_BIO, 0); PyTuple_SET_ITEM(tuple, 1, _BIO); } return tuple; } %} %threadallow pkcs7_write_bio; %inline %{ int pkcs7_write_bio(PKCS7 *pkcs7, BIO* bio) { return PEM_write_bio_PKCS7(bio, pkcs7); } %} %threadallow pkcs7_write_bio_der; %inline %{ int pkcs7_write_bio_der(PKCS7 *pkcs7, BIO *bio) { return i2d_PKCS7_bio(bio, pkcs7); } int pkcs7_type_nid(PKCS7 *pkcs7) { return OBJ_obj2nid(pkcs7->type); } const char *pkcs7_type_sn(PKCS7 *pkcs7) { return OBJ_nid2sn(OBJ_obj2nid(pkcs7->type)); } %} %threadallow smime_crlf_copy; %inline %{ int smime_crlf_copy(BIO *in, BIO *out) { return SMIME_crlf_copy(in, out, PKCS7_TEXT); } /* return STACK_OF(X509)* */ STACK_OF(X509) *pkcs7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags) { return PKCS7_get0_signers(p7, certs, flags); } %} m2crypto-0.42.0/src/SWIG/_py3k_compat.i000066400000000000000000000022611465575656700175110ustar00rootroot00000000000000%{ #if PY_MAJOR_VERSION >= 3 FILE* PyFile_AsFile(PyObject *pyfile) { FILE* fp; int fd; const char *mode_str = NULL; PyObject *mode_obj; if ((fd = PyObject_AsFileDescriptor(pyfile)) == -1) { PyErr_SetString(PyExc_BlockingIOError, "Cannot find file handler for the Python file!"); return NULL; } if ((mode_obj = PyObject_GetAttrString(pyfile, "mode")) == NULL) { mode_str = "rb"; PyErr_Clear(); } else { /* convert to plain string * note that error checking is embedded in the function */ mode_str = PyUnicode_AsUTF8AndSize(mode_obj, NULL); } if((fp = fdopen(fd, mode_str)) == NULL) { PyErr_SetFromErrno(PyExc_IOError); } Py_XDECREF(mode_obj); return fp; } #else /* PY2K */ #ifndef PyLong_FromLong #define PyLong_FromLong(x) PyInt_FromLong(x) #endif #ifndef PyUnicode_AsUTF8 #define PyUnicode_AsUTF8(x) PyString_AsString(x) #endif #ifndef PyUnicode_FromString #define PyUnicode_FromString(x) PyString_FromString(x) #endif #ifndef PyUnicode_Format #define PyUnicode_Format(x, y) PyString_Format(x, y) #endif #endif /* PY_MAJOR_VERSION */ %} m2crypto-0.42.0/src/SWIG/_rand.i000066400000000000000000000073431465575656700162120ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. * Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved. */ /* $Id: _rand.i 721 2010-02-13 06:30:33Z heikki $ */ %module _rand %rename(rand_file_name) RAND_file_name; extern const char *RAND_file_name(char *, size_t ); %rename(rand_load_file) RAND_load_file; extern int RAND_load_file(const char *, long); %rename(rand_save_file) RAND_write_file; extern int RAND_write_file(const char *); %rename(rand_poll) RAND_poll; extern int RAND_poll(void); %rename(rand_status) RAND_status; extern int RAND_status(void); %rename(rand_cleanup) RAND_cleanup; extern void RAND_cleanup(void); %warnfilter(454) _rand_err; %inline %{ static PyObject *_rand_err; void rand_init(PyObject *rand_err) { Py_INCREF(rand_err); _rand_err = rand_err; } PyObject *rand_seed(PyObject *seed) { const void *buf = NULL; int len = 0; m2_PyObject_AsReadBufferInt(seed, &buf, &len); RAND_seed(buf, len); Py_RETURN_NONE; } PyObject *rand_add(PyObject *blob, double entropy) { const void *buf = NULL; int len = 0; m2_PyObject_AsReadBufferInt(blob, &buf, &len); RAND_add(buf, len, entropy); Py_RETURN_NONE; } PyObject *rand_bytes(int n) { void *blob; int ret; PyObject *obj; if (!(blob = PyMem_Malloc(n))) { PyErr_SetString(PyExc_MemoryError, "Insufficient memory for rand_bytes."); return NULL; } if ((ret = RAND_bytes(blob, n)) == 1) { obj = PyBytes_FromStringAndSize(blob, n); PyMem_Free(blob); return obj; } else if (ret == 0) { PyErr_SetString(_rand_err, "Not enough randomness."); PyMem_Free(blob); return NULL; } else if (ret == -1) { PyErr_SetString(_rand_err, "Not supported by the current RAND method."); PyMem_Free(blob); return NULL; } else { PyMem_Free(blob); m2_PyErr_Msg(_rand_err); return NULL; } } PyObject *rand_pseudo_bytes(int n) { int ret; unsigned char *blob; PyObject *tuple; if (!(blob=(unsigned char *)PyMem_Malloc(n))) { PyErr_SetString(PyExc_MemoryError, "Insufficient memory for rand_pseudo_bytes."); return NULL; } if (!(tuple=PyTuple_New(2))) { PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails"); PyMem_Free(blob); return NULL; } ret = RAND_pseudo_bytes(blob, n); if (ret == -1) { PyMem_Free(blob); Py_DECREF(tuple); PyErr_SetString(_rand_err, "Function RAND_pseudo_bytes not supported by the current RAND method."); return NULL; } else { PyTuple_SET_ITEM(tuple, 0, PyBytes_FromStringAndSize((char*)blob, n)); PyMem_Free(blob); PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong((long)ret)); return tuple; } } PyObject *rand_file_name(void) { PyObject *obj; char *str; if ((obj = PyBytes_FromStringAndSize(NULL, BUFSIZ))==NULL) { PyErr_SetString(PyExc_MemoryError, "rand_file_name"); return NULL; } str=PyBytes_AS_STRING(obj); if (RAND_file_name(str, BUFSIZ)==NULL) { PyErr_SetString(PyExc_RuntimeError, "rand_file_name"); return NULL; } if (_PyBytes_Resize(&obj, (Py_ssize_t)strlen(str))!=0) return NULL; /* mem exception set by _PyBytes_Resize */ return obj; } void rand_screen(void) { #ifdef _WIN32 RAND_screen(); #endif } int rand_win32_event(unsigned int imsg, int wparam, long lparam) { #ifdef _WIN32 return RAND_event(imsg, wparam, lparam); #else return 0; #endif } %} /* 2004-04-05, ngps: Still missing: RAND_egd RAND_egd_bytes RAND_query_egd_bytes */ m2crypto-0.42.0/src/SWIG/_rc4.i000066400000000000000000000025601465575656700157520ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. */ /* $Id$ */ %include #if defined(OPENSSL_NO_RC4) #undef OPENSSL_NO_RC4 %constant OPENSSL_NO_RC4 = 1; #else %constant OPENSSL_NO_RC4 = 0; %{ #include %} %apply Pointer NONNULL { RC4_KEY * }; %inline %{ RC4_KEY *rc4_new(void) { RC4_KEY *key; if (!(key = (RC4_KEY *)PyMem_Malloc(sizeof(RC4_KEY)))) PyErr_SetString(PyExc_MemoryError, "rc4_new"); return key; } void rc4_free(RC4_KEY *key) { PyMem_Free((void *)key); } PyObject *rc4_set_key(RC4_KEY *key, PyObject *value) { const void *vbuf = NULL; int vlen = 0; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; RC4_set_key(key, vlen, vbuf); Py_RETURN_NONE; } PyObject *rc4_update(RC4_KEY *key, PyObject *in) { PyObject *ret; const void *buf; Py_ssize_t len; void *out; if (m2_PyObject_AsReadBuffer(in, &buf, &len) == -1) return NULL; if (!(out = PyMem_Malloc(len))) { PyErr_SetString(PyExc_MemoryError, "expected a string object"); return NULL; } RC4(key, len, buf, out); ret = PyBytes_FromStringAndSize(out, len); PyMem_Free(out); return ret; } int rc4_type_check(RC4_KEY *key) { return 1; } %} #endif m2crypto-0.42.0/src/SWIG/_rsa.i000066400000000000000000000312721465575656700160510ustar00rootroot00000000000000/* Copyright (c) 1999-2000 Ng Pheng Siong. All rights reserved. */ /* $Id$ */ %{ #include #include #include #include #include %} %apply Pointer NONNULL { RSA * }; %apply Pointer NONNULL { PyObject *pyfunc }; %rename(rsa_size) RSA_size; extern int RSA_size(const RSA*); %rename(rsa_new) RSA_new; extern RSA *RSA_new(void); %rename(rsa_free) RSA_free; extern void RSA_free(RSA *); %rename(rsa_check_key) RSA_check_key; extern int RSA_check_key(const RSA *); %constant int no_padding = RSA_NO_PADDING; %constant int pkcs1_padding = RSA_PKCS1_PADDING; #ifdef RSA_SSLV23_PADDING %constant int sslv23_padding = RSA_SSLV23_PADDING; #endif %constant int pkcs1_oaep_padding = RSA_PKCS1_OAEP_PADDING; %constant int NID_sha1 = NID_sha1; #if OPENSSL_VERSION_NUMBER >= 0x0090800fL %constant int NID_sha224 = NID_sha224; %constant int NID_sha256 = NID_sha256; %constant int NID_sha384 = NID_sha384; %constant int NID_sha512 = NID_sha512; #endif %constant int NID_md5 = NID_md5; %constant int NID_ripemd160 = NID_ripemd160; %warnfilter(454) _rsa_err; %inline %{ static PyObject *_rsa_err; void rsa_init(PyObject *rsa_err) { Py_INCREF(rsa_err); _rsa_err = rsa_err; } %} %inline %{ RSA *rsa_read_key(BIO *f, PyObject *pyfunc) { RSA *rsa; Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS rsa = PEM_read_bio_RSAPrivateKey(f, NULL, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); return rsa; } %} %inline %{ int rsa_write_key(RSA *rsa, BIO *f, EVP_CIPHER *cipher, PyObject *pyfunc) { int ret; Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS ret = PEM_write_bio_RSAPrivateKey(f, rsa, cipher, NULL, 0, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); return ret; } %} %inline %{ int rsa_write_key_no_cipher(RSA *rsa, BIO *f, PyObject *pyfunc) { int ret; Py_INCREF(pyfunc); Py_BEGIN_ALLOW_THREADS ret = PEM_write_bio_RSAPrivateKey(f, rsa, NULL, NULL, 0, passphrase_callback, (void *)pyfunc); Py_END_ALLOW_THREADS Py_DECREF(pyfunc); return ret; } %} %threadallow rsa_read_pub_key; %inline %{ RSA *rsa_read_pub_key(BIO *f) { return PEM_read_bio_RSA_PUBKEY(f, NULL, NULL, NULL); } %} %threadallow rsa_write_pub_key; %inline %{ int rsa_write_pub_key(RSA *rsa, BIO *f) { return PEM_write_bio_RSA_PUBKEY(f, rsa); } PyObject *rsa_get_e(RSA *rsa) { const BIGNUM* e = NULL; RSA_get0_key(rsa, NULL, &e, NULL); if (!e) { PyErr_SetString(_rsa_err, "'e' is unset"); return NULL; } return bn_to_mpi(e); } PyObject *rsa_get_n(RSA *rsa) { const BIGNUM* n = NULL; RSA_get0_key(rsa, &n, NULL, NULL); if (!n) { PyErr_SetString(_rsa_err, "'n' is unset"); return NULL; } return bn_to_mpi(n); } PyObject *rsa_set_e(RSA *rsa, PyObject *eval) { const BIGNUM* n_read = NULL; BIGNUM* n = NULL; BIGNUM* e; if (!(e = m2_PyObject_AsBIGNUM(eval, _rsa_err))) { return NULL; } /* n and e must be set at the same time so if e is unset, set it to zero */ RSA_get0_key(rsa, &n_read, NULL, NULL); if (!n_read) { n = BN_new(); } if (RSA_set0_key(rsa, n, e, NULL) != 1) { PyErr_SetString(_rsa_err, "Cannot set fields of RSA object."); BN_free(e); BN_free(n); return NULL; } Py_RETURN_NONE; } PyObject *rsa_set_n(RSA *rsa, PyObject *nval) { BIGNUM* n; const BIGNUM* e_read = NULL; BIGNUM* e = NULL; if (!(n = m2_PyObject_AsBIGNUM(nval, _rsa_err))) { return NULL; } /* n and e must be set at the same time so if e is unset, set it to zero */ RSA_get0_key(rsa, NULL, &e_read, NULL); if (!e_read) { e = BN_new(); } if (RSA_set0_key(rsa, n, e, NULL) != 1) { PyErr_SetString(_rsa_err, "Cannot set fields of RSA object."); BN_free(n); BN_free(e); return NULL; } Py_RETURN_NONE; } PyObject *rsa_set_en(RSA *rsa, PyObject *eval, PyObject* nval) { BIGNUM* e, *n; if (!(e = m2_PyObject_AsBIGNUM(eval, _rsa_err)) || !(n = m2_PyObject_AsBIGNUM(nval, _rsa_err))) { return NULL; } if (!RSA_set0_key(rsa, n, e, NULL)) { PyErr_SetString(_rsa_err, "Cannot set fields of RSA object."); BN_free(e); BN_free(n); return NULL; } Py_RETURN_NONE; } static BIGNUM* PyObject_Bin_AsBIGNUM(PyObject* value) { BIGNUM* bn; const void* vbuf; int vlen = 0; if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1) return NULL; if (!(bn = BN_bin2bn((unsigned char *)vbuf, vlen, NULL))) { m2_PyErr_Msg(_rsa_err); return NULL; } return bn; } PyObject *rsa_set_en_bin(RSA *rsa, PyObject *eval, PyObject* nval) { BIGNUM* e, *n; if (!(e = PyObject_Bin_AsBIGNUM(eval)) || !(n = PyObject_Bin_AsBIGNUM(nval))) { return NULL; } if (!RSA_set0_key(rsa, e, n, NULL)) { PyErr_SetString(_rsa_err, "Cannot set fields of RSA object."); BN_free(e); BN_free(n); return NULL; } Py_RETURN_NONE; } PyObject *rsa_private_encrypt(RSA *rsa, PyObject *from, int padding) { const void *fbuf; void *tbuf; int flen = 0, tlen; PyObject *ret; if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) return NULL; if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) { PyErr_SetString(PyExc_MemoryError, "rsa_private_encrypt"); return NULL; } tlen = RSA_private_encrypt(flen, (unsigned char *)fbuf, (unsigned char *)tbuf, rsa, padding); if (tlen == -1) { m2_PyErr_Msg(_rsa_err); PyMem_Free(tbuf); return NULL; } ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); PyMem_Free(tbuf); return ret; } PyObject *rsa_public_decrypt(RSA *rsa, PyObject *from, int padding) { const void *fbuf; void *tbuf; int flen = 0, tlen = 0; PyObject *ret; if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) return NULL; /* OpenSSL docs are confused here: it says we only need buffer * 'RSA_size()-11', but it is true only for RSA PKCS#1 type 1 * padding. For other uses we need to use different sizes. */ if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) { PyErr_SetString(PyExc_MemoryError, "rsa_public_decrypt"); return NULL; } tlen = RSA_public_decrypt(flen, (unsigned char *)fbuf, (unsigned char *)tbuf, rsa, padding); if (tlen == -1) { ERR_clear_error(); PyErr_Clear(); PyMem_Free(tbuf); Py_RETURN_NONE; } ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); PyMem_Free(tbuf); return ret; } PyObject *rsa_public_encrypt(RSA *rsa, PyObject *from, int padding) { const void *fbuf; void *tbuf; int flen = 0, tlen; PyObject *ret; if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) return NULL; if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) { PyErr_SetString(PyExc_MemoryError, "rsa_public_encrypt"); return NULL; } tlen = RSA_public_encrypt(flen, (unsigned char *)fbuf, (unsigned char *)tbuf, rsa, padding); if (tlen == -1) { m2_PyErr_Msg(_rsa_err); PyMem_Free(tbuf); return NULL; } ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); PyMem_Free(tbuf); return ret; } PyObject *rsa_private_decrypt(RSA *rsa, PyObject *from, int padding) { const void *fbuf; void *tbuf; int flen = 0, tlen; PyObject *ret; if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1) return NULL; if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) { PyErr_SetString(PyExc_MemoryError, "rsa_private_decrypt"); return NULL; } tlen = RSA_private_decrypt(flen, (unsigned char *)fbuf, (unsigned char *)tbuf, rsa, padding); if (tlen == -1) { ERR_clear_error(); PyErr_Clear(); PyMem_Free(tbuf); Py_RETURN_NONE; } ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); PyMem_Free(tbuf); return ret; } #if OPENSSL_VERSION_NUMBER >= 0x0090708fL PyObject *rsa_padding_add_pkcs1_pss(RSA *rsa, PyObject *digest, EVP_MD *hash, int salt_length) { const void *dbuf; unsigned char *tbuf; int dlen, result, tlen; PyObject *ret; if (m2_PyObject_AsReadBufferInt(digest, &dbuf, &dlen) == -1) return NULL; tlen = RSA_size(rsa); if (!(tbuf = OPENSSL_malloc(tlen))) { PyErr_SetString(PyExc_MemoryError, "rsa_padding_add_pkcs1_pss"); return NULL; } result = RSA_padding_add_PKCS1_PSS( rsa, tbuf, (unsigned char *)dbuf, hash, salt_length); if (result == -1) { m2_PyErr_Msg(_rsa_err); OPENSSL_cleanse(tbuf, tlen); OPENSSL_free(tbuf); return NULL; } ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); OPENSSL_cleanse(tbuf, tlen); OPENSSL_free(tbuf); return ret; } int rsa_verify_pkcs1_pss(RSA *rsa, PyObject *digest, PyObject *signature, EVP_MD *hash, int salt_length) { const void *dbuf; const void *sbuf; int dlen, slen, ret; if (m2_PyObject_AsReadBufferInt(digest, &dbuf, &dlen) == -1) { return 0; } if (m2_PyObject_AsReadBufferInt(signature, &sbuf, &slen) == -1) { return 0; } ret = RSA_verify_PKCS1_PSS( rsa, (unsigned char *)dbuf, hash, (unsigned char *)sbuf, salt_length); return ret; } #endif PyObject *rsa_sign(RSA *rsa, PyObject *py_digest_string, int method_type) { int digest_len = 0; int buf_len = 0; int ret = 0; unsigned int real_buf_len = 0; char *digest_string = NULL; unsigned char * sign_buf = NULL; PyObject *signature; ret = m2_PyString_AsStringAndSizeInt(py_digest_string, &digest_string, &digest_len); if (ret == -1) { /* PyString_AsStringAndSize raises the correct exceptions. */ return NULL; } buf_len = RSA_size(rsa); sign_buf = (unsigned char *)PyMem_Malloc(buf_len); ret = RSA_sign(method_type, (const unsigned char *)digest_string, digest_len, sign_buf, &real_buf_len, rsa); if (!ret) { m2_PyErr_Msg(_rsa_err); PyMem_Free(sign_buf); return NULL; } signature = PyBytes_FromStringAndSize((const char*) sign_buf, buf_len); PyMem_Free(sign_buf); return signature; } int rsa_verify(RSA *rsa, PyObject *py_verify_string, PyObject* py_sign_string, int method_type){ int ret = 0; char * sign_string = NULL; char * verify_string = NULL; int verify_len = 0; int sign_len = 0; ret = m2_PyString_AsStringAndSizeInt(py_verify_string, &verify_string, &verify_len); if (ret == -1) { /* PyString_AsStringAndSize raises the correct exceptions. */ return 0; } ret = m2_PyString_AsStringAndSizeInt(py_sign_string, &sign_string, &sign_len); if (ret == -1) { return 0; } ret = RSA_verify(method_type, (unsigned char *) verify_string, verify_len, (unsigned char *) sign_string, sign_len, rsa); if (!ret) { m2_PyErr_Msg(_rsa_err); return 0; } return ret; } PyObject *rsa_generate_key(int bits, unsigned long e, PyObject *pyfunc) { RSA *rsa; PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ BN_GENCB *gencb; BIGNUM *e_big; int ret; if ((e_big=BN_new()) == NULL) { m2_PyErr_Msg(_rsa_err); return NULL; } if (BN_set_word(e_big, e) == 0) { m2_PyErr_Msg(_rsa_err); BN_free(e_big); return NULL; } if ((gencb=BN_GENCB_new()) == NULL) { m2_PyErr_Msg(_rsa_err); BN_free(e_big); return NULL; } if ((rsa = RSA_new()) == NULL) { m2_PyErr_Msg(_rsa_err); BN_free(e_big); BN_GENCB_free(gencb); return NULL; } BN_GENCB_set(gencb, bn_gencb_callback, (void *) pyfunc); Py_INCREF(pyfunc); ret = RSA_generate_key_ex(rsa, bits, e_big, gencb); BN_free(e_big); BN_GENCB_free(gencb); Py_DECREF(pyfunc); if (ret) return SWIG_NewPointerObj((void *)rsa, SWIGTYPE_p_RSA, 0); m2_PyErr_Msg(_rsa_err); RSA_free(rsa); return NULL; } int rsa_type_check(RSA *rsa) { return 1; } int rsa_check_pub_key(RSA *rsa) { const BIGNUM* n, *e; RSA_get0_key(rsa, &n, &e, NULL); return n && e; } %} %threadallow rsa_write_key_der; %inline %{ int rsa_write_key_der(RSA *rsa, BIO *bio) { return i2d_RSAPrivateKey_bio(bio, rsa); } %} m2crypto-0.42.0/src/SWIG/_ssl.i000066400000000000000000000661011465575656700160640ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. */ /* ** Portions created by Open Source Applications Foundation (OSAF) are ** Copyright (C) 2004-2005 OSAF. All Rights Reserved. ** ** Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved. ** */ /* $Id$ */ %{ #include #include #include #include #include #include #include #ifdef _WIN32 #include #include #pragma comment(lib, "Ws2_32") typedef unsigned __int64 uint64_t; #else #include #include #endif %} #if OPENSSL_VERSION_NUMBER >= 0x10100005L %include #endif %apply Pointer NONNULL { SSL_CTX * }; %apply Pointer NONNULL { SSL * }; %apply Pointer NONNULL { SSL_CIPHER * }; %apply Pointer NONNULL { STACK_OF(SSL_CIPHER) * }; %apply Pointer NONNULL { STACK_OF(X509) * }; %apply Pointer NONNULL { BIO * }; %apply Pointer NONNULL { DH * }; %apply Pointer NONNULL { RSA * }; %apply Pointer NONNULL { EVP_PKEY *}; %apply Pointer NONNULL { PyObject *pyfunc }; %rename(ssl_get_ciphers) SSL_get_ciphers; extern STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl); %rename(ssl_get_version) SSL_get_version; extern const char *SSL_get_version(const SSL *); %rename(ssl_get_error) SSL_get_error; extern int SSL_get_error(const SSL *, int); %rename(ssl_get_state) SSL_state_string; extern const char *SSL_state_string(const SSL *); %rename(ssl_get_state_v) SSL_state_string_long; extern const char *SSL_state_string_long(const SSL *); %rename(ssl_get_alert_type) SSL_alert_type_string; extern const char *SSL_alert_type_string(int); %rename(ssl_get_alert_type_v) SSL_alert_type_string_long; extern const char *SSL_alert_type_string_long(int); %rename(ssl_get_alert_desc) SSL_alert_desc_string; extern const char *SSL_alert_desc_string(int); %rename(ssl_get_alert_desc_v) SSL_alert_desc_string_long; extern const char *SSL_alert_desc_string_long(int); %rename(sslv23_method) SSLv23_method; extern SSL_METHOD *SSLv23_method(void); %ignore TLSv1_method; extern SSL_METHOD *TLSv1_method(void); %typemap(out) SSL_CTX * { PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if ($1 != NULL) $result = SWIG_NewPointerObj($1, $1_descriptor, 0); else { m2_PyErr_Msg(_ssl_err); $result = NULL; } } %rename(ssl_ctx_new) SSL_CTX_new; extern SSL_CTX *SSL_CTX_new(SSL_METHOD *); %typemap(out) SSL_CTX *; %rename(ssl_ctx_free) SSL_CTX_free; extern void SSL_CTX_free(SSL_CTX *); %rename(ssl_ctx_set_verify_depth) SSL_CTX_set_verify_depth; extern void SSL_CTX_set_verify_depth(SSL_CTX *, int); %rename(ssl_ctx_get_verify_depth) SSL_CTX_get_verify_depth; extern int SSL_CTX_get_verify_depth(const SSL_CTX *); %rename(ssl_ctx_get_verify_mode) SSL_CTX_get_verify_mode; extern int SSL_CTX_get_verify_mode(const SSL_CTX *); %rename(ssl_ctx_set_cipher_list) SSL_CTX_set_cipher_list; extern int SSL_CTX_set_cipher_list(SSL_CTX *, const char *); %rename(ssl_ctx_add_session) SSL_CTX_add_session; extern int SSL_CTX_add_session(SSL_CTX *, SSL_SESSION *); %rename(ssl_ctx_remove_session) SSL_CTX_remove_session; extern int SSL_CTX_remove_session(SSL_CTX *, SSL_SESSION *); %rename(ssl_ctx_set_session_timeout) SSL_CTX_set_timeout; extern long SSL_CTX_set_timeout(SSL_CTX *, long); %rename(ssl_ctx_get_session_timeout) SSL_CTX_get_timeout; extern long SSL_CTX_get_timeout(const SSL_CTX *); %rename(ssl_ctx_get_cert_store) SSL_CTX_get_cert_store; extern X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *); %rename(ssl_ctx_set_default_verify_paths) SSL_CTX_set_default_verify_paths; extern int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); %rename(ssl_get_ex_data_x509_store_ctx_idx) SSL_get_ex_data_X509_STORE_CTX_idx; extern int SSL_get_ex_data_X509_STORE_CTX_idx(void); %rename(bio_new_ssl) BIO_new_ssl; extern BIO *BIO_new_ssl(SSL_CTX *, int); %rename(ssl_new) SSL_new; extern SSL *SSL_new(SSL_CTX *); %rename(ssl_free) SSL_free; %threadallow SSL_free; extern void SSL_free(SSL *); %rename(ssl_dup) SSL_dup; extern SSL *SSL_dup(SSL *); %rename(ssl_set_bio) SSL_set_bio; extern void SSL_set_bio(SSL *, BIO *, BIO *); %rename(ssl_set_accept_state) SSL_set_accept_state; extern void SSL_set_accept_state(SSL *); %rename(ssl_set_connect_state) SSL_set_connect_state; extern void SSL_set_connect_state(SSL *); %rename(ssl_get_shutdown) SSL_get_shutdown; extern int SSL_get_shutdown(const SSL *); %rename(ssl_set_shutdown) SSL_set_shutdown; extern void SSL_set_shutdown(SSL *, int); %rename(ssl_shutdown) SSL_shutdown; %threadallow SSL_shutdown; extern int SSL_shutdown(SSL *); %rename(ssl_clear) SSL_clear; extern int SSL_clear(SSL *); %rename(ssl_do_handshake) SSL_do_handshake; %threadallow SSL_do_handshake; extern int SSL_do_handshake(SSL *); %rename(ssl_renegotiate) SSL_renegotiate; %threadallow SSL_renegotiate; extern int SSL_renegotiate(SSL *); %rename(ssl_pending) SSL_pending; extern int SSL_pending(const SSL *); %rename(ssl_get_peer_cert) SSL_get_peer_certificate; extern X509 *SSL_get_peer_certificate(const SSL *); %rename(ssl_get_current_cipher) SSL_get_current_cipher; extern SSL_CIPHER *SSL_get_current_cipher(const SSL *); %rename(ssl_get_verify_mode) SSL_get_verify_mode; extern int SSL_get_verify_mode(const SSL *); %rename(ssl_get_verify_depth) SSL_get_verify_depth; extern int SSL_get_verify_depth(const SSL *); %rename(ssl_get_verify_result) SSL_get_verify_result; extern long SSL_get_verify_result(const SSL *); %rename(ssl_get_ssl_ctx) SSL_get_SSL_CTX; extern SSL_CTX *SSL_get_SSL_CTX(const SSL *); %rename(ssl_get_default_session_timeout) SSL_get_default_timeout; extern long SSL_get_default_timeout(const SSL *); %rename(ssl_set_cipher_list) SSL_set_cipher_list; extern int SSL_set_cipher_list(SSL *, const char *); %rename(ssl_get_cipher_list) SSL_get_cipher_list; extern const char *SSL_get_cipher_list(const SSL *, int); %rename(ssl_cipher_get_name) SSL_CIPHER_get_name; extern const char *SSL_CIPHER_get_name(const SSL_CIPHER *); %rename(ssl_cipher_get_version) SSL_CIPHER_get_version; extern char *SSL_CIPHER_get_version(const SSL_CIPHER *); %rename(ssl_get_session) SSL_get_session; extern SSL_SESSION *SSL_get_session(const SSL *); %rename(ssl_get1_session) SSL_get1_session; extern SSL_SESSION *SSL_get1_session(SSL *); %rename(ssl_set_session) SSL_set_session; extern int SSL_set_session(SSL *, SSL_SESSION *); %rename(ssl_session_free) SSL_SESSION_free; extern void SSL_SESSION_free(SSL_SESSION *); %rename(ssl_session_print) SSL_SESSION_print; %threadallow SSL_SESSION_print; extern int SSL_SESSION_print(BIO *, const SSL_SESSION *); %rename(ssl_session_set_timeout) SSL_SESSION_set_timeout; extern long SSL_SESSION_set_timeout(SSL_SESSION *, long); %rename(ssl_session_get_timeout) SSL_SESSION_get_timeout; extern long SSL_SESSION_get_timeout(const SSL_SESSION *); extern PyObject *ssl_accept(SSL *ssl, double timeout = -1); extern PyObject *ssl_connect(SSL *ssl, double timeout = -1); extern PyObject *ssl_read(SSL *ssl, int num, double timeout = -1); extern int ssl_write(SSL *ssl, PyObject *blob, double timeout = -1); %constant int ssl_error_none = SSL_ERROR_NONE; %constant int ssl_error_ssl = SSL_ERROR_SSL; %constant int ssl_error_want_read = SSL_ERROR_WANT_READ; %constant int ssl_error_want_write = SSL_ERROR_WANT_WRITE; %constant int ssl_error_want_x509_lookup = SSL_ERROR_WANT_X509_LOOKUP; %constant int ssl_error_syscall = SSL_ERROR_SYSCALL; %constant int ssl_error_zero_return = SSL_ERROR_ZERO_RETURN; %constant int ssl_error_want_connect = SSL_ERROR_WANT_CONNECT; %constant int SSL_VERIFY_NONE = 0x00; %constant int SSL_VERIFY_PEER = 0x01; %constant int SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 0x02; %constant int SSL_VERIFY_CLIENT_ONCE = 0x04; %constant int VERIFY_CRL_CHECK_LEAF = X509_V_FLAG_CRL_CHECK; %constant int VERIFY_CRL_CHECK_CHAIN = X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL; %constant int SSL_ST_CONNECT = 0x1000; %constant int SSL_ST_ACCEPT = 0x2000; %constant int SSL_ST_MASK = 0x0FFF; %constant int SSL_ST_INIT = (SSL_ST_CONNECT|SSL_ST_ACCEPT); %constant int SSL_ST_BEFORE = 0x4000; %constant int SSL_ST_OK = 0x03; /* SWIG 3.0.1 complains about the next line -- simplified declaration for now */ /*%constant int SSL_ST_RENEGOTIATE = (0x04|SSL_ST_INIT);*/ %constant int SSL_ST_RENEGOTIATE = (0x04|SSL_ST_CONNECT|SSL_ST_ACCEPT); %constant int SSL_CB_LOOP = 0x01; %constant int SSL_CB_EXIT = 0x02; %constant int SSL_CB_READ = 0x04; %constant int SSL_CB_WRITE = 0x08; %constant int SSL_CB_ALERT = 0x4000; /* used in callback */ %constant int SSL_CB_READ_ALERT = (SSL_CB_ALERT|SSL_CB_READ); %constant int SSL_CB_WRITE_ALERT = (SSL_CB_ALERT|SSL_CB_WRITE); %constant int SSL_CB_ACCEPT_LOOP = (SSL_ST_ACCEPT|SSL_CB_LOOP); %constant int SSL_CB_ACCEPT_EXIT = (SSL_ST_ACCEPT|SSL_CB_EXIT); %constant int SSL_CB_CONNECT_LOOP = (SSL_ST_CONNECT|SSL_CB_LOOP); %constant int SSL_CB_CONNECT_EXIT = (SSL_ST_CONNECT|SSL_CB_EXIT); %constant int SSL_CB_HANDSHAKE_START = 0x10; %constant int SSL_CB_HANDSHAKE_DONE = 0x20; %constant int SSL_SENT_SHUTDOWN = 1; %constant int SSL_RECEIVED_SHUTDOWN = 2; %constant int SSL_SESS_CACHE_OFF = 0x000; %constant int SSL_SESS_CACHE_CLIENT = 0x001; %constant int SSL_SESS_CACHE_SERVER = 0x002; %constant int SSL_SESS_CACHE_BOTH = (SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_SERVER); %constant int SSL_OP_ALL = 0x00000FFFL; %constant int SSL_OP_NO_SSLv2 = 0x01000000L; %constant int SSL_OP_NO_SSLv3 = 0x02000000L; %constant int SSL_OP_NO_TLSv1 = 0x04000000L; %constant int SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 0x00000800L; %constant int SSL_MODE_ENABLE_PARTIAL_WRITE = SSL_MODE_ENABLE_PARTIAL_WRITE; %constant int SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER = SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; %constant int SSL_MODE_AUTO_RETRY = SSL_MODE_AUTO_RETRY; %ignore ssl_handle_error; %ignore ssl_sleep_with_timeout; %warnfilter(454) _ssl_err; %warnfilter(454) _ssl_timeout_err; %inline %{ static PyObject *_ssl_err; static PyObject *_ssl_timeout_err; void ssl_init(PyObject *ssl_err, PyObject *ssl_timeout_err) { SSL_library_init(); SSL_load_error_strings(); Py_INCREF(ssl_err); Py_INCREF(ssl_timeout_err); _ssl_err = ssl_err; _ssl_timeout_err = ssl_timeout_err; } const SSL_METHOD *tlsv1_method(void) { #if OPENSSL_VERSION_NUMBER >= 0x10100000L PyErr_WarnEx(PyExc_DeprecationWarning, "Function TLSv1_method has been deprecated.", 1); #endif return TLSv1_method(); } void ssl_ctx_passphrase_callback(SSL_CTX *ctx, PyObject *pyfunc) { SSL_CTX_set_default_passwd_cb(ctx, passphrase_callback); SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *)pyfunc); Py_INCREF(pyfunc); } int ssl_ctx_use_x509(SSL_CTX *ctx, X509 *x) { int i; if (!(i = SSL_CTX_use_certificate(ctx, x))) { m2_PyErr_Msg(_ssl_err); return -1; } return i; } int ssl_ctx_use_cert(SSL_CTX *ctx, char *file) { int i; if (!(i = SSL_CTX_use_certificate_file(ctx, file, SSL_FILETYPE_PEM))) { m2_PyErr_Msg(_ssl_err); return -1; } return i; } int ssl_ctx_use_cert_chain(SSL_CTX *ctx, char *file) { int i; if (!(i = SSL_CTX_use_certificate_chain_file(ctx, file))) { m2_PyErr_Msg(_ssl_err); return -1; } return i; } int ssl_ctx_use_privkey(SSL_CTX *ctx, char *file) { int i; if (!(i = SSL_CTX_use_PrivateKey_file(ctx, file, SSL_FILETYPE_PEM))) { m2_PyErr_Msg(_ssl_err); return -1; } return i; } int ssl_ctx_use_rsa_privkey(SSL_CTX *ctx, RSA *rsakey) { int i; if (!(i = SSL_CTX_use_RSAPrivateKey(ctx, rsakey))) { m2_PyErr_Msg(_ssl_err); return -1; } return i; } int ssl_ctx_use_pkey_privkey(SSL_CTX *ctx, EVP_PKEY *pkey) { int i; if (!(i = SSL_CTX_use_PrivateKey(ctx, pkey))) { m2_PyErr_Msg(_ssl_err); return -1; } return i; } int ssl_ctx_check_privkey(SSL_CTX *ctx) { int ret; if (!(ret = SSL_CTX_check_private_key(ctx))) { m2_PyErr_Msg(_ssl_err); return -1; } return ret; } void ssl_ctx_set_client_CA_list_from_file(SSL_CTX *ctx, const char *ca_file) { SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(ca_file)); } void ssl_ctx_set_verify_default(SSL_CTX *ctx, int mode) { SSL_CTX_set_verify(ctx, mode, NULL); } void ssl_ctx_set_verify(SSL_CTX *ctx, int mode, PyObject *pyfunc) { Py_XDECREF(ssl_verify_cb_func); Py_INCREF(pyfunc); ssl_verify_cb_func = pyfunc; SSL_CTX_set_verify(ctx, mode, ssl_verify_callback); } int ssl_ctx_set_session_id_context(SSL_CTX *ctx, PyObject *sid_ctx) { const void *buf = NULL; int len = 0; if (m2_PyObject_AsReadBufferInt(sid_ctx, &buf, &len) == -1) return -1; return SSL_CTX_set_session_id_context(ctx, buf, len); } void ssl_ctx_set_info_callback(SSL_CTX *ctx, PyObject *pyfunc) { Py_XDECREF(ssl_info_cb_func); Py_INCREF(pyfunc); ssl_info_cb_func = pyfunc; SSL_CTX_set_info_callback(ctx, ssl_info_callback); } long ssl_ctx_set_tmp_dh(SSL_CTX *ctx, DH* dh) { return SSL_CTX_set_tmp_dh(ctx, dh); } void ssl_ctx_set_tmp_dh_callback(SSL_CTX *ctx, PyObject *pyfunc) { Py_XDECREF(ssl_set_tmp_dh_cb_func); Py_INCREF(pyfunc); ssl_set_tmp_dh_cb_func = pyfunc; SSL_CTX_set_tmp_dh_callback(ctx, ssl_set_tmp_dh_callback); } long ssl_ctx_set_tmp_rsa(SSL_CTX *ctx, RSA* rsa) { return SSL_CTX_set_tmp_rsa(ctx, rsa); } void ssl_ctx_set_tmp_rsa_callback(SSL_CTX *ctx, PyObject *pyfunc) { Py_XDECREF(ssl_set_tmp_rsa_cb_func); Py_INCREF(pyfunc); ssl_set_tmp_rsa_cb_func = pyfunc; SSL_CTX_set_tmp_rsa_callback(ctx, ssl_set_tmp_rsa_callback); } int ssl_ctx_load_verify_locations(SSL_CTX *ctx, const char *cafile, const char *capath) { return SSL_CTX_load_verify_locations(ctx, cafile, capath); } /* SSL_CTX_set_options is a macro. */ long ssl_ctx_set_options(SSL_CTX *ctx, long op) { return SSL_CTX_set_options(ctx, op); } int bio_set_ssl(BIO *bio, SSL *ssl, int flag) { SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); return BIO_ctrl(bio, BIO_C_SET_SSL, flag, (char *)ssl); } long ssl_set_mode(SSL *ssl, long mode) { return SSL_set_mode(ssl, mode); } long ssl_get_mode(SSL *ssl) { return SSL_get_mode(ssl); } int ssl_set_tlsext_host_name(SSL *ssl, const char *name) { long l; if (!(l = SSL_set_tlsext_host_name(ssl, name))) { m2_PyErr_Msg(_ssl_err); return -1; } /* Return an "int" to match the 'typemap(out) int' in _lib.i */ return 1; } void ssl_set_client_CA_list_from_file(SSL *ssl, const char *ca_file) { SSL_set_client_CA_list(ssl, SSL_load_client_CA_file(ca_file)); } void ssl_set_client_CA_list_from_context(SSL *ssl, SSL_CTX *ctx) { SSL_set_client_CA_list(ssl, SSL_CTX_get_client_CA_list(ctx)); } int ssl_set_session_id_context(SSL *ssl, PyObject *sid_ctx) { const void *buf = NULL; int len = 0; if (m2_PyObject_AsReadBufferInt(sid_ctx, &buf, &len) == -1) return -1; return SSL_set_session_id_context(ssl, buf, len); } int ssl_set_fd(SSL *ssl, int fd) { int ret; if (!(ret = SSL_set_fd(ssl, fd))) { m2_PyErr_Msg(_ssl_err); return -1; } return ret; } static void ssl_handle_error(int ssl_err, int ret) { int err; switch (ssl_err) { case SSL_ERROR_SSL: PyErr_SetString(_ssl_err, ERR_reason_error_string(ERR_get_error())); break; case SSL_ERROR_SYSCALL: err = ERR_get_error(); if (err) PyErr_SetString(_ssl_err, ERR_reason_error_string(err)); else if (ret == 0) PyErr_SetString(_ssl_err, "unexpected eof"); else if (ret == -1) PyErr_SetFromErrno(_ssl_err); else assert(0); break; default: PyErr_SetString(_ssl_err, "unexpected SSL error"); } } #ifdef _WIN32 /* http://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows */ int gettimeofday(struct timeval *tp, void *tzp) { // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); SYSTEMTIME system_time; FILETIME file_time; uint64_t time; GetSystemTime( &system_time ); SystemTimeToFileTime( &system_time, &file_time ); time = ((uint64_t)file_time.dwLowDateTime ) ; time += ((uint64_t)file_time.dwHighDateTime) << 32; tp->tv_sec = (long) ((time - EPOCH) / 10000000L); tp->tv_usec = (long) (system_time.wMilliseconds * 1000); return 0; } #endif static int ssl_sleep_with_timeout(SSL *ssl, const struct timeval *start, double timeout, int ssl_err) { #ifdef _WIN32 WSAPOLLFD fd; #else struct pollfd fd; #endif struct timeval tv; int ms, tmp; assert(timeout > 0); again: gettimeofday(&tv, NULL); /* tv >= start */ if ((timeout + start->tv_sec - tv.tv_sec) > INT_MAX / 1000) ms = -1; else { int fract; ms = ((start->tv_sec + (int)timeout) - tv.tv_sec) * 1000; fract = (int)((start->tv_usec + (timeout - (int)timeout) * 1000000 - tv.tv_usec + 999) / 1000); if (ms > 0 && fract > INT_MAX - ms) ms = -1; else { ms += fract; if (ms <= 0) goto timeout; } } switch (ssl_err) { case SSL_ERROR_WANT_READ: fd.fd = SSL_get_rfd(ssl); fd.events = POLLIN; break; case SSL_ERROR_WANT_WRITE: fd.fd = SSL_get_wfd(ssl); fd.events = POLLOUT; break; case SSL_ERROR_WANT_X509_LOOKUP: return 0; /* FIXME: is this correct? */ default: assert(0); } if (fd.fd == -1) { PyErr_SetString(_ssl_err, "timeout on a non-FD SSL"); return -1; } Py_BEGIN_ALLOW_THREADS #ifdef _WIN32 tmp = WSAPoll(&fd, 1, ms); #else tmp = poll(&fd, 1, ms); #endif Py_END_ALLOW_THREADS switch (tmp) { case 1: return 0; case 0: goto timeout; case -1: #ifdef _WIN32 if (WSAGetLastError() == EINTR) #else if (errno == EINTR) #endif goto again; PyErr_SetFromErrno(_ssl_err); return -1; } return 0; timeout: PyErr_SetString(_ssl_timeout_err, "timed out"); return -1; } PyObject *ssl_accept(SSL *ssl, double timeout) { PyObject *obj = NULL; int r, ssl_err; struct timeval tv; if (timeout > 0) gettimeofday(&tv, NULL); again: Py_BEGIN_ALLOW_THREADS r = SSL_accept(ssl); ssl_err = SSL_get_error(ssl, r); Py_END_ALLOW_THREADS switch (ssl_err) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: obj = PyLong_FromLong((long)1); break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: if (timeout <= 0) { obj = PyLong_FromLong((long)0); break; } if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) goto again; obj = NULL; break; case SSL_ERROR_SSL: case SSL_ERROR_SYSCALL: ssl_handle_error(ssl_err, r); obj = NULL; break; } return obj; } PyObject *ssl_connect(SSL *ssl, double timeout) { PyObject *obj = NULL; int r, ssl_err; struct timeval tv; if (timeout > 0) gettimeofday(&tv, NULL); again: Py_BEGIN_ALLOW_THREADS r = SSL_connect(ssl); ssl_err = SSL_get_error(ssl, r); Py_END_ALLOW_THREADS switch (ssl_err) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: obj = PyLong_FromLong((long)1); break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: if (timeout <= 0) { obj = PyLong_FromLong((long)0); break; } if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) goto again; obj = NULL; break; case SSL_ERROR_SSL: case SSL_ERROR_SYSCALL: ssl_handle_error(ssl_err, r); obj = NULL; break; } return obj; } void ssl_set_shutdown1(SSL *ssl, int mode) { SSL_set_shutdown(ssl, mode); } PyObject *ssl_read(SSL *ssl, int num, double timeout) { PyObject *obj = NULL; void *buf; int r; struct timeval tv; if (!(buf = PyMem_Malloc(num))) { PyErr_SetString(PyExc_MemoryError, "ssl_read"); return NULL; } if (timeout > 0) gettimeofday(&tv, NULL); again: Py_BEGIN_ALLOW_THREADS r = SSL_read(ssl, buf, num); Py_END_ALLOW_THREADS if (r >= 0) { buf = PyMem_Realloc(buf, r); obj = PyBytes_FromStringAndSize(buf, r); } else { int ssl_err; ssl_err = SSL_get_error(ssl, r); switch (ssl_err) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: assert(0); case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: if (timeout <= 0) { Py_INCREF(Py_None); obj = Py_None; break; } if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) goto again; obj = NULL; break; case SSL_ERROR_SSL: case SSL_ERROR_SYSCALL: ssl_handle_error(ssl_err, r); obj = NULL; break; } } PyMem_Free(buf); return obj; } PyObject *ssl_read_nbio(SSL *ssl, int num) { PyObject *obj = NULL; void *buf; int r, err; if (!(buf = PyMem_Malloc(num))) { PyErr_SetString(PyExc_MemoryError, "ssl_read"); return NULL; } Py_BEGIN_ALLOW_THREADS r = SSL_read(ssl, buf, num); Py_END_ALLOW_THREADS switch (SSL_get_error(ssl, r)) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: buf = PyMem_Realloc(buf, r); obj = PyBytes_FromStringAndSize(buf, r); break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: Py_INCREF(Py_None); obj = Py_None; break; case SSL_ERROR_SSL: m2_PyErr_Msg(_ssl_err); obj = NULL; break; case SSL_ERROR_SYSCALL: err = ERR_get_error(); if (err) PyErr_SetString(_ssl_err, ERR_reason_error_string(err)); else if (r == 0) PyErr_SetString(_ssl_err, "unexpected eof"); else if (r == -1) PyErr_SetFromErrno(_ssl_err); obj = NULL; break; } PyMem_Free(buf); return obj; } int ssl_write(SSL *ssl, PyObject *blob, double timeout) { Py_buffer buf; int r, ssl_err, ret; struct timeval tv; if (m2_PyObject_GetBufferInt(blob, &buf, PyBUF_CONTIG_RO) == -1) { return -1; } if (timeout > 0) gettimeofday(&tv, NULL); again: Py_BEGIN_ALLOW_THREADS r = SSL_write(ssl, buf.buf, buf.len); ssl_err = SSL_get_error(ssl, r); Py_END_ALLOW_THREADS switch (ssl_err) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: ret = r; break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: if (timeout <= 0) { ret = -1; break; } if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) goto again; ret = -1; break; case SSL_ERROR_SSL: case SSL_ERROR_SYSCALL: ssl_handle_error(ssl_err, r); default: ret = -1; } m2_PyBuffer_Release(blob, &buf); return ret; } int ssl_write_nbio(SSL *ssl, PyObject *blob) { Py_buffer buf; int r, err, ret; if (m2_PyObject_GetBufferInt(blob, &buf, PyBUF_CONTIG_RO) == -1) { return -1; } Py_BEGIN_ALLOW_THREADS r = SSL_write(ssl, buf.buf, buf.len); Py_END_ALLOW_THREADS switch (SSL_get_error(ssl, r)) { case SSL_ERROR_NONE: case SSL_ERROR_ZERO_RETURN: ret = r; break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: ret = -1; break; case SSL_ERROR_SSL: ret = -1; break; case SSL_ERROR_SYSCALL: err = ERR_get_error(); if (err) PyErr_SetString(_ssl_err, ERR_reason_error_string(err)); else if (r == 0) PyErr_SetString(_ssl_err, "unexpected eof"); else if (r == -1) PyErr_SetFromErrno(_ssl_err); default: ret = -1; } m2_PyBuffer_Release(blob, &buf); return ret; } int ssl_cipher_get_bits(SSL_CIPHER *c) { return SSL_CIPHER_get_bits(c, NULL); } int sk_ssl_cipher_num(STACK_OF(SSL_CIPHER) *stack) { return sk_SSL_CIPHER_num(stack); } const SSL_CIPHER *sk_ssl_cipher_value(STACK_OF(SSL_CIPHER) *stack, int idx) { return sk_SSL_CIPHER_value(stack, idx); } STACK_OF(X509) *ssl_get_peer_cert_chain(SSL *ssl) { return SSL_get_peer_cert_chain(ssl); } int sk_x509_num(STACK_OF(X509) *stack) { return sk_X509_num(stack); } X509 *sk_x509_value(STACK_OF(X509) *stack, int idx) { return sk_X509_value(stack, idx); } %} %threadallow i2d_ssl_session; %inline %{ void i2d_ssl_session(BIO *bio, SSL_SESSION *sess) { i2d_SSL_SESSION_bio(bio, sess); } %} %typemap(out) SSL_SESSION * { PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if ($1 != NULL) $result = SWIG_NewPointerObj($1, $1_descriptor, 0); else { m2_PyErr_Msg(_ssl_err); $result = NULL; } } %threadallow ssl_session_read_pem; %inline %{ SSL_SESSION *ssl_session_read_pem(BIO *bio) { return PEM_read_bio_SSL_SESSION(bio, NULL, NULL, NULL); } %} %typemap(out) SSL_SESSION * ; %threadallow ssl_session_write_pem; %inline %{ int ssl_session_write_pem(SSL_SESSION *sess, BIO *bio) { return PEM_write_bio_SSL_SESSION(bio, sess); } int ssl_ctx_set_session_cache_mode(SSL_CTX *ctx, int mode) { return SSL_CTX_set_session_cache_mode(ctx, mode); } int ssl_ctx_get_session_cache_mode(SSL_CTX *ctx) { return SSL_CTX_get_session_cache_mode(ctx); } static long ssl_ctx_set_cache_size(SSL_CTX *ctx, long arg) { return SSL_CTX_sess_set_cache_size(ctx, arg); } int ssl_is_init_finished(SSL *ssl) { return SSL_is_init_finished(ssl); } %} m2crypto-0.42.0/src/SWIG/_threads.i000066400000000000000000000034231465575656700167130ustar00rootroot00000000000000/* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. */ /* $Id$ */ %{ #include #include #if defined(THREADING) && OPENSSL_VERSION_NUMBER < 0x10100000L #define CRYPTO_num_locks() (CRYPTO_NUM_LOCKS) static PyThread_type_lock lock_cs[CRYPTO_num_locks()]; static long lock_count[CRYPTO_num_locks()]; static int thread_mode = 0; #endif void threading_locking_callback(int mode, int type, const char *file, int line) { #if defined(THREADING) && OPENSSL_VERSION_NUMBER < 0x10100000L if (mode & CRYPTO_LOCK) { PyThread_acquire_lock(lock_cs[type], WAIT_LOCK); lock_count[type]++; } else { PyThread_release_lock(lock_cs[type]); lock_count[type]--; } #endif } unsigned long threading_id_callback(void) { #if defined(THREADING) && OPENSSL_VERSION_NUMBER < 0x10100000L return (unsigned long)PyThread_get_thread_ident(); #else return (unsigned long)0; #endif } %} %inline %{ void threading_init(void) { #if defined(THREADING) && OPENSSL_VERSION_NUMBER < 0x10100000L int i; if (!thread_mode) { for (i=0; i %} %warnfilter(454) _util_err; %inline %{ static PyObject *_util_err; void util_init(PyObject *util_err) { Py_INCREF(util_err); _util_err = util_err; } PyObject *util_hex_to_string(PyObject *blob) { PyObject *obj; const void *buf; char *ret; Py_ssize_t len; if (m2_PyObject_AsReadBuffer(blob, &buf, &len) == -1) return NULL; ret = hex_to_string((unsigned char *)buf, len); if (!ret) { m2_PyErr_Msg(_util_err); return NULL; } obj = PyBytes_FromString(ret); OPENSSL_free(ret); return obj; } PyObject *util_string_to_hex(PyObject *blob) { PyObject *obj; const void *buf; unsigned char *ret; Py_ssize_t len0; long len; if (m2_PyObject_AsReadBuffer(blob, &buf, &len0) == -1) return NULL; len = len0; ret = string_to_hex((char *)buf, &len); if (ret == NULL) { m2_PyErr_Msg(_util_err); return NULL; } obj = PyBytes_FromStringAndSize((char*)ret, len); OPENSSL_free(ret); return obj; } %} m2crypto-0.42.0/src/SWIG/_x509.i000066400000000000000000000660731465575656700160000ustar00rootroot00000000000000/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. */ /* ** Portions created by Open Source Applications Foundation (OSAF) are ** Copyright (C) 2004-2005 OSAF. All Rights Reserved. ** ** Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved. ** */ /* $Id$ */ %{ #include #include #include #include typedef STACK_OF(X509) SEQ_CERT; ASN1_ITEM_TEMPLATE(SEQ_CERT) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, SeqCert, X509) ASN1_ITEM_TEMPLATE_END(SEQ_CERT) IMPLEMENT_ASN1_FUNCTIONS(SEQ_CERT) %} %apply Pointer NONNULL { BIO * }; %apply Pointer NONNULL { X509 * }; %apply Pointer NONNULL { X509_CRL * }; %apply Pointer NONNULL { X509_REQ * }; %apply Pointer NONNULL { X509_NAME * }; %apply Pointer NONNULL { X509_NAME_ENTRY * }; %apply Pointer NONNULL { EVP_PKEY * }; #if OPENSSL_VERSION_NUMBER >= 0x0090800fL %rename(x509_check_ca) X509_check_ca; extern int X509_check_ca(X509 *); #endif %rename(x509_new) X509_new; extern X509 *X509_new( void ); %rename(x509_dup) X509_dup; extern X509 *X509_dup(X509 *); %rename(x509_free) X509_free; extern void X509_free(X509 *); %rename(x509_crl_free) X509_CRL_free; extern void X509_CRL_free(X509_CRL *); %rename(x509_crl_new) X509_CRL_new; extern X509_CRL * X509_CRL_new(); %rename(x509_print) X509_print; %threadallow X509_print; extern int X509_print(BIO *, X509 *); %rename(x509_crl_print) X509_CRL_print; %threadallow X509_CRL_print; extern int X509_CRL_print(BIO *, X509_CRL *); %rename(x509_get_serial_number) X509_get_serialNumber; extern ASN1_INTEGER *X509_get_serialNumber(X509 *); %rename(x509_set_serial_number) X509_set_serialNumber; extern int X509_set_serialNumber(X509 *, ASN1_INTEGER *); %rename(x509_get_pubkey) X509_get_pubkey; extern EVP_PKEY *X509_get_pubkey(X509 *); %rename(x509_set_pubkey) X509_set_pubkey; extern int X509_set_pubkey(X509 *, EVP_PKEY *); %rename(x509_get_issuer_name) X509_get_issuer_name; extern X509_NAME *X509_get_issuer_name(X509 *); %rename(x509_set_issuer_name) X509_set_issuer_name; extern int X509_set_issuer_name(X509 *, X509_NAME *); %rename(x509_get_subject_name) X509_get_subject_name; extern X509_NAME *X509_get_subject_name(X509 *); %rename(x509_set_subject_name) X509_set_subject_name; extern int X509_set_subject_name(X509 *, X509_NAME *); %rename(x509_cmp_current_time) X509_cmp_current_time; extern int X509_cmp_current_time(ASN1_TIME *); /* From x509.h */ /* standard trust ids */ %constant int X509_TRUST_DEFAULT = -1; %constant int X509_TRUST_COMPAT = 1; %constant int X509_TRUST_SSL_CLIENT = 2; %constant int X509_TRUST_SSL_SERVER = 3; %constant int X509_TRUST_EMAIL = 4; %constant int X509_TRUST_OBJECT_SIGN = 5; %constant int X509_TRUST_OCSP_SIGN = 6; %constant int X509_TRUST_OCSP_REQUEST = 7; /* trust_flags values */ %constant int X509_TRUST_DYNAMIC = 1; %constant int X509_TRUST_DYNAMIC_NAME = 2; /* check_trust return codes */ %constant int X509_TRUST_TRUSTED = 1; %constant int X509_TRUST_REJECTED = 2; %constant int X509_TRUST_UNTRUSTED = 3; /* From x509v3.h */ %constant int X509_PURPOSE_SSL_CLIENT = 1; %constant int X509_PURPOSE_SSL_SERVER = 2; %constant int X509_PURPOSE_NS_SSL_SERVER = 3; %constant int X509_PURPOSE_SMIME_SIGN = 4; %constant int X509_PURPOSE_SMIME_ENCRYPT = 5; %constant int X509_PURPOSE_CRL_SIGN = 6; %constant int X509_PURPOSE_ANY = 7; %constant int X509_PURPOSE_OCSP_HELPER = 8; %rename(x509_check_purpose) X509_check_purpose; extern int X509_check_purpose(X509 *, int, int); %rename(x509_check_trust) X509_check_trust; extern int X509_check_trust(X509 *, int, int); %rename(x509_write_pem) PEM_write_bio_X509; %threadallow PEM_write_bio_X509; extern int PEM_write_bio_X509(BIO *, X509 *); %rename(x509_write_pem_file) PEM_write_X509; extern int PEM_write_X509(FILE *, X509 *); %rename(x509_verify) X509_verify; extern int X509_verify(X509 *a, EVP_PKEY *r); %rename(x509_verify_cert) X509_verify_cert; extern int X509_verify_cert(X509_STORE_CTX *ctx); %rename(x509_get_verify_error) X509_verify_cert_error_string; extern const char *X509_verify_cert_error_string(long); %constant long X509V3_EXT_UNKNOWN_MASK = (0xfL << 16); %constant long X509V3_EXT_DEFAULT = 0; %constant long X509V3_EXT_ERROR_UNKNOWN = (1L << 16); %constant long X509V3_EXT_PARSE_UNKNOWN = (2L << 16); %constant long X509V3_EXT_DUMP_UNKNOWN = (3L << 16); %rename(x509_add_ext) X509_add_ext; extern int X509_add_ext(X509 *, X509_EXTENSION *, int); %rename(x509_get_ext_count) X509_get_ext_count; extern int X509_get_ext_count(X509 *); %rename(x509_get_ext) X509_get_ext; extern X509_EXTENSION *X509_get_ext(X509 *, int); %rename(x509_ext_print) X509V3_EXT_print; %threadallow X509V3_EXT_print; extern int X509V3_EXT_print(BIO *, X509_EXTENSION *, unsigned long, int); %rename(x509_name_new) X509_NAME_new; extern X509_NAME *X509_NAME_new( void ); %rename(x509_name_free) X509_NAME_free; extern void X509_NAME_free(X509_NAME *); %rename(x509_name_print) X509_NAME_print; %threadallow X509_NAME_print; extern int X509_NAME_print(BIO *, X509_NAME *, int); %rename(x509_name_get_entry) X509_NAME_get_entry; extern X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *, int); %rename(x509_name_entry_count) X509_NAME_entry_count; extern int X509_NAME_entry_count(X509_NAME *); %rename(x509_name_delete_entry) X509_NAME_delete_entry; extern X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *, int); %rename(x509_name_add_entry) X509_NAME_add_entry; extern int X509_NAME_add_entry(X509_NAME *, X509_NAME_ENTRY *, int, int); %rename(x509_name_add_entry_by_obj) X509_NAME_add_entry_by_OBJ; extern int X509_NAME_add_entry_by_OBJ(X509_NAME *, ASN1_OBJECT *, int, unsigned char *, int, int, int ); %rename(x509_name_add_entry_by_nid) X509_NAME_add_entry_by_NID; extern int X509_NAME_add_entry_by_NID(X509_NAME *, int, int, unsigned char *, int, int, int ); %rename(x509_name_print_ex) X509_NAME_print_ex; %threadallow X509_NAME_print_ex; extern int X509_NAME_print_ex(BIO *, X509_NAME *, int, unsigned long); #if OPENSSL_VERSION_NUMBER >= 0x10000000L %rename(x509_name_hash) X509_NAME_hash_old; extern unsigned long X509_NAME_hash_old(X509_NAME *); #else %rename(x509_name_hash) X509_NAME_hash; extern unsigned long X509_NAME_hash(X509_NAME *); #endif %rename(x509_name_get_index_by_nid) X509_NAME_get_index_by_NID; extern int X509_NAME_get_index_by_NID(X509_NAME *, int, int); %rename(x509_name_entry_new) X509_NAME_ENTRY_new; extern X509_NAME_ENTRY *X509_NAME_ENTRY_new( void ); %rename(x509_name_entry_free) X509_NAME_ENTRY_free; extern void X509_NAME_ENTRY_free( X509_NAME_ENTRY *); /*XXX This is probably bogus:*/ %rename(x509_name_entry_create_by_nid) X509_NAME_ENTRY_create_by_NID; extern X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID( X509_NAME_ENTRY **, int, int, unsigned char *, int); %rename(x509_name_entry_set_object) X509_NAME_ENTRY_set_object; extern int X509_NAME_ENTRY_set_object( X509_NAME_ENTRY *, ASN1_OBJECT *); %rename(x509_name_entry_get_object) X509_NAME_ENTRY_get_object; extern ASN1_OBJECT *X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *); %rename(x509_name_entry_get_data) X509_NAME_ENTRY_get_data; extern ASN1_STRING *X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *); %typemap(in) (const unsigned char *, int) { #if PY_MAJOR_VERSION >= 3 if (PyBytes_Check($input)) { Py_ssize_t len; $1 = PyBytes_AsString($input); len = PyBytes_Size($input); #else if (PyString_Check($input)) { Py_ssize_t len; $1 = (unsigned char *)PyString_AsString($input); len = PyString_Size($input); #endif // PY_MAJOR_VERSION >= 3 if (len > INT_MAX) { PyErr_SetString(_x509_err, "object too large"); return NULL; } $2 = len; } else { PyErr_SetString(PyExc_TypeError, "expected string"); return NULL; } } %rename(x509_name_entry_set_data) X509_NAME_ENTRY_set_data; extern int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *, int, const unsigned char *, int); %typemap(in) (const unsigned char *, int); %rename(x509_req_new) X509_REQ_new; extern X509_REQ * X509_REQ_new(); %rename(x509_req_free) X509_REQ_free; extern void X509_REQ_free(X509_REQ *); %rename(x509_req_print) X509_REQ_print; %threadallow X509_REQ_print; extern int X509_REQ_print(BIO *, X509_REQ *); %rename(x509_req_get_pubkey) X509_REQ_get_pubkey; extern EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *); %rename(x509_req_set_pubkey) X509_REQ_set_pubkey; extern int X509_REQ_set_pubkey(X509_REQ *, EVP_PKEY *); %rename(x509_req_set_subject_name) X509_REQ_set_subject_name; extern int X509_REQ_set_subject_name(X509_REQ *, X509_NAME *); %rename(x509_req_verify) X509_REQ_verify; extern int X509_REQ_verify(X509_REQ *, EVP_PKEY *); %rename(x509_req_sign) X509_REQ_sign; extern int X509_REQ_sign(X509_REQ *, EVP_PKEY *, const EVP_MD *); %rename(i2d_x509_bio) i2d_X509_bio; %threadallow i2d_X509_bio; extern int i2d_X509_bio(BIO *, X509 *); %rename(i2d_x509_req_bio) i2d_X509_REQ_bio; %threadallow i2d_X509_REQ_bio; extern int i2d_X509_REQ_bio(BIO *, X509_REQ *); %rename(x509_store_new) X509_STORE_new; extern X509_STORE *X509_STORE_new(void); %rename(x509_store_free) X509_STORE_free; extern void X509_STORE_free(X509_STORE *); %rename(x509_store_add_cert) X509_STORE_add_cert; extern int X509_STORE_add_cert(X509_STORE *, X509 *); %rename(x509_store_set_verify_cb) X509_STORE_set_verify_cb; extern void X509_STORE_set_verify_cb(X509_STORE *st, int (*verify_cb)(int ok, X509_STORE_CTX *ctx)); %rename(x509_store_ctx_get_current_cert) X509_STORE_CTX_get_current_cert; extern X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *); %rename(x509_store_ctx_get_error) X509_STORE_CTX_get_error; extern int X509_STORE_CTX_get_error(X509_STORE_CTX *); %rename(x509_store_ctx_get_error_depth) X509_STORE_CTX_get_error_depth; extern int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *); %rename(x509_store_ctx_free) X509_STORE_CTX_free; extern void X509_STORE_CTX_free(X509_STORE_CTX *); %rename(x509_store_ctx_get1_chain) X509_STORE_CTX_get1_chain; extern STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *); %rename(x509_extension_get_critical) X509_EXTENSION_get_critical; extern int X509_EXTENSION_get_critical(X509_EXTENSION *); %rename(x509_extension_set_critical) X509_EXTENSION_set_critical; extern int X509_EXTENSION_set_critical(X509_EXTENSION *, int); %rename(x509_store_set_flags) X509_STORE_set_flags; extern int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags); %typemap(out) X509 * { PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if ($1 != NULL) $result = SWIG_NewPointerObj($1, $1_descriptor, 0); else { m2_PyErr_Msg(_x509_err); $result = NULL; } } /* Functions using m2_PyErr_Msg and thus using internal Python C API are * not thread safe, so if we want to have %threadallow here, error * handling must be done outside of these internal functions. */ %threadallow x509_read_pem; %inline %{ X509 *x509_read_pem(BIO *bio) { return PEM_read_bio_X509(bio, NULL, NULL, NULL); } %} %threadallow d2i_x509; %inline %{ X509 *d2i_x509(BIO *bio) { return d2i_X509_bio(bio, NULL); } %} %typemap(out) X509 *; %constant int NID_commonName = 13; %constant int NID_countryName = 14; %constant int NID_localityName = 15; %constant int NID_stateOrProvinceName = 16; %constant int NID_organizationName = 17; %constant int NID_organizationalUnitName = 18; %constant int NID_serialNumber = 105; %constant int NID_surname = 100; %constant int NID_givenName = 99; %constant int NID_pkcs9_emailAddress = 48; /* Cribbed from x509_vfy.h. */ %constant int X509_V_OK = 0; %constant int X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT = 2; %constant int X509_V_ERR_UNABLE_TO_GET_CRL = 3; %constant int X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE = 4; %constant int X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE = 5; %constant int X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY = 6; %constant int X509_V_ERR_CERT_SIGNATURE_FAILURE = 7; %constant int X509_V_ERR_CRL_SIGNATURE_FAILURE = 8; %constant int X509_V_ERR_CERT_NOT_YET_VALID = 9; %constant int X509_V_ERR_CERT_HAS_EXPIRED = 10; %constant int X509_V_ERR_CRL_NOT_YET_VALID = 11; %constant int X509_V_ERR_CRL_HAS_EXPIRED = 12; %constant int X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD = 13; %constant int X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD = 14; %constant int X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD = 15; %constant int X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD = 16; %constant int X509_V_ERR_OUT_OF_MEM = 17; %constant int X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT = 18; %constant int X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN = 19; %constant int X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY = 20; %constant int X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE = 21; %constant int X509_V_ERR_CERT_CHAIN_TOO_LONG = 22; %constant int X509_V_ERR_CERT_REVOKED = 23; %constant int X509_V_ERR_INVALID_CA = 24; %constant int X509_V_ERR_PATH_LENGTH_EXCEEDED = 25; %constant int X509_V_ERR_INVALID_PURPOSE = 26; %constant int X509_V_ERR_CERT_UNTRUSTED = 27; %constant int X509_V_ERR_CERT_REJECTED = 28; %constant int X509_V_ERR_APPLICATION_VERIFICATION = 50; /* See man page of X509_VERIFY_PARAM_set_flags for definition of all these flags */ #ifdef X509_V_FLAG_ALLOW_PROXY_CERTS %constant int VERIFY_ALLOW_PROXY_CERTS = X509_V_FLAG_ALLOW_PROXY_CERTS; #endif #ifdef X509_V_FLAG_CB_ISSUER_CHECK %constant int VERIFY_CB_ISSUER_CHECK = X509_V_FLAG_CB_ISSUER_CHECK; #endif #ifdef X509_V_FLAG_CHECK_SS_SIGNATURE %constant int VERIFY_CHECK_SS_SIGNATURE = X509_V_FLAG_CHECK_SS_SIGNATURE; #endif /* note: X509_V_FLAG_CRL_CHECK is already defined in _ssl.i as VERIFY_CRL_CHECK_LEAF However I add it here for consistency */ #ifdef X509_V_FLAG_CRL_CHECK %constant int VERIFY_CRL_CHECK = X509_V_FLAG_CRL_CHECK; #endif #ifdef X509_V_FLAG_CRL_CHECK_ALL %constant int VERIFY_CRL_CHECK_ALL = X509_V_FLAG_CRL_CHECK_ALL; #endif #ifdef X509_V_FLAG_EXPLICIT_POLICY %constant int VERIFY_EXPLICIT_POLICY = X509_V_FLAG_EXPLICIT_POLICY; #endif #ifdef X509_V_FLAG_EXTENDED_CRL_SUPPORT %constant int VERIFY_EXTENDED_CRL_SUPPORT = X509_V_FLAG_EXTENDED_CRL_SUPPORT; #endif #ifdef X509_V_FLAG_IGNORE_CRITICAL %constant int VERIFY_IGNORE_CRITICAL = X509_V_FLAG_IGNORE_CRITICAL; #endif #ifdef X509_V_FLAG_INHIBIT_ANY %constant int VERIFY_INHIBIT_ANY = X509_V_FLAG_INHIBIT_ANY; #endif #ifdef X509_V_FLAG_INHIBIT_MAP %constant int VERIFY_INHIBIT_MAP = X509_V_FLAG_INHIBIT_MAP; #endif #ifdef X509_V_FLAG_NO_ALT_CHAINS %constant int VERIFY_NO_ALT_CHAINS = X509_V_FLAG_NO_ALT_CHAINS; #endif #ifdef X509_V_FLAG_NO_CHECK_TIME %constant int VERIFY_NO_CHECK_TIME = X509_V_FLAG_NO_CHECK_TIME; #endif #ifdef X509_V_FLAG_NOTIFY_POLICY %constant int VERIFY_NOTIFY_POLICY = X509_V_FLAG_NOTIFY_POLICY; #endif #ifdef X509_V_FLAG_PARTIAL_CHAIN %constant int VERIFY_PARTIAL_CHAIN = X509_V_FLAG_PARTIAL_CHAIN; #endif #ifdef X509_V_FLAG_POLICY_CHECK %constant int VERIFY_POLICY_CHECK = X509_V_FLAG_POLICY_CHECK; #endif #ifdef X509_V_FLAG_TRUSTED_FIRST %constant int VERIFY_TRUSTED_FIRST = X509_V_FLAG_TRUSTED_FIRST; #endif #ifdef X509_V_FLAG_USE_DELTAS %constant int VERIFY_USE_DELTAS = X509_V_FLAG_USE_DELTAS; #endif #ifdef X509_V_FLAG_X509_STRICT %constant int VERIFY_X509_STRICT = X509_V_FLAG_X509_STRICT; #endif /* x509.h */ %constant int XN_FLAG_COMPAT = 0; %constant int XN_FLAG_SEP_COMMA_PLUS = (1 << 16); %constant int XN_FLAG_SEP_CPLUS_SPC = (2 << 16); %constant int XN_FLAG_SEP_MULTILINE = (4 << 16); %constant int XN_FLAG_DN_REV = (1 << 20); %constant int XN_FLAG_FN_LN = (1 << 21); %constant int XN_FLAG_SPC_EQ = (1 << 23); %constant int XN_FLAG_DUMP_UNKNOWN_FIELDS = (1 << 24); %constant int XN_FLAG_FN_ALIGN = (1 << 25); %constant int XN_FLAG_ONELINE =(ASN1_STRFLGS_RFC2253 | \ ASN1_STRFLGS_ESC_QUOTE | \ XN_FLAG_SEP_CPLUS_SPC | \ XN_FLAG_SPC_EQ); %constant int XN_FLAG_MULTILINE = (ASN1_STRFLGS_ESC_CTRL | \ ASN1_STRFLGS_ESC_MSB | \ XN_FLAG_SEP_MULTILINE | \ XN_FLAG_SPC_EQ | \ XN_FLAG_FN_LN | \ XN_FLAG_FN_ALIGN); %constant int XN_FLAG_RFC2253 = (ASN1_STRFLGS_RFC2253 | \ XN_FLAG_SEP_COMMA_PLUS | \ XN_FLAG_DN_REV | \ XN_FLAG_DUMP_UNKNOWN_FIELDS); /* Cribbed from rsa.h. */ %constant int RSA_3 = 0x3L; %constant int RSA_F4 = 0x10001L; %warnfilter(454) _x509_err; %inline %{ static PyObject *_x509_err; void x509_init(PyObject *x509_err) { Py_INCREF(x509_err); _x509_err = x509_err; } %} %typemap(out) X509_REQ * { PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if ($1 != NULL) $result = SWIG_NewPointerObj($1, $1_descriptor, 0); else { m2_PyErr_Msg(_x509_err); $result = NULL; } } %threadallow d2i_x509_req; %inline %{ X509_REQ *d2i_x509_req(BIO *bio) { return d2i_X509_REQ_bio(bio, NULL); } %} %threadallow x509_req_read_pem; %inline %{ X509_REQ *x509_req_read_pem(BIO *bio) { return PEM_read_bio_X509_REQ(bio, NULL, NULL, NULL); } %} %typemap(out) X509_REQ *; %inline %{ PyObject *i2d_x509(X509 *x) { int len; PyObject *ret = NULL; unsigned char *buf = NULL; len = i2d_X509(x, &buf); if (len < 0) { m2_PyErr_Msg(_x509_err); } else { ret = PyBytes_FromStringAndSize((char*)buf, len); OPENSSL_free(buf); } return ret; } %} %threadallow x509_req_write_pem; %inline %{ int x509_req_write_pem(BIO *bio, X509_REQ *x) { return PEM_write_bio_X509_REQ(bio, x); } %} %typemap(out) X509_CRL * { PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if ($1 != NULL) $result = SWIG_NewPointerObj($1, $1_descriptor, 0); else { m2_PyErr_Msg(_x509_err); $result = NULL; } } %threadallow x509_crl_read_pem; %inline %{ X509_CRL *x509_crl_read_pem(BIO *bio) { return PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL); } %} %typemap(out) X509_CRL * ; %inline %{ /* X509_set_version() is a macro. */ int x509_set_version(X509 *x, long version) { return X509_set_version(x, version); } /* X509_get_version() is a macro. */ long x509_get_version(X509 *x) { return X509_get_version(x); } /* X509_set_notBefore() is a macro. */ int x509_set_not_before(X509 *x, ASN1_TIME *tm) { return X509_set_notBefore(x, tm); } /* X509_get_notBefore() is a macro. */ ASN1_TIME *x509_get_not_before(X509 *x) { return X509_get_notBefore(x); } /* X509_set_notAfter() is a macro. */ int x509_set_not_after(X509 *x, ASN1_TIME *tm) { return X509_set_notAfter(x, tm); } /* X509_get_notAfter() is a macro. */ ASN1_TIME *x509_get_not_after(X509 *x) { return X509_get_notAfter(x); } int x509_sign(X509 *x, EVP_PKEY *pkey, EVP_MD *md) { return X509_sign(x, pkey, md); } /* x509_gmtime_adj() is a macro. */ ASN1_TIME *x509_gmtime_adj(ASN1_TIME *s, long adj) { return X509_gmtime_adj(s, adj); } PyObject *x509_name_by_nid(X509_NAME *name, int nid) { void *buf; int len, xlen; PyObject *ret; if ((len = X509_NAME_get_text_by_NID(name, nid, NULL, 0)) == -1) { Py_RETURN_NONE; } len++; if (!(buf = PyMem_Malloc(len))) { PyErr_SetString(PyExc_MemoryError, "x509_name_by_nid"); return NULL; } xlen = X509_NAME_get_text_by_NID(name, nid, buf, len); ret = PyBytes_FromStringAndSize(buf, xlen); PyMem_Free(buf); return ret; } int x509_name_set_by_nid(X509_NAME *name, int nid, PyObject *obj) { return X509_NAME_add_entry_by_NID(name, nid, MBSTRING_ASC, (unsigned char *)PyBytes_AsString(obj), -1, -1, 0); } /* x509_name_add_entry_by_txt */ int x509_name_add_entry_by_txt(X509_NAME *name, char *field, int type, char *bytes, int len, int loc, int set) { return X509_NAME_add_entry_by_txt(name, field, type, (unsigned char *)bytes, len, loc, set); } PyObject *x509_name_get_der(X509_NAME *name) { const char* pder=""; size_t pderlen; i2d_X509_NAME(name, 0); if (!X509_NAME_get0_der(name, (const unsigned char **)&pder, &pderlen)) { m2_PyErr_Msg(_x509_err); return NULL; } return PyBytes_FromStringAndSize(pder, pderlen); } /* sk_X509_free() is a macro. */ void sk_x509_free(STACK_OF(X509) *stack) { sk_X509_free(stack); } /* sk_X509_push() is a macro. */ int sk_x509_push(STACK_OF(X509) *stack, X509 *x509) { return sk_X509_push(stack, x509); } /* sk_X509_pop() is a macro. */ X509 *sk_x509_pop(STACK_OF(X509) *stack) { return sk_X509_pop(stack); } %} %inline %{ int x509_store_load_locations(X509_STORE *store, const char *file) { int locations = 0; if ((locations = X509_STORE_load_locations(store, file, NULL)) < 1) { m2_PyErr_Msg(_x509_err); } return locations; } int x509_type_check(X509 *x509) { return 1; } int x509_name_type_check(X509_NAME *name) { return 1; } X509_NAME *x509_req_get_subject_name(X509_REQ *x) { return X509_REQ_get_subject_name(x); } long x509_req_get_version(X509_REQ *x) { return X509_REQ_get_version(x); } int x509_req_set_version(X509_REQ *x, long version) { return X509_REQ_set_version(x, version); } int x509_req_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts) { return X509_REQ_add_extensions(req, exts); } X509_NAME_ENTRY *x509_name_entry_create_by_txt(X509_NAME_ENTRY **ne, char *field, int type, char *bytes, int len) { return X509_NAME_ENTRY_create_by_txt( ne, field, type, (unsigned char *)bytes, len); } %} %typemap(out) X509V3_CTX * { PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if ($1 != NULL) $result = SWIG_NewPointerObj($1, $1_descriptor, 0); else { $result = NULL; } } %inline %{ X509V3_CTX * x509v3_set_nconf(void) { X509V3_CTX * ctx; CONF *conf = NCONF_new(NULL); if (!(ctx=(X509V3_CTX *)PyMem_Malloc(sizeof(X509V3_CTX)))) { PyErr_SetString(PyExc_MemoryError, "x509v3_set_nconf"); return NULL; } /* X509V3_set_nconf does not generate any error signs at all. */ X509V3_set_nconf(ctx, conf); return ctx; } %} %typemap(out) X509V3_CTX * ; %typemap(out) X509_EXTENSION * { PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if ($1 != NULL) $result = SWIG_NewPointerObj($1, $1_descriptor, 0); else { m2_PyErr_Msg(_x509_err); $result = NULL; } } %inline %{ X509_EXTENSION * x509v3_ext_conf(void *conf, X509V3_CTX *ctx, char *name, char *value) { X509_EXTENSION * ext = NULL; ext = X509V3_EXT_conf(conf, ctx, name, value); PyMem_Free(ctx); return ext; } %} %typemap(out) X509_EXTENSION * ; %inline %{ /* X509_EXTENSION_free() might be a macro, didn't find definition. */ void x509_extension_free(X509_EXTENSION *ext) { X509_EXTENSION_free(ext); } PyObject *x509_extension_get_name(X509_EXTENSION *ext) { PyObject * ext_name; const char * ext_name_str; ext_name_str = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext))); if (!ext_name_str) { m2_PyErr_Msg(_x509_err); return NULL; } ext_name = PyBytes_FromStringAndSize(ext_name_str, strlen(ext_name_str)); return ext_name; } /* sk_X509_EXTENSION_new_null is a macro. */ STACK_OF(X509_EXTENSION) *sk_x509_extension_new_null(void) { return sk_X509_EXTENSION_new_null(); } /* sk_X509_EXTENSION_free() is a macro. */ void sk_x509_extension_free(STACK_OF(X509_EXTENSION) *stack) { sk_X509_EXTENSION_free(stack); } /* sk_X509_EXTENSION_push() is a macro. */ int sk_x509_extension_push(STACK_OF(X509_EXTENSION) *stack, X509_EXTENSION *x509_ext) { return sk_X509_EXTENSION_push(stack, x509_ext); } /* sk_X509_EXTENSION_pop() is a macro. */ X509_EXTENSION *sk_x509_extension_pop(STACK_OF(X509_EXTENSION) *stack) { return sk_X509_EXTENSION_pop(stack); } /* sk_X509_EXTENSION_num() is a macro. */ int sk_x509_extension_num(STACK_OF(X509_EXTENSION) *stack) { return sk_X509_EXTENSION_num(stack); } /* sk_X509_EXTENSION_value() is a macro. */ X509_EXTENSION *sk_x509_extension_value(STACK_OF(X509_EXTENSION) *stack, int i) { return sk_X509_EXTENSION_value(stack, i); } /* X509_STORE_CTX_get_app_data is a macro. */ void *x509_store_ctx_get_app_data(X509_STORE_CTX *ctx) { return X509_STORE_CTX_get_app_data(ctx); } /* X509_STORE_CTX_get_app_data is a macro. */ void *x509_store_ctx_get_ex_data(X509_STORE_CTX *ctx, int idx) { return X509_STORE_CTX_get_ex_data(ctx, idx); } void x509_store_set_verify_cb(X509_STORE *store, PyObject *pyfunc) { Py_XDECREF(x509_store_verify_cb_func); Py_INCREF(pyfunc); x509_store_verify_cb_func = pyfunc; X509_STORE_set_verify_cb(store, x509_store_verify_callback); } %} %typemap(out) STACK_OF(X509) * { PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */ if ($1 != NULL) $result = SWIG_NewPointerObj($1, $1_descriptor, 0); else { $result = NULL; } } %inline %{ STACK_OF(X509) * make_stack_from_der_sequence(PyObject * pyEncodedString){ STACK_OF(X509) *certs; Py_ssize_t encoded_string_len; char *encoded_string; const unsigned char *tmp_str; encoded_string_len = PyBytes_Size(pyEncodedString); if (encoded_string_len > INT_MAX) { PyErr_Format(_x509_err, "object too large"); return NULL; } encoded_string = PyBytes_AsString(pyEncodedString); if (!encoded_string) { PyErr_SetString(_x509_err, "Cannot convert Python Bytes to (char *)."); return NULL; } tmp_str = (unsigned char *)encoded_string; certs = d2i_SEQ_CERT(NULL, &tmp_str, encoded_string_len); if (certs == NULL) { PyErr_SetString(_x509_err, "Generating STACK_OF(X509) failed."); return NULL; } return certs; } /* sk_X509_new_null() is a macro returning "STACK_OF(X509) *". */ STACK_OF(X509) *sk_x509_new_null(void) { return sk_X509_new_null(); } %} %typemap(out) STACK_OF(X509) *; %inline %{ PyObject * get_der_encoding_stack(STACK_OF(X509) *stack){ PyObject * encodedString; unsigned char * encoding = NULL; int len; len = i2d_SEQ_CERT(stack, &encoding); if (!encoding) { m2_PyErr_Msg(_x509_err); return NULL; } encodedString = PyBytes_FromStringAndSize((const char *)encoding, len); if (encoding) OPENSSL_free(encoding); return encodedString; } %} /* Free malloc'ed return value for x509_name_oneline */ %typemap(ret) char * { if ($1 != NULL) OPENSSL_free($1); } %inline %{ char *x509_name_oneline(X509_NAME *x) { return X509_NAME_oneline(x, NULL, 0); } %} %typemap(ret) char *; m2crypto-0.42.0/src/SWIG/libcrypto-compat.h000066400000000000000000000052471465575656700204170ustar00rootroot00000000000000#ifndef LIBCRYPTO_COMPAT_H #define LIBCRYPTO_COMPAT_H #if OPENSSL_VERSION_NUMBER < 0x10100000L #include #include #include #include #include #include int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d); int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q); int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp); void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d); void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q); void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp); void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g); int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g); void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key); int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key); void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps); int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s); void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps); int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s); void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g); int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g); void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key); int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key); int DH_set_length(DH *dh, long length); const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx); unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx); EVP_MD_CTX *EVP_MD_CTX_new(void); void EVP_MD_CTX_free(EVP_MD_CTX *ctx); #define EVP_CIPHER_impl_ctx_size(e) e->ctx_size #define EVP_CIPHER_CTX_get_cipher_data(ctx) ctx->cipher_data int RSA_size(const RSA* rsa); RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth); int RSA_meth_set1_name(RSA_METHOD *meth, const char *name); #define RSA_meth_get_finish(meth) meth->finish int RSA_meth_set_priv_enc(RSA_METHOD *meth, int (*priv_enc) (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)); int RSA_meth_set_priv_dec(RSA_METHOD *meth, int (*priv_dec) (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)); int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa)); void RSA_meth_free(RSA_METHOD *meth); int RSA_bits(const RSA *r); RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey); int X509_NAME_get0_der(X509_NAME *nm, const unsigned char **pder, size_t *pderlen); #endif /* OPENSSL_VERSION_NUMBER */ #endif /* LIBCRYPTO_COMPAT_H */ m2crypto-0.42.0/src/SWIG/py3k_compat.h000066400000000000000000000020721465575656700173510ustar00rootroot00000000000000#ifndef PY3K_COMPAT_H #define PY3K_COMPAT_H #if PY_MAJOR_VERSION >= 3 FILE* PyFile_AsFile(PyObject *p); PyObject* PyFile_Name(PyObject *p); #else /* PY2K */ /* Concerning PyBytes* functions: * * Python 3’s str() type is equivalent to Python 2’s unicode(); the * C functions are called PyUnicode_* for both. The old 8-bit string * type has become bytes(), with C functions called PyBytes_*. Python * 2.6 and later provide a compatibility header, bytesobject.h, mapping * PyBytes names to PyString ones. For best compatibility with Python 3, * PyUnicode should be used for textual data and PyBytes for binary * data. It’s also important to remember that PyBytes and PyUnicode in * Python 3 are not interchangeable like PyString and PyUnicode are in * Python 2. The following example shows best practices with regards to * PyUnicode, PyString, and PyBytes. * * From https://docs.python.org/2.7/howto/cporting.html */ PyObject* PyLong_FromLong(long x); const char* PyUnicode_AsUTF8(PyObject *unicode); #endif /* PY_MAJOR_VERSION */ #endif /* PY3K_COMPAT_H */ m2crypto-0.42.0/tests/000077500000000000000000000000001465575656700145505ustar00rootroot00000000000000m2crypto-0.42.0/tests/README000066400000000000000000000027671465575656700154440ustar00rootroot00000000000000This directory contains unit tests for M2Crypto. To run all tests, make sure you have installed setuptools and then issue the following command from the M2Crypto root directory: python -munittest discover -v tests To run tests in a single file, for example test_ssl.py, do this: python -munittest -v tests.test_ssl Look also in the demo directory for other samples. To create new test certificates: mkdir certs cd certs Making the CA. You may want to use a locally edited openssl.cnf to make sure that X509v3 Basic Constraints CA:TRUE gets set (by default it may be false). By default duration may only be just one year; should set this for at least 3 years. CA.sh -newca cp demoCA/cacert.pem ../ca.pem Making the server certificate and private key. make sure commonName field is localhost. CA.sh -newreq CA.sh -signreq cp newcert.pem ../server.pem openssl rsa >../server.pem Making the x509 certificate and key. CA.sh -newreq CA.sh -signreq cp newcert.pem ../x509.pem openssl rsa >../x509.pem openssl x509 -in ../x509.pem -out ../x509.der -outform DER Making the signer certificate. Make sure the email address is signer@example.com. CA.sh -newreq CA.sh -signreq cp newcert.pem ../signer.pem openssl rsa ../signer_key.pem Making the recipient certificate. Make sure the email address is recipient@example.com. CA.sh -newreq CA.sh -signreq cp newcert.pem ../recipient.pem openssl rsa ../recipient_key.pem Finally run the tests and edit for new values. m2crypto-0.42.0/tests/__init__.py000066400000000000000000000003501465575656700166570ustar00rootroot00000000000000import logging import os.path import sys try: import unittest2 as unittest except ImportError: import unittest logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s', level=logging.DEBUG) m2crypto-0.42.0/tests/alltests.py000066400000000000000000000062661465575656700167670ustar00rootroot00000000000000from __future__ import absolute_import, print_function import platform import struct import sys def suite(): from M2Crypto import m2 # noqa import os import unittest def my_import(name): # See http://docs.python.org/lib/built-in-funcs.html#l2h-6 components = name.split('.') try: # python setup.py test mod = __import__(name) for comp in components[1:]: mod = getattr(mod, comp) except ImportError: # python tests/alltests.py mod = __import__(components[1]) return mod modules_to_test = [ 'tests.test_aes', 'tests.test_asn1', 'tests.test_bio', 'tests.test_bio_membuf', 'tests.test_bio_file', 'tests.test_bio_iobuf', 'tests.test_bio_ssl', 'tests.test_bn', 'tests.test_authcookie', 'tests.test_dh', 'tests.test_dsa', 'tests.test_engine', 'tests.test_err', 'tests.test_evp', 'tests.test_init', 'tests.test_obj', 'tests.test_rand', 'tests.test_rc4', 'tests.test_rsa', 'tests.test_smime', 'tests.test_ssl_offline', 'tests.test_threading', 'tests.test_x509', 'tests.test_timeout'] if os.name == 'posix': modules_to_test.append('tests.test_ssl') elif os.name == 'nt': modules_to_test.append('tests.test_ssl_win') if m2.OPENSSL_VERSION_NUMBER >= 0x90800F and m2.OPENSSL_NO_EC == 0: modules_to_test.append('tests.test_ecdh') modules_to_test.append('tests.test_ecdsa') modules_to_test.append('tests.test_ec_curves') alltests = unittest.TestSuite() for module in map(my_import, modules_to_test): alltests.addTest(module.suite()) print('Version of OpenSSL is {0:x} ({1:s})'.format(m2.OPENSSL_VERSION_NUMBER, m2.OPENSSL_VERSION_TEXT)) print('(struct.calcsize("P") * 8) == 32 : {}'.format((struct.calcsize("P") * 8) == 32)) print("not(sys.maxsize > 2**32) : {}".format(not(sys.maxsize > 2**32))) print("libc_ver = {}".format(platform.libc_ver())) return alltests def dump_garbage(): import gc print('\nGarbage:') gc.collect() if len(gc.garbage): print('\nLeaked objects:') for x in gc.garbage: s = str(x) if len(s) > 77: s = s[:73] + '...' print(type(x), '\n ', s) print('There were %d leaks.' % len(gc.garbage)) else: print('Python garbage collector did not detect any leaks.') print('However, it is still possible there are leaks in the C code.') def runall(report_leaks=0): report_leaks = report_leaks if report_leaks: import gc gc.enable() gc.set_debug(gc.DEBUG_LEAK & ~gc.DEBUG_SAVEALL) import os import unittest from M2Crypto import Rand try: Rand.load_file('tests/randpool.dat', -1) unittest.TextTestRunner(verbosity=2).run(suite()) Rand.save_file('tests/randpool.dat') finally: if os.name == 'posix': from .test_ssl import zap_servers zap_servers() if report_leaks: dump_garbage() m2crypto-0.42.0/tests/bad_date_cert.crt000066400000000000000000000021131465575656700200170ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIC/TCCAeWgAwIBAgIJAPd8QvAqguI9MA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV BAMMCWxvY2FsaG9zdDAgFw0xNjAzMDQxNDU3NDZaGA8yMTE2MDIwOTE0NTc0Nlow FDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAsyy/9CI++wVV22U3xor0Hi1nUUusa8Or/a/ppTpgAH0UREcvKrfSCQU0 cCPbYg2M3Jn+tQlcs3eAfUFnyz4XCDlMnns8iKse6kkzQQpx+budUwAamP21bHa6 8dMwDFT3+z9LxDstqdbsvW+KzQwyuYCsWnp6l2KRNy1P4wt7gVvnm5+GCGRMo89L yWJ6iz21XZt6wsafPArKclxVzkzW6Li7JvMaJWyJstSlDaGMlAORUbbO78/VYVYD idhqtgN+s1rnHZEMKU0io2pTkVTYVVU6hkGvx7OxChVd8ZYQdptYu1jqB4DS9Ima tNLZZMnBh9aAwZAEWLku8N1EV/pfyQIDAQABo1AwTjAdBgNVHQ4EFgQUWc4wUp+0 e1cC0gY3DCtCx1ECCgswHwYDVR0jBBgwFoAUWc4wUp+0e1cC0gY3DCtCx1ECCgsw DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEABmFTO2Q+6VqzQ3Td4Xp4 TwJ25WJWf/n5E/sY96Z4iG5ABzPEo4jzsx6DQzcxQ445nu62/OHtmF8y8abZWk0/ KTmTMEl0+z9ab48zHIjp7WkXcUGxHfbIApI8tmYXn/y1+zEtG5+bRXcAODce0pRL CqWvlchiwLhlao0Pe8Gz1DV7feS/or9XojE8+sokSiuRFGIcwIzpYX/hja4Xtsmc Z/PUfodHmpKW+c559cn9pnVjJjhjXpKqDrgE2l9jtTwRVLQOGMxcISvfoNwu833z OJJ1gyor9okGBpmackBUpwpWD7s6tBwkcMo2sJZGD/Kfv1ncYuRXqa6+tQaHxJRS LA== -----END CERTIFICATE----- m2crypto-0.42.0/tests/ca.pem000066400000000000000000000132221465575656700156360ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 0 (0x0) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=California, O=M2Crypto, CN=Heikki Toivonen Validity Not Before: Oct 9 07:40:19 2019 GMT Not After : Dec 31 07:40:22 2049 GMT Subject: C=US, ST=California, O=M2Crypto, CN=Heikki Toivonen Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:b8:14:c3:7e:10:d4:0e:55:5e:8c:5c:14:07:14: da:a6:32:d4:35:37:23:7c:27:bd:29:69:4a:dd:ee: a7:9f:f3:7f:1b:f4:73:3d:0b:89:6a:a1:f7:35:ac: b0:20:42:b8:e6:f5:36:9f:83:d9:d6:d0:45:b9:60: 0c:a9:dd:f6:28:b9:c4:b7:02:ee:63:cc:ba:3a:70: 0c:34:75:46:9d:f1:7b:d5:5f:46:17:84:94:fc:00: f6:21:c3:e2:cd:6c:d1:33:bf:d9:c2:1c:5f:c8:af: 91:20:0b:ed:c9:68:44:00:45:ec:9e:82:5a:62:c2: a7:53:de:58:db:7d:d5:2c:9e:8f:7c:15:b4:34:30: ab:b7:3d:ed:72:a2:5c:4a:51:d1:85:33:ad:e0:23: e9:12:02:b9:64:0b:d8:de:61:f8:d9:18:4e:43:32: 73:d0:f2:df:c6:de:28:cf:f5:48:7e:46:7c:85:c6: 1e:96:a2:32:b8:16:ff:96:71:81:a7:d1:87:d2:d9: 0e:b8:9f:ad:45:14:a1:d3:b9:52:c8:59:63:77:17: fe:22:ac:f9:c1:97:12:97:98:99:ae:ac:48:1b:97: 83:fa:88:e0:63:9b:bc:55:ea:e0:c7:ec:55:28:e9: 28:2a:b4:be:08:e1:50:43:4e:41:df:10:b7:98:1e: dd:37 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:TRUE X509v3 Subject Key Identifier: 49:6E:7E:9B:16:48:9F:E9:B8:A7:DC:7C:0E:73:F6:26:2A:9C:9D:7C Signature Algorithm: sha256WithRSAEncryption 79:9b:15:c5:45:3e:f1:8a:15:bb:26:38:13:c1:10:bd:88:04: 77:40:0e:05:75:0a:21:4f:7e:cb:6a:0d:a3:10:a9:de:a5:c3: f1:dc:15:d6:a7:c6:61:28:94:9f:0e:5b:fc:22:53:9a:92:f2: a2:cd:4d:fa:29:c6:c6:1f:e9:85:c2:37:60:1f:7f:eb:68:09: 88:0b:d3:30:38:25:76:c0:58:33:33:45:8c:82:9a:55:44:53: 92:14:07:48:0a:df:5c:0c:d2:79:dc:7b:51:1f:44:42:c1:4d: 96:0f:a3:18:83:bf:db:31:a8:b2:3a:53:69:96:59:d5:37:6d: 99:5a:12:d7:cb:66:b9:a7:f4:eb:c3:5f:e6:af:e2:e5:48:f0: ce:89:a0:7c:fd:9e:68:4e:e7:8e:b8:47:1e:69:69:c6:fb:4e: 8e:ea:c7:58:a6:96:b5:40:d3:52:a5:74:cd:93:8f:44:a7:8f: 6e:79:a7:a2:ef:1e:60:3d:bb:5b:ff:14:e6:93:92:91:79:6f: 24:56:8a:75:71:21:d1:d4:aa:f4:21:89:6c:81:1e:88:73:2f: e2:d9:b9:df:64:62:fa:03:74:da:6a:55:ab:c7:ef:83:ed:95: 4e:76:57:60:56:ce:94:73:f5:3e:5a:20:5c:6f:0c:7f:77:b2: ae:ad:81:22 -----BEGIN CERTIFICATE----- MIIDSDCCAjCgAwIBAgIBADANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzET MBEGA1UECAwKQ2FsaWZvcm5pYTERMA8GA1UECgwITTJDcnlwdG8xGDAWBgNVBAMM D0hlaWtraSBUb2l2b25lbjAeFw0xOTEwMDkwNzQwMTlaFw00OTEyMzEwNzQwMjJa ME8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMREwDwYDVQQKDAhN MkNyeXB0bzEYMBYGA1UEAwwPSGVpa2tpIFRvaXZvbmVuMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAuBTDfhDUDlVejFwUBxTapjLUNTcjfCe9KWlK3e6n n/N/G/RzPQuJaqH3NaywIEK45vU2n4PZ1tBFuWAMqd32KLnEtwLuY8y6OnAMNHVG nfF71V9GF4SU/AD2IcPizWzRM7/ZwhxfyK+RIAvtyWhEAEXsnoJaYsKnU95Y233V LJ6PfBW0NDCrtz3tcqJcSlHRhTOt4CPpEgK5ZAvY3mH42RhOQzJz0PLfxt4oz/VI fkZ8hcYelqIyuBb/lnGBp9GH0tkOuJ+tRRSh07lSyFljdxf+Iqz5wZcSl5iZrqxI G5eD+ojgY5u8Vergx+xVKOkoKrS+COFQQ05B3xC3mB7dNwIDAQABoy8wLTAMBgNV HRMEBTADAQH/MB0GA1UdDgQWBBRJbn6bFkif6bin3HwOc/YmKpydfDANBgkqhkiG 9w0BAQsFAAOCAQEAeZsVxUU+8YoVuyY4E8EQvYgEd0AOBXUKIU9+y2oNoxCp3qXD 8dwV1qfGYSiUnw5b/CJTmpLyos1N+inGxh/phcI3YB9/62gJiAvTMDgldsBYMzNF jIKaVURTkhQHSArfXAzSedx7UR9EQsFNlg+jGIO/2zGosjpTaZZZ1TdtmVoS18tm uaf068Nf5q/i5UjwzomgfP2eaE7njrhHHmlpxvtOjurHWKaWtUDTUqV0zZOPRKeP bnmnou8eYD27W/8U5pOSkXlvJFaKdXEh0dSq9CGJbIEeiHMv4tm532Ri+gN02mpV q8fvg+2VTnZXYFbOlHP1PlogXG8Mf3eyrq2BIg== -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEAuBTDfhDUDlVejFwUBxTapjLUNTcjfCe9KWlK3e6nn/N/G/Rz PQuJaqH3NaywIEK45vU2n4PZ1tBFuWAMqd32KLnEtwLuY8y6OnAMNHVGnfF71V9G F4SU/AD2IcPizWzRM7/ZwhxfyK+RIAvtyWhEAEXsnoJaYsKnU95Y233VLJ6PfBW0 NDCrtz3tcqJcSlHRhTOt4CPpEgK5ZAvY3mH42RhOQzJz0PLfxt4oz/VIfkZ8hcYe lqIyuBb/lnGBp9GH0tkOuJ+tRRSh07lSyFljdxf+Iqz5wZcSl5iZrqxIG5eD+ojg Y5u8Vergx+xVKOkoKrS+COFQQ05B3xC3mB7dNwIDAQABAoIBAQCISU8nYbwuVIQo tO9bAtSS4eT89TK/dAh3xW3ZfBz8rmF4R/adxpHZscp+IblQWTXeQMRNO2gnw5Er mvIlPaFHK6p5uKDYoLVsGJLgr8c1npkJM32IYe+P2AJio02iu6LzhmHpdepwgZOX v10wlZJrBVoXTPkwT19lF6R/9NzEJ+qyceixwIUFlqKzFv+LavFL4elP03OVF5Wu TN2DTaVJzNdpBVGdYKkJX7GhX28/gaDRZw6B2wJoJhl56uhzibNe9Lc0S9nyt+0Y ARodv5KVTaM07z4LkFQxIliVFJmR8Bin3CHC36K9ike57srkR/BOR13Vxw9EtUHx tNe11jy5AoGBAOVo1NHwHT7EH06F3O2MvKYJAa5rm8EU9Eq6d70ylVDKHCu2NA9V KeeUbXxGK9Bk3RhLVevZv870AgZqtD4sUEg3qMrW3ZQHyyAlZq57AAw9GlL8REZv aWvDE4/fmpNYVyUrpQ9KIyaZa96VZtqUJbLgzcvQsRhiwo2zQAP9UqL9AoGBAM1q 7DJtTqU1Muk5UWc8XS6HxRf0D5c1240UXP1xkRDCfI2lI3AM3sCQ5iKQP/SsOrvK KgxQDVykdbTqD5F7QDX8BmYTdALzRm/XyqqY52WljDAwNEsdTLPewffDMRhjSBSw sjPiHMnmXJH+0uKKUrSdvDsElBQASKQ81Ojg+ZlDAoGAS2HiJMYQ5hIN84B7Mze+ uZRWEBleCdk32OJi/DGF7REsppRtkOg8J9OXEnIAba7nE9eVeTWJGJkHnVIsvg1T qBdaCKUIFF9nOL3xer4CKwNdBg3M5ZQwgO+OGwWvxmEN6bHowBhtan6Zen9/V628 oYXLOgDuYIP7SBKxo133bIUCgYEAj4hTrFSmbFfE0CQF1k3eimHB/R/DORQf6e89 nrYY+A39e/fU0Dmd+A4HUEVc+vjRPWBgiyPwgjhEKvqVkED/t/j2+6JCIMGeCQ5O hW+72FGZqB42m/nIG7Ld8+KGzpSozBQ/IHOxS/5T1oupDTQ74AqLeO2VDni4SVJc LrDslwMCgYEArxtk6NGesCUgdCTHEueubcY8VoXn/DOHi1QpqV/Fq93Fs5AkDwle yI11+KVvXad2UAZI2LcQsN3P12Wdco0ayfHOSpOf8zv1w+/DyDkrcT10ZxgL9EDJ eBEgQ+XmPoteMubMr6EQrzfXxzKqK/DN+2mq0s7PAFgHOr31g6feLYI= -----END RSA PRIVATE KEY----- m2crypto-0.42.0/tests/ca_key.pem000066400000000000000000000032171465575656700165110ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEAuBTDfhDUDlVejFwUBxTapjLUNTcjfCe9KWlK3e6nn/N/G/Rz PQuJaqH3NaywIEK45vU2n4PZ1tBFuWAMqd32KLnEtwLuY8y6OnAMNHVGnfF71V9G F4SU/AD2IcPizWzRM7/ZwhxfyK+RIAvtyWhEAEXsnoJaYsKnU95Y233VLJ6PfBW0 NDCrtz3tcqJcSlHRhTOt4CPpEgK5ZAvY3mH42RhOQzJz0PLfxt4oz/VIfkZ8hcYe lqIyuBb/lnGBp9GH0tkOuJ+tRRSh07lSyFljdxf+Iqz5wZcSl5iZrqxIG5eD+ojg Y5u8Vergx+xVKOkoKrS+COFQQ05B3xC3mB7dNwIDAQABAoIBAQCISU8nYbwuVIQo tO9bAtSS4eT89TK/dAh3xW3ZfBz8rmF4R/adxpHZscp+IblQWTXeQMRNO2gnw5Er mvIlPaFHK6p5uKDYoLVsGJLgr8c1npkJM32IYe+P2AJio02iu6LzhmHpdepwgZOX v10wlZJrBVoXTPkwT19lF6R/9NzEJ+qyceixwIUFlqKzFv+LavFL4elP03OVF5Wu TN2DTaVJzNdpBVGdYKkJX7GhX28/gaDRZw6B2wJoJhl56uhzibNe9Lc0S9nyt+0Y ARodv5KVTaM07z4LkFQxIliVFJmR8Bin3CHC36K9ike57srkR/BOR13Vxw9EtUHx tNe11jy5AoGBAOVo1NHwHT7EH06F3O2MvKYJAa5rm8EU9Eq6d70ylVDKHCu2NA9V KeeUbXxGK9Bk3RhLVevZv870AgZqtD4sUEg3qMrW3ZQHyyAlZq57AAw9GlL8REZv aWvDE4/fmpNYVyUrpQ9KIyaZa96VZtqUJbLgzcvQsRhiwo2zQAP9UqL9AoGBAM1q 7DJtTqU1Muk5UWc8XS6HxRf0D5c1240UXP1xkRDCfI2lI3AM3sCQ5iKQP/SsOrvK KgxQDVykdbTqD5F7QDX8BmYTdALzRm/XyqqY52WljDAwNEsdTLPewffDMRhjSBSw sjPiHMnmXJH+0uKKUrSdvDsElBQASKQ81Ojg+ZlDAoGAS2HiJMYQ5hIN84B7Mze+ uZRWEBleCdk32OJi/DGF7REsppRtkOg8J9OXEnIAba7nE9eVeTWJGJkHnVIsvg1T qBdaCKUIFF9nOL3xer4CKwNdBg3M5ZQwgO+OGwWvxmEN6bHowBhtan6Zen9/V628 oYXLOgDuYIP7SBKxo133bIUCgYEAj4hTrFSmbFfE0CQF1k3eimHB/R/DORQf6e89 nrYY+A39e/fU0Dmd+A4HUEVc+vjRPWBgiyPwgjhEKvqVkED/t/j2+6JCIMGeCQ5O hW+72FGZqB42m/nIG7Ld8+KGzpSozBQ/IHOxS/5T1oupDTQ74AqLeO2VDni4SVJc LrDslwMCgYEArxtk6NGesCUgdCTHEueubcY8VoXn/DOHi1QpqV/Fq93Fs5AkDwle yI11+KVvXad2UAZI2LcQsN3P12Wdco0ayfHOSpOf8zv1w+/DyDkrcT10ZxgL9EDJ eBEgQ+XmPoteMubMr6EQrzfXxzKqK/DN+2mq0s7PAFgHOr31g6feLYI= -----END RSA PRIVATE KEY----- m2crypto-0.42.0/tests/der_encoded_seq.b64000066400000000000000000000024301465575656700201670ustar00rootroot00000000000000MIIDwTCCA70wggKloAMCAQICAg5QMA0GCSqGSIb3DQEBBQUAMGkxEzARBgoJkiaJk/IsZAEZFgNv cmcxGDAWBgoJkiaJk/IsZAEZFghET0VHcmlkczEgMB4GA1UECxMXQ2VydGlmaWNhdGUgQXV0aG9y aXRpZXMxFjAUBgNVBAMTDURPRUdyaWRzIENBIDEwHhcNMDUwMTEyMDA1MTAyWhcNMDYwMTEyMDA1 MTAyWjBhMRMwEQYKCZImiZPyLGQBGRMDb3JnMRgwFgYKCZImiZPyLGQBGRMIZG9lZ3JpZHMxETAP BgNVBAsTCFNlcnZpY2VzMR0wGwYDVQQDExRob3N0L2Jvc3Nob2cubGJsLmdvdjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAJ+M2ICaiIkr1YcPzXlOSA/DTzduZPq+ALwbmU+nHatL8wXr 8SmwMq/aIG9egGnJzsTlofkSA5D7HAX3nLKkU0A+k0Eig2QzZ5iPjrtAr2m9/b/EsF2I58yOcEDT EZuHQWCg19YE29n3UwqXB6pgpuMcFfFqLz6NydN9i0T7Md8OGwYpNzK6TsOCtyF+nin5mZleDyXF BtkXeIDHmq8sYmsELv1fbAwYzpAZqvz3k0umXSMwnyq+z6WpawybNuLrhRzqMrMZYzq0Db/hS4xr TeXOFuRQ/IcgWt0rLmOIRYKrVfLujFcAQnaPDW8llK2kgi6OrPlTo8e8JVEcz5d7bKUCAwEAAaN3 MHUwEQYJYIZIAYb4QgEBBAQDAgbAMA4GA1UdDwEB/wQEAwIE8DAfBgNVHSMEGDAWgBTKGR0Sjm6k OF1C1DEOCNvZjRcNXTAvBgNVHREEKDAmgg9ib3NzaG9nLmxibC5nb3aBE01LUm9kcmlndWV6QGxi bC5nb3YwDQYJKoZIhvcNAQEFBQADggEBAKZkj+amwHCSdcMC05NBv1Vck46tGEsAEf9WiNvf3B1N O+B0d+egcbXME+LgrxWvOIf4k2DKvORt/oz5BavEbmD1+/NUseBEA01bzjXXgmWwW48CK5cb6Qam wq1uMa/asUgyLfpVkgA9ThwHIr2/g4HEIqUZLaqotLS5+EzZKhOuWh9OJh+AR6WCxOjTQw1xCJd0 T/sSlHdtlH47xBkDL5DKe0pn9CgGY+ihehcRpzXMB8tKgxzsE8NuB49IUrVC+wIgzEXEeaSPFenL XdWxAKaFWRXyPHrsrtsenxnRkM6y8qxWN6UV5UqpvdE/cy+5QORbzWtfVPYqtNVZoO+N3rc=m2crypto-0.42.0/tests/dhparams.pem000066400000000000000000000003651465575656700170560ustar00rootroot00000000000000-----BEGIN DH PARAMETERS----- MIGHAoGBAIgAcu3gpJeO8aS6N+sTMa655BMzBNlK66q62VH9RqmHwFJSjjCs3ZsF aVsTkO3Mt0gULn1drXsK6Lc6pA8s0eQN8ggyEPVr6ND0jN2jr2qc1XlqD7jxzdxe igB66pLvrWvAulrGxg4QMsQjqcpwZZ2ndRpYSmErIi4M1r19nTgjAgEC -----END DH PARAMETERS----- m2crypto-0.42.0/tests/dsa.param.pem000066400000000000000000000007071465575656700171250ustar00rootroot00000000000000-----BEGIN DSA PARAMETERS----- MIIBHgKBgQDqYu3smvs8KHBx4XX8otDHQUdtCyWKIRC52eQUSYeWejvdaqm11rIq QMFBJDnvicM4avyOIU2d/ZOfLzN7aXFw3Ep67amsLpj82N+n4lASUJwKdOJyzyLG 9IS41RRek8B3lRAs/zqk1U6P5EaE/uIG4+avYmkSDpB4kmnRGhTYeQIVALKQpdTy uat9aoq9mFm8dVA2VxAhAoGAausAkdN4Hj6S5nfPMjJTnwV4u7hVY6b6eAZTJmxs ykr3XlKqM3PS0hKhjatp7f+mRNFxYvGrWPLAwnPOIp/iNn7lM7U41ceUj1O3KrD/ Cg4LQ/bADvY48eytdjMLZDpL3Jwootfs4i8WIb0RnIxg8nClhkY2K2/+4voft+Xi DlA= -----END DSA PARAMETERS----- m2crypto-0.42.0/tests/dsa.priv.pem000066400000000000000000000007751465575656700170120ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBAOpi7eya+zwocHHhdfyi0MdBR20L JYohELnZ5BRJh5Z6O91qqbXWsipAwUEkOe+Jwzhq/I4hTZ39k58vM3tpcXDcSnrt qawumPzY36fiUBJQnAp04nLPIsb0hLjVFF6TwHeVECz/OqTVTo/kRoT+4gbj5q9i aRIOkHiSadEaFNh5AhUAspCl1PK5q31qir2YWbx1UDZXECECgYBq6wCR03gePpLm d88yMlOfBXi7uFVjpvp4BlMmbGzKSvdeUqozc9LSEqGNq2nt/6ZE0XFi8atY8sDC c84in+I2fuUztTjVx5SPU7cqsP8KDgtD9sAO9jjx7K12MwtkOkvcnCii1+ziLxYh vRGcjGDycKWGRjYrb/7i+h+35eIOUAQWAhQ/vK8oLKHdEu7W77fbZ3+jQvvt6Q== -----END PRIVATE KEY----- m2crypto-0.42.0/tests/dsa.pub.pem000066400000000000000000000012161465575656700166070ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MIIBtzCCASsGByqGSM44BAEwggEeAoGBAOpi7eya+zwocHHhdfyi0MdBR20LJYoh ELnZ5BRJh5Z6O91qqbXWsipAwUEkOe+Jwzhq/I4hTZ39k58vM3tpcXDcSnrtqawu mPzY36fiUBJQnAp04nLPIsb0hLjVFF6TwHeVECz/OqTVTo/kRoT+4gbj5q9iaRIO kHiSadEaFNh5AhUAspCl1PK5q31qir2YWbx1UDZXECECgYBq6wCR03gePpLmd88y MlOfBXi7uFVjpvp4BlMmbGzKSvdeUqozc9LSEqGNq2nt/6ZE0XFi8atY8sDCc84i n+I2fuUztTjVx5SPU7cqsP8KDgtD9sAO9jjx7K12MwtkOkvcnCii1+ziLxYhvRGc jGDycKWGRjYrb/7i+h+35eIOUAOBhQACgYEAmYO4Qss7pYq3vAEj5qj35A1gsOeC rGxvu8w9Dj8jACuz0IHOTq+vFbnB6p30rdloMU7Ci4NHPWqOVmWCFcXxkFgJMJld sBbkdbGnhPI80sWJGouUYofHFG4pK0QoMeDZKgg7OgwH8EnmQM+W9KDZYJRSuU4+ 6F6hQkmkwAKAXkU= -----END PUBLIC KEY----- m2crypto-0.42.0/tests/easy_rsa.pem000066400000000000000000000100231465575656700170550ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 3 (0x3) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=NC, L=Raleigh, O=Fedora Project, OU=fedmsg, CN=fedmsg/name=fedmsg/emailAddress=admin@fedoraproject.org Validity Not Before: Jul 15 21:18:52 2012 GMT Not After : Jul 13 21:18:52 2022 GMT Subject: C=US, ST=NC, L=Raleigh, O=Fedora Project, OU=fedmsg, CN=shell-app01.phx2.fedoraproject.org/name=shell-app01.phx2.fedoraproject.org/emailAddress=admin@fedoraproject.org Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:c9:5d:32:76:f9:e8:a4:84:e6:16:cd:24:7e:99: 68:2a:3e:a7:5b:4f:c2:3b:3a:74:ac:3c:30:be:e5: 99:17:62:83:76:5d:40:79:15:b3:7e:ca:4e:40:e5: 88:2b:95:7e:a3:6a:b1:60:0e:ad:6a:22:b8:6c:f7: f2:95:82:f5:20:62:30:95:53:fd:99:ae:73:c2:44: 6f:5a:47:ad:5a:31:8e:46:9e:41:ee:0e:e8:10:24: 0e:06:8d:e0:9d:0b:74:51:fe:53:58:04:35:e9:69: f4:6c:2a:c8:41:2a:8e:59:52:92:70:af:6f:52:4f: e8:a2:65:25:01:96:e4:b0:47 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: Easy-RSA Generated Certificate X509v3 Subject Key Identifier: 77:71:57:05:B0:F6:25:6D:EA:72:6A:BE:E5:53:FB:19:CB:B1:1C:5E X509v3 Authority Key Identifier: keyid:00:98:A5:D5:E7:C4:55:0E:84:A3:67:FE:66:4A:16:E0:04:15:DD:21 DirName:/C=US/ST=NC/L=Raleigh/O=Fedora Project/OU=fedmsg/CN=fedmsg/name=fedmsg/emailAddress=admin@fedoraproject.org serial:8E:EB:28:D8:A9:13:9D:7C X509v3 Extended Key Usage: TLS Web Client Authentication X509v3 Key Usage: Digital Signature Signature Algorithm: sha1WithRSAEncryption 11:b5:cc:6f:e5:cd:8c:b3:fe:98:61:44:ea:ba:9f:39:37:41: 45:5e:34:6c:b1:15:dc:71:a0:1e:7b:8f:8c:43:8b:ad:32:cf: 2d:b2:01:87:bd:b3:0a:a5:2f:51:a4:f6:38:c0:e3:f6:5f:fe: 52:cf:17:13:8c:f8:d8:a7:4c:e8:7f:a3:ac:f4:6c:40:41:0a: e7:f0:14:a8:92:fa:e8:3f:a6:3b:08:a3:af:6f:0b:4d:c5:db: 54:b4:a6:ab:8c:f1:b4:23:71:da:00:e6:ae:69:76:26:3f:06: ae:47:50:b9:a8:b3:20:3e:10:db:ba:f6:8b:d0:19:96:54:88: 96:ff -----BEGIN CERTIFICATE----- MIIESTCCA7KgAwIBAgIBAzANBgkqhkiG9w0BAQUFADCBoDELMAkGA1UEBhMCVVMx CzAJBgNVBAgTAk5DMRAwDgYDVQQHEwdSYWxlaWdoMRcwFQYDVQQKEw5GZWRvcmEg UHJvamVjdDEPMA0GA1UECxMGZmVkbXNnMQ8wDQYDVQQDEwZmZWRtc2cxDzANBgNV BCkTBmZlZG1zZzEmMCQGCSqGSIb3DQEJARYXYWRtaW5AZmVkb3JhcHJvamVjdC5v cmcwHhcNMTIwNzE1MjExODUyWhcNMjIwNzEzMjExODUyWjCB2DELMAkGA1UEBhMC VVMxCzAJBgNVBAgTAk5DMRAwDgYDVQQHEwdSYWxlaWdoMRcwFQYDVQQKEw5GZWRv cmEgUHJvamVjdDEPMA0GA1UECxMGZmVkbXNnMSswKQYDVQQDEyJzaGVsbC1hcHAw MS5waHgyLmZlZG9yYXByb2plY3Qub3JnMSswKQYDVQQpEyJzaGVsbC1hcHAwMS5w aHgyLmZlZG9yYXByb2plY3Qub3JnMSYwJAYJKoZIhvcNAQkBFhdhZG1pbkBmZWRv cmFwcm9qZWN0Lm9yZzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyV0ydvno pITmFs0kfploKj6nW0/COzp0rDwwvuWZF2KDdl1AeRWzfspOQOWIK5V+o2qxYA6t aiK4bPfylYL1IGIwlVP9ma5zwkRvWketWjGORp5B7g7oECQOBo3gnQt0Uf5TWAQ1 6Wn0bCrIQSqOWVKScK9vUk/oomUlAZbksEcCAwEAAaOCAVcwggFTMAkGA1UdEwQC MAAwLQYJYIZIAYb4QgENBCAWHkVhc3ktUlNBIEdlbmVyYXRlZCBDZXJ0aWZpY2F0 ZTAdBgNVHQ4EFgQUd3FXBbD2JW3qcmq+5VP7GcuxHF4wgdUGA1UdIwSBzTCByoAU AJil1efEVQ6Eo2f+ZkoW4AQV3SGhgaakgaMwgaAxCzAJBgNVBAYTAlVTMQswCQYD VQQIEwJOQzEQMA4GA1UEBxMHUmFsZWlnaDEXMBUGA1UEChMORmVkb3JhIFByb2pl Y3QxDzANBgNVBAsTBmZlZG1zZzEPMA0GA1UEAxMGZmVkbXNnMQ8wDQYDVQQpEwZm ZWRtc2cxJjAkBgkqhkiG9w0BCQEWF2FkbWluQGZlZG9yYXByb2plY3Qub3JnggkA juso2KkTnXwwEwYDVR0lBAwwCgYIKwYBBQUHAwIwCwYDVR0PBAQDAgeAMA0GCSqG SIb3DQEBBQUAA4GBABG1zG/lzYyz/phhROq6nzk3QUVeNGyxFdxxoB57j4xDi60y zy2yAYe9swqlL1Gk9jjA4/Zf/lLPFxOM+NinTOh/o6z0bEBBCufwFKiS+ug/pjsI o69vC03F21S0pquM8bQjcdoA5q5pdiY/Bq5HULmosyA+ENu69ovQGZZUiJb/ -----END CERTIFICATE----- m2crypto-0.42.0/tests/ec.priv.pem000066400000000000000000000004401465575656700166170ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MIGkAgEBBDDYZmLKVOPc34hDebkYt5vGMQBcX+WtHbXxnncL6ptQtzgkWN1ePGA6 x2HU8NFFpwigBwYFK4EEACKhZANiAASkekXfdAy+vfwcOvO0rwsVDWpil6EKYMlo kdhqz1/kp7hiv5ppw3/LCwsst9CJUUvfAIsRI4qFvTBE0JR8FxLHKFJgasPRHZo9 x5i2EG07MzSevyODOjtVBrklq6nQCao= -----END EC PRIVATE KEY----- m2crypto-0.42.0/tests/ec.pub.pem000066400000000000000000000003271465575656700164310ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEpHpF33QMvr38HDrztK8LFQ1qYpehCmDJ aJHYas9f5Ke4Yr+aacN/ywsLLLfQiVFL3wCLESOKhb0wRNCUfBcSxyhSYGrD0R2a PceYthBtOzM0nr8jgzo7VQa5Jaup0Amq -----END PUBLIC KEY----- m2crypto-0.42.0/tests/ec.pub2.pem000066400000000000000000000003271465575656700165130ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEQdk1A7xe7OelJhoFfE7x0u3gFSACecUC lM/9SqYiPusEpxI9XOe7te/8N/uavHd7z/GxnWSS7cTWuKUzkBgmggZkeVwz1a0a +trEhzxxiEN50Puuc0ExtNFQcgvIa6en -----END PUBLIC KEY----- m2crypto-0.42.0/tests/ed25519.priv.pem000066400000000000000000000001671465575656700172340ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIHYXZmLr4mS9wVx+PZVTNalGrxvuuS2SwrJqEmCUsYaC -----END PRIVATE KEY----- m2crypto-0.42.0/tests/ed25519.pub.pem000066400000000000000000000001611465575656700170340ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEAqVvZ55o7SU/yNEr/07AwMzxtm7teY6xhnhR9bDoWm2k= -----END PUBLIC KEY----- m2crypto-0.42.0/tests/ed25519.pub2.pem000066400000000000000000000001611465575656700171160ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEANSn/xYZB3kS30u9Gxb7RriRu80oJYsQd6jmA3u7TaVY= -----END PUBLIC KEY----- m2crypto-0.42.0/tests/fips.py000066400000000000000000000002111465575656700160550ustar00rootroot00000000000000try: with open('/proc/sys/crypto/fips_enabled') as f: fips_mode = int(f.read()) except (IOError, OSError): fips_mode = 0 m2crypto-0.42.0/tests/long_serial_cert.pem000066400000000000000000000017411465575656700205710ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICsDCCAhmgAwIBAgIJAPR7mEmILgX6MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV BAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQwHhcNMDkwNjE5MTkzNjIyWhcNMDkwNzE5MTkzNjIyWjBF MQswCQYDVQQGEwJVUzETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB gQDRb/jlXLidgXQGsOLoFbh4JAvC+BgufR7jn93KPybI0oo8VXFUqr2eFuLDcPiE gpWIMrLwq9f0US/M/yXQdsH08L2xe+aaiNl+j+o4VsPhXfnvFvAtFRs+JqCR3VfI vVePwov31+/28PmF1kOxr9SmSzvSPnN3SqSC0GDAmhWNYwIDAQABo4GnMIGkMB0G A1UdDgQWBBR3SQBG5X/vH18obsb2aaBxhU/+HjB1BgNVHSMEbjBsgBR3SQBG5X/v H18obsb2aaBxhU/+HqFJpEcwRTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt U3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAPR7mEmI LgX6MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAoyvUPgjkwPAgiqiU 4cD1tZdcxIzkk22U02cTjJtAPnIYwqwwDpFltApvRbp8MNiPqXbBt0tchj/Ovu4D JiDTMaizVOZ+XmiC68uNTZ4nvEwHvVdKmudNVTZDdFr/a6BErAeTknlMCihN3v6M POx8a1iz8Y/wJ8YA74vMPORKlKc= -----END CERTIFICATE----- m2crypto-0.42.0/tests/makecerts.py000077500000000000000000000114251465575656700171060ustar00rootroot00000000000000#!/usr/bin/env python # # Create test certificates: # # ca.pem # server.pem # recipient.pem # signer.pem # x509.pem # from __future__ import print_function import hashlib import os import os.path import sys import time from M2Crypto import ASN1, EC, EVP, RSA, X509, m2, util t = int(time.time() + time.timezone) before = ASN1.ASN1_TIME() before.set_time(t) after = ASN1.ASN1_TIME() after.set_time(t + 60 * 60 * 24 * 365 * 10) # 10 years serial = 1 def callback(self, *args): return ' ' def gen_identifier(cert, dig='sha256'): instr = cert.get_pubkey().get_rsa().as_pem() h = hashlib.new(dig) h.update(instr) digest = h.hexdigest().upper() return ":".join(digest[pos: pos + 2] for pos in range(0, 40, 2)) def make_subject(cn=None, email=None): sub = X509.X509_Name() sub.C = 'US' sub.ST = 'California' sub.O = 'M2Crypto' if cn is not None: sub.CN = cn else: sub.CN = 'Heikki Toivonen' if email is not None: sub.Email = email return sub def req(name): rsa = RSA.load_key(name + '_key.pem') pk = EVP.PKey() pk.assign_rsa(rsa) reqqed = X509.Request() reqqed.set_pubkey(pk) reqqed.set_subject(make_subject()) reqqed.sign(pk, 'sha256') return reqqed, pk def save_text_pem_key(cert, name, with_key=True): with open(name + '.pem', 'wb') as f: for line in cert.as_text(): f.write(line.encode("ascii")) f.write(cert.as_pem()) if with_key: with open(name + '_key.pem', 'rb') as key_f: for line in key_f: f.write(line) def issue(request, ca, capk): global serial pkey = request.get_pubkey() sub = request.get_subject() cert = X509.X509() cert.set_version(2) cert.set_subject(sub) cert.set_serial_number(serial) serial += 1 issuer = ca.get_subject() cert.set_issuer(issuer) cert.set_pubkey(pkey) cert.set_not_before(before) cert.set_not_after(after) ext = X509.new_extension('basicConstraints', 'CA:FALSE') cert.add_ext(ext) ext = X509.new_extension('subjectKeyIdentifier', gen_identifier(cert)) cert.add_ext(ext) # auth = X509.load_cert('ca.pem') # auth_id = auth.get_ext('subjectKeyIdentifier').get_value() # ext = X509.new_extension('authorityKeyIdentifier', 'keyid:%s' % auth_id) # # cert.add_ext(ext) cert.sign(capk, 'sha256') assert cert.verify(capk) return cert def mk_ca(): r, pk = req('ca') pkey = r.get_pubkey() sub = r.get_subject() cert = X509.X509() cert.set_version(2) cert.set_subject(sub) cert.set_serial_number(0) issuer = X509.X509_Name() issuer.C = sub.C issuer.ST = sub.ST issuer.O = sub.O issuer.CN = sub.CN cert.set_issuer(issuer) cert.set_pubkey(pkey) cert.set_not_before(before) cert.set_not_after(after) ext = X509.new_extension('basicConstraints', 'CA:TRUE') cert.add_ext(ext) ski = gen_identifier(cert) ext = X509.new_extension('subjectKeyIdentifier', ski) cert.add_ext(ext) # ext = X509.new_extension('authorityKeyIdentifier', 'keyid:%s' % ski) # cert.add_ext(ext) cert.sign(pk, 'sha256') save_text_pem_key(cert, 'ca') return cert, pk def mk_server(ca, capk): r, _ = req('server') r.set_subject(make_subject(cn='localhost')) cert = issue(r, ca, capk) save_text_pem_key(cert, 'server') def mk_x509(ca, capk): r, _ = req('x509') r.set_subject(make_subject(cn='X509')) cert = issue(r, ca, capk) save_text_pem_key(cert, 'x509') with open('x509.der', 'wb') as derf: derf.write(cert.as_der()) def mk_signer(ca, capk): r, _ = req('signer') r.set_subject(make_subject(cn='Signer', email='signer@example.com')) cert = issue(r, ca, capk) save_text_pem_key(cert, 'signer', with_key=False) def mk_recipient(ca, capk): r, _ = req('recipient') r.set_subject(make_subject(cn='Recipient', email='recipient@example.com')) cert = issue(r, ca, capk) save_text_pem_key(cert, 'recipient') def mk_ec_pair(): priv_key = EC.gen_params(EC.NID_secp384r1) priv_key.gen_key() priv_key.save_key('ec.priv.pem', callback=util.no_passphrase_callback) pub_key = priv_key.pub() pub_key.save_pub_key('ec.pub.pem') if __name__ == '__main__': names = ['ca', 'server', 'recipient', 'signer', 'x509'] os.chdir(os.path.dirname(sys.argv[0])) for key_name in names: genned_key = RSA.gen_key(2048, m2.RSA_F4) genned_key.save_key('%s_key.pem' % key_name, None) ca_bits, pk_bits = mk_ca() mk_server(ca_bits, pk_bits) mk_x509(ca_bits, pk_bits) mk_signer(ca_bits, pk_bits) mk_recipient(ca_bits, pk_bits) # FIXME This doesn't work well. # mk_ec_pair() m2crypto-0.42.0/tests/pubring.pgp000066400000000000000000000021001465575656700167170ustar00rootroot0000000000000028iPH6Nړ[21Ka=b)57X0f9QV!SuEůUN3S5GUv@#dF_H9D~[NY76hoCNV$XFdaft 223a5- d 7x yUTtԔ;JDAMN}> +7VGP=?2WM[) -h{ `5DʤDf:9 fa9>\@# Billy boyL2W salYcomCXyp$gKc,Mկ1v RtN%02zX(͂S٫usilly test this is=2NF0;1H*ۮ!e=zW6Uu+X*\h!Gary Howland L2 sRP M9'B{r<-NF 7Vs+j5S`|W[name=2xѡ^V?B|f_͂ `GOL2 ۽riR 3v# O6H 6[8f|2.'Qsilly test this isL2 _r_W,I$+bI\uCz~h5y&Qb !c8+silly test this is2t펝jwgkf7 4f-KvMķ$V3>../server.pem Making the x509 certificate and key. CA.sh -newreq CA.sh -signreq cp newcert.pem ../x509.pem openssl rsa >../x509.pem openssl x509 -in ../x509.pem -out ../x509.der -outform DER Making the signer certificate. Make sure the email address is signer@example.com. CA.sh -newreq CA.sh -signreq cp newcert.pem ../signer.pem openssl rsa ../signer_key.pem Making the recipient certificate. Make sure the email address is recipient@example.com. CA.sh -newreq CA.sh -signreq cp newcert.pem ../recipient.pem openssl rsa ../recipient_key.pem Finally run the tests and edit for new values. ------38FBD2321B4A76C8BE88AFD029CDED23 Content-Type: application/x-pkcs7-signature; name="smime.p7s" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="smime.p7s" MIIEhQYJKoZIhvcNAQcCoIIEdjCCBHICAQExDzANBglghkgBZQMEAgEFADALBgkq hkiG9w0BBwGgggJkMIICYDCCAcmgAwIBAgIBBDANBgkqhkiG9w0BAQUFADBPMQsw CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEChMITTJDcnlw dG8xGDAWBgNVBAMTD0hlaWtraSBUb2l2b25lbjAeFw0xNTExMjYyMTMzMTJaFw0y NTExMjMyMTMzMTJaMG8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh MREwDwYDVQQKEwhNMkNyeXB0bzESMBAGA1UEAxMJUmVjaXBpZW50MSQwIgYJKoZI hvcNAQkBFhVyZWNpcGllbnRAZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD gY0AMIGJAoGBAJaMhIx8GBrTwmJdDwilmD2LkUw0b80Vr1Ycffk2pgE8nGPPIGT6 dySl4cv+j1rAqJAbmaMCakPv+TGseQH5zEYRfKrRh9+V1PGkesv8TC6LMyL1M/hT augiSBiW8kk5/zOZA+U9wiJS8TOWILzRyCG7S3U9Kz1RTqoP1XNdZkS/AgMBAAGj LDAqMAkGA1UdEwQCMAAwHQYDVR0OBBYEFFON3U+KXkkZq9wvnavqx8PK9vXUMA0G CSqGSIb3DQEBBQUAA4GBABCx3TS7lz4+2ODeapnJvoy3gMcdMNs6aNWk2QJ2K3Zi AIYwWgYDZZK5AKRClF90xpRELowHVfPBbnoKF2ZW71Cvo1/x95dmKdO0FBM0eZaY rVjbIOb8+nCsHCKQv3vD6uOKCr26SP/lyVCDGNkeYTDAx2zqM/7Q/Kga8Zuj3JEQ MYIB5TCCAeECAQEwVDBPMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5p YTERMA8GA1UEChMITTJDcnlwdG8xGDAWBgNVBAMTD0hlaWtraSBUb2l2b25lbgIB BDANBglghkgBZQMEAgEFAKCB5DAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwG CSqGSIb3DQEJBTEPFw0xODA3MjMxODExNTNaMC8GCSqGSIb3DQEJBDEiBCAFNpRM 82d8yvtEyK+nEYuCf5KuyfnooeJYkzIbqUb2yDB5BgkqhkiG9w0BCQ8xbDBqMAsG CWCGSAFlAwQBKjALBglghkgBZQMEARYwCwYJYIZIAWUDBAECMAoGCCqGSIb3DQMH MA4GCCqGSIb3DQMCAgIAgDANBggqhkiG9w0DAgIBQDAHBgUrDgMCBzANBggqhkiG 9w0DAgIBKDANBgkqhkiG9w0BAQEFAASBgEEVB6XZeD44cN+6qmj1LR5Jh6JLGnIQ eQPGrI8Ygymc1dVDWC72872Xp3UTidhMnCyN36QNBZ7GL63tc2mCZ9rgWE24mvqx cj5hCyXF240ty20igJe5BDaXHgzO0JGJPUtoOxNWrM40IhGxh9MSGlfioMOsuRD4 gDf9hUfjCkvG ------38FBD2321B4A76C8BE88AFD029CDED23-- m2crypto-0.42.0/tests/server.pem000066400000000000000000000132011465575656700165560ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=California, O=M2Crypto, CN=Heikki Toivonen Validity Not Before: Oct 9 08:05:20 2019 GMT Not After : Dec 31 08:05:23 2049 GMT Subject: C=US, ST=California, O=M2Crypto, CN=localhost Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:f4:f3:38:31:09:92:0d:5d:8b:06:f0:43:e0:62: 62:e1:71:eb:30:ba:d7:b9:57:db:8c:10:9b:9e:1e: 76:45:ab:14:92:54:d4:47:34:ab:0f:95:f3:83:c5: f1:45:75:58:72:0a:e1:67:77:d0:d3:7e:6a:6f:5d: 1a:a4:df:aa:96:c0:0f:8d:0a:95:9e:aa:e5:bc:7a: 6f:ab:61:41:75:31:0c:da:a6:d5:0d:b3:42:f0:20: f6:2c:74:69:39:79:90:a0:c9:c2:23:ba:5a:c5:9c: 8f:fa:4f:06:bb:04:8e:2d:a1:36:82:c4:23:99:18: 1a:b7:56:0f:8a:ef:ff:57:22:51:96:ca:69:8f:a3: ae:91:b7:84:02:07:be:4d:55:f2:1c:f9:11:2a:ff: 20:ab:0f:27:fb:79:75:6c:b2:53:e3:04:ea:4f:e5: 51:3f:1e:b0:b5:7f:fa:de:0f:f6:e8:e6:85:a3:17: 8c:b1:a6:dd:fc:e9:b8:92:d5:1c:73:d7:82:6e:60: 6c:10:b3:22:ca:a5:d8:c5:d2:41:93:b3:57:3f:1b: cf:cf:78:4c:15:85:b1:ca:b6:84:13:1b:8f:42:ed: 21:bb:90:a2:b7:39:9d:68:bf:4d:da:31:06:53:98: e3:de:8f:f8:3e:7d:25:f2:75:7e:d3:09:e4:eb:4d: 59:c9 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Subject Key Identifier: 56:FF:B6:FD:ED:A3:76:04:AA:CB:1F:25:FB:A5:8D:9D:9A:D5:85:D3 Signature Algorithm: sha256WithRSAEncryption 1d:6f:b2:e1:22:08:4b:9a:41:aa:6e:11:1a:c8:fb:7b:f3:5e: 99:26:ee:cf:ec:58:5d:7e:72:18:72:87:55:d0:73:73:e3:d9: 74:73:cf:88:70:9f:27:99:52:a2:40:2e:53:70:44:a4:61:24: b1:78:22:63:aa:52:2d:69:a6:91:4d:53:66:5d:e7:7e:bf:8f: 64:97:3c:07:49:5b:ae:cb:49:89:3f:22:a6:b0:04:e8:7f:9a: 86:1a:b8:41:b2:64:c0:18:34:0e:01:98:b5:b3:49:f0:cd:18: b6:c6:62:ea:42:d7:1f:75:dc:f8:46:3f:53:04:cf:e1:05:86: 2d:c0:00:08:88:0b:fb:c4:b8:31:9d:8f:f9:8b:3c:75:ec:1c: 37:6c:ea:fe:5f:5f:46:da:d7:38:96:ef:3a:d8:b8:44:33:d2: e2:bd:d5:64:19:43:37:2a:5b:6c:67:bb:63:77:4c:90:55:3b: a5:b8:47:67:50:56:35:0f:1b:b3:23:fe:32:7b:a9:54:d7:7a: e9:da:be:52:80:43:53:0b:21:7b:a9:b5:6a:4f:00:82:9e:38: d4:b4:14:81:a2:58:a2:ca:13:2f:7a:15:fe:01:8e:7a:f1:d5: c0:4b:93:0f:19:76:bc:40:e5:52:d0:42:3d:17:08:85:e7:0e: 34:b2:2e:d1 -----BEGIN CERTIFICATE----- MIIDPzCCAiegAwIBAgIBATANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzET MBEGA1UECAwKQ2FsaWZvcm5pYTERMA8GA1UECgwITTJDcnlwdG8xGDAWBgNVBAMM D0hlaWtraSBUb2l2b25lbjAeFw0xOTEwMDkwODA1MjBaFw00OTEyMzEwODA1MjNa MEkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMREwDwYDVQQKDAhN MkNyeXB0bzESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA9PM4MQmSDV2LBvBD4GJi4XHrMLrXuVfbjBCbnh52RasUklTU RzSrD5Xzg8XxRXVYcgrhZ3fQ035qb10apN+qlsAPjQqVnqrlvHpvq2FBdTEM2qbV DbNC8CD2LHRpOXmQoMnCI7paxZyP+k8GuwSOLaE2gsQjmRgat1YPiu//VyJRlspp j6OukbeEAge+TVXyHPkRKv8gqw8n+3l1bLJT4wTqT+VRPx6wtX/63g/26OaFoxeM sabd/Om4ktUcc9eCbmBsELMiyqXYxdJBk7NXPxvPz3hMFYWxyraEExuPQu0hu5Ci tzmdaL9N2jEGU5jj3o/4Pn0l8nV+0wnk601ZyQIDAQABoywwKjAJBgNVHRMEAjAA MB0GA1UdDgQWBBRW/7b97aN2BKrLHyX7pY2dmtWF0zANBgkqhkiG9w0BAQsFAAOC AQEAHW+y4SIIS5pBqm4RGsj7e/NemSbuz+xYXX5yGHKHVdBzc+PZdHPPiHCfJ5lS okAuU3BEpGEksXgiY6pSLWmmkU1TZl3nfr+PZJc8B0lbrstJiT8iprAE6H+ahhq4 QbJkwBg0DgGYtbNJ8M0YtsZi6kLXH3Xc+EY/UwTP4QWGLcAACIgL+8S4MZ2P+Ys8 dewcN2zq/l9fRtrXOJbvOti4RDPS4r3VZBlDNypbbGe7Y3dMkFU7pbhHZ1BWNQ8b syP+MnupVNd66dq+UoBDUwshe6m1ak8Agp441LQUgaJYosoTL3oV/gGOevHVwEuT Dxl2vEDlUtBCPRcIhecONLIu0Q== -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA9PM4MQmSDV2LBvBD4GJi4XHrMLrXuVfbjBCbnh52RasUklTU RzSrD5Xzg8XxRXVYcgrhZ3fQ035qb10apN+qlsAPjQqVnqrlvHpvq2FBdTEM2qbV DbNC8CD2LHRpOXmQoMnCI7paxZyP+k8GuwSOLaE2gsQjmRgat1YPiu//VyJRlspp j6OukbeEAge+TVXyHPkRKv8gqw8n+3l1bLJT4wTqT+VRPx6wtX/63g/26OaFoxeM sabd/Om4ktUcc9eCbmBsELMiyqXYxdJBk7NXPxvPz3hMFYWxyraEExuPQu0hu5Ci tzmdaL9N2jEGU5jj3o/4Pn0l8nV+0wnk601ZyQIDAQABAoIBAQCgFpWS9v5NXeWP E1hJPgQB88IShwqWR6VlVTVfkekaf0Vina5fGzzxYr9UT/nvu1Gitxm51cTVdLl7 Lw5K0yNagwum0lQW7vpWxG5XQ6jUPsp33LFB0vbcma5KP4rF1X2AmFwZnaHVpQ00 OpHbiI6jo8lMjYP2epp7V/OwikoHV0873HTmuq2Y+jUvRM3o01moDtuF5mKofNEd ft9lArRG8yjLgC5G1C9cmiATGoMGyHBRkEv+UrUWLHVxrpXviUd+/iJmhrwXcpvj rTrZWbUkSA3i4JMml/qYqNQYeVUFVgV/slD331iIwlWP8RipXF5YqN+YGjGeqL0+ yQ4KWtABAoGBAP7XvGBUWNBSBrqioTzqYMTbwz/YjXJkvlO09wwc/UkraYlSihi0 2J1dKBePIfOk6gFbuiJNYMJvAt1hBCsN0Z6o/bH7CiOh/55nkTaL0R4zB38uuDDx 4qf6+9HT1eC9yW3UJVPwBBwI4WZmmq4peQoipBtKwpY2Q+yoUU3gp4KhAoGBAPYP +6uv3gQYoIpkUD2ZdX8kFoaC6rJMP3Z/N75NfsOz1Tx3nNwexYM6EVVQrvTRWpLZ rJyCgCJi9HY4lPASKSKM1cLCT/M3SdR8OiqlEjziZtSH/di6wq8/Hfqhf75nC7sK wV7Ic0eQ3Bjg2hggPpjeBJTv8NIlCYbWbxHnsK4pAoGAY0I39vUjWpB4Wn05e/Z2 FnbaR6XbAfFHSGc1yhwIc1VbV8c0Tocxz6kXEoYHXVSgaEMH7pBg3ZpLbVp6OyK4 wKlllssGmfZhD5ubLbmri62of9r8luO/ulnBd2qg5VZGfGai21yi3SCAWlggazFw GYiAjrjBrawZLLYqZMDZvcECgYBoi6/taWKWMPR8+FQTaBFA/M9JRXR8XuMT8Md5 Zqm2csDl2Rhfef+HWvOkYQyE3jJydGPfd58DfTHKzQ2S1tR9ZoMoJbEccGBBFKsO FWajUbpJEKKtI+S12sZdB6Mj/dpBFTfFkrtQK98n/tkLKSAPiT0/HpceYjgi/xbf 76XkyQKBgQCkAuuTYi/9vlqYBcUH+23f0XmzQ6NNCqi0JxrnUmPv0Mc/ci7QfBZ6 BkjPxfllpAsDihfTFpfp6p1PCMpASq1J+w1yR+lnKgw9BlbBLT4SqSVVDiju0cfw njm6zQu7IR6Ts/vi+YbVqn3yeP8U5W9as7QL5y6KeYfAhwuPqWhvog== -----END RSA PRIVATE KEY----- m2crypto-0.42.0/tests/server_key.pem000066400000000000000000000032171465575656700174340ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA9PM4MQmSDV2LBvBD4GJi4XHrMLrXuVfbjBCbnh52RasUklTU RzSrD5Xzg8XxRXVYcgrhZ3fQ035qb10apN+qlsAPjQqVnqrlvHpvq2FBdTEM2qbV DbNC8CD2LHRpOXmQoMnCI7paxZyP+k8GuwSOLaE2gsQjmRgat1YPiu//VyJRlspp j6OukbeEAge+TVXyHPkRKv8gqw8n+3l1bLJT4wTqT+VRPx6wtX/63g/26OaFoxeM sabd/Om4ktUcc9eCbmBsELMiyqXYxdJBk7NXPxvPz3hMFYWxyraEExuPQu0hu5Ci tzmdaL9N2jEGU5jj3o/4Pn0l8nV+0wnk601ZyQIDAQABAoIBAQCgFpWS9v5NXeWP E1hJPgQB88IShwqWR6VlVTVfkekaf0Vina5fGzzxYr9UT/nvu1Gitxm51cTVdLl7 Lw5K0yNagwum0lQW7vpWxG5XQ6jUPsp33LFB0vbcma5KP4rF1X2AmFwZnaHVpQ00 OpHbiI6jo8lMjYP2epp7V/OwikoHV0873HTmuq2Y+jUvRM3o01moDtuF5mKofNEd ft9lArRG8yjLgC5G1C9cmiATGoMGyHBRkEv+UrUWLHVxrpXviUd+/iJmhrwXcpvj rTrZWbUkSA3i4JMml/qYqNQYeVUFVgV/slD331iIwlWP8RipXF5YqN+YGjGeqL0+ yQ4KWtABAoGBAP7XvGBUWNBSBrqioTzqYMTbwz/YjXJkvlO09wwc/UkraYlSihi0 2J1dKBePIfOk6gFbuiJNYMJvAt1hBCsN0Z6o/bH7CiOh/55nkTaL0R4zB38uuDDx 4qf6+9HT1eC9yW3UJVPwBBwI4WZmmq4peQoipBtKwpY2Q+yoUU3gp4KhAoGBAPYP +6uv3gQYoIpkUD2ZdX8kFoaC6rJMP3Z/N75NfsOz1Tx3nNwexYM6EVVQrvTRWpLZ rJyCgCJi9HY4lPASKSKM1cLCT/M3SdR8OiqlEjziZtSH/di6wq8/Hfqhf75nC7sK wV7Ic0eQ3Bjg2hggPpjeBJTv8NIlCYbWbxHnsK4pAoGAY0I39vUjWpB4Wn05e/Z2 FnbaR6XbAfFHSGc1yhwIc1VbV8c0Tocxz6kXEoYHXVSgaEMH7pBg3ZpLbVp6OyK4 wKlllssGmfZhD5ubLbmri62of9r8luO/ulnBd2qg5VZGfGai21yi3SCAWlggazFw GYiAjrjBrawZLLYqZMDZvcECgYBoi6/taWKWMPR8+FQTaBFA/M9JRXR8XuMT8Md5 Zqm2csDl2Rhfef+HWvOkYQyE3jJydGPfd58DfTHKzQ2S1tR9ZoMoJbEccGBBFKsO FWajUbpJEKKtI+S12sZdB6Mj/dpBFTfFkrtQK98n/tkLKSAPiT0/HpceYjgi/xbf 76XkyQKBgQCkAuuTYi/9vlqYBcUH+23f0XmzQ6NNCqi0JxrnUmPv0Mc/ci7QfBZ6 BkjPxfllpAsDihfTFpfp6p1PCMpASq1J+w1yR+lnKgw9BlbBLT4SqSVVDiju0cfw njm6zQu7IR6Ts/vi+YbVqn3yeP8U5W9as7QL5y6KeYfAhwuPqWhvog== -----END RSA PRIVATE KEY----- m2crypto-0.42.0/tests/signer.pem000066400000000000000000000100701465575656700165400ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 3 (0x3) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=California, O=M2Crypto, CN=Heikki Toivonen Validity Not Before: Oct 9 07:58:35 2019 GMT Not After : Dec 31 07:58:37 2049 GMT Subject: C=US, ST=California, O=M2Crypto, CN=Signer/emailAddress=signer@example.com Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:c8:85:86:3d:72:aa:91:d8:7b:11:02:05:92:b7: 1b:bf:9f:35:be:88:56:db:96:f2:70:3e:98:3c:c3: 62:42:ff:54:74:7a:63:e7:a9:4c:ae:52:48:a2:4f: ab:c5:6b:1d:de:39:b8:f0:89:36:15:f7:70:3d:a8: a6:c3:49:3e:10:d8:ae:ba:cf:1a:e6:dd:0b:d8:cd: d9:00:ea:57:f2:7c:2e:6d:89:80:95:68:b1:fd:06: bc:ea:ba:44:c1:fa:20:87:57:d3:ac:e5:b4:5d:ba: 4f:10:20:82:5b:1b:27:75:b3:0c:ce:4f:79:3f:49: 8e:e3:ba:14:30:cf:8a:82:11:65:59:78:7b:41:16: 43:e8:ea:7f:a4:60:52:46:93:53:4e:de:87:3f:50: 8a:56:c5:d3:04:5c:3c:a2:d3:b0:64:d8:ce:1e:75: ad:ce:cd:91:b1:58:cc:2d:a6:dc:da:b5:b2:c2:0e: 2f:68:74:a7:a5:6e:61:4c:01:f2:d0:7d:83:66:78: 66:9f:b9:87:33:cc:59:dc:03:82:6f:bb:98:0c:e9: 10:63:12:ee:e9:05:c1:5b:98:7e:94:65:98:df:31: bf:59:90:f0:1c:6c:ac:2c:1b:dd:90:71:ab:11:95: 8b:9c:f7:2a:2f:c0:0f:2d:b1:c8:5a:65:d6:a9:34: 44:81 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Subject Key Identifier: 68:03:33:27:D9:87:9A:EA:7D:41:D8:2D:EB:F9:EE:AB:C9:6A:C5:FA Signature Algorithm: sha256WithRSAEncryption 0d:5e:9e:04:7d:db:b6:4a:cf:4b:2d:e5:e4:2d:fe:ea:fb:26: f0:1d:24:36:1c:93:d9:9c:fd:d8:78:b0:48:a8:87:d0:91:8a: 46:3a:b4:1e:48:2c:f1:c2:1f:7c:03:a2:3f:3b:91:ad:55:1c: 2c:42:09:19:5f:dc:be:2d:bd:e5:74:1e:2b:34:4b:8c:af:4d: 89:b6:da:6a:eb:e3:6f:ec:40:47:1b:53:3c:e3:5a:c3:03:52: 0c:64:96:d2:24:2f:8a:d9:e3:e9:9b:0a:10:5c:fa:10:77:c0: b6:eb:3a:1d:d0:76:67:55:57:71:4e:f9:91:45:14:30:74:b4: 6d:88:48:6c:33:d1:9e:a4:a3:5e:8f:56:57:42:88:ce:30:5c: 64:8d:d4:aa:e8:4d:47:89:bd:97:4f:43:b1:51:b4:40:41:16: de:d2:5d:8c:6d:83:96:18:98:d1:01:03:c7:06:44:1c:32:60: eb:f8:1a:ee:8a:28:5d:ae:2c:06:9f:3d:b1:b9:2f:0c:fe:0f: 8d:d2:ab:d8:50:59:9f:0d:be:70:66:01:2c:73:f7:a1:fb:2b: f0:6f:09:8d:89:90:7b:2f:9d:49:99:be:ee:2b:e2:41:9f:fa: 64:d2:0e:e1:1a:81:ee:4f:48:4f:3e:00:e9:07:bc:4c:07:de: 18:80:4f:83 -----BEGIN CERTIFICATE----- MIIDXzCCAkegAwIBAgIBAzANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzET MBEGA1UECAwKQ2FsaWZvcm5pYTERMA8GA1UECgwITTJDcnlwdG8xGDAWBgNVBAMM D0hlaWtraSBUb2l2b25lbjAeFw0xOTEwMDkwNzU4MzVaFw00OTEyMzEwNzU4Mzda MGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMREwDwYDVQQKDAhN MkNyeXB0bzEPMA0GA1UEAwwGU2lnbmVyMSEwHwYJKoZIhvcNAQkBFhJzaWduZXJA ZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIhYY9 cqqR2HsRAgWStxu/nzW+iFbblvJwPpg8w2JC/1R0emPnqUyuUkiiT6vFax3eObjw iTYV93A9qKbDST4Q2K66zxrm3QvYzdkA6lfyfC5tiYCVaLH9BrzqukTB+iCHV9Os 5bRduk8QIIJbGyd1swzOT3k/SY7juhQwz4qCEWVZeHtBFkPo6n+kYFJGk1NO3oc/ UIpWxdMEXDyi07Bk2M4eda3OzZGxWMwtptzatbLCDi9odKelbmFMAfLQfYNmeGaf uYczzFncA4Jvu5gM6RBjEu7pBcFbmH6UZZjfMb9ZkPAcbKwsG92QcasRlYuc9yov wA8tschaZdapNESBAgMBAAGjLDAqMAkGA1UdEwQCMAAwHQYDVR0OBBYEFGgDMyfZ h5rqfUHYLev57qvJasX6MA0GCSqGSIb3DQEBCwUAA4IBAQANXp4Efdu2Ss9LLeXk Lf7q+ybwHSQ2HJPZnP3YeLBIqIfQkYpGOrQeSCzxwh98A6I/O5GtVRwsQgkZX9y+ Lb3ldB4rNEuMr02Jttpq6+Nv7EBHG1M841rDA1IMZJbSJC+K2ePpmwoQXPoQd8C2 6zod0HZnVVdxTvmRRRQwdLRtiEhsM9GepKNej1ZXQojOMFxkjdSq6E1Hib2XT0Ox UbRAQRbe0l2MbYOWGJjRAQPHBkQcMmDr+BruiihdriwGnz2xuS8M/g+N0qvYUFmf Db5wZgEsc/eh+yvwbwmNiZB7L51Jmb7uK+JBn/pk0g7hGoHuT0hPPgDpB7xMB94Y gE+D -----END CERTIFICATE----- m2crypto-0.42.0/tests/signer_key.pem000066400000000000000000000032131465575656700174110ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAyIWGPXKqkdh7EQIFkrcbv581vohW25bycD6YPMNiQv9UdHpj 56lMrlJIok+rxWsd3jm48Ik2FfdwPaimw0k+ENiuus8a5t0L2M3ZAOpX8nwubYmA lWix/Qa86rpEwfogh1fTrOW0XbpPECCCWxsndbMMzk95P0mO47oUMM+KghFlWXh7 QRZD6Op/pGBSRpNTTt6HP1CKVsXTBFw8otOwZNjOHnWtzs2RsVjMLabc2rWywg4v aHSnpW5hTAHy0H2DZnhmn7mHM8xZ3AOCb7uYDOkQYxLu6QXBW5h+lGWY3zG/WZDw HGysLBvdkHGrEZWLnPcqL8APLbHIWmXWqTREgQIDAQABAoIBAFniSI9I1B62PEwe bOMcQ0r9EflLYivimOApntI1/tjrXS8tIZVZdW76oWZociX3YxcXJshjqSPlm6F3 9PC65yBkEMbaSUPNOB9B/pEDetLOSX1+Um4m1QoHuC07u9B7z5L7kn4BJX2SIxim iehO3rxKu2XLiB0PWwbHhX9vuLWeTTnozC5BjCpLe1/bj7j9L8llbyO+XyAwthJ6 ZdfF/pv7ERT3JUfGqhIm9u4aXTWC/6brVlXSUvrJ+9gKJtxUyz5i5+BD/xPU9Lvb H8/3CqSpEmoCtCXxTfs7MD1b9UTzJhldJZmTu7KWTLd+sARNmkaA729tUB+N4usd tbQSlAUCgYEA7sgYTl14iAvEkPjsd3ytH7BkizZr0w7/RQMilR8afyQENoNjkPx6 kYrjgPuuM9oWeIRbn0FruCKrc3lTS+ilym8k+UxUo3m8Fb662Rw+R6Alrrh1E2Y5 Ugic9U6kFvZmlf8tsdjVKCM6EqO0jvPDIrTbMyOwNbQDvNESXFBXDv8CgYEA1vsm T8Wh8qknLDCSoOUP/1QCyR/OvVczisvYlT054/vXluHWbRtrlcAOXlBUUrtgV/vP DETVAkEXPjiNbNsANENf0QZKhGBd8L8Orer0O6Bc8bsGTkFVMp/XWbAIpUFe7fOy Ot4sA4WpfuK0fKdRyBwG9s8FOw8n+usRpJiQLH8CgYAZ8uDBU2MP1ceMwaBg88mU kgS7JDTfgNe41jhh4Dlu66kRi4G8ddOUEXXbxH4P4Hlkq22Rhvh/0DS1nc+xhhzO PPnVpbfk9Au+iTWg9nLGMd8md6ExdIByK8Fy3xLx8+D+F/cNRrUTYZCkCepLRq5E DUds7Unu7Bsj38yQ/6IWXQKBgDbVYHRAaIpIcuFmkj/PrUDm4L8ECetpbpAcZmXK dBWeiuLFP7gcolhT4FZWDuv7Nxu58pmihOJKT+9i5U+6nFa4SJw8Co2xNsTNNqVN pHYA9TQDDByxtVVwR7FsoQfloJz456D0Qi2zzgO7N2YEF2v/GhehvifOOdhaVOmy sDNpAoGBAM/b+jI8eQGtNGbdRWkuHH2gRgmm1n900brEYlTWCHBSGePyghWJj3Uu oiuxsHV22CAUuOlDpOWeZUsNlpa+8dOBYAxZUvkH99y4jukNCCAKvFwI0MS+FUoW DKida/MnaVqE6+1KDC/l6LjXDAP1JcwS0PimBXMqVNYScb2q7eAl -----END RSA PRIVATE KEY----- m2crypto-0.42.0/tests/te_chunked_response.txt000066400000000000000000000001411465575656700213340ustar00rootroot00000000000000HTTP/1.1 200 ok Content-Type: text/plain Transfer-Encoding: chunked 4 foo 7 foobar 0 m2crypto-0.42.0/tests/test_aes.py000066400000000000000000000045261465575656700167400ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import absolute_import, print_function """Unit tests for _aes.i. Copyright (c) 2018 Matej Cepl. All rights reserved. """ import logging from M2Crypto import m2 from tests import unittest log = logging.getLogger('test_AES') KEY_TEXT = (b'blabulka' * 3)[:16] # 128/8 == 16 class AESTestCase(unittest.TestCase): """ Functions in AES module are very low level, and you are HIGHLY encouraged NOT to use them. Use functions from EVP module instead. These tests are here only for checking regressions, not as an illustration for the real world use. """ def test_existing_methods(self): missing = [] exp_mtds = ('aes_128_cbc', 'aes_128_cfb', 'aes_128_ctr', 'aes_128_ecb', 'aes_128_ofb', 'aes_192_cbc', 'aes_192_cfb', 'aes_192_ctr', 'aes_192_ecb', 'aes_192_ofb', 'aes_256_cbc', 'aes_256_cfb', 'aes_256_ctr', 'aes_256_ecb', 'aes_256_ofb') for name in exp_mtds: if not hasattr(m2, name): missing.append(name) self.assertEqual(missing, []) def test_set_key(self): key = m2.aes_new() m2.AES_set_key(key, KEY_TEXT, 128, 1) m2.AES_free(key) key2 = m2.aes_new() m2.AES_set_key(key2, KEY_TEXT, 128, 0) m2.AES_free(key2) # Just to make sure nothing crashed def test_type_check(self): key = m2.aes_new() m2.AES_set_key(key, KEY_TEXT, 128, 1) res = m2.AES_type_check(key) m2.AES_free(key) self.assertEqual(res, 1) # Just to make sure nothing crashed def test_crypt(self): padded = b'zezulicka ' # len(padded) % 16 == 0 key = m2.aes_new() # op == 0: encrypt # otherwise: decrypt (Python code will supply the value 1.) m2.AES_set_key(key, KEY_TEXT, 128, 0) enc = m2.AES_crypt(key, padded, len(padded), 0) m2.AES_free(key) key2 = m2.aes_new() m2.AES_set_key(key2, KEY_TEXT, 128, 1) observed = m2.AES_crypt(key2, enc, len(enc), 1) m2.AES_free(key2) self.assertEqual(padded, observed) def suite(): t_suite = unittest.TestSuite() t_suite.addTest(unittest.TestLoader().loadTestsFromTestCase(AESTestCase)) return t_suite if __name__ == '__main__': unittest.main() m2crypto-0.42.0/tests/test_asn1.py000066400000000000000000000131531465575656700170260ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.ASN1. Copyright (c) 2005 Open Source Applications Foundation. All rights reserved.""" import datetime import platform import time from M2Crypto import ASN1, m2 from M2Crypto.util import is_32bit, expectedFailureIf from tests import unittest class ASN1TestCase(unittest.TestCase): def test_Integer(self): a_int = ASN1.ASN1_Integer(42, 1) self.assertEqual(int(a_int), 42) def test_String(self): # Currently we are supporting only ASCII strings, support for # Unicode strings is unclear. # a_str = ASN1.ASN1_String("дощови́й черв'я́к", 1) # self.assertEqual(str(a_str), "дощови́й черв'я́к") a_str = ASN1.ASN1_String("zizalka", 1) self.assertEqual(str(a_str), "zizalka") a_str = ASN1.ASN1_String(b"zizalka", 1) self.assertEqual(bytes(a_str), b"zizalka") def test_String_legacy(self): # Old API, which expects ASN1_String on __init__ is still supported asn1ptr = m2.asn1_string_new() # FIXME this is probably wrong ... asn1_string_set should have # Python string as its parameter. text = b'hello there' # In RFC2253 format: # #040B68656C6C6F207468657265 # h e l l o t h e r e m2.asn1_string_set(asn1ptr, text) a = ASN1.ASN1_String(asn1ptr, 1) self.assertEqual(a.as_text(), 'hello there', a.as_text()) self.assertEqual(a.as_text(flags=m2.ASN1_STRFLGS_RFC2253), '#040B68656C6C6F207468657265', a.as_text(flags=m2.ASN1_STRFLGS_RFC2253)) self.assertEqual(a.as_text(), str(a)) def test_Object(self): pass # XXX Dunno how to test @unittest.skipIf(platform.system() == 'Windows', 'Skip on Windows.') def test_TIME(self): asn1 = ASN1.ASN1_TIME() self.assertEqual(str(asn1), 'Bad time value') format = '%b %d %H:%M:%S %Y GMT' utcformat = '%y%m%d%H%M%SZ' s = '990807053011Z' asn1.set_string(s) self.assertEqual(str(asn1), 'Aug 7 05:30:11 1999 GMT') t1 = time.strptime(str(asn1), format) t2 = time.strptime(s, utcformat) self.assertEqual(t1, t2) asn1.set_time(500) self.assertEqual(str(asn1), 'Jan 1 00:08:20 1970 GMT') t1 = time.strftime(format, time.strptime(str(asn1), format)) t2 = time.strftime(format, time.gmtime(500)) self.assertEqual(t1, t2) t = int(time.time()) + time.timezone asn1.set_time(t) t1 = time.strftime(format, time.strptime(str(asn1), format)) t2 = time.strftime(format, time.gmtime(t)) self.assertEqual(t1, t2) @unittest.skipIf(platform.system() == 'Windows', 'Skip on Windows.') def test_UTCTIME(self): asn1 = ASN1.ASN1_UTCTIME() self.assertEqual(str(asn1), 'Bad time value') format = '%b %d %H:%M:%S %Y GMT' utcformat = '%y%m%d%H%M%SZ' s = '990807053011Z' asn1.set_string(s) # self.assertEqual(str(asn1), 'Aug 7 05:30:11 1999 GMT') t1 = time.strptime(str(asn1), format) t2 = time.strptime(s, utcformat) self.assertEqual(t1, t2) asn1.set_time(500) # self.assertEqual(str(asn1), 'Jan 1 00:08:20 1970 GMT') t1 = time.strftime(format, time.strptime(str(asn1), format)) t2 = time.strftime(format, time.gmtime(500)) self.assertEqual(t1, t2) t = int(time.time()) + time.timezone asn1.set_time(t) t1 = time.strftime(format, time.strptime(str(asn1), format)) t2 = time.strftime(format, time.gmtime(t)) self.assertEqual(t1, t2) @unittest.skipIf(platform.system() == 'Windows', 'Skip on Windows.') def test_TIME_datetime(self): asn1 = ASN1.ASN1_TIME() # Test get_datetime and set_datetime t = time.time() dt = datetime.datetime.fromtimestamp(int(t)) udt = dt.replace(tzinfo=ASN1.LocalTimezone()).astimezone(ASN1.UTC) asn1.set_time(int(t)) t1 = str(asn1) asn1.set_datetime(dt) t2 = str(asn1) self.assertEqual(t1, t2) self.assertEqual(str(udt), str(asn1.get_datetime())) dt = dt.replace(tzinfo=ASN1.LocalTimezone()) asn1.set_datetime(dt) t2 = str(asn1) self.assertEqual(t1, t2) self.assertEqual(str(udt), str(asn1.get_datetime())) dt = dt.astimezone(ASN1.UTC) asn1.set_datetime(dt) t2 = str(asn1) self.assertEqual(t1, t2) self.assertEqual(str(udt), str(asn1.get_datetime())) @unittest.skipIf(platform.system() == 'Windows', 'Skip on Windows.') def test_UTCTIME_datetime(self): asn1 = ASN1.ASN1_UTCTIME() # Test get_datetime and set_datetime t = time.time() dt = datetime.datetime.fromtimestamp(int(t)) udt = dt.replace(tzinfo=ASN1.LocalTimezone()).astimezone(ASN1.UTC) asn1.set_time(int(t)) t1 = str(asn1) asn1.set_datetime(dt) t2 = str(asn1) self.assertEqual(t1, t2) self.assertEqual(str(udt), str(asn1.get_datetime())) dt = dt.replace(tzinfo=ASN1.LocalTimezone()) asn1.set_datetime(dt) t2 = str(asn1) self.assertEqual(t1, t2) self.assertEqual(str(udt), str(asn1.get_datetime())) dt = dt.astimezone(ASN1.UTC) asn1.set_datetime(dt) t2 = str(asn1) self.assertEqual(t1, t2) self.assertEqual(str(udt), str(asn1.get_datetime())) def suite(): return unittest.TestLoader().loadTestsFromTestCase(ASN1TestCase) if __name__ == '__main__': unittest.TextTestRunner().run(suite()) m2crypto-0.42.0/tests/test_authcookie.py000077500000000000000000000136751465575656700203330ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.AuthCookie. Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.""" import logging import time from M2Crypto import EVP, Rand, util from M2Crypto.AuthCookie import AuthCookie, AuthCookieJar, mix, unmix, unmix3 from http.cookies import SimpleCookie # pylint: disable=no-name-in-module,import-error from tests import unittest log = logging.getLogger(__name__) class AuthCookieTestCase(unittest.TestCase): _format = 'Set-Cookie: _M2AUTH_="exp=%f&data=%s&digest=%s"' _token = '_M2AUTH_' def setUp(self): self.data = 'cogitoergosum' self.exp = time.time() + 3600 self.jar = AuthCookieJar() def tearDown(self): pass def _corrupt_part_str(self, s, fr, to): # type: (str, int, int) -> str out = s[:fr] + ''.join([chr(ord(x) + 13) for x in s[fr:to]]) + s[to:] self.assertNotEqual(s, out) return out def test_encode_part_str(self): a_str = 'a1b2c3d4e5f6h7i8j9' self.assertEqual(self._corrupt_part_str(a_str, 3, 5), 'a1b?p3d4e5f6h7i8j9') def test_mix_unmix(self): dough = mix(self.exp, self.data) exp, data = unmix(dough) self.assertEqual(data, self.data) # we are comparing seconds here, ten-thousandth # second should be enough. self.assertAlmostEqual(exp, self.exp, places=4) def test_make_cookie(self): c = self.jar.makeCookie(self.exp, self.data) self.assertTrue(isinstance(c, AuthCookie)) self.assertEqual(c.expiry(), self.exp) self.assertEqual(c.data(), self.data) # Peek inside the cookie jar... key = self.jar._key # pylint: disable=protected-access mac = util.bin_to_hex( EVP.hmac(key, mix(self.exp, self.data).encode(), 'sha1')) self.assertEqual(c.mac(), mac) # Ok, stop peeking now. cookie_str = self._format % (self.exp, self.data, mac) self.assertEqual(c.output(), cookie_str) def test_make_cookie_invalid(self): with self.assertRaises(ValueError): self.jar.makeCookie("complete nonsense", self.data) def test_expired(self): t = self.exp - 7200 c = self.jar.makeCookie(t, self.data) self.assertTrue(c.isExpired()) def test_not_expired(self): c = self.jar.makeCookie(self.exp, self.data) self.assertFalse(c.isExpired()) def test_is_valid(self): c = self.jar.makeCookie(self.exp, self.data) self.assertTrue(self.jar.isGoodCookie(c)) def test_is_invalid_expired(self): t = self.exp - 7200 c = self.jar.makeCookie(t, self.data) self.assertFalse(self.jar.isGoodCookie(c)) def test_is_invalid_changed_exp(self): c = self.jar.makeCookie(self.exp, self.data) c._expiry = 0 # pylint: disable=protected-access self.assertFalse(self.jar.isGoodCookie(c)) def test_is_invalid_changed_data(self): c = self.jar.makeCookie(self.exp, self.data) c._data = 'this is bad' # pylint: disable=protected-access self.assertFalse(self.jar.isGoodCookie(c)) def test_is_invalid_changed_mac(self): c = self.jar.makeCookie(self.exp, self.data) c._mac = 'this is bad' # pylint: disable=protected-access self.assertFalse(self.jar.isGoodCookie(c)) def test_mix_unmix3(self): c = self.jar.makeCookie(self.exp, self.data) s = SimpleCookie() s.load(c.output(header="")) exp, data, digest = unmix3(s[self._token].value) self.assertEqual(data, self.data) # see comment in test_mix_unmix self.assertAlmostEqual(exp, self.exp, places=4) key = self.jar._key # pylint: disable=protected-access mac = util.bin_to_hex( EVP.hmac(key, mix(self.exp, self.data).encode(), 'sha1')) self.assertEqual(digest, mac) def test_cookie_str(self): c = self.jar.makeCookie(self.exp, self.data) self.assertTrue(self.jar.isGoodCookieString(c.output(header=""))) def test_cookie_str2(self): c = self.jar.makeCookie(self.exp, self.data) s = SimpleCookie() s.load(c.output(header="")) self.assertTrue(self.jar.isGoodCookieString(s.output(header=""))) def test_cookie_str_expired(self): t = self.exp - 7200 c = self.jar.makeCookie(t, self.data) s = SimpleCookie() s.load(c.output(header="")) self.assertFalse(self.jar.isGoodCookieString(s.output(header=""))) def test_cookie_str_arbitrary_change(self): c = self.jar.makeCookie(self.exp, self.data) cout = c.output(header="") cout_str = cout[:20] + 'this is bad' + cout[20:] s = SimpleCookie() s.load(cout_str) self.assertFalse(self.jar.isGoodCookieString(s.output(header=""))) def test_cookie_str_changed_exp(self): c = self.jar.makeCookie(self.exp, self.data) cout = c.output(header="") cout_str = self._corrupt_part_str(cout, 14, 16) s = SimpleCookie() s.load(cout_str) self.assertFalse(self.jar.isGoodCookieString(s.output(header=""))) def test_cookie_str_changed_data(self): c = self.jar.makeCookie(self.exp, self.data) cout = c.output(header="") cout_str = self._corrupt_part_str(cout, 24, 26) s = SimpleCookie() s.load(cout_str) self.assertFalse(self.jar.isGoodCookieString(s.output(header=""))) def test_cookie_str_changed_mac(self): c = self.jar.makeCookie(self.exp, self.data) cout = c.output(header="") cout_str = self._corrupt_part_str(cout, 64, 66) s = SimpleCookie() s.load(cout_str) self.assertFalse(self.jar.isGoodCookieString(s.output(header=""))) def suite(): return unittest.TestLoader().loadTestsFromTestCase(AuthCookieTestCase) if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_bio.py000066400000000000000000000052051465575656700167340ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import absolute_import """ Unit tests for M2Crypto.BIO. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. Copyright (c) 2006 Open Source Applications Foundation Author: Heikki Toivonen """ import logging from M2Crypto import BIO, Rand, m2 from tests import unittest from tests.fips import fips_mode log = logging.getLogger('test_bio') ciphers = [ 'des_ede_ecb', 'des_ede_cbc', 'des_ede_cfb', 'des_ede_ofb', 'des_ede3_ecb', 'des_ede3_cbc', 'des_ede3_cfb', 'des_ede3_ofb', 'aes_128_ecb', 'aes_128_cbc', 'aes_128_cfb', 'aes_128_ofb', 'aes_192_ecb', 'aes_192_cbc', 'aes_192_cfb', 'aes_192_ofb', 'aes_256_ecb', 'aes_256_cbc', 'aes_256_cfb', 'aes_256_ofb'] nonfips_ciphers = ['bf_ecb', 'bf_cbc', 'bf_cfb', 'bf_ofb', # 'idea_ecb', 'idea_cbc', 'idea_cfb', 'idea_ofb', 'cast5_ecb', 'cast5_cbc', 'cast5_cfb', 'cast5_ofb', # 'rc5_ecb', 'rc5_cbc', 'rc5_cfb', 'rc5_ofb', 'des_ecb', 'des_cbc', 'des_cfb', 'des_ofb', 'rc4', 'rc2_40_cbc'] if not fips_mode and m2.OPENSSL_VERSION_NUMBER < 0x30000000: # Forbidden ciphers ciphers += nonfips_ciphers class CipherStreamTestCase(unittest.TestCase): def try_algo(self, algo): data = b'123456789012345678901234' my_key = 3 * 15 * b"key" my_IV = 3 * 16 * b'IV' # Encrypt. mem = BIO.MemoryBuffer() cf = BIO.CipherStream(mem) cf.set_cipher(algo, my_key, my_IV, 1) cf.write(data) cf.flush() cf.write_close() cf.close() ciphertext = mem.read() # Decrypt. mem = BIO.MemoryBuffer(ciphertext) cf = BIO.CipherStream(mem) cf.set_cipher(algo, my_key, my_IV, 0) cf.write_close() data2 = cf.read() cf.close() self.assertFalse(cf.readable()) with self.assertRaises(IOError): cf.read() with self.assertRaises(IOError): cf.readline() with self.assertRaises(IOError): cf.readlines() self.assertEqual(data, data2, '%s algorithm cipher test failed' % algo) def test_algo(self): for algo in ciphers: with self.subTest(algo=algo): self.try_algo(algo) def test_nosuchalgo(self): with self.assertRaises(ValueError): self.try_algo('nosuchalgo4567') def suite(): return unittest.TestLoader().loadTestsFromTestCase(CipherStreamTestCase) if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_bio_file.py000066400000000000000000000101321465575656700177260ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.BIO.File. Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.""" import logging import os import platform import tempfile import ctypes if platform.system() == 'Windows': import ctypes.wintypes from M2Crypto.BIO import File, openfile from tests import unittest log = logging.getLogger(__name__) def getCountProcHandles(): PROCESS_QUERY_INFORMATION = 0x400 handle = ctypes.windll.kernel32.OpenProcess( PROCESS_QUERY_INFORMATION, 0, os.getpid()) hndcnt = ctypes.wintypes.DWORD() ctypes.windll.kernel32.GetProcessHandleCount( handle, ctypes.byref(hndcnt)) sys_value = hndcnt.value ctypes.windll.kernel32.CloseHandle(handle) return sys_value + 1 class FileTestCase(unittest.TestCase): def setUp(self): self.data = b'abcdef' * 64 self.fd, self.fname = tempfile.mkstemp() if platform.system() in ['Linux', 'Darwin', 'FreeBSD']: self.__dev_fd = "/dev/fd/" self.fd_count = self.__mfd() def __mfd(self): if hasattr(self, '__dev_fd'): return len(os.listdir(self.__dev_fd)) elif platform.system() == 'Windows': return getCountProcHandles() else: return None def tearDown(self): self.assertEqual(self.fd_count, self.__mfd(), "last test did not close all file descriptors properly") try: os.close(self.fd) except OSError: pass def test_openfile_rb(self): # First create the file using Python's open(). with open(self.fname, 'wb') as f: f.write(self.data) # Now open the file using M2Crypto.BIO.openfile(). with openfile(self.fname, 'rb') as f: data = f.read(len(self.data)) self.assertEqual(data, self.data) def test_openfile_wb(self): # First create the file using M2Crypto.BIO.openfile(). with openfile(self.fname, 'wb') as f: f.write(self.data) # Now open the file using Python's open(). with open(self.fname, 'rb') as f: data = f.read(len(self.data)) self.assertEqual(data, self.data) def test_closed(self): f = openfile(self.fname, 'wb') f.write(self.data) f.close() with self.assertRaises(IOError): f.write(self.data) def test_use_pyfile(self): # First create the file. with open(self.fname, 'wb') as f: f2 = File(f) f2.write(self.data) f2.close() # Now read the file. with open(self.fname, 'rb') as f: in_data = f.read(len(self.data)) self.assertEqual(len(in_data), len(self.data)) self.assertEqual(in_data, self.data) def test_readline_bin(self): with open(self.fname, 'wb') as f: f.write(b'hello\nworld\n') with openfile(self.fname, 'rb') as f: self.assertTrue(f.readable()) self.assertEqual(f.readline(), b'hello\n') self.assertEqual(f.readline(), b'world\n') with openfile(self.fname, 'rb') as f: self.assertEqual( f.readlines(), [b'hello\n', b'world\n']) def test_readline(self): sep = os.linesep.encode() with open(self.fname, 'w') as f: f.write('hello\nworld\n') with openfile(self.fname, 'rb') as f: self.assertTrue(f.readable()) self.assertEqual(f.readline(), b'hello' + sep) self.assertEqual(f.readline(), b'world' + sep) with openfile(self.fname, 'rb') as f: self.assertEqual( f.readlines(), [b'hello' + sep, b'world' + sep]) def test_tell_seek(self): with open(self.fname, 'w') as f: f.write('hello world') with openfile(self.fname, 'r') as f: # Seek absolute f.seek(6) self.assertEqual(f.tell(), 6) def suite(): return unittest.TestLoader().loadTestsFromTestCase(FileTestCase) if __name__ == '__main__': unittest.TextTestRunner().run(suite()) m2crypto-0.42.0/tests/test_bio_iobuf.py000066400000000000000000000045251465575656700201240ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.BIO.IOBuffer. Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" from io import BytesIO from M2Crypto.BIO import IOBuffer, MemoryBuffer from tests import unittest class IOBufferTestCase(unittest.TestCase): def setUp(self): self._data = b'abcdef\n' self.data = self._data * 1024 def tearDown(self): pass def test_init_empty(self): mb = MemoryBuffer() io = IOBuffer(mb) out = io.read() self.assertEqual(out, b'') def test_init_something(self): mb = MemoryBuffer(self.data) io = IOBuffer(mb) out = io.read(len(self.data)) self.assertEqual(out, self.data) def test_read_less_than(self): chunk = len(self.data) - 7 mb = MemoryBuffer(self.data) io = IOBuffer(mb) out = io.read(chunk) self.assertEqual(out, self.data[:chunk]) def test_read_more_than(self): chunk = len(self.data) + 8 mb = MemoryBuffer(self.data) io = IOBuffer(mb) out = io.read(chunk) self.assertEqual(out, self.data) def test_readline(self): buf = BytesIO() mb = MemoryBuffer(self.data) io = IOBuffer(mb) while 1: out = io.readline() if not out: break buf.write(out) self.assertEqual(out, self._data) self.assertEqual(buf.getvalue(), self.data) def test_readlines(self): buf = BytesIO() mb = MemoryBuffer(self.data) io = IOBuffer(mb) lines = io.readlines() for line in lines: self.assertEqual(line, self._data) buf.write(line) self.assertEqual(buf.getvalue(), self.data) def test_closed(self): mb = MemoryBuffer(self.data) io = IOBuffer(mb) io.close() with self.assertRaises(IOError): io.write(self.data) assert not io.readable() and not io.writeable() def test_read_only(self): mb = MemoryBuffer(self.data) io = IOBuffer(mb, mode='r') with self.assertRaises(IOError): io.write(self.data) assert not io.writeable() def suite(): return unittest.TestLoader().loadTestsFromTestCase(IOBufferTestCase) if __name__ == '__main__': unittest.TextTestRunner().run(suite()) m2crypto-0.42.0/tests/test_bio_membuf.py000066400000000000000000000073551465575656700202770ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.BIO.MemoryBuffer. Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" import os import multiprocessing from platform import system from sys import version_info from M2Crypto import m2 from M2Crypto.BIO import MemoryBuffer from tests import unittest class TimeLimitExpired(Exception): pass def time_limit(timeout, func, exc_msg, *args, **kwargs): # multiprocessing.get_context() available in Python >= 3.4 # Python >=3.8 on MacOS changed start_method to 'spawn' as default. # This creates a new context with the previous 'fork' # start_method. Fixes issue #286. if system() == 'Darwin' and version_info >= (3, 8): start_method = 'fork' else: # use default context start_method = None mp = multiprocessing.get_context(start_method) p = mp.Process(target=func) p.start() p.join(timeout) if p.is_alive(): p.terminate() raise TimeLimitExpired(exc_msg) class MemoryBufferTestCase(unittest.TestCase): def setUp(self): self.data = b'abcdef' * 64 def tearDown(self): pass def test_init_empty(self): mb = MemoryBuffer() self.assertEqual(len(mb), 0) out = mb.read() assert out is None def test_init_empty_cm(self): with MemoryBuffer() as mb: self.assertEqual(len(mb), 0) out = mb.read() assert out is None def test_init_something(self): mb = MemoryBuffer(self.data) self.assertEqual(len(mb), len(self.data)) out = mb.read() self.assertEqual(out, self.data) def test_init_something_result_bytes(self): mb = MemoryBuffer(self.data) self.assertEqual(len(mb), len(self.data)) out = mb.read() self.assertIsInstance(out, bytes) def test_init_something_cm(self): with MemoryBuffer(self.data) as mb: self.assertEqual(len(mb), len(self.data)) out = mb.read() self.assertEqual(out, self.data) def test_read_less_than(self): chunk = len(self.data) - 7 mb = MemoryBuffer(self.data) out = mb.read(chunk) self.assertEqual(out, self.data[:chunk]) self.assertEqual(len(mb), (len(self.data)) - chunk) def test_read_more_than(self): chunk = len(self.data) + 8 mb = MemoryBuffer(self.data) out = mb.read(chunk) self.assertEqual(out, self.data) self.assertEqual(len(mb), 0) def test_write_close(self): mb = MemoryBuffer(self.data) assert mb.writeable() mb.write_close() assert mb.readable() with self.assertRaises(IOError): mb.write(self.data) assert not mb.writeable() def test_closed(self): mb = MemoryBuffer(self.data) mb.close() with self.assertRaises(IOError): mb.write(self.data) m2.err_clear_error() assert mb.readable() and not mb.writeable() def test_readline(self): # test against possible endless loop # http://stackoverflow.com/questions/9280550/ timeout_secs = 10 time_limit(timeout_secs, run_test, 'The readline() should not timeout!') def run_test(*args, **kwargs): sep = os.linesep.encode() with MemoryBuffer(b'hello' + sep + b'world' + sep) as mb: assert mb.readable() assert mb.readline() == b'hello' + sep assert mb.readline() == b'world' + sep with MemoryBuffer(b'hello' + sep + b'world' + sep) as mb: assert mb.readlines() == [b'hello' + sep, b'world' + sep] def suite(): return unittest.TestLoader().loadTestsFromTestCase(MemoryBufferTestCase) if __name__ == '__main__': unittest.TextTestRunner().run(suite()) m2crypto-0.42.0/tests/test_bio_ssl.py000066400000000000000000000116721465575656700176220ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import absolute_import, print_function """Unit tests for M2Crypto.BIO.File. Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.""" import socket import sys import threading from M2Crypto import BIO from M2Crypto import SSL from M2Crypto import Err from M2Crypto import Rand from M2Crypto import threading as m2threading from tests import unittest from tests.test_ssl import srv_host, allocate_srv_port class HandshakeClient(threading.Thread): def __init__(self, host, port): threading.Thread.__init__(self) self.host = host self.port = port def run(self): ctx = SSL.Context() ctx.load_cert_chain("tests/server.pem") conn = SSL.Connection(ctx) cipher_list = conn.get_cipher_list() sslbio = BIO.SSLBio() readbio = BIO.MemoryBuffer() writebio = BIO.MemoryBuffer() sslbio.set_ssl(conn) conn.set_bio(readbio, writebio) conn.set_connect_state() sock = socket.socket() sock.connect((self.host, self.port)) handshake_complete = False while not handshake_complete: ret = sslbio.do_handshake() if ret <= 0: if not sslbio.should_retry() or not sslbio.should_read(): err_string = Err.get_error() print(err_string) sys.exit("unrecoverable error in handshake - client") else: output_token = writebio.read() if output_token is not None: sock.sendall(output_token) else: input_token = sock.recv(1024) readbio.write(input_token) else: handshake_complete = True output_token = writebio.read() if output_token is not None: sock.sendall(output_token) sock.close() class SSLTestCase(unittest.TestCase): def setUp(self): self.sslbio = BIO.SSLBio() def test_pass(self): # XXX leaks 64/24 bytes pass def test_set_ssl(self): # XXX leaks 64/1312 bytes ctx = SSL.Context() conn = SSL.Connection(ctx) self.sslbio.set_ssl(conn) def test_do_handshake_fail(self): # XXX leaks 64/42066 bytes ctx = SSL.Context() conn = SSL.Connection(ctx) conn.set_connect_state() self.sslbio.set_ssl(conn) ret = self.sslbio.do_handshake() self.assertIn(ret, (-1, 0)) def test_should_retry_fail(self): # XXX leaks 64/1312 bytes ctx = SSL.Context() conn = SSL.Connection(ctx) self.sslbio.set_ssl(conn) ret = self.sslbio.do_handshake() self.assertIn(ret, (-1, 0)) ret = self.sslbio.should_retry() self.assertEqual(ret, 0) def test_should_write_fail(self): # XXX leaks 64/1312 bytes ctx = SSL.Context() conn = SSL.Connection(ctx) self.sslbio.set_ssl(conn) ret = self.sslbio.do_handshake() self.assertIn(ret, (-1, 0)) ret = self.sslbio.should_write() self.assertEqual(ret, 0) def test_should_read_fail(self): # XXX leaks 64/1312 bytes ctx = SSL.Context() conn = SSL.Connection(ctx) self.sslbio.set_ssl(conn) ret = self.sslbio.do_handshake() self.assertIn(ret, (-1, 0)) ret = self.sslbio.should_read() self.assertEqual(ret, 0) def test_do_handshake_succeed(self): # XXX leaks 196/26586 bytes ctx = SSL.Context() ctx.load_cert_chain("tests/server.pem") conn = SSL.Connection(ctx) self.sslbio.set_ssl(conn) readbio = BIO.MemoryBuffer() writebio = BIO.MemoryBuffer() conn.set_bio(readbio, writebio) conn.set_accept_state() handshake_complete = False srv_port = allocate_srv_port() sock = socket.socket() sock.bind((srv_host, srv_port)) sock.listen(5) handshake_client = HandshakeClient(srv_host, srv_port) handshake_client.start() new_sock, _ = sock.accept() while not handshake_complete: input_token = new_sock.recv(1024) readbio.write(input_token) ret = self.sslbio.do_handshake() if ret <= 0: if not self.sslbio.should_retry() or not self.sslbio.should_read(): sys.exit("unrecoverable error in handshake - server") else: handshake_complete = True output_token = writebio.read() if output_token is not None: new_sock.sendall(output_token) handshake_client.join() sock.close() new_sock.close() def suite(): return unittest.TestLoader().loadTestsFromTestCase(SSLTestCase) if __name__ == '__main__': Rand.load_file('randpool.dat', -1) m2threading.init() unittest.TextTestRunner().run(suite()) m2threading.cleanup() Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_bn.py000066400000000000000000000040071465575656700165610ustar00rootroot00000000000000#!/usr/bin/env python """ Unit tests for M2Crypto.BN. Copyright (c) 2005 Open Source Applications Foundation. All rights reserved. """ import re import warnings from M2Crypto import BN, Rand from tests import unittest loops = 16 class BNTestCase(unittest.TestCase): def test_rand(self): # defaults for _ in range(loops): r8 = BN.rand(8) # top for _ in range(loops): r8 = BN.rand(8, top=0) assert r8 & 128 for _ in range(loops): r8 = BN.rand(8, top=1) assert r8 & 192 # bottom for _ in range(loops): r8 = BN.rand(8, bottom=1) self.assertEqual(r8 % 2, 1) # make sure we can get big numbers and work with them for _ in range(loops): r8 = BN.rand(8, top=0) r16 = BN.rand(16, top=0) r32 = BN.rand(32, top=0) r64 = BN.rand(64, top=0) r128 = BN.rand(128, top=0) r256 = BN.rand(256, top=0) r512 = BN.rand(512, top=0) assert r8 < r16 < r32 < r64 < r128 < r256 < r512 < (r512 + 1) def test_rand_range(self): # small range for _ in range(loops): r = BN.rand_range(1) self.assertEqual(r, 0) for _ in range(loops): r = BN.rand_range(4) assert 0 <= r < 4 # large range r512 = BN.rand(512, top=0) for _ in range(loops): r = BN.rand_range(r512) assert 0 <= r < r512 def test_randfname(self): m = re.compile('^[a-zA-Z0-9]{8}$') for _ in range(loops): with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) r = BN.randfname(8) assert m.match(r) def suite(): return unittest.TestLoader().loadTestsFromTestCase(BNTestCase) if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_dh.py000066400000000000000000000034531465575656700165610ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.DH. Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" from M2Crypto import DH, BIO, Rand from tests import unittest class DHTestCase(unittest.TestCase): params = 'tests/dhparam.pem' def genparam_callback(self, *args): pass def genparam_callback2(self): pass def test_init_junk(self): with self.assertRaises(TypeError): DH.DH('junk') def test_gen_params(self): a = DH.gen_params(1024, 2, self.genparam_callback) self.assertEqual(a.check_params(), 0) def test_gen_params_bad_cb(self): a = DH.gen_params(1024, 2, self.genparam_callback2) self.assertEqual(a.check_params(), 0) def test_print_params(self): a = DH.gen_params(1024, 2, self.genparam_callback) bio = BIO.MemoryBuffer() a.print_params(bio) params = bio.read() self.assertTrue(params.find(b'(1024 bit)')) self.assertTrue(params.find(b'generator: 2 (0x2)')) def test_load_params(self): a = DH.load_params('tests/dhparams.pem') self.assertEqual(a.check_params(), 0) def test_compute_key(self): a = DH.load_params('tests/dhparams.pem') b = DH.set_params(a.p, a.g) a.gen_key() b.gen_key() ak = a.compute_key(b.pub) bk = b.compute_key(a.pub) self.assertEqual(ak, bk) self.assertEqual(len(a), 128) with self.assertRaises(DH.DHError): setattr(a, 'p', 1) with self.assertRaises(DH.DHError): setattr(a, 'priv', 1) def suite(): return unittest.TestLoader().loadTestsFromTestCase(DHTestCase) if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_dsa.py000066400000000000000000000070561465575656700167400ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.DSA. Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" import hashlib from M2Crypto import DSA, Rand from tests import unittest class DSATestCase(unittest.TestCase): errkey = 'tests/rsa.priv.pem' privkey = 'tests/dsa.priv.pem' pubkey = 'tests/dsa.pub.pem' param = 'tests/dsa.param.pem' data = hashlib.sha1(b'Can you spell subliminal channel?').digest() different_data = hashlib.sha1(b'I can spell.').digest() def callback(self, *args): pass def test_loadkey_junk(self): with self.assertRaises(DSA.DSAError): DSA.load_key(self.errkey) def test_loadkey(self): dsa = DSA.load_key(self.privkey) self.assertEqual(len(dsa), 1024) with self.assertRaises(AttributeError): getattr(dsa, 'foobar') for k in ('p', 'q', 'g', 'priv', 'pub'): with self.assertRaises(DSA.DSAError): setattr(dsa, k, 1) def test_loadparam(self): with self.assertRaises(DSA.DSAError): DSA.load_key(self.param) dsa = DSA.load_params(self.param) assert not dsa.check_key() self.assertEqual(len(dsa), 1024) def test_sign(self): dsa = DSA.load_key(self.privkey) assert dsa.check_key() r, s = dsa.sign(self.data) assert dsa.verify(self.data, r, s) assert not dsa.verify(self.data, s, r) def test_sign_asn1(self): dsa = DSA.load_key(self.privkey) blob = dsa.sign_asn1(self.data) assert dsa.verify_asn1(self.data, blob) def test_sign_with_params_only(self): dsa = DSA.load_params(self.param) with self.assertRaises(AssertionError): dsa.sign(self.data) with self.assertRaises(AssertionError): dsa.sign_asn1(self.data) def test_pub_verify(self): dsa = DSA.load_key(self.privkey) r, s = dsa.sign(self.data) dsapub = DSA.load_pub_key(self.pubkey) assert dsapub.check_key() assert dsapub.verify(self.data, r, s) with self.assertRaises(DSA.DSAError): dsapub.sign() def test_verify_fail(self): dsa = DSA.load_key(self.privkey) r, s = dsa.sign(self.data) assert not dsa.verify(self.different_data, r, s) def test_verify_fail2(self): dsa = DSA.load_key(self.privkey) r, s = dsa.sign(self.data) dsa2 = DSA.load_params(self.param) assert not dsa2.check_key() with self.assertRaises(AssertionError): dsa2.verify(self.data, r, s) def test_genparam_setparam_genkey(self): dsa = DSA.gen_params(1024, self.callback) self.assertEqual(len(dsa), 1024) p = dsa.p q = dsa.q g = dsa.g dsa2 = DSA.set_params(p, q, g) assert not dsa2.check_key() dsa2.gen_key() assert dsa2.check_key() r, s = dsa2.sign(self.data) assert dsa2.verify(self.data, r, s) def test_pub_key_from_params(self): dsa = DSA.gen_params(1024, self.callback) dsa.gen_key() self.assertEqual(len(dsa), 1024) p = dsa.p q = dsa.q g = dsa.g pub = dsa.pub dsa2 = DSA.pub_key_from_params(p, q, g, pub) assert dsa2.check_key() r, s = dsa.sign(self.data) assert dsa2.verify(self.data, r, s) def suite(): return unittest.TestLoader().loadTestsFromTestCase(DSATestCase) if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_ec_curves.py000066400000000000000000000114101465575656700201340ustar00rootroot00000000000000#!/usr/bin/env python # XXX memory leaks from __future__ import absolute_import """ Unit tests for M2Crypto.EC, the curves There are several ways one could unittest elliptical curves but we are going to only validate that we are using the OpenSSL curve and that it works with ECDSA. We will assume OpenSSL has validated the curves themselves. Also, some curves are shorter than a SHA-1 digest of 160 bits. To keep the testing simple, we will take advantage of ECDSA's ability to sign any digest length and create a digset string of only 48 bits. Remember we are testing our ability to access the curve, not ECDSA itself. Copyright (c) 2006 Larry Bugbee. All rights reserved. """ import logging from M2Crypto import EC, Rand, m2 # noqa from tests import unittest log = logging.getLogger(__name__) curves = { 'secp112r1': 112, 'secp112r2': 112, 'secp128r1': 128, 'secp128r2': 128, 'secp160k1': 160, 'secp160r1': 160, 'secp160r2': 160, 'secp192k1': 192, 'secp224k1': 224, 'secp224r1': 224, 'secp256k1': 256, 'secp384r1': 384, 'secp521r1': 521, 'sect113r1': 113, 'sect113r2': 113, 'sect131r1': 131, 'sect131r2': 131, 'sect163k1': 163, 'sect163r1': 163, 'sect163r2': 163, 'sect193r1': 193, 'sect193r2': 193, 'sect233k1': 233, 'sect233r1': 233, 'sect239k1': 239, 'sect283k1': 283, 'sect283r1': 283, 'sect409k1': 409, 'sect409r1': 409, 'sect571k1': 571, 'sect571r1': 571, 'X9_62_prime192v1': 192, 'X9_62_prime192v2': 192, 'X9_62_prime192v3': 192, 'X9_62_prime239v1': 239, 'X9_62_prime239v2': 239, 'X9_62_prime239v3': 239, 'X9_62_prime256v1': 256, 'X9_62_c2pnb163v1': 163, 'X9_62_c2pnb163v2': 163, 'X9_62_c2pnb163v3': 163, 'X9_62_c2pnb176v1': 176, 'X9_62_c2tnb191v1': 191, 'X9_62_c2tnb191v2': 191, 'X9_62_c2tnb191v3': 191, 'X9_62_c2pnb208w1': 208, 'X9_62_c2tnb239v1': 239, 'X9_62_c2tnb239v2': 239, 'X9_62_c2tnb239v3': 239, 'X9_62_c2pnb272w1': 272, 'X9_62_c2pnb304w1': 304, 'X9_62_c2tnb359v1': 359, 'X9_62_c2pnb368w1': 368, 'X9_62_c2tnb431r1': 431, 'wap_wsg_idm_ecid_wtls1': 113, 'wap_wsg_idm_ecid_wtls3': 163, 'wap_wsg_idm_ecid_wtls4': 113, 'wap_wsg_idm_ecid_wtls5': 163, 'wap_wsg_idm_ecid_wtls6': 112, 'wap_wsg_idm_ecid_wtls7': 160, 'wap_wsg_idm_ecid_wtls8': 112, 'wap_wsg_idm_ecid_wtls9': 160, 'wap_wsg_idm_ecid_wtls10': 233, 'wap_wsg_idm_ecid_wtls11': 233, 'wap_wsg_idm_ecid_wtls12': 224 } # The following two curves, according to OpenSSL, have a # "Questionable extension field!" and are not supported by # the OpenSSL inverse function. ECError: no inverse. # As such they cannot be used for signing. They might, # however, be usable for encryption but that has not # been tested. Until thir usefulness can be established, # they are not supported at this time. # curves2 = [ # ('ipsec3', 155), # ('ipsec4', 185), # ] def available_curves(): bc_dict = EC.get_builtin_curves() bin_curves = set(x['sname'] for x in bc_dict) out_curves = tuple((m2.obj_sn2nid(x[0]), x[1]) for x in curves if x[0] in bin_curves) return out_curves # Seems like one of the most widely supported curves. tested_curve = EC.NID_secp384r1, curves['secp384r1'] class ECCurveTests(unittest.TestCase): data = "digest" def genkey(self, curve): try: curve_name = m2.obj_nid2sn(curve[0]) except TypeError: # we have to throw different exception for compatibility raise AttributeError('Unknown cipher %s', curve[0]) ec = EC.gen_params(curve[0]) self.assertEqual(len(ec), curve[1]) ec.gen_key() self.assertTrue(ec.check_key(), 'check_key() failure for "%s"' % curve_name) return ec def sign_verify_ecdsa(self, curve): ec = self.genkey(curve) r, s = ec.sign_dsa(self.data) self.assertTrue(ec.verify_dsa(self.data, r, s)) self.assertFalse(ec.verify_dsa(self.data, s, r)) def test_ec_curves_ECDSA(self): # noqa for curve in available_curves(): self.sign_verify_ecdsa(curve) with self.assertRaises(AttributeError): self.sign_verify_ecdsa(('nosuchcurve', 1)) def test_ec_get_builtin_curves(self): curves = EC.get_builtin_curves() self.assertNotEqual(curves, []) self.assertIsNotNone(curves) def suite(): suite = unittest.TestSuite() suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ECCurveTests)) return suite if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_ecdh.py000066400000000000000000000024531465575656700170700ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.EC, ECDH part. Copyright (c) 2000 Ng Pheng Siong. All rights reserved. Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All rights reserved. """ from M2Crypto import EC, Rand from tests import unittest from tests.test_ec_curves import tested_curve class ECDHTestCase(unittest.TestCase): privkey = 'tests/ec.priv.pem' def test_init_junk(self): with self.assertRaises(TypeError): EC.EC('junk') def test_compute_key(self): a = EC.load_key(self.privkey) b = EC.gen_params(tested_curve[0]) b.gen_key() ak = a.compute_dh_key(b.pub()) bk = b.compute_dh_key(a.pub()) self.assertEqual(ak, bk) def test_pubkey_from_der(self): a = EC.gen_params(tested_curve[0]) a.gen_key() b = EC.gen_params(tested_curve[0]) b.gen_key() a_pub_der = a.pub().get_der() a_pub = EC.pub_key_from_der(a_pub_der) ak = a.compute_dh_key(b.pub()) bk = b.compute_dh_key(a_pub) self.assertEqual(ak, bk) def suite(): return unittest.TestLoader().loadTestsFromTestCase(ECDHTestCase) if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_ecdsa.py000066400000000000000000000052371465575656700172470ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.EC, ECDSA part. Copyright (c) 2000 Ng Pheng Siong. All rights reserved. Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All rights reserved. """ import hashlib import logging from M2Crypto import EC, Rand from tests import unittest from tests.test_ec_curves import tested_curve log = logging.getLogger(__name__) class ECDSATestCase(unittest.TestCase): errkey = 'tests/rsa.priv.pem' privkey = 'tests/ec.priv.pem' pubkey = 'tests/ec.pub.pem' data = hashlib.sha1(b'Can you spell subliminal channel?').digest() def callback(self, *args): pass def callback2(self): pass def test_loadkey_junk(self): with self.assertRaises(ValueError): EC.load_key(self.errkey) def test_loadkey(self): ec = EC.load_key(self.privkey) self.assertEqual(len(ec), tested_curve[1]) def test_loadpubkey(self): # XXX more work needed ec = EC.load_pub_key(self.pubkey) self.assertEqual(len(ec), tested_curve[1]) with self.assertRaises(EC.ECError): EC.load_pub_key(self.errkey) def _test_sign_dsa(self): ec = EC.gen_params(tested_curve[0]) # ec.gen_key() with self.assertRaises(EC.ECError): ec.sign_dsa(self.data) ec = EC.load_key(self.privkey) r, s = ec.sign_dsa(self.data) assert ec.verify_dsa(self.data, r, s) assert not ec.verify_dsa(self.data, s, r) def test_sign_dsa_asn1(self): ec = EC.load_key(self.privkey) blob = ec.sign_dsa_asn1(self.data) assert ec.verify_dsa_asn1(self.data, blob) with self.assertRaises(EC.ECError): ec.verify_dsa_asn1(blob, self.data) def test_verify_dsa(self): ec = EC.load_key(self.privkey) r, s = ec.sign_dsa(self.data) ec2 = EC.load_pub_key(self.pubkey) assert ec2.verify_dsa(self.data, r, s) assert not ec2.verify_dsa(self.data, s, r) def test_genparam(self): ec = EC.gen_params(tested_curve[0]) self.assertEqual(len(ec), tested_curve[1]) def test_pub_key_from_params(self): curve = EC.NID_prime256v1 ec = EC.gen_params(curve) ec.gen_key() ec_pub = ec.pub() k = ec_pub.get_key() ec2 = EC.pub_key_from_params(curve, k) assert ec2.check_key() r, s = ec.sign_dsa(self.data) assert ec2.verify_dsa(self.data, r, s) def suite(): return unittest.TestLoader().loadTestsFromTestCase(ECDSATestCase) if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_engine.py000066400000000000000000000030071465575656700174260ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.Engine.""" from M2Crypto import Engine from tests import unittest class EngineTestCase(unittest.TestCase): privkey = 'tests/rsa.priv.pem' bad_id = '1bea1edfeb97' def tearDown(self): Engine.cleanup() def test_by_id_junk(self): with self.assertRaises(ValueError): Engine.Engine(self.bad_id) with self.assertRaises(ValueError): Engine.Engine() def test_by_id_openssl(self): Engine.load_openssl() e = Engine.Engine('openssl') self.assertEqual(e.get_name(), 'Software engine support') self.assertEqual(e.get_id(), 'openssl') def test_by_id_dynamic(self): Engine.load_dynamic() Engine.Engine('dynamic') def test_engine_ctrl_cmd_string(self): Engine.load_dynamic() e = Engine.Engine('dynamic') e.ctrl_cmd_string('ID', 'TESTID') def test_load_private(self): Engine.load_openssl() e = Engine.Engine('openssl') e.set_default() e.load_private_key(self.privkey) def test_load_certificate(self): Engine.load_openssl() e = Engine.Engine('openssl') e.set_default() try: with self.assertRaises(Engine.EngineError): e.load_certificate('/dev/null') except SystemError: pass def suite(): return unittest.TestLoader().loadTestsFromTestCase(EngineTestCase) if __name__ == '__main__': unittest.TextTestRunner().run(suite()) m2crypto-0.42.0/tests/test_err.py000066400000000000000000000011721465575656700167520ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """Unit tests for M2Crypto.Err. Copyright (C) 2019 Matěj Cepl Released under the terms of MIT/X11 License, see the file LICENCE for more. """ from M2Crypto import Err from tests import unittest class ErrTestCase(unittest.TestCase): def test_no_error(self): # Protection against gl#m2crypto/m2crypto#258 self.assertEqual(Err.get_error_reason(0), '') def suite(): suite = unittest.TestSuite() suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ErrTestCase)) return suite if __name__ == '__main__': unittest.TextTestRunner().run(suite()) m2crypto-0.42.0/tests/test_evp.py000066400000000000000000000726001465575656700167600ustar00rootroot00000000000000from __future__ import absolute_import, division """ Unit tests for M2Crypto.EVP. Copyright (c) 2004-2007 Open Source Applications Foundation Author: Heikki Toivonen """ import base64 import hashlib import io import logging from binascii import a2b_hex, hexlify, unhexlify from M2Crypto import BIO, EVP, RSA, EC, Rand, m2, util from tests import unittest from tests.fips import fips_mode log = logging.getLogger('test_EVP') ciphers = [ 'des_ede_ecb', 'des_ede_cbc', 'des_ede_cfb', 'des_ede_ofb', 'des_ede3_ecb', 'des_ede3_cbc', 'des_ede3_cfb', 'des_ede3_ofb', 'aes_128_ecb', 'aes_128_cbc', 'aes_128_cfb', 'aes_128_ofb', 'aes_128_ctr', 'aes_192_ecb', 'aes_192_cbc', 'aes_192_cfb', 'aes_192_ofb', 'aes_192_ctr', 'aes_256_ecb', 'aes_256_cbc', 'aes_256_cfb', 'aes_256_ofb', 'aes_256_ctr'] nonfips_ciphers = ['bf_ecb', 'bf_cbc', 'bf_cfb', 'bf_ofb', # 'idea_ecb', 'idea_cbc', 'idea_cfb', 'idea_ofb', 'cast5_ecb', 'cast5_cbc', 'cast5_cfb', 'cast5_ofb', # 'rc5_ecb', 'rc5_cbc', 'rc5_cfb', 'rc5_ofb', 'des_ecb', 'des_cbc', 'des_cfb', 'des_ofb', 'rc4', 'rc2_40_cbc'] if not fips_mode and m2.OPENSSL_VERSION_NUMBER < 0x30000000: # Disabled algorithms ciphers += nonfips_ciphers class EVPTestCase(unittest.TestCase): def _gen_callback(self, *args): pass def _pass_callback(self, *args): return b'foobar' def _assign_rsa(self): rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) pkey = EVP.PKey() pkey.assign_rsa(rsa, capture=0) # capture=1 should cause crash return rsa def test_assign(self): rsa = self._assign_rsa() rsa.check_key() def test_pem(self): rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) pkey = EVP.PKey() pkey.assign_rsa(rsa) result_w_callback = pkey.as_pem(callback=self._pass_callback) result_wo_callback = pkey.as_pem(cipher=None) self.assertNotEqual(result_w_callback, result_wo_callback) with self.assertRaises(ValueError): pkey.as_pem(cipher='noXX$$%%suchcipher', callback=self._pass_callback) def test_as_der(self): """ Test DER encoding the PKey instance after assigning a RSA key to it. """ rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) pkey = EVP.PKey() pkey.assign_rsa(rsa) der_blob = pkey.as_der() # A quick but not thorough sanity check self.assertEqual(len(der_blob), 160) def test_get_digestbyname(self): with self.assertRaises(EVP.EVPError): m2.get_digestbyname('sha513') self.assertNotEqual(m2.get_digestbyname('sha1'), None) def test_MessageDigest(self): # noqa with self.assertRaises(ValueError): EVP.MessageDigest('sha513') md = EVP.MessageDigest('sha1') self.assertEqual(md.update(b'Hello'), 1) self.assertEqual(util.octx_to_num(md.final()), 1415821221623963719413415453263690387336440359920) # temporarily remove sha1 from m2 old_sha1 = m2.sha1 del m2.sha1 # now run the same test again, relying on EVP.MessageDigest() to call # get_digestbyname() under the hood md = EVP.MessageDigest('sha1') self.assertEqual(md.update(b'Hello'), 1) self.assertEqual(util.octx_to_num(md.final()), 1415821221623963719413415453263690387336440359920) # put sha1 back in place m2.sha1 = old_sha1 def test_as_der_capture_key(self): """ Test DER encoding the PKey instance after assigning a RSA key to it. Have the PKey instance capture the RSA key. """ rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) pkey = EVP.PKey() pkey.assign_rsa(rsa, 1) der_blob = pkey.as_der() # A quick but not thorough sanity check self.assertEqual(len(der_blob), 160) def test_size(self): rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) pkey = EVP.PKey() pkey.assign_rsa(rsa) size = pkey.size() self.assertEqual(size, 128) def test_hmac(self): self.assertEqual(util.octx_to_num(EVP.hmac(b'key', b'data')), 92800611269186718152770431077867383126636491933, util.octx_to_num(EVP.hmac(b'key', b'data'))) if not fips_mode: # Disabled algorithms self.assertEqual(util.octx_to_num(EVP.hmac(b'key', b'data', algo='md5')), 209168838103121722341657216703105225176, util.octx_to_num(EVP.hmac(b'key', b'data', algo='md5'))) if not fips_mode and m2.OPENSSL_VERSION_NUMBER < 0x30000000: self.assertEqual(util.octx_to_num(EVP.hmac(b'key', b'data', algo='ripemd160')), 1176807136224664126629105846386432860355826868536, util.octx_to_num(EVP.hmac(b'key', b'data', algo='ripemd160'))) if m2.OPENSSL_VERSION_NUMBER >= 0x90800F: self.assertEqual(util.octx_to_num(EVP.hmac(b'key', b'data', algo='sha224')), 2660082265842109788381286338540662430962855478412025487066970872635, util.octx_to_num(EVP.hmac(b'key', b'data', algo='sha224'))) self.assertEqual(util.octx_to_num(EVP.hmac(b'key', b'data', algo='sha256')), 36273358097036101702192658888336808701031275731906771612800928188662823394256, util.octx_to_num(EVP.hmac(b'key', b'data', algo='sha256'))) self.assertEqual(util.octx_to_num(EVP.hmac(b'key', b'data', algo='sha384')), 30471069101236165765942696708481556386452105164815350204559050657318908408184002707969468421951222432574647369766282, util.octx_to_num(EVP.hmac(b'key', b'data', algo='sha384'))) self.assertEqual(util.octx_to_num(EVP.hmac(b'key', b'data', algo='sha512')), 3160730054100700080556942280820129108466291087966635156623014063982211353635774277148932854680195471287740489442390820077884317620321797003323909388868696, util.octx_to_num(EVP.hmac(b'key', b'data', algo='sha512'))) with self.assertRaises(ValueError): EVP.hmac(b'key', b'data', algo='sha513') def test_get_rsa(self): """ Testing retrieving the RSA key from the PKey instance. """ rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) self.assertIsInstance(rsa, RSA.RSA) pkey = EVP.PKey() pkey.assign_rsa(rsa) rsa2 = pkey.get_rsa() self.assertIsInstance(rsa2, RSA.RSA_pub) self.assertEqual(rsa.e, rsa2.e) self.assertEqual(rsa.n, rsa2.n) # FIXME # hanging call is # m2.rsa_write_key(self.rsa, bio._ptr(), ciph, callback)s # from RSA.py/save_key_bio pem = rsa.as_pem(callback=self._pass_callback) pem2 = rsa2.as_pem() assert pem assert pem2 self.assertNotEqual(pem, pem2) message = b'This is the message string' digest = hashlib.sha1(message).digest() self.assertEqual(rsa.sign(digest), rsa2.sign(digest)) rsa3 = RSA.gen_key(1024, 3, callback=self._gen_callback) self.assertNotEqual(rsa.sign(digest), rsa3.sign(digest)) def test_load_key_string_pubkey_rsa(self): """ Testing creating a PKey instance from PEM string. """ rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) self.assertIsInstance(rsa, RSA.RSA) rsa_pem = BIO.MemoryBuffer() rsa.save_pub_key_bio(rsa_pem) pkey = EVP.load_key_string_pubkey(rsa_pem.read()) rsa2 = pkey.get_rsa() self.assertIsInstance(rsa2, RSA.RSA_pub) self.assertEqual(rsa.e, rsa2.e) self.assertEqual(rsa.n, rsa2.n) pem = rsa.as_pem(callback=self._pass_callback) pem2 = rsa2.as_pem() assert pem assert pem2 self.assertNotEqual(pem, pem2) def test_get_rsa_fail(self): """ Testing trying to retrieve the RSA key from the PKey instance when it is not holding a RSA Key. Should raise a ValueError. """ pkey = EVP.PKey() with self.assertRaises(ValueError): pkey.get_rsa() def test_get_ec(self): """ Testing retrieving the EC key from the PKey instance. """ ec = EC.gen_params(m2.NID_secp521r1) ec.gen_key() self.assertIsInstance(ec, EC.EC) pkey = EVP.PKey() pkey.assign_ec(ec) ec2 = pkey.get_ec() self.assertIsInstance(ec2, EC.EC_pub) self.assertEqual(ec.compute_dh_key(ec), ec2.compute_dh_key(ec2)) pem = ec.as_pem(callback=self._pass_callback) pem2 = ec2.as_pem() assert pem assert pem2 self.assertNotEqual(pem, pem2) message = b'This is the message string' digest = hashlib.sha1(message).digest() ec_sign = ec.sign_dsa(digest) ec2_sign = ec.sign_dsa(digest) self.assertEqual(ec.verify_dsa(digest, ec_sign[0], ec_sign[1]), ec.verify_dsa(digest, ec2_sign[0], ec2_sign[1])) ec3 = EC.gen_params(m2.NID_secp521r1) ec3.gen_key() ec3_sign = ec.sign_dsa(digest) self.assertEqual(ec.verify_dsa(digest, ec_sign[0], ec_sign[1]), ec.verify_dsa(digest, ec3_sign[0], ec3_sign[1])) def test_load_key_string_pubkey_ec(self): """ Testing creating a PKey instance from PEM string. """ ec = EC.gen_params(m2.NID_secp521r1) ec.gen_key() self.assertIsInstance(ec, EC.EC) ec_pem = BIO.MemoryBuffer() ec.save_pub_key_bio(ec_pem) pkey = EVP.load_key_string_pubkey(ec_pem.read()) ec2 = pkey.get_ec() self.assertIsInstance(ec2, EC.EC_pub) pem = ec.as_pem(callback=self._pass_callback) pem2 = ec2.as_pem() assert pem assert pem2 self.assertNotEqual(pem, pem2) def test_get_ec_fail(self): """ Testing trying to retrieve the EC key from the PKey instance when it is not holding a EC Key. Should raise a ValueError. """ pkey = EVP.PKey() with self.assertRaises(ValueError): pkey.get_ec() def test_get_modulus(self): pkey = EVP.PKey() with self.assertRaises(ValueError): pkey.get_modulus() rsa = RSA.gen_key(1024, 3, callback=self._gen_callback) pkey.assign_rsa(rsa) mod = pkey.get_modulus() self.assertGreater(len(mod), 0, mod) self.assertEqual(len(mod.strip(b'0123456789ABCDEF')), 0) def test_verify_final(self): from M2Crypto import X509 pkey = EVP.load_key('tests/signer_key.pem') pkey.sign_init() pkey.sign_update(b'test message') sig = pkey.sign_final() # OK x509 = X509.load_cert('tests/signer.pem') pubkey = x509.get_pubkey() pubkey.verify_init() pubkey.verify_update(b'test message') self.assertEqual(pubkey.verify_final(sig), 1) # wrong cert x509 = X509.load_cert('tests/x509.pem') pubkey = x509.get_pubkey() pubkey.verify_init() pubkey.verify_update(b'test message') self.assertEqual(pubkey.verify_final(sig), 0) # wrong message x509 = X509.load_cert('tests/signer.pem') pubkey = x509.get_pubkey() pubkey.verify_init() pubkey.verify_update(b'test message not') self.assertEqual(pubkey.verify_final(sig), 0) @unittest.skipIf(m2.OPENSSL_VERSION_NUMBER < 0x10101000, 'Relies on support for Ed25519 which was introduced in OpenSSL 1.1.1') def test_digest_verify(self): pkey = EVP.load_key('tests/ed25519.priv.pem') pkey.reset_context(None) pkey.digest_sign_init() sig = pkey.digest_sign(b'test message') # OK pkey = EVP.load_key_pubkey('tests/ed25519.pub.pem') pkey.reset_context(None) pkey.digest_verify_init() self.assertEqual(pkey.digest_verify(sig, b'test message'), 1) # wrong public key pkey = EVP.load_key_pubkey('tests/ed25519.pub2.pem') pkey.reset_context(None) pkey.digest_verify_init() self.assertEqual(pkey.digest_verify(sig, b'test message'), 0) # wrong message pkey = EVP.load_key_pubkey('tests/ed25519.pub.pem') pkey.reset_context(None) pkey.digest_verify_init() self.assertEqual(pkey.digest_verify(sig, b'test message not'), 0) @unittest.skipIf(m2.OPENSSL_VERSION_NUMBER < 0x90800F or m2.OPENSSL_NO_EC != 0, 'Relies on support for EC') def test_digest_verify_final(self): pkey = EVP.load_key('tests/ec.priv.pem') pkey.reset_context('sha256') pkey.digest_sign_init() pkey.digest_sign_update(b'test message') sig = pkey.digest_sign_final() # OK pkey = EVP.load_key_pubkey('tests/ec.pub.pem') pkey.reset_context('sha256') pkey.digest_verify_init() pkey.digest_verify_update(b'test message') self.assertEqual(pkey.digest_verify_final(sig), 1) # wrong public key pkey = EVP.load_key_pubkey('tests/ec.pub2.pem') pkey.reset_context('sha256') pkey.digest_verify_init() pkey.digest_verify_update(b'test message') self.assertEqual(pkey.digest_verify_final(sig), 0) # wrong message pkey = EVP.load_key_pubkey('tests/ec.pub.pem') pkey.reset_context('sha256') pkey.digest_verify_init() pkey.digest_verify_update(b'test message not') self.assertEqual(pkey.digest_verify_final(sig), 0) def test_load_bad(self): with self.assertRaises(BIO.BIOError): EVP.load_key('thisdoesnotexist-dfgh56789') with self.assertRaises(EVP.EVPError): EVP.load_key('tests/signer.pem') # not a key with self.assertRaises(EVP.EVPError): EVP.load_key_bio(BIO.MemoryBuffer(b'no a key')) def test_pad(self): self.assertEqual(util.pkcs5_pad('Hello World'), 'Hello World\x05\x05\x05\x05\x05') self.assertEqual(util.pkcs7_pad('Hello World', 15), 'Hello World\x04\x04\x04\x04') with self.assertRaises(ValueError): util.pkcs7_pad('Hello', 256) def test_pkey_verify_crash(self): SIGN_PRIVATE = EVP.load_key('tests/rsa.priv.pem') SIGN_PUBLIC = RSA.load_pub_key('tests/rsa.pub.pem') def sign(data): SIGN_PRIVATE.sign_init() SIGN_PRIVATE.sign_update(data) signed_data = SIGN_PRIVATE.sign_final() return base64.b64encode(signed_data) def verify(response): signature = base64.b64decode(response['sign']) data = response['data'] verify_evp = EVP.PKey() # capture parameter on the following line is required by # the documentation verify_evp.assign_rsa(SIGN_PUBLIC, capture=False) verify_evp.verify_init() verify_evp.verify_update(data) # m2.verify_final(self.ctx, sign, self.pkey) fin_res = verify_evp.verify_final(signature) return fin_res == 1 data = b"test message" signature = sign(data) res = {"data": data, "sign": signature} self.assertTrue(verify(res)) # works fine self.assertTrue(verify(res)) # segmentation fault in *verify_final* class CipherTestCase(unittest.TestCase): def cipher_filter(self, cipher, inf, outf): while 1: buf = inf.read() if not buf: break outf.write(cipher.update(buf)) outf.write(cipher.final()) return outf.getvalue() def try_algo(self, algo): enc = 1 dec = 0 otxt = b'against stupidity the gods themselves contend in vain' k = EVP.Cipher(algo, b'goethe', b'12345678', enc, 1, 'sha1', b'saltsalt', 5) pbuf = io.BytesIO(otxt) cbuf = io.BytesIO() ctxt = self.cipher_filter(k, pbuf, cbuf) pbuf.close() cbuf.close() j = EVP.Cipher(algo, b'goethe', b'12345678', dec, 1, 'sha1', b'saltsalt', 5) pbuf = io.BytesIO() cbuf = io.BytesIO(ctxt) ptxt = self.cipher_filter(j, cbuf, pbuf) pbuf.close() cbuf.close() self.assertEqual(otxt, ptxt, '%s algorithm cipher test failed' % algo) def test_ciphers(self): for ciph in ciphers: with self.subTest(ciph=ciph): self.try_algo(ciph) # non-compiled (['idea_ecb', 'idea_cbc', 'idea_cfb', 'idea_ofb']) # def test_ciphers_not_compiled_idea(self): # # idea might not be compiled in # for ciph in nonfips_ciphers: # with self.subTest(ciph=ciph): # try: # self.try_algo(ciph) # except ValueError as e: # if str(e) != "('unknown cipher', 'idea_ecb')": # raise ## or # except EVP.EVPError as e: # self.skipTest(str(e)) ################# # ['rc5_ecb', 'rc5_cbc', 'rc5_cfb', 'rc5_ofb'] # def test_ciphers_not_compiled_rc5(self, ciph): # # rc5 might not be compiled in # for ciph in []: # with self.subTest(ciph=ciph): # try: # self.try_algo(ciph) # except ValueError as e: # if str(e) != "('unknown cipher', 'rc5_ofb')": # raise def test_ciphers_nosuch(self): with self.assertRaises(ValueError): self.try_algo('nosuchalgo4567') def test_AES(self): # noqa enc = 1 dec = 0 test_data = [ # test vectors from rfc 3602 # Case #1: Encrypting 16 bytes (1 block) using AES-CBC with # 128-bit key { 'KEY': '06a9214036b8a15b512e03d534120006', 'IV': '3dafba429d9eb430b422da802c9fac41', 'PT': b'Single block msg', 'CT': b'e353779c1079aeb82708942dbe77181a', }, # Case #2: Encrypting 32 bytes (2 blocks) using AES-CBC with # 128-bit key { 'KEY': 'c286696d887c9aa0611bbb3e2025a45a', 'IV': '562e17996d093d28ddb3ba695a2e6f58', 'PT': unhexlify(b'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'), 'CT': b'd296cd94c2cccf8a3a863028b5e1dc0a7586602d253cfff91b8266bea6d61ab1', }, # Case #3: Encrypting 48 bytes (3 blocks) using AES-CBC with # 128-bit key { 'KEY': '6c3ea0477630ce21a2ce334aa746c2cd', 'IV': 'c782dc4c098c66cbd9cd27d825682c81', 'PT': b'This is a 48-byte message (exactly 3 AES blocks)', 'CT': b'd0a02b3836451753d493665d33f0e8862dea54cdb293abc7506939276772f8d5021c19216bad525c8579695d83ba2684', }, ] for test in test_data: with self.subTest(msg="test_AES_{}".format(test_data.index(test))): # Test with padding # encrypt k = EVP.Cipher(alg='aes_128_cbc', key=unhexlify(test['KEY']), iv=unhexlify(test['IV']), op=enc) pbuf = io.BytesIO(test['PT']) cbuf = io.BytesIO() ciphertext = hexlify(self.cipher_filter(k, pbuf, cbuf)) cipherpadding = ciphertext[len(test['PT']) * 2:] # Remove the padding from the end ciphertext = ciphertext[:len(test['PT']) * 2] pbuf.close() cbuf.close() self.assertEqual(ciphertext, test['CT']) # decrypt j = EVP.Cipher(alg='aes_128_cbc', key=unhexlify(test['KEY']), iv=unhexlify(test['IV']), op=dec) pbuf = io.BytesIO() cbuf = io.BytesIO(unhexlify(test['CT'] + cipherpadding)) plaintext = self.cipher_filter(j, cbuf, pbuf) pbuf.close() cbuf.close() self.assertEqual(plaintext, test['PT']) # Test without padding # encrypt k = EVP.Cipher(alg='aes_128_cbc', key=unhexlify(test['KEY']), iv=unhexlify(test['IV']), op=enc, padding=False) pbuf = io.BytesIO(test['PT']) cbuf = io.BytesIO() ciphertext = hexlify(self.cipher_filter(k, pbuf, cbuf)) pbuf.close() cbuf.close() self.assertEqual(ciphertext, test['CT']) # decrypt j = EVP.Cipher(alg='aes_128_cbc', key=unhexlify(test['KEY']), iv=unhexlify(test['IV']), op=dec, padding=False) pbuf = io.BytesIO() cbuf = io.BytesIO(unhexlify(test['CT'])) plaintext = self.cipher_filter(j, cbuf, pbuf) pbuf.close() cbuf.close() self.assertEqual(plaintext, test['PT']) def test_AES_ctr(self): # noqa # In CTR mode, encrypt and decrypt are actually the same # operation because you encrypt the nonce value, then use the # output of that to XOR the plaintext. So we set operation=0, # even though this setting is ignored by OpenSSL. op = 0 nonce = unhexlify('4a45a048a1e9f7c1bd17f2908222b964') # CTR nonce value, 16 bytes key = unhexlify('8410ad66fe53a09addc0d041ae00bc6d70e8038ec17019f27e52eecd3846757e') plaintext_value = b'This is three blocks of text with unicode char \x03' ciphertext_values = { '128': unhexlify('6098fb2e49b3f7ed34f841f43f825d84cf4834021511594b931c85f04662544bdb4f38232e9d87fda6280ab1ef450e27'), # noqa '192': unhexlify('2299b1c5363824cb92b5851dedc73f49f30b23fb23f288492e840c951ce703292a5c6de6fc7f0625c403648f8ca4a582'), # noqa '256': unhexlify('713e34bcd2c59affc9185a716c3c6aef5c9bf7b9914337dd96e9d7436344bcb9c35175afb54adb78aab322829ce9cb4a'), # noqa } for key_size in [128, 192, 256]: alg = 'aes_%s_ctr' % str(key_size) # Our key for this test is 256 bits in length (32 bytes). # We will trim it to the appopriate length for testing AES-128 # and AES-192 as well (so 16 and 24 bytes, respectively). key_truncated = key[0:(key_size // 8)] # Test encrypt operations cipher = EVP.Cipher(alg=alg, key=key_truncated, iv=nonce, op=op) ciphertext = cipher.update(plaintext_value) ciphertext = ciphertext + cipher.final() self.assertEqual(ciphertext, ciphertext_values[str(key_size)]) # Test decrypt operations cipher = EVP.Cipher(alg=alg, key=key_truncated, iv=nonce, op=op) plaintext = cipher.update(ciphertext_values[str(key_size)]) plaintext = plaintext + cipher.final() # XXX not quite sure this is the actual intention # but for now let's be happy to find the same content even if with # a different type - XXX self.assertEqual(plaintext, plaintext_value) def test_raises(self): def _cipherFilter(cipher, inf, outf): # noqa while 1: buf = inf.read() if not buf: break outf.write(cipher.update(buf)) outf.write(cipher.final()) return outf.getvalue() def decrypt(ciphertext, key, iv, alg='aes_256_cbc'): cipher = EVP.Cipher(alg=alg, key=key, iv=iv, op=0) pbuf = io.BytesIO() cbuf = io.BytesIO(ciphertext) plaintext = _cipherFilter(cipher, cbuf, pbuf) pbuf.close() cbuf.close() return plaintext with self.assertRaises(EVP.EVPError): decrypt( unhexlify('941d3647a642fab26d9f99a195098b91252c652d07235b9db35758c401627711724637648e45cad0f1121751a1240a4134998cfdf3c4a95c72de2a2444de3f9e40d881d7f205630b0d8ce142fdaebd8d7fbab2aea3dc47f5f29a0e9b55aae59222671d8e2877e1fb5cd8ef1c427027e0'), unhexlify('5f2cc54067f779f74d3cf1f78c735aec404c8c3a4aaaa02eb1946f595ea4cddb'), unhexlify('0001efa4bd154ee415b9413a421cedf04359fff945a30e7c115465b1c780a85b65c0e45c')) with self.assertRaises(EVP.EVPError): decrypt( unhexlify('a78a510416c1a6f1b48077cc9eeb4287dcf8c5d3179ef80136c18876d774570d'), unhexlify('5cd148eeaf680d4ff933aed83009cad4110162f53ef89fd44fad09611b0524d4'), unhexlify('')) def test_cipher_init_reinit(self): ctx = m2.cipher_ctx_new() m2.cipher_init(ctx, m2.aes_128_cbc(), b'\x01' * (128//8), b'\x02' * (128//8), 1) m2.cipher_init(ctx, m2.aes_128_cbc(), None, None, 1) class PBKDF2TestCase(unittest.TestCase): def test_rfc3211_test_vectors(self): password = b'password' salt = unhexlify('1234567878563412') iter = 5 keylen = 8 ret = EVP.pbkdf2(password, salt, iter, keylen) self.assertEqual(ret, unhexlify(b'd1daa78615f287e6')) password = b'All n-entities must communicate with other n-entities' + \ b' via n-1 entiteeheehees' salt = unhexlify('1234567878563412') iter = 500 keylen = 16 ret = EVP.pbkdf2(password, salt, iter, keylen) self.assertEqual(ret, unhexlify(b'6a8970bf68c92caea84a8df285108586')) class HMACTestCase(unittest.TestCase): data1 = [b'', b'More text test vectors to stuff up EBCDIC machines :-)', a2b_hex("b760e92d6662d351eb3801057695ac0346295356")] data2 = [a2b_hex(b'0b' * 16), b"Hi There", a2b_hex("675b0b3a1b4ddf4e124872da6c2f632bfed957e9")] data3 = [b'Jefe', b"what do ya want for nothing?", a2b_hex("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79")] data4 = [a2b_hex(b'aa' * 16), a2b_hex(b'dd' * 50), a2b_hex("d730594d167e35d5956fd8003d0db3d3f46dc7bb")] data = [data1, data2, data3, data4] def test_simple(self): algo = 'sha1' for d in self.data: h = EVP.HMAC(d[0], algo) h.update(d[1]) ret = h.final() self.assertEqual(ret, d[2]) with self.assertRaises(ValueError): EVP.HMAC(d[0], algo='nosuchalgo') def make_chain_HMAC(self, key, start, input, algo='sha1'): # noqa chain = [] hmac = EVP.HMAC(key, algo) hmac.update(repr(start)) digest = hmac.final() chain.append((digest, start)) for i in input: hmac.reset(digest) hmac.update(repr(i)) digest = hmac.final() chain.append((digest, i)) return chain def make_chain_hmac(self, key, start, input, algo='sha1'): chain = [] digest = EVP.hmac(key, start, algo) chain.append((digest, start)) for i in input: digest = EVP.hmac(digest, i, algo) chain.append((digest, i)) return chain def verify_chain_hmac(self, key, start, chain, algo='sha1'): digest = EVP.hmac(key, start, algo) c = chain[0] if c[0] != digest or c[1] != start: return 0 for d, v in chain[1:]: digest = EVP.hmac(digest, v, algo) if digest != d: return 0 return 1 def verify_chain_HMAC(self, key, start, chain, algo='sha1'): # noqa hmac = EVP.HMAC(key, algo) hmac.update(start) digest = hmac.final() c = chain[0] if c[0] != digest or c[1] != start: return 0 for d, v in chain[1:]: hmac.reset(digest) hmac.update(v) digest = hmac.final() if digest != d: return 0 return 1 def test_complicated(self): make_chain = self.make_chain_hmac verify_chain = self.verify_chain_hmac key = b'numero uno' start = b'zeroth item' input = [b'first item', b'go go go', b'fly fly fly'] chain = make_chain(key, start, input) self.assertEqual(verify_chain(b'some key', start, chain), 0) self.assertEqual(verify_chain(key, start, chain), 1) def suite(): suite = unittest.TestSuite() suite.addTest(unittest.TestLoader().loadTestsFromTestCase(EVPTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(CipherTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(PBKDF2TestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(HMACTestCase)) return suite if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_init.py000066400000000000000000000007351465575656700171310ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto initialization. """ import M2Crypto from tests import unittest class InitTestCase(unittest.TestCase): def test_version_info(self): self.assertIs(type(()), type(M2Crypto.version_info)) def suite(): return unittest.TestLoader().loadTestsFromTestCase(InitTestCase) if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_obj.py000066400000000000000000000117201465575656700167340ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.m2 obj_* functions. """ from M2Crypto import ASN1, BIO, Rand, X509, m2 from tests import unittest """ These functions must be cleaned up and moved to some python module Taken from CA managment code """ def x509_name2list(name): for i in range(0, name.entry_count()): yield X509.X509_Name_Entry(m2.x509_name_get_entry(name._ptr(), i), _pyfree=0) def x509_name_entry2tuple(entry): bio = BIO.MemoryBuffer() m2.asn1_string_print(bio._ptr(), m2.x509_name_entry_get_data(entry._ptr())) return ( m2.obj_obj2txt( m2.x509_name_entry_get_object(entry._ptr()), 0).decode(), bio.getvalue().decode()) def tuple2x509_name_entry(tup): obj, data = tup # TODO This is evil, isn't it? Shouldn't we use only official API? # Something like X509.X509_Name.add_entry_by_txt() obj = obj if isinstance(obj, str) else obj.decode() data = data if isinstance(data, str) else data.decode() _x509_ne = m2.x509_name_entry_create_by_txt(None, obj, ASN1.MBSTRING_ASC, data, len(data)) if not _x509_ne: raise ValueError("Invalid object indentifier: %s" % obj) return X509.X509_Name_Entry(_x509_ne, _pyfree=1) # Prevent memory leaks class ObjectsTestCase(unittest.TestCase): def callback(self, *args): pass def test_obj2txt(self): self.assertEqual(m2.obj_obj2txt(m2.obj_txt2obj("commonName", 0), 1), b"2.5.4.3", b"2.5.4.3") self.assertEqual(m2.obj_obj2txt(m2.obj_txt2obj("commonName", 0), 0), b"commonName", b"commonName") def test_nid(self): self.assertEqual(m2.obj_ln2nid("commonName"), m2.obj_txt2nid("2.5.4.3"), "ln2nid and txt2nid mismatch") self.assertEqual(m2.obj_ln2nid("CN"), 0, "ln2nid on sn") self.assertEqual(m2.obj_sn2nid("CN"), m2.obj_ln2nid("commonName"), "ln2nid and sn2nid mismatch") self.assertEqual(m2.obj_sn2nid("CN"), m2.obj_obj2nid(m2.obj_txt2obj("CN", 0)), "obj2nid") self.assertEqual(m2.obj_txt2nid("__unknown"), 0, "__unknown") def test_tuple2tuple(self): tup = ("CN", "someCommonName") tup1 = x509_name_entry2tuple(tuple2x509_name_entry(tup)) # tup1[0] is 'commonName', not 'CN' self.assertEqual(tup1[1], tup[1], tup1) self.assertEqual(x509_name_entry2tuple(tuple2x509_name_entry(tup1)), tup1, tup1) def test_unknown(self): with self.assertRaises(ValueError): tuple2x509_name_entry(("__unknown", "_")) def test_x509_name(self): n = X509.X509_Name() # It seems this actually needs to be a real 2 letter country code n.C = b'US' n.SP = b'State or Province' n.L = b'locality name' n.O = b'orhanization name' n.OU = b'org unit' n.CN = b'common name' n.Email = b'bob@example.com' n.serialNumber = b'1234' n.SN = b'surname' n.GN = b'given name' n.givenName = b'name given' self.assertEqual(len(n), 11, len(n)) # Thierry: this call to list seems extraneous... tl = [x509_name_entry2tuple(x) for x in x509_name2list(n)] self.assertEqual(len(tl), len(n), len(tl)) x509_n = m2.x509_name_new() for o in [tuple2x509_name_entry(x) for x in tl]: m2.x509_name_add_entry(x509_n, o._ptr(), -1, 0) o._pyfree = 0 # Take care of underlying object n1 = X509.X509_Name(x509_n) self.assertEqual(n.as_text(), n1.as_text(), n1.as_text()) # Detailed OpenSSL error message is visible in Python error message: @unittest.skipIf(m2.OPENSSL_VERSION_NUMBER >= 0x30000000, "Failing on OpenSSL3") def test_detailed_error_message(self): from M2Crypto import SMIME, X509 s = SMIME.SMIME() x509 = X509.load_cert('tests/recipient.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) st = X509.X509_Store() st.load_info('tests/recipient.pem') s.set_x509_store(st) p7, data = SMIME.smime_load_pkcs7('tests/sample-p7.pem') self.assertIsInstance(p7, SMIME.PKCS7, p7) try: s.verify(p7, data) except SMIME.PKCS7_Error as e: self.assertRegex(str(e), "unable to get local issuer certificate", "Not received expected error message") def suite(): t_suite = unittest.TestSuite() t_suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ObjectsTestCase)) return t_suite if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_rand.py000066400000000000000000000055361465575656700171160ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.Rand. Copyright (C) 2006 Open Source Applications Foundation (OSAF). All Rights Reserved. """ import os import ctypes import warnings from M2Crypto import Rand, m2 from tests import unittest class RandTestCase(unittest.TestCase): def test_bytes(self): with self.assertRaises(MemoryError): Rand.rand_bytes(-1) self.assertEqual(Rand.rand_bytes(0), b'') self.assertEqual(len(Rand.rand_bytes(1)), 1) def test_pseudo_bytes(self): with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) with self.assertRaises(MemoryError): Rand.rand_pseudo_bytes(-1) self.assertEqual(Rand.rand_pseudo_bytes(0), (b'', 1)) a, b = Rand.rand_pseudo_bytes(1) self.assertEqual(len(a), 1) self.assertEqual(b, 1) def test_file_name(self): if os.name == 'nt': is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0 rand_env = ('RANDFILE', 'HOME', 'USERPROFILE', 'SYSTEMROOT') else: rand_env = ('RANDFILE', 'HOME') is_admin = False key = next((k for k in rand_env if os.environ.get(k)), None) if is_admin and m2.OPENSSL_VERSION_NUMBER < 0x1010000F: path = 'C:\\' else: path = os.path.join(os.environ[key]) self.assertIsNotNone(key, "Could not find required environment") rand_file = os.path.abspath(os.path.join(path, '.rnd')) self.assertEqual(os.path.abspath(Rand.rand_file_name()), rand_file) def test_load_save(self): try: os.remove('tests/randpool.dat') except OSError: pass self.assertIn(Rand.load_file('tests/randpool.dat', -1), [0, -1]) self.assertEqual(Rand.save_file('tests/randpool.dat'), 1024) self.assertEqual(Rand.load_file('tests/randpool.dat', -1), 1024) def test_seed_add(self): self.assertIsNone(Rand.rand_seed(os.urandom(1024))) # XXX Should there be limits on the entropy parameter? self.assertIsNone(Rand.rand_add(os.urandom(2), 0.5)) Rand.rand_add(os.urandom(2), -0.5) Rand.rand_add(os.urandom(2), 5000.0) def test_rand_status(self): # Although it is hard to believe we would ever get 0 (i.e., PRNG # hasn't enough entropy), it is a legitimate value. status = Rand.rand_status() self.assertIn(status, [0, 1], 'Illegal value of RAND.rand_status {0}!'.format(status)) if status == 0: warnings.warn('RAND_status reports insufficient seeding of PRNG!') def suite(): suite = unittest.TestSuite() suite.addTest(unittest.TestLoader().loadTestsFromTestCase(RandTestCase)) return suite if __name__ == '__main__': unittest.TextTestRunner().run(suite()) m2crypto-0.42.0/tests/test_rc4.py000066400000000000000000000027301465575656700166530ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import absolute_import """Unit tests for M2Crypto.RC4. Copyright (c) 2009 Heikki Toivonen. All rights reserved.""" from M2Crypto import RC4, Rand from binascii import hexlify from tests import unittest from tests.fips import fips_mode class RC4TestCase(unittest.TestCase): @unittest.skipIf(fips_mode, "Can't be run in FIPS mode") def test_vectors(self): """ Test with test vectors from Wikipedia: http://en.wikipedia.org/wiki/Rc4 """ if fips_mode: return vectors = ((b'Key', b'Plaintext', b'BBF316E8D940AF0AD3'), (b'Wiki', b'pedia', b'1021BF0420'), (b'Secret', b'Attack at dawn', b'45A01F645FC35B383552544B9BF5')) rc4 = RC4.RC4() for key, plaintext, ciphertext in vectors: rc4.set_key(key) self.assertEqual(hexlify(rc4.update(plaintext)).upper(), ciphertext) self.assertEqual(rc4.final(), '') @unittest.skipIf(fips_mode, "Can't be run in FIPS mode") def test_bad(self): if fips_mode: return rc4 = RC4.RC4(b'foo') self.assertNotEqual(hexlify(rc4.update(b'bar')).upper(), b'45678') def suite(): return unittest.TestLoader().loadTestsFromTestCase(RC4TestCase) if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_rsa.py000066400000000000000000000310731465575656700167520ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import absolute_import """Unit tests for M2Crypto.RSA. Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" import hashlib import logging import os from M2Crypto import BIO, RSA, Rand, X509, m2 from tests import unittest from tests.fips import fips_mode log = logging.getLogger('test_RSA') class RSATestCase(unittest.TestCase): errkey = 'tests/dsa.priv.pem' privkey = 'tests/rsa.priv.pem' privkey2 = 'tests/rsa.priv2.pem' pubkey = 'tests/rsa.pub.pem' data = hashlib.sha1(b'The magic words are squeamish ossifrage.').digest() e_padding_ok = ('pkcs1_padding', 'pkcs1_oaep_padding') s_padding_ok = ('pkcs1_padding',) s_padding_nok = ('no_padding', 'pkcs1_oaep_padding') if hasattr(m2, 'sslv23_padding'): s_padding_nok += ('sslv23_padding',) def gen_callback(self, *args): pass def gen2_callback(self): pass def pp_callback(self, *args): # The passphrase for rsa.priv2.pem is 'qwerty'. return b'qwerty' def pp2_callback(self, *args): # Misbehaving passphrase callback. return b'blabla' def test_rsa_exceptions(self): with self.assertRaises(RSA.RSAError): RSA.rsa_error() def test_loadkey_junk(self): with self.assertRaises(RSA.RSAError): RSA.load_key(self.errkey) def test_loadkey_pp(self): rsa = RSA.load_key(self.privkey2, self.pp_callback) self.assertEqual(len(rsa), 1024) self.assertEqual(rsa.e, b'\000\000\000\003\001\000\001') # aka 65537 aka 0xf4 self.assertEqual(rsa.check_key(), 1) def test_loadkey_pp_bad_cb(self): with self.assertRaises(RSA.RSAError): RSA.load_key(self.privkey2, self.pp2_callback) def test_loadkey(self): rsa = RSA.load_key(self.privkey) self.assertEqual(len(rsa), 1024) self.assertEqual(rsa.e, b'\000\000\000\003\001\000\001') # aka 65537 aka 0xf4 self.assertEqual(rsa.n, b"\x00\x00\x00\x81\x00\xcde!\x15\xdah\xb5`\xce[\xd6\x17d\xba8\xc1I\xb1\xf1\xber\x86K\xc7\xda\xb3\x98\xd6\xf6\x80\xae\xaa\x8f!\x9a\xefQ\xdeh\xbb\xc5\x99\x01o\xebGO\x8e\x9b\x9a\x18\xfb6\xba\x12\xfc\xf2\x17\r$\x00\xa1\x1a \xfc/\x13iUm\x04\x13\x0f\x91D~\xbf\x08\x19C\x1a\xe2\xa3\x91&\x8f\xcf\xcc\xf3\xa4HRf\xaf\xf2\x19\xbd\x05\xe36\x9a\xbbQ\xc86|(\xad\x83\xf2Eu\xb2EL\xdf\xa4@\x7f\xeel|\xfcU\x03\xdb\x89'") with self.assertRaises(AttributeError): getattr(rsa, 'nosuchprop') self.assertEqual(rsa.check_key(), 1) def test_loadkey_bio(self): with open(self.privkey, "rb") as f: keybio = BIO.MemoryBuffer(f.read()) rsa = RSA.load_key_bio(keybio) self.assertEqual(len(rsa), 1024) self.assertEqual(rsa.e, b'\000\000\000\003\001\000\001') # aka 65537 aka 0xf4 self.assertEqual(rsa.check_key(), 1) def test_keygen(self): rsa = RSA.gen_key(1024, 65537, self.gen_callback) self.assertEqual(len(rsa), 1024) self.assertEqual(rsa.e, b'\000\000\000\003\001\000\001') # aka 65537 aka 0xf4 self.assertEqual(rsa.check_key(), 1) def test_keygen_bad_cb(self): rsa = RSA.gen_key(1024, 65537, self.gen2_callback) self.assertEqual(len(rsa), 1024) self.assertEqual(rsa.e, b'\000\000\000\003\001\000\001') # aka 65537 aka 0xf4 self.assertEqual(rsa.check_key(), 1) def test_private_encrypt(self): priv = RSA.load_key(self.privkey) # pkcs1_padding for padding in self.s_padding_ok: p = getattr(RSA, padding) ctxt = priv.private_encrypt(self.data, p) ptxt = priv.public_decrypt(ctxt, p) self.assertEqual(ptxt, self.data) # The other paddings. for padding in self.s_padding_nok: p = getattr(RSA, padding) with self.assertRaises(RSA.RSAError): priv.private_encrypt(self.data, p) # Type-check the data to be encrypted. with self.assertRaises(TypeError): priv.private_encrypt(self.gen_callback, RSA.pkcs1_padding) @unittest.skipIf(m2.OPENSSL_VERSION_NUMBER < 0x1010103f or m2.OPENSSL_VERSION_NUMBER >= 0x30000000, 'Relies on fix which happened only in OpenSSL 1.1.1c') def test_public_encrypt(self): priv = RSA.load_key(self.privkey) # pkcs1_padding, pkcs1_oaep_padding for padding in self.e_padding_ok: p = getattr(RSA, padding) ctxt = priv.public_encrypt(self.data, p) ptxt = priv.private_decrypt(ctxt, p) self.assertEqual(ptxt, self.data) # no_padding m2.err_clear_error() with self.assertRaisesRegex(RSA.RSAError, 'data too small'): priv.public_encrypt(self.data, RSA.no_padding) # Type-check the data to be encrypted. with self.assertRaises(TypeError): priv.public_encrypt(self.gen_callback, RSA.pkcs1_padding) def test_x509_public_encrypt(self): x509 = X509.load_cert("tests/recipient.pem") rsa = x509.get_pubkey().get_rsa() rsa.public_encrypt(b"data", RSA.pkcs1_padding) def test_loadpub(self): rsa = RSA.load_pub_key(self.pubkey) self.assertEqual(len(rsa), 1024) self.assertEqual(rsa.e, b'\000\000\000\003\001\000\001') # aka 65537 aka 0xf4 with self.assertRaises(RSA.RSAError): setattr(rsa, 'e', '\000\000\000\003\001\000\001') with self.assertRaises(RSA.RSAError): rsa.private_decrypt(1) assert rsa.check_key() def test_loadpub_bad(self): with self.assertRaises(RSA.RSAError): RSA.load_pub_key(self.errkey) def test_savepub(self): rsa = RSA.load_pub_key(self.pubkey) assert rsa.as_pem() # calls save_key_bio f = 'tests/rsa_test.pub' try: self.assertEqual(rsa.save_key(f), 1) finally: try: os.remove(f) except IOError: pass def test_set_bn(self): rsa = RSA.load_pub_key(self.pubkey) with self.assertRaises(RSA.RSAError): m2.rsa_set_en(rsa.rsa, b'\000\000\000\003\001\000\001', b'\000\000\000\003\001') def test_set_n(self): rsa = m2.rsa_new() m2.rsa_set_n(rsa, b'\000\000\000\003\001\000\001') n = m2.rsa_get_n(rsa) e = m2.rsa_get_e(rsa) self.assertEqual(n, b'\000\000\000\003\001\000\001') self.assertEqual(e, b'\x00\x00\x00\x00') def test_set_e(self): rsa = m2.rsa_new() m2.rsa_set_e(rsa, b'\000\000\000\003\001\000\001') n = m2.rsa_get_n(rsa) e = m2.rsa_get_e(rsa) self.assertEqual(e, b'\000\000\000\003\001\000\001') self.assertEqual(n, b'\x00\x00\x00\x00') def test_set_n_then_set_e(self): rsa = m2.rsa_new() m2.rsa_set_n(rsa, b'\000\000\000\004\020\011\006\006') m2.rsa_set_e(rsa, b'\000\000\000\003\001\000\001') n = m2.rsa_get_n(rsa) e = m2.rsa_get_e(rsa) self.assertEqual(e, b'\000\000\000\003\001\000\001') self.assertEqual(n, b'\000\000\000\004\020\011\006\006') def test_newpub(self): old = RSA.load_pub_key(self.pubkey) new = RSA.new_pub_key(old.pub()) self.assertTrue(new.check_key()) self.assertEqual(len(new), 1024) # aka 65537 aka 0xf4 self.assertEqual(new.e, b'\000\000\000\003\001\000\001') def test_sign_and_verify(self): """ Testing signing and verifying digests """ algos = {'sha1': '', 'ripemd160': '', 'md5': ''} if m2.OPENSSL_VERSION_NUMBER >= 0x90800F: algos['sha224'] = '' algos['sha256'] = '' algos['sha384'] = '' algos['sha512'] = '' message = b"This is the message string" digest = hashlib.sha1(message).digest() rsa = RSA.load_key(self.privkey) rsa2 = RSA.load_pub_key(self.pubkey) for algo in algos.keys(): signature = rsa.sign(digest, algo) # assert signature == algos[algo], # 'mismatched signature with algorithm %s: # signature=%s' % (algo, signature) verify = rsa2.verify(digest, signature, algo) self.assertEqual(verify, 1, 'verification failed with algorithm %s' % algo) if m2.OPENSSL_VERSION_NUMBER >= 0x90708F: def test_sign_and_verify_rsassa_pss(self): """ Testing signing and verifying using rsassa_pss The maximum size of the salt has to decrease as the size of the digest increases because of the size of our test key limits it. """ message = b"This is the message string" import hashlib algos = {'sha1': 43} if not fips_mode: algos['md5'] = 47 algos['ripemd160'] = 43 if m2.OPENSSL_VERSION_NUMBER >= 0x90800F: algos['sha224'] = 35 algos['sha256'] = 31 algos['sha384'] = 15 algos['sha512'] = 0 for algo, salt_max in algos.items(): try: h = hashlib.new(algo) except ValueError: algos[algo] = (None, None) continue h.update(message) digest = h.digest() algos[algo] = (salt_max, digest) rsa = RSA.load_key(self.privkey) rsa2 = RSA.load_pub_key(self.pubkey) for algo, (salt_max, digest) in algos.items(): if salt_max is None or digest is None: continue for salt_length in range(0, salt_max): signature = rsa.sign_rsassa_pss(digest, algo, salt_length) verify = rsa2.verify_rsassa_pss(digest, signature, algo, salt_length) self.assertEqual(verify, 1, 'verification failed with algorithm ' '%s salt length %d' % (algo, salt_length)) def test_sign_bad_method(self): """ Testing calling sign with an unsupported message digest algorithm """ rsa = RSA.load_key(self.privkey) digest = 'a' * 16 with self.assertRaises(ValueError): rsa.sign(digest, 'bad_digest_method') def test_verify_bad_method(self): """ Testing calling verify with an unsupported message digest algorithm """ rsa = RSA.load_key(self.privkey) digest = b'a' * 16 signature = rsa.sign(digest, 'sha1') with self.assertRaises(ValueError): rsa.verify(digest, signature, 'bad_digest_method') def test_verify_mismatched_algo(self): """ Testing verify to make sure it fails when we use a different message digest algorithm """ rsa = RSA.load_key(self.privkey) message = b"This is the message string" digest = hashlib.sha1(message).digest() signature = rsa.sign(digest, 'sha1') with self.assertRaises(RSA.RSAError): rsa.verify(digest, signature, 'md5') def test_sign_fail(self): """ Testing sign to make sure it fails when I give it a bogus digest. Looking at the RSA sign method I discovered that with the digest methods we use it has to be longer than a certain length. """ rsa = RSA.load_key(self.privkey) digest = b"""This string should be long enough to warrant an error in RSA_sign""" * 2 with self.assertRaises(RSA.RSAError): rsa.sign(digest) def test_verify_bad_signature(self): """ Testing verify to make sure it fails when we use a bad signature """ rsa = RSA.load_key(self.privkey) message = b"This is the message string" digest = hashlib.sha1(message).digest() other_message = b"Abracadabra" other_digest = hashlib.sha1(other_message).digest() other_signature = rsa.sign(other_digest) with self.assertRaises(RSA.RSAError): rsa.verify(digest, other_signature) def suite(): return unittest.TestLoader().loadTestsFromTestCase(RSATestCase) if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_smime.py000066400000000000000000000312041465575656700172730ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.SMIME. Copyright (C) 2006 Open Source Applications Foundation. All Rights Reserved. """ import os.path from M2Crypto import BIO, EVP, Rand, SMIME, X509 from tests import unittest # Various callbacks to set by X509_Store.set_verify_cb() for # testing with SMIME.verify() afterwards. # NOTE: if the Python callback function contains compile-time or run-time # errors, then SMIME.verify() can fail with a mysterious error which can be # hard to trace back. # Python exceptions in callbacks do *not* propagate to verify() call. def verify_cb_dummy_function(ok, ctx): return ok def verify_cb_rejects_cert_from_heikki_toivonen(ok, ctx): cert = ctx.get_current_cert() return "Heikki Toivonen" not in cert.get_issuer().as_text() class SMIMETestCase(unittest.TestCase): cleartext = b'some text to manipulate' def setUp(self): # XXX Ugly, but not sure what would be better self.signed = self.do_test_sign() self.encrypted = self.do_test_encrypt() def test_load_bad(self): s = SMIME.SMIME() with self.assertRaises(EVP.EVPError): s.load_key('tests/signer.pem', 'tests/signer.pem') with self.assertRaises(BIO.BIOError): SMIME.load_pkcs7('nosuchfile-dfg456') with self.assertRaises(SMIME.PKCS7_Error): SMIME.load_pkcs7('tests/signer.pem') with self.assertRaises(SMIME.PKCS7_Error): SMIME.load_pkcs7_bio(BIO.MemoryBuffer(b'no pkcs7')) with self.assertRaises(BIO.BIOError): SMIME.load_pkcs7_der('nosuchfile-dfg456') with self.assertRaises(SMIME.PKCS7_Error): SMIME.load_pkcs7_der('tests/signer.pem') with self.assertRaises(SMIME.PKCS7_Error): SMIME.load_pkcs7_bio_der(BIO.MemoryBuffer(b'no pkcs7')) with self.assertRaises(SMIME.SMIME_Error): SMIME.smime_load_pkcs7('tests/signer.pem') with self.assertRaises(SMIME.SMIME_Error): SMIME.smime_load_pkcs7_bio(BIO.MemoryBuffer(b'no pkcs7')) def test_crlf(self): self.assertEqual(SMIME.text_crlf(b'foobar'), b'Content-Type: text/plain\r\n\r\nfoobar') self.assertEqual(SMIME.text_crlf_bio( BIO.MemoryBuffer(b'foobar')).read(), b'Content-Type: text/plain\r\n\r\nfoobar') def do_test_sign(self): buf = BIO.MemoryBuffer(self.cleartext) s = SMIME.SMIME() s.load_key('tests/signer_key.pem', 'tests/signer.pem') p7 = s.sign(buf, SMIME.PKCS7_DETACHED) self.assertEqual(len(buf), 0) self.assertEqual(p7.type(), SMIME.PKCS7_SIGNED, p7.type()) self.assertIsInstance(p7, SMIME.PKCS7, p7) out = BIO.MemoryBuffer() p7.write(out) buf = out.read() self.assertTrue(buf.startswith(b'-----BEGIN PKCS7-----'), b'-----BEGIN PKCS7-----') buf = buf.strip() self.assertTrue(buf.endswith(b'-----END PKCS7-----'), buf[-len(b'-----END PKCS7-----'):]) self.assertGreater(len(buf), len(b'-----END PKCS7-----') + len(b'-----BEGIN PKCS7-----')) s.write(out, p7, BIO.MemoryBuffer(self.cleartext)) return out def test_sign(self): self.do_test_sign() def test_sign_unknown_digest(self): buf = BIO.MemoryBuffer(self.cleartext) s = SMIME.SMIME() s.load_key('tests/signer_key.pem', 'tests/signer.pem') self.assertRaises(SMIME.SMIME_Error, s.sign, buf, SMIME.PKCS7_DETACHED, 'invalid digest name') def test_sign_nondefault_digest(self): buf = BIO.MemoryBuffer(self.cleartext) s = SMIME.SMIME() s.load_key('tests/signer_key.pem', 'tests/signer.pem') p7 = s.sign(buf, flags=SMIME.PKCS7_DETACHED, algo='sha512') self.assertEqual(p7.type(), SMIME.PKCS7_SIGNED) def test_sign_with_stack(self): buf = BIO.MemoryBuffer(self.cleartext) s = SMIME.SMIME() s.load_key('tests/signer_key.pem', 'tests/signer.pem') cert = X509.load_cert('tests/server.pem') stack = X509.X509_Stack() stack.push(cert) s.set_x509_stack(stack) p7 = s.sign(buf, flags=SMIME.PKCS7_DETACHED, algo='sha512') self.assertEqual(p7.type(), SMIME.PKCS7_SIGNED) def test_store_load_info(self): st = X509.X509_Store() with self.assertRaises(X509.X509Error): st.load_info('tests/ca.pem-typoname') self.assertEqual(st.load_info('tests/ca.pem'), 1) def test_verify(self): s = SMIME.SMIME() x509 = X509.load_cert('tests/signer.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) st = X509.X509_Store() st.load_info('tests/ca.pem') s.set_x509_store(st) p7, data = SMIME.smime_load_pkcs7_bio(self.signed) self.assertIsInstance(p7, SMIME.PKCS7, p7) v = s.verify(p7, data) self.assertEqual(v, self.cleartext) t = p7.get0_signers(sk) self.assertEqual(len(t), 1) self.assertEqual(t[0].as_pem(), x509.as_pem(), t[0].as_text()) def test_verify_with_static_callback(self): s = SMIME.SMIME() x509 = X509.load_cert('tests/signer.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) st = X509.X509_Store() st.load_info('tests/ca.pem') st.set_verify_cb(verify_cb_rejects_cert_from_heikki_toivonen) s.set_x509_store(st) p7, data = SMIME.smime_load_pkcs7_bio(self.signed) self.assertIsInstance(p7, SMIME.PKCS7, p7) # Should reject certificate issued by Heikki Toivonen: with self.assertRaises(SMIME.PKCS7_Error): s.verify(p7, data) data.seek(0) st.set_verify_cb(verify_cb_dummy_function) v = s.verify(p7, data) self.assertEqual(v, self.cleartext) data.seek(0) st.set_verify_cb() v = s.verify(p7, data) self.assertEqual(v, self.cleartext) def verify_cb_dummy_method(self, ok, store): return verify_cb_dummy_function(ok, store) def test_verify_with_method_callback(self): s = SMIME.SMIME() x509 = X509.load_cert('tests/signer.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) st = X509.X509_Store() st.load_info('tests/ca.pem') st.set_verify_cb(self.verify_cb_dummy_method) s.set_x509_store(st) p7, data = SMIME.smime_load_pkcs7_bio(self.signed) self.assertIsInstance(p7, SMIME.PKCS7, p7) v = s.verify(p7, data) self.assertEqual(v, self.cleartext) def test_verifyBad(self): s = SMIME.SMIME() x509 = X509.load_cert('tests/recipient.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) st = X509.X509_Store() st.load_info('tests/recipient.pem') s.set_x509_store(st) p7, data = SMIME.smime_load_pkcs7_bio(self.signed) self.assertIsInstance(p7, SMIME.PKCS7, p7) with self.assertRaises(SMIME.PKCS7_Error): s.verify(p7) # Bad signer def do_test_encrypt(self): buf = BIO.MemoryBuffer(self.cleartext) s = SMIME.SMIME() x509 = X509.load_cert('tests/recipient.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) with self.assertRaises(ValueError): SMIME.Cipher('nosuchcipher') s.set_cipher(SMIME.Cipher('des_ede3_cbc')) p7 = s.encrypt(buf) self.assertEqual(len(buf), 0) self.assertEqual(p7.type(), SMIME.PKCS7_ENVELOPED, p7.type()) self.assertIsInstance(p7, SMIME.PKCS7, p7) out = BIO.MemoryBuffer() p7.write(out) buf = out.read() self.assertTrue(buf.startswith(b'-----BEGIN PKCS7-----')) buf = buf.strip() self.assertTrue(buf.endswith(b'-----END PKCS7-----')) self.assertGreater(len(buf), len(b'-----END PKCS7-----') + len(b'-----BEGIN PKCS7-----')) s.write(out, p7) return out def test_encrypt(self): self.do_test_encrypt() def test_decrypt(self): s = SMIME.SMIME() s.load_key('tests/recipient_key.pem', 'tests/recipient.pem') p7, data = SMIME.smime_load_pkcs7_bio(self.encrypted) self.assertIsInstance(p7, SMIME.PKCS7, p7) with self.assertRaises(SMIME.SMIME_Error): s.verify(p7) # No signer out = s.decrypt(p7) self.assertEqual(out, self.cleartext) def test_decryptBad(self): s = SMIME.SMIME() s.load_key('tests/signer_key.pem', 'tests/signer.pem') p7, data = SMIME.smime_load_pkcs7_bio(self.encrypted) self.assertIsInstance(p7, SMIME.PKCS7, p7) with self.assertRaises(SMIME.SMIME_Error): s.verify(p7) # No signer # Cannot decrypt: no recipient matches certificate with self.assertRaises(SMIME.PKCS7_Error): s.decrypt(p7) def test_signEncryptDecryptVerify(self): # sign buf = BIO.MemoryBuffer(self.cleartext) s = SMIME.SMIME() s.load_key('tests/signer_key.pem', 'tests/signer.pem') p7 = s.sign(buf) # encrypt x509 = X509.load_cert('tests/recipient.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) s.set_cipher(SMIME.Cipher('des_ede3_cbc')) tmp = BIO.MemoryBuffer() s.write(tmp, p7) p7 = s.encrypt(tmp) signedEncrypted = BIO.MemoryBuffer() s.write(signedEncrypted, p7) # decrypt s = SMIME.SMIME() s.load_key('tests/recipient_key.pem', 'tests/recipient.pem') p7, data = SMIME.smime_load_pkcs7_bio(signedEncrypted) out = s.decrypt(p7) # verify x509 = X509.load_cert('tests/signer.pem') sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) st = X509.X509_Store() st.load_info('tests/ca.pem') s.set_x509_store(st) p7_bio = BIO.MemoryBuffer(out) p7, data = SMIME.smime_load_pkcs7_bio(p7_bio) v = s.verify(p7) self.assertEqual(v, self.cleartext) class WriteLoadTestCase(unittest.TestCase): def setUp(self): s = SMIME.SMIME() s.load_key('tests/signer_key.pem', 'tests/signer.pem') p7 = s.sign(BIO.MemoryBuffer(b'some text')) self.filename = 'tests/sig.p7' with BIO.openfile(self.filename, 'wb') as f: self.assertEqual(p7.write(f), 1) self.filename_der = 'tests/sig.p7.der' with BIO.openfile(self.filename_der, 'wb') as f: self.assertEqual(p7.write_der(f), 1) p7 = s.sign(BIO.MemoryBuffer(b'some text'), SMIME.PKCS7_DETACHED) self.filenameSmime = 'tests/sig.p7s' with BIO.openfile(self.filenameSmime, 'wb') as f: self.assertEqual(s.write(f, p7, BIO.MemoryBuffer(b'some text')), 1) def tearDown(self): if os.path.exists(self.filename_der): os.unlink(self.filename_der) def test_load_pkcs7(self): self.assertEqual(SMIME.load_pkcs7(self.filename).type(), SMIME.PKCS7_SIGNED) def test_load_pkcs7_bio(self): with open(self.filename, 'rb') as f: buf = BIO.MemoryBuffer(f.read()) self.assertEqual(SMIME.load_pkcs7_bio(buf).type(), SMIME.PKCS7_SIGNED) def test_load_pkcs7_der(self): self.assertEqual(SMIME.load_pkcs7_der(self.filename_der).type(), SMIME.PKCS7_SIGNED) def test_load_pkcs7_bio_der(self): with open(self.filename_der, 'rb') as f: buf = BIO.MemoryBuffer(f.read()) self.assertEqual(SMIME.load_pkcs7_bio_der(buf).type(), SMIME.PKCS7_SIGNED) def test_load_smime(self): a, b = SMIME.smime_load_pkcs7(self.filenameSmime) self.assertIsInstance(a, SMIME.PKCS7, a) self.assertIsInstance(b, BIO.BIO, b) self.assertEqual(a.type(), SMIME.PKCS7_SIGNED) def test_load_smime_bio(self): with open(self.filenameSmime, 'rb') as f: buf = BIO.MemoryBuffer(f.read()) a, b = SMIME.smime_load_pkcs7_bio(buf) self.assertIsInstance(a, SMIME.PKCS7, a) self.assertIsInstance(b, BIO.BIO, b) self.assertEqual(a.type(), SMIME.PKCS7_SIGNED) def suite(): suite = unittest.TestSuite() suite.addTest(unittest.TestLoader().loadTestsFromTestCase(SMIMETestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(WriteLoadTestCase)) return suite if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_ssl.py000066400000000000000000001326111465575656700167660ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import absolute_import, print_function """Unit tests for M2Crypto.SSL. Copyright (c) 2000-2004 Ng Pheng Siong. All rights reserved. Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved. """ """ TODO Server tests: - ??? Others: - SSLServer - ForkingSSLServer - ThreadingSSLServer """ import gc import logging import os import os.path import signal import socket import subprocess import sys import tempfile import time import warnings from M2Crypto import (Err, Rand, SSL, X509, ftpslib, httpslib, m2, m2urllib, m2urllib2, m2xmlrpclib, util) from M2Crypto.SSL.timeout import DEFAULT_TIMEOUT from tests import unittest from tests.fips import fips_mode log = logging.getLogger('test_SSL') OPENSSL111 = m2.OPENSSL_VERSION_NUMBER > 0x10101000 # FIXME # It would be probably better if the port was randomly selected. # https://fedorahosted.org/libuser/browser/tests/alloc_port.c srv_host = 'localhost' def allocate_srv_port(): s = socket.socket() try: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((srv_host, 0)) (host, port) = s.getsockname() finally: s.close() return port def verify_cb_new_function(ok, store): err = store.get_error() # If err is X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, then instead of # aborting, this callback is called to retrieve additional error # information. In this case, ok might not be False. # See https://github.com/openssl/openssl/commit/2e06150e3928daa06d5ff70c32bffad8088ebe58 if err != m2.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: assert not ok assert err in [ m2.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, m2.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, m2.X509_V_ERR_CERT_UNTRUSTED, m2.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, ] assert store.get_error_depth() == 0 app_data = m2.x509_store_ctx_get_ex_data( store.ctx, m2.ssl_get_ex_data_x509_store_ctx_idx() ) assert app_data x509 = store.get_current_cert() assert x509 stack = store.get1_chain() assert len(stack) == 1 assert stack[0].as_pem() == x509.as_pem() return 1 class VerifyCB(object): def __call__(self, ok, store): return verify_cb_new_function(ok, store) sleepTime = float(os.getenv('M2CRYPTO_TEST_SSL_SLEEP', '1.5')) class BaseSSLClientTestCase(unittest.TestCase): # I would like to make it into a staticmethod, but apparently it # doesn't mesh with @property. Oh well. @property def _is_openssl_in_path(self): if os.name == 'nt' or sys.platform == 'cygwin': openssl = 'openssl.exe' else: openssl = 'openssl' plist = os.environ['PATH'].split(os.pathsep) for p in plist: try: dir = os.listdir(p) if openssl in dir: return True except OSError: pass return False def start_server(self, args): if not self._is_openssl_in_path: raise RuntimeError('openssl command not in PATH') pid = subprocess.Popen( ['openssl'] + args, cwd='tests', stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) time.sleep(sleepTime) return pid def stop_server(self, pid): pid.terminate() out, err = pid.communicate() return out.decode(), err.decode() def http_get(self, s): s.send(b'GET / HTTP/1.0\n\n') resp = b'' while 1: try: r = s.recv(4096) if not r: break except ( SSL.SSLError ): # s_server throws an 'unexpected eof'... break resp = resp + r return resp.decode() def setUp(self): self.srv_host = srv_host self.srv_port = allocate_srv_port() self.srv_addr = (srv_host, self.srv_port) self.srv_url = 'https://%s:%s/' % (srv_host, self.srv_port) self.args = [ 's_server', '-www', '-cert', 'server.pem', '-accept', str(self.srv_port), ] self.test_output = 's_server -www' class PassSSLClientTestCase(BaseSSLClientTestCase): def test_pass(self): pass class HttpslibSSLClientTestCase(BaseSSLClientTestCase): def setUp(self): super(HttpslibSSLClientTestCase, self).setUp() self.ctx = SSL.Context() self.ctx.load_cert_chain( 'tests/server.pem', keyfile='tests/server_key.pem' ) def tearDown(self): self.ctx.close() def test_HTTPSConnection(self): pid = self.start_server(self.args) try: c = httpslib.HTTPSConnection( srv_host, self.srv_port, {'ssl_context': self.ctx} ) c.request('GET', '/') resp = c.getresponse() data = resp.read() c.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data.decode()) @unittest.skipIf(OPENSSL111, "Doesn't work with OpenSSL 1.1.1") def test_HTTPSConnection_resume_session(self): pid = self.start_server(self.args) try: self.ctx.load_verify_locations(cafile='tests/ca.pem') self.ctx.load_cert('tests/x509.pem') self.ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 1 ) self.ctx.set_session_cache_mode(m2.SSL_SESS_CACHE_CLIENT) c = httpslib.HTTPSConnection( srv_host, self.srv_port, ssl_context=self.ctx ) c.request('GET', '/') ses = c.get_session() t = ses.as_text() data = c.getresponse().read() # Appearently closing connection here screws session; Ali Polatel? # c.close() ctx2 = SSL.Context() ctx2.load_verify_locations(cafile='tests/ca.pem') ctx2.load_cert('tests/x509.pem') ctx2.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 1 ) ctx2.set_session_cache_mode(m2.SSL_SESS_CACHE_CLIENT) c2 = httpslib.HTTPSConnection( srv_host, self.srv_port, ssl_context=ctx2 ) c2.set_session(ses) c2.request('GET', '/') ses2 = c2.get_session() t2 = ses2.as_text() data = c2.getresponse().read().decode() c.close() c2.close() self.assertEqual( t, t2, "Sessions did not match: t = %s, t2 = %s" % ( t, t2, ), ) finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_HTTPSConnection_secure_context(self): pid = self.start_server(self.args) try: self.ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9 ) self.ctx.load_verify_locations('tests/ca.pem') c = httpslib.HTTPSConnection( srv_host, self.srv_port, ssl_context=self.ctx ) c.request('GET', '/') data = c.getresponse().read().decode() c.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_HTTPSConnection_secure_context_fail(self): pid = self.start_server(self.args) try: self.ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9 ) self.ctx.load_verify_locations('tests/server.pem') c = httpslib.HTTPSConnection( srv_host, self.srv_port, ssl_context=self.ctx ) with self.assertRaises(SSL.SSLError): c.request('GET', '/') c.close() finally: self.stop_server(pid) def test_HTTPSConnection_illegalkeywordarg(self): with self.assertRaises(ValueError): httpslib.HTTPSConnection('example.org', badKeyword=True) @unittest.skipIf( sys.platform == 'win32', "Test doesn't work on Windows" ) class HttpslibSSLSNIClientTestCase(BaseSSLClientTestCase): def setUp(self): super(HttpslibSSLSNIClientTestCase, self).setUp() self.args = [ 's_server', '-servername', srv_host, '-debug', '-www', '-msg', '-cert', 'server.pem', '-key', 'server_key.pem', '-cert2', 'server.pem', '-key2', 'server_key.pem', '-accept', str(self.srv_port), ] self.ctx = SSL.Context() def tearDown(self): self.ctx.close() def test_SNI_support(self): pid = self.start_server(self.args) try: c = httpslib.HTTPSConnection( self.srv_host, self.srv_port, ssl_context=self.ctx ) c.request('GET', '/') c.close() finally: # (openssl s_server) buffers its log output, and ends the TLS session # with the client (allowing the client to terminate) before flushing # the log; so, the client may get here and terminate the server # before it manages to log the output. # So, give the server hopefully enough time to flush the logs. time.sleep(sleepTime) out, _ = self.stop_server(pid) self.assertIn( 'Hostname in TLS extension: "%s"' % srv_host, out ) def test_IP_call(self): no_exception = True runs_counter = 0 pid = self.start_server(self.args) for entry in socket.getaddrinfo( self.srv_host, self.srv_port, socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, ): ipfamily, socktype, _, _, sockaddr = entry ip = sockaddr[0] sock = socket.socket(ipfamily, socktype) conn = SSL.Connection(self.ctx, sock=sock) conn.set_tlsext_host_name(self.srv_host) conn.set1_host(self.srv_host) runs_counter += 1 try: conn.connect((ip, self.srv_port)) except (SSL.SSLError, socket.error): log.exception( "Failed to connect to %s:%s", ip, self.srv_port ) no_exception = False finally: conn.close() out, _ = self.stop_server(pid) self.assertEqual( out.count( 'Hostname in TLS extension: "%s"' % self.srv_host ), runs_counter, ) self.assertTrue(no_exception) class MiscSSLClientTestCase(BaseSSLClientTestCase): def test_no_connection(self): ctx = SSL.Context() SSL.Connection(ctx) def test_server_simple(self): pid = self.start_server(self.args) try: with self.assertRaises(ValueError): SSL.Context('tlsv5') ctx = SSL.Context() s = SSL.Connection(ctx) s.connect(self.srv_addr) with self.assertRaises(ValueError): s.read(0) data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_server_simple_secure_context(self): pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9 ) ctx.load_verify_locations('tests/ca.pem') s = SSL.Connection(ctx) s.connect(self.srv_addr) data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_server_simple_secure_context_fail(self): pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9 ) ctx.load_verify_locations('tests/server.pem') s = SSL.Connection(ctx) with self.assertRaises(SSL.SSLError): s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) @unittest.skipIf((util.is_32bit() and util.is_libc_musl()), "socket.setsockopt() on musl libc fails (srht#mcepl/m2crypto#341)") def test_server_simple_timeouts(self): pid = self.start_server(self.args) # Arbitrary value: test_timeout_sec = 909 # Linux rounds microseconds in the timeouts up to the HZ kernel parameter. # Windows rounds down to milliseconds. # To avoid checking for rounded values, pick interval long enough # so that it is a whole number of ms and HZ for any reasonable HZ value. test_timeout_microsec = 500000 try: with self.assertRaises(ValueError): SSL.Context('tlsv5') ctx = SSL.Context() s = SSL.Connection(ctx) r = s.get_socket_read_timeout() w = s.get_socket_write_timeout() self.assertEqual(r.sec, 0, r.sec) self.assertEqual(r.microsec, 0, r.microsec) self.assertEqual(w.sec, 0, w.sec) self.assertEqual(w.microsec, 0, w.microsec) s.set_socket_read_timeout(SSL.timeout()) s.set_socket_write_timeout( SSL.timeout(test_timeout_sec, test_timeout_microsec) ) r = s.get_socket_read_timeout() w = s.get_socket_write_timeout() self.assertEqual(r.sec, DEFAULT_TIMEOUT, r.sec) self.assertEqual(r.microsec, 0, r.microsec) self.assertEqual(w.sec, test_timeout_sec, w.sec) self.assertLess( abs(w.microsec - test_timeout_microsec), 4000, w.microsec, ) s.connect(self.srv_addr) data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) # TLS is required in FIPS mode @unittest.skipIf(fips_mode, "Can't be run in FIPS mode") def test_tls1_nok(self): self.args.append('-no_tls1') pid = self.start_server(self.args) try: with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) ctx = SSL.Context('tlsv1') s = SSL.Connection(ctx) s.set_cipher_list('DEFAULT:@SECLEVEL=0') with self.assertRaisesRegex(SSL.SSLError, r'version|unexpected eof'): s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) @unittest.skipIf( m2.OPENSSL_VERSION_NUMBER >= 0x30000000, "No TLS1 is allowed" ) def test_tls1_ok(self): self.args.append('-tls1') pid = self.start_server(self.args) try: with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) ctx = SSL.Context('tlsv1') s = SSL.Connection(ctx) s.connect(self.srv_addr) data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_cipher_mismatch(self): self.args = self.args + ['-cipher', 'AES256-SHA'] pid = self.start_server(self.args) try: ctx = SSL.Context() s = SSL.Connection(ctx) s.set_cipher_list('AES128-SHA') if not OPENSSL111: with self.assertRaisesRegex(SSL.SSLError, 'sslv3 alert handshake failure'): s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) def test_no_such_cipher(self): self.args = self.args + ['-cipher', 'AES128-SHA'] pid = self.start_server(self.args) try: ctx = SSL.Context() s = SSL.Connection(ctx) s.set_cipher_list('EXP-RC2-MD5') if not OPENSSL111: with self.assertRaisesRegex(SSL.SSLError, 'no ciphers available'): s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) def test_cipher_ok(self): if OPENSSL111: TCIPHER = 'TLS_AES_256_GCM_SHA384' self.args = self.args + ['-ciphersuites', TCIPHER] else: TCIPHER = 'AES128-SHA' self.args = self.args + ['-cipher', TCIPHER] pid = self.start_server(self.args) try: ctx = SSL.Context() s = SSL.Connection(ctx) s.set_cipher_list(TCIPHER) s.connect(self.srv_addr) data = self.http_get(s) self.assertEqual( s.get_cipher().name(), TCIPHER, s.get_cipher().name() ) cipher_stack = s.get_ciphers() self.assertEqual( cipher_stack[0].name(), TCIPHER, cipher_stack[0].name(), ) if not OPENSSL111: with self.assertRaises(IndexError): cipher_stack.__getitem__(2) # For some reason there are 2 entries in the stack # self.assertEqual(len(cipher_stack), 1, len(cipher_stack)) self.assertEqual( s.get_cipher_list(), TCIPHER, s.get_cipher_list() ) # Test Cipher_Stack iterator i = 0 for cipher in cipher_stack: i += 1 if not OPENSSL111: cipname = cipher.name() self.assertEqual( cipname, 'AES128-SHA', '"%s" (%s)' % (cipname, type(cipname)), ) self.assertEqual('AES128-SHA-128', str(cipher)) # For some reason there are 2 entries in the stack # self.assertEqual(i, 1, i) self.assertEqual(i, len(cipher_stack)) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def verify_cb_new(self, ok, store): return verify_cb_new_function(ok, store) def test_verify_cb_new(self): pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, self.verify_cb_new, ) s = SSL.Connection(ctx) try: s.connect(self.srv_addr) except SSL.SSLError as e: self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_verify_cb_new_class(self): pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, VerifyCB(), ) s = SSL.Connection(ctx) try: s.connect(self.srv_addr) except SSL.SSLError as e: log.exception(e) self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_verify_cb_new_function(self): pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, verify_cb_new_function, ) s = SSL.Connection(ctx) try: s.connect(self.srv_addr) except SSL.SSLError as e: self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_verify_cb_lambda(self): pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, lambda ok, store: 1, ) s = SSL.Connection(ctx) try: s.connect(self.srv_addr) except SSL.SSLError as e: self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def verify_cb_exception(self, ok, store): self.fail('We should fail verification') def test_verify_cb_exception(self): pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, self.verify_cb_exception, ) s = SSL.Connection(ctx) with self.assertRaises(SSL.SSLError): s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) def test_verify_cb_not_callable(self): ctx = SSL.Context() with self.assertRaises(TypeError): ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, 1, ) def test_verify_cb_wrong_callable(self): pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, lambda _: '', ) s = SSL.Connection(ctx) with self.assertRaises(SSL.SSLError): with warnings.catch_warnings(): warnings.simplefilter( 'ignore', DeprecationWarning ) s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) def verify_cb_old(self, ctx_ptr, x509_ptr, err, depth, ok): try: # If err is X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, then instead of # aborting, this callback is called to retrieve additional error # information. In this case, ok might not be False. # See https://github.com/openssl/openssl/commit/2e06150e3928daa06d5ff70c32bffad8088ebe58 if err != m2.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: self.assertFalse(ok) self.assertIn( err, [ m2.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, m2.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, m2.X509_V_ERR_CERT_UNTRUSTED, m2.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, ], ) self.assertTrue(m2.ssl_ctx_get_cert_store(ctx_ptr)) self.assertTrue(X509.X509(x509_ptr).as_pem()) except AssertionError: # If we let exceptions propagate from here the # caller may see strange errors. This is cleaner. return 0 return 1 def test_verify_cb_old(self): with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, self.verify_cb_old, ) s = SSL.Connection(ctx) try: s.connect(self.srv_addr) except SSL.SSLError as e: self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_verify_allow_unknown_old(self): pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, SSL.cb.ssl_verify_callback_allow_unknown_ca, ) ctx.set_allow_unknown_ca(1) s = SSL.Connection(ctx) try: s.connect(self.srv_addr) except SSL.SSLError: log.error('Failed to connect to %s', self.srv_addr) raise data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_verify_allow_unknown_new(self): pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9, SSL.cb.ssl_verify_callback_allow_unknown_ca, ) s = SSL.Connection(ctx) try: s.connect(self.srv_addr) except SSL.SSLError as e: self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_verify_cert(self): pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9 ) ctx.load_verify_locations('tests/ca.pem') s = SSL.Connection(ctx) try: s.connect(self.srv_addr) except SSL.SSLError as e: self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_verify_cert_fail(self): pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9 ) ctx.load_verify_locations('tests/server.pem') s = SSL.Connection(ctx) with self.assertRaises(SSL.SSLError): s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) def test_verify_cert_mutual_auth(self): self.args.extend(['-Verify', '2', '-CAfile', 'ca.pem']) pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9 ) ctx.load_verify_locations('tests/ca.pem') ctx.load_cert('tests/x509.pem') s = SSL.Connection(ctx) try: s.connect(self.srv_addr) except SSL.SSLError as e: self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_verify_cert_mutual_auth_servernbio(self): self.args.extend( ['-Verify', '2', '-CAfile', 'ca.pem', '-nbio'] ) pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9 ) ctx.load_verify_locations('tests/ca.pem') ctx.load_cert('tests/x509.pem') s = SSL.Connection(ctx) try: s.connect(self.srv_addr) except SSL.SSLError as e: self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_verify_cert_mutual_auth_fail(self): self.args.extend(['-Verify', '2', '-CAfile', 'ca.pem']) pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9 ) ctx.load_verify_locations('tests/ca.pem') s = SSL.Connection(ctx) if not OPENSSL111: with self.assertRaises(SSL.SSLError): s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) def test_verify_nocert_fail(self): self.args.extend(['-nocert']) pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9 ) ctx.load_verify_locations('tests/ca.pem') s = SSL.Connection(ctx) with self.assertRaises(SSL.SSLError): s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) def test_blocking0(self): pid = self.start_server(self.args) try: ctx = SSL.Context() s = SSL.Connection(ctx) s.setblocking(0) with self.assertRaises(Exception): s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) def test_blocking1(self): pid = self.start_server(self.args) try: ctx = SSL.Context() s = SSL.Connection(ctx) s.setblocking(1) try: s.connect(self.srv_addr) except SSL.SSLError as e: self.fail(e) data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) @unittest.skip( "Doesn't work with modern s_server, which checks HTTPS protocol." ) def test_makefile(self): pid = self.start_server(self.args) try: ctx = SSL.Context() s = SSL.Connection(ctx) try: s.connect(self.srv_addr) except SSL.SSLError as e: self.fail(e) bio = s.makefile('rwb') # s.close() # XXX bug 6628? bio.write(b'GET / HTTP/1.0\n\n') bio.flush() data = bio.read() bio.close() s.close() finally: self.stop_server(pid) self.assertIn(self.test_output.encode(), data) def test_makefile_err(self): pid = self.start_server(self.args) try: ctx = SSL.Context() s = SSL.Connection(ctx) try: s.connect(self.srv_addr) except SSL.SSLError as e: self.fail(e) f = s.makefile() data = self.http_get(s) s.close() del f del s err_code = Err.peek_error_code() self.assertEqual( err_code, 0, 'Unexpected error: %s' % err_code ) err = Err.get_error() self.assertIsNone(err, 'Unexpected error: %s' % err) finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_info_callback(self): pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_info_callback() s = SSL.Connection(ctx) s.connect(self.srv_addr) data = self.http_get(s) s.close() finally: self.stop_server(pid) self.assertIn(self.test_output, data) def test_ssl_connection_free(self): pid = self.start_server(self.args) orig_m2_ssl_free = SSL.Connection.m2_ssl_free def _m2_ssl_free(ssl): orig_m2_ssl_free(ssl) _m2_ssl_free.called = True try: ctx = SSL.Context() s = SSL.Connection(ctx) s.m2_ssl_free = _m2_ssl_free s.connect(self.srv_addr) data = self.http_get(s) s.close() self.assertFalse(hasattr(_m2_ssl_free, 'called')) # keep fingers crossed that SSL.Connection.__del__ is called # by the python interpreter del s finally: self.stop_server(pid) self.assertIn(self.test_output, data) self.assertTrue(getattr(_m2_ssl_free, 'called', False)) def test_ssl_connection_no_free(self): pid = self.start_server(self.args) orig_m2_ssl_free = SSL.Connection.m2_ssl_free def _m2_ssl_free(ssl): _m2_ssl_free.called = True orig_m2_ssl_free(ssl) try: ctx = SSL.Context() s = SSL.Connection(ctx) s.m2_ssl_free = _m2_ssl_free s.set_ssl_close_flag(m2.bio_close) s.connect(self.srv_addr) data = self.http_get(s) s.close() self.assertFalse(hasattr(_m2_ssl_free, 'called')) # keep fingers crossed that SSL.Connection.__del__ is called # by the python interpreter del s finally: self.stop_server(pid) self.assertIn(self.test_output, data) self.assertFalse(hasattr(_m2_ssl_free, 'called')) class Urllib2SSLClientTestCase(BaseSSLClientTestCase): def test_urllib2(self): pid = self.start_server(self.args) try: opener = m2urllib2.build_opener() opener.addheaders = [('Connection', 'close')] u = opener.open( 'https://%s:%s/' % (srv_host, self.srv_port) ) data = u.read() u.close() finally: self.stop_server(pid) self.assertIn(self.test_output.encode(), data) def test_urllib2_secure_context(self): pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9 ) ctx.load_verify_locations('tests/ca.pem') opener = m2urllib2.build_opener(ctx) opener.addheaders = [('Connection', 'close')] u = opener.open( 'https://%s:%s/' % (srv_host, self.srv_port) ) data = u.read() u.close() finally: self.stop_server(pid) self.assertIn(self.test_output.encode(), data) def test_urllib2_secure_context_fail(self): pid = self.start_server(self.args) try: ctx = SSL.Context() ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9 ) ctx.load_verify_locations('tests/server.pem') opener = m2urllib2.build_opener(ctx) opener.addheaders = [('Connection', 'close')] with self.assertRaises(SSL.SSLError): opener.open( 'https://%s:%s/' % (srv_host, self.srv_port) ) finally: self.stop_server(pid) def test_z_urllib2_opener(self): pid = self.start_server(self.args) try: ctx = SSL.Context() opener = m2urllib2.build_opener( ctx, m2urllib2.HTTPBasicAuthHandler() ) m2urllib2.install_opener(opener) req = m2urllib2.Request( 'https://%s:%s/' % (srv_host, self.srv_port) ) u = m2urllib2.urlopen(req) data = u.read() u.close() finally: self.stop_server(pid) self.assertIn(self.test_output.encode(), data) def test_urllib2_opener_handlers(self): ctx = SSL.Context() m2urllib2.build_opener(ctx, m2urllib2.HTTPBasicAuthHandler()) def test_urllib2_leak(self): pid = self.start_server(self.args) try: o = m2urllib2.build_opener() r = o.open('https://%s:%s/' % (srv_host, self.srv_port)) s = [r.fp._sock.fp] r.close() # TODO This should be assertEqual 1, but we leak sock # somehwere. Not sure how to fix it. log.debug( 'get_referrers = %d', len(gc.get_referrers(s[0])) ) self.assertLessEqual(len(gc.get_referrers(s[0])), 2) finally: self.stop_server(pid) class Urllib2TEChunkedSSLClientTestCase(BaseSSLClientTestCase): """Test a response with "Transfer-Encoding: chunked".""" def setUp(self): super(Urllib2TEChunkedSSLClientTestCase, self).setUp() self.args = [ 's_server', '-quiet', '-HTTP', '-accept', str(self.srv_port), ] def test_transfer_encoding_chunked(self): pid = self.start_server(self.args) try: url = 'https://%s:%s/te_chunked_response.txt' % ( srv_host, self.srv_port, ) o = m2urllib2.build_opener() u = o.open(url) data = u.read() self.assertEqual(b'foo\nfoobar\n', data) finally: self.stop_server(pid) @unittest.skip( "Twisted integration has been temporarily switched off." ) class TwistedSSLClientTestCase(BaseSSLClientTestCase): def test_timeout(self): pid = self.start_server(self.args) try: ctx = SSL.Context() s = SSL.Connection(ctx) # Just a really small number so we can timeout s.settimeout(0.000000000000000000000000000001) # TODO: Figure out which exception should be raised for timeout. # The following assertion originally expected only a # SSL.SSLTimeoutError exception, but what is raised is actually a # socket.timeout exception. As a temporary circumvention to this # issue, both exceptions are now tolerated. A final fix would need # to figure out which of these two exceptions is supposed to be # raised by SSL.Connection.connect() and possibly other methods # to indicate a timeout. with self.assertRaises( (SSL.SSLTimeoutError, socket.timeout) ): s.connect(self.srv_addr) s.close() finally: self.stop_server(pid) def test_makefile_timeout(self): # httpslib uses makefile to read the response pid = self.start_server(self.args) try: c = httpslib.HTTPSConnection(srv_host, self.srv_port) c.putrequest('GET', '/') c.putheader('Accept', 'text/html') c.putheader('Accept', 'text/plain') c.endheaders() c.sock.settimeout(100) resp = c.getresponse() self.assertEqual(resp.status, 200, resp.reason) data = resp.read() c.close() finally: self.stop_server(pid) self.assertIn(self.test_output.encode(), data) @unittest.skipIf( sys.platform == 'win32', "os.mkfifo not available on Windows" ) def test_makefile_timeout_fires(self): # This is convoluted because (openssl s_server -www) starts # writing the response as soon as it receives the first line of # the request, so it's possible for it to send the response # before the request is sent and there would be no timeout. So, # let the server spend time reading from an empty pipe FIFO_NAME = 'test_makefile_timeout_fires_fifo' # noqa os.mkfifo('tests/' + FIFO_NAME) pipe_pid = os.fork() try: if pipe_pid == 0: try: with open('tests/' + FIFO_NAME, 'w') as f: time.sleep(sleepTime + 1) f.write('Content\n') finally: os._exit(0) self.args[self.args.index('-www')] = '-WWW' pid = self.start_server(self.args) try: c = httpslib.HTTPSConnection(srv_host, self.srv_port) c.putrequest('GET', '/' + FIFO_NAME) c.putheader('Accept', 'text/html') c.putheader('Accept', 'text/plain') c.endheaders() c.sock.settimeout(0.0000000001) with self.assertRaises(socket.timeout): c.getresponse() c.close() finally: self.stop_server(pid) finally: os.kill(pipe_pid, signal.SIGTERM) os.waitpid(pipe_pid, 0) os.unlink('tests/' + FIFO_NAME) def test_twisted_wrapper(self): # Test only when twisted and ZopeInterfaces are present try: from twisted.internet.protocol import ClientFactory from twisted.protocols.basic import LineReceiver from twisted.internet import reactor import M2Crypto.SSL.TwistedProtocolWrapper as wrapper except ImportError: warnings.warn( 'Skipping twisted wrapper test because twisted not found' ) return # TODO Class must implement all abstract methods class EchoClient(LineReceiver): def connectionMade(self): self.sendLine(b'GET / HTTP/1.0\n\n') def lineReceived(self, line): global twisted_data twisted_data += line class EchoClientFactory(ClientFactory): protocol = EchoClient def clientConnectionFailed(self, connector, reason): reactor.stop() self.fail(reason) def clientConnectionLost(self, connector, reason): reactor.stop() pid = self.start_server(self.args) class ContextFactory(object): def getContext(self): return SSL.Context() try: global twisted_data twisted_data = b'' context_factory = ContextFactory() factory = EchoClientFactory() wrapper.connectSSL( srv_host, self.srv_port, factory, context_factory ) # This will block until reactor.stop() is called reactor.run() finally: self.stop_server(pid) self.assertIn(self.test_output.encode(), twisted_data) twisted_data = '' class XmlRpcLibTestCase(unittest.TestCase): def test_lib(self): m2xmlrpclib.SSL_Transport() # XXX need server to test against class FtpsLibTestCase(unittest.TestCase): def test_lib(self): ftpslib.FTP_TLS() # XXX need server to test against class SessionTestCase(unittest.TestCase): def test_session_load_bad(self): with self.assertRaises(SSL.SSLError): SSL.Session.load_session('tests/signer.pem') class FtpslibTestCase(unittest.TestCase): def test_26_compat(self): f = ftpslib.FTP_TLS() # 2.6 used to raise AttributeError: with self.assertRaises( ( socket.gaierror, socket.error, ) ): f.connect('no-such-host-dfgHJK56789', 990) def suite(): suite = unittest.TestSuite() suite.addTest(unittest.TestLoader().loadTestsFromTestCase(SessionTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(XmlRpcLibTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(FtpsLibTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(PassSSLClientTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(HttpslibSSLClientTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(HttpslibSSLSNIClientTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(Urllib2SSLClientTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(Urllib2TEChunkedSSLClientTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(MiscSSLClientTestCase)) suite.addTest(unittest.TestLoader().loadTestsFromTestCase(FtpslibTestCase)) try: import M2Crypto.SSL.TwistedProtocolWrapper as wrapper # noqa suite.addTest( unittest.TestLoader().loadTestsFromTestCase( TwistedSSLClientTestCase ) ) except ImportError: pass return suite def zap_servers(): s = 's_server' fn = tempfile.mktemp() cmd = 'ps | egrep %s > %s' % (s, fn) os.system(cmd) with open(fn) as f: while 1: ps = f.readline() if not ps: break chunk = ps.split() pid, cmd = chunk[0], chunk[4] if cmd == s: os.kill(int(pid), signal.SIGTERM) os.unlink(fn) if __name__ == '__main__': report_leaks = 0 if report_leaks: gc.enable() gc.set_debug(gc.DEBUG_LEAK & ~gc.DEBUG_SAVEALL) try: Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') finally: zap_servers() if report_leaks: from tests import alltests alltests.dump_garbage() m2crypto-0.42.0/tests/test_ssl_offline.py000066400000000000000000000041131465575656700204630ustar00rootroot00000000000000from __future__ import absolute_import """Unit tests for M2Crypto.SSL offline parts Copyright (C) 2006 Open Source Applications Foundation. All Rights Reserved. Copyright (C) 2009-2010 Heikki Toivonen. All Rights Reserved. """ import doctest from M2Crypto import Rand, SSL, X509 from tests import unittest from tests.test_ssl import srv_host class CheckerTestCase(unittest.TestCase): def test_checker(self): check = SSL.Checker.Checker( host=srv_host, peerCertHash='86C01325EFBC44098723CC1567EB75A68727A3D6') x509 = X509.load_cert('tests/server.pem') self.assertTrue(check(x509, srv_host)) with self.assertRaises(SSL.Checker.WrongHost): check(x509, 'example.com') doctest.testmod(SSL.Checker) class ContextTestCase(unittest.TestCase): def test_ctx_load_verify_locations(self): ctx = SSL.Context() with self.assertRaises(ValueError): ctx.load_verify_locations(None, None) def test_ctx_set_default_verify_paths(self): ctx = SSL.Context() ctx.set_default_verify_paths() # test will get here only if the previous won't fail def test_map(self): from M2Crypto.SSL.Context import ctxmap, _ctxmap self.assertIsInstance(ctxmap(), _ctxmap) ctx = SSL.Context() assert ctxmap() ctx.close() self.assertIs(ctxmap(), _ctxmap.singleton) def test_certstore(self): ctx = SSL.Context() ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) ctx.load_verify_locations('tests/ca.pem') ctx.load_cert('tests/x509.pem') store = ctx.get_cert_store() self.assertIsInstance(store, X509.X509_Store) def suite(): t_suite = unittest.TestSuite() t_suite.addTest(unittest.TestLoader().loadTestsFromTestCase(CheckerTestCase)) t_suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ContextTestCase)) return t_suite if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_ssl_win.py000066400000000000000000000037221465575656700176430ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import absolute_import """Unit tests for M2Crypto.SSL. Win32 version - requires Mark Hammond's Win32 extensions and openssl.exe on your PATH. Copyright (c) 2000-2001 Ng Pheng Siong. All rights reserved.""" import os import os.path import time try: import win32process except ImportError: win32process = None from tests import test_ssl, unittest if win32process: from M2Crypto import Rand def find_openssl(): plist = os.environ['PATH'].split(';') for p in plist: try: path_dir = os.listdir(p) if 'openssl.exe' in path_dir: return os.path.join(p, 'openssl.exe') except OSError: pass return None srv_host = 'localhost' srv_port = 64000 class SSLWinClientTestCase(test_ssl.BaseSSLClientTestCase): startupinfo = win32process.STARTUPINFO() openssl = find_openssl() def start_server(self, args): # openssl must be started in the tests directory for it # to find the .pem files os.chdir('tests') try: hproc, _, _, _ = win32process.CreateProcess( self.openssl, ' '.join(args), None, None, 0, win32process.DETACHED_PROCESS, None, None, self.startupinfo) finally: os.chdir('..') time.sleep(0.3) return hproc def stop_server(self, hproc): win32process.TerminateProcess(hproc, 0) def suite(): return unittest.TestLoader().loadTestsFromTestCase(SSLWinClientTestCase) def zap_servers(): pass if __name__ == '__main__': try: if find_openssl() is not None: Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') finally: zap_servers() m2crypto-0.42.0/tests/test_threading.py000066400000000000000000000016221465575656700201270ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.threading. Copyright (C) 2007 Open Source Applications Foundation. All Rights Reserved. """ from M2Crypto import threading as m2threading, Rand from tests import unittest class ThreadingTestCase(unittest.TestCase): def setUp(self): m2threading.init() def tearDown(self): m2threading.cleanup() def test_pass(self): pass def test_multiInitCleanup(self): m2threading.init() m2threading.init() m2threading.cleanup() m2threading.cleanup() m2threading.init() m2threading.cleanup() def suite(): suite = unittest.TestSuite() suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ThreadingTestCase)) return suite if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/test_timeout.py000066400000000000000000000101161465575656700176460ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.SSL.timeout. """ import sys from M2Crypto.SSL import timeout, struct_to_timeout, struct_size from tests import unittest # Max value for sec argument on Windows: # - needs to fit DWORD (signed 32-bit) when converted to millisec MAX_SEC_WIN32 = int((2**31 - 1) / 1000) # Max value for sec argument on other platforms: # Note: It may actually be 64-bit but we are happy with 32-bit. # We use the signed maximum, because the packing uses lower case "l". MAX_SEC_OTHER = 2**31 - 1 # Enable this to test the Windows logic on a non-Windows platform: # sys.platform = 'win32' class TimeoutTestCase(unittest.TestCase): def timeout_test(self, sec, microsec, exp_sec=None, exp_microsec=None): """ Test that the timeout values (sec, microsec) are the same after round tripping through a pack / unpack cycle. """ if exp_sec is None: exp_sec = sec if exp_microsec is None: exp_microsec = microsec to = timeout(sec, microsec) binstr = to.pack() act_to = struct_to_timeout(binstr) self.assertEqual( (act_to.sec, act_to.microsec), (exp_sec, exp_microsec), "Unexpected timeout(sec,microsec) after pack + unpack: " "Got (%r,%r), expected (%r,%r), input was (%r,%r)" % (act_to.sec, act_to.microsec, exp_sec, exp_microsec, sec, microsec)) def test_timeout_0_0(self): self.timeout_test(0, 0) def test_timeout_123_0(self): self.timeout_test(123, 0) def test_timeout_max_0(self): if sys.platform == 'win32': self.timeout_test(MAX_SEC_WIN32, 0) else: self.timeout_test(MAX_SEC_OTHER, 0) def test_timeout_0_456000(self): self.timeout_test(0, 456000) def test_timeout_123_456000(self): self.timeout_test(123, 456000) def test_timeout_2_3000000(self): if sys.platform == 'win32': self.timeout_test(2, 3000000, 5, 0) else: self.timeout_test(2, 3000000) def test_timeout_2_2499000(self): if sys.platform == 'win32': self.timeout_test(2, 2499000, 4, 499000) else: self.timeout_test(2, 2499000) def test_timeout_2_2999000(self): if sys.platform == 'win32': self.timeout_test(2, 2999000, 4, 999000) else: self.timeout_test(2, 2999000) def test_timeout_max_456000(self): if sys.platform == 'win32': self.timeout_test(MAX_SEC_WIN32, 456000) else: self.timeout_test(MAX_SEC_OTHER, 456000) def test_timeout_0_456(self): if sys.platform == 'win32': self.timeout_test(0, 456, None, 0) else: self.timeout_test(0, 456) def test_timeout_123_456(self): if sys.platform == 'win32': self.timeout_test(123, 456, None, 0) else: self.timeout_test(123, 456) def test_timeout_max_456(self): if sys.platform == 'win32': self.timeout_test(MAX_SEC_WIN32, 456, None, 0) else: self.timeout_test(MAX_SEC_OTHER, 456) def test_timeout_1_499(self): if sys.platform == 'win32': self.timeout_test(123, 499, None, 0) # 499 us rounds down to 0 else: self.timeout_test(123, 499) def test_timeout_1_501(self): # We use 501 for this test and not 500 because 0.5 is not exactly # represented in binary floating point numbers, and because 0.5 # rounds differently between py2 and py3. See Python round() docs. if sys.platform == 'win32': self.timeout_test(123, 501, None, 1000) # 501 us rounds up to 1000 else: self.timeout_test(123, 501) def test_timeout_size(self): exp_size = len(timeout(0, 0).pack()) self.assertEqual(struct_size(), exp_size) def suite(): suite = unittest.TestSuite() suite.addTest(unittest.TestLoader().loadTestsFromTestCase(TimeoutTestCase)) return suite if __name__ == '__main__': unittest.TextTestRunner().run(suite()) m2crypto-0.42.0/tests/test_x509.py000066400000000000000000000714261465575656700167000ustar00rootroot00000000000000#!/usr/bin/env python """Unit tests for M2Crypto.X509. Contributed by Toby Allsopp under M2Crypto's license. Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2004-2005 OSAF. All Rights Reserved. Author: Heikki Toivonen """ import base64 import logging import os import platform import time import warnings from M2Crypto import ASN1, BIO, EVP, RSA, Rand, X509, m2 # noqa from M2Crypto.util import is_32bit, is_libc_musl, expectedFailureIf from tests import unittest log = logging.getLogger(__name__) class X509TestCase(unittest.TestCase): def callback(self, *args): pass def setUp(self): self.expected_hash = 'BA4212E8B55527570828E7F5A0005D17C64BDC4C' def mkreq(self, bits, ca=0): pk = EVP.PKey() x = X509.Request() rsa = RSA.gen_key(bits, 65537, self.callback) pk.assign_rsa(rsa) rsa = None # should not be freed here x.set_pubkey(pk) name = x.get_subject() name.C = "UK" name.CN = "OpenSSL Group" if not ca: ext1 = X509.new_extension('subjectAltName', 'DNS:foobar.example.com') ext2 = X509.new_extension('nsComment', 'Hello there') extstack = X509.X509_Extension_Stack() extstack.push(ext1) extstack.push(ext2) x.add_extensions(extstack) with self.assertRaises(ValueError): x.sign(pk, 'sha513') x.sign(pk, 'sha1') self.assertTrue(x.verify(pk)) pk2 = x.get_pubkey() self.assertTrue(x.verify(pk2)) return x, pk def test_ext(self): with self.assertRaises(ValueError): X509.new_extension('subjectKeyIdentifier', 'hash') ext = X509.new_extension('subjectAltName', 'DNS:foobar.example.com') self.assertEqual(ext.get_value(), 'DNS:foobar.example.com') self.assertEqual(ext.get_value(indent=2), ' DNS:foobar.example.com') self.assertEqual(ext.get_value(flag=m2.X509V3_EXT_PARSE_UNKNOWN), 'DNS:foobar.example.com') def test_ext_error(self): with self.assertRaises(X509.X509Error): X509.new_extension('nonsensicalName', 'blabla') def test_extstack(self): # new ext1 = X509.new_extension('subjectAltName', 'DNS:foobar.example.com') ext2 = X509.new_extension('nsComment', 'Hello there') extstack = X509.X509_Extension_Stack() # push extstack.push(ext1) extstack.push(ext2) self.assertEqual(extstack[1].get_name(), 'nsComment') self.assertEqual(len(extstack), 2) # iterator i = 0 for e in extstack: i += 1 self.assertGreater(len(e.get_name()), 0) self.assertEqual(i, 2) # pop ext3 = extstack.pop() self.assertEqual(len(extstack), 1) self.assertEqual(extstack[0].get_name(), 'subjectAltName') extstack.push(ext3) self.assertEqual(len(extstack), 2) self.assertEqual(extstack[1].get_name(), 'nsComment') self.assertIsNotNone(extstack.pop()) self.assertIsNotNone(extstack.pop()) self.assertIsNone(extstack.pop()) def test_x509_name(self): n = X509.X509_Name() # It seems this actually needs to be a real 2 letter country code n.C = 'US' self.assertEqual(n.C, 'US') n.SP = 'State or Province' self.assertEqual(n.SP, 'State or Province') n.L = 'locality name' self.assertEqual(n.L, 'locality name') # Yes, 'orhanization' is a typo, I know it and you're smart. # However, fixing this typo would break later hashes. # I don't think it is worthy of troubles. n.O = 'orhanization name' self.assertEqual(n.O, 'orhanization name') n.OU = 'org unit' self.assertEqual(n.OU, 'org unit') n.CN = 'common name' self.assertEqual(n.CN, 'common name') n.Email = 'bob@example.com' self.assertEqual(n.Email, 'bob@example.com') n.serialNumber = '1234' self.assertEqual(n.serialNumber, '1234') n.SN = 'surname' self.assertEqual(n.SN, 'surname') n.GN = 'given name' self.assertEqual(n.GN, 'given name') self.assertEqual(n.as_text(), 'C=US, ST=State or Province, ' + 'L=locality name, O=orhanization name, ' + 'OU=org unit, CN=common ' + 'name/emailAddress=bob@example.com' + '/serialNumber=1234, ' + 'SN=surname, GN=given name') self.assertEqual(len(n), 10, 'X509_Name has inappropriate length %d ' % len(n)) n.givenName = 'name given' self.assertEqual(n.GN, 'given name') # Just gets the first self.assertEqual(n.as_text(), 'C=US, ST=State or Province, ' + 'L=locality name, O=orhanization name, ' + 'OU=org unit, ' + 'CN=common name/emailAddress=bob@example.com' + '/serialNumber=1234, ' + 'SN=surname, GN=given name, GN=name given') self.assertEqual(len(n), 11, 'After adding one more attribute X509_Name should ' + 'have 11 and not %d attributes.' % len(n)) n.add_entry_by_txt(field="CN", type=ASN1.MBSTRING_ASC, entry="Proxy", len=-1, loc=-1, set=0) self.assertEqual(len(n), 12, 'After adding one more attribute X509_Name should ' + 'have 12 and not %d attributes.' % len(n)) self.assertEqual(n.entry_count(), 12, n.entry_count()) self.assertEqual(n.as_text(), 'C=US, ST=State or Province, ' + 'L=locality name, O=orhanization name, ' + 'OU=org unit, ' + 'CN=common name/emailAddress=bob@example.com' + '/serialNumber=1234, ' + 'SN=surname, GN=given name, GN=name given, ' + 'CN=Proxy') with self.assertRaises(AttributeError): n.__getattr__('foobar') n.foobar = 1 self.assertEqual(n.foobar, 1) # X509_Name_Entry tests l = 0 for entry in n: self.assertIsInstance(entry, X509.X509_Name_Entry) self.assertIsInstance(entry.get_object(), ASN1.ASN1_Object) self.assertIsInstance(entry.get_data(), ASN1.ASN1_String) l += 1 self.assertEqual(l, 12, l) l = 0 for cn in n.get_entries_by_nid(m2.NID_commonName): self.assertIsInstance(cn, X509.X509_Name_Entry) self.assertIsInstance(cn.get_object(), ASN1.ASN1_Object) data = cn.get_data() self.assertIsInstance(data, ASN1.ASN1_String) t = data.as_text() self.assertIn(t, ("common name", "Proxy",)) l += 1 self.assertEqual(l, 2, 'X509_Name has %d commonName entries instead ' 'of expected 2' % l) # The target list is not deleted when the loop is finished # https://docs.python.org/2.7/reference\ # /compound_stmts.html#the-for-statement # so this checks what are the attributes of the last value of # ``cn`` variable. cn.set_data(b"Hello There!") self.assertEqual(cn.get_data().as_text(), "Hello There!") # OpenSSL 1.0.1h switched from encoding strings as PRINTABLESTRING (the # first hash value) to UTF8STRING (the second one) self.assertIn(n.as_hash(), (1697185131, 1370641112), 'Unexpected value of the X509_Name hash %s' % n.as_hash()) self.assertRaises(IndexError, lambda: n[100]) self.assertIsNotNone(n[10]) def test_mkreq(self): (req, _) = self.mkreq(1024) req.save_pem('tests/tmp_request.pem') req2 = X509.load_request('tests/tmp_request.pem') os.remove('tests/tmp_request.pem') req.save('tests/tmp_request.pem') req3 = X509.load_request('tests/tmp_request.pem') os.remove('tests/tmp_request.pem') req.save('tests/tmp_request.der', format=X509.FORMAT_DER) req4 = X509.load_request('tests/tmp_request.der', format=X509.FORMAT_DER) os.remove('tests/tmp_request.der') if m2.OPENSSL_VERSION_NUMBER >= 0x30000000: req2t = req2.as_text().replace(' Public-Key: (1024 bit)', ' RSA Public-Key: (1024 bit)') req3t = req3.as_text().replace(' Public-Key: (1024 bit)', ' RSA Public-Key: (1024 bit)') req4t = req3.as_text().replace(' Public-Key: (1024 bit)', ' RSA Public-Key: (1024 bit)') else: req2t = req2.as_text() req3t = req3.as_text() req4t = req3.as_text() self.assertEqual(req.as_pem(), req2.as_pem()) self.assertEqual(req.as_text(), req2t) self.assertEqual(req.as_der(), req2.as_der()) self.assertEqual(req.as_pem(), req3.as_pem()) self.assertEqual(req.as_text(), req3t) self.assertEqual(req.as_der(), req3.as_der()) self.assertEqual(req.as_pem(), req4.as_pem()) self.assertEqual(req.as_text(), req4t) self.assertEqual(req.as_der(), req4.as_der()) self.assertEqual(req.get_version(), 0) req.set_version(1) self.assertEqual(req.get_version(), 1) req.set_version(0) self.assertEqual(req.get_version(), 0) @unittest.skipIf(platform.system() == 'Windows', 'Skip on Windows. TODO') def test_mkcert(self): for utc in (True, False): req, pk = self.mkreq(1024) pkey = req.get_pubkey() self.assertTrue(req.verify(pkey)) sub = req.get_subject() self.assertEqual(len(sub), 2, 'Subject should be long 2 items not %d' % len(sub)) cert = X509.X509() cert.set_serial_number(1) cert.set_version(2) cert.set_subject(sub) t = int(time.time()) + time.timezone log.debug('t = %s', time.strftime("%a, %d %b %Y %H:%M:%S %z", time.localtime(t))) if utc: now = ASN1.ASN1_UTCTIME() else: now = ASN1.ASN1_TIME() now.set_time(t) log.debug('now = %s', now) now_plus_year = ASN1.ASN1_TIME() now_plus_year.set_time(t + 60 * 60 * 24 * 365) log.debug('now_plus_year = %s', now_plus_year) cert.set_not_before(now) cert.set_not_after(now_plus_year) log.debug('cert = %s', cert.get_not_before()) self.assertEqual(str(cert.get_not_before()), str(now)) self.assertEqual(str(cert.get_not_after()), str(now_plus_year)) issuer = X509.X509_Name() issuer.CN = 'The Issuer Monkey' issuer.O = 'The Organization Otherwise Known as My CA, Inc.' cert.set_issuer(issuer) cert.set_pubkey(pkey) cert.set_pubkey(cert.get_pubkey()) # Make sure get/set work ext = X509.new_extension('subjectAltName', 'DNS:foobar.example.com') ext.set_critical(0) self.assertEqual(ext.get_critical(), 0) cert.add_ext(ext) cert.sign(pk, 'sha1') with self.assertRaises(ValueError): cert.sign(pk, 'nosuchalgo') self.assertTrue(cert.get_ext('subjectAltName').get_name(), 'subjectAltName') self.assertTrue(cert.get_ext_at(0).get_name(), 'subjectAltName') self.assertTrue(cert.get_ext_at(0).get_value(), 'DNS:foobar.example.com') self.assertEqual(cert.get_ext_count(), 1, 'Certificate should have now 1 extension not %d' % cert.get_ext_count()) with self.assertRaises(IndexError): cert.get_ext_at(1) self.assertTrue(cert.verify()) self.assertTrue(cert.verify(pkey)) self.assertTrue(cert.verify(cert.get_pubkey())) self.assertEqual(cert.get_version(), 2) self.assertEqual(cert.get_serial_number(), 1) self.assertEqual(cert.get_issuer().CN, 'The Issuer Monkey') if m2.OPENSSL_VERSION_NUMBER >= 0x90800f: self.assertFalse(cert.check_ca()) self.assertFalse(cert.check_purpose(m2.X509_PURPOSE_SSL_SERVER, 1)) self.assertFalse(cert.check_purpose(m2.X509_PURPOSE_NS_SSL_SERVER, 1)) self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_SSL_SERVER, 0)) self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_NS_SSL_SERVER, 0)) self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_ANY, 0)) else: with self.assertRaises(AttributeError): cert.check_ca() def mkcacert(self, utc): req, pk = self.mkreq(1024, ca=1) pkey = req.get_pubkey() sub = req.get_subject() cert = X509.X509() cert.set_serial_number(1) cert.set_version(2) cert.set_subject(sub) t = int(time.time()) + time.timezone if utc: now = ASN1.ASN1_UTCTIME() else: now = ASN1.ASN1_TIME() now.set_time(t) now_plus_year = ASN1.ASN1_TIME() now_plus_year.set_time(t + 60 * 60 * 24 * 365) cert.set_not_before(now) cert.set_not_after(now_plus_year) issuer = X509.X509_Name() issuer.C = "UK" issuer.CN = "OpenSSL Group" cert.set_issuer(issuer) cert.set_pubkey(pkey) ext = X509.new_extension('basicConstraints', 'CA:TRUE') cert.add_ext(ext) cert.sign(pk, 'sha1') if m2.OPENSSL_VERSION_NUMBER >= 0x0090800f: self.assertTrue(cert.check_ca()) self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_SSL_SERVER, 1)) self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_NS_SSL_SERVER, 1)) self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_ANY, 1)) self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_SSL_SERVER, 0)) self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_NS_SSL_SERVER, 0)) self.assertTrue(cert.check_purpose(m2.X509_PURPOSE_ANY, 0)) else: with self.assertRaises(AttributeError): cert.check_ca() return cert, pk, pkey def test_mkcacert(self): for utc in (True, False): cacert, _, pkey = self.mkcacert(utc) self.assertTrue(cacert.verify(pkey)) def test_mkproxycert(self): for utc in (True, False): cacert, pk1, _ = self.mkcacert(utc) end_entity_cert_req, pk2 = self.mkreq(1024) end_entity_cert = self.make_eecert(cacert, utc) end_entity_cert.set_subject(end_entity_cert_req.get_subject()) end_entity_cert.set_pubkey(end_entity_cert_req.get_pubkey()) end_entity_cert.sign(pk1, 'sha1') proxycert = self.make_proxycert(end_entity_cert, utc) proxycert.sign(pk2, 'sha1') self.assertTrue(proxycert.verify(pk2)) self.assertEqual(proxycert.get_ext_at(0).get_name(), 'proxyCertInfo') self.assertEqual(proxycert.get_ext_at(0).get_value().strip(), 'Path Length Constraint: infinite\n' + 'Policy Language: Inherit all') self.assertEqual(proxycert.get_ext_count(), 1, proxycert.get_ext_count()) self.assertEqual(proxycert.get_subject().as_text(), 'C=UK, CN=OpenSSL Group, CN=Proxy') self.assertEqual( proxycert.get_subject().as_text(indent=2, flags=m2.XN_FLAG_RFC2253), ' CN=Proxy,CN=OpenSSL Group,C=UK') @staticmethod def make_eecert(cacert, utc): eecert = X509.X509() eecert.set_serial_number(2) eecert.set_version(2) t = int(time.time()) + time.timezone if utc: now = ASN1.ASN1_UTCTIME() else: now = ASN1.ASN1_TIME() now.set_time(t) now_plus_year = ASN1.ASN1_TIME() now_plus_year.set_time(t + 60 * 60 * 24 * 365) eecert.set_not_before(now) eecert.set_not_after(now_plus_year) eecert.set_issuer(cacert.get_subject()) return eecert def make_proxycert(self, eecert, utc): proxycert = X509.X509() pk2 = EVP.PKey() proxykey = RSA.gen_key(1024, 65537, self.callback) pk2.assign_rsa(proxykey) proxycert.set_pubkey(pk2) proxycert.set_version(2) if utc: not_before = ASN1.ASN1_UTCTIME() not_after = ASN1.ASN1_UTCTIME() else: not_before = ASN1.ASN1_TIME() not_after = ASN1.ASN1_TIME() not_before.set_time(int(time.time())) offset = 12 * 3600 not_after.set_time(int(time.time()) + offset) proxycert.set_not_before(not_before) proxycert.set_not_after(not_after) proxycert.set_issuer_name(eecert.get_subject()) proxycert.set_serial_number(12345678) issuer_name_string = eecert.get_subject().as_text() seq = issuer_name_string.split(",") subject_name = X509.X509_Name() for entry in seq: l = entry.split("=") subject_name.add_entry_by_txt(field=l[0].strip(), type=ASN1.MBSTRING_ASC, entry=l[1], len=-1, loc=-1, set=0) subject_name.add_entry_by_txt(field="CN", type=ASN1.MBSTRING_ASC, entry="Proxy", len=-1, loc=-1, set=0) proxycert.set_subject_name(subject_name) # XXX leaks 8 bytes pci_ext = X509.new_extension("proxyCertInfo", "critical,language:Inherit all", 1) proxycert.add_ext(pci_ext) return proxycert def test_fingerprint(self): x509 = X509.load_cert('tests/x509.pem') fp = x509.get_fingerprint('sha1') self.assertEqual(fp, self.expected_hash) def test_load_der_string(self): with open('tests/x509.der', 'rb') as f: x509 = X509.load_cert_der_string(f.read()) fp = x509.get_fingerprint('sha1') self.assertEqual(fp, self.expected_hash) def test_save_der_string(self): x509 = X509.load_cert('tests/x509.pem') s = x509.as_der() with open('tests/x509.der', 'rb') as f: s2 = f.read() self.assertEqual(s, s2) def test_load(self): x509 = X509.load_cert('tests/x509.pem') x5092 = X509.load_cert('tests/x509.der', format=X509.FORMAT_DER) self.assertEqual(x509.as_text(), x5092.as_text()) self.assertEqual(x509.as_pem(), x5092.as_pem()) self.assertEqual(x509.as_der(), x5092.as_der()) return def test_load_bio(self): with BIO.openfile('tests/x509.pem') as bio: with BIO.openfile('tests/x509.der') as bio2: x509 = X509.load_cert_bio(bio) x5092 = X509.load_cert_bio(bio2, format=X509.FORMAT_DER) with self.assertRaises(ValueError): X509.load_cert_bio(bio2, format=45678) self.assertEqual(x509.as_text(), x5092.as_text()) self.assertEqual(x509.as_pem(), x5092.as_pem()) self.assertEqual(x509.as_der(), x5092.as_der()) def test_load_string(self): with open('tests/x509.pem') as f: s = f.read() with open('tests/x509.der', 'rb') as f2: s2 = f2.read() x509 = X509.load_cert_string(s) x5092 = X509.load_cert_string(s2, X509.FORMAT_DER) self.assertEqual(x509.as_text(), x5092.as_text()) self.assertEqual(x509.as_pem(), x5092.as_pem()) self.assertEqual(x509.as_der(), x5092.as_der()) def test_load_request_bio(self): (req, _) = self.mkreq(1024) r1 = X509.load_request_der_string(req.as_der()) r2 = X509.load_request_string(req.as_der(), X509.FORMAT_DER) r3 = X509.load_request_string(req.as_pem(), X509.FORMAT_PEM) r4 = X509.load_request_bio(BIO.MemoryBuffer(req.as_der()), X509.FORMAT_DER) r5 = X509.load_request_bio(BIO.MemoryBuffer(req.as_pem()), X509.FORMAT_PEM) for r in [r1, r2, r3, r4, r5]: self.assertEqual(req.as_der(), r.as_der()) with self.assertRaises(ValueError): X509.load_request_bio(BIO.MemoryBuffer(req.as_pem()), 345678) def test_save(self): x509 = X509.load_cert('tests/x509.pem') with open('tests/x509.pem', 'r') as f: l_tmp = f.readlines() # -----BEGIN CERTIFICATE----- : -----END CERTIFICATE----- beg_idx = l_tmp.index('-----BEGIN CERTIFICATE-----\n') end_idx = l_tmp.index('-----END CERTIFICATE-----\n') x509_pem = ''.join(l_tmp[beg_idx:end_idx + 1]) with open('tests/x509.der', 'rb') as f: x509_der = f.read() x509.save('tests/tmpcert.pem') with open('tests/tmpcert.pem') as f: s = f.read() self.assertEqual(s, x509_pem) os.remove('tests/tmpcert.pem') x509.save('tests/tmpcert.der', format=X509.FORMAT_DER) with open('tests/tmpcert.der', 'rb') as f: s = f.read() self.assertEqual(s, x509_der) os.remove('tests/tmpcert.der') def test_malformed_data(self): try: with self.assertRaises(X509.X509Error): X509.load_cert_string('Hello') with self.assertRaises(X509.X509Error): X509.load_cert_der_string('Hello') with self.assertRaises(X509.X509Error): X509.new_stack_from_der(b'Hello') with self.assertRaises(X509.X509Error): X509.load_cert('tests/alltests.py') with self.assertRaises(X509.X509Error): X509.load_request('tests/alltests.py') with self.assertRaises(X509.X509Error): X509.load_request_string('Hello') with self.assertRaises(X509.X509Error): X509.load_request_der_string('Hello') with self.assertRaises(X509.X509Error): X509.load_crl('tests/alltests.py') except SystemError: pass def test_long_serial(self): cert = X509.load_cert('tests/long_serial_cert.pem') self.assertEqual(cert.get_serial_number(), 17616841808974579194) cert = X509.load_cert('tests/thawte.pem') self.assertEqual(cert.get_serial_number(), 127614157056681299805556476275995414779) def test_set_long_serial(self): cert = X509.X509() cert.set_serial_number(127614157056681299805556476275995414779) self.assertEqual(cert.get_serial_number(), 127614157056681299805556476275995414779) @unittest.skipIf(platform.system() == 'Windows', 'Skip on Windows. TODO') @expectedFailureIf(is_32bit() and not is_libc_musl()) def test_date_after_2050_working(self): cert = X509.load_cert('tests/bad_date_cert.crt') self.assertEqual(str(cert.get_not_after()), 'Feb 9 14:57:46 2116 GMT') @unittest.skipIf(platform.system() == 'Windows', 'Skip on Windows. TODO') @expectedFailureIf(is_32bit() and not is_libc_musl()) def test_date_reference_counting(self): """x509_get_not_before() and x509_get_not_after() return internal pointers into X509. As the returned ASN1_TIME objects do not store any reference to the X509 itself, they become invalid when the last reference to X509 goes out of scope and the underlying memory is freed. https://todo.sr.ht/~mcepl/m2crypto/325 """ cert = X509.load_cert('tests/bad_date_cert.crt') not_before = cert.get_not_before() not_after = cert.get_not_after() del cert self.assertEqual(str(not_before), 'Mar 4 14:57:46 2016 GMT') self.assertEqual(str(not_after), 'Feb 9 14:57:46 2116 GMT') def test_easy_rsa_generated(self): """ Test loading a cert generated by easy RSA. https://github.com/fedora-infra/fedmsg/pull/389 """ # Does this raise an exception? X509.load_cert('tests/easy_rsa.pem') class X509StackTestCase(unittest.TestCase): def setUp(self): if m2.OPENSSL_VERSION_NUMBER >= 0x30000000: self.expected_subject = '/DC=org/DC=doegrids/OU=Services/CN=host\\/bosshog.lbl.gov' else: self.expected_subject = '/DC=org/DC=doegrids/OU=Services/CN=host/bosshog.lbl.gov' def test_make_stack_from_der(self): with open("tests/der_encoded_seq.b64", 'rb') as f: b64 = f.read() with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) seq = base64.decodebytes(b64) stack = X509.new_stack_from_der(seq) cert = stack.pop() self.assertIsNone(stack.pop()) cert.foobar = 1 self.assertEqual(cert.foobar, 1) subject = cert.get_subject() self.assertEqual( str(subject), self.expected_subject) def test_make_stack_check_num(self): with open("tests/der_encoded_seq.b64", 'rb') as f: b64 = f.read() with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) seq = base64.decodebytes(b64) stack = X509.new_stack_from_der(seq) num = len(stack) self.assertEqual(num, 1) cert = stack.pop() num = len(stack) self.assertEqual(num, 0) subject = cert.get_subject() self.assertEqual( str(subject), self.expected_subject) def test_make_stack(self): stack = X509.X509_Stack() cert = X509.load_cert("tests/x509.pem") issuer = X509.load_cert("tests/ca.pem") cert_subject1 = cert.get_subject() issuer_subject1 = issuer.get_subject() stack.push(cert) stack.push(issuer) # Test stack iterator i = 0 for c in stack: i += 1 self.assertGreater(len(c.get_subject().CN), 0) self.assertEqual(i, 2) stack.pop() cert_pop = stack.pop() cert_subject2 = cert_pop.get_subject() issuer_subject2 = issuer.get_subject() self.assertEqual(str(cert_subject1), str(cert_subject2)) self.assertEqual(str(issuer_subject1), str(issuer_subject2)) def test_as_der(self): stack = X509.X509_Stack() cert = X509.load_cert("tests/x509.pem") issuer = X509.load_cert("tests/ca.pem") cert_subject1 = cert.get_subject() issuer_subject1 = issuer.get_subject() stack.push(cert) stack.push(issuer) der_seq = stack.as_der() stack2 = X509.new_stack_from_der(der_seq) stack2.pop() cert_pop = stack2.pop() cert_subject2 = cert_pop.get_subject() issuer_subject2 = issuer.get_subject() self.assertEqual(str(cert_subject1), str(cert_subject2)) self.assertEqual(str(issuer_subject1), str(issuer_subject2)) class X509ExtTestCase(unittest.TestCase): def test_ext(self): if 0: # XXX # With this leaks 8 bytes: name = "proxyCertInfo" value = "critical,language:Inherit all" else: # With this there are no leaks: name = "nsComment" value = "Hello" ctx = m2.x509v3_set_nconf() x509_ext_ptr = m2.x509v3_ext_conf(None, ctx, name, value) X509.X509_Extension(x509_ext_ptr, 1) class CRLTestCase(unittest.TestCase): def test_new(self): crl = X509.CRL() self.assertEqual(crl.as_text()[:34], 'Certificate Revocation List (CRL):') def suite(): st = unittest.TestSuite() st.addTest(unittest.TestLoader().loadTestsFromTestCase(X509TestCase)) st.addTest(unittest.TestLoader().loadTestsFromTestCase(X509StackTestCase)) st.addTest(unittest.TestLoader().loadTestsFromTestCase(X509ExtTestCase)) st.addTest(unittest.TestLoader().loadTestsFromTestCase(CRLTestCase)) return st if __name__ == '__main__': Rand.load_file('randpool.dat', -1) unittest.TextTestRunner().run(suite()) Rand.save_file('randpool.dat') m2crypto-0.42.0/tests/thawte.pem000066400000000000000000000027721465575656700165570ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA 2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu MdRAGmI0Nj81Aa6sY6A= -----END CERTIFICATE----- m2crypto-0.42.0/tests/x509.der000066400000000000000000000014761465575656700157610ustar00rootroot000000000000000:0"0  *H  0O1 0 UUS10U California10U M2Crypto10U Heikki Toivonen0 181007151202Z 281004151202Z0D1 0 UUS10U California10U M2Crypto1 0 U X5090"0  *H 0  d*!Һ9,+X].4z`Z*C^wLoJA)Z CHfTFVGk cDŽyV'r_zsЏ Qy 9*e}ӓ%Ξg{9J.]0Q4Kv8SnٛA[L8Ӯ$O%$1攗KHK[̕Mf\>$OCިq-i5AϞOz-aTt&"+ ,0*0 U00U)4Zv<,jЯ0  *H  5%1m8Y&OM|jMYU>!S=#Dq=C>Ebdhq&_f*Jb#D"8 `E)mDң/c?^~4