libmicrohttpd

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

digestauth.c (142330B)


      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2010, 2011, 2012, 2015, 2018 Daniel Pittman and Christian Grothoff
      4      Copyright (C) 2014-2024 Evgeny Grin (Karlson2k)
      5 
      6      This library is free software; you can redistribute it and/or
      7      modify it under the terms of the GNU Lesser General Public
      8      License as published by the Free Software Foundation; either
      9      version 2.1 of the License, or (at your option) any later version.
     10 
     11      This library is distributed in the hope that it will be useful,
     12      but WITHOUT ANY WARRANTY; without even the implied warranty of
     13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14      Lesser General Public License for more details.
     15 
     16      You should have received a copy of the GNU Lesser General Public
     17      License along with this library; if not, write to the Free Software
     18      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     19 */
     20 /**
     21  * @file digestauth.c
     22  * @brief Implements HTTP digest authentication
     23  * @author Amr Ali
     24  * @author Matthieu Speder
     25  * @author Christian Grothoff (RFC 7616 support)
     26  * @author Karlson2k (Evgeny Grin) (fixes, new API, improvements, large rewrite,
     27  *                                  many RFC 7616 features implementation,
     28  *                                  old RFC 2069 support)
     29  */
     30 #include "digestauth.h"
     31 #include "gen_auth.h"
     32 #include "platform.h"
     33 #include "mhd_limits.h"
     34 #include "internal.h"
     35 #include "response.h"
     36 #ifdef MHD_MD5_SUPPORT
     37 #  include "mhd_md5_wrap.h"
     38 #endif /* MHD_MD5_SUPPORT */
     39 #ifdef MHD_SHA256_SUPPORT
     40 #  include "mhd_sha256_wrap.h"
     41 #endif /* MHD_SHA256_SUPPORT */
     42 #ifdef MHD_SHA512_256_SUPPORT
     43 #  include "sha512_256.h"
     44 #endif /* MHD_SHA512_256_SUPPORT */
     45 #include "mhd_locks.h"
     46 #include "mhd_mono_clock.h"
     47 #include "mhd_str.h"
     48 #include "mhd_compat.h"
     49 #include "mhd_bithelpers.h"
     50 #include "mhd_assert.h"
     51 
     52 
     53 /**
     54  * Allow re-use of the nonce-nc map array slot after #REUSE_TIMEOUT seconds,
     55  * if this slot is needed for the new nonce, while the old nonce was not used
     56  * even one time by the client.
     57  * Typically clients immediately use generated nonce for new request.
     58  */
     59 #define REUSE_TIMEOUT 30
     60 
     61 /**
     62  * The maximum value of artificial timestamp difference to avoid clashes.
     63  * The value must be suitable for bitwise AND operation.
     64  */
     65 #define DAUTH_JUMPBACK_MAX (0x7F)
     66 
     67 
     68 /**
     69  * 48 bit value in bytes
     70  */
     71 #define TIMESTAMP_BIN_SIZE (48 / 8)
     72 
     73 
     74 /**
     75  * Trim value to the TIMESTAMP_BIN_SIZE size
     76  */
     77 #define TRIM_TO_TIMESTAMP(value) \
     78   ((value) & ((UINT64_C (1) << (TIMESTAMP_BIN_SIZE * 8)) - 1))
     79 
     80 
     81 /**
     82  * The printed timestamp size in chars
     83  */
     84 #define TIMESTAMP_CHARS_LEN (TIMESTAMP_BIN_SIZE * 2)
     85 
     86 
     87 /**
     88  * Standard server nonce length, not including terminating null,
     89  *
     90  * @param digest_size digest size
     91  */
     92 #define NONCE_STD_LEN(digest_size) \
     93   ((digest_size) * 2 + TIMESTAMP_CHARS_LEN)
     94 
     95 
     96 #ifdef MHD_SHA512_256_SUPPORT
     97 /**
     98  * Maximum size of any digest hash supported by MHD.
     99  * (SHA-512/256 > MD5).
    100  */
    101 #define MAX_DIGEST SHA512_256_DIGEST_SIZE
    102 
    103 /**
    104  * The common size of SHA-256 digest and SHA-512/256 digest
    105  */
    106 #define SHA256_SHA512_256_DIGEST_SIZE SHA512_256_DIGEST_SIZE
    107 #elif defined(MHD_SHA256_SUPPORT)
    108 /**
    109  * Maximum size of any digest hash supported by MHD.
    110  * (SHA-256 > MD5).
    111  */
    112 #define MAX_DIGEST SHA256_DIGEST_SIZE
    113 
    114 /**
    115  * The common size of SHA-256 digest and SHA-512/256 digest
    116  */
    117 #define SHA256_SHA512_256_DIGEST_SIZE SHA256_DIGEST_SIZE
    118 #elif defined(MHD_MD5_SUPPORT)
    119 /**
    120  * Maximum size of any digest hash supported by MHD.
    121  */
    122 #define MAX_DIGEST MD5_DIGEST_SIZE
    123 #else  /* ! MHD_MD5_SUPPORT */
    124 #error At least one hashing algorithm must be enabled
    125 #endif /* ! MHD_MD5_SUPPORT */
    126 
    127 
    128 /**
    129  * Macro to avoid using VLAs if the compiler does not support them.
    130  */
    131 #ifndef HAVE_C_VARARRAYS
    132 /**
    133  * Return #MAX_DIGEST.
    134  *
    135  * @param n length of the digest to be used for a VLA
    136  */
    137 #define VLA_ARRAY_LEN_DIGEST(n) (MAX_DIGEST)
    138 
    139 #else
    140 /**
    141  * Return @a n.
    142  *
    143  * @param n length of the digest to be used for a VLA
    144  */
    145 #define VLA_ARRAY_LEN_DIGEST(n) (n)
    146 #endif
    147 
    148 /**
    149  * Check that @a n is below #MAX_DIGEST
    150  */
    151 #define VLA_CHECK_LEN_DIGEST(n) \
    152   do { if ((n) > MAX_DIGEST) MHD_PANIC (_ ("VLA too big.\n")); } while (0)
    153 
    154 /**
    155  * Maximum length of a username for digest authentication.
    156  */
    157 #define MAX_USERNAME_LENGTH 128
    158 
    159 /**
    160  * Maximum length of a realm for digest authentication.
    161  */
    162 #define MAX_REALM_LENGTH 256
    163 
    164 /**
    165  * Maximum length of the response in digest authentication.
    166  */
    167 #define MAX_AUTH_RESPONSE_LENGTH (MAX_DIGEST * 2)
    168 
    169 /**
    170  * The required prefix of parameter with the extended notation
    171  */
    172 #define MHD_DAUTH_EXT_PARAM_PREFIX "UTF-8'"
    173 
    174 /**
    175  * The minimal size of the prefix for parameter with the extended notation
    176  */
    177 #define MHD_DAUTH_EXT_PARAM_MIN_LEN \
    178   MHD_STATICSTR_LEN_ (MHD_DAUTH_EXT_PARAM_PREFIX "'")
    179 
    180 /**
    181  * The result of nonce-nc map array check.
    182  */
    183 enum MHD_CheckNonceNC_
    184 {
    185   /**
    186    * The nonce and NC are OK (valid and NC was not used before).
    187    */
    188   MHD_CHECK_NONCENC_OK = MHD_DAUTH_OK,
    189 
    190   /**
    191    * The 'nonce' was overwritten with newer 'nonce' in the same slot or
    192    * NC was already used.
    193    * The validity of the 'nonce' was not be checked.
    194    */
    195   MHD_CHECK_NONCENC_STALE = MHD_DAUTH_NONCE_STALE,
    196 
    197   /**
    198    * The 'nonce' is wrong, it was not generated before.
    199    */
    200   MHD_CHECK_NONCENC_WRONG = MHD_DAUTH_NONCE_WRONG
    201 };
    202 
    203 
    204 /**
    205  * Get base hash calculation algorithm from #MHD_DigestAuthAlgo3 value.
    206  * @param algo3 the MHD_DigestAuthAlgo3 value
    207  * @return the base hash calculation algorithm
    208  */
    209 _MHD_static_inline enum MHD_DigestBaseAlgo
    210 get_base_digest_algo (enum MHD_DigestAuthAlgo3 algo3)
    211 {
    212   unsigned int base_algo;
    213 
    214   base_algo =
    215     ((unsigned int) algo3)
    216     & ~((unsigned int)
    217         (MHD_DIGEST_AUTH_ALGO3_NON_SESSION
    218          | MHD_DIGEST_AUTH_ALGO3_SESSION));
    219   return (enum MHD_DigestBaseAlgo) base_algo;
    220 }
    221 
    222 
    223 /**
    224  * Get digest size for specified algorithm.
    225  *
    226  * Internal inline version.
    227  * @param algo3 the algorithm to check
    228  * @return the size of the digest or zero if the input value is not
    229  *         supported/valid
    230  */
    231 _MHD_static_inline size_t
    232 digest_get_hash_size (enum MHD_DigestAuthAlgo3 algo3)
    233 {
    234 #ifdef MHD_MD5_SUPPORT
    235   mhd_assert (MHD_MD5_DIGEST_SIZE == MD5_DIGEST_SIZE);
    236 #endif /* MHD_MD5_SUPPORT */
    237 #ifdef MHD_SHA256_SUPPORT
    238   mhd_assert (MHD_SHA256_DIGEST_SIZE == SHA256_DIGEST_SIZE);
    239 #endif /* MHD_SHA256_SUPPORT */
    240 #ifdef MHD_SHA512_256_SUPPORT
    241   mhd_assert (MHD_SHA512_256_DIGEST_SIZE == SHA512_256_DIGEST_SIZE);
    242 #ifdef MHD_SHA256_SUPPORT
    243   mhd_assert (SHA256_DIGEST_SIZE == SHA512_256_DIGEST_SIZE);
    244 #endif /* MHD_SHA256_SUPPORT */
    245 #endif /* MHD_SHA512_256_SUPPORT */
    246   /* Only one algorithm must be specified */
    247   mhd_assert (1 == \
    248               (((0 != (algo3 & MHD_DIGEST_BASE_ALGO_MD5)) ? 1 : 0)   \
    249                + ((0 != (algo3 & MHD_DIGEST_BASE_ALGO_SHA256)) ? 1 : 0)   \
    250                + ((0 != (algo3 & MHD_DIGEST_BASE_ALGO_SHA512_256)) ? 1 : 0)));
    251 #ifdef MHD_MD5_SUPPORT
    252   if (0 != (((unsigned int) algo3)
    253             & ((unsigned int) MHD_DIGEST_BASE_ALGO_MD5)))
    254     return MHD_MD5_DIGEST_SIZE;
    255   else
    256 #endif /* MHD_MD5_SUPPORT */
    257 #if defined(MHD_SHA256_SUPPORT) && defined(MHD_SHA512_256_SUPPORT)
    258   if (0 != (((unsigned int) algo3)
    259             & ( ((unsigned int) MHD_DIGEST_BASE_ALGO_SHA256)
    260                 | ((unsigned int) MHD_DIGEST_BASE_ALGO_SHA512_256))))
    261     return MHD_SHA256_DIGEST_SIZE; /* The same as SHA512_256_DIGEST_SIZE */
    262   else
    263 #elif defined(MHD_SHA256_SUPPORT)
    264   if (0 != (((unsigned int) algo3)
    265             & ((unsigned int) MHD_DIGEST_BASE_ALGO_SHA256)))
    266     return MHD_SHA256_DIGEST_SIZE;
    267   else
    268 #elif defined(MHD_SHA512_256_SUPPORT)
    269   if (0 != (((unsigned int) algo3)
    270             & ((unsigned int) MHD_DIGEST_BASE_ALGO_SHA512_256)))
    271     return MHD_SHA512_256_DIGEST_SIZE;
    272   else
    273 #endif /* MHD_SHA512_256_SUPPORT */
    274     (void) 0; /* Unsupported algorithm */
    275 
    276   return 0; /* Wrong input or unsupported algorithm */
    277 }
    278 
    279 
    280 /**
    281  * Get digest size for specified algorithm.
    282  *
    283  * The size of the digest specifies the size of the userhash, userdigest
    284  * and other parameters which size depends on used hash algorithm.
    285  * @param algo3 the algorithm to check
    286  * @return the size of the digest (either #MHD_MD5_DIGEST_SIZE or
    287  *         #MHD_SHA256_DIGEST_SIZE/MHD_SHA512_256_DIGEST_SIZE)
    288  *         or zero if the input value is not supported or not valid
    289  * @sa #MHD_digest_auth_calc_userdigest()
    290  * @sa #MHD_digest_auth_calc_userhash(), #MHD_digest_auth_calc_userhash_hex()
    291  * @note Available since #MHD_VERSION 0x00097701
    292  * @ingroup authentication
    293  */
    294 _MHD_EXTERN size_t
    295 MHD_digest_get_hash_size (enum MHD_DigestAuthAlgo3 algo3)
    296 {
    297   return digest_get_hash_size (algo3);
    298 }
    299 
    300 
    301 /**
    302  * Digest context data
    303  */
    304 union DigestCtx
    305 {
    306 #ifdef MHD_MD5_SUPPORT
    307   struct Md5CtxWr md5_ctx;
    308 #endif /* MHD_MD5_SUPPORT */
    309 #ifdef MHD_SHA256_SUPPORT
    310   struct Sha256CtxWr sha256_ctx;
    311 #endif /* MHD_SHA256_SUPPORT */
    312 #ifdef MHD_SHA512_256_SUPPORT
    313   struct Sha512_256Ctx sha512_256_ctx;
    314 #endif /* MHD_SHA512_256_SUPPORT */
    315 };
    316 
    317 /**
    318  * The digest calculation structure.
    319  */
    320 struct DigestAlgorithm
    321 {
    322   /**
    323    * A context for the digest algorithm, already initialized to be
    324    * useful for @e init, @e update and @e digest.
    325    */
    326   union DigestCtx ctx;
    327 
    328   /**
    329    * The hash calculation algorithm.
    330    */
    331   enum MHD_DigestBaseAlgo algo;
    332 
    333   /**
    334    * Buffer for hex-print of the final digest.
    335    */
    336 #ifdef _DEBUG
    337   bool uninitialised; /**< The structure has been not set-up */
    338   bool algo_selected; /**< The algorithm has been selected */
    339   bool ready_for_hashing; /**< The structure is ready to hash data */
    340   bool hashing; /**< Some data has been hashed, but the digest has not finalised yet */
    341 #endif /* _DEBUG */
    342 };
    343 
    344 
    345 /**
    346  * Return the size of the digest.
    347  * @param da the digest calculation structure to identify
    348  * @return the size of the digest.
    349  */
    350 _MHD_static_inline unsigned int
    351 digest_get_size (struct DigestAlgorithm *da)
    352 {
    353   mhd_assert (! da->uninitialised);
    354   mhd_assert (da->algo_selected);
    355 #ifdef MHD_MD5_SUPPORT
    356   if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
    357     return MD5_DIGEST_SIZE;
    358 #endif /* MHD_MD5_SUPPORT */
    359 #ifdef MHD_SHA256_SUPPORT
    360   if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
    361     return SHA256_DIGEST_SIZE;
    362 #endif /* MHD_SHA256_SUPPORT */
    363 #ifdef MHD_SHA512_256_SUPPORT
    364   if (MHD_DIGEST_BASE_ALGO_SHA512_256 == da->algo)
    365     return SHA512_256_DIGEST_SIZE;
    366 #endif /* MHD_SHA512_256_SUPPORT */
    367   mhd_assert (0); /* May not happen */
    368   return 0;
    369 }
    370 
    371 
    372 #if defined(MHD_MD5_HAS_DEINIT) || defined(MHD_SHA256_HAS_DEINIT)
    373 /**
    374  * Indicates presence of digest_deinit() function
    375  */
    376 #define MHD_DIGEST_HAS_DEINIT 1
    377 #endif /* MHD_MD5_HAS_DEINIT || MHD_SHA256_HAS_DEINIT */
    378 
    379 #ifdef MHD_DIGEST_HAS_DEINIT
    380 /**
    381  * Zero-initialise digest calculation structure.
    382  *
    383  * This initialisation is enough to safely call #digest_deinit() only.
    384  * To make any real digest calculation, #digest_setup_and_init() must be called.
    385  * @param da the digest calculation
    386  */
    387 _MHD_static_inline void
    388 digest_setup_zero (struct DigestAlgorithm *da)
    389 {
    390 #ifdef _DEBUG
    391   da->uninitialised = false;
    392   da->algo_selected = false;
    393   da->ready_for_hashing = false;
    394   da->hashing = false;
    395 #endif /* _DEBUG */
    396   da->algo = MHD_DIGEST_BASE_ALGO_INVALID;
    397 }
    398 
    399 
    400 /**
    401  * De-initialise digest calculation structure.
    402  *
    403  * This function must be called if #digest_setup_and_init() was called for
    404  * @a da.
    405  * This function must not be called if @a da was not initialised by
    406  * #digest_setup_and_init() or by #digest_setup_zero().
    407  * @param da the digest calculation
    408  */
    409 _MHD_static_inline void
    410 digest_deinit (struct DigestAlgorithm *da)
    411 {
    412   mhd_assert (! da->uninitialised);
    413 #ifdef MHD_MD5_HAS_DEINIT
    414   if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
    415     MHD_MD5_deinit (&da->ctx.md5_ctx);
    416   else
    417 #endif /* MHD_MD5_HAS_DEINIT */
    418 #ifdef MHD_SHA256_HAS_DEINIT
    419   if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
    420     MHD_SHA256_deinit (&da->ctx.sha256_ctx);
    421   else
    422 #endif /* MHD_SHA256_HAS_DEINIT */
    423   (void) 0;
    424   digest_setup_zero (da);
    425 }
    426 
    427 
    428 #else  /* ! MHD_DIGEST_HAS_DEINIT */
    429 #define digest_setup_zero(da) (void)0
    430 #define digest_deinit(da) (void)0
    431 #endif /* ! MHD_DIGEST_HAS_DEINIT */
    432 
    433 
    434 /**
    435  * Set-up the digest calculation structure and initialise with initial values.
    436  *
    437  * If @a da was successfully initialised, #digest_deinit() must be called
    438  * after finishing using of the @a da.
    439  *
    440  * This function must not be called more than once for any @a da.
    441  *
    442  * @param da the structure to set-up
    443  * @param algo the algorithm to use for digest calculation
    444  * @return boolean 'true' if successfully set-up,
    445  *         false otherwise.
    446  */
    447 _MHD_static_inline bool
    448 digest_init_one_time (struct DigestAlgorithm *da,
    449                       enum MHD_DigestBaseAlgo algo)
    450 {
    451 #ifdef _DEBUG
    452   da->uninitialised = false;
    453   da->algo_selected = false;
    454   da->ready_for_hashing = false;
    455   da->hashing = false;
    456 #endif /* _DEBUG */
    457 #ifdef MHD_MD5_SUPPORT
    458   if (MHD_DIGEST_BASE_ALGO_MD5 == algo)
    459   {
    460     da->algo = MHD_DIGEST_BASE_ALGO_MD5;
    461 #ifdef _DEBUG
    462     da->algo_selected = true;
    463 #endif
    464     MHD_MD5_init_one_time (&da->ctx.md5_ctx);
    465 #ifdef _DEBUG
    466     da->ready_for_hashing = true;
    467 #endif
    468     return true;
    469   }
    470 #endif /* MHD_MD5_SUPPORT */
    471 #ifdef MHD_SHA256_SUPPORT
    472   if (MHD_DIGEST_BASE_ALGO_SHA256 == algo)
    473   {
    474     da->algo = MHD_DIGEST_BASE_ALGO_SHA256;
    475 #ifdef _DEBUG
    476     da->algo_selected = true;
    477 #endif
    478     MHD_SHA256_init_one_time (&da->ctx.sha256_ctx);
    479 #ifdef _DEBUG
    480     da->ready_for_hashing = true;
    481 #endif
    482     return true;
    483   }
    484 #endif /* MHD_SHA256_SUPPORT */
    485 #ifdef MHD_SHA512_256_SUPPORT
    486   if (MHD_DIGEST_BASE_ALGO_SHA512_256 == algo)
    487   {
    488     da->algo = MHD_DIGEST_BASE_ALGO_SHA512_256;
    489 #ifdef _DEBUG
    490     da->algo_selected = true;
    491 #endif
    492     MHD_SHA512_256_init (&da->ctx.sha512_256_ctx);
    493 #ifdef _DEBUG
    494     da->ready_for_hashing = true;
    495 #endif
    496     return true;
    497   }
    498 #endif /* MHD_SHA512_256_SUPPORT */
    499 
    500   da->algo = MHD_DIGEST_BASE_ALGO_INVALID;
    501   return false; /* Unsupported or bad algorithm */
    502 }
    503 
    504 
    505 /**
    506  * Feed digest calculation with more data.
    507  * @param da the digest calculation
    508  * @param data the data to process
    509  * @param length the size of the @a data in bytes
    510  */
    511 _MHD_static_inline void
    512 digest_update (struct DigestAlgorithm *da,
    513                const void *data,
    514                size_t length)
    515 {
    516   mhd_assert (! da->uninitialised);
    517   mhd_assert (da->algo_selected);
    518   mhd_assert (da->ready_for_hashing);
    519 #ifdef MHD_MD5_SUPPORT
    520   if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
    521     MHD_MD5_update (&da->ctx.md5_ctx, (const uint8_t *) data, length);
    522   else
    523 #endif /* MHD_MD5_SUPPORT */
    524 #ifdef MHD_SHA256_SUPPORT
    525   if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
    526     MHD_SHA256_update (&da->ctx.sha256_ctx, (const uint8_t *) data, length);
    527   else
    528 #endif /* MHD_SHA256_SUPPORT */
    529 #ifdef MHD_SHA512_256_SUPPORT
    530   if (MHD_DIGEST_BASE_ALGO_SHA512_256 == da->algo)
    531     MHD_SHA512_256_update (&da->ctx.sha512_256_ctx,
    532                            (const uint8_t *) data, length);
    533   else
    534 #endif /* MHD_SHA512_256_SUPPORT */
    535   mhd_assert (0);   /* May not happen */
    536 #ifdef _DEBUG
    537   da->hashing = true;
    538 #endif
    539 }
    540 
    541 
    542 /**
    543  * Feed digest calculation with more data from string.
    544  * @param da the digest calculation
    545  * @param str the zero-terminated string to process
    546  */
    547 _MHD_static_inline void
    548 digest_update_str (struct DigestAlgorithm *da,
    549                    const char *str)
    550 {
    551   const size_t str_len = strlen (str);
    552   digest_update (da, (const uint8_t *) str, str_len);
    553 }
    554 
    555 
    556 /**
    557  * Feed digest calculation with single colon ':' character.
    558  * @param da the digest calculation
    559  * @param str the zero-terminated string to process
    560  */
    561 _MHD_static_inline void
    562 digest_update_with_colon (struct DigestAlgorithm *da)
    563 {
    564   static const uint8_t colon = (uint8_t) ':';
    565   digest_update (da, &colon, 1);
    566 }
    567 
    568 
    569 /**
    570  * Finally calculate hash (the digest).
    571  * @param da the digest calculation
    572  * @param[out] digest the pointer to the buffer to put calculated digest,
    573  *                    must be at least digest_get_size(da) bytes large
    574  */
    575 _MHD_static_inline void
    576 digest_calc_hash (struct DigestAlgorithm *da, uint8_t *digest)
    577 {
    578   mhd_assert (! da->uninitialised);
    579   mhd_assert (da->algo_selected);
    580   mhd_assert (da->ready_for_hashing);
    581 #ifdef MHD_MD5_SUPPORT
    582   if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
    583   {
    584 #ifdef MHD_MD5_HAS_FINISH
    585     MHD_MD5_finish (&da->ctx.md5_ctx, digest);
    586 #ifdef _DEBUG
    587     da->ready_for_hashing = false;
    588 #endif /* _DEBUG */
    589 #else  /* ! MHD_MD5_HAS_FINISH */
    590     MHD_MD5_finish_reset (&da->ctx.md5_ctx, digest);
    591 #ifdef _DEBUG
    592     da->ready_for_hashing = true;
    593 #endif /* _DEBUG */
    594 #endif /* ! MHD_MD5_HAS_FINISH */
    595   }
    596   else
    597 #endif /* MHD_MD5_SUPPORT */
    598 #ifdef MHD_SHA256_SUPPORT
    599   if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
    600   {
    601 #ifdef MHD_SHA256_HAS_FINISH
    602     MHD_SHA256_finish (&da->ctx.sha256_ctx, digest);
    603 #ifdef _DEBUG
    604     da->ready_for_hashing = false;
    605 #endif /* _DEBUG */
    606 #else  /* ! MHD_SHA256_HAS_FINISH */
    607     MHD_SHA256_finish_reset (&da->ctx.sha256_ctx, digest);
    608 #ifdef _DEBUG
    609     da->ready_for_hashing = true;
    610 #endif /* _DEBUG */
    611 #endif /* ! MHD_SHA256_HAS_FINISH */
    612   }
    613   else
    614 #endif /* MHD_SHA256_SUPPORT */
    615 #ifdef MHD_SHA512_256_SUPPORT
    616   if (MHD_DIGEST_BASE_ALGO_SHA512_256 == da->algo)
    617   {
    618     MHD_SHA512_256_finish (&da->ctx.sha512_256_ctx, digest);
    619 #ifdef _DEBUG
    620     da->ready_for_hashing = false;
    621 #endif /* _DEBUG */
    622   }
    623   else
    624 #endif /* MHD_SHA512_256_SUPPORT */
    625   mhd_assert (0);   /* Should not happen */
    626 #ifdef _DEBUG
    627   da->hashing = false;
    628 #endif /* _DEBUG */
    629 }
    630 
    631 
    632 /**
    633  * Reset the digest calculation structure.
    634  *
    635  * @param da the structure to reset
    636  */
    637 _MHD_static_inline void
    638 digest_reset (struct DigestAlgorithm *da)
    639 {
    640   mhd_assert (! da->uninitialised);
    641   mhd_assert (da->algo_selected);
    642   mhd_assert (! da->hashing);
    643 #ifdef MHD_MD5_SUPPORT
    644   if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
    645   {
    646 #ifdef MHD_MD5_HAS_FINISH
    647     mhd_assert (! da->ready_for_hashing);
    648 #else  /* ! MHD_MD5_HAS_FINISH */
    649     mhd_assert (da->ready_for_hashing);
    650 #endif /* ! MHD_MD5_HAS_FINISH */
    651     MHD_MD5_reset (&da->ctx.md5_ctx);
    652 #ifdef _DEBUG
    653     da->ready_for_hashing = true;
    654 #endif /* _DEBUG */
    655   }
    656   else
    657 #endif /* MHD_MD5_SUPPORT */
    658 #ifdef MHD_SHA256_SUPPORT
    659   if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
    660   {
    661 #ifdef MHD_SHA256_HAS_FINISH
    662     mhd_assert (! da->ready_for_hashing);
    663 #else  /* ! MHD_SHA256_HAS_FINISH */
    664     mhd_assert (da->ready_for_hashing);
    665 #endif /* ! MHD_SHA256_HAS_FINISH */
    666     MHD_SHA256_reset (&da->ctx.sha256_ctx);
    667 #ifdef _DEBUG
    668     da->ready_for_hashing = true;
    669 #endif /* _DEBUG */
    670   }
    671   else
    672 #endif /* MHD_SHA256_SUPPORT */
    673 #ifdef MHD_SHA512_256_SUPPORT
    674   if (MHD_DIGEST_BASE_ALGO_SHA512_256 == da->algo)
    675   {
    676     mhd_assert (! da->ready_for_hashing);
    677     MHD_SHA512_256_init (&da->ctx.sha512_256_ctx);
    678 #ifdef _DEBUG
    679     da->ready_for_hashing = true;
    680 #endif
    681   }
    682   else
    683 #endif /* MHD_SHA512_256_SUPPORT */
    684   {
    685 #ifdef _DEBUG
    686     da->ready_for_hashing = false;
    687 #endif
    688     mhd_assert (0); /* May not happen, bad algorithm */
    689   }
    690 }
    691 
    692 
    693 #if defined(MHD_MD5_HAS_EXT_ERROR) || defined(MHD_SHA256_HAS_EXT_ERROR)
    694 /**
    695  * Indicates that digest algorithm has external error status
    696  */
    697 #define MHD_DIGEST_HAS_EXT_ERROR 1
    698 #endif /* MHD_MD5_HAS_EXT_ERROR || MHD_SHA256_HAS_EXT_ERROR */
    699 
    700 #ifdef MHD_DIGEST_HAS_EXT_ERROR
    701 /**
    702  * Get external error code.
    703  *
    704  * When external digest calculation used, an error may occur during
    705  * initialisation or hashing data. This function checks whether external
    706  * error has been reported for digest calculation.
    707  * @param da the digest calculation
    708  * @return true if external error occurs
    709  */
    710 _MHD_static_inline bool
    711 digest_ext_error (struct DigestAlgorithm *da)
    712 {
    713   mhd_assert (! da->uninitialised);
    714   mhd_assert (da->algo_selected);
    715 #ifdef MHD_MD5_HAS_EXT_ERROR
    716   if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
    717     return 0 != da->ctx.md5_ctx.ext_error;
    718 #endif /* MHD_MD5_HAS_EXT_ERROR */
    719 #ifdef MHD_SHA256_HAS_EXT_ERROR
    720   if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
    721     return 0 != da->ctx.sha256_ctx.ext_error;
    722 #endif /* MHD_MD5_HAS_EXT_ERROR */
    723   return false;
    724 }
    725 
    726 
    727 #else  /* ! MHD_DIGEST_HAS_EXT_ERROR */
    728 #define digest_ext_error(da) (false)
    729 #endif /* ! MHD_DIGEST_HAS_EXT_ERROR */
    730 
    731 
    732 /**
    733  * Extract timestamp from the given nonce.
    734  * @param nonce the nonce to check
    735  * @param noncelen the length of the nonce, zero for autodetect
    736  * @param[out] ptimestamp the pointer to store extracted timestamp
    737  * @return true if timestamp was extracted,
    738  *         false if nonce does not have valid timestamp.
    739  */
    740 static bool
    741 get_nonce_timestamp (const char *const nonce,
    742                      size_t noncelen,
    743                      uint64_t *const ptimestamp)
    744 {
    745   if (0 == noncelen)
    746     noncelen = strlen (nonce);
    747 
    748   if (true
    749 #ifdef MHD_MD5_SUPPORT
    750       && (NONCE_STD_LEN (MD5_DIGEST_SIZE) != noncelen)
    751 #endif /* MHD_MD5_SUPPORT */
    752 #if defined(MHD_SHA256_SUPPORT) || defined(MHD_SHA512_256_SUPPORT)
    753       && (NONCE_STD_LEN (SHA256_SHA512_256_DIGEST_SIZE) != noncelen)
    754 #endif /* MHD_SHA256_SUPPORT */
    755       )
    756     return false;
    757 
    758   if (TIMESTAMP_CHARS_LEN !=
    759       MHD_strx_to_uint64_n_ (nonce + noncelen - TIMESTAMP_CHARS_LEN,
    760                              TIMESTAMP_CHARS_LEN,
    761                              ptimestamp))
    762     return false;
    763   return true;
    764 }
    765 
    766 
    767 MHD_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE_
    768 
    769 /**
    770  * Super-fast xor-based "hash" function
    771  *
    772  * @param data the data to calculate hash for
    773  * @param data_size the size of the data in bytes
    774  * @return the "hash"
    775  */
    776 static uint32_t
    777 fast_simple_hash (const uint8_t *data,
    778                   size_t data_size)
    779 {
    780   uint32_t hash;
    781 
    782   if (0 != data_size)
    783   {
    784     size_t i;
    785     hash = data[0];
    786     for (i = 1; i < data_size; i++)
    787       hash = _MHD_ROTL32 (hash, 7) ^ data[i];
    788   }
    789   else
    790     hash = 0;
    791 
    792   return hash;
    793 }
    794 
    795 
    796 MHD_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE_
    797 
    798 /**
    799  * Get index of the nonce in the nonce-nc map array.
    800  *
    801  * @param arr_size the size of nonce_nc array
    802  * @param nonce the pointer that referenced a zero-terminated array of nonce
    803  * @param noncelen the length of @a nonce, in characters
    804  * @return #MHD_YES if successful, #MHD_NO if invalid (or we have no NC array)
    805  */
    806 static size_t
    807 get_nonce_nc_idx (size_t arr_size,
    808                   const char *nonce,
    809                   size_t noncelen)
    810 {
    811   mhd_assert (0 != arr_size);
    812   mhd_assert (0 != noncelen);
    813   return fast_simple_hash ((const uint8_t *) nonce, noncelen) % arr_size;
    814 }
    815 
    816 
    817 /**
    818  * Check nonce-nc map array with the new nonce counter.
    819  *
    820  * @param connection The MHD connection structure
    821  * @param nonce the pointer that referenced hex nonce, does not need to be
    822  *              zero-terminated
    823  * @param noncelen the length of @a nonce, in characters
    824  * @param nc The nonce counter
    825  * @return #MHD_DAUTH_NONCENC_OK if successful,
    826  *         #MHD_DAUTH_NONCENC_STALE if nonce is stale (or no nonce-nc array
    827  *         is available),
    828  *         #MHD_DAUTH_NONCENC_WRONG if nonce was not recodered in nonce-nc map
    829  *         array, while it should.
    830  */
    831 static enum MHD_CheckNonceNC_
    832 check_nonce_nc (struct MHD_Connection *connection,
    833                 const char *nonce,
    834                 size_t noncelen,
    835                 uint64_t nonce_time,
    836                 uint64_t nc)
    837 {
    838   struct MHD_Daemon *daemon = MHD_get_master (connection->daemon);
    839   struct MHD_NonceNc *nn;
    840   uint32_t mod;
    841   enum MHD_CheckNonceNC_ ret;
    842 
    843   mhd_assert (0 != noncelen);
    844   mhd_assert (0 != nc);
    845   if (MAX_DIGEST_NONCE_LENGTH < noncelen)
    846     return MHD_CHECK_NONCENC_WRONG; /* This should be impossible, but static analysis
    847                       tools have a hard time with it *and* this also
    848                       protects against unsafe modifications that may
    849                       happen in the future... */
    850   mod = daemon->nonce_nc_size;
    851   if (0 == mod)
    852     return MHD_CHECK_NONCENC_STALE;  /* no array! */
    853   if (nc >= UINT32_MAX - 64)
    854     return MHD_CHECK_NONCENC_STALE;  /* Overflow, unrealistically high value */
    855 
    856   nn = &daemon->nnc[get_nonce_nc_idx (mod, nonce, noncelen)];
    857 
    858   MHD_mutex_lock_chk_ (&daemon->nnc_lock);
    859 
    860   mhd_assert (0 == nn->nonce[noncelen]); /* The old value must be valid */
    861 
    862   if ( (0 != memcmp (nn->nonce, nonce, noncelen)) ||
    863        (0 != nn->nonce[noncelen]) )
    864   { /* The nonce in the slot does not match nonce from the client */
    865     if (0 == nn->nonce[0])
    866     { /* The slot was never used, while the client's nonce value should be
    867        * recorded when it was generated by MHD */
    868       ret = MHD_CHECK_NONCENC_WRONG;
    869     }
    870     else if (0 != nn->nonce[noncelen])
    871     { /* The value is the slot is wrong */
    872       ret =  MHD_CHECK_NONCENC_STALE;
    873     }
    874     else
    875     {
    876       uint64_t slot_ts; /**< The timestamp in the slot */
    877       if (! get_nonce_timestamp (nn->nonce, noncelen, &slot_ts))
    878       {
    879         mhd_assert (0); /* The value is the slot is wrong */
    880         ret = MHD_CHECK_NONCENC_STALE;
    881       }
    882       else
    883       {
    884         /* Unsigned value, will be large if nonce_time is less than slot_ts */
    885         const uint64_t ts_diff = TRIM_TO_TIMESTAMP (nonce_time - slot_ts);
    886         if ((REUSE_TIMEOUT * 1000) >= ts_diff)
    887         {
    888           /* The nonce from the client may not have been placed in the slot
    889            * because another nonce in that slot has not yet expired. */
    890           ret = MHD_CHECK_NONCENC_STALE;
    891         }
    892         else if (TRIM_TO_TIMESTAMP (UINT64_MAX) / 2 >= ts_diff)
    893         {
    894           /* Too large value means that nonce_time is less than slot_ts.
    895            * The nonce from the client may have been overwritten by the newer
    896            * nonce. */
    897           ret = MHD_CHECK_NONCENC_STALE;
    898         }
    899         else
    900         {
    901           /* The nonce from the client should be generated after the nonce
    902            * in the slot has been expired, the nonce must be recorded, but
    903            * it's not. */
    904           ret = MHD_CHECK_NONCENC_WRONG;
    905         }
    906       }
    907     }
    908   }
    909   else if (nc > nn->nc)
    910   {
    911     /* 'nc' is larger, shift bitmask and bump limit */
    912     const uint32_t jump_size = (uint32_t) nc - nn->nc;
    913     if (64 > jump_size)
    914     {
    915       /* small jump, less than mask width */
    916       nn->nmask <<= jump_size;
    917       /* Set bit for the old 'nc' value */
    918       nn->nmask |= (UINT64_C (1) << (jump_size - 1));
    919     }
    920     else if (64 == jump_size)
    921       nn->nmask = (UINT64_C (1) << 63);
    922     else
    923       nn->nmask = 0;                /* big jump, unset all bits in the mask */
    924     nn->nc = (uint32_t) nc;
    925     ret = MHD_CHECK_NONCENC_OK;
    926   }
    927   else if (nc < nn->nc)
    928   {
    929     /* Note that we use 64 here, as we do not store the
    930        bit for 'nn->nc' itself in 'nn->nmask' */
    931     if ( (nc + 64 >= nn->nc) &&
    932          (0 == ((UINT64_C (1) << (nn->nc - nc - 1)) & nn->nmask)) )
    933     {
    934       /* Out-of-order nonce, but within 64-bit bitmask, set bit */
    935       nn->nmask |= (UINT64_C (1) << (nn->nc - nc - 1));
    936       ret = MHD_CHECK_NONCENC_OK;
    937     }
    938     else
    939       /* 'nc' was already used or too old (more then 64 values ago) */
    940       ret = MHD_CHECK_NONCENC_STALE;
    941   }
    942   else /* if (nc == nn->nc) */
    943     /* 'nc' was already used */
    944     ret = MHD_CHECK_NONCENC_STALE;
    945 
    946   MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
    947 
    948   return ret;
    949 }
    950 
    951 
    952 /**
    953  * Get username type used by the client.
    954  * This function does not check whether userhash can be decoded or
    955  * extended notation (if used) is valid.
    956  * @param params the Digest Authorization parameters
    957  * @return the type of username
    958  */
    959 _MHD_static_inline enum MHD_DigestAuthUsernameType
    960 get_rq_uname_type (const struct MHD_RqDAuth *params)
    961 {
    962   if (NULL != params->username.value.str)
    963   {
    964     if (NULL == params->username_ext.value.str)
    965       return params->userhash ?
    966              MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH :
    967              MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD;
    968     else  /* Both 'username' and 'username*' are used */
    969       return MHD_DIGEST_AUTH_UNAME_TYPE_INVALID;
    970   }
    971   else if (NULL != params->username_ext.value.str)
    972   {
    973     if (! params->username_ext.quoted && ! params->userhash &&
    974         (MHD_DAUTH_EXT_PARAM_MIN_LEN <= params->username_ext.value.len) )
    975       return MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED;
    976     else
    977       return MHD_DIGEST_AUTH_UNAME_TYPE_INVALID;
    978   }
    979 
    980   return MHD_DIGEST_AUTH_UNAME_TYPE_MISSING;
    981 }
    982 
    983 
    984 /**
    985  * Get total size required for 'username' and 'userhash_bin'
    986  * @param params the Digest Authorization parameters
    987  * @param uname_type the type of username
    988  * @return the total size required for 'username' and
    989  *         'userhash_bin' is userhash is used
    990  */
    991 _MHD_static_inline size_t
    992 get_rq_unames_size (const struct MHD_RqDAuth *params,
    993                     enum MHD_DigestAuthUsernameType uname_type)
    994 {
    995   size_t s;
    996 
    997   mhd_assert (get_rq_uname_type (params) == uname_type);
    998   s = 0;
    999   if ((MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD == uname_type) ||
   1000       (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH == uname_type) )
   1001   {
   1002     s += params->username.value.len + 1; /* Add one byte for zero-termination */
   1003     if (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH == uname_type)
   1004       s += (params->username.value.len + 1) / 2;
   1005   }
   1006   else if (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED == uname_type)
   1007     s += params->username_ext.value.len
   1008          - MHD_DAUTH_EXT_PARAM_MIN_LEN + 1; /* Add one byte for zero-termination */
   1009   return s;
   1010 }
   1011 
   1012 
   1013 /**
   1014  * Get unquoted version of Digest Authorization parameter.
   1015  * This function automatically zero-teminate the result.
   1016  * @param param the parameter to extract
   1017  * @param[out] buf the output buffer, must be enough size to hold the result,
   1018  *                 the recommended size is 'param->value.len + 1'
   1019  * @return the size of the result, not including the terminating zero
   1020  */
   1021 static size_t
   1022 get_rq_param_unquoted_copy_z (const struct MHD_RqDAuthParam *param, char *buf)
   1023 {
   1024   size_t len;
   1025   mhd_assert (NULL != param->value.str);
   1026   if (! param->quoted)
   1027   {
   1028     memcpy (buf, param->value.str, param->value.len);
   1029     buf [param->value.len] = 0;
   1030     return param->value.len;
   1031   }
   1032 
   1033   len = MHD_str_unquote (param->value.str, param->value.len, buf);
   1034   mhd_assert (0 != len);
   1035   mhd_assert (len < param->value.len);
   1036   buf[len] = 0;
   1037   return len;
   1038 }
   1039 
   1040 
   1041 /**
   1042  * Get decoded version of username from extended notation.
   1043  * This function automatically zero-teminate the result.
   1044  * @param uname_ext the string of client's 'username*' parameter value
   1045  * @param uname_ext_len the length of @a uname_ext in chars
   1046  * @param[out] buf the output buffer to put decoded username value
   1047  * @param buf_size the size of @a buf
   1048  * @return the number of characters copied to the output buffer or
   1049  *         -1 if wrong extended notation is used.
   1050  */
   1051 static ssize_t
   1052 get_rq_extended_uname_copy_z (const char *uname_ext, size_t uname_ext_len,
   1053                               char *buf, size_t buf_size)
   1054 {
   1055   size_t r;
   1056   size_t w;
   1057   if ((size_t) SSIZE_MAX < uname_ext_len)
   1058     return -1; /* Too long input string */
   1059 
   1060   if (MHD_DAUTH_EXT_PARAM_MIN_LEN > uname_ext_len)
   1061     return -1; /* Required prefix is missing */
   1062 
   1063   if (! MHD_str_equal_caseless_bin_n_ (uname_ext, MHD_DAUTH_EXT_PARAM_PREFIX,
   1064                                        MHD_STATICSTR_LEN_ ( \
   1065                                          MHD_DAUTH_EXT_PARAM_PREFIX)))
   1066     return -1; /* Only UTF-8 is supported, as it is implied by RFC 7616 */
   1067 
   1068   r = MHD_STATICSTR_LEN_ (MHD_DAUTH_EXT_PARAM_PREFIX);
   1069   /* Skip language tag */
   1070   while (r < uname_ext_len && '\'' != uname_ext[r])
   1071   {
   1072     const char chr = uname_ext[r];
   1073     if ((' ' == chr) || ('\t' == chr) || ('\"' == chr) || (',' == chr) ||
   1074         (';' == chr) )
   1075       return -1; /* Wrong char in language tag */
   1076     r++;
   1077   }
   1078   if (r >= uname_ext_len)
   1079     return -1; /* The end of the language tag was not found */
   1080   r++; /* Advance to the next char */
   1081 
   1082   w = MHD_str_pct_decode_strict_n_ (uname_ext + r, uname_ext_len - r,
   1083                                     buf, buf_size);
   1084   if ((0 == w) && (0 != uname_ext_len - r))
   1085     return -1; /* Broken percent encoding */
   1086   buf[w] = 0; /* Zero terminate the result */
   1087   mhd_assert (SSIZE_MAX > w);
   1088   return (ssize_t) w;
   1089 }
   1090 
   1091 
   1092 /**
   1093  * Get copy of username used by the client.
   1094  * @param params the Digest Authorization parameters
   1095  * @param uname_type the type of username
   1096  * @param[out] uname_info the pointer to the structure to be filled
   1097  * @param buf the buffer to be used for usernames
   1098  * @param buf_size the size of the @a buf
   1099  * @return the size of the @a buf used by pointers in @a unames structure
   1100  */
   1101 static size_t
   1102 get_rq_uname (const struct MHD_RqDAuth *params,
   1103               enum MHD_DigestAuthUsernameType uname_type,
   1104               struct MHD_DigestAuthUsernameInfo *uname_info,
   1105               uint8_t *buf,
   1106               size_t buf_size)
   1107 {
   1108   size_t buf_used;
   1109 
   1110   buf_used = 0;
   1111   mhd_assert (get_rq_uname_type (params) == uname_type);
   1112   mhd_assert (MHD_DIGEST_AUTH_UNAME_TYPE_INVALID != uname_type);
   1113   mhd_assert (MHD_DIGEST_AUTH_UNAME_TYPE_MISSING != uname_type);
   1114 
   1115   uname_info->username = NULL;
   1116   uname_info->username_len = 0;
   1117   uname_info->userhash_hex = NULL;
   1118   uname_info->userhash_hex_len = 0;
   1119   uname_info->userhash_bin = NULL;
   1120 
   1121   if (MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD == uname_type)
   1122   {
   1123     uname_info->username = (char *) (buf + buf_used);
   1124     uname_info->username_len =
   1125       get_rq_param_unquoted_copy_z (&params->username,
   1126                                     uname_info->username);
   1127     buf_used += uname_info->username_len + 1;
   1128     uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD;
   1129   }
   1130   else if (MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH == uname_type)
   1131   {
   1132     size_t res;
   1133 
   1134     uname_info->userhash_hex = (char *) (buf + buf_used);
   1135     uname_info->userhash_hex_len =
   1136       get_rq_param_unquoted_copy_z (&params->username,
   1137                                     uname_info->userhash_hex);
   1138     buf_used += uname_info->userhash_hex_len + 1;
   1139     uname_info->userhash_bin = (uint8_t *) (buf + buf_used);
   1140     res = MHD_hex_to_bin (uname_info->userhash_hex,
   1141                           uname_info->userhash_hex_len,
   1142                           uname_info->userhash_bin);
   1143     if (res != uname_info->userhash_hex_len / 2)
   1144     {
   1145       uname_info->userhash_bin = NULL;
   1146       uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_INVALID;
   1147     }
   1148     else
   1149     {
   1150       /* Avoid pointers outside allocated region when the size is zero */
   1151       if (0 == res)
   1152         uname_info->userhash_bin = (uint8_t *) uname_info->username;
   1153       uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH;
   1154       buf_used += res;
   1155     }
   1156   }
   1157   else if (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED == uname_type)
   1158   {
   1159     ssize_t res;
   1160     res = get_rq_extended_uname_copy_z (params->username_ext.value.str,
   1161                                         params->username_ext.value.len,
   1162                                         (char *) (buf + buf_used),
   1163                                         buf_size - buf_used);
   1164     if (0 > res)
   1165       uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_INVALID;
   1166     else
   1167     {
   1168       uname_info->username = (char *) (buf + buf_used);
   1169       uname_info->username_len = (size_t) res;
   1170       uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED;
   1171       buf_used += uname_info->username_len + 1;
   1172     }
   1173   }
   1174   else
   1175   {
   1176     mhd_assert (0);
   1177     uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_INVALID;
   1178   }
   1179   mhd_assert (buf_size >= buf_used);
   1180   return buf_used;
   1181 }
   1182 
   1183 
   1184 /**
   1185  * Result of request's Digest Authorization 'nc' value extraction
   1186  */
   1187 enum MHD_GetRqNCResult
   1188 {
   1189   MHD_GET_RQ_NC_NONE = -1,    /**< No 'nc' value */
   1190   MHD_GET_RQ_NC_VALID = 0,    /**< Readable 'nc' value */
   1191   MHD_GET_RQ_NC_TOO_LONG = 1, /**< The 'nc' value is too long */
   1192   MHD_GET_RQ_NC_TOO_LARGE = 2,/**< The 'nc' value is too big to fit uint32_t */
   1193   MHD_GET_RQ_NC_BROKEN = 3    /**< The 'nc' value is not a number */
   1194 };
   1195 
   1196 
   1197 /**
   1198  * Get 'nc' value from request's Authorization header
   1199  * @param params the request digest authentication
   1200  * @param[out] nc the pointer to put nc value to
   1201  * @return enum value indicating the result
   1202  */
   1203 static enum MHD_GetRqNCResult
   1204 get_rq_nc (const struct MHD_RqDAuth *params,
   1205            uint32_t *nc)
   1206 {
   1207   const struct MHD_RqDAuthParam *const nc_param =
   1208     &params->nc;
   1209   char unq[16];
   1210   const char *val;
   1211   size_t val_len;
   1212   size_t res;
   1213   uint64_t nc_val;
   1214 
   1215   if (NULL == nc_param->value.str)
   1216     return MHD_GET_RQ_NC_NONE;
   1217 
   1218   if (0 == nc_param->value.len)
   1219     return MHD_GET_RQ_NC_BROKEN;
   1220 
   1221   if (! nc_param->quoted)
   1222   {
   1223     val = nc_param->value.str;
   1224     val_len = nc_param->value.len;
   1225   }
   1226   else
   1227   {
   1228     /* Actually no backslashes must be used in 'nc' */
   1229     if (sizeof(unq) < params->nc.value.len)
   1230       return MHD_GET_RQ_NC_TOO_LONG;
   1231     val_len = MHD_str_unquote (nc_param->value.str, nc_param->value.len, unq);
   1232     if (0 == val_len)
   1233       return MHD_GET_RQ_NC_BROKEN;
   1234     val = unq;
   1235   }
   1236 
   1237   res = MHD_strx_to_uint64_n_ (val, val_len, &nc_val);
   1238   if (0 == res)
   1239   {
   1240     const char f = val[0];
   1241     if ( (('9' >= f) && ('0' <= f)) ||
   1242          (('F' >= f) && ('A' <= f)) ||
   1243          (('a' <= f) && ('f' >= f)) )
   1244       return MHD_GET_RQ_NC_TOO_LARGE;
   1245     else
   1246       return MHD_GET_RQ_NC_BROKEN;
   1247   }
   1248   if (val_len != res)
   1249     return MHD_GET_RQ_NC_BROKEN;
   1250   if (UINT32_MAX < nc_val)
   1251     return MHD_GET_RQ_NC_TOO_LARGE;
   1252   *nc = (uint32_t) nc_val;
   1253   return MHD_GET_RQ_NC_VALID;
   1254 }
   1255 
   1256 
   1257 /**
   1258  * Get information about Digest Authorization client's header.
   1259  *
   1260  * @param connection The MHD connection structure
   1261  * @return NULL no valid Digest Authorization header is used in the request;
   1262  *         a pointer structure with information if the valid request header
   1263  *         found, free using #MHD_free().
   1264  * @note Available since #MHD_VERSION 0x00097701
   1265  * @ingroup authentication
   1266  */
   1267 _MHD_EXTERN struct MHD_DigestAuthInfo *
   1268 MHD_digest_auth_get_request_info3 (struct MHD_Connection *connection)
   1269 {
   1270   const struct MHD_RqDAuth *params;
   1271   struct MHD_DigestAuthInfo *info;
   1272   enum MHD_DigestAuthUsernameType uname_type;
   1273   size_t unif_buf_size;
   1274   uint8_t *unif_buf_ptr;
   1275   size_t unif_buf_used;
   1276   enum MHD_GetRqNCResult nc_res;
   1277 
   1278   params = MHD_get_rq_dauth_params_ (connection);
   1279   if (NULL == params)
   1280     return NULL;
   1281 
   1282   unif_buf_size = 0;
   1283 
   1284   uname_type = get_rq_uname_type (params);
   1285 
   1286   unif_buf_size += get_rq_unames_size (params, uname_type);
   1287 
   1288   if (NULL != params->opaque.value.str)
   1289     unif_buf_size += params->opaque.value.len + 1;  /* Add one for zero-termination */
   1290   if (NULL != params->realm.value.str)
   1291     unif_buf_size += params->realm.value.len + 1;   /* Add one for zero-termination */
   1292   info = (struct MHD_DigestAuthInfo *)
   1293          MHD_calloc_ (1, (sizeof(struct MHD_DigestAuthInfo)) + unif_buf_size);
   1294   unif_buf_ptr = (uint8_t *) (info + 1);
   1295   unif_buf_used = 0;
   1296 
   1297   info->algo3 = params->algo3;
   1298 
   1299   if ( (MHD_DIGEST_AUTH_UNAME_TYPE_MISSING != uname_type) &&
   1300        (MHD_DIGEST_AUTH_UNAME_TYPE_INVALID != uname_type) )
   1301     unif_buf_used +=
   1302       get_rq_uname (params, uname_type,
   1303                     (struct MHD_DigestAuthUsernameInfo *) info,
   1304                     unif_buf_ptr + unif_buf_used,
   1305                     unif_buf_size - unif_buf_used);
   1306   else
   1307     info->uname_type = uname_type;
   1308 
   1309   if (NULL != params->opaque.value.str)
   1310   {
   1311     info->opaque = (char *) (unif_buf_ptr + unif_buf_used);
   1312     info->opaque_len = get_rq_param_unquoted_copy_z (&params->opaque,
   1313                                                      info->opaque);
   1314     unif_buf_used += info->opaque_len + 1;
   1315   }
   1316   if (NULL != params->realm.value.str)
   1317   {
   1318     info->realm = (char *) (unif_buf_ptr + unif_buf_used);
   1319     info->realm_len = get_rq_param_unquoted_copy_z (&params->realm,
   1320                                                     info->realm);
   1321     unif_buf_used += info->realm_len + 1;
   1322   }
   1323 
   1324   mhd_assert (unif_buf_size >= unif_buf_used);
   1325 
   1326   info->qop = params->qop;
   1327 
   1328   if (NULL != params->cnonce.value.str)
   1329     info->cnonce_len = params->cnonce.value.len;
   1330   else
   1331     info->cnonce_len = 0;
   1332 
   1333   nc_res = get_rq_nc (params, &info->nc);
   1334   if (MHD_GET_RQ_NC_VALID != nc_res)
   1335     info->nc = MHD_DIGEST_AUTH_INVALID_NC_VALUE;
   1336 
   1337   return info;
   1338 }
   1339 
   1340 
   1341 /**
   1342  * Get the username from Digest Authorization client's header.
   1343  *
   1344  * @param connection The MHD connection structure
   1345  * @return NULL if no valid Digest Authorization header is used in the request,
   1346  *         or no username parameter is present in the header, or username is
   1347  *         provided incorrectly by client (see description for
   1348  *         #MHD_DIGEST_AUTH_UNAME_TYPE_INVALID);
   1349  *         a pointer structure with information if the valid request header
   1350  *         found, free using #MHD_free().
   1351  * @sa MHD_digest_auth_get_request_info3() provides more complete information
   1352  * @note Available since #MHD_VERSION 0x00097701
   1353  * @ingroup authentication
   1354  */
   1355 _MHD_EXTERN struct MHD_DigestAuthUsernameInfo *
   1356 MHD_digest_auth_get_username3 (struct MHD_Connection *connection)
   1357 {
   1358   const struct MHD_RqDAuth *params;
   1359   struct MHD_DigestAuthUsernameInfo *uname_info;
   1360   enum MHD_DigestAuthUsernameType uname_type;
   1361   size_t unif_buf_size;
   1362   uint8_t *unif_buf_ptr;
   1363   size_t unif_buf_used;
   1364 
   1365   params = MHD_get_rq_dauth_params_ (connection);
   1366   if (NULL == params)
   1367     return NULL;
   1368 
   1369   uname_type = get_rq_uname_type (params);
   1370   if ( (MHD_DIGEST_AUTH_UNAME_TYPE_MISSING == uname_type) ||
   1371        (MHD_DIGEST_AUTH_UNAME_TYPE_INVALID == uname_type) )
   1372     return NULL;
   1373 
   1374   unif_buf_size = get_rq_unames_size (params, uname_type);
   1375 
   1376   uname_info = (struct MHD_DigestAuthUsernameInfo *)
   1377                MHD_calloc_ (1, (sizeof(struct MHD_DigestAuthUsernameInfo))
   1378                             + unif_buf_size);
   1379   unif_buf_ptr = (uint8_t *) (uname_info + 1);
   1380   unif_buf_used = get_rq_uname (params, uname_type, uname_info, unif_buf_ptr,
   1381                                 unif_buf_size);
   1382   mhd_assert (unif_buf_size >= unif_buf_used);
   1383   (void) unif_buf_used; /* Mute compiler warning on non-debug builds */
   1384   mhd_assert (MHD_DIGEST_AUTH_UNAME_TYPE_MISSING != uname_info->uname_type);
   1385 
   1386   if (MHD_DIGEST_AUTH_UNAME_TYPE_INVALID == uname_info->uname_type)
   1387   {
   1388     free (uname_info);
   1389     return NULL;
   1390   }
   1391   mhd_assert (uname_type == uname_info->uname_type);
   1392   uname_info->algo3 = params->algo3;
   1393 
   1394   return uname_info;
   1395 }
   1396 
   1397 
   1398 /**
   1399  * Get the username from the authorization header sent by the client
   1400  *
   1401  * This function supports username in standard and extended notations.
   1402  * "userhash" is not supported by this function.
   1403  *
   1404  * @param connection The MHD connection structure
   1405  * @return NULL if no username could be found, username provided as
   1406  *         "userhash", extended notation broken or memory allocation error
   1407  *         occurs;
   1408  *         a pointer to the username if found, free using #MHD_free().
   1409  * @warning Returned value must be freed by #MHD_free().
   1410  * @sa #MHD_digest_auth_get_username3()
   1411  * @ingroup authentication
   1412  */
   1413 _MHD_EXTERN char *
   1414 MHD_digest_auth_get_username (struct MHD_Connection *connection)
   1415 {
   1416   const struct MHD_RqDAuth *params;
   1417   char *username;
   1418   size_t buf_size;
   1419   enum MHD_DigestAuthUsernameType uname_type;
   1420 
   1421   params = MHD_get_rq_dauth_params_ (connection);
   1422   if (NULL == params)
   1423     return NULL;
   1424 
   1425   uname_type = get_rq_uname_type (params);
   1426 
   1427   if ( (MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD != uname_type) &&
   1428        (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED != uname_type) )
   1429     return NULL;
   1430 
   1431   buf_size = get_rq_unames_size (params, uname_type);
   1432 
   1433   mhd_assert (0 != buf_size);
   1434 
   1435   username = (char *) MHD_calloc_ (1, buf_size);
   1436   if (NULL == username)
   1437     return NULL;
   1438 
   1439   if (1)
   1440   {
   1441     struct MHD_DigestAuthUsernameInfo uname_strct;
   1442     size_t used;
   1443 
   1444     memset (&uname_strct, 0, sizeof(uname_strct));
   1445 
   1446     used = get_rq_uname (params, uname_type, &uname_strct,
   1447                          (uint8_t *) username, buf_size);
   1448     if (uname_type != uname_strct.uname_type)
   1449     { /* Broken encoding for extended notation */
   1450       free (username);
   1451       return NULL;
   1452     }
   1453     (void) used; /* Mute compiler warning for non-debug builds */
   1454     mhd_assert (buf_size >= used);
   1455   }
   1456 
   1457   return username;
   1458 }
   1459 
   1460 
   1461 /**
   1462  * Calculate the server nonce so that it mitigates replay attacks
   1463  * The current format of the nonce is ...
   1464  * H(timestamp:random data:various parameters) + Hex(timestamp)
   1465  *
   1466  * @param nonce_time The amount of time in seconds for a nonce to be invalid
   1467  * @param mthd_e HTTP method as enum value
   1468  * @param method HTTP method as a string
   1469  * @param rnd the pointer to a character array for the random seed
   1470  * @param rnd_size The size of the random seed array @a rnd
   1471  * @param saddr the pointer to the socket address structure
   1472  * @param saddr_size the size of the socket address structure @a saddr
   1473  * @param uri the HTTP URI (in MHD, without the arguments ("?k=v")
   1474  * @param uri_len the length of the @a uri
   1475  * @param first_header the pointer to the first request's header
   1476  * @param realm A string of characters that describes the realm of auth.
   1477  * @param realm_len the length of the @a realm.
   1478  * @param bind_options the nonce bind options (#MHD_DAuthBindNonce values).
   1479  * @param da digest algorithm to use
   1480  * @param[out] nonce the pointer to a character array for the nonce to put in,
   1481  *                   must provide NONCE_STD_LEN(digest_get_size(da)) bytes,
   1482  *                   result is NOT zero-terminated
   1483  */
   1484 static void
   1485 calculate_nonce (uint64_t nonce_time,
   1486                  enum MHD_HTTP_Method mthd_e,
   1487                  const char *method,
   1488                  const char *rnd,
   1489                  size_t rnd_size,
   1490                  const struct sockaddr_storage *saddr,
   1491                  size_t saddr_size,
   1492                  const char *uri,
   1493                  size_t uri_len,
   1494                  const struct MHD_HTTP_Req_Header *first_header,
   1495                  const char *realm,
   1496                  size_t realm_len,
   1497                  unsigned int bind_options,
   1498                  struct DigestAlgorithm *da,
   1499                  char *nonce)
   1500 {
   1501   mhd_assert (! da->hashing);
   1502   if (1)
   1503   {
   1504     /* Add the timestamp to the hash calculation */
   1505     uint8_t timestamp[TIMESTAMP_BIN_SIZE];
   1506     /* If the nonce_time is milliseconds, then the same 48 bit value will repeat
   1507      * every 8 919 years, which is more than enough to mitigate a replay attack */
   1508 #if TIMESTAMP_BIN_SIZE != 6
   1509 #error The code needs to be updated here
   1510 #endif
   1511     timestamp[0] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 0)));
   1512     timestamp[1] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 1)));
   1513     timestamp[2] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 2)));
   1514     timestamp[3] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 3)));
   1515     timestamp[4] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 4)));
   1516     timestamp[5] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 5)));
   1517     MHD_bin_to_hex (timestamp,
   1518                     sizeof (timestamp),
   1519                     nonce + digest_get_size (da) * 2);
   1520     digest_update (da,
   1521                    timestamp,
   1522                    sizeof (timestamp));
   1523   }
   1524   if (rnd_size > 0)
   1525   {
   1526     /* Add the unique random value to the hash calculation */
   1527     digest_update_with_colon (da);
   1528     digest_update (da,
   1529                    rnd,
   1530                    rnd_size);
   1531   }
   1532   if ( (MHD_DAUTH_BIND_NONCE_NONE == bind_options) &&
   1533        (0 != saddr_size) )
   1534   {
   1535     /* Add full client address including source port to make unique nonces
   1536      * for requests received exactly at the same time */
   1537     digest_update_with_colon (da);
   1538     digest_update (da,
   1539                    saddr,
   1540                    saddr_size);
   1541   }
   1542   if ( (0 != (bind_options & MHD_DAUTH_BIND_NONCE_CLIENT_IP)) &&
   1543        (0 != saddr_size) )
   1544   {
   1545     /* Add the client's IP address to the hash calculation */
   1546     digest_update_with_colon (da);
   1547     if (AF_INET == saddr->ss_family)
   1548       digest_update (da,
   1549                      &((const struct sockaddr_in *) saddr)->sin_addr,
   1550                      sizeof(((const struct sockaddr_in *) saddr)->sin_addr));
   1551 #ifdef HAVE_INET6
   1552     else if (AF_INET6 == saddr->ss_family)
   1553       digest_update (da,
   1554                      &((const struct sockaddr_in6 *) saddr)->sin6_addr,
   1555                      sizeof(((const struct sockaddr_in6 *) saddr)->sin6_addr));
   1556 #endif /* HAVE_INET6 */
   1557   }
   1558   if ( (MHD_DAUTH_BIND_NONCE_NONE == bind_options) ||
   1559        (0 != (bind_options & MHD_DAUTH_BIND_NONCE_URI)))
   1560   {
   1561     /* Add the request method to the hash calculation */
   1562     digest_update_with_colon (da);
   1563     if (MHD_HTTP_MTHD_OTHER != mthd_e)
   1564     {
   1565       uint8_t mthd_for_hash;
   1566       if (MHD_HTTP_MTHD_HEAD != mthd_e)
   1567         mthd_for_hash = (uint8_t) mthd_e;
   1568       else /* Treat HEAD method in the same way as GET method */
   1569         mthd_for_hash = (uint8_t) MHD_HTTP_MTHD_GET;
   1570       digest_update (da,
   1571                      &mthd_for_hash,
   1572                      sizeof(mthd_for_hash));
   1573     }
   1574     else
   1575       digest_update_str (da, method);
   1576   }
   1577 
   1578   if (0 != (bind_options & MHD_DAUTH_BIND_NONCE_URI))
   1579   {
   1580     /* Add the request URI to the hash calculation */
   1581     digest_update_with_colon (da);
   1582 
   1583     digest_update (da,
   1584                    uri,
   1585                    uri_len);
   1586   }
   1587   if (0 != (bind_options & MHD_DAUTH_BIND_NONCE_URI_PARAMS))
   1588   {
   1589     /* Add the request URI parameters to the hash calculation */
   1590     const struct MHD_HTTP_Req_Header *h;
   1591 
   1592     digest_update_with_colon (da);
   1593     for (h = first_header; NULL != h; h = h->next)
   1594     {
   1595       if (MHD_GET_ARGUMENT_KIND != h->kind)
   1596         continue;
   1597       digest_update (da, "\0", 2);
   1598       if (0 != h->header_size)
   1599         digest_update (da, h->header, h->header_size);
   1600       digest_update (da, "", 1);
   1601       if (0 != h->value_size)
   1602         digest_update (da, h->value, h->value_size);
   1603     }
   1604   }
   1605   if ( (MHD_DAUTH_BIND_NONCE_NONE == bind_options) ||
   1606        (0 != (bind_options & MHD_DAUTH_BIND_NONCE_REALM)))
   1607   {
   1608     /* Add the realm to the hash calculation */
   1609     digest_update_with_colon (da);
   1610     digest_update (da,
   1611                    realm,
   1612                    realm_len);
   1613   }
   1614   if (1)
   1615   {
   1616     uint8_t hash[MAX_DIGEST];
   1617     digest_calc_hash (da, hash);
   1618     MHD_bin_to_hex (hash,
   1619                     digest_get_size (da),
   1620                     nonce);
   1621   }
   1622 }
   1623 
   1624 
   1625 /**
   1626  * Check whether it is possible to use slot in nonce-nc map array.
   1627  *
   1628  * Should be called with mutex held to avoid external modification of
   1629  * the slot data.
   1630  *
   1631  * @param nn the pointer to the nonce-nc slot
   1632  * @param now the current time
   1633  * @param new_nonce the new nonce supposed to be stored in this slot,
   1634  *                  zero-terminated
   1635  * @param new_nonce_len the length of the @a new_nonce in chars, not including
   1636  *                      the terminating zero.
   1637  * @return true if the slot can be used to store the new nonce,
   1638  *         false otherwise.
   1639  */
   1640 static bool
   1641 is_slot_available (const struct MHD_NonceNc *const nn,
   1642                    const uint64_t now,
   1643                    const char *const new_nonce,
   1644                    size_t new_nonce_len)
   1645 {
   1646   uint64_t timestamp;
   1647   bool timestamp_valid;
   1648   mhd_assert (new_nonce_len <= NONCE_STD_LEN (MAX_DIGEST));
   1649   mhd_assert (NONCE_STD_LEN (MAX_DIGEST) <= MAX_DIGEST_NONCE_LENGTH);
   1650   if (0 == nn->nonce[0])
   1651     return true; /* The slot is empty */
   1652 
   1653   if (0 == memcmp (nn->nonce, new_nonce, new_nonce_len))
   1654   {
   1655     /* The slot has the same nonce already. This nonce cannot be registered
   1656      * again as it would just clear 'nc' usage history. */
   1657     return false;
   1658   }
   1659 
   1660   if (0 != nn->nc)
   1661     return true; /* Client already used the nonce in this slot at least
   1662                     one time, re-use the slot */
   1663 
   1664   /* The nonce must be zero-terminated */
   1665   mhd_assert (0 == nn->nonce[sizeof(nn->nonce) - 1]);
   1666   if (0 != nn->nonce[sizeof(nn->nonce) - 1])
   1667     return true; /* Wrong nonce format in the slot */
   1668 
   1669   timestamp_valid = get_nonce_timestamp (nn->nonce, 0, &timestamp);
   1670   mhd_assert (timestamp_valid);
   1671   if (! timestamp_valid)
   1672     return true; /* Invalid timestamp in nonce-nc, should not be possible */
   1673 
   1674   if ((REUSE_TIMEOUT * 1000) < TRIM_TO_TIMESTAMP (now - timestamp))
   1675     return true;
   1676 
   1677   return false;
   1678 }
   1679 
   1680 
   1681 /**
   1682  * Calculate the server nonce so that it mitigates replay attacks and add
   1683  * the new nonce to the nonce-nc map array.
   1684  *
   1685  * @param connection the MHD connection structure
   1686  * @param timestamp the current timestamp
   1687  * @param realm the string of characters that describes the realm of auth
   1688  * @param realm_len the length of the @a realm
   1689  * @param da the digest algorithm to use
   1690  * @param[out] nonce the pointer to a character array for the nonce to put in,
   1691  *                   must provide NONCE_STD_LEN(digest_get_size(da)) bytes,
   1692  *                   result is NOT zero-terminated
   1693  * @return true if the new nonce has been added to the nonce-nc map array,
   1694  *         false otherwise.
   1695  */
   1696 static bool
   1697 calculate_add_nonce (struct MHD_Connection *const connection,
   1698                      uint64_t timestamp,
   1699                      const char *realm,
   1700                      size_t realm_len,
   1701                      struct DigestAlgorithm *da,
   1702                      char *nonce)
   1703 {
   1704   struct MHD_Daemon *const daemon = MHD_get_master (connection->daemon);
   1705   struct MHD_NonceNc *nn;
   1706   const size_t nonce_size = NONCE_STD_LEN (digest_get_size (da));
   1707   bool ret;
   1708 
   1709   mhd_assert (! da->hashing);
   1710   mhd_assert (MAX_DIGEST_NONCE_LENGTH >= nonce_size);
   1711   mhd_assert (0 != nonce_size);
   1712 
   1713   calculate_nonce (timestamp,
   1714                    connection->rq.http_mthd,
   1715                    connection->rq.method,
   1716                    daemon->digest_auth_random,
   1717                    daemon->digest_auth_rand_size,
   1718                    connection->addr,
   1719                    (size_t) connection->addr_len,
   1720                    connection->rq.url,
   1721                    connection->rq.url_len,
   1722                    connection->rq.headers_received,
   1723                    realm,
   1724                    realm_len,
   1725                    daemon->dauth_bind_type,
   1726                    da,
   1727                    nonce);
   1728 
   1729 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   1730   if (digest_ext_error (da))
   1731     return false;
   1732 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   1733 
   1734   if (0 == daemon->nonce_nc_size)
   1735     return false;
   1736 
   1737   /* Sanity check for values */
   1738   mhd_assert (MAX_DIGEST_NONCE_LENGTH == NONCE_STD_LEN (MAX_DIGEST));
   1739 
   1740   nn = daemon->nnc + get_nonce_nc_idx (daemon->nonce_nc_size,
   1741                                        nonce,
   1742                                        nonce_size);
   1743 
   1744   MHD_mutex_lock_chk_ (&daemon->nnc_lock);
   1745   if (is_slot_available (nn, timestamp, nonce, nonce_size))
   1746   {
   1747     memcpy (nn->nonce,
   1748             nonce,
   1749             nonce_size);
   1750     nn->nonce[nonce_size] = 0;  /* With terminating zero */
   1751     nn->nc = 0;
   1752     nn->nmask = 0;
   1753     ret = true;
   1754   }
   1755   else
   1756     ret = false;
   1757   MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
   1758 
   1759   return ret;
   1760 }
   1761 
   1762 
   1763 MHD_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE_
   1764 
   1765 /**
   1766  * Calculate the server nonce so that it mitigates replay attacks and add
   1767  * the new nonce to the nonce-nc map array.
   1768  *
   1769  * @param connection the MHD connection structure
   1770  * @param realm A string of characters that describes the realm of auth.
   1771  * @param da digest algorithm to use
   1772  * @param[out] nonce the pointer to a character array for the nonce to put in,
   1773  *                   must provide NONCE_STD_LEN(digest_get_size(da)) bytes,
   1774  *                   result is NOT zero-terminated
   1775  */
   1776 static bool
   1777 calculate_add_nonce_with_retry (struct MHD_Connection *const connection,
   1778                                 const char *realm,
   1779                                 struct DigestAlgorithm *da,
   1780                                 char *nonce)
   1781 {
   1782   const uint64_t timestamp1 = MHD_monotonic_msec_counter ();
   1783   const size_t realm_len = strlen (realm);
   1784   mhd_assert (! da->hashing);
   1785 
   1786 #ifdef HAVE_MESSAGES
   1787   if (0 == MHD_get_master (connection->daemon)->digest_auth_rand_size)
   1788     MHD_DLOG (connection->daemon,
   1789               _ ("Random value was not initialised by " \
   1790                  "MHD_OPTION_DIGEST_AUTH_RANDOM or " \
   1791                  "MHD_OPTION_DIGEST_AUTH_RANDOM_COPY, generated nonces " \
   1792                  "are predictable.\n"));
   1793 #endif
   1794 
   1795   if (! calculate_add_nonce (connection, timestamp1, realm, realm_len, da,
   1796                              nonce))
   1797   {
   1798     /* Either:
   1799      * 1. The same nonce was already generated. If it will be used then one
   1800      * of the clients will fail (as no initial 'nc' value could be given to
   1801      * the client, the second client which will use 'nc=00000001' will fail).
   1802      * 2. Another nonce uses the same slot, and this nonce never has been
   1803      * used by the client and this nonce is still fresh enough.
   1804      */
   1805     const size_t digest_size = digest_get_size (da);
   1806     char nonce2[NONCE_STD_LEN (MAX_DIGEST) + 1];
   1807     uint64_t timestamp2;
   1808 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   1809     if (digest_ext_error (da))
   1810       return false; /* No need to re-try */
   1811 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   1812     if (0 == MHD_get_master (connection->daemon)->nonce_nc_size)
   1813       return false; /* No need to re-try */
   1814 
   1815     timestamp2 = MHD_monotonic_msec_counter ();
   1816     if (timestamp1 == timestamp2)
   1817     {
   1818       /* The timestamps are equal, need to generate some arbitrary
   1819        * difference for nonce. */
   1820       /* As the number is needed only to differentiate clients, weak
   1821        * pseudo-random generators could be used. Seeding is not needed. */
   1822       uint64_t base1;
   1823       uint32_t base2;
   1824       uint16_t base3;
   1825       uint8_t base4;
   1826 #ifdef HAVE_RANDOM
   1827       base1 = ((uint64_t) random ()) ^ UINT64_C (0x54a5acff5be47e63);
   1828       base4 = 0xb8;
   1829 #elif defined(HAVE_RAND)
   1830       base1 = ((uint64_t) rand ()) ^ UINT64_C (0xc4bcf553b12f3965);
   1831       base4 = 0x92;
   1832 #else
   1833       /* Monotonic msec counter alone does not really help here as it is already
   1834          known that this value is not unique. */
   1835       base1 = ((uint64_t) (uintptr_t) nonce2) ^ UINT64_C (0xf2e1b21bc6c92655);
   1836       base2 = ((uint32_t) (base1 >> 32)) ^ ((uint32_t) base1);
   1837       base2 = _MHD_ROTR32 (base2, 4);
   1838       base3 = ((uint16_t) (base2 >> 16)) ^ ((uint16_t) base2);
   1839       base4 = ((uint8_t) (base3 >> 8)) ^ ((uint8_t) base3);
   1840       base1 = ((uint64_t) MHD_monotonic_msec_counter ())
   1841               ^ UINT64_C (0xccab93f72cf5b15);
   1842 #endif
   1843       base2 = ((uint32_t) (base1 >> 32)) ^ ((uint32_t) base1);
   1844       base2 = _MHD_ROTL32 (base2, (((base4 >> 4) ^ base4) % 32));
   1845       base3 = ((uint16_t) (base2 >> 16)) ^ ((uint16_t) base2);
   1846       base4 = ((uint8_t) (base3 >> 8)) ^ ((uint8_t) base3);
   1847       /* Use up to 127 ms difference */
   1848       timestamp2 -= (base4 & DAUTH_JUMPBACK_MAX);
   1849       if (timestamp1 == timestamp2)
   1850         timestamp2 -= 2; /* Fallback value */
   1851     }
   1852     digest_reset (da);
   1853     if (! calculate_add_nonce (connection, timestamp2, realm, realm_len, da,
   1854                                nonce2))
   1855     {
   1856       /* No free slot has been found. Re-tries are expensive, just use
   1857        * the generated nonce. As it is not stored in nonce-nc map array,
   1858        * the next request of the client will be recognized as valid, but 'stale'
   1859        * so client should re-try automatically. */
   1860       return false;
   1861     }
   1862     memcpy (nonce, nonce2, NONCE_STD_LEN (digest_size));
   1863   }
   1864   return true;
   1865 }
   1866 
   1867 
   1868 MHD_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE_
   1869 
   1870 /**
   1871  * Calculate userdigest, return it as binary data.
   1872  *
   1873  * It is equal to H(A1) for non-session algorithms.
   1874  *
   1875  * MHD internal version.
   1876  *
   1877  * @param da the digest algorithm
   1878  * @param username the username to use
   1879  * @param username_len the length of the @a username
   1880  * @param realm the realm to use
   1881  * @param realm_len the length of the @a realm
   1882  * @param password the password, must be zero-terminated
   1883  * @param[out] ha1_bin the output buffer, must have at least
   1884  *                     #digest_get_size(da) bytes available
   1885  */
   1886 _MHD_static_inline void
   1887 calc_userdigest (struct DigestAlgorithm *da,
   1888                  const char *username, const size_t username_len,
   1889                  const char *realm, const size_t realm_len,
   1890                  const char *password,
   1891                  uint8_t *ha1_bin)
   1892 {
   1893   mhd_assert (! da->hashing);
   1894   digest_update (da, username, username_len);
   1895   digest_update_with_colon (da);
   1896   digest_update (da, realm, realm_len);
   1897   digest_update_with_colon (da);
   1898   digest_update_str (da, password);
   1899   digest_calc_hash (da, ha1_bin);
   1900 }
   1901 
   1902 
   1903 /**
   1904  * Calculate userdigest, return it as a binary data.
   1905  *
   1906  * The "userdigest" is the hash of the "username:realm:password" string.
   1907  *
   1908  * The "userdigest" can be used to avoid storing the password in clear text
   1909  * in database/files
   1910  *
   1911  * This function is designed to improve security of stored credentials,
   1912  * the "userdigest" does not improve security of the authentication process.
   1913  *
   1914  * The results can be used to store username & userdigest pairs instead of
   1915  * username & password pairs. To further improve security, application may
   1916  * store username & userhash & userdigest triplets.
   1917  *
   1918  * @param algo3 the digest algorithm
   1919  * @param username the username
   1920  * @param realm the realm
   1921  * @param password the password
   1922  * @param[out] userdigest_bin the output buffer for userdigest;
   1923  *                            if this function succeeds, then this buffer has
   1924  *                            #MHD_digest_get_hash_size(algo3) bytes of
   1925  *                            userdigest upon return
   1926  * @param bin_buf_size the size of the @a userdigest_bin buffer, must be
   1927  *                     at least #MHD_digest_get_hash_size(algo3) bytes long
   1928  * @return MHD_YES on success,
   1929  *         MHD_NO if @a userdigest_bin is too small or if @a algo3 algorithm is
   1930  *         not supported (or external error has occurred,
   1931  *         see #MHD_FEATURE_EXTERN_HASH).
   1932  * @sa #MHD_digest_auth_check_digest3()
   1933  * @note Available since #MHD_VERSION 0x00097701
   1934  * @ingroup authentication
   1935  */
   1936 _MHD_EXTERN enum MHD_Result
   1937 MHD_digest_auth_calc_userdigest (enum MHD_DigestAuthAlgo3 algo3,
   1938                                  const char *username,
   1939                                  const char *realm,
   1940                                  const char *password,
   1941                                  void *userdigest_bin,
   1942                                  size_t bin_buf_size)
   1943 {
   1944   struct DigestAlgorithm da;
   1945   enum MHD_Result ret;
   1946   if (! digest_init_one_time (&da, get_base_digest_algo (algo3)))
   1947     return MHD_NO;
   1948 
   1949   if (digest_get_size (&da) > bin_buf_size)
   1950     ret = MHD_NO;
   1951   else
   1952   {
   1953     calc_userdigest (&da,
   1954                      username,
   1955                      strlen (username),
   1956                      realm,
   1957                      strlen (realm),
   1958                      password,
   1959                      userdigest_bin);
   1960     ret = MHD_YES;
   1961 
   1962 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   1963     if (digest_ext_error (&da))
   1964       ret = MHD_NO;
   1965 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   1966   }
   1967   digest_deinit (&da);
   1968 
   1969   return ret;
   1970 }
   1971 
   1972 
   1973 /**
   1974  * Calculate userhash, return it as binary data.
   1975  *
   1976  * MHD internal version.
   1977  *
   1978  * @param da the digest algorithm
   1979  * @param username the username to use
   1980  * @param username_len the length of the @a username
   1981  * @param realm the realm to use
   1982  * @param realm_len the length of the @a realm
   1983  * @param[out] digest_bin the output buffer, must have at least
   1984  *                        #MHD_digest_get_hash_size(algo3) bytes available
   1985  */
   1986 _MHD_static_inline void
   1987 calc_userhash (struct DigestAlgorithm *da,
   1988                const char *username, const size_t username_len,
   1989                const char *realm, const size_t realm_len,
   1990                uint8_t *digest_bin)
   1991 {
   1992   mhd_assert (NULL != username);
   1993   mhd_assert (! da->hashing);
   1994   digest_update (da, username, username_len);
   1995   digest_update_with_colon (da);
   1996   digest_update (da, realm, realm_len);
   1997   digest_calc_hash (da, digest_bin);
   1998 }
   1999 
   2000 
   2001 /**
   2002  * Calculate "userhash", return it as binary data.
   2003  *
   2004  * The "userhash" is the hash of the string "username:realm".
   2005  *
   2006  * The "userhash" could be used to avoid sending username in cleartext in Digest
   2007  * Authorization client's header.
   2008  *
   2009  * Userhash is not designed to hide the username in local database or files,
   2010  * as username in cleartext is required for #MHD_digest_auth_check3() function
   2011  * to check the response, but it can be used to hide username in HTTP headers.
   2012  *
   2013  * This function could be used when the new username is added to the username
   2014  * database to save the "userhash" alongside with the username (preferably) or
   2015  * when loading list of the usernames to generate the userhash for every loaded
   2016  * username (this will cause delays at the start with the long lists).
   2017  *
   2018  * Once "userhash" is generated it could be used to identify users by clients
   2019  * with "userhash" support.
   2020  * Avoid repetitive usage of this function for the same username/realm
   2021  * combination as it will cause excessive CPU load; save and re-use the result
   2022  * instead.
   2023  *
   2024  * @param algo3 the algorithm for userhash calculations
   2025  * @param username the username
   2026  * @param realm the realm
   2027  * @param[out] userhash_bin the output buffer for userhash as binary data;
   2028  *                          if this function succeeds, then this buffer has
   2029  *                          #MHD_digest_get_hash_size(algo3) bytes of userhash
   2030  *                          upon return
   2031  * @param bin_buf_size the size of the @a userhash_bin buffer, must be
   2032  *                     at least #MHD_digest_get_hash_size(algo3) bytes long
   2033  * @return MHD_YES on success,
   2034  *         MHD_NO if @a bin_buf_size is too small or if @a algo3 algorithm is
   2035  *         not supported (or external error has occurred,
   2036  *         see #MHD_FEATURE_EXTERN_HASH)
   2037  * @sa #MHD_digest_auth_calc_userhash_hex()
   2038  * @note Available since #MHD_VERSION 0x00097701
   2039  * @ingroup authentication
   2040  */
   2041 _MHD_EXTERN enum MHD_Result
   2042 MHD_digest_auth_calc_userhash (enum MHD_DigestAuthAlgo3 algo3,
   2043                                const char *username,
   2044                                const char *realm,
   2045                                void *userhash_bin,
   2046                                size_t bin_buf_size)
   2047 {
   2048   struct DigestAlgorithm da;
   2049   enum MHD_Result ret;
   2050 
   2051   if (! digest_init_one_time (&da, get_base_digest_algo (algo3)))
   2052     return MHD_NO;
   2053   if (digest_get_size (&da) > bin_buf_size)
   2054     ret = MHD_NO;
   2055   else
   2056   {
   2057     calc_userhash (&da,
   2058                    username,
   2059                    strlen (username),
   2060                    realm,
   2061                    strlen (realm),
   2062                    userhash_bin);
   2063     ret = MHD_YES;
   2064 
   2065 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   2066     if (digest_ext_error (&da))
   2067       ret = MHD_NO;
   2068 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   2069   }
   2070   digest_deinit (&da);
   2071 
   2072   return ret;
   2073 }
   2074 
   2075 
   2076 /**
   2077  * Calculate "userhash", return it as hexadecimal string.
   2078  *
   2079  * The "userhash" is the hash of the string "username:realm".
   2080  *
   2081  * The "userhash" could be used to avoid sending username in cleartext in Digest
   2082  * Authorization client's header.
   2083  *
   2084  * Userhash is not designed to hide the username in local database or files,
   2085  * as username in cleartext is required for #MHD_digest_auth_check3() function
   2086  * to check the response, but it can be used to hide username in HTTP headers.
   2087  *
   2088  * This function could be used when the new username is added to the username
   2089  * database to save the "userhash" alongside with the username (preferably) or
   2090  * when loading list of the usernames to generate the userhash for every loaded
   2091  * username (this will cause delays at the start with the long lists).
   2092  *
   2093  * Once "userhash" is generated it could be used to identify users by clients
   2094  * with "userhash" support.
   2095  * Avoid repetitive usage of this function for the same username/realm
   2096  * combination as it will cause excessive CPU load; save and re-use the result
   2097  * instead.
   2098  *
   2099  * @param algo3 the algorithm for userhash calculations
   2100  * @param username the username
   2101  * @param realm the realm
   2102  * @param[out] userhash_hex the output buffer for userhash as hex string;
   2103  *                          if this function succeeds, then this buffer has
   2104  *                          #MHD_digest_get_hash_size(algo3)*2 chars long
   2105  *                          userhash zero-terminated string
   2106  * @param bin_buf_size the size of the @a userhash_bin buffer, must be
   2107  *                     at least #MHD_digest_get_hash_size(algo3)*2+1 chars long
   2108  * @return MHD_YES on success,
   2109  *         MHD_NO if @a bin_buf_size is too small or if @a algo3 algorithm is
   2110  *         not supported (or external error has occurred,
   2111  *         see #MHD_FEATURE_EXTERN_HASH).
   2112  * @sa #MHD_digest_auth_calc_userhash()
   2113  * @note Available since #MHD_VERSION 0x00097701
   2114  * @ingroup authentication
   2115  */
   2116 _MHD_EXTERN enum MHD_Result
   2117 MHD_digest_auth_calc_userhash_hex (enum MHD_DigestAuthAlgo3 algo3,
   2118                                    const char *username,
   2119                                    const char *realm,
   2120                                    char *userhash_hex,
   2121                                    size_t hex_buf_size)
   2122 {
   2123   uint8_t userhash_bin[MAX_DIGEST];
   2124   size_t digest_size;
   2125 
   2126   digest_size = digest_get_hash_size (algo3);
   2127   if (digest_size * 2 + 1 > hex_buf_size)
   2128     return MHD_NO;
   2129   if (MHD_NO == MHD_digest_auth_calc_userhash (algo3, username, realm,
   2130                                                userhash_bin, MAX_DIGEST))
   2131     return MHD_NO;
   2132 
   2133   MHD_bin_to_hex_z (userhash_bin, digest_size, userhash_hex);
   2134   return MHD_YES;
   2135 }
   2136 
   2137 
   2138 struct test_header_param
   2139 {
   2140   struct MHD_Connection *connection;
   2141   size_t num_headers;
   2142 };
   2143 
   2144 /**
   2145  * Test if the given key-value pair is in the headers for the
   2146  * given connection.
   2147  *
   2148  * @param cls the test context
   2149  * @param key the key
   2150  * @param key_size number of bytes in @a key
   2151  * @param value the value, can be NULL
   2152  * @param value_size number of bytes in @a value
   2153  * @param kind type of the header
   2154  * @return #MHD_YES if the key-value pair is in the headers,
   2155  *         #MHD_NO if not
   2156  */
   2157 static enum MHD_Result
   2158 test_header (void *cls,
   2159              const char *key,
   2160              size_t key_size,
   2161              const char *value,
   2162              size_t value_size,
   2163              enum MHD_ValueKind kind)
   2164 {
   2165   struct test_header_param *const param = (struct test_header_param *) cls;
   2166   struct MHD_Connection *connection = param->connection;
   2167   struct MHD_HTTP_Req_Header *pos;
   2168   size_t i;
   2169 
   2170   param->num_headers++;
   2171   i = 0;
   2172   for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
   2173   {
   2174     if (kind != pos->kind)
   2175       continue;
   2176     if (++i == param->num_headers)
   2177     {
   2178       if (key_size != pos->header_size)
   2179         return MHD_NO;
   2180       if (value_size != pos->value_size)
   2181         return MHD_NO;
   2182       if (0 != key_size)
   2183       {
   2184         mhd_assert (NULL != key);
   2185         mhd_assert (NULL != pos->header);
   2186         if (0 != memcmp (key,
   2187                          pos->header,
   2188                          key_size))
   2189           return MHD_NO;
   2190       }
   2191       if (0 != value_size)
   2192       {
   2193         mhd_assert (NULL != value);
   2194         mhd_assert (NULL != pos->value);
   2195         if (0 != memcmp (value,
   2196                          pos->value,
   2197                          value_size))
   2198           return MHD_NO;
   2199       }
   2200       return MHD_YES;
   2201     }
   2202   }
   2203   return MHD_NO;
   2204 }
   2205 
   2206 
   2207 /**
   2208  * Check that the arguments given by the client as part
   2209  * of the authentication header match the arguments we
   2210  * got as part of the HTTP request URI.
   2211  *
   2212  * @param connection connections with headers to compare against
   2213  * @param args the copy of argument URI string (after "?" in URI), will be
   2214  *             modified by this function
   2215  * @return boolean true if the arguments match,
   2216  *         boolean false if not
   2217  */
   2218 static bool
   2219 check_argument_match (struct MHD_Connection *connection,
   2220                       char *args)
   2221 {
   2222   struct MHD_HTTP_Req_Header *pos;
   2223   enum MHD_Result ret;
   2224   struct test_header_param param;
   2225 
   2226   param.connection = connection;
   2227   param.num_headers = 0;
   2228   ret = MHD_parse_arguments_ (connection,
   2229                               MHD_GET_ARGUMENT_KIND,
   2230                               args,
   2231                               &test_header,
   2232                               &param);
   2233   if (MHD_NO == ret)
   2234   {
   2235     return false;
   2236   }
   2237   /* also check that the number of headers matches */
   2238   for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
   2239   {
   2240     if (MHD_GET_ARGUMENT_KIND != pos->kind)
   2241       continue;
   2242     param.num_headers--;
   2243   }
   2244   if (0 != param.num_headers)
   2245   {
   2246     /* argument count mismatch */
   2247     return false;
   2248   }
   2249   return true;
   2250 }
   2251 
   2252 
   2253 /**
   2254  * Check that the URI provided by the client as part
   2255  * of the authentication header match the real HTTP request URI.
   2256  *
   2257  * @param connection connections with headers to compare against
   2258  * @param uri the copy of URI in the authentication header, should point to
   2259  *            modifiable buffer at least @a uri_len + 1 characters long,
   2260  *            will be modified by this function, not valid upon return
   2261  * @param uri_len the length of the @a uri string in characters
   2262  * @return boolean true if the URIs match,
   2263  *         boolean false if not
   2264  */
   2265 static bool
   2266 check_uri_match (struct MHD_Connection *connection, char *uri, size_t uri_len)
   2267 {
   2268   char *qmark;
   2269   char *args;
   2270   struct MHD_Daemon *const daemon = connection->daemon;
   2271 
   2272   uri[uri_len] = 0;
   2273   qmark = memchr (uri,
   2274                   '?',
   2275                   uri_len);
   2276   if (NULL != qmark)
   2277     *qmark = '\0';
   2278 
   2279   /* Need to unescape URI before comparing with connection->url */
   2280   uri_len = daemon->unescape_callback (daemon->unescape_callback_cls,
   2281                                        connection,
   2282                                        uri);
   2283   if ((uri_len != connection->rq.url_len) ||
   2284       (0 != memcmp (uri, connection->rq.url, uri_len)))
   2285   {
   2286 #ifdef HAVE_MESSAGES
   2287     MHD_DLOG (daemon,
   2288               _ ("Authentication failed, URI does not match.\n"));
   2289 #endif
   2290     return false;
   2291   }
   2292 
   2293   args = (NULL != qmark) ? (qmark + 1) : uri + uri_len;
   2294 
   2295   if (! check_argument_match (connection,
   2296                               args) )
   2297   {
   2298 #ifdef HAVE_MESSAGES
   2299     MHD_DLOG (daemon,
   2300               _ ("Authentication failed, arguments do not match.\n"));
   2301 #endif
   2302     return false;
   2303   }
   2304   return true;
   2305 }
   2306 
   2307 
   2308 /**
   2309  * The size of the unquoting buffer in stack
   2310  */
   2311 #define _MHD_STATIC_UNQ_BUFFER_SIZE 128
   2312 
   2313 
   2314 /**
   2315  * Get the pointer to buffer with required size
   2316  * @param tmp1 the first buffer with fixed size
   2317  * @param ptmp2 the pointer to pointer to malloc'ed buffer
   2318  * @param ptmp2_size the pointer to the size of the buffer pointed by @a ptmp2
   2319  * @param required_size the required size in buffer
   2320  * @return the pointer to the buffer or NULL if failed to allocate buffer with
   2321  *         requested size
   2322  */
   2323 static char *
   2324 get_buffer_for_size (char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
   2325                      char **ptmp2,
   2326                      size_t *ptmp2_size,
   2327                      size_t required_size)
   2328 {
   2329   mhd_assert ((0 == *ptmp2_size) || (NULL != *ptmp2));
   2330   mhd_assert ((NULL != *ptmp2) || (0 == *ptmp2_size));
   2331   mhd_assert ((0 == *ptmp2_size) || \
   2332               (_MHD_STATIC_UNQ_BUFFER_SIZE < *ptmp2_size));
   2333 
   2334   if (required_size <= _MHD_STATIC_UNQ_BUFFER_SIZE)
   2335     return tmp1;
   2336 
   2337   if (required_size <= *ptmp2_size)
   2338     return *ptmp2;
   2339 
   2340   if (required_size > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE)
   2341     return NULL;
   2342   if (NULL != *ptmp2)
   2343     free (*ptmp2);
   2344   *ptmp2 = (char *) malloc (required_size);
   2345   if (NULL == *ptmp2)
   2346     *ptmp2_size = 0;
   2347   else
   2348     *ptmp2_size = required_size;
   2349   return *ptmp2;
   2350 }
   2351 
   2352 
   2353 /**
   2354   * The result of parameter unquoting
   2355   */
   2356 enum _MHD_GetUnqResult
   2357 {
   2358   _MHD_UNQ_OK = 0,         /**< Got unquoted string */
   2359   _MHD_UNQ_TOO_LARGE = -7, /**< The string is too large to unquote */
   2360   _MHD_UNQ_OUT_OF_MEM = 3  /**< Out of memory error */
   2361 };
   2362 
   2363 /**
   2364  * Get Digest authorisation parameter as unquoted string.
   2365  * @param param the parameter to process
   2366  * @param tmp1 the small buffer in stack
   2367  * @param ptmp2 the pointer to pointer to malloc'ed buffer
   2368  * @param ptmp2_size the pointer to the size of the buffer pointed by @a ptmp2
   2369  * @param[out] unquoted the pointer to store the result, NOT zero terminated
   2370  * @return enum code indicating result of the process
   2371  */
   2372 static enum _MHD_GetUnqResult
   2373 get_unquoted_param (const struct MHD_RqDAuthParam *param,
   2374                     char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
   2375                     char **ptmp2,
   2376                     size_t *ptmp2_size,
   2377                     struct _MHD_str_w_len *unquoted)
   2378 {
   2379   char *str;
   2380   size_t len;
   2381   mhd_assert (NULL != param->value.str);
   2382   mhd_assert (0 != param->value.len);
   2383 
   2384   if (! param->quoted)
   2385   {
   2386     unquoted->str = param->value.str;
   2387     unquoted->len = param->value.len;
   2388     return _MHD_UNQ_OK;
   2389   }
   2390   /* The value is present and is quoted, needs to be copied and unquoted */
   2391   str = get_buffer_for_size (tmp1, ptmp2, ptmp2_size, param->value.len);
   2392   if (NULL == str)
   2393     return (param->value.len > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE) ?
   2394            _MHD_UNQ_TOO_LARGE : _MHD_UNQ_OUT_OF_MEM;
   2395 
   2396   len = MHD_str_unquote (param->value.str, param->value.len, str);
   2397   unquoted->str = str;
   2398   unquoted->len = len;
   2399   mhd_assert (0 != unquoted->len);
   2400   mhd_assert (unquoted->len < param->value.len);
   2401   return _MHD_UNQ_OK;
   2402 }
   2403 
   2404 
   2405 /**
   2406  * Get copy of Digest authorisation parameter as unquoted string.
   2407  * @param param the parameter to process
   2408  * @param tmp1 the small buffer in stack
   2409  * @param ptmp2 the pointer to pointer to malloc'ed buffer
   2410  * @param ptmp2_size the pointer to the size of the buffer pointed by @a ptmp2
   2411  * @param[out] unquoted the pointer to store the result, NOT zero terminated,
   2412  *                      but with enough space to zero-terminate
   2413  * @return enum code indicating result of the process
   2414  */
   2415 static enum _MHD_GetUnqResult
   2416 get_unquoted_param_copy (const struct MHD_RqDAuthParam *param,
   2417                          char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
   2418                          char **ptmp2,
   2419                          size_t *ptmp2_size,
   2420                          struct _MHD_mstr_w_len *unquoted)
   2421 {
   2422   mhd_assert (NULL != param->value.str);
   2423   mhd_assert (0 != param->value.len);
   2424 
   2425   /* The value is present and is quoted, needs to be copied and unquoted */
   2426   /* Allocate buffer with one more additional byte for zero-termination */
   2427   unquoted->str =
   2428     get_buffer_for_size (tmp1, ptmp2, ptmp2_size, param->value.len + 1);
   2429 
   2430   if (NULL == unquoted->str)
   2431     return (param->value.len + 1 > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE) ?
   2432            _MHD_UNQ_TOO_LARGE : _MHD_UNQ_OUT_OF_MEM;
   2433 
   2434   if (! param->quoted)
   2435   {
   2436     memcpy (unquoted->str, param->value.str, param->value.len);
   2437     unquoted->len = param->value.len;
   2438     return _MHD_UNQ_OK;
   2439   }
   2440 
   2441   unquoted->len =
   2442     MHD_str_unquote (param->value.str, param->value.len, unquoted->str);
   2443   mhd_assert (0 != unquoted->len);
   2444   mhd_assert (unquoted->len < param->value.len);
   2445   return _MHD_UNQ_OK;
   2446 }
   2447 
   2448 
   2449 /**
   2450  * Check whether Digest Auth request parameter is equal to given string
   2451  * @param param the parameter to check
   2452  * @param str the string to compare with, does not need to be zero-terminated
   2453  * @param str_len the length of the @a str
   2454  * @return true is parameter is equal to the given string,
   2455  *         false otherwise
   2456  */
   2457 _MHD_static_inline bool
   2458 is_param_equal (const struct MHD_RqDAuthParam *param,
   2459                 const char *const str,
   2460                 const size_t str_len)
   2461 {
   2462   mhd_assert (NULL != param->value.str);
   2463   mhd_assert (0 != param->value.len);
   2464   if (param->quoted)
   2465     return MHD_str_equal_quoted_bin_n (param->value.str, param->value.len,
   2466                                        str, str_len);
   2467   return (str_len == param->value.len) &&
   2468          (0 == memcmp (str, param->value.str, str_len));
   2469 
   2470 }
   2471 
   2472 
   2473 /**
   2474  * Check whether Digest Auth request parameter is caseless equal to given string
   2475  * @param param the parameter to check
   2476  * @param str the string to compare with, does not need to be zero-terminated
   2477  * @param str_len the length of the @a str
   2478  * @return true is parameter is caseless equal to the given string,
   2479  *         false otherwise
   2480  */
   2481 _MHD_static_inline bool
   2482 is_param_equal_caseless (const struct MHD_RqDAuthParam *param,
   2483                          const char *const str,
   2484                          const size_t str_len)
   2485 {
   2486   mhd_assert (NULL != param->value.str);
   2487   mhd_assert (0 != param->value.len);
   2488   if (param->quoted)
   2489     return MHD_str_equal_quoted_bin_n (param->value.str, param->value.len,
   2490                                        str, str_len);
   2491   return (str_len == param->value.len) &&
   2492          (0 == memcmp (str, param->value.str, str_len));
   2493 
   2494 }
   2495 
   2496 
   2497 /**
   2498  * Authenticates the authorization header sent by the client
   2499  *
   2500  * If RFC2069 mode is allowed by setting bit #MHD_DIGEST_AUTH_QOP_NONE in
   2501  * @a mqop and the client uses this mode, then server generated nonces are
   2502  * used as one-time nonces because nonce-count is not supported in this old RFC.
   2503  * Communication in this mode is very inefficient, especially if the client
   2504  * requests several resources one-by-one as for every request new nonce must be
   2505  * generated and client repeat all requests twice (the first time to get a new
   2506  * nonce and the second time to perform an authorised request).
   2507  *
   2508  * @param connection the MHD connection structure
   2509  * @param realm the realm for authorization of the client
   2510  * @param username the username to be authenticated, must be in clear text
   2511  *                 even if userhash is used by the client
   2512  * @param password the password used in the authentication,
   2513  *                 must be NULL if @a userdigest is not NULL
   2514  * @param userdigest the precalculated binary hash of the string
   2515  *                   "username:realm:password",
   2516  *                   must be NULL if @a password is not NULL
   2517  * @param nonce_timeout the period of seconds since nonce generation, when
   2518  *                      the nonce is recognised as valid and not stale;
   2519  *                      unlike #digest_auth_check_all() zero is used literally
   2520  * @param max_nc the maximum allowed nc (Nonce Count) value, if client's nc
   2521  *               exceeds the specified value then MHD_DAUTH_NONCE_STALE is
   2522  *               returned;
   2523  *               unlike #digest_auth_check_all() zero is treated as "no limit"
   2524  * @param mqop the QOP to use
   2525  * @param malgo3 digest algorithms allowed to use, fail if algorithm specified
   2526  *               by the client is not allowed by this parameter
   2527  * @param[out] pbuf the pointer to pointer to internally malloc'ed buffer,
   2528  *                  to be freed if not NULL upon return
   2529  * @return #MHD_DAUTH_OK if authenticated,
   2530  *         error code otherwise.
   2531  * @ingroup authentication
   2532  */
   2533 static enum MHD_DigestAuthResult
   2534 digest_auth_check_all_inner (struct MHD_Connection *connection,
   2535                              const char *realm,
   2536                              const char *username,
   2537                              const char *password,
   2538                              const uint8_t *userdigest,
   2539                              unsigned int nonce_timeout,
   2540                              uint32_t max_nc,
   2541                              enum MHD_DigestAuthMultiQOP mqop,
   2542                              enum MHD_DigestAuthMultiAlgo3 malgo3,
   2543                              char **pbuf,
   2544                              struct DigestAlgorithm *da)
   2545 {
   2546   struct MHD_Daemon *daemon = MHD_get_master (connection->daemon);
   2547   enum MHD_DigestAuthAlgo3 c_algo; /**< Client's algorithm */
   2548   enum MHD_DigestAuthQOP c_qop; /**< Client's QOP */
   2549   unsigned int digest_size;
   2550   uint8_t hash1_bin[MAX_DIGEST];
   2551   uint8_t hash2_bin[MAX_DIGEST];
   2552 #if 0
   2553   const char *hentity = NULL; /* "auth-int" is not supported */
   2554 #endif
   2555   uint64_t nonce_time;
   2556   uint64_t nci;
   2557   const struct MHD_RqDAuth *params;
   2558   /**
   2559    * Temporal buffer in stack for unquoting and other needs
   2560    */
   2561   char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE];
   2562   char **const ptmp2 = pbuf;     /**< Temporal malloc'ed buffer for unquoting */
   2563   size_t tmp2_size; /**< The size of @a tmp2 buffer */
   2564   struct _MHD_str_w_len unquoted;
   2565   struct _MHD_mstr_w_len unq_copy;
   2566   enum _MHD_GetUnqResult unq_res;
   2567   size_t username_len;
   2568   size_t realm_len;
   2569 
   2570   mhd_assert ((NULL != password) || (NULL != userdigest));
   2571   mhd_assert (! ((NULL != userdigest) && (NULL != password)));
   2572 
   2573   tmp2_size = 0;
   2574 
   2575   params = MHD_get_rq_dauth_params_ (connection);
   2576   if (NULL == params)
   2577     return MHD_DAUTH_WRONG_HEADER;
   2578 
   2579   /* ** Initial parameters checks and setup ** */
   2580   /* Get client's algorithm */
   2581   c_algo = params->algo3;
   2582   /* Check whether client's algorithm is allowed by function parameter */
   2583   if (((unsigned int) c_algo) !=
   2584       (((unsigned int) c_algo) & ((unsigned int) malgo3)))
   2585     return MHD_DAUTH_WRONG_ALGO;
   2586   /* Check whether client's algorithm is supported */
   2587   if (0 != (((unsigned int) c_algo) & MHD_DIGEST_AUTH_ALGO3_SESSION))
   2588   {
   2589 #ifdef HAVE_MESSAGES
   2590     MHD_DLOG (connection->daemon,
   2591               _ ("The 'session' algorithms are not supported.\n"));
   2592 #endif /* HAVE_MESSAGES */
   2593     return MHD_DAUTH_WRONG_ALGO;
   2594   }
   2595 #ifndef MHD_MD5_SUPPORT
   2596   if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_MD5))
   2597   {
   2598 #ifdef HAVE_MESSAGES
   2599     MHD_DLOG (connection->daemon,
   2600               _ ("The MD5 algorithm is not supported by this MHD build.\n"));
   2601 #endif /* HAVE_MESSAGES */
   2602     return MHD_DAUTH_WRONG_ALGO;
   2603   }
   2604 #endif /* ! MHD_MD5_SUPPORT */
   2605 #ifndef MHD_SHA256_SUPPORT
   2606   if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_SHA256))
   2607   {
   2608 #ifdef HAVE_MESSAGES
   2609     MHD_DLOG (connection->daemon,
   2610               _ ("The SHA-256 algorithm is not supported by "
   2611                  "this MHD build.\n"));
   2612 #endif /* HAVE_MESSAGES */
   2613     return MHD_DAUTH_WRONG_ALGO;
   2614   }
   2615 #endif /* ! MHD_SHA256_SUPPORT */
   2616 #ifndef MHD_SHA512_256_SUPPORT
   2617   if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_SHA512_256))
   2618   {
   2619 #ifdef HAVE_MESSAGES
   2620     MHD_DLOG (connection->daemon,
   2621               _ ("The SHA-512/256 algorithm is not supported by "
   2622                  "this MHD build.\n"));
   2623 #endif /* HAVE_MESSAGES */
   2624     return MHD_DAUTH_WRONG_ALGO;
   2625   }
   2626 #endif /* ! MHD_SHA512_256_SUPPORT */
   2627   if (! digest_init_one_time (da, get_base_digest_algo (c_algo)))
   2628     MHD_PANIC (_ ("Wrong 'malgo3' value, API violation"));
   2629   /* Check 'mqop' value */
   2630   c_qop = params->qop;
   2631   /* Check whether client's QOP is allowed by function parameter */
   2632   if (((unsigned int) c_qop) !=
   2633       (((unsigned int) c_qop) & ((unsigned int) mqop)))
   2634     return MHD_DAUTH_WRONG_QOP;
   2635   if (0 != (((unsigned int) c_qop) & MHD_DIGEST_AUTH_QOP_AUTH_INT))
   2636   {
   2637 #ifdef HAVE_MESSAGES
   2638     MHD_DLOG (connection->daemon,
   2639               _ ("The 'auth-int' QOP is not supported.\n"));
   2640 #endif /* HAVE_MESSAGES */
   2641     return MHD_DAUTH_WRONG_QOP;
   2642   }
   2643 #ifdef HAVE_MESSAGES
   2644   if ((MHD_DIGEST_AUTH_QOP_NONE == c_qop) &&
   2645       (0 == (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_MD5)))
   2646     MHD_DLOG (connection->daemon,
   2647               _ ("RFC2069 with SHA-256 or SHA-512/256 algorithm is " \
   2648                  "non-standard extension.\n"));
   2649 #endif /* HAVE_MESSAGES */
   2650 
   2651   digest_size = digest_get_size (da);
   2652 
   2653   /* ** A quick check for presence of all required parameters ** */
   2654 
   2655   if ((NULL == params->username.value.str) &&
   2656       (NULL == params->username_ext.value.str))
   2657     return MHD_DAUTH_WRONG_USERNAME;
   2658   else if ((NULL != params->username.value.str) &&
   2659            (NULL != params->username_ext.value.str))
   2660     return MHD_DAUTH_WRONG_USERNAME; /* Parameters cannot be used together */
   2661   else if ((NULL != params->username_ext.value.str) &&
   2662            (MHD_DAUTH_EXT_PARAM_MIN_LEN > params->username_ext.value.len))
   2663     return MHD_DAUTH_WRONG_USERNAME;  /* Broken extended notation */
   2664   else if (params->userhash && (NULL == params->username.value.str))
   2665     return MHD_DAUTH_WRONG_USERNAME;  /* Userhash cannot be used with extended notation */
   2666   else if (params->userhash && (digest_size * 2 > params->username.value.len))
   2667     return MHD_DAUTH_WRONG_USERNAME;  /* Too few chars for correct userhash */
   2668   else if (params->userhash && (digest_size * 4 < params->username.value.len))
   2669     return MHD_DAUTH_WRONG_USERNAME;  /* Too many chars for correct userhash */
   2670 
   2671   if (NULL == params->realm.value.str)
   2672     return MHD_DAUTH_WRONG_REALM;
   2673   else if (((NULL == userdigest) || params->userhash) &&
   2674            (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < params->realm.value.len))
   2675     return MHD_DAUTH_TOO_LARGE; /* Realm is too large and should be used in hash calculations */
   2676 
   2677   if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
   2678   {
   2679     if (NULL == params->nc.value.str)
   2680       return MHD_DAUTH_WRONG_HEADER;
   2681     else if (0 == params->nc.value.len)
   2682       return MHD_DAUTH_WRONG_HEADER;
   2683     else if (4 * 8 < params->nc.value.len) /* Four times more than needed */
   2684       return MHD_DAUTH_WRONG_HEADER;
   2685 
   2686     if (NULL == params->cnonce.value.str)
   2687       return MHD_DAUTH_WRONG_HEADER;
   2688     else if (0 == params->cnonce.value.len)
   2689       return MHD_DAUTH_WRONG_HEADER;
   2690     else if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < params->cnonce.value.len)
   2691       return MHD_DAUTH_TOO_LARGE;
   2692   }
   2693 
   2694   /* The QOP parameter was checked already */
   2695 
   2696   if (NULL == params->uri.value.str)
   2697     return MHD_DAUTH_WRONG_URI;
   2698   else if (0 == params->uri.value.len)
   2699     return MHD_DAUTH_WRONG_URI;
   2700   else if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < params->uri.value.len)
   2701     return MHD_DAUTH_TOO_LARGE;
   2702 
   2703   if (NULL == params->nonce.value.str)
   2704     return MHD_DAUTH_NONCE_WRONG;
   2705   else if (0 == params->nonce.value.len)
   2706     return MHD_DAUTH_NONCE_WRONG;
   2707   else if (NONCE_STD_LEN (digest_size) * 2 < params->nonce.value.len)
   2708     return MHD_DAUTH_NONCE_WRONG;
   2709 
   2710   if (NULL == params->response.value.str)
   2711     return MHD_DAUTH_RESPONSE_WRONG;
   2712   else if (0 == params->response.value.len)
   2713     return MHD_DAUTH_RESPONSE_WRONG;
   2714   else if (digest_size * 4 < params->response.value.len)
   2715     return MHD_DAUTH_RESPONSE_WRONG;
   2716 
   2717   /* ** Check simple parameters match ** */
   2718 
   2719   /* Check 'algorithm' */
   2720   /* The 'algorithm' was checked at the start of the function */
   2721   /* 'algorithm' valid */
   2722 
   2723   /* Check 'qop' */
   2724   /* The 'qop' was checked at the start of the function */
   2725   /* 'qop' valid */
   2726 
   2727   /* Check 'realm' */
   2728   realm_len = strlen (realm);
   2729   if (! is_param_equal (&params->realm, realm, realm_len))
   2730     return MHD_DAUTH_WRONG_REALM;
   2731   /* 'realm' valid */
   2732 
   2733   /* Check 'username' */
   2734   username_len = strlen (username);
   2735   if (! params->userhash)
   2736   {
   2737     if (NULL != params->username.value.str)
   2738     { /* Username in standard notation */
   2739       if (! is_param_equal (&params->username, username, username_len))
   2740         return MHD_DAUTH_WRONG_USERNAME;
   2741     }
   2742     else
   2743     { /* Username in extended notation */
   2744       char *r_uname;
   2745       size_t buf_size = params->username_ext.value.len;
   2746       ssize_t res;
   2747 
   2748       mhd_assert (NULL != params->username_ext.value.str);
   2749       mhd_assert (MHD_DAUTH_EXT_PARAM_MIN_LEN <= buf_size); /* It was checked already */
   2750       buf_size += 1; /* For zero-termination */
   2751       buf_size -= MHD_DAUTH_EXT_PARAM_MIN_LEN;
   2752       r_uname = get_buffer_for_size (tmp1, ptmp2, &tmp2_size, buf_size);
   2753       if (NULL == r_uname)
   2754         return (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < buf_size) ?
   2755                MHD_DAUTH_TOO_LARGE : MHD_DAUTH_ERROR;
   2756       res = get_rq_extended_uname_copy_z (params->username_ext.value.str,
   2757                                           params->username_ext.value.len,
   2758                                           r_uname, buf_size);
   2759       if (0 > res)
   2760         return MHD_DAUTH_WRONG_HEADER; /* Broken extended notation */
   2761       if ((username_len != (size_t) res) ||
   2762           (0 != memcmp (username, r_uname, username_len)))
   2763         return MHD_DAUTH_WRONG_USERNAME;
   2764     }
   2765   }
   2766   else
   2767   { /* Userhash */
   2768     mhd_assert (NULL != params->username.value.str);
   2769     calc_userhash (da, username, username_len, realm, realm_len, hash1_bin);
   2770 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   2771     if (digest_ext_error (da))
   2772       return MHD_DAUTH_ERROR;
   2773 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   2774     mhd_assert (sizeof (tmp1) >= (2 * digest_size));
   2775     MHD_bin_to_hex (hash1_bin, digest_size, tmp1);
   2776     if (! is_param_equal_caseless (&params->username, tmp1, 2 * digest_size))
   2777       return MHD_DAUTH_WRONG_USERNAME;
   2778     /* To simplify the logic, the digest is reset here instead of resetting
   2779        before the next hash calculation. */
   2780     digest_reset (da);
   2781   }
   2782   /* 'username' valid */
   2783 
   2784   /* ** Do basic nonce and nonce-counter checks (size, timestamp) ** */
   2785 
   2786   /* Get 'nc' digital value */
   2787   if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
   2788   {
   2789 
   2790     unq_res = get_unquoted_param (&params->nc, tmp1, ptmp2, &tmp2_size,
   2791                                   &unquoted);
   2792     if (_MHD_UNQ_OK != unq_res)
   2793       return MHD_DAUTH_ERROR;
   2794 
   2795     if (unquoted.len != MHD_strx_to_uint64_n_ (unquoted.str,
   2796                                                unquoted.len,
   2797                                                &nci))
   2798     {
   2799 #ifdef HAVE_MESSAGES
   2800       MHD_DLOG (daemon,
   2801                 _ ("Authentication failed, invalid nc format.\n"));
   2802 #endif
   2803       return MHD_DAUTH_WRONG_HEADER;   /* invalid nonce format */
   2804     }
   2805     if (0 == nci)
   2806     {
   2807 #ifdef HAVE_MESSAGES
   2808       MHD_DLOG (daemon,
   2809                 _ ("Authentication failed, invalid 'nc' value.\n"));
   2810 #endif
   2811       return MHD_DAUTH_WRONG_HEADER;   /* invalid nc value */
   2812     }
   2813     if ((0 != max_nc) && (max_nc < nci))
   2814       return MHD_DAUTH_NONCE_STALE;    /* Too large 'nc' value */
   2815   }
   2816   else
   2817     nci = 1; /* Force 'nc' value */
   2818   /* Got 'nc' digital value */
   2819 
   2820   /* Get 'nonce' with basic checks */
   2821   unq_res = get_unquoted_param (&params->nonce, tmp1, ptmp2, &tmp2_size,
   2822                                 &unquoted);
   2823   if (_MHD_UNQ_OK != unq_res)
   2824     return MHD_DAUTH_ERROR;
   2825 
   2826   if ((NONCE_STD_LEN (digest_size) != unquoted.len) ||
   2827       (! get_nonce_timestamp (unquoted.str, unquoted.len, &nonce_time)))
   2828   {
   2829 #ifdef HAVE_MESSAGES
   2830     MHD_DLOG (daemon,
   2831               _ ("Authentication failed, invalid nonce format.\n"));
   2832 #endif
   2833     return MHD_DAUTH_NONCE_WRONG;
   2834   }
   2835 
   2836   if (1)
   2837   {
   2838     uint64_t t;
   2839 
   2840     t = MHD_monotonic_msec_counter ();
   2841     /*
   2842      * First level vetting for the nonce validity: if the timestamp
   2843      * attached to the nonce exceeds `nonce_timeout', then the nonce is
   2844      * stale.
   2845      */
   2846     if (TRIM_TO_TIMESTAMP (t - nonce_time) > (nonce_timeout * 1000))
   2847       return MHD_DAUTH_NONCE_STALE; /* too old */
   2848   }
   2849   if (1)
   2850   {
   2851     enum MHD_CheckNonceNC_ nonce_nc_check;
   2852     /*
   2853      * Checking if that combination of nonce and nc is sound
   2854      * and not a replay attack attempt. Refuse if nonce was not
   2855      * generated previously.
   2856      */
   2857     nonce_nc_check = check_nonce_nc (connection,
   2858                                      unquoted.str,
   2859                                      NONCE_STD_LEN (digest_size),
   2860                                      nonce_time,
   2861                                      nci);
   2862     if (MHD_CHECK_NONCENC_STALE == nonce_nc_check)
   2863     {
   2864 #ifdef HAVE_MESSAGES
   2865       if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
   2866         MHD_DLOG (daemon,
   2867                   _ ("Stale nonce received. If this happens a lot, you should "
   2868                      "probably increase the size of the nonce array.\n"));
   2869       else
   2870         MHD_DLOG (daemon,
   2871                   _ ("Stale nonce received. This is expected when client " \
   2872                      "uses RFC2069-compatible mode and makes more than one " \
   2873                      "request.\n"));
   2874 #endif
   2875       return MHD_DAUTH_NONCE_STALE;
   2876     }
   2877     else if (MHD_CHECK_NONCENC_WRONG == nonce_nc_check)
   2878     {
   2879 #ifdef HAVE_MESSAGES
   2880       MHD_DLOG (daemon,
   2881                 _ ("Received nonce that was not "
   2882                    "generated by MHD. This may indicate an attack attempt.\n"));
   2883 #endif
   2884       return MHD_DAUTH_NONCE_WRONG;
   2885     }
   2886     mhd_assert (MHD_CHECK_NONCENC_OK == nonce_nc_check);
   2887   }
   2888   /* The nonce was generated by MHD, is not stale and nonce-nc combination was
   2889      not used before */
   2890 
   2891   /* ** Build H(A2) and check URI match in the header and in the request ** */
   2892 
   2893   /* Get 'uri' */
   2894   mhd_assert (! da->hashing);
   2895   digest_update_str (da, connection->rq.method);
   2896   digest_update_with_colon (da);
   2897 #if 0
   2898   /* TODO: add support for "auth-int" */
   2899   digest_update_str (da, hentity);
   2900   digest_update_with_colon (da);
   2901 #endif
   2902   unq_res = get_unquoted_param_copy (&params->uri, tmp1, ptmp2, &tmp2_size,
   2903                                      &unq_copy);
   2904   if (_MHD_UNQ_OK != unq_res)
   2905     return MHD_DAUTH_ERROR;
   2906 
   2907   digest_update (da, unq_copy.str, unq_copy.len);
   2908   /* The next check will modify copied URI string */
   2909   if (! check_uri_match (connection, unq_copy.str, unq_copy.len))
   2910     return MHD_DAUTH_WRONG_URI;
   2911   digest_calc_hash (da, hash2_bin);
   2912 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   2913   /* Skip digest calculation external error check, the next one checks both */
   2914 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   2915   /* Got H(A2) */
   2916 
   2917   /* ** Build H(A1) ** */
   2918   if (NULL == userdigest)
   2919   {
   2920     mhd_assert (! da->hashing);
   2921     digest_reset (da);
   2922     calc_userdigest (da,
   2923                      username, username_len,
   2924                      realm, realm_len,
   2925                      password,
   2926                      hash1_bin);
   2927   }
   2928   /* TODO: support '-sess' versions */
   2929 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   2930   if (digest_ext_error (da))
   2931     return MHD_DAUTH_ERROR;
   2932 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   2933   /* Got H(A1) */
   2934 
   2935   /* **  Check 'response' ** */
   2936 
   2937   mhd_assert (! da->hashing);
   2938   digest_reset (da);
   2939   /* Update digest with H(A1) */
   2940   mhd_assert (sizeof (tmp1) >= (digest_size * 2));
   2941   if (NULL == userdigest)
   2942     MHD_bin_to_hex (hash1_bin, digest_size, tmp1);
   2943   else
   2944     MHD_bin_to_hex (userdigest, digest_size, tmp1);
   2945   digest_update (da, (const uint8_t *) tmp1, digest_size * 2);
   2946 
   2947   /* H(A1) is not needed anymore, reuse the buffer.
   2948    * Use hash1_bin for the client's 'response' decoded to binary form. */
   2949   unq_res = get_unquoted_param (&params->response, tmp1, ptmp2, &tmp2_size,
   2950                                 &unquoted);
   2951   if (_MHD_UNQ_OK != unq_res)
   2952     return MHD_DAUTH_ERROR;
   2953   if (digest_size != MHD_hex_to_bin (unquoted.str, unquoted.len, hash1_bin))
   2954     return MHD_DAUTH_RESPONSE_WRONG;
   2955 
   2956   /* Update digest with ':' */
   2957   digest_update_with_colon (da);
   2958   /* Update digest with 'nonce' text value */
   2959   unq_res = get_unquoted_param (&params->nonce, tmp1, ptmp2, &tmp2_size,
   2960                                 &unquoted);
   2961   if (_MHD_UNQ_OK != unq_res)
   2962     return MHD_DAUTH_ERROR;
   2963   digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
   2964   /* Update digest with ':' */
   2965   digest_update_with_colon (da);
   2966   if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
   2967   {
   2968     /* Update digest with 'nc' text value */
   2969     unq_res = get_unquoted_param (&params->nc, tmp1, ptmp2, &tmp2_size,
   2970                                   &unquoted);
   2971     if (_MHD_UNQ_OK != unq_res)
   2972       return MHD_DAUTH_ERROR;
   2973     digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
   2974     /* Update digest with ':' */
   2975     digest_update_with_colon (da);
   2976     /* Update digest with 'cnonce' value */
   2977     unq_res = get_unquoted_param (&params->cnonce, tmp1, ptmp2, &tmp2_size,
   2978                                   &unquoted);
   2979     if (_MHD_UNQ_OK != unq_res)
   2980       return MHD_DAUTH_ERROR;
   2981     digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
   2982     /* Update digest with ':' */
   2983     digest_update_with_colon (da);
   2984     /* Update digest with 'qop' value */
   2985     unq_res = get_unquoted_param (&params->qop_raw, tmp1, ptmp2, &tmp2_size,
   2986                                   &unquoted);
   2987     if (_MHD_UNQ_OK != unq_res)
   2988       return MHD_DAUTH_ERROR;
   2989     digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
   2990     /* Update digest with ':' */
   2991     digest_update_with_colon (da);
   2992   }
   2993   /* Update digest with H(A2) */
   2994   MHD_bin_to_hex (hash2_bin, digest_size, tmp1);
   2995   digest_update (da, (const uint8_t *) tmp1, digest_size * 2);
   2996 
   2997   /* H(A2) is not needed anymore, reuse the buffer.
   2998    * Use hash2_bin for the calculated response in binary form */
   2999   digest_calc_hash (da, hash2_bin);
   3000 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   3001   if (digest_ext_error (da))
   3002     return MHD_DAUTH_ERROR;
   3003 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   3004 
   3005   if (0 != memcmp (hash1_bin, hash2_bin, digest_size))
   3006     return MHD_DAUTH_RESPONSE_WRONG;
   3007 
   3008   if (MHD_DAUTH_BIND_NONCE_NONE != daemon->dauth_bind_type)
   3009   {
   3010     mhd_assert (sizeof(tmp1) >= (NONCE_STD_LEN (digest_size) + 1));
   3011     /* It was already checked that 'nonce' (including timestamp) was generated
   3012        by MHD. */
   3013     mhd_assert (! da->hashing);
   3014     digest_reset (da);
   3015     calculate_nonce (nonce_time,
   3016                      connection->rq.http_mthd,
   3017                      connection->rq.method,
   3018                      daemon->digest_auth_random,
   3019                      daemon->digest_auth_rand_size,
   3020                      connection->addr,
   3021                      (size_t) connection->addr_len,
   3022                      connection->rq.url,
   3023                      connection->rq.url_len,
   3024                      connection->rq.headers_received,
   3025                      realm,
   3026                      realm_len,
   3027                      daemon->dauth_bind_type,
   3028                      da,
   3029                      tmp1);
   3030 
   3031 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   3032     if (digest_ext_error (da))
   3033       return MHD_DAUTH_ERROR;
   3034 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   3035 
   3036     if (! is_param_equal (&params->nonce, tmp1,
   3037                           NONCE_STD_LEN (digest_size)))
   3038       return MHD_DAUTH_NONCE_OTHER_COND;
   3039     /* The 'nonce' was generated in the same conditions */
   3040   }
   3041 
   3042   return MHD_DAUTH_OK;
   3043 }
   3044 
   3045 
   3046 /**
   3047  * Authenticates the authorization header sent by the client
   3048  *
   3049  * If RFC2069 mode is allowed by setting bit #MHD_DIGEST_AUTH_QOP_NONE in
   3050  * @a mqop and the client uses this mode, then server generated nonces are
   3051  * used as one-time nonces because nonce-count is not supported in this old RFC.
   3052  * Communication in this mode is very inefficient, especially if the client
   3053  * requests several resources one-by-one as for every request new nonce must be
   3054  * generated and client repeat all requests twice (the first time to get a new
   3055  * nonce and the second time to perform an authorised request).
   3056  *
   3057  * @param connection the MHD connection structure
   3058  * @param realm the realm for authorization of the client
   3059  * @param username the username to be authenticated, must be in clear text
   3060  *                 even if userhash is used by the client
   3061  * @param password the password used in the authentication,
   3062  *                 must be NULL if @a userdigest is not NULL
   3063  * @param userdigest the precalculated binary hash of the string
   3064  *                   "username:realm:password",
   3065  *                   must be NULL if @a password is not NULL
   3066  * @param nonce_timeout the period of seconds since nonce generation, when
   3067  *                      the nonce is recognised as valid and not stale;
   3068  *                      if set to zero then daemon's default value is used
   3069  * @param max_nc the maximum allowed nc (Nonce Count) value, if client's nc
   3070  *               exceeds the specified value then MHD_DAUTH_NONCE_STALE is
   3071  *               returned;
   3072  *               if set to zero then daemon's default value is used
   3073  * @param mqop the QOP to use
   3074  * @param malgo3 digest algorithms allowed to use, fail if algorithm specified
   3075  *               by the client is not allowed by this parameter
   3076  * @return #MHD_DAUTH_OK if authenticated,
   3077  *         error code otherwise.
   3078  * @ingroup authentication
   3079  */
   3080 static enum MHD_DigestAuthResult
   3081 digest_auth_check_all (struct MHD_Connection *connection,
   3082                        const char *realm,
   3083                        const char *username,
   3084                        const char *password,
   3085                        const uint8_t *userdigest,
   3086                        unsigned int nonce_timeout,
   3087                        uint32_t max_nc,
   3088                        enum MHD_DigestAuthMultiQOP mqop,
   3089                        enum MHD_DigestAuthMultiAlgo3 malgo3)
   3090 {
   3091   enum MHD_DigestAuthResult res;
   3092   char *buf;
   3093   struct DigestAlgorithm da;
   3094 
   3095   buf = NULL;
   3096   digest_setup_zero (&da);
   3097   if (0 == nonce_timeout)
   3098     nonce_timeout = connection->daemon->dauth_def_nonce_timeout;
   3099   if (0 == max_nc)
   3100     max_nc = connection->daemon->dauth_def_max_nc;
   3101   res = digest_auth_check_all_inner (connection, realm, username, password,
   3102                                      userdigest,
   3103                                      nonce_timeout,
   3104                                      max_nc, mqop, malgo3,
   3105                                      &buf, &da);
   3106   digest_deinit (&da);
   3107   if (NULL != buf)
   3108     free (buf);
   3109 
   3110   return res;
   3111 }
   3112 
   3113 
   3114 /**
   3115  * Authenticates the authorization header sent by the client.
   3116  * Uses #MHD_DIGEST_ALG_MD5 (for now, for backwards-compatibility).
   3117  * Note that this MAY change to #MHD_DIGEST_ALG_AUTO in the future.
   3118  * If you want to be sure you get MD5, use #MHD_digest_auth_check2()
   3119  * and specify MD5 explicitly.
   3120  *
   3121  * @param connection The MHD connection structure
   3122  * @param realm The realm presented to the client
   3123  * @param username The username needs to be authenticated
   3124  * @param password The password used in the authentication
   3125  * @param nonce_timeout The amount of time for a nonce to be
   3126  *      invalid in seconds
   3127  * @return #MHD_YES if authenticated, #MHD_NO if not,
   3128  *         #MHD_INVALID_NONCE if nonce is invalid or stale
   3129  * @deprecated use MHD_digest_auth_check3()
   3130  * @ingroup authentication
   3131  */
   3132 _MHD_EXTERN int
   3133 MHD_digest_auth_check (struct MHD_Connection *connection,
   3134                        const char *realm,
   3135                        const char *username,
   3136                        const char *password,
   3137                        unsigned int nonce_timeout)
   3138 {
   3139   return MHD_digest_auth_check2 (connection,
   3140                                  realm,
   3141                                  username,
   3142                                  password,
   3143                                  nonce_timeout,
   3144                                  MHD_DIGEST_ALG_MD5);
   3145 }
   3146 
   3147 
   3148 /**
   3149  * Authenticates the authorization header sent by the client.
   3150  *
   3151  * If RFC2069 mode is allowed by setting bit #MHD_DIGEST_AUTH_QOP_NONE in
   3152  * @a mqop and the client uses this mode, then server generated nonces are
   3153  * used as one-time nonces because nonce-count is not supported in this old RFC.
   3154  * Communication in this mode is very inefficient, especially if the client
   3155  * requests several resources one-by-one as for every request a new nonce must
   3156  * be generated and client repeats all requests twice (first time to get a new
   3157  * nonce and second time to perform an authorised request).
   3158  *
   3159  * @param connection the MHD connection structure
   3160  * @param realm the realm for authorization of the client
   3161  * @param username the username to be authenticated, must be in clear text
   3162  *                 even if userhash is used by the client
   3163  * @param password the password matching the @a username (and the @a realm)
   3164  * @param nonce_timeout the period of seconds since nonce generation, when
   3165  *                      the nonce is recognised as valid and not stale;
   3166  *                      if zero is specified then daemon default value is used.
   3167  * @param max_nc the maximum allowed nc (Nonce Count) value, if client's nc
   3168  *               exceeds the specified value then MHD_DAUTH_NONCE_STALE is
   3169  *               returned;
   3170  *               if zero is specified then daemon default value is used.
   3171  * @param mqop the QOP to use
   3172  * @param malgo3 digest algorithms allowed to use, fail if algorithm used
   3173  *               by the client is not allowed by this parameter
   3174  * @return #MHD_DAUTH_OK if authenticated,
   3175  *         the error code otherwise
   3176  * @note Available since #MHD_VERSION 0x00097708
   3177  * @ingroup authentication
   3178  */
   3179 _MHD_EXTERN enum MHD_DigestAuthResult
   3180 MHD_digest_auth_check3 (struct MHD_Connection *connection,
   3181                         const char *realm,
   3182                         const char *username,
   3183                         const char *password,
   3184                         unsigned int nonce_timeout,
   3185                         uint32_t max_nc,
   3186                         enum MHD_DigestAuthMultiQOP mqop,
   3187                         enum MHD_DigestAuthMultiAlgo3 malgo3)
   3188 {
   3189   mhd_assert (NULL != password);
   3190 
   3191   return digest_auth_check_all (connection,
   3192                                 realm,
   3193                                 username,
   3194                                 password,
   3195                                 NULL,
   3196                                 nonce_timeout,
   3197                                 max_nc,
   3198                                 mqop,
   3199                                 malgo3);
   3200 }
   3201 
   3202 
   3203 /**
   3204  * Authenticates the authorization header sent by the client by using
   3205  * hash of "username:realm:password".
   3206  *
   3207  * If RFC2069 mode is allowed by setting bit #MHD_DIGEST_AUTH_QOP_NONE in
   3208  * @a mqop and the client uses this mode, then server generated nonces are
   3209  * used as one-time nonces because nonce-count is not supported in this old RFC.
   3210  * Communication in this mode is very inefficient, especially if the client
   3211  * requests several resources one-by-one as for every request a new nonce must
   3212  * be generated and client repeats all requests twice (first time to get a new
   3213  * nonce and second time to perform an authorised request).
   3214  *
   3215  * @param connection the MHD connection structure
   3216  * @param realm the realm for authorization of the client
   3217  * @param username the username to be authenticated, must be in clear text
   3218  *                 even if userhash is used by the client
   3219  * @param userdigest the precalculated binary hash of the string
   3220  *                   "username:realm:password",
   3221  *                   see #MHD_digest_auth_calc_userdigest()
   3222  * @param userdigest_size the size of the @a userdigest in bytes, must match the
   3223  *                        hashing algorithm (see #MHD_MD5_DIGEST_SIZE,
   3224  *                        #MHD_SHA256_DIGEST_SIZE, #MHD_SHA512_256_DIGEST_SIZE,
   3225  *                        #MHD_digest_get_hash_size())
   3226  * @param nonce_timeout the period of seconds since nonce generation, when
   3227  *                      the nonce is recognised as valid and not stale;
   3228  *                      if zero is specified then daemon default value is used.
   3229  * @param max_nc the maximum allowed nc (Nonce Count) value, if client's nc
   3230  *               exceeds the specified value then MHD_DAUTH_NONCE_STALE is
   3231  *               returned;
   3232  *               if zero is specified then daemon default value is used.
   3233  * @param mqop the QOP to use
   3234  * @param malgo3 digest algorithms allowed to use, fail if algorithm used
   3235  *               by the client is not allowed by this parameter;
   3236  *               more than one base algorithms (MD5, SHA-256, SHA-512/256)
   3237  *               cannot be used at the same time for this function
   3238  *               as @a userdigest must match specified algorithm
   3239  * @return #MHD_DAUTH_OK if authenticated,
   3240  *         the error code otherwise
   3241  * @sa #MHD_digest_auth_calc_userdigest()
   3242  * @note Available since #MHD_VERSION 0x00097708
   3243  * @ingroup authentication
   3244  */
   3245 _MHD_EXTERN enum MHD_DigestAuthResult
   3246 MHD_digest_auth_check_digest3 (struct MHD_Connection *connection,
   3247                                const char *realm,
   3248                                const char *username,
   3249                                const void *userdigest,
   3250                                size_t userdigest_size,
   3251                                unsigned int nonce_timeout,
   3252                                uint32_t max_nc,
   3253                                enum MHD_DigestAuthMultiQOP mqop,
   3254                                enum MHD_DigestAuthMultiAlgo3 malgo3)
   3255 {
   3256   if (1 != (((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_MD5)) ? 1 : 0)
   3257             + ((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_SHA256)) ? 1 : 0)
   3258             + ((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_SHA512_256)) ? 1 : 0)))
   3259     MHD_PANIC (_ ("Wrong 'malgo3' value, only one base hashing algorithm " \
   3260                   "(MD5, SHA-256 or SHA-512/256) must be specified, " \
   3261                   "API violation"));
   3262 
   3263 #ifndef MHD_MD5_SUPPORT
   3264   if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_MD5))
   3265   {
   3266 #ifdef HAVE_MESSAGES
   3267     MHD_DLOG (connection->daemon,
   3268               _ ("The MD5 algorithm is not supported by this MHD build.\n"));
   3269 #endif /* HAVE_MESSAGES */
   3270     return MHD_DAUTH_WRONG_ALGO;
   3271   }
   3272 #endif /* ! MHD_MD5_SUPPORT */
   3273 #ifndef MHD_SHA256_SUPPORT
   3274   if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA256))
   3275   {
   3276 #ifdef HAVE_MESSAGES
   3277     MHD_DLOG (connection->daemon,
   3278               _ ("The SHA-256 algorithm is not supported by "
   3279                  "this MHD build.\n"));
   3280 #endif /* HAVE_MESSAGES */
   3281     return MHD_DAUTH_WRONG_ALGO;
   3282   }
   3283 #endif /* ! MHD_SHA256_SUPPORT */
   3284 #ifndef MHD_SHA512_256_SUPPORT
   3285   if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA512_256))
   3286   {
   3287 #ifdef HAVE_MESSAGES
   3288     MHD_DLOG (connection->daemon,
   3289               _ ("The SHA-512/256 algorithm is not supported by "
   3290                  "this MHD build.\n"));
   3291 #endif /* HAVE_MESSAGES */
   3292     return MHD_DAUTH_WRONG_ALGO;
   3293   }
   3294 #endif /* ! MHD_SHA512_256_SUPPORT */
   3295 
   3296   if (digest_get_hash_size ((enum MHD_DigestAuthAlgo3) malgo3) !=
   3297       userdigest_size)
   3298     MHD_PANIC (_ ("Wrong 'userdigest_size' value, does not match 'malgo3', "
   3299                   "API violation"));
   3300 
   3301   return digest_auth_check_all (connection,
   3302                                 realm,
   3303                                 username,
   3304                                 NULL,
   3305                                 (const uint8_t *) userdigest,
   3306                                 nonce_timeout,
   3307                                 max_nc,
   3308                                 mqop,
   3309                                 malgo3);
   3310 }
   3311 
   3312 
   3313 /**
   3314  * Authenticates the authorization header sent by the client.
   3315  *
   3316  * @param connection The MHD connection structure
   3317  * @param realm The realm presented to the client
   3318  * @param username The username needs to be authenticated
   3319  * @param password The password used in the authentication
   3320  * @param nonce_timeout The amount of time for a nonce to be
   3321  *      invalid in seconds
   3322  * @param algo digest algorithms allowed for verification
   3323  * @return #MHD_YES if authenticated, #MHD_NO if not,
   3324  *         #MHD_INVALID_NONCE if nonce is invalid or stale
   3325  * @note Available since #MHD_VERSION 0x00096200
   3326  * @deprecated use MHD_digest_auth_check3()
   3327  * @ingroup authentication
   3328  */
   3329 _MHD_EXTERN int
   3330 MHD_digest_auth_check2 (struct MHD_Connection *connection,
   3331                         const char *realm,
   3332                         const char *username,
   3333                         const char *password,
   3334                         unsigned int nonce_timeout,
   3335                         enum MHD_DigestAuthAlgorithm algo)
   3336 {
   3337   enum MHD_DigestAuthResult res;
   3338   enum MHD_DigestAuthMultiAlgo3 malgo3;
   3339 
   3340   if (MHD_DIGEST_ALG_AUTO == algo)
   3341     malgo3 = MHD_DIGEST_AUTH_MULT_ALGO3_ANY_NON_SESSION;
   3342   else if (MHD_DIGEST_ALG_MD5 == algo)
   3343     malgo3 = MHD_DIGEST_AUTH_MULT_ALGO3_MD5;
   3344   else if (MHD_DIGEST_ALG_SHA256 == algo)
   3345     malgo3 = MHD_DIGEST_AUTH_MULT_ALGO3_SHA256;
   3346   else
   3347     MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
   3348 
   3349   res = MHD_digest_auth_check3 (connection,
   3350                                 realm,
   3351                                 username,
   3352                                 password,
   3353                                 nonce_timeout,
   3354                                 0, MHD_DIGEST_AUTH_MULT_QOP_AUTH,
   3355                                 malgo3);
   3356   if (MHD_DAUTH_OK == res)
   3357     return MHD_YES;
   3358   else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res) ||
   3359            (MHD_DAUTH_NONCE_OTHER_COND == res) )
   3360     return MHD_INVALID_NONCE;
   3361   return MHD_NO;
   3362 
   3363 }
   3364 
   3365 
   3366 /**
   3367  * Authenticates the authorization header sent by the client.
   3368  *
   3369  * @param connection The MHD connection structure
   3370  * @param realm The realm presented to the client
   3371  * @param username The username needs to be authenticated
   3372  * @param digest An `unsigned char *' pointer to the binary MD5 sum
   3373  *      for the precalculated hash value "username:realm:password"
   3374  *      of @a digest_size bytes
   3375  * @param digest_size number of bytes in @a digest (size must match @a algo!)
   3376  * @param nonce_timeout The amount of time for a nonce to be
   3377  *      invalid in seconds
   3378  * @param algo digest algorithms allowed for verification
   3379  * @return #MHD_YES if authenticated, #MHD_NO if not,
   3380  *         #MHD_INVALID_NONCE if nonce is invalid or stale
   3381  * @note Available since #MHD_VERSION 0x00096200
   3382  * @deprecated use MHD_digest_auth_check_digest3()
   3383  * @ingroup authentication
   3384  */
   3385 _MHD_EXTERN int
   3386 MHD_digest_auth_check_digest2 (struct MHD_Connection *connection,
   3387                                const char *realm,
   3388                                const char *username,
   3389                                const uint8_t *digest,
   3390                                size_t digest_size,
   3391                                unsigned int nonce_timeout,
   3392                                enum MHD_DigestAuthAlgorithm algo)
   3393 {
   3394   enum MHD_DigestAuthResult res;
   3395   enum MHD_DigestAuthMultiAlgo3 malgo3;
   3396 
   3397   if (MHD_DIGEST_ALG_AUTO == algo)
   3398     malgo3 = MHD_DIGEST_AUTH_MULT_ALGO3_ANY_NON_SESSION;
   3399   else if (MHD_DIGEST_ALG_MD5 == algo)
   3400     malgo3 = MHD_DIGEST_AUTH_MULT_ALGO3_MD5;
   3401   else if (MHD_DIGEST_ALG_SHA256 == algo)
   3402     malgo3 = MHD_DIGEST_AUTH_MULT_ALGO3_SHA256;
   3403   else
   3404     MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
   3405 
   3406   res = MHD_digest_auth_check_digest3 (connection,
   3407                                        realm,
   3408                                        username,
   3409                                        digest,
   3410                                        digest_size,
   3411                                        nonce_timeout,
   3412                                        0, MHD_DIGEST_AUTH_MULT_QOP_AUTH,
   3413                                        malgo3);
   3414   if (MHD_DAUTH_OK == res)
   3415     return MHD_YES;
   3416   else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res) ||
   3417            (MHD_DAUTH_NONCE_OTHER_COND == res) )
   3418     return MHD_INVALID_NONCE;
   3419   return MHD_NO;
   3420 }
   3421 
   3422 
   3423 /**
   3424  * Authenticates the authorization header sent by the client
   3425  * Uses #MHD_DIGEST_ALG_MD5 (required, as @a digest is of fixed
   3426  * size).
   3427  *
   3428  * @param connection The MHD connection structure
   3429  * @param realm The realm presented to the client
   3430  * @param username The username needs to be authenticated
   3431  * @param digest An `unsigned char *' pointer to the binary hash
   3432  *    for the precalculated hash value "username:realm:password";
   3433  *    length must be #MHD_MD5_DIGEST_SIZE bytes
   3434  * @param nonce_timeout The amount of time for a nonce to be
   3435  *      invalid in seconds
   3436  * @return #MHD_YES if authenticated, #MHD_NO if not,
   3437  *         #MHD_INVALID_NONCE if nonce is invalid or stale
   3438  * @note Available since #MHD_VERSION 0x00096000
   3439  * @deprecated use #MHD_digest_auth_check_digest3()
   3440  * @ingroup authentication
   3441  */
   3442 _MHD_EXTERN int
   3443 MHD_digest_auth_check_digest (struct MHD_Connection *connection,
   3444                               const char *realm,
   3445                               const char *username,
   3446                               const uint8_t digest[MHD_MD5_DIGEST_SIZE],
   3447                               unsigned int nonce_timeout)
   3448 {
   3449   return MHD_digest_auth_check_digest2 (connection,
   3450                                         realm,
   3451                                         username,
   3452                                         digest,
   3453                                         MHD_MD5_DIGEST_SIZE,
   3454                                         nonce_timeout,
   3455                                         MHD_DIGEST_ALG_MD5);
   3456 }
   3457 
   3458 
   3459 /**
   3460  * Internal version of #MHD_queue_auth_required_response3() to simplify
   3461  * cleanups.
   3462  *
   3463  * @param connection the MHD connection structure
   3464  * @param realm the realm presented to the client
   3465  * @param opaque the string for opaque value, can be NULL, but NULL is
   3466  *               not recommended for better compatibility with clients;
   3467  *               the recommended format is hex or Base64 encoded string
   3468  * @param domain the optional space-separated list of URIs for which the
   3469  *               same authorisation could be used, URIs can be in form
   3470  *               "path-absolute" (the path for the same host with initial slash)
   3471  *               or in form "absolute-URI" (the full path with protocol), in
   3472  *               any case client may assume that URI is in the same "protection
   3473  *               space" if it starts with any of values specified here;
   3474  *               could be NULL (clients typically assume that the same
   3475  *               credentials could be used for any URI on the same host)
   3476  * @param response the reply to send; should contain the "access denied"
   3477  *                 body; note that this function sets the "WWW Authenticate"
   3478  *                 header and that the caller should not do this;
   3479  *                 the NULL is tolerated
   3480  * @param signal_stale set to #MHD_YES if the nonce is stale to add 'stale=true'
   3481  *                     to the authentication header, this instructs the client
   3482  *                     to retry immediately with the new nonce and the same
   3483  *                     credentials, without asking user for the new password
   3484  * @param mqop the QOP to use
   3485  * @param malgo3 digest algorithm to use, MHD selects; if several algorithms
   3486  *               are allowed then MD5 is preferred (currently, may be changed
   3487  *               in next versions)
   3488  * @param userhash_support if set to non-zero value (#MHD_YES) then support of
   3489  *                         userhash is indicated, the client may provide
   3490  *                         hash("username:realm") instead of username in
   3491  *                         clear text;
   3492  *                         note that clients are allowed to provide the username
   3493  *                         in cleartext even if this parameter set to non-zero;
   3494  *                         when userhash is used, application must be ready to
   3495  *                         identify users by provided userhash value instead of
   3496  *                         username; see #MHD_digest_auth_calc_userhash() and
   3497  *                         #MHD_digest_auth_calc_userhash_hex()
   3498  * @param prefer_utf8 if not set to #MHD_NO, parameter 'charset=UTF-8' is
   3499  *                    added, indicating for the client that UTF-8 encoding
   3500  *                    is preferred
   3501  * @param prefer_utf8 if not set to #MHD_NO, parameter 'charset=UTF-8' is
   3502  *                    added, indicating for the client that UTF-8 encoding
   3503  *                    is preferred
   3504  * @return #MHD_YES on success, #MHD_NO otherwise
   3505  * @note Available since #MHD_VERSION 0x00097701
   3506  * @ingroup authentication
   3507  */
   3508 static enum MHD_Result
   3509 queue_auth_required_response3_inner (struct MHD_Connection *connection,
   3510                                      const char *realm,
   3511                                      const char *opaque,
   3512                                      const char *domain,
   3513                                      struct MHD_Response *response,
   3514                                      int signal_stale,
   3515                                      enum MHD_DigestAuthMultiQOP mqop,
   3516                                      enum MHD_DigestAuthMultiAlgo3 malgo3,
   3517                                      int userhash_support,
   3518                                      int prefer_utf8,
   3519                                      char **buf_ptr,
   3520                                      struct DigestAlgorithm *da)
   3521 {
   3522   static const char prefix_realm[] = "realm=\"";
   3523   static const char prefix_qop[] = "qop=\"";
   3524   static const char prefix_algo[] = "algorithm=";
   3525   static const char prefix_nonce[] = "nonce=\"";
   3526   static const char prefix_opaque[] = "opaque=\"";
   3527   static const char prefix_domain[] = "domain=\"";
   3528   static const char str_charset[] = "charset=UTF-8";
   3529   static const char str_userhash[] = "userhash=true";
   3530   static const char str_stale[] = "stale=true";
   3531   enum MHD_DigestAuthAlgo3 s_algo; /**< Selected algorithm */
   3532   size_t realm_len;
   3533   size_t opaque_len;
   3534   size_t domain_len;
   3535   size_t buf_size;
   3536   char *buf;
   3537   size_t p; /* The position in the buffer */
   3538   char *hdr_name;
   3539 
   3540   if ((0 == (((unsigned int) malgo3) & MHD_DIGEST_AUTH_ALGO3_NON_SESSION)) ||
   3541       (0 != (((unsigned int) malgo3) & MHD_DIGEST_AUTH_ALGO3_SESSION)))
   3542   {
   3543 #ifdef HAVE_MESSAGES
   3544     MHD_DLOG (connection->daemon,
   3545               _ ("Only non-'session' algorithms are supported.\n"));
   3546 #endif /* HAVE_MESSAGES */
   3547     return MHD_NO;
   3548   }
   3549   malgo3 =
   3550     (enum MHD_DigestAuthMultiAlgo3)
   3551     (malgo3
   3552      & (~((enum MHD_DigestAuthMultiAlgo3) MHD_DIGEST_AUTH_ALGO3_NON_SESSION)));
   3553 #ifdef MHD_MD5_SUPPORT
   3554   if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_MD5))
   3555     s_algo = MHD_DIGEST_AUTH_ALGO3_MD5;
   3556   else
   3557 #endif /* MHD_MD5_SUPPORT */
   3558 #ifdef MHD_SHA256_SUPPORT
   3559   if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA256))
   3560     s_algo = MHD_DIGEST_AUTH_ALGO3_SHA256;
   3561   else
   3562 #endif /* MHD_SHA256_SUPPORT */
   3563 #ifdef MHD_SHA512_256_SUPPORT
   3564   if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA512_256))
   3565     s_algo = MHD_DIGEST_AUTH_ALGO3_SHA512_256;
   3566   else
   3567 #endif /* MHD_SHA512_256_SUPPORT */
   3568   {
   3569     if (0 == (((unsigned int) malgo3)
   3570               & (MHD_DIGEST_BASE_ALGO_MD5 | MHD_DIGEST_BASE_ALGO_SHA256
   3571                  | MHD_DIGEST_BASE_ALGO_SHA512_256)))
   3572       MHD_PANIC (_ ("Wrong 'malgo3' value, API violation"));
   3573     else
   3574     {
   3575 #ifdef HAVE_MESSAGES
   3576       MHD_DLOG (connection->daemon,
   3577                 _ ("No requested algorithm is supported by this MHD build.\n"));
   3578 #endif /* HAVE_MESSAGES */
   3579     }
   3580     return MHD_NO;
   3581   }
   3582 
   3583   if (MHD_DIGEST_AUTH_MULT_QOP_AUTH_INT == mqop)
   3584     MHD_PANIC (_ ("Wrong 'mqop' value, API violation"));
   3585 
   3586   mqop = (enum MHD_DigestAuthMultiQOP)
   3587          (mqop
   3588           & (~((enum MHD_DigestAuthMultiQOP) MHD_DIGEST_AUTH_QOP_AUTH_INT)));
   3589 
   3590   if (! digest_init_one_time (da, get_base_digest_algo (s_algo)))
   3591     MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
   3592 
   3593   if (MHD_DIGEST_AUTH_MULT_QOP_NONE == mqop)
   3594   {
   3595 #ifdef HAVE_MESSAGES
   3596     if ((0 != userhash_support) || (0 != prefer_utf8))
   3597       MHD_DLOG (connection->daemon,
   3598                 _ ("The 'userhash' and 'charset' ('prefer_utf8') parameters " \
   3599                    "are not compatible with RFC2069 and ignored.\n"));
   3600     if (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5))
   3601       MHD_DLOG (connection->daemon,
   3602                 _ ("RFC2069 with SHA-256 or SHA-512/256 algorithm is " \
   3603                    "non-standard extension.\n"));
   3604 #endif
   3605     userhash_support = 0;
   3606     prefer_utf8 = 0;
   3607   }
   3608 
   3609   if (0 == MHD_get_master (connection->daemon)->nonce_nc_size)
   3610   {
   3611 #ifdef HAVE_MESSAGES
   3612     MHD_DLOG (connection->daemon,
   3613               _ ("The nonce array size is zero.\n"));
   3614 #endif /* HAVE_MESSAGES */
   3615     return MHD_NO;
   3616   }
   3617 
   3618   /* Calculate required size */
   3619   buf_size = 0;
   3620   /* 'Digest ' */
   3621   buf_size += MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE) + 1; /* 1 for ' ' */
   3622   buf_size += MHD_STATICSTR_LEN_ (prefix_realm) + 3; /* 3 for '", ' */
   3623   /* 'realm="xxxx", ' */
   3624   realm_len = strlen (realm);
   3625   if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < realm_len)
   3626   {
   3627 #ifdef HAVE_MESSAGES
   3628     MHD_DLOG (connection->daemon,
   3629               _ ("The 'realm' is too large.\n"));
   3630 #endif /* HAVE_MESSAGES */
   3631     return MHD_NO;
   3632   }
   3633   if ((NULL != memchr (realm, '\r', realm_len)) ||
   3634       (NULL != memchr (realm, '\n', realm_len)))
   3635     return MHD_NO;
   3636 
   3637   buf_size += realm_len * 2; /* Quoting may double the size */
   3638   /* 'qop="xxxx", ' */
   3639   if (MHD_DIGEST_AUTH_MULT_QOP_NONE != mqop)
   3640   {
   3641     buf_size += MHD_STATICSTR_LEN_ (prefix_qop) + 3; /* 3 for '", ' */
   3642     buf_size += MHD_STATICSTR_LEN_ (MHD_TOKEN_AUTH_);
   3643   }
   3644   /* 'algorithm="xxxx", ' */
   3645   if (((MHD_DIGEST_AUTH_MULT_QOP_NONE) != mqop) ||
   3646       (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5)))
   3647   {
   3648     buf_size += MHD_STATICSTR_LEN_ (prefix_algo) + 2; /* 2 for ', ' */
   3649 #ifdef MHD_MD5_SUPPORT
   3650     if (MHD_DIGEST_AUTH_ALGO3_MD5 == s_algo)
   3651       buf_size += MHD_STATICSTR_LEN_ (_MHD_MD5_TOKEN);
   3652     else
   3653 #endif /* MHD_MD5_SUPPORT */
   3654 #ifdef MHD_SHA256_SUPPORT
   3655     if (MHD_DIGEST_AUTH_ALGO3_SHA256 == s_algo)
   3656       buf_size += MHD_STATICSTR_LEN_ (_MHD_SHA256_TOKEN);
   3657     else
   3658 #endif /* MHD_SHA256_SUPPORT */
   3659 #ifdef MHD_SHA512_256_SUPPORT
   3660     if (MHD_DIGEST_AUTH_ALGO3_SHA512_256 == s_algo)
   3661       buf_size += MHD_STATICSTR_LEN_ (_MHD_SHA512_256_TOKEN);
   3662     else
   3663 #endif /* MHD_SHA512_256_SUPPORT */
   3664     mhd_assert (0);
   3665   }
   3666   /* 'nonce="xxxx", ' */
   3667   buf_size += MHD_STATICSTR_LEN_ (prefix_nonce) + 3; /* 3 for '", ' */
   3668   buf_size += NONCE_STD_LEN (digest_get_size (da)); /* Escaping not needed */
   3669   /* 'opaque="xxxx", ' */
   3670   if (NULL != opaque)
   3671   {
   3672     buf_size += MHD_STATICSTR_LEN_ (prefix_opaque) + 3; /* 3 for '", ' */
   3673     opaque_len = strlen (opaque);
   3674     if ((NULL != memchr (opaque, '\r', opaque_len)) ||
   3675         (NULL != memchr (opaque, '\n', opaque_len)))
   3676       return MHD_NO;
   3677 
   3678     buf_size += opaque_len * 2; /* Quoting may double the size */
   3679   }
   3680   else
   3681     opaque_len = 0;
   3682   /* 'domain="xxxx", ' */
   3683   if (NULL != domain)
   3684   {
   3685     buf_size += MHD_STATICSTR_LEN_ (prefix_domain) + 3; /* 3 for '", ' */
   3686     domain_len = strlen (domain);
   3687     if ((NULL != memchr (domain, '\r', domain_len)) ||
   3688         (NULL != memchr (domain, '\n', domain_len)))
   3689       return MHD_NO;
   3690 
   3691     buf_size += domain_len * 2; /* Quoting may double the size */
   3692   }
   3693   else
   3694     domain_len = 0;
   3695   /* 'charset=UTF-8' */
   3696   if (MHD_NO != prefer_utf8)
   3697     buf_size += MHD_STATICSTR_LEN_ (str_charset) + 2; /* 2 for ', ' */
   3698   /* 'userhash=true' */
   3699   if (MHD_NO != userhash_support)
   3700     buf_size += MHD_STATICSTR_LEN_ (str_userhash) + 2; /* 2 for ', ' */
   3701   /* 'stale=true' */
   3702   if (MHD_NO != signal_stale)
   3703     buf_size += MHD_STATICSTR_LEN_ (str_stale) + 2; /* 2 for ', ' */
   3704 
   3705   /* The calculated length is for string ended with ", ". One character will
   3706    * be used for zero-termination, the last one will not be used. */
   3707 
   3708   /* Allocate the buffer */
   3709   buf = malloc (buf_size);
   3710   if (NULL == buf)
   3711     return MHD_NO;
   3712   *buf_ptr = buf;
   3713 
   3714   /* Build the challenge string */
   3715   p = 0;
   3716   /* 'Digest: ' */
   3717   memcpy (buf + p, _MHD_AUTH_DIGEST_BASE,
   3718           MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE));
   3719   p += MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE);
   3720   buf[p++] = ' ';
   3721   /* 'realm="xxxx", ' */
   3722   memcpy (buf + p, prefix_realm,
   3723           MHD_STATICSTR_LEN_ (prefix_realm));
   3724   p += MHD_STATICSTR_LEN_ (prefix_realm);
   3725   mhd_assert ((buf_size - p) >= (realm_len * 2));
   3726   if (1)
   3727   {
   3728     size_t quoted_size;
   3729     quoted_size = MHD_str_quote (realm, realm_len, buf + p, buf_size - p);
   3730     if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < quoted_size)
   3731     {
   3732 #ifdef HAVE_MESSAGES
   3733       MHD_DLOG (connection->daemon,
   3734                 _ ("The 'realm' is too large after 'quoting'.\n"));
   3735 #endif /* HAVE_MESSAGES */
   3736       return MHD_NO;
   3737     }
   3738     p += quoted_size;
   3739   }
   3740   buf[p++] = '\"';
   3741   buf[p++] = ',';
   3742   buf[p++] = ' ';
   3743   /* 'qop="xxxx", ' */
   3744   if (MHD_DIGEST_AUTH_MULT_QOP_NONE != mqop)
   3745   {
   3746     memcpy (buf + p, prefix_qop,
   3747             MHD_STATICSTR_LEN_ (prefix_qop));
   3748     p += MHD_STATICSTR_LEN_ (prefix_qop);
   3749     memcpy (buf + p, MHD_TOKEN_AUTH_,
   3750             MHD_STATICSTR_LEN_ (MHD_TOKEN_AUTH_));
   3751     p += MHD_STATICSTR_LEN_ (MHD_TOKEN_AUTH_);
   3752     buf[p++] = '\"';
   3753     buf[p++] = ',';
   3754     buf[p++] = ' ';
   3755   }
   3756   /* 'algorithm="xxxx", ' */
   3757   if (((MHD_DIGEST_AUTH_MULT_QOP_NONE) != mqop) ||
   3758       (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5)))
   3759   {
   3760     memcpy (buf + p, prefix_algo,
   3761             MHD_STATICSTR_LEN_ (prefix_algo));
   3762     p += MHD_STATICSTR_LEN_ (prefix_algo);
   3763 #ifdef MHD_MD5_SUPPORT
   3764     if (MHD_DIGEST_AUTH_ALGO3_MD5 == s_algo)
   3765     {
   3766       memcpy (buf + p, _MHD_MD5_TOKEN,
   3767               MHD_STATICSTR_LEN_ (_MHD_MD5_TOKEN));
   3768       p += MHD_STATICSTR_LEN_ (_MHD_MD5_TOKEN);
   3769     }
   3770     else
   3771 #endif /* MHD_MD5_SUPPORT */
   3772 #ifdef MHD_SHA256_SUPPORT
   3773     if (MHD_DIGEST_AUTH_ALGO3_SHA256 == s_algo)
   3774     {
   3775       memcpy (buf + p, _MHD_SHA256_TOKEN,
   3776               MHD_STATICSTR_LEN_ (_MHD_SHA256_TOKEN));
   3777       p += MHD_STATICSTR_LEN_ (_MHD_SHA256_TOKEN);
   3778     }
   3779     else
   3780 #endif /* MHD_SHA256_SUPPORT */
   3781 #ifdef MHD_SHA512_256_SUPPORT
   3782     if (MHD_DIGEST_AUTH_ALGO3_SHA512_256 == s_algo)
   3783     {
   3784       memcpy (buf + p, _MHD_SHA512_256_TOKEN,
   3785               MHD_STATICSTR_LEN_ (_MHD_SHA512_256_TOKEN));
   3786       p += MHD_STATICSTR_LEN_ (_MHD_SHA512_256_TOKEN);
   3787     }
   3788     else
   3789 #endif /* MHD_SHA512_256_SUPPORT */
   3790     mhd_assert (0);
   3791     buf[p++] = ',';
   3792     buf[p++] = ' ';
   3793   }
   3794   /* 'nonce="xxxx", ' */
   3795   memcpy (buf + p, prefix_nonce,
   3796           MHD_STATICSTR_LEN_ (prefix_nonce));
   3797   p += MHD_STATICSTR_LEN_ (prefix_nonce);
   3798   mhd_assert ((buf_size - p) >= (NONCE_STD_LEN (digest_get_size (da))));
   3799   if (! calculate_add_nonce_with_retry (connection, realm, da, buf + p))
   3800   {
   3801 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   3802     if (digest_ext_error (da))
   3803     {
   3804 #ifdef HAVE_MESSAGES
   3805       MHD_DLOG (connection->daemon,
   3806                 _ ("TLS library reported hash calculation error, nonce could "
   3807                    "not be generated.\n"));
   3808 #endif /* HAVE_MESSAGES */
   3809       return MHD_NO;
   3810     }
   3811 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   3812 #ifdef HAVE_MESSAGES
   3813     MHD_DLOG (connection->daemon,
   3814               _ ("Could not register nonce. Client's requests with this "
   3815                  "nonce will be always 'stale'. Probably clients' requests "
   3816                  "are too intensive.\n"));
   3817 #endif /* HAVE_MESSAGES */
   3818     (void) 0; /* Mute compiler warning for builds without messages */
   3819   }
   3820   p += NONCE_STD_LEN (digest_get_size (da));
   3821   buf[p++] = '\"';
   3822   buf[p++] = ',';
   3823   buf[p++] = ' ';
   3824   /* 'opaque="xxxx", ' */
   3825   if (NULL != opaque)
   3826   {
   3827     memcpy (buf + p, prefix_opaque,
   3828             MHD_STATICSTR_LEN_ (prefix_opaque));
   3829     p += MHD_STATICSTR_LEN_ (prefix_opaque);
   3830     mhd_assert ((buf_size - p) >= (opaque_len * 2));
   3831     p += MHD_str_quote (opaque, opaque_len, buf + p, buf_size - p);
   3832     buf[p++] = '\"';
   3833     buf[p++] = ',';
   3834     buf[p++] = ' ';
   3835   }
   3836   /* 'domain="xxxx", ' */
   3837   if (NULL != domain)
   3838   {
   3839     memcpy (buf + p, prefix_domain,
   3840             MHD_STATICSTR_LEN_ (prefix_domain));
   3841     p += MHD_STATICSTR_LEN_ (prefix_domain);
   3842     mhd_assert ((buf_size - p) >= (domain_len * 2));
   3843     p += MHD_str_quote (domain, domain_len, buf + p, buf_size - p);
   3844     buf[p++] = '\"';
   3845     buf[p++] = ',';
   3846     buf[p++] = ' ';
   3847   }
   3848   /* 'charset=UTF-8' */
   3849   if (MHD_NO != prefer_utf8)
   3850   {
   3851     memcpy (buf + p, str_charset,
   3852             MHD_STATICSTR_LEN_ (str_charset));
   3853     p += MHD_STATICSTR_LEN_ (str_charset);
   3854     buf[p++] = ',';
   3855     buf[p++] = ' ';
   3856   }
   3857   /* 'userhash=true' */
   3858   if (MHD_NO != userhash_support)
   3859   {
   3860     memcpy (buf + p, str_userhash,
   3861             MHD_STATICSTR_LEN_ (str_userhash));
   3862     p += MHD_STATICSTR_LEN_ (str_userhash);
   3863     buf[p++] = ',';
   3864     buf[p++] = ' ';
   3865   }
   3866   /* 'stale=true' */
   3867   if (MHD_NO != signal_stale)
   3868   {
   3869     memcpy (buf + p, str_stale,
   3870             MHD_STATICSTR_LEN_ (str_stale));
   3871     p += MHD_STATICSTR_LEN_ (str_stale);
   3872     buf[p++] = ',';
   3873     buf[p++] = ' ';
   3874   }
   3875   mhd_assert (buf_size >= p);
   3876   /* The built string ends with ", ". Replace comma with zero-termination. */
   3877   --p;
   3878   buf[--p] = 0;
   3879 
   3880   hdr_name = malloc (MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_WWW_AUTHENTICATE) + 1);
   3881   if (NULL != hdr_name)
   3882   {
   3883     memcpy (hdr_name, MHD_HTTP_HEADER_WWW_AUTHENTICATE,
   3884             MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_WWW_AUTHENTICATE) + 1);
   3885     if (MHD_add_response_entry_no_alloc_ (response, MHD_HEADER_KIND,
   3886                                           hdr_name,
   3887                                           MHD_STATICSTR_LEN_ ( \
   3888                                             MHD_HTTP_HEADER_WWW_AUTHENTICATE),
   3889                                           buf, p))
   3890     {
   3891       *buf_ptr = NULL; /* The buffer will be free()ed when the response is destroyed */
   3892       return MHD_queue_response (connection, MHD_HTTP_UNAUTHORIZED, response);
   3893     }
   3894 #ifdef HAVE_MESSAGES
   3895     else
   3896     {
   3897       MHD_DLOG (connection->daemon,
   3898                 _ ("Failed to add Digest auth header.\n"));
   3899     }
   3900 #endif /* HAVE_MESSAGES */
   3901     free (hdr_name);
   3902   }
   3903   return MHD_NO;
   3904 }
   3905 
   3906 
   3907 /**
   3908  * Queues a response to request authentication from the client
   3909  *
   3910  * This function modifies provided @a response. The @a response must not be
   3911  * reused and should be destroyed (by #MHD_destroy_response()) after call of
   3912  * this function.
   3913  *
   3914  * If @a mqop allows both RFC 2069 (MHD_DIGEST_AUTH_QOP_NONE) and QOP with
   3915  * value, then response is formed like if MHD_DIGEST_AUTH_QOP_NONE bit was
   3916  * not set, because such response should be backward-compatible with RFC 2069.
   3917  *
   3918  * If @a mqop allows only MHD_DIGEST_AUTH_MULT_QOP_NONE, then the response is
   3919  * formed in strict accordance with RFC 2069 (no 'qop', no 'userhash', no
   3920  * 'charset'). For better compatibility with clients, it is recommended (but
   3921  * not required) to set @a domain to NULL in this mode.
   3922  *
   3923  * @param connection the MHD connection structure
   3924  * @param realm the realm presented to the client
   3925  * @param opaque the string for opaque value, can be NULL, but NULL is
   3926  *               not recommended for better compatibility with clients;
   3927  *               the recommended format is hex or Base64 encoded string
   3928  * @param domain the optional space-separated list of URIs for which the
   3929  *               same authorisation could be used, URIs can be in form
   3930  *               "path-absolute" (the path for the same host with initial slash)
   3931  *               or in form "absolute-URI" (the full path with protocol), in
   3932  *               any case client may assume that URI is in the same "protection
   3933  *               space" if it starts with any of values specified here;
   3934  *               could be NULL (clients typically assume that the same
   3935  *               credentials could be used for any URI on the same host);
   3936  *               this list provides information for the client only and does
   3937  *               not actually restrict anything on the server side
   3938  * @param response the reply to send; should contain the "access denied"
   3939  *                 body;
   3940  *                 note: this function sets the "WWW Authenticate" header and
   3941  *                 the caller should not set this header;
   3942  *                 the NULL is tolerated
   3943  * @param signal_stale if set to #MHD_YES then indication of stale nonce used in
   3944  *                     the client's request is signalled by adding 'stale=true'
   3945  *                     to the authentication header, this instructs the client
   3946  *                     to retry immediately with the new nonce and the same
   3947  *                     credentials, without asking user for the new password
   3948  * @param mqop the QOP to use
   3949  * @param malgo3 digest algorithm to use; if several algorithms are allowed
   3950  *               then MD5 is preferred (currently, may be changed in next
   3951  *               versions)
   3952  * @param userhash_support if set to non-zero value (#MHD_YES) then support of
   3953  *                         userhash is indicated, allowing client to provide
   3954  *                         hash("username:realm") instead of the username in
   3955  *                         clear text;
   3956  *                         note that clients are allowed to provide the username
   3957  *                         in cleartext even if this parameter set to non-zero;
   3958  *                         when userhash is used, application must be ready to
   3959  *                         identify users by provided userhash value instead of
   3960  *                         username; see #MHD_digest_auth_calc_userhash() and
   3961  *                         #MHD_digest_auth_calc_userhash_hex()
   3962  * @param prefer_utf8 if not set to #MHD_NO, parameter 'charset=UTF-8' is
   3963  *                    added, indicating for the client that UTF-8 encoding for
   3964  *                    the username is preferred
   3965  * @return #MHD_YES on success, #MHD_NO otherwise
   3966  * @note Available since #MHD_VERSION 0x00097701
   3967  * @ingroup authentication
   3968  */
   3969 _MHD_EXTERN enum MHD_Result
   3970 MHD_queue_auth_required_response3 (struct MHD_Connection *connection,
   3971                                    const char *realm,
   3972                                    const char *opaque,
   3973                                    const char *domain,
   3974                                    struct MHD_Response *response,
   3975                                    int signal_stale,
   3976                                    enum MHD_DigestAuthMultiQOP mqop,
   3977                                    enum MHD_DigestAuthMultiAlgo3 malgo3,
   3978                                    int userhash_support,
   3979                                    int prefer_utf8)
   3980 {
   3981   struct DigestAlgorithm da;
   3982   char *buf_ptr;
   3983   enum MHD_Result ret;
   3984 
   3985   buf_ptr = NULL;
   3986   digest_setup_zero (&da);
   3987   ret = queue_auth_required_response3_inner (connection,
   3988                                              realm,
   3989                                              opaque,
   3990                                              domain,
   3991                                              response,
   3992                                              signal_stale,
   3993                                              mqop,
   3994                                              malgo3,
   3995                                              userhash_support,
   3996                                              prefer_utf8,
   3997                                              &buf_ptr,
   3998                                              &da);
   3999   digest_deinit (&da);
   4000   if (NULL != buf_ptr)
   4001     free (buf_ptr);
   4002   return ret;
   4003 }
   4004 
   4005 
   4006 /**
   4007  * Queues a response to request authentication from the client
   4008  *
   4009  * @param connection The MHD connection structure
   4010  * @param realm the realm presented to the client
   4011  * @param opaque string to user for opaque value
   4012  * @param response reply to send; should contain the "access denied"
   4013  *        body; note that this function will set the "WWW Authenticate"
   4014  *        header and that the caller should not do this; the NULL is tolerated
   4015  * @param signal_stale #MHD_YES if the nonce is stale to add
   4016  *        'stale=true' to the authentication header
   4017  * @param algo digest algorithm to use
   4018  * @return #MHD_YES on success, #MHD_NO otherwise
   4019  * @note Available since #MHD_VERSION 0x00096200
   4020  * @ingroup authentication
   4021  */
   4022 _MHD_EXTERN enum MHD_Result
   4023 MHD_queue_auth_fail_response2 (struct MHD_Connection *connection,
   4024                                const char *realm,
   4025                                const char *opaque,
   4026                                struct MHD_Response *response,
   4027                                int signal_stale,
   4028                                enum MHD_DigestAuthAlgorithm algo)
   4029 {
   4030   enum MHD_DigestAuthMultiAlgo3 algo3;
   4031 
   4032   if (MHD_DIGEST_ALG_MD5 == algo)
   4033     algo3 = MHD_DIGEST_AUTH_MULT_ALGO3_MD5;
   4034   else if (MHD_DIGEST_ALG_SHA256 == algo)
   4035     algo3 = MHD_DIGEST_AUTH_MULT_ALGO3_SHA256;
   4036   else if (MHD_DIGEST_ALG_AUTO == algo)
   4037     algo3 = MHD_DIGEST_AUTH_MULT_ALGO3_ANY_NON_SESSION;
   4038   else
   4039     MHD_PANIC (_ ("Wrong algo value.\n")); /* API violation! */
   4040 
   4041   return MHD_queue_auth_required_response3 (connection, realm, opaque,
   4042                                             NULL, response, signal_stale,
   4043                                             MHD_DIGEST_AUTH_MULT_QOP_AUTH,
   4044                                             algo3,
   4045                                             0, 0);
   4046 }
   4047 
   4048 
   4049 /**
   4050  * Queues a response to request authentication from the client.
   4051  * For now uses MD5 (for backwards-compatibility). Still, if you
   4052  * need to be sure, use #MHD_queue_auth_fail_response2().
   4053  *
   4054  * @param connection The MHD connection structure
   4055  * @param realm the realm presented to the client
   4056  * @param opaque string to user for opaque value
   4057  * @param response reply to send; should contain the "access denied"
   4058  *        body; note that this function will set the "WWW Authenticate"
   4059  *        header and that the caller should not do this; the NULL is tolerated
   4060  * @param signal_stale #MHD_YES if the nonce is stale to add
   4061  *        'stale=true' to the authentication header
   4062  * @return #MHD_YES on success, #MHD_NO otherwise
   4063  * @ingroup authentication
   4064  * @deprecated use MHD_queue_auth_fail_response2()
   4065  */
   4066 _MHD_EXTERN enum MHD_Result
   4067 MHD_queue_auth_fail_response (struct MHD_Connection *connection,
   4068                               const char *realm,
   4069                               const char *opaque,
   4070                               struct MHD_Response *response,
   4071                               int signal_stale)
   4072 {
   4073   return MHD_queue_auth_fail_response2 (connection,
   4074                                         realm,
   4075                                         opaque,
   4076                                         response,
   4077                                         signal_stale,
   4078                                         MHD_DIGEST_ALG_MD5);
   4079 }
   4080 
   4081 
   4082 /* end of digestauth.c */