libmicrohttpd

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

commit 8318f56ebc0085f1319f29862b74b65304894afe
parent 9fa5a3b990f93b94557bc2f52aaff8db241702a7
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Sun, 11 Sep 2022 18:39:46 +0300

digestauth: added support for SHA-512/256, made MD5 and SHA-256 optional

Give more flexibility for custom builds: MD5, SHA-256 and SHA-512/256
may be disabled individually.

Diffstat:
Mconfigure.ac | 72+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/include/microhttpd.h | 47++++++++++++++++++++++++++++-------------------
Msrc/microhttpd/Makefile.am | 20++++++++++++++++----
Msrc/microhttpd/daemon.c | 8++++----
Msrc/microhttpd/digestauth.c | 333++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/microhttpd/gen_auth.c | 30+++++++++++++++---------------
Msrc/microhttpd/internal.h | 10+++++++---
Msrc/microhttpd/test_dauth_userdigest.c | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/microhttpd/test_dauth_userhash.c | 233+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/testcurl/Makefile.am | 24+++++++++++++++++-------
10 files changed, 878 insertions(+), 100 deletions(-)

diff --git a/configure.ac b/configure.ac @@ -3082,9 +3082,63 @@ AS_VAR_IF([[enable_cookie]],[["yes"]], AM_CONDITIONAL([ENABLE_COOKIE], [[test "x$enable_cookie" = "xyes"]]) AC_MSG_RESULT([[$enable_cookie]]) +# optional: MD5 support for Digest Auth. Enabled by default. +AC_ARG_ENABLE([[md5]], + [AS_HELP_STRING([[--disable-md5]],[disable MD5 hashing support for Digest Authentication]) + ], + [ + AS_VAR_IF([[enable_md5]],[["yes"]], + [ + AS_VAR_IF([enable_dauth],["yes"],[], + [ + AC_MSG_WARN([The parameter --enable-md5 is ignored as Digest Authentication is disabled]) + enable_md5='no' + ] + ) + ],[[enable_md5='no']] + ) + ], [[enable_md5="${enable_dauth}"]] +) +AC_MSG_CHECKING([[whether to support MD5]]) +AS_VAR_IF([[enable_md5]],[["yes"]], + [ + AC_DEFINE([[MHD_MD5_SUPPORT]],[[1]], + [Define to 1 if libmicrohttpd is compiled with MD5 hashing support.]) + ] +) +AM_CONDITIONAL([ENABLE_MD5], [[test "x${enable_md5}" = "xyes"]]) +AC_MSG_RESULT([[${enable_md5}]]) + +# optional: SHA-256 support for Digest Auth. Enabled by default. +AC_ARG_ENABLE([[sha256]], + [AS_HELP_STRING([[--disable-sha256]],[disable SHA-256 hashing support for Digest Authentication]) + ], + [ + AS_VAR_IF([[enable_sha256]],[["yes"]], + [ + AS_VAR_IF([enable_dauth],["yes"],[], + [ + AC_MSG_WARN([The parameter --enable-sha256 is ignored as Digest Authentication is disabled]) + enable_sha256='no' + ] + ) + ],[[enable_sha256='no']] + ) + ], [[enable_sha256="${enable_dauth}"]] +) +AC_MSG_CHECKING([[whether to support SHA-256]]) +AS_VAR_IF([[enable_sha256]],[["yes"]], + [ + AC_DEFINE([[MHD_SHA256_SUPPORT]],[[1]], + [Define to 1 if libmicrohttpd is compiled with SHA-256 hashing support.]) + ] +) +AM_CONDITIONAL([ENABLE_SHA256], [[test "x${enable_sha256}" = "xyes"]]) +AC_MSG_RESULT([[${enable_sha256}]]) + # optional: SHA-512/256 support for Digest Auth. Enabled by default. AC_ARG_ENABLE([[sha512-256]], - [AS_HELP_STRING([[--disable-sha512-256]],[disable SHA-512/256 support for Digest Authentication]) + [AS_HELP_STRING([[--disable-sha512-256]],[disable SHA-512/256 hashing support for Digest Authentication]) ], [ AS_VAR_IF([[enable_sha512_256]],[["yes"]], @@ -3102,13 +3156,21 @@ AC_ARG_ENABLE([[sha512-256]], AC_MSG_CHECKING([[whether to support SHA-512/256]]) AS_VAR_IF([[enable_sha512_256]],[["yes"]], [ - AC_DEFINE([[SHA512_256_SUPPORT]],[[1]], - [Define to 1 if libmicrohttpd is compiled with SHA-512/256 support.]) + AC_DEFINE([[MHD_SHA512_256_SUPPORT]],[[1]], + [Define to 1 if libmicrohttpd is compiled with SHA-512/256 hashing support.]) ] ) AM_CONDITIONAL([ENABLE_SHA512_256], [[test "x${enable_sha512_256}" = "xyes"]]) AC_MSG_RESULT([[${enable_sha512_256}]]) +AS_IF([test "x$enable_dauth" != "xno"], + [ + AS_IF([test "x${enable_md5}" != "xyes" && test "x${enable_sha256}" != "xyes" && test "x${enable_sha512_256}" != "xyes"], + [AC_MSG_ERROR([At least one hashing algorithm must be enabled if Digest Auth is enabled])] + ) + ] +) + AC_CACHE_CHECK([[for calloc()]], [[mhd_cv_have_func_calloc]], [ @@ -3990,6 +4052,8 @@ AC_MSG_NOTICE([GNU libmicrohttpd ${PACKAGE_VERSION} Configuration Summary: Messages: ${enable_messages} Basic auth.: ${enable_bauth} Digest auth.: ${enable_dauth} + MD5: ${enable_md5} + SHA-256: ${enable_sha256} SHA-512/256: ${enable_sha512_256} HTTP "Upgrade": ${enable_httpupgrade} Cookie parsing: ${enable_cookie} @@ -4011,6 +4075,8 @@ AS_IF([test "x$enable_https" = "xyes"], AS_IF([test "x$enable_bauth" != "xyes" || \ test "x$enable_dauth" != "xyes" || \ + test "x${enable_md5}" != "xyes" || \ + test "x${enable_sha256}" != "xyes" || \ test "x${enable_sha512_256}" != "xyes" || \ test "x$enable_httpupgrade" != "xyes" || \ test "x$enable_cookie" != "xyes" || \ 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 0x00097538 +#define MHD_VERSION 0x00097539 /* If generic headers don't work on your platform, include headers which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', 'off_t', @@ -4430,7 +4430,8 @@ MHD_destroy_post_processor (struct MHD_PostProcessor *pp); /** * Length of the binary output of the SHA-512/256 hash function. - * The value is the same as the #MHD_SHA256_DIGEST_SIZE. + * @warning While this value is the same as the #MHD_SHA256_DIGEST_SIZE, + * the calculated digests for SHA-256 and SHA-512/256 are different. * @sa #MHD_digest_get_hash_size() * @note Available since #MHD_VERSION 0x00097538 * @ingroup authentication @@ -4465,22 +4466,21 @@ enum MHD_DigestBaseAlgo /** * SHA-512/256 hash algorithm. - * Not supported for calculations, only supported for parsing of - * client's authorisation headers. + * As specified by FIPS PUB 180-4 */ MHD_DIGEST_BASE_ALGO_SHA512_256 = (1 << 2) } _MHD_FIXED_FLAGS_ENUM; /** - * The flag indicating digest calculation types, - * like 'MD5' or 'SHA-256'. + * The flag indicating non-session algorithm types, + * like 'MD5', 'SHA-256' or 'SHA-512-256'. * @note Available since #MHD_VERSION 0x00097519 */ #define MHD_DIGEST_AUTH_ALGO3_NON_SESSION (1 << 6) /** * The flag indicating session algorithm types, - * like 'MD5-sess' or 'SHA-256-sess'. + * like 'MD5-sess', 'SHA-256-sess' or 'SHA-512-256-sess'. * @note Available since #MHD_VERSION 0x00097519 */ #define MHD_DIGEST_AUTH_ALGO3_SESSION (1 << 7) @@ -4528,7 +4528,6 @@ enum MHD_DigestAuthAlgo3 /** * The 'SHA-512-256' (SHA-512/256) algorithm. - * Not supported by MHD for authentication. */ MHD_DIGEST_AUTH_ALGO3_SHA512_256 = MHD_DIGEST_BASE_ALGO_SHA512_256 | MHD_DIGEST_AUTH_ALGO3_NON_SESSION, @@ -4549,8 +4548,8 @@ enum MHD_DigestAuthAlgo3 * and other parameters which size depends on used hash algorithm. * @param algo3 the algorithm to check * @return the size of the digest (either #MHD_MD5_DIGEST_SIZE or - * #MHD_SHA256_DIGEST_SIZE) or zero if the input value is not - * recognised/valid + * #MHD_SHA256_DIGEST_SIZE/MHD_SHA512_256_DIGEST_SIZE) + * or zero if the input value is not supported or not valid * @sa #MHD_digest_auth_calc_userdigest() * @sa #MHD_digest_auth_calc_userhash(), #MHD_digest_auth_calc_userhash_hex() * @note Available since #MHD_VERSION 0x00097526 @@ -4601,8 +4600,6 @@ enum MHD_DigestAuthMultiAlgo3 /** * The 'SHA-512-256' (SHA-512/256) algorithm. - * Not supported by MHD for authentication. - * Reserved value. */ MHD_DIGEST_AUTH_MULT_ALGO3_SHA512_256 = MHD_DIGEST_AUTH_ALGO3_SHA512_256, @@ -4646,6 +4643,15 @@ enum MHD_DigestAuthMultiAlgo3 | MHD_DIGEST_AUTH_MULT_ALGO3_SHA256_SESSION, /** + * The 'SHA-512/256' algorithm, session or non-session. + * Not supported by MHD. + * Reserved value. + */ + MHD_DIGEST_AUTH_MULT_ALGO3_SHA512_256_ANY = + MHD_DIGEST_AUTH_MULT_ALGO3_SHA512_256 + | MHD_DIGEST_AUTH_MULT_ALGO3_SHA512_256_SESSION, + + /** * Any algorithm, MHD will choose. */ MHD_DIGEST_AUTH_MULT_ALGO3_ANY = @@ -5317,7 +5323,8 @@ MHD_digest_auth_calc_userdigest (enum MHD_DigestAuthAlgo3 algo3, * see #MHD_digest_auth_calc_userdigest() * @param userdigest_size the size of the @a userdigest in bytes, must match the * hashing algorithm (see #MHD_MD5_DIGEST_SIZE, - * #MHD_SHA256_DIGEST_SIZE, #MHD_digest_get_hash_size()) + * #MHD_SHA256_DIGEST_SIZE, #MHD_SHA512_256_DIGEST_SIZE, + * #MHD_digest_get_hash_size()) * @param nonce_timeout the period of seconds since nonce generation, when * the nonce is recognised as valid and not stale. * @param max_nc the maximum allowed nc (Nonce Count) value, if client's nc @@ -5327,9 +5334,9 @@ MHD_digest_auth_calc_userdigest (enum MHD_DigestAuthAlgo3 algo3, * @param mqop the QOP to use * @param malgo3 digest algorithms allowed to use, fail if algorithm used * by the client is not allowed by this parameter; - * both MD5-based and SHA-256-based algorithms cannot be used at - * the same time for this function as @a userdigest_size must - * match specified algorithm + * more than one base algorithms (MD5, SHA-256, SHA-512/256) + * cannot be used at the same time for this function + * as @a userdigest must match specified algorithm * @return #MHD_DAUTH_OK if authenticated, * the error code otherwise * @sa #MHD_digest_auth_calc_userdigest() @@ -6085,7 +6092,8 @@ enum MHD_FEATURE /** * Get whether the MD5-based hashing algorithms are supported for Digest * Authorization. - * Currently it is always supported if Digest Auth module is built. + * Currently it is always supported if Digest Auth module is built + * unless manually disabled in a custom build. * @note Available since #MHD_VERSION 0x00097527 */ MHD_FEATURE_DIGEST_AUTH_MD5 = 26, @@ -6094,7 +6102,7 @@ enum MHD_FEATURE * Get whether the SHA-256-based hashing algorithms are supported for Digest * Authorization. * It it always supported since #MHD_VERSION 0x00096200 if Digest Auth - * module is built. + * module is built unless manually disabled in a custom build. * @note Available since #MHD_VERSION 0x00097527 */ MHD_FEATURE_DIGEST_AUTH_SHA256 = 27, @@ -6102,7 +6110,8 @@ enum MHD_FEATURE /** * Get whether the SHA-512/256-based hashing algorithms are supported * for Digest Authorization. - * Currently it is always not supported. + * It it always supported since #MHD_VERSION 0x00097539 if Digest Auth + * module is built unless manually disabled in a custom build. * @note Available since #MHD_VERSION 0x00097536 */ MHD_FEATURE_DIGEST_AUTH_SHA512_256 = 28, diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am @@ -168,9 +168,15 @@ endif if ENABLE_DAUTH libmicrohttpd_la_SOURCES += \ digestauth.c digestauth.h \ - mhd_bithelpers.h mhd_byteorder.h mhd_align.h \ - md5.c md5.h \ + mhd_bithelpers.h mhd_byteorder.h mhd_align.h +if ENABLE_MD5 +libmicrohttpd_la_SOURCES += \ + md5.c md5.h +endif +if ENABLE_SHA256 +libmicrohttpd_la_SOURCES += \ sha256.c sha256.h +endif if ENABLE_SHA512_256 libmicrohttpd_la_SOURCES += \ sha512_256.c sha512_256.h @@ -197,9 +203,7 @@ check_PROGRAMS = \ test_str_pct \ test_str_bin_hex \ test_http_reasons \ - test_md5 \ test_sha1 \ - test_sha256 \ test_start_stop \ test_daemon \ test_response_entries \ @@ -219,6 +223,14 @@ check_PROGRAMS = \ test_options \ test_set_panic +if ENABLE_MD5 +check_PROGRAMS += \ + test_md5 +endif +if ENABLE_SHA256 +check_PROGRAMS += \ + test_sha256 +endif if ENABLE_SHA512_256 check_PROGRAMS += \ test_sha512_256 diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c @@ -8430,20 +8430,20 @@ MHD_is_feature_supported (enum MHD_FEATURE feature) return MHD_NO; #endif case MHD_FEATURE_DIGEST_AUTH_MD5: -#ifdef DAUTH_SUPPORT +#if defined(DAUTH_SUPPORT) && defined(MHD_MD5_SUPPORT) return MHD_YES; #else return MHD_NO; #endif case MHD_FEATURE_DIGEST_AUTH_SHA256: -#ifdef DAUTH_SUPPORT +#if defined(DAUTH_SUPPORT) && defined(MHD_SHA256_SUPPORT) return MHD_YES; #else return MHD_NO; #endif case MHD_FEATURE_DIGEST_AUTH_SHA512_256: -#ifdef DAUTH_SUPPORT - return MHD_NO; +#if defined(DAUTH_SUPPORT) && defined(MHD_SHA512_256_SUPPORT) + return MHD_YES; #else return MHD_NO; #endif diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c @@ -33,8 +33,15 @@ #include "mhd_limits.h" #include "internal.h" #include "response.h" -#include "md5.h" -#include "sha256.h" +#ifdef MHD_MD5_SUPPORT +# include "md5.h" +#endif /* MHD_MD5_SUPPORT */ +#ifdef MHD_SHA256_SUPPORT +# include "sha256.h" +#endif /* MHD_SHA256_SUPPORT */ +#ifdef MHD_SHA512_256_SUPPORT +# include "sha512_256.h" +#endif /* MHD_SHA512_256_SUPPORT */ #include "mhd_locks.h" #include "mhd_mono_clock.h" #include "mhd_str.h" @@ -86,6 +93,18 @@ ((digest_size) * 2 + TIMESTAMP_CHARS_LEN) +#ifdef MHD_SHA512_256_SUPPORT +/** + * Maximum size of any digest hash supported by MHD. + * (SHA-512/256 > MD5). + */ +#define MAX_DIGEST SHA512_256_DIGEST_SIZE + +/** + * The common size of SHA-256 digest and SHA-512/256 digest + */ +#define SHA256_SHA512_256_DIGEST_SIZE SHA512_256_DIGEST_SIZE +#elif defined(MHD_SHA256_SUPPORT) /** * Maximum size of any digest hash supported by MHD. * (SHA-256 > MD5). @@ -93,6 +112,20 @@ #define MAX_DIGEST SHA256_DIGEST_SIZE /** + * The common size of SHA-256 digest and SHA-512/256 digest + */ +#define SHA256_SHA512_256_DIGEST_SIZE SHA256_DIGEST_SIZE +#elif defined(MHD_MD5_SUPPORT) +/** + * Maximum size of any digest hash supported by MHD. + */ +#define MAX_DIGEST MD5_DIGEST_SIZE +#else /* ! MHD_MD5_SUPPORT */ +#error At least one hashing algorithm must be enabled +#endif /* ! MHD_MD5_SUPPORT */ + + +/** * Macro to avoid using VLAs if the compiler does not support them. */ #ifndef HAVE_C_VARARRAYS @@ -193,26 +226,54 @@ get_base_digest_algo (enum MHD_DigestAuthAlgo3 algo3) * Internal inline version. * @param algo3 the algorithm to check * @return the size of the digest or zero if the input value is not - * recognised/valid + * supported/valid */ _MHD_static_inline size_t digest_get_hash_size (enum MHD_DigestAuthAlgo3 algo3) { +#ifdef MHD_MD5_SUPPORT mhd_assert (MHD_MD5_DIGEST_SIZE == MD5_DIGEST_SIZE); +#endif /* MHD_MD5_SUPPORT */ +#ifdef MHD_SHA256_SUPPORT mhd_assert (MHD_SHA256_DIGEST_SIZE == SHA256_DIGEST_SIZE); - /* Both MD5 and SHA-256 must not be specified at the same time */ - mhd_assert ( (0 == (((unsigned int) algo3) \ - & ((unsigned int) MHD_DIGEST_BASE_ALGO_MD5))) || \ - (0 == (((unsigned int) algo3) \ - & ((unsigned int) MHD_DIGEST_BASE_ALGO_SHA256))) ); +#endif /* MHD_SHA256_SUPPORT */ +#ifdef MHD_SHA512_256_SUPPORT + mhd_assert (MHD_SHA512_256_DIGEST_SIZE == SHA512_256_DIGEST_SIZE); +#ifdef MHD_SHA256_SUPPORT + mhd_assert (SHA256_DIGEST_SIZE == SHA512_256_DIGEST_SIZE); +#endif /* MHD_SHA256_SUPPORT */ +#endif /* MHD_SHA512_256_SUPPORT */ + /* Only one algorithm must be specified */ + mhd_assert (1 == \ + (((0 != (algo3 & MHD_DIGEST_BASE_ALGO_MD5)) ? 1 : 0) \ + + ((0 != (algo3 & MHD_DIGEST_BASE_ALGO_SHA256)) ? 1 : 0) \ + + ((0 != (algo3 & MHD_DIGEST_BASE_ALGO_SHA512_256)) ? 1 : 0))); +#ifdef MHD_MD5_SUPPORT if (0 != (((unsigned int) algo3) & ((unsigned int) MHD_DIGEST_BASE_ALGO_MD5))) return MHD_MD5_DIGEST_SIZE; - else if (0 != (((unsigned int) algo3) - & ((unsigned int) MHD_DIGEST_BASE_ALGO_SHA256))) + else +#endif /* MHD_MD5_SUPPORT */ +#if defined(MHD_SHA256_SUPPORT) && defined(MHD_SHA512_256_SUPPORT) + if (0 != (((unsigned int) algo3) + & ( ((unsigned int) MHD_DIGEST_BASE_ALGO_SHA256) + | ((unsigned int) MHD_DIGEST_BASE_ALGO_SHA512_256)))) + return MHD_SHA256_DIGEST_SIZE; /* The same as SHA512_256_DIGEST_SIZE */ + else +#elif defined(MHD_SHA256_SUPPORT) + if (0 != (((unsigned int) algo3) + & ((unsigned int) MHD_DIGEST_BASE_ALGO_SHA256))) return MHD_SHA256_DIGEST_SIZE; + else +#elif defined(MHD_SHA512_256_SUPPORT) + if (0 != (((unsigned int) algo3) + & ((unsigned int) MHD_DIGEST_BASE_ALGO_SHA512_256))) + return MHD_SHA512_256_DIGEST_SIZE; + else +#endif /* MHD_SHA512_256_SUPPORT */ + (void) 0; /* Unsupported algorithm */ - return 0; /* Wrong input */ + return 0; /* Wrong input or unsupported algorithm */ } @@ -223,8 +284,8 @@ digest_get_hash_size (enum MHD_DigestAuthAlgo3 algo3) * and other parameters which size depends on used hash algorithm. * @param algo3 the algorithm to check * @return the size of the digest (either #MHD_MD5_DIGEST_SIZE or - * #MHD_SHA256_DIGEST_SIZE) or zero if the input value is not - * recognised/valid + * #MHD_SHA256_DIGEST_SIZE/MHD_SHA512_256_DIGEST_SIZE) + * or zero if the input value is not supported or not valid * @sa #MHD_digest_auth_calc_userdigest() * @sa #MHD_digest_auth_calc_userhash(), #MHD_digest_auth_calc_userhash_hex() * @note Available since #MHD_VERSION 0x00097526 @@ -242,8 +303,15 @@ MHD_digest_get_hash_size (enum MHD_DigestAuthAlgo3 algo3) */ union DigestCtx { +#ifdef MHD_MD5_SUPPORT struct MD5Context md5_ctx; +#endif /* MHD_MD5_SUPPORT */ +#ifdef MHD_SHA256_SUPPORT struct Sha256Ctx sha256_ctx; +#endif /* MHD_SHA256_SUPPORT */ +#ifdef MHD_SHA512_256_SUPPORT + struct Sha512_256Ctx sha512_256_ctx; +#endif /* MHD_SHA512_256_SUPPORT */ }; /** @@ -282,10 +350,18 @@ _MHD_static_inline unsigned int digest_get_size (struct DigestAlgorithm *da) { mhd_assert (da->setup); +#ifdef MHD_MD5_SUPPORT if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo) return MD5_DIGEST_SIZE; +#endif /* MHD_MD5_SUPPORT */ +#ifdef MHD_SHA256_SUPPORT if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo) return SHA256_DIGEST_SIZE; +#endif /* MHD_SHA256_SUPPORT */ +#ifdef MHD_SHA512_256_SUPPORT + if (MHD_DIGEST_BASE_ALGO_SHA512_256 == da->algo) + return SHA512_256_DIGEST_SIZE; +#endif /* MHD_SHA512_256_SUPPORT */ mhd_assert (0); /* May not happen */ return 0; } @@ -307,8 +383,17 @@ digest_setup (struct DigestAlgorithm *da, da->inited = false; da->digest_calculated = false; #endif /* _DEBUG */ - if ((MHD_DIGEST_BASE_ALGO_MD5 == algo) || - (MHD_DIGEST_BASE_ALGO_SHA256 == algo)) + if (false +#ifdef MHD_MD5_SUPPORT + || (MHD_DIGEST_BASE_ALGO_MD5 == algo) +#endif /* MHD_MD5_SUPPORT */ +#ifdef MHD_SHA256_SUPPORT + || (MHD_DIGEST_BASE_ALGO_SHA256 == algo) +#endif /* MHD_SHA256_SUPPORT */ +#ifdef MHD_SHA512_256_SUPPORT + || (MHD_DIGEST_BASE_ALGO_SHA512_256 == algo) +#endif /* MHD_SHA512_256_SUPPORT */ + ) { da->algo = algo; #ifdef _DEBUG @@ -316,8 +401,7 @@ digest_setup (struct DigestAlgorithm *da, #endif /* _DEBUG */ return true; } - mhd_assert (0); /* Bad parameter */ - return false; + return false; /* Bad or unsupported algorithm */ } @@ -332,6 +416,7 @@ digest_init (struct DigestAlgorithm *da) #ifdef _DEBUG da->digest_calculated = false; #endif +#ifdef MHD_MD5_SUPPORT if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo) { MHD_MD5Init (&da->ctx.md5_ctx); @@ -339,7 +424,10 @@ digest_init (struct DigestAlgorithm *da) da->inited = true; #endif } - else if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo) + else +#endif /* MHD_MD5_SUPPORT */ +#ifdef MHD_SHA256_SUPPORT + if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo) { MHD_SHA256_init (&da->ctx.sha256_ctx); #ifdef _DEBUG @@ -347,6 +435,17 @@ digest_init (struct DigestAlgorithm *da) #endif } else +#endif /* MHD_SHA256_SUPPORT */ +#ifdef MHD_SHA512_256_SUPPORT + if (MHD_DIGEST_BASE_ALGO_SHA512_256 == da->algo) + { + MHD_SHA512_256_init (&da->ctx.sha512_256_ctx); +#ifdef _DEBUG + da->inited = true; +#endif + } + else +#endif /* MHD_SHA512_256_SUPPORT */ { #ifdef _DEBUG da->inited = false; @@ -369,12 +468,23 @@ digest_update (struct DigestAlgorithm *da, { mhd_assert (da->inited); mhd_assert (! da->digest_calculated); +#ifdef MHD_MD5_SUPPORT if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo) MHD_MD5Update (&da->ctx.md5_ctx, (const uint8_t *) data, length); - else if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo) + else +#endif /* MHD_MD5_SUPPORT */ +#ifdef MHD_SHA256_SUPPORT + if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo) MHD_SHA256_update (&da->ctx.sha256_ctx, (const uint8_t *) data, length); else - mhd_assert (0); /* May not happen */ +#endif /* MHD_SHA256_SUPPORT */ +#ifdef MHD_SHA512_256_SUPPORT + if (MHD_DIGEST_BASE_ALGO_SHA512_256 == da->algo) + MHD_SHA512_256_update (&da->ctx.sha512_256_ctx, + (const uint8_t *) data, length); + else +#endif /* MHD_SHA512_256_SUPPORT */ + mhd_assert (0); /* May not happen */ } @@ -416,12 +526,22 @@ digest_calc_hash (struct DigestAlgorithm *da, uint8_t *digest) { mhd_assert (da->inited); mhd_assert (! da->digest_calculated); +#ifdef MHD_MD5_SUPPORT if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo) MHD_MD5Final (&da->ctx.md5_ctx, digest); - else if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo) + else +#endif /* MHD_MD5_SUPPORT */ +#ifdef MHD_SHA256_SUPPORT + if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo) MHD_SHA256_finish (&da->ctx.sha256_ctx, digest); else - mhd_assert (0); /* May not happen */ +#endif /* MHD_SHA256_SUPPORT */ +#ifdef MHD_SHA512_256_SUPPORT + if (MHD_DIGEST_BASE_ALGO_SHA512_256 == da->algo) + MHD_SHA512_256_finish (&da->ctx.sha512_256_ctx, digest); + else +#endif /* MHD_SHA512_256_SUPPORT */ + mhd_assert (0); /* May not happen */ #ifdef _DEBUG da->digest_calculated = true; #endif @@ -444,8 +564,14 @@ get_nonce_timestamp (const char *const nonce, if (0 == noncelen) noncelen = strlen (nonce); - if ( (NONCE_STD_LEN (SHA256_DIGEST_SIZE) != noncelen) && - (NONCE_STD_LEN (MD5_DIGEST_SIZE) != noncelen) ) + if (true +#ifdef MHD_MD5_SUPPORT + && (NONCE_STD_LEN (MD5_DIGEST_SIZE) != noncelen) +#endif /* MHD_MD5_SUPPORT */ +#if defined(MHD_SHA256_SUPPORT) || defined(MHD_SHA512_256_SUPPORT) + && (NONCE_STD_LEN (SHA256_SHA512_256_DIGEST_SIZE) != noncelen) +#endif /* MHD_SHA256_SUPPORT */ + ) return false; if (TIMESTAMP_CHARS_LEN != @@ -2213,19 +2339,43 @@ digest_auth_check_all_inner (struct MHD_Connection *connection, #endif /* HAVE_MESSAGES */ return MHD_DAUTH_WRONG_ALGO; } +#ifndef MHD_MD5_SUPPORT + if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_MD5)) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (connection->daemon, + _ ("The MD5 algorithm is not supported by this MHD build.\n")); +#endif /* HAVE_MESSAGES */ + return MHD_DAUTH_WRONG_ALGO; + } +#endif /* ! MHD_MD5_SUPPORT */ +#ifndef MHD_SHA256_SUPPORT + if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_SHA256)) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (connection->daemon, + _ ("The SHA-256 algorithm is not supported by " + "this MHD build.\n")); +#endif /* HAVE_MESSAGES */ + return MHD_DAUTH_WRONG_ALGO; + } +#endif /* ! MHD_SHA256_SUPPORT */ +#ifndef MHD_SHA512_256_SUPPORT if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_SHA512_256)) { #ifdef HAVE_MESSAGES MHD_DLOG (connection->daemon, - _ ("The SHA-512/256 algorithm is not supported.\n")); + _ ("The SHA-512/256 algorithm is not supported by " + "this MHD build.\n")); #endif /* HAVE_MESSAGES */ return MHD_DAUTH_WRONG_ALGO; } +#endif /* ! MHD_SHA512_256_SUPPORT */ if (! digest_setup (&da, get_base_digest_algo (c_algo))) MHD_PANIC (_ ("Wrong 'malgo3' value, API violation")); /* Check 'mqop' value */ c_qop = params->qop; - /* Check whether client's algorithm is allowed by function parameter */ + /* Check whether client's QOP is allowed by function parameter */ if (((unsigned int) c_qop) != (((unsigned int) c_qop) & ((unsigned int) mqop))) return MHD_DAUTH_WRONG_QOP; @@ -2241,8 +2391,8 @@ digest_auth_check_all_inner (struct MHD_Connection *connection, if ((MHD_DIGEST_AUTH_QOP_NONE == c_qop) && (0 == (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_MD5))) MHD_DLOG (connection->daemon, - _ ("RFC2069 with SHA-256 algorithm is non-standard " \ - "extension.\n")); + _ ("RFC2069 with SHA-256 or SHA-512/256 algorithm is " \ + "non-standard extension.\n")); #endif /* HAVE_MESSAGES */ digest_size = digest_get_size (&da); @@ -2776,7 +2926,8 @@ MHD_digest_auth_check3 (struct MHD_Connection *connection, * see #MHD_digest_auth_calc_userdigest() * @param userdigest_size the size of the @a userdigest in bytes, must match the * hashing algorithm (see #MHD_MD5_DIGEST_SIZE, - * #MHD_SHA256_DIGEST_SIZE, #MHD_digest_get_hash_size()) + * #MHD_SHA256_DIGEST_SIZE, #MHD_SHA512_256_DIGEST_SIZE, + * #MHD_digest_get_hash_size()) * @param nonce_timeout the period of seconds since nonce generation, when * the nonce is recognised as valid and not stale. * @param max_nc the maximum allowed nc (Nonce Count) value, if client's nc @@ -2786,9 +2937,9 @@ MHD_digest_auth_check3 (struct MHD_Connection *connection, * @param mqop the QOP to use * @param malgo3 digest algorithms allowed to use, fail if algorithm used * by the client is not allowed by this parameter; - * both MD5-based and SHA-256-based algorithms cannot be used at - * the same time for this function as @a userdigest_size must - * match specified algorithm + * more than one base algorithms (MD5, SHA-256, SHA-512/256) + * cannot be used at the same time for this function + * as @a userdigest must match specified algorithm * @return #MHD_DAUTH_OK if authenticated, * the error code otherwise * @sa #MHD_digest_auth_calc_userdigest() @@ -2806,13 +2957,46 @@ MHD_digest_auth_check_digest3 (struct MHD_Connection *connection, enum MHD_DigestAuthMultiQOP mqop, enum MHD_DigestAuthMultiAlgo3 malgo3) { - if (((unsigned int) (MHD_DIGEST_BASE_ALGO_MD5 - | MHD_DIGEST_BASE_ALGO_SHA256)) == - (((unsigned int) malgo3) & (MHD_DIGEST_BASE_ALGO_MD5 - | MHD_DIGEST_BASE_ALGO_SHA256))) - MHD_PANIC (_ ("Wrong 'malgo3' value, both MD5 and SHA-256 specified, " + if (1 != (((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_MD5)) ? 1 : 0) + + ((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_SHA256)) ? 1 : 0) + + ((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_SHA512_256)) ? 1 : 0))) + MHD_PANIC (_ ("Wrong 'malgo3' value, only one base hashing algorithm " \ + "(MD5, SHA-256 or SHA-512/256) must be specified, " \ "API violation")); +#ifndef MHD_MD5_SUPPORT + if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_MD5)) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (connection->daemon, + _ ("The MD5 algorithm is not supported by this MHD build.\n")); +#endif /* HAVE_MESSAGES */ + return MHD_DAUTH_WRONG_ALGO; + } +#endif /* ! MHD_MD5_SUPPORT */ +#ifndef MHD_SHA256_SUPPORT + if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA256)) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (connection->daemon, + _ ("The SHA-256 algorithm is not supported by " + "this MHD build.\n")); +#endif /* HAVE_MESSAGES */ + return MHD_DAUTH_WRONG_ALGO; + } +#endif /* ! MHD_SHA256_SUPPORT */ +#ifndef MHD_SHA512_256_SUPPORT + if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA512_256)) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (connection->daemon, + _ ("The SHA-512/256 algorithm is not supported by " + "this MHD build.\n")); +#endif /* HAVE_MESSAGES */ + return MHD_DAUTH_WRONG_ALGO; + } +#endif /* ! MHD_SHA512_256_SUPPORT */ + if (digest_get_hash_size ((enum MHD_DigestAuthAlgo3) malgo3) != userdigest_size) MHD_PANIC (_ ("Wrong 'userdigest_size' value, does not match 'malgo3', " @@ -3072,12 +3256,45 @@ MHD_queue_auth_required_response3 (struct MHD_Connection *connection, #endif /* HAVE_MESSAGES */ return MHD_NO; } +#ifndef MHD_SHA512_256_SUPPORT + if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA512_256)) + { +#ifdef HAVE_MESSAGES + MHD_DLOG (connection->daemon, + _ ("The SHA-512/256 algorithm is not enabled.\n")); +#endif /* HAVE_MESSAGES */ + return MHD_NO; + } +#endif /* ! MHD_SHA512_256_SUPPORT */ +#ifdef MHD_MD5_SUPPORT if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_MD5)) s_algo = MHD_DIGEST_AUTH_ALGO3_MD5; - else if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA256)) + else +#endif /* MHD_MD5_SUPPORT */ +#ifdef MHD_SHA256_SUPPORT + if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA256)) s_algo = MHD_DIGEST_AUTH_ALGO3_SHA256; else - MHD_PANIC (_ ("Wrong 'malgo3' value, API violation")); +#endif /* MHD_SHA256_SUPPORT */ +#ifdef MHD_SHA512_256_SUPPORT + if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA512_256)) + s_algo = MHD_DIGEST_AUTH_ALGO3_SHA512_256; + else +#endif /* MHD_SHA512_256_SUPPORT */ + { + if (0 == (((unsigned int) malgo3) + & (MHD_DIGEST_BASE_ALGO_MD5 | MHD_DIGEST_BASE_ALGO_SHA512_256 + | MHD_DIGEST_BASE_ALGO_SHA512_256))) + MHD_PANIC (_ ("Wrong 'malgo3' value, API violation")); + else + { +#ifdef HAVE_MESSAGES + MHD_DLOG (connection->daemon, + _ ("No requested algorithm is supported by this MHD build.\n")); +#endif /* HAVE_MESSAGES */ + } + return MHD_NO; + } if (((unsigned int) mqop) != (((unsigned int) mqop) & MHD_DIGEST_AUTH_MULT_QOP_ANY_NON_INT)) @@ -3095,8 +3312,8 @@ MHD_queue_auth_required_response3 (struct MHD_Connection *connection, "are not compatible with RFC2069 and ignored.\n")); if (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5)) MHD_DLOG (connection->daemon, - _ ("RFC2069 with SHA-256 algorithm is non-standard " \ - "extension.\n")); + _ ("RFC2069 with SHA-256 or SHA-512/256 algorithm is " \ + "non-standard extension.\n")); #endif userhash_support = 0; prefer_utf8 = 0; @@ -3141,12 +3358,22 @@ MHD_queue_auth_required_response3 (struct MHD_Connection *connection, (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5))) { buf_size += MHD_STATICSTR_LEN_ (prefix_algo) + 2; /* 2 for ', ' */ +#ifdef MHD_MD5_SUPPORT if (MHD_DIGEST_AUTH_ALGO3_MD5 == s_algo) buf_size += MHD_STATICSTR_LEN_ (_MHD_MD5_TOKEN); - else if (MHD_DIGEST_AUTH_ALGO3_SHA256 == s_algo) + else +#endif /* MHD_MD5_SUPPORT */ +#ifdef MHD_SHA256_SUPPORT + if (MHD_DIGEST_AUTH_ALGO3_SHA256 == s_algo) buf_size += MHD_STATICSTR_LEN_ (_MHD_SHA256_TOKEN); else - mhd_assert (0); +#endif /* MHD_SHA256_SUPPORT */ +#ifdef MHD_SHA512_256_SUPPORT + if (MHD_DIGEST_AUTH_ALGO3_SHA512_256 == s_algo) + buf_size += MHD_STATICSTR_LEN_ (_MHD_SHA512_256_TOKEN); + else +#endif /* MHD_SHA512_256_SUPPORT */ + mhd_assert (0); } /* 'nonce="xxxx", ' */ buf_size += MHD_STATICSTR_LEN_ (prefix_nonce) + 3; /* 3 for '", ' */ @@ -3243,18 +3470,34 @@ MHD_queue_auth_required_response3 (struct MHD_Connection *connection, memcpy (buf + p, prefix_algo, MHD_STATICSTR_LEN_ (prefix_algo)); p += MHD_STATICSTR_LEN_ (prefix_algo); +#ifdef MHD_MD5_SUPPORT if (MHD_DIGEST_AUTH_ALGO3_MD5 == s_algo) { memcpy (buf + p, _MHD_MD5_TOKEN, MHD_STATICSTR_LEN_ (_MHD_MD5_TOKEN)); p += MHD_STATICSTR_LEN_ (_MHD_MD5_TOKEN); } - else if (MHD_DIGEST_AUTH_ALGO3_SHA256 == s_algo) + else +#endif /* MHD_MD5_SUPPORT */ +#ifdef MHD_SHA256_SUPPORT + if (MHD_DIGEST_AUTH_ALGO3_SHA256 == s_algo) { memcpy (buf + p, _MHD_SHA256_TOKEN, MHD_STATICSTR_LEN_ (_MHD_SHA256_TOKEN)); p += MHD_STATICSTR_LEN_ (_MHD_SHA256_TOKEN); } + else +#endif /* MHD_SHA256_SUPPORT */ +#ifdef MHD_SHA512_256_SUPPORT + if (MHD_DIGEST_AUTH_ALGO3_SHA512_256 == s_algo) + { + memcpy (buf + p, _MHD_SHA512_256_TOKEN, + MHD_STATICSTR_LEN_ (_MHD_SHA512_256_TOKEN)); + p += MHD_STATICSTR_LEN_ (_MHD_SHA512_256_TOKEN); + } + else +#endif /* MHD_SHA512_256_SUPPORT */ + mhd_assert (0); buf[p++] = ','; buf[p++] = ' '; } @@ -3382,7 +3625,7 @@ MHD_queue_auth_fail_response2 (struct MHD_Connection *connection, algo3 = MHD_DIGEST_AUTH_MULT_ALGO3_MD5; else if (MHD_DIGEST_ALG_SHA256 == algo) algo3 = MHD_DIGEST_AUTH_MULT_ALGO3_SHA256; - else if ((MHD_DIGEST_ALG_MD5 == algo) || (MHD_DIGEST_ALG_AUTO == algo)) + else if (MHD_DIGEST_ALG_AUTO == algo) algo3 = MHD_DIGEST_AUTH_MULT_ALGO3_ANY_NON_SESSION; else MHD_PANIC (_ ("Wrong algo value.\n")); /* API violation! */ diff --git a/src/microhttpd/gen_auth.c b/src/microhttpd/gen_auth.c @@ -300,23 +300,23 @@ get_rq_dauth_algo (const struct MHD_RqDAuthParam *const algo_param) if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ algo_param->value.len, \ _MHD_MD5_TOKEN _MHD_SESS_TOKEN)) - return MHD_DIGEST_AUTH_ALGO3_MD5_SESSION; + return MHD_DIGEST_AUTH_ALGO3_SHA512_256; if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ algo_param->value.len, \ - _MHD_SHA256_TOKEN \ + _MHD_SHA512_256_TOKEN \ _MHD_SESS_TOKEN)) - return MHD_DIGEST_AUTH_ALGO3_SHA256_SESSION; - /* Algorithms below are not supported by MHD for authentication */ + /* Algorithms below are not supported by MHD for authentication */ + return MHD_DIGEST_AUTH_ALGO3_MD5_SESSION; if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ algo_param->value.len, \ - _MHD_SHA512_256_TOKEN)) - return MHD_DIGEST_AUTH_ALGO3_SHA512_256; + _MHD_SHA256_TOKEN \ + _MHD_SESS_TOKEN)) + return MHD_DIGEST_AUTH_ALGO3_SHA256_SESSION; if (MHD_str_equal_caseless_quoted_s_bin_n (algo_param->value.str, \ algo_param->value.len, \ - _MHD_SHA512_256_TOKEN \ - _MHD_SESS_TOKEN)) + _MHD_SHA512_256_TOKEN)) return MHD_DIGEST_AUTH_ALGO3_SHA512_256_SESSION; /* No known algorithm has been detected */ @@ -331,6 +331,13 @@ get_rq_dauth_algo (const struct MHD_RqDAuthParam *const algo_param) algo_param->value.str, \ algo_param->value.len)) return MHD_DIGEST_AUTH_ALGO3_SHA256; + if (MHD_str_equal_caseless_s_bin_n_ (_MHD_SHA512_256_TOKEN, \ + algo_param->value.str, \ + algo_param->value.len)) + return MHD_DIGEST_AUTH_ALGO3_SHA512_256; + + /* Algorithms below are not supported by MHD for authentication */ + if (MHD_str_equal_caseless_s_bin_n_ (_MHD_MD5_TOKEN _MHD_SESS_TOKEN, \ algo_param->value.str, \ algo_param->value.len)) @@ -339,13 +346,6 @@ get_rq_dauth_algo (const struct MHD_RqDAuthParam *const algo_param) algo_param->value.str, \ algo_param->value.len)) return MHD_DIGEST_AUTH_ALGO3_SHA256_SESSION; - - /* Algorithms below are not supported by MHD for authentication */ - - if (MHD_str_equal_caseless_s_bin_n_ (_MHD_SHA512_256_TOKEN, \ - algo_param->value.str, \ - algo_param->value.len)) - return MHD_DIGEST_AUTH_ALGO3_SHA512_256; if (MHD_str_equal_caseless_s_bin_n_ (_MHD_SHA512_256_TOKEN _MHD_SESS_TOKEN, \ algo_param->value.str, \ algo_param->value.len)) diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h @@ -250,11 +250,15 @@ enum MHD_ConnectionEventLoopInfo /** * The maximum size of MHD-generated nonce when printed with hexadecimal chars. * - * This is equal to "(32 bytes for SHA-256 nonce plus 6 bytes for timestamp) - * multiplied by two hex chars per byte". + * This is equal to "(32 bytes for SHA-256 (or SHA-512/256) nonce plus 6 bytes + * for timestamp) multiplied by two hex chars per byte". * Please keep it in sync with digestauth.c */ +#if defined(MHD_SHA256_SUPPORT) || defined(MHD_SHA512_256_SUPPORT) #define MAX_DIGEST_NONCE_LENGTH ((32 + 6) * 2) +#else /* !MHD_SHA256_SUPPORT && !MHD_SHA512_256_SUPPORT */ +#define MAX_DIGEST_NONCE_LENGTH ((16 + 6) * 2) +#endif /* !MHD_SHA256_SUPPORT && !MHD_SHA512_256_SUPPORT */ /** * A structure representing the internal holder of the @@ -280,7 +284,7 @@ struct MHD_NonceNc uint64_t nmask; /** - * Nonce value: + * Nonce value */ char nonce[MAX_DIGEST_NONCE_LENGTH + 1]; diff --git a/src/microhttpd/test_dauth_userdigest.c b/src/microhttpd/test_dauth_userdigest.c @@ -123,6 +123,54 @@ static const struct data_sha256 sha256_tests[] = { 0xcb, 0x14, 0x9c, 0x54, 0xf3, 0x7c, 0xff, 0x37}} }; +struct data_sha512_256 +{ + unsigned int line_num; + const char *const username; + const char *const realm; + const char *const password; + const uint8_t hash[MHD_SHA512_256_DIGEST_SIZE]; +}; + +static const struct data_sha512_256 sha512_256_tests[] = { + {__LINE__, + "u", "r", "p", + {0xd5, 0xe8, 0xe7, 0x3b, 0xa3, 0x47, 0xb9, 0xad, 0xf0, 0xe4, 0x7a, 0x9a, + 0xce, 0x43, 0xb7, 0x08, 0x2a, 0xbc, 0x8d, 0x27, 0x27, 0x2e, 0x38, 0x7d, + 0x1d, 0x9c, 0xe2, 0x44, 0x25, 0x68, 0x74, 0x04}}, + {__LINE__, + "testuser", "testrealm", "testpass", + {0x41, 0x7d, 0xf9, 0x60, 0x7c, 0xc9, 0x60, 0x28, 0x44, 0x74, 0x75, 0xf7, + 0x7b, 0x78, 0xe7, 0x60, 0xec, 0x9a, 0xe1, 0x62, 0xd4, 0x95, 0x82, 0x61, + 0x68, 0xa7, 0x94, 0xe8, 0x3b, 0xdf, 0x8d, 0x59}}, + {__LINE__, /* Values from testcurl/test_digestauth2.c */ + "test_user", "TestRealm", "test pass", + {0xe7, 0xa1, 0x9e, 0x27, 0xf6, 0x73, 0x88, 0xb2, 0xde, 0xa4, 0xe2, 0x66, + 0xc5, 0x16, 0x37, 0x17, 0x4d, 0x29, 0xcc, 0xa3, 0xc1, 0xf5, 0xb2, 0x49, + 0x20, 0xc1, 0x05, 0xc9, 0x20, 0x13, 0x3c, 0x3d}}, + {__LINE__, + "Mufasa", "myhost@testrealm.com", "CircleOfLife", + {0x44, 0xbc, 0xd2, 0xb1, 0x1f, 0x6f, 0x7d, 0xd3, 0xae, 0xa6, 0x66, 0x8a, + 0x24, 0x84, 0x4b, 0x87, 0x7d, 0xe1, 0x80, 0x24, 0x9a, 0x26, 0x6b, 0xe6, + 0xdb, 0x7f, 0xe3, 0xc8, 0x7a, 0xf9, 0x75, 0x64}}, + {__LINE__, + "Mufasa", "myhost@example.com", "Circle Of Life", + {0xd5, 0xf6, 0x25, 0x7c, 0x64, 0xe4, 0x01, 0xd2, 0x87, 0xd5, 0xaa, 0x19, + 0xae, 0xf0, 0xa2, 0xa2, 0xce, 0x4e, 0x5d, 0xfc, 0x77, 0x70, 0x0b, 0x72, + 0x90, 0x43, 0x96, 0xd2, 0x95, 0x6e, 0x83, 0x0a}}, + {__LINE__, + "Mufasa", "http-auth@example.org", "Circle of Life", + {0xfb, 0x17, 0x4f, 0x5c, 0x3c, 0x78, 0x02, 0x72, 0x15, 0x17, 0xca, 0xe1, + 0x3b, 0x98, 0xe2, 0xb8, 0xda, 0xe2, 0xe0, 0x11, 0x8c, 0xb7, 0x05, 0xd9, + 0x4e, 0xe2, 0x99, 0x46, 0x31, 0x92, 0x04, 0xce}}, + {__LINE__, + "J" "\xC3\xA4" "s" "\xC3\xB8" "n Doe" /* "Jäsøn Doe" */, + "api@example.org", "Secret, or not?", + {0x2d, 0x3d, 0x9f, 0x12, 0xc9, 0xf3, 0xd3, 0x00, 0x11, 0x25, 0x9d, 0xc5, + 0xfe, 0xce, 0xe0, 0x05, 0xae, 0x24, 0xde, 0x40, 0xe3, 0xe1, 0xf6, 0x18, + 0x06, 0xd0, 0x3e, 0x65, 0xf1, 0xe6, 0x02, 0x4f}} +}; + /* * Helper functions @@ -413,6 +461,156 @@ test_sha256_failure (void) } +static unsigned int +check_sha512_256 (const struct data_sha512_256 *const data) +{ + static const enum MHD_DigestAuthAlgo3 algo3 = + MHD_DIGEST_AUTH_ALGO3_SHA512_256; + uint8_t hash_bin[MHD_SHA512_256_DIGEST_SIZE]; + char hash_hex[MHD_SHA512_256_DIGEST_SIZE * 2 + 1]; + char expected_hex[MHD_SHA512_256_DIGEST_SIZE * 2 + 1]; + const char *func_name; + unsigned int failed = 0; + + func_name = "MHD_digest_auth_calc_userdigest"; + if (MHD_YES != MHD_digest_auth_calc_userdigest (algo3, + data->username, + data->realm, + data->password, + hash_bin, sizeof(hash_bin))) + { + failed++; + fprintf (stderr, + "FAILED: %s() has not returned MHD_YES.\n", + func_name); + } + else if (0 != memcmp (hash_bin, data->hash, sizeof(data->hash))) + { + failed++; + bin2hex (hash_bin, sizeof(hash_bin), hash_hex); + bin2hex (data->hash, sizeof(data->hash), expected_hex); + fprintf (stderr, + "FAILED: %s() produced wrong hash. " + "Calculated digest %s, expected digest %s.\n", + func_name, + hash_hex, expected_hex); + } + + if (failed) + { + fprintf (stderr, + "The check failed for data located at line: %u.\n", + data->line_num); + fflush (stderr); + } + else if (verbose) + { + printf ("PASSED: check for data at line: %u.\n", + data->line_num); + } + return failed ? 1 : 0; +} + + +static unsigned int +test_sha512_256 (void) +{ + unsigned int num_failed = 0; + size_t i; + + for (i = 0; i < sizeof(sha512_256_tests) / sizeof(sha512_256_tests[0]); i++) + num_failed += check_sha512_256 (sha512_256_tests + i); + return num_failed; +} + + +static unsigned int +test_sha512_256_failure (void) +{ + static const enum MHD_DigestAuthAlgo3 algo3 = + MHD_DIGEST_AUTH_ALGO3_SHA512_256; + static const enum MHD_FEATURE feature = MHD_FEATURE_DIGEST_AUTH_SHA512_256; + uint8_t hash_bin[MHD_SHA512_256_DIGEST_SIZE]; + char hash_hex[MHD_SHA512_256_DIGEST_SIZE * 2 + 1]; + const char *func_name; + unsigned int failed = 0; + + func_name = "MHD_digest_auth_calc_userhash"; + if (MHD_NO != MHD_digest_auth_calc_userhash (algo3, + "u", "r", + hash_bin, sizeof(hash_bin) - 1)) + { + failed++; + fprintf (stderr, + "FAILED: %s() has not returned MHD_NO at line: %u.\n", + func_name, (unsigned) __LINE__); + } + if (MHD_NO != MHD_digest_auth_calc_userhash (algo3, + "u", "r", + hash_bin, 0)) + { + failed++; + fprintf (stderr, + "FAILED: %s() has not returned MHD_NO at line: %u.\n", + func_name, (unsigned) __LINE__); + } + if (MHD_NO == MHD_is_feature_supported (feature)) + { + if (MHD_NO != MHD_digest_auth_calc_userhash (algo3, + "u", "r", + hash_bin, sizeof(hash_bin))) + { + failed++; + fprintf (stderr, + "FAILED: %s() has not returned MHD_NO at line: %u.\n", + func_name, (unsigned) __LINE__); + } + } + + func_name = "MHD_digest_auth_calc_userhash_hex"; + if (MHD_NO != + MHD_digest_auth_calc_userhash_hex (algo3, + "u", "r", + hash_hex, sizeof(hash_hex) - 1)) + { + failed++; + fprintf (stderr, + "FAILED: %s() has not returned MHD_NO at line: %u.\n", + func_name, (unsigned) __LINE__); + } + if (MHD_NO != + MHD_digest_auth_calc_userhash_hex (algo3, + "u", "r", + hash_hex, 0)) + { + failed++; + fprintf (stderr, + "FAILED: %s() has not returned MHD_NO at line: %u.\n", + func_name, (unsigned) __LINE__); + } + if (MHD_NO == MHD_is_feature_supported (feature)) + { + if (MHD_NO != + MHD_digest_auth_calc_userhash_hex (algo3, + "u", "r", + hash_hex, sizeof(hash_hex))) + { + failed++; + fprintf (stderr, + "FAILED: %s() has not returned MHD_NO at line: %u.\n", + func_name, (unsigned) __LINE__); + } + } + + if (! failed && verbose) + { + printf ("PASSED: all checks with expected MHD_NO result near line: %u.\n", + (unsigned) __LINE__); + } + return failed ? 1 : 0; +} + + int main (int argc, char *argv[]) { @@ -427,6 +625,9 @@ main (int argc, char *argv[]) if (MHD_is_feature_supported (MHD_FEATURE_DIGEST_AUTH_SHA256)) num_failed += test_sha256 (); num_failed += test_sha256_failure (); + if (MHD_is_feature_supported (MHD_FEATURE_DIGEST_AUTH_SHA512_256)) + num_failed += test_sha512_256 (); + num_failed += test_sha512_256_failure (); return num_failed ? 1 : 0; } diff --git a/src/microhttpd/test_dauth_userhash.c b/src/microhttpd/test_dauth_userhash.c @@ -119,6 +119,53 @@ static const struct data_sha256 sha256_tests[] = { 0xe9, 0x19, 0x1d, 0x8e, 0x94, 0x6f, 0xc4, 0xe7}} }; +struct data_sha512_256 +{ + unsigned int line_num; + const char *const username; + const char *const realm; + const uint8_t hash[MHD_SHA512_256_DIGEST_SIZE]; +}; + + +static const struct data_sha512_256 sha512_256_tests[] = { + {__LINE__, + "u", "r", + {0xc7, 0x38, 0xf2, 0xad, 0x40, 0x1b, 0xc8, 0x7a, 0x71, 0xfe, 0x78, 0x09, + 0x60, 0x15, 0xc9, 0x7b, 0x9a, 0x26, 0xd5, 0x5f, 0x15, 0xe9, 0xf5, 0x0a, + 0xc3, 0xa6, 0xde, 0x73, 0xdd, 0xcd, 0x3d, 0x08}}, + {__LINE__, + "testuser", "testrealm", + {0x4f, 0x69, 0x1e, 0xe9, 0x50, 0x8a, 0xe4, 0x55, 0x21, 0x32, 0x9e, 0xcf, + 0xd4, 0x91, 0xf7, 0xe2, 0x77, 0x4b, 0x6f, 0xb8, 0x60, 0x2c, 0x14, 0x86, + 0xad, 0x94, 0x9d, 0x1c, 0x23, 0xd8, 0xa1, 0xf5}}, + {__LINE__, + "test_user", "TestRealm", /* Values from testcurl/test_digestauth2.c */ + {0x62, 0xe1, 0xac, 0x9f, 0x6c, 0xb1, 0xeb, 0x26, 0xaa, 0x75, 0xeb, 0x5d, + 0x46, 0xef, 0xcd, 0xc8, 0x9c, 0xcb, 0xa7, 0x81, 0xf0, 0xf9, 0xf7, 0x2f, + 0x6a, 0xfd, 0xb9, 0x42, 0x65, 0xd9, 0xa7, 0x9a}}, + {__LINE__, + "Mufasa", "myhost@testrealm.com", + {0xbd, 0x3e, 0xbc, 0x30, 0x10, 0x0b, 0x7c, 0xf1, 0x61, 0x45, 0x6c, 0xfe, + 0x64, 0x1c, 0x4c, 0xd2, 0x82, 0xe0, 0x62, 0x6e, 0x2c, 0x5e, 0x09, 0xc2, + 0x4c, 0x90, 0xb1, 0x60, 0x8a, 0xec, 0x28, 0x64}}, + {__LINE__, + "Mufasa", "myhost@example.com", + {0xea, 0x4b, 0x59, 0x37, 0xde, 0x2c, 0x4e, 0x9f, 0x16, 0xf9, 0x9c, 0x31, + 0x01, 0xb6, 0xdd, 0xf8, 0x8c, 0x85, 0xd7, 0xe8, 0xf1, 0x75, 0x90, 0xd0, + 0x63, 0x2a, 0x75, 0x75, 0xe4, 0x80, 0x13, 0x69}}, + {__LINE__, + "Mufasa", "http-auth@example.org", + {0xe2, 0xdf, 0xab, 0xd1, 0xa9, 0x6d, 0xdf, 0x86, 0x77, 0x10, 0xb6, 0x53, + 0xb6, 0xe6, 0x85, 0x7d, 0x1f, 0x14, 0x70, 0x86, 0xde, 0x7d, 0x7e, 0xf7, + 0x9d, 0xcd, 0x24, 0x98, 0x59, 0x87, 0x25, 0x70}}, + {__LINE__, + "J" "\xC3\xA4" "s" "\xC3\xB8" "n Doe" /* "Jäsøn Doe" */, "api@example.org", + {0x79, 0x32, 0x63, 0xca, 0xab, 0xb7, 0x07, 0xa5, 0x62, 0x11, 0x94, 0x0d, + 0x90, 0x41, 0x1e, 0xa4, 0xa5, 0x75, 0xad, 0xec, 0xcb, 0x7e, 0x36, 0x0a, + 0xeb, 0x62, 0x4e, 0xd0, 0x6e, 0xce, 0x9b, 0x0b}} +}; + /* * Helper functions @@ -510,6 +557,189 @@ test_sha256_failure (void) } +static unsigned int +check_sha512_256 (const struct data_sha512_256 *const data) +{ + static const enum MHD_DigestAuthAlgo3 algo3 = + MHD_DIGEST_AUTH_ALGO3_SHA512_256; + uint8_t hash_bin[MHD_SHA512_256_DIGEST_SIZE]; + char hash_hex[MHD_SHA512_256_DIGEST_SIZE * 2 + 1]; + char expected_hex[MHD_SHA512_256_DIGEST_SIZE * 2 + 1]; + const char *func_name; + unsigned int failed = 0; + + func_name = "MHD_digest_auth_calc_userhash"; + if (MHD_YES != MHD_digest_auth_calc_userhash (algo3, + data->username, data->realm, + hash_bin, sizeof(hash_bin))) + { + failed++; + fprintf (stderr, + "FAILED: %s() has not returned MHD_YES.\n", + func_name); + } + else if (0 != memcmp (hash_bin, data->hash, sizeof(data->hash))) + { + failed++; + bin2hex (hash_bin, sizeof(hash_bin), hash_hex); + bin2hex (data->hash, sizeof(data->hash), expected_hex); + fprintf (stderr, + "FAILED: %s() produced wrong hash. " + "Calculated digest %s, expected digest %s.\n", + func_name, + hash_hex, expected_hex); + } + + func_name = "MHD_digest_auth_calc_userhash_hex"; + if (MHD_YES != + MHD_digest_auth_calc_userhash_hex (algo3, + data->username, data->realm, + hash_hex, sizeof(hash_hex))) + { + failed++; + fprintf (stderr, + "FAILED: %s() has not returned MHD_YES.\n", + func_name); + } + else if (sizeof(hash_hex) - 1 != strlen (hash_hex)) + { + failed++; + fprintf (stderr, + "FAILED: %s produced hash with wrong length. " + "Calculated length %u, expected digest %u.\n", + func_name, + (unsigned) strlen (hash_hex), + (unsigned) (sizeof(hash_hex) - 1)); + } + else + { + bin2hex (data->hash, sizeof(data->hash), expected_hex); + if (0 != memcmp (hash_hex, expected_hex, sizeof(hash_hex))) + { + failed++; + fprintf (stderr, + "FAILED: %s() produced wrong hash. " + "Calculated digest %s, expected digest %s.\n", + func_name, + hash_hex, expected_hex); + } + } + + if (failed) + { + fprintf (stderr, + "The check failed for data located at line: %u.\n", + data->line_num); + fflush (stderr); + } + else if (verbose) + { + printf ("PASSED: check for data at line: %u.\n", + data->line_num); + } + return failed ? 1 : 0; +} + + +static unsigned int +test_sha512_256 (void) +{ + unsigned int num_failed = 0; + size_t i; + + for (i = 0; i < sizeof(sha512_256_tests) / sizeof(sha512_256_tests[0]); i++) + num_failed += check_sha512_256 (sha512_256_tests + i); + return num_failed; +} + + +static unsigned int +test_sha512_256_failure (void) +{ + static const enum MHD_DigestAuthAlgo3 algo3 = + MHD_DIGEST_AUTH_ALGO3_SHA512_256; + static const enum MHD_FEATURE feature = MHD_FEATURE_DIGEST_AUTH_SHA512_256; + uint8_t hash_bin[MHD_SHA512_256_DIGEST_SIZE]; + char hash_hex[MHD_SHA512_256_DIGEST_SIZE * 2 + 1]; + const char *func_name; + unsigned int failed = 0; + + func_name = "MHD_digest_auth_calc_userhash"; + if (MHD_NO != MHD_digest_auth_calc_userhash (algo3, + "u", "r", + hash_bin, sizeof(hash_bin) - 1)) + { + failed++; + fprintf (stderr, + "FAILED: %s() has not returned MHD_NO at line: %u.\n", + func_name, (unsigned) __LINE__); + } + if (MHD_NO != MHD_digest_auth_calc_userhash (algo3, + "u", "r", + hash_bin, 0)) + { + failed++; + fprintf (stderr, + "FAILED: %s() has not returned MHD_NO at line: %u.\n", + func_name, (unsigned) __LINE__); + } + if (MHD_NO == MHD_is_feature_supported (feature)) + { + if (MHD_NO != MHD_digest_auth_calc_userhash (algo3, + "u", "r", + hash_bin, sizeof(hash_bin))) + { + failed++; + fprintf (stderr, + "FAILED: %s() has not returned MHD_NO at line: %u.\n", + func_name, (unsigned) __LINE__); + } + } + + func_name = "MHD_digest_auth_calc_userhash_hex"; + if (MHD_NO != + MHD_digest_auth_calc_userhash_hex (algo3, + "u", "r", + hash_hex, sizeof(hash_hex) - 1)) + { + failed++; + fprintf (stderr, + "FAILED: %s() has not returned MHD_NO at line: %u.\n", + func_name, (unsigned) __LINE__); + } + if (MHD_NO != + MHD_digest_auth_calc_userhash_hex (algo3, + "u", "r", + hash_hex, 0)) + { + failed++; + fprintf (stderr, + "FAILED: %s() has not returned MHD_NO at line: %u.\n", + func_name, (unsigned) __LINE__); + } + if (MHD_NO == MHD_is_feature_supported (feature)) + { + if (MHD_NO != + MHD_digest_auth_calc_userhash_hex (algo3, + "u", "r", + hash_hex, sizeof(hash_hex))) + { + failed++; + fprintf (stderr, + "FAILED: %s() has not returned MHD_NO at line: %u.\n", + func_name, (unsigned) __LINE__); + } + } + + if (! failed && verbose) + { + printf ("PASSED: all checks with expected MHD_NO result near line: %u.\n", + (unsigned) __LINE__); + } + return failed ? 1 : 0; +} + + int main (int argc, char *argv[]) { @@ -524,6 +754,9 @@ main (int argc, char *argv[]) if (MHD_is_feature_supported (MHD_FEATURE_DIGEST_AUTH_SHA256)) num_failed += test_sha256 (); num_failed += test_sha256_failure (); + if (MHD_is_feature_supported (MHD_FEATURE_DIGEST_AUTH_SHA512_256)) + num_failed += test_sha512_256 (); + num_failed += test_sha512_256_failure (); return num_failed ? 1 : 0; } diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am @@ -161,12 +161,18 @@ endif if ENABLE_DAUTH +if ENABLE_MD5 THREAD_ONLY_TESTS += \ test_digestauth \ - test_digestauth_sha256 \ test_digestauth_with_arguments \ test_digestauth_concurrent +endif +if ENABLE_SHA256 +THREAD_ONLY_TESTS += \ + test_digestauth_sha256 +endif +if ENABLE_MD5 check_PROGRAMS += \ test_digestauth_emu_ext \ test_digestauth_emu_ext_oldapi \ @@ -176,21 +182,25 @@ check_PROGRAMS += \ test_digestauth2_oldapi1 \ test_digestauth2_oldapi2 \ test_digestauth2_userhash \ - test_digestauth2_sha256 \ - test_digestauth2_sha256_userhash \ - test_digestauth2_oldapi2_sha256 \ test_digestauth2_userdigest \ test_digestauth2_oldapi1_userdigest \ test_digestauth2_oldapi2_userdigest \ test_digestauth2_userhash_userdigest \ - test_digestauth2_sha256_userdigest \ - test_digestauth2_oldapi2_sha256_userdigest \ - test_digestauth2_sha256_userhash_userdigest \ test_digestauth2_bind_all \ test_digestauth2_bind_uri \ test_digestauth2_oldapi1_bind_all \ test_digestauth2_oldapi1_bind_uri endif +if ENABLE_SHA256 +check_PROGRAMS += \ + test_digestauth2_sha256 \ + test_digestauth2_sha256_userhash \ + test_digestauth2_oldapi2_sha256 \ + test_digestauth2_sha256_userdigest \ + test_digestauth2_oldapi2_sha256_userdigest \ + test_digestauth2_sha256_userhash_userdigest +endif +endif if HEAVY_TESTS if HAVE_FORK_WAITPID