New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

python-pkcs11

Package Overview
Dependencies
Maintainers
2
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

python-pkcs11 - pypi Package Compare versions

Comparing version
0.7.0
to
0.8.0
+54
.github/actions/install-softhsm/action.yml
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
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"]
#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);
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/

@@ -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 @@

@@ -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",
),
]

@@ -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)

@@ -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(

@@ -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_ */

@@ -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

@@ -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."""

@@ -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 @@

@@ -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

@@ -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

@@ -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")

@@ -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()

@@ -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()

@@ -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 @@

@@ -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()

@@ -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.

@@ -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

@@ -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

@@ -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 @@

@@ -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_")

@@ -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 @@

@@ -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 @@ )

@@ -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)

@@ -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)

@@ -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

@@ -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:

@@ -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())
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
#!/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