Skip to content

Commit 188e081

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 eeb0b78 commit 188e081

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
@@ -682,9 +682,19 @@ px_crypt_des(const char *key, const char *setting)
682682
if (*setting == _PASSWORD_EFMT1)
683683
{
684684
/*
685-
* "new"-style: setting - underscore, 4 bytes of count, 4 bytes of
686-
* salt key - unlimited characters
685+
* "new"-style: setting must be a 9-character (underscore, then 4
686+
* bytes of count, then 4 bytes of salt) string. See CRYPT(3) under
687+
* the "Extended crypt" heading for further details.
688+
*
689+
* Unlimited characters of the input key are used. This is known as
690+
* the "Extended crypt" DES method.
691+
*
687692
*/
693+
if (strlen(setting) < 9)
694+
ereport(ERROR,
695+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
696+
errmsg("invalid salt")));
697+
688698
for (i = 1, count = 0L; i < 5; i++)
689699
count |= ascii_to_bin(setting[i]) << (i - 1) * 6;
690700

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

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

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