libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

authentication.inc (34626B)


      1 @cindex authentication
      2 @noindent
      3 MHD supports three types of client authentication:
      4 
      5 @itemize
      6 
      7 @item Basic authentication uses a simple authentication method that
      8 transmits username and password in simple base64 encoding. Username
      9 and password are exchanged in cleartext between the client and the
     10 server, so this method must only be used for non-sensitive content or
     11 when the session is protected with TLS.  When using basic
     12 authentication MHD will have access to the clear password, possibly
     13 allowing the application to create a chained authentication toward an
     14 external authentication server.
     15 
     16 @item Digest authentication uses a one-way authentication method based on
     17 cryptographic hash algorithms. Only the hash is transmitted over the
     18 network, hence protecting the user's password. A nonce is used to
     19 prevent replay attacks. This method is appropriate for general use,
     20 especially when TLS is not used to encrypt the transmission.
     21 
     22 @item Client certificate authentication uses a X.509 certificate from the
     23 client. This is the strongest authentication mechanism and also
     24 requires the use of TLS. Client certificate authentication can be used
     25 simultaneously with Basic or Digest Authentication in order to provide
     26 a two levels authentication (like, for instance, separate machine and
     27 user authentication).
     28 
     29 @end itemize
     30 
     31 @menu
     32 * libmicrohttpd-bauth basic::      Using Basic Authentication.
     33 * libmicrohttpd-bauth example::    Example for Basic Authentication.
     34 * libmicrohttpd-dauth digest::     Using Digest Authentication.
     35 @c * libmicrohttpd-dauth example::    Example for Digest Authentication.
     36 @c * libmicrohttpd-dauth token::     Using Token Authentication.
     37 @c FIXME * libmicrohttpd-dauth tls::     Using TLS Client Authentication.
     38 @end menu
     39 
     40 
     41 @node libmicrohttpd-bauth basic
     42 @section Using Basic Authentication
     43 @cindex basic authentication
     44 
     45 @ref{MHD_LIB_INFO_FIXED_HAS_AUTH_BASIC,,@code{MHD_LIB_INFO_FIXED_HAS_AUTH_BASIC}}
     46 can be used to detect if the MHD build includes support for HTTP basic
     47 authorization.
     48 
     49 To use HTTP basic authentication, the HTTP server must first return a
     50 response with status @code{MHD_HTTP_STATUS_UNAUTHORIZED} asking the
     51 client to authenticate.  This is usually done @emph{after} checking
     52 whether the client did already authenticate, which we will look at
     53 later in this section.  To challenge a client to authenticate using
     54 HTTP basic authentication, MHD offers the
     55 @code{MHD_response_add_auth_basic_challenge()} function which
     56 @emph{modifies} an existing response, adding HTTP headers asking the
     57 client to authenticate.
     58 
     59 @deftypefun {enum MHD_StatusCode} MHD_response_add_auth_basic_challenge (struct MHD_Response *response, const char *realm, enum MHD_Bool prefer_utf8)
     60 
     61 Adds a basic authentication "challenge" to the response.  The
     62 @var{response} must use @code{MHD_HTTP_STATUS_UNAUTHORIZED} for its
     63 HTTP status code.
     64 
     65 If access to any resource should be limited to specific users,
     66 authenticated by basic authentication mechanism, and the request for
     67 this resource does not have basic authentication information
     68 (see @ref{MHD_AuthBasicCreds,,@code{MHD_AuthBasicCreds}}), then a
     69 response with a basic authentication "challenge" should be sent by
     70 extending an error response using this function. This works as an
     71 indication that basic authentication should be used for the access.
     72 
     73 See RFC 7617, section 2 for details.
     74 
     75 @table @var
     76 @item response
     77 the response to update; should contain the "access denied" body; note: this
     78   function sets the "WWW Authenticate" header and thus the caller
     79   should not set this header; the response must have
     80   @code{MHD_HTTP_STATUS_UNAUTHORIZED} HTTP status code; passing
     81   @code{NULL} is tolerated, in which case the result will be
     82   @code{MHD_SC_RESP_POINTER_NULL}
     83 
     84 @item realm
     85 the realm presented to the client
     86 
     87 @item prefer_utf8
     88 if not set to @code{MHD_NO} the parameter 'charset="UTF-8"'
     89 will be added, indicating for client that UTF-8 encoding is preferred
     90 
     91 @end table
     92 
     93 The function returns
     94 @itemize
     95 @item @code{MHD_SC_OK} if it succeeded
     96 @item @code{MHD_SC_TOO_LATE} if the response has been already "frozen" (used to create an action),
     97 @item @code{MHD_SC_RESP_HEADERS_CONFLICT} if a Basic Authentication "challenge" was already added,
     98 @item @code{MHD_SC_RESP_POINTER_NULL} if @var{response} was set to @code{NULL},
     99 @item @code{MHD_SC_RESP_HTTP_CODE_NOT_SUITABLE} is response status code is wrong,
    100 @item @code{MHD_SC_RESP_HEADER_VALUE_INVALID} if realm is zero-length or has CR or LF characters,
    101 @item @code{MHD_SC_RESPONSE_HEADER_MEM_ALLOC_FAILED} if memory allocation failed,
    102 @item or possibly other error codes (that could be defined in the future) on failure.
    103 @end itemize
    104 
    105 @end deftypefun
    106 
    107 @c FIXME: current header ONLY exports this API (and the _p/_a variants) if static inline is supported; that's not nice, API changes based on compiler.
    108 @c FIXME: also not convinced this API is even all that useful. Maybe remove?
    109 MHD provides a convenience API that adds the basic authentication challenge
    110 to response and turns it into the action to be returned
    111 from the @ref{MHD_RequestCallback,,@code{MHD_RequestCallback}}.
    112 
    113 @deftypefun {const struct MHD_Action *} MHD_action_basic_auth_challenge (struct MHD_Request *request, const char *realm, enum MHD_Bool prefer_utf8, struct MHD_Response *response, enum MHD_Bool abort_if_failed)
    114 
    115 Creates an action to reply with a basic authentication "challenge".
    116 The response must use @code{MHD_HTTP_STATUS_UNAUTHORIZED} for its HTTP
    117 status code.
    118 
    119 If access to any resource should be limited to specific users,
    120 authenticated by basic authentication mechanism, and the request for
    121 this resource does not have basic authentication information
    122 (see @ref{MHD_AuthBasicCreds,,@code{MHD_AuthBasicCreds}}), then a response with a basic
    123 authentication "challenge" should be sent by extending an error
    124 response using this function. This works as an indication that basic
    125 authentication should be used for the access.
    126 
    127 See RFC 7617, section-2 for details.
    128 
    129 @table @var
    130 @item request
    131 the client request to generate the action for
    132 
    133 @item realm
    134 the realm presented to the client
    135 
    136 @item response
    137 the reply to send; should contain the "access denied" body; note: this
    138   function sets the "WWW Authenticate" header and thus the caller
    139   should not set this header; the response must have
    140   @code{MHD_HTTP_STATUS_UNAUTHORIZED} HTTP status code; passing
    141   @code{NULL} is tolerated, in which case the result will be
    142   @code{MHD_SC_RESP_POINTER_NULL}
    143 
    144 @item prefer_utf8
    145 if not set to @code{MHD_NO} the parameter 'charset="UTF-8"'
    146 will be added, indicating for client that UTF-8 encoding is preferred
    147 
    148 @item abort_if_failed
    149 if set to @code{MHD_NO} the response will be returned even if
    150 MHD failed to add Basic Authentication "challenge",
    151 if set to @code{MHD_YES} the HTTP request will be aborted
    152 if the "challenge" could not be added.
    153 @end table
    154 @end deftypefun
    155 
    156 If the client has supplied an HTTP basic authorization header, the
    157 application can obtain the credentials using request introspection.
    158 @ref{MHD_REQUEST_INFO_DYNAMIC_AUTH_BASIC_CREDS,,@code{MHD_REQUEST_INFO_DYNAMIC_AUTH_BASIC_CREDS}}
    159 can be used to obtain the credentials as a @code{struct
    160 MHD_AuthBasicCreds}.
    161 
    162 @anchor{MHD_AuthBasicCreds}
    163 @deftp {C Struct} MHD_AuthBasicCreds username password
    164 
    165 Information decoded from a client's header with basic authentication data.
    166 @table @var
    167 @item @code{struct MHD_String} username
    168 The username;
    169 
    170 @item @code{struct MHD_StringNullable} password
    171 The password, string pointer may be @code{NULL} if
    172 the password is not properly encoded in the
    173 transmission from the client.
    174 @end table
    175 @end deftp
    176 
    177 @node libmicrohttpd-bauth example
    178 @section Example for Basic Authentication
    179 @cindex basic authentication
    180 
    181 
    182 @example
    183 @verbatiminclude examples/basic-authentication.c
    184 @end example
    185 
    186 
    187 
    188 @node libmicrohttpd-dauth digest
    189 @section Using Digest Authentication
    190 @cindex digest authentication
    191 
    192 @ref{MHD_LIB_INFO_FIXED_HAS_AUTH_DIGEST,,@code{MHD_LIB_INFO_FIXED_HAS_AUTH_DIGEST}}
    193 can be used to detect if the MHD build includes support for HTTP digest
    194 authorization.
    195 
    196 
    197 To use HTTP digest authentication, the HTTP server must first return a
    198 response with status @code{MHD_HTTP_STATUS_UNAUTHORIZED} asking the
    199 client to authenticate.  This is usually done @emph{after} checking
    200 whether the client did already authenticate, which we will look at
    201 later in this section.  To challenge a client to authenticate using
    202 HTTP digest authentication, MHD offers the
    203 @code{MHD_response_add_auth_digest_challenge()} function which
    204 @emph{modifies} an existing response, adding HTTP headers asking the
    205 client to authenticate.
    206 MHD supports various features of HTTP digest authentication, including
    207 various hash algorithms and levels of quality of protection (qop) which
    208 must be specified by the application when creating the challenge.
    209 
    210 @anchor{MHD_response_add_auth_digest_challenge}
    211 @deftypefun {enum MHD_StatusCode} MHD_response_add_auth_digest_challenge (struct MHD_Response *response, const char *realm, const char *opaque, const char *domain, enum MHD_Bool indicate_stale, enum MHD_DigestAuthMultiQOP mqop, enum MHD_DigestAuthMultiAlgo malgo, enum MHD_Bool userhash_support, enum MHD_Bool prefer_utf8)
    212 
    213 Adds a digest authentication "challenge" to the response.
    214 The @var{response} must use @code{MHD_HTTP_STATUS_UNAUTHORIZED} for its HTTP status code.
    215 
    216 @cindex qop
    217 If @var{mqop} allows both RFC 2069 (@code{MHD_DIGEST_AUTH_QOP_NONE})
    218 and other QOP values, then the "challenge" is formed like if
    219 @code{MHD_DIGEST_AUTH_QOP_NONE} bit was not set, because such
    220 a "challenge" should be backwards-compatible with RFC 2069.
    221 
    222 If @var{mqop} allows only @code{MHD_DIGEST_AUTH_MULT_QOP_NONE},
    223 then the response is formed in strict accordance with RFC 2069
    224 (no 'qop', no 'userhash', no 'charset').
    225 For better compatibility with clients, it is recommended (but
    226 not required) to set @var{domain} to @code{NULL} in this mode.
    227 
    228 New nonces are generated each time when the resulting response is
    229 used.
    230 
    231 See RFC 7616, section 3.3 for details.
    232 
    233 @table @var
    234 
    235 @item response
    236 the response to update; should contain the "access denied"
    237 body; note: this function sets the "WWW Authenticate" header and
    238 the caller should not set this header;
    239 the response must have a @code{MHD_HTTP_STATUS_UNAUTHORIZED} HTTP status
    240 code; a value of @code{NULL} is tolerated (the result will then be
    241 @code{MHD_SC_RESP_POINTER_NULL});
    242 
    243 @item realm
    244 the realm presented to the client;
    245 
    246 @item opaque
    247 the string for the opaque value, can be @code{NULL}, but @code{NULL} is
    248 not recommended for better compatibility with clients;
    249 the recommended format are string using hex or Base64 encoding;
    250 
    251 @item domain
    252 an optional space-separated list of URIs for which the
    253 same authorisation could be used, URIs can be in form
    254 "path-absolute" (the path for the same host with initial slash)
    255 or in form "absolute-URI" (the full path with protocol), in
    256 any case client may assume that URI is in the same "protection
    257 space" if it starts with any of values specified here;
    258 could be @code{NULL} (clients typically assume that the same
    259 credentials could be used for any URI on the same host);
    260 this list provides information for the client only and does
    261 not actually restrict anything on the server side;
    262 
    263 @item indicate_stale
    264 if set to @code{MHD_YES} then an indication of a stale nonce
    265 having been used in the client's request is indicated by adding
    266 ``stale=true'' to the authentication header; this
    267 instructs the client to retry immediately with the new
    268 nonce and the same credentials, without asking the user
    269 for the new password;
    270 
    271 @item mqop
    272 the quality of protection to use (see @ref{MHD_DigestAuthMultiQOP,,@code{MHD_DigestAuthMultiQOP}});
    273 
    274 @item algo
    275 digest algorithm to use; if several algorithms are allowed
    276 then one challenge for each allowed algorithm is added to the
    277 response (@xref{MHD_DigestAuthMultiAlgo});
    278 
    279 @item userhash_support
    280 if set to @code{MHD_YES} then support of the ``userhash'' variant is
    281 indicated, allowing the client to provide @code{hash("username:realm")}
    282 instead of the username in clear text;
    283 note that clients are @emph{allowed} to provide the username
    284 in cleartext even if this parameter set to @code{MHD_YES};
    285 when userhash is used, the application must be ready to
    286 identify users by provided userhash value instead of
    287 the plaintext username; see @ref{MHD_digest_auth_calc_userhash}
    288 @c and @ref{MHD_digest_auth_calc_userhash_hex}
    289 
    290 @item prefer_utf8
    291 if set to @code{MHD_YES}, the parameter ``charset=UTF-8'' is
    292 added, indicating to the client that UTF-8 encoding for
    293 the username is preferred
    294 @end table
    295 
    296 The function returns
    297 @itemize
    298 @item @code{MHD_SC_OK} if it succeeded
    299 @item @code{MHD_SC_TOO_LATE} if the response has been already "frozen" (used to create an action),
    300 @item @code{MHD_SC_RESP_HEADERS_CONFLICT} if a Basic Authentication "challenge" was already added,
    301 @item @code{MHD_SC_RESP_POINTER_NULL} if @var{response} was set to @code{NULL},
    302 @item @code{MHD_SC_RESP_HTTP_CODE_NOT_SUITABLE} is response status code is wrong,
    303 @item @code{MHD_SC_RESP_HEADER_VALUE_INVALID} if realm is zero-length or has CR or LF characters,
    304 @item @code{MHD_SC_RESPONSE_HEADER_MEM_ALLOC_FAILED} if memory allocation failed,
    305 @item or possibly other error codes (that could be defined in the future) on failure.
    306 @end itemize
    307 @end deftypefun
    308 
    309 
    310 @cindex qop
    311 @anchor{MHD_DigestAuthMultiQOP}
    312 @deftp {Enumeration} MHD_DigestAuthMultiQOP
    313 
    314 Quality of protection (QOP) levels supported by the server. Values of
    315 this enumeration can be combined with OR to create a bitmask, allowing
    316 the server to offer multiple protection levels to the client.
    317 
    318 @table @code
    319 
    320 @item MHD_DIGEST_AUTH_MULT_QOP_INVALID
    321 Invalid/unknown QOP.
    322 
    323 @item MHD_DIGEST_AUTH_MULT_QOP_NONE
    324 No QOP parameter.
    325 The digest authentication is to proceed as described in
    326 the old RFC 2069 original specification.
    327 This mode is not allowed by latest RFCs and should be used only to
    328 communicate with clients that do not support more modern modes (with QOP
    329 parameter).
    330 This mode is less secure than other modes and inefficient.
    331 
    332 @item MHD_DIGEST_AUTH_MULT_QOP_AUTH
    333 The 'auth' QOP type.
    334 
    335 @item MHD_DIGEST_AUTH_MULT_QOP_AUTH_INT
    336 The 'auth-int' QOP type. This value is @emph{not} actually supported by MHD.
    337 Reserved value.
    338 
    339 @item MHD_DIGEST_AUTH_MULT_QOP_ANY_NON_INT
    340 The 'auth' QOP type OR the old RFC2069 (no QOP) type.
    341 In other words: any types except 'auth-int'.
    342 RFC2069-compatible mode is allowed, thus this value should be used only
    343 when it is really necessary.
    344 
    345 @item MHD_DIGEST_AUTH_MULT_QOP_AUTH_ANY
    346 Any 'auth' QOP type ('auth' or 'auth-int').
    347 Currently supported by MHD as 'auth' QOP type only.
    348 
    349 @end table
    350 @end deftp
    351 
    352 
    353 @cindex hash
    354 @cindex digest
    355 @anchor{MHD_DigestAuthMultiAlgo}
    356 @deftp {Enumeration} MHD_DigestAuthMultiAlgo
    357 Which digest algorithm should be used. Values of
    358 this enumeration can be combined with OR to create a bitmask, allowing
    359 the server to offer multiple hash functions to the client.
    360 
    361 @table @code
    362 
    363 @item MHD_DIGEST_AUTH_MULT_ALGO_INVALID
    364 Unknown or invalid algorithm type.
    365 
    366 @item MHD_DIGEST_AUTH_MULT_ALGO_MD5
    367 The 'MD5' algorithm, non-session version. Deprecated, only use if you
    368 have legacy clients that require it.
    369 
    370 @item MHD_DIGEST_AUTH_MULT_ALGO_MD5_SESSION
    371 The 'MD5-sess' algorithm.
    372 Not actually supported by MHD for authentication.
    373 Reserved value.
    374 
    375 @item MHD_DIGEST_AUTH_MULT_ALGO_SHA256
    376 The 'SHA-256' algorithm, non-session version.
    377 
    378 @item MHD_DIGEST_AUTH_MULT_ALGO_SHA256_SESSION
    379 The 'SHA-256-sess' algorithm.
    380 Not supported by MHD for authentication.
    381 Reserved value.
    382 
    383 @item MHD_DIGEST_AUTH_MULT_ALGO_SHA512_256
    384 The 'SHA-512-256' (SHA-512/256) algorithm, non-session version.
    385 
    386 @item MHD_DIGEST_AUTH_MULT_ALGO_SHA512_256_SESSION
    387 The 'SHA-512-256-sess' (SHA-512/256 session) algorithm.
    388 Not supported by MHD for authentication.
    389 Reserved value.
    390 
    391 @item MHD_DIGEST_AUTH_MULT_ALGO_SHA_ANY_NON_SESSION
    392 SHA-256 or SHA-512/256 non-session algorithm, MHD will choose
    393 the preferred or the matching one.
    394 
    395 @item MHD_DIGEST_AUTH_MULT_ALGO_ANY_NON_SESSION
    396 Any non-session algorithm, MHD will choose the preferred or
    397 the matching one.
    398 
    399 @item MHD_DIGEST_AUTH_MULT_ALGO_SHA_ANY_SESSION
    400 The SHA-256 or SHA-512/256 session algorithm.
    401 Not supported by MHD.
    402 Reserved value.
    403 
    404 @item MHD_DIGEST_AUTH_MULT_ALGO_ANY_SESSION
    405 Any session algorithm.
    406 Not supported by MHD.
    407 Reserved value.
    408 
    409 @item MHD_DIGEST_AUTH_MULT_ALGO_MD5_ANY
    410 The MD5 algorithm, session or non-session.
    411 Currently supported as non-session only.
    412 
    413 @item MHD_DIGEST_AUTH_MULT_ALGO_SHA256_ANY
    414 The SHA-256 algorithm, session or non-session.
    415 Currently supported as non-session only.
    416 
    417 @item MHD_DIGEST_AUTH_MULT_ALGO_SHA512_256_ANY,
    418 The SHA-512/256 algorithm, session or non-session.
    419 Currently supported as non-session only.
    420 
    421 @item MHD_DIGEST_AUTH_MULT_ALGO_SHA_ANY_ANY
    422 The SHA-256 or SHA-512/256 algorithm, session or non-session.
    423 Currently supported as non-session only.
    424 
    425 @item MHD_DIGEST_AUTH_MULT_ALGO_ANY
    426 Any algorithm. When sending a challenge to the client,
    427 MHD will send challenges for each supported algorithms. When checking
    428 client requests with responses to challenges, MHD will allow
    429 the client to answer with any algorithm it supports.
    430 @end table
    431 @end deftp
    432 
    433 
    434 @c FIXME: did not document MHD_action_digest_auth_challenge (and _p/_a variants), again not always available (depends on static inline!)
    435 @c FIXME: not convinced we want to keep that, just looks like bloat,
    436 
    437 When using digest authentication with @var{userhash_support}, applications
    438 have to compute the @var{userhash} from the @var{username} and the
    439 @var{realm}. This can be done using @code{MHD_digest_auth_calc_userhash()}.
    440 
    441 
    442 
    443 @cindex userhash
    444 
    445 @anchor{MHD_digest_auth_calc_userhash}
    446 @deftypefun {enum MHD_StatusCode} MHD_digest_auth_calc_userhash (enum MHD_DigestAuthAlgo algo, const char *username, const char *realm, size_t bin_buf_size, void *userhash_bin)
    447 
    448 Calculates the @var{userhash_bin} and returns it as binary data.
    449 
    450 The "userhash" is the hash of the string "username:realm".
    451 
    452 The "userhash" can be used to avoid sending username in cleartext in
    453 a header when a client is using digest authorization.
    454 
    455 The userhash is not designed to hide the username in a local database or files, as the username in cleartext is still required for
    456 the @code{MHD_digest_auth_check_digest()} function to check the response,
    457 it can only can be used to hide the plaintext username in HTTP headers.
    458 
    459 This function could be used when the new username is added to a username
    460 database to save the "userhash" alongside with the username (preferably) or
    461 when loading list of the usernames to generate the userhash for every loaded
    462 username (this will cause delays at the start with longer lists).
    463 
    464 Once "userhash" is generated it could be used to identify users by clients
    465 with "userhash" support.
    466 
    467 The result of the computation may be cached and reused across requests.
    468 @table @var
    469 
    470 @item algo
    471 the hash algorithm to use for userhash calculations, see @ref{MHD_DigestAuthAlgorithm};
    472 
    473 @item username
    474 the username;
    475 
    476 @item realm
    477 the realm;
    478 
    479 @item bin_buf_size
    480 the size of the @var{userhash_bin} buffer, must be at least
    481 @code{#MHD_digest_get_hash_size()} bytes long;
    482 
    483 @item userhash_bin
    484 the output buffer for userhash as binary data;
    485 if this function succeeds, then this buffer will be set to
    486 @code{MHD_digest_get_hash_size()} bytes of userhash upon return;
    487 
    488 @end table
    489 
    490 Possible return values include:
    491 @itemize
    492 @item @code{MHD_SC_OK} on success,
    493 @item @code{MHD_SC_OUT_BUFF_TOO_SMALL} if @var{bin_buf_size} is too small,
    494 @item @code{MHD_SC_HASH_FAILED} if hashing failed, or
    495 @item @code{MHD_SC_AUTH_DIGEST_ALGO_NOT_SUPPORTED} if
    496    the requested @var{algo} is unknown or unsupported.
    497 @end itemize
    498 
    499 @end deftypefun
    500 
    501 Different hash algorithms can be specified for the
    502 @var{algo} when computing the userhash.
    503 
    504 @cindex hash
    505 @cindex digest
    506 @anchor{MHD_DigestAuthAlgorithm}
    507 @deftp {Enumeration} MHD_DigestAuthAlgorithm
    508 Which digest algorithm should be used.
    509 
    510 @table @code
    511 @item MHD_DIGEST_AUTH_ALGO_INVALID
    512 Unknown or invalid algorithm type. Using this value will cause MHD to fail.
    513 
    514 @item MHD_DIGEST_AUTH_ALGO_MD5
    515 Use (deprecated, ancient, insecure) MD5.
    516 
    517 @item MHD_DIGEST_AUTH_ALGO_MD5_SESSION
    518 Use (deprecated, ancient, insecure) MD5-sess. Not supported by MHD.
    519 
    520 @item MHD_DIGEST_ALG_SHA256
    521 Use SHA-256.
    522 
    523 @item MHD_DIGEST_ALG_SHA256_SESSION
    524 Use SHA-256-sess. Not supported by MHD.
    525 
    526 @item MHD_DIGEST_ALG_SHA512_256
    527 Use SHA-512_256.
    528 
    529 @item MHD_DIGEST_ALG_SHA512_256_SESSION
    530 Use SHA-512_256-sess. Not supported by MHD.
    531 
    532 @end table
    533 @end deftp
    534 
    535 Given a @ref{MHD_DigestAuthAlgorithm,,@code{MHD_DigestAuthAlgorithm}},
    536 @code{MHD_digest_get_hash_size()} can be used to determine the length
    537 of the corresponding binary hash value.
    538 
    539 
    540 @deftypefun {size_t} MHD_digest_get_hash_size (enum MHD_DigestAuthAlgo algo)
    541 
    542 Return the digest size in bytes for the specified hash algorithm @var{algo}.
    543 
    544 @table @var
    545 
    546 @item algo
    547 the hash algorithm to use for userhash calculations, see @ref{MHD_DigestAuthAlgorithm};
    548 @end table
    549 The function returns the number of bytes of a hash value of the
    550 given @var{algo}. It returns zero if @var{algo} is invalid or
    551 unknown.
    552 
    553 @end deftypefun
    554 
    555 
    556 @c FIXME: MHD_digest_auth_calc_userhash_hex not yet documented, why is this one useful in a MICRO-API that is supposed to be minimal? Do we want to keep it!?
    557 
    558 One key advantage of using digest authentication is not only that
    559 the password does not have to be transmitted in the clear, but
    560 also that the application does not need to store the user's password
    561 in cleartext. Instead, applications @emph{should} use
    562 @code{MHD_digest_auth_calc_userdigest()} to compute a hash of
    563 the user's credentials and only store the resulting digest.
    564 
    565 @cindex userdigest
    566 
    567 @anchor{MHD_digest_auth_calc_userdigest}
    568 @deftypefun {enum MHD_StatusCode} MHD_digest_auth_calc_userdigest (enum MHD_DigestAuthAlgo algo, const char *username, const char *realm, const char *password, size_t bin_buf_size, void *userhash_bin)
    569 
    570 Calculates a userdigest and returns it as a binary data.
    571 The "userdigest" is the hash of the "username:realm:password" string.
    572 The "userdigest" can be used to avoid storing the password in clear text
    573 in database/files of the application.
    574 
    575 This function is designed to improve security of stored credentials,
    576 using "userdigest" does not improve security of the authentication process.
    577 
    578 The result can be used to store @var{username} and @var{userdigest_bin} pairs instead of
    579 @var{username} and @var{password} pairs.
    580 To further improve privacy, application may
    581 store @var{username}, @var{userhash} and @var{userdigest} triplets
    582 and enable @var{userhash_support}.
    583 
    584 
    585 @table @var
    586 
    587 @item algo
    588 the hash algorithm to use for userhash calculations, see @ref{MHD_DigestAuthAlgorithm};
    589 
    590 @item username
    591 the username
    592 
    593 @item realm
    594 the realm
    595 
    596 @item password
    597 the password belonging to @var{username}
    598 
    599 @item bin_buf_size
    600 the size of the @var{userdigest_bin} buffer, must be at least
    601 @code{#MHD_digest_get_hash_size()} bytes long
    602 
    603 @item userdigest_bin
    604 the output buffer for userdigest as binary data;
    605 if this function succeeds, then this buffer will be set to
    606 @code{MHD_digest_get_hash_size()} bytes of userhash upon return
    607 
    608 @end table
    609 
    610 Possible return values include:
    611 @itemize
    612 @item @code{MHD_SC_OK} on success,
    613 @item @code{MHD_SC_OUT_BUFF_TOO_SMALL} if @var{bin_buf_size} is too small,
    614 @item @code{MHD_SC_HASH_FAILED} if hashing failed,
    615 @item @code{MHD_SC_AUTH_DIGEST_ALGO_NOT_SUPPORTED} if
    616    the requested @var{algo} is unknown or unsupported.
    617 @end itemize
    618 
    619 @end deftypefun
    620 
    621 When a client provides a digest authentication header, the application
    622 @emph{must} first use introspection using
    623 @ref{MHD_REQUEST_INFO_DYNAMIC_AUTH_DIGEST_INFO,,@code{MHD_REQUEST_INFO_DYNAMIC_AUTH_DIGEST_INFO}}
    624 to determine the client's identity and algorithmic choices.
    625 Introspection will return a @code{struct MHD_AuthDigestInfo}, or
    626 @code{NULL} if the client did not provide a digest
    627 authorization header.
    628 
    629 @c FIXME: MHD_REQUEST_INFO_DYNAMIC_AUTH_DIGEST_USERNAME is not discussed. When exactly is this necessary!? => will be removed.
    630 
    631 @anchor{MHD_AuthDigestInfo}
    632 @deftp {C Struct} MHD_AuthDigestInfo
    633 
    634 Information decoded from a client's header with digest authentication data.
    635 @table @var
    636 
    637 @item @code{enum MHD_DigestAuthAlgo} algo
    638 The algorithm as selected by the client.
    639 Set automatically to MD5 if not explicitly specified by client.
    640 
    641 @item @code{enum MHD_DigestAuthUsernameType} uname_type
    642 The type of username used by client.
    643 @xref{MHD_DigestAuthUsernameType}.
    644 
    645 @item @code{struct MHD_StringNullable} username
    646 The username as a string.
    647 Used only if @var{uname_type} is standard or extended, always
    648 @code{NULL} otherwise.
    649 If extended notation is used, this string is a pct-decoded string
    650 with charset and language tag removed (i.e. it is original username
    651 extracted from the extended notation).
    652 When userhash is used by the client, the string pointer is @code{NULL} and
    653 @var{userhash_hex} and @var{userhash_bin} will be set instead.
    654 
    655 @item @code{struct MHD_StringNullable} userhash_hex
    656 The userhash string.
    657 Valid only if @var{uname_type} is userhash.
    658 This is unqoted string without decoding of the hexadecimal
    659 digits (as provided by the client).
    660 @c FIXME: why do we return both the _hex and the _bin variants? Seems redundant!
    661 
    662 @item @code{const uint8_t *} userhash_bin
    663 The userhash decoded to binary form.
    664 Used only if @var{uname_type} is userhash, always @code{NULL} otherwise.
    665 When not @code{NULL}, this points to binary sequence of @var{userhash_bin_size} bytes.
    666 The valid size should be @code{MHD_digest_get_hash_size()} bytes.
    667 @emph{Warning:} This buffer points to binary data, there is no zero termination!
    668 @emph{Warning:} To avoid buffer overruns, always check the size of the data before
    669  use, because @var{userhash_bin} can point even to zero bytes of data.
    670 
    671 @item @code{size_t} userhash_bin_size
    672 The size of the data pointed by @var{userhash_bin}.
    673 Always zero when @var{userhash_bin} is @code{NULL}.
    674 
    675 @item @code{struct MHD_StringNullable} opaque
    676 The 'opaque' parameter value, as specified by client.
    677 If not specified by client then string pointer is @code{NULL}.
    678 
    679 @item @code{struct MHD_StringNullable} realm
    680 The 'realm' parameter value, as specified by client.
    681 If not specified by client then string pointer is @code{NULL}.
    682 
    683 @item @code{enum MHD_DigestAuthQOP} qop
    684 The quality of protection (qop) parameter value.
    685 
    686 @item @code{size_t} cnonce_len
    687 Length of the @var{cnonce} parameter, including possible
    688 backslash-escape characters. @var{cnonce} is used in hash
    689 calculation.
    690 An application may want to reject too large @var{cnonce}
    691 values to limit CPU load.
    692 A few kilobytes is a reasonable limit, typical values for
    693 @var{cnonce} should just use 32-160 characters.
    694 
    695 @item @code{enum MHD_DigestAuthNC} nc_type
    696 The type of the nonce count (nc) value provided in the request.
    697 @xref{MHD_DigestAuthNC}.
    698 
    699 @item @code{uint_fast32_t} nc
    700 The nonce count (nc) parameter value.
    701 Can be used by application to limit the number of nonce re-uses. If @var{nc}
    702 is higher than application wants to allow, then "auth required" response
    703 with ``stale=true'' could be used to force client to retry with the fresh
    704 @var{nonce}.
    705 Set to zero when @var{nc_type} is not set to
    706 @code{MHD_DIGEST_AUTH_NC_NUMBER}.
    707 
    708 @end table
    709 @end deftp
    710 
    711 The type of client nonce provided by the client is represented
    712 by an @code{enum MHD_DigestAuthNC}.
    713 
    714 @anchor{MHD_DigestAuthNC}
    715 @deftp {Enumeration} MHD_DigestAuthNC
    716 
    717 The type of nonce count (nc) value provided in the request.
    718 
    719 @table @code
    720 
    721 @item MHD_DIGEST_AUTH_NC_NUMBER
    722 Readable hexdecimal non-zero number.
    723 The decoded value is placed in the @var{nc} member of
    724 @ref{MHD_AuthDigestInfo,,@code{MHD_AuthDigestInfo}}.
    725 
    726 @item MHD_DIGEST_AUTH_NC_ZERO
    727 Readable zero number.
    728 Compliant clients should not use such values.
    729 Should probably be treated as an invalid request.
    730 
    731 @item MHD_DIGEST_AUTH_NC_NONE
    732 No @var{nc} value was provided by the client.
    733 Unless old RFC 2069 mode is allowed, this should be treated as an invalid
    734 request.
    735 
    736 @item MHD_DIGEST_AUTH_NC_TOO_LONG
    737 The provided ``nc'' value was too long to be decoded.
    738 Compliant clients should not use such values.
    739 Should be treated as an invalid request.
    740 
    741 @item MHD_DIGEST_AUTH_NC_TOO_LARGE
    742 The provided ``nc'' value was too large to fit into a @code{uint32_t}.
    743 Compliant clients should not use such values.
    744 Can be treated as request with a stale nonce or as an invalid request.
    745 
    746 @end table
    747 @end deftp
    748 
    749 @c FIXME: MHD_DigestAuthUsernameType not defined
    750 
    751 @anchor{MHD_DigestAuthUsernameType}
    752 @deftp {enum} MHD_DigestAuthUsernameType 
    753 
    754 Type of username encoded by the client in a digest authorization
    755 header.
    756 
    757 @table @var
    758 @item @code{MHD_DIGEST_AUTH_UNAME_TYPE_MISSING} 
    759   No username parameter is in Digest Authorization header.
    760   Not used currently. Value @code{MHD_SC_REQ_AUTH_DATA_BROKEN} is returned
    761   by @ref{MHD_request_get_info_dynamic_sz,,@code{MHD_request_get_info_dynamic_sz()}}
    762   if the request has no username.
    763 
    764 @item @code{MHD_DIGEST_AUTH_UNAME_TYPE_STANDARD}
    765   The 'username' parameter is used to specify the username.
    766 
    767 @item @code{MHD_DIGEST_AUTH_UNAME_TYPE_EXTENDED}
    768   The username is specified by 'username*' parameter with
    769   the extended notation (see RFC 5987, section-3.2.1).
    770   The only difference between standard and extended types is
    771   the way how username value is encoded in the header.
    772 
    773 @item @code{MHD_DIGEST_AUTH_UNAME_TYPE_USERHASH}
    774   The username provided in form of 'userhash' as
    775   specified by RFC 7616, section-3.4.4.
    776   @xref{MHD_digest_auth_calc_userhash,,@code{MHD_digest_auth_calc_userhash()}}.
    777 
    778 @item @code{MHD_DIGEST_AUTH_UNAME_TYPE_INVALID}
    779   The invalid combination of username parameters are used by client.
    780   Either:
    781   @itemize @bullet
    782   @item both 'username' and 'username*' are used
    783   @item 'username*' is used with 'userhash=true'
    784   @item 'username*' used with invalid extended notation
    785   @item 'username' is not hexadecimal string, while 'userhash' set to 'true'
    786   @end itemize
    787   Not used currently. Value @code{MHD_SC_REQ_AUTH_DATA_BROKEN} is returned by
    788   @ref{MHD_request_get_info_dynamic_sz,,@code{MHD_request_get_info_dynamic_sz()}}
    789   if the request has broken username.
    790 @end table
    791 @end deftp
    792 
    793 
    794 
    795 Finally, given the client's identity (username or userhash) the
    796 application must possibly determine the username from the userhash,
    797 and always determine the userdigest.  Given the @var{username} and
    798 @var{userdigest} and the set of algorithms allowed by the application,
    799 it can can use @code{MHD_digest_auth_check_digest()} to actually check
    800 the digest authentication provided by the client's request.
    801 
    802 @anchor{MHD_digest_auth_check_digest}
    803 @deftypefun {enum MHD_DigestAuthResult} MHD_digest_auth_check_digest (struct MHD_Request *request, const char *realm, const char *username, size_t userdigest_size, const void *userdigest, uint_fast32_t max_nc, enum MHD_DigestAuthMultiQOP mqop, enum MHD_DigestAuthMultiAlgo malgo)
    804 
    805 @cindex userdigest
    806 Authenticates the authorization header sent by the client by using
    807 hash of "username:realm:password".
    808 
    809 If RFC2069 mode is allowed by setting bit @code{MHD_DIGEST_AUTH_QOP_NONE} in
    810 @var{mqop} and the client uses this mode, then server generated nonces are
    811 used as one-time nonces because nonce-count is not supported in this old RFC.
    812 Communication in this mode is very inefficient, especially if the client
    813 requests several resources one-by-one as for every request a new nonce must
    814 be generated and client repeats all requests twice (first time to get a new
    815 nonce and second time to perform an authorised request).
    816 
    817 @table @var
    818 @item request
    819 the request;
    820 
    821 @item realm
    822 the realm for authorization of the client;
    823 
    824 @item username
    825 the username to be authenticated, must be in clear text
    826 even if userhash is used by the client;
    827 
    828 @item userdigest_size
    829 the size of the @var{userdigest} in bytes, must match the
    830 hashing algorithm;
    831 
    832 @item userdigest
    833 the precalculated binary hash of the string
    834 "username:realm:password";
    835 see @ref{MHD_digest_auth_calc_userdigest,,@code{MHD_digest_auth_calc_userdigest}};
    836 
    837 @item max_nc
    838 the maximum allowed nonce counter (nc) value, if a client's nc
    839 exceeds the specified value then @code{MHD_DAUTH_NONCE_STALE} is
    840 returned; if zero is specified the daemon's default value is used;
    841 
    842 @item mqop
    843 the quality of protection (QOP) level to use;
    844 
    845 @item malgo
    846 digest algorithms allowed to use, authentication will fail if
    847 the algorithm used by the client is not allowed by this parameter;
    848 only the base algorithms (MD5, SHA-256, SHA-512/256)
    849 cannot be used at the same time for this function
    850 as the @var{userdigest} must match specified algorithm;
    851 
    852 @end table
    853 
    854 The function returns the result of the authentication check.
    855 @xref{MHD_DigestAuthResult}.
    856 
    857 @end deftypefun
    858 
    859 @anchor{MHD_DigestAuthResult}
    860 @deftp {Enumeration} MHD_DigestAuthResult
    861 
    862 The result of digest authentication of the client.
    863 
    864 @table @code
    865 @item MHD_DAUTH_OK
    866 Authentication is OK;
    867 
    868 @item MHD_DAUTH_ERROR
    869 General error, like ``out of memory'';
    870 Authentication may be valid, but cannot be checked;
    871 
    872 @item MHD_DAUTH_HEADER_MISSING
    873 No "Authorization" header for digest authentication
    874 is present in the client's request.
    875 
    876 @item MHD_DAUTH_HEADER_BROKEN
    877 Header is in a wrong format.
    878 Also returned if required parameters in Authorization header are missing
    879 or broken.
    880 
    881 @item MHD_DAUTH_UNSUPPORTED_ALGO
    882 Unsupported algorithm used by the client.
    883 
    884 @item MHD_DAUTH_UNSUPPORTED_QOP
    885 Unsupported quality of protection (qop) level used by the client.
    886 
    887 @item MHD_DAUTH_INVALID_USERDIGEST_SIZE
    888 Incorrect userdigest size used by the client.
    889 
    890 @item MHD_DAUTH_WRONG_USERNAME
    891 Wrong 'username'.
    892 
    893 @item MHD_DAUTH_WRONG_REALM
    894 Wrong 'realm'.
    895 
    896 @item MHD_DAUTH_WRONG_URI
    897 Wrong 'URI' (or URI parameters).
    898 
    899 @item MHD_DAUTH_WRONG_QOP
    900 'qop' value specified by the client is not in the set of values
    901 allowed by the specification or the server disallowed the use of
    902 the given 'qop' mode.
    903 
    904 @item MHD_DAUTH_WRONG_ALGO
    905 The (hash) algorithm value specified by the client is not in the set of values
    906 allowed by the specification or the server disallowed the use of
    907 the given hash function mode.
    908 
    909 @item MHD_DAUTH_TOO_LARGE
    910 Too large (larger than 64 KiB) ``Authorization'' parameter value.
    911 
    912 @item MHD_DAUTH_NONCE_STALE
    913 The 'nonce' is too old. Suggest the client to retry with the same
    914 username and password to get the fresh 'nonce'.
    915 The validity of the 'nonce' may be not checked.
    916 
    917 @item MHD_DAUTH_NONCE_WRONG
    918 The 'nonce' is wrong. May indicate an attempted attack.
    919 
    920 @item MHD_DAUTH_RESPONSE_WRONG
    921 The 'response' is wrong. May indicate using the wrong password.
    922 
    923 @end table
    924 @end deftp
    925 
    926 
    927 @c @node libmicrohttpd-dauth example
    928 @c @section Example for Digest Authentication
    929 @c @cindex digest authentication
    930 
    931 @c FIXME: we should probably add an example here...
    932 
    933 @c @example
    934 @c @verbatiminclude examples/digest-authentication.c
    935 @c @end example