Skip to content

Commit 4d95419

Browse files
committed
pgcrypto: Detect and report too-short crypt() salts.
Certain short salts crashed the backend or disclosed a few bytes of backend memory. For existing salt-induced error conditions, emit a message saying as much. Back-patch to 9.0 (all supported versions). Josh Kupershmidt Security: CVE-2015-5288
1 parent 13ac4c0 commit 4d95419

File tree

9 files changed

+103
-6
lines changed

9 files changed

+103
-6
lines changed

contrib/pgcrypto/crypt-blowfish.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,17 @@ _crypt_blowfish_rn(const char *key, const char *setting,
602602
if (size < 7 + 22 + 31 + 1)
603603
return NULL;
604604

605+
/*
606+
* Blowfish salt value must be formatted as follows: "$2a$" or "$2x$", a
607+
* two digit cost parameter, "$", and 22 digits from the alphabet
608+
* "./0-9A-Za-z". -- from the PHP crypt docs. Apparently we enforce a few
609+
* more restrictions on the count in the salt as well.
610+
*/
611+
if (strlen(setting) < 29)
612+
ereport(ERROR,
613+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
614+
errmsg("invalid salt")));
615+
605616
if (setting[0] != '$' ||
606617
setting[1] != '2' ||
607618
(setting[2] != 'a' && setting[2] != 'x') ||
@@ -611,14 +622,18 @@ _crypt_blowfish_rn(const char *key, const char *setting,
611622
(setting[4] == '3' && setting[5] > '1') ||
612623
setting[6] != '$')
613624
{
614-
return NULL;
625+
ereport(ERROR,
626+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
627+
errmsg("invalid salt")));
615628
}
616629

617630
count = (BF_word) 1 << ((setting[4] - '0') * 10 + (setting[5] - '0'));
618631
if (count < 16 || BF_decode(data.binary.salt, &setting[7], 16))
619632
{
620633
px_memset(data.binary.salt, 0, sizeof(data.binary.salt));
621-
return NULL;
634+
ereport(ERROR,
635+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
636+
errmsg("invalid salt")));
622637
}
623638
BF_swap(data.binary.salt, 4);
624639

contrib/pgcrypto/crypt-des.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -681,9 +681,19 @@ px_crypt_des(const char *key, const char *setting)
681681
if (*setting == _PASSWORD_EFMT1)
682682
{
683683
/*
684-
* "new"-style: setting - underscore, 4 bytes of count, 4 bytes of
685-
* salt key - unlimited characters
684+
* "new"-style: setting must be a 9-character (underscore, then 4
685+
* bytes of count, then 4 bytes of salt) string. See CRYPT(3) under
686+
* the "Extended crypt" heading for further details.
687+
*
688+
* Unlimited characters of the input key are used. This is known as
689+
* the "Extended crypt" DES method.
690+
*
686691
*/
692+
if (strlen(setting) < 9)
693+
ereport(ERROR,
694+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
695+
errmsg("invalid salt")));
696+
687697
for (i = 1, count = 0L; i < 5; i++)
688698
count |= ascii_to_bin(setting[i]) << (i - 1) * 6;
689699

@@ -723,10 +733,16 @@ px_crypt_des(const char *key, const char *setting)
723733
#endif /* !DISABLE_XDES */
724734
{
725735
/*
726-
* "old"-style: setting - 2 bytes of salt key - up to 8 characters
736+
* "old"-style: setting - 2 bytes of salt key - only up to the first 8
737+
* characters of the input key are used.
727738
*/
728739
count = 25;
729740

741+
if (strlen(setting) < 2)
742+
ereport(ERROR,
743+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
744+
errmsg("invalid salt")));
745+
730746
salt = (ascii_to_bin(setting[1]) << 6)
731747
| ascii_to_bin(setting[0]);
732748

