]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
Add tests for loading and using all supported symmetric auth digests.
authorDave Hart <hart@ntp.org>
Mon, 5 Jun 2023 00:21:10 +0000 (00:21 +0000)
committerDave Hart <hart@ntp.org>
Mon, 5 Jun 2023 00:21:10 +0000 (00:21 +0000)
bk: 647d2a76ypF1ZRxI9WVG7YusJXspdQ

18 files changed:
ChangeLog
include/ntp.h
include/ntp_md5.h
include/ntp_stdlib.h
libntp/a_md5encrypt.c
libntp/authkeys.c
libntp/authreadkeys.c
libntp/msyslog.c
libparse/clk_hopf6021.c
libparse/clk_wharton.c
ntpd/ntp_control.c
ntpd/ntp_loopfilter.c
sntp/crypto.c
sntp/crypto.h
tests/libntp/Makefile.am
tests/libntp/data/ntp.keys
tests/libntp/digests.c [new file with mode: 0644]
tests/libntp/run-digests.c [new file with mode: 0644]

index 36137ffc2261f7f6fbc9ec5fc5f67de1dbf53eb8..39703092a1065c0dcad17c3bde375cb3fed457eb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,8 @@
 * [Bug 3821] 4.2.8p16 misreads hex authentication keys, won't interop with
              4.2.8p15.  Reported by Matt Nordhoff, thanks to Miroslav Lichvar
              and Matt for rapid testing narrowing the problem. <hart@ntp.org>
+* Add tests/libntp/digests.c to catch regressions reading keys file or with
+  symmetric authentication digest output.
 
 ---
 (4.2.8p16) 2023/05/31 Released by Harlan Stenn <stenn@ntp.org>
index c037f59860164f9fa4efafb6707c4d500b445aab..258ddd6138f71ba4aaeb3194f80420fd0cbad97b 100644 (file)
@@ -134,7 +134,7 @@ typedef char s_char;
  * Miscellaneous stuff
  */
 #define NTP_MAXKEY     65535   /* max authentication key number */
-#define        KEY_TYPE_MD5    NID_md5 /* MD5 digest NID */
+
 /*
  * Limits of things
  */
index 06c90b2d2faf0765fa647eb25f5d597d1f00ef3a..8b5a7d0cbb49604dde0ff0bad19403f627e0b9cb 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef NTP_MD5_H
 #define NTP_MD5_H
 
+# define KEY_TYPE_MD5                  NID_md5
+
 #ifdef OPENSSL
 # include <openssl/evp.h>
 # include "libssl_compat.h"
@@ -30,6 +32,8 @@
 
   typedef MD5_CTX                      EVP_MD_CTX;
 
+# define NID_md5                       4       /* from openssl/objects.h */
+# define EVP_MAX_MD_SIZE               64      /* from openssl/evp.h */
 # define EVP_MD_CTX_free(c)            free(c)
 # define EVP_MD_CTX_new()              calloc(1, sizeof(MD5_CTX))
 # define EVP_get_digestbynid(t)                NULL
index 2d7c640565d5b72d95e9d2b33cd10604a405d70e..446837e3adcb9ae8ca3c8465544dc49a38bbb806 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "declcond.h"  /* ntpd uses ntpd/declcond.h, others include/ */
 #include "l_stdlib.h"
+#include "ntp_md5.h"
 #include "ntp_net.h"
 #include "ntp_debug.h"
 #include "ntp_malloc.h"
 #include "ntp_syslog.h"
 #include "ntp_keyacc.h"
 
+#ifndef PATH_MAX
+# define PATH_MAX MAX_PATH
+#endif
+
 #ifdef __GNUC__
 #define NTP_PRINTF(fmt, args) __attribute__((__format__(__printf__, fmt, args)))
 #else
@@ -36,24 +41,16 @@ extern      void    mvsyslog(int, const char *, va_list) NTP_PRINTF(2, 0);
 extern void    init_logging    (const char *, u_int32, int);
 extern int     change_logfile  (const char *, int);
 extern void    setup_logfile   (const char *);
-#ifndef errno_to_str
+#ifndef errno_to_str           /* Windows port defines this */
 extern void    errno_to_str(int, char *, size_t);
 #endif
 
-extern char *  ntp_realpath(const char * fsname);
+extern char *  ntp_realpath(const char *fsname);
 
