gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libmicrohttpd] branch master updated (8318f56e -> b6dcf9d2)


From: gnunet
Subject: [libmicrohttpd] branch master updated (8318f56e -> b6dcf9d2)
Date: Sun, 25 Sep 2022 17:43:35 +0200

This is an automated email from the git hooks/post-receive script.

karlson2k pushed a change to branch master
in repository libmicrohttpd.

    from 8318f56e digestauth: added support for SHA-512/256, made MD5 and 
SHA-256 optional
     new 8815effe Fixed regression introduced by 
c3680cb737bcac2a4dc14cca5a80af6ca0de21e7
     new 1e288041 Fixed initialisation of old GnuTLS versions
     new de88268e mhd_locks.h: cosmetics
     new 403f3b8e mhd_options: use standard _MHD_EXTERN if file used outside 
the library
     new 85a90925 sha256: backported minor optimisations from SHA-512/256
     new eb26d6c9 sha256: implemented compact code version, similarly to 
SHA-512/256
     new 98a03752 sha512_256: additional trick for compacter code; doxy and 
comment fixes
     new 532debba md5: replaced public domain MD5 implementation with our own 
implementation
     new f11a6dce md5: improved performance of the first round on LE arches
     new 9e1fcbbf md5: added compact code version
     new 9a3067c3 test_{md5,sha256,sha512_256}: added more checks
     new cce6a8d7 test_sha{256,512_256}: minor fixes
     new b6a36f82 test_md5: added more test sequences
     new 0c9323a9 test_{md5,sha{256,512_256}}: added long test sequence
     new b50bed12 sha{256,512_256}: improved performance of the first steps on 
BE arches
     new eef2d639 test_{md5,sha{256,512_256}}: re-use of the context structure
     new c5171852 digestauth: removed redundant check and report
     new f26b8061 digestauth: changed "slot used" detection logic
     new ebe7f8d2 digestauth: used weak pseudo-random generators to avoid 
nonces clashes
     new 281b22da digestauth: refactored hashing asserts
     new 172b0eeb Implemented support for hash calculation by GnuTLS lib 
functions
     new b6dcf9d2 w32: sync projects with autotools

The 22 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 configure.ac                                       | 256 ++++++-
 src/gnutls/init.c                                  |  16 +-
 src/include/mhd_options.h                          |   3 +
 src/include/microhttpd.h                           |  39 +-
 src/microhttpd/Makefile.am                         |  46 +-
 src/microhttpd/daemon.c                            |  20 +-
 src/microhttpd/digestauth.c                        | 709 ++++++++++++++-----
 src/microhttpd/md5.c                               | 759 +++++++++++++--------
 src/microhttpd/md5.h                               | 140 ++--
 src/microhttpd/md5_ext.c                           |  95 +++
 src/microhttpd/md5_ext.h                           | 115 ++++
 src/microhttpd/mhd_locks.h                         |  19 +-
 src/microhttpd/mhd_md5_wrap.h                      |  98 +++
 src/microhttpd/mhd_sha256_wrap.h                   | 100 +++
 src/microhttpd/sha256.c                            | 269 +++++---
 src/microhttpd/sha256.h                            |  22 +-
 src/microhttpd/sha256_ext.c                        |  95 +++
 src/microhttpd/sha256_ext.h                        | 115 ++++
 src/microhttpd/sha512_256.c                        | 138 ++--
 src/microhttpd/sha512_256.h                        |   9 +-
 src/microhttpd/test_dauth_userdigest.c             |  14 +
 src/microhttpd/test_dauth_userhash.c               |  14 +
 src/microhttpd/test_md5.c                          | 158 ++++-
 src/microhttpd/test_sha256.c                       | 108 ++-
 src/microhttpd/test_sha512_256.c                   |  26 +-
 src/testcurl/https/test_empty_response.c           |   4 +-
 src/testcurl/https/test_https_get.c                |   8 +-
 src/testcurl/https/test_https_get_iovec.c          |   8 +-
 src/testcurl/https/test_https_get_parallel.c       |   4 +-
 .../https/test_https_get_parallel_threads.c        |   8 +-
 src/testcurl/https/test_https_get_select.c         |   4 +-
 src/testcurl/https/test_https_multi_daemon.c       |   8 +-
 src/testcurl/https/test_https_session_info.c       |   8 +-
 src/testcurl/https/test_https_sni.c                |   8 +-
 src/testcurl/https/test_https_time_out.c           |   8 +-
 src/testcurl/https/test_tls_authentication.c       |   8 +-
 src/testcurl/https/test_tls_extensions.c           |   8 +-
 src/testcurl/https/test_tls_options.c              |   8 +-
 src/testcurl/test_basicauth.c                      |   4 +-
 src/testcurl/test_digestauth.c                     |  19 +-
 src/testcurl/test_digestauth2.c                    |  14 +-
 src/testcurl/test_digestauth_concurrent.c          |  18 +-
 src/testcurl/test_digestauth_sha256.c              |  19 +-
 src/testcurl/test_digestauth_with_arguments.c      |  15 +-
 src/testcurl/test_postform.c                       |   8 +-
 w32/common/MHD_config.h                            |  12 +
 w32/common/libmicrohttpd-files.vcxproj             |   6 +-
 w32/common/libmicrohttpd-filters.vcxproj           |  18 +-
 48 files changed, 2764 insertions(+), 844 deletions(-)
 create mode 100644 src/microhttpd/md5_ext.c
 create mode 100644 src/microhttpd/md5_ext.h
 create mode 100644 src/microhttpd/mhd_md5_wrap.h
 create mode 100644 src/microhttpd/mhd_sha256_wrap.h
 create mode 100644 src/microhttpd/sha256_ext.c
 create mode 100644 src/microhttpd/sha256_ext.h

