libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit c3680cb737bcac2a4dc14cca5a80af6ca0de21e7
parent 2699d2782011e97cf0b2563dab03d7237fb8fdb6
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Mon,  5 Sep 2022 14:53:05 +0300

Digest Auth API: do not store 'userhash' in 'username' members

While the 'username' is used to carry 'userhash' in headers, it is
confusing as 'userhash' type of the data is different from type of
the 'username'. To make a clear distinction, use dedicated members
to store 'userhash'.

Diffstat:
Msrc/include/microhttpd.h | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/microhttpd/digestauth.c | 54++++++++++++++++++++++++++++++++----------------------
Msrc/testcurl/test_digestauth2.c | 62+++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/testcurl/test_digestauth_emu_ext.c | 8++++++++
4 files changed, 138 insertions(+), 65 deletions(-)

diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -96,7 +96,7 @@ extern "C" * they are parsed as decimal numbers. * Example: 0x01093001 = 1.9.30-1. */ -#define MHD_VERSION 0x00097536 +#define MHD_VERSION 0x00097537 /* If generic headers don't work on your platform, include headers which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', 'off_t', @@ -4738,7 +4738,16 @@ MHD_digest_auth_calc_userhash_hex (enum MHD_DigestAuthAlgo3 algo3, /** * The type of username used by client in Digest Authorization header * - * @note Available since #MHD_VERSION 0x00097519 + * Values are sorted so simplified checks could be used. + * For example: + * * (value <= MHD_DIGEST_AUTH_UNAME_TYPE_INVALID) is true if not valid username + * is provided by the client + * * (value >= MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH) is true if username is + * provided in any form + * * (value >= MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD) is true if username is + * provided in clear text (not userhash matching is needed) + * + * @note Available since #MHD_VERSION 0x00097537 */ enum MHD_DigestAuthUsernameType { @@ -4751,7 +4760,7 @@ enum MHD_DigestAuthUsernameType /** * The 'username' parameter is used to specify the username. */ - MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD = 1, + MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD = (1 << 2), /** * The username is specified by 'username*' parameter with @@ -4759,14 +4768,14 @@ enum MHD_DigestAuthUsernameType * The only difference between standard and extended types is * the way how username value is encoded in the header. */ - MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED = 2, + MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED = (1 << 3), /** * The username provided in form of 'userhash' as * specified by RFC 7616 #section-3.4.4. * @sa #MHD_digest_auth_calc_userhash_hex(), #MHD_digest_auth_calc_userhash() */ - MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH = 3, + MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH = (1 << 1), /** * The invalid combination of username parameters are used by client. @@ -4776,7 +4785,7 @@ enum MHD_DigestAuthUsernameType * * 'username*' used with invalid extended notation * * 'username' is not hexadecimal digits, while 'userhash' set to 'true' */ - MHD_DIGEST_AUTH_UNAME_TYPE_INVALID = 15 + MHD_DIGEST_AUTH_UNAME_TYPE_INVALID = (1 << 0) } _MHD_FIXED_ENUM; /** @@ -4883,7 +4892,7 @@ enum MHD_DigestAuthMultiQOP * * Application may modify buffers as needed until #MHD_free() is called for * pointer to this structure - * @note Available since #MHD_VERSION 0x00097533 + * @note Available since #MHD_VERSION 0x00097537 */ struct MHD_DigestAuthInfo { @@ -4902,14 +4911,12 @@ struct MHD_DigestAuthInfo /** * The username string. - * Valid only if username is standard, extended, or userhash. - * For userhash this is unqoted string without decoding of the - * hexadecimal digits (as provided by the client). + * Used only if username type is standard or extended, always NULL otherwise. * If extended notation is used, this string is pct-decoded string * with charset and language tag removed (i.e. it is original username * extracted from the extended notation). - * This can be NULL is username is missing or invalid. - * @sa #MHD_digest_auth_calc_userhash_hex() + * When userhash is used by the client, this member is NULL and + * @a userhash_hex is set. */ char *username; @@ -4920,11 +4927,27 @@ struct MHD_DigestAuthInfo size_t username_len; /** + * The userhash string. + * Valid only if username type is userhash. + * This is unqoted string without decoding of the hexadecimal + * digits (as provided by the client). + * @sa #MHD_digest_auth_calc_userhash_hex() + */ + char *userhash_hex; + + /** + * The length of the @a userhash_hex in characters. + * The valid size should be #MHD_digest_get_hash_size(algo3) * 2 characters. + * When the @a userhash_hex is NULL, this member is always zero. + */ + size_t userhash_hex_len; + + /** * The userhash decoded to binary form. * Used only if username type is userhash, always NULL otherwise. - * When not NULL, this points to binary sequence @a username_len /2 bytes + * When not NULL, this points to binary sequence @a userhash_hex_len /2 bytes * long. - * The valid size should be #MHD_digest_get_hash_size(algo) bytes. + * The valid size should be #MHD_digest_get_hash_size(algo3) bytes. * @warning This is binary data, no zero termination. * @warning To avoid buffer overruns, always check the size of the data before * use, because @a userhash_bin can point even to zero-sized @@ -5007,7 +5030,7 @@ MHD_digest_auth_get_request_info3 (struct MHD_Connection *connection); * * Application may modify buffers as needed until #MHD_free() is called for * pointer to this structure - * @note Available since #MHD_VERSION 0x00097534 + * @note Available since #MHD_VERSION 0x00097537 */ struct MHD_DigestAuthUsernameInfo { @@ -5028,12 +5051,12 @@ struct MHD_DigestAuthUsernameInfo /** * The username string. - * For userhash this is unqoted string without decoding of the - * hexadecimal digits (as provided by client). + * Used only if username type is standard or extended, always NULL otherwise. * If extended notation is used, this string is pct-decoded string * with charset and language tag removed (i.e. it is original username * extracted from the extended notation). - * @sa #MHD_digest_auth_calc_userhash_hex() + * When userhash is used by the client, this member is NULL and + * @a userhash_hex is set. */ char *username; @@ -5044,11 +5067,27 @@ struct MHD_DigestAuthUsernameInfo size_t username_len; /** + * The userhash string. + * Valid only if username type is userhash. + * This is unqoted string without decoding of the hexadecimal + * digits (as provided by the client). + * @sa #MHD_digest_auth_calc_userhash_hex() + */ + char *userhash_hex; + + /** + * The length of the @a userhash_hex in characters. + * The valid size should be #MHD_digest_get_hash_size(algo3) * 2 characters. + * When the @a userhash_hex is NULL, this member is always zero. + */ + size_t userhash_hex_len; + + /** * The userhash decoded to binary form. * Used only if username type is userhash, always NULL otherwise. - * When not NULL, this points to binary sequence @a username_len /2 bytes + * When not NULL, this points to binary sequence @a userhash_hex_len /2 bytes * long. - * The valid size should be #MHD_digest_get_hash_size(algo) bytes. + * The valid size should be #MHD_digest_get_hash_size(algo3) bytes. * @warning This is binary data, no zero termination. * @warning To avoid buffer overruns, always check the size of the data before * use, because @a userhash_bin can point even to zero-sized diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c @@ -801,37 +801,47 @@ get_rq_uname (const struct MHD_RqDAuth *params, mhd_assert (MHD_DIGEST_AUTH_UNAME_TYPE_INVALID != uname_type); mhd_assert (MHD_DIGEST_AUTH_UNAME_TYPE_MISSING != uname_type); - if ( (MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD == uname_type) || - (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH == uname_type) ) + uname_info->username = NULL; + uname_info->username_len = 0; + uname_info->userhash_hex = NULL; + uname_info->userhash_hex_len = 0; + uname_info->userhash_bin = NULL; + + if (MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD == uname_type) { uname_info->username = (char *) (buf + buf_used); uname_info->username_len = get_rq_param_unquoted_copy_z (&params->username, uname_info->username); buf_used += uname_info->username_len + 1; - if (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH == uname_type) + uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD; + } + else if (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH == uname_type) + { + size_t res; + + uname_info->userhash_hex = (char *) (buf + buf_used); + uname_info->userhash_hex_len = + get_rq_param_unquoted_copy_z (&params->username, + uname_info->userhash_hex); + buf_used += uname_info->userhash_hex_len + 1; + uname_info->userhash_bin = (uint8_t *) (buf + buf_used); + res = MHD_hex_to_bin (uname_info->userhash_hex, + uname_info->userhash_hex_len, + uname_info->userhash_bin); + if (res != uname_info->username_len / 2) { - size_t res; - uint8_t *const bin_data = (uint8_t *) (buf + buf_used); - res = MHD_hex_to_bin (uname_info->username, - uname_info->username_len, - bin_data); - if (res != uname_info->username_len / 2) - { - uname_info->userhash_bin = NULL; - uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_INVALID; - } - else - { - /* Avoid pointers outside allocated region when the size is zero */ - uname_info->userhash_bin = (0 != res) ? - bin_data : (uint8_t *) uname_info->username; - uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH; - buf_used += res; - } + uname_info->userhash_bin = NULL; + uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_INVALID; } else - uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD; + { + /* Avoid pointers outside allocated region when the size is zero */ + if (0 == res) + uname_info->userhash_bin = (uint8_t *) uname_info->username; + uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH; + buf_used += res; + } } else if (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED == uname_type) { diff --git a/src/testcurl/test_digestauth2.c b/src/testcurl/test_digestauth2.c @@ -476,8 +476,6 @@ ahc_echo (void *cls, enum MHD_DigestAuthResult check_res; enum MHD_DigestAuthResult expect_res; - if (NULL == dinfo->username) - mhdErrorExitDesc ("'username' is NULL"); if (curl_uses_usehash) { if (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH != dinfo->uname_type) @@ -488,29 +486,33 @@ ahc_echo (void *cls, (int) dinfo->uname_type); mhdErrorExitDesc ("Wrong 'uname_type'"); } - else if (dinfo->username_len != userhash_hex_len) + else if (dinfo->userhash_hex_len != userhash_hex_len) { - fprintf (stderr, "'username_len' does not match.\n" + fprintf (stderr, "'userhash_hex_len' does not match.\n" "Expected: %u\tRecieved: %u. ", (unsigned) userhash_hex_len, - (unsigned) dinfo->username_len); - mhdErrorExitDesc ("Wrong 'username_len'"); + (unsigned) dinfo->userhash_hex_len); + mhdErrorExitDesc ("Wrong 'userhash_hex_len'"); } - else if (0 != memcmp (dinfo->username, userhash_hex, - dinfo->username_len)) + else if (0 != memcmp (dinfo->userhash_hex, userhash_hex, + dinfo->userhash_hex_len)) { - fprintf (stderr, "'username' does not match.\n" + fprintf (stderr, "'userhash_hex' does not match.\n" "Expected: '%s'\tRecieved: '%.*s'. ", userhash_hex, - (int) dinfo->username_len, - dinfo->username); - mhdErrorExitDesc ("Wrong 'username'"); + (int) dinfo->userhash_hex_len, + dinfo->userhash_hex); + mhdErrorExitDesc ("Wrong 'userhash_hex'"); } else if (NULL == dinfo->userhash_bin) mhdErrorExitDesc ("'userhash_bin' is NULL"); else if (0 != memcmp (dinfo->userhash_bin, userhash_bin, dinfo->username_len / 2)) mhdErrorExitDesc ("Wrong 'userhash_bin'"); + else if (NULL != dinfo->username) + mhdErrorExitDesc ("'username' is NOT NULL"); + else if (0 != dinfo->username_len) + mhdErrorExitDesc ("'username_len' is NOT zero"); } else { @@ -522,6 +524,8 @@ ahc_echo (void *cls, (int) dinfo->uname_type); mhdErrorExitDesc ("Wrong 'uname_type'"); } + else if (NULL == dinfo->username) + mhdErrorExitDesc ("'username' is NULL"); else if (dinfo->username_len != strlen (username_ptr)) { fprintf (stderr, "'username_len' does not match.\n" @@ -540,6 +544,10 @@ ahc_echo (void *cls, dinfo->username); mhdErrorExitDesc ("Wrong 'username'"); } + else if (NULL != dinfo->userhash_hex) + mhdErrorExitDesc ("'userhash_hex' is NOT NULL"); + else if (0 != dinfo->userhash_hex_len) + mhdErrorExitDesc ("'userhash_hex_len' is NOT zero"); else if (NULL != dinfo->userhash_bin) mhdErrorExitDesc ("'userhash_bin' is NOT NULL"); } @@ -620,8 +628,6 @@ ahc_echo (void *cls, uname = MHD_digest_auth_get_username3 (connection); if (NULL == uname) mhdErrorExitDesc ("MHD_digest_auth_get_username3() returned NULL"); - else if (NULL == uname->username) - mhdErrorExitDesc ("'username' is NULL"); if (curl_uses_usehash) { if (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH != uname->uname_type) @@ -632,29 +638,33 @@ ahc_echo (void *cls, (int) uname->uname_type); mhdErrorExitDesc ("Wrong 'uname_type'"); } - else if (uname->username_len != userhash_hex_len) + else if (uname->userhash_hex_len != userhash_hex_len) { - fprintf (stderr, "'username_len' does not match.\n" + fprintf (stderr, "'userhash_hex_len' does not match.\n" "Expected: %u\tRecieved: %u. ", (unsigned) userhash_hex_len, - (unsigned) uname->username_len); - mhdErrorExitDesc ("Wrong 'username_len'"); + (unsigned) uname->userhash_hex_len); + mhdErrorExitDesc ("Wrong 'userhash_hex_len'"); } - else if (0 != memcmp (uname->username, userhash_hex, - uname->username_len)) + else if (0 != memcmp (uname->userhash_hex, userhash_hex, + uname->userhash_hex_len)) { fprintf (stderr, "'username' does not match.\n" "Expected: '%s'\tRecieved: '%.*s'. ", userhash_hex, - (int) uname->username_len, - uname->username); - mhdErrorExitDesc ("Wrong 'username'"); + (int) uname->userhash_hex_len, + uname->userhash_hex); + mhdErrorExitDesc ("Wrong 'userhash_hex'"); } else if (NULL == uname->userhash_bin) mhdErrorExitDesc ("'userhash_bin' is NULL"); else if (0 != memcmp (uname->userhash_bin, userhash_bin, uname->username_len / 2)) mhdErrorExitDesc ("Wrong 'userhash_bin'"); + else if (NULL != uname->username) + mhdErrorExitDesc ("'username' is NOT NULL"); + else if (0 != uname->username_len) + mhdErrorExitDesc ("'username_len' is NOT zero"); } else { @@ -666,6 +676,8 @@ ahc_echo (void *cls, (int) uname->uname_type); mhdErrorExitDesc ("Wrong 'uname_type'"); } + else if (NULL == uname->username) + mhdErrorExitDesc ("'username' is NULL"); else if (uname->username_len != strlen (username_ptr)) { fprintf (stderr, "'username_len' does not match.\n" @@ -684,6 +696,10 @@ ahc_echo (void *cls, uname->username); mhdErrorExitDesc ("Wrong 'username'"); } + else if (NULL != uname->userhash_hex) + mhdErrorExitDesc ("'userhash_hex' is NOT NULL"); + else if (0 != uname->userhash_hex_len) + mhdErrorExitDesc ("'userhash_hex_len' is NOT zero"); else if (NULL != uname->userhash_bin) mhdErrorExitDesc ("'userhash_bin' is NOT NULL"); } diff --git a/src/testcurl/test_digestauth_emu_ext.c b/src/testcurl/test_digestauth_emu_ext.c @@ -381,6 +381,10 @@ ahc_echo (void *cls, creds->username); mhdErrorExitDesc ("Wrong 'username'"); } + else if (NULL != creds->userhash_hex) + mhdErrorExitDesc ("'userhash_hex' is NOT NULL"); + else if (0 != creds->userhash_hex_len) + mhdErrorExitDesc ("'userhash_hex' is NOT zero"); else if (NULL != creds->userhash_bin) mhdErrorExitDesc ("'userhash_bin' is NOT NULL"); MHD_free (creds); @@ -415,6 +419,10 @@ ahc_echo (void *cls, dinfo->username); mhdErrorExitDesc ("Wrong 'username'"); } + else if (NULL != dinfo->userhash_hex) + mhdErrorExitDesc ("'userhash_hex' is NOT NULL"); + else if (0 != dinfo->userhash_hex_len) + mhdErrorExitDesc ("'userhash_hex' is NOT zero"); else if (NULL != dinfo->userhash_bin) mhdErrorExitDesc ("'userhash_bin' is NOT NULL"); else if (MHD_DIGEST_AUTH_ALGO3_MD5 != dinfo->algo3)