-extern int     xvsbprintf(char**, char* const, char const*, va_list) NTP_PRINTF(3, 0);
-extern int     xsbprintf(char**, char* const, char const*, ...) NTP_PRINTF(3, 4);
-
-/*
- * When building without OpenSSL, use a few macros of theirs to
- * minimize source differences in NTP.
- */
-#ifndef OPENSSL
-#define NID_md5        4       /* from openssl/objects.h */
-/* from openssl/evp.h */
-#define EVP_MAX_MD_SIZE        64      /* longest known is SHA512 */
-#endif
+extern int     xvsbprintf(char **, char * const, char const *, va_list)
+                               NTP_PRINTF(3, 0);
+extern int     xsbprintf(char **, char * const, char const *, ...)
+                               NTP_PRINTF(3, 4);
 
 #define SAVE_ERRNO(stmt)                               \
        {                                               \
@@ -111,10 +108,16 @@ extern    void    auth_prealloc_symkeys(int);
 extern int     ymd2yd          (int, int, int);
 
 /* a_md5encrypt.c */
-extern int     MD5authdecrypt  (int, const u_char *, size_t, u_int32 *, size_t, size_t, keyid_t);
-extern size_t  MD5authencrypt  (int, const u_char *, size_t, u_int32 *, size_t);
-extern void    MD5auth_setkey  (keyid_t, int, const u_char *, size_t, KeyAccT *c);
-extern u_int32 addr2refid      (sockaddr_u *);
+extern size_t  MD5authencrypt  (int type, const u_char *key, size_t klen,
+                                u_int32 *pkt, size_t length);
+extern int     MD5authdecrypt  (int type, const u_char *key, size_t klen,
+                                u_int32 *pkt, size_t length, size_t size,
+                                keyid_t keyno);
+extern u_int32 addr2refid(sockaddr_u *);
+
+/* authkeys.c */
+extern void    MD5auth_setkey  (keyid_t, int, const u_char *, size_t,
+                                KeyAccT *c);
 
 /* emalloc.c */
 #ifndef EREALLOC_CALLSITE      /* ntp_malloc.h defines */
index 6011af52af6dab14c638d7042e3112b07164e37f..7a372969123fd584ed3d1ecf2a8969dd198a35a2 100644 (file)
@@ -9,7 +9,6 @@
 #include "ntp_string.h"
 #include "ntp_stdlib.h"
 #include "ntp.h"
-#include "ntp_md5.h"   /* provides OpenSSL digest API */
 #include "isc/string.h"
 
 typedef struct {
@@ -22,10 +21,12 @@ typedef struct {
        size_t          len;
 } rwbuffT;
 
+
 #if defined(OPENSSL) && defined(ENABLE_CMAC)
 static size_t
 cmac_ctx_size(
-       CMAC_CTX *      ctx)
+       CMAC_CTX *      ctx
+       )
 {
        size_t mlen = 0;
 
@@ -36,14 +37,16 @@ cmac_ctx_size(
        }
        return mlen;
 }
-#endif /*OPENSSL && ENABLE_CMAC*/
+#endif /* OPENSSL && ENABLE_CMAC */
+
 
 static size_t
 make_mac(
        const rwbuffT * digest,
        int             ktype,
        const robuffT * key,
-       const robuffT * msg)
+       const robuffT * msg
+       )
 {
        /*
         * Compute digest of key concatenated with packet. Note: the
@@ -66,8 +69,8 @@ make_mac(
                /* adjust key size (zero padded buffer) if necessary */
                if (AES_128_KEY_SIZE > key->len) {
                        memcpy(keybuf, keyptr, key->len);
-                       memset((keybuf + key->len), 0,
-                              (AES_128_KEY_SIZE - key->len));
+                       zero_mem((keybuf + key->len),
+                                (AES_128_KEY_SIZE - key->len));
                        keyptr = keybuf;
                }
 
@@ -107,10 +110,10 @@ make_mac(
                        goto mac_fail;
                }
 
-           #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
+          #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
                /* make sure MD5 is allowd */
                EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-           #endif
+          #endif
                /* [Bug 3457] DON'T use plain EVP_DigestInit! It would
                 * kill the flags! */
                if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(ktype), NULL)) {
@@ -239,8 +242,8 @@ MD5authdecrypt(
                dlen = MAX_MDG_LEN;
        if (size != (size_t)dlen + KEY_MAC_LEN) {
                msyslog(LOG_ERR,
-                   "MAC decrypt: MAC length error: len=%zu key=%d",
-                       size, keyno);
+                       "MAC decrypt: MAC length error: len=%u key=%d",
+                       (u_int)size, keyno);
                return (0);
        }
        return !isc_tsmemcmp(digest,
index 9f967856768644b3a3f0b376a0840d159803d6d3..d28b4b932b84ee218f6e55b3ef08ce29c1ab0da5 100644 (file)
@@ -284,8 +284,7 @@ init_auth(void)
         */
        newalloc = authhashbuckets * sizeof(key_hash[0]);
 
-       key_hash = erealloc(key_hash, newalloc);
-       memset(key_hash, '\0', newalloc);
+       key_hash = emalloc_zero(newalloc);
 
        INIT_DLIST(key_listhead, llink);
 
@@ -458,7 +457,7 @@ auth_resize_hashtable(void)
        newalloc = authhashbuckets * sizeof(key_hash[0]);
 
        key_hash = erealloc(key_hash, newalloc);
-       memset(key_hash, '\0', newalloc);
+       zero_mem(key_hash, newalloc);
 
        ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
                hash = KEYHASH(sk->keyid);
@@ -528,14 +527,14 @@ freesymkey(
 
        bucket = &key_hash[KEYHASH(sk->keyid)];
        if (sk->secret != NULL) {
-               memset(sk->secret, '\0', sk->secretsize);
+               zero_mem(sk->secret, sk->secretsize);
                free(sk->secret);
        }
        UNLINK_SLIST(unlinked, *bucket, sk, hlink, symkey);
        DEBUG_ENSURE(sk == unlinked);
        UNLINK_DLIST(sk, llink);
-       memset((char *)sk + offsetof(symkey, symkey_payload), '\0',
-              sizeof(*sk) - offsetof(symkey, symkey_payload));
+       zero_mem((char *)sk + offsetof(symkey, symkey_payload),
+                sizeof(*sk) - offsetof(symkey, symkey_payload));
        LINK_SLIST(authfreekeys, sk, llink.f);
        authnumkeys--;
        authnumfreekeys++;
@@ -719,13 +718,13 @@ authistrusted(
 
        if (keyno == cache_keyid) {
                return (KEY_TRUSTED & cache_flags) &&
-                   keyacc_contains(cache_keyacclist, sau, TRUE);
+                       keyacc_contains(cache_keyacclist, sau, TRUE);
        }
 
        if (NULL != (sk = auth_findkey(keyno))) {
                authkeyuncached++;
                return (KEY_TRUSTED & sk->flags) &&
-                   keyacc_contains(sk->keyacclist, sau, TRUE);
+                       keyacc_contains(sk->keyacclist, sau, TRUE);
        }
 
        authkeynotfound++;
@@ -816,7 +815,7 @@ MD5auth_setkey(
 
 /*
  * auth_delkeys - delete non-autokey untrusted keys, and clear all info
- *                except the trusted bit of non-autokey trusted keys, in
+ *               except the trusted bit of non-autokey trusted keys, in
  *               preparation for rereading the keys file.
  */
 void
@@ -835,7 +834,7 @@ auth_delkeys(void)
                 */
                if (KEY_TRUSTED & sk->flags) {
                        if (sk->secret != NULL) {
-                               memset(sk->secret, 0, sk->secretsize);
+                               zero_mem(sk->secret, sk->secretsize);
                                free(sk->secret);
                                sk->secret = NULL; /* TALOS-CAN-0054 */
                        }
@@ -886,9 +885,9 @@ authencrypt(
         * consists of a single word with value zero.
         */
        authencryptions++;
-       pkt[length / 4] = htonl(keyno);
+       pkt[length / KEY_MAC_LEN] = htonl(keyno);
        if (0 == keyno) {
-               return 4;
+               return KEY_MAC_LEN;
        }
        if (!authhavekey(keyno)) {
                return 0;
index da91bd0d3443fdf3f4f317d71d3a6bb38047f5bc..fa2f5b540de45635dea9f985f028e1d41b279a1d 100644 (file)
@@ -234,7 +234,7 @@ authreadkeys(
                 * The key type is unused, but is required to be 'M' or
                 * 'm' for compatibility.
                 */
-               if (!(*token == 'M' || *token == 'm')) {
+               if (! (toupper(*token) == 'M')) {
                        log_maybe(NULL,
                                  "authreadkeys: invalid type for key %d",
                                  keyno);
@@ -357,13 +357,21 @@ authreadkeys(
                        continue;
                }
 
-               INSIST(NULL != next);
+               DEBUG_INSIST(NULL != next);
+#if defined(OPENSSL) && defined(ENABLE_CMAC)
+               if (NID_cmac == keytype && len < 16) {
+                       msyslog(LOG_WARNING, CMAC " keys are 128 bits, "
+                               "zero-extending key %u by %u bits",
+                               (u_int)keyno, 8 * (16 - (u_int)len));
+               }
+#endif /* OPENSSL && ENABLE_CMAC */
                next->next = list;
                list = next;
        }
        fclose(fp);
        if (nerr > 0) {
                const char * why = "";
+
                if (nerr > nerr_maxlimit)
                        why = " (emergency break)";
                msyslog(LOG_ERR,
index ae950171f468181547a5c869e1d73239b4569bd8..a1ba72792595741c9c56a85d27e061f6530e18e6 100644 (file)
@@ -583,8 +583,9 @@ setup_logfile(
                        syslog_fname);
 }
 
-/* Helper for unit tests, where stdout + stderr are piped to the same
- * stream.  This works moderately reliable only if both streams are
+/*
+ * Helper for unit tests, where stdout + stderr are piped to the same
+ * stream.  This works moderately reliably only if both streams are
  * unbuffered or line buffered.  Unfortunately stdout can be fully
  * buffered on pipes or files...
  */
index c5980ef13f2b470884911481b115958e7e1fa488..b0b0c1ff2a73befaaa16da4387c5c7bdc172c7a7 100644 (file)
@@ -25,7 +25,6 @@
 #include "ntp_fp.h"
 #include "ntp_unixtime.h"
 #include "ntp_calendar.h"
-#include "ascii.h"
 
 #include "parse.h"
 
@@ -37,6 +36,8 @@
 extern int printf (const char *, ...);
 #endif
 
+#include "ascii.h"
+
 /*
  * hopf Funkuhr 6021
  *      used with 9600,8N1,
@@ -263,7 +264,7 @@ hexval(
 }
 
 #else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_HOPF6021) */
-int clk_hopf6021_bs;
+NONEMPTY_TRANSLATION_UNIT
 #endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_HOPF6021) */
 
 /*
index 371137dc6fe82efb61cc2d50f0cda789f1e4e147..fbe9cc95f5f76c8e968587671853954d54825b1c 100644 (file)
@@ -15,7 +15,6 @@
  */
 
 #include "ntp_fp.h"
-#include "ascii.h"
 #include "parse.h"
 
 #ifndef PARSESTREAM
@@ -26,6 +25,8 @@
 extern void printf (const char *, ...);
 #endif
 
+#include "ascii.h"
+
 /*
  * In private e-mail alastair@wharton.co.uk said :
  * "If you are going to use the 400A and 404.2 system [for ntp] I recommend
@@ -166,7 +167,7 @@ clockformat_t   clock_wharton_400a =
 };
 
 #else /* not (REFCLOCK && CLOCK_PARSE && CLOCK_WHARTON_400A) */
-int clk_wharton_400a_bs;
+NONEMPTY_TRANSLATION_UNIT
 #endif /* not (REFCLOCK && CLOCK_PARSE && CLOCK_WHARTON_400A) */
 
 /*
index d1108c9d14560d6da7ad1b8a95256022a634b0e7..0cc7fcb47ecd854c727eb81fbd6f8e828588ba30 100644 (file)
@@ -26,7 +26,6 @@
 #include "ntp_crypto.h"
 #include "ntp_assert.h"
 #include "ntp_leapsec.h"
-#include "ntp_md5.h"   /* provides OpenSSL digest API */
 #include "lib_strbuf.h"
 #include "timexsup.h"
 
index 0499c363393df6648b24d8a6e5ad5228bea30666..e76e4dce071106348410e6b664582dbdecafdbdd 100644 (file)
@@ -129,9 +129,6 @@ static int loop_started;    /* TRUE after LOOP_DRIFTINIT */
 static void rstclock (int, double); /* transition function */
 static double direct_freq(double); /* direct set frequency */
 static void set_freq(double);  /* set frequency */
-#ifndef PATH_MAX
-# define PATH_MAX MAX_PATH
-#endif
 static char relative_path[PATH_MAX + 1]; /* relative path per recursive make */
 static char *this_file = NULL;
 
index 5456c092aff8e16c82de6bfaa220e934ca3249db..7807ccc00b03d255facc2a830c64d6b3d9520048 100644 (file)
 #include "crypto.h"
 #include <ctype.h>
 #include "isc/string.h"
-#include "ntp_md5.h"
-
-#ifndef EVP_MAX_MD_SIZE
-# define EVP_MAX_MD_SIZE 32
-#endif
 
 struct key *key_ptr;
 size_t key_cnt = 0;
index 961dca042a9f7f6da87ac5467731f9f92d8b6275..4e75df20a9a3462b5fd00890c725401f73e86d52 100644 (file)
@@ -8,7 +8,6 @@
 #include <ntp_fp.h>
 #include <ntp.h>
 #include <ntp_stdlib.h>
-#include <ntp_md5.h>   /* provides OpenSSL digest API */
 #include "utilities.h"
 #include "sntp-opts.h"
 
index a1d37ecab2072b3aaea61bde8a2fe20607069295..43b72018e6b79cade4ab42742e8d009665bfdc0b 100644 (file)
@@ -8,10 +8,19 @@ std_unity_list =                                                      \
        $(abs_srcdir)/testconf.yml                                      \
        $(NULL)
 
+#
+# Note: the rules to generate run-c_filename.c from c_filename.c below
+#      use the gmake $< construct for the first prerequisite, which
+#      does not work on FreeBSD make.  Use gmake when adding a new
+#      test source file, and check in the resulting run-*.c.
+#
+
 run_unity =    ruby $(std_unity_list)
 
 EXTRA_DIST =                           \
        testconf.yml                    \
+       data/ntp.keys                   \
+       data/mills,david-03.jpg         \
        $(NULL)
 
 check_PROGRAMS =               \
@@ -26,6 +35,7 @@ check_PROGRAMS =              \
        test-calyearstart       \
        test-clocktime          \
        test-decodenetnum       \
+       test-digests            \
        test-hextoint           \
        test-hextolfp           \
        test-humandate          \
@@ -58,13 +68,13 @@ check_PROGRAMS =            \
        test-ymd2yd             \
        $(NULL)
 
-LDADD =                                        \
+LDADD =                                                \
        $(top_builddir)/sntp/unity/libunity.a   \
-       $(top_builddir)/libntp/libntp.a \
-       $(LDADD_LIBNTP)                 \
-       $(PTHREAD_LIBS)                 \
-       $(LDADD_NTP)                    \
-       $(LIBM)                         \
+       $(top_builddir)/libntp/libntp.a         \
+       $(LDADD_LIBNTP)                         \
+       $(PTHREAD_LIBS)                         \
+       $(LDADD_NTP)                            \
+       $(LIBM)                                 \
        $(NULL)
 
 AM_CFLAGS  = $(CFLAGS_NTP)
@@ -92,6 +102,7 @@ BUILT_SOURCES +=                     \
        $(srcdir)/run-calyearstart.c    \
        $(srcdir)/run-clocktime.c       \
        $(srcdir)/run-decodenetnum.c    \
+       $(srcdir)/run-digests.c         \
        $(srcdir)/run-hextoint.c        \
        $(srcdir)/run-hextolfp.c        \
        $(srcdir)/run-humandate.c       \
@@ -263,6 +274,22 @@ $(srcdir)/run-decodenetnum.c: $(srcdir)/decodenetnum.c $(std_unity_list)
 
 ###
 
+test_digests_SOURCES =         \
+       digests.c               \
+       run-digests.c           \
+       srcdir.c                \
+       $(NULL)
+
+$(srcdir)/run-digests.c: $(srcdir)/digests.c $(std_unity_list)
+       $(run_unity) $< $@
+
+BUILT_SOURCES += srcdir.c
+
+srcdir.c: Makefile
+       $(AM_V_GEN)echo 'const char srcdir[] = "$(srcdir)";' >$@
+
+###
+
 test_hextoint_SOURCES =                \
        hextoint.c              \
        run-hextoint.c          \
index 30cd07ea1e561058d8924bdd3368be2bd0f3c177..6c8c743fd7d2cb154aa71791de9e6310f6dcc08b 100644 (file)
@@ -28,7 +28,7 @@
 54 MDC2                3cb1d4633a460179a7c96aed6c6a9273c3c98af8
 55 RIPEMD160   6028ec169bfbe55ab61ffa7baa34b482020f0619
 56 SHA1                17d96a86eb9b9075f33e1c0a08bb2bb61e916e33
-57 SHAKE12     70da1a91030eb91836c1cf76cf67ddfd6b96fa91
+57 SHAKE128    70da1a91030eb91836c1cf76cf67ddfd6b96fa91
 58 SHA1                7ce5deea7569d7423d5e1b497c8eb3bfeff852d5        # unused so far
 59 SHA1                9fd568e8f371deae54a65bc50b52bbe1f6529589        # unused
 60 SHA1                ce85046978a4df8366e102c4f1267399bbc25737        # unused
diff --git a/tests/libntp/digests.c b/tests/libntp/digests.c
new file mode 100644 (file)
index 0000000..03e9ef1
--- /dev/null
@@ -0,0 +1,415 @@
+#include "config.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "unity.h"
+#include "ntp.h"
+#include "ntp_stdlib.h"
+
+/*
+ * tests/libntp/data/ntp.keys has two keys for each algorithm, 50 keyids apart.
+ * The first is 20 random ASCII chars, the 2nd 40 random hex values.
+ */
+#define HEX_KEYID_OFFSET       50
+
+/* in generated srcdir.c */
+extern const char srcdir[];
+
+/* needed by authtrust() */
+u_long                 current_time;
+
+static bool            setup;
+static u_int32 *       pkt;
+static size_t          pkt_sz;
+static u_char *                mac;
+
+/* helper routine */
+void dump_mac(keyid_t keyid, u_char *pmac, size_t octets);
+
+
+/* unity calls setUp before each test routine */
+void setUp(void);
+void
+setUp(void)
+{
+       static bool     done_once;
+       const char      msg_rel_fname[] =       "data/mills,david-03.jpg";
+       const char      keys_rel_fname[] =      "data/ntp.keys";
+       char            msg_fname[PATH_MAX];
+       char            keys_fname[PATH_MAX];
+       int             msgf;
+       int             result;
+       struct stat     msg_stat;
+       u_char *        msg;
+       size_t          msg_sz;
+       size_t          pad_sz;
+       ssize_t         octets;
+
+       if (done_once) {
+               return;
+       }
+       done_once = TRUE;
+
+       init_auth();
+
+       snprintf(keys_fname, sizeof(keys_fname), "%s/%s", srcdir,
+                keys_rel_fname);
+       if (! authreadkeys(keys_fname)) {
+               fprintf(stderr, "could not load keys %s\n", keys_fname);
+               return;
+       }
+
+       snprintf(msg_fname, sizeof(msg_fname), "%s/%s", srcdir, msg_rel_fname);
+       msgf = open(msg_fname, O_RDONLY);
+       if (msgf < 0) {
+               fprintf(stderr, "could not open msg file %s\n", msg_fname);
+               return;
+       }
+
+       result = fstat(msgf, &msg_stat);
+       if (result < 0) {
+               fprintf(stderr, "could not get msg file %s size\n", msg_fname);
+               return;
+       }
+
+       msg_sz = msg_stat.st_size;
+       /* round up to next multiple of 4 as needed by MD5authencrypt() */
+       pad_sz = sizeof(u_int32) - (msg_sz % sizeof(u_int32));
+       if (sizeof(u_int32) == pad_sz) {
+               pad_sz = 0;
+       }
+       /* allocate room for the message, key ID, and MAC */
+       msg = emalloc_zero(msg_sz + pad_sz + MAX_MAC_LEN);
+       octets = read(msgf, msg, msg_sz);
+       if (octets != msg_sz) {
+               fprintf(stderr, "could not read msg from file %s, %u != %u\n",
+                       msg_fname, (u_int)octets, (u_int)msg_sz);
+               return;
+       }
+       zero_mem(msg + msg_sz, pad_sz);
+       pkt_sz = msg_sz + pad_sz;
+       mac = (void *)((u_char *)msg + pkt_sz);
+       pkt = (void *)msg;
+
+       setup = TRUE;
+}
+
+/* reduce code duplication with an ugly macro */
+#define TEST_ONE_DIGEST(key, exp_sz, exp_mac)                          \
+do {                                                                   \
+       size_t res_sz;                                                  \
+                                                                       \
+       zero_mem(mac, MAX_MAC_LEN);                                     \
+       if (!auth_findkey(key)) {                                       \
+               TEST_IGNORE_MESSAGE("MAC unsupported on this system");  \
+               return;                                                 \
+       }                                                               \
+       authtrust((key), 1);                                            \
+                                                                       \
+       res_sz = authencrypt((key), pkt, pkt_sz);                       \
+       if (KEY_MAC_LEN == res_sz) {                                    \
+               TEST_IGNORE_MESSAGE("Likely OpenSSL 3 failed digest "   \
+                                   "init.");                           \
+               return;                                                 \
+       }                                                               \
+       TEST_ASSERT_EQUAL_UINT((u_int)((exp_sz) + KEY_MAC_LEN), res_sz);\
+       dump_mac((key), mac, res_sz);                                   \
+       TEST_ASSERT_EQUAL_HEX8_ARRAY((exp_mac), mac, MAX_MAC_LEN);      \
+} while (FALSE)
+
+
+#define AES128CMAC_KEYID       1
+#undef KEYID_A
+#define KEYID_A                        AES128CMAC_KEYID
+#undef DG_SZ
+#define DG_SZ                  16
+#undef KEYID_B
+#define KEYID_B                        (KEYID_A + HEX_KEYID_OFFSET)
+void test_Digest_AES128CMAC(void);
+void test_Digest_AES128CMAC(void)
+{
+#if defined(OPENSSL) && defined(ENABLE_CMAC)
+       u_char expectedA[MAX_MAC_LEN] =
+               { 
+                       0, 0, 0, KEYID_A,
+                       0x34, 0x5b, 0xcf, 0xa8,
+                       0x85, 0x6e, 0x9d, 0x01,
+                       0xeb, 0x81, 0x25, 0xc2,
+                       0xa4, 0xb8, 0x1b, 0xe0
+               };
+       u_char expectedB[MAX_MAC_LEN] =
+               {
+                       0, 0, 0, KEYID_B,
+                       0xd1, 0x04, 0x4e, 0xbf,
+                       0x79, 0x2d, 0x3a, 0x40,
+                       0xcd, 0xdc, 0x5a, 0x44,
+                       0xde, 0xe0, 0x0c, 0x84
+               };
+
+       TEST_ASSERT(setup);
+       TEST_ONE_DIGEST(KEYID_A, DG_SZ, expectedA);
+       TEST_ONE_DIGEST(KEYID_B, DG_SZ, expectedB);
+#else  /* ! (OPENSSL && ENABLE_CMAC) follows  */
+       TEST_IGNORE_MESSAGE("Skipping, no OPENSSL or not ENABLE_CMAC");
+#endif
+}
+
+
+#define MD4_KEYID              2
+#undef KEYID_A
+#define KEYID_A                        MD4_KEYID
+#undef DG_SZ
+#define DG_SZ                  16
+#undef KEYID_B
+#define KEYID_B                        (KEYID_A + HEX_KEYID_OFFSET)
+void test_Digest_MD4(void);
+void test_Digest_MD4(void)
+{
+#ifdef OPENSSL
+       u_char expectedA[MAX_MAC_LEN] =
+               {
+                       0, 0, 0, KEYID_A,
+                       0xf3, 0x39, 0x34, 0xca,
+                       0xe0, 0x48, 0x26, 0x0f,
+                       0x13, 0xca, 0x56, 0x9e,
+                       0xbc, 0x53, 0x9c, 0x66
+               };
+       u_char expectedB[MAX_MAC_LEN] =
+               {
+                       0, 0, 0, KEYID_B,
+                       0x5e, 0xe6, 0x81, 0xf2,
+                       0x57, 0x57, 0x8a, 0x2b,
+                       0xa8, 0x76, 0x8e, 0x7a,
+                       0xc4, 0xf4, 0x34, 0x7e
+               };
+
+       TEST_ASSERT(setup);
+       TEST_ONE_DIGEST(KEYID_A, DG_SZ, expectedA);
+       TEST_ONE_DIGEST(KEYID_B, DG_SZ, expectedB);
+#else  /* ! OPENSSL follows  */
+       TEST_IGNORE_MESSAGE("Skipping, no OPENSSL");
+#endif
+}
+
+
+#define MD5_KEYID              3
+#undef KEYID_A
+#define KEYID_A                        MD5_KEYID
+#undef DG_SZ
+#define DG_SZ                  16
+#undef KEYID_B
+#define KEYID_B                        (KEYID_A + HEX_KEYID_OFFSET)
+void test_Digest_MD5(void);
+void test_Digest_MD5(void)
+{
+       u_char expectedA[MAX_MAC_LEN] =
+               {
+                       0, 0, 0, KEYID_A,
+                       0xa6, 0x8d, 0x3a, 0xfe,
+                       0x52, 0xe5, 0xf7, 0xe9,
+                       0x4c, 0x97, 0x72, 0x16,
+                       0x7c, 0x28, 0x18, 0xaf
+               };
+       u_char expectedB[MAX_MAC_LEN] =
+               {
+                       0, 0, 0, KEYID_B,
+                       0xd4, 0x11, 0x2c, 0xc6,
+                       0x66, 0x74, 0x46, 0x8b,
+                       0x12, 0xb1, 0x8c, 0x49,
+                       0xb0, 0x06, 0xda, 0x34
+               };
+
+       TEST_ASSERT(setup);
+       TEST_ONE_DIGEST(KEYID_A, DG_SZ, expectedA);
+       TEST_ONE_DIGEST(KEYID_B, DG_SZ, expectedB);
+}
+
+
+#define MDC2_KEYID             4
+#undef KEYID_A
+#define KEYID_A                        MDC2_KEYID
+#undef DG_SZ
+#define DG_SZ                  16
+#undef KEYID_B
+#define KEYID_B                        (KEYID_A + HEX_KEYID_OFFSET)
+void test_Digest_MDC2(void);
+void test_Digest_MDC2(void)
+{
+#ifdef OPENSSL
+       u_char expectedA[MAX_MAC_LEN] =
+               {
+                       0, 0, 0, KEYID_A,
+                       0xa0, 0xfc, 0x18, 0xb6,
+                       0xea, 0xba, 0xa5, 0x27,
+                       0xc9, 0x64, 0x0e, 0x41,
+                       0x95, 0x90, 0x5d, 0xf5
+               };
+       u_char expectedB[MAX_MAC_LEN] =
+               {
+                       0, 0, 0, KEYID_B,
+                       0xe3, 0x2c, 0x1e, 0x64,
+                       0x7f, 0x85, 0x81, 0xe7,
+                       0x3b, 0xc3, 0x93, 0x5e,
+                       0xcd, 0x0e, 0x89, 0xeb
+               };
+
+       TEST_ASSERT(setup);
+       TEST_ONE_DIGEST(KEYID_A, DG_SZ, expectedA);
+       TEST_ONE_DIGEST(KEYID_B, DG_SZ, expectedB);
+#else  /* ! OPENSSL follows  */
+       TEST_IGNORE_MESSAGE("Skipping, no OPENSSL");
+#endif
+}
+
+
+#define RIPEMD160_KEYID                5
+#undef KEYID_A
+#define KEYID_A                        RIPEMD160_KEYID
+#undef DG_SZ
+#define DG_SZ                  20
+#undef KEYID_B
+#define KEYID_B                        (KEYID_A + HEX_KEYID_OFFSET)
+void test_Digest_RIPEMD160(void);
+void test_Digest_RIPEMD160(void)
+{
+#ifdef OPENSSL
+       u_char expectedA[MAX_MAC_LEN] =
+               { 
+                       0, 0, 0, KEYID_A,
+                       0x8c, 0x3e, 0x55, 0xbb,
+                       0xec, 0x7c, 0xf6, 0x30,
+                       0xef, 0xd1, 0x45, 0x8c,
+                       0xdd, 0x29, 0x32, 0x7e,
+                       0x04, 0x87, 0x6c, 0xd7
+               };
+       u_char expectedB[MAX_MAC_LEN] =
+               {
+                       0, 0, 0, KEYID_B,
+                       0x2d, 0x4a, 0x48, 0xdd,
+                       0x28, 0x02, 0xb4, 0x9d,
+                       0xe3, 0x6d, 0x1b, 0x90,
+                       0x2b, 0xc4, 0x3f, 0xe5,
+                       0x19, 0x60, 0x12, 0xbc
+               };
+
+       TEST_ASSERT(setup);
+       TEST_ONE_DIGEST(KEYID_A, DG_SZ, expectedA);
+       TEST_ONE_DIGEST(KEYID_B, DG_SZ, expectedB);
+#else  /* ! OPENSSL follows  */
+       TEST_IGNORE_MESSAGE("Skipping, no OPENSSL");
+#endif
+}
+
+
+#define SHA1_KEYID             6
+#undef KEYID_A
+#define KEYID_A                        SHA1_KEYID
+#undef DG_SZ
+#define DG_SZ                  20
+#undef KEYID_B
+#define KEYID_B                        (KEYID_A + HEX_KEYID_OFFSET)
+void test_Digest_SHA1(void);
+void test_Digest_SHA1(void)
+{
+#ifdef OPENSSL
+       u_char expectedA[MAX_MAC_LEN] =
+               {
+                       0, 0, 0, KEYID_A,
+                       0xe2, 0xc6, 0x17, 0x71,
+                       0x03, 0xc1, 0x85, 0x56,
+                       0x35, 0xc7, 0x4e, 0x75,
+                       0x79, 0x82, 0x9d, 0xcb,
+                       0x2d, 0x06, 0x0e, 0xfa
+               };
+       u_char expectedB[MAX_MAC_LEN] =
+               {
+                       0, 0, 0, KEYID_B,
+                       0x01, 0x16, 0x37, 0xb4,
+                       0xf5, 0x2d, 0xe0, 0x97,
+                       0xaf, 0xd8, 0x58, 0xf7,
+                       0xad, 0xb3, 0x7e, 0x38,
+                       0x86, 0x85, 0x78, 0x44
+               };
+
+       TEST_ASSERT(setup);
+       TEST_ONE_DIGEST(KEYID_A, DG_SZ, expectedA);
+       TEST_ONE_DIGEST(KEYID_B, DG_SZ, expectedB);
+#else  /* ! OPENSSL follows  */
+       TEST_IGNORE_MESSAGE("Skipping, no OPENSSL");
+#endif
+}
+
+
+#define SHAKE128_KEYID         7
+#undef KEYID_A
+#define KEYID_A                        SHAKE128_KEYID
+#undef DG_SZ
+#define DG_SZ                  16
+#undef KEYID_B
+#define KEYID_B                        (KEYID_A + HEX_KEYID_OFFSET)
+void test_Digest_SHAKE128(void);
+void test_Digest_SHAKE128(void)
+{
+#ifdef OPENSSL
+       u_char expectedA[MAX_MAC_LEN] =
+               {
+                       0, 0, 0, KEYID_A,
+                       0x5c, 0x0c, 0x1a, 0x85,
+                       0xad, 0x03, 0xb2, 0x9a,
+                       0xe4, 0x75, 0x37, 0x93,
+                       0xaa, 0xa6, 0xcd, 0x76
+               };
+       u_char expectedB[MAX_MAC_LEN] =
+               { 
+                       0, 0, 0, KEYID_B,
+                       0x07, 0x04, 0x63, 0xcc,
+                       0x46, 0xaf, 0xca, 0x00,
+                       0x7d, 0xd1, 0x5a, 0x39,
+                       0xfd, 0x34, 0xca, 0x10
+               };
+
+       TEST_ASSERT(setup);
+       TEST_ONE_DIGEST(KEYID_A, DG_SZ, expectedA);
+       TEST_ONE_DIGEST(KEYID_B, DG_SZ, expectedB);
+#else  /* ! OPENSSL follows  */
+       TEST_IGNORE_MESSAGE("Skipping, no OPENSSL");
+#endif
+}
+
+
+/*
+ * Dump a MAC in a form easy to cut and paste into the expected declaration.
+ */
+void dump_mac(
+       keyid_t         keyid,
+       u_char *        pmac,
+       size_t          octets
+       )
+{
+       char    dump[128];
+       size_t  dc = 0;
+       size_t  idx;
+
+       dc += snprintf(dump + dc, sizeof(dump) - dc, "digest with key %u { ", keyid);
+
+       for (idx = 0; idx < octets; idx++) {
+               if (10 == idx) {
+                       msyslog(LOG_DEBUG, "%s", dump);
+                       dc = 0;
+               }
+               if (dc < sizeof(dump)) {
+                       dc += snprintf(dump + dc, sizeof(dump) - dc,
+                                      "0x%02x, ", pmac[idx]);
+               }
+       }
+
+       if (dc < sizeof(dump)) {
+               dc += snprintf(dump + dc, sizeof(dump) - dc, "}");
+       }
+
+       msyslog(LOG_DEBUG, "%s", dump);
+}
+
diff --git a/tests/libntp/run-digests.c b/tests/libntp/run-digests.c
new file mode 100644 (file)
index 0000000..bcfe939
--- /dev/null
@@ -0,0 +1,80 @@
+/* AUTOGENERATED FILE. DO NOT EDIT. */
+
+//=======Test Runner Used To Run Each Test Below=====
+#define RUN_TEST(TestFunc, TestLineNum) \
+{ \
+  Unity.CurrentTestName = #TestFunc; \
+  Unity.CurrentTestLineNumber = TestLineNum; \
+  Unity.NumberOfTests++; \
+  if (TEST_PROTECT()) \
+  { \
+      setUp(); \
+      TestFunc(); \
+  } \
+  if (TEST_PROTECT() && !TEST_IS_IGNORED) \
+  { \
+    tearDown(); \
+  } \
+  UnityConcludeTest(); \
+}
+
+//=======Automagically Detected Files To Include=====
+#include "unity.h"
+#include <setjmp.h>
+#include <stdio.h>
+#include "config.h"
+#include "ntp.h"
+#include "ntp_stdlib.h"
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+//=======External Functions This Runner Calls=====
+extern void setUp(void);
+extern void tearDown(void);
+extern void test_Digest_AES128CMAC(void);
+extern void test_Digest_MD4(void);
+extern void test_Digest_MD5(void);
+extern void test_Digest_MDC2(void);
+extern void test_Digest_RIPEMD160(void);
+extern void test_Digest_SHA1(void);
+extern void test_Digest_SHAKE128(void);
+
+
+//=======Suite Setup=====
+static void suite_setup(void)
+{
+extern int change_iobufs(int);
+extern int change_logfile(const char*, int);
+change_iobufs(1);
+change_logfile("stderr", 0);
+}
+
+//=======Test Reset Option=====
+void resetTest(void);
+void resetTest(void)
+{
+  tearDown();
+  setUp();
+}
+
+char const *progname;
+
+
+//=======MAIN=====
+int main(int argc, char *argv[])
+{
+  progname = argv[0];
+  suite_setup();
+  UnityBegin("digests.c");
+  RUN_TEST(test_Digest_AES128CMAC, 121);
+  RUN_TEST(test_Digest_MD4, 180);
+  RUN_TEST(test_Digest_MD5, 239);
+  RUN_TEST(test_Digest_MDC2, 289);
+  RUN_TEST(test_Digest_RIPEMD160, 348);
+  RUN_TEST(test_Digest_SHA1, 407);
+  RUN_TEST(test_Digest_SHAKE128, 466);
+
+  return (UnityEnd());
+}