diff --git a/configure.ac b/configure.ac
index 31ae78ec..1b6310da 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3048,8 +3048,8 @@ AC_MSG_RESULT([[$enable_bauth]])
 AC_MSG_CHECKING([[whether to support HTTP Digest authentication]])
 AC_ARG_ENABLE([dauth],
                [AS_HELP_STRING([--disable-dauth], [disable HTTP Digest 
Authentication support])],
-               [enable_dauth=${enableval}],
-               [enable_dauth=yes])
+               [enable_dauth="${enableval}"],
+               [enable_dauth="yes"])
 AS_IF([[test "x$enable_dauth" != "xno"]],
   [ enable_dauth=yes
     AC_DEFINE([DAUTH_SUPPORT],[1],[Define to 1 if libmicrohttpd is compiled 
with Digest Auth support.]) ])
@@ -3084,57 +3084,249 @@ AC_MSG_RESULT([[$enable_cookie]])
 
 # optional: MD5 support for Digest Auth. Enabled by default.
 AC_ARG_ENABLE([[md5]],
-  [AS_HELP_STRING([[--disable-md5]],[disable MD5 hashing support for Digest 
Authentication])
+  [AS_HELP_STRING([[--enable-md5=TYPE]],[enable TYPE of MD5 hashing code (yes, 
no, builtin, tlslib) [yes if dauth enabled]])
   ],
   [
-    AS_VAR_IF([[enable_md5]],[["yes"]],
+    AS_VAR_IF([enable_md5],["internal"],[enable_md5='builtin'])
+    AS_VAR_IF([enable_md5],["built-in"],[enable_md5='builtin'])
+    AS_VAR_IF([enable_dauth],["yes"],[],
       [
-        AS_VAR_IF([enable_dauth],["yes"],[],
+        AS_VAR_IF([enable_md5],["no"],[],
           [
-            AC_MSG_WARN([The parameter --enable-md5 is ignored as Digest 
Authentication is disabled])
+            AC_MSG_WARN([The parameter --enable-md5=${enable_md5} is ignored 
as Digest Authentication is disabled])
             enable_md5='no'
           ]
         )
-      ],[[enable_md5='no']]
+      ]
     )
   ], [[enable_md5="${enable_dauth}"]]
 )
+AS_CASE([${enable_md5}],[yes|tlslib],
+  [
+    AS_IF([test "x${enable_compact_code}" != "xno" || test "x$enable_md5" = 
"xtlslib"],
+      [
+        AS_IF([test "x$enable_https" = "xyes"],
+          [
+            AC_CACHE_CHECK([whether GnuTLS supports MD5 
hashing],[mhd_cv_gnutls_md5],
+              [
+                CFLAGS="${CFLAGS_ac} ${GNUTLS_CFLAGS} ${user_CFLAGS}"
+                CPPFLAGS="${CPPFLAGS_ac} ${MHD_TLS_LIB_CPPFLAGS} 
${user_CPPFLAGS}"
+                CFLAGS="${CFLAGS_ac} ${MHD_TLS_LIB_CFLAGS} ${user_CFLAGS}"
+                LDFLAGS="${LDFLAGS_ac} ${MHD_TLS_LIB_LDFLAGS} ${user_LDFLAGS}"
+                save_LIBS="$LIBS"
+                LIBS="${MHD_TLS_LIBDEPS} ${LIBS}"
+                AC_LINK_IFELSE(
+                  [
+                    AC_LANG_PROGRAM(
+                      [[
+#include <gnutls/crypto.h>
+                      ]],
+                      [[
+    gnutls_hash_hd_t hash_handle;
+    unsigned char digest[16];
+    int exit_code;
+
+    if (0 == gnutls_hash_init(&hash_handle, GNUTLS_DIG_MD5))
+    {
+      if (0 == gnutls_hash(hash_handle, "", 1))
+      {
+        gnutls_hash_output(hash_handle, digest);
+        if (0x93 == digest[0])
+          exit_code = 0;
+        else
+          exit_code = 7;
+      }
+      else
+        exit_code = 5;
+      gnutls_hash_deinit(hash_handle, (void *)0);
+    }
+    else
+      exit_code = 2;
+    if (exit_code)
+      return exit_code;
+                      ]]
+                    )
+                  ],
+                  [mhd_cv_gnutls_md5='yes'],[mhd_cv_gnutls_md5='no']
+                )
+                LIBS="${save_LIBS}"
+                CFLAGS="${CFLAGS_ac} ${user_CFLAGS}"
+                CPPFLAGS="${CPPFLAGS_ac} ${user_CPPFLAGS}"
+                CFLAGS="${CFLAGS_ac} ${user_CFLAGS}"
+                LDFLAGS="${LDFLAGS_ac} ${user_LDFLAGS}"
+              ]
+            )
+            AS_VAR_IF([mhd_cv_gnutls_md5],["no"],
+              [
+                AS_VAR_IF([enable_md5],["tlslib"],
+                  [AC_MSG_FAILURE([TLS library MD5 implementation is not 
available])]
+                )
+                enable_md5="builtin"
+              ],
+              [enable_md5="tlslib"]
+            )
+          ],
+          [
+            AS_VAR_IF([enable_md5],["tlslib"],
+              [AC_MSG_ERROR([HTTPS is not enabled, TLS library MD5 
implementation cannot be used])]
+            )
+            enable_md5="builtin"
+          ]
+        )
+      ],
+      [
+        enable_md5="builtin"
+      ]
+    )
+  ]
+)
 AC_MSG_CHECKING([[whether to support MD5]])
-AS_VAR_IF([[enable_md5]],[["yes"]],
+AS_UNSET([enable_md5_MSG])
+AS_CASE([${enable_md5}],
+  [builtin],[enable_md5_MSG='yes, built-in'],
+  [tlslib],[enable_md5_MSG='yes, external (TLS library)'],
+  [no],[enable_md5_MSG='no'],
+  [yes],[AC_MSG_ERROR([configure internal error: unexpected variable value])],
+  [AC_MSG_ERROR([Unrecognized parameter --enable-md5=${enable_md5}])]
+)
+AS_IF([test "x${enable_md5}" = "xbuiltin" || test "x${enable_md5}" = "xtlslib" 
],
   [
-   AC_DEFINE([[MHD_MD5_SUPPORT]],[[1]],
-     [Define to 1 if libmicrohttpd is compiled with MD5 hashing support.])
+    AC_DEFINE([[MHD_MD5_SUPPORT]],[[1]],
+      [Define to 1 if libmicrohttpd is compiled with MD5 hashing support.])
   ]
 )
-AM_CONDITIONAL([ENABLE_MD5], [[test "x${enable_md5}" = "xyes"]])
-AC_MSG_RESULT([[${enable_md5}]])
+AS_IF([test "x${enable_md5}" = "xtlslib" ],
+  [
+    AC_DEFINE([[MHD_MD5_TLSLIB]],[[1]],
+      [Define to 1 if libmicrohttpd is compiled with MD5 hashing by TLS 
library.])
+  ]
+)
+AM_CONDITIONAL([ENABLE_MD5], [[test "x${enable_md5}" = "xbuiltin" || test 
"x${enable_md5}" = "xtlslib" ]])
+AM_CONDITIONAL([ENABLE_MD5_EXT], [[test "x${enable_md5}" = "xtlslib" ]])
+AC_MSG_RESULT([[${enable_md5_MSG}]])
 
 # optional: SHA-256 support for Digest Auth. Enabled by default.
 AC_ARG_ENABLE([[sha256]],
-  [AS_HELP_STRING([[--disable-sha256]],[disable SHA-256 hashing support for 
Digest Authentication])
+  [AS_HELP_STRING([[--enable-sha256=TYPE]],[enable TYPE of SHA-256 hashing 
code (yes, no, builtin, tlslib) [yes if dauth enabled]])
   ],
   [
-    AS_VAR_IF([[enable_sha256]],[["yes"]],
+    AS_VAR_IF([enable_sha256],["internal"],[enable_sha256='builtin'])
+    AS_VAR_IF([enable_sha256],["built-in"],[enable_sha256='builtin'])
+    AS_VAR_IF([enable_dauth],["yes"],[],
       [
-        AS_VAR_IF([enable_dauth],["yes"],[],
+        AS_VAR_IF([enable_sha256],["no"],[],
           [
-            AC_MSG_WARN([The parameter --enable-sha256 is ignored as Digest 
Authentication is disabled])
+            AC_MSG_WARN([The parameter --enable-sha256=${enable_sha256} is 
ignored as Digest Authentication is disabled])
             enable_sha256='no'
           ]
         )
-      ],[[enable_sha256='no']]
+      ]
     )
   ], [[enable_sha256="${enable_dauth}"]]
 )
+AS_CASE([${enable_sha256}],[yes|tlslib],
+  [
+    AS_IF([test "x${enable_compact_code}" != "xno" || test "x$enable_sha256" = 
"xtlslib"],
+      [
+        AS_IF([test "x$enable_https" = "xyes"],
+          [
+            AC_CACHE_CHECK([whether GnuTLS supports sha256 
hashing],[mhd_cv_gnutls_sha256],
+              [
+                CFLAGS="${CFLAGS_ac} ${GNUTLS_CFLAGS} ${user_CFLAGS}"
+                CPPFLAGS="${CPPFLAGS_ac} ${MHD_TLS_LIB_CPPFLAGS} 
${user_CPPFLAGS}"
+                CFLAGS="${CFLAGS_ac} ${MHD_TLS_LIB_CFLAGS} ${user_CFLAGS}"
+                LDFLAGS="${LDFLAGS_ac} ${MHD_TLS_LIB_LDFLAGS} ${user_LDFLAGS}"
+                save_LIBS="$LIBS"
+                LIBS="${MHD_TLS_LIBDEPS} ${LIBS}"
+                AC_LINK_IFELSE(
+                  [
+                    AC_LANG_PROGRAM(
+                      [[
+#include <gnutls/crypto.h>
+                      ]],
+                      [[
+    gnutls_hash_hd_t hash_handle;
+    unsigned char digest[32];
+    int exit_code;
+
+    if (0 == gnutls_hash_init(&hash_handle, GNUTLS_DIG_SHA256))
+    {
+      if (0 == gnutls_hash(hash_handle, "", 1))
+      {
+        gnutls_hash_output(hash_handle, digest);
+        if (0x6e == digest[0])
+          exit_code = 0;
+        else
+          exit_code = 7;
+      }
+      else
+        exit_code = 5;
+      gnutls_hash_deinit(hash_handle, (void *)0);
+    }
+    else
+      exit_code = 2;
+    if (exit_code)
+      return exit_code;
+                      ]]
+                    )
+                  ],
+                  [mhd_cv_gnutls_sha256='yes'],[mhd_cv_gnutls_sha256='no']
+                )
+                LIBS="${save_LIBS}"
+                CFLAGS="${CFLAGS_ac} ${user_CFLAGS}"
+                CPPFLAGS="${CPPFLAGS_ac} ${user_CPPFLAGS}"
+                CFLAGS="${CFLAGS_ac} ${user_CFLAGS}"
+                LDFLAGS="${LDFLAGS_ac} ${user_LDFLAGS}"
+              ]
+            )
+            AS_VAR_IF([mhd_cv_gnutls_sha256],["no"],
+              [
+                AS_VAR_IF([enable_sha256],["tlslib"],
+                  [AC_MSG_FAILURE([TLS library SHA-256 implementation is not 
available])]
+                )
+                enable_sha256="builtin"
+              ],
+              [enable_sha256="tlslib"]
+            )
+          ],
+          [
+            AS_VAR_IF([enable_sha256],["tlslib"],
+              [AC_MSG_ERROR([HTTPS is not enabled, TLS library SHA-256 
implementation cannot be used])]
+            )
+            enable_sha256="builtin"
+          ]
+        )
+      ],
+      [
+        enable_sha256="builtin"
+      ]
+    )
+  ]
+)
 AC_MSG_CHECKING([[whether to support SHA-256]])
-AS_VAR_IF([[enable_sha256]],[["yes"]],
+AS_UNSET([enable_sha256_MSG])
+AS_CASE([${enable_sha256}],
+  [builtin],[enable_sha256_MSG='yes, built-in'],
+  [tlslib],[enable_sha256_MSG='yes, external (TLS library)'],
+  [no],[enable_sha256_MSG='no'],
+  [yes],[AC_MSG_ERROR([configure internal error: unexpected variable value])],
+  [AC_MSG_ERROR([Unrecognized parameter --enable-sha256=${enable_sha256}])]
+)
+AS_IF([test "x${enable_sha256}" = "xbuiltin" || test "x${enable_sha256}" = 
"xtlslib" ],
   [
-   AC_DEFINE([[MHD_SHA256_SUPPORT]],[[1]],
-     [Define to 1 if libmicrohttpd is compiled with SHA-256 hashing support.])
+    AC_DEFINE([[MHD_SHA256_SUPPORT]],[[1]],
+      [Define to 1 if libmicrohttpd is compiled with SHA-256 hashing support.])
   ]
 )
-AM_CONDITIONAL([ENABLE_SHA256], [[test "x${enable_sha256}" = "xyes"]])
-AC_MSG_RESULT([[${enable_sha256}]])
+AS_IF([test "x${enable_sha256}" = "xtlslib" ],
+  [
+    AC_DEFINE([[MHD_SHA256_TLSLIB]],[[1]],
+      [Define to 1 if libmicrohttpd is compiled with SHA-256 hashing by TLS 
library.])
+  ]
+)
+AM_CONDITIONAL([ENABLE_SHA256], [[test "x${enable_sha256}" = "xbuiltin" || 
test "x${enable_sha256}" = "xtlslib" ]])
+AM_CONDITIONAL([ENABLE_SHA256_EXT], [[test "x${enable_sha256}" = "xtlslib" ]])
+AC_MSG_RESULT([[${enable_sha256_MSG}]])
 
 # optional: SHA-512/256 support for Digest Auth. Enabled by default.
 AC_ARG_ENABLE([[sha512-256]],
@@ -3154,6 +3346,12 @@ AC_ARG_ENABLE([[sha512-256]],
   ], [[enable_sha512_256="${enable_dauth}"]]
 )
 AC_MSG_CHECKING([[whether to support SHA-512/256]])
+AS_UNSET([enable_sha512_256_MSG])
+AS_CASE([${enable_sha512_256}],
+  [yes],[enable_sha512_256_MSG='yes, built-in'],
+  [no],[enable_sha512_256_MSG='no'],
+  [AC_MSG_ERROR([Unrecognized parameter 
--enable-sha512-256=${enable_sha512_256}])]
+)
 AS_VAR_IF([[enable_sha512_256]],[["yes"]],
   [
    AC_DEFINE([[MHD_SHA512_256_SUPPORT]],[[1]],
@@ -3161,11 +3359,11 @@ AS_VAR_IF([[enable_sha512_256]],[["yes"]],
   ]
 )
 AM_CONDITIONAL([ENABLE_SHA512_256], [[test "x${enable_sha512_256}" = "xyes"]])
-AC_MSG_RESULT([[${enable_sha512_256}]])
+AC_MSG_RESULT([[${enable_sha512_256_MSG}]])
 
 AS_IF([test "x$enable_dauth" != "xno"],
   [
-    AS_IF([test "x${enable_md5}" != "xyes" &&  test "x${enable_sha256}" != 
"xyes" && test "x${enable_sha512_256}" != "xyes"],
+    AS_IF([test "x${enable_md5}" = "xno" &&  test "x${enable_sha256}" = "xno" 
&& test "x${enable_sha512_256}" != "xyes"],
       [AC_MSG_ERROR([At least one hashing algorithm must be enabled if Digest 
Auth is enabled])]
     )
   ]
@@ -4052,9 +4250,9 @@ AC_MSG_NOTICE([GNU libmicrohttpd ${PACKAGE_VERSION} 
Configuration Summary:
   Messages:          ${enable_messages}
   Basic auth.:       ${enable_bauth}
   Digest auth.:      ${enable_dauth}
-  MD5:               ${enable_md5}
-  SHA-256:           ${enable_sha256}
-  SHA-512/256:       ${enable_sha512_256}
+  MD5:               ${enable_md5_MSG}
+  SHA-256:           ${enable_sha256_MSG}
+  SHA-512/256:       ${enable_sha512_256_MSG}
   HTTP "Upgrade":    ${enable_httpupgrade}
   Cookie parsing:    ${enable_cookie}
   Postproc:          ${enable_postprocessor}
@@ -4075,8 +4273,8 @@ AS_IF([test "x$enable_https" = "xyes"],
 
 AS_IF([test "x$enable_bauth" != "xyes" || \
    test "x$enable_dauth" != "xyes" || \
-   test "x${enable_md5}" != "xyes" || \
-   test "x${enable_sha256}" != "xyes" || \
+   test "x${enable_md5}" = "xno" || \
+   test "x${enable_sha256}" = "xno" || \
    test "x${enable_sha512_256}" != "xyes" || \
    test "x$enable_httpupgrade" != "xyes" || \
    test "x$enable_cookie" != "xyes" || \
diff --git a/src/gnutls/init.c b/src/gnutls/init.c
index 638f629c..4c47d162 100644
--- a/src/gnutls/init.c
+++ b/src/gnutls/init.c
@@ -26,7 +26,7 @@
 #include "init.h"
 
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #if defined(HTTPS_SUPPORT) && GCRYPT_VERSION_NUMBER < 0x010600
 #if defined(MHD_USE_POSIX_THREADS)
 GCRY_THREAD_OPTION_PTHREAD_IMPL;
@@ -40,7 +40,7 @@ gcry_w32_mutex_init (void **ppmtx)
 
   if (NULL == *ppmtx)
     return ENOMEM;
-  if (! MHD_mutex_init_ ((MHD_mutex_*) *ppmtx))
+  if (! MHD_mutex_init_ ((MHD_mutex_ *) *ppmtx))
   {
     free (*ppmtx);
     *ppmtx = NULL;
@@ -53,7 +53,7 @@ gcry_w32_mutex_init (void **ppmtx)
 static int
 gcry_w32_mutex_destroy (void **ppmtx)
 {
-  int res = (MHD_mutex_destroy_ ((MHD_mutex_*) *ppmtx)) ? 0 : EINVAL;
+  int res = (MHD_mutex_destroy_ ((MHD_mutex_ *) *ppmtx)) ? 0 : EINVAL;
   free (*ppmtx);
   return res;
 }
@@ -62,14 +62,14 @@ gcry_w32_mutex_destroy (void **ppmtx)
 static int
 gcry_w32_mutex_lock (void **ppmtx)
 {
-  return MHD_mutex_lock_ ((MHD_mutex_*) *ppmtx) ? 0 : EINVAL;
+  return MHD_mutex_lock_ ((MHD_mutex_ *) *ppmtx) ? 0 : EINVAL;
 }
 
 
 static int
 gcry_w32_mutex_unlock (void **ppmtx)
 {
-  return MHD_mutex_unlock_ ((MHD_mutex_*) *ppmtx) ? 0 : EINVAL;
+  return MHD_mutex_unlock_ ((MHD_mutex_ *) *ppmtx) ? 0 : EINVAL;
 }
 
 
@@ -82,7 +82,7 @@ static struct gcry_thread_cbs gcry_threads_w32 = {
 
 #endif /* defined(MHD_W32_MUTEX_) */
 #endif /* HTTPS_SUPPORT && GCRYPT_VERSION_NUMBER < 0x010600 */
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 
 
 #ifndef _AUTOINIT_FUNCS_ARE_SUPPORTED
@@ -129,7 +129,7 @@ MHD_TLS_init (void)
   WSADATA wsd;
 #endif /* _WIN32 && ! __CYGWIN__ */
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #if GCRYPT_VERSION_NUMBER < 0x010600
 #if defined(MHD_USE_POSIX_THREADS)
   if (0 != gcry_control (GCRYCTL_SET_THREAD_CBS,
@@ -146,7 +146,7 @@ MHD_TLS_init (void)
     MHD_PANIC (_ (
                  "libgcrypt is too old. MHD was compiled for libgcrypt 1.6.0 
or newer.\n"));
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
   gnutls_global_init ();
 }
 
diff --git a/src/include/mhd_options.h b/src/include/mhd_options.h
index 9184e1ac..dbfc2409 100644
--- a/src/include/mhd_options.h
+++ b/src/include/mhd_options.h
@@ -41,6 +41,9 @@
  */
 #define _(String) (String)
 
+#if defined(_MHD_EXTERN) && ! defined(BUILDING_MHD_LIB)
+#undef _MHD_EXTERN
+#endif /* _MHD_EXTERN && ! BUILDING_MHD_LIB */
 
 #ifndef _MHD_EXTERN
 #if defined(BUILDING_MHD_LIB) && defined(_WIN32) && \
diff --git a/src/include/microhttpd.h b/src/include/microhttpd.h
index e5f0abac..5e744b69 100644
--- a/src/include/microhttpd.h
+++ b/src/include/microhttpd.h
@@ -96,7 +96,7 @@ extern "C"
  * they are parsed as decimal numbers.
  * Example: 0x01093001 = 1.9.30-1.
  */
-#define MHD_VERSION 0x00097539
+#define MHD_VERSION 0x00097540
 
 /* If generic headers don't work on your platform, include headers
    which define 'va_list', 'size_t', 'ssize_t', 'intptr_t', 'off_t',
@@ -4691,8 +4691,10 @@ enum MHD_DigestAuthMultiAlgo3
  *                          upon return
  * @param bin_buf_size the size of the @a userhash_bin buffer, must be
  *                     at least #MHD_digest_get_hash_size(algo3) bytes long
- * @return MHD_YES on success, MHD_NO if @a bin_buf_size is too small or
- *                             if @a algo3 algorithm is not supported.
+ * @return MHD_YES on success,
+ *         MHD_NO if @a bin_buf_size is too small or if @a algo3 algorithm is
+ *         not supported (or external error has occurred,
+ *         see #MHD_FEATURE_EXTERN_HASH)
  * @note Available since #MHD_VERSION 0x00097535
  * @ingroup authentication
  */
@@ -4736,8 +4738,10 @@ MHD_digest_auth_calc_userhash (enum MHD_DigestAuthAlgo3 
algo3,
  *                          userhash string
  * @param bin_buf_size the size of the @a userhash_bin buffer, must be
  *                     at least #MHD_digest_get_hash_size(algo3)*2+1 chars long
- * @return MHD_YES on success, MHD_NO if @a bin_buf_size is too small or
- *                             if @a algo3 algorithm is not supported.
+ * @return MHD_YES on success,
+ *         MHD_NO if @a bin_buf_size is too small or if @a algo3 algorithm is
+ *         not supported (or external error has occurred,
+ *         see #MHD_FEATURE_EXTERN_HASH).
  * @note Available since #MHD_VERSION 0x00097535
  * @ingroup authentication
  */
@@ -5287,8 +5291,10 @@ MHD_digest_auth_check3 (struct MHD_Connection 
*connection,
  *                            userdigest upon return
  * @param userdigest_bin the size of the @a userdigest_bin buffer, must be
  *                       at least #MHD_digest_get_hash_size(algo3) bytes long
- * @return MHD_YES on success, MHD_NO if @a userdigest_bin is too small or
- *                             if @a algo3 algorithm is not supported.
+ * @return MHD_YES on success,
+ *         MHD_NO if @a userdigest_bin is too small or if @a algo3 algorithm is
+ *         not supported (or external error has occurred,
+ *         see #MHD_FEATURE_EXTERN_HASH).
  * @sa #MHD_digest_auth_check_digest3()
  * @note Available since #MHD_VERSION 0x00097535
  * @ingroup authentication
@@ -5651,6 +5657,9 @@ MHD_queue_auth_fail_response (struct MHD_Connection 
*connection,
                               int signal_stale);
 
 
+/* ********************* Basic Authentication functions *************** */
+
+
 /**
  * Information decoded from Basic Authentication client's header.
  *
@@ -6138,7 +6147,21 @@ enum MHD_FEATURE
    * module is built.
    * @note Available since #MHD_VERSION 0x00097536
    */
-  MHD_FEATURE_DIGEST_AUTH_USERHASH = 31
+  MHD_FEATURE_DIGEST_AUTH_USERHASH = 31,
+
+  /**
+   * Get whether any of hashing algorithms is implemented by external
+   * function (like TLS library) and may fail due to external conditions,
+   * like "out-of-memory".
+   *
+   * If result is #MHD_YES then functions which use hash calculations
+   * like #MHD_digest_auth_calc_userhash(), #MHD_digest_auth_check3() and 
others
+   * potentially may fail even with valid input because of out-of-memory error
+   * or crypto accelerator device failure, however in practice such fails are
+   * unlikely.
+   * @note Available since #MHD_VERSION 0x00097540
+   */
+  MHD_FEATURE_EXTERN_HASH = 32
 };
 
 
diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am
index 10a32f59..c4c15608 100644
--- a/src/microhttpd/Makefile.am
+++ b/src/microhttpd/Makefile.am
@@ -170,12 +170,26 @@ libmicrohttpd_la_SOURCES += \
   digestauth.c digestauth.h \
   mhd_bithelpers.h mhd_byteorder.h mhd_align.h
 if ENABLE_MD5
+libmicrohttpd_la_SOURCES += \
+  mhd_md5_wrap.h
+if ! ENABLE_MD5_EXT
 libmicrohttpd_la_SOURCES += \
   md5.c md5.h
+else
+libmicrohttpd_la_SOURCES += \
+  md5_ext.c md5_ext.h
+endif
 endif
 if ENABLE_SHA256
+libmicrohttpd_la_SOURCES += \
+  mhd_sha256_wrap.h
+if ! ENABLE_SHA256_EXT
 libmicrohttpd_la_SOURCES += \
   sha256.c sha256.h
+else
+libmicrohttpd_la_SOURCES += \
+  sha256_ext.c sha256_ext.h
+endif
 endif
 if ENABLE_SHA512_256
 libmicrohttpd_la_SOURCES += \
@@ -462,12 +476,40 @@ test_http_reasons_SOURCES = \
   reason_phrase.c mhd_str.c mhd_str.h
 
 test_md5_SOURCES = \
-  test_md5.c test_helpers.h \
+  test_md5.c test_helpers.h mhd_md5_wrap.h ../include/mhd_options.h
+if ! ENABLE_MD5_EXT
+test_md5_SOURCES += \
   md5.c md5.h mhd_bithelpers.h mhd_byteorder.h mhd_align.h
+test_md5_CPPFLAGS = $(AM_CPPFLAGS)
+test_md5_CFLAGS = $(AM_CFLAGS)
+test_md5_LDFLAGS = $(AM_LDFLAGS)
+test_md5_LDADD = $(LDADD)
+else
+test_md5_SOURCES += \
+  md5_ext.c md5_ext.h
+test_md5_CPPFLAGS = $(AM_CPPFLAGS) $(MHD_TLS_LIB_CPPFLAGS)
+test_md5_CFLAGS = $(AM_CFLAGS) $(MHD_TLS_LIB_CFLAGS)
+test_md5_LDFLAGS = $(AM_LDFLAGS) $(MHD_TLS_LIB_LDFLAGS)
+test_md5_LDADD = $(MHD_TLS_LIBDEPS) $(LDADD)
+endif
 
 test_sha256_SOURCES = \
-  test_sha256.c test_helpers.h \
+  test_sha256.c test_helpers.h mhd_sha256_wrap.h ../include/mhd_options.h
+if ! ENABLE_SHA256_EXT
+test_sha256_SOURCES += \
   sha256.c sha256.h mhd_bithelpers.h mhd_byteorder.h mhd_align.h
+test_sha256_CPPFLAGS = $(AM_CPPFLAGS)
+test_sha256_CFLAGS = $(AM_CFLAGS)
+test_sha256_LDFLAGS = $(AM_LDFLAGS)
+test_sha256_LDADD = $(LDADD)
+else
+test_sha256_SOURCES += \
+  sha256_ext.c sha256_ext.h
+test_sha256_CPPFLAGS = $(AM_CPPFLAGS) $(MHD_TLS_LIB_CPPFLAGS)
+test_sha256_CFLAGS = $(AM_CFLAGS) $(MHD_TLS_LIB_CFLAGS)
+test_sha256_LDFLAGS = $(AM_LDFLAGS) $(MHD_TLS_LIB_LDFLAGS)
+test_sha256_LDADD = $(MHD_TLS_LIBDEPS) $(LDADD)
+endif
 
 test_sha512_256_SOURCES = \
   test_sha512_256.c test_helpers.h \
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index fc293a1f..29ce1ccc 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -55,9 +55,9 @@
 
 #ifdef HTTPS_SUPPORT
 #include "connection_https.h"
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #include <gcrypt.h>
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 #endif /* HTTPS_SUPPORT */
 
 #if defined(_WIN32) && ! defined(__CYGWIN__)
@@ -8465,6 +8465,12 @@ MHD_is_feature_supported (enum MHD_FEATURE feature)
 #else
     return MHD_NO;
 #endif
+  case MHD_FEATURE_EXTERN_HASH:
+#if defined(MHD_MD5_TLSLIB) || defined(MHD_SHA256_TLSLIB)
+    return MHD_YES;
+#else
+    return MHD_NO;
+#endif
 
   default:
     break;
@@ -8473,7 +8479,7 @@ MHD_is_feature_supported (enum MHD_FEATURE feature)
 }
 
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #if defined(HTTPS_SUPPORT) && GCRYPT_VERSION_NUMBER < 0x010600
 #if defined(MHD_USE_POSIX_THREADS)
 GCRY_THREAD_OPTION_PTHREAD_IMPL;
@@ -8529,7 +8535,7 @@ static struct gcry_thread_cbs gcry_threads_w32 = {
 
 #endif /* defined(MHD_W32_MUTEX_) */
 #endif /* HTTPS_SUPPORT && GCRYPT_VERSION_NUMBER < 0x010600 */
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 
 /**
  * Initialize do setup work.
@@ -8551,8 +8557,9 @@ MHD_init (void)
     MHD_PANIC (_ ("Winsock version 2.2 is not available.\n"));
 #endif /* MHD_WINSOCK_SOCKETS */
 #ifdef HTTPS_SUPPORT
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #if GCRYPT_VERSION_NUMBER < 0x010600
+#if GNUTLS_VERSION_NUMBER <= 0x020b00
 #if defined(MHD_USE_POSIX_THREADS)
   if (0 != gcry_control (GCRYCTL_SET_THREAD_CBS,
                          &gcry_threads_pthread))
@@ -8562,13 +8569,14 @@ MHD_init (void)
                          &gcry_threads_w32))
     MHD_PANIC (_ ("Failed to initialise multithreading in libgcrypt.\n"));
 #endif /* defined(MHD_W32_MUTEX_) */
+#endif /* GNUTLS_VERSION_NUMBER <= 0x020b00 */
   gcry_check_version (NULL);
 #else
   if (NULL == gcry_check_version ("1.6.0"))
     MHD_PANIC (_ (
                  "libgcrypt is too old. MHD was compiled for libgcrypt 1.6.0 
or newer.\n"));
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
   gnutls_global_init ();
 #endif /* HTTPS_SUPPORT */
   MHD_monotonic_sec_counter_init ();
diff --git a/src/microhttpd/digestauth.c b/src/microhttpd/digestauth.c
index 1155e6ff..926ac5f4 100644
--- a/src/microhttpd/digestauth.c
+++ b/src/microhttpd/digestauth.c
@@ -34,10 +34,10 @@
 #include "internal.h"
 #include "response.h"
 #ifdef MHD_MD5_SUPPORT
-#  include "md5.h"
+#  include "mhd_md5_wrap.h"
 #endif /* MHD_MD5_SUPPORT */
 #ifdef MHD_SHA256_SUPPORT
-#  include "sha256.h"
+#  include "mhd_sha256_wrap.h"
 #endif /* MHD_SHA256_SUPPORT */
 #ifdef MHD_SHA512_256_SUPPORT
 #  include "sha512_256.h"
@@ -304,10 +304,10 @@ MHD_digest_get_hash_size (enum MHD_DigestAuthAlgo3 algo3)
 union DigestCtx
 {
 #ifdef MHD_MD5_SUPPORT
-  struct MD5Context md5_ctx;
+  struct Md5CtxWr md5_ctx;
 #endif /* MHD_MD5_SUPPORT */
 #ifdef MHD_SHA256_SUPPORT
-  struct Sha256Ctx sha256_ctx;
+  struct Sha256CtxWr sha256_ctx;
 #endif /* MHD_SHA256_SUPPORT */
 #ifdef MHD_SHA512_256_SUPPORT
   struct Sha512_256Ctx sha512_256_ctx;
@@ -334,9 +334,10 @@ struct DigestAlgorithm
    * Buffer for hex-print of the final digest.
    */
 #if _DEBUG
-  bool setup; /**< The structure was set-up */
-  bool inited; /**< The calculation was initialised */
-  bool digest_calculated; /**< The digest was calculated */
+  bool uninitialised; /**< The structure has been not set-up */
+  bool algo_selected; /**< The algorithm has been selected */
+  bool ready_for_hashing; /**< The structure is ready to hash data */
+  bool hashing; /**< Some data has been hashed, but the digest has not 
finalised yet */
 #endif /* _DEBUG */
 };
 
@@ -349,7 +350,8 @@ struct DigestAlgorithm
 _MHD_static_inline unsigned int
 digest_get_size (struct DigestAlgorithm *da)
 {
-  mhd_assert (da->setup);
+  mhd_assert (! da->uninitialised);
+  mhd_assert (da->algo_selected);
 #ifdef MHD_MD5_SUPPORT
   if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
     return MD5_DIGEST_SIZE;
@@ -367,91 +369,136 @@ digest_get_size (struct DigestAlgorithm *da)
 }
 
 
+#if defined(MHD_MD5_HAS_DEINIT) || defined(MHD_SHA256_HAS_DEINIT)
 /**
- * Set-up the digest calculation structure.
- * @param da the structure to set-up
- * @param algo the algorithm to use for digest calculation
- * @return boolean 'true' if successfully set-up,
- *         false otherwise.
+ * Indicates presence of digest_deinit() function
  */
-_MHD_static_inline bool
-digest_setup (struct DigestAlgorithm *da,
-              enum MHD_DigestBaseAlgo algo)
+#define MHD_DIGEST_HAS_DEINIT 1
+#endif /* MHD_MD5_HAS_DEINIT || MHD_SHA256_HAS_DEINIT */
+
+#ifdef MHD_DIGEST_HAS_DEINIT
+/**
+ * Zero-initialise digest calculation structure.
+ *
+ * This initialisation is enough to safely call #digest_deinit() only.
+ * To make any real digest calculation, #digest_setup_and_init() must be 
called.
+ * @param da the digest calculation
+ */
+_MHD_static_inline void
+digest_setup_zero (struct DigestAlgorithm *da)
 {
 #ifdef _DEBUG
-  da->setup = false;
-  da->inited = false;
-  da->digest_calculated = false;
-#endif /* _DEBUG */
-  if (false
-#ifdef MHD_MD5_SUPPORT
-      || (MHD_DIGEST_BASE_ALGO_MD5 == algo)
-#endif /* MHD_MD5_SUPPORT */
-#ifdef MHD_SHA256_SUPPORT
-      || (MHD_DIGEST_BASE_ALGO_SHA256 == algo)
-#endif /* MHD_SHA256_SUPPORT */
-#ifdef MHD_SHA512_256_SUPPORT
-      || (MHD_DIGEST_BASE_ALGO_SHA512_256 == algo)
-#endif /* MHD_SHA512_256_SUPPORT */
-      )
-  {
-    da->algo = algo;
-#ifdef _DEBUG
-    da->setup = true;
+  da->uninitialised = false;
+  da->algo_selected = false;
+  da->ready_for_hashing = false;
+  da->hashing = false;
 #endif /* _DEBUG */
-    return true;
-  }
-  return false; /* Bad or unsupported algorithm */
+  da->algo = MHD_DIGEST_BASE_ALGO_INVALID;
 }
 
 
 /**
- * Initialise/reset the digest calculation structure.
- * @param da the structure to initialise/reset
+ * De-initialise digest calculation structure.
+ *
+ * This function must be called if #digest_setup_and_init() was called for
+ * @a da.
+ * This function must not be called if @a da was not initialised by
+ * #digest_setup_and_init() or by #digest_setup_zero().
+ * @param da the digest calculation
  */
 _MHD_static_inline void
-digest_init (struct DigestAlgorithm *da)
+digest_deinit (struct DigestAlgorithm *da)
+{
+  mhd_assert (! da->uninitialised);
+#ifdef MHD_MD5_HAS_DEINIT
+  if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
+    MHD_MD5_deinit (&da->ctx.md5_ctx);
+  else
+#endif /* MHD_MD5_HAS_DEINIT */
+#ifdef MHD_SHA256_HAS_DEINIT
+  if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
+    MHD_SHA256_deinit (&da->ctx.sha256_ctx);
+  else
+#endif /* MHD_SHA256_HAS_DEINIT */
+  (void) 0;
+  digest_setup_zero (da);
+}
+
+
+#else  /* ! MHD_DIGEST_HAS_DEINIT */
+#define digest_setup_zero(da) (void)0
+#define digest_deinit(da) (void)0
+#endif /* ! MHD_DIGEST_HAS_DEINIT */
+
+
+/**
+ * Set-up the digest calculation structure and initialise with initial values.
+ *
+ * If @a da was successfully initialised, #digest_deinit() must be called
+ * after finishing using of the @a da.
+ *
+ * This function must not be called more than once for any @a da.
+ *
+ * @param da the structure to set-up
+ * @param algo the algorithm to use for digest calculation
+ * @return boolean 'true' if successfully set-up,
+ *         false otherwise.
+ */
+_MHD_static_inline bool
+digest_init_one_time (struct DigestAlgorithm *da,
+                      enum MHD_DigestBaseAlgo algo)
 {
-  mhd_assert (da->setup);
 #ifdef _DEBUG
-  da->digest_calculated = false;
-#endif
+  da->uninitialised = false;
+  da->algo_selected = false;
+  da->ready_for_hashing = false;
+  da->hashing = false;
+#endif /* _DEBUG */
 #ifdef MHD_MD5_SUPPORT
-  if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
+  if (MHD_DIGEST_BASE_ALGO_MD5 == algo)
   {
-    MHD_MD5Init (&da->ctx.md5_ctx);
+    da->algo = MHD_DIGEST_BASE_ALGO_MD5;
+#ifdef _DEBUG
+    da->algo_selected = true;
+#endif
+    MHD_MD5_init_one_time (&da->ctx.md5_ctx);
 #ifdef _DEBUG
-    da->inited = true;
+    da->ready_for_hashing = true;
 #endif
+    return true;
   }
-  else
 #endif /* MHD_MD5_SUPPORT */
 #ifdef MHD_SHA256_SUPPORT
-  if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
+  if (MHD_DIGEST_BASE_ALGO_SHA256 == algo)
   {
-    MHD_SHA256_init (&da->ctx.sha256_ctx);
+    da->algo = MHD_DIGEST_BASE_ALGO_SHA256;
+#ifdef _DEBUG
+    da->algo_selected = true;
+#endif
+    MHD_SHA256_init_one_time (&da->ctx.sha256_ctx);
 #ifdef _DEBUG
-    da->inited = true;
+    da->ready_for_hashing = true;
 #endif
+    return true;
   }
-  else
 #endif /* MHD_SHA256_SUPPORT */
 #ifdef MHD_SHA512_256_SUPPORT
-  if (MHD_DIGEST_BASE_ALGO_SHA512_256 == da->algo)
+  if (MHD_DIGEST_BASE_ALGO_SHA512_256 == algo)
   {
-    MHD_SHA512_256_init (&da->ctx.sha512_256_ctx);
+    da->algo = MHD_DIGEST_BASE_ALGO_SHA512_256;
 #ifdef _DEBUG
-    da->inited = true;
+    da->algo_selected = true;
 #endif
-  }
-  else
-#endif /* MHD_SHA512_256_SUPPORT */
-  {
+    MHD_SHA512_256_init (&da->ctx.sha512_256_ctx);
 #ifdef _DEBUG
-    da->inited = false;
+    da->ready_for_hashing = true;
 #endif
-    mhd_assert (0); /* Bad algorithm */
+    return true;
   }
+#endif /* MHD_SHA512_256_SUPPORT */
+
+  da->algo = MHD_DIGEST_BASE_ALGO_INVALID;
+  return false; /* Unsupported or bad algorithm */
 }
 
 
@@ -466,11 +513,12 @@ digest_update (struct DigestAlgorithm *da,
                const void *data,
                size_t length)
 {
-  mhd_assert (da->inited);
-  mhd_assert (! da->digest_calculated);
+  mhd_assert (! da->uninitialised);
+  mhd_assert (da->algo_selected);
+  mhd_assert (da->ready_for_hashing);
 #ifdef MHD_MD5_SUPPORT
   if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
-    MHD_MD5Update (&da->ctx.md5_ctx, (const uint8_t *) data, length);
+    MHD_MD5_update (&da->ctx.md5_ctx, (const uint8_t *) data, length);
   else
 #endif /* MHD_MD5_SUPPORT */
 #ifdef MHD_SHA256_SUPPORT
@@ -485,6 +533,9 @@ digest_update (struct DigestAlgorithm *da,
   else
 #endif /* MHD_SHA512_256_SUPPORT */
   mhd_assert (0);   /* May not happen */
+#ifdef _DEBUG
+  da->hashing = true;
+#endif
 }
 
 
@@ -524,30 +575,160 @@ digest_update_with_colon (struct DigestAlgorithm *da)
 _MHD_static_inline void
 digest_calc_hash (struct DigestAlgorithm *da, uint8_t *digest)
 {
-  mhd_assert (da->inited);
-  mhd_assert (! da->digest_calculated);
+  mhd_assert (! da->uninitialised);
+  mhd_assert (da->algo_selected);
+  mhd_assert (da->ready_for_hashing);
 #ifdef MHD_MD5_SUPPORT
   if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
-    MHD_MD5Final (&da->ctx.md5_ctx, digest);
+  {
+#ifdef MHD_MD5_HAS_FINISH
+    MHD_MD5_finish (&da->ctx.md5_ctx, digest);
+#ifdef _DEBUG
+    da->ready_for_hashing = false;
+#endif /* _DEBUG */
+#else  /* ! MHD_MD5_HAS_FINISH */
+    MHD_MD5_finish_reset (&da->ctx.md5_ctx, digest);
+#ifdef _DEBUG
+    da->ready_for_hashing = true;
+#endif /* _DEBUG */
+#endif /* ! MHD_MD5_HAS_FINISH */
+  }
   else
 #endif /* MHD_MD5_SUPPORT */
 #ifdef MHD_SHA256_SUPPORT
   if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
+  {
+#ifdef MHD_SHA256_HAS_FINISH
     MHD_SHA256_finish (&da->ctx.sha256_ctx, digest);
+#ifdef _DEBUG
+    da->ready_for_hashing = false;
+#endif /* _DEBUG */
+#else  /* ! MHD_SHA256_HAS_FINISH */
+    MHD_SHA256_finish_reset (&da->ctx.sha256_ctx, digest);
+#ifdef _DEBUG
+    da->ready_for_hashing = true;
+#endif /* _DEBUG */
+#endif /* ! MHD_SHA256_HAS_FINISH */
+  }
   else
 #endif /* MHD_SHA256_SUPPORT */
 #ifdef MHD_SHA512_256_SUPPORT
   if (MHD_DIGEST_BASE_ALGO_SHA512_256 == da->algo)
+  {
     MHD_SHA512_256_finish (&da->ctx.sha512_256_ctx, digest);
+#ifdef _DEBUG
+    da->ready_for_hashing = false;
+#endif /* _DEBUG */
+  }
   else
 #endif /* MHD_SHA512_256_SUPPORT */
-  mhd_assert (0);   /* May not happen */
+  mhd_assert (0);   /* Should not happen */
+#ifdef _DEBUG
+  da->hashing = false;
+#endif /* _DEBUG */
+}
+
+
+/**
+ * Reset the digest calculation structure.
+ *
+ * @param da the structure to reset
+ */
+_MHD_static_inline void
+digest_reset (struct DigestAlgorithm *da)
+{
+  mhd_assert (! da->uninitialised);
+  mhd_assert (da->algo_selected);
+  mhd_assert (! da->hashing);
+#ifdef MHD_MD5_SUPPORT
+  if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
+  {
+#ifdef MHD_MD5_HAS_FINISH
+    mhd_assert (! da->ready_for_hashing);
+#else  /* ! MHD_MD5_HAS_FINISH */
+    mhd_assert (da->ready_for_hashing);
+#endif /* ! MHD_MD5_HAS_FINISH */
+    MHD_MD5_reset (&da->ctx.md5_ctx);
+#ifdef _DEBUG
+    da->ready_for_hashing = true;
+#endif /* _DEBUG */
+  }
+  else
+#endif /* MHD_MD5_SUPPORT */
+#ifdef MHD_SHA256_SUPPORT
+  if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
+  {
+#ifdef MHD_SHA256_HAS_FINISH
+    mhd_assert (! da->ready_for_hashing);
+#else  /* ! MHD_SHA256_HAS_FINISH */
+    mhd_assert (da->ready_for_hashing);
+#endif /* ! MHD_SHA256_HAS_FINISH */
+    MHD_SHA256_reset (&da->ctx.sha256_ctx);
+#ifdef _DEBUG
+    da->ready_for_hashing = true;
+#endif /* _DEBUG */
+  }
+  else
+#endif /* MHD_SHA256_SUPPORT */
+#ifdef MHD_SHA512_256_SUPPORT
+  if (MHD_DIGEST_BASE_ALGO_SHA512_256 == da->algo)
+  {
+    mhd_assert (! da->ready_for_hashing);
+    MHD_SHA512_256_init (&da->ctx.sha512_256_ctx);
 #ifdef _DEBUG
-  da->digest_calculated = true;
+    da->ready_for_hashing = true;
 #endif
+  }
+  else
+#endif /* MHD_SHA512_256_SUPPORT */
+  {
+#ifdef _DEBUG
+    da->ready_for_hashing = false;
+#endif
+    mhd_assert (0); /* May not happen, bad algorithm */
+  }
+}
+
+
+#if defined(MHD_MD5_HAS_EXT_ERROR) || defined(MHD_SHA256_HAS_EXT_ERROR)
+/**
+ * Indicates that digest algorithm has external error status
+ */
+#define MHD_DIGEST_HAS_EXT_ERROR 1
+#endif /* MHD_MD5_HAS_EXT_ERROR || MHD_SHA256_HAS_EXT_ERROR */
+
+#ifdef MHD_DIGEST_HAS_EXT_ERROR
+/**
+ * Get external error code.
+ *
+ * When external digest calculation used, an error may occur during
+ * initialisation or hashing data. This function checks whether external
+ * error has been reported for digest calculation.
+ * @param da the digest calculation
+ * @return true if external error occurs
+ */
+_MHD_static_inline bool
+digest_ext_error (struct DigestAlgorithm *da)
+{
+  mhd_assert (! da->uninitialised);
+  mhd_assert (da->algo_selected);
+#ifdef MHD_MD5_HAS_EXT_ERROR
+  if (MHD_DIGEST_BASE_ALGO_MD5 == da->algo)
+    return 0 != da->ctx.md5_ctx.ext_error;
+#endif /* MHD_MD5_HAS_EXT_ERROR */
+#ifdef MHD_SHA256_HAS_EXT_ERROR
+  if (MHD_DIGEST_BASE_ALGO_SHA256 == da->algo)
+    return 0 != da->ctx.sha256_ctx.ext_error;
+#endif /* MHD_MD5_HAS_EXT_ERROR */
+  return false;
 }
 
 
+#else  /* ! MHD_DIGEST_HAS_EXT_ERROR */
+#define digest_ext_error(da) (false)
+#endif /* ! MHD_DIGEST_HAS_EXT_ERROR */
+
+
 /**
  * Extract timestamp from the given nonce.
  * @param nonce the nonce to check
@@ -955,7 +1136,7 @@ get_rq_uname (const struct MHD_RqDAuth *params,
     res = MHD_hex_to_bin (uname_info->userhash_hex,
                           uname_info->userhash_hex_len,
                           uname_info->userhash_bin);
-    if (res != uname_info->username_len / 2)
+    if (res != uname_info->userhash_hex_len / 2)
     {
       uname_info->userhash_bin = NULL;
       uname_info->uname_type = MHD_DIGEST_AUTH_UNAME_TYPE_INVALID;
@@ -1313,7 +1494,7 @@ calculate_nonce (uint64_t nonce_time,
                  struct DigestAlgorithm *da,
                  char *nonce)
 {
-  digest_init (da);
+  mhd_assert (! da->hashing);
   if (1)
   {
     /* Add the timestamp to the hash calculation */
@@ -1465,12 +1646,10 @@ is_slot_available (const struct MHD_NonceNc *const nn,
   if (0 == nn->nonce[0])
     return true; /* The slot is empty */
 
-  if ((0 == memcmp (nn->nonce, new_nonce, new_nonce_len)) &&
-      (0 == nn->nonce[new_nonce_len]))
+  if (0 == memcmp (nn->nonce, new_nonce, new_nonce_len))
   {
-    /* The slot has the same nonce already, the same nonce was already 
generated
-     * and used, this slot cannot be used with the same nonce as it would
-     * just reset received 'nc' values. */
+    /* The slot has the same nonce already. This nonce cannot be registered
+     * again as it would just clear 'nc' usage history. */
     return false;
   }
 
@@ -1523,6 +1702,7 @@ calculate_add_nonce (struct MHD_Connection *const 
connection,
   const size_t nonce_size = NONCE_STD_LEN (digest_get_size (da));
   bool ret;
 
+  mhd_assert (! da->hashing);
   mhd_assert (MAX_DIGEST_NONCE_LENGTH >= nonce_size);
   mhd_assert (0 != nonce_size);
 
@@ -1542,6 +1722,11 @@ calculate_add_nonce (struct MHD_Connection *const 
connection,
                    da,
                    nonce);
 
+#ifdef MHD_DIGEST_HAS_EXT_ERROR
+  if (digest_ext_error (da))
+    return false;
+#endif /* MHD_DIGEST_HAS_EXT_ERROR */
+
   if (0 == daemon->nonce_nc_size)
     return false;
 
@@ -1590,6 +1775,7 @@ calculate_add_nonce_with_retry (struct MHD_Connection 
*const connection,
 {
   const uint64_t timestamp1 = MHD_monotonic_msec_counter ();
   const size_t realm_len = strlen (realm);
+  mhd_assert (! da->hashing);
 
 #ifdef HAVE_MESSAGES
   if (0 == MHD_get_master (connection->daemon)->digest_auth_rand_size)
@@ -1613,6 +1799,10 @@ calculate_add_nonce_with_retry (struct MHD_Connection 
*const connection,
     const size_t digest_size = digest_get_size (da);
     char nonce2[NONCE_STD_LEN (MAX_DIGEST) + 1];
     uint64_t timestamp2;
+#ifdef MHD_DIGEST_HAS_EXT_ERROR
+    if (digest_ext_error (da))
+      return false; /* No need to re-try */
+#endif /* MHD_DIGEST_HAS_EXT_ERROR */
     if (0 == MHD_get_master (connection->daemon)->nonce_nc_size)
       return false; /* No need to re-try */
 
@@ -1621,16 +1811,29 @@ calculate_add_nonce_with_retry (struct MHD_Connection 
*const connection,
     {
       /* The timestamps are equal, need to generate some arbitrary
        * difference for nonce. */
+      /* As the number is needed only to differentiate clients, weak
+       * pseudo-random generators could be used. Seeding is not needed. */
       uint64_t base1;
       uint32_t base2;
       uint16_t base3;
       uint8_t base4;
-      base1 = (uint64_t) (uintptr_t) nonce2;
+#ifdef HAVE_RANDOM
+      base1 = ((uint64_t) random ()) ^ UINT64_C (0x54a5acff5be47e63);
+      base4 = 0xb8;
+#elif defined(HAVE_RAND)
+      base1 = ((uint64_t) rand ()) ^ UINT64_C (0xc4bcf553b12f3965);
+      base4 = 0x92;
+#else
+      /* Monotonic msec counter alone does not really help here as it is 
already
+         known that this value is not unique. */
+      base1 = ((uint64_t) (uintptr_t) nonce2) ^ UINT64_C (0xf2e1b21bc6c92655);
       base2 = ((uint32_t) (base1 >> 32)) ^ ((uint32_t) base1);
-      base2 = _MHD_ROTL32 (base2, 4);
+      base2 = _MHD_ROTR32 (base2, 4);
       base3 = ((uint16_t) (base2 >> 16)) ^ ((uint16_t) base2);
       base4 = ((uint8_t) (base3 >> 8)) ^ ((uint8_t) base3);
-      base1 = (uint64_t) (uintptr_t) connection;
+      base1 = ((uint64_t) MHD_monotonic_msec_counter ())
+              ^ UINT64_C (0xccab93f72cf5b15);
+#endif
       base2 = ((uint32_t) (base1 >> 32)) ^ ((uint32_t) base1);
       base2 = _MHD_ROTL32 (base2, (((base4 >> 4) ^ base4) % 32));
       base3 = ((uint16_t) (base2 >> 16)) ^ ((uint16_t) base2);
@@ -1640,6 +1843,7 @@ calculate_add_nonce_with_retry (struct MHD_Connection 
*const connection,
       if (timestamp1 == timestamp2)
         timestamp2 -= 2; /* Fallback value */
     }
+    digest_reset (da);
     if (! calculate_add_nonce (connection, timestamp2, realm, realm_len, da,
                                nonce2))
     {
@@ -1678,7 +1882,7 @@ calc_userdigest (struct DigestAlgorithm *da,
                  const char *password,
                  uint8_t *ha1_bin)
 {
-  digest_init (da);
+  mhd_assert (! da->hashing);
   digest_update (da, username, username_len);
   digest_update_with_colon (da);
   digest_update (da, realm, realm_len);
@@ -1713,8 +1917,10 @@ calc_userdigest (struct DigestAlgorithm *da,
  *                            userdigest upon return
  * @param userdigest_bin the size of the @a userdigest_bin buffer, must be
  *                       at least #MHD_digest_get_hash_size(algo3) bytes long
- * @return MHD_YES on success, MHD_NO if @a userdigest_bin is too small or
- *                             if @a algo3 algorithm is not supported.
+ * @return MHD_YES on success,
+ *         MHD_NO if @a userdigest_bin is too small or if @a algo3 algorithm is
+ *         not supported (or external error has occurred,
+ *         see #MHD_FEATURE_EXTERN_HASH).
  * @sa #MHD_digest_auth_check_digest3()
  * @note Available since #MHD_VERSION 0x00097535
  * @ingroup authentication
@@ -1728,18 +1934,31 @@ MHD_digest_auth_calc_userdigest (enum 
MHD_DigestAuthAlgo3 algo3,
                                  size_t bin_buf_size)
 {
   struct DigestAlgorithm da;
-  if (! digest_setup (&da, get_base_digest_algo (algo3)))
+  enum MHD_Result ret;
+  if (! digest_init_one_time (&da, get_base_digest_algo (algo3)))
     return MHD_NO;
+
   if (digest_get_size (&da) > bin_buf_size)
-    return MHD_NO;
-  calc_userdigest (&da,
-                   username,
-                   strlen (username),
-                   realm,
-                   strlen (realm),
-                   password,
-                   userdigest_bin);
-  return MHD_YES;
+    ret = MHD_NO;
+  else
+  {
+    calc_userdigest (&da,
+                     username,
+                     strlen (username),
+                     realm,
+                     strlen (realm),
+                     password,
+                     userdigest_bin);
+    ret = MHD_YES;
+
+#ifdef MHD_DIGEST_HAS_EXT_ERROR
+    if (digest_ext_error (&da))
+      ret = MHD_NO;
+#endif /* MHD_DIGEST_HAS_EXT_ERROR */
+  }
+  digest_deinit (&da);
+
+  return ret;
 }
 
 
@@ -1763,7 +1982,7 @@ calc_userhash (struct DigestAlgorithm *da,
                uint8_t *digest_bin)
 {
   mhd_assert (NULL != username);
-  digest_init (da);
+  mhd_assert (! da->hashing);
   digest_update (da, username, username_len);
   digest_update_with_colon (da);
   digest_update (da, realm, realm_len);
@@ -1803,8 +2022,10 @@ calc_userhash (struct DigestAlgorithm *da,
  *                          upon return
  * @param bin_buf_size the size of the @a userhash_bin buffer, must be
  *                     at least #MHD_digest_get_hash_size(algo3) bytes long
- * @return MHD_YES on success, MHD_NO if @a bin_buf_size is too small or
- *                             if @a algo3 algorithm is not supported.
+ * @return MHD_YES on success,
+ *         MHD_NO if @a bin_buf_size is too small or if @a algo3 algorithm is
+ *         not supported (or external error has occurred,
+ *         see #MHD_FEATURE_EXTERN_HASH)
  * @note Available since #MHD_VERSION 0x00097535
  * @ingroup authentication
  */
@@ -1816,17 +2037,30 @@ MHD_digest_auth_calc_userhash (enum MHD_DigestAuthAlgo3 
algo3,
                                size_t bin_buf_size)
 {
   struct DigestAlgorithm da;
-  if (! digest_setup (&da, get_base_digest_algo (algo3)))
+  enum MHD_Result ret;
+
+  if (! digest_init_one_time (&da, get_base_digest_algo (algo3)))
     return MHD_NO;
   if (digest_get_size (&da) > bin_buf_size)
-    return MHD_NO;
-  calc_userhash (&da,
-                 username,
-                 strlen (username),
-                 realm,
-                 strlen (realm),
-                 userhash_bin);
-  return MHD_YES;
+    ret = MHD_NO;
+  else
+  {
+    calc_userhash (&da,
+                   username,
+                   strlen (username),
+                   realm,
+                   strlen (realm),
+                   userhash_bin);
+    ret = MHD_YES;
+
+#ifdef MHD_DIGEST_HAS_EXT_ERROR
+    if (digest_ext_error (&da))
+      ret = MHD_NO;
+#endif /* MHD_DIGEST_HAS_EXT_ERROR */
+  }
+  digest_deinit (&da);
+
+  return ret;
 }
 
 
@@ -1862,8 +2096,10 @@ MHD_digest_auth_calc_userhash (enum MHD_DigestAuthAlgo3 
algo3,
  *                          userhash string
  * @param bin_buf_size the size of the @a userhash_bin buffer, must be
  *                     at least #MHD_digest_get_hash_size(algo3)*2+1 chars long
- * @return MHD_YES on success, MHD_NO if @a bin_buf_size is too small or
- *                             if @a algo3 algorithm is not supported.
+ * @return MHD_YES on success,
+ *         MHD_NO if @a bin_buf_size is too small or if @a algo3 algorithm is
+ *         not supported (or external error has occurred,
+ *         see #MHD_FEATURE_EXTERN_HASH).
  * @note Available since #MHD_VERSION 0x00097535
  * @ingroup authentication
  */
@@ -2290,12 +2526,12 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
                              uint32_t max_nc,
                              enum MHD_DigestAuthMultiQOP mqop,
                              enum MHD_DigestAuthMultiAlgo3 malgo3,
-                             char **pbuf)
+                             char **pbuf,
+                             struct DigestAlgorithm *da)
 {
   struct MHD_Daemon *daemon = MHD_get_master (connection->daemon);
   enum MHD_DigestAuthAlgo3 c_algo; /**< Client's algorithm */
   enum MHD_DigestAuthQOP c_qop; /**< Client's QOP */
-  struct DigestAlgorithm da;
   unsigned int digest_size;
   uint8_t hash1_bin[MAX_DIGEST];
   uint8_t hash2_bin[MAX_DIGEST];
@@ -2371,7 +2607,7 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
     return MHD_DAUTH_WRONG_ALGO;
   }
 #endif /* ! MHD_SHA512_256_SUPPORT */
-  if (! digest_setup (&da, get_base_digest_algo (c_algo)))
+  if (! digest_init_one_time (da, get_base_digest_algo (c_algo)))
     MHD_PANIC (_ ("Wrong 'malgo3' value, API violation"));
   /* Check 'mqop' value */
   c_qop = params->qop;
@@ -2395,7 +2631,7 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
                  "non-standard extension.\n"));
 #endif /* HAVE_MESSAGES */
 
-  digest_size = digest_get_size (&da);
+  digest_size = digest_get_size (da);
 
   /* ** A quick check for presence of all required parameters ** */
 
@@ -2513,11 +2749,18 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
   else
   { /* Userhash */
     mhd_assert (NULL != params->username.value.str);
-    calc_userhash (&da, username, username_len, realm, realm_len, hash1_bin);
+    calc_userhash (da, username, username_len, realm, realm_len, hash1_bin);
+#ifdef MHD_DIGEST_HAS_EXT_ERROR
+    if (digest_ext_error (da))
+      return MHD_DAUTH_ERROR;
+#endif /* MHD_DIGEST_HAS_EXT_ERROR */
     mhd_assert (sizeof (tmp1) >= (2 * digest_size));
     MHD_bin_to_hex (hash1_bin, digest_size, tmp1);
     if (! is_param_equal_caseless (&params->username, tmp1, 2 * digest_size))
       return MHD_DAUTH_WRONG_USERNAME;
+    /* To simplify the logic, the digest is reset here instead of resetting
+       before the next hash calculation. */
+    digest_reset (da);
   }
   /* 'username' valid */
 
@@ -2631,9 +2874,9 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
   /* ** Build H(A2) and check URI match in the header and in the request ** */
 
   /* Get 'uri' */
-  digest_init (&da);
-  digest_update_str (&da, connection->rq.method);
-  digest_update_with_colon (&da);
+  mhd_assert (! da->hashing);
+  digest_update_str (da, connection->rq.method);
+  digest_update_with_colon (da);
 #if 0
   /* TODO: add support for "auth-int" */
   digest_update_str (da, hentity);
@@ -2644,33 +2887,45 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
   if (_MHD_UNQ_OK != unq_res)
     return MHD_DAUTH_ERROR;
 
-  digest_update (&da, unq_copy.str, unq_copy.len);
+  digest_update (da, unq_copy.str, unq_copy.len);
   /* The next check will modify copied URI string */
   if (! check_uri_match (connection, unq_copy.str, unq_copy.len))
     return MHD_DAUTH_WRONG_URI;
-  digest_calc_hash (&da, hash2_bin);
+  digest_calc_hash (da, hash2_bin);
+#ifdef MHD_DIGEST_HAS_EXT_ERROR
+  /* Skip digest calculation external error check, the next one checks both */
+#endif /* MHD_DIGEST_HAS_EXT_ERROR */
   /* Got H(A2) */
 
   /* ** Build H(A1) ** */
   if (NULL == userdigest)
-    calc_userdigest (&da,
+  {
+    mhd_assert (! da->hashing);
+    digest_reset (da);
+    calc_userdigest (da,
                      username, username_len,
                      realm, realm_len,
                      password,
                      hash1_bin);
+  }
   /* TODO: support '-sess' versions */
+#ifdef MHD_DIGEST_HAS_EXT_ERROR
+  if (digest_ext_error (da))
+    return MHD_DAUTH_ERROR;
+#endif /* MHD_DIGEST_HAS_EXT_ERROR */
   /* Got H(A1) */
 
   /* **  Check 'response' ** */
 
-  digest_init (&da);
+  mhd_assert (! da->hashing);
+  digest_reset (da);
   /* Update digest with H(A1) */
   mhd_assert (sizeof (tmp1) >= (digest_size * 2));
   if (NULL == userdigest)
     MHD_bin_to_hex (hash1_bin, digest_size, tmp1);
   else
     MHD_bin_to_hex (userdigest, digest_size, tmp1);
-  digest_update (&da, (const uint8_t *) tmp1, digest_size * 2);
+  digest_update (da, (const uint8_t *) tmp1, digest_size * 2);
 
   /* H(A1) is not needed anymore, reuse the buffer.
    * Use hash1_bin for the client's 'response' decoded to binary form. */
@@ -2682,15 +2937,15 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
     return MHD_DAUTH_RESPONSE_WRONG;
 
   /* Update digest with ':' */
-  digest_update_with_colon (&da);
+  digest_update_with_colon (da);
   /* Update digest with 'nonce' text value */
   unq_res = get_unquoted_param (&params->nonce, tmp1, ptmp2, &tmp2_size,
                                 &unquoted);
   if (_MHD_UNQ_OK != unq_res)
     return MHD_DAUTH_ERROR;
-  digest_update (&da, (const uint8_t *) unquoted.str, unquoted.len);
+  digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
   /* Update digest with ':' */
-  digest_update_with_colon (&da);
+  digest_update_with_colon (da);
   if (MHD_DIGEST_AUTH_QOP_NONE != c_qop)
   {
     /* Update digest with 'nc' text value */
@@ -2698,33 +2953,37 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
                                   &unquoted);
     if (_MHD_UNQ_OK != unq_res)
       return MHD_DAUTH_ERROR;
-    digest_update (&da, (const uint8_t *) unquoted.str, unquoted.len);
+    digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
     /* Update digest with ':' */
-    digest_update_with_colon (&da);
+    digest_update_with_colon (da);
     /* Update digest with 'cnonce' value */
     unq_res = get_unquoted_param (&params->cnonce, tmp1, ptmp2, &tmp2_size,
                                   &unquoted);
     if (_MHD_UNQ_OK != unq_res)
       return MHD_DAUTH_ERROR;
-    digest_update (&da, (const uint8_t *) unquoted.str, unquoted.len);
+    digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
     /* Update digest with ':' */
-    digest_update_with_colon (&da);
+    digest_update_with_colon (da);
     /* Update digest with 'qop' value */
     unq_res = get_unquoted_param (&params->qop_raw, tmp1, ptmp2, &tmp2_size,
                                   &unquoted);
     if (_MHD_UNQ_OK != unq_res)
       return MHD_DAUTH_ERROR;
-    digest_update (&da, (const uint8_t *) unquoted.str, unquoted.len);
+    digest_update (da, (const uint8_t *) unquoted.str, unquoted.len);
     /* Update digest with ':' */
-    digest_update_with_colon (&da);
+    digest_update_with_colon (da);
   }
   /* Update digest with H(A2) */
   MHD_bin_to_hex (hash2_bin, digest_size, tmp1);
-  digest_update (&da, (const uint8_t *) tmp1, digest_size * 2);
+  digest_update (da, (const uint8_t *) tmp1, digest_size * 2);
 
   /* H(A2) is not needed anymore, reuse the buffer.
    * Use hash2_bin for the calculated response in binary form */
-  digest_calc_hash (&da, hash2_bin);
+  digest_calc_hash (da, hash2_bin);
+#ifdef MHD_DIGEST_HAS_EXT_ERROR
+  if (digest_ext_error (da))
+    return MHD_DAUTH_ERROR;
+#endif /* MHD_DIGEST_HAS_EXT_ERROR */
 
   if (0 != memcmp (hash1_bin, hash2_bin, digest_size))
     return MHD_DAUTH_RESPONSE_WRONG;
@@ -2734,6 +2993,8 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
     mhd_assert (sizeof(tmp1) >= (NONCE_STD_LEN (digest_size) + 1));
     /* It was already checked that 'nonce' (including timestamp) was generated
        by MHD. */
+    mhd_assert (! da->hashing);
+    digest_reset (da);
     calculate_nonce (nonce_time,
                      connection->rq.http_mthd,
                      connection->rq.method,
@@ -2747,9 +3008,13 @@ digest_auth_check_all_inner (struct MHD_Connection 
*connection,
                      realm,
                      realm_len,
                      daemon->dauth_bind_type,
-                     &da,
+                     da,
                      tmp1);
 
+#ifdef MHD_DIGEST_HAS_EXT_ERROR
+    if (digest_ext_error (da))
+      return MHD_DAUTH_ERROR;
+#endif /* MHD_DIGEST_HAS_EXT_ERROR */
 
     if (! is_param_equal (&params->nonce, tmp1,
                           NONCE_STD_LEN (digest_size)))
@@ -2804,13 +3069,16 @@ digest_auth_check_all (struct MHD_Connection 
*connection,
 {
   enum MHD_DigestAuthResult res;
   char *buf;
+  struct DigestAlgorithm da;
 
   buf = NULL;
+  digest_setup_zero (&da);
   res = digest_auth_check_all_inner (connection, realm, username, password,
                                      userdigest,
                                      nonce_timeout,
                                      max_nc, mqop, malgo3,
-                                     &buf);
+                                     &buf, &da);
+  digest_deinit (&da);
   if (NULL != buf)
     free (buf);
 
@@ -3161,20 +3429,8 @@ MHD_digest_auth_check_digest (struct MHD_Connection 
*connection,
 
 
 /**
- * Queues a response to request authentication from the client
- *
- * This function modifies provided @a response. The @a response must not be
- * reused and should be destroyed (by #MHD_destroy_response()) after call of
- * this function.
- *
- * If @a mqop allows both RFC 2069 (MHD_DIGEST_AUTH_QOP_NONE) and QOP with
- * value, then response is formed like if MHD_DIGEST_AUTH_QOP_NONE bit was
- * not set, because such response should be backward-compatible with RFC 2069.
- *
- * If @a mqop allows only MHD_DIGEST_AUTH_MULT_QOP_NONE, then the response is
- * formed in strict accordance with RFC 2069 (no 'qop', no 'userhash', no
- * 'charset'). For better compatibility with clients, it is recommended (but
- * not required) to set @a domain to NULL in this mode.
+ * Internal version of #MHD_queue_auth_required_response3() to simplify
+ * cleanups.
  *
  * @param connection the MHD connection structure
  * @param realm the realm presented to the client
@@ -3214,21 +3470,26 @@ MHD_digest_auth_check_digest (struct MHD_Connection 
*connection,
  * @param prefer_utf8 if not set to #MHD_NO, parameter 'charset=UTF-8' is
  *                    added, indicating for the client that UTF-8 encoding
  *                    is preferred
+ * @param prefer_utf8 if not set to #MHD_NO, parameter 'charset=UTF-8' is
+ *                    added, indicating for the client that UTF-8 encoding
+ *                    is preferred
  * @return #MHD_YES on success, #MHD_NO otherwise
  * @note Available since #MHD_VERSION 0x00097526
  * @ingroup authentication
  */
-_MHD_EXTERN enum MHD_Result
-MHD_queue_auth_required_response3 (struct MHD_Connection *connection,
-                                   const char *realm,
-                                   const char *opaque,
-                                   const char *domain,
-                                   struct MHD_Response *response,
-                                   int signal_stale,
-                                   enum MHD_DigestAuthMultiQOP mqop,
-                                   enum MHD_DigestAuthMultiAlgo3 malgo3,
-                                   int userhash_support,
-                                   int prefer_utf8)
+static enum MHD_Result
+queue_auth_required_response3_inner (struct MHD_Connection *connection,
+                                     const char *realm,
+                                     const char *opaque,
+                                     const char *domain,
+                                     struct MHD_Response *response,
+                                     int signal_stale,
+                                     enum MHD_DigestAuthMultiQOP mqop,
+                                     enum MHD_DigestAuthMultiAlgo3 malgo3,
+                                     int userhash_support,
+                                     int prefer_utf8,
+                                     char **buf_ptr,
+                                     struct DigestAlgorithm *da)
 {
   static const char prefix_realm[] = "realm=\"";
   static const char prefix_qop[] = "qop=\"";
@@ -3246,7 +3507,6 @@ MHD_queue_auth_required_response3 (struct MHD_Connection 
*connection,
   size_t buf_size;
   char *buf;
   size_t p; /* The position in the buffer */
-  struct DigestAlgorithm da;
 
   if (0 != (((unsigned int) malgo3) & MHD_DIGEST_AUTH_ALGO3_SESSION))
   {
@@ -3256,16 +3516,6 @@ MHD_queue_auth_required_response3 (struct MHD_Connection 
*connection,
 #endif /* HAVE_MESSAGES */
     return MHD_NO;
   }
-#ifndef MHD_SHA512_256_SUPPORT
-  if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_SHA512_256))
-  {
-#ifdef HAVE_MESSAGES
-    MHD_DLOG (connection->daemon,
-              _ ("The SHA-512/256 algorithm is not enabled.\n"));
-#endif /* HAVE_MESSAGES */
-    return MHD_NO;
-  }
-#endif /* ! MHD_SHA512_256_SUPPORT */
 #ifdef MHD_MD5_SUPPORT
   if (0 != (((unsigned int) malgo3) & MHD_DIGEST_BASE_ALGO_MD5))
     s_algo = MHD_DIGEST_AUTH_ALGO3_MD5;
@@ -3300,7 +3550,7 @@ MHD_queue_auth_required_response3 (struct MHD_Connection 
*connection,
       (((unsigned int) mqop) & MHD_DIGEST_AUTH_MULT_QOP_ANY_NON_INT))
     MHD_PANIC (_ ("Wrong 'mqop' value, API violation"));
 
-  if (! digest_setup (&da, get_base_digest_algo (s_algo)))
+  if (! digest_init_one_time (da, get_base_digest_algo (s_algo)))
     MHD_PANIC (_ ("Wrong 'algo' value, API violation"));
 
   if (MHD_DIGEST_AUTH_MULT_QOP_NONE == mqop)
@@ -3346,6 +3596,7 @@ MHD_queue_auth_required_response3 (struct MHD_Connection 
*connection,
   if ((NULL != memchr (realm, '\r', realm_len)) ||
       (NULL != memchr (realm, '\n', realm_len)))
     return MHD_NO;
+
   buf_size += realm_len * 2; /* Quoting may double the size */
   /* 'qop="xxxx", ' */
   if (MHD_DIGEST_AUTH_MULT_QOP_NONE != mqop)
@@ -3377,7 +3628,7 @@ MHD_queue_auth_required_response3 (struct MHD_Connection 
*connection,
   }
   /* 'nonce="xxxx", ' */
   buf_size += MHD_STATICSTR_LEN_ (prefix_nonce) + 3; /* 3 for '", ' */
-  buf_size += NONCE_STD_LEN (digest_get_size (&da)); /* Escaping not needed */
+  buf_size += NONCE_STD_LEN (digest_get_size (da)); /* Escaping not needed */
   /* 'opaque="xxxx", ' */
   if (NULL != opaque)
   {
@@ -3386,6 +3637,7 @@ MHD_queue_auth_required_response3 (struct MHD_Connection 
*connection,
     if ((NULL != memchr (opaque, '\r', opaque_len)) ||
         (NULL != memchr (opaque, '\n', opaque_len)))
       return MHD_NO;
+
     buf_size += opaque_len * 2; /* Quoting may double the size */
   }
   else
@@ -3398,6 +3650,7 @@ MHD_queue_auth_required_response3 (struct MHD_Connection 
*connection,
     if ((NULL != memchr (domain, '\r', domain_len)) ||
         (NULL != memchr (domain, '\n', domain_len)))
       return MHD_NO;
+
     buf_size += domain_len * 2; /* Quoting may double the size */
   }
   else
@@ -3419,6 +3672,7 @@ MHD_queue_auth_required_response3 (struct MHD_Connection 
*connection,
   buf = malloc (buf_size);
   if (NULL == buf)
     return MHD_NO;
+  *buf_ptr = buf;
 
   /* Build the challenge string */
   p = 0;
@@ -3442,7 +3696,6 @@ MHD_queue_auth_required_response3 (struct MHD_Connection 
*connection,
       MHD_DLOG (connection->daemon,
                 _ ("The 'realm' is too large after 'quoting'.\n"));
 #endif /* HAVE_MESSAGES */
-      free (buf);
       return MHD_NO;
     }
     p += quoted_size;
@@ -3505,9 +3758,20 @@ MHD_queue_auth_required_response3 (struct MHD_Connection 
*connection,
   memcpy (buf + p, prefix_nonce,
           MHD_STATICSTR_LEN_ (prefix_nonce));
   p += MHD_STATICSTR_LEN_ (prefix_nonce);
-  mhd_assert ((buf_size - p) >= (NONCE_STD_LEN (digest_get_size (&da))));
-  if (! calculate_add_nonce_with_retry (connection, realm, &da, buf + p))
+  mhd_assert ((buf_size - p) >= (NONCE_STD_LEN (digest_get_size (da))));
+  if (! calculate_add_nonce_with_retry (connection, realm, da, buf + p))
   {
+#ifdef MHD_DIGEST_HAS_EXT_ERROR
+    if (digest_ext_error (da))
+    {
+#ifdef HAVE_MESSAGES
+      MHD_DLOG (connection->daemon,
+                _ ("TLS library reported hash calculation error, nonce could "
+                   "not be generated.\n"));
+#endif /* HAVE_MESSAGES */
+      return MHD_NO;
+    }
+#endif /* MHD_DIGEST_HAS_EXT_ERROR */
 #ifdef HAVE_MESSAGES
     MHD_DLOG (connection->daemon,
               _ ("Could not register nonce. Client's requests with this "
@@ -3516,7 +3780,7 @@ MHD_queue_auth_required_response3 (struct MHD_Connection 
*connection,
 #endif /* HAVE_MESSAGES */
     (void) 0; /* Mute compiler warning for builds without messages */
   }
-  p += NONCE_STD_LEN (digest_get_size (&da));
+  p += NONCE_STD_LEN (digest_get_size (da));
   buf[p++] = '\"';
   buf[p++] = ',';
   buf[p++] = ' ';
@@ -3586,15 +3850,108 @@ MHD_queue_auth_required_response3 (struct 
MHD_Connection *connection,
     MHD_DLOG (connection->daemon,
               _ ("Failed to add Digest auth header.\n"));
 #endif /* HAVE_MESSAGES */
-    free (buf);
     return MHD_NO;
   }
-  free (buf);
 
   return MHD_queue_response (connection, MHD_HTTP_UNAUTHORIZED, response);
 }
 
 
+/**
+ * Queues a response to request authentication from the client
+ *
+ * This function modifies provided @a response. The @a response must not be
+ * reused and should be destroyed (by #MHD_destroy_response()) after call of
+ * this function.
+ *
+ * If @a mqop allows both RFC 2069 (MHD_DIGEST_AUTH_QOP_NONE) and QOP with
+ * value, then response is formed like if MHD_DIGEST_AUTH_QOP_NONE bit was
+ * not set, because such response should be backward-compatible with RFC 2069.
+ *
+ * If @a mqop allows only MHD_DIGEST_AUTH_MULT_QOP_NONE, then the response is
+ * formed in strict accordance with RFC 2069 (no 'qop', no 'userhash', no
+ * 'charset'). For better compatibility with clients, it is recommended (but
+ * not required) to set @a domain to NULL in this mode.
+ *
+ * @param connection the MHD connection structure
+ * @param realm the realm presented to the client
+ * @param opaque the string for opaque value, can be NULL, but NULL is
+ *               not recommended for better compatibility with clients;
+ *               the recommended format is hex or Base64 encoded string
+ * @param domain the optional space-separated list of URIs for which the
+ *               same authorisation could be used, URIs can be in form
+ *               "path-absolute" (the path for the same host with initial 
slash)
+ *               or in form "absolute-URI" (the full path with protocol), in
+ *               any case client may assume that URI is in the same "protection
+ *               space" if it starts with any of values specified here;
+ *               could be NULL (clients typically assume that the same
+ *               credentials could be used for any URI on the same host)
+ * @param response the reply to send; should contain the "access denied"
+ *                 body; note that this function sets the "WWW Authenticate"
+ *                 header and that the caller should not do this;
+ *                 the NULL is tolerated
+ * @param signal_stale set to #MHD_YES if the nonce is stale to add 
'stale=true'
+ *                     to the authentication header, this instructs the client
+ *                     to retry immediately with the new nonce and the same
+ *                     credentials, without asking user for the new password
+ * @param mqop the QOP to use
+ * @param malgo3 digest algorithm to use, MHD selects; if several algorithms
+ *               are allowed then MD5 is preferred (currently, may be changed
+ *               in next versions)
+ * @param userhash_support if set to non-zero value (#MHD_YES) then support of
+ *                         userhash is indicated, the client may provide
+ *                         hash("username:realm") instead of username in
+ *                         clear text;
+ *                         note that clients are allowed to provide the 
username
+ *                         in cleartext even if this parameter set to non-zero;
+ *                         when userhash is used, application must be ready to
+ *                         identify users by provided userhash value instead of
+ *                         username; see #MHD_digest_auth_calc_userhash() and
+ *                         #MHD_digest_auth_calc_userhash_hex()
+ * @param prefer_utf8 if not set to #MHD_NO, parameter 'charset=UTF-8' is
+ *                    added, indicating for the client that UTF-8 encoding
+ *                    is preferred
+ * @return #MHD_YES on success, #MHD_NO otherwise
+ * @note Available since #MHD_VERSION 0x00097526
+ * @ingroup authentication
+ */
+_MHD_EXTERN enum MHD_Result
+MHD_queue_auth_required_response3 (struct MHD_Connection *connection,
+                                   const char *realm,
+                                   const char *opaque,
+                                   const char *domain,
+                                   struct MHD_Response *response,
+                                   int signal_stale,
+                                   enum MHD_DigestAuthMultiQOP mqop,
+                                   enum MHD_DigestAuthMultiAlgo3 malgo3,
+                                   int userhash_support,
+                                   int prefer_utf8)
+{
+  struct DigestAlgorithm da;
+  char *buf_ptr;
+  enum MHD_Result ret;
+
+  buf_ptr = NULL;
+  digest_setup_zero (&da);
+  ret = queue_auth_required_response3_inner (connection,
+                                             realm,
+                                             opaque,
+                                             domain,
+                                             response,
+                                             signal_stale,
+                                             mqop,
+                                             malgo3,
+                                             userhash_support,
+                                             prefer_utf8,
+                                             &buf_ptr,
+                                             &da);
+  digest_deinit (&da);
+  if (NULL != buf_ptr)
+    free (buf_ptr);
+  return ret;
+}
+
+
 /**
  * Queues a response to request authentication from the client
  *
diff --git a/src/microhttpd/md5.c b/src/microhttpd/md5.c
index ada6fd31..609ed50f 100644
--- a/src/microhttpd/md5.c
+++ b/src/microhttpd/md5.c
@@ -1,24 +1,30 @@
 /*
- * This code implements the MD5 message-digest algorithm.
- * The algorithm is due to Ron Rivest. This code was
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD5Context structure, pass it to MHD_MD5Init, call MHD_MD5Update as
- * needed on buffers full of bytes, and then call MHD_MD5Final, which
- * will fill a supplied 16-byte array with the digest.
- */
+     This file is part of GNU libmicrohttpd
+     Copyright (C) 2022 Evgeny Grin (Karlson2k)
+
+     GNU libmicrohttpd is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
 
-/* Based on OpenBSD modifications.
- * Optimized by Karlson2k (Evgeny Grin). */
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library.
+     If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file microhttpd/md5.c
+ * @brief  Calculation of MD5 digest as defined in RFC 1321
+ * @author Karlson2k (Evgeny Grin)
+ */
 
 #include "md5.h"
+
 #include <string.h>
 #ifdef HAVE_MEMORY_H
 #include <memory.h>
@@ -27,293 +33,514 @@
 #include "mhd_assert.h"
 
 /**
- * Number of bytes in single MD5 word
- * used to process data
- */
-#define MD5_BYTES_IN_WORD (32 / 8)
-
-
-/**
- * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
- * initialization constants.
+ * Initialise structure for MD5 calculation.
  *
- * @param ctx must be a `struct MD5Context *`
+ * @param ctx the calculation context
  */
 void
-MHD_MD5Init (struct MD5Context *ctx)
+MHD_MD5_init (struct Md5Ctx *ctx)
 {
-  mhd_assert (ctx != NULL);
+  /* Initial hash values, see RFC 1321, Clause 3.3 (step 3). */
+  /* Note: values specified in RFC by bytes and should be loaded in
+           little-endian mode, therefore hash values here are initialised with
+           original bytes used in little-endian order. */
+  ctx->H[0] = UINT32_C (0x67452301);
+  ctx->H[1] = UINT32_C (0xefcdab89);
+  ctx->H[2] = UINT32_C (0x98badcfe);
+  ctx->H[3] = UINT32_C (0x10325476);
+
+  /* Initialise the number of bytes. */
   ctx->count = 0;
-  ctx->state[0] = UINT32_C (0x67452301);
-  ctx->state[1] = UINT32_C (0xefcdab89);
-  ctx->state[2] = UINT32_C (0x98badcfe);
-  ctx->state[3] = UINT32_C (0x10325476);
 }
 
 
-static void
-MD5Transform (uint32_t state[4],
-              const uint8_t block[MD5_BLOCK_SIZE]);
-
-
 /**
- * Final wrapup--call MD5Pad, fill in digest and zero out ctx.
- *
- * @param ctx must be a `struct MD5Context *`
+ * Base of MD5 transformation.
+ * Gets full 64 bytes block of data and updates hash values;
+ * @param H     hash values
+ * @param M     the data buffer with #MD5_BLOCK_SIZE bytes block
  */
-void
-MHD_MD5Final (struct MD5Context *ctx,
-              uint8_t digest[MD5_DIGEST_SIZE])
+static void
+md5_transform (uint32_t H[MD5_HASH_SIZE_WORDS],
+               const void *M)
 {
-  uint64_t count_bits;
-  size_t have_bytes;
-
-  mhd_assert (ctx != NULL);
-  mhd_assert (digest != NULL);
-
-  /* Convert count to 8 bytes in little endian order. */
-  have_bytes = (ctx->count) & (MD5_BLOCK_SIZE - 1);
-
-  /* Pad data */
-  /* Buffer always have space for one byte or more. */
-  ctx->buffer[have_bytes++] = 0x80; /* First padding byte is 0x80 */
-
-  if (MD5_BLOCK_SIZE - have_bytes < 8)
-  {   /* Not enough space to put number of bits */
-    while (have_bytes < MD5_BLOCK_SIZE)
-      ctx->buffer[have_bytes++] = 0;
-    MD5Transform (ctx->state, ctx->buffer);
-    have_bytes = 0;   /* Additional block */
+  /* Working variables,
+     See RFC 1321, Clause 3.4 (step 4). */
+  uint32_t A = H[0];
+  uint32_t B = H[1];
+  uint32_t C = H[2];
+  uint32_t D = H[3];
+
+  /* The data buffer. See RFC 1321, Clause 3.4 (step 4). */
+  uint32_t X[16];
+
+#ifndef _MHD_GET_32BIT_LE_UNALIGNED
+  if (0 != (((uintptr_t) M) % _MHD_UINT32_ALIGN))
+  { /* The input data is unaligned. */
+    /* Copy the unaligned input data to the aligned buffer. */
+    memcpy (X, M, sizeof(X));
+    /* The X[] buffer itself will be used as the source of the data,
+     * but the data will be reloaded in correct bytes order on
+     * the next steps. */
+    M = (const void *) X;
   }
-  /* Pad out to 56 */
-  memset (ctx->buffer + have_bytes, 0, MD5_BLOCK_SIZE - have_bytes - 8);
-
-  /* Put number of bits */
-  count_bits = ctx->count << 3;
-  _MHD_PUT_64BIT_LE_SAFE (ctx->buffer + 56, count_bits);
-  MD5Transform (ctx->state, ctx->buffer);
-
-  /* Put digest in LE mode */
-#ifndef _MHD_PUT_32BIT_LE_UNALIGNED
-  if (0 != ((uintptr_t) digest) % _MHD_UINT32_ALIGN)
+#endif /* _MHD_GET_32BIT_LE_UNALIGNED */
+
+  /* Four auxiliary functions, see RFC 1321, Clause 3.4 (step 4). */
+  /* Some optimisations used. */
+/* #define F_FUNC(x,y,z) (((x)&(y)) | ((~(x))&(z))) */ /* Original version */
+#define F_FUNC(x,y,z) ((((y) ^ (z)) & (x)) ^ (z))
+/* #define G_FUNC_1(x,y,z) (((x)&(z)) | ((y)&(~(z)))) */ /* Original version */
+/* #define G_FUNC_2(x,y,z) UINT32_C(0) */ /* Original version */
+#ifndef MHD_FAVOR_SMALL_CODE
+#  define G_FUNC_1(x,y,z) ((~(z)) & (y))
+#  define G_FUNC_2(x,y,z) ((z) & (x))
+#else  /* MHD_FAVOR_SMALL_CODE */
+#  define G_FUNC_1(x,y,z) ((((x) ^ (y)) & (z)) ^ (y))
+#  define G_FUNC_2(x,y,z) UINT32_C(0)
+#endif /* MHD_FAVOR_SMALL_CODE */
+#define H_FUNC(x,y,z) ((x) ^ (y) ^ (z)) /* Original version */
+/* #define I_FUNC(x,y,z) ((y) ^ ((x) | (~(z)))) */ /* Original version */
+#define I_FUNC(x,y,z) (((~(z)) | (x)) ^ (y))
+
+  /* One step of round 1 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
+     The original function was modified to use X[k] and T[i] as
+     direct inputs. */
+#define MD5STEP_R1(va,vb,vc,vd,vX,vs,vT) do {          \
+    (va) += (vX) + (vT);                               \
+    (va) += F_FUNC((vb),(vc),(vd));                    \
+    (va) = _MHD_ROTL32((va),(vs)) + (vb); } while (0)
+
+  /* Get value of X(k) from input data buffer.
+     See RFC 1321 Clause 3.4 (step 4). */
+#define GET_X_FROM_DATA(buf,t) \
+  _MHD_GET_32BIT_LE (((const uint32_t*) (buf)) + (t))
+
+  /* One step of round 2 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
+     The original function was modified to use X[k] and T[i] as
+     direct inputs. */
+#define MD5STEP_R2(va,vb,vc,vd,vX,vs,vT) do {         \
+    (va) += (vX) + (vT);                              \
+    (va) += G_FUNC_1((vb),(vc),(vd));                 \
+    (va) += G_FUNC_2((vb),(vc),(vd));                 \
+    (va) = _MHD_ROTL32((va),(vs)) + (vb); } while (0)
+
+  /* One step of round 3 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
+     The original function was modified to use X[k] and T[i] as
+     direct inputs. */
+#define MD5STEP_R3(va,vb,vc,vd,vX,vs,vT) do {         \
+    (va) += (vX) + (vT);                              \
+    (va) += H_FUNC((vb),(vc),(vd));                   \
+    (va) = _MHD_ROTL32((va),(vs)) + (vb); } while (0)
+
+  /* One step of round 4 of MD5 computation, see RFC 1321, Clause 3.4 (step 4).
+     The original function was modified to use X[k] and T[i] as
+     direct inputs. */
+#define MD5STEP_R4(va,vb,vc,vd,vX,vs,vT) do {         \
+    (va) += (vX) + (vT);                              \
+    (va) += I_FUNC((vb),(vc),(vd));                   \
+    (va) = _MHD_ROTL32((va),(vs)) + (vb); } while (0)
+
+#if ! defined(MHD_FAVOR_SMALL_CODE)
+
+  /* Round 1. */
+
+#if _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN
+  if ((const void *) X == M)
   {
-    uint32_t alig_dgst[MD5_DIGEST_SIZE / MD5_BYTES_IN_WORD];
-    _MHD_PUT_32BIT_LE (alig_dgst + 0, ctx->state[0]);
-    _MHD_PUT_32BIT_LE (alig_dgst + 1, ctx->state[1]);
-    _MHD_PUT_32BIT_LE (alig_dgst + 2, ctx->state[2]);
-    _MHD_PUT_32BIT_LE (alig_dgst + 3, ctx->state[3]);
-    /* Copy result to unaligned destination address */
-    memcpy (digest, alig_dgst, MD5_DIGEST_SIZE);
+    /* The input data is already in the data buffer X[] in correct bytes
+       order. */
+    MD5STEP_R1 (A, B, C, D, X[0],  7,  UINT32_C (0xd76aa478));
+    MD5STEP_R1 (D, A, B, C, X[1],  12, UINT32_C (0xe8c7b756));
+    MD5STEP_R1 (C, D, A, B, X[2],  17, UINT32_C (0x242070db));
+    MD5STEP_R1 (B, C, D, A, X[3],  22, UINT32_C (0xc1bdceee));
+
+    MD5STEP_R1 (A, B, C, D, X[4],  7,  UINT32_C (0xf57c0faf));
+    MD5STEP_R1 (D, A, B, C, X[5],  12, UINT32_C (0x4787c62a));
+    MD5STEP_R1 (C, D, A, B, X[6],  17, UINT32_C (0xa8304613));
+    MD5STEP_R1 (B, C, D, A, X[7],  22, UINT32_C (0xfd469501));
+
+    MD5STEP_R1 (A, B, C, D, X[8],  7,  UINT32_C (0x698098d8));
+    MD5STEP_R1 (D, A, B, C, X[9],  12, UINT32_C (0x8b44f7af));
+    MD5STEP_R1 (C, D, A, B, X[10], 17, UINT32_C (0xffff5bb1));
+    MD5STEP_R1 (B, C, D, A, X[11], 22, UINT32_C (0x895cd7be));
+
+    MD5STEP_R1 (A, B, C, D, X[12], 7,  UINT32_C (0x6b901122));
+    MD5STEP_R1 (D, A, B, C, X[13], 12, UINT32_C (0xfd987193));
+    MD5STEP_R1 (C, D, A, B, X[14], 17, UINT32_C (0xa679438e));
+    MD5STEP_R1 (B, C, D, A, X[15], 22, UINT32_C (0x49b40821));
   }
-  else
-#else  /* _MHD_PUT_32BIT_LE_UNALIGNED */
+  else /* Combined with the next 'if' */
+#endif /* _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN */
   if (1)
-#endif /* _MHD_PUT_32BIT_LE_UNALIGNED */
   {
-    /* Use cast to (void*) here to mute compiler alignment warnings.
-     * Compilers are not smart enough to see that alignment has been checked. 
*/
-    _MHD_PUT_32BIT_LE ((void *) (digest + 0), ctx->state[0]);
-    _MHD_PUT_32BIT_LE ((void *) (digest + 4), ctx->state[1]);
-    _MHD_PUT_32BIT_LE ((void *) (digest + 8), ctx->state[2]);
-    _MHD_PUT_32BIT_LE ((void *) (digest + 12), ctx->state[3]);
+    /* The input data is loaded in correct (little-endian) format before
+       calculations on each step. */
+    MD5STEP_R1 (A, B, C, D, X[0]  = GET_X_FROM_DATA (M, 0),  7, \
+                UINT32_C (0xd76aa478));
+    MD5STEP_R1 (D, A, B, C, X[1]  = GET_X_FROM_DATA (M, 1),  12, \
+                UINT32_C (0xe8c7b756));
+    MD5STEP_R1 (C, D, A, B, X[2]  = GET_X_FROM_DATA (M, 2),  17, \
+                UINT32_C (0x242070db));
+    MD5STEP_R1 (B, C, D, A, X[3]  = GET_X_FROM_DATA (M, 3),  22, \
+                UINT32_C (0xc1bdceee));
+
+    MD5STEP_R1 (A, B, C, D, X[4]  = GET_X_FROM_DATA (M, 4),  7, \
+                UINT32_C (0xf57c0faf));
+    MD5STEP_R1 (D, A, B, C, X[5]  = GET_X_FROM_DATA (M, 5),  12, \
+                UINT32_C (0x4787c62a));
+    MD5STEP_R1 (C, D, A, B, X[6]  = GET_X_FROM_DATA (M, 6),  17, \
+                UINT32_C (0xa8304613));
+    MD5STEP_R1 (B, C, D, A, X[7]  = GET_X_FROM_DATA (M, 7),  22, \
+                UINT32_C (0xfd469501));
+
+    MD5STEP_R1 (A, B, C, D, X[8]  = GET_X_FROM_DATA (M, 8),  7, \
+                UINT32_C (0x698098d8));
+    MD5STEP_R1 (D, A, B, C, X[9]  = GET_X_FROM_DATA (M, 9),  12, \
+                UINT32_C (0x8b44f7af));
+    MD5STEP_R1 (C, D, A, B, X[10] = GET_X_FROM_DATA (M, 10), 17, \
+                UINT32_C (0xffff5bb1));
+    MD5STEP_R1 (B, C, D, A, X[11] = GET_X_FROM_DATA (M, 11), 22, \
+                UINT32_C (0x895cd7be));
+
+    MD5STEP_R1 (A, B, C, D, X[12] = GET_X_FROM_DATA (M, 12), 7, \
+                UINT32_C (0x6b901122));
+    MD5STEP_R1 (D, A, B, C, X[13] = GET_X_FROM_DATA (M, 13), 12, \
+                UINT32_C (0xfd987193));
+    MD5STEP_R1 (C, D, A, B, X[14] = GET_X_FROM_DATA (M, 14), 17, \
+                UINT32_C (0xa679438e));
+    MD5STEP_R1 (B, C, D, A, X[15] = GET_X_FROM_DATA (M, 15), 22, \
+                UINT32_C (0x49b40821));
   }
 
-  /* Erase buffer */
-  memset (ctx, 0, sizeof(*ctx));
-}
-
+  /* Round 2. */
+
+  MD5STEP_R2 (A, B, C, D, X[1], 5, UINT32_C (0xf61e2562));
+  MD5STEP_R2 (D, A, B, C, X[6], 9, UINT32_C (0xc040b340));
+  MD5STEP_R2 (C, D, A, B, X[11], 14, UINT32_C (0x265e5a51));
+  MD5STEP_R2 (B, C, D, A, X[0], 20, UINT32_C (0xe9b6c7aa));
+
+  MD5STEP_R2 (A, B, C, D, X[5], 5, UINT32_C (0xd62f105d));
+  MD5STEP_R2 (D, A, B, C, X[10], 9, UINT32_C (0x02441453));
+  MD5STEP_R2 (C, D, A, B, X[15], 14, UINT32_C (0xd8a1e681));
+  MD5STEP_R2 (B, C, D, A, X[4], 20, UINT32_C (0xe7d3fbc8));
+
+  MD5STEP_R2 (A, B, C, D, X[9], 5, UINT32_C (0x21e1cde6));
+  MD5STEP_R2 (D, A, B, C, X[14], 9, UINT32_C (0xc33707d6));
+  MD5STEP_R2 (C, D, A, B, X[3], 14, UINT32_C (0xf4d50d87));
+  MD5STEP_R2 (B, C, D, A, X[8], 20, UINT32_C (0x455a14ed));
+
+  MD5STEP_R2 (A, B, C, D, X[13], 5, UINT32_C (0xa9e3e905));
+  MD5STEP_R2 (D, A, B, C, X[2], 9, UINT32_C (0xfcefa3f8));
+  MD5STEP_R2 (C, D, A, B, X[7], 14, UINT32_C (0x676f02d9));
+  MD5STEP_R2 (B, C, D, A, X[12], 20, UINT32_C (0x8d2a4c8a));
+
+  /* Round 3. */
+
+  MD5STEP_R3 (A, B, C, D, X[5], 4, UINT32_C (0xfffa3942));
+  MD5STEP_R3 (D, A, B, C, X[8], 11, UINT32_C (0x8771f681));
+  MD5STEP_R3 (C, D, A, B, X[11], 16, UINT32_C (0x6d9d6122));
+  MD5STEP_R3 (B, C, D, A, X[14], 23, UINT32_C (0xfde5380c));
+
+  MD5STEP_R3 (A, B, C, D, X[1], 4, UINT32_C (0xa4beea44));
+  MD5STEP_R3 (D, A, B, C, X[4], 11, UINT32_C (0x4bdecfa9));
+  MD5STEP_R3 (C, D, A, B, X[7], 16, UINT32_C (0xf6bb4b60));
+  MD5STEP_R3 (B, C, D, A, X[10], 23, UINT32_C (0xbebfbc70));
+
+  MD5STEP_R3 (A, B, C, D, X[13], 4, UINT32_C (0x289b7ec6));
+  MD5STEP_R3 (D, A, B, C, X[0], 11, UINT32_C (0xeaa127fa));
+  MD5STEP_R3 (C, D, A, B, X[3], 16, UINT32_C (0xd4ef3085));
+  MD5STEP_R3 (B, C, D, A, X[6], 23, UINT32_C (0x04881d05));
+
+  MD5STEP_R3 (A, B, C, D, X[9], 4, UINT32_C (0xd9d4d039));
+  MD5STEP_R3 (D, A, B, C, X[12], 11, UINT32_C (0xe6db99e5));
+  MD5STEP_R3 (C, D, A, B, X[15], 16, UINT32_C (0x1fa27cf8));
+  MD5STEP_R3 (B, C, D, A, X[2], 23, UINT32_C (0xc4ac5665));
+
+  /* Round 4. */
+
+  MD5STEP_R4 (A, B, C, D, X[0], 6, UINT32_C (0xf4292244));
+  MD5STEP_R4 (D, A, B, C, X[7], 10, UINT32_C (0x432aff97));
+  MD5STEP_R4 (C, D, A, B, X[14], 15, UINT32_C (0xab9423a7));
+  MD5STEP_R4 (B, C, D, A, X[5], 21, UINT32_C (0xfc93a039));
+
+  MD5STEP_R4 (A, B, C, D, X[12], 6, UINT32_C (0x655b59c3));
+  MD5STEP_R4 (D, A, B, C, X[3], 10, UINT32_C (0x8f0ccc92));
+  MD5STEP_R4 (C, D, A, B, X[10], 15, UINT32_C (0xffeff47d));
+  MD5STEP_R4 (B, C, D, A, X[1], 21, UINT32_C (0x85845dd1));
+
+  MD5STEP_R4 (A, B, C, D, X[8], 6, UINT32_C (0x6fa87e4f));
+  MD5STEP_R4 (D, A, B, C, X[15], 10, UINT32_C (0xfe2ce6e0));
+  MD5STEP_R4 (C, D, A, B, X[6], 15, UINT32_C (0xa3014314));
+  MD5STEP_R4 (B, C, D, A, X[13], 21, UINT32_C (0x4e0811a1));
+
+  MD5STEP_R4 (A, B, C, D, X[4], 6, UINT32_C (0xf7537e82));
+  MD5STEP_R4 (D, A, B, C, X[11], 10, UINT32_C (0xbd3af235));
+  MD5STEP_R4 (C, D, A, B, X[2], 15, UINT32_C (0x2ad7d2bb));
+  MD5STEP_R4 (B, C, D, A, X[9], 21, UINT32_C (0xeb86d391));
+#else  /* MHD_FAVOR_SMALL_CODE */
+  if (1)
+  {
+    static const uint32_t T[64] =
+    { UINT32_C (0xd76aa478), UINT32_C (0xe8c7b756), UINT32_C (0x242070db),
+      UINT32_C (0xc1bdceee), UINT32_C (0xf57c0faf), UINT32_C (0x4787c62a),
+      UINT32_C (0xa8304613), UINT32_C (0xfd469501), UINT32_C (0x698098d8),
+      UINT32_C (0x8b44f7af), UINT32_C (0xffff5bb1), UINT32_C (0x895cd7be),
+      UINT32_C (0x6b901122), UINT32_C (0xfd987193), UINT32_C (0xa679438e),
+      UINT32_C (0x49b40821), UINT32_C (0xf61e2562), UINT32_C (0xc040b340),
+      UINT32_C (0x265e5a51), UINT32_C (0xe9b6c7aa), UINT32_C (0xd62f105d),
+      UINT32_C (0x02441453), UINT32_C (0xd8a1e681), UINT32_C (0xe7d3fbc8),
+      UINT32_C (0x21e1cde6), UINT32_C (0xc33707d6), UINT32_C (0xf4d50d87),
+      UINT32_C (0x455a14ed), UINT32_C (0xa9e3e905), UINT32_C (0xfcefa3f8),
+      UINT32_C (0x676f02d9), UINT32_C (0x8d2a4c8a), UINT32_C (0xfffa3942),
+      UINT32_C (0x8771f681), UINT32_C (0x6d9d6122), UINT32_C (0xfde5380c),
+      UINT32_C (0xa4beea44), UINT32_C (0x4bdecfa9), UINT32_C (0xf6bb4b60),
+      UINT32_C (0xbebfbc70), UINT32_C (0x289b7ec6), UINT32_C (0xeaa127fa),
+      UINT32_C (0xd4ef3085), UINT32_C (0x04881d05), UINT32_C (0xd9d4d039),
+      UINT32_C (0xe6db99e5), UINT32_C (0x1fa27cf8), UINT32_C (0xc4ac5665),
+      UINT32_C (0xf4292244), UINT32_C (0x432aff97), UINT32_C (0xab9423a7),
+      UINT32_C (0xfc93a039), UINT32_C (0x655b59c3), UINT32_C (0x8f0ccc92),
+      UINT32_C (0xffeff47d), UINT32_C (0x85845dd1), UINT32_C (0x6fa87e4f),
+      UINT32_C (0xfe2ce6e0), UINT32_C (0xa3014314), UINT32_C (0x4e0811a1),
+      UINT32_C (0xf7537e82), UINT32_C (0xbd3af235), UINT32_C (0x2ad7d2bb),
+      UINT32_C (0xeb86d391) };
+    unsigned int i; /**< Zero-based index */
+
+    /* Round 1. */
+
+    i = 0;
+    do
+    {
+      /* The input data is loaded in correct (little-endian) format before
+         calculations on each step. */
+      MD5STEP_R1 (A, B, C, D, X[i]  = GET_X_FROM_DATA (M, i),  7,  T[i]);
+      ++i;
+      MD5STEP_R1 (D, A, B, C, X[i]  = GET_X_FROM_DATA (M, i),  12, T[i]);
+      ++i;
+      MD5STEP_R1 (C, D, A, B, X[i]  = GET_X_FROM_DATA (M, i),  17, T[i]);
+      ++i;
+      MD5STEP_R1 (B, C, D, A, X[i]  = GET_X_FROM_DATA (M, i),  22, T[i]);
+      ++i;
+    } while (i < 16);
+
+    /* Round 2. */
+
+    do
+    {
+      const unsigned int idx_add = i;
+      MD5STEP_R2 (A, B, C, D, X[(1U  + idx_add) & 15U], 5,  T[i]);
+      ++i;
+      MD5STEP_R2 (D, A, B, C, X[(6U  + idx_add) & 15U], 9,  T[i]);
+      ++i;
+      MD5STEP_R2 (C, D, A, B, X[(11U + idx_add) & 15U], 14, T[i]);
+      ++i;
+      MD5STEP_R2 (B, C, D, A, X[(0U  + idx_add) & 15U], 20, T[i]);
+      ++i;
+    } while (i < 32);
+
+    /* Round 3. */
+
+    do
+    {
+      const unsigned int idx_add = i;
+      MD5STEP_R3 (A, B, C, D, X[(5U  + 64U - idx_add) & 15U], 4,  T[i]);
+      ++i;
+      MD5STEP_R3 (D, A, B, C, X[(8U  + 64U - idx_add) & 15U], 11, T[i]);
+      ++i;
+      MD5STEP_R3 (C, D, A, B, X[(11U + 64U - idx_add) & 15U], 16, T[i]);
+      ++i;
+      MD5STEP_R3 (B, C, D, A, X[(14U + 64U - idx_add) & 15U], 23, T[i]);
+      ++i;
+    } while (i < 48);
+
+    /* Round 4. */
+
+    do
+    {
+      const unsigned int idx_add = i;
+      MD5STEP_R4 (A, B, C, D, X[(0U  + 64U - idx_add) & 15U], 6,  T[i]);
+      ++i;
+      MD5STEP_R4 (D, A, B, C, X[(7U  + 64U - idx_add) & 15U], 10, T[i]);
+      ++i;
+      MD5STEP_R4 (C, D, A, B, X[(14U + 64U - idx_add) & 15U], 15, T[i]);
+      ++i;
+      MD5STEP_R4 (B, C, D, A, X[(5U  + 64U - idx_add) & 15U], 21, T[i]);
+      ++i;
+    } while (i < 64);
+  }
+#endif /* MHD_FAVOR_SMALL_CODE */
 
-/* The four core functions - F1 is optimized somewhat */
+  /* Finally increment and store working variables.
+     See RFC 1321, end of Clause 3.4 (step 4). */
 
-/* #define F1(x, y, z) (x & y | ~x & z) */
-#define F1(x, y, z) (z ^ (x & (y ^ z)))
-#define F2(x, y, z) F1 (z, x, y)
-#define F3(x, y, z) (x ^ y ^ z)
-#define F4(x, y, z) (y ^ (x | ~z))
+  H[0] += A;
+  H[1] += B;
+  H[2] += C;
+  H[3] += D;
+}
 
-/* This is the central step in the MD5 algorithm. */
-#define MD5STEP(f, w, x, y, z, data, s) \
-  (w += f (x, y, z) + data,  w = _MHD_ROTL32(w, 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.  MHD_MD5Update blocks
- * the data and converts bytes into longwords for this routine.
+ * Process portion of bytes.
+ *
+ * @param ctx the calculation context
+ * @param data bytes to add to hash
+ * @param length number of bytes in @a data
  */
-static void
-MD5Transform (uint32_t state[4],
-              const uint8_t block[MD5_BLOCK_SIZE])
+void
+MHD_MD5_update (struct Md5Ctx *ctx,
+                const uint8_t *data,
+                size_t length)
 {
-  uint32_t a, b, c, d;
-  uint32_t data_buf[MD5_BLOCK_SIZE / MD5_BYTES_IN_WORD];
-  const uint32_t *in;
+  unsigned int bytes_have; /**< Number of bytes in the context buffer */
 
-#if (_MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN) || \
-  ! defined(_MHD_GET_32BIT_LE_UNALIGNED)
-  if (0 != (((uintptr_t) block) % _MHD_UINT32_ALIGN))
+  mhd_assert ((data != NULL) || (length == 0));
+
+#ifndef MHD_FAVOR_SMALL_CODE
+  if (0 == length)
+    return; /* Shortcut, do nothing */
+#endif /* MHD_FAVOR_SMALL_CODE */
+
+  /* Note: (count & (MD5_BLOCK_SIZE-1))
+           equals (count % MD5_BLOCK_SIZE) for this block size. */
+  bytes_have = (unsigned int) (ctx->count & (MD5_BLOCK_SIZE - 1));
+  ctx->count += length;
+
+  if (0 != bytes_have)
   {
-    /* Copy data to the aligned buffer */
-    memcpy (data_buf, block, MD5_BLOCK_SIZE);
-    in = data_buf;
+    unsigned int bytes_left = MD5_BLOCK_SIZE - bytes_have;
+    if (length >= bytes_left)
+    {     /* Combine new data with data in the buffer and
+             process the full block. */
+      memcpy (((uint8_t *) ctx->buffer) + bytes_have,
+              data,
+              bytes_left);
+      data += bytes_left;
+      length -= bytes_left;
+      md5_transform (ctx->H, ctx->buffer);
+      bytes_have = 0;
+    }
+  }
+
+  while (MD5_BLOCK_SIZE <= length)
+  {   /* Process any full blocks of new data directly,
+         without copying to the buffer. */
+    md5_transform (ctx->H, data);
+    data += MD5_BLOCK_SIZE;
+    length -= MD5_BLOCK_SIZE;
+  }
+
+  if (0 != length)
+  {   /* Copy incomplete block of new data (if any)
+         to the buffer. */
+    memcpy (((uint8_t *) ctx->buffer) + bytes_have, data, length);
   }
-  else
-    in = (const uint32_t *) ((const void *) block);
-#endif /* _MHD_BYTE_ORDER == _MHD_LITTLE_ENDIAN) || \
-          ! _MHD_GET_32BIT_LE_UNALIGNED */
-#if _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN
-  data_buf[0] = _MHD_GET_32BIT_LE (in + 0);
-  data_buf[1] = _MHD_GET_32BIT_LE (in + 1);
-  data_buf[2] = _MHD_GET_32BIT_LE (in + 2);
-  data_buf[3] = _MHD_GET_32BIT_LE (in + 3);
-  data_buf[4] = _MHD_GET_32BIT_LE (in + 4);
-  data_buf[5] = _MHD_GET_32BIT_LE (in + 5);
-  data_buf[6] = _MHD_GET_32BIT_LE (in + 6);
-  data_buf[7] = _MHD_GET_32BIT_LE (in + 7);
-  data_buf[8] = _MHD_GET_32BIT_LE (in + 8);
-  data_buf[9] = _MHD_GET_32BIT_LE (in + 9);
-  data_buf[10] = _MHD_GET_32BIT_LE (in + 10);
-  data_buf[11] = _MHD_GET_32BIT_LE (in + 11);
-  data_buf[12] = _MHD_GET_32BIT_LE (in + 12);
-  data_buf[13] = _MHD_GET_32BIT_LE (in + 13);
-  data_buf[14] = _MHD_GET_32BIT_LE (in + 14);
-  data_buf[15] = _MHD_GET_32BIT_LE (in + 15);
-  in = data_buf;
-#endif /* _MHD_BYTE_ORDER != _MHD_LITTLE_ENDIAN */
-
-  a = state[0];
-  b = state[1];
-  c = state[2];
-  d = state[3];
-
-  MD5STEP (F1, a, b, c, d, in[0]  + UINT32_C (0xd76aa478), 7);
-  MD5STEP (F1, d, a, b, c, in[1]  + UINT32_C (0xe8c7b756), 12);
-  MD5STEP (F1, c, d, a, b, in[2]  + UINT32_C (0x242070db), 17);
-  MD5STEP (F1, b, c, d, a, in[3]  + UINT32_C (0xc1bdceee), 22);
-  MD5STEP (F1, a, b, c, d, in[4]  + UINT32_C (0xf57c0faf), 7);
-  MD5STEP (F1, d, a, b, c, in[5]  + UINT32_C (0x4787c62a), 12);
-  MD5STEP (F1, c, d, a, b, in[6]  + UINT32_C (0xa8304613), 17);
-  MD5STEP (F1, b, c, d, a, in[7]  + UINT32_C (0xfd469501), 22);
-  MD5STEP (F1, a, b, c, d, in[8]  + UINT32_C (0x698098d8), 7);
-  MD5STEP (F1, d, a, b, c, in[9]  + UINT32_C (0x8b44f7af), 12);
-  MD5STEP (F1, c, d, a, b, in[10] + UINT32_C (0xffff5bb1), 17);
-  MD5STEP (F1, b, c, d, a, in[11] + UINT32_C (0x895cd7be), 22);
-  MD5STEP (F1, a, b, c, d, in[12] + UINT32_C (0x6b901122), 7);
-  MD5STEP (F1, d, a, b, c, in[13] + UINT32_C (0xfd987193), 12);
-  MD5STEP (F1, c, d, a, b, in[14] + UINT32_C (0xa679438e), 17);
-  MD5STEP (F1, b, c, d, a, in[15] + UINT32_C (0x49b40821), 22);
-
-  MD5STEP (F2, a, b, c, d, in[1]  + UINT32_C (0xf61e2562), 5);
-  MD5STEP (F2, d, a, b, c, in[6]  + UINT32_C (0xc040b340), 9);
-  MD5STEP (F2, c, d, a, b, in[11] + UINT32_C (0x265e5a51), 14);
-  MD5STEP (F2, b, c, d, a, in[0]  + UINT32_C (0xe9b6c7aa), 20);
-  MD5STEP (F2, a, b, c, d, in[5]  + UINT32_C (0xd62f105d), 5);
-  MD5STEP (F2, d, a, b, c, in[10] + UINT32_C (0x02441453), 9);
-  MD5STEP (F2, c, d, a, b, in[15] + UINT32_C (0xd8a1e681), 14);
-  MD5STEP (F2, b, c, d, a, in[4]  + UINT32_C (0xe7d3fbc8), 20);
-  MD5STEP (F2, a, b, c, d, in[9]  + UINT32_C (0x21e1cde6), 5);
-  MD5STEP (F2, d, a, b, c, in[14] + UINT32_C (0xc33707d6), 9);
-  MD5STEP (F2, c, d, a, b, in[3]  + UINT32_C (0xf4d50d87), 14);
-  MD5STEP (F2, b, c, d, a, in[8]  + UINT32_C (0x455a14ed), 20);
-  MD5STEP (F2, a, b, c, d, in[13] + UINT32_C (0xa9e3e905), 5);
-  MD5STEP (F2, d, a, b, c, in[2]  + UINT32_C (0xfcefa3f8), 9);
-  MD5STEP (F2, c, d, a, b, in[7]  + UINT32_C (0x676f02d9), 14);
-  MD5STEP (F2, b, c, d, a, in[12] + UINT32_C (0x8d2a4c8a), 20);
-
-  MD5STEP (F3, a, b, c, d, in[5]  + UINT32_C (0xfffa3942), 4);
-  MD5STEP (F3, d, a, b, c, in[8]  + UINT32_C (0x8771f681), 11);
-  MD5STEP (F3, c, d, a, b, in[11] + UINT32_C (0x6d9d6122), 16);
-  MD5STEP (F3, b, c, d, a, in[14] + UINT32_C (0xfde5380c), 23);
-  MD5STEP (F3, a, b, c, d, in[1]  + UINT32_C (0xa4beea44), 4);
-  MD5STEP (F3, d, a, b, c, in[4]  + UINT32_C (0x4bdecfa9), 11);
-  MD5STEP (F3, c, d, a, b, in[7]  + UINT32_C (0xf6bb4b60), 16);
-  MD5STEP (F3, b, c, d, a, in[10] + UINT32_C (0xbebfbc70), 23);
-  MD5STEP (F3, a, b, c, d, in[13] + UINT32_C (0x289b7ec6), 4);
-  MD5STEP (F3, d, a, b, c, in[0]  + UINT32_C (0xeaa127fa), 11);
-  MD5STEP (F3, c, d, a, b, in[3]  + UINT32_C (0xd4ef3085), 16);
-  MD5STEP (F3, b, c, d, a, in[6]  + UINT32_C (0x04881d05), 23);
-  MD5STEP (F3, a, b, c, d, in[9]  + UINT32_C (0xd9d4d039), 4);
-  MD5STEP (F3, d, a, b, c, in[12] + UINT32_C (0xe6db99e5), 11);
-  MD5STEP (F3, c, d, a, b, in[15] + UINT32_C (0x1fa27cf8), 16);
-  MD5STEP (F3, b, c, d, a, in[2]  + UINT32_C (0xc4ac5665), 23);
-
-  MD5STEP (F4, a, b, c, d, in[0]  + UINT32_C (0xf4292244), 6);
-  MD5STEP (F4, d, a, b, c, in[7]  + UINT32_C (0x432aff97), 10);
-  MD5STEP (F4, c, d, a, b, in[14] + UINT32_C (0xab9423a7), 15);
-  MD5STEP (F4, b, c, d, a, in[5]  + UINT32_C (0xfc93a039), 21);
-  MD5STEP (F4, a, b, c, d, in[12] + UINT32_C (0x655b59c3), 6);
-  MD5STEP (F4, d, a, b, c, in[3]  + UINT32_C (0x8f0ccc92), 10);
-  MD5STEP (F4, c, d, a, b, in[10] + UINT32_C (0xffeff47d), 15);
-  MD5STEP (F4, b, c, d, a, in[1]  + UINT32_C (0x85845dd1), 21);
-  MD5STEP (F4, a, b, c, d, in[8]  + UINT32_C (0x6fa87e4f), 6);
-  MD5STEP (F4, d, a, b, c, in[15] + UINT32_C (0xfe2ce6e0), 10);
-  MD5STEP (F4, c, d, a, b, in[6]  + UINT32_C (0xa3014314), 15);
-  MD5STEP (F4, b, c, d, a, in[13] + UINT32_C (0x4e0811a1), 21);
-  MD5STEP (F4, a, b, c, d, in[4]  + UINT32_C (0xf7537e82), 6);
-  MD5STEP (F4, d, a, b, c, in[11] + UINT32_C (0xbd3af235), 10);
-  MD5STEP (F4, c, d, a, b, in[2]  + UINT32_C (0x2ad7d2bb), 15);
-  MD5STEP (F4, b, c, d, a, in[9]  + UINT32_C (0xeb86d391), 21);
-
-  state[0] += a;
-  state[1] += b;
-  state[2] += c;
-  state[3] += d;
 }
 
 
 /**
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
+ * Size of "length" insertion in bits.
+ * See RFC 1321, end of Clause 3.2 (step 2).
+ */
+#define MD5_SIZE_OF_LEN_ADD_BITS 64
+
+/**
+ * Size of "length" insertion in bytes.
+ */
+#define MD5_SIZE_OF_LEN_ADD (MD5_SIZE_OF_LEN_ADD_BITS / 8)
+
+/**
+ * Finalise MD5 calculation, return digest.
  *
- * @param ctx must be a `struct MD5Context *`
- * @param input bytes to add to hash
- * @param len the number of bytes in @a data
+ * @param ctx the calculation context
+ * @param[out] digest set to the hash, must be #MD5_DIGEST_SIZE bytes
  */
 void
-MHD_MD5Update (struct MD5Context *ctx,
-               const uint8_t *input,
-               size_t len)
+MHD_MD5_finish (struct Md5Ctx *ctx,
+                uint8_t digest[MD5_DIGEST_SIZE])
 {
-  size_t have, need;
-
-  mhd_assert (ctx != NULL);
-  mhd_assert ((ctx != NULL) || (len == 0));
-
-  /* Check how many bytes we already have and how many more we need. */
-  have = (size_t) ((ctx->count) & (MD5_BLOCK_SIZE - 1));
-  need = MD5_BLOCK_SIZE - have;
-
-  /* Update bytecount */
-  ctx->count += (uint64_t) len;
+  uint64_t num_bits;   /**< Number of processed bits */
+  unsigned int bytes_have; /**< Number of bytes in the context buffer */
+
+  /* Memorise the number of processed bits.
+     The padding and other data added here during the postprocessing must
+     not change the amount of hashed data. */
+  num_bits = ctx->count << 3;
+
+  /* Note: (count & (MD5_BLOCK_SIZE-1))
+           equals (count % MD5_BLOCK_SIZE) for this block size. */
+  bytes_have = (unsigned int) (ctx->count & (MD5_BLOCK_SIZE - 1));
+
+  /* Input data must be padded with a single bit "1", then with zeros and
+     the finally the length of data in bits must be added as the final bytes
+     of the last block.
+     See RFC 1321, Clauses 3.1 and 3.2 (steps 1 and 2). */
+  /* Data is always processed in form of bytes (not by individual bits),
+     therefore position of the first padding bit in byte is always
+     predefined (0x80). */
+  /* Buffer always have space for one byte at least (as full buffers are
+     processed immediately). */
+  ((uint8_t *) ctx->buffer)[bytes_have++] = 0x80;
+
+  if (MD5_BLOCK_SIZE - bytes_have < MD5_SIZE_OF_LEN_ADD)
+  {   /* No space in the current block to put the total length of message.
+         Pad the current block with zeros and process it. */
+    if (bytes_have < MD5_BLOCK_SIZE)
+      memset (((uint8_t *) ctx->buffer) + bytes_have, 0,
+              MD5_BLOCK_SIZE - bytes_have);
+    /* Process the full block. */
+    md5_transform (ctx->H, ctx->buffer);
+    /* Start the new block. */
+    bytes_have = 0;
+  }
 
-  if (len >= need)
+  /* Pad the rest of the buffer with zeros. */
+  memset (((uint8_t *) ctx->buffer) + bytes_have, 0,
+          MD5_BLOCK_SIZE - MD5_SIZE_OF_LEN_ADD - bytes_have);
+  /* Put the number of bits in processed data as little-endian value.
+     See RFC 1321, clauses 2 and 3.2 (step 2). */
+  _MHD_PUT_64BIT_LE_SAFE (ctx->buffer + MD5_BLOCK_SIZE_WORDS - 2,
+                          num_bits);
+  /* Process the full final block. */
+  md5_transform (ctx->H, ctx->buffer);
+
+  /* Put in LE mode the hash as the final digest.
+     See RFC 1321, clauses 2 and 3.5 (step 5). */
+#ifndef _MHD_PUT_32BIT_LE_UNALIGNED
+  if (1
+#ifndef MHD_FAVOR_SMALL_CODE
+      && (0 != ((uintptr_t) digest) % _MHD_UINT32_ALIGN)
+#endif /* MHD_FAVOR_SMALL_CODE */
+      )
   {
-    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;
-    }
+    /* If storing of the final result requires aligned address and
+       the destination address is not aligned or compact code is used,
+       store the final digest in aligned temporary buffer first, then
+       copy it to the destination. */
+    uint32_t alig_dgst[MD5_DIGEST_SIZE_WORDS];
+    _MHD_PUT_32BIT_LE (alig_dgst + 0, ctx->H[0]);
+    _MHD_PUT_32BIT_LE (alig_dgst + 1, ctx->H[1]);
+    _MHD_PUT_32BIT_LE (alig_dgst + 2, ctx->H[2]);
+    _MHD_PUT_32BIT_LE (alig_dgst + 3, ctx->H[3]);
+    /* Copy result to the unaligned destination address. */
+    memcpy (digest, alig_dgst, MD5_DIGEST_SIZE);
   }
+#ifndef MHD_FAVOR_SMALL_CODE
+  else /* Combined with the next 'if' */
+#endif /* MHD_FAVOR_SMALL_CODE */
+#endif /* ! _MHD_PUT_32BIT_LE_UNALIGNED */
+#if ! defined(MHD_FAVOR_SMALL_CODE) || defined(_MHD_PUT_32BIT_LE_UNALIGNED)
+  if (1)
+  {
+    /* Use cast to (void*) here to mute compiler alignment warnings.
+     * Compilers are not smart enough to see that alignment has been checked. 
*/
+    _MHD_PUT_32BIT_LE ((void *) (digest + 0 * MD5_BYTES_IN_WORD), ctx->H[0]);
+    _MHD_PUT_32BIT_LE ((void *) (digest + 1 * MD5_BYTES_IN_WORD), ctx->H[1]);
+    _MHD_PUT_32BIT_LE ((void *) (digest + 2 * MD5_BYTES_IN_WORD), ctx->H[2]);
+    _MHD_PUT_32BIT_LE ((void *) (digest + 3 * MD5_BYTES_IN_WORD), ctx->H[3]);
+  }
+#endif /* ! MHD_FAVOR_SMALL_CODE || _MHD_PUT_32BIT_LE_UNALIGNED */
 
-  /* Handle any remaining bytes of data. */
-  if (0 != len)
-    memcpy (ctx->buffer + have,
-            input,
-            len);
+  /* Erase potentially sensitive data. */
+  memset (ctx, 0, sizeof(struct Md5Ctx));
 }
-
-
-/* end of md5.c */
diff --git a/src/microhttpd/md5.h b/src/microhttpd/md5.h
index bdfc031c..71cb29f3 100644
--- a/src/microhttpd/md5.h
+++ b/src/microhttpd/md5.h
@@ -1,73 +1,131 @@
 /*
- * This code implements the MD5 message-digest algorithm.
- * The algorithm is due to Ron Rivest. This code was
- * written by Colin Plumb in 1993, no copyright is claimed.
- * This code is in the public domain; do with it what you wish.
- *
- * Equivalent code is available from RSA Data Security, Inc.
- * This code has been tested against that, and is equivalent,
- * except that you don't need to include two pages of legalese
- * with every copy.
- *
- * To compute the message digest of a chunk of bytes, declare an
- * MD5Context structure, pass it to MHD_MD5Init, call MHD_MD5Update as
- * needed on buffers full of bytes, and then call MHD_MD5Final, which
- * will fill a supplied 16-byte array with the digest.
+     This file is part of GNU libmicrohttpd
+     Copyright (C) 2022 Evgeny Grin (Karlson2k)
+
+     GNU libmicrohttpd is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with this library.
+     If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file microhttpd/md5.h
+ * @brief  Calculation of MD5 digest
+ * @author Karlson2k (Evgeny Grin)
  */
 
 #ifndef MHD_MD5_H
-#define MHD_MD5_H
+#define MHD_MD5_H 1
 
 #include "mhd_options.h"
 #include <stdint.h>
 #ifdef HAVE_STDDEF_H
-#include <stddef.h>
+#include <stddef.h>  /* for size_t */
 #endif /* HAVE_STDDEF_H */
 
-#define MD5_BLOCK_SIZE              64
-#define MD5_DIGEST_SIZE             16
-#define MD5_DIGEST_STRING_LENGTH    (MD5_DIGEST_SIZE * 2 + 1)
+/**
+ * Number of bits in single MD5 word.
+ */
+#define MD5_WORD_SIZE_BITS 32
+
+/**
+ * Number of bytes in single MD5 word.
+ */
+#define MD5_BYTES_IN_WORD (MD5_WORD_SIZE_BITS / 8)
+
+/**
+ * Hash is kept internally as four 32-bit words.
+ * This is intermediate hash size, used during computing the final digest.
+ */
+#define MD5_HASH_SIZE_WORDS 4
 
-struct MD5Context
+/**
+ * Size of MD5 resulting digest in bytes.
+ * This is the final digest size, not intermediate hash.
+ */
+#define MD5_DIGEST_SIZE_WORDS MD5_HASH_SIZE_WORDS
+
+/**
+ * Size of MD5 resulting digest in bytes
+ * This is the final digest size, not intermediate hash.
+ */
+#define MD5_DIGEST_SIZE (MD5_DIGEST_SIZE_WORDS * MD5_BYTES_IN_WORD)
+
+/**
+ * Size of MD5 digest string in chars including termination NUL.
+ */
+#define MD5_DIGEST_STRING_SIZE ((MD5_DIGEST_SIZE) * 2 + 1)
+
+/**
+ * Size of MD5 single processing block in bits.
+ */
+#define MD5_BLOCK_SIZE_BITS 512
+
+/**
+ * Size of MD5 single processing block in bytes.
+ */
+#define MD5_BLOCK_SIZE (MD5_BLOCK_SIZE_BITS / 8)
+
+/**
+ * Size of MD5 single processing block in words.
+ */
+#define MD5_BLOCK_SIZE_WORDS (MD5_BLOCK_SIZE_BITS / MD5_WORD_SIZE_BITS)
+
+
+/**
+ * MD5 calculation context
+ */
+struct Md5Ctx
 {
-  uint32_t state[4];  /* state */
-  uint64_t count;     /* number of bytes, mod 2^64 */
-  uint8_t buffer[MD5_BLOCK_SIZE]; /* input buffer */
+  uint32_t H[MD5_HASH_SIZE_WORDS];         /**< Intermediate hash value / 
digest at end of calculation */
+  uint32_t buffer[MD5_BLOCK_SIZE_WORDS];   /**< MD5 input data buffer */
+  uint64_t count;                          /**< number of bytes, mod 2^64 */
 };
 
-
 /**
- * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
- * initialization constants.
+ * Initialise structure for MD5 calculation.
  *
- * @param ctx must be a `struct MD5Context *`
+ * @param ctx the calculation context
  */
 void
-MHD_MD5Init (struct MD5Context *ctx);
+MHD_MD5_init (struct Md5Ctx *ctx);
 
 
 /**
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
+ * MD5 process portion of bytes.
  *
- * @param ctx must be a `struct MD5Context *`
- * @param input bytes to add to hash
- * @param len the number of bytes in @a data
+ * @param ctx the calculation context
+ * @param data bytes to add to hash
+ * @param length number of bytes in @a data
  */
 void
-MHD_MD5Update (struct MD5Context *ctx,
-               const uint8_t *input,
-               size_t len);
+MHD_MD5_update (struct Md5Ctx *ctx,
+                const uint8_t *data,
+                size_t length);
 
 
 /**
- * Final wrapup--call MD5Pad, fill in digest and zero out ctx.
+ * Finalise MD5 calculation, return digest.
  *
- * @param ctx must be a `struct MD5Context *`
+ * @param ctx the calculation context
+ * @param[out] digest set to the hash, must be #MD5_DIGEST_SIZE bytes
  */
 void
-MHD_MD5Final (struct MD5Context *ctx,
-              uint8_t digest[MD5_DIGEST_SIZE]);
+MHD_MD5_finish (struct Md5Ctx *ctx,
+                uint8_t digest[MD5_DIGEST_SIZE]);
 
+/**
+ * Indicates that function MHD_MD5_finish() (without context reset) is 
available
+ */
+#define MHD_MD5_HAS_FINISH 1
 
-#endif /* !MHD_MD5_H */
+#endif /* MHD_MD5_H */
diff --git a/src/microhttpd/md5_ext.c b/src/microhttpd/md5_ext.c
new file mode 100644
index 00000000..5466f704
--- /dev/null
+++ b/src/microhttpd/md5_ext.c
@@ -0,0 +1,95 @@
+/*
+     This file is part of GNU libmicrohttpd
+     Copyright (C) 2022 Evgeny Grin (Karlson2k)
+
+     GNU libmicrohttpd is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with GNU libmicrohttpd.
+     If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file microhttpd/md5_ext.h
+ * @brief  Wrapper for MD5 calculation performed by TLS library
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#include <gnutls/crypto.h>
+#include "md5_ext.h"
+#include "mhd_assert.h"
+
+
+/**
+ * Initialise structure for MD5 calculation, allocate resources.
+ *
+ * This function must not be called more than one time for @a ctx.
+ *
+ * @param ctx the calculation context
+ */
+void
+MHD_MD5_init_one_time (struct Md5CtxExt *ctx)
+{
+  ctx->handle = NULL;
+  ctx->ext_error = gnutls_hash_init (&ctx->handle, GNUTLS_DIG_MD5);
+  if ((0 != ctx->ext_error) && (NULL != ctx->handle))
+  {
+    gnutls_free (ctx->handle);
+    ctx->handle = NULL;
+  }
+  else
+    mhd_assert (NULL != ctx->handle);
+}
+
+
+/**
+ * Process portion of bytes.
+ *
+ * @param ctx the calculation context
+ * @param data bytes to add to hash
+ * @param length number of bytes in @a data
+ */
+void
+MHD_MD5_update (struct Md5CtxExt *ctx,
+                const uint8_t *data,
+                size_t length)
+{
+  if (0 == ctx->ext_error)
+    ctx->ext_error = gnutls_hash (ctx->handle, data, length);
+}
+
+
+/**
+ * Finalise MD5 calculation, return digest, reset hash calculation.
+ *
+ * @param ctx the calculation context
+ * @param[out] digest set to the hash, must be #MD5_DIGEST_SIZE bytes
+ */
+void
+MHD_MD5_finish_reset (struct Md5CtxExt *ctx,
+                      uint8_t digest[MD5_DIGEST_SIZE])
+{
+  if (0 == ctx->ext_error)
+    gnutls_hash_output (ctx->handle, digest);
+}
+
+
+/**
+ * Free allocated resources.
+ *
+ * @param ctx the calculation context
+ */
+void
+MHD_MD5_deinit (struct Md5CtxExt *ctx)
+{
+  if (NULL != ctx->handle)
+    gnutls_hash_deinit (ctx->handle, NULL);
+}
diff --git a/src/microhttpd/md5_ext.h b/src/microhttpd/md5_ext.h
new file mode 100644
index 00000000..b7437c03
--- /dev/null
+++ b/src/microhttpd/md5_ext.h
@@ -0,0 +1,115 @@
+/*
+     This file is part of GNU libmicrohttpd
+     Copyright (C) 2022 Evgeny Grin (Karlson2k)
+
+     GNU libmicrohttpd is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with GNU libmicrohttpd.
+     If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file microhttpd/md5_ext.h
+ * @brief  Wrapper declarations for MD5 calculation performed by TLS library
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_MD5_EXT_H
+#define MHD_MD5_EXT_H 1
+
+#include "mhd_options.h"
+#include <stdint.h>
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>  /* for size_t */
+#endif /* HAVE_STDDEF_H */
+
+/**
+ * Size of MD5 resulting digest in bytes
+ * This is the final digest size, not intermediate hash.
+ */
+#define MD5_DIGEST_SIZE (16)
+
+/* Actual declaration is in GnuTLS lib header */
+struct hash_hd_st;
+
+/**
+ * Indicates that struct Md5CtxExt has 'ext_error'
+ */
+#define MHD_MD5_HAS_EXT_ERROR 1
+
+/**
+ * MD5 calculation context
+ */
+struct Md5CtxExt
+{
+  struct hash_hd_st *handle; /**< Hash calculation handle */
+  int ext_error; /**< Non-zero if external error occurs during init or hashing 
*/
+};
+
+/**
+ * Indicates that MHD_MD5_init_one_time() function is present.
+ */
+#define MHD_MD5_HAS_INIT_ONE_TIME 1
+
+/**
+ * Initialise structure for MD5 calculation, allocate resources.
+ *
+ * This function must not be called more than one time for @a ctx.
+ *
+ * @param ctx the calculation context
+ */
+void
+MHD_MD5_init_one_time (struct Md5CtxExt *ctx);
+
+
+/**
+ * MD5 process portion of bytes.
+ *
+ * @param ctx the calculation context
+ * @param data bytes to add to hash
+ * @param length number of bytes in @a data
+ */
+void
+MHD_MD5_update (struct Md5CtxExt *ctx,
+                const uint8_t *data,
+                size_t length);
+
+
+/**
+ * Indicates that MHD_MD5_finish_reset() function is available
+ */
+#define MHD_MD5_HAS_FINISH_RESET 1
+
+/**
+ * Finalise MD5 calculation, return digest, reset hash calculation.
+ *
+ * @param ctx the calculation context
+ * @param[out] digest set to the hash, must be #MD5_DIGEST_SIZE bytes
+ */
+void
+MHD_MD5_finish_reset (struct Md5CtxExt *ctx,
+                      uint8_t digest[MD5_DIGEST_SIZE]);
+
+/**
+ * Indicates that MHD_MD5_deinit() function is present
+ */
+#define MHD_MD5_HAS_DEINIT 1
+
+/**
+ * Free allocated resources.
+ *
+ * @param ctx the calculation context
+ */
+void
+MHD_MD5_deinit (struct Md5CtxExt *ctx);
+
+#endif /* MHD_MD5_EXT_H */
diff --git a/src/microhttpd/mhd_locks.h b/src/microhttpd/mhd_locks.h
index 654ecb6c..ad9fa20e 100644
--- a/src/microhttpd/mhd_locks.h
+++ b/src/microhttpd/mhd_locks.h
@@ -62,10 +62,11 @@
 #    include <stdlib.h>
 #  endif /* HAVE_STDLIB_H */
 /* Simple implementation of MHD_PANIC, to be used outside lib */
-#  define MHD_PANIC(msg) do { fprintf (stderr,           \
-                                       "Abnormal termination at %d line in 
file %s: %s\n", \
-                                       (int) __LINE__, __FILE__, msg); abort 
(); \
-} while (0)
+#  define MHD_PANIC(msg) \
+  do { fprintf (stderr,           \
+       "Abnormal termination at %d line in file %s: %s\n", \
+       (int) __LINE__, __FILE__, msg); abort (); \
+  } while (0)
 #endif /* ! MHD_PANIC */
 
 #if defined(MHD_PTHREAD_MUTEX_)
@@ -87,8 +88,8 @@ typedef CRITICAL_SECTION MHD_mutex_;
  * @param pmutex pointer to mutex
  * @return nonzero on success, zero otherwise
  */
-#define MHD_mutex_init_(pmutex) (InitializeCriticalSectionAndSpinCount ( \
-                                   (pmutex),16))
+#define MHD_mutex_init_(pmutex) \
+  (InitializeCriticalSectionAndSpinCount ((pmutex),16))
 #endif
 
 #if defined(MHD_PTHREAD_MUTEX_)
@@ -96,8 +97,8 @@ typedef CRITICAL_SECTION MHD_mutex_;
 /**
  *  Define static mutex and statically initialise it.
  */
-#    define MHD_MUTEX_STATIC_DEFN_INIT_(m) static MHD_mutex_ m = \
-  PTHREAD_MUTEX_INITIALIZER
+#    define MHD_MUTEX_STATIC_DEFN_INIT_(m) \
+  static MHD_mutex_ m = PTHREAD_MUTEX_INITIALIZER
 #  endif /* PTHREAD_MUTEX_INITIALIZER */
 #endif
 
@@ -125,7 +126,7 @@ typedef CRITICAL_SECTION MHD_mutex_;
 #define MHD_mutex_destroy_chk_(pmutex) do {       \
     if (! MHD_mutex_destroy_ (pmutex))              \
       MHD_PANIC (_ ("Failed to destroy mutex.\n")); \
-} while (0)
+  } while (0)
 
 
 #if defined(MHD_PTHREAD_MUTEX_)
diff --git a/src/microhttpd/mhd_md5_wrap.h b/src/microhttpd/mhd_md5_wrap.h
new file mode 100644
index 00000000..98a5d958
--- /dev/null
+++ b/src/microhttpd/mhd_md5_wrap.h
@@ -0,0 +1,98 @@
+/*
+     This file is part of GNU libmicrohttpd
+     Copyright (C) 2022 Evgeny Grin (Karlson2k)
+
+     GNU libmicrohttpd is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with GNU libmicrohttpd.
+     If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file microhttpd/mhd_md5_wrap.h
+ * @brief  Simple wrapper for selection of built-in/external MD5 implementation
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_MD5_WRAP_H
+#define MHD_MD5_WRAP_H 1
+
+#include "mhd_options.h"
+#ifndef MHD_MD5_SUPPORT
+#error This file must be used only when MD5 is enabled
+#endif
+#ifndef MHD_MD5_TLSLIB
+#include "md5.h"
+#else  /* MHD_MD5_TLSLIB */
+#include "md5_ext.h"
+#endif /* MHD_MD5_TLSLIB */
+
+#ifndef MD5_DIGEST_SIZE
+/**
+ * Size of MD5 resulting digest in bytes
+ * This is the final digest size, not intermediate hash.
+ */
+#define MD5_DIGEST_SIZE (16)
+#endif /* ! MD5_DIGEST_SIZE */
+
+#ifndef MD5_DIGEST_STRING_SIZE
+/**
+ * Size of MD5 digest string in chars including termination NUL.
+ */
+#define MD5_DIGEST_STRING_SIZE ((MD5_DIGEST_SIZE) * 2 + 1)
+#endif /* ! MD5_DIGEST_STRING_SIZE */
+
+#ifndef MHD_MD5_TLSLIB
+/**
+ * Universal ctx type mapped for chosen implementation
+ */
+#define Md5CtxWr Md5Ctx
+#else  /* MHD_MD5_TLSLIB */
+/**
+ * Universal ctx type mapped for chosen implementation
+ */
+#define Md5CtxWr Md5CtxExt
+#endif /* MHD_MD5_TLSLIB */
+
+#ifndef MHD_MD5_HAS_INIT_ONE_TIME
+/**
+ * Setup and prepare ctx for hash calculation
+ */
+#define MHD_MD5_init_one_time(ctx) MHD_MD5_init(ctx)
+#endif /* ! MHD_MD5_HAS_INIT_ONE_TIME */
+
+#ifndef MHD_MD5_HAS_FINISH_RESET
+/**
+ * Re-use the same ctx for the new hashing after digest calculated
+ */
+#define MHD_MD5_reset(ctx) MHD_MD5_init(ctx)
+/**
+ * Finalise MD5 calculation, return digest, reset hash calculation.
+ */
+#define MHD_MD5_finish_reset(ctx,digest) MHD_MD5_finish(ctx,digest), \
+                                         MHD_MD5_reset(ctx)
+
+#else  /* MHD_MD5_HAS_FINISH_RESET */
+#define MHD_MD5_reset(ctx) (void)0
+#endif /* MHD_MD5_HAS_FINISH_RESET */
+
+#ifndef MHD_MD5_HAS_DEINIT
+#define MHD_MD5_deinit(ignore) (void)0
+#endif /* HAVE_MD5_DEINIT */
+
+/* Sanity checks */
+
+#if ! defined(MHD_MD5_HAS_FINISH_RESET) && ! defined(MHD_MD5_HAS_FINISH)
+#error Required at least one of MHD_MD5_finish_reset(), MHD_MD5_finish_reset()
+#endif /* ! MHD_MD5_HAS_FINISH_RESET && ! MHD_MD5_HAS_FINISH */
+
+#endif /* MHD_MD5_WRAP_H */
diff --git a/src/microhttpd/mhd_sha256_wrap.h b/src/microhttpd/mhd_sha256_wrap.h
new file mode 100644
index 00000000..5879c2ca
--- /dev/null
+++ b/src/microhttpd/mhd_sha256_wrap.h
@@ -0,0 +1,100 @@
+/*
+     This file is part of GNU libmicrohttpd
+     Copyright (C) 2022 Evgeny Grin (Karlson2k)
+
+     GNU libmicrohttpd is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with GNU libmicrohttpd.
+     If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file microhttpd/mhd_sha256_wrap.h
+ * @brief  Simple wrapper for selection of built-in/external SHA-256
+ *         implementation
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_SHA256_WRAP_H
+#define MHD_SHA256_WRAP_H 1
+
+#include "mhd_options.h"
+#include "mhd_options.h"
+#ifndef MHD_SHA256_SUPPORT
+#error This file must be used only when SHA-256 is enabled
+#endif
+#ifndef MHD_SHA256_TLSLIB
+#include "sha256.h"
+#else  /* MHD_SHA256_TLSLIB */
+#include "sha256_ext.h"
+#endif /* MHD_SHA256_TLSLIB */
+
+#ifndef SHA256_DIGEST_SIZE
+/**
+ * Size of SHA-256 resulting digest in bytes
+ * This is the final digest size, not intermediate hash.
+ */
+#define SHA256_DIGEST_SIZE (32)
+#endif /* ! SHA256_DIGEST_SIZE */
+
+#ifndef SHA256_DIGEST_STRING_SIZE
+/**
+ * Size of MD5 digest string in chars including termination NUL.
+ */
+#define SHA256_DIGEST_STRING_SIZE ((SHA256_DIGEST_SIZE) * 2 + 1)
+#endif /* ! SHA256_DIGEST_STRING_SIZE */
+
+#ifndef MHD_SHA256_TLSLIB
+/**
+ * Universal ctx type mapped for chosen implementation
+ */
+#define Sha256CtxWr Sha256Ctx
+#else  /* MHD_SHA256_TLSLIB */
+/**
+ * Universal ctx type mapped for chosen implementation
+ */
+#define Sha256CtxWr Sha256CtxExt
+#endif /* MHD_SHA256_TLSLIB */
+
+#ifndef MHD_SHA256_HAS_INIT_ONE_TIME
+/**
+ * Setup and prepare ctx for hash calculation
+ */
+#define MHD_SHA256_init_one_time(ctx) MHD_SHA256_init(ctx)
+#endif /* ! MHD_SHA256_HAS_INIT_ONE_TIME */
+
+#ifndef MHD_SHA256_HAS_FINISH_RESET
+/**
+ * Re-use the same ctx for the new hashing after digest calculated
+ */
+#define MHD_SHA256_reset(ctx) MHD_SHA256_init(ctx)
+/**
+ * Finalise MD5 calculation, return digest, reset hash calculation.
+ */
+#define MHD_SHA256_finish_reset(ctx,digest) MHD_SHA256_finish(ctx,digest), \
+                                            MHD_SHA256_reset(ctx)
+
+#else  /* MHD_SHA256_HAS_FINISH_RESET */
+#define MHD_SHA256_reset(ctx) (void)0
+#endif /* MHD_SHA256_HAS_FINISH_RESET */
+
+#ifndef MHD_SHA256_HAS_DEINIT
+#define MHD_SHA256_deinit(ignore) (void)0
+#endif /* HAVE_SHA256_DEINIT */
+
+/* Sanity checks */
+
+#if ! defined(MHD_SHA256_HAS_FINISH_RESET) && ! defined(MHD_SHA256_HAS_FINISH)
+#error Required MHD_SHA256_finish_reset() or MHD_SHA256_finish_reset()
+#endif /* ! MHD_SHA256_HAS_FINISH_RESET && ! MHD_SHA256_HAS_FINISH */
+
+#endif /* MHD_SHA256_WRAP_H */
diff --git a/src/microhttpd/sha256.c b/src/microhttpd/sha256.c
index f62b4ba1..2f9edf6a 100644
--- a/src/microhttpd/sha256.c
+++ b/src/microhttpd/sha256.c
@@ -1,6 +1,6 @@
 /*
      This file is part of libmicrohttpd
-     Copyright (C) 2019-2021 Karlson2k (Evgeny Grin)
+     Copyright (C) 2019-2022 Evgeny Grin (Karlson2k)
 
      libmicrohttpd is free software; you can redistribute it and/or
      modify it under the terms of the GNU Lesser General Public
@@ -65,8 +65,8 @@ MHD_SHA256_init (struct Sha256Ctx *ctx)
  * @param data  data, must be exactly 64 bytes long
  */
 static void
-sha256_transform (uint32_t H[_SHA256_DIGEST_LENGTH],
-                  const uint8_t data[SHA256_BLOCK_SIZE])
+sha256_transform (uint32_t H[SHA256_DIGEST_SIZE_WORDS],
+                  const void *data)
 {
   /* Working variables,
      see FIPS PUB 180-4 paragraph 6.2. */
@@ -83,6 +83,18 @@ sha256_transform (uint32_t H[_SHA256_DIGEST_LENGTH],
      See FIPS PUB 180-4 paragraphs 5.2.1, 6.2. */
   uint32_t W[16];
 
+#ifndef _MHD_GET_32BIT_BE_UNALIGNED
+  if (0 != (((uintptr_t) data) % _MHD_UINT32_ALIGN))
+  {
+    /* Copy the unaligned input data to the aligned buffer */
+    memcpy (W, data, SHA256_BLOCK_SIZE);
+    /* The W[] buffer itself will be used as the source of the data,
+     * but data will be reloaded in correct bytes order during
+     * the next steps */
+    data = (const void *) W;
+  }
+#endif /* _MHD_GET_32BIT_BE_UNALIGNED */
+
   /* 'Ch' and 'Maj' macro functions are defined with
      widely-used optimization.
      See FIPS PUB 180-4 formulae 4.2, 4.3. */
@@ -103,14 +115,9 @@ sha256_transform (uint32_t H[_SHA256_DIGEST_LENGTH],
 #define sig1(x)  (_MHD_ROTR32 ((x), 17) ^ _MHD_ROTR32 ((x),19) ^ \
                   ((x) >> 10) )
 
-  /* Single step of SHA-256 computation,
+  /* One step of SHA-256 computation,
      see FIPS PUB 180-4 paragraph 6.2.2 step 3.
-   * Note: instead of reassigning all working variables on each step,
-           variables are rotated for each step:
-             SHA2STEP32(a, b, c, d, e, f, g, h, K[0], data[0]);
-             SHA2STEP32(h, a, b, c, d, e, f, g, K[1], data[1]);
-           so current 'vD' will be used as 'vE' on next step,
-           current 'vH' will be used as 'vA' on next step.
+   * Note: this macro updates working variables in-place, without rotation.
    * Note: first (vH += SIG1(vE) + Ch(vE,vF,vG) + kt + wt) equals T1 in FIPS 
PUB 180-4 paragraph 6.2.2 step 3.
            second (vH += SIG0(vA) + Maj(vE,vF,vC) equals T1 + T2 in FIPS PUB 
180-4 paragraph 6.2.2 step 3.
    * Note: 'wt' must be used exactly one time in this macro as it change other 
data as well
@@ -119,18 +126,6 @@ sha256_transform (uint32_t H[_SHA256_DIGEST_LENGTH],
     (vD) += ((vH) += SIG1 ((vE)) + Ch ((vE),(vF),(vG)) + (kt) + (wt));  \
     (vH) += SIG0 ((vA)) + Maj ((vA),(vB),(vC)); } while (0)
 
-#ifndef _MHD_GET_32BIT_BE_UNALIGNED
-  if (0 != (((uintptr_t) data) % _MHD_UINT32_ALIGN))
-  {
-    /* Copy the unaligned input data to the aligned buffer */
-    memcpy (W, data, SHA256_BLOCK_SIZE);
-    /* The W[] buffer itself will be used as the source of the data,
-     * but data will be reloaded in correct bytes order during
-     * the next steps */
-    data = (uint8_t *) W;
-  }
-#endif /* _MHD_GET_32BIT_BE_UNALIGNED */
-
   /* Get value of W(t) from input data buffer,
      See FIPS PUB 180-4 paragraph 6.2.
      Input data must be read in big-endian bytes order,
@@ -141,44 +136,6 @@ sha256_transform (uint32_t H[_SHA256_DIGEST_LENGTH],
   _MHD_GET_32BIT_BE ((const void*)(((const uint8_t*) (buf)) + \
                                    (t) * SHA256_BYTES_IN_WORD))
 
-  /* During first 16 steps, before making any calculations on each step,
-     the W element is read from input data buffer as big-endian value and
-     stored in array of W elements. */
-  /* Note: instead of using K constants as array, all K values are specified
-     individually for each step, see FIPS PUB 180-4 paragraph 4.2.2 for K 
values. */
-  SHA2STEP32 (a, b, c, d, e, f, g, h, UINT32_C (0x428a2f98), W[0] = \
-                GET_W_FROM_DATA (data, 0));
-  SHA2STEP32 (h, a, b, c, d, e, f, g, UINT32_C (0x71374491), W[1] = \
-                GET_W_FROM_DATA (data, 1));
-  SHA2STEP32 (g, h, a, b, c, d, e, f, UINT32_C (0xb5c0fbcf), W[2] = \
-                GET_W_FROM_DATA (data, 2));
-  SHA2STEP32 (f, g, h, a, b, c, d, e, UINT32_C (0xe9b5dba5), W[3] = \
-                GET_W_FROM_DATA (data, 3));
-  SHA2STEP32 (e, f, g, h, a, b, c, d, UINT32_C (0x3956c25b), W[4] = \
-                GET_W_FROM_DATA (data, 4));
-  SHA2STEP32 (d, e, f, g, h, a, b, c, UINT32_C (0x59f111f1), W[5] = \
-                GET_W_FROM_DATA (data, 5));
-  SHA2STEP32 (c, d, e, f, g, h, a, b, UINT32_C (0x923f82a4), W[6] = \
-                GET_W_FROM_DATA (data, 6));
-  SHA2STEP32 (b, c, d, e, f, g, h, a, UINT32_C (0xab1c5ed5), W[7] = \
-                GET_W_FROM_DATA (data, 7));
-  SHA2STEP32 (a, b, c, d, e, f, g, h, UINT32_C (0xd807aa98), W[8] = \
-                GET_W_FROM_DATA (data, 8));
-  SHA2STEP32 (h, a, b, c, d, e, f, g, UINT32_C (0x12835b01), W[9] = \
-                GET_W_FROM_DATA (data, 9));
-  SHA2STEP32 (g, h, a, b, c, d, e, f, UINT32_C (0x243185be), W[10] = \
-                GET_W_FROM_DATA (data, 10));
-  SHA2STEP32 (f, g, h, a, b, c, d, e, UINT32_C (0x550c7dc3), W[11] = \
-                GET_W_FROM_DATA (data, 11));
-  SHA2STEP32 (e, f, g, h, a, b, c, d, UINT32_C (0x72be5d74), W[12] = \
-                GET_W_FROM_DATA (data, 12));
-  SHA2STEP32 (d, e, f, g, h, a, b, c, UINT32_C (0x80deb1fe), W[13] = \
-                GET_W_FROM_DATA (data, 13));
-  SHA2STEP32 (c, d, e, f, g, h, a, b, UINT32_C (0x9bdc06a7), W[14] = \
-                GET_W_FROM_DATA (data, 14));
-  SHA2STEP32 (b, c, d, e, f, g, h, a, UINT32_C (0xc19bf174), W[15] = \
-                GET_W_FROM_DATA (data, 15));
-
   /* 'W' generation and assignment for 16 <= t <= 63.
      See FIPS PUB 180-4 paragraph 6.2.2.
      As only last 16 'W' are used in calculations, it is possible to
@@ -187,9 +144,83 @@ sha256_transform (uint32_t H[_SHA256_DIGEST_LENGTH],
 #define Wgen(w,t) ( (w)[(t - 16) & 0xf] + sig1 ((w)[((t) - 2) & 0xf])   \
                     + (w)[((t) - 7) & 0xf] + sig0 ((w)[((t) - 15) & 0xf]) )
 
+#ifndef MHD_FAVOR_SMALL_CODE
+
+  /* Note: instead of using K constants as array, all K values are specified
+           individually for each step, see FIPS PUB 180-4 paragraph 4.2.2 for
+           K values. */
+  /* Note: instead of reassigning all working variables on each step,
+           variables are rotated for each step:
+             SHA2STEP32(a, b, c, d, e, f, g, h, K[0], data[0]);
+             SHA2STEP32(h, a, b, c, d, e, f, g, K[1], data[1]);
+           so current 'vD' will be used as 'vE' on next step,
+           current 'vH' will be used as 'vA' on next step. */
+#if _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
+  if ((const void *) W == data)
+  {
+    /* The input data is already in the cyclic data buffer W[] in correct bytes
+       order. */
+    SHA2STEP32 (a, b, c, d, e, f, g, h, UINT32_C (0x428a2f98), W[0]);
+    SHA2STEP32 (h, a, b, c, d, e, f, g, UINT32_C (0x71374491), W[1]);
+    SHA2STEP32 (g, h, a, b, c, d, e, f, UINT32_C (0xb5c0fbcf), W[2]);
+    SHA2STEP32 (f, g, h, a, b, c, d, e, UINT32_C (0xe9b5dba5), W[3]);
+    SHA2STEP32 (e, f, g, h, a, b, c, d, UINT32_C (0x3956c25b), W[4]);
+    SHA2STEP32 (d, e, f, g, h, a, b, c, UINT32_C (0x59f111f1), W[5]);
+    SHA2STEP32 (c, d, e, f, g, h, a, b, UINT32_C (0x923f82a4), W[6]);
+    SHA2STEP32 (b, c, d, e, f, g, h, a, UINT32_C (0xab1c5ed5), W[7]);
+    SHA2STEP32 (a, b, c, d, e, f, g, h, UINT32_C (0xd807aa98), W[8]);
+    SHA2STEP32 (h, a, b, c, d, e, f, g, UINT32_C (0x12835b01), W[9]);
+    SHA2STEP32 (g, h, a, b, c, d, e, f, UINT32_C (0x243185be), W[10]);
+    SHA2STEP32 (f, g, h, a, b, c, d, e, UINT32_C (0x550c7dc3), W[11]);
+    SHA2STEP32 (e, f, g, h, a, b, c, d, UINT32_C (0x72be5d74), W[12]);
+    SHA2STEP32 (d, e, f, g, h, a, b, c, UINT32_C (0x80deb1fe), W[13]);
+    SHA2STEP32 (c, d, e, f, g, h, a, b, UINT32_C (0x9bdc06a7), W[14]);
+    SHA2STEP32 (b, c, d, e, f, g, h, a, UINT32_C (0xc19bf174), W[15]);
+  }
+  else /* Combined with the next 'if' */
+#endif /* _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN */
+  if (1)
+  {
+    /* During first 16 steps, before making any calculations on each step,
+       the W element is read from input data buffer as big-endian value and
+       stored in array of W elements. */
+    SHA2STEP32 (a, b, c, d, e, f, g, h, UINT32_C (0x428a2f98), W[0] = \
+                  GET_W_FROM_DATA (data, 0));
+    SHA2STEP32 (h, a, b, c, d, e, f, g, UINT32_C (0x71374491), W[1] = \
+                  GET_W_FROM_DATA (data, 1));
+    SHA2STEP32 (g, h, a, b, c, d, e, f, UINT32_C (0xb5c0fbcf), W[2] = \
+                  GET_W_FROM_DATA (data, 2));
+    SHA2STEP32 (f, g, h, a, b, c, d, e, UINT32_C (0xe9b5dba5), W[3] = \
+                  GET_W_FROM_DATA (data, 3));
+    SHA2STEP32 (e, f, g, h, a, b, c, d, UINT32_C (0x3956c25b), W[4] = \
+                  GET_W_FROM_DATA (data, 4));
+    SHA2STEP32 (d, e, f, g, h, a, b, c, UINT32_C (0x59f111f1), W[5] = \
+                  GET_W_FROM_DATA (data, 5));
+    SHA2STEP32 (c, d, e, f, g, h, a, b, UINT32_C (0x923f82a4), W[6] = \
+                  GET_W_FROM_DATA (data, 6));
+    SHA2STEP32 (b, c, d, e, f, g, h, a, UINT32_C (0xab1c5ed5), W[7] = \
+                  GET_W_FROM_DATA (data, 7));
+    SHA2STEP32 (a, b, c, d, e, f, g, h, UINT32_C (0xd807aa98), W[8] = \
+                  GET_W_FROM_DATA (data, 8));
+    SHA2STEP32 (h, a, b, c, d, e, f, g, UINT32_C (0x12835b01), W[9] = \
+                  GET_W_FROM_DATA (data, 9));
+    SHA2STEP32 (g, h, a, b, c, d, e, f, UINT32_C (0x243185be), W[10] = \
+                  GET_W_FROM_DATA (data, 10));
+    SHA2STEP32 (f, g, h, a, b, c, d, e, UINT32_C (0x550c7dc3), W[11] = \
+                  GET_W_FROM_DATA (data, 11));
+    SHA2STEP32 (e, f, g, h, a, b, c, d, UINT32_C (0x72be5d74), W[12] = \
+                  GET_W_FROM_DATA (data, 12));
+    SHA2STEP32 (d, e, f, g, h, a, b, c, UINT32_C (0x80deb1fe), W[13] = \
+                  GET_W_FROM_DATA (data, 13));
+    SHA2STEP32 (c, d, e, f, g, h, a, b, UINT32_C (0x9bdc06a7), W[14] = \
+                  GET_W_FROM_DATA (data, 14));
+    SHA2STEP32 (b, c, d, e, f, g, h, a, UINT32_C (0xc19bf174), W[15] = \
+                  GET_W_FROM_DATA (data, 15));
+  }
+
   /* During last 48 steps, before making any calculations on each step,
-     W element is generated from W elements of cyclic buffer and generated 
value
-     stored back in cyclic buffer. */
+     current W element is generated from other W elements of the cyclic buffer
+     and the generated value is stored back in the cyclic buffer. */
   /* Note: instead of using K constants as array, all K values are specified
      individually for each step, see FIPS PUB 180-4 paragraph 4.2.2 for K 
values. */
   SHA2STEP32 (a, b, c, d, e, f, g, h, UINT32_C (0xe49b69c1), W[16 & 0xf] = \
@@ -288,6 +319,70 @@ sha256_transform (uint32_t H[_SHA256_DIGEST_LENGTH],
                 Wgen (W,62));
   SHA2STEP32 (b, c, d, e, f, g, h, a, UINT32_C (0xc67178f2), W[63 & 0xf] = \
                 Wgen (W,63));
+#else  /* ! MHD_FAVOR_SMALL_CODE */
+  if (1)
+  {
+    unsigned int t;
+    /* K constants array.
+       See FIPS PUB 180-4 paragraph 4.2.2 for K values. */
+    static const uint32_t K[80] =
+    { UINT32_C (0x428a2f98),  UINT32_C (0x71374491),  UINT32_C (0xb5c0fbcf),
+      UINT32_C (0xe9b5dba5),  UINT32_C (0x3956c25b),  UINT32_C (0x59f111f1),
+      UINT32_C (0x923f82a4),  UINT32_C (0xab1c5ed5),  UINT32_C (0xd807aa98),
+      UINT32_C (0x12835b01),  UINT32_C (0x243185be),  UINT32_C (0x550c7dc3),
+      UINT32_C (0x72be5d74),  UINT32_C (0x80deb1fe),  UINT32_C (0x9bdc06a7),
+      UINT32_C (0xc19bf174),  UINT32_C (0xe49b69c1),  UINT32_C (0xefbe4786),
+      UINT32_C (0x0fc19dc6),  UINT32_C (0x240ca1cc),  UINT32_C (0x2de92c6f),
+      UINT32_C (0x4a7484aa),  UINT32_C (0x5cb0a9dc),  UINT32_C (0x76f988da),
+      UINT32_C (0x983e5152),  UINT32_C (0xa831c66d),  UINT32_C (0xb00327c8),
+      UINT32_C (0xbf597fc7),  UINT32_C (0xc6e00bf3),  UINT32_C (0xd5a79147),
+      UINT32_C (0x06ca6351),  UINT32_C (0x14292967),  UINT32_C (0x27b70a85),
+      UINT32_C (0x2e1b2138),  UINT32_C (0x4d2c6dfc),  UINT32_C (0x53380d13),
+      UINT32_C (0x650a7354),  UINT32_C (0x766a0abb),  UINT32_C (0x81c2c92e),
+      UINT32_C (0x92722c85),  UINT32_C (0xa2bfe8a1),  UINT32_C (0xa81a664b),
+      UINT32_C (0xc24b8b70),  UINT32_C (0xc76c51a3),  UINT32_C (0xd192e819),
+      UINT32_C (0xd6990624),  UINT32_C (0xf40e3585),  UINT32_C (0x106aa070),
+      UINT32_C (0x19a4c116),  UINT32_C (0x1e376c08),  UINT32_C (0x2748774c),
+      UINT32_C (0x34b0bcb5),  UINT32_C (0x391c0cb3),  UINT32_C (0x4ed8aa4a),
+      UINT32_C (0x5b9cca4f),  UINT32_C (0x682e6ff3),  UINT32_C (0x748f82ee),
+      UINT32_C (0x78a5636f),  UINT32_C (0x84c87814),  UINT32_C (0x8cc70208),
+      UINT32_C (0x90befffa),  UINT32_C (0xa4506ceb),  UINT32_C (0xbef9a3f7),
+      UINT32_C (0xc67178f2) };
+    /* One step of SHA-256 computation with working variables rotation,
+       see FIPS PUB 180-4 paragraph 6.2.2 step 3.
+     * Note: this version of macro reassign all working variable on
+             each step. */
+#define SHA2STEP32RV(vA,vB,vC,vD,vE,vF,vG,vH,kt,wt) do {              \
+    uint32_t tmp_h_ = (vH);                                           \
+    SHA2STEP32((vA),(vB),(vC),(vD),(vE),(vF),(vG),tmp_h_,(kt),(wt));  \
+    (vH) = (vG);                                                      \
+    (vG) = (vF);                                                      \
+    (vF) = (vE);                                                      \
+    (vE) = (vD);                                                      \
+    (vD) = (vC);                                                      \
+    (vC) = (vB);                                                      \
+    (vB) = (vA);                                                      \
+    (vA) = tmp_h_;  } while (0)
+
+    /* During first 16 steps, before making any calculations on each step,
+       the W element is read from input data buffer as big-endian value and
+       stored in array of W elements. */
+    for (t = 0; t < 16; ++t)
+    {
+      SHA2STEP32RV (a, b, c, d, e, f, g, h, K[t], \
+                    W[t] = GET_W_FROM_DATA (data, t));
+    }
+
+    /* During last 48 steps, before making any calculations on each step,
+       current W element is generated from other W elements of the cyclic 
buffer
+       and the generated value is stored back in the cyclic buffer. */
+    for (t = 16; t < 64; ++t)
+    {
+      SHA2STEP32RV (a, b, c, d, e, f, g, h, K[t], W[t & 15] = Wgen (W,t));
+    }
+  }
+#endif /* ! MHD_FAVOR_SMALL_CODE */
+
 
   /* Compute intermediate hash.
      See FIPS PUB 180-4 paragraph 6.2.2 step 4. */
@@ -318,8 +413,10 @@ MHD_SHA256_update (struct Sha256Ctx *ctx,
 
   mhd_assert ((data != NULL) || (length == 0));
 
+#ifndef MHD_FAVOR_SMALL_CODE
   if (0 == length)
-    return; /* Do nothing */
+    return; /* Shortcut, do nothing */
+#endif /* MHD_FAVOR_SMALL_CODE */
 
   /* Note: (count & (SHA256_BLOCK_SIZE-1))
            equals (count % SHA256_BLOCK_SIZE) for this block size. */
@@ -332,7 +429,7 @@ MHD_SHA256_update (struct Sha256Ctx *ctx,
     if (length >= bytes_left)
     {     /* Combine new data with data in the buffer and
              process full block. */
-      memcpy (ctx->buffer + bytes_have,
+      memcpy (((uint8_t *) ctx->buffer) + bytes_have,
               data,
               bytes_left);
       data += bytes_left;
@@ -353,7 +450,7 @@ MHD_SHA256_update (struct Sha256Ctx *ctx,
   if (0 != length)
   {   /* Copy incomplete block of new data (if any)
          to the buffer. */
-    memcpy (ctx->buffer + bytes_have, data, length);
+    memcpy (((uint8_t *) ctx->buffer) + bytes_have, data, length);
   }
 }
 
@@ -382,19 +479,24 @@ MHD_SHA256_finish (struct Sha256Ctx *ctx,
            equal (count % SHA256_BLOCK_SIZE) for this block size. */
   bytes_have = (unsigned) (ctx->count & (SHA256_BLOCK_SIZE - 1));
 
-  /* Input data must be padded with bit "1" and with length of data in bits.
+  /* Input data must be padded with a single bit "1", then with zeros and
+     the finally the length of data in bits must be added as the final bytes
+     of the last block.
      See FIPS PUB 180-4 paragraph 5.1.1. */
+
   /* Data is always processed in form of bytes (not by individual bits),
-     therefore position of first padding bit in byte is always predefined 
(0x80). */
+     therefore position of first padding bit in byte is always
+     predefined (0x80). */
   /* Buffer always have space at least for one byte (as full buffers are
      processed immediately). */
-  ctx->buffer[bytes_have++] = 0x80;
+  ((uint8_t *) ctx->buffer)[bytes_have++] = 0x80;
 
   if (SHA256_BLOCK_SIZE - bytes_have < SHA256_SIZE_OF_LEN_ADD)
   {   /* No space in current block to put total length of message.
          Pad current block with zeros and process it. */
     if (bytes_have < SHA256_BLOCK_SIZE)
-      memset (ctx->buffer + bytes_have, 0, SHA256_BLOCK_SIZE - bytes_have);
+      memset (((uint8_t *) ctx->buffer) + bytes_have, 0,
+              SHA256_BLOCK_SIZE - bytes_have);
     /* Process full block. */
     sha256_transform (ctx->H, ctx->buffer);
     /* Start new block. */
@@ -402,20 +504,26 @@ MHD_SHA256_finish (struct Sha256Ctx *ctx,
   }
 
   /* Pad the rest of the buffer with zeros. */
-  memset (ctx->buffer + bytes_have, 0,
+  memset (((uint8_t *) ctx->buffer) + bytes_have, 0,
           SHA256_BLOCK_SIZE - SHA256_SIZE_OF_LEN_ADD - bytes_have);
-  /* Put number of bits in processed message as big-endian value. */
-  _MHD_PUT_64BIT_BE_SAFE (ctx->buffer + SHA256_BLOCK_SIZE
-                          - SHA256_SIZE_OF_LEN_ADD,
-                          num_bits);
+  /* Put the number of bits in processed message as big-endian value. */
+  _MHD_PUT_64BIT_BE_SAFE (ctx->buffer + SHA256_BLOCK_SIZE_WORDS - 2, num_bits);
   /* Process full final block. */
   sha256_transform (ctx->H, ctx->buffer);
 
   /* Put final hash/digest in BE mode */
 #ifndef _MHD_PUT_32BIT_BE_UNALIGNED
-  if (0 != ((uintptr_t) digest) % _MHD_UINT32_ALIGN)
+  if (1
+#ifndef MHD_FAVOR_SMALL_CODE
+      && (0 != ((uintptr_t) digest) % _MHD_UINT32_ALIGN)
+#endif /* MHD_FAVOR_SMALL_CODE */
+      )
   {
-    uint32_t alig_dgst[_SHA256_DIGEST_LENGTH];
+    /* If storing of the final result requires aligned address and
+       the destination address is not aligned or compact code is used,
+       store the final digest in aligned temporary buffer first, then
+       copy it to the destination. */
+    uint32_t alig_dgst[SHA256_DIGEST_SIZE_WORDS];
     _MHD_PUT_32BIT_BE (alig_dgst + 0, ctx->H[0]);
     _MHD_PUT_32BIT_BE (alig_dgst + 1, ctx->H[1]);
     _MHD_PUT_32BIT_BE (alig_dgst + 2, ctx->H[2]);
@@ -427,10 +535,12 @@ MHD_SHA256_finish (struct Sha256Ctx *ctx,
     /* Copy result to unaligned destination address */
     memcpy (digest, alig_dgst, SHA256_DIGEST_SIZE);
   }
-  else
-#else  /* _MHD_PUT_32BIT_BE_UNALIGNED */
+#ifndef MHD_FAVOR_SMALL_CODE
+  else /* Combined with the next 'if' */
+#endif /* MHD_FAVOR_SMALL_CODE */
+#endif /* ! _MHD_PUT_32BIT_BE_UNALIGNED */
+#if ! defined(MHD_FAVOR_SMALL_CODE) || defined(_MHD_PUT_32BIT_BE_UNALIGNED)
   if (1)
-#endif /* _MHD_PUT_32BIT_BE_UNALIGNED */
   {
     /* Use cast to (void*) here to mute compiler alignment warnings.
      * Compilers are not smart enough to see that alignment has been checked. 
*/
@@ -443,6 +553,7 @@ MHD_SHA256_finish (struct Sha256Ctx *ctx,
     _MHD_PUT_32BIT_BE ((void *) (digest + 6 * SHA256_BYTES_IN_WORD), 
ctx->H[6]);
     _MHD_PUT_32BIT_BE ((void *) (digest + 7 * SHA256_BYTES_IN_WORD), 
ctx->H[7]);
   }
+#endif /* ! MHD_FAVOR_SMALL_CODE || _MHD_PUT_32BIT_BE_UNALIGNED */
 
   /* Erase potentially sensitive data. */
   memset (ctx, 0, sizeof(struct Sha256Ctx));
diff --git a/src/microhttpd/sha256.h b/src/microhttpd/sha256.h
index 8feb52fe..9069a59a 100644
--- a/src/microhttpd/sha256.h
+++ b/src/microhttpd/sha256.h
@@ -1,6 +1,6 @@
 /*
      This file is part of libmicrohttpd
-     Copyright (C) 2019-2021 Karlson2k (Evgeny Grin)
+     Copyright (C) 2019-2022 Evgeny Grin (Karlson2k)
 
      This library is free software; you can redistribute it and/or
      modify it under the terms of the GNU Lesser General Public
@@ -36,7 +36,7 @@
 /**
  *  Digest is kept internally as 8 32-bit words.
  */
-#define _SHA256_DIGEST_LENGTH 8
+#define SHA256_DIGEST_SIZE_WORDS 8
 
 /**
  * Number of bits in single SHA-256 word
@@ -52,7 +52,7 @@
 /**
  * Size of SHA-256 digest in bytes
  */
-#define SHA256_DIGEST_SIZE (_SHA256_DIGEST_LENGTH * SHA256_BYTES_IN_WORD)
+#define SHA256_DIGEST_SIZE (SHA256_DIGEST_SIZE_WORDS * SHA256_BYTES_IN_WORD)
 
 /**
  * Size of SHA-256 digest string in chars including termination NUL
@@ -69,12 +69,17 @@
  */
 #define SHA256_BLOCK_SIZE (SHA256_BLOCK_SIZE_BITS / 8)
 
+/**
+ * Size of single processing block in bytes
+ */
+#define SHA256_BLOCK_SIZE_WORDS (SHA256_BLOCK_SIZE_BITS / 
SHA256_WORD_SIZE_BITS)
+
 
 struct Sha256Ctx
 {
-  uint32_t H[_SHA256_DIGEST_LENGTH];    /**< Intermediate hash value / digest 
at end of calculation */
-  uint8_t buffer[SHA256_BLOCK_SIZE];    /**< SHA256 input data buffer */
-  uint64_t count;                       /**< number of bytes, mod 2^64 */
+  uint32_t H[SHA256_DIGEST_SIZE_WORDS];     /**< Intermediate hash value / 
digest at end of calculation */
+  uint32_t buffer[SHA256_BLOCK_SIZE_WORDS]; /**< SHA256 input data buffer */
+  uint64_t count;                           /**< number of bytes, mod 2^64 */
 };
 
 /**
@@ -109,4 +114,9 @@ void
 MHD_SHA256_finish (struct Sha256Ctx *ctx,
                    uint8_t digest[SHA256_DIGEST_SIZE]);
 
+/**
+ * Indicates that function MHD_SHA256_finish() (without context reset) is 
available
+ */
+#define MHD_SHA256_HAS_FINISH 1
+
 #endif /* MHD_SHA256_H */
diff --git a/src/microhttpd/sha256_ext.c b/src/microhttpd/sha256_ext.c
new file mode 100644
index 00000000..d1c2a6ed
--- /dev/null
+++ b/src/microhttpd/sha256_ext.c
@@ -0,0 +1,95 @@
+/*
+     This file is part of GNU libmicrohttpd
+     Copyright (C) 2022 Evgeny Grin (Karlson2k)
+
+     GNU libmicrohttpd is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with GNU libmicrohttpd.
+     If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file microhttpd/sha256_ext.h
+ * @brief  Wrapper for SHA-256 calculation performed by TLS library
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#include <gnutls/crypto.h>
+#include "sha256_ext.h"
+#include "mhd_assert.h"
+
+
+/**
+ * Initialise structure for SHA-256 calculation, allocate resources.
+ *
+ * This function must not be called more than one time for @a ctx.
+ *
+ * @param ctx the calculation context
+ */
+void
+MHD_SHA256_init_one_time (struct Sha256CtxExt *ctx)
+{
+  ctx->handle = NULL;
+  ctx->ext_error = gnutls_hash_init (&ctx->handle, GNUTLS_DIG_SHA256);
+  if ((0 != ctx->ext_error) && (NULL != ctx->handle))
+  {
+    gnutls_free (ctx->handle);
+    ctx->handle = NULL;
+  }
+  else
+    mhd_assert (NULL != ctx->handle);
+}
+
+
+/**
+ * Process portion of bytes.
+ *
+ * @param ctx the calculation context
+ * @param data bytes to add to hash
+ * @param length number of bytes in @a data
+ */
+void
+MHD_SHA256_update (struct Sha256CtxExt *ctx,
+                   const uint8_t *data,
+                   size_t length)
+{
+  if (0 == ctx->ext_error)
+    ctx->ext_error = gnutls_hash (ctx->handle, data, length);
+}
+
+
+/**
+ * Finalise SHA-256 calculation, return digest, reset hash calculation.
+ *
+ * @param ctx the calculation context
+ * @param[out] digest set to the hash, must be #SHA256_DIGEST_SIZE bytes
+ */
+void
+MHD_SHA256_finish_reset (struct Sha256CtxExt *ctx,
+                         uint8_t digest[SHA256_DIGEST_SIZE])
+{
+  if (0 == ctx->ext_error)
+    gnutls_hash_output (ctx->handle, digest);
+}
+
+
+/**
+ * Free allocated resources.
+ *
+ * @param ctx the calculation context
+ */
+void
+MHD_SHA256_deinit (struct Sha256CtxExt *ctx)
+{
+  if (NULL != ctx->handle)
+    gnutls_hash_deinit (ctx->handle, NULL);
+}
diff --git a/src/microhttpd/sha256_ext.h b/src/microhttpd/sha256_ext.h
new file mode 100644
index 00000000..7d2ee6a5
--- /dev/null
+++ b/src/microhttpd/sha256_ext.h
@@ -0,0 +1,115 @@
+/*
+     This file is part of GNU libmicrohttpd
+     Copyright (C) 2022 Evgeny Grin (Karlson2k)
+
+     GNU libmicrohttpd is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Lesser General Public
+     License as published by the Free Software Foundation; either
+     version 2.1 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Lesser General Public License for more details.
+
+     You should have received a copy of the GNU Lesser General Public
+     License along with GNU libmicrohttpd.
+     If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file microhttpd/sha256_ext.h
+ * @brief  Wrapper declarations for SHA-256 calculation performed by TLS 
library
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_SHA256_EXT_H
+#define MHD_SHA256_EXT_H 1
+
+#include "mhd_options.h"
+#include <stdint.h>
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>  /* for size_t */
+#endif /* HAVE_STDDEF_H */
+
+/**
+ * Size of SHA-256 resulting digest in bytes
+ * This is the final digest size, not intermediate hash.
+ */
+#define SHA256_DIGEST_SIZE (32)
+
+/* Actual declaration is in GnuTLS lib header */
+struct hash_hd_st;
+
+/**
+ * Indicates that struct Sha256CtxExt has 'ext_error'
+ */
+#define MHD_SHA256_HAS_EXT_ERROR 1
+
+/**
+ * SHA-256 calculation context
+ */
+struct Sha256CtxExt
+{
+  struct hash_hd_st *handle; /**< Hash calculation handle */
+  int ext_error; /**< Non-zero if external error occurs during init or hashing 
*/
+};
+
+/**
+ * Indicates that MHD_SHA256_init_one_time() function is present.
+ */
+#define MHD_SHA256_HAS_INIT_ONE_TIME 1
+
+/**
+ * Initialise structure for SHA-256 calculation, allocate resources.
+ *
+ * This function must not be called more than one time for @a ctx.
+ *
+ * @param ctx the calculation context
+ */
+void
+MHD_SHA256_init_one_time (struct Sha256CtxExt *ctx);
+
+
+/**
+ * SHA-256 process portion of bytes.
+ *
+ * @param ctx the calculation context
+ * @param data bytes to add to hash
+ * @param length number of bytes in @a data
+ */
+void
+MHD_SHA256_update (struct Sha256CtxExt *ctx,
+                   const uint8_t *data,
+                   size_t length);
+
+
+/**
+ * Indicates that MHD_SHA256_finish_reset() function is available
+ */
+#define MHD_SHA256_HAS_FINISH_RESET 1
+
+/**
+ * Finalise SHA-256 calculation, return digest, reset hash calculation.
+ *
+ * @param ctx the calculation context
+ * @param[out] digest set to the hash, must be #SHA256_DIGEST_SIZE bytes
+ */
+void
+MHD_SHA256_finish_reset (struct Sha256CtxExt *ctx,
+                         uint8_t digest[SHA256_DIGEST_SIZE]);
+
+/**
+ * Indicates that MHD_SHA256_deinit() function is present
+ */
+#define MHD_SHA256_HAS_DEINIT 1
+
+/**
+ * Free allocated resources.
+ *
+ * @param ctx the calculation context
+ */
+void
+MHD_SHA256_deinit (struct Sha256CtxExt *ctx);
+
+#endif /* MHD_SHA256_EXT_H */
diff --git a/src/microhttpd/sha512_256.c b/src/microhttpd/sha512_256.c
index 54389c6b..b7682b28 100644
--- a/src/microhttpd/sha512_256.c
+++ b/src/microhttpd/sha512_256.c
@@ -1,6 +1,6 @@
 /*
      This file is part of GNU libmicrohttpd
-     Copyright (C) 2022 Karlson2k (Evgeny Grin)
+     Copyright (C) 2022 Evgeny Grin (Karlson2k)
 
      GNU libmicrohttpd is free software; you can redistribute it and/or
      modify it under the terms of the GNU Lesser General Public
@@ -60,9 +60,9 @@ MHD_SHA512_256_init (struct Sha512_256Ctx *ctx)
 
 /**
  * Base of SHA-512/256 transformation.
- * Gets full 64 bytes block of data and updates hash values;
+ * Gets full 128 bytes block of data and updates hash values;
  * @param H     hash values
- * @param data  the data buffer with SHA512_256_BLOCK_SIZE bytes block
+ * @param data  the data buffer with #SHA512_256_BLOCK_SIZE bytes block
  */
 static void
 sha512_256_transform (uint64_t H[SHA512_256_HASH_SIZE_WORDS],
@@ -91,7 +91,7 @@ sha512_256_transform (uint64_t H[SHA512_256_HASH_SIZE_WORDS],
     /* The W[] buffer itself will be used as the source of the data,
      * but the data will be reloaded in correct bytes order on
      * the next steps */
-    data = (uint8_t *) W;
+    data = (const void *) W;
   }
 #endif /* _MHD_GET_64BIT_BE_ALLOW_UNALIGNED */
 
@@ -118,12 +118,6 @@ sha512_256_transform (uint64_t 
H[SHA512_256_HASH_SIZE_WORDS],
   /* One step of SHA-512/256 computation,
      see FIPS PUB 180-4 clause 6.4.2 step 3.
    * Note: this macro updates working variables in-place, without rotation.
-   * Note: instead of reassigning all working variables on each step,
-           variables are rotated for each step:
-             SHA2STEP64(a, b, c, d, e, f, g, h, K[0], data[0]);
-             SHA2STEP64(h, a, b, c, d, e, f, g, K[1], data[1]);
-           so current 'vD' will be used as 'vE' on next step,
-           current 'vH' will be used as 'vA' on next step.
    * Note: the first (vH += SIG1(vE) + Ch(vE,vF,vG) + kt + wt) equals T1 in
            FIPS PUB 180-4 clause 6.4.2 step 3.
            the second (vH += SIG0(vA) + Maj(vE,vF,vC) equals T1 + T2 in
@@ -150,9 +144,7 @@ sha512_256_transform (uint64_t 
H[SHA512_256_HASH_SIZE_WORDS],
                     + (w)[((t) - 7) & 15] + sig0 ((w)[((t) - 15) & 15]) )
 
 #ifndef MHD_FAVOR_SMALL_CODE
-  /* During first 16 steps, before making any calculations on each step,
-     the W element is read from the input data buffer as big-endian value and
-     stored in the array of W elements. */
+
   /* Note: instead of using K constants as array, all K values are specified
            individually for each step, see FIPS PUB 180-4 clause 4.2.3 for
            K values. */
@@ -162,38 +154,68 @@ sha512_256_transform (uint64_t 
H[SHA512_256_HASH_SIZE_WORDS],
              SHA2STEP64(h, a, b, c, d, e, f, g, K[1], data[1]);
            so current 'vD' will be used as 'vE' on next step,
            current 'vH' will be used as 'vA' on next step. */
-  SHA2STEP64 (a, b, c, d, e, f, g, h, UINT64_C (0x428a2f98d728ae22), \
-              W[0] = GET_W_FROM_DATA (data, 0));
-  SHA2STEP64 (h, a, b, c, d, e, f, g, UINT64_C (0x7137449123ef65cd), \
-              W[1] = GET_W_FROM_DATA (data, 1));
-  SHA2STEP64 (g, h, a, b, c, d, e, f, UINT64_C (0xb5c0fbcfec4d3b2f), \
-              W[2] = GET_W_FROM_DATA (data, 2));
-  SHA2STEP64 (f, g, h, a, b, c, d, e, UINT64_C (0xe9b5dba58189dbbc), \
-              W[3] = GET_W_FROM_DATA (data, 3));
-  SHA2STEP64 (e, f, g, h, a, b, c, d, UINT64_C (0x3956c25bf348b538), \
-              W[4] = GET_W_FROM_DATA (data, 4));
-  SHA2STEP64 (d, e, f, g, h, a, b, c, UINT64_C (0x59f111f1b605d019), \
-              W[5] = GET_W_FROM_DATA (data, 5));
-  SHA2STEP64 (c, d, e, f, g, h, a, b, UINT64_C (0x923f82a4af194f9b), \
-              W[6] = GET_W_FROM_DATA (data, 6));
-  SHA2STEP64 (b, c, d, e, f, g, h, a, UINT64_C (0xab1c5ed5da6d8118), \
-              W[7] = GET_W_FROM_DATA (data, 7));
-  SHA2STEP64 (a, b, c, d, e, f, g, h, UINT64_C (0xd807aa98a3030242), \
-              W[8] = GET_W_FROM_DATA (data, 8));
-  SHA2STEP64 (h, a, b, c, d, e, f, g, UINT64_C (0x12835b0145706fbe), \
-              W[9] = GET_W_FROM_DATA (data, 9));
-  SHA2STEP64 (g, h, a, b, c, d, e, f, UINT64_C (0x243185be4ee4b28c), \
-              W[10] = GET_W_FROM_DATA (data, 10));
-  SHA2STEP64 (f, g, h, a, b, c, d, e, UINT64_C (0x550c7dc3d5ffb4e2), \
-              W[11] = GET_W_FROM_DATA (data, 11));
-  SHA2STEP64 (e, f, g, h, a, b, c, d, UINT64_C (0x72be5d74f27b896f), \
-              W[12] = GET_W_FROM_DATA (data, 12));
-  SHA2STEP64 (d, e, f, g, h, a, b, c, UINT64_C (0x80deb1fe3b1696b1), \
-              W[13] = GET_W_FROM_DATA (data, 13));
-  SHA2STEP64 (c, d, e, f, g, h, a, b, UINT64_C (0x9bdc06a725c71235), \
-              W[14] = GET_W_FROM_DATA (data, 14));
-  SHA2STEP64 (b, c, d, e, f, g, h, a, UINT64_C (0xc19bf174cf692694), \
-              W[15] = GET_W_FROM_DATA (data, 15));
+#if _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN
+  if ((const void *) W == data)
+  {
+    /* The input data is already in the cyclic data buffer W[] in correct bytes
+       order. */
+    SHA2STEP64 (a, b, c, d, e, f, g, h, UINT64_C (0x428a2f98d728ae22), W[0]);
+    SHA2STEP64 (h, a, b, c, d, e, f, g, UINT64_C (0x7137449123ef65cd), W[1]);
+    SHA2STEP64 (g, h, a, b, c, d, e, f, UINT64_C (0xb5c0fbcfec4d3b2f), W[2]);
+    SHA2STEP64 (f, g, h, a, b, c, d, e, UINT64_C (0xe9b5dba58189dbbc), W[3]);
+    SHA2STEP64 (e, f, g, h, a, b, c, d, UINT64_C (0x3956c25bf348b538), W[4]);
+    SHA2STEP64 (d, e, f, g, h, a, b, c, UINT64_C (0x59f111f1b605d019), W[5]);
+    SHA2STEP64 (c, d, e, f, g, h, a, b, UINT64_C (0x923f82a4af194f9b), W[6]);
+    SHA2STEP64 (b, c, d, e, f, g, h, a, UINT64_C (0xab1c5ed5da6d8118), W[7]);
+    SHA2STEP64 (a, b, c, d, e, f, g, h, UINT64_C (0xd807aa98a3030242), W[8]);
+    SHA2STEP64 (h, a, b, c, d, e, f, g, UINT64_C (0x12835b0145706fbe), W[9]);
+    SHA2STEP64 (g, h, a, b, c, d, e, f, UINT64_C (0x243185be4ee4b28c), W[10]);
+    SHA2STEP64 (f, g, h, a, b, c, d, e, UINT64_C (0x550c7dc3d5ffb4e2), W[11]);
+    SHA2STEP64 (e, f, g, h, a, b, c, d, UINT64_C (0x72be5d74f27b896f), W[12]);
+    SHA2STEP64 (d, e, f, g, h, a, b, c, UINT64_C (0x80deb1fe3b1696b1), W[13]);
+    SHA2STEP64 (c, d, e, f, g, h, a, b, UINT64_C (0x9bdc06a725c71235), W[14]);
+    SHA2STEP64 (b, c, d, e, f, g, h, a, UINT64_C (0xc19bf174cf692694), W[15]);
+  }
+  else /* Combined with the next 'if' */
+#endif /* _MHD_BYTE_ORDER == _MHD_BIG_ENDIAN */
+  if (1)
+  {
+    /* During first 16 steps, before making any calculations on each step,
+       the W element is read from the input data buffer as big-endian value and
+       stored in the array of W elements. */
+    SHA2STEP64 (a, b, c, d, e, f, g, h, UINT64_C (0x428a2f98d728ae22), \
+                W[0] = GET_W_FROM_DATA (data, 0));
+    SHA2STEP64 (h, a, b, c, d, e, f, g, UINT64_C (0x7137449123ef65cd), \
+                W[1] = GET_W_FROM_DATA (data, 1));
+    SHA2STEP64 (g, h, a, b, c, d, e, f, UINT64_C (0xb5c0fbcfec4d3b2f), \
+                W[2] = GET_W_FROM_DATA (data, 2));
+    SHA2STEP64 (f, g, h, a, b, c, d, e, UINT64_C (0xe9b5dba58189dbbc), \
+                W[3] = GET_W_FROM_DATA (data, 3));
+    SHA2STEP64 (e, f, g, h, a, b, c, d, UINT64_C (0x3956c25bf348b538), \
+                W[4] = GET_W_FROM_DATA (data, 4));
+    SHA2STEP64 (d, e, f, g, h, a, b, c, UINT64_C (0x59f111f1b605d019), \
+                W[5] = GET_W_FROM_DATA (data, 5));
+    SHA2STEP64 (c, d, e, f, g, h, a, b, UINT64_C (0x923f82a4af194f9b), \
+                W[6] = GET_W_FROM_DATA (data, 6));
+    SHA2STEP64 (b, c, d, e, f, g, h, a, UINT64_C (0xab1c5ed5da6d8118), \
+                W[7] = GET_W_FROM_DATA (data, 7));
+    SHA2STEP64 (a, b, c, d, e, f, g, h, UINT64_C (0xd807aa98a3030242), \
+                W[8] = GET_W_FROM_DATA (data, 8));
+    SHA2STEP64 (h, a, b, c, d, e, f, g, UINT64_C (0x12835b0145706fbe), \
+                W[9] = GET_W_FROM_DATA (data, 9));
+    SHA2STEP64 (g, h, a, b, c, d, e, f, UINT64_C (0x243185be4ee4b28c), \
+                W[10] = GET_W_FROM_DATA (data, 10));
+    SHA2STEP64 (f, g, h, a, b, c, d, e, UINT64_C (0x550c7dc3d5ffb4e2), \
+                W[11] = GET_W_FROM_DATA (data, 11));
+    SHA2STEP64 (e, f, g, h, a, b, c, d, UINT64_C (0x72be5d74f27b896f), \
+                W[12] = GET_W_FROM_DATA (data, 12));
+    SHA2STEP64 (d, e, f, g, h, a, b, c, UINT64_C (0x80deb1fe3b1696b1), \
+                W[13] = GET_W_FROM_DATA (data, 13));
+    SHA2STEP64 (c, d, e, f, g, h, a, b, UINT64_C (0x9bdc06a725c71235), \
+                W[14] = GET_W_FROM_DATA (data, 14));
+    SHA2STEP64 (b, c, d, e, f, g, h, a, UINT64_C (0xc19bf174cf692694), \
+                W[15] = GET_W_FROM_DATA (data, 15));
+  }
 
   /* During last 64 steps, before making any calculations on each step,
      current W element is generated from other W elements of the cyclic buffer
@@ -442,8 +464,10 @@ MHD_SHA512_256_update (struct Sha512_256Ctx *ctx,
 
   mhd_assert ((data != NULL) || (length == 0));
 
+#ifndef MHD_FAVOR_SMALL_CODE
   if (0 == length)
-    return; /* Do nothing */
+    return; /* Shortcut, do nothing */
+#endif /* ! MHD_FAVOR_SMALL_CODE */
 
   /* Note: (count & (SHA512_256_BLOCK_SIZE-1))
            equals (count % SHA512_256_BLOCK_SIZE) for this block size. */
@@ -521,9 +545,11 @@ MHD_SHA512_256_finish (struct Sha512_256Ctx *ctx,
            equals (count % SHA512_256_BLOCK_SIZE) for this block size. */
   bytes_have = (unsigned int) (ctx->count & (SHA512_256_BLOCK_SIZE - 1));
 
-  /* Input data must be padded with bit "1" and then the length of data in bits
-     must be added as the final bytes of the last block.
+  /* Input data must be padded with a single bit "1", then with zeros and
+     the finally the length of data in bits must be added as the final bytes
+     of the last block.
      See FIPS PUB 180-4 clause 5.1.2. */
+
   /* Data is always processed in form of bytes (not by individual bits),
      therefore position of the first padding bit in byte is always
      predefined (0x80). */
@@ -560,8 +586,16 @@ MHD_SHA512_256_finish (struct Sha512_256Ctx *ctx,
   /* Put in BE mode the leftmost part of the hash as the final digest.
      See FIPS PUB 180-4 clause 6.7. */
 #ifndef _MHD_PUT_64BIT_BE_UNALIGNED
-  if (0 != ((uintptr_t) digest) % _MHD_UINT64_ALIGN)
-  { /* The destination is unaligned */
+  if (1
+#ifndef MHD_FAVOR_SMALL_CODE
+      && (0 != ((uintptr_t) digest) % _MHD_UINT64_ALIGN)
+#endif /* MHD_FAVOR_SMALL_CODE */
+      )
+  {
+    /* If storing of the final result requires aligned address and
+       the destination address is not aligned or compact code is used,
+       store the final digest in aligned temporary buffer first, then
+       copy it to the destination. */
     uint64_t alig_dgst[SHA512_256_DIGEST_SIZE_WORDS];
     _MHD_PUT_64BIT_BE (alig_dgst + 0, ctx->H[0]);
     _MHD_PUT_64BIT_BE (alig_dgst + 1, ctx->H[1]);
@@ -570,8 +604,11 @@ MHD_SHA512_256_finish (struct Sha512_256Ctx *ctx,
     /* Copy result to the unaligned destination address */
     memcpy (digest, alig_dgst, SHA512_256_DIGEST_SIZE);
   }
+#ifndef MHD_FAVOR_SMALL_CODE
   else /* Combined with the next 'if' */
+#endif /* MHD_FAVOR_SMALL_CODE */
 #endif /* ! _MHD_PUT_64BIT_BE_UNALIGNED */
+#if ! defined(MHD_FAVOR_SMALL_CODE) || defined(_MHD_PUT_64BIT_BE_UNALIGNED)
   if (1)
   {
     /* Use cast to (void*) here to mute compiler alignment warnings.
@@ -585,6 +622,7 @@ MHD_SHA512_256_finish (struct Sha512_256Ctx *ctx,
     _MHD_PUT_64BIT_BE ((void *) (digest + 3 * SHA512_256_BYTES_IN_WORD), \
                        ctx->H[3]);
   }
+#endif /* ! MHD_FAVOR_SMALL_CODE || _MHD_PUT_64BIT_BE_UNALIGNED */
 
   /* Erase potentially sensitive data. */
   memset (ctx, 0, sizeof(struct Sha512_256Ctx));
diff --git a/src/microhttpd/sha512_256.h b/src/microhttpd/sha512_256.h
index 43359dc7..31200c2e 100644
--- a/src/microhttpd/sha512_256.h
+++ b/src/microhttpd/sha512_256.h
@@ -1,6 +1,6 @@
 /*
      This file is part of GNU libmicrohttpd
-     Copyright (C) 2022 Karlson2k (Evgeny Grin)
+     Copyright (C) 2022 Evgeny Grin (Karlson2k)
 
      GNU libmicrohttpd is free software; you can redistribute it and/or
      modify it under the terms of the GNU Lesser General Public
@@ -68,18 +68,17 @@
 #define SHA512_256_DIGEST_STRING_SIZE ((SHA512_256_DIGEST_SIZE) * 2 + 1)
 
 /**
- * Size of single processing block in bits.
- * This is the final digest size, not intermediate hash.
+ * Size of SHA-512/256 single processing block in bits.
  */
 #define SHA512_256_BLOCK_SIZE_BITS 1024
 
 /**
- * Size of single processing block in bytes.
+ * Size of SHA-512/256 single processing block in bytes.
  */
 #define SHA512_256_BLOCK_SIZE (SHA512_256_BLOCK_SIZE_BITS / 8)
 
 /**
- * Size of single processing block in words.
+ * Size of SHA-512/256 single processing block in words.
  */
 #define SHA512_256_BLOCK_SIZE_WORDS \
  (SHA512_256_BLOCK_SIZE_BITS / SHA512_256_WORD_SIZE_BITS)
diff --git a/src/microhttpd/test_dauth_userdigest.c 
b/src/microhttpd/test_dauth_userdigest.c
index 6b15a282..f467be6d 100644
--- a/src/microhttpd/test_dauth_userdigest.c
+++ b/src/microhttpd/test_dauth_userdigest.c
@@ -23,12 +23,19 @@
  * @author Karlson2k (Evgeny Grin)
  */
 
+#include "mhd_options.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include "microhttpd.h"
 #include "test_helpers.h"
 
+#if defined(MHD_HTTPS_REQUIRE_GCRYPT) && \
+  (defined(MHD_SHA256_TLSLIB) || defined(MHD_MD5_TLSLIB))
+#define NEED_GCRYP_INIT 1
+#include <gcrypt.h>
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT && (MHD_SHA256_TLSLIB || MHD_MD5_TLSLIB) */
+
 static int verbose = 1; /* verbose level (0-1)*/
 
 /* Declarations and data */
@@ -619,6 +626,13 @@ main (int argc, char *argv[])
   if (has_param (argc, argv, "-s") || has_param (argc, argv, "--silent"))
     verbose = 0;
 
+#ifdef NEED_GCRYP_INIT
+  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif /* GCRYCTL_INITIALIZATION_FINISHED */
+#endif /* NEED_GCRYP_INIT */
+
   if (MHD_is_feature_supported (MHD_FEATURE_DIGEST_AUTH_MD5))
     num_failed += test_md5 ();
   num_failed += test_md5_failure ();
diff --git a/src/microhttpd/test_dauth_userhash.c 
b/src/microhttpd/test_dauth_userhash.c
index 633ab4b9..c145beb0 100644
--- a/src/microhttpd/test_dauth_userhash.c
+++ b/src/microhttpd/test_dauth_userhash.c
@@ -26,9 +26,16 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "mhd_options.h"
 #include "microhttpd.h"
 #include "test_helpers.h"
 
+#if defined(MHD_HTTPS_REQUIRE_GCRYPT) && \
+  (defined(MHD_SHA256_TLSLIB) || defined(MHD_MD5_TLSLIB))
+#define NEED_GCRYP_INIT 1
+#include <gcrypt.h>
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT && (MHD_SHA256_TLSLIB || MHD_MD5_TLSLIB) */
+
 static int verbose = 1; /* verbose level (0-1)*/
 
 /* Declarations and data */
@@ -748,6 +755,13 @@ main (int argc, char *argv[])
   if (has_param (argc, argv, "-s") || has_param (argc, argv, "--silent"))
     verbose = 0;
 
+#ifdef NEED_GCRYP_INIT
+  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif /* GCRYCTL_INITIALIZATION_FINISHED */
+#endif /* NEED_GCRYP_INIT */
+
   if (MHD_is_feature_supported (MHD_FEATURE_DIGEST_AUTH_MD5))
     num_failed += test_md5 ();
   num_failed += test_md5_failure ();
diff --git a/src/microhttpd/test_md5.c b/src/microhttpd/test_md5.c
index 5e04ead0..e6addab3 100644
--- a/src/microhttpd/test_md5.c
+++ b/src/microhttpd/test_md5.c
@@ -1,6 +1,6 @@
 /*
   This file is part of libmicrohttpd
-  Copyright (C) 2019 Karlson2k (Evgeny Grin)
+  Copyright (C) 2019-2022 Evgeny Grin (Karlson2k)
 
   This test tool is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
@@ -24,11 +24,16 @@
  */
 
 #include "mhd_options.h"
-#include "md5.h"
+#include "mhd_md5_wrap.h"
 #include "test_helpers.h"
 #include <stdio.h>
 #include <stdlib.h>
 
+#if defined(MHD_MD5_TLSLIB) && defined(MHD_HTTPS_REQUIRE_GCRYPT)
+#define NEED_GCRYP_INIT 1
+#include <gcrypt.h>
+#endif /* MHD_MD5_TLSLIB && MHD_HTTPS_REQUIRE_GCRYPT */
+
 static int verbose = 0; /* verbose level (0-1)*/
 
 
@@ -59,10 +64,39 @@ static const struct data_unit1 data_units1[] = {
   {D_STR_W_LEN ("zyxwvutsrqponMLKJIHGFEDCBA"),
    {0x05, 0x61, 0x3a, 0x6b, 0xde, 0x75, 0x3a, 0x45, 0x91, 0xa8, 0x81, 0xb0,
     0xa7, 0xe2, 0xe2, 0x0e}},
-  {D_STR_W_LEN ("abcdefghijklmnopqrstuvwxyzzyxwvutsrqponMLKJIHGFEDCBA"
+  {D_STR_W_LEN ("abcdefghijklmnopqrstuvwxyzzyxwvutsrqponMLKJIHGFEDCBA" \
                 "abcdefghijklmnopqrstuvwxyzzyxwvutsrqponMLKJIHGFEDCBA"),
    {0xaf, 0xab, 0xc7, 0xe9, 0xe7, 0x17, 0xbe, 0xd6, 0xc0, 0x0f, 0x78, 0x8c,
     0xde, 0xdd, 0x11, 0xd1}},
+  {D_STR_W_LEN ("/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/path?with%20some=parameters"),
+   {0x7e, 0xe6, 0xdb, 0xe2, 0x76, 0x49, 0x1a, 0xd8, 0xaf, 0xf3, 0x52, 0x2d,
+    0xd8, 0xfc, 0x89, 0x1e}},
+  {D_STR_W_LEN (""),
+   {0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 0xe9, 0x80, 0x09, 0x98,
+    0xec, 0xf8, 0x42, 0x7e}},
+  {D_STR_W_LEN ("a"),
+   {0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, 0x31, 0xc3, 0x99, 0xe2,
+    0x69, 0x77, 0x26, 0x61}},
+  {D_STR_W_LEN ("abc"),
+   {0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d,
+    0x28, 0xe1, 0x7f, 0x72}},
+  {D_STR_W_LEN ("message digest"),
+   {0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, 0x52, 0x5a, 0x2f, 0x31,
+    0xaa, 0xf1, 0x61, 0xd0}},
+  {D_STR_W_LEN ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" \
+                "0123456789"),
+   {0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, 0xa5, 0x61, 0x1c, 0x2c,
+    0x9f, 0x41, 0x9d, 0x9f}},
+  {D_STR_W_LEN ("12345678901234567890123456789012345678901234567890" \
+                "123456789012345678901234567890"),
+   {0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, 0xac, 0x49, 0xda, 0x2e,
+    0x21, 0x07, 0xb6, 0x7a}}
 };
 
 static const size_t units1_num = sizeof(data_units1) / sizeof(data_units1[0]);
@@ -251,8 +285,8 @@ check_result (const char *test_name,
   check_num++; /* Print 1-based numbers */
   if (failed)
   {
-    char calc_str[MD5_DIGEST_STRING_LENGTH];
-    char expc_str[MD5_DIGEST_STRING_LENGTH];
+    char calc_str[MD5_DIGEST_STRING_SIZE];
+    char expc_str[MD5_DIGEST_STRING_SIZE];
     bin2hex (calculated, MD5_DIGEST_SIZE, calc_str);
     bin2hex (expected, MD5_DIGEST_SIZE, expc_str);
     fprintf (stderr,
@@ -262,11 +296,11 @@ check_result (const char *test_name,
   }
   else if (verbose)
   {
-    char calc_str[MD5_DIGEST_STRING_LENGTH];
+    char calc_str[MD5_DIGEST_STRING_SIZE];
     bin2hex (calculated, MD5_DIGEST_SIZE, calc_str);
-    printf (
-      "PASSED: %s check %u: calculated digest %s match expected digest.\n",
-      test_name, check_num, calc_str);
+    printf ("PASSED: %s check %u: calculated digest %s "
+            "matches expected digest.\n",
+            test_name, check_num, calc_str);
     fflush (stdout);
   }
   return failed ? 1 : 0;
@@ -283,19 +317,28 @@ test1_str (void)
 {
   unsigned int i;
   int num_failed = 0;
+  struct Md5CtxWr ctx;
+
+  MHD_MD5_init_one_time (&ctx);
 
   for (i = 0; i < units1_num; i++)
   {
-    struct MD5Context ctx;
     uint8_t digest[MD5_DIGEST_SIZE];
 
-    MHD_MD5Init (&ctx);
-    MHD_MD5Update (&ctx, (const uint8_t*) data_units1[i].str_l.str,
-                   data_units1[i].str_l.len);
-    MHD_MD5Final (&ctx, digest);
+    MHD_MD5_update (&ctx, (const uint8_t *) data_units1[i].str_l.str,
+                    data_units1[i].str_l.len);
+    MHD_MD5_finish_reset (&ctx, digest);
+#ifdef MHD_MD5_HAS_EXT_ERROR
+    if (0 != ctx.ext_error)
+    {
+      fprintf (stderr, "External hashing error: %d.\n", ctx.ext_error);
+      exit (99);
+    }
+#endif
     num_failed += check_result (__FUNCTION__, i, digest,
                                 data_units1[i].digest);
   }
+  MHD_MD5_deinit (&ctx);
   return num_failed;
 }
 
@@ -305,18 +348,27 @@ test1_bin (void)
 {
   unsigned int i;
   int num_failed = 0;
+  struct Md5CtxWr ctx;
+
+  MHD_MD5_init_one_time (&ctx);
 
   for (i = 0; i < units2_num; i++)
   {
-    struct MD5Context ctx;
     uint8_t digest[MD5_DIGEST_SIZE];
 
-    MHD_MD5Init (&ctx);
-    MHD_MD5Update (&ctx, data_units2[i].bin_l.bin, data_units2[i].bin_l.len);
-    MHD_MD5Final (&ctx, digest);
+    MHD_MD5_update (&ctx, data_units2[i].bin_l.bin, data_units2[i].bin_l.len);
+    MHD_MD5_finish_reset (&ctx, digest);
+#ifdef MHD_MD5_HAS_EXT_ERROR
+    if (0 != ctx.ext_error)
+    {
+      fprintf (stderr, "External hashing error: %d.\n", ctx.ext_error);
+      exit (99);
+    }
+#endif
     num_failed += check_result (__FUNCTION__, i, digest,
                                 data_units2[i].digest);
   }
+  MHD_MD5_deinit (&ctx);
   return num_failed;
 }
 
@@ -327,21 +379,33 @@ test2_str (void)
 {
   unsigned int i;
   int num_failed = 0;
+  struct Md5CtxWr ctx;
+
+  MHD_MD5_init_one_time (&ctx);
 
   for (i = 0; i < units1_num; i++)
   {
-    struct MD5Context ctx;
     uint8_t digest[MD5_DIGEST_SIZE];
     size_t part_s = data_units1[i].str_l.len / 4;
 
-    MHD_MD5Init (&ctx);
-    MHD_MD5Update (&ctx, (const uint8_t*) data_units1[i].str_l.str, part_s);
-    MHD_MD5Update (&ctx, (const uint8_t*) data_units1[i].str_l.str + part_s,
-                   data_units1[i].str_l.len - part_s);
-    MHD_MD5Final (&ctx, digest);
+    MHD_MD5_update (&ctx, (const uint8_t *) "", 0);
+    MHD_MD5_update (&ctx, (const uint8_t *) data_units1[i].str_l.str, part_s);
+    MHD_MD5_update (&ctx, (const uint8_t *) "", 0);
+    MHD_MD5_update (&ctx, (const uint8_t *) data_units1[i].str_l.str + part_s,
+                    data_units1[i].str_l.len - part_s);
+    MHD_MD5_update (&ctx, (const uint8_t *) "", 0);
+    MHD_MD5_finish_reset (&ctx, digest);
+#ifdef MHD_MD5_HAS_EXT_ERROR
+    if (0 != ctx.ext_error)
+    {
+      fprintf (stderr, "External hashing error: %d.\n", ctx.ext_error);
+      exit (99);
+    }
+#endif
     num_failed += check_result (__FUNCTION__, i, digest,
                                 data_units1[i].digest);
   }
+  MHD_MD5_deinit (&ctx);
   return num_failed;
 }
 
@@ -351,21 +415,31 @@ test2_bin (void)
 {
   unsigned int i;
   int num_failed = 0;
+  struct Md5CtxWr ctx;
+
+  MHD_MD5_init_one_time (&ctx);
 
   for (i = 0; i < units2_num; i++)
   {
-    struct MD5Context ctx;
     uint8_t digest[MD5_DIGEST_SIZE];
     size_t part_s = data_units2[i].bin_l.len * 2 / 3;
 
-    MHD_MD5Init (&ctx);
-    MHD_MD5Update (&ctx, data_units2[i].bin_l.bin, part_s);
-    MHD_MD5Update (&ctx, data_units2[i].bin_l.bin + part_s,
-                   data_units2[i].bin_l.len - part_s);
-    MHD_MD5Final (&ctx, digest);
+    MHD_MD5_update (&ctx, data_units2[i].bin_l.bin, part_s);
+    MHD_MD5_update (&ctx, (const uint8_t *) "", 0);
+    MHD_MD5_update (&ctx, data_units2[i].bin_l.bin + part_s,
+                    data_units2[i].bin_l.len - part_s);
+    MHD_MD5_finish_reset (&ctx, digest);
+#ifdef MHD_MD5_HAS_EXT_ERROR
+    if (0 != ctx.ext_error)
+    {
+      fprintf (stderr, "External hashing error: %d.\n", ctx.ext_error);
+      exit (99);
+    }
+#endif
     num_failed += check_result (__FUNCTION__, i, digest,
                                 data_units2[i].digest);
   }
+  MHD_MD5_deinit (&ctx);
   return num_failed;
 }
 
@@ -381,6 +455,7 @@ test_unaligned (void)
   unsigned int offset;
   uint8_t *buf;
   uint8_t *digest_buf;
+  struct Md5CtxWr ctx;
 
   const struct data_unit2 *const tdata = data_units2 + DATA_POS;
 
@@ -389,9 +464,10 @@ test_unaligned (void)
   if ((NULL == buf) || (NULL == digest_buf))
     exit (99);
 
+  MHD_MD5_init_one_time (&ctx);
+
   for (offset = MAX_OFFSET; offset >= 1; --offset)
   {
-    struct MD5Context ctx;
     uint8_t *unaligned_digest;
     uint8_t *unaligned_buf;
 
@@ -400,12 +476,19 @@ test_unaligned (void)
     unaligned_digest = digest_buf + MAX_OFFSET - offset;
     memset (unaligned_digest, 0, MD5_DIGEST_SIZE);
 
-    MHD_MD5Init (&ctx);
-    MHD_MD5Update (&ctx, unaligned_buf, tdata->bin_l.len);
-    MHD_MD5Final (&ctx, unaligned_digest);
+    MHD_MD5_update (&ctx, unaligned_buf, tdata->bin_l.len);
+    MHD_MD5_finish_reset (&ctx, unaligned_digest);
+#ifdef MHD_MD5_HAS_EXT_ERROR
+    if (0 != ctx.ext_error)
+    {
+      fprintf (stderr, "External hashing error: %d.\n", ctx.ext_error);
+      exit (99);
+    }
+#endif
     num_failed += check_result (__FUNCTION__, MAX_OFFSET - offset,
                                 unaligned_digest, tdata->digest);
   }
+  MHD_MD5_deinit (&ctx);
   free (digest_buf);
   free (buf);
   return num_failed;
@@ -420,6 +503,13 @@ main (int argc, char *argv[])
   if (has_param (argc, argv, "-v") || has_param (argc, argv, "--verbose"))
     verbose = 1;
 
+#ifdef NEED_GCRYP_INIT
+  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif /* GCRYCTL_INITIALIZATION_FINISHED */
+#endif /* NEED_GCRYP_INIT */
+
   num_failed += test1_str ();
   num_failed += test1_bin ();
 
diff --git a/src/microhttpd/test_sha256.c b/src/microhttpd/test_sha256.c
index 74061cfb..5f6559e2 100644
--- a/src/microhttpd/test_sha256.c
+++ b/src/microhttpd/test_sha256.c
@@ -1,6 +1,6 @@
 /*
   This file is part of libmicrohttpd
-  Copyright (C) 2019 Karlson2k (Evgeny Grin)
+  Copyright (C) 2019-2022 Evgeny Grin (Karlson2k)
 
   This test tool is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
@@ -24,11 +24,16 @@
  */
 
 #include "mhd_options.h"
-#include "sha256.h"
+#include "mhd_sha256_wrap.h"
 #include "test_helpers.h"
 #include <stdio.h>
 #include <stdlib.h>
 
+#if defined(MHD_SHA256_TLSLIB) && defined(MHD_HTTPS_REQUIRE_GCRYPT)
+#define NEED_GCRYP_INIT 1
+#include <gcrypt.h>
+#endif /* MHD_SHA256_TLSLIB && MHD_HTTPS_REQUIRE_GCRYPT */
+
 static int verbose = 0; /* verbose level (0-1)*/
 
 
@@ -82,12 +87,22 @@ static const struct data_unit1 data_units1[] = {
     0x73, 0x82, 0xac, 0x92,
     0xca, 0x37, 0xfd, 0x72, 0x8b, 0x0c, 0xd1, 0x6c, 0x55, 0xd5, 0x88, 0x98,
     0x24, 0xfa, 0x16, 0xf2}},
-  {D_STR_W_LEN ("abcdefghijklmnopqrstuvwxyzzyxwvutsrqponMLKJIHGFEDCBA"
+  {D_STR_W_LEN ("abcdefghijklmnopqrstuvwxyzzyxwvutsrqponMLKJIHGFEDCBA" \
                 "abcdefghijklmnopqrstuvwxyzzyxwvutsrqponMLKJIHGFEDCBA"),
    {0x27, 0xd1, 0xe8, 0xbc, 0x6a, 0x79, 0x16, 0x83, 0x61, 0x73, 0xa9, 0xa8,
     0x9b, 0xaf, 0xaf, 0xcf,
     0x47, 0x4d, 0x09, 0xef, 0x6d, 0x50, 0x35, 0x12, 0x25, 0x72, 0xd8, 0x68,
     0xdc, 0x1f, 0xd2, 0xf4}},
+  {D_STR_W_LEN ("/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/path?with%20some=parameters"),
+   {0x73, 0x85, 0xc5, 0xb9, 0x8f, 0xaf, 0x7d, 0x5e, 0xad, 0xd8, 0x0b, 0x8e,
+    0x12, 0xdb, 0x28, 0x60, 0xc7, 0xc7, 0x55, 0x05, 0x2f, 0x7c, 0x6f, 0xfa,
+    0xd1, 0xe3, 0xe1, 0x7b, 0x04, 0xd4, 0xb0, 0x21}}
 };
 
 static const size_t units1_num = sizeof(data_units1) / sizeof(data_units1[0]);
@@ -310,9 +325,9 @@ check_result (const char *test_name,
   {
     char calc_str[SHA256_DIGEST_STRING_SIZE];
     bin2hex (calculated, SHA256_DIGEST_SIZE, calc_str);
-    printf (
-      "PASSED: %s check %u: calculated digest %s matches expected digest.\n",
-      test_name, check_num, calc_str);
+    printf ("PASSED: %s check %u: calculated digest %s "
+            "matches expected digest.\n",
+            test_name, check_num, calc_str);
     fflush (stdout);
   }
   return failed ? 1 : 0;
@@ -329,19 +344,27 @@ test1_str (void)
 {
   int num_failed = 0;
   unsigned int i;
+  struct Sha256CtxWr ctx;
 
+  MHD_SHA256_init_one_time (&ctx);
   for (i = 0; i < units1_num; i++)
   {
-    struct Sha256Ctx ctx;
     uint8_t digest[SHA256_DIGEST_SIZE];
 
-    MHD_SHA256_init (&ctx);
     MHD_SHA256_update (&ctx, (const uint8_t *) data_units1[i].str_l.str,
                        data_units1[i].str_l.len);
-    MHD_SHA256_finish (&ctx, digest);
+    MHD_SHA256_finish_reset (&ctx, digest);
+#ifdef MHD_SHA256_HAS_EXT_ERROR
+    if (0 != ctx.ext_error)
+    {
+      fprintf (stderr, "External hashing error: %d.\n", ctx.ext_error);
+      exit (99);
+    }
+#endif /* MHD_SHA256_HAS_EXT_ERROR */
     num_failed += check_result (__FUNCTION__, i, digest,
                                 data_units1[i].digest);
   }
+  MHD_SHA256_deinit (&ctx);
   return num_failed;
 }
 
@@ -351,19 +374,27 @@ test1_bin (void)
 {
   int num_failed = 0;
   unsigned int i;
+  struct Sha256CtxWr ctx;
 
+  MHD_SHA256_init_one_time (&ctx);
   for (i = 0; i < units2_num; i++)
   {
-    struct Sha256Ctx ctx;
     uint8_t digest[SHA256_DIGEST_SIZE];
 
-    MHD_SHA256_init (&ctx);
     MHD_SHA256_update (&ctx, data_units2[i].bin_l.bin,
                        data_units2[i].bin_l.len);
-    MHD_SHA256_finish (&ctx, digest);
+    MHD_SHA256_finish_reset (&ctx, digest);
+#ifdef MHD_SHA256_HAS_EXT_ERROR
+    if (0 != ctx.ext_error)
+    {
+      fprintf (stderr, "External hashing error: %d.\n", ctx.ext_error);
+      exit (99);
+    }
+#endif /* MHD_SHA256_HAS_EXT_ERROR */
     num_failed += check_result (__FUNCTION__, i, digest,
                                 data_units2[i].digest);
   }
+  MHD_SHA256_deinit (&ctx);
   return num_failed;
 }
 
@@ -374,23 +405,34 @@ test2_str (void)
 {
   int num_failed = 0;
   unsigned int i;
+  struct Sha256CtxWr ctx;
 
+  MHD_SHA256_init_one_time (&ctx);
   for (i = 0; i < units1_num; i++)
   {
-    struct Sha256Ctx ctx;
     uint8_t digest[SHA256_DIGEST_SIZE];
     size_t part_s = data_units1[i].str_l.len / 4;
 
-    MHD_SHA256_init (&ctx);
+    MHD_SHA256_update (&ctx, (const uint8_t *) "", 0);
     MHD_SHA256_update (&ctx, (const uint8_t *) data_units1[i].str_l.str,
                        part_s);
+    MHD_SHA256_update (&ctx, (const uint8_t *) "", 0);
     MHD_SHA256_update (&ctx, (const uint8_t *) data_units1[i].str_l.str
                        + part_s,
                        data_units1[i].str_l.len - part_s);
-    MHD_SHA256_finish (&ctx, digest);
+    MHD_SHA256_update (&ctx, (const uint8_t *) "", 0);
+    MHD_SHA256_finish_reset (&ctx, digest);
+#ifdef MHD_SHA256_HAS_EXT_ERROR
+    if (0 != ctx.ext_error)
+    {
+      fprintf (stderr, "External hashing error: %d.\n", ctx.ext_error);
+      exit (99);
+    }
+#endif /* MHD_SHA256_HAS_EXT_ERROR */
     num_failed += check_result (__FUNCTION__, i, digest,
                                 data_units1[i].digest);
   }
+  MHD_SHA256_deinit (&ctx);
   return num_failed;
 }
 
@@ -400,21 +442,30 @@ test2_bin (void)
 {
   int num_failed = 0;
   unsigned int i;
+  struct Sha256CtxWr ctx;
 
+  MHD_SHA256_init_one_time (&ctx);
   for (i = 0; i < units2_num; i++)
   {
-    struct Sha256Ctx ctx;
     uint8_t digest[SHA256_DIGEST_SIZE];
     size_t part_s = data_units2[i].bin_l.len * 2 / 3;
 
-    MHD_SHA256_init (&ctx);
     MHD_SHA256_update (&ctx, data_units2[i].bin_l.bin, part_s);
+    MHD_SHA256_update (&ctx, (const uint8_t *) "", 0);
     MHD_SHA256_update (&ctx, data_units2[i].bin_l.bin + part_s,
                        data_units2[i].bin_l.len - part_s);
-    MHD_SHA256_finish (&ctx, digest);
+    MHD_SHA256_finish_reset (&ctx, digest);
+#ifdef MHD_SHA256_HAS_EXT_ERROR
+    if (0 != ctx.ext_error)
+    {
+      fprintf (stderr, "External hashing error: %d.\n", ctx.ext_error);
+      exit (99);
+    }
+#endif /* MHD_SHA256_HAS_EXT_ERROR */
     num_failed += check_result (__FUNCTION__, i, digest,
                                 data_units2[i].digest);
   }
+  MHD_SHA256_deinit (&ctx);
   return num_failed;
 }
 
@@ -430,9 +481,11 @@ test_unaligned (void)
   unsigned int offset;
   uint8_t *buf;
   uint8_t *digest_buf;
+  struct Sha256CtxWr ctx;
 
   const struct data_unit2 *const tdata = data_units2 + DATA_POS;
 
+  MHD_SHA256_init_one_time (&ctx);
   buf = malloc (tdata->bin_l.len + MAX_OFFSET);
   digest_buf = malloc (SHA256_DIGEST_SIZE + MAX_OFFSET);
   if ((NULL == buf) || (NULL == digest_buf))
@@ -440,7 +493,6 @@ test_unaligned (void)
 
   for (offset = MAX_OFFSET; offset >= 1; --offset)
   {
-    struct Sha256Ctx ctx;
     uint8_t *unaligned_digest;
     uint8_t *unaligned_buf;
 
@@ -449,14 +501,21 @@ test_unaligned (void)
     unaligned_digest = digest_buf + MAX_OFFSET - offset;
     memset (unaligned_digest, 0, SHA256_DIGEST_SIZE);
 
-    MHD_SHA256_init (&ctx);
     MHD_SHA256_update (&ctx, unaligned_buf, tdata->bin_l.len);
-    MHD_SHA256_finish (&ctx, unaligned_digest);
+    MHD_SHA256_finish_reset (&ctx, unaligned_digest);
+#ifdef MHD_SHA256_HAS_EXT_ERROR
+    if (0 != ctx.ext_error)
+    {
+      fprintf (stderr, "External hashing error: %d.\n", ctx.ext_error);
+      exit (99);
+    }
+#endif /* MHD_SHA256_HAS_EXT_ERROR */
     num_failed += check_result (__FUNCTION__, MAX_OFFSET - offset,
                                 unaligned_digest, tdata->digest);
   }
   free (digest_buf);
   free (buf);
+  MHD_SHA256_deinit (&ctx);
   return num_failed;
 }
 
@@ -469,6 +528,13 @@ main (int argc, char *argv[])
   if (has_param (argc, argv, "-v") || has_param (argc, argv, "--verbose"))
     verbose = 1;
 
+#ifdef NEED_GCRYP_INIT
+  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif /* GCRYCTL_INITIALIZATION_FINISHED */
+#endif /* NEED_GCRYP_INIT */
+
   num_failed += test1_str ();
   num_failed += test1_bin ();
 
diff --git a/src/microhttpd/test_sha512_256.c b/src/microhttpd/test_sha512_256.c
index 85c3a0ee..81a505c0 100644
--- a/src/microhttpd/test_sha512_256.c
+++ b/src/microhttpd/test_sha512_256.c
@@ -1,6 +1,6 @@
 /*
   This file is part of libmicrohttpd
-  Copyright (C) 2019-2022 Karlson2k (Evgeny Grin)
+  Copyright (C) 2019-2022 Evgeny Grin (Karlson2k)
 
   This test tool is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
@@ -81,6 +81,16 @@ static const struct data_unit1 data_units1[] = {
    {0xad, 0xe9, 0x5d, 0x55, 0x3b, 0x9e, 0x45, 0x69, 0xdb, 0x53, 0xa4, 0x04,
     0x92, 0xe7, 0x87, 0x94, 0xff, 0xc9, 0x98, 0x5f, 0x93, 0x03, 0x86, 0x45,
     0xe1, 0x97, 0x17, 0x72, 0x7c, 0xbc, 0x31, 0x15}},
+  {D_STR_W_LEN ("/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/long/long/long/long/long/long/long" \
+                "/long/long/long/long/path?with%20some=parameters"),
+   {0xbc, 0xab, 0xc6, 0x2c, 0x0a, 0x22, 0xd5, 0xcb, 0xac, 0xac, 0xe9, 0x25,
+    0xcf, 0xce, 0xaa, 0xaf, 0x0e, 0xa1, 0xed, 0x42, 0x46, 0x8a, 0xe2, 0x01,
+    0xee, 0x2f, 0xdb, 0x39, 0x75, 0x47, 0x73, 0xf1}}
 };
 
 static const size_t units1_num = sizeof(data_units1) / sizeof(data_units1[0]);
@@ -436,10 +446,10 @@ test1_str (void)
 {
   int num_failed = 0;
   unsigned int i;
+  struct Sha512_256Ctx ctx;
 
   for (i = 0; i < units1_num; i++)
   {
-    struct Sha512_256Ctx ctx;
     uint8_t digest[SHA512_256_DIGEST_SIZE];
 
     MHD_SHA512_256_init (&ctx);
@@ -458,10 +468,10 @@ test1_bin (void)
 {
   int num_failed = 0;
   unsigned int i;
+  struct Sha512_256Ctx ctx;
 
   for (i = 0; i < units2_num; i++)
   {
-    struct Sha512_256Ctx ctx;
     uint8_t digest[SHA512_256_DIGEST_SIZE];
 
     MHD_SHA512_256_init (&ctx);
@@ -481,19 +491,22 @@ test2_str (void)
 {
   int num_failed = 0;
   unsigned int i;
+  struct Sha512_256Ctx ctx;
 
   for (i = 0; i < units1_num; i++)
   {
-    struct Sha512_256Ctx ctx;
     uint8_t digest[SHA512_256_DIGEST_SIZE];
     size_t part_s = data_units1[i].str_l.len / 4;
 
     MHD_SHA512_256_init (&ctx);
+    MHD_SHA512_256_update (&ctx, (const uint8_t *) "", 0);
     MHD_SHA512_256_update (&ctx, (const uint8_t *) data_units1[i].str_l.str,
                            part_s);
+    MHD_SHA512_256_update (&ctx, (const uint8_t *) "", 0);
     MHD_SHA512_256_update (&ctx, (const uint8_t *) data_units1[i].str_l.str
                            + part_s,
                            data_units1[i].str_l.len - part_s);
+    MHD_SHA512_256_update (&ctx, (const uint8_t *) "", 0);
     MHD_SHA512_256_finish (&ctx, digest);
     num_failed += check_result (__FUNCTION__, i, digest,
                                 data_units1[i].digest);
@@ -507,15 +520,16 @@ test2_bin (void)
 {
   int num_failed = 0;
   unsigned int i;
+  struct Sha512_256Ctx ctx;
 
   for (i = 0; i < units2_num; i++)
   {
-    struct Sha512_256Ctx ctx;
     uint8_t digest[SHA512_256_DIGEST_SIZE];
     size_t part_s = data_units2[i].bin_l.len * 2 / 3;
 
     MHD_SHA512_256_init (&ctx);
     MHD_SHA512_256_update (&ctx, data_units2[i].bin_l.bin, part_s);
+    MHD_SHA512_256_update (&ctx, (const uint8_t *) "", 0);
     MHD_SHA512_256_update (&ctx, data_units2[i].bin_l.bin + part_s,
                            data_units2[i].bin_l.len - part_s);
     MHD_SHA512_256_finish (&ctx, digest);
@@ -537,6 +551,7 @@ test_unaligned (void)
   unsigned int offset;
   uint8_t *buf;
   uint8_t *digest_buf;
+  struct Sha512_256Ctx ctx;
 
   const struct data_unit2 *const tdata = data_units2 + DATA_POS;
 
@@ -547,7 +562,6 @@ test_unaligned (void)
 
   for (offset = MAX_OFFSET; offset >= 1; --offset)
   {
-    struct Sha512_256Ctx ctx;
     uint8_t *unaligned_digest;
     uint8_t *unaligned_buf;
 
diff --git a/src/testcurl/https/test_empty_response.c 
b/src/testcurl/https/test_empty_response.c
index a8de5cd2..3dc5b0bb 100644
--- a/src/testcurl/https/test_empty_response.c
+++ b/src/testcurl/https/test_empty_response.c
@@ -28,9 +28,9 @@
 #include <limits.h>
 #include <sys/stat.h>
 #include <curl/curl.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #include <gcrypt.h>
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 #include "tls_test_common.h"
 #include "tls_test_keys.h"
 
diff --git a/src/testcurl/https/test_https_get.c 
b/src/testcurl/https/test_https_get.c
index 62546324..f2016cc2 100644
--- a/src/testcurl/https/test_https_get.c
+++ b/src/testcurl/https/test_https_get.c
@@ -29,9 +29,9 @@
 #include <limits.h>
 #include <sys/stat.h>
 #include <curl/curl.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #include <gcrypt.h>
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 #include "tls_test_common.h"
 #include "tls_test_keys.h"
 
@@ -234,12 +234,12 @@ main (int argc, char *const *argv)
   const char *aes256_sha_tlsv1   = "AES256-SHA";
   (void) argc; (void) argv;   /* Unused. Silent compiler warning. */
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
   if (! testsuite_curl_global_init ())
     return 99;
   if (NULL == curl_version_info (CURLVERSION_NOW)->ssl_version)
diff --git a/src/testcurl/https/test_https_get_iovec.c 
b/src/testcurl/https/test_https_get_iovec.c
index b2d46c3f..33272952 100644
--- a/src/testcurl/https/test_https_get_iovec.c
+++ b/src/testcurl/https/test_https_get_iovec.c
@@ -37,9 +37,9 @@
 #include <limits.h>
 #include <sys/stat.h>
 #include <curl/curl.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #include <gcrypt.h>
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 #include "tls_test_common.h"
 #include "tls_test_keys.h"
 
@@ -391,12 +391,12 @@ main (int argc, char *const *argv)
   const char *aes256_sha_tlsv1   = "AES256-SHA";
   (void) argc; (void) argv;   /* Unused. Silent compiler warning. */
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
   if (! testsuite_curl_global_init ())
     return 99;
   if (NULL == curl_version_info (CURLVERSION_NOW)->ssl_version)
diff --git a/src/testcurl/https/test_https_get_parallel.c 
b/src/testcurl/https/test_https_get_parallel.c
index 3de7cfe7..cf318a46 100644
--- a/src/testcurl/https/test_https_get_parallel.c
+++ b/src/testcurl/https/test_https_get_parallel.c
@@ -31,9 +31,9 @@
 #include <limits.h>
 #include <curl/curl.h>
 #include <pthread.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #include <gcrypt.h>
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 #include "tls_test_common.h"
 #include "tls_test_keys.h"
 
diff --git a/src/testcurl/https/test_https_get_parallel_threads.c 
b/src/testcurl/https/test_https_get_parallel_threads.c
index 08ee35e6..e8df1e14 100644
--- a/src/testcurl/https/test_https_get_parallel_threads.c
+++ b/src/testcurl/https/test_https_get_parallel_threads.c
@@ -33,9 +33,9 @@
 #include <limits.h>
 #include <curl/curl.h>
 #include <pthread.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #include <gcrypt.h>
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 #include "tls_test_common.h"
 #include "tls_test_keys.h"
 
@@ -152,11 +152,11 @@ main (int argc, char *const *argv)
   /* initialize random seed used by curl clients */
   iseed = (unsigned int) time (NULL);
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
   srand (iseed);
   if (! testsuite_curl_global_init ())
     return 99;
diff --git a/src/testcurl/https/test_https_get_select.c 
b/src/testcurl/https/test_https_get_select.c
index 3b45323b..92774771 100644
--- a/src/testcurl/https/test_https_get_select.c
+++ b/src/testcurl/https/test_https_get_select.c
@@ -29,9 +29,9 @@
 #include <limits.h>
 #include <sys/stat.h>
 #include <curl/curl.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #include <gcrypt.h>
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 #include "tls_test_common.h"
 #include "tls_test_keys.h"
 
diff --git a/src/testcurl/https/test_https_multi_daemon.c 
b/src/testcurl/https/test_https_multi_daemon.c
index 10e7f6ed..da60c543 100644
--- a/src/testcurl/https/test_https_multi_daemon.c
+++ b/src/testcurl/https/test_https_multi_daemon.c
@@ -29,9 +29,9 @@
 #include <curl/curl.h>
 #include <limits.h>
 #include <sys/stat.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #include <gcrypt.h>
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 #include "tls_test_common.h"
 #include "tls_test_keys.h"
 
@@ -132,12 +132,12 @@ main (int argc, char *const *argv)
   const char *aes256_sha = "AES256-SHA";
   (void) argc; (void) argv;       /* Unused. Silent compiler warning. */
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
   if (! testsuite_curl_global_init ())
     return 99;
   if (NULL == curl_version_info (CURLVERSION_NOW)->ssl_version)
diff --git a/src/testcurl/https/test_https_session_info.c 
b/src/testcurl/https/test_https_session_info.c
index fc6f82f7..12208ba7 100644
--- a/src/testcurl/https/test_https_session_info.c
+++ b/src/testcurl/https/test_https_session_info.c
@@ -29,9 +29,9 @@
 #include "platform.h"
 #include "microhttpd.h"
 #include <curl/curl.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #include <gcrypt.h>
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 #include "tls_test_common.h"
 #include "tls_test_keys.h"
 
@@ -200,12 +200,12 @@ main (int argc, char *const *argv)
   const char *ssl_version;
   (void) argc;   /* Unused. Silent compiler warning. */
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
   if (! testsuite_curl_global_init ())
     return 99;
 
diff --git a/src/testcurl/https/test_https_sni.c 
b/src/testcurl/https/test_https_sni.c
index 4ffe1d8f..3581aa17 100644
--- a/src/testcurl/https/test_https_sni.c
+++ b/src/testcurl/https/test_https_sni.c
@@ -28,9 +28,9 @@
 #include <limits.h>
 #include <sys/stat.h>
 #include <curl/curl.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #include <gcrypt.h>
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 #include "tls_test_common.h"
 #include <gnutls/gnutls.h>
 
@@ -264,12 +264,12 @@ main (int argc, char *const *argv)
   else
     port = 3060;
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
   if (! testsuite_curl_global_init ())
     return 99;
   tls_backend = curl_version_info (CURLVERSION_NOW)->ssl_version;
diff --git a/src/testcurl/https/test_https_time_out.c 
b/src/testcurl/https/test_https_time_out.c
index 939101a6..b9e48363 100644
--- a/src/testcurl/https/test_https_time_out.c
+++ b/src/testcurl/https/test_https_time_out.c
@@ -30,9 +30,9 @@
 #include "platform.h"
 #include "microhttpd.h"
 #include "tls_test_common.h"
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #include <gcrypt.h>
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 #ifdef HAVE_SIGNAL_H
 #include <signal.h>
 #endif /* HAVE_SIGNAL_H */
@@ -208,12 +208,12 @@ main (int argc, char *const *argv)
 #endif
 #endif /* MHD_SEND_SPIPE_SUPPRESS_NEEDED */
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
   if (GNUTLS_E_SUCCESS != gnutls_global_init ())
   {
     fprintf (stderr, "Cannot initialize GnuTLS.\n");
diff --git a/src/testcurl/https/test_tls_authentication.c 
b/src/testcurl/https/test_tls_authentication.c
index 22d47b26..0bb87f42 100644
--- a/src/testcurl/https/test_tls_authentication.c
+++ b/src/testcurl/https/test_tls_authentication.c
@@ -29,9 +29,9 @@
 #include <curl/curl.h>
 #include <limits.h>
 #include <sys/stat.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #include <gcrypt.h>
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 #include "tls_test_common.h"
 #include "tls_test_keys.h"
 
@@ -90,12 +90,12 @@ main (int argc, char *const *argv)
   (void) argc;
   (void) argv;       /* Unused. Silent compiler warning. */
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
   if (! testsuite_curl_global_init ())
     return 99;
   if (NULL == curl_version_info (CURLVERSION_NOW)->ssl_version)
diff --git a/src/testcurl/https/test_tls_extensions.c 
b/src/testcurl/https/test_tls_extensions.c
index 3fe4ef71..277bd010 100644
--- a/src/testcurl/https/test_tls_extensions.c
+++ b/src/testcurl/https/test_tls_extensions.c
@@ -29,9 +29,9 @@
 #include "microhttpd.h"
 #include "tls_test_common.h"
 #include "mhd_sockets.h" /* only macros used */
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #include <gcrypt.h>
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 #include "tls_test_keys.h"
 
 #define MAX_EXT_DATA_LENGTH 256
@@ -220,12 +220,12 @@ main (int argc, char *const *argv)
   else
     port = 3080;
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
   MHD_gtls_global_set_log_level (11);
 
   if ((test_fd = setup_test_file ()) == NULL)
diff --git a/src/testcurl/https/test_tls_options.c 
b/src/testcurl/https/test_tls_options.c
index 8c67a0c6..7e15e3ca 100644
--- a/src/testcurl/https/test_tls_options.c
+++ b/src/testcurl/https/test_tls_options.c
@@ -28,9 +28,9 @@
 #include "microhttpd.h"
 #include <sys/stat.h>
 #include <limits.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #include <gcrypt.h>
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 #include "tls_test_common.h"
 #include "tls_test_keys.h"
 
@@ -100,13 +100,13 @@ main (int argc, char *const *argv)
   else
     port = 3010;
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
   if (! testsuite_curl_global_init ())
     return 99;
 
diff --git a/src/testcurl/test_basicauth.c b/src/testcurl/test_basicauth.c
index ed0406db..f9ce2455 100644
--- a/src/testcurl/test_basicauth.c
+++ b/src/testcurl/test_basicauth.c
@@ -721,14 +721,14 @@ main (int argc, char *const *argv)
   }
 #endif /* libcurl version before 7.21.3 */
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #ifdef HAVE_GCRYPT_H
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 #endif
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
   oldapi = has_in_name (argv[0], "_oldapi");
   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
     return 2;
diff --git a/src/testcurl/test_digestauth.c b/src/testcurl/test_digestauth.c
index 61b5b647..adc5f330 100644
--- a/src/testcurl/test_digestauth.c
+++ b/src/testcurl/test_digestauth.c
@@ -26,18 +26,19 @@
  * @author Karlson2k (Evgeny Grin)
  */
 
-#include "MHD_config.h"
+#include "mhd_options.h"
 #include "platform.h"
 #include <curl/curl.h>
 #include <microhttpd.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
-#ifdef HAVE_GCRYPT_H
+
+#if defined(MHD_HTTPS_REQUIRE_GCRYPT) && \
+  (defined(MHD_SHA256_TLSLIB) || defined(MHD_MD5_TLSLIB))
+#define NEED_GCRYP_INIT 1
 #include <gcrypt.h>
-#endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT && (MHD_SHA256_TLSLIB || MHD_MD5_TLSLIB) */
 
 #ifndef WINDOWS
 #include <sys/socket.h>
@@ -491,14 +492,12 @@ main (int argc, char *const *argv)
   unsigned int errorCount = 0;
   (void) argc; (void) argv; /* Unused. Silent compiler warning. */
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
-#ifdef HAVE_GCRYPT_H
+#ifdef NEED_GCRYP_INIT
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
-#endif
-#endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* GCRYCTL_INITIALIZATION_FINISHED */
+#endif /* NEED_GCRYP_INIT */
   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
     return 2;
   errorCount += testDigestAuth ();
diff --git a/src/testcurl/test_digestauth2.c b/src/testcurl/test_digestauth2.c
index 81a93b5e..ab8d2b07 100644
--- a/src/testcurl/test_digestauth2.c
+++ b/src/testcurl/test_digestauth2.c
@@ -25,7 +25,7 @@
  * @author Karlson2k (Evgeny Grin)
  */
 
-#include "MHD_config.h"
+#include "mhd_options.h"
 #include "platform.h"
 #include <curl/curl.h>
 #include <microhttpd.h>
@@ -33,6 +33,12 @@
 #include <string.h>
 #include <time.h>
 
+#if defined(MHD_HTTPS_REQUIRE_GCRYPT) && \
+  (defined(MHD_SHA256_TLSLIB) || defined(MHD_MD5_TLSLIB))
+#define NEED_GCRYP_INIT 1
+#include <gcrypt.h>
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT && (MHD_SHA256_TLSLIB || MHD_MD5_TLSLIB) */
+
 #ifndef _WIN32
 #include <sys/socket.h>
 #include <unistd.h>
@@ -1464,6 +1470,12 @@ main (int argc, char *const *argv)
   int curl_sspi;
   (void) argc; (void) argv; /* Unused. Silent compiler warning. */
 
+#ifdef NEED_GCRYP_INIT
+  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+#ifdef GCRYCTL_INITIALIZATION_FINISHED
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+#endif /* GCRYCTL_INITIALIZATION_FINISHED */
+#endif /* NEED_GCRYP_INIT */
   /* Test type and test parameters */
   verbose = ! (has_param (argc, argv, "-q") ||
                has_param (argc, argv, "--quiet") ||
diff --git a/src/testcurl/test_digestauth_concurrent.c 
b/src/testcurl/test_digestauth_concurrent.c
index efda16b6..792d15de 100644
--- a/src/testcurl/test_digestauth_concurrent.c
+++ b/src/testcurl/test_digestauth_concurrent.c
@@ -26,18 +26,18 @@
  * @author Karlson2k (Evgeny Grin)
  */
 
-#include "MHD_config.h"
+#include "mhd_options.h"
 #include "platform.h"
 #include <curl/curl.h>
 #include <microhttpd.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
-#ifdef HAVE_GCRYPT_H
+#if defined(MHD_HTTPS_REQUIRE_GCRYPT) && \
+  (defined(MHD_SHA256_TLSLIB) || defined(MHD_MD5_TLSLIB))
+#define NEED_GCRYP_INIT 1
 #include <gcrypt.h>
-#endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT && (MHD_SHA256_TLSLIB || MHD_MD5_TLSLIB) */
 
 #ifndef WINDOWS
 #include <sys/socket.h>
@@ -669,14 +669,12 @@ main (int argc, char *const *argv)
                has_param (argc, argv, "-s") ||
                has_param (argc, argv, "--silent"));
 
-  #ifdef MHD_HTTPS_REQUIRE_GRYPT
-#ifdef HAVE_GCRYPT_H
+#ifdef NEED_GCRYP_INIT
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
-#endif
-#endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* GCRYCTL_INITIALIZATION_FINISHED */
+#endif /* NEED_GCRYP_INIT */
   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
     return 2;
   errorCount += testDigestAuth ();
diff --git a/src/testcurl/test_digestauth_sha256.c 
b/src/testcurl/test_digestauth_sha256.c
index 093fe263..cf6ab8ff 100644
--- a/src/testcurl/test_digestauth_sha256.c
+++ b/src/testcurl/test_digestauth_sha256.c
@@ -27,18 +27,19 @@
  * @author Karlson2k (Evgeny Grin)
  */
 
-#include "MHD_config.h"
+#include "mhd_options.h"
 #include "platform.h"
 #include <curl/curl.h>
 #include <microhttpd.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
-#ifdef HAVE_GCRYPT_H
+
+#if defined(MHD_HTTPS_REQUIRE_GCRYPT) && \
+  (defined(MHD_SHA256_TLSLIB) || defined(MHD_MD5_TLSLIB))
+#define NEED_GCRYP_INIT 1
 #include <gcrypt.h>
-#endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT && (MHD_SHA256_TLSLIB || MHD_MD5_TLSLIB) */
 
 #ifndef WINDOWS
 #include <sys/socket.h>
@@ -320,14 +321,12 @@ main (int argc, char *const *argv)
   /* curl added SHA256 support in 7.57 = 7.0x39 */
   if (d->version_num < 0x073900)
     return 77; /* skip test, curl is too old */
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
-#ifdef HAVE_GCRYPT_H
+#ifdef NEED_GCRYP_INIT
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
-#endif
-#endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* GCRYCTL_INITIALIZATION_FINISHED */
+#endif /* NEED_GCRYP_INIT */
   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
     return 2;
   errorCount += testDigestAuth ();
diff --git a/src/testcurl/test_digestauth_with_arguments.c 
b/src/testcurl/test_digestauth_with_arguments.c
index aabf1b7e..903d90a2 100644
--- a/src/testcurl/test_digestauth_with_arguments.c
+++ b/src/testcurl/test_digestauth_with_arguments.c
@@ -25,18 +25,19 @@
  * @author Amr Ali
  * @author Karlson2k (Evgeny Grin)
  */
-#include "MHD_config.h"
+#include "mhd_options.h"
 #include "platform.h"
 #include <curl/curl.h>
 #include <microhttpd.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
-#ifdef HAVE_GCRYPT_H
+
+#if defined(MHD_HTTPS_REQUIRE_GCRYPT) && \
+  (defined(MHD_SHA256_TLSLIB) || defined(MHD_MD5_TLSLIB))
+#define NEED_GCRYP_INIT 1
 #include <gcrypt.h>
-#endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT && (MHD_SHA256_TLSLIB || MHD_MD5_TLSLIB) */
 
 #ifndef WINDOWS
 #include <sys/socket.h>
@@ -289,14 +290,14 @@ main (int argc, char *const *argv)
   }
 #endif /* libcurl version 7.62.x */
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #ifdef HAVE_GCRYPT_H
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 #endif
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
     return 2;
   errorCount += testDigestAuth ();
diff --git a/src/testcurl/test_postform.c b/src/testcurl/test_postform.c
index a2dfd41d..1ada80e2 100644
--- a/src/testcurl/test_postform.c
+++ b/src/testcurl/test_postform.c
@@ -33,11 +33,11 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #ifdef HAVE_GCRYPT_H
 #include <gcrypt.h>
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
 
 #ifndef WINDOWS
 #include <unistd.h>
@@ -624,14 +624,14 @@ main (int argc, char *const *argv)
   unsigned int errorCount = 0;
   (void) argc;   /* Unused. Silent compiler warning. */
 
-#ifdef MHD_HTTPS_REQUIRE_GRYPT
+#ifdef MHD_HTTPS_REQUIRE_GCRYPT
 #ifdef HAVE_GCRYPT_H
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 #ifdef GCRYCTL_INITIALIZATION_FINISHED
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
 #endif
 #endif
-#endif /* MHD_HTTPS_REQUIRE_GRYPT */
+#endif /* MHD_HTTPS_REQUIRE_GCRYPT */
   if ((NULL == argv) || (0 == argv[0]))
     return 99;
   oneone = has_in_name (argv[0], "11");
diff --git a/w32/common/MHD_config.h b/w32/common/MHD_config.h
index 7a658d7b..04e39ea3 100644
--- a/w32/common/MHD_config.h
+++ b/w32/common/MHD_config.h
@@ -74,6 +74,15 @@
 /* Enable digest Auth support */
 #define DAUTH_SUPPORT 1
 
+/* Enable MD5 hashing support. */
+#define MHD_MD5_SUPPORT 1
+
+/* Enable SHA-256 hashing support. */
+#define MHD_SHA256_SUPPORT 1
+
+/* Enable SHA-512/256 hashing support. */
+#define MHD_SHA512_256_SUPPORT 1
+
 /* Enable postprocessor.c */
 #define HAVE_POSTPROCESSOR 1
 
@@ -171,6 +180,9 @@
 #endif /* C11 */
 #endif /* VS 2015 and later */
 
+/* Define to 1 if you have the 'rand' function. */
+#define HAVE_RAND 1
+
 /* *** Headers information *** */
 /* Not really important as not used by code currently */
 
diff --git a/w32/common/libmicrohttpd-files.vcxproj 
b/w32/common/libmicrohttpd-files.vcxproj
index 1818f0df..0790a3eb 100644
--- a/w32/common/libmicrohttpd-files.vcxproj
+++ b/w32/common/libmicrohttpd-files.vcxproj
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="4.0" 
xmlns="http://schemas.microsoft.com/developer/msbuild/2003";>
   <ItemGroup>
-    <ClCompile Include="$(MhdSrc)microhttpd\base64.c" />
     <ClCompile Include="$(MhdSrc)microhttpd\basicauth.c" />
     <ClCompile Include="$(MhdSrc)microhttpd\connection.c" />
     <ClCompile Include="$(MhdSrc)microhttpd\daemon.c" />
@@ -10,6 +9,7 @@
     <ClCompile Include="$(MhdSrc)microhttpd\internal.c" />
     <ClCompile Include="$(MhdSrc)microhttpd\md5.c" />
     <ClCompile Include="$(MhdSrc)microhttpd\sha256.c" />
+    <ClCompile Include="$(MhdSrc)microhttpd\sha512_256.c" />
     <ClCompile Include="$(MhdSrc)microhttpd\memorypool.c" />
     <ClCompile Include="$(MhdSrc)microhttpd\mhd_mono_clock.c" />
     <ClCompile Include="$(MhdSrc)microhttpd\postprocessor.c" />
@@ -32,14 +32,16 @@
     <ClInclude Include="$(MhdSrc)include\microhttpd.h" />
     <ClInclude Include="$(MhdSrc)include\mhd_options.h" />
     <ClInclude Include="$(MhdSrc)include\platform.h" />
-    <ClInclude Include="$(MhdSrc)microhttpd\base64.h" />
     <ClInclude Include="$(MhdSrc)microhttpd\basicauth.h" />
     <ClInclude Include="$(MhdSrc)microhttpd\connection.h" />
     <ClInclude Include="$(MhdSrc)microhttpd\digestauth.h" />
     <ClInclude Include="$(MhdSrc)microhttpd\gen_auth.h" />
     <ClInclude Include="$(MhdSrc)microhttpd\internal.h" />
+    <ClInclude Include="$(MhdSrc)microhttpd\mhd_md5_wrap.h" />
     <ClInclude Include="$(MhdSrc)microhttpd\md5.h" />
+    <ClInclude Include="$(MhdSrc)microhttpd\mhd_sha256_wrap.h" />
     <ClInclude Include="$(MhdSrc)microhttpd\sha256.h" />
+    <ClInclude Include="$(MhdSrc)microhttpd\sha512_256.h" />
     <ClInclude Include="$(MhdSrc)microhttpd\memorypool.h" />
     <ClInclude Include="$(MhdSrc)microhttpd\mhd_assert.h" />
     <ClInclude Include="$(MhdSrc)microhttpd\mhd_align.h" />
diff --git a/w32/common/libmicrohttpd-filters.vcxproj 
b/w32/common/libmicrohttpd-filters.vcxproj
index 76c0c56e..27fd6f18 100644
--- a/w32/common/libmicrohttpd-filters.vcxproj
+++ b/w32/common/libmicrohttpd-filters.vcxproj
@@ -40,9 +40,6 @@
     <ClInclude Include="$(MhdW32Common)MHD_config.h">
       <Filter>Internal Headers</Filter>
     </ClInclude>
-    <ClInclude Include="$(MhdSrc)microhttpd\base64.h">
-      <Filter>Internal Headers</Filter>
-    </ClInclude>
     <ClInclude Include="$(MhdSrc)microhttpd\basicauth.h">
       <Filter>Internal Headers</Filter>
     </ClInclude>
@@ -58,12 +55,21 @@
     <ClInclude Include="$(MhdSrc)microhttpd\internal.h">
       <Filter>Internal Headers</Filter>
     </ClInclude>
+    <ClInclude Include="$(MhdSrc)microhttpd\mhd_md5_wrap.h">
+      <Filter>Internal Headers</Filter>
+    </ClInclude>
     <ClInclude Include="$(MhdSrc)microhttpd\md5.h">
       <Filter>Internal Headers</Filter>
     </ClInclude>
+    <ClInclude Include="$(MhdSrc)microhttpd\mhd_sha256_wrap.h">
+      <Filter>Internal Headers</Filter>
+    </ClInclude>
     <ClInclude Include="$(MhdSrc)microhttpd\sha256.h">
       <Filter>Internal Headers</Filter>
     </ClInclude>
+    <ClInclude Include="$(MhdSrc)microhttpd\sha512_256.h">
+      <Filter>Internal Headers</Filter>
+    </ClInclude>
     <ClInclude Include="$(MhdSrc)microhttpd\memorypool.h">
       <Filter>Internal Headers</Filter>
     </ClInclude>
@@ -129,9 +135,6 @@
     </ClInclude>
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="$(MhdSrc)microhttpd\base64.c">
-      <Filter>Source Files</Filter>
-    </ClCompile>
     <ClCompile Include="$(MhdSrc)microhttpd\basicauth.c">
       <Filter>Source Files</Filter>
     </ClCompile>
@@ -156,6 +159,9 @@
     <ClCompile Include="$(MhdSrc)microhttpd\sha256.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="$(MhdSrc)microhttpd\sha512_256.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
     <ClCompile Include="$(MhdSrc)microhttpd\memorypool.c">
       <Filter>Source Files</Filter>
     </ClCompile>

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]