diff --git a/contrib/pgcrypto/crypt-blowfish.c b/contrib/pgcrypto/crypt-blowfish.c index fbaa3d776a08fb439158ddb41cde4c67f73079b8..4054e6a06fc758e2bd388080ee0b6aeb523de42e 100644 --- a/contrib/pgcrypto/crypt-blowfish.c +++ b/contrib/pgcrypto/crypt-blowfish.c @@ -602,6 +602,17 @@ _crypt_blowfish_rn(const char *key, const char *setting, if (size < 7 + 22 + 31 + 1) return NULL; + /* + * Blowfish salt value must be formatted as follows: "$2a$" or "$2x$", a + * two digit cost parameter, "$", and 22 digits from the alphabet + * "./0-9A-Za-z". -- from the PHP crypt docs. Apparently we enforce a few + * more restrictions on the count in the salt as well. + */ + if (strlen(setting) < 29) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid salt"))); + if (setting[0] != '$' || setting[1] != '2' || (setting[2] != 'a' && setting[2] != 'x') || @@ -611,14 +622,18 @@ _crypt_blowfish_rn(const char *key, const char *setting, (setting[4] == '3' && setting[5] > '1') || setting[6] != '$') { - return NULL; + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid salt"))); } count = (BF_word) 1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); if (count < 16 || BF_decode(data.binary.salt, &setting[7], 16)) { px_memset(data.binary.salt, 0, sizeof(data.binary.salt)); - return NULL; + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid salt"))); } BF_swap(data.binary.salt, 4); diff --git a/contrib/pgcrypto/crypt-des.c b/contrib/pgcrypto/crypt-des.c index 4ed44beeff51707a2ca1b86842bbca7da4e5b647..2108be8c379b3de74042ff0dc4f71b56557fc782 100644 --- a/contrib/pgcrypto/crypt-des.c +++ b/contrib/pgcrypto/crypt-des.c @@ -681,9 +681,19 @@ px_crypt_des(const char *key, const char *setting) if (*setting == _PASSWORD_EFMT1) { /* - * "new"-style: setting - underscore, 4 bytes of count, 4 bytes of - * salt key - unlimited characters + * "new"-style: setting must be a 9-character (underscore, then 4 + * bytes of count, then 4 bytes of salt) string. See CRYPT(3) under + * the "Extended crypt" heading for further details. + * + * Unlimited characters of the input key are used. This is known as + * the "Extended crypt" DES method. + * */ + if (strlen(setting) < 9) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid salt"))); + for (i = 1, count = 0L; i < 5; i++) count |= ascii_to_bin(setting[i]) << (i - 1) * 6; @@ -723,10 +733,16 @@ px_crypt_des(const char *key, const char *setting) #endif /* !DISABLE_XDES */ { /* - * "old"-style: setting - 2 bytes of salt key - up to 8 characters + * "old"-style: setting - 2 bytes of salt key - only up to the first 8 + * characters of the input key are used. */ count = 25; + if (strlen(setting) < 2) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid salt"))); + salt = (ascii_to_bin(setting[1]) << 6) | ascii_to_bin(setting[0]); diff --git a/contrib/pgcrypto/expected/crypt-blowfish.out b/contrib/pgcrypto/expected/crypt-blowfish.out index 329d78f6254621d3e1dedfe86afb8c0b18a03f3d..d79b0c047b4c77a0312acbb517c869959a6e67a7 100644 --- a/contrib/pgcrypto/expected/crypt-blowfish.out +++ b/contrib/pgcrypto/expected/crypt-blowfish.out @@ -13,6 +13,15 @@ SELECT crypt('foox', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O'); $2a$06$RQiOJ.3ELirrXwxIZY8q0OR3CVJrAfda1z26CCHPnB6mmVZD8p0/C (1 row) +-- error, salt too short: +SELECT crypt('foox', '$2a$'); +ERROR: invalid salt +-- error, first digit of count in salt invalid +SELECT crypt('foox', '$2a$40$RQiOJ.3ELirrXwxIZY8q0O'); +ERROR: invalid salt +-- error, count in salt too small +SELECT crypt('foox', '$2a$00$RQiOJ.3ELirrXwxIZY8q0O'); +ERROR: invalid salt CREATE TABLE ctest (data text, res text, salt text); INSERT INTO ctest VALUES ('password', '', ''); UPDATE ctest SET salt = gen_salt('bf', 8); diff --git a/contrib/pgcrypto/expected/crypt-des.out b/contrib/pgcrypto/expected/crypt-des.out index b8b605037d48b1b35fcda93fe66a735aa06122bc..a462dcd580a896295e8f298b752333236154db17 100644 --- a/contrib/pgcrypto/expected/crypt-des.out +++ b/contrib/pgcrypto/expected/crypt-des.out @@ -13,6 +13,10 @@ SELECT crypt('foox', 'NB'); NB53EGGqrrb5E (1 row) +-- We are supposed to pass in a 2-character salt. +-- error since salt is too short: +SELECT crypt('password', 'a'); +ERROR: invalid salt CREATE TABLE ctest (data text, res text, salt text); INSERT INTO ctest VALUES ('password', '', ''); UPDATE ctest SET salt = gen_salt('des'); diff --git a/contrib/pgcrypto/expected/crypt-xdes.out b/contrib/pgcrypto/expected/crypt-xdes.out index cdcdefb1996997f4a7f9b54f3efef46acd20b219..8cf907512f6f7fbbc219788b5fbb862774ac5707 100644 --- a/contrib/pgcrypto/expected/crypt-xdes.out +++ b/contrib/pgcrypto/expected/crypt-xdes.out @@ -13,6 +13,30 @@ SELECT crypt('foox', '_J9..j2zz'); _J9..j2zzAYKMvO2BYRY (1 row) +-- check XDES handling of keys longer than 8 chars +SELECT crypt('longlongpassword', '_J9..j2zz'); + crypt +---------------------- + _J9..j2zz4BeseiQNwUg +(1 row) + +-- error, salt too short +SELECT crypt('foox', '_J9..BWH'); +ERROR: invalid salt +-- error, count specified in the second argument is 0 +SELECT crypt('password', '_........'); +ERROR: crypt(3) returned NULL +-- error, count will wind up still being 0 due to invalid encoding +-- of the count: only chars ``./0-9A-Za-z' are valid +SELECT crypt('password', '_..!!!!!!'); +ERROR: crypt(3) returned NULL +-- count should be non-zero here, will work +SELECT crypt('password', '_/!!!!!!!'); + crypt +---------------------- + _/!!!!!!!zqM49hRzxko +(1 row) + CREATE TABLE ctest (data text, res text, salt text); INSERT INTO ctest VALUES ('password', '', ''); UPDATE ctest SET salt = gen_salt('xdes', 1001); diff --git a/contrib/pgcrypto/px-crypt.c b/contrib/pgcrypto/px-crypt.c index 7b003a76ca663bd418ac858d0a6e7680325e87c8..e3246fc5b9d5f4194735eeefd0f013db9272acff 100644 --- a/contrib/pgcrypto/px-crypt.c +++ b/contrib/pgcrypto/px-crypt.c @@ -42,7 +42,7 @@ run_crypt_des(const char *psw, const char *salt, char *res; res = px_crypt_des(psw, salt); - if (strlen(res) > len - 1) + if (res == NULL || strlen(res) > len - 1) return NULL; strcpy(buf, res); return buf; diff --git a/contrib/pgcrypto/sql/crypt-blowfish.sql b/contrib/pgcrypto/sql/crypt-blowfish.sql index 60c114005552093ba07c83d79a63fc96a3f87aa6..3b5a681c3f5cd56d5376f4a56f466fcc110f7f24 100644 --- a/contrib/pgcrypto/sql/crypt-blowfish.sql +++ b/contrib/pgcrypto/sql/crypt-blowfish.sql @@ -6,6 +6,15 @@ SELECT crypt('', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O'); SELECT crypt('foox', '$2a$06$RQiOJ.3ELirrXwxIZY8q0O'); +-- error, salt too short: +SELECT crypt('foox', '$2a$'); + +-- error, first digit of count in salt invalid +SELECT crypt('foox', '$2a$40$RQiOJ.3ELirrXwxIZY8q0O'); + +-- error, count in salt too small +SELECT crypt('foox', '$2a$00$RQiOJ.3ELirrXwxIZY8q0O'); + CREATE TABLE ctest (data text, res text, salt text); INSERT INTO ctest VALUES ('password', '', ''); diff --git a/contrib/pgcrypto/sql/crypt-des.sql b/contrib/pgcrypto/sql/crypt-des.sql index fabdc652fc986808dc6a7c3a0d5dc21ed31ac7b0..a85ec1e655510d8d66e7f6f478ce63e7375e25c9 100644 --- a/contrib/pgcrypto/sql/crypt-des.sql +++ b/contrib/pgcrypto/sql/crypt-des.sql @@ -6,6 +6,10 @@ SELECT crypt('', 'NB'); SELECT crypt('foox', 'NB'); +-- We are supposed to pass in a 2-character salt. +-- error since salt is too short: +SELECT crypt('password', 'a'); + CREATE TABLE ctest (data text, res text, salt text); INSERT INTO ctest VALUES ('password', '', ''); diff --git a/contrib/pgcrypto/sql/crypt-xdes.sql b/contrib/pgcrypto/sql/crypt-xdes.sql index d4a74f76bde5276b2474a443a04d5e5e34caa602..8171cd872be21e128ca7343979b2cb8400901400 100644 --- a/contrib/pgcrypto/sql/crypt-xdes.sql +++ b/contrib/pgcrypto/sql/crypt-xdes.sql @@ -6,6 +6,22 @@ SELECT crypt('', '_J9..j2zz'); SELECT crypt('foox', '_J9..j2zz'); +-- check XDES handling of keys longer than 8 chars +SELECT crypt('longlongpassword', '_J9..j2zz'); + +-- error, salt too short +SELECT crypt('foox', '_J9..BWH'); + +-- error, count specified in the second argument is 0 +SELECT crypt('password', '_........'); + +-- error, count will wind up still being 0 due to invalid encoding +-- of the count: only chars ``./0-9A-Za-z' are valid +SELECT crypt('password', '_..!!!!!!'); + +-- count should be non-zero here, will work +SELECT crypt('password', '_/!!!!!!!'); + CREATE TABLE ctest (data text, res text, salt text); INSERT INTO ctest VALUES ('password', '', '');