When built against OpenSSL 3.0 or newer, PostgreSQL's OpenSSL crypto backend
still uses pre-3.0 interfaces that do not go through the provider framework,
so a loaded provider's implementation is not used:
- HMAC uses HMAC_CTX / HMAC_Init_ex, deprecated since 3.0;
- cryptohash and channel binding initialize the digest with the implicit
static MDs (EVP_sha256() etc.).
I checked what the digest path actually resolves to at run time. After
EVP_DigestInit_ex(ctx, EVP_sha256(), NULL) -- what the backend does today --
EVP_MD_get0_provider() on the context's MD returns no provider (the legacy
built-in is used). After EVP_MD_fetch(NULL, "SHA256", NULL) the MD reports
the "default" provider. In other words the current code does not reach a
loaded provider for these digests at all; a third-party or FIPS provider is
not consulted. (A small standalone program that prints this via
EVP_MD_get0_provider()/EVP_MAC_get0_provider() is attached as
provider_probe.c.)
This series switches those paths to the provider-fetch APIs -- EVP_MAC_fetch
for HMAC, EVP_MD_fetch for digests -- on OpenSSL 3.0 and newer, keeping the
existing code for older OpenSSL and for LibreSSL (guarded by
OPENSSL_VERSION_NUMBER >= 0x30000000L). The fetches use the default library
context and a NULL property query, so no dependency is added and no
particular provider is required; the provider is selected by the usual
OpenSSL configuration (openssl.cnf).
On EVP_MAC (0001): when the HMAC abstraction was first built, EVP_MAC was
set aside deliberately -- "a bit too new to use though, as we need to support
OpenSSL down to 1.0.1 on HEAD ... So instead I have decided to rely on the
older interface based on HMAC_Init_ex()" [1]. That constraint no longer
holds: the minimum supported OpenSSL is now 1.1.1, and this change is
confined to 3.0+ by the version guard, so the original reason for preferring
HMAC_CTX is gone. 0001 also removes use of an interface deprecated in 3.0,
which stands on its own regardless of provider routing.
Notes:
* Authentication does no crypto of its own -- SCRAM and md5 ride
pg_hmac/pg_cryptohash -- so the whole auth surface follows the active
provider once the backend does.
* md5 authentication then depends on MD5 being offered by the provider,
so it is unavailable under FIPS. That is the intended behavior and
matches the reasoning already given for moving MD5 to EVP: otherwise
PostgreSQL would "cheat if FIPS is enabled because MD5 should not be
authorized", whereas EVP "allows us to rely on OpenSSL to control such
restrictions" [2]. Every md5 hashing call site already fails closed, so
a FIPS provider rejects md5 auth rather than bypassing it. 0002
documents this and points to scram-sha-256.
* EVP_MAC_fetch/EVP_MD_fetch do a provider lookup. The fetched object is
cached in the context (for cryptohash it is fetched once, since the
digest type is fixed for the context's lifetime). These paths are not
hot -- SCRAM runs at connection time and hash-seed setup at startup --
so the lookup is not on any tight loop.
* pg_strong_random() already calls RAND_bytes(), which draws from the
default provider's RNG under 3.0, so nothing there needs to change.
* pgcrypto is deliberately out of scope: it exposes legacy ciphers (DES,
Blowfish, CAST5) that depend on OpenSSL's legacy provider and warrant a
separate discussion.
Tested with OpenSSL 3.0.13: clean build, src/test/regress (245),
src/test/ssl (423, including tls-server-end-point channel binding in
002_scram.pl) and src/test/authentication (323) all pass; HMAC and the
digests were also checked against RFC 4231 and NIST known-answer vectors.
I'll add this to the open commitfest.
[1] https://postgr.es/m/[email protected]
[2] https://postgr.es/m/[email protected]
Mark Atwood (3):
Use EVP_MAC for HMAC with OpenSSL 3.0 and later
Fetch digests explicitly for cryptohash with OpenSSL 3.0 and later
Fetch the channel binding digest explicitly with OpenSSL 3.0 and later
doc/src/sgml/client-auth.sgml | 11 +++
src/backend/libpq/be-secure-openssl.c | 73 +++++++++++++++----
src/common/cryptohash_openssl.c | 57 +++++++++++++++
src/common/hmac_openssl.c | 92 ++++++++++++++++++++++++
src/interfaces/libpq/fe-secure-openssl.c | 86 +++++++++++++++++-----
5 files changed, 285 insertions(+), 34 deletions(-)
--
2.43.0