summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Cholasta <jcholast@redhat.com>2016-01-06 13:10:11 +0100
committerMartin Basti <mbasti@redhat.com>2016-01-21 10:21:32 +0100
commit500ee7e2b1fdaa9669cf136a380907cfe4f0f225 (patch)
tree79b5f3ce0c8d0d6caa68512b468d96c76b2daebf
parentf5f5c8c603e95d246d2cde92f56959fedba4666d (diff)
downloadfreeipa-500ee7e2b1fdaa9669cf136a380907cfe4f0f225.tar.gz
freeipa-500ee7e2b1fdaa9669cf136a380907cfe4f0f225.tar.xz
freeipa-500ee7e2b1fdaa9669cf136a380907cfe4f0f225.zip
ipapython: port p11helper C code to Python
This replaces the binary _ipap11helper module with cffi-based Python code. https://fedorahosted.org/freeipa/ticket/5596 Reviewed-By: Martin Basti <mbasti@redhat.com>
-rw-r--r--.gitignore1
-rw-r--r--freeipa.spec.in12
-rw-r--r--ipapython/Makefile2
-rw-r--r--ipapython/dnssec/abshsm.py2
-rw-r--r--ipapython/dnssec/ldapkeydb.py2
-rwxr-xr-xipapython/dnssec/localhsm.py4
-rw-r--r--ipapython/ipap11helper/Makefile19
-rw-r--r--ipapython/ipap11helper/library.c87
-rw-r--r--ipapython/ipap11helper/library.h48
-rw-r--r--ipapython/ipap11helper/p11helper.c2268
-rw-r--r--ipapython/ipap11helper/setup.py43
-rw-r--r--ipapython/p11helper.py1870
-rw-r--r--ipaserver/install/dnskeysyncinstance.py2
-rw-r--r--ipaserver/install/opendnssecinstance.py2
-rw-r--r--ipatests/pytest.ini1
-rw-r--r--ipatests/test_ipapython/test_ipap11helper.py2
16 files changed, 1873 insertions, 2492 deletions
diff --git a/.gitignore b/.gitignore
index 937559072..e862c08d7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -73,7 +73,6 @@ freeipa2-dev-doc
/ipapython/setup.py
/ipapython/version.py
!/ipapython/Makefile
-!/ipapython/ipap11helper/Makefile
/ipaplatform/__init__.py
/ipaplatform/setup.py
diff --git a/freeipa.spec.in b/freeipa.spec.in
index d045aab8f..899af6c92 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -93,9 +93,7 @@ BuildRequires: systemd
BuildRequires: libunistring-devel
BuildRequires: python-lesscpy
BuildRequires: python-yubico >= 1.2.3
-BuildRequires: softhsm-devel >= 2.0.0rc1-1
BuildRequires: openssl-devel
-BuildRequires: p11-kit-devel
BuildRequires: pki-base >= 10.2.6
BuildRequires: python-pytest-multihost >= 0.5
BuildRequires: python-pytest-sourceorder
@@ -471,6 +469,7 @@ Requires: dbus-python
Requires: python-setuptools
Requires: python-six
Requires: python-jwcrypto
+Requires: python-cffi
Conflicts: %{alt_name}-python < %{version}
@@ -515,6 +514,7 @@ Requires: python3-dbus
Requires: python3-setuptools
Requires: python3-six
Requires: python3-jwcrypto
+Requires: python3-cffi
%description -n python3-ipalib
IPA is an integrated solution to provide centrally managed Identity (users,
@@ -639,10 +639,6 @@ cd daemons; ../autogen.sh --prefix=%{_usr} --sysconfdir=%{_sysconfdir} --localst
cd install; ../autogen.sh --prefix=%{_usr} --sysconfdir=%{_sysconfdir} --localstatedir=%{_localstatedir} --libdir=%{_libdir} --mandir=%{_mandir}; cd ..
%endif # ONLY_CLIENT
-%if 0%{?with_python3}
-(cd ipapython/ipap11helper && make PYTHON=%{__python3} IPA_VERSION_IS_GIT_SNAPSHOT=no %{?_smp_mflags} all)
-%endif
-
%if ! %{ONLY_CLIENT}
make IPA_VERSION_IS_GIT_SNAPSHOT=no %{?_smp_mflags} all
%else
@@ -1311,12 +1307,10 @@ fi
%{python_sitelib}/ipalib/*
%dir %{python_sitelib}/ipaplatform
%{python_sitelib}/ipaplatform/*
-%attr(0644,root,root) %{python_sitearch}/_ipap11helper.so
%{python_sitelib}/ipapython-*.egg-info
%{python_sitelib}/ipalib-*.egg-info
%{python_sitelib}/freeipa-*.egg-info
%{python_sitelib}/ipaplatform-*.egg-info
-%{python_sitearch}/_ipap11helper-*.egg-info
%files common -f %{gettext_domain}.lang
@@ -1338,8 +1332,6 @@ fi
%{python3_sitelib}/ipapython-*.egg-info
%{python3_sitelib}/ipalib-*.egg-info
%{python3_sitelib}/ipaplatform-*.egg-info
-%attr(0644,root,root) %{python3_sitearch}/_ipap11helper.cpython-*.so
-%{python3_sitearch}/_ipap11helper-*.egg-info
%endif # with_python3
diff --git a/ipapython/Makefile b/ipapython/Makefile
index 201c5894d..d262439fd 100644
--- a/ipapython/Makefile
+++ b/ipapython/Makefile
@@ -1,8 +1,6 @@
PYTHON ?= /usr/bin/python2
PYTHONLIBDIR ?= $(shell $(PYTHON) -c "from distutils.sysconfig import *; print(get_python_lib())")
-SUBDIRS = ipap11helper
-
all:
@for subdir in $(SUBDIRS); do \
(cd $$subdir && $(MAKE) $@) || exit 1; \
diff --git a/ipapython/dnssec/abshsm.py b/ipapython/dnssec/abshsm.py
index 156bcf32c..1533892f8 100644
--- a/ipapython/dnssec/abshsm.py
+++ b/ipapython/dnssec/abshsm.py
@@ -2,7 +2,7 @@
# Copyright (C) 2014 FreeIPA Contributors see COPYING for license
#
-import _ipap11helper
+from ipapython import p11helper as _ipap11helper
attrs_id2name = {
#_ipap11helper.CKA_ALLOWED_MECHANISMS: 'ipk11allowedmechanisms',
diff --git a/ipapython/dnssec/ldapkeydb.py b/ipapython/dnssec/ldapkeydb.py
index 0ee309525..55c09c040 100644
--- a/ipapython/dnssec/ldapkeydb.py
+++ b/ipapython/dnssec/ldapkeydb.py
@@ -18,7 +18,7 @@ from ipapython.dnssec.abshsm import (
AbstractHSM,
bool_attr_names,
populate_pkcs11_metadata)
-import _ipap11helper
+from ipapython import p11helper as _ipap11helper
import uuid
def uri_escape(val):
diff --git a/ipapython/dnssec/localhsm.py b/ipapython/dnssec/localhsm.py
index 76ab00444..8f18a45be 100755
--- a/ipapython/dnssec/localhsm.py
+++ b/ipapython/dnssec/localhsm.py
@@ -13,7 +13,7 @@ from pprint import pprint
from ipaplatform.paths import paths
-import _ipap11helper
+from ipapython import p11helper as _ipap11helper
from ipapython.dnssec.abshsm import (attrs_name2id, attrs_id2name, AbstractHSM,
keytype_id2name, keytype_name2id,
ldap2p11helper_api_params)
@@ -65,7 +65,7 @@ class Key(collections.MutableMapping):
return self.p11.set_attribute(self.handle, attrs_name2id[key], value)
def __delitem__(self, key):
- raise _ipap11helper.Exception('__delitem__ is not supported')
+ raise _ipap11helper.P11HelperException('__delitem__ is not supported')
def __iter__(self):
"""generates list of ipa names of all attributes present in the object"""
diff --git a/ipapython/ipap11helper/Makefile b/ipapython/ipap11helper/Makefile
deleted file mode 100644
index f66edb82e..000000000
--- a/ipapython/ipap11helper/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-PYTHON ?= /usr/bin/python2
-PYTHONLIBDIR ?= $(shell $(PYTHON) -c "from distutils.sysconfig import *; print(get_python_lib())")
-
-all:
- $(PYTHON) setup.py build
-
-install:
- if [ "$(DESTDIR)" = "" ]; then \
- $(PYTHON) setup.py install; \
- else \
- $(PYTHON) setup.py install --root $(DESTDIR); \
- fi
-
-clean:
- rm -rf build
-
-distclean: clean
-
-maintainer-clean: distclean
diff --git a/ipapython/ipap11helper/library.c b/ipapython/ipap11helper/library.c
deleted file mode 100644
index acae47e5c..000000000
--- a/ipapython/ipap11helper/library.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2014 FreeIPA Contributors see COPYING for license
- *
- * This code is based on PKCS#11 code from SoftHSM project:
- * https://github.com/opendnssec/SoftHSMv2/
- * Original license follows:
- */
-/*
- * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*****************************************************************************
- library.c
-
- Support function for handling PKCS#11 libraries
- *****************************************************************************/
-
-#include "library.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <dlfcn.h>
-
-// Load the PKCS#11 library
-CK_C_GetFunctionList loadLibrary(const char* module, void** moduleHandle)
-{
- CK_C_GetFunctionList pGetFunctionList = NULL;
-
- void* pDynLib = NULL;
-
- // Load PKCS #11 library
- if (module)
- {
- pDynLib = dlopen(module, RTLD_NOW | RTLD_LOCAL);
- } else {
- return NULL;
- }
-
- if (pDynLib == NULL)
- {
- // Failed to load the PKCS #11 library
- return NULL;
- }
-
- // Retrieve the entry point for C_GetFunctionList
- pGetFunctionList = (CK_C_GetFunctionList) dlsym(pDynLib, "C_GetFunctionList");
- if (pGetFunctionList == NULL)
- {
- dlclose(pDynLib);
- return NULL;
- }
-
- // Store the handle so we can dlclose it later
- *moduleHandle = pDynLib;
-
- return pGetFunctionList;
-}
-
-void unloadLibrary(void* moduleHandle)
-{
- if (moduleHandle)
- {
- dlclose(moduleHandle);
- }
-}
diff --git a/ipapython/ipap11helper/library.h b/ipapython/ipap11helper/library.h
deleted file mode 100644
index afcbd9fd2..000000000
--- a/ipapython/ipap11helper/library.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2014 FreeIPA Contributors see COPYING for license
- *
- * This code is based on PKCS#11 code from SoftHSM project:
- * https://github.com/opendnssec/SoftHSMv2/
- * Original license follows:
- */
-/*
- * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*****************************************************************************
- library.h
-
- Support function for handling PKCS#11 libraries
- *****************************************************************************/
-
-#ifndef _SOFTHSM_V2_BIN_LIBRARY_H
-#define _SOFTHSM_V2_BIN_LIBRARY_H
-
-#include <p11-kit/pkcs11.h>
-
-CK_C_GetFunctionList loadLibrary(const char* module, void** moduleHandle);
-void unloadLibrary(void* moduleHandle);
-
-#endif // !_SOFTHSM_V2_BIN_LIBRARY_H
diff --git a/ipapython/ipap11helper/p11helper.c b/ipapython/ipap11helper/p11helper.c
deleted file mode 100644
index 65bfc07ec..000000000
--- a/ipapython/ipap11helper/p11helper.c
+++ /dev/null
@@ -1,2268 +0,0 @@
-/*
- * Copyright (C) 2014 FreeIPA Contributors see COPYING for license
- *
- * This file includes an "OpenSSL license exception", see the
- * COPYING.openssl file for details.
- *
- * This code is based on PKCS#11 code snippets from NLnetLabs:
- * http://www.nlnetlabs.nl/publications/hsm/examples/pkcs11/
- * Original license follows:
- */
-/*
- * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <Python.h>
-#include "structmember.h"
-
-#include <openssl/asn1.h>
-#include <openssl/x509.h>
-#include <openssl/evp.h>
-#include <openssl/rsa.h>
-#include <openssl/bn.h>
-#include <openssl/bio.h>
-
-#include <p11-kit/pkcs11.h>
-#include <p11-kit/uri.h>
-
-#include "library.h"
-
-#if PY_MAJOR_VERSION >= 3
-// Python 3 uses "PyLong" as the int implementation
-#define PyInt_Check PyLong_Check
-#define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask
-#endif
-
-// compat TODO
-#define CKM_AES_KEY_WRAP (0x2109)
-#define CKM_AES_KEY_WRAP_PAD (0x210a)
-
-// TODO
-#define CKA_COPYABLE (0x0017)
-
-#define CKG_MGF1_SHA1 (0x00000001)
-
-#define CKZ_DATA_SPECIFIED (0x00000001)
-
-struct ck_rsa_pkcs_oaep_params {
- CK_MECHANISM_TYPE hash_alg;
- unsigned long mgf;
- unsigned long source;
- void *source_data;
- unsigned long source_data_len;
-};
-
-typedef struct ck_rsa_pkcs_oaep_params CK_RSA_PKCS_OAEP_PARAMS;
-typedef struct ck_rsa_pkcs_oaep_params *CK_RSA_PKCS_OAEP_PARAMS_PTR;
-
-
-CK_BBOOL true = CK_TRUE;
-CK_BBOOL false = CK_FALSE;
-
-#define MAX_TEMPLATE_LEN 32
-
-/**
- * P11_Helper type
- */
-typedef struct {
- PyObject_HEAD CK_SLOT_ID slot;
- CK_FUNCTION_LIST_PTR p11;
- CK_SESSION_HANDLE session;
- void *module_handle;
-} P11_Helper;
-
-typedef enum {
- sec_en_cka_copyable = 0,
- sec_en_cka_decrypt = 1,
- sec_en_cka_derive = 2,
- sec_en_cka_encrypt = 3,
- sec_en_cka_extractable = 4,
- sec_en_cka_modifiable = 5,
- sec_en_cka_private = 6,
- sec_en_cka_sensitive = 7,
- sec_en_cka_sign = 8,
- sec_en_cka_unwrap = 9,
- sec_en_cka_verify = 10,
- sec_en_cka_wrap = 11,
- sec_en_cka_wrap_with_trusted = 12
-} secrect_key_enum;
-
-typedef enum {
- pub_en_cka_copyable = 0,
- pub_en_cka_derive = 1,
- pub_en_cka_encrypt = 2,
- pub_en_cka_modifiable = 3,
- pub_en_cka_private = 4,
- pub_en_cka_trusted = 5,
- pub_en_cka_verify = 6,
- pub_en_cka_verify_recover = 7,
- pub_en_cka_wrap = 8
-} public_key_enum;
-
-typedef enum {
- priv_en_cka_always_authenticate = 0,
- priv_en_cka_copyable = 1,
- priv_en_cka_decrypt = 2,
- priv_en_cka_derive = 3,
- priv_en_cka_extractable = 4,
- priv_en_cka_modifiable = 5,
- priv_en_cka_private = 6,
- priv_en_cka_sensitive = 7,
- priv_en_cka_sign = 8,
- priv_en_cka_sign_recover = 9,
- priv_en_cka_unwrap = 10,
- priv_en_cka_wrap_with_trusted = 11
-} private_key_enum;
-
-typedef struct {
- PyObject *py_obj;
- CK_BBOOL *bool;
-} PyObj2Bool_mapping_t;
-
-/**
- * Constants
- */
-static const CK_RSA_PKCS_OAEP_PARAMS CONST_RSA_PKCS_OAEP_PARAMS = {
- .hash_alg = CKM_SHA_1,
- .mgf = CKG_MGF1_SHA1,
- .source = CKZ_DATA_SPECIFIED,
- .source_data = NULL,
- .source_data_len = 0
-};
-
-/**
- * ipap11helper Exceptions
- */
-static PyObject *ipap11helperException; // parent class for all exceptions
-
-static PyObject *ipap11helperError; // general error
-static PyObject *ipap11helperNotFound; // key not found
-static PyObject *ipap11helperDuplicationError; // key already exists
-
-/***********************************************************************
- * Support functions
- */
-
-#define GOTO_FAIL \
- do { \
- error = 1; \
- goto final; \
- } while(0);
-
-CK_BBOOL *pyobj_to_bool(PyObject *pyobj) {
- if (PyObject_IsTrue(pyobj))
- return &true;
- return &false;
-
-}
-
-void convert_py2bool(PyObj2Bool_mapping_t *mapping, int length) {
- int i;
- for (i = 0; i < length; ++i) {
- PyObject *py_obj = mapping[i].py_obj;
- if (py_obj != NULL) {
- mapping[i].bool = pyobj_to_bool(py_obj);
- }
- }
-}
-
-PyObject *string_to_pybytes_or_none(const char *str, Py_ssize_t len) {
- if (str == NULL) {
- Py_RETURN_NONE;
- }
- return PyBytes_FromStringAndSize(str, len);
-}
-
-/**
- * Convert a unicode string to the utf8 encoded char array
- * :param unicode: input python unicode object
- * :param l length: of returned string
- * Returns NULL if an error occurs, else pointer to string
- */
-unsigned char *unicode_to_char_array(PyObject *unicode, Py_ssize_t *l) {
- unsigned char *result = NULL;
- PyObject *utf8_str = PyUnicode_AsUTF8String(unicode);
- if (utf8_str == NULL) {
- PyErr_SetString(ipap11helperError, "Unable to encode UTF-8");
- return NULL;
- }
- unsigned char *bytes = (unsigned char *) PyBytes_AS_STRING(utf8_str);
- if (bytes == NULL) {
- PyErr_SetString(ipap11helperError, "Unable to get bytes from string");
- *l = 0;
- } else {
- *l = PyBytes_Size(utf8_str);
-
- /* Copy string first, then DECREF
- * https://docs.python.org/2/c-api/string.html#c.PyString_AS_STRING
- */
- result = (unsigned char *) PyMem_Malloc((size_t) * l);
- if (result == NULL) {
- Py_DECREF(utf8_str);
- PyErr_NoMemory();
- return NULL;
- } else {
- memcpy(result, bytes, *l);
- }
-
- }
- Py_DECREF(utf8_str);
- return result;
-}
-
-/**
- * Convert utf-8 encoded char array to unicode object
- */
-PyObject *char_array_to_unicode(const char *array, unsigned long l) {
- return PyUnicode_DecodeUTF8(array, l, "strict");
-}
-
-/**
- * Tests result value of pkc11 operations
- * :return: 1 if everything is ok, 0 if an error occurs and set the error message
- */
-int check_return_value(CK_RV rv, const char *message) {
- char *errmsg = NULL;
- if (rv != CKR_OK) {
- if (asprintf
- (&errmsg, "Error at %s: 0x%x\n", message, (unsigned int) rv)
- == -1) {
- PyErr_SetString(ipap11helperError,
- "An error occured during error message generation. "
- "Please report this problem. Developers will use "
- "a crystal ball to find out the root cause.");
- return 0;
- }
- if (errmsg != NULL) {
- PyErr_SetString(ipap11helperError, errmsg);
- free(errmsg);
- }
- return 0;
- }
- return 1;
-}
-
-/**
- * Fill template structure with pointers to attributes passed as independent
- * variables.
- * Variables with NULL values will be omitted from template.
- *
- * @warning input variables should not be modified when template is in use
- */
-int _fill_template_from_parts(CK_ATTRIBUTE_PTR attr, CK_ULONG_PTR template_len,
- CK_BYTE_PTR id, CK_ULONG id_len,
- CK_BYTE_PTR label, CK_ULONG label_len,
- CK_OBJECT_CLASS *class, CK_BBOOL *cka_wrap,
- CK_BBOOL *cka_unwrap) {
- int cnt = 0;
- if (label != NULL) {
- attr->type = CKA_LABEL;
- attr->pValue = (void *) label;
- attr->ulValueLen = label_len;
- ++attr;
- ++cnt;
- assert(cnt < *template_len);
- }
- if (id != NULL) {
- attr->type = CKA_ID;
- attr->pValue = (void *) id;
- attr->ulValueLen = id_len;
- ++attr;
- ++cnt;
- assert(cnt < *template_len);
- }
- if (cka_wrap != NULL) {
- attr->type = CKA_WRAP;
- attr->pValue = (void *) cka_wrap;
- attr->ulValueLen = sizeof(CK_BBOOL);
- ++attr;
- ++cnt;
- assert(cnt < *template_len);
- }
- if (cka_unwrap != NULL) {
- attr->type = CKA_UNWRAP;
- attr->pValue = (void *) cka_unwrap;
- attr->ulValueLen = sizeof(CK_BBOOL);
- ++attr;
- ++cnt;
- assert(cnt < *template_len);
- }
-
- if (class != NULL) {
- attr->type = CKA_CLASS;
- attr->pValue = (void *) class;
- attr->ulValueLen = sizeof(CK_OBJECT_CLASS);
- ++attr;
- ++cnt;
- assert(cnt < *template_len);
- }
- *template_len = cnt;
- return 1;
-}
-
-/**
- * Parse string to P11-kit representation of PKCS#11 URI.
- *
- * @pre *urip is NULL
- * @post
- *
- * @retval 0 in case of error
- * @retval 1 when urip is filled with pointer to new URI structure
- */
-int _parse_uri(const char *uri_str, P11KitUri **urip) {
- P11KitUriResult result;
- P11KitUri *uri = NULL;
-
- assert(urip != NULL && *urip == NULL);
-
- uri = p11_kit_uri_new();
- if (!uri) {
- PyErr_SetString(ipap11helperError, "Cannot initialize URI parser");
- return 0;
- }
-
- result = p11_kit_uri_parse(uri_str, P11_KIT_URI_FOR_OBJECT, uri);
- if (result != P11_KIT_URI_OK) {
- PyErr_SetString(ipap11helperError, "Cannot parse URI");
- goto cleanup;
- }
-
- if (p11_kit_uri_any_unrecognized(uri)) {
- PyErr_SetString(ipap11helperError, "PKCS#11 URI contains "
- "unsupported attributes");
- goto cleanup;
- }
-
- *urip = uri;
- return 1;
-
-cleanup:
- p11_kit_uri_free(uri);
- return 0;
-}
-
-/*
- * Find keys matching specified template.
- * Function returns list of key handles via objects parameter.
- *
- * :param template: PKCS#11 template for attribute matching
- * :param objects: found objects, NULL if no objects fit criteria
- * :param objects_count: number of objects in objects array
- * :return: 1 if success, otherwise return 0 and set the exception
- */
-int _find_key(P11_Helper *self, CK_ATTRIBUTE_PTR template,
- CK_ULONG template_len, CK_OBJECT_HANDLE **objects,
- unsigned int *objects_count) {
- CK_OBJECT_HANDLE result_object;
- CK_ULONG objectCount;
- CK_OBJECT_HANDLE *result_objects = NULL;
- CK_OBJECT_HANDLE *tmp_objects_ptr = NULL;
- unsigned int count = 0;
- unsigned int allocated = 0;
- CK_RV rv;
-
- rv = self->p11->C_FindObjectsInit(self->session, template, template_len);
- if (!check_return_value(rv, "Find key init"))
- return 0;
-
- rv = self->p11->C_FindObjects(self->session, &result_object, 1,
- &objectCount);
- if (!check_return_value(rv, "Find key"))
- return 0;
-
- while (objectCount > 0) {
- if (allocated <= count) {
- allocated += 32;
- tmp_objects_ptr = (CK_OBJECT_HANDLE*) realloc(result_objects,
- allocated * sizeof(CK_OBJECT_HANDLE));
- if (tmp_objects_ptr == NULL) {
- *objects_count = 0;
- PyErr_SetString(ipap11helperError, "_find_key realloc failed");
- free(result_objects);
- return 0;
- } else {
- result_objects = tmp_objects_ptr;
- }
- }
- result_objects[count] = result_object;
- count++;
- rv = self->p11->C_FindObjects(self->session, &result_object, 1,
- &objectCount);
- if (!check_return_value(rv, "Check for duplicated key")) {
- free(result_objects);
- return 0;
- }
- }
-
- rv = self->p11->C_FindObjectsFinal(self->session);
- if (!check_return_value(rv, "Find objects final")) {
- free(result_objects);
- return 0;
- }
-
- *objects = result_objects;
- *objects_count = count;
- return 1;
-}
-
-/*
- * Test if object with specified label, id and class exists
- *
- * :param id: key ID, (if value is NULL, will not be used to find key)
- * :param id_len: key ID length
- * :param label key: label (if value is NULL, will not be used to find key)
- * :param label_len: key label length
- * :param class key: class
-
- * :return: 1 if object was found, 0 if object doesnt exists, -1 if error
- * and set the exception
- *
- */
-int _id_exists(P11_Helper *self, CK_BYTE_PTR id, CK_ULONG id_len,
- CK_OBJECT_CLASS class) {
-
- CK_RV rv;
- CK_ULONG object_count = 0;
- CK_OBJECT_HANDLE result_object = 0;
- CK_OBJECT_CLASS class_sec = CKO_SECRET_KEY;
-
- CK_ATTRIBUTE template_pub_priv[] = {
- { CKA_ID, id, id_len },
- { CKA_CLASS, &class, sizeof(CK_OBJECT_CLASS) }
- };
-
- CK_ATTRIBUTE template_sec[] = {
- { CKA_ID, id, id_len },
- { CKA_CLASS, &class_sec, sizeof(CK_OBJECT_CLASS) }
- };
-
- CK_ATTRIBUTE template_id[] = {
- { CKA_ID, id, id_len }
- };
-
- /*
- * Only one secret key with same ID is allowed
- */
- if (class == CKO_SECRET_KEY) {
- rv = self->p11->C_FindObjectsInit(self->session, template_id, 1);
- if (!check_return_value(rv, "id, label exists init"))
- return -1;
-
- rv = self->p11->C_FindObjects(self->session, &result_object, 1,
- &object_count);
- if (!check_return_value(rv, "id, label exists"))
- return -1;
-
- rv = self->p11->C_FindObjectsFinal(self->session);
- if (!check_return_value(rv, "id, label exists final"))
- return -1;
-
- if (object_count > 0) {
- /* object found */
- return 1;
- }
- return 0;
- }
-
- /*
- * Public and private keys can share one ID, but
- */
-
- /* test if secret key with same ID exists */
- rv = self->p11->C_FindObjectsInit(self->session, template_sec, 2);
- if (!check_return_value(rv, "id, label exists init"))
- return -1;
-
- rv = self->p11->C_FindObjects(self->session, &result_object, 1,
- &object_count);
- if (!check_return_value(rv, "id, label exists"))
- return -1;
-
- rv = self->p11->C_FindObjectsFinal(self->session);
- if (!check_return_value(rv, "id, label exists final"))
- return -1;
-
- if (object_count > 0) {
- /* object found */
- return 1;
- }
-
- /* test if pub/private key with same id exists */
- object_count = 0;
-
- rv = self->p11->C_FindObjectsInit(self->session, template_pub_priv, 2);
- if (!check_return_value(rv, "id, label exists init"))
- return -1;
-
- rv = self->p11->C_FindObjects(self->session, &result_object, 1,
- &object_count);
- if (!check_return_value(rv, "id, label exists"))
- return -1;
-
- rv = self->p11->C_FindObjectsFinal(self->session);
- if (!check_return_value(rv, "id, label exists final"))
- return -1;
-
- if (object_count > 0) {
- return 1; /* Object found*/
- }
-
- return 0; /* Object not found*/
-}
-
-/*
- * Function set default param values for wrapping mechanism
- * :param mech_type: mechanism type
- * :param mech: filled structure with params based on mech type
- *
- * :return: 1 if sucessfull, 0 if error (fill proper exception)
- *
- * Warning: do not dealloc param values, it is static variables
- */
-int _set_wrapping_mech_parameters(CK_MECHANISM_TYPE mech_type,
- CK_MECHANISM *mech) {
- switch (mech_type) {
- case CKM_RSA_PKCS:
- case CKM_AES_KEY_WRAP:
- case CKM_AES_KEY_WRAP_PAD:
- mech->pParameter = NULL;
- mech->ulParameterLen = 0;
- break;
-
- case CKM_RSA_PKCS_OAEP:
- /* Use the same configuration as openSSL
- * https://www.openssl.org/docs/crypto/RSA_public_encrypt.html
- */
- mech->pParameter = (void *) &CONST_RSA_PKCS_OAEP_PARAMS;
- mech->ulParameterLen = sizeof(CONST_RSA_PKCS_OAEP_PARAMS);
- break;
-
- default:
- PyErr_SetString(ipap11helperError,
- "Unsupported wrapping mechanism");
- return 0;
- }
- mech->mechanism = mech_type;
- return 1;
-}
-
-
-/***********************************************************************
- * P11_Helper object
- */
-
-static void P11_Helper_dealloc(P11_Helper *self) {
- Py_TYPE(self)->tp_free((PyObject *) self);
-}
-
-static PyObject *P11_Helper_new(PyTypeObject *type, PyObject *args,
- PyObject *kwds) {
- P11_Helper *self;
-
- self = (P11_Helper *) type->tp_alloc(type, 0);
- if (self != NULL) {
-
- self->slot = 0;
- self->session = 0;
- self->p11 = NULL;
- self->module_handle = NULL;
- }
-
- return (PyObject *) self;
-}
-
-static int P11_Helper_init(P11_Helper *self, PyObject *args, PyObject *kwds) {
- const char *user_pin = NULL;
- const char *library_path = NULL;
- CK_RV rv;
- void *module_handle = NULL;
-
- /* Parse method args */
- if (!PyArg_ParseTuple(args, "iss", &self->slot, &user_pin, &library_path))
- return -1;
-
- CK_C_GetFunctionList pGetFunctionList = loadLibrary(library_path,
- &module_handle);
- if (!pGetFunctionList) {
- PyErr_SetString(ipap11helperError, "Could not load the library.");
- return -1;
- }
-
- self->module_handle = module_handle;
-
- /*
- * Load the function list
- */
- (*pGetFunctionList)(&self->p11);
-
- /*
- * Initialize
- */
- rv = self->p11->C_Initialize(NULL);
- if (!check_return_value(rv, "initialize"))
- return -1;
-
- /*
- *Start session
- */
- rv = self->p11->C_OpenSession(self->slot,
- CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL,
- NULL, &self->session);
- if (!check_return_value(rv, "open session"))
- return -1;
-
- /*
- * Login
- */
- rv = self->p11->C_Login(self->session, CKU_USER, (CK_BYTE *) user_pin,
- strlen((char *) user_pin));
- if (!check_return_value(rv, "log in"))
- return -1;
-
- return 0;
-}
-
-static PyMemberDef P11_Helper_members[] = {
- { NULL } /* Sentinel */
-};
-
-/*
- * Finalize operations with pkcs11 library
- */
-static PyObject *P11_Helper_finalize(P11_Helper *self) {
- CK_RV rv;
-
- if (self->p11 == NULL)
- Py_RETURN_NONE;
-
- /*
- * Logout
- */
- rv = self->p11->C_Logout(self->session);
- if (rv != CKR_USER_NOT_LOGGED_IN) {
- if (!check_return_value(rv, "log out"))
- return NULL;
- }
-
- /*
- * End session
- */
- rv = self->p11->C_CloseSession(self->session);
- if (!check_return_value(rv, "close session"))
- return NULL;
-
- /*
- * Finalize
- */
- self->p11->C_Finalize(NULL);
-
- unloadLibrary(self->module_handle);
-
- self->p11 = NULL;
- self->session = 0;
- self->slot = 0;
- self->module_handle = NULL;
-
- Py_RETURN_NONE;
-}
-
-/********************************************************************
- * Methods working with keys
- */
-
-/**
- * Generate master key
- *
- *:return: master key handle
- */
-static PyObject *P11_Helper_generate_master_key(P11_Helper *self,
- PyObject *args,
- PyObject *kwds) {
- PyObj2Bool_mapping_t attrs[] = {
- { NULL, &true }, // sec_en_cka_copyable
- { NULL, &false }, // sec_en_cka_decrypt
- { NULL, &false }, // sec_en_cka_derive
- { NULL, &false }, // sec_en_cka_encrypt
- { NULL, &true }, // sec_en_cka_extractable
- { NULL, &true }, // sec_en_cka_modifiable
- { NULL, &true }, // sec_en_cka_private
- { NULL, &true }, // sec_en_cka_sensitive
- { NULL, &false }, // sec_en_cka_sign
- { NULL, &true }, // sec_en_cka_unwrap
- { NULL, &false }, // sec_en_cka_verify
- { NULL, &true }, // sec_en_cka_wrap
- { NULL, &false } // sec_en_cka_wrap_with_trusted
- };
-
- CK_ULONG key_length = 16;
- CK_RV rv;
- CK_OBJECT_HANDLE master_key;
- CK_BYTE *id = NULL;
- int id_length = 0;
-
- PyObject *label_unicode = NULL;
- Py_ssize_t label_length = 0;
- CK_BYTE *label = NULL;
- int r;
- int error = 0;
- static char *kwlist[] = { "subject", "id", "key_length", "cka_copyable",
- "cka_decrypt", "cka_derive", "cka_encrypt", "cka_extractable",
- "cka_modifiable", "cka_private", "cka_sensitive", "cka_sign",
- "cka_unwrap", "cka_verify", "cka_wrap", "cka_wrap_with_trusted",
- NULL
- };
- //TODO check long overflow
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "Us#|kOOOOOOOOOOOOO", kwlist,
- &label_unicode, &id, &id_length,
- &key_length,
- &attrs[sec_en_cka_copyable].py_obj,
- &attrs[sec_en_cka_decrypt].py_obj,
- &attrs[sec_en_cka_derive].py_obj,
- &attrs[sec_en_cka_encrypt].py_obj,
- &attrs[sec_en_cka_extractable].py_obj,
- &attrs[sec_en_cka_modifiable].py_obj,
- &attrs[sec_en_cka_private].py_obj,
- &attrs[sec_en_cka_sensitive].py_obj,
- &attrs[sec_en_cka_sign].py_obj,
- &attrs[sec_en_cka_unwrap].py_obj,
- &attrs[sec_en_cka_verify].py_obj,
- &attrs[sec_en_cka_wrap].py_obj,
- &attrs
- [sec_en_cka_wrap_with_trusted].py_obj)) {
- return NULL;
- }
-
- label = (unsigned char *) unicode_to_char_array(label_unicode,
- &label_length);
- if (label == NULL)
- GOTO_FAIL;
-
- CK_MECHANISM mechanism = { //TODO param?
- CKM_AES_KEY_GEN, NULL_PTR, 0
- };
-
- if ((key_length != 16) && (key_length != 24) && (key_length != 32)) {
- PyErr_SetString(ipap11helperError,
- "generate_master_key: key length allowed values are: 16, 24 and 32");
- GOTO_FAIL;
- }
-
- r = _id_exists(self, id, id_length, CKO_SECRET_KEY);
- if (r == 1) {
- PyErr_SetString(ipap11helperDuplicationError,
- "Master key with same ID already exists");
- GOTO_FAIL;
- } else if (r == -1) {
- GOTO_FAIL;
- }
-
- /* Process keyword boolean arguments */
- convert_py2bool(attrs, sizeof(attrs) / sizeof(PyObj2Bool_mapping_t));
-
- CK_ATTRIBUTE symKeyTemplate[] = {
- { CKA_ID, id, id_length },
- { CKA_LABEL, label, label_length },
- { CKA_TOKEN, &true, sizeof(CK_BBOOL) },
- { CKA_VALUE_LEN, &key_length, sizeof(key_length) },
- //{ CKA_COPYABLE, attrs[sec_en_cka_copyable].bool, sizeof(CK_BBOOL) }, //TODO Softhsm doesn't support it
- { CKA_DECRYPT, attrs[sec_en_cka_decrypt].bool, sizeof(CK_BBOOL) },
- { CKA_DERIVE, attrs[sec_en_cka_derive].bool, sizeof(CK_BBOOL) },
- { CKA_ENCRYPT, attrs[sec_en_cka_encrypt].bool, sizeof(CK_BBOOL) },
- { CKA_EXTRACTABLE, attrs[sec_en_cka_extractable].bool, sizeof(CK_BBOOL) },
- { CKA_MODIFIABLE, attrs[sec_en_cka_modifiable].bool, sizeof(CK_BBOOL) },
- { CKA_PRIVATE, attrs[sec_en_cka_private].bool, sizeof(CK_BBOOL) },
- { CKA_SENSITIVE, attrs[sec_en_cka_sensitive].bool, sizeof(CK_BBOOL) },
- { CKA_SIGN, attrs[sec_en_cka_sign].bool, sizeof(CK_BBOOL) },
- { CKA_UNWRAP, attrs[sec_en_cka_unwrap].bool, sizeof(CK_BBOOL) },
- { CKA_VERIFY, attrs[sec_en_cka_verify].bool, sizeof(CK_BBOOL) },
- { CKA_WRAP, attrs[sec_en_cka_wrap].bool, sizeof(CK_BBOOL) },
- { CKA_WRAP_WITH_TRUSTED, attrs[sec_en_cka_wrap_with_trusted].bool, sizeof(CK_BBOOL) }
- };
-
- rv = self->p11->C_GenerateKey(self->session, &mechanism, symKeyTemplate,
- sizeof(symKeyTemplate) /
- sizeof(CK_ATTRIBUTE), &master_key);
- if (!check_return_value(rv, "generate master key")) {
- GOTO_FAIL;
- }
-final:
- if (label != NULL)
- PyMem_Free(label);
-
- if (error)
- return NULL;
- return Py_BuildValue("k", master_key);
-}
-
-/**
- * Generate replica keys
- *
- * :returns: tuple (public_key_handle, private_key_handle)
- */
-static PyObject *P11_Helper_generate_replica_key_pair(P11_Helper *self,
- PyObject *args,
- PyObject *kwds) {
- CK_RV rv;
- int r;
- CK_ULONG modulus_bits = 2048;
- CK_BYTE *id = NULL;
- int id_length = 0;
- PyObject *label_unicode = NULL;
- Py_ssize_t label_length = 0;
- CK_BYTE *label = NULL;
- int error = 0;
-
- PyObj2Bool_mapping_t attrs_pub[] = {
- { NULL, &true }, // pub_en_cka_copyable
- { NULL, &false }, // pub_en_cka_derive
- { NULL, &false }, // pub_en_cka_encrypt
- { NULL, &true }, // pub_en_cka_modifiable
- { NULL, &true }, // pub_en_cka_private
- { NULL, &false }, // pub_en_cka_trusted
- { NULL, &false }, // pub_en_cka_verify
- { NULL, &false }, // pub_en_cka_verify_recover
- { NULL, &true }, // pub_en_cka_wrap
- };
-
- PyObj2Bool_mapping_t attrs_priv[] = {
- { NULL, &false }, // priv_en_cka_always_authenticate
- { NULL, &true }, // priv_en_cka_copyable
- { NULL, &false }, // priv_en_cka_decrypt
- { NULL, &false }, // priv_en_cka_derive
- { NULL, &false }, // priv_en_cka_extractable
- { NULL, &true }, // priv_en_cka_modifiable
- { NULL, &true }, // priv_en_cka_private
- { NULL, &true }, // priv_en_cka_sensitive
- { NULL, &false }, // priv_en_cka_sign
- { NULL, &false }, // priv_en_cka_sign_recover
- { NULL, &true }, // priv_en_cka_unwrap
- { NULL, &false } // priv_en_cka_wrap_with_trusted
- };
-
- static char *kwlist[] = { "label", "id", "modulus_bits",
- /* public key kw */
- "pub_cka_copyable", "pub_cka_derive", "pub_cka_encrypt",
- "pub_cka_modifiable", "pub_cka_private", "pub_cka_trusted",
- "pub_cka_verify", "pub_cka_verify_recover", "pub_cka_wrap",
- /* private key kw */
- "priv_cka_always_authenticate", "priv_cka_copyable",
- "priv_cka_decrypt", "priv_cka_derive", "priv_cka_extractable",
- "priv_cka_modifiable", "priv_cka_private", "priv_cka_sensitive",
- "priv_cka_sign", "priv_cka_sign_recover", "priv_cka_unwrap",
- "priv_cka_wrap_with_trusted", NULL
- };
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "Us#|kOOOOOOOOOOOOOOOOOOOOO",
- kwlist, &label_unicode, &id, &id_length,
- &modulus_bits,
- /* public key kw */
- &attrs_pub[pub_en_cka_copyable].py_obj,
- &attrs_pub[pub_en_cka_derive].py_obj,
- &attrs_pub[pub_en_cka_encrypt].py_obj,
- &attrs_pub[pub_en_cka_modifiable].py_obj,
- &attrs_pub[pub_en_cka_private].py_obj,
- &attrs_pub[pub_en_cka_trusted].py_obj,
- &attrs_pub[pub_en_cka_verify].py_obj,
- &attrs_pub[pub_en_cka_verify_recover].py_obj,
- &attrs_pub[pub_en_cka_wrap].py_obj,
- /* private key kw */
- &attrs_priv[priv_en_cka_always_authenticate].py_obj,
- &attrs_priv[priv_en_cka_copyable].py_obj,
- &attrs_priv[priv_en_cka_decrypt].py_obj,
- &attrs_priv[priv_en_cka_derive].py_obj,
- &attrs_priv[priv_en_cka_extractable].py_obj,
- &attrs_priv[priv_en_cka_modifiable].py_obj,
- &attrs_priv[priv_en_cka_private].py_obj,
- &attrs_priv[priv_en_cka_sensitive].py_obj,
- &attrs_priv[priv_en_cka_sign].py_obj,
- &attrs_priv[priv_en_cka_sign_recover].py_obj,
- &attrs_priv[priv_en_cka_unwrap].py_obj,
- &attrs_priv[priv_en_cka_wrap_with_trusted].py_obj)) {
- return NULL;
- }
-
- label = unicode_to_char_array(label_unicode, &label_length);
- if (label == NULL)
- GOTO_FAIL;
-
- CK_OBJECT_HANDLE public_key, private_key;
- CK_MECHANISM mechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 };
-
- r = _id_exists(self, id, id_length, CKO_PRIVATE_KEY);
- if (r == 1) {
- PyErr_SetString(ipap11helperDuplicationError,
- "Private key with same ID already exists");
- GOTO_FAIL;
- } else if (r == -1)
- GOTO_FAIL;
-
- r = _id_exists(self, id, id_length, CKO_PUBLIC_KEY);
- if (r == 1) {
- PyErr_SetString(ipap11helperDuplicationError,
- "Public key with same ID already exists");
- GOTO_FAIL;
- } else if (r == -1)
- GOTO_FAIL;
-
- /* Process keyword boolean arguments */
- convert_py2bool(attrs_pub,
- sizeof(attrs_pub) / sizeof(PyObj2Bool_mapping_t));
- convert_py2bool(attrs_priv,
- sizeof(attrs_priv) / sizeof(PyObj2Bool_mapping_t));
-
- CK_BYTE public_exponent[] = { 1, 0, 1 }; /* 65537 (RFC 6376 section 3.3.1) */
- CK_ATTRIBUTE publicKeyTemplate[] = {
- { CKA_ID, id, id_length },
- { CKA_LABEL, label, label_length },
- { CKA_TOKEN, &true, sizeof(true) },
- { CKA_MODULUS_BITS, &modulus_bits, sizeof(modulus_bits) },
- { CKA_PUBLIC_EXPONENT, public_exponent, 3 },
- //{ CKA_COPYABLE, attrs_pub[pub_en_cka_copyable].bool, sizeof(CK_BBOOL) }, //TODO Softhsm doesn't support it
- { CKA_DERIVE, attrs_pub[pub_en_cka_derive].bool, sizeof(CK_BBOOL) },
- { CKA_ENCRYPT, attrs_pub[pub_en_cka_encrypt].bool, sizeof(CK_BBOOL) },
- { CKA_MODIFIABLE, attrs_pub[pub_en_cka_modifiable].bool, sizeof(CK_BBOOL) },
- { CKA_PRIVATE, attrs_pub[pub_en_cka_private].bool, sizeof(CK_BBOOL) },
- { CKA_TRUSTED, attrs_pub[pub_en_cka_trusted].bool, sizeof(CK_BBOOL) },
- { CKA_VERIFY, attrs_pub[pub_en_cka_verify].bool, sizeof(CK_BBOOL) },
- { CKA_VERIFY_RECOVER, attrs_pub[pub_en_cka_verify_recover].bool, sizeof(CK_BBOOL) },
- { CKA_WRAP, attrs_pub[pub_en_cka_wrap].bool, sizeof(CK_BBOOL) }, };
-
- CK_ATTRIBUTE privateKeyTemplate[] = {
- { CKA_ID, id, id_length },
- { CKA_LABEL, label, label_length },
- { CKA_TOKEN, &true, sizeof(true) },
- { CKA_ALWAYS_AUTHENTICATE, attrs_priv[priv_en_cka_always_authenticate].bool, sizeof(CK_BBOOL) },
- //{ CKA_COPYABLE, attrs_priv[priv_en_cka_copyable].bool, sizeof(CK_BBOOL) }, //TODO Softhsm doesn't support it
- { CKA_DECRYPT, attrs_priv[priv_en_cka_decrypt].bool, sizeof(CK_BBOOL) },
- { CKA_DERIVE, attrs_priv[priv_en_cka_derive].bool, sizeof(CK_BBOOL) },
- { CKA_EXTRACTABLE, attrs_priv[priv_en_cka_extractable].bool, sizeof(CK_BBOOL) },
- { CKA_MODIFIABLE, attrs_priv[priv_en_cka_modifiable].bool, sizeof(CK_BBOOL) },
- { CKA_PRIVATE, attrs_priv[priv_en_cka_private].bool, sizeof(CK_BBOOL) },
- { CKA_SENSITIVE, attrs_priv[priv_en_cka_sensitive].bool, sizeof(CK_BBOOL) },
- { CKA_SIGN, attrs_priv[priv_en_cka_sign].bool, sizeof(CK_BBOOL) },
- { CKA_SIGN_RECOVER, attrs_priv[priv_en_cka_sign].bool, sizeof(CK_BBOOL) },
- { CKA_UNWRAP, attrs_priv[priv_en_cka_unwrap].bool, sizeof(CK_BBOOL) },
- { CKA_WRAP_WITH_TRUSTED, attrs_priv[priv_en_cka_wrap_with_trusted].bool, sizeof(CK_BBOOL) }
- };
-
- rv = self->p11->C_GenerateKeyPair(self->session, &mechanism,
- publicKeyTemplate,
- sizeof(publicKeyTemplate) / sizeof(CK_ATTRIBUTE),
- privateKeyTemplate,
- sizeof(privateKeyTemplate) / sizeof(CK_ATTRIBUTE),
- &public_key,
- &private_key);
- if (!check_return_value(rv, "generate key pair"))
- GOTO_FAIL;
-
-final:
- if (label != NULL)
- PyMem_Free(label);
-
- if (error)
- return NULL;
- return Py_BuildValue("(kk)", public_key, private_key);
-}
-
-/**
- * Find key
- */
-static PyObject *P11_Helper_find_keys(P11_Helper *self, PyObject *args,
- PyObject *kwds) {
- CK_OBJECT_CLASS class = CKO_VENDOR_DEFINED;
- CK_OBJECT_CLASS *class_ptr = &class;
- CK_BYTE *id = NULL;
- CK_BBOOL *ckawrap = NULL;
- CK_BBOOL *ckaunwrap = NULL;
- int id_length = 0;
- PyObject *label_unicode = NULL;
- PyObject *cka_wrap_bool = NULL;
- PyObject *cka_unwrap_bool = NULL;
- Py_ssize_t label_length = 0;
- CK_OBJECT_HANDLE *objects = NULL;
- unsigned int objects_len = 0;
- PyObject *result_list = NULL;
- const char *uri_str = NULL;
- P11KitUri *uri = NULL;
- CK_BYTE *label = NULL;
- CK_ATTRIBUTE template_static[MAX_TEMPLATE_LEN];
- CK_ATTRIBUTE_PTR template = template_static;
- CK_ULONG template_len = MAX_TEMPLATE_LEN;
- int error = 0;
-
- static char *kwlist[] = { "objclass", "label", "id", "cka_wrap",
- "cka_unwrap", "uri", NULL
- };
- //TODO check long overflow
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iUz#OOs", kwlist, &class,
- &label_unicode, &id, &id_length,
- &cka_wrap_bool, &cka_unwrap_bool,
- &uri_str)) {
- GOTO_FAIL;
- }
-
- if (label_unicode != NULL) {
- label = (unsigned char *) unicode_to_char_array(label_unicode, &label_length); //TODO verify signed/unsigned
- if (label == NULL)
- GOTO_FAIL;
- }
-
- if (cka_wrap_bool != NULL) {
- if (PyObject_IsTrue(cka_wrap_bool)) {
- ckawrap = &true;
- } else {
- ckawrap = &false;
- }
- }
-
- if (cka_unwrap_bool != NULL) {
- if (PyObject_IsTrue(cka_unwrap_bool)) {
- ckaunwrap = &true;
- } else {
- ckaunwrap = &false;
- }
- }
-
- if (class == CKO_VENDOR_DEFINED)
- class_ptr = NULL;
-
- if (uri_str == NULL)
- _fill_template_from_parts(template, &template_len, id, id_length,
- label, label_length, class_ptr, ckawrap,
- ckaunwrap);
- else {
- if (!_parse_uri(uri_str, &uri)) {
- GOTO_FAIL;
- }
- template = p11_kit_uri_get_attributes(uri, &template_len);
- /* Do not deallocate URI while you are using the template.
- * Template contains pointers to values inside URI! */
- }
-
- if (!_find_key(self, template, template_len, &objects, &objects_len)) {
- GOTO_FAIL;
- }
-
- result_list = PyList_New(objects_len);
- if (result_list == NULL) {
- PyErr_SetString(ipap11helperError,
- "Unable to create list with results");
- GOTO_FAIL;
- }
-
- for (int i = 0; i < objects_len; ++i) {
- if (PyList_SetItem(result_list, i, Py_BuildValue("k", objects[i]))
- == -1) {
- PyErr_SetString(ipap11helperError,
- "Unable to add to value to result list");
- Py_DECREF(result_list);
- GOTO_FAIL;
- }
- }
-final:
- if (label != NULL)
- PyMem_Free(label);
- if (objects != NULL)
- free(objects);
- if (uri != NULL)
- p11_kit_uri_free(uri);
-
- if (error)
- return NULL;
- return result_list;
-}
-
-/**
- * delete key
- */
-static PyObject *P11_Helper_delete_key(P11_Helper *self, PyObject *args,
- PyObject *kwds) {
- CK_RV rv;
- CK_OBJECT_HANDLE key_handle = 0;
- static char *kwlist[] = { "key_handle", NULL };
- //TODO check long overflow
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "k|", kwlist, &key_handle)) {
- return NULL;
- }
- rv = self->p11->C_DestroyObject(self->session, key_handle);
- if (!check_return_value(rv, "object deletion")) {
- return NULL;
- }
-
- Py_RETURN_NONE;
-}
-
-/**
- * export RSA public key
- */
-static PyObject *P11_Helper_export_RSA_public_key(P11_Helper *self,
- CK_OBJECT_HANDLE object) {
- CK_RV rv;
- PyObject *ret = NULL;
-
- int pp_len;
- unsigned char *pp = NULL;
- EVP_PKEY *pkey = NULL;
- BIGNUM *e = NULL;
- BIGNUM *n = NULL;
- RSA *rsa = NULL;
- CK_BYTE_PTR modulus = NULL;
- CK_BYTE_PTR exponent = NULL;
- CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
- CK_KEY_TYPE key_type = CKK_RSA;
- int error = 0;
-
- CK_ATTRIBUTE obj_template[] = {
- { CKA_MODULUS, NULL_PTR, 0 },
- { CKA_PUBLIC_EXPONENT, NULL_PTR, 0 },
- { CKA_CLASS, &class, sizeof(class) },
- { CKA_KEY_TYPE, &key_type, sizeof(key_type) }
- };
-
- rv = self->p11->C_GetAttributeValue(self->session, object, obj_template,
- sizeof(obj_template) / sizeof(CK_ATTRIBUTE));
- if (!check_return_value(rv, "get RSA public key values - prepare"))
- GOTO_FAIL;
-
- /* Set proper size for attributes */
- modulus =
- (CK_BYTE_PTR) PyMem_Malloc(obj_template[0].ulValueLen *
- sizeof(CK_BYTE));
- if (modulus == NULL) {
- PyErr_NoMemory();
- GOTO_FAIL;
- }
- obj_template[0].pValue = modulus;
- exponent =
- (CK_BYTE_PTR) PyMem_Malloc(obj_template[1].ulValueLen *
- sizeof(CK_BYTE));
- if (exponent == NULL) {
- PyErr_NoMemory();
- GOTO_FAIL;
- }
- obj_template[1].pValue = exponent;
-
- rv = self->p11->C_GetAttributeValue(self->session, object, obj_template,
- sizeof(obj_template) / sizeof(CK_ATTRIBUTE));
- if (!check_return_value(rv, "get RSA public key values")) {
- GOTO_FAIL;
- }
-
- /* Check if the key is RSA public key */
- if (class != CKO_PUBLIC_KEY) {
- PyErr_SetString(ipap11helperError,
- "export_RSA_public_key: required public key class");
- GOTO_FAIL;
- }
-
- if (key_type != CKK_RSA) {
- PyErr_SetString(ipap11helperError,
- "export_RSA_public_key: required RSA key type");
- GOTO_FAIL;
- }
-
- rsa = RSA_new();
- pkey = EVP_PKEY_new();
- n = BN_bin2bn((const unsigned char *) modulus,
- obj_template[0].ulValueLen * sizeof(CK_BYTE), NULL);
- if (n == NULL) {
- PyErr_SetString(ipap11helperError,
- "export_RSA_public_key: internal error: unable to convert modulus");
- GOTO_FAIL;
- }
-
- e = BN_bin2bn((const unsigned char *) exponent,
- obj_template[1].ulValueLen * sizeof(CK_BYTE), NULL);
- if (e == NULL) {
- PyErr_SetString(ipap11helperError,
- "export_RSA_public_key: internal error: unable to convert exponent");
- GOTO_FAIL;
- }
-
- /* set modulus and exponent */
- rsa->n = n;
- rsa->e = e;
-
- if (EVP_PKEY_set1_RSA(pkey, rsa) == 0) {
- PyErr_SetString(ipap11helperError,
- "export_RSA_public_key: internal error: EVP_PKEY_set1_RSA failed");
- GOTO_FAIL;
- }
-
- pp_len = i2d_PUBKEY(pkey, &pp);
- ret = string_to_pybytes_or_none(pp, pp_len);
-
-final:
- if (rsa != NULL) {
- RSA_free(rsa); // this frees also 'n' and 'e'
- } else {
- if (n != NULL)
- BN_free(n);
- if (e != NULL)
- BN_free(e);
- }
-
- if (pkey != NULL)
- EVP_PKEY_free(pkey);
- if (pp != NULL)
- free(pp);
- if (modulus != NULL)
- PyMem_Free(modulus);
- if (exponent != NULL)
- PyMem_Free(exponent);
-
- if (error)
- return NULL;
- return ret;
-}
-
-/**
- * Export public key
- *
- * Export public key in SubjectPublicKeyInfo (RFC5280) DER encoded format
- */
-static PyObject *P11_Helper_export_public_key(P11_Helper *self,
- PyObject *args, PyObject *kwds) {
- CK_RV rv;
- CK_OBJECT_HANDLE object = 0;
- CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
- CK_KEY_TYPE key_type = CKK_RSA;
- static char *kwlist[] = { "key_handle", NULL };
- //TODO check long overflow
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "k|", kwlist, &object)) {
- return NULL;
- }
-
- CK_ATTRIBUTE obj_template[] = {
- { CKA_CLASS, &class, sizeof(class) },
- { CKA_KEY_TYPE, &key_type, sizeof(key_type) }
- };
-
- rv = self->p11->C_GetAttributeValue(self->session, object, obj_template,
- sizeof(obj_template) / sizeof(CK_ATTRIBUTE));
- if (!check_return_value
- (rv, "export_public_key: get RSA public key values"))
- return NULL;
-
- if (class != CKO_PUBLIC_KEY) {
- PyErr_SetString(ipap11helperError,
- "export_public_key: required public key class");
- return NULL;
- }
-
- switch (key_type) {
- case CKK_RSA:
- return P11_Helper_export_RSA_public_key(self, object);
- break;
- default:
- PyErr_SetString(ipap11helperError,
- "export_public_key: unsupported key type");
- }
-
- return NULL;
-}
-
-/**
- * Import RSA public key
- *
- */
-static PyObject *P11_Helper_import_RSA_public_key(P11_Helper *self,
- CK_UTF8CHAR * label,
- Py_ssize_t label_length,
- CK_BYTE * id,
- Py_ssize_t id_length,
- EVP_PKEY * pkey,
- CK_BBOOL *cka_copyable,
- CK_BBOOL *cka_derive,
- CK_BBOOL *cka_encrypt,
- CK_BBOOL *cka_modifiable,
- CK_BBOOL *cka_private,
- CK_BBOOL *cka_trusted,
- CK_BBOOL *cka_verify,
- CK_BBOOL *cka_verify_recover,
- CK_BBOOL *cka_wrap) {
- CK_RV rv;
- CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
- CK_KEY_TYPE keyType = CKK_RSA;
- CK_BBOOL *cka_token = &true;
- RSA *rsa = NULL;
- CK_BYTE_PTR modulus = NULL;
- int modulus_len = 0;
- CK_BYTE_PTR exponent = NULL;
- int exponent_len = 0;
- int error = 0;
-
- if (pkey->type != EVP_PKEY_RSA) {
- PyErr_SetString(ipap11helperError, "Required RSA public key");
- GOTO_FAIL;
- }
-
- rsa = EVP_PKEY_get1_RSA(pkey);
- if (rsa == NULL) {
- PyErr_SetString(ipap11helperError,
- "import_RSA_public_key: EVP_PKEY_get1_RSA error");
- GOTO_FAIL;
- }
-
- /* convert BIGNUM to binary array */
- modulus = (CK_BYTE_PTR) PyMem_Malloc(BN_num_bytes(rsa->n));
- if (modulus == NULL) {
- PyErr_NoMemory();
- GOTO_FAIL;
- }
- modulus_len = BN_bn2bin(rsa->n, (unsigned char *) modulus);
- if (modulus_len == 0) {
- PyErr_SetString(ipap11helperError,
- "import_RSA_public_key: BN_bn2bin modulus error");
- GOTO_FAIL;
- }
-
- exponent = (CK_BYTE_PTR) PyMem_Malloc(BN_num_bytes(rsa->e));
- if (exponent == NULL) {
- PyErr_NoMemory();
- GOTO_FAIL;
- }
- exponent_len = BN_bn2bin(rsa->e, (unsigned char *) exponent);
- if (exponent_len == 0) {
- PyErr_SetString(ipap11helperError,
- "import_RSA_public_key: BN_bn2bin exponent error");
- GOTO_FAIL;
- }
-
- CK_ATTRIBUTE template[] = {
- { CKA_ID, id, id_length },
- { CKA_CLASS, &class, sizeof(class) },
- { CKA_KEY_TYPE, &keyType, sizeof(keyType) },
- { CKA_TOKEN, cka_token, sizeof(CK_BBOOL) },
- { CKA_LABEL, label, label_length },
- { CKA_MODULUS, modulus, modulus_len },
- { CKA_PUBLIC_EXPONENT, exponent, exponent_len },
- //{ CKA_COPYABLE, cka_copyable, sizeof(CK_BBOOL) }, //TODO Softhsm doesn't support it
- { CKA_DERIVE, cka_derive, sizeof(CK_BBOOL) },
- { CKA_ENCRYPT, cka_encrypt, sizeof(CK_BBOOL) },
- { CKA_MODIFIABLE, cka_modifiable, sizeof(CK_BBOOL) },
- { CKA_PRIVATE, cka_private, sizeof(CK_BBOOL) },
- { CKA_TRUSTED, cka_trusted, sizeof(CK_BBOOL) },
- { CKA_VERIFY, cka_verify, sizeof(CK_BBOOL) },
- { CKA_VERIFY_RECOVER, cka_verify_recover, sizeof(CK_BBOOL) },
- { CKA_WRAP, cka_wrap, sizeof(CK_BBOOL) }
- };
- CK_OBJECT_HANDLE object;
-
- rv = self->p11->C_CreateObject(self->session, template,
- sizeof(template) / sizeof(CK_ATTRIBUTE),
- &object);
- if (!check_return_value(rv, "create public key object"))
- GOTO_FAIL;
-
-final:
- if (rsa != NULL)
- RSA_free(rsa);
- if (modulus != NULL)
- PyMem_Free(modulus);
- if (exponent != NULL)
- PyMem_Free(exponent);
-
- if (error)
- return NULL;
- return Py_BuildValue("k", object);
-}
-
-/**
- * Import RSA public key
- *
- */
-static PyObject *P11_Helper_import_public_key(P11_Helper *self,
- PyObject *args, PyObject *kwds) {
- int r;
- PyObject *ret = NULL;
- PyObject *label_unicode = NULL;
- CK_BYTE *id = NULL;
- CK_BYTE *data = NULL;
- CK_UTF8CHAR *label = NULL;
- Py_ssize_t id_length = 0;
- Py_ssize_t data_length = 0;
- Py_ssize_t label_length = 0;
- EVP_PKEY *pkey = NULL;
- int error = 0;
-
- PyObj2Bool_mapping_t attrs_pub[] = {
- { NULL, &true }, // pub_en_cka_copyable
- { NULL, &false }, // pub_en_cka_derive
- { NULL, &false }, // pub_en_cka_encrypt
- { NULL, &true }, // pub_en_cka_modifiable
- { NULL, &true }, // pub_en_cka_private
- { NULL, &false }, // pub_en_cka_trusted
- { NULL, &true }, // pub_en_cka_verify
- { NULL, &true }, // pub_en_cka_verify_recover
- { NULL, &false }, // pub_en_cka_wrap
- };
-
- static char *kwlist[] = { "label", "id", "data",
- /* public key attributes */
- "cka_copyable", "cka_derive", "cka_encrypt", "cka_modifiable",
- "cka_private", "cka_trusted", "cka_verify", "cka_verify_recover",
- "cka_wrap", NULL
- };
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "Us#s#|OOOOOOOOO", kwlist,
- &label_unicode, &id, &id_length, &data,
- &data_length,
- /* public key attributes */
- &attrs_pub[pub_en_cka_copyable].py_obj,
- &attrs_pub[pub_en_cka_derive].py_obj,
- &attrs_pub[pub_en_cka_encrypt].py_obj,
- &attrs_pub[pub_en_cka_modifiable].py_obj,
- &attrs_pub[pub_en_cka_private].py_obj,
- &attrs_pub[pub_en_cka_trusted].py_obj,
- &attrs_pub[pub_en_cka_verify].py_obj,
- &attrs_pub[pub_en_cka_verify_recover].py_obj,
- &attrs_pub[pub_en_cka_wrap].py_obj)) {
- return NULL;
- }
-
- label = (unsigned char *) unicode_to_char_array(label_unicode,
- &label_length);
- if (label == NULL)
- GOTO_FAIL;
-
- r = _id_exists(self, id, id_length, CKO_PUBLIC_KEY);
- if (r == 1) {
- PyErr_SetString(ipap11helperDuplicationError,
- "Public key with same ID already exists");
- GOTO_FAIL;
- } else if (r == -1) {
- GOTO_FAIL;
- }
-
- /* Process keyword boolean arguments */
- convert_py2bool(attrs_pub,
- sizeof(attrs_pub) / sizeof(PyObj2Bool_mapping_t));
-
- /* decode from ASN1 DER */
- pkey = d2i_PUBKEY(NULL, (const unsigned char **) &data, data_length);
- if (pkey == NULL) {
- PyErr_SetString(ipap11helperError,
- "import_public_key: d2i_PUBKEY error");
- GOTO_FAIL;
- }
- switch (pkey->type) {
- case EVP_PKEY_RSA:
- ret = P11_Helper_import_RSA_public_key(self, label, label_length,
- id, id_length, pkey,
- attrs_pub[pub_en_cka_copyable].bool,
- attrs_pub[pub_en_cka_derive].bool,
- attrs_pub[pub_en_cka_encrypt].bool,
- attrs_pub[pub_en_cka_modifiable].bool,
- attrs_pub[pub_en_cka_private].bool,
- attrs_pub[pub_en_cka_trusted].bool,
- attrs_pub[pub_en_cka_verify].bool,
- attrs_pub[pub_en_cka_verify_recover].bool,
- attrs_pub[pub_en_cka_wrap].bool);
- break;
- case EVP_PKEY_DSA:
- error = 1;
- PyErr_SetString(ipap11helperError, "DSA is not supported");
- break;
- case EVP_PKEY_EC:
- error = 1;
- PyErr_SetString(ipap11helperError, "EC is not supported");
- break;
- default:
- error = 1;
- PyErr_SetString(ipap11helperError, "Unsupported key type");
- }
-final:
- if (pkey != NULL)
- EVP_PKEY_free(pkey);
- if (label != NULL)
- PyMem_Free(label);
-
- if (error)
- return NULL;
- return ret;
-}
-
-/**
- * Export wrapped key
- *
- */
-static PyObject *P11_Helper_export_wrapped_key(P11_Helper *self,
- PyObject *args,
- PyObject *kwds) {
- CK_RV rv;
- CK_OBJECT_HANDLE object_key = 0;
- CK_OBJECT_HANDLE object_wrapping_key = 0;
- CK_BYTE_PTR wrapped_key = NULL;
- CK_ULONG wrapped_key_len = 0;
- CK_MECHANISM wrapping_mech = { CKM_RSA_PKCS, NULL, 0 };
- /* currently we don't support parameter in mechanism */
- PyObject *result = NULL;
- int error = 0;
-
- static char *kwlist[] = { "key", "wrapping_key", "wrapping_mech", NULL };
- //TODO check long overflow
- //TODO export method
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "kkk|", kwlist, &object_key,
- &object_wrapping_key,
- &wrapping_mech.mechanism))
- GOTO_FAIL;
-
- // fill mech parameters
- if (!_set_wrapping_mech_parameters(wrapping_mech.mechanism, &wrapping_mech))
- GOTO_FAIL;
-
- rv = self->p11->C_WrapKey(self->session, &wrapping_mech,
- object_wrapping_key, object_key, NULL,
- &wrapped_key_len);
- if (!check_return_value(rv, "key wrapping: get buffer length"))
- GOTO_FAIL;
-
- wrapped_key = PyMem_Malloc(wrapped_key_len);
- if (wrapped_key == NULL) {
- PyErr_NoMemory();
- GOTO_FAIL;
- }
-
- rv = self->p11->C_WrapKey(self->session, &wrapping_mech,
- object_wrapping_key, object_key, wrapped_key,
- &wrapped_key_len);
- if (!check_return_value(rv, "key wrapping: wrapping"))
- GOTO_FAIL;
-
- result = string_to_pybytes_or_none(wrapped_key, wrapped_key_len);
-
-final:
- if (wrapped_key != NULL)
- PyMem_Free(wrapped_key);
-
- if (error)
- return NULL;
- return result;
-
-}
-
-/**
- * Import wrapped secret key
- *
- */
-static PyObject *P11_Helper_import_wrapped_secret_key(P11_Helper *self,
- PyObject *args,
- PyObject *kwds) {
- CK_RV rv;
- int r;
- CK_BYTE_PTR wrapped_key = NULL;
- CK_ULONG wrapped_key_len = 0;
- CK_ULONG unwrapping_key_object = 0;
- CK_OBJECT_HANDLE unwrapped_key_object = 0;
- PyObject *label_unicode = NULL;
- CK_BYTE *id = NULL;
- CK_UTF8CHAR *label = NULL;
- Py_ssize_t id_length = 0;
- Py_ssize_t label_length = 0;
- CK_MECHANISM wrapping_mech = { CKM_RSA_PKCS, NULL, 0 };
- CK_OBJECT_CLASS key_class = CKO_SECRET_KEY;
- CK_KEY_TYPE key_type = CKK_RSA;
- int error = 0;
-
- PyObj2Bool_mapping_t attrs[] = {
- { NULL, &true }, // sec_en_cka_copyable
- { NULL, &false }, // sec_en_cka_decrypt
- { NULL, &false }, // sec_en_cka_derive
- { NULL, &false }, // sec_en_cka_encrypt
- { NULL, &true }, // sec_en_cka_extractable
- { NULL, &true }, // sec_en_cka_modifiable
- { NULL, &true }, // sec_en_cka_private
- { NULL, &true }, // sec_en_cka_sensitive
- { NULL, &false }, // sec_en_cka_sign
- { NULL, &true }, // sec_en_cka_unwrap
- { NULL, &false }, // sec_en_cka_verify
- { NULL, &true }, // sec_en_cka_wrap
- { NULL, &false } // sec_en_cka_wrap_with_trusted
- };
-
- static char *kwlist[] = { "label", "id", "data", "unwrapping_key",
- "wrapping_mech", "key_type",
- // secret key attrs
- "cka_copyable", "cka_decrypt", "cka_derive", "cka_encrypt",
- "cka_extractable", "cka_modifiable", "cka_private", "cka_sensitive",
- "cka_sign", "cka_unwrap", "cka_verify", "cka_wrap",
- "cka_wrap_with_trusted", NULL
- };
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "Us#s#kkk|OOOOOOOOOOOOO",
- kwlist, &label_unicode, &id, &id_length,
- &wrapped_key, &wrapped_key_len,
- &unwrapping_key_object,
- &wrapping_mech.mechanism, &key_type,
- // secret key attrs
- &attrs[sec_en_cka_copyable].py_obj,
- &attrs[sec_en_cka_decrypt].py_obj,
- &attrs[sec_en_cka_derive].py_obj,
- &attrs[sec_en_cka_encrypt].py_obj,
- &attrs[sec_en_cka_extractable].py_obj,
- &attrs[sec_en_cka_modifiable].py_obj,
- &attrs[sec_en_cka_private].py_obj,
- &attrs[sec_en_cka_sensitive].py_obj,
- &attrs[sec_en_cka_sign].py_obj,
- &attrs[sec_en_cka_unwrap].py_obj,
- &attrs[sec_en_cka_verify].py_obj,
- &attrs[sec_en_cka_wrap].py_obj,
- &attrs[sec_en_cka_wrap_with_trusted].py_obj)) {
- return NULL;
- }
-
- if (!_set_wrapping_mech_parameters(wrapping_mech.mechanism, &wrapping_mech))
- return NULL;
-
- label = (unsigned char *) unicode_to_char_array(label_unicode,
- &label_length);
- if (label == NULL)
- GOTO_FAIL;
-
- r = _id_exists(self, id, id_length, key_class);
- if (r == 1) {
- PyErr_SetString(ipap11helperDuplicationError,
- "Secret key with same ID already exists");
- GOTO_FAIL;
-
- } else if (r == -1)
- GOTO_FAIL;
-
-
- /* Process keyword boolean arguments */
- convert_py2bool(attrs, sizeof(attrs) / sizeof(PyObj2Bool_mapping_t));
-
- CK_ATTRIBUTE template[] = {
- { CKA_CLASS, &key_class, sizeof(key_class) },
- { CKA_KEY_TYPE, &key_type, sizeof(key_type) },
- { CKA_ID, id, id_length },
- { CKA_LABEL, label, label_length },
- { CKA_TOKEN, &true, sizeof(CK_BBOOL) },
- //{ CKA_COPYABLE, attrs[sec_en_cka_copyable].bool, sizeof(CK_BBOOL) }, //TODO Softhsm doesn't support it
- { CKA_DECRYPT, attrs[sec_en_cka_decrypt].bool, sizeof(CK_BBOOL) },
- { CKA_DERIVE, attrs[sec_en_cka_derive].bool, sizeof(CK_BBOOL) },
- { CKA_ENCRYPT, attrs[sec_en_cka_encrypt].bool, sizeof(CK_BBOOL) },
- { CKA_EXTRACTABLE, attrs[sec_en_cka_extractable].bool, sizeof(CK_BBOOL) },
- { CKA_MODIFIABLE, attrs[sec_en_cka_modifiable].bool, sizeof(CK_BBOOL) },
- { CKA_PRIVATE, attrs[sec_en_cka_private].bool, sizeof(CK_BBOOL) },
- { CKA_SENSITIVE, attrs[sec_en_cka_sensitive].bool, sizeof(CK_BBOOL) },
- { CKA_SIGN, attrs[sec_en_cka_sign].bool, sizeof(CK_BBOOL) },
- { CKA_UNWRAP, attrs[sec_en_cka_unwrap].bool, sizeof(CK_BBOOL) },
- { CKA_VERIFY, attrs[sec_en_cka_verify].bool, sizeof(CK_BBOOL) },
- { CKA_WRAP, attrs[sec_en_cka_wrap].bool, sizeof(CK_BBOOL) },
- { CKA_WRAP_WITH_TRUSTED, attrs[sec_en_cka_wrap_with_trusted].bool, sizeof(CK_BBOOL) }
- };
-
- rv = self->p11->C_UnwrapKey(self->session, &wrapping_mech,
- unwrapping_key_object, wrapped_key,
- wrapped_key_len, template,
- sizeof(template) / sizeof(CK_ATTRIBUTE),
- &unwrapped_key_object);
- if (!check_return_value(rv, "import_wrapped_key: key unwrapping"))
- GOTO_FAIL;
-
-final:
- if (label != NULL)
- PyMem_Free(label);
-
- if (error)
- return NULL;
-
- return Py_BuildValue("k", unwrapped_key_object);
-}
-
-/**
- * Import wrapped private key
- *
- */
-static PyObject *P11_Helper_import_wrapped_private_key(P11_Helper *self,
- PyObject *args,
- PyObject *kwds) {
- CK_RV rv;
- int r;
- CK_BYTE_PTR wrapped_key = NULL;
- CK_ULONG wrapped_key_len = 0;
- CK_ULONG unwrapping_key_object = 0;
- CK_OBJECT_HANDLE unwrapped_key_object = 0;
- PyObject *label_unicode = NULL;
- CK_BYTE *id = NULL;
- CK_UTF8CHAR *label = NULL;
- Py_ssize_t id_length = 0;
- Py_ssize_t label_length = 0;
- CK_MECHANISM wrapping_mech = { CKM_RSA_PKCS, NULL, 0 };
- CK_OBJECT_CLASS key_class = CKO_PRIVATE_KEY;
- CK_KEY_TYPE key_type = CKK_RSA;
- int error = 0;
-
- PyObj2Bool_mapping_t attrs_priv[] = {
- { NULL, &false }, // priv_en_cka_always_authenticate
- { NULL, &true }, // priv_en_cka_copyable
- { NULL, &false }, // priv_en_cka_decrypt
- { NULL, &false }, // priv_en_cka_derive
- { NULL, &true }, // priv_en_cka_extractable
- { NULL, &true }, // priv_en_cka_modifiable
- { NULL, &true }, // priv_en_cka_private
- { NULL, &true }, // priv_en_cka_sensitive
- { NULL, &true }, // priv_en_cka_sign
- { NULL, &true }, // priv_en_cka_sign_recover
- { NULL, &false }, // priv_en_cka_unwrap
- { NULL, &false } // priv_en_cka_wrap_with_trusted
- };
-
- static char *kwlist[] = { "label", "id", "data", "unwrapping_key",
- "wrapping_mech", "key_type",
- // private key attrs
- "cka_always_authenticate", "cka_copyable", "cka_decrypt",
- "cka_derive", "cka_extractable", "cka_modifiable", "cka_private",
- "cka_sensitive", "cka_sign", "cka_sign_recover", "cka_unwrap",
- "cka_wrap_with_trusted", NULL
- };
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "Us#s#kkk|OOOOOOOOOOOO",
- kwlist, &label_unicode, &id, &id_length,
- &wrapped_key, &wrapped_key_len,
- &unwrapping_key_object,
- &wrapping_mech.mechanism, &key_type,
- // private key attrs
- &attrs_priv[priv_en_cka_always_authenticate].py_obj,
- &attrs_priv[priv_en_cka_copyable].py_obj,
- &attrs_priv[priv_en_cka_decrypt].py_obj,
- &attrs_priv[priv_en_cka_derive].py_obj,
- &attrs_priv[priv_en_cka_extractable].py_obj,
- &attrs_priv[priv_en_cka_modifiable].py_obj,
- &attrs_priv[priv_en_cka_private].py_obj,
- &attrs_priv[priv_en_cka_sensitive].py_obj,
- &attrs_priv[priv_en_cka_sign].py_obj,
- &attrs_priv[priv_en_cka_sign_recover].py_obj,
- &attrs_priv[priv_en_cka_unwrap].py_obj,
- &attrs_priv[priv_en_cka_wrap_with_trusted].py_obj)) {
- return NULL;
- }
-
- label = (unsigned char *) unicode_to_char_array(label_unicode,
- &label_length);
- if (label == NULL)
- GOTO_FAIL;
-
- r = _id_exists(self, id, id_length, CKO_SECRET_KEY);
- if (r == 1) {
- PyErr_SetString(ipap11helperDuplicationError,
- "Secret key with same ID already exists");
- GOTO_FAIL;
- } else if (r == -1) {
- GOTO_FAIL;
- }
-
- /* Process keyword boolean arguments */
- convert_py2bool(attrs_priv,
- sizeof(attrs_priv) / sizeof(PyObj2Bool_mapping_t));
-
- CK_ATTRIBUTE template[] = {
- { CKA_CLASS, &key_class, sizeof(key_class) },
- { CKA_KEY_TYPE, &key_type, sizeof(key_type) },
- { CKA_ID, id, id_length },
- { CKA_LABEL, label, label_length },
- { CKA_TOKEN, &true, sizeof(CK_BBOOL) },
- { CKA_ALWAYS_AUTHENTICATE, attrs_priv[priv_en_cka_always_authenticate].bool, sizeof(CK_BBOOL) },
- //{ CKA_COPYABLE, attrs_priv[priv_en_cka_copyable].bool, sizeof(CK_BBOOL) }, //TODO Softhsm doesn't support it
- { CKA_DECRYPT, attrs_priv[priv_en_cka_decrypt].bool, sizeof(CK_BBOOL) },
- { CKA_DERIVE, attrs_priv[priv_en_cka_derive].bool, sizeof(CK_BBOOL) },
- { CKA_EXTRACTABLE, attrs_priv[priv_en_cka_extractable].bool, sizeof(CK_BBOOL) },
- { CKA_MODIFIABLE, attrs_priv[priv_en_cka_modifiable].bool, sizeof(CK_BBOOL) },
- { CKA_PRIVATE, attrs_priv[priv_en_cka_private].bool, sizeof(CK_BBOOL) },
- { CKA_SENSITIVE, attrs_priv[priv_en_cka_sensitive].bool, sizeof(CK_BBOOL) },
- { CKA_SIGN, attrs_priv[priv_en_cka_sign].bool, sizeof(CK_BBOOL) },
- { CKA_SIGN_RECOVER, attrs_priv[priv_en_cka_sign].bool, sizeof(CK_BBOOL) },
- { CKA_UNWRAP, attrs_priv[priv_en_cka_unwrap].bool, sizeof(CK_BBOOL) },
- { CKA_WRAP_WITH_TRUSTED, attrs_priv[priv_en_cka_wrap_with_trusted].bool, sizeof(CK_BBOOL) }
- };
-
- rv = self->p11->C_UnwrapKey(self->session, &wrapping_mech,
- unwrapping_key_object, wrapped_key,
- wrapped_key_len, template,
- sizeof(template) / sizeof(CK_ATTRIBUTE),
- &unwrapped_key_object);
- if (!check_return_value(rv, "import_wrapped_key: key unwrapping")) {
- GOTO_FAIL;
- }
-final:
- if (label != NULL)
- PyMem_Free(label);
-
- if (error)
- return NULL;
- return PyLong_FromUnsignedLong(unwrapped_key_object);
-
-}
-
-/*
- * Set object attributes
- */
-static PyObject *P11_Helper_set_attribute(P11_Helper *self, PyObject *args,
- PyObject *kwds) {
- PyObject *ret = Py_None;
- PyObject *value = NULL;
- CK_ULONG object = 0;
- unsigned long attr = 0;
- CK_ATTRIBUTE attribute;
- CK_RV rv;
- Py_ssize_t len = 0;
- CK_UTF8CHAR *label = NULL;
- int error = 0;
-
- static char *kwlist[] = { "key_object", "attr", "value", NULL };
- if (!PyArg_ParseTupleAndKeywords
- (args, kwds, "kkO|", kwlist, &object, &attr, &value)) {
- return NULL;
- }
-
- attribute.type = attr;
- switch (attr) {
- case CKA_ALWAYS_AUTHENTICATE:
- case CKA_ALWAYS_SENSITIVE:
- case CKA_COPYABLE:
- case CKA_ENCRYPT:
- case CKA_EXTRACTABLE:
- case CKA_DECRYPT:
- case CKA_DERIVE:
- case CKA_LOCAL:
- case CKA_MODIFIABLE:
- case CKA_NEVER_EXTRACTABLE:
- case CKA_PRIVATE:
- case CKA_SENSITIVE:
- case CKA_SIGN:
- case CKA_SIGN_RECOVER:
- case CKA_TOKEN:
- case CKA_TRUSTED:
- case CKA_UNWRAP:
- case CKA_VERIFY:
- case CKA_VERIFY_RECOVER:
- case CKA_WRAP:
- case CKA_WRAP_WITH_TRUSTED:
- attribute.pValue = PyObject_IsTrue(value) ? &true : &false;
- attribute.ulValueLen = sizeof(CK_BBOOL);
- break;
- case CKA_ID:
- if (!PyBytes_Check(value)) {
- PyErr_SetString(ipap11helperError, "Bytestring value expected");
- GOTO_FAIL;
- }
- if (PyBytes_AsStringAndSize(value, (char **) &attribute.pValue,
- &len) == -1) {
- GOTO_FAIL;
- }
- attribute.ulValueLen = len;
- break;
- case CKA_LABEL:
- if (!PyUnicode_Check(value)) {
- PyErr_SetString(ipap11helperError, "Unicode value expected");
- GOTO_FAIL;
- }
- label = unicode_to_char_array(value, &len);
- /* check for conversion error */
- if (label == NULL)
- GOTO_FAIL;
- attribute.pValue = label;
- attribute.ulValueLen = len;
- break;
- case CKA_KEY_TYPE:
- if (!PyInt_Check(value)) {
- PyErr_SetString(ipap11helperError, "Integer value expected");
- GOTO_FAIL;
- }
- unsigned long lv = PyInt_AsUnsignedLongMask(value);
- attribute.pValue = &lv;
- attribute.ulValueLen = sizeof(unsigned long);
- break;
- default:
- PyErr_SetString(ipap11helperError, "Unknown attribute");
- GOTO_FAIL;
- }
-
- CK_ATTRIBUTE template[] = { attribute };
-
- rv = self->p11->C_SetAttributeValue(self->session, object, template,
- sizeof(template) / sizeof(CK_ATTRIBUTE));
- if (!check_return_value(rv, "set_attribute"))
- GOTO_FAIL;
-
-final:
- if (label != NULL)
- PyMem_Free(label);
- Py_XINCREF(ret);
-
- if (error)
- return NULL;
- return ret;
-}
-
-/*
- * Get object attributes
- */
-static PyObject *P11_Helper_get_attribute(P11_Helper *self, PyObject *args,
- PyObject *kwds) {
- PyObject *ret = NULL;
- void *value = NULL;
- CK_ULONG object = 0;
- unsigned long attr = 0;
- CK_ATTRIBUTE attribute;
- CK_RV rv;
- int error = 0;
-
- static char *kwlist[] = { "key_object", "attr", NULL };
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "kk|", kwlist, &object,
- &attr)) {
- return NULL;
- }
-
- attribute.type = attr;
- attribute.pValue = NULL_PTR;
- attribute.ulValueLen = 0;
- CK_ATTRIBUTE template[] = { attribute };
-
- rv = self->p11->C_GetAttributeValue(self->session, object, template,
- sizeof(template) / sizeof(CK_ATTRIBUTE));
- // attribute doesn't exists
- if (rv == CKR_ATTRIBUTE_TYPE_INVALID
- || template[0].ulValueLen == (unsigned long) -1) {
- PyErr_SetString(ipap11helperNotFound, "attribute does not exist");
- GOTO_FAIL;
- }
- if (!check_return_value(rv, "get_attribute init")) {
- GOTO_FAIL;
- }
- value = PyMem_Malloc(template[0].ulValueLen);
- if (value == NULL) {
- PyErr_NoMemory();
- GOTO_FAIL;
- }
- template[0].pValue = value;
-
- rv = self->p11->C_GetAttributeValue(self->session, object, template,
- sizeof(template) / sizeof(CK_ATTRIBUTE));
- if (!check_return_value(rv, "get_attribute")) {
- GOTO_FAIL;
- }
-
- switch (attr) {
- case CKA_ALWAYS_AUTHENTICATE:
- case CKA_ALWAYS_SENSITIVE:
- case CKA_COPYABLE:
- case CKA_ENCRYPT:
- case CKA_EXTRACTABLE:
- case CKA_DECRYPT:
- case CKA_DERIVE:
- case CKA_LOCAL:
- case CKA_MODIFIABLE:
- case CKA_NEVER_EXTRACTABLE:
- case CKA_PRIVATE:
- case CKA_SENSITIVE:
- case CKA_SIGN:
- case CKA_SIGN_RECOVER:
- case CKA_TOKEN:
- case CKA_TRUSTED:
- case CKA_UNWRAP:
- case CKA_VERIFY:
- case CKA_VERIFY_RECOVER:
- case CKA_WRAP:
- case CKA_WRAP_WITH_TRUSTED:
- /* booleans */
- ret = PyBool_FromLong(*(CK_BBOOL *) value);
- break;
- case CKA_LABEL:
- /* unicode string */
- ret = char_array_to_unicode(value, template[0].ulValueLen);
- break;
- case CKA_MODULUS:
- case CKA_PUBLIC_EXPONENT:
- case CKA_ID:
- /* byte arrays */
- ret = string_to_pybytes_or_none(value, template[0].ulValueLen);
- break;
- case CKA_KEY_TYPE:
- /* unsigned long */
- ret = Py_BuildValue("k", *(unsigned long *) value);
- break;
- default:
- PyErr_SetString(ipap11helperError, "Unknown attribute");
- GOTO_FAIL;
- }
-
-final:
- if (value != NULL)
- PyMem_Free(value);
-
- if (error)
- return NULL;
- return ret;
-}
-
-static PyMethodDef P11_Helper_methods[] = {
- {
- "finalize",
- (PyCFunction) P11_Helper_finalize,
- METH_NOARGS,
- "Finalize operations with pkcs11 library"
- },
- {
- "generate_master_key",
- (PyCFunction) P11_Helper_generate_master_key,
- METH_VARARGS | METH_KEYWORDS,
- "Generate master key"
- },
- {
- "generate_replica_key_pair",
- (PyCFunction) P11_Helper_generate_replica_key_pair,
- METH_VARARGS | METH_KEYWORDS,
- "Generate replica key pair"
- },
- {
- "find_keys",
- (PyCFunction) P11_Helper_find_keys,
- METH_VARARGS | METH_KEYWORDS,
- "Find keys"
- },
- {
- "delete_key",
- (PyCFunction) P11_Helper_delete_key,
- METH_VARARGS | METH_KEYWORDS,
- "Delete key"
- },
- {
- "export_public_key",
- (PyCFunction) P11_Helper_export_public_key,
- METH_VARARGS | METH_KEYWORDS,
- "Export public key"
- },
- {
- "import_public_key",
- (PyCFunction) P11_Helper_import_public_key,
- METH_VARARGS | METH_KEYWORDS,
- "Import public key"
- },
- {
- "export_wrapped_key",
- (PyCFunction) P11_Helper_export_wrapped_key,
- METH_VARARGS | METH_KEYWORDS,
- "Export wrapped private key"
- },
- {
- "import_wrapped_secret_key",
- (PyCFunction) P11_Helper_import_wrapped_secret_key,
- METH_VARARGS | METH_KEYWORDS,
- "Import wrapped secret key"
- },
- {
- "import_wrapped_private_key",
- (PyCFunction) P11_Helper_import_wrapped_private_key,
- METH_VARARGS | METH_KEYWORDS,
- "Import wrapped private key"
- },
- {
- "set_attribute",
- (PyCFunction) P11_Helper_set_attribute,
- METH_VARARGS | METH_KEYWORDS,
- "Set attribute"
- },
- {
- "get_attribute",
- (PyCFunction) P11_Helper_get_attribute,
- METH_VARARGS | METH_KEYWORDS,
- "Get attribute"
- },
- {
- /* Sentinel */
- NULL
- }
-};
-
-static PyTypeObject P11_HelperType = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ipap11helper.P11_Helper", /* tp_name */
- sizeof(P11_Helper), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor) P11_Helper_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_compare */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- "P11_Helper objects", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- P11_Helper_methods, /* tp_methods */
- P11_Helper_members, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc) P11_Helper_init, /* tp_init */
- 0, /* tp_alloc */
- P11_Helper_new, /* tp_new */
-};
-
-static PyMethodDef module_methods[] = {
- { NULL } /* Sentinel */
-};
-
-#define MODULE_DOC PyDoc_STR("Example module that creates an extension type.")
-
-#if PY_MAJOR_VERSION >= 3
-static struct PyModuleDef moduledef = {
- PyModuleDef_HEAD_INIT,
- .m_name = "_ipap11helper",
- .m_doc = MODULE_DOC,
- .m_size = -1,
- .m_methods = module_methods,
-};
-#endif
-
-PyObject * module_init(void);
-PyObject * module_init(void) {
- PyObject *m;
-
- if (PyType_Ready(&P11_HelperType) < 0)
- return NULL;
-
- /*
- * Setting up P11_Helper module
- */
-#if PY_MAJOR_VERSION >= 3
- m = PyModule_Create(&moduledef);
-#else
- m = Py_InitModule3("_ipap11helper", module_methods, MODULE_DOC);
-#endif
-
- if (m == NULL)
- return NULL;
-
- /*
- * Setting up P11_Helper
- */
- Py_INCREF(&P11_HelperType);
- PyModule_AddObject(m, "P11_Helper", (PyObject *) &P11_HelperType);
-
- /*
- * Setting up P11_Helper Exceptions
- */
- ipap11helperException = PyErr_NewException("_ipap11helper.Exception", NULL,
- NULL);
- Py_INCREF(ipap11helperException);
- PyModule_AddObject(m, "Exception", ipap11helperException);
-
- ipap11helperError = PyErr_NewException("_ipap11helper.Error",
- ipap11helperException, NULL);
- Py_INCREF(ipap11helperError);
- PyModule_AddObject(m, "Error", ipap11helperError);
-
- ipap11helperNotFound = PyErr_NewException("_ipap11helper.NotFound",
- ipap11helperException, NULL);
- Py_INCREF(ipap11helperNotFound);
- PyModule_AddObject(m, "NotFound", ipap11helperNotFound);
-
- ipap11helperDuplicationError =
- PyErr_NewException("_ipap11helper.DuplicationError",
- ipap11helperException, NULL);
- Py_INCREF(ipap11helperDuplicationError);
- PyModule_AddObject(m, "DuplicationError", ipap11helperDuplicationError);
-
- /**
- * Setting up module attributes
- */
-
- /* Key Classes */
- PyModule_AddIntConstant(m, "KEY_CLASS_PUBLIC_KEY", CKO_PUBLIC_KEY);
- PyModule_AddIntConstant(m, "KEY_CLASS_PRIVATE_KEY", CKO_PRIVATE_KEY);
- PyModule_AddIntConstant(m, "KEY_CLASS_SECRET_KEY", CKO_SECRET_KEY);
-
- /* Key types */
- PyModule_AddIntConstant(m, "KEY_TYPE_RSA", CKK_RSA);
- PyModule_AddIntConstant(m, "KEY_TYPE_AES", CKK_AES);
-
- /* Wrapping mech type */
- PyModule_AddIntConstant(m, "MECH_RSA_PKCS", CKM_RSA_PKCS);
- PyModule_AddIntConstant(m, "MECH_RSA_PKCS_OAEP", CKM_RSA_PKCS_OAEP);
- PyModule_AddIntConstant(m, "MECH_AES_KEY_WRAP", CKM_AES_KEY_WRAP);
- PyModule_AddIntConstant(m, "MECH_AES_KEY_WRAP_PAD", CKM_AES_KEY_WRAP_PAD);
-
- /* Key attributes */
- PyModule_AddIntMacro(m, CKA_ALWAYS_AUTHENTICATE);
- PyModule_AddIntMacro(m, CKA_ALWAYS_SENSITIVE);
- PyModule_AddIntMacro(m, CKA_COPYABLE);
- PyModule_AddIntMacro(m, CKA_DECRYPT);
- PyModule_AddIntMacro(m, CKA_DERIVE);
- PyModule_AddIntMacro(m, CKA_ENCRYPT);
- PyModule_AddIntMacro(m, CKA_EXTRACTABLE);
- PyModule_AddIntMacro(m, CKA_ID);
- PyModule_AddIntMacro(m, CKA_KEY_TYPE);
- PyModule_AddIntMacro(m, CKA_LOCAL);
- PyModule_AddIntMacro(m, CKA_MODIFIABLE);
- PyModule_AddIntMacro(m, CKA_MODULUS);
- PyModule_AddIntMacro(m, CKA_NEVER_EXTRACTABLE);
- PyModule_AddIntMacro(m, CKA_PRIVATE);
- PyModule_AddIntMacro(m, CKA_PUBLIC_EXPONENT);
- PyModule_AddIntMacro(m, CKA_SENSITIVE);
- PyModule_AddIntMacro(m, CKA_SIGN);
- PyModule_AddIntMacro(m, CKA_SIGN_RECOVER);
- PyModule_AddIntMacro(m, CKA_TRUSTED);
- PyModule_AddIntMacro(m, CKA_VERIFY);
- PyModule_AddIntMacro(m, CKA_VERIFY_RECOVER);
- PyModule_AddIntMacro(m, CKA_UNWRAP);
- PyModule_AddIntMacro(m, CKA_WRAP);
- PyModule_AddIntMacro(m, CKA_WRAP_WITH_TRUSTED);
- PyModule_AddIntMacro(m, CKA_TOKEN);
- PyModule_AddIntMacro(m, CKA_LABEL);
-
- return m;
-}
-
-
-#if PY_MAJOR_VERSION >= 3
-PyMODINIT_FUNC PyInit__ipap11helper(void);
-PyMODINIT_FUNC PyInit__ipap11helper(void)
-{
- return module_init();
-}
-#else
-void init_ipap11helper(void);
-void init_ipap11helper(void)
-{
- module_init();
-}
-#endif
diff --git a/ipapython/ipap11helper/setup.py b/ipapython/ipap11helper/setup.py
deleted file mode 100644
index 9743ac229..000000000
--- a/ipapython/ipap11helper/setup.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/python2
-#
-# Copyright (C) 2014 FreeIPA Contributors see COPYING for license
-#
-
-from distutils.core import setup, Extension
-from distutils.sysconfig import get_python_inc
-import sys
-import os
-
-python_header = os.path.join(get_python_inc(plat_specific=0), 'Python.h')
-if not os.path.exists(python_header):
- sys.exit("Cannot find Python development packages that provide Python.h")
-
-module = Extension('_ipap11helper',
- define_macros = [],
- include_dirs = [],
- libraries = ['dl', 'crypto', 'p11-kit'],
- library_dirs = [],
- extra_compile_args = [
- '-std=c99',
- '-I/usr/include/p11-kit-1',
- '-ggdb3',
- '-O2',
- '-W',
- '-Wall',
- '-Wno-unused-parameter',
- '-Wbad-function-cast',
- '-Wextra',
- ],
- sources = ['p11helper.c', 'library.c'])
-
-setup(name='_ipap11helper',
- version='0.1',
- description='FreeIPA pkcs11 helper',
- author='Martin Basti, Petr Spacek',
- author_email='mbasti@redhat.com, pspacek@redhat.com',
- license='GPLv2+',
- url='http://www.freeipa.org',
- long_description="""
- FreeIPA pkcs11 key manipulation utils.
-""",
- ext_modules = [module])
diff --git a/ipapython/p11helper.py b/ipapython/p11helper.py
index 10a60cc02..7916baa07 100644
--- a/ipapython/p11helper.py
+++ b/ipapython/p11helper.py
@@ -2,19 +2,1877 @@
# Copyright (C) 2014 FreeIPA Contributors see COPYING for license
#
-import _ipap11helper
import random
+import ctypes.util
+
+import six
+from cffi import FFI
+
+if six.PY3:
+ unicode = str
+
+
+_ffi = FFI()
+
+_ffi.cdef('''
+/* stdlib.h */
+
+void free(void *ptr);
+
+
+/* openssl/ossl_typ.h */
+
+typedef ... BIGNUM;
+
+typedef ... EVP_PKEY;
+
+typedef struct rsa_st RSA;
+typedef ... RSA_METHOD;
+
+typedef ... ENGINE;
+
+typedef ... CRYPTO_EX_DATA;
+
+
+/* openssl/x509.h */
+
+int i2d_PUBKEY(EVP_PKEY *a, unsigned char **pp);
+EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp, long length);
+
+
+/* openssl/evp.h */
+
+int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, struct rsa_st *key);
+struct rsa_st *EVP_PKEY_get1_RSA(EVP_PKEY *pkey);
+
+EVP_PKEY *EVP_PKEY_new(void);
+void EVP_PKEY_free(EVP_PKEY *pkey);
+
+
+/* openssl/bn.h */
+
+int BN_num_bits(const BIGNUM *a);
+BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
+int BN_bn2bin(const BIGNUM *a, unsigned char *to);
+
+void BN_free(BIGNUM *a);
+
+
+/* openssl/rsa.h */
+
+struct rsa_st {
+ /*
+ * The first parameter is used to pickup errors where this is passed
+ * instead of aEVP_PKEY, it is set to 0
+ */
+ int pad;
+ long version;
+ const RSA_METHOD *meth;
+ /* functional reference if 'meth' is ENGINE-provided */
+ ENGINE *engine;
+ BIGNUM *n;
+ BIGNUM *e;
+ /* ...; */
+};
+
+RSA *RSA_new(void);
+
+void RSA_free(RSA *r);
+
+
+/* p11-kit/pkcs11.h */
+
+typedef unsigned long CK_FLAGS;
+
+struct _CK_VERSION
+{
+ unsigned char major;
+ unsigned char minor;
+};
+
+typedef unsigned long CK_SLOT_ID;
+
+typedef unsigned long CK_SESSION_HANDLE;
+
+typedef unsigned long CK_USER_TYPE;
+
+typedef unsigned long CK_OBJECT_HANDLE;
+
+typedef unsigned long CK_OBJECT_CLASS;
+
+typedef unsigned long CK_KEY_TYPE;
+
+typedef unsigned long CK_ATTRIBUTE_TYPE;
+
+struct _CK_ATTRIBUTE
+{
+ CK_ATTRIBUTE_TYPE type;
+ void *pValue;
+ unsigned long ulValueLen;
+};
+
+typedef unsigned long CK_MECHANISM_TYPE;
+
+struct _CK_MECHANISM
+{
+ CK_MECHANISM_TYPE mechanism;
+ void *pParameter;
+ unsigned long ulParameterLen;
+};
+
+typedef unsigned long CK_RV;
+
+typedef ... *CK_NOTIFY;
+
+struct _CK_FUNCTION_LIST;
+
+typedef CK_RV (*CK_C_Initialize) (void *init_args);
+typedef CK_RV (*CK_C_Finalize) (void *pReserved);
+typedef ... *CK_C_GetInfo;
+typedef ... *CK_C_GetFunctionList;
+CK_RV C_GetFunctionList (struct _CK_FUNCTION_LIST **function_list);
+typedef ... *CK_C_GetSlotList;
+typedef ... *CK_C_GetSlotInfo;
+typedef ... *CK_C_GetTokenInfo;
+typedef ... *CK_C_WaitForSlotEvent;
+typedef ... *CK_C_GetMechanismList;
+typedef ... *CK_C_GetMechanismInfo;
+typedef ... *CK_C_InitToken;
+typedef ... *CK_C_InitPIN;
+typedef ... *CK_C_SetPIN;
+typedef CK_RV (*CK_C_OpenSession) (CK_SLOT_ID slotID, CK_FLAGS flags,
+ void *application, CK_NOTIFY notify,
+ CK_SESSION_HANDLE *session);
+typedef CK_RV (*CK_C_CloseSession) (CK_SESSION_HANDLE session);
+typedef ... *CK_C_CloseAllSessions;
+typedef ... *CK_C_GetSessionInfo;
+typedef ... *CK_C_GetOperationState;
+typedef ... *CK_C_SetOperationState;
+typedef CK_RV (*CK_C_Login) (CK_SESSION_HANDLE session, CK_USER_TYPE user_type,
+ unsigned char *pin, unsigned long pin_len);
+typedef CK_RV (*CK_C_Logout) (CK_SESSION_HANDLE session);
+typedef CK_RV (*CK_C_CreateObject) (CK_SESSION_HANDLE session,
+ struct _CK_ATTRIBUTE *templ,
+ unsigned long count,
+ CK_OBJECT_HANDLE *object);
+typedef ... *CK_C_CopyObject;
+typedef CK_RV (*CK_C_DestroyObject) (CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object);
+typedef ... *CK_C_GetObjectSize;
+typedef CK_RV (*CK_C_GetAttributeValue) (CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object,
+ struct _CK_ATTRIBUTE *templ,
+ unsigned long count);
+typedef CK_RV (*CK_C_SetAttributeValue) (CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object,
+ struct _CK_ATTRIBUTE *templ,
+ unsigned long count);
+typedef CK_RV (*CK_C_FindObjectsInit) (CK_SESSION_HANDLE session,
+ struct _CK_ATTRIBUTE *templ,
+ unsigned long count);
+typedef CK_RV (*CK_C_FindObjects) (CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE *object,
+ unsigned long max_object_count,
+ unsigned long *object_count);
+typedef CK_RV (*CK_C_FindObjectsFinal) (CK_SESSION_HANDLE session);
+typedef ... *CK_C_EncryptInit;
+typedef ... *CK_C_Encrypt;
+typedef ... *CK_C_EncryptUpdate;
+typedef ... *CK_C_EncryptFinal;
+typedef ... *CK_C_DecryptInit;
+typedef ... *CK_C_Decrypt;
+typedef ... *CK_C_DecryptUpdate;
+typedef ... *CK_C_DecryptFinal;
+typedef ... *CK_C_DigestInit;
+typedef ... *CK_C_Digest;
+typedef ... *CK_C_DigestUpdate;
+typedef ... *CK_C_DigestKey;
+typedef ... *CK_C_DigestFinal;
+typedef ... *CK_C_SignInit;
+typedef ... *CK_C_Sign;
+typedef ... *CK_C_SignUpdate;
+typedef ... *CK_C_SignFinal;
+typedef ... *CK_C_SignRecoverInit;
+typedef ... *CK_C_SignRecover;
+typedef ... *CK_C_VerifyInit;
+typedef ... *CK_C_Verify;
+typedef ... *CK_C_VerifyUpdate;
+typedef ... *CK_C_VerifyFinal;
+typedef ... *CK_C_VerifyRecoverInit;
+typedef ... *CK_C_VerifyRecover;
+typedef ... *CK_C_DigestEncryptUpdate;
+typedef ... *CK_C_DecryptDigestUpdate;
+typedef ... *CK_C_SignEncryptUpdate;
+typedef ... *CK_C_DecryptVerifyUpdate;
+typedef CK_RV (*CK_C_GenerateKey) (CK_SESSION_HANDLE session,
+ struct _CK_MECHANISM *mechanism,
+ struct _CK_ATTRIBUTE *templ,
+ unsigned long count,
+ CK_OBJECT_HANDLE *key);
+typedef CK_RV (*CK_C_GenerateKeyPair) (CK_SESSION_HANDLE session,
+ struct _CK_MECHANISM *mechanism,
+ struct _CK_ATTRIBUTE *
+ public_key_template,
+ unsigned long
+ public_key_attribute_count,
+ struct _CK_ATTRIBUTE *
+ private_key_template,
+ unsigned long
+ private_key_attribute_count,
+ CK_OBJECT_HANDLE *public_key,
+ CK_OBJECT_HANDLE *private_key);
+typedef CK_RV (*CK_C_WrapKey) (CK_SESSION_HANDLE session,
+ struct _CK_MECHANISM *mechanism,
+ CK_OBJECT_HANDLE wrapping_key,
+ CK_OBJECT_HANDLE key,
+ unsigned char *wrapped_key,
+ unsigned long *wrapped_key_len);
+typedef CK_RV (*CK_C_UnwrapKey) (CK_SESSION_HANDLE session,
+ struct _CK_MECHANISM *mechanism,
+ CK_OBJECT_HANDLE unwrapping_key,
+ unsigned char *wrapped_key,
+ unsigned long wrapped_key_len,
+ struct _CK_ATTRIBUTE *templ,
+ unsigned long attribute_count,
+ CK_OBJECT_HANDLE *key);
+typedef ... *CK_C_DeriveKey;
+typedef ... *CK_C_SeedRandom;
+typedef ... *CK_C_GenerateRandom;
+typedef ... *CK_C_GetFunctionStatus;
+typedef ... *CK_C_CancelFunction;
+
+struct _CK_FUNCTION_LIST
+{
+ struct _CK_VERSION version;
+ CK_C_Initialize C_Initialize;
+ CK_C_Finalize C_Finalize;
+ CK_C_GetInfo C_GetInfo;
+ CK_C_GetFunctionList C_GetFunctionList;
+ CK_C_GetSlotList C_GetSlotList;
+ CK_C_GetSlotInfo C_GetSlotInfo;
+ CK_C_GetTokenInfo C_GetTokenInfo;
+ CK_C_GetMechanismList C_GetMechanismList;
+ CK_C_GetMechanismInfo C_GetMechanismInfo;
+ CK_C_InitToken C_InitToken;
+ CK_C_InitPIN C_InitPIN;
+ CK_C_SetPIN C_SetPIN;
+ CK_C_OpenSession C_OpenSession;
+ CK_C_CloseSession C_CloseSession;
+ CK_C_CloseAllSessions C_CloseAllSessions;
+ CK_C_GetSessionInfo C_GetSessionInfo;
+ CK_C_GetOperationState C_GetOperationState;
+ CK_C_SetOperationState C_SetOperationState;
+ CK_C_Login C_Login;
+ CK_C_Logout C_Logout;
+ CK_C_CreateObject C_CreateObject;
+ CK_C_CopyObject C_CopyObject;
+ CK_C_DestroyObject C_DestroyObject;
+ CK_C_GetObjectSize C_GetObjectSize;
+ CK_C_GetAttributeValue C_GetAttributeValue;
+ CK_C_SetAttributeValue C_SetAttributeValue;
+ CK_C_FindObjectsInit C_FindObjectsInit;
+ CK_C_FindObjects C_FindObjects;
+ CK_C_FindObjectsFinal C_FindObjectsFinal;
+ CK_C_EncryptInit C_EncryptInit;
+ CK_C_Encrypt C_Encrypt;
+ CK_C_EncryptUpdate C_EncryptUpdate;
+ CK_C_EncryptFinal C_EncryptFinal;
+ CK_C_DecryptInit C_DecryptInit;
+ CK_C_Decrypt C_Decrypt;
+ CK_C_DecryptUpdate C_DecryptUpdate;
+ CK_C_DecryptFinal C_DecryptFinal;
+ CK_C_DigestInit C_DigestInit;
+ CK_C_Digest C_Digest;
+ CK_C_DigestUpdate C_DigestUpdate;
+ CK_C_DigestKey C_DigestKey;
+ CK_C_DigestFinal C_DigestFinal;
+ CK_C_SignInit C_SignInit;
+ CK_C_Sign C_Sign;
+ CK_C_SignUpdate C_SignUpdate;
+ CK_C_SignFinal C_SignFinal;
+ CK_C_SignRecoverInit C_SignRecoverInit;
+ CK_C_SignRecover C_SignRecover;
+ CK_C_VerifyInit C_VerifyInit;
+ CK_C_Verify C_Verify;
+ CK_C_VerifyUpdate C_VerifyUpdate;
+ CK_C_VerifyFinal C_VerifyFinal;
+ CK_C_VerifyRecoverInit C_VerifyRecoverInit;
+ CK_C_VerifyRecover C_VerifyRecover;
+ CK_C_DigestEncryptUpdate C_DigestEncryptUpdate;
+ CK_C_DecryptDigestUpdate C_DecryptDigestUpdate;
+ CK_C_SignEncryptUpdate C_SignEncryptUpdate;
+ CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate;
+ CK_C_GenerateKey C_GenerateKey;
+ CK_C_GenerateKeyPair C_GenerateKeyPair;
+ CK_C_WrapKey C_WrapKey;
+ CK_C_UnwrapKey C_UnwrapKey;
+ CK_C_DeriveKey C_DeriveKey;
+ CK_C_SeedRandom C_SeedRandom;
+ CK_C_GenerateRandom C_GenerateRandom;
+ CK_C_GetFunctionStatus C_GetFunctionStatus;
+ CK_C_CancelFunction C_CancelFunction;
+ CK_C_WaitForSlotEvent C_WaitForSlotEvent;
+};
+
+typedef unsigned char CK_BYTE;
+typedef unsigned char CK_UTF8CHAR;
+typedef unsigned char CK_BBOOL;
+typedef unsigned long int CK_ULONG;
+typedef CK_BYTE *CK_BYTE_PTR;
+typedef CK_ULONG *CK_ULONG_PTR;
+
+typedef CK_OBJECT_HANDLE *CK_OBJECT_HANDLE_PTR;
+
+typedef struct _CK_ATTRIBUTE CK_ATTRIBUTE;
+typedef struct _CK_ATTRIBUTE *CK_ATTRIBUTE_PTR;
+
+typedef struct _CK_MECHANISM CK_MECHANISM;
+
+typedef struct _CK_FUNCTION_LIST *CK_FUNCTION_LIST_PTR;
+
+
+/* p11-kit/uri.h */
+
+typedef enum {
+ DUMMY /* ..., */
+} P11KitUriType;
+
+typedef ... P11KitUri;
+
+CK_ATTRIBUTE_PTR p11_kit_uri_get_attributes (P11KitUri *uri,
+ CK_ULONG *n_attrs);
+
+int p11_kit_uri_any_unrecognized (P11KitUri *uri);
+
+P11KitUri* p11_kit_uri_new (void);
+
+int p11_kit_uri_parse (const char *string,
+ P11KitUriType uri_type,
+ P11KitUri *uri);
+
+void p11_kit_uri_free (P11KitUri *uri);
+
+
+/* p11helper.c */
+
+struct ck_rsa_pkcs_oaep_params {
+ CK_MECHANISM_TYPE hash_alg;
+ unsigned long mgf;
+ unsigned long source;
+ void *source_data;
+ unsigned long source_data_len;
+};
+
+typedef struct ck_rsa_pkcs_oaep_params CK_RSA_PKCS_OAEP_PARAMS;
+''')
+
+_libc = _ffi.dlopen(None)
+_libcrypto = _ffi.dlopen(ctypes.util.find_library('crypto'))
+_libp11_kit = _ffi.dlopen(ctypes.util.find_library('p11-kit'))
+
+
+# utility
+
+NULL = _ffi.NULL
+
+unsigned_char = _ffi.typeof('unsigned char')
+unsigned_char_ptr = _ffi.typeof('unsigned char *')
+unsigned_int = _ffi.typeof('unsigned int')
+unsigned_long = _ffi.typeof('unsigned long')
+
+sizeof = _ffi.sizeof
+
+
+def new_ptr(ctype, *args):
+ return _ffi.new(_ffi.getctype(ctype, '*'), *args)
+
+
+def new_array(ctype, *args):
+ return _ffi.new(_ffi.getctype(ctype, '[]'), *args)
+
+
+# stdlib.h
+
+free = _libc.free
+
+
+# openssl/x509.h
+
+i2d_PUBKEY = _libcrypto.i2d_PUBKEY
+d2i_PUBKEY = _libcrypto.i2d_PUBKEY
+
+
+# openssl/evp.h
+
+EVP_PKEY_RSA = 6
+EVP_PKEY_DSA = 116
+EVP_PKEY_EC = 408
+
+EVP_PKEY_set1_RSA = _libcrypto.EVP_PKEY_set1_RSA
+EVP_PKEY_get1_RSA = _libcrypto.EVP_PKEY_get1_RSA
+EVP_PKEY_new = _libcrypto.EVP_PKEY_new
+EVP_PKEY_free = _libcrypto.EVP_PKEY_free
+
+
+# openssl/bn.h
+
+def BN_num_bytes(a):
+ return (_libcrypto.BN_num_bits(a) + 7) // 8
+
+BN_bin2bn = _libcrypto.BN_bin2bn
+BN_bn2bin = _libcrypto.BN_bn2bin
+
+BN_free = _libcrypto.BN_free
+
+
+# openssl/rsa.h
+
+RSA_new = _libcrypto.RSA_new
+
+RSA_free = _libcrypto.RSA_free
+
+
+# p11-kit/pkcs11.h
+
+CK_SESSION_HANDLE = _ffi.typeof('CK_SESSION_HANDLE')
+
+CK_OBJECT_HANDLE = _ffi.typeof('CK_OBJECT_HANDLE')
+
+CKU_USER = 1
+
+CKF_RW_SESSION = 0x2
+CKF_SERIAL_SESSION = 0x4
+
+CK_OBJECT_CLASS = _ffi.typeof('CK_OBJECT_CLASS')
+
+CKO_PUBLIC_KEY = 2
+CKO_PRIVATE_KEY = 3
+CKO_SECRET_KEY = 4
+CKO_VENDOR_DEFINED = 0x80000000
+
+CK_KEY_TYPE = _ffi.typeof('CK_KEY_TYPE')
+
+CKK_RSA = 0
+CKK_AES = 0x1f
+
+CKA_CLASS = 0
+CKA_TOKEN = 1
+CKA_PRIVATE = 2
+CKA_LABEL = 3
+CKA_TRUSTED = 0x86
+CKA_KEY_TYPE = 0x100
+CKA_ID = 0x102
+CKA_SENSITIVE = 0x103
+CKA_ENCRYPT = 0x104
+CKA_DECRYPT = 0x105
+CKA_WRAP = 0x106
+CKA_UNWRAP = 0x107
+CKA_SIGN = 0x108
+CKA_SIGN_RECOVER = 0x109
+CKA_VERIFY = 0x10a
+CKA_VERIFY_RECOVER = 0x10b
+CKA_DERIVE = 0x10c
+CKA_MODULUS = 0x120
+CKA_MODULUS_BITS = 0x121
+CKA_PUBLIC_EXPONENT = 0x122
+CKA_VALUE_LEN = 0x161
+CKA_EXTRACTABLE = 0x162
+CKA_LOCAL = 0x163
+CKA_NEVER_EXTRACTABLE = 0x164
+CKA_ALWAYS_SENSITIVE = 0x165
+CKA_MODIFIABLE = 0x170
+CKA_ALWAYS_AUTHENTICATE = 0x202
+CKA_WRAP_WITH_TRUSTED = 0x210
+
+CKM_RSA_PKCS_KEY_PAIR_GEN = 0
+CKM_RSA_PKCS = 1
+CKM_RSA_PKCS_OAEP = 9
+CKM_SHA_1 = 0x220
+CKM_AES_KEY_GEN = 0x1080
+
+CKR_OK = 0
+CKR_ATTRIBUTE_TYPE_INVALID = 0x12
+CKR_USER_NOT_LOGGED_IN = 0x101
+
+CK_BYTE = _ffi.typeof('CK_BYTE')
+CK_BBOOL = _ffi.typeof('CK_BBOOL')
+CK_ULONG = _ffi.typeof('CK_ULONG')
+CK_BYTE_PTR = _ffi.typeof('CK_BYTE_PTR')
+CK_FALSE = 0
+CK_TRUE = 1
+
+CK_OBJECT_HANDLE_PTR = _ffi.typeof('CK_OBJECT_HANDLE_PTR')
+
+CK_ATTRIBUTE = _ffi.typeof('CK_ATTRIBUTE')
+
+CK_MECHANISM = _ffi.typeof('CK_MECHANISM')
+
+CK_FUNCTION_LIST_PTR = _ffi.typeof('CK_FUNCTION_LIST_PTR')
+
+NULL_PTR = NULL
+
+
+# p11-kit/uri.h
+
+P11_KIT_URI_OK = 0
+
+P11_KIT_URI_FOR_OBJECT = 2
+
+p11_kit_uri_get_attributes = _libp11_kit.p11_kit_uri_get_attributes
+
+p11_kit_uri_any_unrecognized = _libp11_kit.p11_kit_uri_any_unrecognized
+
+p11_kit_uri_new = _libp11_kit.p11_kit_uri_new
+
+p11_kit_uri_parse = _libp11_kit.p11_kit_uri_parse
+
+p11_kit_uri_free = _libp11_kit.p11_kit_uri_free
+
+
+# library.c
+
+def loadLibrary(module):
+ """Load the PKCS#11 library"""
+ # Load PKCS #11 library
+ try:
+ if module:
+ # pylint: disable=no-member
+ pDynLib = _ffi.dlopen(module, _ffi.RTLD_NOW | _ffi.RTLD_LOCAL)
+ else:
+ raise Exception()
+
+ except Exception:
+ # Failed to load the PKCS #11 library
+ raise
+
+ # Retrieve the entry point for C_GetFunctionList
+ pGetFunctionList = pDynLib.C_GetFunctionList
+ if pGetFunctionList == NULL:
+ raise Exception()
+
+ # Store the handle so we can dlclose it later
+
+ return pGetFunctionList, pDynLib
+
+
+# p11helper.c
+
+# compat TODO
+CKM_AES_KEY_WRAP = 0x2109
+CKM_AES_KEY_WRAP_PAD = 0x210a
+
+# TODO
+CKA_COPYABLE = 0x0017
+
+CKG_MGF1_SHA1 = 0x00000001
+
+CKZ_DATA_SPECIFIED = 0x00000001
+
+CK_RSA_PKCS_OAEP_PARAMS = _ffi.typeof('CK_RSA_PKCS_OAEP_PARAMS')
+
+
+true_ptr = new_ptr(CK_BBOOL, CK_TRUE)
+false_ptr = new_ptr(CK_BBOOL, CK_FALSE)
+
+MAX_TEMPLATE_LEN = 32
+
+#
+# Constants
+#
+CONST_RSA_PKCS_OAEP_PARAMS_ptr = new_ptr(CK_RSA_PKCS_OAEP_PARAMS, dict(
+ hash_alg=CKM_SHA_1,
+ mgf=CKG_MGF1_SHA1,
+ source=CKZ_DATA_SPECIFIED,
+ source_data=NULL,
+ source_data_len=0,
+))
+
+
+#
+# ipap11helper Exceptions
+#
+class P11HelperException(Exception):
+ """parent class for all exceptions"""
+ pass
+P11HelperException.__name__ = 'Exception'
+
+
+class Error(P11HelperException):
+ """general error"""
+ pass
+
+
+class NotFound(P11HelperException):
+ """key not found"""
+ pass
+
+
+class DuplicationError(P11HelperException):
+ """key already exists"""
+ pass
+
+
+########################################################################
+# Support functions
+#
+
+def pyobj_to_bool(pyobj):
+ if pyobj:
+ return true_ptr
+ return false_ptr
+
+
+def convert_py2bool(mapping):
+ return tuple(pyobj_to_bool(py_obj) for py_obj in mapping)
+
+
+def string_to_pybytes_or_none(str, len):
+ if str == NULL:
+ return None
+ return _ffi.buffer(str, len)[:]
+
+
+def unicode_to_char_array(unicode):
+ """
+ Convert a unicode string to the utf8 encoded char array
+ :param unicode: input python unicode object
+ """
+ try:
+ utf8_str = unicode.encode('utf-8')
+ except Exception:
+ raise Error("Unable to encode UTF-8")
+ try:
+ result = new_array(unsigned_char, utf8_str)
+ except Exception:
+ raise Error("Unable to get bytes from string")
+ l = len(utf8_str)
+ return result, l
+
+
+def char_array_to_unicode(array, l):
+ """
+ Convert utf-8 encoded char array to unicode object
+ """
+ return _ffi.buffer(array, l)[:].decode('utf-8')
+
+
+def check_return_value(rv, message):
+ """
+ Tests result value of pkc11 operations
+ """
+ if rv != CKR_OK:
+ try:
+ errmsg = "Error at %s: 0x%x\n" % (message, rv)
+ except Exception:
+ raise Error("An error occured during error message generation. "
+ "Please report this problem. Developers will use "
+ "a crystal ball to find out the root cause.")
+ else:
+ raise Error(errmsg)
+
+
+def _fill_template_from_parts(attr, template_len, id, id_len, label, label_len,
+ class_, cka_wrap, cka_unwrap):
+ """
+ Fill template structure with pointers to attributes passed as independent
+ variables.
+ Variables with NULL values will be omitted from template.
+
+ @warning input variables should not be modified when template is in use
+ """
+ cnt = 0
+ if label != NULL:
+ attr[0].type = CKA_LABEL
+ attr[0].pValue = label
+ attr[0].ulValueLen = label_len
+ attr += 1
+ cnt += 1
+ assert cnt < template_len[0]
+ if id != NULL:
+ attr[0].type = CKA_ID
+ attr[0].pValue = id
+ attr[0].ulValueLen = id_len
+ attr += 1
+ cnt += 1
+ assert cnt < template_len[0]
+ if cka_wrap != NULL:
+ attr[0].type = CKA_WRAP
+ attr[0].pValue = cka_wrap
+ attr[0].ulValueLen = sizeof(CK_BBOOL)
+ attr += 1
+ cnt += 1
+ assert cnt < template_len[0]
+ if cka_unwrap != NULL:
+ attr[0].type = CKA_UNWRAP
+ attr[0].pValue = cka_unwrap
+ attr[0].ulValueLen = sizeof(CK_BBOOL)
+ attr += 1
+ cnt += 1
+ assert cnt < template_len[0]
+
+ if class_ != NULL:
+ attr[0].type = CKA_CLASS
+ attr[0].pValue = class_
+ attr[0].ulValueLen = sizeof(CK_OBJECT_CLASS)
+ attr += 1
+ cnt += 1
+ assert cnt < template_len[0]
+ template_len[0] = cnt
+
+
+def _parse_uri(uri_str):
+ """
+ Parse string to P11-kit representation of PKCS#11 URI.
+ """
+ uri = p11_kit_uri_new()
+ if not uri:
+ raise Error("Cannot initialize URI parser")
+
+ try:
+ result = p11_kit_uri_parse(uri_str, P11_KIT_URI_FOR_OBJECT, uri)
+ if result != P11_KIT_URI_OK:
+ raise Error("Cannot parse URI")
+
+ if p11_kit_uri_any_unrecognized(uri):
+ raise Error("PKCS#11 URI contains unsupported attributes")
+ except Error:
+ p11_kit_uri_free(uri)
+ raise
+
+ return uri
+
+
+def _set_wrapping_mech_parameters(mech_type, mech):
+ """
+ Function set default param values for wrapping mechanism
+ :param mech_type: mechanism type
+ :param mech: filled structure with params based on mech type
+
+ Warning: do not dealloc param values, it is static variables
+ """
+ if mech_type in (CKM_RSA_PKCS, CKM_AES_KEY_WRAP, CKM_AES_KEY_WRAP_PAD):
+ mech.pParameter = NULL
+ mech.ulParameterLen = 0
+ elif mech_type == CKM_RSA_PKCS_OAEP:
+ # Use the same configuration as openSSL
+ # https://www.openssl.org/docs/crypto/RSA_public_encrypt.html
+ mech.pParameter = CONST_RSA_PKCS_OAEP_PARAMS_ptr
+ mech.ulParameterLen = sizeof(CK_RSA_PKCS_OAEP_PARAMS)
+ else:
+ raise Error("Unsupported wrapping mechanism")
+ mech.mechanism = mech_type
+
+
+########################################################################
+# P11_Helper object
+#
+class P11_Helper(object):
+ @property
+ def p11(self):
+ return self.p11_ptr[0]
+
+ @property
+ def session(self):
+ return self.session_ptr[0]
+
+ def _find_key(self, template, template_len):
+ """
+ Find keys matching specified template.
+ Function returns list of key handles via objects parameter.
+
+ :param template: PKCS#11 template for attribute matching
+ """
+ result_objects = []
+ result_object_ptr = new_ptr(CK_OBJECT_HANDLE)
+ objectCount_ptr = new_ptr(CK_ULONG)
+
+ rv = self.p11.C_FindObjectsInit(self.session, template, template_len)
+ check_return_value(rv, "Find key init")
+
+ rv = self.p11.C_FindObjects(self.session, result_object_ptr, 1,
+ objectCount_ptr)
+ check_return_value(rv, "Find key")
+
+ while objectCount_ptr[0] > 0:
+ result_objects.append(result_object_ptr[0])
+
+ rv = self.p11.C_FindObjects(self.session, result_object_ptr, 1,
+ objectCount_ptr)
+ check_return_value(rv, "Check for duplicated key")
+
+ rv = self.p11.C_FindObjectsFinal(self.session)
+ check_return_value(rv, "Find objects final")
+
+ return result_objects
+
+ def _id_exists(self, id, id_len, class_):
+ """
+ Test if object with specified label, id and class exists
+
+ :param id: key ID, (if value is NULL, will not be used to find key)
+ :param id_len: key ID length
+ :param class_ key: class
+
+ :return: True if object was found, False if object doesnt exists
+ """
+ object_count_ptr = new_ptr(CK_ULONG)
+ result_object_ptr = new_ptr(CK_OBJECT_HANDLE)
+ class_ptr = new_ptr(CK_OBJECT_CLASS, class_)
+ class_sec_ptr = new_ptr(CK_OBJECT_CLASS, CKO_SECRET_KEY)
+
+ template_pub_priv = new_array(CK_ATTRIBUTE, (
+ (CKA_ID, id, id_len),
+ (CKA_CLASS, class_ptr, sizeof(CK_OBJECT_CLASS)),
+ ))
+
+ template_sec = new_array(CK_ATTRIBUTE, (
+ (CKA_ID, id, id_len),
+ (CKA_CLASS, class_sec_ptr, sizeof(CK_OBJECT_CLASS)),
+ ))
+
+ template_id = new_array(CK_ATTRIBUTE, (
+ (CKA_ID, id, id_len),
+ ))
+
+ #
+ # Only one secret key with same ID is allowed
+ #
+ if class_ == CKO_SECRET_KEY:
+ rv = self.p11.C_FindObjectsInit(self.session, template_id, 1)
+ check_return_value(rv, "id, label exists init")
+
+ rv = self.p11.C_FindObjects(self.session, result_object_ptr, 1,
+ object_count_ptr)
+ check_return_value(rv, "id, label exists")
+
+ rv = self.p11.C_FindObjectsFinal(self.session)
+ check_return_value(rv, "id, label exists final")
+
+ if object_count_ptr[0] > 0:
+ return True
+ return False
+
+ #
+ # Public and private keys can share one ID, but
+ #
+
+ # test if secret key with same ID exists
+ rv = self.p11.C_FindObjectsInit(self.session, template_sec, 2)
+ check_return_value(rv, "id, label exists init")
+
+ rv = self.p11.C_FindObjects(self.session, result_object_ptr, 1,
+ object_count_ptr)
+ check_return_value(rv, "id, label exists")
+
+ rv = self.p11.C_FindObjectsFinal(self.session)
+ check_return_value(rv, "id, label exists final")
+
+ if object_count_ptr[0] > 0:
+ # object found
+ return True
+
+ # test if pub/private key with same id exists
+ object_count_ptr[0] = 0
+
+ rv = self.p11.C_FindObjectsInit(self.session, template_pub_priv, 2)
+ check_return_value(rv, "id, label exists init")
+
+ rv = self.p11.C_FindObjects(self.session, result_object_ptr, 1,
+ object_count_ptr)
+ check_return_value(rv, "id, label exists")
+
+ rv = self.p11.C_FindObjectsFinal(self.session)
+ check_return_value(rv, "id, label exists final")
+
+ if object_count_ptr[0] > 0:
+ # Object found
+ return True
+
+ # Object not found
+ return False
+
+ def __init__(self, slot, user_pin, library_path):
+ self.p11_ptr = new_ptr(CK_FUNCTION_LIST_PTR)
+ self.session_ptr = new_ptr(CK_SESSION_HANDLE)
+
+ self.slot = 0
+ self.session_ptr[0] = 0
+ self.p11_ptr[0] = NULL
+ self.module_handle = None
+
+ # Parse method args
+ if isinstance(user_pin, unicode):
+ user_pin = user_pin.encode()
+ if isinstance(library_path, unicode):
+ library_path = library_path.encode()
+ self.slot = slot
+
+ try:
+ pGetFunctionList, module_handle = loadLibrary(library_path)
+ except Exception:
+ raise Error("Could not load the library.")
+
+ self.module_handle = module_handle
+
+ #
+ # Load the function list
+ #
+ pGetFunctionList(self.p11_ptr)
+
+ #
+ # Initialize
+ #
+ rv = self.p11.C_Initialize(NULL)
+ check_return_value(rv, "initialize")
+
+ #
+ # Start session
+ #
+ rv = self.p11.C_OpenSession(self.slot,
+ CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL,
+ NULL, self.session_ptr)
+ check_return_value(rv, "open session")
+
+ #
+ # Login
+ #
+ rv = self.p11.C_Login(self.session, CKU_USER, user_pin, len(user_pin))
+ check_return_value(rv, "log in")
+
+ def finalize(self):
+ """
+ Finalize operations with pkcs11 library
+ """
+ if self.p11 == NULL:
+ return
+
+ #
+ # Logout
+ #
+ rv = self.p11.C_Logout(self.session)
+ check_return_value(rv, "log out")
+
+ #
+ # End session
+ #
+ rv = self.p11.C_CloseSession(self.session)
+ check_return_value(rv, "close session")
+
+ #
+ # Finalize
+ #
+ self.p11.C_Finalize(NULL)
+
+ self.p11_ptr[0] = NULL
+ self.session_ptr[0] = 0
+ self.slot = 0
+ self.module_handle = None
+
+ #################################################################
+ # Methods working with keys
+ #
+
+ def generate_master_key(self, label, id, key_length=16, cka_copyable=True,
+ cka_decrypt=False, cka_derive=False,
+ cka_encrypt=False, cka_extractable=True,
+ cka_modifiable=True, cka_private=True,
+ cka_sensitive=True, cka_sign=False,
+ cka_unwrap=True, cka_verify=False, cka_wrap=True,
+ cka_wrap_with_trusted=False):
+ """
+ Generate master key
+
+ :return: master key handle
+ """
+ if isinstance(id, unicode):
+ id = id.encode()
+
+ attrs = (
+ cka_copyable,
+ cka_decrypt,
+ cka_derive,
+ cka_encrypt,
+ cka_extractable,
+ cka_modifiable,
+ cka_private,
+ cka_sensitive,
+ cka_sign,
+ cka_unwrap,
+ cka_verify,
+ cka_wrap,
+ cka_wrap_with_trusted,
+ )
+
+ key_length_ptr = new_ptr(CK_ULONG, key_length)
+ master_key_ptr = new_ptr(CK_OBJECT_HANDLE)
+
+ label_unicode = label
+ id_length = len(id)
+ id_ = new_array(CK_BYTE, id)
+ # TODO check long overflow
+
+ label, label_length = unicode_to_char_array(label_unicode)
+
+ # TODO param?
+ mechanism_ptr = new_ptr(CK_MECHANISM, (
+ CKM_AES_KEY_GEN, NULL_PTR, 0
+ ))
+
+ if key_length not in (16, 24, 32):
+ raise Error("generate_master_key: key length allowed values are: "
+ "16, 24 and 32")
+
+ if self._id_exists(id_, id_length, CKO_SECRET_KEY):
+ raise DuplicationError("Master key with same ID already exists")
+
+ # Process keyword boolean arguments
+ (cka_copyable_ptr, cka_decrypt_ptr, cka_derive_ptr, cka_encrypt_ptr,
+ cka_extractable_ptr, cka_modifiable_ptr, cka_private_ptr,
+ cka_sensitive_ptr, cka_sign_ptr, cka_unwrap_ptr, cka_verify_ptr,
+ cka_wrap_ptr, cka_wrap_with_trusted_ptr,) = convert_py2bool(attrs)
+
+ symKeyTemplate = new_array(CK_ATTRIBUTE, (
+ (CKA_ID, id_, id_length),
+ (CKA_LABEL, label, label_length),
+ (CKA_TOKEN, true_ptr, sizeof(CK_BBOOL)),
+ (CKA_VALUE_LEN, key_length_ptr, sizeof(CK_ULONG)),
+ # TODO Softhsm doesn't support it
+ # (CKA_COPYABLE, cka_copyable_ptr, sizeof(CK_BBOOL)),
+ (CKA_DECRYPT, cka_decrypt_ptr, sizeof(CK_BBOOL)),
+ (CKA_DERIVE, cka_derive_ptr, sizeof(CK_BBOOL)),
+ (CKA_ENCRYPT, cka_encrypt_ptr, sizeof(CK_BBOOL)),
+ (CKA_EXTRACTABLE, cka_extractable_ptr, sizeof(CK_BBOOL)),
+ (CKA_MODIFIABLE, cka_modifiable_ptr, sizeof(CK_BBOOL)),
+ (CKA_PRIVATE, cka_private_ptr, sizeof(CK_BBOOL)),
+ (CKA_SENSITIVE, cka_sensitive_ptr, sizeof(CK_BBOOL)),
+ (CKA_SIGN, cka_sign_ptr, sizeof(CK_BBOOL)),
+ (CKA_UNWRAP, cka_unwrap_ptr, sizeof(CK_BBOOL)),
+ (CKA_VERIFY, cka_verify_ptr, sizeof(CK_BBOOL)),
+ (CKA_WRAP, cka_wrap_ptr, sizeof(CK_BBOOL)),
+ (CKA_WRAP_WITH_TRUSTED, cka_wrap_with_trusted_ptr,
+ sizeof(CK_BBOOL)),
+ ))
+
+ rv = self.p11.C_GenerateKey(self.session, mechanism_ptr,
+ symKeyTemplate,
+ (sizeof(symKeyTemplate) //
+ sizeof(CK_ATTRIBUTE)), master_key_ptr)
+ check_return_value(rv, "generate master key")
+
+ return master_key_ptr[0]
+
+ def generate_replica_key_pair(self, label, id, modulus_bits=2048,
+ pub_cka_copyable=True, pub_cka_derive=False,
+ pub_cka_encrypt=False,
+ pub_cka_modifiable=True,
+ pub_cka_private=True, pub_cka_trusted=False,
+ pub_cka_verify=False,
+ pub_cka_verify_recover=False,
+ pub_cka_wrap=True,
+ priv_cka_always_authenticate=False,
+ priv_cka_copyable=True,
+ priv_cka_decrypt=False,
+ priv_cka_derive=False,
+ priv_cka_extractable=False,
+ priv_cka_modifiable=True,
+ priv_cka_private=True,
+ priv_cka_sensitive=True,
+ priv_cka_sign=False,
+ priv_cka_sign_recover=False,
+ priv_cka_unwrap=True,
+ priv_cka_wrap_with_trusted=False):
+ """
+ Generate replica keys
+
+ :returns: tuple (public_key_handle, private_key_handle)
+ """
+ if isinstance(id, unicode):
+ id = id.encode()
+
+ attrs_pub = (
+ pub_cka_copyable,
+ pub_cka_derive,
+ pub_cka_encrypt,
+ pub_cka_modifiable,
+ pub_cka_private,
+ pub_cka_trusted,
+ pub_cka_verify,
+ pub_cka_verify_recover,
+ pub_cka_wrap,
+ )
+
+ attrs_priv = (
+ priv_cka_always_authenticate,
+ priv_cka_copyable,
+ priv_cka_decrypt,
+ priv_cka_derive,
+ priv_cka_extractable,
+ priv_cka_modifiable,
+ priv_cka_private,
+ priv_cka_sensitive,
+ priv_cka_sign,
+ priv_cka_sign_recover,
+ priv_cka_unwrap,
+ priv_cka_wrap_with_trusted,
+ )
+
+ label_unicode = label
+ id_ = new_array(CK_BYTE, id)
+ id_length = len(id)
+
+ label, label_length = unicode_to_char_array(label_unicode)
+
+ public_key_ptr = new_ptr(CK_OBJECT_HANDLE)
+ private_key_ptr = new_ptr(CK_OBJECT_HANDLE)
+ mechanism_ptr = new_ptr(CK_MECHANISM,
+ (CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0))
+
+ if self._id_exists(id_, id_length, CKO_PRIVATE_KEY):
+ raise DuplicationError("Private key with same ID already exists")
+
+ if self._id_exists(id_, id_length, CKO_PUBLIC_KEY):
+ raise DuplicationError("Public key with same ID already exists")
+
+ modulus_bits_ptr = new_ptr(CK_ULONG, modulus_bits)
+
+ # Process keyword boolean arguments
+ (pub_cka_copyable_ptr, pub_cka_derive_ptr, pub_cka_encrypt_ptr,
+ pub_cka_modifiable_ptr, pub_cka_private_ptr, pub_cka_trusted_ptr,
+ pub_cka_verify_ptr, pub_cka_verify_recover_ptr, pub_cka_wrap_ptr,
+ ) = convert_py2bool(attrs_pub)
+ (priv_cka_always_authenticate_ptr, priv_cka_copyable_ptr,
+ priv_cka_decrypt_ptr, priv_cka_derive_ptr, priv_cka_extractable_ptr,
+ priv_cka_modifiable_ptr, priv_cka_private_ptr, priv_cka_sensitive_ptr,
+ priv_cka_sign_ptr, priv_cka_sign_recover_ptr, priv_cka_unwrap_ptr,
+ priv_cka_wrap_with_trusted_ptr,) = convert_py2bool(attrs_priv)
+
+ # 65537 (RFC 6376 section 3.3.1)
+ public_exponent = new_array(CK_BYTE, (1, 0, 1))
+ publicKeyTemplate = new_array(CK_ATTRIBUTE, (
+ (CKA_ID, id_, id_length),
+ (CKA_LABEL, label, label_length),
+ (CKA_TOKEN, true_ptr, sizeof(CK_BBOOL)),
+ (CKA_MODULUS_BITS, modulus_bits_ptr, sizeof(CK_ULONG)),
+ (CKA_PUBLIC_EXPONENT, public_exponent, 3),
+ # TODO Softhsm doesn't support it
+ # (CKA_COPYABLE, pub_cka_copyable_p, sizeof(CK_BBOOL)),
+ (CKA_DERIVE, pub_cka_derive_ptr, sizeof(CK_BBOOL)),
+ (CKA_ENCRYPT, pub_cka_encrypt_ptr, sizeof(CK_BBOOL)),
+ (CKA_MODIFIABLE, pub_cka_modifiable_ptr, sizeof(CK_BBOOL)),
+ (CKA_PRIVATE, pub_cka_private_ptr, sizeof(CK_BBOOL)),
+ (CKA_TRUSTED, pub_cka_trusted_ptr, sizeof(CK_BBOOL)),
+ (CKA_VERIFY, pub_cka_verify_ptr, sizeof(CK_BBOOL)),
+ (CKA_VERIFY_RECOVER, pub_cka_verify_recover_ptr, sizeof(CK_BBOOL)),
+ (CKA_WRAP, pub_cka_wrap_ptr, sizeof(CK_BBOOL)),
+ ))
+
+ privateKeyTemplate = new_array(CK_ATTRIBUTE, (
+ (CKA_ID, id_, id_length),
+ (CKA_LABEL, label, label_length),
+ (CKA_TOKEN, true_ptr, sizeof(CK_BBOOL)),
+ (CKA_ALWAYS_AUTHENTICATE, priv_cka_always_authenticate_ptr,
+ sizeof(CK_BBOOL)),
+ # TODO Softhsm doesn't support it
+ # (CKA_COPYABLE, priv_cka_copyable_ptr, sizeof(CK_BBOOL)),
+ (CKA_DECRYPT, priv_cka_decrypt_ptr, sizeof(CK_BBOOL)),
+ (CKA_DERIVE, priv_cka_derive_ptr, sizeof(CK_BBOOL)),
+ (CKA_EXTRACTABLE, priv_cka_extractable_ptr, sizeof(CK_BBOOL)),
+ (CKA_MODIFIABLE, priv_cka_modifiable_ptr, sizeof(CK_BBOOL)),
+ (CKA_PRIVATE, priv_cka_private_ptr, sizeof(CK_BBOOL)),
+ (CKA_SENSITIVE, priv_cka_sensitive_ptr, sizeof(CK_BBOOL)),
+ (CKA_SIGN, priv_cka_sign_ptr, sizeof(CK_BBOOL)),
+ (CKA_SIGN_RECOVER, priv_cka_sign_ptr, sizeof(CK_BBOOL)),
+ (CKA_UNWRAP, priv_cka_unwrap_ptr, sizeof(CK_BBOOL)),
+ (CKA_WRAP_WITH_TRUSTED, priv_cka_wrap_with_trusted_ptr,
+ sizeof(CK_BBOOL)),
+ ))
+
+ rv = self.p11.C_GenerateKeyPair(self.session, mechanism_ptr,
+ publicKeyTemplate,
+ (sizeof(publicKeyTemplate) //
+ sizeof(CK_ATTRIBUTE)),
+ privateKeyTemplate,
+ (sizeof(privateKeyTemplate) //
+ sizeof(CK_ATTRIBUTE)),
+ public_key_ptr,
+ private_key_ptr)
+ check_return_value(rv, "generate key pair")
+
+ return public_key_ptr[0], private_key_ptr[0]
+
+ def find_keys(self, objclass=CKO_VENDOR_DEFINED, label=None, id=None,
+ cka_wrap=None, cka_unwrap=None, uri=None):
+ """
+ Find key
+ """
+ if isinstance(id, unicode):
+ id = id.encode()
+ if isinstance(uri, unicode):
+ uri = uri.encode()
+
+ class_ = objclass
+ class_ptr = new_ptr(CK_OBJECT_CLASS, class_)
+ ckawrap = NULL
+ ckaunwrap = NULL
+ if id is not None:
+ id_ = new_array(CK_BYTE, id)
+ id_length = len(id)
+ else:
+ id_ = NULL
+ id_length = 0
+ label_unicode, label = label, NULL
+ cka_wrap_bool = cka_wrap
+ cka_unwrap_bool = cka_unwrap
+ label_length = 0
+ uri_str = uri
+ uri = NULL
+ template = new_array(CK_ATTRIBUTE, MAX_TEMPLATE_LEN)
+ template_len_ptr = new_ptr(CK_ULONG, MAX_TEMPLATE_LEN)
+
+ # TODO check long overflow
+
+ if label_unicode is not None:
+ label, label_length = unicode_to_char_array(label_unicode)
+
+ if cka_wrap_bool is not None:
+ if cka_wrap_bool:
+ ckawrap = true_ptr
+ else:
+ ckawrap = false_ptr
+
+ if cka_unwrap_bool is not None:
+ if cka_unwrap_bool:
+ ckaunwrap = true_ptr
+ else:
+ ckaunwrap = false_ptr
+
+ if class_ == CKO_VENDOR_DEFINED:
+ class_ptr = NULL
+
+ try:
+ if uri_str is None:
+ _fill_template_from_parts(template, template_len_ptr, id_,
+ id_length, label, label_length,
+ class_ptr, ckawrap, ckaunwrap)
+ else:
+ uri = _parse_uri(uri_str)
+ template = (p11_kit_uri_get_attributes(uri, template_len_ptr))
+ # Do not deallocate URI while you are using the template.
+ # Template contains pointers to values inside URI!
+
+ result_list = self._find_key(template, template_len_ptr[0])
+
+ return result_list
+ finally:
+ if uri != NULL:
+ p11_kit_uri_free(uri)
+
+ def delete_key(self, key_handle):
+ """
+ delete key
+ """
+ # TODO check long overflow
+ rv = self.p11.C_DestroyObject(self.session, key_handle)
+ check_return_value(rv, "object deletion")
+
+ def _export_RSA_public_key(self, object):
+ """
+ export RSA public key
+ """
+ pp_ptr = new_ptr(unsigned_char_ptr, NULL)
+ pkey = NULL
+ e = NULL
+ n = NULL
+ rsa = NULL
+ class_ptr = new_ptr(CK_OBJECT_CLASS, CKO_PUBLIC_KEY)
+ key_type_ptr = new_ptr(CK_KEY_TYPE, CKK_RSA)
+
+ obj_template = new_array(CK_ATTRIBUTE, (
+ (CKA_MODULUS, NULL_PTR, 0),
+ (CKA_PUBLIC_EXPONENT, NULL_PTR, 0),
+ (CKA_CLASS, class_ptr, sizeof(CK_OBJECT_CLASS)),
+ (CKA_KEY_TYPE, key_type_ptr, sizeof(CK_KEY_TYPE)),
+ ))
+
+ rv = self.p11.C_GetAttributeValue(self.session, object, obj_template,
+ (sizeof(obj_template) //
+ sizeof(CK_ATTRIBUTE)))
+ check_return_value(rv, "get RSA public key values - prepare")
+
+ # Set proper size for attributes
+ modulus = new_array(CK_BYTE,
+ obj_template[0].ulValueLen * sizeof(CK_BYTE))
+ obj_template[0].pValue = modulus
+ exponent = new_array(CK_BYTE,
+ obj_template[1].ulValueLen * sizeof(CK_BYTE))
+ obj_template[1].pValue = exponent
+
+ rv = self.p11.C_GetAttributeValue(self.session, object, obj_template,
+ (sizeof(obj_template) //
+ sizeof(CK_ATTRIBUTE)))
+ check_return_value(rv, "get RSA public key values")
+
+ # Check if the key is RSA public key
+ if class_ptr[0] != CKO_PUBLIC_KEY:
+ raise Error("export_RSA_public_key: required public key class")
+
+ if key_type_ptr[0] != CKK_RSA:
+ raise Error("export_RSA_public_key: required RSA key type")
+
+ try:
+ rsa = RSA_new()
+ pkey = EVP_PKEY_new()
+ n = BN_bin2bn(modulus,
+ obj_template[0].ulValueLen * sizeof(CK_BYTE), NULL)
+ if n == NULL:
+ raise Error("export_RSA_public_key: internal error: unable to "
+ "convert modulus")
+
+ e = BN_bin2bn(exponent,
+ obj_template[1].ulValueLen * sizeof(CK_BYTE), NULL)
+ if e == NULL:
+ raise Error("export_RSA_public_key: internal error: unable to "
+ "convert exponent")
+
+ # set modulus and exponent
+ rsa.n = n
+ rsa.e = e
+
+ if EVP_PKEY_set1_RSA(pkey, rsa) == 0:
+ raise Error("export_RSA_public_key: internal error: "
+ "EVP_PKEY_set1_RSA failed")
+
+ pp_len = i2d_PUBKEY(pkey, pp_ptr)
+ ret = string_to_pybytes_or_none(pp_ptr[0], pp_len)
+
+ return ret
+ finally:
+ if rsa != NULL:
+ # this frees also 'n' and 'e'
+ RSA_free(rsa)
+ else:
+ if n != NULL:
+ BN_free(n)
+ if e != NULL:
+ BN_free(e)
+
+ if pkey != NULL:
+ EVP_PKEY_free(pkey)
+ if pp_ptr[0] != NULL:
+ free(pp_ptr[0])
+
+ def export_public_key(self, key_handle):
+ """
+ Export public key
+
+ Export public key in SubjectPublicKeyInfo (RFC5280) DER encoded format
+ """
+ object = key_handle
+ class_ptr = new_ptr(CK_OBJECT_CLASS, CKO_PUBLIC_KEY)
+ key_type_ptr = new_ptr(CK_KEY_TYPE, CKK_RSA)
+ # TODO check long overflow
+
+ obj_template = new_array(CK_ATTRIBUTE, (
+ (CKA_CLASS, class_ptr, sizeof(CK_OBJECT_CLASS)),
+ (CKA_KEY_TYPE, key_type_ptr, sizeof(CK_KEY_TYPE)),
+ ))
+
+ rv = self.p11.C_GetAttributeValue(self.session, object, obj_template,
+ (sizeof(obj_template) //
+ sizeof(CK_ATTRIBUTE)))
+ check_return_value(rv, "export_public_key: get RSA public key values")
+
+ if class_ptr[0] != CKO_PUBLIC_KEY:
+ raise Error("export_public_key: required public key class")
+
+ if key_type_ptr[0] == CKK_RSA:
+ return self._export_RSA_public_key(object)
+ else:
+ raise Error("export_public_key: unsupported key type")
+
+ def _import_RSA_public_key(self, label, label_length, id, id_length, pkey,
+ cka_copyable, cka_derive, cka_encrypt,
+ cka_modifiable, cka_private, cka_trusted,
+ cka_verify, cka_verify_recover, cka_wrap):
+ """
+ Import RSA public key
+ """
+ class_ptr = new_ptr(CK_OBJECT_CLASS, CKO_PUBLIC_KEY)
+ keyType_ptr = new_ptr(CK_KEY_TYPE, CKK_RSA)
+ cka_token = true_ptr
+ rsa = NULL
+
+ if pkey.type != EVP_PKEY_RSA:
+ raise Error("Required RSA public key")
+
+ try:
+ rsa = EVP_PKEY_get1_RSA(pkey)
+ if rsa == NULL:
+ raise Error("import_RSA_public_key: EVP_PKEY_get1_RSA error")
+
+ # convert BIGNUM to binary array
+ modulus = new_array(CK_BYTE, BN_num_bytes(rsa.n))
+ modulus_len = BN_bn2bin(rsa.n, modulus)
+ if modulus_len == 0:
+ raise Error("import_RSA_public_key: BN_bn2bin modulus error")
+
+ exponent = new_array(CK_BYTE, BN_num_bytes(rsa.e))
+ exponent_len = BN_bn2bin(rsa.e, exponent)
+ if exponent_len == 0:
+ raise Error("import_RSA_public_key: BN_bn2bin exponent error")
+
+ template = new_array(CK_ATTRIBUTE, (
+ (CKA_ID, id, id_length),
+ (CKA_CLASS, class_ptr, sizeof(CK_OBJECT_CLASS)),
+ (CKA_KEY_TYPE, keyType_ptr, sizeof(CK_KEY_TYPE)),
+ (CKA_TOKEN, cka_token, sizeof(CK_BBOOL)),
+ (CKA_LABEL, label, label_length),
+ (CKA_MODULUS, modulus, modulus_len),
+ (CKA_PUBLIC_EXPONENT, exponent, exponent_len),
+ # TODO Softhsm doesn't support it
+ # (CKA_COPYABLE, cka_copyable, sizeof(CK_BBOOL)),
+ (CKA_DERIVE, cka_derive, sizeof(CK_BBOOL)),
+ (CKA_ENCRYPT, cka_encrypt, sizeof(CK_BBOOL)),
+ (CKA_MODIFIABLE, cka_modifiable, sizeof(CK_BBOOL)),
+ (CKA_PRIVATE, cka_private, sizeof(CK_BBOOL)),
+ (CKA_TRUSTED, cka_trusted, sizeof(CK_BBOOL)),
+ (CKA_VERIFY, cka_verify, sizeof(CK_BBOOL)),
+ (CKA_VERIFY_RECOVER, cka_verify_recover, sizeof(CK_BBOOL)),
+ (CKA_WRAP, cka_wrap, sizeof(CK_BBOOL)),
+ ))
+ object_ptr = new_ptr(CK_OBJECT_HANDLE)
+
+ rv = self.p11.C_CreateObject(self.session, template,
+ (sizeof(template) //
+ sizeof(CK_ATTRIBUTE)), object_ptr)
+ check_return_value(rv, "create public key object")
+
+ return object_ptr[0]
+ finally:
+ if rsa != NULL:
+ RSA_free(rsa)
+
+ def import_public_key(self, label, id, data, cka_copyable=True,
+ cka_derive=False, cka_encrypt=False,
+ cka_modifiable=True, cka_private=True,
+ cka_trusted=False, cka_verify=True,
+ cka_verify_recover=True, cka_wrap=False):
+ """
+ Import RSA public key
+ """
+ if isinstance(id, unicode):
+ id = id.encode()
+ if isinstance(data, unicode):
+ data = data.encode()
+
+ label_unicode = label
+ id_ = new_array(CK_BYTE, id)
+ data_ = new_array(CK_BYTE, data)
+ data_ptr = new_ptr(CK_BYTE_PTR, data_)
+ id_length = len(id)
+ data_length = len(data)
+ pkey = NULL
+
+ attrs_pub = (
+ cka_copyable,
+ cka_derive,
+ cka_encrypt,
+ cka_modifiable,
+ cka_private,
+ cka_trusted,
+ cka_verify,
+ cka_verify_recover,
+ cka_wrap,
+ )
+
+ label, label_length = unicode_to_char_array(label_unicode)
+
+ if self._id_exists(id_, id_length, CKO_PUBLIC_KEY):
+ raise DuplicationError("Public key with same ID already exists")
+
+ # Process keyword boolean arguments
+ (cka_copyable_ptr, cka_derive_ptr, cka_encrypt_ptr, cka_modifiable_ptr,
+ cka_private_ptr, cka_trusted_ptr, cka_verify_ptr,
+ cka_verify_recover_ptr, cka_wrap_ptr,) = convert_py2bool(attrs_pub)
+
+ try:
+ # decode from ASN1 DER
+ pkey = d2i_PUBKEY(NULL, data_ptr, data_length)
+ if pkey == NULL:
+ raise Error("import_public_key: d2i_PUBKEY error")
+ if pkey.type == EVP_PKEY_RSA:
+ ret = self._import_RSA_public_key(label, label_length, id_,
+ id_length, pkey,
+ cka_copyable_ptr,
+ cka_derive_ptr,
+ cka_encrypt_ptr,
+ cka_modifiable_ptr,
+ cka_private_ptr,
+ cka_trusted_ptr,
+ cka_verify_ptr,
+ cka_verify_recover_ptr,
+ cka_wrap_ptr)
+ elif pkey.type == EVP_PKEY_DSA:
+ raise Error("DSA is not supported")
+ elif pkey.type == EVP_PKEY_EC:
+ raise Error("EC is not supported")
+ else:
+ raise Error("Unsupported key type")
+
+ return ret
+ finally:
+ if pkey != NULL:
+ EVP_PKEY_free(pkey)
+
+ def export_wrapped_key(self, key, wrapping_key, wrapping_mech):
+ """
+ Export wrapped key
+ """
+ object_key = key
+ object_wrapping_key = wrapping_key
+ wrapped_key_len_ptr = new_ptr(CK_ULONG, 0)
+ wrapping_mech_ptr = new_ptr(CK_MECHANISM, (wrapping_mech, NULL, 0))
+ # currently we don't support parameter in mechanism
+
+ # TODO check long overflow
+ # TODO export method
+
+ # fill mech parameters
+ _set_wrapping_mech_parameters(wrapping_mech_ptr.mechanism,
+ wrapping_mech_ptr)
+
+ rv = self.p11.C_WrapKey(self.session, wrapping_mech_ptr,
+ object_wrapping_key, object_key, NULL,
+ wrapped_key_len_ptr)
+ check_return_value(rv, "key wrapping: get buffer length")
+
+ wrapped_key = new_array(CK_BYTE, wrapped_key_len_ptr[0])
+
+ rv = self.p11.C_WrapKey(self.session, wrapping_mech_ptr,
+ object_wrapping_key, object_key, wrapped_key,
+ wrapped_key_len_ptr)
+ check_return_value(rv, "key wrapping: wrapping")
+
+ result = string_to_pybytes_or_none(wrapped_key, wrapped_key_len_ptr[0])
+
+ return result
+
+ def import_wrapped_secret_key(self, label, id, data, unwrapping_key,
+ wrapping_mech, key_type, cka_copyable=True,
+ cka_decrypt=False, cka_derive=False,
+ cka_encrypt=False, cka_extractable=True,
+ cka_modifiable=True, cka_private=True,
+ cka_sensitive=True, cka_sign=False,
+ cka_unwrap=True, cka_verify=False,
+ cka_wrap=True, cka_wrap_with_trusted=False):
+ """
+ Import wrapped secret key
+ """
+ if isinstance(id, unicode):
+ id = id.encode()
+ if isinstance(data, unicode):
+ data = data.encode()
+
+ wrapped_key = new_array(CK_BYTE, data)
+ wrapped_key_len = len(data)
+ unwrapping_key_object = unwrapping_key
+ unwrapped_key_object_ptr = new_ptr(CK_OBJECT_HANDLE, 0)
+ label_unicode = label
+ id_ = new_array(CK_BYTE, id)
+ id_length = len(id)
+ wrapping_mech_ptr = new_ptr(CK_MECHANISM, (wrapping_mech, NULL, 0))
+ key_class_ptr = new_ptr(CK_OBJECT_CLASS, CKO_SECRET_KEY)
+ key_type_ptr = new_ptr(CK_KEY_TYPE, key_type)
+
+ attrs = (
+ cka_copyable,
+ cka_decrypt,
+ cka_derive,
+ cka_encrypt,
+ cka_extractable,
+ cka_modifiable,
+ cka_private,
+ cka_sensitive,
+ cka_sign,
+ cka_unwrap,
+ cka_verify,
+ cka_wrap,
+ cka_wrap_with_trusted,
+ )
+
+ _set_wrapping_mech_parameters(wrapping_mech_ptr.mechanism,
+ wrapping_mech_ptr)
+
+ label, label_length = unicode_to_char_array(label_unicode)
+
+ if self._id_exists(id_, id_length, key_class_ptr[0]):
+ raise DuplicationError("Secret key with same ID already exists")
+
+ # Process keyword boolean arguments
+ (cka_copyable_ptr, cka_decrypt_ptr, cka_derive_ptr, cka_encrypt_ptr,
+ cka_extractable_ptr, cka_modifiable_ptr, cka_private_ptr,
+ cka_sensitive_ptr, cka_sign_ptr, cka_unwrap_ptr, cka_verify_ptr,
+ cka_wrap_ptr, cka_wrap_with_trusted_ptr,) = convert_py2bool(attrs)
+
+ template = new_array(CK_ATTRIBUTE, (
+ (CKA_CLASS, key_class_ptr, sizeof(CK_OBJECT_CLASS)),
+ (CKA_KEY_TYPE, key_type_ptr, sizeof(CK_KEY_TYPE)),
+ (CKA_ID, id_, id_length),
+ (CKA_LABEL, label, label_length),
+ (CKA_TOKEN, true_ptr, sizeof(CK_BBOOL)),
+ # TODO Softhsm doesn't support it
+ # (CKA_COPYABLE, cka_copyable_ptr, sizeof(CK_BBOOL)),
+ (CKA_DECRYPT, cka_decrypt_ptr, sizeof(CK_BBOOL)),
+ (CKA_DERIVE, cka_derive_ptr, sizeof(CK_BBOOL)),
+ (CKA_ENCRYPT, cka_encrypt_ptr, sizeof(CK_BBOOL)),
+ (CKA_EXTRACTABLE, cka_extractable_ptr, sizeof(CK_BBOOL)),
+ (CKA_MODIFIABLE, cka_modifiable_ptr, sizeof(CK_BBOOL)),
+ (CKA_PRIVATE, cka_private_ptr, sizeof(CK_BBOOL)),
+ (CKA_SENSITIVE, cka_sensitive_ptr, sizeof(CK_BBOOL)),
+ (CKA_SIGN, cka_sign_ptr, sizeof(CK_BBOOL)),
+ (CKA_UNWRAP, cka_unwrap_ptr, sizeof(CK_BBOOL)),
+ (CKA_VERIFY, cka_verify_ptr, sizeof(CK_BBOOL)),
+ (CKA_WRAP, cka_wrap_ptr, sizeof(CK_BBOOL)),
+ (CKA_WRAP_WITH_TRUSTED, cka_wrap_with_trusted_ptr,
+ sizeof(CK_BBOOL)),
+ ))
+
+ rv = self.p11.C_UnwrapKey(self.session, wrapping_mech_ptr,
+ unwrapping_key_object, wrapped_key,
+ wrapped_key_len, template,
+ sizeof(template) // sizeof(CK_ATTRIBUTE),
+ unwrapped_key_object_ptr)
+ check_return_value(rv, "import_wrapped_key: key unwrapping")
+
+ return unwrapped_key_object_ptr[0]
+
+ def import_wrapped_private_key(self, label, id, data, unwrapping_key,
+ wrapping_mech, key_type,
+ cka_always_authenticate=False,
+ cka_copyable=True, cka_decrypt=False,
+ cka_derive=False, cka_extractable=True,
+ cka_modifiable=True, cka_private=True,
+ cka_sensitive=True, cka_sign=True,
+ cka_sign_recover=True, cka_unwrap=False,
+ cka_wrap_with_trusted=False):
+ """
+ Import wrapped private key
+ """
+ if isinstance(id, unicode):
+ id = id.encode()
+ if isinstance(data, unicode):
+ data = data.encode()
+
+ wrapped_key = new_array(CK_BYTE, data)
+ wrapped_key_len = len(data)
+ unwrapping_key_object = unwrapping_key
+ unwrapped_key_object_ptr = new_ptr(CK_OBJECT_HANDLE, 0)
+ label_unicode = label
+ id_ = new_array(CK_BYTE, id)
+ id_length = len(id)
+ wrapping_mech_ptr = new_ptr(CK_MECHANISM, (wrapping_mech, NULL, 0))
+ key_class_ptr = new_ptr(CK_OBJECT_CLASS, CKO_PRIVATE_KEY)
+ key_type_ptr = new_ptr(CK_KEY_TYPE, key_type)
+
+ attrs_priv = (
+ cka_always_authenticate,
+ cka_copyable,
+ cka_decrypt,
+ cka_derive,
+ cka_extractable,
+ cka_modifiable,
+ cka_private,
+ cka_sensitive,
+ cka_sign,
+ cka_sign_recover,
+ cka_unwrap,
+ cka_wrap_with_trusted,
+ )
+
+ label, label_length = unicode_to_char_array(label_unicode)
+
+ if self._id_exists(id_, id_length, CKO_SECRET_KEY):
+ raise DuplicationError("Secret key with same ID already exists")
+
+ # Process keyword boolean arguments
+ (cka_always_authenticate_ptr, cka_copyable_ptr, cka_decrypt_ptr,
+ cka_derive_ptr, cka_extractable_ptr, cka_modifiable_ptr,
+ cka_private_ptr, cka_sensitive_ptr, cka_sign_ptr,
+ cka_sign_recover_ptr, cka_unwrap_ptr, cka_wrap_with_trusted_ptr,
+ ) = convert_py2bool(attrs_priv)
+
+ template = new_array(CK_ATTRIBUTE, (
+ (CKA_CLASS, key_class_ptr, sizeof(CK_OBJECT_CLASS)),
+ (CKA_KEY_TYPE, key_type_ptr, sizeof(CK_KEY_TYPE)),
+ (CKA_ID, id_, id_length),
+ (CKA_LABEL, label, label_length),
+ (CKA_TOKEN, true_ptr, sizeof(CK_BBOOL)),
+ (CKA_ALWAYS_AUTHENTICATE, cka_always_authenticate_ptr,
+ sizeof(CK_BBOOL)),
+ # TODO Softhsm doesn't support it
+ # (CKA_COPYABLE, cka_copyable_ptr, sizeof(CK_BBOOL)),
+ (CKA_DECRYPT, cka_decrypt_ptr, sizeof(CK_BBOOL)),
+ (CKA_DERIVE, cka_derive_ptr, sizeof(CK_BBOOL)),
+ (CKA_EXTRACTABLE, cka_extractable_ptr, sizeof(CK_BBOOL)),
+ (CKA_MODIFIABLE, cka_modifiable_ptr, sizeof(CK_BBOOL)),
+ (CKA_PRIVATE, cka_private_ptr, sizeof(CK_BBOOL)),
+ (CKA_SENSITIVE, cka_sensitive_ptr, sizeof(CK_BBOOL)),
+ (CKA_SIGN, cka_sign_ptr, sizeof(CK_BBOOL)),
+ (CKA_SIGN_RECOVER, cka_sign_ptr, sizeof(CK_BBOOL)),
+ (CKA_UNWRAP, cka_unwrap_ptr, sizeof(CK_BBOOL)),
+ (CKA_WRAP_WITH_TRUSTED, cka_wrap_with_trusted_ptr,
+ sizeof(CK_BBOOL)),
+ ))
+
+ rv = self.p11.C_UnwrapKey(self.session, wrapping_mech_ptr,
+ unwrapping_key_object, wrapped_key,
+ wrapped_key_len, template,
+ sizeof(template) // sizeof(CK_ATTRIBUTE),
+ unwrapped_key_object_ptr)
+ check_return_value(rv, "import_wrapped_key: key unwrapping")
+
+ return unwrapped_key_object_ptr[0]
+
+ def set_attribute(self, key_object, attr, value):
+ """
+ Set object attributes
+ """
+ object = key_object
+ attribute_ptr = new_ptr(CK_ATTRIBUTE)
+
+ attribute_ptr.type = attr
+ if attr in (CKA_ALWAYS_AUTHENTICATE,
+ CKA_ALWAYS_SENSITIVE,
+ CKA_COPYABLE,
+ CKA_ENCRYPT,
+ CKA_EXTRACTABLE,
+ CKA_DECRYPT,
+ CKA_DERIVE,
+ CKA_LOCAL,
+ CKA_MODIFIABLE,
+ CKA_NEVER_EXTRACTABLE,
+ CKA_PRIVATE,
+ CKA_SENSITIVE,
+ CKA_SIGN,
+ CKA_SIGN_RECOVER,
+ CKA_TOKEN,
+ CKA_TRUSTED,
+ CKA_UNWRAP,
+ CKA_VERIFY,
+ CKA_VERIFY_RECOVER,
+ CKA_WRAP,
+ CKA_WRAP_WITH_TRUSTED):
+ attribute_ptr.pValue = true_ptr if value else false_ptr
+ attribute_ptr.ulValueLen = sizeof(CK_BBOOL)
+ elif attr == CKA_ID:
+ if not isinstance(value, bytes):
+ raise Error("Bytestring value expected")
+ attribute_ptr.pValue = new_array(CK_BYTE, value)
+ attribute_ptr.ulValueLen = len(value)
+ elif attr == CKA_LABEL:
+ if not isinstance(value, unicode):
+ raise Error("Unicode value expected")
+ label, label_length = unicode_to_char_array(value)
+ attribute_ptr.pValue = label
+ attribute_ptr.ulValueLen = label_length
+ elif attr == CKA_KEY_TYPE:
+ if not isinstance(value, int):
+ raise Error("Integer value expected")
+ attribute_ptr.pValue = new_ptr(unsigned_long, value)
+ attribute_ptr.ulValueLen = sizeof(unsigned_long)
+ else:
+ raise Error("Unknown attribute")
+
+ template = new_array(CK_ATTRIBUTE, (attribute_ptr[0],))
+
+ rv = self.p11.C_SetAttributeValue(self.session, object, template,
+ (sizeof(template) //
+ sizeof(CK_ATTRIBUTE)))
+ check_return_value(rv, "set_attribute")
+
+ def get_attribute(self, key_object, attr):
+ object = key_object
+ attribute_ptr = new_ptr(CK_ATTRIBUTE)
+
+ attribute_ptr.type = attr
+ attribute_ptr.pValue = NULL_PTR
+ attribute_ptr.ulValueLen = 0
+ template = new_array(CK_ATTRIBUTE, (attribute_ptr[0],))
+
+ rv = self.p11.C_GetAttributeValue(self.session, object, template,
+ (sizeof(template) //
+ sizeof(CK_ATTRIBUTE)))
+ if rv == CKR_ATTRIBUTE_TYPE_INVALID or template[0].ulValueLen == -1:
+ raise NotFound("attribute does not exist")
+ check_return_value(rv, "get_attribute init")
+ value = new_array(unsigned_char, template[0].ulValueLen)
+ template[0].pValue = value
+
+ rv = self.p11.C_GetAttributeValue(self.session, object, template,
+ (sizeof(template) //
+ sizeof(CK_ATTRIBUTE)))
+ check_return_value(rv, "get_attribute")
+
+ if attr in (CKA_ALWAYS_AUTHENTICATE,
+ CKA_ALWAYS_SENSITIVE,
+ CKA_COPYABLE,
+ CKA_ENCRYPT,
+ CKA_EXTRACTABLE,
+ CKA_DECRYPT,
+ CKA_DERIVE,
+ CKA_LOCAL,
+ CKA_MODIFIABLE,
+ CKA_NEVER_EXTRACTABLE,
+ CKA_PRIVATE,
+ CKA_SENSITIVE,
+ CKA_SIGN,
+ CKA_SIGN_RECOVER,
+ CKA_TOKEN,
+ CKA_TRUSTED,
+ CKA_UNWRAP,
+ CKA_VERIFY,
+ CKA_VERIFY_RECOVER,
+ CKA_WRAP,
+ CKA_WRAP_WITH_TRUSTED):
+ ret = bool(_ffi.cast(_ffi.getctype(CK_BBOOL, '*'), value)[0])
+ elif attr == CKA_LABEL:
+ ret = char_array_to_unicode(value, template[0].ulValueLen)
+ elif attr in (CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_ID):
+ ret = string_to_pybytes_or_none(value, template[0].ulValueLen)
+ elif attr == CKA_KEY_TYPE:
+ ret = _ffi.cast(_ffi.getctype(unsigned_long, '*'), value)[0]
+ else:
+ raise Error("Unknown attribute")
+
+ return ret
+
+
+# Key Classes
+KEY_CLASS_PUBLIC_KEY = CKO_PUBLIC_KEY
+KEY_CLASS_PRIVATE_KEY = CKO_PRIVATE_KEY
+KEY_CLASS_SECRET_KEY = CKO_SECRET_KEY
+
+# Key types
+KEY_TYPE_RSA = CKK_RSA
+KEY_TYPE_AES = CKK_AES
+
+# Wrapping mech type
+MECH_RSA_PKCS = CKM_RSA_PKCS
+MECH_RSA_PKCS_OAEP = CKM_RSA_PKCS_OAEP
+MECH_AES_KEY_WRAP = CKM_AES_KEY_WRAP
+MECH_AES_KEY_WRAP_PAD = CKM_AES_KEY_WRAP_PAD
+
def generate_master_key(p11, keylabel=u"dnssec-master", key_length=16,
disable_old_keys=True):
- assert isinstance(p11, _ipap11helper.P11_Helper)
+ assert isinstance(p11, P11_Helper)
key_id = None
while True:
# check if key with this ID exist in LDAP or softHSM
# id is 16 Bytes long
key_id = "".join(chr(random.randint(0, 255)) for _ in range(0, 16))
- keys = p11.find_keys(_ipap11helper.KEY_CLASS_SECRET_KEY,
+ keys = p11.find_keys(KEY_CLASS_SECRET_KEY,
label=keylabel,
id=key_id)
if not keys:
@@ -28,12 +1886,12 @@ def generate_master_key(p11, keylabel=u"dnssec-master", key_length=16,
if disable_old_keys:
# set CKA_WRAP=False for old master keys
- master_keys = p11.find_keys(_ipap11helper.KEY_CLASS_SECRET_KEY,
+ master_keys = p11.find_keys(KEY_CLASS_SECRET_KEY,
label=keylabel,
cka_wrap=True)
for handle in master_keys:
# don't disable wrapping for new key
# compare IDs not handle
- if key_id != p11.get_attribute(handle, _ipap11helper.CKA_ID):
- p11.set_attribute(handle, _ipap11helper.CKA_WRAP, False)
+ if key_id != p11.get_attribute(handle, CKA_ID):
+ p11.set_attribute(handle, CKA_WRAP, False)
diff --git a/ipaserver/install/dnskeysyncinstance.py b/ipaserver/install/dnskeysyncinstance.py
index 4ae2d2895..a5871bad7 100644
--- a/ipaserver/install/dnskeysyncinstance.py
+++ b/ipaserver/install/dnskeysyncinstance.py
@@ -13,7 +13,7 @@ import stat
import ldap
-import _ipap11helper
+from ipapython import p11helper as _ipap11helper
from ipapython.dnsutil import DNSName
from ipaserver.install import service
from ipaserver.install import installutils
diff --git a/ipaserver/install/opendnssecinstance.py b/ipaserver/install/opendnssecinstance.py
index 4d3b65ff9..c7a796e8e 100644
--- a/ipaserver/install/opendnssecinstance.py
+++ b/ipaserver/install/opendnssecinstance.py
@@ -9,7 +9,7 @@ import stat
import shutil
from subprocess import CalledProcessError
-import _ipap11helper
+from ipapython import p11helper as _ipap11helper
from ipaserver.install import service
from ipaserver.install import installutils
from ipapython.ipa_log_manager import root_logger
diff --git a/ipatests/pytest.ini b/ipatests/pytest.ini
index e38858bc7..531eb847e 100644
--- a/ipatests/pytest.ini
+++ b/ipatests/pytest.ini
@@ -21,7 +21,6 @@ addopts = --doctest-modules
--ignore=doc/examples/python-api.py
--ignore=install/share/copy-schema-to-ca.py
--ignore=install/share/wsgi.py
- --ignore=ipapython/ipap11helper/setup.py
markers =
tier0: basic unit tests and critical functionality
tier1: functional API tests
diff --git a/ipatests/test_ipapython/test_ipap11helper.py b/ipatests/test_ipapython/test_ipap11helper.py
index 0b442b553..2c8fd2892 100644
--- a/ipatests/test_ipapython/test_ipap11helper.py
+++ b/ipatests/test_ipapython/test_ipap11helper.py
@@ -17,7 +17,7 @@ import tempfile
import pytest
from ipaplatform.paths import paths
-import _ipap11helper
+from ipapython import p11helper as _ipap11helper
pytestmark = pytest.mark.tier0