Skip to content

Commit

Permalink
httpauth: basic challenge creation and verification functions (#875)
Browse files Browse the repository at this point in the history
* httpauth: new httpauth_basic challenge creation and verification

* httpauth: httpauth_basic challenge test case

* add missing doxygen parameter hval

* httpauth: simplify printer function

* httpauth: use mem_seccmp and clean memory afterwards
  • Loading branch information
cHuberCoffee authored Jul 13, 2023
1 parent ace6681 commit bc549f5
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 0 deletions.
15 changes: 15 additions & 0 deletions include/re_httpauth.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ struct httpauth_basic {
struct pl auth;
};

struct httpauth_basic_req {
char *realm;

/* optional */
char *charset;
};


int httpauth_digest_challenge_decode(struct httpauth_digest_chall *chall,
const struct pl *hval);
Expand All @@ -61,3 +68,11 @@ int httpauth_basic_decode(struct httpauth_basic *basic,
int httpauth_basic_make_response(struct httpauth_basic *basic,
const char *user, const char *pwd);
int httpauth_basic_encode(const struct httpauth_basic *basic, struct mbuf *mb);


int httpauth_basic_request_print(struct re_printf *pf,
const struct httpauth_basic_req *req);
int httpauth_basic_verify(const struct pl *hval, const char *user,
const char *passwd);
int httpauth_basic_request(struct httpauth_basic_req **preq,
const char *realm, const char *charset);
124 changes: 124 additions & 0 deletions src/httpauth/basic.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,127 @@ int httpauth_basic_encode(const struct httpauth_basic *basic, struct mbuf *mb)
mbuf_set_pos(mb, 0);
return 0;
}

/* HTTPAUTH BASIC REQUESTS*/

static void httpauth_basic_request_destructor(void *arg)
{
struct httpauth_basic_req *req = arg;

mem_deref(req->realm);
mem_deref(req->charset);
}


int httpauth_basic_request_print(struct re_printf *pf,
const struct httpauth_basic_req *req)
{
int err = 0;

if (!pf || !req)
return EINVAL;

err = re_hprintf(pf, "Basic realm=\"%s\"", req->realm);
if (str_isset(req->charset))
err |= re_hprintf(pf, ", charset=\"%s\"", req->charset);

return err;
}


/**
* Verify received credentials
*
* @param hval http authentication header value containing the credentials
* @param user user name (may be an UTF-8 string)
* @param passwd user password (may be an UTF-8 string)
*
* @return 0 if successfully verified, otherwise errorcode
*/
int httpauth_basic_verify(const struct pl *hval, const char *user,
const char *passwd)
{
struct pl b64c = PL_INIT;
struct mbuf *mb = NULL;
char *c = NULL;
size_t clen = 0;
int err = 0;

if (!hval || !user || !passwd)
return EINVAL;

mb = mbuf_alloc(str_len(user) + str_len(passwd) + 1);
if (!mb)
return ENOMEM;

if (re_regex(hval->p, hval->l, "[ \t\r\n]*Basic[ \t\r\n]+[~ \t\r\n]*",
NULL, NULL, &b64c) || !pl_isset(&b64c)) {
err = EBADMSG;
goto out;
}

clen = b64c.l;
c = mem_zalloc(clen, NULL);
if (!c) {
err = ENOMEM;
goto out;
}

err = base64_decode(b64c.p, b64c.l, (uint8_t *) c, &clen);
if (err)
goto out;

err = mbuf_printf(mb, "%s:%s", user, passwd);
if (err)
goto out;

if (mem_seccmp(mb->buf, (uint8_t *)c, clen) != 0)
err = EACCES;

out:
if (c)
mem_secclean(c, clen);

if (mb)
mem_secclean(mb->buf, mb->size);

mem_deref(c);
mem_deref(mb);

return err;
}


/**
* Create a Basic Authentication Request
*
* @param preq httpauth_basic_req object ptr
* @param realm realm
* @param charset optional charset
*
* @return 0 if successful, otherwise errorcode
*/
int httpauth_basic_request(struct httpauth_basic_req **preq,
const char *realm, const char *charset)
{
struct httpauth_basic_req *req = NULL;
int err = 0;

if (!preq || !realm)
return EINVAL;

req = mem_zalloc(sizeof(*req), httpauth_basic_request_destructor);
if (!req)
return ENOMEM;

err = str_dup(&req->realm, realm);
if (str_isset(charset) && str_casecmp(charset, "UTF-8") == 0)
err |= str_dup(&req->charset, charset);

if (err)
mem_deref(req);
else
*preq = req;

return err;
}
112 changes: 112 additions & 0 deletions test/httpauth.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,115 @@ int test_httpauth_resp(void)

return err;
}


