---
-* AES-128-CMAC support
+* [Bug 3441] Validate the assumption that AF_UNSPEC is 0. stenn@ntp.org
+* [Bug 3439] When running multiple commands / hosts in ntpq... <perlinger@ntp.org>
+ - applied patch by ggarvey
+* [Bug 3438] Negative values and values > 999 days in... <perlinger@ntp.org>
+ - applied patch by ggarvey (with minor mods)
+* [Bug 3437] ntpd tries to open socket with AF_UNSPEC domain
+ - applied patch (with mods) by Miroslav Lichvar <perlinger@ntp.org>
+* [Bug 3435] anchor NTP era alignment <perlinger@ntp.org>
+* [Bug 3430] ntpq dumps core (SIGSEGV) for "keytype md2"
+ - fixed several issues with hash algos in ntpd, sntp, ntpq,
+ ntpdc and the test suites <perlinger@ntp.org>
+* [Bug 3424] Trimble Thunderbolt 1024 week millenium bug <perlinger@ntp.org>
+ - initial patch by Daniel Pouzzner
+* [Bug 3423] QNX adjtime() implementation error checking is
+ wrong <perlinger@ntp.org>
+* [Bug 3417] ntpq ifstats packet counters can be negative
+ made IFSTATS counter quantities unsigned <perlinger@ntp.org>
+* [Bug 3411] problem about SIGN(6) packet handling for ntp-4.2.8p10
+ - raised receive buffer size to 1200 <perlinger@ntp.org>
+* [Bug 3408] refclock_jjy.c: Avoid a wrong report of the coverity static
+ analysis tool. <abe@ntp.org>
+* [Bug 3399] NTP: linker error in 4.2.8p10 during Linux cross-compilation
+ - initial patch by timeflies@mail2tor.com <perlinger@ntp.org>
+* [Bug 3398] tests fail with core dump <perlinger@ntp.org>
+ - patch contributed by Alexander Bluhm
+* [Bug 3397] ctl_putstr() asserts that data fits in its buffer
+ rework of formatting & data transfer stuff in 'ntp_control.c'
+ avoids unecessary buffers and size limitations. <perlinger@ntp.org>
+* [Bug 3394] Leap second deletion does not work on ntpd clients
+ - fixed handling of dynamic deletion w/o leap file <perlinger@ntp.org>
+* [Bug 3391] ntpd segfaults on startup due to small warmup thread stack size
+ - increased mimimum stack size to 32kB <perlinger@ntp.org>
+* [Bug 3367] Faulty LinuxPPS NMEA clock support in 4.2.8 <perlinger@ntp.org>
+ - reverted handling of PPS kernel consumer to 4.2.6 behavior
+* [Bug 3365] Updates driver40(-ja).html and miscopt.html <abe@ntp.org>
* [Bug 3358] Spurious KoD log messages in .INIT. phase. HStenn.
+* [Bug 3016] wrong error position reported for bad ":config pool"
+ - fixed location counter & ntpq output <perlinger@ntp.org>
+* [Bug 2737] Wrong phone number listed for USNO. ntp-bugs@bodosom.net,
+ perlinger@ntp.org
+* [Bug 2557] Fix Thunderbolt init. ntp-bugs@bodosom.net, perlinger@ntp.
+* [Bug 948] Trustedkey config directive leaks memory. <perlinger@ntp.org>
+* Use strlcpy() to copy strings, not memcpy(). HStenn.
+* Typos. HStenn.
+* test_ntp_scanner_LDADD needs ntpd/ntp_io.o. HStenn.
+* refclock_jjy.c: Add missing "%s" to an msyslog() call. HStenn.
+* Build ntpq and libntpq.a with NTP_HARD_*FLAGS. perlinger@ntp.org
+* Fix bug in the override portion of the compiler hardening macro. HStenn.
++* AES-128-CMAC support
---
(4.2.8p10) 2017/03/21 Released by Harlan Stenn <stenn@ntp.org>
EVP_DigestUpdate(ctx, key, cache_secretsize);
EVP_DigestUpdate(ctx, (u_char *)pkt, length);
EVP_DigestFinal(ctx, digest, &len);
+ #endif
EVP_MD_CTX_free(ctx);
+ #ifdef OPENSSL
+ }
+ #endif
/* If the MAC is longer than the MAX then truncate it. */
- if (len > MAX_MAC_LEN - 4)
- len = MAX_MAC_LEN - 4;
- memmove((u_char *)pkt + length + 4, digest, len);
- return (len + 4);
+ if (len > MAX_MDG_LEN)
+ len = MAX_MDG_LEN;
+ memmove((u_char *)pkt + length + KEY_MAC_LEN, digest, len);
+ return (len + KEY_MAC_LEN);
}
* was created.
*/
INIT_SSL();
- ctx = EVP_MD_CTX_new();
- if (!(ctx && EVP_DigestInit(ctx, EVP_get_digestbynid(type)))) {
- msyslog(LOG_ERR,
- "MAC decrypt: digest init failed");
- EVP_MD_CTX_free(ctx);
- return (0);
+ #ifdef OPENSSL
+ /* Check if CMAC key type specific code required */
+ if (cache_type == NID_cmac) {
+ CMAC_CTX * ctx;
+
+
+ if (debug) {
+ fprintf(stderr, "%s:%d:%s():%s:nid\n",
+ __FILE__, __LINE__, __func__, CMAC);
+ }
+
+ if (!(ctx = CMAC_CTX_new())) {
+ fprintf(stderr, "MAC decrypt: CMAC %s CTX new failed.\n", CMAC);
+ msyslog(LOG_ERR, "MAC decrypt: CMAC %s CTX new failed.", CMAC);
+ len = 0;
+ } else
+ if (!CMAC_Init(ctx, key, (u_int)AES_128_KEY_SIZE,
+ EVP_aes_128_cbc(), NULL)) {
+ fprintf(stderr, "MAC decrypt: CMAC %s Init failed.\n", CMAC);
+ msyslog(LOG_ERR, "MAC decrypt: CMAC %s Init failed.", CMAC);
+ len = 0;
+ } else
+ if (!CMAC_Update(ctx, (u_char *)pkt, (u_int)length)) {
+ fprintf(stderr, "MAC decrypt: CMAC %s Update failed.\n", CMAC);
+ msyslog(LOG_ERR, "MAC decrypt: CMAC %s Update failed.", CMAC);
+ len = 0;
+ } else
+ if (!CMAC_Final(ctx, digest, &len)) {
+ fprintf(stderr, "MAC decrypt: CMAC %s Final failed.\n", CMAC);
+ msyslog(LOG_ERR, "MAC decrypt: CMAC %s Final failed.", CMAC);
+ len = 0;
+ }
+
+ CMAC_CTX_cleanup(ctx);
+ } else { /* generic MAC handling */
+ #endif
+ EVP_MD_CTX * ctx;
+
+ if (!(ctx = EVP_MD_CTX_new())) {
+ fprintf(stderr, "MAC decrypt: MAC %s Digest CTX new failed.\n",
+ OBJ_nid2sn(type));
+ msyslog(LOG_ERR, "MAC decrypt: MAC %s Digest CTX new failed.",
+ OBJ_nid2sn(type));
+ len = 0;
+ }
+ #ifdef OPENSSL /* OpenSSL 1 supports return codes 0 fail, 1 okay */
+ else
+ if (!EVP_DigestInit(ctx, EVP_get_digestbynid(type))) {
+ fprintf(stderr, "MAC decrypt: MAC %s Digest Init failed.\n",
+ OBJ_nid2sn(type));
+ msyslog(LOG_ERR, "MAC decrypt: MAC %s Digest Init failed.",
+ OBJ_nid2sn(type));
+ len = 0;
+ } else
+ if (!EVP_DigestUpdate(ctx, key, (u_int)cache_secretsize)) {
+ fprintf(stderr, "MAC decrypt: MAC %s Digest Update key failed.\n",
+ OBJ_nid2sn(type));
+ msyslog(LOG_ERR, "MAC decrypt: MAC %s Digest Update key failed.",
+ OBJ_nid2sn(type));
+ len = 0;
+ } else
+ if (!EVP_DigestUpdate(ctx, (u_char *)pkt, (u_int)length)) {
+ fprintf(stderr, "MAC decrypt: MAC %s Digest Update data failed.\n",
+ OBJ_nid2sn(type));
+ msyslog(LOG_ERR, "MAC decrypt: MAC %s Digest Update data failed.",
+ OBJ_nid2sn(type));
+ len = 0;
+ } else
+ if (!EVP_DigestFinal(ctx, digest, &len)) {
+ fprintf(stderr, "MAC decrypt: MAC %s Digest Final failed.\n",
+ OBJ_nid2sn(type));
+ msyslog(LOG_ERR, "MAC decrypt: MAC %s Digest Final failed.",
+ OBJ_nid2sn(type));
+ len = 0;
+ }
+ #else /* !OPENSSL */
+ if (!(ctx && EVP_DigestInit(ctx, EVP_get_digestbynid(type)))) {
+ msyslog(LOG_ERR,
+ "MAC decrypt: digest init failed");
+ EVP_MD_CTX_free(ctx);
+ return (0);
+ }
+ EVP_DigestUpdate(ctx, key, cache_secretsize);
+ EVP_DigestUpdate(ctx, (u_char *)pkt, (u_int)length);
+ EVP_DigestFinal(ctx, digest, &len);
+ #endif
+ EVP_MD_CTX_free(ctx);
+ #ifdef OPENSSL
}
- EVP_DigestUpdate(ctx, key, cache_secretsize);
- EVP_DigestUpdate(ctx, (u_char *)pkt, length);
- EVP_DigestFinal(ctx, digest, &len);
- EVP_MD_CTX_free(ctx);
+ #endif
/* If the MAC is longer than the MAX then truncate it. */
- if (len > MAX_MAC_LEN - 4)
- len = MAX_MAC_LEN - 4;
- if (size != (size_t)len + 4) {
+ if (len > MAX_MDG_LEN)
+ len = MAX_MDG_LEN;
+ if (size != (size_t)len + KEY_MAC_LEN) {
msyslog(LOG_ERR,
"MAC decrypt: MAC length error");
return (0);
{
int key_type;
u_int digest_len;
-
- /*----------------------------------------------------------- */
-#ifdef OPENSSL
- const u_long max_digest_len = MAX_MAC_LEN - sizeof(keyid_t);
+#ifdef OPENSSL /* --*-- OpenSSL code --*-- */
- /*----------------------------------------------------------- */
-
char * upcased;
char * pch;
+ EVP_MD const * md;
/*
* OpenSSL digest short names are capitalized, so uppercase the
* digest name before passing to OBJ_sn2nid(). If it is not
- * recognized but begins with 'M' or 'm' use NID_md5 to be
- * consistent with past behavior.
+ * recognized but matches our CMAC string use NID_cmac, or if
- * it begins with 'M' use NID_md5 to be consistent with past
- * behavior.
++ * it begins with 'M' or 'm' use NID_md5 to be consistent with
++ * past behavior.
*/
INIT_SSL();
+
+ /* get name in uppercase */
LIB_GETBUF(upcased);
strlcpy(upcased, text, LIB_BUFLENGTH);
- for (pch = upcased; '\0' != *pch; ++pch)
+
+ for (pch = upcased; '\0' != *pch; pch++) {
*pch = (char)toupper((unsigned char)*pch);
+ }
- md = EVP_get_digestbyname(upcased);
- if (NULL == md && !strcmp(upcased, "M"))
- md = EVP_get_digestbyname("MD5");
- if (NULL == md)
- return 0;
+ key_type = OBJ_sn2nid(upcased);
- key_type = EVP_MD_type(md);
- digest_len = EVP_MD_size(md);
+ if (!key_type && !strncmp(CMAC, upcased, strlen(CMAC) + 1)) {
+ key_type = NID_cmac;
- /*----------------------------------------------------------- */
- #else /* --*-- NON-SSL CODE --*-- */
- /*----------------------------------------------------------- */
+ if (debug) {
+ fprintf(stderr, "%s:%d:%s():%s:key\n",
+ __FILE__, __LINE__, __func__, CMAC);
+ }
+ }
+ #else
+
- if ('m' == tolower((unsigned char)text[0]))
- key_type = NID_md5;
- else
- return 0;
+ key_type = 0;
+ #endif
- digest_len = 16;
+ if (!key_type && 'm' == tolower((unsigned char)text[0])) {
+ key_type = NID_md5;
+ }
- /*----------------------------------------------------------- */
- #endif /* --*-- NON-SSL CODE --*-- */
- /*----------------------------------------------------------- */
+ if (!key_type) {
+ return 0;
+ }
- if (pdigest_len)
+ if (NULL != pdigest_len) {
+ #ifdef OPENSSL
+ const EVP_MD * md = EVP_get_digestbynid(key_type);
+
+ digest_len = (md) ? EVP_MD_size(md) : 0;
+
+ if (!md || digest_len <= 0) {
+ if (key_type == NID_cmac) {
+ digest_len = CMAC_LENGTH;
+
+ if (debug) {
+ fprintf(stderr, "%s:%d:%s():%s:len\n",
+ __FILE__, __LINE__, __func__, CMAC);
+ }
+ } else {
+ fprintf(stderr,
+ "key type %s is not supported by OpenSSL\n",
+ keytype_name(key_type));
+ msyslog(LOG_ERR,
+ "key type %s is not supported by OpenSSL\n",
+ keytype_name(key_type));
+ return 0;
+ }
+ }
+
+ if (digest_len > max_digest_len) {
+ fprintf(stderr,
+ "key type %s %u octet digests are too big, max %lu\n",
+ keytype_name(key_type), digest_len,
+ max_digest_len);
+ msyslog(LOG_ERR,
+ "key type %s %u octet digests are too big, max %lu",
+ keytype_name(key_type), digest_len,
+ max_digest_len);
+ return 0;
+ }
+ #else
+ digest_len = MD5_LENGTH;
+ #endif
*pdigest_len = digest_len;
+ }
+
return key_type;
}
* Obtain list of digest names
*/
+#if defined(OPENSSL) && !defined(HAVE_EVP_MD_DO_ALL_SORTED)
+# if defined(_MSC_VER) && OPENSSL_VERSION_NUMBER >= 0x10100000L
+# define HAVE_EVP_MD_DO_ALL_SORTED
+# endif
+#endif
+
#ifdef OPENSSL
# ifdef HAVE_EVP_MD_DO_ALL_SORTED
+ # define K_PER_LINE 8
+ # define K_NL_PFX_STR "\n "
+ # define K_DELIM_STR ", "
+
struct hstate {
char *list;
const char **seen;
int idx;
};
- #define K_PER_LINE 8
- #define K_NL_PFX_STR "\n "
- #define K_DELIM_STR ", "
- static void list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg )
+
+
+ static void
+ list_md_fn(const EVP_MD *m, const char *from, const char *to, void *arg)
{
- size_t len, n;
- const char *name, *cp, **seen;
+ size_t len, n, digest_len;
+ const char *name, **seen;
struct hstate *hstate = arg;
- if (!m)
- return; /* Ignore aliases */
+ /* m is MD obj, from is name or alias, to is base name for alias */
+ if (!m || !from || to) {
+ return; /* Ignore aliases */
+ }
+
+ /* Discard MACs that NTP won't accept. */
+ /* Keep this consistent with keytype_from_text() in ssl_init.c. */
+ if (EVP_MD_size(m) > (MAX_MAC_LEN - sizeof(keyid_t))) {
+ return;
+ }
- /* There are duplicates. Discard if name has been seen.
- *
- * Names are capitalized in 'keytype_from_text()' in ssl_init.c; we
- * have to make sure we do compare case-insensitive when checking
- * for dupes...
- */
name = EVP_MD_name(m);
- len = strlen(name) + 1;
- for (seen = hstate->seen; *seen; seen++)
- if (!strcasecmp(*seen, name))
- return;
-
- /* Discard MACs that NTP won't accept.
- * Keep this consistent with keytype_from_text() in ssl_init.c,
- * which is done most easily by using it...
- */
- if (keytype_from_text(name, &digest_len) == 0)
+
+ /* Lowercase names aren't accepted by keytype_from_text in ssl_init.c */
+
+ for (cp = name; *cp; cp++) {
+ if (islower((unsigned char)*cp)) {
+ return;
+ }
+ }
+
+ len = (cp - name) + 1;
+
+ /* There are duplicates. Discard if name has been seen. */
+
+ for (seen = hstate->seen; *seen; seen++) {
+ if (!strcmp(*seen, name)) {
return;
+ }
+ }
n = (seen - hstate->seen) + 2;
hstate->seen = erealloc(hstate->seen, n * sizeof(*seen));
hstate->seen[n-2] = name;
hstate->seen[n-1] = NULL;
- if (hstate->list != NULL)
- len += strlen(hstate->list);
- len += (hstate->idx >= K_PER_LINE)? strlen(K_NL_PFX_STR): strlen(K_DELIM_STR);
+ if (hstate->list != NULL) {
+ len += strlen(hstate->list);
+ }
+
+ len += (hstate->idx >= K_PER_LINE)
+ ? strlen(K_NL_PFX_STR)
+ : strlen(K_DELIM_STR);
if (hstate->list == NULL) {
- hstate->list = (char *)emalloc(len);
- hstate->list[0] = '\0';
- hstate->list = (char *)emalloc(len);
++ hstate->list = (char *)emalloc(len);
+ hstate->list[0] = '\0';
} else {
- hstate->list = (char *)erealloc(hstate->list, len);
+ hstate->list = (char *)erealloc(hstate->list, len);
}
-
+
sprintf(hstate->list + strlen(hstate->list), "%s%s",
- ((hstate->idx >= K_PER_LINE)? K_NL_PFX_STR : K_DELIM_STR),
+ ((hstate->idx >= K_PER_LINE) ? K_NL_PFX_STR : K_DELIM_STR),
name);
- if (hstate->idx >= K_PER_LINE)
- hstate->idx = 1;
- else
- hstate->idx++;
+
+ if (hstate->idx >= K_PER_LINE) {
+ hstate->idx = 1;
+ } else {
+ hstate->idx++;
+ }
+ }
+
+
+ /* Insert CMAC into SSL digests list */
+ static char *
+ insert_cmac(char *list)
+ {
+ int insert;
+ size_t len;
+
+
+ /* If list empty, we need to insert CMAC on new line */
+ insert = (!list || !*list);
+
+ if (insert) {
+ len = strlen(K_NL_PFX_STR) + strlen(CMAC);
+ list = (char *)erealloc(list, len + 1);
+ sprintf(list, "%s%s", K_NL_PFX_STR, CMAC);
+ } else { /* List not empty */
+ /* Check if CMAC already in list - future proofing */
+ const char *cmac_sn;
+ char *cmac_p;
+
+ cmac_sn = OBJ_nid2sn(NID_cmac);
+ cmac_p = list;
+ insert = cmac_sn != NULL && *cmac_sn != '\0';
+
+ /* CMAC in list if found, followed by nul char or ',' */
+ while (insert && NULL != (cmac_p = strstr(cmac_p, cmac_sn))) {
+ cmac_p += strlen(cmac_sn);
+ /* Still need to insert if not nul and not ',' */
+ insert = *cmac_p && ',' != *cmac_p;
+ }
+
+ /* Find proper insertion point */
+ if (insert) {
+ char *last_nl;
+ char *point;
+ char *delim;
+ int found;
+
+ /* Default to start if list empty */
+ found = 0;
+ delim = list;
+ len = strlen(list);
+
+ /* While new lines */
+ while (delim < list + len && *delim &&
+ !strncmp(K_NL_PFX_STR, delim, strlen(K_NL_PFX_STR))) {
+ point = delim + strlen(K_NL_PFX_STR);
+
+ /* While digest names on line */
+ while (point < list + len && *point) {
+ /* Another digest after on same or next line? */
+ delim = strstr( point, K_DELIM_STR);
+ last_nl = strstr( point, K_NL_PFX_STR);
+
+ /* No - end of list */
+ if (!delim && !last_nl) {
+ delim = list + len;
+ } else
+ /* New line and no delim or before delim? */
+ if (last_nl && (!delim || last_nl < delim)) {
+ delim = last_nl;
+ }
+
+ /* Found insertion point where CMAC before entry? */
+ if (strncmp(CMAC, point, delim - point) < 0) {
+ found = 1;
+ break;
+ }
+
+ if (delim < list + len && *delim &&
+ !strncmp(K_DELIM_STR, delim, strlen(K_DELIM_STR))) {
+ point += strlen(K_DELIM_STR);
+ } else {
+ break;
+ }
+ } /* While digest names on line */
+ } /* While new lines */
+
+ /* If found in list */
+ if (found) {
+ /* insert cmac and delim */
+ /* Space for list could move - save offset */
+ ptrdiff_t p_offset = point - list;
+ len += strlen(CMAC) + strlen(K_DELIM_STR);
+ list = (char *)erealloc(list, len + 1);
+ point = list + p_offset;
+ /* move to handle src/dest overlap */
+ memmove(point + strlen(CMAC) + strlen(K_DELIM_STR),
+ point, strlen(point) + 1);
+ strncpy(point, CMAC, strlen(CMAC));
+ strncpy(point + strlen(CMAC), K_DELIM_STR, strlen(K_DELIM_STR));
+ } else { /* End of list */
+ /* append delim and cmac */
+ len += strlen(K_DELIM_STR) + strlen(CMAC);
+ list = (char *)erealloc(list, len + 1);
+ strcpy(list + strlen(list), K_DELIM_STR);
+ strcpy(list + strlen(list), CMAC);
+ }
+ } /* insert */
+ } /* List not empty */
+
+ return list;
}
# endif
#endif
if (octothorpe)
*octothorpe = '\0';
act = emalloc(sizeof(*act));
- scan_cnt = sscanf(kbuf, "%d %19s %128s", &act->key_id, act->typen, keystring);
+ /* keep width 15 = sizeof struct key.type - 1 synced */
+ scan_cnt = sscanf(kbuf, "%d %15s %128s",
+ &act->key_id, act->type, keystring);
if (scan_cnt == 3) {
int len = strlen(keystring);
+ goodline = 1; /* assume best for now */
if (len <= 20) {
act->key_len = len;
memcpy(act->key_seq, keystring, len + 1);