Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Tue, 14 Aug 2012 07:35:14 +0400
From: Solar Designer <solar@...nwall.com>
To: musl@...ts.openwall.com
Subject: Re: Todo for release?

On Mon, Aug 13, 2012 at 10:58:05PM -0400, Rich Felker wrote:
> On Tue, Aug 14, 2012 at 06:49:03AM +0400, Solar Designer wrote:
> > > If this issue is as simple to solve as it sounds, it might make sense
> > > to allow arbitrary key sizes. After all, programs that could be DoS'd
> > > by long keys are already going to be limiting key length themselves.
> > 
> > That's wishful thinking.
> 
> Are you sure? I haven't read the code lately, but I can't imagine any
> login daemon is going to be calling realloc() in a loop to read an
> arbitrarily long password before authentication. That just sounds
> gratuitously broken (i.e. someone went out of their way to write
> painful code that does nothing useful and makes their daemon
> susceptible to DoS).

I guess many daemons written in C limit the length at a few kilobytes -
which may allow for about 100 times greater than intended (by sysadmin)
crypt() running time.  For md5crypt and sha*crypt, the first slowdown
occurs between length 15 and 16.

Then, it does not take explicit realloc() for just the password string
to support arbitrarily long passwords.  The daemon may be using an
abstraction layer for all strings - e.g., qmail, Postfix, and vsftpd
have such dynamic string libraries of their own, and overall this is
good (it avoids buffer overflows and artificial limits in other places).
I don't know if vsftpd would in fact pass arbitrarily long passwords to
crypt() - this is worth checking.

Finally, some services are written in languages that support dynamically
allocated strings natively.  I recall that OpenStack's Python code was
patched to impose a limit of 4096 chars on passwords recently,
specifically in response to risks like what we're discussing here.
(And 4096 is still a lot - may allow for some attacks.)

> > > something that can never match. By the way, would you agree that all
> > > programs that generate new password hashes should do so by calling
> > > crypt twice, the second time using the output of the first as the
> > > setting/salt, and verify that the results match? This seems to be the
> > > only safe/portable way to make sure you got a valid hash and not an
> > > error.
> > 
> > This makes sense, yet it sounds overkill to me.  I'd simply check for
> > hash && strlen(hash) >= 13.
> 
> Indeed, strlen(hash)>=13 is certainly a necessary condition, but is it
> sufficient? I could imagine a hypothetical crypt implementation that
> puts error messages in the unmatchable hash as a debugging aid to why
> generating the hash failed, but I agree they probably don't exist.
> Still, changing your password should not be a frequent action, so it
> might make the most sense to do the check the way I suggested.

An aspect to consider is that if you call crypt() twice for just one
request from the user (to set a password), you effectively double the
iteration count as it relates to potential CPU time exhaustion DoS
attacks (twice more CPU time is consumed per request).  So if these
attacks are the limiting factor in a sysadmin's ability to set a higher
iteration count, this will result in the iteration count being twice
lower (and accordingly weaker hashes being used on the system).  (If the
protocol is such that the same request contains the old password to be
checked first, then the difference may be 3/2.)  While each individual
sysadmin is somewhat unlikely to apply this reasoning and consider
password setting as the worst DoS attack vector, I think that overall
this may in fact result in somewhat lower iteration counts being used
(average across many systems).

Alexander

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.