int test_httpauth_basic_request(void) {
static const struct {
const char *hval;
struct pl hval_response;
const char *realm;
const char *charset;
const char *user;
const char *passwd;
int err;
int auth_err;
} testv[] = {
{
"Basic realm=\"/my/home\"",
PL("Basic cmV0ZXN0OnJldGVzdHBhc3N3ZA=="),
"/my/home", NULL, "retest", "retestpasswd", 0, 0
},
{
"Basic realm=\"/my/home\", charset=\"UTF-8\"",
PL("Basic cmV0ZXN0OnJldGVzdHBhc3N3ZOKCrA=="),
"/my/home", "UTF-8", "retest",
"retestpasswd\xe2\x82\xac",
0, 0
},
{
"Basic realm=\"/my/home\"",
PL("Basic d3Jvbmc6Y3JlZGVudGlhbHM=="), "/my/home",
NULL, "retest", "retestpasswd", 0, EACCES
},
};
unsigned int i;
int err = 0;

for (i = 0; i < RE_ARRAY_SIZE(testv); ++i) {
struct httpauth_basic_req *req = NULL;
struct mbuf *mb = NULL;
int terr = 0;
int tauth_err = 0;

terr = httpauth_basic_request(&req,
testv[i].realm, testv[i].charset);
if (terr == ENOMEM) {
err = ENOMEM;
break;
}
else if (terr != testv[i].err) {
DEBUG_WARNING("basic req: expected error %d, got %m\n",
testv[i].err, terr);
err = terr;
break;
}

if (str_casecmp(req->realm, testv[i].realm) != 0) {
DEBUG_WARNING("basic req: expected realm %s, got %s\n",
testv[i].realm, req->realm);
err = EBADMSG;
mem_deref(req);
break;
}

if (testv[i].charset) {
if (str_casecmp(req->charset, testv[i].charset) != 0) {
DEBUG_WARNING("basic req: expected charset"
"%s, got %s\n", testv[i].charset,
req->charset);
err = EBADMSG;
mem_deref(req);
break;
}
}

mb = mbuf_alloc(512);
if (!mb) {
err = ENOMEM;
mem_deref(req);
break;
}

err = mbuf_printf(mb, "%H", httpauth_basic_request_print, req);
if (err) {
mem_deref(mb);
mem_deref(req);
break;
}

if (memcmp(testv[i].hval, mb->buf,
str_len(testv[i].hval)) != 0) {
DEBUG_WARNING("basic req: expected hval %s, got %s\n",
testv[i].hval, mb->buf);
err = EBADMSG;
mem_deref(mb);
mem_deref(req);
break;
}

mem_deref(mb);
tauth_err = httpauth_basic_verify(&testv[i].hval_response,
testv[i].user, testv[i].passwd);
if (tauth_err != testv[i].auth_err) {
DEBUG_WARNING("basic req:"
"authentication expected %d, got %d\n",
testv[i].auth_err, tauth_err);
mem_deref(req);
break;
}

mem_deref(req);
}

return err;
}
1 change: 1 addition & 0 deletions test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ static const struct test tests[] = {
#endif
TEST(test_httpauth_chall),
TEST(test_httpauth_resp),
TEST(test_httpauth_basic_request),
TEST(test_ice_cand),
TEST(test_ice_loop),
TEST(test_jbuf),
Expand Down
1 change: 1 addition & 0 deletions test/test.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ int test_https_conn_post_handshake(void);
#endif
int test_httpauth_chall(void);
int test_httpauth_resp(void);
int test_httpauth_basic_request(void);
int test_ice_loop(void);
int test_ice_cand(void);
int test_jbuf(void);
Expand Down

0 comments on commit bc549f5

Please sign in to comment.