From c26b50d9ad992ef73ada5a96e0db29781ddad88a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Mon, 29 Apr 2013 13:08:25 +0000 Subject: [PATCH] [mod_auth] add htpasswd -s (SHA1) support if openssl is used (needs openssl for SHA1). This doesn't use any salt, md5 with salt is probably better. git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2870 152afb58-edef-0310-8abb-c4023f1b3aa9 --- NEWS | 1 + src/http_auth.c | 38 ++++++++++++++++++++++++++++++++++++++ tests/lighttpd.htpasswd | 1 + tests/mod-auth.t | 20 +++++++++++++++++++- 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index bbbf398e..58b802fa 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,7 @@ NEWS * call ERR_clear_error only for ssl connections in CON_STATE_ERROR * reject non ASCII characters in HTTP header names * [mod_auth] use crypt() on encrypted password instead of extracting salt first (fixes #2483) + * [mod_auth] add htpasswd -s (SHA1) support if openssl is used (needs openssl for SHA1). This doesn't use any salt, md5 with salt is probably better. - 1.4.32 - 2012-11-21 * Code cleanup with clang/sparse (fixes #2437, thx kibi) diff --git a/src/http_auth.c b/src/http_auth.c index 451d5d70..c6c8a118 100644 --- a/src/http_auth.c +++ b/src/http_auth.c @@ -29,6 +29,10 @@ #include "md5.h" +#ifdef USE_OPENSSL +#include +#endif + #define HASHLEN 16 #define HASHHEXLEN 32 typedef unsigned char HASH[HASHLEN]; @@ -599,6 +603,35 @@ static void apr_md5_encode(const char *pw, const char *salt, char *result, size_ apr_cpystrn(result, passwd, nbytes - 1); } +#ifdef USE_OPENSSL +static void apr_sha_encode(const char *pw, char *result, size_t nbytes) { + static const unsigned char base64_data[65] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + unsigned char digest[21]; /* multiple of 3 for base64 encoding */ + int i; + + memset(result, 0, nbytes); + + /* need 5 bytes for "{SHA}", 28 for base64 (3 bytes -> 4 bytes) of SHA1 (20 bytes), 1 terminating */ + if (nbytes < 5 + 28 + 1) return; + + SHA1((const unsigned char*) pw, strlen(pw), digest); + digest[20] = 0; + + strcpy(result, "{SHA}"); + result = result + 5; + for (i = 0; i < 21; i += 3) { + unsigned int v = (digest[i] << 16) | (digest[i+1] << 8) | digest[i+2]; + result[3] = base64_data[v & 0x3f]; v >>= 6; + result[2] = base64_data[v & 0x3f]; v >>= 6; + result[1] = base64_data[v & 0x3f]; v >>= 6; + result[0] = base64_data[v & 0x3f]; + result += 4; + } + result[-1] = '='; /* last digest character was already end of string, pad it */ + *result = '\0'; +} +#endif /** * @@ -643,6 +676,11 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p */ apr_md5_encode(pw, password->ptr, sample, sizeof(sample)); return (strcmp(sample, password->ptr) == 0) ? 0 : 1; +#ifdef USE_OPENSSL + } else if (0 == strncmp(password->ptr, "{SHA}", 5)) { + apr_sha_encode(pw, sample, sizeof(sample)); + return (strcmp(sample, password->ptr) == 0) ? 0 : 1; +#endif } else { #ifdef HAVE_CRYPT char *crypted; diff --git a/tests/lighttpd.htpasswd b/tests/lighttpd.htpasswd index 1faf25a4..eed7dd26 100644 --- a/tests/lighttpd.htpasswd +++ b/tests/lighttpd.htpasswd @@ -1,2 +1,3 @@ des:12tMnfw882VDQ md5:$1$md5$kIa7Juuiv8zja0ILQPR36/ +sha:{SHA}2PRZAyDhNDqRW2OUFwZQqPNdaSY= diff --git a/tests/mod-auth.t b/tests/mod-auth.t index 89ead9dd..e070df10 100755 --- a/tests/mod-auth.t +++ b/tests/mod-auth.t @@ -8,7 +8,7 @@ BEGIN { use strict; use IO::Socket; -use Test::More tests => 15; +use Test::More tests => 17; use LightyTest; my $tf = LightyTest->new(); @@ -65,6 +65,24 @@ EOF $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token - htpasswd (des) (lowercase)'); +$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; +ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token - htpasswd (sha)'); + +$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ]; +ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token - htpasswd (sha, wrong password)'); + SKIP: { skip "no md5 for crypt under cygwin", 1 if $^O eq 'cygwin';