Author: sf
Date: Fri Jul 6 11:41:24 2012
New Revision: 1358137
URL: http://svn.apache.org/viewvc?rev=1358137&view=rev
Log:
Merge r1357761,1357772,1357780,1357966,1357968,1357979 from ARP trunk:
Add support for bcrypt encoded passwords.
The bcrypt implementation uses code from crypt_blowfish written by Solar
Designer <solar openwall com>. The x86 assembler implementation is not used
becaused it did not result in significant speed-up on my system.
apr_bcrypt_encode creates hashes with "$2y$" prefix, but
apr_password_validate also accepts the old prefix "$2a$".
* crypto/crypt_blowfish.[ch]: Imported from crypt_blowfish 1.2. The only
change compared to the upstream version is setting BF_ASM to 0.
* crypto/apr_passwd.c: Add bcrypt support to apr_password_validate, add
apr_bcrypt_encode
* test/testpass.c: Add new tests, for bcrypt and the old schemes.
* include/apr_md5.h: apr_password_validate() is left here fore backward
compatibility and apr_bcrypt_encode() is added here as well.
Move non-MD5-related things from apr_md5.c to new file apr_passwd.c
Add an APR_ASSERT_FAILURE macro for tests that must fail
Added:
apr/apr-util/branches/1.5.x/crypto/apr_passwd.c
- copied, changed from r1357772, apr/apr/trunk/crypto/apr_passwd.c
apr/apr-util/branches/1.5.x/crypto/crypt_blowfish.c
- copied unchanged from r1357780, apr/apr/trunk/crypto/crypt_blowfish.c
apr/apr-util/branches/1.5.x/crypto/crypt_blowfish.h
- copied unchanged from r1357780, apr/apr/trunk/crypto/crypt_blowfish.h
Modified:
apr/apr-util/branches/1.5.x/ (props changed)
apr/apr-util/branches/1.5.x/CHANGES
apr/apr-util/branches/1.5.x/build.conf
apr/apr-util/branches/1.5.x/crypto/apr_md5.c
apr/apr-util/branches/1.5.x/include/apr_md5.h
apr/apr-util/branches/1.5.x/test/testpass.c
apr/apr-util/branches/1.5.x/test/testutil.c
apr/apr-util/branches/1.5.x/test/testutil.h
Propchange: apr/apr-util/branches/1.5.x/
------------------------------------------------------------------------------
Merged /apr/apr/trunk:r1357761,1357772,1357780,1357966,1357968,1357979
Modified: apr/apr-util/branches/1.5.x/CHANGES
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.5.x/CHANGES?rev=1358137&r1=1358136&r2=1358137&view=diff
==============================================================================
--- apr/apr-util/branches/1.5.x/CHANGES [utf-8] (original)
+++ apr/apr-util/branches/1.5.x/CHANGES [utf-8] Fri Jul 6 11:41:24 2012
@@ -1,6 +1,11 @@
-*- coding: utf-8 -*-
Changes with APR-util 1.5.0
+ *) apr_password_validate, apr_bcrypt_encode: Add support for bcrypt encoded
+ passwords. The bcrypt implementation uses code from crypt_blowfish
+ written by Solar Designer <solar openwall com>. apr_bcrypt_encode creates
+ hashes with "$2y$" prefix, but apr_password_validate also accepts the old
+ prefix "$2a$". [Stefan Fritsch]
Changes with APR-util 1.4.0
Modified: apr/apr-util/branches/1.5.x/build.conf
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.5.x/build.conf?rev=1358137&r1=1358136&r2=1358137&view=diff
==============================================================================
--- apr/apr-util/branches/1.5.x/build.conf (original)
+++ apr/apr-util/branches/1.5.x/build.conf Fri Jul 6 11:41:24 2012
@@ -10,9 +10,11 @@ paths =
crypto/apr_crypto.c
crypto/apr_md4.c
crypto/apr_md5.c
+ crypto/apr_passwd.c
crypto/apr_sha1.c
crypto/getuuid.c
crypto/uuid.c
+ crypto/crypt_blowfish.c
dbm/apr_dbm_sdbm.c
dbm/apr_dbm.c
dbm/sdbm/*.c
Modified: apr/apr-util/branches/1.5.x/crypto/apr_md5.c
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.5.x/crypto/apr_md5.c?rev=1358137&r1=1358136&r2=1358137&view=diff
==============================================================================
--- apr/apr-util/branches/1.5.x/crypto/apr_md5.c (original)
+++ apr/apr-util/branches/1.5.x/crypto/apr_md5.c Fri Jul 6 11:41:24 2012
@@ -61,20 +61,10 @@
#include "apr_md5.h"
#include "apr_lib.h"
#include "apu_config.h"
-#include "apr_sha1.h"
#if APR_HAVE_STRING_H
#include <string.h>
#endif
-#if APR_HAVE_CRYPT_H
-#include <crypt.h>
-#endif
-#if APR_HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#if APR_HAVE_PTHREAD_H
-#include <pthread.h>
-#endif
/* Constants for MD5Transform routine.
*/
@@ -478,7 +468,7 @@ APU_DECLARE(apr_status_t) apr_MD5InitEBC
* Define the Magic String prefix that identifies a password as being
* hashed using our algorithm.
*/
-static const char *apr1_id = "$apr1$";
+static const char const *apr1_id = "$apr1$";
/*
* The following MD5 password encryption code was largely borrowed from
@@ -660,110 +650,3 @@ APU_DECLARE(apr_status_t) apr_md5_encode
apr_cpystrn(result, passwd, nbytes - 1);
return APR_SUCCESS;
}
-
-#if !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
-#if defined(APU_CRYPT_THREADSAFE) || !APR_HAS_THREADS || \
- defined(CRYPT_R_CRYPTD) || defined(CRYPT_R_STRUCT_CRYPT_DATA)
-
-#define crypt_mutex_lock()
-#define crypt_mutex_unlock()
-
-#elif APR_HAVE_PTHREAD_H && defined(PTHREAD_MUTEX_INITIALIZER)
-
-static pthread_mutex_t crypt_mutex = PTHREAD_MUTEX_INITIALIZER;
-static void crypt_mutex_lock(void)
-{
- pthread_mutex_lock(&crypt_mutex);
-}
-
-static void crypt_mutex_unlock(void)
-{
- pthread_mutex_unlock(&crypt_mutex);
-}
-
-#else
-
-#error apr_password_validate() is not threadsafe. rebuild APR without thread support.
-
-#endif
-#endif
-
-/*
- * Validate a plaintext password against a smashed one. Uses either
- * crypt() (if available) or apr_md5_encode() or apr_sha1_base64(), depending
- * upon the format of the smashed input password. Returns APR_SUCCESS if
- * they match, or APR_EMISMATCH if they don't. If the platform doesn't
- * support crypt, then the default check is against a clear text string.
- */
-APU_DECLARE(apr_status_t) apr_password_validate(const char *passwd,
- const char *hash)
-{
- char sample[120];
-#if !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
- char *crypt_pw;
-#endif
- if (!strncmp(hash, apr1_id, strlen(apr1_id))) {
- /*
- * The hash was created using our custom algorithm.
- */
- apr_md5_encode(passwd, hash, sample, sizeof(sample));
- }
- else if (!strncmp(hash, APR_SHA1PW_ID, APR_SHA1PW_IDLEN)) {
- apr_sha1_base64(passwd, (int)strlen(passwd), sample);
- }
- else {
- /*
- * It's not our algorithm, so feed it to crypt() if possible.
- */
-#if defined(WIN32) || defined(BEOS) || defined(NETWARE)
- apr_cpystrn(sample, passwd, sizeof(sample) - 1);
-#elif defined(CRYPT_R_CRYPTD)
- CRYPTD buffer;
-
- crypt_pw = crypt_r(passwd, hash, &buffer);
- if (!crypt_pw) {
- return APR_EMISMATCH;
- }
- apr_cpystrn(sample, crypt_pw, sizeof(sample) - 1);
-#elif defined(CRYPT_R_STRUCT_CRYPT_DATA)
- struct crypt_data buffer;
-
-#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2,4)
- buffer.initialized = 0;
-#else
- /*
- * glibc before 2.3.2 had a bug that required clearing the
- * whole struct
- */
- memset(&buffer, 0, sizeof(buffer));
-#endif
- crypt_pw = crypt_r(passwd, hash, &buffer);
- if (!crypt_pw) {
- return APR_EMISMATCH;
- }
- apr_cpystrn(sample, crypt_pw, sizeof(sample) - 1);
-#else
- /* Do a bit of sanity checking since we know that crypt_r()
- * should always be used for threaded builds on AIX, and
- * problems in configure logic can result in the wrong
- * choice being made.
- */
-#if defined(_AIX) && APR_HAS_THREADS
-#error Configuration error! crypt_r() should have been selected!
-#endif
-
- /* Handle thread safety issues by holding a mutex around the
- * call to crypt().
- */
- crypt_mutex_lock();
- crypt_pw = crypt(passwd, hash);
- if (!crypt_pw) {
- crypt_mutex_unlock();
- return APR_EMISMATCH;
- }
- apr_cpystrn(sample, crypt_pw, sizeof(sample) - 1);
- crypt_mutex_unlock();
-#endif
- }
- return (strcmp(sample, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
-}
Copied: apr/apr-util/branches/1.5.x/crypto/apr_passwd.c (from r1357772, apr/apr/trunk/crypto/apr_passwd.c)
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.5.x/crypto/apr_passwd.c?p2=apr/apr-util/branches/1.5.x/crypto/apr_passwd.c&p1=apr/apr/trunk/crypto/apr_passwd.c&r1=1357772&r2=1358137&rev=1358137&view=diff
==============================================================================
--- apr/apr/trunk/crypto/apr_passwd.c (original)
+++ apr/apr-util/branches/1.5.x/crypto/apr_passwd.c Fri Jul 6 11:41:24 2012
@@ -17,8 +17,8 @@
#include "apr_strings.h"
#include "apr_md5.h"
#include "apr_lib.h"
-#include "apr_private.h"
#include "apr_sha1.h"
+#include "crypt_blowfish.h"
#if APR_HAVE_STRING_H
#include <string.h>
@@ -55,32 +55,6 @@ static void crypt_mutex_unlock(void)
pthread_mutex_unlock(&crypt_mutex);
}
-#elif defined(OS2)
-
-static HMTX crypt_mutex = 0;
-static void crypt_mutex_lock()
-{
- if (crypt_mutex == 0) {
- /* Prevent race condition where two threads could try to create the
- * mutex concurrently
- */
- DosEnterCritSec();
-
- if (crypt_mutex == 0) {
- DosCreateMutexSem(NULL, &crypt_mutex, 0, FALSE);
- }
-
- DosExitCritSec();
- }
-
- DosRequestMutexSem(crypt_mutex, SEM_INDEFINITE_WAIT);
-}
-
-static void crypt_mutex_unlock()
-{
- DosReleaseMutexSem(crypt_mutex);
-}
-
#else
#error apr_password_validate() is not threadsafe. rebuild APR without thread support.
@@ -95,18 +69,26 @@ static void crypt_mutex_unlock()
* they match, or APR_EMISMATCH if they don't. If the platform doesn't
* support crypt, then the default check is against a clear text string.
*/
-APR_DECLARE(apr_status_t) apr_password_validate(const char *passwd,
+APU_DECLARE(apr_status_t) apr_password_validate(const char *passwd,
const char *hash)
{
char sample[120];
#if !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
char *crypt_pw;
#endif
- if (!strncmp(hash, apr1_id, strlen(apr1_id))) {
- /*
- * The hash was created using our custom algorithm.
- */
- apr_md5_encode(passwd, hash, sample, sizeof(sample));
+ if (hash[0] == '$') {
+ if (hash[1] == '2' && (hash[2] == 'a' || hash[2] == 'y')
+ && hash[3] == '$')
+ {
+ if (_crypt_blowfish_rn(passwd, hash, sample, sizeof(sample)) == NULL)
+ return APR_FROM_OS_ERROR(errno);
+ }
+ else if (!strncmp(hash, apr1_id, strlen(apr1_id))) {
+ /*
+ * The hash was created using our custom algorithm.
+ */
+ apr_md5_encode(passwd, hash, sample, sizeof(sample));
+ }
}
else if (!strncmp(hash, APR_SHA1PW_ID, APR_SHA1PW_IDLEN)) {
apr_sha1_base64(passwd, (int)strlen(passwd), sample);
@@ -167,3 +149,19 @@ APR_DECLARE(apr_status_t) apr_password_v
}
return (strcmp(sample, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
}
+
+static const char const *bcrypt_id = "$2y$";
+APU_DECLARE(apr_status_t) apr_bcrypt_encode(const char *pw,
+ unsigned int count,
+ const unsigned char *salt,
+ apr_size_t salt_len,
+ char *out, apr_size_t out_len)
+{
+ char setting[40];
+ if (_crypt_gensalt_blowfish_rn(bcrypt_id, count, (const char *)salt,
+ salt_len, setting, sizeof(setting)) == NULL)
+ return APR_FROM_OS_ERROR(errno);
+ if (_crypt_blowfish_rn(pw, setting, out, out_len) == NULL)
+ return APR_FROM_OS_ERROR(errno);
+ return APR_SUCCESS;
+}
Modified: apr/apr-util/branches/1.5.x/include/apr_md5.h
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.5.x/include/apr_md5.h?rev=1358137&r1=1358136&r2=1358137&view=diff
==============================================================================
--- apr/apr-util/branches/1.5.x/include/apr_md5.h (original)
+++ apr/apr-util/branches/1.5.x/include/apr_md5.h Fri Jul 6 11:41:24 2012
@@ -132,16 +132,30 @@ APU_DECLARE(apr_status_t) apr_md5(unsign
/**
* Encode a password using an MD5 algorithm
* @param password The password to encode
- * @param salt The salt to use for the encoding
+ * @param salt The salt string to use for the encoding
* @param result The string to store the encoded password in
* @param nbytes The size of the result buffer
*/
APU_DECLARE(apr_status_t) apr_md5_encode(const char *password, const char *salt,
char *result, apr_size_t nbytes);
+/**
+ * Encode a password using the bcrypt algorithm
+ * @param password The password to encode
+ * @param count The cost of the encoding, possible values are 4 to 31
+ * @param salt Pointer to binary data to be used as salt for the encoding
+ * @param salt_len The size of the salt data (must be >= 16)
+ * @param out The string to store the encoded password in
+ * @param out_len The size of the result buffer (must be >= 61)
+ */
+APU_DECLARE(apr_status_t) apr_bcrypt_encode(const char *pw,
+ unsigned int count,
+ const unsigned char *salt,
+ apr_size_t salt_len,
+ char *out, apr_size_t out_len);
/**
- * Validate hashes created by APR-supported algorithms: md5 and sha1.
+ * Validate hashes created by APR-supported algorithms: md5, bcrypt, and sha1.
* hashes created by crypt are supported only on platforms that provide
* crypt(3), so don't rely on that function unless you know that your
* application will be run only on platforms that support it. On platforms
Modified: apr/apr-util/branches/1.5.x/test/testpass.c
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.5.x/test/testpass.c?rev=1358137&r1=1358136&r2=1358137&view=diff
==============================================================================
--- apr/apr-util/branches/1.5.x/test/testpass.c (original)
+++ apr/apr-util/branches/1.5.x/test/testpass.c Fri Jul 6 11:41:24 2012
@@ -117,25 +117,53 @@ static void test_threadsafe(abts_case *t
static void test_shapass(abts_case *tc, void *data)
{
const char *pass = "hellojed";
+ const char *pass2 = "hellojed2";
char hash[100];
apr_sha1_base64(pass, strlen(pass), hash);
apr_assert_success(tc, "SHA1 password validated",
apr_password_validate(pass, hash));
+ APR_ASSERT_FAILURE(tc, "wrong SHA1 password should not validate",
+ apr_password_validate(pass2, hash));
}
static void test_md5pass(abts_case *tc, void *data)
{
const char *pass = "hellojed", *salt = "sardine";
+ const char *pass2 = "hellojed2";
char hash[100];
apr_md5_encode(pass, salt, hash, sizeof hash);
apr_assert_success(tc, "MD5 password validated",
apr_password_validate(pass, hash));
+ APR_ASSERT_FAILURE(tc, "wrong MD5 password should not validate",
+ apr_password_validate(pass2, hash));
}
+static void test_bcryptpass(abts_case *tc, void *data)
+{
+ const char *pass = "hellojed";
+ const char *pass2 = "hellojed2";
+ unsigned char salt[] = "sardine_sardine";
+ char hash[100];
+ const char *hash2 = "$2a$08$qipUJiI9fySUN38hcbz.lucXvAmtgowKOWYtB9y3CXyl6lTknruou";
+ const char *pass3 = "foobar";
+
+ apr_assert_success(tc, "bcrypt encode password",
+ apr_bcrypt_encode(pass, 5, salt, sizeof(salt), hash,
+ sizeof(hash)));
+
+ apr_assert_success(tc, "bcrypt password validated",
+ apr_password_validate(pass, hash));
+ APR_ASSERT_FAILURE(tc, "wrong bcrypt password should not validate",
+ apr_password_validate(pass2, hash));
+ apr_assert_success(tc, "bcrypt password validated",
+ apr_password_validate(pass3, hash2));
+}
+
+
abts_suite *testpass(abts_suite *suite)
{
suite = ADD_SUITE(suite);
@@ -148,6 +176,7 @@ abts_suite *testpass(abts_suite *suite)
#endif /* CRYPT_ALGO_SUPPORTED */
abts_run_test(suite, test_shapass, NULL);
abts_run_test(suite, test_md5pass, NULL);
+ abts_run_test(suite, test_bcryptpass, NULL);
return suite;
}
Modified: apr/apr-util/branches/1.5.x/test/testutil.c
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.5.x/test/testutil.c?rev=1358137&r1=1358136&r2=1358137&view=diff
==============================================================================
--- apr/apr-util/branches/1.5.x/test/testutil.c (original)
+++ apr/apr-util/branches/1.5.x/test/testutil.c Fri Jul 6 11:41:24 2012
@@ -37,6 +37,18 @@ void apr_assert_success(abts_case* tc, c
}
}
+void apr_assert_failure(abts_case* tc, const char* context, apr_status_t rv,
+ int lineno)
+{
+ if (rv == APR_ENOTIMPL) {
+ abts_not_impl(tc, context, lineno);
+ } else if (rv == APR_SUCCESS) {
+ char buf[STRING_MAX];
+ sprintf(buf, "%s (%d): expected failure, got success\n", context, rv);
+ abts_fail(tc, buf, lineno);
+ }
+}
+
void initialize(void) {
if (apr_initialize() != APR_SUCCESS) {
abort();
Modified: apr/apr-util/branches/1.5.x/test/testutil.h
URL: http://svn.apache.org/viewvc/apr/apr-util/branches/1.5.x/test/testutil.h?rev=1358137&r1=1358136&r2=1358137&view=diff
==============================================================================
--- apr/apr-util/branches/1.5.x/test/testutil.h (original)
+++ apr/apr-util/branches/1.5.x/test/testutil.h Fri Jul 6 11:41:24 2012
@@ -41,6 +41,12 @@ extern apr_pool_t *p;
* for RV and CONTEXT message. */
void apr_assert_success(abts_case* tc, const char *context, apr_status_t rv);
+void apr_assert_failure(abts_case* tc, const char *context,
+ apr_status_t rv, int lineno);
+#define APR_ASSERT_FAILURE(tc, ctxt, rv) \
+ apr_assert_failure(tc, ctxt, rv, __LINE__)
+
+
void initialize(void);
abts_suite *teststrmatch(abts_suite *suite);
|