From gitlab at mg.gitlab.com Thu Sep 17 06:54:13 2026 From: gitlab at mg.gitlab.com (Hal Murray (@hal.murray)) Date: Thu, 17 Sep 2026 06:54:13 +0000 Subject: [Git][NTPsec/ntpsec][master] 6 commits: Add note for Alpine to HOWTO-OpenSSL Message-ID: <6aab8e9511bfd_38191fa435b5@gitlab-sidekiq-low-urgency-cpu-bound-v2-5775ff4797-p2tr9.mail> Hal Murray pushed to branch master at NTPsec / ntpsec Commits: c594931a by Hal Murray at 2026-09-01T15:10:38-07:00 Add note for Alpine to HOWTO-OpenSSL - - - - - f9403285 by Hal Murray at 2026-09-01T16:05:49-07:00 Cleanup NTS-KE server The internal calling sequence was pretty ugly, mostly due to passing around arguments to low level routines could provide error text that was printed by the top level routine so we could limit things to one log message per connection. This change adds a struct that holds "everything" so we only need to pass around one parameter. The code now passes all the tests in ntske-test from https://github.com/mlichvar/ntske-test This cleanup was the result of chasing #892 The bug was a typo in unreleased code that I was testing. It treated all unknown type codes as critical. chrony is using one so that broke working with chrony. https://chrony-project.org/doc/spec/nts-compliant-128gcm.html - - - - - df83f3c4 by Hal Murray at 2026-09-14T18:05:38-07:00 Fix for #899 First bug: The test for the length of CookiePlaceholders matching the length of the cookie was broken. It would accept 0 length placeholders if they came before the real cookie. Second bug: There was no limit on CookiePlaceholders. So if you sent a batch of CookiePlaceholders before the real cookie, it would try to send back a batch of cookies which may not fit. - - - - - c2777387 by Hal Murray at 2026-09-14T23:36:48-07:00 Fix derecation warning from OpenSSL 4.1.0-alpha1 ASN1_STRING_length => ASN1_STRING_get_length Also, turn on X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT which is used by my self-signed local testing. I (and others?) probably need to find the option to make this unnecessary. - - - - - 7cc07938 by Hal Murray at 2026-09-15T01:59:29-07:00 Fix #895 - - - - - 55f28be1 by Hal Murray at 2026-09-15T11:01:01-07:00 Add HMAC support for shared key authentication It's now one of the options for NIST's authenticated service. - - - - - 18 changed files: - HOWTO-OpenSSL - NEWS.adoc - docs/includes/ntp.keys-body.adoc - include/ntp_auth.h - include/ntpd.h - include/nts.h - libntp/authkeys.c - libntp/authreadkeys.c - libntp/macencrypt.c - libntp/ssl_init.c - ntpclients/ntpq.py - ntpd/ntp_control.c - ntpd/ntp_util.c - ntpd/nts_client.c - ntpd/nts_extens.c - ntpd/nts_server.c - tests/libntp/macencrypt.c - tests/ntpd/nts_server.c Changes: ===================================== HOWTO-OpenSSL ===================================== @@ -90,9 +90,9 @@ The above check is broken on Fedora Worked on 3.6.1, Fedora 43, 2026-Feb-01) It works on Debian, Ubuntu and FreeBSD. -time make test -j4 |& tee test.log -time make build_docs |& tee docs.log -sudo make install |& tee install.log +time make test -j4 |& tee test.log +time make build_docs -j4 |& tee docs.log +sudo make install |& tee install.log On Linux: sudo su @@ -102,6 +102,12 @@ On Linux: # running ldconfig before install doesn't work ldconfig +On Alpine (musl): + I couldn't get ldconfig work. This fixed it: + cd /etc/ld.so.conf.d + sudo ln -s /usr/local/ssl/lib/libcrypto.99 + sudo ln -s /usr/local/ssl/lib/libssl.99 + On FreeBSD: sudo ldconfig -m /usr/local/ssl/lib/ ?? You have to do this each time you boot ===================================== NEWS.adoc ===================================== @@ -12,6 +12,10 @@ on user-visible changes. == Repository Head +* Shared key authentication now supports HMAC mode. +It's one of the options for NIST's authenticated service. +https://www.nist.gov/pml/time-and-frequency-division/time-services/nist-authenticated-ntp-service + == 2026-07-30: 1.2.5 Note: Python 2 and OpenSSL 1.1.0 support will be removed in the next release. @@ -398,8 +402,9 @@ On this day in 1972 the first leap second is added to the UTC time system. == 2019-06-21: 1.1.4 == -NTS is now implemented. See .../devel/nts.adoc -https://tools.ietf.org/html/draft-ietf-ntp-using-nts-for-ntp +NTS is now implemented. +See RFC 8915 Network Time Security for the Network Time Protocol +https://datatracker.ietf.org/doc/rfc8915/ We thank Cisco for sponsoring the NTS development. ===================================== docs/includes/ntp.keys-body.adoc ===================================== @@ -23,26 +23,30 @@ where `keyno` is a positive integer (between 1 and 65535), The file does not need to be sorted by `keyno`. -`type` can be the name of any digest or cipher supported by your -OpenSSL package. Digests or CMACs longer than 20 bytes will be truncated. +Internally, there are 3 modes corresponding to 3 different 'types': Digest, CMAC, and HMAC. -You can get a list from `openssl list -digest-algorithms` or -`openssl list -cipher-algorithms`. -(As of Jan 2018, they lie. Be sure to try it. {ntpdman} will -print an error on startup if a selected type isn't supported.) - -AES-128 is recommended by RFC 8573. Most modern CPUs have hardware -support. +Digest mode computes the MAC (Message Authentication Code) by computing +the digest of the key prepended to the packet. You get digest mode by +specifying a `type` that is the name of a digest-algorithm that +OpenSSL supports. You can get a list from `openssl list -digest-algorithms`. +CMAC mode uses a cipher algorithm. You get CMAC mode by specifying +a 'type' that is the name of a cipher-algorithm that OpenSSL supports. +You can get a list from `openssl list -cipher-algorithms`. Only the +-CBC+ cipher modes are useful. The +-CBC+ is appended to the `type` internally. Do not include it in `type`. +HMAC mode uses a digest-algorithm. You get to HMAC mode by prepending `HMAC-` to the name of a digest-algorithm. + +MACs longer than 20 bytes will be truncated. + AES is an alias for AES-128. SHA-1 is an alias for SHA1. (NIST uses SHA-1. OpenSSL uses SHA1.) -Note that MD5 was deprecated by RFC 8573 in June of 2019. -+AES-128+ is currently preferred. Most modern CPUs have hardware +Note that MD5 was deprecated by RFC 8573 in June of 2019 which +recommends AES-CMAC as described in RFC 4493 as a replacement. ++AES-128+ is the appropriate `type`. Most modern CPUs have hardware support. Our code still supports MD5 for backwards compatibility. FIPS 140-2, FIPS 180-4, and/or FIPS 202 may restrict your choices. @@ -54,6 +58,8 @@ Keys longer than 20 characters are assumed to be hex. The max length of a (de-hexified) key is 32 bytes. If you want to use an ASCII key longer than 20 bytes, you must hexify it. +Digest (and HMAC-) keys can be any length. CMAC keys will be truncated or padded to match what the cipher-algorithm requires. + Note that the keys used by the {ntpqman} programs are checked against passwords entered by hand, so it is generally appropriate to specify these keys in ASCII format. Or you can ===================================== include/ntp_auth.h ===================================== @@ -6,7 +6,7 @@ #include -typedef enum {AUTH_NONE, AUTH_CMAC, AUTH_DIGEST} AUTH_Type; +typedef enum {AUTH_NONE, AUTH_DIGEST, AUTH_CMAC, AUTH_HMAC} AUTH_Type; /* * Structure to store auth data in the hash table. @@ -23,7 +23,8 @@ struct auth_data { unsigned short key_size; /* secret length */ const EVP_MD * digest; /* Digest mode only */ #if OPENSSL_VERSION_NUMBER > 0x20000000L - EVP_MAC_CTX *mac_ctx; /* EVP CMAC mode only */ + EVP_MAC_CTX *cmac_ctx; /* EVP CMAC mode */ + EVP_MAC_CTX *hmac_ctx; /* EVP HMAC mode */ #else const EVP_CIPHER *cipher; /* Old CMAC mode only */ #endif @@ -50,6 +51,9 @@ extern int digest_encrypt (auth_info*, uint32_t *, int); extern bool cmac_decrypt (auth_info*, uint32_t *, int, int); extern int cmac_encrypt (auth_info*, uint32_t *, int); +extern bool hmac_decrypt (auth_info*, uint32_t *, int, int); +extern int hmac_encrypt (auth_info*, uint32_t *, int); + extern unsigned int authnumkeys; /* number of active keys */ extern unsigned int authnumfreekeys; /* number of free keys */ @@ -58,21 +62,23 @@ extern unsigned long authkeynotfound; /* keys not found */ extern unsigned long authencryptions; /* calls to authencrypt */ extern unsigned long authdigestencrypt;/* calls to digest_encrypt */ extern unsigned long authcmacencrypt; /* calls to cmac_encrypt */ +extern unsigned long authhmacencrypt; /* calls to hmac_encrypt */ extern unsigned long authdecryptions; /* calls to authdecrypt */ extern unsigned long authdigestdecrypt;/* calls to digest_decrypt */ extern unsigned long authdigestfail; /* fails from digest_decrypt */ extern unsigned long authcmacdecrypt; /* calls to cmac_decrypt*/ extern unsigned long authcmacfail; /* fails from cmac_decrypt*/ +extern unsigned long authhmacdecrypt; /* calls to hmac_decrypt*/ +extern unsigned long authhmacfail; /* fails from hmac_decrypt*/ extern uptime_t auth_timereset; /* current_time when stats reset */ #if OPENSSL_VERSION_NUMBER > 0x20000000L -extern EVP_MAC_CTX *evp_ctx; /* used by authreadkeys and authkeys */ +extern EVP_MAC_CTX *evpc_ctx; /* used by authreadkeys and authkeys */ +extern EVP_MAC_CTX *evph_ctx; /* used by authreadkeys and authkeys */ /* For testing */ -extern EVP_MAC_CTX* Setup_MAC_CTX(const char *name, uint8_t *key, int keylen); +extern EVP_MAC_CTX* Setup_CMAC_CTX(const char *name, uint8_t *key, int keylen); +extern EVP_MAC_CTX* Setup_HMAC_CTX(const char *name, uint8_t *key, int keylen); #endif -/* Not in CMAC API */ -#define CMAC_MAX_MAC_LENGTH 64 - #endif /* GUARD_AUTH_H */ ===================================== include/ntpd.h ===================================== @@ -265,6 +265,7 @@ typedef enum {NTSKE_OK, NTSKE_Failed, NTSKE_SSL_Failed} NTSKE_Status; extern void record_ntske_log( NTSKE_Status tag, const char* from, const char* msg, double wall, double usr, double sys, + int aead, const char* errbuf ); ===================================== include/nts.h ===================================== @@ -50,8 +50,19 @@ struct BufCtl_t { typedef struct BufCtl_t BufCtl; // Here for test routines -bool nts_ke_process_receive(struct BufCtl_t *buf, int *aead, - char *errbuf, int errlng, const char **errtxt); +enum process_result { + Process_OK, Process_Critical, Process_Error }; +struct NTS_Server_Info_t { + char hostaddr[100]; + int aead; + bool saw_aead, saw_next_protocol, next_protocol_matched; + const char *errtxt; // pointer to error text goes here + char errbuf[100]; // build it here if not simple constant + struct timespec start; // Usage info at start of work + double sys, usr; // CPU time +}; +typedef struct NTS_Server_Info_t NTS_Server_Info; +enum process_result nts_ke_process_receive(NTS_Server_Info *nsi, BufCtl *buf); // ********************************************************* ===================================== libntp/authkeys.c ===================================== @@ -62,11 +62,14 @@ unsigned long authkeynotfound; /* keys not found */ unsigned long authencryptions; /* calls to authencrypt */ unsigned long authdigestencrypt;/* calls to digest_encrypt */ unsigned long authcmacencrypt; /* calls to cmac_encrypt */ +unsigned long authhmacencrypt; /* calls to hmac_encrypt */ unsigned long authdecryptions; /* calls to authdecrypt */ unsigned long authdigestdecrypt;/* calls to digest_decrypt */ unsigned long authdigestfail; /* fails from digest_decrypt */ unsigned long authcmacdecrypt; /* calls to cmac_decrypt*/ unsigned long authcmacfail; /* fails from cmac_decrypt*/ +unsigned long authhmacdecrypt; /* calls to hmac_decrypt*/ +unsigned long authhmacfail; /* fails from hmac_decrypt*/ uptime_t auth_timereset; /* current_time when stats reset */ /* @@ -124,11 +127,14 @@ auth_reset_stats(uptime_t reset_time) authencryptions = 0; authdigestencrypt = 0; authcmacencrypt = 0; + authhmacencrypt = 0; authdecryptions = 0; authdigestdecrypt = 0; authdigestfail = 0; authcmacdecrypt = 0; authcmacfail = 0; + authhmacdecrypt = 0; + authhmacfail = 0; auth_timereset = reset_time; } @@ -302,29 +308,35 @@ alloc_auth_info( auth->flags = flags; auth->key_size = key_size; auth->key = key; - switch (type) { - case AUTH_NONE: - auth->digest = NULL; + // FIXME: Free stuff?? + auth->digest = NULL; #if OPENSSL_VERSION_NUMBER > 0x20000000L - auth->mac_ctx = NULL; + auth->cmac_ctx = NULL; + auth->hmac_ctx = NULL; #else - auth->cipher = NULL; + auth->cipher = NULL; #endif + switch (type) { + case AUTH_NONE: break; case AUTH_DIGEST: + // FIXME: should use EVP_MD_fetch auth->digest = EVP_get_digestbyname(name); + break; + case AUTH_CMAC: #if OPENSSL_VERSION_NUMBER > 0x20000000L - auth->mac_ctx = NULL; + auth->cmac_ctx = Setup_CMAC_CTX(name, + auth->key, auth->key_size); #else - auth->cipher = NULL; + auth->cipher = EVP_get_cipherbyname(name); #endif break; - case AUTH_CMAC: - auth->digest = NULL; + case AUTH_HMAC: #if OPENSSL_VERSION_NUMBER > 0x20000000L - auth->mac_ctx = Setup_MAC_CTX(name, auth->key, auth->key_size); + auth->hmac_ctx = Setup_HMAC_CTX(name, + auth->key, auth->key_size); #else - auth->cipher = EVP_get_cipherbyname(name); + auth->digest = EVP_get_digestbyname(name); #endif break; default: @@ -355,7 +367,7 @@ free_auth_info( auth->key = NULL; } #if OPENSSL_VERSION_NUMBER > 0x20000000L - EVP_MAC_CTX_free(auth->mac_ctx); + EVP_MAC_CTX_free(auth->cmac_ctx); #endif UNLINK_SLIST(unlinked, *bucket, auth, hlink, auth_info); //ENSURE(sk == unlinked); @@ -470,9 +482,9 @@ auth_setkey( auth->type = type; switch (type) { case AUTH_NONE: - auth->digest = NULL; #if OPENSSL_VERSION_NUMBER > 0x20000000L - auth->mac_ctx = NULL; + auth->cmac_ctx = NULL; + auth->hmac_ctx = NULL; #else auth->cipher = NULL; #endif @@ -480,16 +492,24 @@ auth_setkey( case AUTH_DIGEST: auth->digest = EVP_get_digestbyname(name); #if OPENSSL_VERSION_NUMBER > 0x20000000L - auth->mac_ctx = NULL; + auth->cmac_ctx = NULL; #else auth->cipher = NULL; #endif break; case AUTH_CMAC: - auth->digest = NULL; #if OPENSSL_VERSION_NUMBER > 0x20000000L - EVP_MAC_CTX_free(auth->mac_ctx); - auth->mac_ctx = Setup_MAC_CTX(name, \ + EVP_MAC_CTX_free(auth->cmac_ctx); + auth->cmac_ctx = Setup_CMAC_CTX(name, \ + auth->key, auth->key_size); +#else + auth->cipher = EVP_get_cipherbyname(name); +#endif + break; + case AUTH_HMAC: +#if OPENSSL_VERSION_NUMBER > 0x20000000L + EVP_MAC_CTX_free(auth->hmac_ctx); + auth->hmac_ctx = Setup_HMAC_CTX(name, \ auth->key, auth->key_size); #else auth->cipher = EVP_get_cipherbyname(name); @@ -513,6 +533,7 @@ auth_setkey( /* * Need to allocate new structure. Do it. */ +// FIXME Who owns memory for key?? newkey = emalloc(key_size); memcpy(newkey, key, key_size); alloc_auth_info(bucket, keyno, type, name, 0, @@ -553,7 +574,8 @@ auth_delkeys(void) auth->type = AUTH_NONE; auth->digest = NULL; #if OPENSSL_VERSION_NUMBER > 0x20000000L - auth->mac_ctx = NULL; + auth->cmac_ctx = NULL; + auth->hmac_ctx = NULL; #else auth->cipher = NULL; #endif @@ -590,6 +612,9 @@ authencrypt( case AUTH_CMAC: authcmacencrypt++; return cmac_encrypt(auth, pkt, length); + case AUTH_HMAC: + authhmacencrypt++; + return hmac_encrypt(auth, pkt, length); case AUTH_NONE: default: msyslog(LOG_ERR, "BUG: authencrypt: bogus type %u", auth->type); @@ -630,6 +655,11 @@ authdecrypt( answer = cmac_decrypt(auth, pkt, length, size); if (!answer) authcmacfail++; return answer; + case AUTH_HMAC: + authhmacdecrypt++; + answer = hmac_decrypt(auth, pkt, length, size); + if (!answer) authhmacfail++; + return answer; case AUTH_NONE: default: msyslog(LOG_ERR, "BUG: authdecrypt: bogus type %u", auth->type); @@ -640,15 +670,15 @@ authdecrypt( #if OPENSSL_VERSION_NUMBER > 0x20000000L /* Name needs "-CBC" already appended */ -EVP_MAC_CTX* Setup_MAC_CTX(const char *name, uint8_t *key, int keylen) { +EVP_MAC_CTX* Setup_CMAC_CTX(const char *name, uint8_t *key, int keylen) { OSSL_PARAM params[3]; char temp[100]; /* Hack: OSSL_PARAM doesn't like const */ - EVP_MAC_CTX *ctx = EVP_MAC_CTX_dup(evp_ctx); + EVP_MAC_CTX *ctx = EVP_MAC_CTX_dup(evpc_ctx); if (NULL == ctx) { unsigned long err = ERR_get_error(); char * str = ERR_error_string(err, NULL); - msyslog(LOG_ERR, "Setup_MAC_CTX: EVP_MAC_CTX_dup failed: %s", str); + msyslog(LOG_ERR, "Setup_CMAC_CTX: EVP_MAC_CTX_dup failed: %s", str); exit(1); } @@ -665,5 +695,31 @@ EVP_MAC_CTX* Setup_MAC_CTX(const char *name, uint8_t *key, int keylen) { } return ctx; } + +EVP_MAC_CTX* Setup_HMAC_CTX(const char *name, uint8_t *key, int keylen) { + OSSL_PARAM params[3]; + char temp[100]; /* Hack: OSSL_PARAM doesn't like const */ + + EVP_MAC_CTX *ctx = EVP_MAC_CTX_dup(evph_ctx); + if (NULL == ctx) { + unsigned long err = ERR_get_error(); + char * str = ERR_error_string(err, NULL); + msyslog(LOG_ERR, "Setup_HMAC_CTX: EVP_MAC_CTX_dup failed: %s", str); + exit(1); + } + + strlcpy(temp, name, sizeof(temp)); + params[0] = OSSL_PARAM_construct_utf8_string("digest", temp, 0); + params[1] = OSSL_PARAM_construct_octet_string("key", key, keylen); + params[2] = OSSL_PARAM_construct_end(); + if (0 == EVP_MAC_CTX_set_params(ctx, params)) { + unsigned long err = ERR_get_error(); + char * str = ERR_error_string(err, NULL); + msyslog(LOG_ERR, "EVP_MAC_CTX_set_params() failed: %s: %s.", + str, name); + exit(1); + } + return ctx; +} #endif ===================================== libntp/authreadkeys.c ===================================== @@ -28,6 +28,7 @@ #if OPENSSL_VERSION_NUMBER < 0x20000000L || defined(LIBRESSL_VERSION_NUMBER) #include +#include #endif #define NAMEBUFSIZE 100 @@ -82,6 +83,20 @@ nexttok( return starttok; } +static char* +try_hmac(const char *upcased, char* namebuf) { + if (0 != memcmp("HMAC-", upcased, 5)) { + return NULL; + } + strlcpy(namebuf, upcased+5, NAMEBUFSIZE); + if (0) msyslog(LOG_INFO, "DEBUG try_hmac: %s=>%s", upcased, namebuf); + if (EVP_get_digestbyname(namebuf) == NULL) { + return NULL; + } + /* FIXME: 3.0 needs a Fetch to be sure it really exists. */ + return namebuf; +} + static char* try_cmac(const char *upcased, char* namebuf) { strlcpy(namebuf, upcased, NAMEBUFSIZE); @@ -145,7 +160,7 @@ check_cmac_mac_length( keyid_t keyno, char *name) { size_t length = 0; - EVP_MAC_CTX *ctx = evp_ctx; + EVP_MAC_CTX *ctx = evpc_ctx; OSSL_PARAM params[2]; params[0] = OSSL_PARAM_construct_utf8_string("cipher", name, 0); @@ -159,10 +174,10 @@ check_cmac_mac_length( } length = EVP_MAC_CTX_get_mac_size(ctx); - /* CMAC_MAX_MAC_LENGTH isn't in the OpenSSL API + /* EVP_MAX_MD_SIZE isn't in the OpenSSL API * Check here to avoid buffer overrun in cmac_decrypt and cmac_encrypt */ - if (CMAC_MAX_MAC_LENGTH < length) { + if (EVP_MAX_MD_SIZE < length) { msyslog(LOG_ERR, "AUTH: authreadkeys: CMAC for key %u, %s is too big: %lu", keyno, name, (long unsigned int)length); @@ -178,7 +193,7 @@ static void check_cmac_mac_length( keyid_t keyno, char *name) { - unsigned char mac[CMAC_MAX_MAC_LENGTH+1024]; + unsigned char mac[EVP_MAX_MD_SIZE+1024]; size_t length = 0; char key[EVP_MAX_KEY_LENGTH]; /* garbage is OK */ CMAC_CTX *ctx; @@ -196,10 +211,10 @@ check_cmac_mac_length( CMAC_Final(ctx, mac, &length); CMAC_CTX_free(ctx); - /* CMAC_MAX_MAC_LENGTH isn't in API + /* EVP_MAX_MD_SIZE isn't in API * Check here to avoid buffer overrun in cmac_decrypt and cmac_encrypt */ - if (CMAC_MAX_MAC_LENGTH < length) { + if (EVP_MAX_MD_SIZE < length) { msyslog(LOG_ERR, "AUTH: authreadkeys: CMAC for key %u, %s is too big: %lu", keyno, name, (long unsigned int)length); @@ -212,6 +227,61 @@ check_cmac_mac_length( } #endif +#if OPENSSL_VERSION_NUMBER > 0x20000000L +static void +check_hmac_mac_length( + keyid_t keyno, + char *name) { + size_t length = 0; + EVP_MAC_CTX *ctx = evpc_ctx; + OSSL_PARAM params[2]; + + params[0] = OSSL_PARAM_construct_utf8_string("digest", name, 0); + params[1] = OSSL_PARAM_construct_end(); + if (0 == EVP_MAC_CTX_set_params(ctx, params)) { + unsigned long err = ERR_get_error(); + char * str = ERR_error_string(err, NULL); + msyslog(LOG_ERR, "EVP_MAC_CTX_set_params() failed: %s: %lu=>%s.\n", + str, (unsigned long)keyno, name); + exit(1); + } + length = EVP_MAC_CTX_get_mac_size(ctx); + + /* EVP_MAX_MD_SIZE should cover this. + * Check here to avoid buffer overrun in hmac_decrypt and hmac_encrypt + */ + if (EVP_MAX_MD_SIZE < length) { + msyslog(LOG_ERR, + "AUTH: authreadkeys: HMAC for key %u, %s is too big: %lu", + keyno, name, (long unsigned int)length); + exit(1); + } + + if (MAX_BARE_MAC_LENGTH < length) { + msyslog(LOG_ERR, "AUTH: authreadkeys: HMAC for key %u, %s will be truncated.", keyno, name); + } +} +#else +static void +check_hmac_mac_length( + keyid_t keyno, + char *name) { + + const EVP_MD *digest = EVP_get_digestbyname(name); + uint8_t pkt[100]; + uint8_t key[10]; + unsigned char answer[EVP_MAX_MD_SIZE]; + unsigned int length = 0; + unsigned char *result = HMAC(digest, + key, sizeof(key), pkt, sizeof(pkt), answer, &length); + if (NULL == result) return; /* error */ + + if (MAX_BARE_MAC_LENGTH < length) { + msyslog(LOG_ERR, "AUTH: authreadkeys: HMAC for key %u, %s will be truncated.", keyno, name); + } +} +#endif + /* check_mac_length - Check for CMAC/digest too long. * maybe should check for too short. */ @@ -222,11 +292,14 @@ check_mac_length( char *name, char *upcased) { switch (type) { + case AUTH_DIGEST: + check_digest_mac_length(keyno, name); + break; case AUTH_CMAC: check_cmac_mac_length(keyno, name); break; - case AUTH_DIGEST: - check_digest_mac_length(keyno, name); + case AUTH_HMAC: + check_hmac_mac_length(keyno, name); break; case AUTH_NONE: default: @@ -276,6 +349,7 @@ check_key_length( case AUTH_CMAC: length = check_cmac_key_length(keyno, name, key, keylength); break; + case AUTH_HMAC: case AUTH_DIGEST: /* any length key works */ break; @@ -388,6 +462,11 @@ msyslog(LOG_ERR, "AUTH: authreadkeys: reading %s", file); } name = NULL; + if (NULL == name) { + name = try_hmac(upcased, namebuf); + if (NULL != name) + type = AUTH_HMAC; + } if (NULL == name) { name = try_cmac(upcased, namebuf); if (NULL != name) ===================================== libntp/macencrypt.c ===================================== @@ -1,5 +1,5 @@ /* - * CMAC and digest support for NTP + * Digest, CMAC, and HMAC support for NTP shared keys */ /* Notes: @@ -8,12 +8,12 @@ * This is the working code that has to go fast. * The setup code in authreadkeys is not time critical. * - * There are 3 main options: MD5, SHA1, and AES. - * MD5 and SHA1 are digests. + * There are 3 main options: Digest, CMAC, and HMAC * https://en.wikipedia.org/wiki/Message_digest - * AES is a MAC. - * https://en.wikipedia.org/wiki/Message_authentication_code - * OpenSSL has different APIs for them. + * Digests make a hash of some data. + * For authentication, we make a hash of a secret key followed by the data. + * CMAC uses cipher functions such as AES. + * HMAC is a wrapper around digest functions. * * Before OpenSSL 3, we (and many others) used the undocumented * CMAC interface via openssl/cmac.h which is now (loudly) deprecated. @@ -32,7 +32,7 @@ * Just preloading the cipher will save a lot of memory if you * are using a lot of keys. The edit in this code is simple. * - * Play with attic/cmac-timing for numbers. + * Play with attic/{digest,cmac,hmac}-timing for numbers. * * * Modern CPUs come with support to speed up AES operations. @@ -66,6 +66,7 @@ extern EVP_MD_CTX *digest_ctx; #include #else #include +#include extern CMAC_CTX *cmac_ctx; #endif @@ -82,10 +83,10 @@ cmac_encrypt( int length /* packet length */ ) { - uint8_t mac[CMAC_MAX_MAC_LENGTH]; + uint8_t mac[EVP_MAX_MD_SIZE]; size_t len; #if OPENSSL_VERSION_NUMBER > 0x20000000L - EVP_MAC_CTX *ctx = auth->mac_ctx; + EVP_MAC_CTX *ctx = auth->cmac_ctx; #if OPENSSL_VERSION_NUMBER > 0x30000020L if (0 == EVP_MAC_init(ctx, NULL, 0, NULL)) { @@ -143,10 +144,10 @@ cmac_decrypt( int size /* MAC size */ ) { - uint8_t mac[CMAC_MAX_MAC_LENGTH]; + uint8_t mac[EVP_MAX_MD_SIZE]; size_t len; #if OPENSSL_VERSION_NUMBER > 0x20000000L - EVP_MAC_CTX *ctx = auth->mac_ctx; + EVP_MAC_CTX *ctx = auth->cmac_ctx; #if OPENSSL_VERSION_NUMBER > 0x30000020L if (0 == EVP_MAC_init(ctx, NULL, 0, NULL)) { @@ -200,6 +201,134 @@ cmac_decrypt( return !CRYPTO_memcmp(mac, (char *)pkt + length + 4, len); } +/* + * hmac_encrypt - generate HMAC authenticator + * + * Returns length of MAC including key ID and digest. + */ +int +hmac_encrypt( + auth_info* auth, + uint32_t *pkt, /* packet pointer */ + int length /* packet length */ + ) +{ + uint8_t mac[EVP_MAX_MD_SIZE]; +#if OPENSSL_VERSION_NUMBER > 0x20000000L + size_t len; + EVP_MAC_CTX *ctx = auth->hmac_ctx; + +#if OPENSSL_VERSION_NUMBER > 0x30000020L + if (0 == EVP_MAC_init(ctx, NULL, 0, NULL)) { +#else +// Bug in OpenSSL 3.0.2 +// Bug is in CMAC path. Don't know about HMAC. Be Safe. +// Need to reload key which is slow. See attic/hmac-timing + if (0 == EVP_MAC_init(ctx, auth->key, auth->key_size, NULL)) { +#endif + unsigned long err = ERR_get_error(); + char * str = ERR_error_string(err, NULL); + msyslog(LOG_ERR, "encrypt: EVP_MAC_init() failed: %s.", str); + exit(1); + } + if (0 == EVP_MAC_update(ctx, (unsigned char *)pkt, length)) { + unsigned long err = ERR_get_error(); + char * str = ERR_error_string(err, NULL); + msyslog(LOG_ERR, "encrypt: EVP_MAC_update() failed: %s.", str); + exit(1); + } + if (0 == EVP_MAC_final(ctx, mac, &len, sizeof(mac))) { + unsigned long err = ERR_get_error(); + char * str = ERR_error_string(err, NULL); + msyslog(LOG_ERR, "encrypt: EVP_MAC_final() failed: %s.", str); + exit(1); + } +#else + unsigned int len; + if (NULL == HMAC(auth->digest, auth->key, auth->key_size, + (unsigned char *)pkt, length, mac, &len)) { + unsigned long err = ERR_get_error(); + char * str = ERR_error_string(err, NULL); + msyslog(LOG_ERR, "encrypt: HMAC() failed: %s.", str); + exit(1); + } +#endif + if (MAX_BARE_MAC_LENGTH < len) + len = MAX_BARE_MAC_LENGTH; + memmove((uint8_t *)pkt + length + 4, mac, len); + return (int)(len + 4); +} + + +/* + * hmac_decrypt - verify HMAC authenticator + * + * Returns true if valid, false if invalid. + */ +bool +hmac_decrypt( + auth_info* auth, + uint32_t *pkt, /* packet pointer */ + int length, /* packet length */ + int size /* MAC size */ + ) +{ + uint8_t mac[EVP_MAX_MD_SIZE]; +#if OPENSSL_VERSION_NUMBER > 0x20000000L + size_t len; + EVP_MAC_CTX *ctx = auth->hmac_ctx; + +#if OPENSSL_VERSION_NUMBER > 0x30000020L + if (0 == EVP_MAC_init(ctx, NULL, 0, NULL)) { +#else +// Bug in OpenSSL 3.0.2 +// Need to reload key which is slow. See attic/hmac-timing + if (0 == EVP_MAC_init(ctx, auth->key, auth->key_size, NULL)) { +#endif + unsigned long err = ERR_get_error(); + char * str = ERR_error_string(err, NULL); + msyslog(LOG_ERR, "decrypt: EVP_MAC_init() failed: %s.", str); + return false; + } + if (0 == EVP_MAC_update(ctx, (unsigned char *)pkt, length)) { + unsigned long err = ERR_get_error(); + char * str = ERR_error_string(err, NULL); + msyslog(LOG_ERR, "decrypt: EVP_MAC_update() failed: %s.", str); + return false; + } + if (0 == EVP_MAC_final(ctx, mac, &len, sizeof(mac))) { + unsigned long err = ERR_get_error(); + char * str = ERR_error_string(err, NULL); + msyslog(LOG_ERR, "decrypt: EVP_MAC_final() failed: %s.", str); + return false; + } +#else + unsigned int len; + if (NULL == HMAC(auth->digest, auth->key, auth->key_size, + (unsigned char *)pkt, length, mac, &len)) { + unsigned long err = ERR_get_error(); + char * str = ERR_error_string(err, NULL); + msyslog(LOG_ERR, "decrypt: HMAC() failed: %s.", str); + return false; + } +#endif + if (MAX_BARE_MAC_LENGTH < len) + len = MAX_BARE_MAC_LENGTH; + + if ((unsigned int)size != len + 4) { + /* Beware of DoS attack. + * This indicates either the sender is broken + * or some admin fatfingered things. + * Similar code at digest_decrypt. + */ + if (0) msyslog(LOG_ERR, + "MAC: decrypt: MAC length error"); + return false; + } + return !CRYPTO_memcmp(mac, (char *)pkt + length + 4, len); +} + + /* * digest_encrypt - generate message digest * ===================================== libntp/ssl_init.c ===================================== @@ -18,18 +18,22 @@ #include #endif -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x20000000L || defined(LIBRESSL_VERSION_NUMBER) static void atexit_ssl_cleanup(void); #endif static bool ssl_init_done; EVP_MD_CTX *digest_ctx; #if OPENSSL_VERSION_NUMBER > 0x20000000L -EVP_MAC_CTX *evp_ctx; +EVP_MAC_CTX *evpc_ctx; +EVP_MAC_CTX *evph_ctx; #else CMAC_CTX *cmac_ctx; #endif +void ssl_init_cmac(void); +void ssl_init_hmac(void); + void ssl_init(void) { @@ -43,7 +47,9 @@ ssl_init(void) OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS|OPENSSL_INIT_LOAD_CRYPTO_STRINGS|OPENSSL_INIT_ADD_ALL_CIPHERS|OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); #endif -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +// Was 0x10100000L. Maybe HMAC() doesn't call init?? +// Similar changes in 2 other places for atexit_ssl_cleanup +#if OPENSSL_VERSION_NUMBER < 0x20000000L || defined(LIBRESSL_VERSION_NUMBER) OpenSSL_add_all_digests(); OpenSSL_add_all_ciphers(); atexit(&atexit_ssl_cleanup); @@ -54,6 +60,13 @@ ssl_init(void) ntp_RAND_bytes(&dummy, 1); digest_ctx = EVP_MD_CTX_new(); + ssl_init_cmac(); + ssl_init_hmac(); + + ssl_init_done = true; +} + +void ssl_init_cmac (void) { #if OPENSSL_VERSION_NUMBER > 0x20000000L { EVP_MAC *mac = EVP_MAC_fetch(NULL, "cmac", NULL); @@ -61,8 +74,8 @@ ssl_init(void) msyslog(LOG_ERR, "ssl_init: EVP_MAC_fetch failed"); exit(1); } - evp_ctx = EVP_MAC_CTX_new(mac); - if (NULL == evp_ctx) { + evpc_ctx = EVP_MAC_CTX_new(mac); + if (NULL == evpc_ctx) { msyslog(LOG_ERR, "ssl_init: EVP_MAC_CTX_new failed"); exit(1); } @@ -75,7 +88,7 @@ ssl_init(void) char key[16]; char copy[100]; /* OSSL_PARAM vs const */ - ctx = EVP_MAC_CTX_dup(evp_ctx); + ctx = EVP_MAC_CTX_dup(evpc_ctx); if (NULL != ctx ) { /* Was failing: 2023-feb-20, OpenSSL 3.0.8 */ unsigned long err = ERR_get_error(); @@ -87,28 +100,45 @@ ssl_init(void) params[0] = OSSL_PARAM_construct_utf8_string("cipher", copy, 0); params[1] = OSSL_PARAM_construct_octet_string("key", key, 16); params[2] = OSSL_PARAM_construct_end(); - if (0 == EVP_MAC_CTX_set_params(evp_ctx, params)) { + if (0 == EVP_MAC_CTX_set_params(evpc_ctx, params)) { unsigned long err = ERR_get_error(); char * str = ERR_error_string(err, NULL); - msyslog(LOG_ERR, "ssl_init: EVP_MAC_CTX_set_params() failed: %s", str); + msyslog(LOG_ERR, "ssl_init_cmac: EVP_MAC_CTX_set_params() failed: %s", str); } - ctx = EVP_MAC_CTX_dup(evp_ctx); + ctx = EVP_MAC_CTX_dup(evpc_ctx); if (NULL == ctx ) { unsigned long err = ERR_get_error(); char * str = ERR_error_string(err, NULL); - msyslog(LOG_ERR, "ssl_init: second dup failed: %s", str); + msyslog(LOG_ERR, "ssl_init_cmac: second dup failed: %s", str); } } #else cmac_ctx = CMAC_CTX_new(); #endif - ssl_init_done = true; } +void ssl_init_hmac (void) { +#if OPENSSL_VERSION_NUMBER > 0x20000000L + EVP_MAC *mac; + mac = EVP_MAC_fetch(NULL, "hmac", NULL); + if (NULL == mac) { + unsigned long err = ERR_get_error(); + char * str = ERR_error_string(err, NULL); + msyslog(LOG_ERR, "ssl_init_hmac: EVP_MAC_fetch failed: %s", str); + } + evph_ctx = EVP_MAC_CTX_new(mac); + if (NULL == evph_ctx) { + unsigned long err = ERR_get_error(); + char * str = ERR_error_string(err, NULL); + msyslog(LOG_ERR, "ssl_init_hmac: EVP_MAC_CTX_new failed: %s", str); + } + EVP_MAC_free(mac); +#endif +} -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x20000000L || defined(LIBRESSL_VERSION_NUMBER) static void atexit_ssl_cleanup(void) { ===================================== ntpclients/ntpq.py ===================================== @@ -1633,11 +1633,14 @@ usage: monstats ("authencrypts", "encryptions: ", NTP_PACKETS), ("authdigestencrypts", "digest encryptions: ", NTP_PACKETS), ("authcmacencrypts", "CMAC encryptions: ", NTP_PACKETS), + ("authhmacencrypts", "HMAC encryptions: ", NTP_PACKETS), ("authdecrypts", "decryptions: ", NTP_PACKETS), ("authdigestdecrypts", "digest decryptions: ", NTP_PACKETS), ("authdigestfails", "digest failures: ", NTP_PACKETS), ("authcmacdecrypts", "CMAC decryptions: ", NTP_PACKETS), ("authcmacfails", "CMAC failures: ", NTP_PACKETS), + ("authhmacdecrypts", "HMAC decryptions: ", NTP_PACKETS), + ("authhmacfails", "HMAC failures: ", NTP_PACKETS), # Old variables no longer supported. # Interesting if looking at an old system. ("authkuncached", "uncached keys: ", NTP_INT), ===================================== ntpd/ntp_control.c ===================================== @@ -376,11 +376,14 @@ static const struct var sys_var[] = { Var_uli("authencrypts", RO, authencryptions), Var_uli("authdigestencrypts", RO, authdigestencrypt), Var_uli("authcmacencrypts", RO, authcmacencrypt), + Var_uli("authhmacencrypts", RO, authhmacencrypt), Var_uli("authdecrypts", RO, authdecryptions), Var_uli("authdigestdecrypts", RO, authdigestdecrypt), Var_uli("authdigestfails", RO, authdigestfail), Var_uli("authcmacdecrypts", RO, authcmacdecrypt), Var_uli("authcmacfails", RO, authcmacfail), + Var_uli("authhmacdecrypts", RO, authhmacdecrypt), + Var_uli("authhmacfails", RO, authhmacfail), // kerninfo: Kernel timekeeping info Var_kli("koffset", RO|N_CLOCK|KNUToMS, ntx.offset), @@ -1637,6 +1640,8 @@ ctl_putpeer( break; case CP_SRCADR: + if (AF_UNSPEC == AF(&p->srcadr)) + break; // empty slot: pool, or no DNS yet ctl_putadr(CV_NAME, 0, &p->srcadr); break; ===================================== ntpd/ntp_util.c ===================================== @@ -813,6 +813,7 @@ void record_ntske_stats(void) { void record_ntske_log( NTSKE_Status tag, const char* from, const char* msg, double wall, double usr, double sys, + int aead, const char* errbuf ) { #ifndef DISABLE_NTS @@ -859,6 +860,9 @@ void record_ntske_log( if (errbuf) { used += snprintf(buffer+used, sizeof(buffer)-used, ", %s", errbuf); } + if (NTSKE_OK == tag) { + used += snprintf(buffer+used, sizeof(buffer)-used, ", AEAD=%d", aead); + } /* can't call timespec_to_MJDtime -- not main thread */ day = (unsigned long)now.tv_sec / SECSPERDAY + MJD_1970; sec = (unsigned long)now.tv_sec % SECSPERDAY; @@ -884,6 +888,7 @@ void record_ntske_log( UNUSED_ARG(wall); UNUSED_ARG(usr); UNUSED_ARG(sys); + UNUSED_ARG(aead); UNUSED_ARG(errbuf); #endif } ===================================== ntpd/nts_client.c ===================================== @@ -497,7 +497,7 @@ void set_hostname(SSL *ssl, const char *hostname) { * of wildcards to make it clear that they're permitted unless specifically * prohibited in an RFC */ - SSL_set_hostflags(ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); + SSL_set_hostflags(ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS | X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT); #if OPENSSL_VERSION_NUMBER >= 0x40000000L { sockaddr_u addr; @@ -555,7 +555,11 @@ bool check_certificate(SSL *ssl, struct peer* peer) { if (gen->type != GEN_DNS) continue; // string is NUL terminated but may have internal NULs +#if OPENSSL_VERSION_NUMBER >= 0x40100000L + len = (unsigned int)ASN1_STRING_get_length(gen->d.ia5); +#else len = (unsigned int)ASN1_STRING_length(gen->d.ia5); +#endif dnsname = (const char *)ASN1_STRING_get0_data(gen->d.ia5); if (0 != buff[0]) strlcat(buff, ", ", sizeof(buff)); ===================================== ntpd/nts_extens.c ===================================== @@ -117,6 +117,7 @@ int extens_client_send(struct peer *peer, struct pkt *xpkt) { return used; } +#define CookieLenUnknown -1 bool extens_server_recv(struct ntspacket_t *ntspacket, uint8_t *pkt, int lng) { struct BufCtl_t buf; uint16_t aead; @@ -130,7 +131,7 @@ bool extens_server_recv(struct ntspacket_t *ntspacket, uint8_t *pkt, int lng) { buf.left = lng-LEN_PKT_NOMAC; sawcookie = sawAEEF = false; - cookielen = 0; + cookielen = CookieLenUnknown; ntspacket->uidlen = 0; ntspacket->needed = 0; @@ -160,7 +161,7 @@ bool extens_server_recv(struct ntspacket_t *ntspacket, uint8_t *pkt, int lng) { if (sawcookie) { return false; /* second cookie */ } - if (0 == cookielen) { + if (CookieLenUnknown == cookielen) { cookielen = length; } else if (length != cookielen) { @@ -178,13 +179,16 @@ bool extens_server_recv(struct ntspacket_t *ntspacket, uint8_t *pkt, int lng) { ntspacket->aead = aead; break; case NTS_Cookie_Placeholder: - if (0 == cookielen) { + if (CookieLenUnknown == cookielen) { cookielen = length; } else if (length != cookielen) { return false; } ntspacket->needed++; + if (NTS_MAX_COOKIES < ntspacket->needed) { + return false; + } buf.next += length; buf.left -= length; break; @@ -200,8 +204,8 @@ bool extens_server_recv(struct ntspacket_t *ntspacket, uint8_t *pkt, int lng) { adlength = buf.next-NTP_EX_HDR_LNG-pkt; noncelen = next_uint16(&buf); cmaclen = next_uint16(&buf); - if (noncelen & 3) { - return false; /* would require padding */ + if (NONCE_LENGTH != noncelen) { + return false; } if (CMAC_LENGTH != cmaclen) { return false; ===================================== ntpd/nts_server.c ===================================== @@ -31,14 +31,12 @@ * enough for an IPv6 address. */ - static bool create_listener4(int port); static bool create_listener6(int port); static void* nts_ke_listener(void*); -static void nts_ke_request(SSL *ssl, - char *errbuf, int errlng, const char **errtxt); -static void nts_ke_accept_fail(char* hostname, - double wall, double usr, double sys, int code); +static void nts_ke_request(NTS_Server_Info *nsi, SSL *ssl); +static void nts_ke_accept_fail(NTS_Server_Info *nsi, + int code, const unsigned char *alpn); static void nts_lock_certlock(void); static void nts_unlock_certlock(void); @@ -48,9 +46,11 @@ static SSL_CTX *server_ctx = NULL; static int listener4_sock = -1; static int listener6_sock = -1; -static void nts_ke_setup_send(struct BufCtl_t *buf, int aead, +static void nts_ke_setup_send(BufCtl *buf, int aead, uint8_t *c2s, uint8_t *s2c, int keylen); +void log_ntske (NTS_Server_Info *nsi, NTSKE_Status status, const char *using); + /* We need a lock to protect reloading our certificate. * This seems like overkill, but it doesn't happen often. */ pthread_mutex_t certificate_lock = PTHREAD_MUTEX_INITIALIZER; @@ -191,26 +191,15 @@ void nts_unlock_certlock(void) { } } -// lfptod goes to long double -static inline double lfptox(l_fp r) { -// l_fp to double - return ldexp((double)((int64_t)r), -32); -} - void* nts_ke_listener(void* arg) { struct timeval timeout = {.tv_sec = NTS_KE_TIMEOUT, .tv_usec = 0}; int sock = *(int*)arg; char errbuf[100]; - char addrbuf[100]; char usingbuf[100]; - struct timespec start, finish; // wall clock - l_fp wall, usr, sys; - const char *errtxt; // not NULL if error + NTS_Server_Info nsi; + SSL *ssl; #ifdef RUSAGE_THREAD - // Not in NetBSD 10.1, 2026-Apr-05 - struct timespec start_u, finish_u; // CPU user - struct timespec start_s, finish_s; // CPU system struct rusage usage; #endif @@ -224,32 +213,34 @@ void* nts_ke_listener(void* arg) { * writing the previous msyslog message. */ getrusage(RUSAGE_THREAD, &usage); - start_u = tval_to_tspec(usage.ru_utime); - start_s = tval_to_tspec(usage.ru_stime); + nsi.usr = tspec_to_d(tval_to_tspec(usage.ru_utime)); + nsi.sys = tspec_to_d(tval_to_tspec(usage.ru_stime)); #else - usr = 0; - sys = 0; + nsi.usr = 0; + nsi.sys = 0; #endif while(1) { NTSKE_Status status = NTSKE_SSL_Failed; sockaddr_u addr; socklen_t len = sizeof(addr); - SSL *ssl; + const unsigned char *alpn; + unsigned alpnlen; int client, err; sleep(1); // FIXME: log clutter/DoS - errtxt = NULL; + nsi.errtxt = NULL; client = accept(sock, &addr.sa, &len); if (client < 0) { + // FIXME -- log with new code TCP ntp_strerror_r(errno, errbuf, sizeof(errbuf)); msyslog(LOG_ERR, "NTSs: TCP accept failed: %s", errbuf); if (EBADF == errno) return NULL; continue; } - clock_gettime(CLOCK_MONOTONIC, &start); - sockporttoa_r(&addr, addrbuf, sizeof(addrbuf)); + clock_gettime(CLOCK_MONOTONIC, &nsi.start); + sockporttoa_r(&addr, nsi.hostaddr, sizeof(nsi.hostaddr)); /* This is disabled in order to reduce clutter in the log file. * The client's address is now included in the final message. @@ -294,23 +285,12 @@ void* nts_ke_listener(void* arg) { SSL_set_fd(ssl, client); err = SSL_accept(ssl); - if (0 >= err) { + SSL_get0_alpn_selected(ssl, &alpn, &alpnlen); + if (0 >= err || NULL == alpn) { int code = SSL_get_error(ssl, err); SSL_free(ssl); close(client); - clock_gettime(CLOCK_MONOTONIC, &finish); - wall = tspec_intv_to_lfp(sub_tspec(finish, start)); -#ifdef RUSAGE_THREAD - getrusage(RUSAGE_THREAD, &usage); - finish_u = tval_to_tspec(usage.ru_utime); - finish_s = tval_to_tspec(usage.ru_stime); - usr = tspec_intv_to_lfp(sub_tspec(finish_u, start_u)); - sys = tspec_intv_to_lfp(sub_tspec(finish_s, start_s)); - start_u = finish_u; - start_s = finish_s; -#endif - nts_ke_accept_fail(addrbuf, - lfptox(wall), lfptox(usr), lfptox(sys), code); + nts_ke_accept_fail(&nsi, code, alpn); continue; } @@ -321,27 +301,14 @@ void* nts_ke_listener(void* arg) { SSL_get_cipher_bits(ssl, NULL)); status = NTSKE_Failed; - nts_ke_request(ssl, errbuf, sizeof(errbuf), &errtxt); - if (NULL==errtxt) status = NTSKE_OK; + nts_ke_request(&nsi, ssl); + if (NULL==nsi.errtxt) status = NTSKE_OK; SSL_shutdown(ssl); SSL_free(ssl); close(client); - clock_gettime(CLOCK_MONOTONIC, &finish); - wall = tspec_intv_to_lfp(sub_tspec(finish, start)); -#ifdef RUSAGE_THREAD - getrusage(RUSAGE_THREAD, &usage); - finish_u = tval_to_tspec(usage.ru_utime); - finish_s = tval_to_tspec(usage.ru_stime); - usr = tspec_intv_to_lfp(sub_tspec(finish_u, start_u)); - sys = tspec_intv_to_lfp(sub_tspec(finish_s, start_s)); - start_u = finish_u; - start_s = finish_s; -#endif - record_ntske_log(status, addrbuf, usingbuf, - lfptox(wall), lfptox(usr), lfptox(sys), - errtxt); + log_ntske(&nsi, status, usingbuf); } return NULL; @@ -351,14 +318,15 @@ void* nts_ke_listener(void* arg) { * print single error message for common cases. * Similar code in nts.c, nts_ssl_read() and nts_ssl_write() */ -void nts_ke_accept_fail(char* hostname, - double wall, double usr, double sys, int code) { +void nts_ke_accept_fail(NTS_Server_Info *nsi, + int code, const unsigned char *alpn) { unsigned long err = ERR_peek_error(); - char errbuf[100]; char buff[200]; const char *msg = NULL; - const char *errmsg = NULL; - if (0 == err) { + // NULL==alpn if client tries TLS 1.2 + if (SSL_ERROR_NONE == code && NULL == alpn) { + msg = "No valid ALPN"; + } else if (0 == err) { switch (code) { case SSL_ERROR_WANT_READ: msg = "Timeout"; @@ -370,9 +338,9 @@ void nts_ke_accept_fail(char* hostname, } // fall through default: - ntp_strerror_r(errno, errbuf, sizeof(errbuf)); + ntp_strerror_r(errno, nsi->errbuf, sizeof(nsi->errbuf)); snprintf(buff, sizeof(buff), "code %d, errno=>%d, %s", - code, errno, errbuf); + code, errno, nsi->errbuf); msg = buff; break; } @@ -382,58 +350,91 @@ void nts_ke_accept_fail(char* hostname, err = 0; } else { // Maybe we need to handle other codes - ntp_strerror_r(errno, errbuf, sizeof(errbuf)); + ntp_strerror_r(errno, nsi->errbuf, sizeof(nsi->errbuf)); snprintf(buff, sizeof(buff), "code %d, errno=>%d, %s, %lx=>%s", - code, errno, errbuf, err, ERR_reason_error_string(err)); + code, errno, nsi->errbuf, err, ERR_reason_error_string(err)); err = 0; msg = buff; } } - record_ntske_log(NTSKE_SSL_Failed, hostname, msg, - wall, usr, sys, errmsg); + log_ntske(nsi, NTSKE_SSL_Failed, msg); } -void nts_ke_request(SSL *ssl, - char *errbuf, int errlng, const char **errtxt) { +void nts_ke_request(NTS_Server_Info *nsi, SSL *ssl) { /* RFC 4: servers must accept 1024 * Our cookies can be 104, 136, or 168 for AES_SIV_CMAC_xxx * 8*168 fits comfortably into 2K. */ uint8_t buff[2048]; uint8_t c2s[NTS_MAX_KEYLEN], s2c[NTS_MAX_KEYLEN]; - int aead = NO_AEAD, keylen; - struct BufCtl_t buf; + int keylen; + BufCtl buf; int bytes_read, bytes_written; int used; + enum process_result result; - bytes_read = nts_ssl_read(ssl, buff, sizeof(buff), errtxt); + bytes_read = nts_ssl_read(ssl, buff, sizeof(buff), &nsi->errtxt); if (0 >= bytes_read) return; buf.next = buff; buf.left = bytes_read; - if (!nts_ke_process_receive(&buf, &aead, errbuf, errlng, errtxt)) { + result = nts_ke_process_receive(nsi, &buf); + if (Process_OK != result) { + buf.next = buff; + buf.left = sizeof(buff); + // Send what we can to show what worked to help debugging + if (nsi->saw_aead) { + if (NO_AEAD != nsi->aead) { + ke_append_record_uint16(&buf, nts_algorithm_negotiation, + nsi->aead); + } else { + ke_append_record_null(&buf, nts_algorithm_negotiation); + } + } + if (nsi->saw_next_protocol) { + if (nsi->next_protocol_matched) { + ke_append_record_uint16(&buf, + NTS_CRITICAL+nts_next_protocol_negotiation, + nts_protocol_NTP); + } else { + ke_append_record_null(&buf, + NTS_CRITICAL+nts_next_protocol_negotiation); + } + } + switch (result) { + case Process_Critical: + ke_append_record_uint16(&buf, NTS_CRITICAL+nts_error, + nts_unrecognized_critical_section); + break; + case Process_Error: + ke_append_record_uint16(&buf, NTS_CRITICAL+nts_error, + nts_bad_request); + break; + case Process_OK: // keep compiler happy + break; + default: + break; + } + ke_append_record_null(&buf, NTS_CRITICAL+nts_end_of_message); + used = sizeof(buff)-buf.left; + nts_ssl_write(ssl, buff, used, &nsi->errtxt); return; } - if ((NO_AEAD == aead) && (NULL != ntsconfig.aead)) - aead = nts_string_to_aead(ntsconfig.aead); - if (NO_AEAD == aead) - aead = AEAD_AES_SIV_CMAC_256; // default - - keylen = nts_get_key_length(aead); - if (!nts_make_keys(ssl, aead, c2s, s2c, keylen)) { - *errtxt = "Can't make keys"; + keylen = nts_get_key_length(nsi->aead); + if (!nts_make_keys(ssl, nsi->aead, c2s, s2c, keylen)) { + nsi->errtxt = "Can't make keys"; return; } buf.next = buff; buf.left = sizeof(buff); - nts_ke_setup_send(&buf, aead, c2s, s2c, keylen); + nts_ke_setup_send(&buf, nsi->aead, c2s, s2c, keylen); used = sizeof(buff)-buf.left; - bytes_written = nts_ssl_write(ssl, buff, used, errtxt); + bytes_written = nts_ssl_write(ssl, buff, used, &nsi->errtxt); if (bytes_written != used) return; @@ -542,19 +543,22 @@ bool create_listener6(int port) { return true; } -bool nts_ke_process_receive(struct BufCtl_t *buf, int *aead, - char *errbuf, int errlng, const char **errtxt) { +enum process_result nts_ke_process_receive(NTS_Server_Info *nsi, BufCtl *buf) { + nsi->aead = NO_AEAD; + nsi->saw_next_protocol = false; + nsi->next_protocol_matched = false; + nsi->saw_aead = false; while (buf->left >= NTS_KE_HDR_LNG) { uint16_t type, data; int length; bool critical = false; type = ke_next_record(buf, &length); if (length > buf->left) { - snprintf(errbuf, errlng, + snprintf(nsi->errbuf, sizeof(nsi->errbuf), "Chunk too big: 0x%x, %d, %d", type, buf->left, length); - *errtxt = errbuf; - return false; + nsi->errtxt = nsi->errbuf; + return Process_Error; } if (NTS_CRITICAL & type) { critical = true; @@ -565,73 +569,99 @@ bool nts_ke_process_receive(struct BufCtl_t *buf, int *aead, switch (type) { case nts_error: if (sizeof(data) != length) { - snprintf(errbuf, errlng, + snprintf(nsi->errbuf, sizeof(nsi->errbuf), "Wrong length on error: %d", length); - *errtxt = errbuf; - return false; + nsi->errtxt = nsi->errbuf; + return Process_Error; } data = next_uint16(buf); - snprintf(errbuf, errlng, + snprintf(nsi->errbuf, sizeof(nsi->errbuf), "Received error: %d", data); - *errtxt = errbuf; - return false; + nsi->errtxt = nsi->errbuf; + return Process_Error; case nts_next_protocol_negotiation: - if (sizeof(data) != length) { - snprintf(errbuf, errlng, - "NPN-Wrong length: %d", length); - *errtxt = errbuf; - return false; + if (nsi->saw_next_protocol) { + nsi->errtxt = "NPN Duplicate"; + return Process_Error; } - data = next_uint16(buf); - if (data != nts_protocol_NTP) { - snprintf(errbuf, errlng, - "NPN-Bad data: %d", data); - *errtxt = errbuf; - return false; + if (length % sizeof(uint16_t) > 0) { + snprintf(nsi->errbuf, sizeof(nsi->errbuf), + "NPN Wrong length: %d", length); + nsi->errtxt = nsi->errbuf; + return Process_Error; + } + nsi->saw_next_protocol = true; + for (int i=0; inext_protocol_matched = true; + } } break; case nts_algorithm_negotiation: + if (nsi->saw_aead) { + nsi->errtxt = "AEAD Duplicate"; + return Process_Error; + } if (length % sizeof(uint16_t) > 0) { - snprintf(errbuf, errlng, + snprintf(nsi->errbuf, sizeof(nsi->errbuf), "AN-Wrong length: %d", length); - *errtxt = errbuf; - return false; + nsi->errtxt = nsi->errbuf; + return Process_Error; } + nsi->saw_aead = true; for (int i=0; iaead != NO_AEAD) continue; // already got one - *aead = data; // take this one + nsi->aead = data; // take this one } break; case nts_end_of_message: if ((0 != length) || !critical) { - snprintf(errbuf, errlng, + snprintf(nsi->errbuf, sizeof(nsi->errbuf), "EOM-Wrong length or not Critical: %d, %d", length, critical); - *errtxt = errbuf; - return false; + nsi->errtxt = nsi->errbuf; + return Process_Error; } if (0 != buf->left) { - snprintf(errbuf, errlng, + snprintf(nsi->errbuf, sizeof(nsi->errbuf), "EOM not at end: %d", buf->left); - *errtxt = errbuf; - return false; + nsi->errtxt = nsi->errbuf; + return Process_Error; } - return true; + if (!nsi->saw_next_protocol) { + nsi->errtxt = "NPN Missing"; + return Process_Error; + } + if (!nsi->next_protocol_matched) { + nsi->errtxt = "NPN No match"; + return Process_Error; + } + if (!nsi->saw_aead) { + nsi->errtxt = "AEAD Missing"; + return Process_Error; + } + if (NO_AEAD == nsi->aead) { + nsi->errtxt = "AEAD No match"; + return Process_Error; + } + return Process_OK; default: if (critical) { // This only logs the first one from a connection - snprintf(errbuf, errlng, + snprintf(nsi->errbuf, sizeof(nsi->errbuf), "Received strange type: T=%d, C=%d, L=%d", type, critical, length); - // There is an error code for this - return false; + nsi->errtxt = nsi->errbuf; + return Process_Critical; } // It might be interesting to log non-critical // but that needs rate limiting @@ -646,16 +676,16 @@ bool nts_ke_process_receive(struct BufCtl_t *buf, int *aead, * should never happen. */ if (buf->left > 0) { - *errtxt = "*** Leftovers"; - return false; + nsi->errtxt = "Leftovers"; + return Process_Error; } - *errtxt = "*** Missing EOM"; - return false; + nsi->errtxt = "Missing EOM"; + return Process_Error; } -void nts_ke_setup_send(struct BufCtl_t *buf, int aead, +void nts_ke_setup_send(BufCtl *buf, int aead, uint8_t *c2s, uint8_t *s2c, int keylen) { // 4.1.2 Next Protocol @@ -678,4 +708,30 @@ void nts_ke_setup_send(struct BufCtl_t *buf, int aead, ke_append_record_null(buf, NTS_CRITICAL+nts_end_of_message); } +void log_ntske (NTS_Server_Info *nsi, NTSKE_Status status, const char *using) { + struct timespec finish; + double wall, usr, sys; +#ifdef RUSAGE_THREAD + struct rusage usage; + /* NB: nsi->usr and nsi->sys are from near the end of the previous cycle. + * Thus usage timing includes the TCP accept and + * writing the previous msyslog message. + */ + getrusage(RUSAGE_THREAD, &usage); + usr = tspec_to_d(tval_to_tspec(usage.ru_utime)); + sys = tspec_to_d(tval_to_tspec(usage.ru_stime)); +#else + usr = 0; + sys = 0; +#endif + clock_gettime(CLOCK_MONOTONIC, &finish); + wall = tspec_to_d(sub_tspec(finish, nsi->start)); + record_ntske_log(status, nsi->hostaddr, using, + wall, usr-nsi->usr, sys-nsi->sys, nsi->aead, nsi->errtxt); +#ifdef RUSAGE_THREAD + nsi->usr = usr; + nsi->sys = sys; +#endif +} + // end ===================================== tests/libntp/macencrypt.c ===================================== @@ -26,21 +26,26 @@ TEST_TEAR_DOWN(macencrypt) {} */ char MD5key[] = "abcdefgh"; char CMACkey[] = "0123456789abcdef"; /* AES-128 needs 16 bytes */ +char HMACkey[] = "0123456790abcdef"; const char *packet = "ijklmnopqrstuvwx"; const int packetLength = 16; const int keyIdLength = 4; const int digestLength = 16; +const int hmacLength = 20; /* Need #define to avoid VLA (variable length array) */ -#define totalLength 36 +#define totalDigestLength 36 +#define totalCMACLength 36 +#define totalHMACLength 40 char expectedMD5Packet[] = "ijklmnopqrstuvwx\0\0\0\0\x0c\x0e\x84\xcf\x0b\xb7\xa8\x68\x8e\x52\x38\xdb\xbc\x1c\x39\x53"; char expectedCMACPacket[] = "ijklmnopqrstuvwx\0\0\0\0\xb0\xa1\xcf\xd2\x7f\x69\x0c\x43\xa7\x5d\x6c\x55\x91\x4b\x15\x14"; +char expectedHMACPacket[] = "ijklmnopqrstuvwx\0\0\0\0\x3c\xcf\xfc\x85\x9b\x52\xb4\xcd\xc4\x3a\xfe\xbe\xe5\x27\xe0\x2e\xd6\x60\x46\xa6"; auth_info auth; -TEST(macencrypt, Encrypt) { - char packetPtr[totalLength]; +TEST(macencrypt, EncryptDigest) { + char packetPtr[totalDigestLength+20]; memset(packetPtr+packetLength, 0, (size_t)keyIdLength); memcpy(packetPtr, packet, (size_t)packetLength); @@ -53,7 +58,7 @@ TEST(macencrypt, Encrypt) { auth.digest = EVP_get_digestbyname("MD5"); #endif #if OPENSSL_VERSION_NUMBER > 0x20000000L - auth.mac_ctx = NULL; + auth.cmac_ctx = NULL; #else auth.cipher = NULL; #endif @@ -65,28 +70,28 @@ TEST(macencrypt, Encrypt) { int length = digest_encrypt(&auth, (uint32_t*)packetPtr, packetLength); - TEST_ASSERT_EQUAL(4+16, length); + TEST_ASSERT_EQUAL(4+16, length); /* MD5 */ TEST_ASSERT_TRUE(digest_decrypt(&auth, (uint32_t*)packetPtr, packetLength, length)); if (0) { printf("\n"); - for (int i = 0; i< totalLength; i++) { + for (int i = 0; i< totalDigestLength; i++) { printf("%02x ", (unsigned int)expectedMD5Packet[i] & 0xff); } printf("\n"); - for (int i = 0; i< totalLength; i++) { + for (int i = 0; i< totalDigestLength; i++) { printf("%02x ", (unsigned int)packetPtr[i] & 0xff); } printf("\n"); } - TEST_ASSERT_TRUE(memcmp(expectedMD5Packet, packetPtr, totalLength) == 0); + TEST_ASSERT_TRUE(memcmp(expectedMD5Packet, packetPtr, totalDigestLength) == 0); } TEST(macencrypt, CMAC_Encrypt) { - char packetPtr[totalLength]; + char packetPtr[totalCMACLength+20]; memset(packetPtr+packetLength, 0, (size_t)keyIdLength); memcpy(packetPtr, packet, (size_t)packetLength); @@ -97,8 +102,8 @@ TEST(macencrypt, CMAC_Encrypt) { auth.key = (uint8_t *)CMACkey; auth.key_size = (unsigned short)strlen(CMACkey); #if OPENSSL_VERSION_NUMBER > 0x20000000L - auth.mac_ctx = Setup_MAC_CTX("AES-128-CBC", auth.key, auth.key_size); - TEST_ASSERT_NOT_NULL(auth.mac_ctx); + auth.cmac_ctx = Setup_CMAC_CTX("AES-128-CBC", auth.key, auth.key_size); + TEST_ASSERT_NOT_NULL(auth.cmac_ctx); #else auth.cipher = EVP_get_cipherbyname("AES-128-CBC"); TEST_ASSERT_NOT_NULL(auth.cipher); @@ -114,20 +119,59 @@ TEST(macencrypt, CMAC_Encrypt) { if (0) { printf("\n"); - for (int i = 0; i< totalLength; i++) { + for (int i = 0; i< totalCMACLength; i++) { printf("%02x ", (unsigned int)expectedCMACPacket[i] & 0xff); } printf("\n"); - for (int i = 0; i< totalLength; i++) { + for (int i = 0; i< totalCMACLength; i++) { printf("%02x ", (unsigned int)packetPtr[i] & 0xff); } printf("\n"); } - TEST_ASSERT_TRUE(memcmp(expectedCMACPacket, packetPtr, totalLength) == 0); + TEST_ASSERT_TRUE(memcmp(expectedCMACPacket, packetPtr, totalCMACLength) == 0); +} + +TEST(macencrypt, EncryptHMAC) { + char packetPtr[totalHMACLength]; + memset(packetPtr+packetLength, 0, (size_t)keyIdLength); + memcpy(packetPtr, packet, (size_t)packetLength); + + auth.keyid = 1234; + auth.type = AUTH_HMAC; + auth.digest = NULL; + auth.key = (uint8_t *)HMACkey; + auth.key_size = (unsigned short)strlen(HMACkey); +#if OPENSSL_VERSION_NUMBER > 0x20000000L + auth.hmac_ctx = Setup_HMAC_CTX("SHA256", auth.key, auth.key_size); + TEST_ASSERT_NOT_NULL(auth.cmac_ctx); +#else + auth.digest = EVP_get_digestbyname("SHA256"); + TEST_ASSERT_NOT_NULL(auth.digest); +#endif + + int length = hmac_encrypt(&auth, + (uint32_t*)packetPtr, packetLength); + + TEST_ASSERT_EQUAL(4+20, length); /* SHA256 truncated */ + TEST_ASSERT_TRUE(hmac_decrypt(&auth, + (uint32_t*)packetPtr, packetLength, length)); + + if (1) { + printf("\nExpected: "); + for (int i = 0; i< totalHMACLength; i++) { + printf("%02x ", (unsigned int)expectedHMACPacket[i] & 0xff); + } + printf("\nFound: "); + for (int i = 0; i< totalHMACLength; i++) { + printf("%02x ", (unsigned int)packetPtr[i] & 0xff); + } + printf("\n"); + } + TEST_ASSERT_TRUE(memcmp(expectedHMACPacket, packetPtr, totalHMACLength) == 0); } -TEST(macencrypt, DecryptValid) { +TEST(macencrypt, DecryptValidDigest) { TEST_ASSERT_TRUE(digest_decrypt(&auth, (uint32_t*)expectedMD5Packet, packetLength, 20)); } @@ -137,7 +181,12 @@ TEST(macencrypt, DecryptValidCMAC) { (uint32_t*)expectedCMACPacket, packetLength, 20)); } -TEST(macencrypt, DecryptInvalid) { +TEST(macencrypt, DecryptValidHMAC) { + TEST_ASSERT_TRUE(hmac_decrypt(&auth, + (uint32_t*)expectedHMACPacket, packetLength, 24)); +} + +TEST(macencrypt, DecryptInvalidDigest) { char invalidPacket[] = "ijklmnopqrstuvwx\0\0\0\0\x0c\x0e\x84\xcf\x0b\xb7\xa8\x68\x8e\x52\x38\xdb\xbc\x1c\x39\x54"; TEST_ASSERT_FALSE(digest_decrypt(&auth, @@ -151,6 +200,13 @@ TEST(macencrypt, DecryptInvalidCMAC) { (uint32_t*)invalidPacket, packetLength, 20)); } +TEST(macencrypt, DecryptInvalidHMAC) { + char invalidPacket[] = "ijklmnopqrstuvwx\0\0\0\0\x0c\x0e\x84\xcf\x0b\xb7\xa8\x68\x8e\x52\x38\xdb\xbc\x1c\x39\x54"; + + TEST_ASSERT_FALSE(hmac_decrypt(&auth, + (uint32_t*)invalidPacket, packetLength, 24)); +} + TEST(macencrypt, IPv4AddressToRefId) { sockaddr_u addr; SET_AF(&addr, AF_INET); @@ -213,8 +269,8 @@ TEST(macencrypt, null_trunc) { auth.key_size = (unsigned short)strlen(CMACkey); #if OPENSSL_VERSION_NUMBER > 0x20000000L - auth.mac_ctx = Setup_MAC_CTX("AES-128-CBC", auth.key, auth.key_size); - TEST_ASSERT_NOT_NULL(auth.mac_ctx); + auth.cmac_ctx = Setup_CMAC_CTX("AES-128-CBC", auth.key, auth.key_size); + TEST_ASSERT_NOT_NULL(auth.cmac_ctx); #else auth.cipher = EVP_get_cipherbyname("AES-128-CBC"); TEST_ASSERT_NOT_NULL(auth.cipher); @@ -283,8 +339,8 @@ TEST(macencrypt, CMAC_TestVectors) { auth.key_size = (unsigned short)sizeof(key); #if OPENSSL_VERSION_NUMBER > 0x20000000L - auth.mac_ctx = Setup_MAC_CTX("AES-128-CBC", auth.key, auth.key_size); - TEST_ASSERT_NOT_NULL(auth.mac_ctx); + auth.cmac_ctx = Setup_CMAC_CTX("AES-128-CBC", auth.key, auth.key_size); + TEST_ASSERT_NOT_NULL(auth.cmac_ctx); #else auth.cipher = EVP_get_cipherbyname("AES-128-CBC"); TEST_ASSERT_NOT_NULL(auth.cipher); @@ -316,13 +372,15 @@ TEST(macencrypt, CMAC_TestVectors) { * Thus the tests must be run in the right order. */ TEST_GROUP_RUNNER(macencrypt) { - RUN_TEST_CASE(macencrypt, Encrypt); - RUN_TEST_CASE(macencrypt, DecryptValid); - RUN_TEST_CASE(macencrypt, DecryptInvalid); - RUN_TEST_CASE(macencrypt, CMAC_Encrypt); + RUN_TEST_CASE(macencrypt, EncryptDigest); + RUN_TEST_CASE(macencrypt, DecryptValidDigest); + RUN_TEST_CASE(macencrypt, DecryptInvalidDigest); RUN_TEST_CASE(macencrypt, CMAC_Encrypt); RUN_TEST_CASE(macencrypt, DecryptValidCMAC); RUN_TEST_CASE(macencrypt, DecryptInvalidCMAC); + RUN_TEST_CASE(macencrypt, EncryptHMAC); + RUN_TEST_CASE(macencrypt, DecryptValidHMAC); + RUN_TEST_CASE(macencrypt, DecryptInvalidHMAC); RUN_TEST_CASE(macencrypt, IPv4AddressToRefId); RUN_TEST_CASE(macencrypt, IPv6AddressToRefId); RUN_TEST_CASE(macencrypt, null_trunc); ===================================== tests/ntpd/nts_server.c ===================================== @@ -15,7 +15,7 @@ uint16_t extra_port = 0; void record_ntske_log( NTSKE_Status tag, const char* from, const char* using, double wall, double usr, double sys, - const char* errbuf + int aead, const char* errbuf ) { UNUSED_ARG(tag); UNUSED_ARG(from); @@ -23,6 +23,7 @@ void record_ntske_log( UNUSED_ARG(wall); UNUSED_ARG(usr); UNUSED_ARG(sys); + UNUSED_ARG(aead); UNUSED_ARG(errbuf); } @@ -34,11 +35,9 @@ TEST_TEAR_DOWN(nts_server) {} TEST(nts_server, nts_ke_process_receive) { /* General init */ - char errbuf[100]; - const char *errtxt = NULL; struct BufCtl_t buf; - int aead; - bool success; + NTS_Server_Info nsi; + enum process_result success; /* ===== Test: all correct ===== */ uint8_t buf0[] = { 0x80, nts_next_protocol_negotiation, 0, 2, 0x00, nts_protocol_NTP, @@ -47,12 +46,11 @@ TEST(nts_server, nts_ke_process_receive) { }; buf.next = buf0; buf.left = sizeof(buf0); - aead = NO_AEAD; + nsi.aead = NO_AEAD; /* test */ - success = nts_ke_process_receive(&buf, &aead, - errbuf, sizeof(errbuf), &errtxt); - TEST_ASSERT_EQUAL(true, success); - TEST_ASSERT_EQUAL_INT(AEAD_AES_SIV_CMAC_256, aead); + success = nts_ke_process_receive(&nsi, &buf); + TEST_ASSERT_EQUAL(Process_OK, success); + TEST_ASSERT_EQUAL_INT(AEAD_AES_SIV_CMAC_256, nsi.aead); /* ===== Test: nts_error ===== */ uint8_t buf1[] = { 0x80, nts_error, 0, 0, @@ -61,9 +59,9 @@ TEST(nts_server, nts_ke_process_receive) { buf.next = buf1; buf.left = sizeof(buf1); /* test */ - success = nts_ke_process_receive(&buf, &aead, - errbuf, sizeof(errbuf), &errtxt); - TEST_ASSERT_EQUAL(false, success); + success = nts_ke_process_receive(&nsi, &buf); + TEST_ASSERT_EQUAL(Process_Error, success); + /* ===== Test: nts_next_protocol_negotiation, bad length ===== */ uint8_t buf2[] = { 0x80, nts_next_protocol_negotiation, 0, 4, 0x11, 0x22, 0x33, 0x44, @@ -72,9 +70,9 @@ TEST(nts_server, nts_ke_process_receive) { buf.next = buf2; buf.left = sizeof(buf2); /* test */ - success = nts_ke_process_receive(&buf, &aead, - errbuf, sizeof(errbuf), &errtxt); - TEST_ASSERT_EQUAL(false, success); + success = nts_ke_process_receive(&nsi, &buf); + TEST_ASSERT_EQUAL(Process_Error, success); + /* ===== Test: nts_next_protocol_negotiation, bad protocol ===== */ uint8_t buf3[] = { 0x80, nts_next_protocol_negotiation, 0, 2, 0x11, 0x22, @@ -83,9 +81,9 @@ TEST(nts_server, nts_ke_process_receive) { buf.next = buf3; buf.left = sizeof(buf3); /* test */ - success = nts_ke_process_receive(&buf, &aead, - errbuf, sizeof(errbuf), &errtxt); - TEST_ASSERT_EQUAL(false, success); + success = nts_ke_process_receive(&nsi, &buf); + TEST_ASSERT_EQUAL(Process_Error, success); + /* ===== Test: nts_end_of_message, bad length ===== */ uint8_t buf4[] = { 0x80, nts_end_of_message, 0, 23, @@ -93,9 +91,9 @@ TEST(nts_server, nts_ke_process_receive) { buf.next = buf4; buf.left = sizeof(buf4); /* test */ - success = nts_ke_process_receive(&buf, &aead, - errbuf, sizeof(errbuf), &errtxt); - TEST_ASSERT_EQUAL(false, success); + success = nts_ke_process_receive(&nsi, &buf); + TEST_ASSERT_EQUAL(Process_Error, success); + /* ===== Test: nts_end_of_message, bad critical ===== */ uint8_t buf5[] = { 0x00, nts_end_of_message, 0, 0, @@ -103,9 +101,9 @@ TEST(nts_server, nts_ke_process_receive) { buf.next = buf5; buf.left = sizeof(buf5); /* test */ - success = nts_ke_process_receive(&buf, &aead, - errbuf, sizeof(errbuf), &errtxt); - TEST_ASSERT_EQUAL(false, success); + success = nts_ke_process_receive(&nsi, &buf); + TEST_ASSERT_EQUAL(Process_Error, success); + /* ===== Test: nts_end_of_message, remaining ===== */ uint8_t buf6[] = { 0x00, nts_end_of_message, 0, 0, @@ -114,9 +112,9 @@ TEST(nts_server, nts_ke_process_receive) { buf.next = buf6; buf.left = sizeof(buf6); /* test */ - success = nts_ke_process_receive(&buf, &aead, - errbuf, sizeof(errbuf), &errtxt); - TEST_ASSERT_EQUAL(false, success); + success = nts_ke_process_receive(&nsi, &buf); + TEST_ASSERT_EQUAL(Process_Error, success); + /* ===== Test: default, bad critical ===== */ uint8_t buf7[] = { 0x80, 0xFF, 0, 0, @@ -124,9 +122,8 @@ TEST(nts_server, nts_ke_process_receive) { buf.next = buf7; buf.left = sizeof(buf7); /* test */ - success = nts_ke_process_receive(&buf, &aead, - errbuf, sizeof(errbuf), &errtxt); - TEST_ASSERT_EQUAL(false, success); + success = nts_ke_process_receive(&nsi, &buf); + TEST_ASSERT_EQUAL(Process_Critical, success); } TEST_GROUP_RUNNER(nts_server) { View it on GitLab: https://gitlab.com/NTPsec/ntpsec/-/compare/ccee7465b6e0717ca2e1ed14d6342a2c5c9c7c76...55f28be16cffcca8576b12adca843b870993ed44 -- View it on GitLab: https://gitlab.com/NTPsec/ntpsec/-/compare/ccee7465b6e0717ca2e1ed14d6342a2c5c9c7c76...55f28be16cffcca8576b12adca843b870993ed44 You're receiving this email because of your account on gitlab.com. Manage all notifications: https://gitlab.com/-/profile/notifications | Help: https://gitlab.com/help -------------- next part -------------- An HTML attachment was scrubbed... URL: