From 0b24f66cf8502248c4320aa2a2d07ba61aa48fac Mon Sep 17 00:00:00 2001 From: Christoph Huber Date: Tue, 5 Sep 2023 14:01:09 +0200 Subject: [PATCH 1/8] httpauth: http digest challenge response using RFC 7616 + definition of response struct using char* to save the parameters + added decoding for new fields in http digest challenge struct + response calculation supports qop: none, auth, auth-int + supported hash algorithm: MD5, SHA1, SHA265 and -sess variants --- include/re_httpauth.h | 37 ++++ src/httpauth/digest.c | 434 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 466 insertions(+), 5 deletions(-) diff --git a/include/re_httpauth.h b/include/re_httpauth.h index 0fce26dbd..63bf26042 100644 --- a/include/re_httpauth.h +++ b/include/re_httpauth.h @@ -35,6 +35,28 @@ struct httpauth_digest_chall { struct pl userhash; }; +struct httpauth_digest_enc_resp { + char *realm; + char *nonce; + char *opaque; + char *algorithm; + char *qop; + + /* response specific */ + char *response; + char *username; + char *username_star; + char *uri; + char *cnonce; + char *nc; + + /* optional */ + char *charset; + bool userhash; + void (*hash_function)(const uint8_t *, size_t, uint8_t *); + size_t hash_length; +}; + /** HTTP Digest response */ struct httpauth_digest_resp { struct pl realm; @@ -81,6 +103,21 @@ int httpauth_digest_response_encode(const struct httpauth_digest_resp *resp, struct mbuf *mb); +int httpauth_digest_response_print(struct re_printf *pf, + const struct httpauth_digest_enc_resp *resp); +int httpauth_digest_response_set_cnonce(struct httpauth_digest_enc_resp *resp, + const struct httpauth_digest_chall *chall, const struct pl *method, + const char *user, const char *passwd, const char *entitybody, + const uint32_t cnonce, const uint32_t nc_); +int httpauth_digest_response(struct httpauth_digest_enc_resp **presp, + const struct httpauth_digest_chall *chall, const struct pl *method, + const char *uri, const char *user, const char *passwd, const char *qop, + const char *entitybody); +int httpauth_digest_response_full(struct httpauth_digest_enc_resp **presp, + const struct httpauth_digest_chall *chall, const struct pl *method, + const char *uri, const char *user, const char *passwd, const char *qop, + const char *entitybody, const char *charset, const bool userhash); + int httpauth_digest_chall_req_print(struct re_printf *pf, const struct httpauth_digest_chall_req *req); int httpauth_digest_chall_request(struct httpauth_digest_chall_req **preq, diff --git a/src/httpauth/digest.c b/src/httpauth/digest.c index 1358fd450..3bfce9f60 100644 --- a/src/httpauth/digest.c +++ b/src/httpauth/digest.c @@ -16,21 +16,37 @@ #include +enum { + CNONCE_NC_LENGTH = 9, /* 8 characters + '\0' */ +}; + + typedef void (digest_decode_h)(const struct pl *name, const struct pl *val, void *arg); -static const struct pl param_algorithm = PL("algorithm"); -static const struct pl param_cnonce = PL("cnonce"); -static const struct pl param_nc = PL("nc"); +/* General fields */ +static const struct pl param_realm = PL("realm"); static const struct pl param_nonce = PL("nonce"); static const struct pl param_opaque = PL("opaque"); +static const struct pl param_algorithm = PL("algorithm"); static const struct pl param_qop = PL("qop"); -static const struct pl param_realm = PL("realm"); +static const struct pl param_stale = PL("stale"); + +/* Challenge fields */ +static const struct pl param_domain = PL("domain"); + +/* Response fields */ static const struct pl param_response = PL("response"); static const struct pl param_uri = PL("uri"); static const struct pl param_username = PL("username"); -static const struct pl param_stale = PL("stale"); +/* static const struct pl param_userstar = PL("username*"); future use */ +static const struct pl param_cnonce = PL("cnonce"); +static const struct pl param_nc = PL("nc"); + +/* Optional fields */ +static const struct pl param_charset = PL("charset"); +static const struct pl param_userhash = PL("userhash"); static void challenge_decode(const struct pl *name, const struct pl *val, @@ -40,6 +56,8 @@ static void challenge_decode(const struct pl *name, const struct pl *val, if (!pl_casecmp(name, ¶m_realm)) chall->realm = *val; + else if (!pl_casecmp(name, ¶m_domain)) + chall->domain = *val; else if (!pl_casecmp(name, ¶m_nonce)) chall->nonce = *val; else if (!pl_casecmp(name, ¶m_opaque)) @@ -50,6 +68,10 @@ static void challenge_decode(const struct pl *name, const struct pl *val, chall->algorithm = *val; else if (!pl_casecmp(name, ¶m_qop)) chall->qop = *val; + else if (!pl_casecmp(name, ¶m_charset)) + chall->charset = *val; + else if (!pl_casecmp(name, ¶m_userhash)) + chall->userhash = *val; } @@ -591,3 +613,405 @@ int httpauth_digest_chall_request_full(struct httpauth_digest_chall_req **preq, return err; } + + +static void httpauth_digest_response_destructor(void *arg) +{ + struct httpauth_digest_enc_resp *resp = arg; + + mem_deref(resp->realm); + mem_deref(resp->nonce); + mem_deref(resp->opaque); + mem_deref(resp->algorithm); + mem_deref(resp->qop); + mem_deref(resp->response); + mem_deref(resp->username); + mem_deref(resp->username_star); + mem_deref(resp->uri); + mem_deref(resp->cnonce); + mem_deref(resp->nc); + mem_deref(resp->charset); +} + + +static int digest_response(struct httpauth_digest_enc_resp *resp, + const struct httpauth_digest_chall *chall, + const struct pl *method, const char *user, + const char *passwd, const char *entitybody) +{ + uint8_t *hash1 = NULL; + uint8_t *hash2 = NULL; + struct mbuf *mb = NULL; + size_t hashstringl = (resp->hash_length * 2) + 1; + int err = 0, n = 0; + + mb = mbuf_alloc(str_len(user) + str_len(passwd) + chall->realm.l + 2); + if (!mb) + return ENOMEM; + + hash1 = mem_zalloc(resp->hash_length, NULL); + hash2 = mem_zalloc(resp->hash_length, NULL); + if (!resp->response) + resp->response = mem_zalloc(hashstringl, NULL); + + if (!resp->response || !hash1 || !hash2) { + err = ENOMEM; + goto out; + } + + /* HASH A2 */ + if (str_isset(resp->qop) && str_str(resp->qop, "auth-int")) { + if (!entitybody || str_casecmp(entitybody, "") == 0) { + resp->hash_function((uint8_t *)"", str_len(""), hash1); + } + else { + resp->hash_function((uint8_t *)entitybody, + str_len(entitybody), hash1); + } + + err = mbuf_printf(mb, "%r:%s:%w", + method, resp->uri, hash1, resp->hash_length); + } + else { + err = mbuf_printf(mb, "%r:%s", method, resp->uri); + } + + if (err) + goto out; + + resp->hash_function(mb->buf, mb->end, hash2); + mbuf_rewind(mb); + + /* HASH A1 */ + if (resp->userhash) { + if (!resp->username) + resp->username = mem_zalloc(hashstringl, NULL); + + if (!resp->username) { + err = ENOMEM; + goto out; + } + + err = mbuf_printf(mb, "%s:%s", user, resp->realm); + if (err) + goto out; + + resp->hash_function(mb->buf, mb->end, hash1); + n = re_snprintf(resp->username, hashstringl, "%w", + hash1, hashstringl); + if (n == -1 || n != (int)hashstringl -1) { + err = ERANGE; + goto out; + } + + mbuf_rewind(mb); + err = mbuf_printf(mb, "%w:%s:%s", + hash1, resp->hash_length, resp->realm, passwd); + } + else { + err = mbuf_printf(mb, "%s:%s:%s", user, resp->realm, passwd); + resp->username = mem_deref(resp->username); + err |= str_dup(&resp->username, user); + } + + if (err) + goto out; + + resp->hash_function(mb->buf, mb->end, hash1); + mbuf_rewind(mb); + + if (str_str(resp->algorithm, "-sess")) { + err = mbuf_printf(mb, "%w:%s:%s", + hash1, resp->hash_length, resp->nonce, resp->cnonce); + if (err) + goto out; + + resp->hash_function(mb->buf, mb->end, hash1); + mbuf_rewind(mb); + } + + /* DIGEST */ + if (str_isset(resp->qop)) { + err = mbuf_printf(mb, "%w:%s:%s:%s:%s:%w", + hash1, resp->hash_length, resp->nonce, resp->nc, + resp->cnonce, resp->qop, hash2, resp->hash_length); + } + else { + err = mbuf_printf(mb, "%w:%s:%w", hash1, resp->hash_length, + resp->nonce, hash2, resp->hash_length); + } + + if (err) + goto out; + + resp->hash_function(mb->buf, mb->end, hash1); + n = re_snprintf(resp->response, hashstringl, "%w", + hash1, resp->hash_length); + if (n == -1 || n != (int)hashstringl - 1) + err = ERANGE; + +out: + mem_deref(mb); + mem_deref(hash1); + mem_deref(hash2); + + return err; +} + + +/** + * Prints / encodes an HTTP digest response + * + * @param pf Re_printf object + * @param resp Response to print + * + * @return 0 if success, otherwise errorcode + */ +int httpauth_digest_response_print(struct re_printf *pf, + const struct httpauth_digest_enc_resp *resp) +{ + int err = 0; + + if (!resp) + return EINVAL; + + /* historical reason quoted strings: */ + /* username, realm, nonce, uri, */ + /* response, cnonce, opaque */ + /* historical reason unquoted strings: */ + /* qop, algorithm, nc */ + err = re_hprintf(pf, "Digest realm=\"%s\"," + " nonce=\"%s\", username=\"%s\", uri=\"%s\"," + " response=\"%s\"", + resp->realm, resp->nonce, resp->username, + resp->uri, resp->response); + + if (str_isset(resp->opaque)) + err |= re_hprintf(pf, ", opaque=\"%s\"", resp->opaque); + if (str_isset(resp->algorithm)) + err |= re_hprintf(pf, ", algorithm=%s", resp->algorithm); + if (str_isset(resp->qop)) + err |= re_hprintf(pf, ", qop=%s, cnonce=\"%s\", nc=\"%s\"", + resp->qop, resp->cnonce, resp->nc); + + if (resp->userhash) + err |= re_hprintf(pf, ", userhash=true"); + if (str_isset(resp->charset)) + err |= re_hprintf(pf, ", charset=\"%s\"", resp->charset); + + return err; +} + + +/** + * Set cnonce and nc and recalculate the response value. + * This function should be used only for unit tests + * + * @param resp Httpauth_new_digest_response object pointer + * @param chall Received and decoded digest challenge + * @param method Used method + * @param user Username + * @param passwd User password + * @param entitybody Entitybody if qop=auth-int + * @param cnonce Cnonce + * @param nc_ Nonce counter + * + * @return 0 if success, otherwise errorcode + */ +int httpauth_digest_response_set_cnonce(struct httpauth_digest_enc_resp *resp, + const struct httpauth_digest_chall *chall, const struct pl *method, + const char *user, const char *passwd, const char *entitybody, + const uint32_t cnonce, const uint32_t nc_) +{ + int err = 0, n = 0; + + if (!resp || !chall || !method || !passwd) + return EINVAL; + + n = re_snprintf(resp->cnonce, CNONCE_NC_LENGTH, "%08x", cnonce); + if (n == -1 || n != CNONCE_NC_LENGTH -1) { + err = ERANGE; + goto out; + } + + n = re_snprintf(resp->nc, CNONCE_NC_LENGTH, "%08x", nc_); + if (n == -1 || n != CNONCE_NC_LENGTH -1) { + err = ERANGE; + goto out; + } + + err = digest_response(resp, chall, method, + user, passwd, entitybody); + +out: + return err; +} + + +/** + * Create a digest authentication response + * + * @param presp Httpauth_new_digest_response object pointer + * @param chall Received and decoded digest challenge + * @param method Used method + * @param uri Accessed uri + * @param user Username + * @param passwd User password + * @param qop Quality of protection + * @param entitybody Entitybody if qop=auth-int + * + * @return 0 if success, otherwise errorcode + */ +int httpauth_digest_response(struct httpauth_digest_enc_resp **presp, + const struct httpauth_digest_chall *chall, const struct pl *method, + const char *uri, const char *user, const char *passwd, const char *qop, + const char *entitybody) +{ + return httpauth_digest_response_full(presp, chall, method, uri, + user, passwd, qop, entitybody, NULL, false); +} + + +/** + * Create a full configurable digest authentication response + * + * @param presp Httpauth_new_digest_response object pointer + * @param chall Received and decoded digest challenge + * @param method Used method + * @param uri Accessed uri + * @param user Username + * @param passwd User password + * @param qop Quality of protection + * @param entitybody Entitybody if qop=auth-int + * @param charset Used character set (only UTF-8 or NULL allowed) + * @param userhash Enable hashed usernames + * + * @return 0 if success, otherwise errorcode + */ +int httpauth_digest_response_full(struct httpauth_digest_enc_resp **presp, + const struct httpauth_digest_chall *chall, const struct pl *method, + const char *uri, const char *user, const char *passwd, const char *qop, + const char *entitybody, const char *charset, const bool userhash) +{ + struct httpauth_digest_enc_resp *resp = NULL; + uint32_t cnonce = rand_u32(); + int err = 0, n = 0; + + if (!presp || !chall || !method || !uri || !user || !passwd) + return EINVAL; + + resp = mem_zalloc(sizeof(*resp), httpauth_digest_response_destructor); + if (!resp) { + return ENOMEM; + } + + resp->cnonce = mem_zalloc(CNONCE_NC_LENGTH, NULL); + resp->nc = mem_zalloc(CNONCE_NC_LENGTH, NULL); + if (!resp->cnonce || !resp->nc) { + err = ENOMEM; + goto out; + } + + /* copy fields */ + err = pl_strdup(&resp->realm, &chall->realm); + err |= pl_strdup(&resp->nonce, &chall->nonce); + err |= pl_strdup(&resp->opaque, &chall->opaque); + if (err) { + goto out; + } + + /* userhash supported by server */ + if (userhash && (pl_strcasecmp(&chall->userhash, "true") == 0)) + resp->userhash = true; + + /* only allowed qop Nothing, "auth" or "auth-int" */ + if (str_isset(qop) && (str_casecmp(qop, "auth")) && + (str_casecmp(qop, "auth-int"))) { + err = EPROTONOSUPPORT; + goto out; + } + + /* qop supported by server */ + if (pl_isset(&chall->qop) && str_isset(qop) && + pl_strstr(&chall->qop, qop)) { + err = str_dup(&resp->qop, qop); + if (err) + goto out; + } + + /* only allowed charset Nothing or "UTF-8" */ + if (str_isset(charset) && str_casecmp(charset, "UTF-8")) { + err = EPROTONOSUPPORT; + goto out; + } + + /* charset supported by server */ + if (pl_isset(&chall->charset) && str_isset(charset) && + pl_strstr(&chall->charset, charset) == 0) { + err = str_dup(&resp->charset, charset); + if (err) + goto out; + } + + err = str_dup(&resp->uri, uri); + if (err) + goto out; + + n = re_snprintf(resp->cnonce, CNONCE_NC_LENGTH, "%08x", cnonce); + if (n == -1 || n != CNONCE_NC_LENGTH -1) { + err = ERANGE; + goto out; + } + + n = re_snprintf(resp->nc, CNONCE_NC_LENGTH, "%08x", nc++); + if (n == -1 || n != CNONCE_NC_LENGTH -1) { + err = ERANGE; + goto out; + } + + if (pl_strstr(&chall->algorithm, "SHA256-sess")) { + resp->hash_function = &sha256; + resp->hash_length = SHA256_DIGEST_LENGTH; + err = str_dup(&resp->algorithm, "SHA256-sess"); + } + else if (pl_strstr(&chall->algorithm, "SHA256")) { + resp->hash_function = &sha256; + resp->hash_length = SHA256_DIGEST_LENGTH; + err = str_dup(&resp->algorithm, "SHA256"); + } + else if (pl_strstr(&chall->algorithm, "SHA1-sess")) { + resp->hash_function = &sha1; + resp->hash_length = SHA_DIGEST_LENGTH; + err = str_dup(&resp->algorithm, "SHA1-sess"); + } + else if (pl_strstr(&chall->algorithm, "SHA1")) { + resp->hash_function = &sha1; + resp->hash_length = SHA_DIGEST_LENGTH; + err = str_dup(&resp->algorithm, "SHA1"); + } + else if (pl_strstr(&chall->algorithm, "MD5-sess")) { + resp->hash_function = &md5; + resp->hash_length = MD5_SIZE; + err = str_dup(&resp->algorithm, "MD5-sess"); + } + else if (!pl_isset(&chall->algorithm) || + pl_strstr(&chall->algorithm, "MD5")) { + resp->hash_function = &md5; + resp->hash_length = MD5_SIZE; + err = str_dup(&resp->algorithm, "MD5"); + } + else { + err = EPROTONOSUPPORT; + goto out; + } + + err = digest_response(resp, chall, method, user, passwd, entitybody); + +out: + if (err) + mem_deref(resp); + else + *presp = resp; + + return err; +} From 074b0b6ffbfa9133da2d32bb79f68eb4d63c1c31 Mon Sep 17 00:00:00 2001 From: Christoph Huber Date: Tue, 5 Sep 2023 14:02:18 +0200 Subject: [PATCH 2/8] httpauth: test cases for http digest response calculation and printing --- test/httpauth.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++ test/test.c | 1 + test/test.h | 1 + 3 files changed, 227 insertions(+) diff --git a/test/httpauth.c b/test/httpauth.c index 4c01a981a..c17abe6af 100644 --- a/test/httpauth.c +++ b/test/httpauth.c @@ -45,6 +45,9 @@ static bool chall_equal(const struct httpauth_digest_chall *a, err |= pl_equal("stale", &a->stale, &b->stale); err |= pl_equal("algorithm", &a->algorithm, &b->algorithm); err |= pl_equal("qop", &a->qop, &b->qop); + err |= pl_equal("domain", &a->domain, &b->domain); + err |= pl_equal("charset", &a->charset, &b->charset); + err |= pl_equal("userhash", &a->userhash, &b->userhash); return err == 0; } @@ -504,3 +507,225 @@ int test_httpauth_digest_request(void) return err; } + + +int test_httpauth_digest_response(void) +{ + static const struct { + const struct httpauth_digest_chall chall; + const char *user; + const char *passwd; + const char *qop; + const struct pl method; + const char *uri; + const char *entitybody; + const char *precalc_digest; + const char *resp_hval; + } testv [] = { + { + { + PL("/my/home"), + PL("b5c64f319d37323ac652b77012817ccaa" + "6e9a7e4e7563155f1f9556414dd4615"), + PL("324DF3428BCF42D29A"), PL_INIT, + PL("MD5"), PL("auth"), PL_INIT, PL_INIT, + PL_INIT + }, + "retest", "sec_pwd_retest", "auth", PL("GET"), + "example.com/my/home/something", NULL, + "88f41f7227700e07d0d65256714a5a1a", + + "Digest realm=\"/my/home\"," + " nonce=\"b5c64f319d37323ac652b77012817ccaa6e" + "9a7e4e7563155f1f9556414dd4615\"," + " username=\"retest\"," + " uri=\"example.com/my/home/something\"," + " response=\"88f41f7227700e07d0d65256714a5a1a\"," + " opaque=\"324DF3428BCF42D29A\", algorithm=MD5," + " qop=auth, cnonce=\"deadbeef\", nc=\"00000001\"", + }, + { + { + PL("/my/home"), + PL("b5c64f319d37323ac652b77012817ccaa" + "6e9a7e4e7563155f1f9556414dd4615"), + PL("324DF3428BCF42D29A"), PL_INIT, + PL("SHA1"), PL("auth"), PL_INIT, PL_INIT, + PL_INIT + }, + "retest", "sec_pwd_retest", "auth", PL("GET"), + "example.com/my/home/something", NULL, + "417bd44d62c73baa0f0291fb36d4777878369544", + + "Digest realm=\"/my/home\"," + " nonce=\"b5c64f319d37323ac652b77012817ccaa6e9a" + "7e4e7563155f1f9556414dd4615\","" username=\"retest\"," + " uri=\"example.com/my/home/something\"," + " response=\"417bd44d62c73baa0f0291fb36d4777878" + "369544\", opaque=\"324DF3428BCF42D29A\"," + " algorithm=SHA1, qop=auth, cnonce=\"deadbeef\"," + " nc=\"00000001\"", + }, + { + { + PL("/my/home"), + PL("b5c64f319d37323ac652b77012817ccaa" + "6e9a7e4e7563155f1f9556414dd4615"), + PL("324DF3428BCF42D29A"), PL_INIT, + PL("SHA256"), PL("auth"), PL_INIT, PL_INIT, + PL_INIT + }, + "retest", "sec_pwd_retest", "auth", PL("GET"), + "example.com/my/home/something", NULL, + "c22b56ce81bbb59570f0fbbc0ba27210dbbfcb2b23fe" + "a371d214722f319dc41c", + + "Digest realm=\"/my/home\"," + " nonce=\"b5c64f319d37323ac652b77012817ccaa6e" + "9a7e4e7563155f1f9556414dd4615\", username=\"retest\"," + " uri=\"example.com/my/home/something\"," + " response=\"c22b56ce81bbb59570f0fbbc0ba27210dbbfcb2b2" + "3fea371d214722f319dc41c\"," + " opaque=\"324DF3428BCF42D29A\", algorithm=SHA256," + " qop=auth, cnonce=\"deadbeef\", nc=\"00000001\"", + }, + { + { + PL("/my/home"), + PL("b5c64f319d37323ac652b77012817ccaa" + "6e9a7e4e7563155f1f9556414dd4615"), + PL("324DF3428BCF42D29A"), PL_INIT, + PL("MD5-sess"), PL("auth"), PL_INIT, PL_INIT, + PL_INIT + }, + "retest", "sec_pwd_retest", "auth", PL("GET"), + "example.com/my/home/something", NULL, + "1e79ac7105a4fdf416aaacfc50349110", + + "Digest realm=\"/my/home\"," + " nonce=\"b5c64f319d37323ac652b77012817ccaa6e9a7e4e756" + "3155f1f9556414dd4615\", username=\"retest\"," + " uri=\"example.com/my/home/something\"," + " response=\"1e79ac7105a4fdf416aaacfc50349110\"," + " opaque=\"324DF3428BCF42D29A\", algorithm=MD5-sess," + " qop=auth, cnonce=\"deadbeef\", nc=\"00000001\"", + }, + { + { + PL("/my/home"), + PL("b5c64f319d37323ac652b77012817ccaa" + "6e9a7e4e7563155f1f9556414dd4615"), + PL("324DF3428BCF42D29A"), PL_INIT, + PL("SHA1"), PL("auth-int"), PL_INIT, PL_INIT, + PL_INIT + }, + "retest", "sec_pwd_retest", "auth-int", PL("GET"), + "example.com/my/home/something", "a text body", + "1565b20cc176a3eed8cd0318600cf3caf96fd23c", + + "Digest realm=\"/my/home\"," + " nonce=\"b5c64f319d37323ac652b77012817ccaa6e9a7e4e756" + "3155f1f9556414dd4615\", username=\"retest\"," + " uri=\"example.com/my/home/something\"," + " response=\"1565b20cc176a3eed8cd0318600cf3caf96f" + "d23c\", opaque=\"324DF3428BCF42D29A\"," + " algorithm=SHA1, qop=auth-int, cnonce=\"deadbeef\"," + " nc=\"00000001\"", + }, + { + { + PL("/my/home"), + PL("b5c64f319d37323ac652b77012817ccaa" + "6e9a7e4e7563155f1f9556414dd4615"), + PL("324DF3428BCF42D29A"), PL_INIT, + PL("SHA256"), PL("auth-int"), PL_INIT, PL_INIT, + PL_INIT + }, + "retest", "sec_pwd_retest", "auth-int", PL("GET"), + "example.com/my/home/something", "", + "2c0746b7174441314164d8d9a980d8920732de32e163" + "03f0e6a82970230e79e4", + + "Digest realm=\"/my/home\"," + " nonce=\"b5c64f319d37323ac652b77012817ccaa6e9a7e4e756" + "3155f1f9556414dd4615\", username=\"retest\"," + " uri=\"example.com/my/home/something\"," + " response=\"2c0746b7174441314164d8d9a980d8920732de32e" + "16303f0e6a82970230e79e4\"," + " opaque=\"324DF3428BCF42D29A\", algorithm=SHA256," + " qop=auth-int, cnonce=\"deadbeef\", nc=\"00000001\"", + }, + }; + + int err; + + for (unsigned int i = 0; i < RE_ARRAY_SIZE(testv); i++) { + struct httpauth_digest_enc_resp *resp = NULL; + struct mbuf *mb_printed = NULL; + + mb_printed = mbuf_alloc(512); + if (!mb_printed) { + err = ENOMEM; + goto for_out; + } + + err = httpauth_digest_response_full(&resp, &testv[i].chall, + &testv[i].method, testv[i].uri, testv[i].user, + testv[i].passwd, testv[i].qop, testv[i].entitybody, + NULL, false); + if (err == ENOMEM) { + goto for_out; + } + else if (err) { + DEBUG_WARNING("[%d]" + " Could not generate response %m\n", i, err); + goto for_out; + } + + err = httpauth_digest_response_set_cnonce(resp, + &testv[i].chall, &testv[i].method, testv[i].user, + testv[i].passwd, testv[i].entitybody, + 0xdeadbeef, 0x00000001); + if (err) { + DEBUG_WARNING("[%d]" + " Response recalculation failed %m\n", i, err); + goto for_out; + } + + err = mbuf_printf(mb_printed, "%H", + httpauth_digest_response_print, resp); + if (err) + goto for_out; + + if (str_casecmp(resp->response, + testv[i].precalc_digest) != 0) { + err = EINVAL; + DEBUG_WARNING("[%d]" + " Expected response %s, got %w\n", i, + testv[i].precalc_digest, + resp->response, resp->hash_length); + goto for_out; + } + + if (memcmp(testv[i].resp_hval, + mb_printed->buf, mb_printed->end)) { + err = EINVAL; + DEBUG_WARNING("[%d]" + " Expected header %s, got %b\n", + i, testv[i].resp_hval, + mb_printed->buf, mb_printed->end); + goto for_out; + } + + mb_printed = mem_deref (mb_printed); + resp = mem_deref(resp); + continue; + +for_out: + mb_printed = mem_deref (mb_printed); + resp = mem_deref(resp); + break; + } + + return err; +} diff --git a/test/test.c b/test/test.c index daec37bb1..039dd6894 100644 --- a/test/test.c +++ b/test/test.c @@ -122,6 +122,7 @@ static const struct test tests[] = { TEST(test_httpauth_resp), TEST(test_httpauth_basic_request), TEST(test_httpauth_digest_request), + TEST(test_httpauth_digest_response), TEST(test_ice_cand), TEST(test_ice_loop), TEST(test_json), diff --git a/test/test.h b/test/test.h index 1eb31009e..ee386b5e9 100644 --- a/test/test.h +++ b/test/test.h @@ -226,6 +226,7 @@ int test_httpauth_chall(void); int test_httpauth_resp(void); int test_httpauth_basic_request(void); int test_httpauth_digest_request(void); +int test_httpauth_digest_response(void); int test_ice_loop(void); int test_ice_cand(void); int test_json(void); From 45b8350ecbad09379e799732af32726a21e43948 Mon Sep 17 00:00:00 2001 From: Christoph Huber Date: Tue, 12 Sep 2023 10:24:27 +0200 Subject: [PATCH 3/8] httpauth: fix mentioned review points --- include/re_httpauth.h | 2 +- src/httpauth/digest.c | 69 ++++++++++++++++++++++--------------------- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/include/re_httpauth.h b/include/re_httpauth.h index 63bf26042..83fbebf45 100644 --- a/include/re_httpauth.h +++ b/include/re_httpauth.h @@ -53,7 +53,7 @@ struct httpauth_digest_enc_resp { /* optional */ char *charset; bool userhash; - void (*hash_function)(const uint8_t *, size_t, uint8_t *); + void (*hashh)(const uint8_t *, size_t, uint8_t *); size_t hash_length; }; diff --git a/src/httpauth/digest.c b/src/httpauth/digest.c index 3bfce9f60..dcf0fc98d 100644 --- a/src/httpauth/digest.c +++ b/src/httpauth/digest.c @@ -17,7 +17,7 @@ enum { - CNONCE_NC_LENGTH = 9, /* 8 characters + '\0' */ + CNONCE_NC_SIZE = 9, /* 8 characters + '\0' */ }; @@ -645,6 +645,9 @@ static int digest_response(struct httpauth_digest_enc_resp *resp, size_t hashstringl = (resp->hash_length * 2) + 1; int err = 0, n = 0; + if (!resp || !resp->hashh) + return EINVAL; + mb = mbuf_alloc(str_len(user) + str_len(passwd) + chall->realm.l + 2); if (!mb) return ENOMEM; @@ -662,10 +665,10 @@ static int digest_response(struct httpauth_digest_enc_resp *resp, /* HASH A2 */ if (str_isset(resp->qop) && str_str(resp->qop, "auth-int")) { if (!entitybody || str_casecmp(entitybody, "") == 0) { - resp->hash_function((uint8_t *)"", str_len(""), hash1); + resp->hashh((uint8_t *)"", 0, hash1); } else { - resp->hash_function((uint8_t *)entitybody, + resp->hashh((uint8_t *)entitybody, str_len(entitybody), hash1); } @@ -679,7 +682,7 @@ static int digest_response(struct httpauth_digest_enc_resp *resp, if (err) goto out; - resp->hash_function(mb->buf, mb->end, hash2); + resp->hashh(mb->buf, mb->end, hash2); mbuf_rewind(mb); /* HASH A1 */ @@ -696,7 +699,7 @@ static int digest_response(struct httpauth_digest_enc_resp *resp, if (err) goto out; - resp->hash_function(mb->buf, mb->end, hash1); + resp->hashh(mb->buf, mb->end, hash1); n = re_snprintf(resp->username, hashstringl, "%w", hash1, hashstringl); if (n == -1 || n != (int)hashstringl -1) { @@ -717,7 +720,7 @@ static int digest_response(struct httpauth_digest_enc_resp *resp, if (err) goto out; - resp->hash_function(mb->buf, mb->end, hash1); + resp->hashh(mb->buf, mb->end, hash1); mbuf_rewind(mb); if (str_str(resp->algorithm, "-sess")) { @@ -726,7 +729,7 @@ static int digest_response(struct httpauth_digest_enc_resp *resp, if (err) goto out; - resp->hash_function(mb->buf, mb->end, hash1); + resp->hashh(mb->buf, mb->end, hash1); mbuf_rewind(mb); } @@ -744,7 +747,7 @@ static int digest_response(struct httpauth_digest_enc_resp *resp, if (err) goto out; - resp->hash_function(mb->buf, mb->end, hash1); + resp->hashh(mb->buf, mb->end, hash1); n = re_snprintf(resp->response, hashstringl, "%w", hash1, resp->hash_length); if (n == -1 || n != (int)hashstringl - 1) @@ -807,35 +810,35 @@ int httpauth_digest_response_print(struct re_printf *pf, * Set cnonce and nc and recalculate the response value. * This function should be used only for unit tests * - * @param resp Httpauth_new_digest_response object pointer - * @param chall Received and decoded digest challenge - * @param method Used method - * @param user Username - * @param passwd User password - * @param entitybody Entitybody if qop=auth-int - * @param cnonce Cnonce - * @param nc_ Nonce counter + * @param resp Httpauth_new_digest_response object pointer + * @param chall Received and decoded digest challenge + * @param method Used method + * @param user Username + * @param passwd User password + * @param entitybody Entitybody if qop=auth-int + * @param cnonce Cnonce + * @param nonce_counter Nonce counter * * @return 0 if success, otherwise errorcode */ int httpauth_digest_response_set_cnonce(struct httpauth_digest_enc_resp *resp, const struct httpauth_digest_chall *chall, const struct pl *method, const char *user, const char *passwd, const char *entitybody, - const uint32_t cnonce, const uint32_t nc_) + const uint32_t cnonce, const uint32_t nonce_counter) { int err = 0, n = 0; if (!resp || !chall || !method || !passwd) return EINVAL; - n = re_snprintf(resp->cnonce, CNONCE_NC_LENGTH, "%08x", cnonce); - if (n == -1 || n != CNONCE_NC_LENGTH -1) { + n = re_snprintf(resp->cnonce, CNONCE_NC_SIZE, "%08x", cnonce); + if (n == -1 || n != CNONCE_NC_SIZE -1) { err = ERANGE; goto out; } - n = re_snprintf(resp->nc, CNONCE_NC_LENGTH, "%08x", nc_); - if (n == -1 || n != CNONCE_NC_LENGTH -1) { + n = re_snprintf(resp->nc, CNONCE_NC_SIZE, "%08x", nonce_counter); + if (n == -1 || n != CNONCE_NC_SIZE -1) { err = ERANGE; goto out; } @@ -905,8 +908,8 @@ int httpauth_digest_response_full(struct httpauth_digest_enc_resp **presp, return ENOMEM; } - resp->cnonce = mem_zalloc(CNONCE_NC_LENGTH, NULL); - resp->nc = mem_zalloc(CNONCE_NC_LENGTH, NULL); + resp->cnonce = mem_zalloc(CNONCE_NC_SIZE, NULL); + resp->nc = mem_zalloc(CNONCE_NC_SIZE, NULL); if (!resp->cnonce || !resp->nc) { err = ENOMEM; goto out; @@ -957,46 +960,46 @@ int httpauth_digest_response_full(struct httpauth_digest_enc_resp **presp, if (err) goto out; - n = re_snprintf(resp->cnonce, CNONCE_NC_LENGTH, "%08x", cnonce); - if (n == -1 || n != CNONCE_NC_LENGTH -1) { + n = re_snprintf(resp->cnonce, CNONCE_NC_SIZE, "%08x", cnonce); + if (n == -1 || n != CNONCE_NC_SIZE -1) { err = ERANGE; goto out; } - n = re_snprintf(resp->nc, CNONCE_NC_LENGTH, "%08x", nc++); - if (n == -1 || n != CNONCE_NC_LENGTH -1) { + n = re_snprintf(resp->nc, CNONCE_NC_SIZE, "%08x", nc++); + if (n == -1 || n != CNONCE_NC_SIZE -1) { err = ERANGE; goto out; } if (pl_strstr(&chall->algorithm, "SHA256-sess")) { - resp->hash_function = &sha256; + resp->hashh = &sha256; resp->hash_length = SHA256_DIGEST_LENGTH; err = str_dup(&resp->algorithm, "SHA256-sess"); } else if (pl_strstr(&chall->algorithm, "SHA256")) { - resp->hash_function = &sha256; + resp->hashh = &sha256; resp->hash_length = SHA256_DIGEST_LENGTH; err = str_dup(&resp->algorithm, "SHA256"); } else if (pl_strstr(&chall->algorithm, "SHA1-sess")) { - resp->hash_function = &sha1; + resp->hashh = &sha1; resp->hash_length = SHA_DIGEST_LENGTH; err = str_dup(&resp->algorithm, "SHA1-sess"); } else if (pl_strstr(&chall->algorithm, "SHA1")) { - resp->hash_function = &sha1; + resp->hashh = &sha1; resp->hash_length = SHA_DIGEST_LENGTH; err = str_dup(&resp->algorithm, "SHA1"); } else if (pl_strstr(&chall->algorithm, "MD5-sess")) { - resp->hash_function = &md5; + resp->hashh = &md5; resp->hash_length = MD5_SIZE; err = str_dup(&resp->algorithm, "MD5-sess"); } else if (!pl_isset(&chall->algorithm) || pl_strstr(&chall->algorithm, "MD5")) { - resp->hash_function = &md5; + resp->hashh = &md5; resp->hash_length = MD5_SIZE; err = str_dup(&resp->algorithm, "MD5"); } From d72cb04c6753bce2de582124b06d49d772a3865e Mon Sep 17 00:00:00 2001 From: Christoph Huber Date: Thu, 14 Sep 2023 09:44:46 +0200 Subject: [PATCH 4/8] httpauth: remove SHA1 support --- src/httpauth/digest.c | 20 +++------- test/httpauth.c | 89 ++++++------------------------------------- 2 files changed, 16 insertions(+), 93 deletions(-) diff --git a/src/httpauth/digest.c b/src/httpauth/digest.c index dcf0fc98d..73aa9e50a 100644 --- a/src/httpauth/digest.c +++ b/src/httpauth/digest.c @@ -824,7 +824,7 @@ int httpauth_digest_response_print(struct re_printf *pf, int httpauth_digest_response_set_cnonce(struct httpauth_digest_enc_resp *resp, const struct httpauth_digest_chall *chall, const struct pl *method, const char *user, const char *passwd, const char *entitybody, - const uint32_t cnonce, const uint32_t nonce_counter) + uint32_t cnonce, uint32_t nonce_counter) { int err = 0, n = 0; @@ -972,25 +972,15 @@ int httpauth_digest_response_full(struct httpauth_digest_enc_resp **presp, goto out; } - if (pl_strstr(&chall->algorithm, "SHA256-sess")) { + if (pl_strstr(&chall->algorithm, "SHA-256-sess")) { resp->hashh = &sha256; resp->hash_length = SHA256_DIGEST_LENGTH; - err = str_dup(&resp->algorithm, "SHA256-sess"); + err = str_dup(&resp->algorithm, "SHA-256-sess"); } - else if (pl_strstr(&chall->algorithm, "SHA256")) { + else if (pl_strstr(&chall->algorithm, "SHA-256")) { resp->hashh = &sha256; resp->hash_length = SHA256_DIGEST_LENGTH; - err = str_dup(&resp->algorithm, "SHA256"); - } - else if (pl_strstr(&chall->algorithm, "SHA1-sess")) { - resp->hashh = &sha1; - resp->hash_length = SHA_DIGEST_LENGTH; - err = str_dup(&resp->algorithm, "SHA1-sess"); - } - else if (pl_strstr(&chall->algorithm, "SHA1")) { - resp->hashh = &sha1; - resp->hash_length = SHA_DIGEST_LENGTH; - err = str_dup(&resp->algorithm, "SHA1"); + err = str_dup(&resp->algorithm, "SHA-256"); } else if (pl_strstr(&chall->algorithm, "MD5-sess")) { resp->hashh = &md5; diff --git a/test/httpauth.c b/test/httpauth.c index c17abe6af..1053dc8a3 100644 --- a/test/httpauth.c +++ b/test/httpauth.c @@ -374,38 +374,23 @@ int test_httpauth_digest_request(void) }, { "Digest realm=\"/my/home\", qop=\"auth\"," - " nonce=\"%s\", algorithm=SHA256", + " nonce=\"%s\", algorithm=SHA-256", "/my/home", NULL, "localhost:5060", NULL, false, - "SHA256", "auth", NULL, false, 0 + "SHA-256", "auth", NULL, false, 0 }, { "Digest realm=\"/my/home\", qop=\"auth\"," - " nonce=\"%s\", algorithm=SHA256-sess, stale=true", + " nonce=\"%s\", algorithm=SHA-256-sess, stale=true", "/my/home", NULL, "localhost:5060", NULL, true, - "SHA256-sess", "auth", NULL, false, 0 + "SHA-256-sess", "auth", NULL, false, 0 }, { "Digest realm=\"/my/home\", qop=\"auth\"," - " nonce=\"%s\", algorithm=SHA1," - " stale=true, userhash=true", - "/my/home", NULL, "localhost:5060", NULL, true, - "SHA1", "auth", NULL, true, 0 - }, - { - "Digest realm=\"/my/home\", qop=\"auth\"," - " nonce=\"%s\", algorithm=SHA1-sess," - " domain=\"example.com\", stale=true," - " charset=\"UTF-8\", userhash=true", - "/my/home", "example.com", "localhost:5060", NULL, - true, "SHA1-sess", "auth", "UTF-8", true, 0 - }, - { - "Digest realm=\"/my/home\", qop=\"auth\"," - " nonce=\"%s\", algorithm=SHA256," + " nonce=\"%s\", algorithm=SHA-256," " domain=\"example.com\", stale=true," " charset=\"UTF-8\", userhash=true", "/my/home", "example.com", "localhost:5060", NULL, - true, "SHA256", "auth", "UTF-8", true, 0 + true, "SHA-256", "auth", "UTF-8", true, 0 }, { "Digest realm=\"/my/home\", qop=\"auth-int\"," @@ -415,14 +400,6 @@ int test_httpauth_digest_request(void) "/my/home", "example.com", "localhost:5060", NULL, true, "MD5-sess", "auth-int", "UTF-8", true, 0 }, - { - "Digest realm=\"/my/home\", qop=\"auth-int\"," - " nonce=\"%s\", algorithm=SHA1-sess," - " domain=\"example.com\", stale=true," - " charset=\"UTF-8\", userhash=true", - "/my/home", "example.com", "213579023", NULL, - true, "SHA1-sess", "auth-int", "UTF-8", true, 0 - }, { "Digest realm=\"/my/home\", qop=\"auth-int\"," " nonce=\"%s\", algorithm=MD5," @@ -550,29 +527,7 @@ int test_httpauth_digest_response(void) PL("b5c64f319d37323ac652b77012817ccaa" "6e9a7e4e7563155f1f9556414dd4615"), PL("324DF3428BCF42D29A"), PL_INIT, - PL("SHA1"), PL("auth"), PL_INIT, PL_INIT, - PL_INIT - }, - "retest", "sec_pwd_retest", "auth", PL("GET"), - "example.com/my/home/something", NULL, - "417bd44d62c73baa0f0291fb36d4777878369544", - - "Digest realm=\"/my/home\"," - " nonce=\"b5c64f319d37323ac652b77012817ccaa6e9a" - "7e4e7563155f1f9556414dd4615\","" username=\"retest\"," - " uri=\"example.com/my/home/something\"," - " response=\"417bd44d62c73baa0f0291fb36d4777878" - "369544\", opaque=\"324DF3428BCF42D29A\"," - " algorithm=SHA1, qop=auth, cnonce=\"deadbeef\"," - " nc=\"00000001\"", - }, - { - { - PL("/my/home"), - PL("b5c64f319d37323ac652b77012817ccaa" - "6e9a7e4e7563155f1f9556414dd4615"), - PL("324DF3428BCF42D29A"), PL_INIT, - PL("SHA256"), PL("auth"), PL_INIT, PL_INIT, + PL("SHA-256"), PL("auth"), PL_INIT, PL_INIT, PL_INIT }, "retest", "sec_pwd_retest", "auth", PL("GET"), @@ -586,7 +541,7 @@ int test_httpauth_digest_response(void) " uri=\"example.com/my/home/something\"," " response=\"c22b56ce81bbb59570f0fbbc0ba27210dbbfcb2b2" "3fea371d214722f319dc41c\"," - " opaque=\"324DF3428BCF42D29A\", algorithm=SHA256," + " opaque=\"324DF3428BCF42D29A\", algorithm=SHA-256," " qop=auth, cnonce=\"deadbeef\", nc=\"00000001\"", }, { @@ -616,30 +571,8 @@ int test_httpauth_digest_response(void) PL("b5c64f319d37323ac652b77012817ccaa" "6e9a7e4e7563155f1f9556414dd4615"), PL("324DF3428BCF42D29A"), PL_INIT, - PL("SHA1"), PL("auth-int"), PL_INIT, PL_INIT, - PL_INIT - }, - "retest", "sec_pwd_retest", "auth-int", PL("GET"), - "example.com/my/home/something", "a text body", - "1565b20cc176a3eed8cd0318600cf3caf96fd23c", - - "Digest realm=\"/my/home\"," - " nonce=\"b5c64f319d37323ac652b77012817ccaa6e9a7e4e756" - "3155f1f9556414dd4615\", username=\"retest\"," - " uri=\"example.com/my/home/something\"," - " response=\"1565b20cc176a3eed8cd0318600cf3caf96f" - "d23c\", opaque=\"324DF3428BCF42D29A\"," - " algorithm=SHA1, qop=auth-int, cnonce=\"deadbeef\"," - " nc=\"00000001\"", - }, - { - { - PL("/my/home"), - PL("b5c64f319d37323ac652b77012817ccaa" - "6e9a7e4e7563155f1f9556414dd4615"), - PL("324DF3428BCF42D29A"), PL_INIT, - PL("SHA256"), PL("auth-int"), PL_INIT, PL_INIT, - PL_INIT + PL("SHA-256"), PL("auth-int"), PL_INIT, + PL_INIT, PL_INIT }, "retest", "sec_pwd_retest", "auth-int", PL("GET"), "example.com/my/home/something", "", @@ -652,7 +585,7 @@ int test_httpauth_digest_response(void) " uri=\"example.com/my/home/something\"," " response=\"2c0746b7174441314164d8d9a980d8920732de32e" "16303f0e6a82970230e79e4\"," - " opaque=\"324DF3428BCF42D29A\", algorithm=SHA256," + " opaque=\"324DF3428BCF42D29A\", algorithm=SHA-256," " qop=auth-int, cnonce=\"deadbeef\", nc=\"00000001\"", }, }; From 11ee127515d7c7313bb23417d30c8f51927e393c Mon Sep 17 00:00:00 2001 From: Christoph Huber Date: Wed, 20 Sep 2023 08:26:00 +0200 Subject: [PATCH 5/8] httpauth: save cnonce and nc as uint32_t in struct. --- include/re_httpauth.h | 4 ++-- src/httpauth/digest.c | 52 +++++++++---------------------------------- 2 files changed, 12 insertions(+), 44 deletions(-) diff --git a/include/re_httpauth.h b/include/re_httpauth.h index 83fbebf45..758a90862 100644 --- a/include/re_httpauth.h +++ b/include/re_httpauth.h @@ -47,8 +47,8 @@ struct httpauth_digest_enc_resp { char *username; char *username_star; char *uri; - char *cnonce; - char *nc; + uint32_t cnonce; + uint32_t nc; /* optional */ char *charset; diff --git a/src/httpauth/digest.c b/src/httpauth/digest.c index 73aa9e50a..06e4d90ab 100644 --- a/src/httpauth/digest.c +++ b/src/httpauth/digest.c @@ -628,8 +628,6 @@ static void httpauth_digest_response_destructor(void *arg) mem_deref(resp->username); mem_deref(resp->username_star); mem_deref(resp->uri); - mem_deref(resp->cnonce); - mem_deref(resp->nc); mem_deref(resp->charset); } @@ -724,7 +722,7 @@ static int digest_response(struct httpauth_digest_enc_resp *resp, mbuf_rewind(mb); if (str_str(resp->algorithm, "-sess")) { - err = mbuf_printf(mb, "%w:%s:%s", + err = mbuf_printf(mb, "%w:%s:%08x", hash1, resp->hash_length, resp->nonce, resp->cnonce); if (err) goto out; @@ -735,7 +733,7 @@ static int digest_response(struct httpauth_digest_enc_resp *resp, /* DIGEST */ if (str_isset(resp->qop)) { - err = mbuf_printf(mb, "%w:%s:%s:%s:%s:%w", + err = mbuf_printf(mb, "%w:%s:%08x:%08x:%s:%w", hash1, resp->hash_length, resp->nonce, resp->nc, resp->cnonce, resp->qop, hash2, resp->hash_length); } @@ -794,7 +792,7 @@ int httpauth_digest_response_print(struct re_printf *pf, if (str_isset(resp->algorithm)) err |= re_hprintf(pf, ", algorithm=%s", resp->algorithm); if (str_isset(resp->qop)) - err |= re_hprintf(pf, ", qop=%s, cnonce=\"%s\", nc=\"%s\"", + err |= re_hprintf(pf, ", qop=%s, cnonce=\"%08x\", nc=\"%08x\"", resp->qop, resp->cnonce, resp->nc); if (resp->userhash) @@ -826,28 +824,14 @@ int httpauth_digest_response_set_cnonce(struct httpauth_digest_enc_resp *resp, const char *user, const char *passwd, const char *entitybody, uint32_t cnonce, uint32_t nonce_counter) { - int err = 0, n = 0; - if (!resp || !chall || !method || !passwd) return EINVAL; - n = re_snprintf(resp->cnonce, CNONCE_NC_SIZE, "%08x", cnonce); - if (n == -1 || n != CNONCE_NC_SIZE -1) { - err = ERANGE; - goto out; - } + resp->cnonce = cnonce; + resp->nc = nonce_counter; - n = re_snprintf(resp->nc, CNONCE_NC_SIZE, "%08x", nonce_counter); - if (n == -1 || n != CNONCE_NC_SIZE -1) { - err = ERANGE; - goto out; - } - - err = digest_response(resp, chall, method, + return digest_response(resp, chall, method, user, passwd, entitybody); - -out: - return err; } @@ -897,8 +881,7 @@ int httpauth_digest_response_full(struct httpauth_digest_enc_resp **presp, const char *entitybody, const char *charset, const bool userhash) { struct httpauth_digest_enc_resp *resp = NULL; - uint32_t cnonce = rand_u32(); - int err = 0, n = 0; + int err = 0; if (!presp || !chall || !method || !uri || !user || !passwd) return EINVAL; @@ -908,12 +891,9 @@ int httpauth_digest_response_full(struct httpauth_digest_enc_resp **presp, return ENOMEM; } - resp->cnonce = mem_zalloc(CNONCE_NC_SIZE, NULL); - resp->nc = mem_zalloc(CNONCE_NC_SIZE, NULL); - if (!resp->cnonce || !resp->nc) { - err = ENOMEM; - goto out; - } + /* create cnonce & nonce count */ + resp->cnonce = rand_u32(); + resp->nc = nc++; /* copy fields */ err = pl_strdup(&resp->realm, &chall->realm); @@ -960,18 +940,6 @@ int httpauth_digest_response_full(struct httpauth_digest_enc_resp **presp, if (err) goto out; - n = re_snprintf(resp->cnonce, CNONCE_NC_SIZE, "%08x", cnonce); - if (n == -1 || n != CNONCE_NC_SIZE -1) { - err = ERANGE; - goto out; - } - - n = re_snprintf(resp->nc, CNONCE_NC_SIZE, "%08x", nc++); - if (n == -1 || n != CNONCE_NC_SIZE -1) { - err = ERANGE; - goto out; - } - if (pl_strstr(&chall->algorithm, "SHA-256-sess")) { resp->hashh = &sha256; resp->hash_length = SHA256_DIGEST_LENGTH; From bfa18128a12711111eef26d84ab577c98bc881cd Mon Sep 17 00:00:00 2001 From: Christoph Huber Date: Wed, 20 Sep 2023 08:27:10 +0200 Subject: [PATCH 6/8] httpauth: change loop counter to size_t --- test/httpauth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/httpauth.c b/test/httpauth.c index 1053dc8a3..cc0c91ec4 100644 --- a/test/httpauth.c +++ b/test/httpauth.c @@ -411,7 +411,7 @@ int test_httpauth_digest_request(void) }; int err = 0; - for (unsigned int i = 0; i < RE_ARRAY_SIZE(testv); i++) { + for (size_t i = 0; i < RE_ARRAY_SIZE(testv); i++) { struct httpauth_digest_chall_req *req = NULL; struct mbuf *mb_refval = NULL; struct mbuf *mb_printed = NULL; @@ -592,7 +592,7 @@ int test_httpauth_digest_response(void) int err; - for (unsigned int i = 0; i < RE_ARRAY_SIZE(testv); i++) { + for (size_t i = 0; i < RE_ARRAY_SIZE(testv); i++) { struct httpauth_digest_enc_resp *resp = NULL; struct mbuf *mb_printed = NULL; From 09cfe5cddaa229f896dcdde25f15af9f58b9262e Mon Sep 17 00:00:00 2001 From: Christoph Huber Date: Thu, 19 Oct 2023 09:32:16 +0200 Subject: [PATCH 7/8] httpauth: remove unused enum --- src/httpauth/digest.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/httpauth/digest.c b/src/httpauth/digest.c index 06e4d90ab..5bd6c3a25 100644 --- a/src/httpauth/digest.c +++ b/src/httpauth/digest.c @@ -16,11 +16,6 @@ #include -enum { - CNONCE_NC_SIZE = 9, /* 8 characters + '\0' */ -}; - - typedef void (digest_decode_h)(const struct pl *name, const struct pl *val, void *arg); From c0bcd402305668a3812e7b4b5f20935581f2a147 Mon Sep 17 00:00:00 2001 From: Christoph Huber Date: Thu, 19 Oct 2023 09:36:50 +0200 Subject: [PATCH 8/8] README: update RFC list, add RFC 7616 - HTTP Digest Access Authentication --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e992a7a4b..930ea1afd 100644 --- a/README.md +++ b/README.md @@ -218,6 +218,7 @@ legend: * [RFC 6455](https://tools.ietf.org/html/rfc6455) - The WebSocket Protocol * [RFC 7159](https://tools.ietf.org/html/rfc7159) - JavaScript Object Notation (JSON) * [RFC 7350](https://tools.ietf.org/html/rfc7350) - DTLS as Transport for STUN +* [RFC 7616](https://tools.ietf.org/html/rfc7616) - HTTP Digest Access Authentication * [RFC 7714](https://tools.ietf.org/html/rfc7714) - AES-GCM Authenticated Encryption in SRTP