libmicrohttpd

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

digestauth.c (142731B)


      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   if (NULL == info)
   1295     return NULL;
   1296   unif_buf_ptr = (uint8_t *) (info + 1);
   1297   unif_buf_used = 0;
   1298 
   1299   info->algo3 = params->algo3;
   1300 
   1301   if ( (MHD_DIGEST_AUTH_UNAME_TYPE_MISSING != uname_type) &&
   1302        (MHD_DIGEST_AUTH_UNAME_TYPE_INVALID != uname_type) )
   1303     unif_buf_used +=
   1304       get_rq_uname (params, uname_type,
   1305                     (struct MHD_DigestAuthUsernameInfo *) info,
   1306                     unif_buf_ptr + unif_buf_used,
   1307                     unif_buf_size - unif_buf_used);
   1308   else
   1309     info->uname_type = uname_type;
   1310 
   1311   if (NULL != params->opaque.value.str)
   1312   {
   1313     info->opaque = (char *) (unif_buf_ptr + unif_buf_used);
   1314     info->opaque_len = get_rq_param_unquoted_copy_z (&params->opaque,
   1315                                                      info->opaque);
   1316     unif_buf_used += info->opaque_len + 1;
   1317   }
   1318   if (NULL != params->realm.value.str)
   1319   {
   1320     info->realm = (char *) (unif_buf_ptr + unif_buf_used);
   1321     info->realm_len = get_rq_param_unquoted_copy_z (&params->realm,
   1322                                                     info->realm);
   1323     unif_buf_used += info->realm_len + 1;
   1324   }
   1325 
   1326   mhd_assert (unif_buf_size >= unif_buf_used);
   1327 
   1328   info->qop = params->qop;
   1329 
   1330   if (NULL != params->cnonce.value.str)
   1331     info->cnonce_len = params->cnonce.value.len;
   1332   else
   1333     info->cnonce_len = 0;
   1334 
   1335   nc_res = get_rq_nc (params, &info->nc);
   1336   if (MHD_GET_RQ_NC_VALID != nc_res)
   1337     info->nc = MHD_DIGEST_AUTH_INVALID_NC_VALUE;
   1338 
   1339   return info;
   1340 }
   1341 
   1342 
   1343 /**
   1344  * Get the username from Digest Authorization client's header.
   1345  *
   1346  * @param connection The MHD connection structure
   1347  * @return NULL if no valid Digest Authorization header is used in the request,
   1348  *         or no username parameter is present in the header, or username is
   1349  *         provided incorrectly by client (see description for
   1350  *         #MHD_DIGEST_AUTH_UNAME_TYPE_INVALID);
   1351  *         a pointer structure with information if the valid request header
   1352  *         found, free using #MHD_free().
   1353  * @sa MHD_digest_auth_get_request_info3() provides more complete information
   1354  * @note Available since #MHD_VERSION 0x00097701
   1355  * @ingroup authentication
   1356  */
   1357 _MHD_EXTERN struct MHD_DigestAuthUsernameInfo *
   1358 MHD_digest_auth_get_username3 (struct MHD_Connection *connection)
   1359 {
   1360   const struct MHD_RqDAuth *params;
   1361   struct MHD_DigestAuthUsernameInfo *uname_info;
   1362   enum MHD_DigestAuthUsernameType uname_type;
   1363   size_t unif_buf_size;
   1364   uint8_t *unif_buf_ptr;
   1365   size_t unif_buf_used;
   1366 
   1367   params = MHD_get_rq_dauth_params_ (connection);
   1368   if (NULL == params)
   1369     return NULL;
   1370 
   1371   uname_type = get_rq_uname_type (params);
   1372   if ( (MHD_DIGEST_AUTH_UNAME_TYPE_MISSING == uname_type) ||
   1373        (MHD_DIGEST_AUTH_UNAME_TYPE_INVALID == uname_type) )
   1374     return NULL;
   1375 
   1376   unif_buf_size = get_rq_unames_size (params, uname_type);
   1377 
   1378   uname_info = (struct MHD_DigestAuthUsernameInfo *)
   1379                MHD_calloc_ (1, (sizeof(struct MHD_DigestAuthUsernameInfo))
   1380                             + unif_buf_size);
   1381   if (NULL == uname_info)
   1382     return NULL;
   1383   unif_buf_ptr = (uint8_t *) (uname_info + 1);
   1384   unif_buf_used = get_rq_uname (params, uname_type, uname_info, unif_buf_ptr,
   1385                                 unif_buf_size);
   1386   mhd_assert (unif_buf_size >= unif_buf_used);
   1387   (void) unif_buf_used; /* Mute compiler warning on non-debug builds */
   1388   mhd_assert (MHD_DIGEST_AUTH_UNAME_TYPE_MISSING != uname_info->uname_type);
   1389 
   1390   if (MHD_DIGEST_AUTH_UNAME_TYPE_INVALID == uname_info->uname_type)
   1391   {
   1392     free (uname_info);
   1393     return NULL;
   1394   }
   1395   mhd_assert (uname_type == uname_info->uname_type);
   1396   uname_info->algo3 = params->algo3;
   1397 
   1398   return uname_info;
   1399 }
   1400 
   1401 
   1402 /**
   1403  * Get the username from the authorization header sent by the client
   1404  *
   1405  * This function supports username in standard and extended notations.
   1406  * "userhash" is not supported by this function.
   1407  *
   1408  * @param connection The MHD connection structure
   1409  * @return NULL if no username could be found, username provided as
   1410  *         "userhash", extended notation broken or memory allocation error
   1411  *         occurs;
   1412  *         a pointer to the username if found, free using #MHD_free().
   1413  * @warning Returned value must be freed by #MHD_free().
   1414  * @sa #MHD_digest_auth_get_username3()
   1415  * @ingroup authentication
   1416  */
   1417 _MHD_EXTERN char *
   1418 MHD_digest_auth_get_username (struct MHD_Connection *connection)
   1419 {
   1420   const struct MHD_RqDAuth *params;
   1421   char *username;
   1422   size_t buf_size;
   1423   enum MHD_DigestAuthUsernameType uname_type;
   1424 
   1425   params = MHD_get_rq_dauth_params_ (connection);
   1426   if (NULL == params)
   1427     return NULL;
   1428 
   1429   uname_type = get_rq_uname_type (params);
   1430 
   1431   if ( (MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD != uname_type) &&
   1432        (MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED != uname_type) )
   1433     return NULL;
   1434 
   1435   buf_size = get_rq_unames_size (params, uname_type);
   1436 
   1437   mhd_assert (0 != buf_size);
   1438 
   1439   username = (char *) MHD_calloc_ (1, buf_size);
   1440   if (NULL == username)
   1441     return NULL;
   1442 
   1443   if (1)
   1444   {
   1445     struct MHD_DigestAuthUsernameInfo uname_strct;
   1446     size_t used;
   1447 
   1448     memset (&uname_strct, 0, sizeof(uname_strct));
   1449 
   1450     used = get_rq_uname (params, uname_type, &uname_strct,
   1451                          (uint8_t *) username, buf_size);
   1452     if (uname_type != uname_strct.uname_type)
   1453     { /* Broken encoding for extended notation */
   1454       free (username);
   1455       return NULL;
   1456     }
   1457     (void) used; /* Mute compiler warning for non-debug builds */
   1458     mhd_assert (buf_size >= used);
   1459   }
   1460 
   1461   return username;
   1462 }
   1463 
   1464 
   1465 /**
   1466  * Calculate the server nonce so that it mitigates replay attacks
   1467  * The current format of the nonce is ...
   1468  * H(timestamp:random data:various parameters) + Hex(timestamp)
   1469  *
   1470  * @param nonce_time The amount of time in seconds for a nonce to be invalid
   1471  * @param mthd_e HTTP method as enum value
   1472  * @param method HTTP method as a string
   1473  * @param rnd the pointer to a character array for the random seed
   1474  * @param rnd_size The size of the random seed array @a rnd
   1475  * @param saddr the pointer to the socket address structure
   1476  * @param saddr_size the size of the socket address structure @a saddr
   1477  * @param uri the HTTP URI (in MHD, without the arguments ("?k=v")
   1478  * @param uri_len the length of the @a uri
   1479  * @param first_header the pointer to the first request's header
   1480  * @param realm A string of characters that describes the realm of auth.
   1481  * @param realm_len the length of the @a realm.
   1482  * @param bind_options the nonce bind options (#MHD_DAuthBindNonce values).
   1483  * @param da digest algorithm to use
   1484  * @param[out] nonce the pointer to a character array for the nonce to put in,
   1485  *                   must provide NONCE_STD_LEN(digest_get_size(da)) bytes,
   1486  *                   result is NOT zero-terminated
   1487  */
   1488 static void
   1489 calculate_nonce (uint64_t nonce_time,
   1490                  enum MHD_HTTP_Method mthd_e,
   1491                  const char *method,
   1492                  const char *rnd,
   1493                  size_t rnd_size,
   1494                  const struct sockaddr_storage *saddr,
   1495                  size_t saddr_size,
   1496                  const char *uri,
   1497                  size_t uri_len,
   1498                  const struct MHD_HTTP_Req_Header *first_header,
   1499                  const char *realm,
   1500                  size_t realm_len,
   1501                  unsigned int bind_options,
   1502                  struct DigestAlgorithm *da,
   1503                  char *nonce)
   1504 {
   1505   mhd_assert (! da->hashing);
   1506   if (1)
   1507   {
   1508     /* Add the timestamp to the hash calculation */
   1509     uint8_t timestamp[TIMESTAMP_BIN_SIZE];
   1510     /* If the nonce_time is milliseconds, then the same 48 bit value will repeat
   1511      * every 8 919 years, which is more than enough to mitigate a replay attack */
   1512 #if TIMESTAMP_BIN_SIZE != 6
   1513 #error The code needs to be updated here
   1514 #endif
   1515     timestamp[0] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 0)));
   1516     timestamp[1] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 1)));
   1517     timestamp[2] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 2)));
   1518     timestamp[3] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 3)));
   1519     timestamp[4] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 4)));
   1520     timestamp[5] = (uint8_t) (nonce_time >> (8 * (TIMESTAMP_BIN_SIZE - 1 - 5)));
   1521     MHD_bin_to_hex (timestamp,
   1522                     sizeof (timestamp),
   1523                     nonce + digest_get_size (da) * 2);
   1524     digest_update (da,
   1525                    timestamp,
   1526                    sizeof (timestamp));
   1527   }
   1528   if (rnd_size > 0)
   1529   {
   1530     /* Add the unique random value to the hash calculation */
   1531     digest_update_with_colon (da);
   1532     digest_update (da,
   1533                    rnd,
   1534                    rnd_size);
   1535   }
   1536   if ( (MHD_DAUTH_BIND_NONCE_NONE == bind_options) &&
   1537        (0 != saddr_size) )
   1538   {
   1539     /* Add full client address including source port to make unique nonces
   1540      * for requests received exactly at the same time */
   1541     digest_update_with_colon (da);
   1542     digest_update (da,
   1543                    saddr,
   1544                    saddr_size);
   1545   }
   1546   if ( (0 != (bind_options & MHD_DAUTH_BIND_NONCE_CLIENT_IP)) &&
   1547        (0 != saddr_size) )
   1548   {
   1549     /* Add the client's IP address to the hash calculation */
   1550     digest_update_with_colon (da);
   1551     if (AF_INET == saddr->ss_family)
   1552       digest_update (da,
   1553                      &((const struct sockaddr_in *) saddr)->sin_addr,
   1554                      sizeof(((const struct sockaddr_in *) saddr)->sin_addr));
   1555 #ifdef HAVE_INET6
   1556     else if (AF_INET6 == saddr->ss_family)
   1557       digest_update (da,
   1558                      &((const struct sockaddr_in6 *) saddr)->sin6_addr,
   1559                      sizeof(((const struct sockaddr_in6 *) saddr)->sin6_addr));
   1560 #endif /* HAVE_INET6 */
   1561   }
   1562   if ( (MHD_DAUTH_BIND_NONCE_NONE == bind_options) ||
   1563        (0 != (bind_options & MHD_DAUTH_BIND_NONCE_URI)))
   1564   {
   1565     /* Add the request method to the hash calculation */
   1566     digest_update_with_colon (da);
   1567     if (MHD_HTTP_MTHD_OTHER != mthd_e)
   1568     {
   1569       uint8_t mthd_for_hash;
   1570       if (MHD_HTTP_MTHD_HEAD != mthd_e)
   1571         mthd_for_hash = (uint8_t) mthd_e;
   1572       else /* Treat HEAD method in the same way as GET method */
   1573         mthd_for_hash = (uint8_t) MHD_HTTP_MTHD_GET;
   1574       digest_update (da,
   1575                      &mthd_for_hash,
   1576                      sizeof(mthd_for_hash));
   1577     }
   1578     else
   1579       digest_update_str (da, method);
   1580   }
   1581 
   1582   if (0 != (bind_options & MHD_DAUTH_BIND_NONCE_URI))
   1583   {
   1584     /* Add the request URI to the hash calculation */
   1585     digest_update_with_colon (da);
   1586 
   1587     digest_update (da,
   1588                    uri,
   1589                    uri_len);
   1590   }
   1591   if (0 != (bind_options & MHD_DAUTH_BIND_NONCE_URI_PARAMS))
   1592   {
   1593     /* Add the request URI parameters to the hash calculation */
   1594     const struct MHD_HTTP_Req_Header *h;
   1595 
   1596     digest_update_with_colon (da);
   1597     for (h = first_header; NULL != h; h = h->next)
   1598     {
   1599       if (MHD_GET_ARGUMENT_KIND != h->kind)
   1600         continue;
   1601       digest_update (da, "\0", 2);
   1602       if (0 != h->header_size)
   1603         digest_update (da, h->header, h->header_size);
   1604       digest_update (da, "", 1);
   1605       if (0 != h->value_size)
   1606         digest_update (da, h->value, h->value_size);
   1607     }
   1608   }
   1609   if ( (MHD_DAUTH_BIND_NONCE_NONE == bind_options) ||
   1610        (0 != (bind_options & MHD_DAUTH_BIND_NONCE_REALM)))
   1611   {
   1612     /* Add the realm to the hash calculation */
   1613     digest_update_with_colon (da);
   1614     digest_update (da,
   1615                    realm,
   1616                    realm_len);
   1617   }
   1618   if (1)
   1619   {
   1620     uint8_t hash[MAX_DIGEST];
   1621     digest_calc_hash (da, hash);
   1622     MHD_bin_to_hex (hash,
   1623                     digest_get_size (da),
   1624                     nonce);
   1625   }
   1626 }
   1627 
   1628 
   1629 /**
   1630  * Check whether it is possible to use slot in nonce-nc map array.
   1631  *
   1632  * Should be called with mutex held to avoid external modification of
   1633  * the slot data.
   1634  *
   1635  * @param nn the pointer to the nonce-nc slot
   1636  * @param now the current time
   1637  * @param new_nonce the new nonce supposed to be stored in this slot,
   1638  *                  zero-terminated
   1639  * @param new_nonce_len the length of the @a new_nonce in chars, not including
   1640  *                      the terminating zero.
   1641  * @return true if the slot can be used to store the new nonce,
   1642  *         false otherwise.
   1643  */
   1644 static bool
   1645 is_slot_available (const struct MHD_NonceNc *const nn,
   1646                    const uint64_t now,
   1647                    const char *const new_nonce,
   1648                    size_t new_nonce_len)
   1649 {
   1650   uint64_t timestamp;
   1651   bool timestamp_valid;
   1652   mhd_assert (new_nonce_len <= NONCE_STD_LEN (MAX_DIGEST));
   1653   mhd_assert (NONCE_STD_LEN (MAX_DIGEST) <= MAX_DIGEST_NONCE_LENGTH);
   1654   if (0 == nn->nonce[0])
   1655     return true; /* The slot is empty */
   1656 
   1657   if (0 == memcmp (nn->nonce, new_nonce, new_nonce_len))
   1658   {
   1659     /* The slot has the same nonce already. This nonce cannot be registered
   1660      * again as it would just clear 'nc' usage history. */
   1661     return false;
   1662   }
   1663 
   1664   if (0 != nn->nc)
   1665     return true; /* Client already used the nonce in this slot at least
   1666                     one time, re-use the slot */
   1667 
   1668   /* The nonce must be zero-terminated */
   1669   mhd_assert (0 == nn->nonce[sizeof(nn->nonce) - 1]);
   1670   if (0 != nn->nonce[sizeof(nn->nonce) - 1])
   1671     return true; /* Wrong nonce format in the slot */
   1672 
   1673   timestamp_valid = get_nonce_timestamp (nn->nonce, 0, &timestamp);
   1674   mhd_assert (timestamp_valid);
   1675   if (! timestamp_valid)
   1676     return true; /* Invalid timestamp in nonce-nc, should not be possible */
   1677 
   1678   if ((REUSE_TIMEOUT * 1000) < TRIM_TO_TIMESTAMP (now - timestamp))
   1679     return true;
   1680 
   1681   return false;
   1682 }
   1683 
   1684 
   1685 /**
   1686  * Calculate the server nonce so that it mitigates replay attacks and add
   1687  * the new nonce to the nonce-nc map array.
   1688  *
   1689  * @param connection the MHD connection structure
   1690  * @param timestamp the current timestamp
   1691  * @param realm the string of characters that describes the realm of auth
   1692  * @param realm_len the length of the @a realm
   1693  * @param da the digest algorithm to use
   1694  * @param[out] nonce the pointer to a character array for the nonce to put in,
   1695  *                   must provide NONCE_STD_LEN(digest_get_size(da)) bytes,
   1696  *                   result is NOT zero-terminated
   1697  * @return true if the new nonce has been added to the nonce-nc map array,
   1698  *         false otherwise.
   1699  */
   1700 static bool
   1701 calculate_add_nonce (struct MHD_Connection *const connection,
   1702                      uint64_t timestamp,
   1703                      const char *realm,
   1704                      size_t realm_len,
   1705                      struct DigestAlgorithm *da,
   1706                      char *nonce)
   1707 {
   1708   struct MHD_Daemon *const daemon = MHD_get_master (connection->daemon);
   1709   struct MHD_NonceNc *nn;
   1710   const size_t nonce_size = NONCE_STD_LEN (digest_get_size (da));
   1711   bool ret;
   1712 
   1713   mhd_assert (! da->hashing);
   1714   mhd_assert (MAX_DIGEST_NONCE_LENGTH >= nonce_size);
   1715   mhd_assert (0 != nonce_size);
   1716 
   1717   calculate_nonce (timestamp,
   1718                    connection->rq.http_mthd,
   1719                    connection->rq.method,
   1720                    daemon->digest_auth_random,
   1721                    daemon->digest_auth_rand_size,
   1722                    connection->addr,
   1723                    (size_t) connection->addr_len,
   1724                    connection->rq.url,
   1725                    connection->rq.url_len,
   1726                    connection->rq.headers_received,
   1727                    realm,
   1728                    realm_len,
   1729                    daemon->dauth_bind_type,
   1730                    da,
   1731                    nonce);
   1732 
   1733 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   1734   if (digest_ext_error (da))
   1735     return false;
   1736 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   1737 
   1738   if (0 == daemon->nonce_nc_size)
   1739     return false;
   1740 
   1741   /* Sanity check for values */
   1742   mhd_assert (MAX_DIGEST_NONCE_LENGTH == NONCE_STD_LEN (MAX_DIGEST));
   1743 
   1744   nn = daemon->nnc + get_nonce_nc_idx (daemon->nonce_nc_size,
   1745                                        nonce,
   1746                                        nonce_size);
   1747 
   1748   MHD_mutex_lock_chk_ (&daemon->nnc_lock);
   1749   if (is_slot_available (nn, timestamp, nonce, nonce_size))
   1750   {
   1751     memcpy (nn->nonce,
   1752             nonce,
   1753             nonce_size);
   1754     nn->nonce[nonce_size] = 0;  /* With terminating zero */
   1755     nn->nc = 0;
   1756     nn->nmask = 0;
   1757     ret = true;
   1758   }
   1759   else
   1760     ret = false;
   1761   MHD_mutex_unlock_chk_ (&daemon->nnc_lock);
   1762 
   1763   return ret;
   1764 }
   1765 
   1766 
   1767 MHD_DATA_TRUNCATION_RUNTIME_CHECK_DISABLE_
   1768 
   1769 /**
   1770  * Calculate the server nonce so that it mitigates replay attacks and add
   1771  * the new nonce to the nonce-nc map array.
   1772  *
   1773  * @param connection the MHD connection structure
   1774  * @param realm A string of characters that describes the realm of auth.
   1775  * @param da digest algorithm to use
   1776  * @param[out] nonce the pointer to a character array for the nonce to put in,
   1777  *                   must provide NONCE_STD_LEN(digest_get_size(da)) bytes,
   1778  *                   result is NOT zero-terminated
   1779  */
   1780 static bool
   1781 calculate_add_nonce_with_retry (struct MHD_Connection *const connection,
   1782                                 const char *realm,
   1783                                 struct DigestAlgorithm *da,
   1784                                 char *nonce)
   1785 {
   1786   const uint64_t timestamp1 = MHD_monotonic_msec_counter ();
   1787   const size_t realm_len = strlen (realm);
   1788   mhd_assert (! da->hashing);
   1789 
   1790 #ifdef HAVE_MESSAGES
   1791   if (0 == MHD_get_master (connection->daemon)->digest_auth_rand_size)
   1792     MHD_DLOG (connection->daemon,
   1793               _ ("Random value was not initialised by " \
   1794                  "MHD_OPTION_DIGEST_AUTH_RANDOM or " \
   1795                  "MHD_OPTION_DIGEST_AUTH_RANDOM_COPY, generated nonces " \
   1796                  "are predictable.\n"));
   1797 #endif
   1798 
   1799   if (! calculate_add_nonce (connection, timestamp1, realm, realm_len, da,
   1800                              nonce))
   1801   {
   1802     /* Either:
   1803      * 1. The same nonce was already generated. If it will be used then one
   1804      * of the clients will fail (as no initial 'nc' value could be given to
   1805      * the client, the second client which will use 'nc=00000001' will fail).
   1806      * 2. Another nonce uses the same slot, and this nonce never has been
   1807      * used by the client and this nonce is still fresh enough.
   1808      */
   1809     const size_t digest_size = digest_get_size (da);
   1810     char nonce2[NONCE_STD_LEN (MAX_DIGEST) + 1];
   1811     uint64_t timestamp2;
   1812 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   1813     if (digest_ext_error (da))
   1814       return false; /* No need to re-try */
   1815 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   1816     if (0 == MHD_get_master (connection->daemon)->nonce_nc_size)
   1817       return false; /* No need to re-try */
   1818 
   1819     timestamp2 = MHD_monotonic_msec_counter ();
   1820     if (timestamp1 == timestamp2)
   1821     {
   1822       /* The timestamps are equal, need to generate some arbitrary
   1823        * difference for nonce. */
   1824       /* As the number is needed only to differentiate clients, weak
   1825        * pseudo-random generators could be used. Seeding is not needed. */
   1826       uint64_t base1;
   1827       uint32_t base2;
   1828       uint16_t base3;
   1829       uint8_t base4;
   1830 #ifdef HAVE_RANDOM
   1831       base1 = ((uint64_t) random ()) ^ UINT64_C (0x54a5acff5be47e63);
   1832       base4 = 0xb8;
   1833 #elif defined(HAVE_RAND)
   1834       base1 = ((uint64_t) rand ()) ^ UINT64_C (0xc4bcf553b12f3965);
   1835       base4 = 0x92;
   1836 #else
   1837       /* Monotonic msec counter alone does not really help here as it is already
   1838          known that this value is not unique. */
   1839       base1 = ((uint64_t) (uintptr_t) nonce2) ^ UINT64_C (0xf2e1b21bc6c92655);
   1840       base2 = ((uint32_t) (base1 >> 32)) ^ ((uint32_t) base1);
   1841       base2 = _MHD_ROTR32 (base2, 4);
   1842       base3 = ((uint16_t) (base2 >> 16)) ^ ((uint16_t) base2);
   1843       base4 = ((uint8_t) (base3 >> 8)) ^ ((uint8_t) base3);
   1844       base1 = ((uint64_t) MHD_monotonic_msec_counter ())
   1845               ^ UINT64_C (0xccab93f72cf5b15);
   1846 #endif
   1847       base2 = ((uint32_t) (base1 >> 32)) ^ ((uint32_t) base1);
   1848       base2 = _MHD_ROTL32 (base2, (((base4 >> 4) ^ base4) % 32));
   1849       base3 = ((uint16_t) (base2 >> 16)) ^ ((uint16_t) base2);
   1850       base4 = ((uint8_t) (base3 >> 8)) ^ ((uint8_t) base3);
   1851       /* Use up to 127 ms difference */
   1852       timestamp2 -= (base4 & DAUTH_JUMPBACK_MAX);
   1853       if (timestamp1 == timestamp2)
   1854         timestamp2 -= 2; /* Fallback value */
   1855     }
   1856     digest_reset (da);
   1857     if (! calculate_add_nonce (connection, timestamp2, realm, realm_len, da,
   1858                                nonce2))
   1859     {
   1860       /* No free slot has been found. Re-tries are expensive, just use
   1861        * the generated nonce. As it is not stored in nonce-nc map array,
   1862        * the next request of the client will be recognized as valid, but 'stale'
   1863        * so client should re-try automatically. */
   1864       return false;
   1865     }
   1866     memcpy (nonce, nonce2, NONCE_STD_LEN (digest_size));
   1867   }
   1868   return true;
   1869 }
   1870 
   1871 
   1872 MHD_DATA_TRUNCATION_RUNTIME_CHECK_RESTORE_
   1873 
   1874 /**
   1875  * Calculate userdigest, return it as binary data.
   1876  *
   1877  * It is equal to H(A1) for non-session algorithms.
   1878  *
   1879  * MHD internal version.
   1880  *
   1881  * @param da the digest algorithm
   1882  * @param username the username to use
   1883  * @param username_len the length of the @a username
   1884  * @param realm the realm to use
   1885  * @param realm_len the length of the @a realm
   1886  * @param password the password, must be zero-terminated
   1887  * @param[out] ha1_bin the output buffer, must have at least
   1888  *                     #digest_get_size(da) bytes available
   1889  */
   1890 _MHD_static_inline void
   1891 calc_userdigest (struct DigestAlgorithm *da,
   1892                  const char *username, const size_t username_len,
   1893                  const char *realm, const size_t realm_len,
   1894                  const char *password,
   1895                  uint8_t *ha1_bin)
   1896 {
   1897   mhd_assert (! da->hashing);
   1898   digest_update (da, username, username_len);
   1899   digest_update_with_colon (da);
   1900   digest_update (da, realm, realm_len);
   1901   digest_update_with_colon (da);
   1902   digest_update_str (da, password);
   1903   digest_calc_hash (da, ha1_bin);
   1904 }
   1905 
   1906 
   1907 /**
   1908  * Calculate userdigest, return it as a binary data.
   1909  *
   1910  * The "userdigest" is the hash of the "username:realm:password" string.
   1911  *
   1912  * The "userdigest" can be used to avoid storing the password in clear text
   1913  * in database/files
   1914  *
   1915  * This function is designed to improve security of stored credentials,
   1916  * the "userdigest" does not improve security of the authentication process.
   1917  *
   1918  * The results can be used to store username & userdigest pairs instead of
   1919  * username & password pairs. To further improve security, application may
   1920  * store username & userhash & userdigest triplets.
   1921  *
   1922  * @param algo3 the digest algorithm
   1923  * @param username the username
   1924  * @param realm the realm
   1925  * @param password the password
   1926  * @param[out] userdigest_bin the output buffer for userdigest;
   1927  *                            if this function succeeds, then this buffer has
   1928  *                            #MHD_digest_get_hash_size(algo3) bytes of
   1929  *                            userdigest upon return
   1930  * @param bin_buf_size the size of the @a userdigest_bin buffer, must be
   1931  *                     at least #MHD_digest_get_hash_size(algo3) bytes long
   1932  * @return MHD_YES on success,
   1933  *         MHD_NO if @a userdigest_bin is too small or if @a algo3 algorithm is
   1934  *         not supported (or external error has occurred,
   1935  *         see #MHD_FEATURE_EXTERN_HASH).
   1936  * @sa #MHD_digest_auth_check_digest3()
   1937  * @note Available since #MHD_VERSION 0x00097701
   1938  * @ingroup authentication
   1939  */
   1940 _MHD_EXTERN enum MHD_Result
   1941 MHD_digest_auth_calc_userdigest (enum MHD_DigestAuthAlgo3 algo3,
   1942                                  const char *username,
   1943                                  const char *realm,
   1944                                  const char *password,
   1945                                  void *userdigest_bin,
   1946                                  size_t bin_buf_size)
   1947 {
   1948   struct DigestAlgorithm da;
   1949   enum MHD_Result ret;
   1950   if (! digest_init_one_time (&da, get_base_digest_algo (algo3)))
   1951     return MHD_NO;
   1952 
   1953   if (digest_get_size (&da) > bin_buf_size)
   1954     ret = MHD_NO;
   1955   else
   1956   {
   1957     calc_userdigest (&da,
   1958                      username,
   1959                      strlen (username),
   1960                      realm,
   1961                      strlen (realm),
   1962                      password,
   1963                      userdigest_bin);
   1964     ret = MHD_YES;
   1965 
   1966 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   1967     if (digest_ext_error (&da))
   1968       ret = MHD_NO;
   1969 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   1970   }
   1971   digest_deinit (&da);
   1972 
   1973   return ret;
   1974 }
   1975 
   1976 
   1977 /**
   1978  * Calculate userhash, return it as binary data.
   1979  *
   1980  * MHD internal version.
   1981  *
   1982  * @param da the digest algorithm
   1983  * @param username the username to use
   1984  * @param username_len the length of the @a username
   1985  * @param realm the realm to use
   1986  * @param realm_len the length of the @a realm
   1987  * @param[out] digest_bin the output buffer, must have at least
   1988  *                        #MHD_digest_get_hash_size(algo3) bytes available
   1989  */
   1990 _MHD_static_inline void
   1991 calc_userhash (struct DigestAlgorithm *da,
   1992                const char *username, const size_t username_len,
   1993                const char *realm, const size_t realm_len,
   1994                uint8_t *digest_bin)
   1995 {
   1996   mhd_assert (NULL != username);
   1997   mhd_assert (! da->hashing);
   1998   digest_update (da, username, username_len);
   1999   digest_update_with_colon (da);
   2000   digest_update (da, realm, realm_len);
   2001   digest_calc_hash (da, digest_bin);
   2002 }
   2003 
   2004 
   2005 /**
   2006  * Calculate "userhash", return it as binary data.
   2007  *
   2008  * The "userhash" is the hash of the string "username:realm".
   2009  *
   2010  * The "userhash" could be used to avoid sending username in cleartext in Digest
   2011  * Authorization client's header.
   2012  *
   2013  * Userhash is not designed to hide the username in local database or files,
   2014  * as username in cleartext is required for #MHD_digest_auth_check3() function
   2015  * to check the response, but it can be used to hide username in HTTP headers.
   2016  *
   2017  * This function could be used when the new username is added to the username
   2018  * database to save the "userhash" alongside with the username (preferably) or
   2019  * when loading list of the usernames to generate the userhash for every loaded
   2020  * username (this will cause delays at the start with the long lists).
   2021  *
   2022  * Once "userhash" is generated it could be used to identify users by clients
   2023  * with "userhash" support.
   2024  * Avoid repetitive usage of this function for the same username/realm
   2025  * combination as it will cause excessive CPU load; save and re-use the result
   2026  * instead.
   2027  *
   2028  * @param algo3 the algorithm for userhash calculations
   2029  * @param username the username
   2030  * @param realm the realm
   2031  * @param[out] userhash_bin the output buffer for userhash as binary data;
   2032  *                          if this function succeeds, then this buffer has
   2033  *                          #MHD_digest_get_hash_size(algo3) bytes of userhash
   2034  *                          upon return
   2035  * @param bin_buf_size the size of the @a userhash_bin buffer, must be
   2036  *                     at least #MHD_digest_get_hash_size(algo3) bytes long
   2037  * @return MHD_YES on success,
   2038  *         MHD_NO if @a bin_buf_size is too small or if @a algo3 algorithm is
   2039  *         not supported (or external error has occurred,
   2040  *         see #MHD_FEATURE_EXTERN_HASH)
   2041  * @sa #MHD_digest_auth_calc_userhash_hex()
   2042  * @note Available since #MHD_VERSION 0x00097701
   2043  * @ingroup authentication
   2044  */
   2045 _MHD_EXTERN enum MHD_Result
   2046 MHD_digest_auth_calc_userhash (enum MHD_DigestAuthAlgo3 algo3,
   2047                                const char *username,
   2048                                const char *realm,
   2049                                void *userhash_bin,
   2050                                size_t bin_buf_size)
   2051 {
   2052   struct DigestAlgorithm da;
   2053   enum MHD_Result ret;
   2054 
   2055   if (! digest_init_one_time (&da, get_base_digest_algo (algo3)))
   2056     return MHD_NO;
   2057   if (digest_get_size (&da) > bin_buf_size)
   2058     ret = MHD_NO;
   2059   else
   2060   {
   2061     calc_userhash (&da,
   2062                    username,
   2063                    strlen (username),
   2064                    realm,
   2065                    strlen (realm),
   2066                    userhash_bin);
   2067     ret = MHD_YES;
   2068 
   2069 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   2070     if (digest_ext_error (&da))
   2071       ret = MHD_NO;
   2072 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   2073   }
   2074   digest_deinit (&da);
   2075 
   2076   return ret;
   2077 }
   2078 
   2079 
   2080 /**
   2081  * Calculate "userhash", return it as hexadecimal string.
   2082  *
   2083  * The "userhash" is the hash of the string "username:realm".
   2084  *
   2085  * The "userhash" could be used to avoid sending username in cleartext in Digest
   2086  * Authorization client's header.
   2087  *
   2088  * Userhash is not designed to hide the username in local database or files,
   2089  * as username in cleartext is required for #MHD_digest_auth_check3() function
   2090  * to check the response, but it can be used to hide username in HTTP headers.
   2091  *
   2092  * This function could be used when the new username is added to the username
   2093  * database to save the "userhash" alongside with the username (preferably) or
   2094  * when loading list of the usernames to generate the userhash for every loaded
   2095  * username (this will cause delays at the start with the long lists).
   2096  *
   2097  * Once "userhash" is generated it could be used to identify users by clients
   2098  * with "userhash" support.
   2099  * Avoid repetitive usage of this function for the same username/realm
   2100  * combination as it will cause excessive CPU load; save and re-use the result
   2101  * instead.
   2102  *
   2103  * @param algo3 the algorithm for userhash calculations
   2104  * @param username the username
   2105  * @param realm the realm
   2106  * @param[out] userhash_hex the output buffer for userhash as hex string;
   2107  *                          if this function succeeds, then this buffer has
   2108  *                          #MHD_digest_get_hash_size(algo3)*2 chars long
   2109  *                          userhash zero-terminated string
   2110  * @param bin_buf_size the size of the @a userhash_bin buffer, must be
   2111  *                     at least #MHD_digest_get_hash_size(algo3)*2+1 chars long
   2112  * @return MHD_YES on success,
   2113  *         MHD_NO if @a bin_buf_size is too small or if @a algo3 algorithm is
   2114  *         not supported (or external error has occurred,
   2115  *         see #MHD_FEATURE_EXTERN_HASH).
   2116  * @sa #MHD_digest_auth_calc_userhash()
   2117  * @note Available since #MHD_VERSION 0x00097701
   2118  * @ingroup authentication
   2119  */
   2120 _MHD_EXTERN enum MHD_Result
   2121 MHD_digest_auth_calc_userhash_hex (enum MHD_DigestAuthAlgo3 algo3,
   2122                                    const char *username,
   2123                                    const char *realm,
   2124                                    char *userhash_hex,
   2125                                    size_t hex_buf_size)
   2126 {
   2127   uint8_t userhash_bin[MAX_DIGEST];
   2128   size_t digest_size;
   2129 
   2130   digest_size = digest_get_hash_size (algo3);
   2131   if (digest_size * 2 + 1 > hex_buf_size)
   2132     return MHD_NO;
   2133   if (MHD_NO == MHD_digest_auth_calc_userhash (algo3, username, realm,
   2134                                                userhash_bin, MAX_DIGEST))
   2135     return MHD_NO;
   2136 
   2137   MHD_bin_to_hex_z (userhash_bin, digest_size, userhash_hex);
   2138   return MHD_YES;
   2139 }
   2140 
   2141 
   2142 struct test_header_param
   2143 {
   2144   struct MHD_Connection *connection;
   2145   size_t num_headers;
   2146 };
   2147 
   2148 /**
   2149  * Test if the given key-value pair is in the headers for the
   2150  * given connection.
   2151  *
   2152  * @param cls the test context
   2153  * @param key the key
   2154  * @param key_size number of bytes in @a key
   2155  * @param value the value, can be NULL
   2156  * @param value_size number of bytes in @a value
   2157  * @param kind type of the header
   2158  * @return #MHD_YES if the key-value pair is in the headers,
   2159  *         #MHD_NO if not
   2160  */
   2161 static enum MHD_Result
   2162 test_header (void *cls,
   2163              const char *key,
   2164              size_t key_size,
   2165              const char *value,
   2166              size_t value_size,
   2167              enum MHD_ValueKind kind)
   2168 {
   2169   struct test_header_param *const param = (struct test_header_param *) cls;
   2170   struct MHD_Connection *connection = param->connection;
   2171   struct MHD_HTTP_Req_Header *pos;
   2172   size_t i;
   2173 
   2174   param->num_headers++;
   2175   i = 0;
   2176   for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
   2177   {
   2178     if (kind != pos->kind)
   2179       continue;
   2180     if (++i == param->num_headers)
   2181     {
   2182       if (key_size != pos->header_size)
   2183         return MHD_NO;
   2184       if (value_size != pos->value_size)
   2185         return MHD_NO;
   2186       if (0 != key_size)
   2187       {
   2188         mhd_assert (NULL != key);
   2189         mhd_assert (NULL != pos->header);
   2190         if (0 != memcmp (key,
   2191                          pos->header,
   2192                          key_size))
   2193           return MHD_NO;
   2194       }
   2195       if (0 != value_size)
   2196       {
   2197         mhd_assert (NULL != value);
   2198         mhd_assert (NULL != pos->value);
   2199         if (0 != memcmp (value,
   2200                          pos->value,
   2201                          value_size))
   2202           return MHD_NO;
   2203       }
   2204       return MHD_YES;
   2205     }
   2206   }
   2207   return MHD_NO;
   2208 }
   2209 
   2210 
   2211 /**
   2212  * Check that the arguments given by the client as part
   2213  * of the authentication header match the arguments we
   2214  * got as part of the HTTP request URI.
   2215  *
   2216  * @param connection connections with headers to compare against
   2217  * @param args the copy of argument URI string (after "?" in URI), will be
   2218  *             modified by this function
   2219  * @return boolean true if the arguments match,
   2220  *         boolean false if not
   2221  */
   2222 static bool
   2223 check_argument_match (struct MHD_Connection *connection,
   2224                       char *args)
   2225 {
   2226   struct MHD_HTTP_Req_Header *pos;
   2227   enum MHD_Result ret;
   2228   struct test_header_param param;
   2229 
   2230   param.connection = connection;
   2231   param.num_headers = 0;
   2232   ret = MHD_parse_arguments_ (connection,
   2233                               MHD_GET_ARGUMENT_KIND,
   2234                               args,
   2235                               &test_header,
   2236                               &param);
   2237   if (MHD_NO == ret)
   2238   {
   2239     return false;
   2240   }
   2241   /* also check that the number of headers matches */
   2242   for (pos = connection->rq.headers_received; NULL != pos; pos = pos->next)
   2243   {
   2244     if (MHD_GET_ARGUMENT_KIND != pos->kind)
   2245       continue;
   2246     param.num_headers--;
   2247   }
   2248   if (0 != param.num_headers)
   2249   {
   2250     /* argument count mismatch */
   2251     return false;
   2252   }
   2253   return true;
   2254 }
   2255 
   2256 
   2257 /**
   2258  * Check that the URI provided by the client as part
   2259  * of the authentication header match the real HTTP request URI.
   2260  *
   2261  * @param connection connections with headers to compare against
   2262  * @param uri the copy of URI in the authentication header, should point to
   2263  *            modifiable buffer at least @a uri_len + 1 characters long,
   2264  *            will be modified by this function, not valid upon return
   2265  * @param uri_len the length of the @a uri string in characters
   2266  * @return boolean true if the URIs match,
   2267  *         boolean false if not
   2268  */
   2269 static bool
   2270 check_uri_match (struct MHD_Connection *connection, char *uri, size_t uri_len)
   2271 {
   2272   char *qmark;
   2273   char *args;
   2274   struct MHD_Daemon *const daemon = connection->daemon;
   2275 
   2276   uri[uri_len] = 0;
   2277   qmark = memchr (uri,
   2278                   '?',
   2279                   uri_len);
   2280   if (NULL != qmark)
   2281     *qmark = '\0';
   2282 
   2283   /* Need to unescape URI before comparing with connection->url */
   2284   uri_len = daemon->unescape_callback (daemon->unescape_callback_cls,
   2285                                        connection,
   2286                                        uri);
   2287   if ((uri_len != connection->rq.url_len) ||
   2288       (0 != memcmp (uri, connection->rq.url, uri_len)))
   2289   {
   2290 #ifdef HAVE_MESSAGES
   2291     MHD_DLOG (daemon,
   2292               _ ("Authentication failed, URI does not match.\n"));
   2293 #endif
   2294     return false;
   2295   }
   2296 
   2297   args = (NULL != qmark) ? (qmark + 1) : uri + uri_len;
   2298 
   2299   if (! check_argument_match (connection,
   2300                               args) )
   2301   {
   2302 #ifdef HAVE_MESSAGES
   2303     MHD_DLOG (daemon,
   2304               _ ("Authentication failed, arguments do not match.\n"));
   2305 #endif
   2306     return false;
   2307   }
   2308   return true;
   2309 }
   2310 
   2311 
   2312 /**
   2313  * The size of the unquoting buffer in stack
   2314  */
   2315 #define _MHD_STATIC_UNQ_BUFFER_SIZE 128
   2316 
   2317 
   2318 /**
   2319  * Get the pointer to buffer with required size
   2320  * @param tmp1 the first buffer with fixed size
   2321  * @param ptmp2 the pointer to pointer to malloc'ed buffer
   2322  * @param ptmp2_size the pointer to the size of the buffer pointed by @a ptmp2
   2323  * @param required_size the required size in buffer
   2324  * @return the pointer to the buffer or NULL if failed to allocate buffer with
   2325  *         requested size
   2326  */
   2327 static char *
   2328 get_buffer_for_size (char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
   2329                      char **ptmp2,
   2330                      size_t *ptmp2_size,
   2331                      size_t required_size)
   2332 {
   2333   mhd_assert ((0 == *ptmp2_size) || (NULL != *ptmp2));
   2334   mhd_assert ((NULL != *ptmp2) || (0 == *ptmp2_size));
   2335   mhd_assert ((0 == *ptmp2_size) || \
   2336               (_MHD_STATIC_UNQ_BUFFER_SIZE < *ptmp2_size));
   2337 
   2338   if (required_size <= _MHD_STATIC_UNQ_BUFFER_SIZE)
   2339     return tmp1;
   2340 
   2341   if (required_size <= *ptmp2_size)
   2342     return *ptmp2;
   2343 
   2344   if (required_size > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE)
   2345     return NULL;
   2346   if (NULL != *ptmp2)
   2347     free (*ptmp2);
   2348   *ptmp2 = (char *) malloc (required_size);
   2349   if (NULL == *ptmp2)
   2350     *ptmp2_size = 0;
   2351   else
   2352     *ptmp2_size = required_size;
   2353   return *ptmp2;
   2354 }
   2355 
   2356 
   2357 /**
   2358   * The result of parameter unquoting
   2359   */
   2360 enum _MHD_GetUnqResult
   2361 {
   2362   _MHD_UNQ_OK = 0,         /**< Got unquoted string */
   2363   _MHD_UNQ_TOO_LARGE = -7, /**< The string is too large to unquote */
   2364   _MHD_UNQ_OUT_OF_MEM = 3  /**< Out of memory error */
   2365 };
   2366 
   2367 /**
   2368  * Get Digest authorisation parameter as unquoted string.
   2369  * @param param the parameter to process
   2370  * @param tmp1 the small buffer in stack
   2371  * @param ptmp2 the pointer to pointer to malloc'ed buffer
   2372  * @param ptmp2_size the pointer to the size of the buffer pointed by @a ptmp2
   2373  * @param[out] unquoted the pointer to store the result, NOT zero terminated
   2374  * @return enum code indicating result of the process
   2375  */
   2376 static enum _MHD_GetUnqResult
   2377 get_unquoted_param (const struct MHD_RqDAuthParam *param,
   2378                     char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
   2379                     char **ptmp2,
   2380                     size_t *ptmp2_size,
   2381                     struct _MHD_str_w_len *unquoted)
   2382 {
   2383   char *str;
   2384   size_t len;
   2385   mhd_assert (NULL != param->value.str);
   2386   mhd_assert (0 != param->value.len);
   2387 
   2388   if (! param->quoted)
   2389   {
   2390     unquoted->str = param->value.str;
   2391     unquoted->len = param->value.len;
   2392     return _MHD_UNQ_OK;
   2393   }
   2394   /* The value is present and is quoted, needs to be copied and unquoted */
   2395   str = get_buffer_for_size (tmp1, ptmp2, ptmp2_size, param->value.len);
   2396   if (NULL == str)
   2397     return (param->value.len > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE) ?
   2398            _MHD_UNQ_TOO_LARGE : _MHD_UNQ_OUT_OF_MEM;
   2399 
   2400   len = MHD_str_unquote (param->value.str, param->value.len, str);
   2401   unquoted->str = str;
   2402   unquoted->len = len;
   2403   mhd_assert (0 != unquoted->len);
   2404   mhd_assert (unquoted->len < param->value.len);
   2405   return _MHD_UNQ_OK;
   2406 }
   2407 
   2408 
   2409 /**
   2410  * Get copy of Digest authorisation parameter as unquoted string.
   2411  * @param param the parameter to process
   2412  * @param tmp1 the small buffer in stack
   2413  * @param ptmp2 the pointer to pointer to malloc'ed buffer
   2414  * @param ptmp2_size the pointer to the size of the buffer pointed by @a ptmp2
   2415  * @param[out] unquoted the pointer to store the result, NOT zero terminated,
   2416  *                      but with enough space to zero-terminate
   2417  * @return enum code indicating result of the process
   2418  */
   2419 static enum _MHD_GetUnqResult
   2420 get_unquoted_param_copy (const struct MHD_RqDAuthParam *param,
   2421                          char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE],
   2422                          char **ptmp2,
   2423                          size_t *ptmp2_size,
   2424                          struct _MHD_mstr_w_len *unquoted)
   2425 {
   2426   mhd_assert (NULL != param->value.str);
   2427   mhd_assert (0 != param->value.len);
   2428 
   2429   /* The value is present and is quoted, needs to be copied and unquoted */
   2430   /* Allocate buffer with one more additional byte for zero-termination */
   2431   unquoted->str =
   2432     get_buffer_for_size (tmp1, ptmp2, ptmp2_size, param->value.len + 1);
   2433 
   2434   if (NULL == unquoted->str)
   2435     return (param->value.len + 1 > _MHD_AUTH_DIGEST_MAX_PARAM_SIZE) ?
   2436            _MHD_UNQ_TOO_LARGE : _MHD_UNQ_OUT_OF_MEM;
   2437 
   2438   if (! param->quoted)
   2439   {
   2440     memcpy (unquoted->str, param->value.str, param->value.len);
   2441     unquoted->len = param->value.len;
   2442     return _MHD_UNQ_OK;
   2443   }
   2444 
   2445   unquoted->len =
   2446     MHD_str_unquote (param->value.str, param->value.len, unquoted->str);
   2447   mhd_assert (0 != unquoted->len);
   2448   mhd_assert (unquoted->len < param->value.len);
   2449   return _MHD_UNQ_OK;
   2450 }
   2451 
   2452 
   2453 /**
   2454  * Check whether Digest Auth request parameter is equal to given string
   2455  * @param param the parameter to check
   2456  * @param str the string to compare with, does not need to be zero-terminated
   2457  * @param str_len the length of the @a str
   2458  * @return true is parameter is equal to the given string,
   2459  *         false otherwise
   2460  */
   2461 _MHD_static_inline bool
   2462 is_param_equal (const struct MHD_RqDAuthParam *param,
   2463                 const char *const str,
   2464                 const size_t str_len)
   2465 {
   2466   mhd_assert (NULL != param->value.str);
   2467   mhd_assert (0 != param->value.len);
   2468   if (param->quoted)
   2469     return MHD_str_equal_quoted_bin_n (param->value.str, param->value.len,
   2470                                        str, str_len);
   2471   return (str_len == param->value.len) &&
   2472          (0 == memcmp (str, param->value.str, str_len));
   2473 
   2474 }
   2475 
   2476 
   2477 /**
   2478  * Check whether Digest Auth request parameter is caseless equal to given string
   2479  * @param param the parameter to check
   2480  * @param str the string to compare with, does not need to be zero-terminated
   2481  * @param str_len the length of the @a str
   2482  * @return true is parameter is caseless equal to the given string,
   2483  *         false otherwise
   2484  */
   2485 _MHD_static_inline bool
   2486 is_param_equal_caseless (const struct MHD_RqDAuthParam *param,
   2487                          const char *const str,
   2488                          const size_t str_len)
   2489 {
   2490   mhd_assert (NULL != param->value.str);
   2491   mhd_assert (0 != param->value.len);
   2492   if (param->quoted)
   2493     return MHD_str_equal_caseless_quoted_bin_n (param->value.str,
   2494                                                 param->value.len,
   2495                                                 str,
   2496                                                 str_len);
   2497   return (str_len == param->value.len) &&
   2498          (MHD_str_equal_caseless_bin_n_ (str,
   2499                                          param->value.str,
   2500                                          str_len));
   2501 }
   2502 
   2503 
   2504 /**
   2505  * Authenticates the authorization header sent by the client
   2506  *
   2507  * If RFC2069 mode is allowed by setting bit #MHD_DIGEST_AUTH_QOP_NONE in
   2508  * @a mqop and the client uses this mode, then server generated nonces are
   2509  * used as one-time nonces because nonce-count is not supported in this old RFC.
   2510  * Communication in this mode is very inefficient, especially if the client
   2511  * requests several resources one-by-one as for every request new nonce must be
   2512  * generated and client repeat all requests twice (the first time to get a new
   2513  * nonce and the second time to perform an authorised request).
   2514  *
   2515  * @param connection the MHD connection structure
   2516  * @param realm the realm for authorization of the client
   2517  * @param username the username to be authenticated, must be in clear text
   2518  *                 even if userhash is used by the client
   2519  * @param password the password used in the authentication,
   2520  *                 must be NULL if @a userdigest is not NULL
   2521  * @param userdigest the precalculated binary hash of the string
   2522  *                   "username:realm:password",
   2523  *                   must be NULL if @a password is not NULL
   2524  * @param nonce_timeout the period of seconds since nonce generation, when
   2525  *                      the nonce is recognised as valid and not stale;
   2526  *                      unlike #digest_auth_check_all() zero is used literally
   2527  * @param max_nc the maximum allowed nc (Nonce Count) value, if client's nc
   2528  *               exceeds the specified value then MHD_DAUTH_NONCE_STALE is
   2529  *               returned;
   2530  *               unlike #digest_auth_check_all() zero is treated as "no limit"
   2531  * @param mqop the QOP to use
   2532  * @param malgo3 digest algorithms allowed to use, fail if algorithm specified
   2533  *               by the client is not allowed by this parameter
   2534  * @param[out] pbuf the pointer to pointer to internally malloc'ed buffer,
   2535  *                  to be freed if not NULL upon return
   2536  * @return #MHD_DAUTH_OK if authenticated,
   2537  *         error code otherwise.
   2538  * @ingroup authentication
   2539  */
   2540 static enum MHD_DigestAuthResult
   2541 digest_auth_check_all_inner (struct MHD_Connection *connection,
   2542                              const char *realm,
   2543                              const char *username,
   2544                              const char *password,
   2545                              const uint8_t *userdigest,
   2546                              unsigned int nonce_timeout,
   2547                              uint32_t max_nc,
   2548                              enum MHD_DigestAuthMultiQOP mqop,
   2549                              enum MHD_DigestAuthMultiAlgo3 malgo3,
   2550                              char **pbuf,
   2551                              struct DigestAlgorithm *da)
   2552 {
   2553   struct MHD_Daemon *daemon = MHD_get_master (connection->daemon);
   2554   enum MHD_DigestAuthAlgo3 c_algo; /**< Client's algorithm */
   2555   enum MHD_DigestAuthQOP c_qop; /**< Client's QOP */
   2556   unsigned int digest_size;
   2557   uint8_t hash1_bin[MAX_DIGEST];
   2558   uint8_t hash2_bin[MAX_DIGEST];
   2559 #if 0
   2560   const char *hentity = NULL; /* "auth-int" is not supported */
   2561 #endif
   2562   uint64_t nonce_time;
   2563   uint64_t nci;
   2564   const struct MHD_RqDAuth *params;
   2565   /**
   2566    * Temporal buffer in stack for unquoting and other needs
   2567    */
   2568   char tmp1[_MHD_STATIC_UNQ_BUFFER_SIZE];
   2569   char **const ptmp2 = pbuf;     /**< Temporal malloc'ed buffer for unquoting */
   2570   size_t tmp2_size; /**< The size of @a tmp2 buffer */
   2571   struct _MHD_str_w_len unquoted;
   2572   struct _MHD_mstr_w_len unq_copy;
   2573   enum _MHD_GetUnqResult unq_res;
   2574   size_t username_len;
   2575   size_t realm_len;
   2576 
   2577   mhd_assert ((NULL != password) || (NULL != userdigest));
   2578   mhd_assert (! ((NULL != userdigest) && (NULL != password)));
   2579 
   2580   tmp2_size = 0;
   2581 
   2582   params = MHD_get_rq_dauth_params_ (connection);
   2583   if (NULL == params)
   2584     return MHD_DAUTH_WRONG_HEADER;
   2585 
   2586   /* ** Initial parameters checks and setup ** */
   2587   /* Get client's algorithm */
   2588   c_algo = params->algo3;
   2589   /* Check whether client's algorithm is allowed by function parameter */
   2590   if (((unsigned int) c_algo) !=
   2591       (((unsigned int) c_algo) & ((unsigned int) malgo3)))
   2592     return MHD_DAUTH_WRONG_ALGO;
   2593   /* Check whether client's algorithm is supported */
   2594   if (0 != (((unsigned int) c_algo) & MHD_DIGEST_AUTH_ALGO3_SESSION))
   2595   {
   2596 #ifdef HAVE_MESSAGES
   2597     MHD_DLOG (connection->daemon,
   2598               _ ("The 'session' algorithms are not supported.\n"));
   2599 #endif /* HAVE_MESSAGES */
   2600     return MHD_DAUTH_WRONG_ALGO;
   2601   }
   2602 #ifndef MHD_MD5_SUPPORT
   2603   if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_MD5))
   2604   {
   2605 #ifdef HAVE_MESSAGES
   2606     MHD_DLOG (connection->daemon,
   2607               _ ("The MD5 algorithm is not supported by this MHD build.\n"));
   2608 #endif /* HAVE_MESSAGES */
   2609     return MHD_DAUTH_WRONG_ALGO;
   2610   }
   2611 #endif /* ! MHD_MD5_SUPPORT */
   2612 #ifndef MHD_SHA256_SUPPORT
   2613   if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_SHA256))
   2614   {
   2615 #ifdef HAVE_MESSAGES
   2616     MHD_DLOG (connection->daemon,
   2617               _ ("The SHA-256 algorithm is not supported by "
   2618                  "this MHD build.\n"));
   2619 #endif /* HAVE_MESSAGES */
   2620     return MHD_DAUTH_WRONG_ALGO;
   2621   }
   2622 #endif /* ! MHD_SHA256_SUPPORT */
   2623 #ifndef MHD_SHA512_256_SUPPORT
   2624   if (0 != (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_SHA512_256))
   2625   {
   2626 #ifdef HAVE_MESSAGES
   2627     MHD_DLOG (connection->daemon,
   2628               _ ("The SHA-512/256 algorithm is not supported by "
   2629                  "this MHD build.\n"));
   2630 #endif /* HAVE_MESSAGES */
   2631     return MHD_DAUTH_WRONG_ALGO;
   2632   }
   2633 #endif /* ! MHD_SHA512_256_SUPPORT */
   2634   if (! digest_init_one_time (da, get_base_digest_algo (c_algo)))
   2635     MHD_PANIC (_ ("Wrong 'malgo3' value, API violation"));
   2636   /* Check 'mqop' value */
   2637   c_qop = params->qop;
   2638   /* Check whether client's QOP is allowed by function parameter */
   2639   if (((unsigned int) c_qop) !=
   2640       (((unsigned int) c_qop) & ((unsigned int) mqop)))
   2641     return MHD_DAUTH_WRONG_QOP;
   2642   if (0 != (((unsigned int) c_qop) & MHD_DIGEST_AUTH_QOP_AUTH_INT))
   2643   {
   2644 #ifdef HAVE_MESSAGES
   2645     MHD_DLOG (connection->daemon,
   2646               _ ("The 'auth-int' QOP is not supported.\n"));
   2647 #endif /* HAVE_MESSAGES */
   2648     return MHD_DAUTH_WRONG_QOP;
   2649   }
   2650 #ifdef HAVE_MESSAGES
   2651   if ((MHD_DIGEST_AUTH_QOP_NONE == c_qop) &&
   2652       (0 == (((unsigned int) c_algo) & MHD_DIGEST_BASE_ALGO_MD5)))
   2653     MHD_DLOG (connection->daemon,
   2654               _ ("RFC2069 with SHA-256 or SHA-512/256 algorithm is " \
   2655                  "non-standard extension.\n"));
   2656 #endif /* HAVE_MESSAGES */
   2657 
   2658   digest_size = digest_get_size (da);
   2659 
   2660   /* ** A quick check for presence of all required parameters ** */
   2661 
   2662   if ((NULL == params->username.value.str) &&
   2663       (NULL == params->username_ext.value.str))
   2664     return MHD_DAUTH_WRONG_USERNAME;
   2665   else if ((NULL != params->username.value.str) &&
   2666            (NULL != params->username_ext.value.str))
   2667     return MHD_DAUTH_WRONG_USERNAME; /* Parameters cannot be used together */
   2668   else if ((NULL != params->username_ext.value.str) &&
   2669            (MHD_DAUTH_EXT_PARAM_MIN_LEN > params->username_ext.value.len))
   2670     return MHD_DAUTH_WRONG_USERNAME;  /* Broken extended notation */
   2671   else if (params->userhash && (NULL == params->username.value.str))
   2672     return MHD_DAUTH_WRONG_USERNAME;  /* Userhash cannot be used with extended notation */
   2673   else if (params->userhash && (digest_size * 2 > params->username.value.len))
   2674     return MHD_DAUTH_WRONG_USERNAME;  /* Too few chars for correct userhash */
   2675   else if (params->userhash && (digest_size * 4 < params->username.value.len))
   2676     return MHD_DAUTH_WRONG_USERNAME;  /* Too many chars for correct userhash */
   2677 
   2678   if (NULL == params->realm.value.str)
   2679     return MHD_DAUTH_WRONG_REALM;
   2680   else if (((NULL == userdigest) || params->userhash) &&
   2681            (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < params->realm.value.len))
   2682     return MHD_DAUTH_TOO_LARGE; /* Realm is too large and should be used in hash calculations */
   2683 
   2684   if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
   2685   {
   2686     if (NULL == params->nc.value.str)
   2687       return MHD_DAUTH_WRONG_HEADER;
   2688     else if (0 == params->nc.value.len)
   2689       return MHD_DAUTH_WRONG_HEADER;
   2690     else if (4 * 8 < params->nc.value.len) /* Four times more than needed */
   2691       return MHD_DAUTH_WRONG_HEADER;
   2692 
   2693     if (NULL == params->cnonce.value.str)
   2694       return MHD_DAUTH_WRONG_HEADER;
   2695     else if (0 == params->cnonce.value.len)
   2696       return MHD_DAUTH_WRONG_HEADER;
   2697     else if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < params->cnonce.value.len)
   2698       return MHD_DAUTH_TOO_LARGE;
   2699   }
   2700 
   2701   /* The QOP parameter was checked already */
   2702 
   2703   if (NULL == params->uri.value.str)
   2704     return MHD_DAUTH_WRONG_URI;
   2705   else if (0 == params->uri.value.len)
   2706     return MHD_DAUTH_WRONG_URI;
   2707   else if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < params->uri.value.len)
   2708     return MHD_DAUTH_TOO_LARGE;
   2709 
   2710   if (NULL == params->nonce.value.str)
   2711     return MHD_DAUTH_NONCE_WRONG;
   2712   else if (0 == params->nonce.value.len)
   2713     return MHD_DAUTH_NONCE_WRONG;
   2714   else if (NONCE_STD_LEN (digest_size) * 2 < params->nonce.value.len)
   2715     return MHD_DAUTH_NONCE_WRONG;
   2716 
   2717   if (NULL == params->response.value.str)
   2718     return MHD_DAUTH_RESPONSE_WRONG;
   2719   else if (0 == params->response.value.len)
   2720     return MHD_DAUTH_RESPONSE_WRONG;
   2721   else if (digest_size * 4 < params->response.value.len)
   2722     return MHD_DAUTH_RESPONSE_WRONG;
   2723 
   2724   /* ** Check simple parameters match ** */
   2725 
   2726   /* Check 'algorithm' */
   2727   /* The 'algorithm' was checked at the start of the function */
   2728   /* 'algorithm' valid */
   2729 
   2730   /* Check 'qop' */
   2731   /* The 'qop' was checked at the start of the function */
   2732   /* 'qop' valid */
   2733 
   2734   /* Check 'realm' */
   2735   realm_len = strlen (realm);
   2736   if (! is_param_equal (&params->realm, realm, realm_len))
   2737     return MHD_DAUTH_WRONG_REALM;
   2738   /* 'realm' valid */
   2739 
   2740   /* Check 'username' */
   2741   username_len = strlen (username);
   2742   if (! params->userhash)
   2743   {
   2744     if (NULL != params->username.value.str)
   2745     { /* Username in standard notation */
   2746       if (! is_param_equal (&params->username, username, username_len))
   2747         return MHD_DAUTH_WRONG_USERNAME;
   2748     }
   2749     else
   2750     { /* Username in extended notation */
   2751       char *r_uname;
   2752       size_t buf_size = params->username_ext.value.len;
   2753       ssize_t res;
   2754 
   2755       mhd_assert (NULL != params->username_ext.value.str);
   2756       mhd_assert (MHD_DAUTH_EXT_PARAM_MIN_LEN <= buf_size); /* It was checked already */
   2757       buf_size += 1; /* For zero-termination */
   2758       buf_size -= MHD_DAUTH_EXT_PARAM_MIN_LEN;
   2759       r_uname = get_buffer_for_size (tmp1, ptmp2, &tmp2_size, buf_size);
   2760       if (NULL == r_uname)
   2761         return (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < buf_size) ?
   2762                MHD_DAUTH_TOO_LARGE : MHD_DAUTH_ERROR;
   2763       res = get_rq_extended_uname_copy_z (params->username_ext.value.str,
   2764                                           params->username_ext.value.len,
   2765                                           r_uname, buf_size);
   2766       if (0 > res)
   2767         return MHD_DAUTH_WRONG_HEADER; /* Broken extended notation */
   2768       if ((username_len != (size_t) res) ||
   2769           (0 != memcmp (username, r_uname, username_len)))
   2770         return MHD_DAUTH_WRONG_USERNAME;
   2771     }
   2772   }
   2773   else
   2774   { /* Userhash */
   2775     mhd_assert (NULL != params->username.value.str);
   2776     calc_userhash (da, username, username_len, realm, realm_len, hash1_bin);
   2777 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   2778     if (digest_ext_error (da))
   2779       return MHD_DAUTH_ERROR;
   2780 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   2781     mhd_assert (sizeof (tmp1) >= (2 * digest_size));
   2782     MHD_bin_to_hex (hash1_bin, digest_size, tmp1);
   2783     if (! is_param_equal_caseless (&params->username, tmp1, 2 * digest_size))
   2784       return MHD_DAUTH_WRONG_USERNAME;
   2785     /* To simplify the logic, the digest is reset here instead of resetting
   2786        before the next hash calculation. */
   2787     digest_reset (da);
   2788   }
   2789   /* 'username' valid */
   2790 
   2791   /* ** Do basic nonce and nonce-counter checks (size, timestamp) ** */
   2792 
   2793   /* Get 'nc' digital value */
   2794   if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
   2795   {
   2796 
   2797     unq_res = get_unquoted_param (&params->nc, tmp1, ptmp2, &tmp2_size,
   2798                                   &unquoted);
   2799     if (_MHD_UNQ_OK != unq_res)
   2800       return MHD_DAUTH_ERROR;
   2801 
   2802     if (unquoted.len != MHD_strx_to_uint64_n_ (unquoted.str,
   2803                                                unquoted.len,
   2804                                                &nci))
   2805     {
   2806 #ifdef HAVE_MESSAGES
   2807       MHD_DLOG (daemon,
   2808                 _ ("Authentication failed, invalid nc format.\n"));
   2809 #endif
   2810       return MHD_DAUTH_WRONG_HEADER;   /* invalid nonce format */
   2811     }
   2812     if (0 == nci)
   2813     {
   2814 #ifdef HAVE_MESSAGES
   2815       MHD_DLOG (daemon,
   2816                 _ ("Authentication failed, invalid 'nc' value.\n"));
   2817 #endif
   2818       return MHD_DAUTH_WRONG_HEADER;   /* invalid nc value */
   2819     }
   2820     if ((0 != max_nc) && (max_nc < nci))
   2821       return MHD_DAUTH_NONCE_STALE;    /* Too large 'nc' value */
   2822   }
   2823   else
   2824     nci = 1; /* Force 'nc' value */
   2825   /* Got 'nc' digital value */
   2826 
   2827   /* Get 'nonce' with basic checks */
   2828   unq_res = get_unquoted_param (&params->nonce, tmp1, ptmp2, &tmp2_size,
   2829                                 &unquoted);
   2830   if (_MHD_UNQ_OK != unq_res)
   2831     return MHD_DAUTH_ERROR;
   2832 
   2833   if ((NONCE_STD_LEN (digest_size) != unquoted.len) ||
   2834       (! get_nonce_timestamp (unquoted.str, unquoted.len, &nonce_time)))
   2835   {
   2836 #ifdef HAVE_MESSAGES
   2837     MHD_DLOG (daemon,
   2838               _ ("Authentication failed, invalid nonce format.\n"));
   2839 #endif
   2840     return MHD_DAUTH_NONCE_WRONG;
   2841   }
   2842 
   2843   if (1)
   2844   {
   2845     uint64_t t;
   2846 
   2847     t = MHD_monotonic_msec_counter ();
   2848     /*
   2849      * First level vetting for the nonce validity: if the timestamp
   2850      * attached to the nonce exceeds `nonce_timeout', then the nonce is
   2851      * stale.
   2852      */
   2853     if (TRIM_TO_TIMESTAMP (t - nonce_time) > (nonce_timeout * 1000))
   2854       return MHD_DAUTH_NONCE_STALE; /* too old */
   2855   }
   2856   if (1)
   2857   {
   2858     enum MHD_CheckNonceNC_ nonce_nc_check;
   2859     /*
   2860      * Checking if that combination of nonce and nc is sound
   2861      * and not a replay attack attempt. Refuse if nonce was not
   2862      * generated previously.
   2863      */
   2864     nonce_nc_check = check_nonce_nc (connection,
   2865                                      unquoted.str,
   2866                                      NONCE_STD_LEN (digest_size),
   2867                                      nonce_time,
   2868                                      nci);
   2869     if (MHD_CHECK_NONCENC_STALE == nonce_nc_check)
   2870     {
   2871 #ifdef HAVE_MESSAGES
   2872       if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
   2873         MHD_DLOG (daemon,
   2874                   _ ("Stale nonce received. If this happens a lot, you should "
   2875                      "probably increase the size of the nonce array.\n"));
   2876       else
   2877         MHD_DLOG (daemon,
   2878                   _ ("Stale nonce received. This is expected when client " \
   2879                      "uses RFC2069-compatible mode and makes more than one " \
   2880                      "request.\n"));
   2881 #endif
   2882       return MHD_DAUTH_NONCE_STALE;
   2883     }
   2884     else if (MHD_CHECK_NONCENC_WRONG == nonce_nc_check)
   2885     {
   2886 #ifdef HAVE_MESSAGES
   2887       MHD_DLOG (daemon,
   2888                 _ ("Received nonce that was not "
   2889                    "generated by MHD. This may indicate an attack attempt.\n"));
   2890 #endif
   2891       return MHD_DAUTH_NONCE_WRONG;
   2892     }
   2893     mhd_assert (MHD_CHECK_NONCENC_OK == nonce_nc_check);
   2894   }
   2895   /* The nonce was generated by MHD, is not stale and nonce-nc combination was
   2896      not used before */
   2897 
   2898   /* ** Build H(A2) and check URI match in the header and in the request ** */
   2899 
   2900   /* Get 'uri' */
   2901   mhd_assert (! da->hashing);
   2902   digest_update_str (da, connection->rq.method);
   2903   digest_update_with_colon (da);
   2904 #if 0
   2905   /* TODO: add support for "auth-int" */
   2906   digest_update_str (da, hentity);
   2907   digest_update_with_colon (da);
   2908 #endif
   2909   unq_res = get_unquoted_param_copy (&params->uri, tmp1, ptmp2, &tmp2_size,
   2910                                      &unq_copy);
   2911   if (_MHD_UNQ_OK != unq_res)
   2912     return MHD_DAUTH_ERROR;
   2913 
   2914   digest_update (da, unq_copy.str, unq_copy.len);
   2915   /* The next check will modify copied URI string */
   2916   if (! check_uri_match (connection, unq_copy.str, unq_copy.len))
   2917     return MHD_DAUTH_WRONG_URI;
   2918   digest_calc_hash (da, hash2_bin);
   2919 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   2920   /* Skip digest calculation external error check, the next one checks both */
   2921 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   2922   /* Got H(A2) */
   2923 
   2924   /* ** Build H(A1) ** */
   2925   if (NULL == userdigest)
   2926   {
   2927     mhd_assert (! da->hashing);
   2928     digest_reset (da);
   2929     calc_userdigest (da,
   2930                      username, username_len,
   2931                      realm, realm_len,
   2932                      password,
   2933                      hash1_bin);
   2934   }
   2935   /* TODO: support '-sess' versions */
   2936 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   2937   if (digest_ext_error (da))
   2938     return MHD_DAUTH_ERROR;
   2939 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   2940   /* Got H(A1) */
   2941 
   2942   /* **  Check 'response' ** */
   2943 
   2944   mhd_assert (! da->hashing);
   2945   digest_reset (da);
   2946   /* Update digest with H(A1) */
   2947   mhd_assert (sizeof (tmp1) >= (digest_size * 2));
   2948   if (NULL == userdigest)
   2949     MHD_bin_to_hex (hash1_bin, digest_size, tmp1);
   2950   else
   2951     MHD_bin_to_hex (userdigest, digest_size, tmp1);
   2952   digest_update (da, (const uint8_t *) tmp1, digest_size * 2);
   2953 
   2954   /* H(A1) is not needed anymore, reuse the buffer.
   2955    * Use hash1_bin for the client's 'response' decoded to binary form. */
   2956   unq_res = get_unquoted_param (&params->response, tmp1, ptmp2, &tmp2_size,
   2957                                 &unquoted);
   2958   if (_MHD_UNQ_OK != unq_res)
   2959     return MHD_DAUTH_ERROR;
   2960   if (digest_size != MHD_hex_to_bin (unquoted.str, unquoted.len, hash1_bin))
   2961     return MHD_DAUTH_RESPONSE_WRONG;
   2962 
   2963   /* Update digest with ':' */
   2964   digest_update_with_colon (da);
   2965   /* Update digest with 'nonce' text value */
   2966   unq_res = get_unquoted_param (&params->nonce, tmp1, ptmp2, &tmp2_size,
   2967                                 &unquoted);
   2968   if (_MHD_UNQ_OK != unq_res)
   2969     return MHD_DAUTH_ERROR;
   2970   digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
   2971   /* Update digest with ':' */
   2972   digest_update_with_colon (da);
   2973   if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
   2974   {
   2975     /* Update digest with 'nc' text value */
   2976     unq_res = get_unquoted_param (&params->nc, tmp1, ptmp2, &tmp2_size,
   2977                                   &unquoted);
   2978     if (_MHD_UNQ_OK != unq_res)
   2979       return MHD_DAUTH_ERROR;
   2980     digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
   2981     /* Update digest with ':' */
   2982     digest_update_with_colon (da);
   2983     /* Update digest with 'cnonce' value */
   2984     unq_res = get_unquoted_param (&params->cnonce, tmp1, ptmp2, &tmp2_size,
   2985                                   &unquoted);
   2986     if (_MHD_UNQ_OK != unq_res)
   2987       return MHD_DAUTH_ERROR;
   2988     digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
   2989     /* Update digest with ':' */
   2990     digest_update_with_colon (da);
   2991     /* Update digest with 'qop' value */
   2992     unq_res = get_unquoted_param (&params->qop_raw, tmp1, ptmp2, &tmp2_size,
   2993                                   &unquoted);
   2994     if (_MHD_UNQ_OK != unq_res)
   2995       return MHD_DAUTH_ERROR;
   2996     digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
   2997     /* Update digest with ':' */
   2998     digest_update_with_colon (da);
   2999   }
   3000   /* Update digest with H(A2) */
   3001   MHD_bin_to_hex (hash2_bin,
   3002                   digest_size,
   3003                   tmp1);
   3004   digest_update (da,
   3005                  (const uint8_t *) tmp1,
   3006                  digest_size * 2);
   3007 
   3008   /* H(A2) is not needed anymore, reuse the buffer.
   3009    * Use hash2_bin for the calculated response in binary form */
   3010   digest_calc_hash (da, hash2_bin);
   3011 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   3012   if (digest_ext_error (da))
   3013     return MHD_DAUTH_ERROR;
   3014 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   3015 
   3016   if (0 != memcmp (hash1_bin,
   3017                    hash2_bin,
   3018                    digest_size))
   3019     return MHD_DAUTH_RESPONSE_WRONG;
   3020 
   3021   if (MHD_DAUTH_BIND_NONCE_NONE != daemon->dauth_bind_type)
   3022   {
   3023     mhd_assert (sizeof(tmp1) >= (NONCE_STD_LEN (digest_size) + 1));
   3024     /* It was already checked that 'nonce' (including timestamp) was generated
   3025        by MHD. */
   3026     mhd_assert (! da->hashing);
   3027     digest_reset (da);
   3028     calculate_nonce (nonce_time,
   3029                      connection->rq.http_mthd,
   3030                      connection->rq.method,
   3031                      daemon->digest_auth_random,
   3032                      daemon->digest_auth_rand_size,
   3033                      connection->addr,
   3034                      (size_t) connection->addr_len,
   3035                      connection->rq.url,
   3036                      connection->rq.url_len,
   3037                      connection->rq.headers_received,
   3038                      realm,
   3039                      realm_len,
   3040                      daemon->dauth_bind_type,
   3041                      da,
   3042                      tmp1);
   3043 
   3044 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   3045     if (digest_ext_error (da))
   3046       return MHD_DAUTH_ERROR;
   3047 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   3048 
   3049     if (! is_param_equal (&params->nonce, tmp1,
   3050                           NONCE_STD_LEN (digest_size)))
   3051       return MHD_DAUTH_NONCE_OTHER_COND;
   3052     /* The 'nonce' was generated in the same conditions */
   3053   }
   3054 
   3055   return MHD_DAUTH_OK;
   3056 }
   3057 
   3058 
   3059 /**
   3060  * Authenticates the authorization header sent by the client
   3061  *
   3062  * If RFC2069 mode is allowed by setting bit #MHD_DIGEST_AUTH_QOP_NONE in
   3063  * @a mqop and the client uses this mode, then server generated nonces are
   3064  * used as one-time nonces because nonce-count is not supported in this old RFC.
   3065  * Communication in this mode is very inefficient, especially if the client
   3066  * requests several resources one-by-one as for every request new nonce must be
   3067  * generated and client repeat all requests twice (the first time to get a new
   3068  * nonce and the second time to perform an authorised request).
   3069  *
   3070  * @param connection the MHD connection structure
   3071  * @param realm the realm for authorization of the client
   3072  * @param username the username to be authenticated, must be in clear text
   3073  *                 even if userhash is used by the client
   3074  * @param password the password used in the authentication,
   3075  *                 must be NULL if @a userdigest is not NULL
   3076  * @param userdigest the precalculated binary hash of the string
   3077  *                   "username:realm:password",
   3078  *                   must be NULL if @a password is not NULL
   3079  * @param nonce_timeout the period of seconds since nonce generation, when
   3080  *                      the nonce is recognised as valid and not stale;
   3081  *                      if set to zero then daemon's default value is used
   3082  * @param max_nc the maximum allowed nc (Nonce Count) value, if client's nc
   3083  *               exceeds the specified value then MHD_DAUTH_NONCE_STALE is
   3084  *               returned;
   3085  *               if set to zero then daemon's default value is used
   3086  * @param mqop the QOP to use
   3087  * @param malgo3 digest algorithms allowed to use, fail if algorithm specified
   3088  *               by the client is not allowed by this parameter
   3089  * @return #MHD_DAUTH_OK if authenticated,
   3090  *         error code otherwise.
   3091  * @ingroup authentication
   3092  */
   3093 static enum MHD_DigestAuthResult
   3094 digest_auth_check_all (struct MHD_Connection *connection,
   3095                        const char *realm,
   3096                        const char *username,
   3097                        const char *password,
   3098                        const uint8_t *userdigest,
   3099                        unsigned int nonce_timeout,
   3100                        uint32_t max_nc,
   3101                        enum MHD_DigestAuthMultiQOP mqop,
   3102                        enum MHD_DigestAuthMultiAlgo3 malgo3)
   3103 {
   3104   enum MHD_DigestAuthResult res;
   3105   char *buf;
   3106   struct DigestAlgorithm da;
   3107 
   3108   buf = NULL;
   3109   digest_setup_zero (&da);
   3110   if (0 == nonce_timeout)
   3111     nonce_timeout = connection->daemon->dauth_def_nonce_timeout;
   3112   if (0 == max_nc)
   3113     max_nc = connection->daemon->dauth_def_max_nc;
   3114   res = digest_auth_check_all_inner (connection, realm, username, password,
   3115                                      userdigest,
   3116                                      nonce_timeout,
   3117                                      max_nc, mqop, malgo3,
   3118                                      &buf, &da);
   3119   digest_deinit (&da);
   3120   if (NULL != buf)
   3121     free (buf);
   3122 
   3123   return res;
   3124 }
   3125 
   3126 
   3127 /**
   3128  * Authenticates the authorization header sent by the client.
   3129  * Uses #MHD_DIGEST_ALG_MD5 (for now, for backwards-compatibility).
   3130  * Note that this MAY change to #MHD_DIGEST_ALG_AUTO in the future.
   3131  * If you want to be sure you get MD5, use #MHD_digest_auth_check2()
   3132  * and specify MD5 explicitly.
   3133  *
   3134  * @param connection The MHD connection structure
   3135  * @param realm The realm presented to the client
   3136  * @param username The username needs to be authenticated
   3137  * @param password The password used in the authentication
   3138  * @param nonce_timeout The amount of time for a nonce to be
   3139  *      invalid in seconds
   3140  * @return #MHD_YES if authenticated, #MHD_NO if not,
   3141  *         #MHD_INVALID_NONCE if nonce is invalid or stale
   3142  * @deprecated use MHD_digest_auth_check3()
   3143  * @ingroup authentication
   3144  */
   3145 _MHD_EXTERN int
   3146 MHD_digest_auth_check (struct MHD_Connection *connection,
   3147                        const char *realm,
   3148                        const char *username,
   3149                        const char *password,
   3150                        unsigned int nonce_timeout)
   3151 {
   3152   return MHD_digest_auth_check2 (connection,
   3153                                  realm,
   3154                                  username,
   3155                                  password,
   3156                                  nonce_timeout,
   3157                                  MHD_DIGEST_ALG_MD5);
   3158 }
   3159 
   3160 
   3161 /**
   3162  * Authenticates the authorization header sent by the client.
   3163  *
   3164  * If RFC2069 mode is allowed by setting bit #MHD_DIGEST_AUTH_QOP_NONE in
   3165  * @a mqop and the client uses this mode, then server generated nonces are
   3166  * used as one-time nonces because nonce-count is not supported in this old RFC.
   3167  * Communication in this mode is very inefficient, especially if the client
   3168  * requests several resources one-by-one as for every request a new nonce must
   3169  * be generated and client repeats all requests twice (first time to get a new
   3170  * nonce and second time to perform an authorised request).
   3171  *
   3172  * @param connection the MHD connection structure
   3173  * @param realm the realm for authorization of the client
   3174  * @param username the username to be authenticated, must be in clear text
   3175  *                 even if userhash is used by the client
   3176  * @param password the password matching the @a username (and the @a realm)
   3177  * @param nonce_timeout the period of seconds since nonce generation, when
   3178  *                      the nonce is recognised as valid and not stale;
   3179  *                      if zero is specified then daemon default value is used.
   3180  * @param max_nc the maximum allowed nc (Nonce Count) value, if client's nc
   3181  *               exceeds the specified value then MHD_DAUTH_NONCE_STALE is
   3182  *               returned;
   3183  *               if zero is specified then daemon default value is used.
   3184  * @param mqop the QOP to use
   3185  * @param malgo3 digest algorithms allowed to use, fail if algorithm used
   3186  *               by the client is not allowed by this parameter
   3187  * @return #MHD_DAUTH_OK if authenticated,
   3188  *         the error code otherwise
   3189  * @note Available since #MHD_VERSION 0x00097708
   3190  * @ingroup authentication
   3191  */
   3192 _MHD_EXTERN enum MHD_DigestAuthResult
   3193 MHD_digest_auth_check3 (struct MHD_Connection *connection,
   3194                         const char *realm,
   3195                         const char *username,
   3196                         const char *password,
   3197                         unsigned int nonce_timeout,
   3198                         uint32_t max_nc,
   3199                         enum MHD_DigestAuthMultiQOP mqop,
   3200                         enum MHD_DigestAuthMultiAlgo3 malgo3)
   3201 {
   3202   mhd_assert (NULL != password);
   3203 
   3204   return digest_auth_check_all (connection,
   3205                                 realm,
   3206                                 username,
   3207                                 password,
   3208                                 NULL,
   3209                                 nonce_timeout,
   3210                                 max_nc,
   3211                                 mqop,
   3212                                 malgo3);
   3213 }
   3214 
   3215 
   3216 /**
   3217  * Authenticates the authorization header sent by the client by using
   3218  * hash of "username:realm:password".
   3219  *
   3220  * If RFC2069 mode is allowed by setting bit #MHD_DIGEST_AUTH_QOP_NONE in
   3221  * @a mqop and the client uses this mode, then server generated nonces are
   3222  * used as one-time nonces because nonce-count is not supported in this old RFC.
   3223  * Communication in this mode is very inefficient, especially if the client
   3224  * requests several resources one-by-one as for every request a new nonce must
   3225  * be generated and client repeats all requests twice (first time to get a new
   3226  * nonce and second time to perform an authorised request).
   3227  *
   3228  * @param connection the MHD connection structure
   3229  * @param realm the realm for authorization of the client
   3230  * @param username the username to be authenticated, must be in clear text
   3231  *                 even if userhash is used by the client
   3232  * @param userdigest the precalculated binary hash of the string
   3233  *                   "username:realm:password",
   3234  *                   see #MHD_digest_auth_calc_userdigest()
   3235  * @param userdigest_size the size of the @a userdigest in bytes, must match the
   3236  *                        hashing algorithm (see #MHD_MD5_DIGEST_SIZE,
   3237  *                        #MHD_SHA256_DIGEST_SIZE, #MHD_SHA512_256_DIGEST_SIZE,
   3238  *                        #MHD_digest_get_hash_size())
   3239  * @param nonce_timeout the period of seconds since nonce generation, when
   3240  *                      the nonce is recognised as valid and not stale;
   3241  *                      if zero is specified then daemon default value is used.
   3242  * @param max_nc the maximum allowed nc (Nonce Count) value, if client's nc
   3243  *               exceeds the specified value then MHD_DAUTH_NONCE_STALE is
   3244  *               returned;
   3245  *               if zero is specified then daemon default value is used.
   3246  * @param mqop the QOP to use
   3247  * @param malgo3 digest algorithms allowed to use, fail if algorithm used
   3248  *               by the client is not allowed by this parameter;
   3249  *               more than one base algorithms (MD5, SHA-256, SHA-512/256)
   3250  *               cannot be used at the same time for this function
   3251  *               as @a userdigest must match specified algorithm
   3252  * @return #MHD_DAUTH_OK if authenticated,
   3253  *         the error code otherwise
   3254  * @sa #MHD_digest_auth_calc_userdigest()
   3255  * @note Available since #MHD_VERSION 0x00097708
   3256  * @ingroup authentication
   3257  */
   3258 _MHD_EXTERN enum MHD_DigestAuthResult
   3259 MHD_digest_auth_check_digest3 (struct MHD_Connection *connection,
   3260                                const char *realm,
   3261                                const char *username,
   3262                                const void *userdigest,
   3263                                size_t userdigest_size,
   3264                                unsigned int nonce_timeout,
   3265                                uint32_t max_nc,
   3266                                enum MHD_DigestAuthMultiQOP mqop,
   3267                                enum MHD_DigestAuthMultiAlgo3 malgo3)
   3268 {
   3269   if (1 != (((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_MD5)) ? 1 : 0)
   3270             + ((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_SHA256)) ? 1 : 0)
   3271             + ((0 != (malgo3 & MHD_DIGEST_BASE_ALGO_SHA512_256)) ? 1 : 0)))
   3272     MHD_PANIC (_ ("Wrong 'malgo3' value, only one base hashing algorithm " \
   3273                   "(MD5, SHA-256 or SHA-512/256) must be specified, " \
   3274                   "API violation"));
   3275 
   3276 #ifndef MHD_MD5_SUPPORT
   3277   if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_MD5))
   3278   {
   3279 #ifdef HAVE_MESSAGES
   3280     MHD_DLOG (connection->daemon,
   3281               _ ("The MD5 algorithm is not supported by this MHD build.\n"));
   3282 #endif /* HAVE_MESSAGES */
   3283     return MHD_DAUTH_WRONG_ALGO;
   3284   }
   3285 #endif /* ! MHD_MD5_SUPPORT */
   3286 #ifndef MHD_SHA256_SUPPORT
   3287   if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA256))
   3288   {
   3289 #ifdef HAVE_MESSAGES
   3290     MHD_DLOG (connection->daemon,
   3291               _ ("The SHA-256 algorithm is not supported by "
   3292                  "this MHD build.\n"));
   3293 #endif /* HAVE_MESSAGES */
   3294     return MHD_DAUTH_WRONG_ALGO;
   3295   }
   3296 #endif /* ! MHD_SHA256_SUPPORT */
   3297 #ifndef MHD_SHA512_256_SUPPORT
   3298   if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA512_256))
   3299   {
   3300 #ifdef HAVE_MESSAGES
   3301     MHD_DLOG (connection->daemon,
   3302               _ ("The SHA-512/256 algorithm is not supported by "
   3303                  "this MHD build.\n"));
   3304 #endif /* HAVE_MESSAGES */
   3305     return MHD_DAUTH_WRONG_ALGO;
   3306   }
   3307 #endif /* ! MHD_SHA512_256_SUPPORT */
   3308 
   3309   if (digest_get_hash_size ((enum MHD_DigestAuthAlgo3) malgo3) !=
   3310       userdigest_size)
   3311     MHD_PANIC (_ ("Wrong 'userdigest_size' value, does not match 'malgo3', "
   3312                   "API violation"));
   3313 
   3314   return digest_auth_check_all (connection,
   3315                                 realm,
   3316                                 username,
   3317                                 NULL,
   3318                                 (const uint8_t *) userdigest,
   3319                                 nonce_timeout,
   3320                                 max_nc,
   3321                                 mqop,
   3322                                 malgo3);
   3323 }
   3324 
   3325 
   3326 /**
   3327  * Authenticates the authorization header sent by the client.
   3328  *
   3329  * @param connection The MHD connection structure
   3330  * @param realm The realm presented to the client
   3331  * @param username The username needs to be authenticated
   3332  * @param password The password used in the authentication
   3333  * @param nonce_timeout The amount of time for a nonce to be
   3334  *      invalid in seconds
   3335  * @param algo digest algorithms allowed for verification
   3336  * @return #MHD_YES if authenticated, #MHD_NO if not,
   3337  *         #MHD_INVALID_NONCE if nonce is invalid or stale
   3338  * @note Available since #MHD_VERSION 0x00096200
   3339  * @deprecated use MHD_digest_auth_check3()
   3340  * @ingroup authentication
   3341  */
   3342 _MHD_EXTERN int
   3343 MHD_digest_auth_check2 (struct MHD_Connection *connection,
   3344                         const char *realm,
   3345                         const char *username,
   3346                         const char *password,
   3347                         unsigned int nonce_timeout,
   3348                         enum MHD_DigestAuthAlgorithm algo)
   3349 {
   3350   enum MHD_DigestAuthResult res;
   3351   enum MHD_DigestAuthMultiAlgo3 malgo3;
   3352 
   3353   if (MHD_DIGEST_ALG_AUTO == algo)
   3354     malgo3 = MHD_DIGEST_AUTH_MULT_ALGO3_ANY_NON_SESSION;
   3355   else if (MHD_DIGEST_ALG_MD5 == algo)
   3356     malgo3 = MHD_DIGEST_AUTH_MULT_ALGO3_MD5;
   3357   else if (MHD_DIGEST_ALG_SHA256 == algo)
   3358     malgo3 = MHD_DIGEST_AUTH_MULT_ALGO3_SHA256;
   3359   else
   3360     MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
   3361 
   3362   res = MHD_digest_auth_check3 (connection,
   3363                                 realm,
   3364                                 username,
   3365                                 password,
   3366                                 nonce_timeout,
   3367                                 0, MHD_DIGEST_AUTH_MULT_QOP_AUTH,
   3368                                 malgo3);
   3369   if (MHD_DAUTH_OK == res)
   3370     return MHD_YES;
   3371   else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res) ||
   3372            (MHD_DAUTH_NONCE_OTHER_COND == res) )
   3373     return MHD_INVALID_NONCE;
   3374   return MHD_NO;
   3375 
   3376 }
   3377 
   3378 
   3379 /**
   3380  * Authenticates the authorization header sent by the client.
   3381  *
   3382  * @param connection The MHD connection structure
   3383  * @param realm The realm presented to the client
   3384  * @param username The username needs to be authenticated
   3385  * @param digest An `unsigned char *' pointer to the binary MD5 sum
   3386  *      for the precalculated hash value "username:realm:password"
   3387  *      of @a digest_size bytes
   3388  * @param digest_size number of bytes in @a digest (size must match @a algo!)
   3389  * @param nonce_timeout The amount of time for a nonce to be
   3390  *      invalid in seconds
   3391  * @param algo digest algorithms allowed for verification
   3392  * @return #MHD_YES if authenticated, #MHD_NO if not,
   3393  *         #MHD_INVALID_NONCE if nonce is invalid or stale
   3394  * @note Available since #MHD_VERSION 0x00096200
   3395  * @deprecated use MHD_digest_auth_check_digest3()
   3396  * @ingroup authentication
   3397  */
   3398 _MHD_EXTERN int
   3399 MHD_digest_auth_check_digest2 (struct MHD_Connection *connection,
   3400                                const char *realm,
   3401                                const char *username,
   3402                                const uint8_t *digest,
   3403                                size_t digest_size,
   3404                                unsigned int nonce_timeout,
   3405                                enum MHD_DigestAuthAlgorithm algo)
   3406 {
   3407   enum MHD_DigestAuthResult res;
   3408   enum MHD_DigestAuthMultiAlgo3 malgo3;
   3409 
   3410   if (MHD_DIGEST_ALG_AUTO == algo)
   3411     malgo3 = MHD_DIGEST_AUTH_MULT_ALGO3_ANY_NON_SESSION;
   3412   else if (MHD_DIGEST_ALG_MD5 == algo)
   3413     malgo3 = MHD_DIGEST_AUTH_MULT_ALGO3_MD5;
   3414   else if (MHD_DIGEST_ALG_SHA256 == algo)
   3415     malgo3 = MHD_DIGEST_AUTH_MULT_ALGO3_SHA256;
   3416   else
   3417     MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
   3418 
   3419   res = MHD_digest_auth_check_digest3 (connection,
   3420                                        realm,
   3421                                        username,
   3422                                        digest,
   3423                                        digest_size,
   3424                                        nonce_timeout,
   3425                                        0, MHD_DIGEST_AUTH_MULT_QOP_AUTH,
   3426                                        malgo3);
   3427   if (MHD_DAUTH_OK == res)
   3428     return MHD_YES;
   3429   else if ((MHD_DAUTH_NONCE_STALE == res) || (MHD_DAUTH_NONCE_WRONG == res) ||
   3430            (MHD_DAUTH_NONCE_OTHER_COND == res) )
   3431     return MHD_INVALID_NONCE;
   3432   return MHD_NO;
   3433 }
   3434 
   3435 
   3436 /**
   3437  * Authenticates the authorization header sent by the client
   3438  * Uses #MHD_DIGEST_ALG_MD5 (required, as @a digest is of fixed
   3439  * size).
   3440  *
   3441  * @param connection The MHD connection structure
   3442  * @param realm The realm presented to the client
   3443  * @param username The username needs to be authenticated
   3444  * @param digest An `unsigned char *' pointer to the binary hash
   3445  *    for the precalculated hash value "username:realm:password";
   3446  *    length must be #MHD_MD5_DIGEST_SIZE bytes
   3447  * @param nonce_timeout The amount of time for a nonce to be
   3448  *      invalid in seconds
   3449  * @return #MHD_YES if authenticated, #MHD_NO if not,
   3450  *         #MHD_INVALID_NONCE if nonce is invalid or stale
   3451  * @note Available since #MHD_VERSION 0x00096000
   3452  * @deprecated use #MHD_digest_auth_check_digest3()
   3453  * @ingroup authentication
   3454  */
   3455 _MHD_EXTERN int
   3456 MHD_digest_auth_check_digest (struct MHD_Connection *connection,
   3457                               const char *realm,
   3458                               const char *username,
   3459                               const uint8_t digest[MHD_MD5_DIGEST_SIZE],
   3460                               unsigned int nonce_timeout)
   3461 {
   3462   return MHD_digest_auth_check_digest2 (connection,
   3463                                         realm,
   3464                                         username,
   3465                                         digest,
   3466                                         MHD_MD5_DIGEST_SIZE,
   3467                                         nonce_timeout,
   3468                                         MHD_DIGEST_ALG_MD5);
   3469 }
   3470 
   3471 
   3472 /**
   3473  * Internal version of #MHD_queue_auth_required_response3() to simplify
   3474  * cleanups.
   3475  *
   3476  * @param connection the MHD connection structure
   3477  * @param realm the realm presented to the client
   3478  * @param opaque the string for opaque value, can be NULL, but NULL is
   3479  *               not recommended for better compatibility with clients;
   3480  *               the recommended format is hex or Base64 encoded string
   3481  * @param domain the optional space-separated list of URIs for which the
   3482  *               same authorisation could be used, URIs can be in form
   3483  *               "path-absolute" (the path for the same host with initial slash)
   3484  *               or in form "absolute-URI" (the full path with protocol), in
   3485  *               any case client may assume that URI is in the same "protection
   3486  *               space" if it starts with any of values specified here;
   3487  *               could be NULL (clients typically assume that the same
   3488  *               credentials could be used for any URI on the same host)
   3489  * @param response the reply to send; should contain the "access denied"
   3490  *                 body; note that this function sets the "WWW Authenticate"
   3491  *                 header and that the caller should not do this;
   3492  *                 the NULL is tolerated
   3493  * @param signal_stale set to #MHD_YES if the nonce is stale to add 'stale=true'
   3494  *                     to the authentication header, this instructs the client
   3495  *                     to retry immediately with the new nonce and the same
   3496  *                     credentials, without asking user for the new password
   3497  * @param mqop the QOP to use
   3498  * @param malgo3 digest algorithm to use, MHD selects; if several algorithms
   3499  *               are allowed then MD5 is preferred (currently, may be changed
   3500  *               in next versions)
   3501  * @param userhash_support if set to non-zero value (#MHD_YES) then support of
   3502  *                         userhash is indicated, the client may provide
   3503  *                         hash("username:realm") instead of username in
   3504  *                         clear text;
   3505  *                         note that clients are allowed to provide the username
   3506  *                         in cleartext even if this parameter set to non-zero;
   3507  *                         when userhash is used, application must be ready to
   3508  *                         identify users by provided userhash value instead of
   3509  *                         username; see #MHD_digest_auth_calc_userhash() and
   3510  *                         #MHD_digest_auth_calc_userhash_hex()
   3511  * @param prefer_utf8 if not set to #MHD_NO, parameter 'charset=UTF-8' is
   3512  *                    added, indicating for the client that UTF-8 encoding
   3513  *                    is preferred
   3514  * @param prefer_utf8 if not set to #MHD_NO, parameter 'charset=UTF-8' is
   3515  *                    added, indicating for the client that UTF-8 encoding
   3516  *                    is preferred
   3517  * @return #MHD_YES on success, #MHD_NO otherwise
   3518  * @note Available since #MHD_VERSION 0x00097701
   3519  * @ingroup authentication
   3520  */
   3521 static enum MHD_Result
   3522 queue_auth_required_response3_inner (struct MHD_Connection *connection,
   3523                                      const char *realm,
   3524                                      const char *opaque,
   3525                                      const char *domain,
   3526                                      struct MHD_Response *response,
   3527                                      int signal_stale,
   3528                                      enum MHD_DigestAuthMultiQOP mqop,
   3529                                      enum MHD_DigestAuthMultiAlgo3 malgo3,
   3530                                      int userhash_support,
   3531                                      int prefer_utf8,
   3532                                      char **buf_ptr,
   3533                                      struct DigestAlgorithm *da)
   3534 {
   3535   static const char prefix_realm[] = "realm=\"";
   3536   static const char prefix_qop[] = "qop=\"";
   3537   static const char prefix_algo[] = "algorithm=";
   3538   static const char prefix_nonce[] = "nonce=\"";
   3539   static const char prefix_opaque[] = "opaque=\"";
   3540   static const char prefix_domain[] = "domain=\"";
   3541   static const char str_charset[] = "charset=UTF-8";
   3542   static const char str_userhash[] = "userhash=true";
   3543   static const char str_stale[] = "stale=true";
   3544   enum MHD_DigestAuthAlgo3 s_algo; /**< Selected algorithm */
   3545   size_t realm_len;
   3546   size_t opaque_len;
   3547   size_t domain_len;
   3548   size_t buf_size;
   3549   char *buf;
   3550   size_t p; /* The position in the buffer */
   3551   char *hdr_name;
   3552 
   3553   if ((0 == (((unsigned int) malgo3) & MHD_DIGEST_AUTH_ALGO3_NON_SESSION)) ||
   3554       (0 != (((unsigned int) malgo3) & MHD_DIGEST_AUTH_ALGO3_SESSION)))
   3555   {
   3556 #ifdef HAVE_MESSAGES
   3557     MHD_DLOG (connection->daemon,
   3558               _ ("Only non-'session' algorithms are supported.\n"));
   3559 #endif /* HAVE_MESSAGES */
   3560     return MHD_NO;
   3561   }
   3562   malgo3 =
   3563     (enum MHD_DigestAuthMultiAlgo3)
   3564     (malgo3
   3565      & (~((enum MHD_DigestAuthMultiAlgo3) MHD_DIGEST_AUTH_ALGO3_NON_SESSION)));
   3566 #ifdef MHD_MD5_SUPPORT
   3567   if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_MD5))
   3568     s_algo = MHD_DIGEST_AUTH_ALGO3_MD5;
   3569   else
   3570 #endif /* MHD_MD5_SUPPORT */
   3571 #ifdef MHD_SHA256_SUPPORT
   3572   if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA256))
   3573     s_algo = MHD_DIGEST_AUTH_ALGO3_SHA256;
   3574   else
   3575 #endif /* MHD_SHA256_SUPPORT */
   3576 #ifdef MHD_SHA512_256_SUPPORT
   3577   if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA512_256))
   3578     s_algo = MHD_DIGEST_AUTH_ALGO3_SHA512_256;
   3579   else
   3580 #endif /* MHD_SHA512_256_SUPPORT */
   3581   {
   3582     if (0 == (((unsigned int) malgo3)
   3583               & (MHD_DIGEST_BASE_ALGO_MD5 | MHD_DIGEST_BASE_ALGO_SHA256
   3584                  | MHD_DIGEST_BASE_ALGO_SHA512_256)))
   3585       MHD_PANIC (_ ("Wrong 'malgo3' value, API violation"));
   3586     else
   3587     {
   3588 #ifdef HAVE_MESSAGES
   3589       MHD_DLOG (connection->daemon,
   3590                 _ ("No requested algorithm is supported by this MHD build.\n"));
   3591 #endif /* HAVE_MESSAGES */
   3592     }
   3593     return MHD_NO;
   3594   }
   3595 
   3596   if (MHD_DIGEST_AUTH_MULT_QOP_AUTH_INT == mqop)
   3597     MHD_PANIC (_ ("Wrong 'mqop' value, API violation"));
   3598 
   3599   mqop = (enum MHD_DigestAuthMultiQOP)
   3600          (mqop
   3601           & (~((enum MHD_DigestAuthMultiQOP) MHD_DIGEST_AUTH_QOP_AUTH_INT)));
   3602 
   3603   if (! digest_init_one_time (da, get_base_digest_algo (s_algo)))
   3604     MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
   3605 
   3606   if (MHD_DIGEST_AUTH_MULT_QOP_NONE == mqop)
   3607   {
   3608 #ifdef HAVE_MESSAGES
   3609     if ((0 != userhash_support) || (0 != prefer_utf8))
   3610       MHD_DLOG (connection->daemon,
   3611                 _ ("The 'userhash' and 'charset' ('prefer_utf8') parameters " \
   3612                    "are not compatible with RFC2069 and ignored.\n"));
   3613     if (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5))
   3614       MHD_DLOG (connection->daemon,
   3615                 _ ("RFC2069 with SHA-256 or SHA-512/256 algorithm is " \
   3616                    "non-standard extension.\n"));
   3617 #endif
   3618     userhash_support = 0;
   3619     prefer_utf8 = 0;
   3620   }
   3621 
   3622   if (0 == MHD_get_master (connection->daemon)->nonce_nc_size)
   3623   {
   3624 #ifdef HAVE_MESSAGES
   3625     MHD_DLOG (connection->daemon,
   3626               _ ("The nonce array size is zero.\n"));
   3627 #endif /* HAVE_MESSAGES */
   3628     return MHD_NO;
   3629   }
   3630 
   3631   /* Calculate required size */
   3632   buf_size = 0;
   3633   /* 'Digest ' */
   3634   buf_size += MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE) + 1; /* 1 for ' ' */
   3635   buf_size += MHD_STATICSTR_LEN_ (prefix_realm) + 3; /* 3 for '", ' */
   3636   /* 'realm="xxxx", ' */
   3637   realm_len = strlen (realm);
   3638   if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < realm_len)
   3639   {
   3640 #ifdef HAVE_MESSAGES
   3641     MHD_DLOG (connection->daemon,
   3642               _ ("The 'realm' is too large.\n"));
   3643 #endif /* HAVE_MESSAGES */
   3644     return MHD_NO;
   3645   }
   3646   if ((NULL != memchr (realm, '\r', realm_len)) ||
   3647       (NULL != memchr (realm, '\n', realm_len)))
   3648     return MHD_NO;
   3649 
   3650   buf_size += realm_len * 2; /* Quoting may double the size */
   3651   /* 'qop="xxxx", ' */
   3652   if (MHD_DIGEST_AUTH_MULT_QOP_NONE != mqop)
   3653   {
   3654     buf_size += MHD_STATICSTR_LEN_ (prefix_qop) + 3; /* 3 for '", ' */
   3655     buf_size += MHD_STATICSTR_LEN_ (MHD_TOKEN_AUTH_);
   3656   }
   3657   /* 'algorithm="xxxx", ' */
   3658   if (((MHD_DIGEST_AUTH_MULT_QOP_NONE) != mqop) ||
   3659       (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5)))
   3660   {
   3661     buf_size += MHD_STATICSTR_LEN_ (prefix_algo) + 2; /* 2 for ', ' */
   3662 #ifdef MHD_MD5_SUPPORT
   3663     if (MHD_DIGEST_AUTH_ALGO3_MD5 == s_algo)
   3664       buf_size += MHD_STATICSTR_LEN_ (_MHD_MD5_TOKEN);
   3665     else
   3666 #endif /* MHD_MD5_SUPPORT */
   3667 #ifdef MHD_SHA256_SUPPORT
   3668     if (MHD_DIGEST_AUTH_ALGO3_SHA256 == s_algo)
   3669       buf_size += MHD_STATICSTR_LEN_ (_MHD_SHA256_TOKEN);
   3670     else
   3671 #endif /* MHD_SHA256_SUPPORT */
   3672 #ifdef MHD_SHA512_256_SUPPORT
   3673     if (MHD_DIGEST_AUTH_ALGO3_SHA512_256 == s_algo)
   3674       buf_size += MHD_STATICSTR_LEN_ (_MHD_SHA512_256_TOKEN);
   3675     else
   3676 #endif /* MHD_SHA512_256_SUPPORT */
   3677     mhd_assert (0);
   3678   }
   3679   /* 'nonce="xxxx", ' */
   3680   buf_size += MHD_STATICSTR_LEN_ (prefix_nonce) + 3; /* 3 for '", ' */
   3681   buf_size += NONCE_STD_LEN (digest_get_size (da)); /* Escaping not needed */
   3682   /* 'opaque="xxxx", ' */
   3683   if (NULL != opaque)
   3684   {
   3685     buf_size += MHD_STATICSTR_LEN_ (prefix_opaque) + 3; /* 3 for '", ' */
   3686     opaque_len = strlen (opaque);
   3687     if ((NULL != memchr (opaque, '\r', opaque_len)) ||
   3688         (NULL != memchr (opaque, '\n', opaque_len)))
   3689       return MHD_NO;
   3690 
   3691     buf_size += opaque_len * 2; /* Quoting may double the size */
   3692   }
   3693   else
   3694     opaque_len = 0;
   3695   /* 'domain="xxxx", ' */
   3696   if (NULL != domain)
   3697   {
   3698     buf_size += MHD_STATICSTR_LEN_ (prefix_domain) + 3; /* 3 for '", ' */
   3699     domain_len = strlen (domain);
   3700     if ((NULL != memchr (domain, '\r', domain_len)) ||
   3701         (NULL != memchr (domain, '\n', domain_len)))
   3702       return MHD_NO;
   3703 
   3704     buf_size += domain_len * 2; /* Quoting may double the size */
   3705   }
   3706   else
   3707     domain_len = 0;
   3708   /* 'charset=UTF-8' */
   3709   if (MHD_NO != prefer_utf8)
   3710     buf_size += MHD_STATICSTR_LEN_ (str_charset) + 2; /* 2 for ', ' */
   3711   /* 'userhash=true' */
   3712   if (MHD_NO != userhash_support)
   3713     buf_size += MHD_STATICSTR_LEN_ (str_userhash) + 2; /* 2 for ', ' */
   3714   /* 'stale=true' */
   3715   if (MHD_NO != signal_stale)
   3716     buf_size += MHD_STATICSTR_LEN_ (str_stale) + 2; /* 2 for ', ' */
   3717 
   3718   /* The calculated length is for string ended with ", ". One character will
   3719    * be used for zero-termination, the last one will not be used. */
   3720 
   3721   /* Allocate the buffer */
   3722   buf = malloc (buf_size);
   3723   if (NULL == buf)
   3724     return MHD_NO;
   3725   *buf_ptr = buf;
   3726 
   3727   /* Build the challenge string */
   3728   p = 0;
   3729   /* 'Digest: ' */
   3730   memcpy (buf + p, _MHD_AUTH_DIGEST_BASE,
   3731           MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE));
   3732   p += MHD_STATICSTR_LEN_ (_MHD_AUTH_DIGEST_BASE);
   3733   buf[p++] = ' ';
   3734   /* 'realm="xxxx", ' */
   3735   memcpy (buf + p, prefix_realm,
   3736           MHD_STATICSTR_LEN_ (prefix_realm));
   3737   p += MHD_STATICSTR_LEN_ (prefix_realm);
   3738   mhd_assert ((buf_size - p) >= (realm_len * 2));
   3739   if (1)
   3740   {
   3741     size_t quoted_size;
   3742     quoted_size = MHD_str_quote (realm, realm_len, buf + p, buf_size - p);
   3743     if (_MHD_AUTH_DIGEST_MAX_PARAM_SIZE < quoted_size)
   3744     {
   3745 #ifdef HAVE_MESSAGES
   3746       MHD_DLOG (connection->daemon,
   3747                 _ ("The 'realm' is too large after 'quoting'.\n"));
   3748 #endif /* HAVE_MESSAGES */
   3749       return MHD_NO;
   3750     }
   3751     p += quoted_size;
   3752   }
   3753   buf[p++] = '\"';
   3754   buf[p++] = ',';
   3755   buf[p++] = ' ';
   3756   /* 'qop="xxxx", ' */
   3757   if (MHD_DIGEST_AUTH_MULT_QOP_NONE != mqop)
   3758   {
   3759     memcpy (buf + p, prefix_qop,
   3760             MHD_STATICSTR_LEN_ (prefix_qop));
   3761     p += MHD_STATICSTR_LEN_ (prefix_qop);
   3762     memcpy (buf + p, MHD_TOKEN_AUTH_,
   3763             MHD_STATICSTR_LEN_ (MHD_TOKEN_AUTH_));
   3764     p += MHD_STATICSTR_LEN_ (MHD_TOKEN_AUTH_);
   3765     buf[p++] = '\"';
   3766     buf[p++] = ',';
   3767     buf[p++] = ' ';
   3768   }
   3769   /* 'algorithm="xxxx", ' */
   3770   if (((MHD_DIGEST_AUTH_MULT_QOP_NONE) != mqop) ||
   3771       (0 == (((unsigned int) s_algo) & MHD_DIGEST_BASE_ALGO_MD5)))
   3772   {
   3773     memcpy (buf + p, prefix_algo,
   3774             MHD_STATICSTR_LEN_ (prefix_algo));
   3775     p += MHD_STATICSTR_LEN_ (prefix_algo);
   3776 #ifdef MHD_MD5_SUPPORT
   3777     if (MHD_DIGEST_AUTH_ALGO3_MD5 == s_algo)
   3778     {
   3779       memcpy (buf + p, _MHD_MD5_TOKEN,
   3780               MHD_STATICSTR_LEN_ (_MHD_MD5_TOKEN));
   3781       p += MHD_STATICSTR_LEN_ (_MHD_MD5_TOKEN);
   3782     }
   3783     else
   3784 #endif /* MHD_MD5_SUPPORT */
   3785 #ifdef MHD_SHA256_SUPPORT
   3786     if (MHD_DIGEST_AUTH_ALGO3_SHA256 == s_algo)
   3787     {
   3788       memcpy (buf + p, _MHD_SHA256_TOKEN,
   3789               MHD_STATICSTR_LEN_ (_MHD_SHA256_TOKEN));
   3790       p += MHD_STATICSTR_LEN_ (_MHD_SHA256_TOKEN);
   3791     }
   3792     else
   3793 #endif /* MHD_SHA256_SUPPORT */
   3794 #ifdef MHD_SHA512_256_SUPPORT
   3795     if (MHD_DIGEST_AUTH_ALGO3_SHA512_256 == s_algo)
   3796     {
   3797       memcpy (buf + p, _MHD_SHA512_256_TOKEN,
   3798               MHD_STATICSTR_LEN_ (_MHD_SHA512_256_TOKEN));
   3799       p += MHD_STATICSTR_LEN_ (_MHD_SHA512_256_TOKEN);
   3800     }
   3801     else
   3802 #endif /* MHD_SHA512_256_SUPPORT */
   3803     mhd_assert (0);
   3804     buf[p++] = ',';
   3805     buf[p++] = ' ';
   3806   }
   3807   /* 'nonce="xxxx", ' */
   3808   memcpy (buf + p, prefix_nonce,
   3809           MHD_STATICSTR_LEN_ (prefix_nonce));
   3810   p += MHD_STATICSTR_LEN_ (prefix_nonce);
   3811   mhd_assert ((buf_size - p) >= (NONCE_STD_LEN (digest_get_size (da))));
   3812   if (! calculate_add_nonce_with_retry (connection, realm, da, buf + p))
   3813   {
   3814 #ifdef MHD_DIGEST_HAS_EXT_ERROR
   3815     if (digest_ext_error (da))
   3816     {
   3817 #ifdef HAVE_MESSAGES
   3818       MHD_DLOG (connection->daemon,
   3819                 _ ("TLS library reported hash calculation error, nonce could "
   3820                    "not be generated.\n"));
   3821 #endif /* HAVE_MESSAGES */
   3822       return MHD_NO;
   3823     }
   3824 #endif /* MHD_DIGEST_HAS_EXT_ERROR */
   3825 #ifdef HAVE_MESSAGES
   3826     MHD_DLOG (connection->daemon,
   3827               _ ("Could not register nonce. Client's requests with this "
   3828                  "nonce will be always 'stale'. Probably clients' requests "
   3829                  "are too intensive.\n"));
   3830 #endif /* HAVE_MESSAGES */
   3831     (void) 0; /* Mute compiler warning for builds without messages */
   3832   }
   3833   p += NONCE_STD_LEN (digest_get_size (da));
   3834   buf[p++] = '\"';
   3835   buf[p++] = ',';
   3836   buf[p++] = ' ';
   3837   /* 'opaque="xxxx", ' */
   3838   if (NULL != opaque)
   3839   {
   3840     memcpy (buf + p, prefix_opaque,
   3841             MHD_STATICSTR_LEN_ (prefix_opaque));
   3842     p += MHD_STATICSTR_LEN_ (prefix_opaque);
   3843     mhd_assert ((buf_size - p) >= (opaque_len * 2));
   3844     p += MHD_str_quote (opaque, opaque_len, buf + p, buf_size - p);
   3845     buf[p++] = '\"';
   3846     buf[p++] = ',';
   3847     buf[p++] = ' ';
   3848   }
   3849   /* 'domain="xxxx", ' */
   3850   if (NULL != domain)
   3851   {
   3852     memcpy (buf + p, prefix_domain,
   3853             MHD_STATICSTR_LEN_ (prefix_domain));
   3854     p += MHD_STATICSTR_LEN_ (prefix_domain);
   3855     mhd_assert ((buf_size - p) >= (domain_len * 2));
   3856     p += MHD_str_quote (domain, domain_len, buf + p, buf_size - p);
   3857     buf[p++] = '\"';
   3858     buf[p++] = ',';
   3859     buf[p++] = ' ';
   3860   }
   3861   /* 'charset=UTF-8' */
   3862   if (MHD_NO != prefer_utf8)
   3863   {
   3864     memcpy (buf + p, str_charset,
   3865             MHD_STATICSTR_LEN_ (str_charset));
   3866     p += MHD_STATICSTR_LEN_ (str_charset);
   3867     buf[p++] = ',';
   3868     buf[p++] = ' ';
   3869   }
   3870   /* 'userhash=true' */
   3871   if (MHD_NO != userhash_support)
   3872   {
   3873     memcpy (buf + p, str_userhash,
   3874             MHD_STATICSTR_LEN_ (str_userhash));
   3875     p += MHD_STATICSTR_LEN_ (str_userhash);
   3876     buf[p++] = ',';
   3877     buf[p++] = ' ';
   3878   }
   3879   /* 'stale=true' */
   3880   if (MHD_NO != signal_stale)
   3881   {
   3882     memcpy (buf + p, str_stale,
   3883             MHD_STATICSTR_LEN_ (str_stale));
   3884     p += MHD_STATICSTR_LEN_ (str_stale);
   3885     buf[p++] = ',';
   3886     buf[p++] = ' ';
   3887   }
   3888   mhd_assert (buf_size >= p);
   3889   /* The built string ends with ", ". Replace comma with zero-termination. */
   3890   --p;
   3891   buf[--p] = 0;
   3892 
   3893   hdr_name = malloc (MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_WWW_AUTHENTICATE) + 1);
   3894   if (NULL != hdr_name)
   3895   {
   3896     memcpy (hdr_name, MHD_HTTP_HEADER_WWW_AUTHENTICATE,
   3897             MHD_STATICSTR_LEN_ (MHD_HTTP_HEADER_WWW_AUTHENTICATE) + 1);
   3898     if (MHD_add_response_entry_no_alloc_ (response, MHD_HEADER_KIND,
   3899                                           hdr_name,
   3900                                           MHD_STATICSTR_LEN_ ( \
   3901                                             MHD_HTTP_HEADER_WWW_AUTHENTICATE),
   3902                                           buf, p))
   3903     {
   3904       *buf_ptr = NULL; /* The buffer will be free()ed when the response is destroyed */
   3905       return MHD_queue_response (connection, MHD_HTTP_UNAUTHORIZED, response);
   3906     }
   3907 #ifdef HAVE_MESSAGES
   3908     else
   3909     {
   3910       MHD_DLOG (connection->daemon,
   3911                 _ ("Failed to add Digest auth header.\n"));
   3912     }
   3913 #endif /* HAVE_MESSAGES */
   3914     free (hdr_name);
   3915   }
   3916   return MHD_NO;
   3917 }
   3918 
   3919 
   3920 /**
   3921  * Queues a response to request authentication from the client
   3922  *
   3923  * This function modifies provided @a response. The @a response must not be
   3924  * reused and should be destroyed (by #MHD_destroy_response()) after call of
   3925  * this function.
   3926  *
   3927  * If @a mqop allows both RFC 2069 (MHD_DIGEST_AUTH_QOP_NONE) and QOP with
   3928  * value, then response is formed like if MHD_DIGEST_AUTH_QOP_NONE bit was
   3929  * not set, because such response should be backward-compatible with RFC 2069.
   3930  *
   3931  * If @a mqop allows only MHD_DIGEST_AUTH_MULT_QOP_NONE, then the response is
   3932  * formed in strict accordance with RFC 2069 (no 'qop', no 'userhash', no
   3933  * 'charset'). For better compatibility with clients, it is recommended (but
   3934  * not required) to set @a domain to NULL in this mode.
   3935  *
   3936  * @param connection the MHD connection structure
   3937  * @param realm the realm presented to the client
   3938  * @param opaque the string for opaque value, can be NULL, but NULL is
   3939  *               not recommended for better compatibility with clients;
   3940  *               the recommended format is hex or Base64 encoded string
   3941  * @param domain the optional space-separated list of URIs for which the
   3942  *               same authorisation could be used, URIs can be in form
   3943  *               "path-absolute" (the path for the same host with initial slash)
   3944  *               or in form "absolute-URI" (the full path with protocol), in
   3945  *               any case client may assume that URI is in the same "protection
   3946  *               space" if it starts with any of values specified here;
   3947  *               could be NULL (clients typically assume that the same
   3948  *               credentials could be used for any URI on the same host);
   3949  *               this list provides information for the client only and does
   3950  *               not actually restrict anything on the server side
   3951  * @param response the reply to send; should contain the "access denied"
   3952  *                 body;
   3953  *                 note: this function sets the "WWW Authenticate" header and
   3954  *                 the caller should not set this header;
   3955  *                 the NULL is tolerated
   3956  * @param signal_stale if set to #MHD_YES then indication of stale nonce used in
   3957  *                     the client's request is signalled by adding 'stale=true'
   3958  *                     to the authentication header, this instructs the client
   3959  *                     to retry immediately with the new nonce and the same
   3960  *                     credentials, without asking user for the new password
   3961  * @param mqop the QOP to use
   3962  * @param malgo3 digest algorithm to use; if several algorithms are allowed
   3963  *               then MD5 is preferred (currently, may be changed in next
   3964  *               versions)
   3965  * @param userhash_support if set to non-zero value (#MHD_YES) then support of
   3966  *                         userhash is indicated, allowing client to provide
   3967  *                         hash("username:realm") instead of the username in
   3968  *                         clear text;
   3969  *                         note that clients are allowed to provide the username
   3970  *                         in cleartext even if this parameter set to non-zero;
   3971  *                         when userhash is used, application must be ready to
   3972  *                         identify users by provided userhash value instead of
   3973  *                         username; see #MHD_digest_auth_calc_userhash() and
   3974  *                         #MHD_digest_auth_calc_userhash_hex()
   3975  * @param prefer_utf8 if not set to #MHD_NO, parameter 'charset=UTF-8' is
   3976  *                    added, indicating for the client that UTF-8 encoding for
   3977  *                    the username is preferred
   3978  * @return #MHD_YES on success, #MHD_NO otherwise
   3979  * @note Available since #MHD_VERSION 0x00097701
   3980  * @ingroup authentication
   3981  */
   3982 _MHD_EXTERN enum MHD_Result
   3983 MHD_queue_auth_required_response3 (struct MHD_Connection *connection,
   3984                                    const char *realm,
   3985                                    const char *opaque,
   3986                                    const char *domain,
   3987                                    struct MHD_Response *response,
   3988                                    int signal_stale,
   3989                                    enum MHD_DigestAuthMultiQOP mqop,
   3990                                    enum MHD_DigestAuthMultiAlgo3 malgo3,
   3991                                    int userhash_support,
   3992                                    int prefer_utf8)
   3993 {
   3994   struct DigestAlgorithm da;
   3995   char *buf_ptr;
   3996   enum MHD_Result ret;
   3997 
   3998   buf_ptr = NULL;
   3999   digest_setup_zero (&da);
   4000   ret = queue_auth_required_response3_inner (connection,
   4001                                              realm,
   4002                                              opaque,
   4003                                              domain,
   4004                                              response,
   4005                                              signal_stale,
   4006                                              mqop,
   4007                                              malgo3,
   4008                                              userhash_support,
   4009                                              prefer_utf8,
   4010                                              &buf_ptr,
   4011                                              &da);
   4012   digest_deinit (&da);
   4013   if (NULL != buf_ptr)
   4014     free (buf_ptr);
   4015   return ret;
   4016 }
   4017 
   4018 
   4019 /**
   4020  * Queues a response to request authentication from the client
   4021  *
   4022  * @param connection The MHD connection structure
   4023  * @param realm the realm presented to the client
   4024  * @param opaque string to user for opaque value
   4025  * @param response reply to send; should contain the "access denied"
   4026  *        body; note that this function will set the "WWW Authenticate"
   4027  *        header and that the caller should not do this; the NULL is tolerated
   4028  * @param signal_stale #MHD_YES if the nonce is stale to add
   4029  *        'stale=true' to the authentication header
   4030  * @param algo digest algorithm to use
   4031  * @return #MHD_YES on success, #MHD_NO otherwise
   4032  * @note Available since #MHD_VERSION 0x00096200
   4033  * @ingroup authentication
   4034  */
   4035 _MHD_EXTERN enum MHD_Result
   4036 MHD_queue_auth_fail_response2 (struct MHD_Connection *connection,
   4037                                const char *realm,
   4038                                const char *opaque,
   4039                                struct MHD_Response *response,
   4040                                int signal_stale,
   4041                                enum MHD_DigestAuthAlgorithm algo)
   4042 {
   4043   enum MHD_DigestAuthMultiAlgo3 algo3;
   4044 
   4045   if (MHD_DIGEST_ALG_MD5 == algo)
   4046     algo3 = MHD_DIGEST_AUTH_MULT_ALGO3_MD5;
   4047   else if (MHD_DIGEST_ALG_SHA256 == algo)
   4048     algo3 = MHD_DIGEST_AUTH_MULT_ALGO3_SHA256;
   4049   else if (MHD_DIGEST_ALG_AUTO == algo)
   4050     algo3 = MHD_DIGEST_AUTH_MULT_ALGO3_ANY_NON_SESSION;
   4051   else
   4052     MHD_PANIC (_ ("Wrong algo value.\n")); /* API violation! */
   4053 
   4054   return MHD_queue_auth_required_response3 (connection, realm, opaque,
   4055                                             NULL, response, signal_stale,
   4056                                             MHD_DIGEST_AUTH_MULT_QOP_AUTH,
   4057                                             algo3,
   4058                                             0, 0);
   4059 }
   4060 
   4061 
   4062 /**
   4063  * Queues a response to request authentication from the client.
   4064  * For now uses MD5 (for backwards-compatibility). Still, if you
   4065  * need to be sure, use #MHD_queue_auth_fail_response2().
   4066  *
   4067  * @param connection The MHD connection structure
   4068  * @param realm the realm presented to the client
   4069  * @param opaque string to user for opaque value
   4070  * @param response reply to send; should contain the "access denied"
   4071  *        body; note that this function will set the "WWW Authenticate"
   4072  *        header and that the caller should not do this; the NULL is tolerated
   4073  * @param signal_stale #MHD_YES if the nonce is stale to add
   4074  *        'stale=true' to the authentication header
   4075  * @return #MHD_YES on success, #MHD_NO otherwise
   4076  * @ingroup authentication
   4077  * @deprecated use MHD_queue_auth_fail_response2()
   4078  */
   4079 _MHD_EXTERN enum MHD_Result
   4080 MHD_queue_auth_fail_response (struct MHD_Connection *connection,
   4081                               const char *realm,
   4082                               const char *opaque,
   4083                               struct MHD_Response *response,
   4084                               int signal_stale)
   4085 {
   4086   return MHD_queue_auth_fail_response2 (connection,
   4087                                         realm,
   4088                                         opaque,
   4089                                         response,
   4090                                         signal_stale,
   4091                                         MHD_DIGEST_ALG_MD5);
   4092 }
   4093 
   4094 
   4095 /* end of digestauth.c */