commit 4b7f569c79a1d785ae0b2e6f7c49ee2f5a837be4
parent f17b51ab9ea757c59f209a042bac818d9a0b6287
Author: Christian Grothoff <christian@grothoff.org>
Date: Sun, 23 Nov 2025 22:39:30 +0100
add md5 unit test
Diffstat:
3 files changed, 316 insertions(+), 1 deletion(-)
diff --git a/src/mhd2/Makefile.am b/src/mhd2/Makefile.am
@@ -19,6 +19,7 @@ lib_LTLIBRARIES = \
libmicrohttpd2.la
crypt_LDFLAGS = $(MHD_TLS_LIB_LDFLAGS)
+crypt_LIBDEPS = $(MHD_TLS_LIBDEPS)
noinst_DATA =
MOSTLYCLEANFILES =
@@ -167,16 +168,22 @@ if MHD_SUPPORT_OPENSSL
md5_ext_openssl.c
crypt_LDFLAGS += \
$(OPENSSL_LDFLAGS)
+ crypt_LIBDEPS += \
+ $(OPENSSL_LIBS)
else
if MHD_SUPPORT_GNUTLS
md5_OPTSOURCES += \
md5_ext_gnutls.c
crypt_LDFLAGS += \
$(GNUTLS_LDFLAGS)
+ crypt_LIBDEPS += \
+ $(GNUTLS_LIBS)
else
md5_OPTSOURCES += \
md5_ext_mbedtls.c
crypt_LDFLAGS += \
+ $(MBEDTLS_LDFLAGS)
+ crypt_LIBDEPS += \
-lmbedcrypto
endif
endif
@@ -196,16 +203,22 @@ if MHD_SUPPORT_OPENSSL
sha256_ext_openssl.c
crypt_LDFLAGS += \
$(OPENSSL_LDFLAGS)
+ crypt_LIBDEPS += \
+ $(OPENSSL_LIBS)
else
if MHD_SUPPORT_GNUTLS
sha256_OPTSOURCES += \
sha256_ext_gnutls.c
crypt_LDFLAGS += \
$(GNUTLS_LDFLAGS)
+ crypt_LIBDEPS += \
+ $(GNUTLS_LIBS)
else
sha256_OPTSOURCES += \
sha256_ext_mbedtls.c
crypt_LDFLAGS += \
+ $(MBEDTLS_LDFLAGS)
+ crypt_LIBDEPS += \
-lmbedcrypto
endif
endif
@@ -226,10 +239,14 @@ if MHD_SUPPORT_OPENSSL
sha512_256_ext_openssl.c
crypt_LDFLAGS += \
$(OPENSSL_LDFLAGS)
+ crypt_LIBDEPS += \
+ $(OPENSSL_LIBS)
else
sha256_OPTSOURCES += \
sha512_256_ext_mbedtls.c
crypt_LDFLAGS += \
+ $(MBEDTLS_LDFLAGS)
+ crypt_LIBDEPS += \
-lmbedcrypto
endif
else
@@ -334,7 +351,7 @@ libmicrohttpd2_la_LDFLAGS = \
-export-dynamic -no-undefined \
-version-info @LIB_VER_CURRENT@:@LIB_VER_REVISION@:@LIB_VER_AGE@
libmicrohttpd2_la_LIBADD = \
- $(MHD_LIBDEPS) $(MHD_TLS_LIBDEPS)
+ $(MHD_LIBDEPS) $(MHD_TLS_LIBDEPS) $(crypt_LIBDEPS)
libmicrohttpd2_la_SHORTNAME = mhd2
diff --git a/src/tests/unit/Makefile.am b/src/tests/unit/Makefile.am
@@ -39,6 +39,11 @@ check_PROGRAMS += \
$(EMPTY_ITEM)
endif
+if MHD_SUPPORT_MD5
+check_PROGRAMS += \
+ unit_md5
+endif
+
TESTS = $(check_PROGRAMS)
unit_h2_huffman_encode_SOURCES = \
@@ -58,3 +63,20 @@ unit_hpack_tables_dynamic_SOURCES = \
unit_hpack_tables_static_SOURCES = $(unit_hpack_tables_dynamic_SOURCES)
unit_hpack_tables_combined_SOURCES = $(unit_hpack_tables_dynamic_SOURCES)
+
+unit_md5_SOURCES = unit_md5.c
+
+if MHD_MD5_EXTR
+if MHD_SUPPORT_OPENSSL
+unit_md5_LDFLAGS = $(OPENSSL_LDFLAGS)
+unit_md5_LDADD = $(OPENSSL_LDFLAGS)
+else
+if MHD_SUPPORT_GNUTLS
+unit_md5_LDFLAGS = $(GNUTLS_LDFLAGS)
+unit_md5_LDADD = $(GNUTLS_LIBS)
+else
+unit_md5_LDFLAGS = $(MBEDTLS_LDFLAGS)
+unit_md5_LDADD = -lmbedcrypto
+endif
+endif
+endif
diff --git a/src/tests/unit/unit_md5.c b/src/tests/unit/unit_md5.c
@@ -0,0 +1,276 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
+/*
+ This file is part of GNU libmicrohttpd.
+ Copyright (C) 2025 Christian Grothoff
+
+ 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.
+
+ GNU libmicrohttpd 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.
+
+ Alternatively, you can redistribute GNU libmicrohttpd and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version, together
+ with the eCos exception, as follows:
+
+ As a special exception, if other files instantiate templates or
+ use macros or inline functions from this file, or you compile this
+ file and link it with other works to produce a work based on this
+ file, this file does not by itself cause the resulting work to be
+ covered by the GNU General Public License. However the source code
+ for this file must still be made available in accordance with
+ section (3) of the GNU General Public License v2.
+
+ This exception does not invalidate any other reasons why a work
+ based on this file might be covered by the GNU General Public
+ License.
+
+ You should have received copies of the GNU Lesser General Public
+ License and the GNU General Public License along with this library;
+ if not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file src/test/unit/unit_md5.c
+ * @brief The tests for MD5
+ * @author Christian Grothoff
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "mhd_sys_options.h"
+
+#if MHD_MD5_EXTR_GNUTLS
+#include "../mhd2/md5_ext_gnutls.c"
+#elif MHD_MD5_EXTR_MBEDTLS
+#include "../mhd2/md5_ext_mbedtls.c"
+#elif MHD_MD5_EXTR_OPENSSL
+#include "../mhd2/md5_ext_openssl.c"
+#else
+#include "../mhd2/md5_int.c"
+#endif
+
+#include "../mhd2/mhd_md5.h"
+
+
+/* Define to 1 if libmicrohttpd is compiled with MD5 hashing by OpenSSL. */
+/* #undef MHD_MD5_EXTR_OPENSSL */
+
+/* Helper function to convert hex string to binary */
+static size_t
+hex2bin (const char *hex,
+ uint8_t *bin,
+ size_t max_len)
+{
+ size_t len = strlen (hex) / 2;
+
+ if (len > max_len)
+ len = max_len;
+ for (size_t i = 0; i < len; i++)
+ {
+ sscanf (hex + 2 * i,
+ "%2hhx",
+ &bin[i]);
+ }
+ return len;
+}
+
+
+/* Helper function to compare digest with expected hex string */
+static int
+check_digest (const uint8_t *digest,
+ size_t digest_len,
+ const char *expected_hex,
+ const char *test_name)
+{
+ uint8_t expected[64];
+ size_t expected_len = hex2bin (expected_hex,
+ expected,
+ sizeof(expected));
+
+ if (expected_len != digest_len)
+ {
+ printf ("FAIL: %s - length mismatch\n",
+ test_name);
+ return 0;
+ }
+
+ if (0 !=
+ memcmp (digest,
+ expected,
+ digest_len))
+ {
+ printf ("FAIL: %s\n",
+ test_name);
+ printf (" Expected: %s\n",
+ expected_hex);
+ printf (" Got: ");
+ for (size_t i = 0; i < digest_len; i++)
+ {
+ printf ("%02x",
+ digest[i]);
+ }
+ printf ("\n");
+ return 0;
+ }
+ return 1;
+}
+
+
+int
+main (void)
+{
+ struct Test
+ {
+ const char *name;
+ const char *input;
+ const char *digest;
+ } tests[] = {
+ { "Empty string (RFC 1321)",
+ "",
+ "d41d8cd98f00b204e9800998ecf8427e" },
+ { "a (RFC 1321)",
+ "61",
+ "0cc175b9c0f1b6a831c399e269772661" },
+ { "abc (RFC 1321)",
+ "616263",
+ "900150983cd24fb0d6963f7d28e17f72" },
+ { "a (RFC 1321)",
+ "61",
+ "0cc175b9c0f1b6a831c399e269772661" },
+ { "message digest (RFC 1321)",
+ "6d65737361676520646967657374",
+ "f96b697d7cb7938d525a2f31aaf161d0" },
+ { "abcdefghijklmnopqrstuvwxyz (RFC 1321)",
+ "6162636465666768696A6B6C6D6E6F707172737475767778797A",
+ "c3fcd3d76192e4007dfb496cca67e13b" },
+ { "A-Za-z0-9 (RFC 1321)",
+ "4142434445464748494A4B4C4D4E4F505152535455565758595A6162636465666768696A6B6C6D6E6F707172737475767778797A30313233343536373839",
+ "d174ab98d277d9f5a5611c2c9f419d9f" },
+ { "8 repetitions of 1234567890 (RFC 1321)",
+ "3132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930",
+ "57edf4a22be3c955ac49da2e2107b67a" },
+ { "The quick brown fox jumps over the lazy dog (Wikipedia MD5 article)",
+ "54686520717569636B2062726F776E20666F78206A756D7073206F76657220746865206C617A7920646F67",
+ "9e107d9d372bb6826bd81d3542a419d6" },
+ { "0x00",
+ "00",
+ "93b885adfe0da089cdf634904fd59f71" },
+ { "Two bytes 0x00 0x00",
+ "0000",
+ "c4103f122d27677c9db144cae1394a66" },
+ { NULL, NULL, NULL }
+ };
+ struct mhd_Md5Ctx ctx;
+ uint8_t digest[mhd_MD5_DIGEST_SIZE];
+ uint8_t data[1024];
+ size_t data_len;
+ unsigned int passed = 0;
+ unsigned int total = 0;
+
+ while (NULL != tests[total].name)
+ {
+ const struct Test *t = &tests[total];
+
+ mhd_MD5_init_one_time (&ctx);
+ if (! mhd_MD5_has_err (&ctx))
+ {
+ data_len = hex2bin (t->input,
+ data,
+ sizeof(data));
+ if (0 != data_len)
+ mhd_MD5_update (&ctx,
+ data_len,
+ data);
+ mhd_MD5_finish_deinit (&ctx,
+ digest);
+ if (! mhd_MD5_has_err (&ctx))
+ {
+ if (check_digest (digest,
+ mhd_MD5_DIGEST_SIZE,
+ t->digest,
+ t->name))
+ passed++;
+ }
+ else
+ {
+ printf ("FAIL: %s - error in finish\n",
+ t->name);
+ }
+ }
+ else
+ {
+ printf ("FAIL: %s - error in init\n",
+ t->name);
+ }
+ total++;
+ }
+
+ /*
+ * Test update functionality
+ */
+ total++;
+ mhd_MD5_init_one_time (&ctx);
+ if (! mhd_MD5_has_err (&ctx))
+ {
+ data[0] = 'a';
+ mhd_MD5_update (&ctx, 1, data);
+ data[0] = 'b';
+ mhd_MD5_update (&ctx, 1, data);
+ data[0] = 'c';
+ mhd_MD5_update (&ctx, 1, data);
+ mhd_MD5_finish_deinit (&ctx, digest);
+ if (! mhd_MD5_has_err (&ctx))
+ {
+ if (check_digest (digest,
+ mhd_MD5_DIGEST_SIZE,
+ "900150983cd24fb0d6963f7d28e17f72",
+ "Multi-update: a + b + c"))
+ passed++;
+ }
+ }
+
+ /*
+ * Tests finish_reset and reuse of context
+ */
+ total++;
+ mhd_MD5_init_one_time (&ctx);
+ if (! mhd_MD5_has_err (&ctx))
+ {
+ /* First hash */
+ data_len = hex2bin ("616263",
+ data,
+ sizeof(data)); /* "abc" */
+ mhd_MD5_update (&ctx, data_len, data);
+ mhd_MD5_finish_reset (&ctx, digest);
+
+ /* Second hash on same context */
+ data_len = hex2bin ("616263", data, sizeof(data)); /* "abc" again */
+ mhd_MD5_update (&ctx, data_len, data);
+ mhd_MD5_finish_deinit (&ctx, digest);
+
+ if (! mhd_MD5_has_err (&ctx))
+ {
+ if (check_digest (digest,
+ mhd_MD5_DIGEST_SIZE,
+ "900150983cd24fb0d6963f7d28e17f72",
+ "Reset and reuse context"))
+ passed++;
+ }
+ }
+
+ printf ("Results: %d/%d tests passed\n",
+ passed,
+ total);
+
+ return (passed == total) ? 0 : 1;
+}