Opened 4 months ago

Last modified 4 months ago

#2449 new enhancement

Allow using OpenSSL 3.0 "provider" API instead of deprecated "engine" API

Reported by: nickrbogdanov@… Owned by:
Priority: minor Milestone:
Component: nginx-core Version: 1.23.x
Keywords: openssl, provider, tpm, pkcs11, engine Cc:
uname -a: Linux www 5.15.0-58-generic #64-Ubuntu SMP Thu Jan 5 11:43:13 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 3.0.2 15 Mar 2022
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -ffile-prefix-map=/build/nginx-d8gVax/nginx-1.18.0=. -flto=auto -ffat-lto-objects -flto=auto -ffat-lto-objects -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -flto=auto -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --add-dynamic-module=/build/nginx-d8gVax/nginx-1.18.0/debian/modules/http-geoip2 --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_sub_module

Description

I would like to use hardware encryption to protect my webserver's TLS privkey from theft. My server has a TPM 2.0 chip which supports this, but it's unnecessarily difficult to configure it in nginx. I'm proposing a change to make the process more user-friendly.

For background: old versions of OpenSSL supported HSMs and hardware offloading through the ENGINE API. In nginx this is enabled through the ssl_engine directive: hxxps://github.com/Infineon/optiga-tpm-cheatsheet#nginx--curl

(Please s/hxxps/https/ due to Trac spam filter)

In OpenSSL 3.0 the authors introduced a "Provider API" which is intended to replace the old ENGINE API. It works in a similar way. When using the CLI to sign or create TPM-backed keys, you add -provider tpm2 -provider base to the arguments: hxxps://github.com/Infineon/optiga-tpm-cheatsheet#pem-encoded-key-object-2

I'm running Ubuntu 22.04 LTS on this webserver. This Linux distribution has a tpm2-openssl package ( hxxps://github.com/tpm2-software/tpm2-openssl ) which conforms to the new OpenSSL 3.0 Provider API. The CLI examples on the optiga-tpm-cheatsheet work right out of the box, with no extra configuration. This makes it quick and easy to set up hardware-backed keys, just by installing a single package. For instance, anyone running this distro on an x86 Linux PC can do:

sudo apt install tpm2-openssl
openssl genpkey -provider tpm2 -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -out testkey.priv
echo "test" | openssl pkeyutl -provider tpm2 -provider base -digest sha256 -inkey testkey.priv -sign -rawin -hexdump

But unfortunately, at this time nginx only supports the ENGINE API, not the Provider API. In order to use hardware backed keys with nginx, users would need to compile, install, and configure the legacy tpm2tss ENGINE implementation, and keep it up to date themselves without help from the Debian/Ubuntu package maintainers.

I believe that with a small tweak to nginx, it would be possible for users to specify e.g.

ssl_provider tpm2,base

to tell OpenSSL 3.x to use the tpm2-openssl Provider to support hardware-backed private keys in nginx.

Change History (3)

comment:1 by Maxim Dounin, 4 months ago

Note that it should be possible to load OpenSSL providers using the configuration file, see README-PROVIDERS.md in OpenSSL sources for an example.

Support for loading providers directly from nginx configuration might still be useful from simplicity point of view, though it does not look like something required to use tpm2-openssl provider.

comment:2 by nickrbogdanov@…, 4 months ago

What I found when enabling the tpm2+base providers globally in openssl.cnf, is that applications could utilize the encrypted TSS2 privkeys but they lost the ability to sign using standard non-TPM-backed privkeys. Thus forcing me to choose between "all TPM2" or "all default," systemwide.

I think that if nginx called SSL_CTX_config(ctx, "nginx") then I could add an nginx-specific provider configuration to openssl.cnf and that would largely avoid this downside? But maybe there's a better way to do this without an nginx code change.

comment:3 by Maxim Dounin, 4 months ago

It is certainly possible to provide an nginx-specific OpenSSL configuration file via the OPENSSL_CONF environment variable.

Note: See TracTickets for help on using tickets.