]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
[Bug 3689] Extension for MD5, SHA-1 and other keys
authorJuergen Perlinger <perlinger@ntp.org>
Mon, 19 Oct 2020 06:15:03 +0000 (08:15 +0200)
committerJuergen Perlinger <perlinger@ntp.org>
Mon, 19 Oct 2020 06:15:03 +0000 (08:15 +0200)
 - refactor decoding a passwd string / secret
 - have ntp{q,dc} use the same password decoding ntpd uses

bk: 5f8d2ee74IiW5oemnU69vB9LwoPlzA

ChangeLog
include/ntp_stdlib.h
libntp/authkeys.c
libntp/authreadkeys.c
libntp/authusekey.c

index eeceaa9f10cb57b56caf561eaab50a81ec861f63..7bb391137542e3e3ce8768dc4bd9b1c8730f37f6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+---
+* [Bug 3689] Extension for MD5, SHA-1 and other keys <perlinger@ntp.org>
+  - ntp{q,dc} now use the same password processing as ntpd does in the key
+    file, so havin a binary secret >= 11 bytes is possible for all keys.
+    (This is a different approach to the roblem than suggested)
+
 ---
 (4.2.8p15) 2020/06/23 Released by Harlan Stenn <stenn@ntp.org>
 
index 265aafa73ebc03cc7cb57dcc798c2c1e2d803405..873e9d90fa3461369f6770b94c84190cc62f4e41 100644 (file)
@@ -67,8 +67,13 @@ extern       int     xsbprintf(char**, char* const, char const*, ...) NTP_PRINTF(3, 4);
 typedef void (*ctrl_c_fn)(void);
 
 /* authkeys.c */
+#define AUTHPWD_UNSPEC 0
+#define AUTHPWD_PLAIN  1
+#define AUTHPWD_HEX    2
+
 extern void    auth_delkeys    (void);
 extern int     auth_havekey    (keyid_t);
+extern size_t  authdecodepw    (u_char *dst, size_t dstlen, const char *src, int fmt);
 extern int     authdecrypt     (keyid_t, u_int32 *, size_t, size_t);
 extern size_t  authencrypt     (keyid_t, u_int32 *, size_t);
 extern int     authhavekey     (keyid_t);
index 7c1cbb0655ae229cb770a0eb56290d8dec08acd7..bf9628b738d87a00cbd40055ac166046b0c51053 100644 (file)
@@ -927,3 +927,95 @@ authdecrypt(
                              cache_secret, cache_secretsize,
                              pkt, length, size);
 }
