pax_global_header 0000666 0000000 0000000 00000000064 14655756567 0014544 g ustar 00root root 0000000 0000000 52 comment=25a913ec7867da743bacdbe194b6b5bcc0520437
m2crypto-0.42.0/ 0000775 0000000 0000000 00000000000 14655756567 0013406 5 ustar 00root root 0000000 0000000 m2crypto-0.42.0/.build.yml 0000664 0000000 0000000 00000003226 14655756567 0015311 0 ustar 00root root 0000000 0000000 image: fedora/latest
oauth: git.sr.ht/REPOSITORIES:RW git.sr.ht/PROFILE:RO
packages:
- hut
- swig
- python3
- python3-devel
- python3-pip
- openssl-devel
- openssl
- python3-setuptools
- python3-twisted
- python3-pexpect
- python3-docutils
environment:
CFLAGS: -pthread -Wno-unused-result -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -mtune=generic -D_GNU_SOURCE -fwrapv
sources:
- https://git.sr.ht/~mcepl/m2crypto
secrets:
- nickserv_pass
tasks:
- build: |
cd m2crypto
export PATH=$PATH:$HOME/.local/bin
python3 -mpip install --user -r dev-requirements.txt
python3 -mbuild -v .
find . -name \*.whl -o -name \*.tar.gz
python3 -mpip install -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl
- test: |
cd m2crypto
PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite
[ -n "$GIT_REF" ] && REASON="$JOB_ID ($GIT_REF)"
[ -n "$PATCHSET_URL" ] && REASON="$JOB_ID ($PATCHSET_URL)"
set +x
.builds/irc-send mcepl build-bot m2crypto "sourcehut build $REASON finished with the result $? ($JOB_URL)." "$(cat ~/.irc_pass)"
set -x
- readme: |
cd m2crypto
printf "GIT_REF: %s\n" "${GIT_REF}"
python3 -mdocutils --strict README.rst >/dev/null
if [[ "$GIT_REF" =~ master ]] ; then
python3 -mdocutils README.rst \
| sed -n '1,/
/d;/<\/body>/q;p' \
|hut git -r m2crypto update --readme -
fi
artifacts:
# https://is.gd/Z5VJlI
# - pygn/dist/pygn-*.tar.gz
# - pygn/dist/pygn-*.whl
m2crypto-0.42.0/.builds/ 0000775 0000000 0000000 00000000000 14655756567 0014746 5 ustar 00root root 0000000 0000000 m2crypto-0.42.0/.builds/irc-send 0000775 0000000 0000000 00000002250 14655756567 0016377 0 ustar 00root root 0000000 0000000 #!/usr/bin/python3
import pexpect
import sys
SERVER="irc.libera.chat"
PORT=6697
USER=sys.argv[1]
NICK=sys.argv[2]
REAL_NAME="Commit bot"
CHANNEL=sys.argv[3]
MSG=sys.argv[4]
PASS=sys.argv[5]
assert len(sys.argv) == 6
client = pexpect.spawn(f"openssl s_client -connect {SERVER}:{PORT:d}")
# client.logfile = sys.stdout.buffer
# :mercury.libera.chat NOTICE * :*** Found your hostname: nat2.prg.suse.com
client.expect("Found your hostname: ")
client.sendline(f"NICK {NICK}")
client.sendline(f"USER {USER} * * :{REAL_NAME}")
# :NickServ!NickServ@services.libera.chat NOTICE build-bot :This nickname is registered. Please choose a different nickname, or identify via /msg NickServ IDENTIFY mcepl
client.expect(f"NOTICE {NICK} :This nickname is registered. ")
client.sendline(f"PRIVMSG NickServ :IDENTIFY {USER} {PASS}")
# build-bot build-bot!~mcepl@nat2.prg.suse.com mcepl :You are now logged in as mcepl
client.expect(f"{NICK}.*:You are now logged in as {USER}")
# JOIN #m2crypto
client.sendline(f"JOIN #{CHANNEL}")
# :mercury.libera.chat 366 ceplma #m2crypto :End of /NAMES list.
client.expect("End of /NAMES")
client.sendline(f"PRIVMSG #{CHANNEL} :{MSG}")
client.sendline("QUIT")
m2crypto-0.42.0/.gitignore 0000664 0000000 0000000 00000000335 14655756567 0015377 0 ustar 00root root 0000000 0000000 *.pyc
*.txt
*~
/build
/dist
/src/M2Crypto/*_m2crypto*.so
M2Crypto.egg-info
/.eggs/
/EGG-INFO
/tests/randpool.dat
/tests/sig.p7
/tests/sig.p7s
/tests/tmpcert.der
MANIFEST
*.tap
src/SWIG/_m2crypto_wrap.c
!*requirements.txt
m2crypto-0.42.0/.gitlab-ci-windows.yml 0000664 0000000 0000000 00000005441 14655756567 0017536 0 ustar 00root root 0000000 0000000 # Common steps that install Python, OpenSSL and Swig
.setup_script: &setup_script
# Install Python and Swig
- $CHOCOLATEY_PYTHON_OPTIONS = If ($ARCH -eq "32") {"--forcex86"} Else {""} # Used to force the installation of 32-bit Python
- choco install --limitoutput --yes $CHOCOLATEY_PYTHON_OPTIONS python$PYTHON_VERSION
- choco install --limitoutput --yes swig
# Reload the profile so that the binaries are available in the path
- Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1
- refreshenv
# Print information for debugging
- echo "Python version and architecture:"
- python --version
- python -c 'import struct; print(struct.calcsize(''P'') * 8)'
# Install Python dependencies and OpenSSL
- echo "Install dev dependencies"; python -m pip install -r dev-requirements.txt
- echo "Install OpenSSL"
- curl.exe -o "c:\\$OPENSSL_INSTALLER" -fsSL "https://slproweb.com/download/$OPENSSL_INSTALLER"
- Start-Process -FilePath "c:\\$OPENSSL_INSTALLER" -ArgumentList "/silent /verysilent /DIR=$OPENSSL_PATH" -NoNewWindow -Wait
- echo "Install pywin32"; python -m pip install pywin32
# Print information for debugging
- ls "$OPENSSL_PATH"
- echo "Installed SDKs:"; if (Test-Path "C:/Program Files/Microsoft SDKs/Windows") { ls "C:/Program Files/Microsoft SDKs/Windows" }
- echo "Installed OpenSSL version:"
- Start-Process -FilePath "$OPENSSL_PATH\\bin\\openssl.exe" -ArgumentList "version" -Wait -NoNewWindow
- echo "Python OpenSSL version:"; python -c 'import ssl; print(getattr(ssl, ''OPENSSL_VERSION'', None))'
build-test-windows:
stage: build
parallel:
matrix:
- ARCH: ["32", "64"]
PYTHON_VERSION: [ "310", "311", "312" ]
variables:
OPENSSL_INSTALLER: "Win${ARCH}OpenSSL-1_1_1w.exe"
OPENSSL_PATH: "C:\\OpenSSL-1-1-Win${ARCH}"
BUNDLEDLLS: 1
tags:
- saas-windows-medium-amd64
artifacts:
paths:
- "dist/*"
script:
# Setup environment (Python, Swig, OpenSSL, etc)
- *setup_script
# Build wheel
- echo "BUNDLEDLLS is set to $env:BUNDLEDLLS"
- python -m pip wheel --verbose --no-build-isolation --no-deps --wheel-dir .\\dist .
- ls ".\\dist"
# Install wheel
- $env:PYTHONPATH_DIR = If ($ARCH -eq "32") {"win32-cpython-$PYTHON_VERSION"} Else {"win-amd64-cpython-$PYTHON_VERSION"}
- python -m pip install -v --upgrade --target build/lib.$PYTHONPATH_DIR --no-compile --ignore-installed --no-deps --no-index --find-links dist m2crypto
# Run tests
- $env:PYTHONPATH = "build/lib.$PYTHONPATH_DIR"; python -m unittest -b -v tests.alltests.suite
rules:
- if: ($CI_COMMIT_BRANCH == "master" || $CI_COMMIT_BRANCH =~ /^windows.*/) # Run for all changes to master or branches starting with "windows"
- if: $CI_COMMIT_TAG =~ /^\d+\.\d+\.\d+$/ # Also run when pushing tags for versions, e.g: 0.40.1
m2crypto-0.42.0/.gitlab-ci.yml 0000664 0000000 0000000 00000017406 14655756567 0016052 0 ustar 00root root 0000000 0000000 stages:
- build
- deploy
include: '/.gitlab-ci-windows.yml'
python39:
image: python:3.9-alpine
when: always
stage: build
script:
- apk update
- apk add --no-interactive swig gcc git musl-dev python3-dev python3 py3-pip openssl-dev openssl py3-setuptools py3-twisted py3-docutils py3-wheel
- export PATH=$PATH:$HOME/.local/bin
- python3 -mpip install --break-system-packages --user -r dev-requirements.txt
- python3 -mbuild .
- python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl
- PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite
python3:
image: python:3
when: always
stage: build
script:
- apt-get update -q -y
- apt-get install -y swig libssl-dev python3-dev python3-pip openssl python3-setuptools python3-twisted python3-pip
- export PATH=$PATH:$HOME/.local/bin
- python3 -mpip install --break-system-packages --user -r dev-requirements.txt
- python3 -mbuild .
- python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl
- PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite
alpine-32bit:
image:
name: i386/alpine
entrypoint: ["linux32"]
when: always
stage: build
script:
- apk update
- apk add --no-interactive swig gcc git musl-dev python3-dev python3 py3-pip openssl-dev openssl py3-setuptools py3-twisted py3-docutils py3-wheel
- export PATH=$PATH:$HOME/.local/bin
- python3 -mpip install --break-system-packages --user -r dev-requirements.txt
- python3 -mbuild .
- python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl
- PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite
python3-32bit:
image:
name: i386/debian
entrypoint: ["linux32"]
when: always
stage: build
script:
- apt-get update -q -y
- apt-get install -y swig gcc git libc6-dev python3-dev python3 python3-pip libssl-dev openssl python3-setuptools python3-twisted python3-docutils python3-wheel
- export PATH=$PATH:$HOME/.local/bin
- python3 -mpip install --break-system-packages --user -r dev-requirements.txt
- python3 -mbuild .
- python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl
- PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite
python3-doctest:
image: python:3
when: always
stage: build
script:
- apt-get update -q -y
- apt-get install -y swig libssl-dev python3-dev python3-pip openssl python3-setuptools python3-twisted python3-pip
- export PATH=$PATH:$HOME/.local/bin
- python3 -mpip install --break-system-packages --user -r dev-requirements.txt -r doc/requirements.txt
- python3 -mbuild .
- python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl
- cd doc/
- PYTHONPATH=$(readlink -f ../build/lib.*) make doctest
fedora:
image: fedora:latest
when: always
stage: build
script:
- dnf makecache
- dnf install -y @development-tools fedora-packager rpmdevtools
- dnf install -y swig python3-devel python3-pip openssl-devel openssl python3-setuptools python3-twisted
- export PATH=$PATH:$HOME/.local/bin
- python3 -mpip install --user -r dev-requirements.txt
- python3 -mbuild .
- python3 -mpip install -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl
- PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite
fedora-rawhide:
image: registry.fedoraproject.org/fedora:rawhide
when: always
stage: build
script:
- dnf makecache
- dnf install -y @development-tools fedora-packager rpmdevtools
- dnf install -y swig python3-devel python3-pip openssl-devel openssl python3-setuptools python3-twisted openssl-devel-engine
- export PATH=$PATH:$HOME/.local/bin
- python3 -mpip install --break-system-packages --user -r dev-requirements.txt
- python3 -mbuild .
- python3 -mpip install --break-system-packages -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl
- PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite
leap:
# image: registry.suse.com/bci/bci-base:latest
image: opensuse/leap
when: always
stage: build
script:
- zypper refresh
- zypper install -y pattern:devel_rpm_build pattern:devel_C_C++ osc
- zypper install -y swig python3-devel python3-pip libopenssl-devel openssl python3-service_identity python3-setuptools python3-Twisted
- export PATH=$PATH:$HOME/.local/bin
- python3 -mpip install --user -r dev-requirements.txt
- python3 -mbuild .
- python3 -mpip install -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl
- PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite
opensuse:
image: opensuse/tumbleweed
when: always
stage: build
script:
- zypper refresh
- zypper install -y --force-resolution pattern:devel_rpm_build pattern:devel_C_C++ osc
- zypper install -y --force-resolution swig python3-devel python3-pip libopenssl-devel openssl python3-service_identity python3-setuptools python3-Twisted
- export PATH=$PATH:$HOME/.local/bin
- python3 -mpip install --user --break-system-packages -r dev-requirements.txt
- python3 -mbuild .
- python3 -mpip install -v --upgrade --target $(readlink -f build/lib.*) --no-compile --ignore-installed --no-deps --no-index dist/M2Crypto*.whl
- PYTHONPATH=$(readlink -f build/lib.*) python3 -munittest -b -v tests.alltests.suite
build-sdist:
image: python:3
when: always
stage: build
artifacts:
paths:
- "dist/*.tar.gz"
script:
- apt-get update -q -y
- apt-get install -y swig libssl-dev python3-dev python3-pip openssl python3-setuptools python3-twisted python3-pip
- export PATH=$PATH:$HOME/.local/bin
- python3 -mpip install --break-system-packages --user -r dev-requirements.txt
- python3 -mbuild . --sdist
release-pypi:
stage: deploy
image: python:latest
dependencies:
- build-test-windows
- build-sdist
id_tokens:
PYPI_ID_TOKEN:
aud: pypi
script:
- echo "Built artifacts:"
- ls dist/
# Install dependencies
- apt update && apt install -y jq
- python -m pip install -U twine id
# Retrieve the OIDC token from GitLab CI/CD, and exchange it for a PyPI API token
- oidc_token=$(python -m id PYPI)
- resp=$(curl -X POST https://pypi.org/_/oidc/mint-token -d "{\"token\":\"${oidc_token}\"}")
- api_token=$(jq --raw-output '.token' <<< "${resp}")
# Upload wheel to PyPI authenticating via the newly-minted token
- twine upload -u __token__ -p "${api_token}" dist/*
rules:
- if: $CI_COMMIT_TAG =~ /^\d+\.\d+\.\d+$/ # Job enabled only when pushing tags for versions, e.g: 0.40.1
when: manual # Can only be triggered manually m2crypto-0.42.0/.keys/ 0000775 0000000 0000000 00000000000 14655756567 0014437 5 ustar 00root root 0000000 0000000 m2crypto-0.42.0/.keys/openpgp/ 0000775 0000000 0000000 00000000000 14655756567 0016107 5 ustar 00root root 0000000 0000000 m2crypto-0.42.0/.keys/openpgp/cepl.eu/ 0000775 0000000 0000000 00000000000 14655756567 0017442 5 ustar 00root root 0000000 0000000 m2crypto-0.42.0/.keys/openpgp/cepl.eu/mcepl/ 0000775 0000000 0000000 00000000000 14655756567 0020542 5 ustar 00root root 0000000 0000000 m2crypto-0.42.0/.keys/openpgp/cepl.eu/mcepl/default 0000664 0000000 0000000 00000021424 14655756567 0022114 0 ustar 00root root 0000000 0000000 -----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBFcgpa0BEAC81pv//PpHxEajKRInydtdCrMXUUH7mG7f9crFnz7RQ406hdZg
11v4gBdCtI2FP1600TTssUniYbReHywdmvoMX43Ow5gCSCOT1xLkvnsWtFKUIBLh
0FDg5Y+XAlAmhnv9/OIWnwNlV7U4Bmek8TYmFGg4nVASiSAsqnlfaBkVRxeBFfI2
Oe8617WdvEULqdV8T4vLDeLAHCC0BHwVLKLpIZw4c/mlOjTLgTz5maJVjI0/8RQH
Eb4dwBaVpIvFSjUo4TFPaPynPTAlTvbvvEl05j0LHUYGncbLzxAJKvY5Ubr6chN4
aTkeZLoycoqr9Q3rIXMatkxYZPaOGQkjfDB01b3ZMK8pkkhyfDHuCmJjzIYAN/s0
lTIYfklzXkrG+k9PEA8v/cXzOKGtZ+Zzdz3YdbSrVVNJEUixptkFrmMG0+h8Dfxi
4EjHvihT9+vlcm0IK7/M3tLyy9IA28yKPKLwRf1cDni+9+MJytKlR4r3e/FHYJeO
2diI0B3wclxKZYxjPVBu5MvZ6+0gOt8w/oH/yC+o+EYeKAf8IlOPTQY4TVV4uJZS
O800UWu/qd+UbZSbZ7jbyq6m8gtFjXVO9YFpZQV8mpOIM3h4q7NMa2J88xezRSWC
HGrwk9so+Gdf59dRePcrvQehrrplWmyyZXygwNMYQbn0nSyfP5s1tHc5TwARAQAB
tBtNYXTEm2ogQ2VwbCA8bWNlcGxAY2VwbC5ldT6JAoYEEwEIAHACGwMCHgECF4AF
CwkIBwMFFQoJCAsFFgIDAQACGQEWIQQ8dqAnykWtcJi1vB15IFgCiAvJ2AUCY3M9
TTQUgAAAAAAQABtwcm9vZkBhcmlhZG5lLmlkaHR0cHM6Ly9mbG9zcy5zb2NpYWwv
QG1jZXBsAAoJEHkgWAKIC8nYfmgP/3A8mtVxEBHM8YjdPVgdYIFUtycFHAiZVwk6
L8vOYCztkfe15Tf9iiz1VmQljw72hfycsi/m348uIv0pzLVEp+YeJ7NWFqYkefT/
QQdpwv+f9g2mcMtGrFTFAtIb8HCmnloI54LpmYfr5xEOUwPl6PKT4UbngcrL4x49
OqBdW2gelz7R3iAirWp/72phTV5f27njZJ6M26P9l2gYcD+5zOshumvhpTRs2jIq
KR1b3IQHD+sVsmdKKRIDro4Qo6VqMoR51h3GvZ4L4SLhS9/J4mrkQfzKUtsF6cvo
6Yz2Heiv/awYTd2llOHPOzx2mS0azhi4yFpC3qznsRUI9rXvwmwV/oMWcZvADTbJ
7X//RaZia95KoXEVblA04dbHrQD0e1nJRUmJNclVxjX+Z8nR5HhczEqTqSQ929d0
+yvpuU052kRB7q2pXwvmaBS77Gz64HK4hWFeSDL3vzwdgYauVlUFPGiBIad+F4S/
ejCU8MkYw+3GuKpc9DsLbE4N7WCcp4O4I1Cp6UNqtXERmbyVZTe7iHK0fe6XTxRv
akzh4uis3uheDUHJkm4GNe1YCeec9pKMF9rwhfwa1l1S57zVZtzl1k0HKq5v8ANj
nYoS8A4XNf0fN7/RMz+ILopVncMDo8wV7E66VIeZzcZWW9Js+hCIB+K2ltY+qHaQ
nUNTb9K2tB5NYXTEm2ogQ2VwbCA8bWNlcGxAcmVkaGF0LmNvbT6JAjYEMAEIACAW
IQQ8dqAnykWtcJi1vB15IFgCiAvJ2AUCY2Zb3gIdIAAKCRB5IFgCiAvJ2KOlEACS
BT4WfecoP13LKBbkgAM1IzAvntBxeI4PEBOuFSqO9dOmA8ucf+zaG9w6zBucKbQf
ofOQuQYLV+DqoUCeryYv602Sq4NsqLQEZVUUVo1taR+EYCo24nGhap6WasdZMr+K
B6o+WXJICBF7KuXHzrHGiF3vb3W1ssBwJD2yc0CTFP2K3RLBMOnzvk/itxVa6ITp
Rq9R4EgC0WWOLEjhV1S+8UQ5Rb0fH5u/1WbWBYLvo22nrwaAdFRHPREppMs950HQ
9MY+3s53yFiw6nNtAL4N9Dg1aVkCQku/brH7dFTcvS5TocXHn6qkqPf/dyp2/LN/
jrHQfUX+3AC/BLffbJTr4Bznhmgg2Th5Cs9JYT2J6OkKIx6aEDzxJNrPW952R9I2
jin+7CFGwJBYz6nMacJ6+Pn7hi+a1zI9xX/cQU0wRnAhr/8ddxqnTCRLq9enP9oG
QoUmEylxrTKxuQ9bd245aGNau/CIWlGghgcrjpAoYLAw0Ukd1XxCcsGFL4IbK3Q1
049ynsjIDzLspbfDRd3W0VYyLjZ7PiF3fhFUkZrS0ni0ZRC41fBSC279NRchjcqY
aQUy3E8UOoCNS4HmQUdpM5An3Qo3jL5zXPsxLF9XuYStkXQsoUNNfhS8UpAikHfx
TiXXGaDGKfv5iyhNl7Bida/uFcKLq1HIP3jo960CMrQdTWF0xJtqIENlcGwgPGNl
cGxtQHNlem5hbS5jej6JAjkEEwECACMFAlcgqUkCGwMHCwkIBwMCAQYVCAIJCgsE
FgIDAQIeAQIXgAAKCRB5IFgCiAvJ2L1ED/wONwIPwD6S8e+aNRd7ZHwqv4IH2Ofp
+vukr0CTNJqdt3pw9GhIsIrJ0+29Loe0W/Wg8jqClO8vlzFrbudbbNBG214tTNKJ
v7+FwRSrJaHB+/FTg/78+qvs6zdR7/q+k3kBiOc47eNJV3vFuUJ2zwQeunEkPfyo
RK7+Sag0VUNgHwwRdjYQzXizr7i+2xMcRyEpfosR6/mOOaA+NzAs7SZQyRs+g9U9
qDPA4vyM7PYurVMkLSZ5IYJYovuFKvBkFwi2KndQ79ZfEo25/K3q67bH7w46dEta
+byAgq88gwy61VuYaKZP2fCECeIcAs3UeDiX2pgL7SRqaY9NCfqgGgLK2V0BuaHm
PaUcN2vGoq1NzEHC2qZzsq9mMf/GhZQdIfiX0NW6luJKlntvQa/wi0obvAPQ3eHO
NJrjgsrfDCFaihwx8YRxNWq7W5q3Rxtxheq3zSsWCeBB1/Ys3kCTRzv8hdrfdbZI
Ew+INGrWfCFSzh0bDY1ZOLmUm/tt85qLuvlcF4IJwNEZ+hpvkbzQCfjugcpzpdKu
3TsrJoZBQvMDZJ5QnHp4AuQZqDz87OPVOaYYmS13tNEEEMy0Hqt1EOu1d9zNjm4u
4r3i5BKJBEXA66qdxqKBTklJjLbnTsvxURlZqqZGxLLsI1LALbbmnF21POUXew1Z
7f48IwNJsx31VbQiTWF0xJtqIENlcGwgPG1hdGVqLmNlcGxAZ21haWwuY29tPokC
OQQTAQIAIwUCVyCphAIbAwcLCQgHAwIBBhUIAgkKCwQWAgMBAh4BAheAAAoJEHkg
WAKIC8nYZawP/3n6cvEJenA+mhr1f7nlFLWNk2EWrI3HSmPW9r3S+mr4phruKQmF
KznlJbpoSK8ppYhUkjcXxgi5+8ApLtcQjSFwAY0HXzwY5kK9sohPyAx8s8kOBYnV
faTi/MpQM27/+RXcUDAeQuVOhI/nx10unbCTyT7mOnHmO8h/L+SYsoFLMMJSqYeH
aBdse+iHvLQ7Dx9a8nmO44RGMRJ9HG89plfqVZo1v23Mqxvd9TYz0KLy1aGmaqBT
TCBAZrdLgAOKY+QXGeLJxFDi8QndyhtBo/Upp8v44L8E2ugVOLs+lc6cdLlyNJUs
rvoqKrAaLkjc9LMXTBDci93Bzg5gwV+ipq+hDBm/jj3WfUUPxowLoWzsfmhxM21U
LEyo5tu7AAXqimkcrWiirKQUP++REVsSWOSxeETJgeJ8XQmH+9lfbULt6cwQUpTH
3WZuVua8HA8hR1hOa1FhxhvOWG1S2zmJXI0ouNRCkkP7YV7Z0tlZ81X0ZtQGLFI1
5uMWLPm29L2qQgpac5tR1mgLvxZReJfyMSLRRfnpLbiCDSBzaVRhY4UwEiPoksgl
lGTKXFOtivc09ReG8+9knAJy6ERxMDo1ltczkvpYI9wHSznf4t+NQlEeFkkrnLRV
lXBDT8n0SkBpWQW37GdTZy9yE54lFAWe83cMqa8Ii37oFPGUsfK49lvCtB5NYXTE
m2ogQ2VwbCA8bWF0ZWpAY2VwbG92aS5jej6JAjkEEwECACMFAlcgqZUCGwMHCwkI
BwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRB5IFgCiAvJ2ERsEACWrK2NMHBTaYw7
tHRrkja4xwnj7qWjc0gO3zb5k+QQIjAYcfV22HZUJo6TjmjvD0/D1FjWQvj/dMOi
5vA+vhT6WtiOVgNYONpkcwPjZEZ9+svTC0Ry5fqnF7UbN44FzS9HNhWG/PBH/28T
shrKgMBNkCQlQ+dLma6pugjf/U3Dzixz0curvp6unV14Cp9lf8fbYvxtc/JvGYPS
JMMivo9vYXToREq5y7AHyvNv6jAQY9K3bnKrrBjVJ7jnwd+kvsrAp/SymOqX8rFU
Fq7w+TPDbI0PURdeDkuBJCtWblhn/bPtfTuecr0OHgFZ0C6Hs+ZBb8zlN48ISQxP
4ZumnbGdYEGcusXVS6odobYEIhcXpD5v5TUpTQda61kLJOJOXqXLVMcCGBXZnhaA
h1RHuILM2rm0XytXg7cb/ByXjQ70rQSPWBc8IVweX4Zp1Y6rg0+eVhNKVyn8GhgG
oto3iw2xLYtoCb9Bm9TsFa5Yc+eiQnRdHCh+z75T39hrTH7hAmTDzp//6sAM/kjX
fcCvYKT+qWupO1yRjIO6J6nilVytJ0XeruZxDyrcasVOt4WpzoOHAYFJbUfkLSHC
5G0QoAiD7vR1QhkqkJX0gufONi5nNU2DWo0gChR15O8umctsLOI0XDb5SJCmHWco
ogINtmNJKdrRZi3WeTHRYTjmlX8wj7QbTWF0xJtqIENlcGwgPG1jZXBsQHN1c2Uu
ZGU+iQJRBBMBCAA7FiEEPHagJ8pFrXCYtbwdeSBYAogLydgFAmNmW1MCGwMFCwkI
BwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQeSBYAogLydhS7RAAnJSCgWvA7S1k
kwGr2XmLMZnuBc4pgxdJ3nCCip+92NXXduWuu59eaFLx2s7Qmvlfe+Tbf7Tx9thT
grAcVUg0P7bFpJAy86KxCZUzIR4v4QHdgrxV2/I4oJWsB21LiB24wsRVM/ODqSsU
GCXrVhbt9x8l/E5GghpzERMQLtRUYNTlNq+xaz/iLNnRGg8x9J30cpua62YOnFXo
oHCDc54O3SE1MZEwieVCuQ+J2MDp5XBGk7iT89EphcbIXfdpGUNlk6AEAeEAFAGP
trMTrzLUvjqZ1hjvjzTaEck/TFfCNSRrfESI7xSsitlX/Hnm+L9v9BLuzcsqxW1k
pDmR7y45iGEbFO3gkQIojguJoF2v943zSfRiyxQeGi60tYmg6MOlApj/GwMxCMmM
Gn1j+G2DW88oCOOsPMv9pmnU7vkrgHlim7g8iP4gPR17rQYMMqj7Oy74oAR7aQ5V
lGFT8VyCqXUcUxBGAiYF6dwEd+cBJbr1Bj3qKfC2djg1iSPkCQjWaWJ0aEy+RkL6
kwnN0QnwZOGcWKoVabGZshTgstYRW2msn++wE8Z//wlcA9vbVPNQXMM0okseBOEj
IvSmuezqNVXhisCiNTHAiaRrICd5cvTMJ5OYhvu9Bt73LNHUNVm+m5fBzmFlgf79
4r2YqwzO8BkzSmdyYHWz/8PRq6LNgce0HE1hdMSbaiBDZXBsIDxtY2VwbEBzdXNl
LmNvbT6JAlEEEwEIADsWIQQ8dqAnykWtcJi1vB15IFgCiAvJ2AUCY2ZbagIbAwUL
CQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRB5IFgCiAvJ2BkqD/9MrzLKaLtx
FQ6e+KedhLetWDuYopCFUBo/+hM1ZgLVLm/FKSdg0Idjz9bQ7K34pabOqtpHsnKP
th/Qa0TZ9tJnUuM5JqZ6rCk5tpF0TmsVSND8oaGLwDsAjUavQ02XbuUjsmyLmY+8
X8WCi4TQ/FmFO5Q/9v0O0HZK+O0e4ndEy1S9LfXATu3xIpxwIuuHDflN6PEqzWaR
QTcbX05yvjoMcanzkJk+enzJreGC4xtNBAFpp2eZp5//QUTlEzd3DAp6s6/lkNVu
as+eZqJVxliRiHDgtqaudv5mphM/59IMvcUaKAwJKeba0Xv/tDTnhNWX1/qPC0Hq
9An2T2c4E4NligbeezB+yMFvTFRwsgZF8vEmlRQ6hgtG5HJTlYsysdi6S1Exfwkv
iWKfr1T9XQ3VLv6C0Vm9HI7YRDzea5YwJ4puHCrrE5UVUmhFVWqVZioBeirT2AbE
slBZmCy+NUO8lmssKytCY00rwd+BdrCGBibViqB9GJghC8hUb9/FEmE1zSa5PHeE
9UuYV6kiuyodj/xXwj6EztXh1S5ywxOOwD/m9p/GMHW+sRWIdOe4qE1kqnonlcg2
YqVauNu9ZxUhdhN37ca3h2xxjjcmKA1IaMIrmNsQ0CFzVmW/aUZLY+CDjiSPKj3j
aDyfvfLT0Nps5/Ep2kbByQWlEqCFnn6aE7QbTWF0xJtqIENlcGwgPG1jZXBsQHN1
c2UuY3o+iQJRBBMBCAA7FiEEPHagJ8pFrXCYtbwdeSBYAogLydgFAmNmW3oCGwMF
CwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQeSBYAogLydgsoQ/+KZLiYn0S
g5J5nLd5DjqR4TfJDdDx/uGWLeLn+5xn4aP15Bs6dkwwM5F2C9OYN6H+RBxUxfsy
6N9L0yjutxG6xO7Y/eAayKPD/nDakUyTkIZJ1Ga28hOuLMtfJDF5CygHPPAg+dBG
XJynE+YaaMY2E2T4ftV21UDqssrCSLn5Xltdvlf5B0DGUQgcqxdwrQVFIHLSVCbC
aVc/QM3D5rzvEjvwCvSgfrQNLJOubEh8GXNVpFFr6L+NnbGPlBYy7/pZCqp6iBmW
Zqj0UAXHJGDmvYor4kMtLoWl3WHt8MI2AZE54zupoxif3Cf5r1r5eICJzI+nDjHp
kO/O5SlcSHI/eD87oJlnZhZe2jX9GBGgsG45iHvmAtL1qET58gSdOfmHFC1DvkzL
RiTO2rHJ8pd457a0we0SGzfvIHUry0HZfH1RS2YmvnM1e84oE5h1hbn4cu/1bFZd
LwJyPZVEiUyEpc2pwFTSY4FRD14+PQWGgte6neNY0DiMKYkii5QdJ4kKedPWtRXR
AnTO49DmUFQWum4P8UWO65YGE7MZ8smIGU2L0BGWIKY13qaHcJRj7LRnJbnDxKpS
AVxv2ytXB1xIDOUc+dkEIu/8E9l01Dz9e96Zq/crZdngzwsd3/JORn9FSbCaORdM
GMkekQ9xnLClIMDBMw9eQo+sJ5ogKmlqcBS5Ag0EVyClrQEQAK0YMh0hX/ZBuxTJ
KsxsuwZG+blEw70tiCh/vAnWuoTyjkkL8h1IDLmoTvqVtzT4Ho+RQKIMpit/llZH
OaGgtX2/FuxJmK/Ai4MmODq1Jyqsm8e7KzodvVkFQjlB2E0eY37ChD/LdXq4JWLT
OYrknX1PSev+PtYay4qXlB8VVhcn6qR++rKB+w/uvmJKQl1V1EGB02Pt1wUwfawK
Kf/tAdjmI9muTxeKYugWelmDb2X2W+LKs+GrpjJ1yCzq1qqNmxQM0pYdRKCA9nJN
H80AZPFHN+NFqiYZmxPmeZP4TdGzZAUwYIoU0PaSX0gpMP7t5rw8RiWB894iW6o8
LwrX6FVOw4cgNDK2o065vSzOHinQLRkbKXNKDX8fZuSv0afpGflmBCJXAek1R6cV
B0T90ZWMT8lUbDf6ThgPDZ1BeRSg80Y5JfTODJAsnoD7qn2wux+v+v0fGPw2xmvD
NBLMQUmaeJ688Bv1CfBIYPXclpCKq2fdgpAxkho3aT/sywgayDWIqWYawKUNKZ7h
zmkrnreOKaDFjun5bSlqH7i/7Z9cMMsgpYsHsSaqr6C6O4cFQ7EIsLNo3gldnV74
0Xo+uYw9XAVLJj2nFGzkpJqmMUMBfACp/7c1zXMFX3bLslqdMzt94PRT74eZtMwG
PwXEhEW0ZJIQRGnaPjs12XvEJn/tABEBAAGJAh8EGAECAAkFAlcgpa0CGwwACgkQ
eSBYAogLydghBw/+IbPaGbq4ZiXxvy6ZuroV7+Ja+8ck2ToUn6FGSfIpwc9S1Dbe
RbF5pUp9xCzxk8aCVuXHp38h3Bip1MGJAZ8OKKed5yvmuBsdVHUm9ChAIk7zxP4m
J1t7jzIIlXAJwlta+6RBsa1tV7Mb7dGbSsEFknknS8+qzPeJ1r2MlRtyhZEbbI2w
Z8X2ReXLfDJFvShRW1CyBCqIWBtsIh6t/h1Ar0yTAr/lL92rXFAPZTJtSUcQJnAk
+sOPgHhDCIXv0fDTwxtvdR/u/Mp9aST4I81lfqtPDSwGFQzZOsPUPDeedOwHHH29
uB5aiYdPbph+veSp+YP8i8G6GgCi+z71sUHM4VzCb6earVdcoNRMSvrXPFDkuWfu
V8ffkFBU69tc5ltxvKEw9IA9m55Xk8iplLut5I+6jRFlKZ6fgVWvFDE1sRtfMdCn
p97ZH6CAwYcGDA5RxD1HU3htbB4TH6nJPTHvuLLwJSR6uyzBakvLB3nf6yP5IfOV
N7Bpkt+Mqcc/UsY41yHL3ktAsOPA+48jqFNCyNDRRe8agILZynagRCvnKLdHnssH
+5lJmH+kQepUpsSGqUUwfDadrICy5T1oUvjqn0crunlBNhcGiaqwaLUikR3trZNb
Rjqet+gtd09sVS4yqapFbwpPIXzONnB8rNcB066eA1e+k2RqtabpH9mrN7M=
=/S9/
-----END PGP PUBLIC KEY BLOCK-----
m2crypto-0.42.0/.readthedocs.yaml 0000664 0000000 0000000 00000000717 14655756567 0016642 0 ustar 00root root 0000000 0000000 version: 2
build:
os: ubuntu-22.04
apt_packages:
- swig
tools:
python: "3.12"
sphinx:
configuration: doc/conf.py
python:
install:
- requirements: doc/requirements.txt
# The autodoc generation needs to be able to import the M2Crypto module.
# Since this is only possible when M2Crypto is fully installed (after
# the swig bindings have been generated), we manually install it here.
- method: pip
path: .
m2crypto-0.42.0/CHANGES 0000664 0000000 0000000 00000105413 14655756567 0014405 0 ustar 00root root 0000000 0000000 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.42.0/CONTRIBUTORS.rst 0000664 0000000 0000000 00000003465 14655756567 0016105 0 ustar 00root root 0000000 0000000 * The original project was created inside of the huge `Chandler project`_
where it was mostly work of Ng Pheng Siong [#]_ .
* Then for a log time it was maintained and extended to the large part
by Heikki Toivonen.
With 247 and 415 commits, respectively, these two first maintainers
provided by far the biggest amount of work on the project. Thank you.
* An attempt to restart the project was made by Martin Paljak. Although
his effort was most mostly discarded in the end, all his suggested
changes were reviewed and some of them incorporated in some other
form. Just two commits of his remaining in the tree hugely
underestimate an effort he made to keep this project alive. Thank you
very much for your work.
* Plenty of work on keeping this project alive was made by the
maintainer of the package inside of RHEL, Martin Trmač. He also helped
a lot by advice with this last effort to revive the project, and his
pestering me to do proper small commits rather than freaking dumps of
my current thoughts helped to make changes to be made a little bit
better (and revieweable).
* This last hyena-like effort to revive a dead carcas has been started
by Matěj Cepl.
* I got a lot of help especially with reviewing patches from Hubert
Kario.
* Craig Rodrigues didn't loose the hope that M2Crypto could be ported to
be py3k-compatible, which lead to the renewed effort to do so. He also
helped with plenty of patches in this effort.
* Casey Deccio helped a lot with fixing EC module.
* Remaining contributors could be find in the output of ``git shortlog
-s`` command. Thank you to all.
.. _`Chandler project`:
https://en.wikipedia.org/wiki/Chandler_%28software%29
.. [#] His and everybody else emails can be found in the git log,
I won't make spammers even more happy to collect them here.
m2crypto-0.42.0/INSTALL.rst 0000664 0000000 0000000 00000014330 14655756567 0015247 0 ustar 00root root 0000000 0000000 Installing M2Crypto
===================
.. contents::
Pre-requisites
--------------
The following is required to *use* M2Crypto (once installed):
- ``Python 3.6`` or newer
- ``OpenSSL 1.1.1t`` or newer
To *install* M2Crypto, you must be able to compile and link C sources
against Python and OpenSSL headers/libraries. For example on a Debian-based
system the following packages are needed:
- ``build-essential``
- ``python3-dev`` and/or ``python-dev``
- ``libssl-dev``
- ``swig 4.0`` or newer (for compatibility with Python 3.12, for
older Pythons the default platform swig should be enough).
Installing on Unix-like systems, including Cygwin
-------------------------------------------------
(not tested and most likely obsolete, updated information for building
with Cygwin are welcome).::
$ tar zxf m2crypto-.tar.gz
$ cd m2crypto-
$ python setup.py build
$ python setup.py install
If you have installed setuptools you can also optionally run tests like
this:::
$ python -munittest discover -v tests
This assumes OpenSSL is installed in ``/usr``. You can provide an
alternate OpenSSL prefix location with --openssl option to
``build\_ext`` (or ``build``) command. So, for example, if you
build your local version of OpenSSL and install it with
``/usr/local`` prefix (your includes are in
``/usr/local/include/openssl`` and libs in ``/usr/local/lib``),
then you would add ``--openssl=/usr/local`` to your ``build``
command.
Differences when installing on Windows
--------------------------------------
(Python 2.6 is not supported on Windows anymore, please, just
update to 2.7 if you want to stay on Python 2)
(needs updating)
Before building from source, you need to install OpenSSL's include
files, import libraries and DLLs. OpenSSL 1.1.0 and on are installed
by default in ``%ProgramFiles(86)%\OpenSSL`` (32-bit), or
in ``%ProgramW6432%\OpenSSL`` (64-bit), or as a last resort, in
``%ProgramFiles%\OpenSSL``. setup.py will look in those locations.
OpenSSL before 1.1.0 doesn't have a default install location, so
you have to specify its install location explicitely.
As with other platforms, you can specify a OpenSSL location with
--openssl option to ``build\_ext`` (or ``build``) command. For
example, ``--openssl=c:\pkg\openssl`` would specify that the OpenSSL
include files can be found in ``c:\pkg\openssl\include`` and the
librariesin ``c:\pkg\openssl\lib``.
The '--openssl' option will configure swig and the compiler to look in the
default locations for headers and libraries. If your OpenSSL is installed in a
or you want to modify the default options run the build_ext step with normal
distutils options: `--swig-opts`, `--include-dirs`, `--library-dirs`, and
`--libraries`.
MSVC++ ~\ :sub:`:sub:`:sub:`~```
setup.py is already configured to work with MSVC++ by default.
With MSVC++, the OpenSSL pre 1.1.0 DLLs, as built, are named
``libeay32.dll`` and ``ssleay32.dll``. The OpenSSL 1.1.x DLLs are
named ``libcrypto-1_1.dll`` and ``libssl-1_1.dll``. Install these
somewhere on your PATH; for example in ``c:\bin``, together with
``openssl.exe``.
For MSVC++, the import libraries, as built by OpenSSL pre 1.1.0, are
named ``libeay32.lib`` and ``ssleay32.lib``. The OpenSSL 1.1.x import
libraries are named ``libcrypto.lib`` and ``libssl.lib``.
MINGW :sub:`:sub:`:sub:`~```
.. NOTE:: The following instructions for building M2Crypto with MINGW
are from M2Crypto 0.12. These instructions should continue to work
for this release, although I have not tested them.
Read Sebastien Sauvage's webpage::
http://sebsauvage.net/python/mingw.html
For mingw32, the OpenSSL pre 1.1.0 import libraries are named
``libeay32.dll.a`` and ``libssl32.dll.a``. You may need to edit
setup.py file for these.
You'll also need to create ``libpython2[123].a``, depending on your
version of Python.
OpenSSL pre 1.1.0 DLLs for mingw32 are named ``libeay32.dll`` and
``libssl32.dll``. OpenSSL 1.1.x DLLs are named ``libcrypto-1_1.dll``
and ``libssl-1_1.dll``. Install these somewhere on your PATH; for
example in ``c:\bin``, together with ``openssl.exe``.
Build M2Crypto::
python setup.py build -cmingw32
python setup.py install
BC++ :sub:`:sub:`~``\ ~
.. NOTE:: The following instructions for building M2Crypto with MSVC++
6.0 and BC++ 5.5 free compiler suite are from M2Crypto 0.10. These
instructions should continue to work for this release, although
I have not tested them.
.. NOTE:: OpenSSL 1.1.x doesn't support BC++.
For BC++ these files are created from the MSVC++-built ones using the
tool ``coff2omf.exe``. I call them ``libeay32_bc.lib`` and
``ssleay32_bc.lib``, respectively. You will need to edit setup.py file
for these.
You'll also need Python's import library, e.g., ``python22.lib``, to be
the BC++-compatible version; i.e., create ``python22_bc.lib`` from
``python22.lib``, save a copy of ``python22.lib`` (as
``python22_vc.lib``, say), then rename ``python22_bc.lib`` to
``python22.lib``.
Now you are ready to build M2Crypto. Do one of the following::
python setup.py build
python setup.py build -cbcpp
Then,::
python setup.py install
MacOSX
------
Apple does not provide on more recent versions of Mac OS X (at least
certainly `since 10.11`_) any version of OpenSSL, so it is necessary to
use ``brew`` or similar packaging systems to install third party
packages. A Mac OS X users suggested, that this series of commands gave
him a working copy of M2Crypto on his system::
$ brew install openssl && brew install swig
$ brew --prefix openssl
/usr/local/opt/openssl
$ LDFLAGS="-L$(brew --prefix openssl)/lib" \
CFLAGS="-I$(brew --prefix openssl)/include" \
SWIG_FEATURES="-I$(brew --prefix openssl)/include" \
pip install m2crypto
.. _`since 10.11`:
https://gitlab.com/m2crypto/m2crypto/merge_requests/7#note_2581821
m2crypto-0.42.0/LICENCE 0000664 0000000 0000000 00000002436 14655756567 0014400 0 ustar 00root root 0000000 0000000 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.42.0/MANIFEST.in 0000664 0000000 0000000 00000000555 14655756567 0015151 0 ustar 00root root 0000000 0000000 include src/SWIG/*.i
include src/SWIG/*.h
include src/SWIG/*.def
recursive-include tests *.py *.pem *.der *.b64 README *.pgp *.dat *.p7* *.crt *.txt
recursive-include doc *
recursive-include contrib *
recursive-exclude .keys *
include INSTALL.rst
include README.rst
include CHANGES
include LICENCE
include src/SWIG/_m2crypto_wrap.c
include src/M2Crypto/m2crypto.py
m2crypto-0.42.0/README.rst 0000664 0000000 0000000 00000005273 14655756567 0015104 0 ustar 00root root 0000000 0000000 ========
M2Crypto
========
:Maintainer: Matěj Cepl
:Web-Site: https://sr.ht/~mcepl/m2crypto/
:Documentation: https://m2crypto.readthedocs.io/
:Email list: https://lists.sr.ht/~mcepl/m2crypto (`subscribe via email`_)
:Issue tracker: https://todo.sr.ht/~mcepl/m2crypto (R/O, please
report issues via the email list).
M2Crypto = Python + OpenSSL + SWIG
----------------------------------
.. image:: https://builds.sr.ht/~mcepl.svg
:target: https://builds.sr.ht/~mcepl?
:alt: builds.sr.ht status
**NOTE: This library is currently in maintenance mode. We
recommend using a more modern alternative such as**
`PyCA/cryptography`_. **Examples of how to migrate can be found
in** `the documentation`_.
M2Crypto is a crypto and SSL toolkit for Python.
M2 stands for "me, too!"
M2Crypto comes with the following:
- **RSA**, **DSA**, **DH**, **HMACs**, **message digests**,
**symmetric ciphers** including **AES**,
- **TLS** functionality to implement **clients and servers**.
- **Example SSL client and server programs**, which are variously
**threading**, **forking** or based on **non-blocking socket IO**.
- **HTTPS** extensions to Python's **httplib, urllib and xmlrpclib**.
- Unforgeable HMAC'ing **AuthCookies** for **web session management**.
- **FTP/TLS** client and server.
- **S/MIME v2**.
- **ZSmime**: An S/MIME messenger for **Zope**.
We care a lot about stable API and all Python methods should be
preserved, note however that ``m2.`` namespace is considered internal to
the library and it doesn't have to be preserved. If however some change
to it breaks your app, let us know and we will try to make things
working for you.
- And much more.
M2Crypto is released under a very liberal MIT licence. See
LICENCE for details.
To install, see the file INSTALL.
Look at the tests and demos for example use. Recommended reading before
deploying in production is "Network Security with OpenSSL" by John Viega,
Matt Messier and Pravir Chandra, ISBN 059600270X.
Note these caveats:
- Possible memory leaks, because some objects need to be freed on the
Python side and other objects on the C side, and these may change
between OpenSSL versions. (Multiple free's lead to crashes very
quickly, so these should be relatively rare.)
- No memory locking/clearing for keys, passphrases, etc. because AFAIK
Python does not provide the features needed. On the C (OpenSSL) side
things are cleared when the Python objects are deleted.
Have fun! Your feedback is welcome.
.. _`subscribe via email`:
mailto:~mcepl/m2crypto+subscribe@lists.sr.ht
.. _`PyCA/cryptography`:
https://cryptography.io/en/latest/
.. _`the documentation`:
https://m2crypto.readthedocs.io/en/latest/howto.migration.html
m2crypto-0.42.0/contrib/ 0000775 0000000 0000000 00000000000 14655756567 0015046 5 ustar 00root root 0000000 0000000 m2crypto-0.42.0/contrib/README 0000664 0000000 0000000 00000000215 14655756567 0015724 0 ustar 00root root 0000000 0000000 This directory contains contributions by users of M2Crypto. Some of these
may get folded into the main distribution in time.
Thanks guys!
m2crypto-0.42.0/contrib/SimpleX509create.README 0000664 0000000 0000000 00000000171 14655756567 0020727 0 ustar 00root root 0000000 0000000 Contributed by Peter Teniz as a demonstration of
PKI functionality, also contributed by him.
m2crypto-0.42.0/contrib/SimpleX509create.py 0000664 0000000 0000000 00000012527 14655756567 0020432 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python
#
#vim: ts=4 sw=4 nowrap
#
from __future__ import print_function
"""PKI demo by Peter Teniz """
from M2Crypto import ASN1, EVP, RSA, X509, m2
MBSTRING_FLAG = 0x1000
MBSTRING_ASC = MBSTRING_FLAG | 1
MBSTRING_BMP = MBSTRING_FLAG | 2
class Cert(object):
def __init__ ( self ):
self.RsaKey = { 'KeyLength' : 1024,
'PubExponent' : 0x10001, # -> 65537
'keygen_callback' : self.callback
}
self.KeyPair = None
self.PKey = None
self.X509Request = None
self.X509Certificate = None
def callback ( self, *args ):
return 'p'
def CreatePKey ( self ):
self.KeyPair = RSA.gen_key( self.RsaKey['KeyLength'], self.RsaKey['PubExponent'], self.RsaKey['keygen_callback'] )
#PubKey = RSA.new_pub_key( self.KeyPair.pub () )
self.KeyPair.save_key( 'KeyPair.pem', cipher='des_ede3_cbc', callback=self.callback )
self.PKey = EVP.PKey ( md='sha1')
self.PKey.assign_rsa ( self.KeyPair )
def CreateX509Request ( self ):
#
# X509 REQUEST
#
self.X509Request = X509.Request ()
#
# subject
#
X509Name = X509.X509_Name ()
X509Name.add_entry_by_txt ( field='C', type=MBSTRING_ASC, entry='austria', len=-1, loc=-1, set=0 ) # country name
X509Name.add_entry_by_txt ( field='SP', type=MBSTRING_ASC, entry='kernten', len=-1, loc=-1, set=0 ) # state of province name
X509Name.add_entry_by_txt ( field='L', type=MBSTRING_ASC, entry='stgallen', len=-1, loc=-1, set=0 ) # locality name
X509Name.add_entry_by_txt ( field='O', type=MBSTRING_ASC, entry='labor', len=-1, loc=-1, set=0 ) # organization name
X509Name.add_entry_by_txt ( field='OU', type=MBSTRING_ASC, entry='it-department', len=-1, loc=-1, set=0 ) # organizational unit name
X509Name.add_entry_by_txt ( field='CN', type=MBSTRING_ASC, entry='Certificate client', len=-1, loc=-1, set=0 ) # common name
X509Name.add_entry_by_txt ( field='Email', type=MBSTRING_ASC, entry='user@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address
X509Name.add_entry_by_txt ( field='emailAddress', type=MBSTRING_ASC, entry='user@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address
self.X509Request.set_subject_name( X509Name )
#
# publickey
#
self.X509Request.set_pubkey ( pkey=self.PKey )
self.X509Request.sign ( pkey=self.PKey, md='sha1' )
#print(X509Request.as_text ())
def CreateX509Certificate ( self ):
#
# X509 CERTIFICATE
#
self.X509Certificate = X509.X509 ()
#
# version
#
self.X509Certificate.set_version ( 0 )
#
# time notBefore
#
ASN1 = ASN1.ASN1_TIME ()
ASN1.set_time ( 500 )
self.X509Certificate.set_not_before( ASN1 )
#
# time notAfter
#
ASN1 = ASN1.ASN1_TIME ()
ASN1.set_time ( 500 )
self.X509Certificate.set_not_after( ASN1 )
#
# public key
#
self.X509Certificate.set_pubkey ( pkey=self.PKey )
#
# subject
#
X509Name = self.X509Request.get_subject ()
#print(X509Name.entry_count ())
#print(X509Name.as_text ())
self.X509Certificate.set_subject_name( X509Name )
#
# issuer
#
X509Name = X509.X509_Name ( m2.x509_name_new () )
X509Name.add_entry_by_txt ( field='C', type=MBSTRING_ASC, entry='germany', len=-1, loc=-1, set=0 ) # country name
X509Name.add_entry_by_txt ( field='SP', type=MBSTRING_ASC, entry='bavaria', len=-1, loc=-1, set=0 ) # state of province name
X509Name.add_entry_by_txt ( field='L', type=MBSTRING_ASC, entry='munich', len=-1, loc=-1, set=0 ) # locality name
X509Name.add_entry_by_txt ( field='O', type=MBSTRING_ASC, entry='sbs', len=-1, loc=-1, set=0 ) # organization name
X509Name.add_entry_by_txt ( field='OU', type=MBSTRING_ASC, entry='it-department', len=-1, loc=-1, set=0 ) # organizational unit name
X509Name.add_entry_by_txt ( field='CN', type=MBSTRING_ASC, entry='Certificate Authority', len=-1, loc=-1, set=0 ) # common name
X509Name.add_entry_by_txt ( field='Email', type=MBSTRING_ASC, entry='admin@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address
X509Name.add_entry_by_txt ( field='emailAddress', type=MBSTRING_ASC, entry='admin@localhost', len=-1, loc=-1, set=0 ) # pkcs9 email address
#print(X509Name.entry_count ())
#print(X509Name.as_text ())
self.X509Certificate.set_issuer_name( X509Name )
#
# signing
#
self.X509Certificate.sign( pkey=self.PKey, md='sha1' )
print(self.X509Certificate.as_text ())
if __name__ == '__main__':
run = Cert ()
run.CreatePKey ()
run.CreateX509Request ()
run.CreateX509Certificate ()
m2crypto-0.42.0/contrib/dave.README 0000664 0000000 0000000 00000005305 14655756567 0016647 0 ustar 00root root 0000000 0000000 From dave@pythonapocrypha.com Wed Dec 11 07:57:55 2002
Date: Tue, 10 Dec 2002 15:05:26 -0800 (PST)
From: Dave Brueck
To: ngps@netmemetic.com
Subject: M2Crypto problem with asynch sockets
Hi and thanks for M2Crypto - great stuff!
I wrote an asynchronous socket layer and decided to use M2Crypto to add
SSL support to it. Unfortunately, I've found a small problem in
_m2crypto_wrap.c - hopefully I'm just not understanding something.
The ssl_connect, ssl_read_nbio, etc. calls don't differentiate between
SSL_ERROR_WANT_WRITE and SSL_ERROR_WANT_READ when a non-blocking call
couldn't finish. But without this information, I don't know whether the
socket needs to do more reading or more writing before a subsequent
attempt will work without blocking. The demo applications (e.g.
echod-async.py) don't seem to care about this but they get around it by
simply trying the operation over and over again, which I can't do for
performance reasons.
Am I missing something? I thought about just calling SSL_get_error when
the above calls return None (indicating WANT_READ or WANT_WRITE), but by
then the error has already been removed from the SSL error queue.
Any help or suggestions would be appreciated. I'd be happy to submit a
patch fixing those calls, but by not returning None they would break
existing code.
Thanks again for M2Crypto though!
-Dave
From dave@pythonapocrypha.com Fri Dec 13 00:46:39 2002
Date: Thu, 12 Dec 2002 09:52:08 -0800 (PST)
From: Dave Brueck
To: ngps@netmemetic.com
Subject: Re: M2Crypto problem with asynch sockets
Hello again,
Here is a patch to M2Crypto's _ssl.i that illustrates the fix I had in
mind in my previous message. You might not want to use it as is since it
changes the error semantics of the affected functions (they now raise an
exception that contains the SSL_WANT_READ or SSL_WANT_WRITE flag instead
of returning None or whatever), but if you tell me how you'd like it
instead then I'd be happy to fix the patch and send it back to you.
Just to refresh your memory, this patch fixes the problem where a
non-blocking call to accept/connect/etc results in an SSL_NEED_READ/WRITE;
currently there's no way for the caller to know _which_ of the two
occurred and so it must try again once the socket has become readable OR
writeable, instead of waiting specifically for one or the other. For many
people this won't matter because their performance requirements are low
enough that trying the ssl_accept/etc call again prematurely won't hurt
too much, but for servers with lots of connections or high throughput it's
much more critical to wait until you know the SSL call has a better chance
of success.
Thanks!
-Dave Brueck
m2crypto-0.42.0/contrib/isaac.README 0000664 0000000 0000000 00000001227 14655756567 0017007 0 ustar 00root root 0000000 0000000 This is Isaac Salzberg's application of Mihai Ibanescu's patch
(available on SF) that allows HTTPS tunneling through an
authenticating proxy.
This one's a double whammy: it works with IIS through the
authenticating proxy, whereas the one on SF, which uses Python's
built-in SSL, doesn't.
This code is not folded into the main distribution because:
1. Apparently Mihai is still working on it.
2. Mihai uses Python's built-in SSL. Isaac patched it to use
M2Crypto.SSL. The stuff is essentially #ifdef'ed code.
3. I don't have an authenticating proxy nor an IIS server to test
against, so I can't clean up the code. Volunteers welcome. ;-)
Thanks Isaac.
m2crypto-0.42.0/contrib/isaac.httpslib.py 0000664 0000000 0000000 00000020700 14655756567 0020327 0 ustar 00root root 0000000 0000000 from __future__ import print_function
"""M2Crypto support for Python 2.x's httplib.
Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved."""
import string
from M2Crypto import SSL
from httplib import FakeSocket, HTTP, HTTPConnection, HTTPResponse, HTTPS_PORT
class HTTPSConnection(HTTPConnection):
"""
This class allows communication via SSL using M2Crypto.
"""
default_port = HTTPS_PORT
def __init__(self, host, port=None, **ssl):
keys = ssl.keys()
try:
keys.remove('key_file')
except ValueError:
pass
try:
keys.remove('cert_file')
except ValueError:
pass
try:
keys.remove('ssl_context')
except ValueError:
pass
if keys:
raise ValueError()
try:
self.ssl_ctx = ssl['ssl_context']
assert isinstance(self.ssl_ctx, SSL.Context)
except KeyError:
self.ssl_ctx = SSL.Context('sslv23')
HTTPConnection.__init__(self, host, port)
def connect(self):
self.sock = SSL.Connection(self.ssl_ctx)
self.sock.connect((self.host, self.port))
def close(self):
# This kludges around line 545 of httplib.py,
# which closes the connection in this object;
# the connection remains open in the response
# object.
#
# M2Crypto doesn't close-here-keep-open-there,
# so, in effect, we don't close until the whole
# business is over and gc kicks in.
#
# Long-running callers beware leakage.
#
# 05-Jan-2002: This module works with Python 2.2,
# but I've not investigated if the above conditions
# remain.
pass
class HTTPS(HTTP):
_connection_class = HTTPSConnection
def __init__(self, host='', port=None, **ssl):
HTTP.__init__(self, host, port)
try:
self.ssl_ctx = ssl['ssl_context']
except KeyError:
self.ssl_ctx = SSL.Context('sslv23')
# ISS Added.
# From here, starts the proxy patch
class HTTPProxyConnection(HTTPConnection):
"""
This class provides HTTP access through (authenticated) proxies.
Example:
If the HTTP proxy address is proxy.your.org:8080, an authenticated proxy
(one which requires a username/password combination in order to serve
requests), one can fetch HTTP documents from 'www.webserver.net', port 81:
conn = HTTPProxyConnection('proxy.your.org:8080', 'www.webserver.net',
port=81, username='username', password='password')
conn.connect()
conn.request("HEAD", "/index.html", headers={'X-Custom-Header-1' : 'Value-1'})
resp = conn.getresponse()
...
"""
def __init__(self, proxy, host, port=None, username=None, password=None):
# The connection goes through the proxy
HTTPConnection.__init__(self, proxy)
# save the proxy connection settings
self.__proxy, self.__proxy_port = self.host, self.port
# self.host and self.port will point to the real host
self._set_hostport(host, port)
# save the host and port
self._host, self._port = self.host, self.port
# Authenticated proxies support
self.__username = username
self.__password = password
def connect(self):
"""Connect to the host and port specified in __init__ (through a
proxy)."""
# We are connecting to the proxy, so use the proxy settings
self._set_hostport(self.__proxy, self.__proxy_port)
HTTPConnection.connect(self)
# Restore the real host and port
self._set_hostport(self._host, self._port)
def putrequest(self, method, url):
"""Send a request to the server.
`method' specifies an HTTP request method, e.g. 'GET'.
`url' specifies the object being requested, e.g. '/index.html'.
"""
# The URL has to include the real host
hostname = self._host
if self._port != self.default_port:
hostname = hostname + ':' + str(self._port)
newurl = "http://%s%s" % (hostname, url)
# Piggyback on the parent class
HTTPConnection.putrequest(self, method, newurl)
# Add proxy-specific headers
self._add_auth_proxy_header()
def _add_auth_proxy_header(self):
"""Adds an HTTP header for authenticated proxies
"""
if not self.__username:
# No username, so assume not an authenticated proxy
return
# Authenticated proxy
import base64
userpass = "%s:%s" % (self.__username, self.__password)
enc_userpass = base64.encodestring(userpass).strip()
self.putheader("Proxy-Authorization", "Basic %s" % enc_userpass)
class HTTPSProxyResponse(HTTPResponse):
"""
Replacement class for HTTPResponse
Proxy responses (made through SSL) have to keep the connection open
after the initial request, since the connection is tunneled to the SSL
host with the CONNECT method.
"""
def begin(self):
HTTPResponse.begin(self)
self.will_close = 0
class HTTPSProxyConnection(HTTPProxyConnection):
"""This class provides HTTP access through (authenticated) proxies.
Example:
If the HTTP proxy address is proxy.your.org:8080, an authenticated proxy
(one which requires a username/password combination in order to serve
requests), one can fetch HTTP documents from 'www.webserver.net', port 81:
conn = HTTPProxyConnection('proxy.your.org:8080', 'www.webserver.net',
port=81, username='username', password='password')
conn.connect()
conn.request("HEAD", "/index.html", headers={'X-Custom-Header-1' : 'Value-1'})
resp = conn.getresponse()
...
To avoid dealing with multiple inheritance, this class only inherits from
HTTPProxyConnection.
"""
default_port = HTTPSConnection.default_port
def __init__(self, proxy, host, port=None, username=None, password=None, **x509):
for key in x509.keys():
if key not in ['cert_file', 'key_file', 'ssl_context']:
raise ValueError()
self.key_file = x509.get('key_file')
self.cert_file = x509.get('cert_file')
#ISS Added
self.ssl_ctx = x509.get('ssl_context')
# Piggybacking on HTTPProxyConnection
HTTPProxyConnection.__init__(self, proxy, host, port, username, password)
def connect(self):
"""Connect (using SSL) to the host and port specified in __init__
(through a proxy)."""
import socket
# Set the connection with the proxy
HTTPProxyConnection.connect(self)
# Use the stock HTTPConnection putrequest
host = "%s:%s" % (self._host, self._port)
HTTPConnection.putrequest(self, "CONNECT", host)
# Add proxy-specific stuff
self._add_auth_proxy_header()
# And send the request
HTTPConnection.endheaders(self)
# Save the response class
response_class = self.response_class
# And replace the response class with our own one, which does not
# close the connection
self.response_class = HTTPSProxyResponse
response = HTTPConnection.getresponse(self)
# Restore the response class
self.response_class = response_class
# Close the response object manually
response.close()
if response.status != 200:
# Close the connection manually
self.close()
# XXX Find the appropriate error code
raise socket.error(1001, response.status, response.value)
# NgPS: I haven't read the code recently, but I think it is
# reasonable to assume that self.sock is a connected TCP socket at
# this point.
# Use the real stuff. ;-)
if self.ssl_ctx and isinstance(self.ssl_ctx, SSL.Context):
self.sock = SSL.Connection(self.ssl_ctx)
self.sock.connect((self.host, self.port))
else:
# Fake the socket
ssl = socket.ssl(self.sock, self.key_file, self.cert_file)
self.sock = FakeSocket(self.sock, ssl)
if self.debuglevel > 0: print('socket type:', self.sock)
def putrequest(self, method, url):
"""Send a request to the server.
`method' specifies an HTTP request method, e.g. 'GET'.
`url' specifies the object being requested, e.g. '/index.html'.
"""
# bypass the parent class's putrequest: use the grandparent's one :-)
return HTTPConnection.putrequest(self, method, url)
m2crypto-0.42.0/contrib/smimeplus.README 0000664 0000000 0000000 00000000245 14655756567 0017744 0 ustar 00root root 0000000 0000000 Contributed by Bernard Yue: A high level smime interface. "It works
for Python 2.2 and above, and requires the email module from Python
2.2.3 to work on Python 2.1.
m2crypto-0.42.0/contrib/smimeplus.py 0000664 0000000 0000000 00000012537 14655756567 0017446 0 ustar 00root root 0000000 0000000 import UserDict
import os
import tempfile
from M2Crypto import BIO, Rand, SMIME, X509
from email import Message
class smimeplus(object):
def __init__(self, cert, privkey, passphrase, cacert, randfile=None):
self.cipher = 'des_ede3_cbc' # XXX make it configable??
self.setsender(cert, privkey, passphrase)
self.setcacert(cacert)
self.randfile = randfile
self.__loadrand()
def __passcallback(self, v):
"""private key passphrase callback function"""
return self.passphrase
def __loadrand(self):
"""Load random number file"""
if self.randfile:
Rand.load_file(self.randfile, -1)
def __saverand(self):
"""Save random number file"""
if self.randfile:
Rand.save_file(self.randfile)
def __gettext(self, msg):
"""Return a string representation of 'msg'"""
_data = ''
if isinstance(msg, Message.Message):
for _p in msg.walk():
_data = _data + _p.as_string()
else:
_data = str(msg)
return _data
def __pack(self, msg):
"""Convert 'msg' to string and put it into an memory buffer for
openssl operation"""
return BIO.MemoryBuffer(self.__gettext(msg))
def setsender(self, cert=None, privkey=None, passphrase=None):
if cert:
self.cert = cert
if privkey:
self.key = privkey
if passphrase:
self.passphrase = passphrase
def setcacert(self, cacert):
self.cacert = cacert
def sign(self, msg):
"""Sign a message"""
_sender = SMIME.SMIME()
_sender.load_key_bio(self.__pack(self.key), self.__pack(self.cert),
callback=self.__passcallback)
_signed = _sender.sign(self.__pack(msg), SMIME.PKCS7_DETACHED)
_out = self.__pack(None)
_sender.write(_out, _signed, self.__pack(msg))
return _out.read()
def verify(self, smsg, scert):
"""Verify to see if 'smsg' was signed by 'scert', and scert was
issued by cacert of this object. Return message signed if success,
None otherwise"""
# Load signer's cert.
_x509 = X509.load_cert_bio(self.__pack(scert))
_stack = X509.X509_Stack()
_stack.push(_x509)
# Load CA cert.
_tmpfile = persistdata(self.cacert)
_store = X509.X509_Store()
_store.load_info(_tmpfile)
os.remove(_tmpfile)
# prepare SMIME object
_sender = SMIME.SMIME()
_sender.set_x509_stack(_stack)
_sender.set_x509_store(_store)
# Load signed message, verify it, and return result
_p7, _data = SMIME.smime_load_pkcs7_bio(self.__pack(smsg))
try:
return _sender.verify(_p7, _data, flags=SMIME.PKCS7_SIGNED)
except SMIME.SMIME_Error:
return None
def encrypt(self, rcert, msg):
# Instantiate an SMIME object.
_sender = SMIME.SMIME()
# Load target cert to encrypt to.
_x509 = X509.load_cert_bio(self.__pack(rcert))
_stack = X509.X509_Stack()
_stack.push(_x509)
_sender.set_x509_stack(_stack)
_sender.set_cipher(SMIME.Cipher(self.cipher))
# Encrypt the buffer.
_buf = self.__pack(self.__gettext(msg))
_p7 = _sender.encrypt(_buf)
# Output p7 in mail-friendly format.
_out = self.__pack('')
_sender.write(_out, _p7)
# Save the PRNG's state.
self.__saverand()
return _out.read()
def decrypt(self, emsg):
"""decrypt 'msg'. Return decrypt message if success, None
otherwise"""
# Load private key and cert.
_sender = SMIME.SMIME()
_sender.load_key_bio(self.__pack(self.key), self.__pack(self.cert),
callback=self.__passcallback)
# Load the encrypted data.
_p7, _data = SMIME.smime_load_pkcs7_bio(self.__pack(emsg))
# Decrypt p7.
try:
return _sender.decrypt(_p7)
except SMIME.SMIME_Error:
return None
def addHeader(self, rcert, content, subject=''):
"""Add To, From, Subject Header to 'content'"""
_scert = X509.load_cert_bio(self.__pack(self.cert))
_scertsubj = X509_Subject(str(_scert.get_subject()))
_rcert = X509.load_cert_bio(self.__pack(rcert))
_rcertsubj = X509_Subject(str(_rcert.get_subject()))
_out = 'From: "%(CN)s" <%(emailAddress)s>\n' % _scertsubj
_out = _out + 'To: "%(CN)s" <%(emailAddress)s>\n' % _rcertsubj
_out = _out + 'Subject: %s\n' % subject
_out = _out + content
return _out
class X509_Subject(UserDict.UserDict):
# This class needed to be rewritten or merge with X509_Name
def __init__(self, substr):
UserDict.UserDict.__init__(self)
try:
_data = substr.strip().split('/')
except AttributeError:
pass
else:
for _i in _data:
try:
_k, _v = _i.split('=')
self[_k] = _v
except ValueError:
pass
def persistdata(data, file=None, isbinary=False):
if not file:
file = tempfile.mktemp()
if isbinary:
_flag = 'wb'
else:
_flag = 'w'
_fh = open(file, _flag)
_fh.write(data)
_fh.close()
return file
m2crypto-0.42.0/dev-requirements.txt 0000664 0000000 0000000 00000000400 14655756567 0017440 0 ustar 00root root 0000000 0000000 -r requirements.txt
twine; sys.platform == 'win32'
wheel; sys.platform == 'win32'
flake8
typing; python_version < "3.5"
# Intentionally not in requirements.txt, because only those use it need
# this very specialized module.
twisted; python_version > "3.0"
m2crypto-0.42.0/doc/ 0000775 0000000 0000000 00000000000 14655756567 0014153 5 ustar 00root root 0000000 0000000 m2crypto-0.42.0/doc/HOWTOs.rst 0000664 0000000 0000000 00000000175 14655756567 0015773 0 ustar 00root root 0000000 0000000 HOWTOs
================
Contents:
.. toctree::
:maxdepth: 3
howto.ca
howto.ssl
howto.smime
howto.migration
m2crypto-0.42.0/doc/M2Crypto.SSL.rst 0000664 0000000 0000000 00000002655 14655756567 0017034 0 ustar 00root root 0000000 0000000 SSL Package
===========
:mod:`SSL` Package
------------------
.. automodule:: M2Crypto.SSL
:members:
:undoc-members:
:show-inheritance:
:mod:`Checker` Module
---------------------
.. automodule:: M2Crypto.SSL.Checker
:members:
:undoc-members:
:show-inheritance:
:mod:`Cipher` Module
--------------------
.. automodule:: M2Crypto.SSL.Cipher
:members:
:undoc-members:
:show-inheritance:
:mod:`Connection` Module
------------------------
.. automodule:: M2Crypto.SSL.Connection
:members:
:undoc-members:
:show-inheritance:
:mod:`Context` Module
---------------------
.. automodule:: M2Crypto.SSL.Context
:members:
:undoc-members:
:show-inheritance:
:mod:`SSLServer` Module
-----------------------
.. automodule:: M2Crypto.SSL.SSLServer
:members:
:undoc-members:
:show-inheritance:
:mod:`Session` Module
---------------------
.. automodule:: M2Crypto.SSL.Session
:members:
:undoc-members:
:show-inheritance:
:mod:`TwistedProtocolWrapper` Module
------------------------------------
.. automodule:: M2Crypto.SSL.TwistedProtocolWrapper
:members:
:undoc-members:
:show-inheritance:
:mod:`cb` Module
----------------
.. automodule:: M2Crypto.SSL.cb
:members:
:undoc-members:
:show-inheritance:
:mod:`timeout` Module
---------------------
.. automodule:: M2Crypto.SSL.timeout
:members:
:undoc-members:
:show-inheritance:
m2crypto-0.42.0/doc/M2Crypto.rst 0000664 0000000 0000000 00000006655 14655756567 0016400 0 ustar 00root root 0000000 0000000 M2Crypto Package
================
:mod:`M2Crypto` Package
-----------------------
.. automodule:: M2Crypto.__init__
:members:
:undoc-members:
:show-inheritance:
:mod:`ASN1` Module
------------------
.. automodule:: M2Crypto.ASN1
:members:
:undoc-members:
:show-inheritance:
:mod:`AuthCookie` Module
------------------------
.. automodule:: M2Crypto.AuthCookie
:members:
:undoc-members:
:show-inheritance:
:mod:`BIO` Module
-----------------
.. automodule:: M2Crypto.BIO
:members:
:undoc-members:
:show-inheritance:
:mod:`BN` Module
----------------
.. automodule:: M2Crypto.BN
:members:
:undoc-members:
:show-inheritance:
:mod:`DH` Module
----------------
.. automodule:: M2Crypto.DH
:members:
:undoc-members:
:show-inheritance:
:mod:`DSA` Module
-----------------
.. automodule:: M2Crypto.DSA
:members:
:undoc-members:
:show-inheritance:
:mod:`EC` Module
----------------
.. automodule:: M2Crypto.EC
:members:
:undoc-members:
:show-inheritance:
:mod:`EVP` Module
-----------------
.. automodule:: M2Crypto.EVP
:members:
:undoc-members:
:show-inheritance:
:mod:`Engine` Module
--------------------
.. automodule:: M2Crypto.Engine
:members:
:undoc-members:
:show-inheritance:
:mod:`Err` Module
-----------------
.. automodule:: M2Crypto.Err
:members:
:undoc-members:
:show-inheritance:
:mod:`RC4` Module
-----------------
.. automodule:: M2Crypto.RC4
:members:
:undoc-members:
:show-inheritance:
:mod:`RSA` Module
-----------------
.. automodule:: M2Crypto.RSA
:members:
:undoc-members:
:show-inheritance:
:mod:`Rand` Module
------------------
.. automodule:: M2Crypto.Rand
:members:
:undoc-members:
:show-inheritance:
:mod:`SMIME` Module
-------------------
.. automodule:: M2Crypto.SMIME
:members:
:undoc-members:
:show-inheritance:
:mod:`X509` Module
------------------
.. automodule:: M2Crypto.X509
:members:
:undoc-members:
:show-inheritance:
:mod:`callback` Module
----------------------
.. automodule:: M2Crypto.callback
:members:
:undoc-members:
:show-inheritance:
:mod:`ftpslib` Module
---------------------
.. automodule:: M2Crypto.ftpslib
:members:
:undoc-members:
:show-inheritance:
:mod:`httpslib` Module
----------------------
.. automodule:: M2Crypto.httpslib
:members:
:undoc-members:
:show-inheritance:
:mod:`m2` Module
----------------
.. automodule:: M2Crypto.m2
:members:
:undoc-members:
:show-inheritance:
:mod:`m2crypto` Module
----------------------
.. automodule:: M2Crypto.m2crypto
:members:
:undoc-members:
:show-inheritance:
:mod:`m2urllib` Module
----------------------
.. automodule:: M2Crypto.m2urllib
:members:
:undoc-members:
:show-inheritance:
:mod:`m2urllib2` Module
-----------------------
.. automodule:: M2Crypto.m2urllib2
:members:
:undoc-members:
:show-inheritance:
:mod:`m2xmlrpclib` Module
-------------------------
.. automodule:: M2Crypto.m2xmlrpclib
:members:
:undoc-members:
:show-inheritance:
:mod:`threading` Module
-----------------------
.. automodule:: M2Crypto.threading
:members:
:undoc-members:
:show-inheritance:
:mod:`util` Module
------------------
.. automodule:: M2Crypto.util
:members:
:undoc-members:
:show-inheritance:
Subpackages
-----------
.. toctree::
M2Crypto.SSL
m2crypto-0.42.0/doc/Makefile 0000664 0000000 0000000 00000012715 14655756567 0015621 0 ustar 00root root 0000000 0000000 # Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = .
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make ' where is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/{doctrees,html}
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/M2Crypto.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/M2Crypto.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/M2Crypto"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/M2Crypto"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
m2crypto-0.42.0/doc/conf.py 0000664 0000000 0000000 00000022002 14655756567 0015446 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
#
# M2Crypto documentation build configuration file, created by
# sphinx-quickstart on Thu Apr 20 11:15:12 2017.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath(os.path.join('..')))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.viewcode',
'sphinx_rtd_theme',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'M2Crypto'
copyright = u'2017, Matej Cepl '
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = ''
# The full version, including alpha/beta/rc tags.
release = ''
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# " v documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'M2Cryptodoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'M2Crypto.tex', u'M2Crypto Documentation',
u'Matej Cepl \\textless{}mcepl@cepl.eu\\textgreater{}', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'm2crypto', u'M2Crypto Documentation',
[u'Matej Cepl '], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'M2Crypto', u'M2Crypto Documentation',
u'Matej Cepl ', 'M2Crypto', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# -- Options for Epub output ---------------------------------------------------
# Bibliographic Dublin Core info.
epub_title = u'M2Crypto'
epub_author = u'Matej Cepl '
epub_publisher = u'Matej Cepl '
epub_copyright = u'2017, Matej Cepl '
# The language of the text. It defaults to the language option
# or en if the language is not set.
#epub_language = ''
# The scheme of the identifier. Typical schemes are ISBN or URL.
#epub_scheme = ''
# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#epub_identifier = ''
# A unique identification for the text.
#epub_uid = ''
# A tuple containing the cover image and cover page html template filenames.
#epub_cover = ()
# HTML files that should be inserted before the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_pre_files = []
# HTML files shat should be inserted after the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_post_files = []
# A list of files that should not be packed into the epub file.
#epub_exclude_files = []
# The depth of the table of contents in toc.ncx.
#epub_tocdepth = 3
# Allow duplicate toc entries.
#epub_tocdup = True
m2crypto-0.42.0/doc/howto.ca.rst 0000664 0000000 0000000 00000037123 14655756567 0016435 0 ustar 00root root 0000000 0000000 :orphan:
.. _howto-ca:
HOWTO: Creating your own CA with OpenSSL
########################################
:author: Pheng Siong Ng
:copyright: © 2000, 2001 by Ng Pheng Siong.
Introduction
============
This is a HOWTO on creating your own *certification authority* (*CA*)
with OpenSSL.
I last created a CA about a year ago, when I began work on
`M2Crypto `__ and needed
certificates for the SSL bits. I accepted the tools' default
settings then, e.g., certificate validity of 365 days; this meant
that my certificates, including my CA's certificate, have now
expired.
Since I am using these certificates for M2Crypto's demonstration
programs (and I have forgotten the passphrase to the CA's private
key), I decided to discard the old CA and start afresh. I also
decided to document the process, hence this HOWTO.
The Procedure
=============
I use ``CA.pl``, a Perl program written by Steve Hanson and bundled with
OpenSSL.
The following are the steps to create a CA:
1. Choose a directory to do your CA work. All commands are executed
within this directory. Let's call the directory ``demo``.
2. Copy ``CA.pl`` and ``openssl.cnf`` into ``demo``.
3. Apply the following patch to ``CA.pl``, which allows it to generate a
CA certificate with a validity period of 1095 days, i.e.,
3 years::
--- CA.pl.org Sat Mar 31 12:40:13 2001
+++ CA.pl Sat Mar 31 12:41:15 2001
@@ -97,7 +97,7 @@
} else {
print "Making CA certificate ...\n";
system ("$REQ -new -x509 -keyout " .
- "${CATOP}/private/$CAKEY -out ${CATOP}/$CACERT $DAYS");
+ "${CATOP}/private/$CAKEY -out ${CATOP}/$CACERT -days 1095");
$RET=$?;
}
}
4. Create a new CA like this::
./CA.pl -newca
A certificate filename (or enter to create)
Making CA certificate ...
Using configuration from openssl.cnf
Generating a 1024 bit RSA private key
............++++++
......................++++++
writing new private key to './demoCA/private/cakey.pem'
Enter PEM pass phrase:
Verifying password - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:SG
State or Province Name (full name) [Some-State]:.
Locality Name (eg, city) []:..
Organization Name (eg, company) [Internet Widgits Pty Ltd]:DemoCA
Organizational Unit Name (eg, section) []:.
Common Name (eg, YOUR name) []:DemoCA Certificate Master
Email Address []:certmaster@democa.dom
This creates a new CA in the directory ``demoCA``. The CA's
self-signed certificate is in ``demoCA/cacert.pem`` and its RSA key
pair is in ``demoCA/private/cakey.pem``.
``demoCA/private/cakey.pem`` looks like this::
cat demoCA/private/cakey.pem
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,19973A9DBBB601BA
eOq9WFScNiI4/UWEUaSnGTKpJv2JYuMD3HwQox2Q3Cd4zGqVjJ6gF3exa5126cKf
X/bMVnwbPpuFZPiAIvaLyCjT6pYeXTBbSzs7/GQnvEOv+nYnDUFWi0Qm92qLk0uy
pFi/M1aWheN3vir2ZlAw+DW0bOOZhj8tC7Co7lMYb0YE271b6/YRPZCwQ3GXAHUJ
+aMYxlUDrK45aCUa/1CZDzTgk7h9cDgx2QJSIvYMYytCfI3zsuZMJS8/4OXLL0bI
lKmAc1dwB3DqGJt5XK4WJesiNfdxeCNEgAcYtEAgYZTPIApU+kTgTCIxJl2nMW7j
ax+Q1z7g+4MpgG20WD633D4z4dTlDdz+dnLi0rvuvxiwt+dUhrqiML1tyi+Z6EBH
jU4/cLBWev3rYfrlp4x8J9mDte0YKOk3t0wQOHqRetTsIfdtjnFp/Hu3qDmTCWjD
z/g7PPoO/bg/B877J9WBPbL/1hXXFYo88M+2aGlPOgDcFdiOqbLb2DCscohMbbVr
A4mgiy2kwWfIE73qiyV7yyG8FlRvr1iib+jbT3LTGf743utYAAs7HNGuOUObhoyt
jYvBD7ACn35P5YX7KTqvqErwdijxYCaNBCnvmRtmYSaNw9Kv1UJTxc5Vx7YLwIPk
E9KyBgKI7vPOjWBZ27+zOvNycmv1ciNtpALAw4bWtXnhCDVTHaVDy34OkheMzNCg
2cjcBFzOkMIjcI03KbTQXOFIQGlsTWXGzkNf/zBQ+KksT1MCj+zBXSCvlDASMckg
kef21pGgUqPF14gKGfWX3sV4bjc1vbrRwq6zlG3nMuYqR5MtJJY9eQ==
-----END RSA PRIVATE KEY-----
5. Next, generate a certificate request::
./CA.pl -newreq
Using configuration from openssl.cnf
Generating a 1024 bit RSA private key
..........++++++
..............++++++
writing new private key to 'newreq.pem'
Enter PEM pass phrase:
Verifying password - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:SG
State or Province Name (full name) [Some-State]:..
Locality Name (eg, city) []:.
Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto
Organizational Unit Name (eg, section) []:.
Common Name (eg, YOUR name) []:localhost
Email Address []:admin@server.example.dom
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Request (and private key) is in newreq.pem
\
The certificate request and private key in ``newreq.pem`` looks like
this::
cat newreq.pem
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,41B2874DF3D02DD4
mg611EoVkLEooSTv+qTM0Ddmm/M1jE/Jy5RD/sc3LSMhuGu9xc26OgsTJmkQuIAh
J/B4lAw8G59VTG6DykeEtrG0rUBx4bggc7PKbFuiN423YjJODWcHvVgnPOzXMQt+
lY4tPl5+217MRHyx2NsWGrpkQNdu3GeSPOVMl3jeQiaXupONbwQ7rj42+X/VtAJP
W4D1NNwu8aGCPyShsEXHc/fI1WDpphYWke97pOjIZVQESFZOPty5HjIYZux4U+td
W81xODtq2ecJXc8fn2Wpa9y5VD1LT7oJksOuL1+Z04OVaeUe4x0swM17HlBm2kVt
fe/C/L6kN27MwZhE331VjtTjSGl4/gknqQDbLOtqT06f3OISsDJETm2itllyhgzv
C6Fi3N03rGFmKectijC+tws5k+P+HRG6sai33usk8xPokJqA+HYSWPz1XVlpRmv4
kdjQOdST7ovU62mOTgf3ARcduPPwuzTfxOlYONe5NioO1APVHBrInQwcpLkpOTQR
vI4roIN+b75/nihUWGUJn/nbbBa2Yl0N5Gs1Tyiy9Z+CcRT2TfWKBBFlEUIFl7Mb
J9fTV3DI+k+akbR4il1NkQ8EcSmCr3WpA0I9n0EHI7ZVpVaHxc0sqaPFl8YGdFHq
1Qk53C/w6+qPpDzT3yKFmG2LZytAAM1czvb6RbNRJJP2ZrpBwn/h99sUTo/yPfxY
nueYmFJDm0uVNtG0icXGNUfSfnjKNTtHPAgyKGetRIC3kgJz/bo2w7EI6iEjBAzK
l5TRm4x6ZJxwuXXMiJCehMMd8TC8ybwWO4AO19B3ebFFeTVsUgxSGA==
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE REQUEST-----
MIIBnTCCAQYCAQAwXTELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIw
EAYDVQQDEwlsb2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHNlcnZlci5l
eGFtcGxlLmRvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAr1nYY1Qrll1r
uB/FqlCRrr5nvupdIN+3wF7q915tvEQoc74bnu6b8IbbGRMhzdzmvQ4SzFfVEAuM
MuTHeybPq5th7YDrTNizKKxOBnqE2KYuX9X22A1Kh49soJJFg6kPb9MUgiZBiMlv
tb7K3CHfgw5WagWnLl8Lb+ccvKZZl+8CAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4GB
AHpoRp5YS55CZpy+wdigQEwjL/wSluvo+WjtpvP0YoBMJu4VMKeZi405R7o8oEwi
PdlrrliKNknFmHKIaCKTLRcU59ScA6ADEIWUzqmUzP5Cs6jrSRo3NKfg1bd09D1K
9rsQkRc9Urv9mRBIsredGnYECNeRaK5R1yzpOowninXC
-----END CERTIFICATE REQUEST-----
\
Decoding the certificate request gives the following::
openssl req -text -noout < newreq.pem
Using configuration from /usr/local/pkg/openssl/openssl.cnf
Certificate Request:
Data:
Version: 0 (0x0)
Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50:
91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e:
6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13:
21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4:
c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac:
4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f:
6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9:
6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f:
0b:6f:e7:1c:bc:a6:59:97:ef
Exponent: 65537 (0x10001)
Attributes:
a0:00
Signature Algorithm: md5WithRSAEncryption
7a:68:46:9e:58:4b:9e:42:66:9c:be:c1:d8:a0:40:4c:23:2f:
fc:12:96:eb:e8:f9:68:ed:a6:f3:f4:62:80:4c:26:ee:15:30:
a7:99:8b:8d:39:47:ba:3c:a0:4c:22:3d:d9:6b:ae:58:8a:36:
49:c5:98:72:88:68:22:93:2d:17:14:e7:d4:9c:03:a0:03:10:
85:94:ce:a9:94:cc:fe:42:b3:a8:eb:49:1a:37:34:a7:e0:d5:
b7:74:f4:3d:4a:f6:bb:10:91:17:3d:52:bb:fd:99:10:48:b2:
b7:9d:1a:76:04:08:d7:91:68:ae:51:d7:2c:e9:3a:8c:27:8a:
75:c2
6. Now, sign the certificate request::
./CA.pl -sign
Using configuration from openssl.cnf
Enter PEM pass phrase:
Check that the request matches the signature
Signature ok
The Subjects Distinguished Name is as follows
countryName :PRINTABLE:'SG'
organizationName :PRINTABLE:'M2Crypto'
commonName :PRINTABLE:'localhost'
emailAddress :IA5STRING:'admin@server.example.dom'
Certificate is to be certified until Mar 31 02:57:30 2002 GMT (365 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
Signed certificate is in newcert.pem
\
``newcert.pem`` looks like this::
cat newcert.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=SG, O=DemoCA, CN=DemoCA Certificate Master/Email=certmaster@democa.dom
Validity
Not Before: Mar 31 02:57:30 2001 GMT
Not After : Mar 31 02:57:30 2002 GMT
Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50:
91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e:
6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13:
21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4:
c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac:
4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f:
6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9:
6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f:
0b:6f:e7:1c:bc:a6:59:97:ef
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=SG, O=DemoCA, CN=DemoCA Certificate Master/Email=certmaster@democa.dom
Validity
Not Before: Mar 31 02:57:30 2001 GMT
Not After : Mar 31 02:57:30 2002 GMT
Subject: C=SG, O=M2Crypto, CN=localhost/Email=admin@server.example.dom
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:af:59:d8:63:54:2b:96:5d:6b:b8:1f:c5:aa:50:
91:ae:be:67:be:ea:5d:20:df:b7:c0:5e:ea:f7:5e:
6d:bc:44:28:73:be:1b:9e:ee:9b:f0:86:db:19:13:
21:cd:dc:e6:bd:0e:12:cc:57:d5:10:0b:8c:32:e4:
c7:7b:26:cf:ab:9b:61:ed:80:eb:4c:d8:b3:28:ac:
4e:06:7a:84:d8:a6:2e:5f:d5:f6:d8:0d:4a:87:8f:
6c:a0:92:45:83:a9:0f:6f:d3:14:82:26:41:88:c9:
6f:b5:be:ca:dc:21:df:83:0e:56:6a:05:a7:2e:5f:
0b:6f:e7:1c:bc:a6:59:97:ef
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
B3:D6:89:88:2F:B1:15:40:EC:0A:C0:30:35:3A:B7:DA:72:73:1B:4D
X509v3 Authority Key Identifier:
keyid:F9:6A:A6:34:97:6B:BC:BB:5A:17:0D:19:FC:62:21:0B:00:B5:0E:29
DirName:/C=SG/O=DemoCA/CN=DemoCA Certificate Master/Email=certmaster@democa.dom
serial:00
Signature Algorithm: md5WithRSAEncryption
7. In certain situations, e.g., where your certificate and private key
are to be used in an unattended SSL server, you may wish to not
encrypt the private key, i.e., leave the key in the clear. This
decision should be governed by your site's security policy and threat
model, of course::
openssl rsa < newkey.pem > newkey2.pem
read RSA key
Enter PEM pass phrase:
writing RSA key
``newkey2.pem`` looks like this::
cat newkey2.pem
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQCvWdhjVCuWXWu4H8WqUJGuvme+6l0g37fAXur3Xm28RChzvhue
7pvwhtsZEyHN3Oa9DhLMV9UQC4wy5Md7Js+rm2HtgOtM2LMorE4GeoTYpi5f1fbY
DUqHj2ygkkWDqQ9v0xSCJkGIyW+1vsrcId+DDlZqBacuXwtv5xy8plmX7wIDAQAB
AoGAbAkU8w3W1Qu15Hle1bJSL7GMReoreqeblOBmMAZz4by0l6sXZXJpjWXo86f/
+dASMYTMPC4ZTYtv06N07AFbjL+kDfqDMTfzQkYMHp1LAq1Ihbq1rHWSBH5n3ekq
KiY8JKpv8DR5Po1iKaXJFuDByGDENJwYbSRSpSK3P+vkWWECQQDkEUE/ZPqqqZkQ
2iWRPAsCbEID8SAraQl3DdCLYs/GgARfmmj4yUHEwkys9Jo1H8k4BdxugmaUwNi5
YQ/CVzrXAkEAxNO80ArbGxPUmr11GHG/bGBYj1DUBkHZSc7dgxZdtUCLGNxQnNsg
Iwq3n6j1sUzS3UW6abQ8bivYNOUcMKJAqQJBANQxFaLU4b/NQaODQ3aoBZpAfP9L
5eFdvbet+7zjt2r5CpikgkwOfAmDuXEltx/8LevY0CllW+nErx9zJgVrwUsCQQCu
76H5JiznPBDSF2FjgHWqVVdgyW4owY3mU739LHvNBLicN/RN9VPy0Suy8/CqzKT9
lWPBXzf2k3FuUdNkRlFBAkEAmpXoybuiFR2S5Bma/ax96lVs0/VihhfC1zZP/X/F
Br77+h9dIul+2DnyOl50zu0Sdzst1/7ay4JSDHyiBCMGSQ==
-----END RSA PRIVATE KEY-----
That's it! The certificate, ``newcert.pem``, and the private key -
``newkey.pem`` (encrypted) or ``newkey2.pem`` (unencrypted) - are now
ready to be used. You may wish to rename the files to more intuitive
names.
You should also keep the CA's certificate ``demo/cacert.pem`` handy
for use when developing and deploying SSL or S/MIME applications.
Conclusion
==========
We've walked through the basic steps in the creation of a CA and
certificates using the tools that come with OpenSSL. We did not cover
more advanced topics such as constraining a certificate to be SSL-only
or S/MIME-only.
There exist several HOWTOs similar to this one on the net. This one is
written specifically to facilitate discussions in my other HOWTOs on
developing SSL and S/MIME applications in
`Python `__ using `M2Crypto
`__.
m2crypto-0.42.0/doc/howto.migration.rst 0000664 0000000 0000000 00000015120 14655756567 0020034 0 ustar 00root root 0000000 0000000 :orphan:
.. _howto-migration:
HOWTO: Migrating from M2Crypto to PyCA/cryptography
###################################################
Introduction
************
`PyCA/cryptography `__ is a
package which provides cryptographic recipes and primitives to Python
developers.
This document has instructions on how to migrate from M2Crypto to
PyCA/cryptography for features that are currently supported.
S/MIME
******
Signing
=======
If your application does S/MIME signing, it can be migrated to
`PyCA/cryptography `__ by using
the ``PKCS7`` API, particularly the ``PKCS7SignatureBuilder`` class. Below
is an example migration showcasing the equivalent APIs and parameters in
`PyCA/cryptography `__.
M2Crypto
--------
.. testcode::
from M2Crypto import BIO, SMIME
s = SMIME.SMIME()
s.load_key('../tests/signer_key.pem', '../tests/signer.pem')
data = b'data'
buf = BIO.MemoryBuffer(data)
p7 = s.sign(buf, SMIME.PKCS7_DETACHED)
out = BIO.MemoryBuffer()
buf = BIO.MemoryBuffer(data)
s.write(out, p7, buf)
print(out.read())
.. testoutput::
:hide:
b'MIME-Version: 1.0\nContent-Type: multipart/signed;...
PyCA/cryptography
-----------------
.. testcode::
from cryptography.hazmat.primitives.serialization import load_pem_private_key, pkcs7, Encoding
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
from cryptography.x509 import load_pem_x509_certificate
with open('../tests/signer_key.pem', 'rb') as key_data:
key = load_pem_private_key(key_data.read(), password=None)
with open('../tests/signer.pem', 'rb') as cert_data:
cert = load_pem_x509_certificate(cert_data.read())
output = pkcs7.PKCS7SignatureBuilder().set_data(
b"data"
).add_signer(
cert, key, hashes.SHA512(), rsa_padding=padding.PKCS1v15()
).sign(
Encoding.SMIME, [pkcs7.PKCS7Options.DetachedSignature]
)
print(output)
.. testoutput::
:hide:
b'MIME-Version: 1.0\r\nContent-Type: multipart/signed;...
RSA
***
Following are migration examples for common operations with RSA key pairs.
The documentation for the relevant ``PyCA/cryptography`` APIs can be found
`here `__.
Signing and verifying
=====================
M2Crypto
--------
.. testcode::
from M2Crypto import RSA
import hashlib
message = b"This is the message string"
digest = hashlib.sha1(message).digest()
key = RSA.load_key('../tests/rsa.priv.pem')
signature = key.sign(digest, algo='sha1')
assert key.verify(digest, signature, algo='sha1') == 1
print(signature.hex())
.. testoutput::
:hide:
79aba937863cd5bfef254...
PyCA/cryptography
-----------------
.. testcode::
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
with open('../tests/rsa.priv.pem', 'rb') as key_data:
key = load_pem_private_key(key_data.read(), password=None)
message = b"This is the message string"
signature = key.sign(message, padding.PKCS1v15(), hashes.SHA1())
public_key = key.public_key()
public_key.verify(signature, message, padding.PKCS1v15(), hashes.SHA1())
print(signature.hex())
.. testoutput::
:hide:
79aba937863cd5bfef254...
Encrypting and decrypting
=========================
M2Crypto
--------
.. testcode::
from M2Crypto import RSA
message = b"This is the message string"
key = RSA.load_key('../tests/rsa.priv.pem')
cipher_text = key.public_encrypt(message, RSA.pkcs1_padding)
plain_text = key.private_decrypt(cipher_text, RSA.pkcs1_padding)
assert plain_text == message
PyCA/cryptography
-----------------
.. testcode::
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import serialization
with open('../tests/rsa.priv.pem', 'rb') as key_data:
key = load_pem_private_key(key_data.read(), password=None)
message = b"This is the message string"
public_key = key.public_key()
cipher_text = public_key.encrypt(message, padding.PKCS1v15())
plain_text = key.decrypt(cipher_text, padding.PKCS1v15())
assert plain_text == message
X.509 certificates
******************
Following are migration examples for common operations with X.509 certificates.
The documentation for the relevant ``PyCA/cryptography`` APIs can be found
`here `__.
Loading and examining certificates
==================================
M2Crypto
--------
.. testcode::
from M2Crypto import X509
cert = X509.load_cert('../tests/x509.pem')
print(cert.get_issuer())
print(cert.get_subject())
print(cert.get_not_before())
print(cert.get_not_after())
.. testoutput::
:hide:
/C=US/ST=California/O=M2Crypto/CN=Heikki Toivonen
/C=US/ST=California/O=M2Crypto/CN=X509
Oct 7 15:12:02 2018 GMT
Oct 4 15:12:02 2028 GMT
PyCA/cryptography
-----------------
.. testcode::
from cryptography import x509
with open('../tests/x509.pem', 'rb') as cert_data:
cert = x509.load_pem_x509_certificate(cert_data.read())
print(cert.issuer)
print(cert.subject)
print(cert.not_valid_before_utc)
print(cert.not_valid_after_utc)
.. testoutput::
:hide:
2018-10-07 15:12:02+00:00
2028-10-04 15:12:02+00:00
Signature verification
==================================
Note that this example only checks that the signature of a certificate
matches a public key, as described in
`the OpenSSL documentation `__.
For complete X.509 path validation see
`PyCA/cryptography's X.509 verification module `__.
M2Crypto
--------
.. testcode::
from M2Crypto import X509
cert = X509.load_cert('../tests/x509.pem')
cacert = X509.load_cert("../tests/ca.pem")
assert cert.verify(cacert.get_pubkey()) == 1
PyCA/cryptography
-----------------
.. testcode::
from cryptography.x509 import load_pem_x509_certificate
with open('../tests/ca.pem', 'rb') as cacert_data:
cacert = load_pem_x509_certificate(cacert_data.read())
with open('../tests/x509.pem', 'rb') as cert_data:
cert = load_pem_x509_certificate(cert_data.read())
cert.verify_directly_issued_by(cacert)
m2crypto-0.42.0/doc/howto.smime.rst 0000664 0000000 0000000 00000072610 14655756567 0017164 0 ustar 00root root 0000000 0000000 :orphan:
.. _howto-smime:
HOWTO: Programming S/MIME in Python with M2Crypto
#################################################
:author: Pheng Siong Ng
:copyright: © 2000, 2001 by Ng Pheng Siong.
Introduction
============
`M2Crypto `__ is a `Python
`__ interface to `OpenSSL
`__. It makes available to the Python
programmer SSL functionality to implement clients and servers,
S/MIME v2, RSA, DSA, DH, symmetric ciphers, message digests and
HMACs.
This document demonstrates programming S/MIME with M2Crypto.
S/MIME
======
S/MIME - Secure Multipurpose Internet Mail Extensions [RFC 2311, RFC
2312] - provides a consistent way to send and receive secure MIME data.
Based on the popular Internet MIME standard, S/MIME provides the
following cryptographic security services for electronic messaging
applications - *authentication*, *message integrity* and
*non-repudiation of origin* (using *digital signatures*), and *privacy*
and *data security* (using *encryption*).
Keys and Certificates
=====================
To create an S/MIME-signed message, you need an RSA key pair (this
consists of a public key and a private key) and an X.509 certificate of
said public key.
To create an S/MIME-encrypted message, you need an X.509 certificate for
each recipient.
To create an S/MIME-signed *and* -encrypted message, first create a
signed message, then encrypt the signed message with the recipients'
certificates.
You may generate key pairs and obtain certificates by using a commercial
*certification authority* service.
You can also do so using freely-available software. For many purposes,
e.g., automated S/MIME messaging by system administration processes,
this approach is cheap and effective.
We now work through using OpenSSL to generate key pairs and
certificates. This assumes you have OpenSSL installed properly on your
system.
First, we generate an X.509 certificate to be used for signing::
openssl req -newkey rsa:1024 -nodes -x509 -days 365 -out signer.pem
Using configuration from /usr/local/pkg/openssl/openssl.cnf
Generating a 1024 bit RSA private key
..++++++
....................++++++
writing new private key to 'privkey.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:SG
State or Province Name (full name) [Some-State]:.
Locality Name (eg, city) []:.
Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto
Organizational Unit Name (eg, section) []:.
Common Name (eg, YOUR name) []:S/MIME Sender
Email Address []:sender@example.dom
This generates a 1024-bit RSA key pair, unencrypted, into
``privkey.pem``; it also generates a self-signed X.509 certificate for
the public key into ``signer.pem``. The certificate is valid for 365
days, i.e., a year.
Let's rename ``privkey.pem`` so that we know it is a companion of
``signer.pem``'s::
mv privkey.pem signer_key.pem
To verify the content of ``signer.pem``, execute the following::
openssl x509 -noout -text -in signer.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 0 (0x0)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=SG, O=M2Crypto, CN=S/MIME Sender/Email=sender@example.dom
Validity
Not Before: Mar 24 12:56:16 2001 GMT
Not After : Mar 24 12:56:16 2002 GMT
Subject: C=SG, O=M2Crypto, CN=S/MIME Sender/Email=sender@example.dom
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:a9:d6:e2:b5:11:3b:ae:3c:e2:17:31:70:e1:6e:
01:f4:19:6d:bd:2a:42:36:2b:37:34:e2:83:1d:0d:
11:2e:b4:99:44:db:10:67:be:97:5f:5b:1a:26:33:
46:23:2f:95:04:7a:35:da:9d:f9:26:88:39:9e:17:
cd:3e:eb:a8:19:8d:a8:2a:f1:43:da:55:a9:2e:2c:
65:ed:04:71:42:ce:73:53:b8:ea:7e:c7:f0:23:c6:
63:c5:5e:68:96:64:a7:b4:2a:94:26:76:eb:79:ea:
e3:4e:aa:82:09:4f:44:87:4a:12:62:b5:d7:1f:ca:
f2:ce:d5:ba:7e:1f:48:fd:b9
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
29:FB:38:B6:BF:E2:40:BB:FF:D5:71:D7:D5:C4:F0:83:1A:2B:C7:99
X509v3 Authority Key Identifier:
keyid:29:FB:38:B6:BF:E2:40:BB:FF:D5:71:D7:D5:C4:F0:83:1A:2B:C7:99
DirName:/C=SG/O=M2Crypto/CN=S/MIME Sender/Email=sender@example.dom
serial:00
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: md5WithRSAEncryption
68:c8:6b:1b:fa:7c:9a:39:35:76:18:15:c9:fd:89:97:62:db:
7a:b0:2d:13:dd:97:e8:1b:7a:9f:22:27:83:24:9d:2e:56:ec:
97:89:3c:ef:16:55:80:5a:18:7c:22:d0:f6:bb:e3:a4:e8:59:
30:ff:99:5a:93:3e:ea:bc:ee:7f:8d:d6:7d:37:8c:ac:3d:74:
80:ce:7a:99:ba:27:b9:2a:a3:71:fa:a5:25:ba:47:17:df:07:
56:96:36:fd:60:b9:6c:96:06:e8:e3:7b:9f:4b:6a:95:71:a8:
34:fc:fc:b5:88:8b:c4:3f:1e:24:f6:52:47:b2:7d:44:67:d9:
83:e8
Next, we generate a self-signed X.509 certificate for the recipient.
Note that ``privkey.pem`` will be recreated::
openssl req -newkey rsa:1024 -nodes -x509 -days 365 -out recipient.pem
Using configuration from /usr/local/pkg/openssl/openssl.cnf
Generating a 1024 bit RSA private key
.....................................++++++
.................++++++
writing new private key to 'privkey.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:SG
State or Province Name (full name) [Some-State]:.
Locality Name (eg, city) []:.
Organization Name (eg, company) [Internet Widgits Pty Ltd]:M2Crypto
Organizational Unit Name (eg, section) []:.
Common Name (eg, YOUR name) []:S/MIME Recipient
Email Address []:recipient@example.dom
Again, rename ``privkey.pem``::
mv privkey.pem recipient_key.pem
In the examples to follow, S/MIME Sender, ````,
shall be the sender of S/MIME messages, while S/MIME Recipient,
````, shall be the recipient of S/MIME messages.
Armed with the key pairs and certificates, we are now ready to begin
programming S/MIME in Python.
**Note:** The private keys generated above are *not
passphrase-protected*, i.e., they are *in the clear*. Anyone who has
access to such a key can generate S/MIME-signed messages with it,
and decrypt S/MIME messages encrypted to it's corresponding public
key.
We may passphrase-protect the keys, if we so choose. M2Crypto will
prompt the user for the passphrase when such a key is being loaded.
M2Crypto.SMIME
==============
The Python programmer accesses M2Crypto's S/MIME functionality through
class ``SMIME`` in the module ``M2Crypto.SMIME``. Typically, an
``SMIME`` object is instantiated; the object is then set up for the
intended operation: sign, encrypt, decrypt or verify; finally, the
operation is invoked on the object.
``M2Crypto.SMIME`` makes extensive use of ``M2Crypto.BIO``:
``M2Crypto.BIO`` is a Python abstraction of the ``BIO`` abstraction in
OpenSSL. A commonly used ``BIO`` abstraction in M2Crypto is
``M2Crypto.BIO.MemoryBuffer``, which implements a memory-based file-like
object, similar to Python's own ``StringIO``.
Sign
====
The following code demonstrates how to generate an S/MIME-signed
message. ``randpool.dat`` contains random data which is used to seed
OpenSSL's pseudo-random number generator via M2Crypto::
from M2Crypto import BIO, Rand, SMIME
def makebuf(text):
return BIO.MemoryBuffer(text)
# Make a MemoryBuffer of the message.
buf = makebuf('a sign of our times')
# Seed the PRNG.
Rand.load_file('randpool.dat', -1)
# Instantiate an SMIME object; set it up; sign the buffer.
s = SMIME.SMIME()
s.load_key('signer_key.pem', 'signer.pem')
p7 = s.sign(buf, SMIME.PKCS7_DETACHED)
``p7`` now contains a *PKCS #7 signature blob* wrapped in an
``M2Crypto.SMIME.PKCS7`` object. Note that ``buf`` has been consumed by
``sign()`` and has to be recreated if it is to be used again.
We may now send the signed message via SMTP. In these examples, we shall
not do so; instead, we'll render the S/MIME output in mail-friendly
format, and pretend that our messages are sent and received
correctly::
# Recreate buf.
buf = makebuf('a sign of our times')
# Output p7 in mail-friendly format.
out = BIO.MemoryBuffer()
out.write('From: sender@example.dom\n')
out.write('To: recipient@example.dom\n')
out.write('Subject: M2Crypto S/MIME testing\n')
s.write(out, p7, buf)
print(out.read())
# Save the PRNG's state.
Rand.save_file('randpool.dat')
Here's the output::
From: sender@example.dom
To: recipient@example.dom
Subject: M2Crypto S/MIME testing
MIME-Version: 1.0
Content-Type: multipart/signed ; protocol="application/x-pkcs7-signature" ; micalg=sha1 ; boundary="----3C93156FC7B4EBF49FE9C7DB7F503087"
This is an S/MIME signed message
------3C93156FC7B4EBF49FE9C7DB7F503087
a sign of our times
------3C93156FC7B4EBF49FE9C7DB7F503087
Content-Type: application/x-pkcs7-signature; name="smime.p7s"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.p7s"
MIIE8AYJKoZIhvcNAQcCoIIE4TCCBN0CAQExCzAJBgUrDgMCGgUAMCIGCSqGSIb3
DQEHAaAVBBNhIHNpZ24gb2Ygb3VyIHRpbWVzoIIC5zCCAuMwggJMoAMCAQICAQAw
DQYJKoZIhvcNAQEEBQAwWzELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRv
MRYwFAYDVQQDEw1TL01JTUUgU2VuZGVyMSEwHwYJKoZIhvcNAQkBFhJzZW5kZXJA
ZXhhbXBsZS5kb20wHhcNMDEwMzMxMTE0MDMzWhcNMDIwMzMxMTE0MDMzWjBbMQsw
CQYDVQQGEwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBT
ZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbTCBnzANBgkq
hkiG9w0BAQEFAAOBjQAwgYkCgYEA5c5Tj1CHTSOxa1q2q0FYiwMWYHptJpJcvtZm
UwrgU5sHrA8OnCM0cDXEj0KPf3cfNjHffB8HWMzI4UEgNmFXQNsxoGZ+iqwxLlNj
y9Mh7eFW/Bjq5hNXbouSlQ0rWBRkoxV64y+t6lQehb32WfYXQbKFxFJSXzSxOx3R
8YhSPd0CAwEAAaOBtjCBszAdBgNVHQ4EFgQUXOyolL1t4jaBwZFRM7MS8nBLzUow
gYMGA1UdIwR8MHqAFFzsqJS9beI2gcGRUTOzEvJwS81KoV+kXTBbMQswCQYDVQQG
EwJTRzERMA8GA1UEChMITTJDcnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIx
ITAfBgkqhkiG9w0BCQEWEnNlbmRlckBleGFtcGxlLmRvbYIBADAMBgNVHRMEBTAD
AQH/MA0GCSqGSIb3DQEBBAUAA4GBAHo3DrCHR86fSTVAvfiXdSswWqKtCEhUHRdC
TLFGl4hDk2GyZxaFuqZwiURz/H7nMicymI2wkz8H/wyHFg8G3BIehURpj2v/ZWXY
eovbgS7EZALVVkDj4hNl/IIHWd6Gtv1UODf7URbxtl3hQ9/eTWITrefT1heuPnar
8czydsOLMYIBujCCAbYCAQEwYDBbMQswCQYDVQQGEwJTRzERMA8GA1UEChMITTJD
cnlwdG8xFjAUBgNVBAMTDVMvTUlNRSBTZW5kZXIxITAfBgkqhkiG9w0BCQEWEnNl
bmRlckBleGFtcGxlLmRvbQIBADAJBgUrDgMCGgUAoIGxMBgGCSqGSIb3DQEJAzEL
BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTAxMDMzMTExNDUwMlowIwYJKoZI
hvcNAQkEMRYEFOoeRUd8ExIYXfQq8BTFuKWrSP3iMFIGCSqGSIb3DQEJDzFFMEMw
CgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsO
AwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIGAQpU8hFUtLCF6hO2t
ec9EYJ/Imqqiiw+BxWxkUUVT81Vbjwdn9JST6+sztM5JRP2ZW+b4txEjZriYC8f3
kv95YMTGbIsuWkJ93GrbvqoJ/CxO23r9WWRnZEm/1EZN9ZmlrYqzBTxnNRmP3Dhj
cW8kzZwH+2/2zz2G7x1HxRWH95A=
------3C93156FC7B4EBF49FE9C7DB7F503087--
Verify
======
Assume the above output has been saved into ``sign.p7``. Let's now
verify the signature::
from M2Crypto import SMIME, X509
# Instantiate an SMIME object.
s = SMIME.SMIME()
# Load the signer's cert.
x509 = X509.load_cert('signer.pem')
sk = X509.X509_Stack()
sk.push(x509)
s.set_x509_stack(sk)
# Load the signer's CA cert. In this case, because the signer's
# cert is self-signed, it is the signer's cert itself.
st = X509.X509_Store()
st.load_info('signer.pem')
s.set_x509_store(st)
# Load the data, verify it.
p7, data = SMIME.smime_load_pkcs7('sign.p7')
v = s.verify(p7, data)
print(v)
print(data)
print(data.read())
Here's the output of the above program::
a sign of our times
a sign of our times
Suppose, instead of loading ``signer.pem`` above, we load
``recipient.pem``. That is, we do a global substitution of
``recipient.pem`` for ``signer.pem`` in the above program. Here's the
modified program's output::
Traceback (most recent call last):
File "./verify.py", line 22, in ?
v = s.verify(p7)
File "/usr/local/home/ngps/prog/m2/M2Crypto/SMIME.py", line 205, in verify
raise SMIME_Error, Err.get_error()
M2Crypto.SMIME.SMIME_Error: 312:error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error:pk7_smime.c:213:Verify error:self signed certificate
As displayed, the error is generated by line 213 of OpenSSL's
``pk7_smime.c`` (as of OpenSSL 0.9.6); if you are a C programmer, you
may wish to look up the C source to explore OpenSSL's S/MIME
implementation and understand why the error message is worded thus.
Encrypt
=======
We now demonstrate how to generate an S/MIME-encrypted message::
from M2Crypto import BIO, Rand, SMIME, X509
def makebuf(text):
return BIO.MemoryBuffer(text)
# Make a MemoryBuffer of the message.
buf = makebuf('a sign of our times')
# Seed the PRNG.
Rand.load_file('randpool.dat', -1)
# Instantiate an SMIME object.
s = SMIME.SMIME()
# Load target cert to encrypt to.
x509 = X509.load_cert('recipient.pem')
sk = X509.X509_Stack()
sk.push(x509)
s.set_x509_stack(sk)
# Set cipher: 3-key triple-DES in CBC mode.
s.set_cipher(SMIME.Cipher('des_ede3_cbc'))
# Encrypt the buffer.
p7 = s.encrypt(buf)
# Output p7 in mail-friendly format.
out = BIO.MemoryBuffer()
out.write('From: sender@example.dom\n')
out.write('To: recipient@example.dom\n')
out.write('Subject: M2Crypto S/MIME testing\n')
s.write(out, p7)
print(out.read())
# Save the PRNG's state.
Rand.save_file('randpool.dat')
Here's the output of the above program::
From: sender@example.dom
To: recipient@example.dom
Subject: M2Crypto S/MIME testing
MIME-Version: 1.0
Content-Disposition: attachment; filename="smime.p7m"
Content-Type: application/x-pkcs7-mime; name="smime.p7m"
Content-Transfer-Encoding: base64
MIIBVwYJKoZIhvcNAQcDoIIBSDCCAUQCAQAxggEAMIH9AgEAMGYwYTELMAkGA1UE
BhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRkwFwYDVQQDExBTL01JTUUgUmVjaXBp
ZW50MSQwIgYJKoZIhvcNAQkBFhVyZWNpcGllbnRAZXhhbXBsZS5kb20CAQAwDQYJ
KoZIhvcNAQEBBQAEgYCBaXZ+qjpBEZwdP7gjfzfAtQitESyMwo3i+LBOw6sSDir6
FlNDPCnkrTvqDX3Rt6X6vBtTCYOm+qiN7ujPkOU61cN7h8dvHR8YW9+0IPY80/W0
lZ/HihSRgwTNd7LnxUUcPx8YV1id0dlmP0Hz+Lg+mHf6rqaR//JcYhX9vW4XvjA7
BgkqhkiG9w0BBwEwFAYIKoZIhvcNAwcECMN+qya6ADywgBgHr9Jkhwn5Gsdu7BwX
nIQfYTYcdL9I5Sk=
Decrypt
=======
Assume the above output has been saved into ``encrypt.p7``. Decrypt the
message thusly::
from M2Crypto import BIO, SMIME, X509
# Instantiate an SMIME object.
s = SMIME.SMIME()
# Load private key and cert.
s.load_key('recipient_key.pem', 'recipient.pem')
# Load the encrypted data.
p7, data = SMIME.smime_load_pkcs7('encrypt.p7')
# Decrypt p7.
out = s.decrypt(p7)
print(out)
Here's the output::
a sign of our times
It is also possible to decrypt a message message from a string, without reading it from a file first::
from M2Crypto import SMIME, BIO
# Instantiate an SMIME object.
s = SMIME.SMIME()
# Load private key and cert.
s.load_key('private_key.pkcs7.pem', 'public_key.pkcs7.pem')
# The Encrypted data
data_raw = "MIIBeQYJKoZIhvcNAQcDoIIBajCCAWYCAQAxggEhMIIBHQIBADAFMAACAQEwDQYJKoZIhvcNAQEBBQAEggEAL3r2KUEnR+Ds7lunkNUAEYWqiyppvZipjoCobD1FFF+WdFoaHcxJ/p18EaHfgXVgQ9tIPmEVfbVnxB406rrVEN9dZIrHyHBszl8G5xGcwQpbiYmQgS9cJc7P9Ya/qSwc7fzKAi4eoUfr7BALl3qWI1X+R2KNShDaUoa21c0XehHu0Qb6d2hScEdTulpGhGUaTkwMN4ZJmA60enG7xhSW8RIyZLTx7glRaaI/hEP0LsfkfI+kpKNQ8u52s816/tih5hiVtvpipWOyBU+L3OHVbGy4uzb9vMGO22KDm7Dev9wYs2EzHQry/u33ygdHzZwYwAM5Dm1js3cnJ5vsJdME5zA8BgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBC21FrAYYgygBf8j3Qxflb1gBASekTx2RHk+wRH3Gc0KA09"
# Add relevant headers, newlines that separate header and data, and trailing newline.
data = f"Content-Type: application/x-pkcs7-mime; name=\"smime.p7m\"\n\n{data_raw}\n".encode()
# Load data into a BIO.
bio = BIO.MemoryBuffer(data)
# Load bio data into an SMIME object.
p7, _data = SMIME.smime_load_pkcs7_bio(bio)
# Decrypt p7.
out = s.decrypt(p7)
print(out)
Sign and Encrypt
================
Here's how to generate an S/MIME-signed/encrypted message::
from M2Crypto import BIO, Rand, SMIME, X509
def makebuf(text):
return BIO.MemoryBuffer(text)
# Make a MemoryBuffer of the message.
buf = makebuf('a sign of our times')
# Seed the PRNG.
Rand.load_file('randpool.dat', -1)
# Instantiate an SMIME object.
s = SMIME.SMIME()
# Load signer's key and cert. Sign the buffer.
s.load_key('signer_key.pem', 'signer.pem')
p7 = s.sign(buf)
# Load target cert to encrypt the signed message to.
x509 = X509.load_cert('recipient.pem')
sk = X509.X509_Stack()
sk.push(x509)
s.set_x509_stack(sk)
# Set cipher: 3-key triple-DES in CBC mode.
s.set_cipher(SMIME.Cipher('des_ede3_cbc'))
# Create a temporary buffer.
tmp = BIO.MemoryBuffer()
# Write the signed message into the temporary buffer.
s.write(tmp, p7)
# Encrypt the temporary buffer.
p7 = s.encrypt(tmp)
# Output p7 in mail-friendly format.
out = BIO.MemoryBuffer()
out.write('From: sender@example.dom\n')
out.write('To: recipient@example.dom\n')
out.write('Subject: M2Crypto S/MIME testing\n')
s.write(out, p7)
print(out.read())
# Save the PRNG's state.
Rand.save_file('randpool.dat')
Here's the output of the above program::
From: sender@example.dom
To: recipient@example.dom
Subject: M2Crypto S/MIME testing
MIME-Version: 1.0
Content-Disposition: attachment; filename="smime.p7m"
Content-Type: application/x-pkcs7-mime; name="smime.p7m"
Content-Transfer-Encoding: base64
MIIIwwYJKoZIhvcNAQcDoIIItDCCCLACAQAxggEAMIH9AgEAMGYwYTELMAkGA1UE
BhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRkwFwYDVQQDExBTL01JTUUgUmVjaXBp
ZW50MSQwIgYJKoZIhvcNAQkBFhVyZWNpcGllbnRAZXhhbXBsZS5kb20CAQAwDQYJ
KoZIhvcNAQEBBQAEgYBlZlGupFphwhsGtIAPvDExN61qisz3oem88xoXkUW0SzoR
B9zJFFAuQTWzdNJgrKKYikhWjDojaAc/PFl1K5dYxRgtZLB36ULJD/v/yWmxnjz8
TvtK+Wbal2P/MH2pZ4LVERXa/snTElhCawUlwtiFz/JvY5CiF/dcwd+AwFQq4jCC
B6UGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIRF525UfwszaAggeA85RmX6AXQMxb
eBDz/LJeCgc3RqU1UwIsbKMquIs1S46Ebbm5nP75izPnujOkJ2hv+LNzqOWADmOl
+CnGEq1qxTyduIgUDA2nBgCL/gVyVy+/XC9dtImUUTxtxLgYtB0ujkBNsOaENOlM
fv4SGM3jkR+K/xlYG6HHzZGbfYyNGj2Y7yMZ1rL1m8SnRNmkCysKGTrudeNf6wT9
J6wO9DzLTioz3ZnVr3LjsSKIb4tIp4ugqNJaLuW7m3FtZ3MAgxN68hBbJs8TZ8tL
V/0jwUqS+grcgZEb9ymfcedxahtDUfHjRkpDpsxZzVVGkSBNcbQu92oByQVnRQ8m
wrYLp3/eawM5AvuV7HNpTT5ZR+1t8luishHN9899IMP2Vyg0Ub67FqFypYmM2cm2
sjAI4KpfvT00XFNvgLuYwYEKs9syGTO7hiHNQKcF44F5LYv6nTFwmFQB11dAtY9V
ull4D2CLDx9OvyNyKwdEZB5dyV0r/uKIdkhST60V2Q9KegpzgFpoZtSKM/HPYSVH
1Bc9f3Q/GqZCvNZZCMx8UvRjQR8dRWDSmPJ0VXG1+wJ+fCmSPP3AuQ1/VsgPRqx2
56VrpGPpGut40hV8xQFbWIZ2whwWLKPFAHj8B79ZtFUzUrU6Z2rNpvv8inHc/+S/
b6GR5s8/gucRblvd7n3OFNX5UJmPmcw9zWbu/1Dr9DY8l0nAQh21y5FGSS8B1wdE
oD2M3Lp7JbwjQbRtnDhImqul2S4yu+m+wDD1aR2K4k3GAI7KKgOBWT0+BDClcn8A
4Ju6/YUbj33YlMPJgnGijLnolFy0hNW7TmWqR+8tSI3wO5eNKg4qwBnarqc3vgCV
quVxINAXyGQCO9lzdw6hudk8/+BlweGdqhONaIWbK5z1L/SfQo6LC9MTsj7FJydq
bc+kEbfZS8aSq7uc9axW6Ti0eAPJ8EVHtwhSBgZQRweKFBXs6HbbhMIdc4N0M7Oq
UiFXaF6s4n2uihVP6TqXtHEjTpZoC7pC+HCYiuKXUJtaqtXBOh+y3KLvHk09YL6D
XmTDg+UTiFsh4jKKm/BhdelbR5JbpJcj5AId76Mfr8+F/1g9ePOvsWHpQr/oIQTo
xEkaxCmzEgP0b6caMWfMUQrbVGxBBNcqKc/ir9fGGOPHATzzq/xLcQYvK1tZhd/D
ah/gpMPndsyvVCEuFPluWyDiM0VkwHgC2/3pJIYFHaxK64IutmPsy393rHMEB4kN
AHau6kWK+yL9qEVH1pP2zvswQ12P7gjt3T/G3bGsmvlXkEfztfjkXo6XnjcBNf5y
G+974AKLcjnk1gzIgarz+lAMY57Gkw4oNDMrTqVQ2OJQlvOSbllPXzH+aAiavB8W
ZPECLLwHxD4B1AuaiAArgKl935u/TOB+yQOR8JgGsUzROyJqHJ/SC51HkebgCkL1
aggtjgPlIBEXLZAlhpWLZ9lAQyrQpvCVJYwaOvfMmvRav4NAFNoZ2/Q7S4Tn1z+U
XX+f+GD58P4MPMhU5IKnz4yH4nlHnAiTEvcs85TZUAXze9g/uBOwZITeGtyLi52S
aETIr4v7SgXMepX7ThQ1Pv/jddsK/u4j2F34u0XktwCP+UrbfkE2mocdXvdzxbmd
tZSznK2qwgVSsPOs9MhUaepbnjmNBFFBrULhrUtSglM/VX/rWNiyh0aw4XYyHhIt
9ZNlfEjKjJ67VEMBxBJ/ieUCouRGCxPYD1j65VT7oB3ZiyPu2F2nlUIcYNqPg1Sd
QBCrdaOXdJ0uLwyTAUeVE+wMbgscLvWsfZcCCJHAvw9NHFMUcnrdWxAYMVETNUOn
uryVAK7VfOldaz6z3NOSOi6nonNeHpR/sipBa4ik5xCRLT9e0S2QJgRvO9GyfAqz
3DIzHtxIGePFzTiUYUTxS3i2gnMX2PEe3ChTLlYWD3jNeAKz0iOzpDphIF2xHLLQ
1tCAqBmq/vUzALyDFFdFuTIqQZys4z/u4Dmyq9uXs421eN3v2hkVHvDy8uT2Ot29
lg4Q5YezR1EjaW//9guL1BXbcKrTEdtxeNqtem7SpZOMTSwD2lhB8z65GrX90Cyt
EMmaRSGYEdf5h1afL1SmKOMskbqxe1D2jG/vsXC7XX7xO/ioy0BdiJcYN1JiMOHJ
EOzFol5I20YkiV6j+cenfQFwc/NkaSxEkR8AUHJSbvUmRQRl6r0nnsFpZdR1w7pv
wkaT+eOpZynO4mY/ZtF6MpXJsixi6L4ZYXEbS6yHf+XGFfB0okILylmwv2bf6+Mq
nqXlmGj3Jwq7X9/+2BDqvfpFFX5lSmItKZAobLdssjFR6roJxOqRsGia2aZ+0+U5
VhgdITtnElgtHBaeZU5rHDswgdeLVBP+rGWnKxpJ+pLtNNi25sPYRcWFL6Erd25u
eXiY8GEIr+u7rqBWpc9HR34sAPRs3ubbCUleT748keCbx247ImBtiDctZxcc1O86
+0QjHP6HUT7FSo/FmT7a120S3Gd2jixGh06l/9ij5Z6mJa7Rm7TTbSjup/XISnOT
MKWcbI1nfVOhCv3xDq2eLae+s0oVoc041ceRazqFM2TL/Z6UXRME
Decrypt and Verify
==================
Suppose the above output has been saved into ``se.p7``. The following
demonstrates how to decrypt and verify it::
from M2Crypto import BIO, SMIME, X509
# Instantiate an SMIME object.
s = SMIME.SMIME()
# Load private key and cert.
s.load_key('recipient_key.pem', 'recipient.pem')
# Load the signed/encrypted data.
p7, data = SMIME.smime_load_pkcs7('se.p7')
# After the above step, 'data' == None.
# Decrypt p7. 'out' now contains a PKCS #7 signed blob.
out = s.decrypt(p7)
# Load the signer's cert.
x509 = X509.load_cert('signer.pem')
sk = X509.X509_Stack()
sk.push(x509)
s.set_x509_stack(sk)
# Load the signer's CA cert. In this case, because the signer's
# cert is self-signed, it is the signer's cert itself.
st = X509.X509_Store()
st.load_info('signer.pem')
s.set_x509_store(st)
# Recall 'out' contains a PKCS #7 blob.
# Transform 'out'; verify the resulting PKCS #7 blob.
p7_bio = BIO.MemoryBuffer(out)
p7, data = SMIME.smime_load_pkcs7_bio(p7_bio)
v = s.verify(p7)
print(v)
The output is as follows::
a sign of our times
Sending S/MIME messages via SMTP
================================
In the above examples, we've assumed that our S/MIME messages are sent
and received automagically. The following is a Python function that
generates S/MIME-signed/encrypted messages and sends them via
SMTP::
from M2Crypto import BIO, SMIME, X509
import smtplib, string, sys
def sendsmime(from_addr, to_addrs, subject, msg, from_key, from_cert=None, to_certs=None, smtpd='localhost'):
msg_bio = BIO.MemoryBuffer(msg)
sign = from_key
encrypt = to_certs
s = SMIME.SMIME()
if sign:
s.load_key(from_key, from_cert)
if encrypt:
p7 = s.sign(msg_bio, flags=SMIME.PKCS7_TEXT)
else:
p7 = s.sign(msg_bio, flags=SMIME.PKCS7_TEXT|SMIME.PKCS7_DETACHED)
msg_bio = BIO.MemoryBuffer(msg) # Recreate coz sign() has consumed it.
if encrypt:
sk = X509.X509_Stack()
for x in to_certs:
sk.push(X509.load_cert(x))
s.set_x509_stack(sk)
s.set_cipher(SMIME.Cipher('des_ede3_cbc'))
tmp_bio = BIO.MemoryBuffer()
if sign:
s.write(tmp_bio, p7)
else:
tmp_bio.write(msg)
p7 = s.encrypt(tmp_bio)
out = BIO.MemoryBuffer()
out.write('From: %s\r\n' % from_addr)
out.write('To: %s\r\n' % string.join(to_addrs, ", "))
out.write('Subject: %s\r\n' % subject)
if encrypt:
s.write(out, p7)
else:
if sign:
s.write(out, p7, msg_bio, SMIME.PKCS7_TEXT)
else:
out.write('\r\n')
out.write(msg)
out.close()
smtp = smtplib.SMTP()
smtp.connect(smtpd)
smtp.sendmail(from_addr, to_addrs, out.read())
smtp.quit()
This function sends plain, S/MIME-signed, S/MIME-encrypted, and
S/MIME-signed/encrypted messages, depending on the parameters
``from_key`` and ``to_certs``. The function's output interoperates with
Netscape Messenger.
Verifying origin of S/MIME messages
===================================
In our examples above that decrypt or verify messages, we skipped a
step: verifying that the ``from`` address of the message matches the
``email address`` attribute in the sender's certificate.
The premise of current X.509 certification practice is that the CA is
supposed to verify your identity, and to issue a certificate with
``email address`` that matches your actual mail address. (Verisign's
March 2001 failure in identity verification resulting in Microsoft
certificates being issued to spoofers notwithstanding.)
If you run your own CA, your certification practice is up to you, of
course, and it would probably be part of your security policy.
Whether your S/MIME messaging application needs to verify the ``from``
addresses of S/MIME messages depends on your security policy and your
system's threat model, as always.
Interoperating with Netscape Messenger
======================================
Suppose S/MIME Recipient uses Netscape Messenger. To enable Messenger to
handle S/MIME messages from S/MIME Sender, S/MIME Recipient needs to
configure Messenger with his private key and certificate, as well as
S/MIME Sender's certificate.
**Note:** Configuring Messenger's POP or IMAP settings so that it
retrieves mail correctly is beyond the scope of this HOWTO.
The following steps demonstrate how to import S/MIME Recipient's private
key and certificate for Messenger:
1. Transform S/MIME Recipient's private key and certificate into *PKCS
#12* format::
openssl pkcs12 -export -in recipient.pem -inkey recipient_key.pem \
-name "S/MIME Recipient" -out recipient.p12
Enter Export Password:
Verifying password - Enter Export Password:
2. Start Messenger.
3. Click on the (open) "lock" icon at the bottom left corner of
Messenger's window. This brings up the "Security Info" dialog box.
4. Click on "Yours" under "Certificates".
5. Select "Import a certificate", then pick ``recipient.p12`` from the
ensuing file selection dialog box.
Next, you need to import ``signer.pem`` as a CA certificate, so that
Messenger will mark messages signed by S/MIME Sender as "trusted":
1. Create a DER encoding of ``signer.pem``::
openssl x509 -inform pem -outform der -in signer.pem -out signer.der
2. Install ``signer.der`` into Messenger as MIME type
``application/x-x509-ca-cert``. You do this by downloading
``signer.der`` via Navigator from a HTTP or HTTPS server, with the
correct MIME type mapping. (You may use ``demo/ssl/https_srv.py``,
bundled with M2Crypto, for this purpose.) Follow the series of dialog
boxes to accept ``signer.der`` as a CA for certifying email users.
S/MIME Recipient is now able to decrypt and read S/MIME Sender's
messages with Messenger. Messenger will indicate that S/MIME Sender's
messages are signed, encrypted, or encrypted *and* signed, as the case
may be, via the "stamp" icon on the message window's top right corner.
Clicking on the "stamp" icon brings you to the Security Info dialog box.
Messenger informs you that the message is, say, encrypted with 168-bit
DES-EDE3-CBC and that it is digitally signed by the private key
corresponding to the public key contained in the certificate
``signer.pem``.
Interoperating with Microsoft Outlook
=====================================
I do not know how to do this, as I do not use Outlook. (Nor do I use
Netscape Messenger, actually. I use Mutt, top dog of MUAs. ;-)
Information on how to configure Outlook with keys and certificates so
that it handles S/MIME mail is gratefully accepted.
ZSmime
======
ZSmime is a `Zope `__ *product* that enables Zope
to generate S/MIME-signed/encrypted messages. ZSmime demonstrates how to
invoke M2Crypto in a web application server extension.
ZSmime has its own
`HOWTO `__
explaining its usage. (That HOWTO has some overlap in content with this
document.)
Resources
=========
- IETF S/MIME Working Group - http://www.imc.org/ietf-smime
- S/MIME and OpenPGP - http://www.imc.org/smime-pgpmime.html
- S/MIME Freeware Library -
http://www.getronicsgov.com/hot/sfl_home.htm
- Mozilla Network Security Services -
http://www.mozilla.org/projects/security/pkg/nss
- S/MIME Cracking Screen Saver - http://www.counterpane.com/smime.html
m2crypto-0.42.0/doc/howto.ssl.rst 0000664 0000000 0000000 00000012460 14655756567 0016650 0 ustar 00root root 0000000 0000000 :orphan:
.. _howto-ssl:
HOWTO: Programming SSL in Python with M2Crypto
##############################################
:author: Pheng Siong Ng and Heikki Toivonen (heikki@osafoundation.org)
:copyright: © 2000, 2001 by Ng Pheng Siong,
portions © 2006 by Open Source Applications Foundation
Introduction
============
`M2Crypto `__ is a `Python
`__ interface to `OpenSSL
`__. It makes available to the Python
programmer SSL functionality to implement clients and servers,
S/MIME v2, RSA, DSA, DH, symmetric ciphers, message digests and
HMACs.
This document demonstrates programming HTTPS with M2Crypto.
A bit of history
================
M2Crypto was created during the time of Python 1.5, which features a
module httplib providing client-side HTTP functionality. M2Crypto sports
a httpslib based on httplib.
Beginning with version 2.0, Python's socket module provided
(rudimentary) SSL support. Also in the same version, httplib was
enhanced with class HTTPConnection, which is more sophisticated than the
old class HTTP, and HTTPSConnection, which does HTTPS.
Subsequently, M2Crypto.httpslib grew a compatible (but not identical)
class HTTPSConnection.
The primary interface difference between the two HTTPSConnection classes
is that M2Crypto's version accepts an M2Crypto.SSL.Context instance as a
parameter, whereas Python 2.x's SSL support does not permit Pythonic
control of the SSL context.
Within the implementations, Python's ``HTTPSConnection`` employs a
``FakeSocket`` object, which collects all input from the SSL connection
before returning it to the application as a ``StringIO`` buffer, whereas
M2Crypto's ``HTTPSConnection`` uses a buffering
``M2Crypto.BIO.IOBuffer`` object that works over the underlying
M2Crypto.SSL.Connection directly.
Since then M2Crypto has gained a Twisted wrapper that allows securing
Twisted SSL connections with M2Crypto.
Secure SSL
==========
It is recommended that you read the book Network Security with OpenSSL
by John Viega, Matt Messier and Pravir Chandra, ISBN 059600270X.
Using M2Crypto does not automatically make an SSL connection secure.
There are various steps that need to be made before we can make that
claim. Let's see how a simple client can establish a secure
connection::
ctx = SSL.Context()
ctx.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, depth=9)
if ctx.load_verify_locations('ca.pem') != 1: raise Exception('No CA certs')
s = SSL.Connection(ctx)
s.connect(server_address)
# Normal protocol (for example HTTP) commands follow
The first line creates an SSL context. The defaults allow any SSL
version (except SSL version 2 which has known weaknesses) and sets the
allowed ciphers to secure ones.
The second line tells M2Crypto to perform certificate validation. The
flags shown above are typical for clients, and requires the server to
send a certificate. The depth parameter tells how long certificate
chains are allowed - 9 is pretty common default, although probably too
long in practice.
The third line loads the allowed root (certificate authority or CA)
certificates. Most Linux distributions come with CA certificates in
suitable format. You could also download the
`certdata.txt `__
file from the
`NSS `__ project and
convert it with the little M2Crypto utility script
`demo/x509/certdata2pem.py `__.
The fourth line creates an SSL connection object with the secure
context.
The fifth line connects to the server. During this time we perform the
last security step: just after connection, but before exchanging any
data, we compare the commonName (or subjectAltName DNS field) field in
the certificate the server returned to the server address we tried to
connect to. This happens automatically with SSL.Connection and the
Twisted wrapper class, and anything that uses those. In all other cases
you must do the check manually. It is recommended you call the
SSL.Checker to do the actual check.
SSL servers are different in that they typically do not require the
client to send a certificate, so there is usually no certificate
checking. Also, it is typically useless to perform host name checking.
Code Samples
============
The best samples of how to use the various SSL objects are in the tests
directory, and the test\_ssl.py file specifically. There are additional
samples in the demo directory, but they are not quaranteed to be up to
date.
NOTE: The tests and demos may not be secure as is. Use the information
above on how to make them secure.
ssldump
=======
ssldump "is an SSLv3/TLS network protocol analyser. It identifies TCP
connections on the chosen network interface and attempts to interpret
them as SSLv3/TLS traffic. When it identifies SSLv3/TLS traffic, it
decodes the records and displays them in a textual form to stdout. If
provided with the appropriate keying material, it will also decrypt the
connections and display the application data traffic.
If linked with OpenSSL, ssldump can display certificates in decoded form
and decrypt traffic (provided that it has the appropriate keying
material)."
ssldump is written by Eric Rescorla.
m2crypto-0.42.0/doc/index.rst 0000664 0000000 0000000 00000000350 14655756567 0016012 0 ustar 00root root 0000000 0000000 Welcome to M2Crypto's documentation!
====================================
Contents:
.. toctree::
:maxdepth: 2
M2Crypto
HOWTOs
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
m2crypto-0.42.0/doc/make.bat 0000664 0000000 0000000 00000011754 14655756567 0015570 0 ustar 00root root 0000000 0000000 @ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^` where ^ is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\M2Crypto.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\M2Crypto.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end
m2crypto-0.42.0/doc/requirements.txt 0000664 0000000 0000000 00000000175 14655756567 0017442 0 ustar 00root root 0000000 0000000 cryptography>=42.0.5,==42.* # Needed to run the doctests in the migration docs
sphinx==7.2.6
sphinx-rtd-theme==2.0.0
twisted
m2crypto-0.42.0/pylintrc 0000664 0000000 0000000 00000020564 14655756567 0015204 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8; mode: conf -*-
# lint Python modules using external checkers.
#
# This is the main checker controlling the other ones and the reports
# generation. It is itself both a raw checker and an astng checker in order
# to:
# * handle message activation / deactivation at the module level
# * handle some basic but necessary stats'data (number of classes, methods...)
#
[MASTER]
# Specify a configuration file.
#rcfile=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Add to the black list. It should be a base name, not a
# path. You may set this option multiple times.
ignore=CVS, .git, .svn
# Pickle collected data for later comparisons.
persistent=yes
# Set the cache size for astng objects.
cache-size=500
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
[MESSAGES CONTROL]
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time. See also the "--disable" option for examples.
#enable=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=C0330, C0103, C0111, C0326, R0901, R0903, R0201, I0011
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
# (visual studio) and html. You can also give a reporter class, eg
# mypackage.mymodule.MyReporterClass.
output-format=text
# Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]".
files-output=no
# Tells whether to display a full report or only the messages
reports=yes
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
msg-template={path}:{line}:[{msg_id}({symbol}),{obj}] {msg}
[TYPECHECK]
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# List of classes names for which member attributes should not be checked
# (useful for classes with attributes dynamically set).
ignored-classes=SQLObject
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E0201 when accessed. Python regular
# expressions are accepted.
generated-members=REQUEST,acl_users,aq_parent
[VARIABLES]
# Tells whether we should check for unused import in __init__ files.
init-import=no
# A regular expression matching the beginning of the name of dummy variables
# (i.e. not used).
dummy-variables-rgx=_|dummy
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
[FORMAT]
# Maximum number of characters on a single line.
max-line-length=120
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )??$
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
# List of optional constructs for which whitespace checking is disabled
no-space-check=trailing-comma,dict-separator
# Maximum number of lines in a module
max-module-lines=2000
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
[BASIC]
# List of builtins function names that should not be used, separated by a comma
bad-functions=map,filter,apply,input
# Regular expression which should only match correct module names
# module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
module-rgx=(([a-z_][a-z0-9_]*)|([a-zA-Z0-9]+))$
# Regular expression which should only match correct module level names
const-rgx=[f]?[A-Z_][a-zA-Z0-9_]{2,30}$
# Regular expression which should only match correct class names
class-rgx=[A-Z_]+[a-zA-Z0-9]+$
# Regular expression which should only match correct function names
function-rgx=[a-z_][a-zA-Z0-9_]{2,30}$
# Regular expression which should only match correct method names
method-rgx=[a-zA-Z0-9_]{2,30}$
# Regular expression which should only match correct instance attribute names
attr-rgx=([a-z_][a-zA-Z0-9_]{2,30}|[A-Z0-9_]{2,30})$
# Regular expression which should only match correct argument names
argument-rgx=[a-z_][a-zA-Z0-9_]{2,30}$
# Regular expression which should only match correct variable names
variable-rgx=[a-z_][a-zA-Z0-9_]{0,30}$
# Regular expression which should only match correct attribute names in class
# bodies
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Regular expression which should only match correct list comprehension /
# generator expression variable names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
# Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,ex,Run,_
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=__.*__
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,XXX,TODO
[SIMILARITIES]
# Minimum lines number of a similarity.
min-similarity-lines=4
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
[DESIGN]
# Maximum number of arguments for function / method
max-args=8
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*
# Maximum number of locals for function / method body
max-locals=15
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of branch for function / method body
max-branches=12
# Maximum number of statements in function / method body
max-statements=50
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of attributes for a class (see R0902).
max-attributes=50
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
# Maximum number of public methods for a class (see R0904).
max-public-methods=100
[IMPORTS]
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception
m2crypto-0.42.0/pyproject.toml 0000664 0000000 0000000 00000000221 14655756567 0016315 0 ustar 00root root 0000000 0000000 [build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[tool.black]
line-length = 70
skip-string-normalization = true
m2crypto-0.42.0/requirements.txt 0000664 0000000 0000000 00000000172 14655756567 0016672 0 ustar 00root root 0000000 0000000 build
wheel; sys.platform == 'win32'
setuptools>=43.0.0; python_version<='3.6'
setuptools>=65.6.0; python_version>='3.10'
m2crypto-0.42.0/setup.cfg 0000664 0000000 0000000 00000002732 14655756567 0015233 0 ustar 00root root 0000000 0000000 [metadata]
name = M2Crypto
version = attr: M2Crypto.__version__
author = Ng Pheng Siong
author_email = ngps@sandbox.rulemaker.net
maintainer = Matej Cepl
maintainer_email = mcepl@cepl.eu
description = A Python crypto and SSL toolkit
long_description = file: README.rst
url = https://sr.ht/~mcepl/m2crypto/
keywords =
cryptography
openssl
license = MIT
classifiers =
Development Status :: 5 - Production/Stable
Intended Audience :: Developers
License :: OSI Approved :: MIT License
Operating System :: OS Independent
Programming Language :: C
Programming Language :: Python
Topic :: Security :: Cryptography
Topic :: Software Development :: Libraries :: Python Modules
Programming Language :: Python :: 3
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Programming Language :: Python :: 3.12
[options]
zip_safe = False
include_package_data = True
package_dir=
=src
packages = find:
install_requires =
importlib-metadata; python_version < "3.8"
[options.packages.find]
where=src
exclude =
contrib*
docs*
tests*
[options.package_data]
M2Crypto = *.dll
[egg_info]
tag_build =
tag_svn_revision = 0
[flake8]
; ignore = E402,E501,E731,N806,N803,N802,E265
ignore = E402,N806,N803,N802,E501
[pydocstyle]
ignore = D10,D203,D213
m2crypto-0.42.0/setup.py 0000664 0000000 0000000 00000025117 14655756567 0015126 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python
"""
setuptools based installer for M2Crypto.
Copyright (c) 1999-2004, Ng Pheng Siong. All rights reserved.
Portions created by Open Source Applications Foundation (OSAF) are
Copyright (C) 2004-2007 OSAF. All Rights Reserved.
Copyright 2008-2011 Heikki Toivonen. All rights reserved.
Copyright 2018 Daniel Wozniak. All rights reserved.
"""
import ctypes
import ctypes.util
import glob
import logging
import os
import platform
import re
import shlex
import shutil
import subprocess
import sys
import setuptools
from typing import Dict, List
if sys.version_info[:2] < (3, 10):
from distutils.command import build
from distutils.dir_util import mkpath
else:
from setuptools.command import build
from setuptools.command import build_ext
logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s',
level=logging.DEBUG)
log = logging.getLogger('setup')
requires_list = []
def _get_additional_includes():
if os.name == 'nt':
globmask = os.path.join('C:', os.sep, 'Program Files*',
'*Visual*', 'VC', 'include')
err = glob.glob(globmask)
else:
cpp = shlex.split(os.environ.get('CPP', 'cpp'))
pid = subprocess.Popen(cpp + ['-Wp,-v', '-'],
stdin=open(os.devnull, 'r'),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
_, err = pid.communicate()
err = [line.lstrip() for line in err.decode('utf8').split('\n')
if line and line.startswith(' /')]
log.debug('additional includes:\n%s', err)
return err
def openssl_version(ossldir, req_ver, required=False):
# type: (str, int, bool) -> bool
"""
Compare version of the installed OpenSSL with the maximum required version.
:param ossldir: the directory where OpenSSL is installed
:param req_ver: required version as integer (e.g. 0x10100000)
:param required: whether we want bigger-or-equal or less-than
:return: Boolean indicating whether the satisfying version of
OpenSSL has been installed.
"""
ver = None
try:
if sys.platform == 'win32':
found_lib = glob.glob(os.path.join(os.environ.get('OPENSSL_PATH'),
'libcrypto*.dll'))[0]
crypt_lib = ctypes.WinDLL(found_lib)
else:
crypt_lib = ctypes.cdll.LoadLibrary("libssl.so")
log.info(f'crypt_lib = {crypt_lib}')
except (AttributeError, FileNotFoundError):
ver = None
file = os.path.join(ossldir, 'include', 'openssl', 'opensslv.h')
with open(file) as origin_file:
for line in origin_file:
m = re.match(
r'^# *define *OPENSSL_VERSION_NUMBER *(0x[0-9a-fA-F]*)',
line)
if m:
log.debug('found version number: %s\n', m.group(1))
ver = int(m.group(1), base=16)
break
if ver is None:
raise OSError('Unknown format of file %s\n' % file)
else:
try:
ver = crypt_lib.OpenSSL_version_num()
except OSError:
pass
log.info(f'ctypes: ver = {ver:#0X}')
if required:
return ver >= req_ver
else:
return ver < req_ver
class _M2CryptoBuildExt(build_ext.build_ext):
"""Enable swig_opts to inherit any include_dirs settings made elsewhere."""
def initialize_options(self):
"""Overload to enable custom openssl settings to be picked up."""
build_ext.build_ext.initialize_options(self)
def finalize_options(self):
# type: (None) -> None
"""Append custom openssl include file and library linking options."""
build_ext.build_ext.finalize_options(self)
self.openssl_path = os.environ.get('OPENSSL_PATH', None)
self.bundledlls = os.environ.get('BUNDLEDLLS', None)
self.libraries = ['ssl', 'crypto']
if sys.platform == 'win32':
self.libraries = ['ssleay32', 'libeay32']
if self.openssl_path and openssl_version(self.openssl_path,
0x10100000, True):
self.libraries = ['libssl', 'libcrypto']
self.swig_opts.append('-D_WIN32')
# Swig doesn't know the version of MSVC, which causes
# errors in e_os2.h trying to import stdint.h. Since
# python 2.7 is intimately tied to MSVC 2008, it's
# harmless for now to define this. Will come back to
# this shortly to come up with a better fix.
self.swig_opts.append('-D_MSC_VER=1500')
log.debug('self.openssl_path = %s', self.openssl_path)
log.debug('self.bundledlls = %s', self.bundledlls)
# swig seems to need the default header file directories
self.swig_opts.extend(['-I%s' % i for i in _get_additional_includes()])
log.debug('self.include_dirs = %s', self.include_dirs)
log.debug('self.library_dirs = %s', self.library_dirs)
if self.openssl_path is not None:
log.debug('self.openssl_path = %s', self.openssl_path)
openssl_library_dir = os.path.join(self.openssl_path, 'lib')
openssl_include_dir = os.path.join(self.openssl_path, 'include')
self.library_dirs.append(openssl_library_dir)
self.include_dirs.append(openssl_include_dir)
log.debug('self.include_dirs = %s', self.include_dirs)
log.debug('self.library_dirs = %s', self.library_dirs)
if platform.system() == "Linux":
# For RedHat-based distros, the '-D__{arch}__' option for
# Swig needs to be normalized, particularly on i386.
mach = platform.machine().lower()
if mach in ('i386', 'i486', 'i586', 'i686'):
arch = '__i386__'
elif mach in ('ppc64', 'powerpc64', 'ppc64le', 'ppc64el'):
arch = '__powerpc64__'
elif mach in ('ppc', 'powerpc'):
arch = '__powerpc__'
else:
arch = '__%s__' % mach
self.swig_opts.append('-D%s' % arch)
if mach in ('ppc64le', 'ppc64el'):
self.swig_opts.append('-D_CALL_ELF=2')
if mach in ('arm64_be'):
self.swig_opts.append('-D__AARCH64EB__')
self.swig_opts.extend(['-I%s' % i for i in self.include_dirs])
# Some Linux distributor has added the following line in
# /usr/include/openssl/opensslconf.h:
#
# #include "openssl-x85_64.h"
#
# This is fine with C compilers, because they are smart enough to
# handle 'local inclusion' correctly. Swig, on the other hand, is
# not as smart, and needs to be told where to find this file...
#
# Note that this is risky workaround, since it takes away the
# namespace that OpenSSL uses. If someone else has similarly
# named header files in /usr/include, there will be clashes.
if self.openssl_path is None:
self.swig_opts.append('-I/usr/include/openssl')
else:
self.swig_opts.append(
'-I' + os.path.join(openssl_include_dir, 'openssl'))
self.swig_opts.append('-includeall')
self.swig_opts.append('-builtin')
build_dir = os.path.join(self.build_lib, 'M2Crypto')
os.makedirs(build_dir, exist_ok=True)
# These two lines are a workaround for
# http://bugs.python.org/issue2624 , hard-coding that we are only
# building a single extension with a known path; a proper patch to
# distutils would be in the run phase, when extension name and path are
# known.
self.swig_opts.extend(['-outdir', build_dir])
self.include_dirs.append(os.path.join(os.getcwd(), 'src', 'SWIG'))
if sys.platform == 'cygwin' and self.openssl_path is not None:
# Cygwin SHOULD work (there's code in distutils), but
# if one first starts a Windows command prompt, then bash,
# the distutils code does not seem to work. If you start
# Cygwin directly, then it would work even without this change.
# Someday distutils will be fixed and this won't be needed.
self.library_dirs += [os.path.join(self.openssl_path, 'bin')]
os.makedirs(os.path.join(self.build_lib, 'M2Crypto'), exist_ok=True)
def run(self):
"""
On Win32 platforms include the openssl dll's in the binary packages
"""
# Win32 bdist builds must set OPENSSL_PATH before the builds step.
if self.bundledlls is None:
build_ext.build_ext.run(self)
return
# self.bundledlls is set
if sys.platform == 'win32':
ver_part = ''
if self.openssl_path and openssl_version(self.openssl_path,
0x10100000, True):
ver_part += '-1_1'
if sys.maxsize > 2**32:
ver_part += '-x64'
search = list(self.library_dirs)
if self.openssl_path:
search = search + [self.openssl_path,
os.path.join(self.openssl_path, 'bin')]
libs = list(self.libraries)
for libname in list(libs):
for search_path in search:
dll_name = '{0}{1}.dll'.format(libname, ver_part)
dll_path = os.path.join(search_path, dll_name)
if os.path.exists(dll_path):
shutil.copy(dll_path, 'M2Crypto')
libs.remove(libname)
break
if libs:
raise Exception("Libs not found {}".format(','.join(libs)))
build_ext.build_ext.run(self)
x_comp_args = set()
# We take care of deprecated functions in OpenSSL with our code, no need
# to spam compiler output with it.
if sys.platform == 'win32':
x_comp_args.update(['-DTHREADING', '-D_CRT_SECURE_NO_WARNINGS'])
else:
x_comp_args.update(['-DTHREADING', '-Wno-deprecated-declarations'])
m2crypto = setuptools.Extension(name='M2Crypto._m2crypto',
sources=['src/SWIG/_m2crypto.i'],
extra_compile_args=list(x_comp_args),
# Uncomment to build Universal Mac binaries
# extra_link_args =
# ['-Wl,-search_paths_first'],
)
setuptools.setup(
ext_modules=[m2crypto],
cmdclass={
'build_ext': _M2CryptoBuildExt
}
)
m2crypto-0.42.0/src/ 0000775 0000000 0000000 00000000000 14655756567 0014175 5 ustar 00root root 0000000 0000000 m2crypto-0.42.0/src/M2Crypto/ 0000775 0000000 0000000 00000000000 14655756567 0015654 5 ustar 00root root 0000000 0000000 m2crypto-0.42.0/src/M2Crypto/ASN1.py 0000664 0000000 0000000 00000020646 14655756567 0016740 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""
M2Crypto wrapper for OpenSSL ASN1 API.
Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.
Portions created by Open Source Applications Foundation (OSAF) are
Copyright (C) 2005 OSAF. All Rights Reserved.
"""
import datetime
import time
from M2Crypto import BIO, m2, types as C
from typing import Optional, Union
MBSTRING_FLAG: int = 0x1000
MBSTRING_ASC: int = MBSTRING_FLAG | 1
MBSTRING_BMP: int = MBSTRING_FLAG | 2
class ASN1_Integer:
m2_asn1_integer_free = m2.asn1_integer_free
def __init__(
self, asn1int: Union[C.ASN1_Integer, int], _pyfree: int = 0
):
if isinstance(asn1int, int):
self.asn1int: C.ASN1_Integer = m2.asn1_integer_new()
m2.asn1_integer_set(self.asn1int, asn1int)
else:
self.asn1int = asn1int
self._pyfree = _pyfree
def __cmp__(self, other: "ASN1_Integer") -> int:
if not isinstance(other, ASN1_Integer):
raise TypeError(
"Comparisons supported only between ANS1_Integer objects"
)
return m2.asn1_integer_cmp(self.asn1int, other.asn1int)
def __del__(self) -> None:
if self._pyfree:
self.m2_asn1_integer_free(self.asn1int)
def __int__(self) -> int:
return m2.asn1_integer_get(self.asn1int)
class ASN1_String:
m2_asn1_string_free = m2.asn1_string_free
def __init__(
self, asn1str: Union[C.ASN1_String, str, bytes], _pyfree: int = 0
):
if isinstance(asn1str, str):
self.asn1str: C.ASN1_String = m2.asn1_string_new()
m2.asn1_string_set(self.asn1str, asn1str.encode())
elif isinstance(asn1str, bytes):
self.asn1str: C.ASN1_String = m2.asn1_string_new()
m2.asn1_string_set(self.asn1str, asn1str)
else:
self.asn1str = asn1str
self._pyfree = _pyfree
def __bytes__(self) -> bytes:
buf = BIO.MemoryBuffer()
m2.asn1_string_print(buf.bio_ptr(), self.asn1str)
return buf.read_all()
def __str__(self) -> str:
return self.__bytes__().decode()
def __del__(self) -> None:
if getattr(self, '_pyfree', 0):
self.m2_asn1_string_free(self.asn1str)
def _ptr(self):
return self.asn1str
def as_text(self, flags: int = 0) -> str:
"""Output an ASN1_STRING structure according to the set flags.
:param flags: determine the format of the output by using
predetermined constants, see ASN1_STRING_print_ex(3)
manpage for their meaning.
:return: output an ASN1_STRING structure.
"""
buf = BIO.MemoryBuffer()
m2.asn1_string_print_ex(buf.bio_ptr(), self.asn1str, flags)
return buf.read_all().decode()
class ASN1_Object:
m2_asn1_object_free = m2.asn1_object_free
def __init__(
self, asn1obj: C.ASN1_Object, _pyfree: int = 0
) -> None:
self.asn1obj = asn1obj
self._pyfree = _pyfree
def __del__(self) -> None:
if self._pyfree:
self.m2_asn1_object_free(self.asn1obj)
def _ptr(self):
return self.asn1obj
class _UTC(datetime.tzinfo):
def tzname(self, dt: Optional[datetime.datetime]) -> str:
return "UTC"
def dst(
self, dt: Optional[datetime.datetime]
) -> datetime.timedelta:
return datetime.timedelta(0)
def utcoffset(
self, dt: Optional[datetime.datetime]
) -> datetime.timedelta:
return datetime.timedelta(0)
def __repr__(self) -> str:
return "" % self.tzname(None)
UTC: _UTC = _UTC()
class LocalTimezone(datetime.tzinfo):
"""Localtimezone from datetime manual."""
def __init__(self) -> None:
self._stdoffset = datetime.timedelta(seconds=-time.timezone)
if time.daylight:
self._dstoffset = datetime.timedelta(
seconds=-time.altzone
)
else:
self._dstoffset = self._stdoffset
self._dstdiff = self._dstoffset - self._stdoffset
def utcoffset(self, dt: datetime.datetime) -> datetime.timedelta:
if self._isdst(dt):
return self._dstoffset
else:
return self._stdoffset
def dst(self, dt: datetime.datetime) -> datetime.timedelta:
if self._isdst(dt):
return self._dstdiff
else:
return datetime.timedelta(0)
def tzname(self, dt: datetime.datetime) -> str:
return time.tzname[self._isdst(dt).real]
def _isdst(self, dt: datetime.datetime) -> bool:
tt = (
dt.year,
dt.month,
dt.day,
dt.hour,
dt.minute,
dt.second,
dt.weekday(),
0,
-1,
)
stamp = time.mktime(tt)
tt = time.localtime(stamp)
return tt.tm_isdst > 0
class ASN1_TIME:
_ssl_months = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
]
m2_asn1_time_free = m2.asn1_time_free
def __init__(
self,
asn1_time: Optional[C.ASN1_Time] = None,
_pyfree: int = 0,
asn1_utctime: Optional[C.ASN1_Time] = None,
):
# handle old keyword parameter
if asn1_time is None:
asn1_time = asn1_utctime
if asn1_time is not None:
assert m2.asn1_time_type_check(
asn1_time
), "'asn1_time' type error'"
self.asn1_time = asn1_time
self._pyfree = _pyfree
else:
# that's (ASN1_TIME*)
self.asn1_time: bytes = m2.asn1_time_new()
self._pyfree = 1
def __del__(self) -> None:
if getattr(self, '_pyfree', 0):
self.m2_asn1_time_free(self.asn1_time)
def __str__(self) -> str:
assert m2.asn1_time_type_check(
self.asn1_time
), "'asn1_time' type error'"
buf = BIO.MemoryBuffer()
m2.asn1_time_print(buf.bio_ptr(), self.asn1_time)
return buf.read_all().decode()
def _ptr(self):
assert m2.asn1_time_type_check(
self.asn1_time
), "'asn1_time' type error'"
return self.asn1_time
def set_string(self, string: bytes) -> int:
"""
Set time from UTC string.
:return: 1 if the time value is successfully set and 0
otherwise
"""
assert m2.asn1_time_type_check(
self.asn1_time
), "'asn1_time' type error'"
return m2.asn1_time_set_string(self.asn1_time, string)
def set_time(self, time: int) -> C.ASN1_Time:
"""
Set time from seconds since epoch (int).
:return: pointer to a time structure or NULL if an error
occurred
"""
assert m2.asn1_time_type_check(
self.asn1_time
), "'asn1_time' type error'"
if hasattr(__builtins__, "long"):
time = long(time)
return m2.asn1_time_set(self.asn1_time, time)
def get_datetime(self) -> datetime.datetime:
"""
Get time as datetime.datetime object
:return: always return datetime object
:raises: ValueError if anything wrong happens
"""
date = str(self)
timezone = None
if ' ' not in date:
raise ValueError("Invalid date: %s" % date)
month, rest = date.split(' ', 1)
if month not in self._ssl_months:
raise ValueError(
"Invalid date %s: Invalid month: %s" % (date, month)
)
if rest.endswith(' GMT'):
timezone = UTC
rest = rest[:-4]
if '.' in rest:
dt = datetime.datetime.strptime(rest, "%d %H:%M:%S.%f %Y")
else:
dt = datetime.datetime.strptime(rest, "%d %H:%M:%S %Y")
dt = dt.replace(month=self._ssl_months.index(month) + 1)
if timezone:
dt = dt.replace(tzinfo=UTC)
return dt
def set_datetime(self, date: datetime.datetime) -> C.ASN1_Time:
"""
Set time from datetime.datetime object.
:return: pointer to a time structure or NULL if an error
occurred
"""
local = LocalTimezone()
if date.tzinfo is None:
date = date.replace(tzinfo=local)
date = date.astimezone(local)
return self.set_time(int(time.mktime(date.timetuple())))
ASN1_UTCTIME = ASN1_TIME
m2crypto-0.42.0/src/M2Crypto/AuthCookie.py 0000664 0000000 0000000 00000011670 14655756567 0020266 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""Secure Authenticator Cookies
Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved."""
import logging
import re
import time
from http.cookies import SimpleCookie
from M2Crypto import Rand, m2, util
from typing import Pattern, AnyStr, Optional, Union # noqa
_MIX_FORMAT = 'exp=%f&data=%s&digest='
_MIX_RE = re.compile(r'exp=(\d+\.\d+)&data=(.+)&digest=(\S*)')
log = logging.getLogger(__name__)
def mix(expiry, data, format=_MIX_FORMAT):
# type: (float, AnyStr, str) -> AnyStr
return format % (expiry, data)
def unmix(dough, regex=_MIX_RE):
# type: (AnyStr, Pattern) -> object
mo = regex.match(dough)
if mo:
return float(mo.group(1)), mo.group(2)
else:
return None
def unmix3(dough, regex=_MIX_RE):
# type: (AnyStr, Pattern) -> Optional[tuple[float, AnyStr, AnyStr]]
mo = regex.match(dough)
if mo:
return float(mo.group(1)), mo.group(2), mo.group(3)
else:
return None
_TOKEN = '_M2AUTH_' # type: str
class AuthCookieJar(object):
_keylen = 20 # type: int
def __init__(self):
# type: () -> None
self._key = Rand.rand_bytes(self._keylen)
def _hmac(self, key, data):
# type: (bytes, str) -> str
return util.bin_to_hex(m2.hmac(key, data.encode(), m2.sha1()))
def makeCookie(self, expiry, data):
# type: (float, str) -> AuthCookie
"""
Make a cookie
:param expiry: expiration time (float in seconds)
:param data: cookie content
:return: AuthCookie object
"""
if not isinstance(expiry, (int, float)):
raise ValueError('Expiration time must be number, not "%s' % expiry)
dough = mix(expiry, data)
return AuthCookie(expiry, data, dough, self._hmac(self._key, dough))
def isGoodCookie(self, cookie):
# type: (AuthCookie) -> Union[bool, int]
assert isinstance(cookie, AuthCookie)
if cookie.isExpired():
return 0
c = self.makeCookie(cookie._expiry, cookie._data)
return (c._expiry == cookie._expiry) \
and (c._data == cookie._data) \
and (c._mac == cookie._mac) \
and (c.output() == cookie.output())
def isGoodCookieString(self, cookie_str, _debug=False):
# type: (Union[dict, bytes], bool) -> Union[bool, int]
c = SimpleCookie()
c.load(cookie_str)
if _TOKEN not in c:
log.debug('_TOKEN not in c (keys = %s)', dir(c))
return 0
undough = unmix3(c[_TOKEN].value)
if undough is None:
log.debug('undough is None')
return 0
exp, data, mac = undough
c2 = self.makeCookie(exp, data)
if _debug and (c2._mac == mac):
log.error('cookie_str = %s', cookie_str)
log.error('c2.isExpired = %s', c2.isExpired())
log.error('mac = %s', mac)
log.error('c2._mac = %s', c2._mac)
log.error('c2._mac == mac: %s', str(c2._mac == mac))
return (not c2.isExpired()) and (c2._mac == mac)
class AuthCookie(object):
def __init__(self, expiry, data, dough, mac):
# type: (float, str, str, str) -> None
"""
Create new authentication cookie
:param expiry: expiration time (in seconds)
:param data: cookie payload (as a string)
:param dough: expiry & data concatenated to URL compliant
string
:param mac: SHA1-based HMAC of dough and random key
"""
self._expiry = expiry
self._data = data
self._mac = mac
self._cookie = SimpleCookie()
self._cookie[_TOKEN] = '%s%s' % (dough, mac)
self._name = '%s%s' % (dough, mac) # WebKit only.
def expiry(self):
# type: () -> float
"""Return the cookie's expiry time."""
return self._expiry
def data(self):
# type: () -> str
"""Return the data portion of the cookie."""
return self._data
def mac(self):
# type: () -> str
"""Return the cookie's MAC."""
return self._mac
def output(self, header="Set-Cookie:"):
# type: (Optional[str]) -> str
"""Return the cookie's output in "Set-Cookie" format."""
return self._cookie.output(header=header)
def value(self):
# type: () -> str
"""Return the cookie's output minus the "Set-Cookie: " portion.
"""
return self._cookie[_TOKEN].value
def isExpired(self):
# type: () -> bool
"""Return 1 if the cookie has expired, 0 otherwise."""
return isinstance(self._expiry, (float, int)) and \
(time.time() > self._expiry)
# Following two methods are for WebKit only.
# I may wish to push them to WKAuthCookie, but they are part
# of the API now. Oh well.
def name(self):
# type: () -> str
return self._name
def headerValue(self):
# type: () -> str
return self.value()
m2crypto-0.42.0/src/M2Crypto/BIO.py 0000664 0000000 0000000 00000025457 14655756567 0016654 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""M2Crypto wrapper for OpenSSL BIO API.
Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved."""
import io
import logging
from typing import Any, AnyStr, Callable, Iterable, Optional, Union # noqa
from M2Crypto import m2
log = logging.getLogger('BIO')
class BIOError(ValueError):
pass
m2.bio_init(BIOError)
class BIO(object):
"""Abstract object interface to the BIO API."""
m2_bio_free = m2.bio_free
def __init__(self, bio=None, _pyfree=0, _close_cb=None):
# type: (Optional[BIO], int, Optional[Callable]) -> None
self.bio = bio
self._pyfree = _pyfree
self._close_cb = _close_cb
self.closed = 0
self.write_closed = 0
def __del__(self):
if self._pyfree:
self.m2_bio_free(self.bio)
def _ptr(self):
return self.bio
# Deprecated.
bio_ptr = _ptr
def fileno(self):
# type: () -> int
return m2.bio_get_fd(self.bio)
def readable(self):
# type: () -> bool
return not self.closed
def read(self, size=None):
# type: (Optional[int]) -> Union[bytes, bytearray]
if not self.readable():
raise IOError('cannot read')
if size is None:
buf = bytearray()
while 1:
data = m2.bio_read(self.bio, 4096)
if not data:
break
buf += data
return buf
elif size == 0:
return b''
elif size < 0:
raise ValueError('read count is negative')
else:
return bytes(m2.bio_read(self.bio, size))
def readline(self, size=4096):
# type: (int) -> bytes
if not self.readable():
raise IOError('cannot read')
buf = m2.bio_gets(self.bio, size)
return '' if buf is None else buf
def readlines(self, sizehint='ignored'):
# type: (Union[AnyStr, int]) -> Iterable[bytes]
if not self.readable():
raise IOError('cannot read')
lines = []
while 1:
buf = m2.bio_gets(self.bio, 4096)
if buf is None:
break
lines.append(buf)
return lines
def writeable(self):
# type: () -> bool
return (not self.closed) and (not self.write_closed)
def write(self, data):
# type: (AnyStr) -> int
"""Write data to BIO.
:return: either data written, or [0, -1] for nothing written,
-2 not implemented
"""
if not self.writeable():
raise IOError('cannot write')
if isinstance(data, str):
data = data.encode('utf8')
return m2.bio_write(self.bio, data)
def write_close(self):
# type: () -> None
self.write_closed = 1
def flush(self):
# type: () -> None
"""Flush the buffers.
:return: 1 for success, and 0 or -1 for failure
"""
m2.bio_flush(self.bio)
def reset(self):
# type: () -> int
"""Set the bio to its initial state.
:return: 1 for success, and 0 or -1 for failure
"""
return m2.bio_reset(self.bio)
def close(self):
# type: () -> None
self.closed = 1
if self._close_cb:
self._close_cb()
def should_retry(self):
# type: () -> int
"""
Can the call be attempted again, or was there an error
ie do_handshake
"""
return m2.bio_should_retry(self.bio)
def should_read(self):
# type: () -> int
"""Should we read more data?"""
return m2.bio_should_read(self.bio)
def should_write(self):
# type: () -> int
"""Should we write more data?"""
return m2.bio_should_write(self.bio)
def tell(self):
"""Return the current offset."""
return m2.bio_tell(self.bio)
def seek(self, off):
"""Seek to the specified absolute offset."""
return m2.bio_seek(self.bio, off)
def __enter__(self):
return self
def __exit__(self, *args):
# type: (*Any) -> int
self.close()
class MemoryBuffer(BIO):
"""Object interface to BIO_s_mem.
Empirical testing suggests that this class performs less well than
cStringIO, because cStringIO is implemented in C, whereas this class
is implemented in Python. Thus, the recommended practice is to use
cStringIO for regular work and convert said cStringIO object to
a MemoryBuffer object only when necessary.
"""
def __init__(self, data=None):
# type: (Optional[bytes]) -> None
super(MemoryBuffer, self).__init__(self)
if data is not None and not isinstance(data, bytes):
raise TypeError(
"data must be bytes or None, not %s" % (type(data).__name__, ))
self.bio = m2.bio_new(m2.bio_s_mem())
self._pyfree = 1
if data is not None:
m2.bio_write(self.bio, data)
def __len__(self):
# type: () -> int
return m2.bio_ctrl_pending(self.bio)
def read(self, size=0):
# type: (int) -> bytes
m2.err_clear_error();
if not self.readable():
raise IOError('cannot read')
if size:
return m2.bio_read(self.bio, size)
else:
return m2.bio_read(self.bio, m2.bio_ctrl_pending(self.bio))
# Backwards-compatibility.
getvalue = read_all = read
def write_close(self):
# type: () -> None
super(MemoryBuffer, self).write_close()
m2.bio_set_mem_eof_return(self.bio, 0)
close = write_close
class File(BIO):
"""Object interface to BIO_s_pyfd.
This class interfaces Python to OpenSSL functions that expect BIO. For
general file manipulation in Python, use Python's builtin file object.
"""
def __init__(self, pyfile, close_pyfile=1, mode='rb'):
# type: (Union[io.BytesIO, AnyStr], int, AnyStr) -> None
super(File, self).__init__(self, _pyfree=1)
if isinstance(pyfile, str):
pyfile = open(pyfile, mode)
# This is for downward compatibility, but I don't think, that it is
# good practice to have two handles for the same file. Whats about
# concurrent write access? Last write, last wins? Especially since Py3
# has its own buffer management. See:
#
# https://docs.python.org/3.3/c-api/file.html
#
pyfile.flush()
self.fname = pyfile.name
self.pyfile = pyfile
# Be wary of https://github.com/openssl/openssl/pull/1925
# BIO_new_fd is NEVER to be used before OpenSSL 1.1.1
if hasattr(m2, "bio_new_pyfd"):
self.bio = m2.bio_new_pyfd(pyfile.fileno(), m2.bio_noclose)
else:
self.bio = m2.bio_new_pyfile(pyfile, m2.bio_noclose)
self.close_pyfile = close_pyfile
self.closed = False
def flush(self):
# type: () -> None
super(File, self).flush()
self.pyfile.flush()
def close(self):
# type: () -> None
self.flush()
super(File, self).close()
if self.close_pyfile:
self.pyfile.close()
def reset(self):
# type: () -> int
"""Set the bio to its initial state.
:return: 0 for success, and -1 for failure
"""
return super(File, self).reset()
def openfile(filename, mode='rb'):
# type: (AnyStr, AnyStr) -> File
try:
f = open(filename, mode)
except IOError as ex:
raise BIOError(ex.args)
return File(f)
class IOBuffer(BIO):
"""Object interface to BIO_f_buffer.
Its principal function is to be BIO_push()'ed on top of a BIO_f_ssl, so
that makefile() of said underlying SSL socket works.
"""
m2_bio_pop = m2.bio_pop
m2_bio_free = m2.bio_free
def __init__(self, under_bio, mode='rwb', _pyfree=1):
# type: (BIO, str, int) -> None
super(IOBuffer, self).__init__(self, _pyfree=_pyfree)
self.io = m2.bio_new(m2.bio_f_buffer())
self.bio = m2.bio_push(self.io, under_bio._ptr())
# This reference keeps the underlying BIO alive while we're not closed.
self._under_bio = under_bio
if 'w' in mode:
self.write_closed = 0
else:
self.write_closed = 1
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_bio_pop(self.bio)
self.m2_bio_free(self.io)
def close(self):
# type: () -> None
BIO.close(self)
class CipherStream(BIO):
"""Object interface to BIO_f_cipher."""
SALT_LEN = m2.PKCS5_SALT_LEN
m2_bio_pop = m2.bio_pop
m2_bio_free = m2.bio_free
def __init__(self, obio):
# type: (BIO) -> None
super(CipherStream, self).__init__(self, _pyfree=1)
self.obio = obio
self.bio = m2.bio_new(m2.bio_f_cipher())
self.closed = 0
def __del__(self):
# type: () -> None
if not getattr(self, 'closed', 1):
self.close()
def close(self):
# type: () -> None
self.m2_bio_pop(self.bio)
self.m2_bio_free(self.bio)
self.closed = 1
def write_close(self):
# type: () -> None
self.obio.write_close()
def set_cipher(self, algo, key, iv, op):
# type: (str, AnyStr, AnyStr, int) -> None
cipher = getattr(m2, algo, None)
if cipher is None:
raise ValueError('unknown cipher', algo)
else:
if not isinstance(key, bytes):
key = key.encode('utf8')
if not isinstance(iv, bytes):
iv = iv.encode('utf8')
try:
m2.bio_set_cipher(self.bio, cipher(), key, iv, int(op))
except (OSError, ValueError) as ex:
raise BIOError("BIOError: {}".format(str(ex)))
m2.bio_push(self.bio, self.obio._ptr())
class SSLBio(BIO):
"""Object interface to BIO_f_ssl."""
def __init__(self, _pyfree=1):
# type: (int) -> None
super(SSLBio, self).__init__(self, _pyfree=_pyfree)
self.bio = m2.bio_new(m2.bio_f_ssl())
self.closed = 0
def set_ssl(self, conn, close_flag=m2.bio_noclose):
# type: (Any, int) -> None
# conn should actually be SSL.Connection, but we cannot import
# it here without getting into some serious circular dependency
# business.
"""
Sets the bio to the SSL pointer which is
contained in the connection object.
"""
self._pyfree = 0
m2.bio_set_ssl(self.bio, conn.ssl, close_flag)
if close_flag == m2.bio_noclose:
conn.set_ssl_close_flag(m2.bio_close)
def do_handshake(self):
# type: () -> int
"""Do the handshake.
Return 1 if the handshake completes
Return 0 or a negative number if there is a problem
"""
return m2.bio_do_handshake(self.bio)
m2crypto-0.42.0/src/M2Crypto/BN.py 0000664 0000000 0000000 00000003147 14655756567 0016532 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""
M2Crypto wrapper for OpenSSL BN (BIGNUM) API.
Copyright (c) 2005 Open Source Applications Foundation. All rights reserved.
"""
from M2Crypto import m2
from typing import Optional # noqa
def rand(bits, top=-1, bottom=0):
# type: (int, int, int) -> Optional[int]
"""
Generate cryptographically strong random number.
:param bits: Length of random number in bits.
:param top: If -1, the most significant bit can be 0. If 0, the most
significant bit is 1, and if 1, the two most significant
bits will be 1.
:param bottom: If bottom is true, the number will be odd.
"""
return m2.bn_rand(bits, top, bottom)
def rand_range(range):
# type: (int) -> int
"""
Generate a random number in a range.
:param range: Upper limit for range.
:return: A random number in the range [0, range)
"""
return m2.bn_rand_range(range)
def randfname(length):
# type: (int) -> str
"""
Return a random filename, which is simply a string where all
the characters are from the set [a-zA-Z0-9].
:param length: Length of filename to return.
:return: random filename string
"""
import warnings
warnings.warn(
"Don't use BN.randfname(), use tempfile methods instead.",
DeprecationWarning, stacklevel=2)
letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890'
lettersLen = len(letters)
fname = [] # type: list
for x in range(length):
fname += [letters[m2.bn_rand_range(lettersLen)]]
return ''.join(fname)
m2crypto-0.42.0/src/M2Crypto/DH.py 0000664 0000000 0000000 00000005561 14655756567 0016530 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""M2Crypto wrapper for OpenSSL DH API.
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
from M2Crypto import BIO, m2
from M2Crypto.util import genparam_callback
from typing import AnyStr, Callable, Optional # noqa
class DHError(Exception):
pass
m2.dh_init(DHError)
class DH(object):
"""Object interface to the Diffie-Hellman key exchange protocol.
"""
m2_dh_free = m2.dh_free
def __init__(self, dh, _pyfree=0):
# type: (bytes, int) -> None
assert m2.dh_type_check(dh)
self.dh = dh
self._pyfree = _pyfree
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_dh_free(self.dh)
def __len__(self):
# type: () -> int
assert m2.dh_type_check(self.dh), "'dh' type error"
return int(m2.dh_size(self.dh))
def __getattr__(self, name):
# type: (str) -> bytes
if name in ('p', 'g', 'pub', 'priv'):
method = getattr(m2, 'dh_get_%s' % (name,))
assert m2.dh_type_check(self.dh), "'dh' type error"
return method(self.dh)
else:
raise AttributeError
def __setattr__(self, name, value):
# type: (str, bytes) -> bytes
if name in ('p', 'g'):
raise DHError('set (p, g) via set_params()')
elif name in ('pub', 'priv'):
raise DHError('generate (pub, priv) via gen_key()')
else:
self.__dict__[name] = value
def _ptr(self):
return self.dh
def check_params(self):
# type: () -> int
assert m2.dh_type_check(self.dh), "'dh' type error"
return m2.dh_check(self.dh)
def gen_key(self):
# type: () -> None
assert m2.dh_type_check(self.dh), "'dh' type error"
m2.dh_generate_key(self.dh)
def compute_key(self, pubkey):
# type: (bytes) -> bytes
assert m2.dh_type_check(self.dh), "'dh' type error"
return m2.dh_compute_key(self.dh, pubkey)
def print_params(self, bio):
# type: (BIO.BIO) -> int
assert m2.dh_type_check(self.dh), "'dh' type error"
return m2.dhparams_print(bio._ptr(), self.dh)
def gen_params(plen, g, callback=genparam_callback):
# type: (int, int, Optional[Callable]) -> DH
dh_parms = m2.dh_generate_parameters(plen, g, callback)
dh_obj = DH(dh_parms, 1)
return dh_obj
def load_params(file):
# type: (AnyStr) -> DH
with BIO.openfile(file) as bio:
return load_params_bio(bio)
def load_params_bio(bio):
# type: (BIO.BIO) -> DH
return DH(m2.dh_read_parameters(bio._ptr()), 1)
def set_params(p, g):
# type: (bytes, bytes) -> DH
dh = m2.dh_new()
m2.dh_set_pg(dh, p, g)
return DH(dh, 1)
# def free_params(cptr):
# m2.dh_free(cptr)
DH_GENERATOR_2 = m2.DH_GENERATOR_2
DH_GENERATOR_5 = m2.DH_GENERATOR_5
m2crypto-0.42.0/src/M2Crypto/DSA.py 0000664 0000000 0000000 00000033723 14655756567 0016645 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import, print_function
"""
M2Crypto wrapper for OpenSSL DSA API.
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.
Portions created by Open Source Applications Foundation (OSAF) are
Copyright (C) 2004 OSAF. All Rights Reserved.
"""
from M2Crypto import BIO, m2, util
from typing import Any, AnyStr, Callable, Tuple # noqa
class DSAError(Exception):
pass
m2.dsa_init(DSAError)
class DSA(object):
"""
This class is a context supporting DSA key and parameter
values, signing and verifying.
Simple example::
from M2Crypto import EVP, DSA, util
message = 'Kilroy was here!'
md = EVP.MessageDigest('sha1')
md.update(message)
digest = md.final()
dsa = DSA.gen_params(1024)
dsa.gen_key()
r, s = dsa.sign(digest)
good = dsa.verify(digest, r, s)
if good:
print(' ** success **')
else:
print(' ** verification failed **')
"""
m2_dsa_free = m2.dsa_free
def __init__(self, dsa, _pyfree=0):
# type: (bytes, int) -> None
"""
Use one of the factory functions to create an instance.
:param dsa: binary representation of OpenSSL DSA type
"""
assert m2.dsa_type_check(dsa), "'dsa' type error"
self.dsa = dsa
self._pyfree = _pyfree
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_dsa_free(self.dsa)
def __len__(self):
# type: () -> int
"""
Return the key length.
:return: the DSA key length in bits
"""
assert m2.dsa_type_check(self.dsa), "'dsa' type error"
return m2.dsa_keylen(self.dsa)
def __getattr__(self, name):
# type: (str) -> bytes
"""
Return specified DSA parameters and key values.
:param name: name of variable to be returned. Must be
one of 'p', 'q', 'g', 'pub', 'priv'.
:return: value of specified variable (a "byte string")
"""
if name in ['p', 'q', 'g', 'pub', 'priv']:
method = getattr(m2, 'dsa_get_%s' % (name,))
assert m2.dsa_type_check(self.dsa), "'dsa' type error"
return method(self.dsa)
else:
raise AttributeError
def __setattr__(self, name, value):
# type: (str, bytes) -> None
if name in ['p', 'q', 'g']:
raise DSAError('set (p, q, g) via set_params()')
elif name in ['pub', 'priv']:
raise DSAError('generate (pub, priv) via gen_key()')
else:
self.__dict__[name] = value
def set_params(self, p, q, g):
# type: (bytes, bytes, bytes) -> None
"""
Set new parameters.
:param p: MPI binary representation ... format that consists of
the number's length in bytes represented as a 4-byte
big-endian number, and the number itself in big-endian
format, where the most significant bit signals
a negative number (the representation of numbers with
the MSB set is prefixed with null byte).
:param q: ditto
:param g: ditto
@warning: This does not change the private key, so it may be
unsafe to use this method. It is better to use
gen_params function to create a new DSA object.
"""
m2.dsa_set_pqg(self.dsa, p, q, g)
def gen_key(self):
# type: () -> None
"""
Generate a key pair.
"""
assert m2.dsa_type_check(self.dsa), "'dsa' type error"
m2.dsa_gen_key(self.dsa)
def save_params(self, filename):
# type: (AnyStr) -> int
"""
Save the DSA parameters to a file.
:param filename: Save the DSA parameters to this file.
:return: 1 (true) if successful
"""
with BIO.openfile(filename, 'wb') as bio:
ret = m2.dsa_write_params_bio(self.dsa, bio._ptr())
return ret
def save_params_bio(self, bio):
# type: (BIO.BIO) -> int
"""
Save DSA parameters to a BIO object.
:param bio: Save DSA parameters to this object.
:return: 1 (true) if successful
"""
return m2.dsa_write_params_bio(self.dsa, bio._ptr())
def save_key(self, filename, cipher='aes_128_cbc',
callback=util.passphrase_callback):
# type: (AnyStr, str, Callable) -> int
"""
Save the DSA key pair to a file.
:param filename: Save the DSA key pair to this file.
:param cipher: name of symmetric key algorithm and mode
to encrypt the private key.
:return: 1 (true) if successful
"""
with BIO.openfile(filename, 'wb') as bio:
ret = self.save_key_bio(bio, cipher, callback)
return ret
def save_key_bio(self, bio, cipher='aes_128_cbc',
callback=util.passphrase_callback):
# type: (BIO.BIO, str, Callable) -> int
"""
Save DSA key pair to a BIO object.
:param bio: Save DSA parameters to this object.
:param cipher: name of symmetric key algorithm and mode
to encrypt the private key.
:return: 1 (true) if successful
"""
if cipher is None:
return m2.dsa_write_key_bio_no_cipher(self.dsa,
bio._ptr(), callback)
else:
ciph = getattr(m2, cipher, None)
if ciph is None:
raise DSAError('no such cipher: %s' % cipher)
else:
ciph = ciph()
return m2.dsa_write_key_bio(self.dsa, bio._ptr(), ciph, callback)
def save_pub_key(self, filename):
# type: (AnyStr) -> int
"""
Save the DSA public key (with parameters) to a file.
:param filename: Save DSA public key (with parameters)
to this file.
:return: 1 (true) if successful
"""
with BIO.openfile(filename, 'wb') as bio:
ret = self.save_pub_key_bio(bio)
return ret
def save_pub_key_bio(self, bio):
# type: (BIO.BIO) -> int
"""
Save DSA public key (with parameters) to a BIO object.
:param bio: Save DSA public key (with parameters)
to this object.
:return: 1 (true) if successful
"""
return m2.dsa_write_pub_key_bio(self.dsa, bio._ptr())
def sign(self, digest):
# type: (bytes) -> Tuple[bytes, bytes]
"""
Sign the digest.
:param digest: SHA-1 hash of message (same as output
from MessageDigest, a "byte string")
:return: DSA signature, a tuple of two values, r and s,
both "byte strings".
"""
assert self.check_key(), 'key is not initialised'
return m2.dsa_sign(self.dsa, digest)
def verify(self, digest, r, s):
# type: (bytes, bytes, bytes) -> int
"""
Verify a newly calculated digest against the signature
values r and s.
:param digest: SHA-1 hash of message (same as output
from MessageDigest, a "byte string")
:param r: r value of the signature, a "byte string"
:param s: s value of the signature, a "byte string"
:return: 1 (true) if verify succeeded, 0 if failed
"""
assert self.check_key(), 'key is not initialised'
return m2.dsa_verify(self.dsa, digest, r, s)
def sign_asn1(self, digest):
assert self.check_key(), 'key is not initialised'
return m2.dsa_sign_asn1(self.dsa, digest)
def verify_asn1(self, digest, blob):
assert self.check_key(), 'key is not initialised'
return m2.dsa_verify_asn1(self.dsa, digest, blob)
def check_key(self):
"""
Check to be sure the DSA object has a valid private key.
:return: 1 (true) if a valid private key
"""
assert m2.dsa_type_check(self.dsa), "'dsa' type error"
return m2.dsa_check_key(self.dsa)
class DSA_pub(DSA):
"""
This class is a DSA context that only supports a public key
and verification. It does NOT support a private key or
signing.
"""
def sign(self, *argv):
# type: (*Any) -> None
raise DSAError('DSA_pub object has no private key')
sign_asn1 = sign
def check_key(self):
# type: () -> int
"""
:return: does DSA_pub contain a pub key?
"""
return m2.dsa_check_pub_key(self.dsa)
save_key = DSA.save_pub_key
save_key_bio = DSA.save_pub_key_bio
# --------------------------------------------------------------
# factories and other functions
def gen_params(bits, callback=util.genparam_callback):
# type: (int, Callable) -> DSA
"""
Factory function that generates DSA parameters and
instantiates a DSA object from the output.
:param bits: The length of the prime to be generated. If
'bits' < 512, it is set to 512.
:param callback: A Python callback object that will be
invoked during parameter generation; it usual
purpose is to provide visual feedback.
:return: instance of DSA.
"""
dsa = m2.dsa_generate_parameters(bits, callback)
return DSA(dsa, 1)
def set_params(p, q, g):
# type: (bytes, bytes, bytes) -> DSA
"""
Factory function that instantiates a DSA object with DSA
parameters.
:param p: value of p, a "byte string"
:param q: value of q, a "byte string"
:param g: value of g, a "byte string"
:return: instance of DSA.
"""
dsa = m2.dsa_new()
m2.dsa_set_pqg(dsa, p, q, g)
return DSA(dsa, 1)
def load_params(file, callback=util.passphrase_callback):
# type: (AnyStr, Callable) -> DSA
"""
Factory function that instantiates a DSA object with DSA
parameters from a file.
:param file: Names the file (a path) that contains the PEM
representation of the DSA parameters.
:param callback: A Python callback object that will be
invoked if the DSA parameters file is
passphrase-protected.
:return: instance of DSA.
"""
with BIO.openfile(file) as bio:
ret = load_params_bio(bio, callback)
return ret
def load_params_bio(bio, callback=util.passphrase_callback):
# type: (BIO.BIO, Callable) -> DSA
"""
Factory function that instantiates a DSA object with DSA
parameters from a M2Crypto.BIO object.
:param bio: Contains the PEM representation of the DSA
parameters.
:param callback: A Python callback object that will be
invoked if the DSA parameters file is
passphrase-protected.
:return: instance of DSA.
"""
dsa = m2.dsa_read_params(bio._ptr(), callback)
return DSA(dsa, 1)
def load_key(file, callback=util.passphrase_callback):
# type: (AnyStr, Callable) -> DSA
"""
Factory function that instantiates a DSA object from a
PEM encoded DSA key pair.
:param file: Names the file (a path) that contains the PEM
representation of the DSA key pair.
:param callback: A Python callback object that will be
invoked if the DSA key pair is
passphrase-protected.
:return: instance of DSA.
"""
with BIO.openfile(file) as bio:
ret = load_key_bio(bio, callback)
return ret
def load_key_bio(bio, callback=util.passphrase_callback):
# type: (BIO.BIO, Callable) -> DSA
"""
Factory function that instantiates a DSA object from a
PEM encoded DSA key pair.
:param bio: Contains the PEM representation of the DSA
key pair.
:param callback: A Python callback object that will be
invoked if the DSA key pair is
passphrase-protected.
:return: instance of DSA.
"""
dsa = m2.dsa_read_key(bio._ptr(), callback)
return DSA(dsa, 1)
def pub_key_from_params(p, q, g, pub):
# type: (bytes, bytes, bytes, bytes) -> DSA_pub
"""
Factory function that instantiates a DSA_pub object using
the parameters and public key specified.
:param p: value of p
:param q: value of q
:param g: value of g
:param pub: value of the public key
:return: instance of DSA_pub.
"""
dsa = m2.dsa_new()
m2.dsa_set_pqg(dsa, p, q, g)
m2.dsa_set_pub(dsa, pub)
return DSA_pub(dsa, 1)
def load_pub_key(file, callback=util.passphrase_callback):
# type: (AnyStr, Callable) -> DSA_pub
"""
Factory function that instantiates a DSA_pub object using
a DSA public key contained in PEM file. The PEM file
must contain the parameters in addition to the public key.
:param file: Names the file (a path) that contains the PEM
representation of the DSA public key.
:param callback: A Python callback object that will be
invoked should the DSA public key be
passphrase-protected.
:return: instance of DSA_pub.
"""
with BIO.openfile(file) as bio:
ret = load_pub_key_bio(bio, callback)
return ret
def load_pub_key_bio(bio, callback=util.passphrase_callback):
# type: (BIO.BIO, Callable) -> DSA_pub
"""
Factory function that instantiates a DSA_pub object using
a DSA public key contained in PEM format. The PEM
must contain the parameters in addition to the public key.
:param bio: Contains the PEM representation of the DSA
public key (with params).
:param callback: A Python callback object that will be
invoked should the DSA public key be
passphrase-protected.
:return: instance of DSA_pub.
"""
dsapub = m2.dsa_read_pub_key(bio._ptr(), callback)
return DSA_pub(dsapub, 1)
m2crypto-0.42.0/src/M2Crypto/EC.py 0000664 0000000 0000000 00000037636 14655756567 0016534 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""
M2Crypto wrapper for OpenSSL ECDH/ECDSA API.
@requires: OpenSSL 0.9.8 or newer
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.
Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam.
All rights reserved."""
from M2Crypto import BIO, Err, m2, util
from typing import AnyStr, Callable, Dict, Optional, Tuple, Union # noqa
EC_Key = bytes
class ECError(Exception):
pass
m2.ec_init(ECError)
# Curve identifier constants
NID_secp112r1 = m2.NID_secp112r1 # type: int
NID_secp112r2 = m2.NID_secp112r2 # type: int
NID_secp128r1 = m2.NID_secp128r1 # type: int
NID_secp128r2 = m2.NID_secp128r2 # type: int
NID_secp160k1 = m2.NID_secp160k1 # type: int
NID_secp160r1 = m2.NID_secp160r1 # type: int
NID_secp160r2 = m2.NID_secp160r2 # type: int
NID_secp192k1 = m2.NID_secp192k1 # type: int
NID_secp224k1 = m2.NID_secp224k1 # type: int
NID_secp224r1 = m2.NID_secp224r1 # type: int
NID_secp256k1 = m2.NID_secp256k1 # type: int
NID_secp384r1 = m2.NID_secp384r1 # type: int
NID_secp521r1 = m2.NID_secp521r1 # type: int
NID_sect113r1 = m2.NID_sect113r1 # type: int
NID_sect113r2 = m2.NID_sect113r2 # type: int
NID_sect131r1 = m2.NID_sect131r1 # type: int
NID_sect131r2 = m2.NID_sect131r2 # type: int
NID_sect163k1 = m2.NID_sect163k1 # type: int
NID_sect163r1 = m2.NID_sect163r1 # type: int
NID_sect163r2 = m2.NID_sect163r2 # type: int
NID_sect193r1 = m2.NID_sect193r1 # type: int
NID_sect193r2 = m2.NID_sect193r2 # type: int
# default for secg.org TLS test server
NID_sect233k1 = m2.NID_sect233k1 # type: int
NID_sect233r1 = m2.NID_sect233r1 # type: int
NID_sect239k1 = m2.NID_sect239k1 # type: int
NID_sect283k1 = m2.NID_sect283k1 # type: int
NID_sect283r1 = m2.NID_sect283r1 # type: int
NID_sect409k1 = m2.NID_sect409k1 # type: int
NID_sect409r1 = m2.NID_sect409r1 # type: int
NID_sect571k1 = m2.NID_sect571k1 # type: int
NID_sect571r1 = m2.NID_sect571r1 # type: int
NID_prime192v1 = m2.NID_X9_62_prime192v1 # type: int
NID_prime192v2 = m2.NID_X9_62_prime192v2 # type: int
NID_prime192v3 = m2.NID_X9_62_prime192v3 # type: int
NID_prime239v1 = m2.NID_X9_62_prime239v1 # type: int
NID_prime239v2 = m2.NID_X9_62_prime239v2 # type: int
NID_prime239v3 = m2.NID_X9_62_prime239v3 # type: int
NID_prime256v1 = m2.NID_X9_62_prime256v1 # type: int
NID_c2pnb163v1 = m2.NID_X9_62_c2pnb163v1 # type: int
NID_c2pnb163v2 = m2.NID_X9_62_c2pnb163v2 # type: int
NID_c2pnb163v3 = m2.NID_X9_62_c2pnb163v3 # type: int
NID_c2pnb176v1 = m2.NID_X9_62_c2pnb176v1 # type: int
NID_c2tnb191v1 = m2.NID_X9_62_c2tnb191v1 # type: int
NID_c2tnb191v2 = m2.NID_X9_62_c2tnb191v2 # type: int
NID_c2tnb191v3 = m2.NID_X9_62_c2tnb191v3 # type: int
NID_c2pnb208w1 = m2.NID_X9_62_c2pnb208w1 # type: int
NID_c2tnb239v1 = m2.NID_X9_62_c2tnb239v1 # type: int
NID_c2tnb239v2 = m2.NID_X9_62_c2tnb239v2 # type: int
NID_c2tnb239v3 = m2.NID_X9_62_c2tnb239v3 # type: int
NID_c2pnb272w1 = m2.NID_X9_62_c2pnb272w1 # type: int
NID_c2pnb304w1 = m2.NID_X9_62_c2pnb304w1 # type: int
NID_c2tnb359v1 = m2.NID_X9_62_c2tnb359v1 # type: int
NID_c2pnb368w1 = m2.NID_X9_62_c2pnb368w1 # type: int
NID_c2tnb431r1 = m2.NID_X9_62_c2tnb431r1 # type: int
# To preserve compatibility with older names
NID_X9_62_prime192v1 = NID_prime192v1 # type: int
NID_X9_62_prime192v2 = NID_prime192v2 # type: int
NID_X9_62_prime192v3 = NID_prime192v3 # type: int
NID_X9_62_prime239v1 = NID_prime239v1 # type: int
NID_X9_62_prime239v2 = NID_prime239v2 # type: int
NID_X9_62_prime239v3 = NID_prime239v3 # type: int
NID_X9_62_prime256v1 = NID_prime256v1 # type: int
NID_X9_62_c2pnb163v1 = NID_c2pnb163v1 # type: int
NID_X9_62_c2pnb163v2 = NID_c2pnb163v2 # type: int
NID_X9_62_c2pnb163v3 = NID_c2pnb163v3 # type: int
NID_X9_62_c2pnb176v1 = NID_c2pnb176v1 # type: int
NID_X9_62_c2tnb191v1 = NID_c2tnb191v1 # type: int
NID_X9_62_c2tnb191v2 = NID_c2tnb191v2 # type: int
NID_X9_62_c2tnb191v3 = NID_c2tnb191v3 # type: int
NID_X9_62_c2pnb208w1 = NID_c2pnb208w1 # type: int
NID_X9_62_c2tnb239v1 = NID_c2tnb239v1 # type: int
NID_X9_62_c2tnb239v2 = NID_c2tnb239v2 # type: int
NID_X9_62_c2tnb239v3 = NID_c2tnb239v3 # type: int
NID_X9_62_c2pnb272w1 = NID_c2pnb272w1 # type: int
NID_X9_62_c2pnb304w1 = NID_c2pnb304w1 # type: int
NID_X9_62_c2tnb359v1 = NID_c2tnb359v1 # type: int
NID_X9_62_c2pnb368w1 = NID_c2pnb368w1 # type: int
NID_X9_62_c2tnb431r1 = NID_c2tnb431r1 # type: int
NID_wap_wsg_idm_ecid_wtls1 = m2.NID_wap_wsg_idm_ecid_wtls1 # type: int
NID_wap_wsg_idm_ecid_wtls3 = m2.NID_wap_wsg_idm_ecid_wtls3 # type: int
NID_wap_wsg_idm_ecid_wtls4 = m2.NID_wap_wsg_idm_ecid_wtls4 # type: int
NID_wap_wsg_idm_ecid_wtls5 = m2.NID_wap_wsg_idm_ecid_wtls5 # type: int
NID_wap_wsg_idm_ecid_wtls6 = m2.NID_wap_wsg_idm_ecid_wtls6 # type: int
NID_wap_wsg_idm_ecid_wtls7 = m2.NID_wap_wsg_idm_ecid_wtls7 # type: int
NID_wap_wsg_idm_ecid_wtls8 = m2.NID_wap_wsg_idm_ecid_wtls8 # type: int
NID_wap_wsg_idm_ecid_wtls9 = m2.NID_wap_wsg_idm_ecid_wtls9 # type: int
NID_wap_wsg_idm_ecid_wtls10 = m2.NID_wap_wsg_idm_ecid_wtls10 # type: int
NID_wap_wsg_idm_ecid_wtls11 = m2.NID_wap_wsg_idm_ecid_wtls11 # type: int
NID_wap_wsg_idm_ecid_wtls12 = m2.NID_wap_wsg_idm_ecid_wtls12 # type: int
# The following two curves, according to OpenSSL, have a
# "Questionable extension field!" and are not supported by
# the OpenSSL inverse function. ECError: no inverse.
# As such they cannot be used for signing. They might,
# however, be usable for encryption but that has not
# been tested. Until thir usefulness can be established,
# they are not supported at this time.
# NID_ipsec3 = m2.NID_ipsec3
# NID_ipsec4 = m2.NID_ipsec4
class EC(object):
"""
Object interface to a EC key pair.
"""
m2_ec_key_free = m2.ec_key_free
def __init__(self, ec, _pyfree=0):
# type: (EC, int) -> None
assert m2.ec_key_type_check(ec), "'ec' type error"
self.ec = ec
self._pyfree = _pyfree
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_ec_key_free(self.ec)
def __len__(self):
# type: () -> int
assert m2.ec_key_type_check(self.ec), "'ec' type error"
return m2.ec_key_keylen(self.ec)
def gen_key(self):
# type: () -> int
"""
Generates the key pair from its parameters. Use::
keypair = EC.gen_params(curve)
keypair.gen_key()
to create an EC key pair.
"""
assert m2.ec_key_type_check(self.ec), "'ec' type error"
m2.ec_key_gen_key(self.ec)
def pub(self):
# type: () -> EC_pub
# Don't let python free
return EC_pub(self.ec, 0)
def sign_dsa(self, digest):
# type: (bytes) -> Tuple[bytes, bytes]
"""
Sign the given digest using ECDSA. Returns a tuple (r,s), the two
ECDSA signature parameters.
"""
assert self._check_key_type(), "'ec' type error"
return m2.ecdsa_sign(self.ec, digest)
def verify_dsa(self, digest, r, s):
# type: (bytes, bytes, bytes) -> int
"""
Verify the given digest using ECDSA. r and s are the ECDSA
signature parameters.
"""
assert self._check_key_type(), "'ec' type error"
return m2.ecdsa_verify(self.ec, digest, r, s)
def sign_dsa_asn1(self, digest):
# type: (bytes) -> bytes
assert self._check_key_type(), "'ec' type error"
return m2.ecdsa_sign_asn1(self.ec, digest)
def verify_dsa_asn1(self, digest, blob):
assert self._check_key_type(), "'ec' type error"
return m2.ecdsa_verify_asn1(self.ec, digest, blob)
def compute_dh_key(self, pub_key):
# type: (EC) -> Optional[bytes]
"""
Compute the ECDH shared key of this key pair and the given public
key object. They must both use the same curve. Returns the
shared key in binary as a buffer object. No Key Derivation Function is
applied.
"""
assert self.check_key(), 'key is not initialised'
return m2.ecdh_compute_key(self.ec, pub_key.ec)
def save_key_bio(self, bio, cipher='aes_128_cbc',
callback=util.passphrase_callback):
# type: (BIO.BIO, Optional[str], Callable) -> int
"""
Save the key pair to an M2Crypto.BIO.BIO object in PEM format.
:param bio: M2Crypto.BIO.BIO object to save key to.
:param cipher: Symmetric cipher to protect the key. The default
cipher is 'aes_128_cbc'. If cipher is None, then
the key is saved in the clear.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to protect
the key. The default is
util.passphrase_callback.
"""
if cipher is None:
return m2.ec_key_write_bio_no_cipher(self.ec, bio._ptr(), callback)
else:
ciph = getattr(m2, cipher, None)
if ciph is None:
raise ValueError('not such cipher %s' % cipher)
return m2.ec_key_write_bio(self.ec, bio._ptr(), ciph(), callback)
def save_key(self, file, cipher='aes_128_cbc',
callback=util.passphrase_callback):
# type: (AnyStr, Optional[str], Callable) -> int
"""
Save the key pair to a file in PEM format.
:param file: Name of filename to save key to.
:param cipher: Symmetric cipher to protect the key. The default
cipher is 'aes_128_cbc'. If cipher is None, then
the key is saved in the clear.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to protect
the key. The default is
util.passphrase_callback.
"""
with BIO.openfile(file, 'wb') as bio:
return self.save_key_bio(bio, cipher, callback)
def save_pub_key_bio(self, bio):
# type: (BIO.BIO) -> int
"""
Save the public key to an M2Crypto.BIO.BIO object in PEM format.
:param bio: M2Crypto.BIO.BIO object to save key to.
"""
return m2.ec_key_write_pubkey(self.ec, bio._ptr())
def save_pub_key(self, file):
# type: (AnyStr) -> int
"""
Save the public key to a filename in PEM format.
:param file: Name of filename to save key to.
"""
with BIO.openfile(file, 'wb') as bio:
return m2.ec_key_write_pubkey(self.ec, bio._ptr())
def as_pem(self, cipher='aes_128_cbc', callback=util.passphrase_callback):
"""
Returns the key(pair) as a string in PEM format.
If no password is passed and the cipher is set
it exits with error
"""
with BIO.MemoryBuffer() as bio:
self.save_key_bio(bio, cipher, callback)
return bio.read()
def _check_key_type(self):
# type: () -> int
return m2.ec_key_type_check(self.ec)
def check_key(self):
# type: () -> int
assert m2.ec_key_type_check(self.ec), "'ec' type error"
return m2.ec_key_check_key(self.ec)
class EC_pub(EC):
"""
Object interface to an EC public key.
((don't like this implementation inheritance))
"""
def __init__(self, ec, _pyfree=0):
# type: (EC, int) -> None
EC.__init__(self, ec, _pyfree)
self.der = None # type: Optional[bytes]
def get_der(self):
# type: () -> bytes
"""
Returns the public key in DER format as a buffer object.
"""
assert self.check_key(), 'key is not initialised'
if self.der is None:
self.der = m2.ec_key_get_public_der(self.ec)
return self.der
def get_key(self):
# type: () -> bytes
"""
Returns the public key as a byte string.
"""
assert self.check_key(), 'key is not initialised'
return m2.ec_key_get_public_key(self.ec)
def as_pem(self):
"""
Returns the key(pair) as a string in PEM format.
If no password is passed and the cipher is set
it exits with error
"""
with BIO.MemoryBuffer() as bio:
self.save_key_bio(bio)
return bio.read()
save_key = EC.save_pub_key
save_key_bio = EC.save_pub_key_bio
def gen_params(curve):
# type: (int) -> EC
"""
Factory function that generates EC parameters and
instantiates a EC object from the output.
:param curve: This is the OpenSSL nid of the curve to use.
"""
assert curve in [x['NID'] for x in m2.ec_get_builtin_curves()], \
'Elliptic curve %s is not available on this system.' % \
m2.obj_nid2sn(curve)
return EC(m2.ec_key_new_by_curve_name(curve), 1)
def load_key(file, callback=util.passphrase_callback):
# type: (AnyStr, Callable) -> EC
"""
Factory function that instantiates a EC object.
:param file: Names the filename that contains the PEM representation
of the EC key pair.
:param callback: Python callback object that will be invoked
if the EC key pair is passphrase-protected.
"""
with BIO.openfile(file) as bio:
return load_key_bio(bio, callback)
def load_key_string(string, callback=util.passphrase_callback):
# type: (str, Callable) -> EC
"""
Load an EC key pair from a string.
:param string: String containing EC key pair in PEM format.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to unlock the
key. The default is util.passphrase_callback.
:return: M2Crypto.EC.EC object.
"""
with BIO.MemoryBuffer(string) as bio:
return load_key_bio(bio, callback)
def load_key_bio(bio, callback=util.passphrase_callback):
# type: (BIO.BIO, Callable) -> EC
"""
Factory function that instantiates a EC object.
:param bio: M2Crypto.BIO object that contains the PEM
representation of the EC key pair.
:param callback: Python callback object that will be invoked
if the EC key pair is passphrase-protected.
"""
return EC(m2.ec_key_read_bio(bio._ptr(), callback), 1)
def load_pub_key(file):
# type: (AnyStr) -> EC_pub
"""
Load an EC public key from filename.
:param file: Name of filename containing EC public key in PEM
format.
:return: M2Crypto.EC.EC_pub object.
"""
with BIO.openfile(file) as bio:
return load_pub_key_bio(bio)
def load_key_string_pubkey(string, callback=util.passphrase_callback):
# type: (str, Callable) -> EC.PKey
"""
Load an M2Crypto.EC.PKey from a public key as a string.
:param string: String containing the key in PEM format.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to protect the
key.
:return: M2Crypto.EC.PKey object.
"""
from M2Crypto.EVP import load_key_bio_pubkey
with BIO.MemoryBuffer(string) as bio:
return load_key_bio_pubkey(bio, callback)
def load_pub_key_bio(bio):
# type: (BIO.BIO) -> EC_pub
"""
Load an EC public key from an M2Crypto.BIO.BIO object.
:param bio: M2Crypto.BIO.BIO object containing EC public key in PEM
format.
:return: M2Crypto.EC.EC_pub object.
"""
ec = m2.ec_key_read_pubkey(bio._ptr())
if ec is None:
ec_error()
return EC_pub(ec, 1)
def ec_error():
# type: () -> ECError
raise ECError(Err.get_error_message())
def pub_key_from_der(der):
# type: (bytes) -> EC_pub
"""
Create EC_pub from DER.
"""
return EC_pub(m2.ec_key_from_pubkey_der(der), 1)
def pub_key_from_params(curve, bytes):
# type: (bytes, bytes) -> EC_pub
"""
Create EC_pub from curve name and octet string.
"""
return EC_pub(m2.ec_key_from_pubkey_params(curve, bytes), 1)
def get_builtin_curves():
# type: () -> Tuple[Dict[str, Union[int, str]]]
return m2.ec_get_builtin_curves()
m2crypto-0.42.0/src/M2Crypto/EVP.py 0000664 0000000 0000000 00000043615 14655756567 0016671 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""M2Crypto wrapper for OpenSSL EVP API.
Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.
Portions Copyright (c) 2004-2007 Open Source Applications Foundation.
Author: Heikki Toivonen
"""
import logging
from M2Crypto import BIO, Err, RSA, EC, m2, util
from typing import AnyStr, Optional, Callable # noqa
log = logging.getLogger('EVP')
class EVPError(ValueError):
pass
m2.evp_init(EVPError)
def pbkdf2(password, salt, iter, keylen):
# type: (bytes, bytes, int, int) -> bytes
"""
Derive a key from password using PBKDF2 algorithm specified in RFC 2898.
:param password: Derive the key from this password.
:param salt: Salt.
:param iter: Number of iterations to perform.
:param keylen: Length of key to produce.
:return: Key.
"""
return m2.pkcs5_pbkdf2_hmac_sha1(password, salt, iter, keylen)
class MessageDigest(object):
"""
Message Digest
"""
m2_md_ctx_free = m2.md_ctx_free
def __init__(self, algo):
# type: (str) -> None
md = getattr(m2, algo, None) # type: Optional[Callable]
if md is None:
# if the digest algorithm isn't found as an attribute of the m2
# module, try to look up the digest using get_digestbyname()
self.md = m2.get_digestbyname(algo)
else:
self.md = md()
self.ctx = m2.md_ctx_new()
m2.digest_init(self.ctx, self.md)
def __del__(self):
# type: () -> None
if getattr(self, 'ctx', None):
self.m2_md_ctx_free(self.ctx)
def update(self, data):
# type: (bytes) -> int
"""
Add data to be digested.
:return: -1 for Python error, 1 for success, 0 for OpenSSL failure.
"""
return m2.digest_update(self.ctx, data)
def final(self):
return m2.digest_final(self.ctx)
# Deprecated.
digest = final
class HMAC(object):
m2_hmac_ctx_free = m2.hmac_ctx_free
def __init__(self, key, algo='sha1'):
# type: (bytes, str) -> None
md = getattr(m2, algo, None)
if md is None:
raise ValueError('unknown algorithm', algo)
self.md = md()
self.ctx = m2.hmac_ctx_new()
m2.hmac_init(self.ctx, key, self.md)
def __del__(self):
# type: () -> None
if getattr(self, 'ctx', None):
self.m2_hmac_ctx_free(self.ctx)
def reset(self, key):
# type: (bytes) -> None
m2.hmac_init(self.ctx, key, self.md)
def update(self, data):
# type: (bytes) -> None
m2.hmac_update(self.ctx, data)
def final(self):
# type: () -> bytes
return m2.hmac_final(self.ctx)
digest = final
def hmac(key, data, algo='sha1'):
# type: (bytes, bytes, str) -> bytes
md = getattr(m2, algo, None)
if md is None:
raise ValueError('unknown algorithm', algo)
return m2.hmac(key, data, md())
class Cipher(object):
m2_cipher_ctx_free = m2.cipher_ctx_free
def __init__(self, alg, key, iv, op, key_as_bytes=0, d='md5',
salt=b'12345678', i=1, padding=1):
# type: (str, bytes, bytes, object, int, str, bytes, int, int) -> None
cipher = getattr(m2, alg, None)
if cipher is None:
raise ValueError('unknown cipher', alg)
self.cipher = cipher()
if key_as_bytes:
kmd = getattr(m2, d, None)
if kmd is None:
raise ValueError('unknown message digest', d)
key = m2.bytes_to_key(self.cipher, kmd(), key, salt, iv, i)
self.ctx = m2.cipher_ctx_new()
m2.cipher_init(self.ctx, self.cipher, key, iv, op)
self.set_padding(padding)
del key
def __del__(self):
# type: () -> None
if getattr(self, 'ctx', None):
self.m2_cipher_ctx_free(self.ctx)
def update(self, data):
# type: (bytes) -> bytes
return m2.cipher_update(self.ctx, data)
def final(self):
# type: () -> bytes
return m2.cipher_final(self.ctx)
def set_padding(self, padding=1):
# type: (int) -> int
"""
Actually always return 1
"""
return m2.cipher_set_padding(self.ctx, padding)
class PKey(object):
"""
Object to hold diverse types of asymmetric keys (also known
as "key pairs").
"""
m2_pkey_free = m2.pkey_free
m2_md_ctx_free = m2.md_ctx_free
def __init__(self, pkey=None, _pyfree=0, md='sha1'):
# type: (Optional[bytes], int, str) -> None
if pkey is not None:
self.pkey = pkey # type: bytes
self._pyfree = _pyfree
else:
self.pkey = m2.pkey_new()
self._pyfree = 1
self._set_context(md)
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_pkey_free(self.pkey)
if getattr(self, 'ctx', None):
self.m2_md_ctx_free(self.ctx)
def _ptr(self):
return self.pkey
def _set_context(self, md):
# type: (str) -> None
if not md:
self.md = None
else:
mda = getattr(m2, md, None) # type: Optional[Callable]
if mda is None:
raise ValueError('unknown message digest', md)
self.md = mda()
self.ctx = m2.md_ctx_new() ## type: Context
def reset_context(self, md='sha1'):
# type: (str) -> None
"""
Reset internal message digest context.
:param md: The message digest algorithm.
"""
self._set_context(md)
def sign_init(self):
# type: () -> None
"""
Initialise signing operation with self.
"""
m2.sign_init(self.ctx, self.md)
def sign_update(self, data):
# type: (bytes) -> None
"""
Feed data to signing operation.
:param data: Data to be signed.
"""
m2.sign_update(self.ctx, data)
def sign_final(self):
# type: () -> bytes
"""
Return signature.
:return: The signature.
"""
return m2.sign_final(self.ctx, self.pkey)
# Deprecated
update = sign_update
final = sign_final
def verify_init(self):
# type: () -> None
"""
Initialise signature verification operation with self.
"""
m2.verify_init(self.ctx, self.md)
def verify_update(self, data):
# type: (bytes) -> int
"""
Feed data to verification operation.
:param data: Data to be verified.
:return: -1 on Python error, 1 for success, 0 for OpenSSL error
"""
return m2.verify_update(self.ctx, data)
def verify_final(self, sign):
# type: (bytes) -> int
"""
Return result of verification.
:param sign: Signature to use for verification
:return: Result of verification: 1 for success, 0 for failure, -1 on
other error.
"""
return m2.verify_final(self.ctx, sign, self.pkey)
def digest_sign_init(self):
# type: () -> None
"""
Initialise digest signing operation with self.
"""
if self.md is None:
m2.digest_sign_init(self.ctx, self.pkey)
else:
m2.digest_sign_init(self.ctx, None, self.md, None, self.pkey)
def digest_sign_update(self, data):
# type: (bytes) -> None
"""
Feed data to digest signing operation.
:param data: Data to be signed.
"""
m2.digest_sign_update(self.ctx, data)
def digest_sign_final(self):
# type: () -> bytes
"""
Return signature.
:return: The signature.
"""
return m2.digest_sign_final(self.ctx)
def digest_sign(self, data):
# type: (bytes) -> bytes
"""
Return signature.
:return: The signature.
"""
if m2.OPENSSL_VERSION_NUMBER < 0x10101000:
raise NotImplemented('This method requires OpenSSL version ' +
'1.1.1 or greater.')
return m2.digest_sign(self.ctx, data)
def digest_verify_init(self):
# type: () -> None
"""
Initialise verification operation with self.
"""
if self.md is None:
m2.digest_verify_init(self.ctx, self.pkey)
else:
m2.digest_verify_init(self.ctx, None, self.md, None, self.pkey)
def digest_verify_update(self, data):
# type: (bytes) -> int
"""
Feed data to verification operation.
:param data: Data to be verified.
:return: -1 on Python error, 1 for success, 0 for OpenSSL error
"""
return m2.digest_verify_update(self.ctx, data)
def digest_verify_final(self, sign):
# type: (bytes) -> int
"""
Feed data to digest verification operation.
:param sign: Signature to use for verification
:return: Result of verification: 1 for success, 0 for failure, -1 on
other error.
"""
return m2.digest_verify_final(self.ctx, sign)
def digest_verify(self, sign, data):
# type: (bytes, bytes) -> int
"""
Return result of verification.
:param sign: Signature to use for verification
:param data: Data to be verified.
:return: Result of verification: 1 for success, 0 for failure, -1 on
other error.
"""
if m2.OPENSSL_VERSION_NUMBER < 0x10101000:
raise NotImplemented('This method requires OpenSSL version ' +
'1.1.1 or greater.')
return m2.digest_verify(self.ctx, sign, data)
def assign_rsa(self, rsa, capture=1):
# type: (RSA.RSA, int) -> int
"""
Assign the RSA key pair to self.
:param rsa: M2Crypto.RSA.RSA object to be assigned to self.
:param capture: If true (default), this PKey object will own the RSA
object, meaning that once the PKey object gets
deleted it is no longer safe to use the RSA object.
:return: Return 1 for success and 0 for failure.
"""
if capture:
ret = m2.pkey_assign_rsa(self.pkey, rsa.rsa)
if ret:
rsa._pyfree = 0
else:
ret = m2.pkey_set1_rsa(self.pkey, rsa.rsa)
return ret
def get_rsa(self):
# type: () -> RSA.RSA_pub
"""
Return the underlying RSA key if that is what the EVP
instance is holding.
"""
rsa_ptr = m2.pkey_get1_rsa(self.pkey)
rsa = RSA.RSA_pub(rsa_ptr, 1)
return rsa
def assign_ec(self, ec, capture=1):
# type: (EC.EC, int) -> int
"""
Assign the EC key pair to self.
:param ec: M2Crypto.EC.EC object to be assigned to self.
:param capture: If true (default), this PKey object will own the EC
object, meaning that once the PKey object gets
deleted it is no longer safe to use the EC object.
:return: Return 1 for success and 0 for failure.
"""
if capture:
ret = m2.pkey_assign_ec(self.pkey, ec.ec)
if ret:
ec._pyfree = 0
else:
ret = m2.pkey_set1_ec(self.pkey, ec.ec)
return ret
def get_ec(self):
# type: () -> EC.EC_pub
"""
Return the underlying EC key if that is what the EVP
instance is holding.
"""
ec_ptr = m2.pkey_get1_ec(self.pkey)
ec = EC.EC_pub(ec_ptr)
return ec
def save_key(self, file, cipher='aes_128_cbc',
callback=util.passphrase_callback):
# type: (AnyStr, Optional[str], Callable) -> int
"""
Save the key pair to a file in PEM format.
:param file: Name of file to save key to.
:param cipher: Symmetric cipher to protect the key. The default
cipher is 'aes_128_cbc'. If cipher is None, then
the key is saved in the clear.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to protect
the key. The default is
util.passphrase_callback.
"""
with BIO.openfile(file, 'wb') as bio:
return self.save_key_bio(bio, cipher, callback)
def save_key_bio(self, bio, cipher='aes_128_cbc',
callback=util.passphrase_callback):
# type: (BIO.BIO, Optional[str], Callable) -> int
"""
Save the key pair to the M2Crypto.BIO object 'bio' in PEM format.
:param bio: M2Crypto.BIO object to save key to.
:param cipher: Symmetric cipher to protect the key. The default
cipher is 'aes_128_cbc'. If cipher is None, then
the key is saved in the clear.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to protect
the key. The default is
util.passphrase_callback.
"""
if cipher is None:
return m2.pkey_write_pem_no_cipher(self.pkey, bio._ptr(), callback)
else:
proto = getattr(m2, cipher, None)
if proto is None:
raise ValueError('no such cipher %s' % cipher)
return m2.pkey_write_pem(self.pkey, bio._ptr(), proto(), callback)
def as_pem(self, cipher='aes_128_cbc', callback=util.passphrase_callback):
# type: (Optional[str], Callable) -> bytes
"""
Return key in PEM format in a string.
:param cipher: Symmetric cipher to protect the key. The default
cipher is ``'aes_128_cbc'``. If cipher is None,
then the key is saved in the clear.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to protect
the key. The default is
util.passphrase_callback.
"""
bio = BIO.MemoryBuffer()
self.save_key_bio(bio, cipher, callback)
return bio.read_all()
def as_der(self):
# type: () -> bytes
"""
Return key in DER format in a string
"""
buf = m2.pkey_as_der(self.pkey)
bio = BIO.MemoryBuffer(buf)
return bio.read_all()
def size(self):
# type: () -> int
"""
Return the size of the key in bytes.
"""
return m2.pkey_size(self.pkey)
def get_modulus(self):
# type: () -> Optional[bytes]
"""
Return the modulus in hex format.
"""
return m2.pkey_get_modulus(self.pkey)
def load_key(file, callback=util.passphrase_callback):
# type: (AnyStr, Callable) -> PKey
"""
Load an M2Crypto.EVP.PKey from file.
:param file: Name of file containing the key in PEM format.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to protect the
key.
:return: M2Crypto.EVP.PKey object.
"""
with BIO.openfile(file, 'r') as bio:
cptr = m2.pkey_read_pem(bio.bio, callback)
return PKey(cptr, 1)
def load_key_pubkey(file, callback=util.passphrase_callback):
# type: (AnyStr, Callable) -> PKey
"""
Load an M2Crypto.EVP.PKey from a public key as a file.
:param file: Name of file containing the key in PEM format.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to protect the
key.
:return: M2Crypto.EVP.PKey object.
"""
with BIO.openfile(file, 'r') as bio:
cptr = m2.pkey_read_pem_pubkey(bio._ptr(), callback)
if cptr is None:
raise EVPError(Err.get_error())
return PKey(cptr, 1)
def load_key_bio(bio, callback=util.passphrase_callback):
# type: (BIO.BIO, Callable) -> PKey
"""
Load an M2Crypto.EVP.PKey from an M2Crypto.BIO object.
:param bio: M2Crypto.BIO object containing the key in PEM format.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to protect the
key.
:return: M2Crypto.EVP.PKey object.
"""
cptr = m2.pkey_read_pem(bio._ptr(), callback)
return PKey(cptr, 1)
def load_key_bio_pubkey(bio, callback=util.passphrase_callback):
# type: (BIO.BIO, Callable) -> PKey
"""
Load an M2Crypto.EVP.PKey from a public key as a M2Crypto.BIO object.
:param bio: M2Crypto.BIO object containing the key in PEM format.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to protect the
key.
:return: M2Crypto.EVP.PKey object.
"""
cptr = m2.pkey_read_pem_pubkey(bio._ptr(), callback)
if cptr is None:
raise EVPError(Err.get_error())
return PKey(cptr, 1)
def load_key_string(string, callback=util.passphrase_callback):
# type: (AnyStr, Callable) -> PKey
"""
Load an M2Crypto.EVP.PKey from a string.
:param string: String containing the key in PEM format.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to protect the
key.
:return: M2Crypto.EVP.PKey object.
"""
bio = BIO.MemoryBuffer(string)
return load_key_bio(bio, callback)
def load_key_string_pubkey(string, callback=util.passphrase_callback):
# type: (AnyStr, Callable) -> PKey
"""
Load an M2Crypto.EVP.PKey from a public key as a string.
:param string: String containing the key in PEM format.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to protect the
key.
:return: M2Crypto.EVP.PKey object.
"""
bio = BIO.MemoryBuffer(string)
return load_key_bio_pubkey(bio, callback)
m2crypto-0.42.0/src/M2Crypto/Engine.py 0000664 0000000 0000000 00000011061 14655756567 0017432 0 ustar 00root root 0000000 0000000 # vim: sts=4 sw=4 et
from __future__ import absolute_import
"""
M2Crypto wrapper for OpenSSL ENGINE API.
Pavel Shramov
IMEC MSU
"""
from M2Crypto import EVP, Err, X509, m2
from typing import AnyStr, Callable, Optional # noqa
class EngineError(Exception):
pass
m2.engine_init_error(EngineError)
class Engine(object):
"""Wrapper for ENGINE object."""
m2_engine_free = m2.engine_free
def __init__(self, id=None, _ptr=None, _pyfree=1):
# type: (Optional[bytes], Optional[bytes], int) -> None
"""Create new Engine from ENGINE pointer or obtain by id"""
if not _ptr and not id:
raise ValueError("No engine id specified")
self._ptr = _ptr
if not self._ptr:
self._ptr = m2.engine_by_id(id)
if not self._ptr:
raise ValueError("Unknown engine: %s" % id)
self._pyfree = _pyfree
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_engine_free(self._ptr)
def init(self):
# type: () -> int
"""Obtain a functional reference to the engine.
:return: 0 on error, non-zero on success."""
return m2.engine_init(self._ptr)
def finish(self):
# type: () -> int
"""Release a functional and structural reference to the engine."""
return m2.engine_finish(self._ptr)
def ctrl_cmd_string(self, cmd, arg, optional=0):
# type: (AnyStr, Optional[AnyStr], int) -> None
"""Call ENGINE_ctrl_cmd_string"""
if isinstance(cmd, bytes):
cmd = cmd.decode()
if arg is not None and isinstance(arg, bytes):
arg = arg.decode()
if not m2.engine_ctrl_cmd_string(self._ptr, cmd, arg, optional):
raise EngineError(Err.get_error())
def get_name(self):
# type: () -> bytes
"""Return engine name"""
return m2.engine_get_name(self._ptr)
def get_id(self):
# type: () -> bytes
"""Return engine id"""
return m2.engine_get_id(self._ptr)
def set_default(self, methods=m2.ENGINE_METHOD_ALL):
# type: (int) -> int
"""
Use this engine as default for methods specified in argument
:param methods: Possible values are bitwise OR of m2.ENGINE_METHOD_*
"""
return m2.engine_set_default(self._ptr, methods)
def _engine_load_key(self, func, name, pin=None):
# type: (Callable, bytes, Optional[bytes]) -> EVP.PKey
"""Helper function for loading keys"""
ui = m2.ui_openssl()
cbd = m2.engine_pkcs11_data_new(pin)
try:
kptr = func(self._ptr, name, ui, cbd)
if not kptr:
raise EngineError(Err.get_error())
key = EVP.PKey(kptr, _pyfree=1)
finally:
m2.engine_pkcs11_data_free(cbd)
return key
def load_private_key(self, name, pin=None):
# type: (bytes, Optional[bytes]) -> X509.X509
"""Load private key with engine methods (e.g from smartcard).
If pin is not set it will be asked
"""
return self._engine_load_key(m2.engine_load_private_key, name, pin)
def load_public_key(self, name, pin=None):
# type: (bytes, Optional[bytes]) -> EVP.PKey
"""Load public key with engine methods (e.g from smartcard)."""
return self._engine_load_key(m2.engine_load_public_key, name, pin)
def load_certificate(self, name):
# type: (bytes) -> X509.X509
"""Load certificate from engine (e.g from smartcard).
NOTE: This function may be not implemented by engine!"""
cptr = m2.engine_load_certificate(self._ptr, name)
if not cptr:
raise EngineError("Certificate or card not found")
return X509.X509(cptr, _pyfree=1)
def load_dynamic_engine(id, sopath):
# type: (bytes, AnyStr) -> Engine
"""Load and return dymanic engine from sopath and assign id to it"""
if isinstance(sopath, str):
sopath = sopath.encode('utf8')
m2.engine_load_dynamic()
e = Engine('dynamic')
e.ctrl_cmd_string('SO_PATH', sopath)
e.ctrl_cmd_string('ID', id)
e.ctrl_cmd_string('LIST_ADD', '1')
e.ctrl_cmd_string('LOAD', None)
return e
def load_dynamic():
# type: () -> None
"""Load dynamic engine"""
m2.engine_load_dynamic()
def load_openssl():
# type: () -> None
"""Load openssl engine"""
m2.engine_load_openssl()
def cleanup():
# type: () -> None
"""If you load any engines, you need to clean up after your application
is finished with the engines."""
m2.engine_cleanup()
m2crypto-0.42.0/src/M2Crypto/Err.py 0000664 0000000 0000000 00000003400 14655756567 0016753 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""M2Crypto wrapper for OpenSSL Error API.
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
from M2Crypto import BIO, m2, util # noqa
from typing import Optional # noqa
def get_error():
# type: () -> Optional[str]
err = BIO.MemoryBuffer()
m2.err_print_errors(err.bio_ptr())
err_msg = err.read()
if err_msg:
return err_msg.decode()
def get_error_code():
# type: () -> int
return m2.err_get_error()
def peek_error_code():
# type: () -> int
return m2.err_peek_error()
def get_error_lib(err):
# type: (Optional[int]) -> str
err_str = m2.err_lib_error_string(err)
return err_str.decode() if err_str else ''
def get_error_func(err):
# type: (Optional[int]) -> str
err_str = m2.err_func_error_string(err)
return err_str if err_str else ''
def get_error_reason(err):
# type: (Optional[int]) -> str
err_str = m2.err_reason_error_string(err)
return err_str if err_str else ''
def get_error_message():
# type: () -> str
return get_error_reason(get_error_code())
def get_x509_verify_error(err):
# type: (Optional[int]) -> str
err_str = m2.x509_get_verify_error(err)
return err_str if err_str else ''
class SSLError(Exception):
def __init__(self, err, client_addr):
# type: (int, util.AddrType) -> None
self.err = err
self.client_addr = client_addr
def __str__(self):
# type: () -> str
if not isinstance(self.client_addr, str):
s = self.client_addr.decode()
else:
s = self.client_addr
return "%s: %s: %s" % (get_error_func(self.err), s,
get_error_reason(self.err))
class M2CryptoError(Exception):
pass
m2crypto-0.42.0/src/M2Crypto/RC4.py 0000664 0000000 0000000 00000001621 14655756567 0016616 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""M2Crypto wrapper for OpenSSL RC4 API.
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
from typing import Optional
from M2Crypto.m2 import rc4_free, rc4_new, rc4_set_key, rc4_update
class RC4(object):
"""Object interface to the stream cipher RC4."""
rc4_free = rc4_free
def __init__(self, key=None):
# type: (Optional[bytes]) -> None
self.cipher = rc4_new()
if key:
rc4_set_key(self.cipher, key)
def __del__(self):
# type: () -> None
if getattr(self, 'cipher', None):
self.rc4_free(self.cipher)
def set_key(self, key):
# type: (bytes) -> None
rc4_set_key(self.cipher, key)
def update(self, data):
# type: (bytes) -> bytes
return rc4_update(self.cipher, data)
def final(self):
# type: () -> str
return ''
m2crypto-0.42.0/src/M2Crypto/RSA.py 0000664 0000000 0000000 00000034222 14655756567 0016656 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""M2Crypto wrapper for OpenSSL RSA API.
Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved."""
import sys
from M2Crypto import BIO, Err, m2, util
from typing import Any, AnyStr, Callable, IO, Optional, Tuple # noqa
class RSAError(Exception):
pass
m2.rsa_init(RSAError)
no_padding = m2.no_padding
pkcs1_padding = m2.pkcs1_padding
if hasattr(m2, 'sslv23_padding'):
sslv23_padding = m2.sslv23_padding
pkcs1_oaep_padding = m2.pkcs1_oaep_padding
class RSA(object):
"""
RSA Key Pair.
"""
m2_rsa_free = m2.rsa_free
def __init__(self, rsa, _pyfree=0):
# type: (bytes, int) -> None
"""
:param rsa: binary representation of OpenSSL RSA type
"""
assert m2.rsa_type_check(rsa), "'rsa' type error"
self.rsa = rsa
self._pyfree = _pyfree
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_rsa_free(self.rsa)
def __len__(self):
# type: () -> int
return int(m2.rsa_size(self.rsa) << 3)
def __getattr__(self, name):
# type: (str) -> bytes
if name == 'e':
return m2.rsa_get_e(self.rsa)
elif name == 'n':
return m2.rsa_get_n(self.rsa)
else:
raise AttributeError
def pub(self):
# type: () -> Tuple[bytes, bytes]
assert self.check_key(), 'key is not initialised'
return m2.rsa_get_e(self.rsa), m2.rsa_get_n(self.rsa)
def public_encrypt(self, data, padding):
# type: (bytes, int) -> bytes
assert self.check_key(), 'key is not initialised'
return m2.rsa_public_encrypt(self.rsa, data, padding)
def public_decrypt(self, data, padding):
# type: (bytes, int) -> bytes
assert self.check_key(), 'key is not initialised'
return m2.rsa_public_decrypt(self.rsa, data, padding)
def private_encrypt(self, data, padding):
# type: (bytes, int) -> bytes
assert self.check_key(), 'key is not initialised'
return m2.rsa_private_encrypt(self.rsa, data, padding)
def private_decrypt(self, data, padding):
# type: (bytes, int) -> bytes
assert self.check_key(), 'key is not initialised'
return m2.rsa_private_decrypt(self.rsa, data, padding)
def save_key_bio(self, bio, cipher='aes_128_cbc',
callback=util.passphrase_callback):
# type: (BIO.BIO, Optional[str], Callable) -> int
"""
Save the key pair to an M2Crypto.BIO.BIO object in PEM format.
:param bio: M2Crypto.BIO.BIO object to save key to.
:param cipher: Symmetric cipher to protect the key. The default
cipher is 'aes_128_cbc'. If cipher is None, then
the key is saved in the clear.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to protect
the key. The default is
util.passphrase_callback.
"""
if cipher is None:
return m2.rsa_write_key_no_cipher(self.rsa, bio._ptr(), callback)
else:
ciph = getattr(m2, cipher, None)
if ciph is None:
raise RSAError('not such cipher %s' % cipher)
else:
ciph = ciph()
return m2.rsa_write_key(self.rsa, bio._ptr(), ciph, callback)
def save_key(self, file, cipher='aes_128_cbc',
callback=util.passphrase_callback):
# type: (AnyStr, Optional[str], Callable) -> int
"""
Save the key pair to a file in PEM format.
:param file: Name of file to save key to.
:param cipher: Symmetric cipher to protect the key. The default
cipher is 'aes_128_cbc'. If cipher is None, then
the key is saved in the clear.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to protect
the key. The default is
util.passphrase_callback.
"""
with BIO.openfile(file, 'wb') as bio:
return self.save_key_bio(bio, cipher, callback)
save_pem = save_key
def as_pem(self, cipher='aes_128_cbc', callback=util.passphrase_callback):
# type: (Optional[str], Callable) -> bytes
"""
Returns the key(pair) as a string in PEM format.
"""
bio = BIO.MemoryBuffer()
self.save_key_bio(bio, cipher, callback)
return bio.read()
def save_key_der_bio(self, bio):
# type: (BIO.BIO) -> int
"""
Save the key pair to an M2Crypto.BIO.BIO object in DER format.
:param bio: M2Crypto.BIO.BIO object to save key to.
"""
return m2.rsa_write_key_der(self.rsa, bio._ptr())
def save_key_der(self, file):
# type: (AnyStr) -> int
"""
Save the key pair to a file in DER format.
:param file: Filename to save key to
"""
with BIO.openfile(file, 'wb') as bio:
return self.save_key_der_bio(bio)
def save_pub_key_bio(self, bio):
# type: (BIO.BIO) -> int
"""
Save the public key to an M2Crypto.BIO.BIO object in PEM format.
:param bio: M2Crypto.BIO.BIO object to save key to.
"""
return m2.rsa_write_pub_key(self.rsa, bio._ptr())
def save_pub_key(self, file):
# type: (AnyStr) -> int
"""
Save the public key to a file in PEM format.
:param file: Name of file to save key to.
"""
with BIO.openfile(file, 'wb') as bio:
return m2.rsa_write_pub_key(self.rsa, bio._ptr())
def check_key(self):
# type: () -> int
"""
Validate RSA keys.
It checks that p and q are in fact prime, and that n = p*q.
:return: returns 1 if rsa is a valid RSA key, and 0 otherwise.
-1 is returned if an error occurs while checking the key.
If the key is invalid or an error occurred, the reason
code can be obtained using ERR_get_error(3).
"""
return m2.rsa_check_key(self.rsa)
def sign_rsassa_pss(self, digest, algo='sha1', salt_length=20):
# type: (bytes, str, int) -> bytes
"""
Signs a digest with the private key using RSASSA-PSS
:param digest: A digest created by using the digest method
:param salt_length: The length of the salt to use
:param algo: The hash algorithm to use
Legal values like 'sha1','sha224', 'sha256',
'ripemd160', and 'md5'.
:return: a string which is the signature
"""
hash = getattr(m2, algo, None)
if hash is None:
raise RSAError('not such hash algorithm %s' % algo)
signature = m2.rsa_padding_add_pkcs1_pss(self.rsa, digest, hash(), salt_length)
return self.private_encrypt(signature, m2.no_padding)
def verify_rsassa_pss(self, data, signature, algo='sha1', salt_length=20):
# type: (bytes, bytes, str, int) -> int
"""
Verifies the signature RSASSA-PSS
:param data: Data that has been signed
:param signature: The signature signed with RSASSA-PSS
:param salt_length: The length of the salt that was used
:param algo: The hash algorithm to use
Legal values are for example 'sha1','sha224',
'sha256', 'ripemd160', and 'md5'.
:return: 1 or 0, depending on whether the signature was
verified or not.
"""
hash = getattr(m2, algo, None)
if hash is None:
raise RSAError('not such hash algorithm %s' % algo)
plain_signature = self.public_decrypt(signature, m2.no_padding)
return m2.rsa_verify_pkcs1_pss(self.rsa, data, plain_signature, hash(), salt_length)
def sign(self, digest, algo='sha1'):
# type: (bytes, str) -> bytes
"""
Signs a digest with the private key
:param digest: A digest created by using the digest method
:param algo: The method that created the digest.
Legal values like 'sha1','sha224', 'sha256',
'ripemd160', and 'md5'.
:return: a string which is the signature
"""
digest_type = getattr(m2, 'NID_' + algo, None)
if digest_type is None:
raise ValueError('unknown algorithm', algo)
return m2.rsa_sign(self.rsa, digest, digest_type)
def verify(self, data, signature, algo='sha1'):
# type: (bytes, bytes, str) -> int
"""
Verifies the signature with the public key
:param data: Data that has been signed
:param signature: The signature signed with the private key
:param algo: The method use to create digest from the data
before it was signed. Legal values like
'sha1','sha224', 'sha256', 'ripemd160', and 'md5'.
:return: 1 or 0, depending on whether the signature was
verified or not.
"""
digest_type = getattr(m2, 'NID_' + algo, None)
if digest_type is None:
raise ValueError('unknown algorithm', algo)
return m2.rsa_verify(self.rsa, data, signature, digest_type)
class RSA_pub(RSA):
"""
Object interface to an RSA public key.
"""
def __setattr__(self, name, value):
# type: (str, bytes) -> None
if name in ['e', 'n']:
raise RSAError('use factory function new_pub_key() to set (e, n)')
else:
self.__dict__[name] = value
def private_encrypt(self, *argv):
# type: (*Any) -> None
raise RSAError('RSA_pub object has no private key')
def private_decrypt(self, *argv):
# type: (*Any) -> None
raise RSAError('RSA_pub object has no private key')
def save_key(self, file, *args, **kw):
# type: (AnyStr, *Any, **Any) -> int
"""
Save public key to file.
"""
return self.save_pub_key(file)
def save_key_bio(self, bio, *args, **kw):
# type: (BIO.BIO, *Any, **Any) -> int
"""
Save public key to BIO.
"""
return self.save_pub_key_bio(bio)
# save_key_der
# save_key_der_bio
def check_key(self):
# type: () -> int
return m2.rsa_check_pub_key(self.rsa)
def rsa_error():
# type: () -> None
raise RSAError(Err.get_error_message())
def keygen_callback(p, n, out=sys.stdout):
# type: (int, Any, IO[str]) -> None
"""
Default callback for gen_key().
"""
ch = ['.', '+', '*', '\n']
out.write(ch[p])
out.flush()
def gen_key(bits, e, callback=keygen_callback):
# type: (int, int, Callable) -> RSA
"""
Generate an RSA key pair.
:param bits: Key length, in bits.
:param e: The RSA public exponent.
:param callback: A Python callable object that is invoked
during key generation; its usual purpose is to
provide visual feedback. The default callback is
keygen_callback.
:return: M2Crypto.RSA.RSA object.
"""
return RSA(m2.rsa_generate_key(bits, e, callback), 1)
def load_key(file, callback=util.passphrase_callback):
# type: (AnyStr, Callable) -> RSA
"""
Load an RSA key pair from file.
:param file: Name of file containing RSA public key in PEM format.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to unlock the
key. The default is util.passphrase_callback.
:return: M2Crypto.RSA.RSA object.
"""
with BIO.openfile(file) as bio:
return load_key_bio(bio, callback)
def load_key_bio(bio, callback=util.passphrase_callback):
# type: (BIO.BIO, Callable) -> RSA
"""
Load an RSA key pair from an M2Crypto.BIO.BIO object.
:param bio: M2Crypto.BIO.BIO object containing RSA key pair in PEM
format.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to unlock the
key. The default is util.passphrase_callback.
:return: M2Crypto.RSA.RSA object.
"""
rsa = m2.rsa_read_key(bio._ptr(), callback)
if rsa is None:
rsa_error()
return RSA(rsa, 1)
def load_key_string(string, callback=util.passphrase_callback):
# type: (AnyStr, Callable) -> RSA
"""
Load an RSA key pair from a string.
:param string: String containing RSA key pair in PEM format.
:param callback: A Python callable object that is invoked
to acquire a passphrase with which to unlock the
key. The default is util.passphrase_callback.
:return: M2Crypto.RSA.RSA object.
"""
bio = BIO.MemoryBuffer(string)
return load_key_bio(bio, callback)
def load_pub_key(file):
# type: (AnyStr) -> RSA_pub
"""
Load an RSA public key from file.
:param file: Name of file containing RSA public key in PEM format.
:return: M2Crypto.RSA.RSA_pub object.
"""
with BIO.openfile(file) as bio:
return load_pub_key_bio(bio)
def load_pub_key_bio(bio):
# type: (BIO.BIO) -> RSA_pub
"""
Load an RSA public key from an M2Crypto.BIO.BIO object.
:param bio: M2Crypto.BIO.BIO object containing RSA public key in PEM
format.
:return: M2Crypto.RSA.RSA_pub object.
"""
rsa = m2.rsa_read_pub_key(bio._ptr())
if rsa is None:
rsa_error()
return RSA_pub(rsa, 1)
def new_pub_key(e_n):
# type: (Tuple[bytes, bytes]) -> RSA_pub
"""
Instantiate an RSA_pub object from an (e, n) tuple.
:param e: The RSA public exponent; it is a string in OpenSSL's MPINT
format - 4-byte big-endian bit-count followed by the
appropriate number of bits.
:param n: The RSA composite of primes; it is a string in OpenSSL's
MPINT format - 4-byte big-endian bit-count followed by the
appropriate number of bits.
:return: M2Crypto.RSA.RSA_pub object.
"""
(e, n) = e_n
rsa = m2.rsa_new()
m2.rsa_set_en(rsa, e, n)
return RSA_pub(rsa, 1)
m2crypto-0.42.0/src/M2Crypto/Rand.py 0000664 0000000 0000000 00000010616 14655756567 0017116 0 ustar 00root root 0000000 0000000 """M2Crypto wrapper for OpenSSL PRNG. Requires OpenSSL 0.9.5 and above.
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.
Copyright (c) 2014-2017 Matej Cepl. All rights reserved.
See LICENCE for the license information.
"""
from __future__ import absolute_import
from M2Crypto import m2
from typing import AnyStr, Tuple # noqa
__all__ = ['rand_seed', 'rand_add', 'load_file', 'save_file', 'rand_bytes',
'rand_pseudo_bytes', 'rand_file_name', 'rand_status']
class RandError(ValueError):
pass
m2.rand_init(RandError)
def rand_add(blob, entropy):
# type: (bytes, float) -> None
"""
Mixes blob into the PRNG state.
:param blob: added data
:param entropy: (the lower bound of) an estimate of how much randomness
is contained in blob, measured in bytes.
Thus, if the data at buf are unpredictable to an adversary, this
increases the uncertainty about the state and makes the PRNG output less
predictable. Suitable input comes from user interaction (random key
presses, mouse movements) and certain hardware events.
Details about sources of randomness and how to estimate their entropy
can be found in the literature, e.g. RFC 1750.
"""
m2.rand_add(blob, entropy) # pylint: disable=no-member
def rand_seed(seed):
# type: (bytes) -> None
"""
Equivalent to rand_add() when len(seed) == entropy.
:param seed: added data (see description at rand_add)
"""
m2.rand_seed(seed) # pylint: disable=no-member
def rand_status():
# type: () -> int
"""
Check whether there is enough entropy in PRNG.
:return: 1 if the PRNG has been seeded with enough
data, 0 otherwise.
"""
return m2.rand_status() # pylint: disable=no-member
def rand_file_name():
# type: () -> str
"""
Generate a default path for the random seed file.
:return: string with the filename.
The seed file is $RANDFILE if that environment variable
is set, $HOME/.rnd otherwise. If $HOME is not set either,
an error occurs.
"""
return m2.rand_file_name().decode() # pylint: disable=no-member
def load_file(filename, max_bytes):
# type: (AnyStr, int) -> int
"""
Read a number of bytes from file filename and adds them to the PRNG.
If max_bytes is non-negative, up to to max_bytes are read; starting with
OpenSSL 0.9.5, if max_bytes is -1, the complete file is read.
:param filename:
:param max_bytes:
:return: the number of bytes read.
"""
filename = filename.decode() if isinstance(filename, bytes) else filename
return m2.rand_load_file(filename, max_bytes) # pylint: disable=no-member
def save_file(filename):
# type: (AnyStr) -> int
"""
Write a number of random bytes (currently 1024) to file.
The file then can be used to initialize the PRNG by calling load_file() in
a later session.
:param filename:
:return: returns the number of bytes written, and -1 if the bytes
written were generated without appropriate seed.
"""
return m2.rand_save_file(filename) # pylint: disable=no-member
def rand_bytes(num):
# type: (int) -> bytes
"""
Return n cryptographically strong pseudo-random bytes.
An error occurs if the PRNG has not been seeded with enough randomness
to ensure an unpredictable byte sequence.
:param num: number of bytes to be returned
:return: random bytes
"""
return m2.rand_bytes(num) # pylint: disable=no-member
def rand_pseudo_bytes(num):
# type: (int) -> Tuple[bytes, int]
"""
Return num pseudo-random bytes into buf.
Pseudo-random byte sequences generated by this method will be unique
if they are of sufficient length, but are not necessarily
unpredictable. They can be used for non-cryptographic purposes and for
certain purposes in cryptographic protocols, but usually not for key
generation etc.
Output of the function is mixed into the entropy pool before
retrieving the new pseudo-random bytes unless disabled at compile
time (see FAQ).
:param num: number of bytes to be returned
:return: random bytes
"""
import warnings
if m2.OPENSSL_VERSION_NUMBER >= 0x10100000:
warnings.warn('The underlying OpenSSL method has been ' +
'deprecated. Use Rand.rand_bytes instead.',
DeprecationWarning)
return m2.rand_pseudo_bytes(num) # pylint: disable=no-member
m2crypto-0.42.0/src/M2Crypto/SMIME.py 0000664 0000000 0000000 00000021417 14655756567 0017105 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""M2Crypto wrapper for OpenSSL S/MIME API.
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
from M2Crypto import BIO, EVP, Err, X509, m2, util
from typing import AnyStr, Callable, Optional # noqa
PKCS7_TEXT = m2.PKCS7_TEXT # type: int
PKCS7_NOCERTS = m2.PKCS7_NOCERTS # type: int
PKCS7_NOSIGS = m2.PKCS7_NOSIGS # type: int
PKCS7_NOCHAIN = m2.PKCS7_NOCHAIN # type: int
PKCS7_NOINTERN = m2.PKCS7_NOINTERN # type: int
PKCS7_NOVERIFY = m2.PKCS7_NOVERIFY # type: int
PKCS7_DETACHED = m2.PKCS7_DETACHED # type: int
PKCS7_BINARY = m2.PKCS7_BINARY # type: int
PKCS7_NOATTR = m2.PKCS7_NOATTR # type: int
PKCS7_SIGNED = m2.PKCS7_SIGNED # type: int
PKCS7_ENVELOPED = m2.PKCS7_ENVELOPED # type: int
PKCS7_SIGNED_ENVELOPED = m2.PKCS7_SIGNED_ENVELOPED # Deprecated
PKCS7_DATA = m2.PKCS7_DATA # type: int
class PKCS7_Error(Exception):
pass
m2.pkcs7_init(PKCS7_Error)
class PKCS7(object):
m2_pkcs7_free = m2.pkcs7_free
def __init__(self, pkcs7=None, _pyfree=0):
# type: (Optional[bytes], int) -> None
"""PKCS7 object.
:param pkcs7: binary representation of
the OpenSSL type PKCS7
"""
if pkcs7 is not None:
self.pkcs7 = pkcs7
self._pyfree = _pyfree
else:
self.pkcs7 = m2.pkcs7_new()
self._pyfree = 1
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_pkcs7_free(self.pkcs7)
def _ptr(self):
return self.pkcs7
def type(self, text_name=0):
# type: (int) -> int
if text_name:
return m2.pkcs7_type_sn(self.pkcs7)
else:
return m2.pkcs7_type_nid(self.pkcs7)
def write(self, bio):
# type: (BIO.BIO) -> int
return m2.pkcs7_write_bio(self.pkcs7, bio._ptr())
def write_der(self, bio):
# type: (BIO.BIO) -> int
return m2.pkcs7_write_bio_der(self.pkcs7, bio._ptr())
def get0_signers(self, certs, flags=0):
# type: (X509.X509_Stack, int) -> X509.X509_Stack
return X509.X509_Stack(m2.pkcs7_get0_signers(self.pkcs7,
certs.stack, flags), 1)
def load_pkcs7(p7file):
# type: (AnyStr) -> PKCS7
with BIO.openfile(p7file, 'r') as bio:
p7_ptr = m2.pkcs7_read_bio(bio.bio)
return PKCS7(p7_ptr, 1)
def load_pkcs7_der(p7file):
# type: (AnyStr) -> PKCS7
with BIO.openfile(p7file, 'rb') as bio:
p7_ptr = m2.pkcs7_read_bio_der(bio.bio)
return PKCS7(p7_ptr, 1)
def load_pkcs7_bio(p7_bio):
# type: (BIO.BIO) -> PKCS7
p7_ptr = m2.pkcs7_read_bio(p7_bio._ptr())
return PKCS7(p7_ptr, 1)
def load_pkcs7_bio_der(p7_bio):
# type: (BIO.BIO) -> PKCS7
p7_ptr = m2.pkcs7_read_bio_der(p7_bio._ptr())
return PKCS7(p7_ptr, 1)
def smime_load_pkcs7(p7file):
# type: (AnyStr) -> PKCS7
bio = m2.bio_new_file(p7file, 'r')
try:
p7_ptr, bio_ptr = m2.smime_read_pkcs7(bio)
finally:
m2.bio_free(bio)
if bio_ptr is None:
return PKCS7(p7_ptr, 1), None
else:
return PKCS7(p7_ptr, 1), BIO.BIO(bio_ptr, 1)
def smime_load_pkcs7_bio(p7_bio):
# type: (BIO.BIO) -> PKCS7
p7_ptr, bio_ptr = m2.smime_read_pkcs7(p7_bio._ptr())
if p7_ptr is None:
raise SMIME_Error(Err.get_error())
if bio_ptr is None:
return PKCS7(p7_ptr, 1), None
else:
return PKCS7(p7_ptr, 1), BIO.BIO(bio_ptr, 1)
class Cipher(object):
"""Object interface to EVP_CIPHER without all the frills of
M2Crypto.EVP.Cipher.
"""
def __init__(self, algo):
# type: (str) -> None
cipher = getattr(m2, algo, None)
if cipher is None:
raise ValueError('unknown cipher', algo)
self.cipher = cipher()
def _ptr(self):
return self.cipher
class SMIME_Error(Exception):
pass
m2.smime_init(SMIME_Error)
# FIXME class has no __init__ method
class SMIME(object):
def load_key(self, keyfile, certfile=None,
callback=util.passphrase_callback):
# type: (AnyStr, Optional[AnyStr], Callable) -> None
if certfile is None:
certfile = keyfile
self.pkey = EVP.load_key(keyfile, callback)
self.x509 = X509.load_cert(certfile)
def load_key_bio(self, keybio, certbio=None,
callback=util.passphrase_callback):
# type: (BIO.BIO, Optional[BIO.BIO], Callable) -> None
if certbio is None:
certbio = keybio
self.pkey = EVP.load_key_bio(keybio, callback)
self.x509 = X509.load_cert_bio(certbio)
def set_x509_stack(self, stack):
# type: (X509.X509_Stack) -> None
assert isinstance(stack, X509.X509_Stack)
self.x509_stack = stack
def set_x509_store(self, store):
# type: (X509.X509_Store) -> None
assert isinstance(store, X509.X509_Store)
self.x509_store = store
def set_cipher(self, cipher):
# type: (Cipher) -> None
assert isinstance(cipher, Cipher)
self.cipher = cipher
def unset_key(self):
# type: () -> None
del self.pkey
del self.x509
def unset_x509_stack(self):
# type: () -> None
del self.x509_stack
def unset_x509_store(self):
# type: () -> None
del self.x509_store
def unset_cipher(self):
# type: () -> None
del self.cipher
def encrypt(self, data_bio, flags=0):
# type: (BIO.BIO, int) -> PKCS7
if not hasattr(self, 'cipher'):
raise SMIME_Error('no cipher: use set_cipher()')
if not hasattr(self, 'x509_stack'):
raise SMIME_Error('no recipient certs: use set_x509_stack()')
pkcs7 = m2.pkcs7_encrypt(self.x509_stack._ptr(), data_bio._ptr(),
self.cipher._ptr(), flags)
return PKCS7(pkcs7, 1)
def decrypt(self, pkcs7, flags=0):
# type: (PKCS7, int) -> Optional[bytes]
if not hasattr(self, 'pkey'):
raise SMIME_Error('no private key: use load_key()')
if not hasattr(self, 'x509'):
raise SMIME_Error('no certificate: load_key() used incorrectly?')
blob = m2.pkcs7_decrypt(pkcs7._ptr(), self.pkey._ptr(),
self.x509._ptr(), flags)
return blob
def sign(self, data_bio, flags=0, algo='sha1'):
# type: (BIO.BIO, int, Optional[str]) -> PKCS7
if not hasattr(self, 'pkey'):
raise SMIME_Error('no private key: use load_key()')
hash = getattr(m2, algo, None)
if hash is None:
raise SMIME_Error('no such hash algorithm %s' % algo)
if hasattr(self, 'x509_stack'):
pkcs7 = m2.pkcs7_sign1(self.x509._ptr(), self.pkey._ptr(),
self.x509_stack._ptr(),
data_bio._ptr(), hash(), flags)
return PKCS7(pkcs7, 1)
else:
pkcs7 = m2.pkcs7_sign0(self.x509._ptr(), self.pkey._ptr(),
data_bio._ptr(), hash(), flags)
return PKCS7(pkcs7, 1)
def verify(self, pkcs7, data_bio=None, flags=0):
# type: (PKCS7, Optional[BIO.BIO], int) -> Optional[bytes]
if not hasattr(self, 'x509_stack'):
raise SMIME_Error('no signer certs: use set_x509_stack()')
if not hasattr(self, 'x509_store'):
raise SMIME_Error('no x509 cert store: use set_x509_store()')
assert isinstance(pkcs7, PKCS7), 'pkcs7 not an instance of PKCS7'
p7 = pkcs7._ptr()
if data_bio is None:
blob = m2.pkcs7_verify0(p7, self.x509_stack._ptr(),
self.x509_store._ptr(), flags)
else:
blob = m2.pkcs7_verify1(p7, self.x509_stack._ptr(),
self.x509_store._ptr(),
data_bio._ptr(), flags)
return blob
def write(self, out_bio, pkcs7, data_bio=None, flags=0):
# type: (BIO.BIO, PKCS7, Optional[BIO.BIO], int) -> int
assert isinstance(pkcs7, PKCS7)
if data_bio is None:
return m2.smime_write_pkcs7(out_bio._ptr(), pkcs7._ptr(), flags)
else:
return m2.smime_write_pkcs7_multi(out_bio._ptr(), pkcs7._ptr(),
data_bio._ptr(), flags)
def text_crlf(text):
# type: (bytes) -> bytes
bio_in = BIO.MemoryBuffer(text)
bio_out = BIO.MemoryBuffer()
if m2.smime_crlf_copy(bio_in._ptr(), bio_out._ptr()):
return bio_out.read()
else:
raise SMIME_Error(Err.get_error())
def text_crlf_bio(bio_in):
# type: (BIO.BIO) -> BIO.BIO
bio_out = BIO.MemoryBuffer()
if m2.smime_crlf_copy(bio_in._ptr(), bio_out._ptr()):
return bio_out
else:
raise SMIME_Error(Err.get_error())
m2crypto-0.42.0/src/M2Crypto/SSL/ 0000775 0000000 0000000 00000000000 14655756567 0016315 5 ustar 00root root 0000000 0000000 m2crypto-0.42.0/src/M2Crypto/SSL/Checker.py 0000664 0000000 0000000 00000025344 14655756567 0020243 0 ustar 00root root 0000000 0000000 """
SSL peer certificate checking routines
Copyright (c) 2004-2007 Open Source Applications Foundation.
All rights reserved.
Copyright 2008 Heikki Toivonen. All rights reserved.
"""
__all__ = ['SSLVerificationError', 'NoCertificate', 'WrongCertificate',
'WrongHost', 'Checker']
import re
import socket
from M2Crypto import X509, m2 # noqa
from typing import AnyStr, Optional # noqa
class SSLVerificationError(Exception):
pass
class NoCertificate(SSLVerificationError):
pass
class WrongCertificate(SSLVerificationError):
pass
class WrongHost(SSLVerificationError):
def __init__(self, expectedHost, actualHost, fieldName='commonName'):
# type: (str, AnyStr, str) -> None
"""
This exception will be raised if the certificate returned by the
peer was issued for a different host than we tried to connect to.
This could be due to a server misconfiguration or an active attack.
:param expectedHost: The name of the host we expected to find in the
certificate.
:param actualHost: The name of the host we actually found in the
certificate.
:param fieldName: The field name where we noticed the error. This
should be either 'commonName' or 'subjectAltName'.
"""
if fieldName not in ('commonName', 'subjectAltName'):
raise ValueError(
'Unknown fieldName, should be either commonName ' +
'or subjectAltName')
SSLVerificationError.__init__(self)
self.expectedHost = expectedHost
self.actualHost = actualHost
self.fieldName = fieldName
def __str__(self):
# type: () -> str
return 'Peer certificate %s does not match host, expected %s, got %s' \
% (self.fieldName, self.expectedHost, self.actualHost)
class Checker(object):
numericIpMatch = re.compile(r'^[0-9]+(\.[0-9]+)*$')
def __init__(self, host=None, peerCertHash=None, peerCertDigest='sha1'):
# type: (Optional[str], Optional[bytes], str) -> None
self.host = host
self.fingerprint = peerCertHash
self.digest = peerCertDigest # type: str
def __call__(self, peerCert, host=None):
# type: (X509.X509, Optional[str]) -> bool
if peerCert is None:
raise NoCertificate('peer did not return certificate')
if host is not None:
self.host = host # type: str
if self.fingerprint:
if self.digest not in ('sha1', 'md5'):
raise ValueError('unsupported digest "%s"' % self.digest)
if self.digest == 'sha1':
expected_len = 40
elif self.digest == 'md5':
expected_len = 32
else:
raise ValueError('Unexpected digest {0}'.format(self.digest))
if len(self.fingerprint) != expected_len:
raise WrongCertificate(
('peer certificate fingerprint length does not match\n' +
'fingerprint: {0}\nexpected = {1}\n' +
'observed = {2}').format(self.fingerprint,
expected_len,
len(self.fingerprint)))
expected_fingerprint = self.fingerprint.decode() if isinstance(self.fingerprint, bytes) \
else self.fingerprint
observed_fingerprint = peerCert.get_fingerprint(md=self.digest)
if observed_fingerprint != expected_fingerprint:
raise WrongCertificate(
('peer certificate fingerprint does not match\n' +
'expected = {0},\n' +
'observed = {1}').format(expected_fingerprint,
observed_fingerprint))
if self.host:
hostValidationPassed = False
self.useSubjectAltNameOnly = False
# subjectAltName=DNS:somehost[, ...]*
try:
subjectAltName = peerCert.get_ext('subjectAltName').get_value()
if self._splitSubjectAltName(self.host, subjectAltName):
hostValidationPassed = True
elif self.useSubjectAltNameOnly:
raise WrongHost(expectedHost=self.host,
actualHost=subjectAltName,
fieldName='subjectAltName')
except LookupError:
pass
# commonName=somehost[, ...]*
if not hostValidationPassed:
hasCommonName = False
commonNames = ''
for entry in peerCert.get_subject().get_entries_by_nid(
m2.NID_commonName):
hasCommonName = True
commonName = entry.get_data().as_text()
if not commonNames:
commonNames = commonName
else:
commonNames += ',' + commonName
if self._match(self.host, commonName):
hostValidationPassed = True
break
if not hasCommonName:
raise WrongCertificate('no commonName in peer certificate')
if not hostValidationPassed:
raise WrongHost(expectedHost=self.host,
actualHost=commonNames,
fieldName='commonName')
return True
def _splitSubjectAltName(self, host, subjectAltName):
# type: (AnyStr, AnyStr) -> bool
"""
>>> check = Checker()
>>> check._splitSubjectAltName(host='my.example.com',
... subjectAltName='DNS:my.example.com')
True
>>> check._splitSubjectAltName(host='my.example.com',
... subjectAltName='DNS:*.example.com')
True
>>> check._splitSubjectAltName(host='my.example.com',
... subjectAltName='DNS:m*.example.com')
True
>>> check._splitSubjectAltName(host='my.example.com',
... subjectAltName='DNS:m*ample.com')
False
>>> check.useSubjectAltNameOnly
True
>>> check._splitSubjectAltName(host='my.example.com',
... subjectAltName='DNS:m*ample.com, othername:')
False
>>> check._splitSubjectAltName(host='my.example.com',
... subjectAltName='DNS:m*ample.com, DNS:my.example.org')
False
>>> check._splitSubjectAltName(host='my.example.com',
... subjectAltName='DNS:m*ample.com, DNS:my.example.com')
True
>>> check._splitSubjectAltName(host='my.example.com',
... subjectAltName='DNS:my.example.com, DNS:my.example.org')
True
>>> check.useSubjectAltNameOnly
True
>>> check._splitSubjectAltName(host='my.example.com',
... subjectAltName='')
False
>>> check._splitSubjectAltName(host='my.example.com',
... subjectAltName='othername:')
False
>>> check.useSubjectAltNameOnly
False
"""
self.useSubjectAltNameOnly = False
for certHost in subjectAltName.split(','):
certHost = certHost.lower().strip()
if certHost[:4] == 'dns:':
self.useSubjectAltNameOnly = True
if self._match(host, certHost[4:]):
return True
elif certHost[:11] == 'ip address:':
self.useSubjectAltNameOnly = True
if self._matchIPAddress(host, certHost[11:]):
return True
return False
def _match(self, host, certHost):
# type: (str, str) -> bool
"""
>>> check = Checker()
>>> check._match(host='my.example.com', certHost='my.example.com')
True
>>> check._match(host='my.example.com', certHost='*.example.com')
True
>>> check._match(host='my.example.com', certHost='m*.example.com')
True
>>> check._match(host='my.example.com', certHost='m*.EXAMPLE.com')
True
>>> check._match(host='my.example.com', certHost='m*ample.com')
False
>>> check._match(host='my.example.com', certHost='*.*.com')
False
>>> check._match(host='1.2.3.4', certHost='1.2.3.4')
True
>>> check._match(host='1.2.3.4', certHost='*.2.3.4')
False
>>> check._match(host='1234', certHost='1234')
True
"""
# XXX See RFC 2818 and 3280 for matching rules, this is may not
# XXX yet be complete.
host = host.lower()
certHost = certHost.lower()
if host == certHost:
return True
if certHost.count('*') > 1:
# Not sure about this, but being conservative
return False
if self.numericIpMatch.match(host) or \
self.numericIpMatch.match(certHost.replace('*', '')):
# Not sure if * allowed in numeric IP, but think not.
return False
if certHost.find('\\') > -1:
# Not sure about this, maybe some encoding might have these.
# But being conservative for now, because regex below relies
# on this.
return False
# Massage certHost so that it can be used in regex
certHost = certHost.replace('.', '\\.')
certHost = certHost.replace('*', '[^\\.]*')
if re.compile('^%s$' % certHost).match(host):
return True
return False
def _matchIPAddress(self, host, certHost):
# type: (AnyStr, AnyStr) -> bool
"""
>>> check = Checker()
>>> check._matchIPAddress(host='my.example.com',
... certHost='my.example.com')
False
>>> check._matchIPAddress(host='1.2.3.4', certHost='1.2.3.4')
True
>>> check._matchIPAddress(host='1.2.3.4', certHost='*.2.3.4')
False
>>> check._matchIPAddress(host='1.2.3.4', certHost='1.2.3.40')
False
>>> check._matchIPAddress(host='::1', certHost='::1')
True
>>> check._matchIPAddress(host='::1', certHost='0:0:0:0:0:0:0:1')
True
>>> check._matchIPAddress(host='::1', certHost='::2')
False
"""
try:
canonical = socket.getaddrinfo(host, 0, 0, socket.SOCK_STREAM, 0,
socket.AI_NUMERICHOST)
certCanonical = socket.getaddrinfo(certHost, 0, 0,
socket.SOCK_STREAM, 0,
socket.AI_NUMERICHOST)
except:
return False
return canonical == certCanonical
if __name__ == '__main__':
import doctest
doctest.testmod()
m2crypto-0.42.0/src/M2Crypto/SSL/Cipher.py 0000664 0000000 0000000 00000002731 14655756567 0020104 0 ustar 00root root 0000000 0000000 """SSL Ciphers
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
__all__ = ['Cipher', 'Cipher_Stack']
from M2Crypto import m2
from typing import Iterable # noqa
class Cipher(object):
def __init__(self, cipher):
# type: (str) -> None
self.cipher = cipher
def __len__(self):
# type: () -> int
return m2.ssl_cipher_get_bits(self.cipher)
def __repr__(self):
# type: () -> str
return "%s-%s" % (self.name(), len(self))
def __str__(self):
# type: () -> str
return "%s-%s" % (self.name(), len(self))
def version(self):
# type: () -> int
return m2.ssl_cipher_get_version(self.cipher)
def name(self):
# type: () -> str
return m2.ssl_cipher_get_name(self.cipher)
class Cipher_Stack(object):
def __init__(self, stack):
# type: (bytes) -> None
"""
:param stack: binary of the C-type STACK_OF(SSL_CIPHER)
"""
self.stack = stack
def __len__(self):
# type: () -> int
return m2.sk_ssl_cipher_num(self.stack)
def __getitem__(self, idx):
# type: (int) -> Cipher
if not 0 <= idx < m2.sk_ssl_cipher_num(self.stack):
raise IndexError('index out of range')
v = m2.sk_ssl_cipher_value(self.stack, idx)
return Cipher(v)
def __iter__(self):
# type: () -> Iterable
for i in range(m2.sk_ssl_cipher_num(self.stack)):
yield self[i]
m2crypto-0.42.0/src/M2Crypto/SSL/Connection.py 0000664 0000000 0000000 00000062253 14655756567 0020776 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""SSL Connection aka socket
Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.
Portions created by Open Source Applications Foundation (OSAF) are
Copyright (C) 2004-2007 OSAF. All Rights Reserved.
Copyright 2008 Heikki Toivonen. All rights reserved.
"""
import logging
import socket
import io
from M2Crypto import BIO, Err, X509, m2, util # noqa
from M2Crypto.SSL import Checker, Context, timeout # noqa
from M2Crypto.SSL import SSLError
from M2Crypto.SSL.Cipher import Cipher, Cipher_Stack
from M2Crypto.SSL.Session import Session
from typing import (
Any,
AnyStr,
Callable,
Optional,
Tuple,
Union,
) # noqa
__all__ = [
'Connection',
'timeout', # XXX Not really, but for documentation purposes
]
log = logging.getLogger(__name__)
def _serverPostConnectionCheck(*args, **kw):
# type: (*Any, **Any) -> int
return 1
class Connection(object):
"""An SSL connection."""
serverPostConnectionCheck = _serverPostConnectionCheck
m2_bio_free = m2.bio_free
m2_ssl_free = m2.ssl_free
m2_bio_noclose = m2.bio_noclose
def __init__(self, ctx, sock=None, family=socket.AF_INET):
# type: (Context, Optional[socket.socket], int) -> None
"""
:param ctx: SSL.Context
:param sock: socket to be used
:param family: socket family
"""
# The Checker needs to be an instance attribute
# and not a class attribute for thread safety reason
self.clientPostConnectionCheck = Checker.Checker()
self._bio_freed = False
self.ctx = ctx
self.ssl = m2.ssl_new(self.ctx.ctx) # type: bytes
if sock is not None:
self.socket = sock
else:
self.socket = socket.socket(family, socket.SOCK_STREAM)
self.socket.setsockopt(
socket.SOL_SOCKET, socket.SO_REUSEADDR, 1
)
self._fileno = self.socket.fileno()
self._timeout = self.socket.gettimeout()
if self._timeout is None:
self._timeout = -1.0
self.ssl_close_flag = m2.bio_noclose
if self.ctx.post_connection_check is not None:
self.set_post_connection_check_callback(
self.ctx.post_connection_check
)
self.host = None
def _free_bio(self):
"""
Free the sslbio and sockbio, and close the socket.
"""
# Do not do it twice
if not self._bio_freed:
if getattr(self, 'sslbio', None):
self.m2_bio_free(self.sslbio)
if getattr(self, 'sockbio', None):
self.m2_bio_free(self.sockbio)
if (
self.ssl_close_flag == self.m2_bio_noclose
and getattr(self, 'ssl', None)
):
self.m2_ssl_free(self.ssl)
self.socket.close()
self._bio_freed = True
def __del__(self):
# type: () -> None
# Notice that M2Crypto doesn't automatically shuts down the
# connection here. You have to call self.close() in your
# program, M2Crypto won't do it automatically for you.
if getattr(self, 'sslbio', None):
self.m2_bio_free(self.sslbio)
if getattr(self, 'sockbio', None):
self.m2_bio_free(self.sockbio)
if self.ssl_close_flag == self.m2_bio_noclose and getattr(
self, 'ssl', None
):
self.m2_ssl_free(self.ssl)
self.socket.close()
def close(self, freeBio=False):
# type: (Optional[bool]) -> None
"""
if freeBio is true, call _free_bio
"""
m2.ssl_shutdown(self.ssl)
if freeBio:
self._free_bio()
def clear(self):
# type: () -> int
"""
If there were errors in this connection, call clear() rather
than close() to end it, so that bad sessions will be cleared
from cache.
"""
return m2.ssl_clear(self.ssl)
def set_shutdown(self, mode):
# type: (int) -> None
"""Sets the shutdown state of the Connection to mode.
The shutdown state of an ssl connection is a bitmask of (use
m2.SSL_* constants):
0 No shutdown setting, yet.
SSL_SENT_SHUTDOWN
A "close notify" shutdown alert was sent to the peer, the
connection is being considered closed and the session is
closed and correct.
SSL_RECEIVED_SHUTDOWN
A shutdown alert was received form the peer, either a normal
"close notify" or a fatal error.
SSL_SENT_SHUTDOWN and SSL_RECEIVED_SHUTDOWN can be set at the
same time.
:param mode: set the mode bitmask.
"""
m2.ssl_set_shutdown1(self.ssl, mode)
def get_shutdown(self):
# type: () -> None
"""Get the current shutdown mode of the Connection."""
return m2.ssl_get_shutdown(self.ssl)
def bind(self, addr):
# type: (util.AddrType) -> None
self.socket.bind(addr)
def listen(self, qlen=5):
# type: (int) -> None
self.socket.listen(qlen)
def ssl_get_error(self, ret):
# type: (int) -> int
return m2.ssl_get_error(self.ssl, ret)
def set_bio(self, readbio, writebio):
# type: (BIO.BIO, BIO.BIO) -> None
"""Explicitly set read and write bios
Connects the BIOs for the read and write operations of the
TLS/SSL (encrypted) side of ssl.
The SSL engine inherits the behaviour of both BIO objects,
respectively. If a BIO is non-blocking, the Connection will also
have non-blocking behaviour.
If there was already a BIO connected to Connection, BIO_free()
will be called (for both the reading and writing side, if
different).
:param readbio: BIO for reading
:param writebio: BIO for writing.
"""
m2.ssl_set_bio(self.ssl, readbio._ptr(), writebio._ptr())
def set_client_CA_list_from_file(self, cafile):
# type: (AnyStr) -> None
"""Set the acceptable client CA list.
If the client returns a certificate, it must have been issued by
one of the CAs listed in cafile.
Makes sense only for servers.
:param cafile: Filename from which to load the CA list.
:return: 0 A failure while manipulating the STACK_OF(X509_NAME)
object occurred or the X509_NAME could not be
extracted from cacert. Check the error stack to find
out the reason.
1 The operation succeeded.
"""
m2.ssl_set_client_CA_list_from_file(self.ssl, cafile)
def set_client_CA_list_from_context(self):
# type: () -> None
"""
Set the acceptable client CA list. If the client
returns a certificate, it must have been issued by
one of the CAs listed in context.
Makes sense only for servers.
"""
m2.ssl_set_client_CA_list_from_context(self.ssl, self.ctx.ctx)
def setup_addr(self, addr):
# type: (util.AddrType) -> None
self.addr = addr
def set_ssl_close_flag(self, flag):
# type: (int) -> None
"""
By default, SSL struct will be freed in __del__. Call with
m2.bio_close to override this default.
:param flag: either m2.bio_close or m2.bio_noclose
"""
if flag not in (m2.bio_close, m2.bio_noclose):
raise ValueError(
"flag must be m2.bio_close or m2.bio_noclose"
)
self.ssl_close_flag = flag
def setup_ssl(self):
# type: () -> None
# Make a BIO_s_socket.
self.sockbio = m2.bio_new_socket(self.socket.fileno(), 0)
# Link SSL struct with the BIO_socket.
m2.ssl_set_bio(self.ssl, self.sockbio, self.sockbio)
# Make a BIO_f_ssl.
self.sslbio = m2.bio_new(m2.bio_f_ssl())
# Link BIO_f_ssl with the SSL struct.
m2.bio_set_ssl(self.sslbio, self.ssl, m2.bio_noclose)
def _setup_ssl(self, addr):
# type: (util.AddrType) -> None
"""Deprecated"""
self.setup_addr(addr)
self.setup_ssl()
def set_accept_state(self):
# type: () -> None
"""Sets Connection to work in the server mode."""
m2.ssl_set_accept_state(self.ssl)
def accept_ssl(self):
# type: () -> Optional[int]
"""Waits for a TLS/SSL client to initiate the TLS/SSL handshake.
The communication channel must already have been set and
assigned to the ssl by setting an underlying BIO.
:return: 0 The TLS/SSL handshake was not successful but was shut
down controlled and by the specifications of the
TLS/SSL protocol. Call get_error() with the return
value ret to find out the reason.
1 The TLS/SSL handshake was successfully completed,
a TLS/SSL connection has been established.
<0 The TLS/SSL handshake was not successful because
a fatal error occurred either at the protocol level
or a connection failure occurred. The shutdown was
not clean. It can also occur of action is need to
continue the operation for non-blocking BIOs. Call
get_error() with the return value ret to find
out the reason.
"""
return m2.ssl_accept(self.ssl, self._timeout)
def accept(self):
# type: () -> Tuple[Connection, util.AddrType]
"""Accept an SSL connection.
The return value is a pair (ssl, addr) where ssl is a new SSL
connection object and addr is the address bound to the other end
of the SSL connection.
:return: tuple of Connection and addr. Address can take very
various forms (see socket documentation), for IPv4 it
is tuple(str, int), for IPv6 a tuple of four (host,
port, flowinfo, scopeid), where the last two are
optional ints.
"""
sock, addr = self.socket.accept()
ssl = Connection(self.ctx, sock)
ssl.addr = addr
ssl.setup_ssl()
ssl.set_accept_state()
ssl.accept_ssl()
check = getattr(
self,
'postConnectionCheck',
self.serverPostConnectionCheck,
)
if check is not None:
if not check(ssl.get_peer_cert(), ssl.addr[0]):
raise Checker.SSLVerificationError(
'post connection check failed'
)
return ssl, addr
def set_connect_state(self):
# type: () -> None
"""Sets Connection to work in the client mode."""
m2.ssl_set_connect_state(self.ssl)
def connect_ssl(self):
# type: () -> Optional[int]
return m2.ssl_connect(self.ssl, self._timeout)
def connect(self, addr):
# type: (util.AddrType) -> int
"""Overloading socket.connect()
:param addr: addresses have various depending on their type
:return:status of ssl_connect()
"""
self.socket.connect(addr)
self.addr = addr
self.setup_ssl()
self.set_connect_state()
ret = self.connect_ssl()
check = getattr(
self,
'postConnectionCheck',
self.clientPostConnectionCheck,
)
if check is not None:
if not check(
self.get_peer_cert(),
self.host if self.host else self.addr[0],
):
raise Checker.SSLVerificationError(
'post connection check failed'
)
return ret
def shutdown(self, how):
# type: (int) -> None
m2.ssl_set_shutdown(self.ssl, how)
def renegotiate(self):
# type: () -> int
"""Renegotiate this connection's SSL parameters."""
return m2.ssl_renegotiate(self.ssl)
def pending(self):
# type: () -> int
"""Return the numbers of octets that can be read from the connection."""
return m2.ssl_pending(self.ssl)
def _write_bio(self, data):
# type: (bytes) -> int
return m2.ssl_write(self.ssl, data, self._timeout)
def _write_nbio(self, data):
# type: (bytes) -> int
return m2.ssl_write_nbio(self.ssl, data)
def _read_bio(self, size=1024):
# type: (int) -> bytes
if size <= 0:
raise ValueError('size <= 0')
return m2.ssl_read(self.ssl, size, self._timeout)
def _read_nbio(self, size=1024):
# type: (int) -> bytes
if size <= 0:
raise ValueError('size <= 0')
return m2.ssl_read_nbio(self.ssl, size)
def write(self, data):
# type: (bytes) -> int
if self._timeout != 0.0:
return self._write_bio(data)
return self._write_nbio(data)
sendall = send = write
def _decref_socketios(self):
pass
def recv_into(self, buff, nbytes=0):
# type: (Union[bytearray, memoryview], int) -> int
"""
A version of recv() that stores its data into a buffer
rather than creating a new string. Receive up to nbytes
bytes from the socket. If nbytes is not specified (or
0), receive up to the size available in the given buffer.
If buff is bytearray, it will have after return length of the
actually returned number of bytes. If buff is memoryview, then
the size of buff won't change (it cannot), but all bytes after
the number of returned bytes will be NULL.
:param buffer: a buffer for the received bytes
:param nbytes: maximum number of bytes to read
:return: number of bytes read
See recv() for documentation about the flags.
"""
n = len(buff) if nbytes == 0 else nbytes
if n <= 0:
raise ValueError('recv_into: size of buffer <= 0')
# buff_bytes are actual bytes returned
buff_bytes = m2.ssl_read(self.ssl, n, self._timeout)
buflen = len(buff_bytes)
# memoryview type has been added in 2.7
if isinstance(buff, memoryview):
buff[:buflen] = buff_bytes
buff[buflen:] = b'\x00' * (len(buff) - buflen)
else:
buff[:] = buff_bytes
return buflen
def read(self, size=1024):
# type: (int) -> bytes
if self._timeout != 0.0:
return self._read_bio(size)
return self._read_nbio(size)
recv = read
def setblocking(self, mode):
# type: (int) -> None
"""Set this connection's underlying socket to _mode_.
Set blocking or non-blocking mode of the socket: if flag is 0,
the socket is set to non-blocking, else to blocking mode.
Initially all sockets are in blocking mode. In non-blocking mode,
if a recv() call doesn't find any data, or if a send() call can't
immediately dispose of the data, a error exception is raised;
in blocking mode, the calls block until they can proceed.
s.setblocking(0) is equivalent to s.settimeout(0.0);
s.setblocking(1) is equivalent to s.settimeout(None).
:param mode: new mode to be set
"""
self.socket.setblocking(mode)
if mode:
self._timeout = -1.0
else:
self._timeout = 0.0
def settimeout(self, timeout):
# type: (float) -> None
"""Set this connection's underlying socket's timeout to _timeout_."""
self.socket.settimeout(timeout)
self._timeout = timeout
if self._timeout is None:
self._timeout = -1.0
def fileno(self):
# type: () -> int
return self.socket.fileno()
def getsockopt(self, level, optname, buflen=None):
# type: (int, int, Optional[int]) -> Union[int, bytes]
"""Get the value of the given socket option.
:param level: level at which the option resides.
To manipulate options at the sockets API level, level is
specified as socket.SOL_SOCKET. To manipulate options at
any other level the protocol number of the appropriate
protocol controlling the option is supplied. For example,
to indicate that an option is to be interpreted by the
TCP protocol, level should be set to the protocol number
of socket.SOL_TCP; see getprotoent(3).
:param optname: The value of the given socket option is
described in the Unix man page getsockopt(2)). The needed
symbolic constants (SO_* etc.) are defined in the socket
module.
:param buflen: If it is absent, an integer option is assumed
and its integer value is returned by the function. If
buflen is present, it specifies the maximum length of the
buffer used to receive the option in, and this buffer is
returned as a bytes object.
:return: Either integer or bytes value of the option. It is up
to the caller to decode the contents of the buffer (see
the optional built-in module struct for a way to decode
C structures encoded as byte strings).
"""
return self.socket.getsockopt(level, optname, buflen)
def setsockopt(self, level, optname, value=None):
# type: (int, int, Union[int, bytes, None]) -> Optional[bytes]
"""Set the value of the given socket option.
:param level: same as with getsockopt() above
:param optname: same as with getsockopt() above
:param value: an integer or a string representing a buffer. In
the latter case it is up to the caller to ensure
that the string contains the proper bits (see the
optional built-in module struct for a way to
encode C structures as strings).
:return: None for success or the error handler for failure.
"""
return self.socket.setsockopt(level, optname, value)
def get_context(self):
# type: () -> Context
"""Return the Context object associated with this connection."""
return m2.ssl_get_ssl_ctx(self.ssl)
def get_state(self):
# type: () -> bytes
"""Return the SSL state of this connection.
During its use, an SSL objects passes several states. The state
is internally maintained. Querying the state information is not
very informative before or when a connection has been
established. It however can be of significant interest during
the handshake.
:return: 6 letter string indicating the current state of the SSL
object ssl.
"""
return m2.ssl_get_state(self.ssl)
def verify_ok(self):
# type: () -> bool
return m2.ssl_get_verify_result(self.ssl) == m2.X509_V_OK
def get_verify_mode(self):
# type: () -> int
"""Return the peer certificate verification mode."""
return m2.ssl_get_verify_mode(self.ssl)
def get_verify_depth(self):
# type: () -> int
"""Return the peer certificate verification depth."""
return m2.ssl_get_verify_depth(self.ssl)
def get_verify_result(self):
# type: () -> int
"""Return the peer certificate verification result."""
return m2.ssl_get_verify_result(self.ssl)
def get_peer_cert(self):
# type: () -> X509.X509
"""Return the peer certificate.
If the peer did not provide a certificate, return None.
"""
c = m2.ssl_get_peer_cert(self.ssl)
if c is None:
return None
# Need to free the pointer coz OpenSSL doesn't.
return X509.X509(c, 1)
def get_peer_cert_chain(self):
# type: () -> Optional[X509.X509_Stack]
"""Return the peer certificate chain; if the peer did not provide
a certificate chain, return None.
:warning: The returned chain will be valid only for as long as the
connection object is alive. Once the connection object
gets freed, the chain will be freed as well.
"""
c = m2.ssl_get_peer_cert_chain(self.ssl)
if c is None:
return None
# No need to free the pointer coz OpenSSL does.
return X509.X509_Stack(c)
def get_cipher(self):
# type: () -> Optional[Cipher]
"""Return an M2Crypto.SSL.Cipher object for this connection; if the
connection has not been initialised with a cipher suite, return None.
"""
c = m2.ssl_get_current_cipher(self.ssl)
if c is None:
return None
return Cipher(c)
def get_ciphers(self):
# type: () -> Optional[Cipher_Stack]
"""Return an M2Crypto.SSL.Cipher_Stack object for this
connection; if the connection has not been initialised with
cipher suites, return None.
"""
c = m2.ssl_get_ciphers(self.ssl)
if c is None:
return None
return Cipher_Stack(c)
def get_cipher_list(self, idx=0):
# type: (int) -> str
"""Return the cipher suites for this connection as a string object."""
return m2.ssl_get_cipher_list(self.ssl, idx)
def set_cipher_list(self, cipher_list):
# type: (str) -> int
"""Set the cipher suites for this connection."""
return m2.ssl_set_cipher_list(self.ssl, cipher_list)
def makefile(self, mode='rb', bufsize=-1):
# type: (AnyStr, int) -> Union[io.BufferedRWPair,io.BufferedReader]
raw = socket.SocketIO(self, mode)
if 'rw' in mode:
return io.BufferedRWPair(raw, raw)
return io.BufferedReader(raw, io.DEFAULT_BUFFER_SIZE)
def getsockname(self):
# type: () -> util.AddrType
"""Return the socket's own address.
This is useful to find out the port number of an IPv4/v6 socket,
for instance. (The format of the address returned depends
on the address family -- see above.)
:return:socket's address as addr type
"""
return self.socket.getsockname()
def getpeername(self):
# type: () -> util.AddrType
"""Return the remote address to which the socket is connected.
This is useful to find out the port number of a remote IPv4/v6 socket,
for instance.
On some systems this function is not supported.
:return:
"""
return self.socket.getpeername()
def set_session_id_ctx(self, id):
# type: (bytes) -> int
ret = m2.ssl_set_session_id_context(self.ssl, id)
if not ret:
raise SSLError(Err.get_error_message())
def get_session(self):
# type: () -> Session
sess = m2.ssl_get_session(self.ssl)
return Session(sess)
def set_session(self, session):
# type: (Session) -> None
m2.ssl_set_session(self.ssl, session._ptr())
def get_default_session_timeout(self):
# type: () -> int
return m2.ssl_get_default_session_timeout(self.ssl)
def get_socket_read_timeout(self):
# type: () -> timeout
return timeout.struct_to_timeout(
self.socket.getsockopt(
socket.SOL_SOCKET,
socket.SO_RCVTIMEO,
timeout.struct_size(),
)
)
@staticmethod
def _hexdump(s):
assert isinstance(s, bytes)
return ":".join(s)
def get_socket_write_timeout(self):
# type: () -> timeout
binstr = self.socket.getsockopt(
socket.SOL_SOCKET,
socket.SO_SNDTIMEO,
timeout.struct_size(),
)
timeo = timeout.struct_to_timeout(binstr)
# print("Debug: get_socket_write_timeout: "
# "get sockopt value: %s -> ret timeout(sec=%r, microsec=%r)" %
# (self._hexdump(binstr), timeo.sec, timeo.microsec))
return timeo
def set_socket_read_timeout(self, timeo):
# type: (timeout) -> None
assert isinstance(timeo, timeout.timeout)
self.socket.setsockopt(
socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeo.pack()
)
def set_socket_write_timeout(self, timeo):
# type: (timeout) -> None
assert isinstance(timeo, timeout.timeout)
binstr = timeo.pack()
# print("Debug: set_socket_write_timeout: "
# "input timeout(sec=%r, microsec=%r) -> set sockopt value: %s" %
# (timeo.sec, timeo.microsec, self._hexdump(binstr)))
self.socket.setsockopt(
socket.SOL_SOCKET, socket.SO_SNDTIMEO, binstr
)
def get_version(self):
# type: () -> str
"""Return the TLS/SSL protocol version for this connection."""
return m2.ssl_get_version(self.ssl)
def set_post_connection_check_callback(
self, postConnectionCheck
): # noqa
# type: (Callable) -> None
self.postConnectionCheck = postConnectionCheck
def set_tlsext_host_name(self, name):
# type: (bytes) -> None
"""Set the requested hostname for the SNI (Server Name Indication)
extension.
"""
m2.ssl_set_tlsext_host_name(self.ssl, name)
def set1_host(self, name):
# type: (bytes) -> None
"""Set the requested hostname to check in the server certificate."""
self.host = name
m2crypto-0.42.0/src/M2Crypto/SSL/Context.py 0000664 0000000 0000000 00000041222 14655756567 0020314 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""SSL Context
Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved."""
from M2Crypto import BIO, Err, RSA, X509, m2, util # noqa
from M2Crypto.SSL import cb # noqa
from M2Crypto.SSL.Session import Session # noqa
from weakref import WeakValueDictionary
from typing import Any, AnyStr, Callable, Optional, Union # noqa
__all__ = ['ctxmap', 'Context', 'map']
class _ctxmap(object):
singleton = None # type: Optional[_ctxmap]
def __init__(self):
# type: () -> None
"""Simple WeakReffed list.
"""
self._ctxmap = WeakValueDictionary()
def __getitem__(self, key):
# type: (int) -> Any
return self._ctxmap[key]
def __setitem__(self, key, value):
# type: (int, Any) -> None
self._ctxmap[key] = value
def __delitem__(self, key):
# type: (int) -> None
del self._ctxmap[key]
def ctxmap():
# type: () -> _ctxmap
if _ctxmap.singleton is None:
_ctxmap.singleton = _ctxmap()
return _ctxmap.singleton
# deprecated!!!
map = ctxmap
class Context(object):
"""'Context' for SSL connections."""
m2_ssl_ctx_free = m2.ssl_ctx_free
def __init__(self, protocol='tls', weak_crypto=None,
post_connection_check=None):
# type: (str, Optional[int], Optional[Callable]) -> None
proto = getattr(m2, protocol + '_method', None)
if proto is None:
# default is 'sslv23' for older versions of OpenSSL
if protocol == 'tls':
proto = getattr(m2, 'sslv23_method')
else:
raise ValueError("no such protocol '%s'" % protocol)
self.ctx = m2.ssl_ctx_new(proto())
self.allow_unknown_ca = 0 # type: Union[int, bool]
self.post_connection_check = post_connection_check
ctxmap()[int(self.ctx)] = self
m2.ssl_ctx_set_cache_size(self.ctx, 128)
if weak_crypto is None and protocol in ('sslv23', 'tls'):
self.set_options(m2.SSL_OP_ALL | m2.SSL_OP_NO_SSLv2 |
m2.SSL_OP_NO_SSLv3)
def __del__(self):
# type: () -> None
if getattr(self, 'ctx', None):
self.m2_ssl_ctx_free(self.ctx)
def close(self):
# type: () -> None
del ctxmap()[int(self.ctx)]
def load_cert(self, certfile, keyfile=None,
callback=util.passphrase_callback):
# type: (AnyStr, Optional[AnyStr], Callable) -> None
"""Load certificate and private key into the context.
:param certfile: File that contains the PEM-encoded certificate.
:param keyfile: File that contains the PEM-encoded private key.
Default value of None indicates that the private key
is to be found in 'certfile'.
:param callback: Callable object to be invoked if the private key is
passphrase-protected. Default callback provides a
simple terminal-style input for the passphrase.
"""
m2.ssl_ctx_passphrase_callback(self.ctx, callback)
m2.ssl_ctx_use_cert(self.ctx, certfile)
if not keyfile:
keyfile = certfile
m2.ssl_ctx_use_privkey(self.ctx, keyfile)
if not m2.ssl_ctx_check_privkey(self.ctx):
raise ValueError('public/private key mismatch')
def load_cert_chain(self, certchainfile, keyfile=None,
callback=util.passphrase_callback):
# type: (AnyStr, Optional[AnyStr], Callable) -> None
"""Load certificate chain and private key into the context.
:param certchainfile: File object containing the PEM-encoded
certificate chain.
:param keyfile: File object containing the PEM-encoded private
key. Default value of None indicates that the
private key is to be found in 'certchainfile'.
:param callback: Callable object to be invoked if the private key
is passphrase-protected. Default callback
provides a simple terminal-style input for the
passphrase.
"""
m2.ssl_ctx_passphrase_callback(self.ctx, callback)
m2.ssl_ctx_use_cert_chain(self.ctx, certchainfile)
if not keyfile:
keyfile = certchainfile
m2.ssl_ctx_use_privkey(self.ctx, keyfile)
if not m2.ssl_ctx_check_privkey(self.ctx):
raise ValueError('public/private key mismatch')
def set_client_CA_list_from_file(self, cafile):
# type: (AnyStr) -> None
"""Load CA certs into the context. These CA certs are sent to the
peer during *SSLv3 certificate request*.
:param cafile: File object containing one or more PEM-encoded CA
certificates concatenated together.
"""
m2.ssl_ctx_set_client_CA_list_from_file(self.ctx, cafile)
# Deprecated.
load_client_CA = load_client_ca = set_client_CA_list_from_file
def load_verify_locations(self, cafile=None, capath=None):
# type: (Optional[AnyStr], Optional[AnyStr]) -> int
"""Load CA certs into the context.
These CA certs are used during verification of the peer's
certificate.
:param cafile: File containing one or more PEM-encoded CA
certificates concatenated together.
:param capath: Directory containing PEM-encoded CA certificates
(one certificate per file).
:return: 0 if the operation failed because CAfile and CApath are NULL
or the processing at one of the locations specified failed.
Check the error stack to find out the reason.
1 The operation succeeded.
"""
if cafile is None and capath is None:
raise ValueError("cafile and capath can not both be None.")
return m2.ssl_ctx_load_verify_locations(self.ctx, cafile, capath)
# Deprecated.
load_verify_info = load_verify_locations
def set_session_id_ctx(self, id):
# type: (bytes) -> None
"""Sets the session id for the SSL.Context w/in a session can be reused.
:param id: Sessions are generated within a certain context. When
exporting/importing sessions with
i2d_SSL_SESSION/d2i_SSL_SESSION it would be possible,
to re-import a session generated from another context
(e.g. another application), which might lead to
malfunctions. Therefore each application must set its
own session id context sid_ctx which is used to
distinguish the contexts and is stored in exported
sessions. The sid_ctx can be any kind of binary data
with a given length, it is therefore possible to use
e.g. the name of the application and/or the hostname
and/or service name.
"""
ret = m2.ssl_ctx_set_session_id_context(self.ctx, id)
if not ret:
raise Err.SSLError(Err.get_error_code(), '')
def set_default_verify_paths(self):
# type: () -> int
"""
Specifies that the default locations from which CA certs are
loaded should be used.
There is one default directory and one default file. The default
CA certificates directory is called "certs" in the default
OpenSSL directory. Alternatively the SSL_CERT_DIR environment
variable can be defined to override this location. The default
CA certificates file is called "cert.pem" in the default OpenSSL
directory. Alternatively the SSL_CERT_FILE environment variable
can be defined to override this location.
@return 0 if the operation failed. A missing default location is
still treated as a success. No error code is set.
1 The operation succeeded.
"""
ret = m2.ssl_ctx_set_default_verify_paths(self.ctx)
if not ret:
raise ValueError('Cannot use default SSL certificate store!')
def set_allow_unknown_ca(self, ok):
# type: (Union[int, bool]) -> None
"""Set the context to accept/reject a peer certificate if the
certificate's CA is unknown.
:param ok: True to accept, False to reject.
"""
self.allow_unknown_ca = ok
def get_allow_unknown_ca(self):
# type: () -> Union[int, bool]
"""Get the context's setting that accepts/rejects a peer
certificate if the certificate's CA is unknown.
FIXME 2Bconverted to bool
"""
return self.allow_unknown_ca
def set_verify(self, mode, depth, callback=None):
# type: (int, int, Optional[Callable]) -> None
"""
Set verify options. Most applications will need to call this
method with the right options to make a secure SSL connection.
:param mode: The verification mode to use. Typically at least
SSL.verify_peer is used. Clients would also typically
add SSL.verify_fail_if_no_peer_cert.
:param depth: The maximum allowed depth of the certificate chain
returned by the peer.
:param callback: Callable that can be used to specify custom
verification checks.
"""
if callback is None:
m2.ssl_ctx_set_verify_default(self.ctx, mode)
else:
m2.ssl_ctx_set_verify(self.ctx, mode, callback)
m2.ssl_ctx_set_verify_depth(self.ctx, depth)
def get_verify_mode(self):
# type: () -> int
return m2.ssl_ctx_get_verify_mode(self.ctx)
def get_verify_depth(self):
# type: () -> int
"""Returns the verification mode currently set in the SSL Context."""
return m2.ssl_ctx_get_verify_depth(self.ctx)
def set_tmp_dh(self, dhpfile):
# type: (AnyStr) -> int
"""Load ephemeral DH parameters into the context.
:param dhpfile: Filename of the file containing the PEM-encoded
DH parameters.
"""
f = BIO.openfile(dhpfile)
dhp = m2.dh_read_parameters(f.bio_ptr())
return m2.ssl_ctx_set_tmp_dh(self.ctx, dhp)
def set_tmp_dh_callback(self, callback=None):
# type: (Optional[Callable]) -> None
"""Sets the callback function for SSL.Context.
:param callback: Callable to be used when a DH parameters are required.
"""
if callback is not None:
m2.ssl_ctx_set_tmp_dh_callback(self.ctx, callback)
def set_tmp_rsa(self, rsa):
# type: (RSA.RSA) -> int
"""Load ephemeral RSA key into the context.
:param rsa: RSA.RSA instance.
"""
if isinstance(rsa, RSA.RSA):
return m2.ssl_ctx_set_tmp_rsa(self.ctx, rsa.rsa)
else:
raise TypeError("Expected an instance of RSA.RSA, got %s." % rsa)
def set_tmp_rsa_callback(self, callback=None):
# type: (Optional[Callable]) -> None
"""Sets the callback function to be used when
a temporary/ephemeral RSA key is required.
"""
if callback is not None:
m2.ssl_ctx_set_tmp_rsa_callback(self.ctx, callback)
def set_info_callback(self, callback=cb.ssl_info_callback):
# type: (Callable) -> None
"""Set a callback function to get state information.
It can be used to get state information about the SSL
connections that are created from this context.
:param callback: Callback function. The default prints
information to stderr.
"""
m2.ssl_ctx_set_info_callback(self.ctx, callback)
def set_cipher_list(self, cipher_list):
# type: (str) -> int
"""Sets the list of available ciphers.
:param cipher_list: The format of the string is described in
ciphers(1).
:return: 1 if any cipher could be selected and 0 on complete
failure.
"""
return m2.ssl_ctx_set_cipher_list(self.ctx, cipher_list)
def add_session(self, session):
# type: (Session) -> int
"""Add the session to the context.
:param session: the session to be added.
:return: 0 The operation failed. It was tried to add the same
(identical) session twice.
1 The operation succeeded.
"""
return m2.ssl_ctx_add_session(self.ctx, session._ptr())
def remove_session(self, session):
# type: (Session) -> int
"""Remove the session from the context.
:param session: the session to be removed.
:return: 0 The operation failed. The session was not found in
the cache.
1 The operation succeeded.
"""
return m2.ssl_ctx_remove_session(self.ctx, session._ptr())
def get_session_timeout(self):
# type: () -> int
"""Get current session timeout.
Whenever a new session is created, it is assigned a maximum
lifetime. This lifetime is specified by storing the creation
time of the session and the timeout value valid at this time. If
the actual time is later than creation time plus timeout, the
session is not reused.
Due to this realization, all sessions behave according to the
timeout value valid at the time of the session negotiation.
Changes of the timeout value do not affect already established
sessions.
Expired sessions are removed from the internal session cache,
whenever SSL_CTX_flush_sessions(3) is called, either directly by
the application or automatically (see
SSL_CTX_set_session_cache_mode(3))
The default value for session timeout is decided on a per
protocol basis, see SSL_get_default_timeout(3). All currently
supported protocols have the same default timeout value of 300
seconds.
SSL_CTX_set_timeout() returns the previously set timeout value.
:return: the currently set timeout value.
"""
return m2.ssl_ctx_get_session_timeout(self.ctx)
def set_session_timeout(self, timeout):
# type: (int) -> int
"""Set new session timeout.
See self.get_session_timeout() for explanation of the session
timeouts.
:param timeout: new timeout value.
:return: the previously set timeout value.
"""
return m2.ssl_ctx_set_session_timeout(self.ctx, timeout)
def set_session_cache_mode(self, mode):
# type: (int) -> int
"""Enables/disables session caching.
The mode is set by using m2.SSL_SESS_CACHE_* constants.
:param mode: new mode value.
:return: the previously set cache mode value.
"""
return m2.ssl_ctx_set_session_cache_mode(self.ctx, mode)
def get_session_cache_mode(self):
# type: () -> int
"""Gets the current session caching.
The mode is set to m2.SSL_SESS_CACHE_* constants.
:return: the previously set cache mode value.
"""
return m2.ssl_ctx_get_session_cache_mode(self.ctx)
def set_options(self, op):
# type: (int) -> int
"""Adds the options set via bitmask in options to the Context.
!!! Options already set before are not cleared!
The behaviour of the SSL library can be changed by setting
several options. The options are coded as bitmasks and can be
combined by a logical or operation (|).
SSL.Context.set_options() and SSL.set_options() affect the
(external) protocol behaviour of the SSL library. The (internal)
behaviour of the API can be changed by using the similar
SSL.Context.set_mode() and SSL.set_mode() functions.
During a handshake, the option settings of the SSL object are
used. When a new SSL object is created from a context using
SSL(), the current option setting is copied. Changes to ctx
do not affect already created SSL objects. SSL.clear() does not
affect the settings.
:param op: bitmask of additional options specified in
SSL_CTX_set_options(3) manpage.
:return: the new options bitmask after adding options.
"""
return m2.ssl_ctx_set_options(self.ctx, op)
def get_cert_store(self):
# type: () -> X509.X509
"""
Get the certificate store associated with this context.
:warning: The store is NOT refcounted, and as such can not be relied
to be valid once the context goes away or is changed.
"""
return X509.X509_Store(m2.ssl_ctx_get_cert_store(self.ctx))
m2crypto-0.42.0/src/M2Crypto/SSL/SSLServer.py 0000664 0000000 0000000 00000003712 14655756567 0020522 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import, print_function
"""SSLServer
Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved."""
# M2Crypto
from M2Crypto.SSL import SSLError
from M2Crypto.SSL.Connection import Connection
from M2Crypto.SSL.Context import Context # noqa
from M2Crypto import util # noqa
from socketserver import (BaseRequestHandler, BaseServer,
TCPServer, ThreadingMixIn)
import os
if os.name != 'nt':
from socketserver import ForkingMixIn
from socket import socket # noqa
from typing import Union # noqa
__all__ = ['SSLServer', 'ForkingSSLServer', 'ThreadingSSLServer']
class SSLServer(TCPServer):
def __init__(self, server_address, RequestHandlerClass, ssl_context, # noqa
bind_and_activate=True):
# type: (util.AddrType, BaseRequestHandler, Context, bool) -> None
"""
Superclass says: Constructor. May be extended, do not override.
This class says: Ho-hum.
"""
BaseServer.__init__(self, server_address, RequestHandlerClass)
self.ssl_ctx = ssl_context
self.socket = Connection(self.ssl_ctx)
if bind_and_activate:
self.server_bind()
self.server_activate()
def handle_request(self):
# type: () -> None
request = None
client_address = None
try:
request, client_address = self.get_request()
if self.verify_request(request, client_address):
self.process_request(request, client_address)
except SSLError:
self.handle_error(request, client_address)
def handle_error(self, request, client_address):
# type: (Union[socket, Connection], util.AddrType) -> None
print('-' * 40)
import traceback
traceback.print_exc()
print('-' * 40)
class ThreadingSSLServer(ThreadingMixIn, SSLServer):
pass
if os.name != 'nt':
class ForkingSSLServer(ForkingMixIn, SSLServer):
pass
m2crypto-0.42.0/src/M2Crypto/SSL/Session.py 0000664 0000000 0000000 00000003401 14655756567 0020310 0 ustar 00root root 0000000 0000000 """SSL Session
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
__all__ = ['Session', 'load_session']
from M2Crypto import BIO, Err, m2
from M2Crypto.SSL import SSLError
from typing import AnyStr # noqa
class Session(object):
m2_ssl_session_free = m2.ssl_session_free
def __init__(self, session, _pyfree=0):
# type: (bytes, int) -> None
assert session is not None
self.session = session
self._pyfree = _pyfree
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_ssl_session_free(self.session)
def _ptr(self):
# type: () -> bytes
return self.session
def as_text(self):
# type: () -> bytes
buf = BIO.MemoryBuffer()
m2.ssl_session_print(buf.bio_ptr(), self.session)
return buf.read_all()
def as_der(self):
# type: () -> bytes
buf = BIO.MemoryBuffer()
m2.i2d_ssl_session(buf.bio_ptr(), self.session)
return buf.read_all()
def write_bio(self, bio):
# type: (BIO.BIO) -> int
return m2.ssl_session_write_bio(bio.bio_ptr(), self.session)
def get_time(self):
# type: () -> int
return m2.ssl_session_get_time(self.session)
def set_time(self, t):
# type: (int) -> int
return m2.ssl_session_set_time(self.session, t)
def get_timeout(self):
# type: () -> int
return m2.ssl_session_get_timeout(self.session)
def set_timeout(self, t):
# type: (int) -> int
return m2.ssl_session_set_timeout(self.session, t)
def load_session(pemfile):
# type: (AnyStr) -> Session
with BIO.openfile(pemfile) as f:
cptr = m2.ssl_session_read_pem(f.bio_ptr())
return Session(cptr, 1)
m2crypto-0.42.0/src/M2Crypto/SSL/TwistedProtocolWrapper.py 0000664 0000000 0000000 00000043070 14655756567 0023401 0 ustar 00root root 0000000 0000000 """
Make Twisted use M2Crypto for SSL
Copyright (c) 2004-2007 Open Source Applications Foundation.
All rights reserved.
FIXME THIS HAS NOT BEEN FINISHED. NEITHER PEP484 NOR PORT PYTHON3 HAS
BEEN FINISHED. THE FURTHER WORK WILL BE DONE WHEN THE STATUS OF TWISTED
IN THE PYTHON 3 (AND ASYNCIO) WORLD WILL BE CLEAR.
"""
__all__ = ['connectSSL', 'connectTCP', 'listenSSL', 'listenTCP',
'TLSProtocolWrapper']
import logging
from functools import partial
import twisted.internet.reactor
import twisted.protocols.policies as policies
from M2Crypto import BIO, X509, m2, util
from M2Crypto.SSL.Checker import Checker, SSLVerificationError
from twisted.internet.interfaces import ITLSTransport
from twisted.protocols.policies import ProtocolWrapper
from typing import AnyStr, Callable, Iterable, Optional # noqa
from zope.interface import implementer
log = logging.getLogger(__name__)
def _alwaysSucceedsPostConnectionCheck(peerX509, expectedHost):
return 1
def connectSSL(host, port, factory, contextFactory, timeout=30,
bindAddress=None,
reactor=twisted.internet.reactor,
postConnectionCheck=Checker()):
# type: (str, int, object, object, int, Optional[str], twisted.internet.reactor, Checker) -> reactor.connectTCP
"""
A convenience function to start an SSL/TLS connection using Twisted.
See IReactorSSL interface in Twisted.
"""
wrappingFactory = policies.WrappingFactory(factory)
wrappingFactory.protocol = lambda factory, wrappedProtocol: \
TLSProtocolWrapper(factory,
wrappedProtocol,
startPassThrough=0,
client=1,
contextFactory=contextFactory,
postConnectionCheck=postConnectionCheck)
return reactor.connectTCP(host, port, wrappingFactory, timeout, bindAddress)
def connectTCP(host, port, factory, timeout=30, bindAddress=None,
reactor=twisted.internet.reactor,
postConnectionCheck=Checker()):
# type: (str, int, object, int, Optional[util.AddrType], object, Callable) -> object
"""
A convenience function to start a TCP connection using Twisted.
NOTE: You must call startTLS(ctx) to go into SSL/TLS mode.
See IReactorTCP interface in Twisted.
"""
wrappingFactory = policies.WrappingFactory(factory)
wrappingFactory.protocol = lambda factory, wrappedProtocol: \
TLSProtocolWrapper(factory,
wrappedProtocol,
startPassThrough=1,
client=1,
contextFactory=None,
postConnectionCheck=postConnectionCheck)
return reactor.connectTCP(host, port, wrappingFactory, timeout, bindAddress)
def listenSSL(port, factory, contextFactory, backlog=5, interface='',
reactor=twisted.internet.reactor,
postConnectionCheck=_alwaysSucceedsPostConnectionCheck):
"""
A convenience function to listen for SSL/TLS connections using Twisted.
See IReactorSSL interface in Twisted.
"""
wrappingFactory = policies.WrappingFactory(factory)
wrappingFactory.protocol = lambda factory, wrappedProtocol: \
TLSProtocolWrapper(factory,
wrappedProtocol,
startPassThrough=0,
client=0,
contextFactory=contextFactory,
postConnectionCheck=postConnectionCheck)
return reactor.listenTCP(port, wrappingFactory, backlog, interface)
def listenTCP(port, factory, backlog=5, interface='',
reactor=twisted.internet.reactor,
postConnectionCheck=None):
"""
A convenience function to listen for TCP connections using Twisted.
NOTE: You must call startTLS(ctx) to go into SSL/TLS mode.
See IReactorTCP interface in Twisted.
"""
wrappingFactory = policies.WrappingFactory(factory)
wrappingFactory.protocol = lambda factory, wrappedProtocol: \
TLSProtocolWrapper(factory,
wrappedProtocol,
startPassThrough=1,
client=0,
contextFactory=None,
postConnectionCheck=postConnectionCheck)
return reactor.listenTCP(port, wrappingFactory, backlog, interface)
class _BioProxy(object):
"""
The purpose of this class is to eliminate the __del__ method from
TLSProtocolWrapper, and thus letting it be garbage collected.
"""
m2_bio_free_all = m2.bio_free_all
def __init__(self, bio):
self.bio = bio
def _ptr(self):
return self.bio
def __del__(self):
if self.bio is not None:
self.m2_bio_free_all(self.bio)
class _SSLProxy(object):
"""
The purpose of this class is to eliminate the __del__ method from
TLSProtocolWrapper, and thus letting it be garbage collected.
"""
m2_ssl_free = m2.ssl_free
def __init__(self, ssl):
self.ssl = ssl
def _ptr(self):
return self.ssl
def __del__(self):
if self.ssl is not None:
self.m2_ssl_free(self.ssl)
@implementer(ITLSTransport)
class TLSProtocolWrapper(ProtocolWrapper):
"""
A SSL/TLS protocol wrapper to be used with Twisted. Typically
you would not use this class directly. Use connectTCP,
connectSSL, listenTCP, listenSSL functions defined above,
which will hook in this class.
"""
def __init__(self, factory, wrappedProtocol, startPassThrough, client,
contextFactory, postConnectionCheck):
# type: (policies.WrappingFactory, object, int, int, object, Checker) -> None
"""
:param factory:
:param wrappedProtocol:
:param startPassThrough: If true we won't encrypt at all. Need to
call startTLS() later to switch to SSL/TLS.
:param client: True if this should be a client protocol.
:param contextFactory: Factory that creates SSL.Context objects.
The called function is getContext().
:param postConnectionCheck: The post connection check callback that
will be called just after connection has
been established but before any real data
has been exchanged. The first argument to
this function is an X509 object, the second
is the expected host name string.
"""
# ProtocolWrapper.__init__(self, factory, wrappedProtocol)
# XXX: Twisted 2.0 has a new addition where the wrappingFactory is
# set as the factory of the wrappedProtocol. This is an issue
# as the wrap should be transparent. What we want is
# the factory of the wrappedProtocol to be the wrappedFactory and
# not the outer wrappingFactory. This is how it was implemented in
# Twisted 1.3
self.factory = factory
self.wrappedProtocol = wrappedProtocol
# wrappedProtocol == client/server instance
# factory.wrappedFactory == client/server factory
self.data = b'' # Clear text to encrypt and send
self.encrypted = b'' # Encrypted data we need to decrypt and pass on
self.tlsStarted = 0 # SSL/TLS mode or pass through
self.checked = 0 # Post connection check done or not
self.isClient = client
self.helloDone = 0 # True when hello has been sent
if postConnectionCheck is None:
self.postConnectionCheck = _alwaysSucceedsPostConnectionCheck
else:
self.postConnectionCheck = postConnectionCheck
if not startPassThrough:
self.startTLS(contextFactory.getContext())
def clear(self):
"""
Clear this instance, after which it is ready for reuse.
"""
if getattr(self, 'tlsStarted', 0):
self.sslBio = None
self.ssl = None
self.internalBio = None
self.networkBio = None
self.data = b''
self.encrypted = b''
self.tlsStarted = 0
self.checked = 0
self.isClient = 1
self.helloDone = 0
# We can reuse self.ctx and it will be deleted automatically
# when this instance dies
def startTLS(self, ctx):
"""
Start SSL/TLS. If this is not called, this instance just passes data
through untouched.
"""
# NOTE: This method signature must match the startTLS() method Twisted
# expects transports to have. This will be called automatically
# by Twisted in STARTTLS situations, for example with SMTP.
if self.tlsStarted:
raise Exception('TLS already started')
self.ctx = ctx
self.internalBio = m2.bio_new(m2.bio_s_bio())
m2.bio_set_write_buf_size(self.internalBio, 0)
self.networkBio = _BioProxy(m2.bio_new(m2.bio_s_bio()))
m2.bio_set_write_buf_size(self.networkBio._ptr(), 0)
m2.bio_make_bio_pair(self.internalBio, self.networkBio._ptr())
self.sslBio = _BioProxy(m2.bio_new(m2.bio_f_ssl()))
self.ssl = _SSLProxy(m2.ssl_new(self.ctx.ctx))
if self.isClient:
m2.ssl_set_connect_state(self.ssl._ptr())
else:
m2.ssl_set_accept_state(self.ssl._ptr())
m2.ssl_set_bio(self.ssl._ptr(), self.internalBio, self.internalBio)
m2.bio_set_ssl(self.sslBio._ptr(), self.ssl._ptr(), m2.bio_noclose)
# Need this for writes that are larger than BIO pair buffers
mode = m2.ssl_get_mode(self.ssl._ptr())
m2.ssl_set_mode(self.ssl._ptr(),
mode |
m2.SSL_MODE_ENABLE_PARTIAL_WRITE |
m2.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)
self.tlsStarted = 1
def write(self, data):
# type: (bytes) -> None
if not self.tlsStarted:
ProtocolWrapper.write(self, data)
return
try:
encryptedData = self._encrypt(data)
ProtocolWrapper.write(self, encryptedData)
self.helloDone = 1
except BIO.BIOError as e:
# See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS
# for the error codes returned by SSL_get_verify_result.
e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0])
raise e
def writeSequence(self, data):
# type: (Iterable[bytes]) -> None
if not self.tlsStarted:
ProtocolWrapper.writeSequence(self, b''.join(data))
return
self.write(b''.join(data))
def loseConnection(self):
# XXX Do we need to do m2.ssl_shutdown(self.ssl._ptr())?
ProtocolWrapper.loseConnection(self)
def connectionMade(self):
ProtocolWrapper.connectionMade(self)
if self.tlsStarted and self.isClient and not self.helloDone:
self._clientHello()
def dataReceived(self, data):
# type: (bytes) -> None
if not self.tlsStarted:
ProtocolWrapper.dataReceived(self, data)
return
self.encrypted += data
try:
while 1:
decryptedData = self._decrypt()
self._check()
encryptedData = self._encrypt()
ProtocolWrapper.write(self, encryptedData)
ProtocolWrapper.dataReceived(self, decryptedData)
if decryptedData == b'' and encryptedData == b'':
break
except BIO.BIOError as e:
# See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS
# for the error codes returned by SSL_get_verify_result.
e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0])
raise e
def connectionLost(self, reason):
# type: (AnyStr) -> None
self.clear()
ProtocolWrapper.connectionLost(self, reason)
def _check(self):
if not self.checked and m2.ssl_is_init_finished(self.ssl._ptr()):
x509 = m2.ssl_get_peer_cert(self.ssl._ptr())
if x509 is not None:
x509 = X509.X509(x509, 1)
if self.isClient:
host = self.transport.addr[0]
else:
host = self.transport.getPeer().host
if not self.postConnectionCheck(x509, host):
raise SSLVerificationError('post connection check')
self.checked = 1
def _clientHello(self):
try:
# We rely on OpenSSL implicitly starting with client hello
# when we haven't yet established an SSL connection
encryptedData = self._encrypt(clientHello=1)
ProtocolWrapper.write(self, encryptedData)
self.helloDone = 1
except BIO.BIOError as e:
# See http://www.openssl.org/docs/apps/verify.html#DIAGNOSTICS
# for the error codes returned by SSL_get_verify_result.
e.args = (m2.ssl_get_verify_result(self.ssl._ptr()), e.args[0])
raise e
# Optimizations to reduce attribute accesses
@property
def _get_wr_guar_ssl(self):
# type: () -> Callable[[], int]
"""Return max. length of data can be written to the BIO.
Writes larger than this value will return a value from
BIO_write() less than the amount requested or if the buffer is
full request a retry.
"""
return partial(m2.bio_ctrl_get_write_guarantee,
self.sslBio._ptr())
@property
def _get_wr_guar_net(self):
# type: () -> Callable[[], int]
return partial(m2.bio_ctrl_get_write_guarantee,
self.networkBio._ptr())
@property
def _shoud_retry_ssl(self):
# type: () -> Callable[[], int]
# BIO_should_retry() is true if the call that produced this
# condition should then be retried at a later time.
return partial(m2.bio_should_retry, self.sslBio._ptr())
@property
def _shoud_retry_net(self):
# type: () -> Callable[[], int]
return partial(m2.bio_should_retry, self.networkBio._ptr())
@property
def _ctrl_pend_ssl(self):
# type: () -> Callable[[], int]
# size_t BIO_ctrl_pending(BIO *b);
# BIO_ctrl_pending() return the number of pending characters in
# the BIOs read and write buffers.
return partial(m2.bio_ctrl_pending, self.sslBio._ptr())
@property
def _ctrl_pend_net(self):
# type: () -> Callable[[], int]
return partial(m2.bio_ctrl_pending, self.networkBio._ptr())
@property
def _write_ssl(self):
# type: () -> Callable[[bytes], int]
# All these functions return either the amount of data
# successfully read or written (if the return value is
# positive) or that no data was successfully read or written
# if the result is 0 or -1. If the return value is -2 then
# the operation is not implemented in the specific BIO type.
return partial(m2.bio_write, self.sslBio._ptr())
@property
def _write_net(self):
# type: () -> Callable[[bytes], int]
return partial(m2.bio_write, self.networkBio._ptr())
@property
def _read_ssl(self):
# type: () -> Callable[[int], Optional[bytes]]
return partial(m2.bio_read, self.sslBio._ptr())
@property
def _read_net(self):
# type: () -> Callable[[int], Optional[bytes]]
return partial(m2.bio_read, self.networkBio._ptr())
def _encrypt(self, data=b'', clientHello=0):
# type: (bytes, int) -> bytes
"""
:param data:
:param clientHello:
:return:
"""
encryptedData = b''
self.data += data
while 1:
if (self._get_wr_guar_ssl() > 0 and self.data != b'') or clientHello:
r = self._write_ssl(self.data)
if r <= 0:
if not self._shoud_retry_ssl():
raise IOError(
('Data left to be written to {}, ' +
'but cannot retry SSL connection!').format(self.sslBio))
else:
assert self.checked
self.data = self.data[r:]
pending = self._ctrl_pend_net()
if pending:
d = self._read_net(pending)
if d is not None: # This is strange, but d can be None
encryptedData += d
else:
assert(self._shoud_retry_net())
else:
break
return encryptedData
def _decrypt(self, data=b''):
# type: (bytes) -> bytes
self.encrypted += data
decryptedData = b''
while 1:
if self._get_wr_guar_ssl() > 0 and self.encrypted != b'':
r = self._write_net(self.encrypted)
if r <= 0:
if not self._shoud_retry_net():
raise IOError(
('Data left to be written to {}, ' +
'but cannot retry SSL connection!').format(self.networkBio))
else:
self.encrypted = self.encrypted[r:]
pending = self._ctrl_pend_ssl()
if pending:
d = self._read_ssl(pending)
if d is not None: # This is strange, but d can be None
decryptedData += d
else:
assert(self._shoud_retry_ssl())
else:
break
return decryptedData
m2crypto-0.42.0/src/M2Crypto/SSL/__init__.py 0000664 0000000 0000000 00000002357 14655756567 0020435 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""M2Crypto SSL services.
Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved."""
import socket, os
# M2Crypto
from M2Crypto import _m2crypto as m2
class SSLError(Exception):
pass
class SSLTimeoutError(SSLError, socket.timeout):
pass
m2.ssl_init(SSLError, SSLTimeoutError)
# M2Crypto.SSL
from M2Crypto.SSL.Cipher import Cipher, Cipher_Stack
from M2Crypto.SSL.Connection import Connection
from M2Crypto.SSL.Context import Context
from M2Crypto.SSL.SSLServer import SSLServer, ThreadingSSLServer
if os.name != 'nt':
from M2Crypto.SSL.SSLServer import ForkingSSLServer
from M2Crypto.SSL.timeout import timeout, struct_to_timeout, struct_size
verify_none = m2.SSL_VERIFY_NONE # type: int
verify_peer = m2.SSL_VERIFY_PEER # type: int
verify_fail_if_no_peer_cert = m2.SSL_VERIFY_FAIL_IF_NO_PEER_CERT # type: int
verify_client_once = m2.SSL_VERIFY_CLIENT_ONCE # type: int
verify_crl_check_chain = m2.VERIFY_CRL_CHECK_CHAIN # type: int
verify_crl_check_leaf = m2.VERIFY_CRL_CHECK_LEAF # type: int
SSL_SENT_SHUTDOWN = m2.SSL_SENT_SHUTDOWN # type: int
SSL_RECEIVED_SHUTDOWN = m2.SSL_RECEIVED_SHUTDOWN # type: int
op_all = m2.SSL_OP_ALL # type: int
op_no_sslv2 = m2.SSL_OP_NO_SSLv2 # type: int
m2crypto-0.42.0/src/M2Crypto/SSL/cb.py 0000664 0000000 0000000 00000005206 14655756567 0017256 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""SSL callbacks
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
import sys
from M2Crypto import m2
from typing import Any # noqa
__all__ = ['unknown_issuer', 'ssl_verify_callback_stub', 'ssl_verify_callback',
'ssl_verify_callback_allow_unknown_ca', 'ssl_info_callback']
def ssl_verify_callback_stub(ssl_ctx_ptr, x509_ptr, errnum, errdepth, ok):
# Deprecated
return ok
unknown_issuer = [
m2.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT,
m2.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
m2.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
m2.X509_V_ERR_CERT_UNTRUSTED,
]
def ssl_verify_callback(ssl_ctx_ptr, x509_ptr, errnum, errdepth, ok):
# type: (bytes, bytes, int, int, int) -> int
# Deprecated
from M2Crypto.SSL.Context import Context
ssl_ctx = Context.ctxmap()[int(ssl_ctx_ptr)]
if errnum in unknown_issuer:
if ssl_ctx.get_allow_unknown_ca():
sys.stderr.write("policy: %s: permitted...\n" %
(m2.x509_get_verify_error(errnum)))
sys.stderr.flush()
ok = 1
# CRL checking goes here...
if ok:
if ssl_ctx.get_verify_depth() >= errdepth:
ok = 1
else:
ok = 0
return ok
def ssl_verify_callback_allow_unknown_ca(ok, store):
# type: (int, Any) -> int
errnum = store.get_error()
if errnum in unknown_issuer:
ok = 1
return ok
# Cribbed from OpenSSL's apps/s_cb.c.
def ssl_info_callback(where, ret, ssl_ptr):
# type: (int, int, bytes) -> None
w = where & ~m2.SSL_ST_MASK
if w & m2.SSL_ST_CONNECT:
state = "SSL connect"
elif w & m2.SSL_ST_ACCEPT:
state = "SSL accept"
else:
state = "SSL state unknown"
if where & m2.SSL_CB_LOOP:
sys.stderr.write("LOOP: %s: %s\n" %
(state, m2.ssl_get_state_v(ssl_ptr)))
sys.stderr.flush()
return
if where & m2.SSL_CB_EXIT:
if not ret:
sys.stderr.write("FAILED: %s: %s\n" %
(state, m2.ssl_get_state_v(ssl_ptr)))
sys.stderr.flush()
else:
sys.stderr.write("INFO: %s: %s\n" %
(state, m2.ssl_get_state_v(ssl_ptr)))
sys.stderr.flush()
return
if where & m2.SSL_CB_ALERT:
if where & m2.SSL_CB_READ:
w = 'read'
else:
w = 'write'
sys.stderr.write("ALERT: %s: %s: %s\n" %
(w, m2.ssl_get_alert_type_v(ret),
m2.ssl_get_alert_desc_v(ret)))
sys.stderr.flush()
return
m2crypto-0.42.0/src/M2Crypto/SSL/timeout.py 0000664 0000000 0000000 00000003040 14655756567 0020352 0 ustar 00root root 0000000 0000000 """Support for SSL socket timeouts.
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved.
Copyright 2008 Heikki Toivonen. All rights reserved.
"""
__all__ = ['DEFAULT_TIMEOUT', 'timeout', 'struct_to_timeout', 'struct_size']
import sys
import struct
from M2Crypto.util import is_32bit, is_libc_musl
DEFAULT_TIMEOUT = 600 # type: int
class timeout(object):
def __init__(self, sec=DEFAULT_TIMEOUT, microsec=0):
# type: (int, int) -> None
self.sec = sec
self.microsec = microsec
def pack(self):
if sys.platform == 'win32':
millisec = int(self.sec * 1000 + round(float(self.microsec) / 1000))
binstr = struct.pack('l', millisec)
else:
if is_32bit() and not is_libc_musl():
binstr = struct.pack('ii', self.sec, self.microsec)
else:
binstr = struct.pack('ll', self.sec, self.microsec)
return binstr
def struct_to_timeout(binstr):
# type: (bytes) -> timeout
if sys.platform == 'win32':
millisec = struct.unpack('l', binstr)[0]
# On py3, int/int performs exact division and returns float. We want
# the whole number portion of the exact division result:
sec = int(millisec / 1000)
microsec = (millisec % 1000) * 1000
else:
(sec, microsec) = struct.unpack('ll', binstr)
return timeout(sec, microsec)
def struct_size():
# type: () -> int
if sys.platform == 'win32':
return struct.calcsize('l')
else:
return struct.calcsize('ll')
m2crypto-0.42.0/src/M2Crypto/X509.py 0000664 0000000 0000000 00000132231 14655756567 0016675 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""M2Crypto wrapper for OpenSSL X509 API.
Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.
Portions created by Open Source Applications Foundation (OSAF) are
Copyright (C) 2004-2007 OSAF. All Rights Reserved.
Author: Heikki Toivonen
"""
import binascii
import logging
from M2Crypto import ASN1, BIO, EVP, m2 # noqa
from typing import AnyStr, List, Optional # noqa
FORMAT_DER = 0
FORMAT_PEM = 1
if hasattr(m2, "VERIFY_ALLOW_PROXY_CERTS"):
verify_allow_proxy_certs = m2.VERIFY_ALLOW_PROXY_CERTS
if hasattr(m2, "VERIFY_CB_ISSUER_CHECK"):
verify_cb_issuer_check = m2.VERIFY_CB_ISSUER_CHECK
if hasattr(m2, "VERIFY_CHECK_SS_SIGNATURE"):
verify_check_ss_signature = m2.VERIFY_CHECK_SS_SIGNATURE
if hasattr(m2, "VERIFY_CRL_CHECK"):
verify_crl_check = m2.VERIFY_CRL_CHECK
if hasattr(m2, "VERIFY_CRL_CHECK_ALL"):
verify_crl_check_all = m2.VERIFY_CRL_CHECK_ALL
if hasattr(m2, "VERIFY_EXPLICIT_POLICY"):
verify_explicit_policy = m2.VERIFY_EXPLICIT_POLICY
if hasattr(m2, "VERIFY_EXTENDED_CRL_SUPPORT"):
verify_extended_crl_support = m2.VERIFY_EXTENDED_CRL_SUPPORT
if hasattr(m2, "VERIFY_IGNORE_CRITICAL"):
verify_ignore_critical = m2.VERIFY_IGNORE_CRITICAL
if hasattr(m2, "VERIFY_INHIBIT_ANY"):
verify_inhibit_any = m2.VERIFY_INHIBIT_ANY
if hasattr(m2, "VERIFY_INHIBIT_MAP"):
verify_inhibit_map = m2.VERIFY_INHIBIT_MAP
if hasattr(m2, "VERIFY_NO_ALT_CHAINS"):
verify_no_alt_chains = m2.VERIFY_NO_ALT_CHAINS
if hasattr(m2, "VERIFY_NO_CHECK_TIME"):
verify_no_check_time = m2.VERIFY_NO_CHECK_TIME
if hasattr(m2, "VERIFY_NOTIFY_POLICY"):
verify_notify_policy = m2.VERIFY_NOTIFY_POLICY
if hasattr(m2, "VERIFY_PARTIAL_CHAIN"):
verify_partial_chain = m2.VERIFY_PARTIAL_CHAIN
if hasattr(m2, "VERIFY_POLICY_CHECK"):
verify_policy_check = m2.VERIFY_POLICY_CHECK
if hasattr(m2, "VERIFY_TRUSTED_FIRST"):
verify_trusted_first = m2.VERIFY_TRUSTED_FIRST
if hasattr(m2, "VERIFY_USE_DELTAS"):
verify_use_deltas = m2.VERIFY_USE_DELTAS
if hasattr(m2, "VERIFY_X509_STRICT"):
verify_x509_strict = m2.VERIFY_X509_STRICT
log = logging.getLogger(__name__)
class X509Error(ValueError):
pass
m2.x509_init(X509Error)
V_OK = m2.X509_V_OK # type: int
def x509_store_default_cb(ok, ctx):
# type: (int, X509_Store_Context) -> int
return ok
def new_extension(name, value, critical=0, _pyfree=1):
# type: (str, bytes, int, int) -> X509_Extension
"""
Create new X509_Extension instance.
"""
if name == 'subjectKeyIdentifier' and \
value.strip('0123456789abcdefABCDEF:') != '':
raise ValueError('value must be precomputed hash')
ctx = m2.x509v3_set_nconf()
x509_ext_ptr = m2.x509v3_ext_conf(None, ctx, name, value)
if x509_ext_ptr is None:
raise X509Error(
"Cannot create X509_Extension with name '%s' and value '%s'" %
(name, value))
x509_ext = X509_Extension(x509_ext_ptr, _pyfree)
x509_ext.set_critical(critical)
return x509_ext
class X509_Extension(object):
"""
X509 Extension
"""
m2_x509_extension_free = m2.x509_extension_free
def __init__(self, x509_ext_ptr=None, _pyfree=1):
# type: (Optional[bytes], int) -> None
self.x509_ext = x509_ext_ptr
self._pyfree = _pyfree
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0) and self.x509_ext:
self.m2_x509_extension_free(self.x509_ext)
def _ptr(self):
# type: () -> bytes
return self.x509_ext
def set_critical(self, critical=1):
# type: (int) -> int
"""
Mark this extension critical or noncritical. By default an
extension is not critical.
:param critical: Nonzero sets this extension as critical.
Calling this method without arguments will
set this extension to critical.
:return: 1 for success, 0 for failure
"""
return m2.x509_extension_set_critical(self.x509_ext, critical)
def get_critical(self):
# type: () -> int
"""
Return whether or not this is a critical extension.
:return: Nonzero if this is a critical extension.
"""
return m2.x509_extension_get_critical(self.x509_ext)
def get_name(self):
# type: () -> str
"""
Get the extension name, for example 'subjectAltName'.
"""
out = m2.x509_extension_get_name(self.x509_ext)
return out.decode() if isinstance(out, bytes) else out
def get_value(self, flag=0, indent=0):
# type: (int, int) -> str
"""
Get the extension value, for example 'DNS:www.example.com'.
:param flag: Flag to control what and how to print.
:param indent: How many spaces to print before actual value.
"""
buf = BIO.MemoryBuffer()
m2.x509_ext_print(buf.bio_ptr(), self.x509_ext, flag, indent)
out = buf.read_all()
return out.decode() if isinstance(out, bytes) else out
class X509_Extension_Stack(object):
"""
X509 Extension Stack
:warning: Do not modify the underlying OpenSSL stack
except through this interface, or use any OpenSSL
functions that do so indirectly. Doing so will get the
OpenSSL stack and the internal pystack of this class out
of sync, leading to python memory leaks, exceptions or
even python crashes!
"""
m2_sk_x509_extension_free = m2.sk_x509_extension_free
def __init__(self, stack=None, _pyfree=0):
# type: (Optional[bytes], int) -> None
if stack is not None:
self.stack = stack
self._pyfree = _pyfree
num = m2.sk_x509_extension_num(self.stack)
for i in range(num):
self.pystack.append(X509_Extension(
m2.sk_x509_extension_value(self.stack, i),
_pyfree=_pyfree))
else:
self.stack = m2.sk_x509_extension_new_null()
self._pyfree = 1
self.pystack = [] # This must be kept in sync with self.stack
def __del__(self):
# type: () -> None
# see BIO.py - unbalanced __init__ / __del__
if getattr(self, '_pyfree', 0):
self.m2_sk_x509_extension_free(self.stack)
def __len__(self):
# type: () -> int
assert m2.sk_x509_extension_num(self.stack) == len(self.pystack)
return len(self.pystack)
def __getitem__(self, idx):
# type: (int) -> X509_Extension
return self.pystack[idx]
def __iter__(self):
return iter(self.pystack)
def _ptr(self):
# type: () -> bytes
return self.stack
def push(self, x509_ext):
# type: (X509_Extension) -> int
"""
Push X509_Extension object onto the stack.
:param x509_ext: X509_Extension object to be pushed onto the stack.
:return: The number of extensions on the stack.
"""
self.pystack.append(x509_ext)
ret = m2.sk_x509_extension_push(self.stack, x509_ext._ptr())
assert ret == len(self.pystack)
return ret
def pop(self):
# type: () -> X509_Extension
"""
Pop X509_Extension object from the stack.
:return: X509_Extension popped
"""
x509_ext_ptr = m2.sk_x509_extension_pop(self.stack)
if x509_ext_ptr is None:
assert len(self.pystack) == 0
return None
return self.pystack.pop()
class X509_Name_Entry(object):
"""
X509 Name Entry
"""
m2_x509_name_entry_free = m2.x509_name_entry_free
def __init__(self, x509_name_entry, _pyfree=0):
# type: (bytes, int) -> None
"""
:param x509_name_entry: this should be OpenSSL X509_NAME_ENTRY binary
:param _pyfree:
"""
self.x509_name_entry = x509_name_entry
self._pyfree = _pyfree
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_x509_name_entry_free(self.x509_name_entry)
def _ptr(self):
# type: () -> bytes
return self.x509_name_entry
def set_object(self, asn1obj):
# type: (ASN1.ASN1_Object) -> int
"""
Sets the field name to asn1obj
:param asn1obj:
:return: 0 on failure, 1 on success
"""
return m2.x509_name_entry_set_object(self.x509_name_entry,
asn1obj._ptr())
def set_data(self, data, type=ASN1.MBSTRING_ASC):
# type: (bytes, int) -> int
"""
Sets the field name to asn1obj
:param data: data in a binary form to be set
:return: 0 on failure, 1 on success
"""
return m2.x509_name_entry_set_data(self.x509_name_entry, type, data)
def get_object(self):
# type: () -> ASN1.ASN1_Object
return ASN1.ASN1_Object(
m2.x509_name_entry_get_object(self.x509_name_entry))
def get_data(self):
# type: () -> ASN1.ASN1_String
return ASN1.ASN1_String(
m2.x509_name_entry_get_data(self.x509_name_entry))
def create_by_txt(self, field, type, entry, len):
return m2.x509_name_entry_create_by_txt(self.x509_name_entry._ptr(),
field, type, entry, len)
class X509_Name(object):
"""
X509 Name
"""
nid = {'C': m2.NID_countryName,
'SP': m2.NID_stateOrProvinceName,
'ST': m2.NID_stateOrProvinceName,
'stateOrProvinceName': m2.NID_stateOrProvinceName,
'L': m2.NID_localityName,
'localityName': m2.NID_localityName,
'O': m2.NID_organizationName,
'organizationName': m2.NID_organizationName,
'OU': m2.NID_organizationalUnitName,
'organizationUnitName': m2.NID_organizationalUnitName,
'CN': m2.NID_commonName,
'commonName': m2.NID_commonName,
'Email': m2.NID_pkcs9_emailAddress,
'emailAddress': m2.NID_pkcs9_emailAddress,
'serialNumber': m2.NID_serialNumber,
'SN': m2.NID_surname,
'surname': m2.NID_surname,
'GN': m2.NID_givenName,
'givenName': m2.NID_givenName
}
m2_x509_name_free = m2.x509_name_free
def __init__(self, x509_name=None, _pyfree=0):
# type: (Optional[bytes], int) -> None
"""
:param x509_name: this should be OpenSSL X509_NAME binary
:param _pyfree:
"""
if x509_name is not None:
assert m2.x509_name_type_check(x509_name), "'x509_name' type error"
self.x509_name = x509_name
self._pyfree = _pyfree
else:
self.x509_name = m2.x509_name_new()
self._pyfree = 1
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_x509_name_free(self.x509_name)
def __str__(self):
# type: () -> bytes
assert m2.x509_name_type_check(self.x509_name), \
"'x509_name' type error"
return m2.x509_name_oneline(self.x509_name)
def __getattr__(self, attr):
# type: (str) -> str
if attr in self.nid:
assert m2.x509_name_type_check(self.x509_name), \
"'x509_name' type error"
out = m2.x509_name_by_nid(self.x509_name, self.nid[attr])
return out.decode() if isinstance(out, bytes) else out
if attr in self.__dict__:
return self.__dict__[attr]
raise AttributeError(self, attr)
def __setattr__(self, attr, value):
# type: (str, AnyStr) -> int
"""
:return: 1 for success of 0 if an error occurred.
"""
if attr in self.nid:
assert m2.x509_name_type_check(self.x509_name), \
"'x509_name' type error"
value = value.encode() if isinstance(value, str) else value
return m2.x509_name_set_by_nid(self.x509_name, self.nid[attr],
value)
self.__dict__[attr] = value
def __len__(self):
# type: () -> int
return m2.x509_name_entry_count(self.x509_name)
def __getitem__(self, idx):
# type: (int) -> X509_Name_Entry
if not 0 <= idx < self.entry_count():
raise IndexError("index out of range")
return X509_Name_Entry(m2.x509_name_get_entry(self.x509_name, idx))
def __iter__(self):
for i in range(self.entry_count()):
yield self[i]
def _ptr(self):
assert m2.x509_name_type_check(self.x509_name), \
"'x509_name' type error"
return self.x509_name
def add_entry_by_txt(self, field, type, entry, len, loc, set):
# entry_type: (str, int, bytes, int, int, int) -> int
"""
Add X509_Name field whose name is identified by its name.
:param field: name of the entry
:param type: use MBSTRING_ASC or MBSTRING_UTF8
(or standard ASN1 type like V_ASN1_IA5STRING)
:param entry: value
:param len: buf_len of the entry
(-1 and the length is computed automagically)
The ``loc`` and ``set`` parameters determine where a new entry
should be added.
For almost all applications loc can be set to -1 and set to 0.
This adds a new entry to the end of name as a single valued
RelativeDistinguishedName (RDN).
:param loc: determines the index where the new entry is
inserted: if it is -1 it is appended.
:param set: determines how the new type is added. If it is zero
a new RDN is created.
If set is -1 or 1 it is added to the previous or next RDN
structure respectively. This will then be a multivalued
RDN: since multivalues RDNs are very seldom used set is
almost always set to zero.
:return: 1 for success of 0 if an error occurred.
"""
entry = entry.decode() if isinstance(entry, bytes) else entry
return m2.x509_name_add_entry_by_txt(self.x509_name,
field, type,
entry, len, loc, set)
def entry_count(self):
# type: () -> int
return m2.x509_name_entry_count(self.x509_name)
def get_entries_by_nid(self, nid):
# type: (int) -> List[X509_Name_Entry]
"""
Retrieve the next index matching nid.
:param nid: name of the entry (as m2.NID* constants)
:return: list of X509_Name_Entry items
"""
ret = []
lastpos = -1
while True:
lastpos = m2.x509_name_get_index_by_nid(self.x509_name, nid,
lastpos)
if lastpos == -1:
break
ret.append(self[lastpos])
return ret
def as_text(self, indent=0, flags=m2.XN_FLAG_COMPAT):
# type: (int, int) -> str
"""
as_text returns the name as a string.
:param indent: Each line in multiline format is indented
by this many spaces.
:param flags: Flags that control how the output should be formatted.
"""
assert m2.x509_name_type_check(self.x509_name), \
"'x509_name' type error"
buf = BIO.MemoryBuffer()
m2.x509_name_print_ex(buf.bio_ptr(), self.x509_name, indent, flags)
out = buf.read_all()
return out.decode() if isinstance(out, bytes) else out
def as_der(self):
# type: () -> bytes
assert m2.x509_name_type_check(self.x509_name), \
"'x509_name' type error"
return m2.x509_name_get_der(self.x509_name)
def as_hash(self):
# type: () -> int
assert m2.x509_name_type_check(self.x509_name), \
"'x509_name' type error"
return m2.x509_name_hash(self.x509_name)
class X509(object):
"""
X.509 Certificate
"""
m2_x509_free = m2.x509_free
def __init__(self, x509=None, _pyfree=0):
# type: (Optional[bytes], int) -> None
"""
:param x509: binary representation of
the underlying OpenSSL X509 object.
:param _pyfree:
"""
if x509 is not None:
assert m2.x509_type_check(x509), "'x509' type error"
self.x509 = x509
self._pyfree = _pyfree
else:
self.x509 = m2.x509_new()
self._pyfree = 1
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_x509_free(self.x509)
def _ptr(self):
# type: () -> bytes
assert m2.x509_type_check(self.x509), "'x509' type error"
return self.x509
def as_text(self):
# type: () -> str
assert m2.x509_type_check(self.x509), "'x509' type error"
buf = BIO.MemoryBuffer()
m2.x509_print(buf.bio_ptr(), self.x509)
out = buf.read_all()
return out.decode() if isinstance(out, bytes) else out
def as_der(self):
# type: () -> bytes
assert m2.x509_type_check(self.x509), "'x509' type error"
return m2.i2d_x509(self.x509)
def as_pem(self):
# type: () -> bytes
buf = BIO.MemoryBuffer()
m2.x509_write_pem(buf.bio_ptr(), self.x509)
return buf.read_all()
def save_pem(self, filename):
# type: (AnyStr) -> int
"""
:param filename: name of the file to be loaded
:return: 1 for success or 0 for failure
"""
with BIO.openfile(filename, 'wb') as bio:
return m2.x509_write_pem(bio.bio_ptr(), self.x509)
def save(self, filename, format=FORMAT_PEM):
# type: (AnyStr, int) -> int
"""
Saves X.509 certificate to a file. Default output
format is PEM.
:param filename: Name of the file the cert will be saved to.
:param format: Controls what output format is used to save the cert.
Either FORMAT_PEM or FORMAT_DER to save in PEM or
DER format. Raises a ValueError if an unknow
format is used.
:return: 1 for success or 0 for failure
"""
with BIO.openfile(filename, 'wb') as bio:
if format == FORMAT_PEM:
return m2.x509_write_pem(bio.bio_ptr(), self.x509)
elif format == FORMAT_DER:
return m2.i2d_x509_bio(bio.bio_ptr(), self.x509)
else:
raise ValueError(
"Unknown filetype. Must be either FORMAT_PEM or FORMAT_DER")
def set_version(self, version):
# type: (int) -> int
"""
Set version of the certificate.
:param version: Version number.
:return: Returns 0 on failure.
"""
assert m2.x509_type_check(self.x509), "'x509' type error"
return m2.x509_set_version(self.x509, version)
def set_not_before(self, asn1_time):
# type: (ASN1.ASN1_TIME) -> int
"""
:return: 1 on success, 0 on failure
"""
assert m2.x509_type_check(self.x509), "'x509' type error"
return m2.x509_set_not_before(self.x509, asn1_time._ptr())
def set_not_after(self, asn1_time):
# type: (ASN1.ASN1_TIME) -> int
"""
:return: 1 on success, 0 on failure
"""
assert m2.x509_type_check(self.x509), "'x509' type error"
return m2.x509_set_not_after(self.x509, asn1_time._ptr())
def set_subject_name(self, name):
# type: (X509_Name) -> int
"""
:return: 1 on success, 0 on failure
"""
assert m2.x509_type_check(self.x509), "'x509' type error"
return m2.x509_set_subject_name(self.x509, name.x509_name)
def set_issuer_name(self, name):
# type: (X509_Name) -> int
"""
:return: 1 on success, 0 on failure
"""
assert m2.x509_type_check(self.x509), "'x509' type error"
return m2.x509_set_issuer_name(self.x509, name.x509_name)
def get_version(self):
# type: () -> int
assert m2.x509_type_check(self.x509), "'x509' type error"
return m2.x509_get_version(self.x509)
def get_serial_number(self):
# type: () -> ASN1.ASN1_Integer
assert m2.x509_type_check(self.x509), "'x509' type error"
asn1_integer = m2.x509_get_serial_number(self.x509)
return m2.asn1_integer_get(asn1_integer)
def set_serial_number(self, serial):
# type: (ASN1.ASN1_Integer) -> int
"""
Set serial number.
:param serial: Serial number.
:return 1 for success and 0 for failure.
"""
assert m2.x509_type_check(self.x509), "'x509' type error"
# This "magically" changes serial since asn1_integer
# is C pointer to x509's internal serial number.
asn1_integer = m2.x509_get_serial_number(self.x509)
return m2.asn1_integer_set(asn1_integer, serial)
# XXX Or should I do this?
# asn1_integer = m2.asn1_integer_new()
# m2.asn1_integer_set(asn1_integer, serial)
# return m2.x509_set_serial_number(self.x509, asn1_integer)
def get_not_before(self):
# type: () -> ASN1.ASN1_TIME
assert m2.x509_type_check(self.x509), "'x509' type error"
# ASN1_TIME_dup() as internal ref. depends on self being referenced
ref = ASN1.ASN1_TIME(m2.x509_get_not_before(self.x509))
out = ASN1.ASN1_TIME(_pyfree=1)
out.set_datetime(ref.get_datetime())
return out
def get_not_after(self):
# type: () -> ASN1.ASN1_TIME
assert m2.x509_type_check(self.x509), "'x509' type error"
# ASN1_TIME_dup() as internal ref. depends on self being referenced
ref = ASN1.ASN1_TIME(m2.x509_get_not_after(self.x509))
out = ASN1.ASN1_TIME(_pyfree=1)
out.set_datetime(ref.get_datetime())
if 'Bad time value' in str(out):
raise X509Error(
'''M2Crypto cannot handle dates after year 2050.
See RFC 5280 4.1.2.5 for more information.
''')
return out
def get_pubkey(self):
# type: () -> EVP.PKey
assert m2.x509_type_check(self.x509), "'x509' type error"
return EVP.PKey(m2.x509_get_pubkey(self.x509), _pyfree=1)
def set_pubkey(self, pkey):
# type: (EVP.PKey) -> int
"""
Set the public key for the certificate
:param pkey: Public key
:return 1 for success and 0 for failure
"""
assert m2.x509_type_check(self.x509), "'x509' type error"
return m2.x509_set_pubkey(self.x509, pkey.pkey)
def get_issuer(self):
# type: () -> X509_Name
assert m2.x509_type_check(self.x509), "'x509' type error"
return X509_Name(m2.x509_get_issuer_name(self.x509))
def set_issuer(self, name):
# type: (X509_Name) -> int
"""
Set issuer name.
:param name: subjectName field.
:return 1 for success and 0 for failure
"""
assert m2.x509_type_check(self.x509), "'x509' type error"
return m2.x509_set_issuer_name(self.x509, name.x509_name)
def get_subject(self):
# type: () -> X509_Name
assert m2.x509_type_check(self.x509), "'x509' type error"
return X509_Name(m2.x509_get_subject_name(self.x509))
def set_subject(self, name):
# type: (X509_Name) -> int
"""
Set subject name.
:param name: subjectName field.
:return 1 for success and 0 for failure
"""
assert m2.x509_type_check(self.x509), "'x509' type error"
return m2.x509_set_subject_name(self.x509, name.x509_name)
def add_ext(self, ext):
# type: (X509_Extension) -> int
"""
Add X509 extension to this certificate.
:param ext: Extension
:return 1 for success and 0 for failure
"""
assert m2.x509_type_check(self.x509), "'x509' type error"
return m2.x509_add_ext(self.x509, ext.x509_ext, -1)
def get_ext(self, name):
# type: (str) -> X509_Extension
"""
Get X509 extension by name.
:param name: Name of the extension
:return: X509_Extension
"""
# Optimizations to reduce attribute accesses
m2x509_get_ext = m2.x509_get_ext
m2x509_extension_get_name = m2.x509_extension_get_name
x509 = self.x509
name = name.encode() if isinstance(name, str) else name
for i in range(m2.x509_get_ext_count(x509)):
ext_ptr = m2x509_get_ext(x509, i)
if m2x509_extension_get_name(ext_ptr) == name:
return X509_Extension(ext_ptr, _pyfree=0)
raise LookupError
def get_ext_at(self, index):
# type: (int) -> X509_Extension
"""
Get X509 extension by index.
:param index: Name of the extension
:return: X509_Extension
"""
if index < 0 or index >= self.get_ext_count():
raise IndexError
return X509_Extension(m2.x509_get_ext(self.x509, index),
_pyfree=0)
def get_ext_count(self):
# type: () -> int
"""
Get X509 extension count.
"""
return m2.x509_get_ext_count(self.x509)
def sign(self, pkey, md):
# type: (EVP.PKey, str) -> int
"""
Sign the certificate.
:param pkey: Public key
:param md: Message digest algorithm to use for signing,
for example 'sha1'.
:return int
"""
assert m2.x509_type_check(self.x509), "'x509' type error"
mda = getattr(m2, md, None)
if mda is None:
raise ValueError('unknown message digest', md)
return m2.x509_sign(self.x509, pkey.pkey, mda())
def verify(self, pkey=None):
# type: (Optional[EVP.PKey]) -> int
assert m2.x509_type_check(self.x509), "'x509' type error"
if pkey:
return m2.x509_verify(self.x509, pkey.pkey)
else:
return m2.x509_verify(self.x509, self.get_pubkey().pkey)
def check_ca(self):
# type: () -> int
"""
Check if the certificate is a Certificate Authority (CA) certificate.
:return: 0 if the certificate is not CA, nonzero otherwise.
:requires: OpenSSL 0.9.8 or newer
"""
return m2.x509_check_ca(self.x509)
def check_purpose(self, id, ca):
# type: (int, int) -> int
"""
Check if the certificate's purpose matches the asked purpose.
:param id: Purpose id. See X509_PURPOSE_* constants.
:param ca: 1 if the certificate should be CA, 0 otherwise.
:return: 0 if the certificate purpose does not match, nonzero
otherwise.
"""
return m2.x509_check_purpose(self.x509, id, ca)
def get_fingerprint(self, md='md5'):
# type: (str) -> str
"""
Get the fingerprint of the certificate.
:param md: Message digest algorithm to use.
:return: String containing the fingerprint in hex format.
"""
der = self.as_der()
md = EVP.MessageDigest(md)
md.update(der)
digest = md.final()
return binascii.hexlify(digest).upper().decode()
def load_cert(file, format=FORMAT_PEM):
# type: (AnyStr, int) -> X509
"""
Load certificate from file.
:param file: Name of file containing certificate in either DER or
PEM format.
:param format: Describes the format of the file to be loaded,
either PEM or DER.
:return: M2Crypto.X509.X509 object.
"""
with BIO.openfile(file) as bio:
if format == FORMAT_PEM:
return load_cert_bio(bio)
elif format == FORMAT_DER:
cptr = m2.d2i_x509(bio._ptr())
return X509(cptr, _pyfree=1)
else:
raise ValueError(
"Unknown format. Must be either FORMAT_DER or FORMAT_PEM")
def load_cert_bio(bio, format=FORMAT_PEM):
# type: (BIO.BIO, int) -> X509
"""
Load certificate from a bio.
:param bio: BIO pointing at a certificate in either DER or PEM format.
:param format: Describes the format of the cert to be loaded,
either PEM or DER (via constants FORMAT_PEM
and FORMAT_FORMAT_DER)
:return: M2Crypto.X509.X509 object.
"""
if format == FORMAT_PEM:
cptr = m2.x509_read_pem(bio._ptr())
elif format == FORMAT_DER:
cptr = m2.d2i_x509(bio._ptr())
else:
raise ValueError(
"Unknown format. Must be either FORMAT_DER or FORMAT_PEM")
return X509(cptr, _pyfree=1)
def load_cert_string(cert_str, format=FORMAT_PEM):
# type: (AnyStr, int) -> X509
"""
Load certificate from a cert_str.
:param cert_str: String containing a certificate in either
DER or PEM format.
:param format: Describes the format of the cert to be loaded,
either PEM or DER (via constants FORMAT_PEM
and FORMAT_FORMAT_DER)
:return: M2Crypto.X509.X509 object.
"""
cert_str = cert_str.encode() if isinstance(cert_str, str) else cert_str
bio = BIO.MemoryBuffer(cert_str)
return load_cert_bio(bio, format)
def load_cert_der_string(cert_str):
# type: (AnyStr) -> X509
"""
Load certificate from a cert_str.
:param cert_str: String containing a certificate in DER format.
:return: M2Crypto.X509.X509 object.
"""
cert_str = cert_str.encode() if isinstance(cert_str, str) else cert_str
bio = BIO.MemoryBuffer(cert_str)
cptr = m2.d2i_x509(bio._ptr())
return X509(cptr, _pyfree=1)
class X509_Store_Context(object):
"""
X509 Store Context
"""
m2_x509_store_ctx_free = m2.x509_store_ctx_free
def __init__(self, x509_store_ctx, _pyfree=0):
# type: (bytes, int) -> None
"""
:param x509_store_ctx: binary data for
OpenSSL X509_STORE_CTX type
"""
self.ctx = x509_store_ctx
self._pyfree = _pyfree
def __del__(self):
# type: () -> None
# see BIO.py - unbalanced __init__ / __del__
if not hasattr(self, '_pyfree'):
pass # print("OOPS")
elif self._pyfree:
self.m2_x509_store_ctx_free(self.ctx)
def _ptr(self):
return self.ctx
def get_current_cert(self):
# type: () -> X509
"""
Get current X.509 certificate.
:warning: The returned certificate is NOT refcounted, so you can not
rely on it being valid once the store context goes
away or is modified.
"""
return X509(m2.x509_store_ctx_get_current_cert(self.ctx), _pyfree=0)
def get_error(self):
# type: () -> int
"""
Get error code.
"""
return m2.x509_store_ctx_get_error(self.ctx)
def get_error_depth(self):
# type: () -> int
"""
Get error depth.
"""
return m2.x509_store_ctx_get_error_depth(self.ctx)
def get1_chain(self):
# type: () -> X509_Stack
"""
Get certificate chain.
:return: Reference counted (i.e. safe to use even after the store
context goes away) stack of certificates in the chain.
"""
return X509_Stack(m2.x509_store_ctx_get1_chain(self.ctx), 1, 1)
class X509_Store(object):
"""
X509 Store
"""
m2_x509_store_free = m2.x509_store_free
def __init__(self, store=None, _pyfree=0):
# type: (Optional[bytes], int) -> None
"""
:param store: binary data for OpenSSL X509_STORE_CTX type.
"""
if store is not None:
self.store = store
self._pyfree = _pyfree
else:
self.store = m2.x509_store_new()
self._pyfree = 1
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_x509_store_free(self.store)
def _ptr(self):
return self.store
def load_info(self, file):
# type: (AnyStr) -> int
"""
:param file: filename
:return: 1 on success, 0 on failure
"""
ret = m2.x509_store_load_locations(self.store, file)
return ret
load_locations = load_info
def add_x509(self, x509):
# type: (X509) -> int
assert isinstance(x509, X509)
return m2.x509_store_add_cert(self.store, x509._ptr())
def set_verify_cb(self, callback=None):
# type: (Optional[callable]) -> None
"""
Set callback which will be called when the store is verified.
Wrapper over OpenSSL X509_STORE_set_verify_cb().
:param callback: Callable to specify verification options.
Type of the callable must be:
(int, X509_Store_Context) -> int.
If None: set the standard options.
:note: compile-time or run-time errors in the callback would result
in mysterious errors during verification, which could be hard
to trace.
:note: Python exceptions raised in callbacks do not propagate to
verify() call.
:return: None
"""
if callback is None:
return self.set_verify_cb(x509_store_default_cb)
if not callable(callback):
raise X509Error("set_verify(): callback is not callable")
return m2.x509_store_set_verify_cb(self.store, callback)
add_cert = add_x509
def set_flags(self, flags):
# type: (int) -> int
"""
Set the verification flags for the X509Store
Wrapper over OpenSSL X509_STORE_set_flags()
:param flags: `VERIFICATION FLAGS` section of the
X509_VERIFY_PARAM_set_flags man page has
a complete description of values the flags
parameter can take.
Their M2Crypto equivalent is transformed following
the pattern: "X509_V_FLAG_XYZ" -> lowercase("VERIFY_XYZ")
"""
return m2.x509_store_set_flags(self.store, flags)
class X509_Stack(object):
"""
X509 Stack
:warning: Do not modify the underlying OpenSSL stack
except through this interface, or use any OpenSSL
functions that do so indirectly. Doing so will get the
OpenSSL stack and the internal pystack of this class out
of sync, leading to python memory leaks, exceptions or
even python crashes!
"""
m2_sk_x509_free = m2.sk_x509_free
def __init__(self, stack=None, _pyfree=0, _pyfree_x509=0):
# type: (Optional[bytes], int, int) -> None
if stack is not None:
self.stack = stack
self._pyfree = _pyfree
self.pystack = [] # This must be kept in sync with self.stack
num = m2.sk_x509_num(self.stack)
for i in range(num):
self.pystack.append(X509(m2.sk_x509_value(self.stack, i),
_pyfree=_pyfree_x509))
else:
self.stack = m2.sk_x509_new_null()
self._pyfree = 1
self.pystack = [] # This must be kept in sync with self.stack
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_sk_x509_free(self.stack)
def __len__(self):
# type: () -> int
assert m2.sk_x509_num(self.stack) == len(self.pystack)
return len(self.pystack)
def __getitem__(self, idx):
# type: (int) -> X509
return self.pystack[idx]
def __iter__(self):
return iter(self.pystack)
def _ptr(self):
return self.stack
def push(self, x509):
# type: (X509) -> int
"""
push an X509 certificate onto the stack.
:param x509: X509 object.
:return: The number of X509 objects currently on the stack.
"""
assert isinstance(x509, X509)
self.pystack.append(x509)
ret = m2.sk_x509_push(self.stack, x509._ptr())
assert ret == len(self.pystack)
return ret
def pop(self):
# type: () -> X509
"""
pop a certificate from the stack.
:return: X509 object that was popped, or None if there is
nothing to pop.
"""
x509_ptr = m2.sk_x509_pop(self.stack)
if x509_ptr is None:
assert len(self.pystack) == 0
return None
return self.pystack.pop()
def as_der(self):
# type: () -> bytes
"""
Return the stack as a DER encoded string
"""
return m2.get_der_encoding_stack(self.stack)
def new_stack_from_der(der_string):
# type: (bytes) -> X509_Stack
"""
Create a new X509_Stack from DER string.
:return: X509_Stack
"""
der_string = der_string.encode() if isinstance(der_string, str) else der_string
stack_ptr = m2.make_stack_from_der_sequence(der_string)
return X509_Stack(stack_ptr, 1, 1)
class Request(object):
"""
X509 Certificate Request.
"""
m2_x509_req_free = m2.x509_req_free
def __init__(self, req=None, _pyfree=0):
# type: (Optional[int], int) -> None
if req is not None:
self.req = req
self._pyfree = _pyfree
else:
self.req = m2.x509_req_new()
m2.x509_req_set_version(self.req, 0)
self._pyfree = 1
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_x509_req_free(self.req)
def as_text(self):
# type: () -> str
buf = BIO.MemoryBuffer()
m2.x509_req_print(buf.bio_ptr(), self.req)
out = buf.read_all()
return out.decode() if isinstance(out, bytes) else out
def as_pem(self):
# type: () -> bytes
buf = BIO.MemoryBuffer()
m2.x509_req_write_pem(buf.bio_ptr(), self.req)
return buf.read_all()
def as_der(self):
# type: () -> bytes
buf = BIO.MemoryBuffer()
m2.i2d_x509_req_bio(buf.bio_ptr(), self.req)
return buf.read_all()
def save_pem(self, filename):
# type: (AnyStr) -> int
with BIO.openfile(filename, 'wb') as bio:
return m2.x509_req_write_pem(bio.bio_ptr(), self.req)
def save(self, filename, format=FORMAT_PEM):
# type: (AnyStr, int) -> int
"""
Saves X.509 certificate request to a file. Default output
format is PEM.
:param filename: Name of the file the request will be saved to.
:param format: Controls what output format is used to save the
request. Either FORMAT_PEM or FORMAT_DER to save
in PEM or DER format. Raises ValueError if an
unknown format is used.
:return: 1 for success, 0 for failure.
The error code can be obtained by ERR_get_error.
"""
with BIO.openfile(filename, 'wb') as bio:
if format == FORMAT_PEM:
return m2.x509_req_write_pem(bio.bio_ptr(), self.req)
elif format == FORMAT_DER:
return m2.i2d_x509_req_bio(bio.bio_ptr(), self.req)
else:
raise ValueError(
"Unknown filetype. Must be either FORMAT_DER or FORMAT_PEM")
def get_pubkey(self):
# type: () -> EVP.PKey
"""
Get the public key for the request.
:return: Public key from the request.
"""
return EVP.PKey(m2.x509_req_get_pubkey(self.req), _pyfree=1)
def set_pubkey(self, pkey):
# type: (EVP.PKey) -> int
"""
Set the public key for the request.
:param pkey: Public key
:return: Return 1 for success and 0 for failure.
"""
return m2.x509_req_set_pubkey(self.req, pkey.pkey)
def get_version(self):
# type: () -> int
"""
Get version.
:return: Returns version.
"""
return m2.x509_req_get_version(self.req)
def set_version(self, version):
# type: (int) -> int
"""
Set version.
:param version: Version number.
:return: Returns 0 on failure.
"""
return m2.x509_req_set_version(self.req, version)
def get_subject(self):
# type: () -> X509_Name
return X509_Name(m2.x509_req_get_subject_name(self.req))
def set_subject_name(self, name):
# type: (X509_Name) -> int
"""
Set subject name.
:param name: subjectName field.
:return: 1 for success and 0 for failure
"""
return m2.x509_req_set_subject_name(self.req, name.x509_name)
set_subject = set_subject_name
def add_extensions(self, ext_stack):
# type: (X509_Extension_Stack) -> int
"""
Add X509 extensions to this request.
:param ext_stack: Stack of extensions to add.
:return: 1 for success and 0 for failure
"""
return m2.x509_req_add_extensions(self.req, ext_stack._ptr())
def verify(self, pkey):
# type: (EVP.PKey) -> int
"""
:param pkey: PKey to be verified
:return: 1 for success and 0 for failure
"""
return m2.x509_req_verify(self.req, pkey.pkey)
def sign(self, pkey, md):
# type: (EVP.PKey, str) -> int
"""
:param pkey: PKey to be signed
:param md: used algorigthm
:return: 1 for success and 0 for failure
"""
mda = getattr(m2, md, None)
if mda is None:
raise ValueError('unknown message digest', md)
return m2.x509_req_sign(self.req, pkey.pkey, mda())
def load_request(file, format=FORMAT_PEM):
# type: (AnyStr, int) -> Request
"""
Load certificate request from file.
:param file: Name of file containing certificate request in
either PEM or DER format.
:param format: Describes the format of the file to be loaded,
either PEM or DER. (using constants FORMAT_PEM
and FORMAT_DER)
:return: Request object.
"""
with BIO.openfile(file) as f:
if format == FORMAT_PEM:
cptr = m2.x509_req_read_pem(f.bio_ptr())
elif format == FORMAT_DER:
cptr = m2.d2i_x509_req(f.bio_ptr())
else:
raise ValueError(
"Unknown filetype. Must be either FORMAT_PEM or FORMAT_DER")
return Request(cptr, 1)
def load_request_bio(bio, format=FORMAT_PEM):
# type: (BIO.BIO, int) -> Request
"""
Load certificate request from a bio.
:param bio: BIO pointing at a certificate request in
either DER or PEM format.
:param format: Describes the format of the request to be loaded,
either PEM or DER. (using constants FORMAT_PEM
and FORMAT_DER)
:return: M2Crypto.X509.Request object.
"""
if format == FORMAT_PEM:
cptr = m2.x509_req_read_pem(bio._ptr())
elif format == FORMAT_DER:
cptr = m2.d2i_x509_req(bio._ptr())
else:
raise ValueError(
"Unknown format. Must be either FORMAT_DER or FORMAT_PEM")
return Request(cptr, _pyfree=1)
def load_request_string(cert_str, format=FORMAT_PEM):
# type: (AnyStr, int) -> Request
"""
Load certificate request from a cert_str.
:param cert_str: String containing a certificate request in
either DER or PEM format.
:param format: Describes the format of the request to be loaded,
either PEM or DER. (using constants FORMAT_PEM
and FORMAT_DER)
:return: M2Crypto.X509.Request object.
"""
cert_str = cert_str.encode() if isinstance(cert_str, str) else cert_str
bio = BIO.MemoryBuffer(cert_str)
return load_request_bio(bio, format)
def load_request_der_string(cert_str):
# type: (AnyStr) -> Request
"""
Load certificate request from a cert_str.
:param cert_str: String containing a certificate request in DER format.
:return: M2Crypto.X509.Request object.
"""
cert_str = cert_str.encode() if isinstance(cert_str, str) else cert_str
bio = BIO.MemoryBuffer(cert_str)
return load_request_bio(bio, FORMAT_DER)
class CRL(object):
"""
X509 Certificate Revocation List
"""
m2_x509_crl_free = m2.x509_crl_free
def __init__(self, crl=None, _pyfree=0):
# type: (Optional[bytes], int) -> None
"""
:param crl: binary representation of
the underlying OpenSSL X509_CRL object.
"""
if crl is not None:
self.crl = crl
self._pyfree = _pyfree
else:
self.crl = m2.x509_crl_new()
self._pyfree = 1
def __del__(self):
# type: () -> None
if getattr(self, '_pyfree', 0):
self.m2_x509_crl_free(self.crl)
def as_text(self):
# type: () -> str
"""
Return CRL in PEM format in a string.
:return: String containing the CRL in PEM format.
"""
buf = BIO.MemoryBuffer()
m2.x509_crl_print(buf.bio_ptr(), self.crl)
out = buf.read_all()
return out.decode() if isinstance(out, bytes) else out
def load_crl(file):
# type: (AnyStr) -> CRL
"""
Load CRL from file.
:param file: Name of file containing CRL in PEM format.
:return: M2Crypto.X509.CRL object.
"""
with BIO.openfile(file) as f:
cptr = m2.x509_crl_read_pem(f.bio_ptr())
return CRL(cptr, 1)
m2crypto-0.42.0/src/M2Crypto/__init__.py 0000664 0000000 0000000 00000002440 14655756567 0017765 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""
M2Crypto is the most complete Python wrapper for OpenSSL
featuring RSA, DSA, DH, EC, HMACs, message digests, symmetric
ciphers (including AES); SSL functionality to implement clients
and servers; HTTPS extensions to Python's httplib, urllib, and
xmlrpclib; unforgeable HMAC'ing AuthCookies for web session
management; FTP/TLS client and server; and ZSmime: An S/MIME
messenger for Zope. M2Crypto can also be used to provide SSL for
Twisted. Smartcards supported through the Engine interface.
Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.
Portions created by Open Source Applications Foundation (OSAF) are
Copyright (C) 2004-2007 OSAF. All Rights Reserved.
Copyright 2008-2011 Heikki Toivonen. All rights reserved.
"""
# noqa
__version__ = '0.42.0'
version = __version__ # type: str
try:
from distutils.version import StrictVersion as Version
except ImportError:
try:
from packaging.version import Version
except ImportError:
Version = None
if Version is not None:
__ver = Version(__version__)
if hasattr(__ver, '_version'):
version_info = tuple(__ver._version[1])
elif hasattr(__ver, 'version'):
version_info = __ver.version
from M2Crypto import m2
encrypt = 1
decrypt = 0
m2.lib_init()
m2crypto-0.42.0/src/M2Crypto/callback.py 0000664 0000000 0000000 00000000452 14655756567 0017763 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""Deprecated, use the util module instead.
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
import warnings
warnings.warn('Use the util module instead', DeprecationWarning)
from M2Crypto.util import genparam_callback, passphrase_callback
m2crypto-0.42.0/src/M2Crypto/ftpslib.py 0000664 0000000 0000000 00000005412 14655756567 0017673 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""M2Crypto client-side FTP/TLS.
This implementation complies with draft-murray-auth-ftp-ssl-07.txt.
Example:
>>> from M2Crypto import ftpslib
>>> f = ftpslib.FTP_TLS()
>>> f.connect('', 9021)
'220 spinnaker.dyndns.org M2Crypto (Medusa) FTP/TLS server v0.07 ready.'
>>> f.auth_tls()
>>> f.set_pasv(0)
>>> f.login('ftp', 'ngps@')
'230 Ok.'
>>> f.retrlines('LIST')
-rw-rw-r-- 1 0 198 2326 Jul 3 1996 apache_pb.gif
drwxrwxr-x 7 0 198 1536 Oct 10 2000 manual
drwxrwxr-x 2 0 198 512 Oct 31 2000 modpy
drwxrwxr-x 2 0 198 512 Oct 31 2000 bobo
drwxr-xr-x 2 0 198 14336 May 28 15:54 postgresql
drwxr-xr-x 4 100 198 512 May 16 17:19 home
drwxr-xr-x 7 100 100 3584 Sep 23 2000 openacs
drwxr-xr-x 10 0 0 512 Aug 5 2000 python1.5
-rw-r--r-- 1 100 198 326 Jul 29 03:29 index.html
drwxr-xr-x 12 0 0 512 May 31 17:08 python2.1
'226 Transfer complete'
>>> f.quit()
'221 Goodbye.'
>>>
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
# We want to import whole stdlib ftplib objects, because our users want
# to use them.
from ftplib import * # noqa
# M2Crypto
from M2Crypto import SSL
class FTP_TLS(FTP):
"""Python OO interface to client-side FTP/TLS."""
def __init__(self, host=None, ssl_ctx=None):
"""Initialise the client. If 'host' is supplied, connect to it."""
if ssl_ctx is not None:
self.ssl_ctx = ssl_ctx
else:
self.ssl_ctx = SSL.Context()
FTP.__init__(self, host)
self.prot = 0
def auth_tls(self):
"""Secure the control connection per AUTH TLS, aka AUTH TLS-C."""
self.voidcmd('AUTH TLS')
s = SSL.Connection(self.ssl_ctx, self.sock)
s.setup_ssl()
s.set_connect_state()
s.connect_ssl()
self.sock = s
self.file = self.sock.makefile()
def auth_ssl(self):
"""Secure the control connection per AUTH SSL, aka AUTH TLS-P."""
raise NotImplementedError
def prot_p(self):
"""Set up secure data connection."""
self.voidcmd('PBSZ 0')
self.voidcmd('PROT P')
self.prot = 1
def prot_c(self):
"""Set up data connection in the clear."""
self.voidcmd('PROT C')
self.prot = 0
def ntransfercmd(self, cmd, rest=None):
"""Initiate a data transfer."""
conn, size = FTP.ntransfercmd(self, cmd, rest)
if self.prot:
conn = SSL.Connection(self.ssl_ctx, conn)
conn.setup_ssl()
conn.set_connect_state()
conn.set_session(self.sock.get_session())
conn.connect_ssl()
return conn, size
m2crypto-0.42.0/src/M2Crypto/httpslib.py 0000664 0000000 0000000 00000024166 14655756567 0020070 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
import warnings
"""M2Crypto support for Python's httplib.
Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved."""
import base64
import socket
from M2Crypto import SSL
from urllib.parse import urlsplit, urlunsplit
from http.client import * # noqa
# This is not imported with just '*'
from http.client import HTTPS_PORT
from typing import Any, AnyStr, Callable, Dict, Optional # noqa
class HTTPSConnection(HTTPConnection):
"""
This class allows communication via SSL using M2Crypto.
"""
default_port = HTTPS_PORT
def __init__(self, host, port=None, strict=None, **ssl):
# type: (str, Optional[int], Optional[bool], **Any) -> None
"""
Represents one transaction with an HTTP server over the SSL
connection.
:param host: host name
:param port: port number
:param strict: if switched on, it raises BadStatusLine to be
raised if the status line can't be parsed as
a valid HTTP/1.0 or 1.1 status line.
:param ssl: dict with all remaining named real parameters of the
function. Specifically, ``ssl_context`` is expected
to be included with SSL.Context; if it is not
default ``'sslv23'`` is substituted).
"""
self.session = None # type: bytes
self.host = host
self.port = port
keys = set(ssl.keys()) - set(
('key_file', 'cert_file', 'ssl_context')
)
if keys:
raise ValueError('unknown keyword argument: %s', keys)
try:
self.ssl_ctx = ssl['ssl_context']
assert isinstance(self.ssl_ctx, SSL.Context), self.ssl_ctx
except KeyError:
self.ssl_ctx = SSL.Context()
HTTPConnection.__init__(self, host, port, strict)
def connect(self):
# type: () -> None
error = None
# We ignore the returned sockaddr because SSL.Connection.connect needs
# a host name.
for (family, _, _, _, _) in socket.getaddrinfo(
self.host, self.port, 0, socket.SOCK_STREAM
):
sock = None
try:
sock = SSL.Connection(self.ssl_ctx, family=family)
# set SNI server name since we know it at this point
sock.set_tlsext_host_name(self.host)
if self.session is not None:
sock.set_session(self.session)
sock.connect((self.host, self.port))
self.sock = sock
sock = None
return
except socket.error as e:
# Other exception are probably SSL-related, in that case we
# abort and the exception is forwarded to the caller.
error = e
finally:
if sock is not None:
sock.close()
if error is None:
raise AssertionError("Empty list returned by getaddrinfo")
raise error
def close(self):
# type: () -> None
# This kludges around line 545 of httplib.py,
# which closes the connection in this object;
# the connection remains open in the response
# object.
#
# M2Crypto doesn't close-here-keep-open-there,
# so, in effect, we don't close until the whole
# business is over and gc kicks in.
#
# XXX Long-running callers beware leakage.
#
# XXX 05-Jan-2002: This module works with Python 2.2,
# XXX but I've not investigated if the above conditions
# XXX remain.
pass
def get_session(self):
# type: () -> SSL.Session.Session
return self.sock.get_session()
def set_session(self, session):
# type: (SSL.Session.Session) -> None
self.session = session
class ProxyHTTPSConnection(HTTPSConnection):
"""
An HTTPS Connection that uses a proxy and the CONNECT request.
When the connection is initiated, CONNECT is first sent to the proxy (along
with authorization headers, if supplied). If successful, an SSL connection
will be established over the socket through the proxy and to the target
host.
Finally, the actual request is sent over the SSL connection tunneling
through the proxy.
"""
_ports = {'http': 80, 'https': 443}
_AUTH_HEADER = "Proxy-Authorization"
_UA_HEADER = "User-Agent"
def __init__(
self,
host,
port=None,
strict=None,
username=None,
password=None,
**ssl
):
# type: (str, Optional[int], Optional[bool], Optional[AnyStr], Optional[AnyStr], **Any) -> None
"""
Create the ProxyHTTPSConnection object.
:param host: host name of the proxy server
:param port: port number of the proxy server
:param strict: if switched on, it raises BadStatusLine to be
raised if the status line can't be parsed as
a valid HTTP/1.0 or 1.1 status line.
:param username: username on the proxy server, when required
Username can be ``str``, but preferred type
is ``bytes``. M2Crypto does some conversion to
``bytes`` when necessary, but it's better when
the user of the library does it on its own.
:param password: password on the proxy server, when required
The same as with ``username``, ``str`` is accepted,
but ``bytes`` are preferred.
:param ssl: dict with all remaining named real parameters of the
function. Specifically, ``ssl_context`` is expected
to be included with SSL.Context; if it is not
default ``'sslv23'`` is substituted).
"""
HTTPSConnection.__init__(self, host, port, strict, **ssl)
self._username = username.encode('utf8') \
if isinstance(username, (str,)) else username
self._password = password.encode('utf8') \
if isinstance(password, (str,)) else password
self._proxy_auth = None # type: str
self._proxy_UA = None # type: str
def putrequest(
self, method, url, skip_host=0, skip_accept_encoding=0
):
# type: (AnyStr, AnyStr, int, int) -> None
"""
putrequest is called before connect, so can interpret url and get
real host/port to be used to make CONNECT request to proxy
"""
proto, netloc, path, query, fragment = urlsplit(url)
if not proto:
raise ValueError("unknown URL type: %s" % url)
# get host & port
try:
username_password, host_port = netloc.split('@')
except ValueError:
host_port = netloc
try:
host, port_s = host_port.split(':')
port = int(port_s)
except ValueError:
host = host_port
# try to get port from proto
try:
port = self._ports[proto]
except KeyError:
raise ValueError("unknown protocol for: %s" % url)
self._real_host = host # type: str
self._real_port = port # type: int
rest = urlunsplit(('', '', path, query, fragment))
HTTPSConnection.putrequest(
self, method, rest, skip_host, skip_accept_encoding
)
def putheader(self, header, value):
# type: (AnyStr, AnyStr) -> None
# Store the auth header if passed in.
if header.lower() == self._UA_HEADER.lower():
self._proxy_UA = value
if header.lower() == self._AUTH_HEADER.lower():
self._proxy_auth = value
else:
HTTPSConnection.putheader(self, header, value)
def endheaders(self, *args, **kwargs):
# type: (*Any, **Any) -> None
# We've recieved all of hte headers. Use the supplied username
# and password for authorization, possibly overriding the authstring
# supplied in the headers.
if not self._proxy_auth:
self._proxy_auth = self._encode_auth()
HTTPSConnection.endheaders(self, *args, **kwargs)
def connect(self):
# type: () -> None
HTTPConnection.connect(self)
# send proxy CONNECT request
self.sock.sendall(self._get_connect_msg())
response = HTTPResponse(self.sock)
response.begin()
code = response.status
if code != 200:
# proxy returned and error, abort connection, and raise exception
self.close()
raise socket.error("Proxy connection failed: %d" % code)
self._start_ssl()
def _get_connect_msg(self):
# type: () -> bytes
""" Return an HTTP CONNECT request to send to the proxy. """
msg = "CONNECT %s:%d HTTP/1.1\r\n" % (
self._real_host,
self._real_port,
)
msg = msg + "Host: %s:%d\r\n" % (
self._real_host,
self._real_port,
)
if self._proxy_UA:
msg = msg + "%s: %s\r\n" % (
self._UA_HEADER,
self._proxy_UA,
)
if self._proxy_auth:
msg = msg + "%s: %s\r\n" % (
self._AUTH_HEADER,
self._proxy_auth,
)
msg = msg + "\r\n"
return msg.encode()
def _start_ssl(self):
# type: () -> None
""" Make this connection's socket SSL-aware. """
self.sock = SSL.Connection(self.ssl_ctx, self.sock)
self.sock.setup_ssl()
self.sock.set_connect_state()
self.sock.connect_ssl()
def _encode_auth(self):
# type: () -> Optional[bytes]
""" Encode the username and password for use in the auth header. """
if not (self._username and self._password):
return None
# Authenticated proxy
userpass = "%s:%s" % (self._username, self._password)
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
enc_userpass = base64.encodestring(userpass).replace("\n", "")
return ("Basic %s" % enc_userpass).encode()
m2crypto-0.42.0/src/M2Crypto/m2.py 0000664 0000000 0000000 00000001476 14655756567 0016554 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""M2Crypto low level OpenSSL wrapper functions.
m2 is the low level wrapper for OpenSSL functions. Typically you would not
need to use these directly, since these will be called by the higher level
objects you should try to use instead.
Naming conventions: All functions wrapped by m2 are all lower case,
words separated by underscores.
Examples:
OpenSSL M2Crypto
X509_get_version m2.x509_get_version
X509_get_notBefore m2.x509_get_not_before
X509_REQ_verify m2.x509_req_verify
Exceptions to naming rules:
XXX TDB
Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.
Portions created by Open Source Applications Foundation (OSAF) are
Copyright (C) 2004 OSAF. All Rights Reserved.
"""
from M2Crypto.m2crypto import *
lib_init()
m2crypto-0.42.0/src/M2Crypto/m2.pyi 0000664 0000000 0000000 00000002645 14655756567 0016724 0 ustar 00root root 0000000 0000000 from typing import Optional
from M2Crypto import ASN1, BIO, types as C
def asn1_integer_cmp(a1: C.ASN1_Integer, a2: C.ASN1_Integer) -> int: ...
def asn1_integer_free(a: C.ASN1_Integer) -> None: ...
def asn1_integer_get(a: C.ASN1_Integer) -> Optional[int]: ...
def asn1_integer_set(a: C.ASN1_Integer, v: int) -> int: ...
def asn1_object_free(a: C.ASN1_Object) -> None: ...
def asn1_string_free(a: C.ASN1_String) -> None: ...
def asn1_string_print(out: C.BIO, s: C.ASN1_String) -> int: ...
def asn1_string_print_ex(out: C.BIO, s: C.ASN1_String, flags: int) -> int: ...
def asn1_time_free(a: C.ASN1_TIME) -> None: ...
def asn1_time_new() -> C.ASN1_TIME: ...
def asn1_time_print(out: C.BIO, s: C.ASN1_TIME) -> int: ...
def asn1_time_set(a: C.ASN1_TIME, t: int) -> C.ASN1_TIME: ...
def asn1_time_set_string(a: C.ASN1_TIME, s: str) -> int: ...
def asn1_time_type_check(a: C.ASN1_TIME) -> int: ...
bio_close: int = 0x01
def bio_ctrl_get_write_guarantee(a: C.BIO) -> int: ...
def bio_ctrl_pending(a: C.BIO) -> int: ...
def bio_do_handshake(a: C.BIO) -> int: ...
def bio_f_buffer() -> C.BIO_METHOD: ... # FIXME
def bio_f_cipher() -> C.BIO_METHOD: ... # FIXME
def bio_flush(b: C.BIO) -> int: ...
# See gl#m2crypto/m2crypto#228 and gl#m2crypto/m2cryptor#205
def engine_ctrl_cmd_string(e: Engine.ENGINE, cmd_name: str, arg: str, cmd_optional: int) -> None: ...
def x509_free(a: C.X509) -> None: ...
def x509_new() -> C.X509: ...
m2crypto-0.42.0/src/M2Crypto/m2urllib.py 0000664 0000000 0000000 00000006725 14655756567 0017770 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import, print_function
"""M2Crypto enhancement to Python's urllib for handling
'https' url's.
FIXME: it is questionable whether we need this old-style module at all. urllib
(not urllib2) is in Python 3 support just as a legacy API.
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
import base64
import warnings
from M2Crypto import SSL, httpslib
from urllib.response import addinfourl
from typing import AnyStr, Optional # noqa
from urllib.request import * # noqa for other modules to import
from urllib.parse import * # noqa for other modules to import
from urllib.error import * # noqa for other modules to import
def open_https(self, url, data=None, ssl_context=None):
# type: (URLOpener, AnyStr, Optional[bytes], Optional[SSL.Context]) -> addinfourl
"""
Open URL over the SSL connection.
:param url: URL to be opened
:param data: data for the POST request
:param ssl_context: SSL.Context to be used
:return:
"""
warnings.warn('URLOpener has been deprecated in Py3k', DeprecationWarning)
if ssl_context is not None and isinstance(ssl_context, SSL.Context):
self.ctx = ssl_context
else:
self.ctx = SSL.Context()
user_passwd = None
if isinstance(url, (str,)):
# https://docs.python.org/3/library/urllib.parse.html
parsed = urlparse(url)
host = parsed.hostname
if parsed.port:
host += ":{0}".format(parsed.port)
user_passwd = parsed.password
if parsed.password:
user_passwd += ":{0}".format(parsed.password)
selector = parsed.path
else:
host, selector = url
urltype, rest = splittype(selector)
url = rest
user_passwd = None
if urltype.lower() != 'http':
realhost = None
else:
try: # python 2
realhost, rest = splithost(rest)
if realhost:
user_passwd, realhost = splituser(realhost)
if user_passwd:
selector = "%s://%s%s" % (urltype, realhost, rest)
except NameError: # python 3 has no splithost
parsed = urlparse(rest)
host = parsed.hostname
if parsed.port:
host += ":{0}".format(parsed.port)
user_passwd = parsed.username
if parsed.password:
user_passwd += ":{0}".format(parsed.password)
# print("proxy via http:", host, selector)
if not host:
raise IOError('http error', 'no host given')
if user_passwd:
auth = base64.encodebytes(user_passwd).strip()
else:
auth = None
# Start here!
h = httpslib.HTTPSConnection(host=host, ssl_context=self.ctx)
# h.set_debuglevel(1)
# Stop here!
if data is not None:
h.putrequest('POST', selector)
h.putheader('Content-type', 'application/x-www-form-urlencoded')
h.putheader('Content-length', '%d' % len(data))
else:
h.putrequest('GET', selector)
if auth:
h.putheader('Authorization', 'Basic %s' % auth)
for args in self.addheaders:
h.putheader(*args) # for python3 - used to use apply
h.endheaders()
if data is not None:
h.send(data + '\r\n')
# Here again!
resp = h.getresponse()
fp = resp.fp
return addinfourl(fp, resp.msg, "https:" + url)
# Stop again.
# Minor brain surgery.
URLopener.open_https = open_https
m2crypto-0.42.0/src/M2Crypto/m2urllib2.py 0000664 0000000 0000000 00000013745 14655756567 0020052 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""
M2Crypto enhancement to Python's urllib2 for handling
'https' url's.
Code from urllib2 is Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007
Python Software Foundation; All Rights Reserved
Summary of changes:
- Use an HTTPSProxyConnection if the request is going through a proxy.
- Add the SSL context to the https connection when performing https_open.
- Add the M2Crypto HTTPSHandler when building a default opener.
"""
import socket
from M2Crypto import SSL, httpslib
from urllib.parse import urldefrag, urlparse as url_parse
from urllib.response import addinfourl
from typing import Optional # noqa
from urllib.request import * # noqa other modules want to import
from urllib.error import * # noqa other modules want to import
try:
mother_class = socket._fileobject
except AttributeError:
mother_class = socket.SocketIO
class _closing_fileobject(mother_class): # noqa
"""socket._fileobject that propagates self.close() to the socket.
Python 2.5 provides this as socket._fileobject(sock, close=True).
"""
# for python 3
try:
AbstractHTTPHandler
except NameError:
# somehow this won't get imported by the import * above
import urllib.request
AbstractHTTPHandler = urllib.request.AbstractHTTPHandler
class HTTPSHandler(AbstractHTTPHandler):
def __init__(self, ssl_context=None):
# type: (Optional[SSL.Context]) -> None
AbstractHTTPHandler.__init__(self)
if ssl_context is not None:
assert isinstance(ssl_context, SSL.Context), ssl_context
self.ctx = ssl_context
else:
self.ctx = SSL.Context()
# Copied from urllib2, so we can set the ssl context.
def https_open(self, req):
# type: (Request) -> addinfourl
"""Return an addinfourl object for the request, using http_class.
http_class must implement the HTTPConnection API from httplib.
The addinfourl return value is a file-like object. It also
has methods and attributes including:
- info(): return a mimetools.Message object for the headers
- geturl(): return the original request URL
- code: HTTP status code
"""
# https://docs.python.org/3.3/library/urllib.request.html#urllib.request.Request.get_host
try: # up to python-3.2
host = req.get_host()
except AttributeError: # from python-3.3
host = req.host
if not host:
raise URLError('no host given')
# Our change: Check to see if we're using a proxy.
# Then create an appropriate ssl-aware connection.
full_url = req.get_full_url()
target_host = url_parse(full_url)[1]
if target_host != host:
request_uri = urldefrag(full_url)[0]
h = httpslib.ProxyHTTPSConnection(host=host, ssl_context=self.ctx)
else:
try: # up to python-3.2
request_uri = req.get_selector()
except AttributeError: # from python-3.3
request_uri = req.selector
h = httpslib.HTTPSConnection(host=host, ssl_context=self.ctx)
# End our change
h.set_debuglevel(self._debuglevel)
headers = dict(req.headers)
headers.update(req.unredirected_hdrs)
# We want to make an HTTP/1.1 request, but the addinfourl
# class isn't prepared to deal with a persistent connection.
# It will try to read all remaining data from the socket,
# which will block while the server waits for the next request.
# So make sure the connection gets closed after the (only)
# request.
headers["Connection"] = "close"
try:
h.request(req.get_method(), request_uri, req.data, headers)
r = h.getresponse()
except socket.error as err: # XXX what error?
raise URLError(err)
# Pick apart the HTTPResponse object to get the addinfourl
# object initialized properly.
# Wrap the HTTPResponse object in socket's file object adapter
# for Windows. That adapter calls recv(), so delegate recv()
# to read(). This weird wrapping allows the returned object to
# have readline() and readlines() methods.
r.recv = r.read
r._decref_socketios = lambda: None
r.ssl = h.sock.ssl
r._timeout = -1.0
r.recv_into = r.readinto
fp = socket.SocketIO(r, 'rb')
resp = addinfourl(fp, r.msg, req.get_full_url())
resp.code = r.status
resp.msg = r.reason
return resp
https_request = AbstractHTTPHandler.do_request_
# Copied from urllib2 with modifications for ssl
def build_opener(ssl_context=None, *handlers):
# type: (Optional[SSL.Context], *object) -> OpenerDirector
"""Create an opener object from a list of handlers.
The opener will use several default handlers, including support
for HTTP and FTP.
If any of the handlers passed as arguments are subclasses of the
default handlers, the default handlers will not be used.
"""
def isclass(obj):
return isinstance(obj, type) or hasattr(obj, "__bases__")
opener = OpenerDirector()
default_classes = [ProxyHandler, UnknownHandler, HTTPHandler,
HTTPDefaultErrorHandler, HTTPRedirectHandler,
FTPHandler, FileHandler, HTTPErrorProcessor]
skip = []
for klass in default_classes:
for check in handlers:
if isclass(check):
if issubclass(check, klass):
skip.append(klass)
elif isinstance(check, klass):
skip.append(klass)
for klass in skip:
default_classes.remove(klass)
for klass in default_classes:
opener.add_handler(klass())
# Add the HTTPS handler with ssl_context
if HTTPSHandler not in skip:
opener.add_handler(HTTPSHandler(ssl_context))
for h in handlers:
if isclass(h):
h = h()
opener.add_handler(h)
return opener
m2crypto-0.42.0/src/M2Crypto/m2xmlrpclib.py 0000664 0000000 0000000 00000004345 14655756567 0020467 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""M2Crypto enhancement to xmlrpclib.
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
import base64
from M2Crypto import __version__ as __M2Version
from M2Crypto import SSL, httpslib, m2urllib
from typing import Any, AnyStr, Callable, Optional # noqa
from xmlrpc.client import ProtocolError, Transport
from xmlrpc.client import * # noqa
__version__ = __M2Version
class SSL_Transport(Transport):
user_agent = "M2Crypto_XMLRPC/%s - %s" % (__version__,
Transport.user_agent)
def __init__(self, ssl_context=None, *args, **kw):
# type: (Optional[SSL.Context], *Any, **Any) -> None
Transport.__init__(self, *args, **kw)
if ssl_context is None:
self.ssl_ctx = SSL.Context()
else:
self.ssl_ctx = ssl_context
def request(self, host, handler, request_body, verbose=0):
# type: (AnyStr, Callable, bytes, int) -> object
# Handle username and password.
user_passwd, host_port = m2urllib.splituser(host)
_host, _port = m2urllib.splitport(host_port)
h = httpslib.HTTPSConnection(_host, int(_port),
ssl_context=self.ssl_ctx)
if verbose:
h.set_debuglevel(1)
# What follows is as in xmlrpclib.Transport. (Except the authz bit.)
h.putrequest("POST", handler)
# required by HTTP/1.1
h.putheader("Host", _host)
# required by XML-RPC
h.putheader("User-Agent", self.user_agent)
h.putheader("Content-Type", "text/xml")
h.putheader("Content-Length", str(len(request_body)))
# Authorisation.
if user_passwd is not None:
auth = base64.encodestring(user_passwd).strip()
h.putheader('Authorization', 'Basic %s' % auth)
h.endheaders()
if request_body:
h.send(request_body)
response = h.getresponse()
if response.status != 200:
raise ProtocolError(
host + handler,
response.status, response.reason,
response.getheaders()
)
self.verbose = verbose
return self.parse_response(response)
m2crypto-0.42.0/src/M2Crypto/threading.py 0000664 0000000 0000000 00000000677 14655756567 0020205 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import
"""
M2Crypto threading support, required for multithreaded applications.
Copyright (c) 1999-2003 Ng Pheng Siong. All rights reserved."""
# M2Crypto
from M2Crypto import m2
def init():
# type: () -> None
"""
Initialize threading support.
"""
m2.threading_init()
def cleanup():
# type: () -> None
"""
End and cleanup threading support.
"""
m2.threading_cleanup()
m2crypto-0.42.0/src/M2Crypto/types.py 0000664 0000000 0000000 00000000564 14655756567 0017377 0 ustar 00root root 0000000 0000000 from typing import NewType
BIO = NewType('BIO', bytes)
BIO_METHOD = NewType('BIO_METHOD', bytes)
ASN1_Object = NewType('ASN1_Object', bytes)
ASN1_String = NewType('ASN1_String', bytes)
ASN1_Integer = NewType('ASN1_Integer', int)
ASN1_Time = NewType('ASN1_Time', bytes)
Engine = NewType('Engine', bytes)
X509 = NewType('X509', bytes)
X509_CRL = NewType('X509_CRL', bytes)
m2crypto-0.42.0/src/M2Crypto/util.py 0000664 0000000 0000000 00000005160 14655756567 0017205 0 ustar 00root root 0000000 0000000 from __future__ import absolute_import, print_function
"""
M2Crypto utility routines.
NOTHING IN THIS MODULE IS GUARANTEED TO BE STABLE, USED ONLY FOR
INTERNAL PURPOSES OF M2CRYPTO.
Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.
Portions created by Open Source Applications Foundation (OSAF) are
Copyright (C) 2004 OSAF. All Rights Reserved.
"""
import binascii
import logging
import platform
import struct
import sys
import struct
import unittest
from M2Crypto import m2
from typing import Any, Optional, TextIO, Tuple, Union # noqa
# see https://github.com/python/typeshed/issues/222
AddrType = Union[Tuple[str, int], str]
log = logging.getLogger('util')
class UtilError(Exception):
pass
m2.util_init(UtilError)
def is_libc_musl():
# This is wrong, but unfortunately Python doesn't give us anything better
# gh#python/cpython#87414
return platform.libc_ver() == ("", "")
def is_32bit():
# type: () -> bool
# or alternatively (slightly slower)
# (struct.calcsize("P") * 8) == 32
return not(sys.maxsize > 2**32)
def expectedFailureIf(condition):
"""The test is marked as an expectedFailure if the condition is satisfied."""
def wrapper(func):
if condition:
return unittest.expectedFailure(func)
else:
return func
return wrapper
def pkcs5_pad(data, blklen=8):
# type: (str, int) -> str
pad = (8 - (len(data) % 8))
return data + chr(pad) * pad
def pkcs7_pad(data, blklen):
# type: (str, int) -> str
if blklen > 255:
raise ValueError('illegal block size')
pad = (blklen - (len(data) % blklen))
return data + chr(pad) * pad
def bin_to_hex(b):
# type: (bytes) -> str
return binascii.b2a_base64(b)[:-1].decode()
def octx_to_num(x):
# type: (bytes) -> int
return int(binascii.hexlify(x), 16)
def genparam_callback(p, n, out=sys.stdout):
# type: (int, Any, TextIO) -> None
ch = ['.', '+', '*', '\n']
out.write(ch[p])
out.flush()
def quiet_genparam_callback(p, n, out):
# type: (Any, Any, Any) -> None
pass
def passphrase_callback(v, prompt1='Enter passphrase:',
prompt2='Verify passphrase:'):
# type: (bool, str, str) -> Optional[str]
from getpass import getpass
while 1:
try:
p1 = getpass(prompt1)
if v:
p2 = getpass(prompt2)
if p1 == p2:
break
else:
break
except KeyboardInterrupt:
return None
return p1
def no_passphrase_callback(*args):
# type: (*Any) -> str
return ''
m2crypto-0.42.0/src/SWIG/ 0000775 0000000 0000000 00000000000 14655756567 0014746 5 ustar 00root root 0000000 0000000 m2crypto-0.42.0/src/SWIG/Makefile 0000664 0000000 0000000 00000001163 14655756567 0016407 0 ustar 00root root 0000000 0000000 # $Id$
CFLAGS = -DTHREADING -g
INCLUDE = -I/usr/local/include -I.
LIBS = -L/usr/local/lib -lssl -lcrypto
#if PYTHON_VERSION
PYVER = $(PYTHON_VERSION)
#else
PYVER = 2.3
#endif
PYINCLUDE = -DHAVE_CONFIG_H -I/usr/local/include/python$(PYVER) \
-I/usr/local/lib/python$(PYVER)/config
PYLIB = /usr/local/lib/python$(PYVER)/config
all: _m2crypto
_m2crypto: _m2crypto.i
swig -python -shadow _m2crypto.i
cc -c -fpic $(CFLAGS) $(INCLUDE) $(PYINCLUDE) _m2crypto_wrap.c
ld -Bshareable -o _m2crypto.so _m2crypto_wrap.o $(LIBS)
cp m2crypto.py _m2crypto.so ../M2Crypto
clean:
rm -f *_wrap* *.o *.so _*.py *.pyc
m2crypto-0.42.0/src/SWIG/_aes.i 0000664 0000000 0000000 00000004142 14655756567 0016030 0 ustar 00root root 0000000 0000000 /* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. */
/* $Id$ */
%{
#include
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#include
#endif
/*
// 2004-10-10, ngps:
// CTR mode is not included in the default OpenSSL build.
// To use the AES CTR ciphers, link with your own copy of OpenSSL.
*/
#ifdef HAVE_AES_CTR
extern EVP_CIPHER const *EVP_aes_128_ctr(void);
extern EVP_CIPHER const *EVP_aes_192_ctr(void);
extern EVP_CIPHER const *EVP_aes_256_ctr(void);
#endif
%}
%apply Pointer NONNULL { AES_KEY * };
%constant int AES_BLOCK_SIZE = AES_BLOCK_SIZE;
%inline %{
AES_KEY *aes_new(void) {
AES_KEY *key;
if (!(key = (AES_KEY *)PyMem_Malloc(sizeof(AES_KEY)))) {
PyErr_SetString(PyExc_MemoryError,
"Insufficient memory for AES key.");
return NULL;
}
return key;
}
void AES_free(AES_KEY *key) {
PyMem_Free((void *)key);
}
/*
// op == 0: encrypt
// otherwise: decrypt (Python code will supply the value 1.)
*/
PyObject *AES_set_key(AES_KEY *key, PyObject *value, int bits, int op) {
char *vbuf;
Py_ssize_t vlen;
if (PyBytes_AsStringAndSize(value, &vbuf, &vlen) == -1)
return NULL;
if (op == 0)
AES_set_encrypt_key((const unsigned char *)vbuf, bits, key);
else
AES_set_decrypt_key((const unsigned char *)vbuf, bits, key);
Py_RETURN_NONE;
}
/*
// op == 0: encrypt
// otherwise: decrypt (Python code will supply the value 1.)
*/
PyObject *AES_crypt(const AES_KEY *key, PyObject *in, int outlen, int op) {
char *buf;
Py_ssize_t len;
unsigned char *out;
PyObject *res;
if (PyBytes_AsStringAndSize(in, &buf, &len) == -1)
return NULL;
if (!(out=(unsigned char *)PyMem_Malloc(outlen))) {
PyErr_SetString(PyExc_MemoryError, "AES_crypt");
return NULL;
}
if (op == 0)
AES_encrypt((const unsigned char *)buf, out, key);
else
AES_decrypt((const unsigned char *)buf, out, key);
res = PyBytes_FromStringAndSize((char*)out, outlen);
PyMem_Free(out);
return res;
}
int AES_type_check(AES_KEY *key) {
return 1;
}
%}
m2crypto-0.42.0/src/SWIG/_asn1.i 0000664 0000000 0000000 00000014245 14655756567 0016127 0 ustar 00root root 0000000 0000000 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. */
/*
** Portions created by Open Source Applications Foundation (OSAF) are
** Copyright (C) 2004 OSAF. All Rights Reserved.
*/
/* $Id$ */
%{
#include
#include
%}
%apply Pointer NONNULL { BIO * };
%apply Pointer NONNULL { ASN1_OBJECT * };
%apply Pointer NONNULL { ASN1_STRING * };
%apply Pointer NONNULL { ASN1_INTEGER * };
%apply Pointer NONNULL { ASN1_TIME * };
%rename(asn1_object_new) ASN1_OBJECT_new;
extern ASN1_OBJECT *ASN1_OBJECT_new( void );
%rename(asn1_object_create) ASN1_OBJECT_create;
extern ASN1_OBJECT *ASN1_OBJECT_create( int, unsigned char *, int, const char *, const char *);
%rename(asn1_object_free) ASN1_OBJECT_free;
extern void ASN1_OBJECT_free( ASN1_OBJECT *);
%rename(i2d_asn1_object) i2d_ASN1_OBJECT;
extern int i2d_ASN1_OBJECT( ASN1_OBJECT *, unsigned char **);
%rename(d2i_asn1_object) d2i_ASN1_OBJECT;
extern ASN1_OBJECT *d2i_ASN1_OBJECT( ASN1_OBJECT **, const unsigned char **, long);
%rename(asn1_bit_string_new) ASN1_BIT_STRING_new;
extern ASN1_BIT_STRING *ASN1_BIT_STRING_new( void );
%rename(asn1_string_new) ASN1_STRING_new;
extern ASN1_STRING *ASN1_STRING_new( void );
%rename(asn1_string_free) ASN1_STRING_free;
extern void ASN1_STRING_free( ASN1_STRING *);
%typemap(in) (const void *, int) {
if (PyBytes_Check($input)) {
Py_ssize_t len;
$1 = PyBytes_AsString($input);
len = PyBytes_Size($input);
if (len > INT_MAX) {
PyErr_SetString(PyExc_ValueError, "object too large");
return NULL;
}
$2 = len;
}
else {
PyErr_SetString(PyExc_TypeError, "expected string");
return NULL;
}
}
%rename(asn1_string_set) ASN1_STRING_set;
extern int ASN1_STRING_set( ASN1_STRING *, const void *, int);
%typemap(in) (const void *, int);
%rename(asn1_string_print) ASN1_STRING_print;
%threadallow ASN1_STRING_print;
extern int ASN1_STRING_print(BIO *, ASN1_STRING *);
%threadallow ASN1_STRING_print_ex;
%rename(asn1_string_print_ex) ASN1_STRING_print_ex;
extern int ASN1_STRING_print_ex(BIO *, ASN1_STRING *, unsigned long);
%rename(asn1_time_new) ASN1_TIME_new;
extern ASN1_TIME *ASN1_TIME_new( void );
%rename(asn1_time_free) ASN1_TIME_free;
extern void ASN1_TIME_free(ASN1_TIME *);
%rename(asn1_time_check) ASN1_TIME_check;
extern int ASN1_TIME_check(ASN1_TIME *);
%rename(asn1_time_set_string) ASN1_TIME_set_string;
extern int ASN1_TIME_set_string(ASN1_TIME *, const char *);
%rename(asn1_time_print) ASN1_TIME_print;
%threadallow ASN1_TIME_print;
extern int ASN1_TIME_print(BIO *, ASN1_TIME *);
%rename(asn1_integer_new) ASN1_INTEGER_new;
extern ASN1_INTEGER *ASN1_INTEGER_new( void );
%rename(asn1_integer_free) ASN1_INTEGER_free;
extern void ASN1_INTEGER_free( ASN1_INTEGER *);
%rename(asn1_integer_cmp) ASN1_INTEGER_cmp;
extern int ASN1_INTEGER_cmp(ASN1_INTEGER *, ASN1_INTEGER *);
%constant int ASN1_STRFLGS_ESC_2253 = 1;
%constant int ASN1_STRFLGS_ESC_CTRL = 2;
%constant int ASN1_STRFLGS_ESC_MSB = 4;
%constant int ASN1_STRFLGS_ESC_QUOTE = 8;
%constant int ASN1_STRFLGS_UTF8_CONVERT = 0x10;
%constant int ASN1_STRFLGS_IGNORE_TYPE = 0x20;
%constant int ASN1_STRFLGS_SHOW_TYPE = 0x40;
%constant int ASN1_STRFLGS_DUMP_ALL = 0x80;
%constant int ASN1_STRFLGS_DUMP_UNKNOWN = 0x100;
%constant int ASN1_STRFLGS_DUMP_DER = 0x200;
%constant int ASN1_STRFLGS_RFC2253 = (ASN1_STRFLGS_ESC_2253 | \
ASN1_STRFLGS_ESC_CTRL | \
ASN1_STRFLGS_ESC_MSB | \
ASN1_STRFLGS_UTF8_CONVERT | \
ASN1_STRFLGS_DUMP_UNKNOWN | \
ASN1_STRFLGS_DUMP_DER);
%inline %{
/* ASN1_TIME_set_string () is a macro */
int asn1_time_type_check(ASN1_TIME *ASN1_TIME) {
return 1;
}
ASN1_TIME* asn1_time_set(ASN1_TIME *asn1_time, PyObject *time) {
long long val;
if ((val = PyLong_AsLongLong(time)) >= 0) {
ERR_clear_error();
asn1_time = ASN1_TIME_adj(asn1_time, (time_t)0,
(int)(val / 86400LL),
(long) (val % 86400LL));
return asn1_time;
} else {
char *errstr = PyMem_Malloc(256);
snprintf(errstr, 256, "Error in conversion of PyLong to long (val = %lld)", val);
PyErr_SetString(PyExc_OverflowError, errstr);
PyMem_Free(errstr);
return NULL;
}
}
PyObject *asn1_integer_get(ASN1_INTEGER *asn1) {
BIGNUM *bn;
PyObject *ret;
char *hex;
bn = ASN1_INTEGER_to_BN(asn1, NULL);
if (!bn){
m2_PyErr_Msg(PyExc_RuntimeError);
return NULL;
}
hex = BN_bn2hex(bn);
if (!hex){
m2_PyErr_Msg(PyExc_RuntimeError);
BN_free(bn);
return NULL;
}
BN_free(bn);
ret = PyLong_FromString(hex, NULL, 16);
OPENSSL_free(hex);
return ret;
}
int asn1_integer_set(ASN1_INTEGER *asn1, PyObject *value) {
BIGNUM *bn = NULL;
PyObject *fmt, *args, *hex;
/* Despite all hopes to the contrary, we cannot survive here with
* PyLong_AsLong shims as provided in
* /usr/include/python2.7/longobject.h.
*/
long val = PyLong_AsLong(value);
if (val >= 0) {
return ASN1_INTEGER_set(asn1, val);
} else {
PyErr_Clear();
}
if (!PyLong_Check(value)){
PyErr_SetString(PyExc_TypeError, "expected int or long");
return 0;
}
fmt = PyUnicode_FromString("%x");
if (!fmt)
return 0;
args = PyTuple_New(1);
if (!args){
Py_DECREF(fmt);
PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() failed");
return 0;
}
Py_INCREF(value);
PyTuple_SET_ITEM(args, 0, value);
hex = PyUnicode_Format(fmt, args);
if (!hex){
PyErr_SetString(PyExc_RuntimeError, "PyString_Format() failed");
Py_DECREF(fmt);
Py_DECREF(args);
return 0;
}
Py_DECREF(fmt);
Py_DECREF(args);
if (BN_hex2bn(&bn, PyUnicode_AsUTF8(hex)) <= 0){
m2_PyErr_Msg(PyExc_RuntimeError);
Py_DECREF(hex);
return 0;
}
Py_DECREF(hex);
if (!BN_to_ASN1_INTEGER(bn, asn1)){
m2_PyErr_Msg(PyExc_RuntimeError);
BN_free(bn);
return 0;
}
BN_free(bn);
return 1;
}
%}
m2crypto-0.42.0/src/SWIG/_bio.i 0000664 0000000 0000000 00000031516 14655756567 0016036 0 ustar 00root root 0000000 0000000 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright (c) 1999 Ng Pheng Siong. All rights reserved.
*
* Portions created by Open Source Applications Foundation (OSAF) are
* Copyright (C) 2004-2005 OSAF. All Rights Reserved.
* Author: Heikki Toivonen
*
* Copyright 2018 Daniel Wozniak. All Rights Reserved.*/
/* $Id$ */
%{
#include
%}
%apply Pointer NONNULL { BIO * };
%apply Pointer NONNULL { BIO_METHOD * };
%rename(bio_s_bio) BIO_s_bio;
extern BIO_METHOD *BIO_s_bio(void);
%rename(bio_s_mem) BIO_s_mem;
extern BIO_METHOD *BIO_s_mem(void);
%rename(bio_s_socket) BIO_s_socket;
extern BIO_METHOD *BIO_s_socket(void);
%rename(bio_f_ssl) BIO_f_ssl;
extern BIO_METHOD *BIO_f_ssl(void);
%rename(bio_f_buffer) BIO_f_buffer;
extern BIO_METHOD *BIO_f_buffer(void);
%rename(bio_f_cipher) BIO_f_cipher;
extern BIO_METHOD *BIO_f_cipher(void);
%rename(bio_new) BIO_new;
extern BIO *BIO_new(BIO_METHOD *);
%rename(bio_new_socket) BIO_new_socket;
extern BIO *BIO_new_socket(int, int);
%rename(bio_new_fd) BIO_new_pyfd;
%rename(bio_new_pyfd) BIO_new_pyfd;
%rename(bio_free_all) BIO_free_all;
%threadallow BIO_free_all;
extern void BIO_free_all(BIO *);
%rename(bio_dup_chain) BIO_dup_chain;
extern BIO *BIO_dup_chain(BIO *);
%rename(bio_push) BIO_push;
extern BIO *BIO_push(BIO *, BIO *);
%rename(bio_pop) BIO_pop;
extern BIO *BIO_pop(BIO *);
%rename(bio_eof) BIO_eof;
extern int BIO_eof(BIO *);
%constant int bio_noclose = BIO_NOCLOSE;
%constant int bio_close = BIO_CLOSE;
%constant int BIO_FLAGS_READ = 0x01;
%constant int BIO_FLAGS_WRITE = 0x02;
%constant int BIO_FLAGS_IO_SPECIAL = 0x04;
%constant int BIO_FLAGS_RWS = (BIO_FLAGS_READ|BIO_FLAGS_WRITE|BIO_FLAGS_IO_SPECIAL);
%constant int BIO_FLAGS_SHOULD_RETRY = 0x08;
%constant int BIO_FLAGS_MEM_RDONLY = 0x200;
%warnfilter(454) _bio_err;
%inline %{
static PyObject *_bio_err;
void pyfd_init(void);
void bio_init(PyObject *bio_err) {
Py_INCREF(bio_err);
_bio_err = bio_err;
pyfd_init();
}
int bio_free(BIO *bio) {
int ret;
Py_BEGIN_ALLOW_THREADS
ret = BIO_free(bio);
Py_END_ALLOW_THREADS
if (ret == 0) {
m2_PyErr_Msg(_bio_err);
}
return ret;
}
BIO * bio_new_file(const char *filename, const char *mode) {
BIO *ret;
Py_BEGIN_ALLOW_THREADS
ret = BIO_new_file(filename, mode);
Py_END_ALLOW_THREADS
if (ret == NULL) {
m2_PyErr_Msg(_bio_err);
}
return ret;
}
BIO *bio_new_pyfile(PyObject *pyfile, int bio_close) {
FILE *fp = NULL;
BIO *bio = NULL;
fp = PyFile_AsFile(pyfile);
bio = BIO_new_fp(fp, bio_close);
/* returns NULL if error occurred */
if (bio == NULL) {
/* Find out the name of the file so we can have good error
* message. */
PyObject *pyname = m2_PyFile_Name(pyfile);
char *name = PyBytes_AsString(pyname);
if (name == NULL) {
PyErr_Format(_bio_err,
"Opening of the new BIO on file failed!");
}
else {
PyErr_Format(_bio_err,
"Opening of the new BIO on file %s failed!", name);
}
Py_DECREF(pyname);
}
return bio;
}
PyObject *bio_read(BIO *bio, int num) {
PyObject *blob;
void *buf;
int r;
if (!(buf = PyMem_Malloc(num))) {
PyErr_SetString(PyExc_MemoryError, "bio_read");
return NULL;
}
Py_BEGIN_ALLOW_THREADS
r = BIO_read(bio, buf, num);
Py_END_ALLOW_THREADS
if (r < 0) {
PyMem_Free(buf);
if (ERR_peek_error()) {
m2_PyErr_Msg(_bio_err);
return NULL;
}
Py_RETURN_NONE;
}
blob = PyBytes_FromStringAndSize(buf, r);
PyMem_Free(buf);
return blob;
}
PyObject *bio_gets(BIO *bio, int num) {
PyObject *blob;
void *buf;
int r;
if (!(buf = PyMem_Malloc(num))) {
PyErr_SetString(PyExc_MemoryError, "bio_gets");
return NULL;
}
Py_BEGIN_ALLOW_THREADS
r = BIO_gets(bio, buf, num);
Py_END_ALLOW_THREADS
if (r < 1) {
PyMem_Free(buf);
if (ERR_peek_error()) {
m2_PyErr_Msg(_bio_err);
return NULL;
}
Py_RETURN_NONE;
}
blob = PyBytes_FromStringAndSize(buf, r);
PyMem_Free(buf);
return blob;
}
int bio_write(BIO *bio, PyObject *from) {
const void *fbuf;
int flen = 0, ret;
if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1)
return -1;
Py_BEGIN_ALLOW_THREADS
ret = BIO_write(bio, fbuf, flen);
Py_END_ALLOW_THREADS
if (ret < 0) {
if (ERR_peek_error()) {
m2_PyErr_Msg(_bio_err);
return -1;
}
}
return ret;
}
/* XXX Casting size_t to int. */
int bio_ctrl_pending(BIO *bio) {
return (int)BIO_ctrl_pending(bio);
}
int bio_ctrl_wpending(BIO *bio) {
return (int)BIO_ctrl_wpending(bio);
}
int bio_ctrl_get_write_guarantee(BIO *a) {
return BIO_ctrl_get_write_guarantee(a);
}
int bio_reset(BIO *bio) {
return (int)BIO_reset(bio);
}
%}
%threadallow bio_flush;
%inline %{
int bio_flush(BIO *bio) {
return (int)BIO_flush(bio);
}
int bio_seek(BIO *bio, int offset) {
return (int)BIO_seek(bio, offset);
}
int bio_tell(BIO* bio) {
return BIO_tell(bio);
}
void bio_set_flags(BIO *bio, int flags) {
BIO_set_flags(bio, flags);
}
int bio_get_flags(BIO *bio) {
return BIO_get_flags(bio);
}
/*
* sets the cipher of BIO @param b to c using key @param key and IV @iv.
* @param enc should be set to 1 for encryption and zero to decryption.
*
* @return
*
*/
PyObject *bio_set_cipher(BIO *b, EVP_CIPHER *c, PyObject *key, PyObject *iv, int op) {
const void *kbuf, *ibuf;
Py_ssize_t klen, ilen;
if ((m2_PyObject_AsReadBuffer(key, &kbuf, &klen) == -1)
|| (m2_PyObject_AsReadBuffer(iv, &ibuf, &ilen) == -1)) {
PyErr_SetString(PyExc_ValueError, "Reading of key or IV from buffer failed.");
return NULL;
}
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
if (!BIO_set_cipher(b, (const EVP_CIPHER *)c,
(unsigned char *)kbuf, (unsigned char *)ibuf, op)) {
PyErr_SetString(PyExc_OSError, "Setting of cipher failed.");
return NULL;
}
#else
// https://www.openssl.org/docs/man1.0.2/man3/BIO_set_cipher.html
// BIO_set_cipher in OpenSSL < 3.0 doesn't return any value (error or otherwise).
BIO_set_cipher(b, (const EVP_CIPHER *)c,
(unsigned char *)kbuf, (unsigned char *)ibuf, op);
#endif
Py_RETURN_NONE;
}
int bio_set_mem_eof_return(BIO *b, int v) {
return (int)BIO_set_mem_eof_return(b, v);
}
int bio_get_fd(BIO *bio) {
return BIO_get_fd(bio, NULL);
}
%}
%warnfilter(454) methods_fdp;
%threadallow bio_do_handshake;
%inline %{
int bio_do_handshake(BIO *bio) {
return BIO_do_handshake(bio);
}
/* macro */
int bio_make_bio_pair(BIO* b1, BIO* b2) {
return BIO_make_bio_pair(b1, b2);
}
int bio_set_write_buf_size(BIO* b, size_t size) {
return BIO_set_write_buf_size(b, size);
}
int bio_should_retry(BIO* a) {
return BIO_should_retry(a);
}
int bio_should_read(BIO* a) {
return BIO_should_read(a);
}
int bio_should_write(BIO* a) {
return BIO_should_write(a);
}
/* Macros for things not defined before 1.1.0 */
#if OPENSSL_VERSION_NUMBER < 0x10100000L
static BIO_METHOD *
BIO_meth_new( int type, const char *name )
{
BIO_METHOD *method = malloc( sizeof(BIO_METHOD) );
memset( method, 0, sizeof(BIO_METHOD) );
method->type = type;
method->name = name;
return method;
}
static void
BIO_meth_free( BIO_METHOD *meth )
{
if ( meth == NULL ) {
return;
}
free(meth);
}
#define BIO_meth_set_write(m, f) (m)->bwrite = (f)
#define BIO_meth_set_read(m, f) (m)->bread = (f)
#define BIO_meth_set_puts(m, f) (m)->bputs = (f)
#define BIO_meth_set_gets(m, f) (m)->bgets = (f)
#define BIO_meth_set_ctrl(m, f) (m)->ctrl = (f)
#define BIO_meth_set_create(m, f) (m)->create = (f)
#define BIO_meth_set_destroy(m, f) (m)->destroy = (f)
#define BIO_set_shutdown(b, x) (b)->shutdown = x
#define BIO_get_shutdown(b) (b)->shutdown
#define BIO_set_init(b, x) b->init = x
#define BIO_get_init(b) (b)->init
#define BIO_set_data(b, x) b->ptr = x
#define BIO_clear_flags(b, x) b->flags &= ~(x)
#define BIO_get_data(b) b->ptr
#endif
/* implment custom BIO_s_pyfd */
#ifdef _WIN32
# define clear_sys_error() SetLastError(0)
/* Linux doesn't use underscored calls yet */
# define open(p, f, m) _open(p, f, m)
# define read(f, b, n) _read(f, b, n)
# define write(f, b, n) _write(f, b, n)
# define close(f) _close(f)
# define lseek(fd, o, w) _lseek(fd, o, w)
#else
# define clear_sys_error() errno=0
#endif
typedef struct pyfd_struct {
int fd;
} BIO_PYFD_CTX;
/* Setting up methods_fdp */
static BIO_METHOD *methods_fdp;
static int pyfd_write(BIO *b, const char *in, int inl) {
int ret, fd;
if (BIO_get_fd(b, &fd) == -1) {
PyErr_SetString(_bio_err, "BIO has not been initialized.");
return -1;
}
clear_sys_error();
ret = write(fd, in, inl);
BIO_clear_retry_flags(b);
if (ret <= 0) {
if (BIO_fd_should_retry(ret))
BIO_set_retry_write(b);
}
return ret;
}
static int pyfd_read(BIO *b, char *out, int outl) {
int ret = 0, fd;
if (BIO_get_fd(b, &fd) == -1) {
PyErr_SetString(_bio_err, "BIO has not been initialized.");
return -1;
}
if (out != NULL) {
clear_sys_error();
ret = read(fd, out, outl);
BIO_clear_retry_flags(b);
if (ret <= 0) {
if (BIO_fd_should_retry(ret))
BIO_set_retry_read(b);
}
}
return ret;
}
static int pyfd_puts(BIO *bp, const char *str) {
int n, ret;
n = strlen(str);
ret = pyfd_write(bp, str, n);
return ret;
}
static int pyfd_gets(BIO *bp, char *buf, int size) {
int ret = 0;
char *ptr = buf;
char *end = buf + size - 1;
/* See
https://github.com/openssl/openssl/pull/3442
We were here just repeating a bug from OpenSSL
*/
while (ptr < end && pyfd_read(bp, ptr, 1) > 0) {
if (*ptr++ == '\n')
break;
}
ptr[0] = '\0';
if (buf[0] != '\0')
ret = strlen(buf);
return ret;
}
static int pyfd_new(BIO* b) {
BIO_PYFD_CTX* ctx;
ctx = OPENSSL_zalloc(sizeof(*ctx));
if (ctx == NULL)
return 0;
ctx->fd = -1;
BIO_set_data(b, ctx);
BIO_set_shutdown(b, 0);
BIO_set_init(b, 1);
return 1;
}
static int pyfd_free(BIO* b) {
BIO_PYFD_CTX* ctx;
if (b == 0)
return 0;
ctx = BIO_get_data(b);
if (ctx == NULL)
return 0;
if (BIO_get_shutdown(b) && BIO_get_init(b))
close(ctx->fd);
BIO_set_data(b, NULL);
BIO_set_shutdown(b, 0);
BIO_set_init(b, 0);
OPENSSL_free(ctx);
return 1;
}
static long pyfd_ctrl(BIO *b, int cmd, long num, void *ptr) {
BIO_PYFD_CTX* ctx;
int *ip;
long ret = 1;
ctx = BIO_get_data(b);
if (ctx == NULL)
return 0;
switch (cmd) {
case BIO_CTRL_RESET:
num = 0;
case BIO_C_FILE_SEEK:
ret = (long)lseek(ctx->fd, num, 0);
break;
case BIO_C_FILE_TELL:
case BIO_CTRL_INFO:
ret = (long)lseek(ctx->fd, 0, 1);
break;
case BIO_C_SET_FD:
pyfd_free(b);
if (*((int *)ptr) > -1) {
if (!pyfd_new(b) || !(ctx = BIO_get_data(b)))
return 0;
ctx->fd = *((int *)ptr);
BIO_set_shutdown(b, (int)num);
BIO_set_init(b, 1);
}
break;
case BIO_C_GET_FD:
if (BIO_get_init(b)) {
ip = (int *)ptr;
if (ip != NULL)
*ip = ctx->fd;
ret = ctx->fd;
} else
ret = -1;
break;
case BIO_CTRL_GET_CLOSE:
ret = BIO_get_shutdown(b);
break;
case BIO_CTRL_SET_CLOSE:
BIO_set_shutdown(b, (int)num);
break;
case BIO_CTRL_PENDING:
case BIO_CTRL_WPENDING:
ret = 0;
break;
case BIO_CTRL_DUP:
case BIO_CTRL_FLUSH:
ret = 1;
break;
default:
ret = 0;
break;
}
return ret;
}
void pyfd_init(void) {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
methods_fdp = BIO_meth_new(
BIO_get_new_index()|BIO_TYPE_DESCRIPTOR|BIO_TYPE_SOURCE_SINK,
"python file descriptor");
#else
methods_fdp = BIO_meth_new(
100 |BIO_TYPE_DESCRIPTOR|BIO_TYPE_SOURCE_SINK,
"python file descriptor");
#endif
BIO_meth_set_write(methods_fdp, pyfd_write);
BIO_meth_set_read(methods_fdp, pyfd_read);
BIO_meth_set_puts(methods_fdp, pyfd_puts);
BIO_meth_set_gets(methods_fdp, pyfd_gets);
BIO_meth_set_ctrl(methods_fdp, pyfd_ctrl);
BIO_meth_set_create(methods_fdp, pyfd_new);
BIO_meth_set_destroy(methods_fdp, pyfd_free);
}
BIO* BIO_new_pyfd(int fd, int close_flag) {
BIO *ret;
ret = BIO_new(methods_fdp);
BIO_set_fd(ret, fd, close_flag);
return ret;
}
%}
m2crypto-0.42.0/src/SWIG/_bn.i 0000664 0000000 0000000 00000005720 14655756567 0015662 0 ustar 00root root 0000000 0000000 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright (c) 2005-2006 Open Source Applications Foundation. All rights reserved. */
/* We are converting between the Python arbitrarily long integer and
* the BIGNUM arbitrarily long integer by converting to and from
* a string representation of the number (in hexadecimal).
* Direct manipulation would be a possibility, but would require
* tighter integration with the Python and OpenSSL internals.
*/
%{
#include
%}
%inline %{
PyObject *bn_rand(int bits, int top, int bottom)
{
BIGNUM* rnd;
PyObject *ret;
char *randhex;
rnd = BN_new();
if (rnd == NULL) {
m2_PyErr_Msg(PyExc_Exception);
return NULL;
}
if (!BN_rand(rnd, bits, top, bottom)) {
/*Custom errors?*/
m2_PyErr_Msg(PyExc_Exception);
BN_free(rnd);
return NULL;
}
randhex = BN_bn2hex(rnd);
if (!randhex) {
/*Custom errors?*/
m2_PyErr_Msg(PyExc_Exception);
BN_free(rnd);
return NULL;
}
BN_free(rnd);
ret = PyLong_FromString(randhex, NULL, 16);
OPENSSL_free(randhex);
return ret;
}
PyObject *bn_rand_range(PyObject *range)
{
BIGNUM* rnd;
BIGNUM *rng = NULL;
PyObject *ret, *tuple;
PyObject *format, *rangePyString;
char *randhex; /* PyLong_FromString is unhappy with const */
const char *rangehex;
/* Wow, it's a lot of work to convert into a hex string in C! */
format = PyUnicode_FromString("%x");
if (!format) {
PyErr_SetString(PyExc_RuntimeError, "Cannot create Python string '%x'");
return NULL;
}
tuple = PyTuple_New(1);
if (!tuple) {
Py_DECREF(format);
PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails");
return NULL;
}
Py_INCREF(range);
PyTuple_SET_ITEM(tuple, 0, range);
rangePyString = PyUnicode_Format(format, tuple);
if (!rangePyString) {
PyErr_SetString(PyExc_Exception, "String Format failed");
Py_DECREF(format);
Py_DECREF(tuple);
return NULL;
}
Py_DECREF(format);
Py_DECREF(tuple);
rangehex = (const char*)PyUnicode_AsUTF8(rangePyString);
if (!BN_hex2bn(&rng, rangehex)) {
/*Custom errors?*/
m2_PyErr_Msg(PyExc_Exception);
Py_DECREF(rangePyString);
return NULL;
}
Py_DECREF(rangePyString);
if (!(rnd = BN_new())) {
PyErr_SetString(PyExc_MemoryError, "bn_rand_range");
return NULL;
}
if (!BN_rand_range(rnd, rng)) {
/*Custom errors?*/
m2_PyErr_Msg(PyExc_Exception);
BN_free(rnd);
BN_free(rng);
return NULL;
}
BN_free(rng);
randhex = BN_bn2hex(rnd);
if (!randhex) {
/*Custom errors?*/
m2_PyErr_Msg(PyExc_Exception);
BN_free(rnd);
return NULL;
}
BN_free(rnd);
ret = PyLong_FromString(randhex, NULL, 16);
OPENSSL_free(randhex);
return ret;
}
%}
m2crypto-0.42.0/src/SWIG/_dh.i 0000664 0000000 0000000 00000010363 14655756567 0015655 0 ustar 00root root 0000000 0000000 /* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. */
/* $Id$ */
%{
#include
#include
#include
#include
#include
%}
%apply Pointer NONNULL { DH * };
%rename(dh_new) DH_new;
extern DH *DH_new(void);
%rename(dh_free) DH_free;
extern void DH_free(DH *);
%rename(dh_size) DH_size;
extern int DH_size(const DH *);
%rename(dh_generate_key) DH_generate_key;
extern int DH_generate_key(DH *);
%rename(dhparams_print) DHparams_print;
%threadallow DHparams_print;
extern int DHparams_print(BIO *, const DH *);
%constant int dh_check_ok = 0;
%constant int dh_check_p_not_prime = DH_CHECK_P_NOT_PRIME;
%constant int dh_check_p_not_strong = DH_CHECK_P_NOT_STRONG_PRIME;
%constant int dh_check_g_failed = DH_UNABLE_TO_CHECK_GENERATOR;
%constant int dh_check_bad_g = DH_NOT_SUITABLE_GENERATOR;
%constant DH_GENERATOR_2 = 2;
%constant DH_GENERATOR_5 = 5;
%warnfilter(454) _dh_err;
%inline %{
static PyObject *_dh_err;
void dh_init(PyObject *dh_err) {
Py_INCREF(dh_err);
_dh_err = dh_err;
}
int dh_type_check(DH *dh) {
/* Our getting here means we passed Swig's type checking,
XXX Still need to check the pointer for sanity? */
return 1;
}
%}
%threadallow dh_read_parameters;
%inline %{
DH *dh_read_parameters(BIO *bio) {
return PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
}
DH *dh_generate_parameters(int plen, int g, PyObject *pyfunc) {
DH *dh;
BN_GENCB *gencb;
int ret;
if ((gencb=BN_GENCB_new()) == NULL) {
m2_PyErr_Msg(_dh_err);
return NULL;
}
if ((dh=DH_new()) == NULL) {
m2_PyErr_Msg(_dh_err);
BN_GENCB_free(gencb);
return NULL;
}
BN_GENCB_set(gencb, bn_gencb_callback, (void *)pyfunc);
Py_INCREF(pyfunc);
ret = DH_generate_parameters_ex(dh, plen, g, gencb);
Py_DECREF(pyfunc);
BN_GENCB_free(gencb);
if (ret)
return dh;
m2_PyErr_Msg(_dh_err);
DH_free(dh);
return NULL;
}
/* Note return value shenanigan. */
int dh_check(DH *dh) {
int err;
return (DH_check(dh, &err)) ? 0 : err;
}
PyObject *dh_compute_key(DH *dh, PyObject *pubkey) {
const void *pkbuf;
int pklen = 0, klen;
void *key;
BIGNUM *pk;
PyObject *ret;
if (m2_PyObject_AsReadBufferInt(pubkey, &pkbuf, &pklen) == -1)
return NULL;
if (!(pk = BN_mpi2bn((unsigned char *)pkbuf, pklen, NULL))) {
m2_PyErr_Msg(_dh_err);
return NULL;
}
if (!(key = PyMem_Malloc(DH_size(dh)))) {
BN_free(pk);
PyErr_SetString(PyExc_MemoryError, "dh_compute_key");
return NULL;
}
if ((klen = DH_compute_key((unsigned char *)key, pk, dh)) == -1) {
BN_free(pk);
PyMem_Free(key);
m2_PyErr_Msg(_dh_err);
return NULL;
}
ret = PyBytes_FromStringAndSize((const char *)key, klen);
BN_free(pk);
PyMem_Free(key);
return ret;
}
PyObject *dh_get_p(DH *dh) {
const BIGNUM* p = NULL;
DH_get0_pqg(dh, &p, NULL, NULL);
if (!p) {
PyErr_SetString(_dh_err, "'p' is unset");
return NULL;
}
return bn_to_mpi(p);
}
PyObject *dh_get_g(DH *dh) {
const BIGNUM* g = NULL;
DH_get0_pqg(dh, NULL, NULL, &g);
if (!g) {
PyErr_SetString(_dh_err, "'g' is unset");
return NULL;
}
return bn_to_mpi(g);
}
PyObject *dh_get_pub(DH *dh) {
const BIGNUM* pub_key = NULL;
DH_get0_key(dh, &pub_key, NULL);
if (!pub_key) {
PyErr_SetString(_dh_err, "'pub' is unset");
return NULL;
}
return bn_to_mpi(pub_key);
}
PyObject *dh_get_priv(DH *dh) {
const BIGNUM* priv_key = NULL;
DH_get0_key(dh, NULL, &priv_key);
if (!priv_key) {
PyErr_SetString(_dh_err, "'priv' is unset");
return NULL;
}
return bn_to_mpi(priv_key);
}
PyObject *dh_set_pg(DH *dh, PyObject *pval, PyObject* gval) {
BIGNUM* p, *g;
if (!(p = m2_PyObject_AsBIGNUM(pval, _dh_err))
|| !(g = m2_PyObject_AsBIGNUM(gval, _dh_err)))
return NULL;
if (!DH_set0_pqg(dh, p, NULL, g)) {
PyErr_SetString(_dh_err,
"Cannot set prime number or generator of Z_p for DH.");
BN_free(p);
BN_free(g);
return NULL;
}
Py_RETURN_NONE;
}
%}
m2crypto-0.42.0/src/SWIG/_dsa.i 0000664 0000000 0000000 00000022215 14655756567 0016030 0 ustar 00root root 0000000 0000000 /* Copyright (c) 1999-2000 Ng Pheng Siong. All rights reserved. */
/* $Id$ */
%{
#include
#include
#include
#include
PyObject *dsa_sig_get_r(DSA_SIG *dsa_sig) {
const BIGNUM* pr;
DSA_SIG_get0(dsa_sig, &pr, NULL);
return bn_to_mpi(pr);
}
PyObject *dsa_sig_get_s(DSA_SIG *dsa_sig) {
const BIGNUM* qs;
DSA_SIG_get0(dsa_sig, NULL, &qs);
return bn_to_mpi(qs);
}
%}
%apply Pointer NONNULL { DSA * };
%rename(dsa_new) DSA_new;
extern DSA *DSA_new(void);
%rename(dsa_free) DSA_free;
extern void DSA_free(DSA *);
%rename(dsa_size) DSA_size;
extern int DSA_size(const DSA *); /* assert(dsa->q); */
%rename(dsa_gen_key) DSA_generate_key;
extern int DSA_generate_key(DSA *);
%warnfilter(454) _dsa_err;
%inline %{
static PyObject *_dsa_err;
void dsa_init(PyObject *dsa_err) {
Py_INCREF(dsa_err);
_dsa_err = dsa_err;
}
%}
%typemap(out) DSA * {
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
if ($1 != NULL)
$result = SWIG_NewPointerObj($1, $1_descriptor, 0);
else {
$result = NULL;
}
}
%inline %{
DSA *dsa_generate_parameters(int bits, PyObject *pyfunc) {
DSA *dsa;
BN_GENCB *gencb;
int ret;
if ((gencb=BN_GENCB_new()) == NULL) {
m2_PyErr_Msg(_dh_err);
return NULL;
}
if ((dsa = DSA_new()) == NULL) {
m2_PyErr_Msg(_dsa_err);
BN_GENCB_free(gencb);
return NULL;
}
BN_GENCB_set(gencb, bn_gencb_callback, (void *) pyfunc);
Py_INCREF(pyfunc);
ret = DSA_generate_parameters_ex(dsa, bits, NULL, 0, NULL, NULL,
gencb);
Py_DECREF(pyfunc);
BN_GENCB_free(gencb);
if (ret)
return dsa;
m2_PyErr_Msg(_dsa_err);
DSA_free(dsa);
return NULL;
}
DSA *dsa_read_params(BIO *f, PyObject *pyfunc) {
DSA *ret;
Py_INCREF(pyfunc);
Py_BEGIN_ALLOW_THREADS
ret = PEM_read_bio_DSAparams(f, NULL, passphrase_callback, (void *)pyfunc);
Py_END_ALLOW_THREADS
Py_DECREF(pyfunc);
if (ret == NULL) {
m2_PyErr_Msg(_dsa_err);
}
return ret;
}
DSA *dsa_read_key(BIO *f, PyObject *pyfunc) {
DSA *ret;
Py_INCREF(pyfunc);
Py_BEGIN_ALLOW_THREADS
ret = PEM_read_bio_DSAPrivateKey(f, NULL, passphrase_callback, (void *)pyfunc);
Py_END_ALLOW_THREADS
Py_DECREF(pyfunc);
if (ret == NULL) {
m2_PyErr_Msg(_dsa_err);
}
return ret;
}
DSA *dsa_read_pub_key(BIO *f, PyObject *pyfunc) {
DSA *ret;
Py_INCREF(pyfunc);
Py_BEGIN_ALLOW_THREADS
ret = PEM_read_bio_DSA_PUBKEY(f, NULL, passphrase_callback, (void *)pyfunc);
Py_END_ALLOW_THREADS
Py_DECREF(pyfunc);
if (ret == NULL) {
m2_PyErr_Msg(_dsa_err);
}
return ret;
}
%}
%typemap(out) DSA * ;
%inline %{
PyObject *dsa_get_p(DSA *dsa) {
const BIGNUM* p = NULL;
DSA_get0_pqg(dsa, &p, NULL, NULL);
if (!p) {
PyErr_SetString(_dsa_err, "'p' is unset");
return NULL;
}
return bn_to_mpi(p);
}
PyObject *dsa_get_q(DSA *dsa) {
const BIGNUM* q = NULL;
DSA_get0_pqg(dsa, NULL, &q, NULL);
if (!q) {
PyErr_SetString(_dsa_err, "'q' is unset");
return NULL;
}
return bn_to_mpi(q);
}
PyObject *dsa_get_g(DSA *dsa) {
const BIGNUM* g = NULL;
DSA_get0_pqg(dsa, NULL, NULL, &g);
if (!g) {
PyErr_SetString(_dsa_err, "'g' is unset");
return NULL;
}
return bn_to_mpi(g);
}
PyObject *dsa_get_pub(DSA *dsa) {
const BIGNUM* pub_key = NULL;
DSA_get0_key(dsa, &pub_key, NULL);
if (!pub_key) {
PyErr_SetString(_dsa_err, "'pub' is unset");
return NULL;
}
return bn_to_mpi(pub_key);
}
PyObject *dsa_get_priv(DSA *dsa) {
const BIGNUM* priv_key = NULL;
DSA_get0_key(dsa, NULL, &priv_key);
if (!priv_key) {
PyErr_SetString(_dsa_err, "'priv' is unset");
return NULL;
}
return bn_to_mpi(priv_key);
}
PyObject *dsa_set_pqg(DSA *dsa, PyObject *pval, PyObject* qval, PyObject* gval) {
BIGNUM* p, *q, *g;
if (!(p = m2_PyObject_AsBIGNUM(pval, _dsa_err))
|| !(q = m2_PyObject_AsBIGNUM(qval, _dsa_err))
|| !(g = m2_PyObject_AsBIGNUM(gval, _dsa_err)))
return NULL;
if (!DSA_set0_pqg(dsa, p, q, g)) {
PyErr_SetString(
_dsa_err,
"Cannot set prime number, subprime, or generator of subgroup for DSA.");
BN_free(p);
BN_free(q);
BN_free(g);
return NULL;
}
Py_RETURN_NONE;
}
PyObject *dsa_set_pub(DSA *dsa, PyObject *value) {
BIGNUM *bn;
const void *vbuf;
int vlen = 0;
if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1)
return NULL;
if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) {
m2_PyErr_Msg(_dsa_err);
return NULL;
}
if (!DSA_set0_key(dsa, bn, NULL)) {
BN_free(bn);
PyErr_SetString(_dsa_err, "Cannot set private and public key for DSA.");
}
Py_RETURN_NONE;
}
%}
%threadallow dsa_write_params_bio;
%inline %{
int dsa_write_params_bio(DSA* dsa, BIO* f) {
return PEM_write_bio_DSAparams(f, dsa);
}
%}
%inline %{
int dsa_write_key_bio(DSA* dsa, BIO* f, EVP_CIPHER *cipher, PyObject *pyfunc) {
int ret;
Py_INCREF(pyfunc);
Py_BEGIN_ALLOW_THREADS
ret = PEM_write_bio_DSAPrivateKey(f, dsa, cipher, NULL, 0,
passphrase_callback, (void *)pyfunc);
Py_END_ALLOW_THREADS
Py_DECREF(pyfunc);
return ret;
}
%}
%inline %{
int dsa_write_key_bio_no_cipher(DSA* dsa, BIO* f, PyObject *pyfunc) {
int ret;
Py_INCREF(pyfunc);
Py_BEGIN_ALLOW_THREADS
ret = PEM_write_bio_DSAPrivateKey(f, dsa, NULL, NULL, 0,
passphrase_callback, (void *)pyfunc);
Py_END_ALLOW_THREADS
Py_DECREF(pyfunc);
return ret;
}
%}
%threadallow dsa_write_pub_key_bio;
%inline %{
int dsa_write_pub_key_bio(DSA* dsa, BIO* f) {
return PEM_write_bio_DSA_PUBKEY(f, dsa);
}
%}
%inline %{
PyObject *dsa_sign(DSA *dsa, PyObject *value) {
const void *vbuf;
int vlen = 0;
PyObject *tuple;
DSA_SIG *sig;
if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1)
return NULL;
if (!(sig = DSA_do_sign(vbuf, vlen, dsa))) {
m2_PyErr_Msg(_dsa_err);
return NULL;
}
if (!(tuple = PyTuple_New(2))) {
DSA_SIG_free(sig);
PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails");
return NULL;
}
PyTuple_SET_ITEM(tuple, 0, dsa_sig_get_r(sig));
PyTuple_SET_ITEM(tuple, 1, dsa_sig_get_s(sig));
DSA_SIG_free(sig);
return tuple;
}
int dsa_verify(DSA *dsa, PyObject *value, PyObject *r, PyObject *s) {
const void *vbuf, *rbuf, *sbuf;
int vlen = 0, rlen = 0, slen = 0;
DSA_SIG *sig;
BIGNUM* pr, *ps;
int ret;
if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1)
|| (m2_PyObject_AsReadBufferInt(r, &rbuf, &rlen) == -1)
|| (m2_PyObject_AsReadBufferInt(s, &sbuf, &slen) == -1))
return -1;
if (!(sig = DSA_SIG_new())) {
m2_PyErr_Msg(_dsa_err);
return -1;
}
if (!(pr = BN_mpi2bn((unsigned char *)rbuf, rlen, NULL))) {
m2_PyErr_Msg(_dsa_err);
DSA_SIG_free(sig);
return -1;
}
if (!(ps = BN_mpi2bn((unsigned char *)sbuf, slen, NULL))) {
m2_PyErr_Msg(_dsa_err);
DSA_SIG_free(sig);
BN_free(pr);
return -1;
}
if (!DSA_SIG_set0(sig, pr, ps)) {
m2_PyErr_Msg(_dsa_err);
DSA_SIG_free(sig);
BN_free(pr);
BN_free(ps);
return -1;
}
ret = DSA_do_verify(vbuf, vlen, sig, dsa);
DSA_SIG_free(sig);
if (ret == -1)
m2_PyErr_Msg(_dsa_err);
return ret;
}
PyObject *dsa_sign_asn1(DSA *dsa, PyObject *value) {
const void *vbuf;
int vlen = 0;
void *sigbuf;
unsigned int siglen;
PyObject *ret;
if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1)
return NULL;
if (!(sigbuf = PyMem_Malloc(DSA_size(dsa)))) {
PyErr_SetString(PyExc_MemoryError, "dsa_sign_asn1");
return NULL;
}
if (!DSA_sign(0, vbuf, vlen, (unsigned char *)sigbuf, &siglen, dsa)) {
m2_PyErr_Msg(_dsa_err);
PyMem_Free(sigbuf);
return NULL;
}
ret = PyBytes_FromStringAndSize(sigbuf, siglen);
PyMem_Free(sigbuf);
return ret;
}
int dsa_verify_asn1(DSA *dsa, PyObject *value, PyObject *sig) {
const void *vbuf;
void *sbuf;
int vlen = 0, slen = 0, ret = 0;
if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1)
|| (m2_PyObject_AsReadBufferInt(sig, (const void **)&sbuf, &slen)
== -1))
return -1;
if ((ret = DSA_verify(0, vbuf, vlen, sbuf, slen, dsa)) == -1)
m2_PyErr_Msg(_dsa_err);
return ret;
}
int dsa_check_key(DSA *dsa) {
const BIGNUM* pub_key, *priv_key;
DSA_get0_key(dsa, &pub_key, &priv_key);
return pub_key != NULL && priv_key != NULL;
}
int dsa_check_pub_key(DSA *dsa) {
const BIGNUM* pub_key;
DSA_get0_key(dsa, &pub_key, NULL);
return pub_key ? 1 : 0;
}
int dsa_keylen(DSA *dsa) {
const BIGNUM* p;
DSA_get0_pqg(dsa, &p, NULL, NULL);
return BN_num_bits(p);
}
int dsa_type_check(DSA *dsa) {
return 1;
}
%}
m2crypto-0.42.0/src/SWIG/_ec.i 0000664 0000000 0000000 00000035405 14655756567 0015655 0 ustar 00root root 0000000 0000000 /* Copyright (c) 1999-2000 Ng Pheng Siong. All rights reserved.
Portions copyright (c) 2005-2006 Vrije Universiteit Amsterdam. All rights reserved.
Most code originally from _dsa.i, _rsa.i and _dh.i and adjusted for EC use.
*/
%include
#if OPENSSL_VERSION_NUMBER < 0x0090800fL || defined(OPENSSL_NO_EC)
#undef OPENSSL_NO_EC
%constant OPENSSL_NO_EC = 1;
#else
%constant OPENSSL_NO_EC = 0;
%{
#include
#include
#include
#include
#include
#include
%}
%apply Pointer NONNULL { EC_KEY * };
%rename(ec_key_new) EC_KEY_new;
extern EC_KEY *EC_KEY_new(void);
%rename(ec_key_free) EC_KEY_free;
extern void EC_KEY_free(EC_KEY *);
%rename(ec_key_size) ECDSA_size;
extern int ECDSA_size(const EC_KEY *);
%rename(ec_key_gen_key) EC_KEY_generate_key;
extern int EC_KEY_generate_key(EC_KEY *);
%rename(ec_key_check_key) EC_KEY_check_key;
extern int EC_KEY_check_key(const EC_KEY *);
/* Curve identifier constants from OpenSSL */
%constant int NID_secp112r1 = NID_secp112r1;
%constant int NID_secp112r2 = NID_secp112r2;
%constant int NID_secp128r1 = NID_secp128r1;
%constant int NID_secp128r2 = NID_secp128r2;
%constant int NID_secp160k1 = NID_secp160k1;
%constant int NID_secp160r1 = NID_secp160r1;
%constant int NID_secp160r2 = NID_secp160r2;
%constant int NID_secp192k1 = NID_secp192k1;
%constant int NID_secp224k1 = NID_secp224k1;
%constant int NID_secp224r1 = NID_secp224r1;
%constant int NID_secp256k1 = NID_secp256k1;
%constant int NID_secp384r1 = NID_secp384r1;
%constant int NID_secp521r1 = NID_secp521r1;
%constant int NID_sect113r1 = NID_sect113r1;
%constant int NID_sect113r2 = NID_sect113r2;
%constant int NID_sect131r1 = NID_sect131r1;
%constant int NID_sect131r2 = NID_sect131r2;
%constant int NID_sect163k1 = NID_sect163k1;
%constant int NID_sect163r1 = NID_sect163r1;
%constant int NID_sect163r2 = NID_sect163r2;
%constant int NID_sect193r1 = NID_sect193r1;
%constant int NID_sect193r2 = NID_sect193r2;
%constant int NID_sect233k1 = NID_sect233k1;
%constant int NID_sect233r1 = NID_sect233r1;
%constant int NID_sect239k1 = NID_sect239k1;
%constant int NID_sect283k1 = NID_sect283k1;
%constant int NID_sect283r1 = NID_sect283r1;
%constant int NID_sect409k1 = NID_sect409k1;
%constant int NID_sect409r1 = NID_sect409r1;
%constant int NID_sect571k1 = NID_sect571k1;
%constant int NID_sect571r1 = NID_sect571r1;
%constant int NID_X9_62_prime192v1 = NID_X9_62_prime192v1;
%constant int NID_X9_62_prime192v2 = NID_X9_62_prime192v2;
%constant int NID_X9_62_prime192v3 = NID_X9_62_prime192v3;
%constant int NID_X9_62_prime239v1 = NID_X9_62_prime239v1;
%constant int NID_X9_62_prime239v2 = NID_X9_62_prime239v2;
%constant int NID_X9_62_prime239v3 = NID_X9_62_prime239v3;
%constant int NID_X9_62_prime256v1 = NID_X9_62_prime256v1;
%constant int NID_X9_62_c2pnb163v1 = NID_X9_62_c2pnb163v1;
%constant int NID_X9_62_c2pnb163v2 = NID_X9_62_c2pnb163v2;
%constant int NID_X9_62_c2pnb163v3 = NID_X9_62_c2pnb163v3;
%constant int NID_X9_62_c2pnb176v1 = NID_X9_62_c2pnb176v1;
%constant int NID_X9_62_c2tnb191v1 = NID_X9_62_c2tnb191v1;
%constant int NID_X9_62_c2tnb191v2 = NID_X9_62_c2tnb191v2;
%constant int NID_X9_62_c2tnb191v3 = NID_X9_62_c2tnb191v3;
%constant int NID_X9_62_c2pnb208w1 = NID_X9_62_c2pnb208w1;
%constant int NID_X9_62_c2tnb239v1 = NID_X9_62_c2tnb239v1;
%constant int NID_X9_62_c2tnb239v2 = NID_X9_62_c2tnb239v2;
%constant int NID_X9_62_c2tnb239v3 = NID_X9_62_c2tnb239v3;
%constant int NID_X9_62_c2pnb272w1 = NID_X9_62_c2pnb272w1;
%constant int NID_X9_62_c2pnb304w1 = NID_X9_62_c2pnb304w1;
%constant int NID_X9_62_c2tnb359v1 = NID_X9_62_c2tnb359v1;
%constant int NID_X9_62_c2pnb368w1 = NID_X9_62_c2pnb368w1;
%constant int NID_X9_62_c2tnb431r1 = NID_X9_62_c2tnb431r1;
%constant int NID_wap_wsg_idm_ecid_wtls1 = NID_wap_wsg_idm_ecid_wtls1;
%constant int NID_wap_wsg_idm_ecid_wtls3 = NID_wap_wsg_idm_ecid_wtls3;
%constant int NID_wap_wsg_idm_ecid_wtls4 = NID_wap_wsg_idm_ecid_wtls4;
%constant int NID_wap_wsg_idm_ecid_wtls5 = NID_wap_wsg_idm_ecid_wtls5;
%constant int NID_wap_wsg_idm_ecid_wtls6 = NID_wap_wsg_idm_ecid_wtls6;
%constant int NID_wap_wsg_idm_ecid_wtls7 = NID_wap_wsg_idm_ecid_wtls7;
%constant int NID_wap_wsg_idm_ecid_wtls8 = NID_wap_wsg_idm_ecid_wtls8;
%constant int NID_wap_wsg_idm_ecid_wtls9 = NID_wap_wsg_idm_ecid_wtls9;
%constant int NID_wap_wsg_idm_ecid_wtls10 = NID_wap_wsg_idm_ecid_wtls10;
%constant int NID_wap_wsg_idm_ecid_wtls11 = NID_wap_wsg_idm_ecid_wtls11;
%constant int NID_wap_wsg_idm_ecid_wtls12 = NID_wap_wsg_idm_ecid_wtls12;
%constant int NID_ipsec3 = NID_ipsec3;
%constant int NID_ipsec4 = NID_ipsec4;
%warnfilter(454) _ec_err;
%inline %{
static PyObject *_ec_err;
void ec_init(PyObject *ec_err) {
Py_INCREF(ec_err);
_ec_err = ec_err;
}
PyObject *ec_get_builtin_curves(void) {
/* size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t
* nitems); */
EC_builtin_curve *curves;
Py_ssize_t ret_curves = 0;
size_t num_curves = EC_get_builtin_curves(NULL, 0);
PyObject *ret_tuple = NULL;
PyObject *ret_dict = NULL;
Py_ssize_t i;
const char *comment;
const char *sname;
if (!(curves = PyMem_Malloc(num_curves * sizeof(EC_builtin_curve)))) {
PyErr_SetString(PyExc_MemoryError, "ec_get_builtin_curves");
return NULL;
}
ret_curves = (Py_ssize_t)EC_get_builtin_curves(curves, num_curves);
if (!(ret_tuple = PyTuple_New(ret_curves))) {
PyErr_SetString(PyExc_MemoryError, "ec_get_builtin_curves");
return NULL;
}
for (i = 0; i < ret_curves; i++) {
if (!(ret_dict = PyDict_New())) {
PyErr_SetString(PyExc_MemoryError, "ec_get_builtin_curves");
return NULL;
}
comment = curves[i].comment;
sname = OBJ_nid2sn(curves[i].nid);
if (sname == NULL)
sname = "";
PyDict_SetItemString(ret_dict, "NID",
PyLong_FromLong((long)curves[i].nid));
PyDict_SetItemString(ret_dict, "sname",
PyString_FromString(sname));
PyDict_SetItemString(ret_dict, "comment",
PyString_FromString(comment));
PyTuple_SET_ITEM(ret_tuple, i, ret_dict);
}
PyMem_Free(curves);
return ret_tuple;
}
EC_KEY* ec_key_new_by_curve_name(int nid)
{
EC_KEY *key;
EC_GROUP *group;
int ret =0;
point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED;
int asn1_flag = OPENSSL_EC_NAMED_CURVE;
/* If I simply do "return EC_KEY_new_by_curve_name(nid);"
* I get large public keys (222 vs 84 bytes for sect233k1 curve).
* I don't know why that is, but 'openssl ecparam -genkey ...' sets
* the ASN.1 flag and the point conversion form, and gets the
* small pub keys. So let's do that too.
*/
key = EC_KEY_new();
if (!key) {
PyErr_SetString(PyExc_MemoryError, "ec_key_new_by_curve_name");
return NULL;
}
group = EC_GROUP_new_by_curve_name(nid);
if (!group) {
m2_PyErr_Msg(_ec_err);
EC_KEY_free(key);
return NULL;
}
EC_GROUP_set_asn1_flag(group, asn1_flag);
EC_GROUP_set_point_conversion_form(group, form);
ret = EC_KEY_set_group(key, group);
EC_GROUP_free(group);
if (ret == 0)
{
/* EC_KEY_set_group only returns 0 or 1, and does not set error. */
PyErr_SetString(_ec_err, "cannot set key's group");
EC_KEY_free(key);
return NULL;
}
return key;
}
PyObject *ec_key_get_public_der(EC_KEY *key) {
char *src=NULL;
int src_len=0;
PyObject *pyo=NULL;
/* Convert to binary */
src_len = i2d_EC_PUBKEY( key, (unsigned char**)&src );
if (src_len < 0)
{
m2_PyErr_Msg(_ec_err);
return NULL;
}
/* Create a PyBuffer containing a copy of the binary,
* to simplify memory deallocation
*/
pyo = PyBytes_FromStringAndSize( src, src_len );
OPENSSL_free(src);
return pyo;
}
PyObject *ec_key_get_public_key(EC_KEY *key) {
char *src=NULL;
int src_len=0;
PyObject *pyo=NULL;
/* Convert to binary */
src_len = i2o_ECPublicKey(key, (unsigned char**)&src);
if (src_len < 0)
{
m2_PyErr_Msg(_ec_err);
return NULL;
}
pyo = PyBytes_FromStringAndSize( src, src_len );
OPENSSL_free(src);
return pyo;
}
%}
%threadallow ec_key_read_pubkey;
%inline %{
EC_KEY *ec_key_read_pubkey(BIO *f) {
return PEM_read_bio_EC_PUBKEY(f, NULL, NULL, NULL);
}
%}
%threadallow ec_key_write_pubkey;
%inline %{
int ec_key_write_pubkey(EC_KEY *key, BIO *f) {
return PEM_write_bio_EC_PUBKEY(f, key );
}
%}
%inline %{
EC_KEY *ec_key_read_bio(BIO *f, PyObject *pyfunc) {
EC_KEY *ret;
Py_INCREF(pyfunc);
Py_BEGIN_ALLOW_THREADS
ret = PEM_read_bio_ECPrivateKey(f, NULL, passphrase_callback, (void *)pyfunc);
Py_END_ALLOW_THREADS
Py_DECREF(pyfunc);
return ret;
}
%}
%inline %{
int ec_key_write_bio(EC_KEY *key, BIO *f, EVP_CIPHER *cipher, PyObject *pyfunc) {
int ret;
Py_INCREF(pyfunc);
Py_BEGIN_ALLOW_THREADS
ret = PEM_write_bio_ECPrivateKey(f, key, cipher, NULL, 0,
passphrase_callback, (void *)pyfunc);
Py_END_ALLOW_THREADS
Py_DECREF(pyfunc);
return ret;
}
%}
%inline %{
int ec_key_write_bio_no_cipher(EC_KEY *key, BIO *f, PyObject *pyfunc) {
int ret;
Py_INCREF(pyfunc);
Py_BEGIN_ALLOW_THREADS
ret = PEM_write_bio_ECPrivateKey(f, key, NULL, NULL, 0,
passphrase_callback, (void *)pyfunc);
Py_END_ALLOW_THREADS
Py_DECREF(pyfunc);
return ret;
}
PyObject *ecdsa_sig_get_r(ECDSA_SIG *ecdsa_sig) {
const BIGNUM* pr;
ECDSA_SIG_get0(ecdsa_sig, &pr, NULL);
return bn_to_mpi(pr);
}
PyObject *ecdsa_sig_get_s(ECDSA_SIG *ecdsa_sig) {
const BIGNUM* ps;
ECDSA_SIG_get0(ecdsa_sig, NULL, &ps);
return bn_to_mpi(ps);
}
PyObject *ecdsa_sign(EC_KEY *key, PyObject *value) {
const void *vbuf;
int vlen = 0;
PyObject *tuple;
ECDSA_SIG *sig;
if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1)
return NULL;
if (!(sig = ECDSA_do_sign(vbuf, vlen, key))) {
m2_PyErr_Msg(_ec_err);
return NULL;
}
if (!(tuple = PyTuple_New(2))) {
ECDSA_SIG_free(sig);
PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails");
return NULL;
}
PyTuple_SET_ITEM(tuple, 0, ecdsa_sig_get_r(sig));
PyTuple_SET_ITEM(tuple, 1, ecdsa_sig_get_s(sig));
ECDSA_SIG_free(sig);
return tuple;
}
int ecdsa_verify(EC_KEY *key, PyObject *value, PyObject *r, PyObject *s) {
const void *vbuf, *rbuf, *sbuf;
int vlen = 0, rlen = 0, slen = 0;
ECDSA_SIG *sig;
int ret;
BIGNUM* pr, *ps;
if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1)
|| (m2_PyObject_AsReadBufferInt(r, &rbuf, &rlen) == -1)
|| (m2_PyObject_AsReadBufferInt(s, &sbuf, &slen) == -1))
return -1;
if (!(pr = BN_mpi2bn((unsigned char *)rbuf, rlen, NULL))) {
m2_PyErr_Msg(_ec_err);
return -1;
}
if (!(ps = BN_mpi2bn((unsigned char *)sbuf, slen, NULL))) {
m2_PyErr_Msg(_ec_err);
BN_free(pr);
return -1;
}
if (!(sig = ECDSA_SIG_new())) {
m2_PyErr_Msg(_ec_err);
BN_free(pr);
BN_free(ps);
return -1;
}
if (!ECDSA_SIG_set0(sig, pr, ps)) {
PyErr_SetString(_ec_err, "Cannot set r and s fields of ECDSA_SIG.");
ECDSA_SIG_free(sig);
BN_free(pr);
BN_free(ps);
return -1;
}
ret = ECDSA_do_verify(vbuf, vlen, sig, key);
ECDSA_SIG_free(sig);
if (ret == -1)
m2_PyErr_Msg(_ec_err);
return ret;
}
PyObject *ecdsa_sign_asn1(EC_KEY *key, PyObject *value) {
const void *vbuf;
int vlen = 0;
void *sigbuf;
unsigned int siglen;
PyObject *ret;
if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1)
return NULL;
if (!(sigbuf = PyMem_Malloc(ECDSA_size(key)))) {
PyErr_SetString(PyExc_MemoryError, "ecdsa_sign_asn1");
return NULL;
}
if (!ECDSA_sign(0, vbuf, vlen, (unsigned char *)sigbuf, &siglen, key)) {
m2_PyErr_Msg(_ec_err);
PyMem_Free(sigbuf);
return NULL;
}
ret = PyBytes_FromStringAndSize(sigbuf, siglen);
PyMem_Free(sigbuf);
return ret;
}
int ecdsa_verify_asn1(EC_KEY *key, PyObject *value, PyObject *sig) {
const void *vbuf;
void *sbuf;
int vlen = 0, slen = 0, ret;
if ((m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1)
|| (m2_PyObject_AsReadBufferInt(sig, (const void **)&sbuf, &slen)
== -1))
return -1;
if ((ret = ECDSA_verify(0, vbuf, vlen, sbuf, slen, key)) == -1)
m2_PyErr_Msg(_ec_err);
return ret;
}
PyObject *ecdh_compute_key(EC_KEY *keypairA, EC_KEY *pubkeyB) {
int sharedkeylen;
void *sharedkey;
const EC_POINT *pkpointB;
PyObject *ret;
const EC_GROUP* groupA;
if ((pkpointB = EC_KEY_get0_public_key(pubkeyB)) == NULL)
{
PyErr_SetString(_ec_err, "Cannot get the public key of EC_KEY object.");
return NULL;
}
groupA = EC_KEY_get0_group(keypairA);
sharedkeylen = (EC_GROUP_get_degree(groupA) + 7)/8;
if (!(sharedkey = PyMem_Malloc(sharedkeylen))) {
PyErr_SetString(PyExc_MemoryError, "ecdh_compute_key");
return NULL;
}
if ((sharedkeylen = ECDH_compute_key((unsigned char *)sharedkey, sharedkeylen, pkpointB, keypairA, NULL)) == -1) {
m2_PyErr_Msg(_ec_err);
PyMem_Free(sharedkey);
return NULL;
}
ret = PyBytes_FromStringAndSize((const char *)sharedkey, sharedkeylen);
PyMem_Free(sharedkey);
return ret;
}
EC_KEY* ec_key_from_pubkey_der(PyObject *pubkey) {
const void *keypairbuf;
Py_ssize_t keypairbuflen;
const unsigned char *tempBuf;
EC_KEY *keypair;
if (m2_PyObject_AsReadBuffer(pubkey, &keypairbuf, &keypairbuflen) == -1)
{
return NULL;
}
tempBuf = (const unsigned char *)keypairbuf;
if ((keypair = d2i_EC_PUBKEY( NULL, &tempBuf, keypairbuflen)) == 0)
{
m2_PyErr_Msg(_ec_err);
return NULL;
}
return keypair;
}
EC_KEY* ec_key_from_pubkey_params(int nid, PyObject *pubkey) {
const void *keypairbuf;
Py_ssize_t keypairbuflen;
const unsigned char *tempBuf;
EC_KEY *keypair;
if (m2_PyObject_AsReadBuffer(pubkey, &keypairbuf, &keypairbuflen) == -1)
{
return NULL;
}
keypair = ec_key_new_by_curve_name(nid);
if (!keypair) {
m2_PyErr_Msg(_ec_err);
return NULL;
}
tempBuf = (const unsigned char *)keypairbuf;
if ((o2i_ECPublicKey( &keypair, &tempBuf, keypairbuflen)) == 0)
{
m2_PyErr_Msg(_ec_err);
return NULL;
}
return keypair;
}
// According to [SEC2] the degree of the group is defined as EC key length
int ec_key_keylen(EC_KEY *key) {
const EC_GROUP *group = EC_KEY_get0_group(key);
return EC_GROUP_get_degree(group);
}
int ec_key_type_check(EC_KEY *key) {
return 1;
}
%}
#endif // if OpenSSL version with EC support
m2crypto-0.42.0/src/SWIG/_engine.i 0000664 0000000 0000000 00000012544 14655756567 0016532 0 ustar 00root root 0000000 0000000 /*
* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: syntax=c sts=4 sw=4
*
* ENGINE functions from engine(3SSL).
*
* Pavel Shramov
* IMEC MSU
*/
%{
#include
#include
#include
%}
%apply Pointer NONNULL { ENGINE * };
%apply Pointer NONNULL { const ENGINE * };
%apply Pointer NONNULL { const char * };
/*
* Functions to load different engines
*/
%rename(engine_load_builtin_engines) ENGINE_load_builtin_engines;
extern void ENGINE_load_builtin_engines(void);
%rename(engine_load_dynamic) ENGINE_load_dynamic;
extern void ENGINE_load_dynamic(void);
%rename(engine_load_openssl) ENGINE_load_openssl;
extern void ENGINE_load_openssl(void);
%rename(engine_cleanup) ENGINE_cleanup;
extern void ENGINE_cleanup(void);
/*
* Engine allocation functions
*/
%rename(engine_new) ENGINE_new;
extern ENGINE * ENGINE_new();
%rename(engine_by_id) ENGINE_by_id;
extern ENGINE * ENGINE_by_id(const char *);
%rename(engine_free) ENGINE_free;
extern int ENGINE_free(ENGINE *);
%rename(engine_init) ENGINE_init;
extern int ENGINE_init(ENGINE *);
%rename(engine_finish) ENGINE_finish;
extern int ENGINE_finish(ENGINE *);
/*
* Engine id/name functions
*/
%rename(engine_get_id) ENGINE_get_id;
extern const char * ENGINE_get_id(const ENGINE *);
%rename(engine_get_name) ENGINE_get_name;
extern const char * ENGINE_get_name(const ENGINE *);
/*
* Engine control functions
* Control argument may be NULL (e.g for LOAD command)
*/
%clear const char *;
%rename(engine_ctrl_cmd_string) ENGINE_ctrl_cmd_string;
extern int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name,
const char *arg, int cmd_optional);
%apply Pointer NONNULL { const char * };
/*
* UI methods.
* XXX: UI_OpenSSL method is static and UI_destroy_method is not needed.
*/
%rename(ui_openssl) UI_OpenSSL;
extern UI_METHOD * UI_OpenSSL();
/*
%rename(ui_destroy_method) UI_destroy_method;
extern void UI_destroy_method(UI_METHOD *ui_method);
*/
%clear const char *;
%inline %{
/*
* Code from engine-pkcs11 1.4.0 in engine-pkcs11.c
*
99 static char *get_pin(UI_METHOD * ui_method, void *callback_data, char *sc_pin,
100 int maxlen)
101 {
102 UI *ui;
103 struct {
104 const void *password;
105 const char *prompt_info;
106 } *mycb = callback_data;
107
108 if (mycb->password) {
109 sc_pin = set_pin(mycb->password);
110 return sc_pin;
111 }
*
* So callback_data need to be always provided and have fixed type.
* UI method still may be NULL.
*
* Following functions allocate and free callback data structure with
* optional password set.
*/
typedef struct {
char * password;
char * prompt;
} _cbd_t;
void * engine_pkcs11_data_new(const char *pin) {
_cbd_t * cb = (_cbd_t *) PyMem_Malloc(sizeof(_cbd_t));
if (!cb) {
PyErr_SetString(PyExc_MemoryError, "engine_pkcs11_data_new");
return NULL;
}
cb->password = NULL;
if (pin) {
size_t size = strlen(pin);
cb->password = (char *) PyMem_Malloc(size + 1);
if (!cb->password) {
PyErr_SetString(PyExc_MemoryError, "engine_pkcs11_data_new");
PyMem_Free(cb);
return NULL;
}
memcpy(cb->password, pin, size + 1);
}
cb->prompt = NULL;
return cb;
}
void engine_pkcs11_data_free(void * vcb) {
_cbd_t * cb = (_cbd_t *) vcb;
if (!cb)
return;
if (cb->password)
PyMem_Free(cb->password);
PyMem_Free(cb);
}
%}
%apply Pointer NONNULL { const char * };
/*
* Engine key/cert load functions.
* See above notice about callback_data.
*/
%rename(engine_load_private_key) ENGINE_load_private_key;
extern EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id,
UI_METHOD *ui_method, void *callback_data);
%rename(engine_load_public_key) ENGINE_load_public_key;
extern EVP_PKEY *ENGINE_load_public_key(ENGINE *e, const char *key_id,
UI_METHOD *ui_method, void *callback_data);
/*
* This function may be not implemented in engine.
* pkcs11 engine has this control.
*/
%warnfilter(454) _engine_err;
%inline %{
static PyObject *_engine_err;
void engine_init_error(PyObject *engine_err) {
Py_INCREF(engine_err);
_engine_err = engine_err;
}
X509 * engine_load_certificate(ENGINE *e, const char * slot) {
struct {
const char * slot;
X509 * cert;
} cbd;
cbd.slot = slot;
cbd.cert = NULL;
if (!ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &cbd, NULL, 0)) {
PyErr_SetString(_engine_err, "cannot load certificate");
return NULL;
}
return cbd.cert;
}
%}
/* These flags are used to control combinations of algorithm (methods)
* by bitwise "OR"ing. */
%constant int ENGINE_METHOD_RSA = 0x0001;
%constant int ENGINE_METHOD_DSA = 0x0002;
%constant int ENGINE_METHOD_DH = 0x0004;
%constant int ENGINE_METHOD_RAND = 0x0008;
%constant int ENGINE_METHOD_ECDH = 0x0010;
%constant int ENGINE_METHOD_ECDSA = 0x0020;
%constant int ENGINE_METHOD_CIPHERS = 0x0040;
%constant int ENGINE_METHOD_DIGESTS = 0x0080;
%constant int ENGINE_METHOD_STORE = 0x0100;
/* Obvious all-or-nothing cases. */
%constant int ENGINE_METHOD_ALL = 0xFFFF;
%constant int ENGINE_METHOD_NONE = 0x0000;
%rename(engine_set_default) ENGINE_set_default;
extern int ENGINE_set_default(ENGINE *e, unsigned int flags);
m2crypto-0.42.0/src/SWIG/_evp.i 0000664 0000000 0000000 00000060206 14655756567 0016055 0 ustar 00root root 0000000 0000000 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
Copyright (c) 1999 Ng Pheng Siong. All rights reserved.
Portions Copyright (c) 2004-2007 Open Source Applications Foundation.
Author: Heikki Toivonen
Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved.
*/
%include
%{
#include
#include
#include
#include
#include
#include
#include
#if OPENSSL_VERSION_NUMBER < 0x10100000L
HMAC_CTX *HMAC_CTX_new(void) {
HMAC_CTX *ret = PyMem_Malloc(sizeof(HMAC_CTX));
HMAC_CTX_init(ret);
return ret;
}
#define HMAC_CTX_reset(ctx) HMAC_CTX_init(ctx)
#define HMAC_CTX_free(ctx) \
do { \
HMAC_CTX_cleanup(ctx); \
PyMem_Free((void *)ctx); \
} while(0)
#define EVP_CIPHER_CTX_reset(ctx) EVP_CIPHER_CTX_init(ctx)
#endif
%}
/*
from openssl/crypto/include/internal/evp_int.h struct evp_md_st
typedef struct evp_md_st EVP_MD;
from openssl/crypto/evp/evp_locl.h evp_md_ctx_st
typedef struct evp_md_ctx_st EVP_MD_CTX;
*/
%apply Pointer NONNULL { EVP_MD_CTX * };
%apply Pointer NONNULL { EVP_MD * };
%apply Pointer NONNULL { EVP_PKEY * };
%apply Pointer NONNULL { HMAC_CTX * };
%apply Pointer NONNULL { EVP_CIPHER_CTX * };
%apply Pointer NONNULL { EVP_CIPHER * };
%apply Pointer NONNULL { RSA * };
%apply Pointer NONNULL { EC_KEY * };
%rename(md5) EVP_md5;
extern const EVP_MD *EVP_md5(void);
%rename(sha1) EVP_sha1;
extern const EVP_MD *EVP_sha1(void);
%rename(ripemd160) EVP_ripemd160;
extern const EVP_MD *EVP_ripemd160(void);
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
%rename(sha224) EVP_sha224;
extern const EVP_MD *EVP_sha224(void);
%rename(sha256) EVP_sha256;
extern const EVP_MD *EVP_sha256(void);
%rename(sha384) EVP_sha384;
extern const EVP_MD *EVP_sha384(void);
%rename(sha512) EVP_sha512;
extern const EVP_MD *EVP_sha512(void);
#endif
%rename(digest_init) EVP_DigestInit;
extern int EVP_DigestInit(EVP_MD_CTX *, const EVP_MD *);
%rename(des_ecb) EVP_des_ecb;
extern const EVP_CIPHER *EVP_des_ecb(void);
%rename(des_ede_ecb) EVP_des_ede;
extern const EVP_CIPHER *EVP_des_ede(void);
%rename(des_ede3_ecb) EVP_des_ede3;
extern const EVP_CIPHER *EVP_des_ede3(void);
%rename(des_cbc) EVP_des_cbc;
extern const EVP_CIPHER *EVP_des_cbc(void);
%rename(des_ede_cbc) EVP_des_ede_cbc;
extern const EVP_CIPHER *EVP_des_ede_cbc(void);
%rename(des_ede3_cbc) EVP_des_ede3_cbc;
extern const EVP_CIPHER *EVP_des_ede3_cbc(void);
%rename(des_cfb) EVP_des_cfb;
extern const EVP_CIPHER *EVP_des_cfb(void);
%rename(des_ede_cfb) EVP_des_ede_cfb;
extern const EVP_CIPHER *EVP_des_ede_cfb(void);
%rename(des_ede3_cfb) EVP_des_ede3_cfb;
extern const EVP_CIPHER *EVP_des_ede3_cfb(void);
%rename(des_ofb) EVP_des_ofb;
extern const EVP_CIPHER *EVP_des_ofb(void);
%rename(des_ede_ofb) EVP_des_ede_ofb;
extern const EVP_CIPHER *EVP_des_ede_ofb(void);
%rename(des_ede3_ofb) EVP_des_ede3_ofb;
extern const EVP_CIPHER *EVP_des_ede3_ofb(void);
%rename(bf_ecb) EVP_bf_ecb;
extern const EVP_CIPHER *EVP_bf_ecb(void);
%rename(bf_cbc) EVP_bf_cbc;
extern const EVP_CIPHER *EVP_bf_cbc(void);
%rename(bf_cfb) EVP_bf_cfb;
extern const EVP_CIPHER *EVP_bf_cfb(void);
%rename(bf_ofb) EVP_bf_ofb;
extern const EVP_CIPHER *EVP_bf_ofb(void);
/*
%rename(idea_ecb) extern const EVP_CIPHER *EVP_idea_ecb(void);
%rename(idea_cbc) extern const EVP_CIPHER *EVP_idea_cbc(void);
%rename(idea_cfb) extern const EVP_CIPHER *EVP_idea_cfb(void);
%rename(idea_ofb) extern const EVP_CIPHER *EVP_idea_ofb(void);
*/
%rename(cast5_ecb) EVP_cast5_ecb;
extern const EVP_CIPHER *EVP_cast5_ecb(void);
%rename(cast5_cbc) EVP_cast5_cbc;
extern const EVP_CIPHER *EVP_cast5_cbc(void);
%rename(cast5_cfb) EVP_cast5_cfb;
extern const EVP_CIPHER *EVP_cast5_cfb(void);
%rename(cast5_ofb) EVP_cast5_ofb;
extern const EVP_CIPHER *EVP_cast5_ofb(void);
/*
%rename(rc5_ecb) extern const EVP_CIPHER *EVP_rc5_32_12_16_ecb(void);
%rename(rc5_cbc) extern const EVP_CIPHER *EVP_rc5_32_12_16_cbc(void);
%rename(rc5_cfb) extern const EVP_CIPHER *EVP_rc5_32_12_16_cfb(void);
%rename(rc5_ofb) extern const EVP_CIPHER *EVP_rc5_32_12_16_ofb(void);
*/
#if !defined(OPENSSL_NO_RC4)
%rename(rc4) EVP_rc4;
extern const EVP_CIPHER *EVP_rc4(void);
#endif
#if !defined(OPENSSL_NO_RC2)
%rename(rc2_40_cbc) EVP_rc2_40_cbc;
extern const EVP_CIPHER *EVP_rc2_40_cbc(void);
#endif
%rename(aes_128_ecb) EVP_aes_128_ecb;
extern const EVP_CIPHER *EVP_aes_128_ecb(void);
%rename(aes_128_cbc) EVP_aes_128_cbc;
extern const EVP_CIPHER *EVP_aes_128_cbc(void);
%rename(aes_128_cfb) EVP_aes_128_cfb;
extern const EVP_CIPHER *EVP_aes_128_cfb(void);
%rename(aes_128_ofb) EVP_aes_128_ofb;
extern const EVP_CIPHER *EVP_aes_128_ofb(void);
%rename(aes_128_ctr) EVP_aes_128_ctr;
extern const EVP_CIPHER *EVP_aes_128_ctr(void);
%rename(aes_192_ecb) EVP_aes_192_ecb;
extern const EVP_CIPHER *EVP_aes_192_ecb(void);
%rename(aes_192_cbc) EVP_aes_192_cbc;
extern const EVP_CIPHER *EVP_aes_192_cbc(void);
%rename(aes_192_cfb) EVP_aes_192_cfb;
extern const EVP_CIPHER *EVP_aes_192_cfb(void);
%rename(aes_192_ofb) EVP_aes_192_ofb;
extern const EVP_CIPHER *EVP_aes_192_ofb(void);
%rename(aes_192_ctr) EVP_aes_192_ctr;
extern const EVP_CIPHER *EVP_aes_192_ctr(void);
%rename(aes_256_ecb) EVP_aes_256_ecb;
extern const EVP_CIPHER *EVP_aes_256_ecb(void);
%rename(aes_256_cbc) EVP_aes_256_cbc;
extern const EVP_CIPHER *EVP_aes_256_cbc(void);
%rename(aes_256_cfb) EVP_aes_256_cfb;
extern const EVP_CIPHER *EVP_aes_256_cfb(void);
%rename(aes_256_ofb) EVP_aes_256_ofb;
extern const EVP_CIPHER *EVP_aes_256_ofb(void);
%rename(aes_256_ctr) EVP_aes_256_ctr;
extern EVP_CIPHER const *EVP_aes_256_ctr(void);
%rename(cipher_set_padding) EVP_CIPHER_CTX_set_padding;
extern int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *, int);
%rename(cipher_set_padding) EVP_CIPHER_CTX_set_padding;
extern int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *x, int padding);
%rename(pkey_free) EVP_PKEY_free;
extern void EVP_PKEY_free(EVP_PKEY *);
%rename(pkey_assign) EVP_PKEY_assign;
extern int EVP_PKEY_assign(EVP_PKEY *, int, char *);
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL && !defined(OPENSSL_NO_EC)
%rename(pkey_assign_ec) EVP_PKEY_assign_EC_KEY;
extern int EVP_PKEY_assign_EC_KEY(EVP_PKEY *, EC_KEY *);
%rename(pkey_set1_ec) EVP_PKEY_set1_EC_KEY;
extern int EVP_PKEY_set1_EC_KEY(EVP_PKEY *, EC_KEY *);
#endif
%rename(pkey_set1_rsa) EVP_PKEY_set1_RSA;
extern int EVP_PKEY_set1_RSA(EVP_PKEY *, RSA *);
%rename(sign_init) EVP_SignInit;
extern int EVP_SignInit(EVP_MD_CTX *, const EVP_MD *);
%rename(verify_init) EVP_VerifyInit;
extern int EVP_VerifyInit(EVP_MD_CTX *, const EVP_MD *);
%rename(digest_sign_init) EVP_DigestSignInit;
extern int EVP_DigestSignInit(EVP_MD_CTX *, EVP_PKEY_CTX **, const EVP_MD *, ENGINE *, EVP_PKEY *);
%rename(digest_verify_init) EVP_DigestVerifyInit;
extern int EVP_DigestVerifyInit(EVP_MD_CTX *, EVP_PKEY_CTX **, const EVP_MD *, ENGINE *, EVP_PKEY *);
%rename(pkey_size) EVP_PKEY_size;
extern int EVP_PKEY_size(EVP_PKEY *);
%warnfilter(454) _evp_err;
%inline %{
#define PKCS5_SALT_LEN 8
static PyObject *_evp_err;
void evp_init(PyObject *evp_err) {
Py_INCREF(evp_err);
_evp_err = evp_err;
}
%}
%typemap(out) RSA * {
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
if ($1 != NULL)
$result = SWIG_NewPointerObj($1, $1_descriptor, 0);
else {
$result = NULL;
}
}
%inline %{
RSA *pkey_get1_rsa(EVP_PKEY *pkey) {
RSA *ret = NULL;
if ((ret = EVP_PKEY_get1_RSA(pkey)) == NULL) {
/* _evp_err now inherits from PyExc_ValueError, so we should
* keep API intact.
*/
PyErr_Format(_evp_err, "Invalid key in function %s.", __FUNCTION__);
}
return ret;
}
%}
%typemap(out) RSA * ;
%typemap(out) EC_KEY * {
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
if ($1 != NULL)
$result = SWIG_NewPointerObj($1, $1_descriptor, 0);
else {
$result = NULL;
}
}
%inline %{
EC_KEY *pkey_get1_ec(EVP_PKEY *pkey) {
EC_KEY *ret = NULL;
if ((ret = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) {
/* _evp_err now inherits from PyExc_ValueError, so we should
* keep API intact.
*/
PyErr_Format(_evp_err, "Invalid key in function %s.", __FUNCTION__);
}
return ret;
}
%}
%typemap(out) EC_KEY * ;
%inline %{
PyObject *pkcs5_pbkdf2_hmac_sha1(PyObject *pass,
PyObject *salt,
int iter,
int keylen) {
unsigned char *key;
const void *saltbuf;
const void *passbuf;
PyObject *ret;
int passlen = 0, saltlen = 0;
if (m2_PyObject_AsReadBufferInt(pass, &passbuf, &passlen) == -1)
return NULL;
if (m2_PyObject_AsReadBufferInt(salt, &saltbuf, &saltlen) == -1)
return NULL;
key = PyMem_Malloc(keylen);
if (key == NULL)
return PyErr_NoMemory();
PKCS5_PBKDF2_HMAC_SHA1((const char *)passbuf, passlen, (const unsigned char *)saltbuf, saltlen, iter,
keylen, key);
ret = PyBytes_FromStringAndSize((char*)key, keylen);
OPENSSL_cleanse(key, keylen);
PyMem_Free(key);
return ret;
}
EVP_MD_CTX *md_ctx_new(void) {
EVP_MD_CTX *ctx;
if (!(ctx = EVP_MD_CTX_create())) {
PyErr_SetString(PyExc_MemoryError, "md_ctx_new");
return NULL;
}
return ctx;
}
void md_ctx_free(EVP_MD_CTX *ctx) {
EVP_MD_CTX_destroy(ctx);
}
int digest_update(EVP_MD_CTX *ctx, PyObject *blob) {
const void *buf = NULL;
Py_ssize_t len;
if (m2_PyObject_AsReadBuffer(blob, &buf, &len) == -1)
return -1;
return EVP_DigestUpdate(ctx, buf, (size_t)len);
}
PyObject *digest_final(EVP_MD_CTX *ctx) {
void *blob;
int blen;
PyObject *ret;
if (!(blob = PyMem_Malloc(EVP_MD_CTX_size(ctx)))) {
PyErr_SetString(PyExc_MemoryError, "digest_final");
return NULL;
}
if (!EVP_DigestFinal(ctx, blob, (unsigned int *)&blen)) {
PyMem_Free(blob);
m2_PyErr_Msg(_evp_err);
return NULL;
}
ret = PyBytes_FromStringAndSize(blob, blen);
PyMem_Free(blob);
return ret;
}
HMAC_CTX *hmac_ctx_new(void) {
HMAC_CTX *ctx;
if (!(ctx = HMAC_CTX_new())) {
PyErr_SetString(PyExc_MemoryError, "hmac_ctx_new");
return NULL;
}
return ctx;
}
void hmac_ctx_free(HMAC_CTX *ctx) {
HMAC_CTX_free(ctx);
}
PyObject *hmac_init(HMAC_CTX *ctx, PyObject *key, const EVP_MD *md) {
const void *kbuf;
int klen = 0;
if (m2_PyObject_AsReadBufferInt(key, &kbuf, &klen) == -1)
return NULL;
if (!HMAC_Init_ex(ctx, kbuf, klen, md, NULL)) {
PyErr_SetString(_evp_err, "HMAC_Init failed");
return NULL;
}
Py_RETURN_NONE;
}
PyObject *hmac_update(HMAC_CTX *ctx, PyObject *blob) {
const void *buf = NULL;
Py_ssize_t len;
if (m2_PyObject_AsReadBuffer(blob, &buf, &len) == -1)
return NULL;
if (!HMAC_Update(ctx, (const unsigned char *)buf, (size_t)len)) {
PyErr_SetString(_evp_err, "HMAC_Update failed");
return NULL;
}
Py_RETURN_NONE;
}
PyObject *hmac_final(HMAC_CTX *ctx) {
void *blob;
int blen;
PyObject *ret;
if (!(blob = PyMem_Malloc(HMAC_size(ctx)))) {
PyErr_SetString(PyExc_MemoryError, "hmac_final");
return NULL;
}
if (!HMAC_Final(ctx, blob, (unsigned int *)&blen)) {
PyErr_SetString(_evp_err, "HMAC_Final failed");
return NULL;
}
ret = PyBytes_FromStringAndSize(blob, blen);
PyMem_Free(blob);
return ret;
}
PyObject *hmac(PyObject *key, PyObject *data, const EVP_MD *md) {
const void *kbuf, *dbuf;
void *blob;
int klen = 0;
unsigned int blen;
Py_ssize_t dlen;
PyObject *ret;
if ((m2_PyObject_AsReadBufferInt(key, &kbuf, &klen) == -1)
|| (m2_PyObject_AsReadBuffer(data, &dbuf, &dlen) == -1))
return NULL;
if (!(blob = PyMem_Malloc(EVP_MAX_MD_SIZE))) {
PyErr_SetString(PyExc_MemoryError, "hmac");
return NULL;
}
HMAC(md, kbuf, klen, (const unsigned char *)dbuf, (size_t)dlen, (unsigned char *)blob, &blen);
blob = PyMem_Realloc(blob, blen);
ret = PyBytes_FromStringAndSize(blob, blen);
PyMem_Free(blob);
return ret;
}
EVP_CIPHER_CTX *cipher_ctx_new(void) {
EVP_CIPHER_CTX *ctx;
if (!(ctx = EVP_CIPHER_CTX_new())) {
PyErr_SetString(PyExc_MemoryError, "cipher_ctx_new");
return NULL;
}
EVP_CIPHER_CTX_reset(ctx);
return ctx;
}
void cipher_ctx_free(EVP_CIPHER_CTX *ctx) {
EVP_CIPHER_CTX_free(ctx);
}
PyObject *bytes_to_key(const EVP_CIPHER *cipher, EVP_MD *md,
PyObject *data, PyObject *salt,
PyObject *iv, /* Not used */
int iter) {
unsigned char key[EVP_MAX_KEY_LENGTH];
const void *dbuf, *sbuf;
int dlen = 0, klen;
Py_ssize_t slen;
PyObject *ret;
if ((m2_PyObject_AsReadBufferInt(data, &dbuf, &dlen) == -1)
|| (m2_PyObject_AsReadBuffer(salt, &sbuf, &slen) == -1))
return NULL;
assert((slen == 8) || (slen == 0));
klen = EVP_BytesToKey(cipher, md, (unsigned char *)sbuf,
(unsigned char *)dbuf, dlen, iter,
key, NULL); /* Since we are not returning IV no need to derive it */
ret = PyBytes_FromStringAndSize((char*)key, klen);
return ret;
}
PyObject *cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
PyObject *key, PyObject *iv, int mode) {
const void *kbuf, *ibuf;
Py_ssize_t klen, ilen;
if (key == Py_None)
kbuf = NULL;
else if (m2_PyObject_AsReadBuffer(key, &kbuf, &klen) == -1)
return NULL;
if (iv == Py_None)
ibuf = NULL;
else if (m2_PyObject_AsReadBuffer(iv, &ibuf, &ilen) == -1)
return NULL;
if (!EVP_CipherInit(ctx, cipher, (unsigned char *)kbuf,
(unsigned char *)ibuf, mode)) {
m2_PyErr_Msg(_evp_err);
return NULL;
}
Py_RETURN_NONE;
}
PyObject *cipher_update(EVP_CIPHER_CTX *ctx, PyObject *blob) {
const void *buf;
int len = 0, olen;
void *obuf;
PyObject *ret;
if (m2_PyObject_AsReadBufferInt(blob, &buf, &len) == -1)
return NULL;
if (!(obuf = PyMem_Malloc(len + EVP_CIPHER_CTX_block_size(ctx) - 1))) {
PyErr_SetString(PyExc_MemoryError, "cipher_update");
return NULL;
}
if (!EVP_CipherUpdate(ctx, obuf, &olen, (unsigned char *)buf, len)) {
PyMem_Free(obuf);
m2_PyErr_Msg(_evp_err);
return NULL;
}
ret = PyBytes_FromStringAndSize(obuf, olen);
PyMem_Free(obuf);
return ret;
}
PyObject *cipher_final(EVP_CIPHER_CTX *ctx) {
void *obuf;
int olen;
PyObject *ret;
if (!(obuf = PyMem_Malloc(EVP_CIPHER_CTX_block_size(ctx)))) {
PyErr_SetString(PyExc_MemoryError, "cipher_final");
return NULL;
}
if (!EVP_CipherFinal(ctx, (unsigned char *)obuf, &olen)) {
PyMem_Free(obuf);
m2_PyErr_Msg(_evp_err);
return NULL;
}
ret = PyBytes_FromStringAndSize(obuf, olen);
PyMem_Free(obuf);
return ret;
}
PyObject *sign_update(EVP_MD_CTX *ctx, PyObject *blob) {
const void *buf;
int len;
if (m2_PyObject_AsReadBufferInt(blob, &buf, &len) == -1)
return NULL;
if (!EVP_SignUpdate(ctx, buf, (Py_ssize_t)len)) {
m2_PyErr_Msg(_evp_err);
return NULL;
}
Py_RETURN_NONE;
}
PyObject *sign_final(EVP_MD_CTX *ctx, EVP_PKEY *pkey) {
PyObject *ret;
unsigned char *sigbuf;
unsigned int siglen = EVP_PKEY_size(pkey);
sigbuf = (unsigned char*)OPENSSL_malloc(siglen);
if (!sigbuf) {
PyErr_SetString(PyExc_MemoryError, "sign_final");
return NULL;
}
if (!EVP_SignFinal(ctx, sigbuf, &siglen, pkey)) {
m2_PyErr_Msg(_evp_err);
OPENSSL_cleanse(sigbuf, siglen);
OPENSSL_free(sigbuf);
return NULL;
}
ret = PyBytes_FromStringAndSize((char*)sigbuf, siglen);
OPENSSL_cleanse(sigbuf, siglen);
OPENSSL_free(sigbuf);
return ret;
}
int verify_update(EVP_MD_CTX *ctx, PyObject *blob) {
const void *buf;
int len;
if (m2_PyObject_AsReadBufferInt(blob, &buf, &len) == -1)
return -1;
return EVP_VerifyUpdate(ctx, buf, (Py_ssize_t)len);
}
int verify_final(EVP_MD_CTX *ctx, PyObject *blob, EVP_PKEY *pkey) {
const void *kbuf = NULL;
int len = 0;
if (m2_PyObject_AsReadBufferInt(blob, &kbuf, &len) == -1)
return -1;
return EVP_VerifyFinal(ctx, (const unsigned char *)kbuf, len, pkey);
}
int digest_sign_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey) {
return EVP_DigestSignInit(ctx, NULL, NULL, NULL, pkey);
}
PyObject *digest_sign_update(EVP_MD_CTX *ctx, PyObject *blob) {
const void *buf;
int len = 0;
if (m2_PyObject_AsReadBufferInt(blob, (const void **)&buf, &len) == -1)
return NULL;
if (!EVP_DigestSignUpdate(ctx, buf, len)) {
m2_PyErr_Msg(_evp_err);
return NULL;
}
Py_RETURN_NONE;
}
PyObject *digest_sign_final(EVP_MD_CTX *ctx) {
PyObject *ret;
unsigned char *sigbuf;
size_t siglen;
if (!EVP_DigestSignFinal(ctx, NULL, &siglen)) {
m2_PyErr_Msg(_evp_err);
return NULL;
}
sigbuf = (unsigned char*)OPENSSL_malloc(siglen);
if (!sigbuf) {
PyErr_SetString(PyExc_MemoryError, "digest_sign_final");
return NULL;
}
if (!EVP_DigestSignFinal(ctx, sigbuf, &siglen)) {
m2_PyErr_Msg(_evp_err);
OPENSSL_cleanse(sigbuf, siglen);
OPENSSL_free(sigbuf);
return NULL;
}
ret = PyBytes_FromStringAndSize((char*)sigbuf, siglen);
OPENSSL_cleanse(sigbuf, siglen);
OPENSSL_free(sigbuf);
return ret;
}
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
PyObject *digest_sign(EVP_MD_CTX *ctx, PyObject *msg) {
PyObject *ret;
const void *msgbuf;
unsigned char *sigbuf;
int msglen = 0;
size_t siglen = 0;
if (m2_PyObject_AsReadBufferInt(msg, (const void **)&msgbuf, &msglen) == -1)
return NULL;
if (!EVP_DigestSign(ctx, NULL, &siglen, msgbuf, msglen)) {
m2_PyErr_Msg(_evp_err);
return NULL;
}
sigbuf = (unsigned char*)OPENSSL_malloc(siglen);
if (!sigbuf) {
PyErr_SetString(PyExc_MemoryError, "digest_sign");
return NULL;
}
if (!EVP_DigestSign(ctx, sigbuf, &siglen, msgbuf, msglen)) {
m2_PyErr_Msg(_evp_err);
OPENSSL_cleanse(sigbuf, siglen);
OPENSSL_free(sigbuf);
return NULL;
}
ret = PyBytes_FromStringAndSize((char*)sigbuf, siglen);
OPENSSL_cleanse(sigbuf, siglen);
OPENSSL_free(sigbuf);
return ret;
}
#endif
int digest_verify_init(EVP_MD_CTX *ctx, EVP_PKEY *pkey) {
return EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, pkey);
}
int digest_verify_update(EVP_MD_CTX *ctx, PyObject *blob) {
const void *buf = NULL;
int len = 0;
if (m2_PyObject_AsReadBufferInt(blob, (const void **)&buf, &len) == -1)
return -1;
return EVP_DigestVerifyUpdate(ctx, buf, len);
}
int digest_verify_final(EVP_MD_CTX *ctx, PyObject *blob) {
unsigned char *sigbuf = NULL;
int len = 0;
if (m2_PyObject_AsReadBufferInt(blob, (const void **)&sigbuf, &len) == -1)
return -1;
return EVP_DigestVerifyFinal(ctx, sigbuf, len);
}
#if OPENSSL_VERSION_NUMBER >= 0x10101000L
int digest_verify(EVP_MD_CTX *ctx, PyObject *sig, PyObject *msg) {
unsigned char *sigbuf;
unsigned char *msgbuf;
int siglen = 0;
int msglen = 0;
if (m2_PyObject_AsReadBufferInt(sig, (const void **)&sigbuf, &siglen) == -1)
return -1;
if (m2_PyObject_AsReadBufferInt(msg, (const void **)&msgbuf, &msglen) == -1)
return -1;
return EVP_DigestVerify(ctx, sigbuf, siglen, msgbuf, msglen);
}
#endif
%}
%typemap(out) EVP_MD * {
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
if ($1 != NULL)
$result = SWIG_NewPointerObj($1, $1_descriptor, 0);
else {
$result = NULL;
}
}
%inline %{
const EVP_MD *get_digestbyname(const char* name) {
const EVP_MD *ret = NULL;
if ((ret = EVP_get_digestbyname(name)) == NULL) {
m2_PyErr_Msg(_evp_err);
}
return ret;
}
%}
%typemap(out) EVP_MD *;
%inline %{
int pkey_write_pem_no_cipher(EVP_PKEY *pkey, BIO *f, PyObject *pyfunc) {
int ret;
Py_INCREF(pyfunc);
Py_BEGIN_ALLOW_THREADS
ret = PEM_write_bio_PKCS8PrivateKey(f, pkey, NULL, NULL, 0,
passphrase_callback, (void *)pyfunc);
Py_END_ALLOW_THREADS
Py_DECREF(pyfunc);
return ret;
}
%}
%inline %{
int pkey_write_pem(EVP_PKEY *pkey, BIO *f, EVP_CIPHER *cipher, PyObject *pyfunc) {
int ret;
Py_INCREF(pyfunc);
Py_BEGIN_ALLOW_THREADS
ret = PEM_write_bio_PKCS8PrivateKey(f, pkey, cipher, NULL, 0,
passphrase_callback, (void *)pyfunc);
Py_END_ALLOW_THREADS
Py_DECREF(pyfunc);
return ret;
}
%}
%typemap(out) EVP_PKEY * {
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
if ($1 != NULL)
$result = SWIG_NewPointerObj($1, $1_descriptor, 0);
else {
$result = NULL;
}
}
%inline %{
EVP_PKEY *pkey_new(void) {
EVP_PKEY *ret;
if ((ret = EVP_PKEY_new()) == NULL) {
PyErr_Format(PyExc_MemoryError,
"Insufficient memory for new key in function %s.", __FUNCTION__);
}
return ret;
}
EVP_PKEY *pkey_read_pem(BIO *f, PyObject *pyfunc) {
EVP_PKEY *pk;
Py_INCREF(pyfunc);
Py_BEGIN_ALLOW_THREADS
pk = PEM_read_bio_PrivateKey(f, NULL, passphrase_callback, (void *)pyfunc);
Py_END_ALLOW_THREADS
Py_DECREF(pyfunc);
if (pk == NULL) {
PyErr_Format(_evp_err,
"Unable to read private key in function %s.", __FUNCTION__);
}
return pk;
}
EVP_PKEY *pkey_read_pem_pubkey(BIO *f, PyObject *pyfunc) {
EVP_PKEY *pk;
Py_INCREF(pyfunc);
Py_BEGIN_ALLOW_THREADS
pk = PEM_read_bio_PUBKEY(f, NULL, passphrase_callback, (void *)pyfunc);
Py_END_ALLOW_THREADS
Py_DECREF(pyfunc);
if (pk == NULL) {
PyErr_Format(_evp_err,
"Unable to read public key in function %s.", __FUNCTION__);
}
return pk;
}
%}
%typemap(out) EVP_PKEY * ;
%inline %{
int pkey_assign_rsa(EVP_PKEY *pkey, RSA *rsa) {
return EVP_PKEY_assign_RSA(pkey, rsa);
}
PyObject *pkey_as_der(EVP_PKEY *pkey) {
unsigned char * pp = NULL;
int len;
PyObject * der;
len = i2d_PUBKEY(pkey, &pp);
if (len < 0){
PyErr_SetString(_evp_err, "EVP_PKEY as DER failed");
return NULL;
}
der = PyBytes_FromStringAndSize((char*)pp, len);
OPENSSL_free(pp);
return der;
}
PyObject *pkey_get_modulus(EVP_PKEY *pkey)
{
RSA *rsa;
DSA *dsa;
BIO *bio;
BUF_MEM *bptr;
PyObject *ret;
const BIGNUM* bn;
switch (EVP_PKEY_base_id(pkey)) {
case EVP_PKEY_RSA:
rsa = EVP_PKEY_get1_RSA(pkey);
bio = BIO_new(BIO_s_mem());
if (!bio) {
RSA_free(rsa);
PyErr_SetString(PyExc_MemoryError, "pkey_get_modulus");
return NULL;
}
RSA_get0_key(rsa, &bn, NULL, NULL);
if (!BN_print(bio, bn)) {
m2_PyErr_Msg(PyExc_RuntimeError);
BIO_free(bio);
RSA_free(rsa);
return NULL;
}
BIO_get_mem_ptr(bio, &bptr);
ret = PyBytes_FromStringAndSize(bptr->data, bptr->length);
(void)BIO_set_close(bio, BIO_CLOSE);
BIO_free(bio);
RSA_free(rsa);
return ret;
break;
case EVP_PKEY_DSA:
dsa = EVP_PKEY_get1_DSA(pkey);
bio = BIO_new(BIO_s_mem());
if (!bio) {
DSA_free(dsa);
PyErr_SetString(PyExc_MemoryError, "pkey_get_modulus");
return NULL;
}
DSA_get0_key(dsa, &bn, NULL);
if (!BN_print(bio, bn)) {
m2_PyErr_Msg(PyExc_RuntimeError);
BIO_free(bio);
DSA_free(dsa);
return NULL;
}
BIO_get_mem_ptr(bio, &bptr);
ret = PyBytes_FromStringAndSize(bptr->data, bptr->length);
(void)BIO_set_close(bio, BIO_CLOSE);
BIO_free(bio);
DSA_free(dsa);
return ret;
break;
default:
PyErr_SetString(_evp_err, "unsupported key type");
return NULL;
}
}
%}
m2crypto-0.42.0/src/SWIG/_lib.h 0000664 0000000 0000000 00000002070 14655756567 0016023 0 ustar 00root root 0000000 0000000 /* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. */
/* $Id$ */
#include
typedef struct _blob {
unsigned char *data;
int len;
} Blob;
Blob *blob_new(int len, const char *errmsg);
Blob *blob_copy(Blob *from, const char *errmsg);
void blob_free(Blob *blob);
static int m2_PyObject_AsReadBuffer(PyObject *obj, const void **buffer,
Py_ssize_t *buffer_len);
static int m2_PyObject_AsReadBufferInt(PyObject *obj, const void **buffer,
int *buffer_len);
static int m2_PyString_AsStringAndSizeInt(PyObject *obj, char **s, int *len);
static BIGNUM* m2_PyObject_AsBIGNUM(PyObject* value, PyObject* _py_exc) ;
/* Always use these two together, to correctly handle non-memoryview objects. */
static int m2_PyObject_GetBufferInt(PyObject *obj, Py_buffer *view, int flags);
static void m2_PyBuffer_Release(PyObject *obj, Py_buffer *view);
int bn_gencb_callback(int p, int n, BN_GENCB *gencb);
int passphrase_callback(char *buf, int num, int v, void *userdata);
void lib_init(void);
m2crypto-0.42.0/src/SWIG/_lib.i 0000664 0000000 0000000 00000050013 14655756567 0016024 0 ustar 00root root 0000000 0000000 /* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. */
/* $Id$ */
%{
#include
#include
#include
#include
#include
#include
#include
#include
#include
%}
/* OpenSSL 1.1 compatibility shim */
%include _lib11_compat.i
/* Python 3 compatibility shim */
%include _py3k_compat.i
%{
/* OpenSSL 1.0.2 copmatbility shim */
#if OPENSSL_VERSION_NUMBER < 0x10002000L
typedef void (*OPENSSL_sk_freefunc)(void *);
typedef void *(*OPENSSL_sk_copyfunc)(const void *);
typedef struct stack_st OPENSSL_STACK;
# define MIN_NODES 4
# define sk_deep_copy OPENSSL_sk_deep_copy
void OPENSSL_sk_free(OPENSSL_STACK *st)
{
if (st == NULL)
return;
OPENSSL_free(st->data);
OPENSSL_free(st);
}
OPENSSL_STACK *OPENSSL_sk_deep_copy(const OPENSSL_STACK *sk,
OPENSSL_sk_copyfunc copy_func,
OPENSSL_sk_freefunc free_func)
{
OPENSSL_STACK *ret;
int i;
if (sk->num < 0)
return NULL;
if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL)
return NULL;
/* direct structure assignment */
*ret = *sk;
ret->num_alloc = sk->num > MIN_NODES ? (size_t)sk->num : MIN_NODES;
ret->data = OPENSSL_zalloc(sizeof(*ret->data) * ret->num_alloc);
if (ret->data == NULL) {
OPENSSL_free(ret);
return NULL;
}
for (i = 0; i < ret->num; ++i) {
if (sk->data[i] == NULL)
continue;
if ((ret->data[i] = copy_func(sk->data[i])) == NULL) {
while (--i >= 0)
if (ret->data[i] != NULL)
free_func((void *)ret->data[i]);
OPENSSL_sk_free(ret);
return NULL;
}
}
return ret;
}
#endif /* OpenSSL 1.0.2 copmatbility shim */
/* Blob interface. Deprecated. */
Blob *blob_new(int len, const char *errmsg) {
Blob *blob;
if (!(blob=(Blob *)PyMem_Malloc(sizeof(Blob)))){
PyErr_SetString(PyExc_MemoryError, errmsg);
return NULL;
}
if (!(blob->data=(unsigned char *)PyMem_Malloc(len))) {
PyMem_Free(blob);
PyErr_SetString(PyExc_MemoryError, errmsg);
return NULL;
}
blob->len=len;
return blob;
}
Blob *blob_copy(Blob *from, const char *errmsg) {
Blob *blob=blob_new(from->len, errmsg);
if (!blob) {
PyErr_SetString(PyExc_MemoryError, errmsg);
return NULL;
}
memcpy(blob->data, from->data, from->len);
return blob;
}
void blob_free(Blob *blob) {
PyMem_Free(blob->data);
PyMem_Free(blob);
}
/* Python helpers. */
%}
%ignore PyObject_CheckBuffer;
%ignore PyObject_GetBuffer;
%ignore PyBuffer_Release;
%ignore m2_PyObject_AsReadBuffer;
%ignore m2_PyObject_AsReadBufferInt;
%ignore m2_PyObject_GetBufferInt;
%ignore m2_PyBuffer_Release;
%ignore m2_PyString_AsStringAndSizeInt;
%newobject mpi_to_bn;
%newobject bin_to_bn;
%nodefaultctor bignum_st;
struct bignum_st {};
typedef struct bignum_st BIGNUM;
%extend bignum_st {
~bignum_st() {
BN_free($self);
}
};
%{
static int
m2_PyObject_AsReadBuffer(PyObject * obj, const void **buffer,
Py_ssize_t * buffer_len)
{
Py_ssize_t len = 0;
Py_buffer view;
if (PyObject_CheckBuffer(obj)) {
if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) == 0) {
*buffer = view.buf;
len = view.len;
}
} else {
PyErr_SetString(PyExc_TypeError, "expected a readable buffer object");
return -1;
}
if (len > INT_MAX) {
m2_PyBuffer_Release(obj, &view);
PyErr_SetString(PyExc_ValueError, "object too large");
return -1;
}
*buffer_len = len;
m2_PyBuffer_Release(obj, &view);
return 0;
}
static int
m2_PyObject_AsReadBufferInt(PyObject * obj, const void **buffer,
int *buffer_len)
{
int ret = 0;
Py_ssize_t len = 0;
ret = m2_PyObject_AsReadBuffer(obj, buffer, &len);
*buffer_len = len;
return ret;
}
static int m2_PyObject_GetBufferInt(PyObject *obj, Py_buffer *view, int flags)
{
int ret;
if (PyObject_CheckBuffer(obj))
ret = PyObject_GetBuffer(obj, view, flags);
else {
PyErr_SetString(PyExc_TypeError, "expected a readable buffer object");
return -1;
}
if (ret)
return ret;
if (view->len > INT_MAX) {
PyErr_SetString(PyExc_ValueError, "object too large");
m2_PyBuffer_Release(obj, view);
return -1;
}
return 0;
}
static BIGNUM*
m2_PyObject_AsBIGNUM(PyObject* value, PyObject* _py_exc)
{
BIGNUM* bn;
const void* vbuf;
int vlen = 0;
if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1)
return NULL;
if (!(bn = BN_mpi2bn((unsigned char *)vbuf, vlen, NULL))) {
PyErr_SetString(_py_exc, ERR_reason_error_string(ERR_get_error()));
return NULL;
}
return bn;
}
static void m2_PyBuffer_Release(PyObject *obj, Py_buffer *view)
{
if (PyObject_CheckBuffer(obj))
PyBuffer_Release(view);
/* else do nothing, view->buf comes from PyObject_AsReadBuffer */
}
static int
m2_PyString_AsStringAndSizeInt(PyObject *obj, char **s, int *len)
{
int ret;
Py_ssize_t len2;
ret = PyBytes_AsStringAndSize(obj, s, &len2);
if (ret)
return ret;
if (len2 > INT_MAX) {
PyErr_SetString(PyExc_ValueError, "string too large");
return -1;
}
*len = len2;
return 0;
}
/* Works as PyFile_Name, but always returns a new object. */
PyObject *m2_PyFile_Name(PyObject *pyfile) {
PyObject *out = NULL;
#if PY_MAJOR_VERSION >= 3
out = PyObject_GetAttrString(pyfile, "name");
#else
out = PyFile_Name(pyfile);
Py_XINCREF(out);
#endif
return out;
}
/* Yes, __FUNCTION__ is a non-standard symbol, but it is supported by
* both gcc and MSVC. */
#define m2_PyErr_Msg(type) m2_PyErr_Msg_Caller(type, (const char*) __FUNCTION__)
static void m2_PyErr_Msg_Caller(PyObject *err_type, const char* caller) {
const char *err_reason;
const char *data;
int flags;
/* This max size of a (longer than ours) OpenSSL error string is hardcoded
* in OpenSSL's crypto/err/err_prn.c:ERR_print_errors_cb() */
char err_msg[4096];
unsigned long err_code = ERR_get_error_line_data(NULL, NULL, &data, &flags);
if (err_code != 0) {
err_reason = ERR_reason_error_string(err_code);
if (data && (flags & ERR_TXT_STRING))
snprintf(err_msg, sizeof(err_msg), "%s (%s)", err_reason, data);
else
snprintf(err_msg, sizeof(err_msg), "%s", err_reason);
PyErr_SetString(err_type, err_msg);
} else {
PyErr_Format(err_type, "Unknown error in function %s.", caller);
}
}
/* C callbacks invoked by OpenSSL; these in turn call back into
Python. */
int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) {
PyObject *argv, *ret;
PyObject *_x509_store_ctx_swigptr=0, *_x509_store_ctx_obj=0, *_x509_store_ctx_inst=0, *_klass=0;
PyObject *_x509=0, *_ssl_ctx=0;
SSL *ssl;
SSL_CTX *ssl_ctx;
X509 *x509;
int errnum, errdepth;
int cret;
int new_style_callback = 0, warning_raised_exception=0;
PyGILState_STATE gilstate;
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
ssl = (SSL *)X509_STORE_CTX_get_app_data(ctx);
gilstate = PyGILState_Ensure();
if (PyMethod_Check(ssl_verify_cb_func)) {
PyObject *func;
PyCodeObject *code;
func = PyMethod_Function(ssl_verify_cb_func);
code = (PyCodeObject *) PyFunction_GetCode(func);
if (code && code->co_argcount == 3) { /* XXX Python internals */
new_style_callback = 1;
}
} else if (PyFunction_Check(ssl_verify_cb_func)) {
PyCodeObject *code = (PyCodeObject *) PyFunction_GetCode(ssl_verify_cb_func);
if (code && code->co_argcount == 2) { /* XXX Python internals */
new_style_callback = 1;
}
} else {
/* XXX There are lots of other callable types, but we will assume
* XXX that any other type of callable uses the new style callback,
* XXX although this is not entirely safe assumption.
*/
new_style_callback = 1;
}
if (new_style_callback) {
PyObject *x509mod;
x509mod = PyDict_GetItemString(PyImport_GetModuleDict(), "M2Crypto.X509");
_klass = PyObject_GetAttrString(x509mod, "X509_Store_Context");
_x509_store_ctx_swigptr = SWIG_NewPointerObj((void *)ctx, SWIGTYPE_p_X509_STORE_CTX, 0);
_x509_store_ctx_obj = Py_BuildValue("(Oi)", _x509_store_ctx_swigptr, 0);
_x509_store_ctx_inst = PyObject_CallObject(_klass, _x509_store_ctx_obj);
argv = Py_BuildValue("(iO)", ok, _x509_store_ctx_inst);
} else {
if (PyErr_Warn(PyExc_DeprecationWarning, "Old style callback, use cb_func(ok, store) instead")) {
warning_raised_exception = 1;
}
x509 = X509_STORE_CTX_get_current_cert(ctx);
errnum = X509_STORE_CTX_get_error(ctx);
errdepth = X509_STORE_CTX_get_error_depth(ctx);
ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
ssl_ctx = SSL_get_SSL_CTX(ssl);
_x509 = SWIG_NewPointerObj((void *)x509, SWIGTYPE_p_X509, 0);
_ssl_ctx = SWIG_NewPointerObj((void *)ssl_ctx, SWIGTYPE_p_SSL_CTX, 0);
argv = Py_BuildValue("(OOiii)", _ssl_ctx, _x509, errnum, errdepth, ok);
}
if (!warning_raised_exception) {
ret = PyObject_CallObject(ssl_verify_cb_func, argv);
} else {
ret = 0;
}
if (!ret) {
/* Got an exception in PyObject_CallObject(), let's fail verification
* to be safe.
*/
cret = 0;
} else {
/* FIXME This is possibly problematic if ret > MAXINT */
cret = (int)PyLong_AsLong(ret);
}
Py_XDECREF(ret);
Py_XDECREF(argv);
if (new_style_callback) {
Py_XDECREF(_x509_store_ctx_inst);
Py_XDECREF(_x509_store_ctx_obj);
Py_XDECREF(_x509_store_ctx_swigptr);
Py_XDECREF(_klass);
} else {
Py_XDECREF(_x509);
Py_XDECREF(_ssl_ctx);
}
PyGILState_Release(gilstate);
return cret;
}
int x509_store_verify_callback(int ok, X509_STORE_CTX *ctx) {
PyGILState_STATE gilstate;
PyObject *argv, *ret;
PyObject *_x509_store_ctx_swigptr=0, *_x509_store_ctx_obj=0, *_x509_store_ctx_inst=0, *_klass=0;
int cret;
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
PyObject *x509mod;
gilstate = PyGILState_Ensure();
/* Below, handle only what is called 'new style callback' in ssl_verify_callback().
TODO: does 'old style callback' exist any more? */
x509mod = PyDict_GetItemString(PyImport_GetModuleDict(), "M2Crypto.X509");
_klass = PyObject_GetAttrString(x509mod, "X509_Store_Context");
_x509_store_ctx_swigptr = SWIG_NewPointerObj((void *)ctx, SWIGTYPE_p_X509_STORE_CTX, 0);
_x509_store_ctx_obj = Py_BuildValue("(Oi)", _x509_store_ctx_swigptr, 0);
_x509_store_ctx_inst = PyObject_CallObject(_klass, _x509_store_ctx_obj);
argv = Py_BuildValue("(iO)", ok, _x509_store_ctx_inst);
ret = PyObject_CallObject(x509_store_verify_cb_func, argv);
if (!ret) {
/* Got an exception in PyObject_CallObject(), let's fail verification
* to be safe.
*/
cret = 0;
} else {
cret = (int)PyInt_AsLong(ret);
}
Py_XDECREF(ret);
Py_XDECREF(argv);
Py_XDECREF(_x509_store_ctx_inst);
Py_XDECREF(_x509_store_ctx_obj);
Py_XDECREF(_x509_store_ctx_swigptr);
Py_XDECREF(_klass);
PyGILState_Release(gilstate);
return cret;
}
void ssl_info_callback(const SSL *s, int where, int ret) {
PyObject *argv, *retval, *_SSL;
PyGILState_STATE gilstate;
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
gilstate = PyGILState_Ensure();
_SSL = SWIG_NewPointerObj((void *)s, SWIGTYPE_p_SSL, 0);
argv = Py_BuildValue("(iiO)", where, ret, _SSL);
retval = PyObject_CallObject(ssl_info_cb_func, argv);
Py_XDECREF(retval);
Py_XDECREF(argv);
Py_XDECREF(_SSL);
PyGILState_Release(gilstate);
}
DH *ssl_set_tmp_dh_callback(SSL *ssl, int is_export, int keylength) {
PyObject *argv, *ret, *_ssl;
DH *dh;
PyGILState_STATE gilstate;
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
gilstate = PyGILState_Ensure();
_ssl = SWIG_NewPointerObj((void *)ssl, SWIGTYPE_p_SSL, 0);
argv = Py_BuildValue("(Oii)", _ssl, is_export, keylength);
ret = PyObject_CallObject(ssl_set_tmp_dh_cb_func, argv);
if ((SWIG_ConvertPtr(ret, (void **)&dh, SWIGTYPE_p_DH, SWIG_POINTER_EXCEPTION | 0)) == -1)
dh = NULL;
Py_XDECREF(ret);
Py_XDECREF(argv);
Py_XDECREF(_ssl);
PyGILState_Release(gilstate);
return dh;
}
RSA *ssl_set_tmp_rsa_callback(SSL *ssl, int is_export, int keylength) {
PyObject *argv, *ret, *_ssl;
RSA *rsa;
PyGILState_STATE gilstate;
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
gilstate = PyGILState_Ensure();
_ssl = SWIG_NewPointerObj((void *)ssl, SWIGTYPE_p_SSL, 0);
argv = Py_BuildValue("(Oii)", _ssl, is_export, keylength);
ret = PyObject_CallObject(ssl_set_tmp_rsa_cb_func, argv);
if ((SWIG_ConvertPtr(ret, (void **)&rsa, SWIGTYPE_p_RSA, SWIG_POINTER_EXCEPTION | 0)) == -1)
rsa = NULL;
Py_XDECREF(ret);
Py_XDECREF(argv);
Py_XDECREF(_ssl);
PyGILState_Release(gilstate);
return rsa;
}
/* Universal callback for dh_generate_parameters,
* dsa_generate_parametersm, and rsa_generate_key */
int bn_gencb_callback(int p, int n, BN_GENCB *gencb) {
PyObject *argv, *ret, *cbfunc;
cbfunc = (PyObject *)BN_GENCB_get_arg(gencb);
argv = Py_BuildValue("(ii)", p, n);
ret = PyObject_CallObject(cbfunc, argv);
PyErr_Clear();
Py_DECREF(argv);
Py_XDECREF(ret);
return 1;
}
int passphrase_callback(char *buf, int num, int v, void *arg) {
int i;
Py_ssize_t len;
char *str;
PyObject *argv, *ret, *cbfunc;
PyGILState_STATE gilstate;
gilstate = PyGILState_Ensure();
cbfunc = (PyObject *)arg;
argv = Py_BuildValue("(i)", v);
/* PyObject_CallObject sets exception, if needed. */
ret = PyObject_CallObject(cbfunc, argv);
Py_DECREF(argv);
if (ret == NULL) {
PyGILState_Release(gilstate);
return -1;
}
if (!PyBytes_Check(ret)) {
PyErr_SetString(PyExc_RuntimeError,
"Result of callback is not bytes().");
Py_DECREF(ret);
PyGILState_Release(gilstate);
return -1;
}
if ((len = PyBytes_Size(ret)) > num)
len = num;
str = PyBytes_AsString(ret);
for (i = 0; i < len; i++)
buf[i] = str[i];
Py_DECREF(ret);
PyGILState_Release(gilstate);
return len;
}
%}
%inline %{
void lib_init() {
#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSLeay_add_all_algorithms();
ERR_load_ERR_strings();
#endif
}
/* Bignum routines that aren't not numerous enough to
warrant a separate file. */
PyObject *bn_to_mpi(const BIGNUM *bn) {
int len = 0;
unsigned char *mpi;
PyObject *pyo;
len = BN_bn2mpi(bn, NULL);
if (!(mpi=(unsigned char *)PyMem_Malloc(len))) {
m2_PyErr_Msg(PyExc_MemoryError);
return NULL;
}
len=BN_bn2mpi(bn, mpi);
pyo=PyBytes_FromStringAndSize((const char *)mpi, len);
PyMem_Free(mpi);
return pyo;
}
const BIGNUM *mpi_to_bn(PyObject *value) {
const void *vbuf = NULL;
int vlen = 0;
if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1)
return NULL;
return BN_mpi2bn(vbuf, vlen, NULL);
}
PyObject *bn_to_bin(BIGNUM *bn) {
int len = 0;
unsigned char *bin;
PyObject *pyo;
len = BN_num_bytes(bn);
if (!(bin=(unsigned char *)PyMem_Malloc(len))) {
PyErr_SetString(PyExc_MemoryError, "bn_to_bin");
return NULL;
}
BN_bn2bin(bn, bin);
pyo=PyBytes_FromStringAndSize((const char *)bin, len);
PyMem_Free(bin);
return pyo;
}
const BIGNUM *bin_to_bn(PyObject *value) {
const void *vbuf = NULL;
int vlen = 0;
if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1)
return NULL;
return BN_bin2bn(vbuf, vlen, NULL);
}
PyObject *bn_to_hex(BIGNUM *bn) {
char *hex;
PyObject *pyo;
Py_ssize_t len = 0;
hex = BN_bn2hex(bn);
if (!hex) {
m2_PyErr_Msg(PyExc_RuntimeError);
OPENSSL_free(hex);
return NULL;
}
len = strlen(hex);
pyo=PyBytes_FromStringAndSize(hex, len);
OPENSSL_free(hex);
return pyo;
}
BIGNUM *hex_to_bn(PyObject *value) {
const void *vbuf = NULL;
Py_ssize_t vlen = 0;
BIGNUM *bn;
Py_buffer view;
if (PyObject_CheckBuffer(value)) {
if (PyObject_GetBuffer(value, &view, PyBUF_SIMPLE) == 0) {
vbuf = view.buf;
vlen = view.len;
}
}
else {
if (m2_PyObject_AsReadBuffer(value, &vbuf, &vlen) == -1)
return NULL;
}
if ((bn=BN_new())==NULL) {
m2_PyBuffer_Release(value, &view);
PyErr_SetString(PyExc_MemoryError, "hex_to_bn");
return NULL;
}
if (BN_hex2bn(&bn, (const char *)vbuf) <= 0) {
m2_PyBuffer_Release(value, &view);
m2_PyErr_Msg(PyExc_RuntimeError);
BN_free(bn);
return NULL;
}
m2_PyBuffer_Release(value, &view);
return bn;
}
BIGNUM *dec_to_bn(PyObject *value) {
const void *vbuf = NULL;
Py_ssize_t vlen = 0;
BIGNUM *bn;
Py_buffer view;
if (PyObject_CheckBuffer(value)) {
if (PyObject_GetBuffer(value, &view, PyBUF_SIMPLE) == 0) {
vbuf = view.buf;
vlen = view.len;
}
}
else {
if (m2_PyObject_AsReadBuffer(value, &vbuf, &vlen) == -1)
return NULL;
}
if ((bn=BN_new())==NULL) {
m2_PyBuffer_Release(value, &view);
PyErr_SetString(PyExc_MemoryError, "dec_to_bn");
return NULL;
}
if ((BN_dec2bn(&bn, (const char *)vbuf) <= 0)) {
m2_PyBuffer_Release(value, &view);
m2_PyErr_Msg(PyExc_RuntimeError);
BN_free(bn);
return NULL;
}
m2_PyBuffer_Release(value, &view);
return bn;
}
%}
/* Various useful typemaps. */
%typemap(in) Blob * {
Py_ssize_t len = 0;
if (!PyBytes_Check($input)) {
PyErr_SetString(PyExc_TypeError, "expected PyString");
return NULL;
}
len=PyBytes_Size($input);
if (len > INT_MAX) {
PyErr_SetString(PyExc_ValueError, "object too large");
return NULL;
}
$1=(Blob *)PyMem_Malloc(sizeof(Blob));
if (!$1) {
PyErr_SetString(PyExc_MemoryError, "malloc Blob");
return NULL;
}
$1->data=(unsigned char *)PyBytes_AsString($input);
$1->len=len;
}
%typemap(out) Blob * {
if ($1==NULL) {
Py_INCREF(Py_None);
$result=Py_None;
} else {
$result=PyBytes_FromStringAndSize((const char *)$1->data, $1->len);
PyMem_Free($1->data);
PyMem_Free($1);
}
}
%typemap(in) PyObject *pyfunc {
if (!PyCallable_Check($input)) {
PyErr_SetString(PyExc_TypeError, "expected PyCallable");
return NULL;
}
$1=$input;
}
%typemap(in) PyObject *pyblob {
if (!PyBytes_Check($input)) {
PyErr_SetString(PyExc_TypeError, "expected PyString");
return NULL;
}
$1=$input;
}
%typemap(in) PyObject * {
$1=$input;
}
%typemap(out) PyObject * {
$result=$1;
}
%typemap(out) int {
$result=PyLong_FromLong($1);
if (PyErr_Occurred()) SWIG_fail;
}
/* Pointer checks. */
%apply Pointer NONNULL { Blob * };
/* A bunch of "straight-thru" functions. */
%rename(err_print_errors) ERR_print_errors;
%threadallow ERR_print_errors;
extern void ERR_print_errors(BIO *);
%rename(err_clear_error) ERR_clear_error;
extern void ERR_clear_error(void);
%rename(err_get_error) ERR_get_error;
extern unsigned long ERR_get_error(void);
%rename(err_peek_error) ERR_peek_error;
extern unsigned long ERR_peek_error(void);
%rename(err_lib_error_string) ERR_lib_error_string;
extern const char *ERR_lib_error_string(unsigned long);
%rename(err_func_error_string) ERR_func_error_string;
extern const char *ERR_func_error_string(unsigned long);
%rename(err_reason_error_string) ERR_reason_error_string;
extern const char *ERR_reason_error_string(unsigned long);
m2crypto-0.42.0/src/SWIG/_lib11_compat.i 0000664 0000000 0000000 00000023066 14655756567 0017541 0 ustar 00root root 0000000 0000000 /*
* Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
%{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#include
#include
# define OPENSSL_zalloc(num) \
CRYPTO_zalloc(num, __FILE__, __LINE__)
static void *CRYPTO_zalloc(size_t num, const char *file, int line)
{
void *ret = CRYPTO_malloc(num, file, line);
if (ret != NULL)
memset(ret, 0, num);
return ret;
}
#include
#ifndef BN_F_BN_GENCB_NEW
# define BN_F_BN_GENCB_NEW 143
#endif
# define BN_GENCB_get_arg(gencb) ((gencb)->arg)
BN_GENCB *BN_GENCB_new(void)
{
BN_GENCB *ret;
if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL) {
BNerr(BN_F_BN_GENCB_NEW, ERR_R_MALLOC_FAILURE);
return (NULL);
}
return ret;
}
void BN_GENCB_free(BN_GENCB *cb)
{
if (cb == NULL)
return;
OPENSSL_free(cb);
}
int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
{
/* If the fields n and e in r are NULL, the corresponding input
* parameters MUST be non-NULL for n and e. d may be
* left NULL (in case only the public key is used).
*/
if ((r->n == NULL && n == NULL)
|| (r->e == NULL && e == NULL))
return 0;
if (n != NULL) {
BN_free(r->n);
r->n = n;
}
if (e != NULL) {
BN_free(r->e);
r->e = e;
}
if (d != NULL) {
BN_free(r->d);
r->d = d;
}
return 1;
}
int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
{
/* If the fields p and q in r are NULL, the corresponding input
* parameters MUST be non-NULL.
*/
if ((r->p == NULL && p == NULL)
|| (r->q == NULL && q == NULL))
return 0;
if (p != NULL) {
BN_free(r->p);
r->p = p;
}
if (q != NULL) {
BN_free(r->q);
r->q = q;
}
return 1;
}
int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
{
/* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input
* parameters MUST be non-NULL.
*/
if ((r->dmp1 == NULL && dmp1 == NULL)
|| (r->dmq1 == NULL && dmq1 == NULL)
|| (r->iqmp == NULL && iqmp == NULL))
return 0;
if (dmp1 != NULL) {
BN_free(r->dmp1);
r->dmp1 = dmp1;
}
if (dmq1 != NULL) {
BN_free(r->dmq1);
r->dmq1 = dmq1;
}
if (iqmp != NULL) {
BN_free(r->iqmp);
r->iqmp = iqmp;
}
return 1;
}
void RSA_get0_key(const RSA *r,
const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
{
if (n != NULL)
*n = r->n;
if (e != NULL)
*e = r->e;
if (d != NULL)
*d = r->d;
}
void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
{
if (p != NULL)
*p = r->p;
if (q != NULL)
*q = r->q;
}
void RSA_get0_crt_params(const RSA *r,
const BIGNUM **dmp1, const BIGNUM **dmq1,
const BIGNUM **iqmp)
{
if (dmp1 != NULL)
*dmp1 = r->dmp1;
if (dmq1 != NULL)
*dmq1 = r->dmq1;
if (iqmp != NULL)
*iqmp = r->iqmp;
}
void DSA_get0_pqg(const DSA *d,
const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
{
if (p != NULL)
*p = d->p;
if (q != NULL)
*q = d->q;
if (g != NULL)
*g = d->g;
}
int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{
/* If the fields p, q and g in d are NULL, the corresponding input
* parameters MUST be non-NULL.
*/
if ((d->p == NULL && p == NULL)
|| (d->q == NULL && q == NULL)
|| (d->g == NULL && g == NULL))
return 0;
if (p != NULL) {
BN_free(d->p);
d->p = p;
}
if (q != NULL) {
BN_free(d->q);
d->q = q;
}
if (g != NULL) {
BN_free(d->g);
d->g = g;
}
return 1;
}
void DSA_get0_key(const DSA *d,
const BIGNUM **pub_key, const BIGNUM **priv_key)
{
if (pub_key != NULL)
*pub_key = d->pub_key;
if (priv_key != NULL)
*priv_key = d->priv_key;
}
int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
{
/* If the field pub_key in d is NULL, the corresponding input
* parameters MUST be non-NULL. The priv_key field may
* be left NULL.
*/
if (d->pub_key == NULL && pub_key == NULL)
return 0;
if (pub_key != NULL) {
BN_free(d->pub_key);
d->pub_key = pub_key;
}
if (priv_key != NULL) {
BN_free(d->priv_key);
d->priv_key = priv_key;
}
return 1;
}
void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{
if (pr != NULL)
*pr = sig->r;
if (ps != NULL)
*ps = sig->s;
}
int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
{
if (r == NULL || s == NULL)
return 0;
BN_clear_free(sig->r);
BN_clear_free(sig->s);
sig->r = r;
sig->s = s;
return 1;
}
void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{
if (pr != NULL)
*pr = sig->r;
if (ps != NULL)
*ps = sig->s;
}
int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
{
if (r == NULL || s == NULL)
return 0;
BN_clear_free(sig->r);
BN_clear_free(sig->s);
sig->r = r;
sig->s = s;
return 1;
}
void DH_get0_pqg(const DH *dh,
const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
{
if (p != NULL)
*p = dh->p;
if (q != NULL)
*q = dh->q;
if (g != NULL)
*g = dh->g;
}
int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{
/* If the fields p and g in d are NULL, the corresponding input
* parameters MUST be non-NULL. q may remain NULL.
*/
if ((dh->p == NULL && p == NULL)
|| (dh->g == NULL && g == NULL))
return 0;
if (p != NULL) {
BN_free(dh->p);
dh->p = p;
}
if (q != NULL) {
BN_free(dh->q);
dh->q = q;
}
if (g != NULL) {
BN_free(dh->g);
dh->g = g;
}
if (q != NULL) {
dh->length = BN_num_bits(q);
}
return 1;
}
void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
{
if (pub_key != NULL)
*pub_key = dh->pub_key;
if (priv_key != NULL)
*priv_key = dh->priv_key;
}
int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
{
/* If the field pub_key in dh is NULL, the corresponding input
* parameters MUST be non-NULL. The priv_key field may
* be left NULL.
*/
if (dh->pub_key == NULL && pub_key == NULL)
return 0;
if (pub_key != NULL) {
BN_free(dh->pub_key);
dh->pub_key = pub_key;
}
if (priv_key != NULL) {
BN_free(dh->priv_key);
dh->priv_key = priv_key;
}
return 1;
}
int DH_set_length(DH *dh, long length)
{
dh->length = length;
return 1;
}
const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx)
{
return ctx->iv;
}
unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx)
{
return ctx->iv;
}
EVP_MD_CTX *EVP_MD_CTX_new(void)
{
return OPENSSL_zalloc(sizeof(EVP_MD_CTX));
}
void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
{
EVP_MD_CTX_cleanup(ctx);
OPENSSL_free(ctx);
}
int RSA_size(const RSA* rsa) {
/* BIGNUM* n = NULL;
RSA_get0_key(rsa, n, NULL, NULL); */
return BN_num_bytes(rsa->n);
}
RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth)
{
RSA_METHOD *ret;
ret = OPENSSL_malloc(sizeof(RSA_METHOD));
if (ret != NULL) {
memcpy(ret, meth, sizeof(*meth));
ret->name = OPENSSL_strdup(meth->name);
if (ret->name == NULL) {
OPENSSL_free(ret);
return NULL;
}
}
return ret;
}
int RSA_meth_set1_name(RSA_METHOD *meth, const char *name)
{
char *tmpname;
tmpname = OPENSSL_strdup(name);
if (tmpname == NULL) {
return 0;
}
OPENSSL_free((char *)meth->name);
meth->name = tmpname;
return 1;
}
int RSA_meth_set_priv_enc(RSA_METHOD *meth,
int (*priv_enc) (int flen, const unsigned char *from,
unsigned char *to, RSA *rsa,
int padding))
{
meth->rsa_priv_enc = priv_enc;
return 1;
}
int RSA_meth_set_priv_dec(RSA_METHOD *meth,
int (*priv_dec) (int flen, const unsigned char *from,
unsigned char *to, RSA *rsa,
int padding))
{
meth->rsa_priv_dec = priv_dec;
return 1;
}
int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa))
{
meth->finish = finish;
return 1;
}
void RSA_meth_free(RSA_METHOD *meth)
{
if (meth != NULL) {
OPENSSL_free((char *)meth->name);
OPENSSL_free(meth);
}
}
int RSA_bits(const RSA *r)
{
return (BN_num_bits(r->n));
}
RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
{
if (pkey->type != EVP_PKEY_RSA) {
return NULL;
}
return pkey->pkey.rsa;
}
int X509_NAME_get0_der(X509_NAME *nm, const unsigned char **pder,
size_t *pderlen)
{
/* Make sure encoding is valid */
if (i2d_X509_NAME(nm, NULL) <= 0)
return 0;
if (pder != NULL)
*pder = (unsigned char *)nm->bytes->data;
if (pderlen != NULL)
*pderlen = nm->bytes->length;
return 1;
}
#endif /* OPENSSL_VERSION_NUMBER */
%}
m2crypto-0.42.0/src/SWIG/_m2crypto.def 0000664 0000000 0000000 00000000027 14655756567 0017343 0 ustar 00root root 0000000 0000000 EXPORTS
init_m2crypto
m2crypto-0.42.0/src/SWIG/_m2crypto.i 0000664 0000000 0000000 00000004753 14655756567 0017047 0 ustar 00root root 0000000 0000000 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright (c) 1999-2002 Ng Pheng Siong. All rights reserved.
*
* Portions created by Open Source Applications Foundation (OSAF) are
* Copyright (C) 2004-2006 OSAF. All Rights Reserved.
*
* Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved.
*
*/
%module(threads=1) m2crypto
/* We really don't need threadblock (PyGILState_Ensure() etc.) anywhere.
Disable threadallow as well, only enable it for operations likely to
block. */
%nothreadblock;
%nothreadallow;
#if SWIG_VERSION >= 0x030000
#define __WCHAR_MAX__ __WCHAR_MAX
#define __WCHAR_MIN__ __WCHAR_MIN
#endif
/* https://todo.sr.ht/~mcepl/m2crypto/246 */
%ignore WCHAR_MAX;
%ignore WCHAR_MIN;
/* http://swig.10945.n7.nabble.com/SWIG-AsVal-wchar-t-error-td2264.html */
%{
int SWIG_AsVal_wchar_t(PyObject *p, wchar_t *c) { return SWIG_OK; }
PyObject *SWIG_From_wchar_t(wchar_t c) { return SWIG_Py_Void(); }
%}
%{
#ifdef _WIN32
#define _WINSOCKAPI_
#include
#include
#pragma comment(lib, "Ws2_32")
typedef unsigned __int64 uint64_t;
#endif
%}
%{
#if defined __GNUC__ && __GNUC__ < 5
#pragma GCC diagnostic ignored "-Wunused-label"
#pragma GCC diagnostic warning "-Wstrict-prototypes"
#endif
#include
#include
#include <_lib.h>
#include
#include
#include "compile.h"
static PyObject *ssl_verify_cb_func;
static PyObject *ssl_info_cb_func;
static PyObject *ssl_set_tmp_dh_cb_func;
static PyObject *ssl_set_tmp_rsa_cb_func;
static PyObject *x509_store_verify_cb_func;
%}
%include
/* Bring in STACK_OF macro definition */
#ifdef _WIN32
%include
#endif
%include
/* Bring in LHASH_OF macro definition */
/* XXX Can't include lhash.h where LHASH_OF is defined, because it includes
XXX stdio.h etc. which we fail to include. So we have to (re)define
XXX LHASH_OF here instead.
%include
*/
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
#define LHASH_OF(type) struct lhash_st_##type
#endif
%include constraints.i
%include _threads.i
%include _lib.i
%include _bio.i
%include _bn.i
%include _rand.i
%include _evp.i
%include _aes.i
%include _rc4.i
%include _dh.i
%include _rsa.i
%include _dsa.i
%include _ssl.i
%include _x509.i
%include _asn1.i
%include _pkcs7.i
%include _util.i
%include _ec.i
%include _engine.i
%include _objects.i
#ifdef SWIG_VERSION
%constant int encrypt = 1;
%constant int decrypt = 0;
#endif
m2crypto-0.42.0/src/SWIG/_objects.i 0000664 0000000 0000000 00000005433 14655756567 0016715 0 ustar 00root root 0000000 0000000 /*
* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: syntax=c sts=4 sw=4
*
* ASN1_OBJECT manipulation functions from OBJ_obj2txt(3SSL).
*
* Pavel Shramov
* IMEC MSU
*/
%{
#include
%}
%apply Pointer NONNULL { ASN1_OBJECT * };
%apply Pointer NONNULL { const char * };
%rename(obj_nid2obj) OBJ_nid2obj;
extern ASN1_OBJECT * OBJ_nid2obj(int n);
%rename(obj_nid2ln) OBJ_nid2ln;
extern const char * OBJ_nid2ln(int n);
%rename(obj_nid2sn) OBJ_nid2sn;
extern const char * OBJ_nid2sn(int n);
%rename(obj_obj2nid) OBJ_obj2nid;
extern int OBJ_obj2nid(const ASN1_OBJECT *o);
%rename(obj_ln2nid) OBJ_ln2nid;
extern int OBJ_ln2nid(const char *ln);
%rename(obj_sn2nid) OBJ_sn2nid;
extern int OBJ_sn2nid(const char *sn);
%rename(obj_txt2nid) OBJ_txt2nid;
extern int OBJ_txt2nid(const char *s);
%rename(obj_txt2obj) OBJ_txt2obj;
extern ASN1_OBJECT * OBJ_txt2obj(const char *s, int no_name);
%rename(_obj_obj2txt) OBJ_obj2txt;
extern int OBJ_obj2txt(char *, int, const ASN1_OBJECT *, int);
%inline %{
/*
From the manpage for OBJ_obt2txt ():
BUGS
OBJ_obj2txt() is awkward and messy to use: it doesn’t follow the
convention of other OpenSSL functions where the buffer can be set
to NULL to determine the amount of data that should be written.
Instead buf must point to a valid buffer and buf_len should be set
to a positive value. A buffer length of 80 should be more than
enough to handle any OID encountered in practice.
The first call to OBJ_obj2txt () therefore passes a non-NULL dummy
buffer. This wart is reportedly removed in OpenSSL 0.9.8b, although
the manpage has not been updated.
OBJ_obj2txt always prints \0 at the end. But the return value
is the number of "good" bytes written. So memory is allocated for
len + 1 bytes but only len bytes are marshalled to python.
*/
PyObject *obj_obj2txt(const ASN1_OBJECT *obj, int no_name)
{
int len;
PyObject *ret;
char *buf;
char dummy[1];
len = OBJ_obj2txt(dummy, 1, obj, no_name);
if (len < 0) {
m2_PyErr_Msg(PyExc_RuntimeError);
return NULL;
} else if (len == 0) {
/* XXX: For OpenSSL prior to 0.9.8b.
Changes between 0.9.8a and 0.9.8b [04 May 2006]
...
*) Several fixes and enhancements to the OID generation code. The old code
sometimes allowed invalid OIDs (1.X for X >= 40 for example), couldn't
handle numbers larger than ULONG_MAX, truncated printing and had a
non standard OBJ_obj2txt() behaviour.
[Steve Henson]
*/
len = 80;
}
buf = PyMem_Malloc(len + 1);
len = OBJ_obj2txt(buf, len + 1, obj, no_name);
ret = PyBytes_FromStringAndSize(buf, len);
PyMem_Free(buf);
return ret;
}
%}
m2crypto-0.42.0/src/SWIG/_pkcs7.i 0000664 0000000 0000000 00000016265 14655756567 0016320 0 ustar 00root root 0000000 0000000 /* Copyright (c) 2000 Ng Pheng Siong. All rights reserved.
* Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved.
*/
/* $Id$ */
%{
#include
#include
#include
#include
%}
%apply Pointer NONNULL { BIO * };
%apply Pointer NONNULL { EVP_CIPHER * };
%apply Pointer NONNULL { EVP_PKEY * };
%apply Pointer NONNULL { PKCS7 * };
%apply Pointer NONNULL { STACK_OF(X509) * };
%apply Pointer NONNULL { X509 * };
%rename(pkcs7_new) PKCS7_new;
extern PKCS7 *PKCS7_new(void);
%rename(pkcs7_free) PKCS7_free;
extern void PKCS7_free(PKCS7 *);
%rename(pkcs7_add_certificate) PKCS7_add_certificate;
extern void PKCS7_add_certificate(PKCS7 *, X509 *);
/* S/MIME operation */
%constant int PKCS7_TEXT = 0x1;
%constant int PKCS7_NOCERTS = 0x2;
%constant int PKCS7_NOSIGS = 0x4;
%constant int PKCS7_NOCHAIN = 0x8;
%constant int PKCS7_NOINTERN = 0x10;
%constant int PKCS7_NOVERIFY = 0x20;
%constant int PKCS7_DETACHED = 0x40;
%constant int PKCS7_BINARY = 0x80;
%constant int PKCS7_NOATTR = 0x100;
%constant int PKCS7_SIGNED = NID_pkcs7_signed;
%constant int PKCS7_ENVELOPED = NID_pkcs7_enveloped;
%constant int PKCS7_SIGNED_ENVELOPED = NID_pkcs7_signedAndEnveloped;
%constant int PKCS7_DATA = NID_pkcs7_data;
%warnfilter(454) _pkcs7_err;
%warnfilter(454) _smime_err;
%inline %{
static PyObject *_pkcs7_err, *_smime_err;
void pkcs7_init(PyObject *pkcs7_err) {
Py_INCREF(pkcs7_err);
_pkcs7_err = pkcs7_err;
}
void smime_init(PyObject *smime_err) {
Py_INCREF(smime_err);
_smime_err = smime_err;
}
%}
%inline %{
PyObject *pkcs7_decrypt(PKCS7 *pkcs7, EVP_PKEY *pkey, X509 *cert, int flags) {
int outlen;
char *outbuf;
BIO *bio;
PyObject *ret;
if (!(bio=BIO_new(BIO_s_mem()))) {
PyErr_SetString(PyExc_MemoryError, "pkcs7_decrypt");
return NULL;
}
if (!PKCS7_decrypt(pkcs7, pkey, cert, bio, flags)) {
m2_PyErr_Msg(_pkcs7_err);
BIO_free(bio);
return NULL;
}
outlen = BIO_ctrl_pending(bio);
if (!(outbuf=(char *)PyMem_Malloc(outlen))) {
PyErr_SetString(PyExc_MemoryError, "pkcs7_decrypt");
BIO_free(bio);
return NULL;
}
BIO_read(bio, outbuf, outlen);
ret = PyBytes_FromStringAndSize(outbuf, outlen);
BIO_free(bio);
PyMem_Free(outbuf);
return ret;
}
%}
%typemap(out) PKCS7 * {
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
if ($1 != NULL)
$result = SWIG_NewPointerObj($1, $1_descriptor, 0);
else {
m2_PyErr_Msg(_smime_err);
$result = NULL;
}
}
%threadallow pkcs7_encrypt;
%inline %{
PKCS7 *pkcs7_encrypt(STACK_OF(X509) *stack, BIO *bio, EVP_CIPHER *cipher, int flags) {
return PKCS7_encrypt(stack, bio, cipher, flags);
}
%}
%threadallow pkcs7_sign1;
%inline %{
PKCS7 *pkcs7_sign1(X509 *x509, EVP_PKEY *pkey, STACK_OF(X509) *stack, BIO *bio, EVP_MD *hash, int flags) {
PKCS7 *p7 = PKCS7_sign(NULL, NULL, stack, bio, flags | PKCS7_STREAM);
if (p7 == NULL) {
return NULL;
}
if (PKCS7_sign_add_signer(p7, x509, pkey, hash, flags) == NULL) {
return NULL;
}
if (PKCS7_final(p7, bio, flags) != 1) {
return NULL;
}
return p7;
}
%}
%threadallow pkcs7_sign0;
%inline %{
PKCS7 *pkcs7_sign0(X509 *x509, EVP_PKEY *pkey, BIO *bio, EVP_MD *hash, int flags) {
return pkcs7_sign1(x509, pkey, NULL, bio, hash, flags);
}
%}
%typemap(out) PKCS7 * {
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
if ($1 != NULL)
$result = SWIG_NewPointerObj($1, $1_descriptor, 0);
else {
m2_PyErr_Msg(_pkcs7_err);
$result = NULL;
}
}
%threadallow pkcs7_read_bio;
%inline %{
PKCS7 *pkcs7_read_bio(BIO *bio) {
return PEM_read_bio_PKCS7(bio, NULL, NULL, NULL);
}
%}
%threadallow pkcs7_read_bio_der;
%inline %{
PKCS7 *pkcs7_read_bio_der(BIO *bio) {
return d2i_PKCS7_bio(bio, NULL);
}
%}
%typemap(out) PKCS7 * ;
%inline %{
PyObject *pkcs7_verify1(PKCS7 *pkcs7, STACK_OF(X509) *stack, X509_STORE *store, BIO *data, int flags) {
int res, outlen;
char *outbuf;
BIO *bio;
PyObject *ret;
if (!(bio=BIO_new(BIO_s_mem()))) {
PyErr_SetString(PyExc_MemoryError, "pkcs7_verify1");
return NULL;
}
Py_BEGIN_ALLOW_THREADS
res = PKCS7_verify(pkcs7, stack, store, data, bio, flags);
Py_END_ALLOW_THREADS
if (!res) {
m2_PyErr_Msg(_pkcs7_err);
BIO_free(bio);
return NULL;
}
outlen = BIO_ctrl_pending(bio);
if (!(outbuf=(char *)PyMem_Malloc(outlen))) {
PyErr_SetString(PyExc_MemoryError, "pkcs7_verify1");
BIO_free(bio);
return NULL;
}
BIO_read(bio, outbuf, outlen);
ret = PyBytes_FromStringAndSize(outbuf, outlen);
BIO_free(bio);
PyMem_Free(outbuf);
return ret;
}
PyObject *pkcs7_verify0(PKCS7 *pkcs7, STACK_OF(X509) *stack, X509_STORE *store, int flags) {
return pkcs7_verify1(pkcs7, stack, store, NULL, flags);
}
%}
%threadallow smime_write_pkcs7_multi;
%inline %{
int smime_write_pkcs7_multi(BIO *bio, PKCS7 *pkcs7, BIO *data, int flags) {
return SMIME_write_PKCS7(bio, pkcs7, data, flags | PKCS7_DETACHED);
}
%}
%threadallow smime_write_pkcs7;
%inline %{
int smime_write_pkcs7(BIO *bio, PKCS7 *pkcs7, int flags) {
return SMIME_write_PKCS7(bio, pkcs7, NULL, flags);
}
PyObject *smime_read_pkcs7(BIO *bio) {
BIO *bcont = NULL;
PKCS7 *p7;
PyObject *tuple, *_p7, *_BIO;
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
if (BIO_method_type(bio) == BIO_TYPE_MEM) {
/* OpenSSL FAQ explains that this is needed for mem BIO to return EOF,
* like file BIO does. Might need to do this for more mem BIOs but
* not sure if that is safe, so starting with just this single place.
*/
BIO_set_mem_eof_return(bio, 0);
}
Py_BEGIN_ALLOW_THREADS
p7=SMIME_read_PKCS7(bio, &bcont);
Py_END_ALLOW_THREADS
if (!p7) {
m2_PyErr_Msg(_smime_err);
return NULL;
}
if (!(tuple=PyTuple_New(2))) {
PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails");
return NULL;
}
_p7 = SWIG_NewPointerObj((void *)p7, SWIGTYPE_p_PKCS7, 0);
PyTuple_SET_ITEM(tuple, 0, _p7);
if (!bcont) {
Py_INCREF(Py_None);
PyTuple_SET_ITEM(tuple, 1, Py_None);
} else {
_BIO = SWIG_NewPointerObj((void *)bcont, SWIGTYPE_p_BIO, 0);
PyTuple_SET_ITEM(tuple, 1, _BIO);
}
return tuple;
}
%}
%threadallow pkcs7_write_bio;
%inline %{
int pkcs7_write_bio(PKCS7 *pkcs7, BIO* bio) {
return PEM_write_bio_PKCS7(bio, pkcs7);
}
%}
%threadallow pkcs7_write_bio_der;
%inline %{
int pkcs7_write_bio_der(PKCS7 *pkcs7, BIO *bio) {
return i2d_PKCS7_bio(bio, pkcs7);
}
int pkcs7_type_nid(PKCS7 *pkcs7) {
return OBJ_obj2nid(pkcs7->type);
}
const char *pkcs7_type_sn(PKCS7 *pkcs7) {
return OBJ_nid2sn(OBJ_obj2nid(pkcs7->type));
}
%}
%threadallow smime_crlf_copy;
%inline %{
int smime_crlf_copy(BIO *in, BIO *out) {
return SMIME_crlf_copy(in, out, PKCS7_TEXT);
}
/* return STACK_OF(X509)* */
STACK_OF(X509) *pkcs7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags) {
return PKCS7_get0_signers(p7, certs, flags);
}
%}
m2crypto-0.42.0/src/SWIG/_py3k_compat.i 0000664 0000000 0000000 00000002261 14655756567 0017511 0 ustar 00root root 0000000 0000000 %{
#if PY_MAJOR_VERSION >= 3
FILE* PyFile_AsFile(PyObject *pyfile) {
FILE* fp;
int fd;
const char *mode_str = NULL;
PyObject *mode_obj;
if ((fd = PyObject_AsFileDescriptor(pyfile)) == -1) {
PyErr_SetString(PyExc_BlockingIOError,
"Cannot find file handler for the Python file!");
return NULL;
}
if ((mode_obj = PyObject_GetAttrString(pyfile, "mode")) == NULL) {
mode_str = "rb";
PyErr_Clear();
}
else {
/* convert to plain string
* note that error checking is embedded in the function
*/
mode_str = PyUnicode_AsUTF8AndSize(mode_obj, NULL);
}
if((fp = fdopen(fd, mode_str)) == NULL) {
PyErr_SetFromErrno(PyExc_IOError);
}
Py_XDECREF(mode_obj);
return fp;
}
#else /* PY2K */
#ifndef PyLong_FromLong
#define PyLong_FromLong(x) PyInt_FromLong(x)
#endif
#ifndef PyUnicode_AsUTF8
#define PyUnicode_AsUTF8(x) PyString_AsString(x)
#endif
#ifndef PyUnicode_FromString
#define PyUnicode_FromString(x) PyString_FromString(x)
#endif
#ifndef PyUnicode_Format
#define PyUnicode_Format(x, y) PyString_Format(x, y)
#endif
#endif /* PY_MAJOR_VERSION */
%}
m2crypto-0.42.0/src/SWIG/_rand.i 0000664 0000000 0000000 00000007343 14655756567 0016212 0 ustar 00root root 0000000 0000000 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved.
* Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved.
*/
/* $Id: _rand.i 721 2010-02-13 06:30:33Z heikki $ */
%module _rand
%rename(rand_file_name) RAND_file_name;
extern const char *RAND_file_name(char *, size_t );
%rename(rand_load_file) RAND_load_file;
extern int RAND_load_file(const char *, long);
%rename(rand_save_file) RAND_write_file;
extern int RAND_write_file(const char *);
%rename(rand_poll) RAND_poll;
extern int RAND_poll(void);
%rename(rand_status) RAND_status;
extern int RAND_status(void);
%rename(rand_cleanup) RAND_cleanup;
extern void RAND_cleanup(void);
%warnfilter(454) _rand_err;
%inline %{
static PyObject *_rand_err;
void rand_init(PyObject *rand_err) {
Py_INCREF(rand_err);
_rand_err = rand_err;
}
PyObject *rand_seed(PyObject *seed) {
const void *buf = NULL;
int len = 0;
m2_PyObject_AsReadBufferInt(seed, &buf, &len);
RAND_seed(buf, len);
Py_RETURN_NONE;
}
PyObject *rand_add(PyObject *blob, double entropy) {
const void *buf = NULL;
int len = 0;
m2_PyObject_AsReadBufferInt(blob, &buf, &len);
RAND_add(buf, len, entropy);
Py_RETURN_NONE;
}
PyObject *rand_bytes(int n) {
void *blob;
int ret;
PyObject *obj;
if (!(blob = PyMem_Malloc(n))) {
PyErr_SetString(PyExc_MemoryError,
"Insufficient memory for rand_bytes.");
return NULL;
}
if ((ret = RAND_bytes(blob, n)) == 1) {
obj = PyBytes_FromStringAndSize(blob, n);
PyMem_Free(blob);
return obj;
} else if (ret == 0) {
PyErr_SetString(_rand_err, "Not enough randomness.");
PyMem_Free(blob);
return NULL;
} else if (ret == -1) {
PyErr_SetString(_rand_err,
"Not supported by the current RAND method.");
PyMem_Free(blob);
return NULL;
} else {
PyMem_Free(blob);
m2_PyErr_Msg(_rand_err);
return NULL;
}
}
PyObject *rand_pseudo_bytes(int n) {
int ret;
unsigned char *blob;
PyObject *tuple;
if (!(blob=(unsigned char *)PyMem_Malloc(n))) {
PyErr_SetString(PyExc_MemoryError, "Insufficient memory for rand_pseudo_bytes.");
return NULL;
}
if (!(tuple=PyTuple_New(2))) {
PyErr_SetString(PyExc_RuntimeError, "PyTuple_New() fails");
PyMem_Free(blob);
return NULL;
}
ret = RAND_pseudo_bytes(blob, n);
if (ret == -1) {
PyMem_Free(blob);
Py_DECREF(tuple);
PyErr_SetString(_rand_err,
"Function RAND_pseudo_bytes not supported by the current RAND method.");
return NULL;
} else {
PyTuple_SET_ITEM(tuple, 0, PyBytes_FromStringAndSize((char*)blob, n));
PyMem_Free(blob);
PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong((long)ret));
return tuple;
}
}
PyObject *rand_file_name(void) {
PyObject *obj;
char *str;
if ((obj = PyBytes_FromStringAndSize(NULL, BUFSIZ))==NULL) {
PyErr_SetString(PyExc_MemoryError, "rand_file_name");
return NULL;
}
str=PyBytes_AS_STRING(obj);
if (RAND_file_name(str, BUFSIZ)==NULL) {
PyErr_SetString(PyExc_RuntimeError, "rand_file_name");
return NULL;
}
if (_PyBytes_Resize(&obj, (Py_ssize_t)strlen(str))!=0)
return NULL; /* mem exception set by _PyBytes_Resize */
return obj;
}
void rand_screen(void) {
#ifdef _WIN32
RAND_screen();
#endif
}
int rand_win32_event(unsigned int imsg, int wparam, long lparam) {
#ifdef _WIN32
return RAND_event(imsg, wparam, lparam);
#else
return 0;
#endif
}
%}
/*
2004-04-05, ngps: Still missing:
RAND_egd
RAND_egd_bytes
RAND_query_egd_bytes
*/
m2crypto-0.42.0/src/SWIG/_rc4.i 0000664 0000000 0000000 00000002560 14655756567 0015752 0 ustar 00root root 0000000 0000000 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright (c) 1999 Ng Pheng Siong. All rights reserved. */
/* $Id$ */
%include
#if defined(OPENSSL_NO_RC4)
#undef OPENSSL_NO_RC4
%constant OPENSSL_NO_RC4 = 1;
#else
%constant OPENSSL_NO_RC4 = 0;
%{
#include
%}
%apply Pointer NONNULL { RC4_KEY * };
%inline %{
RC4_KEY *rc4_new(void) {
RC4_KEY *key;
if (!(key = (RC4_KEY *)PyMem_Malloc(sizeof(RC4_KEY))))
PyErr_SetString(PyExc_MemoryError, "rc4_new");
return key;
}
void rc4_free(RC4_KEY *key) {
PyMem_Free((void *)key);
}
PyObject *rc4_set_key(RC4_KEY *key, PyObject *value) {
const void *vbuf = NULL;
int vlen = 0;
if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1)
return NULL;
RC4_set_key(key, vlen, vbuf);
Py_RETURN_NONE;
}
PyObject *rc4_update(RC4_KEY *key, PyObject *in) {
PyObject *ret;
const void *buf;
Py_ssize_t len;
void *out;
if (m2_PyObject_AsReadBuffer(in, &buf, &len) == -1)
return NULL;
if (!(out = PyMem_Malloc(len))) {
PyErr_SetString(PyExc_MemoryError, "expected a string object");
return NULL;
}
RC4(key, len, buf, out);
ret = PyBytes_FromStringAndSize(out, len);
PyMem_Free(out);
return ret;
}
int rc4_type_check(RC4_KEY *key) {
return 1;
}
%}
#endif
m2crypto-0.42.0/src/SWIG/_rsa.i 0000664 0000000 0000000 00000031272 14655756567 0016051 0 ustar 00root root 0000000 0000000 /* Copyright (c) 1999-2000 Ng Pheng Siong. All rights reserved. */
/* $Id$ */
%{
#include
#include
#include
#include
#include
%}
%apply Pointer NONNULL { RSA * };
%apply Pointer NONNULL { PyObject *pyfunc };
%rename(rsa_size) RSA_size;
extern int RSA_size(const RSA*);
%rename(rsa_new) RSA_new;
extern RSA *RSA_new(void);
%rename(rsa_free) RSA_free;
extern void RSA_free(RSA *);
%rename(rsa_check_key) RSA_check_key;
extern int RSA_check_key(const RSA *);
%constant int no_padding = RSA_NO_PADDING;
%constant int pkcs1_padding = RSA_PKCS1_PADDING;
#ifdef RSA_SSLV23_PADDING
%constant int sslv23_padding = RSA_SSLV23_PADDING;
#endif
%constant int pkcs1_oaep_padding = RSA_PKCS1_OAEP_PADDING;
%constant int NID_sha1 = NID_sha1;
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
%constant int NID_sha224 = NID_sha224;
%constant int NID_sha256 = NID_sha256;
%constant int NID_sha384 = NID_sha384;
%constant int NID_sha512 = NID_sha512;
#endif
%constant int NID_md5 = NID_md5;
%constant int NID_ripemd160 = NID_ripemd160;
%warnfilter(454) _rsa_err;
%inline %{
static PyObject *_rsa_err;
void rsa_init(PyObject *rsa_err) {
Py_INCREF(rsa_err);
_rsa_err = rsa_err;
}
%}
%inline %{
RSA *rsa_read_key(BIO *f, PyObject *pyfunc) {
RSA *rsa;
Py_INCREF(pyfunc);
Py_BEGIN_ALLOW_THREADS
rsa = PEM_read_bio_RSAPrivateKey(f, NULL, passphrase_callback, (void *)pyfunc);
Py_END_ALLOW_THREADS
Py_DECREF(pyfunc);
return rsa;
}
%}
%inline %{
int rsa_write_key(RSA *rsa, BIO *f, EVP_CIPHER *cipher, PyObject *pyfunc) {
int ret;
Py_INCREF(pyfunc);
Py_BEGIN_ALLOW_THREADS
ret = PEM_write_bio_RSAPrivateKey(f, rsa, cipher, NULL, 0,
passphrase_callback, (void *)pyfunc);
Py_END_ALLOW_THREADS
Py_DECREF(pyfunc);
return ret;
}
%}
%inline %{
int rsa_write_key_no_cipher(RSA *rsa, BIO *f, PyObject *pyfunc) {
int ret;
Py_INCREF(pyfunc);
Py_BEGIN_ALLOW_THREADS
ret = PEM_write_bio_RSAPrivateKey(f, rsa, NULL, NULL, 0,
passphrase_callback, (void *)pyfunc);
Py_END_ALLOW_THREADS
Py_DECREF(pyfunc);
return ret;
}
%}
%threadallow rsa_read_pub_key;
%inline %{
RSA *rsa_read_pub_key(BIO *f) {
return PEM_read_bio_RSA_PUBKEY(f, NULL, NULL, NULL);
}
%}
%threadallow rsa_write_pub_key;
%inline %{
int rsa_write_pub_key(RSA *rsa, BIO *f) {
return PEM_write_bio_RSA_PUBKEY(f, rsa);
}
PyObject *rsa_get_e(RSA *rsa) {
const BIGNUM* e = NULL;
RSA_get0_key(rsa, NULL, &e, NULL);
if (!e) {
PyErr_SetString(_rsa_err, "'e' is unset");
return NULL;
}
return bn_to_mpi(e);
}
PyObject *rsa_get_n(RSA *rsa) {
const BIGNUM* n = NULL;
RSA_get0_key(rsa, &n, NULL, NULL);
if (!n) {
PyErr_SetString(_rsa_err, "'n' is unset");
return NULL;
}
return bn_to_mpi(n);
}
PyObject *rsa_set_e(RSA *rsa, PyObject *eval) {
const BIGNUM* n_read = NULL;
BIGNUM* n = NULL;
BIGNUM* e;
if (!(e = m2_PyObject_AsBIGNUM(eval, _rsa_err))) {
return NULL;
}
/* n and e must be set at the same time so if e is unset, set it to zero */
RSA_get0_key(rsa, &n_read, NULL, NULL);
if (!n_read) {
n = BN_new();
}
if (RSA_set0_key(rsa, n, e, NULL) != 1) {
PyErr_SetString(_rsa_err, "Cannot set fields of RSA object.");
BN_free(e);
BN_free(n);
return NULL;
}
Py_RETURN_NONE;
}
PyObject *rsa_set_n(RSA *rsa, PyObject *nval) {
BIGNUM* n;
const BIGNUM* e_read = NULL;
BIGNUM* e = NULL;
if (!(n = m2_PyObject_AsBIGNUM(nval, _rsa_err))) {
return NULL;
}
/* n and e must be set at the same time so if e is unset, set it to zero */
RSA_get0_key(rsa, NULL, &e_read, NULL);
if (!e_read) {
e = BN_new();
}
if (RSA_set0_key(rsa, n, e, NULL) != 1) {
PyErr_SetString(_rsa_err, "Cannot set fields of RSA object.");
BN_free(n);
BN_free(e);
return NULL;
}
Py_RETURN_NONE;
}
PyObject *rsa_set_en(RSA *rsa, PyObject *eval, PyObject* nval) {
BIGNUM* e, *n;
if (!(e = m2_PyObject_AsBIGNUM(eval, _rsa_err)) ||
!(n = m2_PyObject_AsBIGNUM(nval, _rsa_err))) {
return NULL;
}
if (!RSA_set0_key(rsa, n, e, NULL)) {
PyErr_SetString(_rsa_err, "Cannot set fields of RSA object.");
BN_free(e);
BN_free(n);
return NULL;
}
Py_RETURN_NONE;
}
static BIGNUM* PyObject_Bin_AsBIGNUM(PyObject* value) {
BIGNUM* bn;
const void* vbuf;
int vlen = 0;
if (m2_PyObject_AsReadBufferInt(value, &vbuf, &vlen) == -1)
return NULL;
if (!(bn = BN_bin2bn((unsigned char *)vbuf, vlen, NULL))) {
m2_PyErr_Msg(_rsa_err);
return NULL;
}
return bn;
}
PyObject *rsa_set_en_bin(RSA *rsa, PyObject *eval, PyObject* nval) {
BIGNUM* e, *n;
if (!(e = PyObject_Bin_AsBIGNUM(eval)) ||
!(n = PyObject_Bin_AsBIGNUM(nval))) {
return NULL;
}
if (!RSA_set0_key(rsa, e, n, NULL)) {
PyErr_SetString(_rsa_err, "Cannot set fields of RSA object.");
BN_free(e);
BN_free(n);
return NULL;
}
Py_RETURN_NONE;
}
PyObject *rsa_private_encrypt(RSA *rsa, PyObject *from, int padding) {
const void *fbuf;
void *tbuf;
int flen = 0, tlen;
PyObject *ret;
if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1)
return NULL;
if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) {
PyErr_SetString(PyExc_MemoryError, "rsa_private_encrypt");
return NULL;
}
tlen = RSA_private_encrypt(flen, (unsigned char *)fbuf,
(unsigned char *)tbuf, rsa, padding);
if (tlen == -1) {
m2_PyErr_Msg(_rsa_err);
PyMem_Free(tbuf);
return NULL;
}
ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen);
PyMem_Free(tbuf);
return ret;
}
PyObject *rsa_public_decrypt(RSA *rsa, PyObject *from, int padding) {
const void *fbuf;
void *tbuf;
int flen = 0, tlen = 0;
PyObject *ret;
if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1)
return NULL;
/* OpenSSL docs are confused here: it says we only need buffer
* 'RSA_size()-11', but it is true only for RSA PKCS#1 type 1
* padding. For other uses we need to use different sizes. */
if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) {
PyErr_SetString(PyExc_MemoryError, "rsa_public_decrypt");
return NULL;
}
tlen = RSA_public_decrypt(flen, (unsigned char *)fbuf,
(unsigned char *)tbuf, rsa, padding);
if (tlen == -1) {
ERR_clear_error();
PyErr_Clear();
PyMem_Free(tbuf);
Py_RETURN_NONE;
}
ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen);
PyMem_Free(tbuf);
return ret;
}
PyObject *rsa_public_encrypt(RSA *rsa, PyObject *from, int padding) {
const void *fbuf;
void *tbuf;
int flen = 0, tlen;
PyObject *ret;
if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1)
return NULL;
if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) {
PyErr_SetString(PyExc_MemoryError, "rsa_public_encrypt");
return NULL;
}
tlen = RSA_public_encrypt(flen, (unsigned char *)fbuf,
(unsigned char *)tbuf, rsa, padding);
if (tlen == -1) {
m2_PyErr_Msg(_rsa_err);
PyMem_Free(tbuf);
return NULL;
}
ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen);
PyMem_Free(tbuf);
return ret;
}
PyObject *rsa_private_decrypt(RSA *rsa, PyObject *from, int padding) {
const void *fbuf;
void *tbuf;
int flen = 0, tlen;
PyObject *ret;
if (m2_PyObject_AsReadBufferInt(from, &fbuf, &flen) == -1)
return NULL;
if (!(tbuf = PyMem_Malloc(RSA_size(rsa)))) {
PyErr_SetString(PyExc_MemoryError, "rsa_private_decrypt");
return NULL;
}
tlen = RSA_private_decrypt(flen, (unsigned char *)fbuf,
(unsigned char *)tbuf, rsa, padding);
if (tlen == -1) {
ERR_clear_error();
PyErr_Clear();
PyMem_Free(tbuf);
Py_RETURN_NONE;
}
ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen);
PyMem_Free(tbuf);
return ret;
}
#if OPENSSL_VERSION_NUMBER >= 0x0090708fL
PyObject *rsa_padding_add_pkcs1_pss(RSA *rsa, PyObject *digest, EVP_MD *hash, int salt_length) {
const void *dbuf;
unsigned char *tbuf;
int dlen, result, tlen;
PyObject *ret;
if (m2_PyObject_AsReadBufferInt(digest, &dbuf, &dlen) == -1)
return NULL;
tlen = RSA_size(rsa);
if (!(tbuf = OPENSSL_malloc(tlen))) {
PyErr_SetString(PyExc_MemoryError, "rsa_padding_add_pkcs1_pss");
return NULL;
}
result = RSA_padding_add_PKCS1_PSS(
rsa,
tbuf,
(unsigned char *)dbuf,
hash,
salt_length);
if (result == -1) {
m2_PyErr_Msg(_rsa_err);
OPENSSL_cleanse(tbuf, tlen);
OPENSSL_free(tbuf);
return NULL;
}
ret = PyBytes_FromStringAndSize((const char *)tbuf, tlen);
OPENSSL_cleanse(tbuf, tlen);
OPENSSL_free(tbuf);
return ret;
}
int rsa_verify_pkcs1_pss(RSA *rsa, PyObject *digest, PyObject *signature, EVP_MD *hash, int salt_length) {
const void *dbuf;
const void *sbuf;
int dlen, slen, ret;
if (m2_PyObject_AsReadBufferInt(digest, &dbuf, &dlen) == -1) {
return 0;
}
if (m2_PyObject_AsReadBufferInt(signature, &sbuf, &slen) == -1) {
return 0;
}
ret = RSA_verify_PKCS1_PSS(
rsa,
(unsigned char *)dbuf,
hash,
(unsigned char *)sbuf,
salt_length);
return ret;
}
#endif
PyObject *rsa_sign(RSA *rsa, PyObject *py_digest_string, int method_type) {
int digest_len = 0;
int buf_len = 0;
int ret = 0;
unsigned int real_buf_len = 0;
char *digest_string = NULL;
unsigned char * sign_buf = NULL;
PyObject *signature;
ret = m2_PyString_AsStringAndSizeInt(py_digest_string, &digest_string,
&digest_len);
if (ret == -1) {
/* PyString_AsStringAndSize raises the correct exceptions. */
return NULL;
}
buf_len = RSA_size(rsa);
sign_buf = (unsigned char *)PyMem_Malloc(buf_len);
ret = RSA_sign(method_type, (const unsigned char *)digest_string, digest_len,
sign_buf, &real_buf_len, rsa);
if (!ret) {
m2_PyErr_Msg(_rsa_err);
PyMem_Free(sign_buf);
return NULL;
}
signature = PyBytes_FromStringAndSize((const char*) sign_buf, buf_len);
PyMem_Free(sign_buf);
return signature;
}
int rsa_verify(RSA *rsa, PyObject *py_verify_string, PyObject* py_sign_string, int method_type){
int ret = 0;
char * sign_string = NULL;
char * verify_string = NULL;
int verify_len = 0;
int sign_len = 0;
ret = m2_PyString_AsStringAndSizeInt(py_verify_string, &verify_string,
&verify_len);
if (ret == -1) {
/* PyString_AsStringAndSize raises the correct exceptions. */
return 0;
}
ret = m2_PyString_AsStringAndSizeInt(py_sign_string, &sign_string,
&sign_len);
if (ret == -1) {
return 0;
}
ret = RSA_verify(method_type, (unsigned char *) verify_string,
verify_len, (unsigned char *) sign_string,
sign_len, rsa);
if (!ret) {
m2_PyErr_Msg(_rsa_err);
return 0;
}
return ret;
}
PyObject *rsa_generate_key(int bits, unsigned long e, PyObject *pyfunc) {
RSA *rsa;
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
BN_GENCB *gencb;
BIGNUM *e_big;
int ret;
if ((e_big=BN_new()) == NULL) {
m2_PyErr_Msg(_rsa_err);
return NULL;
}
if (BN_set_word(e_big, e) == 0) {
m2_PyErr_Msg(_rsa_err);
BN_free(e_big);
return NULL;
}
if ((gencb=BN_GENCB_new()) == NULL) {
m2_PyErr_Msg(_rsa_err);
BN_free(e_big);
return NULL;
}
if ((rsa = RSA_new()) == NULL) {
m2_PyErr_Msg(_rsa_err);
BN_free(e_big);
BN_GENCB_free(gencb);
return NULL;
}
BN_GENCB_set(gencb, bn_gencb_callback, (void *) pyfunc);
Py_INCREF(pyfunc);
ret = RSA_generate_key_ex(rsa, bits, e_big, gencb);
BN_free(e_big);
BN_GENCB_free(gencb);
Py_DECREF(pyfunc);
if (ret)
return SWIG_NewPointerObj((void *)rsa, SWIGTYPE_p_RSA, 0);
m2_PyErr_Msg(_rsa_err);
RSA_free(rsa);
return NULL;
}
int rsa_type_check(RSA *rsa) {
return 1;
}
int rsa_check_pub_key(RSA *rsa) {
const BIGNUM* n, *e;
RSA_get0_key(rsa, &n, &e, NULL);
return n && e;
}
%}
%threadallow rsa_write_key_der;
%inline %{
int rsa_write_key_der(RSA *rsa, BIO *bio) {
return i2d_RSAPrivateKey_bio(bio, rsa);
}
%}
m2crypto-0.42.0/src/SWIG/_ssl.i 0000664 0000000 0000000 00000066101 14655756567 0016064 0 ustar 00root root 0000000 0000000 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* Copyright (c) 1999-2004 Ng Pheng Siong. All rights reserved. */
/*
** Portions created by Open Source Applications Foundation (OSAF) are
** Copyright (C) 2004-2005 OSAF. All Rights Reserved.
**
** Copyright (c) 2009-2010 Heikki Toivonen. All rights reserved.
**
*/
/* $Id$ */
%{
#include
#include
#include
#include
#include
#include
#include
#ifdef _WIN32
#include
#include
#pragma comment(lib, "Ws2_32")
typedef unsigned __int64 uint64_t;
#else
#include
#include
#endif
%}
#if OPENSSL_VERSION_NUMBER >= 0x10100005L
%include
#endif
%apply Pointer NONNULL { SSL_CTX * };
%apply Pointer NONNULL { SSL * };
%apply Pointer NONNULL { SSL_CIPHER * };
%apply Pointer NONNULL { STACK_OF(SSL_CIPHER) * };
%apply Pointer NONNULL { STACK_OF(X509) * };
%apply Pointer NONNULL { BIO * };
%apply Pointer NONNULL { DH * };
%apply Pointer NONNULL { RSA * };
%apply Pointer NONNULL { EVP_PKEY *};
%apply Pointer NONNULL { PyObject *pyfunc };
%rename(ssl_get_ciphers) SSL_get_ciphers;
extern STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl);
%rename(ssl_get_version) SSL_get_version;
extern const char *SSL_get_version(const SSL *);
%rename(ssl_get_error) SSL_get_error;
extern int SSL_get_error(const SSL *, int);
%rename(ssl_get_state) SSL_state_string;
extern const char *SSL_state_string(const SSL *);
%rename(ssl_get_state_v) SSL_state_string_long;
extern const char *SSL_state_string_long(const SSL *);
%rename(ssl_get_alert_type) SSL_alert_type_string;
extern const char *SSL_alert_type_string(int);
%rename(ssl_get_alert_type_v) SSL_alert_type_string_long;
extern const char *SSL_alert_type_string_long(int);
%rename(ssl_get_alert_desc) SSL_alert_desc_string;
extern const char *SSL_alert_desc_string(int);
%rename(ssl_get_alert_desc_v) SSL_alert_desc_string_long;
extern const char *SSL_alert_desc_string_long(int);
%rename(sslv23_method) SSLv23_method;
extern SSL_METHOD *SSLv23_method(void);
%ignore TLSv1_method;
extern SSL_METHOD *TLSv1_method(void);
%typemap(out) SSL_CTX * {
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
if ($1 != NULL)
$result = SWIG_NewPointerObj($1, $1_descriptor, 0);
else {
m2_PyErr_Msg(_ssl_err);
$result = NULL;
}
}
%rename(ssl_ctx_new) SSL_CTX_new;
extern SSL_CTX *SSL_CTX_new(SSL_METHOD *);
%typemap(out) SSL_CTX *;
%rename(ssl_ctx_free) SSL_CTX_free;
extern void SSL_CTX_free(SSL_CTX *);
%rename(ssl_ctx_set_verify_depth) SSL_CTX_set_verify_depth;
extern void SSL_CTX_set_verify_depth(SSL_CTX *, int);
%rename(ssl_ctx_get_verify_depth) SSL_CTX_get_verify_depth;
extern int SSL_CTX_get_verify_depth(const SSL_CTX *);
%rename(ssl_ctx_get_verify_mode) SSL_CTX_get_verify_mode;
extern int SSL_CTX_get_verify_mode(const SSL_CTX *);
%rename(ssl_ctx_set_cipher_list) SSL_CTX_set_cipher_list;
extern int SSL_CTX_set_cipher_list(SSL_CTX *, const char *);
%rename(ssl_ctx_add_session) SSL_CTX_add_session;
extern int SSL_CTX_add_session(SSL_CTX *, SSL_SESSION *);
%rename(ssl_ctx_remove_session) SSL_CTX_remove_session;
extern int SSL_CTX_remove_session(SSL_CTX *, SSL_SESSION *);
%rename(ssl_ctx_set_session_timeout) SSL_CTX_set_timeout;
extern long SSL_CTX_set_timeout(SSL_CTX *, long);
%rename(ssl_ctx_get_session_timeout) SSL_CTX_get_timeout;
extern long SSL_CTX_get_timeout(const SSL_CTX *);
%rename(ssl_ctx_get_cert_store) SSL_CTX_get_cert_store;
extern X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *);
%rename(ssl_ctx_set_default_verify_paths) SSL_CTX_set_default_verify_paths;
extern int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx);
%rename(ssl_get_ex_data_x509_store_ctx_idx) SSL_get_ex_data_X509_STORE_CTX_idx;
extern int SSL_get_ex_data_X509_STORE_CTX_idx(void);
%rename(bio_new_ssl) BIO_new_ssl;
extern BIO *BIO_new_ssl(SSL_CTX *, int);
%rename(ssl_new) SSL_new;
extern SSL *SSL_new(SSL_CTX *);
%rename(ssl_free) SSL_free;
%threadallow SSL_free;
extern void SSL_free(SSL *);
%rename(ssl_dup) SSL_dup;
extern SSL *SSL_dup(SSL *);
%rename(ssl_set_bio) SSL_set_bio;
extern void SSL_set_bio(SSL *, BIO *, BIO *);
%rename(ssl_set_accept_state) SSL_set_accept_state;
extern void SSL_set_accept_state(SSL *);
%rename(ssl_set_connect_state) SSL_set_connect_state;
extern void SSL_set_connect_state(SSL *);
%rename(ssl_get_shutdown) SSL_get_shutdown;
extern int SSL_get_shutdown(const SSL *);
%rename(ssl_set_shutdown) SSL_set_shutdown;
extern void SSL_set_shutdown(SSL *, int);
%rename(ssl_shutdown) SSL_shutdown;
%threadallow SSL_shutdown;
extern int SSL_shutdown(SSL *);
%rename(ssl_clear) SSL_clear;
extern int SSL_clear(SSL *);
%rename(ssl_do_handshake) SSL_do_handshake;
%threadallow SSL_do_handshake;
extern int SSL_do_handshake(SSL *);
%rename(ssl_renegotiate) SSL_renegotiate;
%threadallow SSL_renegotiate;
extern int SSL_renegotiate(SSL *);
%rename(ssl_pending) SSL_pending;
extern int SSL_pending(const SSL *);
%rename(ssl_get_peer_cert) SSL_get_peer_certificate;
extern X509 *SSL_get_peer_certificate(const SSL *);
%rename(ssl_get_current_cipher) SSL_get_current_cipher;
extern SSL_CIPHER *SSL_get_current_cipher(const SSL *);
%rename(ssl_get_verify_mode) SSL_get_verify_mode;
extern int SSL_get_verify_mode(const SSL *);
%rename(ssl_get_verify_depth) SSL_get_verify_depth;
extern int SSL_get_verify_depth(const SSL *);
%rename(ssl_get_verify_result) SSL_get_verify_result;
extern long SSL_get_verify_result(const SSL *);
%rename(ssl_get_ssl_ctx) SSL_get_SSL_CTX;
extern SSL_CTX *SSL_get_SSL_CTX(const SSL *);
%rename(ssl_get_default_session_timeout) SSL_get_default_timeout;
extern long SSL_get_default_timeout(const SSL *);
%rename(ssl_set_cipher_list) SSL_set_cipher_list;
extern int SSL_set_cipher_list(SSL *, const char *);
%rename(ssl_get_cipher_list) SSL_get_cipher_list;
extern const char *SSL_get_cipher_list(const SSL *, int);
%rename(ssl_cipher_get_name) SSL_CIPHER_get_name;
extern const char *SSL_CIPHER_get_name(const SSL_CIPHER *);
%rename(ssl_cipher_get_version) SSL_CIPHER_get_version;
extern char *SSL_CIPHER_get_version(const SSL_CIPHER *);
%rename(ssl_get_session) SSL_get_session;
extern SSL_SESSION *SSL_get_session(const SSL *);
%rename(ssl_get1_session) SSL_get1_session;
extern SSL_SESSION *SSL_get1_session(SSL *);
%rename(ssl_set_session) SSL_set_session;
extern int SSL_set_session(SSL *, SSL_SESSION *);
%rename(ssl_session_free) SSL_SESSION_free;
extern void SSL_SESSION_free(SSL_SESSION *);
%rename(ssl_session_print) SSL_SESSION_print;
%threadallow SSL_SESSION_print;
extern int SSL_SESSION_print(BIO *, const SSL_SESSION *);
%rename(ssl_session_set_timeout) SSL_SESSION_set_timeout;
extern long SSL_SESSION_set_timeout(SSL_SESSION *, long);
%rename(ssl_session_get_timeout) SSL_SESSION_get_timeout;
extern long SSL_SESSION_get_timeout(const SSL_SESSION *);
extern PyObject *ssl_accept(SSL *ssl, double timeout = -1);
extern PyObject *ssl_connect(SSL *ssl, double timeout = -1);
extern PyObject *ssl_read(SSL *ssl, int num, double timeout = -1);
extern int ssl_write(SSL *ssl, PyObject *blob, double timeout = -1);
%constant int ssl_error_none = SSL_ERROR_NONE;
%constant int ssl_error_ssl = SSL_ERROR_SSL;
%constant int ssl_error_want_read = SSL_ERROR_WANT_READ;
%constant int ssl_error_want_write = SSL_ERROR_WANT_WRITE;
%constant int ssl_error_want_x509_lookup = SSL_ERROR_WANT_X509_LOOKUP;
%constant int ssl_error_syscall = SSL_ERROR_SYSCALL;
%constant int ssl_error_zero_return = SSL_ERROR_ZERO_RETURN;
%constant int ssl_error_want_connect = SSL_ERROR_WANT_CONNECT;
%constant int SSL_VERIFY_NONE = 0x00;
%constant int SSL_VERIFY_PEER = 0x01;
%constant int SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 0x02;
%constant int SSL_VERIFY_CLIENT_ONCE = 0x04;
%constant int VERIFY_CRL_CHECK_LEAF = X509_V_FLAG_CRL_CHECK;
%constant int VERIFY_CRL_CHECK_CHAIN = X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL;
%constant int SSL_ST_CONNECT = 0x1000;
%constant int SSL_ST_ACCEPT = 0x2000;
%constant int SSL_ST_MASK = 0x0FFF;
%constant int SSL_ST_INIT = (SSL_ST_CONNECT|SSL_ST_ACCEPT);
%constant int SSL_ST_BEFORE = 0x4000;
%constant int SSL_ST_OK = 0x03;
/* SWIG 3.0.1 complains about the next line -- simplified declaration for now */
/*%constant int SSL_ST_RENEGOTIATE = (0x04|SSL_ST_INIT);*/
%constant int SSL_ST_RENEGOTIATE = (0x04|SSL_ST_CONNECT|SSL_ST_ACCEPT);
%constant int SSL_CB_LOOP = 0x01;
%constant int SSL_CB_EXIT = 0x02;
%constant int SSL_CB_READ = 0x04;
%constant int SSL_CB_WRITE = 0x08;
%constant int SSL_CB_ALERT = 0x4000; /* used in callback */
%constant int SSL_CB_READ_ALERT = (SSL_CB_ALERT|SSL_CB_READ);
%constant int SSL_CB_WRITE_ALERT = (SSL_CB_ALERT|SSL_CB_WRITE);
%constant int SSL_CB_ACCEPT_LOOP = (SSL_ST_ACCEPT|SSL_CB_LOOP);
%constant int SSL_CB_ACCEPT_EXIT = (SSL_ST_ACCEPT|SSL_CB_EXIT);
%constant int SSL_CB_CONNECT_LOOP = (SSL_ST_CONNECT|SSL_CB_LOOP);
%constant int SSL_CB_CONNECT_EXIT = (SSL_ST_CONNECT|SSL_CB_EXIT);
%constant int SSL_CB_HANDSHAKE_START = 0x10;
%constant int SSL_CB_HANDSHAKE_DONE = 0x20;
%constant int SSL_SENT_SHUTDOWN = 1;
%constant int SSL_RECEIVED_SHUTDOWN = 2;
%constant int SSL_SESS_CACHE_OFF = 0x000;
%constant int SSL_SESS_CACHE_CLIENT = 0x001;
%constant int SSL_SESS_CACHE_SERVER = 0x002;
%constant int SSL_SESS_CACHE_BOTH = (SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_SERVER);
%constant int SSL_OP_ALL = 0x00000FFFL;
%constant int SSL_OP_NO_SSLv2 = 0x01000000L;
%constant int SSL_OP_NO_SSLv3 = 0x02000000L;
%constant int SSL_OP_NO_TLSv1 = 0x04000000L;
%constant int SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 0x00000800L;
%constant int SSL_MODE_ENABLE_PARTIAL_WRITE = SSL_MODE_ENABLE_PARTIAL_WRITE;
%constant int SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER = SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER;
%constant int SSL_MODE_AUTO_RETRY = SSL_MODE_AUTO_RETRY;
%ignore ssl_handle_error;
%ignore ssl_sleep_with_timeout;
%warnfilter(454) _ssl_err;
%warnfilter(454) _ssl_timeout_err;
%inline %{
static PyObject *_ssl_err;
static PyObject *_ssl_timeout_err;
void ssl_init(PyObject *ssl_err, PyObject *ssl_timeout_err) {
SSL_library_init();
SSL_load_error_strings();
Py_INCREF(ssl_err);
Py_INCREF(ssl_timeout_err);
_ssl_err = ssl_err;
_ssl_timeout_err = ssl_timeout_err;
}
const SSL_METHOD *tlsv1_method(void) {
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
PyErr_WarnEx(PyExc_DeprecationWarning,
"Function TLSv1_method has been deprecated.", 1);
#endif
return TLSv1_method();
}
void ssl_ctx_passphrase_callback(SSL_CTX *ctx, PyObject *pyfunc) {
SSL_CTX_set_default_passwd_cb(ctx, passphrase_callback);
SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *)pyfunc);
Py_INCREF(pyfunc);
}
int ssl_ctx_use_x509(SSL_CTX *ctx, X509 *x) {
int i;
if (!(i = SSL_CTX_use_certificate(ctx, x))) {
m2_PyErr_Msg(_ssl_err);
return -1;
}
return i;
}
int ssl_ctx_use_cert(SSL_CTX *ctx, char *file) {
int i;
if (!(i = SSL_CTX_use_certificate_file(ctx, file, SSL_FILETYPE_PEM))) {
m2_PyErr_Msg(_ssl_err);
return -1;
}
return i;
}
int ssl_ctx_use_cert_chain(SSL_CTX *ctx, char *file) {
int i;
if (!(i = SSL_CTX_use_certificate_chain_file(ctx, file))) {
m2_PyErr_Msg(_ssl_err);
return -1;
}
return i;
}
int ssl_ctx_use_privkey(SSL_CTX *ctx, char *file) {
int i;
if (!(i = SSL_CTX_use_PrivateKey_file(ctx, file, SSL_FILETYPE_PEM))) {
m2_PyErr_Msg(_ssl_err);
return -1;
}
return i;
}
int ssl_ctx_use_rsa_privkey(SSL_CTX *ctx, RSA *rsakey) {
int i;
if (!(i = SSL_CTX_use_RSAPrivateKey(ctx, rsakey))) {
m2_PyErr_Msg(_ssl_err);
return -1;
}
return i;
}
int ssl_ctx_use_pkey_privkey(SSL_CTX *ctx, EVP_PKEY *pkey) {
int i;
if (!(i = SSL_CTX_use_PrivateKey(ctx, pkey))) {
m2_PyErr_Msg(_ssl_err);
return -1;
}
return i;
}
int ssl_ctx_check_privkey(SSL_CTX *ctx) {
int ret;
if (!(ret = SSL_CTX_check_private_key(ctx))) {
m2_PyErr_Msg(_ssl_err);
return -1;
}
return ret;
}
void ssl_ctx_set_client_CA_list_from_file(SSL_CTX *ctx, const char *ca_file) {
SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(ca_file));
}
void ssl_ctx_set_verify_default(SSL_CTX *ctx, int mode) {
SSL_CTX_set_verify(ctx, mode, NULL);
}
void ssl_ctx_set_verify(SSL_CTX *ctx, int mode, PyObject *pyfunc) {
Py_XDECREF(ssl_verify_cb_func);
Py_INCREF(pyfunc);
ssl_verify_cb_func = pyfunc;
SSL_CTX_set_verify(ctx, mode, ssl_verify_callback);
}
int ssl_ctx_set_session_id_context(SSL_CTX *ctx, PyObject *sid_ctx) {
const void *buf = NULL;
int len = 0;
if (m2_PyObject_AsReadBufferInt(sid_ctx, &buf, &len) == -1)
return -1;
return SSL_CTX_set_session_id_context(ctx, buf, len);
}
void ssl_ctx_set_info_callback(SSL_CTX *ctx, PyObject *pyfunc) {
Py_XDECREF(ssl_info_cb_func);
Py_INCREF(pyfunc);
ssl_info_cb_func = pyfunc;
SSL_CTX_set_info_callback(ctx, ssl_info_callback);
}
long ssl_ctx_set_tmp_dh(SSL_CTX *ctx, DH* dh) {
return SSL_CTX_set_tmp_dh(ctx, dh);
}
void ssl_ctx_set_tmp_dh_callback(SSL_CTX *ctx, PyObject *pyfunc) {
Py_XDECREF(ssl_set_tmp_dh_cb_func);
Py_INCREF(pyfunc);
ssl_set_tmp_dh_cb_func = pyfunc;
SSL_CTX_set_tmp_dh_callback(ctx, ssl_set_tmp_dh_callback);
}
long ssl_ctx_set_tmp_rsa(SSL_CTX *ctx, RSA* rsa) {
return SSL_CTX_set_tmp_rsa(ctx, rsa);
}
void ssl_ctx_set_tmp_rsa_callback(SSL_CTX *ctx, PyObject *pyfunc) {
Py_XDECREF(ssl_set_tmp_rsa_cb_func);
Py_INCREF(pyfunc);
ssl_set_tmp_rsa_cb_func = pyfunc;
SSL_CTX_set_tmp_rsa_callback(ctx, ssl_set_tmp_rsa_callback);
}
int ssl_ctx_load_verify_locations(SSL_CTX *ctx, const char *cafile, const char *capath) {
return SSL_CTX_load_verify_locations(ctx, cafile, capath);
}
/* SSL_CTX_set_options is a macro. */
long ssl_ctx_set_options(SSL_CTX *ctx, long op) {
return SSL_CTX_set_options(ctx, op);
}
int bio_set_ssl(BIO *bio, SSL *ssl, int flag) {
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
return BIO_ctrl(bio, BIO_C_SET_SSL, flag, (char *)ssl);
}
long ssl_set_mode(SSL *ssl, long mode) {
return SSL_set_mode(ssl, mode);
}
long ssl_get_mode(SSL *ssl) {
return SSL_get_mode(ssl);
}
int ssl_set_tlsext_host_name(SSL *ssl, const char *name) {
long l;
if (!(l = SSL_set_tlsext_host_name(ssl, name))) {
m2_PyErr_Msg(_ssl_err);
return -1;
}
/* Return an "int" to match the 'typemap(out) int' in _lib.i */
return 1;
}
void ssl_set_client_CA_list_from_file(SSL *ssl, const char *ca_file) {
SSL_set_client_CA_list(ssl, SSL_load_client_CA_file(ca_file));
}
void ssl_set_client_CA_list_from_context(SSL *ssl, SSL_CTX *ctx) {
SSL_set_client_CA_list(ssl, SSL_CTX_get_client_CA_list(ctx));
}
int ssl_set_session_id_context(SSL *ssl, PyObject *sid_ctx) {
const void *buf = NULL;
int len = 0;
if (m2_PyObject_AsReadBufferInt(sid_ctx, &buf, &len) == -1)
return -1;
return SSL_set_session_id_context(ssl, buf, len);
}
int ssl_set_fd(SSL *ssl, int fd) {
int ret;
if (!(ret = SSL_set_fd(ssl, fd))) {
m2_PyErr_Msg(_ssl_err);
return -1;
}
return ret;
}
static void ssl_handle_error(int ssl_err, int ret) {
int err;
switch (ssl_err) {
case SSL_ERROR_SSL:
PyErr_SetString(_ssl_err,
ERR_reason_error_string(ERR_get_error()));
break;
case SSL_ERROR_SYSCALL:
err = ERR_get_error();
if (err)
PyErr_SetString(_ssl_err, ERR_reason_error_string(err));
else if (ret == 0)
PyErr_SetString(_ssl_err, "unexpected eof");
else if (ret == -1)
PyErr_SetFromErrno(_ssl_err);
else
assert(0);
break;
default:
PyErr_SetString(_ssl_err, "unexpected SSL error");
}
}
#ifdef _WIN32
/* http://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows */
int gettimeofday(struct timeval *tp, void *tzp)
{
// Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
SYSTEMTIME system_time;
FILETIME file_time;
uint64_t time;
GetSystemTime( &system_time );
SystemTimeToFileTime( &system_time, &file_time );
time = ((uint64_t)file_time.dwLowDateTime ) ;
time += ((uint64_t)file_time.dwHighDateTime) << 32;
tp->tv_sec = (long) ((time - EPOCH) / 10000000L);
tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
return 0;
}
#endif
static int ssl_sleep_with_timeout(SSL *ssl, const struct timeval *start,
double timeout, int ssl_err) {
#ifdef _WIN32
WSAPOLLFD fd;
#else
struct pollfd fd;
#endif
struct timeval tv;
int ms, tmp;
assert(timeout > 0);
again:
gettimeofday(&tv, NULL);
/* tv >= start */
if ((timeout + start->tv_sec - tv.tv_sec) > INT_MAX / 1000)
ms = -1;
else {
int fract;
ms = ((start->tv_sec + (int)timeout) - tv.tv_sec) * 1000;
fract = (int)((start->tv_usec + (timeout - (int)timeout) * 1000000
- tv.tv_usec + 999) / 1000);
if (ms > 0 && fract > INT_MAX - ms)
ms = -1;
else {
ms += fract;
if (ms <= 0)
goto timeout;
}
}
switch (ssl_err) {
case SSL_ERROR_WANT_READ:
fd.fd = SSL_get_rfd(ssl);
fd.events = POLLIN;
break;
case SSL_ERROR_WANT_WRITE:
fd.fd = SSL_get_wfd(ssl);
fd.events = POLLOUT;
break;
case SSL_ERROR_WANT_X509_LOOKUP:
return 0; /* FIXME: is this correct? */
default:
assert(0);
}
if (fd.fd == -1) {
PyErr_SetString(_ssl_err, "timeout on a non-FD SSL");
return -1;
}
Py_BEGIN_ALLOW_THREADS
#ifdef _WIN32
tmp = WSAPoll(&fd, 1, ms);
#else
tmp = poll(&fd, 1, ms);
#endif
Py_END_ALLOW_THREADS
switch (tmp) {
case 1:
return 0;
case 0:
goto timeout;
case -1:
#ifdef _WIN32
if (WSAGetLastError() == EINTR)
#else
if (errno == EINTR)
#endif
goto again;
PyErr_SetFromErrno(_ssl_err);
return -1;
}
return 0;
timeout:
PyErr_SetString(_ssl_timeout_err, "timed out");
return -1;
}
PyObject *ssl_accept(SSL *ssl, double timeout) {
PyObject *obj = NULL;
int r, ssl_err;
struct timeval tv;
if (timeout > 0)
gettimeofday(&tv, NULL);
again:
Py_BEGIN_ALLOW_THREADS
r = SSL_accept(ssl);
ssl_err = SSL_get_error(ssl, r);
Py_END_ALLOW_THREADS
switch (ssl_err) {
case SSL_ERROR_NONE:
case SSL_ERROR_ZERO_RETURN:
obj = PyLong_FromLong((long)1);
break;
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_READ:
if (timeout <= 0) {
obj = PyLong_FromLong((long)0);
break;
}
if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0)
goto again;
obj = NULL;
break;
case SSL_ERROR_SSL:
case SSL_ERROR_SYSCALL:
ssl_handle_error(ssl_err, r);
obj = NULL;
break;
}
return obj;
}
PyObject *ssl_connect(SSL *ssl, double timeout) {
PyObject *obj = NULL;
int r, ssl_err;
struct timeval tv;
if (timeout > 0)
gettimeofday(&tv, NULL);
again:
Py_BEGIN_ALLOW_THREADS
r = SSL_connect(ssl);
ssl_err = SSL_get_error(ssl, r);
Py_END_ALLOW_THREADS
switch (ssl_err) {
case SSL_ERROR_NONE:
case SSL_ERROR_ZERO_RETURN:
obj = PyLong_FromLong((long)1);
break;
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_READ:
if (timeout <= 0) {
obj = PyLong_FromLong((long)0);
break;
}
if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0)
goto again;
obj = NULL;
break;
case SSL_ERROR_SSL:
case SSL_ERROR_SYSCALL:
ssl_handle_error(ssl_err, r);
obj = NULL;
break;
}
return obj;
}
void ssl_set_shutdown1(SSL *ssl, int mode) {
SSL_set_shutdown(ssl, mode);
}
PyObject *ssl_read(SSL *ssl, int num, double timeout) {
PyObject *obj = NULL;
void *buf;
int r;
struct timeval tv;
if (!(buf = PyMem_Malloc(num))) {
PyErr_SetString(PyExc_MemoryError, "ssl_read");
return NULL;
}
if (timeout > 0)
gettimeofday(&tv, NULL);
again:
Py_BEGIN_ALLOW_THREADS
r = SSL_read(ssl, buf, num);
Py_END_ALLOW_THREADS
if (r >= 0) {
buf = PyMem_Realloc(buf, r);
obj = PyBytes_FromStringAndSize(buf, r);
} else {
int ssl_err;
ssl_err = SSL_get_error(ssl, r);
switch (ssl_err) {
case SSL_ERROR_NONE:
case SSL_ERROR_ZERO_RETURN:
assert(0);
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_X509_LOOKUP:
if (timeout <= 0) {
Py_INCREF(Py_None);
obj = Py_None;
break;
}
if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0)
goto again;
obj = NULL;
break;
case SSL_ERROR_SSL:
case SSL_ERROR_SYSCALL:
ssl_handle_error(ssl_err, r);
obj = NULL;
break;
}
}
PyMem_Free(buf);
return obj;
}
PyObject *ssl_read_nbio(SSL *ssl, int num) {
PyObject *obj = NULL;
void *buf;
int r, err;
if (!(buf = PyMem_Malloc(num))) {
PyErr_SetString(PyExc_MemoryError, "ssl_read");
return NULL;
}
Py_BEGIN_ALLOW_THREADS
r = SSL_read(ssl, buf, num);
Py_END_ALLOW_THREADS
switch (SSL_get_error(ssl, r)) {
case SSL_ERROR_NONE:
case SSL_ERROR_ZERO_RETURN:
buf = PyMem_Realloc(buf, r);
obj = PyBytes_FromStringAndSize(buf, r);
break;
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_X509_LOOKUP:
Py_INCREF(Py_None);
obj = Py_None;
break;
case SSL_ERROR_SSL:
m2_PyErr_Msg(_ssl_err);
obj = NULL;
break;
case SSL_ERROR_SYSCALL:
err = ERR_get_error();
if (err)
PyErr_SetString(_ssl_err, ERR_reason_error_string(err));
else if (r == 0)
PyErr_SetString(_ssl_err, "unexpected eof");
else if (r == -1)
PyErr_SetFromErrno(_ssl_err);
obj = NULL;
break;
}
PyMem_Free(buf);
return obj;
}
int ssl_write(SSL *ssl, PyObject *blob, double timeout) {
Py_buffer buf;
int r, ssl_err, ret;
struct timeval tv;
if (m2_PyObject_GetBufferInt(blob, &buf, PyBUF_CONTIG_RO) == -1) {
return -1;
}
if (timeout > 0)
gettimeofday(&tv, NULL);
again:
Py_BEGIN_ALLOW_THREADS
r = SSL_write(ssl, buf.buf, buf.len);
ssl_err = SSL_get_error(ssl, r);
Py_END_ALLOW_THREADS
switch (ssl_err) {
case SSL_ERROR_NONE:
case SSL_ERROR_ZERO_RETURN:
ret = r;
break;
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_X509_LOOKUP:
if (timeout <= 0) {
ret = -1;
break;
}
if (ssl_sleep_with_timeout(ssl, &tv, timeout, ssl_err) == 0)
goto again;
ret = -1;
break;
case SSL_ERROR_SSL:
case SSL_ERROR_SYSCALL:
ssl_handle_error(ssl_err, r);
default:
ret = -1;
}
m2_PyBuffer_Release(blob, &buf);
return ret;
}
int ssl_write_nbio(SSL *ssl, PyObject *blob) {
Py_buffer buf;
int r, err, ret;
if (m2_PyObject_GetBufferInt(blob, &buf, PyBUF_CONTIG_RO) == -1) {
return -1;
}
Py_BEGIN_ALLOW_THREADS
r = SSL_write(ssl, buf.buf, buf.len);
Py_END_ALLOW_THREADS
switch (SSL_get_error(ssl, r)) {
case SSL_ERROR_NONE:
case SSL_ERROR_ZERO_RETURN:
ret = r;
break;
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_X509_LOOKUP:
ret = -1;
break;
case SSL_ERROR_SSL:
ret = -1;
break;
case SSL_ERROR_SYSCALL:
err = ERR_get_error();
if (err)
PyErr_SetString(_ssl_err, ERR_reason_error_string(err));
else if (r == 0)
PyErr_SetString(_ssl_err, "unexpected eof");
else if (r == -1)
PyErr_SetFromErrno(_ssl_err);
default:
ret = -1;
}
m2_PyBuffer_Release(blob, &buf);
return ret;
}
int ssl_cipher_get_bits(SSL_CIPHER *c) {
return SSL_CIPHER_get_bits(c, NULL);
}
int sk_ssl_cipher_num(STACK_OF(SSL_CIPHER) *stack) {
return sk_SSL_CIPHER_num(stack);
}
const SSL_CIPHER *sk_ssl_cipher_value(STACK_OF(SSL_CIPHER) *stack, int idx) {
return sk_SSL_CIPHER_value(stack, idx);
}
STACK_OF(X509) *ssl_get_peer_cert_chain(SSL *ssl) {
return SSL_get_peer_cert_chain(ssl);
}
int sk_x509_num(STACK_OF(X509) *stack) {
return sk_X509_num(stack);
}
X509 *sk_x509_value(STACK_OF(X509) *stack, int idx) {
return sk_X509_value(stack, idx);
}
%}
%threadallow i2d_ssl_session;
%inline %{
void i2d_ssl_session(BIO *bio, SSL_SESSION *sess) {
i2d_SSL_SESSION_bio(bio, sess);
}
%}
%typemap(out) SSL_SESSION * {
PyObject *self = NULL; /* bug in SWIG_NewPointerObj as of 3.0.5 */
if ($1 != NULL)
$result = SWIG_NewPointerObj($1, $1_descriptor, 0);
else {
m2_PyErr_Msg(_ssl_err);
$result = NULL;
}
}
%threadallow ssl_session_read_pem;
%inline %{
SSL_SESSION *ssl_session_read_pem(BIO *bio) {
return PEM_read_bio_SSL_SESSION(bio, NULL, NULL, NULL);
}
%}
%typemap(out) SSL_SESSION * ;
%threadallow ssl_session_write_pem;
%inline %{
int ssl_session_write_pem(SSL_SESSION *sess, BIO *bio) {
return PEM_write_bio_SSL_SESSION(bio, sess);
}
int ssl_ctx_set_session_cache_mode(SSL_CTX *ctx, int mode)
{
return SSL_CTX_set_session_cache_mode(ctx, mode);
}
int ssl_ctx_get_session_cache_mode(SSL_CTX *ctx)
{
return SSL_CTX_get_session_cache_mode(ctx);
}
static long ssl_ctx_set_cache_size(SSL_CTX *ctx, long arg)
{
return SSL_CTX_sess_set_cache_size(ctx, arg);
}
int ssl_is_init_finished(SSL *ssl)
{
return SSL_is_init_finished(ssl);
}
%}
m2crypto-0.42.0/src/SWIG/_threads.i 0000664 0000000 0000000 00000003423 14655756567 0016713 0 ustar 00root root 0000000 0000000 /* 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