8000 pgcrypto: Detect and report too-short crypt() salts. · percona/postgres@188e081 · GitHub
[go: up one dir, main page]

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)
0