OpenSSL Providers in HAProxy - haproxy/wiki Wiki

Note

In order to make a full use of the information contained in this document, you need to have OpenSSLv3.0 installed, as well as an HAProxy v2.6 or more, built with SSL enabled. All the build and configuration information provided were tested on an amd64 architecture with an Ubuntu 22.04 operating system.

OpenSSL providers

As described in provider(7), an OpenSSL provider is a unit of code that provides implementations for diverse algorithms. They could be used to provide new hardware-based implementation of algorithms already implemented in OpenSSL or to provide brand new algorithms altogether for instance. The provider mechanism is comparable to the engine one and it is meant to replace it in the short to medium term. It requires an important rewriting of all existing engines in order for them to be fully functioning providers though. This partially explains why not so many providers exist yet (as of June 2022) apart from the ones created by OpenSSL themselves.

Engine support in HAProxy

This section is a quick reminder of the engine support in HAProxy, which defined what we planned on offering through the new provider API. Engines can be loaded into HAProxy thanks to the 'ssl-engine' option, to which we can specify an optional list of algorithms whose implementation should then be taken from the loaded engine. This option then allows for instance to use dedicated hardware to perform cryptographic operations, provided that you load the associated engine from the configuration. Please note that since the engine API was marked as deprecated in OpenSSL 3.0 and is bound to disappear later, the support of engines in HAProxy was disabled by default starting with version 2.6. It could be re-enabled at build time by using the USE_ENGINE option.

Provider support in HAProxy

Three new options were added 'ssl-provider', 'ssl-provider-path' and ssl-propquery'. They are similar to the 'provider', 'provider-path' and 'propquery' options added to OpenSSL (config(5)). They allow to load any provider and to define a default property string that will be used during algorithm fetching. The following configuration snippet allows to make use of the TPM2 provider that will be described below for instance:

global
    ssl-provider-path /usr/lib/x86_64-linux-gnu/ossl-modules
    ssl-provider tpm2
    ssl-provider default
    ssl-propquery ?provider=tpm2

What this does is ask HAProxy to tell OpenSSL to load the tpm2.so shared library that can be found under the /usr/lib/x86_64-linux-gnu/ossl-modules directory, as well as OpenSSL's 'default' provider, and to use the default property string '?provider=tpm2' that tells OpenSSL to prioritize the TPM2 provider when fetching algorithm, but that not all algorithm might be implemented there (hence the '?'). See property(7) for a full explanation about property strings in OpenSSL.

With such a configuration, HAProxy acts merely as a messenger. The task of loading and using providers is entrusted to OpenSSL, and the end-of-line user -HAProxy in this case) does not have to know which provider is used when performing cryptographic operations.

For this reason, the provider configuration can also be performed directly from OpenSSL's configuration file. An equivalent configuration could be achieved by adding the following lines to your openssl.cnf file:

[openssl_init]
providers = provider_sect
alg_section = evp_properties

# List of providers to load
[provider_sect]
tpm2 = tpm2_sect
default = default_sect

[tpm2_sect]
activate = 1

[default_sect]
activate = 1

[evp_properties]
default_properties = "?provider=tpm2"

