mirror of
https://dev.iopsys.eu/bbf/icwmp.git
synced 2025-12-10 07:44:41 +01:00
HTTP auth code cleanup
This commit is contained in:
parent
20e8be761b
commit
00d037ce85
7 changed files with 475 additions and 506 deletions
|
|
@ -11,7 +11,7 @@ icwmpd_SOURCES = \
|
||||||
./config.c \
|
./config.c \
|
||||||
./session.c \
|
./session.c \
|
||||||
./backupSession.c \
|
./backupSession.c \
|
||||||
./digestauth.c \
|
./digauth.c \
|
||||||
./event.c \
|
./event.c \
|
||||||
./http.c \
|
./http.c \
|
||||||
./netlink.c \
|
./netlink.c \
|
||||||
|
|
|
||||||
6
cwmp.c
6
cwmp.c
|
|
@ -31,7 +31,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "backupSession.h"
|
#include "backupSession.h"
|
||||||
#include "ubus_utils.h"
|
#include "ubus_utils.h"
|
||||||
#include "digestauth.h"
|
#include "digauth.h"
|
||||||
#include "upload.h"
|
#include "upload.h"
|
||||||
#include "download.h"
|
#include "download.h"
|
||||||
#include "sched_inform.h"
|
#include "sched_inform.h"
|
||||||
|
|
@ -763,7 +763,7 @@ static int cwmp_init(int argc, char **argv, struct cwmp *cwmp)
|
||||||
load_custom_notify_json(cwmp);
|
load_custom_notify_json(cwmp);
|
||||||
init_list_param_notify();
|
init_list_param_notify();
|
||||||
cwmp_uci_exit();
|
cwmp_uci_exit();
|
||||||
generate_nonce_priv_key();
|
get_nonce_key();
|
||||||
return CWMP_OK;
|
return CWMP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -789,7 +789,7 @@ static void cwmp_free(struct cwmp *cwmp)
|
||||||
FREE(cwmp->conf.forced_inform_json_file);
|
FREE(cwmp->conf.forced_inform_json_file);
|
||||||
FREE(cwmp->conf.custom_notify_json);
|
FREE(cwmp->conf.custom_notify_json);
|
||||||
FREE(cwmp->conf.boot_inform_json_file);
|
FREE(cwmp->conf.boot_inform_json_file);
|
||||||
FREE(nonce_privacy_key);
|
FREE(nonce_key);
|
||||||
clean_list_param_notify();
|
clean_list_param_notify();
|
||||||
bkp_tree_clean();
|
bkp_tree_clean();
|
||||||
|
|
||||||
|
|
|
||||||
451
digauth.c
Normal file
451
digauth.c
Normal file
|
|
@ -0,0 +1,451 @@
|
||||||
|
/*
|
||||||
|
* digauth.c - HTTP digest authentication utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022, IOPSYS Software Solutions AB.
|
||||||
|
*
|
||||||
|
* Author: suvendhu.hansa@iopsys.eu
|
||||||
|
*
|
||||||
|
* See LICENSE file for license related information.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "digauth.h"
|
||||||
|
#include "ssl_utils.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#ifdef LMBEDTLS
|
||||||
|
#include <mbedtls/md5.h>
|
||||||
|
#define MD5_CTX mbedtls_md5_context
|
||||||
|
#define MD5_INIT(X) { mbedtls_md5_init(X); mbedtls_md5_starts_ret(X); }
|
||||||
|
#define MD5_UPDATE(X, Y, Z) mbedtls_md5_update_ret(X, (unsigned char *)Y, Z)
|
||||||
|
#define MD5_FINAL(X, Y) mbedtls_md5_finish_ret(Y, X)
|
||||||
|
#else
|
||||||
|
#include <openssl/md5.h>
|
||||||
|
#define MD5_CTX MD5_CTX
|
||||||
|
#define MD5_INIT MD5_Init
|
||||||
|
#define MD5_UPDATE MD5_Update
|
||||||
|
#define MD5_FINAL MD5_Final
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MD5_DIGEST_SIZE
|
||||||
|
#define MD5_DIGEST_SIZE 16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MD5_HASH_HEX_LEN (2 * MD5_DIGEST_SIZE)
|
||||||
|
|
||||||
|
char *nonce_key = NULL;
|
||||||
|
|
||||||
|
struct parameters {
|
||||||
|
char *key;
|
||||||
|
char value[2049];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum param_index {
|
||||||
|
E_USERNAME,
|
||||||
|
E_REALM,
|
||||||
|
E_NONCE,
|
||||||
|
E_URI,
|
||||||
|
E_QOP,
|
||||||
|
E_NC,
|
||||||
|
E_CNONCE,
|
||||||
|
E_RESPONSE,
|
||||||
|
__E_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct parameters param[__E_MAX] = {
|
||||||
|
{ "username", {'\0'} },
|
||||||
|
{ "realm", {'\0'} },
|
||||||
|
{ "nonce", {'\0'} },
|
||||||
|
{ "uri", {'\0'} },
|
||||||
|
{ "qop", {'\0'} },
|
||||||
|
{ "nc", {'\0'} },
|
||||||
|
{ "cnonce", {'\0'} },
|
||||||
|
{ "response", {'\0'} }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void clear_param_values(void)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < (sizeof(param)/sizeof(param[0])); i++) {
|
||||||
|
memset(param[i].value, 0, sizeof(param[i].value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_param_index(char *key)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < (sizeof(param)/sizeof(param[0])); i++) {
|
||||||
|
if (strncmp(key, param[i].key, strlen(param[i].key)) == 0)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void strip_lead_trail_char(char *str, char ch)
|
||||||
|
{
|
||||||
|
/* First remove leading strip-char */
|
||||||
|
const char* first_valid = str;
|
||||||
|
|
||||||
|
while(*first_valid != '\0' && *first_valid == ch) {
|
||||||
|
++first_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = strlen(first_valid) + 1;
|
||||||
|
|
||||||
|
memmove(str, first_valid, len);
|
||||||
|
|
||||||
|
/* Now remove trailing strip-char */
|
||||||
|
char* end_str = str + strlen(str) - 1;
|
||||||
|
|
||||||
|
while(str < end_str && *end_str == ch) {
|
||||||
|
*end_str = '\0';
|
||||||
|
--end_str ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_hexstring(unsigned char *hash, int len, char *hexstr, int buflen)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
if (hash == NULL || hexstr == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (buflen <= len * 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset(hexstr, 0, buflen);
|
||||||
|
|
||||||
|
for (i = 0, j = 0; i < len; i++) {
|
||||||
|
sprintf(hexstr + j, "%02X", hash[i]);
|
||||||
|
j = j + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_value_from_header(const char *data)
|
||||||
|
{
|
||||||
|
if (data == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int header_len = strlen(data) + 1;
|
||||||
|
char header[header_len];
|
||||||
|
memset(header, 0, header_len);
|
||||||
|
strncpy(header, data, header_len);
|
||||||
|
|
||||||
|
clear_param_values();
|
||||||
|
|
||||||
|
char *start = strtok(header, ",");
|
||||||
|
while (start) {
|
||||||
|
char *eq = strchr(start, '=');
|
||||||
|
if (eq == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int len = eq - start + 1;
|
||||||
|
char key[len];
|
||||||
|
snprintf(key, len, "%s", start);
|
||||||
|
strip_lead_trail_char(key, ' ');
|
||||||
|
strip_lead_trail_char(key, '\"');
|
||||||
|
|
||||||
|
eq = eq + 1;
|
||||||
|
char *end = eq + strlen(eq) - 1;
|
||||||
|
len = end - eq + 2;
|
||||||
|
char val[len];
|
||||||
|
snprintf(val, len, "%s", eq);
|
||||||
|
strip_lead_trail_char(val, ' ');
|
||||||
|
strip_lead_trail_char(val, '\"');
|
||||||
|
|
||||||
|
int ind = get_param_index(key);
|
||||||
|
if (ind >= 0) {
|
||||||
|
snprintf(param[ind].value, sizeof(param[ind].value), "%s", val);
|
||||||
|
}
|
||||||
|
|
||||||
|
start = strtok(NULL, ",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_digest_ha1(const char *algo, const char *uname, const char *rlm,
|
||||||
|
const char *psw, const char *nonce, const char *cnonce,
|
||||||
|
char *skey, int skey_len)
|
||||||
|
{
|
||||||
|
unsigned char digest[MD5_DIGEST_SIZE];
|
||||||
|
MD5_CTX context;
|
||||||
|
|
||||||
|
if (algo == NULL || uname == NULL || rlm == NULL ||
|
||||||
|
psw == NULL || nonce == NULL || cnonce == NULL || skey == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int len = strlen(uname) + strlen(rlm) + strlen(psw) + 3;
|
||||||
|
char *a = (char *)calloc(sizeof(char), len);
|
||||||
|
if (a == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
snprintf(a, len, "%s:%s:%s", uname, rlm, psw);
|
||||||
|
|
||||||
|
MD5_INIT(&context);
|
||||||
|
MD5_UPDATE(&context, a, strlen(a));
|
||||||
|
MD5_FINAL(digest, &context);
|
||||||
|
|
||||||
|
free(a);
|
||||||
|
a = NULL;
|
||||||
|
|
||||||
|
if (0 == strcasecmp(algo, "md5-sess")) {
|
||||||
|
len = strlen(nonce) + strlen(cnonce) + 3;
|
||||||
|
a = (char *)calloc(sizeof(char), len);
|
||||||
|
if (a == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
snprintf(a, len, ":%s:%s", nonce, cnonce);
|
||||||
|
|
||||||
|
MD5_INIT(&context);
|
||||||
|
MD5_UPDATE(&context, digest, sizeof(digest));
|
||||||
|
MD5_UPDATE(&context, a, strlen(a));
|
||||||
|
MD5_FINAL(digest, &context);
|
||||||
|
|
||||||
|
free(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
get_hexstring(digest, sizeof(digest), skey, skey_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_digest_ha2(const char *method, const char *uri, char *ha2, int ha2_len)
|
||||||
|
{
|
||||||
|
unsigned char digest[MD5_DIGEST_SIZE];
|
||||||
|
MD5_CTX context;
|
||||||
|
|
||||||
|
if (method == NULL || uri == NULL || ha2 == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int len = strlen(method) + strlen(uri) + 2;
|
||||||
|
char *a = (char *)calloc(sizeof(char), len);
|
||||||
|
if (a == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
snprintf(a, len, "%s:%s", method, uri);
|
||||||
|
|
||||||
|
MD5_INIT(&context);
|
||||||
|
MD5_UPDATE(&context, a, strlen(a));
|
||||||
|
MD5_FINAL(digest, &context);
|
||||||
|
|
||||||
|
free(a);
|
||||||
|
|
||||||
|
get_hexstring(digest, sizeof(digest), ha2, ha2_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_digest_response(const char *ha1, const char *nonce, const char *nonce_cnt,
|
||||||
|
const char *cnonce, const char *qop, const char *ha2,
|
||||||
|
char *resp, int resp_len)
|
||||||
|
{
|
||||||
|
MD5_CTX context;
|
||||||
|
unsigned char digest[MD5_DIGEST_SIZE];
|
||||||
|
|
||||||
|
if (ha1 == NULL || nonce == NULL || nonce_cnt == NULL || cnonce == NULL ||
|
||||||
|
qop == NULL || ha2 == NULL || resp == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int len = strlen(nonce) + 3;
|
||||||
|
char *a = (char *)calloc(sizeof(char), len);
|
||||||
|
if (a == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
snprintf(a, len, ":%s:", nonce);
|
||||||
|
|
||||||
|
if (qop[0] != '\0') {
|
||||||
|
len = len + strlen(nonce_cnt) + strlen(cnonce) + strlen(qop) + 3;
|
||||||
|
char *b = (char *)calloc(sizeof(char), len);
|
||||||
|
if (b == NULL) {
|
||||||
|
free(a);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(b, len, "%s%s:%s:%s:", a, nonce_cnt, cnonce, qop);
|
||||||
|
|
||||||
|
free(a);
|
||||||
|
a = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
MD5_INIT(&context);
|
||||||
|
MD5_UPDATE(&context, ha1, MD5_HASH_HEX_LEN);
|
||||||
|
MD5_UPDATE(&context, a, strlen(a));
|
||||||
|
MD5_UPDATE(&context, ha2, MD5_HASH_HEX_LEN);
|
||||||
|
MD5_FINAL(digest, &context);
|
||||||
|
|
||||||
|
free(a);
|
||||||
|
get_hexstring(digest, sizeof(digest), resp, resp_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_nonce(uint32_t time, const char* method, const char *rand,
|
||||||
|
unsigned int rand_size, const char *uri, const char *rlm,
|
||||||
|
char *nonce, unsigned int nonce_size)
|
||||||
|
{
|
||||||
|
unsigned char ts[4];
|
||||||
|
|
||||||
|
if (method == NULL || uri == NULL || rlm == NULL || nonce == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 3; i >= 0; i--) {
|
||||||
|
ts[i] = (time >> (8 * (3 - i))) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
char tshex[sizeof(ts) * 2 + 1];
|
||||||
|
get_hexstring(ts, sizeof(ts), tshex, sizeof(tshex));
|
||||||
|
|
||||||
|
unsigned int len = strlen(method) + 3;
|
||||||
|
char *meth = (char *)calloc(sizeof(char), len);
|
||||||
|
if (meth == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
snprintf(meth, len, ":%s:", method);
|
||||||
|
|
||||||
|
len = strlen(uri) + strlen(rlm) + 3;
|
||||||
|
char *uri_realm = (char *)calloc(sizeof(char), len);
|
||||||
|
if (uri_realm == NULL) {
|
||||||
|
free(meth);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(uri_realm, len, ":%s:%s", uri, rlm);
|
||||||
|
|
||||||
|
MD5_CTX context;
|
||||||
|
unsigned char digest[MD5_DIGEST_SIZE];
|
||||||
|
|
||||||
|
MD5_INIT(&context);
|
||||||
|
MD5_UPDATE(&context, ts, 4);
|
||||||
|
MD5_UPDATE(&context, meth, strlen(meth));
|
||||||
|
if (rand != NULL && rand_size > 0)
|
||||||
|
MD5_UPDATE(&context, rand, rand_size);
|
||||||
|
MD5_UPDATE(&context, uri_realm, strlen(uri_realm));
|
||||||
|
MD5_FINAL(digest, &context);
|
||||||
|
|
||||||
|
free(meth);
|
||||||
|
free(uri_realm);
|
||||||
|
memset(nonce, 0, nonce_size);
|
||||||
|
get_hexstring(digest, sizeof(digest), nonce, nonce_size);
|
||||||
|
len = nonce_size - strlen(nonce) - 1;
|
||||||
|
strncat(nonce, tshex, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int http_authentication_failure_resp(FILE *fp, const char *http_meth, const char *uri,
|
||||||
|
const char *rlm, const char *opq)
|
||||||
|
{
|
||||||
|
if (fp == NULL || http_meth == NULL || uri == NULL || rlm == NULL || opq == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int len;
|
||||||
|
char nonce[MD5_HASH_HEX_LEN + 9];
|
||||||
|
uint32_t tm;
|
||||||
|
|
||||||
|
tm = (uint32_t)time(NULL);
|
||||||
|
|
||||||
|
len = nonce_key ? strlen(nonce_key) : 0;
|
||||||
|
get_nonce(tm, http_meth, nonce_key, len, uri, rlm, nonce, sizeof(nonce));
|
||||||
|
|
||||||
|
if (fprintf(fp, "WWW-Authenticate: Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"", rlm, nonce, opq) < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int validate_http_digest_auth(const char *http_meth, const char *uri, const char *hdr,
|
||||||
|
const char *rlm, const char *usr, const char *psw,
|
||||||
|
unsigned int timeout)
|
||||||
|
{
|
||||||
|
get_value_from_header(hdr);
|
||||||
|
|
||||||
|
if (strcmp(param[E_USERNAME].value, usr) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (strlen(param[E_REALM].value) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (strcmp(param[E_REALM].value, rlm) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (strlen(param[E_CNONCE].value) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (strlen(param[E_QOP].value) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (strlen(param[E_NC].value) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (strlen(param[E_RESPONSE].value) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int len = strlen(param[E_NONCE].value);
|
||||||
|
if (len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
char *tms = param[E_NONCE].value + len - 8;
|
||||||
|
uint32_t tm = strtoul(tms, NULL, 16);
|
||||||
|
uint32_t cur_tm = (uint32_t)time(NULL);
|
||||||
|
|
||||||
|
if (cur_tm > tm + timeout) {
|
||||||
|
CWMP_LOG(ERROR, "Time exceeded the timeout");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nonce_key ==NULL) {
|
||||||
|
if (get_nonce_key() != CWMP_OK)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char nonce[MD5_HASH_HEX_LEN + 9];
|
||||||
|
get_nonce(tm, http_meth, nonce_key, strlen(nonce_key), uri, rlm, nonce, sizeof(nonce));
|
||||||
|
|
||||||
|
if (strcmp(param[E_NONCE].value, nonce) != 0) {
|
||||||
|
CWMP_LOG(ERROR, "Nonce value is probably fabricated");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(param[E_URI].value) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (strncmp(param[E_URI].value, uri, strlen(uri)) != 0) {
|
||||||
|
CWMP_LOG(ERROR, "Authentication failed, URI is not matched");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((strcmp(param[E_QOP].value, "auth") != 0) && (strcmp(param[E_QOP].value, "") != 0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
char *tmp;
|
||||||
|
unsigned long int nc_int = strtoul(param[E_NC].value, &tmp, 16);
|
||||||
|
if ((*tmp != '\0') || (nc_int == LONG_MAX && errno == ERANGE)) {
|
||||||
|
CWMP_LOG(ERROR, "Authentication failed due to invalid format");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char ha1[MD5_HASH_HEX_LEN + 1];
|
||||||
|
char ha2[MD5_HASH_HEX_LEN + 1];
|
||||||
|
char resp[MD5_HASH_HEX_LEN + 1];
|
||||||
|
|
||||||
|
get_digest_ha1("md5", usr, rlm, psw, param[E_NONCE].value, param[E_CNONCE].value, ha1, sizeof(ha1));
|
||||||
|
get_digest_ha2(http_meth, uri, ha2, sizeof(ha2));
|
||||||
|
get_digest_response(ha1, param[E_NONCE].value, param[E_NC].value, param[E_CNONCE].value,
|
||||||
|
param[E_QOP].value, ha2, resp, sizeof(resp));
|
||||||
|
|
||||||
|
if (strcmp(resp, param[E_RESPONSE].value) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_nonce_key(void)
|
||||||
|
{
|
||||||
|
nonce_key = generate_random_string(28);
|
||||||
|
if (nonce_key == NULL)
|
||||||
|
return CWMP_GEN_ERR;
|
||||||
|
|
||||||
|
return CWMP_OK;
|
||||||
|
}
|
||||||
437
digestauth.c
437
digestauth.c
|
|
@ -1,437 +0,0 @@
|
||||||
/*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
* HTTP digest auth functions: originally imported from libmicrohttpd
|
|
||||||
*
|
|
||||||
* Copyright (C) 2013 Oussama Ghorbel <oussama.ghorbel@pivasoftware.com>
|
|
||||||
* Omar Kallel <omar.kallel@pivasoftware.com>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef LMBEDTLS
|
|
||||||
#include <mbedtls/md5.h>
|
|
||||||
#define MD5_CTX mbedtls_md5_context
|
|
||||||
#define MD5_INIT(X) { mbedtls_md5_init(X); mbedtls_md5_starts_ret(X); }
|
|
||||||
#define MD5_UPDATE(X, Y, Z) mbedtls_md5_update_ret(X, (unsigned char *)Y, Z)
|
|
||||||
#define MD5_FINAL(X, Y) mbedtls_md5_finish_ret(Y, X)
|
|
||||||
#else
|
|
||||||
#include <openssl/md5.h>
|
|
||||||
#define MD5_CTX MD5_CTX
|
|
||||||
#define MD5_INIT MD5_Init
|
|
||||||
#define MD5_UPDATE MD5_Update
|
|
||||||
#define MD5_FINAL MD5_Final
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "log.h"
|
|
||||||
#include "common.h"
|
|
||||||
#include "digestauth.h"
|
|
||||||
#include "ssl_utils.h"
|
|
||||||
|
|
||||||
#ifndef MD5_DIGEST_SIZE
|
|
||||||
#define MD5_DIGEST_SIZE 16
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define HASH_MD5_HEX_LEN (2 * MD5_DIGEST_SIZE)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum length of a username for digest authentication.
|
|
||||||
*/
|
|
||||||
#define MAX_USERNAME_LENGTH 1024
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum length of a realm for digest authentication.
|
|
||||||
*/
|
|
||||||
#define MAX_REALM_LENGTH 1024
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum length of the response in digest authentication.
|
|
||||||
*/
|
|
||||||
#define MAX_AUTH_RESPONSE_LENGTH 1024
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum length of the nonce in digest authentication.
|
|
||||||
*/
|
|
||||||
#define MAX_NONCE_LENGTH 1024
|
|
||||||
|
|
||||||
char *nonce_privacy_key = NULL;
|
|
||||||
|
|
||||||
int generate_nonce_priv_key(void)
|
|
||||||
{
|
|
||||||
nonce_privacy_key = generate_random_string(28);
|
|
||||||
if (nonce_privacy_key == NULL)
|
|
||||||
return CWMP_GEN_ERR;
|
|
||||||
return CWMP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static time_t mhd_monotonic_time(void)
|
|
||||||
{
|
|
||||||
struct timespec ts;
|
|
||||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
|
|
||||||
return ts.tv_sec;
|
|
||||||
return time(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* convert bin to hex
|
|
||||||
*
|
|
||||||
* @param bin binary data
|
|
||||||
* @param len number of bytes in bin
|
|
||||||
* @param hex pointer to len*2+1 bytes
|
|
||||||
*/
|
|
||||||
static void cvthex(const unsigned char *bin, size_t len, char *hex)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < len; ++i) {
|
|
||||||
unsigned int j;
|
|
||||||
j = (bin[i] >> 4) & 0x0f;
|
|
||||||
hex[i * 2] = j <= 9 ? (j + '0') : (j + 'a' - 10);
|
|
||||||
j = bin[i] & 0x0f;
|
|
||||||
hex[i * 2 + 1] = j <= 9 ? (j + '0') : (j + 'a' - 10);
|
|
||||||
}
|
|
||||||
hex[len * 2] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the server nonce so that it mitigates replay attacks
|
|
||||||
* The current format of the nonce is ...
|
|
||||||
* H(timestamp ":" method ":" random ":" uri ":" realm) + Hex(timestamp)
|
|
||||||
*
|
|
||||||
* @param nonce_time The amount of time in seconds for a nonce to be invalid
|
|
||||||
* @param method HTTP method
|
|
||||||
* @param rnd A pointer to a character array for the random seed
|
|
||||||
* @param rnd_size The size of the random seed array
|
|
||||||
* @param uri HTTP URI (in MHD, without the arguments ("?k=v")
|
|
||||||
* @param realm A string of characters that describes the realm of auth.
|
|
||||||
* @param nonce A pointer to a character array for the nonce to put in
|
|
||||||
*/
|
|
||||||
static void calculate_nonce(uint32_t nonce_time, const char *method, const char *rnd, unsigned int rnd_size, const char *uri, const char *realm, char *nonce, size_t size)
|
|
||||||
{
|
|
||||||
MD5_CTX md5;
|
|
||||||
unsigned char timestamp[4];
|
|
||||||
unsigned char tmpnonce[MD5_DIGEST_SIZE];
|
|
||||||
char timestamphex[sizeof(timestamp) * 2 + 1];
|
|
||||||
|
|
||||||
if (nonce == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
memset(nonce, 0, size);
|
|
||||||
|
|
||||||
MD5_INIT(&md5);
|
|
||||||
timestamp[0] = (nonce_time & 0xff000000) >> 0x18;
|
|
||||||
timestamp[1] = (nonce_time & 0x00ff0000) >> 0x10;
|
|
||||||
timestamp[2] = (nonce_time & 0x0000ff00) >> 0x08;
|
|
||||||
timestamp[3] = (nonce_time & 0x000000ff);
|
|
||||||
MD5_UPDATE(&md5, timestamp, 4);
|
|
||||||
MD5_UPDATE(&md5, ":", 1);
|
|
||||||
MD5_UPDATE(&md5, method, strlen(method));
|
|
||||||
MD5_UPDATE(&md5, ":", 1);
|
|
||||||
if (rnd_size > 0)
|
|
||||||
MD5_UPDATE(&md5, rnd, rnd_size);
|
|
||||||
MD5_UPDATE(&md5, ":", 1);
|
|
||||||
MD5_UPDATE(&md5, uri, strlen(uri));
|
|
||||||
MD5_UPDATE(&md5, ":", 1);
|
|
||||||
MD5_UPDATE(&md5, realm, strlen(realm));
|
|
||||||
MD5_FINAL(tmpnonce, &md5);
|
|
||||||
cvthex(tmpnonce, sizeof(tmpnonce), nonce);
|
|
||||||
cvthex(timestamp, 4, timestamphex);
|
|
||||||
size_t len = size - strlen(nonce) - 1;
|
|
||||||
strncat(nonce, timestamphex, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lookup subvalue off of the HTTP Authorization header.
|
|
||||||
*
|
|
||||||
* A description of the input format for 'data' is at
|
|
||||||
* http://en.wikipedia.org/wiki/Digest_access_authentication
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param dest where to store the result (possibly truncated if
|
|
||||||
* the buffer is not big enough).
|
|
||||||
* @param size size of dest
|
|
||||||
* @param data pointer to the Authorization header
|
|
||||||
* @param key key to look up in data
|
|
||||||
* @return size of the located value, 0 if otherwise
|
|
||||||
*/
|
|
||||||
static int lookup_sub_value(char *dest, size_t size, const char *data, const char *key)
|
|
||||||
{
|
|
||||||
size_t keylen;
|
|
||||||
size_t len;
|
|
||||||
const char *ptr;
|
|
||||||
const char *eq;
|
|
||||||
const char *q2;
|
|
||||||
const char *qn;
|
|
||||||
|
|
||||||
unsigned int diff;
|
|
||||||
if (0 == size)
|
|
||||||
return 0;
|
|
||||||
keylen = strlen(key);
|
|
||||||
ptr = data;
|
|
||||||
while ('\0' != *ptr) {
|
|
||||||
const char *q1;
|
|
||||||
if (NULL == (eq = strchr(ptr, '=')))
|
|
||||||
return 0;
|
|
||||||
q1 = eq + 1;
|
|
||||||
while (' ' == *q1)
|
|
||||||
q1++;
|
|
||||||
if ('\"' != *q1) {
|
|
||||||
q2 = strchr(q1, ',');
|
|
||||||
qn = q2;
|
|
||||||
} else {
|
|
||||||
q1++;
|
|
||||||
q2 = strchr(q1, '\"');
|
|
||||||
if (NULL == q2)
|
|
||||||
return 0; /* end quote not found */
|
|
||||||
qn = q2 + 1;
|
|
||||||
}
|
|
||||||
if ((0 == strncasecmp(ptr, key, keylen)) && (eq == &ptr[keylen])) {
|
|
||||||
if (NULL == q2) {
|
|
||||||
len = strlen(q1);
|
|
||||||
snprintf(dest, size, "%s", q1);
|
|
||||||
return len;
|
|
||||||
} else {
|
|
||||||
diff = (q2 - q1) + 1;
|
|
||||||
if (size > diff)
|
|
||||||
size = diff;
|
|
||||||
snprintf(dest, size, "%s", q1);
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (NULL == qn)
|
|
||||||
return 0;
|
|
||||||
ptr = strchr(qn, ',');
|
|
||||||
if (NULL == ptr)
|
|
||||||
return 0;
|
|
||||||
ptr++;
|
|
||||||
while (' ' == *ptr)
|
|
||||||
ptr++;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* calculate H(A1) as per RFC2617 spec and store the
|
|
||||||
* result in 'sessionkey'.
|
|
||||||
*
|
|
||||||
* @param alg The hash algorithm used, can be "md5" or "md5-sess"
|
|
||||||
* @param username A `char *' pointer to the username value
|
|
||||||
* @param realm A `char *' pointer to the realm value
|
|
||||||
* @param password A `char *' pointer to the password value
|
|
||||||
* @param nonce A `char *' pointer to the nonce value
|
|
||||||
* @param cnonce A `char *' pointer to the cnonce value
|
|
||||||
* @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes
|
|
||||||
*/
|
|
||||||
static void digest_calc_ha1(const char *alg, const char *username, const char *realm, const char *password, const char *nonce, const char *cnonce, char *sessionkey)
|
|
||||||
{
|
|
||||||
MD5_CTX md5;
|
|
||||||
unsigned char ha1[MD5_DIGEST_SIZE];
|
|
||||||
|
|
||||||
MD5_INIT(&md5);
|
|
||||||
MD5_UPDATE(&md5, username, strlen(username));
|
|
||||||
MD5_UPDATE(&md5, ":", 1);
|
|
||||||
MD5_UPDATE(&md5, realm, strlen(realm));
|
|
||||||
MD5_UPDATE(&md5, ":", 1);
|
|
||||||
MD5_UPDATE(&md5, password, strlen(password));
|
|
||||||
MD5_FINAL(ha1, &md5);
|
|
||||||
if (0 == strcasecmp(alg, "md5-sess")) {
|
|
||||||
MD5_INIT(&md5);
|
|
||||||
MD5_UPDATE(&md5, ha1, sizeof(ha1));
|
|
||||||
MD5_UPDATE(&md5, ":", 1);
|
|
||||||
MD5_UPDATE(&md5, nonce, strlen(nonce));
|
|
||||||
MD5_UPDATE(&md5, ":", 1);
|
|
||||||
MD5_UPDATE(&md5, cnonce, strlen(cnonce));
|
|
||||||
MD5_FINAL(ha1, &md5);
|
|
||||||
}
|
|
||||||
cvthex(ha1, sizeof(ha1), sessionkey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate request-digest/response-digest as per RFC2617 spec
|
|
||||||
*
|
|
||||||
* @param ha1 H(A1)
|
|
||||||
* @param nonce nonce from server
|
|
||||||
* @param noncecount 8 hex digits
|
|
||||||
* @param cnonce client nonce
|
|
||||||
* @param qop qop-value: "", "auth" or "auth-int"
|
|
||||||
* @param method method from request
|
|
||||||
* @param uri requested URL
|
|
||||||
* @param hentity H(entity body) if qop="auth-int"
|
|
||||||
* @param response request-digest or response-digest
|
|
||||||
*/
|
|
||||||
static void digest_calc_response(const char *ha1, const char *nonce, const char *noncecount, const char *cnonce, const char *qop, const char *method, const char *uri, char *response)
|
|
||||||
{
|
|
||||||
MD5_CTX md5;
|
|
||||||
unsigned char ha2[MD5_DIGEST_SIZE];
|
|
||||||
unsigned char resphash[MD5_DIGEST_SIZE];
|
|
||||||
char ha2hex[HASH_MD5_HEX_LEN + 1];
|
|
||||||
|
|
||||||
MD5_INIT(&md5);
|
|
||||||
MD5_UPDATE(&md5, method, strlen(method));
|
|
||||||
MD5_UPDATE(&md5, ":", 1);
|
|
||||||
MD5_UPDATE(&md5, uri, strlen(uri));
|
|
||||||
MD5_FINAL(ha2, &md5);
|
|
||||||
cvthex(ha2, MD5_DIGEST_SIZE, ha2hex);
|
|
||||||
MD5_INIT(&md5);
|
|
||||||
/* calculate response */
|
|
||||||
MD5_UPDATE(&md5, ha1, HASH_MD5_HEX_LEN);
|
|
||||||
MD5_UPDATE(&md5, ":", 1);
|
|
||||||
MD5_UPDATE(&md5, nonce, strlen(nonce));
|
|
||||||
MD5_UPDATE(&md5, ":", 1);
|
|
||||||
if ('\0' != *qop) {
|
|
||||||
MD5_UPDATE(&md5, noncecount, strlen(noncecount));
|
|
||||||
MD5_UPDATE(&md5, ":", 1);
|
|
||||||
MD5_UPDATE(&md5, cnonce, strlen(cnonce));
|
|
||||||
MD5_UPDATE(&md5, ":", 1);
|
|
||||||
MD5_UPDATE(&md5, qop, strlen(qop));
|
|
||||||
MD5_UPDATE(&md5, ":", 1);
|
|
||||||
}
|
|
||||||
MD5_UPDATE(&md5, ha2hex, HASH_MD5_HEX_LEN);
|
|
||||||
MD5_FINAL(resphash, &md5);
|
|
||||||
cvthex(resphash, sizeof(resphash), response);
|
|
||||||
}
|
|
||||||
|
|
||||||
int http_digest_auth_fail_response(FILE *fp, const char *http_method, const char *url, const char *realm, const char *opaque)
|
|
||||||
{
|
|
||||||
size_t hlen, nonce_key_len = 0;
|
|
||||||
char nonce[HASH_MD5_HEX_LEN + 9];
|
|
||||||
|
|
||||||
/* Generating the server nonce */
|
|
||||||
nonce_key_len = nonce_privacy_key ? strlen(nonce_privacy_key) : 0;
|
|
||||||
calculate_nonce((uint32_t)mhd_monotonic_time(), http_method, nonce_privacy_key, nonce_key_len, url, realm, nonce, sizeof(nonce));
|
|
||||||
|
|
||||||
/* Building the authentication header */
|
|
||||||
hlen = snprintf(NULL, 0, "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"", realm, nonce, opaque);
|
|
||||||
{
|
|
||||||
char header[hlen + 1];
|
|
||||||
|
|
||||||
snprintf(header, sizeof(header), "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"", realm, nonce, opaque);
|
|
||||||
|
|
||||||
fputs("WWW-Authenticate: ", fp);
|
|
||||||
fputs(header, fp);
|
|
||||||
return MHD_YES;
|
|
||||||
}
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
int http_digest_auth_check(const char *http_method, const char *url, const char *header, const char *realm, const char *username, const char *password, unsigned int nonce_timeout)
|
|
||||||
{
|
|
||||||
size_t len;
|
|
||||||
char *end;
|
|
||||||
char nonce[MAX_NONCE_LENGTH];
|
|
||||||
size_t left; /* number of characters left in 'header' for 'uri' */
|
|
||||||
|
|
||||||
left = strlen(header);
|
|
||||||
|
|
||||||
{
|
|
||||||
char un[MAX_USERNAME_LENGTH];
|
|
||||||
|
|
||||||
len = lookup_sub_value(un, sizeof(un), header, "username");
|
|
||||||
if (0 != strcmp(username, un))
|
|
||||||
return MHD_NO;
|
|
||||||
left -= strlen("username") + len;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
char r[MAX_REALM_LENGTH];
|
|
||||||
|
|
||||||
len = lookup_sub_value(r, sizeof(r), header, "realm");
|
|
||||||
if ((0 == len) || (0 != strcmp(realm, r)))
|
|
||||||
return MHD_NO;
|
|
||||||
left -= strlen("realm") + len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 == (len = lookup_sub_value(nonce, sizeof(nonce), header, "nonce")))
|
|
||||||
return MHD_NO;
|
|
||||||
left -= strlen("nonce") + len;
|
|
||||||
|
|
||||||
{
|
|
||||||
char uri[left];
|
|
||||||
char cnonce[MAX_NONCE_LENGTH];
|
|
||||||
char qop[15]; /* auth,auth-int */
|
|
||||||
char nc[20];
|
|
||||||
char response[MAX_AUTH_RESPONSE_LENGTH];
|
|
||||||
char ha1[HASH_MD5_HEX_LEN + 1];
|
|
||||||
char respexp[HASH_MD5_HEX_LEN + 1];
|
|
||||||
char noncehashexp[HASH_MD5_HEX_LEN + 9];
|
|
||||||
uint32_t nonce_time;
|
|
||||||
unsigned long int nci;
|
|
||||||
uint32_t t;
|
|
||||||
size_t nonce_key_len = 0;
|
|
||||||
|
|
||||||
|
|
||||||
if (0 == lookup_sub_value(uri, sizeof(uri), header, "uri"))
|
|
||||||
return MHD_NO;
|
|
||||||
|
|
||||||
/* 8 = 4 hexadecimal numbers for the timestamp */
|
|
||||||
nonce_time = strtoul(nonce + len - 8, (char **)NULL, 16);
|
|
||||||
t = (uint32_t)mhd_monotonic_time();
|
|
||||||
/*
|
|
||||||
* First level vetting for the nonce validity if the timestamp
|
|
||||||
* attached to the nonce exceeds `nonce_timeout' then the nonce is
|
|
||||||
* invalid.
|
|
||||||
*/
|
|
||||||
if ((t > nonce_time + nonce_timeout) || (nonce_time + nonce_timeout < nonce_time)) {
|
|
||||||
CWMP_LOG(ERROR, "Timestamp attached to the nonce exceeds");
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 != strncmp(uri, url, strlen(url))) {
|
|
||||||
CWMP_LOG(ERROR, "Authentication failed: URI does not match.");
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nonce_privacy_key == NULL) {
|
|
||||||
if (generate_nonce_priv_key() != CWMP_OK)
|
|
||||||
return MHD_INVALID_NONCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nonce_key_len = strlen(nonce_privacy_key);
|
|
||||||
calculate_nonce(nonce_time, http_method, nonce_privacy_key, nonce_key_len, url, realm, noncehashexp, sizeof(noncehashexp));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Second level vetting for the nonce validity
|
|
||||||
* if the timestamp attached to the nonce is valid
|
|
||||||
* and possibly fabricated (in case of an attack)
|
|
||||||
* the attacker must also know the random seed to be
|
|
||||||
* able to generate a "sane" nonce, which if he does
|
|
||||||
* not, the nonce fabrication process going to be
|
|
||||||
* very hard to achieve.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (0 != strcmp(nonce, noncehashexp)) {
|
|
||||||
CWMP_LOG(ERROR, "Nonce value is valid and possibly fabricated");
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((0 == lookup_sub_value(cnonce, sizeof(cnonce), header, "cnonce")) || (0 == lookup_sub_value(qop, sizeof(qop), header, "qop")) || ((0 != strcmp(qop, "auth")) && (0 != strcmp(qop, ""))) || (0 == lookup_sub_value(nc, sizeof(nc), header, "nc")) ||
|
|
||||||
(0 == lookup_sub_value(response, sizeof(response), header, "response"))) {
|
|
||||||
CWMP_LOG(ERROR, "Authentication failed, invalid format.");
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
nci = strtoul(nc, &end, 16);
|
|
||||||
if (('\0' != *end) || ((LONG_MAX == nci) && (ERANGE == errno))) {
|
|
||||||
CWMP_LOG(ERROR, "Authentication failed, invalid format.");
|
|
||||||
return MHD_NO; /* invalid nonce format */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Checking if that combination of nonce and nc is sound
|
|
||||||
* and not a replay attack attempt. Also adds the nonce
|
|
||||||
* to the nonce-nc map if it does not exist there.
|
|
||||||
*/
|
|
||||||
|
|
||||||
digest_calc_ha1("md5", username, realm, password, nonce, cnonce, ha1);
|
|
||||||
digest_calc_response(ha1, nonce, nc, cnonce, qop, http_method, uri, respexp);
|
|
||||||
|
|
||||||
return (0 == strcmp(response, respexp)) ? MHD_YES : MHD_NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
10
http.c
10
http.c
|
|
@ -21,7 +21,7 @@
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "ubus_utils.h"
|
#include "ubus_utils.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "digestauth.h"
|
#include "digauth.h"
|
||||||
|
|
||||||
#define REALM "authenticate@cwmp"
|
#define REALM "authenticate@cwmp"
|
||||||
#define OPAQUE "11733b200778ce33060f31c9af70a870ba96ddd4"
|
#define OPAQUE "11733b200778ce33060f31c9af70a870ba96ddd4"
|
||||||
|
|
@ -326,12 +326,12 @@ static void http_cr_new_client(int client, bool service_available)
|
||||||
if (!service_available || !method_is_get) {
|
if (!service_available || !method_is_get) {
|
||||||
goto http_end;
|
goto http_end;
|
||||||
}
|
}
|
||||||
int auth_check = http_digest_auth_check("GET", "/", auth_digest_buffer + strlen("Authorization: Digest "), REALM, username, password, 300);
|
int auth_check = validate_http_digest_auth("GET", "/", auth_digest_buffer + strlen("Authorization: Digest "), REALM, username, password, 300);
|
||||||
if (auth_check == MHD_INVALID_NONCE) {
|
if (auth_check == -1) { /* invalid nonce */
|
||||||
internal_error = true;
|
internal_error = true;
|
||||||
goto http_end;
|
goto http_end;
|
||||||
}
|
}
|
||||||
if (auth_digest_checked && auth_check == MHD_YES)
|
if (auth_digest_checked && auth_check == 0)
|
||||||
auth_status = 1;
|
auth_status = 1;
|
||||||
else
|
else
|
||||||
auth_status = 0;
|
auth_status = 0;
|
||||||
|
|
@ -357,7 +357,7 @@ http_end:
|
||||||
CWMP_LOG(INFO, "Receive Connection Request: Return 401 Unauthorized");
|
CWMP_LOG(INFO, "Receive Connection Request: Return 401 Unauthorized");
|
||||||
fputs("HTTP/1.1 401 Unauthorized\r\n", fp);
|
fputs("HTTP/1.1 401 Unauthorized\r\n", fp);
|
||||||
fputs("Connection: close\r\n", fp);
|
fputs("Connection: close\r\n", fp);
|
||||||
http_digest_auth_fail_response(fp, "GET", "/", REALM, OPAQUE);
|
http_authentication_failure_resp(fp, "GET", "/", REALM, OPAQUE);
|
||||||
fputs("\r\n", fp);
|
fputs("\r\n", fp);
|
||||||
}
|
}
|
||||||
fputs("\r\n", fp);
|
fputs("\r\n", fp);
|
||||||
|
|
|
||||||
15
inc/digauth.h
Normal file
15
inc/digauth.h
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef DIGAUTH_H_
|
||||||
|
#define DIGAUTH_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern char *nonce_key;
|
||||||
|
|
||||||
|
int get_nonce_key(void);
|
||||||
|
int validate_http_digest_auth(const char *http_meth, const char *uri, const char *hdr,
|
||||||
|
const char *rlm, const char *usr, const char *psw,
|
||||||
|
unsigned int timeout);
|
||||||
|
int http_authentication_failure_resp(FILE *fp, const char *http_meth, const char *uri,
|
||||||
|
const char *rlm, const char *opq);
|
||||||
|
|
||||||
|
#endif /* DIGAUTH_H_ */
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
* HTTP digest auth functions: originally imported from libmicrohttpd
|
|
||||||
*
|
|
||||||
* Copyright (C) 2013 Oussama Ghorbel <oussama.ghorbel@pivasoftware.com>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DIGESTAUTH_H_
|
|
||||||
#define DIGESTAUTH_H_
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MHD-internal return code for "YES".
|
|
||||||
*/
|
|
||||||
#define MHD_YES 1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MHD-internal return code for "NO".
|
|
||||||
*/
|
|
||||||
#define MHD_NO 0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MHD digest auth internal code for an invalid nonce.
|
|
||||||
*/
|
|
||||||
#define MHD_INVALID_NONCE -1
|
|
||||||
|
|
||||||
extern char *nonce_privacy_key;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* make response to request authentication from the client
|
|
||||||
*
|
|
||||||
* @param fp
|
|
||||||
* @param http_method
|
|
||||||
* @param url
|
|
||||||
* @param realm the realm presented to the client
|
|
||||||
* @param opaque string to user for opaque value
|
|
||||||
* @return 'MHD_YES' on success, otherwise 'MHD_NO'
|
|
||||||
*/
|
|
||||||
int http_digest_auth_fail_response(FILE *fp, const char *http_method, const char *url, const char *realm, const char *opaque);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Authenticates the authorization header sent by the client
|
|
||||||
*
|
|
||||||
* @param http_method
|
|
||||||
* @param url
|
|
||||||
* @param header: pointer to the position just after the string "Authorization: Digest "
|
|
||||||
* @param realm The realm presented to the client
|
|
||||||
* @param username The username needs to be authenticated
|
|
||||||
* @param password The password used in the authentication
|
|
||||||
* @param nonce_timeout The amount of time for a nonce to be invalid in seconds
|
|
||||||
* @return 'MHD_YES' if authenticated, 'MHD_NO' if not, 'MHD_INVALID_NONCE' if nonce is invalid
|
|
||||||
*/
|
|
||||||
int http_digest_auth_check(const char *http_method, const char *url, const char *header, const char *realm, const char *username, const char *password, unsigned int nonce_timeout);
|
|
||||||
|
|
||||||
int generate_nonce_priv_key(void);
|
|
||||||
|
|
||||||
#endif /* DIGESTAUTH_H_ */
|
|
||||||
Loading…
Add table
Reference in a new issue