contrib/pgcrypto/expected/crypt-blowfish.out

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ SELECT crypt('foox', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O');
1313
$2a$06$RQiOJ.3ELirrXwxIZY8q0OR3CVJrAfda1z26CCHPnB6mmVZD8p0/C
1414
(1 row)
1515

16+
-- error, salt too short:
17+
SELECT crypt('foox', '$2a$');
18+
ERROR: invalid salt
19+
-- error, first digit of count in salt invalid
20+
SELECT crypt('foox', '$2a$40$RQiOJ.3ELirrXwxIZY8q0O');
21+
ERROR: invalid salt
22+
-- error, count in salt too small
23+
SELECT crypt('foox', '$2a$00$RQiOJ.3ELirrXwxIZY8q0O');
24+
ERROR: invalid salt
1625
CREATE TABLE ctest (data text, res text, salt text);
1726
INSERT INTO ctest VALUES ('password', '', '');
1827
UPDATE ctest SET salt = gen_salt('bf', 8);

contrib/pgcrypto/expected/crypt-des.out

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ SELECT crypt('foox', 'NB');
1313
NB53EGGqrrb5E
1414
(1 row)
1515

16+
-- We are supposed to pass in a 2-character salt.
17+
-- error since salt is too short:
18+
SELECT crypt('password', 'a');
19+
ERROR: invalid salt
1620
CREATE TABLE ctest (data text, res text, salt text);
1721
INSERT INTO ctest VALUES ('password', '', '');
1822
UPDATE ctest SET salt = gen_salt('des');

contrib/pgcrypto/expected/crypt-xdes.out

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,30 @@ SELECT crypt('foox', '_J9..j2zz');
1313
_J9..j2zzAYKMvO2BYRY
1414
(1 row)
1515

16+
-- check XDES handling of keys longer than 8 chars
17+
SELECT crypt('longlongpassword', '_J9..j2zz');
18+
crypt
19+
----------------------
20+
_J9..j2zz4BeseiQNwUg
21+
(1 row)
22+
23+
-- error, salt too short
24+
SELECT crypt('foox', '_J9..BWH');
25+
ERROR: invalid salt
26+
-- error, count specified in the second argument is 0
27+
SELECT crypt('password', '_........');
28+
ERROR: crypt(3) returned NULL
29+
-- error, count will wind up still being 0 due to invalid encoding
30+
-- of the count: only chars ``./0-9A-Za-z' are valid
31+
SELECT crypt('password', '_..!!!!!!');
32+
ERROR: crypt(3) returned NULL
33+
-- count should be non-zero here, will work
34+
SELECT crypt('password', '_/!!!!!!!');
35+
crypt
36+
----------------------
37+
_/!!!!!!!zqM49hRzxko
38+
(1 row)
39+
1640
CREATE TABLE ctest (data text, res text, salt text);
1741
INSERT INTO ctest VALUES ('password', '', '');
1842
UPDATE ctest SET salt = gen_salt('xdes', 1001);

contrib/pgcrypto/px-crypt.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ run_crypt_des(const char *psw, const char *salt,
4242
char *res;
4343

4444
res = px_crypt_des(psw, salt);
45-
if (strlen(res) > len - 1)
45+
if (res == NULL || strlen(res) > len - 1)
4646
return NULL;
4747
strcpy(buf, res);
4848
return buf;

contrib/pgcrypto/sql/crypt-blowfish.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ SELECT crypt('', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O');
66

77
SELECT crypt('foox', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O');
88

9+
-- error, salt too short:
10+
SELECT crypt('foox', '$2a$');
11+
12+
-- error, first digit of count in salt invalid
13+
SELECT crypt('foox', '$2a$40$RQiOJ.3ELirrXwxIZY8q0O');
14+
15+
-- error, count in salt too small
16+
SELECT crypt('foox', '$2a$00$RQiOJ.3ELirrXwxIZY8q0O');
17+
918
CREATE TABLE ctest (data text, res text, salt text);
1019
INSERT INTO ctest VALUES ('password', '', '');
1120

contrib/pgcrypto/sql/crypt-des.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ SELECT crypt('', 'NB');
66

77
SELECT crypt('foox', 'NB');
88

9+
-- We are supposed to pass in a 2-character salt.
10+
-- error since salt is too short:
11+
SELECT crypt('password', 'a');
12+
913
CREATE TABLE ctest (data text, res text, salt text);
1014
INSERT INTO ctest VALUES ('password', '', '');
1115

contrib/pgcrypto/sql/crypt-xdes.sql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,22 @@ SELECT crypt('', '_J9..j2zz');
66

77
SELECT crypt('foox', '_J9..j2zz');
88

9+
-- check XDES handling of keys longer than 8 chars
10+
SELECT crypt('longlongpassword', '_J9..j2zz');
11+
12+
-- error, salt too short
13+
SELECT crypt('foox', '_J9..BWH');
14+
15+
-- error, count specified in the second argument is 0
16+
SELECT crypt('password', '_........');
17+
18+
-- error, count will wind up still being 0 due to invalid encoding
19+
-- of the count: only chars ``./0-9A-Za-z' are valid
20+
SELECT crypt('password', '_..!!!!!!');
21+
22+
-- count should be non-zero here, will work
23+
SELECT crypt('password', '_/!!!!!!!');
24+
925
CREATE TABLE ctest (data text, res text, salt text);
1026
INSERT INTO ctest VALUES ('password', '', '');
1127

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy