[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#550360: apr_password_validate() always succeeds if hash parameter is empty string



Package: libaprutil1
Version: 1.3.9+dfsg-2


While working on a Python module that interfaces with the MD5 routines of
libaprutil, I believe I have found a bug in the behaviour of
apr_password_validate(). Consider the following C program:

  #include <apr-1.0/apr_md5.h>
  #include <stdio.h>   // for printf()
  #include <assert.h>  // for assert()

  int main(int argc, char** argv)
  {
    const char* password = "foo";
    const char* hash = "";

    apr_status_t status = apr_password_validate(password, hash);
    printf("status is %d\n", status);
    assert(APR_EMISMATCH == status);

    return 0;
  }

The program tests the apr_password_validate() function for a border case
where the "hash" input parameter is an empty string. The program expects
the function to fail and return a status of APR_EMISMATCH. Surprisingly,
though, the function succeeds when the program is run, meaning that the
password could be validated. In my opinion, this is a bug.

In order to track down the problem, I had a look at the implementation of
apr_password_validate(), in crypto/apr_md5.c of the 1.3.9 release of
libaprutil (online:
http://svn.apache.org/repos/asf/apr/apr-util/tags/1.3.9/crypto/apr_md5.c).
I saw that with the above input parameters (i.e. an empty hash)
apr_password_validate() is calling one of the various crypt() variants. It
passes both the password and the hash to crypt() without any
modifications. It is therefore reasonable to conclude that crypt() must do
something unexpected. The following C program tests this by calling
crypt() in a fashion similar to apr_password_validate():

  #include <crypt.h>
  #include <stdio.h>   // for printf()
  #include <assert.h>  // for assert()

  int main(int argc, char** argv)
  {
    const char* passwd = "foo";
    const char* salt = "";
    char* hash;

    hash = crypt(passwd, salt);
    size_t hash_len = strlen(hash);
    printf("hash = %s, hash len = %d\n", hash, hash_len);
    assert(hash_len > 0);

    return 0;
  }

The program tests crypt() for a border case where the "salt" input
parameter is an empty string. The program expects crypt() to succeed and
return a non-empty hash. However, when the program is actually run it
reveals that crypt() returns an empty hash.


Although the whole issue can be considered a bug in the implementation of
crypt(), I still report the issue against libaprutil, because I found the
problem when working with apr_password_validate(), and the function
certainly behaves incorrectly (with an empty hash parameter, *every*
password validates).

I am not sure if it is of interest, but crypt() on Mac OS X (where I am
originally developing my Python module) can handle an empty salt - for
instance, crypt() on Mac OS X 10.5 returns the following hash for password
"foo" and an empty salt: ".hDUin/FRHqqI". Consequently, the two test
programs above work on Mac OS X, but fail on Debian.


If I can help with further testing, please let me know.

Cheers
Patrick


My Debian environment:
* VirtualBox machine
* testing distribution
* libaprutil1 and libaprutil1-dev, both packages version 1.3.9+dfsg-2
* libc6 and libc6-dev, both packages version 2.9.25
* gcc, package version 4:4.3.3-9


I compiled the the two test programs like this:
* gcc -o test-pwval test-pwval.c -laprutil-1
* gcc -o test-crypt test-crypt.c -lcrypt





Reply to: