|
|
Message-ID: <20261106230259.GY3542221@port70.net> Date: Sat, 7 Nov 2026 00:02:59 +0100 From: Szabolcs Nagy <nsz@...t70.net> To: Rich Felker <dalias@...c.org> Cc: musl@...ts.openwall.com Subject: Re: [PATCH] [RFC] Harden against misuse of crypt * Rich Felker <dalias@...c.org> [2026-11-06 16:54:05 -0500]: > This patch changes crypt to return "*0" instead of "*" as the "failure > token" that will not match any password. > > Likewise, "*1" is used in place of "x" if the failure token would be > identical to the input salt, but this case is presently unreachable. > Since the existing DES path interprets characters outside the portable > range as valid DES salt, passing a setting of "*0" will not produce > "*1" but instead a DES-hashed password with "*0" as the salt. I don't > see any problem with this -- "*0" should never appear in the > passwd/shadow db anyway, and if it somehow did, crypt(pass,"*0") would > still return something not-equal to "*0": "*0" followed by 11 > characters of DES hash. > > In any case, I put the "*1" code path in there in case anything ever > changes with how we handle DES, to be sure crypt(pass,"*0") can never > return "*0". > > Rich looks good, but this commit has no reference to the analysis in https://www.openwall.com/lists/musl/2026/11/06/7 i would add a link. or a note that the misuse was observed in the wild motivating the change. and that "*0" has historical precendent so broken callers are less likely. as a friend put it, if the goal is to minimize the likelihood of the failure token matching a passwd entry then it is possible to do better than "*0": e.g. 100 non-printable bytes (in case we really want to be defensive about misuses and typos in passwd files) but if the plan is to move to return NULL then i guess "*0" is the least risky solution for now. > diff --git a/src/crypt/crypt_blowfish.c b/src/crypt/crypt_blowfish.c > index d722607b..0bb82360 100644 > --- a/src/crypt/crypt_blowfish.c > +++ b/src/crypt/crypt_blowfish.c > @@ -802,5 +802,5 @@ char *__crypt_blowfish(const char *key, const char *setting, char *output) > if (ok && retval) > return retval; > > - return "*"; > + return "*0"; > } > diff --git a/src/crypt/crypt_des.c b/src/crypt/crypt_des.c > index 338a8f37..38e63395 100644 > --- a/src/crypt/crypt_des.c > +++ b/src/crypt/crypt_des.c > @@ -1012,5 +1012,5 @@ char *__crypt_des(const char *key, const char *setting, char *output) > if (p && !strcmp(p, test_hash) && retval) > return retval; > > - return (setting[0]=='*') ? "x" : "*"; > + return (setting[0]!='*' || setting[1]!='0') ? "*0" : "*1"; > } > diff --git a/src/crypt/crypt_md5.c b/src/crypt/crypt_md5.c > index 6e75b36c..e8c609f1 100644 > --- a/src/crypt/crypt_md5.c > +++ b/src/crypt/crypt_md5.c > @@ -4,7 +4,7 @@ > * original md5 crypt design is from Poul-Henning Kamp > * this implementation was created based on the code in freebsd > * at least 32bit int is assumed, key is limited and $1$ prefix is mandatory, > - * on error "*" is returned > + * on error "*0" is returned > */ > #include <string.h> > #include <stdint.h> > @@ -280,6 +280,6 @@ char *__crypt_md5(const char *key, const char *setting, char *output) > /* self test and stack cleanup */ > q = md5crypt(testkey, testsetting, testbuf); > if (!p || q != testbuf || memcmp(testbuf, testhash, sizeof testhash)) > - return "*"; > + return "*0"; > return p; > } > diff --git a/src/crypt/crypt_sha256.c b/src/crypt/crypt_sha256.c > index e885dc68..8d9c7e73 100644 > --- a/src/crypt/crypt_sha256.c > +++ b/src/crypt/crypt_sha256.c > @@ -5,7 +5,7 @@ > * in this implementation at least 32bit int is assumed, > * key length is limited, the $5$ prefix is mandatory, '\n' and ':' is rejected > * in the salt and rounds= setting must contain a valid iteration count, > - * on error "*" is returned. > + * on error "*0" is returned. > */ > #include <ctype.h> > #include <stdlib.h> > @@ -317,6 +317,6 @@ char *__crypt_sha256(const char *key, const char *setting, char *output) > /* self test and stack cleanup */ > q = sha256crypt(testkey, testsetting, testbuf); > if (!p || q != testbuf || memcmp(testbuf, testhash, sizeof testhash)) > - return "*"; > + return "*0"; > return p; > } > diff --git a/src/crypt/crypt_sha512.c b/src/crypt/crypt_sha512.c > index 39970caf..c9973f0e 100644 > --- a/src/crypt/crypt_sha512.c > +++ b/src/crypt/crypt_sha512.c > @@ -5,7 +5,7 @@ > * in this implementation at least 32bit int is assumed, > * key length is limited, the $6$ prefix is mandatory, '\n' and ':' is rejected > * in the salt and rounds= setting must contain a valid iteration count, > - * on error "*" is returned. > + * on error "*0" is returned. > */ > #include <ctype.h> > #include <stdlib.h> > @@ -366,6 +366,6 @@ char *__crypt_sha512(const char *key, const char *setting, char *output) > /* self test and stack cleanup */ > q = sha512crypt(testkey, testsetting, testbuf); > if (!p || q != testbuf || memcmp(testbuf, testhash, sizeof testhash)) > - return "*"; > + return "*0"; > return p; > }
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.