and the environment variable OPENSSL_CONF can be used to point to the openssl configuration file you want to use (in case you don't want to use this configuration for every single application that needs OpenSSL).

TPM2 provider

The TPM2 provider is an example of completed provider. It offers the funtionalities that were previously provided by an engine (TPM2 engine). It implements the cryptographic functions for Trusted Platform Module (TPM 2.0).

The way to use this provider with HAProxy requires that you first have a usable TPM setup. It needs an integrated TPM chip (unless you just want to test the provider mechanism in which case a TPM simulator could be enough). The simplest ways to know if TPM is enabled on your machine is to check if you have a /dev/tpm0 device, or to look for TPM related messages in dmesg such as the following :

$ dmesg | grep -i TPM
[    0.000000] efi: ACPI=0xbd7fd000 ACPI 2.0=0xbd7fd014 TPMFinalLog=0xbd62b000 SMBIOS=0xb9ed8000 SMBIOS 3.0=0xb9ecb000 MEMATTR=0xb4531018 ESRT=0xb8a70000 MOKvar=0xb4536000 RNG=0xb9fc3598 TPMEventLog=0xaa3a0018
[    0.005224] ACPI: SSDT 0x00000000B9EAC000 000651 (v02 LENOVO Tpm2Tabl 00001000 INTL 20120711)
[    0.005227] ACPI: TPM2 0x00000000B9EAB000 000034 (v03 LENOVO TP-R13   00001150 PTEC 00000002)
[    0.005300] ACPI: Reserving TPM2 table memory at [mem 0xb9eab000-0xb9eab033]
[    0.426373] tpm_tis STM7308:00: 2.0 TPM (device-id 0x0, rev-id 78)

Any message such as the following in your dmesg output can be ignored, they won't prevent the TPM from working

[    0.430409] tpm tpm0: [Firmware Bug]: TPM interrupt not working, polling instead

If you are supposed to have a TPM chip but none of the methods above yields any result, check in your BIOS configuration if TPM is indeed enabled (under Security -> Security Chip).

There might be multiple ways to make the TPM work. The way described here will rely on the tpm2-abrmd program, which will serve as an intermediate between the provider and the actual chip.

tpm2-openssl

The TPM2 provider repository contains the actual provider. Its compiling and installation is pretty straightforward. You simpy need to

./bootstrap
./configure
make
make install

tpm2-abrmd

Abrmd stands for Access Broker and Resource Management Daemon. This daemon will communicate via dbus with the TPM2 provider. It will manage session resources and provide isolation between all the processes that make use of the TPM functionalities. The tpm2-abrmd repository should be cloned and the tpm2-abrmd to build and install it. All the information required to build it are contained in the INSTALL.md file. If you have a non-standard OpenSSL install or if you want to enable some specific options, look at the repository's files. The "standard" way is the following :

sudo useradd --system --user-group tss
./bootstrap
./configure --with-dbuspolicydir=/etc/dbus-1/system.d
make
sudo make install

Then the resource manager can be launched as user 'tss'

sudo -u tss tpm2-abrmd

Troubleshooting

There are some common errors that can be raised by tpm2-abrmd which I stumbled upon. If you have the following error

** (tpm2-abrmd:30487): CRITICAL **: 10:50:48.747: Failed to acquire DBus name com.intel.tss2.Tabrmd. UID 106 must be allowed to "own" this name. Check DBus config and check that this is running as user tss or root.

then you might need to check where the dbus configuration files are located on your system and to set the --with-dbuspolicydir option accordingly when calling the configure script.

If you already have another tpm2-abrmd instance running, then the second one will raise the following error

ERROR:tcti:src/tss2-tcti/tcti-device.c:451:Tss2_Tcti_Device_Init() Failed to open specified TCTI device file /dev/tpm0: Device or resource busy

tpm2-tools

The tpm2-tools repository is an optional one that could be used as well. It provides a plethora of applications that allow to manage TPM2 keys and that communicate directly with the chip. It also provides debugging tools such as tpm2_rc_decode which should give detailed information about an error code that you could have received while performing tpm operations. During testing I sometimes managed to put my TPM chip in "DA lockout mode", a kind of security mode that I could get out of either by clearing the TPM chip contents directly from the BIOS, or by calling the tpm2_clear command (as user 'tss').

TPM2 simulator

Many TPM2 simulators exist already. They allow to test a TPM setup without interacting with an actual TPM chip. The simulator suggested by the provider's documentation is IBM's one. You just need to get it from Microsoft/IBM TPM2 simulator and run the 'tpm_server' app. The abrmd should then be launched as follows

sudo -u tss tpm2-abrmd --tcti mssim:host=localhost,port=2321

The provider side of the chain will be configured the same way (and behave the same way as well).

Actual execution

Once your TPM2 setup is running, you can create TPM2 keys and certificate directly from openssl. The following command will create a key and self-signed certificate via the tpm2 provider:

openssl req -provider tpm2 -x509 -subj "/C=GB/CN=foo" -keyout testkey.pem -out testcert.pem

Depending on the way you installed openssl and the provider, you might need to add a -provider-path option as well. You could check that your certificate is valid by using it in an openssl server instance:

openssl s_server -provider tpm2 -provider default -propquery ?provider=tpm2 -accept 4443 -www -key testkey.pem -cert testcert.pem

curl --cacert testcert.pem --insecure https://localhost:4443/

The curl call should be successful and you should receive an html status message including information about the ciphers used and various session parameters (because of the -www option).

Once you have a usable PEM certificate (which contains the private key and certificate), you can use it in an HAProxy frontend and handshakes should work. No provider-specific option needs to be added to frontend and backend configuration lines, the proper use of the loaded provider will be completely managed by OpenSSL.