|
|
|
@ -1,7 +1,6 @@
|
|
|
|
|
#include "server.h"
|
|
|
|
|
#include "log.h"
|
|
|
|
|
#include "http_auth.h"
|
|
|
|
|
#include "http_auth_digest.h"
|
|
|
|
|
#include "inet_ntop_cache.h"
|
|
|
|
|
#include "stream.h"
|
|
|
|
|
|
|
|
|
@ -28,17 +27,22 @@
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
|
|
#ifdef USE_OPENSSL
|
|
|
|
|
# include <openssl/md5.h>
|
|
|
|
|
#else
|
|
|
|
|
# include "md5.h"
|
|
|
|
|
#include "md5.h"
|
|
|
|
|
|
|
|
|
|
typedef li_MD5_CTX MD5_CTX;
|
|
|
|
|
#define MD5_Init li_MD5_Init
|
|
|
|
|
#define MD5_Update li_MD5_Update
|
|
|
|
|
#define MD5_Final li_MD5_Final
|
|
|
|
|
#define HASHLEN 16
|
|
|
|
|
#define HASHHEXLEN 32
|
|
|
|
|
typedef unsigned char HASH[HASHLEN];
|
|
|
|
|
typedef char HASHHEX[HASHHEXLEN+1];
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
static void CvtHex(const HASH Bin, char Hex[33]) {
|
|
|
|
|
unsigned short i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
|
Hex[i*2] = int2hex((Bin[i] >> 4) & 0xf);
|
|
|
|
|
Hex[i*2+1] = int2hex(Bin[i] & 0xf);
|
|
|
|
|
}
|
|
|
|
|
Hex[32] = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* the $apr1$ handling is taken from apache 1.3.x
|
|
|
|
@ -435,7 +439,7 @@ static int http_auth_match_rules(server *srv, mod_auth_plugin_data *p, const cha
|
|
|
|
|
|
|
|
|
|
static void to64(char *s, unsigned long v, int n)
|
|
|
|
|
{
|
|
|
|
|
static unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */
|
|
|
|
|
static const unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */
|
|
|
|
|
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
|
|
|
|
|
|
|
|
while (--n >= 0) {
|
|
|
|
@ -455,7 +459,7 @@ static void apr_md5_encode(const char *pw, const char *salt, char *result, size_
|
|
|
|
|
const char *sp, *ep;
|
|
|
|
|
unsigned char final[APR_MD5_DIGESTSIZE];
|
|
|
|
|
ssize_t sl, pl, i;
|
|
|
|
|
MD5_CTX ctx, ctx1;
|
|
|
|
|
li_MD5_CTX ctx, ctx1;
|
|
|
|
|
unsigned long l;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -487,33 +491,33 @@ static void apr_md5_encode(const char *pw, const char *salt, char *result, size_
|
|
|
|
|
/*
|
|
|
|
|
* 'Time to make the doughnuts..'
|
|
|
|
|
*/
|
|
|
|
|
MD5_Init(&ctx);
|
|
|
|
|
li_MD5_Init(&ctx);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The password first, since that is what is most unknown
|
|
|
|
|
*/
|
|
|
|
|
MD5_Update(&ctx, pw, strlen(pw));
|
|
|
|
|
li_MD5_Update(&ctx, pw, strlen(pw));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Then our magic string
|
|
|
|
|
*/
|
|
|
|
|
MD5_Update(&ctx, APR1_ID, strlen(APR1_ID));
|
|
|
|
|
li_MD5_Update(&ctx, APR1_ID, strlen(APR1_ID));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Then the raw salt
|
|
|
|
|
*/
|
|
|
|
|
MD5_Update(&ctx, sp, sl);
|
|
|
|
|
li_MD5_Update(&ctx, sp, sl);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Then just as many characters of the MD5(pw, salt, pw)
|
|
|
|
|
*/
|
|
|
|
|
MD5_Init(&ctx1);
|
|
|
|
|
MD5_Update(&ctx1, pw, strlen(pw));
|
|
|
|
|
MD5_Update(&ctx1, sp, sl);
|
|
|
|
|
MD5_Update(&ctx1, pw, strlen(pw));
|
|
|
|
|
MD5_Final(final, &ctx1);
|
|
|
|
|
li_MD5_Init(&ctx1);
|
|
|
|
|
li_MD5_Update(&ctx1, pw, strlen(pw));
|
|
|
|
|
li_MD5_Update(&ctx1, sp, sl);
|
|
|
|
|
li_MD5_Update(&ctx1, pw, strlen(pw));
|
|
|
|
|
li_MD5_Final(final, &ctx1);
|
|
|
|
|
for (pl = strlen(pw); pl > 0; pl -= APR_MD5_DIGESTSIZE) {
|
|
|
|
|
MD5_Update(&ctx, final,
|
|
|
|
|
li_MD5_Update(&ctx, final,
|
|
|
|
|
(pl > APR_MD5_DIGESTSIZE) ? APR_MD5_DIGESTSIZE : pl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -527,10 +531,10 @@ static void apr_md5_encode(const char *pw, const char *salt, char *result, size_
|
|
|
|
|
*/
|
|
|
|
|
for (i = strlen(pw); i != 0; i >>= 1) {
|
|
|
|
|
if (i & 1) {
|
|
|
|
|
MD5_Update(&ctx, final, 1);
|
|
|
|
|
li_MD5_Update(&ctx, final, 1);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
MD5_Update(&ctx, pw, 1);
|
|
|
|
|
li_MD5_Update(&ctx, pw, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -542,7 +546,7 @@ static void apr_md5_encode(const char *pw, const char *salt, char *result, size_
|
|
|
|
|
strncat(passwd, sp, sl);
|
|
|
|
|
strcat(passwd, "$");
|
|
|
|
|
|
|
|
|
|
MD5_Final(final, &ctx);
|
|
|
|
|
li_MD5_Final(final, &ctx);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* And now, just to make sure things don't run too fast..
|
|
|
|
@ -550,28 +554,28 @@ static void apr_md5_encode(const char *pw, const char *salt, char *result, size_
|
|
|
|
|
* need 30 seconds to build a 1000 entry dictionary...
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < 1000; i++) {
|
|
|
|
|
MD5_Init(&ctx1);
|
|
|
|
|
li_MD5_Init(&ctx1);
|
|
|
|
|
if (i & 1) {
|
|
|
|
|
MD5_Update(&ctx1, pw, strlen(pw));
|
|
|
|
|
li_MD5_Update(&ctx1, pw, strlen(pw));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE);
|
|
|
|
|
li_MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE);
|
|
|
|
|
}
|
|
|
|
|
if (i % 3) {
|
|
|
|
|
MD5_Update(&ctx1, sp, sl);
|
|
|
|
|
li_MD5_Update(&ctx1, sp, sl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i % 7) {
|
|
|
|
|
MD5_Update(&ctx1, pw, strlen(pw));
|
|
|
|
|
li_MD5_Update(&ctx1, pw, strlen(pw));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i & 1) {
|
|
|
|
|
MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE);
|
|
|
|
|
li_MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
MD5_Update(&ctx1, pw, strlen(pw));
|
|
|
|
|
li_MD5_Update(&ctx1, pw, strlen(pw));
|
|
|
|
|
}
|
|
|
|
|
MD5_Final(final,&ctx1);
|
|
|
|
|
li_MD5_Final(final,&ctx1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p = passwd + strlen(passwd);
|
|
|
|
@ -614,17 +618,17 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p
|
|
|
|
|
* user:realm:md5(user:realm:password)
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
MD5_CTX Md5Ctx;
|
|
|
|
|
li_MD5_CTX Md5Ctx;
|
|
|
|
|
HASH HA1;
|
|
|
|
|
char a1[256];
|
|
|
|
|
|
|
|
|
|
MD5_Init(&Md5Ctx);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)realm->ptr, realm->used - 1);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
|
|
|
|
|
MD5_Final(HA1, &Md5Ctx);
|
|
|
|
|
li_MD5_Init(&Md5Ctx);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)realm->ptr, realm->used - 1);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
|
|
|
|
|
li_MD5_Final(HA1, &Md5Ctx);
|
|
|
|
|
|
|
|
|
|
CvtHex(HA1, a1);
|
|
|
|
|
|
|
|
|
@ -930,7 +934,7 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p
|
|
|
|
|
int i;
|
|
|
|
|
buffer *password, *b, *username_buf, *realm_buf;
|
|
|
|
|
|
|
|
|
|
MD5_CTX Md5Ctx;
|
|
|
|
|
li_MD5_CTX Md5Ctx;
|
|
|
|
|
HASH HA1;
|
|
|
|
|
HASH HA2;
|
|
|
|
|
HASH RespHash;
|
|
|
|
@ -1067,13 +1071,13 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p
|
|
|
|
|
|
|
|
|
|
if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
|
|
|
|
|
/* generate password from plain-text */
|
|
|
|
|
MD5_Init(&Md5Ctx);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)username, strlen(username));
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)realm, strlen(realm));
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)password->ptr, password->used - 1);
|
|
|
|
|
MD5_Final(HA1, &Md5Ctx);
|
|
|
|
|
li_MD5_Init(&Md5Ctx);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)username, strlen(username));
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)realm, strlen(realm));
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)password->ptr, password->used - 1);
|
|
|
|
|
li_MD5_Final(HA1, &Md5Ctx);
|
|
|
|
|
} else if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
|
|
|
|
|
/* HA1 */
|
|
|
|
|
/* transform the 32-byte-hex-md5 to a 16-byte-md5 */
|
|
|
|
@ -1090,45 +1094,45 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p
|
|
|
|
|
|
|
|
|
|
if (algorithm &&
|
|
|
|
|
strcasecmp(algorithm, "md5-sess") == 0) {
|
|
|
|
|
MD5_Init(&Md5Ctx);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)HA1, 16);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce));
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
|
|
|
|
|
MD5_Final(HA1, &Md5Ctx);
|
|
|
|
|
li_MD5_Init(&Md5Ctx);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)HA1, 16);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce));
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
|
|
|
|
|
li_MD5_Final(HA1, &Md5Ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CvtHex(HA1, a1);
|
|
|
|
|
|
|
|
|
|
/* calculate H(A2) */
|
|
|
|
|
MD5_Init(&Md5Ctx);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)uri, strlen(uri));
|
|
|
|
|
li_MD5_Init(&Md5Ctx);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)uri, strlen(uri));
|
|
|
|
|
if (qop && strcasecmp(qop, "auth-int") == 0) {
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)"", HASHHEXLEN);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)"", HASHHEXLEN);
|
|
|
|
|
}
|
|
|
|
|
MD5_Final(HA2, &Md5Ctx);
|
|
|
|
|
li_MD5_Final(HA2, &Md5Ctx);
|
|
|
|
|
CvtHex(HA2, HA2Hex);
|
|
|
|
|
|
|
|
|
|
/* calculate response */
|
|
|
|
|
MD5_Init(&Md5Ctx);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce));
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
li_MD5_Init(&Md5Ctx);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)nonce, strlen(nonce));
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
if (qop && *qop) {
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)nc, strlen(nc));
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)qop, strlen(qop));
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)nc, strlen(nc));
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)qop, strlen(qop));
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
|
|
|
|
|
};
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
|
|
|
|
|
MD5_Final(RespHash, &Md5Ctx);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
|
|
|
|
|
li_MD5_Final(RespHash, &Md5Ctx);
|
|
|
|
|
CvtHex(RespHash, a2);
|
|
|
|
|
|
|
|
|
|
if (0 != strcmp(a2, respons)) {
|
|
|
|
@ -1171,24 +1175,24 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p
|
|
|
|
|
|
|
|
|
|
int http_auth_digest_generate_nonce(server *srv, mod_auth_plugin_data *p, buffer *fn, char out[33]) {
|
|
|
|
|
HASH h;
|
|
|
|
|
MD5_CTX Md5Ctx;
|
|
|
|
|
li_MD5_CTX Md5Ctx;
|
|
|
|
|
char hh[32];
|
|
|
|
|
|
|
|
|
|
UNUSED(p);
|
|
|
|
|
|
|
|
|
|
/* generate shared-secret */
|
|
|
|
|
MD5_Init(&Md5Ctx);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
|
|
|
|
|
li_MD5_Init(&Md5Ctx);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
|
|
|
|
|
|
|
|
|
|
/* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
|
|
|
|
|
LI_ltostr(hh, srv->cur_ts);
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)srv->entropy, sizeof(srv->entropy));
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)srv->entropy, sizeof(srv->entropy));
|
|
|
|
|
LI_ltostr(hh, rand());
|
|
|
|
|
MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
|
|
|
|
|
li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
|
|
|
|
|
|
|
|
|
|
MD5_Final(h, &Md5Ctx);
|
|
|
|
|
li_MD5_Final(h, &Md5Ctx);
|
|
|
|
|
|
|
|
|
|
CvtHex(h, out);
|
|
|
|
|
|
|
|
|
|