Hello list, [RFC] PKCS#11 key support provider & engine (rev. 2) Addresses: https://github.com/haproxy/haproxy/issues/71
This RFC now supports provider(OpenSSL 3) and engine(OpenSSL 1.1.1) The patch will follow in the next email. Background Here is the revised version of my original RFC[1] to support PKCS#11 keys in master-worker mode by recreating private keys in the worker. First let me address some previous questions: from @wlallemand[2] "Did you identify why the fork was causing an issue? We should probably try to understand this before, it could be something stupid in haproxy's code or in the pkcs11 provider." This is a known PKCS#11 issue and not really a haproxy problem. Several integrations, such as provider/engine, do try to mitigate this but in general it is a tricky problem. After fork some of these integrations will attempt to restore handles but as GnuTLS says[3] "Note that, PKCS #11 modules behave in a peculiar way after a fork; they require a reinitialization of all the used PKCS #11 resources. While GnuTLS automates that process, there are corner cases where it is not possible to handle it correctly in an automated way. For that, it is recommended not to mix fork() and PKCS #11 module usage. It is recommended to initialize and use any PKCS #11 resources in a single process." PKCS#11 v3 does have support for PKCS#11 modules with "fork tolerant semantics"[4], but such modules are rare at the moment. Revised version Changes from [1] - now support both provider(OpenSSL 3) and engine(OpenSSL 1.1.1); the exemplars are pkcs11-provider[5] and opensc pkcs11 engine[6] - remove use of maps (ckch_data* -> PEM, SSL_CTX* -> ckch_data*) What does this RFC do? In master-worker mode it recreates the private key in the worker and installs this private key in the SSL_CTX*, overriding the original private key created in master. How does it do this? - extend struct ckch_data to store a copy of the PEM data used to create the cert / key - (engine specific) extend struct ckch_data to store the engine name and key name - thus - hash map (struct ckch_data -> PEM/engine data) is not needed - when creating SSL_CTX* store a pointer to struct ckch_data with SSL_CTX_set_app_data(); thus - hash map (SSL_CTX* -> struct ckch_data) is no longer needed - in the worker process, just before SSL_use_SSL_CTX(), we use the stored PEM data to recreate the provider private key or (engine specific) use the stored engine/key name to recreate the engine private key - the worker key is cached for future use How are engine keys referenced? - use crt "extra files" and store engine "key" in a specially formatted "xxxx.crt.key" file - this is not a private key PEM file, it is simply a text file containing two lines: engine = pkcs11 private_key = pkcs11:token=SomePKCS11Token;object=SomePrivateKeyLabel;type=private - repeat: an engine "xxxx.crt.key" file is not a PEM-"PRIVATE KEY" file that we are familiar with; it is a special text file with the name of the engine and private key - engine keys must live in a separate .key file as they are not PEM How are pkcs11-provider keys referenced? - like TPM2 pkcs11-provider can store keys in PEM objects with label "PKCS#11 PROVIDER URI" - a provider key can be merged into the .crt file - current glitch in pkcs11-provider PEM parser: a key in a merged file must be the first PEM object References 1. https://www.mail-archive.com/haproxy@formilux.org/msg44736.html 2. https://www.mail-archive.com/haproxy@formilux.org/msg44741.html 3. https://www.gnutls.org/manual/html_node/PKCS11-Initialization.html 4. https://docs.oasis-open.org/pkcs11/pkcs11-base/v3.0/csprd01/pkcs11-base-v3.0-csprd01.html 5. https://github.com/latchset/pkcs11-provider 6. https://github.com/OpenSC/libp11 Regards Richard