diff --git a/contrib/pgcrypto/expected/init.out b/contrib/pgcrypto/expected/init.out index d1341a6715..8a52ec76e9 100644 --- a/contrib/pgcrypto/expected/init.out +++ b/contrib/pgcrypto/expected/init.out @@ -2,6 +2,13 @@ -- init pgcrypto -- CREATE EXTENSION pgcrypto; +-- check that the compatibility function agrees with core +select public.fips_mode() = pg_catalog.fips_mode() AS same_fips_mode; + same_fips_mode +---------------- + t +(1 row) + -- check error handling select gen_salt('foo'); ERROR: gen_salt: Unknown salt algorithm diff --git a/contrib/pgcrypto/openssl.c b/contrib/pgcrypto/openssl.c index c4ab2d6c71..4dba6d28b9 100644 --- a/contrib/pgcrypto/openssl.c +++ b/contrib/pgcrypto/openssl.c @@ -36,6 +36,7 @@ #include #include +#include "common/openssl.h" #include "px.h" #include "utils/memutils.h" #include "utils/resowner.h" @@ -838,33 +839,6 @@ ResOwnerReleaseOSSLCipher(Datum res) free_openssl_cipher(cipher); } -/* - * CheckFIPSMode - * - * Returns the FIPS mode of the underlying OpenSSL installation. - */ -bool -CheckFIPSMode(void) -{ - int fips_enabled = 0; - - /* - * EVP_default_properties_is_fips_enabled was added in OpenSSL 3.0, before - * that FIPS_mode() was used to test for FIPS being enabled. The last - * upstream OpenSSL version before 3.0 which supported FIPS was 1.0.2, but - * there are forks of 1.1.1 which are FIPS validated so we still need to - * test with FIPS_mode() even though we don't support 1.0.2. - */ - fips_enabled = -#if OPENSSL_VERSION_NUMBER >= 0x30000000L - EVP_default_properties_is_fips_enabled(NULL); -#else - FIPS_mode(); -#endif - - return (fips_enabled == 1); -} - /* * CheckBuiltinCryptoMode * @@ -885,7 +859,7 @@ CheckBuiltinCryptoMode(void) Assert(builtin_crypto_enabled == BC_FIPS); - if (CheckFIPSMode() == true) + if (pg_openssl_is_fips_enabled()) ereport(ERROR, errmsg("use of non-FIPS validated crypto not allowed when OpenSSL is in FIPS mode")); } diff --git a/contrib/pgcrypto/pgcrypto.c b/contrib/pgcrypto/pgcrypto.c index 24019f8289..0e1d3c1981 100644 --- a/contrib/pgcrypto/pgcrypto.c +++ b/contrib/pgcrypto/pgcrypto.c @@ -489,7 +489,8 @@ PG_FUNCTION_INFO_V1(pg_check_fipsmode); Datum pg_check_fipsmode(PG_FUNCTION_ARGS) { - PG_RETURN_BOOL(CheckFIPSMode()); + /* redirect to built-in function */ + return pg_fips_mode(fcinfo); } static void * diff --git a/contrib/pgcrypto/px.h b/contrib/pgcrypto/px.h index 6d48f39fc4..b0353be668 100644 --- a/contrib/pgcrypto/px.h +++ b/contrib/pgcrypto/px.h @@ -188,7 +188,6 @@ const char *px_resolve_alias(const PX_Alias *list, const char *name); void px_set_debug_handler(void (*handler) (const char *)); -bool CheckFIPSMode(void); void CheckBuiltinCryptoMode(void); #ifdef PX_DEBUG diff --git a/contrib/pgcrypto/sql/init.sql b/contrib/pgcrypto/sql/init.sql index 6388187996..054d0ec2fa 100644 --- a/contrib/pgcrypto/sql/init.sql +++ b/contrib/pgcrypto/sql/init.sql @@ -4,6 +4,9 @@ CREATE EXTENSION pgcrypto; +-- check that the compatibility function agrees with core +select public.fips_mode() = pg_catalog.fips_mode() AS same_fips_mode; + -- check error handling select gen_salt('foo'); select digest('foo', 'foo'); diff --git a/doc/src/sgml/func/func-info.sgml b/doc/src/sgml/func/func-info.sgml index 2f03766b67..9c0feb7a9a 100644 --- a/doc/src/sgml/func/func-info.sgml +++ b/doc/src/sgml/func/func-info.sgml @@ -149,6 +149,21 @@ + + + + fips_mode + + fips_mode () + boolean + + + Returns true if OpenSSL + is running with FIPS mode enabled, otherwise false. + This does not by itself indicate that the server is FIPS compliant. + + + diff --git a/doc/src/sgml/pgcrypto.sgml b/doc/src/sgml/pgcrypto.sgml index 00a35f3715..e0ec17491a 100644 --- a/doc/src/sgml/pgcrypto.sgml +++ b/doc/src/sgml/pgcrypto.sgml @@ -1244,7 +1244,9 @@ fips_mode() returns boolean Returns true if OpenSSL is - running with FIPS mode enabled, otherwise false. + running with FIPS mode enabled, otherwise false. This + function is retained for compatibility and internally calls the + core function of the same name. diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index c033e68ba1..b31f4c7345 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -29,6 +29,7 @@ #include "catalog/system_fk_info.h" #include "commands/tablespace.h" #include "common/keywords.h" +#include "common/openssl.h" #include "funcapi.h" #include "miscadmin.h" #include "nodes/miscnodes.h" @@ -219,6 +220,16 @@ current_database(PG_FUNCTION_ARGS) } +/* + * Return whether FIPS mode is enabled in the underlying OpenSSL installation. + */ +Datum +pg_fips_mode(PG_FUNCTION_ARGS) +{ + PG_RETURN_BOOL(pg_openssl_is_fips_enabled()); +} + + /* * current_query() * Expose the current query to the user (useful in stored procedures) diff --git a/src/common/Makefile b/src/common/Makefile index 3404601b6b..5127ada2a4 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -66,6 +66,7 @@ OBJS_COMMON = \ kwlookup.o \ link-canary.o \ md5_common.o \ + openssl.o \ parse_manifest.o \ percentrepl.o \ pg_get_line.o \ diff --git a/src/common/meson.build b/src/common/meson.build index fc89a17334..3522b378fa 100644 --- a/src/common/meson.build +++ b/src/common/meson.build @@ -20,6 +20,7 @@ common_sources = files( 'kwlookup.c', 'link-canary.c', 'md5_common.c', + 'openssl.c', 'parse_manifest.c', 'percentrepl.c', 'pg_get_line.c', diff --git a/src/common/openssl.c b/src/common/openssl.c new file mode 100644 index 0000000000..55021b7b5b --- /dev/null +++ b/src/common/openssl.c @@ -0,0 +1,51 @@ +/*------------------------------------------------------------------------- + * + * openssl.c + * OpenSSL supporting functionality shared between frontend and backend + * + * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/openssl.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#ifdef USE_OPENSSL +#include +#include +#endif + +#include "common/openssl.h" + + +/* + * Return whether FIPS mode is enabled in the underlying OpenSSL installation. + */ +bool +pg_openssl_is_fips_enabled(void) +{ +#ifdef USE_OPENSSL + /* + * EVP_default_properties_is_fips_enabled was added in OpenSSL 3.0, before + * that FIPS_mode() was used to test for FIPS being enabled. The last + * upstream OpenSSL version before 3.0 which supported FIPS was 1.0.2, but + * there are forks of 1.1.1 which are FIPS validated so we still need to + * test with FIPS_mode() even though we don't support 1.0.2. + */ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + return EVP_default_properties_is_fips_enabled(NULL) == 1; +#else + return FIPS_mode() == 1; +#endif +#else + return false; +#endif +} diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 6979c7d116..f4b2bda0c2 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -7045,6 +7045,9 @@ { oid => '315', descr => 'Is JIT compilation available in this session?', proname => 'pg_jit_available', provolatile => 'v', prorettype => 'bool', proargtypes => '', prosrc => 'pg_jit_available' }, +{ oid => '9312', descr => 'is OpenSSL FIPS mode enabled', + proname => 'fips_mode', provolatile => 'v', prorettype => 'bool', + proargtypes => '', prosrc => 'pg_fips_mode' }, { oid => '2971', descr => 'convert boolean to text', proname => 'text', prorettype => 'text', proargtypes => 'bool', diff --git a/src/include/common/openssl.h b/src/include/common/openssl.h index 07e8bfbe4f..7f0ff356df 100644 --- a/src/include/common/openssl.h +++ b/src/include/common/openssl.h @@ -40,4 +40,6 @@ #endif /* USE_OPENSSL */ +extern bool pg_openssl_is_fips_enabled(void); + #endif /* COMMON_OPENSSL_H */ diff --git a/src/test/regress/expected/misc_functions.out b/src/test/regress/expected/misc_functions.out index 2990e0c4f2..dc7e8efbc1 100644 --- a/src/test/regress/expected/misc_functions.out +++ b/src/test/regress/expected/misc_functions.out @@ -2,6 +2,18 @@ \getenv libdir PG_LIBDIR \getenv dlsuffix PG_DLSUFFIX \set regresslib :libdir '/regress' :dlsuffix +-- +-- fips_mode() +-- +SELECT CASE WHEN current_setting('ssl_library') = '' + THEN NOT fips_mode() + ELSE fips_mode() IS NOT NULL + END AS valid; + valid +------- + t +(1 row) + -- -- num_nulls() -- diff --git a/src/test/regress/sql/misc_functions.sql b/src/test/regress/sql/misc_functions.sql index 950d9ab1a4..3c05745dc6 100644 --- a/src/test/regress/sql/misc_functions.sql +++ b/src/test/regress/sql/misc_functions.sql @@ -4,6 +4,15 @@ \set regresslib :libdir '/regress' :dlsuffix +-- +-- fips_mode() +-- + +SELECT CASE WHEN current_setting('ssl_library') = '' + THEN NOT fips_mode() + ELSE fips_mode() IS NOT NULL + END AS valid; + -- -- num_nulls() -- -- 2.34.1