pgcrypto: Make it possible to disable built-in crypto

When using OpenSSL and/or the underlying operating system in FIPS
mode no non-FIPS certified crypto implementations should be used.
While that is already possible by just not invoking the built-in
crypto in pgcrypto, this adds a GUC which prohibit the code from
being called.  This doesn't change the FIPS status of PostgreSQL
but can make it easier for sites which target FIPS compliance to
ensure that violations cannot occur.

Author: Daniel Gustafsson <daniel@yesql.se>
Author: Joe Conway <mail@joeconway.com>
Reviewed-by: Joe Conway <mail@joeconway.com>
Reviewed-by: Peter Eisentraut <peter@eisentraut.org>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Discussion: https://postgr.es/m/16b4a157-9ea1-44d0-b7b3-4c85df5de97b@joeconway.com
This commit is contained in:
Daniel Gustafsson 2025-01-24 14:25:08 +01:00
parent 924d89a354
commit 035f99cbeb
7 changed files with 121 additions and 0 deletions

View File

@ -28,4 +28,11 @@ FROM ctest;
t
(1 row)
-- check disabling of built in crypto functions
SET pgcrypto.builtin_crypto_enabled = off;
UPDATE ctest SET salt = gen_salt('des');
ERROR: use of built-in crypto functions is disabled
UPDATE ctest SET res = crypt(data, salt);
ERROR: use of built-in crypto functions is disabled
RESET pgcrypto.builtin_crypto_enabled;
DROP TABLE ctest;

View File

@ -31,6 +31,7 @@
#include "postgres.h"
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/rand.h>
@ -821,3 +822,28 @@ CheckFIPSMode(void)
return (fips_enabled == 1);
}
/*
* CheckBuiltinCryptoMode
*
* Function for erroring out in case built-in crypto is executed when the user
* has disabled it. If builtin_crypto_enabled is set to BC_OFF or BC_FIPS and
* OpenSSL is operating in FIPS mode the function will error out, else the
* query executing built-in crypto can proceed.
*/
void
CheckBuiltinCryptoMode(void)
{
if (builtin_crypto_enabled == BC_ON)
return;
if (builtin_crypto_enabled == BC_OFF)
ereport(ERROR,
errmsg("use of built-in crypto functions is disabled"));
Assert(builtin_crypto_enabled == BC_FIPS);
if (CheckFIPSMode() == true)
ereport(ERROR,
errmsg("use of non-FIPS validated crypto not allowed when OpenSSL is in FIPS mode"));
}

View File

@ -38,16 +38,47 @@
#include "px-crypt.h"
#include "px.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "varatt.h"
PG_MODULE_MAGIC;
/* private stuff */
static const struct config_enum_entry builtin_crypto_options[] = {
{"on", BC_ON, false},
{"off", BC_OFF, false},
{"fips", BC_FIPS, false},
{NULL, 0, false}
};
typedef int (*PFN) (const char *name, void **res);
static void *find_provider(text *name, PFN provider_lookup, const char *desc,
int silent);
int builtin_crypto_enabled = BC_ON;
/*
* Entrypoint of this module.
*/
void
_PG_init(void)
{
DefineCustomEnumVariable("pgcrypto.builtin_crypto_enabled",
"Sets if builtin crypto functions are enabled.",
"\"on\" enables builtin crypto, \"off\" unconditionally disables and \"fips\" "
"will disable builtin crypto if OpenSSL is in FIPS mode",
&builtin_crypto_enabled,
BC_ON,
builtin_crypto_options,
PGC_SUSET,
0,
NULL,
NULL,
NULL);
MarkGUCPrefixReserved("pgcrypto");
}
/* SQL function: hash(bytea, text) returns bytea */
PG_FUNCTION_INFO_V1(pg_digest);

View File

@ -91,6 +91,8 @@ px_crypt(const char *psw, const char *salt, char *buf, unsigned len)
{
const struct px_crypt_algo *c;
CheckBuiltinCryptoMode();
for (c = px_crypt_list; c->id; c++)
{
if (!c->id_len)
@ -135,6 +137,8 @@ px_gen_salt(const char *salt_type, char *buf, int rounds)
char *p;
char rbuf[16];
CheckBuiltinCryptoMode();
for (g = gen_list; g->name; g++)
if (pg_strcasecmp(g->name, salt_type) == 0)
break;

View File

@ -89,6 +89,12 @@
#define PXE_PGP_UNSUPPORTED_PUBALGO -122
#define PXE_PGP_MULTIPLE_SUBKEYS -123
typedef enum BuiltinCryptoOptions
{
BC_ON,
BC_OFF,
BC_FIPS,
} BuiltinCryptoOptions;
typedef struct px_digest PX_MD;
typedef struct px_alias PX_Alias;
@ -96,6 +102,8 @@ typedef struct px_hmac PX_HMAC;
typedef struct px_cipher PX_Cipher;
typedef struct px_combo PX_Combo;
extern int builtin_crypto_enabled;
struct px_digest
{
unsigned (*result_size) (PX_MD *h);
@ -183,6 +191,7 @@ void px_set_debug_handler(void (*handler) (const char *));
void px_memset(void *ptr, int c, size_t len);
bool CheckFIPSMode(void);
void CheckBuiltinCryptoMode(void);
#ifdef PX_DEBUG
void px_debug(const char *fmt,...) pg_attribute_printf(1, 2);

View File

@ -18,4 +18,10 @@ UPDATE ctest SET res = crypt(data, salt);
SELECT res = crypt(data, res) AS "worked"
FROM ctest;
-- check disabling of built in crypto functions
SET pgcrypto.builtin_crypto_enabled = off;
UPDATE ctest SET salt = gen_salt('des');
UPDATE ctest SET res = crypt(data, salt);
RESET pgcrypto.builtin_crypto_enabled;
DROP TABLE ctest;

View File

@ -1165,6 +1165,44 @@ fips_mode() returns boolean
</para>
</sect2>
<sect2 id="pgcrypto-configuration-parameters">
<title>Configuration Parameters</title>
<para>
There is one configuration parameter that controls the behavior of
<filename>pgcrypto</filename>.
</para>
<variablelist>
<varlistentry id="pgcrypto-configuration-parameters-builtin_crypto_enabled">
<term>
<varname>pgcrypto.builtin_crypto_enabled</varname> (<type>enum</type>)
<indexterm>
<primary><varname>pgcrypto.builtin_crypto_enabled</varname> configuration
parameter</primary>
</indexterm>
</term>
<listitem>
<para>
<varname>pgcrypto.builtin_crypto_enabled</varname> determines if the
built in crypto functions <function>gen_salt()</function>, and
<function>crypt()</function> are available for use. Setting this to
<literal>off</literal> disables these functions. <literal>on</literal>
(the default) enables these functions to work normally.
<literal>fips</literal> disables these functions if
<productname>OpenSSL</productname> is detected to operate in FIPS mode.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
In ordinary usage, this parameter is set
in <filename>postgresql.conf</filename>, although superusers can alter it
on-the-fly within their own sessions.
</para>
</sect2>
<sect2 id="pgcrypto-notes">
<title>Notes</title>