├── .appveyor.yml
├── .editorconfig
├── .gitattributes
├── .github
└── workflows
│ ├── linuxbrew.yml
│ ├── macosx.yml
│ ├── manylinux.yml
│ ├── sdist.yml
│ └── wheels.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .readthedocs.yaml
├── .travis.yml
├── LICENSE
├── MANIFEST.in
├── README.rst
├── doc
├── Makefile
└── source
│ ├── api.rst
│ ├── conf.py
│ ├── examples.rst
│ ├── examples
│ ├── decrypt.py
│ ├── enc1-doc.xml
│ ├── enc1-res.xml
│ ├── encrypt.py
│ ├── rsacert.pem
│ ├── rsakey.pem
│ ├── rsapub.pem
│ ├── sign.py
│ ├── sign1-res.xml
│ ├── sign1-tmpl.xml
│ ├── sign_binary.py
│ ├── verify.py
│ └── verify_binary.py
│ ├── index.rst
│ ├── install.rst
│ ├── modules
│ ├── constants.rst
│ ├── template.rst
│ ├── tree.rst
│ └── xmlsec.rst
│ └── requirements.txt
├── pyproject.toml
├── requirements-test.txt
├── requirements.txt
├── setup.cfg
├── setup.py
├── src
├── common.h
├── constants.c
├── constants.h
├── debug.h
├── ds.c
├── enc.c
├── exception.c
├── exception.h
├── keys.c
├── keys.h
├── lxml.c
├── lxml.h
├── main.c
├── platform.h
├── template.c
├── tree.c
├── utils.c
├── utils.h
└── xmlsec
│ ├── __init__.pyi
│ ├── constants.pyi
│ ├── py.typed
│ ├── template.pyi
│ └── tree.pyi
└── tests
├── __init__.py
├── base.py
├── conftest.py
├── data
├── deskey.bin
├── doc.xml
├── dsacert.der
├── dsakey.der
├── enc1-in.xml
├── enc1-out.xml
├── enc2-in.xml
├── enc2-out.xml
├── enc3-in.xml
├── enc3-out.xml
├── enc_template.xml
├── rsacert.pem
├── rsakey.pem
├── rsapub.pem
├── sign1-in.xml
├── sign1-out.xml
├── sign2-in.xml
├── sign2-out.xml
├── sign3-in.xml
├── sign3-out.xml
├── sign4-in.xml
├── sign4-out.xml
├── sign5-in.xml
├── sign5-out-xmlsec_1_2_36_to_37.xml
├── sign5-out.xml
├── sign6-in.bin
├── sign6-out.bin
└── sign_template.xml
├── softhsm_setup.py
├── test_constants.py
├── test_doc_examples.py
├── test_ds.py
├── test_enc.py
├── test_keys.py
├── test_main.py
├── test_pkcs11.py
├── test_templates.py
├── test_tree.py
├── test_type_stubs.py
└── test_xmlsec.py
/.appveyor.yml:
--------------------------------------------------------------------------------
1 | environment:
2 | matrix:
3 | - python: 35
4 | - python: 35-x64
5 | - python: 36
6 | - python: 36-x64
7 | - python: 37
8 | - python: 37-x64
9 | - python: 38
10 | - python: 38-x64
11 | - python: 39
12 | python_version: 3.9.13
13 | - python: 39-x64
14 | python_version: 3.9.13
15 | - python: 310
16 | python_version: 3.10.6
17 | - python: 310-x64
18 | python_version: 3.10.6
19 | - python: 311
20 | python_version: 3.11.2
21 | - python: 311-x64
22 | python_version: 3.11.2
23 |
24 | install:
25 | - ps: |
26 | # from https://github.com/appveyor/build-images/blob/27bde614bc60d7ef7a8bc46182f4d7582fa11b56/scripts/Windows/install_python.ps1#L88-L108
27 | function InstallPythonEXE($targetPath, $version) {
28 | $urlPlatform = ""
29 | if ($targetPath -match '-x64$') {
30 | $urlPlatform = "-amd64"
31 | }
32 | Write-Host "Installing Python $version$urlPlatform to $($targetPath)..." -ForegroundColor Cyan
33 | $downloadUrl = "https://www.python.org/ftp/python/$version/python-$version$urlPlatform.exe"
34 | Write-Host "Downloading $($downloadUrl)..."
35 | $exePath = "$env:TEMP\python-$version.exe"
36 | (New-Object Net.WebClient).DownloadFile($downloadUrl, $exePath)
37 | Write-Host "Installing..."
38 | cmd /c start /wait $exePath /quiet TargetDir="$targetPath" Shortcuts=0 Include_launcher=1 InstallLauncherAllUsers=1 Include_debug=1
39 | Remove-Item $exePath
40 | Write-Host "Installed Python $version" -ForegroundColor Green
41 | }
42 | if ( -not ( Test-Path -Path C:\\Python$env:PYTHON -PathType Container ) ) {
43 | InstallPythonEXE C:\\Python$env:PYTHON $env:PYTHON_VERSION
44 | }
45 | - SET PATH=C:\\Python%PYTHON%;c:\\Python%PYTHON%\\scripts;%PATH%
46 | - python -m pip install -U pip wheel setuptools
47 |
48 | build: off
49 | build_script:
50 | - python setup.py bdist_wheel
51 |
52 | test: off
53 | test_script:
54 | - pip install -r requirements-test.txt
55 | - pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist
56 | - pytest -v --color=yes --junitxml=unittests.xml
57 | - ps: Get-ChildItem dist\*.whl | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
58 |
59 | on_finish:
60 | - ps: |
61 | # archive test results at AppVeyor
62 | $wc = New-Object 'System.Net.WebClient'
63 | $wc.UploadFile("https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\unittests.xml))
64 | $LastExitCode = 0
65 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 4
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.github/workflows/linuxbrew.yml:
--------------------------------------------------------------------------------
1 | name: linuxbrew
2 | on: [push, pull_request]
3 | jobs:
4 | linuxbrew:
5 | runs-on: ubuntu-latest
6 | strategy:
7 | matrix:
8 | python: ["3.9", "3.10", "3.11", "3.12", "3.13"]
9 | steps:
10 | - uses: actions/checkout@v3
11 | - name: Install brew
12 | run: |
13 | sudo apt install -y build-essential procps curl file git
14 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
15 | echo "/home/linuxbrew/.linuxbrew/bin" >> $GITHUB_PATH
16 | - name: Install build dependencies
17 | run: |
18 | brew update
19 | brew install python@${{ matrix.python }} gcc libxml2 libxmlsec1 pkg-config
20 | echo "/home/linuxbrew/.linuxbrew/opt/python@${{ matrix.python }}/libexec/bin" >> $GITHUB_PATH
21 | - name: Build wheel
22 | run: |
23 | python3 -m venv build_venv
24 | source build_venv/bin/activate
25 | pip3 install --upgrade setuptools wheel build
26 | export CFLAGS="-I$(brew --prefix)/include"
27 | export LDFLAGS="-L$(brew --prefix)/lib"
28 | python3 -m build
29 | rm -rf build/
30 | - name: Run tests
31 | run: |
32 | python3 -m venv test_venv
33 | source test_venv/bin/activate
34 | pip3 install --upgrade --no-binary=lxml -r requirements-test.txt
35 | pip3 install xmlsec --only-binary=xmlsec --no-index --find-links=dist/
36 | pytest -v --color=yes
37 |
--------------------------------------------------------------------------------
/.github/workflows/macosx.yml:
--------------------------------------------------------------------------------
1 | name: MacOS
2 | on: [push, pull_request]
3 | jobs:
4 | macosx:
5 | runs-on: macos-latest
6 | strategy:
7 | matrix:
8 | python: ["3.9", "3.10", "3.11", "3.12", "3.13"]
9 | static_deps: ["static", ""]
10 | steps:
11 | - uses: actions/checkout@v3
12 | - name: Setup Python
13 | uses: actions/setup-python@v4
14 | with:
15 | python-version: ${{ matrix.python }}
16 | - name: Install build dependencies
17 | run: |
18 | pip install --upgrade pip setuptools wheel build
19 | brew install libxml2 libxmlsec1 pkg-config
20 | - name: Build macosx_x86_64 wheel
21 | env:
22 | CC: clang
23 | CFLAGS: "-fprofile-instr-generate -fcoverage-mapping"
24 | LDFLAGS: "-fprofile-instr-generate -fcoverage-mapping"
25 | PYXMLSEC_STATIC_DEPS: ${{ matrix.static_deps }}
26 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27 | run: |
28 | export PKG_CONFIG_PATH="$(brew --prefix)/opt/libxml2/lib/pkgconfig"
29 | python -m build
30 | rm -rf build/
31 | - name: Set environment variables
32 | shell: bash
33 | run: |
34 | echo "PKGVER=$(python setup.py --version)" >> $GITHUB_ENV
35 | echo "LLVM_PROFILE_FILE=pyxmlsec.profraw" >> $GITHUB_ENV
36 | - name: Install test dependencies
37 | run: |
38 | export PKG_CONFIG_PATH="$(brew --prefix)/opt/libxml2/lib/pkgconfig"
39 | pip install coverage --upgrade --no-binary=lxml -r requirements-test.txt
40 | pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/
41 | echo "PYXMLSEC_LIBFILE=$(python -c 'import xmlsec; print(xmlsec.__file__)')" >> $GITHUB_ENV
42 | - name: Run tests
43 | run: |
44 | coverage run -m pytest -v --color=yes
45 | - name: Report coverage to codecov
46 | run: |
47 | /Library/Developer/CommandLineTools/usr/bin/llvm-profdata merge -sparse ${{ env.LLVM_PROFILE_FILE }} -output pyxmlsec.profdata
48 | /Library/Developer/CommandLineTools/usr/bin/llvm-cov show ${{ env.PYXMLSEC_LIBFILE }} --arch=$(uname -m) --instr-profile=pyxmlsec.profdata src > coverage.txt
49 | bash <(curl -s https://codecov.io/bash) -f coverage.txt
50 | if: matrix.static_deps != 'static'
51 |
--------------------------------------------------------------------------------
/.github/workflows/manylinux.yml:
--------------------------------------------------------------------------------
1 | name: manylinux
2 | on: [push, pull_request]
3 | jobs:
4 | manylinux:
5 | runs-on: ubuntu-latest
6 | strategy:
7 | matrix:
8 | python-abi: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39, cp310-cp310, cp311-cp311]
9 | image:
10 | - manylinux2014_x86_64
11 | - manylinux_2_28_x86_64
12 | - musllinux_1_1_x86_64
13 | container: quay.io/pypa/${{ matrix.image }}
14 | steps:
15 | - uses: actions/checkout@v1
16 | - name: Install python build dependencies
17 | run: |
18 | # https://github.com/actions/runner/issues/2033
19 | chown -R $(id -u):$(id -g) $PWD
20 | /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade pip setuptools wheel build
21 | - name: Install system build dependencies (manylinux)
22 | run: |
23 | yum install -y perl-core
24 | if: contains(matrix.image, 'manylinux')
25 | - name: Set environment variables
26 | shell: bash
27 | run: |
28 | echo "PKGVER=$(/opt/python/${{ matrix.python-abi }}/bin/python setup.py --version)" >> $GITHUB_ENV
29 | - name: Build linux_x86_64 wheel
30 | env:
31 | PYXMLSEC_STATIC_DEPS: true
32 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33 | run: |
34 | /opt/python/${{ matrix.python-abi }}/bin/python -m build
35 | - name: Label manylinux wheel
36 | run: |
37 | ls -la dist/
38 | auditwheel show dist/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-linux_x86_64.whl
39 | auditwheel repair dist/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-linux_x86_64.whl
40 | ls -la wheelhouse/
41 | auditwheel show wheelhouse/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-*${{ matrix.image }}*.whl
42 | - name: Install test dependencies
43 | run: |
44 | /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade -r requirements-test.txt
45 | /opt/python/${{ matrix.python-abi }}/bin/pip install xmlsec --only-binary=xmlsec --no-index --find-links=wheelhouse/
46 | - name: Run tests
47 | run: |
48 | /opt/python/${{ matrix.python-abi }}/bin/pytest -v --color=yes
49 |
--------------------------------------------------------------------------------
/.github/workflows/sdist.yml:
--------------------------------------------------------------------------------
1 | name: sdist
2 | on: [push, pull_request]
3 | jobs:
4 | sdist:
5 | runs-on: ubuntu-latest
6 | strategy:
7 | matrix:
8 | python: ["3.9", "3.10", "3.11", "3.12", "3.13"]
9 | steps:
10 | - uses: actions/checkout@v3
11 | - name: Set up Python
12 | uses: actions/setup-python@v4
13 | with:
14 | python-version: ${{ matrix.python }}
15 | - name: Install build dependencies
16 | run: |
17 | pip install --upgrade pip setuptools wheel
18 | - name: Package source dist
19 | run: |
20 | python setup.py sdist
21 | - name: Install test dependencies
22 | run: |
23 | sudo apt-get update
24 | sudo apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-openssl opensc softhsm2 libengine-pkcs11-openssl
25 | pip install --upgrade -r requirements-test.txt --no-binary lxml
26 | pip install dist/xmlsec-$(python setup.py --version).tar.gz
27 | - name: Run tests
28 | run: |
29 | pytest -v --color=yes
30 |
--------------------------------------------------------------------------------
/.github/workflows/wheels.yml:
--------------------------------------------------------------------------------
1 | name: Wheel build
2 |
3 | on:
4 | release:
5 | types: [created]
6 | schedule:
7 | # ┌───────────── minute (0 - 59)
8 | # │ ┌───────────── hour (0 - 23)
9 | # │ │ ┌───────────── day of the month (1 - 31)
10 | # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
11 | # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
12 | # │ │ │ │ │
13 | - cron: "42 3 * * 4"
14 | push:
15 | pull_request:
16 | workflow_dispatch:
17 |
18 | permissions: {}
19 |
20 | jobs:
21 | sdist:
22 | runs-on: ubuntu-latest
23 |
24 | permissions:
25 | contents: write
26 |
27 | steps:
28 | - uses: actions/checkout@v4.1.1
29 | with:
30 | fetch-depth: 0
31 |
32 | - name: Set up Python
33 | uses: actions/setup-python@v5.0.0
34 | with:
35 | python-version: "3.x"
36 |
37 | - name: Install build dependencies
38 | run: |
39 | pip install --upgrade pip setuptools wheel
40 |
41 | - name: Package source dist
42 | run: python setup.py sdist
43 |
44 | - name: Install test dependencies
45 | run: |
46 | sudo apt-get update -y -q
47 | sudo apt-get install -y -q libxml2-dev libxslt1-dev libxmlsec1-dev libxmlsec1-openssl opensc softhsm2 libengine-pkcs11-openssl
48 | pip install --upgrade -r requirements-test.txt --no-binary lxml
49 | pip install dist/xmlsec-$(python setup.py --version).tar.gz
50 |
51 | - name: Run tests
52 | run: pytest -v --color=yes
53 |
54 | - name: Upload sdist
55 | uses: actions/upload-artifact@v4.3.1
56 | with:
57 | name: sdist
58 | path: dist/*.tar.gz
59 |
60 | generate-wheels-matrix:
61 | # Create a matrix of all architectures & versions to build.
62 | # This enables the next step to run cibuildwheel in parallel.
63 | # From https://iscinumpy.dev/post/cibuildwheel-2-10-0/#only-210
64 | name: Generate wheels matrix
65 | runs-on: ubuntu-latest
66 | outputs:
67 | include: ${{ steps.set-matrix.outputs.include }}
68 | steps:
69 | - uses: actions/checkout@v4
70 | - name: Install cibuildwheel
71 | # Nb. keep cibuildwheel version pin consistent with job below
72 | run: pipx install cibuildwheel==2.21.3
73 | - id: set-matrix
74 | # Once we have the windows build figured out, it can be added here
75 | # by updating the matrix to include windows builds as well.
76 | # See example here:
77 | # https://github.com/lxml/lxml/blob/3ccc7d583e325ceb0ebdf8fc295bbb7fc8cd404d/.github/workflows/wheels.yml#L95C1-L106C51
78 | run: |
79 | MATRIX=$(
80 | {
81 | cibuildwheel --print-build-identifiers --platform linux \
82 | | jq -nRc '{"only": inputs, "os": "ubuntu-latest"}' \
83 | && cibuildwheel --print-build-identifiers --platform macos \
84 | | jq -nRc '{"only": inputs, "os": "macos-latest"}' \
85 | && cibuildwheel --print-build-identifiers --platform windows \
86 | | jq -nRc '{"only": inputs, "os": "windows-2019"}'
87 | } | jq -sc
88 | )
89 | echo "include=$MATRIX"
90 | echo "include=$MATRIX" >> $GITHUB_OUTPUT
91 |
92 | build_wheels:
93 | name: Build for ${{ matrix.only }}
94 | needs: generate-wheels-matrix
95 | runs-on: ${{ matrix.os }}
96 |
97 | strategy:
98 | fail-fast: false
99 | matrix:
100 | include: ${{ fromJson(needs.generate-wheels-matrix.outputs.include) }}
101 |
102 | env:
103 | PYXMLSEC_LIBXML2_VERSION: 2.13.5
104 | PYXMLSEC_LIBXSLT_VERSION: 1.1.42
105 |
106 | steps:
107 | - name: Check out the repo
108 | uses: actions/checkout@v4
109 | with:
110 | fetch-depth: 0
111 |
112 | - name: Set up QEMU
113 | if: runner.os == 'Linux'
114 | uses: docker/setup-qemu-action@v3
115 | with:
116 | platforms: all
117 |
118 | - name: Build wheels
119 | uses: pypa/cibuildwheel@v2.21.3
120 | with:
121 | only: ${{ matrix.only }}
122 | env:
123 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
124 |
125 | - uses: actions/upload-artifact@v4.3.1
126 | with:
127 | path: ./wheelhouse/*.whl
128 | name: xmlsec-wheel-${{ matrix.only }}
129 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Dot files
2 | .*
3 | !.editorconfig
4 | !.travis*
5 | !.appveyor*
6 | !.git*
7 | !.readthedocs.yaml
8 | !.pre-commit-config.yaml
9 |
10 | # Python
11 | /dist
12 | /build
13 | *.pyc
14 | *.pyo
15 | *.egg*
16 | *.so
17 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | # See https://pre-commit.com for more information
2 | # See https://pre-commit.com/hooks.html for more hooks
3 | repos:
4 | - repo: https://github.com/psf/black
5 | rev: 24.3.0
6 | hooks:
7 | - id: black
8 | types: []
9 | files: ^.*.pyi?$
10 | exclude: ^doc/
11 | - repo: https://github.com/pre-commit/pre-commit-hooks
12 | rev: v4.6.0
13 | hooks:
14 | - id: no-commit-to-branch
15 | - id: trailing-whitespace
16 | - id: end-of-file-fixer
17 | - id: check-yaml
18 | - id: check-added-large-files
19 | - id: check-ast
20 | - id: check-merge-conflict
21 | - id: check-json
22 | - id: detect-private-key
23 | exclude: ^.*/rsakey.pem$
24 | - id: mixed-line-ending
25 | - id: pretty-format-json
26 | args: [--autofix]
27 | - repo: https://github.com/PyCQA/flake8
28 | rev: 7.0.0
29 | hooks:
30 | - id: flake8
31 | exclude: ^setup.py$
32 | additional_dependencies: [flake8-docstrings, flake8-bugbear, flake8-logging-format, flake8-builtins, flake8-eradicate, flake8-fixme, pep8-naming, flake8-pep3101, flake8-annotations-complexity,flake8-pyi]
33 | - repo: https://github.com/PyCQA/isort
34 | rev: 5.13.2
35 | hooks:
36 | - id: isort
37 | - repo: https://github.com/pre-commit/mirrors-mypy
38 | rev: v1.9.0
39 | hooks:
40 | - id: mypy
41 | exclude: (setup.py|tests/.*.py|doc/.*)
42 | types: []
43 | files: ^.*.pyi?$
44 | additional_dependencies: [lxml-stubs,types-docutils]
45 | - repo: https://github.com/pre-commit/pygrep-hooks
46 | rev: v1.10.0
47 | hooks:
48 | - id: rst-backticks
49 |
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | version: 2
2 |
3 | build:
4 | os: ubuntu-20.04
5 | tools:
6 | python: '3.9'
7 |
8 | sphinx:
9 | configuration: doc/source/conf.py
10 |
11 | python:
12 | install:
13 | - method: pip
14 | path: .
15 | - requirements: doc/source/requirements.txt
16 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: trusty
2 | sudo: false
3 | language: python
4 | notifications:
5 | email: false
6 | matrix:
7 | include:
8 | - python: 3.5
9 | - python: 3.6
10 | - python: 3.7
11 | dist: xenial
12 | sudo: required
13 | - python: 3.8
14 | dist: xenial
15 | sudo: required
16 | - python: 3.9
17 | dist: xenial
18 | sudo: required
19 | - python: 3.11
20 | dist: xenial
21 | sudo: required
22 | env:
23 | global:
24 | - CFLAGS=-coverage
25 | - LDFLAGS=-coverage -lgcov
26 | - PYXMLSEC_TEST_ITERATIONS=50
27 |
28 | addons:
29 | apt:
30 | packages:
31 | - libssl-dev
32 | - libxmlsec1
33 | - libxmlsec1-dev
34 | - libxmlsec1-openssl
35 | - libxslt1-dev
36 | - pkg-config
37 | - lcov
38 | install:
39 | - travis_retry pip install --upgrade pip setuptools wheel
40 | - travis_retry pip install coverage -r requirements-test.txt --upgrade --force-reinstall
41 | - python setup.py bdist_wheel
42 | - pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/
43 | script: coverage run -m pytest -v tests --color=yes
44 | after_success:
45 | - lcov --capture --no-external --directory . --output-file coverage.info
46 | - lcov --list coverage.info
47 | - bash <(curl -s https://codecov.io/bash) -f coverage.info
48 | before_deploy:
49 | - travis_retry pip install Sphinx -r doc/source/requirements.txt
50 | - git apply --verbose --no-index --unsafe-paths --directory=$(python -c "import site; print(site.getsitepackages()[0])") doc/source/sphinx-pr-6916.diff
51 | - sphinx-build -EWanb html doc/source build/sphinx
52 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Ryan Leckey
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is furnished
10 | to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | recursive-include src *
2 | recursive-include tests *
3 | prune */__pycache__
4 | prune .github
5 | prune doc
6 | exclude .appveyor.yml
7 | exclude .editorconfig
8 | exclude .travis.yml
9 | exclude .gitattributes
10 | exclude .gitignore
11 | exclude requirements-test.txt
12 | exclude requirements.txt
13 | exclude xmlsec_extra.py
14 | exclude xmlsec_setupinfo.py
15 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | python-xmlsec
2 | =============
3 |
4 | .. image:: https://img.shields.io/pypi/v/xmlsec.svg?logo=python&logoColor=white
5 | :target: https://pypi.python.org/pypi/xmlsec
6 | .. image:: https://results.pre-commit.ci/badge/github/xmlsec/python-xmlsec/master.svg
7 | :target: https://results.pre-commit.ci/latest/github/xmlsec/python-xmlsec/master
8 | :alt: pre-commit.ci status
9 | .. image:: https://img.shields.io/appveyor/ci/hoefling/xmlsec/master.svg?logo=appveyor&logoColor=white&label=AppVeyor
10 | :target: https://ci.appveyor.com/project/hoefling/xmlsec
11 | .. image:: https://github.com/mehcode/python-xmlsec/actions/workflows/manylinux.yml/badge.svg
12 | :target: https://github.com/mehcode/python-xmlsec/actions/workflows/manylinux.yml
13 | .. image:: https://github.com/mehcode/python-xmlsec/actions/workflows/macosx.yml/badge.svg
14 | :target: https://github.com/mehcode/python-xmlsec/actions/workflows/macosx.yml
15 | .. image:: https://github.com/mehcode/python-xmlsec/actions/workflows/linuxbrew.yml/badge.svg
16 | :target: https://github.com/mehcode/python-xmlsec/actions/workflows/linuxbrew.yml
17 | .. image:: https://github.com/mehcode/python-xmlsec/actions/workflows/opensuse-tumbleweed.yml/badge.svg
18 | :target: https://github.com/mehcode/python-xmlsec/actions/workflows/opensuse-tumbleweed.yml
19 | .. image:: https://codecov.io/gh/xmlsec/python-xmlsec/branch/master/graph/badge.svg
20 | :target: https://codecov.io/gh/xmlsec/python-xmlsec
21 | .. image:: https://img.shields.io/readthedocs/xmlsec/latest?logo=read-the-docs
22 | :target: https://xmlsec.readthedocs.io/en/latest/?badge=latest
23 | :alt: Documentation Status
24 |
25 | Python bindings for the `XML Security Library `_.
26 |
27 | Documentation
28 | *************
29 |
30 | A documentation for ``xmlsec`` can be found at `xmlsec.readthedocs.io `_.
31 |
32 | Usage
33 | *****
34 |
35 | Check the `examples `_ section in the documentation to see various examples of signing and verifying using the library.
36 |
37 | Requirements
38 | ************
39 | - ``libxml2 >= 2.9.1``
40 | - ``libxmlsec1 >= 1.2.33``
41 |
42 | Install
43 | *******
44 |
45 | ``xmlsec`` is available on PyPI:
46 |
47 | .. code-block:: bash
48 |
49 | pip install xmlsec
50 |
51 | Depending on your OS, you may need to install the required native
52 | libraries first:
53 |
54 | Linux (Debian)
55 | ^^^^^^^^^^^^^^
56 |
57 | .. code-block:: bash
58 |
59 | apt-get install pkg-config libxml2-dev libxmlsec1-dev libxmlsec1-openssl
60 |
61 |
62 | Note: There is no required version of LibXML2 for Ubuntu Precise,
63 | so you need to download and install it manually.
64 |
65 | .. code-block:: bash
66 |
67 | wget http://xmlsoft.org/sources/libxml2-2.9.1.tar.gz
68 | tar -xvf libxml2-2.9.1.tar.gz
69 | cd libxml2-2.9.1
70 | ./configure && make && make install
71 |
72 |
73 | Linux (CentOS)
74 | ^^^^^^^^^^^^^^
75 |
76 | .. code-block:: bash
77 |
78 | yum install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel
79 |
80 |
81 | Linux (Fedora)
82 | ^^^^^^^^^^^^^^
83 |
84 | .. code-block:: bash
85 |
86 | dnf install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel
87 |
88 |
89 | Mac
90 | ^^^
91 |
92 | .. code-block:: bash
93 |
94 | brew install libxml2 libxmlsec1 pkg-config
95 |
96 | or
97 |
98 | .. code-block:: bash
99 |
100 | port install libxml2 xmlsec pkgconfig
101 |
102 |
103 | Alpine
104 | ^^^^^^
105 |
106 | .. code-block:: bash
107 |
108 | apk add build-base libressl libffi-dev libressl-dev libxslt-dev libxml2-dev xmlsec-dev xmlsec
109 |
110 |
111 | Troubleshooting
112 | ***************
113 |
114 | Mac
115 | ^^^
116 |
117 | If you get any fatal errors about missing ``.h`` files, update your
118 | ``C_INCLUDE_PATH`` environment variable to include the appropriate
119 | files from the ``libxml2`` and ``libxmlsec1`` libraries.
120 |
121 |
122 | Windows
123 | ^^^^^^^
124 |
125 | Starting with 1.3.7, prebuilt wheels are available for Windows,
126 | so running ``pip install xmlsec`` should suffice. If you want
127 | to build from source:
128 |
129 | #. Configure build environment, see `wiki.python.org `_ for more details.
130 |
131 | #. Install from source dist:
132 |
133 | .. code-block:: bash
134 |
135 | pip install xmlsec --no-binary=xmlsec
136 |
137 |
138 | Building from source
139 | ********************
140 |
141 | #. Clone the ``xmlsec`` source code repository to your local computer.
142 |
143 | .. code-block:: bash
144 |
145 | git clone https://github.com/xmlsec/python-xmlsec.git
146 |
147 | #. Change into the ``python-xmlsec`` root directory.
148 |
149 | .. code-block:: bash
150 |
151 | cd /path/to/xmlsec
152 |
153 |
154 | #. Install the project and all its dependencies using ``pip``.
155 |
156 | .. code-block:: bash
157 |
158 | pip install .
159 |
160 |
161 | Contributing
162 | ************
163 |
164 | Setting up your environment
165 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
166 |
167 | #. Follow steps 1 and 2 of the `manual installation instructions <#building-from-source>`_.
168 |
169 |
170 | #. Initialize a virtual environment to develop in.
171 | This is done so as to ensure every contributor is working with
172 | close-to-identicial versions of packages.
173 |
174 | .. code-block:: bash
175 |
176 | mkvirtualenv xmlsec
177 |
178 | The ``mkvirtualenv`` command is available from ``virtualenvwrapper`` package which can be installed by following `link `_.
179 |
180 | #. Activate the created virtual environment:
181 |
182 | .. code-block:: bash
183 |
184 | workon xmlsec
185 |
186 | #. Install ``xmlsec`` in development mode with testing enabled.
187 | This will download all dependencies required for running the unit tests.
188 |
189 | .. code-block:: bash
190 |
191 | pip install -r requirements-test.txt
192 | pip install -e "."
193 |
194 |
195 | Running the test suite
196 | ^^^^^^^^^^^^^^^^^^^^^^
197 |
198 | #. `Set up your environment <#setting-up-your-environment>`_.
199 |
200 | #. Run the unit tests.
201 |
202 | .. code-block:: bash
203 |
204 | pytest tests
205 |
206 | #. Tests configuration
207 |
208 | Env variable ``PYXMLSEC_TEST_ITERATIONS`` specifies number of
209 | test iterations to detect memory leaks.
210 |
211 | Reporting an issue
212 | ^^^^^^^^^^^^^^^^^^
213 |
214 | Please attach the output of following information:
215 |
216 | * version of ``xmlsec``
217 | * version of ``libxmlsec1``
218 | * version of ``libxml2``
219 | * output from the command
220 |
221 | .. code-block:: bash
222 |
223 | pkg-config --cflags xmlsec1
224 |
225 | License
226 | *******
227 |
228 | Unless otherwise noted, all files contained within this project are licensed under the MIT opensource license.
229 | See the included ``LICENSE`` file or visit `opensource.org `_ for more information.
230 |
--------------------------------------------------------------------------------
/doc/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | SPHINXPROJ = python-xmlsec
8 | SOURCEDIR = source
9 | BUILDDIR = build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/doc/source/api.rst:
--------------------------------------------------------------------------------
1 | API Reference
2 | =============
3 |
4 | .. toctree::
5 | :maxdepth: 1
6 |
7 | modules/xmlsec
8 | modules/constants
9 | modules/template
10 | modules/tree
11 |
12 |
13 | :ref:`contents`
14 |
--------------------------------------------------------------------------------
/doc/source/conf.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import importlib.metadata
4 | import urllib.request
5 |
6 | import lxml
7 | from docutils.nodes import Text, reference
8 | from packaging.version import Version, parse
9 | from sphinx.addnodes import pending_xref
10 | from sphinx.application import Sphinx
11 | from sphinx.environment import BuildEnvironment
12 | from sphinx.errors import ExtensionError
13 |
14 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx']
15 |
16 | intersphinx_mapping = {'python': ('https://docs.python.org/3/', None)}
17 |
18 | templates_path = ['_templates']
19 | source_suffix = '.rst'
20 | master_doc = 'index'
21 |
22 | project = u'python-xmlsec'
23 | copyright = u'2020, Oleg Hoefling ' # noqa: A001
24 | author = u'Bulat Gaifullin '
25 | release = importlib.metadata.version('xmlsec')
26 | parsed: Version = parse(release)
27 | version = '{}.{}'.format(parsed.major, parsed.minor)
28 |
29 | exclude_patterns: list[str] = []
30 | pygments_style = 'sphinx'
31 | todo_include_todos = False
32 |
33 | html_theme = 'furo'
34 | html_static_path: list[str] = []
35 | htmlhelp_basename = 'python-xmlsecdoc'
36 |
37 | latex_elements: dict[str, str] = {}
38 | latex_documents = [
39 | (
40 | master_doc,
41 | 'python-xmlsec.tex',
42 | u'python-xmlsec Documentation',
43 | u'Bulat Gaifullin \\textless{}gaifullinbf@gmail.com\\textgreater{}',
44 | 'manual',
45 | )
46 | ]
47 |
48 | man_pages = [(master_doc, 'python-xmlsec', u'python-xmlsec Documentation', [author], 1)]
49 |
50 | texinfo_documents = [
51 | (
52 | master_doc,
53 | 'python-xmlsec',
54 | u'python-xmlsec Documentation',
55 | author,
56 | 'python-xmlsec',
57 | 'One line description of project.',
58 | 'Miscellaneous',
59 | )
60 | ]
61 |
62 | autodoc_member_order = 'groupwise'
63 | autodoc_docstring_signature = True
64 |
65 |
66 | rst_prolog = '''
67 | .. role:: xml(code)
68 | :language: xml
69 | '''
70 |
71 | # LXML crossref'ing stuff:
72 | # LXML doesn't have an intersphinx docs,
73 | # so we link to lxml.etree._Element explicitly
74 | lxml_element_cls_doc_uri = 'https://lxml.de/api/lxml.etree._Element-class.html'
75 |
76 |
77 | def lxml_element_doc_reference(app: Sphinx, env: BuildEnvironment, node: pending_xref, contnode: Text) -> reference:
78 | """
79 | Handle a missing reference only if it is a ``lxml.etree._Element`` ref.
80 |
81 | We handle only :class:`lxml.etree._Element` and :class:`~lxml.etree._Element` nodes.
82 | """
83 | if (
84 | node.get('reftype', None) == 'class'
85 | and node.get('reftarget', None) == 'lxml.etree._Element'
86 | and contnode.astext() in ('lxml.etree._Element', '_Element')
87 | ):
88 | reftitle = '(in lxml v{})'.format(lxml.__version__) # type: ignore[attr-defined]
89 | newnode = reference('', '', internal=False, refuri=lxml_element_cls_doc_uri, reftitle=reftitle)
90 | newnode.append(contnode)
91 | return newnode
92 |
93 |
94 | def setup(app: Sphinx) -> None:
95 | # first, check whether the doc URL is still valid
96 | if urllib.request.urlopen(lxml_element_cls_doc_uri).getcode() != 200:
97 | raise ExtensionError('URL to `lxml.etree._Element` docs is not accesible.')
98 | app.connect('missing-reference', lxml_element_doc_reference)
99 |
--------------------------------------------------------------------------------
/doc/source/examples.rst:
--------------------------------------------------------------------------------
1 | Examples
2 | ========
3 |
4 | Decrypt
5 | -------
6 |
7 | .. literalinclude:: examples/decrypt.py
8 |
9 | Encrypt
10 | -------
11 |
12 | .. literalinclude:: examples/encrypt.py
13 |
14 |
15 | Sign
16 | ----
17 |
18 | .. literalinclude:: examples/sign.py
19 |
20 | Sign-Binary
21 | -----------
22 |
23 | .. literalinclude:: examples/sign_binary.py
24 |
25 |
26 | Verify
27 | ------
28 |
29 | .. literalinclude:: examples/verify.py
30 |
31 |
32 | Verify-Binary
33 | -------------
34 |
35 | .. literalinclude:: examples/verify_binary.py
36 |
--------------------------------------------------------------------------------
/doc/source/examples/decrypt.py:
--------------------------------------------------------------------------------
1 | from lxml import etree
2 |
3 | import xmlsec
4 |
5 | manager = xmlsec.KeysManager()
6 | key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem)
7 | manager.add_key(key)
8 | enc_ctx = xmlsec.EncryptionContext(manager)
9 | root = etree.parse("enc1-res.xml").getroot()
10 | enc_data = xmlsec.tree.find_child(root, "EncryptedData", xmlsec.constants.EncNs)
11 | decrypted = enc_ctx.decrypt(enc_data)
12 | print(etree.tostring(decrypted))
13 |
--------------------------------------------------------------------------------
/doc/source/examples/enc1-doc.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | Hello, World!
7 |
8 |
--------------------------------------------------------------------------------
/doc/source/examples/enc1-res.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | UrTgE0UxQa8xevs4SyRA0rsibEz/ZFDjCBD+t4pKSdajB/cefYObZzqq2l41Q6R/
10 | tqYLht5hEBh26AHfjmQSJAL+eChXOt/EaOf63zzJedO90HGqIQyzOeOPURAl3Li8
11 | ivPyLVyocJDeVNeh7W+7kYwpFQ6PLuQxWsFFQXVoRAWbXHpZkSzVheR+5RpYJRTb
12 | 1UYXKxu8jg4NqbjucVMDIxUOzsVCDRyk8R8sQrM7D/H/N0y7DAY8oX/WZ45xLwUy
13 | DY/U86tTpTn95NwHD10SLyrL6rpXdbEuoIQHhWLwV9uQxnJA/Pn1KZ+xXK/fePfP
14 | 26PBo/hUrN5pm5U8ycc4iw==
15 |
16 |
17 |
18 |
19 | 2pb5Mxd0f+AW56Cs3MfQ9HJkUVeliSi1hVCNCVHTKeMyC2VL6lPhQ9+L01aSeTSY
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/doc/source/examples/encrypt.py:
--------------------------------------------------------------------------------
1 | from lxml import etree
2 |
3 | import xmlsec
4 |
5 | with open('enc1-doc.xml') as fp:
6 | template = etree.parse(fp).getroot()
7 |
8 | enc_data = xmlsec.template.encrypted_data_create(
9 | template,
10 | xmlsec.constants.TransformAes128Cbc,
11 | type=xmlsec.constants.TypeEncElement,
12 | ns="xenc",
13 | )
14 |
15 | xmlsec.template.encrypted_data_ensure_cipher_value(enc_data)
16 | key_info = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig")
17 | enc_key = xmlsec.template.add_encrypted_key(key_info, xmlsec.constants.TransformRsaOaep)
18 | xmlsec.template.encrypted_data_ensure_cipher_value(enc_key)
19 | data = template.find('./Data')
20 |
21 | # Encryption
22 | manager = xmlsec.KeysManager()
23 | key = xmlsec.Key.from_file('rsacert.pem', xmlsec.constants.KeyDataFormatCertPem, None)
24 | manager.add_key(key)
25 |
26 | enc_ctx = xmlsec.EncryptionContext(manager)
27 | enc_ctx.key = xmlsec.Key.generate(
28 | xmlsec.constants.KeyDataAes, 128, xmlsec.constants.KeyDataTypeSession
29 | )
30 | enc_data = enc_ctx.encrypt_xml(enc_data, data)
31 | enc_method = xmlsec.tree.find_child(
32 | enc_data, xmlsec.constants.NodeEncryptionMethod, xmlsec.constants.EncNs
33 | )
34 | key_info = xmlsec.tree.find_child(
35 | enc_data, xmlsec.constants.NodeKeyInfo, xmlsec.constants.DSigNs
36 | )
37 | enc_method = xmlsec.tree.find_node(
38 | key_info, xmlsec.constants.NodeEncryptionMethod, xmlsec.constants.EncNs
39 | )
40 | cipher_value = xmlsec.tree.find_node(
41 | key_info, xmlsec.constants.NodeCipherValue, xmlsec.constants.EncNs
42 | )
43 | print(etree.tostring(cipher_value))
44 |
--------------------------------------------------------------------------------
/doc/source/examples/rsacert.pem:
--------------------------------------------------------------------------------
1 | Certificate:
2 | Data:
3 | Version: 3 (0x2)
4 | Serial Number: 5 (0x5)
5 | Signature Algorithm: md5WithRSAEncryption
6 | Issuer: C=US, ST=California, L=Sunnyvale, O=XML Security Library (http://www.aleksey.com/xmlsec), OU=Root Certificate, CN=Aleksey Sanin/emailAddress=xmlsec@aleksey.com
7 | Validity
8 | Not Before: Mar 31 04:02:22 2003 GMT
9 | Not After : Mar 28 04:02:22 2013 GMT
10 | Subject: C=US, ST=California, O=XML Security Library (http://www.aleksey.com/xmlsec), OU=Examples RSA Certificate, CN=Aleksey Sanin/emailAddress=xmlsec@aleksey.com
11 | Subject Public Key Info:
12 | Public Key Algorithm: rsaEncryption
13 | RSA Public Key: (2048 bit)
14 | Modulus (2048 bit):
15 | 00:97:b8:fe:b4:3f:83:35:78:16:89:04:ec:2b:61:
16 | 8c:bf:c4:5f:00:81:4a:45:e6:d9:cd:e9:e2:3c:97:
17 | 3b:45:ad:aa:e6:8d:0b:77:71:07:01:4f:7c:f9:7d:
18 | e2:19:aa:dd:91:59:f4:f1:cf:3d:ba:78:46:96:11:
19 | 9c:b6:5b:46:39:73:55:23:aa:f7:9e:00:5c:e5:e9:
20 | 49:ec:3b:9c:3f:84:99:3a:90:ad:df:7e:64:86:c6:
21 | 26:72:ce:31:08:79:7e:13:15:b8:e5:bf:d6:56:02:
22 | 8d:60:21:4c:27:18:64:fb:fb:55:70:f6:33:bd:2f:
23 | 55:70:d5:5e:7e:99:ae:a4:e0:aa:45:47:13:a8:30:
24 | d5:a0:8a:9d:cc:20:ec:e4:8e:51:c9:54:c5:7f:3e:
25 | 66:2d:74:bf:a3:7a:f8:f3:ec:94:57:39:b4:ac:00:
26 | 75:62:61:54:b4:d0:e0:52:86:f8:5e:77:ec:50:43:
27 | 9c:d2:ba:a7:8c:62:5a:bc:b2:fe:f3:cc:62:7e:23:
28 | 60:6b:c7:51:49:37:78:7e:25:15:30:ab:fa:b4:ae:
29 | 25:8f:22:fc:a3:48:7f:f2:0a:8a:6e:e0:fe:8d:f0:
30 | 01:ed:c6:33:cc:6b:a1:fd:a6:80:ef:06:8c:af:f6:
31 | 40:3a:8e:42:14:20:61:12:1f:e3:fc:05:b1:05:d5:
32 | 65:c3
33 | Exponent: 65537 (0x10001)
34 | X509v3 extensions:
35 | X509v3 Basic Constraints:
36 | CA:FALSE
37 | Netscape Comment:
38 | OpenSSL Generated Certificate
39 | X509v3 Subject Key Identifier:
40 | 24:84:2C:F2:D4:59:20:62:8B:2E:5C:86:90:A3:AA:30:BA:27:1A:9C
41 | X509v3 Authority Key Identifier:
42 | keyid:B4:B9:EF:9A:E6:97:0E:68:65:1E:98:CE:FA:55:0D:89:06:DB:4C:7C
43 | DirName:/C=US/ST=California/L=Sunnyvale/O=XML Security Library (http://www.aleksey.com/xmlsec)/OU=Root Certificate/CN=Aleksey Sanin/emailAddress=xmlsec@aleksey.com
44 | serial:00
45 |
46 | Signature Algorithm: md5WithRSAEncryption
47 | b5:3f:9b:32:31:4a:ff:2f:84:3b:a8:9b:11:5c:a6:5c:f0:76:
48 | 52:d9:6e:f4:90:ad:fa:0d:90:c1:98:d5:4a:12:dd:82:6b:37:
49 | e8:d9:2d:62:92:c9:61:37:98:86:8f:a4:49:6a:5e:25:d0:18:
50 | 69:30:0f:98:8f:43:58:89:31:b2:3b:05:e2:ef:c7:a6:71:5f:
51 | f7:fe:73:c5:a7:b2:cd:2e:73:53:71:7d:a8:4c:68:1a:32:1b:
52 | 5e:48:2f:8f:9b:7a:a3:b5:f3:67:e8:b1:a2:89:4e:b2:4d:1b:
53 | 79:9c:ff:f0:0d:19:4f:4e:b1:03:3d:99:f0:44:b7:8a:0b:34:
54 | 9d:83
55 | -----BEGIN CERTIFICATE-----
56 | MIIE3zCCBEigAwIBAgIBBTANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCVVMx
57 | EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
58 | ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
59 | eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
60 | a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMB4X
61 | DTAzMDMzMTA0MDIyMloXDTEzMDMyODA0MDIyMlowgb8xCzAJBgNVBAYTAlVTMRMw
62 | EQYDVQQIEwpDYWxpZm9ybmlhMT0wOwYDVQQKEzRYTUwgU2VjdXJpdHkgTGlicmFy
63 | eSAoaHR0cDovL3d3dy5hbGVrc2V5LmNvbS94bWxzZWMpMSEwHwYDVQQLExhFeGFt
64 | cGxlcyBSU0EgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUFsZWtzZXkgU2FuaW4xITAf
65 | BgkqhkiG9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbTCCASIwDQYJKoZIhvcNAQEB
66 | BQADggEPADCCAQoCggEBAJe4/rQ/gzV4FokE7CthjL/EXwCBSkXm2c3p4jyXO0Wt
67 | quaNC3dxBwFPfPl94hmq3ZFZ9PHPPbp4RpYRnLZbRjlzVSOq954AXOXpSew7nD+E
68 | mTqQrd9+ZIbGJnLOMQh5fhMVuOW/1lYCjWAhTCcYZPv7VXD2M70vVXDVXn6ZrqTg
69 | qkVHE6gw1aCKncwg7OSOUclUxX8+Zi10v6N6+PPslFc5tKwAdWJhVLTQ4FKG+F53
70 | 7FBDnNK6p4xiWryy/vPMYn4jYGvHUUk3eH4lFTCr+rSuJY8i/KNIf/IKim7g/o3w
71 | Ae3GM8xrof2mgO8GjK/2QDqOQhQgYRIf4/wFsQXVZcMCAwEAAaOCAVcwggFTMAkG
72 | A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp
73 | ZmljYXRlMB0GA1UdDgQWBBQkhCzy1FkgYosuXIaQo6owuicanDCB+AYDVR0jBIHw
74 | MIHtgBS0ue+a5pcOaGUemM76VQ2JBttMfKGB0aSBzjCByzELMAkGA1UEBhMCVVMx
75 | EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
76 | ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
77 | eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
78 | a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggEA
79 | MA0GCSqGSIb3DQEBBAUAA4GBALU/mzIxSv8vhDuomxFcplzwdlLZbvSQrfoNkMGY
80 | 1UoS3YJrN+jZLWKSyWE3mIaPpElqXiXQGGkwD5iPQ1iJMbI7BeLvx6ZxX/f+c8Wn
81 | ss0uc1NxfahMaBoyG15IL4+beqO182fosaKJTrJNG3mc//ANGU9OsQM9mfBEt4oL
82 | NJ2D
83 | -----END CERTIFICATE-----
84 |
--------------------------------------------------------------------------------
/doc/source/examples/rsakey.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEowIBAAKCAQEAl7j+tD+DNXgWiQTsK2GMv8RfAIFKRebZzeniPJc7Ra2q5o0L
3 | d3EHAU98+X3iGardkVn08c89unhGlhGctltGOXNVI6r3ngBc5elJ7DucP4SZOpCt
4 | 335khsYmcs4xCHl+ExW45b/WVgKNYCFMJxhk+/tVcPYzvS9VcNVefpmupOCqRUcT
5 | qDDVoIqdzCDs5I5RyVTFfz5mLXS/o3r48+yUVzm0rAB1YmFUtNDgUob4XnfsUEOc
6 | 0rqnjGJavLL+88xifiNga8dRSTd4fiUVMKv6tK4ljyL8o0h/8gqKbuD+jfAB7cYz
7 | zGuh/aaA7waMr/ZAOo5CFCBhEh/j/AWxBdVlwwIDAQABAoIBAQCAvt6DnZF9gdW9
8 | l4vAlBqXb88d4phgELCp5tmviLUnP2NSGEWuqR7Eoeru2z9NgIxblvYfazh6Ty22
9 | kmNk6rcAcTnB9oYAcVZjUj8EUuEXlTFhXPvuNpafNu3RZd59znqJP1mSu+LpQWku
10 | NZMlabHnkTLDlGf7FXtvL9/rlgV4qk3QcDVF793JFszWrtK3mnld3KHQ6cuo9iSm
11 | 0rQKtkDjeHsRell8qTQvfBsgG1q2bv8QWT45/eQrra9mMbGTr3DbnXvoeJmTj1VN
12 | XJV7tBNllxxPahlYMByJaf/Tuva5j6HWUEIfYky5ihr2z1P/fNQ2OSCM6SQHpkiG
13 | EXQDueXBAoGBAMfW7KcmToEQEcTiqfey6C1LOLoemcX0/ROUktPq/5JQJRRrT4t7
14 | XevLX0ed8sLyR5T29XQtdnuV0DJfvcJD+6ZwfOcQ+f6ZzCaNXJP97JtEt5kSWY01
15 | Ei+nphZ0RFvPb04V3qDU9dElU26GR36CRBYJyM2WQPx4v+/YyDSZH9kLAoGBAMJc
16 | ZBU8pRbIia/FFOHUlS3v5P18nVmXyOd0fvRq0ZelaQCebTZ4K9wjnCfw//yzkb2Z
17 | 0vZFNB+xVBKB0Pt6nVvnSNzxdQ8EAXVFwHtXa25FUyP2RERQgTvmajqmgWjZsDYp
18 | 6GHcK3ZhmdmscQHF/Q2Uo4scvBcheahm9IXiNskpAoGAXelEgTBhSAmTMCEMmti6
19 | fz6QQ/bJcNu2apMxhOE0hT+gjT34vaWV9481EWTKho5w0TJVGumaem1mz6VqeXaV
20 | Nhw6tiOmN91ysNNRpEJ6BGWAmjCjYNaF21s/k+HDlhmfRuTEIHSzqDuQP6pewrbY
21 | 5Dpo4SQxGfRsznvjacRj0Q0CgYBN247oBvQnDUxCkhNMZ8kersOvW5T4x9neBge5
22 | R3UQZ12Jtu0O7dK8C7PJODyDcTeHmTAuIQjBTVrdUw1xP+v7XcoNX9hBnJws6zUw
23 | 85MAiFrGxCcSqqEqaqHRPtQGOXXiLKV/ViA++tgTn4VhbXtyTkG5P1iFd45xjFSV
24 | sUm7CQKBgDn92tHxzePly1L1mK584TkVryx4cP9RFHpebnmNduGwwjnRuYipoj8y
25 | pPPAkVbbaA3f9OB2go48rN0Ft9nHdlqgh9BpIKCVtkIb1XN0K3Oa/8BW8W/GAiNG
26 | HJcsrOtIrGVRdlyJG6bDaN8T49DnhOcsqMbf+IkIvfh50VeE9L/e
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/doc/source/examples/rsapub.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN PUBLIC KEY-----
2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl7j+tD+DNXgWiQTsK2GM
3 | v8RfAIFKRebZzeniPJc7Ra2q5o0Ld3EHAU98+X3iGardkVn08c89unhGlhGctltG
4 | OXNVI6r3ngBc5elJ7DucP4SZOpCt335khsYmcs4xCHl+ExW45b/WVgKNYCFMJxhk
5 | +/tVcPYzvS9VcNVefpmupOCqRUcTqDDVoIqdzCDs5I5RyVTFfz5mLXS/o3r48+yU
6 | Vzm0rAB1YmFUtNDgUob4XnfsUEOc0rqnjGJavLL+88xifiNga8dRSTd4fiUVMKv6
7 | tK4ljyL8o0h/8gqKbuD+jfAB7cYzzGuh/aaA7waMr/ZAOo5CFCBhEh/j/AWxBdVl
8 | wwIDAQAB
9 | -----END PUBLIC KEY-----
10 |
--------------------------------------------------------------------------------
/doc/source/examples/sign.py:
--------------------------------------------------------------------------------
1 | from lxml import etree
2 |
3 | import xmlsec
4 |
5 | with open('sign1-tmpl.xml') as fp:
6 | template = etree.parse(fp).getroot()
7 |
8 | signature_node = xmlsec.tree.find_node(template, xmlsec.constants.NodeSignature)
9 | ctx = xmlsec.SignatureContext()
10 | key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem)
11 | ctx.key = key
12 | ctx.sign(signature_node)
13 | print(etree.tostring(template))
14 |
--------------------------------------------------------------------------------
/doc/source/examples/sign1-res.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Hello, World!
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | 9H/rQr2Axe9hYTV2n/tCp+3UIQQ=
19 |
20 |
21 | Mx4psIy9/UY+u8QBJRDrwQWKRaCGz0WOVftyDzAe6WHAFSjMNr7qb2ojq9kdipT8
22 | Oub5q2OQ7mzdSLiiejkrO1VeqM/90yEIGI4En6KEB6ArEzw+iq4N1wm6EptcyxXx
23 | M9StAOOa9ilWYqR9Tfx3SW1urUIuKYgUitxsONiUHBVaW6HeX51bsXoTF++4ZI+D
24 | jiPBjN4HHmr0cbJ6BXk91S27ffZIfp1Qj5nL9onFLUGbR6EFgu2luiRzQbPuM2tP
25 | XxyI7GZ8AfHnRJK28ARvBC9oi+O1ej20S79CIV7gdBxbLbFprozBHAwOEC57YgJc
26 | x+YEjSjcO7SBIR1FiUA7pw==
27 |
28 | rsakey.pem
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/doc/source/examples/sign1-tmpl.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Hello, World!
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/doc/source/examples/sign_binary.py:
--------------------------------------------------------------------------------
1 | import xmlsec
2 |
3 | ctx = xmlsec.SignatureContext()
4 | key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem)
5 | ctx.key = key
6 | data = b'\xa8f4dP\x82\x02\xd3\xf5.\x02\xc1\x03\xef\xc4\x86\xabC\xec\xb7>\x8e\x1f\xa3\xa3\xc5\xb9qc\xc2\x81\xb1-\xa4B\xdf\x03>\xba\xd1'
7 | sign = ctx.sign_binary(data, xmlsec.constants.TransformRsaSha1)
8 | print(sign)
9 |
--------------------------------------------------------------------------------
/doc/source/examples/verify.py:
--------------------------------------------------------------------------------
1 | from lxml import etree
2 |
3 | import xmlsec
4 |
5 | with open('sign1-res.xml') as fp:
6 | template = etree.parse(fp).getroot()
7 |
8 | xmlsec.tree.add_ids(template, ["ID"])
9 | signature_node = xmlsec.tree.find_node(template, xmlsec.constants.NodeSignature)
10 | # Create a digital signature context (no key manager is needed).
11 | ctx = xmlsec.SignatureContext()
12 | key = xmlsec.Key.from_file('rsapub.pem', xmlsec.constants.KeyDataFormatPem)
13 | # Set the key on the context.
14 | ctx.key = key
15 | ctx.verify(signature_node)
16 |
--------------------------------------------------------------------------------
/doc/source/examples/verify_binary.py:
--------------------------------------------------------------------------------
1 | import xmlsec
2 |
3 | ctx = xmlsec.SignatureContext()
4 | key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem)
5 | ctx.key = key
6 |
7 | data = b'\xa8f4dP\x82\x02\xd3\xf5.\x02\xc1\x03\xef\xc4\x86\xabC\xec\xb7>\x8e\x1f\xa3\xa3\xc5\xb9qc\xc2\x81\xb1-\xa4B\xdf\x03>\xba\xd1'
8 | sign = b"h\xcb\xb1\x82\xfa`e\x89x\xe5\xc5ir\xd6\xd1Q\x9a\x0b\xeaU_G\xcc'\xa4c\xa3>\x9b27\xbf^`\xa7p\xfb\x98\xcb\x81\xd2\xb1\x0c'\x9d\xe2\n\xec\xb2<\xcf@\x98=\xe0}O8}fy\xc2\xc4\xe9\xec\x87\xf6\xc1\xde\xfd\x96*o\xab\xae\x12\xc9{\xcc\x0e\x93y\x9a\x16\x80o\x92\xeb\x02^h|\xa0\x9b<\x99_\x97\xcb\xe27\xe9u\xc3\xfa_\xcct/sTb\xa0\t\xd3\x93'\xb4\xa4\x0ez\xcbL\x14D\xdb\xe3\x84\x886\xe9J[\xe7\xce\xc0\xb1\x99\x07\x17{\xc6:\xff\x1dt\xfd\xab^2\xf7\x9e\xa4\xccT\x8e~b\xdb\x9a\x04\x04\xbaM\xfa\xbd\xec)z\xbb\x89\xd7\xb2Q\xac\xaf\x13\xdcD\xcd\n6\x92\xfao\xb9\xd9\x96$\xce\xa6\xcf\xf8\xe4Bb60\xf5\xd2a\xb1o\x8c\x0f\x8bl\x88vh\xb5h\xfa\xfa\xb66\xedQ\x10\xc4\xef\xfa\x81\xf0\xc9.^\x98\x1ePQS\x9e\xafAy\x90\xe4\x95\x03V\xc2\xa0\x18\xa5d\xc2\x15*\xb6\xd7$\xc0\t2\xa1"
9 | ctx.verify_binary(data, xmlsec.constants.TransformRsaSha1, sign)
10 |
--------------------------------------------------------------------------------
/doc/source/index.rst:
--------------------------------------------------------------------------------
1 | .. python-xmlsec documentation master file, created by
2 | sphinx-quickstart on Fri Mar 17 10:30:14 2017.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root ``toctree`` directive.
5 |
6 | Welcome to python-xmlsec's documentation!
7 | =========================================
8 |
9 | Python bindings for the XML Security Library.
10 |
11 | .. _contents:
12 |
13 | Table of contents
14 | =================
15 |
16 | .. toctree::
17 | :maxdepth: 2
18 |
19 | install
20 | api
21 | examples
22 |
23 | Indices and tables
24 | ==================
25 |
26 | * :ref:`genindex`
27 | * :ref:`modindex`
28 | * :ref:`search`
29 |
--------------------------------------------------------------------------------
/doc/source/install.rst:
--------------------------------------------------------------------------------
1 | Installation
2 | ============
3 |
4 | ``xmlsec`` is available on PyPI:
5 |
6 | .. code-block:: bash
7 |
8 | pip install xmlsec
9 |
10 | Depending on your OS, you may need to install the required native
11 | libraries first:
12 |
13 | Linux (Debian)
14 | --------------
15 |
16 | .. code-block:: bash
17 |
18 | apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-openssl
19 |
20 | .. note:: There is no required version of LibXML2 for Ubuntu Precise,
21 | so you need to download and install it manually:
22 |
23 | .. code-block:: bash
24 |
25 | wget http://xmlsoft.org/sources/libxml2-2.9.1.tar.gz
26 | tar -xvf libxml2-2.9.1.tar.gz
27 | cd libxml2-2.9.1
28 | ./configure && make && make install
29 |
30 |
31 | Linux (CentOS)
32 | --------------
33 |
34 | .. code-block:: bash
35 |
36 | yum install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel
37 |
38 |
39 | Linux (Fedora)
40 | --------------
41 |
42 | .. code-block:: bash
43 |
44 | dnf install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel
45 |
46 |
47 | Mac
48 | ---
49 |
50 | .. code-block:: bash
51 |
52 | xcode-select --install
53 | brew upgrade
54 | brew install libxml2 libxmlsec1 pkg-config
55 |
56 |
57 | Alpine
58 | ------
59 |
60 | .. code-block:: bash
61 |
62 | apk add build-base libressl libffi-dev libressl-dev libxslt-dev libxml2-dev xmlsec-dev xmlsec
63 |
64 |
65 | Troubleshooting
66 | ***************
67 |
68 | Mac
69 | ---
70 |
71 | If you get any fatal errors about missing ``.h`` files, update your
72 | ``C_INCLUDE_PATH`` environment variable to include the appropriate
73 | files from the ``libxml2`` and ``libxmlsec1`` libraries.
74 |
75 |
76 | Windows
77 | -------
78 |
79 | Starting with 1.3.7, prebuilt wheels are available for Windows,
80 | so running ``pip install xmlsec`` should suffice. If you want
81 | to build from source:
82 |
83 | #. Configure build environment, see `wiki.python.org `_ for more details.
84 |
85 | #. Install from source dist:
86 |
87 | .. code-block:: bash
88 |
89 | pip install xmlsec --no-binary=xmlsec
90 |
--------------------------------------------------------------------------------
/doc/source/modules/constants.rst:
--------------------------------------------------------------------------------
1 | ``xmlsec.constants``
2 | --------------------
3 |
4 | Various constants used by the library.
5 |
6 | EncryptionType
7 | **************
8 |
9 | .. data:: xmlsec.constants.TypeEncContent
10 | :annotation: = 'http://www.w3.org/2001/04/xmlenc#Content'
11 |
12 | .. data:: xmlsec.constants.TypeEncElement
13 | :annotation: = 'http://www.w3.org/2001/04/xmlenc#Element'
14 |
15 | KeyData
16 | *******
17 |
18 | .. class:: __KeyData
19 |
20 | Base type for all :samp:`KeyData{XXX}` constants.
21 |
22 | .. data:: xmlsec.constants.KeyDataName
23 |
24 | The :xml:`` processing class.
25 |
26 | .. data:: xmlsec.constants.KeyDataValue
27 |
28 | The :xml:`` processing class.
29 |
30 | .. data:: xmlsec.constants.KeyDataRetrievalMethod
31 |
32 | The :xml:`` processing class.
33 |
34 | .. data:: xmlsec.constants.KeyDataEncryptedKey
35 |
36 | The :xml:`` processing class.
37 |
38 | .. data:: xmlsec.constants.KeyDataAes
39 |
40 | The AES key klass.
41 |
42 | .. data:: xmlsec.constants.KeyDataDes
43 |
44 | The DES key klass.
45 |
46 | .. data:: xmlsec.constants.KeyDataDsa
47 |
48 | The DSA key klass.
49 |
50 | .. data:: xmlsec.constants.KeyDataEcdsa
51 |
52 | (Deprecated. The EC key klass) The ECDSA key klass.
53 |
54 | .. data:: xmlsec.constants.KeyDataEc
55 |
56 | The EC key klass.
57 |
58 | .. data:: xmlsec.constants.KeyDataHmac
59 |
60 | The DHMAC key klass.
61 |
62 | .. data:: xmlsec.constants.KeyDataRsa
63 |
64 | The RSA key klass.
65 |
66 | .. data:: xmlsec.constants.KeyDataX509
67 |
68 | The X509 data klass.
69 |
70 | .. data:: xmlsec.constants.KeyDataRawX509Cert
71 |
72 | The raw X509 certificate klass.
73 |
74 | KeyDataFormat
75 | *************
76 |
77 | .. data:: xmlsec.constants.KeyDataFormatUnknown
78 |
79 | the key data format is unknown.
80 |
81 | .. data:: xmlsec.constants.KeyDataFormatBinary
82 |
83 | the binary key data.
84 |
85 | .. data:: xmlsec.constants.KeyDataFormatPem
86 |
87 | the PEM key data (cert or public/private key).
88 |
89 | .. data:: xmlsec.constants.KeyDataFormatDer
90 |
91 | the DER key data (cert or public/private key).
92 |
93 | .. data:: xmlsec.constants.KeyDataFormatPkcs8Pem
94 |
95 | the PKCS8 PEM private key.
96 |
97 | .. data:: xmlsec.constants.KeyDataFormatPkcs8Der
98 |
99 | the PKCS8 DER private key.
100 |
101 | .. data:: xmlsec.constants.KeyDataFormatPkcs12
102 |
103 | the PKCS12 format (bag of keys and certs)
104 |
105 | .. data:: xmlsec.constants.KeyDataFormatCertPem
106 |
107 | the PEM cert.
108 |
109 | .. data:: xmlsec.constants.KeyDataFormatCertDer
110 |
111 | the DER cert.
112 |
113 | KeyDataType
114 | ***********
115 |
116 | .. data:: xmlsec.constants.KeyDataTypeUnknown
117 |
118 | The key data type is unknown
119 |
120 | .. data:: xmlsec.constants.KeyDataTypeNone
121 |
122 | The key data type is unknown
123 |
124 | .. data:: xmlsec.constants.KeyDataTypePublic
125 |
126 | The key data contain a public key.
127 |
128 | .. data:: xmlsec.constants.KeyDataTypePrivate
129 |
130 | The key data contain a private key.
131 |
132 | .. data:: xmlsec.constants.KeyDataTypeSymmetric
133 |
134 | The key data contain a symmetric key.
135 |
136 | .. data:: xmlsec.constants.KeyDataTypeSession
137 |
138 | The key data contain session key (one time key, not stored in keys manager).
139 |
140 | .. data:: xmlsec.constants.KeyDataTypePermanent
141 |
142 | The key data contain permanent key (stored in keys manager).
143 |
144 | .. data:: xmlsec.constants.KeyDataTypeTrusted
145 |
146 | The key data is trusted.
147 |
148 | .. data:: xmlsec.constants.KeyDataTypeAny
149 |
150 | The key data is trusted.
151 |
152 | Namespaces
153 | **********
154 |
155 | .. data:: xmlsec.constants.Ns
156 | :annotation: = 'http://www.aleksey.com/xmlsec/2002'
157 |
158 | .. data:: xmlsec.constants.DSigNs
159 | :annotation: = 'http://www.w3.org/2000/09/xmldsig#'
160 |
161 | .. data:: xmlsec.constants.EncNs
162 | :annotation: = 'http://www.w3.org/2001/04/xmlenc#'
163 |
164 | .. data:: xmlsec.constants.XPathNs
165 | :annotation: = 'http://www.w3.org/TR/1999/REC-xpath-19991116'
166 |
167 | .. data:: xmlsec.constants.XPath2Ns
168 | :annotation: = 'http://www.w3.org/2002/06/xmldsig-filter2'
169 |
170 | .. data:: xmlsec.constants.XPointerNs
171 | :annotation: = 'http://www.w3.org/2001/04/xmldsig-more/xptr'
172 |
173 | .. data:: xmlsec.constants.NsExcC14N
174 | :annotation: = 'http://www.w3.org/2001/10/xml-exc-c14n#'
175 |
176 | .. data:: xmlsec.constants.NsExcC14NWithComments
177 | :annotation: = 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments'
178 |
179 | Nodes
180 | *****
181 |
182 | .. data:: xmlsec.constants.NodeSignature
183 | :annotation: = 'Signature'
184 |
185 | .. data:: xmlsec.constants.NodeSignedInfo
186 | :annotation: = 'SignedInfo'
187 |
188 | .. data:: xmlsec.constants.NodeCanonicalizationMethod
189 | :annotation: = 'CanonicalizationMethod'
190 |
191 | .. data:: xmlsec.constants.NodeSignatureMethod
192 | :annotation: = 'SignatureMethod'
193 |
194 | .. data:: xmlsec.constants.NodeSignatureValue
195 | :annotation: = 'SignatureValue'
196 |
197 | .. data:: xmlsec.constants.NodeSignatureProperties
198 | :annotation: = 'SignatureProperties'
199 |
200 | .. data:: xmlsec.constants.NodeDigestMethod
201 | :annotation: = 'DigestMethod'
202 |
203 | .. data:: xmlsec.constants.NodeDigestValue
204 | :annotation: = 'DigestValue'
205 |
206 | .. data:: xmlsec.constants.NodeObject
207 | :annotation: = 'Object'
208 |
209 | .. data:: xmlsec.constants.NodeManifest
210 | :annotation: = 'Manifest'
211 |
212 | .. data:: xmlsec.constants.NodeEncryptedData
213 | :annotation: = 'EncryptedData'
214 |
215 | .. data:: xmlsec.constants.NodeEncryptedKey
216 | :annotation: = 'EncryptedKey'
217 |
218 | .. data:: xmlsec.constants.NodeEncryptionMethod
219 | :annotation: = 'EncryptionMethod'
220 |
221 | .. data:: xmlsec.constants.NodeEncryptionProperties
222 | :annotation: = 'EncryptionProperties'
223 |
224 | .. data:: xmlsec.constants.NodeEncryptionProperty
225 | :annotation: = 'EncryptionProperty'
226 |
227 | .. data:: xmlsec.constants.NodeCipherData
228 | :annotation: = 'CipherData'
229 |
230 | .. data:: xmlsec.constants.NodeCipherValue
231 | :annotation: = 'CipherValue'
232 |
233 | .. data:: xmlsec.constants.NodeCipherReference
234 | :annotation: = 'CipherReference'
235 |
236 | .. data:: xmlsec.constants.NodeReference
237 | :annotation: = 'Reference'
238 |
239 | .. data:: xmlsec.constants.NodeReferenceList
240 | :annotation: = 'ReferenceList'
241 |
242 | .. data:: xmlsec.constants.NodeDataReference
243 | :annotation: = 'DataReference'
244 |
245 | .. data:: xmlsec.constants.NodeKeyReference
246 | :annotation: = 'KeyReference'
247 |
248 | .. data:: xmlsec.constants.NodeKeyInfo
249 | :annotation: = 'KeyInfo'
250 |
251 | .. data:: xmlsec.constants.NodeKeyName
252 | :annotation: = 'KeyName'
253 |
254 | .. data:: xmlsec.constants.NodeKeyValue
255 | :annotation: = 'KeyValue'
256 |
257 | .. data:: xmlsec.constants.NodeX509Data
258 | :annotation: = 'X509Data'
259 |
260 | Transforms
261 | **********
262 |
263 | .. class:: __Transform
264 |
265 | Base type for all :samp:`Transform{XXX}` constants.
266 |
267 | .. data:: xmlsec.constants.TransformUsageUnknown
268 |
269 | Transforms usage is unknown or undefined.
270 |
271 | .. data:: xmlsec.constants.TransformUsageDSigTransform
272 |
273 | Transform could be used in :xml:``.
274 |
275 | .. data:: xmlsec.constants.TransformUsageC14NMethod
276 |
277 | Transform could be used in :xml:``.
278 |
279 | .. data:: xmlsec.constants.TransformUsageDigestMethod
280 |
281 | Transform could be used in :xml:``.
282 |
283 | .. data:: xmlsec.constants.TransformUsageSignatureMethod
284 |
285 | Transform could be used in :xml:``.
286 |
287 | .. data:: xmlsec.constants.TransformUsageEncryptionMethod
288 |
289 | Transform could be used in :xml:``.
290 |
291 | .. data:: xmlsec.constants.TransformUsageAny
292 |
293 | Transform could be used for operation.
294 |
295 | .. data:: xmlsec.constants.TransformInclC14N
296 |
297 | The regular (inclusive) C14N without comments transform klass.
298 |
299 | .. data:: xmlsec.constants.TransformInclC14NWithComments
300 |
301 | The regular (inclusive) C14N with comments transform klass.
302 |
303 | .. data:: xmlsec.constants.TransformInclC14N11
304 |
305 | The regular (inclusive) C14N 1.1 without comments transform klass.
306 |
307 | .. data:: xmlsec.constants.TransformInclC14N11WithComments
308 |
309 | The regular (inclusive) C14N 1.1 with comments transform klass.
310 |
311 | .. data:: xmlsec.constants.TransformExclC14N
312 |
313 | The exclusive C14N without comments transform klass.
314 |
315 | .. data:: xmlsec.constants.TransformExclC14NWithComments
316 |
317 | The exclusive C14N with comments transform klass.
318 |
319 | .. data:: xmlsec.constants.TransformEnveloped
320 |
321 | The "enveloped" transform klass.
322 |
323 | .. data:: xmlsec.constants.TransformXPath
324 |
325 | The XPath transform klass.
326 |
327 | .. data:: xmlsec.constants.TransformXPath2
328 |
329 | The XPath2 transform klass.
330 |
331 | .. data:: xmlsec.constants.TransformXPointer
332 |
333 | The XPointer transform klass.
334 |
335 | .. data:: xmlsec.constants.TransformXslt
336 |
337 | The XSLT transform klass.
338 |
339 | .. data:: xmlsec.constants.TransformRemoveXmlTagsC14N
340 |
341 | The "remove all xml tags" transform klass (used before base64 transforms).
342 |
343 | .. data:: xmlsec.constants.TransformVisa3DHack
344 |
345 | Selects node subtree by given node id string. The only reason why we need this is Visa3D protocol. It doesn't follow XML/XPointer/XMLDSig specs and allows invalid XPointer expressions in the URI attribute. Since we couldn't evaluate such expressions thru XPath/XPointer engine, we need to have this hack here.
346 |
347 | .. data:: xmlsec.constants.TransformAes128Cbc
348 |
349 | The AES128 CBC cipher transform klass.
350 |
351 | .. data:: xmlsec.constants.TransformAes192Cbc
352 |
353 | The AES192 CBC cipher transform klass.
354 |
355 | .. data:: xmlsec.constants.TransformAes256Cbc
356 |
357 | The AES256 CBC cipher transform klass.
358 |
359 | .. data:: xmlsec.constants.TransformKWAes128
360 |
361 | The AES 128 key wrap transform klass.
362 |
363 | .. data:: xmlsec.constants.TransformKWAes192
364 |
365 | The AES 192 key wrap transform klass.
366 |
367 | .. data:: xmlsec.constants.TransformKWAes256
368 |
369 | The AES 256 key wrap transform klass.
370 |
371 | .. data:: xmlsec.constants.TransformDes3Cbc
372 |
373 | The DES3 CBC cipher transform klass.
374 |
375 | .. data:: xmlsec.constants.TransformKWDes3
376 |
377 | The DES3 key wrap transform klass.
378 |
379 | .. data:: xmlsec.constants.TransformDsaSha1
380 |
381 | The DSA-SHA1 signature transform klass.
382 |
383 | .. data:: xmlsec.constants.TransformEcdsaSha1
384 |
385 | The ECDSA-SHA1 signature transform klass.
386 |
387 | .. data:: xmlsec.constants.TransformEcdsaSha224
388 |
389 | The ECDSA-SHA224 signature transform klass.
390 |
391 | .. data:: xmlsec.constants.TransformEcdsaSha256
392 |
393 | The ECDSA-SHA256 signature transform klass.
394 |
395 | .. data:: xmlsec.constants.TransformEcdsaSha384
396 |
397 | The ECDS-SHA384 signature transform klass.
398 |
399 | .. data:: xmlsec.constants.TransformEcdsaSha512
400 |
401 | The ECDSA-SHA512 signature transform klass.
402 |
403 | .. data:: xmlsec.constants.TransformHmacMd5
404 |
405 | The HMAC with MD5 signature transform klass.
406 |
407 | .. data:: xmlsec.constants.TransformHmacRipemd160
408 |
409 | The HMAC with RipeMD160 signature transform klass.
410 |
411 | .. data:: xmlsec.constants.TransformHmacSha1
412 |
413 | The HMAC with SHA1 signature transform klass.
414 |
415 | .. data:: xmlsec.constants.TransformHmacSha224
416 |
417 | The HMAC with SHA224 signature transform klass.
418 |
419 | .. data:: xmlsec.constants.TransformHmacSha256
420 |
421 | The HMAC with SHA256 signature transform klass.
422 |
423 | .. data:: xmlsec.constants.TransformHmacSha384
424 |
425 | The HMAC with SHA384 signature transform klass.
426 |
427 | .. data:: xmlsec.constants.TransformHmacSha512
428 |
429 | The HMAC with SHA512 signature transform klass.
430 |
431 | .. data:: xmlsec.constants.TransformRsaMd5
432 |
433 | The RSA-MD5 signature transform klass.
434 |
435 | .. data:: xmlsec.constants.TransformRsaRipemd160
436 |
437 | The RSA-RIPEMD160 signature transform klass.
438 |
439 | .. data:: xmlsec.constants.TransformRsaSha1
440 |
441 | The RSA-SHA1 signature transform klass.
442 |
443 | .. data:: xmlsec.constants.TransformRsaSha224
444 |
445 | The RSA-SHA224 signature transform klass.
446 |
447 | .. data:: xmlsec.constants.TransformRsaSha256
448 |
449 | The RSA-SHA256 signature transform klass.
450 |
451 | .. data:: xmlsec.constants.TransformRsaSha384
452 |
453 | The RSA-SHA384 signature transform klass.
454 |
455 | .. data:: xmlsec.constants.TransformRsaSha512
456 |
457 | The RSA-SHA512 signature transform klass.
458 |
459 | .. data:: xmlsec.constants.TransformRsaPkcs1
460 |
461 | The RSA PKCS1 key transport transform klass.
462 |
463 | .. data:: xmlsec.constants.TransformRsaOaep
464 |
465 | The RSA OAEP key transport transform klass.
466 |
467 | .. data:: xmlsec.constants.TransformMd5
468 |
469 | The MD5 digest transform klass.
470 |
471 | .. data:: xmlsec.constants.TransformRipemd160
472 |
473 | The RIPEMD160 digest transform klass.
474 |
475 | .. data:: xmlsec.constants.TransformSha1
476 |
477 | The SHA1 digest transform klass.
478 |
479 | .. data:: xmlsec.constants.TransformSha224
480 |
481 | The SHA224 digest transform klass.
482 |
483 | .. data:: xmlsec.constants.TransformSha256
484 |
485 | The SHA256 digest transform klass.
486 |
487 | .. data:: xmlsec.constants.TransformSha384
488 |
489 | The SHA384 digest transform klass.
490 |
491 | .. data:: xmlsec.constants.TransformSha512
492 |
493 | The SHA512 digest transform klass.
494 |
495 | :ref:`contents`
496 |
--------------------------------------------------------------------------------
/doc/source/modules/template.rst:
--------------------------------------------------------------------------------
1 | ``xmlsec.template``
2 | -------------------
3 |
4 | .. automodule:: xmlsec.template
5 | :members:
6 | :undoc-members:
7 |
8 |
9 | :ref:`contents`
10 |
--------------------------------------------------------------------------------
/doc/source/modules/tree.rst:
--------------------------------------------------------------------------------
1 | ``xmlsec.tree``
2 | ---------------
3 |
4 | .. automodule:: xmlsec.tree
5 | :members:
6 | :undoc-members:
7 |
8 |
9 | :ref:`contents`
10 |
--------------------------------------------------------------------------------
/doc/source/modules/xmlsec.rst:
--------------------------------------------------------------------------------
1 | ``xmlsec``
2 | ----------
3 |
4 | .. automodule:: xmlsec
5 | :members:
6 | :undoc-members:
7 |
8 |
9 | :ref:`contents`
10 |
--------------------------------------------------------------------------------
/doc/source/requirements.txt:
--------------------------------------------------------------------------------
1 | lxml>=3.8
2 | importlib_metadata;python_version < '3.8'
3 | packaging
4 | Sphinx>=3
5 | furo>=2021.4.11b34
6 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.mypy]
2 | files = ['src']
3 | ignore_missing_imports = false
4 | warn_unused_configs = true
5 | disallow_subclassing_any = true
6 | disallow_any_generics = true
7 | disallow_untyped_calls = true
8 | disallow_untyped_defs = true
9 | disallow_incomplete_defs = true
10 | check_untyped_defs = true
11 | disallow_untyped_decorators = true
12 | disallow_any_unimported = true
13 | strict_optional = true
14 | no_implicit_optional = true
15 | warn_redundant_casts = true
16 | warn_unused_ignores = true
17 | warn_return_any = true
18 | warn_no_return = true
19 | no_implicit_reexport = true
20 | show_error_codes = true
21 |
22 | [tool.black]
23 | line_length = 130
24 | skip-string-normalization = true
25 | target_version = ['py39']
26 | include = '\.pyi?$'
27 | exclude = '''
28 |
29 | (
30 | /(
31 | \.eggs # exclude a few common directories in the
32 | | \.git # root of the project
33 | | \.mypy_cache
34 | | \.tox
35 | | build
36 | | dist
37 | )/
38 | )
39 | '''
40 |
41 | [tool.isort]
42 | profile = 'black'
43 | known_first_party = ['xmlsec']
44 | known_third_party = ['lxml', 'pytest', '_pytest', 'hypothesis']
45 |
46 | [build-system]
47 | requires = ['setuptools>=42', 'wheel', 'setuptools_scm[toml]>=3.4', "pkgconfig>=1.5.1", "lxml>=3.8, !=4.7.0"]
48 |
49 | [tool.cibuildwheel]
50 | build-verbosity = 1
51 | build-frontend = "build"
52 | skip = [
53 | "pp*",
54 | "*-musllinux_i686",
55 | # LXML doesn't publish wheels for these platforms, which makes it
56 | # difficult for us to build wheels, so we exclude them.
57 | "cp36-manylinux_aarch64",
58 | "cp37-manylinux_aarch64",
59 | "cp36-musllinux_aarch64",
60 | "cp37-musllinux_aarch64",
61 | "cp36-macosx*",
62 | "cp37-macosx*",
63 | "cp38-macosx*",
64 | ]
65 | test-command = "pytest -v --color=yes {package}/tests"
66 | before-test = "pip install -r requirements-test.txt"
67 | test-skip = "*-macosx_arm64"
68 |
69 | [tool.cibuildwheel.environment]
70 | PYXMLSEC_STATIC_DEPS = "true"
71 |
72 | [tool.cibuildwheel.linux]
73 | archs = ["x86_64", "aarch64", "i686"]
74 | environment-pass = [
75 | "PYXMLSEC_LIBXML2_VERSION",
76 | "PYXMLSEC_LIBXSLT_VERSION",
77 | "PYXMLSEC_STATIC_DEPS",
78 | "GH_TOKEN"
79 | ]
80 |
81 | [tool.cibuildwheel.macos]
82 | archs = ["x86_64", "arm64"]
83 | before-all = "brew install perl"
84 |
85 | [tool.cibuildwheel.windows]
86 | archs = ["AMD64", "x86"]
87 |
88 | [[tool.cibuildwheel.overrides]]
89 | select = "*-manylinux*"
90 | before-all = "yum install -y perl-core"
91 |
--------------------------------------------------------------------------------
/requirements-test.txt:
--------------------------------------------------------------------------------
1 | -r requirements.txt
2 | pytest>=4.6.9
3 | lxml-stubs
4 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | lxml >= 3.8.0, !=4.7.0 --no-binary=lxml
2 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | description_file = README.rst
3 |
4 | [bdist_rpm]
5 | release = 1
6 | build_requires = pkg-config xmlsec1-devel libxml2-devel xmlsec1-openssl-devel
7 | group = Development/Libraries
8 | requires = xmlsec1 xmlsec1-openssl
9 |
10 | [build_sphinx]
11 | source-dir = doc/source
12 | build-dir = doc/build
13 | all_files = 1
14 |
15 | [upload_docs]
16 | upload_dir = doc/build/html
17 |
18 | [flake8]
19 | per-file-ignores =
20 | *.pyi: E301, E302, E305, E501, E701, F401, F822
21 | doc/source/conf.py: D1
22 | doc/source/examples/*.py: D1, E501
23 | tests/*.py: D1
24 | exclude = .venv*,.git,*_pb2.pyi,build,dist,libs,.eggs,.direnv*
25 | max-line-length = 130
26 |
--------------------------------------------------------------------------------
/src/common.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 Ryan Leckey
2 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
8 | // SOFTWARE.
9 |
10 | #ifndef __PYXMLSEC_COMMON_H__
11 | #define __PYXMLSEC_COMMON_H__
12 |
13 | #include "debug.h"
14 |
15 | #ifndef MODULE_NAME
16 | #define MODULE_NAME xmlsec
17 | #endif
18 |
19 | #define JOIN(X,Y) DO_JOIN1(X,Y)
20 | #define DO_JOIN1(X,Y) DO_JOIN2(X,Y)
21 | #define DO_JOIN2(X,Y) X##Y
22 |
23 | #define DO_STRINGIFY(x) #x
24 | #define STRINGIFY(x) DO_STRINGIFY(x)
25 |
26 | #endif //__PYXMLSEC_COMMON_H__
27 |
--------------------------------------------------------------------------------
/src/constants.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 Ryan Leckey
2 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
8 | // SOFTWARE.
9 |
10 | #ifndef __PYXMLSEC_CONSTANTS_H__
11 | #define __PYXMLSEC_CONSTANTS_H__
12 |
13 | #include "platform.h"
14 |
15 | #include
16 | #include
17 |
18 | typedef struct {
19 | PyObject_HEAD
20 | xmlSecTransformId id;
21 | } PyXmlSec_Transform;
22 |
23 | typedef struct {
24 | PyObject_HEAD
25 | xmlSecKeyDataId id;
26 | } PyXmlSec_KeyData;
27 |
28 | extern PyTypeObject* PyXmlSec_TransformType;
29 | extern PyTypeObject* PyXmlSec_KeyDataType;
30 |
31 | #endif //__PYXMLSEC_CONSTANTS_H__
32 |
--------------------------------------------------------------------------------
/src/debug.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 Ryan Leckey
2 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
8 | // SOFTWARE.
9 |
10 | #ifndef __PYXMLSEC_DEBUG_H__
11 | #define __PYXMLSEC_DEBUG_H__
12 |
13 | #ifdef PYXMLSEC_ENABLE_DEBUG
14 |
15 | #include
16 | #define PYXMLSEC_DEBUG(fmt) fprintf(stderr, "[%s:%d %s] " fmt "\n", __FILE__, __LINE__, __FUNCTION__)
17 | #define PYXMLSEC_DEBUGF(fmt, ...) fprintf(stderr, "[%s:%d %s] " fmt "\n", __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
18 | #define PYXMLSEC_DUMP(method, obj) method(obj, stderr)
19 | #else
20 | #define PYXMLSEC_DEBUG(...)
21 | #define PYXMLSEC_DEBUGF(...)
22 | #define PYXMLSEC_DUMP(method, obj)
23 | #endif // PYXMLSEC_ENABLE_DEBUG
24 |
25 | #endif // __PYXMLSEC_DEBUG_H__
26 |
--------------------------------------------------------------------------------
/src/exception.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 Ryan Leckey
2 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
8 | // SOFTWARE.
9 |
10 | #include "common.h"
11 | #include "exception.h"
12 | #include "utils.h"
13 |
14 | #include
15 | #include
16 |
17 | #include
18 |
19 | #include
20 |
21 | // default error class
22 | PyObject* PyXmlSec_Error;
23 | PyObject* PyXmlSec_InternalError;
24 | PyObject* PyXmlSec_VerificationError;
25 |
26 | #if PY_MINOR_VERSION >= 7
27 | static Py_tss_t PyXmlSec_LastErrorKey;
28 | #else
29 | static int PyXmlSec_LastErrorKey = 0;
30 | #endif
31 |
32 | static int PyXmlSec_PrintErrorMessage = 0;
33 |
34 | typedef struct {
35 | const xmlChar* file;
36 | const xmlChar* func;
37 | const xmlChar* object;
38 | const xmlChar* subject;
39 | const xmlChar* msg;
40 | int line;
41 | int reason;
42 | } PyXmlSec_ErrorHolder;
43 |
44 | PyXmlSec_ErrorHolder* PyXmlSec_ErrorHolderCreate(const char* file, int line, const char* func, const char* object, const char* subject, int reason, const char* msg) {
45 | PyXmlSec_ErrorHolder* h = (PyXmlSec_ErrorHolder*)xmlMalloc(sizeof(PyXmlSec_ErrorHolder));
46 |
47 | // file and func is __FILE__ and __FUNCTION__ macro, so it can be stored as is.
48 | h->file = XSTR(file);
49 | h->line = line;
50 | h->func = XSTR(func);
51 | h->reason = reason;
52 | // there is no guarantee that object and subject will not be deallocate after exit from function,
53 | // so make a copy
54 | // xmlCharStrdup returns NULL if arg is NULL
55 | h->object = xmlCharStrdup(object);
56 | h->subject = xmlCharStrdup(subject);
57 | h->msg = xmlCharStrdup(msg);
58 |
59 | PYXMLSEC_DEBUGF("new error %p", h);
60 | return h;
61 | }
62 |
63 | void PyXmlSec_ErrorHolderFree(PyXmlSec_ErrorHolder* h) {
64 | if (h != NULL) {
65 | PYXMLSEC_DEBUGF("free error %p", h);
66 | xmlFree((void*)(h->object));
67 | xmlFree((void*)(h->subject));
68 | xmlFree((void*)(h->msg));
69 | xmlFree((void*)(h));
70 | }
71 | }
72 |
73 | // saves new error in TLS and returns previous
74 | static PyXmlSec_ErrorHolder* PyXmlSec_ExchangeLastError(PyXmlSec_ErrorHolder* e) {
75 | PyXmlSec_ErrorHolder* v;
76 | int r;
77 |
78 | #if PY_MINOR_VERSION >= 7
79 | if (PyThread_tss_is_created(&PyXmlSec_LastErrorKey) == 0) {
80 | #else
81 | if (PyXmlSec_LastErrorKey == 0) {
82 | #endif
83 | PYXMLSEC_DEBUG("WARNING: There is no error key.");
84 | PyXmlSec_ErrorHolderFree(e);
85 | return NULL;
86 | }
87 |
88 | // get_key_value and set_key_value are gil free
89 | #if PY_MINOR_VERSION >= 7
90 | v = (PyXmlSec_ErrorHolder*)PyThread_tss_get(&PyXmlSec_LastErrorKey);
91 | //PyThread_tss_delete(&PyXmlSec_LastErrorKey);
92 | r = PyThread_tss_set(&PyXmlSec_LastErrorKey, (void*)e);
93 | #else
94 | v = (PyXmlSec_ErrorHolder*)PyThread_get_key_value(PyXmlSec_LastErrorKey);
95 | PyThread_delete_key_value(PyXmlSec_LastErrorKey);
96 | r = PyThread_set_key_value(PyXmlSec_LastErrorKey, (void*)e);
97 | #endif
98 | PYXMLSEC_DEBUGF("set_key_value returns %d", r);
99 | return v;
100 | }
101 |
102 | // xmlsec library error callback
103 | static void PyXmlSec_ErrorCallback(const char* file, int line, const char* func, const char* object, const char* subject, int reason, const char* msg) {
104 | // TODO do not allocate error object each time.
105 | PyXmlSec_ErrorHolderFree(PyXmlSec_ExchangeLastError(PyXmlSec_ErrorHolderCreate(file, line, func, object, subject, reason, msg)));
106 |
107 | if (PyXmlSec_PrintErrorMessage) {
108 | const char* error_msg = NULL;
109 | xmlSecSize i;
110 | for (i = 0; (i < XMLSEC_ERRORS_MAX_NUMBER) && (xmlSecErrorsGetMsg(i) != NULL); ++i) {
111 | if(xmlSecErrorsGetCode(i) == reason) {
112 | error_msg = xmlSecErrorsGetMsg(i);
113 | break;
114 | }
115 | }
116 |
117 | fprintf(stderr,
118 | "func=%s:file=%s:line=%d:obj=%s:subj=%s:error=%d:%s:%s\n",
119 | (func != NULL) ? func : "unknown",
120 | (file != NULL) ? file : "unknown",
121 | line,
122 | (object != NULL) ? object : "unknown",
123 | (subject != NULL) ? subject : "unknown",
124 | reason,
125 | (error_msg != NULL) ? error_msg : "",
126 | (msg != NULL) ? msg : "");
127 | }
128 | }
129 |
130 | // pops the last error which was occurred in current thread
131 | // the gil should be acquired
132 | static PyObject* PyXmlSec_GetLastError(PyObject* type, const char* msg) {
133 | PyXmlSec_ErrorHolder* h = PyXmlSec_ExchangeLastError(NULL);
134 | PyObject* exc;
135 |
136 | if (h == NULL) {
137 | return NULL;
138 | }
139 |
140 | exc = PyObject_CallFunction(type, "is", h->reason, msg);
141 | if (exc == NULL) goto ON_FAIL;
142 |
143 | PyXmlSec_SetLongAttr(exc, "code", h->reason);
144 | PyXmlSec_SetStringAttr(exc, "message", msg);
145 | PyXmlSec_SetStringAttr(exc, "details", (const char*)xmlSecErrorsSafeString(h->msg));
146 | PyXmlSec_SetStringAttr(exc, "file", (const char*)xmlSecErrorsSafeString(h->file));
147 | PyXmlSec_SetLongAttr(exc, "line", h->line);
148 | PyXmlSec_SetStringAttr(exc, "func", (const char*)xmlSecErrorsSafeString(h->func));
149 | PyXmlSec_SetStringAttr(exc, "object", (const char*)xmlSecErrorsSafeString(h->object));
150 | PyXmlSec_SetStringAttr(exc, "subject", (const char*)xmlSecErrorsSafeString(h->subject));
151 |
152 | ON_FAIL:
153 | PyXmlSec_ErrorHolderFree(h);
154 | return exc;
155 | }
156 |
157 | void PyXmlSec_SetLastError2(PyObject* type, const char* msg) {
158 | PyObject* last = PyXmlSec_GetLastError(type, msg);
159 | if (last == NULL) {
160 | PYXMLSEC_DEBUG("WARNING: no xmlsec error");
161 | last = PyObject_CallFunction(PyXmlSec_InternalError, "is", (int)-1, msg);
162 | if (last == NULL) {
163 | return;
164 | }
165 | }
166 | PyErr_SetObject(type, last);
167 | Py_DECREF(last);
168 | }
169 |
170 | void PyXmlSec_SetLastError(const char* msg) {
171 | PyXmlSec_SetLastError2(PyXmlSec_Error, msg);
172 | }
173 |
174 | void PyXmlSec_ClearError(void) {
175 | PyXmlSec_ErrorHolderFree(PyXmlSec_ExchangeLastError(NULL));
176 | }
177 |
178 | void PyXmlSecEnableDebugTrace(int v) {
179 | PyXmlSec_PrintErrorMessage = v;
180 | }
181 |
182 | void PyXmlSec_InstallErrorCallback() {
183 | #if PY_MINOR_VERSION >= 7
184 | if (PyThread_tss_is_created(&PyXmlSec_LastErrorKey) != 0) {
185 | #else
186 | if (PyXmlSec_LastErrorKey != 0) {
187 | #endif
188 | xmlSecErrorsSetCallback(PyXmlSec_ErrorCallback);
189 | }
190 | }
191 |
192 | // initializes errors module
193 | int PyXmlSec_ExceptionsModule_Init(PyObject* package) {
194 | PyXmlSec_Error = NULL;
195 | PyXmlSec_InternalError = NULL;
196 | PyXmlSec_VerificationError = NULL;
197 |
198 | if ((PyXmlSec_Error = PyErr_NewExceptionWithDoc(
199 | STRINGIFY(MODULE_NAME) ".Error", "The common exception class.", PyExc_Exception, 0)) == NULL) goto ON_FAIL;
200 |
201 | if ((PyXmlSec_InternalError = PyErr_NewExceptionWithDoc(
202 | STRINGIFY(MODULE_NAME) ".InternalError", "The internal exception class.", PyXmlSec_Error, 0)) == NULL) goto ON_FAIL;
203 |
204 | if ((PyXmlSec_VerificationError = PyErr_NewExceptionWithDoc(
205 | STRINGIFY(MODULE_NAME) ".VerificationError", "The verification exception class.", PyXmlSec_Error, 0)) == NULL) goto ON_FAIL;
206 |
207 | if (PyModule_AddObject(package, "Error", PyXmlSec_Error) < 0) goto ON_FAIL;
208 | if (PyModule_AddObject(package, "InternalError", PyXmlSec_InternalError) < 0) goto ON_FAIL;
209 | if (PyModule_AddObject(package, "VerificationError", PyXmlSec_VerificationError) < 0) goto ON_FAIL;
210 |
211 | #if PY_MINOR_VERSION >= 7
212 | if (PyThread_tss_create(&PyXmlSec_LastErrorKey) == 0) {
213 | PyXmlSec_InstallErrorCallback();
214 | }
215 | #else
216 | PyXmlSec_LastErrorKey = PyThread_create_key();
217 | PyXmlSec_InstallErrorCallback();
218 | #endif
219 |
220 | return 0;
221 |
222 | ON_FAIL:
223 | Py_XDECREF(PyXmlSec_Error);
224 | Py_XDECREF(PyXmlSec_InternalError);
225 | Py_XDECREF(PyXmlSec_VerificationError);
226 | return -1;
227 | }
228 |
--------------------------------------------------------------------------------
/src/exception.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 Ryan Leckey
2 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
8 | // SOFTWARE.
9 |
10 | #ifndef __PYXMLSEC_EXCEPTIONS_H__
11 | #define __PYXMLSEC_EXCEPTIONS_H__
12 |
13 | #include "platform.h"
14 |
15 | extern PyObject* PyXmlSec_Error;
16 | extern PyObject* PyXmlSec_InternalError;
17 | extern PyObject* PyXmlSec_VerificationError;
18 |
19 | void PyXmlSec_SetLastError(const char* msg);
20 |
21 | void PyXmlSec_SetLastError2(PyObject* type, const char* msg);
22 |
23 | void PyXmlSec_ClearError(void);
24 |
25 | void PyXmlSecEnableDebugTrace(int);
26 |
27 | void PyXmlSec_InstallErrorCallback();
28 |
29 | #endif //__PYXMLSEC_EXCEPTIONS_H__
30 |
--------------------------------------------------------------------------------
/src/keys.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 Ryan Leckey
2 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
8 | // SOFTWARE.
9 |
10 | #ifndef __PYXMLSEC_KEY_H__
11 | #define __PYXMLSEC_KEY_H__
12 |
13 | #include "platform.h"
14 |
15 | #include
16 |
17 | typedef struct {
18 | PyObject_HEAD
19 | xmlSecKeyPtr handle;
20 | int is_own;
21 | } PyXmlSec_Key;
22 |
23 | extern PyTypeObject* PyXmlSec_KeyType;
24 |
25 | PyXmlSec_Key* PyXmlSec_NewKey(void);
26 |
27 | typedef struct {
28 | PyObject_HEAD
29 | xmlSecKeysMngrPtr handle;
30 | } PyXmlSec_KeysManager;
31 |
32 | extern PyTypeObject* PyXmlSec_KeysManagerType;
33 |
34 | // converts object `o` to PyXmlSec_KeysManager, None will be converted to NULL, increments ref_count
35 | int PyXmlSec_KeysManagerConvert(PyObject* o, PyXmlSec_KeysManager** p);
36 |
37 | #endif //__PYXMLSEC_KEY_H__
38 |
--------------------------------------------------------------------------------
/src/lxml.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 Ryan Leckey
2 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
8 | // SOFTWARE.
9 |
10 | #include "common.h"
11 | #include "lxml.h"
12 | #include "exception.h"
13 |
14 | #include
15 | #include
16 |
17 | #include
18 | #include
19 | #include
20 |
21 | #define XMLSEC_EXTRACT_VERSION(x, y) ((x / (y)) % 100)
22 |
23 | #define XMLSEC_EXTRACT_MAJOR(x) XMLSEC_EXTRACT_VERSION(x, 100 * 100)
24 | #define XMLSEC_EXTRACT_MINOR(x) XMLSEC_EXTRACT_VERSION(x, 100)
25 | #define XMLSEC_EXTRACT_PATCH(x) XMLSEC_EXTRACT_VERSION(x, 1)
26 |
27 | static long PyXmlSec_GetLibXmlVersionLong() {
28 | return PyOS_strtol(xmlParserVersion, NULL, 10);
29 | }
30 | long PyXmlSec_GetLibXmlVersionMajor() {
31 | return XMLSEC_EXTRACT_MAJOR(PyXmlSec_GetLibXmlVersionLong());
32 | }
33 | long PyXmlSec_GetLibXmlVersionMinor() {
34 | return XMLSEC_EXTRACT_MINOR(PyXmlSec_GetLibXmlVersionLong());
35 | }
36 | long PyXmlSec_GetLibXmlVersionPatch() {
37 | return XMLSEC_EXTRACT_PATCH(PyXmlSec_GetLibXmlVersionLong());
38 | }
39 |
40 | long PyXmlSec_GetLibXmlCompiledVersionMajor() {
41 | return XMLSEC_EXTRACT_MAJOR(LIBXML_VERSION);
42 | }
43 | long PyXmlSec_GetLibXmlCompiledVersionMinor() {
44 | return XMLSEC_EXTRACT_MINOR(LIBXML_VERSION);
45 | }
46 | long PyXmlSec_GetLibXmlCompiledVersionPatch() {
47 | return XMLSEC_EXTRACT_PATCH(LIBXML_VERSION);
48 | }
49 |
50 | static int PyXmlSec_CheckLxmlLibraryVersion(void) {
51 | // Make sure that the version of libxml2 lxml is using is the same as the one we are using. Because
52 | // we pass trees between the two libraries, we need to make sure that they are using the same version
53 | // of libxml2, or we could run into difficult to debug segfaults.
54 | // See: https://github.com/xmlsec/python-xmlsec/issues/283
55 |
56 | PyObject* lxml = NULL;
57 | PyObject* version = NULL;
58 |
59 | // Default to failure
60 | int result = -1;
61 |
62 | lxml = PyImport_ImportModule("lxml.etree");
63 | if (lxml == NULL) {
64 | goto FINALIZE;
65 | }
66 | version = PyObject_GetAttrString(lxml, "LIBXML_VERSION");
67 | if (version == NULL) {
68 | goto FINALIZE;
69 | }
70 | if (!PyTuple_Check(version) || PyTuple_Size(version) < 2) {
71 | goto FINALIZE;
72 | }
73 |
74 | PyObject* major = PyTuple_GetItem(version, 0);
75 | if (major == NULL) {
76 | goto FINALIZE;
77 | }
78 | PyObject* minor = PyTuple_GetItem(version, 1);
79 | if (minor == NULL) {
80 | goto FINALIZE;
81 | }
82 |
83 | if (!PyLong_Check(major) || !PyLong_Check(minor)) {
84 | goto FINALIZE;
85 | }
86 |
87 | if (PyLong_AsLong(major) != PyXmlSec_GetLibXmlVersionMajor() || PyLong_AsLong(minor) != PyXmlSec_GetLibXmlVersionMinor()) {
88 | goto FINALIZE;
89 | }
90 |
91 | result = 0;
92 |
93 | FINALIZE:
94 | // Clear any errors that may have occurred
95 | PyErr_Clear();
96 |
97 | // Cleanup our references, and return the result
98 | Py_XDECREF(lxml);
99 | Py_XDECREF(version);
100 |
101 | return result;
102 | }
103 |
104 | int PyXmlSec_InitLxmlModule(void) {
105 | if (PyXmlSec_CheckLxmlLibraryVersion() < 0) {
106 | PyXmlSec_SetLastError("lxml & xmlsec libxml2 library version mismatch");
107 | return -1;
108 | }
109 |
110 | return import_lxml__etree();
111 | }
112 |
113 | int PyXmlSec_IsElement(xmlNodePtr xnode) {
114 | return _isElement(xnode);
115 | }
116 |
117 | PyXmlSec_LxmlElementPtr PyXmlSec_elementFactory(PyXmlSec_LxmlDocumentPtr doc, xmlNodePtr xnode) {
118 | return elementFactory(doc, xnode);
119 | }
120 |
121 |
122 | int PyXmlSec_LxmlElementConverter(PyObject* o, PyXmlSec_LxmlElementPtr* p) {
123 | PyXmlSec_LxmlElementPtr node = rootNodeOrRaise(o);
124 | if (node == NULL) {
125 | return 0;
126 | }
127 | *p = node;
128 | // rootNodeOrRaise - increments ref-count, so need to compensate this.
129 | Py_DECREF(node);
130 | return 1;
131 | }
132 |
--------------------------------------------------------------------------------
/src/lxml.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 Ryan Leckey
2 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
8 | // SOFTWARE.
9 |
10 | #ifndef __PYXMLSEC_LXML_H__
11 | #define __PYXMLSEC_LXML_H__
12 |
13 | #include "platform.h"
14 |
15 | #include
16 | #include
17 |
18 | #include
19 | #include
20 |
21 | typedef struct LxmlElement* PyXmlSec_LxmlElementPtr;
22 | typedef struct LxmlDocument* PyXmlSec_LxmlDocumentPtr;
23 |
24 | // checks that xnode is Element
25 | int PyXmlSec_IsElement(xmlNodePtr xnode);
26 | // creates a new element
27 | PyXmlSec_LxmlElementPtr PyXmlSec_elementFactory(PyXmlSec_LxmlDocumentPtr doc, xmlNodePtr node);
28 |
29 | // converts o to PyObject, None object is not allowed, does not increment ref_counts
30 | int PyXmlSec_LxmlElementConverter(PyObject* o, PyXmlSec_LxmlElementPtr* p);
31 |
32 | // get version numbers for libxml2 both compiled and loaded
33 | long PyXmlSec_GetLibXmlVersionMajor();
34 | long PyXmlSec_GetLibXmlVersionMinor();
35 | long PyXmlSec_GetLibXmlVersionPatch();
36 |
37 | long PyXmlSec_GetLibXmlCompiledVersionMajor();
38 | long PyXmlSec_GetLibXmlCompiledVersionMinor();
39 | long PyXmlSec_GetLibXmlCompiledVersionPatch();
40 |
41 | #endif // __PYXMLSEC_LXML_H__
42 |
--------------------------------------------------------------------------------
/src/platform.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 Ryan Leckey
2 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
8 | // SOFTWARE.
9 |
10 | #ifndef __PYXMLSEC_PLATFORM_H__
11 | #define __PYXMLSEC_PLATFORM_H__
12 |
13 | #define PY_SSIZE_T_CLEAN 1
14 |
15 | #include
16 | #include
17 |
18 | #ifdef MS_WIN32
19 | #include
20 | #endif /* MS_WIN32 */
21 |
22 | #define XMLSEC_VERSION_HEX ((XMLSEC_VERSION_MAJOR << 16) | (XMLSEC_VERSION_MINOR << 8) | (XMLSEC_VERSION_SUBMINOR))
23 |
24 | // XKMS support was removed in version 1.2.21
25 | // https://mail.gnome.org/archives/commits-list/2015-February/msg10555.html
26 | #if XMLSEC_VERSION_HEX > 0x10214
27 | #define XMLSEC_NO_XKMS 1
28 | #endif
29 |
30 | #define XSTR(c) (const xmlChar*)(c)
31 |
32 | #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
33 | typedef int Py_ssize_t;
34 | #define PY_SSIZE_T_MAX INT_MAX
35 | #define PY_SSIZE_T_MIN INT_MIN
36 | #endif
37 |
38 | static inline char* PyBytes_AsStringAndSize2(PyObject *obj, Py_ssize_t* length) {
39 | char* buffer = NULL;
40 | return ((PyBytes_AsStringAndSize(obj, &buffer, length) < 0) ? (char*)(0) : buffer);
41 | }
42 |
43 | #endif //__PYXMLSEC_PLATFORM_H__
44 |
--------------------------------------------------------------------------------
/src/tree.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 Ryan Leckey
2 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
8 | // SOFTWARE.
9 |
10 | #include "common.h"
11 | #include "utils.h"
12 | #include "lxml.h"
13 |
14 | #include
15 |
16 | #define PYXMLSEC_TREE_DOC "Common XML utility functions"
17 |
18 | static char PyXmlSec_TreeFindChild__doc__[] = \
19 | "find_child(parent, name, namespace)\n"
20 | "Searches a direct child of the ``parent`` node having given ``name`` and ``namespace`` href.\n\n"
21 | ":param parent: the pointer to XML node\n"
22 | ":type parent: :class:`lxml.etree._Element`\n"
23 | ":param name: the name\n"
24 | ":type name: :class:`str`\n"
25 | ":param namespace: the namespace href (optional)\n"
26 | ":type namespace: :class:`str`\n"
27 | ":return: the pointer to the found node or :data:`None` if node is not found\n"
28 | ":rtype: :class:`lxml.etree._Element` or :data:`None`";
29 | static PyObject* PyXmlSec_TreeFindChild(PyObject* self, PyObject *args, PyObject *kwargs) {
30 | static char *kwlist[] = { "parent", "name", "namespace", NULL};
31 |
32 | PyXmlSec_LxmlElementPtr node = NULL;
33 | const char* name = NULL;
34 | const char* ns = (const char*)xmlSecDSigNs;
35 | xmlNodePtr res;
36 |
37 | PYXMLSEC_DEBUG("tree find_child - start");
38 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|s:find_child", kwlist,
39 | PyXmlSec_LxmlElementConverter, &node, &name, &ns))
40 | {
41 | goto ON_FAIL;
42 | }
43 |
44 | Py_BEGIN_ALLOW_THREADS;
45 | res = xmlSecFindChild(node->_c_node, XSTR(name), XSTR(ns));
46 | Py_END_ALLOW_THREADS;
47 |
48 | PYXMLSEC_DEBUG("tree find_child - ok");
49 | if (res == NULL) {
50 | Py_RETURN_NONE;
51 | }
52 | return (PyObject*)PyXmlSec_elementFactory(node->_doc, res);
53 |
54 | ON_FAIL:
55 | PYXMLSEC_DEBUG("tree find_child - fail");
56 | return NULL;
57 | }
58 |
59 | static char PyXmlSec_TreeFindParent__doc__[] = \
60 | "find_parent(node, name, namespace)\n"
61 | "Searches the ancestors axis of the ``node`` having given ``name`` and ``namespace`` href.\n\n"
62 | ":param node: the pointer to XML node\n"
63 | ":type node: :class:`lxml.etree._Element`\n"
64 | ":param name: the name\n"
65 | ":type name: :class:`str`\n"
66 | ":param namespace: the namespace href (optional)\n"
67 | ":type namespace: :class:`str`\n"
68 | ":return: the pointer to the found node or :data:`None` if node is not found\n"
69 | ":rtype: :class:`lxml.etree._Element` or :data:`None`";
70 | static PyObject* PyXmlSec_TreeFindParent(PyObject* self, PyObject *args, PyObject *kwargs) {
71 | static char *kwlist[] = { "node", "name", "namespace", NULL};
72 |
73 | PyXmlSec_LxmlElementPtr node = NULL;
74 | const char* name = NULL;
75 | const char* ns = (const char*)xmlSecDSigNs;
76 | xmlNodePtr res;
77 |
78 | PYXMLSEC_DEBUG("tree find_parent - start");
79 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|s:find_parent", kwlist,
80 | PyXmlSec_LxmlElementConverter, &node, &name, &ns))
81 | {
82 | goto ON_FAIL;
83 | }
84 |
85 | Py_BEGIN_ALLOW_THREADS;
86 | res = xmlSecFindParent(node->_c_node, XSTR(name), XSTR(ns));
87 | Py_END_ALLOW_THREADS;
88 |
89 | PYXMLSEC_DEBUG("tree find_parent - ok");
90 | if (res == NULL) {
91 | Py_RETURN_NONE;
92 | }
93 | return (PyObject*)PyXmlSec_elementFactory(node->_doc, res);
94 |
95 | ON_FAIL:
96 | PYXMLSEC_DEBUG("tree find_parent - fail");
97 | return NULL;
98 | }
99 |
100 | static char PyXmlSec_TreeFindNode__doc__[] = \
101 | "find_node(node, name, namespace)\n"
102 | "Searches all children of the given ``node`` having given ``name`` and ``namespace`` href.\n\n"
103 | ":param node: the pointer to XML node\n"
104 | ":type node: :class:`lxml.etree._Element`\n"
105 | ":param name: the name\n"
106 | ":type name: :class:`str`\n"
107 | ":param namespace: the namespace href (optional)\n"
108 | ":type namespace: :class:`str`\n"
109 | ":return: the pointer to the found node or :data:`None` if node is not found\n"
110 | ":rtype: :class:`lxml.etree._Element` or :data:`None`";
111 | static PyObject* PyXmlSec_TreeFindNode(PyObject* self, PyObject *args, PyObject *kwargs) {
112 | static char *kwlist[] = { "node", "name", "namespace", NULL};
113 |
114 | PyXmlSec_LxmlElementPtr node = NULL;
115 | const char* name = NULL;
116 | const char* ns = (const char*)xmlSecDSigNs;
117 | xmlNodePtr res;
118 |
119 | PYXMLSEC_DEBUG("tree find_node - start");
120 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|s:find_node", kwlist,
121 | PyXmlSec_LxmlElementConverter, &node, &name, &ns))
122 | {
123 | goto ON_FAIL;
124 | }
125 |
126 | Py_BEGIN_ALLOW_THREADS;
127 | res = xmlSecFindNode(node->_c_node, XSTR(name), XSTR(ns));
128 | Py_END_ALLOW_THREADS;
129 |
130 | PYXMLSEC_DEBUG("tree find_node - ok");
131 | if (res == NULL) {
132 | Py_RETURN_NONE;
133 | }
134 | return (PyObject*)PyXmlSec_elementFactory(node->_doc, res);
135 |
136 | ON_FAIL:
137 | PYXMLSEC_DEBUG("tree find_node - fail");
138 | return NULL;
139 | }
140 |
141 | static char PyXmlSec_TreeAddIds__doc__[] = \
142 | "add_ids(node, ids) -> None\n"
143 | "Registers ``ids`` as ids used below ``node``. ``ids`` is a sequence of attribute names "\
144 | "used as XML ids in the subtree rooted at ``node``.\n"\
145 | "A call to :func:`~.add_ids` may be necessary to make known which attributes contain XML ids.\n"\
146 | "This is the case, if a transform references an id via ``XPointer`` or a self document uri and "
147 | "the id inkey_data_formation is not available by other means (e.g. an associated DTD or XML schema).\n\n"
148 | ":param node: the pointer to XML node\n"
149 | ":type node: :class:`lxml.etree._Element`\n"
150 | ":param ids: the list of ID attributes.\n"
151 | ":type ids: :class:`list` of strings";
152 | static PyObject* PyXmlSec_TreeAddIds(PyObject* self, PyObject *args, PyObject *kwargs) {
153 | static char *kwlist[] = { "node", "ids", NULL};
154 |
155 | PyXmlSec_LxmlElementPtr node = NULL;
156 | PyObject* ids = NULL;
157 |
158 | const xmlChar** list = NULL;
159 |
160 | Py_ssize_t n;
161 | PyObject* tmp;
162 | PyObject* key;
163 | Py_ssize_t i;
164 |
165 | PYXMLSEC_DEBUG("tree add_ids - start");
166 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O:add_ids", kwlist, PyXmlSec_LxmlElementConverter, &node, &ids))
167 | {
168 | goto ON_FAIL;
169 | }
170 | n = PyObject_Length(ids);
171 | if (n < 0) goto ON_FAIL;
172 |
173 | list = (const xmlChar**)xmlMalloc(sizeof(xmlChar*) * (n + 1));
174 | if (list == NULL) {
175 | PyErr_SetString(PyExc_MemoryError, "no memory");
176 | goto ON_FAIL;
177 | }
178 |
179 | for (i = 0; i < n; ++i) {
180 | key = PyLong_FromSsize_t(i);
181 | if (key == NULL) goto ON_FAIL;
182 | tmp = PyObject_GetItem(ids, key);
183 | Py_DECREF(key);
184 | if (tmp == NULL) goto ON_FAIL;
185 | list[i] = XSTR(PyUnicode_AsUTF8(tmp));
186 | Py_DECREF(tmp);
187 | if (list[i] == NULL) goto ON_FAIL;
188 | }
189 | list[n] = NULL;
190 |
191 | Py_BEGIN_ALLOW_THREADS;
192 | xmlSecAddIDs(node->_doc->_c_doc, node->_c_node, list);
193 | Py_END_ALLOW_THREADS;
194 |
195 | PyMem_Free(list);
196 |
197 | PYXMLSEC_DEBUG("tree add_ids - ok");
198 | Py_RETURN_NONE;
199 | ON_FAIL:
200 | PYXMLSEC_DEBUG("tree add_ids - fail");
201 | xmlFree(list);
202 | return NULL;
203 | }
204 |
205 | static PyMethodDef PyXmlSec_TreeMethods[] = {
206 | {
207 | "find_child",
208 | (PyCFunction)PyXmlSec_TreeFindChild,
209 | METH_VARARGS|METH_KEYWORDS,
210 | PyXmlSec_TreeFindChild__doc__,
211 | },
212 | {
213 | "find_parent",
214 | (PyCFunction)PyXmlSec_TreeFindParent,
215 | METH_VARARGS|METH_KEYWORDS,
216 | PyXmlSec_TreeFindParent__doc__,
217 | },
218 | {
219 | "find_node",
220 | (PyCFunction)PyXmlSec_TreeFindNode,
221 | METH_VARARGS|METH_KEYWORDS,
222 | PyXmlSec_TreeFindNode__doc__,
223 | },
224 | {
225 | "add_ids",
226 | (PyCFunction)PyXmlSec_TreeAddIds,
227 | METH_VARARGS|METH_KEYWORDS,
228 | PyXmlSec_TreeAddIds__doc__,
229 | },
230 | {NULL, NULL} /* sentinel */
231 | };
232 |
233 | static PyModuleDef PyXmlSec_TreeModule =
234 | {
235 | PyModuleDef_HEAD_INIT,
236 | STRINGIFY(MODULE_NAME) ".tree",
237 | PYXMLSEC_TREE_DOC,
238 | -1,
239 | PyXmlSec_TreeMethods, /* m_methods */
240 | NULL, /* m_slots */
241 | NULL, /* m_traverse */
242 | NULL, /* m_clear */
243 | NULL, /* m_free */
244 | };
245 |
246 |
247 | int PyXmlSec_TreeModule_Init(PyObject* package) {
248 | PyObject* tree = PyModule_Create(&PyXmlSec_TreeModule);
249 |
250 | if (!tree) goto ON_FAIL;
251 |
252 | if (PyModule_AddObject(package, "tree", tree) < 0) goto ON_FAIL;
253 |
254 | return 0;
255 | ON_FAIL:
256 | Py_XDECREF(tree);
257 | return -1;
258 | }
259 |
--------------------------------------------------------------------------------
/src/utils.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 Ryan Leckey
2 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
8 | // SOFTWARE.
9 |
10 | #include "utils.h"
11 |
12 | PyObject* PyXmlSec_GetFilePathOrContent(PyObject* file, int* is_content) {
13 | PyObject* data;
14 | PyObject* utf8;
15 | PyObject* tmp = NULL;
16 |
17 | if (PyObject_HasAttrString(file, "read")) {
18 | data = PyObject_CallMethod(file, "read", NULL);
19 | if (data != NULL && PyUnicode_Check(data)) {
20 | utf8 = PyUnicode_AsUTF8String(data);
21 | Py_DECREF(data);
22 | data = utf8;
23 | }
24 | *is_content = 1;
25 | return data;
26 | }
27 | *is_content = 0;
28 | if (!PyUnicode_FSConverter(file, &tmp)) {
29 | return NULL;
30 | }
31 | return tmp;
32 | }
33 |
34 | int PyXmlSec_SetStringAttr(PyObject* obj, const char* name, const char* value) {
35 | PyObject* tmp = PyUnicode_FromString(value);
36 | int r;
37 |
38 | if (tmp == NULL) {
39 | return -1;
40 | }
41 | r = PyObject_SetAttrString(obj, name, tmp);
42 | Py_DECREF(tmp);
43 | return r;
44 | }
45 |
46 | int PyXmlSec_SetLongAttr(PyObject* obj, const char* name, long value) {
47 | PyObject* tmp = PyLong_FromLong(value);
48 | int r;
49 |
50 | if (tmp == NULL) {
51 | return -1;
52 | }
53 | r = PyObject_SetAttrString(obj, name, tmp);
54 | Py_DECREF(tmp);
55 | return r;
56 | }
57 |
--------------------------------------------------------------------------------
/src/utils.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2017 Ryan Leckey
2 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
5 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
8 | // SOFTWARE.
9 |
10 | #ifndef __PYXMLSEC_UTILS_H__
11 | #define __PYXMLSEC_UTILS_H__
12 |
13 | #include "platform.h"
14 |
15 | int PyXmlSec_SetStringAttr(PyObject* obj, const char* name, const char* value);
16 |
17 | int PyXmlSec_SetLongAttr(PyObject* obj, const char* name, long value);
18 |
19 | // return content if file is fileobject, or fs encoded filepath
20 | PyObject* PyXmlSec_GetFilePathOrContent(PyObject* file, int* is_content);
21 |
22 | #endif //__PYXMLSEC_UTILS_H__
23 |
--------------------------------------------------------------------------------
/src/xmlsec/__init__.pyi:
--------------------------------------------------------------------------------
1 | from collections.abc import Callable, Iterable
2 | from typing import IO, Any, AnyStr, TypeVar, overload
3 |
4 | from _typeshed import GenericPath, Self, StrOrBytesPath
5 | from lxml.etree import _Element
6 |
7 | from xmlsec import constants as constants
8 | from xmlsec import template as template
9 | from xmlsec import tree as tree
10 | from xmlsec.constants import __KeyData as KeyData
11 | from xmlsec.constants import __Transform as Transform
12 |
13 | _E = TypeVar('_E', bound=_Element)
14 |
15 | def enable_debug_trace(enabled: bool = ...) -> None: ...
16 | def get_libxml_version() -> tuple[int, int, int]: ...
17 | def get_libxml_compiled_version() -> tuple[int, int, int]: ...
18 | def init() -> None: ...
19 | def shutdown() -> None: ...
20 | def cleanup_callbacks() -> None: ...
21 | def register_default_callbacks() -> None: ...
22 | def register_callbacks(
23 | input_match_callback: Callable[[bytes], bool],
24 | input_open_callback: Callable[[bytes], Any],
25 | input_read_callback: Callable[[Any, memoryview], int],
26 | input_close_callback: Callable[[Any], None],
27 | ) -> None: ...
28 | @overload
29 | def base64_default_line_size() -> int: ...
30 | @overload
31 | def base64_default_line_size(size: int) -> None: ...
32 |
33 | class EncryptionContext:
34 | key: Key | None
35 | def __init__(self, manager: KeysManager | None = ...) -> None: ...
36 | def decrypt(self, node: _Element) -> _Element: ...
37 | def encrypt_binary(self, template: _E, data: bytes) -> _E: ...
38 | def encrypt_uri(self, template: _E, uri: str) -> _E: ...
39 | def encrypt_xml(self, template: _E, node: _Element) -> _E: ...
40 | def reset(self) -> None: ...
41 |
42 | class Error(Exception): ...
43 | class InternalError(Error): ...
44 |
45 | class Key:
46 | name: str
47 | @classmethod
48 | def from_binary_data(cls: type[Self], klass: KeyData, data: AnyStr) -> Self: ...
49 | @classmethod
50 | def from_binary_file(cls: type[Self], klass: KeyData, filename: StrOrBytesPath) -> Self: ...
51 | @classmethod
52 | def from_file(cls: type[Self], file: GenericPath[AnyStr] | IO[AnyStr], format: int, password: str | None = ...) -> Self: ...
53 | @classmethod
54 | def from_engine(cls: type[Self], engine_and_key_id: AnyStr) -> Self: ...
55 | @classmethod
56 | def from_memory(cls: type[Self], data: AnyStr, format: int, password: str | None = ...) -> Self: ...
57 | @classmethod
58 | def generate(cls: type[Self], klass: KeyData, size: int, type: int) -> Self: ...
59 | def load_cert_from_file(self, file: GenericPath[AnyStr] | IO[AnyStr], format: int) -> None: ...
60 | def load_cert_from_memory(self, data: AnyStr, format: int) -> None: ...
61 | def __copy__(self: Self) -> Self: ...
62 | def __deepcopy__(self: Self) -> Self: ...
63 |
64 | class KeysManager:
65 | def add_key(self, key: Key) -> None: ...
66 | def load_cert(self, filename: StrOrBytesPath, format: int, type: int) -> None: ...
67 | def load_cert_from_memory(self, data: AnyStr, format: int, type: int) -> None: ...
68 |
69 | class SignatureContext:
70 | key: Key | None
71 | def enable_reference_transform(self, transform: Transform) -> None: ...
72 | def enable_signature_transform(self, transform: Transform) -> None: ...
73 | def register_id(self, node: _Element, id_attr: str = ..., id_ns: str | None = ...) -> None: ...
74 | def set_enabled_key_data(self, keydata_list: Iterable[KeyData]) -> None: ...
75 | def sign(self, node: _Element) -> None: ...
76 | def sign_binary(self, bytes: bytes, transform: Transform) -> bytes: ...
77 | def verify(self, node: _Element) -> None: ...
78 | def verify_binary(self, bytes: bytes, transform: Transform, signature: bytes) -> None: ...
79 |
80 | class VerificationError(Error): ...
81 |
--------------------------------------------------------------------------------
/src/xmlsec/constants.pyi:
--------------------------------------------------------------------------------
1 | import sys
2 | from typing import NamedTuple
3 |
4 | if sys.version_info >= (3, 8):
5 | from typing import Final
6 | else:
7 | from typing_extensions import Final
8 |
9 | class __KeyData(NamedTuple): # __KeyData type
10 | href: str
11 | name: str
12 |
13 | class __KeyDataNoHref(NamedTuple): # __KeyData type
14 | href: None
15 | name: str
16 |
17 | class __Transform(NamedTuple): # __Transform type
18 | href: str
19 | name: str
20 | usage: int
21 |
22 | class __TransformNoHref(NamedTuple): # __Transform type
23 | href: None
24 | name: str
25 | usage: int
26 |
27 | DSigNs: Final[str]
28 | EncNs: Final[str]
29 | KeyDataAes: Final[__KeyData]
30 | KeyDataDes: Final[__KeyData]
31 | KeyDataDsa: Final[__KeyData]
32 | KeyDataEc: Final[__KeyData]
33 | KeyDataEcdsa: Final[__KeyData]
34 | KeyDataEncryptedKey: Final[__KeyData]
35 | KeyDataFormatBinary: Final[int]
36 | KeyDataFormatCertDer: Final[int]
37 | KeyDataFormatCertPem: Final[int]
38 | KeyDataFormatDer: Final[int]
39 | KeyDataFormatPem: Final[int]
40 | KeyDataFormatPkcs12: Final[int]
41 | KeyDataFormatPkcs8Der: Final[int]
42 | KeyDataFormatPkcs8Pem: Final[int]
43 | KeyDataFormatUnknown: Final[int]
44 | KeyDataHmac: Final[__KeyData]
45 | KeyDataName: Final[__KeyDataNoHref]
46 | KeyDataRawX509Cert: Final[__KeyData]
47 | KeyDataRetrievalMethod: Final[__KeyDataNoHref]
48 | KeyDataRsa: Final[__KeyData]
49 | KeyDataTypeAny: Final[int]
50 | KeyDataTypeNone: Final[int]
51 | KeyDataTypePermanent: Final[int]
52 | KeyDataTypePrivate: Final[int]
53 | KeyDataTypePublic: Final[int]
54 | KeyDataTypeSession: Final[int]
55 | KeyDataTypeSymmetric: Final[int]
56 | KeyDataTypeTrusted: Final[int]
57 | KeyDataTypeUnknown: Final[int]
58 | KeyDataValue: Final[__KeyDataNoHref]
59 | KeyDataX509: Final[__KeyData]
60 | NodeCanonicalizationMethod: Final[str]
61 | NodeCipherData: Final[str]
62 | NodeCipherReference: Final[str]
63 | NodeCipherValue: Final[str]
64 | NodeDataReference: Final[str]
65 | NodeDigestMethod: Final[str]
66 | NodeDigestValue: Final[str]
67 | NodeEncryptedData: Final[str]
68 | NodeEncryptedKey: Final[str]
69 | NodeEncryptionMethod: Final[str]
70 | NodeEncryptionProperties: Final[str]
71 | NodeEncryptionProperty: Final[str]
72 | NodeKeyInfo: Final[str]
73 | NodeKeyName: Final[str]
74 | NodeKeyReference: Final[str]
75 | NodeKeyValue: Final[str]
76 | NodeManifest: Final[str]
77 | NodeObject: Final[str]
78 | NodeReference: Final[str]
79 | NodeReferenceList: Final[str]
80 | NodeSignature: Final[str]
81 | NodeSignatureMethod: Final[str]
82 | NodeSignatureProperties: Final[str]
83 | NodeSignatureValue: Final[str]
84 | NodeSignedInfo: Final[str]
85 | NodeX509Data: Final[str]
86 | Ns: Final[str]
87 | NsExcC14N: Final[str]
88 | NsExcC14NWithComments: Final[str]
89 | TransformAes128Cbc: Final[__Transform]
90 | TransformAes128Gcm: Final[__Transform]
91 | TransformAes192Cbc: Final[__Transform]
92 | TransformAes192Gcm: Final[__Transform]
93 | TransformAes256Cbc: Final[__Transform]
94 | TransformAes256Gcm: Final[__Transform]
95 | TransformDes3Cbc: Final[__Transform]
96 | TransformDsaSha1: Final[__Transform]
97 | TransformEcdsaSha1: Final[__Transform]
98 | TransformEcdsaSha224: Final[__Transform]
99 | TransformEcdsaSha256: Final[__Transform]
100 | TransformEcdsaSha384: Final[__Transform]
101 | TransformEcdsaSha512: Final[__Transform]
102 | TransformEnveloped: Final[__Transform]
103 | TransformExclC14N: Final[__Transform]
104 | TransformExclC14NWithComments: Final[__Transform]
105 | TransformHmacMd5: Final[__Transform]
106 | TransformHmacRipemd160: Final[__Transform]
107 | TransformHmacSha1: Final[__Transform]
108 | TransformHmacSha224: Final[__Transform]
109 | TransformHmacSha256: Final[__Transform]
110 | TransformHmacSha384: Final[__Transform]
111 | TransformHmacSha512: Final[__Transform]
112 | TransformInclC14N: Final[__Transform]
113 | TransformInclC14N11: Final[__Transform]
114 | TransformInclC14N11WithComments: Final[__Transform]
115 | TransformInclC14NWithComments: Final[__Transform]
116 | TransformKWAes128: Final[__Transform]
117 | TransformKWAes192: Final[__Transform]
118 | TransformKWAes256: Final[__Transform]
119 | TransformKWDes3: Final[__Transform]
120 | TransformMd5: Final[__Transform]
121 | TransformRemoveXmlTagsC14N: Final[__TransformNoHref]
122 | TransformRipemd160: Final[__Transform]
123 | TransformRsaMd5: Final[__Transform]
124 | TransformRsaOaep: Final[__Transform]
125 | TransformRsaPkcs1: Final[__Transform]
126 | TransformRsaRipemd160: Final[__Transform]
127 | TransformRsaSha1: Final[__Transform]
128 | TransformRsaSha224: Final[__Transform]
129 | TransformRsaSha256: Final[__Transform]
130 | TransformRsaSha384: Final[__Transform]
131 | TransformRsaSha512: Final[__Transform]
132 | TransformSha1: Final[__Transform]
133 | TransformSha224: Final[__Transform]
134 | TransformSha256: Final[__Transform]
135 | TransformSha384: Final[__Transform]
136 | TransformSha512: Final[__Transform]
137 | TransformUsageAny: Final[int]
138 | TransformUsageC14NMethod: Final[int]
139 | TransformUsageDSigTransform: Final[int]
140 | TransformUsageDigestMethod: Final[int]
141 | TransformUsageEncryptionMethod: Final[int]
142 | TransformUsageSignatureMethod: Final[int]
143 | TransformUsageUnknown: Final[int]
144 | TransformVisa3DHack: Final[__TransformNoHref]
145 | TransformXPath: Final[__Transform]
146 | TransformXPath2: Final[__Transform]
147 | TransformXPointer: Final[__Transform]
148 | TransformXslt: Final[__Transform]
149 | TypeEncContent: Final[str]
150 | TypeEncElement: Final[str]
151 | XPath2Ns: Final[str]
152 | XPathNs: Final[str]
153 | XPointerNs: Final[str]
154 |
--------------------------------------------------------------------------------
/src/xmlsec/py.typed:
--------------------------------------------------------------------------------
1 | # Marker file for PEP 561. The xmlsec package uses stub files.
2 |
--------------------------------------------------------------------------------
/src/xmlsec/template.pyi:
--------------------------------------------------------------------------------
1 | from collections.abc import Sequence
2 | from typing import Any
3 |
4 | from lxml.etree import _Element
5 |
6 | from xmlsec.constants import __Transform as Transform
7 |
8 | def add_encrypted_key(
9 | node: _Element, method: Transform, id: str | None = ..., type: str | None = ..., recipient: str | None = ...
10 | ) -> _Element: ...
11 | def add_key_name(node: _Element, name: str | None = ...) -> _Element: ...
12 | def add_key_value(node: _Element) -> _Element: ...
13 | def add_reference(
14 | node: _Element, digest_method: Transform, id: str | None = ..., uri: str | None = ..., type: str | None = ...
15 | ) -> _Element: ...
16 | def add_transform(node: _Element, transform: Transform) -> Any: ...
17 | def add_x509_data(node: _Element) -> _Element: ...
18 | def create(node: _Element, c14n_method: Transform, sign_method: Transform) -> _Element: ...
19 | def encrypted_data_create(
20 | node: _Element,
21 | method: Transform,
22 | id: str | None = ...,
23 | type: str | None = ...,
24 | mime_type: str | None = ...,
25 | encoding: str | None = ...,
26 | ns: str | None = ...,
27 | ) -> _Element: ...
28 | def encrypted_data_ensure_cipher_value(node: _Element) -> _Element: ...
29 | def encrypted_data_ensure_key_info(node: _Element, id: str | None = ..., ns: str | None = ...) -> _Element: ...
30 | def ensure_key_info(node: _Element, id: str | None = ...) -> _Element: ...
31 | def transform_add_c14n_inclusive_namespaces(node: _Element, prefixes: str | Sequence[str]) -> None: ...
32 | def x509_data_add_certificate(node: _Element) -> _Element: ...
33 | def x509_data_add_crl(node: _Element) -> _Element: ...
34 | def x509_data_add_issuer_serial(node: _Element) -> _Element: ...
35 | def x509_data_add_ski(node: _Element) -> _Element: ...
36 | def x509_data_add_subject_name(node: _Element) -> _Element: ...
37 | def x509_issuer_serial_add_issuer_name(node: _Element, name: str | None = ...) -> _Element: ...
38 | def x509_issuer_serial_add_serial_number(node: _Element, serial: str | None = ...) -> _Element: ...
39 |
--------------------------------------------------------------------------------
/src/xmlsec/tree.pyi:
--------------------------------------------------------------------------------
1 | from collections.abc import Sequence
2 | from typing import overload
3 |
4 | from lxml.etree import _Element
5 |
6 | def add_ids(node: _Element, ids: Sequence[str]) -> None: ...
7 | @overload
8 | def find_child(parent: _Element, name: str) -> _Element | None: ...
9 | @overload
10 | def find_child(parent: _Element, name: str, namespace: str = ...) -> _Element | None: ...
11 | @overload
12 | def find_node(node: _Element, name: str) -> _Element | None: ...
13 | @overload
14 | def find_node(node: _Element, name: str, namespace: str = ...) -> _Element | None: ...
15 | @overload
16 | def find_parent(node: _Element, name: str) -> _Element | None: ...
17 | @overload
18 | def find_parent(node: _Element, name: str, namespace: str = ...) -> _Element | None: ...
19 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmlsec/python-xmlsec/967754b6ec084d3ee5baa73ad256cf19f0f231de/tests/__init__.py
--------------------------------------------------------------------------------
/tests/base.py:
--------------------------------------------------------------------------------
1 | import gc
2 | import os
3 | import sys
4 | import unittest
5 |
6 | from lxml import etree
7 |
8 | import xmlsec
9 |
10 | etype = type(etree.Element('test'))
11 |
12 | ns = {'dsig': xmlsec.constants.DSigNs, 'enc': xmlsec.constants.EncNs}
13 |
14 |
15 | try:
16 | import resource
17 |
18 | test_iterations = int(os.environ.get('PYXMLSEC_TEST_ITERATIONS', '10'))
19 | except (ImportError, ValueError):
20 | test_iterations = 0
21 |
22 |
23 | class TestMemoryLeaks(unittest.TestCase):
24 | maxDiff = None
25 |
26 | iterations = test_iterations
27 |
28 | data_dir = os.path.join(os.path.dirname(__file__), "data")
29 |
30 | def setUp(self):
31 | gc.disable()
32 | self.addTypeEqualityFunc(etype, "assertXmlEqual")
33 | xmlsec.enable_debug_trace(1)
34 |
35 | def run(self, result=None):
36 | # run first time
37 | super(TestMemoryLeaks, self).run(result=result)
38 | if self.iterations == 0:
39 | return
40 |
41 | m_usage = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
42 | o_count = gc.get_count()[0]
43 | m_hits = 0
44 | o_hits = 0
45 | for _ in range(self.iterations):
46 | super(TestMemoryLeaks, self).run(result=result)
47 | m_usage_n = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
48 | if m_usage_n > m_usage:
49 | m_usage = m_usage_n
50 | m_hits += 1
51 | o_count_n = gc.get_count()[0]
52 | if o_count_n > o_count:
53 | o_count = o_count_n
54 | o_hits += 1
55 | del m_usage_n
56 | del o_count_n
57 |
58 | if m_hits > int(self.iterations * 0.8):
59 | result.buffer = False
60 | try:
61 | raise AssertionError("memory leak detected")
62 | except AssertionError:
63 | result.addError(self, sys.exc_info())
64 | if o_hits > int(self.iterations * 0.8):
65 | result.buffer = False
66 | try:
67 | raise AssertionError("unreferenced objects detected")
68 | except AssertionError:
69 | result.addError(self, sys.exc_info())
70 |
71 | def path(self, name):
72 | """Return full path for resource."""
73 | return os.path.join(self.data_dir, name)
74 |
75 | def load(self, name):
76 | """Load resource by name."""
77 | with open(self.path(name), "rb") as stream:
78 | return stream.read()
79 |
80 | def load_xml(self, name, xpath=None):
81 | """Return xml.etree."""
82 | with open(self.path(name)) as f:
83 | root = etree.parse(f).getroot()
84 | if xpath is None:
85 | return root
86 | return root.find(xpath)
87 |
88 | def dump(self, root):
89 | print(etree.tostring(root))
90 |
91 | def assertXmlEqual(self, first, second, msg=None): # noqa: N802
92 | """Check equality of etree.roots."""
93 | msg = msg or ''
94 | if first.tag != second.tag:
95 | self.fail('Tags do not match: {} and {}. {}'.format(first.tag, second.tag, msg))
96 | for name, value in first.attrib.items():
97 | if second.attrib.get(name) != value:
98 | self.fail('Attributes do not match: {}={!r}, {}={!r}. {}'.format(name, value, name, second.attrib.get(name), msg))
99 | for name in second.attrib.keys():
100 | if name not in first.attrib:
101 | self.fail('x2 has an attribute x1 is missing: {}. {}'.format(name, msg))
102 | if not _xml_text_compare(first.text, second.text):
103 | self.fail('text: {!r} != {!r}. {}'.format(first.text, second.text, msg))
104 | if not _xml_text_compare(first.tail, second.tail):
105 | self.fail('tail: {!r} != {!r}. {}'.format(first.tail, second.tail, msg))
106 | cl1 = sorted(first.getchildren(), key=lambda x: x.tag)
107 | cl2 = sorted(second.getchildren(), key=lambda x: x.tag)
108 | if len(cl1) != len(cl2):
109 | self.fail('children length differs, {} != {}. {}'.format(len(cl1), len(cl2), msg))
110 | i = 0
111 | for c1, c2 in zip(cl1, cl2):
112 | i += 1
113 | self.assertXmlEqual(c1, c2)
114 |
115 |
116 | def _xml_text_compare(t1, t2):
117 | if not t1 and not t2:
118 | return True
119 | if t1 == '*' or t2 == '*':
120 | return True
121 | return (t1 or '').strip() == (t2 or '').strip()
122 |
--------------------------------------------------------------------------------
/tests/conftest.py:
--------------------------------------------------------------------------------
1 | def pytest_collection_modifyitems(items):
2 | """
3 | Put the module init test first.
4 |
5 | This way, we implicitly check whether any subsequent test fails because of module reinitialization.
6 | """
7 |
8 | def module_init_tests_first(item):
9 | return int('test_xmlsec.py::TestModule::test_reinitialize_module' not in item.nodeid)
10 |
11 | items.sort(key=module_init_tests_first)
12 |
--------------------------------------------------------------------------------
/tests/data/deskey.bin:
--------------------------------------------------------------------------------
1 | 012345670123456701234567
2 |
--------------------------------------------------------------------------------
/tests/data/doc.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | Hello, World!
7 |
8 |
--------------------------------------------------------------------------------
/tests/data/dsacert.der:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmlsec/python-xmlsec/967754b6ec084d3ee5baa73ad256cf19f0f231de/tests/data/dsacert.der
--------------------------------------------------------------------------------
/tests/data/dsakey.der:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmlsec/python-xmlsec/967754b6ec084d3ee5baa73ad256cf19f0f231de/tests/data/dsakey.der
--------------------------------------------------------------------------------
/tests/data/enc1-in.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | Hello, World!
7 |
8 |
--------------------------------------------------------------------------------
/tests/data/enc1-out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | UrTgE0UxQa8xevs4SyRA0rsibEz/ZFDjCBD+t4pKSdajB/cefYObZzqq2l41Q6R/
10 | tqYLht5hEBh26AHfjmQSJAL+eChXOt/EaOf63zzJedO90HGqIQyzOeOPURAl3Li8
11 | ivPyLVyocJDeVNeh7W+7kYwpFQ6PLuQxWsFFQXVoRAWbXHpZkSzVheR+5RpYJRTb
12 | 1UYXKxu8jg4NqbjucVMDIxUOzsVCDRyk8R8sQrM7D/H/N0y7DAY8oX/WZ45xLwUy
13 | DY/U86tTpTn95NwHD10SLyrL6rpXdbEuoIQHhWLwV9uQxnJA/Pn1KZ+xXK/fePfP
14 | 26PBo/hUrN5pm5U8ycc4iw==
15 |
16 |
17 |
18 |
19 | 2pb5Mxd0f+AW56Cs3MfQ9HJkUVeliSi1hVCNCVHTKeMyC2VL6lPhQ9+L01aSeTSY
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tests/data/enc2-in.xml:
--------------------------------------------------------------------------------
1 |
2 | test
3 |
--------------------------------------------------------------------------------
/tests/data/enc2-out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | HJwrfL7kOIB0QaldMJdza1HitpLCjw+eoult1C6yExDXJ09zKaSQER+pUL9Vt5fm
10 | d4Oitsf0CUNkjG1xWJdFsftqUIuvYGnkUNhT0vtqoYbdhJkCcB9cCwvTrww2+VTF
11 | NIasTdechlSD1qQOR8uf6+S94Ae4PVSfWU+5YLTJFpMjR+OT7f6BSbYNv1By6Cko
12 | G39WTSKTRcVDzcMxRepAGb59r508yKIJhwabCf3Opu+Ams7ia7BH4oa4ro9YSWwm
13 | hAJ0CN4a6b5odcRbNvuHcwWSxpoysWKbOROQ0H4xC4nGZeL/AXlpSc8eNuNG+g6D
14 | CTBwsOXCAEJYXPkTrnB3qQ==
15 |
16 |
17 |
18 |
19 | 4m5BRKEswOe8JISY7NrPGLBYv7Ay5pBV+nG6it51gz0=
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tests/data/enc3-in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | test
4 |
5 |
--------------------------------------------------------------------------------
/tests/data/enc3-out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | HJwrfL7kOIB0QaldMJdza1HitpLCjw+eoult1C6yExDXJ09zKaSQER+pUL9Vt5fm
7 | d4Oitsf0CUNkjG1xWJdFsftqUIuvYGnkUNhT0vtqoYbdhJkCcB9cCwvTrww2+VTF
8 | NIasTdechlSD1qQOR8uf6+S94Ae4PVSfWU+5YLTJFpMjR+OT7f6BSbYNv1By6Cko
9 | G39WTSKTRcVDzcMxRepAGb59r508yKIJhwabCf3Opu+Ams7ia7BH4oa4ro9YSWwm
10 | hAJ0CN4a6b5odcRbNvuHcwWSxpoysWKbOROQ0H4xC4nGZeL/AXlpSc8eNuNG+g6D
11 | CTBwsOXCAEJYXPkTrnB3qQ==
12 |
13 |
14 |
15 |
16 |
17 | 4m5BRKEswOe8JISY7NrPGLBYv7Ay5pBV+nG6it51gz0=
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/tests/data/enc_template.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/tests/data/rsacert.pem:
--------------------------------------------------------------------------------
1 | Certificate:
2 | Data:
3 | Version: 3 (0x2)
4 | Serial Number: 5 (0x5)
5 | Signature Algorithm: md5WithRSAEncryption
6 | Issuer: C=US, ST=California, L=Sunnyvale, O=XML Security Library (http://www.aleksey.com/xmlsec), OU=Root Certificate, CN=Aleksey Sanin/emailAddress=xmlsec@aleksey.com
7 | Validity
8 | Not Before: Mar 31 04:02:22 2003 GMT
9 | Not After : Mar 28 04:02:22 2013 GMT
10 | Subject: C=US, ST=California, O=XML Security Library (http://www.aleksey.com/xmlsec), OU=Examples RSA Certificate, CN=Aleksey Sanin/emailAddress=xmlsec@aleksey.com
11 | Subject Public Key Info:
12 | Public Key Algorithm: rsaEncryption
13 | RSA Public Key: (2048 bit)
14 | Modulus (2048 bit):
15 | 00:97:b8:fe:b4:3f:83:35:78:16:89:04:ec:2b:61:
16 | 8c:bf:c4:5f:00:81:4a:45:e6:d9:cd:e9:e2:3c:97:
17 | 3b:45:ad:aa:e6:8d:0b:77:71:07:01:4f:7c:f9:7d:
18 | e2:19:aa:dd:91:59:f4:f1:cf:3d:ba:78:46:96:11:
19 | 9c:b6:5b:46:39:73:55:23:aa:f7:9e:00:5c:e5:e9:
20 | 49:ec:3b:9c:3f:84:99:3a:90:ad:df:7e:64:86:c6:
21 | 26:72:ce:31:08:79:7e:13:15:b8:e5:bf:d6:56:02:
22 | 8d:60:21:4c:27:18:64:fb:fb:55:70:f6:33:bd:2f:
23 | 55:70:d5:5e:7e:99:ae:a4:e0:aa:45:47:13:a8:30:
24 | d5:a0:8a:9d:cc:20:ec:e4:8e:51:c9:54:c5:7f:3e:
25 | 66:2d:74:bf:a3:7a:f8:f3:ec:94:57:39:b4:ac:00:
26 | 75:62:61:54:b4:d0:e0:52:86:f8:5e:77:ec:50:43:
27 | 9c:d2:ba:a7:8c:62:5a:bc:b2:fe:f3:cc:62:7e:23:
28 | 60:6b:c7:51:49:37:78:7e:25:15:30:ab:fa:b4:ae:
29 | 25:8f:22:fc:a3:48:7f:f2:0a:8a:6e:e0:fe:8d:f0:
30 | 01:ed:c6:33:cc:6b:a1:fd:a6:80:ef:06:8c:af:f6:
31 | 40:3a:8e:42:14:20:61:12:1f:e3:fc:05:b1:05:d5:
32 | 65:c3
33 | Exponent: 65537 (0x10001)
34 | X509v3 extensions:
35 | X509v3 Basic Constraints:
36 | CA:FALSE
37 | Netscape Comment:
38 | OpenSSL Generated Certificate
39 | X509v3 Subject Key Identifier:
40 | 24:84:2C:F2:D4:59:20:62:8B:2E:5C:86:90:A3:AA:30:BA:27:1A:9C
41 | X509v3 Authority Key Identifier:
42 | keyid:B4:B9:EF:9A:E6:97:0E:68:65:1E:98:CE:FA:55:0D:89:06:DB:4C:7C
43 | DirName:/C=US/ST=California/L=Sunnyvale/O=XML Security Library (http://www.aleksey.com/xmlsec)/OU=Root Certificate/CN=Aleksey Sanin/emailAddress=xmlsec@aleksey.com
44 | serial:00
45 |
46 | Signature Algorithm: md5WithRSAEncryption
47 | b5:3f:9b:32:31:4a:ff:2f:84:3b:a8:9b:11:5c:a6:5c:f0:76:
48 | 52:d9:6e:f4:90:ad:fa:0d:90:c1:98:d5:4a:12:dd:82:6b:37:
49 | e8:d9:2d:62:92:c9:61:37:98:86:8f:a4:49:6a:5e:25:d0:18:
50 | 69:30:0f:98:8f:43:58:89:31:b2:3b:05:e2:ef:c7:a6:71:5f:
51 | f7:fe:73:c5:a7:b2:cd:2e:73:53:71:7d:a8:4c:68:1a:32:1b:
52 | 5e:48:2f:8f:9b:7a:a3:b5:f3:67:e8:b1:a2:89:4e:b2:4d:1b:
53 | 79:9c:ff:f0:0d:19:4f:4e:b1:03:3d:99:f0:44:b7:8a:0b:34:
54 | 9d:83
55 | -----BEGIN CERTIFICATE-----
56 | MIIE3zCCBEigAwIBAgIBBTANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCVVMx
57 | EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
58 | ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
59 | eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
60 | a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMB4X
61 | DTAzMDMzMTA0MDIyMloXDTEzMDMyODA0MDIyMlowgb8xCzAJBgNVBAYTAlVTMRMw
62 | EQYDVQQIEwpDYWxpZm9ybmlhMT0wOwYDVQQKEzRYTUwgU2VjdXJpdHkgTGlicmFy
63 | eSAoaHR0cDovL3d3dy5hbGVrc2V5LmNvbS94bWxzZWMpMSEwHwYDVQQLExhFeGFt
64 | cGxlcyBSU0EgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUFsZWtzZXkgU2FuaW4xITAf
65 | BgkqhkiG9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbTCCASIwDQYJKoZIhvcNAQEB
66 | BQADggEPADCCAQoCggEBAJe4/rQ/gzV4FokE7CthjL/EXwCBSkXm2c3p4jyXO0Wt
67 | quaNC3dxBwFPfPl94hmq3ZFZ9PHPPbp4RpYRnLZbRjlzVSOq954AXOXpSew7nD+E
68 | mTqQrd9+ZIbGJnLOMQh5fhMVuOW/1lYCjWAhTCcYZPv7VXD2M70vVXDVXn6ZrqTg
69 | qkVHE6gw1aCKncwg7OSOUclUxX8+Zi10v6N6+PPslFc5tKwAdWJhVLTQ4FKG+F53
70 | 7FBDnNK6p4xiWryy/vPMYn4jYGvHUUk3eH4lFTCr+rSuJY8i/KNIf/IKim7g/o3w
71 | Ae3GM8xrof2mgO8GjK/2QDqOQhQgYRIf4/wFsQXVZcMCAwEAAaOCAVcwggFTMAkG
72 | A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp
73 | ZmljYXRlMB0GA1UdDgQWBBQkhCzy1FkgYosuXIaQo6owuicanDCB+AYDVR0jBIHw
74 | MIHtgBS0ue+a5pcOaGUemM76VQ2JBttMfKGB0aSBzjCByzELMAkGA1UEBhMCVVMx
75 | EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
76 | ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
77 | eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
78 | a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggEA
79 | MA0GCSqGSIb3DQEBBAUAA4GBALU/mzIxSv8vhDuomxFcplzwdlLZbvSQrfoNkMGY
80 | 1UoS3YJrN+jZLWKSyWE3mIaPpElqXiXQGGkwD5iPQ1iJMbI7BeLvx6ZxX/f+c8Wn
81 | ss0uc1NxfahMaBoyG15IL4+beqO182fosaKJTrJNG3mc//ANGU9OsQM9mfBEt4oL
82 | NJ2D
83 | -----END CERTIFICATE-----
84 |
--------------------------------------------------------------------------------
/tests/data/rsakey.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEowIBAAKCAQEAl7j+tD+DNXgWiQTsK2GMv8RfAIFKRebZzeniPJc7Ra2q5o0L
3 | d3EHAU98+X3iGardkVn08c89unhGlhGctltGOXNVI6r3ngBc5elJ7DucP4SZOpCt
4 | 335khsYmcs4xCHl+ExW45b/WVgKNYCFMJxhk+/tVcPYzvS9VcNVefpmupOCqRUcT
5 | qDDVoIqdzCDs5I5RyVTFfz5mLXS/o3r48+yUVzm0rAB1YmFUtNDgUob4XnfsUEOc
6 | 0rqnjGJavLL+88xifiNga8dRSTd4fiUVMKv6tK4ljyL8o0h/8gqKbuD+jfAB7cYz
7 | zGuh/aaA7waMr/ZAOo5CFCBhEh/j/AWxBdVlwwIDAQABAoIBAQCAvt6DnZF9gdW9
8 | l4vAlBqXb88d4phgELCp5tmviLUnP2NSGEWuqR7Eoeru2z9NgIxblvYfazh6Ty22
9 | kmNk6rcAcTnB9oYAcVZjUj8EUuEXlTFhXPvuNpafNu3RZd59znqJP1mSu+LpQWku
10 | NZMlabHnkTLDlGf7FXtvL9/rlgV4qk3QcDVF793JFszWrtK3mnld3KHQ6cuo9iSm
11 | 0rQKtkDjeHsRell8qTQvfBsgG1q2bv8QWT45/eQrra9mMbGTr3DbnXvoeJmTj1VN
12 | XJV7tBNllxxPahlYMByJaf/Tuva5j6HWUEIfYky5ihr2z1P/fNQ2OSCM6SQHpkiG
13 | EXQDueXBAoGBAMfW7KcmToEQEcTiqfey6C1LOLoemcX0/ROUktPq/5JQJRRrT4t7
14 | XevLX0ed8sLyR5T29XQtdnuV0DJfvcJD+6ZwfOcQ+f6ZzCaNXJP97JtEt5kSWY01
15 | Ei+nphZ0RFvPb04V3qDU9dElU26GR36CRBYJyM2WQPx4v+/YyDSZH9kLAoGBAMJc
16 | ZBU8pRbIia/FFOHUlS3v5P18nVmXyOd0fvRq0ZelaQCebTZ4K9wjnCfw//yzkb2Z
17 | 0vZFNB+xVBKB0Pt6nVvnSNzxdQ8EAXVFwHtXa25FUyP2RERQgTvmajqmgWjZsDYp
18 | 6GHcK3ZhmdmscQHF/Q2Uo4scvBcheahm9IXiNskpAoGAXelEgTBhSAmTMCEMmti6
19 | fz6QQ/bJcNu2apMxhOE0hT+gjT34vaWV9481EWTKho5w0TJVGumaem1mz6VqeXaV
20 | Nhw6tiOmN91ysNNRpEJ6BGWAmjCjYNaF21s/k+HDlhmfRuTEIHSzqDuQP6pewrbY
21 | 5Dpo4SQxGfRsznvjacRj0Q0CgYBN247oBvQnDUxCkhNMZ8kersOvW5T4x9neBge5
22 | R3UQZ12Jtu0O7dK8C7PJODyDcTeHmTAuIQjBTVrdUw1xP+v7XcoNX9hBnJws6zUw
23 | 85MAiFrGxCcSqqEqaqHRPtQGOXXiLKV/ViA++tgTn4VhbXtyTkG5P1iFd45xjFSV
24 | sUm7CQKBgDn92tHxzePly1L1mK584TkVryx4cP9RFHpebnmNduGwwjnRuYipoj8y
25 | pPPAkVbbaA3f9OB2go48rN0Ft9nHdlqgh9BpIKCVtkIb1XN0K3Oa/8BW8W/GAiNG
26 | HJcsrOtIrGVRdlyJG6bDaN8T49DnhOcsqMbf+IkIvfh50VeE9L/e
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/tests/data/rsapub.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN PUBLIC KEY-----
2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl7j+tD+DNXgWiQTsK2GM
3 | v8RfAIFKRebZzeniPJc7Ra2q5o0Ld3EHAU98+X3iGardkVn08c89unhGlhGctltG
4 | OXNVI6r3ngBc5elJ7DucP4SZOpCt335khsYmcs4xCHl+ExW45b/WVgKNYCFMJxhk
5 | +/tVcPYzvS9VcNVefpmupOCqRUcTqDDVoIqdzCDs5I5RyVTFfz5mLXS/o3r48+yU
6 | Vzm0rAB1YmFUtNDgUob4XnfsUEOc0rqnjGJavLL+88xifiNga8dRSTd4fiUVMKv6
7 | tK4ljyL8o0h/8gqKbuD+jfAB7cYzzGuh/aaA7waMr/ZAOo5CFCBhEh/j/AWxBdVl
8 | wwIDAQAB
9 | -----END PUBLIC KEY-----
10 |
--------------------------------------------------------------------------------
/tests/data/sign1-in.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Hello, World!
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/tests/data/sign1-out.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Hello, World!
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | 9H/rQr2Axe9hYTV2n/tCp+3UIQQ=
19 |
20 |
21 | Mx4psIy9/UY+u8QBJRDrwQWKRaCGz0WOVftyDzAe6WHAFSjMNr7qb2ojq9kdipT8
22 | Oub5q2OQ7mzdSLiiejkrO1VeqM/90yEIGI4En6KEB6ArEzw+iq4N1wm6EptcyxXx
23 | M9StAOOa9ilWYqR9Tfx3SW1urUIuKYgUitxsONiUHBVaW6HeX51bsXoTF++4ZI+D
24 | jiPBjN4HHmr0cbJ6BXk91S27ffZIfp1Qj5nL9onFLUGbR6EFgu2luiRzQbPuM2tP
25 | XxyI7GZ8AfHnRJK28ARvBC9oi+O1ej20S79CIV7gdBxbLbFprozBHAwOEC57YgJc
26 | x+YEjSjcO7SBIR1FiUA7pw==
27 |
28 | rsakey.pem
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/tests/data/sign2-in.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Hello, World!
8 |
9 |
10 |
--------------------------------------------------------------------------------
/tests/data/sign2-out.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Hello, World!
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | HjY8ilZAIEM2tBbPn5mYO1ieIX4=
19 |
20 |
21 | SIaj/6KY3C1SmDXU2++Gm31U1xTadFp04WhBgfsJFbxrL+q7GKSKN9kfQ+UpN9+i
22 | D5fWmuavXEHe4Gw6RMaMEkq2URQo7F68+d5J/ajq8/l4n+xE6/reGScVwT6L4dEP
23 | XXVJcAi2ZnQ3O7GTNvNGCPibL9mUcyCWBFZ92Uemtc/vJFCQ7ZyKMdMfACgxOwyN
24 | T/9971oog241/2doudhonc0I/3mgPYWkZdX6yvr62mEjnG+oUZkhWYJ4ewZJ4hM4
25 | JjbFqZO+OEzDRSbw3DkmuBA/mtlx+3t13SESfEub5hqoMdVmtth/eTb64dsPdl9r
26 | 3k1ACVX9f8aHfQQdJOmLFQ==
27 |
28 | rsakey.pem
29 |
30 |
31 |
--------------------------------------------------------------------------------
/tests/data/sign3-in.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Hello, World!
8 |
9 |
10 |
--------------------------------------------------------------------------------
/tests/data/sign3-out.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Hello, World!
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | HjY8ilZAIEM2tBbPn5mYO1ieIX4=
19 |
20 |
21 | SIaj/6KY3C1SmDXU2++Gm31U1xTadFp04WhBgfsJFbxrL+q7GKSKN9kfQ+UpN9+i
22 | D5fWmuavXEHe4Gw6RMaMEkq2URQo7F68+d5J/ajq8/l4n+xE6/reGScVwT6L4dEP
23 | XXVJcAi2ZnQ3O7GTNvNGCPibL9mUcyCWBFZ92Uemtc/vJFCQ7ZyKMdMfACgxOwyN
24 | T/9971oog241/2doudhonc0I/3mgPYWkZdX6yvr62mEjnG+oUZkhWYJ4ewZJ4hM4
25 | JjbFqZO+OEzDRSbw3DkmuBA/mtlx+3t13SESfEub5hqoMdVmtth/eTb64dsPdl9r
26 | 3k1ACVX9f8aHfQQdJOmLFQ==
27 |
28 |
29 | MIIE3zCCBEigAwIBAgIBBTANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCVVMx
30 | EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
31 | ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
32 | eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
33 | a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMB4X
34 | DTAzMDMzMTA0MDIyMloXDTEzMDMyODA0MDIyMlowgb8xCzAJBgNVBAYTAlVTMRMw
35 | EQYDVQQIEwpDYWxpZm9ybmlhMT0wOwYDVQQKEzRYTUwgU2VjdXJpdHkgTGlicmFy
36 | eSAoaHR0cDovL3d3dy5hbGVrc2V5LmNvbS94bWxzZWMpMSEwHwYDVQQLExhFeGFt
37 | cGxlcyBSU0EgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUFsZWtzZXkgU2FuaW4xITAf
38 | BgkqhkiG9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbTCCASIwDQYJKoZIhvcNAQEB
39 | BQADggEPADCCAQoCggEBAJe4/rQ/gzV4FokE7CthjL/EXwCBSkXm2c3p4jyXO0Wt
40 | quaNC3dxBwFPfPl94hmq3ZFZ9PHPPbp4RpYRnLZbRjlzVSOq954AXOXpSew7nD+E
41 | mTqQrd9+ZIbGJnLOMQh5fhMVuOW/1lYCjWAhTCcYZPv7VXD2M70vVXDVXn6ZrqTg
42 | qkVHE6gw1aCKncwg7OSOUclUxX8+Zi10v6N6+PPslFc5tKwAdWJhVLTQ4FKG+F53
43 | 7FBDnNK6p4xiWryy/vPMYn4jYGvHUUk3eH4lFTCr+rSuJY8i/KNIf/IKim7g/o3w
44 | Ae3GM8xrof2mgO8GjK/2QDqOQhQgYRIf4/wFsQXVZcMCAwEAAaOCAVcwggFTMAkG
45 | A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp
46 | ZmljYXRlMB0GA1UdDgQWBBQkhCzy1FkgYosuXIaQo6owuicanDCB+AYDVR0jBIHw
47 | MIHtgBS0ue+a5pcOaGUemM76VQ2JBttMfKGB0aSBzjCByzELMAkGA1UEBhMCVVMx
48 | EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
49 | ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
50 | eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
51 | a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggEA
52 | MA0GCSqGSIb3DQEBBAUAA4GBALU/mzIxSv8vhDuomxFcplzwdlLZbvSQrfoNkMGY
53 | 1UoS3YJrN+jZLWKSyWE3mIaPpElqXiXQGGkwD5iPQ1iJMbI7BeLvx6ZxX/f+c8Wn
54 | ss0uc1NxfahMaBoyG15IL4+beqO182fosaKJTrJNG3mc//ANGU9OsQM9mfBEt4oL
55 | NJ2D
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/tests/data/sign4-in.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Hello, World!
8 |
9 |
10 |
--------------------------------------------------------------------------------
/tests/data/sign4-out.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello, World!
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | ERS7F/ifxZoyTe0mhco+HeAEKGo=
16 |
17 |
18 | G+mZNFqh9w0wIkDSbuYwvVDu7CMP8PEsw7jfwiZBC8nyF3loAtYKKAkdi6Zy3dJs
19 | tU8qKfhzvabmCjdIrGkFTdtlCNCVKDMzwogFtxEX4Oh77X6jjx4b22XNJx4AbnUG
20 | JV/EcsD+po8s5qVEXw62lRRd8cMDafbzOA/rBH96CMNgZhzxyaF9VRLa/vbt1ht2
21 | hE1KkdZCB4Y0Lv3QyeDL2jax3NFks9FUv8IqoWYQSvywdMLY2ZMiQ9UpPeVfMizi
22 | trd5zDUSD/s3hyIEs4gD5NJF3HZPD/Fe2Zw1PBPj9eLADdEzcdueyCdPJ2YioFIi
23 | 1sMW/qPDhR/DoOJwGpUxwQ==
24 |
25 |
26 | MIIE3zCCBEigAwIBAgIBBTANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCVVMx
27 | EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
28 | ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
29 | eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
30 | a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMB4X
31 | DTAzMDMzMTA0MDIyMloXDTEzMDMyODA0MDIyMlowgb8xCzAJBgNVBAYTAlVTMRMw
32 | EQYDVQQIEwpDYWxpZm9ybmlhMT0wOwYDVQQKEzRYTUwgU2VjdXJpdHkgTGlicmFy
33 | eSAoaHR0cDovL3d3dy5hbGVrc2V5LmNvbS94bWxzZWMpMSEwHwYDVQQLExhFeGFt
34 | cGxlcyBSU0EgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUFsZWtzZXkgU2FuaW4xITAf
35 | BgkqhkiG9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbTCCASIwDQYJKoZIhvcNAQEB
36 | BQADggEPADCCAQoCggEBAJe4/rQ/gzV4FokE7CthjL/EXwCBSkXm2c3p4jyXO0Wt
37 | quaNC3dxBwFPfPl94hmq3ZFZ9PHPPbp4RpYRnLZbRjlzVSOq954AXOXpSew7nD+E
38 | mTqQrd9+ZIbGJnLOMQh5fhMVuOW/1lYCjWAhTCcYZPv7VXD2M70vVXDVXn6ZrqTg
39 | qkVHE6gw1aCKncwg7OSOUclUxX8+Zi10v6N6+PPslFc5tKwAdWJhVLTQ4FKG+F53
40 | 7FBDnNK6p4xiWryy/vPMYn4jYGvHUUk3eH4lFTCr+rSuJY8i/KNIf/IKim7g/o3w
41 | Ae3GM8xrof2mgO8GjK/2QDqOQhQgYRIf4/wFsQXVZcMCAwEAAaOCAVcwggFTMAkG
42 | A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp
43 | ZmljYXRlMB0GA1UdDgQWBBQkhCzy1FkgYosuXIaQo6owuicanDCB+AYDVR0jBIHw
44 | MIHtgBS0ue+a5pcOaGUemM76VQ2JBttMfKGB0aSBzjCByzELMAkGA1UEBhMCVVMx
45 | EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
46 | ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
47 | eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
48 | a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggEA
49 | MA0GCSqGSIb3DQEBBAUAA4GBALU/mzIxSv8vhDuomxFcplzwdlLZbvSQrfoNkMGY
50 | 1UoS3YJrN+jZLWKSyWE3mIaPpElqXiXQGGkwD5iPQ1iJMbI7BeLvx6ZxX/f+c8Wn
51 | ss0uc1NxfahMaBoyG15IL4+beqO182fosaKJTrJNG3mc//ANGU9OsQM9mfBEt4oL
52 | NJ2D
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/tests/data/sign5-in.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Hello, World!
8 |
9 |
10 |
--------------------------------------------------------------------------------
/tests/data/sign5-out-xmlsec_1_2_36_to_37.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Hello, World!
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | HjY8ilZAIEM2tBbPn5mYO1ieIX4=
19 |
20 |
21 | SIaj/6KY3C1SmDXU2++Gm31U1xTadFp04WhBgfsJFbxrL+q7GKSKN9kfQ+UpN9+i
22 | D5fWmuavXEHe4Gw6RMaMEkq2URQo7F68+d5J/ajq8/l4n+xE6/reGScVwT6L4dEP
23 | XXVJcAi2ZnQ3O7GTNvNGCPibL9mUcyCWBFZ92Uemtc/vJFCQ7ZyKMdMfACgxOwyN
24 | T/9971oog241/2doudhonc0I/3mgPYWkZdX6yvr62mEjnG+oUZkhWYJ4ewZJ4hM4
25 | JjbFqZO+OEzDRSbw3DkmuBA/mtlx+3t13SESfEub5hqoMdVmtth/eTb64dsPdl9r
26 | 3k1ACVX9f8aHfQQdJOmLFQ==
27 |
28 |
29 |
30 |
31 |
32 |
33 | Test Issuer
34 | 1
35 |
36 | MIIE3zCCBEigAwIBAgIBBTANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCVVMx
37 | EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
38 | ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
39 | eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
40 | a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMB4X
41 | DTAzMDMzMTA0MDIyMloXDTEzMDMyODA0MDIyMlowgb8xCzAJBgNVBAYTAlVTMRMw
42 | EQYDVQQIEwpDYWxpZm9ybmlhMT0wOwYDVQQKEzRYTUwgU2VjdXJpdHkgTGlicmFy
43 | eSAoaHR0cDovL3d3dy5hbGVrc2V5LmNvbS94bWxzZWMpMSEwHwYDVQQLExhFeGFt
44 | cGxlcyBSU0EgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUFsZWtzZXkgU2FuaW4xITAf
45 | BgkqhkiG9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbTCCASIwDQYJKoZIhvcNAQEB
46 | BQADggEPADCCAQoCggEBAJe4/rQ/gzV4FokE7CthjL/EXwCBSkXm2c3p4jyXO0Wt
47 | quaNC3dxBwFPfPl94hmq3ZFZ9PHPPbp4RpYRnLZbRjlzVSOq954AXOXpSew7nD+E
48 | mTqQrd9+ZIbGJnLOMQh5fhMVuOW/1lYCjWAhTCcYZPv7VXD2M70vVXDVXn6ZrqTg
49 | qkVHE6gw1aCKncwg7OSOUclUxX8+Zi10v6N6+PPslFc5tKwAdWJhVLTQ4FKG+F53
50 | 7FBDnNK6p4xiWryy/vPMYn4jYGvHUUk3eH4lFTCr+rSuJY8i/KNIf/IKim7g/o3w
51 | Ae3GM8xrof2mgO8GjK/2QDqOQhQgYRIf4/wFsQXVZcMCAwEAAaOCAVcwggFTMAkG
52 | A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp
53 | ZmljYXRlMB0GA1UdDgQWBBQkhCzy1FkgYosuXIaQo6owuicanDCB+AYDVR0jBIHw
54 | MIHtgBS0ue+a5pcOaGUemM76VQ2JBttMfKGB0aSBzjCByzELMAkGA1UEBhMCVVMx
55 | EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
56 | ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
57 | eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
58 | a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggEA
59 | MA0GCSqGSIb3DQEBBAUAA4GBALU/mzIxSv8vhDuomxFcplzwdlLZbvSQrfoNkMGY
60 | 1UoS3YJrN+jZLWKSyWE3mIaPpElqXiXQGGkwD5iPQ1iJMbI7BeLvx6ZxX/f+c8Wn
61 | ss0uc1NxfahMaBoyG15IL4+beqO182fosaKJTrJNG3mc//ANGU9OsQM9mfBEt4oL
62 | NJ2D
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/tests/data/sign5-out.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Hello, World!
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | HjY8ilZAIEM2tBbPn5mYO1ieIX4=
19 |
20 |
21 | SIaj/6KY3C1SmDXU2++Gm31U1xTadFp04WhBgfsJFbxrL+q7GKSKN9kfQ+UpN9+i
22 | D5fWmuavXEHe4Gw6RMaMEkq2URQo7F68+d5J/ajq8/l4n+xE6/reGScVwT6L4dEP
23 | XXVJcAi2ZnQ3O7GTNvNGCPibL9mUcyCWBFZ92Uemtc/vJFCQ7ZyKMdMfACgxOwyN
24 | T/9971oog241/2doudhonc0I/3mgPYWkZdX6yvr62mEjnG+oUZkhWYJ4ewZJ4hM4
25 | JjbFqZO+OEzDRSbw3DkmuBA/mtlx+3t13SESfEub5hqoMdVmtth/eTb64dsPdl9r
26 | 3k1ACVX9f8aHfQQdJOmLFQ==
27 |
28 |
29 |
30 |
31 |
32 |
33 | Test Issuer
34 | 1
35 |
36 | MIIE3zCCBEigAwIBAgIBBTANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCVVMx
37 | EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
38 | ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
39 | eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
40 | a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMB4X
41 | DTAzMDMzMTA0MDIyMloXDTEzMDMyODA0MDIyMlowgb8xCzAJBgNVBAYTAlVTMRMw
42 | EQYDVQQIEwpDYWxpZm9ybmlhMT0wOwYDVQQKEzRYTUwgU2VjdXJpdHkgTGlicmFy
43 | eSAoaHR0cDovL3d3dy5hbGVrc2V5LmNvbS94bWxzZWMpMSEwHwYDVQQLExhFeGFt
44 | cGxlcyBSU0EgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUFsZWtzZXkgU2FuaW4xITAf
45 | BgkqhkiG9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbTCCASIwDQYJKoZIhvcNAQEB
46 | BQADggEPADCCAQoCggEBAJe4/rQ/gzV4FokE7CthjL/EXwCBSkXm2c3p4jyXO0Wt
47 | quaNC3dxBwFPfPl94hmq3ZFZ9PHPPbp4RpYRnLZbRjlzVSOq954AXOXpSew7nD+E
48 | mTqQrd9+ZIbGJnLOMQh5fhMVuOW/1lYCjWAhTCcYZPv7VXD2M70vVXDVXn6ZrqTg
49 | qkVHE6gw1aCKncwg7OSOUclUxX8+Zi10v6N6+PPslFc5tKwAdWJhVLTQ4FKG+F53
50 | 7FBDnNK6p4xiWryy/vPMYn4jYGvHUUk3eH4lFTCr+rSuJY8i/KNIf/IKim7g/o3w
51 | Ae3GM8xrof2mgO8GjK/2QDqOQhQgYRIf4/wFsQXVZcMCAwEAAaOCAVcwggFTMAkG
52 | A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp
53 | ZmljYXRlMB0GA1UdDgQWBBQkhCzy1FkgYosuXIaQo6owuicanDCB+AYDVR0jBIHw
54 | MIHtgBS0ue+a5pcOaGUemM76VQ2JBttMfKGB0aSBzjCByzELMAkGA1UEBhMCVVMx
55 | EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
56 | ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
57 | eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
58 | a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggEA
59 | MA0GCSqGSIb3DQEBBAUAA4GBALU/mzIxSv8vhDuomxFcplzwdlLZbvSQrfoNkMGY
60 | 1UoS3YJrN+jZLWKSyWE3mIaPpElqXiXQGGkwD5iPQ1iJMbI7BeLvx6ZxX/f+c8Wn
61 | ss0uc1NxfahMaBoyG15IL4+beqO182fosaKJTrJNG3mc//ANGU9OsQM9mfBEt4oL
62 | NJ2D
63 | emailAddress=xmlsec@aleksey.com,CN=Aleksey Sanin,OU=Examples RSA Certificate,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US
64 | JIQs8tRZIGKLLlyGkKOqMLonGpw=
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/tests/data/sign6-in.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmlsec/python-xmlsec/967754b6ec084d3ee5baa73ad256cf19f0f231de/tests/data/sign6-in.bin
--------------------------------------------------------------------------------
/tests/data/sign6-out.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmlsec/python-xmlsec/967754b6ec084d3ee5baa73ad256cf19f0f231de/tests/data/sign6-out.bin
--------------------------------------------------------------------------------
/tests/data/sign_template.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/tests/softhsm_setup.py:
--------------------------------------------------------------------------------
1 | """Testing the PKCS#11 shim layer.
2 |
3 | Heavily inspired by from https://github.com/IdentityPython/pyXMLSecurity by leifj
4 | under license "As is", see https://github.com/IdentityPython/pyXMLSecurity/blob/master/LICENSE.txt
5 | """
6 |
7 | import logging
8 | import os
9 | import shutil
10 | import subprocess
11 | import tempfile
12 | import traceback
13 | import unittest
14 |
15 | DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
16 |
17 |
18 | def paths_for_component(component: str, default_paths):
19 | env_path = os.environ.get(component)
20 | return [env_path] if env_path else default_paths
21 |
22 |
23 | def find_alts(component_name, alts) -> str:
24 | for a in alts:
25 | if os.path.exists(a):
26 | return a
27 | raise unittest.SkipTest('Required component is missing: {}'.format(component_name))
28 |
29 |
30 | def run_cmd(args, softhsm_conf=None):
31 | env = {}
32 | if softhsm_conf is not None:
33 | env['SOFTHSM_CONF'] = softhsm_conf
34 | env['SOFTHSM2_CONF'] = softhsm_conf
35 | proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
36 | out, err = proc.communicate()
37 | if err is not None and len(err) > 0:
38 | logging.error(err)
39 | if out is not None and len(out) > 0:
40 | logging.debug(out)
41 | rv = proc.wait()
42 | if rv:
43 | with open(softhsm_conf) as f:
44 | conf = f.read()
45 | msg = '[cmd: {cmd}] [code: {code}] [stdout: {out}] [stderr: {err}] [config: {conf}]'
46 | msg = msg.format(
47 | cmd=' '.join(args),
48 | code=rv,
49 | out=out.strip(),
50 | err=err.strip(),
51 | conf=conf,
52 | )
53 | raise RuntimeError(msg)
54 | return out, err
55 |
56 |
57 | component_default_paths = {
58 | 'P11_MODULE': [
59 | '/usr/lib/softhsm/libsofthsm2.so',
60 | '/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so',
61 | '/usr/lib/softhsm/libsofthsm.so',
62 | '/usr/lib64/softhsm/libsofthsm2.so',
63 | ],
64 | 'P11_ENGINE': [
65 | '/usr/lib/ssl/engines/libpkcs11.so',
66 | '/usr/lib/engines/engine_pkcs11.so',
67 | '/usr/lib/x86_64-linux-gnu/engines-1.1/pkcs11.so',
68 | '/usr/lib64/engines-1.1/pkcs11.so',
69 | '/usr/lib64/engines-1.1/libpkcs11.so',
70 | '/usr/lib64/engines-3/pkcs11.so',
71 | '/usr/lib64/engines-3/libpkcs11.so',
72 | '/usr/lib/x86_64-linux-gnu/engines-3/pkcs11.so',
73 | '/usr/lib/x86_64-linux-gnu/engines-3/libpkcs11.so',
74 | ],
75 | 'PKCS11_TOOL': [
76 | '/usr/bin/pkcs11-tool',
77 | ],
78 | 'SOFTHSM': [
79 | '/usr/bin/softhsm2-util',
80 | '/usr/bin/softhsm',
81 | ],
82 | 'OPENSSL': [
83 | '/usr/bin/openssl',
84 | ],
85 | }
86 |
87 | component_path = {
88 | component_name: find_alts(component_name, paths_for_component(component_name, default_paths))
89 | for component_name, default_paths in component_default_paths.items()
90 | }
91 |
92 | softhsm_version = 1
93 | if component_path['SOFTHSM'].endswith('softhsm2-util'):
94 | softhsm_version = 2
95 |
96 | openssl_version = subprocess.check_output([component_path['OPENSSL'], 'version'])[8:11].decode()
97 |
98 | p11_test_files = []
99 | softhsm_conf = None
100 | softhsm_db = None
101 |
102 |
103 | def _temp_file() -> str:
104 | f = tempfile.NamedTemporaryFile(delete=False)
105 | p11_test_files.append(f.name)
106 | return f.name
107 |
108 |
109 | def _temp_dir() -> str:
110 | d = tempfile.mkdtemp()
111 | p11_test_files.append(d)
112 | return d
113 |
114 |
115 | @unittest.skipIf(component_path['P11_MODULE'] is None, 'SoftHSM PKCS11 module not installed')
116 | def setup() -> None:
117 | logging.debug('Creating test pkcs11 token using softhsm')
118 | try:
119 | global softhsm_conf
120 | softhsm_conf = _temp_file()
121 | logging.debug('Generating softhsm.conf')
122 | with open(softhsm_conf, 'w') as f:
123 | if softhsm_version == 2:
124 | softhsm_db = _temp_dir()
125 | f.write(
126 | """
127 | # Generated by test
128 | directories.tokendir = {}
129 | objectstore.backend = file
130 | log.level = DEBUG
131 | """.format(
132 | softhsm_db
133 | )
134 | )
135 | else:
136 | softhsm_db = _temp_file()
137 | f.write(
138 | """
139 | # Generated by test
140 | 0:{}
141 | """.format(
142 | softhsm_db
143 | )
144 | )
145 |
146 | logging.debug('Initializing the token')
147 | out, err = run_cmd(
148 | [
149 | component_path['SOFTHSM'],
150 | '--slot',
151 | '0',
152 | '--label',
153 | 'test',
154 | '--init-token',
155 | '--pin',
156 | 'secret1',
157 | '--so-pin',
158 | 'secret2',
159 | ],
160 | softhsm_conf=softhsm_conf,
161 | )
162 |
163 | hash_priv_key = _temp_file()
164 | logging.debug('Converting test private key to format for softhsm')
165 | run_cmd(
166 | [
167 | component_path['OPENSSL'],
168 | 'pkcs8',
169 | '-topk8',
170 | '-inform',
171 | 'PEM',
172 | '-outform',
173 | 'PEM',
174 | '-nocrypt',
175 | '-in',
176 | os.path.join(DATA_DIR, 'rsakey.pem'),
177 | '-out',
178 | hash_priv_key,
179 | ],
180 | softhsm_conf=softhsm_conf,
181 | )
182 |
183 | logging.debug('Importing the test key to softhsm')
184 | run_cmd(
185 | [
186 | component_path['SOFTHSM'],
187 | '--import',
188 | hash_priv_key,
189 | '--token',
190 | 'test',
191 | '--id',
192 | 'a1b2',
193 | '--label',
194 | 'test',
195 | '--pin',
196 | 'secret1',
197 | ],
198 | softhsm_conf=softhsm_conf,
199 | )
200 | run_cmd(
201 | [
202 | component_path['PKCS11_TOOL'],
203 | '--module',
204 | component_path['P11_MODULE'],
205 | '-l',
206 | '--pin',
207 | 'secret1',
208 | '-O',
209 | ],
210 | softhsm_conf=softhsm_conf,
211 | )
212 | signer_cert_pem = _temp_file()
213 | openssl_conf = _temp_file()
214 | logging.debug('Generating OpenSSL config for version %s', openssl_version)
215 | with open(openssl_conf, 'w') as f:
216 | f.write(
217 | '\n'.join(
218 | [
219 | 'openssl_conf = openssl_def',
220 | '[openssl_def]',
221 | 'engines = engine_section',
222 | '[engine_section]',
223 | 'pkcs11 = pkcs11_section',
224 | '[req]',
225 | 'distinguished_name = req_distinguished_name',
226 | '[req_distinguished_name]',
227 | '[pkcs11_section]',
228 | 'engine_id = pkcs11',
229 | # dynamic_path,
230 | "MODULE_PATH = {}".format(component_path['P11_MODULE']),
231 | 'init = 0',
232 | ]
233 | )
234 | )
235 |
236 | with open(openssl_conf, 'r') as f:
237 | logging.debug('-------- START DEBUG openssl_conf --------')
238 | logging.debug(f.readlines())
239 | logging.debug('-------- END DEBUG openssl_conf --------')
240 | logging.debug('-------- START DEBUG paths --------')
241 | logging.debug(run_cmd(['ls', '-ld', component_path['P11_ENGINE']]))
242 | logging.debug(run_cmd(['ls', '-ld', component_path['P11_MODULE']]))
243 | logging.debug('-------- END DEBUG paths --------')
244 |
245 | signer_cert_der = _temp_file()
246 |
247 | logging.debug('Generating self-signed certificate')
248 | run_cmd(
249 | [
250 | component_path['OPENSSL'],
251 | 'req',
252 | '-new',
253 | '-x509',
254 | '-subj',
255 | '/CN=Test Signer',
256 | '-engine',
257 | 'pkcs11',
258 | '-config',
259 | openssl_conf,
260 | '-keyform',
261 | 'engine',
262 | '-key',
263 | 'label_test',
264 | '-passin',
265 | 'pass:secret1',
266 | '-out',
267 | signer_cert_pem,
268 | ],
269 | softhsm_conf=softhsm_conf,
270 | )
271 |
272 | run_cmd(
273 | [
274 | component_path['OPENSSL'],
275 | 'x509',
276 | '-inform',
277 | 'PEM',
278 | '-outform',
279 | 'DER',
280 | '-in',
281 | signer_cert_pem,
282 | '-out',
283 | signer_cert_der,
284 | ],
285 | softhsm_conf=softhsm_conf,
286 | )
287 |
288 | logging.debug('Importing certificate into token')
289 |
290 | run_cmd(
291 | [
292 | component_path['PKCS11_TOOL'],
293 | '--module',
294 | component_path['P11_MODULE'],
295 | '-l',
296 | '--slot-index',
297 | '0',
298 | '--id',
299 | 'a1b2',
300 | '--label',
301 | 'test',
302 | '-y',
303 | 'cert',
304 | '-w',
305 | signer_cert_der,
306 | '--pin',
307 | 'secret1',
308 | ],
309 | softhsm_conf=softhsm_conf,
310 | )
311 |
312 | # TODO: Should be teardowned in teardown # noqa: T101
313 | os.environ['SOFTHSM_CONF'] = softhsm_conf
314 | os.environ['SOFTHSM2_CONF'] = softhsm_conf
315 |
316 | except Exception as ex:
317 | print('-' * 64)
318 | traceback.print_exc()
319 | print('-' * 64)
320 | logging.exception('PKCS11 tests disabled: unable to initialize test token')
321 | raise ex
322 |
323 |
324 | def teardown() -> None:
325 | global p11_test_files
326 | for o in p11_test_files:
327 | if os.path.exists(o):
328 | if os.path.isdir(o):
329 | shutil.rmtree(o)
330 | else:
331 | os.unlink(o)
332 | p11_test_files = []
333 |
--------------------------------------------------------------------------------
/tests/test_constants.py:
--------------------------------------------------------------------------------
1 | """Test constants from :mod:`xmlsec.constants` module."""
2 |
3 | import pytest
4 |
5 | import xmlsec
6 |
7 |
8 | def _constants(typename):
9 | return list(
10 | sorted(
11 | (
12 | getattr(xmlsec.constants, name)
13 | for name in dir(xmlsec.constants)
14 | if type(getattr(xmlsec.constants, name)).__name__ == typename
15 | ),
16 | key=lambda t: t.name.lower(),
17 | )
18 | )
19 |
20 |
21 | @pytest.mark.parametrize('transform', _constants('__Transform'), ids=repr)
22 | def test_transform_str(transform):
23 | """Test string representation of ``xmlsec.constants.__Transform``."""
24 | assert str(transform) == '{}, {}'.format(transform.name, transform.href)
25 |
26 |
27 | @pytest.mark.parametrize('transform', _constants('__Transform'), ids=repr)
28 | def test_transform_repr(transform):
29 | """Test raw string representation of ``xmlsec.constants.__Transform``."""
30 | assert repr(transform) == '__Transform({!r}, {!r}, {})'.format(transform.name, transform.href, transform.usage)
31 |
32 |
33 | @pytest.mark.parametrize('keydata', _constants('__KeyData'), ids=repr)
34 | def test_keydata_str(keydata):
35 | """Test string representation of ``xmlsec.constants.__KeyData``."""
36 | assert str(keydata) == '{}, {}'.format(keydata.name, keydata.href)
37 |
38 |
39 | @pytest.mark.parametrize('keydata', _constants('__KeyData'), ids=repr)
40 | def test_keydata_repr(keydata):
41 | """Test raw string representation of ``xmlsec.constants.__KeyData``."""
42 | assert repr(keydata) == '__KeyData({!r}, {!r})'.format(keydata.name, keydata.href)
43 |
--------------------------------------------------------------------------------
/tests/test_doc_examples.py:
--------------------------------------------------------------------------------
1 | """Run tests over code examples in the documentation."""
2 |
3 | import contextlib
4 | import os
5 | import runpy
6 | import sys
7 |
8 | import pytest
9 |
10 | if sys.version_info >= (3, 4):
11 | from pathlib import Path
12 | else: # python2.7 compat
13 | from _pytest.pathlib import Path
14 |
15 |
16 | examples_dir = Path(__file__, '../../doc/source/examples').resolve()
17 | examples = sorted(examples_dir.glob('*.py'))
18 |
19 |
20 | @contextlib.contextmanager
21 | def cd(where_to):
22 | """
23 | Temporarily change the working directory.
24 |
25 | Restore the current working dir after exiting the context.
26 | """
27 | curr = Path.cwd()
28 | try:
29 | os.chdir(str(where_to))
30 | yield
31 | finally:
32 | os.chdir(str(curr))
33 |
34 |
35 | @pytest.mark.parametrize('example', examples, ids=lambda p: p.name)
36 | def test_doc_example(example):
37 | """
38 | Verify example scripts included in the docs are up to date.
39 |
40 | Execute each script in :file:`docs/source/examples`,
41 | not raising any errors is good enough.
42 | """
43 | with cd(example.parent):
44 | runpy.run_path(str(example))
45 |
--------------------------------------------------------------------------------
/tests/test_enc.py:
--------------------------------------------------------------------------------
1 | import tempfile
2 |
3 | from lxml import etree
4 |
5 | import xmlsec
6 | from tests import base
7 |
8 | consts = xmlsec.constants
9 |
10 |
11 | class TestEncryptionContext(base.TestMemoryLeaks):
12 | def test_init(self):
13 | ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager())
14 | del ctx
15 |
16 | def test_init_no_keys_manager(self):
17 | ctx = xmlsec.EncryptionContext()
18 | del ctx
19 |
20 | def test_init_bad_args(self):
21 | with self.assertRaisesRegex(TypeError, 'KeysManager required'):
22 | xmlsec.EncryptionContext(manager='foo')
23 |
24 | def test_no_key(self):
25 | ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager())
26 | self.assertIsNone(ctx.key)
27 |
28 | def test_get_key(self):
29 | ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager())
30 | self.assertIsNone(ctx.key)
31 | ctx.key = xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem)
32 | self.assertIsNotNone(ctx.key)
33 |
34 | def test_del_key(self):
35 | ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager())
36 | ctx.key = xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem)
37 | del ctx.key
38 | self.assertIsNone(ctx.key)
39 |
40 | def test_set_key(self):
41 | ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager())
42 | ctx.key = xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem)
43 | self.assertIsNotNone(ctx.key)
44 |
45 | def test_set_key_bad_type(self):
46 | ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager())
47 | with self.assertRaisesRegex(TypeError, r'instance of \*xmlsec.Key\* expected.'):
48 | ctx.key = ''
49 |
50 | def test_set_invalid_key(self):
51 | ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager())
52 | with self.assertRaisesRegex(TypeError, 'empty key.'):
53 | ctx.key = xmlsec.Key()
54 |
55 | def test_encrypt_xml(self):
56 | root = self.load_xml('enc1-in.xml')
57 | enc_data = xmlsec.template.encrypted_data_create(root, consts.TransformAes128Cbc, type=consts.TypeEncElement, ns="xenc")
58 | xmlsec.template.encrypted_data_ensure_cipher_value(enc_data)
59 | ki = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig")
60 | ek = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep)
61 | xmlsec.template.encrypted_data_ensure_cipher_value(ek)
62 | data = root.find('./Data')
63 | self.assertIsNotNone(data)
64 |
65 | manager = xmlsec.KeysManager()
66 | manager.add_key(xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem))
67 |
68 | ctx = xmlsec.EncryptionContext(manager)
69 | ctx.key = xmlsec.Key.generate(consts.KeyDataAes, 128, consts.KeyDataTypeSession)
70 |
71 | encrypted = ctx.encrypt_xml(enc_data, data)
72 | self.assertIsNotNone(encrypted)
73 |
74 | enc_method = xmlsec.tree.find_child(enc_data, consts.NodeEncryptionMethod, consts.EncNs)
75 | self.assertIsNotNone(enc_method)
76 | self.assertEqual("http://www.w3.org/2001/04/xmlenc#aes128-cbc", enc_method.get("Algorithm"))
77 | ki = xmlsec.tree.find_child(enc_data, consts.NodeKeyInfo, consts.DSigNs)
78 | self.assertIsNotNone(ki)
79 | enc_method2 = xmlsec.tree.find_node(ki, consts.NodeEncryptionMethod, consts.EncNs)
80 | self.assertIsNotNone(enc_method2)
81 | self.assertEqual("http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p", enc_method2.get("Algorithm"))
82 | cipher_value = xmlsec.tree.find_node(ki, consts.NodeCipherValue, consts.EncNs)
83 | self.assertIsNotNone(cipher_value)
84 |
85 | def test_encrypt_xml_bad_args(self):
86 | ctx = xmlsec.EncryptionContext()
87 | with self.assertRaises(TypeError):
88 | ctx.encrypt_xml('', 0)
89 |
90 | def test_encrypt_xml_bad_template(self):
91 | ctx = xmlsec.EncryptionContext()
92 | with self.assertRaisesRegex(xmlsec.Error, 'unsupported `Type`, it should be `element` or `content`'):
93 | ctx.encrypt_xml(etree.Element('root'), etree.Element('node'))
94 |
95 | def test_encrypt_xml_bad_template_bad_type_attribute(self):
96 | ctx = xmlsec.EncryptionContext()
97 | with self.assertRaisesRegex(xmlsec.Error, 'unsupported `Type`, it should be `element` or `content`'):
98 | root = etree.Element('root')
99 | root.attrib['Type'] = 'foo'
100 | ctx.encrypt_xml(root, etree.Element('node'))
101 |
102 | def test_encrypt_xml_fail(self):
103 | ctx = xmlsec.EncryptionContext()
104 | with self.assertRaisesRegex(xmlsec.Error, 'failed to encrypt xml'):
105 | root = etree.Element('root')
106 | root.attrib['Type'] = consts.TypeEncElement
107 | ctx.encrypt_xml(root, etree.Element('node'))
108 |
109 | def test_encrypt_binary(self):
110 | root = self.load_xml('enc2-in.xml')
111 | enc_data = xmlsec.template.encrypted_data_create(
112 | root, consts.TransformAes128Cbc, type=consts.TypeEncContent, ns="xenc", mime_type="binary/octet-stream"
113 | )
114 | xmlsec.template.encrypted_data_ensure_cipher_value(enc_data)
115 | ki = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig")
116 | ek = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep)
117 | xmlsec.template.encrypted_data_ensure_cipher_value(ek)
118 |
119 | manager = xmlsec.KeysManager()
120 | manager.add_key(xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem))
121 |
122 | ctx = xmlsec.EncryptionContext(manager)
123 | ctx.key = xmlsec.Key.generate(consts.KeyDataAes, 128, consts.KeyDataTypeSession)
124 |
125 | encrypted = ctx.encrypt_binary(enc_data, b'test')
126 | self.assertIsNotNone(encrypted)
127 | self.assertEqual("{{{}}}{}".format(consts.EncNs, consts.NodeEncryptedData), encrypted.tag)
128 |
129 | enc_method = xmlsec.tree.find_child(enc_data, consts.NodeEncryptionMethod, consts.EncNs)
130 | self.assertIsNotNone(enc_method)
131 | self.assertEqual("http://www.w3.org/2001/04/xmlenc#aes128-cbc", enc_method.get("Algorithm"))
132 |
133 | ki = xmlsec.tree.find_child(enc_data, consts.NodeKeyInfo, consts.DSigNs)
134 | self.assertIsNotNone(ki)
135 | enc_method2 = xmlsec.tree.find_node(ki, consts.NodeEncryptionMethod, consts.EncNs)
136 | self.assertIsNotNone(enc_method2)
137 | self.assertEqual("http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p", enc_method2.get("Algorithm"))
138 | cipher_value = xmlsec.tree.find_node(ki, consts.NodeCipherValue, consts.EncNs)
139 | self.assertIsNotNone(cipher_value)
140 |
141 | def test_encrypt_binary_bad_args(self):
142 | ctx = xmlsec.EncryptionContext()
143 | with self.assertRaises(TypeError):
144 | ctx.encrypt_binary('', 0)
145 |
146 | def test_encrypt_binary_bad_template(self):
147 | ctx = xmlsec.EncryptionContext()
148 | with self.assertRaisesRegex(xmlsec.Error, 'failed to encrypt binary'):
149 | ctx.encrypt_binary(etree.Element('root'), b'data')
150 |
151 | def test_encrypt_uri(self):
152 | root = self.load_xml('enc2-in.xml')
153 | enc_data = xmlsec.template.encrypted_data_create(
154 | root, consts.TransformAes128Cbc, type=consts.TypeEncContent, ns="xenc", mime_type="binary/octet-stream"
155 | )
156 | xmlsec.template.encrypted_data_ensure_cipher_value(enc_data)
157 | ki = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig")
158 | ek = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep)
159 | xmlsec.template.encrypted_data_ensure_cipher_value(ek)
160 |
161 | manager = xmlsec.KeysManager()
162 | manager.add_key(xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem))
163 |
164 | ctx = xmlsec.EncryptionContext(manager)
165 | ctx.key = xmlsec.Key.generate(consts.KeyDataAes, 128, consts.KeyDataTypeSession)
166 |
167 | with tempfile.NamedTemporaryFile(delete=False) as tmpfile:
168 | tmpfile.write(b'test')
169 |
170 | encrypted = ctx.encrypt_binary(enc_data, 'file://' + tmpfile.name)
171 | self.assertIsNotNone(encrypted)
172 | self.assertEqual("{{{}}}{}".format(consts.EncNs, consts.NodeEncryptedData), encrypted.tag)
173 |
174 | enc_method = xmlsec.tree.find_child(enc_data, consts.NodeEncryptionMethod, consts.EncNs)
175 | self.assertIsNotNone(enc_method)
176 | self.assertEqual("http://www.w3.org/2001/04/xmlenc#aes128-cbc", enc_method.get("Algorithm"))
177 |
178 | ki = xmlsec.tree.find_child(enc_data, consts.NodeKeyInfo, consts.DSigNs)
179 | self.assertIsNotNone(ki)
180 | enc_method2 = xmlsec.tree.find_node(ki, consts.NodeEncryptionMethod, consts.EncNs)
181 | self.assertIsNotNone(enc_method2)
182 | self.assertEqual("http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p", enc_method2.get("Algorithm"))
183 | cipher_value = xmlsec.tree.find_node(ki, consts.NodeCipherValue, consts.EncNs)
184 | self.assertIsNotNone(cipher_value)
185 |
186 | def test_encrypt_uri_bad_args(self):
187 | ctx = xmlsec.EncryptionContext()
188 | with self.assertRaises(TypeError):
189 | ctx.encrypt_uri('', 0)
190 |
191 | def test_encrypt_uri_fail(self):
192 | ctx = xmlsec.EncryptionContext()
193 | with self.assertRaisesRegex(xmlsec.Error, 'failed to encrypt URI'):
194 | ctx.encrypt_uri(etree.Element('root'), '')
195 |
196 | def test_decrypt1(self):
197 | self.check_decrypt(1)
198 |
199 | def test_decrypt2(self):
200 | self.check_decrypt(2)
201 |
202 | def test_decrypt_key(self):
203 | root = self.load_xml('enc3-out.xml')
204 | enc_key = xmlsec.tree.find_child(root, consts.NodeEncryptedKey, consts.EncNs)
205 | self.assertIsNotNone(enc_key)
206 |
207 | manager = xmlsec.KeysManager()
208 | manager.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem))
209 | ctx = xmlsec.EncryptionContext(manager)
210 | keydata = ctx.decrypt(enc_key)
211 | ctx.reset()
212 | root.remove(enc_key)
213 | ctx.key = xmlsec.Key.from_binary_data(consts.KeyDataAes, keydata)
214 | enc_data = xmlsec.tree.find_child(root, consts.NodeEncryptedData, consts.EncNs)
215 | self.assertIsNotNone(enc_data)
216 | decrypted = ctx.decrypt(enc_data)
217 | self.assertIsNotNone(decrypted)
218 | self.assertEqual(self.load_xml("enc3-in.xml"), decrypted)
219 |
220 | def check_decrypt(self, i):
221 | root = self.load_xml('enc{}-out.xml'.format(i))
222 | enc_data = xmlsec.tree.find_child(root, consts.NodeEncryptedData, consts.EncNs)
223 | self.assertIsNotNone(enc_data)
224 |
225 | manager = xmlsec.KeysManager()
226 | manager.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem))
227 | ctx = xmlsec.EncryptionContext(manager)
228 | decrypted = ctx.decrypt(enc_data)
229 | self.assertIsNotNone(decrypted)
230 | self.assertEqual(self.load_xml("enc{}-in.xml".format(i)), root)
231 |
232 | def test_decrypt_bad_args(self):
233 | ctx = xmlsec.EncryptionContext()
234 | with self.assertRaises(TypeError):
235 | ctx.decrypt('')
236 |
--------------------------------------------------------------------------------
/tests/test_keys.py:
--------------------------------------------------------------------------------
1 | import copy
2 | import tempfile
3 |
4 | import xmlsec
5 | from tests import base
6 |
7 | consts = xmlsec.constants
8 |
9 |
10 | class TestKeys(base.TestMemoryLeaks):
11 | def test_key_from_memory(self):
12 | key = xmlsec.Key.from_memory(self.load("rsakey.pem"), format=consts.KeyDataFormatPem)
13 | self.assertIsNotNone(key)
14 |
15 | def test_key_from_memory_with_bad_args(self):
16 | with self.assertRaises(TypeError):
17 | xmlsec.Key.from_memory(1, format="")
18 |
19 | def test_key_from_memory_invalid_data(self):
20 | with self.assertRaisesRegex(xmlsec.Error, '.*cannot load key.*'):
21 | xmlsec.Key.from_memory(b'foo', format=consts.KeyDataFormatPem)
22 |
23 | def test_key_from_file(self):
24 | key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
25 | self.assertIsNotNone(key)
26 |
27 | def test_key_from_file_with_bad_args(self):
28 | with self.assertRaises(TypeError):
29 | xmlsec.Key.from_file(1, format="")
30 |
31 | def test_key_from_invalid_file(self):
32 | with self.assertRaisesRegex(xmlsec.Error, '.*cannot read key.*'):
33 | with tempfile.NamedTemporaryFile() as tmpfile:
34 | tmpfile.write(b'foo')
35 | xmlsec.Key.from_file(tmpfile.name, format=consts.KeyDataFormatPem)
36 |
37 | def test_key_from_fileobj(self):
38 | with open(self.path("rsakey.pem"), "rb") as fobj:
39 | key = xmlsec.Key.from_file(fobj, format=consts.KeyDataFormatPem)
40 | self.assertIsNotNone(key)
41 |
42 | def test_key_from_invalid_fileobj(self):
43 | with tempfile.NamedTemporaryFile(delete=False) as tmpfile:
44 | tmpfile.write(b'foo')
45 | with self.assertRaisesRegex(xmlsec.Error, '.*cannot read key.*'), open(tmpfile.name) as fp:
46 | xmlsec.Key.from_file(fp, format=consts.KeyDataFormatPem)
47 |
48 | def test_generate(self):
49 | key = xmlsec.Key.generate(klass=consts.KeyDataAes, size=256, type=consts.KeyDataTypeSession)
50 | self.assertIsNotNone(key)
51 |
52 | def test_generate_with_bad_args(self):
53 | with self.assertRaises(TypeError):
54 | xmlsec.Key.generate(klass="", size="", type="")
55 |
56 | def test_generate_invalid_size(self):
57 | with self.assertRaisesRegex(xmlsec.Error, '.*cannot generate key.*'):
58 | xmlsec.Key.generate(klass=consts.KeyDataAes, size=0, type=consts.KeyDataTypeSession)
59 |
60 | def test_from_binary_file(self):
61 | key = xmlsec.Key.from_binary_file(klass=consts.KeyDataDes, filename=self.path("deskey.bin"))
62 | self.assertIsNotNone(key)
63 |
64 | def test_from_binary_file_with_bad_args(self):
65 | with self.assertRaises(TypeError):
66 | xmlsec.Key.from_binary_file(klass="", filename=1)
67 |
68 | def test_from_invalid_binary_file(self):
69 | with self.assertRaisesRegex(xmlsec.Error, '.*cannot read key.*'):
70 | with tempfile.NamedTemporaryFile() as tmpfile:
71 | tmpfile.write(b'foo')
72 | xmlsec.Key.from_binary_file(klass=consts.KeyDataDes, filename=tmpfile.name)
73 |
74 | def test_from_binary_data(self):
75 | key = xmlsec.Key.from_binary_data(klass=consts.KeyDataDes, data=self.load("deskey.bin"))
76 | self.assertIsNotNone(key)
77 |
78 | def test_from_binary_data_with_bad_args(self):
79 | with self.assertRaises(TypeError):
80 | xmlsec.Key.from_binary_data(klass="", data=1)
81 |
82 | def test_from_invalid_binary_data(self):
83 | with self.assertRaisesRegex(xmlsec.Error, '.*cannot read key.*'):
84 | xmlsec.Key.from_binary_data(klass=consts.KeyDataDes, data=b'')
85 |
86 | def test_load_cert_from_file(self):
87 | key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
88 | self.assertIsNotNone(key)
89 | key.load_cert_from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatPem)
90 |
91 | def test_load_cert_from_file_with_bad_args(self):
92 | key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
93 | self.assertIsNotNone(key)
94 | with self.assertRaises(TypeError):
95 | key.load_cert_from_file(1, format="")
96 |
97 | def test_load_cert_from_invalid_file(self):
98 | key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
99 | self.assertIsNotNone(key)
100 | with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'):
101 | with tempfile.NamedTemporaryFile() as tmpfile:
102 | tmpfile.write(b'foo')
103 | key.load_cert_from_file(tmpfile.name, format=consts.KeyDataFormatPem)
104 |
105 | def test_load_cert_from_fileobj(self):
106 | key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
107 | self.assertIsNotNone(key)
108 | with open(self.path("rsacert.pem"), "rb") as fobj:
109 | key.load_cert_from_file(fobj, format=consts.KeyDataFormatPem)
110 |
111 | def test_load_cert_from_fileobj_with_bad_args(self):
112 | key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
113 | self.assertIsNotNone(key)
114 | with self.assertRaises(TypeError), open(self.path("rsacert.pem"), "rb") as fobj:
115 | key.load_cert_from_file(fobj, format='')
116 |
117 | def test_load_cert_from_invalid_fileobj(self):
118 | key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
119 | self.assertIsNotNone(key)
120 | with tempfile.NamedTemporaryFile(delete=False) as tmpfile:
121 | tmpfile.write(b'foo')
122 | with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'), open(tmpfile.name) as fp:
123 | key.load_cert_from_file(fp, format=consts.KeyDataFormatPem)
124 |
125 | def test_load_cert_from_memory(self):
126 | key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
127 | self.assertIsNotNone(key)
128 | key.load_cert_from_memory(self.load("rsacert.pem"), format=consts.KeyDataFormatPem)
129 |
130 | def test_load_cert_from_memory_with_bad_args(self):
131 | key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
132 | self.assertIsNotNone(key)
133 | with self.assertRaises(TypeError):
134 | key.load_cert_from_memory(1, format="")
135 |
136 | def test_load_cert_from_memory_invalid_data(self):
137 | key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
138 | self.assertIsNotNone(key)
139 | with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'):
140 | key.load_cert_from_memory(b'', format=consts.KeyDataFormatPem)
141 |
142 | def test_get_name(self):
143 | key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
144 | self.assertIsNone(key.name)
145 |
146 | def test_get_name_invalid_key(self):
147 | key = xmlsec.Key()
148 | with self.assertRaisesRegex(ValueError, 'key is not ready'):
149 | key.name
150 |
151 | def test_del_name(self):
152 | key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
153 | key.name = "rsakey"
154 | del key.name
155 | self.assertIsNone(key.name)
156 |
157 | def test_set_name(self):
158 | key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
159 | key.name = "rsakey"
160 | self.assertEqual("rsakey", key.name)
161 |
162 | def test_set_name_invalid_key(self):
163 | key = xmlsec.Key()
164 | with self.assertRaisesRegex(ValueError, 'key is not ready'):
165 | key.name = 'foo'
166 |
167 | def test_copy(self):
168 | key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
169 | key2 = copy.copy(key)
170 | del key
171 | key2.load_cert_from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatPem)
172 |
173 |
174 | class TestKeysManager(base.TestMemoryLeaks):
175 | def test_add_key(self):
176 | key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
177 | mngr = xmlsec.KeysManager()
178 | mngr.add_key(key)
179 |
180 | def test_add_key_with_bad_args(self):
181 | mngr = xmlsec.KeysManager()
182 | with self.assertRaises(TypeError):
183 | mngr.add_key("")
184 |
185 | def test_load_cert(self):
186 | mngr = xmlsec.KeysManager()
187 | mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem))
188 | mngr.load_cert(self.path("rsacert.pem"), format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted)
189 |
190 | def test_load_cert_with_bad_args(self):
191 | mngr = xmlsec.KeysManager()
192 | mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem))
193 | with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'):
194 | with tempfile.NamedTemporaryFile() as tmpfile:
195 | tmpfile.write(b'foo')
196 | mngr.load_cert(tmpfile.name, format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted)
197 |
198 | def test_load_invalid_cert(self):
199 | mngr = xmlsec.KeysManager()
200 | mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem))
201 | with self.assertRaises(TypeError):
202 | mngr.load_cert(1, format="", type="")
203 |
204 | def test_load_cert_from_memory(self):
205 | mngr = xmlsec.KeysManager()
206 | mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem))
207 | mngr.load_cert_from_memory(self.load("rsacert.pem"), format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted)
208 |
209 | def test_load_cert_from_memory_with_bad_args(self):
210 | mngr = xmlsec.KeysManager()
211 | mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem))
212 | with self.assertRaises(TypeError):
213 | mngr.load_cert_from_memory(1, format="", type="")
214 |
215 | def test_load_cert_from_memory_invalid_data(self):
216 | mngr = xmlsec.KeysManager()
217 | mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem))
218 | with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'):
219 | mngr.load_cert_from_memory(b'', format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted)
220 |
221 | def test_load_invalid_key(self):
222 | mngr = xmlsec.KeysManager()
223 | with self.assertRaises(ValueError):
224 | mngr.add_key(xmlsec.Key())
225 |
--------------------------------------------------------------------------------
/tests/test_main.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from io import BytesIO
3 | from unittest import skipIf
4 |
5 | import xmlsec
6 | from tests import base
7 | from xmlsec import constants as consts
8 |
9 |
10 | class TestBase64LineSize(base.TestMemoryLeaks):
11 | def tearDown(self):
12 | xmlsec.base64_default_line_size(64)
13 | super(TestBase64LineSize, self).tearDown()
14 |
15 | def test_get_base64_default_line_size(self):
16 | self.assertEqual(xmlsec.base64_default_line_size(), 64)
17 |
18 | def test_set_base64_default_line_size_positional_arg(self):
19 | xmlsec.base64_default_line_size(0)
20 | self.assertEqual(xmlsec.base64_default_line_size(), 0)
21 |
22 | def test_set_base64_default_line_size_keyword_arg(self):
23 | xmlsec.base64_default_line_size(size=0)
24 | self.assertEqual(xmlsec.base64_default_line_size(), 0)
25 |
26 | def test_set_base64_default_line_size_with_bad_args(self):
27 | size = xmlsec.base64_default_line_size()
28 | for bad_size in (None, '', object()):
29 | with self.assertRaises(TypeError):
30 | xmlsec.base64_default_line_size(bad_size)
31 | self.assertEqual(xmlsec.base64_default_line_size(), size)
32 |
33 | def test_set_base64_default_line_size_rejects_negative_values(self):
34 | size = xmlsec.base64_default_line_size()
35 | with self.assertRaises(ValueError):
36 | xmlsec.base64_default_line_size(-1)
37 | self.assertEqual(xmlsec.base64_default_line_size(), size)
38 |
39 |
40 | class TestCallbacks(base.TestMemoryLeaks):
41 | def setUp(self):
42 | super().setUp()
43 | xmlsec.cleanup_callbacks()
44 |
45 | def _sign_doc(self):
46 | root = self.load_xml("doc.xml")
47 | sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1)
48 | xmlsec.template.add_reference(sign, consts.TransformSha1, uri="cid:123456")
49 |
50 | ctx = xmlsec.SignatureContext()
51 | ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)
52 | ctx.sign(sign)
53 | return sign
54 |
55 | def _expect_sign_failure(self):
56 | with self.assertRaisesRegex(xmlsec.Error, 'failed to sign'):
57 | self._sign_doc()
58 |
59 | def _mismatch_callbacks(self, match_cb=lambda filename: False):
60 | return [
61 | match_cb,
62 | lambda filename: None,
63 | lambda none, buf: 0,
64 | lambda none: None,
65 | ]
66 |
67 | def _register_mismatch_callbacks(self, match_cb=lambda filename: False):
68 | xmlsec.register_callbacks(*self._mismatch_callbacks(match_cb))
69 |
70 | def _register_match_callbacks(self):
71 | xmlsec.register_callbacks(
72 | lambda filename: filename == b'cid:123456',
73 | lambda filename: BytesIO(b''),
74 | lambda bio, buf: bio.readinto(buf),
75 | lambda bio: bio.close(),
76 | )
77 |
78 | def _find(self, elem, *tags):
79 | try:
80 | return elem.xpath(
81 | './' + '/'.join('xmldsig:{}'.format(tag) for tag in tags),
82 | namespaces={
83 | 'xmldsig': 'http://www.w3.org/2000/09/xmldsig#',
84 | },
85 | )[0]
86 | except IndexError as e:
87 | raise KeyError(tags) from e
88 |
89 | def _verify_external_data_signature(self):
90 | signature = self._sign_doc()
91 | digest = self._find(signature, 'SignedInfo', 'Reference', 'DigestValue').text
92 | self.assertEqual(digest, 'VihZwVMGJ48NsNl7ertVHiURXk8=')
93 |
94 | def test_sign_external_data_no_callbacks_fails(self):
95 | self._expect_sign_failure()
96 |
97 | def test_sign_external_data_default_callbacks_fails(self):
98 | xmlsec.register_default_callbacks()
99 | self._expect_sign_failure()
100 |
101 | def test_sign_external_data_no_matching_callbacks_fails(self):
102 | self._register_mismatch_callbacks()
103 | self._expect_sign_failure()
104 |
105 | def test_sign_data_from_callbacks(self):
106 | self._register_match_callbacks()
107 | self._verify_external_data_signature()
108 |
109 | def test_sign_data_not_first_callback(self):
110 | bad_match_calls = 0
111 |
112 | def match_cb(filename):
113 | nonlocal bad_match_calls
114 | bad_match_calls += 1
115 | return False
116 |
117 | for _ in range(2):
118 | self._register_mismatch_callbacks(match_cb)
119 |
120 | self._register_match_callbacks()
121 |
122 | for _ in range(2):
123 | self._register_mismatch_callbacks()
124 |
125 | self._verify_external_data_signature()
126 | self.assertEqual(bad_match_calls, 0)
127 |
128 | @skipIf(sys.platform == "win32", "unclear behaviour on windows")
129 | def test_failed_sign_because_default_callbacks(self):
130 | mismatch_calls = 0
131 |
132 | def mismatch_cb(filename):
133 | nonlocal mismatch_calls
134 | mismatch_calls += 1
135 | return False
136 |
137 | # NB: These first two sets of callbacks should never get called,
138 | # because the default callbacks always match beforehand:
139 | self._register_match_callbacks()
140 | self._register_mismatch_callbacks(mismatch_cb)
141 | xmlsec.register_default_callbacks()
142 | self._register_mismatch_callbacks(mismatch_cb)
143 | self._register_mismatch_callbacks(mismatch_cb)
144 | self._expect_sign_failure()
145 | self.assertEqual(mismatch_calls, 2)
146 |
147 | def test_register_non_callables(self):
148 | for idx in range(4):
149 | cbs = self._mismatch_callbacks()
150 | cbs[idx] = None
151 | self.assertRaises(TypeError, xmlsec.register_callbacks, *cbs)
152 |
153 | def test_sign_external_data_fails_on_read_callback_wrong_returns(self):
154 | xmlsec.register_callbacks(
155 | lambda filename: filename == b'cid:123456',
156 | lambda filename: BytesIO(b''),
157 | lambda bio, buf: None,
158 | lambda bio: bio.close(),
159 | )
160 | self._expect_sign_failure()
161 |
--------------------------------------------------------------------------------
/tests/test_pkcs11.py:
--------------------------------------------------------------------------------
1 | import xmlsec
2 | from tests import base
3 | from xmlsec import constants as consts
4 |
5 | KEY_URL = "pkcs11;pkcs11:token=test;object=test;pin-value=secret1"
6 |
7 |
8 | def setUpModule():
9 | from tests import softhsm_setup
10 |
11 | softhsm_setup.setup()
12 |
13 |
14 | def tearDownModule():
15 | from tests import softhsm_setup
16 |
17 | softhsm_setup.teardown()
18 |
19 |
20 | class TestKeys(base.TestMemoryLeaks):
21 | def test_del_key(self):
22 | ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager())
23 | ctx.key = xmlsec.Key.from_engine(KEY_URL)
24 | del ctx.key
25 | self.assertIsNone(ctx.key)
26 |
27 | def test_set_key(self):
28 | ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager())
29 | ctx.key = xmlsec.Key.from_engine(KEY_URL)
30 | self.assertIsNotNone(ctx.key)
31 |
32 | def test_sign_bad_args(self):
33 | ctx = xmlsec.SignatureContext()
34 | ctx.key = xmlsec.Key.from_engine(KEY_URL)
35 | with self.assertRaises(TypeError):
36 | ctx.sign('')
37 |
38 | def test_sign_fail(self):
39 | ctx = xmlsec.SignatureContext()
40 | ctx.key = xmlsec.Key.from_engine(KEY_URL)
41 | with self.assertRaisesRegex(xmlsec.Error, 'failed to sign'):
42 | ctx.sign(self.load_xml('sign1-in.xml'))
43 |
44 | def test_sign_case1(self):
45 | """Should sign a pre-constructed template file using a key from a pkcs11 engine."""
46 | root = self.load_xml("sign1-in.xml")
47 | sign = xmlsec.tree.find_node(root, consts.NodeSignature)
48 | self.assertIsNotNone(sign)
49 |
50 | ctx = xmlsec.SignatureContext()
51 | ctx.key = xmlsec.Key.from_engine(KEY_URL)
52 | self.assertIsNotNone(ctx.key)
53 | ctx.key.name = 'rsakey.pem'
54 | self.assertEqual("rsakey.pem", ctx.key.name)
55 |
56 | ctx.sign(sign)
57 | self.assertEqual(self.load_xml("sign1-out.xml"), root)
58 |
--------------------------------------------------------------------------------
/tests/test_templates.py:
--------------------------------------------------------------------------------
1 | import unittest
2 |
3 | from lxml import etree
4 |
5 | import xmlsec
6 | from tests import base
7 |
8 | consts = xmlsec.constants
9 |
10 |
11 | class TestTemplates(base.TestMemoryLeaks):
12 | def test_create(self):
13 | root = self.load_xml("doc.xml")
14 | sign = xmlsec.template.create(
15 | root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1, id="Id", ns="test"
16 | )
17 | self.assertEqual("Id", sign.get("Id"))
18 | self.assertEqual("test", sign.prefix)
19 |
20 | def test_create_bad_args(self):
21 | with self.assertRaises(TypeError):
22 | xmlsec.template.create('', c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1)
23 |
24 | def test_encrypt_data_create(self):
25 | root = self.load_xml("doc.xml")
26 | enc = xmlsec.template.encrypted_data_create(
27 | root, method=consts.TransformDes3Cbc, id="Id", type="Type", mime_type="MimeType", encoding="Encoding", ns="test"
28 | )
29 | for a in ("Id", "Type", "MimeType", "Encoding"):
30 | self.assertEqual(a, enc.get(a))
31 | self.assertEqual("test", enc.prefix)
32 |
33 | def test_ensure_key_info(self):
34 | root = self.load_xml("doc.xml")
35 | sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1)
36 | ki = xmlsec.template.ensure_key_info(sign, id="Id")
37 | self.assertEqual("Id", ki.get("Id"))
38 |
39 | def test_ensure_key_info_fail(self):
40 | with self.assertRaisesRegex(xmlsec.Error, 'cannot ensure key info.'):
41 | xmlsec.template.ensure_key_info(etree.fromstring(b''), id="Id")
42 |
43 | def test_ensure_key_info_bad_args(self):
44 | with self.assertRaises(TypeError):
45 | xmlsec.template.ensure_key_info('', id=0)
46 |
47 | def test_add_encrypted_key(self):
48 | root = self.load_xml("doc.xml")
49 | sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1)
50 | ki = xmlsec.template.ensure_key_info(sign)
51 | ek = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep)
52 | self.assertEqual(ek, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeEncryptedKey, consts.EncNs))
53 | ek2 = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep, id="Id", type="Type", recipient="Recipient")
54 | for a in ("Id", "Type", "Recipient"):
55 | self.assertEqual(a, ek2.get(a))
56 |
57 | def test_add_key_name(self):
58 | root = self.load_xml("doc.xml")
59 | sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1)
60 | ki = xmlsec.template.ensure_key_info(sign)
61 | kn = xmlsec.template.add_key_name(ki)
62 | self.assertEqual(kn, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeKeyName, consts.DSigNs))
63 | kn2 = xmlsec.template.add_key_name(ki, name="name")
64 | self.assertEqual("name", kn2.text)
65 |
66 | def test_add_key_name_none(self):
67 | root = self.load_xml("doc.xml")
68 | sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1)
69 | ki = xmlsec.template.ensure_key_info(sign)
70 | kn2 = xmlsec.template.add_key_name(ki, name=None)
71 | self.assertEqual(kn2.text, None)
72 | print(etree.tostring(kn2))
73 |
74 | def test_add_key_name_bad_args(self):
75 | with self.assertRaises(TypeError):
76 | xmlsec.template.add_key_name('')
77 |
78 | def test_add_reference(self):
79 | root = self.load_xml("doc.xml")
80 | sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1)
81 | ref = xmlsec.template.add_reference(sign, consts.TransformSha1, id="Id", uri="URI", type="Type")
82 | for a in ("Id", "URI", "Type"):
83 | self.assertEqual(a, ref.get(a))
84 |
85 | def test_add_reference_bad_args(self):
86 | with self.assertRaises(TypeError):
87 | xmlsec.template.add_reference('', consts.TransformSha1)
88 | with self.assertRaises(TypeError):
89 | xmlsec.template.add_reference(etree.Element('root'), '')
90 |
91 | def test_add_reference_fail(self):
92 | with self.assertRaisesRegex(xmlsec.Error, 'cannot add reference.'):
93 | xmlsec.template.add_reference(etree.Element('root'), consts.TransformSha1)
94 |
95 | def test_add_transform_bad_args(self):
96 | with self.assertRaises(TypeError):
97 | xmlsec.template.add_transform('', consts.TransformSha1)
98 | with self.assertRaises(TypeError):
99 | xmlsec.template.add_transform(etree.Element('root'), '')
100 |
101 | def test_add_key_value(self):
102 | root = self.load_xml("doc.xml")
103 | sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1)
104 | ki = xmlsec.template.ensure_key_info(sign)
105 | kv = xmlsec.template.add_key_value(ki)
106 | self.assertEqual(kv, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeKeyValue, consts.DSigNs))
107 |
108 | def test_add_key_value_bad_args(self):
109 | with self.assertRaises(TypeError):
110 | xmlsec.template.add_key_value('')
111 |
112 | def test_add_x509_data(self):
113 | root = self.load_xml("doc.xml")
114 | sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1)
115 | ki = xmlsec.template.ensure_key_info(sign)
116 | x509 = xmlsec.template.add_x509_data(ki)
117 | xmlsec.template.x509_data_add_certificate(x509)
118 | xmlsec.template.x509_data_add_crl(x509)
119 | issuer = xmlsec.template.x509_data_add_issuer_serial(x509)
120 | xmlsec.template.x509_data_add_ski(x509)
121 | xmlsec.template.x509_data_add_subject_name(x509)
122 | xmlsec.template.x509_issuer_serial_add_issuer_name(issuer)
123 | xmlsec.template.x509_issuer_serial_add_serial_number(issuer)
124 | self.assertEqual(x509, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeX509Data, consts.DSigNs))
125 |
126 | def test_add_x509_data_bad_args(self):
127 | with self.assertRaises(TypeError):
128 | xmlsec.template.add_x509_data('')
129 |
130 | def test_x509_issuer_serial_add_issuer(self):
131 | root = self.load_xml("doc.xml")
132 | sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1)
133 | ki = xmlsec.template.ensure_key_info(sign)
134 | x509 = xmlsec.template.add_x509_data(ki)
135 | issuer = xmlsec.template.x509_data_add_issuer_serial(x509)
136 | name = xmlsec.template.x509_issuer_serial_add_issuer_name(issuer, name="Name")
137 | serial = xmlsec.template.x509_issuer_serial_add_serial_number(issuer, serial="Serial")
138 | self.assertEqual("Name", name.text)
139 | self.assertEqual("Serial", serial.text)
140 |
141 | def test_x509_issuer_serial_add_issuer_bad_args(self):
142 | with self.assertRaises(TypeError):
143 | xmlsec.template.x509_data_add_issuer_serial('')
144 |
145 | def test_x509_issuer_serial_add_issuer_name_bad_args(self):
146 | with self.assertRaises(TypeError):
147 | xmlsec.template.x509_issuer_serial_add_issuer_name('')
148 |
149 | def test_x509_issuer_serial_add_serial_number_bad_args(self):
150 | with self.assertRaises(TypeError):
151 | xmlsec.template.x509_issuer_serial_add_serial_number('')
152 |
153 | def test_x509_data_add_subject_name_bad_args(self):
154 | with self.assertRaises(TypeError):
155 | xmlsec.template.x509_data_add_subject_name('')
156 |
157 | def test_x509_data_add_ski_bad_args(self):
158 | with self.assertRaises(TypeError):
159 | xmlsec.template.x509_data_add_ski('')
160 |
161 | def test_x509_data_add_certificate_bad_args(self):
162 | with self.assertRaises(TypeError):
163 | xmlsec.template.x509_data_add_certificate('')
164 |
165 | def test_x509_data_add_crl_bad_args(self):
166 | with self.assertRaises(TypeError):
167 | xmlsec.template.x509_data_add_crl('')
168 |
169 | def test_add_encrypted_key_bad_args(self):
170 | with self.assertRaises(TypeError):
171 | xmlsec.template.add_encrypted_key('', 0)
172 |
173 | def test_encrypted_data_create_bad_args(self):
174 | with self.assertRaises(TypeError):
175 | xmlsec.template.encrypted_data_create('', 0)
176 |
177 | def test_encrypted_data_ensure_cipher_value(self):
178 | root = self.load_xml("doc.xml")
179 | enc = xmlsec.template.encrypted_data_create(root, method=consts.TransformDes3Cbc)
180 | cv = xmlsec.template.encrypted_data_ensure_cipher_value(enc)
181 | self.assertEqual(cv, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeCipherValue, consts.EncNs))
182 |
183 | def test_encrypted_data_ensure_cipher_value_bad_args(self):
184 | with self.assertRaises(TypeError):
185 | xmlsec.template.encrypted_data_ensure_cipher_value('')
186 |
187 | def test_encrypted_data_ensure_key_info(self):
188 | root = self.load_xml("doc.xml")
189 | enc = xmlsec.template.encrypted_data_create(root, method=consts.TransformDes3Cbc)
190 | ki = xmlsec.template.encrypted_data_ensure_key_info(enc)
191 | self.assertEqual(ki, xmlsec.tree.find_node(self.load_xml("enc_template.xml"), consts.NodeKeyInfo, consts.DSigNs))
192 | ki2 = xmlsec.template.encrypted_data_ensure_key_info(enc, id="Id", ns="test")
193 | self.assertEqual("Id", ki2.get("Id"))
194 | self.assertEqual("test", ki2.prefix)
195 |
196 | def test_encrypted_data_ensure_key_info_bad_args(self):
197 | with self.assertRaises(TypeError):
198 | xmlsec.template.encrypted_data_ensure_key_info('')
199 |
200 | @unittest.skipIf(not hasattr(consts, 'TransformXslt'), reason='XSLT transformations not enabled')
201 | def test_transform_add_c14n_inclusive_namespaces(self):
202 | root = self.load_xml("doc.xml")
203 | sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1)
204 | ref = xmlsec.template.add_reference(sign, consts.TransformSha1)
205 | trans1 = xmlsec.template.add_transform(ref, consts.TransformEnveloped)
206 | xmlsec.template.transform_add_c14n_inclusive_namespaces(trans1, "default")
207 | trans2 = xmlsec.template.add_transform(ref, consts.TransformXslt)
208 | xmlsec.template.transform_add_c14n_inclusive_namespaces(trans2, ["ns1", "ns2"])
209 | self.assertEqual(ref, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeReference, consts.DSigNs))
210 |
211 | def test_transform_add_c14n_inclusive_namespaces_bad_args(self):
212 | with self.assertRaises(TypeError):
213 | xmlsec.template.transform_add_c14n_inclusive_namespaces('', [])
214 |
--------------------------------------------------------------------------------
/tests/test_tree.py:
--------------------------------------------------------------------------------
1 | import xmlsec
2 | from tests import base
3 |
4 | consts = xmlsec.constants
5 |
6 |
7 | class TestTree(base.TestMemoryLeaks):
8 | def test_find_child(self):
9 | root = self.load_xml("sign_template.xml")
10 | si = xmlsec.tree.find_child(root, consts.NodeSignedInfo, consts.DSigNs)
11 | self.assertEqual(consts.NodeSignedInfo, si.tag.partition('}')[2])
12 | self.assertIsNone(xmlsec.tree.find_child(root, consts.NodeReference))
13 | self.assertIsNone(xmlsec.tree.find_child(root, consts.NodeSignedInfo, consts.EncNs))
14 |
15 | def test_find_child_bad_args(self):
16 | with self.assertRaises(TypeError):
17 | xmlsec.tree.find_child('', 0, True)
18 |
19 | def test_find_parent(self):
20 | root = self.load_xml("sign_template.xml")
21 | si = xmlsec.tree.find_child(root, consts.NodeSignedInfo, consts.DSigNs)
22 | self.assertIs(root, xmlsec.tree.find_parent(si, consts.NodeSignature))
23 | self.assertIsNone(xmlsec.tree.find_parent(root, consts.NodeSignedInfo))
24 |
25 | def test_find_parent_bad_args(self):
26 | with self.assertRaises(TypeError):
27 | xmlsec.tree.find_parent('', 0, True)
28 |
29 | def test_find_node(self):
30 | root = self.load_xml("sign_template.xml")
31 | ref = xmlsec.tree.find_node(root, consts.NodeReference)
32 | self.assertEqual(consts.NodeReference, ref.tag.partition('}')[2])
33 | self.assertIsNone(xmlsec.tree.find_node(root, consts.NodeReference, consts.EncNs))
34 |
35 | def test_find_node_bad_args(self):
36 | with self.assertRaises(TypeError):
37 | xmlsec.tree.find_node('', 0, True)
38 |
39 | def test_add_ids(self):
40 | root = self.load_xml("sign_template.xml")
41 | xmlsec.tree.add_ids(root, ["id1", "id2", "id3"])
42 |
43 | def test_add_ids_bad_args(self):
44 | with self.assertRaises(TypeError):
45 | xmlsec.tree.add_ids('', [])
46 |
--------------------------------------------------------------------------------
/tests/test_type_stubs.py:
--------------------------------------------------------------------------------
1 | """Test type stubs for correctness where possible."""
2 |
3 | import os
4 |
5 | import pytest
6 |
7 | import xmlsec
8 |
9 | black = pytest.importorskip('black')
10 |
11 |
12 | constants_stub_header = """
13 | import sys
14 | from typing import NamedTuple
15 |
16 | if sys.version_info >= (3, 8):
17 | from typing import Final
18 | else:
19 | from typing_extensions import Final
20 |
21 | class __KeyData(NamedTuple): # __KeyData type
22 | href: str
23 | name: str
24 |
25 | class __KeyDataNoHref(NamedTuple): # __KeyData type
26 | href: None
27 | name: str
28 |
29 | class __Transform(NamedTuple): # __Transform type
30 | href: str
31 | name: str
32 | usage: int
33 |
34 | class __TransformNoHref(NamedTuple): # __Transform type
35 | href: None
36 | name: str
37 | usage: int
38 |
39 | """
40 |
41 |
42 | def gen_constants_stub():
43 | """
44 | Generate contents of the file:`xmlsec/constants.pyi`.
45 |
46 | Simply load all constants at runtime,
47 | generate appropriate type hint for each constant type.
48 | """
49 |
50 | def process_constant(name):
51 | """Generate line in stub file for constant name."""
52 | obj = getattr(xmlsec.constants, name)
53 | type_name = type(obj).__name__
54 | if type_name in ('__KeyData', '__Transform') and obj.href is None:
55 | type_name += 'NoHref'
56 | return '{name}: Final[{type_name}]'.format(name=name, type_name=type_name)
57 |
58 | names = list(sorted(name for name in dir(xmlsec.constants) if not name.startswith('__')))
59 | lines = [process_constant(name) for name in names]
60 | return constants_stub_header + os.linesep.join(lines)
61 |
62 |
63 | def test_xmlsec_constants_stub(request):
64 | """
65 | Generate the stub file for :mod:`xmlsec.constants` from existing code.
66 |
67 | Compare it against the existing stub :file:`xmlsec/constants.pyi`.
68 | """
69 | stub = request.config.rootpath / 'src' / 'xmlsec' / 'constants.pyi'
70 | mode = black.FileMode(target_versions={black.TargetVersion.PY39}, line_length=130, is_pyi=True, string_normalization=False)
71 | formatted = black.format_file_contents(gen_constants_stub(), fast=False, mode=mode)
72 | assert formatted == stub.read_text()
73 |
--------------------------------------------------------------------------------
/tests/test_xmlsec.py:
--------------------------------------------------------------------------------
1 | import xmlsec
2 | from tests import base
3 |
4 |
5 | class TestModule(base.TestMemoryLeaks):
6 | def test_reinitialize_module(self):
7 | """
8 | This test doesn't explicitly verify anything, but will be invoked first in the suite.
9 |
10 | So if the subsequent tests don't fail, we know that the ``init()``/``shutdown()``
11 | function pair doesn't break anything.
12 | """
13 | xmlsec.shutdown()
14 | xmlsec.init()
15 |
--------------------------------------------------------------------------------