python-pkcs11
Advanced tools
| name: install-softhsm | ||
| author: Matthias Valvekens | ||
| description: Install SoftHSM and configure an empty token | ||
| inputs: | ||
| os: | ||
| description: OS to target | ||
| required: true | ||
| token-label: | ||
| description: Label assigned to the token | ||
| required: false | ||
| default: TEST | ||
| token-user-pin: | ||
| description: User PIN to configure on the token | ||
| required: false | ||
| default: "1234" | ||
| token-so-pin: | ||
| description: Security officer PIN to configure on the token | ||
| required: false | ||
| default: "5678" | ||
| runs: | ||
| using: "composite" | ||
| steps: | ||
| - name: Install SoftHSM | ||
| shell: bash | ||
| run: | | ||
| if [[ "${OS_NAME:0:6}" == 'ubuntu' ]]; then | ||
| sudo apt-get install softhsm2 | ||
| mkdir softhsm_tokens | ||
| echo "directories.tokendir = $(pwd)/softhsm_tokens" > /tmp/softhsm2.conf | ||
| echo "SOFTHSM2_CONF=/tmp/softhsm2.conf" >> "$GITHUB_ENV" | ||
| echo "PKCS11_MODULE=/usr/lib/softhsm/libsofthsm2.so" >> "$GITHUB_ENV" | ||
| elif [[ "${OS_NAME:0:5}" == 'macos' ]]; then | ||
| brew install softhsm | ||
| echo "PKCS11_MODULE=/opt/homebrew/lib/softhsm/libsofthsm2.so" >> "$GITHUB_ENV" | ||
| elif [[ "${OS_NAME:0:7}" == 'windows' ]]; then | ||
| choco install softhsm.install | ||
| echo "SOFTHSM2_CONF=D:/SoftHSM2/etc/softhsm2.conf" >> "$GITHUB_ENV" | ||
| echo "PKCS11_MODULE=D:/SoftHSM2/lib/softhsm2-x64.dll" >> "$GITHUB_ENV" | ||
| echo "D:/SoftHSM2/bin" >> "$GITHUB_PATH" | ||
| echo "D:/SoftHSM2/lib" >> "$GITHUB_PATH" | ||
| else | ||
| echo "$OS_NAME is not a supported target system" | ||
| exit 1 | ||
| fi | ||
| env: | ||
| OS_NAME: ${{ inputs.os }} | ||
| - name: Initialize SoftHSM token | ||
| shell: bash | ||
| run: | | ||
| softhsm2-util --init-token --free --label "${{ inputs.token-label }}" \ | ||
| --pin "${{ inputs.token-user-pin }}" --so-pin "${{ inputs.token-so-pin }}" | ||
| echo "PKCS11_TOKEN_LABEL=${{ inputs.token-label }}" >> "$GITHUB_ENV" | ||
| echo "PKCS11_TOKEN_PIN=${{ inputs.token-user-pin }}" >> "$GITHUB_ENV" | ||
| echo "PKCS11_TOKEN_SO_PIN=${{ inputs.token-so-pin }}" >> "$GITHUB_ENV" |
| A source distribution and wheels for common platforms have been published to [PyPI](https://pypi.org/project/python-pkcs11/:VERSION). |
| name: Code quality | ||
| on: | ||
| push: {} | ||
| pull_request: {} | ||
| env: | ||
| UV_PYTHON_PREFERENCE: only-system | ||
| UV_NO_SYNC: "1" | ||
| jobs: | ||
| run: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Acquire sources | ||
| uses: actions/checkout@v4 | ||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v4 | ||
| with: | ||
| enable-cache: true | ||
| - name: Setup Python | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: "3.13" | ||
| architecture: x64 | ||
| - name: Install lint dependencies | ||
| run: uv sync --no-dev --exact --group lint | ||
| - name: ruff format | ||
| run: uv run ruff format --diff . | ||
| - name: ruff check | ||
| run: uv run ruff check --diff . |
| name: Publish release to PyPI | ||
| on: | ||
| push: | ||
| tags: | ||
| - 'v[0-9]+.[0-9]+.[0-9]+' | ||
| workflow_dispatch: | ||
| inputs: | ||
| environment: | ||
| type: environment | ||
| description: "Environment in which to execute the release process" | ||
| env: | ||
| UV_PYTHON_PREFERENCE: only-system | ||
| # we do all UV syncing explicitly | ||
| UV_NO_SYNC: "1" | ||
| jobs: | ||
| extract-params: | ||
| name: Determine release parameters | ||
| runs-on: ubuntu-latest | ||
| permissions: {} | ||
| outputs: | ||
| publish-env: ${{ steps.setenv.outputs.envname }} | ||
| version: ${{ steps.getrelease.outputs.version }} | ||
| steps: | ||
| - id: setenv | ||
| run: | | ||
| if [[ $GITHUB_EVENT_NAME == 'workflow_dispatch' ]]; then | ||
| echo "envname=${{ inputs.environment }}" >> "$GITHUB_OUTPUT" | ||
| elif [[ $GITHUB_EVENT_NAME == 'push' ]]; then | ||
| echo "envname=pypi" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "Cannot run release workflow for trigger event $GITHUB_EVENT_NAME" | ||
| exit 1 | ||
| fi | ||
| cat "$GITHUB_OUTPUT" | ||
| - name: Get version information | ||
| id: getrelease | ||
| run: | | ||
| set -eo pipefail | ||
| VER_REGEX="v[0-9]\+\.[0-9]\+\..\+" | ||
| if [[ "${GITHUB_REF:0:11}" != 'refs/tags/v' ]]; then | ||
| echo "Cannot run release workflow for ref $GITHUB_REF, must be a tag starting with 'v'" | ||
| exit 1 | ||
| fi | ||
| VERSION=${GITHUB_REF:10} | ||
| if echo $VERSION | grep -q "$VER_REGEX"; then | ||
| echo "version=${VERSION:1}" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "Tag $VERSION does not follow v<version> naming scheme" | ||
| exit 1 | ||
| fi | ||
| - uses: actions/checkout@v4 | ||
| - name: Generate release body | ||
| run: | | ||
| sed "s/:VERSION/$VERSION/g" < .github/release-template.md > release.md | ||
| cat release.md | ||
| env: | ||
| VERSION: ${{ steps.getrelease.outputs.version }} | ||
| - name: Upload release body | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: release-body | ||
| path: release.md | ||
| build-wheels: | ||
| runs-on: ${{ matrix.os }} | ||
| needs: [extract-params] | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| os: | ||
| - ubuntu-latest | ||
| - ubuntu-24.04-arm | ||
| - windows-latest | ||
| - macos-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Setup Python | ||
| uses: actions/setup-python@v5 | ||
| - name: Build wheels | ||
| uses: pypa/cibuildwheel@v3.0.0 | ||
| - uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: wheels-${{ matrix.os }}-${{ strategy.job-index }} | ||
| path: ./wheelhouse/*.whl | ||
| build-sdist: | ||
| runs-on: ubuntu-latest | ||
| needs: [extract-params] | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Setup Python | ||
| uses: actions/setup-python@v5 | ||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v4 | ||
| with: | ||
| enable-cache: true | ||
| - name: Build source distribution | ||
| run: uv build --sdist | ||
| - uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: sdist | ||
| path: ./dist/*.tar.gz | ||
| publish: | ||
| name: Publish release artifacts | ||
| needs: [extract-params, build-sdist, build-wheels] | ||
| runs-on: ubuntu-latest | ||
| environment: ${{ needs.extract-params.outputs.publish-env }} | ||
| permissions: | ||
| # we use PyPI's trusted publisher model -> expose identity token | ||
| id-token: write | ||
| # Needed to create GitHub releases | ||
| contents: write | ||
| steps: | ||
| - name: Download wheels | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| pattern: wheels-* | ||
| path: dist/ | ||
| merge-multiple: 'true' | ||
| - name: Download source distribution | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: sdist | ||
| path: dist/ | ||
| - name: Download release body | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: release-body | ||
| path: release-body | ||
| - name: Upload to PyPI | ||
| uses: pypa/gh-action-pypi-publish@release/v1 | ||
| with: | ||
| repository-url: ${{ vars.REPOSITORY_URL }} | ||
| - name: Create GitHub release | ||
| if: needs.extract-params.outputs.publish-env == 'pypi' && startsWith(github.ref, 'refs/tags/') | ||
| uses: softprops/action-gh-release@v2 | ||
| with: | ||
| files: | | ||
| dist/*.whl | ||
| dist/*.tar.gz | ||
| body_path: release-body/release.md | ||
| fail_on_unmatched_files: true | ||
| name: python-pkcs11 ${{ needs.extract-params.outputs.version }} |
| name: Tests | ||
| on: | ||
| push: | ||
| branches: ["**"] | ||
| pull_request: {} | ||
| workflow_dispatch: {} | ||
| env: | ||
| UV_PYTHON_PREFERENCE: only-system | ||
| UV_NO_SYNC: "1" | ||
| jobs: | ||
| run: | ||
| runs-on: ${{ matrix.os }} | ||
| strategy: | ||
| matrix: | ||
| os: | ||
| - ubuntu-latest | ||
| - windows-latest | ||
| - macos-latest | ||
| python-version: | ||
| - "3.9" | ||
| - "3.10" | ||
| - "3.11" | ||
| - "3.12" | ||
| # 3.13.4 has a regression in C extension builds, | ||
| # need to stick to 3.13.3 until 3.13.5 is available on runners | ||
| - "3.13.3" | ||
| steps: | ||
| - name: Acquire sources | ||
| uses: actions/checkout@v4 | ||
| - name: Setup Python | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: ${{ matrix.python-version }} | ||
| - uses: ./.github/actions/install-softhsm | ||
| with: | ||
| os: ${{ matrix.os }} | ||
| - name: Install uv | ||
| uses: astral-sh/setup-uv@v4 | ||
| with: | ||
| enable-cache: true | ||
| python-version: ${{ matrix.python-version }} | ||
| - name: Install testing dependencies | ||
| run: uv sync --no-dev --exact --group testing | ||
| - name: Run tests | ||
| run: uv run pytest -v |
Sorry, the diff of this file is not supported yet
| version: 2 | ||
| build: | ||
| os: ubuntu-24.04 | ||
| tools: | ||
| python: "3.12" | ||
| # readthedocs does not support [dependency-groups] directly | ||
| jobs: | ||
| create_environment: | ||
| - asdf plugin add uv | ||
| - asdf install uv latest | ||
| - asdf global uv latest | ||
| build: | ||
| html: | ||
| - make -C docs html BUILDDIR=$READTHEDOCS_OUTPUT | ||
| formats: all |
+27
| ARG IMAGE=debian:stable | ||
| FROM $IMAGE | ||
| RUN apt-get update && \ | ||
| DEBIAN_FRONTEND="noninteractive" apt-get install -y gcc python3 python3-dev softhsm2 openssl && \ | ||
| rm -rf /var/lib/apt/lists/* | ||
| COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ | ||
| WORKDIR /test | ||
| ADD uv.lock pyproject.toml setup.py . | ||
| ADD pkcs11/ pkcs11/ | ||
| ADD extern/ extern/ | ||
| ENV UV_LINK_MODE=copy | ||
| RUN --mount=type=cache,target=/root/.cache/uv \ | ||
| uv sync --all-extras | ||
| ENV PKCS11_MODULE=/usr/lib/softhsm/libsofthsm2.so | ||
| ENV PKCS11_TOKEN_LABEL=TEST | ||
| ENV PKCS11_TOKEN_PIN=1234 | ||
| ENV PKCS11_TOKEN_SO_PIN=5678 | ||
| RUN softhsm2-util --init-token --free --label TEST --pin 1234 --so-pin 5678 | ||
| ADD tests/ tests/ | ||
| CMD ["uv", "run", "pytest", "-v"] |
| !*.c |
| #define PY_SSIZE_T_CLEAN | ||
| #include "load_module.h" | ||
| #ifdef _WIN32 | ||
| static PyObject* p11_error() { | ||
| DWORD dwMessageId = GetLastError(); | ||
| LPWSTR msgbuffer = NULL; | ||
| if (dwMessageId != 0) { | ||
| DWORD l = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, | ||
| NULL, | ||
| dwMessageId, | ||
| MAKELANGID(LANG_USER_DEFAULT, SUBLANG_DEFAULT), | ||
| (LPWSTR) &msgbuffer, | ||
| 0, | ||
| NULL); | ||
| PyObject* errmsg = PyUnicode_FromWideChar(msgbuffer, l); | ||
| LocalFree(msgbuffer); | ||
| return errmsg; | ||
| } else { | ||
| return NULL; | ||
| } | ||
| } | ||
| static P11_HANDLE* p11_open(PyObject *path_str) { | ||
| wchar_t *path = PyUnicode_AsWideCharString(path_str, NULL); | ||
| LIB_HANDLE handle = LoadLibraryW(path); | ||
| PyMem_Free(path); | ||
| P11_HANDLE* result = NULL; | ||
| if (handle != NULL) { | ||
| void * ptr = GetProcAddress(handle, "C_GetFunctionList"); | ||
| if (ptr != NULL) { | ||
| result = (P11_HANDLE*) PyMem_Malloc(sizeof(P11_HANDLE)); | ||
| result->lib_handle = handle; | ||
| result->get_function_list_ptr = ptr; | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
| static int p11_close(P11_HANDLE* handle) { | ||
| if(handle != NULL) { | ||
| LIB_HANDLE lib_handle = handle->lib_handle; | ||
| PyMem_Free(handle); | ||
| if (lib_handle != NULL) { | ||
| return FreeLibrary(lib_handle); | ||
| } | ||
| } | ||
| return 0; | ||
| } | ||
| #else | ||
| static PyObject* p11_error() { | ||
| char* error = dlerror(); | ||
| if (error == NULL) { | ||
| return NULL; | ||
| } | ||
| int len = strlen(error); | ||
| PyObject* result = PyUnicode_DecodeUTF8(error, len, NULL); | ||
| PyMem_Free(error); | ||
| return result; | ||
| } | ||
| static P11_HANDLE* p11_open(PyObject *path_str) { | ||
| const char *path = PyUnicode_AsUTF8AndSize(path_str, NULL); | ||
| // Note: python manages this buffer, no need to deallocate it here | ||
| P11_HANDLE* result = NULL; | ||
| LIB_HANDLE handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL); | ||
| if (handle != NULL) { | ||
| void * ptr = dlsym(handle, "C_GetFunctionList"); | ||
| if (ptr != NULL) { | ||
| result = (P11_HANDLE*) PyMem_Malloc(sizeof(P11_HANDLE)); | ||
| result->lib_handle = handle; | ||
| result->get_function_list_ptr = ptr; | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
| static int p11_close(P11_HANDLE* handle) { | ||
| if(handle != NULL) { | ||
| LIB_HANDLE lib_handle = handle->lib_handle; | ||
| PyMem_Free(handle); | ||
| if (lib_handle != NULL) { | ||
| return dlclose(lib_handle); | ||
| } | ||
| } | ||
| return 0; | ||
| } | ||
| #endif |
| #define PY_SSIZE_T_CLEAN | ||
| #include <Python.h> | ||
| #ifdef _WIN32 | ||
| #include "Windows.h" | ||
| typedef HINSTANCE LIB_HANDLE; | ||
| #else | ||
| #include <dlfcn.h> | ||
| typedef void *LIB_HANDLE; | ||
| #endif | ||
| #ifndef P11_HANDLE | ||
| typedef struct P11_HANDLE { | ||
| LIB_HANDLE lib_handle; | ||
| void * get_function_list_ptr; | ||
| } P11_HANDLE; | ||
| #endif | ||
| static PyObject* p11_error(); | ||
| static P11_HANDLE* p11_open(PyObject *path_str); | ||
| static int p11_close(P11_HANDLE* handle); |
+21
| MIT License | ||
| Copyright (c) 2017 Danielle Madeley | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. |
| graft extern/ | ||
| include pkcs11/*.pxd |
| """ | ||
| Definitions imported from PKCS11 C headers. | ||
| """ | ||
| from cython.view cimport array | ||
| from defaults import * | ||
| cdef extern from '../extern/cryptoki.h': | ||
| ctypedef unsigned char CK_BYTE | ||
| ctypedef CK_BYTE CK_BBOOL | ||
| ctypedef CK_BYTE CK_UTF8CHAR | ||
| ctypedef unsigned char CK_CHAR | ||
| ctypedef unsigned long int CK_ULONG | ||
| ctypedef CK_ULONG CK_ATTRIBUTE_TYPE | ||
| ctypedef CK_ULONG CK_EC_KDF_TYPE | ||
| ctypedef CK_ULONG CK_FLAGS | ||
| ctypedef CK_ULONG CK_MECHANISM_TYPE | ||
| ctypedef CK_ULONG CK_OBJECT_HANDLE | ||
| ctypedef CK_ULONG CK_RSA_PKCS_MGF_TYPE | ||
| ctypedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE | ||
| ctypedef CK_ULONG CK_SESSION_HANDLE | ||
| ctypedef CK_ULONG CK_SLOT_ID | ||
| ctypedef CK_ULONG CK_STATE | ||
| ctypedef enum CK_RV: | ||
| CKR_OK, | ||
| CKR_CANCEL, | ||
| CKR_HOST_MEMORY, | ||
| CKR_SLOT_ID_INVALID, | ||
| CKR_GENERAL_ERROR, | ||
| CKR_FUNCTION_FAILED, | ||
| CKR_ARGUMENTS_BAD, | ||
| CKR_NO_EVENT, | ||
| CKR_NEED_TO_CREATE_THREADS, | ||
| CKR_CANT_LOCK, | ||
| CKR_ATTRIBUTE_READ_ONLY, | ||
| CKR_ATTRIBUTE_SENSITIVE, | ||
| CKR_ATTRIBUTE_TYPE_INVALID, | ||
| CKR_ATTRIBUTE_VALUE_INVALID, | ||
| CKR_DATA_INVALID, | ||
| CKR_DATA_LEN_RANGE, | ||
| CKR_DEVICE_ERROR, | ||
| CKR_DEVICE_MEMORY, | ||
| CKR_DEVICE_REMOVED, | ||
| CKR_ENCRYPTED_DATA_INVALID, | ||
| CKR_ENCRYPTED_DATA_LEN_RANGE, | ||
| CKR_FUNCTION_CANCELED, | ||
| CKR_FUNCTION_NOT_PARALLEL, | ||
| CKR_FUNCTION_NOT_SUPPORTED, | ||
| CKR_KEY_HANDLE_INVALID, | ||
| CKR_KEY_SIZE_RANGE, | ||
| CKR_KEY_TYPE_INCONSISTENT, | ||
| CKR_KEY_NOT_NEEDED, | ||
| CKR_KEY_CHANGED, | ||
| CKR_KEY_NEEDED, | ||
| CKR_KEY_INDIGESTIBLE, | ||
| CKR_KEY_FUNCTION_NOT_PERMITTED, | ||
| CKR_KEY_NOT_WRAPPABLE, | ||
| CKR_KEY_UNEXTRACTABLE, | ||
| CKR_MECHANISM_INVALID, | ||
| CKR_MECHANISM_PARAM_INVALID, | ||
| CKR_OBJECT_HANDLE_INVALID, | ||
| CKR_OPERATION_ACTIVE, | ||
| CKR_OPERATION_NOT_INITIALIZED, | ||
| CKR_PIN_INCORRECT, | ||
| CKR_PIN_INVALID, | ||
| CKR_PIN_LEN_RANGE, | ||
| CKR_PIN_EXPIRED, | ||
| CKR_PIN_LOCKED, | ||
| CKR_SESSION_CLOSED, | ||
| CKR_SESSION_COUNT, | ||
| CKR_SESSION_HANDLE_INVALID, | ||
| CKR_SESSION_PARALLEL_NOT_SUPPORTED, | ||
| CKR_SESSION_READ_ONLY, | ||
| CKR_SESSION_EXISTS, | ||
| CKR_SESSION_READ_ONLY_EXISTS, | ||
| CKR_SESSION_READ_WRITE_SO_EXISTS, | ||
| CKR_SIGNATURE_INVALID, | ||
| CKR_SIGNATURE_LEN_RANGE, | ||
| CKR_TEMPLATE_INCOMPLETE, | ||
| CKR_TEMPLATE_INCONSISTENT, | ||
| CKR_TOKEN_NOT_PRESENT, | ||
| CKR_TOKEN_NOT_RECOGNIZED, | ||
| CKR_TOKEN_WRITE_PROTECTED, | ||
| CKR_UNWRAPPING_KEY_HANDLE_INVALID, | ||
| CKR_UNWRAPPING_KEY_SIZE_RANGE, | ||
| CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT, | ||
| CKR_USER_ALREADY_LOGGED_IN, | ||
| CKR_USER_NOT_LOGGED_IN, | ||
| CKR_USER_PIN_NOT_INITIALIZED, | ||
| CKR_USER_TYPE_INVALID, | ||
| CKR_USER_ANOTHER_ALREADY_LOGGED_IN, | ||
| CKR_USER_TOO_MANY_TYPES, | ||
| CKR_WRAPPED_KEY_INVALID, | ||
| CKR_WRAPPED_KEY_LEN_RANGE, | ||
| CKR_WRAPPING_KEY_HANDLE_INVALID, | ||
| CKR_WRAPPING_KEY_SIZE_RANGE, | ||
| CKR_WRAPPING_KEY_TYPE_INCONSISTENT, | ||
| CKR_RANDOM_SEED_NOT_SUPPORTED, | ||
| CKR_RANDOM_NO_RNG, | ||
| CKR_DOMAIN_PARAMS_INVALID, | ||
| CKR_BUFFER_TOO_SMALL, | ||
| CKR_SAVED_STATE_INVALID, | ||
| CKR_INFORMATION_SENSITIVE, | ||
| CKR_STATE_UNSAVEABLE, | ||
| CKR_CRYPTOKI_NOT_INITIALIZED, | ||
| CKR_CRYPTOKI_ALREADY_INITIALIZED, | ||
| CKR_MUTEX_BAD, | ||
| CKR_MUTEX_NOT_LOCKED, | ||
| CKR_NEW_PIN_MODE, | ||
| CKR_NEXT_OTP, | ||
| CKR_EXCEEDED_MAX_ITERATIONS, | ||
| CKR_FIPS_SELF_TEST_FAILED, | ||
| CKR_LIBRARY_LOAD_FAILED, | ||
| CKR_PIN_TOO_WEAK, | ||
| CKR_PUBLIC_KEY_INVALID, | ||
| CKR_FUNCTION_REJECTED, | ||
| CKR_VENDOR_DEFINED, | ||
| ctypedef enum CK_USER_TYPE: | ||
| CKU_SO, | ||
| CKU_USER, | ||
| CKU_CONTEXT_SPECIFIC, | ||
| cdef enum: | ||
| CK_TRUE, | ||
| CK_FALSE, | ||
| cdef enum: | ||
| CK_UNAVAILABLE_INFORMATION, | ||
| CK_EFFECTIVELY_INFINITE, | ||
| cdef enum: # CK_FLAGS | ||
| CKF_DONT_BLOCK, | ||
| CKF_RW_SESSION, | ||
| CKF_SERIAL_SESSION, | ||
| cdef enum: # CKZ | ||
| CKZ_DATA_SPECIFIED, | ||
| cdef enum: # CK_STATE | ||
| CKS_RO_PUBLIC_SESSION, | ||
| CKS_RO_USER_FUNCTIONS, | ||
| CKS_RW_PUBLIC_SESSION, | ||
| CKS_RW_USER_FUNCTIONS, | ||
| CKS_RW_SO_FUNCTIONS | ||
| ctypedef struct CK_VERSION: | ||
| CK_BYTE major | ||
| CK_BYTE minor | ||
| ctypedef struct CK_INFO: | ||
| CK_VERSION cryptokiVersion; | ||
| CK_UTF8CHAR manufacturerID[32] | ||
| CK_FLAGS flags | ||
| CK_UTF8CHAR libraryDescription[32] | ||
| CK_VERSION libraryVersion; | ||
| ctypedef struct CK_SLOT_INFO: | ||
| CK_UTF8CHAR slotDescription[64] | ||
| CK_UTF8CHAR manufacturerID[32] | ||
| CK_FLAGS flags | ||
| CK_VERSION hardwareVersion | ||
| CK_VERSION firmwareVersion | ||
| ctypedef struct CK_MECHANISM_INFO: | ||
| CK_ULONG ulMinKeySize | ||
| CK_ULONG ulMaxKeySize | ||
| CK_FLAGS flags | ||
| ctypedef struct CK_TOKEN_INFO: | ||
| CK_UTF8CHAR label[32] | ||
| CK_UTF8CHAR manufacturerID[32] | ||
| CK_UTF8CHAR model[16] | ||
| CK_CHAR serialNumber[16] | ||
| CK_FLAGS flags | ||
| CK_ULONG ulMaxSessionCount | ||
| CK_ULONG ulSessionCount | ||
| CK_ULONG ulMaxRwSessionCount | ||
| CK_ULONG ulRwSessionCount | ||
| CK_ULONG ulMaxPinLen | ||
| CK_ULONG ulMinPinLen | ||
| CK_ULONG ulTotalPublicMemory | ||
| CK_ULONG ulFreePublicMemory | ||
| CK_ULONG ulTotalPrivateMemory | ||
| CK_ULONG ulFreePrivateMemory | ||
| CK_VERSION hardwareVersion | ||
| CK_VERSION firmwareVersion | ||
| CK_CHAR utcTime[16] | ||
| ctypedef struct CK_SESSION_INFO: | ||
| CK_SLOT_ID slotID | ||
| CK_STATE state | ||
| CK_FLAGS flags | ||
| CK_ULONG ulDeviceError | ||
| ctypedef struct CK_MECHANISM: | ||
| CK_MECHANISM_TYPE mechanism | ||
| void *pParameter | ||
| CK_ULONG ulParameterLen | ||
| ctypedef struct CK_ATTRIBUTE: | ||
| CK_ATTRIBUTE_TYPE type | ||
| void *pValue | ||
| CK_ULONG ulValueLen | ||
| ctypedef struct CK_RSA_PKCS_OAEP_PARAMS: | ||
| CK_MECHANISM_TYPE hashAlg | ||
| CK_RSA_PKCS_MGF_TYPE mgf | ||
| CK_RSA_PKCS_OAEP_SOURCE_TYPE source | ||
| void *pSourceData | ||
| CK_ULONG ulSourceDataLen | ||
| ctypedef struct CK_RSA_PKCS_PSS_PARAMS: | ||
| CK_MECHANISM_TYPE hashAlg | ||
| CK_RSA_PKCS_MGF_TYPE mgf | ||
| CK_ULONG sLen | ||
| ctypedef struct CK_ECDH1_DERIVE_PARAMS: | ||
| CK_EC_KDF_TYPE kdf | ||
| CK_ULONG ulSharedDataLen | ||
| CK_BYTE *pSharedData | ||
| CK_ULONG ulPublicDataLen | ||
| CK_BYTE *pPublicData | ||
| ctypedef struct CK_KEY_DERIVATION_STRING_DATA: | ||
| CK_BYTE *pData | ||
| CK_ULONG ulLen | ||
| ctypedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS: | ||
| CK_BYTE iv[16] | ||
| CK_BYTE *pData | ||
| CK_ULONG length | ||
| ctypedef struct CK_EDDSA_PARAMS: | ||
| CK_BBOOL phFlag | ||
| CK_ULONG ulContextDataLen | ||
| CK_BYTE *pContextData | ||
| cdef struct CK_FUNCTION_LIST: | ||
| CK_VERSION version | ||
| ## pointers to library functions are stored here | ||
| ## caution: order matters! | ||
| ## general purpose | ||
| CK_RV C_Initialize(void *) nogil | ||
| CK_RV C_Finalize(void *) nogil | ||
| CK_RV C_GetInfo(CK_INFO *info) nogil | ||
| CK_RV C_GetFunctionList(CK_FUNCTION_LIST **) nogil | ||
| ## slot and token management | ||
| CK_RV C_GetSlotList(CK_BBOOL tokenPresent, | ||
| CK_SLOT_ID *slotList, | ||
| CK_ULONG *count) nogil | ||
| CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, | ||
| CK_SLOT_INFO *info) nogil | ||
| CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, | ||
| CK_TOKEN_INFO *info) nogil | ||
| CK_RV C_GetMechanismList(CK_SLOT_ID slotID, | ||
| CK_MECHANISM_TYPE *mechanismList, | ||
| CK_ULONG *count) nogil | ||
| CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, | ||
| CK_MECHANISM_TYPE mechanism, | ||
| CK_MECHANISM_INFO *info) nogil | ||
| CK_RV C_InitToken(CK_SLOT_ID slotID, | ||
| CK_UTF8CHAR *pPin, | ||
| CK_ULONG ulPinLen, | ||
| CK_UTF8CHAR *pLabel) nogil | ||
| CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, | ||
| CK_UTF8CHAR *pPin, | ||
| CK_ULONG ulPinLen) nogil | ||
| CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, | ||
| CK_UTF8CHAR *pOldPin, | ||
| CK_ULONG ulOldLen, | ||
| CK_UTF8CHAR *pNewPin, | ||
| CK_ULONG ulNewLen) nogil | ||
| ## session management | ||
| CK_RV C_OpenSession(CK_SLOT_ID slotID, | ||
| CK_FLAGS flags, | ||
| void *application, | ||
| void *notify, | ||
| CK_SESSION_HANDLE *handle) nogil | ||
| CK_RV C_CloseSession(CK_SESSION_HANDLE session) nogil | ||
| CK_RV C_CloseAllSessions(CK_SLOT_ID slotID) nogil | ||
| CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, | ||
| CK_SESSION_INFO *pInfo) nogil | ||
| CK_RV C_GetOperationState(CK_SESSION_HANDLE hSession, | ||
| CK_BYTE *pOperationState, | ||
| CK_ULONG *pulOperationStateLen) nogil | ||
| CK_RV C_SetOperationState(CK_SESSION_HANDLE hSession, | ||
| CK_BYTE *pOperationState, | ||
| CK_ULONG ulOperationStateLen, | ||
| CK_OBJECT_HANDLE hEncryptionKey, | ||
| CK_OBJECT_HANDLE hAuthenticationKey) nogil | ||
| CK_RV C_Login(CK_SESSION_HANDLE session, | ||
| CK_USER_TYPE userType, | ||
| CK_UTF8CHAR *pin, | ||
| CK_ULONG pinLen) nogil | ||
| CK_RV C_Logout(CK_SESSION_HANDLE session) nogil | ||
| ## object management | ||
| CK_RV C_CreateObject(CK_SESSION_HANDLE session, | ||
| CK_ATTRIBUTE *template, | ||
| CK_ULONG count, | ||
| CK_OBJECT_HANDLE *key) nogil | ||
| CK_RV C_CopyObject(CK_SESSION_HANDLE session, | ||
| CK_OBJECT_HANDLE key, | ||
| CK_ATTRIBUTE *template, | ||
| CK_ULONG count, | ||
| CK_OBJECT_HANDLE *new_key) nogil | ||
| CK_RV C_DestroyObject(CK_SESSION_HANDLE session, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_GetObjectSize(CK_SESSION_HANDLE hSession, | ||
| CK_OBJECT_HANDLE hObject, | ||
| CK_ULONG *pulSize) nogil | ||
| CK_RV C_GetAttributeValue(CK_SESSION_HANDLE session, | ||
| CK_OBJECT_HANDLE key, | ||
| CK_ATTRIBUTE *template, | ||
| CK_ULONG count) nogil | ||
| CK_RV C_SetAttributeValue(CK_SESSION_HANDLE session, | ||
| CK_OBJECT_HANDLE key, | ||
| CK_ATTRIBUTE *template, | ||
| CK_ULONG count) nogil | ||
| CK_RV C_FindObjectsInit(CK_SESSION_HANDLE session, | ||
| CK_ATTRIBUTE *template, | ||
| CK_ULONG count) nogil | ||
| CK_RV C_FindObjects(CK_SESSION_HANDLE session, | ||
| CK_OBJECT_HANDLE *objects, | ||
| CK_ULONG objectsMax, | ||
| CK_ULONG *objectsLength) nogil | ||
| CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE session) nogil | ||
| ## encryption and decryption | ||
| CK_RV C_EncryptInit(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_Encrypt(CK_SESSION_HANDLE session, | ||
| CK_BYTE *plaintext, | ||
| CK_ULONG plaintext_len, | ||
| CK_BYTE *ciphertext, | ||
| CK_ULONG *ciphertext_len) nogil | ||
| CK_RV C_EncryptUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *part_in, | ||
| CK_ULONG part_in_len, | ||
| CK_BYTE *part_out, | ||
| CK_ULONG *part_out_len) nogil | ||
| CK_RV C_EncryptFinal(CK_SESSION_HANDLE session, | ||
| CK_BYTE *part_out, | ||
| CK_ULONG *part_out_len) nogil | ||
| CK_RV C_DecryptInit(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_Decrypt(CK_SESSION_HANDLE session, | ||
| CK_BYTE *ciphertext, | ||
| CK_ULONG ciphertext_len, | ||
| CK_BYTE *plaintext, | ||
| CK_ULONG *plaintext_len) nogil | ||
| CK_RV C_DecryptUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *part_in, | ||
| CK_ULONG part_in_len, | ||
| CK_BYTE *part_out, | ||
| CK_ULONG *part_out_len) nogil | ||
| CK_RV C_DecryptFinal(CK_SESSION_HANDLE session, | ||
| CK_BYTE *part_out, | ||
| CK_ULONG *part_out_len) nogil | ||
| ## Message digests | ||
| CK_RV C_DigestInit(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism) nogil | ||
| CK_RV C_Digest(CK_SESSION_HANDLE session, | ||
| CK_BYTE *data, | ||
| CK_ULONG data_len, | ||
| CK_BYTE *digest, | ||
| CK_ULONG *digest_len) nogil | ||
| CK_RV C_DigestUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *data, | ||
| CK_ULONG data_len) nogil | ||
| CK_RV C_DigestKey(CK_SESSION_HANDLE session, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_DigestFinal(CK_SESSION_HANDLE session, | ||
| CK_BYTE *digest, | ||
| CK_ULONG *digest_len) nogil | ||
| ## Signing and MACing | ||
| CK_RV C_SignInit(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_Sign(CK_SESSION_HANDLE session, | ||
| CK_BYTE *text, | ||
| CK_ULONG text_len, | ||
| CK_BYTE *signature, | ||
| CK_ULONG *sig_len) nogil | ||
| CK_RV C_SignUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *part, | ||
| CK_ULONG part_len) nogil | ||
| CK_RV C_SignFinal(CK_SESSION_HANDLE session, | ||
| CK_BYTE *signature, | ||
| CK_ULONG *sig_len) nogil | ||
| CK_RV C_SignRecoverInit(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_SignRecover(CK_SESSION_HANDLE session, | ||
| CK_BYTE *text, | ||
| CK_ULONG text_len, | ||
| CK_BYTE *signature, | ||
| CK_ULONG *sig_len) nogil | ||
| ## Verifying signatures and MACs | ||
| CK_RV C_VerifyInit(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_Verify(CK_SESSION_HANDLE session, | ||
| CK_BYTE *text, | ||
| CK_ULONG text_len, | ||
| CK_BYTE *signature, | ||
| CK_ULONG sig_len) nogil | ||
| CK_RV C_VerifyUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *text, | ||
| CK_ULONG text_len) nogil | ||
| CK_RV C_VerifyFinal(CK_SESSION_HANDLE session, | ||
| CK_BYTE *signature, | ||
| CK_ULONG sig_len) nogil | ||
| CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_VerifyRecover(CK_SESSION_HANDLE session, | ||
| CK_BYTE *text, | ||
| CK_ULONG text_len, | ||
| CK_BYTE *signature, | ||
| CK_ULONG sig_len) nogil | ||
| ## dual-function crypto operations | ||
| CK_RV C_DigestEncryptUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *data, | ||
| CK_ULONG data_len, | ||
| CK_BYTE *encrypted, | ||
| CK_ULONG *encrypted_len) nogil | ||
| CK_RV C_DecryptDigestUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *encrypted, | ||
| CK_ULONG encrypted_len, | ||
| CK_BYTE *data, | ||
| CK_ULONG *data_len) nogil | ||
| CK_RV C_SignEncryptUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *part, | ||
| CK_ULONG part_len) nogil | ||
| CK_RV C_DecryptVerifyUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *text, | ||
| CK_ULONG text_len) nogil | ||
| ## key management | ||
| CK_RV C_GenerateKey(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_ATTRIBUTE *template, | ||
| CK_ULONG count, | ||
| CK_OBJECT_HANDLE *key) nogil | ||
| CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_ATTRIBUTE *public_template, | ||
| CK_ULONG public_count, | ||
| CK_ATTRIBUTE *private_template, | ||
| CK_ULONG private_count, | ||
| CK_OBJECT_HANDLE *public_key, | ||
| CK_OBJECT_HANDLE *private_key) nogil | ||
| CK_RV C_WrapKey(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE wrapping_key, | ||
| CK_OBJECT_HANDLE key_to_wrap, | ||
| CK_BYTE *wrapped_key, | ||
| CK_ULONG *wrapped_key_len) nogil | ||
| CK_RV C_UnwrapKey(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE unwrapping_key, | ||
| CK_BYTE *wrapped_key, | ||
| CK_ULONG wrapped_key_len, | ||
| CK_ATTRIBUTE *attrs, | ||
| CK_ULONG attr_len, | ||
| CK_OBJECT_HANDLE *unwrapped_key) nogil | ||
| CK_RV C_DeriveKey(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE src_key, | ||
| CK_ATTRIBUTE *template, | ||
| CK_ULONG count, | ||
| CK_OBJECT_HANDLE *new_key) nogil | ||
| ## random number generation | ||
| CK_RV C_SeedRandom(CK_SESSION_HANDLE session, | ||
| CK_BYTE *seed, | ||
| CK_ULONG length) nogil | ||
| CK_RV C_GenerateRandom(CK_SESSION_HANDLE session, | ||
| CK_BYTE *random, | ||
| CK_ULONG length) nogil | ||
| ## parallel processing | ||
| CK_RV C_GetFunctionStatus(CK_SESSION_HANDLE session) nogil | ||
| CK_RV C_CancelFunction(CK_SESSION_HANDLE session) nogil | ||
| ## smart card events | ||
| CK_RV C_WaitForSlotEvent(CK_FLAGS flags, | ||
| CK_SLOT_ID *slot, | ||
| void *pRserved) nogil | ||
| # The only external API call that must be defined in a PKCS#11 library | ||
| # All other APIs are taken from the CK_FUNCTION_LIST table | ||
| ctypedef CK_RV (*C_GetFunctionList_ptr) (CK_FUNCTION_LIST **) nogil | ||
| cdef inline CK_BYTE_buffer(length): | ||
| """Make a buffer for `length` CK_BYTEs.""" | ||
| return array(shape=(length,), itemsize=sizeof(CK_BYTE), format='B') | ||
| cdef inline CK_ULONG_buffer(length): | ||
| """Make a buffer for `length` CK_ULONGs.""" | ||
| return array(shape=(length,), itemsize=sizeof(CK_ULONG), format='L') | ||
| cdef inline bytes _pack_attribute(key, value): | ||
| """Pack a Attribute value into a bytes array.""" | ||
| try: | ||
| pack, _ = ATTRIBUTE_TYPES[key] | ||
| return pack(value) | ||
| except KeyError: | ||
| raise NotImplementedError("Can't pack this %s. " | ||
| "Expand ATTRIBUTE_TYPES!" % key) | ||
| cdef inline _unpack_attributes(key, value): | ||
| """Unpack a Attribute bytes array into a Python value.""" | ||
| try: | ||
| _, unpack = ATTRIBUTE_TYPES[key] | ||
| return unpack(bytes(value)) | ||
| except KeyError: | ||
| raise NotImplementedError("Can't unpack this %s. " | ||
| "Expand ATTRIBUTE_TYPES!" % key) |
| [build-system] | ||
| requires = ["setuptools>=80.8", "cython", "setuptools-scm>=8.3.1"] | ||
| build-backend = "setuptools.build_meta" | ||
| [project] | ||
| name = "python-pkcs11" | ||
| description = "PKCS#11 support for Python" | ||
| readme = "README.rst" | ||
| authors = [ | ||
| {name = "Andrey Kislyuk", email = "kislyuk@gmail.com"}, | ||
| {name = "Danielle Madeley", email = "danielle@madeley.id.au"}, | ||
| ] | ||
| maintainers = [ | ||
| {name = "Andrey Kislyuk", email = "kislyuk@gmail.com"}, | ||
| ] | ||
| classifiers = [ | ||
| "Programming Language :: Python", | ||
| "Programming Language :: Python :: 3", | ||
| "Programming Language :: Python :: 3.9", | ||
| "Programming Language :: Python :: 3.10", | ||
| "Programming Language :: Python :: 3.11", | ||
| "Programming Language :: Python :: 3.12", | ||
| "Programming Language :: Python :: 3.13", | ||
| "Topic :: Security :: Cryptography", | ||
| ] | ||
| dependencies = ["asn1crypto>=1.5.1"] | ||
| license = "MIT" | ||
| requires-python = ">=3.9" | ||
| dynamic = ["version"] | ||
| [project.urls] | ||
| Homepage = "https://python-pkcs11.readthedocs.io/en/latest/" | ||
| Documentation = "https://python-pkcs11.readthedocs.io/en/latest/" | ||
| Issues = "https://github.com/pyauth/python-pkcs11/issues" | ||
| Repository = "https://github.com/pyauth/python-pkcs11" | ||
| [tool.ruff] | ||
| line-length = 100 | ||
| [tool.ruff.lint] | ||
| extend-select = [ | ||
| "B", # flake8-bugbear | ||
| "E", # pycodestyle | ||
| "F", # pyflakes | ||
| "I", # isort | ||
| "G", # flake8-logging-format | ||
| "RUF", # ruff specific checks | ||
| ] | ||
| [tool.ruff.lint.isort] | ||
| combine-as-imports = true | ||
| [tool.setuptools] | ||
| ext-modules = [ | ||
| {name = "pkcs11._pkcs11", sources = ["pkcs11/_pkcs11.pyx"]} | ||
| ] | ||
| [tool.cibuildwheel.linux] | ||
| archs = ["auto64"] | ||
| [tool.cibuildwheel.windows] | ||
| archs = ["AMD64"] | ||
| [tool.cibuildwheel.macos] | ||
| archs = ["universal2"] | ||
| [tool.setuptools.packages.find] | ||
| include = ["pkcs11*"] | ||
| [dependency-groups] | ||
| testing = [ | ||
| "cryptography>=44.0.0", | ||
| "parameterized>=0.9.0", | ||
| "pytest>=8.3.4", | ||
| ] | ||
| docs = [ | ||
| "sphinx>=7.4.7", | ||
| "sphinx-rtd-theme>=3.0.2", | ||
| ] | ||
| lint = [ | ||
| "ruff>=0.8.3", | ||
| ] | ||
| release = [ | ||
| "setuptools>=80.8", | ||
| "setuptools-scm>=8.3.1", | ||
| "cython", | ||
| ] | ||
| docs-build = [ | ||
| { include-group = "docs" }, | ||
| "python-pkcs11", | ||
| ] | ||
| dev = [ | ||
| { include-group = "docs" }, | ||
| { include-group = "testing" }, | ||
| { include-group = "lint" }, | ||
| { include-group = "release" }, | ||
| ] | ||
| [tool.setuptools_scm] |
Sorry, the diff of this file is too big to display
+1
-1
| *.so | ||
| *.c | ||
| __pycache__ | ||
| .idea/ | ||
| /build | ||
@@ -6,0 +6,0 @@ /dist/ |
+11
-0
@@ -62,2 +62,13 @@ API Reference | ||
| .. method:: wait_for_slot_event(blocking=True) | ||
| Waits for a slot event such as a token insertion or removal to occur. | ||
| Returns the Slot on which the event was detected. If not blocking and no slot events were detected | ||
| :class:`pkcs11.exceptions.NoEvent` is raised. | ||
| :param blocking: If true, the thread will block. | ||
| :rtype: Slot | ||
| .. method:: reinitialize() | ||
@@ -64,0 +75,0 @@ |
+37
-34
@@ -22,5 +22,6 @@ #!/usr/bin/env python3 | ||
| import sys | ||
| import sphinx_rtd_theme | ||
| sys.path.insert(0, os.path.abspath('..')) | ||
| sys.path.insert(0, os.path.abspath("..")) | ||
@@ -38,13 +39,13 @@ | ||
| extensions = [ | ||
| 'sphinx.ext.autodoc', | ||
| 'sphinx.ext.coverage', | ||
| 'sphinx.ext.intersphinx', | ||
| "sphinx.ext.autodoc", | ||
| "sphinx.ext.coverage", | ||
| "sphinx.ext.intersphinx", | ||
| ] | ||
| autodoc_member_order = 'bysource' | ||
| autodoc_member_order = "bysource" | ||
| intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} | ||
| intersphinx_mapping = {"python": ("https://docs.python.org/3", None)} | ||
| # Add any paths that contain templates here, relative to this directory. | ||
| templates_path = ['_templates'] | ||
| templates_path = ["_templates"] | ||
@@ -55,11 +56,11 @@ # The suffix(es) of source filenames. | ||
| # source_suffix = ['.rst', '.md'] | ||
| source_suffix = '.rst' | ||
| source_suffix = ".rst" | ||
| # The master toctree document. | ||
| master_doc = 'index' | ||
| master_doc = "index" | ||
| # General information about the project. | ||
| project = 'Python PKCS#11' | ||
| copyright = '2017, Danielle Madeley' | ||
| author = 'Danielle Madeley' | ||
| project = "Python PKCS#11" | ||
| copyright = "2017, Danielle Madeley" | ||
| author = "Danielle Madeley" | ||
@@ -71,5 +72,5 @@ # The version info for the project you're documenting, acts as replacement for | ||
| # The short X.Y version. | ||
| version = '' | ||
| version = "" | ||
| # The full version, including alpha/beta/rc tags. | ||
| release = '' | ||
| release = "" | ||
@@ -86,6 +87,6 @@ # The language for content autogenerated by Sphinx. Refer to documentation | ||
| # This patterns also effect to html_static_path and html_extra_path | ||
| exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] | ||
| exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] | ||
| # The name of the Pygments (syntax highlighting) style to use. | ||
| pygments_style = 'sphinx' | ||
| pygments_style = "sphinx" | ||
@@ -101,3 +102,3 @@ # If true, `todo` and `todoList` produce output, else they produce nothing. | ||
| # | ||
| html_theme = 'sphinx_rtd_theme' | ||
| html_theme = "sphinx_rtd_theme" | ||
| html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] | ||
@@ -114,3 +115,3 @@ | ||
| # so a file named "default.css" will overwrite the builtin "default.css". | ||
| html_static_path = ['_static'] | ||
| html_static_path = ["_static"] | ||
@@ -121,3 +122,3 @@ | ||
| # Output file base name for HTML help builder. | ||
| htmlhelp_basename = 'PythonPKCS11doc' | ||
| htmlhelp_basename = "PythonPKCS11doc" | ||
@@ -131,11 +132,8 @@ | ||
| # 'papersize': 'letterpaper', | ||
| # The font size ('10pt', '11pt' or '12pt'). | ||
| # | ||
| # 'pointsize': '10pt', | ||
| # Additional stuff for the LaTeX preamble. | ||
| # | ||
| # 'preamble': '', | ||
| # Latex figure (float) alignment | ||
@@ -150,4 +148,9 @@ # | ||
| latex_documents = [ | ||
| (master_doc, 'PythonPKCS11.tex', 'Python PKCS\\#11 Documentation', | ||
| 'Danielle Madeley', 'manual'), | ||
| ( | ||
| master_doc, | ||
| "PythonPKCS11.tex", | ||
| "Python PKCS\\#11 Documentation", | ||
| "Danielle Madeley", | ||
| "manual", | ||
| ), | ||
| ] | ||
@@ -160,6 +163,3 @@ | ||
| # (source start file, name, description, authors, manual section). | ||
| man_pages = [ | ||
| (master_doc, 'pythonpkcs11', 'Python PKCS#11 Documentation', | ||
| [author], 1) | ||
| ] | ||
| man_pages = [(master_doc, "pythonpkcs11", "Python PKCS#11 Documentation", [author], 1)] | ||
@@ -173,8 +173,11 @@ | ||
| texinfo_documents = [ | ||
| (master_doc, 'PythonPKCS11', 'Python PKCS#11 Documentation', | ||
| author, 'PythonPKCS11', 'One line description of project.', | ||
| 'Miscellaneous'), | ||
| ( | ||
| master_doc, | ||
| "PythonPKCS11", | ||
| "Python PKCS#11 Documentation", | ||
| author, | ||
| "PythonPKCS11", | ||
| "One line description of project.", | ||
| "Miscellaneous", | ||
| ), | ||
| ] | ||
+4
-4
@@ -5,4 +5,4 @@ # Minimal makefile for Sphinx documentation | ||
| # You can set these variables from the command line. | ||
| SPHINXOPTS = | ||
| SPHINXBUILD = python -msphinx | ||
| SPHINXOPTS ?= | ||
| SPHINXBUILD ?= sphinx-build | ||
| SPHINXPROJ = PythonPKCS11 | ||
@@ -14,3 +14,3 @@ SOURCEDIR = . | ||
| help: | ||
| @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) | ||
| @uv run --no-dev --group docs-build $(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) | ||
@@ -22,2 +22,2 @@ .PHONY: help Makefile | ||
| %: Makefile | ||
| @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) | ||
| @uv run --no-dev --group docs-build $(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) |
+1
-1
@@ -178,3 +178,3 @@ Using with SmartCard-HSM (Nitrokey HSM) | ||
| # interchange | ||
| bob_priv = ec.generate_private_key(ec.SECP256R1, | ||
| bob_priv = ec.generate_private_key(ec.SECP256R1(), | ||
| default_backend()) | ||
@@ -181,0 +181,0 @@ bob_pub = bob_priv.public_key().public_bytes( |
+33
-49
@@ -1,11 +0,14 @@ | ||
| /* Copyright (c) OASIS Open 2016. All Rights Reserved./ | ||
| /* | ||
| * PKCS #11 Specification Version 3.1 | ||
| * OASIS Standard | ||
| * 23 July 2023 | ||
| * Copyright (c) OASIS Open 2023. All Rights Reserved. | ||
| * Source: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/include/pkcs11-v3.1/ | ||
| * Latest stage of narrative specification: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/pkcs11-spec-v3.1.html | ||
| * TC IPR Statement: https://www.oasis-open.org/committees/pkcs11/ipr.php | ||
| * /Distributed under the terms of the OASIS IPR Policy, | ||
| * [http://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY | ||
| * [https://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY | ||
| * IMPLIED OR EXPRESS WARRANTY; there is no warranty of MERCHANTABILITY, FITNESS FOR A | ||
| * PARTICULAR PURPOSE or NONINFRINGEMENT of the rights of others. | ||
| */ | ||
| /* Latest version of the specification: | ||
| * http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html | ||
| */ | ||
@@ -32,4 +35,3 @@ #ifndef _PKCS11_H_ | ||
| * | ||
| * If you're using Microsoft Developer Studio 5.0 to produce | ||
| * Win32 stuff, this might be done by using the following | ||
| * If you're using Windows this might be done by using the following | ||
| * preprocessor directive before including pkcs11.h or pkcs11t.h: | ||
@@ -44,9 +46,2 @@ * | ||
| * | ||
| * If you're using an earlier version of Microsoft Developer | ||
| * Studio to produce Win16 stuff, this might be done by using | ||
| * the following preprocessor directive before including | ||
| * pkcs11.h or pkcs11t.h: | ||
| * | ||
| * #pragma pack(1) | ||
| * | ||
| * In a UNIX environment, you're on your own for this. You might | ||
@@ -64,12 +59,6 @@ * not need to do (or be able to do!) anything. | ||
| * | ||
| * If you're using Microsoft Developer Studio 5.0 to produce | ||
| * Win32 stuff, it might be defined by: | ||
| * If you're using Windows, it might be defined by: | ||
| * | ||
| * #define CK_PTR * | ||
| * | ||
| * If you're using an earlier version of Microsoft Developer | ||
| * Studio to produce Win16 stuff, it might be defined by: | ||
| * | ||
| * #define CK_PTR far * | ||
| * | ||
| * In a typical UNIX environment, it might be defined by: | ||
@@ -89,4 +78,4 @@ * | ||
| * | ||
| * If you're using Microsoft Developer Studio 5.0 to declare a | ||
| * function in a Win32 Cryptoki .dll, it might be defined by: | ||
| * If you're using Windows to declare a function in a Win32 Cryptoki .dll, | ||
| * it might be defined by: | ||
| * | ||
@@ -96,9 +85,2 @@ * #define CK_DECLARE_FUNCTION(returnType, name) \ | ||
| * | ||
| * If you're using an earlier version of Microsoft Developer | ||
| * Studio to declare a function in a Win16 Cryptoki .dll, it | ||
| * might be defined by: | ||
| * | ||
| * #define CK_DECLARE_FUNCTION(returnType, name) \ | ||
| * returnType __export _far _pascal name | ||
| * | ||
| * In a UNIX environment, it might be defined by: | ||
@@ -128,3 +110,3 @@ * | ||
| * | ||
| * If you're using Microsoft Developer Studio 5.0 to access | ||
| * If you're using Windows to access | ||
| * functions in a Win32 Cryptoki .dll, in might be defined by: | ||
@@ -135,9 +117,2 @@ * | ||
| * | ||
| * If you're using an earlier version of Microsoft Developer | ||
| * Studio to access functions in a Win16 Cryptoki .dll, it might | ||
| * be defined by: | ||
| * | ||
| * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ | ||
| * returnType __export _far _pascal (* name) | ||
| * | ||
| * In a UNIX environment, it might be defined by: | ||
@@ -163,4 +138,3 @@ * | ||
| * | ||
| * If you're using Microsoft Developer Studio 5.0 to do Win32 | ||
| * Cryptoki development, it might be defined by: | ||
| * If you're using Windows, it might be defined by: | ||
| * | ||
@@ -170,8 +144,2 @@ * #define CK_CALLBACK_FUNCTION(returnType, name) \ | ||
| * | ||
| * If you're using an earlier version of Microsoft Developer | ||
| * Studio to do Win16 development, it might be defined by: | ||
| * | ||
| * #define CK_CALLBACK_FUNCTION(returnType, name) \ | ||
| * returnType _far _pascal (* name) | ||
| * | ||
| * In a UNIX environment, it might be defined by: | ||
@@ -252,2 +220,18 @@ * | ||
| /* Create the 3.0 Function list */ | ||
| struct CK_FUNCTION_LIST_3_0 { | ||
| CK_VERSION version; /* Cryptoki version */ | ||
| /* Pile all the function pointers into the CK_FUNCTION_LIST. */ | ||
| /* pkcs11f.h has all the information about the Cryptoki | ||
| * function prototypes. | ||
| */ | ||
| #include "pkcs11f.h" | ||
| }; | ||
| #define CK_PKCS11_2_0_ONLY 1 | ||
| /* Continue to define the old CK_FUNCTION_LIST */ | ||
| struct CK_FUNCTION_LIST { | ||
@@ -266,2 +250,3 @@ | ||
| #undef CK_PKCS11_FUNCTION_INFO | ||
| #undef CK_PKCS11_2_0_ONLY | ||
@@ -275,3 +260,2 @@ | ||
| #endif /* _PKCS11_H_ */ | ||
| #endif /* _PKCS11_H_ */ |
+266
-6
@@ -1,11 +0,14 @@ | ||
| /* Copyright (c) OASIS Open 2016. All Rights Reserved./ | ||
| /* | ||
| * PKCS #11 Specification Version 3.1 | ||
| * OASIS Standard | ||
| * 23 July 2023 | ||
| * Copyright (c) OASIS Open 2023. All Rights Reserved. | ||
| * Source: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/include/pkcs11-v3.1/ | ||
| * Latest stage of narrative specification: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/pkcs11-spec-v3.1.html | ||
| * TC IPR Statement: https://www.oasis-open.org/committees/pkcs11/ipr.php | ||
| * /Distributed under the terms of the OASIS IPR Policy, | ||
| * [http://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY | ||
| * [https://www.oasis-open.org/policies-guidelines/ipr], AS-IS, WITHOUT ANY | ||
| * IMPLIED OR EXPRESS WARRANTY; there is no warranty of MERCHANTABILITY, FITNESS FOR A | ||
| * PARTICULAR PURPOSE or NONINFRINGEMENT of the rights of others. | ||
| */ | ||
| /* Latest version of the specification: | ||
| * http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html | ||
| */ | ||
@@ -940,1 +943,258 @@ /* This header file contains pretty much everything about all the | ||
| #ifndef CK_PKCS11_2_0_ONLY | ||
| /* C_GetInterfaceList returns all the interfaces supported by the module*/ | ||
| CK_PKCS11_FUNCTION_INFO(C_GetInterfaceList) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_INTERFACE_PTR pInterfacesList, /* returned interfaces */ | ||
| CK_ULONG_PTR pulCount /* number of interfaces returned */ | ||
| ); | ||
| #endif | ||
| /* C_GetInterface returns a specific interface from the module. */ | ||
| CK_PKCS11_FUNCTION_INFO(C_GetInterface) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_UTF8CHAR_PTR pInterfaceName, /* name of the interface */ | ||
| CK_VERSION_PTR pVersion, /* version of the interface */ | ||
| CK_INTERFACE_PTR_PTR ppInterface, /* returned interface */ | ||
| CK_FLAGS flags /* flags controlling the semantics | ||
| * of the interface */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_LoginUser) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_USER_TYPE userType, /* the user type */ | ||
| CK_UTF8CHAR_PTR pPin, /* the user's PIN */ | ||
| CK_ULONG ulPinLen, /* the length of the PIN */ | ||
| CK_UTF8CHAR_PTR pUsername, /* the user's name */ | ||
| CK_ULONG ulUsernameLen /*the length of the user's name */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_SessionCancel) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_FLAGS flags /* flags control which sessions are cancelled */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_MessageEncryptInit) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */ | ||
| CK_OBJECT_HANDLE hKey /* handle of encryption key */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_EncryptMessage) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_VOID_PTR pParameter, /* message specific parameter */ | ||
| CK_ULONG ulParameterLen, /* length of message specific parameter */ | ||
| CK_BYTE_PTR pAssociatedData, /* AEAD Associated data */ | ||
| CK_ULONG ulAssociatedDataLen, /* AEAD Associated data length */ | ||
| CK_BYTE_PTR pPlaintext, /* plain text */ | ||
| CK_ULONG ulPlaintextLen, /* plain text length */ | ||
| CK_BYTE_PTR pCiphertext, /* gets cipher text */ | ||
| CK_ULONG_PTR pulCiphertextLen /* gets cipher text length */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_EncryptMessageBegin) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_VOID_PTR pParameter, /* message specific parameter */ | ||
| CK_ULONG ulParameterLen, /* length of message specific parameter */ | ||
| CK_BYTE_PTR pAssociatedData, /* AEAD Associated data */ | ||
| CK_ULONG ulAssociatedDataLen /* AEAD Associated data length */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_EncryptMessageNext) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_VOID_PTR pParameter, /* message specific parameter */ | ||
| CK_ULONG ulParameterLen, /* length of message specific parameter */ | ||
| CK_BYTE_PTR pPlaintextPart, /* plain text */ | ||
| CK_ULONG ulPlaintextPartLen, /* plain text length */ | ||
| CK_BYTE_PTR pCiphertextPart, /* gets cipher text */ | ||
| CK_ULONG_PTR pulCiphertextPartLen, /* gets cipher text length */ | ||
| CK_FLAGS flags /* multi mode flag */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_MessageEncryptFinal) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession /* the session's handle */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_MessageDecryptInit) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */ | ||
| CK_OBJECT_HANDLE hKey /* handle of decryption key */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_DecryptMessage) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_VOID_PTR pParameter, /* message specific parameter */ | ||
| CK_ULONG ulParameterLen, /* length of message specific parameter */ | ||
| CK_BYTE_PTR pAssociatedData, /* AEAD Associated data */ | ||
| CK_ULONG ulAssociatedDataLen, /* AEAD Associated data length */ | ||
| CK_BYTE_PTR pCiphertext, /* cipher text */ | ||
| CK_ULONG ulCiphertextLen, /* cipher text length */ | ||
| CK_BYTE_PTR pPlaintext, /* gets plain text */ | ||
| CK_ULONG_PTR pulPlaintextLen /* gets plain text length */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_DecryptMessageBegin) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_VOID_PTR pParameter, /* message specific parameter */ | ||
| CK_ULONG ulParameterLen, /* length of message specific parameter */ | ||
| CK_BYTE_PTR pAssociatedData, /* AEAD Associated data */ | ||
| CK_ULONG ulAssociatedDataLen /* AEAD Associated data length */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_DecryptMessageNext) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_VOID_PTR pParameter, /* message specific parameter */ | ||
| CK_ULONG ulParameterLen, /* length of message specific parameter */ | ||
| CK_BYTE_PTR pCiphertextPart, /* cipher text */ | ||
| CK_ULONG ulCiphertextPartLen, /* cipher text length */ | ||
| CK_BYTE_PTR pPlaintextPart, /* gets plain text */ | ||
| CK_ULONG_PTR pulPlaintextPartLen, /* gets plain text length */ | ||
| CK_FLAGS flags /* multi mode flag */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_MessageDecryptFinal) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession /* the session's handle */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_MessageSignInit) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_MECHANISM_PTR pMechanism, /* the signing mechanism */ | ||
| CK_OBJECT_HANDLE hKey /* handle of signing key */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_SignMessage) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_VOID_PTR pParameter, /* message specific parameter */ | ||
| CK_ULONG ulParameterLen, /* length of message specific parameter */ | ||
| CK_BYTE_PTR pData, /* data to sign */ | ||
| CK_ULONG ulDataLen, /* data to sign length */ | ||
| CK_BYTE_PTR pSignature, /* gets signature */ | ||
| CK_ULONG_PTR pulSignatureLen /* gets signature length */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_SignMessageBegin) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_VOID_PTR pParameter, /* message specific parameter */ | ||
| CK_ULONG ulParameterLen /* length of message specific parameter */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_SignMessageNext) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_VOID_PTR pParameter, /* message specific parameter */ | ||
| CK_ULONG ulParameterLen, /* length of message specific parameter */ | ||
| CK_BYTE_PTR pData, /* data to sign */ | ||
| CK_ULONG ulDataLen, /* data to sign length */ | ||
| CK_BYTE_PTR pSignature, /* gets signature */ | ||
| CK_ULONG_PTR pulSignatureLen /* gets signature length */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_MessageSignFinal) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession /* the session's handle */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_MessageVerifyInit) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_MECHANISM_PTR pMechanism, /* the signing mechanism */ | ||
| CK_OBJECT_HANDLE hKey /* handle of signing key */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_VerifyMessage) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_VOID_PTR pParameter, /* message specific parameter */ | ||
| CK_ULONG ulParameterLen, /* length of message specific parameter */ | ||
| CK_BYTE_PTR pData, /* data to sign */ | ||
| CK_ULONG ulDataLen, /* data to sign length */ | ||
| CK_BYTE_PTR pSignature, /* signature */ | ||
| CK_ULONG ulSignatureLen /* signature length */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_VerifyMessageBegin) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_VOID_PTR pParameter, /* message specific parameter */ | ||
| CK_ULONG ulParameterLen /* length of message specific parameter */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_VerifyMessageNext) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession, /* the session's handle */ | ||
| CK_VOID_PTR pParameter, /* message specific parameter */ | ||
| CK_ULONG ulParameterLen, /* length of message specific parameter */ | ||
| CK_BYTE_PTR pData, /* data to sign */ | ||
| CK_ULONG ulDataLen, /* data to sign length */ | ||
| CK_BYTE_PTR pSignature, /* signature */ | ||
| CK_ULONG ulSignatureLen /* signature length */ | ||
| ); | ||
| #endif | ||
| CK_PKCS11_FUNCTION_INFO(C_MessageVerifyFinal) | ||
| #ifdef CK_NEED_ARG_LIST | ||
| ( | ||
| CK_SESSION_HANDLE hSession /* the session's handle */ | ||
| ); | ||
| #endif | ||
| #endif /* CK_PKCS11_2_0_ONLY */ |
@@ -9,4 +9,4 @@ """ | ||
| from .types import * # noqa: F403 | ||
| from .util import dh, dsa, ec, rsa, x509 # noqa: F401 | ||
| _so = None | ||
@@ -27,3 +27,4 @@ _lib = None | ||
| raise AlreadyInitialized( # noqa: F405 | ||
| "Already initialized with %s" % so) | ||
| "Already initialized with %s" % _so | ||
| ) | ||
| else: | ||
@@ -30,0 +31,0 @@ return _lib |
+11
-11
@@ -8,8 +8,4 @@ """ | ||
| try: | ||
| from enum import IntEnum, IntFlag, unique | ||
| except ImportError: | ||
| from aenum import IntEnum, IntFlag, unique | ||
| from enum import IntEnum, IntFlag, unique | ||
| DEFAULT = object() | ||
@@ -44,2 +40,3 @@ """Sentinel value used in templates. | ||
| """ | ||
| DATA = 0x00000000 | ||
@@ -59,2 +56,3 @@ CERTIFICATE = 0x00000001 | ||
| OTP_KEY = 0x00000008 | ||
| PROFILE = 0x00000009 | ||
@@ -64,3 +62,3 @@ _VENDOR_DEFINED = 0x80000000 | ||
| def __repr__(self): | ||
| return '<ObjectClass.%s>' % self.name | ||
| return "<ObjectClass.%s>" % self.name | ||
@@ -305,5 +303,5 @@ | ||
| """Key can only be wrapped with a `TRUSTED` key.""" | ||
| WRAP_TEMPLATE = (_ARRAY_ATTRIBUTE | 0x00000211) | ||
| UNWRAP_TEMPLATE = (_ARRAY_ATTRIBUTE | 0x00000212) | ||
| DERIVE_TEMPLATE = (_ARRAY_ATTRIBUTE | 0x00000213) | ||
| WRAP_TEMPLATE = _ARRAY_ATTRIBUTE | 0x00000211 | ||
| UNWRAP_TEMPLATE = _ARRAY_ATTRIBUTE | 0x00000212 | ||
| DERIVE_TEMPLATE = _ARRAY_ATTRIBUTE | 0x00000213 | ||
@@ -347,3 +345,3 @@ OTP_FORMAT = 0x00000220 | ||
| SUPPORTED_CMS_ATTRIBUTES = 0x00000503 | ||
| ALLOWED_MECHANISMS = (_ARRAY_ATTRIBUTE | 0x00000600) | ||
| ALLOWED_MECHANISMS = _ARRAY_ATTRIBUTE | 0x00000600 | ||
@@ -353,3 +351,3 @@ _VENDOR_DEFINED = 0x80000000 | ||
| def __repr__(self): | ||
| return '<Attribute.%s>' % self.name | ||
| return "<Attribute.%s>" % self.name | ||
@@ -361,2 +359,3 @@ | ||
| """ | ||
| X_509 = 0x00000000 | ||
@@ -377,2 +376,3 @@ X_509_ATTR_CERT = 0x00000001 | ||
| """ | ||
| HW = 0x00000001 | ||
@@ -379,0 +379,0 @@ """Mechanism is performed in hardware.""" |
+10
-9
@@ -17,5 +17,4 @@ """ | ||
| ) | ||
| from .mechanisms import Mechanism, KeyType, MGF | ||
| from .mechanisms import MGF, KeyType, Mechanism | ||
| DEFAULT_GENERATE_MECHANISMS = { | ||
@@ -31,2 +30,3 @@ KeyType.AES: Mechanism.AES_KEY_GEN, | ||
| KeyType.EC_EDWARDS: Mechanism.EC_EDWARDS_KEY_PAIR_GEN, | ||
| KeyType.GENERIC_SECRET: Mechanism.GENERIC_SECRET_KEY_GEN, | ||
| } | ||
@@ -118,7 +118,9 @@ """ | ||
| # (Pack Function, Unpack Function) functions | ||
| _bool = (Struct('?').pack, lambda v: Struct('?').unpack(v)[0]) | ||
| _ulong = (Struct('L').pack, lambda v: Struct('L').unpack(v)[0]) | ||
| _str = (lambda s: s.encode('utf-8'), lambda b: b.decode('utf-8')) | ||
| _date = (lambda s: s.strftime('%Y%m%d').encode('ascii'), | ||
| lambda s: datetime.strptime(s.decode('ascii'), '%Y%m%d').date()) | ||
| _bool = (Struct("?").pack, lambda v: Struct("?").unpack(v)[0]) | ||
| _ulong = (Struct("L").pack, lambda v: Struct("L").unpack(v)[0]) | ||
| _str = (lambda s: s.encode("utf-8"), lambda b: b.decode("utf-8")) | ||
| _date = ( | ||
| lambda s: s.strftime("%Y%m%d").encode("ascii"), | ||
| lambda s: datetime.strptime(s.decode("ascii"), "%Y%m%d").date(), | ||
| ) | ||
| _bytes = (bytes, bytes) | ||
@@ -134,4 +136,3 @@ # The PKCS#11 biginteger type is an array of bytes in network byte order. | ||
| return (lambda v: pack(int(v)), | ||
| lambda v: type_(unpack(v))) | ||
| return (lambda v: pack(int(v)), lambda v: type_(unpack(v))) | ||
@@ -138,0 +139,0 @@ |
+14
-8
@@ -64,3 +64,3 @@ """ | ||
| The plaintext input data to a cryptographic operation has a bad length. | ||
| Depending on the operation’s mechanism, this could mean that the plaintext | ||
| Depending on the operation's mechanism, this could mean that the plaintext | ||
| data is too short, too long, or is not a multiple of some particular block | ||
@@ -107,3 +107,3 @@ size. | ||
| invalid ciphertext solely on the basis of its length. Depending on the | ||
| operation’s mechanism, this could mean that the ciphertext is too short, | ||
| operation's mechanism, this could mean that the ciphertext is too short, | ||
| too long, or is not a multiple of some particular block size. | ||
@@ -171,7 +171,7 @@ """ | ||
| """ | ||
| In unusual (and extremely unpleasant!) circumstances, a function can fail | ||
| with the return value CKR_GENERAL_ERROR. When this happens, the token | ||
| and/or host computer may be in an inconsistent state, and the goals of the | ||
| function may have been partially achieved. | ||
| """ | ||
| In unusual (and extremely unpleasant!) circumstances, a function can fail | ||
| with the return value CKR_GENERAL_ERROR. When this happens, the token | ||
| and/or host computer may be in an inconsistent state, and the goals of the | ||
| function may have been partially achieved. | ||
| """ | ||
@@ -208,2 +208,8 @@ | ||
| class NoEvent(PKCS11Error): | ||
| """ | ||
| No slot events were detected. | ||
| """ | ||
| class NoSuchKey(PKCS11Error): | ||
@@ -233,3 +239,3 @@ """ | ||
| Cryptoki from activating a signature operation. Or, on a token which | ||
| doesn’t support simultaneous dual cryptographic operations in a session | ||
| doesn't support simultaneous dual cryptographic operations in a session | ||
| (see the description of the CKF_DUAL_CRYPTO_OPERATIONS flag in the | ||
@@ -236,0 +242,0 @@ CK_TOKEN_INFO structure), an active signature operation would prevent |
+56
-5
@@ -13,2 +13,3 @@ from enum import IntEnum | ||
| """ | ||
| RSA = 0x00000000 | ||
@@ -94,2 +95,6 @@ """ | ||
| SHA224_HMAC = 0x0000002E | ||
| SHA3_224_HMAC = 0x00000036 | ||
| SHA3_256_HMAC = 0x00000037 | ||
| SHA3_384_HMAC = 0x00000038 | ||
| SHA3_512_HMAC = 0x00000039 | ||
| SEED = 0x0000002F | ||
@@ -106,3 +111,3 @@ GOSTR3410 = 0x00000030 | ||
| def __repr__(self): | ||
| return '<KeyType.%s>' % self.name | ||
| return "<KeyType.%s>" % self.name | ||
@@ -197,2 +202,6 @@ | ||
| """ | ||
| SHA3_224_RSA_PKCS = 0x00000066 | ||
| SHA3_256_RSA_PKCS = 0x00000060 | ||
| SHA3_384_RSA_PKCS = 0x00000061 | ||
| SHA3_512_RSA_PKCS = 0x00000062 | ||
@@ -220,2 +229,6 @@ RSA_PKCS_PSS = 0x0000000D | ||
| SHA512_RSA_PKCS_PSS = 0x00000045 | ||
| SHA3_256_RSA_PKCS_PSS = 0x00000063 | ||
| SHA3_384_RSA_PKCS_PSS = 0x00000064 | ||
| SHA3_512_RSA_PKCS_PSS = 0x00000065 | ||
| SHA3_224_RSA_PKCS_PSS = 0x00000067 | ||
@@ -470,2 +483,9 @@ RSA_X9_31_KEY_PAIR_GEN = 0x0000000A | ||
| SHA3_256_KEY_DERIVATION = 0x00000397 | ||
| SHA3_224_KEY_DERIVATION = 0x00000398 | ||
| SHA3_384_KEY_DERIVATION = 0x00000399 | ||
| SHA3_512_KEY_DERIVATION = 0x0000039A | ||
| SHAKE_128_KEY_DERIVATION = 0x0000039B | ||
| SHAKE_256_KEY_DERIVATION = 0x0000039C | ||
| _PBE_MD2_DES_CBC = 0x000003A0 | ||
@@ -547,3 +567,3 @@ _PBE_MD5_DES_CBC = 0x000003A1 | ||
| _SKIPJACK_PRIVATE_WRAP = 0x00001009 | ||
| _SKIPJACK_RELAYX = 0x0000100a | ||
| _SKIPJACK_RELAYX = 0x0000100A | ||
@@ -669,2 +689,6 @@ _KEA_KEY_PAIR_GEN = 0x00001010 | ||
| AES_KEY_WRAP_PAD = 0x0000210A | ||
| AES_KEY_WRAP_KWP = 0x0000210B | ||
| """Bug: SoftHSMv2 mechanism AES_KEY_WRAP_PAD is actually AES_KEY_WRAP_KWP""" | ||
| AES_KEY_WRAP_PKCS7 = 0x0000210C | ||
| """PKCS #11 v3.1: AES_KEY_WRAP_PAD is deprecated due to confusion in implementation""" | ||
@@ -717,6 +741,23 @@ DES_ECB_ENCRYPT_DATA = 0x00001100 | ||
| SHA3_256 = 0x000002B0 | ||
| SHA3_256_HMAC = 0x000002B1 | ||
| SHA3_256_HMAC_GENERAL = 0x000002B2 | ||
| SHA3_256_KEY_GEN = 0x000002B3 | ||
| SHA3_224 = 0x000002B5 | ||
| SHA3_224_HMAC = 0x000002B6 | ||
| SHA3_224_HMAC_GENERAL = 0x000002B7 | ||
| SHA3_224_KEY_GEN = 0x000002B8 | ||
| SHA3_384 = 0x000002C0 | ||
| SHA3_384_HMAC = 0x000002C1 | ||
| SHA3_384_HMAC_GENERAL = 0x000002C2 | ||
| SHA3_384_KEY_GEN = 0x000002C3 | ||
| SHA3_512 = 0x000002D0 | ||
| SHA3_512_HMAC = 0x000002D1 | ||
| SHA3_512_HMAC_GENERAL = 0x000002D2 | ||
| SHA3_512_KEY_GEN = 0x000002D3 | ||
| _VENDOR_DEFINED = 0x80000000 | ||
| def __repr__(self): | ||
| return '<Mechanism.%s>' % self.name | ||
| return "<Mechanism.%s>" % self.name | ||
@@ -728,2 +769,3 @@ | ||
| """ | ||
| NULL = 0x00000001 | ||
@@ -739,5 +781,9 @@ SHA1 = 0x00000002 | ||
| CPDIVERSIFY = 0x00000009 | ||
| SHA3_224_KDF = 0x0000000A | ||
| SHA3_256_KDF = 0x0000000B | ||
| SHA3_384_KDF = 0x0000000C | ||
| SHA3_512_KDF = 0x0000000D | ||
| def __repr__(self): | ||
| return '<KDF.%s>' % self.name | ||
| return "<KDF.%s>" % self.name | ||
@@ -749,2 +795,3 @@ | ||
| """ | ||
| SHA1 = 0x00000001 | ||
@@ -755,4 +802,8 @@ SHA256 = 0x00000002 | ||
| SHA224 = 0x00000005 | ||
| SHA3_224 = 0x00000006 | ||
| SHA3_256 = 0x00000007 | ||
| SHA3_384 = 0x00000008 | ||
| SHA3_512 = 0x00000009 | ||
| def __repr__(self): | ||
| return '<MGF.%s>' % self.name | ||
| return "<MGF.%s>" % self.name |
+148
-114
@@ -7,6 +7,9 @@ """ | ||
| from binascii import hexlify | ||
| from threading import RLock | ||
| from binascii import hexlify | ||
| from cached_property import cached_property | ||
| try: | ||
| from functools import cached_property | ||
| except ImportError: | ||
| from cached_property import cached_property | ||
@@ -21,11 +24,11 @@ from .constants import ( | ||
| ) | ||
| from .mechanisms import KeyType, Mechanism | ||
| from .exceptions import ( | ||
| ArgumentsBad, | ||
| AttributeTypeInvalid, | ||
| MultipleObjectsReturned, | ||
| NoSuchKey, | ||
| MultipleObjectsReturned, | ||
| SignatureInvalid, | ||
| SignatureLenRange, | ||
| ) | ||
| from .mechanisms import KeyType, Mechanism | ||
@@ -35,5 +38,6 @@ PROTECTED_AUTH = object() | ||
| def _CK_UTF8CHAR_to_str(data): | ||
| """Convert CK_UTF8CHAR to string.""" | ||
| return data.decode('utf-8').rstrip() | ||
| return data.rstrip(b"\0").decode("utf-8").rstrip() | ||
@@ -43,3 +47,3 @@ | ||
| """Convert CK_VERSION to tuple.""" | ||
| return (data['major'], data['minor']) | ||
| return (data["major"], data["minor"]) | ||
@@ -62,10 +66,3 @@ | ||
| def __init__(self, | ||
| slot, | ||
| mechanism, | ||
| ulMinKeySize=None, | ||
| ulMaxKeySize=None, | ||
| flags=None, | ||
| **kwargs): | ||
| def __init__(self, slot, mechanism, ulMinKeySize=None, ulMaxKeySize=None, flags=None, **kwargs): | ||
| self.slot = slot | ||
@@ -83,13 +80,13 @@ """:class:`pkcs11.Slot` this information is for.""" | ||
| def __str__(self): | ||
| return '\n'.join(( | ||
| "Supported key lengths: [%s, %s]" % (self.min_key_length, | ||
| self.max_key_length), | ||
| "Flags: %s" % self.flags, | ||
| )) | ||
| return "\n".join( | ||
| ( | ||
| "Supported key lengths: [%s, %s]" % (self.min_key_length, self.max_key_length), | ||
| "Flags: %s" % self.flags, | ||
| ) | ||
| ) | ||
| def __repr__(self): | ||
| return '<{klass} (mechanism={mechanism}, flags={flags})>'.format( | ||
| klass=type(self).__name__, | ||
| mechanism=str(self.mechanism), | ||
| flags=str(self.flags)) | ||
| return "<{klass} (mechanism={mechanism}, flags={flags})>".format( | ||
| klass=type(self).__name__, mechanism=str(self.mechanism), flags=str(self.flags) | ||
| ) | ||
@@ -106,10 +103,13 @@ | ||
| def __init__(self, lib, slot_id, | ||
| slotDescription=None, | ||
| manufacturerID=None, | ||
| hardwareVersion=None, | ||
| firmwareVersion=None, | ||
| flags=None, | ||
| **kwargs): | ||
| def __init__( | ||
| self, | ||
| lib, | ||
| slot_id, | ||
| slotDescription=None, | ||
| manufacturerID=None, | ||
| hardwareVersion=None, | ||
| firmwareVersion=None, | ||
| flags=None, | ||
| **kwargs, | ||
| ): | ||
| self._lib = lib # Hold a reference to the lib to prevent gc | ||
@@ -159,15 +159,16 @@ | ||
| def __str__(self): | ||
| return '\n'.join(( | ||
| "Slot Description: %s" % self.slot_description, | ||
| "Manufacturer ID: %s" % self.manufacturer_id, | ||
| "Hardware Version: %s.%s" % self.hardware_version, | ||
| "Firmware Version: %s.%s" % self.firmware_version, | ||
| "Flags: %s" % self.flags, | ||
| )) | ||
| return "\n".join( | ||
| ( | ||
| "Slot Description: %s" % self.slot_description, | ||
| "Manufacturer ID: %s" % self.manufacturer_id, | ||
| "Hardware Version: %s.%s" % self.hardware_version, | ||
| "Firmware Version: %s.%s" % self.firmware_version, | ||
| "Flags: %s" % self.flags, | ||
| ) | ||
| ) | ||
| def __repr__(self): | ||
| return '<{klass} (slotID={slot_id} flags={flags})>'.format( | ||
| klass=type(self).__name__, | ||
| slot_id=self.slot_id, | ||
| flags=str(self.flags)) | ||
| return "<{klass} (slotID={slot_id} flags={flags})>".format( | ||
| klass=type(self).__name__, slot_id=self.slot_id, flags=str(self.flags) | ||
| ) | ||
@@ -183,12 +184,14 @@ | ||
| def __init__(self, slot, | ||
| label=None, | ||
| serialNumber=None, | ||
| model=None, | ||
| manufacturerID=None, | ||
| hardwareVersion=None, | ||
| firmwareVersion=None, | ||
| flags=None, | ||
| **kwargs): | ||
| def __init__( | ||
| self, | ||
| slot, | ||
| label=None, | ||
| serialNumber=None, | ||
| model=None, | ||
| manufacturerID=None, | ||
| hardwareVersion=None, | ||
| firmwareVersion=None, | ||
| flags=None, | ||
| **kwargs, | ||
| ): | ||
| self.slot = slot | ||
@@ -214,3 +217,3 @@ """The :class:`Slot` this token is installed in.""" | ||
| def open(self, rw=False, user_pin=None, so_pin=None): | ||
| def open(self, rw=False, user_pin=None, so_pin=None, user_type=None): | ||
| """ | ||
@@ -233,2 +236,5 @@ Open a session on the token and optionally log in as a user or | ||
| security officer. | ||
| :param user_type: Sets the userType parameter to C_Login. | ||
| Allows for vendor-defined values. Defaults to UserType.SO if | ||
| so_pin is set, otherwise UserType.USER. | ||
@@ -243,7 +249,5 @@ :rtype: Session | ||
| def __repr__(self): | ||
| return "<{klass} (label='{label}' serial={serial} flags={flags})>"\ | ||
| .format(klass=type(self).__name__, | ||
| label=self.label, | ||
| serial=self.serial, | ||
| flags=str(self.flags)) | ||
| return "<{klass} (label='{label}' serial={serial} flags={flags})>".format( | ||
| klass=type(self).__name__, label=self.label, serial=self.serial, flags=str(self.flags) | ||
| ) | ||
@@ -278,4 +282,3 @@ | ||
| def __eq__(self, other): | ||
| return self.token == other.token and \ | ||
| self._handle == other._handle | ||
| return self.token == other.token and self._handle == other._handle | ||
@@ -313,6 +316,3 @@ def __hash__(self): | ||
| if object_class is None and \ | ||
| key_type is None and \ | ||
| label is None \ | ||
| and id is None: | ||
| if object_class is None and key_type is None and label is None and id is None: | ||
| raise ArgumentsBad("Must specify at least one search parameter.") | ||
@@ -339,9 +339,8 @@ | ||
| key = next(iterator) | ||
| except StopIteration: | ||
| raise NoSuchKey("No key matching %s" % attrs) | ||
| except StopIteration as ex: | ||
| raise NoSuchKey("No key matching %s" % attrs) from ex | ||
| try: | ||
| next(iterator) | ||
| raise MultipleObjectsReturned("More than 1 key matches %s" % | ||
| attrs) | ||
| raise MultipleObjectsReturned("More than 1 key matches %s" % attrs) | ||
| except StopIteration: | ||
@@ -394,3 +393,4 @@ return key | ||
| Requires a read/write session, unless the object is not to be | ||
| stored. | ||
| stored. To permanently store the object in the HSM add **pkcs.Attribute.TOKEN: True**, | ||
| see :meth:`pkcs11.Attribute` for more available object attributes. | ||
@@ -402,4 +402,3 @@ :param dict(Attribute,*) attrs: attributes of the object to create | ||
| def create_domain_parameters(self, key_type, attrs, | ||
| local=False, store=False): | ||
| def create_domain_parameters(self, key_type, attrs, local=False, store=False): | ||
| """ | ||
@@ -434,5 +433,11 @@ Create a domain parameters object from known parameters. | ||
| def generate_domain_parameters(self, key_type, param_length, store=False, | ||
| mechanism=None, mechanism_param=None, | ||
| template=None): | ||
| def generate_domain_parameters( | ||
| self, | ||
| key_type, | ||
| param_length, | ||
| store=False, | ||
| mechanism=None, | ||
| mechanism_param=None, | ||
| template=None, | ||
| ): | ||
| """ | ||
@@ -463,7 +468,14 @@ Generate domain parameters. | ||
| def generate_key(self, key_type, key_length=None, | ||
| id=None, label=None, | ||
| store=False, capabilities=None, | ||
| mechanism=None, mechanism_param=None, | ||
| template=None): | ||
| def generate_key( | ||
| self, | ||
| key_type, | ||
| key_length=None, | ||
| id=None, | ||
| label=None, | ||
| store=False, | ||
| capabilities=None, | ||
| mechanism=None, | ||
| mechanism_param=None, | ||
| template=None, | ||
| ): | ||
| """ | ||
@@ -512,7 +524,8 @@ Generate a single key (e.g. AES, DES). | ||
| :param str label: Key label. | ||
| :param store: Store key on token (requires R/W session). | ||
| :param bool store: Store key on token (requires R/W session). | ||
| :param MechanismFlag capabilities: Key capabilities (or default). | ||
| :param Mechanism mechanism: Generation mechanism (or default). | ||
| :param bytes mechanism_param: Optional vector to the mechanism. | ||
| :param dict(Attribute,*) template: Additional attributes. | ||
| :param dict(Attribute,*) private_template: Additional attributes for private key. | ||
| :param dict(Attribute,*) public_template: Additional attributes for public key. | ||
@@ -529,4 +542,3 @@ :rtype: (PublicKey, PrivateKey) | ||
| else: | ||
| return self._generate_keypair(key_type, key_length=key_length, | ||
| **kwargs) | ||
| return self._generate_keypair(key_type, key_length=key_length, **kwargs) | ||
@@ -569,3 +581,3 @@ def seed_random(self, seed): | ||
| if isinstance(data, str): | ||
| data = data.encode('utf-8') | ||
| data = data.encode("utf-8") | ||
@@ -602,4 +614,3 @@ if isinstance(data, bytes): | ||
| def __eq__(self, other): | ||
| return self.session == other.session and \ | ||
| self._handle == other._handle | ||
| return self.session == other.session and self._handle == other._handle | ||
@@ -660,4 +671,4 @@ def __hash__(self): | ||
| return self.params[key] | ||
| except KeyError: | ||
| raise AttributeTypeInvalid | ||
| except KeyError as ex: | ||
| raise AttributeTypeInvalid from ex | ||
| else: | ||
@@ -680,6 +691,13 @@ return super().__getitem__(key) | ||
| def generate_keypair(self, id=None, label=None, | ||
| store=False, capabilities=None, | ||
| mechanism=None, mechanism_param=None, | ||
| public_template=None, private_template=None): | ||
| def generate_keypair( | ||
| self, | ||
| id=None, | ||
| label=None, | ||
| store=False, | ||
| capabilities=None, | ||
| mechanism=None, | ||
| mechanism_param=None, | ||
| public_template=None, | ||
| private_template=None, | ||
| ): | ||
| """ | ||
@@ -726,3 +744,3 @@ Generate a key pair from these domain parameters (e.g. for | ||
| try: | ||
| return '%s-bit %s' % (self.key_length, self.key_type.name) | ||
| return "%s-bit %s" % (self.key_length, self.key_type.name) | ||
| except AttributeTypeInvalid: | ||
@@ -735,4 +753,5 @@ return self.key_type.name | ||
| self.label, | ||
| hexlify(self.id).decode('ascii'), | ||
| self._key_description) | ||
| hexlify(self.id).decode("ascii"), | ||
| self._key_description, | ||
| ) | ||
@@ -806,2 +825,3 @@ | ||
| """ | ||
| object_class = ObjectClass.CERTIFICATE | ||
@@ -895,3 +915,3 @@ | ||
| if isinstance(data, str): | ||
| data = data.encode('utf-8') | ||
| data = data.encode("utf-8") | ||
@@ -902,4 +922,3 @@ if isinstance(data, bytes): | ||
| else: | ||
| return self._encrypt_generator(data, | ||
| buffer_size=buffer_size, **kwargs) | ||
| return self._encrypt_generator(data, buffer_size=buffer_size, **kwargs) | ||
@@ -924,2 +943,3 @@ | ||
| (e.g. initialisation vector). | ||
| :param pin: optional user pin for keys that require it (e.g. YubiKey) | ||
| :param int buffer_size: size of the working buffer (for generators). | ||
@@ -936,4 +956,3 @@ | ||
| else: | ||
| return self._decrypt_generator(data, | ||
| buffer_size=buffer_size, **kwargs) | ||
| return self._decrypt_generator(data, buffer_size=buffer_size, **kwargs) | ||
@@ -962,2 +981,3 @@ | ||
| :param bytes mechanism_param: optional mechanism parameter | ||
| :param pin: optional user pin for keys that require it (e.g. YubiKey) | ||
@@ -969,3 +989,3 @@ :rtype: bytes | ||
| if isinstance(data, str): | ||
| data = data.encode('utf-8') | ||
| data = data.encode("utf-8") | ||
@@ -1009,3 +1029,3 @@ if isinstance(data, bytes): | ||
| if isinstance(data, str): | ||
| data = data.encode('utf-8') | ||
| data = data.encode("utf-8") | ||
@@ -1029,4 +1049,3 @@ try: | ||
| def wrap_key(self, key, | ||
| mechanism=None, mechanism_param=None): | ||
| def wrap_key(self, key, mechanism=None, mechanism_param=None): | ||
| """ | ||
@@ -1052,7 +1071,15 @@ Use this key to wrap (i.e. encrypt) `key` for export. Returns | ||
| def unwrap_key(self, object_class, key_type, key_data, | ||
| id=None, label=None, | ||
| mechanism=None, mechanism_param=None, | ||
| store=False, capabilities=None, | ||
| template=None): | ||
| def unwrap_key( | ||
| self, | ||
| object_class, | ||
| key_type, | ||
| key_data, | ||
| id=None, | ||
| label=None, | ||
| mechanism=None, | ||
| mechanism_param=None, | ||
| store=False, | ||
| capabilities=None, | ||
| template=None, | ||
| ): | ||
| """ | ||
@@ -1084,7 +1111,14 @@ Use this key to unwrap (i.e. decrypt) and import `key_data`. | ||
| def derive_key(self, key_type, key_length, | ||
| id=None, label=None, | ||
| store=False, capabilities=None, | ||
| mechanism=None, mechanism_param=None, | ||
| template=None): | ||
| def derive_key( | ||
| self, | ||
| key_type, | ||
| key_length, | ||
| id=None, | ||
| label=None, | ||
| store=False, | ||
| capabilities=None, | ||
| mechanism=None, | ||
| mechanism_param=None, | ||
| template=None, | ||
| ): | ||
| """ | ||
@@ -1091,0 +1125,0 @@ Derive a new key from this key. Used to create session |
@@ -12,3 +12,2 @@ def biginteger(value): | ||
| return value.to_bytes((value.bit_length() + 7) // 8, | ||
| byteorder='big') | ||
| return value.to_bytes((value.bit_length() + 7) // 8, byteorder="big") |
+10
-9
@@ -8,5 +8,4 @@ """ | ||
| from ..constants import Attribute | ||
| from . import biginteger | ||
| from ..constants import Attribute | ||
| from ..exceptions import AttributeTypeInvalid | ||
@@ -25,4 +24,4 @@ | ||
| return { | ||
| Attribute.BASE: biginteger(params['g']), | ||
| Attribute.PRIME: biginteger(params['p']), | ||
| Attribute.BASE: biginteger(params["g"]), | ||
| Attribute.PRIME: biginteger(params["p"]), | ||
| } | ||
@@ -41,6 +40,8 @@ | ||
| asn1 = DHParameters({ | ||
| 'g': int.from_bytes(obj[Attribute.BASE], byteorder='big'), | ||
| 'p': int.from_bytes(obj[Attribute.PRIME], byteorder='big'), | ||
| }) | ||
| asn1 = DHParameters( | ||
| { | ||
| "g": int.from_bytes(obj[Attribute.BASE], byteorder="big"), | ||
| "p": int.from_bytes(obj[Attribute.PRIME], byteorder="big"), | ||
| } | ||
| ) | ||
@@ -58,3 +59,3 @@ return asn1.dump() | ||
| asn1 = Integer(int.from_bytes(key[Attribute.VALUE], byteorder='big')) | ||
| asn1 = Integer(int.from_bytes(key[Attribute.VALUE], byteorder="big")) | ||
@@ -61,0 +62,0 @@ return asn1.dump() |
+13
-11
@@ -5,8 +5,8 @@ """ | ||
| from asn1crypto.algos import DSASignature | ||
| from asn1crypto.core import Integer | ||
| from asn1crypto.keys import DSAParams | ||
| from asn1crypto.algos import DSASignature | ||
| from ..constants import Attribute | ||
| from . import biginteger | ||
| from ..constants import Attribute | ||
@@ -25,5 +25,5 @@ | ||
| return { | ||
| Attribute.BASE: biginteger(params['g']), | ||
| Attribute.PRIME: biginteger(params['p']), | ||
| Attribute.SUBPRIME: biginteger(params['q']), | ||
| Attribute.BASE: biginteger(params["g"]), | ||
| Attribute.PRIME: biginteger(params["p"]), | ||
| Attribute.SUBPRIME: biginteger(params["q"]), | ||
| } | ||
@@ -39,7 +39,9 @@ | ||
| """ | ||
| asn1 = DSAParams({ | ||
| 'g': int.from_bytes(obj[Attribute.BASE], byteorder='big'), | ||
| 'p': int.from_bytes(obj[Attribute.PRIME], byteorder='big'), | ||
| 'q': int.from_bytes(obj[Attribute.SUBPRIME], byteorder='big'), | ||
| }) | ||
| asn1 = DSAParams( | ||
| { | ||
| "g": int.from_bytes(obj[Attribute.BASE], byteorder="big"), | ||
| "p": int.from_bytes(obj[Attribute.PRIME], byteorder="big"), | ||
| "q": int.from_bytes(obj[Attribute.SUBPRIME], byteorder="big"), | ||
| } | ||
| ) | ||
@@ -57,3 +59,3 @@ return asn1.dump() | ||
| asn1 = Integer(int.from_bytes(key[Attribute.VALUE], byteorder='big')) | ||
| asn1 = Integer(int.from_bytes(key[Attribute.VALUE], byteorder="big")) | ||
@@ -60,0 +62,0 @@ return asn1.dump() |
+18
-16
@@ -6,2 +6,4 @@ """ | ||
| from asn1crypto.algos import DSASignature | ||
| from asn1crypto.core import OctetString | ||
| from asn1crypto.keys import ( | ||
@@ -13,4 +15,3 @@ ECDomainParameters, | ||
| ) | ||
| from asn1crypto.algos import DSASignature | ||
| from asn1crypto.core import OctetString | ||
| from ..constants import Attribute, ObjectClass | ||
@@ -32,3 +33,3 @@ from ..mechanisms import KeyType | ||
| return ECDomainParameters( | ||
| name='named', | ||
| name="named", | ||
| value=NamedCurve.unmap(oid), | ||
@@ -57,6 +58,5 @@ ).dump() | ||
| assert asn1.algorithm == 'ec', \ | ||
| "Wrong algorithm, not an EC key!" | ||
| assert asn1.algorithm == "ec", "Wrong algorithm, not an EC key!" | ||
| ecpoint = bytes(asn1['public_key']) | ||
| ecpoint = bytes(asn1["public_key"]) | ||
@@ -69,3 +69,3 @@ if encode_ec_point: | ||
| Attribute.CLASS: ObjectClass.PUBLIC_KEY, | ||
| Attribute.EC_PARAMS: asn1['algorithm']['parameters'].dump(), | ||
| Attribute.EC_PARAMS: asn1["algorithm"]["parameters"].dump(), | ||
| Attribute.EC_POINT: ecpoint, | ||
@@ -89,4 +89,4 @@ } | ||
| Attribute.CLASS: ObjectClass.PRIVATE_KEY, | ||
| Attribute.EC_PARAMS: asn1['parameters'].chosen.dump(), | ||
| Attribute.VALUE: asn1['private_key'].contents, | ||
| Attribute.EC_PARAMS: asn1["parameters"].chosen.dump(), | ||
| Attribute.VALUE: asn1["private_key"].contents, | ||
| } | ||
@@ -106,9 +106,11 @@ | ||
| return PublicKeyInfo({ | ||
| 'algorithm': { | ||
| 'algorithm': 'ec', | ||
| 'parameters': ecparams, | ||
| }, | ||
| 'public_key': ecpoint, | ||
| }).dump() | ||
| return PublicKeyInfo( | ||
| { | ||
| "algorithm": { | ||
| "algorithm": "ec", | ||
| "parameters": ecparams, | ||
| }, | ||
| "public_key": ecpoint, | ||
| } | ||
| ).dump() | ||
@@ -115,0 +117,0 @@ |
+19
-18
@@ -7,6 +7,6 @@ """ | ||
| from ..constants import Attribute, MechanismFlag, ObjectClass | ||
| from ..defaults import DEFAULT_KEY_CAPABILITIES | ||
| from ..mechanisms import KeyType | ||
| from . import biginteger | ||
| from ..constants import Attribute, ObjectClass, MechanismFlag | ||
| from ..mechanisms import KeyType | ||
| from ..defaults import DEFAULT_KEY_CAPABILITIES | ||
@@ -31,10 +31,10 @@ | ||
| Attribute.KEY_TYPE: KeyType.RSA, | ||
| Attribute.MODULUS: biginteger(key['modulus']), | ||
| Attribute.PUBLIC_EXPONENT: biginteger(key['public_exponent']), | ||
| Attribute.PRIVATE_EXPONENT: biginteger(key['private_exponent']), | ||
| Attribute.PRIME_1: biginteger(key['prime1']), | ||
| Attribute.PRIME_2: biginteger(key['prime2']), | ||
| Attribute.EXPONENT_1: biginteger(key['exponent1']), | ||
| Attribute.EXPONENT_2: biginteger(key['exponent2']), | ||
| Attribute.COEFFICIENT: biginteger(key['coefficient']), | ||
| Attribute.MODULUS: biginteger(key["modulus"]), | ||
| Attribute.PUBLIC_EXPONENT: biginteger(key["public_exponent"]), | ||
| Attribute.PRIVATE_EXPONENT: biginteger(key["private_exponent"]), | ||
| Attribute.PRIME_1: biginteger(key["prime1"]), | ||
| Attribute.PRIME_2: biginteger(key["prime2"]), | ||
| Attribute.EXPONENT_1: biginteger(key["exponent1"]), | ||
| Attribute.EXPONENT_2: biginteger(key["exponent2"]), | ||
| Attribute.COEFFICIENT: biginteger(key["coefficient"]), | ||
| Attribute.DECRYPT: MechanismFlag.DECRYPT in capabilities, | ||
@@ -63,4 +63,4 @@ Attribute.SIGN: MechanismFlag.SIGN in capabilities, | ||
| Attribute.KEY_TYPE: KeyType.RSA, | ||
| Attribute.MODULUS: biginteger(key['modulus']), | ||
| Attribute.PUBLIC_EXPONENT: biginteger(key['public_exponent']), | ||
| Attribute.MODULUS: biginteger(key["modulus"]), | ||
| Attribute.PUBLIC_EXPONENT: biginteger(key["public_exponent"]), | ||
| Attribute.ENCRYPT: MechanismFlag.ENCRYPT in capabilities, | ||
@@ -79,6 +79,7 @@ Attribute.VERIFY: MechanismFlag.VERIFY in capabilities, | ||
| """ | ||
| return RSAPublicKey({ | ||
| 'modulus': int.from_bytes(key[Attribute.MODULUS], byteorder='big'), | ||
| 'public_exponent': int.from_bytes(key[Attribute.PUBLIC_EXPONENT], | ||
| byteorder='big'), | ||
| }).dump() | ||
| return RSAPublicKey( | ||
| { | ||
| "modulus": int.from_bytes(key[Attribute.MODULUS], byteorder="big"), | ||
| "public_exponent": int.from_bytes(key[Attribute.PUBLIC_EXPONENT], byteorder="big"), | ||
| } | ||
| ).dump() |
+31
-27
@@ -7,3 +7,3 @@ """ | ||
| from ..constants import Attribute, ObjectClass, CertificateType | ||
| from ..constants import Attribute, CertificateType, ObjectClass | ||
| from ..mechanisms import KeyType | ||
@@ -28,8 +28,8 @@ | ||
| key_info = x509.public_key | ||
| key = bytes(key_info['public_key']) | ||
| key = bytes(key_info["public_key"]) | ||
| key_type = { | ||
| 'rsa': KeyType.RSA, | ||
| 'dsa': KeyType.DSA, | ||
| 'ec': KeyType.EC, | ||
| "rsa": KeyType.RSA, | ||
| "dsa": KeyType.DSA, | ||
| "ec": KeyType.EC, | ||
| }[key_info.algorithm] | ||
@@ -44,18 +44,24 @@ | ||
| from .rsa import decode_rsa_public_key | ||
| attrs.update(decode_rsa_public_key(key)) | ||
| elif key_type is KeyType.DSA: | ||
| from .dsa import decode_dsa_domain_parameters, decode_dsa_public_key | ||
| params = key_info['algorithm']['parameters'].dump() | ||
| params = key_info["algorithm"]["parameters"].dump() | ||
| attrs.update(decode_dsa_domain_parameters(params)) | ||
| attrs.update({ | ||
| Attribute.VALUE: decode_dsa_public_key(key), | ||
| }) | ||
| attrs.update( | ||
| { | ||
| Attribute.VALUE: decode_dsa_public_key(key), | ||
| } | ||
| ) | ||
| elif key_type is KeyType.EC: | ||
| params = key_info['algorithm']['parameters'].dump() | ||
| params = key_info["algorithm"]["parameters"].dump() | ||
| attrs.update({ | ||
| Attribute.EC_PARAMS: params, | ||
| Attribute.EC_POINT: key, | ||
| }) | ||
| attrs.update( | ||
| { | ||
| Attribute.EC_PARAMS: params, | ||
| Attribute.EC_POINT: key, | ||
| } | ||
| ) | ||
| else: | ||
@@ -88,3 +94,3 @@ raise AssertionError("Should not be reached") | ||
| issuer = x509.issuer | ||
| serial = x509['tbs_certificate']['serial_number'] | ||
| serial = x509["tbs_certificate"]["serial_number"] | ||
@@ -101,16 +107,15 @@ template = { | ||
| if extended_set: | ||
| start_date = \ | ||
| x509['tbs_certificate']['validity']['not_before'].native.date() | ||
| end_date = \ | ||
| x509['tbs_certificate']['validity']['not_after'].native.date() | ||
| start_date = x509["tbs_certificate"]["validity"]["not_before"].native.date() | ||
| end_date = x509["tbs_certificate"]["validity"]["not_after"].native.date() | ||
| template.update({ | ||
| Attribute.START_DATE: start_date, | ||
| Attribute.END_DATE: end_date, | ||
| }) | ||
| template.update( | ||
| { | ||
| Attribute.START_DATE: start_date, | ||
| Attribute.END_DATE: end_date, | ||
| } | ||
| ) | ||
| # FIXME: is this correct? | ||
| try: | ||
| template[Attribute.HASH_OF_SUBJECT_PUBLIC_KEY] = \ | ||
| x509.key_identifier | ||
| template[Attribute.HASH_OF_SUBJECT_PUBLIC_KEY] = x509.key_identifier | ||
| except KeyError: | ||
@@ -120,4 +125,3 @@ pass | ||
| try: | ||
| template[Attribute.HASH_OF_ISSUER_PUBLIC_KEY] = \ | ||
| x509.authority_key_identifier | ||
| template[Attribute.HASH_OF_ISSUER_PUBLIC_KEY] = x509.authority_key_identifier | ||
| except KeyError: | ||
@@ -124,0 +128,0 @@ pass |
+388
-371
@@ -1,375 +0,392 @@ | ||
| Metadata-Version: 1.1 | ||
| Metadata-Version: 2.4 | ||
| Name: python-pkcs11 | ||
| Version: 0.7.0 | ||
| Summary: PKCS#11 (Cryptoki) support for Python | ||
| Home-page: https://github.com/danni/python-pkcs11 | ||
| Author: Danielle Madeley | ||
| Author-email: danielle@madeley.id.au | ||
| License: UNKNOWN | ||
| Description: Python PKCS#11 - High Level Wrapper API | ||
| ======================================= | ||
| A high level, "more Pythonic" interface to the PKCS#11 (Cryptoki) standard | ||
| to support HSM and Smartcard devices in Python. | ||
| The interface is designed to follow the logical structure of a HSM, with | ||
| useful defaults for obscurely documented parameters. Many APIs will optionally | ||
| accept iterables and act as generators, allowing you to stream large data | ||
| blocks for symmetric encryption. | ||
| python-pkcs11 also includes numerous utility functions to convert between PKCS | ||
| #11 data structures and common interchange formats including PKCS #1 and X.509. | ||
| python-pkcs11 is fully documented and has a full integration test suite for all | ||
| features, with continuous integration against multiple HSM platforms including: | ||
| * Thales nCipher | ||
| * Opencryptoki TPM | ||
| * OpenSC/Smartcard-HSM/Nitrokey HSM | ||
| Source: https://github.com/danni/python-pkcs11 | ||
| Documentation: http://python-pkcs11.readthedocs.io/en/latest/ | ||
| Getting Started | ||
| --------------- | ||
| Install from Pip: | ||
| :: | ||
| pip install python-pkcs11 | ||
| Or build from source: | ||
| :: | ||
| python setup.py build | ||
| Assuming your PKCS#11 library is set as `PKCS11_MODULE` and contains a | ||
| token named `DEMO`: | ||
| AES | ||
| ~~~ | ||
| :: | ||
| import pkcs11 | ||
| # Initialise our PKCS#11 library | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an AES key in this session | ||
| key = session.generate_key(pkcs11.KeyType.AES, 256) | ||
| # Get an initialisation vector | ||
| iv = session.generate_random(128) # AES blocks are fixed at 128 bits | ||
| # Encrypt our data | ||
| crypttext = key.encrypt(data, mechanism_param=iv) | ||
| 3DES | ||
| ~~~~ | ||
| :: | ||
| import pkcs11 | ||
| # Initialise our PKCS#11 library | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate a DES key in this session | ||
| key = session.generate_key(pkcs11.KeyType.DES3) | ||
| # Get an initialisation vector | ||
| iv = session.generate_random(64) # DES blocks are fixed at 64 bits | ||
| # Encrypt our data | ||
| crypttext = key.encrypt(data, mechanism_param=iv) | ||
| RSA | ||
| ~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an RSA keypair in this session | ||
| pub, priv = session.generate_keypair(pkcs11.KeyType.RSA, 2048) | ||
| # Encrypt as one block | ||
| crypttext = pub.encrypt(data) | ||
| DSA | ||
| ~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an DSA keypair in this session | ||
| pub, priv = session.generate_keypair(pkcs11.KeyType.DSA, 1024) | ||
| # Sign | ||
| signature = priv.sign(data) | ||
| ECDSA | ||
| ~~~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an EC keypair in this session from a named curve | ||
| ecparams = session.create_domain_parameters( | ||
| pkcs11.KeyType.EC, { | ||
| pkcs11.Attribute.EC_PARAMS: pkcs11.util.ec.encode_named_curve_parameters('prime256v1'), | ||
| }, local=True) | ||
| pub, priv = ecparams.generate_keypair() | ||
| # Sign | ||
| signature = priv.sign(data) | ||
| Diffie-Hellman | ||
| ~~~~~~~~~~~~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| with token.open() as session: | ||
| # Given shared Diffie-Hellman parameters | ||
| parameters = session.create_domain_parameters(pkcs11.KeyType.DH, { | ||
| pkcs11.Attribute.PRIME: prime, # Diffie-Hellman parameters | ||
| pkcs11.Attribute.BASE: base, | ||
| }) | ||
| # Generate a DH key pair from the public parameters | ||
| public, private = parameters.generate_keypair() | ||
| # Share the public half of it with our other party. | ||
| _network_.write(public[Attribute.VALUE]) | ||
| # And get their shared value | ||
| other_value = _network_.read() | ||
| # Derive a shared session key with perfect forward secrecy | ||
| session_key = private.derive_key( | ||
| pkcs11.KeyType.AES, 128, | ||
| mechanism_param=other_value) | ||
| Elliptic-Curve Diffie-Hellman | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| with token.open() as session: | ||
| # Given DER encocded EC parameters, e.g. from | ||
| # openssl ecparam -outform der -name <named curve> | ||
| parameters = session.create_domain_parameters(pkcs11.KeyType.EC, { | ||
| pkcs11.Attribute.EC_PARAMS: ecparams, | ||
| }) | ||
| # Generate a DH key pair from the public parameters | ||
| public, private = parameters.generate_keypair() | ||
| # Share the public half of it with our other party. | ||
| _network_.write(public[pkcs11.Attribute.EC_POINT]) | ||
| # And get their shared value | ||
| other_value = _network_.read() | ||
| # Derive a shared session key | ||
| session_key = private.derive_key( | ||
| pkcs11.KeyType.AES, 128, | ||
| mechanism_param=(pkcs11.KDF.NULL, None, other_value)) | ||
| Tested Compatibility | ||
| -------------------- | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Functionality | SoftHSMv2 | Thales nCipher | Opencryptoki | OpenSC (Nitrokey) | | ||
| +==============================+==============+=================+==============+===================+ | ||
| | Get Slots/Tokens | Works | Works | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Get Mechanisms | Works | Works | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Initialize token | Not implemented | | ||
| +------------------------------+-------------------------------------------------------------------+ | ||
| | Slot events | Not implemented | | ||
| +------------------------------+-------------------------------------------------------------------+ | ||
| | Alternative authentication | Not implemented | | ||
| | path | | | ||
| +------------------------------+-------------------------------------------------------------------+ | ||
| | `Always authenticate` keys | Not implemented | | ||
| +-------------+----------------+--------------+-----------------+--------------+-------------------+ | ||
| | Create/Copy | Keys | Works | Works | Errors | Create | | ||
| | +----------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Certificates | Caveats [1]_ | Caveats [1]_ | Caveats [1]_ | ? | | ||
| | +----------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Domain Params | Caveats [1]_ | Caveats [1]_ | ? | N/A | | ||
| +-------------+----------------+--------------+-----------------+--------------+-------------------+ | ||
| | Destroy Object | Works | N/A | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Generate Random | Works | Works | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Seed Random | Works | N/A | N/A | N/A | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Digest (Data & Keys) | Works | Caveats [2]_ | Works | Works | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | AES | Generate key | Works | Works | Works | N/A | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Encrypt/Decrypt | Works | Works | Works | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Wrap/Unwrap | ? [3]_ | Works | Errors | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Sign/Verify | Works | Works [4]_ | N/A | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | DES2/ | Generate key | Works | Works | Works | N/A | | ||
| | DES3 +---------------------+--------------+-----------------+--------------+ | | ||
| | | Encrypt/Decrypt | Works | Works | Works | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Wrap/Unwrap | ? | ? | ? | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Sign/Verify | ? | ? | ? | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | RSA | Generate key pair | Works | Works | Works | Works [4]_ [8]_ | | ||
| | +---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Encrypt/Decrypt | Works | Works | Works | Decrypt only [9]_ | | ||
| | +---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Wrap/Unwrap | Works | Works | Works | N/A | | ||
| | +---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Sign/Verify | Works | Works | Works | Works | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | DSA | Generate parameters | Works | Error | N/A | N/A | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Generate key pair | Works | Caveats [5]_ | | | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Sign/Verify | Works | Works [4]_ | | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | DH | Generate parameters | Works | N/A | N/A | N/A | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Generate key pair | Works | Caveats [6]_ | | | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Derive Key | Works | Caveats [7]_ | | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | EC | Generate key pair | Caveats [6]_ | ? [3]_ | N/A | Works | | ||
| | +---------------------+--------------+-----------------+ +-------------------+ | ||
| | | Sign/Verify (ECDSA) | Works [4]_ | ? [3]_ | | Sign only [9]_ | | ||
| | +---------------------+--------------+-----------------+ +-------------------+ | ||
| | | Derive key (ECDH) | Works | ? [3]_ | | ? | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Proprietary extensions | N/A | Not implemented | N/A | N/A | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| .. [1] Device supports limited set of attributes. | ||
| .. [2] Digesting keys is not supported. | ||
| .. [3] Untested: requires support in device. | ||
| .. [4] Default mechanism not supported, must specify a mechanism. | ||
| .. [5] From existing domain parameters. | ||
| .. [6] Local domain parameters only. | ||
| .. [7] Generates security warnings about the derived key. | ||
| .. [8] `store` parameter is ignored, all keys are stored. | ||
| .. [9] Encryption/verify not supported, extract the public key | ||
| Python version: | ||
| * 3.4 (with `aenum`) | ||
| * 3.5 (with `aenum`) | ||
| * 3.6 | ||
| PKCS#11 versions: | ||
| * 2.11 | ||
| * 2.20 | ||
| * 2.40 | ||
| Feel free to send pull requests for any functionality that's not exposed. The | ||
| code is designed to be readable and expose the PKCS #11 spec in a | ||
| straight-forward way. | ||
| If you want your device supported, get in touch! | ||
| More info on PKCS #11 | ||
| --------------------- | ||
| The latest version of the PKCS #11 spec is available from OASIS: | ||
| http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html | ||
| You should also consult the documentation for your PKCS #11 implementation. | ||
| Many implementations expose additional vendor options configurable in your | ||
| environment, including alternative features, modes and debugging | ||
| information. | ||
| License | ||
| ------- | ||
| MIT License | ||
| Copyright (c) 2017 Danielle Madeley | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. | ||
| Platform: UNKNOWN | ||
| Classifier: License :: OSI Approved :: MIT License | ||
| Version: 0.8.0 | ||
| Summary: PKCS#11 support for Python | ||
| Author-email: Andrey Kislyuk <kislyuk@gmail.com>, Danielle Madeley <danielle@madeley.id.au> | ||
| Maintainer-email: Andrey Kislyuk <kislyuk@gmail.com> | ||
| License-Expression: MIT | ||
| Project-URL: Homepage, https://python-pkcs11.readthedocs.io/en/latest/ | ||
| Project-URL: Documentation, https://python-pkcs11.readthedocs.io/en/latest/ | ||
| Project-URL: Issues, https://github.com/pyauth/python-pkcs11/issues | ||
| Project-URL: Repository, https://github.com/pyauth/python-pkcs11 | ||
| Classifier: Programming Language :: Python | ||
| Classifier: Programming Language :: Python :: 3 | ||
| Classifier: Programming Language :: Python :: 3.5 | ||
| Classifier: Programming Language :: Python :: 3.6 | ||
| Classifier: Programming Language :: Python :: 3.7 | ||
| Classifier: Programming Language :: Python :: 3.8 | ||
| Classifier: Programming Language :: Python :: 3.9 | ||
| Classifier: Programming Language :: Python :: 3.10 | ||
| Classifier: Programming Language :: Python :: 3.11 | ||
| Classifier: Programming Language :: Python :: 3.12 | ||
| Classifier: Programming Language :: Python :: 3.13 | ||
| Classifier: Topic :: Security :: Cryptography | ||
| Requires-Python: >=3.9 | ||
| Description-Content-Type: text/x-rst | ||
| License-File: LICENSE | ||
| Requires-Dist: asn1crypto>=1.5.1 | ||
| Dynamic: license-file | ||
| .. image:: https://travis-ci.org/danni/python-pkcs11.svg?branch=master | ||
| :target: https://travis-ci.org/danni/python-pkcs11 | ||
| Python PKCS#11 - High Level Wrapper API | ||
| ======================================= | ||
| A high level, "more Pythonic" interface to the PKCS#11 (Cryptoki) standard | ||
| to support HSM and Smartcard devices in Python. | ||
| The interface is designed to follow the logical structure of a HSM, with | ||
| useful defaults for obscurely documented parameters. Many APIs will optionally | ||
| accept iterables and act as generators, allowing you to stream large data | ||
| blocks for symmetric encryption. | ||
| python-pkcs11 also includes numerous utility functions to convert between PKCS | ||
| #11 data structures and common interchange formats including PKCS #1 and X.509. | ||
| python-pkcs11 is fully documented and has a full integration test suite for all | ||
| features. | ||
| Historically, this project used to run continuous integration tests against several | ||
| HSM platforms, but this test setup has not been maintained over time. Currently, | ||
| the integration tests in GitHub Actions use SoftHSMv2 as a baseline. If you would like | ||
| to contribute some CI setup with additional PKCS#11 implementations or actual HSMs, | ||
| let's chat! | ||
| Source: https://github.com/pyauth/python-pkcs11 | ||
| Documentation: http://python-pkcs11.readthedocs.io/en/latest/ | ||
| Getting Started | ||
| --------------- | ||
| Install from Pip: | ||
| :: | ||
| pip install python-pkcs11 | ||
| Or build from source: | ||
| :: | ||
| python -m build . | ||
| Or using ``uv``: | ||
| :: | ||
| uv build | ||
| Assuming your PKCS#11 library is set as `PKCS11_MODULE` and contains a | ||
| token named `DEMO`: | ||
| AES | ||
| ~~~ | ||
| :: | ||
| import pkcs11 | ||
| # Initialise our PKCS#11 library | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an AES key in this session | ||
| key = session.generate_key(pkcs11.KeyType.AES, 256) | ||
| # Get an initialisation vector | ||
| iv = session.generate_random(128) # AES blocks are fixed at 128 bits | ||
| # Encrypt our data | ||
| crypttext = key.encrypt(data, mechanism_param=iv) | ||
| 3DES | ||
| ~~~~ | ||
| :: | ||
| import pkcs11 | ||
| # Initialise our PKCS#11 library | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate a DES key in this session | ||
| key = session.generate_key(pkcs11.KeyType.DES3) | ||
| # Get an initialisation vector | ||
| iv = session.generate_random(64) # DES blocks are fixed at 64 bits | ||
| # Encrypt our data | ||
| crypttext = key.encrypt(data, mechanism_param=iv) | ||
| RSA | ||
| ~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an RSA keypair in this session | ||
| pub, priv = session.generate_keypair(pkcs11.KeyType.RSA, 2048) | ||
| # Encrypt as one block | ||
| crypttext = pub.encrypt(data) | ||
| DSA | ||
| ~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an DSA keypair in this session | ||
| pub, priv = session.generate_keypair(pkcs11.KeyType.DSA, 1024) | ||
| # Sign | ||
| signature = priv.sign(data) | ||
| ECDSA | ||
| ~~~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an EC keypair in this session from a named curve | ||
| ecparams = session.create_domain_parameters( | ||
| pkcs11.KeyType.EC, { | ||
| pkcs11.Attribute.EC_PARAMS: pkcs11.util.ec.encode_named_curve_parameters('secp256r1'), | ||
| }, local=True) | ||
| pub, priv = ecparams.generate_keypair() | ||
| # Sign | ||
| signature = priv.sign(data) | ||
| Diffie-Hellman | ||
| ~~~~~~~~~~~~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| with token.open() as session: | ||
| # Given shared Diffie-Hellman parameters | ||
| parameters = session.create_domain_parameters(pkcs11.KeyType.DH, { | ||
| pkcs11.Attribute.PRIME: prime, # Diffie-Hellman parameters | ||
| pkcs11.Attribute.BASE: base, | ||
| }) | ||
| # Generate a DH key pair from the public parameters | ||
| public, private = parameters.generate_keypair() | ||
| # Share the public half of it with our other party. | ||
| _network_.write(public[Attribute.VALUE]) | ||
| # And get their shared value | ||
| other_value = _network_.read() | ||
| # Derive a shared session key with perfect forward secrecy | ||
| session_key = private.derive_key( | ||
| pkcs11.KeyType.AES, 128, | ||
| mechanism_param=other_value) | ||
| Elliptic-Curve Diffie-Hellman | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| with token.open() as session: | ||
| # Given DER encocded EC parameters, e.g. from | ||
| # openssl ecparam -outform der -name <named curve> | ||
| parameters = session.create_domain_parameters(pkcs11.KeyType.EC, { | ||
| pkcs11.Attribute.EC_PARAMS: ecparams, | ||
| }) | ||
| # Generate a DH key pair from the public parameters | ||
| public, private = parameters.generate_keypair() | ||
| # Share the public half of it with our other party. | ||
| _network_.write(public[pkcs11.Attribute.EC_POINT]) | ||
| # And get their shared value | ||
| other_value = _network_.read() | ||
| # Derive a shared session key | ||
| session_key = private.derive_key( | ||
| pkcs11.KeyType.AES, 128, | ||
| mechanism_param=(pkcs11.KDF.NULL, None, other_value)) | ||
| Tested Compatibility | ||
| -------------------- | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Functionality | SoftHSMv2 | Thales nCipher | Opencryptoki | OpenSC (Nitrokey) | | ||
| +==============================+==============+=================+==============+===================+ | ||
| | Get Slots/Tokens | Works | Works | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Get Mechanisms | Works | Works | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Initialize token | Not implemented | | ||
| +------------------------------+-------------------------------------------------------------------+ | ||
| | Slot events | Not implemented | | ||
| +------------------------------+-------------------------------------------------------------------+ | ||
| | Alternative authentication | Not implemented | | ||
| | path | | | ||
| +------------------------------+-------------------------------------------------------------------+ | ||
| | `Always authenticate` keys | Not implemented | | ||
| +-------------+----------------+--------------+-----------------+--------------+-------------------+ | ||
| | Create/Copy | Keys | Works | Works | Errors | Create | | ||
| | +----------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Certificates | Caveats [1]_ | Caveats [1]_ | Caveats [1]_ | ? | | ||
| | +----------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Domain Params | Caveats [1]_ | Caveats [1]_ | ? | N/A | | ||
| +-------------+----------------+--------------+-----------------+--------------+-------------------+ | ||
| | Destroy Object | Works | N/A | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Generate Random | Works | Works | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Seed Random | Works | N/A | N/A | N/A | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Digest (Data & Keys) | Works | Caveats [2]_ | Works | Works | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | AES | Generate key | Works | Works | Works | N/A | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Encrypt/Decrypt | Works | Works | Works | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Wrap/Unwrap | ? [3]_ | Works | Errors | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Sign/Verify | Works | Works [4]_ | N/A | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | DES2/ | Generate key | Works | Works | Works | N/A | | ||
| | DES3 +---------------------+--------------+-----------------+--------------+ | | ||
| | | Encrypt/Decrypt | Works | Works | Works | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Wrap/Unwrap | ? | ? | ? | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Sign/Verify | ? | ? | ? | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | RSA | Generate key pair | Works | Works | Works | Works [4]_ [8]_ | | ||
| | +---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Encrypt/Decrypt | Works | Works | Works | Decrypt only [9]_ | | ||
| | +---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Wrap/Unwrap | Works | Works | Works | N/A | | ||
| | +---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Sign/Verify | Works | Works | Works | Works | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | DSA | Generate parameters | Works | Error | N/A | N/A | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Generate key pair | Works | Caveats [5]_ | | | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Sign/Verify | Works | Works [4]_ | | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | DH | Generate parameters | Works | N/A | N/A | N/A | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Generate key pair | Works | Caveats [6]_ | | | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Derive Key | Works | Caveats [7]_ | | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | EC | Generate key pair | Caveats [6]_ | ? [3]_ | N/A | Works | | ||
| | +---------------------+--------------+-----------------+ +-------------------+ | ||
| | | Sign/Verify (ECDSA) | Works [4]_ | ? [3]_ | | Sign only [9]_ | | ||
| | +---------------------+--------------+-----------------+ +-------------------+ | ||
| | | Derive key (ECDH) | Works | ? [3]_ | | ? | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Proprietary extensions | N/A | Not implemented | N/A | N/A | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| .. [1] Device supports limited set of attributes. | ||
| .. [2] Digesting keys is not supported. | ||
| .. [3] Untested: requires support in device. | ||
| .. [4] Default mechanism not supported, must specify a mechanism. | ||
| .. [5] From existing domain parameters. | ||
| .. [6] Local domain parameters only. | ||
| .. [7] Generates security warnings about the derived key. | ||
| .. [8] `store` parameter is ignored, all keys are stored. | ||
| .. [9] Encryption/verify not supported, extract the public key | ||
| Python version: | ||
| * >= 3.9 | ||
| PKCS#11 versions: | ||
| * 2.11 | ||
| * 2.20 | ||
| * 2.40 | ||
| * 3.1 | ||
| Feel free to send pull requests for any functionality that's not exposed. The | ||
| code is designed to be readable and expose the PKCS #11 spec in a | ||
| straight-forward way. | ||
| If you want your device supported, get in touch! | ||
| More info on PKCS #11 | ||
| --------------------- | ||
| The latest version of the PKCS #11 spec is available from OASIS: | ||
| http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html | ||
| You should also consult the documentation for your PKCS #11 implementation. | ||
| Many implementations expose additional vendor options configurable in your | ||
| environment, including alternative features, modes and debugging | ||
| information. | ||
| License | ||
| ------- | ||
| MIT License | ||
| Copyright (c) 2017 Danielle Madeley and contributors | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. |
+388
-371
@@ -1,375 +0,392 @@ | ||
| Metadata-Version: 1.1 | ||
| Metadata-Version: 2.4 | ||
| Name: python-pkcs11 | ||
| Version: 0.7.0 | ||
| Summary: PKCS#11 (Cryptoki) support for Python | ||
| Home-page: https://github.com/danni/python-pkcs11 | ||
| Author: Danielle Madeley | ||
| Author-email: danielle@madeley.id.au | ||
| License: UNKNOWN | ||
| Description: Python PKCS#11 - High Level Wrapper API | ||
| ======================================= | ||
| A high level, "more Pythonic" interface to the PKCS#11 (Cryptoki) standard | ||
| to support HSM and Smartcard devices in Python. | ||
| The interface is designed to follow the logical structure of a HSM, with | ||
| useful defaults for obscurely documented parameters. Many APIs will optionally | ||
| accept iterables and act as generators, allowing you to stream large data | ||
| blocks for symmetric encryption. | ||
| python-pkcs11 also includes numerous utility functions to convert between PKCS | ||
| #11 data structures and common interchange formats including PKCS #1 and X.509. | ||
| python-pkcs11 is fully documented and has a full integration test suite for all | ||
| features, with continuous integration against multiple HSM platforms including: | ||
| * Thales nCipher | ||
| * Opencryptoki TPM | ||
| * OpenSC/Smartcard-HSM/Nitrokey HSM | ||
| Source: https://github.com/danni/python-pkcs11 | ||
| Documentation: http://python-pkcs11.readthedocs.io/en/latest/ | ||
| Getting Started | ||
| --------------- | ||
| Install from Pip: | ||
| :: | ||
| pip install python-pkcs11 | ||
| Or build from source: | ||
| :: | ||
| python setup.py build | ||
| Assuming your PKCS#11 library is set as `PKCS11_MODULE` and contains a | ||
| token named `DEMO`: | ||
| AES | ||
| ~~~ | ||
| :: | ||
| import pkcs11 | ||
| # Initialise our PKCS#11 library | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an AES key in this session | ||
| key = session.generate_key(pkcs11.KeyType.AES, 256) | ||
| # Get an initialisation vector | ||
| iv = session.generate_random(128) # AES blocks are fixed at 128 bits | ||
| # Encrypt our data | ||
| crypttext = key.encrypt(data, mechanism_param=iv) | ||
| 3DES | ||
| ~~~~ | ||
| :: | ||
| import pkcs11 | ||
| # Initialise our PKCS#11 library | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate a DES key in this session | ||
| key = session.generate_key(pkcs11.KeyType.DES3) | ||
| # Get an initialisation vector | ||
| iv = session.generate_random(64) # DES blocks are fixed at 64 bits | ||
| # Encrypt our data | ||
| crypttext = key.encrypt(data, mechanism_param=iv) | ||
| RSA | ||
| ~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an RSA keypair in this session | ||
| pub, priv = session.generate_keypair(pkcs11.KeyType.RSA, 2048) | ||
| # Encrypt as one block | ||
| crypttext = pub.encrypt(data) | ||
| DSA | ||
| ~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an DSA keypair in this session | ||
| pub, priv = session.generate_keypair(pkcs11.KeyType.DSA, 1024) | ||
| # Sign | ||
| signature = priv.sign(data) | ||
| ECDSA | ||
| ~~~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an EC keypair in this session from a named curve | ||
| ecparams = session.create_domain_parameters( | ||
| pkcs11.KeyType.EC, { | ||
| pkcs11.Attribute.EC_PARAMS: pkcs11.util.ec.encode_named_curve_parameters('prime256v1'), | ||
| }, local=True) | ||
| pub, priv = ecparams.generate_keypair() | ||
| # Sign | ||
| signature = priv.sign(data) | ||
| Diffie-Hellman | ||
| ~~~~~~~~~~~~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| with token.open() as session: | ||
| # Given shared Diffie-Hellman parameters | ||
| parameters = session.create_domain_parameters(pkcs11.KeyType.DH, { | ||
| pkcs11.Attribute.PRIME: prime, # Diffie-Hellman parameters | ||
| pkcs11.Attribute.BASE: base, | ||
| }) | ||
| # Generate a DH key pair from the public parameters | ||
| public, private = parameters.generate_keypair() | ||
| # Share the public half of it with our other party. | ||
| _network_.write(public[Attribute.VALUE]) | ||
| # And get their shared value | ||
| other_value = _network_.read() | ||
| # Derive a shared session key with perfect forward secrecy | ||
| session_key = private.derive_key( | ||
| pkcs11.KeyType.AES, 128, | ||
| mechanism_param=other_value) | ||
| Elliptic-Curve Diffie-Hellman | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| with token.open() as session: | ||
| # Given DER encocded EC parameters, e.g. from | ||
| # openssl ecparam -outform der -name <named curve> | ||
| parameters = session.create_domain_parameters(pkcs11.KeyType.EC, { | ||
| pkcs11.Attribute.EC_PARAMS: ecparams, | ||
| }) | ||
| # Generate a DH key pair from the public parameters | ||
| public, private = parameters.generate_keypair() | ||
| # Share the public half of it with our other party. | ||
| _network_.write(public[pkcs11.Attribute.EC_POINT]) | ||
| # And get their shared value | ||
| other_value = _network_.read() | ||
| # Derive a shared session key | ||
| session_key = private.derive_key( | ||
| pkcs11.KeyType.AES, 128, | ||
| mechanism_param=(pkcs11.KDF.NULL, None, other_value)) | ||
| Tested Compatibility | ||
| -------------------- | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Functionality | SoftHSMv2 | Thales nCipher | Opencryptoki | OpenSC (Nitrokey) | | ||
| +==============================+==============+=================+==============+===================+ | ||
| | Get Slots/Tokens | Works | Works | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Get Mechanisms | Works | Works | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Initialize token | Not implemented | | ||
| +------------------------------+-------------------------------------------------------------------+ | ||
| | Slot events | Not implemented | | ||
| +------------------------------+-------------------------------------------------------------------+ | ||
| | Alternative authentication | Not implemented | | ||
| | path | | | ||
| +------------------------------+-------------------------------------------------------------------+ | ||
| | `Always authenticate` keys | Not implemented | | ||
| +-------------+----------------+--------------+-----------------+--------------+-------------------+ | ||
| | Create/Copy | Keys | Works | Works | Errors | Create | | ||
| | +----------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Certificates | Caveats [1]_ | Caveats [1]_ | Caveats [1]_ | ? | | ||
| | +----------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Domain Params | Caveats [1]_ | Caveats [1]_ | ? | N/A | | ||
| +-------------+----------------+--------------+-----------------+--------------+-------------------+ | ||
| | Destroy Object | Works | N/A | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Generate Random | Works | Works | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Seed Random | Works | N/A | N/A | N/A | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Digest (Data & Keys) | Works | Caveats [2]_ | Works | Works | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | AES | Generate key | Works | Works | Works | N/A | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Encrypt/Decrypt | Works | Works | Works | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Wrap/Unwrap | ? [3]_ | Works | Errors | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Sign/Verify | Works | Works [4]_ | N/A | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | DES2/ | Generate key | Works | Works | Works | N/A | | ||
| | DES3 +---------------------+--------------+-----------------+--------------+ | | ||
| | | Encrypt/Decrypt | Works | Works | Works | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Wrap/Unwrap | ? | ? | ? | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Sign/Verify | ? | ? | ? | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | RSA | Generate key pair | Works | Works | Works | Works [4]_ [8]_ | | ||
| | +---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Encrypt/Decrypt | Works | Works | Works | Decrypt only [9]_ | | ||
| | +---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Wrap/Unwrap | Works | Works | Works | N/A | | ||
| | +---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Sign/Verify | Works | Works | Works | Works | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | DSA | Generate parameters | Works | Error | N/A | N/A | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Generate key pair | Works | Caveats [5]_ | | | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Sign/Verify | Works | Works [4]_ | | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | DH | Generate parameters | Works | N/A | N/A | N/A | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Generate key pair | Works | Caveats [6]_ | | | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Derive Key | Works | Caveats [7]_ | | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | EC | Generate key pair | Caveats [6]_ | ? [3]_ | N/A | Works | | ||
| | +---------------------+--------------+-----------------+ +-------------------+ | ||
| | | Sign/Verify (ECDSA) | Works [4]_ | ? [3]_ | | Sign only [9]_ | | ||
| | +---------------------+--------------+-----------------+ +-------------------+ | ||
| | | Derive key (ECDH) | Works | ? [3]_ | | ? | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Proprietary extensions | N/A | Not implemented | N/A | N/A | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| .. [1] Device supports limited set of attributes. | ||
| .. [2] Digesting keys is not supported. | ||
| .. [3] Untested: requires support in device. | ||
| .. [4] Default mechanism not supported, must specify a mechanism. | ||
| .. [5] From existing domain parameters. | ||
| .. [6] Local domain parameters only. | ||
| .. [7] Generates security warnings about the derived key. | ||
| .. [8] `store` parameter is ignored, all keys are stored. | ||
| .. [9] Encryption/verify not supported, extract the public key | ||
| Python version: | ||
| * 3.4 (with `aenum`) | ||
| * 3.5 (with `aenum`) | ||
| * 3.6 | ||
| PKCS#11 versions: | ||
| * 2.11 | ||
| * 2.20 | ||
| * 2.40 | ||
| Feel free to send pull requests for any functionality that's not exposed. The | ||
| code is designed to be readable and expose the PKCS #11 spec in a | ||
| straight-forward way. | ||
| If you want your device supported, get in touch! | ||
| More info on PKCS #11 | ||
| --------------------- | ||
| The latest version of the PKCS #11 spec is available from OASIS: | ||
| http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html | ||
| You should also consult the documentation for your PKCS #11 implementation. | ||
| Many implementations expose additional vendor options configurable in your | ||
| environment, including alternative features, modes and debugging | ||
| information. | ||
| License | ||
| ------- | ||
| MIT License | ||
| Copyright (c) 2017 Danielle Madeley | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. | ||
| Platform: UNKNOWN | ||
| Classifier: License :: OSI Approved :: MIT License | ||
| Version: 0.8.0 | ||
| Summary: PKCS#11 support for Python | ||
| Author-email: Andrey Kislyuk <kislyuk@gmail.com>, Danielle Madeley <danielle@madeley.id.au> | ||
| Maintainer-email: Andrey Kislyuk <kislyuk@gmail.com> | ||
| License-Expression: MIT | ||
| Project-URL: Homepage, https://python-pkcs11.readthedocs.io/en/latest/ | ||
| Project-URL: Documentation, https://python-pkcs11.readthedocs.io/en/latest/ | ||
| Project-URL: Issues, https://github.com/pyauth/python-pkcs11/issues | ||
| Project-URL: Repository, https://github.com/pyauth/python-pkcs11 | ||
| Classifier: Programming Language :: Python | ||
| Classifier: Programming Language :: Python :: 3 | ||
| Classifier: Programming Language :: Python :: 3.5 | ||
| Classifier: Programming Language :: Python :: 3.6 | ||
| Classifier: Programming Language :: Python :: 3.7 | ||
| Classifier: Programming Language :: Python :: 3.8 | ||
| Classifier: Programming Language :: Python :: 3.9 | ||
| Classifier: Programming Language :: Python :: 3.10 | ||
| Classifier: Programming Language :: Python :: 3.11 | ||
| Classifier: Programming Language :: Python :: 3.12 | ||
| Classifier: Programming Language :: Python :: 3.13 | ||
| Classifier: Topic :: Security :: Cryptography | ||
| Requires-Python: >=3.9 | ||
| Description-Content-Type: text/x-rst | ||
| License-File: LICENSE | ||
| Requires-Dist: asn1crypto>=1.5.1 | ||
| Dynamic: license-file | ||
| .. image:: https://travis-ci.org/danni/python-pkcs11.svg?branch=master | ||
| :target: https://travis-ci.org/danni/python-pkcs11 | ||
| Python PKCS#11 - High Level Wrapper API | ||
| ======================================= | ||
| A high level, "more Pythonic" interface to the PKCS#11 (Cryptoki) standard | ||
| to support HSM and Smartcard devices in Python. | ||
| The interface is designed to follow the logical structure of a HSM, with | ||
| useful defaults for obscurely documented parameters. Many APIs will optionally | ||
| accept iterables and act as generators, allowing you to stream large data | ||
| blocks for symmetric encryption. | ||
| python-pkcs11 also includes numerous utility functions to convert between PKCS | ||
| #11 data structures and common interchange formats including PKCS #1 and X.509. | ||
| python-pkcs11 is fully documented and has a full integration test suite for all | ||
| features. | ||
| Historically, this project used to run continuous integration tests against several | ||
| HSM platforms, but this test setup has not been maintained over time. Currently, | ||
| the integration tests in GitHub Actions use SoftHSMv2 as a baseline. If you would like | ||
| to contribute some CI setup with additional PKCS#11 implementations or actual HSMs, | ||
| let's chat! | ||
| Source: https://github.com/pyauth/python-pkcs11 | ||
| Documentation: http://python-pkcs11.readthedocs.io/en/latest/ | ||
| Getting Started | ||
| --------------- | ||
| Install from Pip: | ||
| :: | ||
| pip install python-pkcs11 | ||
| Or build from source: | ||
| :: | ||
| python -m build . | ||
| Or using ``uv``: | ||
| :: | ||
| uv build | ||
| Assuming your PKCS#11 library is set as `PKCS11_MODULE` and contains a | ||
| token named `DEMO`: | ||
| AES | ||
| ~~~ | ||
| :: | ||
| import pkcs11 | ||
| # Initialise our PKCS#11 library | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an AES key in this session | ||
| key = session.generate_key(pkcs11.KeyType.AES, 256) | ||
| # Get an initialisation vector | ||
| iv = session.generate_random(128) # AES blocks are fixed at 128 bits | ||
| # Encrypt our data | ||
| crypttext = key.encrypt(data, mechanism_param=iv) | ||
| 3DES | ||
| ~~~~ | ||
| :: | ||
| import pkcs11 | ||
| # Initialise our PKCS#11 library | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate a DES key in this session | ||
| key = session.generate_key(pkcs11.KeyType.DES3) | ||
| # Get an initialisation vector | ||
| iv = session.generate_random(64) # DES blocks are fixed at 64 bits | ||
| # Encrypt our data | ||
| crypttext = key.encrypt(data, mechanism_param=iv) | ||
| RSA | ||
| ~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an RSA keypair in this session | ||
| pub, priv = session.generate_keypair(pkcs11.KeyType.RSA, 2048) | ||
| # Encrypt as one block | ||
| crypttext = pub.encrypt(data) | ||
| DSA | ||
| ~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an DSA keypair in this session | ||
| pub, priv = session.generate_keypair(pkcs11.KeyType.DSA, 1024) | ||
| # Sign | ||
| signature = priv.sign(data) | ||
| ECDSA | ||
| ~~~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| data = b'INPUT DATA' | ||
| # Open a session on our token | ||
| with token.open(user_pin='1234') as session: | ||
| # Generate an EC keypair in this session from a named curve | ||
| ecparams = session.create_domain_parameters( | ||
| pkcs11.KeyType.EC, { | ||
| pkcs11.Attribute.EC_PARAMS: pkcs11.util.ec.encode_named_curve_parameters('secp256r1'), | ||
| }, local=True) | ||
| pub, priv = ecparams.generate_keypair() | ||
| # Sign | ||
| signature = priv.sign(data) | ||
| Diffie-Hellman | ||
| ~~~~~~~~~~~~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| with token.open() as session: | ||
| # Given shared Diffie-Hellman parameters | ||
| parameters = session.create_domain_parameters(pkcs11.KeyType.DH, { | ||
| pkcs11.Attribute.PRIME: prime, # Diffie-Hellman parameters | ||
| pkcs11.Attribute.BASE: base, | ||
| }) | ||
| # Generate a DH key pair from the public parameters | ||
| public, private = parameters.generate_keypair() | ||
| # Share the public half of it with our other party. | ||
| _network_.write(public[Attribute.VALUE]) | ||
| # And get their shared value | ||
| other_value = _network_.read() | ||
| # Derive a shared session key with perfect forward secrecy | ||
| session_key = private.derive_key( | ||
| pkcs11.KeyType.AES, 128, | ||
| mechanism_param=other_value) | ||
| Elliptic-Curve Diffie-Hellman | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| :: | ||
| import pkcs11 | ||
| lib = pkcs11.lib(os.environ['PKCS11_MODULE']) | ||
| token = lib.get_token(token_label='DEMO') | ||
| with token.open() as session: | ||
| # Given DER encocded EC parameters, e.g. from | ||
| # openssl ecparam -outform der -name <named curve> | ||
| parameters = session.create_domain_parameters(pkcs11.KeyType.EC, { | ||
| pkcs11.Attribute.EC_PARAMS: ecparams, | ||
| }) | ||
| # Generate a DH key pair from the public parameters | ||
| public, private = parameters.generate_keypair() | ||
| # Share the public half of it with our other party. | ||
| _network_.write(public[pkcs11.Attribute.EC_POINT]) | ||
| # And get their shared value | ||
| other_value = _network_.read() | ||
| # Derive a shared session key | ||
| session_key = private.derive_key( | ||
| pkcs11.KeyType.AES, 128, | ||
| mechanism_param=(pkcs11.KDF.NULL, None, other_value)) | ||
| Tested Compatibility | ||
| -------------------- | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Functionality | SoftHSMv2 | Thales nCipher | Opencryptoki | OpenSC (Nitrokey) | | ||
| +==============================+==============+=================+==============+===================+ | ||
| | Get Slots/Tokens | Works | Works | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Get Mechanisms | Works | Works | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Initialize token | Not implemented | | ||
| +------------------------------+-------------------------------------------------------------------+ | ||
| | Slot events | Not implemented | | ||
| +------------------------------+-------------------------------------------------------------------+ | ||
| | Alternative authentication | Not implemented | | ||
| | path | | | ||
| +------------------------------+-------------------------------------------------------------------+ | ||
| | `Always authenticate` keys | Not implemented | | ||
| +-------------+----------------+--------------+-----------------+--------------+-------------------+ | ||
| | Create/Copy | Keys | Works | Works | Errors | Create | | ||
| | +----------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Certificates | Caveats [1]_ | Caveats [1]_ | Caveats [1]_ | ? | | ||
| | +----------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Domain Params | Caveats [1]_ | Caveats [1]_ | ? | N/A | | ||
| +-------------+----------------+--------------+-----------------+--------------+-------------------+ | ||
| | Destroy Object | Works | N/A | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Generate Random | Works | Works | Works | Works | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Seed Random | Works | N/A | N/A | N/A | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Digest (Data & Keys) | Works | Caveats [2]_ | Works | Works | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | AES | Generate key | Works | Works | Works | N/A | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Encrypt/Decrypt | Works | Works | Works | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Wrap/Unwrap | ? [3]_ | Works | Errors | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Sign/Verify | Works | Works [4]_ | N/A | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | DES2/ | Generate key | Works | Works | Works | N/A | | ||
| | DES3 +---------------------+--------------+-----------------+--------------+ | | ||
| | | Encrypt/Decrypt | Works | Works | Works | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Wrap/Unwrap | ? | ? | ? | | | ||
| | +---------------------+--------------+-----------------+--------------+ | | ||
| | | Sign/Verify | ? | ? | ? | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | RSA | Generate key pair | Works | Works | Works | Works [4]_ [8]_ | | ||
| | +---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Encrypt/Decrypt | Works | Works | Works | Decrypt only [9]_ | | ||
| | +---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Wrap/Unwrap | Works | Works | Works | N/A | | ||
| | +---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | | Sign/Verify | Works | Works | Works | Works | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | DSA | Generate parameters | Works | Error | N/A | N/A | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Generate key pair | Works | Caveats [5]_ | | | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Sign/Verify | Works | Works [4]_ | | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | DH | Generate parameters | Works | N/A | N/A | N/A | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Generate key pair | Works | Caveats [6]_ | | | | ||
| | +---------------------+--------------+-----------------+ | | | ||
| | | Derive Key | Works | Caveats [7]_ | | | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | EC | Generate key pair | Caveats [6]_ | ? [3]_ | N/A | Works | | ||
| | +---------------------+--------------+-----------------+ +-------------------+ | ||
| | | Sign/Verify (ECDSA) | Works [4]_ | ? [3]_ | | Sign only [9]_ | | ||
| | +---------------------+--------------+-----------------+ +-------------------+ | ||
| | | Derive key (ECDH) | Works | ? [3]_ | | ? | | ||
| +--------+---------------------+--------------+-----------------+--------------+-------------------+ | ||
| | Proprietary extensions | N/A | Not implemented | N/A | N/A | | ||
| +------------------------------+--------------+-----------------+--------------+-------------------+ | ||
| .. [1] Device supports limited set of attributes. | ||
| .. [2] Digesting keys is not supported. | ||
| .. [3] Untested: requires support in device. | ||
| .. [4] Default mechanism not supported, must specify a mechanism. | ||
| .. [5] From existing domain parameters. | ||
| .. [6] Local domain parameters only. | ||
| .. [7] Generates security warnings about the derived key. | ||
| .. [8] `store` parameter is ignored, all keys are stored. | ||
| .. [9] Encryption/verify not supported, extract the public key | ||
| Python version: | ||
| * >= 3.9 | ||
| PKCS#11 versions: | ||
| * 2.11 | ||
| * 2.20 | ||
| * 2.40 | ||
| * 3.1 | ||
| Feel free to send pull requests for any functionality that's not exposed. The | ||
| code is designed to be readable and expose the PKCS #11 spec in a | ||
| straight-forward way. | ||
| If you want your device supported, get in touch! | ||
| More info on PKCS #11 | ||
| --------------------- | ||
| The latest version of the PKCS #11 spec is available from OASIS: | ||
| http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html | ||
| You should also consult the documentation for your PKCS #11 implementation. | ||
| Many implementations expose additional vendor options configurable in your | ||
| environment, including alternative features, modes and debugging | ||
| information. | ||
| License | ||
| ------- | ||
| MIT License | ||
| Copyright (c) 2017 Danielle Madeley and contributors | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. |
@@ -1,5 +0,1 @@ | ||
| asn1crypto | ||
| cached-property | ||
| [:python_version < "3.6"] | ||
| aenum | ||
| asn1crypto>=1.5.1 |
| .gitignore | ||
| .travis.yml | ||
| .python-version | ||
| .readthedocs.yaml | ||
| Dockerfile | ||
| LICENSE | ||
| MANIFEST.in | ||
| README.rst | ||
| dev-requirements.in | ||
| dev-requirements.txt | ||
| requirements.in | ||
| requirements.txt | ||
| setup.py | ||
| pyproject.toml | ||
| uv.lock | ||
| .github/release-template.md | ||
| .github/actions/install-softhsm/action.yml | ||
| .github/workflows/quality.yml | ||
| .github/workflows/release.yml | ||
| .github/workflows/tests.yml | ||
| docs/Makefile | ||
@@ -17,3 +23,6 @@ docs/api.rst | ||
| docs/opensc.rst | ||
| extern/.gitignore | ||
| extern/cryptoki.h | ||
| extern/load_module.c | ||
| extern/load_module.h | ||
| extern/pkcs11.h | ||
@@ -23,7 +32,4 @@ extern/pkcs11f.h | ||
| pkcs11/__init__.py | ||
| pkcs11/_errors.pyx | ||
| pkcs11/_mswin.pxd | ||
| pkcs11/_pkcs11.pxd | ||
| pkcs11/_pkcs11.pyx | ||
| pkcs11/_pkcs11_defn.pxd | ||
| pkcs11/_utils.pyx | ||
| pkcs11/constants.py | ||
@@ -58,8 +64,2 @@ pkcs11/defaults.py | ||
| tests/test_threading.py | ||
| tests/test_x509.py | ||
| tools/buildbot/build.sh | ||
| tools/buildbot/install.sh | ||
| tools/buildbot/test.sh | ||
| tools/nfast/build.sh | ||
| tools/nfast/install.sh | ||
| tools/nfast/test.sh | ||
| tests/test_x509.py |
+21
-11
@@ -0,1 +1,4 @@ | ||
| .. image:: https://travis-ci.org/danni/python-pkcs11.svg?branch=master | ||
| :target: https://travis-ci.org/danni/python-pkcs11 | ||
| Python PKCS#11 - High Level Wrapper API | ||
@@ -16,9 +19,11 @@ ======================================= | ||
| python-pkcs11 is fully documented and has a full integration test suite for all | ||
| features, with continuous integration against multiple HSM platforms including: | ||
| features. | ||
| * Thales nCipher | ||
| * Opencryptoki TPM | ||
| * OpenSC/Smartcard-HSM/Nitrokey HSM | ||
| Historically, this project used to run continuous integration tests against several | ||
| HSM platforms, but this test setup has not been maintained over time. Currently, | ||
| the integration tests in GitHub Actions use SoftHSMv2 as a baseline. If you would like | ||
| to contribute some CI setup with additional PKCS#11 implementations or actual HSMs, | ||
| let's chat! | ||
| Source: https://github.com/danni/python-pkcs11 | ||
| Source: https://github.com/pyauth/python-pkcs11 | ||
@@ -41,4 +46,10 @@ Documentation: http://python-pkcs11.readthedocs.io/en/latest/ | ||
| python setup.py build | ||
| python -m build . | ||
| Or using ``uv``: | ||
| :: | ||
| uv build | ||
| Assuming your PKCS#11 library is set as `PKCS11_MODULE` and contains a | ||
@@ -150,3 +161,3 @@ token named `DEMO`: | ||
| pkcs11.KeyType.EC, { | ||
| pkcs11.Attribute.EC_PARAMS: pkcs11.util.ec.encode_named_curve_parameters('prime256v1'), | ||
| pkcs11.Attribute.EC_PARAMS: pkcs11.util.ec.encode_named_curve_parameters('secp256r1'), | ||
| }, local=True) | ||
@@ -309,5 +320,3 @@ pub, priv = ecparams.generate_keypair() | ||
| * 3.4 (with `aenum`) | ||
| * 3.5 (with `aenum`) | ||
| * 3.6 | ||
| * >= 3.9 | ||
@@ -319,2 +328,3 @@ PKCS#11 versions: | ||
| * 2.40 | ||
| * 3.1 | ||
@@ -344,3 +354,3 @@ Feel free to send pull requests for any functionality that's not exposed. The | ||
| Copyright (c) 2017 Danielle Madeley | ||
| Copyright (c) 2017 Danielle Madeley and contributors | ||
@@ -347,0 +357,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy |
+28
-21
@@ -21,26 +21,28 @@ """ | ||
| try: | ||
| LIB = os.environ['PKCS11_MODULE'] | ||
| except KeyError: | ||
| raise RuntimeError("Must define `PKCS11_MODULE' to run tests.") | ||
| LIB = os.environ["PKCS11_MODULE"] | ||
| except KeyError as ex: | ||
| raise RuntimeError("Must define `PKCS11_MODULE' to run tests.") from ex | ||
| try: | ||
| TOKEN = os.environ['PKCS11_TOKEN_LABEL'] | ||
| except KeyError: | ||
| raise RuntimeError("Must define `PKCS11_TOKEN_LABEL' to run tests.") | ||
| TOKEN = os.environ["PKCS11_TOKEN_LABEL"] | ||
| except KeyError as ex: | ||
| raise RuntimeError("Must define `PKCS11_TOKEN_LABEL' to run tests.") from ex | ||
| TOKEN_PIN = os.environ.get('PKCS11_TOKEN_PIN') # Can be None | ||
| TOKEN_PIN = os.environ.get("PKCS11_TOKEN_PIN") # Can be None | ||
| if TOKEN_PIN is None: | ||
| warn("`PKCS11_TOKEN_PIN' env variable is unset.") | ||
| warn("`PKCS11_TOKEN_PIN' env variable is unset.", stacklevel=2) | ||
| TOKEN_SO_PIN = os.environ.get('PKCS11_TOKEN_SO_PIN') | ||
| TOKEN_SO_PIN = os.environ.get("PKCS11_TOKEN_SO_PIN") | ||
| if TOKEN_SO_PIN is None: | ||
| TOKEN_SO_PIN = TOKEN_PIN | ||
| warn("`PKCS11_TOKEN_SO_PIN' env variable is unset. Using value from `PKCS11_TOKEN_PIN'") | ||
| warn( | ||
| "`PKCS11_TOKEN_SO_PIN' env variable is unset. Using value from `PKCS11_TOKEN_PIN'", | ||
| stacklevel=2, | ||
| ) | ||
| OPENSSL = shutil.which('openssl', path=os.environ.get('OPENSSL_PATH')) | ||
| OPENSSL = shutil.which("openssl", path=os.environ.get("OPENSSL_PATH")) | ||
| if OPENSSL is None: | ||
| warn("Path to OpenSSL not found. Please adjust `PATH' or define `OPENSSL_PATH'") | ||
| warn("Path to OpenSSL not found. Please adjust `PATH' or define `OPENSSL_PATH'", stacklevel=2) | ||
@@ -88,4 +90,3 @@ | ||
| if unavailable: | ||
| raise unittest.SkipTest("Requires %s" | ||
| % ', '.join(map(str, unavailable))) | ||
| raise unittest.SkipTest("Requires %s" % ", ".join(map(str, unavailable))) | ||
@@ -121,8 +122,11 @@ def inner(func): | ||
| """ | ||
| # trick: str.endswith() can accept tuples, | ||
| # see https://stackoverflow.com/questions/18351951/check-if-string-ends-with-one-of-the-strings-from-a-list | ||
| softhsm2 = LIB.lower().endswith(('libsofthsm2.so', 'libsofthsm2.dylib', 'softhsm2.dll', 'softhsm2-x64.dll')) | ||
| nfast = LIB.lower().endswith(('libcknfast.so', 'cknfast.dll')) | ||
| opencryptoki = LIB.endswith('libopencryptoki.so') | ||
| travis = os.environ.get('TRAVIS') == 'true' | ||
| softhsm2 = LIB.lower().endswith( | ||
| ("libsofthsm2.so", "libsofthsm2.dylib", "softhsm2.dll", "softhsm2-x64.dll") | ||
| ) | ||
| nfast = LIB.lower().endswith(("libcknfast.so", "cknfast.dll")) | ||
| opencryptoki = LIB.endswith("libopencryptoki.so") | ||
| travis = os.environ.get("TRAVIS") == "true" | ||
@@ -134,2 +138,3 @@ | ||
| """ | ||
| # openssl is searched across the exec path. Optionally, OPENSSL_PATH env variable can be defined | ||
@@ -139,2 +144,3 @@ # in case there is no direct path to it (i.e. PATH does not point to it) | ||
| class Only: | ||
@@ -144,5 +150,7 @@ """ | ||
| """ | ||
| softhsm2 = unittest.skipUnless(Is.softhsm2, "SoftHSMv2 only") | ||
| openssl = unittest.skipUnless(Avail.openssl, "openssl not found in the path") | ||
| class Not: | ||
@@ -155,4 +163,3 @@ """ | ||
| nfast = unittest.skipIf(Is.nfast, "Not supported by nFast") | ||
| opencryptoki = unittest.skipIf(Is.opencryptoki, | ||
| "Not supported by OpenCryptoki") | ||
| opencryptoki = unittest.skipIf(Is.opencryptoki, "Not supported by OpenCryptoki") | ||
@@ -159,0 +166,0 @@ |
+306
-42
@@ -5,10 +5,11 @@ """ | ||
| from parameterized import parameterized | ||
| import pkcs11 | ||
| from pkcs11 import Mechanism | ||
| from . import TestCase, requires, FIXME | ||
| from . import FIXME, TestCase, requires | ||
| class AESTests(TestCase): | ||
| @requires(Mechanism.AES_KEY_GEN) | ||
@@ -21,4 +22,4 @@ def setUp(self): | ||
| def test_encrypt(self): | ||
| data = b'INPUT DATA' | ||
| iv = b'0' * 16 | ||
| data = b"INPUT DATA" | ||
| iv = b"0" * 16 | ||
@@ -31,3 +32,3 @@ crypttext = self.key.encrypt(data, mechanism_param=iv) | ||
| # Ensure we didn't just get 16 nulls | ||
| self.assertFalse(all(c == '\0' for c in crypttext)) | ||
| self.assertFalse(all(c == "\0" for c in crypttext)) | ||
@@ -40,9 +41,9 @@ text = self.key.decrypt(crypttext, mechanism_param=iv) | ||
| data = ( | ||
| b'I' * 16, | ||
| b'N' * 16, | ||
| b'P' * 16, | ||
| b'U' * 16, | ||
| b'T' * 10, # don't align to the blocksize | ||
| b"I" * 16, | ||
| b"N" * 16, | ||
| b"P" * 16, | ||
| b"U" * 16, | ||
| b"T" * 10, # don't align to the blocksize | ||
| ) | ||
| iv = b'0' * 16 | ||
| iv = b"0" * 16 | ||
@@ -53,20 +54,17 @@ cryptblocks = list(self.key.encrypt(data, mechanism_param=iv)) | ||
| crypttext = b''.join(cryptblocks) | ||
| crypttext = b"".join(cryptblocks) | ||
| self.assertNotEqual(b''.join(data), crypttext) | ||
| self.assertNotEqual(b"".join(data), crypttext) | ||
| # We should be aligned to the block size | ||
| self.assertEqual(len(crypttext) % 16, 0) | ||
| # Ensure we didn't just get 16 nulls | ||
| self.assertFalse(all(c == '\0' for c in crypttext)) | ||
| self.assertFalse(all(c == "\0" for c in crypttext)) | ||
| text = b''.join(self.key.decrypt(cryptblocks, mechanism_param=iv)) | ||
| self.assertEqual(b''.join(data), text) | ||
| text = b"".join(self.key.decrypt(cryptblocks, mechanism_param=iv)) | ||
| self.assertEqual(b"".join(data), text) | ||
| @requires(Mechanism.AES_CBC_PAD) | ||
| def test_encrypt_whacky_sizes(self): | ||
| data = [ | ||
| (char * ord(char)).encode('utf-8') | ||
| for char in 'HELLO WORLD' | ||
| ] | ||
| iv = b'0' * 16 | ||
| data = [(char * ord(char)).encode("utf-8") for char in "HELLO WORLD"] | ||
| iv = b"0" * 16 | ||
@@ -76,7 +74,7 @@ cryptblocks = list(self.key.encrypt(data, mechanism_param=iv)) | ||
| self.assertEqual(b''.join(data), b''.join(textblocks)) | ||
| self.assertEqual(b"".join(data), b"".join(textblocks)) | ||
| @requires(Mechanism.AES_CBC_PAD) | ||
| def test_encrypt_big_string(self): | ||
| data = b'HELLO WORLD' * 1024 | ||
| data = b"HELLO WORLD" * 1024 | ||
@@ -91,3 +89,3 @@ iv = self.session.generate_random(128) | ||
| def test_sign(self): | ||
| data = b'HELLO WORLD' | ||
| data = b"HELLO WORLD" | ||
@@ -98,3 +96,3 @@ signature = self.key.sign(data) | ||
| self.assertTrue(self.key.verify(data, signature)) | ||
| self.assertFalse(self.key.verify(data, b'1234')) | ||
| self.assertFalse(self.key.verify(data, b"1234")) | ||
@@ -104,7 +102,7 @@ @requires(Mechanism.AES_MAC) | ||
| data = ( | ||
| b'I' * 16, | ||
| b'N' * 16, | ||
| b'P' * 16, | ||
| b'U' * 16, | ||
| b'T' * 10, # don't align to the blocksize | ||
| b"I" * 16, | ||
| b"N" * 16, | ||
| b"P" * 16, | ||
| b"U" * 16, | ||
| b"T" * 10, # don't align to the blocksize | ||
| ) | ||
@@ -120,16 +118,282 @@ | ||
| def test_wrap(self): | ||
| key = self.session.generate_key(pkcs11.KeyType.AES, 128, template={ | ||
| pkcs11.Attribute.EXTRACTABLE: True, | ||
| pkcs11.Attribute.SENSITIVE: False, | ||
| }) | ||
| key = self.session.generate_key( | ||
| pkcs11.KeyType.AES, | ||
| 128, | ||
| template={ | ||
| pkcs11.Attribute.EXTRACTABLE: True, | ||
| pkcs11.Attribute.SENSITIVE: False, | ||
| }, | ||
| ) | ||
| data = self.key.wrap_key(key) | ||
| key2 = self.key.unwrap_key(pkcs11.ObjectClass.SECRET_KEY, | ||
| pkcs11.KeyType.AES, | ||
| data, template={ | ||
| pkcs11.Attribute.EXTRACTABLE: True, | ||
| pkcs11.Attribute.SENSITIVE: False, | ||
| }) | ||
| key2 = self.key.unwrap_key( | ||
| pkcs11.ObjectClass.SECRET_KEY, | ||
| pkcs11.KeyType.AES, | ||
| data, | ||
| template={ | ||
| pkcs11.Attribute.EXTRACTABLE: True, | ||
| pkcs11.Attribute.SENSITIVE: False, | ||
| }, | ||
| ) | ||
| self.assertEqual(key[pkcs11.Attribute.VALUE], | ||
| key2[pkcs11.Attribute.VALUE]) | ||
| self.assertEqual(key[pkcs11.Attribute.VALUE], key2[pkcs11.Attribute.VALUE]) | ||
| @parameterized.expand( | ||
| [ | ||
| ("POSITIVE_128_BIT", 128, 16, TestCase.assertIsNotNone), | ||
| ("POSITIVE_128_BIT_LONG_IV", 128, 32, TestCase.assertIsNotNone), | ||
| ("NEGATIVE_128_BIT_BAD_IV", 128, 15, TestCase.assertIsNone), | ||
| ("POSITIVE_256_BIT_LONG_IV", 256, 32, TestCase.assertIsNotNone), | ||
| ("NEGATIVE_256_BIT_SHORT_IV", 256, 16, TestCase.assertIsNone), | ||
| ("NEGATIVE_256_BIT_BAD_IV", 256, 31, TestCase.assertIsNone), | ||
| ] | ||
| ) | ||
| @requires(Mechanism.AES_ECB_ENCRYPT_DATA) | ||
| @FIXME.opencryptoki # can't set key attributes | ||
| def test_derive_using_ecb_encrypt(self, test_type, test_key_length, iv_length, assert_fn): | ||
| """Function to test AES Key Derivation using the ECB_ENCRYPT Mechanism. | ||
| Refer to Section 2.15 of http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/errata01/os/pkcs11-curr-v2.40-errata01-os-complete.html#_Toc441850521 | ||
| """ | ||
| # Create the Master Key | ||
| capabilities = pkcs11.defaults.DEFAULT_KEY_CAPABILITIES[pkcs11.KeyType.AES] | ||
| capabilities |= pkcs11.MechanismFlag.DERIVE | ||
| key = self.session.generate_key( | ||
| pkcs11.KeyType.AES, | ||
| key_length=test_key_length, | ||
| capabilities=capabilities, | ||
| template={ | ||
| pkcs11.Attribute.EXTRACTABLE: True, | ||
| pkcs11.Attribute.DERIVE: True, | ||
| pkcs11.Attribute.SENSITIVE: False, | ||
| }, | ||
| ) | ||
| self.assertTrue( | ||
| key is not None, "Failed to create {}-bit Master Key".format(test_key_length) | ||
| ) | ||
| # Derive a Key from the Master Key | ||
| iv = b"0" * iv_length | ||
| try: | ||
| derived_key = key.derive_key( | ||
| pkcs11.KeyType.AES, | ||
| key_length=test_key_length, | ||
| capabilities=capabilities, | ||
| mechanism=Mechanism.AES_ECB_ENCRYPT_DATA, | ||
| mechanism_param=iv, | ||
| template={ | ||
| pkcs11.Attribute.EXTRACTABLE: True, | ||
| pkcs11.Attribute.SENSITIVE: False, | ||
| }, | ||
| ) | ||
| except (pkcs11.exceptions.MechanismParamInvalid, pkcs11.exceptions.FunctionFailed): | ||
| derived_key = None | ||
| assert_fn(self, derived_key, "{}-bit Key Derivation Failure".format(test_key_length)) | ||
| @parameterized.expand( | ||
| [ | ||
| ("POSITIVE_128_BIT", 128, 16), | ||
| ("POSITIVE_256_BIT_LONG_IV", 256, 32), | ||
| ] | ||
| ) | ||
| @requires(Mechanism.AES_ECB_ENCRYPT_DATA) | ||
| @FIXME.opencryptoki # can't set key attributes | ||
| def test_encrypt_with_key_derived_using_ecb_encrypt( | ||
| self, test_type, test_key_length, iv_length | ||
| ): | ||
| """Function to test Data Encryption/Decryption using a Derived AES Key. | ||
| Function to test Data Encryption/Decryption using an AES Key | ||
| Derived by the ECB_ENCRYPT Mechanism. | ||
| Refer to Section 2.15 of http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/errata01/os/pkcs11-curr-v2.40-errata01-os-complete.html#_Toc441850521 | ||
| """ | ||
| # Create the Master Key | ||
| capabilities = pkcs11.defaults.DEFAULT_KEY_CAPABILITIES[pkcs11.KeyType.AES] | ||
| capabilities |= pkcs11.MechanismFlag.DERIVE | ||
| key = self.session.generate_key( | ||
| pkcs11.KeyType.AES, | ||
| key_length=test_key_length, | ||
| capabilities=capabilities, | ||
| template={ | ||
| pkcs11.Attribute.EXTRACTABLE: True, | ||
| pkcs11.Attribute.DERIVE: True, | ||
| pkcs11.Attribute.SENSITIVE: False, | ||
| }, | ||
| ) | ||
| self.assertTrue( | ||
| key is not None, "Failed to create {}-bit Master Key".format(test_key_length) | ||
| ) | ||
| # Derive a Key from the Master Key | ||
| iv = b"0" * iv_length | ||
| try: | ||
| derived_key = key.derive_key( | ||
| pkcs11.KeyType.AES, | ||
| key_length=test_key_length, | ||
| capabilities=capabilities, | ||
| mechanism=Mechanism.AES_ECB_ENCRYPT_DATA, | ||
| mechanism_param=iv, | ||
| template={ | ||
| pkcs11.Attribute.EXTRACTABLE: True, | ||
| pkcs11.Attribute.SENSITIVE: False, | ||
| }, | ||
| ) | ||
| except (pkcs11.exceptions.MechanismParamInvalid, pkcs11.exceptions.FunctionFailed): | ||
| derived_key = None | ||
| self.assertTrue( | ||
| derived_key is not None, "Failed to derive {}-bit Derived Key".format(test_key_length) | ||
| ) | ||
| # Test capability of Key to Encrypt/Decrypt data | ||
| data = b"HELLO WORLD" * 1024 | ||
| iv = self.session.generate_random(128) | ||
| crypttext = self.key.encrypt(data, mechanism_param=iv) | ||
| text = self.key.decrypt(crypttext, mechanism_param=iv) | ||
| self.assertEqual(text, data) | ||
| @parameterized.expand( | ||
| [ | ||
| ("POSITIVE_128_BIT", 128, 16, 16, TestCase.assertIsNotNone), | ||
| ("POSITIVE_128_BIT_LONG_DATA", 128, 16, 64, TestCase.assertIsNotNone), | ||
| ("NEGATIVE_128_BIT_BAD_IV", 128, 15, 16, TestCase.assertIsNone), | ||
| ("NEGATIVE_128_BIT_BAD_DATA", 128, 16, 31, TestCase.assertIsNone), | ||
| ("POSITIVE_256_BIT", 256, 16, 32, TestCase.assertIsNotNone), | ||
| ("POSITIVE_256_BIT_LONG_DATA", 256, 16, 64, TestCase.assertIsNotNone), | ||
| ("NEGATIVE_256_BIT_BAD_IV", 256, 15, 16, TestCase.assertIsNone), | ||
| ("NEGATIVE_256_BIT_BAD_DATA", 256, 16, 31, TestCase.assertIsNone), | ||
| ("NEGATIVE_256_BIT_SHORT_DATA", 256, 16, 16, TestCase.assertIsNone), | ||
| ] | ||
| ) | ||
| @requires(Mechanism.AES_CBC_ENCRYPT_DATA) | ||
| @FIXME.opencryptoki # can't set key attributes | ||
| def test_derive_using_cbc_encrypt( | ||
| self, test_type, test_key_length, iv_length, data_length, assert_fn | ||
| ): | ||
| """Function to test AES Key Derivation using the CBC_ENCRYPT Mechanism. | ||
| Refer to Section 2.15 of http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/errata01/os/pkcs11-curr-v2.40-errata01-os-complete.html#_Toc441850521 | ||
| """ | ||
| # Create the Master Key | ||
| capabilities = pkcs11.defaults.DEFAULT_KEY_CAPABILITIES[pkcs11.KeyType.AES] | ||
| capabilities |= pkcs11.MechanismFlag.DERIVE | ||
| key = self.session.generate_key( | ||
| pkcs11.KeyType.AES, | ||
| key_length=test_key_length, | ||
| capabilities=capabilities, | ||
| template={ | ||
| pkcs11.Attribute.EXTRACTABLE: True, | ||
| pkcs11.Attribute.DERIVE: True, | ||
| pkcs11.Attribute.SENSITIVE: False, | ||
| }, | ||
| ) | ||
| self.assertTrue( | ||
| key is not None, "Failed to create {}-bit Master Key".format(test_key_length) | ||
| ) | ||
| # Derive a Key from the Master Key | ||
| iv = b"0" * iv_length | ||
| data = b"1" * data_length | ||
| try: | ||
| derived_key = key.derive_key( | ||
| pkcs11.KeyType.AES, | ||
| key_length=test_key_length, | ||
| capabilities=capabilities, | ||
| mechanism=Mechanism.AES_CBC_ENCRYPT_DATA, | ||
| mechanism_param=(iv, data), | ||
| template={ | ||
| pkcs11.Attribute.EXTRACTABLE: True, | ||
| pkcs11.Attribute.SENSITIVE: False, | ||
| }, | ||
| ) | ||
| except ( | ||
| pkcs11.exceptions.MechanismParamInvalid, | ||
| pkcs11.exceptions.FunctionFailed, | ||
| IndexError, | ||
| ): | ||
| derived_key = None | ||
| assert_fn(self, derived_key, "{}-bit Key Derivation Failure".format(test_key_length)) | ||
| @parameterized.expand( | ||
| [ | ||
| ("POSITIVE_128_BIT", 128, 16, 16), | ||
| ("POSITIVE_256_BIT", 256, 16, 32), | ||
| ("POSITIVE_256_BIT_LONG_DATA", 256, 16, 64), | ||
| ] | ||
| ) | ||
| @requires(Mechanism.AES_CBC_ENCRYPT_DATA) | ||
| @FIXME.opencryptoki # can't set key attributes | ||
| def test_encrypt_with_key_derived_using_cbc_encrypt( | ||
| self, test_type, test_key_length, iv_length, data_length | ||
| ): | ||
| """Function to test Data Encryption/Decryption using a Derived AES Key. | ||
| Function to test Data Encryption/Decryption using an AES Key | ||
| Derived by the CBC_ENCRYPT Mechanism. | ||
| Refer to Section 2.15 of http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/errata01/os/pkcs11-curr-v2.40-errata01-os-complete.html#_Toc441850521 | ||
| """ | ||
| # Create the Master Key | ||
| capabilities = pkcs11.defaults.DEFAULT_KEY_CAPABILITIES[pkcs11.KeyType.AES] | ||
| capabilities |= pkcs11.MechanismFlag.DERIVE | ||
| key = self.session.generate_key( | ||
| pkcs11.KeyType.AES, | ||
| key_length=test_key_length, | ||
| capabilities=capabilities, | ||
| template={ | ||
| pkcs11.Attribute.EXTRACTABLE: True, | ||
| pkcs11.Attribute.DERIVE: True, | ||
| pkcs11.Attribute.SENSITIVE: False, | ||
| }, | ||
| ) | ||
| self.assertTrue( | ||
| key is not None, "Failed to create {}-bit Master Key".format(test_key_length) | ||
| ) | ||
| # Derive a Key from the Master Key | ||
| iv = b"0" * iv_length | ||
| data = b"1" * data_length | ||
| try: | ||
| derived_key = key.derive_key( | ||
| pkcs11.KeyType.AES, | ||
| key_length=test_key_length, | ||
| capabilities=capabilities, | ||
| mechanism=Mechanism.AES_CBC_ENCRYPT_DATA, | ||
| mechanism_param=(iv, data), | ||
| template={ | ||
| pkcs11.Attribute.EXTRACTABLE: True, | ||
| pkcs11.Attribute.SENSITIVE: False, | ||
| }, | ||
| ) | ||
| except ( | ||
| pkcs11.exceptions.MechanismParamInvalid, | ||
| pkcs11.exceptions.FunctionFailed, | ||
| IndexError, | ||
| ): | ||
| derived_key = None | ||
| self.assertTrue( | ||
| derived_key is not None, "Failed to derive {}-bit Derived Key".format(test_key_length) | ||
| ) | ||
| # Test capability of Key to Encrypt/Decrypt data | ||
| data = b"HELLO WORLD" * 1024 | ||
| iv = self.session.generate_random(128) | ||
| crypttext = self.key.encrypt(data, mechanism_param=iv) | ||
| text = self.key.decrypt(crypttext, mechanism_param=iv) | ||
| self.assertEqual(text, data) |
@@ -27,6 +27,6 @@ """ | ||
| iv = self.session.generate_random(64) | ||
| crypttext = key.encrypt('PLAIN TEXT_', mechanism_param=iv) | ||
| crypttext = key.encrypt("PLAIN TEXT_", mechanism_param=iv) | ||
| plaintext = key.decrypt(crypttext, mechanism_param=iv) | ||
| self.assertEqual(plaintext, b'PLAIN TEXT_') | ||
| self.assertEqual(plaintext, b"PLAIN TEXT_") | ||
@@ -38,5 +38,5 @@ @requires(Mechanism.DES3_KEY_GEN, Mechanism.DES3_CBC_PAD) | ||
| iv = self.session.generate_random(64) | ||
| crypttext = key.encrypt('PLAIN TEXT_', mechanism_param=iv) | ||
| crypttext = key.encrypt("PLAIN TEXT_", mechanism_param=iv) | ||
| plaintext = key.decrypt(crypttext, mechanism_param=iv) | ||
| self.assertEqual(plaintext, b'PLAIN TEXT_') | ||
| self.assertEqual(plaintext, b"PLAIN TEXT_") |
+311
-49
@@ -7,3 +7,3 @@ """ | ||
| from pkcs11 import Attribute, KeyType, DomainParameters, Mechanism | ||
| from pkcs11 import Attribute, DomainParameters, KeyType, Mechanism | ||
| from pkcs11.util.dh import ( | ||
@@ -15,7 +15,6 @@ decode_dh_domain_parameters, | ||
| from . import TestCase, requires, FIXME | ||
| from . import FIXME, TestCase, requires | ||
| class DHTests(TestCase): | ||
| @requires(Mechanism.DH_PKCS_KEY_PAIR_GEN, Mechanism.DH_PKCS_DERIVE) | ||
@@ -29,31 +28,291 @@ @FIXME.opencryptoki # AttributeValueInvalid when generating keypair | ||
| prime = [ | ||
| 0x0F,0x52,0xE5,0x24,0xF5,0xFA,0x9D,0xDC,0xC6,0xAB,0xE6,0x04, # noqa | ||
| 0xE4,0x20,0x89,0x8A,0xB4,0xBF,0x27,0xB5,0x4A,0x95,0x57,0xA1, # noqa | ||
| 0x06,0xE7,0x30,0x73,0x83,0x5E,0xC9,0x23,0x11,0xED,0x42,0x45, # noqa | ||
| 0xAC,0x49,0xD3,0xE3,0xF3,0x34,0x73,0xC5,0x7D,0x00,0x3C,0x86, # noqa | ||
| 0x63,0x74,0xE0,0x75,0x97,0x84,0x1D,0x0B,0x11,0xDA,0x04,0xD0, # noqa | ||
| 0xFE,0x4F,0xB0,0x37,0xDF,0x57,0x22,0x2E,0x96,0x42,0xE0,0x7C, # noqa | ||
| 0xD7,0x5E,0x46,0x29,0xAF,0xB1,0xF4,0x81,0xAF,0xFC,0x9A,0xEF, # noqa | ||
| 0xFA,0x89,0x9E,0x0A,0xFB,0x16,0xE3,0x8F,0x01,0xA2,0xC8,0xDD, # noqa | ||
| 0xB4,0x47,0x12,0xF8,0x29,0x09,0x13,0x6E,0x9D,0xA8,0xF9,0x5D, # noqa | ||
| 0x08,0x00,0x3A,0x8C,0xA7,0xFF,0x6C,0xCF,0xE3,0x7C,0x3B,0x6B, # noqa | ||
| 0xB4,0x26,0xCC,0xDA,0x89,0x93,0x01,0x73,0xA8,0x55,0x3E,0x5B, # noqa | ||
| 0x77,0x25,0x8F,0x27,0xA3,0xF1,0xBF,0x7A,0x73,0x1F,0x85,0x96, # noqa | ||
| 0x0C,0x45,0x14,0xC1,0x06,0xB7,0x1C,0x75,0xAA,0x10,0xBC,0x86, # noqa | ||
| 0x98,0x75,0x44,0x70,0xD1,0x0F,0x20,0xF4,0xAC,0x4C,0xB3,0x88, # noqa | ||
| 0x16,0x1C,0x7E,0xA3,0x27,0xE4,0xAD,0xE1,0xA1,0x85,0x4F,0x1A, # noqa | ||
| 0x22,0x0D,0x05,0x42,0x73,0x69,0x45,0xC9,0x2F,0xF7,0xC2,0x48, # noqa | ||
| 0xE3,0xCE,0x9D,0x74,0x58,0x53,0xE7,0xA7,0x82,0x18,0xD9,0x3D, # noqa | ||
| 0xAF,0xAB,0x40,0x9F,0xAA,0x4C,0x78,0x0A,0xC3,0x24,0x2D,0xDB, # noqa | ||
| 0x12,0xA9,0x54,0xE5,0x47,0x87,0xAC,0x52,0xFE,0xE8,0x3D,0x0B, # noqa | ||
| 0x56,0xED,0x9C,0x9F,0xFF,0x39,0xE5,0xE5,0xBF,0x62,0x32,0x42, # noqa | ||
| 0x08,0xAE,0x6A,0xED,0x88,0x0E,0xB3,0x1A,0x4C,0xD3,0x08,0xE4, # noqa | ||
| 0xC4,0xAA,0x2C,0xCC,0xB1,0x37,0xA5,0xC1,0xA9,0x64,0x7E,0xEB, # noqa | ||
| 0xF9,0xD3,0xF5,0x15,0x28,0xFE,0x2E,0xE2,0x7F,0xFE,0xD9,0xB9, # noqa | ||
| 0x38,0x42,0x57,0x03, # noqa | ||
| 0x0F, | ||
| 0x52, | ||
| 0xE5, | ||
| 0x24, | ||
| 0xF5, | ||
| 0xFA, | ||
| 0x9D, | ||
| 0xDC, | ||
| 0xC6, | ||
| 0xAB, | ||
| 0xE6, | ||
| 0x04, | ||
| 0xE4, | ||
| 0x20, | ||
| 0x89, | ||
| 0x8A, | ||
| 0xB4, | ||
| 0xBF, | ||
| 0x27, | ||
| 0xB5, | ||
| 0x4A, | ||
| 0x95, | ||
| 0x57, | ||
| 0xA1, | ||
| 0x06, | ||
| 0xE7, | ||
| 0x30, | ||
| 0x73, | ||
| 0x83, | ||
| 0x5E, | ||
| 0xC9, | ||
| 0x23, | ||
| 0x11, | ||
| 0xED, | ||
| 0x42, | ||
| 0x45, | ||
| 0xAC, | ||
| 0x49, | ||
| 0xD3, | ||
| 0xE3, | ||
| 0xF3, | ||
| 0x34, | ||
| 0x73, | ||
| 0xC5, | ||
| 0x7D, | ||
| 0x00, | ||
| 0x3C, | ||
| 0x86, | ||
| 0x63, | ||
| 0x74, | ||
| 0xE0, | ||
| 0x75, | ||
| 0x97, | ||
| 0x84, | ||
| 0x1D, | ||
| 0x0B, | ||
| 0x11, | ||
| 0xDA, | ||
| 0x04, | ||
| 0xD0, | ||
| 0xFE, | ||
| 0x4F, | ||
| 0xB0, | ||
| 0x37, | ||
| 0xDF, | ||
| 0x57, | ||
| 0x22, | ||
| 0x2E, | ||
| 0x96, | ||
| 0x42, | ||
| 0xE0, | ||
| 0x7C, | ||
| 0xD7, | ||
| 0x5E, | ||
| 0x46, | ||
| 0x29, | ||
| 0xAF, | ||
| 0xB1, | ||
| 0xF4, | ||
| 0x81, | ||
| 0xAF, | ||
| 0xFC, | ||
| 0x9A, | ||
| 0xEF, | ||
| 0xFA, | ||
| 0x89, | ||
| 0x9E, | ||
| 0x0A, | ||
| 0xFB, | ||
| 0x16, | ||
| 0xE3, | ||
| 0x8F, | ||
| 0x01, | ||
| 0xA2, | ||
| 0xC8, | ||
| 0xDD, | ||
| 0xB4, | ||
| 0x47, | ||
| 0x12, | ||
| 0xF8, | ||
| 0x29, | ||
| 0x09, | ||
| 0x13, | ||
| 0x6E, | ||
| 0x9D, | ||
| 0xA8, | ||
| 0xF9, | ||
| 0x5D, | ||
| 0x08, | ||
| 0x00, | ||
| 0x3A, | ||
| 0x8C, | ||
| 0xA7, | ||
| 0xFF, | ||
| 0x6C, | ||
| 0xCF, | ||
| 0xE3, | ||
| 0x7C, | ||
| 0x3B, | ||
| 0x6B, | ||
| 0xB4, | ||
| 0x26, | ||
| 0xCC, | ||
| 0xDA, | ||
| 0x89, | ||
| 0x93, | ||
| 0x01, | ||
| 0x73, | ||
| 0xA8, | ||
| 0x55, | ||
| 0x3E, | ||
| 0x5B, | ||
| 0x77, | ||
| 0x25, | ||
| 0x8F, | ||
| 0x27, | ||
| 0xA3, | ||
| 0xF1, | ||
| 0xBF, | ||
| 0x7A, | ||
| 0x73, | ||
| 0x1F, | ||
| 0x85, | ||
| 0x96, | ||
| 0x0C, | ||
| 0x45, | ||
| 0x14, | ||
| 0xC1, | ||
| 0x06, | ||
| 0xB7, | ||
| 0x1C, | ||
| 0x75, | ||
| 0xAA, | ||
| 0x10, | ||
| 0xBC, | ||
| 0x86, | ||
| 0x98, | ||
| 0x75, | ||
| 0x44, | ||
| 0x70, | ||
| 0xD1, | ||
| 0x0F, | ||
| 0x20, | ||
| 0xF4, | ||
| 0xAC, | ||
| 0x4C, | ||
| 0xB3, | ||
| 0x88, | ||
| 0x16, | ||
| 0x1C, | ||
| 0x7E, | ||
| 0xA3, | ||
| 0x27, | ||
| 0xE4, | ||
| 0xAD, | ||
| 0xE1, | ||
| 0xA1, | ||
| 0x85, | ||
| 0x4F, | ||
| 0x1A, | ||
| 0x22, | ||
| 0x0D, | ||
| 0x05, | ||
| 0x42, | ||
| 0x73, | ||
| 0x69, | ||
| 0x45, | ||
| 0xC9, | ||
| 0x2F, | ||
| 0xF7, | ||
| 0xC2, | ||
| 0x48, | ||
| 0xE3, | ||
| 0xCE, | ||
| 0x9D, | ||
| 0x74, | ||
| 0x58, | ||
| 0x53, | ||
| 0xE7, | ||
| 0xA7, | ||
| 0x82, | ||
| 0x18, | ||
| 0xD9, | ||
| 0x3D, | ||
| 0xAF, | ||
| 0xAB, | ||
| 0x40, | ||
| 0x9F, | ||
| 0xAA, | ||
| 0x4C, | ||
| 0x78, | ||
| 0x0A, | ||
| 0xC3, | ||
| 0x24, | ||
| 0x2D, | ||
| 0xDB, | ||
| 0x12, | ||
| 0xA9, | ||
| 0x54, | ||
| 0xE5, | ||
| 0x47, | ||
| 0x87, | ||
| 0xAC, | ||
| 0x52, | ||
| 0xFE, | ||
| 0xE8, | ||
| 0x3D, | ||
| 0x0B, | ||
| 0x56, | ||
| 0xED, | ||
| 0x9C, | ||
| 0x9F, | ||
| 0xFF, | ||
| 0x39, | ||
| 0xE5, | ||
| 0xE5, | ||
| 0xBF, | ||
| 0x62, | ||
| 0x32, | ||
| 0x42, | ||
| 0x08, | ||
| 0xAE, | ||
| 0x6A, | ||
| 0xED, | ||
| 0x88, | ||
| 0x0E, | ||
| 0xB3, | ||
| 0x1A, | ||
| 0x4C, | ||
| 0xD3, | ||
| 0x08, | ||
| 0xE4, | ||
| 0xC4, | ||
| 0xAA, | ||
| 0x2C, | ||
| 0xCC, | ||
| 0xB1, | ||
| 0x37, | ||
| 0xA5, | ||
| 0xC1, | ||
| 0xA9, | ||
| 0x64, | ||
| 0x7E, | ||
| 0xEB, | ||
| 0xF9, | ||
| 0xD3, | ||
| 0xF5, | ||
| 0x15, | ||
| 0x28, | ||
| 0xFE, | ||
| 0x2E, | ||
| 0xE2, | ||
| 0x7F, | ||
| 0xFE, | ||
| 0xD9, | ||
| 0xB9, | ||
| 0x38, | ||
| 0x42, | ||
| 0x57, | ||
| 0x03, | ||
| ] | ||
| parameters = self.session.create_domain_parameters(KeyType.DH, { | ||
| Attribute.PRIME: prime, | ||
| Attribute.BASE: [0x2], | ||
| }, local=True) | ||
| parameters = self.session.create_domain_parameters( | ||
| KeyType.DH, | ||
| { | ||
| Attribute.PRIME: prime, | ||
| Attribute.BASE: [0x2], | ||
| }, | ||
| local=True, | ||
| ) | ||
@@ -74,20 +333,25 @@ # Alice generate a keypair | ||
| alice_session = alice_private.derive_key( | ||
| KeyType.AES, 128, | ||
| mechanism_param=bob_value, template={ | ||
| KeyType.AES, | ||
| 128, | ||
| mechanism_param=bob_value, | ||
| template={ | ||
| Attribute.SENSITIVE: False, | ||
| Attribute.EXTRACTABLE: True, | ||
| }) | ||
| }, | ||
| ) | ||
| bob_session = bob_private.derive_key( | ||
| KeyType.AES, 128, | ||
| mechanism_param=alice_value, template={ | ||
| KeyType.AES, | ||
| 128, | ||
| mechanism_param=alice_value, | ||
| template={ | ||
| Attribute.SENSITIVE: False, | ||
| Attribute.EXTRACTABLE: True, | ||
| }) | ||
| }, | ||
| ) | ||
| self.assertEqual(alice_session[Attribute.VALUE], | ||
| bob_session[Attribute.VALUE]) | ||
| self.assertEqual(alice_session[Attribute.VALUE], bob_session[Attribute.VALUE]) | ||
| crypttext = alice_session.encrypt('HI BOB!', mechanism_param=iv) | ||
| crypttext = alice_session.encrypt("HI BOB!", mechanism_param=iv) | ||
| plaintext = bob_session.decrypt(crypttext, mechanism_param=iv) | ||
| self.assertEqual(plaintext, b'HI BOB!') | ||
| self.assertEqual(plaintext, b"HI BOB!") | ||
@@ -112,15 +376,13 @@ def test_load_params(self): | ||
| params = self.session.create_domain_parameters( | ||
| KeyType.DH, | ||
| decode_dh_domain_parameters(PARAMS), | ||
| local=True) | ||
| KeyType.DH, decode_dh_domain_parameters(PARAMS), local=True | ||
| ) | ||
| self.assertIsInstance(params, DomainParameters) | ||
| self.assertEqual(params[Attribute.PRIME][:4], | ||
| b'\xAD\x10\x7E\x1E') | ||
| self.assertEqual(params[Attribute.PRIME][:4], b"\xad\x10\x7e\x1e") | ||
| @requires(Mechanism.DH_PKCS_PARAMETER_GEN, Mechanism.DH_PKCS_KEY_PAIR_GEN) | ||
| def test_generate_params(self): | ||
| params = self.session.generate_domain_parameters(KeyType.DH, 512) | ||
| params = self.session.generate_domain_parameters(KeyType.DH, 1024) | ||
| self.assertIsInstance(params, DomainParameters) | ||
| self.assertEqual(params[Attribute.PRIME_BITS], 512) | ||
| self.assertEqual(len(params[Attribute.PRIME]) * 8, 512) | ||
| self.assertEqual(params[Attribute.PRIME_BITS], 1024) | ||
| self.assertEqual(len(params[Attribute.PRIME]) * 8, 1024) | ||
| encode_dh_domain_parameters(params) | ||
@@ -127,0 +389,0 @@ |
+25
-22
@@ -7,16 +7,14 @@ """ | ||
| from pkcs11 import Mechanism, KeyType, Attribute | ||
| from pkcs11 import Attribute, KeyType, Mechanism | ||
| from . import TestCase, Not, requires | ||
| from . import Not, TestCase, requires | ||
| class DigestTests(TestCase): | ||
| @requires(Mechanism.SHA256) | ||
| def test_digest(self): | ||
| data = 'THIS IS SOME DATA TO DIGEST' | ||
| data = "THIS IS SOME DATA TO DIGEST" | ||
| digest = self.session.digest(data, mechanism=Mechanism.SHA256) | ||
| self.assertEqual(digest, | ||
| hashlib.sha256(data.encode('utf-8')).digest()) | ||
| self.assertEqual(digest, hashlib.sha256(data.encode("utf-8")).digest()) | ||
@@ -26,5 +24,5 @@ @requires(Mechanism.SHA256) | ||
| data = ( | ||
| b'This is ', | ||
| b'some data ', | ||
| b'to digest.', | ||
| b"This is ", | ||
| b"some data ", | ||
| b"to digest.", | ||
| ) | ||
@@ -43,12 +41,14 @@ | ||
| def test_digest_key(self): | ||
| key = self.session.generate_key(KeyType.AES, 128, | ||
| template={ | ||
| Attribute.SENSITIVE: False, | ||
| Attribute.EXTRACTABLE: True, | ||
| }) | ||
| key = self.session.generate_key( | ||
| KeyType.AES, | ||
| 128, | ||
| template={ | ||
| Attribute.SENSITIVE: False, | ||
| Attribute.EXTRACTABLE: True, | ||
| }, | ||
| ) | ||
| digest = self.session.digest(key, mechanism=Mechanism.SHA256) | ||
| self.assertEqual(digest, | ||
| hashlib.sha256(key[Attribute.VALUE]).digest()) | ||
| self.assertEqual(digest, hashlib.sha256(key[Attribute.VALUE]).digest()) | ||
@@ -58,10 +58,13 @@ @requires(Mechanism.AES_KEY_GEN, Mechanism.SHA256) | ||
| def test_digest_key_data(self): | ||
| key = self.session.generate_key(KeyType.AES, 128, | ||
| template={ | ||
| Attribute.SENSITIVE: False, | ||
| Attribute.EXTRACTABLE: True, | ||
| }) | ||
| key = self.session.generate_key( | ||
| KeyType.AES, | ||
| 128, | ||
| template={ | ||
| Attribute.SENSITIVE: False, | ||
| Attribute.EXTRACTABLE: True, | ||
| }, | ||
| ) | ||
| data = ( | ||
| b'Some data', | ||
| b"Some data", | ||
| key, | ||
@@ -68,0 +71,0 @@ ) |
+14
-13
@@ -8,11 +8,10 @@ """ | ||
| import pkcs11 | ||
| from pkcs11 import KeyType, Attribute, Mechanism | ||
| from pkcs11 import Attribute, KeyType, Mechanism | ||
| from pkcs11.util.dsa import ( | ||
| decode_dsa_domain_parameters, | ||
| encode_dsa_domain_parameters, | ||
| decode_dsa_domain_parameters, | ||
| ) | ||
| from . import TestCase, requires, FIXME | ||
| from . import FIXME, TestCase, requires | ||
| DHPARAMS = base64.b64decode(""" | ||
@@ -29,3 +28,2 @@ MIIBHwKBgQD8jXSat2sk+j0plaMn51AVYBWEyWee3ui3llRUckVceDILsjVdBs1tXCDhU7WC+VZZ | ||
| class DSATests(TestCase): | ||
| @requires(Mechanism.DSA_PARAMETER_GEN) | ||
@@ -43,5 +41,4 @@ @FIXME.nfast # returns Function Failed | ||
| dhparams = self.session.create_domain_parameters( | ||
| KeyType.DSA, | ||
| decode_dsa_domain_parameters(DHPARAMS), | ||
| local=True) | ||
| KeyType.DSA, decode_dsa_domain_parameters(DHPARAMS), local=True | ||
| ) | ||
@@ -51,8 +48,11 @@ public, private = dhparams.generate_keypair() | ||
| self.assertIsInstance(private, pkcs11.PrivateKey) | ||
| self.assertEqual(len(public[Attribute.VALUE]), 1024 // 8) | ||
| # We expect a length of 128 (1024/8) in the vast majority of cases, | ||
| # but since the length of an integer value in DER is not fixed, there's | ||
| # a chance that we end up with a slightly shorter key length. | ||
| # The probability that the length falls short of 120 is vanishingly low, though. | ||
| self.assertGreater(len(public[Attribute.VALUE]), 120) | ||
| data = 'Message to sign' | ||
| data = "Message to sign" | ||
| signature = private.sign(data, mechanism=Mechanism.DSA_SHA1) | ||
| self.assertTrue(public.verify(data, signature, | ||
| mechanism=Mechanism.DSA_SHA1)) | ||
| self.assertTrue(public.verify(data, signature, mechanism=Mechanism.DSA_SHA1)) | ||
@@ -63,2 +63,3 @@ @requires(Mechanism.DSA_PARAMETER_GEN, Mechanism.DSA_KEY_PAIR_GEN) | ||
| public, private = self.session.generate_keypair(KeyType.DSA, 1024) | ||
| self.assertEqual(len(public[Attribute.VALUE]), 1024 // 8) | ||
| # See above. | ||
| self.assertGreater(len(public[Attribute.VALUE]), 120) |
+61
-30
@@ -7,10 +7,12 @@ """ | ||
| from asn1crypto.keys import PrivateKeyAlgorithmId | ||
| import pkcs11 | ||
| from pkcs11 import Attribute, KeyType, KDF, Mechanism | ||
| from pkcs11 import KDF, Attribute, KeyType, Mechanism | ||
| from pkcs11.util.ec import ( | ||
| encode_named_curve_parameters, | ||
| decode_ec_private_key, | ||
| decode_ec_public_key, | ||
| decode_ec_private_key, | ||
| decode_ecdsa_signature, | ||
| encode_ec_public_key, | ||
| decode_ecdsa_signature, | ||
| encode_named_curve_parameters, | ||
| ) | ||
@@ -24,5 +26,7 @@ | ||
| def test_sign_ecdsa(self): | ||
| parameters = self.session.create_domain_parameters(KeyType.EC, { | ||
| Attribute.EC_PARAMS: encode_named_curve_parameters('secp256r1') | ||
| }, local=True) | ||
| parameters = self.session.create_domain_parameters( | ||
| KeyType.EC, | ||
| {Attribute.EC_PARAMS: encode_named_curve_parameters("secp256r1")}, | ||
| local=True, | ||
| ) | ||
@@ -32,3 +36,3 @@ pub, priv = parameters.generate_keypair() | ||
| mechanism = Mechanism.ECDSA | ||
| data = b'HI BOB!' | ||
| data = b"HI BOB!" | ||
| ecdsa = priv.sign(data, mechanism=mechanism) | ||
@@ -41,7 +45,11 @@ self.assertTrue(pub.verify(data, ecdsa, mechanism=mechanism)) | ||
| # openssl ecparam -out ec_param.der -name prime192v1 | ||
| ecparams = base64.b64decode(b'BggqhkjOPQMBAQ==') | ||
| ecparams = base64.b64decode(b"BggqhkjOPQMBAQ==") | ||
| parameters = self.session.create_domain_parameters(KeyType.EC, { | ||
| Attribute.EC_PARAMS: ecparams, | ||
| }, local=True) | ||
| parameters = self.session.create_domain_parameters( | ||
| KeyType.EC, | ||
| { | ||
| Attribute.EC_PARAMS: ecparams, | ||
| }, | ||
| local=True, | ||
| ) | ||
| alice_pub, alice_priv = parameters.generate_keypair() | ||
@@ -56,13 +64,13 @@ alice_value = alice_pub[Attribute.EC_POINT] | ||
| alice_session = alice_priv.derive_key( | ||
| KeyType.AES, 128, | ||
| mechanism_param=(KDF.NULL, None, bob_value)) | ||
| KeyType.AES, 128, mechanism_param=(KDF.NULL, None, bob_value) | ||
| ) | ||
| bob_session = bob_priv.derive_key( | ||
| KeyType.AES, 128, | ||
| mechanism_param=(KDF.NULL, None, alice_value)) | ||
| KeyType.AES, 128, mechanism_param=(KDF.NULL, None, alice_value) | ||
| ) | ||
| iv = self.session.generate_random(128) | ||
| crypttext = alice_session.encrypt('HI BOB!', mechanism_param=iv) | ||
| crypttext = alice_session.encrypt("HI BOB!", mechanism_param=iv) | ||
| plaintext = bob_session.decrypt(crypttext, mechanism_param=iv) | ||
| self.assertEqual(plaintext, b'HI BOB!') | ||
| self.assertEqual(plaintext, b"HI BOB!") | ||
@@ -108,4 +116,3 @@ @requires(Mechanism.ECDSA) | ||
| self.assertTrue(key.verify(b'Data to sign', signature, | ||
| mechanism=Mechanism.ECDSA_SHA1)) | ||
| self.assertTrue(key.verify(b"Data to sign", signature, mechanism=Mechanism.ECDSA_SHA1)) | ||
@@ -152,13 +159,16 @@ # We should get back to identity | ||
| signature = priv.sign(b'Example', mechanism=Mechanism.ECDSA) | ||
| self.assertTrue(pub.verify(b'Example', signature, | ||
| mechanism=Mechanism.ECDSA)) | ||
| signature = priv.sign(b"Example", mechanism=Mechanism.ECDSA) | ||
| self.assertTrue(pub.verify(b"Example", signature, mechanism=Mechanism.ECDSA)) | ||
| @requires(Mechanism.EC_EDWARDS_KEY_PAIR_GEN, Mechanism.EDDSA) | ||
| def test_sign_eddsa(self): | ||
| parameters = self.session.create_domain_parameters(KeyType.EC, { | ||
| # use "Ed25519" once https://github.com/wbond/asn1crypto/pull/134 | ||
| # is merged | ||
| Attribute.EC_PARAMS: encode_named_curve_parameters('1.3.101.112') | ||
| }, local=True) | ||
| def test_sign_ed25519(self): | ||
| parameters = self.session.create_domain_parameters( | ||
| KeyType.EC_EDWARDS, | ||
| { | ||
| Attribute.EC_PARAMS: encode_named_curve_parameters( | ||
| PrivateKeyAlgorithmId.unmap("ed25519") | ||
| ) | ||
| }, | ||
| local=True, | ||
| ) | ||
@@ -168,4 +178,25 @@ pub, priv = parameters.generate_keypair() | ||
| mechanism = Mechanism.EDDSA | ||
| data = b'HI BOB!' | ||
| data = b"HI BOB!" | ||
| eddsa = priv.sign(data, mechanism=mechanism) | ||
| self.assertTrue(pub.verify(data, eddsa, mechanism=mechanism)) | ||
| @requires(Mechanism.EC_EDWARDS_KEY_PAIR_GEN, Mechanism.EDDSA) | ||
| def test_sign_ed448(self): | ||
| parameters = self.session.create_domain_parameters( | ||
| KeyType.EC_EDWARDS, | ||
| { | ||
| Attribute.EC_PARAMS: encode_named_curve_parameters( | ||
| PrivateKeyAlgorithmId.unmap("ed448") | ||
| ) | ||
| }, | ||
| local=True, | ||
| ) | ||
| pub, priv = parameters.generate_keypair() | ||
| mechanism = Mechanism.EDDSA | ||
| data = b"HI BOB!" | ||
| # As per the spec, mechanism parameters are required for Ed448: phFlag is False and | ||
| # the contextData is null for a regular Ed448 signature. | ||
| eddsa = priv.sign(data, mechanism=mechanism, mechanism_param=(False, None)) | ||
| self.assertTrue(pub.verify(data, eddsa, mechanism=mechanism, mechanism_param=(False, None))) |
@@ -13,12 +13,10 @@ """ | ||
| class IteratorTests(TestCase): | ||
| @requires(pkcs11.Mechanism.AES_KEY_GEN, pkcs11.Mechanism.AES_CBC_PAD) | ||
| def test_partial_decrypt(self): | ||
| self.session.generate_key(pkcs11.KeyType.AES, 128, | ||
| label='LOOK ME UP') | ||
| self.session.generate_key(pkcs11.KeyType.AES, 128, label="LOOK ME UP") | ||
| key = self.session.get_key(label='LOOK ME UP') | ||
| key = self.session.get_key(label="LOOK ME UP") | ||
| data = ( | ||
| b'1234', | ||
| b'1234', | ||
| b"1234", | ||
| b"1234", | ||
| ) | ||
@@ -41,9 +39,8 @@ | ||
| def test_close_iterators(self): | ||
| self.session.generate_key(pkcs11.KeyType.AES, 128, | ||
| label='LOOK ME UP') | ||
| self.session.generate_key(pkcs11.KeyType.AES, 128, label="LOOK ME UP") | ||
| key = self.session.get_key(label='LOOK ME UP') | ||
| key = self.session.get_key(label="LOOK ME UP") | ||
| data = ( | ||
| b'1234', | ||
| b'1234', | ||
| b"1234", | ||
| b"1234", | ||
| ) | ||
@@ -50,0 +47,0 @@ |
@@ -1,3 +0,16 @@ | ||
| from pkcs11 import KeyType, ObjectClass, Mechanism, Attribute, KDF | ||
| from pkcs11.util.rsa import encode_rsa_public_key | ||
| from cryptography.hazmat.primitives.asymmetric import ec | ||
| from cryptography.hazmat.primitives.asymmetric.ec import ECDSA | ||
| from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15 | ||
| from cryptography.hazmat.primitives.ciphers import Cipher | ||
| from cryptography.hazmat.primitives.ciphers.algorithms import AES | ||
| from cryptography.hazmat.primitives.ciphers.modes import CBC | ||
| from cryptography.hazmat.primitives.hashes import SHA256 | ||
| from cryptography.hazmat.primitives.padding import PKCS7 | ||
| from cryptography.hazmat.primitives.serialization import ( | ||
| Encoding, | ||
| PublicFormat, | ||
| load_der_public_key, | ||
| ) | ||
| from pkcs11 import KDF, Attribute, KeyType, Mechanism, ObjectClass | ||
| from pkcs11.util.ec import ( | ||
@@ -9,8 +22,8 @@ decode_ec_public_key, | ||
| ) | ||
| from pkcs11.util.rsa import encode_rsa_public_key | ||
| from . import TestCase, requires, Is | ||
| from . import Is, TestCase, requires | ||
| class ExternalPublicKeyTests(TestCase): | ||
| @requires(Mechanism.RSA_PKCS) | ||
@@ -21,66 +34,54 @@ def test_rsa(self): | ||
| pub = self.session.get_key(key_type=KeyType.RSA, | ||
| object_class=ObjectClass.PUBLIC_KEY) | ||
| pub = self.session.get_key(key_type=KeyType.RSA, object_class=ObjectClass.PUBLIC_KEY) | ||
| pub = encode_rsa_public_key(pub) | ||
| from oscrypto.asymmetric import load_public_key, rsa_pkcs1v15_encrypt | ||
| pub = load_der_public_key(pub) | ||
| crypttext = pub.encrypt(b"Data to encrypt", PKCS1v15()) | ||
| pub = load_public_key(pub) | ||
| crypttext = rsa_pkcs1v15_encrypt(pub, b'Data to encrypt') | ||
| priv = self.session.get_key(key_type=KeyType.RSA, object_class=ObjectClass.PRIVATE_KEY) | ||
| priv = self.session.get_key(key_type=KeyType.RSA, | ||
| object_class=ObjectClass.PRIVATE_KEY) | ||
| plaintext = priv.decrypt(crypttext, mechanism=Mechanism.RSA_PKCS) | ||
| self.assertEqual(plaintext, b'Data to encrypt') | ||
| self.assertEqual(plaintext, b"Data to encrypt") | ||
| @requires(Mechanism.ECDSA_SHA1) | ||
| @requires(Mechanism.ECDSA_SHA256) | ||
| def test_ecdsa(self): | ||
| # A key we generated earlier | ||
| self.session.create_domain_parameters(KeyType.EC, { | ||
| Attribute.EC_PARAMS: encode_named_curve_parameters('secp256r1'), | ||
| }, local=True)\ | ||
| .generate_keypair() | ||
| self.session.create_domain_parameters( | ||
| KeyType.EC, | ||
| { | ||
| Attribute.EC_PARAMS: encode_named_curve_parameters("secp256r1"), | ||
| }, | ||
| local=True, | ||
| ).generate_keypair() | ||
| priv = self.session.get_key(key_type=KeyType.EC, | ||
| object_class=ObjectClass.PRIVATE_KEY) | ||
| priv = self.session.get_key(key_type=KeyType.EC, object_class=ObjectClass.PRIVATE_KEY) | ||
| signature = priv.sign(b'Data to sign', mechanism=Mechanism.ECDSA_SHA1) | ||
| # Encode as ASN.1 for OpenSSL | ||
| signature = priv.sign(b"Data to sign", mechanism=Mechanism.ECDSA_SHA256) | ||
| signature = encode_ecdsa_signature(signature) | ||
| from oscrypto.asymmetric import load_public_key, ecdsa_verify | ||
| pub = self.session.get_key(key_type=KeyType.EC, object_class=ObjectClass.PUBLIC_KEY) | ||
| pub = load_der_public_key(encode_ec_public_key(pub)) | ||
| pub.verify(signature, b"Data to sign", ECDSA(SHA256())) | ||
| pub = self.session.get_key(key_type=KeyType.EC, | ||
| object_class=ObjectClass.PUBLIC_KEY) | ||
| pub = load_public_key(encode_ec_public_key(pub)) | ||
| ecdsa_verify(pub, signature, b'Data to sign', 'sha1') | ||
| @requires(Mechanism.ECDH1_DERIVE) | ||
| def test_ecdh(self): | ||
| # A key we generated earlier | ||
| self.session.create_domain_parameters(KeyType.EC, { | ||
| Attribute.EC_PARAMS: encode_named_curve_parameters('secp256r1'), | ||
| }, local=True)\ | ||
| .generate_keypair() | ||
| self.session.create_domain_parameters( | ||
| KeyType.EC, | ||
| { | ||
| Attribute.EC_PARAMS: encode_named_curve_parameters("secp256r1"), | ||
| }, | ||
| local=True, | ||
| ).generate_keypair() | ||
| # Retrieve our keypair, with our public key encoded for interchange | ||
| alice_priv = self.session.get_key(key_type=KeyType.EC, | ||
| object_class=ObjectClass.PRIVATE_KEY) | ||
| alice_pub = self.session.get_key(key_type=KeyType.EC, | ||
| object_class=ObjectClass.PUBLIC_KEY) | ||
| alice_priv = self.session.get_key(key_type=KeyType.EC, object_class=ObjectClass.PRIVATE_KEY) | ||
| alice_pub = self.session.get_key(key_type=KeyType.EC, object_class=ObjectClass.PUBLIC_KEY) | ||
| alice_pub = encode_ec_public_key(alice_pub) | ||
| from cryptography.hazmat.backends import default_backend | ||
| from cryptography.hazmat.primitives.asymmetric import ec | ||
| from cryptography.hazmat.primitives.serialization import \ | ||
| Encoding, PublicFormat, load_der_public_key | ||
| # Bob generates a keypair, with their public key encoded for | ||
| # interchange | ||
| bob_priv = ec.generate_private_key(ec.SECP256R1, | ||
| default_backend()) | ||
| bob_priv = ec.generate_private_key(ec.SECP256R1()) | ||
| bob_pub = bob_priv.public_key().public_bytes( | ||
@@ -95,13 +96,14 @@ Encoding.DER, | ||
| ec.ECDH(), | ||
| load_der_public_key(alice_pub, default_backend()), | ||
| load_der_public_key(alice_pub), | ||
| ) | ||
| key = alice_priv.derive_key( | ||
| KeyType.GENERIC_SECRET, 256, | ||
| KeyType.GENERIC_SECRET, | ||
| 256, | ||
| mechanism_param=( | ||
| KDF.NULL, None, | ||
| KDF.NULL, | ||
| None, | ||
| # N.B. it seems like SoftHSMv2 requires an EC_POINT to be | ||
| # DER-encoded, which is not what the spec says | ||
| decode_ec_public_key(bob_pub, encode_ec_point=Is.softhsm2) | ||
| [Attribute.EC_POINT], | ||
| decode_ec_public_key(bob_pub, encode_ec_point=Is.softhsm2)[Attribute.EC_POINT], | ||
| ), | ||
@@ -122,7 +124,2 @@ template={ | ||
| import io | ||
| from oscrypto.asymmetric import load_public_key, rsa_pkcs1v15_encrypt | ||
| from oscrypto.symmetric import ( | ||
| aes_cbc_pkcs7_encrypt, | ||
| aes_cbc_pkcs7_decrypt, | ||
| ) | ||
@@ -132,5 +129,4 @@ # A key we generated earlier | ||
| pub = self.session.get_key(key_type=KeyType.RSA, | ||
| object_class=ObjectClass.PUBLIC_KEY) | ||
| pub = load_public_key(encode_rsa_public_key(pub)) | ||
| pub = self.session.get_key(key_type=KeyType.RSA, object_class=ObjectClass.PUBLIC_KEY) | ||
| pub = load_der_public_key(encode_rsa_public_key(pub)) | ||
@@ -140,3 +136,3 @@ key = self.session.generate_random(256) | ||
| source = b'This is my amazing file' | ||
| source = b"This is my amazing file" | ||
@@ -150,5 +146,9 @@ with io.BytesIO() as dest: | ||
| # frame with nonsense | ||
| self.assertEqual(dest.write(rsa_pkcs1v15_encrypt(pub, key + iv)), | ||
| 128) | ||
| _, ciphertext = aes_cbc_pkcs7_encrypt(key, source, iv) | ||
| self.assertEqual(dest.write(pub.encrypt(key + iv, PKCS1v15())), 128) | ||
| cipher = Cipher(AES(key), CBC(iv)) | ||
| encryptor = cipher.encryptor() | ||
| padder = PKCS7(128).padder() | ||
| padded_data = padder.update(source) + padder.finalize() | ||
| ciphertext = encryptor.update(padded_data) + encryptor.finalize() | ||
| dest.write(ciphertext) | ||
@@ -160,4 +160,3 @@ | ||
| # Look up our private key | ||
| priv = self.session.get_key(key_type=KeyType.RSA, | ||
| object_class=ObjectClass.PRIVATE_KEY) | ||
| priv = self.session.get_key(key_type=KeyType.RSA, object_class=ObjectClass.PRIVATE_KEY) | ||
| # Read the header | ||
@@ -173,4 +172,8 @@ header = dest.read(priv.key_length // 8) | ||
| plaintext = aes_cbc_pkcs7_decrypt(key, dest.read(), iv) | ||
| cipher = Cipher(AES(key), CBC(iv)) | ||
| decryptor = cipher.decryptor() | ||
| unpadder = PKCS7(128).unpadder() | ||
| padded_plaintext = decryptor.update(dest.read()) + decryptor.finalize() | ||
| plaintext = unpadder.update(padded_plaintext) + unpadder.finalize() | ||
| self.assertEqual(source, plaintext) |
+49
-49
@@ -6,9 +6,8 @@ """ | ||
| import pkcs11 | ||
| from pkcs11 import Attribute, KeyType, ObjectClass, Mechanism, MGF | ||
| from pkcs11 import MGF, Attribute, KeyType, Mechanism, ObjectClass | ||
| from . import TestCase, requires, FIXME | ||
| from . import FIXME, TestCase, requires | ||
| class RSATests(TestCase): | ||
| @requires(Mechanism.RSA_PKCS_KEY_PAIR_GEN) | ||
@@ -18,8 +17,7 @@ def setUp(self): | ||
| self.public, self.private = \ | ||
| self.session.generate_keypair(KeyType.RSA, 1024) | ||
| self.public, self.private = self.session.generate_keypair(KeyType.RSA, 1024) | ||
| @requires(Mechanism.RSA_PKCS) | ||
| def test_sign_pkcs_v15(self): | ||
| data = b'00000000' | ||
| data = b"00000000" | ||
@@ -29,10 +27,8 @@ signature = self.private.sign(data, mechanism=Mechanism.RSA_PKCS) | ||
| self.assertIsInstance(signature, bytes) | ||
| self.assertTrue(self.public.verify(data, signature, | ||
| mechanism=Mechanism.RSA_PKCS)) | ||
| self.assertFalse(self.public.verify(data, b'1234', | ||
| mechanism=Mechanism.RSA_PKCS)) | ||
| self.assertTrue(self.public.verify(data, signature, mechanism=Mechanism.RSA_PKCS)) | ||
| self.assertFalse(self.public.verify(data, b"1234", mechanism=Mechanism.RSA_PKCS)) | ||
| @requires(Mechanism.SHA512_RSA_PKCS) | ||
| def test_sign_default(self): | ||
| data = b'HELLO WORLD' * 1024 | ||
| data = b"HELLO WORLD" * 1024 | ||
@@ -43,3 +39,3 @@ signature = self.private.sign(data) | ||
| self.assertTrue(self.public.verify(data, signature)) | ||
| self.assertFalse(self.public.verify(data, b'1234')) | ||
| self.assertFalse(self.public.verify(data, b"1234")) | ||
@@ -49,7 +45,7 @@ @requires(Mechanism.SHA512_RSA_PKCS) | ||
| data = ( | ||
| b'I' * 16, | ||
| b'N' * 16, | ||
| b'P' * 16, | ||
| b'U' * 16, | ||
| b'T' * 10, # don't align to the blocksize | ||
| b"I" * 16, | ||
| b"N" * 16, | ||
| b"P" * 16, | ||
| b"U" * 16, | ||
| b"T" * 10, # don't align to the blocksize | ||
| ) | ||
@@ -65,7 +61,10 @@ | ||
| def test_key_wrap(self): | ||
| key = self.session.generate_key(KeyType.AES, 128, | ||
| template={ | ||
| Attribute.EXTRACTABLE: True, | ||
| Attribute.SENSITIVE: False, | ||
| }) | ||
| key = self.session.generate_key( | ||
| KeyType.AES, | ||
| 128, | ||
| template={ | ||
| Attribute.EXTRACTABLE: True, | ||
| Attribute.SENSITIVE: False, | ||
| }, | ||
| ) | ||
@@ -75,9 +74,11 @@ data = self.public.wrap_key(key) | ||
| key2 = self.private.unwrap_key(ObjectClass.SECRET_KEY, | ||
| KeyType.AES, | ||
| data, | ||
| template={ | ||
| Attribute.EXTRACTABLE: True, | ||
| Attribute.SENSITIVE: False, | ||
| }) | ||
| key2 = self.private.unwrap_key( | ||
| ObjectClass.SECRET_KEY, | ||
| KeyType.AES, | ||
| data, | ||
| template={ | ||
| Attribute.EXTRACTABLE: True, | ||
| Attribute.SENSITIVE: False, | ||
| }, | ||
| ) | ||
@@ -88,17 +89,17 @@ self.assertEqual(key[Attribute.VALUE], key2[Attribute.VALUE]) | ||
| def test_encrypt_oaep(self): | ||
| data = b'SOME DATA' | ||
| data = b"SOME DATA" | ||
| crypttext = self.public.encrypt(data, | ||
| mechanism=Mechanism.RSA_PKCS_OAEP, | ||
| mechanism_param=(Mechanism.SHA_1, | ||
| MGF.SHA1, | ||
| None)) | ||
| crypttext = self.public.encrypt( | ||
| data, | ||
| mechanism=Mechanism.RSA_PKCS_OAEP, | ||
| mechanism_param=(Mechanism.SHA_1, MGF.SHA1, None), | ||
| ) | ||
| self.assertNotEqual(data, crypttext) | ||
| plaintext = self.private.decrypt(crypttext, | ||
| mechanism=Mechanism.RSA_PKCS_OAEP, | ||
| mechanism_param=(Mechanism.SHA_1, | ||
| MGF.SHA1, | ||
| None)) | ||
| plaintext = self.private.decrypt( | ||
| crypttext, | ||
| mechanism=Mechanism.RSA_PKCS_OAEP, | ||
| mechanism_param=(Mechanism.SHA_1, MGF.SHA1, None), | ||
| ) | ||
@@ -109,17 +110,16 @@ self.assertEqual(data, plaintext) | ||
| def test_sign_pss(self): | ||
| data = b'SOME DATA' | ||
| data = b"SOME DATA" | ||
| # These are the default params | ||
| signature = self.private.sign(data, | ||
| mechanism=Mechanism.SHA1_RSA_PKCS_PSS, | ||
| mechanism_param=(Mechanism.SHA_1, | ||
| MGF.SHA1, | ||
| 20)) | ||
| signature = self.private.sign( | ||
| data, | ||
| mechanism=Mechanism.SHA1_RSA_PKCS_PSS, | ||
| mechanism_param=(Mechanism.SHA_1, MGF.SHA1, 20), | ||
| ) | ||
| self.assertTrue(self.public.verify( | ||
| data, signature, mechanism=Mechanism.SHA1_RSA_PKCS_PSS)) | ||
| self.assertTrue(self.public.verify(data, signature, mechanism=Mechanism.SHA1_RSA_PKCS_PSS)) | ||
| @requires(Mechanism.RSA_PKCS_OAEP) | ||
| def test_encrypt_too_much_data(self): | ||
| data = b'1234' * 128 | ||
| data = b"1234" * 128 | ||
@@ -126,0 +126,0 @@ # You can't encrypt lots of data with RSA |
+42
-43
@@ -7,7 +7,6 @@ """ | ||
| from . import TestCase, TOKEN_PIN, TOKEN_SO_PIN, Not, Only, requires, FIXME | ||
| from . import FIXME, TOKEN_PIN, TOKEN_SO_PIN, Not, Only, TestCase, requires | ||
| class SessionTests(TestCase): | ||
| with_session = False | ||
@@ -41,8 +40,7 @@ | ||
| # Test GetAttribute | ||
| self.assertIs(key[pkcs11.Attribute.CLASS], | ||
| pkcs11.ObjectClass.SECRET_KEY) | ||
| self.assertIs(key[pkcs11.Attribute.CLASS], pkcs11.ObjectClass.SECRET_KEY) | ||
| self.assertEqual(key[pkcs11.Attribute.TOKEN], False) | ||
| self.assertEqual(key[pkcs11.Attribute.LOCAL], True) | ||
| self.assertEqual(key[pkcs11.Attribute.MODIFIABLE], True) | ||
| self.assertEqual(key[pkcs11.Attribute.LABEL], '') | ||
| self.assertEqual(key[pkcs11.Attribute.LABEL], "") | ||
@@ -55,6 +53,5 @@ # Test SetAttribute | ||
| # Create another key with no capabilities | ||
| key = session.generate_key(pkcs11.KeyType.AES, 128, | ||
| label='MY KEY', | ||
| id=b'\1\2\3\4', | ||
| capabilities=0) | ||
| key = session.generate_key( | ||
| pkcs11.KeyType.AES, 128, label="MY KEY", id=b"\1\2\3\4", capabilities=0 | ||
| ) | ||
| self.assertIsInstance(key, pkcs11.Object) | ||
@@ -64,14 +61,12 @@ self.assertIsInstance(key, pkcs11.SecretKey) | ||
| self.assertEqual(key.label, 'MY KEY') | ||
| self.assertEqual(key.label, "MY KEY") | ||
| @requires(pkcs11.Mechanism.RSA_PKCS_KEY_PAIR_GEN, | ||
| pkcs11.Mechanism.RSA_PKCS) | ||
| @requires(pkcs11.Mechanism.RSA_PKCS_KEY_PAIR_GEN, pkcs11.Mechanism.RSA_PKCS) | ||
| def test_generate_keypair(self): | ||
| with self.token.open(user_pin=TOKEN_PIN) as session: | ||
| pub, priv = session.generate_keypair( | ||
| pkcs11.KeyType.RSA, 1024) | ||
| pub, priv = session.generate_keypair(pkcs11.KeyType.RSA, 1024) | ||
| self.assertIsInstance(pub, pkcs11.PublicKey) | ||
| self.assertIsInstance(priv, pkcs11.PrivateKey) | ||
| data = b'HELLO WORLD' | ||
| data = b"HELLO WORLD" | ||
| crypttext = pub.encrypt(data, mechanism=pkcs11.Mechanism.RSA_PKCS) | ||
@@ -85,8 +80,11 @@ self.assertNotEqual(data, crypttext) | ||
| with self.token.open(user_pin=TOKEN_PIN) as session: | ||
| key = session.generate_key(pkcs11.KeyType.AES, 128, | ||
| label='SAMPLE KEY') | ||
| key = session.generate_key(pkcs11.KeyType.AES, 128, label="SAMPLE KEY") | ||
| search = list(session.get_objects({ | ||
| pkcs11.Attribute.LABEL: 'SAMPLE KEY', | ||
| })) | ||
| search = list( | ||
| session.get_objects( | ||
| { | ||
| pkcs11.Attribute.LABEL: "SAMPLE KEY", | ||
| } | ||
| ) | ||
| ) | ||
@@ -99,7 +97,9 @@ self.assertEqual(len(search), 1) | ||
| with self.token.open(user_pin=TOKEN_PIN) as session: | ||
| key = session.create_object({ | ||
| pkcs11.Attribute.CLASS: pkcs11.ObjectClass.SECRET_KEY, | ||
| pkcs11.Attribute.KEY_TYPE: pkcs11.KeyType.AES, | ||
| pkcs11.Attribute.VALUE: b'1' * 16, | ||
| }) | ||
| key = session.create_object( | ||
| { | ||
| pkcs11.Attribute.CLASS: pkcs11.ObjectClass.SECRET_KEY, | ||
| pkcs11.Attribute.KEY_TYPE: pkcs11.KeyType.AES, | ||
| pkcs11.Attribute.VALUE: b"1" * 16, | ||
| } | ||
| ) | ||
@@ -112,4 +112,3 @@ self.assertIsInstance(key, pkcs11.SecretKey) | ||
| with self.token.open(user_pin=TOKEN_PIN) as session: | ||
| key = session.generate_key(pkcs11.KeyType.AES, 128, | ||
| label='SAMPLE KEY') | ||
| key = session.generate_key(pkcs11.KeyType.AES, 128, label="SAMPLE KEY") | ||
| key.destroy() | ||
@@ -122,7 +121,8 @@ | ||
| with self.token.open(user_pin=TOKEN_PIN) as session: | ||
| key = session.generate_key(pkcs11.KeyType.AES, 128, | ||
| label='SAMPLE KEY') | ||
| new = key.copy({ | ||
| pkcs11.Attribute.LABEL: 'SOMETHING ELSE', | ||
| }) | ||
| key = session.generate_key(pkcs11.KeyType.AES, 128, label="SAMPLE KEY") | ||
| new = key.copy( | ||
| { | ||
| pkcs11.Attribute.LABEL: "SOMETHING ELSE", | ||
| } | ||
| ) | ||
@@ -134,8 +134,9 @@ self.assertEqual(set(session.get_objects()), {key, new}) | ||
| with self.token.open(user_pin=TOKEN_PIN) as session: | ||
| session.generate_key(pkcs11.KeyType.AES, 128, | ||
| label='SAMPLE KEY') | ||
| session.generate_key(pkcs11.KeyType.AES, 128, label="SAMPLE KEY") | ||
| key = session.get_key(label='SAMPLE KEY',) | ||
| key = session.get_key( | ||
| label="SAMPLE KEY", | ||
| ) | ||
| self.assertIsInstance(key, pkcs11.SecretKey) | ||
| key.encrypt(b'test', mechanism_param=b'IV' * 8) | ||
| key.encrypt(b"test", mechanism_param=b"IV" * 8) | ||
@@ -145,3 +146,3 @@ def test_get_key_not_found(self): | ||
| with self.assertRaises(pkcs11.NoSuchKey): | ||
| session.get_key(label='SAMPLE KEY') | ||
| session.get_key(label="SAMPLE KEY") | ||
@@ -151,6 +152,4 @@ @requires(pkcs11.Mechanism.AES_KEY_GEN) | ||
| with self.token.open(user_pin=TOKEN_PIN) as session: | ||
| session.generate_key(pkcs11.KeyType.AES, 128, | ||
| label='SAMPLE KEY') | ||
| session.generate_key(pkcs11.KeyType.AES, 128, | ||
| label='SAMPLE KEY 2') | ||
| session.generate_key(pkcs11.KeyType.AES, 128, label="SAMPLE KEY") | ||
| session.generate_key(pkcs11.KeyType.AES, 128, label="SAMPLE KEY 2") | ||
@@ -164,3 +163,3 @@ with self.assertRaises(pkcs11.MultipleObjectsReturned): | ||
| with self.token.open() as session: | ||
| session.seed_random(b'12345678') | ||
| session.seed_random(b"12345678") | ||
@@ -172,2 +171,2 @@ def test_generate_random(self): | ||
| # Ensure we didn't get 16 bytes of zeros | ||
| self.assertTrue(all(c != '\0' for c in random)) | ||
| self.assertTrue(all(c != "\0" for c in random)) |
@@ -9,7 +9,6 @@ """ | ||
| from . import LIB, TOKEN, Only, Not | ||
| from . import LIB, TOKEN, Not, Only | ||
| class SlotsAndTokensTests(unittest.TestCase): | ||
| def test_double_initialise(self): | ||
@@ -22,3 +21,3 @@ self.assertIsNotNone(pkcs11.lib(LIB)) | ||
| with self.assertRaises(pkcs11.AlreadyInitialized): | ||
| pkcs11.lib('somethingelse.so') | ||
| pkcs11.lib("somethingelse.so") | ||
@@ -25,0 +24,0 @@ @Only.softhsm2 |
@@ -12,3 +12,3 @@ """ | ||
| from . import TestCase, Not, requires | ||
| from . import Not, TestCase, requires | ||
@@ -18,7 +18,6 @@ | ||
| class ThreadingTests(TestCase): | ||
| @requires(pkcs11.Mechanism.AES_KEY_GEN, pkcs11.Mechanism.AES_CBC_PAD) | ||
| def test_concurrency(self): | ||
| # Multiplexing a session between processes | ||
| self.session.generate_key(pkcs11.KeyType.AES, 128, label='LOOK ME UP') | ||
| self.session.generate_key(pkcs11.KeyType.AES, 128, label="LOOK ME UP") | ||
@@ -29,5 +28,5 @@ test_passed = [True] | ||
| try: | ||
| data = b'1234' * 1024 * 1024 # Multichunk files | ||
| data = b"1234" * 1024 * 1024 # Multichunk files | ||
| iv = self.session.generate_random(128) | ||
| key = self.session.get_key(label='LOOK ME UP') | ||
| key = self.session.get_key(label="LOOK ME UP") | ||
| self.assertIsNotNone(key.encrypt(data, mechanism_param=iv)) | ||
@@ -38,6 +37,3 @@ except pkcs11.PKCS11Error: | ||
| threads = [ | ||
| threading.Thread(target=thread_work) | ||
| for _ in range(10) | ||
| ] | ||
| threads = [threading.Thread(target=thread_work) for _ in range(10)] | ||
@@ -44,0 +40,0 @@ for thread in threads: |
+128
-115
@@ -6,15 +6,13 @@ """ | ||
| import base64 | ||
| import subprocess | ||
| import datetime | ||
| from asn1crypto import pem | ||
| from asn1crypto.x509 import Certificate, TbsCertificate, Time, Name | ||
| from asn1crypto.csr import CertificationRequest, CertificationRequestInfo | ||
| from asn1crypto.keys import RSAPublicKey | ||
| from asn1crypto.csr import CertificationRequest, CertificationRequestInfo | ||
| from asn1crypto.x509 import Certificate, Name, TbsCertificate, Time | ||
| from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15 | ||
| from cryptography.hazmat.primitives.hashes import SHA256 | ||
| from cryptography.hazmat.primitives.serialization import load_der_public_key | ||
| import pkcs11 | ||
| from pkcs11.util.rsa import encode_rsa_public_key | ||
| from pkcs11.util.dsa import decode_dsa_signature | ||
| from pkcs11.util.ec import decode_ecdsa_signature | ||
| from pkcs11.util.x509 import decode_x509_certificate, decode_x509_public_key | ||
| from pkcs11 import ( | ||
@@ -25,6 +23,9 @@ Attribute, | ||
| ) | ||
| from pkcs11.util.dsa import decode_dsa_signature | ||
| from pkcs11.util.ec import decode_ecdsa_signature | ||
| from pkcs11.util.rsa import encode_rsa_public_key | ||
| from pkcs11.util.x509 import decode_x509_certificate, decode_x509_public_key | ||
| from . import TestCase, Not, Only, requires, OPENSSL | ||
| from . import Not, TestCase, requires | ||
| # X.509 self-signed certificate (generated with OpenSSL) | ||
@@ -56,3 +57,2 @@ # openssl req -x509 \ | ||
| class X509Tests(TestCase): | ||
| def test_import_ca_certificate_easy(self): | ||
@@ -65,13 +65,14 @@ cert = self.session.create_object(decode_x509_certificate(CERT)) | ||
| def test_import_ca_certificate(self): | ||
| cert = self.session.create_object( | ||
| decode_x509_certificate(CERT, extended_set=True)) | ||
| cert = self.session.create_object(decode_x509_certificate(CERT, extended_set=True)) | ||
| self.assertIsInstance(cert, pkcs11.Certificate) | ||
| self.assertEqual(cert[Attribute.HASH_OF_ISSUER_PUBLIC_KEY], | ||
| b'\xf9\xc1\xb6\xe3\x43\xf3\xcf\x4c\xba\x8a' | ||
| b'\x0b\x66\x86\x79\x35\xfb\x52\x85\xbf\xa8') | ||
| self.assertEqual( | ||
| cert[Attribute.HASH_OF_ISSUER_PUBLIC_KEY], | ||
| b"\xf9\xc1\xb6\xe3\x43\xf3\xcf\x4c\xba\x8a\x0b\x66\x86\x79\x35\xfb\x52\x85\xbf\xa8", | ||
| ) | ||
| # Cert is self signed | ||
| self.assertEqual(cert[Attribute.HASH_OF_SUBJECT_PUBLIC_KEY], | ||
| b'\xf9\xc1\xb6\xe3\x43\xf3\xcf\x4c\xba\x8a' | ||
| b'\x0b\x66\x86\x79\x35\xfb\x52\x85\xbf\xa8') | ||
| self.assertEqual( | ||
| cert[Attribute.HASH_OF_SUBJECT_PUBLIC_KEY], | ||
| b"\xf9\xc1\xb6\xe3\x43\xf3\xcf\x4c\xba\x8a\x0b\x66\x86\x79\x35\xfb\x52\x85\xbf\xa8", | ||
| ) | ||
@@ -85,10 +86,9 @@ @requires(Mechanism.SHA1_RSA_PKCS) | ||
| value = x509['tbs_certificate'].dump() | ||
| value = x509["tbs_certificate"].dump() | ||
| signature = x509.signature | ||
| assert x509.signature_algo == 'rsassa_pkcs1v15' | ||
| assert x509.hash_algo == 'sha1' | ||
| assert x509.signature_algo == "rsassa_pkcs1v15" | ||
| assert x509.hash_algo == "sha1" | ||
| self.assertTrue(key.verify(value, signature, | ||
| mechanism=Mechanism.SHA1_RSA_PKCS)) | ||
| self.assertTrue(key.verify(value, signature, mechanism=Mechanism.SHA1_RSA_PKCS)) | ||
@@ -124,11 +124,10 @@ @requires(Mechanism.DSA_SHA1) | ||
| value = x509['tbs_certificate'].dump() | ||
| value = x509["tbs_certificate"].dump() | ||
| assert x509.signature_algo == 'dsa' | ||
| assert x509.hash_algo == 'sha1' | ||
| assert x509.signature_algo == "dsa" | ||
| assert x509.hash_algo == "sha1" | ||
| signature = decode_dsa_signature(x509.signature) | ||
| self.assertTrue(key.verify(value, signature, | ||
| mechanism=Mechanism.DSA_SHA1)) | ||
| self.assertTrue(key.verify(value, signature, mechanism=Mechanism.DSA_SHA1)) | ||
@@ -162,72 +161,85 @@ @requires(Mechanism.ECDSA_SHA1) | ||
| value = x509['tbs_certificate'].dump() | ||
| value = x509["tbs_certificate"].dump() | ||
| assert x509.signature_algo == 'ecdsa' | ||
| assert x509.hash_algo == 'sha1' | ||
| assert x509.signature_algo == "ecdsa" | ||
| assert x509.hash_algo == "sha1" | ||
| signature = decode_ecdsa_signature(x509.signature) | ||
| self.assertTrue(key.verify(value, signature, | ||
| mechanism=Mechanism.ECDSA_SHA1)) | ||
| self.assertTrue(key.verify(value, signature, mechanism=Mechanism.ECDSA_SHA1)) | ||
| @Only.openssl | ||
| @requires(Mechanism.RSA_PKCS_KEY_PAIR_GEN, Mechanism.SHA1_RSA_PKCS) | ||
| @requires(Mechanism.RSA_PKCS_KEY_PAIR_GEN, Mechanism.SHA256_RSA_PKCS) | ||
| def test_self_sign_certificate(self): | ||
| # Warning: proof of concept code only! | ||
| pub, priv = self.session.generate_keypair(KeyType.RSA, 1024) | ||
| pub_asn1 = RSAPublicKey.load(encode_rsa_public_key(pub)) | ||
| tbs = TbsCertificate({ | ||
| 'version': 'v1', | ||
| 'serial_number': 1, | ||
| 'issuer': Name.build({ | ||
| 'common_name': 'Test Certificate', | ||
| }), | ||
| 'subject': Name.build({ | ||
| 'common_name': 'Test Certificate', | ||
| }), | ||
| 'signature': { | ||
| 'algorithm': 'sha1_rsa', | ||
| 'parameters': None, | ||
| }, | ||
| 'validity': { | ||
| 'not_before': Time({ | ||
| 'utc_time': datetime.datetime(2017, 1, 1, 0, 0), | ||
| }), | ||
| 'not_after': Time({ | ||
| 'utc_time': datetime.datetime(2038, 12, 31, 23, 59), | ||
| }), | ||
| }, | ||
| 'subject_public_key_info': { | ||
| 'algorithm': { | ||
| 'algorithm': 'rsa', | ||
| 'parameters': None, | ||
| tbs = TbsCertificate( | ||
| { | ||
| "version": "v1", | ||
| "serial_number": 1, | ||
| "issuer": Name.build( | ||
| { | ||
| "common_name": "Test Certificate", | ||
| } | ||
| ), | ||
| "subject": Name.build( | ||
| { | ||
| "common_name": "Test Certificate", | ||
| } | ||
| ), | ||
| "signature": { | ||
| "algorithm": "sha256_rsa", | ||
| "parameters": None, | ||
| }, | ||
| 'public_key': RSAPublicKey.load(encode_rsa_public_key(pub)), | ||
| "validity": { | ||
| "not_before": Time( | ||
| { | ||
| "utc_time": datetime.datetime( | ||
| 2017, 1, 1, 0, 0, tzinfo=datetime.timezone.utc | ||
| ), | ||
| } | ||
| ), | ||
| "not_after": Time( | ||
| { | ||
| "utc_time": datetime.datetime( | ||
| 2038, 12, 31, 23, 59, tzinfo=datetime.timezone.utc | ||
| ), | ||
| } | ||
| ), | ||
| }, | ||
| "subject_public_key_info": { | ||
| "algorithm": { | ||
| "algorithm": "rsa", | ||
| "parameters": None, | ||
| }, | ||
| "public_key": pub_asn1, | ||
| }, | ||
| } | ||
| }) | ||
| ) | ||
| # Sign the TBS Certificate | ||
| value = priv.sign(tbs.dump(), | ||
| mechanism=Mechanism.SHA1_RSA_PKCS) | ||
| value = priv.sign(tbs.dump(), mechanism=Mechanism.SHA256_RSA_PKCS) | ||
| cert = Certificate({ | ||
| 'tbs_certificate': tbs, | ||
| 'signature_algorithm': { | ||
| 'algorithm': 'sha1_rsa', | ||
| 'parameters': None, | ||
| }, | ||
| 'signature_value': value, | ||
| }) | ||
| cert = Certificate( | ||
| { | ||
| "tbs_certificate": tbs, | ||
| "signature_algorithm": { | ||
| "algorithm": "sha256_rsa", | ||
| "parameters": None, | ||
| }, | ||
| "signature_value": value, | ||
| } | ||
| ) | ||
| # Pipe our certificate to OpenSSL to verify it | ||
| with subprocess.Popen((OPENSSL, 'verify'), | ||
| stdin=subprocess.PIPE, | ||
| stdout=subprocess.DEVNULL) as proc: | ||
| der_cert = cert.dump() | ||
| proc.stdin.write(pem.armor('CERTIFICATE', cert.dump())) | ||
| proc.stdin.close() | ||
| self.assertEqual(proc.wait(), 0) | ||
| # read back the data and validate it | ||
| pub_key_handle = load_der_public_key(pub_asn1.dump()) | ||
| cert_loaded = Certificate.load(der_cert) | ||
| tbs_bytes = cert_loaded["tbs_certificate"].dump() | ||
| signature_bytes = cert_loaded["signature_value"].native | ||
| pub_key_handle.verify(signature_bytes, tbs_bytes, PKCS1v15(), SHA256()) | ||
| @Only.openssl | ||
| @requires(Mechanism.RSA_PKCS_KEY_PAIR_GEN, Mechanism.SHA1_RSA_PKCS) | ||
| @requires(Mechanism.RSA_PKCS_KEY_PAIR_GEN, Mechanism.SHA256_RSA_PKCS) | ||
| def test_sign_csr(self): | ||
@@ -237,40 +249,41 @@ # Warning: proof of concept code only! | ||
| info = CertificationRequestInfo({ | ||
| 'version': 0, | ||
| 'subject': Name.build({ | ||
| 'common_name': 'Test Certificate', | ||
| }), | ||
| 'subject_pk_info': { | ||
| 'algorithm': { | ||
| 'algorithm': 'rsa', | ||
| 'parameters': None, | ||
| pub_asn1 = RSAPublicKey.load(encode_rsa_public_key(pub)) | ||
| info = CertificationRequestInfo( | ||
| { | ||
| "version": 0, | ||
| "subject": Name.build( | ||
| { | ||
| "common_name": "Test Certificate", | ||
| } | ||
| ), | ||
| "subject_pk_info": { | ||
| "algorithm": { | ||
| "algorithm": "rsa", | ||
| "parameters": None, | ||
| }, | ||
| "public_key": pub_asn1, | ||
| }, | ||
| 'public_key': RSAPublicKey.load(encode_rsa_public_key(pub)), | ||
| }, | ||
| }) | ||
| } | ||
| ) | ||
| # Sign the CSR Info | ||
| value = priv.sign(info.dump(), | ||
| mechanism=Mechanism.SHA1_RSA_PKCS) | ||
| value = priv.sign(info.dump(), mechanism=Mechanism.SHA256_RSA_PKCS) | ||
| csr = CertificationRequest({ | ||
| 'certification_request_info': info, | ||
| 'signature_algorithm': { | ||
| 'algorithm': 'sha1_rsa', | ||
| 'parameters': None, | ||
| }, | ||
| 'signature': value, | ||
| }) | ||
| csr_data = CertificationRequest( | ||
| { | ||
| "certification_request_info": info, | ||
| "signature_algorithm": { | ||
| "algorithm": "sha256_rsa", | ||
| "parameters": None, | ||
| }, | ||
| "signature": value, | ||
| } | ||
| ).dump() | ||
| # Pipe our CSR to OpenSSL to verify it | ||
| with subprocess.Popen((OPENSSL, 'req', | ||
| '-inform', 'der', | ||
| '-noout', | ||
| '-verify'), | ||
| stdin=subprocess.PIPE, | ||
| stdout=subprocess.DEVNULL) as proc: | ||
| proc.stdin.write(csr.dump()) | ||
| proc.stdin.close() | ||
| self.assertEqual(proc.wait(), 0) | ||
| # read back the data and validate it | ||
| pub_key_handle = load_der_public_key(pub_asn1.dump()) | ||
| csr_loaded = CertificationRequest.load(csr_data) | ||
| info_bytes = csr_loaded["certification_request_info"].dump() | ||
| signature_bytes = csr_loaded["signature"].native | ||
| pub_key_handle.verify(signature_bytes, info_bytes, PKCS1v15(), SHA256()) |
-45
| sudo: false | ||
| language: python | ||
| python: | ||
| - '3.5' | ||
| - '3.6' | ||
| - '3.7' | ||
| - '3.8' | ||
| env: | ||
| global: | ||
| - PKCS11_MODULE=/home/travis/lib/softhsm/libsofthsm2.so | ||
| - PKCS11_TOKEN_LABEL=TEST | ||
| - PKCS11_TOKEN_PIN=1234 | ||
| - PKCS11_TOKEN_SO_PIN=5678 | ||
| cache: | ||
| - pip | ||
| - ccache # For SoftHSMv2 | ||
| before_install: | ||
| - pip install -U pip setuptools | ||
| - pip install -r dev-requirements.txt | ||
| # Install SoftHSMv2 | ||
| - curl https://dist.opendnssec.org/source/softhsm-2.5.0.tar.gz | tar -zxv | ||
| - (cd softhsm-2.5.0 && ./configure --prefix=$HOME --disable-p11-kit --disable-gost && make all install CC="ccache gcc" CXX="ccache g++") | ||
| before_script: | ||
| # Initialise a token on the SoftHSM | ||
| - $HOME/bin/softhsm2-util --init-token --free --label TEST --pin 1234 --so-pin 5678 | ||
| # Build our extension | ||
| - python setup.py build_ext -i | ||
| script: python -m unittest | ||
| deploy: | ||
| provider: pypi | ||
| user: danni | ||
| password: | ||
| secure: "A/W51+GTE9CBAm4m+1AVg11EAF63BUBrCXIonmYCdTT2htEGStk9AJnZGOinHPhwgJoWujBqgqyjqm8wJSvsmhyPSWxGk20lkCJOptcHdExu4FoSnLNNzAgPtZH5lLarkpvxB20J9hUUb4CQbgz5BWeNqFPvKigKFworCksRr9EM4J/Ys8tmkI2zwSTRDH2YAmhI/h8BWGpHMP+pNUsjlp9ZbDaxgNY85r7RloP07N5R0A7TPePH8wJzuGMDOv8dLazdr0epCbvFk+2CyJ7KiEJoX+SlS/2Hi7OKnmuf7QG2z2YyukLlJcP+IhRfzZDVgUeXwJbu24XAUdMoBS8OxId8dOKFla+GJScpWGpA9rO5vgItTAYLG7sd9HuveCtvUZxqbJd5teST4PdcxjjeO5LxYkgXKrLEo1dvDtPOm/veA0axFrXzlberJCKyN2T6grfM5QVUCORQnUYPnOqkYXMHFKSIUfa2mpfJ8NZaHR7jEbddU/PpQTHwlcehMtTx9IKQyfzillmhiXVc+UMOInFbEsU4oD9f0eP2fcs2dDB3ppR+Rdkh8bb80zH2r55Giu4Fv/WGcllwaYvMGkm6TBdod/Hva4sypJaLkLFDH6LQ0jOBHfPdFYKzEn16kZ1F4X+QWl6lKiz4XWAJI8Cf73y9Acj1Q+4MAHobkE/908M=" | ||
| skip_upload_docs: true | ||
| on: | ||
| tags: true | ||
| python: 3.6 |
| Cython | ||
| setuptools_scm | ||
| # Used for tests | ||
| oscrypto | ||
| cryptography | ||
| sphinx | ||
| sphinx-rtd-theme | ||
| flake8 |
| # | ||
| # This file is autogenerated by pip-compile | ||
| # To update, run: | ||
| # | ||
| # pip-compile dev-requirements.in | ||
| # | ||
| alabaster==0.7.12 # via sphinx | ||
| asn1crypto==1.3.0 # via oscrypto | ||
| babel==2.8.0 # via sphinx | ||
| certifi==2019.11.28 # via requests | ||
| cffi==1.14.0 # via cryptography | ||
| chardet==3.0.4 # via requests | ||
| cryptography==2.8 # via -r dev-requirements.in | ||
| cython==0.29.15 # via -r dev-requirements.in | ||
| docutils==0.16 # via sphinx | ||
| entrypoints==0.3 # via flake8 | ||
| flake8==3.7.9 # via -r dev-requirements.in | ||
| idna==2.9 # via requests | ||
| imagesize==1.2.0 # via sphinx | ||
| jinja2==2.11.1 # via sphinx | ||
| markupsafe==1.1.1 # via jinja2 | ||
| mccabe==0.6.1 # via flake8 | ||
| oscrypto==1.2.0 # via -r dev-requirements.in | ||
| packaging==20.1 # via sphinx | ||
| pycodestyle==2.5.0 # via flake8 | ||
| pycparser==2.19 # via cffi | ||
| pyflakes==2.1.1 # via flake8 | ||
| pygments==2.5.2 # via sphinx | ||
| pyparsing==2.4.6 # via packaging | ||
| pytz==2019.3 # via babel | ||
| requests==2.23.0 # via sphinx | ||
| setuptools-scm==3.5.0 # via -r dev-requirements.in | ||
| six==1.14.0 # via cryptography, packaging | ||
| snowballstemmer==2.0.0 # via sphinx | ||
| sphinx-rtd-theme==0.4.3 # via -r dev-requirements.in | ||
| sphinx==2.4.3 # via -r dev-requirements.in, sphinx-rtd-theme | ||
| sphinxcontrib-applehelp==1.0.1 # via sphinx | ||
| sphinxcontrib-devhelp==1.0.1 # via sphinx | ||
| sphinxcontrib-htmlhelp==1.0.3 # via sphinx | ||
| sphinxcontrib-jsmath==1.0.1 # via sphinx | ||
| sphinxcontrib-qthelp==1.0.2 # via sphinx | ||
| sphinxcontrib-serializinghtml==1.1.3 # via sphinx | ||
| urllib3==1.25.8 # via requests | ||
| # The following packages are considered to be unsafe in a requirements file: | ||
| # setuptools |
| """ | ||
| Map from CKR return codes to Python exceptions. | ||
| """ | ||
| from .exceptions import * | ||
| cdef ERROR_MAP = { | ||
| CKR_ATTRIBUTE_TYPE_INVALID: AttributeTypeInvalid, | ||
| CKR_ATTRIBUTE_VALUE_INVALID: AttributeValueInvalid, | ||
| CKR_ATTRIBUTE_READ_ONLY: AttributeReadOnly, | ||
| CKR_ATTRIBUTE_SENSITIVE: AttributeSensitive, | ||
| CKR_ARGUMENTS_BAD: ArgumentsBad, | ||
| CKR_BUFFER_TOO_SMALL: MemoryError("Buffer was too small. Should never see this."), | ||
| CKR_CRYPTOKI_ALREADY_INITIALIZED: RuntimeError("Initialisation error (already initialized). Should never see this."), | ||
| CKR_CRYPTOKI_NOT_INITIALIZED: RuntimeError("Initialisation error (not initialized). Should never see this."), | ||
| CKR_DATA_INVALID: DataInvalid, | ||
| CKR_DATA_LEN_RANGE: DataLenRange, | ||
| CKR_DOMAIN_PARAMS_INVALID: DomainParamsInvalid, | ||
| CKR_DEVICE_ERROR: DeviceError, | ||
| CKR_DEVICE_MEMORY: DeviceMemory, | ||
| CKR_DEVICE_REMOVED: DeviceRemoved, | ||
| CKR_ENCRYPTED_DATA_INVALID: EncryptedDataInvalid, | ||
| CKR_ENCRYPTED_DATA_LEN_RANGE: EncryptedDataLenRange, | ||
| CKR_EXCEEDED_MAX_ITERATIONS: ExceededMaxIterations, | ||
| CKR_FUNCTION_CANCELED: FunctionCancelled, | ||
| CKR_FUNCTION_FAILED: FunctionFailed, | ||
| CKR_FUNCTION_REJECTED: FunctionRejected, | ||
| CKR_FUNCTION_NOT_SUPPORTED: FunctionNotSupported, | ||
| CKR_KEY_HANDLE_INVALID: KeyHandleInvalid, | ||
| CKR_KEY_INDIGESTIBLE: KeyIndigestible, | ||
| CKR_KEY_NEEDED: KeyNeeded, | ||
| CKR_KEY_NOT_NEEDED: KeyNotNeeded, | ||
| CKR_KEY_SIZE_RANGE: KeySizeRange, | ||
| CKR_KEY_NOT_WRAPPABLE: KeyNotWrappable, | ||
| CKR_KEY_TYPE_INCONSISTENT: KeyTypeInconsistent, | ||
| CKR_KEY_UNEXTRACTABLE: KeyUnextractable, | ||
| CKR_GENERAL_ERROR: GeneralError, | ||
| CKR_HOST_MEMORY: HostMemory, | ||
| CKR_MECHANISM_INVALID: MechanismInvalid, | ||
| CKR_MECHANISM_PARAM_INVALID: MechanismParamInvalid, | ||
| CKR_OBJECT_HANDLE_INVALID: ObjectHandleInvalid, | ||
| CKR_OPERATION_ACTIVE: OperationActive, | ||
| CKR_OPERATION_NOT_INITIALIZED: OperationNotInitialized, | ||
| CKR_PIN_EXPIRED: PinExpired, | ||
| CKR_PIN_INCORRECT: PinIncorrect, | ||
| CKR_PIN_INVALID: PinInvalid, | ||
| CKR_PIN_LOCKED: PinLocked, | ||
| CKR_PIN_TOO_WEAK: PinTooWeak, | ||
| CKR_PUBLIC_KEY_INVALID: PublicKeyInvalid, | ||
| CKR_RANDOM_NO_RNG: RandomNoRNG, | ||
| CKR_RANDOM_SEED_NOT_SUPPORTED: RandomSeedNotSupported, | ||
| CKR_SESSION_CLOSED: SessionClosed, | ||
| CKR_SESSION_COUNT: SessionCount, | ||
| CKR_SESSION_EXISTS: SessionExists, | ||
| CKR_SESSION_HANDLE_INVALID: SessionHandleInvalid, | ||
| CKR_SESSION_PARALLEL_NOT_SUPPORTED: RuntimeError("Parallel not supported. Should never see this."), | ||
| CKR_SESSION_READ_ONLY: SessionReadOnly, | ||
| CKR_SESSION_READ_ONLY_EXISTS: SessionReadOnlyExists, | ||
| CKR_SESSION_READ_WRITE_SO_EXISTS: SessionReadWriteSOExists, | ||
| CKR_SIGNATURE_LEN_RANGE: SignatureLenRange, | ||
| CKR_SIGNATURE_INVALID: SignatureInvalid, | ||
| CKR_TEMPLATE_INCOMPLETE: TemplateIncomplete, | ||
| CKR_TEMPLATE_INCONSISTENT: TemplateInconsistent, | ||
| CKR_SLOT_ID_INVALID: SlotIDInvalid, | ||
| CKR_TOKEN_NOT_PRESENT: TokenNotPresent, | ||
| CKR_TOKEN_NOT_RECOGNIZED: TokenNotRecognised, | ||
| CKR_TOKEN_WRITE_PROTECTED: TokenWriteProtected, | ||
| CKR_UNWRAPPING_KEY_HANDLE_INVALID: UnwrappingKeyHandleInvalid, | ||
| CKR_UNWRAPPING_KEY_SIZE_RANGE: UnwrappingKeySizeRange, | ||
| CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT: UnwrappingKeyTypeInconsistent, | ||
| CKR_USER_NOT_LOGGED_IN: UserNotLoggedIn, | ||
| CKR_USER_ALREADY_LOGGED_IN: UserAlreadyLoggedIn, | ||
| CKR_USER_ANOTHER_ALREADY_LOGGED_IN: AnotherUserAlreadyLoggedIn, | ||
| CKR_USER_PIN_NOT_INITIALIZED: UserPinNotInitialized, | ||
| CKR_USER_TOO_MANY_TYPES: UserTooManyTypes, | ||
| CKR_USER_TYPE_INVALID: RuntimeError("User type invalid. Should never see this."), | ||
| CKR_WRAPPED_KEY_INVALID: WrappedKeyInvalid, | ||
| CKR_WRAPPED_KEY_LEN_RANGE: WrappedKeyLenRange, | ||
| CKR_WRAPPING_KEY_HANDLE_INVALID: WrappingKeyHandleInvalid, | ||
| CKR_WRAPPING_KEY_SIZE_RANGE: WrappingKeySizeRange, | ||
| CKR_WRAPPING_KEY_TYPE_INCONSISTENT: WrappingKeyTypeInconsistent, | ||
| } | ||
| cpdef void assertRV(CK_RV rv) nogil except *: | ||
| """Check for an acceptable RV value or thrown an exception.""" | ||
| if rv != CKR_OK: | ||
| raise ERROR_MAP.get(rv, | ||
| PKCS11Error("Unmapped error code %s" % hex(rv))) |
| #!python | ||
| #cython: language_level=3 | ||
| # | ||
| # MIT License | ||
| # | ||
| # Copyright 2019 Eric Devolder | ||
| # | ||
| # Permission is hereby granted, free of charge, to any person obtaining | ||
| # a copy of this software and associated documentation files (the | ||
| # "Software"), to deal in the Software without restriction, including | ||
| # without limitation the rights to use, copy, modify, merge, publish, | ||
| # distribute, sublicense, and/or sell copies of the Software, and to | ||
| # permit persons to whom the Software is furnished to do so, subject to | ||
| # the following conditions: | ||
| # | ||
| # The above copyright notice and this permission notice shall be | ||
| # included in all copies or substantial portions of the Software. | ||
| # | ||
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
| # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
| # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
| # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| """ | ||
| Definitions to support compilation on Windows platform | ||
| """ | ||
| cdef extern from "Windows.h": | ||
| ctypedef unsigned long DWORD | ||
| ctypedef Py_UNICODE wchar_t | ||
| ctypedef wchar_t *LPWSTR | ||
| ctypedef const wchar_t *LPCWSTR | ||
| ctypedef char *LPSTR | ||
| ctypedef const char *LPCSTR | ||
| ctypedef void *PVOID | ||
| ctypedef const void *LPCVOID | ||
| ctypedef PVOID HANDLE | ||
| ctypedef HANDLE HLOCAL | ||
| ctypedef HANDLE HINSTANCE | ||
| ctypedef HINSTANCE HMODULE | ||
| ctypedef bint BOOL | ||
| ctypedef short INT16 | ||
| ctypedef enum LANG_ID: | ||
| LANG_NEUTRAL | ||
| LANG_USER_DEFAULT | ||
| SUBLANG_DEFAULT | ||
| ctypedef enum FORMAT_FLAGS: | ||
| FORMAT_MESSAGE_ALLOCATE_BUFFER | ||
| FORMAT_MESSAGE_FROM_SYSTEM | ||
| FORMAT_MESSAGE_IGNORE_INSERTS | ||
| HMODULE LoadLibraryW(LPCWSTR lpLibFileName) | ||
| BOOL FreeLibrary(HMODULE hLinModule) | ||
| PVOID GetProcAddress(HMODULE hModule, LPCSTR lpProcName) | ||
| DWORD GetLastError() | ||
| DWORD MAKELANGID(INT16 p, INT16 s) | ||
| DWORD FormatMessageW( | ||
| DWORD dwFlags, | ||
| LPCVOID lpSource, | ||
| DWORD dwMessageId, | ||
| DWORD dwLanguageId, | ||
| LPWSTR lpBuffer, | ||
| DWORD nSize, | ||
| ... | ||
| ) | ||
| HLOCAL LocalFree(HLOCAL handle) | ||
| cdef inline winerror(so) with gil: | ||
| """ | ||
| returns the last error message, as a string. | ||
| If the string has '%1', it is substituted with the content of 'so' arg. | ||
| """ | ||
| # | ||
| # inspired from https://docs.microsoft.com/en-us/windows/desktop/debug/retrieving-the-last-error-code | ||
| # | ||
| cdef LPWSTR msgbuffer = NULL | ||
| dw = GetLastError() | ||
| errmsg = "" | ||
| if dw != 0: | ||
| # from https://docs.microsoft.com/en-us/windows/desktop/api/WinBase/nf-winbase-formatmessage | ||
| # at 'Security Remarks': | ||
| # In particular, it is unsafe to take an arbitrary system error code returned from an API | ||
| # and use FORMAT_MESSAGE_FROM_SYSTEM without FORMAT_MESSAGE_IGNORE_INSERTS. | ||
| # | ||
| # Given that remark, we are not attempting to parse inserts with a va_list. | ||
| # Instead, we only substitute '%1' with the value of so argument, on the returned string. | ||
| FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, | ||
| NULL, | ||
| dw, | ||
| MAKELANGID(LANG_USER_DEFAULT, SUBLANG_DEFAULT), | ||
| <LPWSTR>&msgbuffer, | ||
| 0, | ||
| NULL) | ||
| errmsg = <str>msgbuffer # C to python string copy | ||
| LocalFree(msgbuffer) | ||
| return errmsg.replace('%1', so) | ||
| #EOF |
| """ | ||
| Definitions imported from PKCS11 C headers. | ||
| """ | ||
| cdef extern from '../extern/cryptoki.h': | ||
| ctypedef unsigned char CK_BYTE | ||
| ctypedef CK_BYTE CK_BBOOL | ||
| ctypedef CK_BYTE CK_UTF8CHAR | ||
| ctypedef unsigned char CK_CHAR | ||
| ctypedef unsigned long int CK_ULONG | ||
| ctypedef CK_ULONG CK_ATTRIBUTE_TYPE | ||
| ctypedef CK_ULONG CK_EC_KDF_TYPE | ||
| ctypedef CK_ULONG CK_FLAGS | ||
| ctypedef CK_ULONG CK_MECHANISM_TYPE | ||
| ctypedef CK_ULONG CK_OBJECT_HANDLE | ||
| ctypedef CK_ULONG CK_RSA_PKCS_MGF_TYPE | ||
| ctypedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE | ||
| ctypedef CK_ULONG CK_SESSION_HANDLE | ||
| ctypedef CK_ULONG CK_SLOT_ID | ||
| ctypedef CK_ULONG CK_STATE | ||
| ctypedef enum CK_RV: | ||
| CKR_OK, | ||
| CKR_CANCEL, | ||
| CKR_HOST_MEMORY, | ||
| CKR_SLOT_ID_INVALID, | ||
| CKR_GENERAL_ERROR, | ||
| CKR_FUNCTION_FAILED, | ||
| CKR_ARGUMENTS_BAD, | ||
| CKR_NO_EVENT, | ||
| CKR_NEED_TO_CREATE_THREADS, | ||
| CKR_CANT_LOCK, | ||
| CKR_ATTRIBUTE_READ_ONLY, | ||
| CKR_ATTRIBUTE_SENSITIVE, | ||
| CKR_ATTRIBUTE_TYPE_INVALID, | ||
| CKR_ATTRIBUTE_VALUE_INVALID, | ||
| CKR_DATA_INVALID, | ||
| CKR_DATA_LEN_RANGE, | ||
| CKR_DEVICE_ERROR, | ||
| CKR_DEVICE_MEMORY, | ||
| CKR_DEVICE_REMOVED, | ||
| CKR_ENCRYPTED_DATA_INVALID, | ||
| CKR_ENCRYPTED_DATA_LEN_RANGE, | ||
| CKR_FUNCTION_CANCELED, | ||
| CKR_FUNCTION_NOT_PARALLEL, | ||
| CKR_FUNCTION_NOT_SUPPORTED, | ||
| CKR_KEY_HANDLE_INVALID, | ||
| CKR_KEY_SIZE_RANGE, | ||
| CKR_KEY_TYPE_INCONSISTENT, | ||
| CKR_KEY_NOT_NEEDED, | ||
| CKR_KEY_CHANGED, | ||
| CKR_KEY_NEEDED, | ||
| CKR_KEY_INDIGESTIBLE, | ||
| CKR_KEY_FUNCTION_NOT_PERMITTED, | ||
| CKR_KEY_NOT_WRAPPABLE, | ||
| CKR_KEY_UNEXTRACTABLE, | ||
| CKR_MECHANISM_INVALID, | ||
| CKR_MECHANISM_PARAM_INVALID, | ||
| CKR_OBJECT_HANDLE_INVALID, | ||
| CKR_OPERATION_ACTIVE, | ||
| CKR_OPERATION_NOT_INITIALIZED, | ||
| CKR_PIN_INCORRECT, | ||
| CKR_PIN_INVALID, | ||
| CKR_PIN_LEN_RANGE, | ||
| CKR_PIN_EXPIRED, | ||
| CKR_PIN_LOCKED, | ||
| CKR_SESSION_CLOSED, | ||
| CKR_SESSION_COUNT, | ||
| CKR_SESSION_HANDLE_INVALID, | ||
| CKR_SESSION_PARALLEL_NOT_SUPPORTED, | ||
| CKR_SESSION_READ_ONLY, | ||
| CKR_SESSION_EXISTS, | ||
| CKR_SESSION_READ_ONLY_EXISTS, | ||
| CKR_SESSION_READ_WRITE_SO_EXISTS, | ||
| CKR_SIGNATURE_INVALID, | ||
| CKR_SIGNATURE_LEN_RANGE, | ||
| CKR_TEMPLATE_INCOMPLETE, | ||
| CKR_TEMPLATE_INCONSISTENT, | ||
| CKR_TOKEN_NOT_PRESENT, | ||
| CKR_TOKEN_NOT_RECOGNIZED, | ||
| CKR_TOKEN_WRITE_PROTECTED, | ||
| CKR_UNWRAPPING_KEY_HANDLE_INVALID, | ||
| CKR_UNWRAPPING_KEY_SIZE_RANGE, | ||
| CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT, | ||
| CKR_USER_ALREADY_LOGGED_IN, | ||
| CKR_USER_NOT_LOGGED_IN, | ||
| CKR_USER_PIN_NOT_INITIALIZED, | ||
| CKR_USER_TYPE_INVALID, | ||
| CKR_USER_ANOTHER_ALREADY_LOGGED_IN, | ||
| CKR_USER_TOO_MANY_TYPES, | ||
| CKR_WRAPPED_KEY_INVALID, | ||
| CKR_WRAPPED_KEY_LEN_RANGE, | ||
| CKR_WRAPPING_KEY_HANDLE_INVALID, | ||
| CKR_WRAPPING_KEY_SIZE_RANGE, | ||
| CKR_WRAPPING_KEY_TYPE_INCONSISTENT, | ||
| CKR_RANDOM_SEED_NOT_SUPPORTED, | ||
| CKR_RANDOM_NO_RNG, | ||
| CKR_DOMAIN_PARAMS_INVALID, | ||
| CKR_BUFFER_TOO_SMALL, | ||
| CKR_SAVED_STATE_INVALID, | ||
| CKR_INFORMATION_SENSITIVE, | ||
| CKR_STATE_UNSAVEABLE, | ||
| CKR_CRYPTOKI_NOT_INITIALIZED, | ||
| CKR_CRYPTOKI_ALREADY_INITIALIZED, | ||
| CKR_MUTEX_BAD, | ||
| CKR_MUTEX_NOT_LOCKED, | ||
| CKR_NEW_PIN_MODE, | ||
| CKR_NEXT_OTP, | ||
| CKR_EXCEEDED_MAX_ITERATIONS, | ||
| CKR_FIPS_SELF_TEST_FAILED, | ||
| CKR_LIBRARY_LOAD_FAILED, | ||
| CKR_PIN_TOO_WEAK, | ||
| CKR_PUBLIC_KEY_INVALID, | ||
| CKR_FUNCTION_REJECTED, | ||
| CKR_VENDOR_DEFINED, | ||
| ctypedef enum CK_USER_TYPE: | ||
| CKU_SO, | ||
| CKU_USER, | ||
| CKU_CONTEXT_SPECIFIC, | ||
| cdef enum: | ||
| CK_TRUE, | ||
| CK_FALSE, | ||
| cdef enum: # CK_FLAGS | ||
| CKF_RW_SESSION, | ||
| CKF_SERIAL_SESSION, | ||
| cdef enum: # CKZ | ||
| CKZ_DATA_SPECIFIED, | ||
| cdef enum: # CK_STATE | ||
| CKS_RO_PUBLIC_SESSION, | ||
| CKS_RO_USER_FUNCTIONS, | ||
| CKS_RW_PUBLIC_SESSION, | ||
| CKS_RW_USER_FUNCTIONS, | ||
| CKS_RW_SO_FUNCTIONS | ||
| ctypedef struct CK_VERSION: | ||
| CK_BYTE major | ||
| CK_BYTE minor | ||
| ctypedef struct CK_INFO: | ||
| CK_VERSION cryptokiVersion; | ||
| CK_UTF8CHAR manufacturerID[32] | ||
| CK_FLAGS flags | ||
| CK_UTF8CHAR libraryDescription[32] | ||
| CK_VERSION libraryVersion; | ||
| ctypedef struct CK_SLOT_INFO: | ||
| CK_UTF8CHAR slotDescription[64] | ||
| CK_UTF8CHAR manufacturerID[32] | ||
| CK_FLAGS flags | ||
| CK_VERSION hardwareVersion | ||
| CK_VERSION firmwareVersion | ||
| ctypedef struct CK_MECHANISM_INFO: | ||
| CK_ULONG ulMinKeySize | ||
| CK_ULONG ulMaxKeySize | ||
| CK_FLAGS flags | ||
| ctypedef struct CK_TOKEN_INFO: | ||
| CK_UTF8CHAR label[32] | ||
| CK_UTF8CHAR manufacturerID[32] | ||
| CK_UTF8CHAR model[16] | ||
| CK_CHAR serialNumber[16] | ||
| CK_FLAGS flags | ||
| CK_ULONG ulMaxSessionCount | ||
| CK_ULONG ulSessionCount | ||
| CK_ULONG ulMaxRwSessionCount | ||
| CK_ULONG ulRwSessionCount | ||
| CK_ULONG ulMaxPinLen | ||
| CK_ULONG ulMinPinLen | ||
| CK_ULONG ulTotalPublicMemory | ||
| CK_ULONG ulFreePublicMemory | ||
| CK_ULONG ulTotalPrivateMemory | ||
| CK_ULONG ulFreePrivateMemory | ||
| CK_VERSION hardwareVersion | ||
| CK_VERSION firmwareVersion | ||
| CK_CHAR utcTime[16] | ||
| ctypedef struct CK_SESSION_INFO: | ||
| CK_SLOT_ID slotID | ||
| CK_STATE state | ||
| CK_FLAGS flags | ||
| CK_ULONG ulDeviceError | ||
| ctypedef struct CK_MECHANISM: | ||
| CK_MECHANISM_TYPE mechanism | ||
| void *pParameter | ||
| CK_ULONG ulParameterLen | ||
| ctypedef struct CK_ATTRIBUTE: | ||
| CK_ATTRIBUTE_TYPE type | ||
| void *pValue | ||
| CK_ULONG ulValueLen | ||
| ctypedef struct CK_RSA_PKCS_OAEP_PARAMS: | ||
| CK_MECHANISM_TYPE hashAlg | ||
| CK_RSA_PKCS_MGF_TYPE mgf | ||
| CK_RSA_PKCS_OAEP_SOURCE_TYPE source | ||
| void *pSourceData | ||
| CK_ULONG ulSourceDataLen | ||
| ctypedef struct CK_RSA_PKCS_PSS_PARAMS: | ||
| CK_MECHANISM_TYPE hashAlg | ||
| CK_RSA_PKCS_MGF_TYPE mgf | ||
| CK_ULONG sLen | ||
| ctypedef struct CK_ECDH1_DERIVE_PARAMS: | ||
| CK_EC_KDF_TYPE kdf | ||
| CK_ULONG ulSharedDataLen | ||
| CK_BYTE *pSharedData | ||
| CK_ULONG ulPublicDataLen | ||
| CK_BYTE *pPublicData | ||
| cdef struct CK_FUNCTION_LIST: | ||
| CK_VERSION version | ||
| ## pointers to library functions are stored here | ||
| ## caution: order matters! | ||
| ## general purpose | ||
| CK_RV C_Initialize(void *) nogil | ||
| CK_RV C_Finalize(void *) nogil | ||
| CK_RV C_GetInfo(CK_INFO *info) nogil | ||
| CK_RV C_GetFunctionList(CK_FUNCTION_LIST **) nogil | ||
| ## slot and token management | ||
| CK_RV C_GetSlotList(CK_BBOOL tokenPresent, | ||
| CK_SLOT_ID *slotList, | ||
| CK_ULONG *count) nogil | ||
| CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, | ||
| CK_SLOT_INFO *info) nogil | ||
| CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, | ||
| CK_TOKEN_INFO *info) nogil | ||
| CK_RV C_GetMechanismList(CK_SLOT_ID slotID, | ||
| CK_MECHANISM_TYPE *mechanismList, | ||
| CK_ULONG *count) nogil | ||
| CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, | ||
| CK_MECHANISM_TYPE mechanism, | ||
| CK_MECHANISM_INFO *info) nogil | ||
| CK_RV C_InitToken(CK_SLOT_ID slotID, | ||
| CK_UTF8CHAR *pPin, | ||
| CK_ULONG ulPinLen, | ||
| CK_UTF8CHAR *pLabel) nogil | ||
| CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, | ||
| CK_UTF8CHAR *pPin, | ||
| CK_ULONG ulPinLen) nogil | ||
| CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, | ||
| CK_UTF8CHAR *pOldPin, | ||
| CK_ULONG ulOldLen, | ||
| CK_UTF8CHAR *pNewPin, | ||
| CK_ULONG ulNewLen) nogil | ||
| ## session management | ||
| CK_RV C_OpenSession(CK_SLOT_ID slotID, | ||
| CK_FLAGS flags, | ||
| void *application, | ||
| void *notify, | ||
| CK_SESSION_HANDLE *handle) nogil | ||
| CK_RV C_CloseSession(CK_SESSION_HANDLE session) nogil | ||
| CK_RV C_CloseAllSessions(CK_SLOT_ID slotID) nogil | ||
| CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, | ||
| CK_SESSION_INFO *pInfo) nogil | ||
| CK_RV C_GetOperationState(CK_SESSION_HANDLE hSession, | ||
| CK_BYTE *pOperationState, | ||
| CK_ULONG *pulOperationStateLen) nogil | ||
| CK_RV C_SetOperationState(CK_SESSION_HANDLE hSession, | ||
| CK_BYTE *pOperationState, | ||
| CK_ULONG ulOperationStateLen, | ||
| CK_OBJECT_HANDLE hEncryptionKey, | ||
| CK_OBJECT_HANDLE hAuthenticationKey) nogil | ||
| CK_RV C_Login(CK_SESSION_HANDLE session, | ||
| CK_USER_TYPE userType, | ||
| CK_UTF8CHAR *pin, | ||
| CK_ULONG pinLen) nogil | ||
| CK_RV C_Logout(CK_SESSION_HANDLE session) nogil | ||
| ## object management | ||
| CK_RV C_CreateObject(CK_SESSION_HANDLE session, | ||
| CK_ATTRIBUTE *template, | ||
| CK_ULONG count, | ||
| CK_OBJECT_HANDLE *key) nogil | ||
| CK_RV C_CopyObject(CK_SESSION_HANDLE session, | ||
| CK_OBJECT_HANDLE key, | ||
| CK_ATTRIBUTE *template, | ||
| CK_ULONG count, | ||
| CK_OBJECT_HANDLE *new_key) nogil | ||
| CK_RV C_DestroyObject(CK_SESSION_HANDLE session, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_GetObjectSize(CK_SESSION_HANDLE hSession, | ||
| CK_OBJECT_HANDLE hObject, | ||
| CK_ULONG *pulSize) nogil | ||
| CK_RV C_GetAttributeValue(CK_SESSION_HANDLE session, | ||
| CK_OBJECT_HANDLE key, | ||
| CK_ATTRIBUTE *template, | ||
| CK_ULONG count) nogil | ||
| CK_RV C_SetAttributeValue(CK_SESSION_HANDLE session, | ||
| CK_OBJECT_HANDLE key, | ||
| CK_ATTRIBUTE *template, | ||
| CK_ULONG count) nogil | ||
| CK_RV C_FindObjectsInit(CK_SESSION_HANDLE session, | ||
| CK_ATTRIBUTE *template, | ||
| CK_ULONG count) nogil | ||
| CK_RV C_FindObjects(CK_SESSION_HANDLE session, | ||
| CK_OBJECT_HANDLE *objects, | ||
| CK_ULONG objectsMax, | ||
| CK_ULONG *objectsLength) nogil | ||
| CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE session) nogil | ||
| ## encryption and decryption | ||
| CK_RV C_EncryptInit(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_Encrypt(CK_SESSION_HANDLE session, | ||
| CK_BYTE *plaintext, | ||
| CK_ULONG plaintext_len, | ||
| CK_BYTE *ciphertext, | ||
| CK_ULONG *ciphertext_len) nogil | ||
| CK_RV C_EncryptUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *part_in, | ||
| CK_ULONG part_in_len, | ||
| CK_BYTE *part_out, | ||
| CK_ULONG *part_out_len) nogil | ||
| CK_RV C_EncryptFinal(CK_SESSION_HANDLE session, | ||
| CK_BYTE *part_out, | ||
| CK_ULONG *part_out_len) nogil | ||
| CK_RV C_DecryptInit(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_Decrypt(CK_SESSION_HANDLE session, | ||
| CK_BYTE *ciphertext, | ||
| CK_ULONG ciphertext_len, | ||
| CK_BYTE *plaintext, | ||
| CK_ULONG *plaintext_len) nogil | ||
| CK_RV C_DecryptUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *part_in, | ||
| CK_ULONG part_in_len, | ||
| CK_BYTE *part_out, | ||
| CK_ULONG *part_out_len) nogil | ||
| CK_RV C_DecryptFinal(CK_SESSION_HANDLE session, | ||
| CK_BYTE *part_out, | ||
| CK_ULONG *part_out_len) nogil | ||
| ## Message digests | ||
| CK_RV C_DigestInit(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism) nogil | ||
| CK_RV C_Digest(CK_SESSION_HANDLE session, | ||
| CK_BYTE *data, | ||
| CK_ULONG data_len, | ||
| CK_BYTE *digest, | ||
| CK_ULONG *digest_len) nogil | ||
| CK_RV C_DigestUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *data, | ||
| CK_ULONG data_len) nogil | ||
| CK_RV C_DigestKey(CK_SESSION_HANDLE session, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_DigestFinal(CK_SESSION_HANDLE session, | ||
| CK_BYTE *digest, | ||
| CK_ULONG *digest_len) nogil | ||
| ## Signing and MACing | ||
| CK_RV C_SignInit(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_Sign(CK_SESSION_HANDLE session, | ||
| CK_BYTE *text, | ||
| CK_ULONG text_len, | ||
| CK_BYTE *signature, | ||
| CK_ULONG *sig_len) nogil | ||
| CK_RV C_SignUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *part, | ||
| CK_ULONG part_len) nogil | ||
| CK_RV C_SignFinal(CK_SESSION_HANDLE session, | ||
| CK_BYTE *signature, | ||
| CK_ULONG *sig_len) nogil | ||
| CK_RV C_SignRecoverInit(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_SignRecover(CK_SESSION_HANDLE session, | ||
| CK_BYTE *text, | ||
| CK_ULONG text_len, | ||
| CK_BYTE *signature, | ||
| CK_ULONG *sig_len) nogil | ||
| ## Verifying signatures and MACs | ||
| CK_RV C_VerifyInit(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_Verify(CK_SESSION_HANDLE session, | ||
| CK_BYTE *text, | ||
| CK_ULONG text_len, | ||
| CK_BYTE *signature, | ||
| CK_ULONG sig_len) nogil | ||
| CK_RV C_VerifyUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *text, | ||
| CK_ULONG text_len) nogil | ||
| CK_RV C_VerifyFinal(CK_SESSION_HANDLE session, | ||
| CK_BYTE *signature, | ||
| CK_ULONG sig_len) nogil | ||
| CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE key) nogil | ||
| CK_RV C_VerifyRecover(CK_SESSION_HANDLE session, | ||
| CK_BYTE *text, | ||
| CK_ULONG text_len, | ||
| CK_BYTE *signature, | ||
| CK_ULONG sig_len) nogil | ||
| ## dual-function crypto operations | ||
| CK_RV C_DigestEncryptUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *data, | ||
| CK_ULONG data_len, | ||
| CK_BYTE *encrypted, | ||
| CK_ULONG *encrypted_len) nogil | ||
| CK_RV C_DecryptDigestUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *encrypted, | ||
| CK_ULONG encrypted_len, | ||
| CK_BYTE *data, | ||
| CK_ULONG *data_len) nogil | ||
| CK_RV C_SignEncryptUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *part, | ||
| CK_ULONG part_len) nogil | ||
| CK_RV C_DecryptVerifyUpdate(CK_SESSION_HANDLE session, | ||
| CK_BYTE *text, | ||
| CK_ULONG text_len) nogil | ||
| ## key management | ||
| CK_RV C_GenerateKey(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_ATTRIBUTE *template, | ||
| CK_ULONG count, | ||
| CK_OBJECT_HANDLE *key) nogil | ||
| CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_ATTRIBUTE *public_template, | ||
| CK_ULONG public_count, | ||
| CK_ATTRIBUTE *private_template, | ||
| CK_ULONG private_count, | ||
| CK_OBJECT_HANDLE *public_key, | ||
| CK_OBJECT_HANDLE *private_key) nogil | ||
| CK_RV C_WrapKey(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE wrapping_key, | ||
| CK_OBJECT_HANDLE key_to_wrap, | ||
| CK_BYTE *wrapped_key, | ||
| CK_ULONG *wrapped_key_len) nogil | ||
| CK_RV C_UnwrapKey(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE unwrapping_key, | ||
| CK_BYTE *wrapped_key, | ||
| CK_ULONG wrapped_key_len, | ||
| CK_ATTRIBUTE *attrs, | ||
| CK_ULONG attr_len, | ||
| CK_OBJECT_HANDLE *unwrapped_key) nogil | ||
| CK_RV C_DeriveKey(CK_SESSION_HANDLE session, | ||
| CK_MECHANISM *mechanism, | ||
| CK_OBJECT_HANDLE src_key, | ||
| CK_ATTRIBUTE *template, | ||
| CK_ULONG count, | ||
| CK_OBJECT_HANDLE *new_key) nogil | ||
| ## random number generation | ||
| CK_RV C_SeedRandom(CK_SESSION_HANDLE session, | ||
| CK_BYTE *seed, | ||
| CK_ULONG length) nogil | ||
| CK_RV C_GenerateRandom(CK_SESSION_HANDLE session, | ||
| CK_BYTE *random, | ||
| CK_ULONG length) nogil | ||
| ## parallel processing | ||
| CK_RV C_GetFunctionStatus(CK_SESSION_HANDLE session) nogil | ||
| CK_RV C_CancelFunction(CK_SESSION_HANDLE session) nogil | ||
| ## smart card events | ||
| CK_RV C_WaitForSlotEvent(CK_FLAGS flags, | ||
| CK_SLOT_ID *slot, | ||
| void *pRserved) nogil | ||
| # The only external API call that must be defined in a PKCS#11 library | ||
| # All other APIs are taken from the CK_FUNCTION_LIST table | ||
| ctypedef CK_RV (*C_GetFunctionList_ptr) (CK_FUNCTION_LIST **) nogil |
| """ | ||
| Type wrangling utility functions. | ||
| """ | ||
| from .constants import * | ||
| from .mechanisms import * | ||
| cdef CK_BYTE_buffer(length): | ||
| """Make a buffer for `length` CK_BYTEs.""" | ||
| return array(shape=(length,), itemsize=sizeof(CK_BYTE), format='B') | ||
| cdef CK_ULONG_buffer(length): | ||
| """Make a buffer for `length` CK_ULONGs.""" | ||
| return array(shape=(length,), itemsize=sizeof(CK_ULONG), format='L') | ||
| cdef bytes _pack_attribute(key, value): | ||
| """Pack a Attribute value into a bytes array.""" | ||
| try: | ||
| pack, _ = ATTRIBUTE_TYPES[key] | ||
| return pack(value) | ||
| except KeyError: | ||
| raise NotImplementedError("Can't pack this %s. " | ||
| "Expand ATTRIBUTE_TYPES!" % key) | ||
| cdef _unpack_attributes(key, value): | ||
| """Unpack a Attribute bytes array into a Python value.""" | ||
| try: | ||
| _, unpack = ATTRIBUTE_TYPES[key] | ||
| return unpack(bytes(value)) | ||
| except KeyError: | ||
| raise NotImplementedError("Can't unpack this %s. " | ||
| "Expand ATTRIBUTE_TYPES!" % key) |
| aenum; python_version < "3.6" | ||
| asn1crypto | ||
| cached-property |
| # | ||
| # This file is autogenerated by pip-compile | ||
| # To update, run: | ||
| # | ||
| # pip-compile --output-file requirements.txt requirements.in | ||
| # | ||
| aenum==2.0.7 ; python_version < "3.6" | ||
| asn1crypto==0.22.0 | ||
| cached-property==1.3.0 |
-61
| #!/usr/bin/env python | ||
| """ | ||
| setup.py | ||
| """ | ||
| from setuptools import setup, find_packages | ||
| from setuptools.extension import Extension | ||
| import platform | ||
| # if compiling using MSVC, we need to link against user32 library | ||
| if platform.system() == 'Windows': | ||
| libraries = ('user32',) | ||
| else: | ||
| libraries = () | ||
| if __name__ == '__main__': | ||
| with \ | ||
| open('requirements.in') as requirements, \ | ||
| open('README.rst') as readme: | ||
| ext_modules = [ | ||
| Extension('pkcs11._pkcs11', | ||
| sources=[ | ||
| 'pkcs11/_pkcs11.pyx', | ||
| ], | ||
| libraries=libraries, | ||
| ), | ||
| ] | ||
| setup( | ||
| name='python-pkcs11', | ||
| description='PKCS#11 (Cryptoki) support for Python', | ||
| use_scm_version=True, | ||
| author='Danielle Madeley', | ||
| author_email='danielle@madeley.id.au', | ||
| url='https://github.com/danni/python-pkcs11', | ||
| long_description=readme.read(), | ||
| classifiers=[ | ||
| 'License :: OSI Approved :: MIT License', | ||
| 'Programming Language :: Python', | ||
| 'Programming Language :: Python :: 3', | ||
| 'Programming Language :: Python :: 3.5', | ||
| 'Programming Language :: Python :: 3.6', | ||
| 'Programming Language :: Python :: 3.7', | ||
| 'Programming Language :: Python :: 3.8', | ||
| 'Topic :: Security :: Cryptography', | ||
| ], | ||
| packages=find_packages(exclude=['tests']), | ||
| include_package_data=True, | ||
| ext_modules=ext_modules, | ||
| install_requires=requirements.readlines(), | ||
| setup_requires=[ | ||
| 'cython', | ||
| 'setuptools >= 18.0', | ||
| 'setuptools_scm', | ||
| ], | ||
| test_suite='tests', | ||
| ) |
| #!/bin/sh | ||
| # | ||
| # Build pkcs11 | ||
| # | ||
| set -xe | ||
| # Enable our virtualenv | ||
| . python_env/bin/activate | ||
| python setup.py build_ext -i |
| #!/bin/sh | ||
| # | ||
| # Install dependencies | ||
| # | ||
| set -xe | ||
| # Create virtualenv if needed | ||
| [ -d python_env ] || python3 -m venv python_env | ||
| # Enable our virtualenv | ||
| . python_env/bin/activate | ||
| pip install -U pip six | ||
| pip install -U setuptools cython | ||
| pip install -r requirements.txt -r dev-requirements.txt |
| #!/bin/sh | ||
| # | ||
| # Test pkcs11 | ||
| # | ||
| set -xe | ||
| # Enable our virtualenv | ||
| . python_env/bin/activate | ||
| # Test parameters come from ShellCommand | ||
| # export PKCS11_MODULE= | ||
| # export PKCS11_TOKEN_LABEL= | ||
| # export PKCS11_TOKEN_PIN= | ||
| python -m unittest |
| #!/bin/sh | ||
| # | ||
| # Build pkcs11 | ||
| # | ||
| set -xe | ||
| # Enable Python 3.5 from SCL | ||
| . /opt/rh/rh-python35/enable | ||
| # Enable our virtualenv | ||
| . python_env/bin/activate | ||
| python setup.py build_ext -i |
| #!/bin/sh | ||
| # | ||
| # Install dependencies for nFast tests on RHEL7 | ||
| # | ||
| set -xe | ||
| # Enable Python 3.5 from SCL | ||
| . /opt/rh/rh-python35/enable | ||
| # Create virtualenv if needed | ||
| [ -d python_env ] || virtualenv -p python3 python_env | ||
| # Enable our virtualenv | ||
| . python_env/bin/activate | ||
| pip install -U pip six | ||
| pip install -U setuptools cython | ||
| pip install -r requirements.txt -r dev-requirements.txt |
| #!/bin/sh | ||
| # | ||
| # Test pkcs11 | ||
| # | ||
| set -xe | ||
| # Enable Python 3.5 from SCL | ||
| . /opt/rh/rh-python35/enable | ||
| # Enable our virtualenv | ||
| . python_env/bin/activate | ||
| # Test parameters | ||
| export CKNFAST_FAKE_ACCELERATOR_LOGIN=true | ||
| export CKNFAST_LOADSHARING=1 | ||
| export CKNFAST_DEBUG=6 | ||
| export PKCS11_MODULE=/opt/nfast/toolkits/pkcs11/libcknfast.so | ||
| export PKCS11_TOKEN_LABEL='loadshared accelerator' | ||
| export PKCS11_TOKEN_PIN='0000' | ||
| python -m unittest |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
681008
40.51%4855
14.05%