public inbox for [email protected]
help / color / mirror / Atom feedFrom: Michael Paquier <[email protected]>
To: Daniel Gustafsson <[email protected]>
Cc: [email protected]
Cc: [email protected]
Subject: Re: BUG #19457: RE: pgp_sym_encrypt silently accepts non-FIPS ciphers (bf, cast5, 3des) when OpenSSL is in FIPS mod
Date: Fri, 24 Apr 2026 13:20:50 +0900
Message-ID: <[email protected]> (raw)
In-Reply-To: <[email protected]>
References: <[email protected]>
<[email protected]>
On Tue, Apr 21, 2026 at 04:04:40PM +0200, Daniel Gustafsson wrote:
> Not just FIPS, it should check CheckBuiltinCryptoMode() to be consistent with
> the other builtin checks.
I am interesting in getting that fixed for the next point release, so
I have given it a try, finishing with the attached. This would cause
pgp_sym_encrypt() and pgp_sym_decrypt() to complain when the builtin
mode is disabled, making things more consistent with the surroundings.
I agree that this could break environments where builtin_crypto is
off, as the functions would now be blocked, but I am not sure that
this is worth worrying about as builtin_crypto=on is the default.
Daniel, what do you think?
--
Michael
From f336e4e09f3d8dda9dd55b855f3eb2cd0913436a Mon Sep 17 00:00:00 2001
From: Michael Paquier <[email protected]>
Date: Fri, 24 Apr 2026 13:12:06 +0900
Subject: [PATCH] pgcrypto: Respect builtin_crypto_enabled for PGP ciphers
pgp_sym_encrypt() and pgp_pub_encrypt() silently accepted
non-FIPS-approved cipher algorithms even if OpenSSL was in FIPS mode and
pgcrypto.builtin_crypto_enabled was set to its 'fips' mode. This causes
pgcrypto to be non-compliant.
A new flag is added to the information list of ciphers, upon which a
filtering is done should FIPS be enabled, depending on the builtin
crypto mode.
Reported-by: Shishir Sharma <[email protected]>
Suggested-by: Daniel Gustafsson <[email protected]>
Discussion: https://postgr.es/m/[email protected]
Backpatch-through: 18
---
doc/src/sgml/pgcrypto.sgml | 9 +-
contrib/pgcrypto/Makefile | 2 +-
contrib/pgcrypto/expected/pgp-fips-cipher.out | 77 +++++++++++++++
.../pgcrypto/expected/pgp-fips-cipher_1.out | 95 +++++++++++++++++++
contrib/pgcrypto/meson.build | 3 +-
contrib/pgcrypto/pgp.c | 32 +++++--
contrib/pgcrypto/sql/pgp-fips-cipher.sql | 46 +++++++++
7 files changed, 250 insertions(+), 14 deletions(-)
create mode 100644 contrib/pgcrypto/expected/pgp-fips-cipher.out
create mode 100644 contrib/pgcrypto/expected/pgp-fips-cipher_1.out
create mode 100644 contrib/pgcrypto/sql/pgp-fips-cipher.sql
diff --git a/doc/src/sgml/pgcrypto.sgml b/doc/src/sgml/pgcrypto.sgml
index 6fc2069ad3ec..96b043097eaa 100644
--- a/doc/src/sgml/pgcrypto.sgml
+++ b/doc/src/sgml/pgcrypto.sgml
@@ -1236,12 +1236,17 @@ fips_mode() returns boolean
<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
+ built in crypto functions <function>gen_salt()</function>,
+ <function>crypt()</function>, <function>pgp_sym_encrypt()</function>
+ and <function>pgp_pub_encrypt()</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.
+ <function>pgp_sym_encrypt()</function> and
+ <function>pgp_pub_encrypt()</function> are disabled for ciphers that
+ are not FIPS-approved.
</para>
</listitem>
</varlistentry>
diff --git a/contrib/pgcrypto/Makefile b/contrib/pgcrypto/Makefile
index 17d2b0c5ed17..dde8933f706d 100644
--- a/contrib/pgcrypto/Makefile
+++ b/contrib/pgcrypto/Makefile
@@ -45,7 +45,7 @@ REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt pgp-encrypt-md5 $(CF_PGP_TESTS) \
pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-pubkey-session \
- pgp-info crypt-shacrypt
+ pgp-info crypt-shacrypt pgp-fips-cipher
ifdef USE_PGXS
PG_CONFIG = pg_config
diff --git a/contrib/pgcrypto/expected/pgp-fips-cipher.out b/contrib/pgcrypto/expected/pgp-fips-cipher.out
new file mode 100644
index 000000000000..eed6db0a6490
--- /dev/null
+++ b/contrib/pgcrypto/expected/pgp-fips-cipher.out
@@ -0,0 +1,77 @@
+--
+-- PGP FIPS cipher restrictions
+--
+-- crypto functions disabled. All PGP encryption are blocked.
+SET pgcrypto.builtin_crypto_enabled = off;
+SELECT pgp_sym_encrypt('data', 'key');
+ERROR: use of built-in crypto functions is disabled
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=aes256');
+ERROR: use of built-in crypto functions is disabled
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=bf');
+ERROR: use of built-in crypto functions is disabled
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=3des');
+ERROR: use of built-in crypto functions is disabled
+RESET pgcrypto.builtin_crypto_enabled;
+-- crypto functions enabled. All work.
+SET pgcrypto.builtin_crypto_enabled = on;
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes128'),
+ 'key', 'expect-cipher-algo=aes128');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes192'),
+ 'key', 'expect-cipher-algo=aes192');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes256'),
+ 'key', 'expect-cipher-algo=aes256');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=bf'),
+ 'key', 'expect-cipher-algo=bf');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=3des'),
+ 'key', 'expect-cipher-algo=3des');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=cast5'),
+ 'key', 'expect-cipher-algo=cast5');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+RESET pgcrypto.builtin_crypto_enabled;
+-- crypto functions with FIPS mode.
+SELECT fips_mode() AS is_fips \gset
+\if :is_fips
+SET pgcrypto.builtin_crypto_enabled = fips;
+-- non-AES ciphers must error
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=bf');
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=3des');
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=cast5');
+-- AES ciphers work
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes128'),
+ 'key', 'expect-cipher-algo=aes128');
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes256'),
+ 'key', 'expect-cipher-algo=aes256');
+-- AES round trip under FIPS
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('FIPS round trip test', 'key',
+ 'cipher-algo=aes256'), 'key');
+RESET pgcrypto.builtin_crypto_enabled;
+\endif
diff --git a/contrib/pgcrypto/expected/pgp-fips-cipher_1.out b/contrib/pgcrypto/expected/pgp-fips-cipher_1.out
new file mode 100644
index 000000000000..8ba974cb4c7a
--- /dev/null
+++ b/contrib/pgcrypto/expected/pgp-fips-cipher_1.out
@@ -0,0 +1,95 @@
+--
+-- PGP FIPS cipher restrictions
+--
+-- crypto functions disabled. All PGP encryption are blocked.
+SET pgcrypto.builtin_crypto_enabled = off;
+SELECT pgp_sym_encrypt('data', 'key');
+ERROR: use of built-in crypto functions is disabled
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=aes256');
+ERROR: use of built-in crypto functions is disabled
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=bf');
+ERROR: use of built-in crypto functions is disabled
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=3des');
+ERROR: use of built-in crypto functions is disabled
+RESET pgcrypto.builtin_crypto_enabled;
+-- crypto functions enabled. All work.
+SET pgcrypto.builtin_crypto_enabled = on;
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes128'),
+ 'key', 'expect-cipher-algo=aes128');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes192'),
+ 'key', 'expect-cipher-algo=aes192');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes256'),
+ 'key', 'expect-cipher-algo=aes256');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=bf'),
+ 'key', 'expect-cipher-algo=bf');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=3des'),
+ 'key', 'expect-cipher-algo=3des');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=cast5'),
+ 'key', 'expect-cipher-algo=cast5');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+RESET pgcrypto.builtin_crypto_enabled;
+-- crypto functions with FIPS mode.
+SELECT fips_mode() AS is_fips \gset
+\if :is_fips
+SET pgcrypto.builtin_crypto_enabled = fips;
+-- non-AES ciphers must error
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=bf');
+ERROR: cipher bf is not FIPS approved
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=3des');
+ERROR: cipher 3des is not FIPS approved
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=cast5');
+ERROR: cipher cast5 is not FIPS approved
+-- AES ciphers work
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes128'),
+ 'key', 'expect-cipher-algo=aes128');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes256'),
+ 'key', 'expect-cipher-algo=aes256');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+-- AES round trip under FIPS
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('FIPS round trip test', 'key',
+ 'cipher-algo=aes256'), 'key');
+ pgp_sym_decrypt
+----------------------
+ FIPS round trip test
+(1 row)
+
+RESET pgcrypto.builtin_crypto_enabled;
+\endif
diff --git a/contrib/pgcrypto/meson.build b/contrib/pgcrypto/meson.build
index 4f255c8cb05d..f922c1fb8bdd 100644
--- a/contrib/pgcrypto/meson.build
+++ b/contrib/pgcrypto/meson.build
@@ -54,7 +54,8 @@ pgcrypto_regress = [
'pgp-pubkey-encrypt',
'pgp-pubkey-session',
'pgp-info',
- 'crypt-shacrypt'
+ 'crypt-shacrypt',
+ 'pgp-fips-cipher',
]
pgcrypto_openssl_sources = files(
diff --git a/contrib/pgcrypto/pgp.c b/contrib/pgcrypto/pgp.c
index 8a6a6c2adf1f..2d5375910a9c 100644
--- a/contrib/pgcrypto/pgp.c
+++ b/contrib/pgcrypto/pgp.c
@@ -63,6 +63,7 @@ struct cipher_info
const char *int_name;
int key_len;
int block_len;
+ bool fips_allowed;
};
static const struct digest_info digest_list[] = {
@@ -77,16 +78,16 @@ static const struct digest_info digest_list[] = {
};
static const struct cipher_info cipher_list[] = {
- {"3des", PGP_SYM_DES3, "3des-ecb", 192 / 8, 64 / 8},
- {"cast5", PGP_SYM_CAST5, "cast5-ecb", 128 / 8, 64 / 8},
- {"bf", PGP_SYM_BLOWFISH, "bf-ecb", 128 / 8, 64 / 8},
- {"blowfish", PGP_SYM_BLOWFISH, "bf-ecb", 128 / 8, 64 / 8},
- {"aes", PGP_SYM_AES_128, "aes-ecb", 128 / 8, 128 / 8},
- {"aes128", PGP_SYM_AES_128, "aes-ecb", 128 / 8, 128 / 8},
- {"aes192", PGP_SYM_AES_192, "aes-ecb", 192 / 8, 128 / 8},
- {"aes256", PGP_SYM_AES_256, "aes-ecb", 256 / 8, 128 / 8},
- {"twofish", PGP_SYM_TWOFISH, "twofish-ecb", 256 / 8, 128 / 8},
- {NULL, 0, NULL}
+ {"3des", PGP_SYM_DES3, "3des-ecb", 192 / 8, 64 / 8, false},
+ {"cast5", PGP_SYM_CAST5, "cast5-ecb", 128 / 8, 64 / 8, false},
+ {"bf", PGP_SYM_BLOWFISH, "bf-ecb", 128 / 8, 64 / 8, false},
+ {"blowfish", PGP_SYM_BLOWFISH, "bf-ecb", 128 / 8, 64 / 8, false},
+ {"aes", PGP_SYM_AES_128, "aes-ecb", 128 / 8, 128 / 8, true},
+ {"aes128", PGP_SYM_AES_128, "aes-ecb", 128 / 8, 128 / 8, true},
+ {"aes192", PGP_SYM_AES_192, "aes-ecb", 192 / 8, 128 / 8, true},
+ {"aes256", PGP_SYM_AES_256, "aes-ecb", 256 / 8, 128 / 8, true},
+ {"twofish", PGP_SYM_TWOFISH, "twofish-ecb", 256 / 8, 128 / 8, false},
+ {NULL, 0, NULL, 0, 0, false}
};
static const struct cipher_info *
@@ -162,6 +163,17 @@ pgp_load_cipher(int code, PX_Cipher **res)
if (i == NULL)
return PXE_PGP_CORRUPT_DATA;
+ CheckBuiltinCryptoMode();
+
+ /*
+ * In FIPS mode, only allow ciphers that are FIPS approved.
+ */
+ if (builtin_crypto_enabled == BC_FIPS &&
+ CheckFIPSMode() &&
+ !i->fips_allowed)
+ ereport(ERROR,
+ errmsg("cipher %s is not FIPS approved", i->name));
+
err = px_find_cipher(i->int_name, res);
if (err == 0)
return 0;
diff --git a/contrib/pgcrypto/sql/pgp-fips-cipher.sql b/contrib/pgcrypto/sql/pgp-fips-cipher.sql
new file mode 100644
index 000000000000..cb425a9ccdf9
--- /dev/null
+++ b/contrib/pgcrypto/sql/pgp-fips-cipher.sql
@@ -0,0 +1,46 @@
+--
+-- PGP FIPS cipher restrictions
+--
+
+-- crypto functions disabled. All PGP encryption are blocked.
+SET pgcrypto.builtin_crypto_enabled = off;
+SELECT pgp_sym_encrypt('data', 'key');
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=aes256');
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=bf');
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=3des');
+RESET pgcrypto.builtin_crypto_enabled;
+
+-- crypto functions enabled. All work.
+SET pgcrypto.builtin_crypto_enabled = on;
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes128'),
+ 'key', 'expect-cipher-algo=aes128');
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes192'),
+ 'key', 'expect-cipher-algo=aes192');
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes256'),
+ 'key', 'expect-cipher-algo=aes256');
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=bf'),
+ 'key', 'expect-cipher-algo=bf');
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=3des'),
+ 'key', 'expect-cipher-algo=3des');
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=cast5'),
+ 'key', 'expect-cipher-algo=cast5');
+RESET pgcrypto.builtin_crypto_enabled;
+
+-- crypto functions with FIPS mode.
+SELECT fips_mode() AS is_fips \gset
+\if :is_fips
+SET pgcrypto.builtin_crypto_enabled = fips;
+-- non-AES ciphers must error
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=bf');
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=3des');
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=cast5');
+-- AES ciphers work
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes128'),
+ 'key', 'expect-cipher-algo=aes128');
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes256'),
+ 'key', 'expect-cipher-algo=aes256');
+-- AES round trip under FIPS
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('FIPS round trip test', 'key',
+ 'cipher-algo=aes256'), 'key');
+RESET pgcrypto.builtin_crypto_enabled;
+\endif
--
2.53.0
Attachments:
[text/plain] 0001-pgcrypto-Respect-builtin_crypto_enabled-for-PGP-ciph.patch (13.7K, 2-0001-pgcrypto-Respect-builtin_crypto_enabled-for-PGP-ciph.patch)
download | inline diff:
From f336e4e09f3d8dda9dd55b855f3eb2cd0913436a Mon Sep 17 00:00:00 2001
From: Michael Paquier <[email protected]>
Date: Fri, 24 Apr 2026 13:12:06 +0900
Subject: [PATCH] pgcrypto: Respect builtin_crypto_enabled for PGP ciphers
pgp_sym_encrypt() and pgp_pub_encrypt() silently accepted
non-FIPS-approved cipher algorithms even if OpenSSL was in FIPS mode and
pgcrypto.builtin_crypto_enabled was set to its 'fips' mode. This causes
pgcrypto to be non-compliant.
A new flag is added to the information list of ciphers, upon which a
filtering is done should FIPS be enabled, depending on the builtin
crypto mode.
Reported-by: Shishir Sharma <[email protected]>
Suggested-by: Daniel Gustafsson <[email protected]>
Discussion: https://postgr.es/m/[email protected]
Backpatch-through: 18
---
doc/src/sgml/pgcrypto.sgml | 9 +-
contrib/pgcrypto/Makefile | 2 +-
contrib/pgcrypto/expected/pgp-fips-cipher.out | 77 +++++++++++++++
.../pgcrypto/expected/pgp-fips-cipher_1.out | 95 +++++++++++++++++++
contrib/pgcrypto/meson.build | 3 +-
contrib/pgcrypto/pgp.c | 32 +++++--
contrib/pgcrypto/sql/pgp-fips-cipher.sql | 46 +++++++++
7 files changed, 250 insertions(+), 14 deletions(-)
create mode 100644 contrib/pgcrypto/expected/pgp-fips-cipher.out
create mode 100644 contrib/pgcrypto/expected/pgp-fips-cipher_1.out
create mode 100644 contrib/pgcrypto/sql/pgp-fips-cipher.sql
diff --git a/doc/src/sgml/pgcrypto.sgml b/doc/src/sgml/pgcrypto.sgml
index 6fc2069ad3ec..96b043097eaa 100644
--- a/doc/src/sgml/pgcrypto.sgml
+++ b/doc/src/sgml/pgcrypto.sgml
@@ -1236,12 +1236,17 @@ fips_mode() returns boolean
<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
+ built in crypto functions <function>gen_salt()</function>,
+ <function>crypt()</function>, <function>pgp_sym_encrypt()</function>
+ and <function>pgp_pub_encrypt()</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.
+ <function>pgp_sym_encrypt()</function> and
+ <function>pgp_pub_encrypt()</function> are disabled for ciphers that
+ are not FIPS-approved.
</para>
</listitem>
</varlistentry>
diff --git a/contrib/pgcrypto/Makefile b/contrib/pgcrypto/Makefile
index 17d2b0c5ed17..dde8933f706d 100644
--- a/contrib/pgcrypto/Makefile
+++ b/contrib/pgcrypto/Makefile
@@ -45,7 +45,7 @@ REGRESS = init md5 sha1 hmac-md5 hmac-sha1 blowfish rijndael \
crypt-des crypt-md5 crypt-blowfish crypt-xdes \
pgp-armor pgp-decrypt pgp-encrypt pgp-encrypt-md5 $(CF_PGP_TESTS) \
pgp-pubkey-decrypt pgp-pubkey-encrypt pgp-pubkey-session \
- pgp-info crypt-shacrypt
+ pgp-info crypt-shacrypt pgp-fips-cipher
ifdef USE_PGXS
PG_CONFIG = pg_config
diff --git a/contrib/pgcrypto/expected/pgp-fips-cipher.out b/contrib/pgcrypto/expected/pgp-fips-cipher.out
new file mode 100644
index 000000000000..eed6db0a6490
--- /dev/null
+++ b/contrib/pgcrypto/expected/pgp-fips-cipher.out
@@ -0,0 +1,77 @@
+--
+-- PGP FIPS cipher restrictions
+--
+-- crypto functions disabled. All PGP encryption are blocked.
+SET pgcrypto.builtin_crypto_enabled = off;
+SELECT pgp_sym_encrypt('data', 'key');
+ERROR: use of built-in crypto functions is disabled
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=aes256');
+ERROR: use of built-in crypto functions is disabled
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=bf');
+ERROR: use of built-in crypto functions is disabled
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=3des');
+ERROR: use of built-in crypto functions is disabled
+RESET pgcrypto.builtin_crypto_enabled;
+-- crypto functions enabled. All work.
+SET pgcrypto.builtin_crypto_enabled = on;
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes128'),
+ 'key', 'expect-cipher-algo=aes128');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes192'),
+ 'key', 'expect-cipher-algo=aes192');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes256'),
+ 'key', 'expect-cipher-algo=aes256');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=bf'),
+ 'key', 'expect-cipher-algo=bf');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=3des'),
+ 'key', 'expect-cipher-algo=3des');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=cast5'),
+ 'key', 'expect-cipher-algo=cast5');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+RESET pgcrypto.builtin_crypto_enabled;
+-- crypto functions with FIPS mode.
+SELECT fips_mode() AS is_fips \gset
+\if :is_fips
+SET pgcrypto.builtin_crypto_enabled = fips;
+-- non-AES ciphers must error
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=bf');
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=3des');
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=cast5');
+-- AES ciphers work
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes128'),
+ 'key', 'expect-cipher-algo=aes128');
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes256'),
+ 'key', 'expect-cipher-algo=aes256');
+-- AES round trip under FIPS
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('FIPS round trip test', 'key',
+ 'cipher-algo=aes256'), 'key');
+RESET pgcrypto.builtin_crypto_enabled;
+\endif
diff --git a/contrib/pgcrypto/expected/pgp-fips-cipher_1.out b/contrib/pgcrypto/expected/pgp-fips-cipher_1.out
new file mode 100644
index 000000000000..8ba974cb4c7a
--- /dev/null
+++ b/contrib/pgcrypto/expected/pgp-fips-cipher_1.out
@@ -0,0 +1,95 @@
+--
+-- PGP FIPS cipher restrictions
+--
+-- crypto functions disabled. All PGP encryption are blocked.
+SET pgcrypto.builtin_crypto_enabled = off;
+SELECT pgp_sym_encrypt('data', 'key');
+ERROR: use of built-in crypto functions is disabled
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=aes256');
+ERROR: use of built-in crypto functions is disabled
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=bf');
+ERROR: use of built-in crypto functions is disabled
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=3des');
+ERROR: use of built-in crypto functions is disabled
+RESET pgcrypto.builtin_crypto_enabled;
+-- crypto functions enabled. All work.
+SET pgcrypto.builtin_crypto_enabled = on;
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes128'),
+ 'key', 'expect-cipher-algo=aes128');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes192'),
+ 'key', 'expect-cipher-algo=aes192');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes256'),
+ 'key', 'expect-cipher-algo=aes256');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=bf'),
+ 'key', 'expect-cipher-algo=bf');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=3des'),
+ 'key', 'expect-cipher-algo=3des');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=cast5'),
+ 'key', 'expect-cipher-algo=cast5');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+RESET pgcrypto.builtin_crypto_enabled;
+-- crypto functions with FIPS mode.
+SELECT fips_mode() AS is_fips \gset
+\if :is_fips
+SET pgcrypto.builtin_crypto_enabled = fips;
+-- non-AES ciphers must error
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=bf');
+ERROR: cipher bf is not FIPS approved
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=3des');
+ERROR: cipher 3des is not FIPS approved
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=cast5');
+ERROR: cipher cast5 is not FIPS approved
+-- AES ciphers work
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes128'),
+ 'key', 'expect-cipher-algo=aes128');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes256'),
+ 'key', 'expect-cipher-algo=aes256');
+ pgp_sym_decrypt
+-----------------
+ Secret.
+(1 row)
+
+-- AES round trip under FIPS
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('FIPS round trip test', 'key',
+ 'cipher-algo=aes256'), 'key');
+ pgp_sym_decrypt
+----------------------
+ FIPS round trip test
+(1 row)
+
+RESET pgcrypto.builtin_crypto_enabled;
+\endif
diff --git a/contrib/pgcrypto/meson.build b/contrib/pgcrypto/meson.build
index 4f255c8cb05d..f922c1fb8bdd 100644
--- a/contrib/pgcrypto/meson.build
+++ b/contrib/pgcrypto/meson.build
@@ -54,7 +54,8 @@ pgcrypto_regress = [
'pgp-pubkey-encrypt',
'pgp-pubkey-session',
'pgp-info',
- 'crypt-shacrypt'
+ 'crypt-shacrypt',
+ 'pgp-fips-cipher',
]
pgcrypto_openssl_sources = files(
diff --git a/contrib/pgcrypto/pgp.c b/contrib/pgcrypto/pgp.c
index 8a6a6c2adf1f..2d5375910a9c 100644
--- a/contrib/pgcrypto/pgp.c
+++ b/contrib/pgcrypto/pgp.c
@@ -63,6 +63,7 @@ struct cipher_info
const char *int_name;
int key_len;
int block_len;
+ bool fips_allowed;
};
static const struct digest_info digest_list[] = {
@@ -77,16 +78,16 @@ static const struct digest_info digest_list[] = {
};
static const struct cipher_info cipher_list[] = {
- {"3des", PGP_SYM_DES3, "3des-ecb", 192 / 8, 64 / 8},
- {"cast5", PGP_SYM_CAST5, "cast5-ecb", 128 / 8, 64 / 8},
- {"bf", PGP_SYM_BLOWFISH, "bf-ecb", 128 / 8, 64 / 8},
- {"blowfish", PGP_SYM_BLOWFISH, "bf-ecb", 128 / 8, 64 / 8},
- {"aes", PGP_SYM_AES_128, "aes-ecb", 128 / 8, 128 / 8},
- {"aes128", PGP_SYM_AES_128, "aes-ecb", 128 / 8, 128 / 8},
- {"aes192", PGP_SYM_AES_192, "aes-ecb", 192 / 8, 128 / 8},
- {"aes256", PGP_SYM_AES_256, "aes-ecb", 256 / 8, 128 / 8},
- {"twofish", PGP_SYM_TWOFISH, "twofish-ecb", 256 / 8, 128 / 8},
- {NULL, 0, NULL}
+ {"3des", PGP_SYM_DES3, "3des-ecb", 192 / 8, 64 / 8, false},
+ {"cast5", PGP_SYM_CAST5, "cast5-ecb", 128 / 8, 64 / 8, false},
+ {"bf", PGP_SYM_BLOWFISH, "bf-ecb", 128 / 8, 64 / 8, false},
+ {"blowfish", PGP_SYM_BLOWFISH, "bf-ecb", 128 / 8, 64 / 8, false},
+ {"aes", PGP_SYM_AES_128, "aes-ecb", 128 / 8, 128 / 8, true},
+ {"aes128", PGP_SYM_AES_128, "aes-ecb", 128 / 8, 128 / 8, true},
+ {"aes192", PGP_SYM_AES_192, "aes-ecb", 192 / 8, 128 / 8, true},
+ {"aes256", PGP_SYM_AES_256, "aes-ecb", 256 / 8, 128 / 8, true},
+ {"twofish", PGP_SYM_TWOFISH, "twofish-ecb", 256 / 8, 128 / 8, false},
+ {NULL, 0, NULL, 0, 0, false}
};
static const struct cipher_info *
@@ -162,6 +163,17 @@ pgp_load_cipher(int code, PX_Cipher **res)
if (i == NULL)
return PXE_PGP_CORRUPT_DATA;
+ CheckBuiltinCryptoMode();
+
+ /*
+ * In FIPS mode, only allow ciphers that are FIPS approved.
+ */
+ if (builtin_crypto_enabled == BC_FIPS &&
+ CheckFIPSMode() &&
+ !i->fips_allowed)
+ ereport(ERROR,
+ errmsg("cipher %s is not FIPS approved", i->name));
+
err = px_find_cipher(i->int_name, res);
if (err == 0)
return 0;
diff --git a/contrib/pgcrypto/sql/pgp-fips-cipher.sql b/contrib/pgcrypto/sql/pgp-fips-cipher.sql
new file mode 100644
index 000000000000..cb425a9ccdf9
--- /dev/null
+++ b/contrib/pgcrypto/sql/pgp-fips-cipher.sql
@@ -0,0 +1,46 @@
+--
+-- PGP FIPS cipher restrictions
+--
+
+-- crypto functions disabled. All PGP encryption are blocked.
+SET pgcrypto.builtin_crypto_enabled = off;
+SELECT pgp_sym_encrypt('data', 'key');
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=aes256');
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=bf');
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=3des');
+RESET pgcrypto.builtin_crypto_enabled;
+
+-- crypto functions enabled. All work.
+SET pgcrypto.builtin_crypto_enabled = on;
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes128'),
+ 'key', 'expect-cipher-algo=aes128');
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes192'),
+ 'key', 'expect-cipher-algo=aes192');
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes256'),
+ 'key', 'expect-cipher-algo=aes256');
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=bf'),
+ 'key', 'expect-cipher-algo=bf');
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=3des'),
+ 'key', 'expect-cipher-algo=3des');
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=cast5'),
+ 'key', 'expect-cipher-algo=cast5');
+RESET pgcrypto.builtin_crypto_enabled;
+
+-- crypto functions with FIPS mode.
+SELECT fips_mode() AS is_fips \gset
+\if :is_fips
+SET pgcrypto.builtin_crypto_enabled = fips;
+-- non-AES ciphers must error
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=bf');
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=3des');
+SELECT pgp_sym_encrypt('data', 'key', 'cipher-algo=cast5');
+-- AES ciphers work
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes128'),
+ 'key', 'expect-cipher-algo=aes128');
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes256'),
+ 'key', 'expect-cipher-algo=aes256');
+-- AES round trip under FIPS
+SELECT pgp_sym_decrypt(pgp_sym_encrypt('FIPS round trip test', 'key',
+ 'cipher-algo=aes256'), 'key');
+RESET pgcrypto.builtin_crypto_enabled;
+\endif
--
2.53.0
[application/pgp-signature] signature.asc (833B, 3-signature.asc)
download
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected], [email protected], [email protected], [email protected]
Subject: Re: BUG #19457: RE: pgp_sym_encrypt silently accepts non-FIPS ciphers (bf, cast5, 3des) when OpenSSL is in FIPS mod
In-Reply-To: <[email protected]>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox