1
0
mirror of https://github.com/lammertb/libhttp.git synced 2025-12-22 04:02:04 +03:00

Use 64 bit random number nonce in http digest auth

This commit is contained in:
bel
2015-12-09 23:03:31 +01:00
parent 31c19f74a5
commit f3b5d0f35d

View File

@@ -149,12 +149,12 @@ clock_gettime(int clk_id, struct timespec *t)
return 0; return 0;
} else if (clk_id == CLOCK_MONOTONIC) { } else if (clk_id == CLOCK_MONOTONIC) {
static uint64_t start_time = 0; static uint64_t clock_start_time = 0;
static mach_timebase_info_data_t timebase_ifo = {0, 0}; static mach_timebase_info_data_t timebase_ifo = {0, 0};
uint64_t now = mach_absolute_time(); uint64_t now = mach_absolute_time();
if (start_time == 0) { if (clock_start_time == 0) {
kern_return_t mach_status = mach_timebase_info(&timebase_ifo); kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
#if defined(DEBUG) #if defined(DEBUG)
assert(mach_status == KERN_SUCCESS); assert(mach_status == KERN_SUCCESS);
@@ -162,10 +162,11 @@ clock_gettime(int clk_id, struct timespec *t)
/* appease "unused variable" warning for release builds */ /* appease "unused variable" warning for release builds */
(void)mach_status; (void)mach_status;
#endif #endif
start_time = now; clock_start_time = now;
} }
now = (uint64_t)((double)(now - start_time) * (double)timebase_ifo.numer now = (uint64_t)((double)(now - clock_start_time)
* (double)timebase_ifo.numer
/ (double)timebase_ifo.denom); / (double)timebase_ifo.denom);
t->tv_sec = now / 1000000000; t->tv_sec = now / 1000000000;
@@ -270,6 +271,7 @@ typedef long off_t;
#endif /* !EWOULDBLOCK */ #endif /* !EWOULDBLOCK */
#define _POSIX_ #define _POSIX_
#define INT64_FMT "I64d" #define INT64_FMT "I64d"
#define UINT64_FMT "I64u"
#define WINCDECL __cdecl #define WINCDECL __cdecl
#define SHUT_RD (0) #define SHUT_RD (0)
@@ -426,6 +428,7 @@ typedef unsigned short int in_port_t;
#define ERRNO (errno) #define ERRNO (errno)
#define INVALID_SOCKET (-1) #define INVALID_SOCKET (-1)
#define INT64_FMT PRId64 #define INT64_FMT PRId64
#define UINT64_FMT PRIu64
typedef int SOCKET; typedef int SOCKET;
#define WINCDECL #define WINCDECL
@@ -1160,7 +1163,8 @@ struct mg_context {
cfg_worker_threads; /* The number of configured worker threads. */ cfg_worker_threads; /* The number of configured worker threads. */
pthread_t *workerthreadids; /* The worker thread IDs */ pthread_t *workerthreadids; /* The worker thread IDs */
unsigned long start_time; /* Server start time, used for authentication */ time_t start_time; /* Server start time, used for authentication */
uint64_t auth_nonce_mask; /* Mask for all nonce values */
pthread_mutex_t nonce_mutex; /* Protects nonce_count */ pthread_mutex_t nonce_mutex; /* Protects nonce_count */
unsigned long nonce_count; /* Used nonces, used for authentication */ unsigned long nonce_count; /* Used nonces, used for authentication */
@@ -1556,6 +1560,7 @@ mg_vsnprintf(const struct mg_connection *conn,
buf[n] = '\0'; buf[n] = '\0';
} }
static void static void
mg_snprintf(const struct mg_connection *conn, mg_snprintf(const struct mg_connection *conn,
int *truncated, int *truncated,
@@ -1572,39 +1577,6 @@ mg_snprintf(const struct mg_connection *conn,
} }
static int64_t
get_random(void)
{
static uint64_t lfsr = 0; /* Linear feedback shift register */
static uint64_t lcg = 0; /* Linear congruential generator */
struct timespec now;
memset(&now, 0, sizeof(now));
clock_gettime(CLOCK_MONOTONIC, &now);
if (lfsr == 0) {
/* lfsr will be only 0 if has not been initialized,
* so this code is called only once. */
lfsr = (((uint64_t)now.tv_sec) << 21) ^ ((uint64_t)now.tv_nsec)
^ ((uint64_t)(ptrdiff_t)&now) ^ ((uint64_t)pthread_self())
^ (((uint64_t)time(NULL)) << 33);
lcg = (((uint64_t)now.tv_sec) << 25) + (uint64_t)now.tv_nsec
+ (uint64_t)(ptrdiff_t)&now;
} else {
/* Get the next step of both random number generators. */
lfsr = (lfsr >> 1)
| ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
<< 63);
lcg = lcg * 6364136223846793005 + 1442695040888963407;
}
/* Combining two pseudo-random number generators and a high resolution part
* of the current server time will make it hard (impossible?) to guess the
* next number. */
return (lfsr ^ lcg ^ now.tv_nsec);
}
static int static int
get_option_index(const char *name) get_option_index(const char *name)
{ {
@@ -1618,6 +1590,7 @@ get_option_index(const char *name)
return -1; return -1;
} }
const char * const char *
mg_get_option(const struct mg_context *ctx, const char *name) mg_get_option(const struct mg_context *ctx, const char *name)
{ {
@@ -1631,18 +1604,21 @@ mg_get_option(const struct mg_context *ctx, const char *name)
} }
} }
struct mg_context * struct mg_context *
mg_get_context(const struct mg_connection *conn) mg_get_context(const struct mg_connection *conn)
{ {
return (conn == NULL) ? (struct mg_context *)NULL : (conn->ctx); return (conn == NULL) ? (struct mg_context *)NULL : (conn->ctx);
} }
void * void *
mg_get_user_data(const struct mg_context *ctx) mg_get_user_data(const struct mg_context *ctx)
{ {
return (ctx == NULL) ? NULL : ctx->user_data; return (ctx == NULL) ? NULL : ctx->user_data;
} }
void void
mg_set_user_connection_data(const struct mg_connection *conn, void *data) mg_set_user_connection_data(const struct mg_connection *conn, void *data)
{ {
@@ -1651,6 +1627,7 @@ mg_set_user_connection_data(const struct mg_connection *conn, void *data)
} }
} }
void * void *
mg_get_user_connection_data(const struct mg_connection *conn) mg_get_user_connection_data(const struct mg_connection *conn)
{ {
@@ -1660,6 +1637,7 @@ mg_get_user_connection_data(const struct mg_connection *conn)
return NULL; return NULL;
} }
size_t size_t
mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl) mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
{ {
@@ -1674,6 +1652,7 @@ mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
return i; return i;
} }
int int
mg_get_server_ports(const struct mg_context *ctx, mg_get_server_ports(const struct mg_context *ctx,
int size, int size,
@@ -1712,6 +1691,7 @@ mg_get_server_ports(const struct mg_context *ctx,
return cnt; return cnt;
} }
static void static void
sockaddr_to_string(char *buf, size_t len, const union usa *usa) sockaddr_to_string(char *buf, size_t len, const union usa *usa)
{ {
@@ -1743,6 +1723,7 @@ sockaddr_to_string(char *buf, size_t len, const union usa *usa)
#endif #endif
} }
/* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be /* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be
* included in all responses other than 100, 101, 5xx. */ * included in all responses other than 100, 101, 5xx. */
static void static void
@@ -1759,6 +1740,7 @@ gmt_time_string(char *buf, size_t buf_len, time_t *t)
} }
} }
/* difftime for struct timespec. Return value is in seconds. */ /* difftime for struct timespec. Return value is in seconds. */
static double static double
mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before) mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
@@ -1767,6 +1749,7 @@ mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
+ (double)(ts_now->tv_sec - ts_before->tv_sec); + (double)(ts_now->tv_sec - ts_before->tv_sec);
} }
/* Print error message to the opened error log stream. */ /* Print error message to the opened error log stream. */
void void
mg_cry(const struct mg_connection *conn, const char *fmt, ...) mg_cry(const struct mg_connection *conn, const char *fmt, ...)
@@ -1815,6 +1798,7 @@ mg_cry(const struct mg_connection *conn, const char *fmt, ...)
} }
} }
/* Return fake connection structure. Used for logging, if connection /* Return fake connection structure. Used for logging, if connection
* is not applicable at the moment of logging. */ * is not applicable at the moment of logging. */
static struct mg_connection * static struct mg_connection *
@@ -1825,12 +1809,14 @@ fc(struct mg_context *ctx)
return &fake_connection; return &fake_connection;
} }
const char * const char *
mg_version(void) mg_version(void)
{ {
return CIVETWEB_VERSION; return CIVETWEB_VERSION;
} }
const struct mg_request_info * const struct mg_request_info *
mg_get_request_info(const struct mg_connection *conn) mg_get_request_info(const struct mg_connection *conn)
{ {
@@ -1840,6 +1826,7 @@ mg_get_request_info(const struct mg_connection *conn)
return &conn->request_info; return &conn->request_info;
} }
/* Skip the characters until one of the delimiters characters found. /* Skip the characters until one of the delimiters characters found.
* 0-terminate resulting word. Skip the delimiter and following whitespaces. * 0-terminate resulting word. Skip the delimiter and following whitespaces.
* Advance pointer to buffer to the next word. Return found 0-terminated word. * Advance pointer to buffer to the next word. Return found 0-terminated word.
@@ -1894,6 +1881,7 @@ skip_quoted(char **buf,
return begin_word; return begin_word;
} }
/* Simplified version of skip_quoted without quote char /* Simplified version of skip_quoted without quote char
* and whitespace == delimiters */ * and whitespace == delimiters */
static char * static char *
@@ -1902,6 +1890,7 @@ skip(char **buf, const char *delimiters)
return skip_quoted(buf, delimiters, delimiters, 0); return skip_quoted(buf, delimiters, delimiters, 0);
} }
/* Return HTTP header value, or NULL if not found. */ /* Return HTTP header value, or NULL if not found. */
static const char * static const char *
get_header(const struct mg_request_info *ri, const char *name) get_header(const struct mg_request_info *ri, const char *name)
@@ -1918,6 +1907,7 @@ get_header(const struct mg_request_info *ri, const char *name)
return NULL; return NULL;
} }
const char * const char *
mg_get_header(const struct mg_connection *conn, const char *name) mg_get_header(const struct mg_connection *conn, const char *name)
{ {
@@ -1928,6 +1918,7 @@ mg_get_header(const struct mg_connection *conn, const char *name)
return get_header(&conn->request_info, name); return get_header(&conn->request_info, name);
} }
/* A helper function for traversing a comma separated list of values. /* A helper function for traversing a comma separated list of values.
* It returns a list pointer shifted to the next value, or NULL if the end * It returns a list pointer shifted to the next value, or NULL if the end
* of the list found. * of the list found.
@@ -3355,6 +3346,42 @@ set_non_blocking_mode(SOCKET sock)
return 0; return 0;
} }
#endif /* _WIN32 */ #endif /* _WIN32 */
/* End of initial operating system specific define block. */
/* Get a random number (independent of C rand function) */
static int64_t
get_random(void)
{
static uint64_t lfsr = 0; /* Linear feedback shift register */
static uint64_t lcg = 0; /* Linear congruential generator */
struct timespec now;
memset(&now, 0, sizeof(now));
clock_gettime(CLOCK_MONOTONIC, &now);
if (lfsr == 0) {
/* lfsr will be only 0 if has not been initialized,
* so this code is called only once. */
lfsr = (((uint64_t)now.tv_sec) << 21) ^ ((uint64_t)now.tv_nsec)
^ ((uint64_t)(ptrdiff_t)&now) ^ ((uint64_t)pthread_self())
^ (((uint64_t)time(NULL)) << 33);
lcg = (((uint64_t)now.tv_sec) << 25) + (uint64_t)now.tv_nsec
+ (uint64_t)(ptrdiff_t)&now;
} else {
/* Get the next step of both random number generators. */
lfsr = (lfsr >> 1)
| ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
<< 63);
lcg = lcg * 6364136223846793005 + 1442695040888963407;
}
/* Combining two pseudo-random number generators and a high resolution part
* of the current server time will make it hard (impossible?) to guess the
* next number. */
return (lfsr ^ lcg ^ (uint64_t)now.tv_nsec);
}
/* Write data to the IO channel - opened file descriptor, socket or SSL /* Write data to the IO channel - opened file descriptor, socket or SSL
* descriptor. Return number of bytes written. */ * descriptor. Return number of bytes written. */
@@ -4841,7 +4868,7 @@ parse_auth_header(struct mg_connection *conn,
{ {
char *name, *value, *s; char *name, *value, *s;
const char *auth_header; const char *auth_header;
unsigned long nonce; uint64_t nonce;
if (!ah || !conn) { if (!ah || !conn) {
return 0; return 0;
@@ -4902,13 +4929,13 @@ parse_auth_header(struct mg_connection *conn,
return 0; return 0;
} }
s = NULL; s = NULL;
nonce = strtoul(ah->nonce, &s, 10); nonce = strtoull(ah->nonce, &s, 10);
if ((s == NULL) || (*s != 0)) { if ((s == NULL) || (*s != 0)) {
return 0; return 0;
} }
/* Convert the nonce from the client to a number. */ /* Convert the nonce from the client to a number. */
nonce ^= (uintptr_t)(conn->ctx); nonce ^= conn->ctx->auth_nonce_mask;
/* The converted number corresponds to the time the nounce has been /* The converted number corresponds to the time the nounce has been
* created. This should not be earlier than the server start. */ * created. This should not be earlier than the server start. */
@@ -4918,14 +4945,14 @@ parse_auth_header(struct mg_connection *conn,
/* However, the reasonable default is to not accept a nonce from a /* However, the reasonable default is to not accept a nonce from a
* previous start, so if anyone changed the access rights between * previous start, so if anyone changed the access rights between
* two restarts, a new login is required. */ * two restarts, a new login is required. */
if (nonce < conn->ctx->start_time) { if (nonce < (uint64_t)conn->ctx->start_time) {
/* nonce is from a previous start of the server and no longer valid /* nonce is from a previous start of the server and no longer valid
* (replay attack?) */ * (replay attack?) */
return 0; return 0;
} }
/* Check if the nonce is too high, so it has not (yet) been used by the /* Check if the nonce is too high, so it has not (yet) been used by the
* server. */ * server. */
if (nonce >= conn->ctx->start_time + conn->ctx->nonce_count) { if (nonce >= ((uint64_t)conn->ctx->start_time + conn->ctx->nonce_count)) {
return 0; return 0;
} }
#endif #endif
@@ -5155,14 +5182,14 @@ send_authorization_request(struct mg_connection *conn)
time_t curtime = time(NULL); time_t curtime = time(NULL);
if (conn && conn->ctx) { if (conn && conn->ctx) {
unsigned long nonce = (unsigned long)(conn->ctx->start_time); uint64_t nonce = (uint64_t)(conn->ctx->start_time);
(void)pthread_mutex_lock(&conn->ctx->nonce_mutex); (void)pthread_mutex_lock(&conn->ctx->nonce_mutex);
nonce += conn->ctx->nonce_count; nonce += conn->ctx->nonce_count;
++conn->ctx->nonce_count; ++conn->ctx->nonce_count;
(void)pthread_mutex_unlock(&conn->ctx->nonce_mutex); (void)pthread_mutex_unlock(&conn->ctx->nonce_mutex);
nonce ^= (uintptr_t)(conn->ctx); nonce ^= conn->ctx->auth_nonce_mask;
conn->status_code = 401; conn->status_code = 401;
conn->must_close = 1; conn->must_close = 1;
@@ -5174,7 +5201,7 @@ send_authorization_request(struct mg_connection *conn)
"Connection: %s\r\n" "Connection: %s\r\n"
"Content-Length: 0\r\n" "Content-Length: 0\r\n"
"WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", " "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
"nonce=\"%lu\"\r\n\r\n", "nonce=\"%" UINT64_FMT "\"\r\n\r\n",
date, date,
suggest_connection_header(conn), suggest_connection_header(conn),
conn->ctx->config[AUTHENTICATION_DOMAIN], conn->ctx->config[AUTHENTICATION_DOMAIN],
@@ -11607,7 +11634,7 @@ master_thread_run(void *thread_func_param)
pthread_setspecific(sTlsKey, &tls); pthread_setspecific(sTlsKey, &tls);
/* Server starts *now* */ /* Server starts *now* */
ctx->start_time = (unsigned long)time(NULL); ctx->start_time = time(NULL);
/* Allocate memory for the listening sockets, and start the server */ /* Allocate memory for the listening sockets, and start the server */
pfd = pfd =
@@ -11867,7 +11894,8 @@ mg_start(const struct mg_callbacks *callbacks,
} }
/* Random number generator will initialize at the first call */ /* Random number generator will initialize at the first call */
(void)get_random(); ctx->auth_nonce_mask =
(uint64_t)get_random() ^ (uint64_t)(ptrdiff_t)(options);
if (mg_atomic_inc(&sTlsInit) == 1) { if (mg_atomic_inc(&sTlsInit) == 1) {