pax_global_header00006660000000000000000000000064150674674230014530gustar00rootroot0000000000000052 comment=4c0a0c403d51dd637d98343b5df2cb295b225026 m2crypto-0.46.2/000077500000000000000000000000001506746742300134005ustar00rootroot00000000000000m2crypto-0.46.2/.builds/000077500000000000000000000000001506746742300147405ustar00rootroot00000000000000m2crypto-0.46.2/.builds/fedora.yml000066400000000000000000000040461506746742300167270ustar00rootroot00000000000000image: fedora/rawhide oauth: git.sr.ht/REPOSITORIES:RW git.sr.ht/PROFILE:RO packages: - hut - swig - python3 - python3-devel - python3-pip - openssl-devel - openssl-devel-engine - openssl - python3-setuptools - python3-twisted - python3-irc - python3-docutils - python3-mypy 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 -mpip wheel --verbose --no-cache-dir --no-clean --no-build-isolation --wheel-dir dist/ --editable . find . -name \*.c find . -name \*.whl -o -name \*.tar.gz mkdir -p shadowing/sys && touch shadowing/sys/types.h python3 -mpip install -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/[mM]2[cC]rypto*.whl - mypy: | cd m2crypto PYTHONPATH=$(readlink -f build/lib.*) python3 -mmypy --no-color-output -p M2Crypto - 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)" echo "Sourcehut build $BUILD_REASON finished with the result $? ($JOB_URL)." \ | .builds/irc-send irc.ergo.chat commit-bot mcepl "#m2crypto" - readme: | cd m2crypto printf "GIT_REF: %s\n" "${GIT_REF}" python3 -mdocutils --strict README.rst >/dev/null case $GIT_REF in *master*) python3 -mdocutils README.rst \ | sed -n '1,//d;/<\/body>/q;p' \ |hut git -r m2crypto update --readme - ;; esac artifacts: - m2crypto/src/SWIG/_m2crypto_wrap.c # https://is.gd/Z5VJlI # - pygn/dist/pygn-*.tar.gz # - pygn/dist/pygn-*.whl m2crypto-0.46.2/.builds/irc-send000077500000000000000000000110221506746742300163660ustar00rootroot00000000000000#! /usr/bin/env python3 # # IRC Cat script using irc.client.SimpleIRCClient with SASL and SSL/TLS. # # IMPORTANT: sasl_login must equal your nickserv account name # # Adapted to read configuration from CLI and password from ~/.irc_pass. import logging import functools import ssl import sys import os import argparse import irc.client import irc.connection import functools import ssl import sys import os import argparse import irc.client import irc.connection class IRCCat(irc.client.SimpleIRCClient): # Simplified __init__ for demonstration def __init__(self, target): irc.client.SimpleIRCClient.__init__(self) self.target = target def on_welcome(self, connection, event): # The library handles SASL negotiation automatically before this event, # but joining is often safe here if SASL fails/isn't supported. # Note: For strict SASL-only connection, you might wait for a 'logged_in' event if available. if irc.client.is_channel(self.target): connection.join(self.target) else: self.send_it() def on_login_failed(self, connection, event): # A specific event handler for login failure (e.g., SASL failed) logging.error(f"Login failed: {event.arguments[0]}") # Note: Depending on the server, you might get a standard DISCONNECT event instead. def on_join(self, connection, event): self.send_it() def on_disconnect(self, connection, event): logging.debug(f"Disconnected: {event.arguments[0]}") sys.exit(0) def send_it(self): # Reads from stdin and sends as PRIVMSG while 1: try: line = sys.stdin.readline().strip() except EOFError: break if not line: break self.connection.privmsg(self.target, line) quit_message = "Using irc.client.py (SASL-SSL)" self.connection.quit(quit_message) # Stop the reactor immediately after sending QUIT. # This prevents the client from waiting for and reacting to the # server's final QUIT/ERROR sequence, which causes the peer reset message. self.connection.reactor.disconnect_all() def read_password_from_file(): """Reads and strips the password from the ~/.irc_pass file.""" password_file_path = os.path.expanduser("~/.irc_pass") try: with open(password_file_path, "r") as f: # Read and strip leading/trailing whitespace, including EOL password = f.read().strip() if not password: raise ValueError("Password file is empty.") return password except FileNotFoundError: logging.error( f"Error: Password file not found at {password_file_path}" ) sys.exit(1) except Exception as e: logging.error(f"Error reading password file: {e}") sys.exit(1) def get_args(): parser = argparse.ArgumentParser( description="IRC Cat client with SASL and SSL/TLS." ) parser.add_argument("server", help="IRC server hostname (e.g., irc.ergo.chat)") parser.add_argument("nickname", help="IRC nickname to use") parser.add_argument( "account", help="SASL account name (usually your NickServ name)" ) parser.add_argument("target", help="A nickname or channel (e.g., #mychannel)") parser.add_argument( "-p", "--port", default=6697, type=int, help="Port number (default 6697 for TLS)", ) return parser.parse_args() def main(): logging.basicConfig( format="%(levelname)s:%(funcName)s:%(message)s", level=logging.INFO ) args = get_args() password = read_password_from_file() context = ssl.create_default_context() context.load_default_certs(ssl.Purpose.SERVER_AUTH) # Ensure system CAs are loaded wrapper = functools.partial(context.wrap_socket, server_hostname=args.server) c = IRCCat(args.target) try: c.connect( args.server, args.port, args.nickname, password, # <-- IRC PASS (Used for SASL PLAIN) sasl_login=args.account, # <-- SASL Account Name username=args.account, # Use account name as ident user connect_factory=irc.connection.Factory(wrapper=wrapper), ) logging.debug("Connection initiated successfully.") except irc.client.ServerConnectionError as x: logging.error(f"Connection Error: {x}") sys.exit(1) c.start() if __name__ == "__main__": main() m2crypto-0.46.2/.editorconfig000066400000000000000000000003311506746742300160520ustar00rootroot00000000000000root = true [*.{py,pyi,c,cpp,h,rst,md,yml,yaml,json,test}] trim_trailing_whitespace = true insert_final_newline = true indent_style = space [*.{py,pyi,c,h,json,test}] indent_size = 4 [*.{yml,yaml}] indent_size = 2 m2crypto-0.46.2/.git-blame-ignore-revs000066400000000000000000000001731506746742300175010ustar00rootroot00000000000000# Blackening of the whole tree 69c02442aedd8239e13678ced5cdcbc6f52f111c # hinting 0f7ba2a62522076fa42c79fb09a6b40aa0c0a047 m2crypto-0.46.2/.gitignore000066400000000000000000000003421506746742300153670ustar00rootroot00000000000000*.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 .env m2crypto-0.46.2/.gitlab-ci-windows.yml000066400000000000000000000054631506746742300175340ustar00rootroot00000000000000# 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)' - 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))' # Install Python dependencies and OpenSSL - echo "Install dev dependencies"; python -m pip install -r dev-requirements.txt build-test-windows: stage: build parallel: matrix: - ARCH: ["32", "64"] PYTHON_VERSION: [ "310", "311", "312", "313" ] 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 --editable . - 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.46.2/.gitlab-ci.yml000066400000000000000000000302371506746742300160410ustar00rootroot00000000000000stages: - 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 - mkdir -p $HOME/.local/bin - ls $HOME/.local/bin - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --break-system-packages --user -r dev-requirements.txt - ls $HOME/.local/bin - python3 -mpip wheel --verbose --no-cache-dir --no-clean --no-build-isolation --wheel-dir dist/ --editable . - python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/[mM]2[cC]rypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite - echo "$PYTHONPATH" ; python3 -c 'import sys; print(sys.path)' 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 python3-irc - mkdir -p $HOME/.local/bin - ls $HOME/.local/bin - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --break-system-packages --user -r dev-requirements.txt - ls $HOME/.local/bin - python3 -mpip wheel --verbose --no-cache-dir --no-clean --no-build-isolation --wheel-dir dist/ --editable . - python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/[mM]2[cC]rypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite - echo "$PYTHONPATH" ; python3 -c 'import sys; print(sys.path)' 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 - mkdir -p $HOME/.local/bin - ls $HOME/.local/bin - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --break-system-packages --user -r dev-requirements.txt - ls $HOME/.local/bin - python3 -mpip wheel --verbose --no-cache-dir --no-clean --no-build-isolation --wheel-dir dist/ --editable . - python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/[mM]2[cC]rypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite - echo "$PYTHONPATH" ; python3 -c 'import sys; print(sys.path)' - echo "$IRC_PASS" > ~/.irc_pass && chmod 600 ~/.irc_pass - echo "GitLab build task $CI_JOB_NAME for $REASON finished with the result $? ($CI_JOB_URL)." | .builds/irc-send irc.ergo.chat commit-bot mcepl "#m2crypto" 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 - mkdir -p $HOME/.local/bin - ls $HOME/.local/bin - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --break-system-packages --user -r dev-requirements.txt - ls $HOME/.local/bin - python3 -mpip wheel --verbose --no-cache-dir --no-clean --no-build-isolation --wheel-dir dist/ --editable . - python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/[mM]2[cC]rypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite - echo "$PYTHONPATH" ; python3 -c 'import sys; print(sys.path)' - echo "$IRC_PASS" > ~/.irc_pass && chmod 600 ~/.irc_pass - echo "GitLab build task $CI_JOB_NAME for $REASON finished with the result $? ($CI_JOB_URL)." | .builds/irc-send irc.ergo.chat commit-bot mcepl "#m2crypto" 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 python3-irc - mkdir -p $HOME/.local/bin - ls $HOME/.local/bin - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --break-system-packages --user -r dev-requirements.txt - python3 -mpip install --break-system-packages --user -r doc/requirements.txt - ls $HOME/.local/bin - python3 -mpip wheel --verbose --no-cache-dir --no-clean --no-build-isolation --wheel-dir dist/ --editable . - python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/[mM]2[cC]rypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) make -C doc/ doctest - echo "$PYTHONPATH" ; python3 -c 'import sys; print(sys.path)' - echo "$IRC_PASS" > ~/.irc_pass && chmod 600 ~/.irc_pass - echo "GitLab build task $CI_JOB_NAME for $REASON finished with the result $? ($CI_JOB_URL)." | .builds/irc-send irc.ergo.chat commit-bot mcepl "#m2crypto" fedora: image: quay.io/fedora/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 openssl-devel-engine python3-irc - mkdir -p $HOME/.local/bin - ls $HOME/.local/bin - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --user -r dev-requirements.txt - ls $HOME/.local/bin - python3 -mpip wheel --verbose --no-cache-dir --no-clean --no-build-isolation --wheel-dir dist/ --editable . - python3 -mpip install -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/[mM]2[cC]rypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite - echo "$PYTHONPATH" ; python3 -c 'import sys; print(sys.path)' - echo "$IRC_PASS" > ~/.irc_pass && chmod 600 ~/.irc_pass - echo "GitLab build task $CI_JOB_NAME for $REASON finished with the result $? ($CI_JOB_URL)." | .builds/irc-send irc.ergo.chat commit-bot mcepl "#m2crypto" fedora-rawhide: image: quay.io/fedora/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 - mkdir -p $HOME/.local/bin - ls $HOME/.local/bin - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --break-system-packages --user -r dev-requirements.txt - ls $HOME/.local/bin - python3 -mpip wheel --verbose --no-cache-dir --no-clean --no-build-isolation --wheel-dir dist/ --editable . - python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/[mM]2[cC]rypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite - echo "$PYTHONPATH" ; python3 -c 'import sys; print(sys.path)' - echo "$IRC_PASS" > ~/.irc_pass && chmod 600 ~/.irc_pass - echo "GitLab build task $CI_JOB_NAME for $REASON finished with the result $? ($CI_JOB_URL)." | .builds/irc-send irc.ergo.chat commit-bot mcepl "#m2crypto" allow_failure: true leap: # image: registry.suse.com/bci/bci-base:latest image: opensuse/leap when: always stage: build artifacts: paths: - "src/SWIG/*.c" 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 - mkdir -p $HOME/.local/bin - ls $HOME/.local/bin - export PATH=$PATH:$HOME/.local/bin - python3 -mpip --disable-pip-version-check install --user --upgrade-strategy only-if-needed -r dev-requirements.txt - ls $HOME/.local/bin - python3 -mpip --disable-pip-version-check wheel --verbose --no-cache-dir --no-clean --no-build-isolation --wheel-dir dist/ --editable . - find . -name \*.c -ls - python3 -mpip --disable-pip-version-check 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 - echo "$PYTHONPATH" ; python3 -c 'import sys; print(sys.path)' 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 python3-irc - mkdir -p $HOME/.local/bin - ls $HOME/.local/bin - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --user --break-system-packages -r dev-requirements.txt - ls $HOME/.local/bin - python3 -mpip wheel --verbose --no-cache-dir --no-clean --no-build-isolation --wheel-dir dist/ --editable . - python3 -mpip install -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/[mM]2[cC]rypto*.whl - PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite - echo "$PYTHONPATH" ; python3 -c 'import sys; print(sys.path)' - echo "$IRC_PASS" > ~/.irc_pass && chmod 600 ~/.irc_pass - echo "GitLab build task $CI_JOB_NAME for $REASON finished with the result $? ($CI_JOB_URL)." | .builds/irc-send irc.ergo.chat commit-bot mcepl "#m2crypto" 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 - mkdir -p $HOME/.local/bin - ls $HOME/.local/bin - export PATH=$PATH:$HOME/.local/bin - python3 -mpip install --break-system-packages --user -r dev-requirements.txt - ls $HOME/.local/bin - python3 -mbuild . --sdist - echo "$PYTHONPATH" ; python3 -c 'import sys; print(sys.path)' - echo "$IRC_PASS" > ~/.irc_pass && chmod 600 ~/.irc_pass - echo "GitLab build task $CI_JOB_NAME for $REASON finished with the result $? ($CI_JOB_URL)." | .builds/irc-send irc.ergo.chat commit-bot mcepl "#m2crypto" 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 manually m2crypto-0.46.2/.keys/000077500000000000000000000000001506746742300144315ustar00rootroot00000000000000m2crypto-0.46.2/.keys/openpgp/000077500000000000000000000000001506746742300161015ustar00rootroot00000000000000m2crypto-0.46.2/.keys/openpgp/cepl.eu/000077500000000000000000000000001506746742300174345ustar00rootroot00000000000000m2crypto-0.46.2/.keys/openpgp/cepl.eu/mcepl/000077500000000000000000000000001506746742300205345ustar00rootroot00000000000000m2crypto-0.46.2/.keys/openpgp/cepl.eu/mcepl/default000066400000000000000000000214241506746742300221060ustar00rootroot00000000000000-----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.46.2/.readthedocs.yaml000066400000000000000000000007171506746742300166340ustar00rootroot00000000000000version: 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.46.2/CHANGES000066400000000000000000001146711506746742300144050ustar00rootroot000000000000000.46.2 - 2025-10-02 ------------------- - fix[m2xmlrpclib]: make the module compatible with Python 3.6 0.46.1 - 2025-10-02 ------------------- - Correct license to BSD-2-Clause and update references - Specify in setup.cfg that we require Python >= 3.6 0.46.0 - 2025-10-01 ------------------- (Tested on Pythons between 3.6 and 3.14.0~rc3) - M2Crypto closes SSL connection on closing HTTPS Connection, and some other related issues (#203, #278) - Modernize C API by eliminating use of deprecated PyBytes_AsStringAndSize and related functions with Python Buffer Protocol (#375) - Whole project is completely covered with type hints and is checked by mypy (also while doing that, the whole project was blackened) (#344) - Add logging support to C extension code sending messages to the Python logging - Introducing first efforts to support Engine object (#229) - Reworked and fixed M2Crypto.m2xmlrpclib module (#163) - Reverted removal of demo/ subdirectory - Improve SMIME documentation (#377) - Some other minor bugs, improvements, and removal of dead code 0.45.1 - 2025-04-23 ------------------- - ci: switch from using sha1 to sha256. - ci(keys): regenerate rsa*.pem keys as well - fix: make the package compatible with OpenSSL >= 3.4 (don’t rely on LEGACY crypto-policies) - chore: package also system_shadowing directory to make builds more reliable 0.45.0 - 2025-04-17 ------------------- - chore: preparing 0.45.0 release - fix(lib,ssl): rewrite ssl_accept, ssl_{read,write}_nbio for better error handling - fix: replace m2_PyBuffer_Release with native PyBuffer_Release - chore: build Windows builds with Python 3.13 as well - fix: remove support for Engine - chore: mark actual license of the project BSD-2-Clause instead of wrong MIT - ci(Debian): make M2Crypto buildable on Debian - swig: Workaround for reading sys/select.h ending with wrong types. - ci: bump required setuptools version because of change in naming strategy - fix: add fix for build with older GCC - fix: remove AnyStr and Any types - chore: add .git-blame-ignore-revs - chore: blacken everything 0.44.0 - 2025-02-17 ------------------- - fix(RSA): introduce internal cache for RSA.check_key() - fix[AuthCookie]: modernize the module - fix(_lib): add missing #include for Windows - ci: the same relaxing of crypto policies for tests on GitLab. - ci: relax Fedora crypto policy to LEGACY. - Enhance setup.py for macOS compatibility - Prefer packaging.version over distutils.version - Fix segfault with OpenSSL 3.4.0 - fix[EC]: raise IOError instead when load_key_bio() cannot read the file. - doc: update installation instructions for Windows. - Fix setting X509.verify_* variables - Fix building against OpenSSL in non-standard location - test_x509: Use only X509_VERSION_1 (0) as version for CSR. - fix: remove support for Engine 0.43.0 - 2024-10-30 ------------------- - feat[m2]: add m2.time_t_bits to checking for 32bitness. - fix[tests]: Use only X509_VERSION_1 (0) as version for CSR. - fix[EC]: raise ValueError when load_key_bio() cannot read the file. - ci: use -mpip wheel instead of -mbuild - fix: use PyMem_Malloc() instead of malloc() - fix[hints]: more work on conversion of type hints to the py3k ones - fix: make the package build even on Python 3.6 - ci[local]: skip freezing local tests - fix[hints]: remove AnyStr type - test: add suggested test for RSA.{get,set}_ex_data - fix: implement interfaces for RSA_{get,set}_ex_new_{data,index} - fix: generate src/SWIG/x509_v_flag.h to overcome weaknesses of swig - fix: replace literal enumeration of all VERIFY_ constants by a cycle - test: unify various test cases in test_ssl related to ftpslib - fix: replace deprecated url keyword in setup.cfg with complete project_urls map 0.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.46.2/CONTRIBUTORS.rst000066400000000000000000000034651506746742300160770ustar00rootroot00000000000000* 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.46.2/INSTALL.rst000066400000000000000000000133611506746742300152440ustar00rootroot00000000000000Installing 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.1.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 -------------------------------------- Binary wheels for many Windows conifgurations are available on PyPI. Try selecting a version, selecting a job that matches your Python version, then going to the "Artifacts" tab and downloading an installer. 1. Install the latest `Build Tools for Visual Studio 2019`. See https://visualstudio.microsoft.com/downloads/ under "All Downloads" -> "Tools for Visual Studio 2019". 2. In the installer, select "C++ Build Tools", install, and reboot if necessary. 3. Install the latest full (not `Light`) `OpenSSL` for your architecture (`Win64`/`Win32`). Current version as of this writing is `1.1.1d`. Make note of the directory to which you install `OpenSSL`. https://slproweb.com/products/Win32OpenSSL.html 4. In `PowerShell`, install the `Chocolatey` package manager. I used this command from their website: `Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))` 5. Install `swig` with `Chocolatey` (in `PowerShell`). `choco install -r -y swig` 6. Install the `pywin32` dependency. Run `pip install pywin32`. If you have problems, try first running `pip install wheel`. To get `pip` to target a specific Python installation, try launching it using `py -[version] -m pip install [module]`. Note: you may need to use an elevated (administrator) `PowerShell` to install Python modules. 7. Get the latest `m2crypto` code. If you have `git` installed, run `git clone https://git.sr.ht/~mcepl/m2crypto`. Otherwise, download and extract the code from SourceHut: https://git.sr.ht/~mcepl/m2crypto/archive/master.tar.gz 8. Use `cd` to change into the directory `m2crypto` was cloned/extracted to. 9. Assuming `python` launches your desired Python interpreter version, run `python setup.py build --openssl="C:\Program Files\OpenSSL-Win64" --bundledlls`, replacing `C:\Program Files\OpenSSL-Win64` with the directory to which you installed `OpenSSL`. (On some systems you can use the `py` launcher to specify a Python version to use, run `py -h` for more information.) 10. Generate the installable files. `python.exe setup.py bdist_wheel bdist_wininst bdist_msi`. 11. Install the module. `cd` into the `dist` directory and run `pip install M2Crypto-0.35.2-cp38-cp38-win_amd64.whl`, replacing the filename with the generated `.whl` file. If you have problems, try first running `pip install wheel`. To get `pip` to target a specific Python installation, try launching it using `py -[version] -m pip install [module]`. Alternatively, you can run the generated `.exe` or `.msi` installer. Note: you may need to use an elevated (administrator) `PowerShell` to install Python modules. (needs updating) .. 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 `setup.py build` you may need to use parameter `-cmingw32`. 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.46.2/LICENSES/000077500000000000000000000000001506746742300146055ustar00rootroot00000000000000m2crypto-0.46.2/LICENSES/BSD-2-Clause.txt000066400000000000000000000026301506746742300173300ustar00rootroot00000000000000(text of the license differs slightly from the standard BSD-2-Clause, but it is the closest fit, and it is functionally equivalent) Copyright (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.46.2/MANIFEST.in000066400000000000000000000014331506746742300151370ustar00rootroot00000000000000# include source code for Swig include src/SWIG/*.i include src/SWIG/*.h include src/SWIG/*.def # include tests, contribute and documentation files recursive-include tests *.py *.pem *.der *.b64 README *.pgp *.dat *.p7* *.crt *.txt recursive-include doc * recursive-include contrib * recursive-include demo * # don't include patatt registry recursive-exclude .keys * # include workaround for reading sys/select.h ending with wrong types recursive-include system_shadowing * # include package documentation files include INSTALL.rst include README.rst include CHANGES # include Swig-generated files include src/SWIG/_m2crypto_wrap.c include src/M2Crypto/m2crypto.py # Include type stubs and the PEP 561 marker in the sdist include src/M2Crypto/py.typed recursive-include src/M2Crypto *.pyi m2crypto-0.46.2/Makefile000066400000000000000000000071571506746742300150520ustar00rootroot00000000000000# Makefile for m2crypto # Use ?= to allow overriding from the command line (e.g., `make PYTHON=python3.11`) PYTHON ?= python3 PIP = $(PYTHON) -mpip # --- Source File Dependencies --- # Find all relevant source files recursively in the src/ directory. # The wheel will be rebuilt only if any of these files are modified. SRC_FILES := $(shell find src -name '*.py' -o -name '*.i' -o -name '*.h') # --- Build Artifacts --- # Directory for the wheel file and the sentinel file. DIST_DIR = dist # A sentinel file to track when the wheel was last built successfully. # This avoids rebuilding if source files haven't changed. WHEEL_SENTINEL = $(DIST_DIR)/.wheel_built # Parse src/M2Crypto/__init__.py to get the current version of the package we work on # Depends on blackening of that file to have all values covered by doublequotes CUR_VERSION = $(shell awk -F'"' '/^__version__/ { print $$2 }' src/M2Crypto/__init__.py) ifeq ($(CUR_VERSION),) $(error Cannot extract version from src/M2Crypto/__init__.py) endif # Find the most recently built wheel file in the dist directory. LATEST_WHEEL := $(firstword $(wildcard dist/[mM]2[Cc]rypto-$(CUR_VERSION)*.whl)) LATEST_TAR := $(firstword $(wildcard dist/[mM]2[Cc]rypto-$(CUR_VERSION)*.tar.gz)) # The directory where the package is installed for testing. BUILD_LIB_DIR = $(shell find build -maxdepth 1 -type d -name "lib.*") # Phony targets are actions, not files. Declaring them prevents conflicts # with files of the same name and improves performance. .PHONY: all wheel install check clean help # The default 'all' target now runs the full build and test cycle. all: check ## Build the wheel (if needed), install it locally, and run tests. # The 'wheel' target is a simple alias for the sentinel file. # Running `make wheel` will trigger the build only if source files have changed. wheel: $(WHEEL_SENTINEL) ## Build the wheel package if source files have changed. # This is the core build rule. It runs if the sentinel file is missing # or if any of the SRC_FILES are newer than it. $(WHEEL_SENTINEL): $(SRC_FILES) rm -rf build @mkdir -p $(DIST_DIR) $(PIP) wheel \ --verbose \ --no-cache-dir \ --no-clean \ --no-build-isolation \ --wheel-dir $(DIST_DIR)/ \ --editable . @touch $@ # 'install' depends on the wheel being created first. install: wheel ## Install the wheel into the local 'build' directory. @if [ -z "$(LATEST_WHEEL)" ]; then \ echo "Error: No wheel file found in dist/. Run 'make wheel' first."; \ exit 1; \ fi @echo "Installing $(LATEST_WHEEL)..." $(PIP) install \ --verbose \ --upgrade \ --target "$(BUILD_LIB_DIR)" \ --no-compile \ --ignore-installed \ --no-deps \ --no-index \ "$(LATEST_WHEEL)" sdist: $(SRC_FILES) $(PYTHON) setup.py sdist $(PYTHON) -mtwine check --strict $(LATEST_TAR) $(PYTHON) -mpyroma --quiet --min=10 $(LATEST_TAR) # 'check' depends on the package being installed locally. check: install ## Run the unit tests. @if [ -z "$(BUILD_LIB_DIR)" ]; then \ echo "Error: Build library directory not found. Run 'make install' first."; \ exit 1; \ fi PYTHONPATH="$(BUILD_LIB_DIR)" $(PYTHON) -m unittest -v tests.alltests.suite # 'clean' is a manual operation to remove all generated files. clean: ## Remove all generated files and build artifacts. rm -rf build src/m2crypto.egg-info $(LATEST_WHEEL) $(LATEST_TAR) $(WHEEL_SENTINEL) rm -f src/SWIG/_m2crypto_wrap.c find . -type d -name "__pycache__" -exec rm -r {} + # A self-documenting 'help' target. help: ## Show this help message. @echo "Available targets:" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}'m2crypto-0.46.2/README.rst000066400000000000000000000054021506746742300150700ustar00rootroot00000000000000======== M2Crypto ======== :Maintainer: Matěj Cepl :Web-Site: https://sr.ht/~mcepl/m2crypto/ :Documentation: https://m2crypto.readthedocs.io/ :IRC channel: irc://irc.ergo.chat/#m2crypto :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 BSD-2-Clause licence. See LICENSES/BSD-2-Clause.txt 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.46.2/contrib/000077500000000000000000000000001506746742300150405ustar00rootroot00000000000000m2crypto-0.46.2/contrib/README000066400000000000000000000002151506746742300157160ustar00rootroot00000000000000This directory contains contributions by users of M2Crypto. Some of these may get folded into the main distribution in time. Thanks guys! m2crypto-0.46.2/contrib/SimpleX509create.README000066400000000000000000000001711506746742300207210ustar00rootroot00000000000000Contributed by Peter Teniz as a demonstration of PKI functionality, also contributed by him. m2crypto-0.46.2/contrib/SimpleX509create.py000066400000000000000000000142611506746742300204210ustar00rootroot00000000000000#!/usr/bin/env python # # vim: ts=4 sw=4 nowrap # """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.46.2/contrib/dave.README000066400000000000000000000053051506746742300166410ustar00rootroot00000000000000From 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.46.2/contrib/isaac.README000066400000000000000000000012271506746742300170010ustar00rootroot00000000000000This 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.46.2/contrib/isaac.httpslib.py000066400000000000000000000207021506746742300203230ustar00rootroot00000000000000"""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.46.2/contrib/smimeplus.README000066400000000000000000000002451506746742300177360ustar00rootroot00000000000000Contributed 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.46.2/contrib/smimeplus.py000066400000000000000000000143541506746742300174370ustar00rootroot00000000000000import 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 = "aes_256_cbc" # XXX make it configable?? self.setsender(cert, privkey, passphrase) self.setcacert(cacert) if randfile is None and os.path.exists("/dev/urandom"): # Default to /dev/urandom on POSIX-like systems if no file is specified self.randfile = "/dev/urandom" else: 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: # On POSIX-like systems, only load a small amount from /dev/urandom # to seed the PRNG, unless it's a dedicated file for state saving. if self.randfile == "/dev/urandom": # Read -1 bytes (all available), M2Crypto Rand.load_file() reads up to 1024 bytes # from /dev/urandom by default if max_bytes is -1 (or similar logic). # To be explicit, we can load a small seed. Rand.load_file(self.randfile, 1024) else: # Load the full user-specified random file Rand.load_file(self.randfile, -1) def __saverand(self): """Save random number file""" if self.randfile and self.randfile != "/dev/urandom": 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 directly from the data into a BIO and then the X509_Store. _ca_bio = self.__pack(self.cacert) _store = X509.X509_Store() # load_info_bio is the typical replacement for file-based loading with a BIO. _store.load_info_bio(_ca_bio) # 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: # Removed flags=SMIME.PKCS7_SIGNED which erroneously sets PKCS7_NOSIGS # https://todo.sr.ht/~mcepl/m2crypto/329 return _sender.verify( _p7, _data, flags=0 # Use flags=0 for standard verification ) 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)) # Use get_components() to get CN and emailAddress _scertsubj_data = _scert.get_subject().get_components() _rcert = X509.load_cert_bio(self.__pack(rcert)) # Use get_components() to get CN and emailAddress directly _rcertsubj_data = _rcert.get_subject().get_components() # The data comes from get_components, which returns bytes, so decode them. _sender_cn = _scertsubj_data.get("CN", b"").decode() _sender_email = _scertsubj_data.get("emailAddress", b"").decode() _recipient_cn = _rcertsubj_data.get("CN", b"").decode() _recipient_email = _rcertsubj_data.get("emailAddress", b"").decode() _out = f'From: "{_sender_cn}" <{_sender_email}>\n' _out += f'To: "{_recipient_cn}" <{_recipient_email}>\n' _out += f"Subject: {subject}\n" _out += content return _out m2crypto-0.46.2/demo/000077500000000000000000000000001506746742300143245ustar00rootroot00000000000000m2crypto-0.46.2/demo/CipherSaber/000077500000000000000000000000001506746742300165135ustar00rootroot00000000000000m2crypto-0.46.2/demo/CipherSaber/CipherSaber.py000066400000000000000000000025021506746742300212530ustar00rootroot00000000000000#!/usr/bin/env python """CipherSaber, http://ciphersaber.gurus.com. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" # XXX getopt handling has bugs. from M2Crypto import RC4, Rand import getopt, getpass, sys class argerr(Exception): pass cmd = -1 inf = sys.stdin outf = sys.stdout optlist, optarg = getopt.getopt(sys.argv[1:], "dei:o:") for opt in optlist: if "-d" in opt: cmd = cmd + 1 elif "-e" in opt: cmd = cmd + 2 elif "-i" in opt: i = opt[1] if i == "-": inf = sys.stdin else: inf = open(i, "rb") elif "-o" in opt: o = opt[1] if o == "-": outf = sys.stdout else: outf = open(o, "wb") if cmd < 0: raise argerr("either -d or -e") if cmd > 1: raise argerr("either -d or -e, not both") if cmd == 0: iv = inf.read(10) pp = getpass.getpass("Enter decryption passphrase: ") else: iv = Rand.rand_bytes(10) outf.write(iv) pp = getpass.getpass("Enter encryption passphrase: ") pp2 = getpass.getpass("Enter passphrase again: ") if pp != pp2: raise SystemExit("passphrase mismatch, I'm outta here...") ci = RC4.RC4(pp + iv) del pp, iv while 1: buf = inf.read() if not buf: break outf.write(ci.update(buf)) outf.write(ci.final()) m2crypto-0.46.2/demo/CipherSaber/cstest1.cs1000066400000000000000000000000501506746742300205040ustar00rootroot00000000000000om g0wt縅CVH|OO_m2crypto-0.46.2/demo/Zope/000077500000000000000000000000001506746742300152415ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope/ZServer/000077500000000000000000000000001506746742300166415ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope/ZServer/HTTPS_Server.py000066400000000000000000000143061506746742300214470ustar00rootroot00000000000000############################################################################## # # Copyright (c) 2000-2004, Ng Pheng Siong. All Rights Reserved. # This file is derived from Zope's ZServer/HTTPServer.py. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ Medusa HTTPS server for Zope changes from Medusa's http_server: Request Threads -- Requests are processed by threads from a thread pool. Output Handling -- Output is pushed directly into the producer fifo by the request-handling thread. The HTTP server does not do any post-processing such as chunking. Pipelineable -- This is needed for protocols such as HTTP/1.1 in which mutiple requests come in on the same channel, before responses are sent back. When requests are pipelined, the client doesn't wait for the response before sending another request. The server must ensure that responses are sent back in the same order as requests are received. changes from Zope's HTTP server: Well, this is a *HTTPS* server :) X.509 certificate-based authentication -- When this is in force, zhttps_handler, a subclass of zhttp_handler, is installed. The https server is configured to request an X.509 certificate from the client. When the request reaches zhttps_handler, it sets REMOTE_USER to the client's subject distinguished name (DN) from the certificate. Zope's REMOTE_USER machinery takes care of the rest, e.g., in conjunction with the RemoteUserFolder product. """ import sys, time, types from PubCore import handle from medusa import asyncore from ZServer import CONNECTION_LIMIT, ZOPE_VERSION from HTTPServer import zhttp_handler from zLOG import register_subsystem from M2Crypto import SSL, version from medusa.https_server import https_server, https_channel from medusa.asyncore import dispatcher ZSERVER_SSL_VERSION = version register_subsystem("ZServer HTTPS_Server") class zhttps0_handler(zhttp_handler): "zhttps0 handler - sets SSL request headers a la mod_ssl" def __init__(self, module, uri_base=None, env=None): zhttp_handler.__init__(self, module, uri_base, env) def get_environment(self, request): env = zhttp_handler.get_environment(self, request) env["SSL_CIPHER"] = request.channel.get_cipher() return env class zhttps_handler(zhttps0_handler): "zhttps handler - sets REMOTE_USER to user's X.509 certificate Subject DN" def __init__(self, module, uri_base=None, env=None): zhttps0_handler.__init__(self, module, uri_base, env) def get_environment(self, request): env = zhttps0_handler.get_environment(self, request) peer = request.channel.get_peer_cert() if peer is not None: env["REMOTE_USER"] = str(peer.get_subject()) return env class zhttps_channel(https_channel): "https channel" closed = 0 zombie_timeout = 100 * 60 # 100 minutes def __init__(self, server, conn, addr): https_channel.__init__(self, server, conn, addr) self.queue = [] self.working = 0 self.peer_found = 0 def push(self, producer, send=1): # this is thread-safe when send is false # note, that strings are not wrapped in # producers by default if self.closed: return self.producer_fifo.push(producer) if send: self.initiate_send() push_with_producer = push def work(self): "try to handle a request" if not self.working: if self.queue: self.working = 1 try: module_name, request, response = self.queue.pop(0) except: return handle(module_name, request, response) def close(self): self.closed = 1 while self.queue: self.queue.pop() if self.current_request is not None: self.current_request.channel = None # break circ refs self.current_request = None while self.producer_fifo: p = self.producer_fifo.first() if p is not None and type(p) != types.StringType: p.more() # free up resources held by producer self.producer_fifo.pop() self.del_channel() # self.socket.set_shutdown(SSL.SSL_SENT_SHUTDOWN|SSL.SSL_RECEIVED_SHUTDOWN) self.socket.close() def done(self): "Called when a publishing request is finished" self.working = 0 self.work() def kill_zombies(self): now = int(time.time()) for channel in asyncore.socket_map.values(): if channel.__class__ == self.__class__: if (now - channel.creation_time) > channel.zombie_timeout: channel.close() class zhttps_server(https_server): "https server" SERVER_IDENT = "ZServerSSL/%s" % (ZSERVER_SSL_VERSION,) channel_class = zhttps_channel shutup = 0 def __init__(self, ip, port, ssl_ctx, resolver=None, logger_object=None): self.shutup = 1 https_server.__init__(self, ip, port, ssl_ctx, resolver, logger_object) self.ssl_ctx = ssl_ctx self.shutup = 0 self.log_info( "(%s) HTTPS server started at %s\n" "\tHostname: %s\n\tPort: %d" % ( self.SERVER_IDENT, time.ctime(time.time()), self.server_name, self.server_port, ) ) def log_info(self, message, type="info"): if self.shutup: return dispatcher.log_info(self, message, type) def readable(self): return self.accepting and len(asyncore.socket_map) < CONNECTION_LIMIT def listen(self, num): # override asyncore limits for nt's listen queue size self.accepting = 1 return self.socket.listen(num) m2crypto-0.46.2/demo/Zope/ZServer/__init__.py000066400000000000000000000062321506746742300207550ustar00rootroot00000000000000############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## import sys, os # HACKERY to get around asyncore issues. This ought to go away! We're # currently using the Python 2.2 asyncore bundled with Zope to override # brokenness in the Python 2.1 version. We need to do some funny business # to make this work, as a 2.2-ism crept into the asyncore code. if os.name == "posix": import fcntl if not hasattr(fcntl, "F_GETFL"): import FCNTL fcntl.F_GETFL = FCNTL.F_GETFL fcntl.F_SETFL = FCNTL.F_SETFL from medusa import asyncore sys.modules["asyncore"] = asyncore from medusa.test import max_sockets CONNECTION_LIMIT = max_sockets.max_select_sockets() ZSERVER_VERSION = "1.1b1" import App.FindHomes try: import App.version_txt ZOPE_VERSION = App.version_txt.version_txt() except: ZOPE_VERSION = "experimental" # Try to poke zLOG default logging into asyncore # XXX We should probably should do a better job of this, # however that would mean that ZServer required zLOG. try: from zLOG import LOG, register_subsystem, BLATHER, INFO, WARNING, ERROR register_subsystem("ZServer") severity = {"info": INFO, "warning": WARNING, "error": ERROR} def log_info(self, message, type="info"): if ( message[:14] == "adding channel" or message[:15] == "closing channel" or message == "Computing default hostname" ): LOG("ZServer", BLATHER, message) else: LOG("ZServer", severity[type], message) import asyncore asyncore.dispatcher.log_info = log_info except: pass # A routine to try to arrange for request sockets to be closed # on exec. This makes it easier for folks who spawn long running # processes from Zope code. Thanks to Dieter Maurer for this. try: import fcntl try: from fcntl import F_SETFD, FD_CLOEXEC except ImportError: from FCNTL import F_SETFD, FD_CLOEXEC def requestCloseOnExec(sock): try: fcntl.fcntl(sock.fileno(), F_SETFD, FD_CLOEXEC) except: pass except (ImportError, AttributeError): def requestCloseOnExec(sock): pass import asyncore from medusa import resolver, logger from HTTPServer import zhttp_server, zhttp_handler from HTTPS_Server import zhttps_server, zhttps0_handler, zhttps_handler from PCGIServer import PCGIServer from FCGIServer import FCGIServer from FTPServer import FTPServer from PubCore import setNumberOfThreads from medusa.monitor import secure_monitor_server # override the service name in logger.syslog_logger logger.syslog_logger.svc_name = "ZServer" m2crypto-0.46.2/demo/Zope/ZServer/medusa/000077500000000000000000000000001506746742300201175ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope/ZServer/medusa/ftps_server.py000066400000000000000000000360521506746742300230410ustar00rootroot00000000000000"""An FTP/TLS server built on Medusa's ftp_server. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" # Python import socket, string, sys, time # Medusa from counter import counter import asynchat, asyncore, ftp_server, logger # M2Crypto from M2Crypto import SSL VERSION_STRING = "0.09" class ftp_tls_channel(ftp_server.ftp_channel): """FTP/TLS server channel for Medusa.""" def __init__(self, server, ssl_ctx, conn, addr): """Initialise the channel.""" self.ssl_ctx = ssl_ctx self.server = server self.current_mode = "a" self.addr = addr asynchat.async_chat.__init__(self, conn) self.set_terminator("\r\n") self.client_addr = (addr[0], 21) self.client_dc = None self.in_buffer = "" self.closing = 0 self.passive_acceptor = None self.passive_connection = None self.filesystem = None self.authorized = 0 self._ssl_accepting = 0 self._ssl_accepted = 0 self._pbsz = None self._prot = None resp = "220 %s M2Crypto (Medusa) FTP/TLS server v%s ready." self.respond(resp % (self.server.hostname, VERSION_STRING)) def writable(self): return self._ssl_accepting or self._ssl_accepted def handle_read(self): """Handle a read event.""" if self._ssl_accepting: self._ssl_accepted = self.socket.accept_ssl() if self._ssl_accepted: self._ssl_accepting = 0 else: try: ftp_server.ftp_channel.handle_read(self) except SSL.SSLError as what: if str(what) == "unexpected eof": self.close() else: raise def handle_write(self): """Handle a write event.""" if self._ssl_accepting: self._ssl_accepted = self.socket.accept_ssl() if self._ssl_accepted: self._ssl_accepting = 0 else: try: ftp_server.ftp_channel.handle_write(self) except SSL.SSLError as what: if str(what) == "unexpected eof": self.close() else: raise def send(self, data): """Send data over SSL.""" try: result = self.socket.send(data) if result <= 0: return 0 else: return result except SSL.SSLError as what: self.close() self.log_info("send: closing channel %s %s" % (repr(self), what)) return 0 def recv(self, buffer_size): """Receive data over SSL.""" try: result = self.socket.recv(buffer_size) if not result: return "" else: return result except SSL.SSLError as what: self.close() self.log_info("recv: closing channel %s %s" % (repr(self), what)) return "" def found_terminator(self): """Dispatch the FTP command.""" line = self.in_buffer if not len(line): return sp = string.find(line, " ") if sp != -1: line = [line[:sp], line[sp + 1 :]] else: line = [line] command = string.lower(line[0]) if string.find(command, "stor") != -1: while command and command[0] not in string.letters: command = command[1:] func_name = "cmd_%s" % command if command != "pass": self.log("<== %s" % repr(self.in_buffer)[1:-1]) else: self.log("<== %s" % line[0] + " ") self.in_buffer = "" if not hasattr(self, func_name): self.command_not_understood(line[0]) return func = getattr(self, func_name) if not self.check_command_authorization(command): self.command_not_authorized(command) else: try: result = apply(func, (line,)) except: self.server.total_exceptions.increment() (file, func, line), t, v, tbinfo = asyncore.compact_traceback() if self.client_dc: try: self.client_dc_close() except: pass resp = "451 Server error: %s, %s: file %s line: %s" self.respond(resp % (t, v, file, line)) def make_xmit_channel(self): """Create a connection for sending data.""" pa = self.passive_acceptor if pa: if pa.ready: conn, addr = pa.ready if self._prot: cdc = tls_xmit_channel(self, conn, self.ssl_ctx, addr) else: cdc = ftp_server.xmit_channel(self, addr) cdc.set_socket(conn) cdc.connected = 1 self.passive_acceptor.close() self.passive_acceptor = None else: if self._prot: cdc = tls_xmit_channel(self, None, self.ssl_ctx, None) else: cdc = ftp_server.xmit_channel(self) else: if self._prot: cdc = tls_xmit_channel(self, None, self.ssl_ctx, self.client_addr) else: cdc = ftp_server.xmit_channel(self, self.client_addr) cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) if self.bind_local_minus_one: cdc.bind(("", self.server.port - 1)) try: cdc.connect(self.client_addr) except socket.error as what: self.respond("425 Cannot build data connection") self.client_dc = cdc def make_recv_channel(self, fd): """Create a connection for receiving data.""" pa = self.passive_acceptor if pa: if pa.ready: conn, addr = pa.ready if self._prot: cdc = tls_recv_channel(self, conn, self.ssl_ctx, addr, fd) else: cdc = ftp_server.recv_channel(self, addr, fd) cdc.set_socket(conn) cdc.connected = 1 self.passive_acceptor.close() self.passive_acceptor = None else: if self._prot: cdc = tls_recv_channel(self, None, self.ssl_ctx, None, fd) else: cdc = ftp_server.recv_channel(self, None, fd) else: if self._prot: cdc = tls_recv_channel( self, None, self.ssl_ctx, self._prot, self.client_addr, fd ) else: cdc = ftp_server.recv_channel(self, self.client_addr, fd) cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) try: cdc.connect(self.client_addr) except socket.error as what: self.respond("425 Cannot build data connection") self.client_dc = cdc def cmd_auth(self, line): """Prepare for TLS operation.""" # XXX Handle variations. if line[1] != "TLS": self.command_not_understood(string.join(line)) else: self.respond("234 AUTH TLS successful") self._ssl_accepting = 1 self.socket = SSL.Connection(self.ssl_ctx, self.socket) self.socket.setup_addr(self.addr) self.socket.setup_ssl() self.socket.set_accept_state() self._ssl_accepted = self.socket.accept_ssl() if self._ssl_accepted: self._ssl_accepting = 0 def cmd_pbsz(self, line): """Negotiate size of buffer for secure data transfer. For FTP/TLS the only valid value for the parameter is '0'; any other value is accepted but ignored.""" if not (self._ssl_accepting or self._ssl_accepted): return self.respond("503 AUTH TLS must be issued prior to PBSZ") self._pbsz = 1 self.respond("200 PBSZ=0 successful.") def cmd_prot(self, line): """Negotiate the security level of the data connection.""" if self._pbsz is None: return self.respond("503 PBSZ must be issued prior to PROT") if line[1] == "C": self.respond("200 Protection set to Clear") self._pbsz = None self._prot = None elif line[1] == "P": self.respond("200 Protection set to Private") self._prot = 1 elif line[1] in ("S", "E"): self.respond("536 PROT %s unsupported" % line[1]) else: self.respond("504 PROT %s unsupported" % line[1]) class ftp_tls_server(ftp_server.ftp_server): """FTP/TLS server for Medusa.""" SERVER_IDENT = "M2Crypto FTP/TLS Server (v%s)" % VERSION_STRING ftp_channel_class = ftp_tls_channel def __init__( self, authz, ssl_ctx, host=None, ip="", port=21, resolver=None, log_obj=None ): """Initialise the server.""" self.ssl_ctx = ssl_ctx self.ip = ip self.port = port self.authorizer = authz if host is None: self.hostname = socket.gethostname() else: self.hostname = host self.total_sessions = counter() self.closed_sessions = counter() self.total_files_out = counter() self.total_files_in = counter() self.total_bytes_out = counter() self.total_bytes_in = counter() self.total_exceptions = counter() asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() self.bind((self.ip, self.port)) self.listen(5) if log_obj is None: log_obj = sys.stdout if resolver: self.logger = logger.resolving_logger(resolver, log_obj) else: self.logger = logger.unresolving_logger(logger.file_logger(sys.stdout)) l = "M2Crypto (Medusa) FTP/TLS server started at %s\n\tAuthz: %s\n\tHostname: %s\n\tPort: %d" self.log_info( l % (time.ctime(time.time()), repr(self.authorizer), self.hostname, self.port) ) def handle_accept(self): """Accept a socket and dispatch a channel to handle it.""" conn, addr = self.accept() self.total_sessions.increment() self.log_info("Connection from %s:%d" % addr) self.ftp_channel_class(self, self.ssl_ctx, conn, addr) class nbio_ftp_tls_actor: """TLS protocol negotiation mixin for FTP/TLS.""" def tls_init(self, sock, ssl_ctx, client_addr): """Perform TLS protocol negotiation.""" self.ssl_ctx = ssl_ctx self.client_addr = client_addr self._ssl_handshaking = 1 self._ssl_handshake_ok = 0 if sock: self.socket = SSL.Connection(self.ssl_ctx, sock) self.socket.setup_addr(self.client_addr) self.socket.setup_ssl() self._ssl_handshake_ok = self.socket.accept_ssl() if self._ssl_handshake_ok: self._ssl_handshaking = 0 self.add_channel() # else the client hasn't connected yet; when that happens, # handle_connect() will be triggered. def tls_neg_ok(self): """Return status of TLS protocol negotiation.""" if self._ssl_handshaking: self._ssl_handshake_ok = self.socket.accept_ssl() if self._ssl_handshake_ok: self._ssl_handshaking = 0 return self._ssl_handshake_ok def handle_connect(self): """Handle a data connection that occurs after this instance came into being. When this handler is triggered, self.socket has been created and refers to the underlying connected socket.""" self.socket = SSL.Connection(self.ssl_ctx, self.socket) self.socket.setup_addr(self.client_addr) self.socket.setup_ssl() self._ssl_handshake_ok = self.socket.accept_ssl() if self._ssl_handshake_ok: self._ssl_handshaking = 0 self.add_channel() def send(self, data): """Send data over SSL.""" try: result = self.socket.send(data) if result <= 0: return 0 else: return result except SSL.SSLError as what: self.close() self.log_info("send: closing channel %s %s" % (repr(self), what)) return 0 def recv(self, buffer_size): """Receive data over SSL.""" try: result = self.socket.recv(buffer_size) if not result: return "" else: return result except SSL.SSLError as what: self.close() self.log_info("recv: closing channel %s %s" % (repr(self), what)) return "" class tls_xmit_channel(nbio_ftp_tls_actor, ftp_server.xmit_channel): """TLS driver for a send-only data connection.""" def __init__(self, channel, conn, ssl_ctx, client_addr=None): """Initialise the driver.""" ftp_server.xmit_channel.__init__(self, channel, client_addr) self.tls_init(conn, ssl_ctx, client_addr) def readable(self): """This channel is readable iff TLS negotiation is in progress. (Which implies a connected channel, of course.)""" if not self.connected: return 0 else: return self._ssl_handshaking def writable(self): """This channel is writable iff TLS negotiation is in progress or the application has data to send.""" if self._ssl_handshaking: return 1 else: return ftp_server.xmit_channel.writable(self) def handle_read(self): """Handle a read event: either continue with TLS negotiation or let the application handle this event.""" if self.tls_neg_ok(): ftp_server.xmit_channel.handle_read(self) def handle_write(self): """Handle a write event: either continue with TLS negotiation or let the application handle this event.""" if self.tls_neg_ok(): ftp_server.xmit_channel.handle_write(self) class tls_recv_channel(nbio_ftp_tls_actor, ftp_server.recv_channel): """TLS driver for a receive-only data connection.""" def __init__(self, channel, conn, ssl_ctx, client_addr, fd): """Initialise the driver.""" ftp_server.recv_channel.__init__(self, channel, client_addr, fd) self.tls_init(conn, ssl_ctx, client_addr) def writable(self): """This channel is writable iff TLS negotiation is in progress.""" return self._ssl_handshaking def handle_read(self): """Handle a read event: either continue with TLS negotiation or let the application handle this event.""" if self.tls_neg_ok(): ftp_server.recv_channel.handle_read(self) def handle_write(self): """Handle a write event: either continue with TLS negotiation or let the application handle this event.""" if self.tls_neg_ok(): ftp_server.recv_channel.handle_write(self) m2crypto-0.46.2/demo/Zope/ZServer/medusa/https_server.py000066400000000000000000000050411506746742300232210ustar00rootroot00000000000000#!/usr/bin/env python """A https server built on Medusa's http_server. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" import asynchat, asyncore, http_server, socket, sys from M2Crypto import SSL, version VERSION_STRING = version class https_channel(http_server.http_channel): ac_in_buffer_size = 1 << 16 def __init__(self, server, conn, addr): http_server.http_channel.__init__(self, server, conn, addr) def send(self, data): try: result = self.socket._write_nbio(data) if result <= 0: return 0 else: self.server.bytes_out.increment(result) return result except SSL.SSLError as why: self.close() self.log_info("send: closing channel %s %s" % (repr(self), why)) return 0 def recv(self, buffer_size): try: result = self.socket._read_nbio(buffer_size) if result is None: return "" elif result == "": self.close() return "" else: self.server.bytes_in.increment(len(result)) return result except SSL.SSLError as why: self.close() self.log_info("recv: closing channel %s %s" % (repr(self), why)) return "" class https_server(http_server.http_server): SERVER_IDENT = "M2Crypto HTTPS Server (v%s)" % VERSION_STRING channel_class = https_channel def __init__(self, ip, port, ssl_ctx, resolver=None, logger_object=None): http_server.http_server.__init__(self, ip, port, resolver, logger_object) self.ssl_ctx = ssl_ctx def handle_accept(self): # Cribbed from http_server. self.total_clients.increment() try: conn, addr = self.accept() except socket.error: # linux: on rare occasions we get a bogus socket back from # accept. socketmodule.c:makesockaddr complains that the # address family is unknown. We don't want the whole server # to shut down because of this. sys.stderr.write("warning: server accept() threw an exception\n") return # Turn the vanilla socket into an SSL connection. try: ssl_conn = SSL.Connection(self.ssl_ctx, conn) ssl_conn._setup_ssl(addr) ssl_conn.accept_ssl() self.channel_class(self, ssl_conn, addr) except SSL.SSLError: pass def writeable(self): return 0 m2crypto-0.46.2/demo/Zope/ca.pem000066400000000000000000000023041506746742300163260ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDWTCCAsKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAxMTIxNTA1NTU0NloXDTA0MTIxNDA1NTU0 NlowgYAxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxML TTJDcnlwdG8gQ0ExJDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3Rl cjEiMCAGCSqGSIb3DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbTCBnzANBgkqhkiG 9w0BAQEFAAOBjQAwgYkCgYEAx8soJbS719LHK62VVVIQeC3oW0HvFArwPnA0LuEK q+LaqMOJg1rS7hvFdX03diV+XJw7cC0iECZYJNG4ii1xbY6KRmufkInaAwm54E3N e+YYVocaqUkcN6xVf6fwnLfPXbpFS/K2Umg11ObKMmi80JmiIdjcjRRCQZC7g1hf q+kCAwEAAaOB4DCB3TAdBgNVHQ4EFgQU6/qcBzEtQphfXLhiOHbt2KqBwMIwga0G A1UdIwSBpTCBooAU6/qcBzEtQphfXLhiOHbt2KqBwMKhgYakgYMwgYAxCzAJBgNV BAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0Ex JDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEiMCAGCSqGSIb3 DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqG SIb3DQEBBAUAA4GBAD+I14GuS5vJmyv1k7mUMbAicsWRHZ+zrGOq9L/L2LsA+lKQ dAzEZE2+Zv8LBPJVltbJJhcFNJS/ZMAjEm4xlJuCpvXVMxd/M5AM29aqekWlIK7J vsdDL8IuzpRkMniUiNKPhmB6IPIOslvUKx6QofcE0wDh6pg4VvIbCjkpZ7gf -----END CERTIFICATE----- m2crypto-0.46.2/demo/Zope/dh1024.pem000066400000000000000000000003651506746742300166520ustar00rootroot00000000000000-----BEGIN DH PARAMETERS----- MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq /Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx /mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC -----END DH PARAMETERS----- m2crypto-0.46.2/demo/Zope/lib/000077500000000000000000000000001506746742300160075ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope/lib/python/000077500000000000000000000000001506746742300173305ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope/lib/python/Products/000077500000000000000000000000001506746742300211335ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope/lib/python/Products/GuardedFile/000077500000000000000000000000001506746742300233065ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope/lib/python/Products/GuardedFile/GuardedFile.py000066400000000000000000000034211506746742300260330ustar00rootroot00000000000000"""GuardedFile.GuardedFile Copyright (c) 2000-2003 Ng Pheng Siong. All rights reserved. This software is released under the ZPL. Usual disclaimers apply.""" __version__ = "1.3" from AccessControl import getSecurityManager from Globals import HTMLFile, MessageDialog from OFS.Image import File, cookId manage_addForm = HTMLFile("add", globals(), Kind="GuardedFile", kind="GuardedFile") def manage_addGuardedFile( self, id, file, title="", precondition="", content_type="", REQUEST=None ): """ Add a new GuardedFile object. Creates a new GuardedFile object 'id' with the content of 'file'. """ # Object creation stuff, cribbed from OFS.Image.manage_addFile(). id, title = cookId(id, title, file) self = self.this() self._setObject(id, GuardedFile(id, title, "", content_type, precondition)) obj = self._getOb(id) obj.manage_upload(file) # Unset permission acquisition. obj.manage_acquiredPermissions() # Create a proxy role and set a specific permission for it. proxy_role = "proxy_for_%s" % id self._addRole(proxy_role) obj.manage_role(proxy_role, ["View"]) uname = getSecurityManager().getUser().getUserName() self.manage_addLocalRoles(uname, (proxy_role,), REQUEST) # Feedback. if REQUEST: return MessageDialog( title="Success!", message='GuardedFile "%s" has been created.' % id, action="manage_main", ) class GuardedFile(File): """A File object accessible by proxy only.""" meta_type = "GuardedFile" def manage_beforeDelete(self, item, container): """Delete self's proxy role.""" role = "proxy_for_%s" % self.__name__ container._delRoles([role], None) self.manage_delLocalRoles(self.users_with_local_role(role)) m2crypto-0.46.2/demo/Zope/lib/python/Products/GuardedFile/README.txt000066400000000000000000000006541506746742300250110ustar00rootroot00000000000000GuardedFile A GuardedFile is a Zope File that is accessible *by proxy* only. When a GuardedFile is created, all acquired permissions are unset. A proxy role is created in its container with the sole permission "View". When the GuardedFile is deleted, its associated proxy role is also removed. In all other aspects a GuardedFile behaves exactly like a File. $Id$ $Revision: 1.2 $ m2crypto-0.46.2/demo/Zope/lib/python/Products/GuardedFile/TODO.txt000066400000000000000000000000111506746742300246040ustar00rootroot000000000000001. Icon. m2crypto-0.46.2/demo/Zope/lib/python/Products/GuardedFile/__init__.py000066400000000000000000000013061506746742300254170ustar00rootroot00000000000000"""GuardedFile.__init__ Copyright (c) 2000 Ng Pheng Siong. All rights reserved. This software is released under the ZPL.""" __version__ = "1.1" import GuardedFile def initialize(context): try: context.registerClass( GuardedFile.GuardedFile, constructors=( GuardedFile.manage_addForm, GuardedFile.manage_addGuardedFile, ), # icon='folder.gif' ) context.registerBaseClass(GuardedFile.GuardedFile) except: import sys, traceback, string type, val, tb = sys.exc_info() sys.stderr.write(string.join(traceback.format_exception(type, val, tb), "")) del type, val, tb m2crypto-0.46.2/demo/Zope/lib/python/Products/GuardedFile/add.dtml000066400000000000000000000035051506746742300247230ustar00rootroot00000000000000

A GuardedFile is a Zope File that is accessible by proxy only.

When a GuardedFile is created, all acquired permissions are unset. A proxy role is created in its container with the sole permission "View".

When the GuardedFile is deleted, its associated proxy role is also removed.

In all other aspects a GuardedFile behaves exactly like a File.

You can create a new using the form below. Select a file from your local computer by clicking the Browse button. The file you select will be uploaded to Zope as a .

Id
Title
File
m2crypto-0.46.2/demo/Zope/lib/python/Products/GuardedFile/refresh.txt000066400000000000000000000000001506746742300254730ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope/lib/python/Products/GuardedFile/version.txt000066400000000000000000000000221506746742300255260ustar00rootroot00000000000000GuardedFile-1-1-0 m2crypto-0.46.2/demo/Zope/lib/python/Products/ZSmime/000077500000000000000000000000001506746742300223375ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope/lib/python/Products/ZSmime/README.txt000066400000000000000000000012721506746742300240370ustar00rootroot00000000000000ZSmime enables Zope to generate S/MIME-signed/encrypted messages. ZSmime is useful where Zope accepts confidential information over the web, e.g., credit card information, Swiss bank account instructions, etc. Such information can be protected by ZSmime and relayed off-site immediately. This reduces the value of the information carried on-site and in turn reduces the effect of a successful attack against the site. Even if the S/MIME-protected information remains on-site, it is now encrypted - this introduces additional cost in defeating the protection and may mitigate the impact of a successful site penetration. ZSmime adds a DTML tag "dtml-smime" to Zope. $Id$ $Revision: 1.1 $ m2crypto-0.46.2/demo/Zope/lib/python/Products/ZSmime/SmimeTag.py000066400000000000000000000056021506746742300244220ustar00rootroot00000000000000"""ZSmime.SmimeTag Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved. This software is released under the ZPL. Usual disclaimers apply.""" __version__ = "1.2" # Zope tag stuff. from DocumentTemplate.DT_String import String from DocumentTemplate.DT_Util import * from DocumentTemplate.DT_Var import Var, Call # M2Crypto. from M2Crypto import BIO, SMIME, X509 SmimeError = "SmimeTag Error" class SmimeTag: """""" name = "smime" blockContinuations = () def __init__(self, blocks): tname, args, section = blocks[0] self.section = section args = parse_params(args, signer=None, recipients=None) has_key = args.has_key if has_key("signer"): self.signer = args["signer"] try: Call(self.signer) except ParseError: raise SmimeError('Invalid parameter "signer".') else: raise SmimeError('The parameter "signer" was not specified in tag.') if has_key("recipients"): self.recipients = args["recipients"] try: Call(self.recipients) except ParseError: raise SmimeError('Invalid parameter "recipients".') else: raise SmimeError('The parameter "recipients" was not specified in tag.') def render(self, md): # Render the dtml block. data = render_blocks(self.section.blocks, md) data_bio = BIO.MemoryBuffer(data) # Prepare to S/MIME. s = SMIME.SMIME() # Render the signer key, load into BIO. try: signer = Var(self.signer).render(md) except ParseError: raise SmimeError('Invalid parameter "signer".') signer_key_bio = BIO.MemoryBuffer(signer) signer_cert_bio = BIO.MemoryBuffer(signer) # XXX Kludge. # Sign the data. s.load_key_bio(signer_key_bio, signer_cert_bio) p7 = s.sign(data_bio, flags=SMIME.PKCS7_TEXT) # Recreate coz sign() has consumed the MemoryBuffer. # May be cheaper to seek to start. data_bio = BIO.MemoryBuffer(data) # Render recipients, load into BIO. try: recip = Var(self.recipients).render(md) except ParseError: raise SmimeError('Invalid parameter "recipients".') recip_bio = BIO.MemoryBuffer(recip) # Load recipient certificates. sk = X509.X509_Stack() sk.push(X509.load_cert_bio(recip_bio)) s.set_x509_stack(sk) # Set a cipher. s.set_cipher(SMIME.Cipher("des_ede3_cbc")) # Encrypt. tmp_bio = BIO.MemoryBuffer() s.write(tmp_bio, p7) p7 = s.encrypt(tmp_bio) # Finally, return the now signed/encrypted PKCS7. out = BIO.MemoryBuffer() s.write(out, p7) return out.getvalue() __call__ = render String.commands["smime"] = SmimeTag m2crypto-0.46.2/demo/Zope/lib/python/Products/ZSmime/__init__.py000066400000000000000000000002671506746742300244550ustar00rootroot00000000000000"""ZSmime.__init__ Copyright (c) 2000 Ng Pheng Siong. All rights reserved. This software is released under the ZPL. Usual disclaimers apply.""" __version__ = "1.1" import SmimeTag m2crypto-0.46.2/demo/Zope/lib/python/Products/ZSmime/version.txt000066400000000000000000000000151506746742300245610ustar00rootroot00000000000000ZSmime-1-0-1 m2crypto-0.46.2/demo/Zope/server.pem000066400000000000000000000041101506746742300172460ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDYjCCAsugAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAzMDYyMjEzMzAxNFoXDTA0MDYyMTEzMzAx NFowXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwls b2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5leGFtcGxlLmRv bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA37aKGZtFicl8xXXTLJ8/JD7c kd3t/teCX9i61lpaDQCKBoVrrursIvZihemMKI9g/u/+BLqt5g8mBdgUdYz0txc8 KEbV2hj+wwOX4H3XwD0Y+DysXiNHq7/tFdmzSVHoLxpY4zYzXbxQ/p049wvIyPRp /y3omcnx/TEUhkn+JmkCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4 QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTB H/mUYlww24mJlSxEtGdlwojO9zCBrQYDVR0jBIGlMIGigBTr+pwHMS1CmF9cuGI4 du3YqoHAwqGBhqSBgzCBgDELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv MRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8gQ2VydGlm aWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNuZ3BzQG5ldG1lbWV0aWMuY29t ggEAMA0GCSqGSIb3DQEBBAUAA4GBAAvl6v0s3eFeGP4iAcrfysuK7jzFKhjDYuOy lVS3u33bZNLnMpM6OSEM9yPh4WpFCVHf+nYwC71pk4ilsLVXjKxymm2lNGcxLVuW iydFz4Ly9nmN7Ja9ygYT39dGAFP/wN7ELTpsbul8VfmqhNg9y81d8i/A1tK3AGA8 0QkPQNdP -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDftooZm0WJyXzFddMsnz8kPtyR3e3+14Jf2LrWWloNAIoGhWuu 6uwi9mKF6Ywoj2D+7/4Euq3mDyYF2BR1jPS3FzwoRtXaGP7DA5fgfdfAPRj4PKxe I0erv+0V2bNJUegvGljjNjNdvFD+nTj3C8jI9Gn/LeiZyfH9MRSGSf4maQIDAQAB AoGAHpeVtv62uarl9xKvuBBm0AwQmZnhq9HIsFaw5hMg8Vo7hbzFBvx1IirTOkC/ u+QvfW1QLVFh6m3z4ySzV4fZBtcd6F9SbSrZ0xsxIUB2NOSa1RGgiaP61bJnMMM1 xM3O9iwM5GZc3Gqy08QOCpDl0772VJ+9Gz3FA88mrc6rHQkCQQDz6RIatFjT28n8 1vy0nHwwZz2oXTpe/pyZPwoKj8zVsmrKhKwOw7l8ArxjP8zoHOE7AQBCXYDMNoFp IAF0yuqrAkEA6s0wMEdPpQeb0XHAfccyJQoeULxHdVFoz1wWmGSOm4YmQtR8/QJx luEgfpeRkzxBKt5Ls3MEkheIOw7xV24zOwJAMz+DaE0AZPNHS3K4ghJnHZxzng6I lzEUIjbWm0V/ml70hTy/EhMZw+6nOotLOHHo+QbK0SboSwAgzL/Gzo1cJQJANqpS 38qadleRJXAQWrg3qnvyluVe1aeAeVZ9RDmVIgxXeBO0jcs12uTLBe4PzHGo0mwy v7K1i7XC180gzzQu5QJBAOxITT9RoWSSozPvnirHd37sn+RsrNYkV07NAa80M20Z DkBPHeMVkNgigrQ6L6vWmbRDGQbGcMplAxnI5ppKCoU= -----END RSA PRIVATE KEY----- m2crypto-0.46.2/demo/Zope/starts000066400000000000000000000011101506746742300164750ustar00rootroot00000000000000#!/bin/sh umask 077 reldir=`dirname $0` cwd=`cd $reldir; pwd` # Zope's event logger is controlled by the "EVENT_LOG_FILE" environment # variable. If you don't have a "EVENT_LOG_FILE" environment variable # (or its older alias "STUPID_LOG_FILE") set, Zope will log to the standard # output. For more information on EVENT_LOG_FILE, see doc/ENVIRONMENT.txt. ZLOGFILE=$EVENT_LOG_FILE if [ -z "$ZLOGFILE" ]; then ZLOGFILE=$STUPID_LOG_FILE fi if [ -z "$ZLOGFILE" ]; then EVENT_LOG_FILE="" export EVENT_LOG_FILE fi exec /usr/local/bin/python2.1 $cwd/z2s.py -D "$@" m2crypto-0.46.2/demo/Zope/starts.bat000077500000000000000000000001261506746742300172530ustar00rootroot00000000000000"C:\pkg\zope260\bin\python.exe" "C:\pkg\zope260\z2s.py" -D %1 %2 %3 %4 %5 %6 %7 %8 %9 m2crypto-0.46.2/demo/Zope/utilities/000077500000000000000000000000001506746742300172545ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope/utilities/x509_user.py000066400000000000000000000035111506746742300213710ustar00rootroot00000000000000#!/usr/bin/env python """ This is a very simple program to manage the access_x509 database. The overriding goal is program portability, hence its use of 'anydbm'. Invoke it thusly: x509_user.py -u [ -x ] [ -f ] is the Zope username; it must be present. is the X.509 certificate's subject distinguished name to associate with the user. If it is present, the association is created or updated. If it is absent, the association is removed. defaults to 'access_x509'. (I told you this is a dumb program.) To read the subject distinguished name from the certificate 'client.pem', invoke 'openssl' thusly: openssl x509 -subject -noout -in client.pem This produces the output: subject=/C=SG/O=M2Crypto Client/CN=M2Crypto Client/Email=ngps@post1.com Next, invoke this tool: x509_user.py -u superuser \\ -f "/C=SG/O=M2Crypto Client/CN=M2Crypto Client/Email=ngps@post1.com" This associates the user who owns client.pem to the Zope "superuser". Copyright (c) 2000 Ng Pheng Siong. This program is released under the ZPL. """ import anydbm, getopt, sys x509_db = "access_x509" username = subject_dn = None argerr = "Usage" optlist, optarg = getopt.getopt(sys.argv[1:], "f:u:x:") # ;-) for opt in optlist: if "-f" in opt: x509_db = opt[1] elif "-u" in opt: username = opt[1] elif "-x" in opt: subject_dn = opt[1] if username is None: raise argerr("\n" + __doc__) db = anydbm.open(x509_db, "cw") if subject_dn is None: # Remove the association... try: subject_dn = db[username] del db[subject_dn] del db[username] except: pass else: # Create/update the association. db[subject_dn] = username db[username] = subject_dn db.close() m2crypto-0.46.2/demo/Zope/z2s.py000066400000000000000000001115651506746742300163420ustar00rootroot00000000000000############################################################################## # # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## from __future__ import print_function """Zope 2 ZServer start-up file Usage: %(program)s [options] [environment settings] Options: -h Output this text. -z path The location of the Zope installation. The default is the location of this script, %(here)s. -Z 0 or 1 UNIX only! This option is ignored on Windows. This option controls whether a management process will be created that restarts Zope after a shutdown or crash. If the argument to -Z is non-null (e.g. "-Z1" or "-Zyes"), a management process will be used. If the argument to -Z is "-", or "0", (e.g. "-Z-" or "-Z0"), a management process will not be used. On UNIX, the default behavior is to create a separate management process (e.g. -Z1) if the -Z option is not specified. (Note: the -Z option in Zopes before Zope 2.6 used to be used to specify a pidfile name for the management process. This pidfile no longer exists). -t n The number of threads to use, if ZODB3 is used. The default is %(NUMBER_OF_THREADS)s. -i n Set the interpreter check interval. This integer value determines how often the interpreter checks for periodic things such as thread switches and signal handlers. The Zope default is 500, but you may want to experiment with other values that may increase performance in your particular environment. -D Run in Zope debug mode. This causes the Zope process not to detach from the controlling terminal, and is equivalent to supplying the environment variable setting Z_DEBUG_MODE=1 -a ipaddress The IP address to listen on. If this is an empty string (e.g. -a ''), then all addresses on the machine are used. The default is %(IP_ADDRESS)s. -d ipaddress IP address of your DNS server. If this is an empty string (e.g. -d ''), then IP addresses will not be logged. If you have DNS service on your local machine then you can set this to 127.0.0.1. The default is: %(DNS_IP)s. -u username or uid number The username to run ZServer as. You may want to run ZServer as a dedicated user. This only works under Unix, and if ZServer is started as root, and is required in that case. -P [ipaddress:]number Set the web, ftp and monitor port numbers simultaneously as offsets from the number. The web port number will be number+80. The FTP port number will be number+21. The monitor port number will be number+99. The number can be preeceeded by an ip address follwed by a colon to specify an address to listen on. This allows different servers to listen on different addresses. Multiple -P options can be provided to run multiple sets of servers. -w port The Web server (HTTP) port. This defaults to %(HTTP_PORT)s. The standard port for HTTP services is 80. If this is a dash (e.g. -w -), then HTTP is disabled. The number can be preeceeded by an ip address follwed by a colon to specify an address to listen on. This allows different servers to listen on different addresses. Multiple -w options can be provided to run multiple servers. -y port The SSL Web server (HTTPS) port. This defaults to %(HTTPS_PORT)s. The standard port for HTTPS services is 443. If this is a dash (e.g. -y -), then HTTPS is disabled. The number can be preeceeded by an ip address follwed by a colon to specify an address to listen on. This allows different servers to listen on different addresses. Multiple -y options can be provided to run multiple servers. -W port The "WebDAV source" port. If this is a dash (e.g. -W -), then "WebDAV source" is disabled. The default is disabled. Note that this feature is a workaround for the lack of "source-link" support in standard WebDAV clients. The port can be preeceeded by an ip address follwed by a colon to specify an address to listen on. This allows different servers to listen on different addresses. Multiple -W options can be provided to run multiple servers. -Y port The "WebDAV source over HTTPS" port. If this is a dash (e.g. -Y -), then "WebDAV source over HTTPS" is disabled. The default is disabled. Note that this feature is a workaround for the lack of "source-link" support in standard WebDAV clients. The port can be preeceeded by an ip address follwed by a colon to specify an address to listen on. This allows different servers to listen on different addresses. Multiple -Y options can be provided to run multiple servers. -x If present, this option causes Zope to run in X.509 certificate-based authentication mode. -C --force-http-connection-close If present, this option causes Zope to close all HTTP connections, regardless of the 'Connection:' header (or lack of one) sent by the client. -f port The FTP port. If this is a dash (e.g. -f -), then FTP is disabled. The standard port for FTP services is 21. The default is %(FTP_PORT)s. The port can be preeceeded by an ip address follwed by a colon to specify an address to listen on. This allows different servers to listen on different addresses. Multiple -f options can be provided to run multiple servers. -p path Path to the PCGI resource file. The default value is %(PCGI_FILE)s, relative to the Zope location. If this is a dash (-p -) or the file does not exist, then PCGI is disabled. -F path_or_port Either a port number (for inet sockets) or a path name (for unix domain sockets) for the FastCGI Server. If the flag and value are not specified then the FastCGI Server is disabled. -m port The secure monitor server port. If this is a dash (-m -), then the monitor server is disabled. The monitor server allows interactive Python style access to a running ZServer. To access the server see medusa/monitor_client.py or medusa/monitor_client_win32.py. The monitor server password is the same as the Zope emergency user password set in the 'access' file. The default is to not start up a monitor server. The port can be preeceeded by an ip address follwed by a colon to specify an address to listen on. This allows different servers to listen on different addresses. Multiple -m options can be provided to run multiple servers. --icp port The ICP port. ICP can be used to distribute load between back-end zope servers, if you are using an ICP-aware front-end proxy such as Squid. The port can be preeceeded by an ip address follwed by a colon to specify an address to listen on. This allows different servers to listen on different addresses. Multiple --icp options can be provided to run multiple servers. -l path Path to the ZServer log file. If this is a relative path then the log file will be written to the 'var' directory. The default is %(LOG_FILE)s. -r Run ZServer is read-only mode. ZServer won't write anything to disk. No log files, no pid files, nothing. This means that you can't do a lot of stuff like use PCGI, and zdaemon. ZServer will log hits to STDOUT and zLOG will log to STDERR. -L Enable locale (internationalization) support. The value passed for this option should be the name of the locale to be used (see your operating system documentation for locale information specific to your system). If an empty string is passed for this option (-L ''), Zope will set the locale to the user's default setting (typically specified in the $LANG environment variable). If your Python installation does not support the locale module, the requested locale is not supported by your system or an empty string was passed but no default locale can be found, an error will be raised and Zope will not start. -X Disable servers. This might be used to effectively disable all default server settings or previous server settings in the option list before providing new settings. For example to provide just a web server: %(program)s -X -w80 -M file Save detailed logging information to the given file. This log includes separate entries for: - The start of a request, - The start of processing the request in an application thread, - The start of response output, and - The end of the request. Environment settings are of the form: NAME=VALUE. Note: you *must* use Python 2.1 or later! """ # This is required path hackery for the win32 binary distribution # that ensures that the bundled python libraries are used. In a # win32 binary distribution, the installer will have replaced the # marker string with the actual software home. If that has not # happened, then the path munging code is skipped. swhome = r"INSERT_SOFTWARE_HOME" if swhome != "INSERT_SOFTWARE_HOME": import sys sys.path.insert(0, "%s/lib/python" % swhome) sys.path.insert(1, "%s/bin/lib" % swhome) sys.path.insert(2, "%s/bin/lib/plat-win" % swhome) sys.path.insert(3, "%s/bin/lib/win32" % swhome) sys.path.insert(4, "%s/bin/lib/win32/lib" % swhome) sys.path.insert(5, "%s" % swhome) import os, sys, getopt, codecs, string, importlib import socket from types import StringType, IntType # workaround to allow unicode encoding conversions in DTML dummy = codecs.lookup("iso-8859-1") sys.setcheckinterval(500) program = sys.argv[0] here = os.path.join(os.getcwd(), os.path.split(program)[0]) ######################################################################## # Configuration section ## General configuration options ## # This is the IP address of the network interface you want your servers to # be visible from. This can be changed to '' to listen on all interfaces. IP_ADDRESS = "" # IP address of your DNS server. Set to '' if you do not want to resolve # IP addresses. If you have DNS service on your local machine then you can # set this to '127.0.0.1' DNS_IP = "" # User id to run ZServer as. Note that this only works under Unix, and if # ZServer is started by root. This no longer defaults to 'nobody' since # that can lead to a Zope file compromise. UID = None # Log file location. If this is a relative path, then it is joined the # the 'var' directory. LOG_FILE = "Z2.log" ## HTTP configuration ## # Port for HTTP Server. The standard port for HTTP services is 80. HTTP_PORT = 8080 # Port for HTTPS Server. The standard port for HTTPS services is 443. HTTPS_PORT = 8443 # HTTP enivornment settings. HTTP_ENV = {} # HTTPS enivornment settings. HTTPS_ENV = {} # Should we close all HTTP connections, ignoring the (usually absent) # 'Connection:' header? FORCE_HTTP_CONNECTION_CLOSE = 0 # Port for the special "WebDAV source view" HTTP handler. There is no # standard port for this handler, which is disabled by default. WEBDAV_SOURCE_PORT = [] # Port for the special "WebDAV source view over SSL" HTTP handler. There is no # standard port for this handler, which is disabled by default. WEBDAV_SSL_SOURCE_PORT = [] # Should we use client X.509 certificate-based authentication? X509_REMOTE_USER = None ## FTP configuration # Port for the FTP Server. The standard port for FTP services is 21. FTP_PORT = 8021 ## PCGI configuration # You can configure the PCGI server manually, or have it read its # configuration information from a PCGI info file. PCGI_FILE = "Zope.cgi" ## Monitor configuration MONITOR_PORT = 0 ## ICP configuration ICP_PORT = 0 # Module to be published, which must be Main or Zope MODULE = "Zope" # The size of the thread pool, if ZODB3 is used. NUMBER_OF_THREADS = 4 # Localization support LOCALE_ID = None # Socket path or port for the FastCGI Server FCGI_PORT = None # Detailed log file DETAILED_LOG_FILE = "" # Use a daemon process USE_DAEMON = 1 # ######################################################################## ######################################################################## # Handle command-line arguments: def server_info(old, v, offset=0): # interpret v as a port or address/port and get new value if v == "-": v = "" l = v.find(":") if l >= 0: a = v[:l] v = v[l + 1 :] else: a = IP_ADDRESS if not v: return v try: v = int(v) if v < 0: raise ValueError("Invalid port", v) v = v + offset except: raise ValueError("Invalid port", v) if isinstance(old, IntType): old = [(a, v)] else: old.append((a, v)) return old try: opts, args = getopt.getopt( sys.argv[1:], "hz:Z:t:i:a:d:u:w:W:y:Y:x:f:p:m:Sl:2DP:rF:L:XM:C", ["icp=", "force-http-connection-close"], ) DEBUG = 0 READ_ONLY = 0 if sys.platform == "win32": USE_DAEMON = 0 # Get environment variables for a in args: if a.find("="): a = a.split("=") o = a[0] v = "=".join(a[1:]) if o: os.environ[o] = v HTTP_ENV[o] = v else: raise ValueError("Invalid argument", a) for o, v in opts: if o == "-z": here = v elif o == "-Z": if v in ("-", "0", ""): USE_DAEMON = 0 elif sys.platform != "win32": USE_DAEMON = 1 elif o == "-r": READ_ONLY = 1 elif o == "-t": try: v = int(v) except: raise ValueError("Invalid number of threads", v) NUMBER_OF_THREADS = v elif o == "-i": try: v = int(v) except: raise ValueError("Invalid value for -i option", v) sys.setcheckinterval(v) elif o == "-a": IP_ADDRESS = v elif o == "-d": if v == "-": v = "" DNS_IP = v elif o == "-u": UID = v elif o == "-D": os.environ["Z_DEBUG_MODE"] = "1" DEBUG = 1 elif o == "-S": sys.ZMANAGED = 1 elif o == "-X": MONITOR_PORT = HTTP_PORT = FTP_PORT = FCGI_PORT = ICP_PORT = 0 WEBDAV_SOURCE_PORT = 0 PCGI_FILE = "" elif o == "-m": MONITOR_PORT = server_info(MONITOR_PORT, v) elif o == "-w": HTTP_PORT = server_info(HTTP_PORT, v) elif o == "-y": HTTPS_PORT = server_info(HTTPS_PORT, v) elif o == "-C" or o == "--force-http-connection-close": FORCE_HTTP_CONNECTION_CLOSE = 1 elif o == "-W": WEBDAV_SOURCE_PORT = server_info(WEBDAV_SOURCE_PORT, v) elif o == "-Y": WEBDAV_SSL_SOURCE_PORT = server_info(WEBDAV_SSL_SOURCE_PORT, v) elif o == "-x": if v in ("-", "0", ""): X509_REMOTE_USER = None else: X509_REMOTE_USER = 1 elif o == "-f": FTP_PORT = server_info(FTP_PORT, v) elif o == "-P": HTTP_PORT = server_info(HTTP_PORT, v, 80) FTP_PORT = server_info(FTP_PORT, v, 21) elif o == "--icp": ICP_PORT = server_info(ICP_PORT, v) elif o == "-p": if v == "-": v = "" PCGI_FILE = v elif o == "-h": print(__doc__ % vars()) sys.exit(0) elif o == "-2": MODULE = "Main" elif o == "-l": LOG_FILE = v elif o == "-L": if v: LOCALE_ID = v else: LOCALE_ID = "" elif o == "-F": if v == "-": v = "" FCGI_PORT = v elif o == "-M": DETAILED_LOG_FILE = v except SystemExit: sys.exit(0) except: print(__doc__ % vars()) print() print("Error:") print("%s: %s" % (sys.exc_type, sys.exc_value)) sys.exit(1) # ######################################################################## ######################################################################## # OK, let's get going! # Jigger path: sys.path = [os.path.join(here, "lib", "python"), here] + filter(None, sys.path) # Try to set the locale if specified on the command # line. If the locale module is not available or the # requested locale is not supported by the local # machine, raise ValueError(an error so that the user is made) # aware of the problem. def set_locale(val): try: import locale except: raise SystemExit( "The locale module could not be imported.\n" "To use localization options, you must ensure\n" "that the locale module is compiled into your\n" "Python installation." ) try: locale.setlocale(locale.LC_ALL, val) except: raise SystemExit( "The specified locale is not supported by your system.\n" "See your operating system documentation for more\n" "information on locale support." ) if LOCALE_ID is not None: set_locale(LOCALE_ID) import zdaemon # from this point forward we can use the zope logger # importing ZDaemon before importing ZServer causes ZServer logging # not to work. # Import ZServer before we open the database or get at interesting # application code so that ZServer's asyncore gets to be the # official one. Also gets SOFTWARE_HOME, INSTANCE_HOME, and CLIENT_HOME import ZServer # install signal handlers if on posix if os.name == "posix": from Signals import Signals Signals.registerZopeSignals() # Location of the ZServer pid file. When Zope starts up it will write # its PID to this file. If Zope is run under zdaemon control, zdaemon # will write to this pidfile instead of Zope. PID_FILE = os.path.join(CLIENT_HOME, "Z2.pid") if USE_DAEMON and not READ_ONLY: import App.FindHomes sys.ZMANAGED = 1 # zdaemon.run creates a process which "manages" the actual Zope # process (restarts it if it dies). The management process passes along # signals that it receives to its child. zdaemon.run(sys.argv, os.path.join(CLIENT_HOME, PID_FILE)) os.chdir(CLIENT_HOME) def _warn_nobody(): zLOG.LOG( "z2", zLOG.INFO, ( "Running Zope as 'nobody' can compromise " "your Zope files; consider using a " "dedicated user account for Zope" ), ) try: # Import logging support import zLOG import ZLogger if READ_ONLY: if hasattr(zLOG, "_set_stupid_dest"): zLOG._set_stupid_dest(sys.stderr) else: zLOG._stupid_dest = sys.stderr else: zLOG.log_write = ZLogger.ZLogger.log_write if DETAILED_LOG_FILE: from ZServer import DebugLogger logfile = os.path.join(CLIENT_HOME, DETAILED_LOG_FILE) zLOG.LOG("z2", zLOG.BLATHER, "Using detailed request log file %s" % logfile) DL = DebugLogger.DebugLogger(logfile) DebugLogger.log = DL.log DebugLogger.reopen = DL.reopen sys.__detailedlog = DL # Import Zope (or Main) if MODULE == "Zope": import Zope Zope.startup() else: importlib.import_module(MODULE) # Location of the ZServer log file. This file logs all ZServer activity. # You may wish to create different logs for different servers. See # medusa/logger.py for more information. if not os.path.isabs(LOG_FILE): LOG_PATH = os.path.join(CLIENT_HOME, LOG_FILE) else: LOG_PATH = LOG_FILE # import ZServer stuff # First, we need to increase the number of threads if MODULE == "Zope": from ZServer import setNumberOfThreads setNumberOfThreads(NUMBER_OF_THREADS) from ZServer import resolver, logger, asyncore from ZServer import zhttp_server, zhttp_handler from ZServer import zhttps_server, zhttps0_handler, zhttps_handler from ZServer.WebDAVSrcHandler import WebDAVSrcHandler from ZServer import PCGIServer, FTPServer, FCGIServer from ZServer import secure_monitor_server from M2Crypto import SSL, Rand ## ZServer startup ## ## In X509_REMOTE_USER mode, we log the client cert's subject DN. if X509_REMOTE_USER: import base64, string, time def log(self, bytes): user_agent = self.get_header("user-agent") if not user_agent: user_agent = "" referer = self.get_header("referer") if not referer: referer = "" get_peer_cert = getattr(self.channel, "get_peer_cert", None) if get_peer_cert is not None: name = str(get_peer_cert().get_subject()) else: name = "Anonymous" auth = self.get_header("Authorization") if auth is not None: if string.lower(auth[:6]) == "basic ": try: decoded = base64.decodestring(auth[6:]) except base64.binascii.Error: decoded = "" t = string.split(decoded, ":", 1) if len(t) < 2: name = "Unknown (bad auth string)" else: name = t[0] self.channel.server.logger.log( self.channel.addr[0], ' - %s [%s] "%s" %d %d "%s" "%s"\n' % ( name, self.log_date_string(time.time()), self.request, self.reply_code, bytes, referer, user_agent, ), ) from ZServer.medusa import http_server http_server.http_request.log = log # Resolver and Logger, used by other servers if DNS_IP: rs = resolver.caching_resolver(DNS_IP) else: rs = None if READ_ONLY: lg = logger.file_logger("-") # log to stdout zLOG.LOG("z2", zLOG.BLATHER, "Logging access log to stdout") elif "ZSYSLOG_ACCESS" in os.environ: if "ZSYSLOG_ACCESS_FACILITY" in os.environ: lg = logger.syslog_logger( os.environ["ZSYSLOG_ACCESS"], facility=os.environ["ZSYSLOG_ACCESS_FACILITY"], ) else: lg = logger.syslog_logger(os.environ["ZSYSLOG_ACCESS"]) zLOG.LOG("z2", zLOG.BLATHER, "Using local syslog access log") elif "ZSYSLOG_ACCESS_SERVER" in os.environ: (addr, port) = os.environ["ZSYSLOG_ACCESS_SERVER"].split(":") lg = logger.syslog_logger((addr, int(port))) zLOG.LOG("z2", zLOG.BLATHER, "Using remote syslog access log") else: lg = logger.file_logger(LOG_PATH) zLOG.LOG("z2", zLOG.BLATHER, "Using access log file %s" % LOG_PATH) sys.__lg = lg port_err = ( "\n\nZope wants to use %(socktype)s port %(port)s for its " "%(protocol)s service, but it is already in use by another " "application on this machine. Either shut the application down " "which is using this port, or start Zope with a different " '%(protocol)s port via the "%(switch)s" command-line switch.\n' ) # HTTP Server if HTTP_PORT: if isinstance(HTTP_PORT, IntType): HTTP_PORT = ((IP_ADDRESS, HTTP_PORT),) for address, port in HTTP_PORT: try: hs = zhttp_server(ip=address, port=port, resolver=rs, logger_object=lg) except socket.error as why: if why[0] == 98: # address in use raise ValueError( port_err % { "port": port, "socktype": "TCP", "protocol": "HTTP", "switch": "-w", } ) raise # Handler for a published module. zhttp_handler takes 3 arguments: # The name of the module to publish, and optionally the URI base # which is basically the SCRIPT_NAME, and optionally a dictionary # with CGI environment variables which override default # settings. The URI base setting is useful when you want to # publish more than one module with the same HTTP server. The CGI # environment setting is useful when you want to proxy requests # from another web server to ZServer, and would like the CGI # environment to reflect the CGI environment of the other web # server. try: del HTTP_ENV["HTTPS"] except KeyError: pass zh = zhttp_handler(MODULE, "", HTTP_ENV) if FORCE_HTTP_CONNECTION_CLOSE: zh._force_connection_close = 1 hs.install_handler(zh) # HTTPS Server if HTTPS_PORT: ssl_ctx = SSL.Context("sslv23") ssl_ctx.load_cert_chain("%s/server.pem" % INSTANCE_HOME) ssl_ctx.load_verify_locations("%s/ca.pem" % INSTANCE_HOME) ssl_ctx.load_client_CA("%s/ca.pem" % INSTANCE_HOME) # ssl_ctx.set_allow_unknown_ca(1) ssl_ctx.set_session_id_ctx(MODULE) ssl_ctx.set_tmp_dh("%s/dh1024.pem" % INSTANCE_HOME) if X509_REMOTE_USER: ssl_ctx.set_verify(SSL.verify_peer, 10) else: ssl_ctx.set_verify(SSL.verify_none, 10) if type(HTTPS_PORT) is type(0): HTTPS_PORT = ((IP_ADDRESS, HTTPS_PORT),) for address, port in HTTPS_PORT: hss = zhttps_server( ip=address, port=port, ssl_ctx=ssl_ctx, resolver=rs, logger_object=lg ) try: del HTTPS_ENV["HTTP"] except KeyError: pass HTTPS_ENV["HTTPS"] = "ON" if X509_REMOTE_USER: zsh = zhttps_handler(MODULE, "", HTTPS_ENV) else: zsh = zhttps0_handler(MODULE, "", HTTPS_ENV) hss.install_handler(zsh) # WebDAV source Server (runs HTTP, but munges request to return # 'manage_FTPget'). if WEBDAV_SOURCE_PORT: if isinstance(WEBDAV_SOURCE_PORT, IntType): WEBDAV_SOURCE_PORT = ((IP_ADDRESS, WEBDAV_SOURCE_PORT),) for address, port in WEBDAV_SOURCE_PORT: try: hs = zhttp_server(ip=address, port=port, resolver=rs, logger_object=lg) except socket.error as why: if why[0] == 98: # address in use raise ValueError( port_err % { "port": port, "socktype": "TCP", "protocol": "WebDAV source", "switch": "-W", } ) raise # Handler for a published module. zhttp_handler takes 3 arguments: # The name of the module to publish, and optionally the URI base # which is basically the SCRIPT_NAME, and optionally a dictionary # with CGI environment variables which override default # settings. The URI base setting is useful when you want to # publish more than one module with the same HTTP server. The CGI # environment setting is useful when you want to proxy requests # from another web server to ZServer, and would like the CGI # environment to reflect the CGI environment of the other web # server. zh = WebDAVSrcHandler(MODULE, "", HTTP_ENV) hs.install_handler(zh) # enable document retrieval of the document source on the # standard HTTP port clients = os.environ.get("WEBDAV_SOURCE_PORT_CLIENTS") if clients: import re sys.WEBDAV_SOURCE_PORT_CLIENTS = re.compile(clients).search else: sys.WEBDAV_SOURCE_PORT_CLIENTS = None # WebDAV-over-SSL source Server (runs HTTPS, but munges request to return # 'manage_FTPget'). if WEBDAV_SSL_SOURCE_PORT: ssl_ctx = SSL.Context("sslv23") ssl_ctx.load_cert_chain("%s/server.pem" % INSTANCE_HOME) ssl_ctx.load_verify_locations("%s/ca.pem" % INSTANCE_HOME) ssl_ctx.load_client_CA("%s/ca.pem" % INSTANCE_HOME) ssl_ctx.set_verify(SSL.verify_none, 10) ssl_ctx.set_session_id_ctx(MODULE) ssl_ctx.set_tmp_dh("%s/dh1024.pem" % INSTANCE_HOME) if type(WEBDAV_SSL_SOURCE_PORT) is type(0): WEBDAV_SSL_SOURCE_PORT = ((IP_ADDRESS, WEBDAV_SSL_SOURCE_PORT),) for address, port in WEBDAV_SSL_SOURCE_PORT: hss = zhttps_server( ip=address, port=port, ssl_ctx=ssl_ctx, resolver=rs, logger_object=lg ) try: del HTTPS_ENV["HTTP"] except KeyError: pass HTTPS_ENV["HTTPS"] = "ON" zsh = WebDAVSrcHandler(MODULE, "", HTTPS_ENV) hss.install_handler(zsh) # FTP Server if FTP_PORT: if isinstance(FTP_PORT, IntType): FTP_PORT = ((IP_ADDRESS, FTP_PORT),) for address, port in FTP_PORT: try: FTPServer( module=MODULE, ip=address, port=port, resolver=rs, logger_object=lg ) except socket.error as why: if why[0] == 98: # address in use raise ValueError( port_err % { "port": port, "socktype": "TCP", "protocol": "FTP", "switch": "-f", } ) raise # PCGI Server if PCGI_FILE and not READ_ONLY: PCGI_FILE = os.path.join(here, PCGI_FILE) if os.path.exists(PCGI_FILE): zpcgi = PCGIServer( module=MODULE, ip=IP_ADDRESS, pcgi_file=PCGI_FILE, resolver=rs, logger_object=lg, ) # FastCGI Server if FCGI_PORT and not READ_ONLY: fcgiPort = None fcgiPath = None try: fcgiPort = int(FCGI_PORT) except ValueError: fcgiPath = FCGI_PORT try: zfcgi = FCGIServer( module=MODULE, ip=IP_ADDRESS, port=fcgiPort, socket_file=fcgiPath, resolver=rs, logger_object=lg, ) except socket.error as why: if why[0] == 98: # address in use raise ValueError( port_err % { "port": fcgiPort, "socktype": "TCP", "protocol": "FastCGI", "switch": "-F", } ) raise # Monitor Server if MONITOR_PORT: from AccessControl.User import emergency_user if not hasattr(emergency_user, "__null_user__"): pw = emergency_user._getPassword() else: pw = None zLOG.LOG( "z2", zLOG.WARNING, "Monitor server not started" " because no emergency user exists.", ) if pw: if isinstance(MONITOR_PORT, IntType): MONITOR_PORT = ((IP_ADDRESS, MONITOR_PORT),) for address, port in MONITOR_PORT: try: monitor = secure_monitor_server( password=pw, hostname=address, port=port ) except socket.error as why: if why[0] == 98: # address in use raise ValueError( port_err % { "port": port, "socktype": "TCP", "protocol": "monitor server", "switch": "-m", } ) raise if ICP_PORT: if isinstance(ICP_PORT, IntType): ICP_PORT = ((IP_ADDRESS, ICP_PORT),) from ZServer.ICPServer import ICPServer for address, port in ICP_PORT: try: ICPServer(address, port) except socket.error as why: if why[0] == 98: # address in use raise ValueError( port_err % { "port": port, "socktype": "UDP", "protocol": "ICP", "switch": "--icp", } ) raise if not USE_DAEMON and not READ_ONLY: if os.path.exists(PID_FILE): os.unlink(PID_FILE) pf = open(PID_FILE, "w") pid = "%s\n" % os.getpid() pf.write(pid) pf.close() # Warn if we were started as nobody. try: import pwd if os.getuid(): if pwd.getpwuid(os.getuid())[0] == "nobody": _warn_nobody() except: pass # Drop root privileges if we have them, and do some sanity checking # to make sure we're not starting with an obviously insecure setup. try: if os.getuid() == 0: try: import initgroups except: raise SystemExit("initgroups is required to safely setuid") if UID == None: raise SystemExit( "A user was not specified to setuid " "to; fix this to start as root (see " "doc/SETUID.txt)" ) import stat client_home_stat = os.stat(CLIENT_HOME) client_home_faults = [] if not (client_home_stat[stat.ST_MODE] & 0o1000): client_home_faults.append("does not have the sticky bit set") if client_home_stat[stat.ST_UID] != 0: client_home_faults.append("is not owned by root") if client_home_faults: client_home_faults.append( "fix this to start as root (see " "doc/SETUID.txt)" ) err = "%s %s" % (CLIENT_HOME, ", ".join(client_home_faults)) raise SystemExit(err) try: try: UID = string.atoi(UID) except: pass gid = None if isinstance(UID, StringType): uid = pwd.getpwnam(UID)[2] gid = pwd.getpwnam(UID)[3] elif isinstance(UID, IntType): uid = pwd.getpwuid(UID)[2] gid = pwd.getpwuid(UID)[3] UID = pwd.getpwuid(UID)[0] else: raise ValueError(KeyError) if UID == "nobody": _warn_nobody() try: initgroups.initgroups(UID, gid) if gid is not None: try: os.setgid(gid) except OSError: pass os.setuid(uid) except OSError: pass except KeyError: zLOG.LOG("z2", zLOG.ERROR, ("Can't find UID %s" % UID)) except AttributeError: pass except: raise # Check umask sanity if we're on posix. if os.name == "posix" and not os.environ.get("Z_DEBUG_MODE"): # umask is silly, blame POSIX. We have to set it to get its value. current_umask = os.umask(0) os.umask(current_umask) if current_umask != 0o77: current_umask = "%03o" % current_umask zLOG.LOG( "z2", zLOG.INFO, ( "Your umask of %s may be too permissive; for the security of " "your Zope data, it is recommended you use 077" % current_umask ), ) except: # Log startup exception and tell zdaemon not to restart us. try: zLOG.LOG("z2", zLOG.PANIC, "Startup exception", error=sys.exc_info()) except: pass sys.exit(0) # Start Medusa, Ye Hass! Rand.load_file("%s/randpool.dat" % INSTANCE_HOME, -1) sys.ZServerExitCode = 0 asyncore.loop() Rand.save_file("%s/randpool.dat" % INSTANCE_HOME) sys.exit(sys.ZServerExitCode) m2crypto-0.46.2/demo/Zope/z2s.py.diff000066400000000000000000000221701506746742300172420ustar00rootroot00000000000000--- z2s.py Sun Oct 26 17:51:00 2003 +++ /usr/local/home/ngps/pkg/zope261/z2.py Thu Jan 30 22:41:42 2003 @@ -105,21 +105,9 @@ Multiple -w options can be provided to run multiple servers. - -y port - - The SSL Web server (HTTPS) port. This defaults to %(HTTPS_PORT)s. The - standard port for HTTPS services is 443. If this is a dash - (e.g. -y -), then HTTPS is disabled. - - The number can be preeceeded by an ip address follwed by a colon - to specify an address to listen on. This allows different servers - to listen on different addresses. - - Multiple -y options can be provided to run multiple servers. - -W port - The "WebDAV source" port. If this is a dash (e.g. -W -), then + The "WebDAV source" port. If this is a dash (e.g. -w -), then "WebDAV source" is disabled. The default is disabled. Note that this feature is a workaround for the lack of "source-link" support in standard WebDAV clients. @@ -130,24 +118,6 @@ Multiple -W options can be provided to run multiple servers. - -Y port - - The "WebDAV source over HTTPS" port. If this is a dash (e.g. -Y -), then - "WebDAV source over HTTPS" is disabled. The default is disabled. Note that - this feature is a workaround for the lack of "source-link" support - in standard WebDAV clients. - - The port can be preeceeded by an ip address follwed by a colon - to specify an address to listen on. This allows different servers - to listen on different addresses. - - Multiple -Y options can be provided to run multiple servers. - - -x - - If present, this option causes Zope to run in X.509 certificate-based - authentication mode. - -C --force-http-connection-close @@ -316,15 +286,9 @@ # Port for HTTP Server. The standard port for HTTP services is 80. HTTP_PORT=8080 -# Port for HTTPS Server. The standard port for HTTPS services is 443. -HTTPS_PORT=8443 - # HTTP enivornment settings. HTTP_ENV={} -# HTTPS enivornment settings. -HTTPS_ENV={} - # Should we close all HTTP connections, ignoring the (usually absent) # 'Connection:' header? FORCE_HTTP_CONNECTION_CLOSE=0 @@ -333,13 +297,6 @@ # standard port for this handler, which is disabled by default. WEBDAV_SOURCE_PORT=[] -# Port for the special "WebDAV source view over SSL" HTTP handler. There is no -# standard port for this handler, which is disabled by default. -WEBDAV_SSL_SOURCE_PORT=[] - -# Should we use client X.509 certificate-based authentication? -X509_REMOTE_USER=None - ## FTP configuration # Port for the FTP Server. The standard port for FTP services is 21. @@ -429,7 +386,7 @@ opts, args = getopt.getopt(sys.argv[1:], - 'hz:Z:t:i:a:d:u:w:W:y:Y:x:f:p:m:Sl:2DP:rF:L:XM:C', + 'hz:Z:t:i:a:d:u:w:W:f:p:m:Sl:2DP:rF:L:XM:C', ['icp=', 'force-http-connection-close' ]) @@ -486,19 +443,10 @@ MONITOR_PORT=server_info(MONITOR_PORT, v) elif o=='-w': HTTP_PORT=server_info(HTTP_PORT, v) - elif o=='-y': - HTTPS_PORT=server_info(HTTPS_PORT, v) elif o=='-C' or o=='--force-http-connection-close': FORCE_HTTP_CONNECTION_CLOSE=1 elif o=='-W': WEBDAV_SOURCE_PORT=server_info(WEBDAV_SOURCE_PORT, v) - elif o=='-Y': - WEBDAV_SSL_SOURCE_PORT=server_info(WEBDAV_SSL_SOURCE_PORT, v) - elif o=='-x': - if v in ('-', '0', ''): - X509_REMOTE_USER=None - else: - X509_REMOTE_USER=1 elif o=='-f': FTP_PORT=server_info(FTP_PORT, v) elif o=='-P': @@ -653,60 +601,14 @@ from ZServer import resolver, logger, asyncore from ZServer import zhttp_server, zhttp_handler - from ZServer import zhttps_server, zhttps0_handler, zhttps_handler from ZServer.WebDAVSrcHandler import WebDAVSrcHandler from ZServer import PCGIServer,FTPServer,FCGIServer from ZServer import secure_monitor_server - from M2Crypto import SSL, Rand - ## ZServer startup ## - ## In X509_REMOTE_USER mode, we log the client cert's subject DN. - if X509_REMOTE_USER: - - import base64, string, time - - def log (self, bytes): - user_agent=self.get_header('user-agent') - if not user_agent: user_agent='' - referer=self.get_header('referer') - if not referer: referer='' - - get_peer_cert = getattr(self.channel, 'get_peer_cert', None) - if get_peer_cert is not None: - name = str(get_peer_cert().get_subject()) - else: - name = 'Anonymous' - auth=self.get_header('Authorization') - if auth is not None: - if string.lower(auth[:6]) == 'basic ': - try: decoded=base64.decodestring(auth[6:]) - except base64.binascii.Error: decoded='' - t = string.split(decoded, ':', 1) - if len(t) < 2: - name = 'Unknown (bad auth string)' - else: - name = t[0] - - self.channel.server.logger.log ( - self.channel.addr[0], - ' - %s [%s] "%s" %d %d "%s" "%s"\n' % ( - name, - self.log_date_string (time.time()), - self.request, - self.reply_code, - bytes, - referer, - user_agent - ) - ) - - from ZServer.medusa import http_server - http_server.http_request.log = log - # Resolver and Logger, used by other servers if DNS_IP: rs = resolver.caching_resolver(DNS_IP) @@ -766,51 +668,11 @@ # from another web server to ZServer, and would like the CGI # environment to reflect the CGI environment of the other web # server. - try: - del HTTP_ENV['HTTPS'] - except KeyError: - pass zh = zhttp_handler(MODULE, '', HTTP_ENV) if FORCE_HTTP_CONNECTION_CLOSE: zh._force_connection_close = 1 hs.install_handler(zh) - # HTTPS Server - if HTTPS_PORT: - ssl_ctx = SSL.Context('sslv23') - ssl_ctx.load_cert_chain('%s/server.pem' % INSTANCE_HOME) - ssl_ctx.load_verify_locations('%s/ca.pem' % INSTANCE_HOME) - ssl_ctx.load_client_CA('%s/ca.pem' % INSTANCE_HOME) - #ssl_ctx.set_allow_unknown_ca(1) - ssl_ctx.set_session_id_ctx(MODULE) - ssl_ctx.set_tmp_dh('%s/dh1024.pem' % INSTANCE_HOME) - if X509_REMOTE_USER: - ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_fail_if_no_peer_cert, 10) - #ssl_ctx.set_verify(SSL.verify_peer, 10) - else: - ssl_ctx.set_verify(SSL.verify_none, 10) - if type(HTTPS_PORT) is type(0): HTTPS_PORT=((IP_ADDRESS, HTTPS_PORT),) - - for address, port in HTTPS_PORT: - hss = zhttps_server( - ip=address, - port=port, - ssl_ctx=ssl_ctx, - resolver=rs, - logger_object=lg) - - try: - del HTTPS_ENV['HTTP'] - except KeyError: - pass - HTTPS_ENV['HTTPS']='ON' - - if X509_REMOTE_USER: - zsh = zhttps_handler(MODULE, '', HTTPS_ENV) - else: - zsh = zhttps0_handler(MODULE, '', HTTPS_ENV) - hss.install_handler(zsh) - # WebDAV source Server (runs HTTP, but munges request to return # 'manage_FTPget'). if WEBDAV_SOURCE_PORT: @@ -854,34 +716,6 @@ else: sys.WEBDAV_SOURCE_PORT_CLIENTS = None - # WebDAV-over-SSL source Server (runs HTTPS, but munges request to return - # 'manage_FTPget'). - if WEBDAV_SSL_SOURCE_PORT: - ssl_ctx = SSL.Context('sslv23') - ssl_ctx.load_cert_chain('%s/server.pem' % INSTANCE_HOME) - ssl_ctx.load_verify_locations('%s/ca.pem' % INSTANCE_HOME) - ssl_ctx.load_client_CA('%s/ca.pem' % INSTANCE_HOME) - ssl_ctx.set_verify(SSL.verify_none, 10) - ssl_ctx.set_session_id_ctx(MODULE) - ssl_ctx.set_tmp_dh('%s/dh1024.pem' % INSTANCE_HOME) - if type(WEBDAV_SSL_SOURCE_PORT) is type(0): - WEBDAV_SSL_SOURCE_PORT=((IP_ADDRESS, WEBDAV_SSL_SOURCE_PORT),) - for address, port in WEBDAV_SSL_SOURCE_PORT: - hss = zhttps_server( - ip=address, - port=port, - ssl_ctx=ssl_ctx, - resolver=rs, - logger_object=lg) - - try: - del HTTPS_ENV['HTTP'] - except KeyError: - pass - HTTPS_ENV['HTTPS']='ON' - - zsh = WebDAVSrcHandler(MODULE, '', HTTPS_ENV) - hss.install_handler(zsh) # FTP Server if FTP_PORT: @@ -1072,8 +906,6 @@ sys.exit(0) # Start Medusa, Ye Hass! -Rand.load_file('%s/randpool.dat' % INSTANCE_HOME, -1) sys.ZServerExitCode=0 asyncore.loop() -Rand.save_file('%s/randpool.dat' % INSTANCE_HOME) sys.exit(sys.ZServerExitCode) m2crypto-0.46.2/demo/Zope27/000077500000000000000000000000001506746742300154125ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope27/INSTALL.txt000066400000000000000000000121371506746742300172650ustar00rootroot00000000000000========================================= ZServerSSL for Zope 2.7.0b2 ========================================= :Author: Ng Pheng Siong :Id: $Id$ :Date: $Date$ :Web-Site: http://sandbox.rulemaker.net/ngps/zope/zssl/ .. contents:: Directories ----------------------- This distribution is contained in ``m2crypto-0.12/demo/Zope27/``. Its directory structure assumes the following: - Zope 2.7.0b2 is installed in . - An instance has been created in . ----------------------- The following files are to be copied to the corresponding directories in your : - install_dir/lib/python/ZServer/HTTPS_Server.py - install_dir/lib/python/ZServer/medusa/https_server.py The following patch files are to be applied to the corresponding directories in your : - install_dir/lib/python/ZServer/__init__.py.patch - install_dir/lib/python/ZServer/component.xml.patch - install_dir/lib/python/ZServer/datatypes.py.patch ----------------------- The following files are to be copied to the corresponding directories in your : - instance_home/ssl/ca.pem - instance_home/ssl/server.pem - instance_home/ssl/dh1024.pem These are example files. For more information on them, consult the ZServerSSL HOWTO for Zope 2.6. The following patch files are to be applied to the corresponding directories in your : - instance_home/README.txt.patch - instance_home/etc/zope.conf.patch (Patching README.txt is optional.) There appears to be a bug in Zope 2.7.0b2, where INSTANCE_HOME in a running Zope points to , not . Workaround this with the following: :: $ (cd ; ln -s /ssl) Launch ZServerSSL ------------------- :: $ /bin/runzope Testing --------- Below, we assume your Zope server is running on ``localhost``. HTTPS ~~~~~~~ This testing is done with Mozilla 1.1 on FreeBSD. 1. With a browser, connect to https://localhost:8443/. Browse around. Check out your browser's HTTPS informational screens. 2. Connect to https://localhost:8443/manage. Verify that you can access Zope's management functionality. WebDAV-over-HTTPS ~~~~~~~~~~~~~~~~~~~ This testing is done with Cadaver 0.21.0 on FreeBSD. :: $ cadaver https://localhost:8443/ WARNING: Untrusted server certificate presented: Issued to: M2Crypto, SG Issued by: M2Crypto, SG Do you wish to accept the certificate? (y/n) y Authentication required for Zope on server `localhost': Username: admin Password: dav:/> ls Listing collection `/': succeeded. Coll: Control_Panel 0 Sep 28 00:38 Coll: temp_folder 0 Sep 28 17:30 acl_users 0 Sep 28 00:38 browser_id_manager 0 Sep 28 00:38 error_log 0 Sep 28 00:38 index_html 28 Sep 28 00:39 session_data_manager 0 Sep 28 00:38 standard_error_message 1189 Sep 28 00:39 standard_html_footer 18 Sep 28 00:39 standard_html_header 82 Sep 28 00:39 standard_template.pt 282 Sep 28 00:39 dav:/> quit Connection to `localhost' closed. $ Python with M2Crypto ~~~~~~~~~~~~~~~~~~~~~~ This testing is done with M2Crypto 0.12 and Python 2.2.3 on FreeBSD. HTTPS ``````` >>> from M2Crypto import Rand, SSL, m2urllib >>> url = m2urllib.FancyURLopener() >>> url.addheader('Connection', 'close') >>> u = url.open('https://127.0.0.1:8443/') send: 'GET / HTTP/1.1\r\nHost: 127.0.0.1:8443\r\nAccept-Encoding: identity\r\nUser-agent: Python-urllib/1.15\r\nConnection: close\r\n\r\n' reply: 'HTTP/1.1 200 OK\r\n' header: Server: ZServerSSL/0.12 header: Date: Sun, 28 Sep 2003 09:40:14 GMT header: Content-Length: 3055 header: Etag: header: Content-Type: text/html header: Connection: close >>> while 1: ... data = u.read() ... if not data: break ... print(data) ... :: [blah blah blah]

Go directly to the Zope Management Interface if you'd like to start working with Zope right away. NOTE: Some versions of Microsoft Internet Explorer, (specifically IE 5.01 and early versions of IE 5.5) may have problems displaying Zope management pages. If you cannot view the management pages, try upgrading your IE installation to the latest release version, or use a different browser.

  • Find out about Zope Corporation, the publishers of Zope.

  • >>> u.close() >>> XMLRPC-over-HTTPS ``````````````````` >>> from M2Crypto.m2xmlrpclib import Server, SSL_Transport >>> zs = Server('https://127.0.0.1:8443/', SSL_Transport()) >>> print(zs.propertyMap()) [{'type': 'string', 'id': 'title', 'mode': 'w'}] >>> Conclusion ------------ Yes, it works! ;-) m2crypto-0.46.2/demo/Zope27/install_dir/000077500000000000000000000000001506746742300177165ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope27/install_dir/lib/000077500000000000000000000000001506746742300204645ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope27/install_dir/lib/python/000077500000000000000000000000001506746742300220055ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope27/install_dir/lib/python/ZServer/000077500000000000000000000000001506746742300234055ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope27/install_dir/lib/python/ZServer/HTTPS_Server.py000066400000000000000000000142511506746742300262120ustar00rootroot00000000000000############################################################################## # # Copyright (c) 2000-2003, Ng Pheng Siong. All Rights Reserved. # This file is derived from Zope's ZServer/HTTPServer.py. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """ Medusa HTTPS server for Zope changes from Medusa's http_server: Request Threads -- Requests are processed by threads from a thread pool. Output Handling -- Output is pushed directly into the producer fifo by the request-handling thread. The HTTP server does not do any post-processing such as chunking. Pipelineable -- This is needed for protocols such as HTTP/1.1 in which mutiple requests come in on the same channel, before responses are sent back. When requests are pipelined, the client doesn't wait for the response before sending another request. The server must ensure that responses are sent back in the same order as requests are received. changes from Zope's HTTP server: Well, this is a *HTTPS* server :) X.509 certificate-based authentication -- When this is in force, zhttps_handler, a subclass of zhttp_handler, is installed. The https server is configured to request an X.509 certificate from the client. When the request reaches zhttps_handler, it sets REMOTE_USER to the client's subject distinguished name (DN) from the certificate. Zope's REMOTE_USER machinery takes care of the rest, e.g., in conjunction with the RemoteUserFolder product. """ import sys, time, types from PubCore import handle import asyncore from ZServer import CONNECTION_LIMIT, ZOPE_VERSION from HTTPServer import zhttp_handler from zLOG import register_subsystem from M2Crypto import SSL from medusa.https_server import https_server, https_channel from asyncore import dispatcher ZSERVER_SSL_VERSION = "0.12" register_subsystem("ZServer HTTPS_Server") class zhttps0_handler(zhttp_handler): "zhttps0 handler - sets SSL request headers a la mod_ssl" def __init__(self, module, uri_base=None, env=None): zhttp_handler.__init__(self, module, uri_base, env) def get_environment(self, request): env = zhttp_handler.get_environment(self, request) env["SSL_CIPHER"] = request.channel.get_cipher() return env class zhttps_handler(zhttps0_handler): "zhttps handler - sets REMOTE_USER to user's X.509 certificate Subject DN" def __init__(self, module, uri_base=None, env=None): zhttps0_handler.__init__(self, module, uri_base, env) def get_environment(self, request): env = zhttps0_handler.get_environment(self, request) peer = request.channel.get_peer_cert() if peer is not None: env["REMOTE_USER"] = str(peer.get_subject()) return env class zhttps_channel(https_channel): "https channel" closed = 0 zombie_timeout = 100 * 60 # 100 minutes def __init__(self, server, conn, addr): https_channel.__init__(self, server, conn, addr) self.queue = [] self.working = 0 self.peer_found = 0 def push(self, producer, send=1): # this is thread-safe when send is false # note, that strings are not wrapped in # producers by default if self.closed: return self.producer_fifo.push(producer) if send: self.initiate_send() push_with_producer = push def work(self): "try to handle a request" if not self.working: if self.queue: self.working = 1 try: module_name, request, response = self.queue.pop(0) except: return handle(module_name, request, response) def close(self): self.closed = 1 while self.queue: self.queue.pop() if self.current_request is not None: self.current_request.channel = None # break circ refs self.current_request = None while self.producer_fifo: p = self.producer_fifo.first() if p is not None and type(p) != types.StringType: p.more() # free up resources held by producer self.producer_fifo.pop() self.del_channel() # self.socket.set_shutdown(SSL.SSL_SENT_SHUTDOWN|SSL.SSL_RECEIVED_SHUTDOWN) self.socket.close() def done(self): "Called when a publishing request is finished" self.working = 0 self.work() def kill_zombies(self): now = int(time.time()) for channel in asyncore.socket_map.values(): if channel.__class__ == self.__class__: if (now - channel.creation_time) > channel.zombie_timeout: channel.close() class zhttps_server(https_server): "https server" SERVER_IDENT = "ZServerSSL/%s" % (ZSERVER_SSL_VERSION,) channel_class = zhttps_channel shutup = 0 def __init__(self, ip, port, ssl_ctx, resolver=None, logger_object=None): self.shutup = 1 https_server.__init__(self, ip, port, ssl_ctx, resolver, logger_object) self.ssl_ctx = ssl_ctx self.shutup = 0 self.log_info( "(%s) HTTPS server started at %s\n" "\tHostname: %s\n\tPort: %d" % ( self.SERVER_IDENT, time.ctime(time.time()), self.server_name, self.server_port, ) ) def log_info(self, message, type="info"): if self.shutup: return dispatcher.log_info(self, message, type) def readable(self): return self.accepting and len(asyncore.socket_map) < CONNECTION_LIMIT def listen(self, num): # override asyncore limits for nt's listen queue size self.accepting = 1 return self.socket.listen(num) m2crypto-0.46.2/demo/Zope27/install_dir/lib/python/ZServer/__init__.py.patch000066400000000000000000000006021506746742300266120ustar00rootroot00000000000000--- __init__.py.org Sat Sep 27 20:23:00 2003 +++ __init__.py Sun Oct 26 18:01:27 2003 @@ -68,6 +68,7 @@ import asyncore from medusa import resolver, logger from HTTPServer import zhttp_server, zhttp_handler +from HTTPS_Server import zhttps_server, zhttps0_handler, zhttps_handler from PCGIServer import PCGIServer from FCGIServer import FCGIServer from FTPServer import FTPServer m2crypto-0.46.2/demo/Zope27/install_dir/lib/python/ZServer/component.xml.patch000066400000000000000000000020141506746742300272240ustar00rootroot00000000000000--- component.xml.org Sat Sep 27 20:21:22 2003 +++ component.xml Sat Sep 27 21:11:26 2003 @@ -21,6 +21,25 @@ + + + + + + Regular expression used to identify clients who should + receive WebDAV source responses to GET requests. + + + + + If "on", request client X.509 certificate and set REMOTE_USER to + said certificate's Subject Distinguished Name. + + + + m2crypto-0.46.2/demo/Zope27/install_dir/lib/python/ZServer/datatypes.py.patch000066400000000000000000000045021506746742300270540ustar00rootroot00000000000000--- datatypes.py.org Sat Sep 27 20:21:15 2003 +++ datatypes.py Sun Oct 26 21:19:58 2003 @@ -72,7 +72,56 @@ def createHandler(self): from ZServer import HTTPServer + try: + del self.cgienv['HTTPS'] + except KeyError: + pass return HTTPServer.zhttp_handler(self.module, '', self.cgienv) + + +class HTTPS_ServerFactory(HTTPServerFactory): + def __init__(self, section): + HTTPServerFactory.__init__(self, section) + self.x509_remote_user = section.x509_remote_user + from M2Crypto import Rand, SSL + Rand.load_file('%s/randpool.dat' % INSTANCE_HOME, -1) + ssl_ctx = SSL.Context('sslv23') + ssl_ctx.load_cert_chain('%s/ssl/server.pem' % INSTANCE_HOME) + ssl_ctx.load_verify_locations('%s/ssl/ca.pem' % INSTANCE_HOME,'') + ssl_ctx.load_client_CA('%s/ssl/ca.pem' % INSTANCE_HOME) + ssl_ctx.set_session_id_ctx('Zope 2.7.0b2') + ssl_ctx.set_tmp_dh('%s/ssl/dh1024.pem' % INSTANCE_HOME) + if self.x509_remote_user: + ssl_ctx.set_verify(SSL.verify_peer, 10) + else: + ssl_ctx.set_verify(SSL.verify_none, 10) + self.ssl_ctx = ssl_ctx + + def create(self): + from ZServer import HTTPS_Server + from ZServer.AccessLogger import access_logger + handler = self.createHandler() + handler._force_connection_close = self.force_connection_close + if self.webdav_source_clients: + handler.set_webdav_source_clients(self.webdav_source_clients) + server = HTTPS_Server.zhttps_server(ip=self.host, port=self.port, + ssl_ctx=self.ssl_ctx, + resolver=self.dnsresolver, + logger_object=access_logger) + server.install_handler(handler) + return server + + def createHandler(self): + from ZServer import HTTPS_Server + try: + del self.cgienv['HTTP'] + except KeyError: + pass + self.cgienv['HTTPS'] = 'ON' + if self.x509_remote_user: + return HTTPS_Server.zhttps_handler(self.module, '', self.cgienv) + else: + return HTTPS_Server.zhttps0_handler(self.module, '', self.cgienv) class WebDAVSourceServerFactory(HTTPServerFactory): m2crypto-0.46.2/demo/Zope27/install_dir/lib/python/ZServer/medusa/000077500000000000000000000000001506746742300246635ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope27/install_dir/lib/python/ZServer/medusa/https_server.py000066400000000000000000000050411506746742300277650ustar00rootroot00000000000000#!/usr/bin/env python """A https server built on Medusa's http_server. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" import asynchat, asyncore, http_server, socket, sys from M2Crypto import SSL, version VERSION_STRING = version class https_channel(http_server.http_channel): ac_in_buffer_size = 1 << 16 def __init__(self, server, conn, addr): http_server.http_channel.__init__(self, server, conn, addr) def send(self, data): try: result = self.socket._write_nbio(data) if result <= 0: return 0 else: self.server.bytes_out.increment(result) return result except SSL.SSLError as why: self.close() self.log_info("send: closing channel %s %s" % (repr(self), why)) return 0 def recv(self, buffer_size): try: result = self.socket._read_nbio(buffer_size) if result is None: return "" elif result == "": self.close() return "" else: self.server.bytes_in.increment(len(result)) return result except SSL.SSLError as why: self.close() self.log_info("recv: closing channel %s %s" % (repr(self), why)) return "" class https_server(http_server.http_server): SERVER_IDENT = "M2Crypto HTTPS Server (v%s)" % VERSION_STRING channel_class = https_channel def __init__(self, ip, port, ssl_ctx, resolver=None, logger_object=None): http_server.http_server.__init__(self, ip, port, resolver, logger_object) self.ssl_ctx = ssl_ctx def handle_accept(self): # Cribbed from http_server. self.total_clients.increment() try: conn, addr = self.accept() except socket.error: # linux: on rare occasions we get a bogus socket back from # accept. socketmodule.c:makesockaddr complains that the # address family is unknown. We don't want the whole server # to shut down because of this. sys.stderr.write("warning: server accept() threw an exception\n") return # Turn the vanilla socket into an SSL connection. try: ssl_conn = SSL.Connection(self.ssl_ctx, conn) ssl_conn._setup_ssl(addr) ssl_conn.accept_ssl() self.channel_class(self, ssl_conn, addr) except SSL.SSLError: pass def writeable(self): return 0 m2crypto-0.46.2/demo/Zope27/instance_home/000077500000000000000000000000001506746742300202265ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope27/instance_home/README.txt.patch000066400000000000000000000004421506746742300230220ustar00rootroot00000000000000--- README.txt.org Sat Sep 27 20:56:11 2003 +++ README.txt Sat Sep 27 20:56:44 2003 @@ -7,3 +7,4 @@ log/ Log files Products/ Installed products specific to the instance var/ Run-time data files, including the object database + ssl/ ZServerSSL data files m2crypto-0.46.2/demo/Zope27/instance_home/etc/000077500000000000000000000000001506746742300210015ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope27/instance_home/etc/zope.conf.patch000066400000000000000000000006121506746742300237220ustar00rootroot00000000000000--- zope.conf.org Sat Sep 27 21:03:22 2003 +++ zope.conf Sat Sep 27 21:05:08 2003 @@ -650,6 +650,13 @@ # force-connection-close on + + # valid keys are "address", "force-connection-close" and "x509-remote-user" + address 8443 + # force-connection-close on + x509-remote-user on + + # valid key is "address" address 8021 m2crypto-0.46.2/demo/Zope27/instance_home/ssl/000077500000000000000000000000001506746742300210275ustar00rootroot00000000000000m2crypto-0.46.2/demo/Zope27/instance_home/ssl/ca.pem000066400000000000000000000023041506746742300221140ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDWTCCAsKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAxMTIxNTA1NTU0NloXDTA0MTIxNDA1NTU0 NlowgYAxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxML TTJDcnlwdG8gQ0ExJDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3Rl cjEiMCAGCSqGSIb3DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbTCBnzANBgkqhkiG 9w0BAQEFAAOBjQAwgYkCgYEAx8soJbS719LHK62VVVIQeC3oW0HvFArwPnA0LuEK q+LaqMOJg1rS7hvFdX03diV+XJw7cC0iECZYJNG4ii1xbY6KRmufkInaAwm54E3N e+YYVocaqUkcN6xVf6fwnLfPXbpFS/K2Umg11ObKMmi80JmiIdjcjRRCQZC7g1hf q+kCAwEAAaOB4DCB3TAdBgNVHQ4EFgQU6/qcBzEtQphfXLhiOHbt2KqBwMIwga0G A1UdIwSBpTCBooAU6/qcBzEtQphfXLhiOHbt2KqBwMKhgYakgYMwgYAxCzAJBgNV BAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0Ex JDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEiMCAGCSqGSIb3 DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqG SIb3DQEBBAUAA4GBAD+I14GuS5vJmyv1k7mUMbAicsWRHZ+zrGOq9L/L2LsA+lKQ dAzEZE2+Zv8LBPJVltbJJhcFNJS/ZMAjEm4xlJuCpvXVMxd/M5AM29aqekWlIK7J vsdDL8IuzpRkMniUiNKPhmB6IPIOslvUKx6QofcE0wDh6pg4VvIbCjkpZ7gf -----END CERTIFICATE----- m2crypto-0.46.2/demo/Zope27/instance_home/ssl/dh1024.pem000066400000000000000000000003651506746742300224400ustar00rootroot00000000000000-----BEGIN DH PARAMETERS----- MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq /Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx /mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC -----END DH PARAMETERS----- m2crypto-0.46.2/demo/Zope27/instance_home/ssl/server.pem000066400000000000000000000041101506746742300230340ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDYjCCAsugAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAzMDYyMjEzMzAxNFoXDTA0MDYyMTEzMzAx NFowXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwls b2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5leGFtcGxlLmRv bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA37aKGZtFicl8xXXTLJ8/JD7c kd3t/teCX9i61lpaDQCKBoVrrursIvZihemMKI9g/u/+BLqt5g8mBdgUdYz0txc8 KEbV2hj+wwOX4H3XwD0Y+DysXiNHq7/tFdmzSVHoLxpY4zYzXbxQ/p049wvIyPRp /y3omcnx/TEUhkn+JmkCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4 QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTB H/mUYlww24mJlSxEtGdlwojO9zCBrQYDVR0jBIGlMIGigBTr+pwHMS1CmF9cuGI4 du3YqoHAwqGBhqSBgzCBgDELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv MRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8gQ2VydGlm aWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNuZ3BzQG5ldG1lbWV0aWMuY29t ggEAMA0GCSqGSIb3DQEBBAUAA4GBAAvl6v0s3eFeGP4iAcrfysuK7jzFKhjDYuOy lVS3u33bZNLnMpM6OSEM9yPh4WpFCVHf+nYwC71pk4ilsLVXjKxymm2lNGcxLVuW iydFz4Ly9nmN7Ja9ygYT39dGAFP/wN7ELTpsbul8VfmqhNg9y81d8i/A1tK3AGA8 0QkPQNdP -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDftooZm0WJyXzFddMsnz8kPtyR3e3+14Jf2LrWWloNAIoGhWuu 6uwi9mKF6Ywoj2D+7/4Euq3mDyYF2BR1jPS3FzwoRtXaGP7DA5fgfdfAPRj4PKxe I0erv+0V2bNJUegvGljjNjNdvFD+nTj3C8jI9Gn/LeiZyfH9MRSGSf4maQIDAQAB AoGAHpeVtv62uarl9xKvuBBm0AwQmZnhq9HIsFaw5hMg8Vo7hbzFBvx1IirTOkC/ u+QvfW1QLVFh6m3z4ySzV4fZBtcd6F9SbSrZ0xsxIUB2NOSa1RGgiaP61bJnMMM1 xM3O9iwM5GZc3Gqy08QOCpDl0772VJ+9Gz3FA88mrc6rHQkCQQDz6RIatFjT28n8 1vy0nHwwZz2oXTpe/pyZPwoKj8zVsmrKhKwOw7l8ArxjP8zoHOE7AQBCXYDMNoFp IAF0yuqrAkEA6s0wMEdPpQeb0XHAfccyJQoeULxHdVFoz1wWmGSOm4YmQtR8/QJx luEgfpeRkzxBKt5Ls3MEkheIOw7xV24zOwJAMz+DaE0AZPNHS3K4ghJnHZxzng6I lzEUIjbWm0V/ml70hTy/EhMZw+6nOotLOHHo+QbK0SboSwAgzL/Gzo1cJQJANqpS 38qadleRJXAQWrg3qnvyluVe1aeAeVZ9RDmVIgxXeBO0jcs12uTLBe4PzHGo0mwy v7K1i7XC180gzzQu5QJBAOxITT9RoWSSozPvnirHd37sn+RsrNYkV07NAa80M20Z DkBPHeMVkNgigrQ6L6vWmbRDGQbGcMplAxnI5ppKCoU= -----END RSA PRIVATE KEY----- m2crypto-0.46.2/demo/ZopeX3/000077500000000000000000000000001506746742300154545ustar00rootroot00000000000000m2crypto-0.46.2/demo/ZopeX3/INSTALL.txt000066400000000000000000000030261506746742300173240ustar00rootroot00000000000000========================================= ZServerSSL for ZopeX3.0.0 ========================================= :Author: Ng Pheng Siong :Id: $Id$ :Date: $Date$ :Web-Site: http://sandbox.rulemaker.net/ngps/zope/zssl/ .. contents:: Directories ----------------------- Directory structure assumes the following: - ZopeX3.0.0 is installed in . - An instance has been created in . ----------------------- The following files are to be copied to the corresponding directories in your : - install_dir/lib/python/zope/server/http/https_server.py - install_dir/lib/python/zope/server/http/https_serverchannel.py - install_dir/lib/python/zope/server/http/publisherhttps_server.py - install_dir/lib/python/zope/app/server/https.py ----------------------- The following files are to be copied to the corresponding directories in your : - instance_home/ssl/ca.pem - instance_home/ssl/server.pem - instance_home/ssl/dh1024.pem These are example files. For more information on them, consult the ZServerSSL HOWTO for Zope 2.6. The following patch files are to be applied to the corresponding directories: - install_dir/lib/python/zope/app/server/configure.zcml.patch - instance_home/etc/zope.conf.patch Launch ZServerSSL ------------------- :: $ /bin/runzope Testing --------- This section TDB. I have tested ZServerSSL for Zope 3 with 'openssl s_client' and 'openssl s_client -nbio' successfully. Conclusion ------------ Yes, it works! ;-) m2crypto-0.46.2/demo/ZopeX3/install_dir/000077500000000000000000000000001506746742300177605ustar00rootroot00000000000000m2crypto-0.46.2/demo/ZopeX3/install_dir/lib/000077500000000000000000000000001506746742300205265ustar00rootroot00000000000000m2crypto-0.46.2/demo/ZopeX3/install_dir/lib/python/000077500000000000000000000000001506746742300220475ustar00rootroot00000000000000m2crypto-0.46.2/demo/ZopeX3/install_dir/lib/python/zope/000077500000000000000000000000001506746742300230245ustar00rootroot00000000000000m2crypto-0.46.2/demo/ZopeX3/install_dir/lib/python/zope/app/000077500000000000000000000000001506746742300236045ustar00rootroot00000000000000m2crypto-0.46.2/demo/ZopeX3/install_dir/lib/python/zope/app/server/000077500000000000000000000000001506746742300251125ustar00rootroot00000000000000m2crypto-0.46.2/demo/ZopeX3/install_dir/lib/python/zope/app/server/configure.zcml.patch000066400000000000000000000012751506746742300310650ustar00rootroot00000000000000--- configure.zcml.org Mon Sep 27 16:10:47 2004 +++ configure.zcml Mon Sep 27 16:11:42 2004 @@ -5,6 +5,12 @@ provides="zope.app.applicationcontrol.interfaces.IServerControl" /> + + + + m2crypto-0.46.2/demo/ZopeX3/install_dir/lib/python/zope/app/server/https.py000066400000000000000000000015721506746742300266330ustar00rootroot00000000000000############################################################################## # # Copyright (c) 2004, Ng Pheng Siong. # All Rights Reserved. # # XXX license TBD; should be Zope 3's ZPL, I just haven't read thru that. # ############################################################################## """HTTPS server factories $Id$ """ from zope.app.publication.httpfactory import HTTPPublicationRequestFactory from zope.app.server.servertype import ServerType from zope.server.http.commonaccesslogger import CommonAccessLogger from zope.server.http.publisherhttps_server import PMDBHTTPS_Server from zope.server.http.publisherhttps_server import PublisherHTTPS_Server https = ServerType( PublisherHTTPS_Server, HTTPPublicationRequestFactory, CommonAccessLogger, 8443, True ) pmhttps = ServerType( PMDBHTTPS_Server, HTTPPublicationRequestFactory, CommonAccessLogger, 8376, True ) m2crypto-0.46.2/demo/ZopeX3/install_dir/lib/python/zope/server/000077500000000000000000000000001506746742300243325ustar00rootroot00000000000000m2crypto-0.46.2/demo/ZopeX3/install_dir/lib/python/zope/server/http/000077500000000000000000000000001506746742300253115ustar00rootroot00000000000000m2crypto-0.46.2/demo/ZopeX3/install_dir/lib/python/zope/server/http/https_server.py000066400000000000000000000072161506746742300304210ustar00rootroot00000000000000############################################################################## # # Copyright (c) 2004, Ng Pheng Siong. # All Rights Reserved. # # XXX license TBD; should be Zope 3's ZPL, I just haven't read thru that. # ############################################################################## from __future__ import print_function """HTTPS Server This is a HTTPS version of HTTPServer. $Id$ """ import asyncore, logging, os.path from zope.server.http.httpserver import HTTPServer from zope.server.http.https_serverchannel import HTTPS_ServerChannel from M2Crypto import SSL, version # 2004-09-27, ngps: # 'sslv2' or 'sslv23' interoperates with Firefox and IE. # 'sslv3' or 'tlsv1' doesn't. def make_ssl_context(dir, ssl_proto="sslv23"): sslctx = SSL.Context(ssl_proto) sslctx.load_cert(os.path.join(dir, "server.pem")) sslctx.load_verify_locations(os.path.join(dir, "ca.pem")) sslctx.load_client_CA(os.path.join(dir, "ca.pem")) sslctx.set_verify(SSL.verify_none, 10) sslctx.set_session_id_ctx("someblahblahthing") sslctx.set_tmp_dh(os.path.join(dir, "dh1024.pem")) # sslctx.set_info_callback() # debugging only; not thread-safe return sslctx class HTTPS_Server(HTTPServer): """This is a generic HTTPS Server.""" channel_class = HTTPS_ServerChannel SERVER_IDENT = "zope.server.zserverssl_https" def __init__( self, ip, port, ssl_ctx=None, task_dispatcher=None, adj=None, start=1, hit_log=None, verbose=0, ): HTTPServer.__init__( self, ip, port, task_dispatcher, adj, start, hit_log, verbose ) if ssl_ctx is None: self.ssl_ctx = make_ssl_context(os.path.realpath(__file__)) else: self.ssl_ctx = ssl_ctx def executeRequest(self, task): """Execute an HTTP request.""" # This is a default implementation, meant to be overridden. body = "The HTTPS server is running!\r\n" * 10 task.response_headers["Content-Type"] = "text/plain" task.response_headers["Content-Length"] = str(len(body)) task.write(body) def handle_accept(self): """See zope.server.interfaces.IDispatcherEventHandler""" try: v = self.accept() if v is None: return conn, addr = v except socket.error: # Linux: On rare occasions we get a bogus socket back from # accept. socketmodule.c:makesockaddr complains that the # address family is unknown. We don't want the whole server # to shut down because of this. if self.adj.log_socket_errors: self.log_info("warning: server accept() threw an exception", "warning") return for level, optname, value in self.adj.socket_options: conn.setsockopt(level, optname, value) # Turn the vanilla socket into an SSL connection. try: ssl_conn = SSL.Connection(self.ssl_ctx, conn) ssl_conn._setup_ssl(addr) ssl_conn.accept_ssl() self.channel_class(self, ssl_conn, addr, self.adj) except SSL.SSLError as why: self.log_info("accept: cannot make SSL connection %s" % (why,), "warning") pass if __name__ == "__main__": from zope.server.taskthreads import ThreadedTaskDispatcher td = ThreadedTaskDispatcher() td.setThreadCount(4) HTTPS_Server("", 8443, ssl_ctx=None, task_dispatcher=td, verbose=1) try: import asyncore while 1: asyncore.poll(5) except KeyboardInterrupt: print("shutting down...") td.shutdown() m2crypto-0.46.2/demo/ZopeX3/install_dir/lib/python/zope/server/http/https_serverchannel.py000066400000000000000000000032371506746742300317510ustar00rootroot00000000000000############################################################################## # # Copyright (c) 2004, Ng Pheng Siong. # All Rights Reserved. # # XXX license TBD; should be Zope 3's ZPL, I just haven't read thru that. # ############################################################################## """HTTPS Server Channel $Id$ """ from zope.server.serverchannelbase import ServerChannelBase from zope.server.http.httptask import HTTPTask from zope.server.http.httprequestparser import HTTPRequestParser from zope.server.http.httpserverchannel import HTTPServerChannel from M2Crypto import SSL class HTTPS_ServerChannel(HTTPServerChannel): """HTTPS-specific Server Channel""" task_class = HTTPTask parser_class = HTTPRequestParser def send(self, data): try: result = self.socket._write_nbio(data) if result <= 0: return 0 else: # self.server.bytes_out.increment(result) return result except SSL.SSLError as why: self.close() self.log_info("send: closing channel %s %s" % (repr(self), why), "warning") return 0 def recv(self, buffer_size): try: result = self.socket._read_nbio(buffer_size) if result is None: return "" elif result == "": self.close() return "" else: # self.server.bytes_in.increment(len(result)) return result except SSL.SSLError as why: self.close() self.log_info("recv: closing channel %s %s" % (repr(self), why), "warning") return "" m2crypto-0.46.2/demo/ZopeX3/install_dir/lib/python/zope/server/http/publisherhttps_server.py000066400000000000000000000054011506746742300323310ustar00rootroot00000000000000############################################################################## # # Copyright (c) 2004, Ng Pheng Siong. # All Rights Reserved. # # XXX license TBD; should be Zope 3's ZPL, I just haven't read thru that. # ############################################################################## from __future__ import print_function """HTTPS Server that uses the Zope Publisher for executing a task. $Id$ """ import os.path, sys from zope.server.http.https_server import HTTPS_Server, make_ssl_context from zope.publisher.publish import publish def get_instance_ssldir(): # This is real cheesy: It seems Zope3 doesn't have convenient # programmatic access to INSTANCE_HOME. This code relies on zopectl # setting the first entry of PYTHONPATH to $INSTANCE_HOME/lib/python. return os.path.join(os.path.dirname(os.path.dirname(sys.path[0])), "ssl") class PublisherHTTPS_Server(HTTPS_Server): """Zope Publisher-specific HTTPS Server""" def __init__(self, request_factory, sub_protocol=None, *args, **kw): # The common HTTP self.request_factory = request_factory # An HTTP server is not limited to serving up HTML; it can be # used for other protocols, like XML-RPC, SOAP and so as well # Here we just allow the logger to output the sub-protocol type. if sub_protocol: self.SERVER_IDENT += " (%s)" % str(sub_protocol) kw["ssl_ctx"] = make_ssl_context(get_instance_ssldir()) HTTPS_Server.__init__(self, *args, **kw) def executeRequest(self, task): """Overrides HTTPServer.executeRequest().""" env = task.getCGIEnvironment() env["HTTPS"] = "ON" try: del env["HTTP"] except KeyError: pass instream = task.request_data.getBodyStream() request = self.request_factory(instream, task, env) response = request.response response.setHeaderOutput(task) response.setHTTPTransaction(task) publish(request) class PMDBHTTPS_Server(PublisherHTTPS_Server): """Enter the post-mortem debugger when there's an error""" def executeRequest(self, task): """Overrides HTTPServer.executeRequest().""" env = task.getCGIEnvironment() env["HTTPS"] = "ON" try: del env["HTTP"] except KeyError: pass instream = task.request_data.getBodyStream() request = self.request_factory(instream, task, env) response = request.response response.setHeaderOutput(task) try: publish(request, handle_errors=False) except: import sys, pdb print("%s:" % sys.exc_info()[0]) print(sys.exc_info()[1]) pdb.post_mortem(sys.exc_info()[2]) raise m2crypto-0.46.2/demo/ZopeX3/instance_home/000077500000000000000000000000001506746742300202705ustar00rootroot00000000000000m2crypto-0.46.2/demo/ZopeX3/instance_home/etc/000077500000000000000000000000001506746742300210435ustar00rootroot00000000000000m2crypto-0.46.2/demo/ZopeX3/instance_home/etc/zope.conf.patch000066400000000000000000000011021506746742300237570ustar00rootroot00000000000000--- zope.conf.org Tue Sep 28 09:49:02 2004 +++ zope.conf Tue Sep 28 09:49:27 2004 @@ -20,6 +20,11 @@ address 8080 + + type HTTPS + address 8443 + + # For debugging purposes, you can use this publisher instead/as well # (obviously if it's as well, use a different port number). If there's # an exception, Zope will drop into pdb at the point of the exception. @@ -27,6 +32,11 @@ # # type PostmortemDebuggingHTTP # address 8080 +# +# +# +# type PostmortemDebuggingHTTPS +# address 8443 # m2crypto-0.46.2/demo/ZopeX3/instance_home/ssl/000077500000000000000000000000001506746742300210715ustar00rootroot00000000000000m2crypto-0.46.2/demo/ZopeX3/instance_home/ssl/ca.pem000066400000000000000000000023041506746742300221560ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDWTCCAsKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAxMTIxNTA1NTU0NloXDTA0MTIxNDA1NTU0 NlowgYAxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxML TTJDcnlwdG8gQ0ExJDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3Rl cjEiMCAGCSqGSIb3DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbTCBnzANBgkqhkiG 9w0BAQEFAAOBjQAwgYkCgYEAx8soJbS719LHK62VVVIQeC3oW0HvFArwPnA0LuEK q+LaqMOJg1rS7hvFdX03diV+XJw7cC0iECZYJNG4ii1xbY6KRmufkInaAwm54E3N e+YYVocaqUkcN6xVf6fwnLfPXbpFS/K2Umg11ObKMmi80JmiIdjcjRRCQZC7g1hf q+kCAwEAAaOB4DCB3TAdBgNVHQ4EFgQU6/qcBzEtQphfXLhiOHbt2KqBwMIwga0G A1UdIwSBpTCBooAU6/qcBzEtQphfXLhiOHbt2KqBwMKhgYakgYMwgYAxCzAJBgNV BAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0Ex JDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEiMCAGCSqGSIb3 DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqG SIb3DQEBBAUAA4GBAD+I14GuS5vJmyv1k7mUMbAicsWRHZ+zrGOq9L/L2LsA+lKQ dAzEZE2+Zv8LBPJVltbJJhcFNJS/ZMAjEm4xlJuCpvXVMxd/M5AM29aqekWlIK7J vsdDL8IuzpRkMniUiNKPhmB6IPIOslvUKx6QofcE0wDh6pg4VvIbCjkpZ7gf -----END CERTIFICATE----- m2crypto-0.46.2/demo/ZopeX3/instance_home/ssl/dh1024.pem000066400000000000000000000003651506746742300225020ustar00rootroot00000000000000-----BEGIN DH PARAMETERS----- MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq /Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx /mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC -----END DH PARAMETERS----- m2crypto-0.46.2/demo/ZopeX3/instance_home/ssl/server.pem000066400000000000000000000041101506746742300230760ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDYjCCAsugAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAzMDYyMjEzMzAxNFoXDTA0MDYyMTEzMzAx NFowXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwls b2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5leGFtcGxlLmRv bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA37aKGZtFicl8xXXTLJ8/JD7c kd3t/teCX9i61lpaDQCKBoVrrursIvZihemMKI9g/u/+BLqt5g8mBdgUdYz0txc8 KEbV2hj+wwOX4H3XwD0Y+DysXiNHq7/tFdmzSVHoLxpY4zYzXbxQ/p049wvIyPRp /y3omcnx/TEUhkn+JmkCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4 QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTB H/mUYlww24mJlSxEtGdlwojO9zCBrQYDVR0jBIGlMIGigBTr+pwHMS1CmF9cuGI4 du3YqoHAwqGBhqSBgzCBgDELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv MRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8gQ2VydGlm aWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNuZ3BzQG5ldG1lbWV0aWMuY29t ggEAMA0GCSqGSIb3DQEBBAUAA4GBAAvl6v0s3eFeGP4iAcrfysuK7jzFKhjDYuOy lVS3u33bZNLnMpM6OSEM9yPh4WpFCVHf+nYwC71pk4ilsLVXjKxymm2lNGcxLVuW iydFz4Ly9nmN7Ja9ygYT39dGAFP/wN7ELTpsbul8VfmqhNg9y81d8i/A1tK3AGA8 0QkPQNdP -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDftooZm0WJyXzFddMsnz8kPtyR3e3+14Jf2LrWWloNAIoGhWuu 6uwi9mKF6Ywoj2D+7/4Euq3mDyYF2BR1jPS3FzwoRtXaGP7DA5fgfdfAPRj4PKxe I0erv+0V2bNJUegvGljjNjNdvFD+nTj3C8jI9Gn/LeiZyfH9MRSGSf4maQIDAQAB AoGAHpeVtv62uarl9xKvuBBm0AwQmZnhq9HIsFaw5hMg8Vo7hbzFBvx1IirTOkC/ u+QvfW1QLVFh6m3z4ySzV4fZBtcd6F9SbSrZ0xsxIUB2NOSa1RGgiaP61bJnMMM1 xM3O9iwM5GZc3Gqy08QOCpDl0772VJ+9Gz3FA88mrc6rHQkCQQDz6RIatFjT28n8 1vy0nHwwZz2oXTpe/pyZPwoKj8zVsmrKhKwOw7l8ArxjP8zoHOE7AQBCXYDMNoFp IAF0yuqrAkEA6s0wMEdPpQeb0XHAfccyJQoeULxHdVFoz1wWmGSOm4YmQtR8/QJx luEgfpeRkzxBKt5Ls3MEkheIOw7xV24zOwJAMz+DaE0AZPNHS3K4ghJnHZxzng6I lzEUIjbWm0V/ml70hTy/EhMZw+6nOotLOHHo+QbK0SboSwAgzL/Gzo1cJQJANqpS 38qadleRJXAQWrg3qnvyluVe1aeAeVZ9RDmVIgxXeBO0jcs12uTLBe4PzHGo0mwy v7K1i7XC180gzzQu5QJBAOxITT9RoWSSozPvnirHd37sn+RsrNYkV07NAa80M20Z DkBPHeMVkNgigrQ6L6vWmbRDGQbGcMplAxnI5ppKCoU= -----END RSA PRIVATE KEY----- m2crypto-0.46.2/demo/bio_mem_rw.py000066400000000000000000000020541506746742300170160ustar00rootroot00000000000000#!/usr/bin/env python2.0 from __future__ import print_function """Demonstrates the use of m2.bio_set_mem_eof_return(). Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from M2Crypto import m2 m2.lib_init() use_mem = 1 if use_mem: bio = m2.bio_new(m2.bio_s_mem()) else: bio = m2.bio_new_file("XXX", "wb") ciph = m2.bf_cbc() filt = m2.bio_new(m2.bio_f_cipher()) m2.bio_set_cipher(filt, ciph, "key", "iv", 1) m2.bio_push(filt, bio) m2.bio_write(filt, "12345678901234567890") m2.bio_flush(filt) m2.bio_pop(filt) m2.bio_free(filt) if use_mem: m2.bio_set_mem_eof_return(bio, 0) xxx = m2.bio_read(bio, 100) print(repr(xxx), len(xxx)) m2.bio_free(bio) if use_mem: bio = m2.bio_new(m2.bio_s_mem()) m2.bio_write(bio, xxx) m2.bio_set_mem_eof_return(bio, 0) else: bio = m2.bio_new_file("XXX", "rb") ciph = m2.bf_cbc() filt = m2.bio_new(m2.bio_f_cipher()) m2.bio_set_cipher(filt, ciph, "key", "iv", 0) m2.bio_push(filt, bio) yyy = m2.bio_read(filt, 100) print(repr(yyy)) m2.bio_pop(filt) m2.bio_free(filt) m2.bio_free(bio) m2crypto-0.46.2/demo/dhtest.py000066400000000000000000000013361506746742300161740ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """DH demonstration. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from M2Crypto import DH, Rand def test(): print("generating dh params:") a = DH.gen_params(128, 2) b = DH.set_params(a.p, a.g) a.gen_key() b.gen_key() print("p = ", repr(a.p)) print("g = ", repr(a.g)) print("a.pub =", repr(a.pub)) print("a.priv =", repr(a.priv)) print("b.pub =", repr(b.pub)) print("b.priv =", repr(b.priv)) print("a.key = ", repr(a.compute_key(b.pub))) print("b.key = ", repr(b.compute_key(a.pub))) if __name__ == "__main__": Rand.load_file("randpool.dat", -1) test() Rand.save_file("randpool.dat") m2crypto-0.46.2/demo/dsa1024pvtkey.pem000066400000000000000000000012401506746742300173450ustar00rootroot00000000000000-----BEGIN DSA PRIVATE KEY----- MIIBvQIBAAKBgQD08iE3LXjSB/lA6Gq19XMzfmTvRBgFn+t9qNN6awFhrkowgyrI HaR6oCCHSvUcjdC0JcJdz8lSqofZkPknX6EEDkmlzZiUhtTZf0XiooeKigAiSlE2 PpoS4RFcOOqOwVwRJI3mC2lzypI46/OPS0IOZFsxhXQpn1xnkmpEt83ZwwIVAPNw e6agkM25mv12Il7IuBBNl3cPAoGBAKOES1BV2E3zWj6gXOXFP02dk5A+zd7z4Qj+ cx5euat07cAHYU0BZGJMTXlHSGf7YQOePuaxs9vTtSeUb1TeMFEr63Jispc9Kzce rd+E/IjiX7KCMbeGHnhtzC0FU/squZ76vp1TAXSozpfBvn73zAwAFPo/rHO4k6kH lXAez1QqAoGBAN6iYzbOnMckBtouHGBrdF4ea750DYnH5O2cij+yjgLMttuaxmZe 0iFtJpXp6m4IHKAzIGgKhUGabAz+4O2/ZnmNu0oZzXkpBLL84pksDd0nObtgueL6 sdTbhGl1kqpWRiK9T16gwqYxdcZiG5M5qbWtJIWWdv3mI9ql0XfUPWfpAhUA8e81 iGFXunNE3ecKjCOKUL2EnEA= -----END DSA PRIVATE KEY----- m2crypto-0.46.2/demo/dsa_bench.py000066400000000000000000000123001506746742300166000ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """ DSA demo and benchmark. Usage: python -O dsa_bench.py [option option option ...] where options may include: makenewkey showpubkey showdigest showprofile md5 sha1 sha256 sha512 NB: DSA is formally defined with SHA-1 and key length 1024. The OpenSSL implementation actually supports most any hashing algorithm and key length, as long as the key length is longer than the digest length. If not SHA-1 and 1024, you should be very clear. The use of "DSA" without any qualifiers implies SHA-1 and 1024. Larry Bugbee November 2006 Some portions are 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 DSA, EVP, Rand from M2Crypto.EVP import MessageDigest import sys, base64 # -------------------------------------------------------------- # program parameters makenewkey = 0 # 1 = make/save new key, 0 = use existing showpubkey = 0 # 1 = show the public key value showdigest = 0 # 1 = show the digest value showprofile = 0 # 1 = use the python profiler hashalgs = ["md5", "ripemd160", "sha1", "sha224", "sha256", "sha384", "sha512"] # default hashing algorithm hashalg = "sha1" # default key length keylen = 1024 # number of speed test loops N1 = N2 = 100 # -------------------------------------------------------------- # functions def test(dsa, dgst): print(" testing signing and verification...", end=" ") try: r, s = dsa.sign(dgst) except Exception as e: print("\n\n *** %s *** \n" % e) sys.exit() if not dsa.verify(dgst, r, s): print("not ok") else: print("ok") def test_asn1(dsa, dgst): # XXX Randomly fails: bug in there somewhere... (0.9.4) print(" testing asn1 signing and verification...", end=" ") blob = dsa.sign_asn1(dgst) if not dsa.verify_asn1(dgst, blob): print("not ok") else: print("ok") def speed(): from time import time t1 = time() for i in range(N1): r, s = dsa.sign(dgst) print(" %d signings: %8.2fs" % (N1, (time() - t1))) t1 = time() for i in range(N2): dsa.verify(dgst, r, s) print(" %d verifications: %8.2fs" % (N2, (time() - t1))) def test_speed(dsa, dgst): print(" measuring speed...") if showprofile: import profile profile.run("speed()") else: speed() print() # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def main(keylen, hashalg): global dsa, dgst # this exists ONLY for speed testing Rand.load_file("randpool.dat", -1) pvtkeyfilename = "DSA%dpvtkey.pem" % (keylen) pubkeyfilename = "DSA%dpubkey.pem" % (keylen) if makenewkey: print(" making and saving a new key") dsa = DSA.gen_params(keylen) dsa.gen_key() dsa.save_key(pvtkeyfilename, None) # no pswd callback dsa.save_pub_key(pubkeyfilename) else: print(" loading an existing key") dsa = DSA.load_key(pvtkeyfilename) print(" dsa key length:", len(dsa)) if not dsa.check_key(): raise "key is not initialised" if showpubkey: dsa_pub = dsa.pub pub_pem = base64.encodestring(dsa_pub) print(" PEM public key is: \n", pub_pem) # since we are testing signing and verification, let's not # be fussy about the digest. Just make one. md = EVP.MessageDigest(hashalg) md.update("can you spell subliminal channel?") dgst = md.digest() print(" hash algorithm: %s" % hashalg) if showdigest: print(" %s digest: \n%s" % (hashalg, base64.encodestring(dgst))) test(dsa, dgst) # test_asn1(dsa, dgst) test_speed(dsa, dgst) Rand.save_file("randpool.dat") # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def print_usage(): print( """ Usage: python -O %s [option option option ...] where options may include: makenewkey showpubkey showdigest showprofile md5 sha1 sha256 sha512 """ % sys.argv[0] ) sys.exit() # -------------------------------------------------------------- # -------------------------------------------------------------- if __name__ == "__main__": for arg in sys.argv[1:]: if arg in hashalgs: hashalg = arg continue if arg == "makenewkey": makenewkey = 1 continue if arg == "showpubkey": showpubkey = 1 continue if arg == "showdigest": showdigest = 1 continue if arg == "showprofile": showprofile = 1 continue try: keylen = int(arg) except: print('\n *** argument "%s" not understood ***' % arg) print_usage() main(keylen, hashalg) # -------------------------------------------------------------- # -------------------------------------------------------------- # -------------------------------------------------------------- m2crypto-0.46.2/demo/dsatest.pem000066400000000000000000000006241506746742300165000ustar00rootroot00000000000000-----BEGIN DSA PRIVATE KEY----- MIH4AgEAAkEA0NGZ0GRXdPLh/0c980Ot8ZbfV/DvJ19ZzsDhKXRxNNw36Ms4lb9Y ZMnJ1CliIDkpHx8sXEak0vkdeB2efGGBPQIVAJY7PF7CiA+jj+t3EyHf/sgVagPP AkEApkvDehftx8Kt+3GRsYkEgcKqsU6tue+QQOFOFYsCbMq/3rxIEKk0q1PqHfid +BsMiEY4FFmF5BqmgGAf6+V9twJATbbgPKi/EboVrtBdkTM52LSCQHPa/CEcj322 0s5Ix1dwojdQaNpq6HhCm6+g9SXPENy9I/PK85YnawI4A6w1pQIULRB2HSm1X14c +guvmhIobv6wE50= -----END DSA PRIVATE KEY----- m2crypto-0.46.2/demo/dsatest.py000066400000000000000000000024231506746742300163460ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """DSA demonstration. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from M2Crypto import DSA, EVP, Rand md = EVP.MessageDigest("sha1") md.update("can you spell subliminal channel?") dgst = md.digest() d = DSA.load_key("dsatest.pem") def test(): print("testing signing...", end=" ") r, s = d.sign(dgst) if not d.verify(dgst, r, s): print("not ok") else: print("ok") def test_asn1(): # XXX Randomly fails: bug in there somewhere... (0.9.4) print("testing asn1 signing...", end=" ") blob = d.sign_asn1(dgst) if not d.verify_asn1(dgst, blob): print("not ok") else: print("ok") def speed(): from time import time N1 = 5242 N2 = 2621 t1 = time() for i in range(N1): r, s = d.sign(dgst) print("%d signings: %8.2fs" % (N1, (time() - t1))) t1 = time() for i in range(N2): d.verify(dgst, r, s) print("%d verifications: %8.2fs" % (N2, (time() - t1))) def test_speed(): print("measuring speed...") import profile profile.run("speed()") if __name__ == "__main__": Rand.load_file("randpool.dat", -1) test() test_asn1() # test_speed() Rand.save_file("randpool.dat") m2crypto-0.46.2/demo/ec/000077500000000000000000000000001506746742300147135ustar00rootroot00000000000000m2crypto-0.46.2/demo/ec/ecdhtest.py000066400000000000000000000015141506746742300170710ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """ECDH demonstration. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All rights reserved.""" from M2Crypto import EC, Rand def test(): print("generating ec keys:") a = EC.gen_params(EC.NID_sect233k1) a.gen_key() b = EC.gen_params(EC.NID_sect233k1) b.gen_key() a_shared_key = a.compute_dh_key(b.pub()) b_shared_key = b.compute_dh_key(a.pub()) print("shared key according to a = ", repr(a_shared_key)) print("shared key according to b = ", repr(b_shared_key)) if a_shared_key == b_shared_key: print("ok") else: print("not ok") if __name__ == "__main__": Rand.load_file("randpool.dat", -1) test() Rand.save_file("randpool.dat") m2crypto-0.46.2/demo/ec/ecdsa_bench.py000066400000000000000000000276621506746742300175200ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """ ECDSA demo and benchmark. Usage: python -O ecdsa_bench.py [option option option ...] where options may include: makenewkey showpubkey showdigest showprofile md5 sha1 sha256 sha512 secp160r1 secp224r1 secp192k1 sect283r1 sect283k1 secp256k1 secp384r1 secp521r1 (other curves and hashes are supported, see below) Larry Bugbee, June 2006 Portions: Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. Copyright (c) 2005 Vrije Universiteit Amsterdam. All rights reserved. """ from M2Crypto import EC, EVP, Rand from M2Crypto.EVP import MessageDigest import sys, base64 # -------------------------------------------------------------- # program parameters makenewkey = 0 # 1 = make/save new key, 0 = use existing showpubkey = 0 # 1 = show the public key value showdigest = 0 # 1 = show the digest value showprofile = 0 # 1 = use the python profiler hashalgs = ["md5", "ripemd160", "sha1", "sha224", "sha256", "sha384", "sha512"] curves = [ "secp112r1", "secp112r2", "secp128r1", "secp128r2", "secp160k1", "secp160r1", "secp160r2", "secp192k1", "secp224k1", "secp224r1", "secp256k1", "secp384r1", "secp521r1", "sect113r1", "sect113r2", "sect131r1", "sect131r2", "sect163k1", "sect163r1", "sect163r2", "sect193r1", "sect193r2", "sect233k1", "sect233r1", "sect239k1", "sect283k1", "sect283r1", "sect409k1", "sect409r1", "sect571k1", "sect571r1", "X9_62_prime192v1", "X9_62_prime192v2", "X9_62_prime192v3", "X9_62_prime239v1", "X9_62_prime239v2", "X9_62_prime239v3", "X9_62_prime256v1", "X9_62_c2pnb163v1", "X9_62_c2pnb163v2", "X9_62_c2pnb163v3", "X9_62_c2pnb176v1", "X9_62_c2tnb191v1", "X9_62_c2tnb191v2", "X9_62_c2tnb191v3", "X9_62_c2pnb208w1", "X9_62_c2tnb239v1", "X9_62_c2tnb239v2", "X9_62_c2tnb239v3", "X9_62_c2pnb272w1", "X9_62_c2pnb304w1", "X9_62_c2tnb359v1", "X9_62_c2pnb368w1", "X9_62_c2tnb431r1", "wap_wsg_idm_ecid_wtls1", "wap_wsg_idm_ecid_wtls3", "wap_wsg_idm_ecid_wtls4", "wap_wsg_idm_ecid_wtls5", "wap_wsg_idm_ecid_wtls6", "wap_wsg_idm_ecid_wtls7", "wap_wsg_idm_ecid_wtls8", "wap_wsg_idm_ecid_wtls9", "wap_wsg_idm_ecid_wtls10", "wap_wsg_idm_ecid_wtls11", "wap_wsg_idm_ecid_wtls12", ] # 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. # # Oakley-EC2N-3: # IPSec/IKE/Oakley curve #3 over a 155 bit binary field. # Oakley-EC2N-4: # IPSec/IKE/Oakley curve #4 over a 185 bit binary field. # # aka 'ipsec3' and 'ipsec4' # curves2 is a shorthand convenience so as to not require the # entering the "X9_62_" prefix curves2 = [ "prime192v1", "prime192v2", "prime192v3", "prime239v1", "prime239v2", "prime239v3", "prime256v1", "c2pnb163v1", "c2pnb163v2", "c2pnb163v3", "c2pnb176v1", "c2tnb191v1", "c2tnb191v2", "c2tnb191v3", "c2pnb208w1", "c2tnb239v1", "c2tnb239v2", "c2tnb239v3", "c2pnb272w1", "c2pnb304w1", "c2tnb359v1", "c2pnb368w1", "c2tnb431r1", ] # default hashing algorithm hashalg = "sha1" # default elliptical curve curve = "secp160r1" # for a complete list of supported algorithms and curves, see # the bottom of this file # number of speed test loops N1 = N2 = 100 # -------------------------------------------------------------- # functions def test(ec, dgst): print(" testing signing and verification...", end=" ") try: # ec = EC.gen_params(EC.NID_secp160r1) # ec.gen_key() r, s = ec.sign_dsa(dgst) except Exception as e: print("\n\n *** %s *** \n" % e) sys.exit() if not ec.verify_dsa(dgst, r, s): print("not ok") else: print("ok") def test_asn1(ec, dgst): print(" testing asn1 signing and verification...", end=" ") blob = ec.sign_dsa_asn1(dgst) if not ec.verify_dsa_asn1(dgst, blob): print("not ok") else: print("ok") def speed(): from time import time t1 = time() for i in range(N1): r, s = ec.sign_dsa(dgst) print(" %d signings: %8.2fs" % (N1, (time() - t1))) t1 = time() for i in range(N2): ec.verify_dsa(dgst, r, s) print(" %d verifications: %8.2fs" % (N2, (time() - t1))) def test_speed(ec, dgst): print(" measuring speed...") if showprofile: import profile profile.run("speed()") else: speed() print() # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def main(curve, hashalg): global ec, dgst # this exists ONLY for speed testing Rand.load_file("randpool.dat", -1) if curve in curves2: curve = "X9_62_" + curve ec_curve = eval("EC.NID_%s" % curve) pvtkeyfilename = "%spvtkey.pem" % (curve) pubkeyfilename = "%spubkey.pem" % (curve) if makenewkey: print(" making and saving a new key") ec = EC.gen_params(ec_curve) ec.gen_key() ec.save_key(pvtkeyfilename, None) ec.save_pub_key(pubkeyfilename) else: print(" loading an existing key") ec = EC.load_key(pvtkeyfilename) print(" ecdsa key length:", len(ec)) print(" curve: %s" % curve) if not ec.check_key(): raise "key is not initialised" if showpubkey: ec_pub = ec.pub() pub_der = ec_pub.get_der() pub_pem = base64.encodestring(pub_der) print(" PEM public key is: \n", pub_pem) # since we are testing signing and verification, let's not # be fussy about the digest. Just make one. md = EVP.MessageDigest(hashalg) md.update("can you spell subliminal channel?") dgst = md.digest() print(" hash algorithm: %s" % hashalg) if showdigest: print(" %s digest: \n%s" % (base64.encodestring(dgst))) test(ec, dgst) # test_asn1(ec, dgst) test_speed(ec, dgst) Rand.save_file("randpool.dat") # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def print_usage(): print( """ Usage: python -O %s [option option option ...] where options may include: makenewkey showpubkey showdigest showprofile md5 sha1 sha256 sha512 secp160r1 secp224r1 secp192k1 sect283r1 sect283k1 secp256k1 secp384r1 secp521r1 (other curves and hashes are supported, check pgm src) """ % sys.argv[0] ) sys.exit() # -------------------------------------------------------------- # -------------------------------------------------------------- if __name__ == "__main__": for arg in sys.argv[1:]: if arg in hashalgs: hashalg = arg continue if arg in curves + curves2: curve = arg continue if arg == "makenewkey": makenewkey = 1 continue if arg == "showpubkey": showpubkey = 1 continue if arg == "showdigest": showdigest = 1 continue if arg == "showprofile": showprofile = 1 continue print('\n *** argument "%s" not understood ***' % arg) print_usage() main(curve, hashalg) # -------------------------------------------------------------- # -------------------------------------------------------------- # -------------------------------------------------------------- """ Elliptical curves supported by OpenSSL ====================================== $ openssl ecparam -list_curves secp112r1 : SECG/WTLS curve over a 112 bit prime field secp112r2 : SECG curve over a 112 bit prime field secp128r1 : SECG curve over a 128 bit prime field secp128r2 : SECG curve over a 128 bit prime field secp160k1 : SECG curve over a 160 bit prime field secp160r1 : SECG curve over a 160 bit prime field secp160r2 : SECG/WTLS curve over a 160 bit prime field secp192k1 : SECG curve over a 192 bit prime field secp224k1 : SECG curve over a 224 bit prime field secp224r1 : NIST/SECG curve over a 224 bit prime field secp256k1 : SECG curve over a 256 bit prime field secp384r1 : NIST/SECG curve over a 384 bit prime field secp521r1 : NIST/SECG curve over a 521 bit prime field prime192v1: NIST/X9.62/SECG curve over a 192 bit prime field prime192v2: X9.62 curve over a 192 bit prime field prime192v3: X9.62 curve over a 192 bit prime field prime239v1: X9.62 curve over a 239 bit prime field prime239v2: X9.62 curve over a 239 bit prime field prime239v3: X9.62 curve over a 239 bit prime field prime256v1: X9.62/SECG curve over a 256 bit prime field sect113r1 : SECG curve over a 113 bit binary field sect113r2 : SECG curve over a 113 bit binary field sect131r1 : SECG/WTLS curve over a 131 bit binary field sect131r2 : SECG curve over a 131 bit binary field sect163k1 : NIST/SECG/WTLS curve over a 163 bit binary field sect163r1 : SECG curve over a 163 bit binary field sect163r2 : NIST/SECG curve over a 163 bit binary field sect193r1 : SECG curve over a 193 bit binary field sect193r2 : SECG curve over a 193 bit binary field sect233k1 : NIST/SECG/WTLS curve over a 233 bit binary field sect233r1 : NIST/SECG/WTLS curve over a 233 bit binary field sect239k1 : SECG curve over a 239 bit binary field sect283k1 : NIST/SECG curve over a 283 bit binary field sect283r1 : NIST/SECG curve over a 283 bit binary field sect409k1 : NIST/SECG curve over a 409 bit binary field sect409r1 : NIST/SECG curve over a 409 bit binary field sect571k1 : NIST/SECG curve over a 571 bit binary field sect571r1 : NIST/SECG curve over a 571 bit binary field c2pnb163v1: X9.62 curve over a 163 bit binary field c2pnb163v2: X9.62 curve over a 163 bit binary field c2pnb163v3: X9.62 curve over a 163 bit binary field c2pnb176v1: X9.62 curve over a 176 bit binary field c2tnb191v1: X9.62 curve over a 191 bit binary field c2tnb191v2: X9.62 curve over a 191 bit binary field c2tnb191v3: X9.62 curve over a 191 bit binary field c2pnb208w1: X9.62 curve over a 208 bit binary field c2tnb239v1: X9.62 curve over a 239 bit binary field c2tnb239v2: X9.62 curve over a 239 bit binary field c2tnb239v3: X9.62 curve over a 239 bit binary field c2pnb272w1: X9.62 curve over a 272 bit binary field c2pnb304w1: X9.62 curve over a 304 bit binary field c2tnb359v1: X9.62 curve over a 359 bit binary field c2pnb368w1: X9.62 curve over a 368 bit binary field c2tnb431r1: X9.62 curve over a 431 bit binary field wap-wsg-idm-ecid-wtls1: WTLS curve over a 113 bit binary field wap-wsg-idm-ecid-wtls3: NIST/SECG/WTLS curve over a 163 bit binary field wap-wsg-idm-ecid-wtls4: SECG curve over a 113 bit binary field wap-wsg-idm-ecid-wtls5: X9.62 curve over a 163 bit binary field wap-wsg-idm-ecid-wtls6: SECG/WTLS curve over a 112 bit prime field wap-wsg-idm-ecid-wtls7: SECG/WTLS curve over a 160 bit prime field wap-wsg-idm-ecid-wtls8: WTLS curve over a 112 bit prime field wap-wsg-idm-ecid-wtls9: WTLS curve over a 160 bit prime field wap-wsg-idm-ecid-wtls10: NIST/SECG/WTLS curve over a 233 bit binary field wap-wsg-idm-ecid-wtls11: NIST/SECG/WTLS curve over a 233 bit binary field wap-wsg-idm-ecid-wtls12: WTLS curvs over a 224 bit prime field Oakley-EC2N-3: IPSec/IKE/Oakley curve #3 over a 155 bit binary field. Not suitable for ECDSA. Questionable extension field! Oakley-EC2N-4: IPSec/IKE/Oakley curve #4 over a 185 bit binary field. Not suitable for ECDSA. Questionable extension field! """ m2crypto-0.46.2/demo/ec/ecdsatest.pem000066400000000000000000000003231506746742300173730ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MG0CAQEEHVkQ54w5gN39TScPaC+TTKmJunupCfuNqEcWOZeXoAcGBSuBBAAaoUAD PgAEAIcWBNwIi1fP2Sd33wpayKBuw2oqBVvgvfYiipMcASzxCf6IFUC03IOob/Lu Y3mPHRZKwzSKBlD1ZkXh -----END EC PRIVATE KEY----- m2crypto-0.46.2/demo/ec/ecdsatest.py000066400000000000000000000031361506746742300172470ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """ECDSA demonstration. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All rights reserved. """ from M2Crypto import EC, EVP, Rand import base64 md = EVP.MessageDigest("sha1") md.update("can you spell subliminal channel?") dgst = md.digest() ec = EC.load_key("ecdsatest.pem") # ec=EC.gen_params(EC.NID_sect233k1) # ec.gen_key() ec_pub = ec.pub() pub_der = ec_pub.get_der() pub_pem = base64.encodestring(pub_der) print("PEM public key is", pub_pem) ec.save_key("ecdsatest.pem", None) def test(): print("testing signing...", end=" ") r, s = ec.sign_dsa(dgst) if not ec.verify_dsa(dgst, r, s): print("not ok") else: print("ok") def test_asn1(): # XXX Randomly fails: bug in there somewhere... (0.9.4) print("testing asn1 signing...", end=" ") blob = ec.sign_dsa_asn1(dgst) if not ec.verify_dsa_asn1(dgst, blob): print("not ok") else: print("ok") def speed(): from time import time N1 = 5242 N2 = 2621 t1 = time() for i in range(N1): r, s = ec.sign(dgst) print("%d signings: %8.2fs" % (N1, (time() - t1))) t1 = time() for i in range(N2): ec.verify(dgst, r, s) print("%d verifications: %8.2fs" % (N2, (time() - t1))) def test_speed(): print("measuring speed...") import profile profile.run("speed()") if __name__ == "__main__": Rand.load_file("randpool.dat", -1) test() test_asn1() # test_speed() Rand.save_file("randpool.dat") m2crypto-0.46.2/demo/ec/secp160r1pvtkey.pem000066400000000000000000000002561506746742300203100ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MFACAQEEFN1C7AYNKDl9dBLfm0QW1nB7WGs7oAcGBSuBBAAIoSwDKgEErnCVbfXH 11Ax4AZq4eh8c3gWIBeaRu6tGRpITFCjtHot78c/oVqBrg== -----END EC PRIVATE KEY----- m2crypto-0.46.2/demo/https.howto/000077500000000000000000000000001506746742300166255ustar00rootroot00000000000000m2crypto-0.46.2/demo/https.howto/ca.pem000066400000000000000000000056371506746742300177260ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 0 (0x0) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=CA, O=M2Crypto CA, CN=localhost Validity Not Before: Apr 22 04:35:56 2006 GMT Not After : Apr 21 04:35:56 2009 GMT Subject: C=US, ST=CA, O=M2Crypto CA, CN=localhost Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:d8:80:02:8f:b5:7d:9f:9b:79:76:67:a5:66:64: c0:30:0c:71:65:f1:c6:78:01:a0:29:d4:3a:2c:e5: ee:58:4d:db:53:c5:74:6e:4e:f7:b6:a5:8e:ef:ab: e8:7c:f5:5d:2d:18:ba:95:b8:15:43:6e:5a:78:c2: 91:05:08:b2:7e:cf:c4:d3:bb:ac:c7:43:27:fb:8f: 43:0d:7b:d0:d1:32:51:86:11:6e:3e:aa:68:19:88: b9:cf:d5:72:f0:a4:73:d1:69:c4:65:14:0e:12:64: 7e:1f:df:18:09:0b:6a:4b:cd:bf:ae:59:82:15:1c: 90:0f:c3:e5:cb:b3:ed:86:4d Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:TRUE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 5C:F9:C5:9B:B0:02:37:3C:66:73:4D:0E:CB:5A:3D:BB:3A:46:22:DD X509v3 Authority Key Identifier: keyid:5C:F9:C5:9B:B0:02:37:3C:66:73:4D:0E:CB:5A:3D:BB:3A:46:22:DD Signature Algorithm: sha1WithRSAEncryption 6b:9e:71:4a:ad:d2:1c:b7:58:1a:6e:8b:89:92:8d:4e:62:61: 06:2e:e8:11:f8:9c:a0:e2:11:7c:b6:e2:be:ef:b9:b1:35:20: d1:81:62:c5:ca:3c:4f:c9:88:72:f7:50:d8:e8:e0:06:43:ee: c5:5c:38:9b:e7:24:46:a6:ee:8d:b0:70:4e:75:96:00:db:d6: 59:f9:58:74:67:9f:ca:9c:12:fc:77:a7:0e:5a:38:22:5b:de: c9:33:35:bd:d0:4c:9f:6a:0f:71:7b:db:cb:fd:da:bc:39:4f: 23:1e:74:5b:ff:8d:73:72:16:a9:9f:57:54:96:3e:2c:f0:65: af:df -----BEGIN CERTIFICATE----- MIICfDCCAeWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEL MAkGA1UECBMCQ0ExFDASBgNVBAoTC00yQ3J5cHRvIENBMRIwEAYDVQQDEwlsb2Nh bGhvc3QwHhcNMDYwNDIyMDQzNTU2WhcNMDkwNDIxMDQzNTU2WjBEMQswCQYDVQQG EwJVUzELMAkGA1UECBMCQ0ExFDASBgNVBAoTC00yQ3J5cHRvIENBMRIwEAYDVQQD Ewlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANiAAo+1fZ+b eXZnpWZkwDAMcWXxxngBoCnUOizl7lhN21PFdG5O97alju+r6Hz1XS0YupW4FUNu WnjCkQUIsn7PxNO7rMdDJ/uPQw170NEyUYYRbj6qaBmIuc/VcvCkc9FpxGUUDhJk fh/fGAkLakvNv65ZghUckA/D5cuz7YZNAgMBAAGjfjB8MAwGA1UdEwQFMAMBAf8w LAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0G A1UdDgQWBBRc+cWbsAI3PGZzTQ7LWj27OkYi3TAfBgNVHSMEGDAWgBRc+cWbsAI3 PGZzTQ7LWj27OkYi3TANBgkqhkiG9w0BAQUFAAOBgQBrnnFKrdIct1gabouJko1O YmEGLugR+Jyg4hF8tuK+77mxNSDRgWLFyjxPyYhy91DY6OAGQ+7FXDib5yRGpu6N sHBOdZYA29ZZ+Vh0Z5/KnBL8d6cOWjgiW97JMzW90Eyfag9xe9vL/dq8OU8jHnRb /41zchapn1dUlj4s8GWv3w== -----END CERTIFICATE----- m2crypto-0.46.2/demo/https.howto/dh1024.pem000066400000000000000000000003651506746742300202360ustar00rootroot00000000000000-----BEGIN DH PARAMETERS----- MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq /Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx /mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC -----END DH PARAMETERS----- m2crypto-0.46.2/demo/https.howto/get_https.py000077500000000000000000000016161506746742300212070ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """Demonstrations of M2Crypto.httpslib. Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved. Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2006 OSAF. All Rights Reserved. """ from M2Crypto import Rand, SSL, httpslib def get_https(): ctx = SSL.Context() if ctx.load_verify_locations("ca.pem") != 1: raise Exception("CA certificates not loaded") ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) h = httpslib.HTTPSConnection("localhost", 9443, ssl_context=ctx) h.set_debuglevel(1) h.putrequest("GET", "/") h.endheaders() resp = h.getresponse() while 1: data = resp.read() if not data: break print(data) h.close() Rand.load_file("../randpool.dat", -1) get_https() Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/https.howto/https_cli.py000066400000000000000000000024361506746742300211750ustar00rootroot00000000000000#!/usr/bin/env python """Demonstrations of M2Crypto.httpslib. Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved. Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2006 OSAF. All Rights Reserved. """ import sys from M2Crypto import Rand, SSL, httpslib, threading def test_httpslib(): ctx = SSL.Context() if ctx.load_verify_locations("ca.pem") != 1: raise Exception("CA certificates not loaded") ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) ctx.set_info_callback() h = httpslib.HTTPSConnection("localhost", 9443, ssl_context=ctx) h.set_debuglevel(1) h.putrequest("GET", "/") h.putheader("Accept", "text/html") h.putheader("Accept", "text/plain") h.putheader("Connection", "close") h.endheaders() resp = h.getresponse() f = resp.fp c = 0 while 1: # Either of following two works. # data = f.readline() data = resp.read() if not data: break c = c + len(data) sys.stdout.write(data) sys.stdout.flush() f.close() h.close() if __name__ == "__main__": Rand.load_file("../randpool.dat", -1) # threading.init() test_httpslib() # threading.cleanup() Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/https.howto/orig_https_srv.py000066400000000000000000000106571506746742300222640ustar00rootroot00000000000000"""This server extends BaseHTTPServer and SimpleHTTPServer thusly: 1. One thread per connection. 2. Generates directory listings. In addition, it has the following properties: 1. Works over HTTPS only. 2. Displays SSL handshaking and SSL session info. 3. Performs SSL renegotiation when a magic url is requested. TODO: 1. Cache stat() of directory entries. 2. Fancy directory indexing. 3. Interface ZPublisher. Copyright (c) 1999-2000 Ng Pheng Siong. All rights reserved. Portions created by Open Source Applications Foundation (OSAF) are Copyright (C) 2006 OSAF. All Rights Reserved. """ import os, sys from SimpleHTTPServer import SimpleHTTPRequestHandler from M2Crypto import Rand, SSL, threading from M2Crypto.SSL.SSLServer import ThreadingSSLServer try: from cStringIO import StringIO except ImportError: from StringIO import StringIO def mkdirlist(path, url): dirlist = os.listdir(path) dirlist.sort() f = StringIO() f.write("Index listing for %s\r\n" % (url,)) f.write("

    Index listing for %s

    \r\n" % (url,)) f.write("
    \r\n")
        for d in dirlist:
            if os.path.isdir(os.path.join(path, d)):
                d2 = d + "/"
            else:
                d2 = d
            if url == "/":
                f.write('%s
    \r\n' % (d, d2)) else: f.write('%s
    \r\n' % (url, d, d2)) f.write("
    \r\n\r\n") f.reset() return f class HTTP_Handler(SimpleHTTPRequestHandler): server_version = "https_srv/0.1" reneg = 0 # Cribbed from SimpleHTTPRequestHander to add the ".der" entry, # which facilitates installing your own certificates into browsers. extensions_map = { "": "text/plain", # Default, *must* be present ".html": "text/html", ".htm": "text/html", ".gif": "image/gif", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".der": "application/x-x509-ca-cert", } def send_head(self): if self.path[1:8] == "_reneg_": self.reneg = 1 self.path = self.path[8:] path = self.translate_path(self.path) if os.path.isdir(path): f = mkdirlist(path, self.path) filetype = "text/html" else: try: f = open(path, "rb") filetype = self.guess_type(path) except IOError: self.send_error(404, "File not found") return None self.send_response(200) self.send_header("Content-type", filetype) self.end_headers() return f def do_GET(self): # sess = self.request.get_session() # self.log_message('\n%s', sess.as_text()) f = self.send_head() if self.reneg: self.reneg = 0 self.request.renegotiate() sess = self.request.get_session() self.log_message("\n%s", sess.as_text()) if f: self.copyfile(f, self.wfile) f.close() def do_HEAD(self): # sess = self.request.get_session() # self.log_message('\n%s', sess.as_text()) f = self.send_head() if f: f.close() class HTTPS_Server(ThreadingSSLServer): def __init__(self, server_addr, handler, ssl_ctx): ThreadingSSLServer.__init__(self, server_addr, handler, ssl_ctx) self.server_name = server_addr[0] self.server_port = server_addr[1] def finish(self): self.request.set_shutdown(SSL.SSL_RECEIVED_SHUTDOWN | SSL.SSL_SENT_SHUTDOWN) self.request.close() def init_context(protocol, certfile, cafile, verify, verify_depth=10): ctx = SSL.Context(protocol) ctx.load_cert(certfile) ctx.load_client_ca(cafile) if ctx.load_verify_locations(cafile) != 1: raise Exception("CA certificates not loaded") ctx.set_verify(verify, verify_depth) ctx.set_allow_unknown_ca(1) ctx.set_session_id_ctx("https_srv") ctx.set_info_callback() return ctx if __name__ == "__main__": if len(sys.argv) < 2: wdir = "." else: wdir = sys.argv[1] Rand.load_file("../randpool.dat", -1) threading.init() ctx = init_context("sslv23", "server.pem", "ca.pem", SSL.verify_none) # SSL.verify_peer | SSL.verify_fail_if_no_peer_cert) ctx.set_tmp_dh("dh1024.pem") os.chdir(wdir) httpsd = HTTPS_Server(("", 9443), HTTP_Handler, ctx) httpsd.serve_forever() threading.cleanup() Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/https.howto/server.pem000066400000000000000000000074331506746742300206450ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=CA, O=M2Crypto CA, CN=localhost Validity Not Before: Apr 22 04:36:56 2006 GMT Not After : Apr 22 04:36:56 2007 GMT Subject: C=US, ST=CA, O=M2Crypto Server, CN=localhost Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:a5:cc:39:ad:ba:81:3d:bd:05:f4:61:50:9f:9c: f6:ad:ec:29:d9:78:1e:24:61:f7:1b:36:bf:69:d8: b3:45:ae:6f:3a:4c:4f:d6:13:6d:60:8d:f2:bb:2a: c4:1b:79:fd:e2:f8:d6:3c:56:53:3b:27:f7:3f:70: a4:64:99:63:46:2e:3f:ef:52:da:a9:04:5b:6e:d4: 40:57:c5:59:61:d3:3f:7d:b8:03:c1:9b:65:46:2a: c5:9d:70:b7:ca:79:6e:dd:e4:3f:c2:f4:2f:2e:81: 32:c8:e9:a6:b6:a8:c8:1f:48:be:7a:66:56:98:fc: 3c:25:fc:d9:3d:73:07:30:71 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: F0:48:3A:32:88:8C:80:D7:22:AB:56:F8:86:B3:04:47:10:76:37:BE X509v3 Authority Key Identifier: keyid:5C:F9:C5:9B:B0:02:37:3C:66:73:4D:0E:CB:5A:3D:BB:3A:46:22:DD Signature Algorithm: sha1WithRSAEncryption 39:47:95:5c:ea:7e:db:b8:e0:80:f6:e5:d4:9f:83:bc:41:89: 31:97:c8:a4:95:0d:5d:6d:cc:64:8d:19:71:17:75:4b:7f:fb: 35:88:bf:68:e2:a2:be:c5:71:71:56:2a:92:31:25:2a:4b:98: 4e:77:42:45:78:45:21:a5:76:99:92:39:32:7d:a2:4c:38:b0: f1:db:7f:d1:4d:23:99:35:1e:0e:a1:59:a3:ff:9c:51:ef:4c: 11:c9:32:61:38:11:7d:57:2a:81:9a:96:1f:b3:88:f7:ab:5b: 58:f7:79:9b:a8:e3:b7:09:90:8e:c9:7d:44:4f:af:85:dc:c8: 29:4d -----BEGIN CERTIFICATE----- MIICfTCCAeagAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEL MAkGA1UECBMCQ0ExFDASBgNVBAoTC00yQ3J5cHRvIENBMRIwEAYDVQQDEwlsb2Nh bGhvc3QwHhcNMDYwNDIyMDQzNjU2WhcNMDcwNDIyMDQzNjU2WjBIMQswCQYDVQQG EwJVUzELMAkGA1UECBMCQ0ExGDAWBgNVBAoTD00yQ3J5cHRvIFNlcnZlcjESMBAG A1UEAxMJbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQClzDmt uoE9vQX0YVCfnPat7CnZeB4kYfcbNr9p2LNFrm86TE/WE21gjfK7KsQbef3i+NY8 VlM7J/c/cKRkmWNGLj/vUtqpBFtu1EBXxVlh0z99uAPBm2VGKsWdcLfKeW7d5D/C 9C8ugTLI6aa2qMgfSL56ZlaY/Dwl/Nk9cwcwcQIDAQABo3sweTAJBgNVHRMEAjAA MCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd BgNVHQ4EFgQU8Eg6MoiMgNciq1b4hrMERxB2N74wHwYDVR0jBBgwFoAUXPnFm7AC Nzxmc00Oy1o9uzpGIt0wDQYJKoZIhvcNAQEFBQADgYEAOUeVXOp+27jggPbl1J+D vEGJMZfIpJUNXW3MZI0ZcRd1S3/7NYi/aOKivsVxcVYqkjElKkuYTndCRXhFIaV2 mZI5Mn2iTDiw8dt/0U0jmTUeDqFZo/+cUe9MEckyYTgRfVcqgZqWH7OI96tbWPd5 m6jjtwmQjsl9RE+vhdzIKU0= -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQClzDmtuoE9vQX0YVCfnPat7CnZeB4kYfcbNr9p2LNFrm86TE/W E21gjfK7KsQbef3i+NY8VlM7J/c/cKRkmWNGLj/vUtqpBFtu1EBXxVlh0z99uAPB m2VGKsWdcLfKeW7d5D/C9C8ugTLI6aa2qMgfSL56ZlaY/Dwl/Nk9cwcwcQIDAQAB AoGBAIwzbZbePsnxXOaxoBbJCcQ7D4yJSZvkh6womKauC7Lh9carn1tc5EIg5uCl Il5Fw466c5dkPE+q1SZ9X1Z+avYh4ypHjpcr1Lfvwo0wfOBx5MBj6ppMdwgrMXuo jRChK3gBZXmKaIH19h/sGp/lZRW2HiX63aN11KDmtfwo6Bq9AkEA2OftYJUqceK3 /E8q6OE1oQLm+oK6CPZ29A5TRNOadRu1opDR/y59GcUQ5ebJNH8DXyF82lSi3DKt SNoSOF32cwJBAMOuKGUAwnq1yH3q+MAF7CZjGou7Ar6VRseyLnD5nttynT85QRW8 N/WCosKLhV7wi9kKJmHGUJfRAqdo14D8IIsCQQCVjrU6FyABDpZVvjCUClT0BBBH QsQLUgWLGiWIG28wuD5xLPHexas0jZCtNIgfTkSA35I66Iiy065vwQ03GHLJAkAG eGC/jjngAtjBSR62grufPVGoYyOhF6CCg+LDO43EJdMLPyJmzJVxGcO1+RUM4ZlO MOa5/uu1SWT0EiRmEHAnAkBusVcHcd6d4uaoiCybIhF4hL4GsbKoImIciakNlteA c1RZZHc2jzO/Ihoz50H1njXwY86YbjncOXw8shtayd8j -----END RSA PRIVATE KEY----- m2crypto-0.46.2/demo/medusa/000077500000000000000000000000001506746742300156025ustar00rootroot00000000000000m2crypto-0.46.2/demo/medusa/00_README000066400000000000000000000014711506746742300167640ustar00rootroot00000000000000 19 Sep 2001 ------------- M2Crypto HTTPS and FTP/TLS servers All the files in this directory are from the Apr 2001 release of Medusa, except for the following: - 00_README (this file) - server.pem, the server's certificate - ca.pem, my CA certificate - https_server.py - ftps_server.py - START.py - START_xmlrpc.py - index.html, a sample HTML file - poison_handler.py, a webpoison clone By default, http_server listens on port 9080 and https_server port 9443. Document root is current directory, and serves up index.html. The xmlrpc server is accessible below '/RPC2'. It requires Fredrik Lundh's xmlrpc_handler on PYTHONPATH. The FTP/TLS server listens on port 9021 by default. I've only tested it with the 'anonymous' authentication handler. Medusa files are copyright Sam Rushing. My files are copyright me. m2crypto-0.46.2/demo/medusa/START.py000066400000000000000000000035601506746742300170550ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function # Standard Python library import os import os.path import sys # Medusa import asyncore import default_handler import filesys import ftp_server import http_server import status_handler # M2Crypto import https_server import poison_handler import ftps_server from M2Crypto import Rand, SSL, threading HTTP_PORT = 9080 HTTPS_PORT = 9443 FTP_PORT = 9021 hs = http_server.http_server("", HTTP_PORT) Rand.load_file("../randpool.dat", -1) ssl_ctx = SSL.Context("sslv23") ssl_ctx.load_cert("server.pem") ssl_ctx.load_verify_location("ca.pem") ssl_ctx.load_client_CA("ca.pem") # ssl_ctx.set_verify(SSL.verify_peer, 10) # ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_fail_if_no_peer_cert, 10) # ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_client_once, 10) ssl_ctx.set_verify(SSL.verify_none, 10) ssl_ctx.set_session_id_ctx("127.0.0.1:9443") ssl_ctx.set_tmp_dh("dh1024.pem") ssl_ctx.set_info_callback() hss = https_server.https_server("", HTTPS_PORT, ssl_ctx) # fs=filesys.os_filesystem(os.path.abspath(os.curdir)) fs = filesys.os_filesystem("/usr/local/pkg/apache/htdocs") # fs=filesys.os_filesystem('c:/pkg/jdk130/docs') dh = default_handler.default_handler(fs) hs.install_handler(dh) hss.install_handler(dh) # class rpc_demo (xmlrpc_handler.xmlrpc_handler): # def call (self, method, params): # print('method="%s" params=%s' % (method, params)) # return "Sure, that works" # rpch = rpc_demo() # hs.install_handler(rpch) # hss.install_handler(rpch) ph = poison_handler.poison_handler(10) hs.install_handler(ph) hss.install_handler(ph) fauthz = ftp_server.anon_authorizer("/usr/local/pkg/apache/htdocs") ftps = ftps_server.ftp_tls_server(fauthz, ssl_ctx, port=FTP_PORT) sh = status_handler.status_extension([hs, hss, ftps]) hs.install_handler(sh) hss.install_handler(sh) asyncore.loop() Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/medusa/START_xmlrpc.py000066400000000000000000000034241506746742300204410ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function # Standard Python library import os import os.path import sys # Medusa import asyncore import default_handler import filesys import http_server import status_handler # M2Crypto import https_server import poison_handler from M2Crypto import Rand, SSL # XMLrpc import xmlrpc_handler HTTP_PORT = 9080 HTTPS_PORT = 9443 hs = http_server.http_server("", HTTP_PORT) Rand.load_file("../randpool.dat", -1) ssl_ctx = SSL.Context("sslv23") ssl_ctx.load_cert("server.pem") # ssl_ctx.load_verify_location('ca.pem') # ssl_ctx.load_client_CA('ca.pem') # ssl_ctx.set_verify(SSL.verify_peer, 10) # ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_fail_if_no_peer_cert, 10) # ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_client_once, 10) ssl_ctx.set_verify(SSL.verify_none, 10) ssl_ctx.set_session_id_ctx("127.0.0.1:9443") ssl_ctx.set_tmp_dh("dh1024.pem") # ssl_ctx.set_info_callback() hss = https_server.https_server("", HTTPS_PORT, ssl_ctx) # fs=filesys.os_filesystem(os.path.abspath(os.curdir)) fs = filesys.os_filesystem("/usr/local/pkg/apache/htdocs") # fs=filesys.os_filesystem('c:/pkg/jdk118/docs') dh = default_handler.default_handler(fs) hs.install_handler(dh) hss.install_handler(dh) # Cribbed from xmlrpc_handler.py. # This is where you implement your RPC functionality. class rpc_demo(xmlrpc_handler.xmlrpc_handler): def call(self, method, params): print('method="%s" params=%s' % (method, params)) return "Sure, that works" rpch = rpc_demo() hs.install_handler(rpch) hss.install_handler(rpch) ph = poison_handler.poison_handler(10) hs.install_handler(ph) hss.install_handler(ph) sh = status_handler.status_extension([hss]) hs.install_handler(sh) hss.install_handler(sh) asyncore.loop() Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/medusa/asynchat.py000066400000000000000000000243541506746742300177760ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- # $Id$ # Author: Sam Rushing # ====================================================================== # Copyright 1996 by Sam Rushing # # 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, and that the name of Sam # Rushing not be used in advertising or publicity pertaining to # distribution of the software without specific, written prior # permission. # # SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN # NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # ====================================================================== """A class supporting chat-style (command/response) protocols. This class adds support for 'chat' style protocols - where one side sends a 'command', and the other sends a response (examples would be the common internet protocols - smtp, nntp, ftp, etc..). The handle_read() method looks at the input stream for the current 'terminator' (usually '\r\n' for single-line responses, '\r\n.\r\n' for multi-line output), calling self.found_terminator() on its receipt. for example: Say you build an async nntp client using this class. At the start of the connection, you'll have self.terminator set to '\r\n', in order to process the single-line greeting. Just before issuing a 'LIST' command you'll set it to '\r\n.\r\n'. The output of the LIST command will be accumulated (using your own 'collect_incoming_data' method) up to the terminator, and then control will be returned to you - by calling your self.found_terminator() method. """ import socket import asyncore import string class async_chat(asyncore.dispatcher): """This is an abstract class. You must derive from this class, and add the two methods collect_incoming_data() and found_terminator()""" # these are overridable defaults ac_in_buffer_size = 4096 ac_out_buffer_size = 4096 def __init__(self, conn=None): self.ac_in_buffer = "" self.ac_out_buffer = "" self.producer_fifo = fifo() asyncore.dispatcher.__init__(self, conn) def set_terminator(self, term): "Set the input delimiter. Can be a fixed string of any length, an integer, or None" self.terminator = term def get_terminator(self): return self.terminator # grab some more data from the socket, # throw it to the collector method, # check for the terminator, # if found, transition to the next state. def handle_read(self): try: data = self.recv(self.ac_in_buffer_size) except socket.error as why: self.handle_error() return self.ac_in_buffer = self.ac_in_buffer + data # Continue to search for self.terminator in self.ac_in_buffer, # while calling self.collect_incoming_data. The while loop # is necessary because we might read several data+terminator # combos with a single recv(1024). while self.ac_in_buffer: lb = len(self.ac_in_buffer) terminator = self.get_terminator() if terminator is None: # no terminator, collect it all self.collect_incoming_data(self.ac_in_buffer) self.ac_in_buffer = "" elif type(terminator) == type(0): # numeric terminator n = terminator if lb < n: self.collect_incoming_data(self.ac_in_buffer) self.ac_in_buffer = "" self.terminator = self.terminator - lb else: self.collect_incoming_data(self.ac_in_buffer[:n]) self.ac_in_buffer = self.ac_in_buffer[n:] self.terminator = 0 self.found_terminator() else: # 3 cases: # 1) end of buffer matches terminator exactly: # collect data, transition # 2) end of buffer matches some prefix: # collect data to the prefix # 3) end of buffer does not match any prefix: # collect data terminator_len = len(terminator) index = string.find(self.ac_in_buffer, terminator) if index != -1: # we found the terminator if index > 0: # don't bother reporting the empty string (source of subtle bugs) self.collect_incoming_data(self.ac_in_buffer[:index]) self.ac_in_buffer = self.ac_in_buffer[index + terminator_len :] # This does the Right Thing if the terminator is changed here. self.found_terminator() else: # check for a prefix of the terminator index = find_prefix_at_end(self.ac_in_buffer, terminator) if index: if index != lb: # we found a prefix, collect up to the prefix self.collect_incoming_data(self.ac_in_buffer[:-index]) self.ac_in_buffer = self.ac_in_buffer[-index:] break else: # no prefix, collect it all self.collect_incoming_data(self.ac_in_buffer) self.ac_in_buffer = "" def handle_write(self): self.initiate_send() def handle_close(self): self.close() def push(self, data): self.producer_fifo.push(simple_producer(data)) self.initiate_send() def push_with_producer(self, producer): self.producer_fifo.push(producer) self.initiate_send() def readable(self): "predicate for inclusion in the readable for select()" return len(self.ac_in_buffer) <= self.ac_in_buffer_size def writable(self): "predicate for inclusion in the writable for select()" # return len(self.ac_out_buffer) or len(self.producer_fifo) or (not self.connected) # this is about twice as fast, though not as clear. return not ( (self.ac_out_buffer is "") and self.producer_fifo.is_empty() and self.connected ) def close_when_done(self): "automatically close this channel once the outgoing queue is empty" self.producer_fifo.push(None) # refill the outgoing buffer by calling the more() method # of the first producer in the queue def refill_buffer(self): _string_type = type("") while 1: if len(self.producer_fifo): p = self.producer_fifo.first() # a 'None' in the producer fifo is a sentinel, # telling us to close the channel. if p is None: if not self.ac_out_buffer: self.producer_fifo.pop() self.close() return elif type(p) is _string_type: self.producer_fifo.pop() self.ac_out_buffer = self.ac_out_buffer + p return data = p.more() if data: self.ac_out_buffer = self.ac_out_buffer + data return else: self.producer_fifo.pop() else: return def initiate_send(self): obs = self.ac_out_buffer_size # try to refill the buffer if len(self.ac_out_buffer) < obs: self.refill_buffer() if self.ac_out_buffer and self.connected: # try to send the buffer try: num_sent = self.send(self.ac_out_buffer[:obs]) if num_sent: self.ac_out_buffer = self.ac_out_buffer[num_sent:] except socket.error as why: self.handle_error() return def discard_buffers(self): # Emergencies only! self.ac_in_buffer = "" self.ac_out_buffer = "" while self.producer_fifo: self.producer_fifo.pop() class simple_producer: def __init__(self, data, buffer_size=512): self.data = data self.buffer_size = buffer_size def more(self): if len(self.data) > self.buffer_size: result = self.data[: self.buffer_size] self.data = self.data[self.buffer_size :] return result else: result = self.data self.data = "" return result class fifo: def __init__(self, list=None): if not list: self.list = [] else: self.list = list def __len__(self): return len(self.list) def is_empty(self): return self.list == [] def first(self): return self.list[0] def push(self, data): self.list.append(data) def pop(self): if self.list: result = self.list[0] del self.list[0] return (1, result) else: return (0, None) # Given 'haystack', see if any prefix of 'needle' is at its end. This # assumes an exact match has already been checked. Return the number of # characters matched. # for example: # f_p_a_e ("qwerty\r", "\r\n") => 1 # f_p_a_e ("qwertydkjf", "\r\n") => 0 # f_p_a_e ("qwerty\r\n", "\r\n") => # this could maybe be made faster with a computed regex? # [answer: no; circa Python-2.0, Jan 2001] # new python: 28961/s # old python: 18307/s # re: 12820/s # regex: 14035/s def find_prefix_at_end(haystack, needle): l = len(needle) - 1 while l and not haystack.endswith(needle[:l]): l -= 1 return l m2crypto-0.46.2/demo/medusa/asyncore.py000066400000000000000000000406631506746742300200100ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- # $Id$ # Author: Sam Rushing # ====================================================================== # Copyright 1996 by Sam Rushing # # 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, and that the name of Sam # Rushing not be used in advertising or publicity pertaining to # distribution of the software without specific, written prior # permission. # # SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN # NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # ====================================================================== from __future__ import print_function """Basic infrastructure for asynchronous socket service clients and servers. There are only two ways to have a program on a single processor do "more than one thing at a time". Multi-threaded programming is the simplest and most popular way to do it, but there is another very different technique, that lets you have nearly all the advantages of multi-threading, without actually using multiple threads. it's really only practical if your program is largely I/O bound. If your program is CPU bound, then pre-emptive scheduled threads are probably what you really need. Network servers are rarely CPU-bound, however. If your operating system supports the select() system call in its I/O library (and nearly all do), then you can use it to juggle multiple communication channels at once; doing other work while your I/O is taking place in the "background." Although this strategy can seem strange and complex, especially at first, it is in many ways easier to understand and control than multi-threaded programming. The module documented here solves many of the difficult problems for you, making the task of building sophisticated high-performance network servers and clients a snap. """ import exceptions import select import socket import string import sys import os if os.name == "nt": EWOULDBLOCK = 10035 EINPROGRESS = 10036 EALREADY = 10037 ECONNRESET = 10054 ENOTCONN = 10057 ESHUTDOWN = 10058 else: from errno import ( EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, ENOTCONN, ESHUTDOWN, ) try: socket_map except NameError: socket_map = {} class ExitNow(exceptions.Exception): pass DEBUG = 0 def poll(timeout=0.0, map=None): global DEBUG if map is None: map = socket_map if map: r = [] w = [] e = [] for fd, obj in map.items(): if obj.readable(): r.append(fd) if obj.writable(): w.append(fd) r, w, e = select.select(r, w, e, timeout) if DEBUG: print(r, w, e) for fd in r: try: obj = map[fd] try: obj.handle_read_event() except ExitNow: raise ExitNow except: obj.handle_error() except KeyError: pass for fd in w: try: obj = map[fd] try: obj.handle_write_event() except ExitNow: raise ExitNow except: obj.handle_error() except KeyError: pass def poll2(timeout=0.0, map=None): import poll if map is None: map = socket_map # timeout is in milliseconds timeout = int(timeout * 1000) if map: l = [] for fd, obj in map.items(): flags = 0 if obj.readable(): flags = poll.POLLIN if obj.writable(): flags = flags | poll.POLLOUT if flags: l.append((fd, flags)) r = poll.poll(l, timeout) for fd, flags in r: try: obj = map[fd] try: if flags & poll.POLLIN: obj.handle_read_event() if flags & poll.POLLOUT: obj.handle_write_event() except ExitNow: raise ExitNow except: obj.handle_error() except KeyError: pass def poll3(timeout=0.0, map=None): # Use the poll() support added to the select module in Python 2.0 if map is None: map = socket_map # timeout is in milliseconds timeout = int(timeout * 1000) pollster = select.poll() if map: l = [] for fd, obj in map.items(): flags = 0 if obj.readable(): flags = select.POLLIN if obj.writable(): flags = flags | select.POLLOUT if flags: pollster.register(fd, flags) r = pollster.poll(timeout) for fd, flags in r: try: obj = map[fd] try: if flags & select.POLLIN: obj.handle_read_event() if flags & select.POLLOUT: obj.handle_write_event() except ExitNow: raise ExitNow except: obj.handle_error() except KeyError: pass def loop(timeout=30.0, use_poll=0, map=None): if use_poll: if hasattr(select, "poll"): poll_fun = poll3 else: poll_fun = poll2 else: poll_fun = poll if map is None: map = socket_map while map: poll_fun(timeout, map) class dispatcher: debug = 0 connected = 0 accepting = 0 closing = 0 addr = None def __init__(self, sock=None, map=None): if sock: self.set_socket(sock, map) # I think it should inherit this anyway self.socket.setblocking(0) self.connected = 1 def __repr__(self): try: status = [] if self.accepting and self.addr: status.append("listening") elif self.connected: status.append("connected") if self.addr: status.append("%s:%d" % self.addr) return "<%s %s at %x>" % ( self.__class__.__name__, string.join(status, " "), id(self), ) except: try: ar = repr(self.addr) except: ar = "no self.addr!" return "<__repr__ (self) failed for object at %x (addr=%s)>" % ( id(self), ar, ) def add_channel(self, map=None): # self.log_info ('adding channel %s' % self) if map is None: map = socket_map map[self._fileno] = self def del_channel(self, map=None): fd = self._fileno if map is None: map = socket_map if fd in map: # self.log_info ('closing channel %d:%s' % (fd, self)) del map[fd] def create_socket(self, family, type): self.family_and_type = family, type self.socket = socket.socket(family, type) self.socket.setblocking(0) self._fileno = self.socket.fileno() self.add_channel() def set_socket(self, sock, map=None): self.__dict__["socket"] = sock self._fileno = sock.fileno() self.add_channel(map) def set_reuse_addr(self): # try to re-use a server port if possible try: self.socket.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR) | 1, ) except: pass # ================================================== # predicates for select() # these are used as filters for the lists of sockets # to pass to select(). # ================================================== def readable(self): return 1 if os.name == "mac": # The macintosh will select a listening socket for # write if you let it. What might this mean? def writable(self): return not self.accepting else: def writable(self): return 1 # ================================================== # socket object methods. # ================================================== def listen(self, num): self.accepting = 1 if os.name == "nt" and num > 5: num = 1 return self.socket.listen(num) def bind(self, addr): self.addr = addr return self.socket.bind(addr) def connect(self, address): self.connected = 0 try: self.socket.connect(address) except socket.error as why: if why[0] in (EINPROGRESS, EALREADY, EWOULDBLOCK): return else: raise socket.error(why[0]) self.connected = 1 self.handle_connect() def accept(self): try: conn, addr = self.socket.accept() return conn, addr except socket.error as why: if why[0] == EWOULDBLOCK: pass else: raise socket.error(why[0]) def send(self, data): try: result = self.socket.send(data) return result except socket.error as why: if why[0] == EWOULDBLOCK: return 0 else: raise socket.error(why[0]) return 0 def recv(self, buffer_size): try: data = self.socket.recv(buffer_size) if not data: # a closed connection is indicated by signaling # a read condition, and having recv() return 0. self.handle_close() return "" else: return data except socket.error as why: # winsock sometimes throws ENOTCONN if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN]: self.handle_close() return "" else: raise socket.error(why[0]) def close(self): self.del_channel() self.socket.close() # cheap inheritance, used to pass all other attribute # references to the underlying socket object. def __getattr__(self, attr): return getattr(self.socket, attr) # log and log_info maybe overriden to provide more sophisitcated # logging and warning methods. In general, log is for 'hit' logging # and 'log_info' is for informational, warning and error logging. def log(self, message): sys.stderr.write("log: %s\n" % str(message)) def log_info(self, message, type="info"): if __debug__ or type != "info": print("%s: %s" % (type, message)) def handle_read_event(self): if self.accepting: # for an accepting socket, getting a read implies # that we are connected if not self.connected: self.connected = 1 self.handle_accept() elif not self.connected: self.handle_connect() self.connected = 1 self.handle_read() else: self.handle_read() def handle_write_event(self): # getting a write implies that we are connected if not self.connected: self.handle_connect() self.connected = 1 self.handle_write() def handle_expt_event(self): self.handle_expt() def handle_error(self): (file, fun, line), t, v, tbinfo = compact_traceback() # sometimes a user repr method will crash. try: self_repr = repr(self) except: self_repr = "<__repr__ (self) failed for object at %0x>" % id(self) self.log_info( "uncaptured python exception, closing channel %s (%s:%s %s)" % (self_repr, t, v, tbinfo), "error", ) self.close() def handle_expt(self): self.log_info("unhandled exception", "warning") def handle_read(self): self.log_info("unhandled read event", "warning") def handle_write(self): self.log_info("unhandled write event", "warning") def handle_connect(self): self.log_info("unhandled connect event", "warning") def handle_accept(self): self.log_info("unhandled accept event", "warning") def handle_close(self): self.log_info("unhandled close event", "warning") self.close() # --------------------------------------------------------------------------- # adds simple buffered output capability, useful for simple clients. # [for more sophisticated usage use asynchat.async_chat] # --------------------------------------------------------------------------- class dispatcher_with_send(dispatcher): def __init__(self, sock=None): dispatcher.__init__(self, sock) self.out_buffer = "" def initiate_send(self): num_sent = 0 num_sent = dispatcher.send(self, self.out_buffer[:512]) self.out_buffer = self.out_buffer[num_sent:] def handle_write(self): self.initiate_send() def writable(self): return (not self.connected) or len(self.out_buffer) def send(self, data): if self.debug: self.log_info("sending %s" % repr(data)) self.out_buffer = self.out_buffer + data self.initiate_send() # --------------------------------------------------------------------------- # used for debugging. # --------------------------------------------------------------------------- def compact_traceback(): t, v, tb = sys.exc_info() tbinfo = [] while 1: tbinfo.append( ( tb.tb_frame.f_code.co_filename, tb.tb_frame.f_code.co_name, str(tb.tb_lineno), ) ) tb = tb.tb_next if not tb: break # just to be safe del tb file, function, line = tbinfo[-1] info = "[" + string.join(map(lambda x: string.join(x, "|"), tbinfo), "] [") + "]" return (file, function, line), t, v, info def close_all(map=None): if map is None: map = socket_map for x in map.values(): x.socket.close() map.clear() # Asynchronous File I/O: # # After a little research (reading man pages on various unixen, and # digging through the linux kernel), I've determined that select() # isn't meant for doing doing asynchronous file i/o. # Heartening, though - reading linux/mm/filemap.c shows that linux # supports asynchronous read-ahead. So _MOST_ of the time, the data # will be sitting in memory for us already when we go to read it. # # What other OS's (besides NT) support async file i/o? [VMS?] # # Regardless, this is useful for pipes, and stdin/stdout... import os if os.name == "posix": import fcntl import FCNTL class file_wrapper: # here we override just enough to make a file # look like a socket for the purposes of asyncore. def __init__(self, fd): self.fd = fd def recv(self, *args): return apply(os.read, (self.fd,) + args) def send(self, *args): return apply(os.write, (self.fd,) + args) read = recv write = send def close(self): return os.close(self.fd) def fileno(self): return self.fd class file_dispatcher(dispatcher): def __init__(self, fd): dispatcher.__init__(self) self.connected = 1 # set it to non-blocking mode flags = fcntl.fcntl(fd, FCNTL.F_GETFL, 0) flags = flags | FCNTL.O_NONBLOCK fcntl.fcntl(fd, FCNTL.F_SETFL, flags) self.set_file(fd) def set_file(self, fd): self._fileno = fd self.socket = file_wrapper(fd) self.add_channel() m2crypto-0.46.2/demo/medusa/auth_handler.py000066400000000000000000000107021506746742300206120ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- # # Author: Sam Rushing # Copyright 1996-2000 by Sam Rushing # All Rights Reserved. # # support for 'basic' authenticaion. from __future__ import print_function import base64 import hashlib import re import string import time import counter import default_handler get_header = default_handler.get_header import http_server import producers # This is a 'handler' that wraps an authorization method # around access to the resources normally served up by # another handler. # does anyone support digest authentication? (rfc2069) class auth_handler: def __init__(self, dict, handler, realm="default"): self.authorizer = dictionary_authorizer(dict) self.handler = handler self.realm = realm self.pass_count = counter.counter() self.fail_count = counter.counter() def match(self, request): # by default, use the given handler's matcher return self.handler.match(request) def handle_request(self, request): # authorize a request before handling it... scheme = get_header(AUTHORIZATION, request.header) if scheme: scheme = string.lower(scheme) if scheme == "basic": cookie = AUTHORIZATION.group(2) try: decoded = base64.decodestring(cookie) except: print("malformed authorization info <%s>" % cookie) request.error(400) return auth_info = string.split(decoded, ":") if self.authorizer.authorize(auth_info): self.pass_count.increment() request.auth_info = auth_info self.handler.handle_request(request) else: self.handle_unauthorized(request) # elif scheme == 'digest': # print('digest: ',AUTHORIZATION.group(2)) else: print("unknown/unsupported auth method: %s" % scheme) self.handle_unauthorized() else: # list both? prefer one or the other? # you could also use a 'nonce' here. [see below] # auth = 'Basic realm="%s" Digest realm="%s"' % # (self.realm, self.realm) # nonce = self.make_nonce (request) # auth = 'Digest realm="%s" nonce="%s"' % (self.realm, nonce) # request['WWW-Authenticate'] = auth # print('sending header: %s' % request['WWW-Authenticate']) self.handle_unauthorized(request) def handle_unauthorized(self, request): # We are now going to receive data that we want to ignore. # to ignore the file data we're not interested in. self.fail_count.increment() request.channel.set_terminator(None) request["Connection"] = "close" request["WWW-Authenticate"] = 'Basic realm="%s"' % self.realm request.error(401) def make_nonce(self, request): "A digest-authentication , constructed as suggested in RFC 2069" ip = request.channel.server.ip now = str(long(time.time()))[:-1] private_key = str(id(self)) nonce = string.join([ip, now, private_key], ":") return self.apply_hash(nonce) def apply_hash(self, s): "Apply MD5 to a string , then wrap it in base64 encoding." m = hashlib.new() m.update(s) d = m.digest() # base64.encodestring tacks on an extra linefeed. return base64.encodestring(d)[:-1] def status(self): # Thanks to mwm@contessa.phone.net (Mike Meyer) r = [ producers.simple_producer( "
  • Authorization Extension : " "Unauthorized requests: %s
      " % self.fail_count ) ] if hasattr(self.handler, "status"): r.append(self.handler.status()) r.append(producers.simple_producer("
    ")) return producers.composite_producer(http_server.fifo(r)) class dictionary_authorizer: def __init__(self, dict): self.dict = dict def authorize(self, auth_info): [username, password] = auth_info if (username in self.dict) and (self.dict[username] == password): return 1 else: return 0 AUTHORIZATION = re.compile( # scheme challenge "Authorization: ([^ ]+) (.*)", re.IGNORECASE, ) m2crypto-0.46.2/demo/medusa/ca.pem000066400000000000000000000023041506746742300166670ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDWTCCAsKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAxMTIxNTA1NTU0NloXDTA0MTIxNDA1NTU0 NlowgYAxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxML TTJDcnlwdG8gQ0ExJDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3Rl cjEiMCAGCSqGSIb3DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbTCBnzANBgkqhkiG 9w0BAQEFAAOBjQAwgYkCgYEAx8soJbS719LHK62VVVIQeC3oW0HvFArwPnA0LuEK q+LaqMOJg1rS7hvFdX03diV+XJw7cC0iECZYJNG4ii1xbY6KRmufkInaAwm54E3N e+YYVocaqUkcN6xVf6fwnLfPXbpFS/K2Umg11ObKMmi80JmiIdjcjRRCQZC7g1hf q+kCAwEAAaOB4DCB3TAdBgNVHQ4EFgQU6/qcBzEtQphfXLhiOHbt2KqBwMIwga0G A1UdIwSBpTCBooAU6/qcBzEtQphfXLhiOHbt2KqBwMKhgYakgYMwgYAxCzAJBgNV BAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0Ex JDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEiMCAGCSqGSIb3 DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqG SIb3DQEBBAUAA4GBAD+I14GuS5vJmyv1k7mUMbAicsWRHZ+zrGOq9L/L2LsA+lKQ dAzEZE2+Zv8LBPJVltbJJhcFNJS/ZMAjEm4xlJuCpvXVMxd/M5AM29aqekWlIK7J vsdDL8IuzpRkMniUiNKPhmB6IPIOslvUKx6QofcE0wDh6pg4VvIbCjkpZ7gf -----END CERTIFICATE----- m2crypto-0.46.2/demo/medusa/counter.py000066400000000000000000000026741506746742300176440ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- # It is tempting to add an __int__ method to this class, but it's not # a good idea. This class tries to gracefully handle integer # overflow, and to hide this detail from both the programmer and the # user. Note that the __str__ method can be relied on for printing out # the value of a counter: # # >>> print('Total Client: %s' % self.total_clients) # # If you need to do arithmetic with the value, then use the 'as_long' # method, the use of long arithmetic is a reminder that the counter # will overflow. from __future__ import print_function class counter: "general-purpose counter" def __init__(self, initial_value=0): self.value = initial_value def increment(self, delta=1): result = self.value try: self.value = self.value + delta except OverflowError: self.value = long(self.value) + delta return result def decrement(self, delta=1): result = self.value try: self.value = self.value - delta except OverflowError: self.value = long(self.value) - delta return result def as_long(self): return long(self.value) def __nonzero__(self): return self.value != 0 def __repr__(self): return "" % (self.value, id(self)) def __str__(self): return str(long(self.value)) # return str(long(self.value))[:-1] m2crypto-0.46.2/demo/medusa/default_handler.py000066400000000000000000000136271506746742300213060ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- # # Author: Sam Rushing # Copyright 1997 by Sam Rushing # All Rights Reserved. # # standard python modules import os import re import posixpath import stat import string import time # medusa modules import http_date import http_server import mime_type_table import status_handler import producers unquote = http_server.unquote # This is the 'default' handler. it implements the base set of # features expected of a simple file-delivering HTTP server. file # services are provided through a 'filesystem' object, the very same # one used by the FTP server. # # You can replace or modify this handler if you want a non-standard # HTTP server. You can also derive your own handler classes from # it. # # support for handling POST requests is available in the derived # class , defined below. # from counter import counter class default_handler: valid_commands = ["get", "head"] IDENT = "Default HTTP Request Handler" # Pathnames that are tried when a URI resolves to a directory name directory_defaults = ["index.html", "default.html"] default_file_producer = producers.file_producer def __init__(self, filesystem): self.filesystem = filesystem # count total hits self.hit_counter = counter() # count file deliveries self.file_counter = counter() # count cache hits self.cache_counter = counter() hit_counter = 0 def __repr__(self): return "<%s (%s hits) at %x>" % (self.IDENT, self.hit_counter, id(self)) # always match, since this is a default def match(self, request): return 1 # handle a file request, with caching. def handle_request(self, request): if request.command not in self.valid_commands: request.error(400) # bad request return self.hit_counter.increment() path, params, query, fragment = request.split_uri() if "%" in path: path = unquote(path) # strip off all leading slashes while path and path[0] == "/": path = path[1:] if self.filesystem.isdir(path): if path and path[-1] != "/": request["Location"] = "http://%s/%s/" % ( request.channel.server.server_name, path, ) request.error(301) return # we could also generate a directory listing here, # may want to move this into another method for that # purpose found = 0 if path and path[-1] != "/": path = path + "/" for default in self.directory_defaults: p = path + default if self.filesystem.isfile(p): path = p found = 1 break if not found: request.error(404) # Not Found return elif not self.filesystem.isfile(path): request.error(404) # Not Found return file_length = self.filesystem.stat(path)[stat.ST_SIZE] ims = get_header_match(IF_MODIFIED_SINCE, request.header) length_match = 1 if ims: length = ims.group(4) if length: try: length = string.atoi(length) if length != file_length: length_match = 0 except: pass ims_date = 0 if ims: ims_date = http_date.parse_http_date(ims.group(1)) try: mtime = self.filesystem.stat(path)[stat.ST_MTIME] except: request.error(404) return if length_match and ims_date: if mtime <= ims_date: request.reply_code = 304 request.done() self.cache_counter.increment() return try: file = self.filesystem.open(path, "rb") except IOError: request.error(404) return request["Last-Modified"] = http_date.build_http_date(mtime) request["Content-Length"] = file_length self.set_content_type(path, request) if request.command == "get": request.push(self.default_file_producer(file)) self.file_counter.increment() request.done() def set_content_type(self, path, request): ext = string.lower(get_extension(path)) if ext in mime_type_table.content_type_map: request["Content-Type"] = mime_type_table.content_type_map[ext] else: # TODO: test a chunk off the front of the file for 8-bit # characters, and use application/octet-stream instead. request["Content-Type"] = "text/plain" def status(self): return producers.simple_producer( "
  • %s" % status_handler.html_repr(self) + "
      " + "
    • Total Hits: %s" % self.hit_counter + "
    • Files Delivered: %s" % self.file_counter + "
    • Cache Hits: %s" % self.cache_counter + "
    " ) # HTTP/1.0 doesn't say anything about the "; length=nnnn" addition # to this header. I suppose it's purpose is to avoid the overhead # of parsing dates... IF_MODIFIED_SINCE = re.compile( "If-Modified-Since: ([^;]+)((; length=([0-9]+)$)|$)", re.IGNORECASE ) USER_AGENT = re.compile("User-Agent: (.*)", re.IGNORECASE) CONTENT_TYPE = re.compile( r"Content-Type: ([^;]+)((; boundary=([A-Za-z0-9\'\(\)+_,./:=?-]+)$)|$)", re.IGNORECASE, ) get_header = http_server.get_header get_header_match = http_server.get_header_match def get_extension(path): dirsep = string.rfind(path, "/") dotsep = string.rfind(path, ".") if dotsep > dirsep: return path[dotsep + 1 :] else: return "" m2crypto-0.46.2/demo/medusa/dh1024.pem000066400000000000000000000003651506746742300172130ustar00rootroot00000000000000-----BEGIN DH PARAMETERS----- MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq /Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx /mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC -----END DH PARAMETERS----- m2crypto-0.46.2/demo/medusa/filesys.py000066400000000000000000000314441506746742300176400ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- # $Id$ # Author: Sam Rushing # # Generic filesystem interface. # # We want to provide a complete wrapper around any and all # filesystem operations. # this class is really just for documentation, # identifying the API for a filesystem object. # opening files for reading, and listing directories, should # return a producer. from __future__ import print_function class abstract_filesystem: def __init__(self): pass def current_directory(self): "Return a string representing the current directory." pass def listdir(self, path, long=0): """Return a listing of the directory at 'path' The empty string indicates the current directory. If 'long' is set, instead return a list of (name, stat_info) tuples """ pass def open(self, path, mode): "Return an open file object" pass def stat(self, path): "Return the equivalent of os.stat() on the given path." pass def isdir(self, path): "Does the path represent a directory?" pass def isfile(self, path): "Does the path represent a plain file?" pass def cwd(self, path): "Change the working directory." pass def cdup(self): "Change to the parent of the current directory." pass def longify(self, path): """Return a 'long' representation of the filename [for the output of the LIST command]""" pass # standard wrapper around a unix-like filesystem, with a 'false root' # capability. # security considerations: can symbolic links be used to 'escape' the # root? should we allow it? if not, then we could scan the # filesystem on startup, but that would not help if they were added # later. We will probably need to check for symlinks in the cwd method. # what to do if wd is an invalid directory? import os import stat import string def safe_stat(path): try: return (path, os.stat(path)) except: return None import regsub import glob class os_filesystem: path_module = os.path # set this to zero if you want to disable pathname globbing. # [we currently don't glob, anyway] do_globbing = 1 def __init__(self, root, wd="/"): self.root = root self.wd = wd def current_directory(self): return self.wd def isfile(self, path): p = self.normalize(self.path_module.join(self.wd, path)) return self.path_module.isfile(self.translate(p)) def isdir(self, path): p = self.normalize(self.path_module.join(self.wd, path)) return self.path_module.isdir(self.translate(p)) def cwd(self, path): p = self.normalize(self.path_module.join(self.wd, path)) translated_path = self.translate(p) if not self.path_module.isdir(translated_path): return 0 else: old_dir = os.getcwd() # temporarily change to that directory, in order # to see if we have permission to do so. try: can = 0 try: os.chdir(translated_path) can = 1 self.wd = p except: pass finally: if can: os.chdir(old_dir) return can def cdup(self): return self.cwd("..") def listdir(self, path, long=0): p = self.translate(path) # I think we should glob, but limit it to the current # directory only. ld = os.listdir(p) if not long: return list_producer(ld, 0, None) else: old_dir = os.getcwd() try: os.chdir(p) # if os.stat fails we ignore that file. result = filter(None, map(safe_stat, ld)) finally: os.chdir(old_dir) return list_producer(result, 1, self.longify) # TODO: implement a cache w/timeout for stat() def stat(self, path): p = self.translate(path) return os.stat(p) def open(self, path, mode): p = self.translate(path) return open(p, mode) def unlink(self, path): p = self.translate(path) return os.unlink(p) def mkdir(self, path): p = self.translate(path) return os.mkdir(p) def rmdir(self, path): p = self.translate(path) return os.rmdir(p) # utility methods def normalize(self, path): # watch for the ever-sneaky '/+' path element path = regsub.gsub("/+", "/", path) p = self.path_module.normpath(path) # remove 'dangling' cdup's. if len(p) > 2 and p[:3] == "/..": p = "/" return p def translate(self, path): # we need to join together three separate # path components, and do it safely. # // # use the operating system's path separator. path = string.join(string.split(path, "/"), os.sep) p = self.normalize(self.path_module.join(self.wd, path)) p = self.normalize(self.path_module.join(self.root, p[1:])) return p def longify(self, arg_tuple): path, stat_info = arg_tuple return unix_longify(path, stat_info) def __repr__(self): return "" % (self.root, self.wd) if os.name == "posix": class unix_filesystem(os_filesystem): pass class schizophrenic_unix_filesystem(os_filesystem): PROCESS_UID = os.getuid() PROCESS_EUID = os.geteuid() PROCESS_GID = os.getgid() PROCESS_EGID = os.getegid() def __init__(self, root, wd="/", persona=(None, None)): os_filesystem.__init__(self, root, wd) self.persona = persona def become_persona(self): if self.persona is not (None, None): uid, gid = self.persona # the order of these is important! os.setegid(gid) os.seteuid(uid) def become_nobody(self): if self.persona is not (None, None): os.seteuid(self.PROCESS_UID) os.setegid(self.PROCESS_GID) # cwd, cdup, open, listdir def cwd(self, path): try: self.become_persona() return os_filesystem.cwd(self, path) finally: self.become_nobody() def cdup(self, path): try: self.become_persona() return os_filesystem.cdup(self) finally: self.become_nobody() def open(self, filename, mode): try: self.become_persona() return os_filesystem.open(self, filename, mode) finally: self.become_nobody() def listdir(self, path, long=0): try: self.become_persona() return os_filesystem.listdir(self, path, long) finally: self.become_nobody() # This hasn't been very reliable across different platforms. # maybe think about a separate 'directory server'. # # import posixpath # import fcntl # import FCNTL # import select # import asyncore # # # pipes /bin/ls for directory listings. # class unix_filesystem (os_filesystem): # pass # path_module = posixpath # # def listdir (self, path, long=0): # p = self.translate (path) # if not long: # return list_producer (os.listdir (p), 0, None) # else: # command = '/bin/ls -l %s' % p # print('opening pipe to "%s"' % command) # fd = os.popen (command, 'rt') # return pipe_channel (fd) # # # this is both a dispatcher, _and_ a producer # class pipe_channel (asyncore.file_dispatcher): # buffer_size = 4096 # # def __init__ (self, fd): # asyncore.file_dispatcher.__init__ (self, fd) # self.fd = fd # self.done = 0 # self.data = '' # # def handle_read (self): # if len (self.data) < self.buffer_size: # self.data = self.data + self.fd.read (self.buffer_size) # #print('%s.handle_read() => len(self.data) == %d' % (self, len(self.data))) # # def handle_expt (self): # #print('%s.handle_expt()' % self) # self.done = 1 # # def ready (self): # #print('%s.ready() => %d' % (self, len(self.data))) # return ((len (self.data) > 0) or self.done) # # def more (self): # if self.data: # r = self.data # self.data = '' # elif self.done: # self.close() # self.downstream.finished() # r = '' # else: # r = None # #print('%s.more() => %s' % (self, (r and len(r)))) # return r # For the 'real' root, we could obtain a list of drives, and then # use that. Doesn't win32 provide such a 'real' filesystem? # [yes, I think something like this "\\.\c\windows"] class msdos_filesystem(os_filesystem): def longify(self, arg_tuple): path, stat_info = arg_tuple return msdos_longify(path, stat_info) # A merged filesystem will let you plug other filesystems together. # We really need the equivalent of a 'mount' capability - this seems # to be the most general idea. So you'd use a 'mount' method to place # another filesystem somewhere in the hierarchy. # Note: this is most likely how I will handle ~user directories # with the http server. class merged_filesystem: def __init__(self, *fsys): pass # this matches the output of NT's ftp server (when in # MSDOS mode) exactly. def msdos_longify(file, stat_info): if stat.S_ISDIR(stat_info[stat.ST_MODE]): dir = "" else: dir = " " date = msdos_date(stat_info[stat.ST_MTIME]) return "%s %s %8d %s" % (date, dir, stat_info[stat.ST_SIZE], file) def msdos_date(t): try: info = time.gmtime(t) except: info = time.gmtime(0) # year, month, day, hour, minute, second, ... if info[3] > 11: merid = "PM" info[3] = info[3] - 12 else: merid = "AM" return "%02d-%02d-%02d %02d:%02d%s" % ( info[1], info[2], info[0] % 100, info[3], info[4], merid, ) months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ] mode_table = { "0": "---", "1": "--x", "2": "-w-", "3": "-wx", "4": "r--", "5": "r-x", "6": "rw-", "7": "rwx", } import time def unix_longify(file, stat_info): # for now, only pay attention to the lower bits mode = ("%o" % stat_info[stat.ST_MODE])[-3:] mode = string.join(map(lambda x: mode_table[x], mode), "") if stat.S_ISDIR(stat_info[stat.ST_MODE]): dirchar = "d" else: dirchar = "-" date = ls_date(long(time.time()), stat_info[stat.ST_MTIME]) return "%s%s %3d %-8d %-8d %8d %s %s" % ( dirchar, mode, stat_info[stat.ST_NLINK], stat_info[stat.ST_UID], stat_info[stat.ST_GID], stat_info[stat.ST_SIZE], date, file, ) # Emulate the unix 'ls' command's date field. # it has two formats - if the date is more than 180 # days in the past, then it's like this: # Oct 19 1995 # otherwise, it looks like this: # Oct 19 17:33 def ls_date(now, t): try: info = time.gmtime(t) except: info = time.gmtime(0) # 15,600,000 == 86,400 * 180 if (now - t) > 15600000: return "%s %2d %d" % (months[info[1] - 1], info[2], info[0]) else: return "%s %2d %02d:%02d" % (months[info[1] - 1], info[2], info[3], info[4]) # =========================================================================== # Producers # =========================================================================== class list_producer: def __init__(self, file_list, long, longify): self.file_list = file_list self.long = long self.longify = longify self.done = 0 def ready(self): if len(self.file_list): return 1 else: if not self.done: self.done = 1 return 0 return len(self.file_list) > 0 # this should do a pushd/popd def more(self): if not self.file_list: return "" else: # do a few at a time bunch = self.file_list[:50] if self.long: bunch = map(self.longify, bunch) self.file_list = self.file_list[50:] return string.joinfields(bunch, "\r\n") + "\r\n" m2crypto-0.46.2/demo/medusa/ftp_server.py000066400000000000000000001114571506746742300203440ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- # Author: Sam Rushing # Copyright 1996-2000 by Sam Rushing # All Rights Reserved. # # An extensible, configurable, asynchronous FTP server. # # All socket I/O is non-blocking, however file I/O is currently # blocking. Eventually file I/O may be made non-blocking, too, if it # seems necessary. Currently the only CPU-intensive operation is # getting and formatting a directory listing. [this could be moved # into another process/directory server, or another thread?] # # Only a subset of RFC 959 is implemented, but much of that RFC is # vestigial anyway. I've attempted to include the most commonly-used # commands, using the feature set of wu-ftpd as a guide. from __future__ import print_function import asyncore import asynchat import os import regsub import socket import stat import string import sys import time # TODO: implement a directory listing cache. On very-high-load # servers this could save a lot of disk abuse, and possibly the # work of computing emulated unix ls output. # Potential security problem with the FTP protocol? I don't think # there's any verification of the origin of a data connection. Not # really a problem for the server (since it doesn't send the port # command, except when in PASV mode) But I think a data connection # could be spoofed by a program with access to a sniffer - it could # watch for a PORT command to go over a command channel, and then # connect to that port before the server does. # Unix user id's: # In order to support assuming the id of a particular user, # it seems there are two options: # 1) fork, and seteuid in the child # 2) carefully control the effective uid around filesystem accessing # methods, using try/finally. [this seems to work] VERSION = "1.1" from counter import counter import producers import status_handler import logger import string class ftp_channel(asynchat.async_chat): # defaults for a reliable __repr__ addr = ("unknown", "0") # unset this in a derived class in order # to enable the commands in 'self.write_commands' read_only = 1 write_commands = ["appe", "dele", "mkd", "rmd", "rnfr", "rnto", "stor", "stou"] restart_position = 0 # comply with (possibly troublesome) RFC959 requirements # This is necessary to correctly run an active data connection # through a firewall that triggers on the source port (expected # to be 'L-1', or 20 in the normal case). bind_local_minus_one = 0 def __init__(self, server, conn, addr): self.server = server self.current_mode = "a" self.addr = addr asynchat.async_chat.__init__(self, conn) self.set_terminator("\r\n") # client data port. Defaults to 'the same as the control connection'. self.client_addr = (addr[0], 21) self.client_dc = None self.in_buffer = "" self.closing = 0 self.passive_acceptor = None self.passive_connection = None self.filesystem = None self.authorized = 0 # send the greeting self.respond( "220 %s FTP server (Medusa Async V%s [experimental]) ready." % (self.server.hostname, VERSION) ) # def __del__ (self): # print('ftp_channel.__del__()') # -------------------------------------------------- # async-library methods # -------------------------------------------------- def handle_expt(self): # this is handled below. not sure what I could # do here to make that code less kludgish. pass def collect_incoming_data(self, data): self.in_buffer = self.in_buffer + data if len(self.in_buffer) > 4096: # silently truncate really long lines # (possible denial-of-service attack) self.in_buffer = "" def found_terminator(self): line = self.in_buffer if not len(line): return sp = string.find(line, " ") if sp != -1: line = [line[:sp], line[sp + 1 :]] else: line = [line] command = string.lower(line[0]) # watch especially for 'urgent' abort commands. if string.find(command, "abor") != -1: # strip off telnet sync chars and the like... while command and command[0] not in string.letters: command = command[1:] fun_name = "cmd_%s" % command if command != "pass": self.log("<== %s" % repr(self.in_buffer)[1:-1]) else: self.log("<== %s" % line[0] + " ") self.in_buffer = "" if not hasattr(self, fun_name): self.command_not_understood(line[0]) return fun = getattr(self, fun_name) if (not self.authorized) and (command not in ("user", "pass", "help", "quit")): self.respond("530 Please log in with USER and PASS") elif not self.check_command_authorization(command): self.command_not_authorized(command) else: try: result = apply(fun, (line,)) except: self.server.total_exceptions.increment() (file, fun, line), t, v, tbinfo = asyncore.compact_traceback() if self.client_dc: try: self.client_dc.close() except: pass self.respond( "451 Server Error: %s, %s: file: %s line: %s" % ( t, v, file, line, ) ) closed = 0 def close(self): if not self.closed: self.closed = 1 if self.passive_acceptor: self.passive_acceptor.close() if self.client_dc: self.client_dc.close() self.server.closed_sessions.increment() asynchat.async_chat.close(self) # -------------------------------------------------- # filesystem interface functions. # override these to provide access control or perform # other functions. # -------------------------------------------------- def cwd(self, line): return self.filesystem.cwd(line[1]) def cdup(self, line): return self.filesystem.cdup() def open(self, path, mode): return self.filesystem.open(path, mode) # returns a producer def listdir(self, path, long=0): return self.filesystem.listdir(path, long) def get_dir_list(self, line, long=0): # we need to scan the command line for arguments to '/bin/ls'... args = line[1:] path_args = [] for arg in args: if arg[0] != "-": path_args.append(arg) else: # ignore arguments pass if len(path_args) < 1: dir = "." else: dir = path_args[0] return self.listdir(dir, long) # -------------------------------------------------- # authorization methods # -------------------------------------------------- def check_command_authorization(self, command): if command in self.write_commands and self.read_only: return 0 else: return 1 # -------------------------------------------------- # utility methods # -------------------------------------------------- def log(self, message): self.server.logger.log(self.addr[0], "%d %s" % (self.addr[1], message)) def respond(self, resp): self.log("==> %s" % resp) self.push(resp + "\r\n") def command_not_understood(self, command): self.respond("500 '%s': command not understood." % command) def command_not_authorized(self, command): self.respond( "530 You are not authorized to perform the '%s' command" % (command) ) def make_xmit_channel(self): # In PASV mode, the connection may or may _not_ have been made # yet. [although in most cases it is... FTP Explorer being # the only exception I've yet seen]. This gets somewhat confusing # because things may happen in any order... pa = self.passive_acceptor if pa: if pa.ready: # a connection has already been made. conn, addr = self.passive_acceptor.ready cdc = xmit_channel(self, addr) cdc.set_socket(conn) cdc.connected = 1 self.passive_acceptor.close() self.passive_acceptor = None else: # we're still waiting for a connect to the PASV port. cdc = xmit_channel(self) else: # not in PASV mode. ip, port = self.client_addr cdc = xmit_channel(self, self.client_addr) cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) if self.bind_local_minus_one: cdc.bind(("", self.server.port - 1)) try: cdc.connect((ip, port)) except socket.error as why: self.respond("425 Can't build data connection") self.client_dc = cdc # pretty much the same as xmit, but only right on the verge of # being worth a merge. def make_recv_channel(self, fd): pa = self.passive_acceptor if pa: if pa.ready: # a connection has already been made. conn, addr = pa.ready cdc = recv_channel(self, addr, fd) cdc.set_socket(conn) cdc.connected = 1 self.passive_acceptor.close() self.passive_acceptor = None else: # we're still waiting for a connect to the PASV port. cdc = recv_channel(self, None, fd) else: # not in PASV mode. ip, port = self.client_addr cdc = recv_channel(self, self.client_addr, fd) cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) try: cdc.connect((ip, port)) except socket.error as why: self.respond("425 Can't build data connection") self.client_dc = cdc type_map = {"a": "ASCII", "i": "Binary", "e": "EBCDIC", "l": "Binary"} type_mode_map = {"a": "t", "i": "b", "e": "b", "l": "b"} # -------------------------------------------------- # command methods # -------------------------------------------------- def cmd_type(self, line): "specify data transfer type" # ascii, ebcdic, image, local t = string.lower(line[1]) # no support for EBCDIC # if t not in ['a','e','i','l']: if t not in ["a", "i", "l"]: self.command_not_understood(string.join(line)) elif t == "l" and (len(line) > 2 and line[2] != "8"): self.respond("504 Byte size must be 8") else: self.current_mode = t self.respond("200 Type set to %s." % self.type_map[t]) def cmd_quit(self, line): "terminate session" self.respond("221 Goodbye.") self.close_when_done() def cmd_port(self, line): "specify data connection port" info = string.split(line[1], ",") ip = string.join(info[:4], ".") port = string.atoi(info[4]) * 256 + string.atoi(info[5]) # how many data connections at a time? # I'm assuming one for now... # TODO: we should (optionally) verify that the # ip number belongs to the client. [wu-ftpd does this?] self.client_addr = (ip, port) self.respond("200 PORT command successful.") def new_passive_acceptor(self): # ensure that only one of these exists at a time. if self.passive_acceptor is not None: self.passive_acceptor.close() self.passive_acceptor = None self.passive_acceptor = passive_acceptor(self) return self.passive_acceptor def cmd_pasv(self, line): "prepare for server-to-server transfer" pc = self.new_passive_acceptor() port = pc.addr[1] ip_addr = pc.control_channel.getsockname()[0] self.respond( "227 Entering Passive Mode (%s,%d,%d)" % (string.join(string.split(ip_addr, "."), ","), port / 256, port % 256) ) self.client_dc = None def cmd_nlst(self, line): "give name list of files in directory" # ncftp adds the -FC argument for the user-visible 'nlist' # command. We could try to emulate ls flags, but not just yet. if "-FC" in line: line.remove("-FC") try: dir_list_producer = self.get_dir_list(line, 0) except os.error as why: self.respond("550 Could not list directory: %s" % repr(why)) return self.respond( "150 Opening %s mode data connection for file list" % (self.type_map[self.current_mode]) ) self.make_xmit_channel() self.client_dc.push_with_producer(dir_list_producer) self.client_dc.close_when_done() def cmd_list(self, line): "give list files in a directory" try: dir_list_producer = self.get_dir_list(line, 1) except os.error as why: self.respond("550 Could not list directory: %s" % repr(why)) return self.respond( "150 Opening %s mode data connection for file list" % (self.type_map[self.current_mode]) ) self.make_xmit_channel() self.client_dc.push_with_producer(dir_list_producer) self.client_dc.close_when_done() def cmd_cwd(self, line): "change working directory" if self.cwd(line): self.respond("250 CWD command successful.") else: self.respond("550 No such directory.") def cmd_cdup(self, line): "change to parent of current working directory" if self.cdup(line): self.respond("250 CDUP command successful.") else: self.respond("550 No such directory.") def cmd_pwd(self, line): "print the current working directory" self.respond( '257 "%s" is the current directory.' % (self.filesystem.current_directory()) ) # modification time # example output: # 213 19960301204320 def cmd_mdtm(self, line): "show last modification time of file" filename = line[1] if not self.filesystem.isfile(filename): self.respond('550 "%s" is not a file' % filename) else: mtime = time.gmtime(self.filesystem.stat(filename)[stat.ST_MTIME]) self.respond( "213 %4d%02d%02d%02d%02d%02d" % (mtime[0], mtime[1], mtime[2], mtime[3], mtime[4], mtime[5]) ) def cmd_noop(self, line): "do nothing" self.respond("200 NOOP command successful.") def cmd_size(self, line): "return size of file" filename = line[1] if not self.filesystem.isfile(filename): self.respond('550 "%s" is not a file' % filename) else: self.respond("213 %d" % (self.filesystem.stat(filename)[stat.ST_SIZE])) def cmd_retr(self, line): "retrieve a file" if len(line) < 2: self.command_not_understood(string.join(line)) else: file = line[1] if not self.filesystem.isfile(file): self.log_info("checking %s" % file) self.respond("550 No such file") else: try: # FIXME: for some reason, 'rt' isn't working on win95 mode = "r" + self.type_mode_map[self.current_mode] fd = self.open(file, mode) except IOError as why: self.respond( "553 could not open file for reading: %s" % (repr(why)) ) return self.respond( "150 Opening %s mode data connection for file '%s'" % (self.type_map[self.current_mode], file) ) self.make_xmit_channel() if self.restart_position: # try to position the file as requested, but # give up silently on failure (the 'file object' # may not support seek()) try: fd.seek(self.restart_position) except: pass self.restart_position = 0 self.client_dc.push_with_producer( file_producer(self, self.client_dc, fd) ) self.client_dc.close_when_done() def cmd_stor(self, line, mode="wb"): "store a file" if len(line) < 2: self.command_not_understood(string.join(line)) else: if self.restart_position: restart_position = 0 self.respond("553 restart on STOR not yet supported") return file = line[1] # todo: handle that type flag try: fd = self.open(file, mode) except IOError as why: self.respond("553 could not open file for writing: %s" % (repr(why))) return self.respond( "150 Opening %s connection for %s" % (self.type_map[self.current_mode], file) ) self.make_recv_channel(fd) def cmd_abor(self, line): "abort operation" if self.client_dc: self.client_dc.close() self.respond("226 ABOR command successful.") def cmd_appe(self, line): "append to a file" return self.cmd_stor(line, "ab") def cmd_dele(self, line): if len(line) != 2: self.command_not_understood(string.join(line)) else: file = line[1] if self.filesystem.isfile(file): try: self.filesystem.unlink(file) self.respond("250 DELE command successful.") except: self.respond("550 error deleting file.") else: self.respond("550 %s: No such file." % file) def cmd_mkd(self, line): if len(line) != 2: self.command.not_understood(string.join(line)) else: path = line[1] try: self.filesystem.mkdir(path) self.respond("257 MKD command successful.") except: self.respond("550 error creating directory.") def cmd_rmd(self, line): if len(line) != 2: self.command.not_understood(string.join(line)) else: path = line[1] try: self.filesystem.rmdir(path) self.respond("250 RMD command successful.") except: self.respond("550 error removing directory.") def cmd_user(self, line): "specify user name" if len(line) > 1: self.user = line[1] self.respond("331 Password required.") else: self.command_not_understood(string.join(line)) def cmd_pass(self, line): "specify password" if len(line) < 2: pw = "" else: pw = line[1] result, message, fs = self.server.authorizer.authorize(self, self.user, pw) if result: self.respond("230 %s" % message) self.filesystem = fs self.authorized = 1 self.log_info("Successful login: Filesystem=%s" % repr(fs)) else: self.respond("530 %s" % message) def cmd_rest(self, line): "restart incomplete transfer" try: pos = string.atoi(line[1]) except ValueError: self.command_not_understood(string.join(line)) self.restart_position = pos self.respond( "350 Restarting at %d. Send STORE or RETRIEVE to initiate transfer." % pos ) def cmd_stru(self, line): "obsolete - set file transfer structure" if line[1] in "fF": # f == 'file' self.respond("200 STRU F Ok") else: self.respond("504 Unimplemented STRU type") def cmd_mode(self, line): "obsolete - set file transfer mode" if line[1] in "sS": # f == 'file' self.respond("200 MODE S Ok") else: self.respond("502 Unimplemented MODE type") # The stat command has two personalities. Normally it returns status # information about the current connection. But if given an argument, # it is equivalent to the LIST command, with the data sent over the # control connection. Strange. But wuftpd, ftpd, and nt's ftp server # all support it. # ## def cmd_stat (self, line): ## 'return status of server' ## pass def cmd_syst(self, line): "show operating system type of server system" # Replying to this command is of questionable utility, because # this server does not behave in a predictable way w.r.t. the # output of the LIST command. We emulate Unix ls output, but # on win32 the pathname can contain drive information at the front # Currently, the combination of ensuring that os.sep == '/' # and removing the leading slash when necessary seems to work. # [cd'ing to another drive also works] # # This is how wuftpd responds, and is probably # the most expected. The main purpose of this reply is so that # the client knows to expect Unix ls-style LIST output. self.respond("215 UNIX Type: L8") # one disadvantage to this is that some client programs # assume they can pass args to /bin/ls. # a few typical responses: # 215 UNIX Type: L8 (wuftpd) # 215 Windows_NT version 3.51 # 215 VMS MultiNet V3.3 # 500 'SYST': command not understood. (SVR4) def cmd_help(self, line): "give help information" # find all the methods that match 'cmd_xxxx', # use their docstrings for the help response. attrs = dir(self.__class__) help_lines = [] for attr in attrs: if attr[:4] == "cmd_": x = getattr(self, attr) if type(x) == type(self.cmd_help): if x.__doc__: help_lines.append("\t%s\t%s" % (attr[4:], x.__doc__)) if help_lines: self.push("214-The following commands are recognized\r\n") self.push_with_producer(producers.lines_producer(help_lines)) self.push("214\r\n") else: self.push("214-\r\n\tHelp Unavailable\r\n214\r\n") class ftp_server(asyncore.dispatcher): # override this to spawn a different FTP channel class. ftp_channel_class = ftp_channel SERVER_IDENT = "FTP Server (V%s)" % VERSION def __init__( self, authorizer, hostname=None, ip="", port=21, resolver=None, logger_object=logger.file_logger(sys.stdout), ): self.ip = ip self.port = port self.authorizer = authorizer if hostname is None: self.hostname = socket.gethostname() else: self.hostname = hostname # statistics self.total_sessions = counter() self.closed_sessions = counter() self.total_files_out = counter() self.total_files_in = counter() self.total_bytes_out = counter() self.total_bytes_in = counter() self.total_exceptions = counter() # asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() self.bind((self.ip, self.port)) self.listen(5) if not logger_object: logger_object = sys.stdout if resolver: self.logger = logger.resolving_logger(resolver, logger_object) else: self.logger = logger.unresolving_logger(logger_object) self.log_info( "FTP server started at %s\n\tAuthorizer:%s\n\tHostname: %s\n\tPort: %d" % (time.ctime(time.time()), repr(self.authorizer), self.hostname, self.port) ) def writable(self): return 0 def handle_read(self): pass def handle_connect(self): pass def handle_accept(self): conn, addr = self.accept() self.total_sessions.increment() self.log_info("Incoming connection from %s:%d" % (addr[0], addr[1])) self.ftp_channel_class(self, conn, addr) # return a producer describing the state of the server def status(self): def nice_bytes(n): return string.join(status_handler.english_bytes(n)) return producers.lines_producer( [ "

    %s

    " % self.SERVER_IDENT, "
    Listening on Host: %s" % self.hostname, "Port: %d" % self.port, "
    Sessions", "Total: %s" % self.total_sessions, "Current: %d" % (self.total_sessions.as_long() - self.closed_sessions.as_long()), "
    Files", "Sent: %s" % self.total_files_out, "Received: %s" % self.total_files_in, "
    Bytes", "Sent: %s" % nice_bytes(self.total_bytes_out.as_long()), "Received: %s" % nice_bytes(self.total_bytes_in.as_long()), "
    Exceptions: %s" % self.total_exceptions, ] ) # ====================================================================== # Data Channel Classes # ====================================================================== # This socket accepts a data connection, used when the server has been # placed in passive mode. Although the RFC implies that we ought to # be able to use the same acceptor over and over again, this presents # a problem: how do we shut it off, so that we are accepting # connections only when we expect them? [we can't] # # wuftpd, and probably all the other servers, solve this by allowing # only one connection to hit this acceptor. They then close it. Any # subsequent data-connection command will then try for the default # port on the client side [which is of course never there]. So the # 'always-send-PORT/PASV' behavior seems required. # # Another note: wuftpd will also be listening on the channel as soon # as the PASV command is sent. It does not wait for a data command # first. # --- we need to queue up a particular behavior: # 1) xmit : queue up producer[s] # 2) recv : the file object # # It would be nice if we could make both channels the same. Hmmm.. # class passive_acceptor(asyncore.dispatcher): ready = None def __init__(self, control_channel): # connect_fun (conn, addr) asyncore.dispatcher.__init__(self) self.control_channel = control_channel self.create_socket(socket.AF_INET, socket.SOCK_STREAM) # bind to an address on the interface that the # control connection is coming from. self.bind((self.control_channel.getsockname()[0], 0)) self.addr = self.getsockname() self.listen(1) # def __del__ (self): # print('passive_acceptor.__del__()') def log(self, *ignore): pass def handle_accept(self): conn, addr = self.accept() dc = self.control_channel.client_dc if dc is not None: dc.set_socket(conn) dc.addr = addr dc.connected = 1 self.control_channel.passive_acceptor = None else: self.ready = conn, addr self.close() class xmit_channel(asynchat.async_chat): # for an ethernet, you want this to be fairly large, in fact, it # _must_ be large for performance comparable to an ftpd. [64k] we # ought to investigate automatically-sized buffers... ac_out_buffer_size = 16384 bytes_out = 0 def __init__(self, channel, client_addr=None): self.channel = channel self.client_addr = client_addr asynchat.async_chat.__init__(self) # def __del__ (self): # print('xmit_channel.__del__()') def log(*args): pass def readable(self): return not self.connected def writable(self): return 1 def send(self, data): result = asynchat.async_chat.send(self, data) self.bytes_out = self.bytes_out + result return result def handle_error(self): # usually this is to catch an unexpected disconnect. self.log_info("unexpected disconnect on data xmit channel", "error") try: self.close() except: pass # TODO: there's a better way to do this. we need to be able to # put 'events' in the producer fifo. to do this cleanly we need # to reposition the 'producer' fifo as an 'event' fifo. def close(self): c = self.channel s = c.server c.client_dc = None s.total_files_out.increment() s.total_bytes_out.increment(self.bytes_out) if not len(self.producer_fifo): c.respond("226 Transfer complete") elif not c.closed: c.respond("426 Connection closed; transfer aborted") del c del s del self.channel asynchat.async_chat.close(self) class recv_channel(asyncore.dispatcher): def __init__(self, channel, client_addr, fd): self.channel = channel self.client_addr = client_addr self.fd = fd asyncore.dispatcher.__init__(self) self.bytes_in = counter() def log(self, *ignore): pass def handle_connect(self): pass def writable(self): return 0 def recv(*args): result = apply(asyncore.dispatcher.recv, args) self = args[0] self.bytes_in.increment(len(result)) return result buffer_size = 8192 def handle_read(self): block = self.recv(self.buffer_size) if block: try: self.fd.write(block) except IOError: self.log_info("got exception writing block...", "error") def handle_close(self): s = self.channel.server s.total_files_in.increment() s.total_bytes_in.increment(self.bytes_in.as_long()) self.fd.close() self.channel.respond("226 Transfer complete.") self.close() import filesys # not much of a doorman! 8^) class dummy_authorizer: def __init__(self, root="/"): self.root = root def authorize(self, channel, username, password): channel.persona = -1, -1 channel.read_only = 1 return 1, "Ok.", filesys.os_filesystem(self.root) class anon_authorizer: def __init__(self, root="/"): self.root = root def authorize(self, channel, username, password): if username in ("ftp", "anonymous"): channel.persona = -1, -1 channel.read_only = 1 return 1, "Ok.", filesys.os_filesystem(self.root) else: return 0, "Password invalid.", None # =========================================================================== # Unix-specific improvements # =========================================================================== if os.name == "posix": class unix_authorizer: # return a trio of (success, reply_string, filesystem) def authorize(self, channel, username, password): import crypt import pwd try: info = pwd.getpwnam(username) except KeyError: return 0, "No such user.", None mangled = info[1] if crypt.crypt(password, mangled[:2]) == mangled: channel.read_only = 0 fs = filesys.schizophrenic_unix_filesystem( "/", info[5], persona=(info[2], info[3]) ) return 1, "Login successful.", fs else: return 0, "Password invalid.", None def __repr__(self): return "" # simple anonymous ftp support class unix_authorizer_with_anonymous(unix_authorizer): def __init__(self, root=None, real_users=0): self.root = root self.real_users = real_users def authorize(self, channel, username, password): if string.lower(username) in ["anonymous", "ftp"]: import pwd try: # ok, here we run into lots of confusion. # on some os', anon runs under user 'nobody', # on others as 'ftp'. ownership is also critical. # need to investigate. # linux: new linuxen seem to have nobody's UID=-1, # which is an illegal value. Use ftp. ftp_user_info = pwd.getpwnam("ftp") if string.lower(os.uname()[0]) == "linux": nobody_user_info = pwd.getpwnam("ftp") else: nobody_user_info = pwd.getpwnam("nobody") channel.read_only = 1 if self.root is None: self.root = ftp_user_info[5] fs = filesys.unix_filesystem(self.root, "/") return 1, "Anonymous Login Successful", fs except KeyError: return 0, "Anonymous account not set up", None elif self.real_users: return unix_authorizer.authorize(self, channel, username, password) else: return 0, "User logins not allowed", None class file_producer: block_size = 16384 def __init__(self, server, dc, fd): self.fd = fd self.done = 0 def more(self): if self.done: return "" else: block = self.fd.read(self.block_size) if not block: self.fd.close() self.done = 1 return block # usage: ftp_server /PATH/TO/FTP/ROOT PORT # for example: # $ ftp_server /home/users/ftp 8021 if os.name == "posix": def test(port="8021"): import sys fs = ftp_server(unix_authorizer(), port=string.atoi(port)) try: asyncore.loop() except KeyboardInterrupt: self.log_info("FTP server shutting down. (received SIGINT)", "warning") # close everything down on SIGINT. # of course this should be a cleaner shutdown. asyncore.close_all() if __name__ == "__main__": test(sys.argv[1]) # not unix else: def test(): fs = ftp_server(dummy_authorizer()) if __name__ == "__main__": test() # this is the command list from the wuftpd man page # '*' means we've implemented it. # '!' requires write access # command_documentation = { "abor": "abort previous command", # * "acct": "specify account (ignored)", "allo": "allocate storage (vacuously)", "appe": "append to a file", # *! "cdup": "change to parent of current working directory", # * "cwd": "change working directory", # * "dele": "delete a file", #! "help": "give help information", # * "list": "give list files in a directory", # * "mkd": "make a directory", #! "mdtm": "show last modification time of file", # * "mode": "specify data transfer mode", "nlst": "give name list of files in directory", # * "noop": "do nothing", # * "pass": "specify password", # * "pasv": "prepare for server-to-server transfer", # * "port": "specify data connection port", # * "pwd": "print the current working directory", # * "quit": "terminate session", # * "rest": "restart incomplete transfer", # * "retr": "retrieve a file", # * "rmd": "remove a directory", #! "rnfr": "specify rename-from file name", #! "rnto": "specify rename-to file name", #! "site": "non-standard commands (see next section)", "size": "return size of file", # * "stat": "return status of server", # * "stor": "store a file", # *! "stou": "store a file with a unique name", #! "stru": "specify data transfer structure", "syst": "show operating system type of server system", # * "type": "specify data transfer type", # * "user": "specify user name", # * "xcup": "change to parent of current working directory (deprecated)", "xcwd": "change working directory (deprecated)", "xmkd": "make a directory (deprecated)", #! "xpwd": "print the current working directory (deprecated)", "xrmd": "remove a directory (deprecated)", #! } # debugging aid (linux) def get_vm_size(): return string.atoi(string.split(open("/proc/self/stat").readline())[22]) def print_vm(): print("vm: %8dk" % (get_vm_size() / 1024)) m2crypto-0.46.2/demo/medusa/ftps_server.py000066400000000000000000000360521506746742300205240ustar00rootroot00000000000000"""An FTP/TLS server built on Medusa's ftp_server. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" # Python import socket, string, sys, time # Medusa from counter import counter import asynchat, asyncore, ftp_server, logger # M2Crypto from M2Crypto import SSL VERSION_STRING = "0.09" class ftp_tls_channel(ftp_server.ftp_channel): """FTP/TLS server channel for Medusa.""" def __init__(self, server, ssl_ctx, conn, addr): """Initialise the channel.""" self.ssl_ctx = ssl_ctx self.server = server self.current_mode = "a" self.addr = addr asynchat.async_chat.__init__(self, conn) self.set_terminator("\r\n") self.client_addr = (addr[0], 21) self.client_dc = None self.in_buffer = "" self.closing = 0 self.passive_acceptor = None self.passive_connection = None self.filesystem = None self.authorized = 0 self._ssl_accepting = 0 self._ssl_accepted = 0 self._pbsz = None self._prot = None resp = "220 %s M2Crypto (Medusa) FTP/TLS server v%s ready." self.respond(resp % (self.server.hostname, VERSION_STRING)) def writable(self): return self._ssl_accepting or self._ssl_accepted def handle_read(self): """Handle a read event.""" if self._ssl_accepting: self._ssl_accepted = self.socket.accept_ssl() if self._ssl_accepted: self._ssl_accepting = 0 else: try: ftp_server.ftp_channel.handle_read(self) except SSL.SSLError as what: if str(what) == "unexpected eof": self.close() else: raise def handle_write(self): """Handle a write event.""" if self._ssl_accepting: self._ssl_accepted = self.socket.accept_ssl() if self._ssl_accepted: self._ssl_accepting = 0 else: try: ftp_server.ftp_channel.handle_write(self) except SSL.SSLError as what: if str(what) == "unexpected eof": self.close() else: raise def send(self, data): """Send data over SSL.""" try: result = self.socket.send(data) if result <= 0: return 0 else: return result except SSL.SSLError as what: self.close() self.log_info("send: closing channel %s %s" % (repr(self), what)) return 0 def recv(self, buffer_size): """Receive data over SSL.""" try: result = self.socket.recv(buffer_size) if not result: return "" else: return result except SSL.SSLError as what: self.close() self.log_info("recv: closing channel %s %s" % (repr(self), what)) return "" def found_terminator(self): """Dispatch the FTP command.""" line = self.in_buffer if not len(line): return sp = string.find(line, " ") if sp != -1: line = [line[:sp], line[sp + 1 :]] else: line = [line] command = string.lower(line[0]) if string.find(command, "stor") != -1: while command and command[0] not in string.letters: command = command[1:] func_name = "cmd_%s" % command if command != "pass": self.log("<== %s" % repr(self.in_buffer)[1:-1]) else: self.log("<== %s" % line[0] + " ") self.in_buffer = "" if not hasattr(self, func_name): self.command_not_understood(line[0]) return func = getattr(self, func_name) if not self.check_command_authorization(command): self.command_not_authorized(command) else: try: result = apply(func, (line,)) except: self.server.total_exceptions.increment() (file, func, line), t, v, tbinfo = asyncore.compact_traceback() if self.client_dc: try: self.client_dc_close() except: pass resp = "451 Server error: %s, %s: file %s line: %s" self.respond(resp % (t, v, file, line)) def make_xmit_channel(self): """Create a connection for sending data.""" pa = self.passive_acceptor if pa: if pa.ready: conn, addr = pa.ready if self._prot: cdc = tls_xmit_channel(self, conn, self.ssl_ctx, addr) else: cdc = ftp_server.xmit_channel(self, addr) cdc.set_socket(conn) cdc.connected = 1 self.passive_acceptor.close() self.passive_acceptor = None else: if self._prot: cdc = tls_xmit_channel(self, None, self.ssl_ctx, None) else: cdc = ftp_server.xmit_channel(self) else: if self._prot: cdc = tls_xmit_channel(self, None, self.ssl_ctx, self.client_addr) else: cdc = ftp_server.xmit_channel(self, self.client_addr) cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) if self.bind_local_minus_one: cdc.bind(("", self.server.port - 1)) try: cdc.connect(self.client_addr) except socket.error as what: self.respond("425 Cannot build data connection") self.client_dc = cdc def make_recv_channel(self, fd): """Create a connection for receiving data.""" pa = self.passive_acceptor if pa: if pa.ready: conn, addr = pa.ready if self._prot: cdc = tls_recv_channel(self, conn, self.ssl_ctx, addr, fd) else: cdc = ftp_server.recv_channel(self, addr, fd) cdc.set_socket(conn) cdc.connected = 1 self.passive_acceptor.close() self.passive_acceptor = None else: if self._prot: cdc = tls_recv_channel(self, None, self.ssl_ctx, None, fd) else: cdc = ftp_server.recv_channel(self, None, fd) else: if self._prot: cdc = tls_recv_channel( self, None, self.ssl_ctx, self._prot, self.client_addr, fd ) else: cdc = ftp_server.recv_channel(self, self.client_addr, fd) cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) try: cdc.connect(self.client_addr) except socket.error as what: self.respond("425 Cannot build data connection") self.client_dc = cdc def cmd_auth(self, line): """Prepare for TLS operation.""" # XXX Handle variations. if line[1] != "TLS": self.command_not_understood(string.join(line)) else: self.respond("234 AUTH TLS successful") self._ssl_accepting = 1 self.socket = SSL.Connection(self.ssl_ctx, self.socket) self.socket.setup_addr(self.addr) self.socket.setup_ssl() self.socket.set_accept_state() self._ssl_accepted = self.socket.accept_ssl() if self._ssl_accepted: self._ssl_accepting = 0 def cmd_pbsz(self, line): """Negotiate size of buffer for secure data transfer. For FTP/TLS the only valid value for the parameter is '0'; any other value is accepted but ignored.""" if not (self._ssl_accepting or self._ssl_accepted): return self.respond("503 AUTH TLS must be issued prior to PBSZ") self._pbsz = 1 self.respond("200 PBSZ=0 successful.") def cmd_prot(self, line): """Negotiate the security level of the data connection.""" if self._pbsz is None: return self.respond("503 PBSZ must be issued prior to PROT") if line[1] == "C": self.respond("200 Protection set to Clear") self._pbsz = None self._prot = None elif line[1] == "P": self.respond("200 Protection set to Private") self._prot = 1 elif line[1] in ("S", "E"): self.respond("536 PROT %s unsupported" % line[1]) else: self.respond("504 PROT %s unsupported" % line[1]) class ftp_tls_server(ftp_server.ftp_server): """FTP/TLS server for Medusa.""" SERVER_IDENT = "M2Crypto FTP/TLS Server (v%s)" % VERSION_STRING ftp_channel_class = ftp_tls_channel def __init__( self, authz, ssl_ctx, host=None, ip="", port=21, resolver=None, log_obj=None ): """Initialise the server.""" self.ssl_ctx = ssl_ctx self.ip = ip self.port = port self.authorizer = authz if host is None: self.hostname = socket.gethostname() else: self.hostname = host self.total_sessions = counter() self.closed_sessions = counter() self.total_files_out = counter() self.total_files_in = counter() self.total_bytes_out = counter() self.total_bytes_in = counter() self.total_exceptions = counter() asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() self.bind((self.ip, self.port)) self.listen(5) if log_obj is None: log_obj = sys.stdout if resolver: self.logger = logger.resolving_logger(resolver, log_obj) else: self.logger = logger.unresolving_logger(logger.file_logger(sys.stdout)) l = "M2Crypto (Medusa) FTP/TLS server started at %s\n\tAuthz: %s\n\tHostname: %s\n\tPort: %d" self.log_info( l % (time.ctime(time.time()), repr(self.authorizer), self.hostname, self.port) ) def handle_accept(self): """Accept a socket and dispatch a channel to handle it.""" conn, addr = self.accept() self.total_sessions.increment() self.log_info("Connection from %s:%d" % addr) self.ftp_channel_class(self, self.ssl_ctx, conn, addr) class nbio_ftp_tls_actor: """TLS protocol negotiation mixin for FTP/TLS.""" def tls_init(self, sock, ssl_ctx, client_addr): """Perform TLS protocol negotiation.""" self.ssl_ctx = ssl_ctx self.client_addr = client_addr self._ssl_handshaking = 1 self._ssl_handshake_ok = 0 if sock: self.socket = SSL.Connection(self.ssl_ctx, sock) self.socket.setup_addr(self.client_addr) self.socket.setup_ssl() self._ssl_handshake_ok = self.socket.accept_ssl() if self._ssl_handshake_ok: self._ssl_handshaking = 0 self.add_channel() # else the client hasn't connected yet; when that happens, # handle_connect() will be triggered. def tls_neg_ok(self): """Return status of TLS protocol negotiation.""" if self._ssl_handshaking: self._ssl_handshake_ok = self.socket.accept_ssl() if self._ssl_handshake_ok: self._ssl_handshaking = 0 return self._ssl_handshake_ok def handle_connect(self): """Handle a data connection that occurs after this instance came into being. When this handler is triggered, self.socket has been created and refers to the underlying connected socket.""" self.socket = SSL.Connection(self.ssl_ctx, self.socket) self.socket.setup_addr(self.client_addr) self.socket.setup_ssl() self._ssl_handshake_ok = self.socket.accept_ssl() if self._ssl_handshake_ok: self._ssl_handshaking = 0 self.add_channel() def send(self, data): """Send data over SSL.""" try: result = self.socket.send(data) if result <= 0: return 0 else: return result except SSL.SSLError as what: self.close() self.log_info("send: closing channel %s %s" % (repr(self), what)) return 0 def recv(self, buffer_size): """Receive data over SSL.""" try: result = self.socket.recv(buffer_size) if not result: return "" else: return result except SSL.SSLError as what: self.close() self.log_info("recv: closing channel %s %s" % (repr(self), what)) return "" class tls_xmit_channel(nbio_ftp_tls_actor, ftp_server.xmit_channel): """TLS driver for a send-only data connection.""" def __init__(self, channel, conn, ssl_ctx, client_addr=None): """Initialise the driver.""" ftp_server.xmit_channel.__init__(self, channel, client_addr) self.tls_init(conn, ssl_ctx, client_addr) def readable(self): """This channel is readable iff TLS negotiation is in progress. (Which implies a connected channel, of course.)""" if not self.connected: return 0 else: return self._ssl_handshaking def writable(self): """This channel is writable iff TLS negotiation is in progress or the application has data to send.""" if self._ssl_handshaking: return 1 else: return ftp_server.xmit_channel.writable(self) def handle_read(self): """Handle a read event: either continue with TLS negotiation or let the application handle this event.""" if self.tls_neg_ok(): ftp_server.xmit_channel.handle_read(self) def handle_write(self): """Handle a write event: either continue with TLS negotiation or let the application handle this event.""" if self.tls_neg_ok(): ftp_server.xmit_channel.handle_write(self) class tls_recv_channel(nbio_ftp_tls_actor, ftp_server.recv_channel): """TLS driver for a receive-only data connection.""" def __init__(self, channel, conn, ssl_ctx, client_addr, fd): """Initialise the driver.""" ftp_server.recv_channel.__init__(self, channel, client_addr, fd) self.tls_init(conn, ssl_ctx, client_addr) def writable(self): """This channel is writable iff TLS negotiation is in progress.""" return self._ssl_handshaking def handle_read(self): """Handle a read event: either continue with TLS negotiation or let the application handle this event.""" if self.tls_neg_ok(): ftp_server.recv_channel.handle_read(self) def handle_write(self): """Handle a write event: either continue with TLS negotiation or let the application handle this event.""" if self.tls_neg_ok(): ftp_server.recv_channel.handle_write(self) m2crypto-0.46.2/demo/medusa/http_date.py000066400000000000000000000057241506746742300201400ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- import re import string import time def concat(*args): return "".join(args) def join(seq, field=" "): return field.join(seq) def group(s): return "(" + s + ")" short_days = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"] long_days = [ "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", ] short_day_reg = group(join(short_days, "|")) long_day_reg = group(join(long_days, "|")) daymap = {} for i in range(7): daymap[short_days[i]] = i daymap[long_days[i]] = i hms_reg = join(3 * [group("[0-9][0-9]")], ":") months = [ "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec", ] monmap = {} for i in range(12): monmap[months[i]] = i + 1 months_reg = group(join(months, "|")) # From draft-ietf-http-v11-spec-07.txt/3.3.1 # Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 # Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 # Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format # rfc822 format rfc822_date = join( [ concat(short_day_reg, ","), # day group("[0-9][0-9]?"), # date months_reg, # month group("[0-9]+"), # year hms_reg, # hour minute second "gmt", ], " ", ) rfc822_reg = re.compile(rfc822_date) def unpack_rfc822(m): g = m.group a = string.atoi return ( a(g(4)), # year monmap[g(3)], # month a(g(2)), # day a(g(5)), # hour a(g(6)), # minute a(g(7)), # second 0, 0, 0, ) # rfc850 format rfc850_date = join( [ concat(long_day_reg, ","), join([group("[0-9][0-9]?"), months_reg, group("[0-9]+")], "-"), hms_reg, "gmt", ], " ", ) rfc850_reg = re.compile(rfc850_date) # they actually unpack the same way def unpack_rfc850(m): g = m.group a = string.atoi return ( a(g(4)), # year monmap[g(3)], # month a(g(2)), # day a(g(5)), # hour a(g(6)), # minute a(g(7)), # second 0, 0, 0, ) # parsdate.parsedate - ~700/sec. # parse_http_date - ~1333/sec. def build_http_date(when): return time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(when)) def parse_http_date(d): d = string.lower(d) tz = time.timezone m = rfc850_reg.match(d) if m and m.end() == len(d): retval = int(time.mktime(unpack_rfc850(m)) - tz) else: m = rfc822_reg.match(d) if m and m.end() == len(d): retval = int(time.mktime(unpack_rfc822(m)) - tz) else: return 0 # Thanks to Craig Silverstein for pointing # out the DST discrepancy if time.daylight and time.localtime(retval)[-1] == 1: # DST correction retval = retval + (tz - time.altzone) return retval m2crypto-0.46.2/demo/medusa/http_server.py000066400000000000000000000606721506746742300205340ustar00rootroot00000000000000#! /usr/local/bin/python # -*- Mode: Python; tab-width: 4 -*- # # Author: Sam Rushing # Copyright 1996-2000 by Sam Rushing # All Rights Reserved. # from __future__ import print_function # python modules import os import re import socket import stat import string import sys import time # async modules import asyncore import asynchat # medusa modules import http_date import producers import status_handler import logger VERSION_STRING = "1.1" from counter import counter from urllib import unquote # =========================================================================== # Request Object # =========================================================================== class http_request: # default reply code reply_code = 200 request_counter = counter() # Whether to automatically use chunked encoding when # # HTTP version is 1.1 # Content-Length is not set # Chunked encoding is not already in effect # # If your clients are having trouble, you might want to disable this. use_chunked = 1 # by default, this request object ignores user data. collector = None def __init__(self, *args): # unpack information about the request ( self.channel, self.request, self.command, self.uri, self.version, self.header, ) = args self.outgoing = fifo() self.reply_headers = { "Server": "Medusa/%s" % VERSION_STRING, "Date": http_date.build_http_date(time.time()), } self.request_number = http_request.request_counter.increment() self._split_uri = None self._header_cache = {} # -------------------------------------------------- # reply header management # -------------------------------------------------- def __setitem__(self, key, value): self.reply_headers[key] = value def __getitem__(self, key): return self.reply_headers[key] def has_key(self, key): return key in self.reply_headers def build_reply_header(self): return ( string.join( [self.response(self.reply_code)] + map(lambda x: "%s: %s" % x, self.reply_headers.items()), "\r\n", ) + "\r\n\r\n" ) # -------------------------------------------------- # split a uri # -------------------------------------------------- # ;?# path_regex = re.compile( # path params query fragment r"([^;?#]*)(;[^?#]*)?(\?[^#]*)?(#.*)?" ) def split_uri(self): if self._split_uri is None: m = self.path_regex.match(self.uri) if m.end() != len(self.uri): raise ValueError("Broken URI") else: self._split_uri = m.groups() return self._split_uri def get_header_with_regex(self, head_reg, group): for line in self.header: m = head_reg.match(line) if m.end() == len(line): return head_reg.group(group) return "" def get_header(self, header): header = string.lower(header) hc = self._header_cache if header not in hc: h = header + ": " hl = len(h) for line in self.header: if string.lower(line[:hl]) == h: r = line[hl:] hc[header] = r return r hc[header] = None return None else: return hc[header] # -------------------------------------------------- # user data # -------------------------------------------------- def collect_incoming_data(self, data): if self.collector: self.collector.collect_incoming_data(data) else: self.log_info( "Dropping %d bytes of incoming request data" % len(data), "warning" ) def found_terminator(self): if self.collector: self.collector.found_terminator() else: self.log_info("Unexpected end-of-record for incoming request", "warning") def push(self, thing): if type(thing) == type(""): self.outgoing.push(producers.simple_producer(thing)) else: self.outgoing.push(thing) def response(self, code=200): message = self.responses[code] self.reply_code = code return "HTTP/%s %d %s" % (self.version, code, message) def error(self, code): self.reply_code = code message = self.responses[code] s = self.DEFAULT_ERROR_MESSAGE % { "code": code, "message": message, } self["Content-Length"] = len(s) self["Content-Type"] = "text/html" # make an error reply self.push(s) self.done() # can also be used for empty replies reply_now = error def done(self): "finalize this transaction - send output to the http channel" # ---------------------------------------- # persistent connection management # ---------------------------------------- # --- BUCKLE UP! ---- connection = string.lower(get_header(CONNECTION, self.header)) close_it = 0 wrap_in_chunking = 0 if self.version == "1.0": if connection == "keep-alive": if "Content-Length" not in self: close_it = 1 else: self["Connection"] = "Keep-Alive" else: close_it = 1 elif self.version == "1.1": if connection == "close": close_it = 1 elif "Content-Length" not in self: if "Transfer-Encoding" in self: if not self["Transfer-Encoding"] == "chunked": close_it = 1 elif self.use_chunked: self["Transfer-Encoding"] = "chunked" wrap_in_chunking = 1 else: close_it = 1 elif self.version is None: # Although we don't *really* support http/0.9 (because we'd have to # use \r\n as a terminator, and it would just yuck up a lot of stuff) # it's very common for developers to not want to type a version number # when using telnet to debug a server. close_it = 1 outgoing_header = producers.simple_producer(self.build_reply_header()) if close_it: self["Connection"] = "close" if wrap_in_chunking: outgoing_producer = producers.chunked_producer( producers.composite_producer(self.outgoing) ) # prepend the header outgoing_producer = producers.composite_producer( fifo([outgoing_header, outgoing_producer]) ) else: # prepend the header self.outgoing.push_front(outgoing_header) outgoing_producer = producers.composite_producer(self.outgoing) # apply a few final transformations to the output self.channel.push_with_producer( # globbing gives us large packets producers.globbing_producer( # hooking lets us log the number of bytes sent producers.hooked_producer(outgoing_producer, self.log) ) ) self.channel.current_request = None if close_it: self.channel.close_when_done() def log_date_string(self, when): return time.strftime("%d/%b/%Y:%H:%M:%S ", time.gmtime(when)) + tz_for_log def log(self, bytes): self.channel.server.logger.log( self.channel.addr[0], '%d - - [%s] "%s" %d %d\n' % ( self.channel.addr[1], self.log_date_string(time.time()), self.request, self.reply_code, bytes, ), ) responses = { 100: "Continue", 101: "Switching Protocols", 200: "OK", 201: "Created", 202: "Accepted", 203: "Non-Authoritative Information", 204: "No Content", 205: "Reset Content", 206: "Partial Content", 300: "Multiple Choices", 301: "Moved Permanently", 302: "Moved Temporarily", 303: "See Other", 304: "Not Modified", 305: "Use Proxy", 400: "Bad Request", 401: "Unauthorized", 402: "Payment Required", 403: "Forbidden", 404: "Not Found", 405: "Method Not Allowed", 406: "Not Acceptable", 407: "Proxy Authentication Required", 408: "Request Time-out", 409: "Conflict", 410: "Gone", 411: "Length Required", 412: "Precondition Failed", 413: "Request Entity Too Large", 414: "Request-URI Too Large", 415: "Unsupported Media Type", 500: "Internal Server Error", 501: "Not Implemented", 502: "Bad Gateway", 503: "Service Unavailable", 504: "Gateway Time-out", 505: "HTTP Version not supported", } # Default error message DEFAULT_ERROR_MESSAGE = string.join( [ "", "Error response", "", "", "

    Error response

    ", "

    Error code %(code)d.", "

    Message: %(message)s.", "", "", ], "\r\n", ) # =========================================================================== # HTTP Channel Object # =========================================================================== class http_channel(asynchat.async_chat): # use a larger default output buffer ac_out_buffer_size = 1 << 16 current_request = None channel_counter = counter() def __init__(self, server, conn, addr): self.channel_number = http_channel.channel_counter.increment() self.request_counter = counter() asynchat.async_chat.__init__(self, conn) self.server = server self.addr = addr self.set_terminator("\r\n\r\n") self.in_buffer = "" self.creation_time = int(time.time()) self.check_maintenance() def __repr__(self): ar = asynchat.async_chat.__repr__(self)[1:-1] return "<%s channel#: %s requests:%s>" % ( ar, self.channel_number, self.request_counter, ) # Channel Counter, Maintenance Interval... maintenance_interval = 500 def check_maintenance(self): if not self.channel_number % self.maintenance_interval: self.maintenance() def maintenance(self): self.kill_zombies() # 30-minute zombie timeout. status_handler also knows how to kill zombies. zombie_timeout = 30 * 60 def kill_zombies(self): now = int(time.time()) for channel in asyncore.socket_map.values(): if channel.__class__ == self.__class__: if (now - channel.creation_time) > channel.zombie_timeout: channel.close() # -------------------------------------------------- # send/recv overrides, good place for instrumentation. # -------------------------------------------------- # this information needs to get into the request object, # so that it may log correctly. def send(self, data): result = asynchat.async_chat.send(self, data) self.server.bytes_out.increment(len(data)) return result def recv(self, buffer_size): try: result = asynchat.async_chat.recv(self, buffer_size) self.server.bytes_in.increment(len(result)) return result except MemoryError: # --- Save a Trip to Your Service Provider --- # It's possible for a process to eat up all the memory of # the machine, and put it in an extremely wedged state, # where medusa keeps running and can't be shut down. This # is where MemoryError tends to get thrown, though of # course it could get thrown elsewhere. sys.exit("Out of Memory!") def handle_error(self): t, v = sys.exc_info()[:2] if t is SystemExit: raise t(v) else: asynchat.async_chat.handle_error(self) def log(self, *args): pass # -------------------------------------------------- # async_chat methods # -------------------------------------------------- def collect_incoming_data(self, data): if self.current_request: # we are receiving data (probably POST data) for a request self.current_request.collect_incoming_data(data) else: # we are receiving header (request) data self.in_buffer = self.in_buffer + data def found_terminator(self): if self.current_request: self.current_request.found_terminator() else: header = self.in_buffer self.in_buffer = "" lines = string.split(header, "\r\n") # -------------------------------------------------- # crack the request header # -------------------------------------------------- while lines and not lines[0]: # as per the suggestion of http-1.1 section 4.1, (and # Eric Parker ), ignore a leading # blank lines (buggy browsers tack it onto the end of # POST requests) lines = lines[1:] if not lines: self.close_when_done() return request = lines[0] # unquote path if necessary (thanks to Skip Montaro for pointing # out that we must unquote in piecemeal fashion). if "%" in request: request = unquote(request) command, uri, version = crack_request(request) header = join_headers(lines[1:]) r = http_request(self, request, command, uri, version, header) self.request_counter.increment() self.server.total_requests.increment() if command is None: self.log_info("Bad HTTP request: %s" % repr(request), "error") r.error(400) return # -------------------------------------------------- # handler selection and dispatch # -------------------------------------------------- for h in self.server.handlers: if h.match(r): try: self.current_request = r # This isn't used anywhere. # r.handler = h # CYCLE h.handle_request(r) except: self.server.exceptions.increment() (file, fun, line), t, v, tbinfo = asyncore.compact_traceback() self.log_info( "Server Error: %s, %s: file: %s line: %s" % (t, v, file, line), "error", ) try: r.error(500) except: pass return # no handlers, so complain r.error(404) def writable(self): # this is just the normal async_chat 'writable', here for comparison return self.ac_out_buffer or len(self.producer_fifo) def writable_for_proxy(self): # this version of writable supports the idea of a 'stalled' producer # [i.e., it's not ready to produce any output yet] This is needed by # the proxy, which will be waiting for the magic combination of # 1) hostname resolved # 2) connection made # 3) data available. if self.ac_out_buffer: return 1 elif len(self.producer_fifo): p = self.producer_fifo.first() if hasattr(p, "stalled"): return not p.stalled() else: return 1 # =========================================================================== # HTTP Server Object # =========================================================================== class http_server(asyncore.dispatcher): SERVER_IDENT = "HTTP Server (V%s)" % VERSION_STRING channel_class = http_channel def __init__(self, ip, port, resolver=None, logger_object=None): self.ip = ip self.port = port asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.handlers = [] if not logger_object: logger_object = logger.file_logger(sys.stdout) self.set_reuse_addr() self.bind((ip, port)) # lower this to 5 if your OS complains self.listen(1024) host, port = self.socket.getsockname() if not ip: self.log_info("Computing default hostname", "warning") ip = socket.gethostbyname(socket.gethostname()) try: self.server_name = socket.gethostbyaddr(ip)[0] except socket.error: self.log_info("Cannot do reverse lookup", "warning") self.server_name = ip # use the IP address as the "hostname" self.server_port = port self.total_clients = counter() self.total_requests = counter() self.exceptions = counter() self.bytes_out = counter() self.bytes_in = counter() if not logger_object: logger_object = logger.file_logger(sys.stdout) if resolver: self.logger = logger.resolving_logger(resolver, logger_object) else: self.logger = logger.unresolving_logger(logger_object) self.log_info( "Medusa (V%s) started at %s" "\n\tHostname: %s" "\n\tPort:%d" "\n" % ( VERSION_STRING, time.ctime(time.time()), self.server_name, port, ) ) def writable(self): return 0 def handle_read(self): pass def readable(self): return self.accepting def handle_connect(self): pass def handle_accept(self): self.total_clients.increment() try: conn, addr = self.accept() except socket.error: # linux: on rare occasions we get a bogus socket back from # accept. socketmodule.c:makesockaddr complains that the # address family is unknown. We don't want the whole server # to shut down because of this. self.log_info("warning: server accept() threw an exception", "warning") return except TypeError: # unpack non-sequence. this can happen when a read event # fires on a listening socket, but when we call accept() # we get EWOULDBLOCK, so dispatcher.accept() returns None. # Seen on FreeBSD3. self.log_info("warning: server accept() threw EWOULDBLOCK", "warning") return self.channel_class(self, conn, addr) def install_handler(self, handler, back=0): if back: self.handlers.append(handler) else: self.handlers.insert(0, handler) def remove_handler(self, handler): self.handlers.remove(handler) def status(self): def nice_bytes(n): return string.join(status_handler.english_bytes(n)) handler_stats = filter(None, map(maybe_status, self.handlers)) if self.total_clients: ratio = self.total_requests.as_long() / float(self.total_clients.as_long()) else: ratio = 0.0 return producers.composite_producer( fifo( [ producers.lines_producer( [ "

    %s

    " % self.SERVER_IDENT, "
    Listening on: Host: %s" % self.server_name, "Port: %d" % self.port, "

      " "
    • Total Clients: %s" % self.total_clients, "Requests: %s" % self.total_requests, "Requests/Client: %.1f" % (ratio), "
    • Total Bytes In: %s" % (nice_bytes(self.bytes_in.as_long())), "Bytes Out: %s" % (nice_bytes(self.bytes_out.as_long())), "
    • Total Exceptions: %s" % self.exceptions, "

    " "Extension List

      ", ] ) ] + handler_stats + [producers.simple_producer("
    ")] ) ) def maybe_status(thing): if hasattr(thing, "status"): return thing.status() else: return None CONNECTION = re.compile("Connection: (.*)", re.IGNORECASE) # merge multi-line headers # [486dx2: ~500/sec] def join_headers(headers): r = [] for i in range(len(headers)): if headers[i][0] in " \t": r[-1] = r[-1] + headers[i][1:] else: r.append(headers[i]) return r def get_header(head_reg, lines, group=1): for line in lines: m = head_reg.match(line) if m and m.end() == len(line): return m.group(group) return "" def get_header_match(head_reg, lines): for line in lines: m = head_reg.match(line) if m and m.end() == len(line): return m return "" REQUEST = re.compile("([^ ]+) ([^ ]+)(( HTTP/([0-9.]+))$|$)") def crack_request(r): m = REQUEST.match(r) if m.end() == len(r): if m.group(3): version = m.group(5) else: version = None return string.lower(m.group(1)), m.group(2), version else: return None, None, None class fifo: def __init__(self, list=None): if not list: self.list = [] else: self.list = list def __len__(self): return len(self.list) def first(self): return self.list[0] def push_front(self, object): self.list.insert(0, object) def push(self, data): self.list.append(data) def pop(self): if self.list: result = self.list[0] del self.list[0] return (1, result) else: return (0, None) def compute_timezone_for_log(): if time.daylight: tz = time.altzone else: tz = time.timezone if tz > 0: neg = 1 else: neg = 0 tz = -tz h, rem = divmod(tz, 3600) m, rem = divmod(rem, 60) if neg: return "-%02d%02d" % (h, m) else: return "+%02d%02d" % (h, m) # if you run this program over a TZ change boundary, this will be invalid. tz_for_log = compute_timezone_for_log() if __name__ == "__main__": import sys if len(sys.argv) < 2: print("usage: %s " % (sys.argv[0])) else: import monitor import filesys import default_handler import status_handler import ftp_server import chat_server import resolver import logger rs = resolver.caching_resolver("127.0.0.1") lg = logger.file_logger(sys.stdout) ms = monitor.secure_monitor_server("fnord", "127.0.0.1", 9999) fs = filesys.os_filesystem(sys.argv[1]) dh = default_handler.default_handler(fs) hs = http_server("", string.atoi(sys.argv[2]), rs, lg) hs.install_handler(dh) ftp = ftp_server.ftp_server( ftp_server.dummy_authorizer(sys.argv[1]), port=8021, resolver=rs, logger_object=lg, ) cs = chat_server.chat_server("", 7777) sh = status_handler.status_extension([hs, ms, ftp, cs, rs]) hs.install_handler(sh) if "-p" in sys.argv: def profile_loop(): try: asyncore.loop() except KeyboardInterrupt: pass import profile profile.run("profile_loop()", "profile.out") else: asyncore.loop() m2crypto-0.46.2/demo/medusa/https_server.py000066400000000000000000000051061506746742300207060ustar00rootroot00000000000000#!/usr/bin/env python """A https server built on Medusa's http_server. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" import asynchat, asyncore, http_server, socket, sys from M2Crypto import SSL VERSION_STRING = "0.09" class https_channel(http_server.http_channel): def __init__(self, server, conn, addr): http_server.http_channel.__init__(self, server, conn, addr) def send(self, data): try: result = self.socket._write_nbio(data) if result <= 0: return 0 else: self.server.bytes_out.increment(result) return result except SSL.SSLError as why: self.close() self.log_info("send: closing channel %s %s" % (repr(self), why)) return 0 def recv(self, buffer_size): try: result = self.socket._read_nbio(buffer_size) if result is None: return "" elif result == "": self.close() return "" else: self.server.bytes_in.increment(len(result)) return result except SSL.SSLError as why: self.close() self.log_info("recv: closing channel %s %s" % (repr(self), why)) return "" class https_server(http_server.http_server): SERVER_IDENT = "M2Crypto HTTPS Server (v%s)" % VERSION_STRING channel_class = https_channel def __init__(self, ip, port, ssl_ctx, resolver=None, logger_object=None): http_server.http_server.__init__(self, ip, port, resolver, logger_object) sys.stdout.write(self.SERVER_IDENT + "\n\n") sys.stdout.flush() self.ssl_ctx = ssl_ctx def handle_accept(self): # Cribbed from http_server. self.total_clients.increment() try: conn, addr = self.accept() except socket.error: # linux: on rare occasions we get a bogus socket back from # accept. socketmodule.c:makesockaddr complains that the # address family is unknown. We don't want the whole server # to shut down because of this. sys.stderr.write("warning: server accept() threw an exception\n") return # Turn the vanilla socket into an SSL connection. try: ssl_conn = SSL.Connection(self.ssl_ctx, conn) ssl_conn._setup_ssl(addr) ssl_conn.accept_ssl() self.channel_class(self, ssl_conn, addr) except SSL.SSLError: pass def writeable(self): return 0 m2crypto-0.46.2/demo/medusa/index.html000066400000000000000000000001561506746742300176010ustar00rootroot00000000000000 M2Crypto HTTPS Server

    M2Crypto HTTPS Server - It works!

    m2crypto-0.46.2/demo/medusa/logger.py000066400000000000000000000170131506746742300174350ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- import asynchat import socket import string import time # these three are for the rotating logger import os # | import stat # v # # three types of log: # 1) file # with optional flushing. Also, one that rotates the log. # 2) socket # dump output directly to a socket connection. [how do we # keep it open?] # 3) syslog # log to syslog via tcp. this is a per-line protocol. # # # The 'standard' interface to a logging object is simply # log_object.log (message) # # a file-like object that captures output, and # makes sure to flush it always... this could # be connected to: # o stdio file # o low-level file # o socket channel # o syslog output... class file_logger: # pass this either a path or a file object. def __init__(self, file, flush=1, mode="a"): if type(file) == type(""): if file == "-": import sys self.file = sys.stdout else: self.file = open(file, mode) else: self.file = file self.do_flush = flush def __repr__(self): return "" % self.file def write(self, data): self.file.write(data) self.maybe_flush() def writeline(self, line): self.file.writeline(line) self.maybe_flush() def writelines(self, lines): self.file.writelines(lines) self.maybe_flush() def maybe_flush(self): if self.do_flush: self.file.flush() def flush(self): self.file.flush() def softspace(self, *args): pass def log(self, message): if message[-1] not in ("\r", "\n"): self.write(message + "\n") else: self.write(message) # like a file_logger, but it must be attached to a filename. # When the log gets too full, or a certain time has passed, # it backs up the log and starts a new one. Note that backing # up the log is done via "mv" because anything else (cp, gzip) # would take time, during which medusa would do nothing else. class rotating_file_logger(file_logger): # If freq is non-None we back up "daily", "weekly", or "monthly". # Else if maxsize is non-None we back up whenever the log gets # to big. If both are None we never back up. def __init__(self, file, freq=None, maxsize=None, flush=1, mode="a"): self.filename = file self.mode = mode self.file = open(file, mode) self.freq = freq self.maxsize = maxsize self.rotate_when = self.next_backup(self.freq) self.do_flush = flush def __repr__(self): return "" % self.file # We back up at midnight every 1) day, 2) monday, or 3) 1st of month def next_backup(self, freq): (yr, mo, day, hr, min, sec, wd, jday, dst) = time.localtime(time.time()) if freq == "daily": return time.mktime(yr, mo, day + 1, 0, 0, 0, 0, 0, -1) elif freq == "weekly": return time.mktime(yr, mo, day - wd + 7, 0, 0, 0, 0, 0, -1) # wd(monday)==0 elif freq == "monthly": return time.mktime(yr, mo + 1, 1, 0, 0, 0, 0, 0, -1) else: return None # not a date-based backup def maybe_flush(self): # rotate first if necessary self.maybe_rotate() if self.do_flush: # from file_logger() self.file.flush() def maybe_rotate(self): if self.freq and time.time() > self.rotate_when: self.rotate() self.rotate_when = self.next_backup(self.freq) elif self.maxsize: # rotate when we get too big try: if os.stat(self.filename)[stat.ST_SIZE] > self.maxsize: self.rotate() except os.error: # file not found, probably self.rotate() # will create a new file def rotate(self): (yr, mo, day, hr, min, sec, wd, jday, dst) = time.localtime(time.time()) try: self.file.close() newname = "%s.ends%04d%02d%02d" % (self.filename, yr, mo, day) try: open(newname, "r").close() # check if file exists newname = newname + "-%02d%02d%02d" % (hr, min, sec) except: # YEARMODY is unique pass os.rename(self.filename, newname) self.file = open(self.filename, self.mode) except: pass # syslog is a line-oriented log protocol - this class would be # appropriate for FTP or HTTP logs, but not for dumping stderr to. # TODO: a simple safety wrapper that will ensure that the line sent # to syslog is reasonable. # TODO: async version of syslog_client: now, log entries use blocking # send() import m_syslog syslog_logger = m_syslog.syslog_client class syslog_logger(m_syslog.syslog_client): def __init__(self, address, facility="user"): m_syslog.syslog_client.__init__(self, address) self.facility = m_syslog.facility_names[facility] self.address = address def __repr__(self): return "" % (repr(self.address)) def log(self, message): m_syslog.syslog_client.log( self, message, facility=self.facility, priority=m_syslog.LOG_INFO ) # log to a stream socket, asynchronously class socket_logger(asynchat.async_chat): def __init__(self, address): if type(address) == type(""): self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM) else: self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect(address) self.address = address def __repr__(self): return "" % (self.address) def log(self, message): if message[-2:] != "\r\n": self.socket.push(message + "\r\n") else: self.socket.push(message) # log to multiple places class multi_logger: def __init__(self, loggers): self.loggers = loggers def __repr__(self): return "" % (repr(self.loggers)) def log(self, message): for logger in self.loggers: logger.log(message) class resolving_logger: """Feed (ip, message) combinations into this logger to get a resolved hostname in front of the message. The message will not be logged until the PTR request finishes (or fails).""" def __init__(self, resolver, logger): self.resolver = resolver self.logger = logger class logger_thunk: def __init__(self, message, logger): self.message = message self.logger = logger def __call__(self, host, ttl, answer): if not answer: answer = host self.logger.log("%s:%s" % (answer, self.message)) def log(self, ip, message): self.resolver.resolve_ptr(ip, self.logger_thunk(message, self.logger)) class unresolving_logger: "Just in case you don't want to resolve" def __init__(self, logger): self.logger = logger def log(self, ip, message): self.logger.log("%s:%s" % (ip, message)) def strip_eol(line): while line and line[-1] in "\r\n": line = line[:-1] return line class tail_logger: "Keep track of the last log messages" def __init__(self, logger, size=500): self.size = size self.logger = logger self.messages = [] def log(self, message): self.messages.append(strip_eol(message)) if len(self.messages) > self.size: del self.messages[0] self.logger.log(message) m2crypto-0.46.2/demo/medusa/m_syslog.py000066400000000000000000000135351506746742300200170ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- # ====================================================================== # Copyright 1997 by Sam Rushing # # 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, and that the name of Sam # Rushing not be used in advertising or publicity pertaining to # distribution of the software without specific, written prior # permission. # # SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN # NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # ====================================================================== """socket interface to unix syslog. On Unix, there are usually two ways of getting to syslog: via a local unix-domain socket, or via the TCP service. Usually "/dev/log" is the unix domain socket. This may be different for other systems. >>> my_client = syslog_client ('/dev/log') Otherwise, just use the UDP version, port 514. >>> my_client = syslog_client (('my_log_host', 514)) On win32, you will have to use the UDP version. Note that you can use this to log to other hosts (and indeed, multiple hosts). This module is not a drop-in replacement for the python extension module - the interface is different. Usage: >>> c = syslog_client() >>> c = syslog_client ('/strange/non_standard_log_location') >>> c = syslog_client (('other_host.com', 514)) >>> c.log ('testing', facility='local0', priority='debug') """ # TODO: support named-pipe syslog. # [see ftp://sunsite.unc.edu/pub/Linux/system/Daemons/syslog-fifo.tar.z] # from : # =========================================================================== # priorities/facilities are encoded into a single 32-bit quantity, where the # bottom 3 bits are the priority (0-7) and the top 28 bits are the facility # (0-big number). Both the priorities and the facilities map roughly # one-to-one to strings in the syslogd(8) source code. This mapping is # included in this file. # # priorities (these are ordered) LOG_EMERG = 0 # system is unusable LOG_ALERT = 1 # action must be taken immediately LOG_CRIT = 2 # critical conditions LOG_ERR = 3 # error conditions LOG_WARNING = 4 # warning conditions LOG_NOTICE = 5 # normal but significant condition LOG_INFO = 6 # informational LOG_DEBUG = 7 # debug-level messages # facility codes LOG_KERN = 0 # kernel messages LOG_USER = 1 # random user-level messages LOG_MAIL = 2 # mail system LOG_DAEMON = 3 # system daemons LOG_AUTH = 4 # security/authorization messages LOG_SYSLOG = 5 # messages generated internally by syslogd LOG_LPR = 6 # line printer subsystem LOG_NEWS = 7 # network news subsystem LOG_UUCP = 8 # UUCP subsystem LOG_CRON = 9 # clock daemon LOG_AUTHPRIV = 10 # security/authorization messages (private) # other codes through 15 reserved for system use LOG_LOCAL0 = 16 # reserved for local use LOG_LOCAL1 = 17 # reserved for local use LOG_LOCAL2 = 18 # reserved for local use LOG_LOCAL3 = 19 # reserved for local use LOG_LOCAL4 = 20 # reserved for local use LOG_LOCAL5 = 21 # reserved for local use LOG_LOCAL6 = 22 # reserved for local use LOG_LOCAL7 = 23 # reserved for local use priority_names = { "alert": LOG_ALERT, "crit": LOG_CRIT, "debug": LOG_DEBUG, "emerg": LOG_EMERG, "err": LOG_ERR, "error": LOG_ERR, # DEPRECATED "info": LOG_INFO, "notice": LOG_NOTICE, "panic": LOG_EMERG, # DEPRECATED "warn": LOG_WARNING, # DEPRECATED "warning": LOG_WARNING, } facility_names = { "auth": LOG_AUTH, "authpriv": LOG_AUTHPRIV, "cron": LOG_CRON, "daemon": LOG_DAEMON, "kern": LOG_KERN, "lpr": LOG_LPR, "mail": LOG_MAIL, "news": LOG_NEWS, "security": LOG_AUTH, # DEPRECATED "syslog": LOG_SYSLOG, "user": LOG_USER, "uucp": LOG_UUCP, "local0": LOG_LOCAL0, "local1": LOG_LOCAL1, "local2": LOG_LOCAL2, "local3": LOG_LOCAL3, "local4": LOG_LOCAL4, "local5": LOG_LOCAL5, "local6": LOG_LOCAL6, "local7": LOG_LOCAL7, } import socket class syslog_client: def __init__(self, address="/dev/log"): self.address = address if type(address) == type(""): self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self.socket.connect(address) self.unix = 1 else: self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.unix = 0 # curious: when talking to the unix-domain '/dev/log' socket, a # zero-terminator seems to be required. this string is placed # into a class variable so that it can be overridden if # necessary. log_format_string = "<%d>%s\000" def log(self, message, facility=LOG_USER, priority=LOG_INFO): message = self.log_format_string % ( self.encode_priority(facility, priority), message, ) if self.unix: self.socket.send(message) else: self.socket.sendto(message, self.address) def encode_priority(self, facility, priority): if type(facility) == type(""): facility = facility_names[facility] if type(priority) == type(""): priority = priority_names[priority] return (facility << 3) | priority def close(self): if self.unix: self.socket.close() m2crypto-0.46.2/demo/medusa/medusa_gif.py000066400000000000000000000053241506746742300202630ustar00rootroot00000000000000# -*- Mode: Python -*- # the medusa icon as a python source file. width = 97 height = 61 data = "GIF89aa\000=\000\204\000\000\000\000\000\255\255\255\245\245\245ssskkkccc111)))\326\326\326!!!\316\316\316\300\300\300\204\204\000\224\224\224\214\214\214\200\200\200RRR\377\377\377JJJ\367\367\367BBB\347\347\347\000\204\000\020\020\020\265\265\265\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000!\371\004\001\000\000\021\000,\000\000\000\000a\000=\000\000\005\376`$\216di\236h\252\256l\353\276p,\317tm\337x\256\357|m\001@\240E\305\000\364\2164\206R)$\005\201\214\007r\012{X\255\312a\004\260\\>\026\3240\353)\224n\001W+X\334\373\231~\344.\303b\216\024\027x<\273\307\255G,rJiWN\014{S}k\"?ti\013EdPQ\207G@_%\000\026yy\\\201\202\227\224<\221Fs$pOjWz\241\272\002\325\307g\012(\007\205\312#j\317(\012A\200\224.\241\003\346GS\247\033\245\344\264\366\015L'PXQl]\266\263\243\232\260?\245\316\371\362\225\035\332\243J\273\332Q\263\357-D\241T\327\270\265\013W&\330\010u\371b\322IW0\214\261]\003\033Va\365Z#\207\213a\030k\2647\262\014p\354\024[n\321N\363\346\317\003\037P\000\235C\302\000\3228(\244\363YaA\005\022\255_\237@\260\000A\212\326\256qbp\321\332\266\011\334=T\023\010\"!B\005\003A\010\224\020\220 H\002\337#\020 O\276E\357h\221\327\003\\\000b@v\004\351A.h\365\354\342B\002\011\257\025\\ \220\340\301\353\006\000\024\214\200pA\300\353\012\364\241k/\340\033C\202\003\000\310fZ\011\003V\240R\005\007\354\376\026A\000\000\360'\202\177\024\004\210\003\000\305\215\360\000\000\015\220\240\332\203\027@'\202\004\025VpA\000%\210x\321\206\032J\341\316\010\262\211H\"l\333\341\200\200>\"]P\002\212\011\010`\002\0066FP\200\001'\024p]\004\027(8B\221\306]\000\201w>\002iB\001\007\340\260\"v7J1\343(\257\020\251\243\011\242i\263\017\215\337\035\220\200\221\365m4d\015\016D\251\341iN\354\346Ng\253\200I\240\031\35609\245\2057\311I\302\2007t\231\"&`\314\310\244\011e\226(\236\010w\212\300\234\011\012HX(\214\253\311@\001\233^\222pg{% \340\035\224&H\000\246\201\362\215`@\001\"L\340\004\030\234\022\250'\015(V:\302\235\030\240q\337\205\224\212h@\177\006\000\250\210\004\007\310\207\337\005\257-P\346\257\367]p\353\203\271\256:\203\236\211F\340\247\010\3329g\244\010\307*=A\000\203\260y\012\304s#\014\007D\207,N\007\304\265\027\021C\233\207%B\366[m\353\006\006\034j\360\306+\357\274a\204\000\000;" m2crypto-0.46.2/demo/medusa/mime_type_table.py000066400000000000000000000067161506746742300213250ustar00rootroot00000000000000# -*- Python -*- # Converted by ./convert_mime_type_table.py from: # /usr/src2/apache_1.2b6/conf/mime.types # content_type_map = { "ai": "application/postscript", "aif": "audio/x-aiff", "aifc": "audio/x-aiff", "aiff": "audio/x-aiff", "au": "audio/basic", "avi": "video/x-msvideo", "bcpio": "application/x-bcpio", "bin": "application/octet-stream", "cdf": "application/x-netcdf", "class": "application/octet-stream", "cpio": "application/x-cpio", "cpt": "application/mac-compactpro", "csh": "application/x-csh", "dcr": "application/x-director", "dir": "application/x-director", "dms": "application/octet-stream", "doc": "application/msword", "dvi": "application/x-dvi", "dxr": "application/x-director", "eps": "application/postscript", "etx": "text/x-setext", "exe": "application/octet-stream", "gif": "image/gif", "gtar": "application/x-gtar", "gz": "application/x-gzip", "hdf": "application/x-hdf", "hqx": "application/mac-binhex40", "htm": "text/html", "html": "text/html", "ice": "x-conference/x-cooltalk", "ief": "image/ief", "jpe": "image/jpeg", "jpeg": "image/jpeg", "jpg": "image/jpeg", "kar": "audio/midi", "latex": "application/x-latex", "lha": "application/octet-stream", "lzh": "application/octet-stream", "man": "application/x-troff-man", "me": "application/x-troff-me", "mid": "audio/midi", "midi": "audio/midi", "mif": "application/x-mif", "mov": "video/quicktime", "movie": "video/x-sgi-movie", "mp2": "audio/mpeg", "mpe": "video/mpeg", "mpeg": "video/mpeg", "mpg": "video/mpeg", "mpga": "audio/mpeg", "mp3": "audio/mpeg", "ms": "application/x-troff-ms", "nc": "application/x-netcdf", "oda": "application/oda", "pbm": "image/x-portable-bitmap", "pdb": "chemical/x-pdb", "pdf": "application/pdf", "pgm": "image/x-portable-graymap", "png": "image/png", "pnm": "image/x-portable-anymap", "ppm": "image/x-portable-pixmap", "ppt": "application/powerpoint", "ps": "application/postscript", "qt": "video/quicktime", "ra": "audio/x-realaudio", "ram": "audio/x-pn-realaudio", "ras": "image/x-cmu-raster", "rgb": "image/x-rgb", "roff": "application/x-troff", "rpm": "audio/x-pn-realaudio-plugin", "rtf": "application/rtf", "rtx": "text/richtext", "sgm": "text/x-sgml", "sgml": "text/x-sgml", "sh": "application/x-sh", "shar": "application/x-shar", "sit": "application/x-stuffit", "skd": "application/x-koan", "skm": "application/x-koan", "skp": "application/x-koan", "skt": "application/x-koan", "snd": "audio/basic", "src": "application/x-wais-source", "sv4cpio": "application/x-sv4cpio", "sv4crc": "application/x-sv4crc", "t": "application/x-troff", "tar": "application/x-tar", "tcl": "application/x-tcl", "tex": "application/x-tex", "texi": "application/x-texinfo", "texinfo": "application/x-texinfo", "tif": "image/tiff", "tiff": "image/tiff", "tr": "application/x-troff", "tsv": "text/tab-separated-values", "txt": "text/plain", "ustar": "application/x-ustar", "vcd": "application/x-cdlink", "vrml": "x-world/x-vrml", "wav": "audio/x-wav", "wrl": "x-world/x-vrml", "xbm": "image/x-xbitmap", "xpm": "image/x-xpixmap", "xwd": "image/x-xwindowdump", "xyz": "chemical/x-pdb", "zip": "application/zip", } m2crypto-0.46.2/demo/medusa/poison_handler.py000066400000000000000000000035131506746742300211620ustar00rootroot00000000000000import string import whrandom RESP_HEAD = """\ """ RESP_MIDDLE = """

    M2Crypto https server demonstration

    This web page is generated by the "poison" http request handler.
    The links just go on and on and on...

    """ RESP_TAIL = """ """ charset = "012345678/90ABCDEFGHIJKLM/NOPQRSTUVWXYZabcd/efghijklmnopqrs/tuvwxyz" numchar = len(charset) def makepage(numlinks): title = "" for u in range(whrandom.randint(3, 15)): pick = whrandom.randint(0, numchar - 1) title = title + charset[pick] title = title + "" url = "\r\n" numlinks = whrandom.randint(2, numlinks) for i in range(numlinks): url = url + '' for u in range(whrandom.randint(3, 15)): pick = whrandom.randint(0, numchar - 1) url = url + charset[pick] url = url + "
    \r\n" url = RESP_HEAD + title + RESP_MIDDLE + url + RESP_TAIL return url class poison_handler: """This is a clone of webpoison - every URL returns a page of URLs, each of which returns a page of URLs, each of _which_ returns a page of URLs, ad infinitum. The objective is to sucker address-harvesting bots run by spammers.""" def __init__(self, numlinks=10): self.numlinks = numlinks self.poison_level = 0 def match(self, request): return request.uri[:7] == "/poison" def handle_request(self, request): if request.command == "get": request.push(makepage(self.numlinks)) request.done() m2crypto-0.46.2/demo/medusa/producers.py000066400000000000000000000220471506746742300201670ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- import string """ A collection of producers. Each producer implements a particular feature: They can be combined in various ways to get interesting and useful behaviors. For example, you can feed dynamically-produced output into the compressing producer, then wrap this with the 'chunked' transfer-encoding producer. """ class simple_producer: "producer for a string" def __init__(self, data, buffer_size=1024): self.data = data self.buffer_size = buffer_size def more(self): if len(self.data) > self.buffer_size: result = self.data[: self.buffer_size] self.data = self.data[self.buffer_size :] return result else: result = self.data self.data = "" return result class scanning_producer: "like simple_producer, but more efficient for large strings" def __init__(self, data, buffer_size=1024): self.data = data self.buffer_size = buffer_size self.pos = 0 def more(self): if self.pos < len(self.data): lp = self.pos rp = min(len(self.data), self.pos + self.buffer_size) result = self.data[lp:rp] self.pos = self.pos + len(result) return result else: return "" class lines_producer: "producer for a list of lines" def __init__(self, lines): self.lines = lines def ready(self): return len(self.lines) def more(self): if self.lines: chunk = self.lines[:50] self.lines = self.lines[50:] return string.join(chunk, "\r\n") + "\r\n" else: return "" class buffer_list_producer: "producer for a list of buffers" # i.e., data == string.join (buffers, '') def __init__(self, buffers): self.index = 0 self.buffers = buffers def more(self): if self.index >= len(self.buffers): return "" else: data = self.buffers[self.index] self.index = self.index + 1 return data class file_producer: "producer wrapper for file[-like] objects" # match http_channel's outgoing buffer size out_buffer_size = 1 << 16 def __init__(self, file): self.done = 0 self.file = file def more(self): if self.done: return "" else: data = self.file.read(self.out_buffer_size) if not data: self.file.close() del self.file self.done = 1 return "" else: return data # A simple output producer. This one does not [yet] have # the safety feature builtin to the monitor channel: runaway # output will not be caught. # don't try to print from within any of the methods # of this object. class output_producer: "Acts like an output file; suitable for capturing sys.stdout" def __init__(self): self.data = "" def write(self, data): lines = string.splitfields(data, "\n") data = string.join(lines, "\r\n") self.data = self.data + data def writeline(self, line): self.data = self.data + line + "\r\n" def writelines(self, lines): self.data = self.data + string.joinfields(lines, "\r\n") + "\r\n" def ready(self): return len(self.data) > 0 def flush(self): pass def softspace(self, *args): pass def more(self): if self.data: result = self.data[:512] self.data = self.data[512:] return result else: return "" class composite_producer: "combine a fifo of producers into one" def __init__(self, producers): self.producers = producers def more(self): while len(self.producers): p = self.producers.first() d = p.more() if d: return d else: self.producers.pop() else: return "" class globbing_producer: """ 'glob' the output from a producer into a particular buffer size. helps reduce the number of calls to send(). [this appears to gain about 30% performance on requests to a single channel] """ def __init__(self, producer, buffer_size=1 << 16): self.producer = producer self.buffer = "" self.buffer_size = buffer_size def more(self): while len(self.buffer) < self.buffer_size: data = self.producer.more() if data: self.buffer = self.buffer + data else: break r = self.buffer self.buffer = "" return r class hooked_producer: """ A producer that will call when it empties,. with an argument of the number of bytes produced. Useful for logging/instrumentation purposes. """ def __init__(self, producer, function): self.producer = producer self.function = function self.bytes = 0 def more(self): if self.producer: result = self.producer.more() if not result: self.producer = None self.function(self.bytes) else: self.bytes = self.bytes + len(result) return result else: return "" # HTTP 1.1 emphasizes that an advertised Content-Length header MUST be # correct. In the face of Strange Files, it is conceivable that # reading a 'file' may produce an amount of data not matching that # reported by os.stat() [text/binary mode issues, perhaps the file is # being appended to, etc..] This makes the chunked encoding a True # Blessing, and it really ought to be used even with normal files. # How beautifully it blends with the concept of the producer. class chunked_producer: """A producer that implements the 'chunked' transfer coding for HTTP/1.1. Here is a sample usage: request['Transfer-Encoding'] = 'chunked' request.push ( producers.chunked_producer (your_producer) ) request.done() """ def __init__(self, producer, footers=None): self.producer = producer self.footers = footers def more(self): if self.producer: data = self.producer.more() if data: return "%x\r\n%s\r\n" % (len(data), data) else: self.producer = None if self.footers: return string.join(["0"] + self.footers, "\r\n") + "\r\n\r\n" else: return "0\r\n\r\n" else: return "" # Unfortunately this isn't very useful right now (Aug 97), because # apparently the browsers don't do on-the-fly decompression. Which # is sad, because this could _really_ speed things up, especially for # low-bandwidth clients (i.e., most everyone). try: import zlib except ImportError: zlib = None class compressed_producer: """ Compress another producer on-the-fly, using ZLIB [Unfortunately, none of the current browsers seem to support this] """ # Note: It's not very efficient to have the server repeatedly # compressing your outgoing files: compress them ahead of time, or # use a compress-once-and-store scheme. However, if you have low # bandwidth and low traffic, this may make more sense than # maintaining your source files compressed. # # Can also be used for compressing dynamically-produced output. def __init__(self, producer, level=5): self.producer = producer self.compressor = zlib.compressobj(level) def more(self): if self.producer: cdata = "" # feed until we get some output while not cdata: data = self.producer.more() if not data: self.producer = None return self.compressor.flush() else: cdata = self.compressor.compress(data) return cdata else: return "" class escaping_producer: "A producer that escapes a sequence of characters" " Common usage: escaping the CRLF.CRLF sequence in SMTP, NNTP, etc..." def __init__(self, producer, esc_from="\r\n.", esc_to="\r\n.."): self.producer = producer self.esc_from = esc_from self.esc_to = esc_to self.buffer = "" from asynchat import find_prefix_at_end self.find_prefix_at_end = find_prefix_at_end def more(self): esc_from = self.esc_from esc_to = self.esc_to buffer = self.buffer + self.producer.more() if buffer: buffer = string.replace(buffer, esc_from, esc_to) i = self.find_prefix_at_end(buffer, esc_from) if i: # we found a prefix self.buffer = buffer[-i:] return buffer[:-i] else: # no prefix, return it all self.buffer = "" return buffer else: return buffer m2crypto-0.46.2/demo/medusa/put_handler.py000066400000000000000000000062111506746742300204610ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- # # Author: Sam Rushing # Copyright 1996-2000 by Sam Rushing # All Rights Reserved. # from __future__ import print_function import re import string import default_handler unquote = default_handler.unquote get_header = default_handler.get_header last_request = None class put_handler: def __init__(self, filesystem, uri_regex): self.filesystem = filesystem if type(uri_regex) == type(""): self.uri_regex = re.compile(uri_regex) else: self.uri_regex = uri_regex def match(self, request): uri = request.uri if request.command == "put": m = self.uri_regex.match(uri) if m and m.end() == len(uri): return 1 return 0 def handle_request(self, request): path, params, query, fragment = request.split_uri() # strip off leading slashes while path and path[0] == "/": path = path[1:] if "%" in path: path = unquote(path) # make sure there's a content-length header cl = get_header(CONTENT_LENGTH, request.header) if not cl: request.error(411) return else: cl = string.atoi(cl) # don't let the try to overwrite a directory if self.filesystem.isdir(path): request.error(405) return is_update = self.filesystem.isfile(path) try: output_file = self.filesystem.open(path, "wb") except: request.error(405) return request.collector = put_collector(output_file, cl, request, is_update) # no terminator while receiving PUT data request.channel.set_terminator(None) # don't respond yet, wait until we've received the data... class put_collector: def __init__(self, file, length, request, is_update): self.file = file self.length = length self.request = request self.is_update = is_update self.bytes_in = 0 def collect_incoming_data(self, data): ld = len(data) bi = self.bytes_in if (bi + ld) >= self.length: # last bit of data chunk = self.length - bi self.file.write(data[:chunk]) self.file.close() if chunk != ld: print("orphaned %d bytes: <%s>" % (ld - chunk, repr(data[chunk:]))) # do some housekeeping r = self.request ch = r.channel ch.current_request = None # set the terminator back to the default ch.set_terminator("\r\n\r\n") if self.is_update: r.reply_code = 204 # No content r.done() else: r.reply_now(201) # Created # avoid circular reference del self.request else: self.file.write(data) self.bytes_in = self.bytes_in + ld def found_terminator(self): # shouldn't be called pass CONTENT_LENGTH = re.compile("Content-Length: ([0-9]+)", re.IGNORECASE) m2crypto-0.46.2/demo/medusa/redirecting_handler.py000066400000000000000000000023121506746742300221460ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- # # Author: Sam Rushing # Copyright 1996-2000 by Sam Rushing # All Rights Reserved. # import re import counter class redirecting_handler: def __init__(self, pattern, redirect, regex_flag=re.IGNORECASE): self.pattern = pattern self.redirect = redirect self.patreg = re.compile(pattern, regex_flag) self.hits = counter.counter() def match(self, request): m = self.patref.match(request.uri) return m and (m.end() == len(request.uri)) def handle_request(self, request): self.hits.increment() m = self.patreg.match(request.uri) part = m.group(1) request["Location"] = self.redirect % part request.error(302) # moved temporarily def __repr__(self): return " %s]>" % ( id(self), repr(self.pattern), repr(self.redirect), ) def status(self): import producers return producers.simple_producer( "
  • Redirecting Handler %s => %s Hits: %s" % (self.pattern, self.redirect, self.hits) ) m2crypto-0.46.2/demo/medusa/server.pem000066400000000000000000000041101506746742300176070ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDYjCCAsugAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAzMDYyMjEzMzAxNFoXDTA0MDYyMTEzMzAx NFowXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwls b2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5leGFtcGxlLmRv bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA37aKGZtFicl8xXXTLJ8/JD7c kd3t/teCX9i61lpaDQCKBoVrrursIvZihemMKI9g/u/+BLqt5g8mBdgUdYz0txc8 KEbV2hj+wwOX4H3XwD0Y+DysXiNHq7/tFdmzSVHoLxpY4zYzXbxQ/p049wvIyPRp /y3omcnx/TEUhkn+JmkCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4 QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTB H/mUYlww24mJlSxEtGdlwojO9zCBrQYDVR0jBIGlMIGigBTr+pwHMS1CmF9cuGI4 du3YqoHAwqGBhqSBgzCBgDELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv MRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8gQ2VydGlm aWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNuZ3BzQG5ldG1lbWV0aWMuY29t ggEAMA0GCSqGSIb3DQEBBAUAA4GBAAvl6v0s3eFeGP4iAcrfysuK7jzFKhjDYuOy lVS3u33bZNLnMpM6OSEM9yPh4WpFCVHf+nYwC71pk4ilsLVXjKxymm2lNGcxLVuW iydFz4Ly9nmN7Ja9ygYT39dGAFP/wN7ELTpsbul8VfmqhNg9y81d8i/A1tK3AGA8 0QkPQNdP -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDftooZm0WJyXzFddMsnz8kPtyR3e3+14Jf2LrWWloNAIoGhWuu 6uwi9mKF6Ywoj2D+7/4Euq3mDyYF2BR1jPS3FzwoRtXaGP7DA5fgfdfAPRj4PKxe I0erv+0V2bNJUegvGljjNjNdvFD+nTj3C8jI9Gn/LeiZyfH9MRSGSf4maQIDAQAB AoGAHpeVtv62uarl9xKvuBBm0AwQmZnhq9HIsFaw5hMg8Vo7hbzFBvx1IirTOkC/ u+QvfW1QLVFh6m3z4ySzV4fZBtcd6F9SbSrZ0xsxIUB2NOSa1RGgiaP61bJnMMM1 xM3O9iwM5GZc3Gqy08QOCpDl0772VJ+9Gz3FA88mrc6rHQkCQQDz6RIatFjT28n8 1vy0nHwwZz2oXTpe/pyZPwoKj8zVsmrKhKwOw7l8ArxjP8zoHOE7AQBCXYDMNoFp IAF0yuqrAkEA6s0wMEdPpQeb0XHAfccyJQoeULxHdVFoz1wWmGSOm4YmQtR8/QJx luEgfpeRkzxBKt5Ls3MEkheIOw7xV24zOwJAMz+DaE0AZPNHS3K4ghJnHZxzng6I lzEUIjbWm0V/ml70hTy/EhMZw+6nOotLOHHo+QbK0SboSwAgzL/Gzo1cJQJANqpS 38qadleRJXAQWrg3qnvyluVe1aeAeVZ9RDmVIgxXeBO0jcs12uTLBe4PzHGo0mwy v7K1i7XC180gzzQu5QJBAOxITT9RoWSSozPvnirHd37sn+RsrNYkV07NAa80M20Z DkBPHeMVkNgigrQ6L6vWmbRDGQbGcMplAxnI5ppKCoU= -----END RSA PRIVATE KEY----- m2crypto-0.46.2/demo/medusa/status_handler.py000066400000000000000000000212171506746742300211770ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- VERSION_STRING = "$Id$" # # medusa status extension # import string import time import re import asyncore import http_server import medusa_gif import producers from counter import counter START_TIME = long(time.time()) class status_extension: hit_counter = counter() def __init__(self, objects, statusdir="/status", allow_emergency_debug=0): self.objects = objects self.statusdir = statusdir self.allow_emergency_debug = allow_emergency_debug # We use /status instead of statusdir here because it's too # hard to pass statusdir to the logger, who makes the HREF # to the object dir. We don't need the security-through- # obscurity here in any case, because the id is obscurity enough self.hyper_regex = re.compile("/status/object/([0-9]+)/.*") self.hyper_objects = [] for object in objects: self.register_hyper_object(object) def __repr__(self): return "" % (self.hit_counter, id(self)) def match(self, request): path, params, query, fragment = request.split_uri() # For reasons explained above, we don't use statusdir for /object return ( path[: len(self.statusdir)] == self.statusdir or path[: len("/status/object/")] == "/status/object/" ) # Possible Targets: # /status # /status/channel_list # /status/medusa.gif # can we have 'clickable' objects? # [yes, we can use id(x) and do a linear search] # Dynamic producers: # HTTP/1.0: we must close the channel, because it's dynamic output # HTTP/1.1: we can use the chunked transfer-encoding, and leave # it open. def handle_request(self, request): [path, params, query, fragment] = request.split_uri() self.hit_counter.increment() if path == self.statusdir: # and not a subdirectory up_time = string.join(english_time(long(time.time()) - START_TIME)) request["Content-Type"] = "text/html" request.push( "" "Medusa Status Reports" '' "

    Medusa Status Reports

    " "Up: %s" % up_time ) for i in range(len(self.objects)): request.push(self.objects[i].status()) request.push("
    \r\n") request.push( '

    Channel List' "


    " '' "" % (self.statusdir, self.statusdir, medusa_gif.width, medusa_gif.height) ) request.done() elif path == self.statusdir + "/channel_list": request["Content-Type"] = "text/html" request.push("") request.push(channel_list_producer(self.statusdir)) request.push( "
    " '' % (self.statusdir, medusa_gif.width, medusa_gif.height) + "" ) request.done() elif path == self.statusdir + "/medusa.gif": request["Content-Type"] = "image/gif" request["Content-Length"] = len(medusa_gif.data) request.push(medusa_gif.data) request.done() elif path == self.statusdir + "/close_zombies": message = ( "

    Closing all zombie http client connections...

    " '

    Back to the status page' % self.statusdir ) request["Content-Type"] = "text/html" request["Content-Length"] = len(message) request.push(message) now = int(time.time()) for channel in asyncore.socket_map.keys(): if channel.__class__ == http_server.http_channel: if channel != request.channel: if (now - channel.creation_time) > channel.zombie_timeout: channel.close() request.done() # Emergency Debug Mode # If a server is running away from you, don't KILL it! # Move all the AF_INET server ports and perform an autopsy... # [disabled by default to protect the innocent] elif self.allow_emergency_debug and path == self.statusdir + "/emergency_debug": request.push("Moving All Servers...") request.done() for channel in asyncore.socket_map.keys(): if channel.accepting: if type(channel.addr) is type(()): ip, port = channel.addr channel.socket.close() channel.del_channel() channel.addr = (ip, port + 10000) fam, typ = channel.family_and_type channel.create_socket(fam, typ) channel.set_reuse_addr() channel.bind(channel.addr) channel.listen(5) else: m = self.hyper_regex.match(path) if m: oid = string.atoi(m.group(1)) for object in self.hyper_objects: if id(object) == oid: if hasattr(object, "hyper_respond"): object.hyper_respond(self, path, request) else: request.error(404) return def status(self): return producers.simple_producer( "

  • Status Extension Hits : %s" % self.hit_counter ) def register_hyper_object(self, object): if not object in self.hyper_objects: self.hyper_objects.append(object) import logger class logger_for_status(logger.tail_logger): def status(self): return "Last %d log entries for: %s" % (len(self.messages), html_repr(self)) def hyper_respond(self, sh, path, request): request["Content-Type"] = "text/plain" messages = self.messages[:] messages.reverse() request.push(lines_producer(messages)) request.done() class lines_producer: def __init__(self, lines): self.lines = lines def ready(self): return len(self.lines) def more(self): if self.lines: chunk = self.lines[:50] self.lines = self.lines[50:] return string.join(chunk, "\r\n") + "\r\n" else: return "" class channel_list_producer(lines_producer): def __init__(self, statusdir): channel_reprs = map( lambda x: "<" + repr(x)[1:-1] + ">", asyncore.socket_map.values() ) channel_reprs.sort() lines_producer.__init__( self, ["

    Active Channel List

    ", "
    "]
                + channel_reprs
                + ["
    ", '

    Status Report' % statusdir], ) # this really needs a full-blown quoter... def sanitize(s): if "<" in s: s = string.join(string.split(s, "<"), "<") if ">" in s: s = string.join(string.split(s, ">"), ">") return s def html_repr(object): so = sanitize(repr(object)) if hasattr(object, "hyper_respond"): return '%s' % (id(object), so) else: return so def html_reprs(list, front="", back=""): reprs = map( lambda x, f=front, b=back: "%s%s%s" % (f, x, b), map(lambda x: sanitize(html_repr(x)), list), ) reprs.sort() return reprs # for example, tera, giga, mega, kilo # p_d (n, (1024, 1024, 1024, 1024)) # smallest divider goes first - for example # minutes, hours, days # p_d (n, (60, 60, 24)) def progressive_divide(n, parts): result = [] for part in parts: n, rem = divmod(n, part) result.append(rem) result.append(n) return result # b,k,m,g,t def split_by_units(n, units, dividers, format_string): divs = progressive_divide(n, dividers) result = [] for i in range(len(units)): if divs[i]: result.append(format_string % (divs[i], units[i])) result.reverse() if not result: return [format_string % (0, units[0])] else: return result def english_bytes(n): return split_by_units( n, ("", "K", "M", "G", "T"), (1024, 1024, 1024, 1024, 1024), "%d %sB" ) def english_time(n): return split_by_units( n, ("secs", "mins", "hours", "days", "weeks", "years"), (60, 60, 24, 7, 52), "%d %s", ) m2crypto-0.46.2/demo/medusa/virtual_handler.py000066400000000000000000000033501506746742300213400ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- import socket import default_handler import re HOST = re.compile("Host: ([^:/]+).*", re.IGNORECASE) get_header = default_handler.get_header class virtual_handler: """HTTP request handler for an HTTP/1.0-style virtual host. Each Virtual host must have a different IP""" def __init__(self, handler, hostname): self.handler = handler self.hostname = hostname try: self.ip = socket.gethostbyname(hostname) except socket.error: raise ValueError( "Virtual Hostname %s does not appear to be registered in the DNS" % hostname ) def match(self, request): if request.channel.addr[0] == self.ip: return 1 else: return 0 def handle_request(self, request): return self.handler.handle_request(request) def __repr__(self): return "" % self.hostname class virtual_handler_with_host: """HTTP request handler for HTTP/1.1-style virtual hosts. This matches by checking the value of the 'Host' header in the request. You actually don't _have_ to support HTTP/1.1 to use this, since many browsers now send the 'Host' header. This is a Good Thing.""" def __init__(self, handler, hostname): self.handler = handler self.hostname = hostname def match(self, request): host = get_header(HOST, request.header) if host == self.hostname: return 1 else: return 0 def handle_request(self, request): return self.handler.handle_request(request) def __repr__(self): return "" % self.hostname m2crypto-0.46.2/demo/medusa/xmlrpc_handler.py000066400000000000000000000055651506746742300211710ustar00rootroot00000000000000# -*- Mode: Python; tab-width: 4 -*- # See http://www.xml-rpc.com/ # http://www.pythonware.com/products/xmlrpc/ # Based on "xmlrpcserver.py" by Fredrik Lundh (fredrik@pythonware.com) from __future__ import print_function VERSION = "$Id$" import http_server import xmlrpclib import string import sys class xmlrpc_handler: def match(self, request): # Note: /RPC2 is not required by the spec, so you may override this method. if request.uri[:5] == "/RPC2": return 1 else: return 0 def handle_request(self, request): [path, params, query, fragment] = request.split_uri() if request.command in ("post", "put"): request.collector = collector(self, request) else: request.error(400) def continue_request(self, data, request): params, method = xmlrpclib.loads(data) try: # generate response try: response = self.call(method, params) if type(response) != type(()): response = (response,) except: # report exception back to server response = xmlrpclib.dumps( xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value)) ) else: response = xmlrpclib.dumps(response, methodresponse=1) except: # internal error, report as HTTP server error request.error(500) else: # got a valid XML RPC response request["Content-Type"] = "text/xml" request.push(response) request.done() def call(self, method, params): # override this method to implement RPC methods raise "NotYetImplemented" class collector: "gathers input for POST and PUT requests" def __init__(self, handler, request): self.handler = handler self.request = request self.data = "" # make sure there's a content-length header cl = request.get_header("content-length") if not cl: request.error(411) else: cl = string.atoi(cl) # using a 'numeric' terminator self.request.channel.set_terminator(cl) def collect_incoming_data(self, data): self.data = self.data + data def found_terminator(self): # set the terminator back to the default self.request.channel.set_terminator("\r\n\r\n") self.handler.continue_request(self.data, self.request) if __name__ == "__main__": class rpc_demo(xmlrpc_handler): def call(self, method, params): print('method="%s" params=%s' % (method, params)) return "Sure, that works" import asyncore import http_server hs = http_server.http_server("", 8000) rpc = rpc_demo() hs.install_handler(rpc) asyncore.loop() m2crypto-0.46.2/demo/medusa054/000077500000000000000000000000001506746742300160335ustar00rootroot00000000000000m2crypto-0.46.2/demo/medusa054/00_README000066400000000000000000000014361506746742300172160ustar00rootroot00000000000000 21 Mar 2004 ------------- M2Crypto HTTPS and FTP/TLS servers All the files in this directory are from Medusa 0.54, except for the following: - 00_README (this file) - server.pem, the server's certificate - ca.pem, my CA certificate - https_server.py - ftps_server.py - START.py - START_xmlrpc.py - index.html, a sample HTML file - poison_handler.py, a webpoison clone By default, http_server listens on port 39080 and https_server port 39443. Document root is current directory, and serves up index.html. The xmlrpc server is accessible below '/RPC2'. The FTP/TLS server listens on port 39021 by default. I've only tested it with the 'anonymous' authentication handler. Medusa files are copyright Sam Rushing. Recent versions are maintained by Andrew Kuchling. My files are copyright me. m2crypto-0.46.2/demo/medusa054/START.py000066400000000000000000000035711506746742300173100ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function # Standard Python library import os import os.path import sys # Medusa import asyncore import default_handler import filesys import ftp_server import http_server import status_handler # M2Crypto import https_server import poison_handler import ftps_server from M2Crypto import Rand, SSL, threading HTTP_PORT = 39080 HTTPS_PORT = 39443 FTP_PORT = 39021 hs = http_server.http_server("", HTTP_PORT) Rand.load_file("../randpool.dat", -1) ssl_ctx = SSL.Context("sslv23") ssl_ctx.load_cert("server.pem") ssl_ctx.load_verify_locations("ca.pem", "") ssl_ctx.load_client_CA("ca.pem") # ssl_ctx.set_verify(SSL.verify_peer, 10) # ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_fail_if_no_peer_cert, 10) # ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_client_once, 10) ssl_ctx.set_verify(SSL.verify_none, 10) ssl_ctx.set_session_id_ctx("127.0.0.1:39443") ssl_ctx.set_tmp_dh("dh1024.pem") ssl_ctx.set_info_callback() hss = https_server.https_server("", HTTPS_PORT, ssl_ctx) fs = filesys.os_filesystem(os.path.abspath(os.curdir)) # fs=filesys.os_filesystem('/usr/local/pkg/apache/htdocs') # fs=filesys.os_filesystem('c:/pkg/jdk130/docs') dh = default_handler.default_handler(fs) hs.install_handler(dh) hss.install_handler(dh) # class rpc_demo (xmlrpc_handler.xmlrpc_handler): # def call (self, method, params): # print('method="%s" params=%s' % (method, params)) # return "Sure, that works" # rpch = rpc_demo() # hs.install_handler(rpch) # hss.install_handler(rpch) ph = poison_handler.poison_handler(10) hs.install_handler(ph) hss.install_handler(ph) fauthz = ftp_server.anon_authorizer("/usr/local/pkg/apache/htdocs") ftps = ftps_server.ftp_tls_server(fauthz, ssl_ctx, port=FTP_PORT) sh = status_handler.status_extension([hs, hss, ftps]) hs.install_handler(sh) hss.install_handler(sh) asyncore.loop() Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/medusa054/START_xmlrpc.py000066400000000000000000000034261506746742300206740ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function # Standard Python library import os import os.path import sys # Medusa import asyncore import default_handler import filesys import http_server import status_handler # M2Crypto import https_server import poison_handler from M2Crypto import Rand, SSL # XMLrpc import xmlrpc_handler HTTP_PORT = 39080 HTTPS_PORT = 39443 hs = http_server.http_server("", HTTP_PORT) Rand.load_file("../randpool.dat", -1) ssl_ctx = SSL.Context("sslv23") ssl_ctx.load_cert("server.pem") # ssl_ctx.load_verify_location('ca.pem') # ssl_ctx.load_client_CA('ca.pem') # ssl_ctx.set_verify(SSL.verify_peer, 10) # ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_fail_if_no_peer_cert, 10) # ssl_ctx.set_verify(SSL.verify_peer|SSL.verify_client_once, 10) ssl_ctx.set_verify(SSL.verify_none, 10) ssl_ctx.set_session_id_ctx("127.0.0.1:9443") ssl_ctx.set_tmp_dh("dh1024.pem") # ssl_ctx.set_info_callback() hss = https_server.https_server("", HTTPS_PORT, ssl_ctx) fs = filesys.os_filesystem(os.path.abspath(os.curdir)) # fs=filesys.os_filesystem('/usr/local/pkg/apache/htdocs') # fs=filesys.os_filesystem('c:/pkg/jdk118/docs') dh = default_handler.default_handler(fs) hs.install_handler(dh) hss.install_handler(dh) # Cribbed from xmlrpc_handler.py. # This is where you implement your RPC functionality. class rpc_demo(xmlrpc_handler.xmlrpc_handler): def call(self, method, params): print('method="%s" params=%s' % (method, params)) return "Sure, that works" rpch = rpc_demo() hs.install_handler(rpch) hss.install_handler(rpch) ph = poison_handler.poison_handler(10) hs.install_handler(ph) hss.install_handler(ph) sh = status_handler.status_extension([hss]) hs.install_handler(sh) hss.install_handler(sh) asyncore.loop() Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/medusa054/ca.pem000066400000000000000000000023041506746742300171200ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDWTCCAsKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAxMTIxNTA1NTU0NloXDTA0MTIxNDA1NTU0 NlowgYAxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxML TTJDcnlwdG8gQ0ExJDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3Rl cjEiMCAGCSqGSIb3DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbTCBnzANBgkqhkiG 9w0BAQEFAAOBjQAwgYkCgYEAx8soJbS719LHK62VVVIQeC3oW0HvFArwPnA0LuEK q+LaqMOJg1rS7hvFdX03diV+XJw7cC0iECZYJNG4ii1xbY6KRmufkInaAwm54E3N e+YYVocaqUkcN6xVf6fwnLfPXbpFS/K2Umg11ObKMmi80JmiIdjcjRRCQZC7g1hf q+kCAwEAAaOB4DCB3TAdBgNVHQ4EFgQU6/qcBzEtQphfXLhiOHbt2KqBwMIwga0G A1UdIwSBpTCBooAU6/qcBzEtQphfXLhiOHbt2KqBwMKhgYakgYMwgYAxCzAJBgNV BAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0Ex JDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEiMCAGCSqGSIb3 DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqG SIb3DQEBBAUAA4GBAD+I14GuS5vJmyv1k7mUMbAicsWRHZ+zrGOq9L/L2LsA+lKQ dAzEZE2+Zv8LBPJVltbJJhcFNJS/ZMAjEm4xlJuCpvXVMxd/M5AM29aqekWlIK7J vsdDL8IuzpRkMniUiNKPhmB6IPIOslvUKx6QofcE0wDh6pg4VvIbCjkpZ7gf -----END CERTIFICATE----- m2crypto-0.46.2/demo/medusa054/counter.py000066400000000000000000000027011506746742300200640ustar00rootroot00000000000000# -*- Mode: Python -*- # It is tempting to add an __int__ method to this class, but it's not # a good idea. This class tries to gracefully handle integer # overflow, and to hide this detail from both the programmer and the # user. Note that the __str__ method can be relied on for printing out # the value of a counter: # # >>> print('Total Client: %s' % self.total_clients) # # If you need to do arithmetic with the value, then use the 'as_long' # method, the use of long arithmetic is a reminder that the counter # will overflow. from __future__ import print_function class counter: "general-purpose counter" def __init__(self, initial_value=0): self.value = initial_value def increment(self, delta=1): result = self.value try: self.value = self.value + delta except OverflowError: self.value = long(self.value) + delta return result def decrement(self, delta=1): result = self.value try: self.value = self.value - delta except OverflowError: self.value = long(self.value) - delta return result def as_long(self): return long(self.value) def __nonzero__(self): return self.value != 0 def __repr__(self): return "" % (self.value, id(self)) def __str__(self): s = str(long(self.value)) if s[-1:] == "L": s = s[:-1] return s m2crypto-0.46.2/demo/medusa054/default_handler.py000066400000000000000000000135611506746742300215340ustar00rootroot00000000000000# -*- Mode: Python -*- # # Author: Sam Rushing # Copyright 1997 by Sam Rushing # All Rights Reserved. # # standard python modules import mimetypes import re import stat import string # medusa modules import http_date import http_server import status_handler import producers unquote = http_server.unquote # This is the 'default' handler. it implements the base set of # features expected of a simple file-delivering HTTP server. file # services are provided through a 'filesystem' object, the very same # one used by the FTP server. # # You can replace or modify this handler if you want a non-standard # HTTP server. You can also derive your own handler classes from # it. # # support for handling POST requests is available in the derived # class , defined below. # from counter import counter class default_handler: valid_commands = ["GET", "HEAD"] IDENT = "Default HTTP Request Handler" # Pathnames that are tried when a URI resolves to a directory name directory_defaults = ["index.html", "default.html"] default_file_producer = producers.file_producer def __init__(self, filesystem): self.filesystem = filesystem # count total hits self.hit_counter = counter() # count file deliveries self.file_counter = counter() # count cache hits self.cache_counter = counter() hit_counter = 0 def __repr__(self): return "<%s (%s hits) at %x>" % (self.IDENT, self.hit_counter, id(self)) # always match, since this is a default def match(self, request): return 1 # handle a file request, with caching. def handle_request(self, request): if request.command not in self.valid_commands: request.error(400) # bad request return self.hit_counter.increment() path, params, query, fragment = request.split_uri() if "%" in path: path = unquote(path) # strip off all leading slashes while path and path[0] == "/": path = path[1:] if self.filesystem.isdir(path): if path and path[-1] != "/": request["Location"] = "http://%s/%s/" % ( request.channel.server.server_name, path, ) request.error(301) return # we could also generate a directory listing here, # may want to move this into another method for that # purpose found = 0 if path and path[-1] != "/": path = path + "/" for default in self.directory_defaults: p = path + default if self.filesystem.isfile(p): path = p found = 1 break if not found: request.error(404) # Not Found return elif not self.filesystem.isfile(path): request.error(404) # Not Found return file_length = self.filesystem.stat(path)[stat.ST_SIZE] ims = get_header_match(IF_MODIFIED_SINCE, request.header) length_match = 1 if ims: length = ims.group(4) if length: try: length = string.atoi(length) if length != file_length: length_match = 0 except: pass ims_date = 0 if ims: ims_date = http_date.parse_http_date(ims.group(1)) try: mtime = self.filesystem.stat(path)[stat.ST_MTIME] except: request.error(404) return if length_match and ims_date: if mtime <= ims_date: request.reply_code = 304 request.done() self.cache_counter.increment() return try: file = self.filesystem.open(path, "rb") except IOError: request.error(404) return request["Last-Modified"] = http_date.build_http_date(mtime) request["Content-Length"] = file_length self.set_content_type(path, request) if request.command == "GET": request.push(self.default_file_producer(file)) self.file_counter.increment() request.done() def set_content_type(self, path, request): ext = string.lower(get_extension(path)) typ, encoding = mimetypes.guess_type(path) if typ is not None: request["Content-Type"] = typ else: # TODO: test a chunk off the front of the file for 8-bit # characters, and use application/octet-stream instead. request["Content-Type"] = "text/plain" def status(self): return producers.simple_producer( "

  • %s" % status_handler.html_repr(self) + "
      " + "
    • Total Hits: %s" % self.hit_counter + "
    • Files Delivered: %s" % self.file_counter + "
    • Cache Hits: %s" % self.cache_counter + "
    " ) # HTTP/1.0 doesn't say anything about the "; length=nnnn" addition # to this header. I suppose its purpose is to avoid the overhead # of parsing dates... IF_MODIFIED_SINCE = re.compile( "If-Modified-Since: ([^;]+)((; length=([0-9]+)$)|$)", re.IGNORECASE ) USER_AGENT = re.compile("User-Agent: (.*)", re.IGNORECASE) CONTENT_TYPE = re.compile( r"Content-Type: ([^;]+)((; boundary=([A-Za-z0-9\'\(\)+_,./:=?-]+)$)|$)", re.IGNORECASE, ) get_header = http_server.get_header get_header_match = http_server.get_header_match def get_extension(path): dirsep = string.rfind(path, "/") dotsep = string.rfind(path, ".") if dotsep > dirsep: return path[dotsep + 1 :] else: return "" m2crypto-0.46.2/demo/medusa054/dh1024.pem000066400000000000000000000003651506746742300174440ustar00rootroot00000000000000-----BEGIN DH PARAMETERS----- MIGHAoGBAJf2QmHKtQXdKCjhPx1ottPb0PMTBH9A6FbaWMsTuKG/K3g6TG1Z1fkq /Gz/PWk/eLI9TzFgqVAuPvr3q14a1aZeVUMTgo2oO5/y2UHe6VaJ+trqCTat3xlx /mNbIK9HA2RgPC3gWfVLZQrY+gz3ASHHR5nXWHEyvpuZm7m3h+irAgEC -----END DH PARAMETERS----- m2crypto-0.46.2/demo/medusa054/filesys.py000066400000000000000000000250171506746742300200700ustar00rootroot00000000000000# -*- Mode: Python -*- # $Id$ # Author: Sam Rushing # # Generic filesystem interface. # # We want to provide a complete wrapper around any and all # filesystem operations. # this class is really just for documentation, # identifying the API for a filesystem object. # opening files for reading, and listing directories, should # return a producer. class abstract_filesystem: def __init__(self): pass def current_directory(self): "Return a string representing the current directory." pass def listdir(self, path, long=0): """Return a listing of the directory at 'path' The empty string indicates the current directory. If 'long' is set, instead return a list of (name, stat_info) tuples """ pass def open(self, path, mode): "Return an open file object" pass def stat(self, path): "Return the equivalent of os.stat() on the given path." pass def isdir(self, path): "Does the path represent a directory?" pass def isfile(self, path): "Does the path represent a plain file?" pass def cwd(self, path): "Change the working directory." pass def cdup(self): "Change to the parent of the current directory." pass def longify(self, path): """Return a 'long' representation of the filename [for the output of the LIST command]""" pass # standard wrapper around a unix-like filesystem, with a 'false root' # capability. # security considerations: can symbolic links be used to 'escape' the # root? should we allow it? if not, then we could scan the # filesystem on startup, but that would not help if they were added # later. We will probably need to check for symlinks in the cwd method. # what to do if wd is an invalid directory? import os import stat import re import string def safe_stat(path): try: return (path, os.stat(path)) except: return None import glob class os_filesystem: path_module = os.path # set this to zero if you want to disable pathname globbing. # [we currently don't glob, anyway] do_globbing = 1 def __init__(self, root, wd="/"): self.root = root self.wd = wd def current_directory(self): return self.wd def isfile(self, path): p = self.normalize(self.path_module.join(self.wd, path)) return self.path_module.isfile(self.translate(p)) def isdir(self, path): p = self.normalize(self.path_module.join(self.wd, path)) return self.path_module.isdir(self.translate(p)) def cwd(self, path): p = self.normalize(self.path_module.join(self.wd, path)) translated_path = self.translate(p) if not self.path_module.isdir(translated_path): return 0 else: old_dir = os.getcwd() # temporarily change to that directory, in order # to see if we have permission to do so. try: can = 0 try: os.chdir(translated_path) can = 1 self.wd = p except: pass finally: if can: os.chdir(old_dir) return can def cdup(self): return self.cwd("..") def listdir(self, path, long=0): p = self.translate(path) # I think we should glob, but limit it to the current # directory only. ld = os.listdir(p) if not long: return list_producer(ld, None) else: old_dir = os.getcwd() try: os.chdir(p) # if os.stat fails we ignore that file. result = filter(None, map(safe_stat, ld)) finally: os.chdir(old_dir) return list_producer(result, self.longify) # TODO: implement a cache w/timeout for stat() def stat(self, path): p = self.translate(path) return os.stat(p) def open(self, path, mode): p = self.translate(path) return open(p, mode) def unlink(self, path): p = self.translate(path) return os.unlink(p) def mkdir(self, path): p = self.translate(path) return os.mkdir(p) def rmdir(self, path): p = self.translate(path) return os.rmdir(p) # utility methods def normalize(self, path): # watch for the ever-sneaky '/+' path element path = re.sub("/+", "/", path) p = self.path_module.normpath(path) # remove 'dangling' cdup's. if len(p) > 2 and p[:3] == "/..": p = "/" return p def translate(self, path): # we need to join together three separate # path components, and do it safely. # // # use the operating system's path separator. path = string.join(string.split(path, "/"), os.sep) p = self.normalize(self.path_module.join(self.wd, path)) p = self.normalize(self.path_module.join(self.root, p[1:])) return p def longify(self, arg_tuple): path, stat_info = arg_tuple return unix_longify(path, stat_info) def __repr__(self): return "" % (self.root, self.wd) if os.name == "posix": class unix_filesystem(os_filesystem): pass class schizophrenic_unix_filesystem(os_filesystem): PROCESS_UID = os.getuid() PROCESS_EUID = os.geteuid() PROCESS_GID = os.getgid() PROCESS_EGID = os.getegid() def __init__(self, root, wd="/", persona=(None, None)): os_filesystem.__init__(self, root, wd) self.persona = persona def become_persona(self): if self.persona is not (None, None): uid, gid = self.persona # the order of these is important! os.setegid(gid) os.seteuid(uid) def become_nobody(self): if self.persona is not (None, None): os.seteuid(self.PROCESS_UID) os.setegid(self.PROCESS_GID) # cwd, cdup, open, listdir def cwd(self, path): try: self.become_persona() return os_filesystem.cwd(self, path) finally: self.become_nobody() def cdup(self, path): try: self.become_persona() return os_filesystem.cdup(self) finally: self.become_nobody() def open(self, filename, mode): try: self.become_persona() return os_filesystem.open(self, filename, mode) finally: self.become_nobody() def listdir(self, path, long=0): try: self.become_persona() return os_filesystem.listdir(self, path, long) finally: self.become_nobody() # For the 'real' root, we could obtain a list of drives, and then # use that. Doesn't win32 provide such a 'real' filesystem? # [yes, I think something like this "\\.\c\windows"] class msdos_filesystem(os_filesystem): def longify(self, arg_tuple): path, stat_info = arg_tuple return msdos_longify(path, stat_info) # A merged filesystem will let you plug other filesystems together. # We really need the equivalent of a 'mount' capability - this seems # to be the most general idea. So you'd use a 'mount' method to place # another filesystem somewhere in the hierarchy. # Note: this is most likely how I will handle ~user directories # with the http server. class merged_filesystem: def __init__(self, *fsys): pass # this matches the output of NT's ftp server (when in # MSDOS mode) exactly. def msdos_longify(file, stat_info): if stat.S_ISDIR(stat_info[stat.ST_MODE]): dir = "" else: dir = " " date = msdos_date(stat_info[stat.ST_MTIME]) return "%s %s %8d %s" % (date, dir, stat_info[stat.ST_SIZE], file) def msdos_date(t): try: info = time.gmtime(t) except: info = time.gmtime(0) # year, month, day, hour, minute, second, ... if info[3] > 11: merid = "PM" info[3] = info[3] - 12 else: merid = "AM" return "%02d-%02d-%02d %02d:%02d%s" % ( info[1], info[2], info[0] % 100, info[3], info[4], merid, ) months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ] mode_table = { "0": "---", "1": "--x", "2": "-w-", "3": "-wx", "4": "r--", "5": "r-x", "6": "rw-", "7": "rwx", } import time def unix_longify(file, stat_info): # for now, only pay attention to the lower bits mode = ("%o" % stat_info[stat.ST_MODE])[-3:] mode = string.join(map(lambda x: mode_table[x], mode), "") if stat.S_ISDIR(stat_info[stat.ST_MODE]): dirchar = "d" else: dirchar = "-" date = ls_date(long(time.time()), stat_info[stat.ST_MTIME]) return "%s%s %3d %-8d %-8d %8d %s %s" % ( dirchar, mode, stat_info[stat.ST_NLINK], stat_info[stat.ST_UID], stat_info[stat.ST_GID], stat_info[stat.ST_SIZE], date, file, ) # Emulate the unix 'ls' command's date field. # it has two formats - if the date is more than 180 # days in the past, then it's like this: # Oct 19 1995 # otherwise, it looks like this: # Oct 19 17:33 def ls_date(now, t): try: info = time.gmtime(t) except: info = time.gmtime(0) # 15,600,000 == 86,400 * 180 if (now - t) > 15600000: return "%s %2d %d" % (months[info[1] - 1], info[2], info[0]) else: return "%s %2d %02d:%02d" % (months[info[1] - 1], info[2], info[3], info[4]) # =========================================================================== # Producers # =========================================================================== class list_producer: def __init__(self, list, func=None): self.list = list self.func = func # this should do a pushd/popd def more(self): if not self.list: return "" else: # do a few at a time bunch = self.list[:50] if self.func is not None: bunch = map(self.func, bunch) self.list = self.list[50:] return string.joinfields(bunch, "\r\n") + "\r\n" m2crypto-0.46.2/demo/medusa054/ftp_server.py000066400000000000000000001107451506746742300205740ustar00rootroot00000000000000# -*- Mode: Python -*- # Author: Sam Rushing # Copyright 1996-2000 by Sam Rushing # All Rights Reserved. # # An extensible, configurable, asynchronous FTP server. # # All socket I/O is non-blocking, however file I/O is currently # blocking. Eventually file I/O may be made non-blocking, too, if it # seems necessary. Currently the only CPU-intensive operation is # getting and formatting a directory listing. [this could be moved # into another process/directory server, or another thread?] # # Only a subset of RFC 959 is implemented, but much of that RFC is # vestigial anyway. I've attempted to include the most commonly-used # commands, using the feature set of wu-ftpd as a guide. from __future__ import print_function import asyncore import asynchat import os import socket import stat import string import sys import time # from medusa.producers import file_producer from producers import file_producer # TODO: implement a directory listing cache. On very-high-load # servers this could save a lot of disk abuse, and possibly the # work of computing emulated unix ls output. # Potential security problem with the FTP protocol? I don't think # there's any verification of the origin of a data connection. Not # really a problem for the server (since it doesn't send the port # command, except when in PASV mode) But I think a data connection # could be spoofed by a program with access to a sniffer - it could # watch for a PORT command to go over a command channel, and then # connect to that port before the server does. # Unix user id's: # In order to support assuming the id of a particular user, # it seems there are two options: # 1) fork, and seteuid in the child # 2) carefully control the effective uid around filesystem accessing # methods, using try/finally. [this seems to work] VERSION = "1.1" from counter import counter import producers import status_handler import logger class ftp_channel(asynchat.async_chat): # defaults for a reliable __repr__ addr = ("unknown", "0") # unset this in a derived class in order # to enable the commands in 'self.write_commands' read_only = 1 write_commands = ["appe", "dele", "mkd", "rmd", "rnfr", "rnto", "stor", "stou"] restart_position = 0 # comply with (possibly troublesome) RFC959 requirements # This is necessary to correctly run an active data connection # through a firewall that triggers on the source port (expected # to be 'L-1', or 20 in the normal case). bind_local_minus_one = 0 def __init__(self, server, conn, addr): self.server = server self.current_mode = "a" self.addr = addr asynchat.async_chat.__init__(self, conn) self.set_terminator("\r\n") # client data port. Defaults to 'the same as the control connection'. self.client_addr = (addr[0], 21) self.client_dc = None self.in_buffer = "" self.closing = 0 self.passive_acceptor = None self.passive_connection = None self.filesystem = None self.authorized = 0 # send the greeting self.respond( "220 %s FTP server (Medusa Async V%s [experimental]) ready." % (self.server.hostname, VERSION) ) # def __del__ (self): # print('ftp_channel.__del__()') # -------------------------------------------------- # async-library methods # -------------------------------------------------- def handle_expt(self): # this is handled below. not sure what I could # do here to make that code less kludgish. pass def collect_incoming_data(self, data): self.in_buffer = self.in_buffer + data if len(self.in_buffer) > 4096: # silently truncate really long lines # (possible denial-of-service attack) self.in_buffer = "" def found_terminator(self): line = self.in_buffer if not len(line): return sp = string.find(line, " ") if sp != -1: line = [line[:sp], line[sp + 1 :]] else: line = [line] command = string.lower(line[0]) # watch especially for 'urgent' abort commands. if string.find(command, "abor") != -1: # strip off telnet sync chars and the like... while command and command[0] not in string.letters: command = command[1:] fun_name = "cmd_%s" % command if command != "pass": self.log("<== %s" % repr(self.in_buffer)[1:-1]) else: self.log("<== %s" % line[0] + " ") self.in_buffer = "" if not hasattr(self, fun_name): self.command_not_understood(line[0]) return fun = getattr(self, fun_name) if (not self.authorized) and (command not in ("user", "pass", "help", "quit")): self.respond("530 Please log in with USER and PASS") elif not self.check_command_authorization(command): self.command_not_authorized(command) else: try: result = apply(fun, (line,)) except: self.server.total_exceptions.increment() (file, fun, line), t, v, tbinfo = asyncore.compact_traceback() if self.client_dc: try: self.client_dc.close() except: pass self.respond( "451 Server Error: %s, %s: file: %s line: %s" % ( t, v, file, line, ) ) closed = 0 def close(self): if not self.closed: self.closed = 1 if self.passive_acceptor: self.passive_acceptor.close() if self.client_dc: self.client_dc.close() self.server.closed_sessions.increment() asynchat.async_chat.close(self) # -------------------------------------------------- # filesystem interface functions. # override these to provide access control or perform # other functions. # -------------------------------------------------- def cwd(self, line): return self.filesystem.cwd(line[1]) def cdup(self, line): return self.filesystem.cdup() def open(self, path, mode): return self.filesystem.open(path, mode) # returns a producer def listdir(self, path, long=0): return self.filesystem.listdir(path, long) def get_dir_list(self, line, long=0): # we need to scan the command line for arguments to '/bin/ls'... args = line[1:] path_args = [] for arg in args: if arg[0] != "-": path_args.append(arg) else: # ignore arguments pass if len(path_args) < 1: dir = "." else: dir = path_args[0] return self.listdir(dir, long) # -------------------------------------------------- # authorization methods # -------------------------------------------------- def check_command_authorization(self, command): if command in self.write_commands and self.read_only: return 0 else: return 1 # -------------------------------------------------- # utility methods # -------------------------------------------------- def log(self, message): self.server.logger.log(self.addr[0], "%d %s" % (self.addr[1], message)) def respond(self, resp): self.log("==> %s" % resp) self.push(resp + "\r\n") def command_not_understood(self, command): self.respond("500 '%s': command not understood." % command) def command_not_authorized(self, command): self.respond( "530 You are not authorized to perform the '%s' command" % (command) ) def make_xmit_channel(self): # In PASV mode, the connection may or may _not_ have been made # yet. [although in most cases it is... FTP Explorer being # the only exception I've yet seen]. This gets somewhat confusing # because things may happen in any order... pa = self.passive_acceptor if pa: if pa.ready: # a connection has already been made. conn, addr = self.passive_acceptor.ready cdc = xmit_channel(self, addr) cdc.set_socket(conn) cdc.connected = 1 self.passive_acceptor.close() self.passive_acceptor = None else: # we're still waiting for a connect to the PASV port. cdc = xmit_channel(self) else: # not in PASV mode. ip, port = self.client_addr cdc = xmit_channel(self, self.client_addr) cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) if self.bind_local_minus_one: cdc.bind(("", self.server.port - 1)) try: cdc.connect((ip, port)) except socket.error as why: self.respond("425 Can't build data connection") self.client_dc = cdc # pretty much the same as xmit, but only right on the verge of # being worth a merge. def make_recv_channel(self, fd): pa = self.passive_acceptor if pa: if pa.ready: # a connection has already been made. conn, addr = pa.ready cdc = recv_channel(self, addr, fd) cdc.set_socket(conn) cdc.connected = 1 self.passive_acceptor.close() self.passive_acceptor = None else: # we're still waiting for a connect to the PASV port. cdc = recv_channel(self, None, fd) else: # not in PASV mode. ip, port = self.client_addr cdc = recv_channel(self, self.client_addr, fd) cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) try: cdc.connect((ip, port)) except socket.error as why: self.respond("425 Can't build data connection") self.client_dc = cdc type_map = {"a": "ASCII", "i": "Binary", "e": "EBCDIC", "l": "Binary"} type_mode_map = {"a": "t", "i": "b", "e": "b", "l": "b"} # -------------------------------------------------- # command methods # -------------------------------------------------- def cmd_type(self, line): "specify data transfer type" # ascii, ebcdic, image, local t = string.lower(line[1]) # no support for EBCDIC # if t not in ['a','e','i','l']: if t not in ["a", "i", "l"]: self.command_not_understood(string.join(line)) elif t == "l" and (len(line) > 2 and line[2] != "8"): self.respond("504 Byte size must be 8") else: self.current_mode = t self.respond("200 Type set to %s." % self.type_map[t]) def cmd_quit(self, line): "terminate session" self.respond("221 Goodbye.") self.close_when_done() def cmd_port(self, line): "specify data connection port" info = string.split(line[1], ",") ip = string.join(info[:4], ".") port = string.atoi(info[4]) * 256 + string.atoi(info[5]) # how many data connections at a time? # I'm assuming one for now... # TODO: we should (optionally) verify that the # ip number belongs to the client. [wu-ftpd does this?] self.client_addr = (ip, port) self.respond("200 PORT command successful.") def new_passive_acceptor(self): # ensure that only one of these exists at a time. if self.passive_acceptor is not None: self.passive_acceptor.close() self.passive_acceptor = None self.passive_acceptor = passive_acceptor(self) return self.passive_acceptor def cmd_pasv(self, line): "prepare for server-to-server transfer" pc = self.new_passive_acceptor() port = pc.addr[1] ip_addr = pc.control_channel.getsockname()[0] self.respond( "227 Entering Passive Mode (%s,%d,%d)" % (string.replace(ip_addr, ".", ","), port / 256, port % 256) ) self.client_dc = None def cmd_nlst(self, line): "give name list of files in directory" # ncftp adds the -FC argument for the user-visible 'nlist' # command. We could try to emulate ls flags, but not just yet. if "-FC" in line: line.remove("-FC") try: dir_list_producer = self.get_dir_list(line, 0) except os.error as why: self.respond("550 Could not list directory: %s" % why) return self.respond( "150 Opening %s mode data connection for file list" % (self.type_map[self.current_mode]) ) self.make_xmit_channel() self.client_dc.push_with_producer(dir_list_producer) self.client_dc.close_when_done() def cmd_list(self, line): "give a list of files in a directory" try: dir_list_producer = self.get_dir_list(line, 1) except os.error as why: self.respond("550 Could not list directory: %s" % why) return self.respond( "150 Opening %s mode data connection for file list" % (self.type_map[self.current_mode]) ) self.make_xmit_channel() self.client_dc.push_with_producer(dir_list_producer) self.client_dc.close_when_done() def cmd_cwd(self, line): "change working directory" if self.cwd(line): self.respond("250 CWD command successful.") else: self.respond("550 No such directory.") def cmd_cdup(self, line): "change to parent of current working directory" if self.cdup(line): self.respond("250 CDUP command successful.") else: self.respond("550 No such directory.") def cmd_pwd(self, line): "print the current working directory" self.respond( '257 "%s" is the current directory.' % (self.filesystem.current_directory()) ) # modification time # example output: # 213 19960301204320 def cmd_mdtm(self, line): "show last modification time of file" filename = line[1] if not self.filesystem.isfile(filename): self.respond('550 "%s" is not a file' % filename) else: mtime = time.gmtime(self.filesystem.stat(filename)[stat.ST_MTIME]) self.respond( "213 %4d%02d%02d%02d%02d%02d" % (mtime[0], mtime[1], mtime[2], mtime[3], mtime[4], mtime[5]) ) def cmd_noop(self, line): "do nothing" self.respond("200 NOOP command successful.") def cmd_size(self, line): "return size of file" filename = line[1] if not self.filesystem.isfile(filename): self.respond('550 "%s" is not a file' % filename) else: self.respond("213 %d" % (self.filesystem.stat(filename)[stat.ST_SIZE])) def cmd_retr(self, line): "retrieve a file" if len(line) < 2: self.command_not_understood(string.join(line)) else: file = line[1] if not self.filesystem.isfile(file): self.log_info("checking %s" % file) self.respond("550 No such file") else: try: # FIXME: for some reason, 'rt' isn't working on win95 mode = "r" + self.type_mode_map[self.current_mode] fd = self.open(file, mode) except IOError as why: self.respond( "553 could not open file for reading: %s" % (repr(why)) ) return self.respond( "150 Opening %s mode data connection for file '%s'" % (self.type_map[self.current_mode], file) ) self.make_xmit_channel() if self.restart_position: # try to position the file as requested, but # give up silently on failure (the 'file object' # may not support seek()) try: fd.seek(self.restart_position) except: pass self.restart_position = 0 self.client_dc.push_with_producer(file_producer(fd)) self.client_dc.close_when_done() def cmd_stor(self, line, mode="wb"): "store a file" if len(line) < 2: self.command_not_understood(string.join(line)) else: if self.restart_position: restart_position = 0 self.respond("553 restart on STOR not yet supported") return file = line[1] # todo: handle that type flag try: fd = self.open(file, mode) except IOError as why: self.respond("553 could not open file for writing: %s" % (repr(why))) return self.respond( "150 Opening %s connection for %s" % (self.type_map[self.current_mode], file) ) self.make_recv_channel(fd) def cmd_abor(self, line): "abort operation" if self.client_dc: self.client_dc.close() self.respond("226 ABOR command successful.") def cmd_appe(self, line): "append to a file" return self.cmd_stor(line, "ab") def cmd_dele(self, line): if len(line) != 2: self.command_not_understood(string.join(line)) else: file = line[1] if self.filesystem.isfile(file): try: self.filesystem.unlink(file) self.respond("250 DELE command successful.") except: self.respond("550 error deleting file.") else: self.respond("550 %s: No such file." % file) def cmd_mkd(self, line): if len(line) != 2: self.command_not_understood(string.join(line)) else: path = line[1] try: self.filesystem.mkdir(path) self.respond("257 MKD command successful.") except: self.respond("550 error creating directory.") def cmd_rmd(self, line): if len(line) != 2: self.command_not_understood(string.join(line)) else: path = line[1] try: self.filesystem.rmdir(path) self.respond("250 RMD command successful.") except: self.respond("550 error removing directory.") def cmd_user(self, line): "specify user name" if len(line) > 1: self.user = line[1] self.respond("331 Password required.") else: self.command_not_understood(string.join(line)) def cmd_pass(self, line): "specify password" if len(line) < 2: pw = "" else: pw = line[1] result, message, fs = self.server.authorizer.authorize(self, self.user, pw) if result: self.respond("230 %s" % message) self.filesystem = fs self.authorized = 1 self.log_info("Successful login: Filesystem=%s" % repr(fs)) else: self.respond("530 %s" % message) def cmd_rest(self, line): "restart incomplete transfer" try: pos = string.atoi(line[1]) except ValueError: self.command_not_understood(string.join(line)) self.restart_position = pos self.respond( "350 Restarting at %d. Send STORE or RETRIEVE to initiate transfer." % pos ) def cmd_stru(self, line): "obsolete - set file transfer structure" if line[1] in "fF": # f == 'file' self.respond("200 STRU F Ok") else: self.respond("504 Unimplemented STRU type") def cmd_mode(self, line): "obsolete - set file transfer mode" if line[1] in "sS": # f == 'file' self.respond("200 MODE S Ok") else: self.respond("502 Unimplemented MODE type") # The stat command has two personalities. Normally it returns status # information about the current connection. But if given an argument, # it is equivalent to the LIST command, with the data sent over the # control connection. Strange. But wuftpd, ftpd, and nt's ftp server # all support it. # ## def cmd_stat (self, line): ## 'return status of server' ## pass def cmd_syst(self, line): "show operating system type of server system" # Replying to this command is of questionable utility, because # this server does not behave in a predictable way w.r.t. the # output of the LIST command. We emulate Unix ls output, but # on win32 the pathname can contain drive information at the front # Currently, the combination of ensuring that os.sep == '/' # and removing the leading slash when necessary seems to work. # [cd'ing to another drive also works] # # This is how wuftpd responds, and is probably # the most expected. The main purpose of this reply is so that # the client knows to expect Unix ls-style LIST output. self.respond("215 UNIX Type: L8") # one disadvantage to this is that some client programs # assume they can pass args to /bin/ls. # a few typical responses: # 215 UNIX Type: L8 (wuftpd) # 215 Windows_NT version 3.51 # 215 VMS MultiNet V3.3 # 500 'SYST': command not understood. (SVR4) def cmd_help(self, line): "give help information" # find all the methods that match 'cmd_xxxx', # use their docstrings for the help response. attrs = dir(self.__class__) help_lines = [] for attr in attrs: if attr[:4] == "cmd_": x = getattr(self, attr) if type(x) == type(self.cmd_help): if x.__doc__: help_lines.append("\t%s\t%s" % (attr[4:], x.__doc__)) if help_lines: self.push("214-The following commands are recognized\r\n") self.push_with_producer(producers.lines_producer(help_lines)) self.push("214\r\n") else: self.push("214-\r\n\tHelp Unavailable\r\n214\r\n") class ftp_server(asyncore.dispatcher): # override this to spawn a different FTP channel class. ftp_channel_class = ftp_channel SERVER_IDENT = "FTP Server (V%s)" % VERSION def __init__( self, authorizer, hostname=None, ip="", port=21, resolver=None, logger_object=logger.file_logger(sys.stdout), ): self.ip = ip self.port = port self.authorizer = authorizer if hostname is None: self.hostname = socket.gethostname() else: self.hostname = hostname # statistics self.total_sessions = counter() self.closed_sessions = counter() self.total_files_out = counter() self.total_files_in = counter() self.total_bytes_out = counter() self.total_bytes_in = counter() self.total_exceptions = counter() # asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() self.bind((self.ip, self.port)) self.listen(5) if not logger_object: logger_object = sys.stdout if resolver: self.logger = logger.resolving_logger(resolver, logger_object) else: self.logger = logger.unresolving_logger(logger_object) self.log_info( "FTP server started at %s\n\tAuthorizer:%s\n\tHostname: %s\n\tPort: %d" % (time.ctime(time.time()), repr(self.authorizer), self.hostname, self.port) ) def writable(self): return 0 def handle_read(self): pass def handle_connect(self): pass def handle_accept(self): conn, addr = self.accept() self.total_sessions.increment() self.log_info("Incoming connection from %s:%d" % (addr[0], addr[1])) self.ftp_channel_class(self, conn, addr) # return a producer describing the state of the server def status(self): def nice_bytes(n): return string.join(status_handler.english_bytes(n)) return producers.lines_producer( [ "

    %s

    " % self.SERVER_IDENT, "
    Listening on Host: %s" % self.hostname, "Port: %d" % self.port, "
    Sessions", "Total: %s" % self.total_sessions, "Current: %d" % (self.total_sessions.as_long() - self.closed_sessions.as_long()), "
    Files", "Sent: %s" % self.total_files_out, "Received: %s" % self.total_files_in, "
    Bytes", "Sent: %s" % nice_bytes(self.total_bytes_out.as_long()), "Received: %s" % nice_bytes(self.total_bytes_in.as_long()), "
    Exceptions: %s" % self.total_exceptions, ] ) # ====================================================================== # Data Channel Classes # ====================================================================== # This socket accepts a data connection, used when the server has been # placed in passive mode. Although the RFC implies that we ought to # be able to use the same acceptor over and over again, this presents # a problem: how do we shut it off, so that we are accepting # connections only when we expect them? [we can't] # # wuftpd, and probably all the other servers, solve this by allowing # only one connection to hit this acceptor. They then close it. Any # subsequent data-connection command will then try for the default # port on the client side [which is of course never there]. So the # 'always-send-PORT/PASV' behavior seems required. # # Another note: wuftpd will also be listening on the channel as soon # as the PASV command is sent. It does not wait for a data command # first. # --- we need to queue up a particular behavior: # 1) xmit : queue up producer[s] # 2) recv : the file object # # It would be nice if we could make both channels the same. Hmmm.. # class passive_acceptor(asyncore.dispatcher): ready = None def __init__(self, control_channel): # connect_fun (conn, addr) asyncore.dispatcher.__init__(self) self.control_channel = control_channel self.create_socket(socket.AF_INET, socket.SOCK_STREAM) # bind to an address on the interface that the # control connection is coming from. self.bind((self.control_channel.getsockname()[0], 0)) self.addr = self.getsockname() self.listen(1) # def __del__ (self): # print('passive_acceptor.__del__()') def log(self, *ignore): pass def handle_accept(self): conn, addr = self.accept() dc = self.control_channel.client_dc if dc is not None: dc.set_socket(conn) dc.addr = addr dc.connected = 1 self.control_channel.passive_acceptor = None else: self.ready = conn, addr self.close() class xmit_channel(asynchat.async_chat): # for an ethernet, you want this to be fairly large, in fact, it # _must_ be large for performance comparable to an ftpd. [64k] we # ought to investigate automatically-sized buffers... ac_out_buffer_size = 16384 bytes_out = 0 def __init__(self, channel, client_addr=None): self.channel = channel self.client_addr = client_addr asynchat.async_chat.__init__(self) # def __del__ (self): # print('xmit_channel.__del__()') def log(self, *args): pass def readable(self): return not self.connected def writable(self): return 1 def send(self, data): result = asynchat.async_chat.send(self, data) self.bytes_out = self.bytes_out + result return result def handle_error(self): # usually this is to catch an unexpected disconnect. self.log_info("unexpected disconnect on data xmit channel", "error") try: self.close() except: pass # TODO: there's a better way to do this. we need to be able to # put 'events' in the producer fifo. to do this cleanly we need # to reposition the 'producer' fifo as an 'event' fifo. def close(self): c = self.channel s = c.server c.client_dc = None s.total_files_out.increment() s.total_bytes_out.increment(self.bytes_out) if not len(self.producer_fifo): c.respond("226 Transfer complete") elif not c.closed: c.respond("426 Connection closed; transfer aborted") del c del s del self.channel asynchat.async_chat.close(self) class recv_channel(asyncore.dispatcher): def __init__(self, channel, client_addr, fd): self.channel = channel self.client_addr = client_addr self.fd = fd asyncore.dispatcher.__init__(self) self.bytes_in = counter() def log(self, *ignore): pass def handle_connect(self): pass def writable(self): return 0 def recv(*args): result = apply(asyncore.dispatcher.recv, args) self = args[0] self.bytes_in.increment(len(result)) return result buffer_size = 8192 def handle_read(self): block = self.recv(self.buffer_size) if block: try: self.fd.write(block) except IOError: self.log_info("got exception writing block...", "error") def handle_close(self): s = self.channel.server s.total_files_in.increment() s.total_bytes_in.increment(self.bytes_in.as_long()) self.fd.close() self.channel.respond("226 Transfer complete.") self.close() import filesys # not much of a doorman! 8^) class dummy_authorizer: def __init__(self, root="/"): self.root = root def authorize(self, channel, username, password): channel.persona = -1, -1 channel.read_only = 1 return 1, "Ok.", filesys.os_filesystem(self.root) class anon_authorizer: def __init__(self, root="/"): self.root = root def authorize(self, channel, username, password): if username in ("ftp", "anonymous"): channel.persona = -1, -1 channel.read_only = 1 return 1, "Ok.", filesys.os_filesystem(self.root) else: return 0, "Password invalid.", None # =========================================================================== # Unix-specific improvements # =========================================================================== if os.name == "posix": class unix_authorizer: # return a trio of (success, reply_string, filesystem) def authorize(self, channel, username, password): import crypt import pwd try: info = pwd.getpwnam(username) except KeyError: return 0, "No such user.", None mangled = info[1] if crypt.crypt(password, mangled[:2]) == mangled: channel.read_only = 0 fs = filesys.schizophrenic_unix_filesystem( "/", info[5], persona=(info[2], info[3]) ) return 1, "Login successful.", fs else: return 0, "Password invalid.", None def __repr__(self): return "" # simple anonymous ftp support class unix_authorizer_with_anonymous(unix_authorizer): def __init__(self, root=None, real_users=0): self.root = root self.real_users = real_users def authorize(self, channel, username, password): if string.lower(username) in ["anonymous", "ftp"]: import pwd try: # ok, here we run into lots of confusion. # on some os', anon runs under user 'nobody', # on others as 'ftp'. ownership is also critical. # need to investigate. # linux: new linuxen seem to have nobody's UID=-1, # which is an illegal value. Use ftp. ftp_user_info = pwd.getpwnam("ftp") if string.lower(os.uname()[0]) == "linux": nobody_user_info = pwd.getpwnam("ftp") else: nobody_user_info = pwd.getpwnam("nobody") channel.read_only = 1 if self.root is None: self.root = ftp_user_info[5] fs = filesys.unix_filesystem(self.root, "/") return 1, "Anonymous Login Successful", fs except KeyError: return 0, "Anonymous account not set up", None elif self.real_users: return unix_authorizer.authorize(self, channel, username, password) else: return 0, "User logins not allowed", None # usage: ftp_server /PATH/TO/FTP/ROOT PORT # for example: # $ ftp_server /home/users/ftp 8021 if os.name == "posix": def test(port="8021"): fs = ftp_server(unix_authorizer(), port=string.atoi(port)) try: asyncore.loop() except KeyboardInterrupt: fs.log_info("FTP server shutting down. (received SIGINT)", "warning") # close everything down on SIGINT. # of course this should be a cleaner shutdown. asyncore.close_all() if __name__ == "__main__": test(sys.argv[1]) # not unix else: def test(): fs = ftp_server(dummy_authorizer()) if __name__ == "__main__": test() # this is the command list from the wuftpd man page # '*' means we've implemented it. # '!' requires write access # command_documentation = { "abor": "abort previous command", # * "acct": "specify account (ignored)", "allo": "allocate storage (vacuously)", "appe": "append to a file", # *! "cdup": "change to parent of current working directory", # * "cwd": "change working directory", # * "dele": "delete a file", #! "help": "give help information", # * "list": "give list files in a directory", # * "mkd": "make a directory", #! "mdtm": "show last modification time of file", # * "mode": "specify data transfer mode", "nlst": "give name list of files in directory", # * "noop": "do nothing", # * "pass": "specify password", # * "pasv": "prepare for server-to-server transfer", # * "port": "specify data connection port", # * "pwd": "print the current working directory", # * "quit": "terminate session", # * "rest": "restart incomplete transfer", # * "retr": "retrieve a file", # * "rmd": "remove a directory", #! "rnfr": "specify rename-from file name", #! "rnto": "specify rename-to file name", #! "site": "non-standard commands (see next section)", "size": "return size of file", # * "stat": "return status of server", # * "stor": "store a file", # *! "stou": "store a file with a unique name", #! "stru": "specify data transfer structure", "syst": "show operating system type of server system", # * "type": "specify data transfer type", # * "user": "specify user name", # * "xcup": "change to parent of current working directory (deprecated)", "xcwd": "change working directory (deprecated)", "xmkd": "make a directory (deprecated)", #! "xpwd": "print the current working directory (deprecated)", "xrmd": "remove a directory (deprecated)", #! } # debugging aid (linux) def get_vm_size(): return string.atoi(string.split(open("/proc/self/stat").readline())[22]) def print_vm(): print("vm: %8dk" % (get_vm_size() / 1024)) m2crypto-0.46.2/demo/medusa054/ftps_server.py000066400000000000000000000360641506746742300207600ustar00rootroot00000000000000"""An FTP/TLS server built on Medusa's ftp_server. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" # Python import socket, string, sys, time # Medusa from counter import counter import asynchat, asyncore, ftp_server, logger # M2Crypto from M2Crypto import SSL, version VERSION_STRING = version class ftp_tls_channel(ftp_server.ftp_channel): """FTP/TLS server channel for Medusa.""" def __init__(self, server, ssl_ctx, conn, addr): """Initialise the channel.""" self.ssl_ctx = ssl_ctx self.server = server self.current_mode = "a" self.addr = addr asynchat.async_chat.__init__(self, conn) self.set_terminator("\r\n") self.client_addr = (addr[0], 21) self.client_dc = None self.in_buffer = "" self.closing = 0 self.passive_acceptor = None self.passive_connection = None self.filesystem = None self.authorized = 0 self._ssl_accepting = 0 self._ssl_accepted = 0 self._pbsz = None self._prot = None resp = "220 %s M2Crypto (Medusa) FTP/TLS server v%s ready." self.respond(resp % (self.server.hostname, VERSION_STRING)) def writable(self): return self._ssl_accepting or self._ssl_accepted def handle_read(self): """Handle a read event.""" if self._ssl_accepting: self._ssl_accepted = self.socket.accept_ssl() if self._ssl_accepted: self._ssl_accepting = 0 else: try: ftp_server.ftp_channel.handle_read(self) except SSL.SSLError as what: if str(what) == "unexpected eof": self.close() else: raise def handle_write(self): """Handle a write event.""" if self._ssl_accepting: self._ssl_accepted = self.socket.accept_ssl() if self._ssl_accepted: self._ssl_accepting = 0 else: try: ftp_server.ftp_channel.handle_write(self) except SSL.SSLError as what: if str(what) == "unexpected eof": self.close() else: raise def send(self, data): """Send data over SSL.""" try: result = self.socket.send(data) if result <= 0: return 0 else: return result except SSL.SSLError as what: self.close() self.log_info("send: closing channel %s %s" % (repr(self), what)) return 0 def recv(self, buffer_size): """Receive data over SSL.""" try: result = self.socket.recv(buffer_size) if not result: return "" else: return result except SSL.SSLError as what: self.close() self.log_info("recv: closing channel %s %s" % (repr(self), what)) return "" def found_terminator(self): """Dispatch the FTP command.""" line = self.in_buffer if not len(line): return sp = string.find(line, " ") if sp != -1: line = [line[:sp], line[sp + 1 :]] else: line = [line] command = string.lower(line[0]) if string.find(command, "stor") != -1: while command and command[0] not in string.letters: command = command[1:] func_name = "cmd_%s" % command if command != "pass": self.log("<== %s" % repr(self.in_buffer)[1:-1]) else: self.log("<== %s" % line[0] + " ") self.in_buffer = "" if not hasattr(self, func_name): self.command_not_understood(line[0]) return func = getattr(self, func_name) if not self.check_command_authorization(command): self.command_not_authorized(command) else: try: result = apply(func, (line,)) except: self.server.total_exceptions.increment() (file, func, line), t, v, tbinfo = asyncore.compact_traceback() if self.client_dc: try: self.client_dc_close() except: pass resp = "451 Server error: %s, %s: file %s line: %s" self.respond(resp % (t, v, file, line)) def make_xmit_channel(self): """Create a connection for sending data.""" pa = self.passive_acceptor if pa: if pa.ready: conn, addr = pa.ready if self._prot: cdc = tls_xmit_channel(self, conn, self.ssl_ctx, addr) else: cdc = ftp_server.xmit_channel(self, addr) cdc.set_socket(conn) cdc.connected = 1 self.passive_acceptor.close() self.passive_acceptor = None else: if self._prot: cdc = tls_xmit_channel(self, None, self.ssl_ctx, None) else: cdc = ftp_server.xmit_channel(self) else: if self._prot: cdc = tls_xmit_channel(self, None, self.ssl_ctx, self.client_addr) else: cdc = ftp_server.xmit_channel(self, self.client_addr) cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) if self.bind_local_minus_one: cdc.bind(("", self.server.port - 1)) try: cdc.connect(self.client_addr) except socket.error as what: self.respond("425 Cannot build data connection") self.client_dc = cdc def make_recv_channel(self, fd): """Create a connection for receiving data.""" pa = self.passive_acceptor if pa: if pa.ready: conn, addr = pa.ready if self._prot: cdc = tls_recv_channel(self, conn, self.ssl_ctx, addr, fd) else: cdc = ftp_server.recv_channel(self, addr, fd) cdc.set_socket(conn) cdc.connected = 1 self.passive_acceptor.close() self.passive_acceptor = None else: if self._prot: cdc = tls_recv_channel(self, None, self.ssl_ctx, None, fd) else: cdc = ftp_server.recv_channel(self, None, fd) else: if self._prot: cdc = tls_recv_channel( self, None, self.ssl_ctx, self._prot, self.client_addr, fd ) else: cdc = ftp_server.recv_channel(self, self.client_addr, fd) cdc.create_socket(socket.AF_INET, socket.SOCK_STREAM) try: cdc.connect(self.client_addr) except socket.error as what: self.respond("425 Cannot build data connection") self.client_dc = cdc def cmd_auth(self, line): """Prepare for TLS operation.""" # XXX Handle variations. if line[1] != "TLS": self.command_not_understood(string.join(line)) else: self.respond("234 AUTH TLS successful") self._ssl_accepting = 1 self.socket = SSL.Connection(self.ssl_ctx, self.socket) self.socket.setup_addr(self.addr) self.socket.setup_ssl() self.socket.set_accept_state() self._ssl_accepted = self.socket.accept_ssl() if self._ssl_accepted: self._ssl_accepting = 0 def cmd_pbsz(self, line): """Negotiate size of buffer for secure data transfer. For FTP/TLS the only valid value for the parameter is '0'; any other value is accepted but ignored.""" if not (self._ssl_accepting or self._ssl_accepted): return self.respond("503 AUTH TLS must be issued prior to PBSZ") self._pbsz = 1 self.respond("200 PBSZ=0 successful.") def cmd_prot(self, line): """Negotiate the security level of the data connection.""" if self._pbsz is None: return self.respond("503 PBSZ must be issued prior to PROT") if line[1] == "C": self.respond("200 Protection set to Clear") self._pbsz = None self._prot = None elif line[1] == "P": self.respond("200 Protection set to Private") self._prot = 1 elif line[1] in ("S", "E"): self.respond("536 PROT %s unsupported" % line[1]) else: self.respond("504 PROT %s unsupported" % line[1]) class ftp_tls_server(ftp_server.ftp_server): """FTP/TLS server for Medusa.""" SERVER_IDENT = "M2Crypto FTP/TLS Server (v%s)" % VERSION_STRING ftp_channel_class = ftp_tls_channel def __init__( self, authz, ssl_ctx, host=None, ip="", port=21, resolver=None, log_obj=None ): """Initialise the server.""" self.ssl_ctx = ssl_ctx self.ip = ip self.port = port self.authorizer = authz if host is None: self.hostname = socket.gethostname() else: self.hostname = host self.total_sessions = counter() self.closed_sessions = counter() self.total_files_out = counter() self.total_files_in = counter() self.total_bytes_out = counter() self.total_bytes_in = counter() self.total_exceptions = counter() asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() self.bind((self.ip, self.port)) self.listen(5) if log_obj is None: log_obj = sys.stdout if resolver: self.logger = logger.resolving_logger(resolver, log_obj) else: self.logger = logger.unresolving_logger(logger.file_logger(sys.stdout)) l = "M2Crypto (Medusa) FTP/TLS server started at %s\n\tAuthz: %s\n\tHostname: %s\n\tPort: %d" self.log_info( l % (time.ctime(time.time()), repr(self.authorizer), self.hostname, self.port) ) def handle_accept(self): """Accept a socket and dispatch a channel to handle it.""" conn, addr = self.accept() self.total_sessions.increment() self.log_info("Connection from %s:%d" % addr) self.ftp_channel_class(self, self.ssl_ctx, conn, addr) class nbio_ftp_tls_actor: """TLS protocol negotiation mixin for FTP/TLS.""" def tls_init(self, sock, ssl_ctx, client_addr): """Perform TLS protocol negotiation.""" self.ssl_ctx = ssl_ctx self.client_addr = client_addr self._ssl_handshaking = 1 self._ssl_handshake_ok = 0 if sock: self.socket = SSL.Connection(self.ssl_ctx, sock) self.socket.setup_addr(self.client_addr) self.socket.setup_ssl() self._ssl_handshake_ok = self.socket.accept_ssl() if self._ssl_handshake_ok: self._ssl_handshaking = 0 self.add_channel() # else the client hasn't connected yet; when that happens, # handle_connect() will be triggered. def tls_neg_ok(self): """Return status of TLS protocol negotiation.""" if self._ssl_handshaking: self._ssl_handshake_ok = self.socket.accept_ssl() if self._ssl_handshake_ok: self._ssl_handshaking = 0 return self._ssl_handshake_ok def handle_connect(self): """Handle a data connection that occurs after this instance came into being. When this handler is triggered, self.socket has been created and refers to the underlying connected socket.""" self.socket = SSL.Connection(self.ssl_ctx, self.socket) self.socket.setup_addr(self.client_addr) self.socket.setup_ssl() self._ssl_handshake_ok = self.socket.accept_ssl() if self._ssl_handshake_ok: self._ssl_handshaking = 0 self.add_channel() def send(self, data): """Send data over SSL.""" try: result = self.socket.send(data) if result <= 0: return 0 else: return result except SSL.SSLError as what: self.close() self.log_info("send: closing channel %s %s" % (repr(self), what)) return 0 def recv(self, buffer_size): """Receive data over SSL.""" try: result = self.socket.recv(buffer_size) if not result: return "" else: return result except SSL.SSLError as what: self.close() self.log_info("recv: closing channel %s %s" % (repr(self), what)) return "" class tls_xmit_channel(nbio_ftp_tls_actor, ftp_server.xmit_channel): """TLS driver for a send-only data connection.""" def __init__(self, channel, conn, ssl_ctx, client_addr=None): """Initialise the driver.""" ftp_server.xmit_channel.__init__(self, channel, client_addr) self.tls_init(conn, ssl_ctx, client_addr) def readable(self): """This channel is readable iff TLS negotiation is in progress. (Which implies a connected channel, of course.)""" if not self.connected: return 0 else: return self._ssl_handshaking def writable(self): """This channel is writable iff TLS negotiation is in progress or the application has data to send.""" if self._ssl_handshaking: return 1 else: return ftp_server.xmit_channel.writable(self) def handle_read(self): """Handle a read event: either continue with TLS negotiation or let the application handle this event.""" if self.tls_neg_ok(): ftp_server.xmit_channel.handle_read(self) def handle_write(self): """Handle a write event: either continue with TLS negotiation or let the application handle this event.""" if self.tls_neg_ok(): ftp_server.xmit_channel.handle_write(self) class tls_recv_channel(nbio_ftp_tls_actor, ftp_server.recv_channel): """TLS driver for a receive-only data connection.""" def __init__(self, channel, conn, ssl_ctx, client_addr, fd): """Initialise the driver.""" ftp_server.recv_channel.__init__(self, channel, client_addr, fd) self.tls_init(conn, ssl_ctx, client_addr) def writable(self): """This channel is writable iff TLS negotiation is in progress.""" return self._ssl_handshaking def handle_read(self): """Handle a read event: either continue with TLS negotiation or let the application handle this event.""" if self.tls_neg_ok(): ftp_server.recv_channel.handle_read(self) def handle_write(self): """Handle a write event: either continue with TLS negotiation or let the application handle this event.""" if self.tls_neg_ok(): ftp_server.recv_channel.handle_write(self) m2crypto-0.46.2/demo/medusa054/http_date.py000066400000000000000000000057051506746742300203700ustar00rootroot00000000000000# -*- Mode: Python -*- import re import string import time def concat(*args): return "".join(args) def join(seq, field=" "): return field.join(seq) def group(s): return "(" + s + ")" short_days = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"] long_days = [ "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", ] short_day_reg = group(join(short_days, "|")) long_day_reg = group(join(long_days, "|")) daymap = {} for i in range(7): daymap[short_days[i]] = i daymap[long_days[i]] = i hms_reg = join(3 * [group("[0-9][0-9]")], ":") months = [ "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec", ] monmap = {} for i in range(12): monmap[months[i]] = i + 1 months_reg = group(join(months, "|")) # From draft-ietf-http-v11-spec-07.txt/3.3.1 # Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 # Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 # Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format # rfc822 format rfc822_date = join( [ concat(short_day_reg, ","), # day group("[0-9][0-9]?"), # date months_reg, # month group("[0-9]+"), # year hms_reg, # hour minute second "gmt", ], " ", ) rfc822_reg = re.compile(rfc822_date) def unpack_rfc822(m): g = m.group a = string.atoi return ( a(g(4)), # year monmap[g(3)], # month a(g(2)), # day a(g(5)), # hour a(g(6)), # minute a(g(7)), # second 0, 0, 0, ) # rfc850 format rfc850_date = join( [ concat(long_day_reg, ","), join([group("[0-9][0-9]?"), months_reg, group("[0-9]+")], "-"), hms_reg, "gmt", ], " ", ) rfc850_reg = re.compile(rfc850_date) # they actually unpack the same way def unpack_rfc850(m): g = m.group a = string.atoi return ( a(g(4)), # year monmap[g(3)], # month a(g(2)), # day a(g(5)), # hour a(g(6)), # minute a(g(7)), # second 0, 0, 0, ) # parsdate.parsedate - ~700/sec. # parse_http_date - ~1333/sec. def build_http_date(when): return time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(when)) def parse_http_date(d): d = string.lower(d) tz = time.timezone m = rfc850_reg.match(d) if m and m.end() == len(d): retval = int(time.mktime(unpack_rfc850(m)) - tz) else: m = rfc822_reg.match(d) if m and m.end() == len(d): retval = int(time.mktime(unpack_rfc822(m)) - tz) else: return 0 # Thanks to Craig Silverstein for pointing # out the DST discrepancy if time.daylight and time.localtime(retval)[-1] == 1: # DST correction retval = retval + (tz - time.altzone) return retval m2crypto-0.46.2/demo/medusa054/http_server.py000066400000000000000000000573441506746742300207670ustar00rootroot00000000000000#! /usr/local/bin/python # -*- Mode: Python -*- # # Author: Sam Rushing # Copyright 1996-2000 by Sam Rushing # All Rights Reserved. # from __future__ import print_function # python modules import os import re import socket import string import sys import time # async modules import asyncore import asynchat # medusa modules import http_date import producers import status_handler import logger VERSION_STRING = "1.1" from counter import counter from urllib import unquote, splitquery # =========================================================================== # Request Object # =========================================================================== class http_request: # default reply code reply_code = 200 request_counter = counter() # Whether to automatically use chunked encoding when # # HTTP version is 1.1 # Content-Length is not set # Chunked encoding is not already in effect # # If your clients are having trouble, you might want to disable this. use_chunked = 1 # by default, this request object ignores user data. collector = None def __init__(self, *args): # unpack information about the request ( self.channel, self.request, self.command, self.uri, self.version, self.header, ) = args self.outgoing = [] self.reply_headers = { "Server": "Medusa/%s" % VERSION_STRING, "Date": http_date.build_http_date(time.time()), } self.request_number = http_request.request_counter.increment() self._split_uri = None self._header_cache = {} # -------------------------------------------------- # reply header management # -------------------------------------------------- def __setitem__(self, key, value): self.reply_headers[key] = value def __getitem__(self, key): return self.reply_headers[key] def has_key(self, key): return key in self.reply_headers def build_reply_header(self): return ( string.join( [self.response(self.reply_code)] + map(lambda x: "%s: %s" % x, self.reply_headers.items()), "\r\n", ) + "\r\n\r\n" ) # -------------------------------------------------- # split a uri # -------------------------------------------------- # ;?# path_regex = re.compile( # path params query fragment r"([^;?#]*)(;[^?#]*)?(\?[^#]*)?(#.*)?" ) def split_uri(self): if self._split_uri is None: m = self.path_regex.match(self.uri) if m.end() != len(self.uri): raise ValueError("Broken URI") else: self._split_uri = m.groups() return self._split_uri def get_header_with_regex(self, head_reg, group): for line in self.header: m = head_reg.match(line) if m.end() == len(line): return m.group(group) return "" def get_header(self, header): header = string.lower(header) hc = self._header_cache if header not in hc: h = header + ": " hl = len(h) for line in self.header: if string.lower(line[:hl]) == h: r = line[hl:] hc[header] = r return r hc[header] = None return None else: return hc[header] # -------------------------------------------------- # user data # -------------------------------------------------- def collect_incoming_data(self, data): if self.collector: self.collector.collect_incoming_data(data) else: self.log_info( "Dropping %d bytes of incoming request data" % len(data), "warning" ) def found_terminator(self): if self.collector: self.collector.found_terminator() else: self.log_info("Unexpected end-of-record for incoming request", "warning") def push(self, thing): if type(thing) == type(""): self.outgoing.append(producers.simple_producer(thing)) else: self.outgoing.append(thing) def response(self, code=200): message = self.responses[code] self.reply_code = code return "HTTP/%s %d %s" % (self.version, code, message) def error(self, code): self.reply_code = code message = self.responses[code] s = self.DEFAULT_ERROR_MESSAGE % { "code": code, "message": message, } self["Content-Length"] = len(s) self["Content-Type"] = "text/html" # make an error reply self.push(s) self.done() # can also be used for empty replies reply_now = error def done(self): "finalize this transaction - send output to the http channel" # ---------------------------------------- # persistent connection management # ---------------------------------------- # --- BUCKLE UP! ---- connection = string.lower(get_header(CONNECTION, self.header)) close_it = 0 wrap_in_chunking = 0 if self.version == "1.0": if connection == "keep-alive": if "Content-Length" not in self: close_it = 1 else: self["Connection"] = "Keep-Alive" else: close_it = 1 elif self.version == "1.1": if connection == "close": close_it = 1 elif "Content-Length" not in self: if "Transfer-Encoding" in self: if not self["Transfer-Encoding"] == "chunked": close_it = 1 elif self.use_chunked: self["Transfer-Encoding"] = "chunked" wrap_in_chunking = 1 else: close_it = 1 elif self.version is None: # Although we don't *really* support http/0.9 (because we'd have to # use \r\n as a terminator, and it would just yuck up a lot of stuff) # it's very common for developers to not want to type a version number # when using telnet to debug a server. close_it = 1 outgoing_header = producers.simple_producer(self.build_reply_header()) if close_it: self["Connection"] = "close" if wrap_in_chunking: outgoing_producer = producers.chunked_producer( producers.composite_producer(self.outgoing) ) # prepend the header outgoing_producer = producers.composite_producer( [outgoing_header, outgoing_producer] ) else: # prepend the header self.outgoing.insert(0, outgoing_header) outgoing_producer = producers.composite_producer(self.outgoing) # apply a few final transformations to the output self.channel.push_with_producer( # globbing gives us large packets producers.globbing_producer( # hooking lets us log the number of bytes sent producers.hooked_producer(outgoing_producer, self.log) ) ) self.channel.current_request = None if close_it: self.channel.close_when_done() def log_date_string(self, when): gmt = time.gmtime(when) if time.daylight and gmt[8]: tz = time.altzone else: tz = time.timezone if tz > 0: neg = 1 else: neg = 0 tz = -tz h, rem = divmod(tz, 3600) m, rem = divmod(rem, 60) if neg: offset = "-%02d%02d" % (h, m) else: offset = "+%02d%02d" % (h, m) return time.strftime("%d/%b/%Y:%H:%M:%S ", gmt) + offset def log(self, bytes): self.channel.server.logger.log( self.channel.addr[0], '%d - - [%s] "%s" %d %d\n' % ( self.channel.addr[1], self.log_date_string(time.time()), self.request, self.reply_code, bytes, ), ) responses = { 100: "Continue", 101: "Switching Protocols", 200: "OK", 201: "Created", 202: "Accepted", 203: "Non-Authoritative Information", 204: "No Content", 205: "Reset Content", 206: "Partial Content", 300: "Multiple Choices", 301: "Moved Permanently", 302: "Moved Temporarily", 303: "See Other", 304: "Not Modified", 305: "Use Proxy", 400: "Bad Request", 401: "Unauthorized", 402: "Payment Required", 403: "Forbidden", 404: "Not Found", 405: "Method Not Allowed", 406: "Not Acceptable", 407: "Proxy Authentication Required", 408: "Request Time-out", 409: "Conflict", 410: "Gone", 411: "Length Required", 412: "Precondition Failed", 413: "Request Entity Too Large", 414: "Request-URI Too Large", 415: "Unsupported Media Type", 500: "Internal Server Error", 501: "Not Implemented", 502: "Bad Gateway", 503: "Service Unavailable", 504: "Gateway Time-out", 505: "HTTP Version not supported", } # Default error message DEFAULT_ERROR_MESSAGE = string.join( [ "", "Error response", "", "", "

    Error response

    ", "

    Error code %(code)d.", "

    Message: %(message)s.", "", "", ], "\r\n", ) # =========================================================================== # HTTP Channel Object # =========================================================================== class http_channel(asynchat.async_chat): # use a larger default output buffer ac_out_buffer_size = 1 << 16 current_request = None channel_counter = counter() def __init__(self, server, conn, addr): self.channel_number = http_channel.channel_counter.increment() self.request_counter = counter() asynchat.async_chat.__init__(self, conn) self.server = server self.addr = addr self.set_terminator("\r\n\r\n") self.in_buffer = "" self.creation_time = int(time.time()) self.check_maintenance() def __repr__(self): ar = asynchat.async_chat.__repr__(self)[1:-1] return "<%s channel#: %s requests:%s>" % ( ar, self.channel_number, self.request_counter, ) # Channel Counter, Maintenance Interval... maintenance_interval = 500 def check_maintenance(self): if not self.channel_number % self.maintenance_interval: self.maintenance() def maintenance(self): self.kill_zombies() # 30-minute zombie timeout. status_handler also knows how to kill zombies. zombie_timeout = 30 * 60 def kill_zombies(self): now = int(time.time()) for channel in asyncore.socket_map.values(): if channel.__class__ == self.__class__: if (now - channel.creation_time) > channel.zombie_timeout: channel.close() # -------------------------------------------------- # send/recv overrides, good place for instrumentation. # -------------------------------------------------- # this information needs to get into the request object, # so that it may log correctly. def send(self, data): result = asynchat.async_chat.send(self, data) self.server.bytes_out.increment(len(data)) return result def recv(self, buffer_size): try: result = asynchat.async_chat.recv(self, buffer_size) self.server.bytes_in.increment(len(result)) return result except MemoryError: # --- Save a Trip to Your Service Provider --- # It's possible for a process to eat up all the memory of # the machine, and put it in an extremely wedged state, # where medusa keeps running and can't be shut down. This # is where MemoryError tends to get thrown, though of # course it could get thrown elsewhere. sys.exit("Out of Memory!") def handle_error(self): t, v = sys.exc_info()[:2] if t is SystemExit: raise t(v) else: asynchat.async_chat.handle_error(self) def log(self, *args): pass # -------------------------------------------------- # async_chat methods # -------------------------------------------------- def collect_incoming_data(self, data): if self.current_request: # we are receiving data (probably POST data) for a request self.current_request.collect_incoming_data(data) else: # we are receiving header (request) data self.in_buffer = self.in_buffer + data def found_terminator(self): if self.current_request: self.current_request.found_terminator() else: header = self.in_buffer self.in_buffer = "" lines = string.split(header, "\r\n") # -------------------------------------------------- # crack the request header # -------------------------------------------------- while lines and not lines[0]: # as per the suggestion of http-1.1 section 4.1, (and # Eric Parker ), ignore a leading # blank lines (buggy browsers tack it onto the end of # POST requests) lines = lines[1:] if not lines: self.close_when_done() return request = lines[0] command, uri, version = crack_request(request) header = join_headers(lines[1:]) # unquote path if necessary (thanks to Skip Montanaro for pointing # out that we must unquote in piecemeal fashion). rpath, rquery = splitquery(uri) if "%" in rpath: if rquery: uri = unquote(rpath) + "?" + rquery else: uri = unquote(rpath) r = http_request(self, request, command, uri, version, header) self.request_counter.increment() self.server.total_requests.increment() if command is None: self.log_info("Bad HTTP request: %s" % repr(request), "error") r.error(400) return # -------------------------------------------------- # handler selection and dispatch # -------------------------------------------------- for h in self.server.handlers: if h.match(r): try: self.current_request = r # This isn't used anywhere. # r.handler = h # CYCLE h.handle_request(r) except: self.server.exceptions.increment() (file, fun, line), t, v, tbinfo = asyncore.compact_traceback() self.log_info( "Server Error: %s, %s: file: %s line: %s" % (t, v, file, line), "error", ) try: r.error(500) except: pass return # no handlers, so complain r.error(404) def writable_for_proxy(self): # this version of writable supports the idea of a 'stalled' producer # [i.e., it's not ready to produce any output yet] This is needed by # the proxy, which will be waiting for the magic combination of # 1) hostname resolved # 2) connection made # 3) data available. if self.ac_out_buffer: return 1 elif len(self.producer_fifo): p = self.producer_fifo.first() if hasattr(p, "stalled"): return not p.stalled() else: return 1 # =========================================================================== # HTTP Server Object # =========================================================================== class http_server(asyncore.dispatcher): SERVER_IDENT = "HTTP Server (V%s)" % VERSION_STRING channel_class = http_channel def __init__(self, ip, port, resolver=None, logger_object=None): self.ip = ip self.port = port asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.handlers = [] if not logger_object: logger_object = logger.file_logger(sys.stdout) self.set_reuse_addr() self.bind((ip, port)) # lower this to 5 if your OS complains self.listen(1024) host, port = self.socket.getsockname() if not ip: self.log_info("Computing default hostname", "warning") ip = socket.gethostbyname(socket.gethostname()) try: self.server_name = socket.gethostbyaddr(ip)[0] except socket.error: self.log_info("Cannot do reverse lookup", "warning") self.server_name = ip # use the IP address as the "hostname" self.server_port = port self.total_clients = counter() self.total_requests = counter() self.exceptions = counter() self.bytes_out = counter() self.bytes_in = counter() if not logger_object: logger_object = logger.file_logger(sys.stdout) if resolver: self.logger = logger.resolving_logger(resolver, logger_object) else: self.logger = logger.unresolving_logger(logger_object) self.log_info( "Medusa (V%s) started at %s" "\n\tHostname: %s" "\n\tPort:%d" "\n" % ( VERSION_STRING, time.ctime(time.time()), self.server_name, port, ) ) def writable(self): return 0 def handle_read(self): pass def readable(self): return self.accepting def handle_connect(self): pass def handle_accept(self): self.total_clients.increment() try: conn, addr = self.accept() except socket.error: # linux: on rare occasions we get a bogus socket back from # accept. socketmodule.c:makesockaddr complains that the # address family is unknown. We don't want the whole server # to shut down because of this. self.log_info("warning: server accept() threw an exception", "warning") return except TypeError: # unpack non-sequence. this can happen when a read event # fires on a listening socket, but when we call accept() # we get EWOULDBLOCK, so dispatcher.accept() returns None. # Seen on FreeBSD3. self.log_info("warning: server accept() threw EWOULDBLOCK", "warning") return self.channel_class(self, conn, addr) def install_handler(self, handler, back=0): if back: self.handlers.append(handler) else: self.handlers.insert(0, handler) def remove_handler(self, handler): self.handlers.remove(handler) def status(self): def nice_bytes(n): return string.join(status_handler.english_bytes(n)) handler_stats = filter(None, map(maybe_status, self.handlers)) if self.total_clients: ratio = self.total_requests.as_long() / float(self.total_clients.as_long()) else: ratio = 0.0 return producers.composite_producer( [ producers.lines_producer( [ "

    %s

    " % self.SERVER_IDENT, "
    Listening on: Host: %s" % self.server_name, "Port: %d" % self.port, "

      " "
    • Total Clients: %s" % self.total_clients, "Requests: %s" % self.total_requests, "Requests/Client: %.1f" % (ratio), "
    • Total Bytes In: %s" % (nice_bytes(self.bytes_in.as_long())), "Bytes Out: %s" % (nice_bytes(self.bytes_out.as_long())), "
    • Total Exceptions: %s" % self.exceptions, "

    " "Extension List

      ", ] ) ] + handler_stats + [producers.simple_producer("
    ")] ) def maybe_status(thing): if hasattr(thing, "status"): return thing.status() else: return None CONNECTION = re.compile("Connection: (.*)", re.IGNORECASE) # merge multi-line headers # [486dx2: ~500/sec] def join_headers(headers): r = [] for i in range(len(headers)): if headers[i][0] in " \t": r[-1] = r[-1] + headers[i][1:] else: r.append(headers[i]) return r def get_header(head_reg, lines, group=1): for line in lines: m = head_reg.match(line) if m and m.end() == len(line): return m.group(group) return "" def get_header_match(head_reg, lines): for line in lines: m = head_reg.match(line) if m and m.end() == len(line): return m return "" REQUEST = re.compile("([^ ]+) ([^ ]+)(( HTTP/([0-9.]+))$|$)") def crack_request(r): m = REQUEST.match(r) if m and m.end() == len(r): if m.group(3): version = m.group(5) else: version = None return m.group(1), m.group(2), version else: return None, None, None if __name__ == "__main__": import sys if len(sys.argv) < 2: print("usage: %s " % (sys.argv[0])) else: import monitor import filesys import default_handler import status_handler import ftp_server import chat_server import resolver import logger rs = resolver.caching_resolver("127.0.0.1") lg = logger.file_logger(sys.stdout) ms = monitor.secure_monitor_server("fnord", "127.0.0.1", 9999) fs = filesys.os_filesystem(sys.argv[1]) dh = default_handler.default_handler(fs) hs = http_server("", string.atoi(sys.argv[2]), rs, lg) hs.install_handler(dh) ftp = ftp_server.ftp_server( ftp_server.dummy_authorizer(sys.argv[1]), port=8021, resolver=rs, logger_object=lg, ) cs = chat_server.chat_server("", 7777) sh = status_handler.status_extension([hs, ms, ftp, cs, rs]) hs.install_handler(sh) if "-p" in sys.argv: def profile_loop(): try: asyncore.loop() except KeyboardInterrupt: pass import profile profile.run("profile_loop()", "profile.out") else: asyncore.loop() m2crypto-0.46.2/demo/medusa054/https_server.py000066400000000000000000000051611506746742300211400ustar00rootroot00000000000000#!/usr/bin/env python """A https server built on Medusa's http_server. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" import asynchat, asyncore, http_server, socket, sys from M2Crypto import SSL, version VERSION_STRING = version class https_channel(http_server.http_channel): ac_in_buffer_size = 1 << 16 def __init__(self, server, conn, addr): http_server.http_channel.__init__(self, server, conn, addr) def send(self, data): try: result = self.socket._write_nbio(data) if result <= 0: return 0 else: self.server.bytes_out.increment(result) return result except SSL.SSLError as why: self.close() self.log_info("send: closing channel %s %s" % (repr(self), why)) return 0 def recv(self, buffer_size): try: result = self.socket._read_nbio(buffer_size) if result is None: return "" elif result == "": self.close() return "" else: self.server.bytes_in.increment(len(result)) return result except SSL.SSLError as why: self.close() self.log_info("recv: closing channel %s %s" % (repr(self), why)) return "" class https_server(http_server.http_server): SERVER_IDENT = "M2Crypto HTTPS Server (v%s)" % VERSION_STRING channel_class = https_channel def __init__(self, ip, port, ssl_ctx, resolver=None, logger_object=None): http_server.http_server.__init__(self, ip, port, resolver, logger_object) sys.stdout.write(self.SERVER_IDENT + "\n\n") sys.stdout.flush() self.ssl_ctx = ssl_ctx def handle_accept(self): # Cribbed from http_server. self.total_clients.increment() try: conn, addr = self.accept() except socket.error: # linux: on rare occasions we get a bogus socket back from # accept. socketmodule.c:makesockaddr complains that the # address family is unknown. We don't want the whole server # to shut down because of this. sys.stderr.write("warning: server accept() threw an exception\n") return # Turn the vanilla socket into an SSL connection. try: ssl_conn = SSL.Connection(self.ssl_ctx, conn) ssl_conn._setup_ssl(addr) ssl_conn.accept_ssl() self.channel_class(self, ssl_conn, addr) except SSL.SSLError: pass def writeable(self): return 0 m2crypto-0.46.2/demo/medusa054/index.html000066400000000000000000000001561506746742300200320ustar00rootroot00000000000000 M2Crypto HTTPS Server

    M2Crypto HTTPS Server - It works!

    m2crypto-0.46.2/demo/medusa054/logger.py000066400000000000000000000170231506746742300176670ustar00rootroot00000000000000# -*- Mode: Python -*- import asynchat import socket import time # these three are for the rotating logger import os # | import stat # v # # three types of log: # 1) file # with optional flushing. Also, one that rotates the log. # 2) socket # dump output directly to a socket connection. [how do we # keep it open?] # 3) syslog # log to syslog via tcp. this is a per-line protocol. # # # The 'standard' interface to a logging object is simply # log_object.log (message) # # a file-like object that captures output, and # makes sure to flush it always... this could # be connected to: # o stdio file # o low-level file # o socket channel # o syslog output... class file_logger: # pass this either a path or a file object. def __init__(self, file, flush=1, mode="a"): if type(file) == type(""): if file == "-": import sys self.file = sys.stdout else: self.file = open(file, mode) else: self.file = file self.do_flush = flush def __repr__(self): return "" % self.file def write(self, data): self.file.write(data) self.maybe_flush() def writeline(self, line): self.file.writeline(line) self.maybe_flush() def writelines(self, lines): self.file.writelines(lines) self.maybe_flush() def maybe_flush(self): if self.do_flush: self.file.flush() def flush(self): self.file.flush() def softspace(self, *args): pass def log(self, message): if message[-1] not in ("\r", "\n"): self.write(message + "\n") else: self.write(message) # like a file_logger, but it must be attached to a filename. # When the log gets too full, or a certain time has passed, # it backs up the log and starts a new one. Note that backing # up the log is done via "mv" because anything else (cp, gzip) # would take time, during which medusa would do nothing else. class rotating_file_logger(file_logger): # If freq is non-None we back up "daily", "weekly", or "monthly". # Else if maxsize is non-None we back up whenever the log gets # to big. If both are None we never back up. def __init__(self, file, freq=None, maxsize=None, flush=1, mode="a"): self.filename = file self.mode = mode self.file = open(file, mode) self.freq = freq self.maxsize = maxsize self.rotate_when = self.next_backup(self.freq) self.do_flush = flush def __repr__(self): return "" % self.file # We back up at midnight every 1) day, 2) monday, or 3) 1st of month def next_backup(self, freq): (yr, mo, day, hr, min, sec, wd, jday, dst) = time.localtime(time.time()) if freq == "daily": return time.mktime((yr, mo, day + 1, 0, 0, 0, 0, 0, -1)) elif freq == "weekly": return time.mktime( (yr, mo, day - wd + 7, 0, 0, 0, 0, 0, -1) ) # wd(monday)==0 elif freq == "monthly": return time.mktime((yr, mo + 1, 1, 0, 0, 0, 0, 0, -1)) else: return None # not a date-based backup def maybe_flush(self): # rotate first if necessary self.maybe_rotate() if self.do_flush: # from file_logger() self.file.flush() def maybe_rotate(self): if self.freq and time.time() > self.rotate_when: self.rotate() self.rotate_when = self.next_backup(self.freq) elif self.maxsize: # rotate when we get too big try: if os.stat(self.filename)[stat.ST_SIZE] > self.maxsize: self.rotate() except os.error: # file not found, probably self.rotate() # will create a new file def rotate(self): (yr, mo, day, hr, min, sec, wd, jday, dst) = time.localtime(time.time()) try: self.file.close() newname = "%s.ends%04d%02d%02d" % (self.filename, yr, mo, day) try: open(newname, "r").close() # check if file exists newname = newname + "-%02d%02d%02d" % (hr, min, sec) except: # YEARMODY is unique pass os.rename(self.filename, newname) self.file = open(self.filename, self.mode) except: pass # syslog is a line-oriented log protocol - this class would be # appropriate for FTP or HTTP logs, but not for dumping stderr to. # TODO: a simple safety wrapper that will ensure that the line sent # to syslog is reasonable. # TODO: async version of syslog_client: now, log entries use blocking # send() import m_syslog syslog_logger = m_syslog.syslog_client class syslog_logger(m_syslog.syslog_client): def __init__(self, address, facility="user"): m_syslog.syslog_client.__init__(self, address) self.facility = m_syslog.facility_names[facility] self.address = address def __repr__(self): return "" % (repr(self.address)) def log(self, message): m_syslog.syslog_client.log( self, message, facility=self.facility, priority=m_syslog.LOG_INFO ) # log to a stream socket, asynchronously class socket_logger(asynchat.async_chat): def __init__(self, address): if type(address) == type(""): self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM) else: self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect(address) self.address = address def __repr__(self): return "" % (self.address) def log(self, message): if message[-2:] != "\r\n": self.socket.push(message + "\r\n") else: self.socket.push(message) # log to multiple places class multi_logger: def __init__(self, loggers): self.loggers = loggers def __repr__(self): return "" % (repr(self.loggers)) def log(self, message): for logger in self.loggers: logger.log(message) class resolving_logger: """Feed (ip, message) combinations into this logger to get a resolved hostname in front of the message. The message will not be logged until the PTR request finishes (or fails).""" def __init__(self, resolver, logger): self.resolver = resolver self.logger = logger class logger_thunk: def __init__(self, message, logger): self.message = message self.logger = logger def __call__(self, host, ttl, answer): if not answer: answer = host self.logger.log("%s:%s" % (answer, self.message)) def log(self, ip, message): self.resolver.resolve_ptr(ip, self.logger_thunk(message, self.logger)) class unresolving_logger: "Just in case you don't want to resolve" def __init__(self, logger): self.logger = logger def log(self, ip, message): self.logger.log("%s:%s" % (ip, message)) def strip_eol(line): while line and line[-1] in "\r\n": line = line[:-1] return line class tail_logger: "Keep track of the last log messages" def __init__(self, logger, size=500): self.size = size self.logger = logger self.messages = [] def log(self, message): self.messages.append(strip_eol(message)) if len(self.messages) > self.size: del self.messages[0] self.logger.log(message) m2crypto-0.46.2/demo/medusa054/m_syslog.py000066400000000000000000000141351506746742300202450ustar00rootroot00000000000000# -*- Mode: Python -*- # ====================================================================== # Copyright 1997 by Sam Rushing # # 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, and that the name of Sam # Rushing not be used in advertising or publicity pertaining to # distribution of the software without specific, written prior # permission. # # SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN # NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # ====================================================================== """socket interface to unix syslog. On Unix, there are usually two ways of getting to syslog: via a local unix-domain socket, or via the TCP service. Usually "/dev/log" is the unix domain socket. This may be different for other systems. >>> my_client = syslog_client ('/dev/log') Otherwise, just use the UDP version, port 514. >>> my_client = syslog_client (('my_log_host', 514)) On win32, you will have to use the UDP version. Note that you can use this to log to other hosts (and indeed, multiple hosts). This module is not a drop-in replacement for the python extension module - the interface is different. Usage: >>> c = syslog_client() >>> c = syslog_client ('/strange/non_standard_log_location') >>> c = syslog_client (('other_host.com', 514)) >>> c.log ('testing', facility='local0', priority='debug') """ # TODO: support named-pipe syslog. # [see ftp://sunsite.unc.edu/pub/Linux/system/Daemons/syslog-fifo.tar.z] # from : # =========================================================================== # priorities/facilities are encoded into a single 32-bit quantity, where the # bottom 3 bits are the priority (0-7) and the top 28 bits are the facility # (0-big number). Both the priorities and the facilities map roughly # one-to-one to strings in the syslogd(8) source code. This mapping is # included in this file. # # priorities (these are ordered) LOG_EMERG = 0 # system is unusable LOG_ALERT = 1 # action must be taken immediately LOG_CRIT = 2 # critical conditions LOG_ERR = 3 # error conditions LOG_WARNING = 4 # warning conditions LOG_NOTICE = 5 # normal but significant condition LOG_INFO = 6 # informational LOG_DEBUG = 7 # debug-level messages # facility codes LOG_KERN = 0 # kernel messages LOG_USER = 1 # random user-level messages LOG_MAIL = 2 # mail system LOG_DAEMON = 3 # system daemons LOG_AUTH = 4 # security/authorization messages LOG_SYSLOG = 5 # messages generated internally by syslogd LOG_LPR = 6 # line printer subsystem LOG_NEWS = 7 # network news subsystem LOG_UUCP = 8 # UUCP subsystem LOG_CRON = 9 # clock daemon LOG_AUTHPRIV = 10 # security/authorization messages (private) # other codes through 15 reserved for system use LOG_LOCAL0 = 16 # reserved for local use LOG_LOCAL1 = 17 # reserved for local use LOG_LOCAL2 = 18 # reserved for local use LOG_LOCAL3 = 19 # reserved for local use LOG_LOCAL4 = 20 # reserved for local use LOG_LOCAL5 = 21 # reserved for local use LOG_LOCAL6 = 22 # reserved for local use LOG_LOCAL7 = 23 # reserved for local use priority_names = { "alert": LOG_ALERT, "crit": LOG_CRIT, "debug": LOG_DEBUG, "emerg": LOG_EMERG, "err": LOG_ERR, "error": LOG_ERR, # DEPRECATED "info": LOG_INFO, "notice": LOG_NOTICE, "panic": LOG_EMERG, # DEPRECATED "warn": LOG_WARNING, # DEPRECATED "warning": LOG_WARNING, } facility_names = { "auth": LOG_AUTH, "authpriv": LOG_AUTHPRIV, "cron": LOG_CRON, "daemon": LOG_DAEMON, "kern": LOG_KERN, "lpr": LOG_LPR, "mail": LOG_MAIL, "news": LOG_NEWS, "security": LOG_AUTH, # DEPRECATED "syslog": LOG_SYSLOG, "user": LOG_USER, "uucp": LOG_UUCP, "local0": LOG_LOCAL0, "local1": LOG_LOCAL1, "local2": LOG_LOCAL2, "local3": LOG_LOCAL3, "local4": LOG_LOCAL4, "local5": LOG_LOCAL5, "local6": LOG_LOCAL6, "local7": LOG_LOCAL7, } import socket class syslog_client: def __init__(self, address="/dev/log"): self.address = address self.stream = 0 if isinstance(address, type("")): try: self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) self.socket.connect(address) except socket.error: # Some Linux installations have /dev/log # a stream socket instead of a datagram socket. self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self.stream = 1 else: self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # curious: when talking to the unix-domain '/dev/log' socket, a # zero-terminator seems to be required. this string is placed # into a class variable so that it can be overridden if # necessary. log_format_string = "<%d>%s\000" def log(self, message, facility=LOG_USER, priority=LOG_INFO): message = self.log_format_string % ( self.encode_priority(facility, priority), message, ) if self.stream: self.socket.send(message) else: self.socket.sendto(message, self.address) def encode_priority(self, facility, priority): if type(facility) == type(""): facility = facility_names[facility] if type(priority) == type(""): priority = priority_names[priority] return (facility << 3) | priority def close(self): if self.stream: self.socket.close() m2crypto-0.46.2/demo/medusa054/medusa_gif.py000066400000000000000000000053241506746742300205140ustar00rootroot00000000000000# -*- Mode: Python -*- # the medusa icon as a python source file. width = 97 height = 61 data = "GIF89aa\000=\000\204\000\000\000\000\000\255\255\255\245\245\245ssskkkccc111)))\326\326\326!!!\316\316\316\300\300\300\204\204\000\224\224\224\214\214\214\200\200\200RRR\377\377\377JJJ\367\367\367BBB\347\347\347\000\204\000\020\020\020\265\265\265\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000!\371\004\001\000\000\021\000,\000\000\000\000a\000=\000\000\005\376`$\216di\236h\252\256l\353\276p,\317tm\337x\256\357|m\001@\240E\305\000\364\2164\206R)$\005\201\214\007r\012{X\255\312a\004\260\\>\026\3240\353)\224n\001W+X\334\373\231~\344.\303b\216\024\027x<\273\307\255G,rJiWN\014{S}k\"?ti\013EdPQ\207G@_%\000\026yy\\\201\202\227\224<\221Fs$pOjWz\241\272\002\325\307g\012(\007\205\312#j\317(\012A\200\224.\241\003\346GS\247\033\245\344\264\366\015L'PXQl]\266\263\243\232\260?\245\316\371\362\225\035\332\243J\273\332Q\263\357-D\241T\327\270\265\013W&\330\010u\371b\322IW0\214\261]\003\033Va\365Z#\207\213a\030k\2647\262\014p\354\024[n\321N\363\346\317\003\037P\000\235C\302\000\3228(\244\363YaA\005\022\255_\237@\260\000A\212\326\256qbp\321\332\266\011\334=T\023\010\"!B\005\003A\010\224\020\220 H\002\337#\020 O\276E\357h\221\327\003\\\000b@v\004\351A.h\365\354\342B\002\011\257\025\\ \220\340\301\353\006\000\024\214\200pA\300\353\012\364\241k/\340\033C\202\003\000\310fZ\011\003V\240R\005\007\354\376\026A\000\000\360'\202\177\024\004\210\003\000\305\215\360\000\000\015\220\240\332\203\027@'\202\004\025VpA\000%\210x\321\206\032J\341\316\010\262\211H\"l\333\341\200\200>\"]P\002\212\011\010`\002\0066FP\200\001'\024p]\004\027(8B\221\306]\000\201w>\002iB\001\007\340\260\"v7J1\343(\257\020\251\243\011\242i\263\017\215\337\035\220\200\221\365m4d\015\016D\251\341iN\354\346Ng\253\200I\240\031\35609\245\2057\311I\302\2007t\231\"&`\314\310\244\011e\226(\236\010w\212\300\234\011\012HX(\214\253\311@\001\233^\222pg{% \340\035\224&H\000\246\201\362\215`@\001\"L\340\004\030\234\022\250'\015(V:\302\235\030\240q\337\205\224\212h@\177\006\000\250\210\004\007\310\207\337\005\257-P\346\257\367]p\353\203\271\256:\203\236\211F\340\247\010\3329g\244\010\307*=A\000\203\260y\012\304s#\014\007D\207,N\007\304\265\027\021C\233\207%B\366[m\353\006\006\034j\360\306+\357\274a\204\000\000;" m2crypto-0.46.2/demo/medusa054/poison_handler.py000066400000000000000000000035131506746742300214130ustar00rootroot00000000000000import string import whrandom RESP_HEAD = """\ """ RESP_MIDDLE = """

    M2Crypto https server demonstration

    This web page is generated by the "poison" http request handler.
    The links just go on and on and on...

    """ RESP_TAIL = """ """ charset = "012345678/90ABCDEFGHIJKLM/NOPQRSTUVWXYZabcd/efghijklmnopqrs/tuvwxyz" numchar = len(charset) def makepage(numlinks): title = "" for u in range(whrandom.randint(3, 15)): pick = whrandom.randint(0, numchar - 1) title = title + charset[pick] title = title + "" url = "\r\n" numlinks = whrandom.randint(2, numlinks) for i in range(numlinks): url = url + '' for u in range(whrandom.randint(3, 15)): pick = whrandom.randint(0, numchar - 1) url = url + charset[pick] url = url + "
    \r\n" url = RESP_HEAD + title + RESP_MIDDLE + url + RESP_TAIL return url class poison_handler: """This is a clone of webpoison - every URL returns a page of URLs, each of which returns a page of URLs, each of _which_ returns a page of URLs, ad infinitum. The objective is to sucker address-harvesting bots run by spammers.""" def __init__(self, numlinks=10): self.numlinks = numlinks self.poison_level = 0 def match(self, request): return request.uri[:7] == "/poison" def handle_request(self, request): if request.command == "get": request.push(makepage(self.numlinks)) request.done() m2crypto-0.46.2/demo/medusa054/producers.py000066400000000000000000000216731506746742300204240ustar00rootroot00000000000000# -*- Mode: Python -*- """ A collection of producers. Each producer implements a particular feature: They can be combined in various ways to get interesting and useful behaviors. For example, you can feed dynamically-produced output into the compressing producer, then wrap this with the 'chunked' transfer-encoding producer. """ import string from asynchat import find_prefix_at_end class simple_producer: "producer for a string" def __init__(self, data, buffer_size=1024): self.data = data self.buffer_size = buffer_size def more(self): if len(self.data) > self.buffer_size: result = self.data[: self.buffer_size] self.data = self.data[self.buffer_size :] return result else: result = self.data self.data = "" return result class scanning_producer: "like simple_producer, but more efficient for large strings" def __init__(self, data, buffer_size=1024): self.data = data self.buffer_size = buffer_size self.pos = 0 def more(self): if self.pos < len(self.data): lp = self.pos rp = min(len(self.data), self.pos + self.buffer_size) result = self.data[lp:rp] self.pos = self.pos + len(result) return result else: return "" class lines_producer: "producer for a list of lines" def __init__(self, lines): self.lines = lines def more(self): if self.lines: chunk = self.lines[:50] self.lines = self.lines[50:] return string.join(chunk, "\r\n") + "\r\n" else: return "" class buffer_list_producer: "producer for a list of strings" # i.e., data == string.join (buffers, '') def __init__(self, buffers): self.index = 0 self.buffers = buffers def more(self): if self.index >= len(self.buffers): return "" else: data = self.buffers[self.index] self.index = self.index + 1 return data class file_producer: "producer wrapper for file[-like] objects" # match http_channel's outgoing buffer size out_buffer_size = 1 << 16 def __init__(self, file): self.done = 0 self.file = file def more(self): if self.done: return "" else: data = self.file.read(self.out_buffer_size) if not data: self.file.close() del self.file self.done = 1 return "" else: return data # A simple output producer. This one does not [yet] have # the safety feature builtin to the monitor channel: runaway # output will not be caught. # don't try to print from within any of the methods # of this object. class output_producer: "Acts like an output file; suitable for capturing sys.stdout" def __init__(self): self.data = "" def write(self, data): lines = string.splitfields(data, "\n") data = string.join(lines, "\r\n") self.data = self.data + data def writeline(self, line): self.data = self.data + line + "\r\n" def writelines(self, lines): self.data = self.data + string.joinfields(lines, "\r\n") + "\r\n" def flush(self): pass def softspace(self, *args): pass def more(self): if self.data: result = self.data[:512] self.data = self.data[512:] return result else: return "" class composite_producer: "combine a fifo of producers into one" def __init__(self, producers): self.producers = producers def more(self): while len(self.producers): p = self.producers[0] d = p.more() if d: return d else: self.producers.pop(0) else: return "" class globbing_producer: """ 'glob' the output from a producer into a particular buffer size. helps reduce the number of calls to send(). [this appears to gain about 30% performance on requests to a single channel] """ def __init__(self, producer, buffer_size=1 << 16): self.producer = producer self.buffer = "" self.buffer_size = buffer_size def more(self): while len(self.buffer) < self.buffer_size: data = self.producer.more() if data: self.buffer = self.buffer + data else: break r = self.buffer self.buffer = "" return r class hooked_producer: """ A producer that will call when it empties,. with an argument of the number of bytes produced. Useful for logging/instrumentation purposes. """ def __init__(self, producer, function): self.producer = producer self.function = function self.bytes = 0 def more(self): if self.producer: result = self.producer.more() if not result: self.producer = None self.function(self.bytes) else: self.bytes = self.bytes + len(result) return result else: return "" # HTTP 1.1 emphasizes that an advertised Content-Length header MUST be # correct. In the face of Strange Files, it is conceivable that # reading a 'file' may produce an amount of data not matching that # reported by os.stat() [text/binary mode issues, perhaps the file is # being appended to, etc..] This makes the chunked encoding a True # Blessing, and it really ought to be used even with normal files. # How beautifully it blends with the concept of the producer. class chunked_producer: """A producer that implements the 'chunked' transfer coding for HTTP/1.1. Here is a sample usage: request['Transfer-Encoding'] = 'chunked' request.push ( producers.chunked_producer (your_producer) ) request.done() """ def __init__(self, producer, footers=None): self.producer = producer self.footers = footers def more(self): if self.producer: data = self.producer.more() if data: return "%x\r\n%s\r\n" % (len(data), data) else: self.producer = None if self.footers: return string.join(["0"] + self.footers, "\r\n") + "\r\n\r\n" else: return "0\r\n\r\n" else: return "" # Unfortunately this isn't very useful right now (Aug 97), because # apparently the browsers don't do on-the-fly decompression. Which # is sad, because this could _really_ speed things up, especially for # low-bandwidth clients (i.e., most everyone). try: import zlib except ImportError: zlib = None class compressed_producer: """ Compress another producer on-the-fly, using ZLIB [Unfortunately, none of the current browsers seem to support this] """ # Note: It's not very efficient to have the server repeatedly # compressing your outgoing files: compress them ahead of time, or # use a compress-once-and-store scheme. However, if you have low # bandwidth and low traffic, this may make more sense than # maintaining your source files compressed. # # Can also be used for compressing dynamically-produced output. def __init__(self, producer, level=5): self.producer = producer self.compressor = zlib.compressobj(level) def more(self): if self.producer: cdata = "" # feed until we get some output while not cdata: data = self.producer.more() if not data: self.producer = None return self.compressor.flush() else: cdata = self.compressor.compress(data) return cdata else: return "" class escaping_producer: "A producer that escapes a sequence of characters" " Common usage: escaping the CRLF.CRLF sequence in SMTP, NNTP, etc..." def __init__(self, producer, esc_from="\r\n.", esc_to="\r\n.."): self.producer = producer self.esc_from = esc_from self.esc_to = esc_to self.buffer = "" self.find_prefix_at_end = find_prefix_at_end def more(self): esc_from = self.esc_from esc_to = self.esc_to buffer = self.buffer + self.producer.more() if buffer: buffer = string.replace(buffer, esc_from, esc_to) i = self.find_prefix_at_end(buffer, esc_from) if i: # we found a prefix self.buffer = buffer[-i:] return buffer[:-i] else: # no prefix, return it all self.buffer = "" return buffer else: return buffer m2crypto-0.46.2/demo/medusa054/server.pem000066400000000000000000000041101506746742300200400ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDYjCCAsugAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAzMDYyMjEzMzAxNFoXDTA0MDYyMTEzMzAx NFowXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwls b2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5leGFtcGxlLmRv bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA37aKGZtFicl8xXXTLJ8/JD7c kd3t/teCX9i61lpaDQCKBoVrrursIvZihemMKI9g/u/+BLqt5g8mBdgUdYz0txc8 KEbV2hj+wwOX4H3XwD0Y+DysXiNHq7/tFdmzSVHoLxpY4zYzXbxQ/p049wvIyPRp /y3omcnx/TEUhkn+JmkCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4 QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTB H/mUYlww24mJlSxEtGdlwojO9zCBrQYDVR0jBIGlMIGigBTr+pwHMS1CmF9cuGI4 du3YqoHAwqGBhqSBgzCBgDELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv MRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8gQ2VydGlm aWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNuZ3BzQG5ldG1lbWV0aWMuY29t ggEAMA0GCSqGSIb3DQEBBAUAA4GBAAvl6v0s3eFeGP4iAcrfysuK7jzFKhjDYuOy lVS3u33bZNLnMpM6OSEM9yPh4WpFCVHf+nYwC71pk4ilsLVXjKxymm2lNGcxLVuW iydFz4Ly9nmN7Ja9ygYT39dGAFP/wN7ELTpsbul8VfmqhNg9y81d8i/A1tK3AGA8 0QkPQNdP -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDftooZm0WJyXzFddMsnz8kPtyR3e3+14Jf2LrWWloNAIoGhWuu 6uwi9mKF6Ywoj2D+7/4Euq3mDyYF2BR1jPS3FzwoRtXaGP7DA5fgfdfAPRj4PKxe I0erv+0V2bNJUegvGljjNjNdvFD+nTj3C8jI9Gn/LeiZyfH9MRSGSf4maQIDAQAB AoGAHpeVtv62uarl9xKvuBBm0AwQmZnhq9HIsFaw5hMg8Vo7hbzFBvx1IirTOkC/ u+QvfW1QLVFh6m3z4ySzV4fZBtcd6F9SbSrZ0xsxIUB2NOSa1RGgiaP61bJnMMM1 xM3O9iwM5GZc3Gqy08QOCpDl0772VJ+9Gz3FA88mrc6rHQkCQQDz6RIatFjT28n8 1vy0nHwwZz2oXTpe/pyZPwoKj8zVsmrKhKwOw7l8ArxjP8zoHOE7AQBCXYDMNoFp IAF0yuqrAkEA6s0wMEdPpQeb0XHAfccyJQoeULxHdVFoz1wWmGSOm4YmQtR8/QJx luEgfpeRkzxBKt5Ls3MEkheIOw7xV24zOwJAMz+DaE0AZPNHS3K4ghJnHZxzng6I lzEUIjbWm0V/ml70hTy/EhMZw+6nOotLOHHo+QbK0SboSwAgzL/Gzo1cJQJANqpS 38qadleRJXAQWrg3qnvyluVe1aeAeVZ9RDmVIgxXeBO0jcs12uTLBe4PzHGo0mwy v7K1i7XC180gzzQu5QJBAOxITT9RoWSSozPvnirHd37sn+RsrNYkV07NAa80M20Z DkBPHeMVkNgigrQ6L6vWmbRDGQbGcMplAxnI5ppKCoU= -----END RSA PRIVATE KEY----- m2crypto-0.46.2/demo/medusa054/status_handler.py000066400000000000000000000206061506746742300214310ustar00rootroot00000000000000# -*- Mode: Python -*- VERSION_STRING = "$Id$" # # medusa status extension # import string import time import re from cgi import escape import asyncore import http_server import medusa_gif import producers from counter import counter START_TIME = long(time.time()) class status_extension: hit_counter = counter() def __init__(self, objects, statusdir="/status", allow_emergency_debug=0): self.objects = objects self.statusdir = statusdir self.allow_emergency_debug = allow_emergency_debug # We use /status instead of statusdir here because it's too # hard to pass statusdir to the logger, who makes the HREF # to the object dir. We don't need the security-through- # obscurity here in any case, because the id is obscurity enough self.hyper_regex = re.compile("/status/object/([0-9]+)/.*") self.hyper_objects = [] for object in objects: self.register_hyper_object(object) def __repr__(self): return "" % (self.hit_counter, id(self)) def match(self, request): path, params, query, fragment = request.split_uri() # For reasons explained above, we don't use statusdir for /object return ( path[: len(self.statusdir)] == self.statusdir or path[: len("/status/object/")] == "/status/object/" ) # Possible Targets: # /status # /status/channel_list # /status/medusa.gif # can we have 'clickable' objects? # [yes, we can use id(x) and do a linear search] # Dynamic producers: # HTTP/1.0: we must close the channel, because it's dynamic output # HTTP/1.1: we can use the chunked transfer-encoding, and leave # it open. def handle_request(self, request): [path, params, query, fragment] = request.split_uri() self.hit_counter.increment() if path == self.statusdir: # and not a subdirectory up_time = string.join(english_time(long(time.time()) - START_TIME)) request["Content-Type"] = "text/html" request.push( "" "Medusa Status Reports" '' "

    Medusa Status Reports

    " "Up: %s" % up_time ) for i in range(len(self.objects)): request.push(self.objects[i].status()) request.push("
    \r\n") request.push( '

    Channel List' "


    " '' "" % (self.statusdir, self.statusdir, medusa_gif.width, medusa_gif.height) ) request.done() elif path == self.statusdir + "/channel_list": request["Content-Type"] = "text/html" request.push("") request.push(channel_list_producer(self.statusdir)) request.push( "
    " '' % (self.statusdir, medusa_gif.width, medusa_gif.height) + "" ) request.done() elif path == self.statusdir + "/medusa.gif": request["Content-Type"] = "image/gif" request["Content-Length"] = len(medusa_gif.data) request.push(medusa_gif.data) request.done() elif path == self.statusdir + "/close_zombies": message = ( "

    Closing all zombie http client connections...

    " '

    Back to the status page' % self.statusdir ) request["Content-Type"] = "text/html" request["Content-Length"] = len(message) request.push(message) now = int(time.time()) for channel in asyncore.socket_map.keys(): if channel.__class__ == http_server.http_channel: if channel != request.channel: if (now - channel.creation_time) > channel.zombie_timeout: channel.close() request.done() # Emergency Debug Mode # If a server is running away from you, don't KILL it! # Move all the AF_INET server ports and perform an autopsy... # [disabled by default to protect the innocent] elif self.allow_emergency_debug and path == self.statusdir + "/emergency_debug": request.push("Moving All Servers...") request.done() for channel in asyncore.socket_map.keys(): if channel.accepting: if type(channel.addr) is type(()): ip, port = channel.addr channel.socket.close() channel.del_channel() channel.addr = (ip, port + 10000) fam, typ = channel.family_and_type channel.create_socket(fam, typ) channel.set_reuse_addr() channel.bind(channel.addr) channel.listen(5) else: m = self.hyper_regex.match(path) if m: oid = string.atoi(m.group(1)) for object in self.hyper_objects: if id(object) == oid: if hasattr(object, "hyper_respond"): object.hyper_respond(self, path, request) else: request.error(404) return def status(self): return producers.simple_producer( "

  • Status Extension Hits : %s" % self.hit_counter ) def register_hyper_object(self, object): if not object in self.hyper_objects: self.hyper_objects.append(object) import logger class logger_for_status(logger.tail_logger): def status(self): return "Last %d log entries for: %s" % (len(self.messages), html_repr(self)) def hyper_respond(self, sh, path, request): request["Content-Type"] = "text/plain" messages = self.messages[:] messages.reverse() request.push(lines_producer(messages)) request.done() class lines_producer: def __init__(self, lines): self.lines = lines def more(self): if self.lines: chunk = self.lines[:50] self.lines = self.lines[50:] return string.join(chunk, "\r\n") + "\r\n" else: return "" class channel_list_producer(lines_producer): def __init__(self, statusdir): channel_reprs = map( lambda x: "<" + repr(x)[1:-1] + ">", asyncore.socket_map.values() ) channel_reprs.sort() lines_producer.__init__( self, ["

    Active Channel List

    ", "
    "]
                + channel_reprs
                + ["
    ", '

    Status Report' % statusdir], ) def html_repr(object): so = escape(repr(object)) if hasattr(object, "hyper_respond"): return '%s' % (id(object), so) else: return so def html_reprs(list, front="", back=""): reprs = map( lambda x, f=front, b=back: "%s%s%s" % (f, x, b), map(lambda x: escape(html_repr(x)), list), ) reprs.sort() return reprs # for example, tera, giga, mega, kilo # p_d (n, (1024, 1024, 1024, 1024)) # smallest divider goes first - for example # minutes, hours, days # p_d (n, (60, 60, 24)) def progressive_divide(n, parts): result = [] for part in parts: n, rem = divmod(n, part) result.append(rem) result.append(n) return result # b,k,m,g,t def split_by_units(n, units, dividers, format_string): divs = progressive_divide(n, dividers) result = [] for i in range(len(units)): if divs[i]: result.append(format_string % (divs[i], units[i])) result.reverse() if not result: return [format_string % (0, units[0])] else: return result def english_bytes(n): return split_by_units( n, ("", "K", "M", "G", "T"), (1024, 1024, 1024, 1024, 1024), "%d %sB" ) def english_time(n): return split_by_units( n, ("secs", "mins", "hours", "days", "weeks", "years"), (60, 60, 24, 7, 52), "%d %s", ) m2crypto-0.46.2/demo/medusa054/xmlrpc_handler.py000066400000000000000000000055071506746742300214160ustar00rootroot00000000000000# -*- Mode: Python -*- # See http://www.xml-rpc.com/ # http://www.pythonware.com/products/xmlrpc/ # Based on "xmlrpcserver.py" by Fredrik Lundh (fredrik@pythonware.com) from __future__ import print_function VERSION = "$Id$" import http_server import xmlrpclib import string import sys class xmlrpc_handler: def match(self, request): # Note: /RPC2 is not required by the spec, so you may override this method. if request.uri[:5] == "/RPC2": return 1 else: return 0 def handle_request(self, request): [path, params, query, fragment] = request.split_uri() if request.command == "POST": request.collector = collector(self, request) else: request.error(400) def continue_request(self, data, request): params, method = xmlrpclib.loads(data) try: # generate response try: response = self.call(method, params) if type(response) != type(()): response = (response,) except: # report exception back to server response = xmlrpclib.dumps( xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value)) ) else: response = xmlrpclib.dumps(response, methodresponse=1) except: # internal error, report as HTTP server error request.error(500) else: # got a valid XML RPC response request["Content-Type"] = "text/xml" request.push(response) request.done() def call(self, method, params): # override this method to implement RPC methods raise "NotYetImplemented" class collector: "gathers input for POST and PUT requests" def __init__(self, handler, request): self.handler = handler self.request = request self.data = "" # make sure there's a content-length header cl = request.get_header("content-length") if not cl: request.error(411) else: cl = string.atoi(cl) # using a 'numeric' terminator self.request.channel.set_terminator(cl) def collect_incoming_data(self, data): self.data = self.data + data def found_terminator(self): # set the terminator back to the default self.request.channel.set_terminator("\r\n\r\n") self.handler.continue_request(self.data, self.request) if __name__ == "__main__": class rpc_demo(xmlrpc_handler): def call(self, method, params): print('method="%s" params=%s' % (method, params)) return "Sure, that works" import asyncore hs = http_server.http_server("", 8000) rpc = rpc_demo() hs.install_handler(rpc) asyncore.loop() m2crypto-0.46.2/demo/perf/000077500000000000000000000000001506746742300152605ustar00rootroot00000000000000m2crypto-0.46.2/demo/perf/memio.py000066400000000000000000000023701506746742300167420ustar00rootroot00000000000000#!/usr/bin/env python2.0 """A comparison of Python's cStringIO and M2Crypto's MemoryBuffer, the outcome of which is that MemoryBuffer suffers from doing too much in Python. Two way to optimise MemoryBuffer: 1. Create MemoryBufferIn and MemoryBufferOut a la StringI and StringO. 2. Have MemoryBuffer do all internal work with cStringIO. ;-) """ from cStringIO import StringIO from M2Crypto.BIO import MemoryBuffer from M2Crypto import m2 import profile txt = "Python, Smalltalk, Haskell, Scheme, Lisp, Self, Erlang, ML, ..." def stringi(iter, txt=txt): buf = StringIO() for i in range(iter): buf.write(txt) out = buf.getvalue() def membufi(iter, txt=txt): buf = MemoryBuffer() for i in range(iter): buf.write(txt) out = buf.getvalue() def membuf2i(iter, txt=txt): buf = MemoryBuffer() buf.write(txt * iter) out = buf.getvalue() def cmembufi(iter, txt=txt): buf = m2.bio_new(m2.bio_s_mem()) for i in range(iter): m2.bio_write(buf, txt) m2.bio_set_mem_eof_return(buf, 0) out = m2.bio_read(buf, m2.bio_ctrl_pending(buf)) if __name__ == "__main__": profile.run("stringi(10000)") profile.run("cmembufi(10000)") profile.run("membufi(10000)") profile.run("membuf2i(10000)") m2crypto-0.46.2/demo/perf/sha1.py000066400000000000000000000020461506746742300164700ustar00rootroot00000000000000#!/usr/bin/env python2.0 """A comparison of Python's sha and M2Crypto.EVP.MessageDigest, the outcome of which is that EVP.MessageDigest suffers from doing too much in Python.""" import profile from sha import sha import M2Crypto from M2Crypto import m2 from M2Crypto.EVP import MessageDigest txt = "Python, Smalltalk, Haskell, Scheme, Lisp, Self, Erlang, ML, ..." def py_sha(iter, txt=txt): s = sha() for i in range(iter): s.update(txt) out = s.digest() def m2_sha(iter, txt=txt): s = MessageDigest("sha1") for i in range(iter): s.update(txt) out = s.digest() def m2_sha_2(iter, txt=txt): s = MessageDigest("sha1") s.update(txt * iter) out = s.digest() def m2c_sha(iter, txt=txt): ctx = m2.md_ctx_new() m2.digest_init(ctx, m2.sha1()) for i in range(iter): m2.digest_update(ctx, txt) out = m2.digest_final(ctx) if __name__ == "__main__": profile.run("py_sha(10000)") profile.run("m2_sha(10000)") profile.run("m2_sha_2(10000)") profile.run("m2c_sha(10000)") m2crypto-0.46.2/demo/pgp/000077500000000000000000000000001506746742300151125ustar00rootroot00000000000000m2crypto-0.46.2/demo/pgp/pgpstep.py000066400000000000000000000063351506746742300171550ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """pgpstep - steps through a pgp2 packet stream. Copyright (c) 1999 Ng Pheng Siong. All rights reserved.""" from M2Crypto import PGP, util import time def desc_public_key(pkt): print("packet = public_key") print("version =", pkt.version()) print("created = ", time.asctime(time.gmtime(pkt.timestamp()))) print("validity code =", pkt.validity()) print("pkc type =", repr(pkt.pkc())) # e, n = pkt.pubkey() print("e =", repr(pkt._e)) print("n =", repr(pkt._n)) print() def desc_trust(pkt): print("packet = trust") print("trustworthiness = ") print() def desc_userid(pkt): print("packet = user_id") print("user_id =", pkt.userid()) print() def desc_signature(pkt): print("packet = signature") print("version =", pkt.version()) print("classification =", repr(pkt._classification)) print("created = ", time.asctime(time.gmtime(pkt.timestamp()))) print("keyid =", repr(pkt._keyid)) print("pkc type =", repr(pkt.pkc())) print("md_algo =", repr(pkt._md_algo)) print("md_chksum =", repr(pkt._md_chksum)) print("sig =", repr(pkt._sig)) print() def desc_private_key(pkt): print("packet = private key") print("version =", pkt.version()) print("created = ", time.asctime(time.gmtime(pkt.timestamp()))) print("validity code =", pkt.validity()) print("pkc type =", repr(pkt.pkc())) print("e =", repr(pkt._e)) print("n =", repr(pkt._n)) print("cipher =", repr(pkt._cipher)) if pkt._cipher == "\001": print("following attributes are encrypted") print("iv =", repr(pkt._iv)) print("d =", repr(pkt._d)) print("p =", repr(pkt._p)) print("q =", repr(pkt._q)) print("u =", repr(pkt._u)) print("checksum =", repr(pkt._cksum)) print() def desc_cke(pkt): print("packet = cke") print("iv =", repr(pkt.iv)) print("checksum =", repr(pkt.cksum)) print("ciphertext =", repr(pkt.ctxt)) print() def desc_pke(pkt): print("packet = pke") print("version =", pkt.version) print("keyid =", repr(pkt.keyid)) print("pkc type =", pkt.pkc_type) print("dek =", hex(pkt.dek)[:-1]) print() def desc_literal(pkt): print("packet = literal data") print("mode =", repr(pkt.fmode)) print("filename =", pkt.fname) print("time = ", time.asctime(time.gmtime(pkt.ftime))) print("data = <%d octets of literal data>" % (len(pkt.data),)) print() DESC = { PGP.public_key_packet: desc_public_key, PGP.trust_packet: desc_trust, PGP.userid_packet: desc_userid, PGP.signature_packet: desc_signature, PGP.private_key_packet: desc_private_key, PGP.cke_packet: desc_cke, PGP.pke_packet: desc_pke, PGP.literal_packet: desc_literal, } if __name__ == "__main__": import sys count = 0 for arg in sys.argv[1:]: f = open(arg, "rb") ps = PGP.packet_stream(f) while 1: pkt = ps.read() if pkt is None: break elif pkt: print("-" * 70) DESC[pkt.__class__](pkt) count = count + ps.count() ps.close() print("-" * 70) print("Total octets processed =", count) m2crypto-0.46.2/demo/pgp/pubring.pgp000066400000000000000000000021001506746742300172610ustar00rootroot0000000000000028iPH6Nړ[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ķ$V3XO $ֱmTױv eM0 "++ݒma@Fw[A ^`("o: mC($Xښ@yRU Zl跿l"n5i>;`/f'W6ut2(KϻΟHdaft 223a5- d 7x yUTtԔ;JDAMN}> +7VGP=?2WM[) -h{ `5DʤDf:9 fa9>\@#=Ogёvi1r%R[IY.'G un5&Qd|d1U0^ִk⣟XLΘUhSUDz)!:^IVC+fOB PdσwaύxGt֑:oDIL= ƪHпtz}X#ViץBF-)RaQ f%8aQ* :O>h1!U~jrK`O+[",drgmF |·^4 Uڟis`琫:E/g|)w]\|?SeDWx nU Billy boy2o;$/Ea T-.vd>kdmf&nU^˚@ BE<8Q:I!MIl=\37L DK>V7N`q~!o?9AV] ,.y,2Hyfcx'/'3K^BBA qWt\B(O}3X`Ø~I6_e7uo.6oM-c>uUH#L+/?US-~#DQ':d~j5βG6DzM֭]V뎉~P5} cG !=" |Or/5ʭ-5P |̰|ptBns7|cBwv[\+}2c57G-:g aMzCDG*L:`'2 Shʽ%IА@+n" rI(jr UfEJOx7D !N/6.5So-nZU>.&eZtHh[bXT&뙭daftm2crypto-0.46.2/demo/pkcs7/000077500000000000000000000000001506746742300153535ustar00rootroot00000000000000m2crypto-0.46.2/demo/pkcs7/pkcs7-thawte.pem000066400000000000000000000053511506746742300204030ustar00rootroot00000000000000-----BEGIN PKCS7----- MIAGCSqGSIb3DQEHAqCAMIIH1wIBATELMAkGBSsOAwIaBQAwgAYJKoZIhvcNAQcB AACgggXgMIICxDCCAi2gAwIBAgIDAphPMA0GCSqGSIb3DQEBBAUAMIGUMQswCQYD VQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRQwEgYDVQQHEwtEdXJiYW52 aWxsZTEPMA0GA1UEChMGVGhhd3RlMR0wGwYDVQQLExRDZXJ0aWZpY2F0ZSBTZXJ2 aWNlczEoMCYGA1UEAxMfUGVyc29uYWwgRnJlZW1haWwgUlNBIDE5OTkuOS4xNjAe Fw0wMDA1MTgxMTA4MTJaFw0wMTA1MTgxMTA4MTJaMGUxETAPBgNVBAQTCFN0cm9l ZGVyMRAwDgYDVQQqEwdNaWNoYWVsMRkwFwYDVQQDExBNaWNoYWVsIFN0cm9lZGVy MSMwIQYJKoZIhvcNAQkBFhRtaWNoYWVsQHN0cm9lZGVyLmNvbTCBnzANBgkqhkiG 9w0BAQEFAAOBjQAwgYkCgYEAqzxf+ZpWoELOD7sXes/G9O6dSCkGeNL/G5l0k/b4 C9QnZyEh2S0vWI+g43G1uGhu6sgI5Y1SfrG08xGIUEcmexxnl6krTR/QlHr+t9If UXFTmEPAnuIpfPRUqhOQlNFB1DfwKVLb4J3b2947ulv4vpb4owVMC+WjDM5fo765 RXMCAwEAAaNSMFAwHwYDVR0RBBgwFoEUbWljaGFlbEBzdHJvZWRlci5jb20wDAYD VR0TAQH/BAIwADAfBgNVHSMEGDAWgBSIq/Fgg2ZV9ORYx0YdwGG9I9fDjDANBgkq hkiG9w0BAQQFAAOBgQCxx7Uvsnq1F/yOIPiUmlaTXLFAvvTj2trHAF4UFhkQGe6V IBHmDk62H1xJhA4AHNVz3Pe250S8Fu75OgOh2pRJ8KfB6cJU0gxz9ahRt48Qy6+m XUHk9135ru2u8I505nj4i37T6zK3+O/lZU+P79qdPHYwO6dNsYyaRFYLxGyXTjCC AxQwggJ9oAMCAQICAQswDQYJKoZIhvcNAQEEBQAwgdExCzAJBgNVBAYTAlpBMRUw EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy dmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFp bCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNv bTAeFw05OTA5MTYxNDAxNDBaFw0wMTA5MTUxNDAxNDBaMIGUMQswCQYDVQQGEwJa QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRQwEgYDVQQHEwtEdXJiYW52aWxsZTEP MA0GA1UEChMGVGhhd3RlMR0wGwYDVQQLExRDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEo MCYGA1UEAxMfUGVyc29uYWwgRnJlZW1haWwgUlNBIDE5OTkuOS4xNjCBnzANBgkq hkiG9w0BAQEFAAOBjQAwgYkCgYEAs2lal9TQFgt6tcVd6SGcI3LNEkxL937Px/vK ciT0QlKsV5Xje2F6F4Tn/XI5OJS06u1lp5IGXr3gZfYZu5R5dkw+uWhwdYQc9BF0 ALwFLE8JAxcxzPRB1HLGpl3iiESwiy7ETfHw1oU+bPOVlHiRfkDpnNGNFVeOwnPl MN5G9U8CAwEAAaM3MDUwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBRy ScJzNMZV9At2coF+d/SH58ayDjANBgkqhkiG9w0BAQQFAAOBgQBrxlnpMfrptuyx A9jfcnL+kWBI6sZV3XvwZ47GYXDnbcKlN9idtxcoVgWL3Vx1b8aRkMZsZnET0BB8 a5FvhuAhNi3B1+qyCa3PLW3Gg1Kb+7v+nIed/LfpdJLkXJeu/H6syg1vcnpnLGtz 9Yb5nfUAbvQdB86dnoJjKe+TCX5V3jGCAdAwggHMAgEBMIGcMIGUMQswCQYDVQQG EwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRQwEgYDVQQHEwtEdXJiYW52aWxs ZTEPMA0GA1UEChMGVGhhd3RlMR0wGwYDVQQLExRDZXJ0aWZpY2F0ZSBTZXJ2aWNl czEoMCYGA1UEAxMfUGVyc29uYWwgRnJlZW1haWwgUlNBIDE5OTkuOS4xNgIDAphP MAkGBSsOAwIaBQCggYowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG 9w0BCQUxDxcNMDAwNzE2MTQ0MzQ0WjAjBgkqhkiG9w0BCQQxFgQU2jmj7l5rSw0y Vb/vlWAYkK/YBwkwKwYJKoZIhvcNAQkPMR4wHDAKBggqhkiG9w0DBzAOBggqhkiG 9w0DAgICAIAwDQYJKoZIhvcNAQEBBQAEgYBagl1y4nRwW+GLhZ5tElkh9Z/yFirz ZXI0jMywML/ADxsAf1yV2JIYCCk0V33QdrYy8MVqgErGXxGdA5aKnm5545Wf4Noz CLWF4FJc6RDSFp7dv2631TrswdFRRCHNds+dvP5v5EAiADvmEOYaDiWM07jp73jx TkkzxW9cevZDaQAAAAA= -----END PKCS7----- m2crypto-0.46.2/demo/pkcs7/test.py000066400000000000000000000002361506746742300167050ustar00rootroot00000000000000from __future__ import print_function from M2Crypto import BIO, SMIME pf = BIO.openfile("pkcs7-thawte.pem") p7 = SMIME.load_pkcs7_bio(pf) print(p7.type(1)) m2crypto-0.46.2/demo/rsa.priv.pem000066400000000000000000000007611506746742300165770ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIBOwIBAAJBANQNY7RD9BarYRsmMazM1hd7a+u3QeMPFZQ7Ic+BmmeWHvvVP4Yj yu1t6vAut7mKkaDeKbT3yiGVUgAEUaWMXqECAwEAAQJAIHCz8h37N4ScZHThYJgt oIYHKpZsg/oIyRaKw54GKxZq5f7YivcWoZ8j7IQ65lHVH3gmaqKOvqdAVVt5imKZ KQIhAPPsr9i3FxU+Mac0pvQKhFVJUzAFfKiG3ulVUdHgAaw/AiEA3ozHKzfZWKxH gs8v8ZQ/FnfI7DwYYhJC0YsXb6NSvR8CIHymwLo73mTxsogjBQqDcVrwLL3GoAyz V6jf+/8HvXMbAiEAj1b3FVQEboOQD6WoyJ1mQO9n/xf50HjYhqRitOnp6ZsCIQDS AvkvYKc6LG8IANmVv93g1dyKZvU/OQkAZepqHZB2MQ== -----END RSA PRIVATE KEY----- m2crypto-0.46.2/demo/rsa.priv0.pem000066400000000000000000000011541506746742300166540ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-CBC,244DDAFE6F991A53 h1/NnMxq2ku9UkBG2tfM7hCFWmOvwMbVQBYgS4jLm3ENvWRgkm7pCqjCug99Uo5o r+NhzqyvSBH+eX3ojVAfpMxkL0TIjMrogRq2TD75v6hTGu/fd4Yrw7vZaKRbLzoh rG6m7zdbiQwNyh0bTbbo3WmQ07FXkXrDqihLaZTJOvHNLS1lKwRjIS0MqtyhOfPj NNwuNEs6AFz4k6UxNMRXhyU2SXn5SOgZZB12SCIsYA034rwKFKqNRoneaLSlhtut 1z/BlJaLiZDHJmtxtgz5h3Ss9fQ9J0pLnybx+EM70TPM3hz47/8cQiEYIVg7+QFW jNYaGIA6IOcyB7fwX5e/zFy5yXAsmuIw/iP0sYa29hdUG++T8Mp2knrBBwQO77OS WRz219dMQQRyyn2jpN5x23AZyz4gHj4YKMm3KO06Y2k= -----END RSA PRIVATE KEY----- This is the same key as rsa.priv.pem. Passphrase is 'qwerty'. m2crypto-0.46.2/demo/rsa.pub.pem000066400000000000000000000002661506746742300164050ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANQNY7RD9BarYRsmMazM1hd7a+u3QeMP FZQ7Ic+BmmeWHvvVP4Yjyu1t6vAut7mKkaDeKbT3yiGVUgAEUaWMXqECAwEAAQ== -----END PUBLIC KEY----- m2crypto-0.46.2/demo/rsa1024pvtkey.pem000066400000000000000000000015671506746742300173770ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQDE3rnXDvA4lrIUj7ZXQM2ODLw0NnjKXh7+O3GPttvoFoacK1qk BRO+aO4hPhvQumySTz+N2RkIsT9PTx6yfyWWwYC1zbbv2cxlCBisGAvrUSL6IfHX ND2/vVN+QmOd/b4hfC/ekRo2ylrnX0pOXv/JxiblV9WumiZsBEuhUvxCnQIDAQAB AoGBALdaLEDkM8ywZQiLVCptO0RaDgqe1N68zCbBXCGaD7NXD2VxZ0itRdcnyOiC /MroZWfakPleQVd8JNeLe66IhosAJd7Zbjf/npYnD4zD1x54zRrSuBquXhz+ev7U tZONPxU5QCf/aow4z1s/M+knLyy+0lAUlWwTgOrd5VCQ8suBAkEA5/v48HZW8pQC 2zxQUFfsnRu6DxJuQ1UvWp51FNUYZM2LjpwgGyCNkCw+nuxPgM1HnOTAMVXkZdwL 7XG0Gm5ZoQJBANlAKKUc7ItOfN5TeD154Qz9FLtZUgWnWfawvEqiHJ0cPrzyv9v6 wu19QxP6ORZBWyr8c20/p2fNrk+7YOZAH30CQQDZ9p1HEWlQMlEcu+aaFoJyewKt 9pszGG6NriRDlpR84cMmEvr3gfaAZ5HOsCli031dpHAP6qvWKJHsXtDhpJ0BAkBs fANP4A+myLzF8Hx8hl4BNGej3kh9FkJwU3TS9/y935rck4OG/8NTAFf8o9jZ6izy XDnvdffMeALxQapzj9WpAkBQt2yjU3V3bKkNl0XwTk/VK8WGEWTBF1byZv/6VZOb q/vOPSexrQmu+T8+lljraJISfIpMSWZhR4oarmnGVRPX -----END RSA PRIVATE KEY----- m2crypto-0.46.2/demo/rsa_bench.py000066400000000000000000000132401506746742300166220ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """ RSA signing demo and benchmark. Usage: python -O rsa_bench.py [option option option ...] where options may include: makenewkey showdigest showprofile md5 sha1 sha256 sha512 Larry Bugbee November 2006 Some portions are 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 RSA, EVP, Rand from M2Crypto.EVP import MessageDigest import sys, base64 # -------------------------------------------------------------- # program parameters makenewkey = 0 # 1 = make/save new key, 0 = use existing showpubkey = 0 # 1 = show the public key value showdigest = 0 # 1 = show the digest value showprofile = 0 # 1 = use the python profiler hashalgs = ["md5", "ripemd160", "sha1", "sha224", "sha256", "sha384", "sha512"] # default hashing algorithm hashalg = "sha1" # default key parameters keylen = 1024 exponent = 65537 """ There is some temptation to use an RSA exponent of 3 because 1) it is easy to remember and 2) it minimizes the effort of signature verification. Unfortunately there a couple of attacks based on the use of 3. From a draft RFC (Easklake, Dec 2000): A public exponent of 3 minimizes the effort needed to verify a signature. Use of 3 as the public exponent is weak for confidentiality uses since, if the same data can be collected encrypted under three different keys with an exponent of 3 then, using the Chinese Remainder Theorem [NETSEC], the original plain text can be easily recovered. This applies to confidentiality so it is not of major concern here. The second attack is a protocol implementation weakness and can be patched, but has the patch been applied? ...correctly? It is arguably better to get into the habit of using a stronger exponent and avoiding these and possible future attacks based on 3. I suggest getting in the habit of using something stronger. Some suggest using 65537. """ # number of speed test loops N1 = N2 = 100 # -------------------------------------------------------------- # functions def test(rsa, dgst): print(" testing signing and verification...", end=" ") try: sig = rsa.sign(dgst) except Exception as e: print("\n\n *** %s *** \n" % e) sys.exit() if not rsa.verify(dgst, sig): print("not ok") else: print("ok") def test_asn1(rsa, dgst): print(" testing asn1 signing and verification...", end=" ") blob = rsa.sign_asn1(dgst) if not rsa.verify_asn1(dgst, blob): print("not ok") else: print("ok") def speed(): from time import time t1 = time() for i in range(N1): sig = rsa.sign(dgst) print(" %d signings: %8.2fs" % (N1, (time() - t1))) t1 = time() for i in range(N2): rsa.verify(dgst, sig) print(" %d verifications: %8.2fs" % (N2, (time() - t1))) def test_speed(rsa, dgst): print(" measuring speed...") if showprofile: import profile profile.run("speed()") else: speed() print() # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def main(keylen, hashalg): global rsa, dgst # this exists ONLY for speed testing Rand.load_file("randpool.dat", -1) pvtkeyfilename = "rsa%dpvtkey.pem" % (keylen) pubkeyfilename = "rsa%dpubkey.pem" % (keylen) if makenewkey: print(" making and saving a new key") rsa = RSA.gen_key(keylen, exponent) rsa.save_key(pvtkeyfilename, None) # no pswd callback rsa.save_pub_key(pubkeyfilename) else: print(" loading an existing key") rsa = RSA.load_key(pvtkeyfilename) print(" rsa key length:", len(rsa)) if not rsa.check_key(): raise "key is not initialised" # since we are testing signing and verification, let's not # be fussy about the digest. Just make one. md = EVP.MessageDigest(hashalg) md.update("can you spell subliminal channel?") dgst = md.digest() print(" hash algorithm: %s" % hashalg) if showdigest: print(" %s digest: \n%s" % (hashalg, base64.encodestring(dgst))) test(rsa, dgst) # test_asn1(rsa, dgst) test_speed(rsa, dgst) Rand.save_file("randpool.dat") # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def print_usage(): print( """ Usage: python -O %s [option option option ...] where options may include: makenewkey showdigest showprofile md5 sha1 sha256 sha512 """ % sys.argv[0] ) sys.exit() # -------------------------------------------------------------- # -------------------------------------------------------------- if __name__ == "__main__": for arg in sys.argv[1:]: if arg in hashalgs: hashalg = arg continue if arg == "makenewkey": makenewkey = 1 continue if arg == "showpubkey": showpubkey = 1 continue if arg == "showdigest": showdigest = 1 continue if arg == "showprofile": showprofile = 1 continue try: keylen = int(arg) except: print('\n *** argument "%s" not understood ***' % arg) print_usage() main(keylen, hashalg) # -------------------------------------------------------------- # -------------------------------------------------------------- # -------------------------------------------------------------- m2crypto-0.46.2/demo/rsatest.py000066400000000000000000000024471506746742300163720ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """RSA demonstration. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from M2Crypto import RSA, EVP, Rand msg = "The magic words are squeamish ossifrage." sha1 = EVP.MessageDigest("sha1") sha1.update(msg) dgst = sha1.digest() priv = RSA.load_key("rsa.priv.pem") pub = RSA.load_pub_key("rsa.pub.pem") def test_encrypt(padding): print("testing public-key encryption:", padding) padding = eval("RSA." + padding) ctxt = pub.public_encrypt(dgst, padding) ptxt = priv.private_decrypt(ctxt, padding) if ptxt != dgst: print("public_encrypt -> private_decrypt: not ok") def test_sign(padding): print("testing private-key signing:", padding) padding = eval("RSA." + padding) ctxt = priv.private_encrypt(dgst, padding) ptxt = pub.public_decrypt(ctxt, padding) if ptxt != dgst: print("private_decrypt -> public_encrypt: not ok") def test0(): print("testing misc.") print(repr(pub.e), repr(pub.n)) print(repr(priv.e), repr(priv.n)) if __name__ == "__main__": Rand.load_file("randpool.dat", -1) test_encrypt("pkcs1_padding") test_encrypt("pkcs1_oaep_padding") # test_encrypt('sslv23_padding') test_sign("pkcs1_padding") Rand.save_file("randpool.dat") m2crypto-0.46.2/demo/smime.howto/000077500000000000000000000000001506746742300165755ustar00rootroot00000000000000m2crypto-0.46.2/demo/smime.howto/README000066400000000000000000000001141506746742300174510ustar00rootroot00000000000000 01 Apr 2001 ------------- These are the example programs from the HOWTO. m2crypto-0.46.2/demo/smime.howto/decrypt.py000066400000000000000000000007001506746742300206160ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """S/MIME HOWTO demo program. Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" 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) m2crypto-0.46.2/demo/smime.howto/dv.py000066400000000000000000000020071506746742300175570ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """S/MIME HOWTO demo program. Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" 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) m2crypto-0.46.2/demo/smime.howto/encrypt.p7000066400000000000000000000012611506746742300205310ustar00rootroot00000000000000From: sender@example.dom To: recipient@example.dom 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 KoZIhvcNAQEBBQAEgYCdBULuQ/kfjgk17dMwBHdY+vXfqR/B+vJnF0gXhK6gc5d4 gCkRefEyVu7lGAD2MOdD0cOLFvHdmGHFJqyJ8T+A1mmqrxMAiJImtqN586YnoTUb Cw5FaMEd20d6hpGeEVBFHkam0vQKdR1GLG1VPiFn+ytB06g7NNphsI5/uFGyLDA7 BgkqhkiG9w0BBwEwFAYIKoZIhvcNAwcECPfuW3hoPVr0gBiA4CiFG4m74CT4wHPu q1fhEkG3zjraxn4= m2crypto-0.46.2/demo/smime.howto/encrypt.py000066400000000000000000000017311506746742300206350ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """S/MIME HOWTO demo program. Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" 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") m2crypto-0.46.2/demo/smime.howto/recipient.pem000066400000000000000000000021021506746742300212550ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIC9zCCAmCgAwIBAgIBADANBgkqhkiG9w0BAQQFADBhMQswCQYDVQQGEwJTRzER MA8GA1UEChMITTJDcnlwdG8xGTAXBgNVBAMTEFMvTUlNRSBSZWNpcGllbnQxJDAi BgkqhkiG9w0BCQEWFXJlY2lwaWVudEBleGFtcGxlLmRvbTAeFw0wMTAzMzExMTQy MTVaFw0wMjAzMzExMTQyMTVaMGExCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNy eXB0bzEZMBcGA1UEAxMQUy9NSU1FIFJlY2lwaWVudDEkMCIGCSqGSIb3DQEJARYV cmVjaXBpZW50QGV4YW1wbGUuZG9tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB gQDQwLwQSshbTn/GUZXnZUQEUDc61OUd+qcPpHfi76Y7ar+2NwsalQ3bu2i7edEK IZZWMFRnrOwE9PhmJHJIzfYDswgpHWtRy0P/Oyzt5kLBjvJYuMIqu8gZtWFz0G28 Q8tGvIuPdWba+9TT3LOv4CXNF1V0k0KgAPd1Uq2FUcBa2QIDAQABo4G+MIG7MB0G A1UdDgQWBBQe7b4CDEBuMJyiscil27YBdZBr9zCBiwYDVR0jBIGDMIGAgBQe7b4C DEBuMJyiscil27YBdZBr96FlpGMwYTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0y Q3J5cHRvMRkwFwYDVQQDExBTL01JTUUgUmVjaXBpZW50MSQwIgYJKoZIhvcNAQkB FhVyZWNpcGllbnRAZXhhbXBsZS5kb22CAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG 9w0BAQQFAAOBgQAJbQXzP7AK9u2kyvl8oeZAeJQDRsip4PVMkYd64HW3Hq/9ud3g hj/laeUyfcga+c1c1yPUug5Ab+loeHhEEKsL9LqYFXzpFU1lXaID02zcqG7g3PWe r9RKsUqrn4ZbRQ+clidnIx4nYLuG6CPQ6ME/uFrYHMsmQEO/+KoJONf/cg== -----END CERTIFICATE----- m2crypto-0.46.2/demo/smime.howto/recipient_key.pem000066400000000000000000000015671506746742300221430ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDQwLwQSshbTn/GUZXnZUQEUDc61OUd+qcPpHfi76Y7ar+2Nwsa lQ3bu2i7edEKIZZWMFRnrOwE9PhmJHJIzfYDswgpHWtRy0P/Oyzt5kLBjvJYuMIq u8gZtWFz0G28Q8tGvIuPdWba+9TT3LOv4CXNF1V0k0KgAPd1Uq2FUcBa2QIDAQAB AoGAVOMrFozycH65YtHmXVRGlmJwMxJDoS8+JBRDVBsTw/Gix9wWPdcC7amF60ac BLynv6Cjkg01ZMahBBgqCQUH1rii6Kg20MJJtpqvt1X+CAZkytVsQqwutSQXHj+g TzZVDxQiuPKMyVhKTSVqutqs2EyFgSKcYuodfms5xDk2EyECQQD6vnEAl2PHBoia 5wrauujbWTM6H5oioWvJgLaUNgUhJ86/Y+ewKoGxLdYaxx99KhKxN/04i2chIHk0 c53THOt9AkEA1SD1Rdm93FUMEor+BYEQgiN/4pWnSIsgUjyqV7lPv9QegdDTbVfm WuPNev6Z+qo9mpDWbvhCZhH159q7uGfzjQJAe88dLRWThuqK+TGsAmTYJbbdvI1u JjteZZjQjk4+KijlxUsnU60pbLsdRQudWMg1gpwKxKjQu2K1dljATUWyYQJARI83 l2K1+py5J3XixS6BevukdeUiTOnEWe/98/4+szyvG59rg+8UwQQq43fnXIVLD9+r u0LNSTxZ2F26qVV3OQJBAIBG0Gv9C44UlCPiJhmMqcpzexX20erOEGu+UiCUhHAC ZdWdFaD2dlmk0O/E82LxPPivkGv5DtkNpzCl+3Vo+kI= -----END RSA PRIVATE KEY----- m2crypto-0.46.2/demo/smime.howto/se.p7000066400000000000000000000062741506746742300174650ustar00rootroot00000000000000From: sender@example.dom To: recipient@example.dom 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 KoZIhvcNAQEBBQAEgYCn4qL7Z8QlmVEMbO2zU5RUtBqw1cYPzxd/4ZF9H+djlL7f EDIYHidvTBksXwcBXSTxsKsSusGF95NtwaZf4D3eiR1ChdkeXaiWCUPAQr0Mw4+A EJa9eGBuLH+LXH0pDN5OhYb8hsL/EcV2OpOEjOe4aM/u3Ot5u1kK1582oikhCDCC B6UGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQImrxQEPwEHHeAggeACeVVKqKjySva zos9ahumXC7bMIcfesxQF0L2CcR4wQtnwuzESXNAnQabtlN6cXKLNFGWmilztaEZ zHFEEDqtqEeP5BmEkjnNFakhr49yrK/SZpVYYScsUHNcMDOwXMPKKxkk3qOKUlqQ m+WvvyaWwZ8kbZNkO+YY4BpOVDEQRH3HG7ngtLP3y/LSx7kcpTl0wi8On9pigZ46 4u9Odac7bNh5FVMOFiXbIXMuFJ1epy9agtX09eOK9JC9ZHnIl9IgGEL833d+l8MQ OdeKqvSTnNf0JKZs52uzUqluI4pywNIiJT1OeU3Ch2vdfvcOcTQohGhIEUb7NWEn Z02pBiZ0Tzg/T/sr8B60rPcRSSnGYAfQZPS86QgAMIEaqoHQVox+Qgigr2dynvWQ KO0ny4iJLhtRoxD7W7LxaZat6fWvbC4WXKwgis2UJnEWwe8DsoZ3XEnYid3ke2/F 2+ejHtugd6E4o05vRAO/pOVZUbc4mbZm2zoPgzwm0M9GqQcTOVy1tkpEc6mhrH6y AjbSeP/1YkZakDB9bl+TCw24lRquIUbGyNI9GM+oFYyciIYu6RfPhfoh9YU9wqS7 KcnHk3WG5AxJZ6tZAsz/i/DhtD5zxFsldKMy5OaeBjh6txmQ0aHXPYLmIEdxPSa0 BnrAeTam/1iOboXT1O2GkPiLJAJjWRAvK/QXsxJMGtSYEnwT+kkAZtU75FOyBuxI gQOHO98CGGEy5CI/e/Th+1yMqyiimqDmfVktN4KgzZXbjyv4xzpgNE6o85v7fUg1 1WoTF38GmbcIbVfBHaRwdWmSxeAsFltHb38u7pP8D24+3hC5OKsNLXxGFJhfp3HW 4A51fNAi3CaWIh9aZb+SYof8MmtZp9mjL0dKB1OZTyTXqkQ/yU3PIHE+ytM6men3 tzQefsJlnk/t/zBhxdZo+yCna/ZJe3KmrShoD4ob9prWs48ohDhG7cY4vfW0NuxX Im30y+JZe3A0Ktamq1VmpWDhW6Emo+Wk04nDTtU2AcClMoKWgcvIUp0HAgWDhrrx 6Rf1CiRZngJuCEheCMAvKT8IgcTt7vWRUpRoJrhlKR23GKEVA6T6DF9q8L4F82ul yzQ2kdec6s8bD1EQT7e0QcIqEn8RNoSa2aLxRG2JBWqv0AZflKyCjwx35mCv7AmN 17zPENkGdDgE9xcEEdEe4rkigJ8uaYauEofQsDgSHWQ2oAk91g5FLNImsRn3Z7uy qtjc9JTXOymowDXbdYebqNZTxJhXDUnrbawWqyCgohtytnVdW61wKsXV3oEp7PZc aL0ZZvVkVkUofaf/2gIGvQ9WnTfpUJ/bEAr0hDdtnmg1QPVu/v/l9eXAnbkh71GX OdFpIfvf0zVm/tn/7Vi+HfHRjupHSJBO+bIVQBt3uMLlovU48axSRXUnpIXdHYwN 3b/MabDQnzV1qvhGTRRj+o39RbDrueNSpXIleA7SzFqZO2LnaDZ/FKbca1CAL+Iy KsByJUz7cReE4gU8N3SKKv7ivaibmFG63cvwA1GMUsWZgIYD/xy2nCB4jPCodiFB wWUgAblxMcaidKox6Z1zK9oZA62QIX4XGl+0mE/xwxmt2fE5lSBhY8q7N7MvS/Nv RDLEgULBMRvcjgIwL4MZZYkUl7oAqQ2aHL45j7vp7U9vIK2j8bcp9v5K3jeccENJ qYn/35awflQ66lrrSUWH3evs5IO0FhKSn9c1GGTaZDA5TABzJKySmvphyAh1m24W ylzgXQkp/Zi2oWajZ50txiIBgB14dWhuCS4vcwkWjyKur/yGpkY5DILSHZyguqDk cwOgKRrC5myL7Zr0/5CwN6sBofOGb2Qhcx+4Cg6DnPwyMXKVTKYnXPvcTj2KvVW+ qzTIhur0rwC13lK1+sMs/+Esel99fohCTz7+tiebqkPaFcnx8hUgMrllYfGCMXQ/ hiY+1BVEyDWHWOjj5lxPwzNtPqbVz3uA//Rut/BozOpD/hEjCMVRbadSFZTM+x6+ nr39DHGZsOn3XSEZSU2C93v77Ls/vdJi6IdJTwCD/yoEK1OY60ciBvCpJ/lLVSQl PAdozKEAjqP+fX95MeAENtysXTsqbWawWeS7H/zXmwpWn3LnSJ48pymvwV6nJrYL YXHaiuMGIZim9jOT04AyK5LPZ2E9omwVFaHgi10iRigc9y5MixHvN9P5WQ9nP+/c kflFQXuph3RqBEWfG8vPFKFvqVQTN0lxUXoOXkKhZ7/Doe3orbfRw/xZUyKnfrzs O7MU7PVAubVNUXjKHs2UCYtVMUH0tSuDMkuWUd6d6cmkPht86KvopoXha6zRw1pu SE/nGq/o6bproWMPRfoCCN+xow9jeipTD7xkYbiw1+g/9hYaqUYm7QUbuYOrBtLe RAlm69yornWrh7+n3GXUSCFQz3nj6sE4JjXciQzhUfEFrCn+qDrgaviFKe0yVYbQ LRr3qtSM0gTVWn2XnOlnNuLdvx2UWV7KNNPrnRIoK3KvnfOJTl/RzkT1g+HaEvC3 MFNlSJNXN6Gavdr8pAdtnVGivdnM1iw0yFKuuzoF1F+cuN8rGMmp m2crypto-0.46.2/demo/smime.howto/se.py000066400000000000000000000023411506746742300175560ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """S/MIME HOWTO demo program. Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" 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") m2crypto-0.46.2/demo/smime.howto/sendsmime.py000066400000000000000000000050221506746742300211320ustar00rootroot00000000000000#!/usr/bin/env python """S/MIME sender. Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" from M2Crypto import BIO, Rand, 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("rc2_40_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() # XXX Cleanup the stack and store. msg = """ 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). S/MIME is built on the PKCS #7 standard. [PKCS7] S/MIME is implemented in Netscape Messenger and Microsoft Outlook. """ if __name__ == "__main__": Rand.load_file("../randpool.dat", -1) sendsmime( from_addr="ngps@post1.com", to_addrs=["popuser@nova.dyndns.org"], subject="S/MIME testing", msg=msg, # from_key = 'signer.pem', from_key=None, # to_certs = None) to_certs=["recipient.pem"], ) Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/smime.howto/sign.p7000066400000000000000000000043571506746742300200160ustar00rootroot00000000000000From: 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="----2221986D060512556B8AC18AAA106F39" This is an S/MIME signed message ------2221986D060512556B8AC18AAA106F39 a sign of our times ------2221986D060512556B8AC18AAA106F39 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 BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTAxMDMzMTE0NTgyMVowIwYJKoZI hvcNAQkEMRYEFOoeRUd8ExIYXfQq8BTFuKWrSP3iMFIGCSqGSIb3DQEJDzFFMEMw CgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsO AwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIGAKMjEdSteeZg9ji1C Y2r6zuxDVVftpSLy9ZhYOblGYY2b3PhzI0XytdUoLdb+GlPImqE/F5FJCPvTAovq uLElbx/FuijA2ly7PQF2ekyFJ0EhvNWT1gcLhi1m0W+Hk/jgCQx7YRojT53Pa9fj zuHk7ZkSKe5rZlOJvPJtYREnvD8= ------2221986D060512556B8AC18AAA106F39-- m2crypto-0.46.2/demo/smime.howto/sign.py000066400000000000000000000015651506746742300201160ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """S/MIME HOWTO demo program. Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" 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) # 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") m2crypto-0.46.2/demo/smime.howto/signer.pem000066400000000000000000000020461506746742300205710ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIC4zCCAkygAwIBAgIBADANBgkqhkiG9w0BAQQFADBbMQswCQYDVQQGEwJTRzER MA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIxITAfBgkq hkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbTAeFw0wMTAzMzExMTQwMzNaFw0w MjAzMzExMTQwMzNaMFsxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEW MBQGA1UEAxMNUy9NSU1FIFNlbmRlcjEhMB8GCSqGSIb3DQEJARYSc2VuZGVyQGV4 YW1wbGUuZG9tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlzlOPUIdNI7Fr WrarQViLAxZgem0mkly+1mZTCuBTmwesDw6cIzRwNcSPQo9/dx82Md98HwdYzMjh QSA2YVdA2zGgZn6KrDEuU2PL0yHt4Vb8GOrmE1dui5KVDStYFGSjFXrjL63qVB6F vfZZ9hdBsoXEUlJfNLE7HdHxiFI93QIDAQABo4G2MIGzMB0GA1UdDgQWBBRc7KiU vW3iNoHBkVEzsxLycEvNSjCBgwYDVR0jBHwweoAUXOyolL1t4jaBwZFRM7MS8nBL zUqhX6RdMFsxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEWMBQGA1UE AxMNUy9NSU1FIFNlbmRlcjEhMB8GCSqGSIb3DQEJARYSc2VuZGVyQGV4YW1wbGUu ZG9tggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAejcOsIdHzp9J NUC9+Jd1KzBaoq0ISFQdF0JMsUaXiEOTYbJnFoW6pnCJRHP8fucyJzKYjbCTPwf/ DIcWDwbcEh6FRGmPa/9lZdh6i9uBLsRkAtVWQOPiE2X8ggdZ3oa2/VQ4N/tRFvG2 XeFD395NYhOt59PWF64+dqvxzPJ2w4s= -----END CERTIFICATE----- m2crypto-0.46.2/demo/smime.howto/signer_key.pem000066400000000000000000000015731506746742300214450ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQDlzlOPUIdNI7FrWrarQViLAxZgem0mkly+1mZTCuBTmwesDw6c IzRwNcSPQo9/dx82Md98HwdYzMjhQSA2YVdA2zGgZn6KrDEuU2PL0yHt4Vb8GOrm E1dui5KVDStYFGSjFXrjL63qVB6FvfZZ9hdBsoXEUlJfNLE7HdHxiFI93QIDAQAB AoGBALqc4OgZSbYPjQyTfpD1IJTKLgqsgCR5aE0kR7WZuG7MDt/e3ktWn0ebsgFv 2J12u2bD+yqM++dVbK7WtvTR+QpMhb/0XMhXNsvmn5gOLdKlJjS0RXDDs2DzIS6p JNzAmn5zqTVteZAMDLk7ygkO++iGzwRz713ZgxRaKr5YWiLVAkEA+3ev1TTXNEOk wQ9fbukMrfUXesqwgrx9VZ1z1X5we42RIIMTYI1edpcujXYvgS3/jdzAWDS1Nqta 9QB3uy91ywJBAOnysIIQhHn+4zvaOA5vh85WczPhN9C+yRmV70eyL9h+aThUFS4c kg2jQOLp8MaxAkmk4xRbZBgehjmDr45b5fcCQQDpIGNlYFBmhpN129+YffugRgjX cJNFEKONPKRHd6mmEW9K2dmb+FNr0+p3gOq3csJpbQ7wdyTMov13B1D4ux4TAkAR URB1oCleKlrBjGaH0wOXZ1jBp1MNVYHnLez3Pp5CBSFetQKYVi8NaV8dLLnQyztj Hhxc3mLrUh8XVMMC45SDAkEAxRCKmkneLceIdwixLIUF0zr0OzJtgyhxMxvHu3ET gJcZqNN0y3EgPwcNihpBw7rjpp5e5sjlRNVqLqn8a5/Fog== -----END RSA PRIVATE KEY----- m2crypto-0.46.2/demo/smime.howto/verify.py000066400000000000000000000012621506746742300204540ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """S/MIME HOWTO demo program. Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" 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()) m2crypto-0.46.2/demo/smime/000077500000000000000000000000001506746742300154365ustar00rootroot00000000000000m2crypto-0.46.2/demo/smime/README000066400000000000000000000031531506746742300163200ustar00rootroot00000000000000 29 Nov 2000 ------------- - test.py works. - makesmime.py is sendsmime.py modified to not send SMTP, because I do not now have an SMTP server handy. - sendsmime.py should still work, because makesmime.py does. - unsmime.py doesn't work, possibly because the certificates used to generate the tested PKCS7 objects are no longer available. 20 Nov 2000 ------------- This directory contains various programs and supporting files demonstrating M2Crypto's S/MIME functionality. - test.py exercises the various S/MIME functionality. - sendsmime.py (optionally) signs and/or encrypts a message, then sends the output via SMTP. - makesmime.py is exactly like sendsmime.py, except it writes its output to sys.stdout. - unsmime.py decrypts and verifies an S/MIME SignedAndEnveloped message. It handles the S/MIME output of Netscape Messenger successfully. - ca.pem is M2Crypto's test CA certificate. - client.pem and client2.pem contain user certificates and their corresponding private keys. - clear.p7 is a clear-signed S/MIME message. - opaque.p7 is a signed S/MIME message. - ns.p7 is a clear-signed S/MIME message produced by Messenger. - ns.se.p7 is a signed-then-encrypted S/MIME message produced by Messenger. - m2.se.p7 is a signed-then-encrypted S/MIME message produced by sendsmime.py. I tested with export and strong versions of Netscape Communicator 4.7x. I have also done some interoperability testing with Sampo Kellomaki's smime tool. I am interested in interoperability testing with Outlook and other S/MIME tools. Write me if you want to collaborate. m2crypto-0.46.2/demo/smime/ca.pem000066400000000000000000000023041506746742300165230ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDWTCCAsKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAxMTIxNTA1NTU0NloXDTA0MTIxNDA1NTU0 NlowgYAxCzAJBgNVBAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxML TTJDcnlwdG8gQ0ExJDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3Rl cjEiMCAGCSqGSIb3DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbTCBnzANBgkqhkiG 9w0BAQEFAAOBjQAwgYkCgYEAx8soJbS719LHK62VVVIQeC3oW0HvFArwPnA0LuEK q+LaqMOJg1rS7hvFdX03diV+XJw7cC0iECZYJNG4ii1xbY6KRmufkInaAwm54E3N e+YYVocaqUkcN6xVf6fwnLfPXbpFS/K2Umg11ObKMmi80JmiIdjcjRRCQZC7g1hf q+kCAwEAAaOB4DCB3TAdBgNVHQ4EFgQU6/qcBzEtQphfXLhiOHbt2KqBwMIwga0G A1UdIwSBpTCBooAU6/qcBzEtQphfXLhiOHbt2KqBwMKhgYakgYMwgYAxCzAJBgNV BAYTAlNHMREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0Ex JDAiBgNVBAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEiMCAGCSqGSIb3 DQEJARYTbmdwc0BuZXRtZW1ldGljLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqG SIb3DQEBBAUAA4GBAD+I14GuS5vJmyv1k7mUMbAicsWRHZ+zrGOq9L/L2LsA+lKQ dAzEZE2+Zv8LBPJVltbJJhcFNJS/ZMAjEm4xlJuCpvXVMxd/M5AM29aqekWlIK7J vsdDL8IuzpRkMniUiNKPhmB6IPIOslvUKx6QofcE0wDh6pg4VvIbCjkpZ7gf -----END CERTIFICATE----- m2crypto-0.46.2/demo/smime/clear.p7000066400000000000000000000067211506746742300170020ustar00rootroot00000000000000To: ngps@post1.com From: ngps@post1.com Subject: testing MIME-Version: 1.0 Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg=sha1; boundary="----F0DD27AD8CDFF9AB55B87EE3A626E6D7" This is an S/MIME signed message ------F0DD27AD8CDFF9AB55B87EE3A626E6D7 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). S/MIME is built on the PKCS #7 standard. [PKCS7] S/MIME is implemented in Netscape Messenger and Microsoft Outlook. ------F0DD27AD8CDFF9AB55B87EE3A626E6D7 Content-Type: application/x-pkcs7-signature; name="smime.p7s" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="smime.p7s" MIIHHAYJKoZIhvcNAQcCoIIHDTCCBwkCAQExCzAJBgUrDgMCGgUAMIICQwYJKoZI hvcNAQcBoIICNASCAjANClMvTUlNRSAtIFNlY3VyZSBNdWx0aXB1cnBvc2UgSW50 ZXJuZXQgTWFpbCBFeHRlbnNpb25zIFtSRkMgMjMxMSwgUkZDIDIzMTJdIC0gDQpw cm92aWRlcyBhIGNvbnNpc3RlbnQgd2F5IHRvIHNlbmQgYW5kIHJlY2VpdmUgc2Vj dXJlIE1JTUUgZGF0YS4gQmFzZWQgb24gdGhlDQpwb3B1bGFyIEludGVybmV0IE1J TUUgc3RhbmRhcmQsIFMvTUlNRSBwcm92aWRlcyB0aGUgZm9sbG93aW5nIGNyeXB0 b2dyYXBoaWMNCnNlY3VyaXR5IHNlcnZpY2VzIGZvciBlbGVjdHJvbmljIG1lc3Nh Z2luZyBhcHBsaWNhdGlvbnMgLSBhdXRoZW50aWNhdGlvbiwNCm1lc3NhZ2UgaW50 ZWdyaXR5IGFuZCBub24tcmVwdWRpYXRpb24gb2Ygb3JpZ2luICh1c2luZyBkaWdp dGFsIHNpZ25hdHVyZXMpDQphbmQgcHJpdmFjeSBhbmQgZGF0YSBzZWN1cml0eSAo dXNpbmcgZW5jcnlwdGlvbikuDQoNClMvTUlNRSBpcyBidWlsdCBvbiB0aGUgUEtD UyAjNyBzdGFuZGFyZC4gW1BLQ1M3XQ0KDQpTL01JTUUgaXMgaW1wbGVtZW50ZWQg aW4gTmV0c2NhcGUgTWVzc2VuZ2VyIGFuZCBNaWNyb3NvZnQgT3V0bG9vay4NCqCC AxAwggMMMIICdaADAgECAgECMA0GCSqGSIb3DQEBBAUAMHsxCzAJBgNVBAYTAlNH MREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0ExJDAiBgNV BAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEdMBsGCSqGSIb3DQEJARYO bmdwc0Bwb3N0MS5jb20wHhcNMDAwOTEwMDk1ODIwWhcNMDIwOTEwMDk1ODIwWjBZ MQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xGDAWBgNVBAMTD00yQ3J5 cHRvIENsaWVudDEdMBsGCSqGSIb3DQEJARYObmdwc0Bwb3N0MS5jb20wXDANBgkq hkiG9w0BAQEFAANLADBIAkEAoz3zUF0dmxSU+1fso+eTdmjDY71gWNeXWX28qsBJ 0UFmq4JCtw7Gv4fJ0TZgQHVIrXgKrUvzsquu8eiVjuP/NwIDAQABo4IBBDCCAQAw CQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy dGlmaWNhdGUwHQYDVR0OBBYEFMcQhEeJ1x9d+8Rzag9yjCiutYKOMIGlBgNVHSME gZ0wgZqAFPuHI2nrnDqTFeXFvylRT/7tKDgBoX+kfTB7MQswCQYDVQQGEwJTRzER MA8GA1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQD ExtNMkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5n cHNAcG9zdDEuY29tggEAMA0GCSqGSIb3DQEBBAUAA4GBAKy2cWa2BF6cbBPE4ici //wOqkLDbsI3YZyUSj7ZPnefghx9EwRJfLB3/sXEf78OHL7yV6IMrvEVEAJCYs+3 w/lspCMJC0hOomxnt0vjyCCd0JeaEwihQGbOo9V0reXzrUy8yNkwo1w8mMSbIvqh +D5uTB0jKL/ml1EVLw3NJf68MYIBmjCCAZYCAQEwgYAwezELMAkGA1UEBhMCU0cx ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMR0wGwYJKoZIhvcNAQkBFg5u Z3BzQHBvc3QxLmNvbQIBAjAJBgUrDgMCGgUAoIGxMBgGCSqGSIb3DQEJAzELBgkq hkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTAyMTIwODE3NTIyMVowIwYJKoZIhvcN AQkEMRYEFI/KcwJXhIg0bRzYLfAtDhxRMzghMFIGCSqGSIb3DQEJDzFFMEMwCgYI KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABEBrhZ8JVqGZ+S7dh+xKDwbF yRXiOQWEa2uxD1O5fD02VfGEzDSrV1sPdQ8AcM3o+ny5AyC11E4Fns2cIkXwZEwz ------F0DD27AD8CDFF9AB55B87EE3A626E6D7-- m2crypto-0.46.2/demo/smime/client.p12000066400000000000000000000031041506746742300172360ustar00rootroot000000000000000@0 *H 00 *H 00 *H 0 *H  0zyD06zxu1lK[fSoeEm;E_ R j+%W_ְZXtLo?󭲾nF2 U竜~5= w׍^MBnWVYǝnS|ƣ bV(hA#I'Mc@BF0pdg\ݟ6ƶmPO iR36(gN{1?̒ዟ tD?u*>M@e~'JL_b\K`҅G5mAa~5f+ÆaMӒqrhhuv.#aHwM= kd3êRvC_o·ՊTTbP)TcO } #Ad0(;[e>Yh ,Nݾ^!@Ơ%p)V4,]6bz&叜j%1.9 WBuЎvCҫbf{BS-.\ՓEmo]}5[yyP%%:V_<`)f6 Eǫ9S0nY)_6I!% X-Mailer: Mozilla 4.5 [en] (WinNT; I) X-Accept-Language: en MIME-Version: 1.0 To: ngps@post1.com Subject: S/MIME signing Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg=sha1; boundary="------------msD996346BF03A805B450DC20D" This is a cryptographically signed message in MIME format. --------------msD996346BF03A805B450DC20D Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit smime -vs- pgp war over? --------------msD996346BF03A805B450DC20D Content-Type: application/x-pkcs7-signature; name="smime.p7s" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="smime.p7s" Content-Description: S/MIME Cryptographic Signature MIIF8gYJKoZIhvcNAQcCoIIF4zCCBd8CAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCC A9cwggPTMIIDPKADAgECAgEDMA0GCSqGSIb3DQEBBAUAMIG3MQswCQYDVQQGEwJTRzEvMC0G A1UEChMmRmFzdCBTZWN1cmUgQ2hlYXAgQ2VydGlmaWNhdGVzIFB0ZSBMdGQxMjAwBgNVBAsT KUZhc3QgU2VjdXJlIENoZWFwIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtG YXN0IFNlY3VyZSBDaGVhcCBLZXlNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5ncHNAcG9zdDEu Y29tMB4XDTk5MDkxNzA1NTAzOFoXDTAwMDkxNjA1NTAzOFowYDELMAkGA1UEBhMCU0cxGDAW BgNVBAoTD00yQ3J5cHRvIENsaWVudDEYMBYGA1UEAxMPTTJDcnlwdG8gQ2xpZW50MR0wGwYJ KoZIhvcNAQkBFg5uZ3BzQHBvc3QxLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA vp8eCa+KpzNCv0MWyicUImP+WHxlrxm5EummI1Qe77U4w0k8IQuue7QIURWKDjdZI97izzeQ SozHvgSsjCvuJlqifMoV0v7U4iUQoZkrXO3hzwM5VNr875M95SYeBjqWDUc0v3R6tka3xhg3 dMoEL3QR6gsiardPEwygdL7/FN0CAwEAAaOCAUMwggE/MAkGA1UdEwQCMAAwLAYJYIZIAYb4 QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTEHU/WosFL yRo8NT9ViQ8APbKBXTCB5AYDVR0jBIHcMIHZgBQOTokwY/jsgXmHJoyQ5DmTVN0c8KGBvaSB ujCBtzELMAkGA1UEBhMCU0cxLzAtBgNVBAoTJkZhc3QgU2VjdXJlIENoZWFwIENlcnRpZmlj YXRlcyBQdGUgTHRkMTIwMAYDVQQLEylGYXN0IFNlY3VyZSBDaGVhcCBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eTEkMCIGA1UEAxMbRmFzdCBTZWN1cmUgQ2hlYXAgS2V5TWFzdGVyMR0wGwYJ KoZIhvcNAQkBFg5uZ3BzQHBvc3QxLmNvbYIBADANBgkqhkiG9w0BAQQFAAOBgQBN4w1l4IXm DJke8XVyo3SFlre1nL/bjDB+hpYCgTQnceHAmSi6L8FljGs2KYGFePWLSCsOxA99q8lVtl7a sdoOtYkTluccWGqnWloyusOzlO2xgpoQxZ2iue3PT4Y4u8czMTs2AyanZyd6NdQoaYGfI2g0 tpgiDhSqcX8r/JYYVzGCAeMwggHfAgEBMIG9MIG3MQswCQYDVQQGEwJTRzEvMC0GA1UEChMm RmFzdCBTZWN1cmUgQ2hlYXAgQ2VydGlmaWNhdGVzIFB0ZSBMdGQxMjAwBgNVBAsTKUZhc3Qg U2VjdXJlIENoZWFwIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtGYXN0IFNl Y3VyZSBDaGVhcCBLZXlNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5ncHNAcG9zdDEuY29tAgED MAkGBSsOAwIaBQCgfTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEP Fw0wMDAzMzEwNTExNTJaMB4GCSqGSIb3DQEJDzERMA8wDQYIKoZIhvcNAwICASgwIwYJKoZI hvcNAQkEMRYEFDIu42hsp6w5K/x7ejaVgiqgPYk4MA0GCSqGSIb3DQEBAQUABIGAkipjxn6+ NhIyRPGgrqY9zpDC8AGdt7sGFMKfxhJ+UoSb+lBH0imHSBhA/BnlfysyyDXCpit1Gxy/W/jn vHpI0lMLvvcKOtSQp9HUPAtawdeF6Zau8SovSBroUnxxY7DILJoKnaHheHF7G2MbYusyZCmi r3xZ4P0Ps3fhNEAmrH0= --------------msD996346BF03A805B450DC20D-- m2crypto-0.46.2/demo/smime/ns.se.p7000066400000000000000000000120331506746742300167330ustar00rootroot00000000000000MIME-Version: 1.0 Content-Type: application/x-pkcs7-mime; name="smime.p7m" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="smime.p7m" Content-Description: S/MIME Encrypted Message MIAGCSqGSIb3DQEHA6CAMIACAQAxggKyMIIBVQIBADCBvTCBtzELMAkGA1UEBhMCU0cxLzAt BgNVBAoTJkZhc3QgU2VjdXJlIENoZWFwIENlcnRpZmljYXRlcyBQdGUgTHRkMTIwMAYDVQQL EylGYXN0IFNlY3VyZSBDaGVhcCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMb RmFzdCBTZWN1cmUgQ2hlYXAgS2V5TWFzdGVyMR0wGwYJKoZIhvcNAQkBFg5uZ3BzQHBvc3Qx LmNvbQIBAzANBgkqhkiG9w0BAQEFAASBgERIsZhX2nmvB4kOtcfqUpuWjK9njs8YixtPSS4w ugmAx3LhBMTgY1OlsbKi7etVPwEU2jSqgkwCHPeYeOQt6M9aQ66tcue7/fWjfMBfZ+tetwOb kpqlw//GyjhkJx2QBGPuw3Ye84ll1KA7x/CGxmk8g0YBHoLo9Xy1W1XHVUanMIIBVQIBADCB vTCBtzELMAkGA1UEBhMCU0cxLzAtBgNVBAoTJkZhc3QgU2VjdXJlIENoZWFwIENlcnRpZmlj YXRlcyBQdGUgTHRkMTIwMAYDVQQLEylGYXN0IFNlY3VyZSBDaGVhcCBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eTEkMCIGA1UEAxMbRmFzdCBTZWN1cmUgQ2hlYXAgS2V5TWFzdGVyMR0wGwYJ KoZIhvcNAQkBFg5uZ3BzQHBvc3QxLmNvbQIBBzANBgkqhkiG9w0BAQEFAASBgKFEdyFcaj2z 7LBp/rdEiDRNkyvjZtpEc3F1tvml2jmOuRZq/Gd0Ib4ELmAuC2qZ7AG+MNwlMeCQp1PKGjCk 3Af9hjcOX27c+qF3pSK35WOPrdQTaVLjqdNwejInEoBjGlHa83V1L/MTiD5ABOXGIZKOFS8m G0tPxoc3AhlYbHspMIAGCSqGSIb3DQEHATARBgUrDgMCBwQIvFFOv2EOARiggASBsBBa97DM xPCX8mZ2K/jjVl2LKtBP0uwG+nd48IiaoBERbJohEdzxTlIU3pj+QZ4ktmSSYo/4Os0eSCfK v2mG3d5SPxcE6HztA4FttvQ4IiByTQUU61vJhMoirV5Nvfkxk8i8xPMKMlJSruFBnIOteXQv vwVwBCIAkMhxBE9Sj+OfW5966d+LmB3yGEZa9GEW//4VbR6DNs1frEz7riUod0om5CA66bou 8kXxGTZ5fYydBDDdrsgcU7DBTlw2XayUmYS3Gp0vQvW4l/iiYEeYh+OrKkGYQGdsb5CcZr0F FfT2PRAEICA58XUUrt//zi0TzBTwDKAWoJWe/QfOXXEVQsfqCl1iBBhACmC4JLQRSulBCCpA F3E3daztLz81ycQEIDyHXxMGZFzZQCvy51fN7eRLl+yACoXKxKtVs6EKpJq9BBDDGI8CWqTZ DIMC98l4AV76BIIBAFKj+L6ZG8Sew6IpE5UVq1oS42UrmUDQRrYpZX3OHC8I9pr7mtlU/V0H mA55PmixsjcchT6wOF2wVD9G0rBCOlUfuYNTkhR/k51floP9fk9Oy69+jXxUb7r0AF1M2b13 XQpmnz6YPQPdPxgi8i34iT1oqRY1d4Nntmgl/3xbQ/9MGbgZQSDbduRiy+Zk3JPZzMSVWEVP Pt7anOrPmCKDAvlzpX9yKdyE4Ug68s2///S1JjCjGd65007oPXME3S+7WWylQXdjCe8EM/Li IE33DcRUFvbuo7q1ftxbwRKn32+Z1gkiG4j+DQ4fTO0RrhnTLUpaaOaX4N3psjSA/3Y+vKYE CAkYtbSSwRr5BAhmVVsaf0vm7QQIE77+DXI3Gt0ECIs/MQuPnwd6BAjpq83cshzQ1QQI3Soo r1XwQYIECES6t6POe3yxBAgmObWcpGTawQQI+6e28OKubqkESBlD4aGRdfOXkGSw5zN1pVK0 s37qLWOsO+jClvd4EmfB/JI/ABieNmfBHx2jweIazMA2b9wylRvYp/TMiDFkRl/thDqyj/sC 7QRIypPg5i7a745PX+HcyHhcy5lUxkpnK5pjAAHSUPTXNc/3H6PpU/8+qiPncfqNXVdoiiSa VMSmFMZI+YGDyf4twVuGZbdR5JV2BFCbQNJeSkEhEnZiMKshmNWXbjs4DzYlTO0Pq5D+9RYJ 1iy/kahcms+2nDNlrVf6jH/lCTpPCM/OJWrjaTdpiFzp/eEY39qbWk5AcIFYQ7xIcARIHVPX uhyuO+5BmO0MdMMOL/KlhRtosKHHRG7PH9huyWYFloA4aeoiOxeXkDJk3y0NkG+nJjdM/gWT 1J2HJi8opt0F0bn8t7MsBEgt2VgTZmkHT/yaJDInQEqrpe9PJ412M+2/kXAwt4VfYrEC3ocQ WQuNEpFc1kb6ZGJSYz0TvnW8DbP/GoZqQpF17p1vs1T0QhIESC1qr8SbwXjHjOdAh94Lp5jG b8kAl20P0hqqL+5qq661JzAdGotFN7sMOe07Xn3eaYEVe4htVHlIfYMPH2B0CYyHu9LH2ueG gwRQ7Dv1hygub3ioK/s9CkgAi83qUENz5RWYMtIiP7tbv34zq6DKwv0ioBY4MEKfR4cCuGzS 6I67vTvCgXPVxW9qHtoTTDfufUR6yOOa/gvuZt4ESN3fo5Kgpm+74AMeOVR0RZ1lZ+75E9KV wmiBGm5ORHGSmyt3MQMW+5UEloz8mxK39O6RtKBL7iKH3d0clJn63KXvUsf2l7/8swRIIVzc 1jGzpwOsUseKHaeLQuknjTuXAlyCTQYa3C0gEcEBElJY/TMevV+ZrlBB/nCwyaYbmH+WxxfQ +xF79+eIZ1+L5zGAlSNUBEhO1Gy1T77JUa+s4UUqGP+BNNsGDuR4YXWfCIA2vBfCFZVggkaD v1+uX2Rgim39wzMCLkXQ8ZXLWdWo7/XcllOrxJSH84uPat8EULZTtkbY1oW90JzGEJKbOkEA YaoQ7I0dKXnkLsY3Y54p1WW7fPQ4JLLhld2LpmZbYOntRJmn8LZWGWv9J3uYlAk9ujAfF10f 7/qV2zDB//oKBEih8QUPicP+mSdpvRlws5RfiKmcf9W7btoNALqqA2COEOHjjJHdX9b3EVlk vftz5n2AbaS7fenhIl1/rbhmBfub3eHwmInRoUEESHcpUKHCEe3dtGe6vB2VXR4U/MvKScZV RpHv6KGj0pFZwNasoZ9W5RB0dwAbhuD+xiimlv/m9XwhIQihgTUmarVdEbYcbl1aHgRIFMEp bOJ4D49qYR9DXZprlST9nZTgU/R1KTcZe2LsXBNa9xxlO9NYvZCSQSuRndIIwbAXjgezK1d0 fk+JSIyC8kaQzWBwDGdXBFDA3tUZzKed3JM+R/a8319iAemyyYgvk/izKKXncpOfCdBtVgHc cOC7LPs1BGxqGCyOzgD2KMQSclRZJo+siuRvJ2wlKCPjd3DHMk0IJ6EYWgRI3XuDbhKfLzEQ h9G5n3wQr8qizabBZ+xZEmJk7AUxA7ykEdSuLlV7qP/ujj9sZ9e/AaHG+mfjGRI01OPquZxW Pwt9nRpg1KqCBEjFQqB+hbkfT218E5+mFX/aotUq+tEoZ1Tg3Lq5WENZVwMNR0eFR69vN+gL SZU3nnLPEchS3pasz7ZBohL+kEBad4fZfKNWUa4ESO9adCvusxTvjlvf8Gu/lXU17gZuAHsj bMwSWyQeZKObCp7kOtK1nQCtLHkWHEpmx16eQWG57+makKYpjD4BSXFXGEwMf3Pw9AQQd6Po 6JLMr7k5LjkOcyCe/gQIJ2ORlLJDWKMECHz5jFYLkHrLBAhPDugA9fP+MgQIQq/w/QD4YBIE CGeYC0G4o7ElBAj3O1FpJvdU+wQIiOZHO6By7rAECN9TZKOJa8YbBDD/7QgWqJSNhck7fNEY tHmopW9OWfXfXUInzaQFBtLauNRj0C2OW/zB5dgsC3+9/jYECG3bevzH5HiDBBBHiuTo8yYJ 1FFJ/y4nIIXaBDC92swMrVUYZUpoNUjf02DsBiVP53Fon+CnKnEQ8gBCncIkb8DBnlZYeZd2 XISBWmEECNOMqXZKxL2vBBDDg2nHASKLEobcHqmPoIQFBBhcrb6prkWNKColNlf5ss49ocnK 68UgsNEECNJJEPZOUMW1BBApQ6CzF2t+QiJTdQwoApPzBBg8ZCeSHgypK9CWcWb2iMWiFuKc KUmIuskECFr2TQ/U6cWbBAisYHDp2/w4kgQISMieG/GdQlAEEGLN6GdGVz2wf1Hx93PJ4VsE EJRdLeaU3FsCwXEICvSKZPMEEIcEdqQkAhmsxfNoKA90QlUECDdUY0tvC48sBBBNOevphvxS 0dwE2Lzf6gLGBAjoSuhhSYuZBAQIRKWk1TxshoAECFUuzdHGuR3zBBjlvJQjSDrEPqg7unh2 ZaNy11cUKB07vPMECIbZbuiAcb81BBCyb6N/Aymqo24VwyE9/lTDBCCR0Sn7D8OfmpwUp0MJ zEdp+4eTPVu9W6bNj5cTwcG0VQQI9Z1/nYjZ93cECCZ7u+8p0rP8BAg6S5MaaL8mTQQIMt+W TF2XgOMEQLOZQ0FOc4oD9mBoXzN/NDmlEz0QWnZPnO/7OhVcuKPi6rtE+5RfdGDL/qxWGU6G 0qvFT0zTodnwjpzKnYAnoeMEUDPxz4djUsMXhHzpye9vc7N2/B8QUBubRaFPp/FoLv3jjwga +AawOtkkW1uLku0m6zdN7YYzXTsKlMhwDd3nZS4Vm/v11AnFChiDC2LFmLw0BCC/X36boypP pTObDByKlN6IldnnPEi4tl/6Cxr2+28LWgQohCdg9nl3s5COEnwQW+ggcvKodHHK9SdVRscS J4ykS0lWZ0ns4/g6/wQIKIXduWxdKJMAAAAAAAAAAAAA m2crypto-0.46.2/demo/smime/opaque.p7000066400000000000000000000052051506746742300172020ustar00rootroot00000000000000To: ngps@post1.com From: ngps@mpost1.com Subject: testing MIME-Version: 1.0 Content-Disposition: attachment; filename="smime.p7m" Content-Type: application/x-pkcs7-mime; name="smime.p7m" Content-Transfer-Encoding: base64 MIIHHAYJKoZIhvcNAQcCoIIHDTCCBwkCAQExCzAJBgUrDgMCGgUAMIICQwYJKoZI hvcNAQcBoIICNASCAjANClMvTUlNRSAtIFNlY3VyZSBNdWx0aXB1cnBvc2UgSW50 ZXJuZXQgTWFpbCBFeHRlbnNpb25zIFtSRkMgMjMxMSwgUkZDIDIzMTJdIC0gDQpw cm92aWRlcyBhIGNvbnNpc3RlbnQgd2F5IHRvIHNlbmQgYW5kIHJlY2VpdmUgc2Vj dXJlIE1JTUUgZGF0YS4gQmFzZWQgb24gdGhlDQpwb3B1bGFyIEludGVybmV0IE1J TUUgc3RhbmRhcmQsIFMvTUlNRSBwcm92aWRlcyB0aGUgZm9sbG93aW5nIGNyeXB0 b2dyYXBoaWMNCnNlY3VyaXR5IHNlcnZpY2VzIGZvciBlbGVjdHJvbmljIG1lc3Nh Z2luZyBhcHBsaWNhdGlvbnMgLSBhdXRoZW50aWNhdGlvbiwNCm1lc3NhZ2UgaW50 ZWdyaXR5IGFuZCBub24tcmVwdWRpYXRpb24gb2Ygb3JpZ2luICh1c2luZyBkaWdp dGFsIHNpZ25hdHVyZXMpDQphbmQgcHJpdmFjeSBhbmQgZGF0YSBzZWN1cml0eSAo dXNpbmcgZW5jcnlwdGlvbikuDQoNClMvTUlNRSBpcyBidWlsdCBvbiB0aGUgUEtD UyAjNyBzdGFuZGFyZC4gW1BLQ1M3XQ0KDQpTL01JTUUgaXMgaW1wbGVtZW50ZWQg aW4gTmV0c2NhcGUgTWVzc2VuZ2VyIGFuZCBNaWNyb3NvZnQgT3V0bG9vay4NCqCC AxAwggMMMIICdaADAgECAgECMA0GCSqGSIb3DQEBBAUAMHsxCzAJBgNVBAYTAlNH MREwDwYDVQQKEwhNMkNyeXB0bzEUMBIGA1UECxMLTTJDcnlwdG8gQ0ExJDAiBgNV BAMTG00yQ3J5cHRvIENlcnRpZmljYXRlIE1hc3RlcjEdMBsGCSqGSIb3DQEJARYO bmdwc0Bwb3N0MS5jb20wHhcNMDAwOTEwMDk1ODIwWhcNMDIwOTEwMDk1ODIwWjBZ MQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xGDAWBgNVBAMTD00yQ3J5 cHRvIENsaWVudDEdMBsGCSqGSIb3DQEJARYObmdwc0Bwb3N0MS5jb20wXDANBgkq hkiG9w0BAQEFAANLADBIAkEAoz3zUF0dmxSU+1fso+eTdmjDY71gWNeXWX28qsBJ 0UFmq4JCtw7Gv4fJ0TZgQHVIrXgKrUvzsquu8eiVjuP/NwIDAQABo4IBBDCCAQAw CQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy dGlmaWNhdGUwHQYDVR0OBBYEFMcQhEeJ1x9d+8Rzag9yjCiutYKOMIGlBgNVHSME gZ0wgZqAFPuHI2nrnDqTFeXFvylRT/7tKDgBoX+kfTB7MQswCQYDVQQGEwJTRzER MA8GA1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQD ExtNMkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5n cHNAcG9zdDEuY29tggEAMA0GCSqGSIb3DQEBBAUAA4GBAKy2cWa2BF6cbBPE4ici //wOqkLDbsI3YZyUSj7ZPnefghx9EwRJfLB3/sXEf78OHL7yV6IMrvEVEAJCYs+3 w/lspCMJC0hOomxnt0vjyCCd0JeaEwihQGbOo9V0reXzrUy8yNkwo1w8mMSbIvqh +D5uTB0jKL/ml1EVLw3NJf68MYIBmjCCAZYCAQEwgYAwezELMAkGA1UEBhMCU0cx ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMR0wGwYJKoZIhvcNAQkBFg5u Z3BzQHBvc3QxLmNvbQIBAjAJBgUrDgMCGgUAoIGxMBgGCSqGSIb3DQEJAzELBgkq hkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTAyMTIwODE3NTIyMVowIwYJKoZIhvcN AQkEMRYEFI/KcwJXhIg0bRzYLfAtDhxRMzghMFIGCSqGSIb3DQEJDzFFMEMwCgYI KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABEBrhZ8JVqGZ+S7dh+xKDwbF yRXiOQWEa2uxD1O5fD02VfGEzDSrV1sPdQ8AcM3o+ny5AyC11E4Fns2cIkXwZEwz m2crypto-0.46.2/demo/smime/sendsmime.py000066400000000000000000000050131506746742300177730ustar00rootroot00000000000000#!/usr/bin/env python """S/MIME sender. Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" from M2Crypto import BIO, Rand, 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("rc2_40_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() # XXX Cleanup the stack and store. msg = """ 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). S/MIME is built on the PKCS #7 standard. [PKCS7] S/MIME is implemented in Netscape Messenger and Microsoft Outlook. """ if __name__ == "__main__": Rand.load_file("../randpool.dat", -1) sendsmime( from_addr="ngps@post1.com", to_addrs=["jerry", "ngps@post1.com"], subject="S/MIME testing", msg=msg, from_key="client2.pem", # from_key = None, # to_certs = None) to_certs=["client.pem"], ) Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/smime/test.py000066400000000000000000000111511506746742300167660ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """S/MIME demo. Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" from M2Crypto import BIO, Rand, SMIME, X509 ptxt = """ 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). S/MIME is built on the PKCS #7 standard. [PKCS7] S/MIME is implemented in Netscape Messenger and Microsoft Outlook. """ def makebuf(): buf = BIO.MemoryBuffer(ptxt) return buf def sign(): print("test sign & save...", end=" ") buf = makebuf() s = SMIME.SMIME() s.load_key("client.pem") p7 = s.sign(buf, SMIME.PKCS7_DETACHED) out = BIO.openfile("clear.p7", "w") out.write("To: ngps@post1.com\n") out.write("From: ngps@post1.com\n") out.write("Subject: testing\n") buf = makebuf() # Recreate buf, because sign() has consumed it. s.write(out, p7, buf) out.close() buf = makebuf() p7 = s.sign(buf) out = BIO.openfile("opaque.p7", "w") out.write("To: ngps@post1.com\n") out.write("From: ngps@mpost1.com\n") out.write("Subject: testing\n") s.write(out, p7) out.close() print("ok") def verify_clear(): print("test load & verify clear...", end=" ") s = SMIME.SMIME() x509 = X509.load_cert("client.pem") sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) st = X509.X509_Store() st.load_info("ca.pem") s.set_x509_store(st) p7, data = SMIME.smime_load_pkcs7("clear.p7") v = s.verify(p7, data) if v: print("ok") else: print("not ok") def verify_opaque(): print("test load & verify opaque...", end=" ") s = SMIME.SMIME() x509 = X509.load_cert("client.pem") sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) st = X509.X509_Store() st.load_info("ca.pem") s.set_x509_store(st) p7, data = SMIME.smime_load_pkcs7("opaque.p7") v = s.verify(p7, data) if v: print("ok") else: print("not ok") def verify_netscape(): print("test load & verify netscape messager output...", end=" ") s = SMIME.SMIME() # x509 = X509.load_cert('client.pem') sk = X509.X509_Stack() # sk.push(x509) s.set_x509_stack(sk) st = X509.X509_Store() st.load_info("ca.pem") s.set_x509_store(st) p7, data = SMIME.smime_load_pkcs7("ns.p7") v = s.verify(p7, data) print("\n", v, "\n...ok") def sv(): print("test sign/verify...", end=" ") buf = makebuf() s = SMIME.SMIME() # Load a private key. s.load_key("client.pem") # Sign. p7 = s.sign(buf, SMIME.PKCS7_DETACHED) # Output the stuff. buf = makebuf() # Recreate buf, because sign() has consumed it. bio = BIO.MemoryBuffer() s.write(bio, p7, buf) # Plumbing for verification: CA's cert. st = X509.X509_Store() st.load_info("ca.pem") s.set_x509_store(st) # Plumbing for verification: Signer's cert. x509 = X509.load_cert("client.pem") sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) # Verify. p7, buf = SMIME.smime_load_pkcs7_bio(bio) v = s.verify(p7, buf, flags=SMIME.PKCS7_DETACHED) if v: print("ok") else: print("not ok") def ed(): print("test encrypt/decrypt...", end=" ") buf = makebuf() s = SMIME.SMIME() # Load target cert to encrypt to. x509 = X509.load_cert("client.pem") sk = X509.X509_Stack() sk.push(x509) s.set_x509_stack(sk) # Add a cipher. s.set_cipher(SMIME.Cipher("bf_cbc")) # Encrypt. p7 = s.encrypt(buf) # Load target's private key. s.load_key("client.pem") # Decrypt. data = s.decrypt(p7) if data: print("ok") else: print("not ok") def zope_test(): print("test zophistry...") f = open("client.pem") cert_str = f.read() key_bio = BIO.MemoryBuffer(cert_str) cert_bio = BIO.MemoryBuffer(cert_str) # XXX Kludge. s = SMIME.SMIME() s.load_key_bio(key_bio, cert_bio) # XXX unfinished... def leak_test(): # Seems ok, not leaking. while 1: ed() # sv() if __name__ == "__main__": Rand.load_file("../randpool.dat", -1) ed() sign() verify_opaque() verify_clear() # verify_netscape() sv() # zope_test() # leak_test() Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/smime/unsmime.py000066400000000000000000000024161506746742300174700ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """S/MIME demo. Copyright (c) 2000 Ng Pheng Siong. All rights reserved.""" from M2Crypto import BIO, Rand, SMIME, X509 import sys def decrypt_verify(p7file, recip_key, signer_cert, ca_cert): s = SMIME.SMIME() # Load decryption private key. s.load_key(recip_key) # Extract PKCS#7 blob from input. p7, bio = SMIME.smime_load_pkcs7_bio(p7file) # Decrypt. data = s.decrypt(p7) # Because we passed in a SignAndEnveloped blob, the output # of our decryption is a Signed blob. We now verify it. # Load the signer's cert. sk = X509.X509_Stack() s.set_x509_stack(sk) # Load the CA cert. st = X509.X509_Store() st.load_info(ca_cert) s.set_x509_store(st) # Verify. p7, bio = SMIME.smime_load_pkcs7_bio(BIO.MemoryBuffer(data)) if bio is not None: # Netscape Messenger clear-signs, when also encrypting. data = s.verify(p7, bio) else: # M2Crypto's sendsmime.py opaque-signs, when also encrypting. data = s.verify(p7) print(data) if __name__ == "__main__": Rand.load_file("../randpool.dat", -1) decrypt_verify(BIO.File(sys.stdin), "client.pem", "client2.pem", "ca.pem") Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/ssl/000077500000000000000000000000001506746742300151255ustar00rootroot00000000000000m2crypto-0.46.2/demo/ssl/README000066400000000000000000000015571506746742300160150ustar00rootroot00000000000000 29 Nov 00 ----------- This directory contains SSL clients and servers written as demos and testbeds. The oldest ones are s_server.py and s_client.py: these are modeled after the eponymous demo programs in OpenSSL. Once I got them going, I moved on to Medusa and other "real-world" servers. The pair has been in a state of neglect and quite likely no longer work with the current M2Crypto. My current testbeds are the echod-* servers and echo.py. These should always work. Note that Python on the three platforms that I test on are built --with-threads. Python 2.0's httplib introduces HTTP/1.1 functionality and an interface substantially different from Python 1.5.2's HTTP/1.0 interface. M2Crypto.httpslib provides both interfaces. The demo programs are https_cli.py and urllib_cli.py; these have been tested with Apache/1.3.14 (Unix) mod_ssl/2.7.1 OpenSSL/0.9.6. m2crypto-0.46.2/demo/ssl/c.py000066400000000000000000000030171506746742300157220ustar00rootroot00000000000000#!/usr/bin/env python """C programming in Python. Have SWIG sweat the pointers. ;-) Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from socket import * import sys from M2Crypto import SSL, m2 HOST = "127.0.0.1" PORT = 9443 req_10 = "GET / HTTP/1.0\r\n\r\n" req_11 = "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n" def c_10(): c_style(HOST, PORT, req_10) def c_11(): c_style(HOST, PORT, req_11) def c_style(HOST, PORT, req): # Set up SSL context. ctx = m2.ssl_ctx_new(m2.sslv3_method()) m2.ssl_ctx_use_cert(ctx, "client.pem") m2.ssl_ctx_use_privkey(ctx, "client.pem") # Make the socket connection. s = socket(AF_INET, SOCK_STREAM) s.connect((HOST, PORT)) # Set up the SSL connection. sbio = m2.bio_new_socket(s.fileno(), 0) ssl = m2.ssl_new(ctx) m2.ssl_set_bio(ssl, sbio, sbio) m2.ssl_connect(ssl) sslbio = m2.bio_new(m2.bio_f_ssl()) m2.bio_set_ssl(sslbio, ssl, 0) # Push a buffering BIO over the SSL BIO. iobuf = m2.bio_new(m2.bio_f_buffer()) topbio = m2.bio_push(iobuf, sslbio) # Send the request. m2.bio_write(sslbio, req) # Receive the response. while 1: data = m2.bio_gets(topbio, 4096) if not data: break sys.stdout.write(data) # Cleanup. May be missing some necessary steps. ;-| m2.bio_pop(topbio) m2.bio_free(iobuf) m2.ssl_shutdown(ssl) m2.ssl_free(ssl) m2.ssl_ctx_free(ctx) s.close() if __name__ == "__main__": c_10() c_11() m2crypto-0.46.2/demo/ssl/c_bio.py000066400000000000000000000030211506746742300165460ustar00rootroot00000000000000#!/usr/bin/env python """C programming in Python. Have SWIG sweat the pointers. ;-) Copyright (c) 1999-2000 Ng Pheng Siong. All rights reserved.""" from socket import * import sys from M2Crypto import SSL, m2 HOST = "127.0.0.1" PORT = 9443 req_10 = "GET / HTTP/1.0\r\n\r\n" req_11 = "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n" def c_10(): c_style(HOST, PORT, req_10) def c_11(): c_style(HOST, PORT, req_11) def c_style(HOST, PORT, req): # Set up SSL context. ctx = m2.ssl_ctx_new(m2.sslv3_method()) m2.ssl_ctx_use_cert(ctx, "client.pem") m2.ssl_ctx_use_privkey(ctx, "client.pem") # Make the socket connection. s = socket(AF_INET, SOCK_STREAM) s.connect((HOST, PORT)) # Set up the SSL connection. sbio = m2.bio_new_socket(s.fileno(), 0) ssl = m2.ssl_new(ctx) m2.ssl_set_bio(ssl, sbio, sbio) m2.ssl_connect(ssl) sslbio = m2.bio_new(m2.bio_f_ssl()) m2.bio_set_ssl(sslbio, ssl, 0) # Push a buffering BIO over the SSL BIO. iobuf = m2.bio_new(m2.bio_f_buffer()) topbio = m2.bio_push(iobuf, sslbio) # Send the request. m2.bio_write(sslbio, req) # Receive the response. while 1: data = m2.bio_gets(topbio, 4096) if not data: break sys.stdout.write(data) # Cleanup. May be missing some necessary steps. ;-| m2.bio_pop(topbio) m2.bio_free(iobuf) m2.ssl_shutdown(ssl) m2.ssl_free(ssl) m2.ssl_ctx_free(ctx) s.close() if __name__ == "__main__": # c_10() c_11() m2crypto-0.46.2/demo/ssl/ca.der000066400000000000000000000015111506746742300162020ustar00rootroot000000000000000E00  *H 0{1 0 USG10U M2Crypto10U  M2Crypto CA1$0"UM2Crypto Certificate Master10 *H  ngps@post1.com0 000910085835Z 030910085835Z0{1 0 USG10U M2Crypto10U  M2Crypto CA1$0"UM2Crypto Certificate Master10 *H  ngps@post1.com00  *H 0ǁL;D*N<3vO.9,IKA#C?CH/zRufJTA:= Ċ`& KhBȭ&7@s>BLVѺ#ΗJ00U#i:ſ)QO(80U#0#i:ſ)QO(8}0{1 0 USG10U M2Crypto10U  M2Crypto CA1$0"UM2Crypto Certificate Master10 *H  ngps@post1.com0 U00  *H utOYzaRS6]T{瞀ßqvÈXV[b15ziPCX Y~NA'ӯ 065a7+dJH*J, LNvг>oyq 0])\; 43YpK W!,(EirTٴG8骽:+b=0{L  /2:4JVGc q3=Q7Hv#k/N6ӤH6 S! w ͻ"!0TiN/ȫA0ǤIsIa.&Z/댗Da"?Wt'|Ic:Yɂ/!Oc*V׺۾Q[e0?TQ C@ o5Hu7n4zS҅ g/NRߥUڐ!!/3٪eP^<0ꝔSxϓٲqcta9"PI#&=v %b3Cb~'pb 0) def handle_write(self): if self._ssl_accepting: s = self.socket.accept_ssl() if s: self._ssl_accepting = 0 else: try: n = self.send(self.buffer) if n == -1: pass elif n == 0: self.handle_close() else: self.buffer = self.buffer[n:] except SSL.SSLError as what: if str(what) == "unexpected eof": self.handle_close() return else: raise def readable(self): return 1 def handle_read(self): if self._ssl_accepting: s = self.socket.accept_ssl() if s: self._ssl_accepting = 0 else: try: blob = self.recv(4096) if blob is None: pass elif blob == "": self.handle_close() else: self.buffer = self.buffer + blob except SSL.SSLError as what: if str(what) == "unexpected eof": self.handle_close() return else: raise class ssl_echo_server(SSL.ssl_dispatcher): channel_class = ssl_echo_channel def __init__(self, addr, port, ssl_context): SSL.ssl_dispatcher.__init__(self) self.create_socket(ssl_context) self.set_reuse_addr() self.socket.setblocking(0) self.bind((addr, port)) self.listen(5) self.ssl_ctx = ssl_context def handle_accept(self): try: sock, addr = self.socket.accept() self.channel_class(sock) except: print("-" * 40) import traceback traceback.print_exc() print("-" * 40) return def writable(self): return 0 if __name__ == "__main__": Rand.load_file("../randpool.dat", -1) ctx = echod_lib.init_context( "sslv23", "server.pem", "ca.pem", # SSL.verify_peer | SSL.verify_fail_if_no_peer_cert) SSL.verify_none, ) ctx.set_tmp_dh("dh1024.pem") ssl_echo_server("", 9999, ctx) asyncore.loop() Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/ssl/echod-eg1.py000066400000000000000000000027411506746742300172370ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """Demo SSL server #1 for the HOWTO. Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" import SocketServer from M2Crypto import Err, Rand, SSL, threading def init_context(protocol, dhpfile, certfile, cafile, verify, verify_depth=10): ctx = SSL.Context(protocol) ctx.set_tmp_dh(dhpfile) ctx.load_cert(certfile) # ctx.load_verify_info(cafile) ctx.set_verify(verify, verify_depth) ctx.set_session_id_ctx("echod") ctx.set_info_callback() return ctx class ssl_echo_handler(SocketServer.BaseRequestHandler): buffer = "Ye Olde Echo Servre\r\n" def handle(self): peer = self.request.get_peer_cert() if peer is not None: print("Client CA =", peer.get_issuer().O) print("Client Subject =", peer.get_subject().CN) self.request.write(self.buffer) while 1: buf = self.request.read() if not buf: break self.request.write(buf) def finish(self): self.request.set_shutdown(SSL.SSL_SENT_SHUTDOWN | SSL.SSL_RECEIVED_SHUTDOWN) self.request.close() if __name__ == "__main__": Rand.load_file("randpool.dat", -1) threading.init() ctx = init_context("sslv23", "dh1024.pem", "server.pem", "ca.pem", SSL.verify_peer) s = SSL.SSLServer(("", 9999), ssl_echo_handler, ctx) s.serve_forever() threading.cleanup() Rand.save_file("randpool.dat") m2crypto-0.46.2/demo/ssl/echod-forking.py000066400000000000000000000012231506746742300202140ustar00rootroot00000000000000#!/usr/bin/env python """A forking SSL 'echo' server. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from M2Crypto import DH, Rand, SSL import echod_lib class ssl_echo_handler(echod_lib.ssl_echo_handler): buffer = "Ye Olde Forking Echo Servre\r\n" if __name__ == "__main__": Rand.load_file("../randpool.dat", -1) ctx = echod_lib.init_context( "sslv23", "server.pem", "ca.pem", SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, ) ctx.set_tmp_dh("dh1024.pem") s = SSL.ForkingSSLServer(("", 9999), ssl_echo_handler, ctx) s.serve_forever() Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/ssl/echod-iterative.py000066400000000000000000000012561506746742300205570ustar00rootroot00000000000000#!/usr/bin/env python """A simple iterative SSL 'echo' server. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from M2Crypto import Rand, SSL import echod_lib class ssl_echo_handler(echod_lib.ssl_echo_handler): buffer = "Ye Olde One-At-A-Time Echo Servre\r\n" if __name__ == "__main__": Rand.load_file("../randpool.dat", -1) ctx = echod_lib.init_context( "sslv23", "server.pem", "ca.pem", SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, ) # SSL.verify_none) ctx.set_tmp_dh("dh1024.pem") s = SSL.SSLServer(("", 9999), ssl_echo_handler, ctx) s.serve_forever() Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/ssl/echod-thread.py000066400000000000000000000027731506746742300200370ustar00rootroot00000000000000#!/usr/bin/env python """Another multi-threading SSL 'echo' server. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from M2Crypto import Rand, SSL, threading import echod_lib import thread from socket import * buffer = "Ye Newe Threading Echo Servre\r\n" def echo_handler(sslctx, sock, addr): sslconn = SSL.Connection(sslctx, sock) sslconn.setup_addr(addr) sslconn.setup_ssl() sslconn.set_accept_state() sslconn.accept_ssl() sslconn.write(buffer) while 1: try: buf = sslconn.read() if not buf: break sslconn.write(buf) except SSL.SSLError as what: if str(what) == "unexpected eof": break else: raise except: break # Threading servers need this. sslconn.set_shutdown(SSL.SSL_RECEIVED_SHUTDOWN | SSL.SSL_SENT_SHUTDOWN) sslconn.close() if __name__ == "__main__": threading.init() Rand.load_file("../randpool.dat", -1) ctx = echod_lib.init_context( "sslv23", "server.pem", "ca.pem", SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, ) ctx.set_tmp_dh("dh1024.pem") sock = socket(AF_INET, SOCK_STREAM) sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) sock.bind(("", 9999)) sock.listen(5) while 1: conn, addr = sock.accept() thread.start_new_thread(echo_handler, (ctx, conn, addr)) Rand.save_file("../randpool.dat") threading.cleanup() m2crypto-0.46.2/demo/ssl/echod-threading.py000066400000000000000000000017211506746742300205250ustar00rootroot00000000000000#!/usr/bin/env python """A multi-threading SSL 'echo' server. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from M2Crypto import DH, Rand, SSL, threading import echod_lib class ssl_echo_handler(echod_lib.ssl_echo_handler): buffer = "Ye Olde Threading Echo Servre\r\n" def finish(self): # Threading servers need this. self.request.set_shutdown(SSL.SSL_SENT_SHUTDOWN | SSL.SSL_RECEIVED_SHUTDOWN) self.request.close() if __name__ == "__main__": try: threading.init() Rand.load_file("../randpool.dat", -1) ctx = echod_lib.init_context( "sslv23", "server.pem", "ca.pem", SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, ) ctx.set_tmp_dh("dh1024.pem") s = SSL.ThreadingSSLServer(("", 9999), ssl_echo_handler, ctx) s.serve_forever() Rand.save_file("../randpool.dat") except: threading.cleanup() m2crypto-0.46.2/demo/ssl/echod_lib.py000066400000000000000000000024641506746742300174150ustar00rootroot00000000000000from __future__ import print_function """Support routines for the various SSL 'echo' servers. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" import SocketServer from M2Crypto import SSL def init_context(protocol, certfile, cafile, verify, verify_depth=10): ctx = SSL.Context(protocol) ctx.load_cert_chain(certfile) ctx.load_verify_locations(cafile) ctx.set_client_CA_list_from_file(cafile) ctx.set_verify(verify, verify_depth) # ctx.set_allow_unknown_ca(1) ctx.set_session_id_ctx("echod") ctx.set_info_callback() return ctx class ssl_echo_handler(SocketServer.BaseRequestHandler): buffer = "Ye Olde Echo Servre\r\n" def handle(self): peer = self.request.get_peer_cert() if peer is not None: print("Client CA =", peer.get_issuer().O) print("Client Subject =", peer.get_subject().CN) x = self.request.write(self.buffer) while 1: try: buf = self.request.read() if not buf: break self.request.write(buf) except SSL.SSLError as what: if str(what) == "unexpected eof": break else: raise def finish(self): self.request.close() m2crypto-0.46.2/demo/ssl/ftp_tls.py000066400000000000000000000015661506746742300171620ustar00rootroot00000000000000#!/usr/bin/env python """Demo for M2Crypto.ftpslib's FTP/TLS client. This client interoperates with M2Crypto's Medusa-based FTP/TLS server as well as Peter Runestig's patched-for-TLS OpenBSD FTP server. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" from M2Crypto import SSL, ftpslib, threading def passive(): ctx = SSL.Context("sslv23") f = ftpslib.FTP_TLS(ssl_ctx=ctx) f.connect("127.0.0.1", 39021) f.auth_tls() f.set_pasv(1) f.login("ftp", "ngps@") f.prot_p() f.retrlines("LIST") f.quit() def active(): ctx = SSL.Context("sslv23") f = ftpslib.FTP_TLS(ssl_ctx=ctx) f.connect("127.0.0.1", 39021) f.auth_tls() f.set_pasv(0) f.login("ftp", "ngps@") f.prot_p() f.retrlines("LIST") f.quit() if __name__ == "__main__": threading.init() active() passive() threading.cleanup() m2crypto-0.46.2/demo/ssl/http_cli_20.py000066400000000000000000000007761506746742300176200ustar00rootroot00000000000000import httplib, sys def test_httplib(): h = httplib.HTTPConnection("127.0.0.1", 80) h.set_debuglevel(1) h.putrequest("GET", "/") h.putheader("Accept", "text/html") h.putheader("Accept", "text/plain") h.putheader("Connection", "close") h.endheaders() resp = h.getresponse() f = resp.fp while 1: data = f.readline() if not data: break sys.stdout.write(data) f.close() h.close() if __name__ == "__main__": test_httplib() m2crypto-0.46.2/demo/ssl/https_cli.py000066400000000000000000000023031506746742300174660ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """Demonstrations of M2Crypto.httpslib. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" import sys from M2Crypto import Rand, SSL, httpslib, threading def test_httpslib(): ctx = SSL.Context("sslv23") ctx.load_cert_chain("client.pem") ctx.load_verify_locations("ca.pem", "") ctx.set_verify(SSL.verify_peer, 10) ctx.set_info_callback() h = httpslib.HTTPSConnection("localhost", 19443, ssl_context=ctx) h.set_debuglevel(1) h.putrequest("GET", "/") h.putheader("Accept", "text/html") h.putheader("Accept", "text/plain") h.putheader("Connection", "close") h.endheaders() resp = h.getresponse() f = resp.fp c = 0 while 1: # Either of following two works. # data = f.readline(4096) data = resp.read(4096) if not data: break c = c + len(data) # print(data) sys.stdout.write(data) sys.stdout.flush() f.close() h.close() if __name__ == "__main__": Rand.load_file("../randpool.dat", -1) # threading.init() test_httpslib() # threading.cleanup() Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/ssl/https_cli_async.py000066400000000000000000000073741506746742300207000ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """Demo for client-side ssl_dispatcher usage. Note that connect() is blocking. (Need fix?) This isn't really a HTTPS client; it's just a toy. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" import asyncore, sys, time from M2Crypto import Rand, SSL class https_client(SSL.ssl_dispatcher): def __init__(self, host, path, ssl_ctx): SSL.ssl_dispatcher.__init__(self) self.path = path self.buffer = "GET %s HTTP/1.0\r\n\r\n" % self.path self.create_socket(ssl_ctx) self.socket.connect((host, 19443)) self._can_read = 1 self._count = 0 def handle_connect(self): pass def readable(self): return self._can_read def handle_read(self): try: result = self.recv() if result is None: return elif result == "": self._can_read = 0 sys.stdout.write( "%s: total: %5d\n" % ( self.path, self._count, ) ) sys.stdout.flush() self.close() else: # print(result) l = len(result) self._count = self._count + l display = (time.time(), l, self.path) sys.stdout.write("%14.3f: read %5d from %s\n" % display) sys.stdout.flush() except SSL.SSLError as why: print("handle_read:", why) self.close() raise def writable(self): return len(self.buffer) > 0 def handle_write(self): try: sent = self.send(self.buffer) self.buffer = self.buffer[sent:] except SSL.SSLError as why: print("handle_write:", why) self.close() if __name__ == "__main__": Rand.load_file("../randpool.dat", -1) ctx = SSL.Context() url = ( "/jdk118/api/u-names.html", "/postgresql/xfunc-c.html", "/python2.1/modindex.html", ) for u in url: https_client("localhost", u, ctx) asyncore.loop() Rand.save_file("../randpool.dat") # Here's a sample output. Server is Apache+mod_ssl on localhost. # $ python https_cli_async.py # 991501090.682: read 278 from /python2.1/modindex.html # 991501090.684: read 278 from /postgresql/xfunc-c.html # 991501090.742: read 4096 from /postgresql/xfunc-c.html # 991501090.743: read 4096 from /postgresql/xfunc-c.html # 991501090.744: read 4096 from /postgresql/xfunc-c.html # 991501090.744: read 4096 from /postgresql/xfunc-c.html # 991501090.755: read 4096 from /postgresql/xfunc-c.html # 991501090.756: read 278 from /jdk118/api/u-names.html # 991501090.777: read 4096 from /postgresql/xfunc-c.html # 991501090.778: read 4096 from /postgresql/xfunc-c.html # 991501090.778: read 4096 from /postgresql/xfunc-c.html # 991501090.782: read 4096 from /postgresql/xfunc-c.html # 991501090.813: read 4096 from /python2.1/modindex.html # 991501090.839: read 4096 from /jdk118/api/u-names.html # 991501090.849: read 4096 from /python2.1/modindex.html # 991501090.873: read 3484 from /postgresql/xfunc-c.html # 991501090.874: read 4096 from /jdk118/api/u-names.html # 991501090.874: read 4096 from /python2.1/modindex.html # /postgresql/xfunc-c.html: total: 40626 # 991501090.886: read 4096 from /jdk118/api/u-names.html # 991501090.886: read 2958 from /python2.1/modindex.html # 991501090.887: read 4096 from /jdk118/api/u-names.html # /python2.1/modindex.html: total: 15524 # 991501090.893: read 4096 from /jdk118/api/u-names.html # 991501090.894: read 2484 from /jdk118/api/u-names.html # /jdk118/api/u-names.html: total: 23242 # $ m2crypto-0.46.2/demo/ssl/https_srv.py000066400000000000000000000104461506746742300175400ustar00rootroot00000000000000"""This server extends BaseHTTPServer and SimpleHTTPServer thusly: 1. One thread per connection. 2. Generates directory listings. In addition, it has the following properties: 1. Works over HTTPS only. 2. Displays SSL handshaking and SSL session info. 3. Performs SSL renegotiation when a magic url is requested. TODO: 1. Cache stat() of directory entries. 2. Fancy directory indexing. 3. Interface ZPublisher. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. """ import os, sys from SimpleHTTPServer import SimpleHTTPRequestHandler from M2Crypto import Rand, SSL from M2Crypto.SSL.SSLServer import ThreadingSSLServer try: from cStringIO import StringIO except ImportError: from StringIO import StringIO def mkdirlist(path, url): dirlist = os.listdir(path) dirlist.sort() f = StringIO() f.write("Index listing for %s\r\n" % (url,)) f.write("

    Index listing for %s

    \r\n" % (url,)) f.write("
    \r\n")
        for d in dirlist:
            if os.path.isdir(os.path.join(path, d)):
                d2 = d + "/"
            else:
                d2 = d
            if url == "/":
                f.write('%s
    \r\n' % (d, d2)) else: f.write('%s
    \r\n' % (url, d, d2)) f.write("
    \r\n\r\n") f.reset() return f class HTTP_Handler(SimpleHTTPRequestHandler): server_version = "https_srv/0.1" reneg = 0 # Cribbed from SimpleHTTPRequestHander to add the ".der" entry, # which facilitates installing your own certificates into browsers. extensions_map = { "": "text/plain", # Default, *must* be present ".html": "text/html", ".htm": "text/html", ".gif": "image/gif", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".der": "application/x-x509-ca-cert", } def send_head(self): if self.path[1:8] == "_reneg_": self.reneg = 1 self.path = self.path[8:] path = self.translate_path(self.path) if os.path.isdir(path): f = mkdirlist(path, self.path) filetype = "text/html" else: try: f = open(path, "rb") filetype = self.guess_type(path) except IOError: self.send_error(404, "File not found") return None self.send_response(200) self.send_header("Content-type", filetype) self.end_headers() return f def do_GET(self): # sess = self.request.get_session() # self.log_message('\n%s', sess.as_text()) f = self.send_head() if self.reneg: self.reneg = 0 self.request.renegotiate() sess = self.request.get_session() self.log_message("\n%s", sess.as_text()) if f: self.copyfile(f, self.wfile) f.close() def do_HEAD(self): # sess = self.request.get_session() # self.log_message('\n%s', sess.as_text()) f = self.send_head() if f: f.close() class HTTPS_Server(ThreadingSSLServer): def __init__(self, server_addr, handler, ssl_ctx): ThreadingSSLServer.__init__(self, server_addr, handler, ssl_ctx) self.server_name = server_addr[0] self.server_port = server_addr[1] def finish(self): self.request.set_shutdown(SSL.SSL_RECEIVED_SHUTDOWN | SSL.SSL_SENT_SHUTDOWN) self.request.close() def init_context(protocol, certfile, cafile, verify, verify_depth=10): ctx = SSL.Context(protocol) ctx.load_cert(certfile) ctx.load_client_ca(cafile) ctx.load_verify_info(cafile) ctx.set_verify(verify, verify_depth) ctx.set_allow_unknown_ca(1) ctx.set_session_id_ctx("https_srv") ctx.set_info_callback() return ctx if __name__ == "__main__": from M2Crypto import threading as m2threading m2threading.init() if len(sys.argv) < 2: wdir = "." else: wdir = sys.argv[1] Rand.load_file("../randpool.dat", -1) ctx = init_context("sslv23", "server.pem", "ca.pem", SSL.verify_none) # SSL.verify_peer | SSL.verify_fail_if_no_peer_cert) ctx.set_tmp_dh("dh1024.pem") os.chdir(wdir) httpsd = HTTPS_Server(("", 19443), HTTP_Handler, ctx) httpsd.serve_forever() Rand.save_file("../randpool.dat") m2threading.cleanup() m2crypto-0.46.2/demo/ssl/myapp.py000066400000000000000000000014011506746742300166210ustar00rootroot00000000000000""" Sample application for socklib and somelib. Copyright (c) 2007 Open Source Applications Foundation. All rights reserved. """ # Sample application that uses socklib to override socket.ssl in order # to make the 3rd party library use M2Crypto for SSL, instead of python # stdlib SSL. import socklib # sets M2Crypto.SSL.Connection as socket.ssl # Set up the secure context for socklib from M2Crypto import SSL def getContext(): ctx = SSL.Context() ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 9) ctx.load_verify_locations("ca.pem") return ctx socklib.setSSLContextFactory(getContext) # Import and use 3rd party lib import somelib if __name__ == "__main__": c = somelib.HttpsGetSlash() c.get("verisign.com", 443) m2crypto-0.46.2/demo/ssl/s_client.py000066400000000000000000000057761506746742300173160ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """An M2Crypto implementation of OpenSSL's s_client. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from socket import * import getopt import string import sys from M2Crypto import SSL # s_server -www HOST = "127.0.0.1" PORT = 4433 REQ = "GET / HTTP/1.0\r\n\r\n" class Config: pass def config(args): options = [ "connect=", "verify=", "cert=", "key=", "CApath=", "CAfile=", "reconnect", "pause", "showcerts", "debug", "nbio_test", "state", "nbio", "crlf", "sslv2", "sslv3", "tlsv1", "no_sslv2", "no_sslv3", "no_tlsv1", "bugs", "cipher=", "Verify=", ] optlist, optarg = getopt.getopt(args, "", options) cfg = Config() for opt in optlist: setattr(cfg, opt[0][2:], opt[1]) for x in (("tlsv1", "no_tlsv1"), ("sslv3", "no_sslv3"), ("sslv2", "no_sslv2")): if hasattr(cfg, x[0]) and hasattr(cfg, x[1]): raise ValueError("mutually exclusive: %s and %s" % x) if hasattr(cfg, "connect"): (host, port) = string.split(cfg.connect, ":") cfg.connect = (host, int(port)) else: cfg.connect = (HOST, PORT) cfg.protocol = [] # First protocol found will be used. # Permutate the following tuple for preference. for p in ("tlsv1", "sslv3", "sslv2"): if hasattr(cfg, p): cfg.protocol.append(p) cfg.protocol.append("sslv23") return cfg def make_context(config): ctx = SSL.Context(config.protocol[0]) if hasattr(config, "cert"): cert = config.cert else: cert = "client.pem" if hasattr(config, "key"): key = config.key else: key = "client.pem" # ctx.load_cert(cert, key) if hasattr(config, "verify"): verify = SSL.verify_peer depth = int(config.verify) elif hasattr(config, "Verify"): verify = SSL.verify_peer | SSL.verify_fail_if_no_peer_cert depth = int(config.Verify) else: verify = SSL.verify_none depth = 10 config.verify = verify config.verify_depth = depth ctx.set_verify(verify, depth) if hasattr(config, "CAfile"): cafile = config.CAfile else: cafile = "ca.pem" ctx.load_verify_location(cafile) return ctx def s_client(config): ctx = make_context(config) s = SSL.Connection(ctx) s.connect(config.connect) if config.verify != SSL.verify_none and not s.verify_ok(): print("peer verification failed") peer = s.get_peer_cert() if peer is None: print("unable to get peer certificate") else: print("peer.as_text()") raise SystemExit s.send(REQ) while 1: data = s.recv() if not data: break print(data) s.close() if __name__ == "__main__": cfg = config(sys.argv[1:]) s_client(cfg) m2crypto-0.46.2/demo/ssl/s_server.py000066400000000000000000000122531506746742300173320ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """An M2Crypto implementation of OpenSSL's s_server. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from socket import * import asyncore import cStringIO import getopt import string import sys from M2Crypto import SSL, BIO, DH, Err # s_server -www HOST = "" PORT = 4433 class Config: pass def config(args): options = [ "accept=", "context=", "verify=", "Verify=", "cert=", "key=", "dcert=", "dkey=", "nocert", "crlf", "debug", "CApath=", "CAfile=", "quiet", "no_tmp_rsa", "state", "sslv2", "sslv3", "tlsv1", "no_sslv2", "no_sslv3", "no_tlsv1", "bugs", "cipher=", ] optlist, optarg = getopt.getopt(args, "", options) cfg = Config() for opt in optlist: setattr(cfg, opt[0][2:], opt[1]) for x in (("tlsv1", "no_tlsv1"), ("sslv3", "no_sslv3"), ("sslv2", "no_sslv2")): if hasattr(cfg, x[0]) and hasattr(cfg, x[1]): raise ValueError("mutually exclusive: %s and %s" % x) if hasattr(cfg, "accept"): cfg.accept = string.split(cfg.connect, ":") else: cfg.accept = (HOST, PORT) cfg.protocol = [] # First protocol found will be used. # Permutate the following tuple for preference. for p in ("tlsv1", "sslv3", "sslv2"): if hasattr(cfg, p): cfg.protocol.append(p) cfg.protocol.append("sslv23") return cfg RESP_HEAD = """\ HTTP/1.0 200 ok Content-type: text/html
    
    Emulating s_server -www
    Ciphers supported in s_server.py
    """
    
    RESP_TAIL = """\
    
    """ class channel(SSL.ssl_dispatcher): def __init__(self, conn, debug): SSL.ssl_dispatcher.__init__(self, conn) self.socket.setblocking(0) self.buffer = self.fixup_buffer() self.debug = debug def fixup_buffer(self): even = 0 buffer = cStringIO.StringIO() buffer.write(RESP_HEAD) for c in self.get_ciphers(): # This formatting works for around 80 columns. buffer.write("%-11s:%-28s" % (c.version(), c.name())) if even: buffer.write("\r\n") even = 1 - even buffer.write("\r\n%s" % RESP_TAIL) return buffer.getvalue() def handle_connect(self): pass def handle_close(self): self.close() def handle_error(self, exc_type, exc_value, exc_traceback): if self.debug: print("handle_error()") # print(exc_type, exc_value, exc_traceback) print(Err.get_error()) self.handle_close() def writeable(self): return len(self.buffer) def handle_write(self): n = self.send(self.buffer) if n == -1: pass elif n == 0: self.handle_close() else: self.buffer = self.buffer[n:] if self.debug: print("handle_write():", n) def readable(self): return 1 def handle_read(self): blob = self.recv() if blob is None: pass elif blob == "": self.handle_close() else: pass if self.debug: print("handle_read():", blob) class server(SSL.ssl_dispatcher): channel_class = channel def __init__(self, addr, port, config, ssl_context): asyncore.dispatcher.__init__(self) self.create_socket(ssl_context) self.set_reuse_addr() self.socket.setblocking(0) self.bind((addr, port)) self.listen(5) self.config = config self.debug = config.debug self.ssl_ctx = ssl_context def handle_accept(self): sock, addr = self.accept() print(self.ssl_ctx.get_verify_mode()) if (self.ssl_ctx.get_verify_mode() is SSL.verify_none) or sock.verify_ok(): self.channel_class(sock, self.debug) else: print("client verification failed") sock.close() def writeable(self): return 0 def s_server(config): ctx = SSL.Context(config.protocol[0]) if hasattr(config, "debug"): config.debug = 1 else: config.debug = 0 if hasattr(config, "cert"): cert = config.cert else: cert = "server.pem" if hasattr(config, "key"): cert = config.key else: cert = "server.pem" ctx.load_cert(cert) if hasattr(config, "CAfile"): cafile = config.CAfile else: cafile = "ca.pem" ctx.load_verify_location(cafile) if hasattr(config, "verify"): verify = SSL.verify_peer depth = int(config.verify) elif hasattr(config, "Verify"): verify = SSL.verify_peer | SSL.verify_fail_if_no_peer_cert depth = int(config.Verify) else: verify = SSL.verify_none depth = 0 ctx.set_verify(verify, depth) ctx.set_tmp_dh("dh1024.pem") # ctx.set_info_callback() server(cfg.accept[0], cfg.accept[1], cfg, ctx) asyncore.loop() if __name__ == "__main__": cfg = config(sys.argv[1:]) s_server(cfg) m2crypto-0.46.2/demo/ssl/server.pem000066400000000000000000000041101506746742300171320ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDYjCCAsugAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAzMDYyMjEzMzAxNFoXDTA0MDYyMTEzMzAx NFowXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwls b2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5leGFtcGxlLmRv bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA37aKGZtFicl8xXXTLJ8/JD7c kd3t/teCX9i61lpaDQCKBoVrrursIvZihemMKI9g/u/+BLqt5g8mBdgUdYz0txc8 KEbV2hj+wwOX4H3XwD0Y+DysXiNHq7/tFdmzSVHoLxpY4zYzXbxQ/p049wvIyPRp /y3omcnx/TEUhkn+JmkCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4 QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTB H/mUYlww24mJlSxEtGdlwojO9zCBrQYDVR0jBIGlMIGigBTr+pwHMS1CmF9cuGI4 du3YqoHAwqGBhqSBgzCBgDELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv MRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8gQ2VydGlm aWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNuZ3BzQG5ldG1lbWV0aWMuY29t ggEAMA0GCSqGSIb3DQEBBAUAA4GBAAvl6v0s3eFeGP4iAcrfysuK7jzFKhjDYuOy lVS3u33bZNLnMpM6OSEM9yPh4WpFCVHf+nYwC71pk4ilsLVXjKxymm2lNGcxLVuW iydFz4Ly9nmN7Ja9ygYT39dGAFP/wN7ELTpsbul8VfmqhNg9y81d8i/A1tK3AGA8 0QkPQNdP -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDftooZm0WJyXzFddMsnz8kPtyR3e3+14Jf2LrWWloNAIoGhWuu 6uwi9mKF6Ywoj2D+7/4Euq3mDyYF2BR1jPS3FzwoRtXaGP7DA5fgfdfAPRj4PKxe I0erv+0V2bNJUegvGljjNjNdvFD+nTj3C8jI9Gn/LeiZyfH9MRSGSf4maQIDAQAB AoGAHpeVtv62uarl9xKvuBBm0AwQmZnhq9HIsFaw5hMg8Vo7hbzFBvx1IirTOkC/ u+QvfW1QLVFh6m3z4ySzV4fZBtcd6F9SbSrZ0xsxIUB2NOSa1RGgiaP61bJnMMM1 xM3O9iwM5GZc3Gqy08QOCpDl0772VJ+9Gz3FA88mrc6rHQkCQQDz6RIatFjT28n8 1vy0nHwwZz2oXTpe/pyZPwoKj8zVsmrKhKwOw7l8ArxjP8zoHOE7AQBCXYDMNoFp IAF0yuqrAkEA6s0wMEdPpQeb0XHAfccyJQoeULxHdVFoz1wWmGSOm4YmQtR8/QJx luEgfpeRkzxBKt5Ls3MEkheIOw7xV24zOwJAMz+DaE0AZPNHS3K4ghJnHZxzng6I lzEUIjbWm0V/ml70hTy/EhMZw+6nOotLOHHo+QbK0SboSwAgzL/Gzo1cJQJANqpS 38qadleRJXAQWrg3qnvyluVe1aeAeVZ9RDmVIgxXeBO0jcs12uTLBe4PzHGo0mwy v7K1i7XC180gzzQu5QJBAOxITT9RoWSSozPvnirHd37sn+RsrNYkV07NAa80M20Z DkBPHeMVkNgigrQ6L6vWmbRDGQbGcMplAxnI5ppKCoU= -----END RSA PRIVATE KEY----- m2crypto-0.46.2/demo/ssl/server3.py000066400000000000000000000062351506746742300170760ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """ server3 from the book 'Network Security with OpenSSL', but modified to Python/M2Crypto from the original C implementation. Copyright (c) 2004-2005 Open Source Applications Foundation. Author: Heikki Toivonen """ from M2Crypto import SSL, Rand, threading, DH import thread from socket import * verbose_debug = 1 def verify_callback(ok, store): if not ok: print("***Verify Not ok") return ok dh1024 = None def init_dhparams(): global dh1024 dh1024 = DH.load_params("dh1024.pem") def tmp_dh_callback(ssl, is_export, keylength): global dh1024 if not dh1024: init_dhparams() return dh1024._ptr() def setup_server_ctx(): ctx = SSL.Context("sslv23") if ctx.load_verify_locations("ca.pem") != 1: print("***No CA file") # if ctx.set_default_verify_paths() != 1: # print("***No default verify paths") ctx.load_cert_chain("server.pem") ctx.set_verify( SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, 10, verify_callback ) ctx.set_options(SSL.op_all | SSL.op_no_sslv2) ctx.set_tmp_dh_callback(tmp_dh_callback) # ctx.set_tmp_dh('dh1024.pem') if ctx.set_cipher_list("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH") != 1: print("***No valid ciphers") if verbose_debug: ctx.set_info_callback() return ctx def post_connection_check(peerX509, expectedHost): if peerX509 is None: print("***No peer certificate") # Not sure if we can do any other checks return 1 def do_server_loop(conn): while 1: try: buf = conn.read() if not buf: break print(buf) except SSL.SSLError as what: if str(what) == "unexpected eof": break else: raise except: break if conn.get_shutdown(): return 1 return 0 # How about something like: # def server_thread(ctx, ssl, addr): # conn = SSL.Connection(ctx, None) # conn.ssl = ssl # conn.setup_addr(addr) def server_thread(ctx, sock, addr): conn = SSL.Connection(ctx, sock) conn.set_post_connection_check_callback(post_connection_check) conn.setup_addr(addr) conn.set_accept_state() conn.setup_ssl() conn.accept_ssl() post_connection_check(conn) print("SSL Connection opened") if do_server_loop(conn): conn.close() else: conn.clear() print("SSL Connection closed") if __name__ == "__main__": threading.init() Rand.load_file("../randpool.dat", -1) ctx = setup_server_ctx() # How about something like this? # conn_root = SSL.Connection(ctx) # conn_root.bind(('127.0.0.1', 9999)) # conn_root.listen(5) # while 1: # ssl, addr = conn_root.accept() # thread.start_new_thread(server_thread, (ctx, ssl, addr)) sock = socket(AF_INET, SOCK_STREAM) sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) sock.bind(("", 9999)) sock.listen(5) while 1: conn, addr = sock.accept() thread.start_new_thread(server_thread, (ctx, conn, addr)) Rand.save_file("../randpool.dat") threading.cleanup() m2crypto-0.46.2/demo/ssl/sess.py000066400000000000000000000042631506746742300164610ustar00rootroot00000000000000from __future__ import print_function """M2Crypto.SSL.Session client demo: This program requests a URL from a HTTPS server, saves the negotiated SSL session id, parses the HTML returned by the server, then requests each HREF in a separate thread using the saved SSL session id. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from M2Crypto import Err, Rand, SSL, X509, threading m2_threading = threading del threading import formatter, getopt, htmllib, sys from threading import Thread from socket import gethostname def handler(sslctx, host, port, href, recurs=0, sslsess=None): s = SSL.Connection(sslctx) if sslsess: s.set_session(sslsess) s.connect((host, port)) else: s.connect((host, port)) sslsess = s.get_session() # print(sslsess.as_text()) if recurs: p = htmllib.HTMLParser(formatter.NullFormatter()) f = s.makefile("rw") f.write(href) f.flush() while 1: data = f.read() if not data: break if recurs: p.feed(data) if recurs: p.close() f.close() if recurs: for a in p.anchorlist: req = "GET %s HTTP/1.0\r\n\r\n" % a thr = Thread( target=handler, args=(sslctx, host, port, req, recurs - 1, sslsess) ) print("Thread =", thr.getName()) thr.start() if __name__ == "__main__": m2_threading.init() Rand.load_file("../randpool.dat", -1) host = "127.0.0.1" port = 9443 req = "/" optlist, optarg = getopt.getopt(sys.argv[1:], "h:p:r:") for opt in optlist: if "-h" in opt: host = opt[1] elif "-p" in opt: port = int(opt[1]) elif "-r" in opt: req = opt[1] ctx = SSL.Context("sslv3") ctx.load_cert("client.pem") ctx.load_verify_info("ca.pem") ctx.load_client_ca("ca.pem") ctx.set_verify(SSL.verify_none, 10) req = "GET %s HTTP/1.0\r\n\r\n" % req start = Thread(target=handler, args=(ctx, host, port, req, 1)) print("Thread =", start.getName()) start.start() start.join() m2_threading.cleanup() Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/ssl/sess2.py000066400000000000000000000037201506746742300165400ustar00rootroot00000000000000from __future__ import print_function """M2Crypto.SSL.Session client demo2: This program creates two sockets, each bound to a different local address. The first creates an SSL connection, the second then creates another SSL connection using the first's SSL session id. (This program only works if you've ifconfig'ed your interfaces correctly, of course.) Copyright (c) 1999-2001 Ng Pheng Siong. All rights reserved.""" from M2Crypto import Err, Rand, SSL, X509, threading m2_threading = threading del threading import formatter, getopt, htmllib, sys from threading import Thread from socket import gethostname ADDR1 = "127.0.0.1", 9999 ADDR2 = "127.0.0.2", 9999 def handler(addr, sslctx, host, port, req, sslsess=None): s = SSL.Connection(sslctx) s.bind(addr) if sslsess: s.set_session(sslsess) s.connect((host, port)) else: s.connect((host, port)) sslsess = s.get_session() s.write(req) while 1: data = s.read(4096) if not data: break if addr != ADDR2: thr = Thread(target=handler, args=(ADDR2, sslctx, host, port, req, sslsess)) print("Thread =", thr.getName()) thr.start() s.close() if __name__ == "__main__": m2_threading.init() Rand.load_file("../randpool.dat", -1) host = "127.0.0.1" port = 443 req = "/" optlist, optarg = getopt.getopt(sys.argv[1:], "h:p:r:") for opt in optlist: if "-h" in opt: host = opt[1] elif "-p" in opt: port = int(opt[1]) elif "-r" in opt: req = opt[1] ctx = SSL.Context("sslv3") ctx.load_cert("client.pem") ctx.load_verify_info("ca.pem") ctx.set_verify(SSL.verify_none, 10) req = "GET %s HTTP/1.0\r\n\r\n" % req start = Thread(target=handler, args=(ADDR1, ctx, host, port, req)) print("Thread =", start.getName()) start.start() start.join() m2_threading.cleanup() Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/ssl/sess2.ssldump.out000066400000000000000000000105161506746742300204060ustar00rootroot00000000000000New TCP connection #1: localhost(9999) <-> localhost(443) 1 1 0.0061 (0.0061) C>S Handshake ClientHello Version 3.0 cipher suites SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA SSL_RSA_WITH_3DES_EDE_CBC_SHA SSL_DHE_DSS_WITH_RC4_128_SHA SSL_RSA_WITH_IDEA_CBC_SHA SSL_RSA_WITH_RC4_128_SHA SSL_RSA_WITH_RC4_128_MD5 SSL_DHE_DSS_WITH_RC2_56_CBC_SHA SSL_RSA_EXPORT1024_WITH_RC4_56_SHA SSL_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA SSL_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 SSL_RSA_EXPORT1024_WITH_RC4_56_MD5 SSL_DHE_RSA_WITH_DES_CBC_SHA SSL_DHE_DSS_WITH_DES_CBC_SHA SSL_RSA_WITH_DES_CBC_SHA SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA SSL_RSA_EXPORT_WITH_DES40_CBC_SHA SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 SSL_RSA_EXPORT_WITH_RC4_40_MD5 compression methods NULL 1 2 0.0068 (0.0006) S>C Handshake ServerHello Version 3.0 session_id[32]= f2 6e ab c1 e6 db fa 55 4d 77 97 be 0d 28 23 fe 53 8a d5 3b 31 58 1d 93 35 65 10 a9 06 6b a2 a6 cipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA compressionMethod NULL 1 3 0.0846 (0.0778) S>C Handshake Certificate 1 4 0.0848 (0.0001) S>C Handshake ServerKeyExchange 1 5 0.0848 (0.0000) S>C Handshake ServerHelloDone 1 6 0.2475 (0.1627) C>S Handshake ClientKeyExchange DiffieHellmanClientPublicValue[128]= 3c 8f 0f 93 8a 3a 1e 5c 07 cf 40 2f 7d bf 25 7a e8 2b ba 54 46 d5 54 40 22 90 38 f2 88 c3 62 8a ec b1 b7 f1 06 6d fa ba 46 dd f1 92 5f 44 18 44 8e df 33 30 64 79 e0 77 07 1f bc 10 dc 0d 6e 4b 4d 68 01 af 4a bf 83 62 de 87 d7 98 6c e3 9b af a2 a6 60 67 18 46 89 29 fa 1a 72 df 92 2d 9e 4f 2c b2 02 b3 ef b7 03 07 49 69 c5 b2 37 ae a1 0e 10 e1 79 25 a4 70 02 15 69 d9 47 2c c8 48 23 67 1 7 0.2475 (0.0000) C>S ChangeCipherSpec 1 8 0.2475 (0.0000) C>S Handshake 1 9 0.3239 (0.0763) S>C ChangeCipherSpec 1 10 0.3239 (0.0000) S>C Handshake 1 11 0.3266 (0.0027) C>S application_data 1 12 0.3566 (0.0299) S>C application_data 1 13 0.3571 (0.0005) S>C Alert 1 0.3574 (0.0003) S>C TCP FIN New TCP connection #2: 127.0.0.2(9999) <-> localhost(443) 2 1 0.0039 (0.0039) C>S Handshake ClientHello Version 3.0 resume [32]= f2 6e ab c1 e6 db fa 55 4d 77 97 be 0d 28 23 fe 53 8a d5 3b 31 58 1d 93 35 65 10 a9 06 6b a2 a6 cipher suites SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA SSL_RSA_WITH_3DES_EDE_CBC_SHA SSL_DHE_DSS_WITH_RC4_128_SHA SSL_RSA_WITH_IDEA_CBC_SHA SSL_RSA_WITH_RC4_128_SHA SSL_RSA_WITH_RC4_128_MD5 SSL_DHE_DSS_WITH_RC2_56_CBC_SHA SSL_RSA_EXPORT1024_WITH_RC4_56_SHA SSL_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA SSL_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 SSL_RSA_EXPORT1024_WITH_RC4_56_MD5 SSL_DHE_RSA_WITH_DES_CBC_SHA SSL_DHE_DSS_WITH_DES_CBC_SHA SSL_RSA_WITH_DES_CBC_SHA SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA SSL_RSA_EXPORT_WITH_DES40_CBC_SHA SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 SSL_RSA_EXPORT_WITH_RC4_40_MD5 compression methods NULL 2 2 0.0055 (0.0016) S>C Handshake ServerHello Version 3.0 session_id[32]= f2 6e ab c1 e6 db fa 55 4d 77 97 be 0d 28 23 fe 53 8a d5 3b 31 58 1d 93 35 65 10 a9 06 6b a2 a6 cipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA compressionMethod NULL 2 3 0.0055 (0.0000) S>C ChangeCipherSpec 2 4 0.0055 (0.0000) S>C Handshake 2 5 0.0066 (0.0010) C>S ChangeCipherSpec 2 6 0.0066 (0.0000) C>S Handshake 1 14 0.3698 (0.0124) C>S Alert 1 0.3702 (0.0004) C>S TCP FIN 2 7 0.0996 (0.0930) C>S application_data 2 8 0.1224 (0.0227) S>C application_data 2 9 0.1244 (0.0019) S>C Alert 2 10 0.1248 (0.0004) C>S Alert 2 0.1254 (0.0005) C>S TCP FIN 2 0.1300 (0.0046) S>C TCP FIN m2crypto-0.46.2/demo/ssl/socklib.py000066400000000000000000000025231506746742300171270ustar00rootroot00000000000000""" socklib provides a way to transparently replace socket.ssl with M2Crypto.SSL.Connection. Usage: Import socklib before the 3rd party module that uses socket.ssl. Also, call socketlib.setSSLContextFactory() to set it up with a way to get secure SSL contexts. Copyright (c) 2007 Open Source Applications Foundation. All rights reserved. """ sslContextFactory = None def setSSLContextFactory(factory): global sslContextFactory sslContextFactory = factory from M2Crypto.SSL import Connection, Checker import socket class ssl_socket(socket.socket): def connect(self, addr, *args): self.addr = addr return super(ssl_socket, self).connect(addr, *args) def close(self): if hasattr(self, "conn"): self.conn.close() socket.socket.close(self) def ssl(sock): sock.conn = Connection(ctx=sslContextFactory(), sock=sock) sock.conn.addr = sock.addr sock.conn.setup_ssl() sock.conn.set_connect_state() sock.conn.connect_ssl() check = getattr( sock.conn, "postConnectionCheck", sock.conn.clientPostConnectionCheck ) if check is not None: if not check(sock.conn.get_peer_cert(), sock.conn.addr[0]): raise Checker.SSLVerificationError("post connection check failed") return sock.conn socket.socket = ssl_socket socket.ssl = ssl m2crypto-0.46.2/demo/ssl/somelib.py000066400000000000000000000012471506746742300171350ustar00rootroot00000000000000from __future__ import print_function """ Sample 3rd party lib to use with socklib and myapp. Copyright (c) 2007 Open Source Applications Foundation. All rights reserved. """ # This represents some 3rd party library we don't want to modify import socket class HttpsGetSlash(object): def __init__(self): self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) def get(self, host, port): self.socket.connect((host, port)) ssl_sock = socket.ssl(self.socket) ssl_sock.write("GET / HTTP/1.0\n\n") print(ssl_sock.read()) self.socket.close() m2crypto-0.46.2/demo/ssl/ss.py000066400000000000000000000007161506746742300161300ustar00rootroot00000000000000#!/usr/bin/env python import os, popen2, time from socket import * def main0(): cin, cout = popen2.popen2("openssl s_server") cout.write("Q\n") cout.flush() s = socket(AF_INET, SOCK_STREAM) s.connect(("", 4433)) s.close() def main(): pid = os.fork() if pid: time.sleep(1) os.kill(pid, 1) os.waitpid(pid, 0) else: os.execvp("openssl", ("s_server",)) if __name__ == "__main__": main() m2crypto-0.46.2/demo/ssl/twistedsslclient.py000077500000000000000000000022751506746742300211140ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """ Demonstrates M2Crypto.SSL.TwistedProtocolWrapper Copyright (c) 2005 Open Source Applications Foundation. All rights reserved. """ import twisted.internet.protocol as protocol import twisted.protocols.basic as basic import twisted.internet.reactor as reactor import M2Crypto.SSL.TwistedProtocolWrapper as wrapper import M2Crypto.SSL as SSL class EchoClient(basic.LineReceiver): def connectionMade(self): self.sendLine("Hello World!") def lineReceived(self, line): print('received: "%s"' % line) self.transport.loseConnection() class EchoClientFactory(protocol.ClientFactory): protocol = EchoClient def clientConnectionFailed(self, connector, reason): print("connection failed") reactor.stop() def clientConnectionLost(self, connector, reason): print("connection lost") reactor.stop() class ContextFactory: def getContext(self): return SSL.Context() if __name__ == "__main__": factory = EchoClientFactory() wrapper.connectSSL("localhost", 8000, factory, ContextFactory()) reactor.run() # This will block until reactor.stop() is called m2crypto-0.46.2/demo/ssl/twistedsslserver.py000077500000000000000000000016611506746742300211420ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """ Demonstrates M2Crypto.SSL.TwistedProtocolWrapper Copyright (c) 2005 Open Source Applications Foundation. All rights reserved. """ import sys import M2Crypto.SSL as SSL import M2Crypto.SSL.TwistedProtocolWrapper as wrapper import twisted.internet.protocol as protocol import twisted.internet.reactor as reactor import twisted.python.log as log class Echo(protocol.Protocol): def dataReceived(self, data): print('received: "%s"' % data) self.transport.write(data) def connectionMade(self): print("connection made") class ContextFactory: def getContext(self): ctx = SSL.Context() ctx.load_cert("server.pem") return ctx if __name__ == "__main__": log.startLogging(sys.stdout) factory = protocol.Factory() factory.protocol = Echo wrapper.listenSSL(8000, factory, ContextFactory()) reactor.run() m2crypto-0.46.2/demo/ssl/xmlrpc_cli.py000066400000000000000000000013601506746742300176330ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """Demonstration of M2Crypto.xmlrpclib2. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" from M2Crypto import Rand from M2Crypto.m2xmlrpclib import Server, SSL_Transport def ZServerSSL(): # Server is Zope-2.6.4 on ZServerSSL/0.12. zs = Server("https://127.0.0.1:8443/", SSL_Transport()) print(zs.propertyMap()) def xmlrpc_srv(): # Server is ../https/START_xmlrpc.py or ./xmlrpc_srv.py. zs = Server("https://127.0.0.1:39443", SSL_Transport()) print(zs.Testing(1, 2, 3)) print(zs.BringOn("SOAP")) if __name__ == "__main__": Rand.load_file("../randpool.dat", -1) # ZServerSSL() xmlrpc_srv() Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/ssl/xmlrpc_srv.py000066400000000000000000000014341506746742300177000ustar00rootroot00000000000000from __future__ import print_function """Server demonstration of M2Crypto.xmlrpclib2. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" # M2Crypto from M2Crypto import DH, SSL from echod_lib import init_context # /F's xmlrpcserver.py. from xmlrpcserver import RequestHandler class xmlrpc_handler(RequestHandler): def call(self, method, params): print("XMLRPC call:", method, params) return params def finish(self): self.request.set_shutdown(SSL.SSL_RECEIVED_SHUTDOWN | SSL.SSL_SENT_SHUTDOWN) self.request.close() if __name__ == "__main__": ctx = init_context("sslv23", "server.pem", "ca.pem", SSL.verify_none) ctx.set_tmp_dh("dh1024.pem") s = SSL.ThreadingSSLServer(("", 9443), xmlrpc_handler, ctx) s.serve_forever() m2crypto-0.46.2/demo/tinderbox/000077500000000000000000000000001506746742300163225ustar00rootroot00000000000000m2crypto-0.46.2/demo/tinderbox/build_lib.py000066400000000000000000000100441506746742300206200ustar00rootroot00000000000000# Copyright (c) 2006-2007 Open Source Applications Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Trimmed down for M2Crypto build purposes from __future__ import print_function import os, sys import glob import fnmatch import shutil import fileinput import errno import subprocess import killableprocess import tempfile _logFilename = "tbox.log" _logPrefix = "" _logFile = None _logEcho = True _logEchoErrors = False def initLog(filename, prefix="", echo=True, echoErrors=False): """ Initialize log file and store log parameters Note: initLog assumes it is called only once per program """ global _logFilename, _logPrefix, _logFile, _logEcho, _logEchoErrors _logFilename = filename or _logFilename _logEcho = echo _logEchoErrors = echoErrors _logPrefix = prefix try: _logFile = open(_logFilename, "w+") result = True except: result = False return result def closeLog(): """Need to close log to flush all data.""" _logFile.close() def log(msg, error=False, newline="\n"): """ Output log message to an open log file or to StdOut """ echo = _logEcho if _logFile is None: if error or _logEcho: echo = True else: _logFile.write("%s%s%s" % (_logPrefix, msg, newline)) if error and _logEchoErrors: sys.stderr.write("%s%s%s" % (_logPrefix, msg, newline)) if echo: sys.stdout.write("%s%s%s" % (_logPrefix, msg, newline)) sys.stdout.flush() def setpgid_preexec_fn(): os.setpgid(0, 0) def runCommand(cmd, env=None, timeout=-1, logger=log, ignorepreexec=False): """ Execute the given command and log all output Success and failure codes: >>> runCommand(['true']) 0 >>> runCommand(['false']) 1 Interleaved stdout and stderr messages: >>> runCommand(['python', '-c', r'print(1);import sys;sys.stdout.flush();print(2, file=sys.stderr);print(3)']) 1 2 3 0 Now with timeout: >>> runCommand(['python', '-c', r'print(1);import sys;sys.stdout.flush();print(2, file=sys.stderr);print(3)'], timeout=5) 1 2 3 0 Setting environment variable: >>> runCommand(['python', '-c', 'import os;print(os.getenv("ENVTEST")'], env={'ENVTEST': '42'})) 42 0 Timeout: >>> runCommand(['sleep', '60'], timeout=5) -9 """ redirect = True if logger == log and _logFile is None: redirect = False else: if timeout == -1: output = subprocess.PIPE else: output = tempfile.TemporaryFile() if ignorepreexec: preexec_fn = None else: preexec_fn = setpgid_preexec_fn if redirect: p = killableprocess.Popen( cmd, env=env, stdin=subprocess.PIPE, stdout=output, stderr=subprocess.STDOUT, preexec_fn=preexec_fn, ) else: p = killableprocess.Popen( cmd, env=env, stdin=subprocess.PIPE, preexec_fn=preexec_fn ) try: if timeout == -1 and redirect: for line in p.stdout: logger(line[:-1]) p.wait(timeout=timeout, group=True) except KeyboardInterrupt: try: p.kill(group=True) except OSError: p.wait(30) if timeout != -1 and redirect: output.seek(0) for line in output: logger(line[:-1]) return p.returncode m2crypto-0.46.2/demo/tinderbox/killableprocess.py000066400000000000000000000177471506746742300220720ustar00rootroot00000000000000# killableprocess - subprocesses which can be reliably killed # # Parts of this module are copied from the subprocess.py file contained # in the Python distribution. # # Copyright (c) 2003-2004 by Peter Astrand # # Additions and modifications written by Benjamin Smedberg # are Copyright (c) 2006 by the Mozilla Foundation # # # By obtaining, using, and/or copying this software and/or its # associated documentation, you agree that you have read, understood, # and will comply with the following terms and conditions: # # Permission to use, copy, modify, and distribute this software and # its associated documentation for any purpose and without fee is # hereby granted, provided that the above copyright notice appears in # all copies, and that both that copyright notice and this permission # notice appear in supporting documentation, and that the name of the # author not be used in advertising or publicity pertaining to # distribution of the software without specific, written prior # permission. # # THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. r"""killableprocess - Subprocesses which can be reliably killed This module is a subclass of the builtin "subprocess" module. It allows processes that launch subprocesses to be reliably killed on Windows (via the Popen.kill() method. It also adds a timeout argument to Wait() for a limited period of time before forcefully killing the process. Note: On Windows, this module requires Windows 2000 or higher (no support for Windows 95, 98, or NT 4.0). It also requires ctypes, which is bundled with Python 2.5+ or available from http://python.net/crew/theller/ctypes/ """ import subprocess import sys import os import time import types try: from subprocess import CalledProcessError except ImportError: # Python 2.4 doesn't implement CalledProcessError class CalledProcessError(Exception): """This exception is raised when a process run by check_call() returns a non-zero exit status. The exit status will be stored in the returncode attribute.""" def __init__(self, returncode, cmd): self.returncode = returncode self.cmd = cmd def __str__(self): return "Command '%s' returned non-zero exit status %d" % ( self.cmd, self.returncode, ) mswindows = sys.platform == "win32" if mswindows: import winprocess else: import signal def call(*args, **kwargs): waitargs = {} if "timeout" in kwargs: waitargs["timeout"] = kwargs.pop("timeout") return Popen(*args, **kwargs).wait(**waitargs) def check_call(*args, **kwargs): """Call a program with an optional timeout. If the program has a non-zero exit status, raises a CalledProcessError.""" retcode = call(*args, **kwargs) if retcode: cmd = kwargs.get("args") if cmd is None: cmd = args[0] raise CalledProcessError(retcode, cmd) if not mswindows: def DoNothing(*args): pass class Popen(subprocess.Popen): if mswindows: def _execute_child( self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, ): if not isinstance(args, types.StringTypes): args = subprocess.list2cmdline(args) if startupinfo is None: startupinfo = winprocess.STARTUPINFO() if None not in (p2cread, c2pwrite, errwrite): startupinfo.dwFlags |= winprocess.STARTF_USESTDHANDLES startupinfo.hStdInput = int(p2cread) startupinfo.hStdOutput = int(c2pwrite) startupinfo.hStdError = int(errwrite) if shell: startupinfo.dwFlags |= winprocess.STARTF_USESHOWWINDOW startupinfo.wShowWindow = winprocess.SW_HIDE comspec = os.environ.get("COMSPEC", "cmd.exe") args = comspec + " /c " + args # We create a new job for this process, so that we can kill # the process and any sub-processes self._job = winprocess.CreateJobObject() creationflags |= winprocess.CREATE_SUSPENDED creationflags |= winprocess.CREATE_UNICODE_ENVIRONMENT hp, ht, pid, tid = winprocess.CreateProcess( executable, args, None, None, # No special security 1, # Must inherit handles! creationflags, winprocess.EnvironmentBlock(env), cwd, startupinfo, ) self._child_created = True self._handle = hp self._thread = ht self.pid = pid winprocess.AssignProcessToJobObject(self._job, hp) winprocess.ResumeThread(ht) if p2cread is not None: p2cread.Close() if c2pwrite is not None: c2pwrite.Close() if errwrite is not None: errwrite.Close() def kill(self, group=True): """Kill the process. If group=True, all sub-processes will also be killed.""" if mswindows: if group: winprocess.TerminateJobObject(self._job, 127) else: winprocess.TerminateProcess(self._handle, 127) self.returncode = 127 else: if sys.platform == "cygwin": cmd = "taskkill /f /pid " + str(self.pid) if group: cmd += " /t" os.system(cmd) elif group: os.killpg(self.pid, signal.SIGKILL) else: os.kill(self.pid, signal.SIGKILL) self.returncode = -9 def wait(self, timeout=-1, group=True): """Wait for the process to terminate. Returns returncode attribute. If timeout seconds are reached and the process has not terminated, it will be forcefully killed. If timeout is -1, wait will not time out.""" if self.returncode is not None: return self.returncode if mswindows: if timeout != -1: timeout = timeout * 1000 rc = winprocess.WaitForSingleObject(self._handle, timeout) if rc == winprocess.WAIT_TIMEOUT: self.kill(group) else: self.returncode = winprocess.GetExitCodeProcess(self._handle) else: if timeout == -1: subprocess.Popen.wait(self) return self.returncode starttime = time.time() # Make sure there is a signal handler for SIGCHLD installed oldsignal = signal.signal(signal.SIGCHLD, DoNothing) while time.time() < starttime + timeout - 0.01: pid, sts = os.waitpid(self.pid, os.WNOHANG) if pid != 0: self._handle_exitstatus(sts) signal.signal(signal.SIGCHLD, oldsignal) return self.returncode # time.sleep is interrupted by signals (good!) newtimeout = timeout - time.time() + starttime time.sleep(newtimeout) self.kill(group) signal.signal(signal.SIGCHLD, oldsignal) subprocess.Popen.wait(self) return self.returncode m2crypto-0.46.2/demo/tinderbox/slave.py000077500000000000000000000115131506746742300200120ustar00rootroot00000000000000#!/usr/bin/env python # """ This is a sample Tinderbox2 buildslave script. NOTE: WAIT at least 6 minutes after the last build before starting the next build! Create config.ini file with the following contents: [build] name = identify your build slave, for example Ubuntu 8.04 32-bit ;;optional fields: ;;uname = uname -a ;;swig = swig -version ;;cc = gcc --version ;;openssl = openssl version ;;python = python --version ;;clean = rm -fr m2crypto ;;svn = svn co http://svn.osafoundation.org/m2crypto/trunk m2crypto ;;patch = ;;build = python setup.py clean --all build ;; OR another way to do tests without setuptools: ;;build = PYTHONPATH=build/lib-something python tests/alltests.py ;;test = python setup.py test ;;wait = 3600 ;;timeout = 180 [email] from = your email to = Email Heikki Toivonen to get the address user = smtp username password = smtp password server = smtp server port = smtp port """ import time, smtplib, os, ConfigParser, tempfile import build_lib as bl # Change to True when you are troubleshooting this build script debug_script = False # These commands assume we are running on a unix-like system where default # build options work and all prerequisites are installed and in PATH etc. DEFAULT_COMMANDS = { "uname": ["uname", "-a"], "swig": ["swig", "-version"], "cc": ["gcc", "--version"], "openssl": ["openssl", "version"], "python": ["python", "--version"], "clean": ["rm", "-rf", "m2crypto"], "svn": ["svn", "co", "http://svn.osafoundation.org/m2crypto/trunk", "m2crypto"], "patch": [], "build": ["python", "setup.py", "clean", "--all", "build"], "test": ["python", "setup.py", "test"], } def load_config(cfg="config.ini"): config = {} cp = ConfigParser.ConfigParser() cp.read(cfg) for section in cp.sections(): for option in cp.options(section): config[option] = cp.get(section, option).strip() return config # XXX copied from test_ssl def zap_servers(): s = "s_server" fn = tempfile.mktemp() cmd = "ps | egrep %s > %s" % (s, fn) os.system(cmd) f = open(fn) while 1: ps = f.readline() if not ps: break chunk = string.split(ps) pid, cmd = chunk[0], chunk[4] if cmd == s: os.kill(int(pid), 1) f.close() os.unlink(fn) def build(commands, config): status = "success" cwd = os.getcwd() timeout = int(config.get("timeout") or 180) bl.initLog("tbox.log", echo=debug_script) starttime = int(time.time()) for command in commands: cmd = config.get(command) if not cmd: cmd = DEFAULT_COMMANDS[command] if not cmd: continue else: cmd = cmd.split() bl.log("*** %s, timeout=%ds" % (" ".join(cmd), timeout)) exit_code = bl.runCommand(cmd, timeout=timeout) if exit_code: bl.log("*** error exit code = %d" % exit_code) if command == "test": status = "test_failed" if os.name != "nt": try: # If tests were killed due to timeout, we may have left # openssl processes running, so try killing zap_servers() except Exception as e: bl.log("*** error: tried to zap_servers: " + str(e)) else: status = "build_failed" break if command == "svn": os.chdir("m2crypto") timenow = int(time.time()) bl.closeLog() os.chdir(cwd) return "tbox.log", starttime, timenow, status def email(logpath, starttime, timenow, status, config): msg = """From: %(from)s To: %(to)s Subject: tree: M2Crypto tinderbox: tree: M2Crypto tinderbox: starttime: %(starttime)d tinderbox: timenow: %(timenow)d tinderbox: status: %(status)s tinderbox: buildname: %(buildname)s tinderbox: errorparser: unix tinderbox: END """ % { "from": config["from"], "to": config["to"], "starttime": starttime, "timenow": timenow, "status": status, "buildname": config["name"], } msg += open(logpath).read() server = smtplib.SMTP(host=config["server"], port=int(config["port"])) if debug_script: server.set_debuglevel(1) server.starttls() # if your server supports STARTTLS if config.get("user"): server.login(config["user"], config["password"]) server.sendmail(config["from"], config["to"], msg) server.quit() if __name__ == "__main__": config = load_config() commands = [ "uname", "swig", "cc", "openssl", "python", "clean", "svn", "patch", "build", "test", ] logpath, starttime, timenow, status = build(commands, config) email(logpath, starttime, timenow, status, config) m2crypto-0.46.2/demo/tinderbox/winprocess.py000066400000000000000000000173121506746742300210740ustar00rootroot00000000000000# A module to expose various thread/process/job related structures and # methods from kernel32 # # The MIT License # # Copyright (c) 2006 the Mozilla Foundation # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from ctypes import c_void_p, POINTER, sizeof, Structure, windll, WinError, WINFUNCTYPE from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LPCWSTR, LPWSTR, UINT, WORD LPVOID = c_void_p LPBYTE = POINTER(BYTE) LPDWORD = POINTER(DWORD) def ErrCheckBool(result, func, args): """errcheck function for Windows functions that return a BOOL True on success""" if not result: raise WinError() return args # CloseHandle() CloseHandleProto = WINFUNCTYPE(BOOL, HANDLE) CloseHandle = CloseHandleProto(("CloseHandle", windll.kernel32)) CloseHandle.errcheck = ErrCheckBool # AutoHANDLE class AutoHANDLE(HANDLE): """Subclass of HANDLE which will call CloseHandle() on deletion.""" def Close(self): if self.value: CloseHandle(self) self.value = 0 def __del__(self): self.Close() def __int__(self): return self.value def ErrCheckHandle(result, func, args): """errcheck function for Windows functions that return a HANDLE.""" if not result: raise WinError() return AutoHANDLE(result) # PROCESS_INFORMATION structure class PROCESS_INFORMATION(Structure): _fields_ = [ ("hProcess", HANDLE), ("hThread", HANDLE), ("dwProcessID", DWORD), ("dwThreadID", DWORD), ] def __init__(self): Structure.__init__(self) self.cb = sizeof(self) LPPROCESS_INFORMATION = POINTER(PROCESS_INFORMATION) # STARTUPINFO structure class STARTUPINFO(Structure): _fields_ = [ ("cb", DWORD), ("lpReserved", LPWSTR), ("lpDesktop", LPWSTR), ("lpTitle", LPWSTR), ("dwX", DWORD), ("dwY", DWORD), ("dwXSize", DWORD), ("dwYSize", DWORD), ("dwXCountChars", DWORD), ("dwYCountChars", DWORD), ("dwFillAttribute", DWORD), ("dwFlags", DWORD), ("wShowWindow", WORD), ("cbReserved2", WORD), ("lpReserved2", LPBYTE), ("hStdInput", HANDLE), ("hStdOutput", HANDLE), ("hStdError", HANDLE), ] LPSTARTUPINFO = POINTER(STARTUPINFO) STARTF_USESHOWWINDOW = 0x01 STARTF_USESIZE = 0x02 STARTF_USEPOSITION = 0x04 STARTF_USECOUNTCHARS = 0x08 STARTF_USEFILLATTRIBUTE = 0x10 STARTF_RUNFULLSCREEN = 0x20 STARTF_FORCEONFEEDBACK = 0x40 STARTF_FORCEOFFFEEDBACK = 0x80 STARTF_USESTDHANDLES = 0x100 # EnvironmentBlock class EnvironmentBlock: """An object which can be passed as the lpEnv parameter of CreateProcess. It is initialized with a dictionary.""" def __init__(self, dict): if not dict: self._as_parameter_ = None else: values = ["%s=%s" % (key, value) for (key, value) in dict.iteritems()] values.append("") self._as_parameter_ = LPCWSTR("\0".join(values)) # CreateProcess() CreateProcessProto = WINFUNCTYPE( BOOL, # Return type LPCWSTR, # lpApplicationName LPWSTR, # lpCommandLine LPVOID, # lpProcessAttributes LPVOID, # lpThreadAttributes BOOL, # bInheritHandles DWORD, # dwCreationFlags LPVOID, # lpEnvironment LPCWSTR, # lpCurrentDirectory LPSTARTUPINFO, # lpStartupInfo LPPROCESS_INFORMATION, # lpProcessInformation ) CreateProcessFlags = ( (1, "lpApplicationName", None), (1, "lpCommandLine"), (1, "lpProcessAttributes", None), (1, "lpThreadAttributes", None), (1, "bInheritHandles", True), (1, "dwCreationFlags", 0), (1, "lpEnvironment", None), (1, "lpCurrentDirectory", None), (1, "lpStartupInfo"), (2, "lpProcessInformation"), ) def ErrCheckCreateProcess(result, func, args): ErrCheckBool(result, func, args) # return a tuple (hProcess, hThread, dwProcessID, dwThreadID) pi = args[9] return ( AutoHANDLE(pi.hProcess), AutoHANDLE(pi.hThread), pi.dwProcessID, pi.dwThreadID, ) CreateProcess = CreateProcessProto( ("CreateProcessW", windll.kernel32), CreateProcessFlags ) CreateProcess.errcheck = ErrCheckCreateProcess CREATE_BREAKAWAY_FROM_JOB = 0x01000000 CREATE_DEFAULT_ERROR_MODE = 0x04000000 CREATE_NEW_CONSOLE = 0x00000010 CREATE_NEW_PROCESS_GROUP = 0x00000200 CREATE_NO_WINDOW = 0x08000000 CREATE_SUSPENDED = 0x00000004 CREATE_UNICODE_ENVIRONMENT = 0x00000400 DEBUG_ONLY_THIS_PROCESS = 0x00000002 DEBUG_PROCESS = 0x00000001 DETACHED_PROCESS = 0x00000008 # CreateJobObject() CreateJobObjectProto = WINFUNCTYPE( HANDLE, LPVOID, LPCWSTR # Return type # lpJobAttributes # lpName ) CreateJobObjectFlags = ((1, "lpJobAttributes", None), (1, "lpName", None)) CreateJobObject = CreateJobObjectProto( ("CreateJobObjectW", windll.kernel32), CreateJobObjectFlags ) CreateJobObject.errcheck = ErrCheckHandle # AssignProcessToJobObject() AssignProcessToJobObjectProto = WINFUNCTYPE( BOOL, HANDLE, HANDLE # Return type # hJob # hProcess ) AssignProcessToJobObjectFlags = ((1, "hJob"), (1, "hProcess")) AssignProcessToJobObject = AssignProcessToJobObjectProto( ("AssignProcessToJobObject", windll.kernel32), AssignProcessToJobObjectFlags ) AssignProcessToJobObject.errcheck = ErrCheckBool # ResumeThread() def ErrCheckResumeThread(result, func, args): if result == -1: raise WinError() return args ResumeThreadProto = WINFUNCTYPE(DWORD, HANDLE) # Return type # hThread ResumeThreadFlags = ((1, "hThread"),) ResumeThread = ResumeThreadProto(("ResumeThread", windll.kernel32), ResumeThreadFlags) ResumeThread.errcheck = ErrCheckResumeThread # TerminateJobObject() TerminateJobObjectProto = WINFUNCTYPE( BOOL, HANDLE, UINT # Return type # hJob # uExitCode ) TerminateJobObjectFlags = ((1, "hJob"), (1, "uExitCode", 127)) TerminateJobObject = TerminateJobObjectProto( ("TerminateJobObject", windll.kernel32), TerminateJobObjectFlags ) TerminateJobObject.errcheck = ErrCheckBool # WaitForSingleObject() WaitForSingleObjectProto = WINFUNCTYPE( DWORD, # Return type HANDLE, # hHandle DWORD, # dwMilliseconds ) WaitForSingleObjectFlags = ((1, "hHandle"), (1, "dwMilliseconds", -1)) WaitForSingleObject = WaitForSingleObjectProto( ("WaitForSingleObject", windll.kernel32), WaitForSingleObjectFlags ) INFINITE = -1 WAIT_TIMEOUT = 0x0102 WAIT_OBJECT_0 = 0x0 WAIT_ABANDONED = 0x0080 # GetExitCodeProcess() GetExitCodeProcessProto = WINFUNCTYPE( BOOL, # Return type HANDLE, # hProcess LPDWORD, # lpExitCode ) GetExitCodeProcessFlags = ((1, "hProcess"), (2, "lpExitCode")) GetExitCodeProcess = GetExitCodeProcessProto( ("GetExitCodeProcess", windll.kernel32), GetExitCodeProcessFlags ) GetExitCodeProcess.errcheck = ErrCheckBool m2crypto-0.46.2/demo/x509/000077500000000000000000000000001506746742300150315ustar00rootroot00000000000000m2crypto-0.46.2/demo/x509/ca.py000066400000000000000000000062661506746742300160000ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """ How to create a CA certificate with Python. WARNING: This sample only demonstrates how to use the objects and methods, not how to create a safe and correct certificate. Copyright (c) 2004 Open Source Applications Foundation. Author: Heikki Toivonen """ from M2Crypto import RSA, X509, EVP, m2, Rand, Err # XXX Do I actually need more keys? # XXX Check return values from functions def generateRSAKey(): return RSA.gen_key(2048, m2.RSA_F4) def makePKey(key): pkey = EVP.PKey() pkey.assign_rsa(key) return pkey def makeRequest(pkey): req = X509.Request() req.set_version(2) req.set_pubkey(pkey) name = X509.X509_Name() name.CN = "My CA, Inc." req.set_subject_name(name) 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) assert extstack[1].get_name() == "nsComment" req.add_extensions(extstack) req.sign(pkey, "sha1") return req def makeCert(req, caPkey): pkey = req.get_pubkey() # woop = makePKey(generateRSAKey()) # if not req.verify(woop.pkey): if not req.verify(pkey): # XXX What error object should I use? raise ValueError("Error verifying request") sub = req.get_subject() # If this were a real certificate request, you would display # all the relevant data from the request and ask a human operator # if you were sure. Now we just create the certificate blindly based # on the request. cert = X509.X509() # We know we are making CA cert now... # Serial defaults to 0. cert.set_serial_number(1) cert.set_version(2) cert.set_subject(sub) 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) notBefore = m2.x509_get_not_before(cert.x509) notAfter = m2.x509_get_not_after(cert.x509) m2.x509_gmtime_adj(notBefore, 0) days = 30 m2.x509_gmtime_adj(notAfter, 60 * 60 * 24 * days) cert.add_ext(X509.new_extension("subjectAltName", "DNS:foobar.example.com")) ext = X509.new_extension("nsComment", "M2Crypto generated certificate") ext.set_critical(0) # Defaults to non-critical, but we can also set it cert.add_ext(ext) cert.sign(caPkey, "sha1") assert cert.get_ext("subjectAltName").get_name() == "subjectAltName" assert cert.get_ext_at(0).get_name() == "subjectAltName" assert cert.get_ext_at(0).get_value() == "DNS:foobar.example.com" return cert def ca(): key = generateRSAKey() pkey = makePKey(key) req = makeRequest(pkey) cert = makeCert(req, pkey) return (cert, pkey) if __name__ == "__main__": Rand.load_file("../randpool.dat", -1) rsa = generateRSAKey() pkey = makePKey(rsa) req = makeRequest(pkey) print(req.as_text()) cert = makeCert(req, pkey) print(cert.as_text()) print(cert.as_pem()) cert.save_pem("my_ca_cert.pem") rsa.save_key("my_key.pem", "aes_256_cbc") Rand.save_file("../randpool.dat") m2crypto-0.46.2/demo/x509/certdata2pem.py000077500000000000000000000032471506746742300177670ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """ Small utility to convert the Mozilla-format certificates (/mozilla/security/nss/lib/ckfw/builtins/certdata.txt in the Mozilla CVS) into PEM. Got the idea from http://curl.haxx.se/docs/parse-certs.txt. Copyright (c) 2007 Open Source Applications Foundation. """ import array from M2Crypto import X509 counter = 0 value = None name = None out = open("cacert.pem", "wb") for line in open("certdata.txt"): line = line.strip() if line.startswith("CKA_LABEL"): assert value is None label_encoding, name, dummy = line.split('"') label, encoding = label_encoding.split() assert encoding == "UTF8" elif line == "CKA_VALUE MULTILINE_OCTAL": assert name is not None value = array.array("c") elif value is not None and line == "END": assert name is not None print("Writing " + name) x509 = X509.load_cert_string(value.tostring(), X509.FORMAT_DER) if not x509.verify(): print(" Skipping " + name + " since it does not verify") name = None value = None continue counter += 1 out.write(name + "\n" + "=" * len(name) + "\n\n") out.write("SHA1 Fingerprint=" + x509.get_fingerprint("sha1") + "\n") out.write(x509.as_text()) out.write(x509.as_pem()) out.write("\n") name = None value = None elif value is not None: assert name is not None for number in line.split("\\"): if not number: continue value.append(chr(int(number, 8))) print("Wrote %d certificates" % counter) m2crypto-0.46.2/demo/x509/client2.pem000066400000000000000000000040201506746742300170700ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDDjCCAnegAwIBAgIBAzANBgkqhkiG9w0BAQQFADB7MQswCQYDVQQGEwJTRzER MA8GA1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQD ExtNMkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5n cHNAcG9zdDEuY29tMB4XDTAwMTEyMDEzMDMwNVoXDTAyMTEyMDEzMDMwNVowWzEL MAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRowGAYDVQQDExFNMkNyeXB0 byBDbGllbnQgMjEdMBsGCSqGSIb3DQEJARYObmdwc0Bwb3N0MS5jb20wXDANBgkq hkiG9w0BAQEFAANLADBIAkEAn9qneRYTKPokme3obiJa2NTz1Z2kcF3NHVh60Qod /TV/q4olPrZdFR2TDWt63Lgnygcsgf3u9pnhcEGk6IvntwIDAQABo4IBBDCCAQAw CQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2Vy dGlmaWNhdGUwHQYDVR0OBBYEFDKWFe6VWMhtRTE3/78+hAnSGxmvMIGlBgNVHSME gZ0wgZqAFPuHI2nrnDqTFeXFvylRT/7tKDgBoX+kfTB7MQswCQYDVQQGEwJTRzER MA8GA1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQD ExtNMkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5n cHNAcG9zdDEuY29tggEAMA0GCSqGSIb3DQEBBAUAA4GBABpE9xt1Hlq2dQZUXHuX HI57vc2mlWnhhM0wnNhsNZFwfXRHCZOo/JJBhEIT3Rgyz0ErrbOr1SN96HNDKXOD z6bh4NxB5DZ9sRPKEBj66zDsWJVMlom+Lkeal+GkVy36vpAyP1r+cTXyc9M2Gw/o FBMinMHH/BXvF5GJ+UleheZe -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIBOgIBAAJBAJ/ap3kWEyj6JJnt6G4iWtjU89WdpHBdzR1YetEKHf01f6uKJT62 XRUdkw1rety4J8oHLIH97vaZ4XBBpOiL57cCAwEAAQJANXfspprUo9MvpPEn2pbR Lk/kk2IcW510e0laI0uwBj50djfHqvsU5ccuVLrxowngLGrFmM3G4lnMknR2NvH8 0QIhAMsK0AwStUNM/KyvIMikHHBOE9PrK7ARgKvlKl+0ieWPAiEAyYwonIVAtr1f M8vmrc6TM2YxzSq4+jyYktaaNhYw11kCIA5pmhMBUPSSBm2LkNwtKgeewzGLw/If i+6nubZJbnBpAiEAvJQvy4PCsTkvQr+d7zJB+O2920IGId1gxMOXNtQ8jsECIGvn Uz54oonshmTg+Kj2DxnUKQEzFAmQLbtFslp1m47v -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE REQUEST----- MIIBFTCBwAIBADBbMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xGjAY BgNVBAMTEU0yQ3J5cHRvIENsaWVudCAyMR0wGwYJKoZIhvcNAQkBFg5uZ3BzQHBv c3QxLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCf2qd5FhMo+iSZ7ehuIlrY 1PPVnaRwXc0dWHrRCh39NX+riiU+tl0VHZMNa3rcuCfKByyB/e72meFwQaToi+e3 AgMBAAGgADANBgkqhkiG9w0BAQQFAANBAHI5KXfL6kIRoNjR8G9/uKiPUt4uVBKF ecGp87M5t2a92Z0KpWOMXSHZ0LLQKqwWzALvWcPPIj6S8F6ENdwpfMk= -----END CERTIFICATE REQUEST----- m2crypto-0.46.2/demo/x509/demo1.py000066400000000000000000000030761506746742300164160ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function """X.509 certificate manipulation and such. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" import os from M2Crypto import X509 from M2Crypto.EVP import MessageDigest def demo1(): print("Test 1: As DER...") cert1 = X509.load_cert("server.pem") der1 = cert1.as_der() dgst1 = MessageDigest("sha1") dgst1.update(der1) print("Using M2Crypto:\n", repr(dgst1.final()), "\n") cert2 = os.popen("openssl x509 -inform pem -outform der -in server.pem") der2 = cert2.read() dgst2 = MessageDigest("sha1") dgst2.update(der2) print("Openssl command line:\n", repr(dgst2.final()), "\n") def demo2(): print("Test 2: As text...") cert = X509.load_cert("client2.pem") print("version ", cert.get_version()) print("serial# ", cert.get_serial_number()) print("not before ", cert.get_not_before()) print("not after ", cert.get_not_after()) issuer = cert.get_issuer() # print('issuer ', issuer) print("issuer.C ", repr(issuer.C)) print("issuer.SP ", repr(issuer.SP)) print("issuer.L ", repr(issuer.L)) print("issuer.O ", repr(issuer.O)) print("issuer.OU ", repr(issuer.OU)) print("issuer.CN ", repr(issuer.CN)) print("issuer.Email", repr(issuer.Email)) print("subject ", cert.get_subject()) # print(cert.as_text(), '\n') def demo3(): cert = X509.load_cert("server.pem") while 1: x = cert.get_subject() if __name__ == "__main__": # demo1() demo2() # demo3() m2crypto-0.46.2/demo/x509/proxy_destroy.py000066400000000000000000000022021506746742300203310ustar00rootroot00000000000000#!/usr/bin/env python ############################################################################ # Matt Rodriguez, LBNL MKRodriguez@lbl.gov ############################################################################ """ Script that destroys a proxy certificate file by overwriting its contents before the file is removed """ import proxylib import optparse, os USAGEHELP = "proxy_destroy.py file1 file2 Destroys files listed" JUNK = "LalalAlalaLalalALalalAlalaLalalALalalAlalaLalalALalalAlalaLalalA" def scrub_file(filename): """ Overwrite the file with junk, before removing it """ s = os.stat(filename) proxy_file = file(filename, "w") size = s.st_size while size > 64: proxy_file.write(JUNK) size -= 64 proxy_file.flush() proxy_file.close() os.remove(filename) def main(): parser = optparse.OptionParser() parser.set_usage(USAGEHELP) opts, args = parser.parse_args() if len(args) is 0: proxy_file = proxylib.get_proxy_filename() scrub_file(proxy_file) for proxy_file in args: scrub_file(proxy_file) if __name__ == "__main__": main() m2crypto-0.46.2/demo/x509/proxy_info.py000066400000000000000000000037041506746742300176030ustar00rootroot00000000000000#!/usr/bin/env python ############################################################################ # Matt Rodriguez, LBNL MKRodriguez@lbl.gov ############################################################################ from __future__ import print_function """ script that displays information about a proxy certificate """ import proxylib import time, datetime, calendar import sys, optparse FILEHELP = "Location of the proxy." def print_info(proxy_cert): """ Print information about the proxy cert """ cert = proxy_cert.getcert() print("Subject: ", cert.get_subject().as_text()) print("Issuer: ", cert.get_issuer().as_text()) pubkey = cert.get_pubkey() size = pubkey.size() print("Strength: ", size * 8) after = cert.get_not_after() after_tuple = time.strptime(str(after), "%b %d %H:%M:%S %Y %Z") expires = calendar.timegm(after_tuple) now = datetime.timedelta(seconds=time.time()) expires = datetime.timedelta(seconds=expires) td = expires - now if td.days < 0: print("Time left: Proxy has expired.") else: hours = td.seconds / 3600 hours += td.days * 24 minutes = (td.seconds % 3600) / 60 seconds = (td.seconds % 3600) % 60 print("Time left: %d:%d:%d" % (hours, minutes, seconds)) fraction = round((float(td.seconds) / float(3600 * 24)), 1) print("Days left: ", str(td.days) + str(fraction)[1:]) def main(): parser = optparse.OptionParser() parser.add_option("-f", "--file", dest="filename", help=FILEHELP) (opts, args) = parser.parse_args() filename = opts.filename if filename is None: proxyfile = proxylib.get_proxy_filename() else: proxyfile = filename proxy_cert = proxylib.Proxy() try: proxy_cert.read(proxyfile) except IOError: print("The file: " + proxyfile + " does not exist.") sys.exit(0) print_info(proxy_cert) if __name__ == "__main__": main() m2crypto-0.46.2/demo/x509/proxy_init.py000066400000000000000000000034171506746742300176140ustar00rootroot00000000000000#!/usr/bin/env python ############################################################################ # Matt Rodriguez, LBNL MKRodriguez@lbl.gov ############################################################################ from __future__ import print_function """ script that generates a proxy certificate """ import proxylib import optparse import sys OUTHELP = "Location of the new proxy cert." CERTHELP = "Location of user certificate." KEYHELP = "Location of the user key." VALIDHELP = "h:m Proxy certificate is valid for h hours and m minutes." FULLPROXY = "Creates a limited proxy" def main(): parser = optparse.OptionParser() parser.add_option("-o", "--output", dest="output", help=OUTHELP) parser.add_option("-c", "--cert", dest="cert", help=CERTHELP) parser.add_option("-k", "--key", dest="key", help=KEYHELP) parser.add_option("-v", "--valid", dest="valid", help=VALIDHELP) parser.add_option( "-l", "--limited", action="store_true", default=False, dest="limited", help=VALIDHELP, ) (opts, args) = parser.parse_args() kw = {} kw["cert"] = opts.cert kw["key"] = opts.key if opts.valid is None: valid_tuple = (12, 0) else: valid = opts.valid.split(":") valid_tuple = tuple(map(int, valid)) kw["valid"] = valid_tuple kw["full"] = not opts.limited try: proxy_factory = proxylib.ProxyFactory(kw) except IOError: print("Can't find usercert or userkey. Use the -c or -k arguments") sys.exit(0) proxy_factory.generate() proxy_cert = proxy_factory.getproxy() if opts.output is None: proxy_cert.write(proxylib.get_proxy_filename()) else: proxy_cert.write(opts.output) if __name__ == "__main__": main() m2crypto-0.46.2/demo/x509/proxylib.py000066400000000000000000000244701506746742300172620ustar00rootroot00000000000000############################################################################ # Matt Rodriguez, LBNL # Copyright (c) 2003, The Regents of the University of California, # through Lawrence Berkeley National Laboratory # (subject to receipt of any required approvals from the U.S. Dept. of Energy). # All rights reserved. ############################################################################ from __future__ import print_function """ API to generated proxy certificates """ import os, sys import struct import re import time, calendar, datetime import_regex = re.compile(r"\s*libssl.so.0.9.8\s*") errstr = "You must have the openssl 0.9.8 libraries in your LD_LIBRARY_PATH" "" try: from M2Crypto import BIO, X509, RSA, EVP, ASN1 except ImportError as ex: if import_regex.match(str(ex)): print(errstr) sys.exit(-1) else: raise ex MBSTRING_FLAG = 0x1000 MBSTRING_ASC = MBSTRING_FLAG | 1 KEY_USAGE_VALUE = "Digital Signature, Key Encipherment, Data Encipherment" PCI_VALUE_FULL = "critical, language:Inherit all" PCI_VALUE_LIMITED = "critical, language:1.3.6.1.4.1.3536.1.1.1.9" def create_write_file(fname, perm=0o600): """ Creates a file to write to while avoiding a possible race condition. This is essential for writing out the proxy file. Need to make sure there is no pre-existing file. """ if os.path.exists(fname): os.remove(fname) # Make sure the file doesn't exist. Will throw an exception if # it does. This would only happen if the code is attacked. fd = os.open(fname, os.O_CREAT | os.O_EXCL | os.O_WRONLY, perm) f = os.fdopen(fd, "w") return f class ProxyFactoryException(Exception): """ Base class for exceptions in the ProxyFactory class """ class Proxy: """ class that holds proxy certificate information, consisting of an issuer cert a user cert and a key for the user cert """ def __init__(self): self._key = None self._cert = None self._issuer = None def read(self, proxypath=None): """ reads in a proxy certificate information """ if proxypath is None: proxypath = get_proxy_filename() proxyfile = open(proxypath) bio = BIO.File(proxyfile) self._cert = X509.load_cert_bio(bio) self._key = RSA.load_key_bio(bio) self._issuer = X509.load_cert_bio(bio) def getcert(self): """ Returns a X509 instance """ return self._cert def getkey(self): """ Returns a RSA instance """ return self._key def getissuer(self): """ Returns a X509 instance """ return self._issuer def setcert(self, cert): """ Sets the user cert should be a X509 instance """ self._cert = cert def setkey(self, key): """ Sets the user key should be a RSA instance """ self._key = key def setissuer(self, issuer): """ Sets the issuer cert should be a X509 instance """ self._issuer = issuer def write(self, proxypath=None): """ Writes the proxy information to a file """ proxyfile = create_write_file(proxypath) bio = BIO.File(proxyfile) bio.write(self._cert.as_pem()) self._key.save_key_bio(bio, cipher=None) bio.write(self._issuer.as_pem()) bio.close() os.chmod(proxypath, 0o600) class ProxyFactory: """ Creates proxies """ def __init__(self, kw={"cert": None, "key": None, "valid": (12, 0), "full": True}): self._usercert = get_usercert(kw["cert"]) self._userkey = get_userkey(kw["key"]) self._proxycert = None self._proxykey = None self._valid = kw["valid"] self._full = kw["full"] def generate(self): """ generates a new proxy like grid-proxy-init """ if not self._check_valid(): raise ProxyFactoryException("The issuer cert is expired") if self._proxycert is None: self._proxycert = X509.X509() key = EVP.PKey() self._proxykey = RSA.gen_key(512, 65537) key.assign_rsa(self._proxykey, capture=0) self._proxycert.set_pubkey(key) self._proxycert.set_version(2) self._set_times() issuer_name = self._usercert.get_subject() self._proxycert.set_issuer_name(issuer_name) serial_number = self._make_serial_number(self._proxycert) self._proxycert.set_serial_number(serial_number) self._set_subject() sign_pk = EVP.PKey() sign_pk.assign_rsa(self._userkey) self._add_extensions() self._proxycert.sign(sign_pk, "md5") def set_proxycert(self, proxycert): """ This method is useful if you don't want to pay the costs associated with generating a new key pair. """ self._proxycert = proxycert def getproxy(self): """ Return a proxy instance """ proxy = Proxy() proxy.setissuer(self._usercert) proxy.setcert(self._proxycert) proxy.setkey(self._proxykey) return proxy def _set_subject(self): """ Internal method that sets the subject name """ subject_name = X509.X509_Name() serial_number = self._make_serial_number(self._proxycert) issuer_name = self._usercert.get_subject() issuer_name_txt = issuer_name.as_text() seq = issuer_name_txt.split(",") for entry in seq: name_component = entry.split("=") subject_name.add_entry_by_txt( field=name_component[0].strip(), type=MBSTRING_ASC, entry=name_component[1], len=-1, loc=-1, set=0, ) subject_name.add_entry_by_txt( field="CN", type=MBSTRING_ASC, entry=str(serial_number), len=-1, loc=-1, set=0, ) self._proxycert.set_subject_name(subject_name) def _set_times(self): """ Internal function that sets the time on the proxy certificate """ not_before = ASN1.ASN1_UTCTIME() not_after = ASN1.ASN1_UTCTIME() not_before.set_time(int(time.time())) offset = (self._valid[0] * 3600) + (self._valid[1] * 60) not_after.set_time(int(time.time()) + offset) self._proxycert.set_not_before(not_before) self._proxycert.set_not_after(not_after) def _make_serial_number(self, cert): """ Lifted from the globus code """ message_digest = EVP.MessageDigest("sha1") pubkey = cert.get_pubkey() der_encoding = pubkey.as_der() message_digest.update(der_encoding) digest = message_digest.final() digest_tuple = struct.unpack("BBBB", digest[:4]) sub_hash = long( digest_tuple[0] + (digest_tuple[1] + (digest_tuple[2] + (digest_tuple[3] >> 1) * 256) * 256) * 256 ) return sub_hash def _add_extensions(self): """ Internal method that adds the extensions to the certificate """ key_usage_ext = X509.new_extension("keyUsage", KEY_USAGE_VALUE, 1) self._proxycert.add_ext(key_usage_ext) if self._full: pci_ext = X509.new_extension("proxyCertInfo", PCI_VALUE_FULL, 1, 0) else: pci_ext = X509.new_extension("proxyCertInfo", PCI_VALUE_LIMITED, 1, 0) self._proxycert.add_ext(pci_ext) def _check_valid(self): """ Internal method that ensures the issuer cert has valid, not_before and not_after fields """ before_time = self._usercert.get_not_before() after_time = self._usercert.get_not_after() before_tuple = time.strptime(str(before_time), "%b %d %H:%M:%S %Y %Z") after_tuple = time.strptime(str(after_time), "%b %d %H:%M:%S %Y %Z") starts = datetime.timedelta(seconds=calendar.timegm(before_tuple)) expires = datetime.timedelta(seconds=calendar.timegm(after_tuple)) now = datetime.timedelta(seconds=time.time()) time_delta = expires - now # cert has expired if time_delta.days < 0: return False # cert is not yet valid, not likely but should still return False time_delta = now - starts if time_delta.days < 0: return False return True # Utility Functions def get_proxy_filename(): """ function that returns the default proxy path which is /tmp/x509up_uuid """ if os.name == "posix": proxy_filename = "x509up_u" + (str(os.getuid())) proxypath = os.path.join("/tmp", proxy_filename) elif os.name == "nt": username = os.getenv("USERNAME") if username is None: raise RuntimeError( """USERNAME is not set in environment. Can't determine proxy file location""" ) proxy_filename = "x509up_u" + username drive = os.path.splitdrive(os.getcwd())[0] proxydir = drive + os.sep + "temp" proxypath = os.path.join(proxydir, proxy_filename) else: except_string = """get_proxy_filename is not supported on this platform Try explicitly specifying the location of the proxyfile""" raise RuntimeError(except_string) return proxypath def get_usercert(certfile=None): """ function that returns a X509 instance which is the user cert that is expected to be a ~/.globus/usercert.pem A check is performed to ensure the certificate has valid before and after times. """ if certfile is None: certfile = open(os.path.join(os.getenv("HOME"), ".globus", "usercert.pem")) else: certfile = open(certfile) bio = BIO.File(certfile) cert = X509.load_cert_bio(bio) return cert def get_userkey(keyfile=None): """ function that returns a X509 instance which is the user cert that is expected to be a ~/.globus/userkey.pem """ if keyfile is None: keyfile = open(os.path.join(os.getenv("HOME"), ".globus", "userkey.pem")) else: keyfile = open(keyfile) bio = BIO.File(keyfile) key = RSA.load_key_bio(bio) return key m2crypto-0.46.2/demo/x509/server-expired.pem000066400000000000000000000040001506746742300204720ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDBjCCAm+gAwIBAgIBATANBgkqhkiG9w0BAQQFADB7MQswCQYDVQQGEwJTRzER MA8GA1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQD ExtNMkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5n cHNAcG9zdDEuY29tMB4XDTAwMDkxMDA5NTEzMFoXDTAyMDkxMDA5NTEzMFowUzEL MAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwlsb2NhbGhv c3QxHTAbBgkqhkiG9w0BCQEWDm5ncHNAcG9zdDEuY29tMFwwDQYJKoZIhvcNAQEB BQADSwAwSAJBAKy+e3dulvXzV7zoTZWc5TzgApr8DmeQHTYC8ydfzH7EECe4R1Xh 5kwIzOuuFfn178FBiS84gngaNcrFi0Z5fAkCAwEAAaOCAQQwggEAMAkGA1UdEwQC MAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRl MB0GA1UdDgQWBBTPhIKSvnsmYsBVNWjj0m3M2z0qVTCBpQYDVR0jBIGdMIGagBT7 hyNp65w6kxXlxb8pUU/+7Sg4AaF/pH0wezELMAkGA1UEBhMCU0cxETAPBgNVBAoT CE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlw dG8gQ2VydGlmaWNhdGUgTWFzdGVyMR0wGwYJKoZIhvcNAQkBFg5uZ3BzQHBvc3Qx LmNvbYIBADANBgkqhkiG9w0BAQQFAAOBgQA7/CqT6PoHycTdhEStWNZde7M/2Yc6 BoJuVwnW8YxGO8Sn6UJ4FeffZNcYZddSDKosw8LtPOeWoK3JINjAk5jiPQ2cww++ 7QGG/g5NDjxFZNDJP1dGiLAxPW6JXwov4v0FmdzfLOZ01jDcgQQZqEpYlgpuI5JE WUQ9Ho4EzbYCOQ== -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIBPAIBAAJBAKy+e3dulvXzV7zoTZWc5TzgApr8DmeQHTYC8ydfzH7EECe4R1Xh 5kwIzOuuFfn178FBiS84gngaNcrFi0Z5fAkCAwEAAQJBAIqm/bz4NA1H++Vx5Ewx OcKp3w19QSaZAwlGRtsUxrP7436QjnREM3Bm8ygU11BjkPVmtrKm6AayQfCHqJoT ZIECIQDW0BoMoL0HOYM/mrTLhaykYAVqgIeJsPjvkEhTFXWBuQIhAM3deFAvWNu4 nklUQ37XsCT2c9tmNt1LAT+slG2JOTTRAiAuXDtC/m3NYVwyHfFm+zKHRzHkClk2 HjubeEgjpj32AQIhAJqMGTaZVOwevTXvvHwNEH+vRWsAYU/gbx+OQB+7VOcBAiEA oolb6NMg/R3enNPvS1O4UU1H8wpaF77L4yiSWlE0p4w= -----END RSA PRIVATE KEY----- -----BEGIN CERTIFICATE REQUEST----- MIIBDTCBuAIBADBTMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xEjAQ BgNVBAMTCWxvY2FsaG9zdDEdMBsGCSqGSIb3DQEJARYObmdwc0Bwb3N0MS5jb20w XDANBgkqhkiG9w0BAQEFAANLADBIAkEArL57d26W9fNXvOhNlZzlPOACmvwOZ5Ad NgLzJ1/MfsQQJ7hHVeHmTAjM664V+fXvwUGJLziCeBo1ysWLRnl8CQIDAQABoAAw DQYJKoZIhvcNAQEEBQADQQA7uqbrNTjVWpF6By5ZNPvhZ4YdFgkeXFVWi5ao/TaP Vq4BG021fJ9nlHRtr4rotpgHDX1rr+iWeHKsx4+5DRSy -----END CERTIFICATE REQUEST----- m2crypto-0.46.2/demo/x509/server.pem000066400000000000000000000041101506746742300170360ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDYjCCAsugAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBgDELMAkGA1UEBhMCU0cx ETAPBgNVBAoTCE0yQ3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UE AxMbTTJDcnlwdG8gQ2VydGlmaWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNu Z3BzQG5ldG1lbWV0aWMuY29tMB4XDTAzMDYyMjEzMzAxNFoXDTA0MDYyMTEzMzAx NFowXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwls b2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5leGFtcGxlLmRv bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA37aKGZtFicl8xXXTLJ8/JD7c kd3t/teCX9i61lpaDQCKBoVrrursIvZihemMKI9g/u/+BLqt5g8mBdgUdYz0txc8 KEbV2hj+wwOX4H3XwD0Y+DysXiNHq7/tFdmzSVHoLxpY4zYzXbxQ/p049wvIyPRp /y3omcnx/TEUhkn+JmkCAwEAAaOCAQwwggEIMAkGA1UdEwQCMAAwLAYJYIZIAYb4 QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBTB H/mUYlww24mJlSxEtGdlwojO9zCBrQYDVR0jBIGlMIGigBTr+pwHMS1CmF9cuGI4 du3YqoHAwqGBhqSBgzCBgDELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv MRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8gQ2VydGlm aWNhdGUgTWFzdGVyMSIwIAYJKoZIhvcNAQkBFhNuZ3BzQG5ldG1lbWV0aWMuY29t ggEAMA0GCSqGSIb3DQEBBAUAA4GBAAvl6v0s3eFeGP4iAcrfysuK7jzFKhjDYuOy lVS3u33bZNLnMpM6OSEM9yPh4WpFCVHf+nYwC71pk4ilsLVXjKxymm2lNGcxLVuW iydFz4Ly9nmN7Ja9ygYT39dGAFP/wN7ELTpsbul8VfmqhNg9y81d8i/A1tK3AGA8 0QkPQNdP -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDftooZm0WJyXzFddMsnz8kPtyR3e3+14Jf2LrWWloNAIoGhWuu 6uwi9mKF6Ywoj2D+7/4Euq3mDyYF2BR1jPS3FzwoRtXaGP7DA5fgfdfAPRj4PKxe I0erv+0V2bNJUegvGljjNjNdvFD+nTj3C8jI9Gn/LeiZyfH9MRSGSf4maQIDAQAB AoGAHpeVtv62uarl9xKvuBBm0AwQmZnhq9HIsFaw5hMg8Vo7hbzFBvx1IirTOkC/ u+QvfW1QLVFh6m3z4ySzV4fZBtcd6F9SbSrZ0xsxIUB2NOSa1RGgiaP61bJnMMM1 xM3O9iwM5GZc3Gqy08QOCpDl0772VJ+9Gz3FA88mrc6rHQkCQQDz6RIatFjT28n8 1vy0nHwwZz2oXTpe/pyZPwoKj8zVsmrKhKwOw7l8ArxjP8zoHOE7AQBCXYDMNoFp IAF0yuqrAkEA6s0wMEdPpQeb0XHAfccyJQoeULxHdVFoz1wWmGSOm4YmQtR8/QJx luEgfpeRkzxBKt5Ls3MEkheIOw7xV24zOwJAMz+DaE0AZPNHS3K4ghJnHZxzng6I lzEUIjbWm0V/ml70hTy/EhMZw+6nOotLOHHo+QbK0SboSwAgzL/Gzo1cJQJANqpS 38qadleRJXAQWrg3qnvyluVe1aeAeVZ9RDmVIgxXeBO0jcs12uTLBe4PzHGo0mwy v7K1i7XC180gzzQu5QJBAOxITT9RoWSSozPvnirHd37sn+RsrNYkV07NAa80M20Z DkBPHeMVkNgigrQ6L6vWmbRDGQbGcMplAxnI5ppKCoU= -----END RSA PRIVATE KEY----- m2crypto-0.46.2/demo/x509/x509auth.py000066400000000000000000001127361506746742300170040ustar00rootroot00000000000000#!/usr/bin/env python2 # # vim: ts=4 sw=4 nowrap # # ChannelHandler # ReceiveChannel # SendChannel # # SocketDispatcher # Loop # Poll # ReadEvent # WriteEvent # from __future__ import print_function import sys, re, time, thread, os import getopt import exceptions import select import string import socket import StringIO import traceback from errno import ( EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, ENOTCONN, ESHUTDOWN, EINTR, EISCONN, ) STDOUT = sys.stdout IDstdin = 0 IDstdout = 1 IDstderr = 2 class ExitNow(exceptions.Exception): pass class AuthError(exceptions.Exception): def __init__(self, msg): self.msg = msg def __str__(self): return repr(self.msg) # ---------------------------------------------------------------- # # Class Security Certification # # ---------------------------------------------------------------- import M2Crypto import random import base64 import sha class CertHandler: def __init__(self): self.Nonce = None self.CurrentObj = {} # self.ServerName = socket.gethostbyaddr(socket.gethostname())[2][0] self.ServerName = "AuthInstance" self.ObjNames = { "C": "countryName", "ST": "stateOrProvinceName", "L": "localityName", "O": "organizationName", "OU": "organizationalUnitName", "CN": "commonName", "email": "emailAddress", } self.ObjMap = {} self.Params = { "Digest": "sha1", "Version": 1, "Serial": 1, "NotBefore": (60 * 60 * 24 * 365), "NotAfter": (60 * 60 * 24 * 365 * 5), "Issuer": { "countryName": "US", "stateOrProvinceName": "florida", "localityName": "tampas", "organizationName": "watersprings", "organizationalUnitName": "security", "commonName": "Certificate Authority", "emailAddress": "admin@security", }, "Subject": { "countryName": "US", "stateOrProvinceName": "florida", "localityName": "miami", "organizationName": "watersprings", "organizationalUnitName": "security", "commonName": "Certificate Authority", "emailAddress": "admin@security", }, } self.KeyEnv = { "RsaPubKey": ["-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----"], "RsaPKey": [ "-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----", ], "X509Cert": ["-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----"], } self.CertContainer() self.ObjFromContainer(ObjName="CA") self.ObjFromContainer(ObjName=self.ServerName) self.ServerObj = self.ObjMap[self.ServerName] def CertContainer(self): self.PemMap = { "CA": { "Subject": { "organizationalUnitName": "security", "organizationName": "watersprings", "commonName": "Certificate Authority", "stateOrProvinceName": "florida", "countryName": "US", "emailAddress": "admin@security", "localityName": "miami", }, "RsaPKey": [ "MIICXQIBAAKBgQDmAl+4+XdF34D3kBN58An29mA8/D+NUHVJW+XeE96uDJ9mw8f1", "xguVYgfpMaiVihW/qDWZRu/NhWOfheKBVNstx5OcqIjY10vBvGAG17CQZhcon8eN", "Kufg7XzON7e5WXXD8qyklhuesHtTEGGpZ1FfA+n+D/0JF3YfTBDeYyY2VQIDAQAB", "AoGBAI53L/Uxx7fmzUoJ2pZvoKxwRIHhuDd+e3c5zbJ1WjsyJFWRtLw9tBUOCFpf", "YM1nHzt8I97RulzxXxiC5B45ghu3S0s+B06oEOUxNLbjsai08DKBRFqM+IZIx11r", "IM/tZsTdJg1KtKojRu63NDtOzR6a7ggTeMge5CDKpXVWpvVtAkEA+QF/q2NnsdmL", "ak6ALl8QwMbvwujJcjLwvecHQJmB0jO9KF60Hh4VY8mTRIMZ/r9Wf+REsQcZtmhG", "WRr12si5qwJBAOx4R0Wd/inoXOpvKheIoKgTg01FnLhT8uiLY59CuZRr6AcTELjC", "Kvk6LyfhspYBkUwWAEwKxJ3kMeqXG+k8z/8CQQCy+GDKzqe5LKMHxWRb7/galuG9", "NZOUgQiHdYXA6JRmgMl0Op07CGRXVIqEs7X7Y4rIYUj99ByG/muRn88VcTABAkBQ", "Z6V0WoBtp4DQhfP+BIr8G4Zt49miI4lY4OyC3qFTgk1m+miZKgyKqeoW2Xtr3iSV", "hnWbZZ3tQgZnCfKHoBHpAkAmf2OvfhLxaW1PwdjBdm9tFGVbzkLFDqdqww2aHRUx", "sXonHyVG2EDm37qW7nzmAqUgQCueMhHREZQYceDrtLLO", ], "X509Cert": [ "MIICpzCCAhCgAwIBAQIBATANBgkqhkiG9w0BAQUFADCBmTERMA8GA1UECxMIc2Vj", "dXJpdHkxFTATBgNVBAoTDHdhdGVyc3ByaW5nczEeMBwGA1UEAxMVQ2VydGlmaWNh", "dGUgQXV0aG9yaXR5MRAwDgYDVQQIEwdmbG9yaWRhMQswCQYDVQQGEwJVUzEdMBsG", "CSqGSIb3DQEJARYOYWRtaW5Ac2VjdXJpdHkxDzANBgNVBAcTBnRhbXBhczAeFw0w", "MzAzMzExMDQ2MDVaFw0wOTAzMjkxMDQ2MDVaMIGYMREwDwYDVQQLEwhzZWN1cml0", "eTEVMBMGA1UEChMMd2F0ZXJzcHJpbmdzMR4wHAYDVQQDExVDZXJ0aWZpY2F0ZSBB", "dXRob3JpdHkxEDAOBgNVBAgTB2Zsb3JpZGExCzAJBgNVBAYTAlVTMR0wGwYJKoZI", "hvcNAQkBFg5hZG1pbkBzZWN1cml0eTEOMAwGA1UEBxMFbWlhbWkwgZ8wDQYJKoZI", "hvcNAQEBBQADgY0AMIGJAoGBAOYCX7j5d0XfgPeQE3nwCfb2YDz8P41QdUlb5d4T", "3q4Mn2bDx/XGC5ViB+kxqJWKFb+oNZlG782FY5+F4oFU2y3Hk5yoiNjXS8G8YAbX", "sJBmFyifx40q5+DtfM43t7lZdcPyrKSWG56we1MQYalnUV8D6f4P/QkXdh9MEN5j", "JjZVAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAK7f4YodUnT7Ygp7BWBBDHSq/r+tY", "H69ly3W23U5VupaIglNiNQoMqnZpVVfcuIYltajrux5TSH4gPbenCg163Ua8RvF6", "E2JElccprbKiCf9tf8l6Rxpsall4EF+CazP56DiUD1NfGLhWp9V2ga9SoynEo1P1", "eztMBfk01atBJ/s=", ], }, "AuthInstance": { "Subject": { "commonName": "AuthInstance", "organizationalUnitName": "security", "emailAddress": "ioclient@AuthInstance", }, "RsaPKey": [ "MIICXQIBAAKBgQCwfB6CoOQTJTd6D4ua1G/H9hwqpdVUMMjG3O8Y93vYGesZdwtT", "1iEQX/6TWACBxa7jOC8hHUHe2lsPu7imHv8dDiD59Rzets7BM88HsJTemYrxSv5G", "uh8FloB1KEtSHeCZSlDT/tzSX4M0JfVPmtx+0FsyDOVZ6jXjRIyIKgqDlwIDAQAB", "AoGAYc8YFatXW6j3mwU8iL2NidPC/nvTxAoZa+UL+dlG4JhUrFNGitsUjf+1ljFi", "bomBiFod/Is7c2euqgSOrDpnheYlogv2QpnP80YUpiv9OruaB9I1zqJ7QM7PrkrH", "m1C36DzyzVY+4DMvTV29do4Mf6CKT8xf6hXlLK/NbqwO9NkCQQDYwxwCTWxrkX08", "+0c5KaTYxfqCByxOqoiKl97p6wHxNtlzdLeFoSZD0n3Q1c2v0DIXhcBPRPPaZBWC", "yTayMkRzAkEA0G6I5mHQVNIx18Xmc75urC0QWrum9cj5VcyRvl3KCzB2kQoXkx6v", "y0JN6YS37rSp8vmvIFNO/oHWSuEJlFYfTQJAajWv07D8Hvj61JaLH4c4Lr9TL8M0", "Apesr7wajaOJIBgwFFJsWh3MEg9hdqJMVok9AimXQUAX/DpuD9dn5Yib4QJBAIdt", "Kno2V7ylDkmahk/yDcrFRPkPMD5GpOrAjnnYSqzWglNe8U5gA+zXWfQ+jZwFut7q", "qIUiXBM1nVzttuGwy4kCQQC3MHppypSWoFqd+TaxK3MX/HoZqaoRELXdeiniOt3Z", "gFMJ4m6D9lL4segWDoDpequjDYxv2cl+wS1+qDOyeG3J", ], "X509Cert": [ "MIIBxDCCAS2gAwIBAQIBATANBgkqhkiG9w0BAQUFADAAMB4XDTAzMDMzMTEwNTE1", "N1oXDTA5MDMyOTEwNTE1N1owUDEkMCIGCSqGSIb3DQEJARYVaW9jbGllbnRAQXV0", "aEluc3RhbmNlMREwDwYDVQQLEwhzZWN1cml0eTEVMBMGA1UEAxMMQXV0aEluc3Rh", "bmNlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwfB6CoOQTJTd6D4ua1G/H", "9hwqpdVUMMjG3O8Y93vYGesZdwtT1iEQX/6TWACBxa7jOC8hHUHe2lsPu7imHv8d", "DiD59Rzets7BM88HsJTemYrxSv5Guh8FloB1KEtSHeCZSlDT/tzSX4M0JfVPmtx+", "0FsyDOVZ6jXjRIyIKgqDlwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFsXewlXnKpH", "uSwxavmLPUqRk7o1D5E3ByTddBe3BY5NqEXk7Y2SJFtumiuUY5/sWB/aO8Xbqj/b", "/7Cwg9+bc9QqxeeIe/YvtFOmv1ELh2BC1Nof7zSa5rLa/+gPYCoogS4mLRMuUfRk", "tVHhpoxL1B+UXp4jNeKeTgquOjpUiyBR", ], }, "192.168.1.20": { "Subject": { "commonName": "192.168.1.20", "organizationalUnitName": "security", "emailAddress": "ioclient@192.168.1.20", }, "RsaPKey": [ "MIICWwIBAAKBgQDD285BGY+FHhfpRvcqupN8X2lPwUNq4G7k5kit5cyuQLfN0+eQ", "I+VFZdtfJhCZC54dEIvNgA4I7563pRUD0S9rmN6kh/M0GgrKZjYNO+CvvG2dts26", "MGK0eUQaSsvDf9phEA+0mSv9dsUrdyBTJBn4mXvApekYHt+mNLfCVLkM1QIDAQAB", "AoGAMqcFB3cJ0/59Zpowz/8ip3axcKvluJ1EcLRRtY+JyML6BiQ4beGqqLD38/qP", "LlV/1bpyvXnRp2P5IztxXORbo77IzDVzl62YesQATnecSCMLTaeOusy2EZZsjE0k", "V2cR1rZvzyJPY+Fi8X54hiB+5IcKkPRX9LVw7+yBbBh4sKECQQD0Yi0/DGa3IetR", "9F+/jgN/VIcTd5KwMBW3Bw/+Bh78ZlZGaucpRiR1IQuD7sLTnhNS6RMJUxv10jnS", "BGW9pjX5AkEAzSslOGFyJ5Aoy48rgC2kKwq6nFKJ/PmY92cnm0nqmwb2npbOtDxz", "sPUdb7oYmUU/nVCJh3yb+KJIw2g9XxnUvQJAG8ybNwPTH1vlZ+Izjhe6gB5+axF8", "BzzBC5vrDstldPKzN7lraD+JYCWNKMndMbNWoWTP/IyOrqzmVOSZKjShCQJAbzuE", "C2QxaqeqpmnxkKWuCrPfZl8NdryvpPolK/jQG8qTrHlgibD4nCjYE7nWGkrD6Xs/", "hNgXC56YSnDaTRQJFQJAD5GFACv9QgcMZhy1hza0yGDMSQ0WR8/y3CJhi3DPOuAf", "MetGM1kLQR8bDFrl7yEs+Nufk8QTsE5ngZ7dGFgmuA==", ], "X509Cert": [ "MIIBxDCCAS2gAwIBAQIBATANBgkqhkiG9w0BAQUFADAAMB4XDTAzMDMzMTEwNTMw", "NVoXDTA5MDMyOTEwNTMwNVowUDEkMCIGCSqGSIb3DQEJARYVaW9jbGllbnRAMTky", "LjE2OC4xLjIwMREwDwYDVQQLEwhzZWN1cml0eTEVMBMGA1UEAxMMMTkyLjE2OC4x", "LjIwMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDD285BGY+FHhfpRvcqupN8", "X2lPwUNq4G7k5kit5cyuQLfN0+eQI+VFZdtfJhCZC54dEIvNgA4I7563pRUD0S9r", "mN6kh/M0GgrKZjYNO+CvvG2dts26MGK0eUQaSsvDf9phEA+0mSv9dsUrdyBTJBn4", "mXvApekYHt+mNLfCVLkM1QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAA5pWiXJOHCJ", "P6kHcBITJuwv94zZ0dbHby1ljUfG/8z3Fmr8JRUcTuTtgVYH9M0O9QujIR8YLWSV", "0GeD3nkLRn0+ezam0CW0dF/Ph5vNXFP4a0DSEVv7T0G21VFmbUV3xrVeaXARFuLa", "AtqRoSyBMajd3g0WNXDCgGEH7LvzJ5EP", ], }, "192.168.1.26": { "Subject": { "commonName": "192.168.1.26", "organizationalUnitName": "security", "emailAddress": "ioclient@192.168.1.26", }, "RsaPKey": [ "MIICXQIBAAKBgQC5ILRHC3wFoqG9Egb96N3iGEnVrgvQikHyXYc/jFMUgB79rVJp", "hY1MziGkSjSyc3RFMshkjHlMlARMPCNtomIikqAQaO4Eke2SYWyaOBoTdkeOy+yZ", "t/POpoGp3nRmKGed6NNcdMd5BO01GiatUb7X/Se3Yyvmj5UcEmv/hZQGFwIDAQAB", "AoGBALdR5FMp0zE9X437iQLsErQuOwcmpzplfnJDHYfXK/nz+TxY4m/tuQNiZ7vp", "Y4+Gdo+Dfx7aX89uD2dycd7B2wwTziBGIEjhusD8gtralVjhBDjCowSOkezWTeY+", "2h40NB4e1uypOZb0PXWvAL/l9xN7NBGioq9zmShT5c+FFO8RAkEA4k3QSaT1ScGI", "5II5JolvPnv6yS+0dCQTn1SC2ABWbH75NDUHMGAdNIf1sqhaLSQnY9GuXhb8XqX6", "UUhoypUHzwJBANFrqnuEuTNKR0HVD31/2trPYLfZL6/9RUsR4mlvxPb0tX+T5LVL", "5he43zbura/lZqNxt0ZVeD03LanPN7bvZzkCQQCMAToIJa6+x6YKQOpchhA1pvwb", "NZE9fQhKvT0JpwPQsak4/EmLSxsmYarGsdLANKrN3W4ztaLCZ4r6eIKkOhkPAkBz", "ke4wYitucbRnUTRONuvJSx599x6JCcVey0zekO7qtlsfP7e8kVk2iDCu+QLjCj8d", "Pdk9uFc1uSi7CH8ftniJAkBLNYF0kfGC+CaTuyfnIwiBZ/tjmm4UvHfwtlaZHJYc", "QIjimBxVA7mujrv3xIBTiDMdxUhq9YIaKIEdlveaTwPK", ], "X509Cert": [ "MIIBxDCCAS2gAwIBAQIBATANBgkqhkiG9w0BAQUFADAAMB4XDTAzMDMzMTEwNTQx", "NloXDTA5MDMyOTEwNTQxNlowUDEkMCIGCSqGSIb3DQEJARYVaW9jbGllbnRAMTky", "LjE2OC4xLjI2MREwDwYDVQQLEwhzZWN1cml0eTEVMBMGA1UEAxMMMTkyLjE2OC4x", "LjI2MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5ILRHC3wFoqG9Egb96N3i", "GEnVrgvQikHyXYc/jFMUgB79rVJphY1MziGkSjSyc3RFMshkjHlMlARMPCNtomIi", "kqAQaO4Eke2SYWyaOBoTdkeOy+yZt/POpoGp3nRmKGed6NNcdMd5BO01GiatUb7X", "/Se3Yyvmj5UcEmv/hZQGFwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAMPd5SXzpwZ+", "40SdOv/PeQ5cjieDm6QjndWE/T8nG2I5h6YRWbZPohsCClQjrTyZCMXwcUiCimuJ", "BaMigI/YqP5THVv58Gu8DpoVZppz7uhUNS5hsuV9lxZUh1bRkUtL6n0qSTEdM34I", "NJBJKGlf0skULg9BT4LJYTPGWJ0KosUl", ], }, } def CreateObj(self, ObjName="CA"): self.ObjMap[ObjName] = { "RsaPKey": None, "PsaPubKey": None, "EvpPKey": None, "EvpPubKey": None, "X509Req": None, "X509Cert": None, } self.CurrentObj = self.ObjMap[ObjName] def ObjFromContainer(self, ObjName="CA"): if ObjName not in self.ObjMap: self.CreateObj(ObjName=ObjName) self.PKeyFromPemRepr(ObjName=ObjName) self.CertFromPemRepr(ObjName=ObjName) def PKeyFromPemRepr(self, ObjName=None, PemPKey=None): def callback(): return "" if ObjName in self.PemMap: UsedPemPKey = ( self.KeyEnv["RsaPKey"][0] + "\n" + string.join(self.PemMap[ObjName]["RsaPKey"], "\n") + "\n" + self.KeyEnv["RsaPKey"][1] + "\n" ) else: if not PemPKey: raise AuthError('no such Object "%s" in container - abort!' % ObjName) else: UsedPemPKey = PemPKey self.CurrentObj["RsaPKey"] = M2Crypto.RSA.load_key_string(UsedPemPKey, callback) self.CurrentObj["EvpPKey"] = M2Crypto.EVP.PKey(md="sha1") self.CurrentObj["EvpPKey"].assign_rsa(self.CurrentObj["RsaPKey"]) self.CurrentObj["RsaPubKey"] = M2Crypto.RSA.new_pub_key( self.CurrentObj["RsaPKey"].pub() ) def CertFromPemRepr(self, ObjName=None, PemCert=None): if ObjName in self.PemMap: UsedPemCert = ( self.KeyEnv["X509Cert"][0] + "\n" + string.join(self.PemMap[ObjName]["X509Cert"], "\n") + "\n" + self.KeyEnv["X509Cert"][1] + "\n" ) else: UsedPemCert = PemCert self.CurrentObj["X509Cert"] = M2Crypto.X509.load_cert_string(PemCert) self.CurrentObj["EvpPubKey"] = self.CurrentObj["X509Cert"].get_pubkey() # self.CurrentObj['RsaPubKey'] = M2Crypto.RSA.rsa_from_pkey( self.CurrentObj['EvpPubKey'] ) def ObjNameFromPemCert(self, PemCert=None): """ generate objmap structure and fill it with values from PemCert return ObjName string """ X509Cert = M2Crypto.X509.load_cert_string(PemCert) Subject = X509Cert.get_subject() SubjectTxt = Subject.print_ex() SubjectTxtList = re.split("[\n\r]", SubjectTxt) SubjectMap = {} for Entry in SubjectTxtList: (Key, Value) = re.split("=", Entry) if Key in self.ObjNames: SubjectMap[self.ObjNames[Key]] = Value else: SubjectMap[Key] = Value if "commonName" not in SubjectMap: return False ObjName = SubjectMap["commonName"] if ObjName not in self.ObjMap: self.CreateObj(ObjName=ObjName) self.CurrentObj = self.ObjMap[ObjName] self.CurrentObj["X509Cert"] = X509Cert self.CurrentObj["EvpPubKey"] = self.CurrentObj["X509Cert"].get_pubkey() self.CurrentObj["RsaPubKey"] = M2Crypto.RSA.rsa_from_pkey( self.CurrentObj["EvpPubKey"] ) else: self.CurrentObj = self.ObjMap[ObjName] return ObjName def ServerCert(self): self.ObjFromContainer(ObjName="X509Auth") def CreatePKey(self): def PassPhraseFkt(): return "" RsaKeyParams = { "KeyLength": 1024, "PubExponent": 0x10001, # -> 65537 "keygen_callback": PassPhraseFkt, } self.CurrentObj["RsaPKey"] = M2Crypto.RSA.gen_key( RsaKeyParams["KeyLength"], RsaKeyParams["PubExponent"], RsaKeyParams["keygen_callback"], ) self.CurrentObj["EvpPKey"] = M2Crypto.EVP.PKey(md=self.Params["Digest"]) self.CurrentObj["EvpPKey"].assign_rsa(self.CurrentObj["RsaPKey"]) # print(self.EvpPKey) def CreateCert(self, SignEvpPKey=None): """ generate new x509 certificate SignEvpKey pkey to sign x509 certification, if None this x509 cert will be self signed """ self.CurrentObj = self.ObjMap["CA"] self.CreatePKey() X509Cert = M2Crypto.X509.X509() X509Cert.set_version(self.Params["Version"]) X509Cert.set_serial_number(self.Params["Serial"]) X509Cert.set_not_before( int(time.time() - self.Params["NotBefore"]) ) # 1 year in the past X509Cert.set_not_after( int(time.time() + self.Params["NotAfter"]) ) # 5 years in the future X509Cert.set_issuer(self.Params["Issuer"]) X509Cert.set_subject(self.Params["Subject"]) X509Cert.set_pubkey(self.CurrentObj["EvpPKey"]) if SignEvpPKey: X509Cert.sign(SignEvpPKey, self.Params["Digest"]) else: X509Cert.sign(self.CurrentObj["EvpPKey"], self.Params["Digest"]) self.CurrentObj["X509Cert"] = X509Cert self.DumpOutInternalPemRepr(ObjName="CA") def CreateObjCert(self, ObjName): """ generate Obj with new PKey and Request, signed by 'CA' ObjName the primary key to identify key-pair """ # new obj if ObjName not in self.ObjMap: self.ObjMap[ObjName] = {} self.CurrentObj = self.ObjMap[ObjName] if "Subject" not in self.CurrentObj: self.CurrentObj["Subject"] = { "organizationalUnitName": "security", "commonName": ObjName, "emailAddress": "ioclient@" + ObjName, } # new pkey self.CreatePKey() # new request self.CreateReq(SignEvpPKey=self.ObjMap["CA"]["EvpPKey"]) # new certification if not self.Req2Cert(SignEvpPKey=self.ObjMap["CA"]["EvpPKey"]): print("300 error occured while verifying - abort!") # shipout x509 certification self.DumpOutInternalPemRepr(ObjName=ObjName) def CreateReq(self, SignEvpPKey=None): X509Req = M2Crypto.X509.Request() if self.Params["Version"]: X509Req.set_version(self.Params["Version"]) X509Req.set_subject(self.CurrentObj["Subject"]) X509Req.set_pubkey(self.CurrentObj["EvpPKey"]) if SignEvpPKey: X509Req.sign(SignEvpPKey, self.Params["Digest"]) else: X509Req.sign(self.CurrentObj["EvpPKey"], self.Params["Digest"]) self.CurrentObj["X509Req"] = X509Req def Req2Cert(self, SignEvpPKey=None): X509Cert = M2Crypto.X509.X509() Version = self.CurrentObj["X509Req"].get_version() X509Cert.set_version(Version) X509Cert.set_serial(self.Params["Serial"]) X509Cert.set_not_before( int(time.time() - self.Params["NotBefore"]) ) # 1 year in the past X509Cert.set_not_after( int(time.time() + self.Params["NotAfter"]) ) # 5 years in the future Issuer = self.ObjMap["CA"]["X509Cert"].get_issuer() X509Cert.set_issuer_name(Issuer) X509Name_Subject = self.CurrentObj["X509Req"].get_subject() X509Cert.set_subject_name(X509Name_Subject) PKey = self.CurrentObj["X509Req"].get_pubkey() EvpPKey = M2Crypto.EVP.PKey(PKey) X509Cert.set_pubkey(EvpPKey) if SignEvpPKey: X509Cert.sign(SignEvpPKey, self.Params["Digest"]) else: X509Cert.sign(self.CurrentObj["EvpPKey"], self.Params["Digest"]) self.CurrentObj["X509Cert"] = X509Cert if self.VerifyCert(SignEvpPKey): return True else: return False # -------------------------------- # CertHandler Verifying # -------------------------------- def ExtractPublicKeyFromCert(self): self.CurrentObj["EvpPubKey"] = self.CurrentObj["X509Cert"].get_pubkey() def VerifyCert(self, EvpPKey): if dir(EvpPKey).count("_ptr"): Result = self.CurrentObj["X509Cert"].verify(EvpPKey._ptr()) else: Result = self.CurrentObj["X509Cert"].verify(EvpPKey) if Result: return True return False # -------------------------------- # CertHandler DumpOut # -------------------------------- def DumpOutInternalPemRepr(self, ObjName="unknown", File="PyReprPem.txt"): if File: open(File, "w").write("\t\t\t\t'%s' : { " % (ObjName)) else: sys.stdout.write("\t\t\t\t'%s' : { " % (ObjName)) self.ShowX509CertSubject(File) self.RsaPKey2PemRepr(File, Cipher=None) # unprotectd pkey representation self.X509Cert2PemRepr(File) if File: open(File, "a").write("\t\t\t\t\t }\n") else: sys.stdout.write("\t\t\t\t\t }\n") def ShowX509CertIssuer(self, File=None): IssuerName = self.CurrentObj["X509Cert"].get_issuer() print(IssuerName.print_ex()) def ShowX509CertSubject(self, File=None): Subject = self.CurrentObj["X509Cert"].get_subject() SubjectTxt = Subject.print_ex() SubjectTxtList = re.split("[\n\r]", SubjectTxt) SubjectMap = {} for Entry in SubjectTxtList: (Key, Value) = re.split("=", Entry) if Key in self.ObjNames: SubjectMap[self.ObjNames[Key]] = Value else: SubjectMap[Key] = Value if File: open(File, "a").write("'Subject' : %s,\n" % (repr(SubjectMap))) else: sys.stdout.write("Subject: %s\n" % (repr(SubjectMap))) def RsaPKey2PemRepr(self, File=None, Cipher=None): """ converting pkey to PEM representation Cipher if set to None, the pkey will be unprotected!!!!! possible other value: 'des_ede3_cbc' """ PemRsaPKey = self.CurrentObj["RsaPKey"].repr_key_pem(cipher=Cipher) PemRsaPKeyList = re.split("[\n\r]", PemRsaPKey) if File: open(File, "a").write( "\t\t\t\t\t\t\t\t'RsaPKey' : %s,\n" % (repr(PemRsaPKeyList[1:-2])) ) else: sys.stdout.write( "\t\t\t\t\t\t\t\t'RsaPKey' : %s,\n" % (repr(PemRsaPKeyList[1:-2])) ) def X509Cert2PemRepr(self, File=None): PemCert = self.CurrentObj["X509Cert"].repr_cert_pem() # print(PemCert) PemCertList = re.split("[\n\r]", PemCert) if File: open(File, "a").write( "\t\t\t\t\t\t\t\t'X509Cert' : %s\n" % (repr(PemCertList[1:-2])) ) else: sys.stdout.write( "\t\t\t\t\t\t\t\t'X509Cert' : %s\n" % (repr(PemCertList[1:-2])) ) # -------------------------------- # CertHandler encryption / decryption # -------------------------------- def CreateNonce(self): """ creating some randomised data return new Nonce string """ random.seed() RawNonce = "%s_%f_%f" % (os.getpid(), time.time(), random.random()) sha1 = M2Crypto.EVP.MessageDigest("sha1") sha1.update(RawNonce) NonceDecrypted = sha1.digest() return NonceDecrypted def NonceEncryptPrivate(self, NonceDecrypted, RsaPKey=None): """ creating private encrypted string from NonceDecrypted """ padding = M2Crypto.RSA.pkcs1_padding if not RsaPKey: UsedRsaPKey = self.ServerObj["RsaPKey"] else: UsedRsaPKey = RsaPKey NoncePrivEncrypted = UsedRsaPKey.private_encrypt(NonceDecrypted, padding) return NoncePrivEncrypted def NonceEncryptPublic(self, NonceDecrypted, RsaPubKey=None): """ creating public encrypted string from NonceDecrypted """ padding = M2Crypto.RSA.pkcs1_padding if not RsaPubKey: UsedRsaPubKey = self.ServerObj["RsaPubKey"] else: UsedRsaPubKey = RsaPubKey NoncePubEncrypted = UsedRsaPubKey.public_encrypt(NonceDecrypted, padding) return NoncePubEncrypted def NonceDecryptPublic(self, NoncePrivEncrypted, RsaPubKey=None): """ creating decrypted string from NoncePrivEncrypted """ padding = M2Crypto.RSA.pkcs1_padding if not RsaPubKey: UsedRsaPubKey = self.ServerObj["RsaPubKey"] else: UsedRsaPubKey = RsaPubKey try: NonceDecrypted = UsedRsaPubKey.public_decrypt(NoncePrivEncrypted, padding) except: raise AuthError("decrypting of public key failed - abort!") return NonceDecrypted def NonceDecryptPrivate(self, NoncePubEncrypted, RsaPKey=None): padding = M2Crypto.RSA.pkcs1_padding if not RsaPKey: UsedRsaPKey = self.ServerObj["RsaPKey"] else: UsedRsaPKey = RsaPKey NonceDecrypted = UsedRsaPKey.private_decrypt(NoncePubEncrypted, padding) return NonceDecrypted def NonceVerify(self, DecryptedNonce=None): if self.CurrentObj["Nonce"]["Decrypted"] == DecryptNonce: return True return False # -------------------------------- # CertHandler authentication request # -------------------------------- def ClientInit(self, ObjName=None): """ generating AuthString Nonce messagedigest 'sha1', encrypted with own instance private key Cert own instance X509 cert, PEM encoded any linefeed charaters stripped out of the base64 code return generated Nonce and AuthString """ if ObjName: if ObjName in self.PemMap: UsedObjName = ObjName else: UsedObjName = self.ServerName else: UsedObjName = self.ServerName NonceDecrypted = self.CreateNonce() NoncePrivEncrypted = re.sub( "\012", "", base64.encodestring( self.NonceEncryptPrivate( NonceDecrypted, RsaPKey=self.ServerObj["RsaPKey"] ) ), ) PemCert = re.sub( "\012", "", base64.encodestring( self.KeyEnv["X509Cert"][0] + "\n" + string.join(self.PemMap[UsedObjName]["X509Cert"], "\n") + "\n" + self.KeyEnv["X509Cert"][1] + "\n" ), ) InitString = re.sub( "\012", "", base64.encodestring("%s:%s" % (NoncePrivEncrypted, PemCert)) ) return (NonceDecrypted, InitString) def ClientInitVerify(self, InitString): """ return decrypted Nonce from AuthString and ObjName from AuthString X509 Cert """ try: PemBaseString = base64.decodestring(InitString) except base64.binascii.Error as msg: raise base64.binascii.Error(msg) try: (Base64Nonce, Base64Cert) = re.split(":", PemBaseString) except: raise AuthError("cannot split PemBaseString into parts - abort!") try: NoncePrivEncrypted = base64.decodestring(Base64Nonce) except base64.binascii.Error as msg: raise base64.binascii.Error(msg) try: PemCert = base64.decodestring(Base64Cert) except base64.binascii.Error as msg: raise base64.binascii.Error(msg) try: X509Cert = M2Crypto.X509.load_cert_string(PemCert) except: raise AuthError("cannot extract X509 cert from PEM representation - abort!") EvpPKey = self.ObjMap["CA"]["EvpPKey"] if dir(EvpPKey).count("_ptr"): Result = X509Cert.verify(EvpPKey._ptr()) else: Result = X509Cert.verify(EvpPKey) if Result != 1: raise AuthError( 'verification of X509 cert with Certification Authority "CA" failed with code %d - abort!' % (Result) ) ClientObjName = self.ObjNameFromPemCert(PemCert=PemCert) try: NonceDecrypted = self.NonceDecryptPublic( NoncePrivEncrypted, RsaPubKey=self.CurrentObj["RsaPubKey"] ) except: raise AuthError("wrong public key for encoding nonce - abort!") return (NonceDecrypted, ClientObjName) def ServerInit(self, ClientObjName, ClientNonce): """ NonceServer new Nonce from server encrypted with client publickey and base64 encoded NonceBounce the authrequest nonce encrypted with server privatekey and base64 encoded PemServerCert server X509 certification PEM encoded and base64 encoded """ if ClientObjName not in self.ObjMap: if ClientObjName not in self.PemMap: raise AuthError("cannot find ClientObjName - abort!") else: self.ObjFromContainer(ObjName=ClientObjName) else: self.CurrentObj = self.ObjMap[ClientObjName] NonceDecrypted = self.CreateNonce() NonceServer = re.sub( "\012", "", base64.encodestring( self.NonceEncryptPublic( NonceDecrypted, RsaPubKey=self.CurrentObj["RsaPubKey"] ) ), ) NonceBounce = re.sub( "\012", "", base64.encodestring( self.NonceEncryptPublic( ClientNonce, RsaPubKey=self.CurrentObj["RsaPubKey"] ) ), ) PemServerCert = re.sub( "\012", "", base64.encodestring( self.KeyEnv["X509Cert"][0] + "\n" + string.join(self.PemMap[self.ServerName]["X509Cert"], "\n") + "\n" + self.KeyEnv["X509Cert"][1] + "\n" ), ) InitString = re.sub( "\012", "", base64.encodestring("%s:%s:%s" % (NonceServer, NonceBounce, PemServerCert)), ) return (NonceDecrypted, InitString) def ServerInitVerify(self, InitString, ObjName=None): NonceDecrypted = "" ObjName = "" try: PemBaseString = base64.decodestring(InitString) except: return False (NonceServer, NonceBounce, ServerCert) = re.split(":", PemBaseString) NoncePubServer = base64.decodestring(NonceServer) # NonceServer NoncePubBounce = base64.decodestring(NonceBounce) # NonceBounce PemServerCert = base64.decodestring(ServerCert) # PemServerCert try: X509Cert = M2Crypto.X509.load_cert_string(PemServerCert) except: return False # verify X509 cert EvpPKey = self.ObjMap["CA"]["EvpPKey"] if dir(EvpPKey).count("_ptr"): Result = X509Cert.verify(EvpPKey._ptr()) else: Result = X509Cert.verify(EvpPKey) if not Result: return False # verify Nonce from Server encrypted with my own publickey try: NonceDecrypted = self.NonceDecryptPrivate( NoncePubServer, RsaPKey=self.ServerObj["RsaPKey"] ) except: return False ServerObjName = self.ObjNameFromPemCert(PemCert=PemServerCert) # verify Nonce bounced from Server encrypted with server privatekey try: NonceBounceDecrypted = self.NonceDecryptPrivate( NoncePubBounce, RsaPKey=self.CurrentObj["RsaPKey"] ) except: return False return (NonceDecrypted, NonceBounceDecrypted, ServerObjName) def ReplyInit(self, ReplyObjName, ReplyBounce): NonceDecrypted = self.CreateNonce() NoncePubInit = re.sub( "\012", "", base64.encodestring( self.NonceEncryptPublic( NonceDecrypted, RsaPubKey=self.ObjMap[ReplyObjName]["RsaPubKey"] ) ), ) NoncePubBounce = re.sub( "\012", "", base64.encodestring( self.NonceEncryptPublic( ReplyBounce, RsaPubKey=self.ObjMap[ReplyObjName]["RsaPubKey"] ) ), ) ReplyString = re.sub( "\012", "", base64.encodestring("%s:%s" % (NoncePubInit, NoncePubBounce)) ) return (NonceDecrypted, ReplyString) def ReplyVerify(self, ReplyString): try: PemBaseString = base64.decodestring(ReplyString) except base64.binascii.Error as msg: raise base64.binascii.Error(msg) (NoncePubInit, NoncePubBounce) = re.split(":", PemBaseString) try: NoncePubInit = base64.decodestring( NoncePubInit ) # new Nonce from Remote, encrypted with own publickey except base64.binascii.Error as msg: raise base64.binascii.Error(msg) try: NoncePubBounce = base64.decodestring( NoncePubBounce ) # bounced Nonce from Remote, encrypted with Remote privatekey except base64.binascii.Error as msg: raise base64.binascii.Error(msg) # verify Nonce from Remote encrypted with my own publickey try: NonceRemote = self.NonceDecryptPrivate( NoncePubInit, RsaPKey=self.ServerObj["RsaPKey"] ) except: raise AuthError("cannot encode nonce with own private key - abort!") # verify Nonce bounced from Remote encrypted with Remote privatekey try: NonceBounced = self.NonceDecryptPrivate( NoncePubBounce, RsaPKey=self.ServerObj["RsaPKey"] ) except: raise AuthError("wrong public key for encoding nonce - abort!") return (NonceRemote, NonceBounced) # ------------------------------------------------------------------------------------------- # TEST # ------------------------------------------------------------------------------------------- def CreateCAForContainer(self): self.CreateCert() def CreateForContainer(self, ObjName): """ create new pkey pair and x509 cert for specified objname result will be written in file "PyReprPem.txt" """ self.ObjFromContainer(ObjName="AuthInstance") self.CreateObjCert(ObjName=ObjName) def Test(self): # self.CreateCert () # self.ExtractPublicKeyFromCert () # self.VerifyCert () (ClientInitNonce, ClientInitString) = self.ClientInit() (ClientSendNonce, ClientObjName) = self.ClientInitVerify( InitString=ClientInitString ) (ServerInitNonce, ServerInitString) = self.ServerInit( ClientObjName=ClientObjName, ClientNonce=ClientSendNonce ) (ServerSendNonce, ClientBounceNonce, ServerObjName) = self.ServerInitVerify( InitString=ServerInitString ) if ClientInitNonce == ClientBounceNonce: print("100 Test Nonce bounced True") else: print("100 Test Nonce bounced False - abort!") (ReplyInitNonce, ReplyInitString) = self.ReplyInit( ReplyObjName=ClientObjName, ReplyBounce=ServerSendNonce ) (ReplySendNonce, NonceBounced) = self.ReplyVerify(ReplyString=ReplyInitString) if ServerInitNonce == NonceBounced: print("100 Test Nonce bounced True") else: print("100 Test Nonce bounced False - abort!") (Reply2InitNonce, Reply2InitString) = self.ReplyInit( ReplyObjName=ClientObjName, ReplyBounce=ServerSendNonce ) (Reply2SendNonce, Nonce2Bounced) = self.ReplyVerify( ReplyString=Reply2InitString ) if ServerInitNonce == Nonce2Bounced: print("100 Test Nonce bounced True") else: print("100 Test Nonce bounced False - abort!") # self.NonceEncryptPrivate () # self.NonceDecryptPublic () # self.NonceVerify () # ----------------------------------------------------------------------------------------------- # MAIN # # x509auth.py --ca # will create a file "PyReprPem.txt" in the current directory # append the contents of the file to the CertContainer in this script # # x509auth.py --cert # creates a file "PyReprPem.txt" in the current directory # append the contents of the file to the CertContainer in this script # # x509auth.py --test # running authentification tests with bounced nonce # # ----------------------------------------------------------------------------------------------- if __name__ == "__main__": run = CertHandler() if len(sys.argv) > 1: if sys.argv[1] == "--test": run.Test() elif sys.argv[1] == "--ca": run.CreateCert() elif sys.argv[1] == "--cert": run.CreateForContainer(sys.argv[2]) sys.exit(0) m2crypto-0.46.2/dev-requirements.txt000066400000000000000000000005071506746742300174420ustar00rootroot00000000000000build; python_version>'3.6' wheel irc setuptools>=43.0.0; python_version<='3.6' setuptools>=75.8.1; python_version>='3.9' twine; 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.46.2/doc/000077500000000000000000000000001506746742300141455ustar00rootroot00000000000000m2crypto-0.46.2/doc/HOWTOs.rst000066400000000000000000000001751506746742300157650ustar00rootroot00000000000000HOWTOs ================ Contents: .. toctree:: :maxdepth: 3 howto.ca howto.ssl howto.smime howto.migration m2crypto-0.46.2/doc/M2Crypto.SSL.rst000066400000000000000000000026551506746742300170260ustar00rootroot00000000000000SSL 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.46.2/doc/M2Crypto.rst000066400000000000000000000064501506746742300163630ustar00rootroot00000000000000M2Crypto 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:`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.46.2/doc/Makefile000066400000000000000000000127151506746742300156130ustar00rootroot00000000000000# 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.46.2/doc/conf.py000066400000000000000000000222651506746742300154530ustar00rootroot00000000000000# 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 = "M2Crypto" copyright = "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", "M2Crypto Documentation", "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", "M2Crypto Documentation", ["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", "M2Crypto Documentation", "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 = "M2Crypto" epub_author = "Matej Cepl " epub_publisher = "Matej Cepl " epub_copyright = "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.46.2/doc/howto.ca.rst000066400000000000000000000371231506746742300164270ustar00rootroot00000000000000: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.46.2/doc/howto.migration.rst000066400000000000000000000151361506746742300200350ustar00rootroot00000000000000: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: 12068af2140bb2907fc0086872ae... 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: 12068af2140bb2907fc0086872ae... 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 Apr 22 14:50:27 2025 GMT Apr 20 14:50:27 2035 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: 2025-04-22 14:50:27+00:00 2035-04-20 14:50:27+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.46.2/doc/howto.smime.rst000066400000000000000000000726101506746742300171560ustar00rootroot00000000000000: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.46.2/doc/howto.ssl.rst000066400000000000000000000124601506746742300166420ustar00rootroot00000000000000: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.46.2/doc/index.rst000066400000000000000000000003501506746742300160040ustar00rootroot00000000000000Welcome to M2Crypto's documentation! ==================================== Contents: .. toctree:: :maxdepth: 2 M2Crypto HOWTOs Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` m2crypto-0.46.2/doc/make.bat000066400000000000000000000117541506746742300155620ustar00rootroot00000000000000@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.46.2/doc/requirements.txt000066400000000000000000000001751506746742300174340ustar00rootroot00000000000000cryptography>=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.46.2/pylintrc000066400000000000000000000205641506746742300151760ustar00rootroot00000000000000# -*- 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.46.2/pyproject.toml000066400000000000000000000002641506746742300163160ustar00rootroot00000000000000[build-system] requires = [ "setuptools>=43.0.0; python_version<='3.6'", "setuptools>=75.8.1; python_version>='3.9'", "wheel" ] build-backend = "setuptools.build_meta" m2crypto-0.46.2/setup.cfg000066400000000000000000000037501506746742300152260ustar00rootroot00000000000000[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 long_description_content_type = text/x-rst keywords = cryptography openssl license = BSD-2-Clause license_file = LICENSES/BSD-2-Clause.txt classifiers = Development Status :: 5 - Production/Stable Intended Audience :: Developers 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 project_urls = home_page = https://sr.ht/~mcepl/m2crypto/ source = https://git.sr.ht/~mcepl/m2crypto documentation = https://m2crypto.readthedocs.io/en/latest/ report = https://lists.sr.ht/~mcepl/m2crypto changelog = https://git.sr.ht/~mcepl/m2crypto/tree/master/item/CHANGES [options] zip_safe = False include_package_data = True package_dir= =src packages = find: python_requires = >=3.6 [options.packages.find] where=src exclude = contrib* docs* tests* [options.package_data] M2Crypto = *.dll py.typed *.pyi [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 [black] line-length = 70 skip-string-normalization = true [mypy] [mypy-M2Crypto.m2crypto] # Mypy fails to resolve the relative import of the C-extension # in the SWIG-generated wrapper file. disable_error_code = import-not-found m2crypto-0.46.2/setup.py000066400000000000000000000304371506746742300151210ustar00rootroot00000000000000#!/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 # type: ignore from distutils.dir_util import mkpath # type: ignore else: from setuptools.command import build from setuptools.command import build_ext logging.basicConfig( format="%(levelname)s:%(funcName)s:%(message)s", stream=sys.stdout, 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: if platform.system() == "Darwin": sdk_path = ( subprocess.check_output(["xcrun", "--show-sdk-path"]).decode().strip() ) return [os.path.join(sdk_path, "usr", "include")] cpp = shlex.split(os.environ.get("CPP", "cpp")) cflags = os.environ.get("CFLAGS") if cflags is not None: cpp += cflags.split() 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: str, req_ver: int, required: bool = False): """ 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) -> 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") if os.path.exists(os.path.join(os.curdir, "system_shadowing")): self.swig_opts.append("-Isystem_shadowing") 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]) if sys.platform != "win32": # generate src/SWIG/x509_v_flag.h to overcome weaknesses of swig # https://todo.sr.ht/~mcepl/m2crypto/298 with open("src/SWIG/x509_v_flag.h", "w", encoding="utf-8") as x509_v_h: cmd = [shutil.which(os.environ.get("CC", "gcc"))] cflags = os.environ.get("CFLAGS") if cflags is not None: cmd += cflags.split() cmd += [ "-E", "-fdirectives-only", "-include", "openssl/x509_vfy.h", "-", ] pid = subprocess.Popen( cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, ) xout, xerr = pid.communicate("\n") if pid.returncode == 0: for line in xout.split("\n"): if line and line.find("X509_V_FLAG") > -1: print(line, file=x509_v_h) else: raise RuntimeError( f"gcc -E ended with return code {pid.returncode}" ) # 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")) if platform.system() == "Darwin": self.swig_opts.append("-cpperraswarn") 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.46.2/src/000077500000000000000000000000001506746742300141675ustar00rootroot00000000000000m2crypto-0.46.2/src/M2Crypto/000077500000000000000000000000001506746742300156465ustar00rootroot00000000000000m2crypto-0.46.2/src/M2Crypto/ASN1.py000066400000000000000000000203251506746742300167240ustar00rootroot00000000000000""" 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, Any MBSTRING_FLAG: int = 0x1000 MBSTRING_ASC: int = MBSTRING_FLAG | 1 MBSTRING_BMP: int = MBSTRING_FLAG | 2 class ASN1_Integer: 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: m2.asn1_integer_free(self.asn1int) def __int__(self) -> int: ret = m2.asn1_integer_get(self.asn1int) if ret is None: raise ValueError("ASN1_Integer value is NULL") return ret class ASN1_String: def __init__( self, asn1str: Union[C.ASN1_String, str, bytes], _pyfree: int = 0, ): self.asn1str: C.ASN1_String = m2.asn1_string_new() if isinstance(asn1str, str): encoded_str = asn1str.encode() m2.asn1_string_set(self.asn1str, encoded_str) elif isinstance(asn1str, bytes): 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): 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: 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: Optional[datetime.datetime]) -> datetime.timedelta: if self._isdst(dt): return self._dstoffset else: return self._stdoffset def dst(self, dt: Optional[datetime.datetime]) -> datetime.timedelta: if self._isdst(dt): return self._dstdiff else: return datetime.timedelta(0) def tzname(self, dt: Optional[datetime.datetime]) -> str: if dt is None: return "" return time.tzname[self._isdst(dt).real] def _isdst(self, dt: Optional[datetime.datetime]) -> bool: if dt is None: return False 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() # type: ignore [no-redef] self._pyfree = 1 self.owner: Any = None def __del__(self) -> None: if getattr(self, "_pyfree", 0): 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: str) -> 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'" 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.46.2/src/M2Crypto/AuthCookie.py000066400000000000000000000111041506746742300202500ustar00rootroot00000000000000"""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, Optional, Tuple, 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: float, data: str, format: str = _MIX_FORMAT) -> str: return format % (expiry, data) def unmix( dough: Union[str, bytes], regex: Pattern = _MIX_RE ) -> Optional[Tuple[float, str]]: mo = regex.match(dough) if mo: return float(mo.group(1)), mo.group(2) else: return None def unmix3( dough: Union[str, bytes], regex: Pattern = _MIX_RE ) -> Optional[Tuple[float, str, str]]: mo = regex.match(dough) if mo: return float(mo.group(1)), mo.group(2), mo.group(3) else: return None _TOKEN: str = "_M2AUTH_" class AuthCookie: def __init__(self, expiry: float, data: str, dough: str, mac: 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) -> float: """Return the cookie's expiry time.""" return self._expiry def data(self) -> str: """Return the data portion of the cookie.""" return self._data def mac(self) -> str: """Return the cookie's MAC.""" return self._mac def output(self, header: str = "Set-Cookie:") -> str: """Return the cookie's output in "Set-Cookie" format.""" return self._cookie.output(header=header) def value(self) -> str: """Return the cookie's output minus the "Set-Cookie: " portion.""" return self._cookie[_TOKEN].value def isExpired(self) -> 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) -> str: return self._name def headerValue(self) -> str: return self.value() class AuthCookieJar: _keylen: int = 20 def __init__(self) -> None: self._key = Rand.rand_bytes(self._keylen) def _hmac(self, key: bytes, data: str) -> str: return util.bin_to_hex(m2.hmac(key, data.encode(), m2.sha256())) def makeCookie(self, expiry: float, data: 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: AuthCookie) -> bool: if cookie.isExpired(): return False 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: Union[dict, str], _debug: bool = False ) -> bool: c = SimpleCookie() c.load(cookie_str) if _TOKEN not in c: log.debug("_TOKEN not in c (keys = %s)", dir(c)) return False undough = unmix3(c[_TOKEN].value) if undough is None: log.debug("undough is None") return False 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) m2crypto-0.46.2/src/M2Crypto/BIO.py000066400000000000000000000263431506746742300166410ustar00rootroot00000000000000"""M2Crypto wrapper for OpenSSL BIO API. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" import io import logging from typing import Callable, IO, Iterable, Optional, Union, TYPE_CHECKING from M2Crypto import m2, types as C if TYPE_CHECKING: import M2Crypto.SSL as SSL log = logging.getLogger("BIO") class BIOError(ValueError): pass m2.bio_init(BIOError) class BIO(object): """Abstract object interface to the BIO API.""" def __init__( self, bio: Optional[C.BIO] = None, _pyfree: int = 0, _close_cb: Optional[Callable] = None, ) -> 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 and self.bio: m2.bio_free(self.bio) def _ptr(self): return self.bio # Deprecated. bio_ptr = _ptr def fileno(self) -> int: if self.bio is None: raise BIOError("Uninitialized self.bio") return m2.bio_get_fd(self.bio) def readable(self) -> bool: return not self.closed def read(self, size: Optional[int] = None) -> Union[bytes, bytearray]: if not self.readable(): raise IOError("cannot read") if self.bio is None: raise BIOError("Uninitialized self.bio") 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: int = 4096) -> bytes: if not self.readable(): raise IOError("cannot read") if self.bio is None: raise BIOError("Uninitialized self.bio") buf = m2.bio_gets(self.bio, size) return b"" if buf is None else buf def readlines( self, sizehint: Union[str, bytes, int] = "ignored" ) -> Iterable[bytes]: if not self.readable(): raise IOError("cannot read") if self.bio is None: raise BIOError("Uninitialized self.bio") lines = [] while 1: buf = m2.bio_gets(self.bio, 4096) if buf is None: break lines.append(buf) return lines def writeable(self) -> bool: return (not self.closed) and (not self.write_closed) def write(self, data: Union[str, bytes]) -> 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 self.bio is None: raise BIOError("Uninitialized self.bio") if isinstance(data, str): data = data.encode("utf8") return m2.bio_write(self.bio, data) def write_close(self) -> None: self.write_closed = 1 def flush(self) -> None: """Flush the buffers. :return: 1 for success, and 0 or -1 for failure """ if self.bio is None: raise BIOError("Uninitialized self.bio") m2.bio_flush(self.bio) def reset(self) -> int: """Set the bio to its initial state. :return: 1 for success, and 0 or -1 for failure """ if self.bio is None: raise BIOError("Uninitialized self.bio") return m2.bio_reset(self.bio) def close(self) -> None: self.closed = 1 if self._close_cb: self._close_cb() def should_retry(self) -> int: """ Can the call be attempted again, or was there an error ie do_handshake """ if self.bio is None: raise BIOError("Uninitialized self.bio") return m2.bio_should_retry(self.bio) def should_read(self) -> int: """Should we read more data?""" if self.bio is None: raise BIOError("Uninitialized self.bio") return m2.bio_should_read(self.bio) def should_write(self) -> int: """Should we write more data?""" if self.bio is None: raise BIOError("Uninitialized self.bio") return m2.bio_should_write(self.bio) def tell(self): """Return the current offset.""" if self.bio is None: raise BIOError("Uninitialized self.bio") return m2.bio_tell(self.bio) def seek(self, off): """Seek to the specified absolute offset.""" if self.bio is None: raise BIOError("Uninitialized self.bio") return m2.bio_seek(self.bio, off) def __enter__(self): return self def __exit__(self, *args) -> None: 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: Optional[bytes] = None) -> None: super().__init__() 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) -> int: if self.bio is None: raise BIOError("Uninitialized self.bio") return m2.bio_ctrl_pending(self.bio) def read(self, size: Optional[int] = None) -> bytes: m2.err_clear_error() if not self.readable(): raise IOError("cannot read") if self.bio is None: raise BIOError("Uninitialized self.bio") if size is None: return m2.bio_read(self.bio, m2.bio_ctrl_pending(self.bio)) if size < 0: raise ValueError("read count is negative") return m2.bio_read(self.bio, size) # Backwards-compatibility. getvalue = read_all = read def write_close(self) -> None: super().write_close() if self.bio is None: raise BIOError("Uninitialized self.bio") 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_arg: Union[IO, str], close_pyfile: int = 1, mode: str = "rb", ) -> None: super().__init__(_pyfree=1) pyfile: IO if isinstance(pyfile_arg, str): pyfile = open(pyfile_arg, mode) else: pyfile = pyfile_arg pyfile.flush() self.fname = getattr(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) -> None: super().flush() self.pyfile.flush() def close(self) -> None: self.flush() super().close() if self.close_pyfile: self.pyfile.close() def reset(self) -> int: """Set the bio to its initial state. :return: 0 for success, and -1 for failure """ return super().reset() def openfile(filename: Union[str, bytes], mode: str = "rb") -> 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. """ def __init__(self, under_bio: BIO, mode: str = "rwb", _pyfree: int = 1) -> None: super().__init__(_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) -> None: if getattr(self, "_pyfree", 0): if self.bio: m2.bio_pop(self.bio) if self.io: m2.bio_free(self.io) def close(self) -> None: BIO.close(self) class CipherStream(BIO): """Object interface to BIO_f_cipher.""" SALT_LEN = m2.PKCS5_SALT_LEN def __init__(self, obio: BIO) -> None: super().__init__(_pyfree=1) self.obio = obio self.bio = m2.bio_new(m2.bio_f_cipher()) self.closed = 0 def __del__(self) -> None: if not getattr(self, "closed", 1): self.close() def close(self) -> None: if self.bio: m2.bio_pop(self.bio) m2.bio_free(self.bio) self.closed = 1 def write_close(self) -> None: self.obio.write_close() def set_cipher( self, algo: str, key: Union[str, bytes], iv: Union[str, bytes], op: 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: assert self.bio is not None m2.bio_set_cipher(self.bio, cipher(), key, iv, int(op)) except (OSError, ValueError) as ex: raise BIOError("BIOError: {}".format(str(ex))) assert self.bio is not None m2.bio_push(self.bio, self.obio._ptr()) class SSLBio(BIO): """Object interface to BIO_f_ssl.""" def __init__(self, _pyfree: int = 1) -> None: super().__init__(_pyfree=_pyfree) self.bio = m2.bio_new(m2.bio_f_ssl()) self.closed = 0 def set_ssl(self, conn: "SSL.Connection", close_flag: int = m2.bio_noclose) -> None: """ Sets the bio to the SSL pointer which is contained in the connection object. """ self._pyfree = 0 assert self.bio is not None m2.bio_set_ssl(self.bio, conn.ssl, close_flag) # type: ignore[arg-type] if close_flag == m2.bio_noclose: conn.set_ssl_close_flag(m2.bio_close) def do_handshake(self) -> int: """Do the handshake. Return 1 if the handshake completes Return 0 or a negative number if there is a problem """ assert self.bio is not None return m2.bio_do_handshake(self.bio) m2crypto-0.46.2/src/M2Crypto/BN.py000066400000000000000000000030431506746742300165170ustar00rootroot00000000000000""" 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: int, top: int = -1, bottom: int = 0) -> 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: 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: 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: list = [] for x in range(length): fname += [letters[m2.bn_rand_range(lettersLen)]] return "".join(fname) m2crypto-0.46.2/src/M2Crypto/DH.py000066400000000000000000000054411506746742300165170ustar00rootroot00000000000000"""M2Crypto wrapper for OpenSSL DH API. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from M2Crypto import BIO, m2, types as C from M2Crypto.util import genparam_callback from typing import Callable, Optional, Union # noqa class DHError(Exception): pass m2.dh_init(DHError) class DH(object): """Object interface to the Diffie-Hellman key exchange protocol.""" def __init__(self, dh: C.DH, _pyfree: int = 0) -> None: assert m2.dh_type_check(dh) self.dh = dh self._pyfree = _pyfree @staticmethod def m2_dh_free(dh: C.DH) -> None: m2.dh_free(dh) def __del__(self) -> None: if getattr(self, "_pyfree", 0): self.m2_dh_free(self.dh) def __len__(self) -> int: assert m2.dh_type_check(self.dh), "'dh' type error" return int(m2.dh_size(self.dh)) def __getattr__(self, name: 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: str, value: bytes) -> None: 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) -> int: assert m2.dh_type_check(self.dh), "'dh' type error" return m2.dh_check(self.dh) def gen_key(self) -> None: assert m2.dh_type_check(self.dh), "'dh' type error" m2.dh_generate_key(self.dh) def compute_key(self, pubkey: 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: 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: int, g: int, callback: Callable = genparam_callback, ) -> DH: dh_parms = m2.dh_generate_parameters(plen, g, callback) dh_obj = DH(dh_parms, 1) return dh_obj def load_params(file: Union[str, bytes]) -> DH: with BIO.openfile(file) as bio: return load_params_bio(bio) def load_params_bio(bio: BIO.BIO) -> DH: dh_ptr = m2.dh_read_parameters(bio._ptr()) if dh_ptr is None: raise DHError("Failed to load DH parameters.") return DH(dh_ptr, 1) def set_params(p: bytes, g: 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.46.2/src/M2Crypto/DSA.py000066400000000000000000000337031506746742300166350ustar00rootroot00000000000000""" 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, types as C from typing import Callable, NoReturn, Tuple, Union # noqa class DSAError(Exception): pass m2.dsa_init(DSAError) class DSA: """ 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('sha256') md.update(message) digest = md.final() dsa = DSA.gen_params(1024, cb) dsa.gen_key() r, s = dsa.sign(digest) good = dsa.verify(digest, r, s) if good: print(' ** success **') else: print(' ** verification failed **') """ def __init__(self, dsa: C.DSA, _pyfree: int = 0) -> 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 @staticmethod def m2_dsa_free(dsa: C.DSA) -> None: m2.dsa_free(dsa) def __del__(self) -> None: if getattr(self, "_pyfree", 0): self.m2_dsa_free(self.dsa) def __len__(self) -> 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: 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: str, value: 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: bytes, q: bytes, g: 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) -> 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: Union[str, bytes]) -> 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: 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: Union[str, bytes], cipher: str = "aes_128_cbc", callback: Callable = util.passphrase_callback, ) -> 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: BIO.BIO, cipher: str = "aes_128_cbc", callback: Callable = util.passphrase_callback, ) -> 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: Union[str, bytes]) -> 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: 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: 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: bytes, r: bytes, s: 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, digest: bytes = b"") -> NoReturn: raise DSAError("DSA_pub object has no private key") sign_asn1 = sign def check_key(self) -> int: """ :return: does DSA_pub contain a pub key? """ return m2.dsa_check_pub_key(self.dsa) save_key: Callable = DSA.save_pub_key save_key_bio: Callable = DSA.save_pub_key_bio # -------------------------------------------------------------- # factories and other functions def gen_params( bits: int, callback: Callable[[int, int], int] = util.genparam_callback, ) -> 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: bytes, q: bytes, g: 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: Union[str, bytes], callback: Callable = util.passphrase_callback, ) -> 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: BIO.BIO, callback: Callable = util.passphrase_callback) -> 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) if dsa is None: raise DSAError("failed to load DSA parameters") return DSA(dsa, 1) def load_key( file: Union[str, bytes], callback: Callable = util.passphrase_callback, ) -> 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: BIO.BIO, callback: Callable = util.passphrase_callback) -> 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) if dsa is None: raise DSAError("failed to load DSA key") return DSA(dsa, 1) def pub_key_from_params(p: bytes, q: bytes, g: bytes, pub: 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: Union[str, bytes], callback: Callable = util.passphrase_callback, ) -> 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: BIO.BIO, callback: Callable = util.passphrase_callback ) -> 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) if dsapub is None: raise DSAError("failed to load DSA public key") return DSA_pub(dsapub, 1) m2crypto-0.46.2/src/M2Crypto/EC.py000066400000000000000000000364501506746742300165170ustar00rootroot00000000000000""" 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 typing import Callable, Dict, List, NoReturn, Optional, Tuple, Union # noqa from M2Crypto import BIO, Err, EVP, m2, types as C, util EC_Key = bytes class ECError(Exception): pass m2.ec_init(ECError) # Curve identifier constants NID_secp112r1: int = m2.NID_secp112r1 NID_secp112r2: int = m2.NID_secp112r2 NID_secp128r1: int = m2.NID_secp128r1 NID_secp128r2: int = m2.NID_secp128r2 NID_secp160k1: int = m2.NID_secp160k1 NID_secp160r1: int = m2.NID_secp160r1 NID_secp160r2: int = m2.NID_secp160r2 NID_secp192k1: int = m2.NID_secp192k1 NID_secp224k1: int = m2.NID_secp224k1 NID_secp224r1: int = m2.NID_secp224r1 NID_secp256k1: int = m2.NID_secp256k1 NID_secp384r1: int = m2.NID_secp384r1 NID_secp521r1: int = m2.NID_secp521r1 NID_sect113r1: int = m2.NID_sect113r1 NID_sect113r2: int = m2.NID_sect113r2 NID_sect131r1: int = m2.NID_sect131r1 NID_sect131r2: int = m2.NID_sect131r2 NID_sect163k1: int = m2.NID_sect163k1 NID_sect163r1: int = m2.NID_sect163r1 NID_sect163r2: int = m2.NID_sect163r2 NID_sect193r1: int = m2.NID_sect193r1 NID_sect193r2: int = m2.NID_sect193r2 # default for secg.org TLS test server NID_sect233k1: int = m2.NID_sect233k1 NID_sect233r1: int = m2.NID_sect233r1 NID_sect239k1: int = m2.NID_sect239k1 NID_sect283k1: int = m2.NID_sect283k1 NID_sect283r1: int = m2.NID_sect283r1 NID_sect409k1: int = m2.NID_sect409k1 NID_sect409r1: int = m2.NID_sect409r1 NID_sect571k1: int = m2.NID_sect571k1 NID_sect571r1: int = m2.NID_sect571r1 NID_prime192v1: int = m2.NID_X9_62_prime192v1 NID_prime192v2: int = m2.NID_X9_62_prime192v2 NID_prime192v3: int = m2.NID_X9_62_prime192v3 NID_prime239v1: int = m2.NID_X9_62_prime239v1 NID_prime239v2: int = m2.NID_X9_62_prime239v2 NID_prime239v3: int = m2.NID_X9_62_prime239v3 NID_prime256v1: int = m2.NID_X9_62_prime256v1 NID_c2pnb163v1: int = m2.NID_X9_62_c2pnb163v1 NID_c2pnb163v2: int = m2.NID_X9_62_c2pnb163v2 NID_c2pnb163v3: int = m2.NID_X9_62_c2pnb163v3 NID_c2pnb176v1: int = m2.NID_X9_62_c2pnb176v1 NID_c2tnb191v1: int = m2.NID_X9_62_c2tnb191v1 NID_c2tnb191v2: int = m2.NID_X9_62_c2tnb191v2 NID_c2tnb191v3: int = m2.NID_X9_62_c2tnb191v3 NID_c2pnb208w1: int = m2.NID_X9_62_c2pnb208w1 NID_c2tnb239v1: int = m2.NID_X9_62_c2tnb239v1 NID_c2tnb239v2: int = m2.NID_X9_62_c2tnb239v2 NID_c2tnb239v3: int = m2.NID_X9_62_c2tnb239v3 NID_c2pnb272w1: int = m2.NID_X9_62_c2pnb272w1 NID_c2pnb304w1: int = m2.NID_X9_62_c2pnb304w1 NID_c2tnb359v1: int = m2.NID_X9_62_c2tnb359v1 NID_c2pnb368w1: int = m2.NID_X9_62_c2pnb368w1 NID_c2tnb431r1: int = m2.NID_X9_62_c2tnb431r1 # To preserve compatibility with older names NID_X9_62_prime192v1: int = NID_prime192v1 NID_X9_62_prime192v2: int = NID_prime192v2 NID_X9_62_prime192v3: int = NID_prime192v3 NID_X9_62_prime239v1: int = NID_prime239v1 NID_X9_62_prime239v2: int = NID_prime239v2 NID_X9_62_prime239v3: int = NID_prime239v3 NID_X9_62_prime256v1: int = NID_prime256v1 NID_X9_62_c2pnb163v1: int = NID_c2pnb163v1 NID_X9_62_c2pnb163v2: int = NID_c2pnb163v2 NID_X9_62_c2pnb163v3: int = NID_c2pnb163v3 NID_X9_62_c2pnb176v1: int = NID_c2pnb176v1 NID_X9_62_c2tnb191v1: int = NID_c2tnb191v1 NID_X9_62_c2tnb191v2: int = NID_c2tnb191v2 NID_X9_62_c2tnb191v3: int = NID_c2tnb191v3 NID_X9_62_c2pnb208w1: int = NID_c2pnb208w1 NID_X9_62_c2tnb239v1: int = NID_c2tnb239v1 NID_X9_62_c2tnb239v2: int = NID_c2tnb239v2 NID_X9_62_c2tnb239v3: int = NID_c2tnb239v3 NID_X9_62_c2pnb272w1: int = NID_c2pnb272w1 NID_X9_62_c2pnb304w1: int = NID_c2pnb304w1 NID_X9_62_c2tnb359v1: int = NID_c2tnb359v1 NID_X9_62_c2pnb368w1: int = NID_c2pnb368w1 NID_X9_62_c2tnb431r1: int = NID_c2tnb431r1 NID_wap_wsg_idm_ecid_wtls1: int = m2.NID_wap_wsg_idm_ecid_wtls1 NID_wap_wsg_idm_ecid_wtls3: int = m2.NID_wap_wsg_idm_ecid_wtls3 NID_wap_wsg_idm_ecid_wtls4: int = m2.NID_wap_wsg_idm_ecid_wtls4 NID_wap_wsg_idm_ecid_wtls5: int = m2.NID_wap_wsg_idm_ecid_wtls5 NID_wap_wsg_idm_ecid_wtls6: int = m2.NID_wap_wsg_idm_ecid_wtls6 NID_wap_wsg_idm_ecid_wtls7: int = m2.NID_wap_wsg_idm_ecid_wtls7 NID_wap_wsg_idm_ecid_wtls8: int = m2.NID_wap_wsg_idm_ecid_wtls8 NID_wap_wsg_idm_ecid_wtls9: int = m2.NID_wap_wsg_idm_ecid_wtls9 NID_wap_wsg_idm_ecid_wtls10: int = m2.NID_wap_wsg_idm_ecid_wtls10 NID_wap_wsg_idm_ecid_wtls11: int = m2.NID_wap_wsg_idm_ecid_wtls11 NID_wap_wsg_idm_ecid_wtls12: int = m2.NID_wap_wsg_idm_ecid_wtls12 # 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. """ def __init__(self, ec: C.EC_KEY, _pyfree: int = 0) -> None: assert m2.ec_key_type_check(ec), "'ec' type error" self.ec = ec self._pyfree = _pyfree @staticmethod def m2_ec_key_free(ec: C.EC_KEY) -> None: m2.ec_key_free(ec) def __del__(self) -> None: if getattr(self, "_pyfree", 0): self.m2_ec_key_free(self.ec) def __len__(self) -> int: assert m2.ec_key_type_check(self.ec), "'ec' type error" return m2.ec_key_keylen(self.ec) def gen_key(self) -> None: """ 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) -> "EC_pub": # Don't let python free return EC_pub(self.ec, 0) def sign_dsa(self, digest: 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: bytes, r: bytes, s: 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: bytes) -> bytes: assert self._check_key_type(), "'ec' type error" return m2.ecdsa_sign_asn1(self.ec, digest) def verify_dsa_asn1(self, digest: bytes, blob: bytes) -> int: assert self._check_key_type(), "'ec' type error" return m2.ecdsa_verify_asn1(self.ec, digest, blob) def compute_dh_key(self, pub_key: "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: BIO.BIO, cipher: Optional[str] = "aes_128_cbc", callback: Callable = util.passphrase_callback, ) -> 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: Union[str, bytes], cipher: Optional[str] = "aes_128_cbc", callback: Callable = util.passphrase_callback, ) -> 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: 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: Union[str, bytes]) -> 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: str = "aes_128_cbc", callback: Callable = util.passphrase_callback, ) -> bytes: """ 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) -> int: return m2.ec_key_type_check(self.ec) def check_key(self) -> 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: C.EC_KEY, _pyfree: int = 0) -> None: EC.__init__(self, ec, _pyfree) self.der: Optional[bytes] = None def get_der(self) -> 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) -> 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: Callable = EC.save_pub_key # type: ignore[assignment] save_key_bio: Callable = EC.save_pub_key_bio # type: ignore[assignment] def gen_params(curve: 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: Union[str, bytes], callback: Callable = util.passphrase_callback, ) -> 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: str, callback: Callable = util.passphrase_callback) -> 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.encode()) as bio: return load_key_bio(bio, callback) def load_key_bio(bio: BIO.BIO, callback: Callable = util.passphrase_callback) -> 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. """ key = m2.ec_key_read_bio(bio._ptr(), callback) if key is None: raise IOError( "Cannot read EC key pair from PEM file {}.".format( getattr(bio, "fname", "in-memory buffer") ) ) return EC(key, 1) def load_pub_key(file: Union[str, bytes]) -> 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: str, callback: Callable = util.passphrase_callback ) -> "EVP.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. """ from M2Crypto.EVP import load_key_bio_pubkey with BIO.MemoryBuffer(string.encode()) as bio: return load_key_bio_pubkey(bio, callback) def load_pub_key_bio(bio: 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() -> NoReturn: raise ECError(Err.get_error_message()) def pub_key_from_der(der: 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: int, 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() -> List[Dict[str, Union[int, str]]]: return m2.ec_get_builtin_curves() m2crypto-0.46.2/src/M2Crypto/EVP.py000066400000000000000000000451161506746742300166610ustar00rootroot00000000000000"""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, types as C from typing import Optional, Callable, Union # noqa log = logging.getLogger("EVP") class EVPError(ValueError): pass m2.evp_init(EVPError) def pbkdf2(password: bytes, salt: bytes, iter: int, keylen: 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 """ @staticmethod def m2_md_ctx_free(ctx: C.EVP_MD_CTX) -> None: m2.md_ctx_free(ctx) def __init__(self, algo: str) -> None: md: Optional[Callable] = getattr(m2, algo, None) 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) if self.md is None: raise EVPError("unknown algorithm %s" % (algo,)) else: self.md = md() self.ctx = m2.md_ctx_new() m2.digest_init(self.ctx, self.md) def __del__(self) -> None: if getattr(self, "ctx", None): self.m2_md_ctx_free(self.ctx) def update(self, data: 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): @staticmethod def m2_hmac_ctx_free(ctx: C.HMAC_CTX) -> None: m2.hmac_ctx_free(ctx) def __init__(self, key: bytes, algo: str = "sha256") -> 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) -> None: if getattr(self, "ctx", None): self.m2_hmac_ctx_free(self.ctx) def reset(self, key: bytes) -> None: m2.hmac_init(self.ctx, key, self.md) def update(self, data: bytes) -> None: m2.hmac_update(self.ctx, data) def final(self) -> bytes: return m2.hmac_final(self.ctx) digest = final def hmac(key: bytes, data: bytes, algo: str = "sha256") -> bytes: md = getattr(m2, algo, None) if md is None: raise ValueError("unknown algorithm", algo) return m2.hmac(key, data, md()) class Cipher(object): @staticmethod def m2_cipher_ctx_free(ctx: C.EVP_CIPHER_CTX) -> None: m2.cipher_ctx_free(ctx) def __init__( self, alg: str, key: bytes, iv: bytes, op: int, key_as_bytes: int = 0, d: str = "md5", salt: bytes = b"12345678", i: int = 1, padding: int = 1, ) -> 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) -> None: if getattr(self, "ctx", None): self.m2_cipher_ctx_free(self.ctx) def update(self, data: bytes) -> bytes: return m2.cipher_update(self.ctx, data) def final(self) -> bytes: return m2.cipher_final(self.ctx) def set_padding(self, padding: int = 1) -> 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"). """ def __init__( self, pkey: Optional[C.EVP_PKEY] = None, _pyfree: int = 0, md: str = "sha256", ) -> None: if pkey is not None: self.pkey = pkey self._pyfree = _pyfree else: self.pkey = m2.pkey_new() self._pyfree = 1 self._set_context(md) @staticmethod def _m2_pkey_free(pkey: C.EVP_PKEY) -> None: m2.pkey_free(pkey) @staticmethod def _m2_md_ctx_free(ctx: C.EVP_MD_CTX) -> None: m2.md_ctx_free(ctx) def __del__(self) -> 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: str) -> None: if not md: self.md = None else: mda: Optional[Callable] = getattr(m2, md, None) if mda is None: raise ValueError("unknown message digest", md) self.md = mda() self.ctx: C.EVP_MD_CTX = m2.md_ctx_new() def reset_context(self, md: str = "sha256") -> None: """ Reset internal message digest context. :param md: The message digest algorithm. """ self._set_context(md) def sign_init(self) -> None: """ Initialise signing operation with self. """ if self.md is None: raise EVPError("Digest algorithm not set") m2.sign_init(self.ctx, self.md) def sign_update(self, data: bytes) -> None: """ Feed data to signing operation. :param data: Data to be signed. """ m2.sign_update(self.ctx, data) def sign_final(self) -> 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) -> None: """ Initialise signature verification operation with self. """ if self.md is None: raise EVPError("Digest algorithm not set") m2.verify_init(self.ctx, self.md) def verify_update(self, data: 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: 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) -> 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: 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) -> bytes: """ Return signature. :return: The signature. """ return m2.digest_sign_final(self.ctx) def digest_sign(self, data: bytes) -> bytes: """ Return signature. :return: The signature. """ if not hasattr(m2, "digest_sign"): raise NotImplemented( "This method requires OpenSSL version " + "1.1.1 or greater." ) # type: ignore[misc] return m2.digest_sign(self.ctx, data) def digest_verify_init(self) -> 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: 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: 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: bytes, data: 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 not hasattr(m2, "digest_verify"): raise NotImplemented( "This method requires OpenSSL version " + "1.1.1 or greater." ) # type: ignore[misc] return m2.digest_verify(self.ctx, sign, data) def assign_rsa(self, rsa: RSA.RSA, capture: int = 1) -> 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) -> 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) if rsa_ptr is None: raise EVPError("Not an RSA key") rsa = RSA.RSA_pub(rsa_ptr, 1) return rsa def assign_ec(self, ec: "EC.EC", capture: int = 1) -> 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) -> "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) if ec_ptr is None: raise ValueError("Not an EC key") ec = EC.EC_pub(ec_ptr, 1) return ec def save_key( self, file: Union[str, bytes], cipher: Optional[str] = "aes_128_cbc", callback: Callable = util.passphrase_callback, ) -> 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: BIO.BIO, cipher: Optional[str] = "aes_128_cbc", callback: Callable = util.passphrase_callback, ) -> 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: Optional[str] = "aes_128_cbc", callback: Callable = util.passphrase_callback, ) -> 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) -> 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) -> int: """ Return the size of the key in bytes. """ return m2.pkey_size(self.pkey) def get_modulus(self) -> Optional[bytes]: """ Return the modulus in hex format. """ return m2.pkey_get_modulus(self.pkey) def get_key_identifier(self) -> bytes: """ Return the Subject Key Identifier (SKID) calculated as the SHA-1 hash of the raw public key bytes (method 1 in RFC 5280, section 4.2.1.2). :return: SHA1 digest (20 bytes) of the public key. """ return m2.pkey_get_raw_pub_key_sha1(self.pkey) def load_key( file: Union[str, bytes], callback: Callable = util.passphrase_callback, ) -> 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: Union[str, bytes], callback: Callable = util.passphrase_callback, ) -> 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: BIO.BIO, callback: Callable = util.passphrase_callback) -> 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: BIO.BIO, callback: Callable = util.passphrase_callback ) -> 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: Union[str, bytes], callback: Callable = util.passphrase_callback, ) -> 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. """ data = string.encode("utf8") if isinstance(string, str) else string bio = BIO.MemoryBuffer(data) return load_key_bio(bio, callback) def load_key_string_pubkey( string: Union[str, bytes], callback: Callable = util.passphrase_callback, ) -> 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. """ data = string.encode("utf8") if isinstance(string, str) else string bio = BIO.MemoryBuffer(data) return load_key_bio_pubkey(bio, callback) m2crypto-0.46.2/src/M2Crypto/Err.py000066400000000000000000000035521506746742300167550ustar00rootroot00000000000000"""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() -> Optional[str]: err = BIO.MemoryBuffer() m2.err_print_errors(err.bio_ptr()) err_msg = err.read() if err_msg: return err_msg.decode() return None def get_error_code() -> int: return m2.err_get_error() def peek_error_code() -> int: return m2.err_peek_error() def get_error_lib(err: Optional[int]) -> str: if err is None: return "" err_str = m2.err_lib_error_string(err) return err_str if err_str else "" def get_error_func(err: Optional[int]) -> str: if err is None: return "" err_str = m2.err_func_error_string(err) return err_str if err_str else "" def get_error_reason(err: Optional[int]) -> str: if err is None: return "" err_str = m2.err_reason_error_string(err) return err_str if err_str else "" def get_error_message() -> str: return get_error_reason(get_error_code()) def get_x509_verify_error(err: Optional[int]) -> str: if err is None: return "" err_str = m2.x509_get_verify_error(err) return err_str if err_str else "" class SSLError(Exception): def __init__(self, err: int, client_addr: util.AddrType) -> None: self.err = err self.client_addr = client_addr def __str__(self) -> str: if not isinstance(self.client_addr, str): s = ( self.client_addr if isinstance(self.client_addr, str) else str(self.client_addr) ) 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.46.2/src/M2Crypto/RC4.py000066400000000000000000000015011506746742300166050ustar00rootroot00000000000000"""M2Crypto wrapper for OpenSSL RC4 API. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" from typing import Optional from M2Crypto import m2, types as C class RC4(object): """Object interface to the stream cipher RC4.""" def __init__(self, key: Optional[bytes] = None) -> None: self.cipher = m2.rc4_new() if key: m2.rc4_set_key(self.cipher, key) @staticmethod def rc4_free(cipher: C.RC4_KEY) -> None: m2.rc4_free(cipher) def __del__(self) -> None: if getattr(self, "cipher", None): self.rc4_free(self.cipher) def set_key(self, key: bytes) -> None: m2.rc4_set_key(self.cipher, key) def update(self, data: bytes) -> bytes: return m2.rc4_update(self.cipher, data) def final(self) -> str: return "" m2crypto-0.46.2/src/M2Crypto/RSA.py000066400000000000000000000365761506746742300166660ustar00rootroot00000000000000"""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, types as C from typing import Callable, IO, Optional, Tuple, Union, Any # 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. """ def __init__(self, rsa: C.RSA, _pyfree: int = 0) -> None: """ :param rsa: OpenSSL RSA object """ self.rsa = rsa self._pyfree = _pyfree self._check_cache: Optional[int] = None def __del__(self) -> None: if getattr(self, "_pyfree", 0): # FIX: Call module function directly to avoid implicit 'self' m2.rsa_free(self.rsa) def __len__(self) -> int: return int(m2.rsa_size(self.rsa) << 3) def __getattr__(self, name: 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(name) def pub(self) -> Tuple[bytes, bytes]: if self.check_key() != 1: raise RSAError("key is not initialized") return m2.rsa_get_e(self.rsa), m2.rsa_get_n(self.rsa) def public_encrypt(self, data: bytes, padding: int) -> bytes: if self.check_key() != 1: raise RSAError("key is not initialized") return m2.rsa_public_encrypt(self.rsa, data, padding) def public_decrypt(self, data: bytes, padding: int) -> Optional[bytes]: # FIX: Return type is Optional[bytes] because it can fail. if self.check_key() != 1: raise RSAError("key is not initialized") return m2.rsa_public_decrypt(self.rsa, data, padding) def private_encrypt(self, data: bytes, padding: int) -> bytes: if self.check_key() != 1: raise RSAError("key is not initialized") return m2.rsa_private_encrypt(self.rsa, data, padding) def private_decrypt(self, data: bytes, padding: int) -> Optional[bytes]: # FIX: Return type is Optional[bytes] because it can fail. if self.check_key() != 1: raise RSAError("key is not initialized") return m2.rsa_private_decrypt(self.rsa, data, padding) def save_key_bio( self, bio: BIO.BIO, cipher: Optional[str] = "aes_128_cbc", callback: Callable[..., Any] = util.passphrase_callback, ) -> 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 bio.bio is None: raise RSAError("Uninitialized bio.bio") if cipher is None: return m2.rsa_write_key_no_cipher(self.rsa, bio.bio, callback) else: ciph = getattr(m2, cipher, None) if ciph is None: raise RSAError("not such cipher %s" % cipher) else: ciph_obj = ciph() return m2.rsa_write_key(self.rsa, bio.bio, ciph_obj, callback) def save_key( self, file: Union[str, bytes], cipher: Optional[str] = "aes_128_cbc", callback: Callable[..., Any] = util.passphrase_callback, ) -> 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: Optional[str] = "aes_128_cbc", callback: Callable[..., Any] = util.passphrase_callback, ) -> bytes: """ Returns the key(pair) as a string in PEM format. """ bio = BIO.MemoryBuffer() self.save_key_bio(bio, cipher, callback) return bio.read() or b"" def save_key_der_bio(self, bio: 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. """ if bio.bio is None: raise RSAError("Uninitialized bio.bio") return m2.rsa_write_key_der(self.rsa, bio.bio) def save_key_der(self, file: Union[str, bytes]) -> 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: 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. """ if bio.bio is None: raise RSAError("Uninitialized bio.bio") return m2.rsa_write_pub_key(self.rsa, bio.bio) def save_pub_key(self, file: Union[str, bytes]) -> 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 self.save_pub_key_bio(bio) def check_key(self) -> 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). """ if self._check_cache is not None: return self._check_cache self._check_cache = m2.rsa_check_key(self.rsa) return self._check_cache def sign_rsassa_pss( self, digest: bytes, algo: str = "sha256", salt_length: int = 20 ) -> 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_func = getattr(m2, algo, None) if hash_func is None: raise RSAError("not such hash algorithm %s" % algo) signature = m2.rsa_padding_add_pkcs1_pss( self.rsa, digest, hash_func(), salt_length ) return self.private_encrypt(signature, no_padding) def verify_rsassa_pss( self, data: bytes, signature: bytes, algo: str = "sha256", salt_length: int = 20, ) -> 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_func = getattr(m2, algo, None) if hash_func is None: raise RSAError("not such hash algorithm %s" % algo) plain_signature = self.public_decrypt(signature, no_padding) if plain_signature is None: return 0 # Decrypt failed, so verification fails return m2.rsa_verify_pkcs1_pss( self.rsa, data, plain_signature, hash_func(), salt_length ) def sign(self, digest: bytes, algo: str = "sha256") -> 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: bytes, signature: bytes, algo: str = "sha256") -> 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) def set_ex_data(self, index: int, data: Any) -> int: if self.check_key() != 1: raise RSAError("key is not initialized") return m2.rsa_set_ex_data(self.rsa, index, data) def get_ex_data(self, index: int) -> Any: if self.check_key() != 1: raise RSAError("key is not initialized") return m2.rsa_get_ex_data(self.rsa, index) class RSA_pub(RSA): """ Object interface to an RSA public key. """ def __setattr__(self, name: str, value: Any) -> 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: Any) -> None: # type: ignore[override] raise RSAError("RSA_pub object has no private key") def private_decrypt(self, *argv: Any) -> None: # type: ignore[override] raise RSAError("RSA_pub object has no private key") def save_key(self, file: Union[str, bytes], *args: Any, **kw: Any) -> int: """ Save public key to file. """ return self.save_pub_key(file) def save_key_bio(self, bio: BIO.BIO, *args: Any, **kw: Any) -> int: """ Save public key to BIO. """ return self.save_pub_key_bio(bio) def check_key(self) -> int: return m2.rsa_check_pub_key(self.rsa) def rsa_error() -> None: raise RSAError(Err.get_error_message()) def keygen_callback(p: int, n: int) -> int: """ Default callback for gen_key(). """ ch = [".", "+", "*", "\n"] sys.stdout.write(ch[p]) sys.stdout.flush() return 1 def gen_key( bits: int, e: int, callback: Callable[[int, int], int] = keygen_callback, ) -> 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. """ rsa_obj = m2.rsa_generate_key(bits, e, callback) if rsa_obj is None: rsa_error() return RSA(rsa_obj, 1) def load_key( file: Union[str, bytes], callback: Callable[..., Any] = util.passphrase_callback, ) -> 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: BIO.BIO, callback: Callable[..., Any] = util.passphrase_callback ) -> 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. """ if bio.bio is None: raise RSAError("Uninitialized bio.bio") rsa = m2.rsa_read_key(bio.bio, callback) if rsa is None: rsa_error() return RSA(rsa, 1) def load_key_string( string: Union[str, bytes], callback: Callable[..., Any] = util.passphrase_callback, ) -> 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. """ bytes_to_load = string.encode("utf-8") if isinstance(string, str) else string bio = BIO.MemoryBuffer(bytes_to_load) return load_key_bio(bio, callback) def load_pub_key(file: Union[str, bytes]) -> 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: 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. """ if bio.bio is None: raise RSAError("Uninitialized bio.bio") rsa = m2.rsa_read_pub_key(bio.bio) if rsa is None: rsa_error() return RSA_pub(rsa, 1) def new_pub_key(e_n: 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.46.2/src/M2Crypto/Rand.py000066400000000000000000000105661506746742300171140ustar00rootroot00000000000000"""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 M2Crypto import m2 from typing import Tuple, Union # 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: bytes, entropy: 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: 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() -> 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() -> 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: Union[str, bytes], max_bytes: 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: Union[str, bytes]) -> 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. """ if isinstance(filename, bytes): filename = filename.decode() return m2.rand_save_file(filename) # pylint: disable=no-member def rand_bytes(num: 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: 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.46.2/src/M2Crypto/SMIME.py000066400000000000000000000212571506746742300171010ustar00rootroot00000000000000"""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, types as C from typing import Callable, Optional, Tuple, Union # noqa PKCS7_TEXT: int = m2.PKCS7_TEXT PKCS7_NOCERTS: int = m2.PKCS7_NOCERTS PKCS7_NOSIGS: int = m2.PKCS7_NOSIGS PKCS7_NOCHAIN: int = m2.PKCS7_NOCHAIN PKCS7_NOINTERN: int = m2.PKCS7_NOINTERN PKCS7_NOVERIFY: int = m2.PKCS7_NOVERIFY PKCS7_DETACHED: int = m2.PKCS7_DETACHED PKCS7_BINARY: int = m2.PKCS7_BINARY PKCS7_NOATTR: int = m2.PKCS7_NOATTR PKCS7_SIGNED: int = m2.PKCS7_SIGNED PKCS7_ENVELOPED: int = m2.PKCS7_ENVELOPED PKCS7_SIGNED_ENVELOPED: int = m2.PKCS7_SIGNED_ENVELOPED # Deprecated PKCS7_DATA: int = m2.PKCS7_DATA class PKCS7_Error(Exception): pass m2.pkcs7_init(PKCS7_Error) class PKCS7(object): def __init__(self, pkcs7: Optional[C.PKCS7] = None, _pyfree: int = 0) -> 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 @staticmethod def _m2_pkcs7_free(p7: C.PKCS7) -> None: m2.pkcs7_free(p7) def __del__(self) -> None: if getattr(self, "_pyfree", 0): self._m2_pkcs7_free(self.pkcs7) def _ptr(self): return self.pkcs7 def type(self, text_name: int = 0) -> Union[int, str]: if text_name: return m2.pkcs7_type_sn(self.pkcs7) else: return m2.pkcs7_type_nid(self.pkcs7) def write(self, bio: BIO.BIO) -> int: return m2.pkcs7_write_bio(self.pkcs7, bio._ptr()) def write_der(self, bio: BIO.BIO) -> int: return m2.pkcs7_write_bio_der(self.pkcs7, bio._ptr()) def get0_signers(self, certs: X509.X509_Stack, flags: int = 0) -> X509.X509_Stack: return X509.X509_Stack(m2.pkcs7_get0_signers(self.pkcs7, certs.stack, flags), 1) def load_pkcs7(p7file: Union[str, bytes]) -> 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: Union[str, bytes]) -> 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: BIO.BIO) -> PKCS7: p7_ptr = m2.pkcs7_read_bio(p7_bio._ptr()) return PKCS7(p7_ptr, 1) def load_pkcs7_bio_der(p7_bio: BIO.BIO) -> PKCS7: p7_ptr = m2.pkcs7_read_bio_der(p7_bio._ptr()) return PKCS7(p7_ptr, 1) def smime_load_pkcs7(p7file: Union[str, bytes]) -> Tuple[PKCS7, Optional[BIO.BIO]]: filename = p7file.decode() if isinstance(p7file, bytes) else p7file bio = m2.bio_new_file(filename, "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: BIO.BIO) -> Tuple[PKCS7, Optional[BIO.BIO]]: 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: 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: Union[str, bytes], certfile: Union[str, bytes, None] = None, callback: Callable = util.passphrase_callback, ) -> 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: BIO.BIO, certbio: Optional[BIO.BIO] = None, callback: Callable = util.passphrase_callback, ) -> 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: X509.X509_Stack) -> None: assert isinstance(stack, X509.X509_Stack) self.x509_stack = stack def set_x509_store(self, store: X509.X509_Store) -> None: assert isinstance(store, X509.X509_Store) self.x509_store = store def set_cipher(self, cipher: Cipher) -> None: assert isinstance(cipher, Cipher) self.cipher = cipher def unset_key(self) -> None: del self.pkey del self.x509 def unset_x509_stack(self) -> None: del self.x509_stack def unset_x509_store(self) -> None: del self.x509_store def unset_cipher(self) -> None: del self.cipher def encrypt(self, data_bio: BIO.BIO, flags: int = 0) -> 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: PKCS7, flags: int = 0) -> 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: BIO.BIO, flags: int = 0, algo: str = "sha256", ) -> 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: PKCS7, data_bio: Optional[BIO.BIO] = None, flags: int = 0, ) -> 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: BIO.BIO, pkcs7: PKCS7, data_bio: Optional[BIO.BIO] = None, flags: int = 0, ) -> int: 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: 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: 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.46.2/src/M2Crypto/SSL/000077500000000000000000000000001506746742300163075ustar00rootroot00000000000000m2crypto-0.46.2/src/M2Crypto/SSL/Checker.py000066400000000000000000000270601506746742300202320ustar00rootroot00000000000000""" 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 Optional, Union # noqa try: from re import Pattern except ImportError: from typing import Pattern class SSLVerificationError(Exception): pass class NoCertificate(SSLVerificationError): pass class WrongCertificate(SSLVerificationError): pass class WrongHost(SSLVerificationError): def __init__( self, expectedHost: str, actualHost: Union[str, bytes], fieldName: str = "commonName", ) -> 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) -> str: actual = ( self.actualHost.decode() if isinstance(self.actualHost, bytes) else self.actualHost ) return "Peer certificate %s does not match host, expected %s, got %s" % ( self.fieldName, self.expectedHost, actual, ) class Checker: # COMPATIBILITY: re.Pattern is available only from Python 3.7+ numericIpMatch: Pattern[str] = re.compile(r"^[0-9]+(\.[0-9]+)*$") def __init__( self, host: Optional[str] = None, peerCertHash: Optional[bytes] = None, peerCertDigest: str = "sha256", ) -> None: self.host = host self.fingerprint = peerCertHash self.digest: str = peerCertDigest def __call__( self, peerCert: Optional[X509.X509], host: Optional[str] = None ) -> bool: if peerCert is None: raise NoCertificate("peer did not return certificate") if host is not None: self.host = host if self.fingerprint: if self.digest not in ("sha256"): raise ValueError('unsupported digest "%s"' % self.digest) if self.digest == "sha256": expected_len = 64 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: Union[str, bytes], subjectAltName: Union[str, bytes], ) -> 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 """ host_str = host.decode() if isinstance(host, bytes) else host san_str = ( subjectAltName.decode() if isinstance(subjectAltName, bytes) else subjectAltName ) self.useSubjectAltNameOnly = False for certHost in san_str.split(","): certHost = certHost.lower().strip() if certHost[:4] == "dns:": self.useSubjectAltNameOnly = True if self._match(host_str, certHost[4:]): return True elif certHost[:11] == "ip address:": self.useSubjectAltNameOnly = True if self._matchIPAddress(host_str, certHost[11:]): return True return False def _match(self, host: str, certHost: 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: Union[str, bytes], certHost: Union[str, bytes] ) -> 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.46.2/src/M2Crypto/SSL/Cipher.py000066400000000000000000000026461506746742300201030ustar00rootroot00000000000000"""SSL Ciphers Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" __all__ = ["Cipher", "Cipher_Stack"] from M2Crypto import m2, types as C from typing import Iterable # noqa class Cipher(object): cipher: C.SSL_CIPHER def __init__(self, cipher: C.SSL_CIPHER, _pyfree: int = 0) -> None: self.cipher = cipher def __len__(self) -> int: return m2.ssl_cipher_get_bits(self.cipher) def __repr__(self) -> str: return "%s-%s" % (self.name(), len(self)) def __str__(self) -> str: return "%s-%s" % (self.name(), len(self)) def version(self) -> str: return m2.ssl_cipher_get_version(self.cipher) def name(self) -> str: return m2.ssl_cipher_get_name(self.cipher) class Cipher_Stack(object): stack: C.STACK_OF_SSL_CIPHER def __init__(self, stack: C.STACK_OF_SSL_CIPHER, _pyfree: int = 0) -> None: """ :param stack: binary of the C-type STACK_OF(SSL_CIPHER) """ self.stack = stack def __len__(self) -> int: return m2.sk_ssl_cipher_num(self.stack) def __getitem__(self, idx: 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) -> Iterable: for i in range(m2.sk_ssl_cipher_num(self.stack)): yield self[i] m2crypto-0.46.2/src/M2Crypto/SSL/Connection.py000066400000000000000000000613621506746742300207700ustar00rootroot00000000000000"""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, types as C from .Checker import Checker, SSLVerificationError from .Cipher import Cipher, Cipher_Stack from .Session import Session from .SSLError import SSLError from .timeout import timeout as Timeout, struct_to_timeout, struct_size from typing import ( Callable, TYPE_CHECKING, Optional, Tuple, Union, ) if TYPE_CHECKING: from .Context import Context __all__ = [ "Connection", ] log = logging.getLogger(__name__) def _serverPostConnectionCheck(*args, **kw) -> int: return 1 class Connection: """An SSL connection.""" def __init__( self, ctx: "Context", sock: Optional[socket.socket] = None, family: int = socket.AF_INET, ) -> 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() self._bio_freed = False self.ctx = ctx self.ssl: C.SSL = m2.ssl_new(self.ctx.ctx) 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: float timeout_val = self.socket.gettimeout() if timeout_val is None: self._timeout = -1.0 else: self._timeout = timeout_val 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: Optional[bytes] = None self._closed = False m2_bio_noclose = m2.bio_noclose @staticmethod def m2_ssl_free(ssl: C.SSL) -> None: m2.ssl_free(ssl) @staticmethod def m2_bio_free(bio: C.BIO) -> int: return m2.bio_free(bio) @property def closed(self) -> bool: return self._closed def _free_bio(self): """ Free the sslbio and sockbio, and close the socket. """ if not self._bio_freed: if getattr(self, "sslbio", None) and self.sslbio: self.m2_bio_free(self.sslbio) if getattr(self, "sockbio", None) and self.sockbio: self.m2_bio_free(self.sockbio) self.socket.close() self._bio_freed = True def __del__(self) -> None: if not self._closed: self.close() if self.ssl_close_flag == self.m2_bio_noclose and getattr(self, "ssl", None): self.m2_ssl_free(self.ssl) def close(self, freeBio: Optional[bool] = True) -> None: """ if freeBio is true, call _free_bio """ if self._closed: return self._closed = True m2.ssl_shutdown(self.ssl) if freeBio: self._free_bio() def clear(self) -> 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: 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) -> int: """Get the current shutdown mode of the Connection.""" return m2.ssl_get_shutdown(self.ssl) def bind(self, addr: util.AddrType) -> None: self.socket.bind(addr) def listen(self, qlen: int = 5) -> None: self.socket.listen(qlen) def ssl_get_error(self, ret: int) -> int: return m2.ssl_get_error(self.ssl, ret) def set_bio(self, readbio: BIO.BIO, writebio: 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: str) -> 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) -> 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: util.AddrType) -> None: self.addr = addr def set_ssl_close_flag(self, flag: 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) -> 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: util.AddrType) -> None: """Deprecated""" self.setup_addr(addr) self.setup_ssl() def set_accept_state(self) -> None: """Sets Connection to work in the server mode.""" m2.ssl_set_accept_state(self.ssl) def accept_ssl(self) -> 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) -> 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, "serverPostConnectionCheck", _serverPostConnectionCheck, ) if check is not None: if self.host is not None: hostname = ( self.host if isinstance(self.host, str) else self.host.decode("utf-8") ) else: hostname = self.addr[0] if not check(ssl.get_peer_cert(), hostname): raise SSLVerificationError("post connection check failed") return ssl, addr def set_connect_state(self) -> None: """Sets Connection to work in the client mode.""" m2.ssl_set_connect_state(self.ssl) def connect_ssl(self) -> Optional[int]: return m2.ssl_connect(self.ssl, self._timeout) def connect(self, addr: util.AddrType) -> Optional[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: peer_cert = self.get_peer_cert() if self.host is not None: hostname = ( self.host if isinstance(self.host, str) else self.host.decode("utf-8") ) else: hostname = self.addr[0] if not check(peer_cert, hostname): raise SSLVerificationError("post connection check failed") return ret def shutdown(self, how: int) -> None: m2.ssl_set_shutdown1(self.ssl, how) def renegotiate(self) -> int: """Renegotiate this connection's SSL parameters.""" return m2.ssl_renegotiate(self.ssl) def pending(self) -> int: """Return the numbers of octets that can be read from the connection.""" return m2.ssl_pending(self.ssl) def write(self, data: bytes) -> int: return m2.ssl_write(self.ssl, data, self._timeout) sendall = send = write def _decref_socketios(self): pass def recv_into(self, buff: Union[bytearray, memoryview], nbytes: int = 0) -> 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 must be > 0") # buff_bytes are actual bytes returned buff_bytes = m2.ssl_read(self.ssl, n, self._timeout) if buff_bytes is None: return 0 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: int = 1024) -> bytes: if size <= 0: raise ValueError("size <= 0") ret: Optional[bytes] = m2.ssl_read(self.ssl, size, self._timeout) return ret if ret is not None else b"" recv = read def readable(self) -> bool: return True def writable(self) -> bool: return True def readinto(self, b: bytearray) -> int: return self.recv_into(b) def flush(self) -> None: pass def setblocking(self, mode: 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(bool(mode)) if mode: self._timeout = -1.0 else: self._timeout = 0.0 def settimeout(self, timeout: float) -> None: """Set this connection's underlying socket's timeout to _timeout_.""" self.socket.settimeout(timeout) if timeout is None: self._timeout = -1.0 else: self._timeout = timeout def fileno(self) -> int: return self.socket.fileno() def getsockopt( self, level: int, optname: int, buflen: Optional[int] = None ) -> 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). """ if buflen is None: return self.socket.getsockopt(level, optname) else: return self.socket.getsockopt(level, optname, buflen) def setsockopt( self, level: int, optname: int, value: Union[int, bytes, None] = 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. """ if value is None: raise TypeError("value must not be None for setsockopt") return self.socket.setsockopt(level, optname, value) def get_context(self) -> "Context": """Return the Context object associated with this connection.""" return self.ctx def get_state(self) -> str: """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) -> bool: return m2.ssl_get_verify_result(self.ssl) == m2.X509_V_OK def get_verify_mode(self) -> int: """Return the peer certificate verification mode.""" return m2.ssl_get_verify_mode(self.ssl) def get_verify_depth(self) -> int: """Return the peer certificate verification depth.""" return m2.ssl_get_verify_depth(self.ssl) def get_verify_result(self) -> int: """Return the peer certificate verification result.""" return m2.ssl_get_verify_result(self.ssl) def get_peer_cert(self) -> Optional[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) -> 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) -> 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, _pyfree=1) def get_ciphers(self) -> 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, _pyfree=1) def get_cipher_list(self, idx: int = 0) -> 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: str) -> int: """Set the cipher suites for this connection.""" return m2.ssl_set_cipher_list(self.ssl, cipher_list) def makefile( self, mode: str = "rb", bufsize: int = -1 ) -> Union[io.BufferedRWPair, io.BufferedReader, io.BufferedWriter]: if "b" not in mode: raise ValueError("makefile requires binary mode") if bufsize < 0: bufsize = io.DEFAULT_BUFFER_SIZE if "w" in mode and "r" in mode: return io.BufferedRWPair(self, self, buffer_size=bufsize) # type: ignore[call-arg,arg-type] elif "w" in mode: return io.BufferedWriter(self, buffer_size=bufsize) # type: ignore[call-arg,arg-type] elif "r" in mode: return io.BufferedReader(self, buffer_size=bufsize) # type: ignore[call-arg,arg-type] else: raise ValueError("Invalid mode: %s" % mode) def getsockname(self) -> 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) -> 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: bytes) -> int: ret: int = m2.ssl_set_session_id_context(self.ssl, id) if not ret: raise SSLError(Err.get_error_message()) return ret def get_session(self) -> Optional[Session]: sess = m2.ssl_get_session(self.ssl) if sess is None: return None return Session(sess, _pyfree=1) # type: ignore[arg-type] def set_session(self, session: Session) -> None: m2.ssl_set_session(self.ssl, session.session) # type: ignore[arg-type] def get_default_session_timeout(self) -> int: return m2.ssl_get_default_session_timeout(self.ssl) def get_socket_read_timeout(self) -> Timeout: return struct_to_timeout( self.socket.getsockopt( socket.SOL_SOCKET, socket.SO_RCVTIMEO, struct_size(), ) ) def get_socket_write_timeout(self) -> Timeout: binstr = self.socket.getsockopt( socket.SOL_SOCKET, socket.SO_SNDTIMEO, struct_size(), # type: ignore[attr-defined] ) timeo = struct_to_timeout(binstr) # type: ignore[attr-defined] # 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: Timeout) -> None: assert isinstance(timeo, Timeout) # type: ignore[attr-defined] self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeo.pack()) def set_socket_write_timeout(self, timeo: Timeout) -> None: assert isinstance(timeo, Timeout) # type: ignore[attr-defined] 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) -> 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: Callable ) -> None: # noqa self.postConnectionCheck = postConnectionCheck def set_tlsext_host_name(self, name: str) -> 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: bytes) -> None: """Set the requested hostname to check in the server certificate.""" self.host = name m2crypto-0.46.2/src/M2Crypto/SSL/Context.py000066400000000000000000000425551506746742300203200ustar00rootroot00000000000000"""SSL Context Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" import os from M2Crypto import BIO, Err, RSA, X509, m2, types as C, util # noqa from M2Crypto.SSL import cb # noqa from M2Crypto.SSL.Session import Session # noqa from weakref import WeakValueDictionary from typing import cast, Any, Callable, Optional, Union # noqa __all__ = ["ctxmap", "Context", "map"] class _ctxmap(object): singleton: Optional["_ctxmap"] = None def __init__(self) -> None: """Simple WeakReffed list.""" self._ctxmap: WeakValueDictionary[int, Any] = WeakValueDictionary() def __getitem__(self, key: int) -> Any: return self._ctxmap[key] def __setitem__(self, key: int, value: Any) -> None: self._ctxmap[key] = value def __delitem__(self, key: int) -> None: del self._ctxmap[key] def ctxmap() -> _ctxmap: if _ctxmap.singleton is None: _ctxmap.singleton = _ctxmap() return _ctxmap.singleton # deprecated!!! map = ctxmap class Context(object): """'Context' for SSL connections.""" @staticmethod def m2_ssl_ctx_free(ctx: C.SSL_CTX) -> None: m2.ssl_ctx_free(ctx) def __init__( self, protocol: str = "tls", weak_crypto: Optional[int] = None, post_connection_check: Optional[Callable] = None, ) -> 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: Union[int, bool] = 0 self.post_connection_check = post_connection_check ctxmap()[id(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) -> None: if getattr(self, "ctx", None): self.m2_ssl_ctx_free(self.ctx) def close(self) -> None: del ctxmap()[id(self.ctx)] def load_cert( self, certfile: Union[str, bytes], keyfile: Union[str, bytes, None] = None, callback: Callable = util.passphrase_callback, ) -> 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) certfile_str = ( os.fsdecode(certfile) if isinstance(certfile, bytes) else certfile ) m2.ssl_ctx_use_cert(self.ctx, certfile_str) if not keyfile: keyfile_str = certfile_str else: keyfile_str = ( os.fsdecode(keyfile) if isinstance(keyfile, bytes) else keyfile ) m2.ssl_ctx_use_privkey(self.ctx, keyfile_str) if not m2.ssl_ctx_check_privkey(self.ctx): raise ValueError("public/private key mismatch") def load_cert_chain( self, certchainfile: Union[str, bytes], keyfile: Union[str, bytes, None] = None, callback: Callable = util.passphrase_callback, ) -> 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) certchainfile_str = ( os.fsdecode(certchainfile) if isinstance(certchainfile, bytes) else certchainfile ) m2.ssl_ctx_use_cert_chain(self.ctx, certchainfile_str) if not keyfile: keyfile_str = certchainfile_str else: keyfile_str = ( os.fsdecode(certchainfile) if isinstance(certchainfile, bytes) else certchainfile ) m2.ssl_ctx_use_privkey(self.ctx, keyfile_str) if not m2.ssl_ctx_check_privkey(self.ctx): raise ValueError("public/private key mismatch") def set_client_CA_list_from_file(self, cafile: Union[str, bytes]) -> 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. """ cafile_str = os.fsdecode(cafile) if isinstance(cafile, bytes) else cafile m2.ssl_ctx_set_client_CA_list_from_file(self.ctx, cafile_str) # Deprecated. load_client_CA = load_client_ca = set_client_CA_list_from_file def load_verify_locations( self, cafile: Union[str, bytes, None] = None, capath: Union[str, bytes, None] = None, ) -> 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.") cafile_str = os.fsdecode(cafile) if isinstance(cafile, bytes) else cafile capath_str = os.fsdecode(capath) if isinstance(capath, bytes) else capath return m2.ssl_ctx_load_verify_locations(self.ctx, cafile_str, capath_str) # Deprecated. load_verify_info = load_verify_locations def set_session_id_ctx(self, id: 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) -> 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!") return ret def set_allow_unknown_ca(self, ok: 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) -> 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: int, depth: int, callback: Optional[Callable[[int, C.X509_STORE_CTX], int]] = None, ) -> 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) -> int: return m2.ssl_ctx_get_verify_mode(self.ctx) def get_verify_depth(self) -> 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: Union[str, bytes]) -> 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()) if dhp is None: raise BIO.BIOError("Could not read DH parameters") return m2.ssl_ctx_set_tmp_dh(self.ctx, dhp) def set_tmp_dh_callback(self, callback: Optional[Callable] = None) -> 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: 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: Optional[Callable] = None) -> 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: Callable = cb.ssl_info_callback) -> 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: 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: 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, cast(C.SSL_SESSION, session._ptr())) def remove_session(self, session: 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, cast(C.SSL_SESSION, session._ptr())) def get_session_timeout(self) -> 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: 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: 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) -> 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: 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) -> X509.X509_Store: """ 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.46.2/src/M2Crypto/SSL/SSLError.py000066400000000000000000000003571506746742300203410ustar00rootroot00000000000000"""SSL Exceptions Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" import socket __all__ = ["SSLError", "SSLTimeoutError"] class SSLError(Exception): pass class SSLTimeoutError(SSLError, socket.timeout): pass m2crypto-0.46.2/src/M2Crypto/SSL/SSLServer.py000066400000000000000000000040371506746742300205150ustar00rootroot00000000000000"""SSLServer Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.""" # M2Crypto 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 import socket as std_socket from typing import Union, Optional __all__ = ["SSLServer", "ForkingSSLServer", "ThreadingSSLServer"] class SSLServer(TCPServer): socket: Connection # type: ignore[assignment] def __init__( self, server_address: util.AddrType, RequestHandlerClass: "BaseRequestHandler", ssl_context: "Context", bind_and_activate: bool = True, ) -> None: """ Superclass says: Constructor. May be extended, do not override. This class says: Ho-hum. """ BaseServer.__init__(self, server_address, RequestHandlerClass) # type: ignore[arg-type] 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) -> None: from M2Crypto.SSL import SSLError 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( # type: ignore[override] self, request: Optional[Union[std_socket.socket, Connection]], client_address: Optional[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.46.2/src/M2Crypto/SSL/Session.py000066400000000000000000000032021506746742300203010ustar00rootroot00000000000000"""SSL Session Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" __all__ = ["Session", "load_session"] from M2Crypto import BIO, Err, m2, types as C from typing import Union, cast, TYPE_CHECKING # noqa class Session(object): def __init__(self, session, _pyfree: int = 0) -> None: assert session is not None self.session = session self._pyfree = _pyfree @staticmethod def m2_ssl_session_free(sess: C.SSL_SESSION) -> None: m2.ssl_session_free(sess) def __del__(self) -> None: if getattr(self, "_pyfree", 0): self.m2_ssl_session_free(self.session) def _ptr(self) -> bytes: return self.session def as_text(self) -> bytes: buf = BIO.MemoryBuffer() m2.ssl_session_print(buf.bio_ptr(), self.session) return buf.read_all() def as_der(self) -> bytes: buf = BIO.MemoryBuffer() m2.i2d_ssl_session(buf.bio_ptr(), self.session) return buf.read_all() def write_bio(self, bio: BIO.BIO) -> int: return m2.ssl_session_write_pem(bio.bio_ptr(), self.session) def get_time(self) -> int: return m2.ssl_session_get_time(self.session) def set_time(self, t: int) -> int: return m2.ssl_session_set_time(self.session, t) def get_timeout(self) -> int: return m2.ssl_session_get_timeout(self.session) def set_timeout(self, t: int) -> int: return m2.ssl_session_set_timeout(self.session, t) def load_session(pemfile: Union[str, bytes]) -> Session: with BIO.openfile(pemfile) as f: cptr = m2.ssl_session_read_pem(f.bio_ptr()) return Session(cptr, 1) m2crypto-0.46.2/src/M2Crypto/SSL/TwistedProtocolWrapper.py000066400000000000000000000500631506746742300233730ustar00rootroot00000000000000""" 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, types as C from M2Crypto.SSL.Checker import Checker, SSLVerificationError from M2Crypto.SSL import Context from twisted.internet.interfaces import ( ITLSTransport, IProtocolFactory, IProtocol, IReactorTCP, IReactorSSL, ) from twisted.protocols.policies import ProtocolWrapper from twisted.python.failure import Failure from typing import Callable, Iterable, Optional, Union, Any # noqa from zope.interface import implementer # type: ignore[import-untyped] log = logging.getLogger(__name__) def _alwaysSucceedsPostConnectionCheck( peerX509: Optional[X509.X509], expectedHost: str ) -> int: return 1 def connectSSL( host: str, port: int, factory: IProtocolFactory, contextFactory: Context, timeout: int = 30, bindAddress: Optional[str] = None, reactor: IReactorSSL = twisted.internet.reactor, # type: ignore[assignment] postConnectionCheck: Checker = Checker(), ) -> object: """ 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( # type: ignore[assignment] factory, wrappedProtocol, startPassThrough=0, client=1, contextFactory=contextFactory, postConnectionCheck=postConnectionCheck, ) return reactor.connectTCP(host, port, wrappingFactory, timeout, bindAddress) # type: ignore[call-arg, arg-type] def connectTCP( host: str, port: int, factory: IProtocolFactory, timeout: int = 30, bindAddress: Optional[util.AddrType] = None, reactor: IReactorTCP = twisted.internet.reactor, # type: ignore[assignment] postConnectionCheck: Callable = Checker(), ) -> 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( # type: ignore[assignment] factory, wrappedProtocol, startPassThrough=1, client=1, contextFactory=None, postConnectionCheck=postConnectionCheck, ) return reactor.connectTCP(host, port, wrappingFactory, timeout, bindAddress) # type: ignore[call-arg, arg-type, misc] def listenSSL( port: Union[int, str], factory: IProtocolFactory, contextFactory: Context, backlog: int = 5, interface: str = "", reactor: IReactorSSL = twisted.internet.reactor, # type: ignore[assignment] postConnectionCheck: Callable = _alwaysSucceedsPostConnectionCheck, ) -> object: """ 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( # type: ignore[assignment] factory, wrappedProtocol, startPassThrough=0, client=0, contextFactory=contextFactory, postConnectionCheck=postConnectionCheck, ) return reactor.listenTCP(port, wrappingFactory, backlog, interface) # type: ignore[call-arg, arg-type] def listenTCP( port: Union[int, str], factory: IProtocolFactory, backlog: int = 5, interface: str = "", reactor: IReactorTCP = twisted.internet.reactor, # type: ignore[assignment] postConnectionCheck: Optional[Callable] = None, ) -> object: """ 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( # type: ignore[assignment] factory, wrappedProtocol, startPassThrough=1, client=0, contextFactory=None, postConnectionCheck=postConnectionCheck, ) return reactor.listenTCP(port, wrappingFactory, backlog, interface) # type: ignore[call-arg, arg-type, misc] class _BioProxy(object): """ The purpose of this class is to eliminate the __del__ method from TLSProtocolWrapper, and thus letting it be garbage collected. """ def __init__(self, bio: BIO.BIO) -> None: self.bio = bio @staticmethod def m2_bio_free_all(bio: BIO.BIO): m2.bio_free_all(bio) # type: ignore[arg-type] def _ptr(self) -> C.BIO: return self.bio # type: ignore[return-value] def __del__(self) -> None: if self.bio is not None: # self.m2_bio_free_all(self.bio) # Mypy complains about types, better to let it go pass class _SSLProxy(object): """ The purpose of this class is to eliminate the __del__ method from TLSProtocolWrapper, and thus letting it be garbage collected. """ def __init__(self, ssl: C.SSL) -> None: self.ssl = ssl @staticmethod def m2_ssl_free(ssl: Any): m2.ssl_free(ssl) # type: ignore[arg-type] def _ptr(self) -> C.SSL: return self.ssl # type: ignore[return-value] def __del__(self) -> None: if self.ssl is not None: # self.m2_ssl_free(self.ssl) # Mypy complains about types, better to let it go pass @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. """ ctx: Optional[Context] = None sslBio: Optional[_BioProxy] = None ssl: Optional[_SSLProxy] = None internalBio: Any = None networkBio: Optional[_BioProxy] = None data: bytes encrypted: bytes tlsStarted: int checked: int isClient: int helloDone: int postConnectionCheck: Callable def __init__( self, factory: policies.WrappingFactory, wrappedProtocol: IProtocol, startPassThrough: int, client: int, contextFactory: Optional[Context], postConnectionCheck: Optional[Callable], ) -> 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: if contextFactory is not None: self.startTLS(contextFactory.getContext()) # type: ignore[attr-defined] def clear(self) -> None: """ 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: Context) -> None: """ 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 # Corrected bio_s_bio to bio_s_mem based on previous assumed stub error, but will ignore the call self.internalBio = m2.bio_new(m2.bio_s_mem()) # type: ignore[attr-defined] m2.bio_set_write_buf_size(self.internalBio, 0) self.networkBio = _BioProxy(m2.bio_new(m2.bio_s_mem())) # type: ignore[arg-type, attr-defined] m2.bio_set_write_buf_size(self.networkBio._ptr(), 0) m2.bio_make_bio_pair(self.internalBio, self.networkBio._ptr()) # type: ignore[attr-defined] self.sslBio = _BioProxy(m2.bio_new(m2.bio_f_ssl())) # type: ignore[arg-type, attr-defined] 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()) # type: ignore[attr-defined] m2.ssl_set_mode( # type: ignore[attr-defined] self.ssl._ptr(), mode | m2.SSL_MODE_ENABLE_PARTIAL_WRITE # type: ignore[attr-defined] | m2.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER, # type: ignore[attr-defined] ) self.tlsStarted = 1 def write(self, data: 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()), # type: ignore[union-attr] e.args[0], ) raise e def writeSequence(self, data: Iterable[bytes]) -> None: if not self.tlsStarted: ProtocolWrapper.writeSequence(self, b"".join(data)) return self.write(b"".join(data)) def loseConnection(self) -> None: # XXX Do we need to do m2.ssl_shutdown(self.ssl._ptr())? ProtocolWrapper.loseConnection(self) def connectionMade(self) -> None: ProtocolWrapper.connectionMade(self) if self.tlsStarted and self.isClient and not self.helloDone: self._clientHello() def dataReceived(self, data: 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()), # type: ignore[union-attr] e.args[0], ) raise e def connectionLost( self, reason: Optional[Failure] = None ) -> None: # Added = None to match base class self.clear() ProtocolWrapper.connectionLost(self, reason) def _check(self) -> None: if not self.checked and self.ssl is not None and m2.ssl_is_init_finished(self.ssl._ptr()): # type: ignore[attr-defined] x509 = m2.ssl_get_peer_cert(self.ssl._ptr()) if x509 is not None: x509 = X509.X509(x509, 1) # type: ignore[assignment] if self.isClient: if self.transport is not None: host = self.transport.addr[0] # type: ignore[union-attr] else: return # Exit if transport is missing else: if self.transport is not None: host = self.transport.getPeer().host # type: ignore[union-attr, misc] else: return # Exit if transport is missing if not self.postConnectionCheck(x509, host): raise SSLVerificationError("post connection check") self.checked = 1 def _clientHello(self) -> None: 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()), # type: ignore[union-attr] e.args[0], ) raise e # Optimizations to reduce attribute accesses @property def _get_wr_guar_ssl(self) -> 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()) # type: ignore[union-attr] @property def _get_wr_guar_net(self) -> Callable[[], int]: return partial(m2.bio_ctrl_get_write_guarantee, self.networkBio._ptr()) # type: ignore[union-attr] @property def _shoud_retry_ssl(self) -> 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()) # type: ignore[union-attr] @property def _shoud_retry_net(self) -> Callable[[], int]: return partial(m2.bio_should_retry, self.networkBio._ptr()) # type: ignore[union-attr] @property def _ctrl_pend_ssl(self) -> 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()) # type: ignore[union-attr] @property def _ctrl_pend_net(self) -> Callable[[], int]: return partial(m2.bio_ctrl_pending, self.networkBio._ptr()) # type: ignore[union-attr] @property def _write_ssl(self) -> 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()) # type: ignore[union-attr] @property def _write_net(self) -> Callable[[bytes], int]: return partial(m2.bio_write, self.networkBio._ptr()) # type: ignore[union-attr] @property def _read_ssl(self) -> Callable[[int], Optional[bytes]]: return partial(m2.bio_read, self.sslBio._ptr()) # type: ignore[union-attr] @property def _read_net(self) -> Callable[[int], Optional[bytes]]: return partial(m2.bio_read, self.networkBio._ptr()) # type: ignore[union-attr] def _encrypt(self, data: bytes = b"", clientHello: int = 0) -> 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: bytes = b"") -> 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.46.2/src/M2Crypto/SSL/__init__.py000066400000000000000000000020221506746742300204140ustar00rootroot00000000000000"""M2Crypto SSL services. Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.""" import socket, os # M2Crypto from M2Crypto import _m2crypto as m2 from .SSLError import SSLError, SSLTimeoutError m2.ssl_init(SSLError, SSLTimeoutError) # M2Crypto.SSL from .Cipher import Cipher, Cipher_Stack from .Connection import Connection from .Context import Context from .SSLServer import SSLServer, ThreadingSSLServer if os.name != "nt": from .SSLServer import ForkingSSLServer from .timeout import ( timeout, struct_to_timeout, struct_size, ) verify_none: int = m2.SSL_VERIFY_NONE verify_peer: int = m2.SSL_VERIFY_PEER verify_fail_if_no_peer_cert: int = m2.SSL_VERIFY_FAIL_IF_NO_PEER_CERT verify_client_once: int = m2.SSL_VERIFY_CLIENT_ONCE verify_crl_check_chain: int = m2.VERIFY_CRL_CHECK_CHAIN verify_crl_check_leaf: int = m2.VERIFY_CRL_CHECK_LEAF SSL_SENT_SHUTDOWN: int = m2.SSL_SENT_SHUTDOWN SSL_RECEIVED_SHUTDOWN: int = m2.SSL_RECEIVED_SHUTDOWN op_all: int = m2.SSL_OP_ALL op_no_sslv2: int = m2.SSL_OP_NO_SSLv2 m2crypto-0.46.2/src/M2Crypto/SSL/cb.py000066400000000000000000000061321506746742300172470ustar00rootroot00000000000000"""SSL callbacks Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" import sys from M2Crypto import X509, m2, types as C from typing import List __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: List[int] = [ 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: C.SSL_CTX, x509_ptr: C.X509, errnum: int, errdepth: int, ok: int, ) -> int: from M2Crypto.SSL.Context import Context, ctxmap ssl_ctx = ctxmap()[id(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: int, store: X509.X509_Store_Context ) -> int: """ Callback that allows unknown CA errors. This version relies on a corrected SWIG typemap to receive a valid 'store' object. """ store_ptr = store.ctx errnum = m2.x509_store_ctx_get_error(store_ptr) if errnum in unknown_issuer: # It's an error we want to ignore. Clear the error from the # context and return 1 to override the failure. m2.x509_store_ctx_set_error(store_ptr, m2.X509_V_OK) return 1 # For any other error, respect the original verification status. return ok # Cribbed from OpenSSL's apps/s_cb.c. def ssl_info_callback(where: int, ret: int, ssl_ptr: C.SSL) -> None: where_int = where & ~m2.SSL_ST_MASK if where_int & m2.SSL_ST_CONNECT: state = "SSL connect" elif where_int & 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: # Use a new variable for the alert operation string alert_op = "read" if (where & m2.SSL_CB_READ) else "write" sys.stderr.write( "ALERT: %s: %s: %s\n" % ( alert_op, m2.ssl_get_alert_type_v(ret), m2.ssl_get_alert_desc_v(ret), ) ) sys.stderr.flush() return m2crypto-0.46.2/src/M2Crypto/SSL/timeout.py000066400000000000000000000030061506746742300203460ustar00rootroot00000000000000"""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 import m2 DEFAULT_TIMEOUT: int = 600 class timeout(object): sec: int microsec: int def __init__(self, sec: int = DEFAULT_TIMEOUT, microsec: int = 0) -> None: self.sec = sec self.microsec = microsec def pack(self) -> bytes: if sys.platform == "win32": millisec = int(self.sec * 1000 + round(float(self.microsec) / 1000)) binstr = struct.pack("l", millisec) else: if m2.time_t_bits() == 32: binstr = struct.pack("ii", self.sec, self.microsec) else: binstr = struct.pack("ll", self.sec, self.microsec) return binstr def struct_to_timeout(binstr: 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() -> int: if sys.platform == "win32": return struct.calcsize("l") else: return struct.calcsize("ll") m2crypto-0.46.2/src/M2Crypto/X509.py000066400000000000000000001273201506746742300166720ustar00rootroot00000000000000"""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, types as C from typing import ( Callable, List, Optional, Union, Iterator, Any, overload, Iterable, ) FORMAT_DER = 0 FORMAT_PEM = 1 __g = globals() for x in dir(m2): if x.startswith("X509_V_ERR"): __g[x] = getattr(m2, x) elif x.startswith("XN_FLAG_"): __g[x] = getattr(m2, x) elif x.startswith("X509_PURPOSE_"): __g[x] = getattr(m2, x) elif x.startswith("VERIFY_"): __g[x.lower()] = getattr(m2, x) log = logging.getLogger(__name__) class X509Error(ValueError): pass m2.x509_init(X509Error) V_OK: int = m2.X509_V_OK class X509_Extension(object): """ X509 Extension """ def __init__( self, x509_ext_ptr: Optional[C.X509_EXTENSION] = None, _pyfree: int = 1 ) -> None: self.x509_ext = x509_ext_ptr self._pyfree = _pyfree def __del__(self) -> None: if getattr(self, "_pyfree", 0) and self.x509_ext: m2.x509_extension_free(self.x509_ext) def _ptr(self) -> Optional[C.X509_EXTENSION]: return self.x509_ext def set_critical(self, critical: int = 1) -> 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 """ if self.x509_ext is None: raise X509Error("Extension not initialized") return m2.x509_extension_set_critical(self.x509_ext, critical) def get_critical(self) -> int: """ Return whether or not this is a critical extension. :return: Nonzero if this is a critical extension. """ if self.x509_ext is None: raise X509Error("Extension not initialized") return m2.x509_extension_get_critical(self.x509_ext) def get_name(self) -> str: """ Get the extension name, for example 'subjectAltName'. """ if self.x509_ext is None: raise X509Error("Extension not initialized") out = m2.x509_extension_get_name(self.x509_ext) return out.decode() def get_value(self, flag: int = 0, indent: int = 0) -> 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. """ if self.x509_ext is None: raise X509Error("Extension not initialized") buf = BIO.MemoryBuffer() m2.x509_ext_print(buf.bio_ptr(), self.x509_ext, flag, indent) return (buf.read_all() or b"").decode() def new_extension( name: str, value: str, critical: int = 0, _pyfree: int = 1, pkey: Optional[EVP.PKey] = None, ) -> X509_Extension: """ Create a new X509_Extension instance using OpenSSL's internal V3 extension configuration. This method relies on the OpenSSL 'x509v3_ext_conf' function to parse a textual extension name and value into an X509_EXTENSION structure. :param name: The short name of the extension (e.g., 'subjectAltName', 'basicConstraints'). :param value: The value string for the extension (e.g., 'DNS:example.com', 'CA:TRUE'). For complex extensions like 'subjectKeyIdentifier', the value often specifies the content, such as 'hash' to compute the hash of the subject's public key. :param critical: Set to 1 to mark the extension as critical, 0 otherwise (default is 0). :param _pyfree: Internal flag (default 1). :param pkey: Optional EVP.PKey object. **Required** when the extension value requires an associated public key to be computed, such as when: - `name` is 'subjectKeyIdentifier' and `value` is 'hash'. If an extension requires a public key context and `pkey` is None, an `X509Error` will be raised to prevent a Segmentation Fault (SIGSEGV) in modern OpenSSL versions by accessing an uninitialized context pointer. :return: A new `X509_Extension` instance. :raises X509Error: If the extension cannot be created (e.g., invalid name/value) or if a required context (`pkey`) is missing. """ ctx = m2.x509v3_set_nconf() # This block enforces context availability for subjectKeyIdentifier:hash # to prevent a SIGSEGV in OpenSSL > 3.0 when ctx->subject_cert is NULL. if name == "subjectKeyIdentifier" and value == "hash" and pkey is None: m2.x509v3_ctx_free(ctx) # Clean up the context object before raising error raise X509Error( "Cannot create 'subjectKeyIdentifier:hash' without a public key (pkey) context." ) if pkey is not None: m2.X509V3_CTX_set_nconf_pkey(ctx, pkey._ptr()) x509_ext_ptr = m2.x509v3_ext_conf(None, ctx, name, str(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_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! """ def __init__( self, stack: Optional[C.STACK_OF_X509_EXTENSION] = None, _pyfree: int = 0 ) -> None: self.pystack: List[X509_Extension] = [] if stack is not None: self.stack = stack self._pyfree = _pyfree num = m2.sk_x509_extension_num(self.stack) for i in range(num): # Set _pyfree=0, the C stack owns the extension objects. self.pystack.append( X509_Extension( m2.sk_x509_extension_value(self.stack, i), _pyfree=0, ) ) else: self.stack = m2.sk_x509_extension_new_null() self._pyfree = 1 def __del__(self) -> None: # see BIO.py - unbalanced __init__ / __del__ if getattr(self, "_pyfree", 0): m2.sk_x509_extension_free(self.stack) def __len__(self) -> int: return len(self.pystack) def __getitem__(self, idx: int) -> X509_Extension: return self.pystack[idx] def __iter__(self) -> Iterator[X509_Extension]: return iter(self.pystack) def _ptr(self) -> C.STACK_OF_X509_EXTENSION: return self.stack def push(self, x509_ext: 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. """ ext_ptr = x509_ext._ptr() if ext_ptr is None: raise X509Error("Cannot push an uninitialized extension") self.pystack.append(x509_ext) ret = m2.sk_x509_extension_push(self.stack, ext_ptr) assert ret == len(self.pystack) return ret def pop(self) -> Optional[X509_Extension]: """ Pop X509_Extension object from the stack. :return: X509_Extension object that was popped, or None if there is nothing to pop. """ 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 """ def __init__(self, x509_name_entry: C.X509_NAME_ENTRY, _pyfree: int = 0) -> 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) -> None: if getattr(self, "_pyfree", 0): m2.x509_name_entry_free(self.x509_name_entry) def _ptr(self) -> C.X509_NAME_ENTRY: return self.x509_name_entry def set_object(self, asn1obj: 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: bytes, type: int = ASN1.MBSTRING_ASC) -> int: """ Sets the field value. :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) -> ASN1.ASN1_Object: obj_ptr = m2.x509_name_entry_get_object(self.x509_name_entry) return ASN1.ASN1_Object(obj_ptr, _pyfree=0) def get_data(self) -> ASN1.ASN1_String: str_ptr = m2.x509_name_entry_get_data(self.x509_name_entry) return ASN1.ASN1_String(str_ptr, _pyfree=0) def create_by_txt( self, field: str, type: int, entry: bytes, length: int ) -> C.X509_NAME_ENTRY: """ Creates and returns a new X509_NAME_ENTRY object. Note: This is a factory method that uses an existing instance's pointer space in a confusing way. It should likely be a static or class method for clarity. The corrected implementation below makes it work as written. """ return m2.x509_name_entry_create_by_txt( self.x509_name_entry, field, type, entry, length ) 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, } _alias_map = { "SP": "ST", "Email": "emailAddress", } def __init__( self, x509_name: Optional[C.X509_NAME] = None, _pyfree: int = 0 ) -> 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) -> None: if getattr(self, "_pyfree", 0): m2.x509_name_free(self.x509_name) def __str__(self) -> str: return m2.x509_name_oneline(self.x509_name) def __getattr__(self, attr: 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]) if out is None: raise AttributeError(attr) return out.decode() raise AttributeError(attr) def __setattr__(self, attr: str, value: Any) -> None: """ :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" self.add_entry_by_txt(attr, ASN1.MBSTRING_ASC, value, -1, -1, 0) else: super().__setattr__(attr, value) def __len__(self) -> int: return m2.x509_name_entry_count(self.x509_name) def __getitem__(self, idx: int) -> X509_Name_Entry: if not 0 <= idx < len(self): raise IndexError("index out of range") return X509_Name_Entry(m2.x509_name_get_entry(self.x509_name, idx), _pyfree=0) def __iter__(self) -> Iterator[X509_Name_Entry]: for i in range(len(self)): yield self[i] def _ptr(self) -> C.X509_NAME: return self.x509_name def add_entry_by_txt( self, field: str, type: int, entry: Union[str, bytes], len: int, loc: int, set: 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) :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. """ assert m2.x509_name_type_check(self.x509_name), "'x509_name' type error" # The SWIG wrapper for this function is quirky and appears to expect # Python strings for both field and entry, handling encoding internally. entry_str = entry.decode("utf-8") if isinstance(entry, bytes) else str(entry) canonical_field = self._alias_map.get(field, field) ret = m2.x509_name_add_entry_by_txt( self.x509_name, canonical_field, type, entry_str, len, loc, set ) if not ret: err_code = m2.err_get_error() m2.err_clear_error() err_lib = m2.err_lib_error_string(err_code) err_func = m2.err_func_error_string(err_code) err_reason = m2.err_reason_error_string(err_code) raise X509Error( "Failed to set attribute '{}'. OpenSSL error: [{}] {}: {}".format( field, err_lib, err_func, err_reason ) ) return ret def entry_count(self) -> int: return m2.x509_name_entry_count(self.x509_name) def get_entries_by_nid(self, nid: 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: int = 0, flags: int = m2.XN_FLAG_COMPAT) -> 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) return (buf.read_all() or b"").decode() def as_der(self) -> 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) -> 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 """ def __init__(self, x509: Optional[C.X509] = None, _pyfree: int = 0) -> None: """ :param x509: binary representation of the underlying OpenSSL X509 object. """ 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) -> None: if getattr(self, "_pyfree", 0): m2.x509_free(self.x509) def _ptr(self) -> C.X509: return self.x509 def as_text(self) -> str: assert m2.x509_type_check(self.x509), "'x509' type error" buf = BIO.MemoryBuffer() m2.x509_print(buf.bio_ptr(), self.x509) return (buf.read_all() or b"").decode() def as_der(self) -> bytes: assert m2.x509_type_check(self.x509), "'x509' type error" return m2.i2d_x509(self.x509) def as_pem(self) -> bytes: assert m2.x509_type_check(self.x509), "'x509' type error" buf = BIO.MemoryBuffer() m2.x509_write_pem(buf.bio_ptr(), self.x509) return buf.read() or b"" def save_pem(self, filename: str) -> 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: str, format: int = FORMAT_PEM) -> 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: int) -> int: """ Set version of the certificate. :param version: Version number. :return: Returns 0 on failure. """ return m2.x509_set_version(self.x509, version) def get_version(self) -> int: return m2.x509_get_version(self.x509) def set_not_before(self, asn1_time: ASN1.ASN1_TIME) -> int: """ :return: 1 on success, 0 on failure """ return m2.x509_set_not_before(self.x509, asn1_time._ptr()) def set_not_after(self, asn1_time: ASN1.ASN1_TIME) -> int: """ :return: 1 on success, 0 on failure """ return m2.x509_set_not_after(self.x509, asn1_time._ptr()) def get_not_before(self) -> ASN1.ASN1_TIME: time_ptr = m2.x509_get_not_before(self.x509) time = ASN1.ASN1_TIME(time_ptr, _pyfree=0) time.owner = self return time def get_not_after(self) -> ASN1.ASN1_TIME: time_ptr = m2.x509_get_not_after(self.x509) time = ASN1.ASN1_TIME(time_ptr, _pyfree=0) time.owner = self return time def get_serial_number(self) -> int: asn1_int = m2.x509_get_serial_number(self.x509) py_int = int(ASN1.ASN1_Integer(asn1_int)) if py_int is None: raise X509Error("Could not retrieve serial number") return py_int def set_serial_number(self, serial: int) -> int: """ Set serial number. :param serial: Serial number. :return 1 for success and 0 for failure. """ asn1_integer = ASN1.ASN1_Integer(serial) return m2.x509_set_serial_number(self.x509, asn1_integer.asn1int) def get_pubkey(self) -> EVP.PKey: pkey_ptr = m2.x509_get_pubkey(self.x509) if pkey_ptr is None: raise X509Error("Could not get public key") return EVP.PKey(pkey_ptr, _pyfree=1) def set_pubkey(self, pkey: EVP.PKey) -> int: """ Set the public key for the certificate :param pkey: Public key :return 1 for success and 0 for failure """ return m2.x509_set_pubkey(self.x509, pkey.pkey) def get_issuer(self) -> X509_Name: return X509_Name(m2.x509_get_issuer_name(self.x509), _pyfree=0) def set_issuer(self, name: X509_Name) -> int: return m2.x509_set_issuer_name(self.x509, name._ptr()) set_issuer_name = set_issuer def get_subject(self) -> X509_Name: return X509_Name(m2.x509_get_subject_name(self.x509), _pyfree=0) def set_subject_name(self, name: X509_Name) -> int: """ :return: 1 on success, 0 on failure """ return m2.x509_set_subject_name(self.x509, name._ptr()) set_subject = set_subject_name def add_ext(self, ext: X509_Extension) -> int: """ Add X509 extension to this certificate. :param ext: Extension :return 1 for success and 0 for failure """ ext_ptr = ext._ptr() if ext_ptr is None: raise X509Error("Cannot add an uninitialized extension") return m2.x509_add_ext(self.x509, ext_ptr, -1) def get_ext_count(self) -> int: """ Get X509 extension count. """ return m2.x509_get_ext_count(self.x509) def get_ext_at(self, index: int) -> X509_Extension: """ Get X509 extension by index. :param index: Name of the extension :return: X509_Extension """ if not 0 <= index < self.get_ext_count(): raise IndexError("index out of range") ext_ptr = m2.x509_get_ext(self.x509, index) return X509_Extension(ext_ptr, _pyfree=0) def get_ext(self, name: str) -> X509_Extension: """ Get X509 extension by name. :param name: Name of the extension :return: X509_Extension """ for i in range(self.get_ext_count()): ext = self.get_ext_at(i) if ext.get_name() == name: return ext raise LookupError def sign(self, pkey: EVP.PKey, md: str) -> int: """ Sign the certificate. :param pkey: Public key :param md: Message digest algorithm to use for signing, for example 'sha1'. :return int """ 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: Optional[EVP.PKey] = None) -> int: if pkey: return m2.x509_verify(self.x509, pkey.pkey) else: pubkey = self.get_pubkey() return m2.x509_verify(self.x509, pubkey.pkey) def check_ca(self) -> 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: int, ca: 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: str = "sha1") -> str: """ Get the fingerprint of the certificate. :param md: Message digest algorithm to use. :return: String containing the fingerprint in hex format. """ md_obj = EVP.MessageDigest(md) md_obj.update(self.as_der()) digest = md_obj.final() return binascii.hexlify(digest).upper().decode() def add_subject_key_identifier(self) -> int: """ Adds a Subject Key Identifier (SKI) extension to the certificate, calculating the key identifier from the certificate's public key. This bypasses the error-prone use of 'subjectKeyIdentifier', 'hash' in new_extension, which requires a pre-configured OpenSSL context. :return: 1 for success and 0 for failure. """ pkey = self.get_pubkey() # The SKID value is typically the SHA1 hash of the public key's contents. # We compute the hash manually and then format it for the extension value. skid_digest = pkey.get_key_identifier() # Format the digest into the required OpenSSL extension value string format: # A list of hex octets separated by colons (e.g., 'A1:B2:C3:D4:...') value = ":".join(f"{b:02X}" for b in skid_digest) # Create the extension directly with the computed value # Note: SKID is usually non-critical (critical=0 by default for new_extension) ext = new_extension("subjectKeyIdentifier", value) # Add the extension to the certificate object return self.add_ext(ext) def load_cert(file: Union[str, bytes], format: int = FORMAT_PEM) -> 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. """ if isinstance(file, bytes): file = file.decode() 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: BIO.BIO, format: int = FORMAT_PEM) -> 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") if cptr is None: raise X509Error("Failed to load certificate from BIO") return X509(cptr, _pyfree=1) def load_cert_string(string: Union[str, bytes], format: int = FORMAT_PEM) -> 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. """ if isinstance(string, str): string = string.encode("utf-8") bio = BIO.MemoryBuffer(string) return load_cert_bio(bio, format) def load_cert_der_string(cert_str: Union[str, bytes]) -> X509: """ Load certificate from a cert_str. :param cert_str: String containing a certificate in DER format. :return: M2Crypto.X509.X509 object. """ if isinstance(cert_str, str): cert_str = cert_str.encode("utf-8") return load_cert_string(cert_str, FORMAT_DER) 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! """ def __init__( self, stack: Optional[C.STACK_OF_X509] = None, _pyfree: int = 0, _pyfree_x509: int = 0, ) -> None: """ :param stack: OpenSSL STACK_OF(X509) """ self.pystack: List[X509] = [] if stack is not None: self.stack = stack self._pyfree = _pyfree 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 def __del__(self) -> None: if getattr(self, "_pyfree", 0): m2.sk_x509_free(self.stack) def __len__(self) -> int: return len(self.pystack) def __getitem__(self, idx: int) -> X509: return self.pystack[idx] def __iter__(self) -> Iterator[X509]: return iter(self.pystack) def _ptr(self) -> C.STACK_OF_X509: return self.stack def push(self, x509: X509) -> int: """ push an X509 certificate onto the stack. :param x509: X509 object. :return: The number of X509 objects currently on the stack. """ self.pystack.append(x509) return m2.sk_x509_push(self.stack, x509._ptr()) def pop(self) -> Optional[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: # Sanity check: our Python list should also be empty. assert not self.pystack return None return self.pystack.pop() def as_der(self) -> bytes: """ Return the stack as a DER encoded string """ return m2.get_der_encoding_stack(self.stack) class X509_Store_Context(object): """ X509 Store Context """ def __init__(self, x509_store_ctx: C.X509_STORE_CTX, _pyfree: int = 0) -> None: """ :param x509_store_ctx: binary data for OpenSSL X509_STORE_CTX type """ self.ctx = x509_store_ctx self._pyfree = _pyfree def __del__(self) -> None: if getattr(self, "_pyfree", 0): m2.x509_store_ctx_free(self.ctx) def _ptr(self) -> C.X509_STORE_CTX: return self.ctx def get_current_cert(self) -> Optional[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. """ cert_ptr = m2.x509_store_ctx_get_current_cert(self.ctx) if cert_ptr is None: return None return X509(cert_ptr, _pyfree=0) def get_error(self) -> int: """ Get error code. """ return m2.x509_store_ctx_get_error(self.ctx) def get_error_depth(self) -> int: """ Get error depth. """ return m2.x509_store_ctx_get_error_depth(self.ctx) def get1_chain(self) -> 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 as X509_Stack. """ return X509_Stack(m2.x509_store_ctx_get1_chain(self.ctx), 1, 1) def x509_store_default_cb(ok: int, ctx: C.X509_STORE_CTX) -> int: return ok class X509_Store(object): """ X509 Store """ def __init__(self, store: Optional[C.X509_STORE] = None, _pyfree: int = 0) -> 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) -> None: if getattr(self, "_pyfree", 0): m2.x509_store_free(self.store) def _ptr(self) -> C.X509_STORE: return self.store def load_info(self, file: str) -> int: """ :param file: filename :return: 1 on success, 0 on failure """ return m2.x509_store_load_locations(self.store, file) load_locations = load_info def add_x509(self, x509: X509) -> int: """ Add X509 certificate to the store. """ return m2.x509_store_add_cert(self.store, x509._ptr()) add_cert = add_x509 def set_verify_cb( self, callback: Optional[Callable[[int, C.X509_STORE_CTX], int]] = None ) -> 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: callback = x509_store_default_cb if not callable(callback): raise X509Error("set_verify(): callback is not callable") m2.x509_store_set_verify_cb(self.store, callback) def set_flags(self, flags: 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) def new_stack_from_der(der_string: bytes) -> X509_Stack: """ Create a new X509_Stack from DER string. """ stack_ptr = m2.make_stack_from_der_sequence(der_string) if stack_ptr is None: raise X509Error("Failed to create stack from DER sequence") return X509_Stack(stack_ptr, 1, 1) class Request(object): """ X509 Certificate Request. """ def __init__(self, req: Optional[C.X509_REQ] = None, _pyfree: int = 0) -> 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) -> None: if getattr(self, "_pyfree", 0): m2.x509_req_free(self.req) def _ptr(self) -> C.X509_REQ: return self.req def as_text(self) -> str: buf = BIO.MemoryBuffer() m2.x509_req_print(buf.bio_ptr(), self.req) return (buf.read_all() or b"").decode() def as_pem(self) -> bytes: buf = BIO.MemoryBuffer() m2.x509_req_write_pem(buf.bio_ptr(), self.req) return buf.read() or b"" def as_der(self) -> bytes: buf = BIO.MemoryBuffer() m2.i2d_x509_req_bio(buf.bio_ptr(), self.req) return buf.read() or b"" def save_pem(self, filename: str) -> int: with BIO.openfile(filename, "wb") as bio: return m2.x509_req_write_pem(bio.bio_ptr(), self.req) def save(self, filename: str, format: int = FORMAT_PEM) -> int: """ Saves X.509 certificate request to a file. Default output format is PEM. :param filename: Name of the file the request will be s: aved to. request. Either FORMAT_PEM or FORMAT_DER to save in PEM or DER format. Raises V: a lueError 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) -> EVP.PKey: """ Get the public key for the request. :return: Public key from the request. """ pkey_ptr = m2.x509_req_get_pubkey(self.req) if pkey_ptr is None: raise X509Error("Could not get public key from request") return EVP.PKey(pkey_ptr, _pyfree=1) def set_pubkey(self, pkey: 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_subject(self) -> X509_Name: return X509_Name(m2.x509_req_get_subject_name(self.req), _pyfree=0) def set_subject_name(self, name: 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._ptr()) set_subject = set_subject_name def add_extensions(self, ext_stack: 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: 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: EVP.PKey, md: 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 get_version(self) -> int: """ Get the version of the request. :return: Version number. """ return m2.x509_req_get_version(self.req) def set_version(self, ver: int) -> int: """ Set the version of the request. :param ver: Version number. :return: 1 for success, 0 for failure. """ return m2.x509_req_set_version(self.req, ver) def load_request(file: Union[str, bytes], format: int = FORMAT_PEM) -> 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. """ if isinstance(file, bytes): file = file.decode() 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" ) if cptr is None: raise X509Error("Failed to load request from file") return Request(cptr, 1) def load_request_bio(bio: BIO.BIO, format: int = FORMAT_PEM) -> 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") if cptr is None: raise X509Error("Failed to load request from BIO") return Request(cptr, _pyfree=1) def load_request_string(string: Union[str, bytes], format: int = FORMAT_PEM) -> 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. """ if isinstance(string, str): string = string.encode("utf-8") bio = BIO.MemoryBuffer(string) return load_request_bio(bio, format) def load_request_der_string(cert_str: Union[str, bytes]) -> 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 return load_request_string(cert_str, FORMAT_DER) class CRL(object): """ X509 Certificate Revocation List """ def __init__(self, crl: Optional[C.X509_CRL] = None, _pyfree: int = 0) -> 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) -> None: if getattr(self, "_pyfree", 0): m2.x509_crl_free(self.crl) def as_text(self) -> 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) return (buf.read_all() or b"").decode() def load_crl(file: str) -> 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()) if cptr is None: raise X509Error("Failed to load CRL from file") return CRL(cptr, 1) m2crypto-0.46.2/src/M2Crypto/__init__.py000066400000000000000000000024631506746742300177640ustar00rootroot00000000000000""" 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. 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. """ __version__: str = "0.46.2" version: str = __version__ try: from packaging.version import Version except ImportError: try: from distutils.version import StrictVersion as Version # type: ignore [no-redef, import-not-found] except ImportError: Version = None # type: ignore[misc, assignment] if Version is not None: version_info: tuple = (0, 0, 0) __ver: Version = 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: int = 1 decrypt: int = 0 m2crypto-0.46.2/src/M2Crypto/_m2crypto.pyi000066400000000000000000001030371506746742300203130ustar00rootroot00000000000000# mypy: allow-untyped-defs """ Fully populated mypy stub for M2Crypto's C bindings (_m2crypto) Generated based on _m2crypto_wrap.c """ from typing import Any, Callable, List, Optional, Tuple, overload # char * is str and it is for string constants only; NO R/W! from M2Crypto import ASN1, BIO, types as C # --- Constants --- OPENSSL_VERSION_NUMBER: int bio_close: int bio_noclose: int encrypt: int decrypt: int no_padding: int pkcs1_padding: int pkcs1_oaep_padding: int sslv2_padding: int # PKCS7 flags PKCS7_BINARY: int PKCS7_NOCERTS: int PKCS7_NOCHAIN: int PKCS7_NOINTERN: int PKCS7_NOSIGS: int PKCS7_NOVERIFY: int PKCS7_TEXT: int PKCS7_DETACHED: int PKCS7_NOATTR: int PKCS7_SIGNED: int PKCS7_ENVELOPED: int PKCS7_SIGNED_ENVELOPED: int PKCS7_DATA: int PKCS5_SALT_LEN: int # SSL verify modes SSL_VERIFY_NONE: int SSL_VERIFY_PEER: int SSL_VERIFY_FAIL_IF_NO_PEER_CERT: int SSL_VERIFY_CLIENT_ONCE: int # SSL options SSL_OP_ALL: int SSL_OP_NO_SSLv2: int SSL_OP_NO_SSLv3: int SSL_OP_NO_TLSv1: int # SSL state flags SSL_ST_CONNECT: int SSL_ST_ACCEPT: int SSL_ST_MASK: int SSL_ST_INIT: int SSL_ST_BEFORE: int SSL_ST_OK: int SSL_ST_RENEGOTIATE: int # SSL callback flags SSL_CB_LOOP: int SSL_CB_EXIT: int SSL_CB_READ: int SSL_CB_WRITE: int SSL_CB_ALERT: int SSL_CB_READ_ALERT: int SSL_CB_WRITE_ALERT: int SSL_CB_ACCEPT_LOOP: int SSL_CB_ACCEPT_EXIT: int SSL_CB_CONNECT_LOOP: int SSL_CB_CONNECT_EXIT: int SSL_CB_HANDSHAKE_START: int SSL_CB_HANDSHAKE_DONE: int SSL_SENT_SHUTDOWN: int SSL_RECEIVED_SHUTDOWN: int # DH Generators DH_GENERATOR_2: int DH_GENERATOR_5: int # EC constants NID_secp112r1: int NID_secp112r2: int NID_secp128r1: int NID_secp128r2: int NID_secp160k1: int NID_secp160r1: int NID_secp160r2: int NID_secp192k1: int NID_secp224k1: int NID_secp224r1: int NID_secp256k1: int NID_secp384r1: int NID_secp521r1: int NID_sect113r1: int NID_sect113r2: int NID_sect131r1: int NID_sect131r2: int NID_sect163k1: int NID_sect163r1: int NID_sect163r2: int NID_sect193r1: int NID_sect193r2: int NID_sect233k1: int NID_sect233r1: int NID_sect239k1: int NID_sect283k1: int NID_sect283r1: int NID_sect409k1: int NID_sect409r1: int NID_sect571k1: int NID_sect571r1: int NID_X9_62_prime192v1: int NID_X9_62_prime192v2: int NID_X9_62_prime192v3: int NID_X9_62_prime239v1: int NID_X9_62_prime239v2: int NID_X9_62_prime239v3: int NID_X9_62_prime256v1: int NID_X9_62_c2pnb163v1: int NID_X9_62_c2pnb163v2: int NID_X9_62_c2pnb163v3: int NID_X9_62_c2pnb176v1: int NID_X9_62_c2tnb191v1: int NID_X9_62_c2tnb191v2: int NID_X9_62_c2tnb191v3: int NID_X9_62_c2pnb208w1: int NID_X9_62_c2tnb239v1: int NID_X9_62_c2tnb239v2: int NID_X9_62_c2tnb239v3: int NID_X9_62_c2pnb272w1: int NID_X9_62_c2pnb304w1: int NID_X9_62_c2tnb359v1: int NID_X9_62_c2pnb368w1: int NID_X9_62_c2tnb431r1: int NID_wap_wsg_idm_ecid_wtls1: int NID_wap_wsg_idm_ecid_wtls3: int NID_wap_wsg_idm_ecid_wtls4: int NID_wap_wsg_idm_ecid_wtls5: int NID_wap_wsg_idm_ecid_wtls6: int NID_wap_wsg_idm_ecid_wtls7: int NID_wap_wsg_idm_ecid_wtls8: int NID_wap_wsg_idm_ecid_wtls9: int NID_wap_wsg_idm_ecid_wtls10: int NID_wap_wsg_idm_ecid_wtls11: int NID_wap_wsg_idm_ecid_wtls12: int NID_ipsec3: int NID_ipsec4: int # X509 constants NID_commonName: int NID_countryName: int NID_localityName: int NID_stateOrProvinceName: int NID_organizationName: int NID_organizationalUnitName: int NID_serialNumber: int NID_surname: int NID_givenName: int NID_pkcs9_emailAddress: int X509_V_OK: int X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: int X509_V_ERR_UNABLE_TO_GET_CRL: int X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: int X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: int X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: int X509_V_ERR_CERT_SIGNATURE_FAILURE: int X509_V_ERR_CRL_SIGNATURE_FAILURE: int X509_V_ERR_CERT_NOT_YET_VALID: int X509_V_ERR_CERT_HAS_EXPIRED: int X509_V_ERR_CRL_NOT_YET_VALID: int X509_V_ERR_CRL_HAS_EXPIRED: int X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: int X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: int X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: int X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: int X509_V_ERR_OUT_OF_MEM: int X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: int X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: int X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: int X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: int X509_V_ERR_CERT_CHAIN_TOO_LONG: int X509_V_ERR_CERT_REVOKED: int X509_V_ERR_INVALID_CA: int X509_V_ERR_PATH_LENGTH_EXCEEDED: int X509_V_ERR_INVALID_PURPOSE: int X509_V_ERR_CERT_UNTRUSTED: int X509_V_ERR_CERT_REJECTED: int X509_V_ERR_APPLICATION_VERIFICATION: int VERIFY_ALLOW_PROXY_CERTS: int VERIFY_CB_ISSUER_CHECK: int VERIFY_CHECK_SS_SIGNATURE: int VERIFY_CRL_CHECK: int VERIFY_CRL_CHECK_ALL: int VERIFY_CRL_CHECK_CHAIN: int VERIFY_CRL_CHECK_LEAF: int VERIFY_EXPLICIT_POLICY: int VERIFY_EXTENDED_CRL_SUPPORT: int VERIFY_IGNORE_CRITICAL: int VERIFY_INHIBIT_ANY: int VERIFY_INHIBIT_MAP: int VERIFY_NO_ALT_CHAINS: int VERIFY_NO_CHECK_TIME: int VERIFY_NOTIFY_POLICY: int VERIFY_PARTIAL_CHAIN: int VERIFY_POLICY_CHECK: int VERIFY_TRUSTED_FIRST: int VERIFY_USE_DELTAS: int VERIFY_X509_STRICT: int XN_FLAG_COMPAT: int XN_FLAG_SEP_COMMA_PLUS: int XN_FLAG_SEP_CPLUS_SPC: int XN_FLAG_SEP_MULTILINE: int XN_FLAG_DN_REV: int XN_FLAG_FN_LN: int XN_FLAG_SPC_EQ: int XN_FLAG_DUMP_UNKNOWN_FIELDS: int XN_FLAG_FN_ALIGN: int XN_FLAG_ONELINE: int XN_FLAG_MULTILINE: int XN_FLAG_RFC2253: int RSA_3: int RSA_F4: int # --- Library Initialization and Utility Functions --- def lib_init() -> None: ... def time_t_bits() -> int: ... def threading_init() -> None: ... def threading_cleanup() -> None: ... # --- Error Handling --- def err_print_errors(bio: C.BIO) -> None: ... def err_clear_error() -> None: ... def err_get_error() -> int: ... def err_peek_error() -> int: ... def err_lib_error_string(err: int) -> str: ... def err_func_error_string(err: int) -> str: ... def err_reason_error_string(err: int) -> str: ... def x509_get_verify_error(err: int) -> str: ... # --- ASN.1 Functions --- def asn1_integer_new() -> C.ASN1_Integer: ... 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_string_new() -> C.ASN1_String: ... 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_string_set(s: C.ASN1_String, data: bytes) -> 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: ... def asn1_object_free(a: C.ASN1_Object) -> None: ... # --- BIO (Basic I/O) Functions --- def bio_ctrl_get_write_guarantee(b: C.BIO) -> int: ... def bio_ctrl_pending(b: C.BIO) -> int: ... def bio_ctrl_wpending(b: C.BIO) -> int: ... def bio_do_handshake(b: C.BIO) -> int: ... def bio_eof(b: C.BIO) -> int: ... def bio_f_buffer() -> C.BIO_METHOD: ... def bio_f_cipher() -> C.BIO_METHOD: ... def bio_flush(b: C.BIO) -> int: ... def bio_free_all(b: C.BIO) -> None: ... def bio_free(b: C.BIO) -> int: ... def bio_f_ssl() -> C.BIO_METHOD: ... def bio_get_fd(b: C.BIO) -> int: ... def bio_gets(b: C.BIO, size: int) -> bytes: ... def bio_init(err: Any) -> None: ... def bio_new_file(filename: str, mode: str) -> C.BIO: ... def bio_new(method: C.BIO_METHOD) -> C.BIO: ... def bio_new_pyfile(pyfile: Any, close_on_del: int) -> C.BIO: ... def bio_new_socket(sock: int, close_flag: int) -> C.BIO: ... def bio_pop(b: C.BIO) -> C.BIO: ... def bio_push(b: C.BIO, append: C.BIO) -> C.BIO: ... def bio_read(b: C.BIO, size: int) -> bytes: ... def bio_reset(b: C.BIO) -> int: ... def bio_seek(b: C.BIO, offset: int) -> int: ... def bio_set_cipher( b: C.BIO, c: C.EVP_CIPHER, key: bytes, iv: bytes, op: int ) -> None: ... def bio_set_flags(b: C.BIO, flags: int) -> None: ... def bio_set_mem_eof_return(b: C.BIO, v: int) -> int: ... def bio_set_ssl(b: C.BIO, ssl: C.SSL, flag: int) -> int: ... def bio_set_write_buf_size(b: C.BIO, size: int) -> int: ... def bio_should_read(b: C.BIO) -> int: ... def bio_should_retry(b: C.BIO) -> int: ... def bio_should_write(b: C.BIO) -> int: ... def bio_s_mem() -> C.BIO_METHOD: ... def bio_s_socket() -> C.BIO_METHOD: ... def bio_write(b: C.BIO, data: bytes) -> int: ... # --- Big Number (BIGNUM) Functions --- def bn_to_mpi(bn: C.BIGNUM) -> bytes: ... def mpi_to_bn(s: bytes) -> C.BIGNUM: ... def bn_to_bin(bn: C.BIGNUM) -> bytes: ... def bin_to_bn(s: bytes) -> C.BIGNUM: ... def bn_to_hex(bn: C.BIGNUM) -> str: ... def hex_to_bn(s: str) -> C.BIGNUM: ... def dec_to_bn(s: str) -> C.BIGNUM: ... def bn_rand(bits: int, top: int, bottom: int) -> int: ... def bn_rand_range(range_bn: int) -> int: ... # --- DH (Diffie-Hellman) Functions --- def dh_compute_key(dh: C.DH, pubkey: bytes) -> bytes: ... def dh_free(dh: C.DH) -> None: ... def dh_generate_key(dh: C.DH) -> int: ... def dh_generate_parameters( plen: int, g: int, pyfunc: Callable[[int, int], int] ) -> C.DH: ... def dh_check(dh: C.DH) -> int: ... def dh_init(err: Any) -> None: ... def dh_new() -> C.DH: ... def dhparams_print(bio: C.BIO, dh: C.DH) -> int: ... def dh_read_parameters(bio: C.BIO) -> Optional[C.DH]: ... def dh_set_pg(dh: C.DH, p: bytes, g: bytes) -> int: ... def dh_size(dh: C.DH) -> int: ... def dh_type_check(dh: C.DH) -> int: ... # --- DSA Functions --- def dsa_free(dsa: C.DSA) -> None: ... def dsa_generate_key(dsa: C.DSA) -> int: ... def dsa_generate_parameters(bits: int, pyfunc: Callable[[int, int], int]) -> C.DSA: ... def dsa_gen_key(dsa: C.DSA) -> int: ... def dsa_check_pub_key(dsa: C.DSA) -> int: ... def dsa_init(err: Any) -> None: ... def dsa_keylen(dsa: C.DSA) -> int: ... def dsa_new() -> C.DSA: ... def dsa_read_key( bio: C.BIO, pyfunc: Optional[Callable[[int], bytes]] = None ) -> Optional[C.DSA]: ... def dsa_read_params( bio: C.BIO, pyfunc: Optional[Callable[[int], bytes]] = None ) -> Optional[C.DSA]: ... def dsa_read_pub_key( bio: C.BIO, pyfunc: Optional[Callable[[int], bytes]] = None ) -> Optional[C.DSA]: ... def dsa_set_pqg(dsa: C.DSA, p: bytes, q: bytes, g: bytes) -> int: ... def dsa_set_pub(dsa: C.DSA, pub_key: bytes) -> int: ... def dsa_sign_asn1(dsa: C.DSA, data: bytes) -> bytes: ... def dsa_sign(dsa: C.DSA, data: bytes) -> Tuple[bytes, bytes]: ... def dsa_type_check(dsa: C.DSA) -> int: ... def dsa_verify_asn1(dsa: C.DSA, data: bytes, sig: bytes) -> int: ... def dsa_verify(dsa: C.DSA, data: bytes, r: bytes, s: bytes) -> int: ... def dsa_write_key_bio( dsa: C.DSA, bio: C.BIO, cipher: Optional[C.EVP_CIPHER], pyfunc: Callable[[int], bytes], ) -> int: ... def dsa_write_key_bio_no_cipher( dsa: C.DSA, bio: C.BIO, pyfunc: Callable[[int], bytes] ) -> int: ... def dsa_write_params_bio(dsa: C.DSA, bio: C.BIO) -> int: ... def dsa_write_pub_key_bio(dsa: C.DSA, bio: C.BIO) -> int: ... # --- EC (Elliptic Curve) Functions --- def ecdh_compute_key(keypairA: C.EC_KEY, pubkeyB: C.EC_KEY) -> bytes: ... def ecdsa_sign_asn1(key: C.EC_KEY, data: bytes) -> bytes: ... def ecdsa_sign(key: C.EC_KEY, data: bytes) -> Tuple[bytes, bytes]: ... def ecdsa_verify_asn1(key: C.EC_KEY, data: bytes, sig: bytes) -> int: ... def ecdsa_verify(key: C.EC_KEY, data: bytes, r: bytes, s: bytes) -> int: ... def ec_get_builtin_curves() -> List[Any]: ... def ec_init(err: Any) -> None: ... def ec_key_free(key: C.EC_KEY) -> None: ... def ec_key_from_pubkey_der(pubkey: bytes) -> C.EC_KEY: ... def ec_key_from_pubkey_params(nid: int, pubkey: bytes) -> C.EC_KEY: ... def ec_key_gen_key(key: C.EC_KEY) -> int: ... def ec_key_get_public_der(key: C.EC_KEY) -> bytes: ... def ec_key_get_public_key(key: C.EC_KEY) -> bytes: ... def ec_key_check_key(key: C.EC_KEY) -> int: ... def ec_key_keylen(key: C.EC_KEY) -> int: ... def ec_key_new_by_curve_name(nid: int) -> C.EC_KEY: ... def ec_key_new() -> C.EC_KEY: ... def ec_key_read_bio( bio: C.BIO, pyfunc: Optional[Callable[[int], bytes]] = None ) -> Optional[C.EC_KEY]: ... def ec_key_read_pubkey(bio: C.BIO) -> Optional[C.EC_KEY]: ... def ec_key_type_check(key: C.EC_KEY) -> int: ... def ec_key_write_bio( key: C.EC_KEY, bio: C.BIO, cipher: Optional[C.EVP_CIPHER], pyfunc: Callable[[int], bytes], ) -> int: ... def ec_key_write_bio_no_cipher( key: C.EC_KEY, bio: C.BIO, pyfunc: Callable[[int], bytes] ) -> int: ... def ec_key_write_pubkey(key: C.EC_KEY, bio: C.BIO) -> int: ... # --- EVP (High-level Crypto) Functions --- def aes_128_cbc() -> C.EVP_CIPHER: ... def aes_192_cbc() -> C.EVP_CIPHER: ... def aes_256_cbc() -> C.EVP_CIPHER: ... def bf_cbc() -> C.EVP_CIPHER: ... def bytes_to_key( cipher: C.EVP_CIPHER, md: C.EVP_MD, data: bytes, salt: Optional[bytes], iv: Any, iter: int, ) -> bytes: ... def cast5_cbc() -> C.EVP_CIPHER: ... def cipher_ctx_free(ctx: C.EVP_CIPHER_CTX) -> None: ... def cipher_ctx_new() -> C.EVP_CIPHER_CTX: ... def cipher_final(ctx: C.EVP_CIPHER_CTX) -> bytes: ... def cipher_init( ctx: C.EVP_CIPHER_CTX, cipher: C.EVP_CIPHER, key: Optional[bytes], iv: Optional[bytes], op: int, ) -> None: ... def cipher_set_padding(ctx: C.EVP_CIPHER_CTX, padding: int) -> int: ... def cipher_update(ctx: C.EVP_CIPHER_CTX, data: bytes) -> bytes: ... def des_cbc() -> C.EVP_CIPHER: ... def des_ecb() -> C.EVP_CIPHER: ... def des_ede_cbc() -> C.EVP_CIPHER: ... def des_ede3_cbc() -> C.EVP_CIPHER: ... def digest_final(ctx: C.EVP_MD_CTX) -> bytes: ... def digest_init(ctx: C.EVP_MD_CTX, md: C.EVP_MD) -> int: ... def digest_sign(ctx: C.EVP_MD_CTX, msg: bytes) -> bytes: ... def digest_sign_final(ctx: C.EVP_MD_CTX) -> bytes: ... @overload def digest_sign_init(ctx: C.EVP_MD_CTX, pkey: C.EVP_PKEY) -> int: ... @overload def digest_sign_init( ctx: C.EVP_MD_CTX, pctx: Optional[C.EVP_PKEY_CTX], md: C.EVP_MD, e: Optional[C.ENGINE], pkey: C.EVP_PKEY, ) -> int: ... def digest_sign_update(ctx: C.EVP_MD_CTX, data: bytes) -> None: ... def digest_update(ctx: C.EVP_MD_CTX, data: bytes) -> int: ... def digest_verify(ctx: C.EVP_MD_CTX, sig: bytes, msg: bytes) -> int: ... def digest_verify_final(ctx: C.EVP_MD_CTX, sig: bytes) -> int: ... @overload def digest_verify_init(ctx: C.EVP_MD_CTX, pkey: C.EVP_PKEY) -> int: ... @overload def digest_verify_init( ctx: C.EVP_MD_CTX, pctx: Optional[C.EVP_PKEY_CTX], md: C.EVP_MD, e: Optional[C.ENGINE], pkey: C.EVP_PKEY, ) -> int: ... def digest_verify_update(ctx: C.EVP_MD_CTX, data: bytes) -> int: ... def evp_init(err: Any) -> None: ... def get_digestbyname(name: str) -> Optional[C.EVP_MD]: ... def hmac_ctx_free(ctx: C.HMAC_CTX) -> None: ... def hmac_ctx_new() -> C.HMAC_CTX: ... def hmac_final(ctx: C.HMAC_CTX) -> bytes: ... def hmac_init(ctx: C.HMAC_CTX, key: bytes, md: C.EVP_MD) -> None: ... def hmac(key: bytes, data: bytes, md: C.EVP_MD) -> bytes: ... def hmac_update(ctx: C.HMAC_CTX, data: bytes) -> None: ... def md_ctx_free(ctx: C.EVP_MD_CTX) -> None: ... def md_ctx_new() -> C.EVP_MD_CTX: ... def md5() -> C.EVP_MD: ... def pkcs5_pbkdf2_hmac_sha1( password: bytes, salt: bytes, iterations: int, key_len: int ) -> bytes: ... def pkey_as_der(pkey: C.EVP_PKEY) -> bytes: ... def pkey_assign_ec(pkey: C.EVP_PKEY, ec: C.EC_KEY) -> int: ... def pkey_assign_rsa(pkey: C.EVP_PKEY, rsa: C.RSA) -> int: ... def pkey_free(pkey: C.EVP_PKEY) -> None: ... def pkey_get_modulus(pkey: C.EVP_PKEY) -> bytes: ... def pkey_get_raw_pub_key_sha1(pkey: C.EVP_PKEY) -> bytes: ... def pkey_get1_ec(pkey: C.EVP_PKEY) -> Optional[C.EC_KEY]: ... def pkey_get1_rsa(pkey: C.EVP_PKEY) -> Optional[C.RSA]: ... def pkey_new() -> C.EVP_PKEY: ... def pkey_read_pem(bio: C.BIO, pyfunc: Callable[[], bytes]) -> C.EVP_PKEY: ... def pkey_read_pem_pubkey(bio: C.BIO, pyfunc: Callable[[], bytes]) -> C.EVP_PKEY: ... def pkey_set1_ec(pkey: C.EVP_PKEY, ec: C.EC_KEY) -> int: ... def pkey_set1_rsa(pkey: C.EVP_PKEY, rsa: C.RSA) -> int: ... def pkey_size(pkey: C.EVP_PKEY) -> int: ... def pkey_write_pem_no_cipher( pkey: C.EVP_PKEY, bio: C.BIO, pyfunc: Callable[[], bytes] ) -> int: ... def pkey_write_pem( pkey: C.EVP_PKEY, bio: C.BIO, cipher: C.EVP_CIPHER, pyfunc: Callable[[], bytes] ) -> int: ... def rc2_40_cbc() -> C.EVP_CIPHER: ... def rc4() -> C.EVP_CIPHER: ... def ripemd160() -> C.EVP_MD: ... def sha1() -> C.EVP_MD: ... def sha224() -> C.EVP_MD: ... def sha256() -> C.EVP_MD: ... def sha384() -> C.EVP_MD: ... def sha512() -> C.EVP_MD: ... def sign_final(ctx: C.EVP_MD_CTX, pkey: C.EVP_PKEY) -> bytes: ... def sign_init(ctx: C.EVP_MD_CTX, md: C.EVP_MD) -> int: ... def sign_update(ctx: C.EVP_MD_CTX, data: bytes) -> None: ... def verify_final(ctx: C.EVP_MD_CTX, sig: bytes, pkey: C.EVP_PKEY) -> int: ... def verify_init(ctx: C.EVP_MD_CTX, md: C.EVP_MD) -> int: ... def verify_update(ctx: C.EVP_MD_CTX, data: bytes) -> int: ... # --- Misc Utility Functions --- def util_init(err: Any) -> None: ... def util_hex_to_string(data: bytes) -> str: ... def util_string_to_hex(data: str) -> bytes: ... def obj_obj2txt(obj: C.ASN1_Object, no_name: int) -> str: ... def obj_ln2nid(ln: str) -> int: ... def obj_nid2sn(nid: int) -> str: ... def obj_sn2nid(sn: str) -> int: ... def obj_txt2nid(txt: str) -> int: ... # --- RSA --- def rsa_init(err: Any) -> None: ... def rsa_new() -> C.RSA: ... def rsa_generate_key( bits: int, e: int, callback: Callable[[int, int], int] ) -> C.RSA: ... def rsa_free(rsa: C.RSA) -> None: ... def rsa_get_e(rsa: C.RSA) -> bytes: ... def rsa_get_ex_data(rsa: C.RSA, index: int) -> Any: ... def rsa_get_n(rsa: C.RSA) -> bytes: ... def rsa_check_key(rsa: C.RSA) -> int: ... def rsa_check_pub_key(rsa: C.RSA) -> int: ... def rsa_padding_add_pkcs1_pss( rsa: C.RSA, digest: bytes, hash_obj: C.EVP_MD, salt_length: int ) -> bytes: ... def rsa_private_decrypt(rsa: C.RSA, data: bytes, padding: int) -> Optional[bytes]: ... def rsa_private_encrypt(rsa: C.RSA, data: bytes, padding: int) -> bytes: ... def rsa_public_decrypt(rsa: C.RSA, data: bytes, padding: int) -> Optional[bytes]: ... def rsa_public_encrypt(rsa: C.RSA, data: bytes, padding: int) -> bytes: ... def rsa_read_key(bio: C.BIO, pyfunc: Callable[[int], bytes]) -> C.RSA: ... def rsa_read_pub_key(bio: C.BIO) -> C.RSA: ... def rsa_set_en(rsa: C.RSA, e: bytes, n: bytes) -> None: ... def rsa_set_ex_data(rsa: C.RSA, index: int, data: Any) -> int: ... def rsa_sign(rsa: C.RSA, digest: bytes, method_type: int) -> bytes: ... def rsa_size(rsa: C.RSA) -> int: ... def rsa_type_check(rsa: C.RSA) -> int: ... def rsa_write_key( rsa: C.RSA, bio: C.BIO, cipher: C.EVP_CIPHER, pyfunc: Callable[[int], bytes] ) -> int: ... def rsa_write_key_no_cipher( rsa: C.RSA, bio: C.BIO, pyfunc: Callable[[int], bytes] ) -> int: ... def rsa_verify_pkcs1_pss( rsa: C.RSA, digest: bytes, signature: bytes, hash_obj: C.EVP_MD, salt_length: int ) -> int: ... def rsa_verify( rsa: C.RSA, digest: bytes, signature: bytes, method_type: int ) -> int: ... def rsa_write_key_der(rsa: C.RSA, bio: C.BIO) -> int: ... def rsa_write_pub_key(rsa: C.RSA, bio: C.BIO) -> int: ... # --- RC4 --- def rc4_new() -> C.RC4_KEY: ... def rc4_free(key: C.RC4_KEY) -> None: ... def rc4_set_key(key: C.RC4_KEY, data: bytes) -> None: ... def rc4_update(key: C.RC4_KEY, data: bytes) -> bytes: ... # --- SSL / TLS --- def i2d_ssl_session(bio: C.BIO, sess: C.SSL_SESSION) -> None: ... def sk_ssl_cipher_num(stack: C.STACK_OF_SSL_CIPHER) -> int: ... def sk_ssl_cipher_value(stack: C.STACK_OF_SSL_CIPHER, idx: int) -> C.SSL_CIPHER: ... def ssl_accept(ssl: C.SSL, timeout: float = -1.0) -> int: ... def ssl_cipher_get_bits(c: C.SSL_CIPHER) -> int: ... def ssl_cipher_get_name(c: C.SSL_CIPHER) -> str: ... def ssl_cipher_get_version(c: C.SSL_CIPHER) -> str: ... def ssl_clear(ssl: C.SSL) -> int: ... def ssl_connect(ssl: C.SSL, timeout: float = -1.0) -> int: ... def ssl_ctx_add_session(ctx: C.SSL_CTX, sess: C.SSL_SESSION) -> int: ... def ssl_ctx_free(ctx: C.SSL_CTX) -> None: ... def ssl_ctx_get_cert_store(ctx: C.SSL_CTX) -> C.X509_STORE: ... def ssl_ctx_get_session_cache_mode(ctx: C.SSL_CTX) -> int: ... def ssl_ctx_get_session_timeout(ctx: C.SSL_CTX) -> int: ... def ssl_ctx_get_verify_depth(ctx: C.SSL_CTX) -> int: ... def ssl_ctx_get_verify_mode(ctx: C.SSL_CTX) -> int: ... def ssl_ctx_check_privkey(ctx: C.SSL_CTX) -> int: ... def ssl_ctx_load_verify_locations( ctx: C.SSL_CTX, cafile: Optional[str], capath: Optional[str] ) -> int: ... def ssl_ctx_new(method: C.SSL_METHOD) -> C.SSL_CTX: ... def ssl_ctx_passphrase_callback( ctx: C.SSL_CTX, pyfunc: Callable[[], bytes] ) -> None: ... def ssl_ctx_remove_session(ctx: C.SSL_CTX, sess: C.SSL_SESSION) -> int: ... def ssl_ctx_set_cache_size(ctx: C.SSL_CTX, size: int) -> int: ... def ssl_ctx_set_cipher_list(ctx: C.SSL_CTX, ciphers: str) -> int: ... def ssl_ctx_set_client_CA_list_from_file(ctx: C.SSL_CTX, ca_file: str) -> None: ... def ssl_ctx_set_default_verify_paths(ctx: C.SSL_CTX) -> int: ... def ssl_ctx_set_info_callback(ctx: C.SSL_CTX, callback: Callable) -> None: ... def ssl_ctx_set_options(ctx: C.SSL_CTX, op: int) -> int: ... def ssl_ctx_set_session_cache_mode(ctx: C.SSL_CTX, mode: int) -> int: ... def ssl_ctx_set_session_id_context(ctx: C.SSL_CTX, sid_ctx: bytes) -> int: ... def ssl_ctx_set_session_timeout(ctx: C.SSL_CTX, t: int) -> int: ... def ssl_ctx_set_tmp_dh(ctx: C.SSL_CTX, dh: C.DH) -> int: ... def ssl_ctx_set_tmp_dh_callback(ctx: C.SSL_CTX, callback: Callable) -> None: ... def ssl_ctx_set_tmp_rsa(ctx: C.SSL_CTX, rsa: C.RSA) -> int: ... def ssl_ctx_set_tmp_rsa_callback(ctx: C.SSL_CTX, callback: Callable) -> None: ... def ssl_ctx_set_verify( ctx: C.SSL_CTX, mode: int, callback: Callable[[int, C.X509_STORE_CTX], int] ) -> None: ... def ssl_ctx_set_verify_default(ctx: C.SSL_CTX, mode: int) -> None: ... def ssl_ctx_set_verify_depth(ctx: C.SSL_CTX, depth: int) -> None: ... def ssl_ctx_use_cert(ctx: C.SSL_CTX, cert_file: str) -> int: ... def ssl_ctx_use_cert_chain(ctx: C.SSL_CTX, chain_file: str) -> int: ... def ssl_ctx_use_pkey_privkey(ctx: C.SSL_CTX, pkey: C.EVP_PKEY) -> int: ... def ssl_ctx_use_privkey(ctx: C.SSL_CTX, key_file: str) -> int: ... def ssl_free(ssl: C.SSL) -> None: ... def ssl_get_cipher_list(ssl: C.SSL, n: int) -> str: ... def ssl_get_ciphers(ssl: C.SSL) -> C.STACK_OF_SSL_CIPHER: ... def ssl_get_current_cipher(ssl: C.SSL) -> Optional[C.SSL_CIPHER]: ... def ssl_get_default_session_timeout(ssl: C.SSL) -> int: ... def ssl_get_error(ssl: C.SSL, ret: int) -> int: ... def ssl_get_peer_cert_chain(ssl: C.SSL) -> Optional[C.STACK_OF_X509]: ... def ssl_get_session(ssl: C.SSL) -> Optional[C.SSL_SESSION]: ... def ssl_get_shutdown(ssl: C.SSL) -> int: ... def ssl_get_verify_mode(ssl: C.SSL) -> int: ... def ssl_get_verify_depth(ssl: C.SSL) -> int: ... def ssl_get_peer_cert(ssl: C.SSL) -> Optional[C.X509]: ... def ssl_get_ssl_ctx(ssl: C.SSL) -> C.SSL_CTX: ... def ssl_get_state(ssl: C.SSL) -> str: ... def ssl_get_state_v(ssl: C.SSL) -> str: ... def ssl_get_verify_result(ssl: C.SSL) -> int: ... def ssl_get_version(ssl: C.SSL) -> str: ... def ssl_get_alert_type_v(err: int) -> str: ... def ssl_get_alert_desc_v(err: int) -> str: ... def ssl_init(ssl_err: Any, ssl_timeout_err: Any) -> None: ... def ssl_is_init_finished(ssl: C.SSL) -> int: ... def ssl_new(ctx: C.SSL_CTX) -> C.SSL: ... def ssl_pending(ssl: C.SSL) -> int: ... def ssl_read_nbio(ssl: C.SSL, num: int) -> Optional[bytes]: ... def ssl_read(ssl: C.SSL, num: int, timeout: float = -1.0) -> Optional[bytes]: ... def ssl_renegotiate(ssl: C.SSL) -> int: ... def ssl_session_free(sess: C.SSL_SESSION) -> None: ... def ssl_session_get_timeout(sess: C.SSL_SESSION) -> int: ... def ssl_session_get_time(sess: C.SSL_SESSION) -> int: ... def ssl_session_print(bio: C.BIO, sess: C.SSL_SESSION) -> int: ... def ssl_session_read_pem(bio: C.BIO) -> Optional[C.SSL_SESSION]: ... def ssl_session_set_timeout(sess: C.SSL_SESSION, t: int) -> int: ... def ssl_session_set_time(sess: C.SSL_SESSION, t: int) -> int: ... def ssl_session_write_pem(sess: C.SSL_SESSION, bio: C.BIO) -> int: ... def ssl_set_accept_state(ssl: C.SSL) -> None: ... def ssl_set_bio(ssl: C.SSL, rbio: C.BIO, wbio: C.BIO) -> None: ... def ssl_set_cipher_list(ssl: C.SSL, ciphers: str) -> int: ... def ssl_set_client_CA_list_from_context(ssl: C.SSL, ctx: C.SSL_CTX) -> None: ... def ssl_set_client_CA_list_from_file(ssl: C.SSL, ca_file: str) -> None: ... def ssl_set_connect_state(ssl: C.SSL) -> None: ... def ssl_set_session_id_context(ssl: C.SSL, sid_ctx: bytes) -> int: ... def ssl_set_session(ssl: C.SSL, sess: C.SSL_SESSION) -> int: ... def ssl_set_shutdown1(ssl: C.SSL, mode: int) -> None: ... def ssl_set_tlsext_host_name(ssl: C.SSL, name: str) -> int: ... def ssl_shutdown(ssl: C.SSL) -> int: ... def sslv23_method() -> C.SSL_METHOD: ... def ssl_write_nbio(ssl: C.SSL, data: bytes) -> int: ... def ssl_write(ssl: C.SSL, data: bytes, timeout: float = -1.0) -> int: ... def set_client_CA_list_from_file(ssl: C.SSL, ca_file: str) -> None: ... def tlsv1_method() -> C.SSL_METHOD: ... # --- X509 --- def d2i_x509(bio: C.BIO) -> Optional[C.X509]: ... def d2i_x509_req(bio: C.BIO) -> Optional[C.X509_REQ]: ... def get_der_encoding_stack(stack: C.STACK_OF_X509) -> bytes: ... def i2d_x509_bio(bio: C.BIO, x509: C.X509) -> int: ... def i2d_x509_req_bio(bio: C.BIO, req: C.X509_REQ) -> int: ... def i2d_x509(x: C.X509) -> bytes: ... def make_stack_from_der_sequence(der: bytes) -> C.STACK_OF_X509: ... def sk_x509_extension_free(stack: C.STACK_OF_X509_EXTENSION) -> None: ... def sk_x509_extension_new_null() -> C.STACK_OF_X509_EXTENSION: ... def sk_x509_extension_num(stack: C.STACK_OF_X509_EXTENSION) -> int: ... def sk_x509_extension_pop(stack: C.STACK_OF_X509_EXTENSION) -> C.X509_EXTENSION: ... def sk_x509_extension_push( stack: C.STACK_OF_X509_EXTENSION, ext: C.X509_EXTENSION ) -> int: ... def sk_x509_extension_value( stack: C.STACK_OF_X509_EXTENSION, idx: int ) -> C.X509_EXTENSION: ... def sk_x509_free(stack: C.STACK_OF_X509) -> None: ... def sk_x509_new_null() -> C.STACK_OF_X509: ... def sk_x509_num(stack: C.STACK_OF_X509) -> int: ... def sk_x509_pop(stack: C.STACK_OF_X509) -> Optional[C.X509]: ... def sk_x509_push(stack: C.STACK_OF_X509, cert: C.X509) -> int: ... def sk_x509_value(stack: C.STACK_OF_X509, idx: int) -> C.X509: ... def x509_add_ext(x: C.X509, ext: C.X509_EXTENSION, loc: int) -> int: ... def x509_crl_free(crl: C.X509_CRL) -> None: ... def x509_crl_new() -> C.X509_CRL: ... def x509_crl_print(bio: C.BIO, crl: C.X509_CRL) -> int: ... def x509_crl_read_pem(bio: C.BIO) -> Optional[C.X509_CRL]: ... def x509_extension_free(ext: C.X509_EXTENSION) -> None: ... def x509_extension_get_critical(ext: C.X509_EXTENSION) -> int: ... def x509_extension_get_name(ext: C.X509_EXTENSION) -> bytes: ... def x509_extension_set_critical(ext: C.X509_EXTENSION, crit: int) -> int: ... def x509_ext_print( bio: C.BIO, ext: C.X509_EXTENSION, flags: int, indent: int ) -> int: ... def x509_free(x: C.X509) -> None: ... def x509_get_ext_count(x: C.X509) -> int: ... def x509_get_ext(x: C.X509, loc: int) -> C.X509_EXTENSION: ... def x509_get_issuer_name(x: C.X509) -> C.X509_NAME: ... def x509_get_not_after(x509: C.X509) -> C.ASN1_Time: ... def x509_get_not_before(x509: C.X509) -> C.ASN1_Time: ... def x509_get_pubkey(x: C.X509) -> Optional[C.EVP_PKEY]: ... def x509_get_serial_number(x: C.X509) -> C.ASN1_Integer: ... def x509_get_subject_name(x: C.X509) -> C.X509_NAME: ... def x509_get_version(x: C.X509) -> int: ... def x509_check_ca(x: C.X509) -> int: ... def x509_check_purpose(x: C.X509, id: int, ca: int) -> int: ... def x509_init(err: Any) -> None: ... def x509_name_add_entry_by_txt( name: C.X509_NAME, field: str, type: int, value: str, length: int, loc: int, set: int, ) -> int: ... def x509_name_by_nid(name: C.X509_NAME, nid: int) -> Optional[bytes]: ... def x509_name_entry_count(name: C.X509_NAME) -> int: ... def x509_name_entry_create_by_txt( ne: C.X509_NAME_ENTRY, field: str, type: int, bytes: bytes, len: int ) -> C.X509_NAME_ENTRY: ... def x509_name_entry_free(entry: C.X509_NAME_ENTRY) -> None: ... def x509_name_entry_get_data(entry: C.X509_NAME_ENTRY) -> C.ASN1_String: ... def x509_name_entry_get_object(entry: C.X509_NAME_ENTRY) -> C.ASN1_Object: ... def x509_name_entry_set_data( entry: C.X509_NAME_ENTRY, type: int, data: bytes ) -> int: ... def x509_name_entry_set_object(entry: C.X509_NAME_ENTRY, obj: C.ASN1_Object) -> int: ... def x509_name_free(name: C.X509_NAME) -> None: ... def x509_name_get_der(name: C.X509_NAME) -> bytes: ... def x509_name_get_entry(name: C.X509_NAME, loc: int) -> C.X509_NAME_ENTRY: ... def x509_name_get_index_by_nid(name: C.X509_NAME, nid: int, lastpos: int) -> int: ... def x509_name_hash(name: C.X509_NAME) -> int: ... def x509_name_new() -> C.X509_NAME: ... def x509_name_oneline(name: C.X509_NAME) -> str: ... def x509_name_print_ex( bio: C.BIO, name: C.X509_NAME, indent: int, flags: int ) -> int: ... def x509_name_set_by_nid(name: C.X509_NAME, nid: int, value: str) -> int: ... def x509_name_type_check(name: C.X509_NAME) -> int: ... def x509_new() -> C.X509: ... def x509_print(bio: C.BIO, x509: C.X509) -> int: ... def x509_read_pem(bio: C.BIO) -> Optional[C.X509]: ... def x509_req_add_extensions( req: C.X509_REQ, exts: C.STACK_OF_X509_EXTENSION ) -> int: ... def x509_req_free(req: C.X509_REQ) -> None: ... def x509_req_get_pubkey(req: C.X509_REQ) -> Optional[C.EVP_PKEY]: ... def x509_req_get_subject_name(req: C.X509_REQ) -> C.X509_NAME: ... def x509_req_get_version(req: C.X509_REQ) -> int: ... def x509_req_new() -> C.X509_REQ: ... def x509_req_print(bio: C.BIO, req: C.X509_REQ) -> int: ... def x509_req_read_pem(bio: C.BIO) -> Optional[C.X509_REQ]: ... def x509_req_set_pubkey(req: C.X509_REQ, pkey: C.EVP_PKEY) -> int: ... def x509_req_set_subject_name(req: C.X509_REQ, name: C.X509_NAME) -> int: ... def x509_req_set_version(req: C.X509_REQ, ver: int) -> int: ... def x509_req_sign(req: C.X509_REQ, pkey: C.EVP_PKEY, md: C.EVP_MD) -> int: ... def x509_req_verify(req: C.X509_REQ, pkey: C.EVP_PKEY) -> int: ... def x509_req_write_pem(bio: C.BIO, req: C.X509_REQ) -> int: ... def x509_set_issuer_name(x: C.X509, name: C.X509_NAME) -> int: ... def x509_set_not_after(x509: C.X509, tm: C.ASN1_Time) -> int: ... def x509_set_not_before(x509: C.X509, tm: C.ASN1_Time) -> int: ... def x509_set_pubkey(x: C.X509, pkey: C.EVP_PKEY) -> int: ... def x509_set_serial_number(x: C.X509, bn: C.ASN1_Integer) -> int: ... def x509_set_subject_name(x: C.X509, name: C.X509_NAME) -> int: ... def x509_set_version(x: C.X509, version: int) -> int: ... def x509_sign(x: C.X509, pkey: C.EVP_PKEY, md: C.EVP_MD) -> int: ... def x509_store_add_cert(store: C.X509_STORE, x: C.X509) -> int: ... def x509_store_ctx_free(ctx: C.X509_STORE_CTX) -> None: ... def x509_store_ctx_get_current_cert(ctx: C.X509_STORE_CTX) -> C.X509: ... def x509_store_ctx_get_error(ctx: C.X509_STORE_CTX) -> int: ... def x509_store_ctx_get_error_depth(ctx: C.X509_STORE_CTX) -> int: ... def x509_store_ctx_get1_chain(ctx: C.X509_STORE_CTX) -> C.STACK_OF_X509: ... def x509_store_free(store: C.X509_STORE) -> None: ... def x509_store_load_locations(store: C.X509_STORE, cafile: str) -> int: ... def x509_store_new() -> C.X509_STORE: ... def x509_store_set_flags(store: C.X509_STORE, flags: int) -> int: ... def x509_store_ctx_set_error(ctx: C.X509_STORE_CTX, err: int) -> None: ... def x509_store_ctx_get_ex_data(ctx: C.X509_STORE_CTX, idx: int) -> C.SSL: ... def x509_store_set_verify_cb( store: C.X509_STORE, cb: Callable[[int, C.X509_STORE_CTX], int] ) -> None: ... def x509_type_check(x509: C.X509) -> int: ... def x509_verify(x: C.X509, pkey: C.EVP_PKEY) -> int: ... def x509v3_ext_conf( conf: Any, ctx: C.X509V3_CTX, name: str, value: str ) -> C.X509_EXTENSION: ... def x509v3_set_nconf() -> C.X509V3_CTX: ... def x509_write_pem(bio: C.BIO, x: C.X509) -> int: ... def x509v3_ctx_free(ctx: C.X509V3_CTX) -> None: ... def X509V3_CTX_set_nconf_pkey(ctx: C.X509V3_CTX, pkey: C.EVP_PKEY) -> None: ... # --- S/MIME and PKCS7 --- def smime_init(err: Any) -> None: ... def pkcs7_init(err: Any) -> None: ... def pkcs7_new() -> C.PKCS7: ... def pkcs7_free(p7: C.PKCS7) -> None: ... def pkcs7_sign0( signer_cert: C.X509, signer_key: C.EVP_PKEY, data: C.BIO, hash_obj: C.EVP_MD, flags: int, ) -> Optional[C.PKCS7]: ... def pkcs7_sign1( signer_cert: C.X509, signer_key: C.EVP_PKEY, certs: C.STACK_OF_X509, data: C.BIO, hash_obj: C.EVP_MD, flags: int, ) -> Optional[C.PKCS7]: ... def pkcs7_verify0( p7: C.PKCS7, certs: C.STACK_OF_X509, store: C.X509_STORE, flags: int ) -> bytes: ... def pkcs7_verify1( p7: C.PKCS7, certs: C.STACK_OF_X509, store: C.X509_STORE, data: C.BIO, flags: int ) -> bytes: ... def pkcs7_encrypt( certs: C.STACK_OF_X509, data: C.BIO, cipher: C.EVP_CIPHER, flags: int ) -> Optional[C.PKCS7]: ... def pkcs7_decrypt(p7: C.PKCS7, pkey: C.EVP_PKEY, cert: C.X509, flags: int) -> bytes: ... def pkcs7_read_bio(bio: C.BIO) -> Optional[C.PKCS7]: ... def pkcs7_read_bio_der(bio: C.BIO) -> Optional[C.PKCS7]: ... def pkcs7_write_bio(p7: C.PKCS7, bio: C.BIO) -> int: ... def pkcs7_write_bio_der(p7: C.PKCS7, bio: C.BIO) -> int: ... def smime_read_pkcs7(bio: C.BIO) -> Tuple[Optional[C.PKCS7], Optional[C.BIO]]: ... def smime_write_pkcs7(bio: C.BIO, p7: C.PKCS7, flags: int) -> int: ... def smime_write_pkcs7_multi( bio: C.BIO, p7: C.PKCS7, data: C.BIO, flags: int ) -> int: ... def smime_crlf_copy(in_bio: C.BIO, out_bio: C.BIO) -> int: ... def pkcs7_get0_signers( p7: C.PKCS7, certs: C.STACK_OF_X509, flags: int ) -> C.STACK_OF_X509: ... def pkcs7_type_nid(p7: C.PKCS7) -> int: ... def pkcs7_type_sn(p7: C.PKCS7) -> str: ... def pkcs7_add_certificate(p7: C.PKCS7, cert: C.X509) -> None: ... # --- Rand --- def rand_init(err: Any) -> None: ... def rand_add(blob: bytes, entropy: float) -> None: ... def rand_seed(seed: bytes) -> None: ... def rand_status() -> int: ... def rand_file_name() -> bytes: ... def rand_load_file(filename: str, max_bytes: int) -> int: ... def rand_save_file(filename: str) -> int: ... def rand_bytes(n: int) -> bytes: ... def rand_pseudo_bytes(n: int) -> Tuple[bytes, int]: ... m2crypto-0.46.2/src/M2Crypto/callback.py000066400000000000000000000004021506746742300177500ustar00rootroot00000000000000"""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.46.2/src/M2Crypto/ftpslib.py000066400000000000000000000045641506746742300176740ustar00rootroot00000000000000"""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('ftp.example.com', 21) f.auth_tls() f.set_pasv(0) f.login('username', 'password') f.retrlines('LIST') # Output: # -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 # ... # '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): # type: ignore [no-redef] """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.46.2/src/M2Crypto/httpslib.py000066400000000000000000000257561506746742300200700ustar00rootroot00000000000000import 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, Callable, Dict, Optional, Type, Union class HTTPSConnection(HTTPConnection): # type: ignore [no-redef] """ This class allows communication via SSL using M2Crypto. """ sock: SSL.Connection default_port = HTTPS_PORT def __init__( self, host: str, port: Optional[int] = None, strict: Optional[bool] = None, # This parameter is ignored ssl_conn_cls: Type[SSL.Connection] = SSL.Connection, **ssl, ) -> 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: Optional[SSL.Session.Session] = None self.host = host if port is None: self.port = self.default_port else: self.port = port self._ssl_conn_cls = ssl_conn_cls 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) def connect(self) -> 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 = self._ssl_conn_cls(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) -> 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) -> Optional[SSL.Session.Session]: return self.sock.get_session() def set_session(self, session: 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. """ _ssl_conn_cls: Type[SSL.Connection] ssl_ctx: SSL.Context _ports = {"http": 80, "https": 443} _AUTH_HEADER = "Proxy-Authorization" _UA_HEADER = "User-Agent" def __init__( self, host: str, port: Optional[int] = None, strict: Optional[bool] = None, # This parameter is now ignored username: Union[str, bytes, None] = None, password: Union[str, bytes, None] = None, **ssl, ) -> 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, **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: Optional[str] = None self._proxy_UA: Optional[str] = None def putrequest( self, method: Union[str, bytes], url: Union[str, bytes], skip_host: bool = False, skip_accept_encoding: bool = False, ) -> None: """ putrequest is called before connect, so can interpret url and get real host/port to be used to make CONNECT request to proxy """ url_str = url.decode("latin-1") if isinstance(url, bytes) else url proto, netloc, path, query, fragment = urlsplit(url_str) if not proto: raise ValueError("unknown URL type: %s" % url_str) # get host & port try: _, host_port = netloc.split("@", 1) except ValueError: host_port = netloc try: host, port_s = host_port.split(":", 1) 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_str) self._real_host = host self._real_port = port rest_tuple = ("", "", path, query, fragment) rest = urlunsplit(rest_tuple) method_str = method.decode("ascii") if isinstance(method, bytes) else method super(HTTPSConnection, self).putrequest( method_str, rest, skip_host=skip_host, skip_accept_encoding=skip_accept_encoding, ) def putheader(self, header: Union[str, bytes], *values: Any) -> None: str_values = [ v.decode("latin-1") if isinstance(v, bytes) else str(v) for v in values ] value = " ".join(str_values) header_str = header.decode("latin-1") if isinstance(header, bytes) else header # Store the auth header if passed in. if header_str.lower() == self._UA_HEADER.lower(): self._proxy_UA = value elif header_str.lower() == self._AUTH_HEADER.lower(): self._proxy_auth = value else: super(HTTPSConnection, self).putheader(header, *values) def endheaders(self, *args, **kwargs) -> 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) -> 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) -> 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) -> None: """Make this connection's socket SSL-aware.""" self.sock = self._ssl_conn_cls(self.ssl_ctx, self.sock) self.sock.setup_ssl() self.sock.set_connect_state() self.sock.connect_ssl() def _encode_auth(self) -> Optional[str]: """Encode the username and password for use in the auth header.""" if not (self._username and self._password): return None username = ( self._username.decode("utf-8") if isinstance(self._username, bytes) else self._username ) password = ( self._password.decode("utf-8") if isinstance(self._password, bytes) else self._password ) userpass = f"{username}:{password}".encode("utf-8") enc_userpass = base64.b64encode(userpass).decode("ascii") return f"Basic {enc_userpass}" m2crypto-0.46.2/src/M2Crypto/m2.py000066400000000000000000000014731506746742300165430ustar00rootroot00000000000000"""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 * try: lib_init() except NameError: pass m2crypto-0.46.2/src/M2Crypto/m2crypto.py000066400000000000000000000010111506746742300177700ustar00rootroot00000000000000# This file was automatically generated by SWIG (https://www.swig.org). # Version 4.2.1 # # Do not make changes to this file unless you know what you are doing - modify # the SWIG interface file instead. from sys import version_info as _swig_python_version_info # Pull in all the attributes from the low-level C/C++ module try: if __package__ or "." in __name__: from ._m2crypto import * else: from _m2crypto import * # type: ignore[import-not-found, misc] except ModuleNotFoundError: pass m2crypto-0.46.2/src/M2Crypto/m2urllib.py000066400000000000000000000101741506746742300177530ustar00rootroot00000000000000"""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 Optional, Union # 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 if "URLopener" in globals(): def open_https( self: URLopener, url: Union[str, bytes], data: Optional[bytes] = None, ssl_context: Optional[SSL.Context] = None, ) -> 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) # Dynamically add the SSL context to the URLopener instance. context: SSL.Context if ssl_context is not None and isinstance(ssl_context, SSL.Context): context = ssl_context else: context = SSL.Context() self.ctx = context # type: ignore[attr-defined] # Normalize the URL to a string for robust parsing. url_str = url.decode("latin-1") if isinstance(url, bytes) else url parsed = urlparse(url_str) if parsed.scheme.lower() != "https": raise IOError("url error", "invalid URL scheme") host = parsed.hostname if not host: raise IOError("http error", "no host given") # Build the host:port string for the connection. host_port = host if parsed.port: host_port += f":{parsed.port}" # Reconstruct the path and query part of the URL. selector = urlunsplit(("", "", parsed.path, parsed.query, parsed.fragment)) if not selector: selector = "/" # Handle authentication from the URL. auth_header_value = None if parsed.username: user_pass = parsed.username if parsed.password: user_pass += f":{parsed.password}" # base64.encodebytes requires bytes and returns bytes. auth_bytes = base64.encodebytes(user_pass.encode("utf-8")).strip() # The final header value must be a string. auth_header_value = f'Basic {auth_bytes.decode("ascii")}' # Mypy gets confused by our re-defined HTTPSConnection. h = httpslib.HTTPSConnection( host=host_port, ssl_context=context ) # type: ignore[call-arg] if data is not None: h.putrequest("POST", selector) h.putheader("Content-type", "application/x-www-form-urlencoded") h.putheader("Content-length", str(len(data))) else: h.putrequest("GET", selector) if auth_header_value: h.putheader("Authorization", auth_header_value) # URLopener stores extra headers in `addheaders`. for header, value in self.addheaders: # type: ignore[attr-defined] h.putheader(header, value) h.endheaders() if data is not None: h.send(data) # Get the response and wrap it in the expected addinfourl object. resp = h.getresponse() # Use the modern `.headers` attribute, not the deprecated `.msg`. return addinfourl(resp, resp.headers, "https:" + url_str) # Monkey-patch the method onto the (deprecated) URLopener class. URLopener.open_https = open_https # type: ignore[attr-defined, method-assign, used-before-def, assignment] else: import sys class URLopener: # type: ignore [no-redef] msg = f'Python {"%d.%d" % (sys.version_info[:2])} does not support URLopener any more.' def __init__(self): raise RuntimeError(self.msg) def open_https(self): raise RuntimeError(self.msg) m2crypto-0.46.2/src/M2Crypto/m2urllib2.py000066400000000000000000000177471506746742300200520ustar00rootroot00000000000000""" 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.request import AbstractHTTPHandler from urllib.response import addinfourl from typing import Optional, Type # noqa from urllib.request import * # noqa other modules want to import from urllib.error import * # noqa other modules want to import def _makefile(sock_like, mode, bufsize): """ The original implementation of this function created an infinite recursion by incorrectly monkey-patching _decref_socketios. Removing the incorrect logic resolves the issue. The SocketIO object correctly calls close() on the wrapped sock_like object by default. """ return socket.SocketIO(sock_like, mode) class RefCountingSSLConnection(SSL.Connection): """A reference counting SSL connection. It can be wrapped into a socket._fileobject or socket.SocketIO instance. If the wrapping object is closed or subject to garbage collection, this SSL connection is only shut down if there are no more references, which were created by RefCountingSSLConnection.makefile, to it. """ def __init__(self, *args, **kwargs): SSL.Connection.__init__(self, *args, **kwargs) # Start with one reference for the connection object itself. self._refs = 0 self._closed = False def _decref_socketios(self): if self._refs > 0: self._refs -= 1 if self._refs == 0 and not self._closed: # make sure we close the connection only once # (otherwise we end up with a bidirectional shutdown) self._closed = True super(RefCountingSSLConnection, self).close() def close(self): """ Close the connection. This is idempotent. The original ref-counting logic has been bypassed for this direct call to provide a simpler, more robust shutdown path for the primary use case. """ if not getattr(self, "_closed", False): self._closed = True # Directly close the parent connection without complex logic. super(RefCountingSSLConnection, self).close() def makefile(self, mode="rb", bufsize=-1): self._refs += 1 return _makefile(self, mode, bufsize) class HTTPSHandler(AbstractHTTPHandler): # type: ignore [no-redef] def __init__( self, ssl_context: Optional[SSL.Context] = None, ssl_conn_cls: Type[SSL.Connection] = RefCountingSSLConnection, ): 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() self._ssl_conn_cls = ssl_conn_cls # Copied from urllib2, so we can set the ssl context. def https_open(self, req: 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 """ 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] # Explicitly type `h` to the base class to handle both branches. h: httpslib.HTTPSConnection if target_host != host: request_uri = urldefrag(full_url)[0] # Mypy gets confused by re-defined classes, so we ignore errors. h = httpslib.ProxyHTTPSConnection( # type: ignore[call-arg] host=host, ssl_context=self.ctx, ssl_conn_cls=self._ssl_conn_cls, ) else: request_uri = req.selector # Mypy gets confused by re-defined classes, so we ignore errors. h = httpslib.HTTPSConnection( # type: ignore[call-arg] host=host, ssl_context=self.ctx, ssl_conn_cls=self._ssl_conn_cls, ) # The parent class has this attribute, mypy is just confused. h.set_debuglevel(self._debuglevel) # type: ignore[attr-defined] headers = dict(req.headers) headers.update(req.unredirected_hdrs) headers["Connection"] = "close" try: h.request(req.get_method(), request_uri, req.data, headers) r = h.getresponse() except (socket.error, SSL.SSLError) as err: h.close() # Ensure cleanup on failure. raise URLError(err) # The HTTPResponse object 'r' is the file-like object we need. # The following lines monkey-patch 'r' to add attributes that older # versions of urllib expected. r.recv = r.read # type: ignore[attr-defined] r.ssl = h.sock # type: ignore[attr-defined] # Use the modern .headers attribute, not the deprecated .msg. resp = addinfourl(r, r.headers, req.get_full_url()) resp.code = r.status resp.msg = r.reason # type: ignore[attr-defined] # Attach the connection to the response to prevent premature GC. resp._connection = h # type: ignore[attr-defined] # Hijack the close method to ensure the underlying SSL connection closes. the_connection_to_close = h.sock original_close = resp.close def new_close() -> None: try: original_close() finally: del resp._connection if the_connection_to_close: the_connection_to_close.close() # Tell mypy to ignore the assignment to a method. resp.close = new_close # type: ignore[method-assign] return resp https_request = AbstractHTTPHandler.do_request_ # Copied from urllib2 with modifications for ssl def build_opener( # type: ignore [no-redef] ssl_context: Optional[SSL.Context] = None, *handlers ) -> 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()) # type: ignore[call-arg] # Add the HTTPS handler with ssl_context if HTTPSHandler not in skip: opener.add_handler(HTTPSHandler(ssl_context)) # type: ignore[arg-type] for h in handlers: if isclass(h): h = h() opener.add_handler(h) return opener m2crypto-0.46.2/src/M2Crypto/m2xmlrpclib.py000066400000000000000000000067461506746742300204700ustar00rootroot00000000000000"""M2Crypto enhancement to xmlrpclib. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" import base64 import re from M2Crypto import __version__ as __M2Version from M2Crypto import SSL, httpslib, m2urllib2 # type: ignore from typing import Callable, Optional, Union, Any, Dict, Tuple # noqa from xmlrpc.client import ProtocolError, Transport from xmlrpc.client import * # noqa __version__ = __M2Version HostType = Union[str, Tuple[str, Dict[str, str]]] Marshallable = Any SizedBufferType = Union[bytes, bytearray] class SSL_Transport(Transport): user_agent = "M2Crypto_XMLRPC/%s - %s" % ( __version__, Transport.user_agent, ) def __init__(self, ssl_context: Optional[SSL.Context] = None, *args, **kw) -> None: Transport.__init__(self, *args, **kw) if ssl_context is None: self.ssl_ctx = SSL.Context() else: # FIX: Add assertion to make test_init_junk_ssl_context pass assert isinstance(ssl_context, SSL.Context), ssl_context self.ssl_ctx = ssl_context @staticmethod def splituser(host): """splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'.""" match = re.match("^(.*)@(.*)$", host) if match: return match.group(1, 2) return None, host @staticmethod def splitport(host): """splitport('host:port') --> 'host', 'port'.""" match = re.match("^(.*):([0-9]*)$", host) if match: host, port = match.groups() if port: return host, port return host, None # This ignore is necessary because SizedBuffer is a private Protocol we cannot import # and satisfy fully at the argument level. def request( self, host: HostType, handler: str, request_body: SizedBufferType, # type: ignore[override] verbose: int = 0, ) -> Tuple[Marshallable, ...]: # Handle username and password. user_passwd, host_port = self.splituser(host) _host, _port = self.splitport(host_port) _host_str = _host.decode("latin-1") if isinstance(_host, bytes) else _host h = httpslib.HTTPSConnection(_host_str, int(_port), ssl_context=self.ssl_ctx) # type: ignore[call-arg] try: if verbose: h.set_debuglevel(1) h.putrequest("POST", handler) # required by HTTP/1.1 h.putheader("Host", _host_str) # 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.encodebytes(user_passwd).strip() h.putheader("Authorization", "Basic %s" % auth.decode("ascii")) h.endheaders() if request_body: h.send(request_body) response = h.getresponse() host_str = host if isinstance(host, str) else str(host) headers_dict = dict(response.getheaders()) if response.status != 200: raise ProtocolError( host_str + handler, response.status, response.reason, headers_dict, ) self.verbose = verbose return self.parse_response(response) finally: h.close() m2crypto-0.46.2/src/M2Crypto/py.typed000066400000000000000000000000001506746742300173330ustar00rootroot00000000000000m2crypto-0.46.2/src/M2Crypto/threading.py000066400000000000000000000005711506746742300201700ustar00rootroot00000000000000""" M2Crypto threading support, required for multithreaded applications. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.""" # M2Crypto from M2Crypto import m2 def init() -> None: """ Initialize threading support. """ m2.threading_init() def cleanup() -> None: """ End and cleanup threading support. """ m2.threading_cleanup() m2crypto-0.46.2/src/M2Crypto/types.py000066400000000000000000000040031506746742300173610ustar00rootroot00000000000000# src/M2Crypto/types.py """ Type aliases for opaque C structures used in M2Crypto's C-bindings. """ from typing import Any, List, NewType # The base type 'object' is used because these are opaque pointers # at the Python level. NewType ensures they are treated as distinct types by mypy. AES_KEY = NewType("AES_KEY", object) ASN1_BitString = NewType("ASN1_BitString", object) ASN1_Integer = NewType("ASN1_Integer", object) ASN1_Object = NewType("ASN1_Object", object) ASN1_String = NewType("ASN1_String", object) ASN1_Time = NewType("ASN1_Time", object) BIGNUM = NewType("BIGNUM", object) BIO_METHOD = NewType("BIO_METHOD", object) BIO = NewType("BIO", object) DH = NewType("DH", object) DSA = NewType("DSA", object) DSA_SIG = NewType("DSA_SIG", object) EC = NewType("EC", object) EC_KEY = NewType("EC_KEY", object) ECDSA_SIG = NewType("ECDSA_SIG", object) ENGINE = NewType("ENGINE", object) EVP_CIPHER_CTX = NewType("EVP_CIPHER_CTX", object) EVP_CIPHER = NewType("EVP_CIPHER", object) EVP_MD_CTX = NewType("EVP_MD_CTX", object) EVP_MD = NewType("EVP_MD", object) EVP_PKEY_CTX = NewType("EVP_PKEY_CTX", object) EVP_PKEY = NewType("EVP_PKEY", object) HMAC_CTX = NewType("HMAC_CTX", object) PKCS7 = NewType("PKCS7", object) RC4_KEY = NewType("RC4_KEY", object) RSA = NewType("RSA", object) SSL_CIPHER = NewType("SSL_CIPHER", object) SSL_CTX = NewType("SSL_CTX", object) SSL_METHOD = NewType("SSL_METHOD", object) SSL = NewType("SSL", object) SSL_SESSION = NewType("SSL_SESSION", object) X509_CRL = NewType("X509_CRL", object) X509_EXTENSION = NewType("X509_EXTENSION", object) X509 = NewType("X509", object) X509_NAME = NewType("X509_NAME", object) X509_NAME_ENTRY = NewType("X509_NAME_ENTRY", object) X509_REQ = NewType("X509_REQ", object) X509_STORE = NewType("X509_STORE", object) X509_STORE_CTX = NewType("X509_STORE_CTX", object) X509V3_CTX = NewType("X509V3_CTX", object) # Generic STACK_OF type for simplicity STACK_OF = List[Any] STACK_OF_X509 = List[X509] STACK_OF_SSL_CIPHER = List[SSL_CIPHER] STACK_OF_X509_EXTENSION = List[X509_EXTENSION] m2crypto-0.46.2/src/M2Crypto/util.py000066400000000000000000000046161506746742300172040ustar00rootroot00000000000000""" 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 ( Callable, Optional, TextIO, Tuple, Union, ) # see https://github.com/python/typeshed/issues/222 AddrType = Union[Tuple[str, int], str] # COMPATIBILITY: Literal is only Python 3.8+ # ModeStr = Literal['r', 'w', 'rw', 'rb', 'wb', 'rwb'] ModeStr = str log = logging.getLogger("util") class UtilError(Exception): pass m2.util_init(UtilError) def is_32bit() -> bool: # or alternatively (slightly slower) # (struct.calcsize("P") * 8) == 32 return not (sys.maxsize > 2**32) def expectedFailureIf(condition: bool) -> Callable: """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: str, blklen: int = 8) -> str: pad = 8 - (len(data) % 8) return data + chr(pad) * pad def pkcs7_pad(data: str, blklen: 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: bytes) -> str: return binascii.b2a_base64(b)[:-1].decode() def octx_to_num(x: bytes) -> int: return int(binascii.hexlify(x), 16) def genparam_callback(p: int, n: int) -> int: ch = [".", "+", "*", "\n"] sys.stdout.write(ch[p]) sys.stdout.flush() return 1 def quiet_genparam_callback(p: int, n: int) -> int: return 1 def passphrase_callback( v: bool, prompt1: str = "Enter passphrase:", prompt2: str = "Verify passphrase:", ) -> 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) -> str: return "" m2crypto-0.46.2/src/SWIG/000077500000000000000000000000001506746742300147405ustar00rootroot00000000000000m2crypto-0.46.2/src/SWIG/Makefile000066400000000000000000000011631506746742300164010ustar00rootroot00000000000000# $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.46.2/src/SWIG/_aes.i000066400000000000000000000043131506746742300160220ustar00rootroot00000000000000/* 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) { Py_buffer vbuf; if (m2_PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) == -1) return NULL; if (op == 0) AES_set_encrypt_key((const unsigned char *)vbuf.buf, bits, key); else AES_set_decrypt_key((const unsigned char *)vbuf.buf, bits, key); m2_PyBuffer_Release(value, &vbuf); 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) { unsigned char *out; PyObject *res; Py_buffer buf; if (m2_PyObject_GetBuffer(in, &buf, PyBUF_SIMPLE) == -1) return NULL; if (!(out=(unsigned char *)PyMem_Malloc(outlen))) { PyErr_SetString(PyExc_MemoryError, "AES_crypt"); m2_PyBuffer_Release(in, &buf); return NULL; } if (op == 0) AES_encrypt((const unsigned char *)buf.buf, out, key); else AES_decrypt((const unsigned char *)buf.buf, out, key); m2_PyBuffer_Release(in, &buf); res = PyBytes_FromStringAndSize((char*)out, outlen); PyMem_Free(out); return res; } int AES_type_check(AES_KEY *key) { return 1; } %} m2crypto-0.46.2/src/SWIG/_asn1.i000066400000000000000000000142451506746742300161210ustar00rootroot00000000000000/* -*- 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.46.2/src/SWIG/_bio.i000066400000000000000000000322021506746742300160210ustar00rootroot00000000000000/* -*- 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) { Py_buffer fbuf; int ret; if (m2_PyObject_GetBufferInt(from, &fbuf, PyBUF_SIMPLE) == -1) return -1; Py_BEGIN_ALLOW_THREADS ret = BIO_write(bio, fbuf.buf, fbuf.len); Py_END_ALLOW_THREADS if (ret < 0) { if (ERR_peek_error()) { m2_PyErr_Msg(_bio_err); return -1; } } m2_PyBuffer_Release(from, &fbuf); 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) { Py_buffer kbuf, ibuf; if (m2_PyObject_GetBuffer(key, &kbuf, PyBUF_SIMPLE) == -1) { PyErr_SetString(PyExc_ValueError, "Reading of key from buffer failed."); return NULL; } if (m2_PyObject_GetBuffer(iv, &ibuf, PyBUF_SIMPLE) == -1) { m2_PyBuffer_Release(key, &kbuf); PyErr_SetString(PyExc_ValueError, "Reading of IV from buffer failed."); return NULL; } #if OPENSSL_VERSION_NUMBER >= 0x30000000L if (!BIO_set_cipher(b, (const EVP_CIPHER *)c, (unsigned char *)kbuf.buf, (unsigned char *)ibuf.buf, 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.buf, (unsigned char *)ibuf.buf, op); #endif m2_PyBuffer_Release(iv, &ibuf); m2_PyBuffer_Release(key, &kbuf); 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; Py_BEGIN_ALLOW_THREADS method = PyMem_Malloc(sizeof(BIO_METHOD)); Py_END_ALLOW_THREADS 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; } PyMem_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.46.2/src/SWIG/_bn.i000066400000000000000000000057201506746742300156540ustar00rootroot00000000000000/* -*- 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.46.2/src/SWIG/_dh.i000066400000000000000000000135631506746742300156540ustar00rootroot00000000000000/* 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) { Py_buffer pkbuf; int klen; void *key; BIGNUM *pk; PyObject *ret; if (m2_PyObject_GetBufferInt(pubkey, &pkbuf, PyBUF_SIMPLE) == -1) return NULL; if (!(pk = BN_mpi2bn((unsigned char *)pkbuf.buf, pkbuf.len, 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"); m2_PyBuffer_Release(pubkey, &pkbuf); return NULL; } if ((klen = DH_compute_key((unsigned char *)key, pk, dh)) == -1) { BN_free(pk); PyMem_Free(key); m2_PyErr_Msg(_dh_err); m2_PyBuffer_Release(pubkey, &pkbuf); return NULL; } ret = PyBytes_FromStringAndSize((const char *)key, klen); BN_free(pk); PyMem_Free(key); m2_PyBuffer_Release(pubkey, &pkbuf); 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 = NULL; BIGNUM* g = NULL; Py_buffer pbuf, gbuf; /* Try pval as a buffer (MPI format) */ if (m2_PyObject_GetBufferInt(pval, &pbuf, PyBUF_SIMPLE) != -1) { if (!(p = BN_mpi2bn((unsigned char *)pbuf.buf, pbuf.len, NULL))) { PyErr_SetString(_dh_err, ERR_reason_error_string(ERR_get_error())); m2_PyBuffer_Release(pval, &pbuf); return NULL; } m2_PyBuffer_Release(pval, &pbuf); } else { PyErr_Clear(); /* Clear buffer-related errors and try integer conversion */ } /* If not set by buffer conversion, try standard BIGNUM conversion (e.g., from Python int) */ if (p == NULL) { if (!(p = m2_PyObject_AsBIGNUM(pval, _dh_err))) { return NULL; /* Failed both buffer and standard conversion */ } } /* Try gval as a buffer (MPI format) */ if (m2_PyObject_GetBufferInt(gval, &gbuf, PyBUF_SIMPLE) != -1) { if (!(g = BN_mpi2bn((unsigned char *)gbuf.buf, gbuf.len, NULL))) { PyErr_SetString(_dh_err, ERR_reason_error_string(ERR_get_error())); m2_PyBuffer_Release(gval, &gbuf); BN_free(p); /* Clean up p as well */ return NULL; } m2_PyBuffer_Release(gval, &gbuf); } else { PyErr_Clear(); /* Clear buffer-related errors and try integer conversion */ } /* If not set by buffer conversion, try standard BIGNUM conversion (e.g., from Python int) */ if (g == NULL) { if (!(g = m2_PyObject_AsBIGNUM(gval, _dh_err))) { BN_free(p); /* Clean up p */ return NULL; /* Failed both buffer and standard conversion */ } } 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.46.2/src/SWIG/_dsa.i000066400000000000000000000301631506746742300160230ustar00rootroot00000000000000/* 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 = NULL; BIGNUM* q = NULL; BIGNUM* g = NULL; Py_buffer pbuf, qbuf, gbuf; /* --- Process P (Prime) --- */ if (m2_PyObject_GetBufferInt(pval, &pbuf, PyBUF_SIMPLE) != -1) { if (!(p = BN_mpi2bn((unsigned char *)pbuf.buf, pbuf.len, NULL))) { PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); m2_PyBuffer_Release(pval, &pbuf); return NULL; } m2_PyBuffer_Release(pval, &pbuf); } else { PyErr_Clear(); } if (p == NULL) { if (!(p = m2_PyObject_AsBIGNUM(pval, _dsa_err))) { return NULL; } } /* --- Process Q (Subprime) --- */ if (m2_PyObject_GetBufferInt(qval, &qbuf, PyBUF_SIMPLE) != -1) { if (!(q = BN_mpi2bn((unsigned char *)qbuf.buf, qbuf.len, NULL))) { PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); m2_PyBuffer_Release(qval, &qbuf); BN_free(p); /* Cleanup previous */ return NULL; } m2_PyBuffer_Release(qval, &qbuf); } else { PyErr_Clear(); } if (q == NULL) { if (!(q = m2_PyObject_AsBIGNUM(qval, _dsa_err))) { BN_free(p); /* Cleanup previous */ return NULL; } } /* --- Process G (Generator) --- */ if (m2_PyObject_GetBufferInt(gval, &gbuf, PyBUF_SIMPLE) != -1) { if (!(g = BN_mpi2bn((unsigned char *)gbuf.buf, gbuf.len, NULL))) { PyErr_SetString(_dsa_err, ERR_reason_error_string(ERR_get_error())); m2_PyBuffer_Release(gval, &gbuf); BN_free(p); BN_free(q); /* Cleanup previous */ return NULL; } m2_PyBuffer_Release(gval, &gbuf); } else { PyErr_Clear(); } if (g == NULL) { if (!(g = m2_PyObject_AsBIGNUM(gval, _dsa_err))) { BN_free(p); BN_free(q); /* Cleanup previous */ return NULL; } } /* --- Set parameters using OpenSSL 1.1.0+ API --- */ 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; Py_buffer vbuf; if (m2_PyObject_GetBufferInt(value, &vbuf, PyBUF_SIMPLE) == -1) return NULL; if (!(bn = BN_mpi2bn((unsigned char *)vbuf.buf, vbuf.len, NULL))) { m2_PyErr_Msg(_dsa_err); m2_PyBuffer_Release(value, &vbuf); return NULL; } m2_PyBuffer_Release(value, &vbuf); 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) { Py_buffer vbuf; PyObject *tuple; DSA_SIG *sig; if (m2_PyObject_GetBufferInt(value, &vbuf, PyBUF_SIMPLE) == -1) return NULL; if (!(sig = DSA_do_sign(vbuf.buf, vbuf.len, dsa))) { m2_PyErr_Msg(_dsa_err); m2_PyBuffer_Release(value, &vbuf); return NULL; } if (!(tuple = PyTuple_New(2))) { DSA_SIG_free(sig); PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails"); m2_PyBuffer_Release(value, &vbuf); 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); m2_PyBuffer_Release(value, &vbuf); return tuple; } int dsa_verify(DSA *dsa, PyObject *value, PyObject *r, PyObject *s) { Py_buffer vbuf, rbuf, sbuf; DSA_SIG *sig; BIGNUM* pr, *ps; int ret; if (m2_PyObject_GetBufferInt(value, &vbuf, PyBUF_SIMPLE) == -1) return -1; if (m2_PyObject_GetBufferInt(r, &rbuf, PyBUF_SIMPLE) == -1) { m2_PyBuffer_Release(value, &vbuf); return -1; } if (m2_PyObject_GetBufferInt(s, &sbuf, PyBUF_SIMPLE) == -1) { m2_PyBuffer_Release(value, &vbuf); m2_PyBuffer_Release(r, &rbuf); return -1; } if (!(sig = DSA_SIG_new())) { m2_PyErr_Msg(_dsa_err); m2_PyBuffer_Release(value, &vbuf); m2_PyBuffer_Release(r, &rbuf); m2_PyBuffer_Release(s, &sbuf); return -1; } pr = BN_mpi2bn((unsigned char *)rbuf.buf, rbuf.len, NULL); if (!pr) { m2_PyErr_Msg(_dsa_err); DSA_SIG_free(sig); m2_PyBuffer_Release(value, &vbuf); m2_PyBuffer_Release(r, &rbuf); m2_PyBuffer_Release(s, &sbuf); return -1; } ps = BN_mpi2bn((unsigned char *)sbuf.buf, sbuf.len, NULL); if (!ps) { m2_PyErr_Msg(_dsa_err); DSA_SIG_free(sig); m2_PyBuffer_Release(value, &vbuf); m2_PyBuffer_Release(r, &rbuf); m2_PyBuffer_Release(s, &sbuf); BN_free(pr); return -1; } if (!DSA_SIG_set0(sig, pr, ps)) { m2_PyErr_Msg(_dsa_err); DSA_SIG_free(sig); m2_PyBuffer_Release(value, &vbuf); m2_PyBuffer_Release(r, &rbuf); m2_PyBuffer_Release(s, &sbuf); BN_free(pr); BN_free(ps); return -1; } ret = DSA_do_verify(vbuf.buf, vbuf.len, sig, dsa); DSA_SIG_free(sig); if (ret == -1) m2_PyErr_Msg(_dsa_err); m2_PyBuffer_Release(value, &vbuf); m2_PyBuffer_Release(r, &rbuf); m2_PyBuffer_Release(s, &sbuf); return ret; } PyObject *dsa_sign_asn1(DSA *dsa, PyObject *value) { void *sigbuf; Py_buffer vbuf; PyObject *ret; unsigned int siglen; if (m2_PyObject_GetBufferInt(value, &vbuf, PyBUF_SIMPLE) == -1) return NULL; if (!(sigbuf = PyMem_Malloc(DSA_size(dsa)))) { PyErr_SetString(PyExc_MemoryError, "dsa_sign_asn1"); m2_PyBuffer_Release(value, &vbuf); return NULL; } if (!DSA_sign(0, vbuf.buf, vbuf.len, (unsigned char *)sigbuf, &siglen, dsa)) { m2_PyErr_Msg(_dsa_err); PyMem_Free(sigbuf); m2_PyBuffer_Release(value, &vbuf); return NULL; } ret = PyBytes_FromStringAndSize(sigbuf, siglen); m2_PyBuffer_Release(value, &vbuf); PyMem_Free(sigbuf); return ret; } int dsa_verify_asn1(DSA *dsa, PyObject *value, PyObject *sig) { int ret; Py_buffer vbuf, sbuf; if (m2_PyObject_GetBufferInt(value, &vbuf, PyBUF_SIMPLE) == -1) return -1; if (m2_PyObject_GetBufferInt(sig, &sbuf, PyBUF_SIMPLE) == -1) { m2_PyBuffer_Release(value, &vbuf); return -1; } if ((ret = DSA_verify(0, (const void *) vbuf.buf, vbuf.len, (void *) sbuf.buf, sbuf.len, dsa)) == -1) m2_PyErr_Msg(_dsa_err); m2_PyBuffer_Release(value, &vbuf); m2_PyBuffer_Release(sig, &sbuf); 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.46.2/src/SWIG/_ec.i000066400000000000000000000374561506746742300156570ustar00rootroot00000000000000/* 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) { PyObject *tuple; ECDSA_SIG *sig; Py_buffer vbuf; if (m2_PyObject_GetBufferInt(value, &vbuf, PyBUF_SIMPLE) == -1) return NULL; if (!(sig = ECDSA_do_sign(vbuf.buf, vbuf.len, key))) { m2_PyErr_Msg(_ec_err); m2_PyBuffer_Release(value, &vbuf); return NULL; } if (!(tuple = PyTuple_New(2))) { ECDSA_SIG_free(sig); PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails"); m2_PyBuffer_Release(value, &vbuf); 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); m2_PyBuffer_Release(value, &vbuf); return tuple; } int ecdsa_verify(EC_KEY *key, PyObject *value, PyObject *r, PyObject *s) { Py_buffer vbuf, rbuf, sbuf; ECDSA_SIG *sig; int ret; BIGNUM* pr, *ps; if (m2_PyObject_GetBufferInt(value, &vbuf, PyBUF_SIMPLE) == -1) return -1; if (m2_PyObject_GetBufferInt(r, &rbuf, PyBUF_SIMPLE) == -1) { m2_PyBuffer_Release(value, &vbuf); return -1; } if (m2_PyObject_GetBufferInt(s, &sbuf, PyBUF_SIMPLE) == -1) { m2_PyBuffer_Release(value, &vbuf); m2_PyBuffer_Release(r, &rbuf); return -1; } pr = BN_mpi2bn((unsigned char *)rbuf.buf, rbuf.len, NULL); if (!pr) { m2_PyErr_Msg(_ec_err); m2_PyBuffer_Release(value, &vbuf); m2_PyBuffer_Release(r, &rbuf); m2_PyBuffer_Release(s, &sbuf); return -1; } ps = BN_mpi2bn((unsigned char *)sbuf.buf, sbuf.len, NULL); if (!ps) { m2_PyErr_Msg(_ec_err); BN_free(pr); m2_PyBuffer_Release(value, &vbuf); m2_PyBuffer_Release(r, &rbuf); m2_PyBuffer_Release(s, &sbuf); return -1; } if (!(sig = ECDSA_SIG_new())) { m2_PyErr_Msg(_ec_err); m2_PyBuffer_Release(value, &vbuf); m2_PyBuffer_Release(r, &rbuf); m2_PyBuffer_Release(s, &sbuf); 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.buf, vbuf.len, sig, key); ECDSA_SIG_free(sig); m2_PyBuffer_Release(value, &vbuf); m2_PyBuffer_Release(r, &rbuf); m2_PyBuffer_Release(s, &sbuf); if (ret == -1) m2_PyErr_Msg(_ec_err); return ret; } PyObject *ecdsa_sign_asn1(EC_KEY *key, PyObject *value) { Py_buffer vbuf; void *sigbuf; unsigned int siglen; PyObject *ret; if (m2_PyObject_GetBufferInt(value, &vbuf, PyBUF_SIMPLE) == -1) return NULL; if (!(sigbuf = PyMem_Malloc(ECDSA_size(key)))) { PyErr_SetString(PyExc_MemoryError, "ecdsa_sign_asn1"); m2_PyBuffer_Release(value, &vbuf); return NULL; } if (!ECDSA_sign(0, vbuf.buf, vbuf.len, (unsigned char *)sigbuf, &siglen, key)) { m2_PyErr_Msg(_ec_err); PyMem_Free(sigbuf); m2_PyBuffer_Release(value, &vbuf); return NULL; } ret = PyBytes_FromStringAndSize(sigbuf, siglen); PyMem_Free(sigbuf); m2_PyBuffer_Release(value, &vbuf); return ret; } int ecdsa_verify_asn1(EC_KEY *key, PyObject *value, PyObject *sig) { Py_buffer vbuf, sbuf; int ret; if (m2_PyObject_GetBufferInt(value, &vbuf, PyBUF_SIMPLE) == -1) return -1; if (m2_PyObject_GetBufferInt(sig, &sbuf, PyBUF_SIMPLE) == -1) { m2_PyBuffer_Release(value, &vbuf); return -1; } if ((ret = ECDSA_verify(0, (const void *) vbuf.buf, vbuf.len, sbuf.buf, sbuf.len, key)) == -1) m2_PyErr_Msg(_ec_err); m2_PyBuffer_Release(value, &vbuf); m2_PyBuffer_Release(sig, &sbuf); 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) { Py_buffer keypairbuf; const unsigned char *tempBuf; EC_KEY *keypair; if (m2_PyObject_GetBuffer(pubkey, &keypairbuf, PyBUF_SIMPLE) == -1) return NULL; tempBuf = (const unsigned char *)keypairbuf.buf; if ((keypair = d2i_EC_PUBKEY( NULL, &tempBuf, keypairbuf.len)) == 0) { m2_PyErr_Msg(_ec_err); m2_PyBuffer_Release(pubkey, &keypairbuf); return NULL; } m2_PyBuffer_Release(pubkey, &keypairbuf); return keypair; } EC_KEY* ec_key_from_pubkey_params(int nid, PyObject *pubkey) { Py_buffer keypairbuf; const unsigned char *tempBuf; EC_KEY *keypair; if (m2_PyObject_GetBuffer(pubkey, &keypairbuf, PyBUF_SIMPLE) == -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.buf; if ((o2i_ECPublicKey( &keypair, &tempBuf, keypairbuf.len)) == 0) { m2_PyErr_Msg(_ec_err); m2_PyBuffer_Release(pubkey, &keypairbuf); return NULL; } m2_PyBuffer_Release(pubkey, &keypairbuf); 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.46.2/src/SWIG/_evp.i000066400000000000000000000660331506746742300160530ustar00rootroot00000000000000/* -*- 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 = NULL; PyObject *ret; Py_buffer passbuf, saltbuf; if (m2_PyObject_GetBufferInt(pass, &passbuf, PyBUF_SIMPLE) == -1) return NULL; if (m2_PyObject_GetBufferInt(salt, &saltbuf, PyBUF_SIMPLE) == -1) { m2_PyBuffer_Release(pass, &passbuf); return NULL; } if (!(key = PyMem_Malloc(keylen))) { PyErr_SetString(PyExc_MemoryError, "pkcs5_pbkdf2_hmac_sha1"); m2_PyBuffer_Release(pass, &passbuf); m2_PyBuffer_Release(salt, &saltbuf); return NULL; } PKCS5_PBKDF2_HMAC_SHA1((char *) passbuf.buf, passbuf.len, (unsigned char *) saltbuf.buf, saltbuf.len, iter, keylen, key); ret = PyBytes_FromStringAndSize((char*)key, keylen); OPENSSL_cleanse(key, keylen); PyMem_Free(key); m2_PyBuffer_Release(pass, &passbuf); m2_PyBuffer_Release(salt, &saltbuf); 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) { Py_buffer buf; int ret; if (m2_PyObject_GetBuffer(blob, &buf, PyBUF_SIMPLE) == -1) return -1; ret = EVP_DigestUpdate(ctx, buf.buf, buf.len); m2_PyBuffer_Release(blob, &buf); return ret; } 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) { Py_buffer kbuf; if (m2_PyObject_GetBufferInt(key, &kbuf, PyBUF_SIMPLE) == -1) { if (PyErr_Occurred()) { PyErr_Clear(); PyErr_Format(_evp_err, "Invalid key: empty buffer object"); } return NULL; } if (!HMAC_Init(ctx, kbuf.buf, kbuf.len, md)) { PyErr_SetString(_evp_err, "HMAC_Init failed"); m2_PyBuffer_Release(key, &kbuf); return NULL; } m2_PyBuffer_Release(key, &kbuf); Py_RETURN_NONE; } PyObject *hmac_update(HMAC_CTX *ctx, PyObject *blob) { Py_buffer buf; if (m2_PyObject_GetBuffer(blob, &buf, PyBUF_SIMPLE) == -1) return NULL; if (!HMAC_Update(ctx, buf.buf, buf.len)) { PyErr_SetString(_evp_err, "HMAC_Update failed"); m2_PyBuffer_Release(blob, &buf); return NULL; } m2_PyBuffer_Release(blob, &buf); 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) { void *blob; unsigned int blen; PyObject *ret; Py_buffer kbuf, dbuf; if (m2_PyObject_GetBufferInt(key, &kbuf, PyBUF_SIMPLE) == -1) return NULL; if (m2_PyObject_GetBuffer(data, &dbuf, PyBUF_SIMPLE) == -1) { m2_PyBuffer_Release(key, &kbuf); return NULL; } if (!(blob = PyMem_Malloc(EVP_MAX_MD_SIZE))) { PyErr_SetString(PyExc_MemoryError, "hmac"); m2_PyBuffer_Release(key, &kbuf); m2_PyBuffer_Release(data, &dbuf); return NULL; } HMAC(md, kbuf.buf, kbuf.len, dbuf.buf, dbuf.len, blob, &blen); blob = PyMem_Realloc(blob, blen); ret = PyBytes_FromStringAndSize(blob, blen); PyMem_Free(blob); m2_PyBuffer_Release(key, &kbuf); m2_PyBuffer_Release(data, &dbuf); 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]; int klen; PyObject *ret; Py_buffer dbuf, sbuf; if (m2_PyObject_GetBufferInt(data, &dbuf, PyBUF_SIMPLE) == -1) return NULL; if (m2_PyObject_GetBuffer(salt, &sbuf, PyBUF_SIMPLE) == -1) { m2_PyBuffer_Release(data, &dbuf); return NULL; } assert((sbuf.len == 8) || (sbuf.len == 0)); klen = EVP_BytesToKey(cipher, md, (unsigned char *)sbuf.buf, (unsigned char *)dbuf.buf, dbuf.len, iter, key, NULL); /* Since we are not returning IV no need to derive it */ ret = PyBytes_FromStringAndSize((char*)key, klen); m2_PyBuffer_Release(data, &dbuf); m2_PyBuffer_Release(salt, &sbuf); return ret; } PyObject *cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, PyObject *key, PyObject *iv, int mode) { Py_buffer kbuf, ibuf; if (key == Py_None) kbuf.buf = NULL; else if (m2_PyObject_GetBuffer(key, &kbuf, PyBUF_SIMPLE) == -1) { if (PyErr_Occurred()) { PyErr_Clear(); PyErr_Format(_evp_err, "Invalid key: empty buffer object"); } return NULL; } if (iv == Py_None) ibuf.buf = NULL; else if (m2_PyObject_GetBuffer(iv, &ibuf, PyBUF_SIMPLE) == -1) { if (PyErr_Occurred()) { PyErr_Clear(); PyErr_Format(_evp_err, "Invalid IV: empty buffer object"); } return NULL; } if (!EVP_CipherInit(ctx, cipher, (unsigned char *)kbuf.buf, (unsigned char *)ibuf.buf, mode)) { m2_PyErr_Msg(_evp_err); m2_PyBuffer_Release(key, &kbuf); m2_PyBuffer_Release(iv, &ibuf); return NULL; } m2_PyBuffer_Release(key, &kbuf); m2_PyBuffer_Release(iv, &ibuf); Py_RETURN_NONE; } PyObject *cipher_update(EVP_CIPHER_CTX *ctx, PyObject *blob) { int olen; void *obuf; PyObject *ret; Py_buffer buf; if (m2_PyObject_GetBuffer(blob, &buf, PyBUF_SIMPLE) == -1) return NULL; if (!(obuf = PyMem_Malloc(buf.len + EVP_CIPHER_CTX_block_size(ctx) - 1))) { PyErr_SetString(PyExc_MemoryError, "cipher_update"); m2_PyBuffer_Release(blob, &buf); return NULL; } if (!EVP_CipherUpdate(ctx, obuf, &olen, (unsigned char *)buf.buf, buf.len)) { PyMem_Free(obuf); m2_PyErr_Msg(_evp_err); m2_PyBuffer_Release(blob, &buf); return NULL; } ret = PyBytes_FromStringAndSize(obuf, olen); PyMem_Free(obuf); m2_PyBuffer_Release(blob, &buf); 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) { Py_buffer buf; if (m2_PyObject_GetBuffer(blob, &buf, PyBUF_SIMPLE) == -1) return NULL; if (!EVP_SignUpdate(ctx, buf.buf, buf.len)) { m2_PyErr_Msg(_evp_err); m2_PyBuffer_Release(blob, &buf); return NULL; } m2_PyBuffer_Release(blob, &buf); 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) { Py_buffer buf; int ret; if (m2_PyObject_GetBuffer(blob, &buf, PyBUF_SIMPLE) == -1) return -1; ret = EVP_VerifyUpdate(ctx, buf.buf, buf.len); m2_PyBuffer_Release(blob, &buf); return ret; } int verify_final(EVP_MD_CTX *ctx, PyObject *blob, EVP_PKEY *pkey) { Py_buffer kbuf; int ret; if (m2_PyObject_GetBufferInt(blob, &kbuf, PyBUF_SIMPLE) == -1) return -1; ret = EVP_VerifyFinal(ctx, (unsigned char *) kbuf.buf, kbuf.len, pkey); m2_PyBuffer_Release(blob, &kbuf); return ret; } 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) { Py_buffer buf; if (m2_PyObject_GetBufferInt(blob, &buf, PyBUF_SIMPLE) == -1) return NULL; if (!EVP_DigestSignUpdate(ctx, buf.buf, buf.len)) { m2_PyErr_Msg(_evp_err); m2_PyBuffer_Release(blob, &buf); return NULL; } m2_PyBuffer_Release(blob, &buf); 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; Py_buffer msgbuf; unsigned char *sigbuf; size_t siglen = 0; if (m2_PyObject_GetBufferInt(msg, &msgbuf, PyBUF_SIMPLE) == -1) return NULL; if (!EVP_DigestSign(ctx, NULL, &siglen, msgbuf.buf, msgbuf.len)) { m2_PyErr_Msg(_evp_err); m2_PyBuffer_Release(msg, &msgbuf); return NULL; } sigbuf = (unsigned char*)OPENSSL_malloc(siglen); if (!sigbuf) { PyErr_SetString(PyExc_MemoryError, "digest_sign"); m2_PyBuffer_Release(msg, &msgbuf); return NULL; } if (!EVP_DigestSign(ctx, sigbuf, &siglen, msgbuf.buf, msgbuf.len)) { 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); m2_PyBuffer_Release(msg, &msgbuf); 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) { Py_buffer buf; int ret; if (m2_PyObject_GetBufferInt(blob, &buf, PyBUF_SIMPLE) == -1) return -1; ret = EVP_DigestVerifyUpdate(ctx, buf.buf, buf.len); m2_PyBuffer_Release(blob, &buf); return ret; } int digest_verify_final(EVP_MD_CTX *ctx, PyObject *blob) { Py_buffer sigbuf; int ret; if (m2_PyObject_GetBufferInt(blob, &sigbuf, PyBUF_SIMPLE) == -1) return -1; ret = EVP_DigestVerifyFinal(ctx, (unsigned char *)sigbuf.buf, sigbuf.len); m2_PyBuffer_Release(blob, &sigbuf); return ret; } #if OPENSSL_VERSION_NUMBER >= 0x10101000L int digest_verify(EVP_MD_CTX *ctx, PyObject *sig, PyObject *msg) { Py_buffer sigbuf, msgbuf; int ret; if (m2_PyObject_GetBufferInt(sig, &sigbuf, PyBUF_SIMPLE) == -1) return -1; if (m2_PyObject_GetBufferInt(msg, &msgbuf, PyBUF_SIMPLE) == -1) { m2_PyBuffer_Release(sig, &sigbuf); return -1; } ret = EVP_DigestVerify(ctx, sigbuf.buf, sigbuf.len, msgbuf.buf, msgbuf.len); m2_PyBuffer_Release(sig, &sigbuf); m2_PyBuffer_Release(msg, &msgbuf); return ret; } #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; } PyObject *pkey_get_raw_pub_key_sha1(EVP_PKEY *pkey) { unsigned char *pub_key_bytes = NULL; int len = 0; PyObject *ret = NULL; unsigned char md[SHA_DIGEST_LENGTH]; /* Export the public key data into an allocated buffer. */ /* i2d_PublicKey() returns the number of bytes written, or -1 on error. * It allocates the buffer and updates the pointer if the pointer is NULL. */ len = i2d_PublicKey(pkey, &pub_key_bytes); if (len < 0) { m2_PyErr_Msg(_evp_err); return NULL; } /* Compute SHA1 hash of the raw public key data (SKID mechanism 1) */ if (!SHA1(pub_key_bytes, len, md)) { PyErr_SetString(_evp_err, "SHA1 digest computation failed"); OPENSSL_free(pub_key_bytes); return NULL; } /* Create a Python bytes object from the SHA1 digest */ ret = PyBytes_FromStringAndSize((char*)md, SHA_DIGEST_LENGTH); /* Free the buffer allocated by i2d_PublicKey */ if (pub_key_bytes) { OPENSSL_free(pub_key_bytes); } 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.46.2/src/SWIG/_lib.h000066400000000000000000000010601506746742300160130ustar00rootroot00000000000000/* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. */ /* $Id$ */ #include 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); 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.46.2/src/SWIG/_lib.i000066400000000000000000000441541506746742300160270ustar00rootroot00000000000000/* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. */ /* $Id$ */ %{ /* for time_t_bits */ #include /* For snprintf, strncpy */ #include #include #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 %inline %{ /* test for time_t size */ int time_t_bits() { return sizeof(time_t) * 8; } %} /* logging with Python logging module */ %include _python_logging.i %ignore m2_PyBuffer_Release; %ignore m2_PyErr_SetString_from_openssl_error; %ignore m2_PyObject_GetBuffer; %ignore m2_PyObject_GetBufferInt; %ignore m2_PyString_AsStringAndSizeInt; %ignore PyBuffer_Release; %ignore PyObject_GetBuffer; %ignore PyObject_CheckBuffer; %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); } }; %{ /* * Convert an OpenSSL error code into a Python Exception string. */ void m2_PyErr_SetString_from_openssl_error(PyObject *err_type, unsigned long err_code) { char err_buf[256]; const char *reason_str = NULL; reason_str = ERR_reason_error_string(err_code); if (reason_str != NULL) { // OpenSSL provided a reason string. Use it directly. strncpy(err_buf, reason_str, sizeof(err_buf)); err_buf[sizeof(err_buf) - 1] = '\0'; } else { // OpenSSL did not provide a specific reason string for this code. // Create a fallback message including the raw error code for diagnostics. snprintf(err_buf, sizeof(err_buf), "Unknown OpenSSL error code: %lu", err_code); } PyErr_SetString(err_type, err_buf); } 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_PyObject_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { int ret; if (PyObject_CheckBuffer(obj)) ret = PyObject_GetBuffer(obj, view, flags); else { /* In modern Python (3.13+), if an object doesn't support the * Buffer Protocol, it's not a valid input for binary operations. * We remove the deprecated PyObject_AsReadBuffer fallback. */ PyErr_SetString(PyExc_TypeError, "expected a readable buffer object (bytes, bytearray, etc.)"); return -1; } 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"); PyBuffer_Release(view); return -1; } return 0; } /* * Convert an OpenSSL error code into a Python Exception string. */ static BIGNUM* m2_PyObject_AsBIGNUM(PyObject* value, PyObject* _py_exc) { BIGNUM* bn = NULL; Py_buffer vbuf; if (!_py_exc || !PyExceptionClass_Check(_py_exc)) { PyErr_SetString(PyExc_TypeError, "Invalid exception type provided internally."); return NULL; } if (m2_PyObject_GetBufferInt(value, &vbuf, PyBUF_SIMPLE) == -1) { return NULL; } ERR_clear_error(); if (!(bn = BN_mpi2bn((unsigned char *)vbuf.buf, vbuf.len, NULL))) { unsigned long err_code = ERR_get_error(); m2_PyErr_SetString_from_openssl_error(_py_exc, err_code); m2_PyBuffer_Release(value, &vbuf); return NULL; } m2_PyBuffer_Release(value, &vbuf); return bn; } 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; out = PyObject_GetAttrString(pyfile, "name"); 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*) __func__) 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; size_t len; /* Get the first error with detailed line/data info */ 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); /* Now, drain any remaining errors from the stack */ while ((err_code = ERR_get_error()) != 0) { len = strlen(err_msg); if (len < sizeof(err_msg) - 2) { // Ensure space for separator and new error snprintf(err_msg + len, sizeof(err_msg) - len, "; %s", ERR_reason_error_string(err_code)); } } 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_parameters, 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) { Py_buffer vbuf; BIGNUM *ret; if (m2_PyObject_GetBufferInt(value, &vbuf, PyBUF_SIMPLE) == -1) return NULL; ret = BN_mpi2bn(vbuf.buf, vbuf.len, NULL); m2_PyBuffer_Release(value, &vbuf); return ret; } 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) { Py_buffer vbuf; BIGNUM *ret; if (m2_PyObject_GetBufferInt(value, &vbuf, PyBUF_SIMPLE) == -1) return NULL; ret = BN_bin2bn(vbuf.buf, vbuf.len, NULL); m2_PyBuffer_Release(value, &vbuf); return ret; } 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) { Py_buffer vbuf; BIGNUM *bn; if (m2_PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) == -1) return NULL; if ((bn=BN_new())==NULL) { PyErr_SetString(PyExc_MemoryError, "hex_to_bn"); m2_PyBuffer_Release(value, &vbuf); return NULL; } /* BN_hex2bn expects a null-terminated string/buffer */ /* We pass vbuf.buf assuming input is correctly formatted (e.g. bytes from hex string) */ if (BN_hex2bn(&bn, (const char *)vbuf.buf) <= 0) { m2_PyErr_Msg(PyExc_RuntimeError); BN_free(bn); m2_PyBuffer_Release(value, &vbuf); return NULL; } m2_PyBuffer_Release(value, &vbuf); return bn; } BIGNUM *dec_to_bn(PyObject *value) { Py_buffer vbuf; BIGNUM *bn; if (m2_PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) == -1) return NULL; if ((bn=BN_new())==NULL) { PyErr_SetString(PyExc_MemoryError, "dec_to_bn"); m2_PyBuffer_Release(value, &vbuf); return NULL; } /* BN_dec2bn expects a null-terminated string/buffer */ if ((BN_dec2bn(&bn, (const char *)vbuf.buf) <= 0)) { m2_PyErr_Msg(PyExc_RuntimeError); BN_free(bn); m2_PyBuffer_Release(value, &vbuf); return NULL; } m2_PyBuffer_Release(value, &vbuf); return bn; } %} /* Various useful typemaps. */ %typemap(in) PyObject *pyfunc { if (!PyCallable_Check($input)) { PyErr_SetString(PyExc_TypeError, "expected PyCallable"); 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. */ /* 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.46.2/src/SWIG/_lib11_compat.i000066400000000000000000000230321506746742300175240ustar00rootroot00000000000000/* * 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 # 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.46.2/src/SWIG/_m2crypto.def000066400000000000000000000000271506746742300173350ustar00rootroot00000000000000EXPORTS init_m2crypto m2crypto-0.46.2/src/SWIG/_m2crypto.i000066400000000000000000000050651506746742300170360ustar00rootroot00000000000000/* -*- 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. * */ %pythoncode %{ # mypy: disable-error-code="import-not-found" %} %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 #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 _objects.i #ifdef SWIG_VERSION %constant int encrypt = 1; %constant int decrypt = 0; #endif m2crypto-0.46.2/src/SWIG/_objects.i000066400000000000000000000054331506746742300167070ustar00rootroot00000000000000/* * -*- 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.46.2/src/SWIG/_pkcs7.i000066400000000000000000000162651506746742300163120ustar00rootroot00000000000000/* 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.46.2/src/SWIG/_py3k_compat.i000066400000000000000000000022611506746742300175030ustar00rootroot00000000000000%{ #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.46.2/src/SWIG/_python_logging.i000066400000000000000000000040321506746742300202770ustar00rootroot00000000000000%{ /***********************************************************/ /* define logging function and logtypes for python.logging */ /* by H.Dickten 2014 */ /* https://gist.github.com/hensing/0db3f8e3a99590006368 */ /***********************************************************/ #include // Include for va_list // Buffer size for formatted log message #define LOG_MSG_MAX_SIZE 512 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" static void log_msg(int type, const char *format, ...) { static PyObject *logging = NULL; char buffer[LOG_MSG_MAX_SIZE]; va_list args; PyObject *string = NULL; // Format the message va_start(args, format); vsnprintf(buffer, LOG_MSG_MAX_SIZE, format, args); va_end(args); // import logging module on demand if (logging == NULL){ // Using "logging" module name directly, no need to check NoBlock logging = PyImport_ImportModule("logging"); if (logging == NULL) { // Error importing module is handled by PyErr_Occurred() later return; } } // build msg-string from the formatted buffer string = Py_BuildValue("s", buffer); if (string == NULL) { // Handle error building string return; } // call function depending on loglevel switch (type) { case info: PyObject_CallMethod(logging, "info", "O", string); break; case warning: PyObject_CallMethod(logging, "warn", "O", string); break; case error: PyObject_CallMethod(logging, "error", "O", string); break; case debug: PyObject_CallMethod(logging, "debug", "O", string); break; } Py_DECREF(string); // Clear any temporary Python error set by PyObject_CallMethod if logging failed // (A failed log call should not propagate to the C caller) if (PyErr_Occurred()) { PyErr_Clear(); } } #pragma GCC diagnostic pop %} m2crypto-0.46.2/src/SWIG/_rand.i000066400000000000000000000075001506746742300161770ustar00rootroot00000000000000/* -*- 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 $ */ %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) { Py_buffer buf; if (m2_PyObject_GetBufferInt(seed, &buf, PyBUF_SIMPLE) == -1) return NULL; RAND_seed(buf.buf, buf.len); m2_PyBuffer_Release(seed, &buf); Py_RETURN_NONE; } PyObject *rand_add(PyObject *blob, double entropy) { Py_buffer buf; if (m2_PyObject_GetBufferInt(blob, &buf, PyBUF_SIMPLE) == -1) return NULL; RAND_add(buf.buf, buf.len, entropy); m2_PyBuffer_Release(blob, &buf); 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.46.2/src/SWIG/_rc4.i000066400000000000000000000027261506746742300157500ustar00rootroot00000000000000/* -*- 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) { Py_buffer vbuf; if (m2_PyObject_GetBufferInt(value, &vbuf, PyBUF_SIMPLE) == -1) return NULL; RC4_set_key(key, vbuf.len, vbuf.buf); m2_PyBuffer_Release(value, &vbuf); Py_RETURN_NONE; } PyObject *rc4_update(RC4_KEY *key, PyObject *in) { PyObject *ret; void *out; Py_buffer buf; if (m2_PyObject_GetBuffer(in, &buf, PyBUF_SIMPLE) == -1) return NULL; if (!(out = PyMem_Malloc(buf.len))) { PyErr_SetString(PyExc_MemoryError, "expected a string object"); m2_PyBuffer_Release(in, &buf); return NULL; } RC4(key, buf.len, buf.buf, out); ret = PyBytes_FromStringAndSize((char*)out, buf.len); PyMem_Free(out); m2_PyBuffer_Release(in, &buf); return ret; } int rc4_type_check(RC4_KEY *key) { return 1; } %} #endif m2crypto-0.46.2/src/SWIG/_rsa.i000066400000000000000000000340501506746742300160400ustar00rootroot00000000000000/* 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 = NULL; Py_buffer vbuf; if (m2_PyObject_GetBufferInt(value, &vbuf, PyBUF_SIMPLE) == -1) { return NULL; } if (!(bn = BN_bin2bn((const unsigned char *)vbuf.buf, vbuf.len, NULL))) { /* If conversion fails, set error and fall through to cleanup */ m2_PyErr_Msg(_rsa_err); } m2_PyBuffer_Release(value, &vbuf); 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) { void *tbuf; PyObject *ret; int tlen; Py_buffer pybuf; if (m2_PyObject_GetBufferInt(from, &pybuf, PyBUF_SIMPLE) == -1) return NULL; if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) { PyErr_SetString(PyExc_MemoryError, "rsa_private_encrypt"); m2_PyBuffer_Release(from, &pybuf); return NULL; } tlen = RSA_private_encrypt(pybuf.len, (unsigned char *)pybuf.buf, (unsigned char *)tbuf, rsa, padding); if (tlen == -1) { m2_PyErr_Msg(_rsa_err); PyMem_Free(tbuf); m2_PyBuffer_Release(from, &pybuf); return NULL; } ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); PyMem_Free(tbuf); m2_PyBuffer_Release(from, &pybuf); return ret; } PyObject *rsa_public_decrypt(RSA *rsa, PyObject *from, int padding) { void *tbuf; int tlen = 0; PyObject *ret; Py_buffer pybuf; if (m2_PyObject_GetBufferInt(from, &pybuf, PyBUF_SIMPLE) == -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"); m2_PyBuffer_Release(from, &pybuf); return NULL; } tlen = RSA_public_decrypt(pybuf.len, (unsigned char *)pybuf.buf, (unsigned char *)tbuf, rsa, padding); if (tlen == -1) { ERR_clear_error(); PyErr_Clear(); PyMem_Free(tbuf); m2_PyBuffer_Release(from, &pybuf); Py_RETURN_NONE; } ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); PyMem_Free(tbuf); m2_PyBuffer_Release(from, &pybuf); return ret; } PyObject *rsa_public_encrypt(RSA *rsa, PyObject *from, int padding) { void *tbuf; int tlen; PyObject *ret; Py_buffer pybuf; if (m2_PyObject_GetBufferInt(from, &pybuf, PyBUF_SIMPLE) == -1) return NULL; if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) { PyErr_SetString(PyExc_MemoryError, "rsa_public_encrypt"); m2_PyBuffer_Release(from, &pybuf); return NULL; } tlen = RSA_public_encrypt(pybuf.len, (unsigned char *)pybuf.buf, (unsigned char *)tbuf, rsa, padding); if (tlen == -1) { m2_PyErr_Msg(_rsa_err); PyMem_Free(tbuf); m2_PyBuffer_Release(from, &pybuf); return NULL; } ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); PyMem_Free(tbuf); m2_PyBuffer_Release(from, &pybuf); return ret; } PyObject *rsa_private_decrypt(RSA *rsa, PyObject *from, int padding) { void *tbuf; int tlen; PyObject *ret; Py_buffer pybuf; if (m2_PyObject_GetBufferInt(from, &pybuf, PyBUF_SIMPLE) == -1) return NULL; if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) { PyErr_SetString(PyExc_MemoryError, "rsa_private_decrypt"); m2_PyBuffer_Release(from, &pybuf); return NULL; } tlen = RSA_private_decrypt(pybuf.len, (unsigned char *)pybuf.buf, (unsigned char *)tbuf, rsa, padding); if (tlen == -1) { ERR_clear_error(); PyErr_Clear(); PyMem_Free(tbuf); m2_PyBuffer_Release(from, &pybuf); Py_RETURN_NONE; } ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); PyMem_Free(tbuf); m2_PyBuffer_Release(from, &pybuf); return ret; } #if OPENSSL_VERSION_NUMBER >= 0x0090708fL PyObject *rsa_padding_add_pkcs1_pss(RSA *rsa, PyObject *digest, EVP_MD *hash, int salt_length) { unsigned char *tbuf; int result, tlen; PyObject *ret; Py_buffer dbuf; if (m2_PyObject_GetBufferInt(digest, &dbuf, PyBUF_SIMPLE) == -1) return NULL; tlen = RSA_size(rsa); if (!(tbuf = OPENSSL_malloc(tlen))) { PyErr_SetString(PyExc_MemoryError, "rsa_padding_add_pkcs1_pss"); m2_PyBuffer_Release(digest, &dbuf); return NULL; } result = RSA_padding_add_PKCS1_PSS( rsa, tbuf, (unsigned char *)dbuf.buf, hash, salt_length); if (result == -1) { m2_PyErr_Msg(_rsa_err); OPENSSL_cleanse(tbuf, tlen); OPENSSL_free(tbuf); m2_PyBuffer_Release(digest, &dbuf); return NULL; } ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen); OPENSSL_cleanse(tbuf, tlen); OPENSSL_free(tbuf); m2_PyBuffer_Release(digest, &dbuf); return ret; } int rsa_verify_pkcs1_pss(RSA *rsa, PyObject *digest, PyObject *signature, EVP_MD *hash, int salt_length) { int ret; Py_buffer dbuf, sbuf; if (m2_PyObject_GetBufferInt(digest, &dbuf, PyBUF_SIMPLE) == -1) { return 0; } if (m2_PyObject_GetBufferInt(signature, &sbuf, PyBUF_SIMPLE) == -1) { m2_PyBuffer_Release(digest, &dbuf); return 0; } ret = RSA_verify_PKCS1_PSS( rsa, (unsigned char *)dbuf.buf, hash, (unsigned char *)sbuf.buf, salt_length); m2_PyBuffer_Release(digest, &dbuf); m2_PyBuffer_Release(signature, &sbuf); 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; } int rsa_set_ex_data(RSA *rsa, int index, long data) { long *data_buf; data_buf = PyMem_Malloc(sizeof(long)); *data_buf = data; return RSA_set_ex_data(rsa, index, data_buf); } PyObject *rsa_get_ex_data(RSA *rsa, int index) { long *data; data = RSA_get_ex_data(rsa, index); if (data == 0) { PyErr_SetString(_rsa_err, ERR_reason_error_string(ERR_get_error())); return NULL; } return PyInt_FromLong(*data); } %} %threadallow rsa_write_key_der; %inline %{ int rsa_write_key_der(RSA *rsa, BIO *bio) { return i2d_RSAPrivateKey_bio(bio, rsa); } %} m2crypto-0.46.2/src/SWIG/_ssl.i000066400000000000000000001111501506746742300160510ustar00rootroot00000000000000/* -*- 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 #include #include #ifdef _WIN32 #include #include #include #pragma comment(lib, "Ws2_32") typedef unsigned __int64 uint64_t; #define EINTR WSAEINTR // Map EINTR for Windows Sockets if needed elsewhere #else #include #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); } void x509_store_ctx_set_error(X509_STORE_CTX *ctx, int err) { X509_STORE_CTX_set_error(ctx, err); } int ssl_ctx_set_session_id_context(SSL_CTX *ctx, PyObject *sid_ctx) { Py_buffer buf; int ret; if (m2_PyObject_GetBufferInt(sid_ctx, &buf, PyBUF_SIMPLE) == -1) return -1; ret = SSL_CTX_set_session_id_context(ctx, buf.buf, buf.len); m2_PyBuffer_Release(sid_ctx, &buf); return ret; } 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) { Py_buffer buf; int ret; if (m2_PyObject_GetBufferInt(sid_ctx, &buf, PyBUF_SIMPLE) == -1) return -1; ret = SSL_set_session_id_context(ssl, buf.buf, buf.len); m2_PyBuffer_Release(sid_ctx, &buf); return ret; } 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) { unsigned long err; switch (ssl_err) { case SSL_ERROR_SSL: m2_PyErr_SetString_from_openssl_error(_ssl_err, ERR_get_error()); break; case SSL_ERROR_SYSCALL: err = ERR_get_error(); if (err) m2_PyErr_SetString_from_openssl_error(_ssl_err, 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 // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) // until 00:00:00 January 1, 1970 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 now, deadline, remaining; int ms, tmp; long remaining_ms; // Use long for intermediate calculation assert(timeout > 0); // Calculate the absolute deadline time deadline = *start; deadline.tv_sec += (time_t)timeout; // Add whole seconds // Add fractional seconds as microseconds deadline.tv_usec += (long)((timeout - (time_t)timeout) * 1000000.0); // Normalize microseconds (handle carry-over) deadline.tv_sec += deadline.tv_usec / 1000000; deadline.tv_usec %= 1000000; again: if (gettimeofday(&now, NULL) != 0) { // Should not happen, but handle defensively PyErr_SetString(PyExc_OSError, "gettimeofday failed"); return -1; } // Check if deadline has already passed if (deadline.tv_sec < now.tv_sec || (deadline.tv_sec == now.tv_sec && deadline.tv_usec <= now.tv_usec)) { goto timeout_error; } // Calculate remaining time: remaining = deadline - now remaining.tv_sec = deadline.tv_sec - now.tv_sec; remaining.tv_usec = deadline.tv_usec - now.tv_usec; if (remaining.tv_usec < 0) { remaining.tv_sec--; remaining.tv_usec += 1000000; } // Convert remaining time to milliseconds for poll/WSAPoll, capping at INT_MAX if (remaining.tv_sec >= (INT_MAX / 1000)) { ms = INT_MAX; } else { remaining_ms = remaining.tv_sec * 1000 + (remaining.tv_usec + 999) / 1000; // Round up usec if (remaining_ms > INT_MAX) { ms = INT_MAX; } else { ms = (int)remaining_ms; } } // Ensure ms is positive (should be, as we checked deadline earlier, but safety check) if (ms <= 0) { goto timeout_error; } 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: // Cannot handle this by waiting on FD. Signal error. PyErr_SetString(_ssl_err, "SSL operation waiting for X509 lookup callback"); return -1; // Indicate error default: // Should not happen if called correctly from ssl_accept/etc. PyErr_SetString(_ssl_err, "Internal error: Unexpected SSL error code in watcher"); assert(0); // Assert in debug builds return -1; // Indicate error } if (fd.fd < 0) { PyErr_SetString(_ssl_err, "Cannot wait for readiness: SSL object not associated with a file descriptor"); return -1; } // Clear revents field before polling fd.revents = 0; 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_error; case -1: #ifdef _WIN32 if (WSAGetLastError() == EINTR) #else if (errno == EINTR) #endif goto again; PyErr_SetFromErrno(_ssl_err); return -1; } // This point should be unreachable due to switch handling all cases assert(0); return -1; timeout_error: PyErr_SetString(_ssl_timeout_err, "The operation timed out"); return -1; } PyObject *ssl_accept(SSL *ssl, double timeout) { PyObject *obj = NULL; int r = 0, ssl_err = 0; struct timeval tv_start; int sleep_result; int has_timeout = (timeout > 0); // Get start time only if a timeout is specified if (has_timeout) { if (gettimeofday(&tv_start, NULL) != 0) { PyErr_SetString(PyExc_OSError, "gettimeofday failed"); return NULL; } } while (1) { ERR_clear_error(); 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: // Handshake successful obj = PyLong_FromLong(1L); goto done; case SSL_ERROR_ZERO_RETURN: // Handshake terminated cleanly by peer during the process // Return 0 to indicate connection is not ready/closed. obj = PyLong_FromLong(0L); goto done; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: // Handshake needs more I/O if (!has_timeout) { // Non-blocking mode (timeout <= 0) // Return 0 to indicate "try again later" obj = PyLong_FromLong(0L); goto done; } else { // Blocking mode with timeout sleep_result = ssl_sleep_with_timeout(ssl, &tv_start, timeout, ssl_err); if (sleep_result == 0) { // Socket is ready, retry SSL_accept continue; } else { // Timeout occurred or error in ssl_sleep_with_timeout (-1) // Exception should have been set by ssl_sleep_with_timeout obj = NULL; goto done; } } break; // Not reachable due to continue/goto case SSL_ERROR_SSL: // SSL library error case SSL_ERROR_SYSCALL: // System call error (I/O, EOF) ssl_handle_error(ssl_err, r); // Sets the Python exception obj = NULL; goto done; default: // Unexpected error code from SSL_get_error PyErr_Format(_ssl_err, "Internal error: Unexpected SSL error code %d from SSL_get_error", ssl_err); obj = NULL; goto done; } break; // This break is technically unreachable due to gotos/continue in switch cases } // end while(1) done: 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); } /* Translation of the underlying function SSL_read(3) * * Important thing is that contrary to the original function it does NOT * return int with number of read bytes, but it returns whole buffer * with read data (of the correct length, of course, and as Python bytes * object). */ 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; } while (1) { Py_BEGIN_ALLOW_THREADS r = SSL_read(ssl, buf, num); Py_END_ALLOW_THREADS if (r >= 0) { // Success or EOF (r=0) break; // Exit the loop } else { // Error case (r < 0) int ssl_err = SSL_get_error(ssl, r); switch (ssl_err) { /* This should never happen here: documentation for * SSL_get_error(3) claims that "This result code is * returned if and only if ret > 0." */ case SSL_ERROR_NONE: PyErr_SetString(PyExc_IOError, "Got SSL_ERROR_NONE while in the error handler."); obj = NULL; break; /* The operation did not complete and can be retried later. */ 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; goto cleanup; } // NOTE: ssl_sleep_with_timeout must now check and enforce the timeout // This function should return 0 on success/retry, and -1 on timeout or error if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0) { obj = NULL; goto cleanup; } // If it returns 0 (success/retry), loop continues. break; /* Some non-recoverable, fatal I/O error occurred. If this * error occurs then no further I/O operations should be * performed on the connection and SSL_shutdown() must not * be called. */ case SSL_ERROR_SSL: case SSL_ERROR_SYSCALL: ssl_handle_error(ssl_err, r); obj = NULL; goto cleanup; default: // Handle other unexpected errors PyErr_Format(PyExc_IOError, "Unexpected SSL error: %d", ssl_err); obj = NULL; goto cleanup; } } } // Post-loop processing (r >= 0) if (r > 0) { obj = PyBytes_FromStringAndSize(buf, r); } else { // r == 0, end of file Py_INCREF(Py_None); obj = Py_None; } cleanup: // Unified cleanup label PyMem_Free(buf); return obj; } PyObject *ssl_read_nbio(SSL *ssl, int num) { PyObject *obj = NULL; void *buf = NULL; // Initialize to NULL int r = 0; int ssl_err = 0; unsigned long err_code = 0; // For SYSCALL OpenSSL error code // Ensure num is non-negative; handle potentially large num if necessary if (num < 0) { PyErr_SetString(PyExc_ValueError, "read count must be non-negative"); return NULL; } if (num == 0) { // Read 0 bytes: return empty bytes object immediately return PyBytes_FromStringAndSize(NULL, 0); } // Allocate buffer using Python's memory manager if (!(buf = PyMem_Malloc(num))) { PyErr_SetString(PyExc_MemoryError, "Failed to allocate buffer for ssl_read"); return NULL; } ERR_clear_error(); // Clear OpenSSL error queue before the call Py_BEGIN_ALLOW_THREADS r = SSL_read(ssl, buf, num); ssl_err = SSL_get_error(ssl, r); Py_END_ALLOW_THREADS switch (ssl_err) { case SSL_ERROR_NONE: // Success: r contains bytes read (0 < r <= num) // Create bytes object by *copying* r bytes from buf obj = PyBytes_FromStringAndSize(buf, r); // Note: obj will be NULL if PyBytes creation fails (MemoryError) break; case SSL_ERROR_ZERO_RETURN: // Clean EOF: r == 0 // Return an empty bytes object obj = PyBytes_FromStringAndSize(NULL, 0); break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: // Operation would block or needs other action (e.g., callback) // Return None to signal "try again" or "needs other action" Py_INCREF(Py_None); obj = Py_None; break; case SSL_ERROR_SSL: // SSL library internal error m2_PyErr_SetString_from_openssl_error(_ssl_err, ERR_get_error()); obj = NULL; break; case SSL_ERROR_SYSCALL: // System call error (I/O, EOF) err_code = ERR_get_error(); // Check OpenSSL queue first if (err_code != 0) { m2_PyErr_SetString_from_openssl_error(_ssl_err, err_code); } else if (r == 0) { // Unexpected EOF reported as SYSCALL PyErr_SetString(_ssl_err, "Unexpected EOF received in violation of protocol"); } else if (r == -1) { // Underlying system call error, use errno PyErr_SetFromErrno(_ssl_err); } else { // Should not happen for SYSCALL with err_code 0 PyErr_Format(_ssl_err, "Internal error: Unexpected SSL_ERROR_SYSCALL state (r=%d)", r); assert(0); // Assert in debug builds } obj = NULL; break; default: PyErr_Format(_ssl_err, "Internal error: Unexpected SSL error code %d from SSL_get_error", ssl_err); obj = NULL; break; } if (buf) { PyMem_Free(buf); } return obj; } int ssl_write(SSL *ssl, PyObject *blob, double timeout) { int r, ssl_err, ret; Py_buffer buf; 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 = 0; int ssl_err = 0; int ret = -1; // Default to error return, change on success unsigned long err_code = 0; // For SYSCALL OpenSSL error code // Get a read-only C-contiguous buffer view of the input object // Assuming m2_PyObject_GetBufferInt sets exception on failure if (m2_PyObject_GetBufferInt(blob, &buf, PyBUF_CONTIG_RO) == -1) { return -1; // Exception already set by helper } // Check for zero-length write if (buf.len == 0) { PyBuffer_Release(&buf); return 0; // Successfully wrote 0 bytes } ERR_clear_error(); 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: // Success: r contains bytes written (0 < r <= buf.len) assert(r > 0); ret = r; break; case SSL_ERROR_ZERO_RETURN: // This indicates connection closed cleanly during/before write. // Treat as an error similar to BrokenPipeError. // SSL_write doesn't usually return this; suspect underlying closure. PyErr_SetString(PyExc_BrokenPipeError, "SSL/TLS connection closed cleanly by peer during write"); ret = -1; break; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: // Operation would block or needs other action (e.g., callback/renegotiation) // Return -1 without setting an exception to signal non-blocking status. ret = -1; break; case SSL_ERROR_SSL: // SSL library internal error m2_PyErr_SetString_from_openssl_error(_ssl_err, ERR_get_error()); ret = -1; break; case SSL_ERROR_SYSCALL: // System call error (I/O, EOF) err_code = ERR_get_error(); if (err_code != 0) { m2_PyErr_SetString_from_openssl_error(_ssl_err, err_code); } else if (r == 0) { // Write returned 0, reported as SYSCALL - unexpected EOF/closure? PyErr_SetString(PyExc_BrokenPipeError, "Unexpected EOF/Connection closed during write"); } else if (r == -1) { // Underlying system call error, use errno PyErr_SetFromErrno(_ssl_err); } else { // Should not happen for SYSCALL with err_code 0 PyErr_Format(_ssl_err, "Internal error: Unexpected SSL_ERROR_SYSCALL state (r=%d)", r); assert(0); } ret = -1; break; default: PyErr_Format(_ssl_err, "Internal error: Unexpected SSL error code %d from SSL_get_error", ssl_err); ret = -1; break; } m2_PyBuffer_Release(blob, &buf); return ret; // Return bytes written (r) or -1 (error / would block) } 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.46.2/src/SWIG/_threads.i000066400000000000000000000034231506746742300167050ustar00rootroot00000000000000/* 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; char *ret; Py_buffer buf; if (m2_PyObject_GetBuffer(blob, &buf, PyBUF_SIMPLE) == -1) return NULL; ret = (char *)hex_to_string((unsigned char *)buf.buf, buf.len); if (!ret) { m2_PyErr_Msg(_util_err); m2_PyBuffer_Release(blob, &buf); return NULL; } obj = PyBytes_FromString(ret); OPENSSL_free(ret); m2_PyBuffer_Release(blob, &buf); return obj; } PyObject *util_string_to_hex(PyObject *blob) { PyObject *obj; unsigned char *ret; long len; Py_buffer buf; if (m2_PyObject_GetBuffer(blob, &buf, PyBUF_SIMPLE) == -1) return NULL; len = buf.len; ret = string_to_hex((char *)buf.buf, &len); if (ret == NULL) { m2_PyErr_Msg(_util_err); m2_PyBuffer_Release(blob, &buf); return NULL; } obj = PyBytes_FromStringAndSize((char*)ret, len); OPENSSL_free(ret); m2_PyBuffer_Release(blob, &buf); return obj; } %} m2crypto-0.46.2/src/SWIG/_x509.i000066400000000000000000000663471506746742300157760ustar00rootroot00000000000000/* -*- 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) %} %include "x509_v_flag.h" %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; } void x509v3_ctx_free(X509V3_CTX *ctx) { PyMem_Free(ctx); } %} %typemap(out) X509_EXTENSION * ; %typemap(in) X509_STORE_CTX * { $1 = ($1_type)SWIG_Python_MustGetPtr($input, SWIG_TypeQuery("$1_basetype *"), 1, 0); } %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); } SSL *x509_store_ctx_get_ex_data(X509_STORE_CTX *ctx, int idx) { return (SSL *)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.46.2/src/SWIG/libcrypto-compat.h000066400000000000000000000052471506746742300204110ustar00rootroot00000000000000#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.46.2/src/SWIG/py3k_compat.h000066400000000000000000000020721506746742300173430ustar00rootroot00000000000000#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.46.2/src/SWIG/python_logging.h000066400000000000000000000004171506746742300201420ustar00rootroot00000000000000#ifndef PYTHON_LOGGING_H #define PYTHON_LOGGING_H #include enum logtypes {info, warning, error, debug}; // Changed signature to support varargs (const char *format, ...) static void log_msg(int type, const char *format, ...); #endif /* PYTHON_LOGGING_H */ m2crypto-0.46.2/src/SWIG/x509_v_flag.h000066400000000000000000000021271506746742300171360ustar00rootroot00000000000000/* Errors in case a check in X509_V_FLAG_X509_STRICT mode fails */ #define X509_V_FLAG_CB_ISSUER_CHECK 0x0 #define X509_V_FLAG_USE_CHECK_TIME 0x2 #define X509_V_FLAG_CRL_CHECK 0x4 #define X509_V_FLAG_CRL_CHECK_ALL 0x8 #define X509_V_FLAG_IGNORE_CRITICAL 0x10 #define X509_V_FLAG_X509_STRICT 0x20 #define X509_V_FLAG_ALLOW_PROXY_CERTS 0x40 #define X509_V_FLAG_POLICY_CHECK 0x80 #define X509_V_FLAG_EXPLICIT_POLICY 0x100 #define X509_V_FLAG_INHIBIT_ANY 0x200 #define X509_V_FLAG_INHIBIT_MAP 0x400 #define X509_V_FLAG_NOTIFY_POLICY 0x800 #define X509_V_FLAG_EXTENDED_CRL_SUPPORT 0x1000 #define X509_V_FLAG_USE_DELTAS 0x2000 #define X509_V_FLAG_CHECK_SS_SIGNATURE 0x4000 #define X509_V_FLAG_TRUSTED_FIRST 0x8000 #define X509_V_FLAG_SUITEB_128_LOS_ONLY 0x10000 #define X509_V_FLAG_SUITEB_192_LOS 0x20000 #define X509_V_FLAG_SUITEB_128_LOS 0x30000 #define X509_V_FLAG_PARTIAL_CHAIN 0x80000 #define X509_V_FLAG_NO_ALT_CHAINS 0x100000 #define X509_V_FLAG_NO_CHECK_TIME 0x200000 #define X509_V_FLAG_POLICY_MASK (X509_V_FLAG_POLICY_CHECK | X509_V_FLAG_EXPLICIT_POLICY | X509_V_FLAG_INHIBIT_ANY | X509_V_FLAG_INHIBIT_MAP) m2crypto-0.46.2/system_shadowing/000077500000000000000000000000001506746742300167675ustar00rootroot00000000000000m2crypto-0.46.2/system_shadowing/sys/000077500000000000000000000000001506746742300176055ustar00rootroot00000000000000m2crypto-0.46.2/system_shadowing/sys/types.h000066400000000000000000000000141506746742300211150ustar00rootroot00000000000000/* empty */ m2crypto-0.46.2/tests/000077500000000000000000000000001506746742300145425ustar00rootroot00000000000000m2crypto-0.46.2/tests/README000066400000000000000000000027671506746742300154360ustar00rootroot00000000000000This 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.46.2/tests/__init__.py000066400000000000000000000003371506746742300166560ustar00rootroot00000000000000import 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.46.2/tests/alltests.py000066400000000000000000000063111506746742300167500ustar00rootroot00000000000000import 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_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_util", "tests.test_timeout", "tests.test_xmlrpc", ] 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.46.2/tests/bad_date_cert.crt000066400000000000000000000021131506746742300200110ustar00rootroot00000000000000-----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.46.2/tests/ca.pem000066400000000000000000000132241506746742300156320ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 0 (0x0) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=California, O=M2Crypto, CN=Heikki Toivonen Validity Not Before: Apr 22 14:50:27 2025 GMT Not After : Apr 20 14:50:27 2035 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:aa:7b:06:6b:1d:10:4c:81:3d:68:32:64:96:70: f1:07:66:b3:b6:b3:1c:79:60:9c:7c:f3:3f:90:db: 6b:b0:35:24:17:7c:cd:02:e2:20:06:1f:5d:c7:47: a6:ef:47:50:82:f7:cc:2c:4f:bc:95:a8:2f:47:5c: a9:bf:72:3b:93:48:75:4a:fc:27:ed:10:af:3c:5a: 96:95:15:52:03:82:b7:86:3d:c3:ca:ba:14:c4:d4: b2:67:f0:6d:cf:b3:49:88:a3:da:c9:b6:ec:01:c2: fd:93:91:1e:ce:b6:33:ab:26:8e:05:f4:6d:65:57: db:3a:16:9f:a4:68:2f:48:b1:92:e1:64:dd:cf:4f: 64:a2:af:ff:24:b1:8d:7e:bd:96:23:f3:11:b7:5b: ee:6c:01:f2:7b:f1:e6:51:ea:c2:3f:2e:d1:57:22: d1:10:0f:a9:6a:37:d4:d5:ef:7a:e8:d6:a2:b3:1d: 3f:22:65:40:49:d5:93:92:7c:a7:05:ea:c2:5f:85: c8:5f:c6:2c:54:a0:27:6c:46:0a:05:7c:74:a3:e2: 7a:4f:86:97:c4:45:f9:65:41:b5:c9:fd:d9:bb:40: 0b:83:05:34:e8:28:88:bf:c4:4f:8f:cb:79:1f:60: c0:a3:ae:53:25:5d:c2:46:aa:49:f8:fc:3a:b1:d8: c1:fd Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:TRUE X509v3 Subject Key Identifier: 15:57:F1:3C:CE:3C:71:9A:1F:D4:FE:DB:CF:DD:79:26:06:15:32:06 Signature Algorithm: sha256WithRSAEncryption Signature Value: 48:18:54:62:d2:1a:6d:81:31:10:56:1a:1c:c7:eb:28:bf:f9: c4:99:4a:c4:d3:9c:a3:77:22:cf:c3:31:8f:75:e9:b3:a0:62: 8c:6c:41:5f:6e:1c:7c:eb:88:e0:d7:8b:36:67:2e:e0:8e:06: 74:43:e0:c6:ba:a7:79:2c:e0:52:ca:6a:e4:26:7e:64:3e:d5: d0:32:ef:d6:e3:e2:4b:d5:d2:02:c5:63:96:b9:6d:d5:60:dc: 34:32:6a:e6:e0:7c:eb:a1:8f:1e:a8:8e:ad:f1:77:bb:65:3f: 80:f2:8c:30:29:2c:7b:1f:2c:ff:44:16:58:0d:59:7a:52:1c: a6:2d:4e:9b:c8:8c:c3:ef:07:53:77:de:3f:e0:6b:94:dd:4f: 19:e3:64:ce:e1:b2:29:99:a3:4d:55:39:d6:f1:93:47:6f:43: 7a:0f:31:73:93:8c:57:52:d9:a1:fb:61:76:cb:56:7e:10:11: 17:16:b1:2c:87:4e:a2:d1:94:aa:90:af:f4:0d:8b:92:a5:a7: a2:2b:fe:ab:36:66:4b:c8:38:d5:04:e4:d5:1f:81:ad:93:49: f5:1c:0d:7a:fb:b8:2d:ac:b8:b2:0f:28:76:13:4d:ae:ad:fe: 3d:3b:14:af:90:92:8e:85:df:39:78:a4:fa:0e:9a:ef:a6:e2: bc:c3:0d:c4 -----BEGIN CERTIFICATE----- MIIDSDCCAjCgAwIBAgIBADANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzET MBEGA1UECAwKQ2FsaWZvcm5pYTERMA8GA1UECgwITTJDcnlwdG8xGDAWBgNVBAMM D0hlaWtraSBUb2l2b25lbjAeFw0yNTA0MjIxNDUwMjdaFw0zNTA0MjAxNDUwMjda ME8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMREwDwYDVQQKDAhN MkNyeXB0bzEYMBYGA1UEAwwPSGVpa2tpIFRvaXZvbmVuMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAqnsGax0QTIE9aDJklnDxB2aztrMceWCcfPM/kNtr sDUkF3zNAuIgBh9dx0em70dQgvfMLE+8lagvR1ypv3I7k0h1Svwn7RCvPFqWlRVS A4K3hj3DyroUxNSyZ/Btz7NJiKPaybbsAcL9k5EezrYzqyaOBfRtZVfbOhafpGgv SLGS4WTdz09koq//JLGNfr2WI/MRt1vubAHye/HmUerCPy7RVyLREA+pajfU1e96 6Naisx0/ImVASdWTknynBerCX4XIX8YsVKAnbEYKBXx0o+J6T4aXxEX5ZUG1yf3Z u0ALgwU06CiIv8RPj8t5H2DAo65TJV3CRqpJ+Pw6sdjB/QIDAQABoy8wLTAMBgNV HRMEBTADAQH/MB0GA1UdDgQWBBQVV/E8zjxxmh/U/tvP3XkmBhUyBjANBgkqhkiG 9w0BAQsFAAOCAQEASBhUYtIabYExEFYaHMfrKL/5xJlKxNOco3ciz8Mxj3Xps6Bi jGxBX24cfOuI4NeLNmcu4I4GdEPgxrqneSzgUspq5CZ+ZD7V0DLv1uPiS9XSAsVj lrlt1WDcNDJq5uB866GPHqiOrfF3u2U/gPKMMCksex8s/0QWWA1ZelIcpi1Om8iM w+8HU3feP+BrlN1PGeNkzuGyKZmjTVU51vGTR29Deg8xc5OMV1LZofthdstWfhAR FxaxLIdOotGUqpCv9A2LkqWnoiv+qzZmS8g41QTk1R+BrZNJ9RwNevu4Lay4sg8o dhNNrq3+PTsUr5CSjoXfOXik+g6a76bivMMNxA== -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAqnsGax0QTIE9aDJklnDxB2aztrMceWCcfPM/kNtrsDUkF3zN AuIgBh9dx0em70dQgvfMLE+8lagvR1ypv3I7k0h1Svwn7RCvPFqWlRVSA4K3hj3D yroUxNSyZ/Btz7NJiKPaybbsAcL9k5EezrYzqyaOBfRtZVfbOhafpGgvSLGS4WTd z09koq//JLGNfr2WI/MRt1vubAHye/HmUerCPy7RVyLREA+pajfU1e966Naisx0/ ImVASdWTknynBerCX4XIX8YsVKAnbEYKBXx0o+J6T4aXxEX5ZUG1yf3Zu0ALgwU0 6CiIv8RPj8t5H2DAo65TJV3CRqpJ+Pw6sdjB/QIDAQABAoIBABUgrgj0TyLMGYoi RKkIUjayma8Yv3yjZoFtvAD90HjD/TcT9mxXDdT0ajDaRmv9EJNKlnkfYKXDdCiJ 6VealpuILVEfsusEWFNIfsT3IXTh7FCssuka6pwCKCINf+5vr7tJY0IAc3s8aSSy pXjEx958JrnCMxSOMNMgHqTHbKS7eOgnBjdYP9vxPhdoXz4DCFerAr/6p5qtMBa2 b3OlPxRzHtbO5gi2M+8MpZx3+XeLCCjCNRewcUKNpzNnvMUjyosqkqhK5i5P16U9 BQH58R6myx/iwjwPtU82qXT2kpjWrjQWzJLqp8GUaaq6BicMsz2nsZ1pfglEQp/A 2wqN7IECgYEA6/gFVFkBgrY13d995yDgRgKqgvg+vuNoLQloPP88HjZ/TBsPTAIT C2xw2LmbmDTqPzJr6Ir83KpGmFncgQXQICRPnygXApyjflDbPBaKC/X5RYmpfkL4 K1vKrfVNkCJMRsl3WvHjS5ZnPBXt6M5m68kblUgaErsk3vaP0/BK0fECgYEAuPPW +8141kFrIC2cVitco9LB9PbLwLuS8GE/phr/Po0foCeIrpwBY0NKZkuuyhHl99ba 4qqmMz3BvDZTnS3KFI2hhXqVDM8O8XEAs931pwGAwhWMV+M0a4qh0A2stUk7KI3G D53qIHi5U0xcfvJkGwEvux5pVlJF0MDhL9405M0CgYBgB7SriflqZ5rua5jCage7 ljQsTrjCWKu5wF1SjZC6vvT5VP3ZsfJsMLqQCKFAxTAbffqaTY3wg79tGwz42RPF MOHSZK9QmcyTiHZgMtAFZBoI6ag3wStcAeQu/WiOYtbl6/GN6mjVByWGN2p11yHd jR+Tlh8+RjkQIAmSd/ULEQKBgAmuCWRoXpioF9k5SeNgpZqVXz1Y5VUS/B/ElzY0 V4OIk00ohIjO9Wuii/RKpb1Bro2IGzCdydEIvGkDVuD1Eox81SVNQxvGgnu0dFr1 lPPGqlx+EDhRVd8DBHEFJjLewE/hC6qpkyVb7Ccl6fli6kZXi435i33PFIRWc/Kz aIVJAoGBAKj0qeQzuIQLOD//xyYdb8PgTLSC4lw3ol1Uj/QoUPILmfB4S+s1op3q E44hV8J+JpQi7fbq5Ffmem2lfHwHtjYjwnmwuPKiE1hSpWLaUIZjOhuqGd4TLr24 sh6NaEekgZEE8XJpFL/aFVqZr6HjF4+FW/fGKVKzjvzW93EsOhSf -----END RSA PRIVATE KEY----- m2crypto-0.46.2/tests/ca_key.pem000066400000000000000000000032131506746742300164770ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAqnsGax0QTIE9aDJklnDxB2aztrMceWCcfPM/kNtrsDUkF3zN AuIgBh9dx0em70dQgvfMLE+8lagvR1ypv3I7k0h1Svwn7RCvPFqWlRVSA4K3hj3D yroUxNSyZ/Btz7NJiKPaybbsAcL9k5EezrYzqyaOBfRtZVfbOhafpGgvSLGS4WTd z09koq//JLGNfr2WI/MRt1vubAHye/HmUerCPy7RVyLREA+pajfU1e966Naisx0/ ImVASdWTknynBerCX4XIX8YsVKAnbEYKBXx0o+J6T4aXxEX5ZUG1yf3Zu0ALgwU0 6CiIv8RPj8t5H2DAo65TJV3CRqpJ+Pw6sdjB/QIDAQABAoIBABUgrgj0TyLMGYoi RKkIUjayma8Yv3yjZoFtvAD90HjD/TcT9mxXDdT0ajDaRmv9EJNKlnkfYKXDdCiJ 6VealpuILVEfsusEWFNIfsT3IXTh7FCssuka6pwCKCINf+5vr7tJY0IAc3s8aSSy pXjEx958JrnCMxSOMNMgHqTHbKS7eOgnBjdYP9vxPhdoXz4DCFerAr/6p5qtMBa2 b3OlPxRzHtbO5gi2M+8MpZx3+XeLCCjCNRewcUKNpzNnvMUjyosqkqhK5i5P16U9 BQH58R6myx/iwjwPtU82qXT2kpjWrjQWzJLqp8GUaaq6BicMsz2nsZ1pfglEQp/A 2wqN7IECgYEA6/gFVFkBgrY13d995yDgRgKqgvg+vuNoLQloPP88HjZ/TBsPTAIT C2xw2LmbmDTqPzJr6Ir83KpGmFncgQXQICRPnygXApyjflDbPBaKC/X5RYmpfkL4 K1vKrfVNkCJMRsl3WvHjS5ZnPBXt6M5m68kblUgaErsk3vaP0/BK0fECgYEAuPPW +8141kFrIC2cVitco9LB9PbLwLuS8GE/phr/Po0foCeIrpwBY0NKZkuuyhHl99ba 4qqmMz3BvDZTnS3KFI2hhXqVDM8O8XEAs931pwGAwhWMV+M0a4qh0A2stUk7KI3G D53qIHi5U0xcfvJkGwEvux5pVlJF0MDhL9405M0CgYBgB7SriflqZ5rua5jCage7 ljQsTrjCWKu5wF1SjZC6vvT5VP3ZsfJsMLqQCKFAxTAbffqaTY3wg79tGwz42RPF MOHSZK9QmcyTiHZgMtAFZBoI6ag3wStcAeQu/WiOYtbl6/GN6mjVByWGN2p11yHd jR+Tlh8+RjkQIAmSd/ULEQKBgAmuCWRoXpioF9k5SeNgpZqVXz1Y5VUS/B/ElzY0 V4OIk00ohIjO9Wuii/RKpb1Bro2IGzCdydEIvGkDVuD1Eox81SVNQxvGgnu0dFr1 lPPGqlx+EDhRVd8DBHEFJjLewE/hC6qpkyVb7Ccl6fli6kZXi435i33PFIRWc/Kz aIVJAoGBAKj0qeQzuIQLOD//xyYdb8PgTLSC4lw3ol1Uj/QoUPILmfB4S+s1op3q E44hV8J+JpQi7fbq5Ffmem2lfHwHtjYjwnmwuPKiE1hSpWLaUIZjOhuqGd4TLr24 sh6NaEekgZEE8XJpFL/aFVqZr6HjF4+FW/fGKVKzjvzW93EsOhSf -----END RSA PRIVATE KEY----- m2crypto-0.46.2/tests/der_encoded_seq.b64000066400000000000000000000024301506746742300201610ustar00rootroot00000000000000MIIDwTCCA70wggKloAMCAQICAg5QMA0GCSqGSIb3DQEBBQUAMGkxEzARBgoJkiaJk/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.46.2/tests/dhparams.pem000066400000000000000000000003651506746742300170500ustar00rootroot00000000000000-----BEGIN DH PARAMETERS----- MIGHAoGBAIgAcu3gpJeO8aS6N+sTMa655BMzBNlK66q62VH9RqmHwFJSjjCs3ZsF aVsTkO3Mt0gULn1drXsK6Lc6pA8s0eQN8ggyEPVr6ND0jN2jr2qc1XlqD7jxzdxe igB66pLvrWvAulrGxg4QMsQjqcpwZZ2ndRpYSmErIi4M1r19nTgjAgEC -----END DH PARAMETERS----- m2crypto-0.46.2/tests/dsa.param.pem000066400000000000000000000007071506746742300171170ustar00rootroot00000000000000-----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.46.2/tests/dsa.priv.pem000066400000000000000000000007751506746742300170040ustar00rootroot00000000000000-----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.46.2/tests/dsa.pub.pem000066400000000000000000000012161506746742300166010ustar00rootroot00000000000000-----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.46.2/tests/easy_rsa.pem000066400000000000000000000100231506746742300170470ustar00rootroot00000000000000Certificate: 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.46.2/tests/ec.priv.pem000066400000000000000000000004401506746742300166110ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MIGkAgEBBDDYZmLKVOPc34hDebkYt5vGMQBcX+WtHbXxnncL6ptQtzgkWN1ePGA6 x2HU8NFFpwigBwYFK4EEACKhZANiAASkekXfdAy+vfwcOvO0rwsVDWpil6EKYMlo kdhqz1/kp7hiv5ppw3/LCwsst9CJUUvfAIsRI4qFvTBE0JR8FxLHKFJgasPRHZo9 x5i2EG07MzSevyODOjtVBrklq6nQCao= -----END EC PRIVATE KEY----- m2crypto-0.46.2/tests/ec.pub.pem000066400000000000000000000003271506746742300164230ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEpHpF33QMvr38HDrztK8LFQ1qYpehCmDJ aJHYas9f5Ke4Yr+aacN/ywsLLLfQiVFL3wCLESOKhb0wRNCUfBcSxyhSYGrD0R2a PceYthBtOzM0nr8jgzo7VQa5Jaup0Amq -----END PUBLIC KEY----- m2crypto-0.46.2/tests/ec.pub2.pem000066400000000000000000000003271506746742300165050ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEQdk1A7xe7OelJhoFfE7x0u3gFSACecUC lM/9SqYiPusEpxI9XOe7te/8N/uavHd7z/GxnWSS7cTWuKUzkBgmggZkeVwz1a0a +trEhzxxiEN50Puuc0ExtNFQcgvIa6en -----END PUBLIC KEY----- m2crypto-0.46.2/tests/ed25519.priv.pem000066400000000000000000000001671506746742300172260ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIHYXZmLr4mS9wVx+PZVTNalGrxvuuS2SwrJqEmCUsYaC -----END PRIVATE KEY----- m2crypto-0.46.2/tests/ed25519.pub.pem000066400000000000000000000001611506746742300170260ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEAqVvZ55o7SU/yNEr/07AwMzxtm7teY6xhnhR9bDoWm2k= -----END PUBLIC KEY----- m2crypto-0.46.2/tests/ed25519.pub2.pem000066400000000000000000000001611506746742300171100ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEANSn/xYZB3kS30u9Gxb7RriRu80oJYsQd6jmA3u7TaVY= -----END PUBLIC KEY----- m2crypto-0.46.2/tests/fips.py000066400000000000000000000002111506746742300160470ustar00rootroot00000000000000try: with open("/proc/sys/crypto/fips_enabled") as f: fips_mode = int(f.read()) except (IOError, OSError): fips_mode = 0 m2crypto-0.46.2/tests/long_serial_cert.pem000066400000000000000000000017411506746742300205630ustar00rootroot00000000000000-----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.46.2/tests/makecerts.py000077500000000000000000000131221506746742300170740ustar00rootroot00000000000000#!/usr/bin/env python3 # # Create test certificates: # # ca.pem # server.pem # recipient.pem # signer.pem # x509.pem # import hashlib import os import os.path import sys import time from M2Crypto import ASN1, 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(): from M2Crypto import EC 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") def mk_rsa_key_pair(): def password_callback(*args): return b"qwerty" g_key = RSA.gen_key(2048, m2.RSA_F4) pkey = EVP.PKey() pkey.assign_rsa(g_key) try: # cipher=None means unencrypted pkey.save_key("rsa.priv.pem", cipher=None) except Exception as e: print(f"Error saving private key: {e}") raise # Save the private key with password qwerty try: # cipher=None means unencrypted pkey.save_key("rsa.priv2.pem", cipher=None, callback=password_callback) except Exception as e: print(f"Error saving private key: {e}") raise # Save the corresponding public key try: rsa_key_from_pkey = pkey.get_rsa() rsa_key_from_pkey.save_pub_key("rsa.pub.pem") except Exception as e: print(f"Error saving public key: {e}") raise 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) mk_rsa_key_pair() # FIXME This doesn't work well. # mk_ec_pair() m2crypto-0.46.2/tests/pubring.pgp000066400000000000000000000021001506746742300167110ustar00rootroot0000000000000028iPH6Nړ[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.46.2/tests/server.pem000066400000000000000000000132031506746742300165520ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=California, O=M2Crypto, CN=Heikki Toivonen Validity Not Before: Apr 22 14:50:27 2025 GMT Not After : Apr 20 14:50:27 2035 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:c8:99:5f:67:6b:be:f2:45:2d:85:0b:ca:d9:ad: 66:d9:47:97:7c:d4:cb:e6:91:55:33:79:45:86:1c: 4f:08:12:7f:4b:ec:83:bc:da:b5:af:0b:36:94:e9: 7a:90:c5:0f:39:63:c6:a4:51:b9:92:00:8e:d8:d6: 32:6f:7f:47:9d:f6:9a:9a:0f:18:66:14:13:a0:99: f7:29:8e:31:ee:9f:17:07:18:bd:b3:3c:74:bc:a9: 6f:0d:b4:25:1a:3d:5f:b5:d5:1d:85:5b:5b:ed:f5: 30:1e:0a:31:21:33:59:0d:d5:d0:33:71:33:7e:21: 5e:f0:bd:d2:79:e7:a7:e3:e0:48:dd:c2:11:65:5a: 27:39:ad:39:3a:23:02:01:9f:d6:e6:5a:f0:b0:8f: 8d:34:c8:44:f1:2b:38:59:d7:dd:3b:ee:e2:40:a5: 15:b9:96:05:59:43:9e:03:92:06:2f:01:64:11:3a: 60:31:ec:c3:55:fe:9a:5d:54:6a:6a:a9:b7:f5:1b: 0e:c4:73:b3:50:c3:14:04:5a:ba:70:d1:dc:ec:37: 1b:10:e3:59:51:54:06:fa:8e:c3:03:09:6f:c5:97: a8:80:a5:64:d9:3a:a5:62:e2:ca:7a:aa:4c:99:dc: 89:29:59:88:de:d3:96:ee:23:c7:30:2e:bd:b9:44: bf:97 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Subject Key Identifier: A5:1F:B6:1F:99:5E:36:5D:FB:55:D5:A1:99:E8:76:32:5D:60:08:BF Signature Algorithm: sha256WithRSAEncryption Signature Value: 77:d9:f1:59:61:76:7c:dc:f6:f1:46:d4:6a:f8:30:e5:94:dd: 92:63:20:5a:e5:b2:a0:a5:c7:5c:22:c8:ca:9f:c7:d7:bc:42: b3:8c:a0:3e:60:76:bd:a4:98:fb:25:8f:a6:87:6d:dc:43:37: 7e:15:60:ad:f2:17:29:34:2b:ea:fc:f6:69:ca:20:e3:c7:6e: 66:42:2e:d3:21:f3:53:40:7a:2e:f2:26:74:ac:6c:1f:6f:7d: b8:d1:d3:24:0e:5e:9e:d9:4c:da:d8:f1:db:4d:9e:5b:48:66: 70:92:93:db:80:c1:84:d4:73:f2:57:b3:f0:d5:8e:43:2b:14: 0d:6d:77:51:36:48:ac:35:b5:d3:57:a4:29:af:35:8a:a6:c2: a7:77:c6:62:aa:64:6a:3e:61:a7:ed:94:01:64:fb:d3:45:0c: c5:e8:1a:ad:83:d4:b8:fd:6c:d8:7d:5f:f6:02:c6:4d:e8:37: 83:1c:4e:bb:b6:97:e0:54:b2:91:5f:e3:cd:c9:a5:c0:f2:35: 9d:24:21:ae:4f:48:0c:f8:fc:f7:19:2a:25:8d:a7:41:de:a3: 52:0f:c0:52:55:4d:60:d2:9f:55:4f:f2:ea:0d:36:94:00:8f: 99:01:d8:33:c0:d1:6c:57:b6:a7:3a:4b:cd:f8:62:d8:21:bd: 5c:ab:2a:0b -----BEGIN CERTIFICATE----- MIIDPzCCAiegAwIBAgIBATANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzET MBEGA1UECAwKQ2FsaWZvcm5pYTERMA8GA1UECgwITTJDcnlwdG8xGDAWBgNVBAMM D0hlaWtraSBUb2l2b25lbjAeFw0yNTA0MjIxNDUwMjdaFw0zNTA0MjAxNDUwMjda MEkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMREwDwYDVQQKDAhN MkNyeXB0bzESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAyJlfZ2u+8kUthQvK2a1m2UeXfNTL5pFVM3lFhhxPCBJ/S+yD vNq1rws2lOl6kMUPOWPGpFG5kgCO2NYyb39Hnfaamg8YZhQToJn3KY4x7p8XBxi9 szx0vKlvDbQlGj1ftdUdhVtb7fUwHgoxITNZDdXQM3EzfiFe8L3Seeen4+BI3cIR ZVonOa05OiMCAZ/W5lrwsI+NNMhE8Ss4WdfdO+7iQKUVuZYFWUOeA5IGLwFkETpg MezDVf6aXVRqaqm39RsOxHOzUMMUBFq6cNHc7DcbEONZUVQG+o7DAwlvxZeogKVk 2TqlYuLKeqpMmdyJKVmI3tOW7iPHMC69uUS/lwIDAQABoywwKjAJBgNVHRMEAjAA MB0GA1UdDgQWBBSlH7YfmV42XftV1aGZ6HYyXWAIvzANBgkqhkiG9w0BAQsFAAOC AQEAd9nxWWF2fNz28UbUavgw5ZTdkmMgWuWyoKXHXCLIyp/H17xCs4ygPmB2vaSY +yWPpodt3EM3fhVgrfIXKTQr6vz2acog48duZkIu0yHzU0B6LvImdKxsH299uNHT JA5entlM2tjx202eW0hmcJKT24DBhNRz8lez8NWOQysUDW13UTZIrDW101ekKa81 iqbCp3fGYqpkaj5hp+2UAWT700UMxegarYPUuP1s2H1f9gLGTeg3gxxOu7aX4FSy kV/jzcmlwPI1nSQhrk9IDPj89xkqJY2nQd6jUg/AUlVNYNKfVU/y6g02lACPmQHY M8DRbFe2pzpLzfhi2CG9XKsqCw== -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAyJlfZ2u+8kUthQvK2a1m2UeXfNTL5pFVM3lFhhxPCBJ/S+yD vNq1rws2lOl6kMUPOWPGpFG5kgCO2NYyb39Hnfaamg8YZhQToJn3KY4x7p8XBxi9 szx0vKlvDbQlGj1ftdUdhVtb7fUwHgoxITNZDdXQM3EzfiFe8L3Seeen4+BI3cIR ZVonOa05OiMCAZ/W5lrwsI+NNMhE8Ss4WdfdO+7iQKUVuZYFWUOeA5IGLwFkETpg MezDVf6aXVRqaqm39RsOxHOzUMMUBFq6cNHc7DcbEONZUVQG+o7DAwlvxZeogKVk 2TqlYuLKeqpMmdyJKVmI3tOW7iPHMC69uUS/lwIDAQABAoIBAEOjg4nJyN7D+K9N 5J41W+KTwz6yOfaKtqHemFS6IuPj6Mxe+aSqUmytaUAY4d0CtTlyrT4m2F2kloYC 44q47hsTVdnwkReKWXvjrnVynt+JASjBbOWM0wfyUaHbRk9stmMHcybOQVchP5JB eYNqXvLNT6Co4OX8tpiSSPAV7oRlOGz6eA4Kk2NKYbGGVdw/bj2jbbDE2k8sm419 FmKXxzzsiYo/dXDx0MHllMBuIqU++lKY//9WJjaHxi2VqofBNha9Cn9Oq9aJWS1t taNdV4d0edMKEVEG0ZA5YPAn4TBL9RywC1DQ3UIr2du6LxN0ABN7K7qzl2O/wc/T CHTGqbECgYEA+PQhGeM3EqngiBHwEkMFH08U1GPPrwNd7w+lXaVakfm/tkU03IyY yhDR/FJls0XDHu+8piGLcjcBbjQIYvMv8ftP72neWJzxqpTbx7LQxAV8m8Gy+ayf QqfySfuFFo/DMOsYNWtEiQjHnGpdQ9XBDpJvZeYvKPd+3nZLatVSmdMCgYEAzkbg Lzmh3ts4EkL1nSlgsezXvR38stexP7rShhILydlAiydJZRPKE6SthG3JMTTlZZK0 ifu8AfFkOOl3fmz7nfxaKCGMuNOACzgiNiFASxmzjgcQQawqRp2xVcVP7Gd4DP82 2wlDuk9L29cGfzZ7l2scGWdaqCBn0O+Vy5sWhK0CgYB0l7ks65nuVrr+XxBFLTgn 6pyBv+ETQQtsG7LBweBB/2qGzbCtHfesouYFOv3AUQrJ4VNDpvAs5I/58cp/tQ8e UCmmobltXMtdrWulAhz9wOgT9kqA3hSUXh1+AprY7ylmLqRe2Eb3urHpknLtgx1w WqprWbt6fzberx4xAYk22wKBgES1qxtP8TFQiD7c+v9ctw7NO5eNE41m922pB1MN U8vqh+tSLMp0aw1b/0hrYWb4najV0zlbFub2x1GFwv3jw3R+iHFxq3QtTyttiUfK j6X0a7DVfX7CoFphUJ6nWNYAKSb7JASV829t1nDmEQ3y0fw/+14i5Tm3gZ1BEP5/ LGMJAoGBAPS9wfFT31r1sd0oAl9MWRyRNNr71G5nwt36Oqj2RLMaswLaAbwGLWkp +9LCRnQPC00PsMB9QbWdb3WmHrnpiWwd0Re/e5BSSOtpbW/A+WT9SPHU5z8+dVyQ 1mnG1XXjIOdaIDbANdGuE6qUYUQBQFUiBawJfhMxsfBwPHdcRi0f -----END RSA PRIVATE KEY----- m2crypto-0.46.2/tests/server_key.pem000066400000000000000000000032131506746742300174220ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAyJlfZ2u+8kUthQvK2a1m2UeXfNTL5pFVM3lFhhxPCBJ/S+yD vNq1rws2lOl6kMUPOWPGpFG5kgCO2NYyb39Hnfaamg8YZhQToJn3KY4x7p8XBxi9 szx0vKlvDbQlGj1ftdUdhVtb7fUwHgoxITNZDdXQM3EzfiFe8L3Seeen4+BI3cIR ZVonOa05OiMCAZ/W5lrwsI+NNMhE8Ss4WdfdO+7iQKUVuZYFWUOeA5IGLwFkETpg MezDVf6aXVRqaqm39RsOxHOzUMMUBFq6cNHc7DcbEONZUVQG+o7DAwlvxZeogKVk 2TqlYuLKeqpMmdyJKVmI3tOW7iPHMC69uUS/lwIDAQABAoIBAEOjg4nJyN7D+K9N 5J41W+KTwz6yOfaKtqHemFS6IuPj6Mxe+aSqUmytaUAY4d0CtTlyrT4m2F2kloYC 44q47hsTVdnwkReKWXvjrnVynt+JASjBbOWM0wfyUaHbRk9stmMHcybOQVchP5JB eYNqXvLNT6Co4OX8tpiSSPAV7oRlOGz6eA4Kk2NKYbGGVdw/bj2jbbDE2k8sm419 FmKXxzzsiYo/dXDx0MHllMBuIqU++lKY//9WJjaHxi2VqofBNha9Cn9Oq9aJWS1t taNdV4d0edMKEVEG0ZA5YPAn4TBL9RywC1DQ3UIr2du6LxN0ABN7K7qzl2O/wc/T CHTGqbECgYEA+PQhGeM3EqngiBHwEkMFH08U1GPPrwNd7w+lXaVakfm/tkU03IyY yhDR/FJls0XDHu+8piGLcjcBbjQIYvMv8ftP72neWJzxqpTbx7LQxAV8m8Gy+ayf QqfySfuFFo/DMOsYNWtEiQjHnGpdQ9XBDpJvZeYvKPd+3nZLatVSmdMCgYEAzkbg Lzmh3ts4EkL1nSlgsezXvR38stexP7rShhILydlAiydJZRPKE6SthG3JMTTlZZK0 ifu8AfFkOOl3fmz7nfxaKCGMuNOACzgiNiFASxmzjgcQQawqRp2xVcVP7Gd4DP82 2wlDuk9L29cGfzZ7l2scGWdaqCBn0O+Vy5sWhK0CgYB0l7ks65nuVrr+XxBFLTgn 6pyBv+ETQQtsG7LBweBB/2qGzbCtHfesouYFOv3AUQrJ4VNDpvAs5I/58cp/tQ8e UCmmobltXMtdrWulAhz9wOgT9kqA3hSUXh1+AprY7ylmLqRe2Eb3urHpknLtgx1w WqprWbt6fzberx4xAYk22wKBgES1qxtP8TFQiD7c+v9ctw7NO5eNE41m922pB1MN U8vqh+tSLMp0aw1b/0hrYWb4najV0zlbFub2x1GFwv3jw3R+iHFxq3QtTyttiUfK j6X0a7DVfX7CoFphUJ6nWNYAKSb7JASV829t1nDmEQ3y0fw/+14i5Tm3gZ1BEP5/ LGMJAoGBAPS9wfFT31r1sd0oAl9MWRyRNNr71G5nwt36Oqj2RLMaswLaAbwGLWkp +9LCRnQPC00PsMB9QbWdb3WmHrnpiWwd0Re/e5BSSOtpbW/A+WT9SPHU5z8+dVyQ 1mnG1XXjIOdaIDbANdGuE6qUYUQBQFUiBawJfhMxsfBwPHdcRi0f -----END RSA PRIVATE KEY----- m2crypto-0.46.2/tests/signer.pem000066400000000000000000000100761506746742300165400ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 3 (0x3) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=California, O=M2Crypto, CN=Heikki Toivonen Validity Not Before: Apr 22 14:50:27 2025 GMT Not After : Apr 20 14:50:27 2035 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:d0:90:54:6d:02:19:6c:bd:2a:cd:08:ac:b1:1e: 19:f5:64:2f:11:62:8d:ee:51:bc:b1:69:0d:0e:e4: 9c:aa:fc:5b:60:ca:53:0c:52:1c:2f:92:f4:c2:56: 98:7a:8c:ac:50:a8:d9:bf:a0:d8:99:8a:ca:92:b0: 98:84:77:4c:ae:30:5f:5c:2c:3c:9e:68:0c:a7:bc: 53:1e:d1:c0:d8:22:d8:fe:bd:18:cf:60:21:38:97: 66:17:9c:11:6b:31:ea:48:03:82:b3:de:a6:c4:48: dd:95:bd:6d:d6:d9:42:6c:1c:22:5e:4f:83:02:ce: 32:8d:0b:8b:a5:d9:6d:e6:b7:0a:9e:56:0f:c0:0b: a1:05:a4:dd:3b:f3:20:ce:70:6b:c6:b3:a3:f4:fb: c8:27:af:05:c8:94:a0:d5:17:03:30:72:64:3c:d1: 9b:b2:3b:4f:94:ff:ee:42:c2:bb:05:e3:6e:de:bf: 39:02:dc:17:63:40:4f:6c:7c:bb:b6:7b:a0:b3:4d: c8:c4:e0:27:43:3d:a7:5c:2f:5c:a7:dc:09:d8:46: ad:d0:2e:0c:97:bc:6f:03:69:df:1b:37:6d:67:6f: fd:4d:68:fb:53:0f:df:01:db:e8:05:b5:be:9b:fb: dc:e2:8a:68:0a:96:2a:3e:75:0f:fc:03:c6:a8:50: 77:e3 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Subject Key Identifier: 72:2E:DF:45:BD:A4:04:AD:32:46:BA:C0:72:A1:4A:CB:2D:13:77:39 Signature Algorithm: sha256WithRSAEncryption Signature Value: 28:12:22:43:61:b3:88:f2:6b:4c:6c:cd:f7:17:84:06:ab:ca: d8:f8:c3:39:fd:a0:46:b9:d4:3c:46:c4:f5:89:7b:3c:47:f6: 8b:48:b0:7a:69:63:da:61:f3:ad:82:6f:0f:82:c3:9f:5f:69: 73:55:3e:6d:b6:d0:c4:3d:76:a4:3e:c8:f9:82:9a:60:4b:5f: 3a:a3:ea:06:21:f3:02:5c:9d:17:7a:42:34:75:d5:0e:52:39: 83:37:02:3f:df:48:99:68:4e:47:64:8d:dd:34:7c:12:c5:c2: e3:d3:c0:b9:1f:74:4e:08:c8:90:6b:95:b6:ed:8a:54:be:fc: 9d:5e:af:4e:d7:f7:4a:04:c0:e6:23:73:32:a3:7f:5a:a0:ce: f3:d8:d1:b6:96:ab:73:1c:b2:6a:ff:7b:45:d7:f6:3e:12:d1: 89:31:b0:46:5e:ea:71:a9:59:6b:97:0a:59:73:87:f0:3d:e4: 47:80:e7:6f:99:06:99:e0:59:c7:dc:6a:00:51:d1:90:10:89: 6a:c8:39:07:1f:48:26:c2:85:a0:17:28:20:be:61:6a:d8:ad: 4f:ce:73:6b:d5:fd:4b:85:1f:53:e8:53:a5:9b:77:e3:94:fb: a9:ed:0f:d0:b3:9a:88:18:0d:a9:4d:13:d8:f6:93:82:17:86: 21:b4:c6:54 -----BEGIN CERTIFICATE----- MIIDXzCCAkegAwIBAgIBAzANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzET MBEGA1UECAwKQ2FsaWZvcm5pYTERMA8GA1UECgwITTJDcnlwdG8xGDAWBgNVBAMM D0hlaWtraSBUb2l2b25lbjAeFw0yNTA0MjIxNDUwMjdaFw0zNTA0MjAxNDUwMjda MGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMREwDwYDVQQKDAhN MkNyeXB0bzEPMA0GA1UEAwwGU2lnbmVyMSEwHwYJKoZIhvcNAQkBFhJzaWduZXJA ZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQkFRt AhlsvSrNCKyxHhn1ZC8RYo3uUbyxaQ0O5Jyq/FtgylMMUhwvkvTCVph6jKxQqNm/ oNiZisqSsJiEd0yuMF9cLDyeaAynvFMe0cDYItj+vRjPYCE4l2YXnBFrMepIA4Kz 3qbESN2VvW3W2UJsHCJeT4MCzjKNC4ul2W3mtwqeVg/AC6EFpN078yDOcGvGs6P0 +8gnrwXIlKDVFwMwcmQ80ZuyO0+U/+5CwrsF427evzkC3BdjQE9sfLu2e6CzTcjE 4CdDPadcL1yn3AnYRq3QLgyXvG8Dad8bN21nb/1NaPtTD98B2+gFtb6b+9ziimgK lio+dQ/8A8aoUHfjAgMBAAGjLDAqMAkGA1UdEwQCMAAwHQYDVR0OBBYEFHIu30W9 pAStMka6wHKhSsstE3c5MA0GCSqGSIb3DQEBCwUAA4IBAQAoEiJDYbOI8mtMbM33 F4QGq8rY+MM5/aBGudQ8RsT1iXs8R/aLSLB6aWPaYfOtgm8PgsOfX2lzVT5tttDE PXakPsj5gppgS186o+oGIfMCXJ0XekI0ddUOUjmDNwI/30iZaE5HZI3dNHwSxcLj 08C5H3ROCMiQa5W27YpUvvydXq9O1/dKBMDmI3Myo39aoM7z2NG2lqtzHLJq/3tF 1/Y+EtGJMbBGXupxqVlrlwpZc4fwPeRHgOdvmQaZ4FnH3GoAUdGQEIlqyDkHH0gm woWgFyggvmFq2K1PznNr1f1LhR9T6FOlm3fjlPup7Q/Qs5qIGA2pTRPY9pOCF4Yh tMZU -----END CERTIFICATE----- m2crypto-0.46.2/tests/signer_key.pem000066400000000000000000000032171506746742300174070ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA0JBUbQIZbL0qzQissR4Z9WQvEWKN7lG8sWkNDuScqvxbYMpT DFIcL5L0wlaYeoysUKjZv6DYmYrKkrCYhHdMrjBfXCw8nmgMp7xTHtHA2CLY/r0Y z2AhOJdmF5wRazHqSAOCs96mxEjdlb1t1tlCbBwiXk+DAs4yjQuLpdlt5rcKnlYP wAuhBaTdO/MgznBrxrOj9PvIJ68FyJSg1RcDMHJkPNGbsjtPlP/uQsK7BeNu3r85 AtwXY0BPbHy7tnugs03IxOAnQz2nXC9cp9wJ2Eat0C4Ml7xvA2nfGzdtZ2/9TWj7 Uw/fAdvoBbW+m/vc4opoCpYqPnUP/APGqFB34wIDAQABAoIBAAHLfC6D+hwJdLjW /kV38Nk/x3fq1TXb1jfgo5AhP4fpLBAlLZnJixyNszWI8T78vu7ixRz1EWgg3aVt h6J8NFi7adatOshSNOmsoTp+q54wjpWCoxgFx8No6iQB39SAVXfRL+rEW8MMrXuA adWTgRLVGyacoJABnkXAd68xs9Rsctvqh5z5UjtKwUCs0WCo3MAXOnWOe9XHvyWq P+nyjMvU/ZLuuxqc8sysBVT/x9ozpyPID8PD2w2L1kxOBa7gmC8ARL3MzLTJkjwf c6DfBlMmb+VSbyzdqzUxjJHiGJkTHEiVujxpeuYwjThThUqVicj3fN/1JXkomG4h dzePjMECgYEA8On9H+CMzWueMIsvpg7LXYgjfDkYVWJ9rZI5+PSqiopdtIWZhd/G G38f0WUYD0r1sSaS93UDlRRP2zrC4aM3uh2qTJZhrMvF5EsxhdQKmoMAMC8Xug0T XgijVpCUBBj2kAWUD6NQtu/px61+3Ipx1YQQValNM6jihLoHWn88fBsCgYEA3Z++ 0wx2G/KK92ORhsmFjOdsgFeaMUnr7kQ+tH8UE7WcN+u7sytmCZdRlgxeB20VE086 /KPOJuRSkS3zDID7s+5l3xnSrJVMoZ3X0wy2kNenJpbzmar1SceYV8coo8hAhtZZ /q/gJmeHRhLioZEpol+292XQe+SFHRWNDxlMH9kCgYEAwhqU0lE2wO+bhdsu6elz mwlsJdNOssTnI6j0QozGt1biRud5mW6BjHfxZ+G+79tid3fv46cI2t2Btc3zZJ7/ 8Fmkc46aZgHMkLKw1PXSEUnJJglbYZDVcOcey0kzqNWAGuwTrkHUb4B/aF12IDT/ oJuGGa6NwDirQWstL5HiZs8CgYEA0YLJv/SA10zD6LkdAwIRmbHRlca7AqtyOY4U hUe5MCS4qPjWObvmO1zsiN/qKDUL/nQhPGKSaZvhHlQE96YbzO6rKWzdB8AgcIyq Ul8rW+QypT2Azp2aQwRIVXr2RVbzAUU0UJvtWAD5FdqWmsyDQngfnOOIYwcWe/c6 obJ1j4kCgYAQHWs4Ex+xb3KXzvTepG0BUkRFtqrHo8R+nAj0wX1aPPIcreAa5JO5 j8iTj72VYNb6xIXxGrZvkeoiIJzVxUqOaipIdN8a174AY9E4TvXzKkCdOpyUdF02 Z7LwYu/00uTLvGRYqDAGxBSH18tGHJjbmvmDX0ta3+FdFiXPivfBBQ== -----END RSA PRIVATE KEY----- m2crypto-0.46.2/tests/te_chunked_response.txt000066400000000000000000000001411506746742300213260ustar00rootroot00000000000000HTTP/1.1 200 ok Content-Type: text/plain Transfer-Encoding: chunked 4 foo 7 foobar 0 m2crypto-0.46.2/tests/test_aes.py000066400000000000000000000046171506746742300167330ustar00rootroot00000000000000#!/usr/bin/env python """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.46.2/tests/test_asn1.py000066400000000000000000000131511506746742300170160ustar00rootroot00000000000000#!/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.46.2/tests/test_authcookie.py000066400000000000000000000137101506746742300203100ustar00rootroot00000000000000#!/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: str, fr: int, to: 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(), "sha256") ) 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(), "sha256") ) 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.46.2/tests/test_bio.py000066400000000000000000000051471506746742300167330ustar00rootroot00000000000000#!/usr/bin/env python """ 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.46.2/tests/test_bio_file.py000066400000000000000000000100531506746742300177220ustar00rootroot00000000000000#!/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.46.2/tests/test_bio_iobuf.py000066400000000000000000000045251506746742300201160ustar00rootroot00000000000000#!/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.46.2/tests/test_bio_membuf.py000066400000000000000000000074121506746742300202630ustar00rootroot00000000000000#!/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.46.2/tests/test_bio_ssl.py000066400000000000000000000116031506746742300176060ustar00rootroot00000000000000#!/usr/bin/env python """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.46.2/tests/test_bn.py000066400000000000000000000040071506746742300165530ustar00rootroot00000000000000#!/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.46.2/tests/test_dh.py000066400000000000000000000034531506746742300165530ustar00rootroot00000000000000#!/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.46.2/tests/test_dsa.py000066400000000000000000000070621506746742300167270ustar00rootroot00000000000000#!/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.sha256(b"Can you spell subliminal channel?").digest() different_data = hashlib.sha256(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.46.2/tests/test_ec_curves.py000066400000000000000000000112351506746742300201330ustar00rootroot00000000000000#!/usr/bin/env python # XXX memory leaks """ 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.46.2/tests/test_ecdh.py000066400000000000000000000024531506746742300170620ustar00rootroot00000000000000#!/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.46.2/tests/test_ecdsa.py000066400000000000000000000062341506746742300172370ustar00rootroot00000000000000#!/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 import os import os.path 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.sha256(b"Can you spell subliminal channel?").digest() def setUp(self): assert os.path.exists(self.errkey) and os.access( self.errkey, os.R_OK ), "Cannot access errkey file {}".format(self.errkey) assert os.path.exists(self.privkey) and os.access( self.privkey, os.R_OK ), "Cannot access privkey file {}".format(self.privkey) assert os.path.exists(self.pubkey) and os.access( self.pubkey, os.R_OK ), "Cannot access pubkey file {}".format(self.pubkey) def callback(self, *args): pass def callback2(self): pass def test_loadkey_junk(self): with self.assertRaises(IOError): 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.46.2/tests/test_err.py000066400000000000000000000011411506746742300167400ustar00rootroot00000000000000#!/usr/bin/env python """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.46.2/tests/test_evp.py000066400000000000000000000747761506746742300167720ustar00rootroot00000000000000""" Unit tests for M2Crypto.EVP. Copyright (c) 2004-2007 Open Source Applications Foundation Author: Heikki Toivonen """ import base64 import hashlib import io import logging import sys from binascii import a2b_hex, b2a_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("sha256"), None) def test_MessageDigest(self): # noqa with self.assertRaises(ValueError): EVP.MessageDigest("sha513") md = EVP.MessageDigest("sha256") self.assertEqual(md.update(b"Hello"), 1) self.assertEqual( util.octx_to_num(md.final()), 11024336812845202542736754815889718862783203771635063178616734621641926515049, ) # temporarily remove sha256 from m2 old_sha1 = m2.sha256 del m2.sha256 # now run the same test again, relying on EVP.MessageDigest() to call # get_digestbyname() under the hood md = EVP.MessageDigest("sha256") self.assertEqual(md.update(b"Hello"), 1) self.assertEqual( util.octx_to_num(md.final()), 11024336812845202542736754815889718862783203771635063178616734621641926515049, ) # put sha256 back in place m2.sha256 = 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")), 36273358097036101702192658888336808701031275731906771612800928188662823394256, 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.sha256(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.sha256(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, "sha256", 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, "sha256", 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"someKey", b"More text test vectors to stuff up EBCDIC machines :-)", a2b_hex(b"9ab50f9901ac7d3cefad459b17259cf570e286a8bfd7472aeb4a257897b5ac10"), ] data2 = [ a2b_hex(b"0b" * 16), b"Hi There", a2b_hex(b"492ce020fe2534a5789dc3848806c78f4f6711397f08e7e7a12ca5a4483c8aa6"), ] data3 = [ b"Jefe", b"what do ya want for nothing?", a2b_hex(b"5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"), ] data4 = [ a2b_hex(b"aa" * 16), a2b_hex(b"dd" * 50), a2b_hex(b"7dda3cc169743a6484649f94f0eda0f9f2ff496a9733fb796ed5adb40a44c3c1"), ] data = [data1, data2, data3, data4] def test_simple(self): self.maxDiff = None algo = "sha256" for d in self.data: with self.subTest(i=self.data.index(d)): h = EVP.HMAC(d[0], algo) h.update(d[1]) ret = h.final() try: self.assertEqual(ret, d[2]) except AssertionError: print(f"ret:\n{ret}", file=sys.stderr, flush=True) raise with self.assertRaises(ValueError): EVP.HMAC(d[0], algo="nosuchalgo") def make_chain_HMAC(self, key, start, input, algo="sha256"): # 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="sha256"): 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="sha256"): 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="sha256"): # 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.46.2/tests/test_init.py000066400000000000000000000007361506746742300171240ustar00rootroot00000000000000#!/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.46.2/tests/test_obj.py000066400000000000000000000115721506746742300167330ustar00rootroot00000000000000#!/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.46.2/tests/test_rand.py000066400000000000000000000057061506746742300171070ustar00rootroot00000000000000#!/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.46.2/tests/test_rc4.py000066400000000000000000000027101506746742300166430ustar00rootroot00000000000000#!/usr/bin/env python """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.46.2/tests/test_rsa.py000066400000000000000000000327521506746742300167510ustar00rootroot00000000000000#!/usr/bin/env python """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.sha256(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), 2048) 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) RSA.load_key(self.privkey2, self.pp2_callback) def test_loadkey(self): self.maxDiff = None rsa = RSA.load_key(self.privkey) self.assertEqual(len(rsa), 2048) self.assertEqual(rsa.e, b"\000\000\000\003\001\000\001") # aka 65537 aka 0xf4 log.debug("rsa.n = %s", repr(rsa.n)) self.assertEqual( rsa.n, b"\x00\x00\x01\x01\x00\xc9\xb76\x91\x86\xcb\x9a!" + b"w\x9c\xfb\x8c\xe8\xaa\xe7\xecT\xb02s\x00\xfav" + b"\x0b\xe4\xb7I\xa4\xf2\x8f\xe1\xaf\x93\xeevxT{" + b"\xc2\xb0\t\x05x?\xe6|\xfd\xf5\x86\x0b\xd2\x97\xc4\xc3\x99\x88h" + b"\xd4n{~`\x8a\xe4\xe73\n\xe6\x94\x1bTr\x9a\xa5\xf5+\xbe\x81\xacV" + b"\x0c\xb6s\xa3\x94\xacT.\xbf\xd3\t\x06[\x8a\x918\x01\xcf\xcb" + b"\x95\xce\x1b\xf3\xd4\xcf\xaf3qo\xf1\t\xe2\x16\xab\r\xdd\r_>" + b"\xc7\xa1\x88\xf4\x10'\xe54S\x1a\x9c\xf3\xa1\xaf\xddw\xec{" + b"\x9f\xefvCS\xc2\xa6\xba\xcb\xa1-{\xee\xd4\xa2hiY\x7f)\xb3{" + b'\x1d\xf3\x19NX\x01t\xbe\x83\xaa\x17\xc0\xaax\x97\x10\xe9"y' + b"\x9e\x1d'i\xfe'\xec\xb0\xd8:\xd42\\a\xea\xeb\x19\x1e\xab|" + b'\xad\xb8\xda\x1b\xb7,.o"\x84\xa4\xd3\xff\xc2\xff\xf6iH>C\x14z' + b"\xea\xc6f6\xa5\x96N^\x8c\xdej\xferN\xad'\x9e\xcf6\x06A,\xa7W=" + b"\xa1\x07\xc5\xfb\xbb2\xd5;V\x14\xe7", ) 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), 2048) 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), 2048) 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), 2048) # 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 = {"sha256": "", "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.sha256(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 = {"sha256": 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, "sha256") 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.sha256(message).digest() signature = rsa.sign(digest, "sha256") 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) 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.sha256(message).digest() other_message = b"Abracadabra" other_digest = hashlib.sha256(other_message).digest() other_signature = rsa.sign(other_digest) with self.assertRaises(RSA.RSAError): rsa.verify(digest, other_signature) def test_rsa_ex_data(self): rsa = RSA.gen_key(2048, m2.RSA_F4) ret = rsa.set_ex_data(1, 22) data = rsa.get_ex_data(1) self.assertEqual(data, 22) self.assertIsInstance(data, int) 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.46.2/tests/test_smime.py000066400000000000000000000313161506746742300172710ustar00rootroot00000000000000#!/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.46.2/tests/test_ssl.py000066400000000000000000001312751506746742300167650ustar00rootroot00000000000000#!/usr/bin/env python """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 platform import signal import socket import subprocess import sys import tempfile import time import warnings from M2Crypto import ( Err, Rand, SSL, X509, ftpslib, httpslib, m2, 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, "-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() @unittest.skipIf( "DISTROBOX_ENTER_PATH" in os.environ, "Don't run the test on local machine", ) 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) @unittest.skipIf( "DISTROBOX_ENTER_PATH" in os.environ, "Don't run the test on local machine", ) 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) # the test for musl libc based on the unresolved bug in CPython gh#python/cpython#87414 @unittest.skipIf( (util.is_32bit() and platform.libc_ver() == ("", "")), "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(m2urllib2.URLError): 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_no_sock_leak(self): pid = self.start_server(self.args) try: o = m2urllib2.build_opener() r = o.open("https://%s:%s/" % (srv_host, self.srv_port)) # The SSL.Connection object is now attached directly to the # HTTPResponse object (r.fp) as the 'ssl' attribute. ssl_conn = r.fp.ssl # Keep a reference to the connection object in 's' for the leak check. s = [ssl_conn] self.assertFalse(ssl_conn._closed) r.close() self.assertTrue(ssl_conn._closed) # TODO This should be assertEqual 1, but we leak sock # somewhere. 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])), 4) 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 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) class SessionTestCase(unittest.TestCase): def test_session_load_bad(self): with self.assertRaises(SSL.SSLError): SSL.Session.load_session("tests/signer.pem") 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)) 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.46.2/tests/test_ssl_offline.py000066400000000000000000000041061506746742300204570ustar00rootroot00000000000000"""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="9917962167CFDB8BCFAC775093E79A1113B3DA146EA4E1EB1FEFC6E58770D158", ) 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.46.2/tests/test_ssl_win.py000066400000000000000000000040651506746742300176360ustar00rootroot00000000000000#!/usr/bin/env python """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.46.2/tests/test_threading.py000066400000000000000000000016221506746742300201210ustar00rootroot00000000000000#!/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.46.2/tests/test_timeout.py000066400000000000000000000103061506746742300176410ustar00rootroot00000000000000#!/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.46.2/tests/test_util.py000066400000000000000000000017701506746742300171350ustar00rootroot00000000000000#!/usr/bin/env python """ Unit tests for M2Crypto.util. Copyright (c) 2024 Matěj Cepl. All rights reserved. """ import os import platform from M2Crypto import m2, util from tests import unittest class UtilTestCase(unittest.TestCase): def test_is32bit(self): # defaults bit32 = m2.time_t_bits() # test for libc musl from unfinished upstream bug gh#python/cpython#87414 if ( util.is_32bit() and (platform.libc_ver() != ("", "")) and ( os.environ.get("M2_TIMET_NO_ARCH", "").casefold() not in ["true", "1", "yes"] ) ): self.assertEqual(bit32, 32) else: self.assertNotEqual(bit32, 32) self.assertIsInstance(bit32, int) def suite(): return unittest.TestLoader().loadTestsFromTestCase(UtilTestCase) if __name__ == "__main__": Rand.load_file("randpool.dat", -1) unittest.TextTestRunner().run(suite()) Rand.save_file("randpool.dat") m2crypto-0.46.2/tests/test_x509.py000066400000000000000000000743141506746742300166710ustar00rootroot00000000000000#!/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 expectedFailureIf from tests import unittest log = logging.getLogger(__name__) class X509TestCase(unittest.TestCase): def callback(self, *args): pass def setUp(self): self.expected_hash = ( "1A041EA7A3E77809868B8620B89A246DCAE229A5FC830CF5C26BB479F4CC1D8A" ) 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, "sha256") 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) if m2.OPENSSL_VERSION_NUMBER < 0x30400000: 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, "sha256") 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, "sha256") 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, "sha256") proxycert = self.make_proxycert(end_entity_cert, utc) proxycert.sign(pk2, "sha256") 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("sha256") 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("sha256") 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") 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") 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") def test_add_subject_key_identifier(self): # 1. Create a certificate (it needs a key pair and subject/issuer set up) req, pk = self.mkreq(1024) cert = X509.X509() cert.set_serial_number(3) cert.set_version(2) cert.set_subject(req.get_subject()) cert.set_issuer(req.get_subject()) # Self-signed for simplicity cert.set_pubkey(pk) # 2. Add the Subject Key Identifier # Assuming EVP.PKey has get_key_identifier() or similar for the SKID hash result = cert.add_subject_key_identifier() self.assertEqual(result, 1, "Failed to add subjectKeyIdentifier extension") # 3. Verify the extension exists and its value format is correct skid_ext = cert.get_ext("subjectKeyIdentifier") # Check the name self.assertEqual(skid_ext.get_name(), "subjectKeyIdentifier") # Check that the value is non-empty and has the correct colon-separated hex format value = skid_ext.get_value() self.assertGreater(len(value), 10, "SKID value is too short or empty") self.assertTrue( all(c in "0123456789ABCDEF:" for c in value.upper()), "SKID value contains invalid characters", ) self.assertIn(":", value, "SKID value should be colon-separated hex string") # 4. Sign the certificate (requires the SKID extension to be correctly formed) cert.sign(pk, "sha256") self.assertTrue( cert.verify(pk), "Certificate signature failed after adding SKID" ) 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: str = "proxyCertInfo" value: str = "critical,language:Inherit all" else: # With this there are no leaks: name: str = "nsComment" value: str = "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.46.2/tests/test_xmlrpc.py000066400000000000000000000164611506746742300174700ustar00rootroot00000000000000"""Unit tests for M2Crypto.m2xmlrpclib. Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved. Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All rights reserved. """ import base64 from unittest.mock import patch, MagicMock from M2Crypto import SSL, Rand from M2Crypto.m2xmlrpclib import SSL_Transport from xmlrpc.client import ProtocolError, Transport from tests import unittest # A valid minimal XML-RPC success response for mock VALID_XML_RESPONSE = b"OK" # Create a mock for the full response object expected from h.getresponse() class MockResponse: def __init__(self, status, reason, headers, content=b""): self.status = status self.reason = reason self._headers = headers self._content = content self._read_queue = [content, b""] def getheaders(self): """Returns headers as a list of (name, value) tuples.""" return self._headers def read(self, size=None): """Implements reading the response body using a side effect queue.""" # FIX: Ensure b'' is returned after content is consumed if self._read_queue: return self._read_queue.pop(0) return b"" # Return empty bytes if the queue is exhausted def close(self): pass def geturl(self): # Required by xmlrpc.client.Transport.parse_response return "https://mockhost/RPC2" # Class for tests that DO NOT require patching class SSLTransportInitTests(unittest.TestCase): def setUp(self): """Set up a custom SSL context for testing.""" self.custom_ctx = SSL.Context() self.assertIsNotNone(self.custom_ctx) def test_init_default_ssl_context(self): """Test instantiation with no SSL context provided.""" t = SSL_Transport() self.assertIsInstance(t, SSL_Transport) self.assertIsInstance(t.ssl_ctx, SSL.Context) self.assertIsInstance(t, Transport) self.assertTrue(t.user_agent.startswith("M2Crypto_XMLRPC/")) def test_init_custom_ssl_context(self): """Test instantiation with a custom SSL context.""" t = SSL_Transport(ssl_context=self.custom_ctx) self.assertIs(t.ssl_ctx, self.custom_ctx) def test_init_junk_ssl_context(self): """Test instantiation with an invalid type for ssl_context.""" with self.assertRaises(AssertionError): SSL_Transport(ssl_context=object()) # Test basic TypeError for positional args outside of SSL context with self.assertRaises(AssertionError): SSL_Transport("junk_arg") # Class for tests that DO require patching @patch("M2Crypto.m2xmlrpclib.m2urllib2") @patch("M2Crypto.httpslib.HTTPSConnection") class SSLTransportRequestTests(unittest.TestCase): def setUp(self): """Set up a custom SSL context for testing.""" self.custom_ctx = SSL.Context() self.assertIsNotNone(self.custom_ctx) self.t = SSL_Transport(ssl_context=self.custom_ctx) self.request_body = b"test" self.host_url = "example.com:443" self.handler = "/RPC2" def test_request_basic_success(self, MockConn, mock_m2urllib2): """Test successful request with basic setup and correct response parsing.""" mock_m2urllib2.splituser.return_value = (None, self.host_url) mock_m2urllib2.splitport.return_value = ("example.com", "443") mock_conn_instance = MockConn.return_value mock_conn_instance.getresponse.return_value = MockResponse( status=200, reason="OK", headers=[("Content-Length", str(len(VALID_XML_RESPONSE)))], content=VALID_XML_RESPONSE, ) result = self.t.request( host=self.host_url, handler=self.handler, request_body=self.request_body, verbose=0, ) MockConn.assert_called_once_with("example.com", 443, ssl_context=self.t.ssl_ctx) mock_conn_instance.putrequest.assert_called_once_with("POST", self.handler) mock_conn_instance.send.assert_called_once_with(self.request_body) mock_conn_instance.close.assert_called_once() self.assertIsInstance(result, tuple) def test_request_with_basic_auth(self, MockConn, mock_m2urllib2): """Test request includes Authorization header when credentials are provided.""" with patch( "M2Crypto.m2xmlrpclib.SSL_Transport.splitport" ) as mock_splitport, patch( "M2Crypto.m2xmlrpclib.SSL_Transport.splituser" ) as mock_splituser: user_pass_bytes = b"user:secret" host_url_auth = "user:secret@authhost.com:8000" mock_splituser.return_value = (user_pass_bytes, "authhost.com:8000") mock_splitport.return_value = ("authhost.com", "8000") mock_conn_instance = MockConn.return_value mock_conn_instance.getresponse.return_value = MockResponse( status=200, reason="OK", headers=[], content=VALID_XML_RESPONSE, # FIX: Use clean XML ) self.t.request( host=host_url_auth, handler=self.handler, request_body=self.request_body, verbose=0, ) expected_auth_val = ( base64.encodebytes(user_pass_bytes).strip().decode("ascii") ) mock_conn_instance.putheader.assert_any_call( "Authorization", f"Basic {expected_auth_val}" ) mock_conn_instance.close.assert_called_once() def test_request_http_error(self, MockConn, mock_m2urllib2): """Test request raises ProtocolError on non-200 HTTP status.""" with patch( "M2Crypto.m2xmlrpclib.SSL_Transport.splituser" ) as mock_splituser, patch( "M2Crypto.m2xmlrpclib.SSL_Transport.splitport" ) as mock_splitport: mock_splituser.return_value = (None, self.host_url) mock_splitport.return_value = ("example.com", "443") mock_conn_instance = MockConn.return_value error_headers = [("Connection", "close"), ("X-Error", "Auth-Failed")] mock_conn_instance.getresponse.return_value = MockResponse( status=404, reason="Not Found", headers=error_headers, content=b"Not Found", ) with self.assertRaises(ProtocolError) as cm: self.t.request( host=self.host_url, handler="/MISSING", request_body=b"", verbose=0, ) self.assertEqual(cm.exception.errcode, 404) mock_conn_instance.close.assert_called_once() def suite(): """Returns a unittest.TestSuite object for the module's tests.""" loader = unittest.TestLoader() return unittest.TestSuite( [ loader.loadTestsFromTestCase(SSLTransportInitTests), loader.loadTestsFromTestCase(SSLTransportRequestTests), ] ) if __name__ == "__main__": Rand.load_file("randpool.dat", -1) unittest.TextTestRunner().run(suite()) Rand.save_file("randpool.dat") m2crypto-0.46.2/tests/thawte.pem000066400000000000000000000027721506746742300165510ustar00rootroot00000000000000-----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.46.2/tests/x509.der000066400000000000000000000014761506746742300157530ustar00rootroot000000000000000:0"0  *H  0O1 0 UUS10U California10U M2Crypto10U Heikki Toivonen0 250422145027Z 350420145027Z0D1 0 UUS10U California10U M2Crypto1 0 U X5090"0  *H 0 ʘs$G>PH:ͬ\̟sʇS5O=]y¤ ==d CR Ux'W/2# )сٯX]@˩9[ۥ wI7b^SOLMgZ]DYt}+ʃuazYFTkexthV^YRϋ$6_Ud(Sj|.B(Զ{)z}Q;qb"C,0*0 U00Uհ@Ρ+{] )m0  *H  Wl;XE\z؉[CNdg AslS}R0VKVBRzߥQ9OXƵMM"fY"GBWޓbyd"U[O v:] {%2VoN М=x(h`bRƴP;d')J}f)y*Mh(y3e+ 3),̢)oqE"im]ٗu o%X"6Pm2crypto-0.46.2/tests/x509.pem000066400000000000000000000131721506746742300157560ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 2 (0x2) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=California, O=M2Crypto, CN=Heikki Toivonen Validity Not Before: Apr 22 14:50:27 2025 GMT Not After : Apr 20 14:50:27 2035 GMT Subject: C=US, ST=California, O=M2Crypto, CN=X509 Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:ca:98:73:24:82:47:8c:3e:8e:50:cd:c7:48:f3: 3a:cd:ac:5c:1a:cc:9f:16:c7:73:f7:ca:87:84:53: 35:fa:1b:ba:4f:e5:f6:3d:5d:db:79:c2:a4:fa:b6: f5:85:9e:bc:c0:11:a5:0c:f4:a0:3d:89:3d:64:0d: c0:43:ee:8c:9f:8e:52:0a:55:e2:b3:78:00:cf:f3: e9:fc:b5:27:8c:57:b7:2f:ab:a2:32:ec:f7:8a:f1: cc:23:ad:0a:81:29:d1:81:d9:af:a8:e5:58:5d:40: cb:a9:9c:ab:01:39:5b:a3:df:15:94:db:a5:ba:d1: f6:d3:18:09:d5:f0:8a:77:8e:88:49:ef:37:62:b6: 5e:53:4f:d5:4c:4d:b6:67:8b:5a:d3:d6:5d:44:59: a1:ff:9a:8d:74:7d:ba:e2:88:d9:02:2b:f4:ca:83: c9:75:12:61:06:f7:bd:ef:7a:59:46:c5:54:c2:6b: e4:cd:f0:65:eb:f8:78:a7:a9:d2:74:ab:f9:a5:a1: 84:fc:87:a2:00:c5:dd:68:90:56:5e:59:b4:86:86: 52:cf:8b:1b:a0:24:36:5f:55:c1:64:28:53:6a:ac: 9b:7c:e8:9d:2e:42:b4:84:c6:28:1c:c6:d4:b6:7b: 11:29:dd:ca:7a:7d:51:3b:fb:9e:71:62:ea:22:0e: 8f:43 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Subject Key Identifier: 1E:D5:B0:40:A0:8C:9A:A3:CE:A1:FE:E7:2B:7B:5D:0C:29:B4:F4:6D Signature Algorithm: sha256WithRSAEncryption Signature Value: 92:57:6c:3b:58:94:c7:45:5c:c0:7a:06:d8:89:ff:af:5b:9f: 43:4e:fe:95:de:64:8d:b0:e2:67:ba:85:82:20:84:41:a8:73: 6c:f2:01:17:53:7d:f7:ff:93:52:30:56:ac:4b:fa:99:56:d7: 42:f6:52:1e:7a:df:a5:d5:ec:cb:f2:a1:05:ec:be:51:86:39: c9:4f:d8:fe:58:c6:b5:4d:4d:22:66:a9:aa:59:fb:22:47:99: 42:9e:c9:1c:57:d7:de:93:8b:ef:62:f4:79:64:9c:f8:18:9f: ef:22:b0:55:5b:4f:0c:cc:c4:15:76:3a:5d:20:06:7b:ea:cb: 25:f5:32:93:fd:c6:56:6f:07:8b:4e:20:d0:9c:c6:07:3d:78: 28:68:60:d1:62:fb:f5:f7:52:1f:b5:c6:b4:d1:50:08:80:ee: d4:c3:cb:3b:19:03:64:fd:27:29:e6:4a:7d:e0:66:84:f7:92: 06:29:79:2a:85:be:c5:4d:8b:a2:fd:68:28:f5:79:fa:e5:90: df:06:10:a7:b4:9f:33:65:12:2b:80:0d:01:11:fa:33:bd:e4: 29:0f:2c:cc:a2:29:6f:71:45:aa:22:f5:69:bd:c5:e6:cc:6d: 5d:d9:97:75:f4:0b:b5:c9:08:f6:05:c9:6f:80:25:82:58:22: 36:82:c5:50 -----BEGIN CERTIFICATE----- MIIDOjCCAiKgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJVUzET MBEGA1UECAwKQ2FsaWZvcm5pYTERMA8GA1UECgwITTJDcnlwdG8xGDAWBgNVBAMM D0hlaWtraSBUb2l2b25lbjAeFw0yNTA0MjIxNDUwMjdaFw0zNTA0MjAxNDUwMjda MEQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMREwDwYDVQQKDAhN MkNyeXB0bzENMAsGA1UEAwwEWDUwOTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAMqYcySCR4w+jlDNx0jzOs2sXBrMnxbHc/fKh4RTNfobuk/l9j1d23nC pPq29YWevMARpQz0oD2JPWQNwEPujJ+OUgpV4rN4AM/z6fy1J4xXty+rojLs94rx zCOtCoEp0YHZr6jlWF1Ay6mcqwE5W6PfFZTbpbrR9tMYCdXwineOiEnvN2K2XlNP 1UxNtmeLWtPWXURZof+ajXR9uuKI2QIr9MqDyXUSYQb3ve96WUbFVMJr5M3wZev4 eKep0nSr+aWhhPyHogDF3WiQVl5ZtIaGUs+LG6AkNl9VwWQoU2qsm3zonS5CtITG KBzG1LZ7ESndynp9UTv7nnFi6iIOj0MCAwEAAaMsMCowCQYDVR0TBAIwADAdBgNV HQ4EFgQUHtWwQKCMmqPOof7nK3tdDCm09G0wDQYJKoZIhvcNAQELBQADggEBAJJX bDtYlMdFXMB6BtiJ/69bn0NO/pXeZI2w4me6hYIghEGoc2zyARdTfff/k1IwVqxL +plW10L2Uh5636XV7MvyoQXsvlGGOclP2P5YxrVNTSJmqapZ+yJHmUKeyRxX196T i+9i9HlknPgYn+8isFVbTwzMxBV2Ol0gBnvqyyX1MpP9xlZvB4tOINCcxgc9eCho YNFi+/X3Uh+1xrTRUAiA7tTDyzsZA2T9JynmSn3gZoT3kgYpeSqFvsVNi6L9aCj1 efrlkN8GEKe0nzNlEiuADQER+jO95CkPLMyiKW9xRaoi9Wm9xebMbV3Zl3X0C7XJ CPYFyW+AJYJYIjaCxVA= -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEAyphzJIJHjD6OUM3HSPM6zaxcGsyfFsdz98qHhFM1+hu6T+X2 PV3becKk+rb1hZ68wBGlDPSgPYk9ZA3AQ+6Mn45SClXis3gAz/Pp/LUnjFe3L6ui Muz3ivHMI60KgSnRgdmvqOVYXUDLqZyrATlbo98VlNulutH20xgJ1fCKd46ISe83 YrZeU0/VTE22Z4ta09ZdRFmh/5qNdH264ojZAiv0yoPJdRJhBve973pZRsVUwmvk zfBl6/h4p6nSdKv5paGE/IeiAMXdaJBWXlm0hoZSz4sboCQ2X1XBZChTaqybfOid LkK0hMYoHMbUtnsRKd3Ken1RO/uecWLqIg6PQwIDAQABAoIBAFTXuiSYcIkha20Y eDQrND2MyHeqqJccCQtE5DK8vDaVJRWvusrhQvf/VSLvuutt2iLfYM0HpxGOJ0j+ 3z0zqe1p5x6P8CPzhfeQcLWVUc4ar8sFaCRGi7ZC45gvL95+mk/0T3V+Ml6/M2tB AnY9RIzgcEPKJmIR6vllMD1JgltldRvVgIE8hTjphbwrNnieeAsB1YUbriVxaVwn by8skGMLjwJEEX1kxTFGU8NoYK2w718K+2c1AOdh1Sl2uvJtFBYewYGFUgJ+G63R 523500LwQL4x5mlqohYyVRqTvJYT/tNlltIfWE1GCDxBvk0sM/YsgHHp3ACW3Lly PHcBqaECgYEA5AofgANvZ2LHcwIvKZrADUXjovtXoIu9ezghdimpdG73DCtmQhfy YFC6kHjwvBs1f4InLkICdSelcxI06vOmKuOxKNn++4izMbSGNI5NIv4VRqF/nZf5 FdYgHLGQARypjLMz9e0/MyOvLni/Iz2q6DzIQa+Flbob7jcD3qNKZqMCgYEA42+r jzgqm/Ht+oEkqIOGzx1f8asP5sGD3TecJSutxQQ4WGs5roHeWsAj1/IUejlIGnY9 OAe+nICsgWjHUHTYZW7ywYOE1cL3tS94esog3PLZtxzj4ImY9ZMihN49f1N1X24z 9D3mwi1EbHcV17c85kW71tn5El2+o0reEZRD3uECgYEAyojPJ2Rlqp5J5LS47Ku8 DU3YeyXe0wGp3emhlpA0J+xyUQWuwd8A71hkCvLPZVKJNmGDqQsJocH/qW8vPsn9 +LPX4h+T3xWvieL7G2yTyBOBFAVWEcMrgKB4TuPJsaMiV4vGB5OagTIdYhnuMT+R LsjlV6mr7KqqKe4E6tV+vB8CgYEAyuPzx+/zEurfwXkzmqC6wkkSLiTMKq63U8Eo KoCso/T/zuDYtDRmh86gKyRp4B75k6GnOzStdi/TtB4ksEGMSfCP3tHUzlz/XULb 1645YuHCFvhO0R/utCRtxtn7QnrRWjCVaG1QTijTwW76rVVpnoLW7vPEnf3C8yj2 sffyFAECgYEAs+5JbQZuB7O+/ujtuXyZtckSAWYOdVI4uwG9eFgh2b4EQGIRErIh Mx0SUa0Dc/HSM9QJ+ZEQG42O66jC9wA0EZlsjNdYAJVJAnWARWhqDmRyHDLLOwz1 XHdGs9trY2L3jGwKQ/28DX9jCbCeaPF6NOFTvWWjuCi3Sb4ystCBaNY= -----END RSA PRIVATE KEY----- m2crypto-0.46.2/tests/x509_key.pem000066400000000000000000000032171506746742300166250ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEAyphzJIJHjD6OUM3HSPM6zaxcGsyfFsdz98qHhFM1+hu6T+X2 PV3becKk+rb1hZ68wBGlDPSgPYk9ZA3AQ+6Mn45SClXis3gAz/Pp/LUnjFe3L6ui Muz3ivHMI60KgSnRgdmvqOVYXUDLqZyrATlbo98VlNulutH20xgJ1fCKd46ISe83 YrZeU0/VTE22Z4ta09ZdRFmh/5qNdH264ojZAiv0yoPJdRJhBve973pZRsVUwmvk zfBl6/h4p6nSdKv5paGE/IeiAMXdaJBWXlm0hoZSz4sboCQ2X1XBZChTaqybfOid LkK0hMYoHMbUtnsRKd3Ken1RO/uecWLqIg6PQwIDAQABAoIBAFTXuiSYcIkha20Y eDQrND2MyHeqqJccCQtE5DK8vDaVJRWvusrhQvf/VSLvuutt2iLfYM0HpxGOJ0j+ 3z0zqe1p5x6P8CPzhfeQcLWVUc4ar8sFaCRGi7ZC45gvL95+mk/0T3V+Ml6/M2tB AnY9RIzgcEPKJmIR6vllMD1JgltldRvVgIE8hTjphbwrNnieeAsB1YUbriVxaVwn by8skGMLjwJEEX1kxTFGU8NoYK2w718K+2c1AOdh1Sl2uvJtFBYewYGFUgJ+G63R 523500LwQL4x5mlqohYyVRqTvJYT/tNlltIfWE1GCDxBvk0sM/YsgHHp3ACW3Lly PHcBqaECgYEA5AofgANvZ2LHcwIvKZrADUXjovtXoIu9ezghdimpdG73DCtmQhfy YFC6kHjwvBs1f4InLkICdSelcxI06vOmKuOxKNn++4izMbSGNI5NIv4VRqF/nZf5 FdYgHLGQARypjLMz9e0/MyOvLni/Iz2q6DzIQa+Flbob7jcD3qNKZqMCgYEA42+r jzgqm/Ht+oEkqIOGzx1f8asP5sGD3TecJSutxQQ4WGs5roHeWsAj1/IUejlIGnY9 OAe+nICsgWjHUHTYZW7ywYOE1cL3tS94esog3PLZtxzj4ImY9ZMihN49f1N1X24z 9D3mwi1EbHcV17c85kW71tn5El2+o0reEZRD3uECgYEAyojPJ2Rlqp5J5LS47Ku8 DU3YeyXe0wGp3emhlpA0J+xyUQWuwd8A71hkCvLPZVKJNmGDqQsJocH/qW8vPsn9 +LPX4h+T3xWvieL7G2yTyBOBFAVWEcMrgKB4TuPJsaMiV4vGB5OagTIdYhnuMT+R LsjlV6mr7KqqKe4E6tV+vB8CgYEAyuPzx+/zEurfwXkzmqC6wkkSLiTMKq63U8Eo KoCso/T/zuDYtDRmh86gKyRp4B75k6GnOzStdi/TtB4ksEGMSfCP3tHUzlz/XULb 1645YuHCFvhO0R/utCRtxtn7QnrRWjCVaG1QTijTwW76rVVpnoLW7vPEnf3C8yj2 sffyFAECgYEAs+5JbQZuB7O+/ujtuXyZtckSAWYOdVI4uwG9eFgh2b4EQGIRErIh Mx0SUa0Dc/HSM9QJ+ZEQG42O66jC9wA0EZlsjNdYAJVJAnWARWhqDmRyHDLLOwz1 XHdGs9trY2L3jGwKQ/28DX9jCbCeaPF6NOFTvWWjuCi3Sb4ystCBaNY= -----END RSA PRIVATE KEY-----