+
+/* password decoding helpers */
+static size_t
+pwdecode_plain(
+       u_char *        dst,
+       size_t          dstlen,
+       const char *    src
+       )
+{
+       size_t          srclen = strlen(src);
+       if (srclen > dstlen) {
+               errno = ENOMEM;
+               return (size_t)-1;
+       }
+       memcpy(dst, src, srclen);
+       return srclen;
+}
+
+static size_t
+pwdecode_hex(
+       u_char *        dst,
+       size_t          dstlen,
+       const char *    src
+       )
+{
+       static const char hex[] = "00112233445566778899AaBbCcDdEeFf";
+       
+       size_t          srclen = strlen(src);
+       size_t          reslen = (srclen >> 1) + (srclen & 1);
+       u_char          tmp;
+       char            *ptr;
+       size_t          j;
+
+       if (reslen > dstlen) {
+               errno = ENOMEM;
+               reslen = (size_t)-1;
+       } else {        
+               for (j = 0; j < srclen; ++j) {
+                       tmp = *(const unsigned char*)(src + j);
+                       ptr = strchr(hex, tmp);
+                       if (ptr == NULL) {
+                               errno = EINVAL;
+                               reslen = (size_t)-1;
+                               break;
+                       }
+                       tmp = (u_char)((ptr - hex) > 1);
+                       if (j & 1)
+                               dst[j >> 1] |= tmp;
+                       else
+                               dst[j >> 1] = tmp << 4;
+               }
+       }
+       return reslen;
+}
+/*
+ * authdecodepw - decode plaintext or hex-encoded password to binary
+ * secret.  Returns size of secret in bytes or -1 on error.
+ */
+size_t
+authdecodepw(
+       u_char *        dst,
+       size_t          dstlen,
+       const char *    src,
+       int             fmt
+       )
+{
+       size_t          reslen;
+       
+       if ( !(dst && dstlen && src)) {
+               errno  = EINVAL;
+               reslen = (size_t)-1;
+       } else {
+               switch (fmt) {
+               case AUTHPWD_UNSPEC:
+                       if (strlen(src) <= 20)
+                               reslen = pwdecode_plain(dst, dstlen, src);
+                       else
+                               reslen = pwdecode_hex(dst, dstlen, src);
+                       break;
+               case AUTHPWD_PLAIN:
+                       reslen = pwdecode_plain(dst, dstlen, src);
+                       break;
+               case AUTHPWD_HEX:
+                       reslen = pwdecode_hex(dst, dstlen, src);
+                       break;
+               default:
+                       errno = EINVAL;
+                       reslen = (size_t)-1;
+               }
+       }
+       return reslen;
+}
index 48c5c4d5ec6eeed3a89213798ddca8c5826797f5..adf53beaea8023a2a470c61d2447185d107bf0ca 100644 (file)
@@ -38,7 +38,7 @@ nexttok(
         */
        while (*cp == ' ' || *cp == '\t')
                cp++;
-       
+
        /*
         * Save this and space to end of token
         */
@@ -46,19 +46,19 @@ nexttok(
        while (*cp != '\0' && *cp != '\n' && *cp != ' '
               && *cp != '\t' && *cp != '#')
                cp++;
-       
+
        /*
         * If token length is zero return an error, else set end of
         * token to zero and return start.
         */
        if (starttok == cp)
                return NULL;
-       
+
        if (*cp == ' ' || *cp == '\t')
                *cp++ = '\0';
        else
                *cp = '\0';
-       
+
        *str = cp;
        return starttok;
 }
@@ -114,7 +114,7 @@ free_keydata(
        )
 {
        KeyAccT *kap;
-       
+
        if (node) {
                while (node->keyacclist) {
                        kap = node->keyacclist;
@@ -142,9 +142,8 @@ authreadkeys(
        keyid_t keyno;
        int     keytype;
        char    buf[512];               /* lots of room for line */
-       u_char  keystr[32];             /* Bug 2537 */
+       u_char  keystr[64];             /* Bug 2537 */
        size_t  len;
-       size_t  j;
        u_int   nerr;
        KeyDataT *list = NULL;
        KeyDataT *next = NULL;
@@ -172,7 +171,7 @@ authreadkeys(
                token = nexttok(&line);
                if (token == NULL)
                        continue;
-               
+
                /*
                 * First is key number.  See if it is okay.
                 */
@@ -208,10 +207,10 @@ authreadkeys(
                 * have to process the line completely and have to
                 * finally throw away the result... This is a bit more
                 * work, but it also results in better error detection.
-                */ 
+                */
 #ifdef OPENSSL
                /*
-                * The key type is the NID used by the message digest 
+                * The key type is the NID used by the message digest
                 * algorithm. There are a number of inconsistencies in
                 * the OpenSSL database. We attempt to discover them
                 * here and prevent use of inconsistent data later.
@@ -258,45 +257,33 @@ authreadkeys(
                        continue;
                }
                next = NULL;
-               len = strlen(token);
-               if (len <= 20) {        /* Bug 2537 */
-                       next = emalloc(sizeof(KeyDataT) + len);
-                       next->keyacclist = NULL;
-                       next->keyid   = keyno;
-                       next->keytype = keytype;
-                       next->seclen  = len;
-                       memcpy(next->secbuf, token, len);
-               } else {
-                       static const char hex[] = "0123456789abcdef";
-                       u_char  temp;
-                       char    *ptr;
-                       size_t  jlim;
-
-                       jlim = min(len, 2 * sizeof(keystr));
-                       for (j = 0; j < jlim; j++) {
-                               ptr = strchr(hex, tolower((unsigned char)token[j]));
-                               if (ptr == NULL)
-                                       break;  /* abort decoding */
-                               temp = (u_char)(ptr - hex);
-                               if (j & 1)
-                                       keystr[j / 2] |= temp;
-                               else
-                                       keystr[j / 2] = temp << 4;
-                       }
-                       if (j < jlim) {
+               len = authdecodepw(keystr, sizeof(keystr), token, AUTHPWD_UNSPEC);
+               if (len > sizeof(keystr)) {
+                       switch (errno) {
+                       case ENOMEM:
+                               log_maybe(&nerr,
+                                         "authreadkeys: passwd too long for key %d",
+                                         keyno);
+                               break;
+                       case EINVAL:
                                log_maybe(&nerr,
-                                         "authreadkeys: invalid hex digit for key %d",
+                                         "authreadkeys: passwd has bad char for key %d",
                                          keyno);
-                               continue;
+                               break;
+                       default:
+                               log_maybe(&nerr,
+                                         "authreadkeys: unknown errno %d for key %d",
+                                         errno, keyno);
+                               break;
                        }
-                       len = jlim/2; /* hmmmm.... what about odd length?!? */
-                       next = emalloc(sizeof(KeyDataT) + len);
-                       next->keyacclist = NULL;
-                       next->keyid   = keyno;
-                       next->keytype = keytype;
-                       next->seclen  = len;
-                       memcpy(next->secbuf, keystr, len);
+                       continue;
                }
+               next = emalloc(sizeof(KeyDataT) + len);
+               next->keyacclist = NULL;
+               next->keyid   = keyno;
+               next->keytype = keytype;
+               next->seclen  = len;
+               memcpy(next->secbuf, keystr, len);
 
                token = nexttok(&line);
                if (token != NULL) {    /* A comma-separated IP access list */
@@ -369,7 +356,7 @@ authreadkeys(
                        next = NULL;
                        continue;
                }
-               
+
                INSIST(NULL != next);
                next->next = list;
                list = next;
index ff449d3df6fc9a0f504ed38839b390b7e143a5bd..abc762188057b615499e0393a6484aeb6412134e 100644 (file)
 #include "ntp_stdlib.h"
 
 /*
- * Types of ascii representations for keys.  "Standard" means a 64 bit
- * hex number in NBS format, i.e. with the low order bit of each byte
- * a parity bit.  "NTP" means a 64 bit key in NTP format, with the
- * high order bit of each byte a parity bit.  "Ascii" means a 1-to-8
- * character string whose ascii representation is used as the key.
+ * Only used by ntp{q,dc} to set the key/algo/secret triple to use.
+ * Uses the same decoding scheme ntpd uses for keys in the key file.
  */
 int
 authusekey(
@@ -24,11 +21,14 @@ authusekey(
        )
 {
        size_t  len;
-
-       len = strlen((const char *)str);
-       if (0 == len)
+       u_char  buf[64];
+       
+       len = authdecodepw(buf, sizeof(buf), (const char*)str,
+                          AUTHPWD_UNSPEC);
+       if (len < 1 || len > sizeof(buf))
                return 0;
-
-       MD5auth_setkey(keyno, keytype, str, len, NULL);
+       
+       MD5auth_setkey(keyno, keytype, buf, len, NULL);
+       memset(buf, 0, sizeof(buf));
        return 1;
 }