This adds a SQL callable function for reading and returning the status
of FIPS configuration of OpenSSL.  If OpenSSL is operating with FIPS
enabled it will return true, otherwise false.  As this adds a function
to the SQL file, bump the extension version to 1.4.
Author: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Joe Conway <mail@joeconway.com>
Discussion: https://postgr.es/m/
8f979145-e206-475a-a31b-
73c977a4134c@joeconway.com
 
 EXTENSION = pgcrypto
 DATA = pgcrypto--1.3.sql pgcrypto--1.2--1.3.sql pgcrypto--1.1--1.2.sql \
-   pgcrypto--1.0--1.1.sql
+   pgcrypto--1.0--1.1.sql pgcrypto--1.3--1.4.sql
 PGFILEDESC = "pgcrypto - cryptographic functions"
 
 REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
 
   'pgcrypto--1.1--1.2.sql',
   'pgcrypto--1.2--1.3.sql',
   'pgcrypto--1.3.sql',
+  'pgcrypto--1.3--1.4.sql',
   'pgcrypto.control',
   kwargs: contrib_data_args,
 )
 
 {
    free_openssl_cipher((OSSLCipher *) DatumGetPointer(res));
 }
+
+/*
+ * 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);
+}
 
--- /dev/null
+/* contrib/pgcrypto/pgcrypto--1.3--1.4.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION pgcrypto UPDATE TO '1.4'" to load this file. \quit
+
+CREATE FUNCTION fips_mode()
+RETURNS bool
+AS 'MODULE_PATHNAME', 'pg_check_fipsmode'
+LANGUAGE C VOLATILE STRICT PARALLEL SAFE;
 
    return gen_random_uuid(fcinfo);
 }
 
+PG_FUNCTION_INFO_V1(pg_check_fipsmode);
+
+Datum
+pg_check_fipsmode(PG_FUNCTION_ARGS)
+{
+   PG_RETURN_BOOL(CheckFIPSMode());
+}
+
 static void *
 find_provider(text *name,
              PFN provider_lookup,
 
 # pgcrypto extension
 comment = 'cryptographic functions'
-default_version = '1.3'
+default_version = '1.4'
 module_pathname = '$libdir/pgcrypto'
 relocatable = true
 trusted = true
 
 
 void       px_memset(void *ptr, int c, size_t len);
 
+bool       CheckFIPSMode(void);
+
 #ifdef PX_DEBUG
 void       px_debug(const char *fmt,...) pg_attribute_printf(1, 2);
 #else
 
   </para>
  </sect2>
 
+ <sect2 id="pgcrypto-openssl-support-funcs">
+  <title>OpenSSL Support Functions</title>
+
+  <indexterm>
+   <primary>fips_mode</primary>
+  </indexterm>
+
+<synopsis>
+fips_mode() returns boolean
+</synopsis>
+  <para>
+   Returns <literal>true</literal> if <productname>OpenSSL</productname> is
+   running with FIPS mode enabled, otherwise <literal>false</literal>.
+  </para>
+ </sect2>
+
  <sect2 id="pgcrypto-notes">
   <title>Notes</title>