summaryrefslogtreecommitdiff
path: root/contrib/pgcrypto/pgp-decrypt.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/pgcrypto/pgp-decrypt.c')
-rw-r--r--contrib/pgcrypto/pgp-decrypt.c70
1 files changed, 52 insertions, 18 deletions
diff --git a/contrib/pgcrypto/pgp-decrypt.c b/contrib/pgcrypto/pgp-decrypt.c
index c0c5773e66c..5c69745156c 100644
--- a/contrib/pgcrypto/pgp-decrypt.c
+++ b/contrib/pgcrypto/pgp-decrypt.c
@@ -236,6 +236,8 @@ pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
/*
* Prefix check filter
+ * https://tools.ietf.org/html/rfc4880#section-5.7
+ * https://tools.ietf.org/html/rfc4880#section-5.13
*/
static int
@@ -264,20 +266,7 @@ prefix_init(void **priv_p, void *arg, PullFilter *src)
if (buf[len - 2] != buf[len] || buf[len - 1] != buf[len + 1])
{
px_debug("prefix_init: corrupt prefix");
-
- /*
- * The original purpose of the 2-byte check was to show user a
- * friendly "wrong key" message. This made following possible:
- *
- * "An Attack on CFB Mode Encryption As Used By OpenPGP" by Serge
- * Mister and Robert Zuccherato
- *
- * To avoid being 'oracle', we delay reporting, which basically means
- * we prefer to run into corrupt packet header.
- *
- * We _could_ throw PXE_PGP_CORRUPT_DATA here, but there is
- * possibility of attack via timing, so we don't.
- */
+ /* report error in pgp_decrypt() */
ctx->corrupt_prefix = 1;
}
px_memset(tmpbuf, 0, sizeof(tmpbuf));
@@ -788,12 +777,15 @@ parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
}
px_memset(tmpbuf, 0, 4);
- /* check if text */
+ /*
+ * If called from an SQL function that returns text, pgp_decrypt() rejects
+ * inputs not self-identifying as text.
+ */
if (ctx->text_mode)
if (type != 't' && type != 'u')
{
px_debug("parse_literal_data: data type=%c", type);
- return PXE_PGP_NOT_TEXT;
+ ctx->unexpected_binary = true;
}
ctx->unicode_mode = (type == 'u') ? 1 : 0;
@@ -827,6 +819,7 @@ parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
int res;
uint8 type;
PullFilter *pf_decompr;
+ uint8 *discard_buf;
GETBYTE(pkt, type);
@@ -850,7 +843,20 @@ parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
case PGP_COMPR_BZIP2:
px_debug("parse_compressed_data: bzip2 unsupported");
- res = PXE_PGP_UNSUPPORTED_COMPR;
+ /* report error in pgp_decrypt() */
+ ctx->unsupported_compr = 1;
+
+ /*
+ * Discard the compressed data, allowing it to first affect any
+ * MDC digest computation.
+ */
+ while (1)
+ {
+ res = pullf_read(pkt, 32 * 1024, &discard_buf);
+ if (res <= 0)
+ break;
+ }
+
break;
default:
@@ -1168,8 +1174,36 @@ pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
if (res < 0)
return res;
+ /*
+ * Report a failure of the prefix_init() "quick check" now, rather than
+ * upon detection, to hinder timing attacks. pgcrypto is not generally
+ * secure against timing attacks, but this helps.
+ */
if (!got_data || ctx->corrupt_prefix)
- res = PXE_PGP_CORRUPT_DATA;
+ return PXE_PGP_CORRUPT_DATA;
+
+ /*
+ * Code interpreting purportedly-decrypted data prior to this stage shall
+ * report no error other than PXE_PGP_CORRUPT_DATA. (PXE_BUG is okay so
+ * long as it remains unreachable.) This ensures that an attacker able to
+ * choose a ciphertext and receive a corresponding decryption error
+ * message cannot use that oracle to gather clues about the decryption
+ * key. See "An Attack on CFB Mode Encryption As Used By OpenPGP" by
+ * Serge Mister and Robert Zuccherato.
+ *
+ * A problematic value in the first octet of a Literal Data or Compressed
+ * Data packet may indicate a simple user error, such as the need to call
+ * pgp_sym_decrypt_bytea instead of pgp_sym_decrypt. Occasionally,
+ * though, it is the first symptom of the encryption key not matching the
+ * decryption key. When this was the only problem encountered, report a
+ * specific error to guide the user; otherwise, we will have reported
+ * PXE_PGP_CORRUPT_DATA before now. A key mismatch makes the other errors
+ * into red herrings, and this avoids leaking clues to attackers.
+ */
+ if (ctx->unsupported_compr)
+ return PXE_PGP_UNSUPPORTED_COMPR;
+ if (ctx->unexpected_binary)
+ return PXE_PGP_NOT_TEXT;
return res;
}