Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfba1fb4

Browse files
committed
pgcrypto: Report errant decryption as "Wrong key or corrupt data".
This has been the predominant outcome. When the output of decryptingwith a wrong key coincidentally resembled an OpenPGP packet header,pgcrypto could instead report "Corrupt data", "Not text data" or"Unsupported compression algorithm". The distinct "Corrupt data"message added no value. The latter two error messages misled when thedecrypted payload also exhibited fundamental integrity problems. Worse,error message variance in other systems has enabled cryptologic attacks;see RFC 4880 section "14. Security Considerations". Whether thesepgcrypto behaviors are likewise exploitable is unknown.In passing, document that pgcrypto does not resist side-channel attacks.Back-patch to 9.0 (all supported versions).Security:CVE-2015-3167
1 parentca32594 commitfba1fb4

File tree

9 files changed

+162
-27
lines changed

9 files changed

+162
-27
lines changed

‎contrib/pgcrypto/expected/pgp-decrypt.out

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,3 +372,54 @@ select pgp_sym_decrypt(pgp_sym_encrypt(repeat('x',65530),'1'),'1') = repeat('x',
372372
(1 row)
373373

374374
-- expected: true
375+
-- Negative tests
376+
-- Decryption with a certain incorrect key yields an apparent Literal Data
377+
-- packet reporting its content to be binary data. Ciphertext source:
378+
-- iterative pgp_sym_encrypt('secret', 'key') until the random prefix gave
379+
-- rise to that property.
380+
select pgp_sym_decrypt(dearmor('
381+
-----BEGIN PGP MESSAGE-----
382+
383+
ww0EBwMCxf8PTrQBmJdl0jcB6y2joE7GSLKRv7trbNsF5Z8ou5NISLUg31llVH/S0B2wl4bvzZjV
384+
VsxxqLSPzNLAeIspJk5G
385+
=mSd/
386+
-----END PGP MESSAGE-----
387+
'), 'wrong-key', 'debug=1');
388+
NOTICE: dbg: prefix_init: corrupt prefix
389+
NOTICE: dbg: parse_literal_data: data type=b
390+
NOTICE: dbg: mdcbuf_finish: bad MDC pkt hdr
391+
ERROR: Wrong key or corrupt data
392+
-- Routine text/binary mismatch.
393+
select pgp_sym_decrypt(pgp_sym_encrypt_bytea('P', 'key'), 'key', 'debug=1');
394+
NOTICE: dbg: parse_literal_data: data type=b
395+
ERROR: Not text data
396+
-- Decryption with a certain incorrect key yields an apparent BZip2-compressed
397+
-- plaintext. Ciphertext source: iterative pgp_sym_encrypt('secret', 'key')
398+
-- until the random prefix gave rise to that property.
399+
select pgp_sym_decrypt(dearmor('
400+
-----BEGIN PGP MESSAGE-----
401+
402+
ww0EBwMC9rK/dMkF5Zlt0jcBlzAQ1mQY2qYbKYbw8h3EZ5Jk0K2IiY92R82TRhWzBIF/8cmXDPtP
403+
GXsd65oYJZp3Khz0qfyn
404+
=Nmpq
405+
-----END PGP MESSAGE-----
406+
'), 'wrong-key', 'debug=1');
407+
NOTICE: dbg: prefix_init: corrupt prefix
408+
NOTICE: dbg: parse_compressed_data: bzip2 unsupported
409+
NOTICE: dbg: mdcbuf_finish: bad MDC pkt hdr
410+
ERROR: Wrong key or corrupt data
411+
-- Routine use of BZip2 compression. Ciphertext source:
412+
-- echo x | gpg --homedir /nonexistent --personal-compress-preferences bzip2 \
413+
-- --personal-cipher-preferences aes --no-emit-version --batch \
414+
-- --symmetric --passphrase key --armor
415+
select pgp_sym_decrypt(dearmor('
416+
-----BEGIN PGP MESSAGE-----
417+
418+
jA0EBwMCRhFrAKNcLVJg0mMBLJG1cCASNk/x/3dt1zJ+2eo7jHfjgg3N6wpB3XIe
419+
QCwkWJwlBG5pzbO5gu7xuPQN+TbPJ7aQ2sLx3bAHhtYb0i3vV9RO10Gw++yUyd4R
420+
UCAAw2JRIISttRHMfDpDuZJpvYo=
421+
=AZ9M
422+
-----END PGP MESSAGE-----
423+
'), 'key', 'debug=1');
424+
NOTICE: dbg: parse_compressed_data: bzip2 unsupported
425+
ERROR: Unsupported compression algorithm

‎contrib/pgcrypto/expected/pgp-pubkey-decrypt.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ ERROR: No encryption key found
625625
-- rsa: password-protected secret key, wrong password
626626
select pgp_pub_decrypt(dearmor(data), dearmor(seckey), '123')
627627
from keytbl, encdata where keytbl.id=7 and encdata.id=4;
628-
ERROR:Corrupt data
628+
ERROR:Wrong key or corrupt data
629629
-- rsa: password-protected secret key, right password
630630
select pgp_pub_decrypt(dearmor(data), dearmor(seckey), 'parool')
631631
from keytbl, encdata where keytbl.id=7 and encdata.id=4;
@@ -641,7 +641,7 @@ ERROR: Need password for secret key
641641
-- password-protected secret key, wrong password
642642
select pgp_pub_decrypt(dearmor(data), dearmor(seckey), 'foo')
643643
from keytbl, encdata where keytbl.id=5 and encdata.id=1;
644-
ERROR:Corrupt data
644+
ERROR:Wrong key or corrupt data
645645
-- password-protected secret key, right password
646646
select pgp_pub_decrypt(dearmor(data), dearmor(seckey), 'parool')
647647
from keytbl, encdata where keytbl.id=5 and encdata.id=1;

‎contrib/pgcrypto/mbuf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
325325
if (res!=len)
326326
{
327327
px_debug("pullf_read_fixed: need=%d got=%d",len,res);
328-
returnPXE_MBUF_SHORT_READ;
328+
returnPXE_PGP_CORRUPT_DATA;
329329
}
330330
if (p!=dst)
331331
memcpy(dst,p,len);

‎contrib/pgcrypto/pgp-decrypt.c

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
236236

237237
/*
238238
* Prefix check filter
239+
* https://tools.ietf.org/html/rfc4880#section-5.7
240+
* https://tools.ietf.org/html/rfc4880#section-5.13
239241
*/
240242

241243
staticint
@@ -264,20 +266,7 @@ prefix_init(void **priv_p, void *arg, PullFilter *src)
264266
if (buf[len-2]!=buf[len]||buf[len-1]!=buf[len+1])
265267
{
266268
px_debug("prefix_init: corrupt prefix");
267-
268-
/*
269-
* The original purpose of the 2-byte check was to show user a
270-
* friendly "wrong key" message. This made following possible:
271-
*
272-
* "An Attack on CFB Mode Encryption As Used By OpenPGP" by Serge
273-
* Mister and Robert Zuccherato
274-
*
275-
* To avoid being 'oracle', we delay reporting, which basically means
276-
* we prefer to run into corrupt packet header.
277-
*
278-
* We _could_ throw PXE_PGP_CORRUPT_DATA here, but there is
279-
* possibility of attack via timing, so we don't.
280-
*/
269+
/* report error in pgp_decrypt() */
281270
ctx->corrupt_prefix=1;
282271
}
283272
px_memset(tmpbuf,0,sizeof(tmpbuf));
@@ -788,12 +777,15 @@ parse_literal_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
788777
}
789778
px_memset(tmpbuf,0,4);
790779

791-
/* check if text */
780+
/*
781+
* If called from an SQL function that returns text, pgp_decrypt() rejects
782+
* inputs not self-identifying as text.
783+
*/
792784
if (ctx->text_mode)
793785
if (type!='t'&&type!='u')
794786
{
795787
px_debug("parse_literal_data: data type=%c",type);
796-
returnPXE_PGP_NOT_TEXT;
788+
ctx->unexpected_binary= true;
797789
}
798790

799791
ctx->unicode_mode= (type=='u') ?1 :0;
@@ -827,6 +819,7 @@ parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
827819
intres;
828820
uint8type;
829821
PullFilter*pf_decompr;
822+
uint8*discard_buf;
830823

831824
GETBYTE(pkt,type);
832825

@@ -850,7 +843,20 @@ parse_compressed_data(PGP_Context *ctx, MBuf *dst, PullFilter *pkt)
850843

851844
casePGP_COMPR_BZIP2:
852845
px_debug("parse_compressed_data: bzip2 unsupported");
853-
res=PXE_PGP_UNSUPPORTED_COMPR;
846+
/* report error in pgp_decrypt() */
847+
ctx->unsupported_compr=1;
848+
849+
/*
850+
* Discard the compressed data, allowing it to first affect any
851+
* MDC digest computation.
852+
*/
853+
while (1)
854+
{
855+
res=pullf_read(pkt,32*1024,&discard_buf);
856+
if (res <=0)
857+
break;
858+
}
859+
854860
break;
855861

856862
default:
@@ -1171,8 +1177,36 @@ pgp_decrypt(PGP_Context *ctx, MBuf *msrc, MBuf *mdst)
11711177
if (res<0)
11721178
returnres;
11731179

1180+
/*
1181+
* Report a failure of the prefix_init() "quick check" now, rather than
1182+
* upon detection, to hinder timing attacks. pgcrypto is not generally
1183+
* secure against timing attacks, but this helps.
1184+
*/
11741185
if (!got_data||ctx->corrupt_prefix)
1175-
res=PXE_PGP_CORRUPT_DATA;
1186+
returnPXE_PGP_CORRUPT_DATA;
1187+
1188+
/*
1189+
* Code interpreting purportedly-decrypted data prior to this stage shall
1190+
* report no error other than PXE_PGP_CORRUPT_DATA. (PXE_BUG is okay so
1191+
* long as it remains unreachable.) This ensures that an attacker able to
1192+
* choose a ciphertext and receive a corresponding decryption error
1193+
* message cannot use that oracle to gather clues about the decryption
1194+
* key. See "An Attack on CFB Mode Encryption As Used By OpenPGP" by
1195+
* Serge Mister and Robert Zuccherato.
1196+
*
1197+
* A problematic value in the first octet of a Literal Data or Compressed
1198+
* Data packet may indicate a simple user error, such as the need to call
1199+
* pgp_sym_decrypt_bytea instead of pgp_sym_decrypt. Occasionally,
1200+
* though, it is the first symptom of the encryption key not matching the
1201+
* decryption key. When this was the only problem encountered, report a
1202+
* specific error to guide the user; otherwise, we will have reported
1203+
* PXE_PGP_CORRUPT_DATA before now. A key mismatch makes the other errors
1204+
* into red herrings, and this avoids leaking clues to attackers.
1205+
*/
1206+
if (ctx->unsupported_compr)
1207+
returnPXE_PGP_UNSUPPORTED_COMPR;
1208+
if (ctx->unexpected_binary)
1209+
returnPXE_PGP_NOT_TEXT;
11761210

11771211
returnres;
11781212
}

‎contrib/pgcrypto/pgp.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,9 @@ struct PGP_Context
151151
* internal variables
152152
*/
153153
intmdc_checked;
154-
intcorrupt_prefix;
154+
intcorrupt_prefix;/* prefix failed RFC 4880 "quick check" */
155+
intunsupported_compr;/* has bzip2 compression */
156+
intunexpected_binary;/* binary data seen in text_mode */
155157
intin_mdc_pkt;
156158
intuse_mdcbuf_filter;
157159
PX_MD*mdc_ctx;

‎contrib/pgcrypto/px.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,6 @@ static const struct error_desc px_err_list[] = {
8787
{PXE_PGP_UNSUPPORTED_PUBALGO,"Unsupported public key algorithm"},
8888
{PXE_PGP_MULTIPLE_SUBKEYS,"Several subkeys not supported"},
8989

90-
/* fake this as PXE_PGP_CORRUPT_DATA */
91-
{PXE_MBUF_SHORT_READ,"Corrupt data"},
92-
9390
{0,NULL},
9491
};
9592

‎contrib/pgcrypto/px.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,6 @@ voidpx_free(void *p);
8080
#definePXE_NO_RANDOM-17
8181
#definePXE_DECRYPT_FAILED-18
8282

83-
#definePXE_MBUF_SHORT_READ-50
84-
8583
#definePXE_PGP_CORRUPT_DATA-100
8684
#definePXE_PGP_CORRUPT_ARMOR-101
8785
#definePXE_PGP_UNSUPPORTED_COMPR-102

‎contrib/pgcrypto/sql/pgp-decrypt.sql

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,3 +268,48 @@ a3nsOzKTXUfS9VyaXo8IrncM6n7fdaXpwba/3tNsAhJG4lDv1k4g9v8Ix2dfv6Rs
268268
-- check BUG #11905, problem with messages 6 less than a power of 2.
269269
select pgp_sym_decrypt(pgp_sym_encrypt(repeat('x',65530),'1'),'1')= repeat('x',65530);
270270
-- expected: true
271+
272+
273+
-- Negative tests
274+
275+
-- Decryption with a certain incorrect key yields an apparent Literal Data
276+
-- packet reporting its content to be binary data. Ciphertext source:
277+
-- iterative pgp_sym_encrypt('secret', 'key') until the random prefix gave
278+
-- rise to that property.
279+
select pgp_sym_decrypt(dearmor('
280+
-----BEGIN PGP MESSAGE-----
281+
282+
ww0EBwMCxf8PTrQBmJdl0jcB6y2joE7GSLKRv7trbNsF5Z8ou5NISLUg31llVH/S0B2wl4bvzZjV
283+
VsxxqLSPzNLAeIspJk5G
284+
=mSd/
285+
-----END PGP MESSAGE-----
286+
'),'wrong-key','debug=1');
287+
288+
-- Routine text/binary mismatch.
289+
select pgp_sym_decrypt(pgp_sym_encrypt_bytea('P','key'),'key','debug=1');
290+
291+
-- Decryption with a certain incorrect key yields an apparent BZip2-compressed
292+
-- plaintext. Ciphertext source: iterative pgp_sym_encrypt('secret', 'key')
293+
-- until the random prefix gave rise to that property.
294+
select pgp_sym_decrypt(dearmor('
295+
-----BEGIN PGP MESSAGE-----
296+
297+
ww0EBwMC9rK/dMkF5Zlt0jcBlzAQ1mQY2qYbKYbw8h3EZ5Jk0K2IiY92R82TRhWzBIF/8cmXDPtP
298+
GXsd65oYJZp3Khz0qfyn
299+
=Nmpq
300+
-----END PGP MESSAGE-----
301+
'),'wrong-key','debug=1');
302+
303+
-- Routine use of BZip2 compression. Ciphertext source:
304+
-- echo x | gpg --homedir /nonexistent --personal-compress-preferences bzip2 \
305+
-- --personal-cipher-preferences aes --no-emit-version --batch \
306+
-- --symmetric --passphrase key --armor
307+
select pgp_sym_decrypt(dearmor('
308+
-----BEGIN PGP MESSAGE-----
309+
310+
jA0EBwMCRhFrAKNcLVJg0mMBLJG1cCASNk/x/3dt1zJ+2eo7jHfjgg3N6wpB3XIe
311+
QCwkWJwlBG5pzbO5gu7xuPQN+TbPJ7aQ2sLx3bAHhtYb0i3vV9RO10Gw++yUyd4R
312+
UCAAw2JRIISttRHMfDpDuZJpvYo=
313+
=AZ9M
314+
-----END PGP MESSAGE-----
315+
'),'key','debug=1');

‎doc/src/sgml/pgcrypto.sgml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,14 @@ gen_random_uuid() returns uuid
12441244
<para>
12451245
If you cannot, then better do crypto inside client application.
12461246
</para>
1247+
1248+
<para>
1249+
The implementation does not resist
1250+
<ulink url="http://en.wikipedia.org/wiki/Side-channel_attack">side-channel
1251+
attacks</ulink>. For example, the time required for
1252+
a <filename>pgcrypto</> decryption function to complete varies among
1253+
ciphertexts of a given size.
1254+
</para>
12471255
</sect3>
12481256

12491257
<sect3>

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp