From cd6894f52bf1b3134e8dd8a34530f88235124ff8 Mon Sep 17 00:00:00 2001 From: Martin van Es <martin@mrvanes.com> Date: Thu, 16 Dec 2021 13:56:04 +0100 Subject: [PATCH] Add PKCS11 (softHSM2) Signer --- README.md | 18 +++++++++++++++++- mdserver.py | 9 +++++---- requirements.txt | 2 ++ signers.py | 8 +++++++- utils.py | 43 +++++++++++++++++++++++++++---------------- 5 files changed, 58 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 28db9e5..c3436ce 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Alternate MDX research project ## ```mdsigner.py [mdfile] [mdfile] [mdfile] ...``` Reads source metadata file(s) and outputs them signed to filesystem -## ```mdserver.py [mdfile] [mdfile] [mdfile] ...``` +## ```mdserver.py``` Starts a metadata signer server. Reads source metadata files(s) from mdsigner.yaml configuration, see example. Reloads metadata on inotify CLOSE_WRITE of metadata file. @@ -28,3 +28,19 @@ MDQ Queries can then be pointed at - ```http://mdserver:5001/sign/<entityid>``` - ```http://mdproxy:5002/cache/<entityid>``` + +## Bootstrap softHSM2 +This is a very brief summary of the successive commands to initialize softHSM2 for testing. Tested on Ubuntu 21.10. +``` +# softhsm2-util --show-slots +# softhsm2-util --init-token --slot 0 --label "My token 1" --pin "secret" --so-pin "secret" +# softhsm2-util --show-slots + +# pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so -l -k --key-type rsa:1024 --slot-index 0 --id a1b2 --label test --pin secret +# pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so -l --pin secret -O + +# openssl req -new -x509 -subj "/CN=Test Signer" -engine pkcs11 -keyform engine -key label_test -passin 'pass:secret' -out hsm.crt +# openssl x509 -inform PEM -outform DER -in hsm.crt -out hsm.der + +# pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so -l --slot-index 0 --id a1b2 --label test -y cert -w hsm.der --pin secret +``` \ No newline at end of file diff --git a/mdserver.py b/mdserver.py index 1384575..a1263ae 100755 --- a/mdserver.py +++ b/mdserver.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -from utils import read_config, server, event_notifier +from utils import read_config, Resource, server from flask import Flask, Response config = read_config() @@ -24,9 +24,10 @@ def serve(domain, entity_id): for domain, values in config.items(): print(f"domain: {domain}") - conf = (values['metadir'], values['signer']) - server[domain] = conf + location = values['metadir'] + signer = values['signer'] + server[domain] = Resource(location, signer) + server.add_watch(domain, location) -event_notifier.start() app.run(host='127.0.0.1', port=5001) diff --git a/requirements.txt b/requirements.txt index 30cbf8e..b43dcbc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,3 +6,5 @@ python-dateutil isoduration pyyaml pyinotify +pyXMLSecurity +PyKCS11 diff --git a/signers.py b/signers.py index b2a0b61..9168c7a 100644 --- a/signers.py +++ b/signers.py @@ -1,3 +1,4 @@ +import xmlsec from signxml import XMLSigner cert = open("meta.crt").read() @@ -17,10 +18,15 @@ def Signers(signer): print("Foobar signer") return XMLSigner().sign(xml, key=key, cert=cert) + def _hsm_signer(xml): + print("HSM signer") + return xmlsec.sign(xml, key_spec="pkcs11:///usr/lib/softhsm/libsofthsm2.so/test?pin=secret") + signers = { 'normal_signer': _normal_signer, 'test_signer': _test_signer, - 'foobar_signer': _foobar_signer + 'foobar_signer': _foobar_signer, + 'hsm_signer': _hsm_signer } return signers[signer] diff --git a/utils.py b/utils.py index 23cb4f2..cd66514 100755 --- a/utils.py +++ b/utils.py @@ -9,8 +9,8 @@ import yaml import pyinotify from signers import Signers -watch_list = {} -watch_manager = pyinotify.WatchManager() +# watch_list = {} +# watch_manager = pyinotify.WatchManager() def read_config(): @@ -26,13 +26,6 @@ def hasher(entity_id): return sha1_digest -class EventProcessor(pyinotify.ProcessEvent): - def process_IN_CLOSE_WRITE(self, event): - domain = watch_list[event.path] - print(f"Notify {domain} {event.path}") - server[domain].walk_location(event.path) - - class Entity: def __init__(self): self.md = None @@ -60,7 +53,6 @@ class Resource: found = 0 removed = 0 old_idps = self.mdfiles[mdfile].copy() - print(f"old_idps: {old_idps}") tree = ET.ElementTree(file=mdfile) root = tree.getroot() ns = root.nsmap.copy() @@ -129,16 +121,35 @@ class Resource: return data +class EventProcessor(pyinotify.ProcessEvent): + def process_IN_CLOSE_WRITE(self, event): + server.process(event.path) + + class Server: - def __setitem__(self, domain, conf): - location, signer = conf - self.__dict__[domain] = Resource(location, signer) - watch_list[location] = domain - watch_manager.add_watch(location, pyinotify.IN_CLOSE_WRITE) + watch_list = {} + + def __init__(self): + self.watch_manager = pyinotify.WatchManager() + self.event_notifier = pyinotify.ThreadedNotifier(self.watch_manager, EventProcessor()) + self.event_notifier.start() + + def add_watch(self, domain, location): + self.watch_list[location] = domain + self.watch_manager.add_watch(location, pyinotify.IN_CLOSE_WRITE) + + def process(self, location): + domain = self.watch_list[location] + print(f"Notify {domain} {location}") + self.__dict__[domain].walk_location(location) + + def __setitem__(self, domain, resource): + self.__dict__[domain] = resource + # watch_list[location] = domain + # watch_manager.add_watch(location, pyinotify.IN_CLOSE_WRITE) def __getitem__(self, domain): return self.__dict__[domain] server = Server() -event_notifier = pyinotify.ThreadedNotifier(watch_manager, EventProcessor()) -- GitLab