mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
Fix errorhandling for PGP encryption
PGP encryption was using px_cipher_encrypt without checking if any error was returned. When OpenSSL is running in FIPS mode, or when the legacy provider hasn't been loaded, not all ciphers which are supported by the PGP code are available and fail the init step in px_cipher_encrypt. Since the PGP encryption failed to notice this it XORed the non-encrypted block with the plaintext, effectively disabling the encryption. This was found due to a report of PGP encryption not respecting the pgcrypto.builtin_crypto_enabled flag and allowing Blowfish and DES. This however turned out to be a false positive, since the PGP code only use ciphers from OpenSSL and not the built in ciphers. Bug: #19457 Reported-by: Shishir Sharma <ansh01072001@gmail.com> Reviewed-by: Jacob Champion <jacob.champion@enterprisedb.com> Discussion: https://postgr.es/m/19457-4bab15c17aea36c7@postgresql.org Security: CVE-2026-14663 Backpatch-through: 14
This commit is contained in:
committed by
Noah Misch
parent
a16c31d39c
commit
d0ecee6de9
@@ -11,7 +11,7 @@ yA6Ce1QTMK3KdL2MPfamsTUSAML8huCJMwYQFfE=
|
||||
=JcP+
|
||||
-----END PGP MESSAGE-----
|
||||
'), 'foobar');
|
||||
ERROR: Wrong key or corrupt data
|
||||
ERROR: encrypt error: Cipher cannot be initialized
|
||||
select pgp_sym_decrypt(dearmor('
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
Comment: dat1.aes.sha1.mdc.s2k3.z0
|
||||
|
||||
192
contrib/pgcrypto/expected/pgp-encrypt_1.out
Normal file
192
contrib/pgcrypto/expected/pgp-encrypt_1.out
Normal file
@@ -0,0 +1,192 @@
|
||||
--
|
||||
-- PGP encrypt
|
||||
--
|
||||
select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'), 'key');
|
||||
pgp_sym_decrypt
|
||||
-----------------
|
||||
Secret.
|
||||
(1 row)
|
||||
|
||||
-- check whether the defaults are ok
|
||||
select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
|
||||
'key', 'expect-cipher-algo=aes128,
|
||||
expect-disable-mdc=0,
|
||||
expect-sess-key=0,
|
||||
expect-s2k-mode=3,
|
||||
expect-s2k-digest-algo=sha1,
|
||||
expect-compress-algo=0
|
||||
');
|
||||
pgp_sym_decrypt
|
||||
-----------------
|
||||
Secret.
|
||||
(1 row)
|
||||
|
||||
-- maybe the expect- stuff simply does not work
|
||||
select pgp_sym_decrypt(pgp_sym_encrypt('Secret.', 'key'),
|
||||
'key', 'expect-cipher-algo=bf,
|
||||
expect-disable-mdc=1,
|
||||
expect-sess-key=1,
|
||||
expect-s2k-mode=0,
|
||||
expect-s2k-digest-algo=md5,
|
||||
expect-compress-algo=1
|
||||
');
|
||||
NOTICE: pgp_decrypt: unexpected cipher_algo: expected 4 got 7
|
||||
NOTICE: pgp_decrypt: unexpected s2k_mode: expected 0 got 3
|
||||
NOTICE: pgp_decrypt: unexpected s2k_digest_algo: expected 1 got 2
|
||||
NOTICE: pgp_decrypt: unexpected use_sess_key: expected 1 got 0
|
||||
NOTICE: pgp_decrypt: unexpected disable_mdc: expected 1 got 0
|
||||
NOTICE: pgp_decrypt: unexpected compress_algo: expected 1 got 0
|
||||
pgp_sym_decrypt
|
||||
-----------------
|
||||
Secret.
|
||||
(1 row)
|
||||
|
||||
-- bytea as text
|
||||
select pgp_sym_decrypt(pgp_sym_encrypt_bytea('Binary', 'baz'), 'baz');
|
||||
ERROR: Not text data
|
||||
-- text as bytea
|
||||
select encode(pgp_sym_decrypt_bytea(pgp_sym_encrypt('Text', 'baz'), 'baz'), 'escape');
|
||||
encode
|
||||
--------
|
||||
Text
|
||||
(1 row)
|
||||
|
||||
-- algorithm change
|
||||
select pgp_sym_decrypt(
|
||||
pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=bf'),
|
||||
'key', 'expect-cipher-algo=bf');
|
||||
ERROR: encrypt error: Cipher cannot be initialized
|
||||
select pgp_sym_decrypt(
|
||||
pgp_sym_encrypt('Secret.', 'key', 'cipher-algo=aes'),
|
||||
'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)
|
||||
|
||||
-- s2k change
|
||||
select pgp_sym_decrypt(
|
||||
pgp_sym_encrypt('Secret.', 'key', 's2k-mode=0'),
|
||||
'key', 'expect-s2k-mode=0');
|
||||
pgp_sym_decrypt
|
||||
-----------------
|
||||
Secret.
|
||||
(1 row)
|
||||
|
||||
select pgp_sym_decrypt(
|
||||
pgp_sym_encrypt('Secret.', 'key', 's2k-mode=1'),
|
||||
'key', 'expect-s2k-mode=1');
|
||||
pgp_sym_decrypt
|
||||
-----------------
|
||||
Secret.
|
||||
(1 row)
|
||||
|
||||
select pgp_sym_decrypt(
|
||||
pgp_sym_encrypt('Secret.', 'key', 's2k-mode=3'),
|
||||
'key', 'expect-s2k-mode=3');
|
||||
pgp_sym_decrypt
|
||||
-----------------
|
||||
Secret.
|
||||
(1 row)
|
||||
|
||||
-- s2k count change
|
||||
select pgp_sym_decrypt(
|
||||
pgp_sym_encrypt('Secret.', 'key', 's2k-count=1024'),
|
||||
'key', 'expect-s2k-count=1024');
|
||||
pgp_sym_decrypt
|
||||
-----------------
|
||||
Secret.
|
||||
(1 row)
|
||||
|
||||
-- s2k_count rounds up
|
||||
select pgp_sym_decrypt(
|
||||
pgp_sym_encrypt('Secret.', 'key', 's2k-count=65000000'),
|
||||
'key', 'expect-s2k-count=65000000');
|
||||
NOTICE: pgp_decrypt: unexpected s2k_count: expected 65000000 got 65011712
|
||||
pgp_sym_decrypt
|
||||
-----------------
|
||||
Secret.
|
||||
(1 row)
|
||||
|
||||
-- s2k digest change
|
||||
select pgp_sym_decrypt(
|
||||
pgp_sym_encrypt('Secret.', 'key', 's2k-digest-algo=sha1'),
|
||||
'key', 'expect-s2k-digest-algo=sha1');
|
||||
pgp_sym_decrypt
|
||||
-----------------
|
||||
Secret.
|
||||
(1 row)
|
||||
|
||||
-- sess key
|
||||
select pgp_sym_decrypt(
|
||||
pgp_sym_encrypt('Secret.', 'key', 'sess-key=0'),
|
||||
'key', 'expect-sess-key=0');
|
||||
pgp_sym_decrypt
|
||||
-----------------
|
||||
Secret.
|
||||
(1 row)
|
||||
|
||||
select pgp_sym_decrypt(
|
||||
pgp_sym_encrypt('Secret.', 'key', 'sess-key=1'),
|
||||
'key', 'expect-sess-key=1');
|
||||
pgp_sym_decrypt
|
||||
-----------------
|
||||
Secret.
|
||||
(1 row)
|
||||
|
||||
select pgp_sym_decrypt(
|
||||
pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=bf'),
|
||||
'key', 'expect-sess-key=1, expect-cipher-algo=bf');
|
||||
ERROR: encrypt error: Cipher cannot be initialized
|
||||
select pgp_sym_decrypt(
|
||||
pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=aes192'),
|
||||
'key', 'expect-sess-key=1, expect-cipher-algo=aes192');
|
||||
pgp_sym_decrypt
|
||||
-----------------
|
||||
Secret.
|
||||
(1 row)
|
||||
|
||||
select pgp_sym_decrypt(
|
||||
pgp_sym_encrypt('Secret.', 'key', 'sess-key=1, cipher-algo=aes256'),
|
||||
'key', 'expect-sess-key=1, expect-cipher-algo=aes256');
|
||||
pgp_sym_decrypt
|
||||
-----------------
|
||||
Secret.
|
||||
(1 row)
|
||||
|
||||
-- no mdc
|
||||
select pgp_sym_decrypt(
|
||||
pgp_sym_encrypt('Secret.', 'key', 'disable-mdc=1'),
|
||||
'key', 'expect-disable-mdc=1');
|
||||
pgp_sym_decrypt
|
||||
-----------------
|
||||
Secret.
|
||||
(1 row)
|
||||
|
||||
-- crlf
|
||||
select pgp_sym_decrypt_bytea(
|
||||
pgp_sym_encrypt(E'1\n2\n3\r\n', 'key', 'convert-crlf=1'),
|
||||
'key');
|
||||
pgp_sym_decrypt_bytea
|
||||
------------------------
|
||||
\x310d0a320d0a330d0d0a
|
||||
(1 row)
|
||||
|
||||
-- conversion should be lossless
|
||||
select digest(pgp_sym_decrypt(
|
||||
pgp_sym_encrypt(E'\r\n0\n1\r\r\n\n2\r', 'key', 'convert-crlf=1'),
|
||||
'key', 'convert-crlf=1'), 'sha1') as result,
|
||||
digest(E'\r\n0\n1\r\r\n\n2\r', 'sha1') as expect;
|
||||
result | expect
|
||||
--------------------------------------------+--------------------------------------------
|
||||
\x47bde5d88d6ef8770572b9cbb4278b402aa69966 | \x47bde5d88d6ef8770572b9cbb4278b402aa69966
|
||||
(1 row)
|
||||
|
||||
@@ -595,7 +595,7 @@ from keytbl, encdata where keytbl.id=1 and encdata.id=1;
|
||||
|
||||
select pgp_pub_decrypt(dearmor(data), dearmor(seckey))
|
||||
from keytbl, encdata where keytbl.id=2 and encdata.id=2;
|
||||
ERROR: Wrong key or corrupt data
|
||||
ERROR: encrypt error: Cipher cannot be initialized
|
||||
select pgp_pub_decrypt(dearmor(data), dearmor(seckey))
|
||||
from keytbl, encdata where keytbl.id=3 and encdata.id=3;
|
||||
pgp_pub_decrypt
|
||||
|
||||
@@ -221,8 +221,14 @@ cfb_process(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst,
|
||||
while (len > 0)
|
||||
{
|
||||
unsigned rlen;
|
||||
int err;
|
||||
|
||||
err = px_cipher_encrypt(ctx->ciph, 0, ctx->fr, ctx->block_size, ctx->fre, &rlen);
|
||||
if (err)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
|
||||
errmsg("encrypt error: %s", px_strerror(err))));
|
||||
|
||||
px_cipher_encrypt(ctx->ciph, 0, ctx->fr, ctx->block_size, ctx->fre, &rlen);
|
||||
if (ctx->block_no < 5)
|
||||
ctx->block_no++;
|
||||
|
||||
|
||||
@@ -1243,6 +1243,11 @@ fips_mode() returns boolean
|
||||
<literal>fips</literal> disables these functions if
|
||||
<productname>OpenSSL</productname> is detected to operate in FIPS mode.
|
||||
</para>
|
||||
<para>
|
||||
<function>pgp_sym_encrypt()</function> and
|
||||
<function>pgp_pub_encrypt()</function> do not use built in crypto so
|
||||
they are not affected.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
Reference in New Issue
Block a user