libmicrohttpd

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

digestauth.c (145350B)


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