libmicrohttpd

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

commit bcba3f58c5fc9b4a3776494d3edddceb244ab110
parent 6bb3796f50f31bf6381c0ff0f082503597b1640f
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sat,  8 Dec 2018 17:35:37 +0100

preliminary implementation for RFC 7616 support

Diffstat:
MChangeLog | 4++++
Msrc/include/microhttpd.h | 114++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/microhttpd/Makefile.am | 9+++++----
Msrc/microhttpd/digestauth.c | 779++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Msrc/microhttpd/md5.c | 130++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/microhttpd/md5.h | 37++++++++++++++++++++-----------------
Msrc/microhttpd/sha256.c | 88++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/microhttpd/sha256.h | 45++++++++++++++++++++++++++++-----------------
8 files changed, 805 insertions(+), 401 deletions(-)

diff --git a/ChangeLog b/ChangeLog @@ -1,3 +1,7 @@ +Sat Dec 8 17:34:58 CET 2018 + Adding support for RFC 7616, experimental, needs + testing and documentation still! -CG + Fri Dec 7 12:37:17 CET 2018 Add option to build MHD without any threads and MHD_FEATURE_THREADS to test for it. -CG diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h @@ -3192,7 +3192,30 @@ MHD_free (void *ptr); /** - * Authenticates the authorization header sent by the client + * Which digest algorithm should MHD use for HTTP digest authentication? + */ +enum MHD_DigestAuthAlgorithm { + + /** + * MHD should pick (currently defaults to SHA-256). + */ + MHD_DIGEST_ALG_AUTO = 0, + + /** + * Force use of MD5. + */ + MHD_DIGEST_ALG_MD5, + + /** + * Force use of SHA-256. + */ + MHD_DIGEST_ALG_SHA256 + +}; + + +/** + * Authenticates the authorization header sent by the client. * * @param connection The MHD connection structure * @param realm The realm presented to the client @@ -3200,11 +3223,39 @@ MHD_free (void *ptr); * @param password The password used in the authentication * @param nonce_timeout The amount of time for a nonce to be * invalid in seconds + * @param algo digest algorithms allowed for verification * @return #MHD_YES if authenticated, #MHD_NO if not, * #MHD_INVALID_NONCE if nonce is invalid * @ingroup authentication */ _MHD_EXTERN int +MHD_digest_auth_check2 (struct MHD_Connection *connection, + const char *realm, + const char *username, + const char *password, + unsigned int nonce_timeout, + enum MHD_DigestAuthAlgorithm algo); + + +/** + * Authenticates the authorization header sent by the client. + * Uses #MHD_DIGEST_ALG_MD5 (for now, for backwards-compatibility). + * Note that this MAY change to #MHD_DIGEST_ALG_AUTO in the future. + * If you want to be sure you get MD5, use #MHD_digest_auth_check2() + * and specifiy MD5 explicitly. + * + * @param connection The MHD connection structure + * @param realm The realm presented to the client + * @param username The username needs to be authenticated + * @param password The password used in the authentication + * @param nonce_timeout The amount of time for a nonce to be + * invalid in seconds + * @return #MHD_YES if authenticated, #MHD_NO if not, + * #MHD_INVALID_NONCE if nonce is invalid + * @ingroup authentication + * @deprecated use MHD_digest_auth_check2() + */ +_MHD_EXTERN int MHD_digest_auth_check (struct MHD_Connection *connection, const char *realm, const char *username, @@ -3213,21 +3264,51 @@ MHD_digest_auth_check (struct MHD_Connection *connection, /** - * Authenticates the authorization header sent by the client + * Authenticates the authorization header sent by the client. * * @param connection The MHD connection structure * @param realm The realm presented to the client * @param username The username needs to be authenticated * @param digest An `unsigned char *' pointer to the binary MD5 sum * for the precalculated hash value "username:realm:password" - * of #MHD_MD5_DIGEST_SIZE bytes + * of @a digest_size bytes + * @param digest_size number of bytes in @a digest (size must match @a algo!) * @param nonce_timeout The amount of time for a nonce to be * invalid in seconds + * @param algo digest algorithms allowed for verification * @return #MHD_YES if authenticated, #MHD_NO if not, * #MHD_INVALID_NONCE if nonce is invalid * @ingroup authentication */ _MHD_EXTERN int +MHD_digest_auth_check_digest2 (struct MHD_Connection *connection, + const char *realm, + const char *username, + const uint8_t *digest, + size_t digest_size, + unsigned int nonce_timeout, + enum MHD_DigestAuthAlgorithm algo); + + +/** + * Authenticates the authorization header sent by the client + * Uses #MHD_DIGEST_ALG_MD5 (required, as @a digest is of fixed + * size). + * + * @param connection The MHD connection structure + * @param realm The realm presented to the client + * @param username The username needs to be authenticated + * @param digest An `unsigned char *' pointer to the binary hash + * for the precalculated hash value "username:realm:password"; + * length must be #MHD_MD5_DIGEST_SIZE bytes + * @param nonce_timeout The amount of time for a nonce to be + * invalid in seconds + * @return #MHD_YES if authenticated, #MHD_NO if not, + * #MHD_INVALID_NONCE if nonce is invalid + * @ingroup authentication + * @deprecated use #MHD_digest_auth_check_digest2() + */ +_MHD_EXTERN int MHD_digest_auth_check_digest (struct MHD_Connection *connection, const char *realm, const char *username, @@ -3239,6 +3320,32 @@ MHD_digest_auth_check_digest (struct MHD_Connection *connection, * Queues a response to request authentication from the client * * @param connection The MHD connection structure + * @param realm the realm presented to the client + * @param opaque string to user for opaque value + * @param response reply to send; should contain the "access denied" + * body; note that this function will set the "WWW Authenticate" + * header and that the caller should not do this + * @param signal_stale #MHD_YES if the nonce is invalid to add + * 'stale=true' to the authentication header + * @param algo digest algorithm to use + * @return #MHD_YES on success, #MHD_NO otherwise + * @ingroup authentication + */ +int +MHD_queue_auth_fail_response2 (struct MHD_Connection *connection, + const char *realm, + const char *opaque, + struct MHD_Response *response, + int signal_stale, + enum MHD_DigestAuthAlgorithm algo); + + +/** + * Queues a response to request authentication from the client + * For now uses MD5 (for backwards-compatibility). Still, if you + * need to be sure, use #MHD_queue_fail_auth_response2(). + * + * @param connection The MHD connection structure * @param realm The realm presented to the client * @param opaque string to user for opaque value * @param response reply to send; should contain the "access denied" @@ -3248,6 +3355,7 @@ MHD_digest_auth_check_digest (struct MHD_Connection *connection, * 'stale=true' to the authentication header * @return #MHD_YES on success, #MHD_NO otherwise * @ingroup authentication + * @deprecated use MHD_queue_auth_fail_response2() */ _MHD_EXTERN int MHD_queue_auth_fail_response (struct MHD_Connection *connection, diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am @@ -133,7 +133,8 @@ endif if ENABLE_DAUTH libmicrohttpd_la_SOURCES += \ digestauth.c \ - md5.c md5.h + md5.c md5.h \ + sha256.c sha256.h endif if ENABLE_BAUTH @@ -160,18 +161,18 @@ check_PROGRAMS = \ if HAVE_POSIX_THREADS if ENABLE_UPGRADE -if USE_POSIX_THREADS +if USE_POSIX_THREADS check_PROGRAMS += test_upgrade endif if USE_W32_THREADS check_PROGRAMS += test_upgrade endif if ENABLE_HTTPS -if USE_POSIX_THREADS +if USE_POSIX_THREADS check_PROGRAMS += test_upgrade_tls endif if USE_W32_THREADS -check_PROGRAMS += test_upgrade_tls +check_PROGRAMS += test_upgrade_tls endif endif endif diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c @@ -21,11 +21,13 @@ * @brief Implements HTTP digest authentication * @author Amr Ali * @author Matthieu Speder + * @author Christian Grothoff (RFC 7616 support) */ #include "platform.h" #include "mhd_limits.h" #include "internal.h" #include "md5.h" +#include "sha256.h" #include "mhd_mono_clock.h" #include "mhd_str.h" #include "mhd_compat.h" @@ -37,13 +39,18 @@ #include <windows.h> #endif /* MHD_W32_MUTEX_ */ -#define HASH_MD5_HEX_LEN (2 * MHD_MD5_DIGEST_SIZE) -/* 32 bit value is 4 bytes */ +/** + * 32 bit value is 4 bytes + */ #define TIMESTAMP_BIN_SIZE 4 -#define TIMESTAMP_HEX_LEN (2 * TIMESTAMP_BIN_SIZE) -/* Standard server nonce length, not including terminating null */ -#define NONCE_STD_LEN (HASH_MD5_HEX_LEN + TIMESTAMP_HEX_LEN) +/** + * Standard server nonce length, not including terminating null, + * + * @param digest_size digest size + */ +#define NONCE_STD_LEN(digest_size) \ + ((digest_size) * 2 + TIMESTAMP_BIN_SIZE * 2) /** * Beginning string for any valid Digest authentication header. @@ -63,7 +70,66 @@ /** * Maximum length of the response in digest authentication. */ -#define MAX_AUTH_RESPONSE_LENGTH 128 +#define MAX_AUTH_RESPONSE_LENGTH 256 + + +/** + * Context passed to functions that need to calculate + * a digest but are orthogonal to the specific + * algorithm. + */ +struct DigestAlgorithm +{ + /** + * Size of the final digest returned by @e digest. + */ + unsigned int digest_size; + + /** + * A context for the digest algorithm, already initialized to be + * useful for @e init, @e update and @e digest. + */ + void *ctx; + + /** + * Name of the algorithm, "md5" or "sha-256" + */ + const char *alg; + + /** + * Buffer of @e digest_size * 2 + 1 bytes. + */ + char *sessionkey; + + /** + * Call to initialize @e ctx. + */ + void + (*init)(void *ctx); + + /** + * Feed more data into the digest function. + * + * @param ctx context to feed + * @param length number of bytes in @a data + * @param data data to add + */ + void + (*update)(void *ctx, + const uint8_t *data, + size_t length); + + /** + * Compute final @a digest. + * + * @param ctx context to use + * @param digest[out] where to write the result, + * must be @e digest_length bytes long + */ + void + (*digest)(void *ctx, + uint8_t *digest); +}; /** @@ -97,54 +163,57 @@ cvthex (const unsigned char *bin, * and store the * result in 'sessionkey'. * * @param alg The hash algorithm used, can be "md5" or "md5-sess" + * or "sha-256" or "sha-256-sess" + * Note that the rest of the code does not support the the "-sess" variants! + * @param da[in,out] digest implementation, must match @a alg; the + * da->sessionkey will be initialized to the digest in HEX * @param digest An `unsigned char *' pointer to the binary MD5 sum * for the precalculated hash value "username:realm:password" - * of #MHD_MD5_DIGEST_SIZE bytes + * of #MHD_MD5_DIGEST_SIZE or #MHD_SHA256_DIGEST_SIZE bytes * @param nonce A `char *' pointer to the nonce value * @param cnonce A `char *' pointer to the cnonce value - * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes */ static void digest_calc_ha1_from_digest (const char *alg, - const uint8_t digest[MHD_MD5_DIGEST_SIZE], + struct DigestAlgorithm *da, + const uint8_t *digest, const char *nonce, - const char *cnonce, - char sessionkey[HASH_MD5_HEX_LEN + 1]) + const char *cnonce) { - struct MD5Context md5; - - if (MHD_str_equal_caseless_(alg, - "md5-sess")) + if ( (MHD_str_equal_caseless_(alg, + "md5-sess")) || + (MHD_str_equal_caseless_(alg, + "sha-256-sess")) ) { - unsigned char ha1[MHD_MD5_DIGEST_SIZE]; - - MD5Init (&md5); - MD5Update (&md5, - digest, - MHD_MD5_DIGEST_SIZE); - MD5Update (&md5, + uint8_t dig[da->digest_size]; + + da->init (da->ctx); + da->update (da->ctx, + digest, + MHD_MD5_DIGEST_SIZE); + da->update (da->ctx, + (const unsigned char *) ":", + 1); + da->update (da->ctx, + (const unsigned char *) nonce, + strlen (nonce)); + da->update (da->ctx, (const unsigned char *) ":", 1); - MD5Update (&md5, - (const unsigned char *) nonce, - strlen (nonce)); - MD5Update (&md5, - (const unsigned char *) ":", - 1); - MD5Update (&md5, - (const unsigned char *) cnonce, - strlen (cnonce)); - MD5Final (ha1, - &md5); - cvthex (ha1, - sizeof (ha1), - sessionkey); + da->update (da->ctx, + (const unsigned char *) cnonce, + strlen (cnonce)); + da->digest (da->ctx, + dig); + cvthex (dig, + sizeof (dig), + da->sessionkey); } else { cvthex (digest, - MHD_MD5_DIGEST_SIZE, - sessionkey); + da->digest_size, + da->sessionkey); } } @@ -154,12 +223,14 @@ digest_calc_ha1_from_digest (const char *alg, * and store the result in 'sessionkey'. * * @param alg The hash algorithm used, can be "md5" or "md5-sess" + * or "sha-256" or "sha-256-sess" * @param username A `char *' pointer to the username value * @param realm A `char *' pointer to the realm value * @param password A `char *' pointer to the password value * @param nonce A `char *' pointer to the nonce value * @param cnonce A `char *' pointer to the cnonce value - * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes + * @param da[in,out] digest algorithm to use, and where to write + * the sessionkey to */ static void digest_calc_ha1_from_user (const char *alg, @@ -168,52 +239,54 @@ digest_calc_ha1_from_user (const char *alg, const char *password, const char *nonce, const char *cnonce, - char sessionkey[HASH_MD5_HEX_LEN + 1]) + struct DigestAlgorithm *da) { - struct MD5Context md5; - unsigned char ha1[MHD_MD5_DIGEST_SIZE]; + unsigned char ha1[da->digest_size]; - MD5Init (&md5); - MD5Update (&md5, + da->init (da->ctx); + da->update (da->ctx, (const unsigned char *) username, strlen (username)); - MD5Update (&md5, - (const unsigned char *) ":", - 1); - MD5Update (&md5, - (const unsigned char *) realm, - strlen (realm)); - MD5Update (&md5, - (const unsigned char *) ":", - 1); - MD5Update (&md5, - (const unsigned char *) password, - strlen (password)); - MD5Final (ha1, - &md5); - digest_calc_ha1_from_digest(alg, - ha1, - nonce, - cnonce, - sessionkey); + da->update (da->ctx, + (const unsigned char *) ":", + 1); + da->update (da->ctx, + (const unsigned char *) realm, + strlen (realm)); + da->update (da->ctx, + (const unsigned char *) ":", + 1); + da->update (da->ctx, + (const unsigned char *) password, + strlen (password)); + da->digest (da->ctx, + ha1); + digest_calc_ha1_from_digest (alg, + da, + ha1, + nonce, + cnonce); } /** - * Calculate request-digest/response-digest as per RFC2617 spec + * Calculate request-digest/response-digest as per RFC2617 / RFC7616 + * spec. * - * @param ha1 H(A1) + * @param ha1 H(A1), twice the @a da->digest_size + 1 bytes (0-terminated), + * MUST NOT be aliased with `da->sessionkey`! * @param nonce nonce from server * @param noncecount 8 hex digits * @param cnonce client nonce - * @param qop qop-value: "", "auth" or "auth-int" + * @param qop qop-value: "", "auth" or "auth-int" (NOTE: only 'auth' is supported today.) * @param method method from request * @param uri requested URL * @param hentity H(entity body) if qop="auth-int" - * @param response request-digest or response-digest + * @param da[in,out] digest algorithm to use, also + * we write da->sessionkey (set to response request-digest or response-digest) */ static void -digest_calc_response (const char ha1[HASH_MD5_HEX_LEN + 1], +digest_calc_response (const char *ha1, const char *nonce, const char *noncecount, const char *cnonce, @@ -221,87 +294,85 @@ digest_calc_response (const char ha1[HASH_MD5_HEX_LEN + 1], const char *method, const char *uri, const char *hentity, - char response[HASH_MD5_HEX_LEN + 1]) + struct DigestAlgorithm *da) { - struct MD5Context md5; - unsigned char ha2[MHD_MD5_DIGEST_SIZE]; - unsigned char resphash[MHD_MD5_DIGEST_SIZE]; - char ha2hex[HASH_MD5_HEX_LEN + 1]; - (void)hentity; /* Unused. Silent compiler warning. */ - - MD5Init (&md5); - MD5Update (&md5, - (const unsigned char *) method, - strlen (method)); - MD5Update (&md5, - (const unsigned char *) ":", - 1); - MD5Update (&md5, + unsigned char ha2[da->digest_size]; + unsigned char resphash[da->digest_size]; + (void)hentity; /* Unused. Silence compiler warning. */ + + da->init (da->ctx); + da->update (da->ctx, + (const unsigned char *) method, + strlen (method)); + da->update (da->ctx, + (const unsigned char *) ":", + 1); + da->update (da->ctx, (const unsigned char *) uri, strlen (uri)); #if 0 - if (0 == strcasecmp(qop, - "auth-int")) + if (0 == strcasecmp (qop, + "auth-int")) { /* This is dead code since the rest of this module does not support auth-int. */ - MD5Update (&md5, - ":", - 1); + da->update (da->ctx, + ":", + 1); if (NULL != hentity) - MD5Update (&md5, - hentity, - strlen (hentity)); + da->update (da->ctx, + hentity, + strlen (hentity)); } #endif - MD5Final (ha2, - &md5); + da->digest (da->ctx, + ha2); cvthex (ha2, - MHD_MD5_DIGEST_SIZE, - ha2hex); - MD5Init (&md5); + da->digest_size, + da->sessionkey); + da->init (da->ctx); /* calculate response */ - MD5Update (&md5, - (const unsigned char *) ha1, - HASH_MD5_HEX_LEN); - MD5Update (&md5, - (const unsigned char *) ":", - 1); - MD5Update (&md5, - (const unsigned char *) nonce, - strlen (nonce)); - MD5Update (&md5, - (const unsigned char*) ":", - 1); + da->update (da->ctx, + (const unsigned char *) ha1, + da->digest_size * 2); + da->update (da->ctx, + (const unsigned char *) ":", + 1); + da->update (da->ctx, + (const unsigned char *) nonce, + strlen (nonce)); + da->update (da->ctx, + (const unsigned char*) ":", + 1); if ('\0' != *qop) { - MD5Update (&md5, - (const unsigned char *) noncecount, - strlen (noncecount)); - MD5Update (&md5, - (const unsigned char *) ":", - 1); - MD5Update (&md5, - (const unsigned char *) cnonce, - strlen (cnonce)); - MD5Update (&md5, - (const unsigned char *) ":", - 1); - MD5Update (&md5, - (const unsigned char *) qop, - strlen (qop)); - MD5Update (&md5, - (const unsigned char *) ":", - 1); + da->update (da->ctx, + (const unsigned char *) noncecount, + strlen (noncecount)); + da->update (da->ctx, + (const unsigned char *) ":", + 1); + da->update (da->ctx, + (const unsigned char *) cnonce, + strlen (cnonce)); + da->update (da->ctx, + (const unsigned char *) ":", + 1); + da->update (da->ctx, + (const unsigned char *) qop, + strlen (qop)); + da->update (da->ctx, + (const unsigned char *) ":", + 1); } - MD5Update (&md5, - (const unsigned char *) ha2hex, - HASH_MD5_HEX_LEN); - MD5Final (resphash, - &md5); + da->update (da->ctx, + (const unsigned char *) da->sessionkey, + da->digest_size * 2); + da->digest (da->ctx, + resphash); cvthex (resphash, sizeof(resphash), - response); + da->sessionkey); } @@ -552,7 +623,9 @@ MHD_digest_auth_get_username(struct MHD_Connection *connection) * @param rnd_size The size of the random seed array @a rnd * @param uri HTTP URI (in MHD, without the arguments ("?k=v") * @param realm A string of characters that describes the realm of auth. - * @param nonce A pointer to a character array for the nonce to put in + * @param da digest algorithm to use + * @param nonce A pointer to a character array for the nonce to put in, + * must provide NONCE_STD_LEN(da->digest_size)+1 bytes */ static void calculate_nonce (uint32_t nonce_time, @@ -561,48 +634,48 @@ calculate_nonce (uint32_t nonce_time, size_t rnd_size, const char *uri, const char *realm, - char nonce[NONCE_STD_LEN + 1]) + struct DigestAlgorithm *da, + char *nonce) { - struct MD5Context md5; unsigned char timestamp[TIMESTAMP_BIN_SIZE]; - unsigned char tmpnonce[MHD_MD5_DIGEST_SIZE]; - char timestamphex[TIMESTAMP_HEX_LEN + 1]; + unsigned char tmpnonce[da->digest_size]; + char timestamphex[TIMESTAMP_BIN_SIZE * 2 + 1]; - MD5Init (&md5); + da->init (da->ctx); timestamp[0] = (unsigned char)((nonce_time & 0xff000000) >> 0x18); timestamp[1] = (unsigned char)((nonce_time & 0x00ff0000) >> 0x10); timestamp[2] = (unsigned char)((nonce_time & 0x0000ff00) >> 0x08); timestamp[3] = (unsigned char)((nonce_time & 0x000000ff)); - MD5Update (&md5, - timestamp, - sizeof (timestamp)); - MD5Update (&md5, - (const unsigned char *) ":", - 1); - MD5Update (&md5, - (const unsigned char *) method, - strlen (method)); - MD5Update (&md5, - (const unsigned char *) ":", - 1); + da->update (da->ctx, + timestamp, + sizeof (timestamp)); + da->update (da->ctx, + (const unsigned char *) ":", + 1); + da->update (da->ctx, + (const unsigned char *) method, + strlen (method)); + da->update (da->ctx, + (const unsigned char *) ":", + 1); if (rnd_size > 0) - MD5Update (&md5, - (const unsigned char *) rnd, - rnd_size); - MD5Update (&md5, - (const unsigned char *) ":", - 1); - MD5Update (&md5, - (const unsigned char *) uri, - strlen (uri)); - MD5Update (&md5, - (const unsigned char *) ":", - 1); - MD5Update (&md5, - (const unsigned char *) realm, - strlen (realm)); - MD5Final (tmpnonce, - &md5); + da->update (da->ctx, + (const unsigned char *) rnd, + rnd_size); + da->update (da->ctx, + (const unsigned char *) ":", + 1); + da->update (da->ctx, + (const unsigned char *) uri, + strlen (uri)); + da->update (da->ctx, + (const unsigned char *) ":", + 1); + da->update (da->ctx, + (const unsigned char *) realm, + strlen (realm)); + da->digest (da->ctx, + tmpnonce); cvthex (tmpnonce, sizeof (tmpnonce), nonce); @@ -713,12 +786,15 @@ check_argument_match (struct MHD_Connection *connection, * Authenticates the authorization header sent by the client * * @param connection The MHD connection structure + * @param da[in,out] digest algorithm to use for checking (written to as + * part of the calculations, but the values left in the struct + * are not actually expected to be useful for the caller) * @param realm The realm presented to the client * @param username The username needs to be authenticated * @param password The password used in the authentication - * @param digest An optional `unsigned char *' pointer to the binary MD5 sum - * for the precalculated hash value "username:realm:password" - * of #MHD_MD5_DIGEST_SIZE bytes + * @param digest An optional binary hash + * of the precalculated hash value "username:realm:password" + * (must contain "da->digest_size" bytes or be NULL) * @param nonce_timeout The amount of time for a nonce to be * invalid in seconds * @return #MHD_YES if authenticated, #MHD_NO if not, @@ -727,10 +803,11 @@ check_argument_match (struct MHD_Connection *connection, */ static int digest_auth_check_all (struct MHD_Connection *connection, + struct DigestAlgorithm *da, const char *realm, const char *username, const char *password, - const uint8_t digest[MHD_MD5_DIGEST_SIZE], + const uint8_t *digest, unsigned int nonce_timeout) { struct MHD_Daemon *daemon = connection->daemon; @@ -738,13 +815,12 @@ digest_auth_check_all (struct MHD_Connection *connection, const char *header; char nonce[MAX_NONCE_LENGTH]; char cnonce[MAX_NONCE_LENGTH]; + char ha1[da->digest_size * 2 + 1]; char qop[15]; /* auth,auth-int */ char nc[20]; char response[MAX_AUTH_RESPONSE_LENGTH]; const char *hentity = NULL; /* "auth-int" is not supported */ - char ha1[HASH_MD5_HEX_LEN + 1]; - char respexp[HASH_MD5_HEX_LEN + 1]; - char noncehashexp[NONCE_STD_LEN + 1]; + char noncehashexp[NONCE_STD_LEN(da->digest_size) + 1]; uint32_t nonce_time; uint32_t t; size_t left; /* number of characters left in 'header' for 'uri' */ @@ -807,9 +883,9 @@ digest_auth_check_all (struct MHD_Connection *connection, header value. */ return MHD_NO; } - if (TIMESTAMP_HEX_LEN != - MHD_strx_to_uint32_n_ (nonce + len - TIMESTAMP_HEX_LEN, - TIMESTAMP_HEX_LEN, + if (TIMESTAMP_BIN_SIZE * 2 != + MHD_strx_to_uint32_n_ (nonce + len - TIMESTAMP_BIN_SIZE * 2, + TIMESTAMP_BIN_SIZE * 2, &nonce_time)) { #ifdef HAVE_MESSAGES @@ -837,6 +913,7 @@ digest_auth_check_all (struct MHD_Connection *connection, daemon->digest_auth_rand_size, connection->url, realm, + da, noncehashexp); /* * Second level vetting for the nonce validity @@ -848,7 +925,8 @@ digest_auth_check_all (struct MHD_Connection *connection, * very hard to achieve. */ - if (0 != strcmp (nonce, noncehashexp)) + if (0 != strcmp (nonce, + noncehashexp)) { return MHD_INVALID_NONCE; } @@ -908,40 +986,45 @@ digest_auth_check_all (struct MHD_Connection *connection, uri = malloc (left + 1); if (NULL == uri) - { + { #ifdef HAVE_MESSAGES - MHD_DLOG(daemon, - _("Failed to allocate memory for auth header processing\n")); + MHD_DLOG(daemon, + _("Failed to allocate memory for auth header processing\n")); #endif /* HAVE_MESSAGES */ - return MHD_NO; - } + return MHD_NO; + } if (0 == lookup_sub_value (uri, left + 1, header, "uri")) - { - free (uri); - return MHD_NO; - } - + { + free (uri); + return MHD_NO; + } if (NULL != digest) { - digest_calc_ha1_from_digest ("md5", + /* This will initialize da->sessionkey (ha1) */ + digest_calc_ha1_from_digest (da->alg, + da, digest, nonce, - cnonce, - ha1); + cnonce); } else { - digest_calc_ha1_from_user ("md5", + /* This will initialize da->sessionkey (ha1) */ + digest_calc_ha1_from_user (da->alg, username, realm, password, nonce, cnonce, - ha1); + da); } + memcpy (ha1, + da->sessionkey, + sizeof (ha1)); + /* This will initialize da->sessionkey (respexp) */ digest_calc_response (ha1, nonce, nc, @@ -950,7 +1033,7 @@ digest_auth_check_all (struct MHD_Connection *connection, connection->method, uri, hentity, - respexp); + da); /* Need to unescape URI before comparing with connection->url */ @@ -991,7 +1074,7 @@ digest_auth_check_all (struct MHD_Connection *connection, } free (uri); return (0 == strcmp (response, - respexp)) + da->sessionkey)) ? MHD_YES : MHD_NO; } @@ -999,7 +1082,11 @@ digest_auth_check_all (struct MHD_Connection *connection, /** - * Authenticates the authorization header sent by the client + * Authenticates the authorization header sent by the client. + * Uses #MHD_DIGEST_ALG_MD5 (for now, for backwards-compatibility). + * Note that this MAY change to #MHD_DIGEST_ALG_AUTO in the future. + * If you want to be sure you get MD5, use #MHD_digest_auth_check2 + * and specifiy MD5 explicitly. * * @param connection The MHD connection structure * @param realm The realm presented to the client @@ -1018,7 +1105,85 @@ MHD_digest_auth_check (struct MHD_Connection *connection, const char *password, unsigned int nonce_timeout) { + return MHD_digest_auth_check2 (connection, + realm, + username, + password, + nonce_timeout, + MHD_DIGEST_ALG_MD5); +} + + +/** + * Setup digest authentication data structures (on the + * stack, hence must be done inline!). Initializes a + * "struct DigestAlgorithm da" for algorithm @a algo. + * + * @param algo digest algorithm to provide + * @param da data structure to setup + */ +#define SETUP_DA(algo,da) \ + union { \ + struct MD5Context md5; \ + struct sha256_ctx sha256; \ + } ctx; \ + union { \ + char md5[MD5_DIGEST_SIZE * 2 + 1]; \ + char sha256[SHA256_DIGEST_SIZE * 2 + 1]; \ + } skey; \ + struct DigestAlgorithm da; \ + \ + switch (algo) { \ + case MHD_DIGEST_ALG_MD5: \ + da.digest_size = MD5_DIGEST_SIZE; \ + da.ctx = &ctx.md5; \ + da.alg = "md5"; \ + da.sessionkey = skey.md5; \ + da.init = &MD5Init; \ + da.update = &MD5Update; \ + da.digest = &MD5Final; \ + break; \ + case MHD_DIGEST_ALG_AUTO: \ + /* auto == SHA256, fall-though thus intentional! */ \ + case MHD_DIGEST_ALG_SHA256: \ + da.digest_size = SHA256_DIGEST_SIZE; \ + da.ctx = &ctx.sha256; \ + da.alg = "sha-256"; \ + da.sessionkey = skey.sha256; \ + da.init = &sha256_init; \ + da.update = &sha256_update; \ + da.digest = &sha256_digest; \ + break; \ + } + + + +/** + * Authenticates the authorization header sent by the client. + * + * @param connection The MHD connection structure + * @param realm The realm presented to the client + * @param username The username needs to be authenticated + * @param password The password used in the authentication + * @param nonce_timeout The amount of time for a nonce to be + * invalid in seconds + * @param algo digest algorithms allowed for verification + * @return #MHD_YES if authenticated, #MHD_NO if not, + * #MHD_INVALID_NONCE if nonce is invalid + * @ingroup authentication + */ +_MHD_EXTERN int +MHD_digest_auth_check2 (struct MHD_Connection *connection, + const char *realm, + const char *username, + const char *password, + unsigned int nonce_timeout, + enum MHD_DigestAuthAlgorithm algo) +{ + SETUP_DA (algo, da); + return digest_auth_check_all (connection, + &da, realm, username, password, @@ -1028,7 +1193,7 @@ MHD_digest_auth_check (struct MHD_Connection *connection, /** - * Authenticates the authorization header sent by the client + * Authenticates the authorization header sent by the client. * * @param connection The MHD connection structure * @param realm The realm presented to the client @@ -1036,20 +1201,29 @@ MHD_digest_auth_check (struct MHD_Connection *connection, * @param digest An `unsigned char *' pointer to the binary MD5 sum * for the precalculated hash value "username:realm:password" * of #MHD_MD5_DIGEST_SIZE bytes + * @param digest_size number of bytes in @a digest * @param nonce_timeout The amount of time for a nonce to be * invalid in seconds + * @param algo digest algorithms allowed for verification * @return #MHD_YES if authenticated, #MHD_NO if not, * #MHD_INVALID_NONCE if nonce is invalid * @ingroup authentication */ _MHD_EXTERN int -MHD_digest_auth_check_digest (struct MHD_Connection *connection, - const char *realm, - const char *username, - const uint8_t digest[MD5_DIGEST_SIZE], - unsigned int nonce_timeout) +MHD_digest_auth_check_digest2 (struct MHD_Connection *connection, + const char *realm, + const char *username, + const uint8_t *digest, + size_t digest_size, + unsigned int nonce_timeout, + enum MHD_DigestAuthAlgorithm algo) { + SETUP_DA (algo, da); + + if (da.digest_size != digest_size) + MHD_PANIC (_("digest size missmatch")); /* API violation! */ return digest_auth_check_all (connection, + &da, realm, username, NULL, @@ -1059,6 +1233,40 @@ MHD_digest_auth_check_digest (struct MHD_Connection *connection, /** + * Authenticates the authorization header sent by the client. + * Uses #MHD_DIGEST_ALG_MD5 (required, as @a digest is of fixed + * size). + * + * @param connection The MHD connection structure + * @param realm The realm presented to the client + * @param username The username needs to be authenticated + * @param digest An `unsigned char *' pointer to the binary digest + * for the precalculated hash value "username:realm:password" + * of @a digest_size bytes + * @param nonce_timeout The amount of time for a nonce to be + * invalid in seconds + * @return #MHD_YES if authenticated, #MHD_NO if not, + * #MHD_INVALID_NONCE if nonce is invalid + * @ingroup authentication + */ +_MHD_EXTERN int +MHD_digest_auth_check_digest (struct MHD_Connection *connection, + const char *realm, + const char *username, + const uint8_t digest[MHD_MD5_DIGEST_SIZE], + unsigned int nonce_timeout) +{ + return MHD_digest_auth_check_digest2 (connection, + realm, + username, + digest, + MHD_MD5_DIGEST_SIZE, + nonce_timeout, + MHD_DIGEST_ALG_MD5); +} + + +/** * Queues a response to request authentication from the client * * @param connection The MHD connection structure @@ -1069,81 +1277,90 @@ MHD_digest_auth_check_digest (struct MHD_Connection *connection, * header and that the caller should not do this * @param signal_stale #MHD_YES if the nonce is invalid to add * 'stale=true' to the authentication header + * @param algo digest algorithm to use * @return #MHD_YES on success, #MHD_NO otherwise * @ingroup authentication */ int -MHD_queue_auth_fail_response (struct MHD_Connection *connection, - const char *realm, - const char *opaque, - struct MHD_Response *response, - int signal_stale) +MHD_queue_auth_fail_response2 (struct MHD_Connection *connection, + const char *realm, + const char *opaque, + struct MHD_Response *response, + int signal_stale, + enum MHD_DigestAuthAlgorithm algo) { int ret; int hlen; - char nonce[NONCE_STD_LEN + 1]; - - /* Generating the server nonce */ - calculate_nonce ((uint32_t) MHD_monotonic_sec_counter(), - connection->method, - connection->daemon->digest_auth_random, - connection->daemon->digest_auth_rand_size, - connection->url, - realm, - nonce); - if (MHD_YES != - check_nonce_nc (connection, - nonce, - 0)) - { + SETUP_DA (algo, da); + + { + char nonce[NONCE_STD_LEN(da.digest_size) + 1]; + /* Generating the server nonce */ + calculate_nonce ((uint32_t) MHD_monotonic_sec_counter(), + connection->method, + connection->daemon->digest_auth_random, + connection->daemon->digest_auth_rand_size, + connection->url, + realm, + &da, + nonce); + if (MHD_YES != + check_nonce_nc (connection, + nonce, + 0)) + { #ifdef HAVE_MESSAGES - MHD_DLOG (connection->daemon, - _("Could not register nonce (is the nonce array size zero?).\n")); + MHD_DLOG (connection->daemon, + _("Could not register nonce (is the nonce array size zero?).\n")); #endif - return MHD_NO; - } - /* Building the authentication header */ - hlen = MHD_snprintf_ (NULL, - 0, - "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s", - realm, - nonce, - opaque, - signal_stale - ? ",stale=\"true\"" - : ""); - if (hlen > 0) - { - char *header; + return MHD_NO; + } + /* Building the authentication header */ + hlen = MHD_snprintf_ (NULL, + 0, + "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\",algorithm=%s%s", + realm, + nonce, + opaque, + da.alg, + signal_stale + ? ",stale=\"true\"" + : ""); + if (hlen > 0) + { + char *header; - header = MHD_calloc_ (1, hlen + 1); - if (NULL == header) - { + header = MHD_calloc_ (1, + hlen + 1); + if (NULL == header) + { #ifdef HAVE_MESSAGES - MHD_DLOG(connection->daemon, - _("Failed to allocate memory for auth response header\n")); + MHD_DLOG(connection->daemon, + _("Failed to allocate memory for auth response header\n")); #endif /* HAVE_MESSAGES */ - return MHD_NO; - } - - if (MHD_snprintf_ (header, - hlen + 1, - "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\"%s", - realm, - nonce, - opaque, - signal_stale - ? ",stale=\"true\"" - : "") == hlen) - ret = MHD_add_response_header(response, - MHD_HTTP_HEADER_WWW_AUTHENTICATE, - header); - else - ret = MHD_NO; - free (header); - } - else - ret = MHD_NO; + return MHD_NO; + } + + if (MHD_snprintf_ (header, + hlen + 1, + "Digest realm=\"%s\",qop=\"auth\",nonce=\"%s\",opaque=\"%s\",algorithm=%s%s", + realm, + nonce, + opaque, + da.alg, + signal_stale + ? ",stale=\"true\"" + : "") == hlen) + ret = MHD_add_response_header(response, + MHD_HTTP_HEADER_WWW_AUTHENTICATE, + header); + else + ret = MHD_NO; + free (header); + } + else + ret = MHD_NO; + } if (MHD_YES == ret) { @@ -1162,4 +1379,36 @@ MHD_queue_auth_fail_response (struct MHD_Connection *connection, } +/** + * Queues a response to request authentication from the client. + * For now uses MD5 (for backwards-compatibility). Still, if you + * need to be sure, use #MHD_queue_fail_auth_response2(). + * + * @param connection The MHD connection structure + * @param realm the realm presented to the client + * @param opaque string to user for opaque value + * @param response reply to send; should contain the "access denied" + * body; note that this function will set the "WWW Authenticate" + * header and that the caller should not do this + * @param signal_stale #MHD_YES if the nonce is invalid to add + * 'stale=true' to the authentication header + * @return #MHD_YES on success, #MHD_NO otherwise + * @ingroup authentication + */ +int +MHD_queue_auth_fail_response (struct MHD_Connection *connection, + const char *realm, + const char *opaque, + struct MHD_Response *response, + int signal_stale) +{ + return MHD_queue_auth_fail_response2 (connection, + realm, + opaque, + response, + signal_stale, + MHD_DIGEST_ALG_MD5); +} + + /* end of digestauth.c */ diff --git a/src/microhttpd/md5.c b/src/microhttpd/md5.c @@ -42,16 +42,20 @@ static uint8_t PADDING[MD5_BLOCK_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -/* + +/** * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. + * + * @param ctx must be a `struct MD5Context *` */ void -MD5Init(struct MD5Context *ctx) +MD5Init (void *ctx_) { + struct MD5Context *ctx = ctx_; + if (!ctx) return; - ctx->count = 0; ctx->state[0] = 0x67452301; ctx->state[1] = 0xefcdab89; @@ -59,56 +63,13 @@ MD5Init(struct MD5Context *ctx) ctx->state[3] = 0x10325476; } -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -void -MD5Update(struct MD5Context *ctx, const unsigned char *input, size_t len) -{ - size_t have, need; - - if (!ctx || !input) - return; - - /* Check how many bytes we already have and how many more we need. */ - have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_SIZE - 1)); - need = MD5_BLOCK_SIZE - have; - - /* Update bitcount */ - ctx->count += (uint64_t)len << 3; - - if (len >= need) - { - if (have != 0) - { - memcpy(ctx->buffer + have, input, need); - MD5Transform(ctx->state, ctx->buffer); - input += need; - len -= need; - have = 0; - } - /* Process data in MD5_BLOCK_SIZE-byte chunks. */ - while (len >= MD5_BLOCK_SIZE) - { - MD5Transform(ctx->state, input); - input += MD5_BLOCK_SIZE; - len -= MD5_BLOCK_SIZE; - } - } - - /* Handle any remaining bytes of data. */ - if (len != 0) - memcpy(ctx->buffer + have, input, len); -} - -/* +/** * Pad pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ -void -MD5Pad(struct MD5Context *ctx) +static void +MD5Pad (struct MD5Context *ctx) { uint8_t count[8]; size_t padlen; @@ -128,12 +89,17 @@ MD5Pad(struct MD5Context *ctx) MD5Update(ctx, count, 8); } -/* + +/** * Final wrapup--call MD5Pad, fill in digest and zero out ctx. + * + * @param ctx must be a `struct MD5Context *` */ void -MD5Final(unsigned char digest[MD5_DIGEST_SIZE], struct MD5Context *ctx) +MD5Final (void *ctx_, + unsigned char digest[MD5_DIGEST_SIZE]) { + struct MD5Context *ctx = ctx_; int i; if (!ctx || !digest) @@ -159,13 +125,14 @@ MD5Final(unsigned char digest[MD5_DIGEST_SIZE], struct MD5Context *ctx) #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) -/* +/** * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ -void -MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_SIZE]) +static void +MD5Transform (uint32_t state[4], + const uint8_t block[MD5_BLOCK_SIZE]) { uint32_t a, b, c, d, in[MD5_BLOCK_SIZE / 4]; @@ -261,4 +228,59 @@ MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_SIZE]) state[3] += d; } + +/** + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +MD5Update (void *ctx_, + const uint8_t *input, + size_t len) +{ + struct MD5Context *ctx = ctx_; + size_t have, need; + + if (!ctx || !input) + return; + + /* Check how many bytes we already have and how many more we need. */ + have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_SIZE - 1)); + need = MD5_BLOCK_SIZE - have; + + /* Update bitcount */ + ctx->count += (uint64_t)len << 3; + + if (len >= need) + { + if (have != 0) + { + memcpy (ctx->buffer + have, + input, + need); + MD5Transform(ctx->state, ctx->buffer); + input += need; + len -= need; + have = 0; + } + + /* Process data in MD5_BLOCK_SIZE-byte chunks. */ + while (len >= MD5_BLOCK_SIZE) + { + MD5Transform (ctx->state, + (const unsigned char *) input); + input += MD5_BLOCK_SIZE; + len -= MD5_BLOCK_SIZE; + } + } + + /* Handle any remaining bytes of data. */ + if (0 != len) + memcpy (ctx->buffer + have, + input, + len); +} + + + /* end of md5.c */ diff --git a/src/microhttpd/md5.h b/src/microhttpd/md5.h @@ -31,34 +31,37 @@ struct MD5Context uint8_t buffer[MD5_BLOCK_SIZE]; /* input buffer */ }; -/* + +/** * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. + * + * @param ctx_ must be a `struct MD5Context *` */ -void MD5Init(struct MD5Context *ctx); +void +MD5Init (void *ctx_); -/* + +/** * Update context to reflect the concatenation of another buffer full * of bytes. + * + * @param ctx_ must be a `struct MD5Context *` */ -void MD5Update(struct MD5Context *ctx, const unsigned char *input, size_t len); +void +MD5Update (void *ctx_, + const uint8_t *input, + size_t len); -/* - * Pad pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void MD5Pad(struct MD5Context *ctx); -/* +/** * Final wrapup--call MD5Pad, fill in digest and zero out ctx. + * + * @param ctx_ must be a `struct MD5Context *` */ -void MD5Final(unsigned char digest[MD5_DIGEST_SIZE], struct MD5Context *ctx); +void +MD5Final (void *ctx_, + unsigned char digest[MD5_DIGEST_SIZE]); -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -void MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_SIZE]); #endif /* !MHD_MD5_H */ diff --git a/src/microhttpd/sha256.c b/src/microhttpd/sha256.c @@ -48,22 +48,22 @@ static const uint32_t K[64] = { - 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, - 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, - 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, - 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, - 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, - 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, - 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, - 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, - 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, - 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, - 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, - 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, - 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, - 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, - 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, - 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL, + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL, }; @@ -77,11 +77,11 @@ K[64] = this */ /* #define Choice(x,y,z) ( ( (x) & (y) ) | ( ~(x) & (z) ) ) */ -#define Choice(x,y,z) ( (z) ^ ( (x) & ( (y) ^ (z) ) ) ) +#define Choice(x,y,z) ( (z) ^ ( (x) & ( (y) ^ (z) ) ) ) /* #define Majority(x,y,z) ( ((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)) ) */ #define Majority(x,y,z) ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) ) -#define S0(x) (ROTL32(30,(x)) ^ ROTL32(19,(x)) ^ ROTL32(10,(x))) +#define S0(x) (ROTL32(30,(x)) ^ ROTL32(19,(x)) ^ ROTL32(10,(x))) #define S1(x) (ROTL32(26,(x)) ^ ROTL32(21,(x)) ^ ROTL32(7,(x))) #define s0(x) (ROTL32(25,(x)) ^ ROTL32(14,(x)) ^ ((x) >> 3)) @@ -182,22 +182,22 @@ _nettle_sha256_compress(uint32_t *state, const uint8_t *input, const uint32_t *k F = state[5]; G = state[6]; H = state[7]; - + /* Heavy mangling */ /* First 16 subrounds that act on the original data */ for (i = 0, d = data; i<16; i+=8, k += 8, d+= 8) { - ROUND(A, B, C, D, E, F, G, H, k[0], d[0]); - ROUND(H, A, B, C, D, E, F, G, k[1], d[1]); + ROUND(A, B, C, D, E, F, G, H, k[0], d[0]); + ROUND(H, A, B, C, D, E, F, G, k[1], d[1]); ROUND(G, H, A, B, C, D, E, F, k[2], d[2]); ROUND(F, G, H, A, B, C, D, E, k[3], d[3]); ROUND(E, F, G, H, A, B, C, D, k[4], d[4]); ROUND(D, E, F, G, H, A, B, C, k[5], d[5]); - ROUND(C, D, E, F, G, H, A, B, k[6], d[6]); - ROUND(B, C, D, E, F, G, H, A, k[7], d[7]); + ROUND(C, D, E, F, G, H, A, B, k[6], d[6]); + ROUND(B, C, D, E, F, G, H, A, k[7], d[7]); } - + for (; i<64; i += 16, k+= 16) { ROUND(A, B, C, D, E, F, G, H, k[ 0], EXPAND(data, 0)); @@ -235,20 +235,21 @@ _nettle_sha256_compress(uint32_t *state, const uint8_t *input, const uint32_t *k /* Initialize the SHA values */ void -sha256_init(struct sha256_ctx *ctx) +sha256_init (void *ctx_) { /* Initial values, also generated by the shadata program. */ static const uint32_t H0[_SHA256_DIGEST_LENGTH] = { - 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, - 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL, + 0x6a09e667UL, 0xbb67ae85UL, 0x3c6ef372UL, 0xa54ff53aUL, + 0x510e527fUL, 0x9b05688cUL, 0x1f83d9abUL, 0x5be0cd19UL, }; + struct sha256_ctx *ctx = ctx_; memcpy(ctx->state, H0, sizeof(H0)); /* Initialize bit count */ ctx->count = 0; - + /* Initialize buffer */ ctx->index = 0; } @@ -322,9 +323,11 @@ sha256_init(struct sha256_ctx *ctx) void -sha256_update(struct sha256_ctx *ctx, - size_t length, const uint8_t *data) +sha256_update (void *ctx_, + const uint8_t *data, + size_t length) { + struct sha256_ctx *ctx = ctx_; MD_UPDATE (ctx, length, data, COMPRESS, ctx->count++); } @@ -337,7 +340,7 @@ _nettle_write_be32(size_t length, uint8_t *dst, size_t i; size_t words; unsigned leftover; - + words = length / 4; leftover = length % 4; @@ -348,9 +351,9 @@ _nettle_write_be32(size_t length, uint8_t *dst, { uint32_t word; unsigned j = leftover; - + word = src[i]; - + switch (leftover) { default: @@ -369,9 +372,9 @@ _nettle_write_be32(size_t length, uint8_t *dst, static void -sha256_write_digest(struct sha256_ctx *ctx, - size_t length, - uint8_t *digest) +sha256_write_digest (struct sha256_ctx *ctx, + size_t length, + uint8_t *digest) { uint64_t bit_count; @@ -379,7 +382,7 @@ sha256_write_digest(struct sha256_ctx *ctx, MD_PAD(ctx, 8, COMPRESS); - /* There are 512 = 2^9 bits in one block */ + /* There are 512 = 2^9 bits in one block */ bit_count = (ctx->count << 9) | (ctx->index << 3); /* This is slightly inefficient, as the numbers are converted to @@ -392,10 +395,13 @@ sha256_write_digest(struct sha256_ctx *ctx, } void -sha256_digest(struct sha256_ctx *ctx, - size_t length, +sha256_digest (void *ctx_, uint8_t *digest) { - sha256_write_digest(ctx, length, digest); - sha256_init(ctx); + struct sha256_ctx *ctx = ctx_; + + sha256_write_digest (ctx, + SHA256_DIGEST_SIZE, + digest); + sha256_init (ctx); } diff --git a/src/microhttpd/sha256.h b/src/microhttpd/sha256.h @@ -32,14 +32,10 @@ the GNU Lesser General Public License along with this program. If not, see http://www.gnu.org/licenses/. */ - + #ifndef NETTLE_SHA2_H_INCLUDED #define NETTLE_SHA2_H_INCLUDED -#ifdef __cplusplus -extern "C" { -#endif - #define SHA256_DIGEST_SIZE 32 #define SHA256_BLOCK_SIZE 64 @@ -54,21 +50,36 @@ struct sha256_ctx unsigned int index; /* index into buffer */ }; -void -sha256_init(struct sha256_ctx *ctx); +/** + * Start SHA256 calculation. + * + * @param ctx_ must be a `struct sha256_ctx *` + */ void -sha256_update(struct sha256_ctx *ctx, - size_t length, - const uint8_t *data); +sha256_init (void *ctx_); -void -sha256_digest(struct sha256_ctx *ctx, - size_t length, - uint8_t *digest); -#ifdef __cplusplus -} -#endif +/** + * Update hash calculation. + * + * @param ctx_ must be a `struct sha256_ctx *` + * @param length number of bytes in @a data + * @param data bytes to add to hash + */ +void +sha256_update (void *ctx_, + const uint8_t *data, + size_t length); + +/** + * Complete SHA256 calculation. + * + * @param ctx_ must be a `struct sha256_ctx *` + * @param digest[out] set to the hash, must be #SHA256_DIGEST_SIZE bytes + */ +void +sha256_digest (void *ctx_, + uint8_t digest[SHA256_DIGEST_SIZE]); #endif /* NETTLE_SHA2_H_INCLUDED */