925 lines
32 KiB
Diff
925 lines
32 KiB
Diff
From a7f95d55cd660d1a212fa76a527063b3b7dbe8bb Mon Sep 17 00:00:00 2001
|
|
From: Dan Vella <dan.vella@invicti.com>
|
|
Date: Fri, 17 Mar 2023 13:58:25 +0100
|
|
Subject: [PATCH 1/7] Added changes to enable 3.11 builds
|
|
|
|
---
|
|
.appveyor.yml | 4 ++++
|
|
.github/workflows/macosx.yml | 2 +-
|
|
.github/workflows/manylinux.yml | 6 +++---
|
|
.github/workflows/opensuse-tumbleweed.yml | 2 +-
|
|
.github/workflows/sdist.yml | 4 ++--
|
|
.travis.yml | 3 +++
|
|
setup.py | 1 +
|
|
7 files changed, 15 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/setup.py b/setup.py
|
|
index 9a3c927..5c7e0da 100644
|
|
--- a/setup.py
|
|
+++ b/setup.py
|
|
@@ -533,6 +533,7 @@ def prepare_static_build_linux(self):
|
|
'Programming Language :: Python :: 3.7',
|
|
'Programming Language :: Python :: 3.8',
|
|
'Programming Language :: Python :: 3.9',
|
|
+ 'Programming Language :: Python :: 3.11',
|
|
'Topic :: Text Processing :: Markup :: XML',
|
|
'Typing :: Typed',
|
|
],
|
|
|
|
From b7683774f747c7aed6a0b30e6045da679bc68760 Mon Sep 17 00:00:00 2001
|
|
From: Dan Vella <dan.vella@invicti.com>
|
|
Date: Fri, 17 Mar 2023 14:00:32 +0100
|
|
Subject: [PATCH 2/7] Added changes to enable 3.11 builds
|
|
|
|
---
|
|
.appveyor.yml | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
From bddf28e68a2509a287f9889aaeadc3adab80ccbc Mon Sep 17 00:00:00 2001
|
|
From: Dan Vella <dan.vella@invicti.com>
|
|
Date: Fri, 17 Mar 2023 14:52:40 +0100
|
|
Subject: [PATCH 3/7] bumped isort to 5.11.5
|
|
|
|
---
|
|
.pre-commit-config.yaml | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
From 2c58d43eedf72590e3e201252f5fc5ddae36f8c6 Mon Sep 17 00:00:00 2001
|
|
From: Tomas Divis <tomas.divis@nic.cz>
|
|
Date: Wed, 22 Mar 2023 20:36:45 +0100
|
|
Subject: [PATCH 4/7] Fix #244 - Fix failing test with libxmlsec-1.2.36, also
|
|
make libxmlsec version available from Python.
|
|
|
|
---
|
|
src/main.c | 13 ++++
|
|
tests/data/sign5-out-xmlsec_1_2_36_to_37.xml | 67 ++++++++++++++++++++
|
|
tests/test_ds.py | 6 +-
|
|
3 files changed, 85 insertions(+), 1 deletion(-)
|
|
create mode 100644 tests/data/sign5-out-xmlsec_1_2_36_to_37.xml
|
|
|
|
diff --git a/src/main.c b/src/main.c
|
|
index ffcae14..5773db3 100644
|
|
--- a/src/main.c
|
|
+++ b/src/main.c
|
|
@@ -119,6 +119,13 @@ static PyObject* PyXmlSec_PyShutdown(PyObject* self) {
|
|
Py_RETURN_NONE;
|
|
}
|
|
|
|
+static char PyXmlSec_GetLibXmlSecVersion__doc__[] = \
|
|
+ "get_libxmlsec_version() -> tuple\n"
|
|
+ "Returns Version tuple of wrapped libxml library.";
|
|
+static PyObject* PyXmlSec_GetLibXmlSecVersion() {
|
|
+ return Py_BuildValue("(iii)", XMLSEC_VERSION_MAJOR, XMLSEC_VERSION_MINOR, XMLSEC_VERSION_SUBMINOR);
|
|
+}
|
|
+
|
|
static char PyXmlSec_PyEnableDebugOutput__doc__[] = \
|
|
"enable_debug_trace(enabled) -> None\n"
|
|
"Enables or disables calling LibXML2 callback from the default errors callback.\n\n"
|
|
@@ -386,6 +393,12 @@ static PyMethodDef PyXmlSec_MainMethods[] = {
|
|
METH_NOARGS,
|
|
PyXmlSec_PyShutdown__doc__
|
|
},
|
|
+ {
|
|
+ "get_libxmlsec_version",
|
|
+ (PyCFunction)PyXmlSec_GetLibXmlSecVersion,
|
|
+ METH_NOARGS,
|
|
+ PyXmlSec_GetLibXmlSecVersion__doc__
|
|
+ },
|
|
{
|
|
"enable_debug_trace",
|
|
(PyCFunction)PyXmlSec_PyEnableDebugOutput,
|
|
diff --git a/tests/data/sign5-out-xmlsec_1_2_36_to_37.xml b/tests/data/sign5-out-xmlsec_1_2_36_to_37.xml
|
|
new file mode 100644
|
|
index 0000000..f359b13
|
|
--- /dev/null
|
|
+++ b/tests/data/sign5-out-xmlsec_1_2_36_to_37.xml
|
|
@@ -0,0 +1,67 @@
|
|
+<?xml version="1.0" encoding="UTF-8"?>
|
|
+<!--
|
|
+XML Security Library example: Signed XML doc file (sign5 example).
|
|
+-->
|
|
+<Envelope xmlns="urn:envelope">
|
|
+ <Data>
|
|
+ Hello, World!
|
|
+ </Data>
|
|
+<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
|
+<SignedInfo>
|
|
+<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
|
+<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
|
|
+<Reference>
|
|
+<Transforms>
|
|
+<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
|
+</Transforms>
|
|
+<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
|
|
+<DigestValue>HjY8ilZAIEM2tBbPn5mYO1ieIX4=</DigestValue>
|
|
+</Reference>
|
|
+</SignedInfo>
|
|
+<SignatureValue>SIaj/6KY3C1SmDXU2++Gm31U1xTadFp04WhBgfsJFbxrL+q7GKSKN9kfQ+UpN9+i
|
|
+D5fWmuavXEHe4Gw6RMaMEkq2URQo7F68+d5J/ajq8/l4n+xE6/reGScVwT6L4dEP
|
|
+XXVJcAi2ZnQ3O7GTNvNGCPibL9mUcyCWBFZ92Uemtc/vJFCQ7ZyKMdMfACgxOwyN
|
|
+T/9971oog241/2doudhonc0I/3mgPYWkZdX6yvr62mEjnG+oUZkhWYJ4ewZJ4hM4
|
|
+JjbFqZO+OEzDRSbw3DkmuBA/mtlx+3t13SESfEub5hqoMdVmtth/eTb64dsPdl9r
|
|
+3k1ACVX9f8aHfQQdJOmLFQ==</SignatureValue>
|
|
+<KeyInfo>
|
|
+<X509Data>
|
|
+
|
|
+
|
|
+
|
|
+<X509IssuerSerial>
|
|
+<X509IssuerName>Test Issuer</X509IssuerName>
|
|
+<X509SerialNumber>1</X509SerialNumber>
|
|
+</X509IssuerSerial>
|
|
+<X509Certificate>MIIE3zCCBEigAwIBAgIBBTANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCVVMx
|
|
+EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
|
|
+ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
|
|
+eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
|
|
+a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMB4X
|
|
+DTAzMDMzMTA0MDIyMloXDTEzMDMyODA0MDIyMlowgb8xCzAJBgNVBAYTAlVTMRMw
|
|
+EQYDVQQIEwpDYWxpZm9ybmlhMT0wOwYDVQQKEzRYTUwgU2VjdXJpdHkgTGlicmFy
|
|
+eSAoaHR0cDovL3d3dy5hbGVrc2V5LmNvbS94bWxzZWMpMSEwHwYDVQQLExhFeGFt
|
|
+cGxlcyBSU0EgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUFsZWtzZXkgU2FuaW4xITAf
|
|
+BgkqhkiG9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbTCCASIwDQYJKoZIhvcNAQEB
|
|
+BQADggEPADCCAQoCggEBAJe4/rQ/gzV4FokE7CthjL/EXwCBSkXm2c3p4jyXO0Wt
|
|
+quaNC3dxBwFPfPl94hmq3ZFZ9PHPPbp4RpYRnLZbRjlzVSOq954AXOXpSew7nD+E
|
|
+mTqQrd9+ZIbGJnLOMQh5fhMVuOW/1lYCjWAhTCcYZPv7VXD2M70vVXDVXn6ZrqTg
|
|
+qkVHE6gw1aCKncwg7OSOUclUxX8+Zi10v6N6+PPslFc5tKwAdWJhVLTQ4FKG+F53
|
|
+7FBDnNK6p4xiWryy/vPMYn4jYGvHUUk3eH4lFTCr+rSuJY8i/KNIf/IKim7g/o3w
|
|
+Ae3GM8xrof2mgO8GjK/2QDqOQhQgYRIf4/wFsQXVZcMCAwEAAaOCAVcwggFTMAkG
|
|
+A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp
|
|
+ZmljYXRlMB0GA1UdDgQWBBQkhCzy1FkgYosuXIaQo6owuicanDCB+AYDVR0jBIHw
|
|
+MIHtgBS0ue+a5pcOaGUemM76VQ2JBttMfKGB0aSBzjCByzELMAkGA1UEBhMCVVMx
|
|
+EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE
|
|
+ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v
|
|
+eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl
|
|
+a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggEA
|
|
+MA0GCSqGSIb3DQEBBAUAA4GBALU/mzIxSv8vhDuomxFcplzwdlLZbvSQrfoNkMGY
|
|
+1UoS3YJrN+jZLWKSyWE3mIaPpElqXiXQGGkwD5iPQ1iJMbI7BeLvx6ZxX/f+c8Wn
|
|
+ss0uc1NxfahMaBoyG15IL4+beqO182fosaKJTrJNG3mc//ANGU9OsQM9mfBEt4oL
|
|
+NJ2D</X509Certificate>
|
|
+<X509SubjectName/>
|
|
+<X509SKI/>
|
|
+</X509Data>
|
|
+</KeyInfo>
|
|
+</Signature></Envelope>
|
|
diff --git a/tests/test_ds.py b/tests/test_ds.py
|
|
index 694ad43..38f0b25 100644
|
|
--- a/tests/test_ds.py
|
|
+++ b/tests/test_ds.py
|
|
@@ -182,7 +182,11 @@ def test_sign_case5(self):
|
|
self.assertEqual("rsakey.pem", ctx.key.name)
|
|
|
|
ctx.sign(sign)
|
|
- self.assertEqual(self.load_xml("sign5-out.xml"), root)
|
|
+ if (1, 2, 36) <= xmlsec.get_libxmlsec_version() <= (1, 2, 37):
|
|
+ expected_xml_file = 'sign5-out-xmlsec_1_2_36_to_37.xml'
|
|
+ else:
|
|
+ expected_xml_file = 'sign5-out.xml'
|
|
+ self.assertEqual(self.load_xml(expected_xml_file), root)
|
|
|
|
def test_sign_binary_bad_args(self):
|
|
ctx = xmlsec.SignatureContext()
|
|
|
|
From 1cf6785b3e06c2b8f6cac1266cf8f1934650bc4b Mon Sep 17 00:00:00 2001
|
|
From: Tomas Divis <tomas.divis@nic.cz>
|
|
Date: Wed, 21 Dec 2022 14:01:14 +0100
|
|
Subject: [PATCH 5/7] Fix #164 - Add support for loading keys from engine (e.g.
|
|
pkcs11).
|
|
|
|
---
|
|
README.rst | 2 +-
|
|
src/keys.c | 47 +++++++++++++++++++++++++++++++++++++++++
|
|
src/xmlsec/__init__.pyi | 2 ++
|
|
3 files changed, 50 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/README.rst b/README.rst
|
|
index 34bdd37..e192465 100644
|
|
--- a/README.rst
|
|
+++ b/README.rst
|
|
@@ -37,7 +37,7 @@ Check the `examples <https://xmlsec.readthedocs.io/en/latest/examples.html>`_ se
|
|
Requirements
|
|
************
|
|
- ``libxml2 >= 2.9.1``
|
|
-- ``libxmlsec1 >= 1.2.18``
|
|
+- ``libxmlsec1 >= 1.2.33``
|
|
|
|
Install
|
|
*******
|
|
diff --git a/src/keys.c b/src/keys.c
|
|
index 1362b12..1440331 100644
|
|
--- a/src/keys.c
|
|
+++ b/src/keys.c
|
|
@@ -185,6 +185,47 @@ static PyObject* PyXmlSec_KeyFromFile(PyObject* self, PyObject* args, PyObject*
|
|
return NULL;
|
|
}
|
|
|
|
+static const char PyXmlSec_KeyFromEngine__doc__[] = \
|
|
+ "from_engine(engine_and_key_id) -> xmlsec.Key\n"
|
|
+ "Loads PKI key from an engine.\n\n"
|
|
+ ":param engine_and_key_id: engine and key id, i.e. 'pkcs11;pkcs11:token=XmlsecToken;object=XmlsecKey;pin-value=password'\n"
|
|
+ ":type engine_and_key_id: :class:`str`, "
|
|
+ ":return: pointer to newly created key\n"
|
|
+ ":rtype: :class:`~xmlsec.Key`";
|
|
+static PyObject* PyXmlSec_KeyFromEngine(PyObject* self, PyObject* args, PyObject* kwargs) {
|
|
+ static char *kwlist[] = {"engine_and_key_id", NULL};
|
|
+
|
|
+ const char* engine_and_key_id = NULL;
|
|
+ PyXmlSec_Key* key = NULL;
|
|
+
|
|
+ PYXMLSEC_DEBUG("load key from engine - start");
|
|
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:from_engine", kwlist, &engine_and_key_id)) {
|
|
+ goto ON_FAIL;
|
|
+ }
|
|
+
|
|
+ if ((key = PyXmlSec_NewKey1((PyTypeObject*)self)) == NULL) goto ON_FAIL;
|
|
+
|
|
+ Py_BEGIN_ALLOW_THREADS;
|
|
+ key->handle = xmlSecCryptoAppKeyLoad(engine_and_key_id, xmlSecKeyDataFormatEngine, NULL, xmlSecCryptoAppGetDefaultPwdCallback(),
|
|
+ (void*)engine_and_key_id);
|
|
+ Py_END_ALLOW_THREADS;
|
|
+
|
|
+ if (key->handle == NULL) {
|
|
+ PyXmlSec_SetLastError("cannot read key");
|
|
+ goto ON_FAIL;
|
|
+ }
|
|
+
|
|
+ key->is_own = 1;
|
|
+
|
|
+ PYXMLSEC_DEBUG("load key from engine - ok");
|
|
+ return (PyObject*)key;
|
|
+
|
|
+ON_FAIL:
|
|
+ PYXMLSEC_DEBUG("load key from engine - fail");
|
|
+ Py_XDECREF(key);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
static const char PyXmlSec_KeyGenerate__doc__[] = \
|
|
"generate(klass, size, type) -> xmlsec.Key\n"
|
|
"Generates key of kind ``klass`` with ``size`` and ``type``.\n\n"
|
|
@@ -494,6 +535,12 @@ static PyMethodDef PyXmlSec_KeyMethods[] = {
|
|
METH_CLASS|METH_VARARGS|METH_KEYWORDS,
|
|
PyXmlSec_KeyFromFile__doc__
|
|
},
|
|
+ {
|
|
+ "from_engine",
|
|
+ (PyCFunction)PyXmlSec_KeyFromEngine,
|
|
+ METH_CLASS|METH_VARARGS|METH_KEYWORDS,
|
|
+ PyXmlSec_KeyFromEngine__doc__
|
|
+ },
|
|
{
|
|
"generate",
|
|
(PyCFunction)PyXmlSec_KeyGenerate,
|
|
diff --git a/src/xmlsec/__init__.pyi b/src/xmlsec/__init__.pyi
|
|
index 56356e5..6c326f5 100644
|
|
--- a/src/xmlsec/__init__.pyi
|
|
+++ b/src/xmlsec/__init__.pyi
|
|
@@ -49,6 +49,8 @@ class Key:
|
|
@classmethod
|
|
def from_file(cls: type[Self], file: GenericPath[AnyStr] | IO[AnyStr], format: int, password: str | None = ...) -> Self: ...
|
|
@classmethod
|
|
+ def from_engine(cls: type[Self], engine_and_key_id: AnyStr) -> Self: ...
|
|
+ @classmethod
|
|
def from_memory(cls: type[Self], data: AnyStr, format: int, password: str | None = ...) -> Self: ...
|
|
@classmethod
|
|
def generate(cls: type[Self], klass: KeyData, size: int, type: int) -> Self: ...
|
|
|
|
From 0b5939fc65e98cebb669d311b4fb58844bf887e5 Mon Sep 17 00:00:00 2001
|
|
From: Tomas Divis <tomas.divis@nic.cz>
|
|
Date: Thu, 13 Apr 2023 14:28:02 +0200
|
|
Subject: [PATCH 6/7] Fix #164 - Add tests for pkcs11 (softhsm) key.
|
|
|
|
---
|
|
.github/workflows/sdist.yml | 3 +-
|
|
tests/softhsm_setup.py | 265 ++++++++++++++++++++++++++++++++++++
|
|
tests/test_pkcs11.py | 57 ++++++++
|
|
3 files changed, 323 insertions(+), 2 deletions(-)
|
|
create mode 100644 tests/softhsm_setup.py
|
|
create mode 100644 tests/test_pkcs11.py
|
|
|
|
diff --git a/tests/softhsm_setup.py b/tests/softhsm_setup.py
|
|
new file mode 100644
|
|
index 0000000..0a7c37d
|
|
--- /dev/null
|
|
+++ b/tests/softhsm_setup.py
|
|
@@ -0,0 +1,265 @@
|
|
+"""
|
|
+Testing the PKCS#11 shim layer.
|
|
+Heavily inspired by from https://github.com/IdentityPython/pyXMLSecurity by leifj
|
|
+under licence "As is", see https://github.com/IdentityPython/pyXMLSecurity/blob/master/LICENSE.txt
|
|
+"""
|
|
+
|
|
+import logging
|
|
+import os
|
|
+import shutil
|
|
+import subprocess
|
|
+import tempfile
|
|
+import traceback
|
|
+import unittest
|
|
+from typing import Dict, List, Optional, Tuple
|
|
+
|
|
+DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
|
|
+
|
|
+
|
|
+def paths_for_component(component: str, default_paths: List[str]):
|
|
+ env_path = os.environ.get(component)
|
|
+ return [env_path] if env_path else default_paths
|
|
+
|
|
+
|
|
+def find_alts(component_name, alts: List[str]) -> str:
|
|
+ for a in alts:
|
|
+ if os.path.exists(a):
|
|
+ return a
|
|
+ raise unittest.SkipTest("Required component is missing: {}".format(component_name))
|
|
+
|
|
+
|
|
+def run_cmd(args, softhsm_conf=None) -> Tuple[bytes, bytes]:
|
|
+ env = {}
|
|
+ if softhsm_conf is not None:
|
|
+ env['SOFTHSM_CONF'] = softhsm_conf
|
|
+ env['SOFTHSM2_CONF'] = softhsm_conf
|
|
+ proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
|
|
+ out, err = proc.communicate()
|
|
+ if err is not None and len(err) > 0:
|
|
+ logging.error(err)
|
|
+ if out is not None and len(out) > 0:
|
|
+ logging.debug(out)
|
|
+ rv = proc.wait()
|
|
+ if rv:
|
|
+ with open(softhsm_conf) as f:
|
|
+ conf = f.read()
|
|
+ msg = '[cmd: {cmd}] [code: {code}] [stdout: {out}] [stderr: {err}] [config: {conf}]'
|
|
+ msg = msg.format(
|
|
+ cmd=" ".join(args), code=rv, out=out.strip(), err=err.strip(), conf=conf,
|
|
+ )
|
|
+ raise RuntimeError(msg)
|
|
+ return out, err
|
|
+
|
|
+
|
|
+component_default_paths: Dict[str, List[str]] = {
|
|
+ 'P11_MODULE': [
|
|
+ '/usr/lib/softhsm/libsofthsm2.so',
|
|
+ '/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so',
|
|
+ '/usr/lib/softhsm/libsofthsm.so',
|
|
+ '/usr/lib64/softhsm/libsofthsm2.so',
|
|
+ ],
|
|
+ 'P11_ENGINE': [
|
|
+ '/usr/lib/ssl/engines/libpkcs11.so',
|
|
+ '/usr/lib/engines/engine_pkcs11.so',
|
|
+ '/usr/lib/x86_64-linux-gnu/engines-1.1/pkcs11.so',
|
|
+ '/usr/lib64/engines-1.1/pkcs11.so',
|
|
+ '/usr/lib64/engines-1.1/libpkcs11.so',
|
|
+ '/usr/lib64/engines-3/pkcs11.so',
|
|
+ '/usr/lib64/engines-3/libpkcs11.so',
|
|
+ '/usr/lib/x86_64-linux-gnu/engines-3/pkcs11.so',
|
|
+ '/usr/lib/x86_64-linux-gnu/engines-3/libpkcs11.so',
|
|
+ ],
|
|
+ 'PKCS11_TOOL': [
|
|
+ '/usr/bin/pkcs11-tool',
|
|
+ ],
|
|
+ 'SOFTHSM': [
|
|
+ '/usr/bin/softhsm2-util',
|
|
+ '/usr/bin/softhsm',
|
|
+ ],
|
|
+ 'OPENSSL': [
|
|
+ '/usr/bin/openssl',
|
|
+ ],
|
|
+}
|
|
+
|
|
+component_path: Dict[str, str] = {
|
|
+ component_name: find_alts(component_name, paths_for_component(component_name, default_paths))
|
|
+ for component_name, default_paths in component_default_paths.items()
|
|
+}
|
|
+
|
|
+softhsm_version = 1
|
|
+if component_path['SOFTHSM'].endswith('softhsm2-util'):
|
|
+ softhsm_version = 2
|
|
+
|
|
+openssl_version = subprocess.check_output([component_path['OPENSSL'],
|
|
+ 'version']
|
|
+ )[8:11].decode()
|
|
+
|
|
+p11_test_files: List[str] = []
|
|
+softhsm_conf: Optional[str] = None
|
|
+softhsm_db: Optional[str] = None
|
|
+
|
|
+
|
|
+def _temp_file() -> str:
|
|
+ f = tempfile.NamedTemporaryFile(delete=False)
|
|
+ p11_test_files.append(f.name)
|
|
+ return f.name
|
|
+
|
|
+
|
|
+def _temp_dir() -> str:
|
|
+ d = tempfile.mkdtemp()
|
|
+ p11_test_files.append(d)
|
|
+ return d
|
|
+
|
|
+
|
|
+@unittest.skipIf(component_path['P11_MODULE'] is None, "SoftHSM PKCS11 module not installed")
|
|
+def setup() -> None:
|
|
+ logging.debug("Creating test pkcs11 token using softhsm")
|
|
+ try:
|
|
+ global softhsm_conf
|
|
+ softhsm_conf = _temp_file()
|
|
+ logging.debug("Generating softhsm.conf")
|
|
+ with open(softhsm_conf, "w") as f:
|
|
+ if softhsm_version == 2:
|
|
+ softhsm_db = _temp_dir()
|
|
+ f.write("""
|
|
+# Generated by test
|
|
+directories.tokendir = %s
|
|
+objectstore.backend = file
|
|
+log.level = DEBUG
|
|
+""" % softhsm_db)
|
|
+ else:
|
|
+ softhsm_db = _temp_file()
|
|
+ f.write("""
|
|
+# Generated by test
|
|
+0:%s
|
|
+""" % softhsm_db)
|
|
+
|
|
+ logging.debug("Initializing the token")
|
|
+ out, err = run_cmd([component_path['SOFTHSM'],
|
|
+ '--slot', '0',
|
|
+ '--label', 'test',
|
|
+ '--init-token',
|
|
+ '--pin', 'secret1',
|
|
+ '--so-pin', 'secret2'],
|
|
+ softhsm_conf=softhsm_conf)
|
|
+
|
|
+ # logging.debug("Generating 1024 bit RSA key in token")
|
|
+ # run_cmd([component_path['PKCS11_TOOL'],
|
|
+ # '--module', component_path['P11_MODULE'],
|
|
+ # '-l',
|
|
+ # '-k',
|
|
+ # '--key-type', 'rsa:1024',
|
|
+ # '--id', 'a1b2',
|
|
+ # '--label', 'test',
|
|
+ # '--pin', 'secret1'], softhsm_conf=softhsm_conf)
|
|
+
|
|
+ hash_priv_key = _temp_file()
|
|
+ logging.debug("Converting test private key to format for softhsm")
|
|
+ run_cmd([component_path['OPENSSL'], 'pkcs8',
|
|
+ '-topk8',
|
|
+ '-inform', 'PEM',
|
|
+ '-outform', 'PEM',
|
|
+ '-nocrypt',
|
|
+ '-in', os.path.join(DATA_DIR, 'rsakey.pem'),
|
|
+ '-out', hash_priv_key], softhsm_conf=softhsm_conf)
|
|
+
|
|
+ logging.debug("Importing the test key to softhsm")
|
|
+ run_cmd([component_path['SOFTHSM'],
|
|
+ '--import', hash_priv_key,
|
|
+ '--token', 'test',
|
|
+ '--id', 'a1b2',
|
|
+ '--label', 'test',
|
|
+ '--pin', 'secret1'],
|
|
+ softhsm_conf=softhsm_conf)
|
|
+ run_cmd([component_path['PKCS11_TOOL'],
|
|
+ '--module', component_path['P11_MODULE'],
|
|
+ '-l',
|
|
+ '--pin', 'secret1', '-O'], softhsm_conf=softhsm_conf)
|
|
+ signer_cert_pem = _temp_file()
|
|
+ openssl_conf = _temp_file()
|
|
+ logging.debug("Generating OpenSSL config for version {}".format(openssl_version))
|
|
+ with open(openssl_conf, "w") as f:
|
|
+ # Might be needed with some versions of openssl, but in more recent versions dynamic_path breaks it.
|
|
+ # dynamic_path = (
|
|
+ # "dynamic_path = %s" % component_path['P11_ENGINE']
|
|
+ # if openssl_version.startswith(b'1.')
|
|
+ # else ""
|
|
+ # )
|
|
+ f.write("\n".join([
|
|
+ "openssl_conf = openssl_def",
|
|
+ "[openssl_def]",
|
|
+ "engines = engine_section",
|
|
+ "[engine_section]",
|
|
+ "pkcs11 = pkcs11_section",
|
|
+ "[req]",
|
|
+ "distinguished_name = req_distinguished_name",
|
|
+ "[req_distinguished_name]",
|
|
+ "[pkcs11_section]",
|
|
+ "engine_id = pkcs11",
|
|
+ # dynamic_path,
|
|
+ "MODULE_PATH = %s" % component_path['P11_MODULE'],
|
|
+ "init = 0",
|
|
+ ]))
|
|
+
|
|
+ with open(openssl_conf, "r") as f:
|
|
+ logging.debug('-------- START DEBUG openssl_conf --------')
|
|
+ logging.debug(f.readlines())
|
|
+ logging.debug('-------- END DEBUG openssl_conf --------')
|
|
+ logging.debug('-------- START DEBUG paths --------')
|
|
+ logging.debug(run_cmd(['ls', '-ld', component_path['P11_ENGINE']]))
|
|
+ logging.debug(run_cmd(['ls', '-ld', component_path['P11_MODULE']]))
|
|
+ logging.debug('-------- END DEBUG paths --------')
|
|
+
|
|
+ signer_cert_der = _temp_file()
|
|
+
|
|
+ logging.debug("Generating self-signed certificate")
|
|
+ run_cmd([component_path['OPENSSL'], 'req',
|
|
+ '-new',
|
|
+ '-x509',
|
|
+ '-subj', "/CN=Test Signer",
|
|
+ '-engine', 'pkcs11',
|
|
+ '-config', openssl_conf,
|
|
+ '-keyform', 'engine',
|
|
+ '-key', 'label_test',
|
|
+ '-passin', 'pass:secret1',
|
|
+ '-out', signer_cert_pem], softhsm_conf=softhsm_conf)
|
|
+
|
|
+ run_cmd([component_path['OPENSSL'], 'x509',
|
|
+ '-inform', 'PEM',
|
|
+ '-outform', 'DER',
|
|
+ '-in', signer_cert_pem,
|
|
+ '-out', signer_cert_der], softhsm_conf=softhsm_conf)
|
|
+
|
|
+ logging.debug("Importing certificate into token")
|
|
+
|
|
+ run_cmd([component_path['PKCS11_TOOL'],
|
|
+ '--module', component_path['P11_MODULE'],
|
|
+ '-l',
|
|
+ '--slot-index', '0',
|
|
+ '--id', 'a1b2',
|
|
+ '--label', 'test',
|
|
+ '-y', 'cert',
|
|
+ '-w', signer_cert_der,
|
|
+ '--pin', 'secret1'], softhsm_conf=softhsm_conf)
|
|
+
|
|
+ # TODO: Should be teardowned in teardown:
|
|
+ os.environ['SOFTHSM_CONF'] = softhsm_conf
|
|
+ os.environ['SOFTHSM2_CONF'] = softhsm_conf
|
|
+
|
|
+ except Exception as ex:
|
|
+ print("-" * 64)
|
|
+ traceback.print_exc()
|
|
+ print("-" * 64)
|
|
+ logging.error("PKCS11 tests disabled: unable to initialize test token: %s" % ex)
|
|
+ raise ex
|
|
+
|
|
+
|
|
+def teardown() -> None:
|
|
+ global p11_test_files
|
|
+ for o in p11_test_files:
|
|
+ if os.path.exists(o):
|
|
+ if os.path.isdir(o):
|
|
+ shutil.rmtree(o)
|
|
+ else:
|
|
+ os.unlink(o)
|
|
+ p11_test_files = []
|
|
diff --git a/tests/test_pkcs11.py b/tests/test_pkcs11.py
|
|
new file mode 100644
|
|
index 0000000..accd29a
|
|
--- /dev/null
|
|
+++ b/tests/test_pkcs11.py
|
|
@@ -0,0 +1,57 @@
|
|
+import xmlsec
|
|
+from tests import base
|
|
+from xmlsec import constants as consts
|
|
+
|
|
+KEY_URL = "pkcs11;pkcs11:token=test;object=test;pin-value=secret1"
|
|
+
|
|
+
|
|
+def setUpModule():
|
|
+ from tests import softhsm_setup
|
|
+
|
|
+ softhsm_setup.setup()
|
|
+
|
|
+
|
|
+def tearDownModule():
|
|
+ from tests import softhsm_setup
|
|
+
|
|
+ softhsm_setup.teardown()
|
|
+
|
|
+
|
|
+class TestKeys(base.TestMemoryLeaks):
|
|
+ def test_del_key(self):
|
|
+ ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager())
|
|
+ ctx.key = xmlsec.Key.from_engine(KEY_URL)
|
|
+ del ctx.key
|
|
+ self.assertIsNone(ctx.key)
|
|
+
|
|
+ def test_set_key(self):
|
|
+ ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager())
|
|
+ ctx.key = xmlsec.Key.from_engine(KEY_URL)
|
|
+ self.assertIsNotNone(ctx.key)
|
|
+
|
|
+ def test_sign_bad_args(self):
|
|
+ ctx = xmlsec.SignatureContext()
|
|
+ ctx.key = xmlsec.Key.from_engine(KEY_URL)
|
|
+ with self.assertRaises(TypeError):
|
|
+ ctx.sign('')
|
|
+
|
|
+ def test_sign_fail(self):
|
|
+ ctx = xmlsec.SignatureContext()
|
|
+ ctx.key = xmlsec.Key.from_engine(KEY_URL)
|
|
+ with self.assertRaisesRegex(xmlsec.Error, 'failed to sign'):
|
|
+ ctx.sign(self.load_xml('sign1-in.xml'))
|
|
+
|
|
+ def test_sign_case1(self):
|
|
+ """Should sign a pre-constructed template file using a key from a pkcs11 engine."""
|
|
+ root = self.load_xml("sign1-in.xml")
|
|
+ sign = xmlsec.tree.find_node(root, consts.NodeSignature)
|
|
+ self.assertIsNotNone(sign)
|
|
+
|
|
+ ctx = xmlsec.SignatureContext()
|
|
+ ctx.key = xmlsec.Key.from_engine(KEY_URL)
|
|
+ self.assertIsNotNone(ctx.key)
|
|
+ ctx.key.name = 'rsakey.pem'
|
|
+ self.assertEqual("rsakey.pem", ctx.key.name)
|
|
+
|
|
+ ctx.sign(sign)
|
|
+ self.assertEqual(self.load_xml("sign1-out.xml"), root)
|
|
|
|
From 4f5daea286df89c64fbfc615f422be62b2cdf114 Mon Sep 17 00:00:00 2001
|
|
From: "pre-commit-ci[bot]"
|
|
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
|
|
Date: Mon, 17 Apr 2023 11:55:28 +0000
|
|
Subject: [PATCH 7/7] [pre-commit.ci] auto fixes from pre-commit.com hooks
|
|
|
|
for more information, see https://pre-commit.ci
|
|
---
|
|
tests/softhsm_setup.py | 220 +++++++++++++++++++++++++++--------------
|
|
1 file changed, 147 insertions(+), 73 deletions(-)
|
|
|
|
diff --git a/tests/softhsm_setup.py b/tests/softhsm_setup.py
|
|
index 0a7c37d..432d4b1 100644
|
|
--- a/tests/softhsm_setup.py
|
|
+++ b/tests/softhsm_setup.py
|
|
@@ -45,7 +45,11 @@ def run_cmd(args, softhsm_conf=None) -> Tuple[bytes, bytes]:
|
|
conf = f.read()
|
|
msg = '[cmd: {cmd}] [code: {code}] [stdout: {out}] [stderr: {err}] [config: {conf}]'
|
|
msg = msg.format(
|
|
- cmd=" ".join(args), code=rv, out=out.strip(), err=err.strip(), conf=conf,
|
|
+ cmd=" ".join(args),
|
|
+ code=rv,
|
|
+ out=out.strip(),
|
|
+ err=err.strip(),
|
|
+ conf=conf,
|
|
)
|
|
raise RuntimeError(msg)
|
|
return out, err
|
|
@@ -90,9 +94,7 @@ def run_cmd(args, softhsm_conf=None) -> Tuple[bytes, bytes]:
|
|
if component_path['SOFTHSM'].endswith('softhsm2-util'):
|
|
softhsm_version = 2
|
|
|
|
-openssl_version = subprocess.check_output([component_path['OPENSSL'],
|
|
- 'version']
|
|
- )[8:11].decode()
|
|
+openssl_version = subprocess.check_output([component_path['OPENSSL'], 'version'])[8:11].decode()
|
|
|
|
p11_test_files: List[str] = []
|
|
softhsm_conf: Optional[str] = None
|
|
@@ -121,27 +123,41 @@ def setup() -> None:
|
|
with open(softhsm_conf, "w") as f:
|
|
if softhsm_version == 2:
|
|
softhsm_db = _temp_dir()
|
|
- f.write("""
|
|
+ f.write(
|
|
+ """
|
|
# Generated by test
|
|
directories.tokendir = %s
|
|
objectstore.backend = file
|
|
log.level = DEBUG
|
|
-""" % softhsm_db)
|
|
+"""
|
|
+ % softhsm_db
|
|
+ )
|
|
else:
|
|
softhsm_db = _temp_file()
|
|
- f.write("""
|
|
+ f.write(
|
|
+ """
|
|
# Generated by test
|
|
0:%s
|
|
-""" % softhsm_db)
|
|
+"""
|
|
+ % softhsm_db
|
|
+ )
|
|
|
|
logging.debug("Initializing the token")
|
|
- out, err = run_cmd([component_path['SOFTHSM'],
|
|
- '--slot', '0',
|
|
- '--label', 'test',
|
|
- '--init-token',
|
|
- '--pin', 'secret1',
|
|
- '--so-pin', 'secret2'],
|
|
- softhsm_conf=softhsm_conf)
|
|
+ out, err = run_cmd(
|
|
+ [
|
|
+ component_path['SOFTHSM'],
|
|
+ '--slot',
|
|
+ '0',
|
|
+ '--label',
|
|
+ 'test',
|
|
+ '--init-token',
|
|
+ '--pin',
|
|
+ 'secret1',
|
|
+ '--so-pin',
|
|
+ 'secret2',
|
|
+ ],
|
|
+ softhsm_conf=softhsm_conf,
|
|
+ )
|
|
|
|
# logging.debug("Generating 1024 bit RSA key in token")
|
|
# run_cmd([component_path['PKCS11_TOOL'],
|
|
@@ -155,26 +171,45 @@ def setup() -> None:
|
|
|
|
hash_priv_key = _temp_file()
|
|
logging.debug("Converting test private key to format for softhsm")
|
|
- run_cmd([component_path['OPENSSL'], 'pkcs8',
|
|
- '-topk8',
|
|
- '-inform', 'PEM',
|
|
- '-outform', 'PEM',
|
|
- '-nocrypt',
|
|
- '-in', os.path.join(DATA_DIR, 'rsakey.pem'),
|
|
- '-out', hash_priv_key], softhsm_conf=softhsm_conf)
|
|
+ run_cmd(
|
|
+ [
|
|
+ component_path['OPENSSL'],
|
|
+ 'pkcs8',
|
|
+ '-topk8',
|
|
+ '-inform',
|
|
+ 'PEM',
|
|
+ '-outform',
|
|
+ 'PEM',
|
|
+ '-nocrypt',
|
|
+ '-in',
|
|
+ os.path.join(DATA_DIR, 'rsakey.pem'),
|
|
+ '-out',
|
|
+ hash_priv_key,
|
|
+ ],
|
|
+ softhsm_conf=softhsm_conf,
|
|
+ )
|
|
|
|
logging.debug("Importing the test key to softhsm")
|
|
- run_cmd([component_path['SOFTHSM'],
|
|
- '--import', hash_priv_key,
|
|
- '--token', 'test',
|
|
- '--id', 'a1b2',
|
|
- '--label', 'test',
|
|
- '--pin', 'secret1'],
|
|
- softhsm_conf=softhsm_conf)
|
|
- run_cmd([component_path['PKCS11_TOOL'],
|
|
- '--module', component_path['P11_MODULE'],
|
|
- '-l',
|
|
- '--pin', 'secret1', '-O'], softhsm_conf=softhsm_conf)
|
|
+ run_cmd(
|
|
+ [
|
|
+ component_path['SOFTHSM'],
|
|
+ '--import',
|
|
+ hash_priv_key,
|
|
+ '--token',
|
|
+ 'test',
|
|
+ '--id',
|
|
+ 'a1b2',
|
|
+ '--label',
|
|
+ 'test',
|
|
+ '--pin',
|
|
+ 'secret1',
|
|
+ ],
|
|
+ softhsm_conf=softhsm_conf,
|
|
+ )
|
|
+ run_cmd(
|
|
+ [component_path['PKCS11_TOOL'], '--module', component_path['P11_MODULE'], '-l', '--pin', 'secret1', '-O'],
|
|
+ softhsm_conf=softhsm_conf,
|
|
+ )
|
|
signer_cert_pem = _temp_file()
|
|
openssl_conf = _temp_file()
|
|
logging.debug("Generating OpenSSL config for version {}".format(openssl_version))
|
|
@@ -185,21 +220,25 @@ def setup() -> None:
|
|
# if openssl_version.startswith(b'1.')
|
|
# else ""
|
|
# )
|
|
- f.write("\n".join([
|
|
- "openssl_conf = openssl_def",
|
|
- "[openssl_def]",
|
|
- "engines = engine_section",
|
|
- "[engine_section]",
|
|
- "pkcs11 = pkcs11_section",
|
|
- "[req]",
|
|
- "distinguished_name = req_distinguished_name",
|
|
- "[req_distinguished_name]",
|
|
- "[pkcs11_section]",
|
|
- "engine_id = pkcs11",
|
|
- # dynamic_path,
|
|
- "MODULE_PATH = %s" % component_path['P11_MODULE'],
|
|
- "init = 0",
|
|
- ]))
|
|
+ f.write(
|
|
+ "\n".join(
|
|
+ [
|
|
+ "openssl_conf = openssl_def",
|
|
+ "[openssl_def]",
|
|
+ "engines = engine_section",
|
|
+ "[engine_section]",
|
|
+ "pkcs11 = pkcs11_section",
|
|
+ "[req]",
|
|
+ "distinguished_name = req_distinguished_name",
|
|
+ "[req_distinguished_name]",
|
|
+ "[pkcs11_section]",
|
|
+ "engine_id = pkcs11",
|
|
+ # dynamic_path,
|
|
+ "MODULE_PATH = %s" % component_path['P11_MODULE'],
|
|
+ "init = 0",
|
|
+ ]
|
|
+ )
|
|
+ )
|
|
|
|
with open(openssl_conf, "r") as f:
|
|
logging.debug('-------- START DEBUG openssl_conf --------')
|
|
@@ -213,34 +252,69 @@ def setup() -> None:
|
|
signer_cert_der = _temp_file()
|
|
|
|
logging.debug("Generating self-signed certificate")
|
|
- run_cmd([component_path['OPENSSL'], 'req',
|
|
- '-new',
|
|
- '-x509',
|
|
- '-subj', "/CN=Test Signer",
|
|
- '-engine', 'pkcs11',
|
|
- '-config', openssl_conf,
|
|
- '-keyform', 'engine',
|
|
- '-key', 'label_test',
|
|
- '-passin', 'pass:secret1',
|
|
- '-out', signer_cert_pem], softhsm_conf=softhsm_conf)
|
|
-
|
|
- run_cmd([component_path['OPENSSL'], 'x509',
|
|
- '-inform', 'PEM',
|
|
- '-outform', 'DER',
|
|
- '-in', signer_cert_pem,
|
|
- '-out', signer_cert_der], softhsm_conf=softhsm_conf)
|
|
+ run_cmd(
|
|
+ [
|
|
+ component_path['OPENSSL'],
|
|
+ 'req',
|
|
+ '-new',
|
|
+ '-x509',
|
|
+ '-subj',
|
|
+ "/CN=Test Signer",
|
|
+ '-engine',
|
|
+ 'pkcs11',
|
|
+ '-config',
|
|
+ openssl_conf,
|
|
+ '-keyform',
|
|
+ 'engine',
|
|
+ '-key',
|
|
+ 'label_test',
|
|
+ '-passin',
|
|
+ 'pass:secret1',
|
|
+ '-out',
|
|
+ signer_cert_pem,
|
|
+ ],
|
|
+ softhsm_conf=softhsm_conf,
|
|
+ )
|
|
+
|
|
+ run_cmd(
|
|
+ [
|
|
+ component_path['OPENSSL'],
|
|
+ 'x509',
|
|
+ '-inform',
|
|
+ 'PEM',
|
|
+ '-outform',
|
|
+ 'DER',
|
|
+ '-in',
|
|
+ signer_cert_pem,
|
|
+ '-out',
|
|
+ signer_cert_der,
|
|
+ ],
|
|
+ softhsm_conf=softhsm_conf,
|
|
+ )
|
|
|
|
logging.debug("Importing certificate into token")
|
|
|
|
- run_cmd([component_path['PKCS11_TOOL'],
|
|
- '--module', component_path['P11_MODULE'],
|
|
- '-l',
|
|
- '--slot-index', '0',
|
|
- '--id', 'a1b2',
|
|
- '--label', 'test',
|
|
- '-y', 'cert',
|
|
- '-w', signer_cert_der,
|
|
- '--pin', 'secret1'], softhsm_conf=softhsm_conf)
|
|
+ run_cmd(
|
|
+ [
|
|
+ component_path['PKCS11_TOOL'],
|
|
+ '--module',
|
|
+ component_path['P11_MODULE'],
|
|
+ '-l',
|
|
+ '--slot-index',
|
|
+ '0',
|
|
+ '--id',
|
|
+ 'a1b2',
|
|
+ '--label',
|
|
+ 'test',
|
|
+ '-y',
|
|
+ 'cert',
|
|
+ '-w',
|
|
+ signer_cert_der,
|
|
+ '--pin',
|
|
+ 'secret1',
|
|
+ ],
|
|
+ softhsm_conf=softhsm_conf,
|
|
+ )
|
|
|
|
# TODO: Should be teardowned in teardown:
|
|
os.environ['SOFTHSM_CONF'] = softhsm_conf
|