]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
Many files:
authorHarlan Stenn <stenn@ntp.org>
Sat, 8 Apr 2000 04:06:57 +0000 (04:06 -0000)
committerHarlan Stenn <stenn@ntp.org>
Sat, 8 Apr 2000 04:06:57 +0000 (04:06 -0000)
  Dave improved the crypto stuff.

bk: 38eeb061Q05XHxfPGD5DD4ib41Evug

include/ntp.h
include/ntp_control.h
include/ntp_crypto.h
include/ntpd.h
ntpd/ntp_control.c
ntpd/ntp_crypto.c
ntpd/ntp_peer.c
ntpd/ntp_proto.c
ntpd/ntp_timer.c
ntpd/ntpd.c

index 87d2202fe25ced2f90348d1628f29561647a40d2..fcc003266aa2f0724c09b0dc9f885b9fee32ba36 100644 (file)
@@ -151,13 +151,38 @@ typedef char s_char;
 
 #ifdef AUTOKEY
 /*
- * THe autokey structure holds the data necessary to authenticate
+ * The autokey structure holds the data necessary to authenticate
  * the key IDs.
  */
-struct autokey {
+struct autokey {               /* network byte order */
+       u_int32 tstamp;         /* timestamp */
        keyid_t key;            /* key ID */
        int     seq;            /* key number */
-       u_int32 tstamp;         /* timestamp (s) */
+       u_int   siglen;         /* signature length */
+       u_char  *sig;           /* signature */
+};
+
+/*
+ * The cookie structure holds the current private value used to
+ * construct session keys.
+ */
+struct cookie {                        /* network byte order */
+       u_int32 tstamp;         /* timestamp */
+       keyid_t key;            /* key ID */
+       u_int   siglen;         /* signature length */
+       u_char  *sig;           /* signature */
+};
+
+/*
+ * The value structure holds variable length data such as host
+ * name and public value.
+ */
+struct value {                 /* network byte order */
+       u_int32 tstamp;         /* timestamp */
+       u_int   vallen;         /* value length */
+       u_char  *val;           /* value */
+       u_int   siglen;         /* signature length */
+       u_char  *sig;           /* signature */
 };
 #endif /* AUTOKEY */
 
@@ -256,17 +281,15 @@ struct peer {
 #ifdef PUBKEY
        u_char  *pubkey;        /* public key */
 #endif /* PUBKEY */
-#ifdef AUTOKEY
        keyid_t pkeyid;         /* previous key ID */
+#ifdef AUTOKEY
 #define clear_to_zero pkeyid
+#define crypto_to_zero pkeyid
        keyid_t hcookie;        /* host cookie */
-       keyid_t pcookie;        /* peer cookie */
-       int     recseq;         /* current key number */
+       struct cookie pcookie;  /* peer cookie */
        struct autokey recauto; /* autokey */
        u_int32 cmmd;           /* peer command */
        u_short assoc;          /* association ID of peer */
-       u_char  *dh_public;     /* Diffie-Hellman public value */
-       u_char  *dh_key;        /* Diffie-Hellman agreed key */
 
        /*
         * Variables used by authenticated server
@@ -274,20 +297,18 @@ struct peer {
        keyid_t *keylist;       /* session key ID list */
        int     keynumber;      /* current key number */
        struct autokey sndauto; /* autokey */
-#ifdef PUBKEY
-       u_char  *sign;          /* signature of keylist values */
-       u_int   signlen;        /* length of signature */
-#endif /* PUBKEY */
 #endif /* AUTOKEY */
 
        /*
         * Ephemeral state variables
         */
        u_int   valid;          /* valid update counter */
-       u_int   tailcnt;        /* tailgate poll counter */
-#ifndef AUTOKEY
+#ifdef AUTOKEY
+#define end_crypto_to_zero valid
+#else
 #define clear_to_zero valid
 #endif /* AUTOKEY */
+       u_int   tailcnt;        /* tailgate poll counter */
        u_char  status;         /* peer status */
        u_char  pollsw;         /* what it says */
        u_char  reach;          /* reachability register */
@@ -398,6 +419,11 @@ struct peer {
 #define        END_CLEAR_TO_ZERO(p)    ((char *)&((p)->end_clear_to_zero))
 #define        LEN_CLEAR_TO_ZERO       (END_CLEAR_TO_ZERO((struct peer *)0) \
                                    - CLEAR_TO_ZERO((struct peer *)0))
+#define CRYPTO_TO_ZERO(p)        ((char *)&((p)->clear_to_zero))
+#define END_CRYPTO_TO_ZERO(p)    ((char *)&((p)->end_clear_to_zero))
+#define LEN_CRYPTO_TO_ZERO       (END_CRYPTO_TO_ZERO((struct peer *)0) \
+                                   - CRYPTO_TO_ZERO((struct peer *)0))
+
 /*
  * Reference clock identifiers (for pps signal)
  */
index 864ce13eb63289ebae9017b96c76d6ebb8bc6d0b..b2084c8bbf09c870ee868406eb9f8fe2af618ab7 100644 (file)
@@ -167,7 +167,9 @@ struct ntp_control {
 #define        CS_PRIVATE      19
 #define CS_PUBLIC      20
 #define CS_DHPARAMS    21
-#define        CS_MAXCODE      CS_DHPARAMS
+#define        CS_HOSTNAM      22
+#define        CS_REVTIME      23
+#define        CS_MAXCODE      CS_REVTIME
 #else
 #define        CS_MAXCODE      CS_VARLIST
 #endif /* PUBKEY */
@@ -216,10 +218,9 @@ struct ntp_control {
 #define CP_PUBLIC      38
 #define        CP_SESKEY       39
 #define        CP_SASKEY       40
-#define        CP_AUTOSEQ      41
-#define        CP_INITSEQ      42
-#define        CP_INITKEY      43
-#define        CP_INITTSP      44
+#define        CP_INITSEQ      41
+#define        CP_INITKEY      42
+#define        CP_INITTSP      43
 #define        CP_MAXCODE      CP_INITTSP
 #else
 #define        CP_MAXCODE      CP_VARLIST
index 604b286b280c95b5baa444504d0370f4cb0cc746..afb4047a984b46c674e42e481a4fab18adb3b164 100644 (file)
@@ -29,6 +29,9 @@
 #define CRYPTO_FLAG_PUBL  0x01 /* read peer public key from file */
 
 #ifdef PUBKEY
+
+#define MAX_DH_LEN (DH_PRIME_LEN(1024)) /* max agreed key length */
+
 /*
  * Configuration codes
  */
@@ -51,12 +54,12 @@ extern      keyid_t session_key     P((struct sockaddr_in *, struct
                                    u_long));
 extern void    make_keylist    P((struct peer *));
 extern void    key_expire      P((struct peer *));
+extern void    crypto_agree    P((void));
 #ifdef PUBKEY
 extern void    crypto_init     P((void));
 extern void    crypto_config   P((int, char *));
 extern void    crypto_setup    P((void));
 extern int     crypto_public   P((struct peer *, u_char *));
-extern void    crypto_agree    P((void));
 
 /*
  * Cryptographic values
index 9535ad67b68fba2dcd521ea6266e4a5ff87b578e..d60f1445d2a0760e7df7bb4e838cc399f842eb32 100644 (file)
@@ -132,7 +132,8 @@ extern      struct peer *peer_config P((struct sockaddr_in *, struct interface *, int
 extern void    peer_reset      P((struct peer *));
 extern int     peer_unconfig   P((struct sockaddr_in *, struct interface *, int));
 extern void    unpeer          P((struct peer *));
-extern void    key_expire_all  P((void));
+extern void    clear_all       P((void));
+extern void    expire_all      P((void));
 extern struct  peer *findmanycastpeer  P((l_fp *));
 extern void    peer_config_manycast    P((struct peer *, struct peer *));
 
@@ -179,6 +180,11 @@ extern     void    hack_restrict   P((int, struct sockaddr_in *, struct sockaddr_in *, in
 extern void    init_timer      P((void));
 extern void    timer           P((void));
 extern void    timer_clr_stats P((void));
+#ifdef AUTOKEY
+extern char    *sys_hostname;
+extern u_int   sys_hostnamelen;
+extern l_fp    sys_revoketime;
+#endif /* AUTOKEY */
 
 /* ntp_util.c */
 extern void    init_util       P((void));
index a880c8b9a6aa3583536f07cd5c4a215d56dbc4a7..3b654d3b5d696ac50044dbe1acfde4735797de2c 100644 (file)
@@ -116,6 +116,8 @@ static struct ctl_var sys_var[] = {
        { CS_PRIVATE,   RO, "privatekey" },     /* 19 */
        { CS_PUBLIC,    RO, "publickey" },      /* 20 */
        { CS_DHPARAMS,  RO, "dhparams" },       /* 21 */
+       { CS_HOSTNAM,   RO, "hostname" },       /* 22 */
+       { CS_REVTIME,   RO, "revoketime"},      /* 23 */
 #endif /* PUBKEY */
        { 0,            EOV,    ""  }
 };
@@ -148,6 +150,8 @@ static      u_char def_sys_var[] = {
        CS_PRIVATE,
        CS_PUBLIC,
        CS_DHPARAMS,
+       CS_HOSTNAM,
+       CS_REVTIME,
 #endif /* PUBKEY */
        0
 };
@@ -199,10 +203,9 @@ static struct ctl_var peer_var[] = {
        { CP_PUBLIC,    RO, "publickey" },      /* 38 */
        { CP_SESKEY,    RO, "pcookie" },        /* 39 */
        { CP_SASKEY,    RO, "hcookie" },        /* 40 */
-       { CP_AUTOSEQ,   RO, "sequence" },       /* 41 */
-       { CP_INITSEQ,   RO, "initsequence" },   /* 42 */
-       { CP_INITKEY,   RO, "initkey" },        /* 43 */
-       { CP_INITTSP,   RO, "timestamp" },      /* 44 */
+       { CP_INITSEQ,   RO, "initsequence" },   /* 41 */
+       { CP_INITKEY,   RO, "initkey" },        /* 42 */
+       { CP_INITTSP,   RO, "timestamp" },      /* 43 */
 #endif /* PUBKEY */
        { 0,            EOV,    ""  }
 };
@@ -244,7 +247,7 @@ static u_char def_peer_var[] = {
 #ifdef PUBKEY
        CP_PUBLIC,
        CP_SESKEY,
-       CP_AUTOSEQ,
+       CP_INITSEQ,
 #endif /* PUBKEY */
        0
 };
@@ -1321,6 +1324,16 @@ ctl_putsys(
                        ctl_putstr(sys_var[CS_DHPARAMS].text,
                            dh_params_file, strlen(dh_params_file));
                break;
+
+       case CS_HOSTNAM:
+               if (sys_hostname != NULL)
+                       ctl_putstr(sys_var[CS_HOSTNAM].text,
+                           sys_hostname, sys_hostnamelen);
+               break;
+
+       case CS_REVTIME:
+               ctl_putts(sys_var[CS_REVTIME].text, &sys_revoketime);
+               break;
 #endif /* PUBKEY */
        }
 }
@@ -1560,16 +1573,16 @@ ctl_putpeer(
                break;
 
        case CP_SESKEY:
-               if (peer->pcookie != NULL)
-                       ctl_puthex(peer_var[CP_SESKEY].text, peer->pcookie);
+               if (peer->pcookie.key != NULL)
+                       ctl_puthex(peer_var[CP_SESKEY].text,
+                           peer->pcookie.key);
                if (peer->hcookie != NULL)
                        ctl_puthex(peer_var[CP_SASKEY].text, peer->hcookie);
                break;
 
-       case CP_AUTOSEQ:
+       case CP_INITSEQ:
                if (peer->keylist == NULL)
                        break;
-               ctl_putint(peer_var[CP_AUTOSEQ].text, peer->recseq);
                ctl_putint(peer_var[CP_INITSEQ].text, peer->recauto.seq);
                ctl_puthex(peer_var[CP_INITKEY].text, peer->recauto.key);
                ctl_putuint(peer_var[CP_INITTSP].text, peer->recauto.tstamp);
index 2d39340b52d722a8fa3feac99186bf1381ff737a..a8a7f66490620f9333b3f02f12324d288d9532a5 100644 (file)
  *   +-------+-------+   +-------+-------+   +-------+-------+
  * 1 |    assoc ID   |   |    assoc ID   |   |    assoc ID   |
  *   +---------------+   +---------------+   +---------------+
- * 2 |  current seq  |   |  peer cookie  |   |   value len   |
+ * 2 |   timestamp   |   |   timestamp   |   |   timestamp   |
  *   +---------------+   +---------------+   +---------------+
- * 3 |   final seq   |   | signature len |   |               |
+ * 3 |   final seq   |   |     cookie    |   |   value len   |
+ *   +---------------+   +---------------+   +---------------+
+ * 4 |   final key   |   | signature len |   |               |
  *   +---------------+   +---------------+   =     value     =
- * 4 |   final key   |   |               |   |               |
+ * 5 | signature len |   |               |   |               |
  *   +---------------+   =   signature   =   +---------------+
- * 4 |   timestamp   |   |               |   CRYPTO_DH req/rsp
- *   +---------------+   +---------------+   CRYPTO_PUB rsp
- * 5 | signature len |   CRYPTO_PRIV rsp     CRYPTO_NAME rsp
- *   +---------------+
- * 6 |               |
- *   =   signature   =
- *   |               |   Other requests and responses have only the
- *   +---------------+   first two words.
- *   CRYPTO_AUTO rsp
- *
+ * 6 |               |   |               |   | signature len |
+ *   =   signature   =   +---------------+   +---------------+
+ * 7 |               |   CRYPTO_PRIV rsp     |               |
+ *   +---------------+                       =   signature   =
+ *   CRYPTO_AUTO rsp                         |               |
+ *                                           +---------------+
+ *                                           CRYPTO_DH rsp
+ *                                           CRYPTO_NAME rsp
+ *                                           
  *   CRYPTO_PUBL  1  request/respond for public key
  *   CRYPTO_ASSOC 2  request/respond association ID
  *   CRYPTO_AUTO  3  request/respond autokey values
@@ -65,6 +66,8 @@ static u_char *dh_public;     /* Diffie-Hellman public value */
 static u_char *dh_private;     /* Diffie-Hellman private value */
 static R_RSA_PRIVATE_KEY private_key; /* RSA private key */
 static R_RSA_PUBLIC_KEY public_key; /* RSA public key */
+static u_char *dh_sign = NULL; /* Diffie-Hellman public signature */
+static struct value host;      /* host name, timestamp and signature */
 
 int    crypto_enable;          /* master switch */
 int    crypto_flags;           /* flags that wave cryptically */
@@ -80,6 +83,7 @@ static        int     crypto_read     P((u_char *, u_char *, u_int));
 static void    crypto_line     P((FILE *, u_char **, u_int *));
 #endif /* PUBKEY */
 
+
 /*
  * session_key - generate session key
  *
@@ -144,6 +148,7 @@ make_keylist(
        struct peer *peer       /* peer structure pointer */
        )
 {
+       struct autokey *ap;     /* autokey pointer */
        keyid_t keyid;          /* next key ID */
        keyid_t cookie;         /* private value */
        l_fp tstamp;            /* NTP timestamp */
@@ -152,7 +157,7 @@ make_keylist(
 #ifdef PUBKEY
        R_SIGNATURE_CTX ctx;    /* signature context */
        int rval;               /* return value */
-       u_int32 xpkt[3];        /* data in network byte order */
+       u_int len;
 #endif /* PUBKEY */
 
        /*
@@ -161,7 +166,7 @@ make_keylist(
        L_CLR(&tstamp);
        if (sys_leap != LEAP_NOTINSYNC)
                get_systime(&tstamp);
-       if (peer->keylist == 0)
+       if (peer->keylist == NULL)
                peer->keylist = (keyid_t *)emalloc(sizeof(keyid_t) *
                    NTP_MAXSESSION);
 
@@ -188,14 +193,18 @@ make_keylist(
        ltemp = sys_automax;
        peer->hcookie = session_key(&peer->dstadr->sin, &peer->srcadr,
            0, sys_private, 0);
-       if (peer->hmode == MODE_BROADCAST)
+       if (peer->hmode == MODE_BROADCAST) {
                cookie = 0;
-       else
+       } else {
 #ifdef PUBKEY
-               cookie = peer->pcookie;
+               cookie = peer->pcookie.key;
 #else
-               cookie = peer->hcookie ^ peer->pcookie;
+               if (peer->hmode == MODE_CLIENT)
+                       cookie = peer->pcookie.key;
+               else
+                       cookie = peer->hcookie ^ peer->pcookie.key;
 #endif /* PUBKEY */
+       }
        for (i = 0; i < NTP_MAXSESSION; i++) {
                peer->keylist[i] = keyid;
                peer->keynumber = i;
@@ -213,13 +222,15 @@ make_keylist(
         * then sign these values for later retrieval by the clients. Be
         * careful not to use invalid key media.
         */
-       peer->sndauto.seq = peer->keynumber;
-       peer->sndauto.key = keyid;
-       peer->sndauto.tstamp = tstamp.l_ui;
+       ap = &peer->sndauto;
+       ap->tstamp = htonl(tstamp.l_ui);
+       ap->seq = htonl(peer->keynumber);
+       ap->key = htonl(keyid);
+       ap->siglen = 0;
 #if DEBUG
        if (debug)
-               printf("make_keys: %d %08x %u\n", peer->sndauto.seq,
-                   peer->sndauto.key, peer->sndauto.tstamp);
+               printf("make_keys: %d %08x %08x ts %u\n", ntohl(ap->seq),
+                   ntohl(ap->key), cookie, ntohl(ap->tstamp));
 #endif
 #ifdef PUBKEY
        if(!crypto_enable)
@@ -228,15 +239,12 @@ make_keylist(
            private_key.bits > MAX_RSA_MODULUS_BITS) {
                rval = -1;
        } else {
-               if (peer->sign == NULL)
-                       peer->sign = emalloc(MAX_SIGNATURE_LEN);
-               xpkt[0] = htonl(peer->sndauto.seq);
-               xpkt[1] = htonl(peer->sndauto.key);
-               xpkt[2] = htonl(peer->sndauto.tstamp);
+               if (ap->sig == NULL)
+                       ap->sig = emalloc(MAX_SIGNATURE_LEN);
                R_SignInit(&ctx, DA_MD5);
-               R_SignUpdate(&ctx, (u_char *)xpkt, 12);
-               rval = R_SignFinal(&ctx, peer->sign, &peer->signlen,
-                   &private_key);
+               R_SignUpdate(&ctx, (u_char *)ap, 12);
+               rval = R_SignFinal(&ctx, ap->sig, &len, &private_key);
+               ap->siglen = htonl(len);
        }
        if (rval != 0)
                msyslog(LOG_ERR, "make_keylist: signature fails %x",
@@ -249,7 +257,9 @@ make_keylist(
  * crypto_recv - parse extension fields
  *
  * This routine is called when the packet has been matched to an
- * association and passed sanity, format and authentication checks.
+ * association and passed sanity, format and authentication checks. We
+ * believe the extension field values only if the public key is valid
+ * and the signature has valid length and is verified.
  */
 void
 crypto_recv(
@@ -258,16 +268,21 @@ crypto_recv(
        )
 {
        u_int32 *pkt;           /* packet pointer */
+       struct autokey *ap;     /* autokey pointer */
+       struct cookie *cp;      /* cookie pointer */
        int has_mac;            /* length of MAC field */
        int authlen;            /* offset of MAC field */
        int len;                /* extension field length */
        u_int code;             /* extension field opcode */
+       u_int tstamp;           /* extension field timestamp */
        int i;
        u_int temp;
 #ifdef PUBKEY
        R_SIGNATURE_CTX ctx;    /* signature context */
-       u_int modulus;          /* modulus length */
-       int rval;               /* return value */
+       u_char dh_key[MAX_DH_LEN]; /* Diffie-Hellman agreed key */
+       u_int modulus;
+       int rval;
+       int j;
 #endif /* PUBKEY */
 
        /*
@@ -280,12 +295,13 @@ crypto_recv(
                i = authlen / 4;
                len = ntohl(pkt[i]) & 0xffff;
                code = (ntohl(pkt[i]) >> 16) & 0xffff;
+               tstamp = ntohl(pkt[i + 2]);
                if (code & CRYPTO_RESP)
                        peer->assoc = ntohl(pkt[i + 1]);
 #ifdef DEBUG
                if (debug)
                        printf(
-                           "crypto_recv: ext field offset %d length %d code %x assoc ID %d\n",
+                           "crypto_recv: ext offset %d len %d code %x assoc ID %d\n",
                            authlen, len, code, (u_int32)ntohl(pkt[i +
                            1]));
 #endif
@@ -306,45 +322,43 @@ crypto_recv(
                 * only if the timestamp is nonzero.
                 */
                case CRYPTO_AUTO | CRYPTO_RESP:
+                       ap = (struct autokey *)&pkt[i + 2];
 #ifdef PUBKEY
-                       temp = ntohl(pkt[i + 6]);
+                       temp = public_key.bits / 8;
                        if (!crypto_enable) {
                                rval = 0;
-                       } else if (temp == 0 || peer->pubkey == NULL) {
+                       } else if (tstamp < peer->recauto.tstamp) {
+                               break;
+                       } else if (peer->pubkey == NULL || temp !=
+                           ntohl(ap->siglen)) {
                                rval = -1;
                        } else {
                                R_VerifyInit(&ctx, DA_MD5);
-                               R_VerifyUpdate(&ctx, (char *)&pkt[i +
-                                   3], 12);
+                               R_VerifyUpdate(&ctx, (u_char *)ap, 12);
                                rval = R_VerifyFinal(&ctx,
-                                   (char *)&pkt[i + 7], temp,
+                                   (u_char *)&ap->sig, temp,
                                    (R_RSA_PUBLIC_KEY *)peer->pubkey);
                        }
 #ifdef DEBUG
                        if (debug)
                                printf(
-                                   "crypto_recv: verify %x autokey %d %d %08x %u (%u)\n",
-                                   rval, (u_int32)ntohl(pkt[i + 2]),
-                                   (u_int32)ntohl(pkt[i + 3]),
-                                   (u_int32)ntohl(pkt[i + 4]),
-                                   (u_int32)ntohl(pkt[i + 5]),
+                                   "crypto_recv: verify %x autokey %d %08x ts %u (%u)\n",
+                                   rval, ntohl(ap->seq),
+                                   ntohl(ap->key), tstamp,
                                    peer->recauto.tstamp);
 #endif
-                       if (ntohl(pkt[i + 5]) < peer->recauto.tstamp)
-                               break;
                        if (rval != 0) {
                                peer->flags &= ~FLAG_AUTOKEY;
                                break;
                        }
-                       if (ntohl(pkt[i + 5]) != 0)
+                       if (tstamp != 0)
                                peer->flags |= FLAG_AUTOKEY;
 #endif /* PUBKEY */
                        peer->flash &= ~TEST10;
-                       peer->recseq = ntohl(pkt[i + 2]);
-                       peer->recauto.seq = ntohl(pkt[i + 3]);
-                       peer->recauto.key = peer->pkeyid = ntohl(pkt[i +
-                           4]);
-                       peer->recauto.tstamp = ntohl(pkt[i + 5]);
+                       peer->recauto.tstamp = ntohl(ap->tstamp);
+                       peer->recauto.seq = ntohl(ap->seq);
+                       peer->recauto.key = ntohl(ap->key);
+                       peer->pkeyid = peer->recauto.key;
                        break;
 
                /*
@@ -354,132 +368,148 @@ crypto_recv(
                 * we mark as authentic only if the value is nonzero.
                 */
                case CRYPTO_PRIV | CRYPTO_RESP:
+                       cp = (struct cookie *)&pkt[i + 2];
 #ifdef PUBKEY
-                       temp = ntohl(pkt[i + 3]);
+                       temp = public_key.bits / 8;
                        if (!crypto_enable) {
                                rval = 0;
-                               temp = ntohl(pkt[i + 2]);
-                       } else if (temp == 0 || peer->pubkey == NULL) {
+                       } else if (tstamp < peer->pcookie.tstamp) {
+                               break;
+                       } else if (peer->pubkey == NULL || temp !=
+                           ntohl(cp->siglen)) {
                                rval = -1;
-                               temp = 0;
                        } else {
                                R_VerifyInit(&ctx, DA_MD5);
-                               R_VerifyUpdate(&ctx, (char *)&pkt[i +
-                                   2], 4);
+                               R_VerifyUpdate(&ctx, (u_char *)cp, 8);
                                rval = R_VerifyFinal(&ctx,
-                                   (char *)&pkt[i + 4], temp,
+                                   (u_char *)&cp->sig, temp,
                                    (R_RSA_PUBLIC_KEY *)peer->pubkey);
-                               temp = ntohl(pkt[i + 2]);
                        }
+                       temp = cp->key;
 #ifdef DEBUG
                        if (debug)
                                printf(
-                           "crypto_recv: verify %x cookie %08x\n",
-                                   rval, temp);
+                           "crypto_recv: verify %x cookie %08x ts %u\n",
+                                   rval, temp, tstamp);
 #endif
                        if (rval != 0) {
                                peer->flags &= ~FLAG_AUTOKEY;
                                break;
                        }
-                       if (temp != 0)
+                       if (tstamp != 0)
                                peer->flags |= FLAG_AUTOKEY;
 #else
-                       temp = ntohl(pkt[i + 2]);
+                       temp = cp->key;
 #endif /* PUBKEY */
                        peer->flash &= ~TEST10;
-                       if (temp != peer->pcookie) {
+                       if (temp != peer->pcookie.key) {
                                key_expire(peer);
-                               peer->pcookie = temp;
+                               peer->pcookie.tstamp = tstamp;
+                               peer->pcookie.key = temp;
                        }
                        break;
 
 #ifdef PUBKEY
                /*
-                * Compute Diffie-Hellman key agreement in symmetric
-                * modes. We allocate space and save the public value to
-                * compute the signature later, Then we allocate space
-                * for the agreed key, run the agreement algorithm and
-                * stash the key value. We use only the first u_int32
-                * for the host cookie. Wasteful.
+                * Verify Diffie-Hellman public value and compute key
+                * agreement in symmetric modes. We believe the
+                * value only if the public key is valid and the
+                * signature has valid length and is verified. 
                 */
                case CRYPTO_DH:
-                       temp = ntohl(pkt[i + 2]);
-                       if (temp == 0 || temp != dh_params.primeLen) {
+                       peer->cmmd = ntohl(pkt[i]);
+                       /* fall through */
+
+               case CRYPTO_DH | CRYPTO_RESP:
+                       temp = ntohl(pkt[i + 3]);
+                       j = i + 4 + temp / 4;
+                       if (tstamp < peer->pcookie.tstamp) {
+                               break;
+                       } else if (peer->pubkey == NULL ||
+                           ntohl(pkt[j]) != public_key.bits / 8) {
                                rval = -1;
+                       } else if (temp != dh_params.primeLen ||
+                           dh_public == NULL) {
+                               rval = -2;
+                       } else {
+                               R_VerifyInit(&ctx, DA_MD5);
+                               R_VerifyUpdate(&ctx, (u_char *)&pkt[i +
+                                   2], temp + 8);
+                               rval = R_VerifyFinal(&ctx,
+                                   (u_char *)&pkt[j + 1],
+                                   public_key.bits / 8,
+                                   (R_RSA_PUBLIC_KEY *)peer->pubkey);
+                       }
+
+                       /*
+                        * Run the agreement algorithm and stash the key
+                        * value. We use only the first u_int32 for the
+                        * host cookie. Wasteful.
+                        */
+                       if (rval != 0) {
                                temp = 0;
                        } else {
-                               if (peer->dh_public == NULL) 
-                                       peer->dh_public =
-                                           (u_char *)emalloc(temp);
-                               memcpy(peer->dh_public,
-                                   (char *)&pkt[i + 3], temp);
-                               if (peer->dh_key == NULL) 
-                                       peer->dh_key =
-                                           (u_char *)emalloc(temp);
-                               rval = R_ComputeDHAgreedKey(
-                                   peer->dh_key, peer->dh_public,
-                                   dh_private, dh_keyLen, &dh_params);
-                               temp = ntohl(*((u_int *)peer->dh_key));
+                               rval = R_ComputeDHAgreedKey(dh_key,
+                                   (u_char *)&pkt[i + 4], dh_private,
+                                   dh_keyLen, &dh_params);
+                               temp = ntohl(*(u_int32 *)dh_key);
                        }
 #ifdef DEBUG
                        if (debug)
                                printf(
-                                   "crypto_recv: d-h agree %x %08x\n",
-                                   rval, temp);
+                                   "crypto_recv: verify %x d-h %08x ts %u\n",
+                                   rval, temp, tstamp);
 #endif
                        if (rval != 0) {
                                peer->flags &= ~FLAG_AUTOKEY;
+                               peer->cmmd = 0;
                                break;
                        }
                        peer->flash &= ~TEST10;
-                       if (temp != peer->pcookie)
-                               peer->pcookie = 0;
-                       peer->cmmd = ntohl(pkt[i]);
+                       if (temp != peer->pcookie.key) {
+                               key_expire(peer);
+                               peer->pcookie.tstamp = tstamp;
+                               peer->pcookie.key = temp;
+                       }
                        break;
 
                /*
-                * Verify signature of Diffie-Hellman public values in
-                * symmetric modes. The verification fails if the
-                * signature length does not match the modulus length or
-                * any of the public values or the agreed key is not
-                * valid.
+                * Receive remote host name and install public key from
+                * file.
                 */
-               case CRYPTO_DH | CRYPTO_RESP:
-                       temp = ntohl(pkt[i + 2]);
-                       if (temp == 0 || temp != dh_params.primeLen ||
-                           peer->pubkey == NULL || peer->dh_public ==
-                           NULL || dh_public == NULL || peer->dh_key ==
-                           NULL) {
+               case CRYPTO_NAME | CRYPTO_RESP:
+                       temp = ntohl(pkt[i + 3]);
+                       j = i + 4 + temp / 4;
+                       if (tstamp < peer->pcookie.tstamp) {
+                               break;
+                       } else if (ntohl(pkt[j]) != public_key.bits / 8)
+                           {
                                rval = -1;
-                               temp = 0;
-                       } else {
+                       } else if (crypto_public(peer, (char *)&pkt[i +
+                           4])) {
                                R_VerifyInit(&ctx, DA_MD5);
-                               R_VerifyUpdate(&ctx,
-                                   (u_char *)peer->dh_public,
-                                   dh_params.primeLen);
-                               R_VerifyUpdate(&ctx, dh_public,
-                                   dh_params.primeLen);
+
+                               R_VerifyUpdate(&ctx, (char *)&pkt[i +
+                                   2], 8 + temp);
+
                                rval = R_VerifyFinal(&ctx,
-                                   (u_char *)&pkt[i + 3], temp,
+                                   (u_char *)&pkt[j + 1],
+                                   public_key.bits / 8,
                                    (R_RSA_PUBLIC_KEY *)peer->pubkey);
-                               temp = ntohl(*((u_int *)peer->dh_key));
+                               if (rval != 0) {
+                                       free(peer->pubkey);
+                                       peer->pubkey = NULL;
+                               }
+                       } else {
+                               rval = -2;
                        }
 #ifdef DEBUG
                        if (debug)
+
                                printf(
-                                   "crypto_recv: d-h verify %x %08x\n",
-                                   rval, temp);
+                                   "crypto_recv: verify %x host %s ts %u\n",
+                                   rval, (char *)&pkt[i + 4], tstamp); 
 #endif
-                       if (rval != 0) {
-                               peer->flags &= ~FLAG_AUTOKEY;
-                               break;
-                       }
-                       peer->flash &= ~TEST10;
-                       peer->flags |= FLAG_AUTOKEY;
-                       if (temp != peer->pcookie) {
-                               key_expire(peer);
-                               peer->pcookie = temp;
-                       }
                        break;
 
                /*
@@ -508,19 +538,6 @@ crypto_recv(
                            ((R_RSA_PUBLIC_KEY *)peer->pubkey)->modulus,
                            (u_char *)&(pkt[i + 4]), temp);
                        break;
-
-               /*
-                * Receive remote host name and install public key from
-                * file.
-                */
-               case CRYPTO_NAME | CRYPTO_RESP:
-                       temp = crypto_public(peer, (char *)&pkt[i + 3]);
-#ifdef DEBUG
-                       if (debug)
-                               printf("crypto_recv: host %d %s\n",
-                                   temp, (char *)&pkt[i + 3]); 
-#endif
-                       break;
 #endif /* PUBKEY */
 
                /*
@@ -558,13 +575,17 @@ crypto_xmit(
        )
 {
        struct peer *peer;      /* peer structure pointer */
+       struct autokey *ap;     /* autokey pointer */
+       struct cookie *cp;      /* cookie pointer */
        int len;                /* extension field length */
        u_int opcode;           /* extension field opcode */
        int i;
 #ifdef PUBKEY
        R_SIGNATURE_CTX ctx;    /* signature context */
+       struct value *vp;       /* value pointer */
        int rval;               /* return value */
        u_int temp;
+       int j;
 #endif /* PUBKEY */
 
        /*
@@ -586,11 +607,7 @@ crypto_xmit(
 
        /*
         * Find peer and send autokey data and signature in broadcast
-        * server and symmetric modes. We send the data only if the peer
-        * exists and the make_keylist routine has previously
-        * constructed the list and successfully signed the data. Note
-        * that the timestamp is zero if the server has not
-        * synchronized.
+        * server and symmetric modes.
         */
        case CRYPTO_AUTO | CRYPTO_RESP:
                peer = findpeerbyassoc(associd);
@@ -598,108 +615,102 @@ crypto_xmit(
                        opcode |= CRYPTO_ERROR;
                        break;
                }
-               xpkt[i + 2] = htonl(peer->keynumber);
-               xpkt[i + 3] = htonl(peer->sndauto.seq);
-               xpkt[i + 4] = htonl(peer->sndauto.key);
-               xpkt[i + 5] = htonl(peer->sndauto.tstamp);
-               xpkt[i + 6] = 0;
-               len += 20;
+               ap = (struct autokey *)&xpkt[i + 2];
+               ap->tstamp = peer->sndauto.tstamp;
+               ap->seq = peer->sndauto.seq;
+               ap->key = peer->sndauto.key;
+               ap->siglen = 0;
+               len += 16;
 #ifdef PUBKEY
-               if (peer->signlen == 0)
+               if (!crypto_enable)
                        break;
-               xpkt[i + 6] = htonl(peer->signlen);
-               memcpy((u_char *)&xpkt[i + 7], peer->sign,
-                   peer->signlen);
-               len += peer->signlen;
+               ap->siglen = peer->sndauto.siglen;
+               temp = ntohl(peer->sndauto.siglen);
+               if (temp > 0)
+                       memcpy(&ap->sig, peer->sndauto.sig, temp);
+               len += temp;
 #endif /* PUBKEY */
                break;
 
        /*
-        * Send peer cookie and signature in server mode. We send the
-        * signature only if the private key exists and is valid. Note
-        * that the cookie is zero of the server has not synchronized.
+        * Send peer cookie and signature in server mode.
         */
        case CRYPTO_PRIV | CRYPTO_RESP:
-               xpkt[i + 2] = 0;
-               if (sys_leap != LEAP_NOTINSYNC)
-                       xpkt[i + 2] = htonl(cookie);
-               xpkt[i + 3] = 0;
-               len += 8;
+               cp = (struct cookie *)&xpkt[i + 2];
+               cp->tstamp = htonl(sys_revoketime.l_ui);
+               cp->key = htonl(cookie);
+               cp->siglen = 0;
+               len += 12;
 #ifdef PUBKEY
+               if (!crypto_enable)
+                       break;
+               cp->siglen = htonl(public_key.bits / 8);
                if (private_key.bits < MIN_RSA_MODULUS_BITS ||
                    private_key.bits > MAX_RSA_MODULUS_BITS) {
                        rval = -1;
                } else {
                        R_SignInit(&ctx, DA_MD5);
-                       R_SignUpdate(&ctx, (u_char *)&xpkt[i + 2], 4);
-                       rval = R_SignFinal(&ctx, (u_char *)&xpkt[i + 4],
+                       R_SignUpdate(&ctx, (u_char *)cp, 8);
+                       rval = R_SignFinal(&ctx, (u_char *)&cp->sig,
                            &temp, &private_key);
                }
                if (rval != 0) {
+                       cp->siglen = 0;
                        msyslog(LOG_ERR,
-                           "crypto_xmit: signature fails %x", rval);
+                           "crypto_xmit: cookie signature fails %x",
+                           rval);
                        break;
                }
-               xpkt[i + 3] = htonl(temp);
                len += temp;
 #endif /* PUBKEY */
                break;
 
 #ifdef PUBKEY
        /*
-        * Send Diffie-Hellman public value in symmetric modes. We send
-        * only if the parameters have been initialized and the
-        * public/private values have been set up.
+        * Send Diffie-Hellman public value, timestamp and signature.
         */
        case CRYPTO_DH:
-               xpkt[i + 2] = 0;
-               len += 4;
-               if (dh_params.primeLen == 0 || dh_public == NULL)
+       case CRYPTO_DH | CRYPTO_RESP:
+               vp = (struct value *)&xpkt[i + 2];
+               vp->tstamp = htonl(sys_revoketime.l_ui);
+               vp->vallen = 0;
+               len += 8;
+               temp = dh_params.primeLen;
+               if (dh_sign == NULL)
                        break;
-               xpkt[i + 2] = htonl(dh_params.primeLen);
-               memcpy((u_char *)&xpkt[i + 3], dh_public,
-                   dh_params.primeLen);
-               len += dh_params.primeLen;
+               vp->vallen = htonl(temp);
+               memcpy((u_char *)&vp->val, dh_public, temp);
+               len += temp;
+               j = i + 4 + temp / 4;
+               temp = public_key.bits / 8;
+               xpkt[j++] = htonl(temp);
+               memcpy((u_char *)&xpkt[j], dh_sign, temp);
+               len += temp + 4;
                break;
 
        /*
-        * Find peer and send signature of Diffie-Hellman public values
-        * in symmetric modes. We send only if the public key exists and
-        * is valid and the public values exist.
+        * Send host name, timestamp and signature.
         */
-       case CRYPTO_DH | CRYPTO_RESP:
-               peer = findpeerbyassoc(associd);
-               if (peer == NULL) {
-                       opcode |= CRYPTO_ERROR;
-                       break;
-               }
-               xpkt[i + 2] = 0;
-               len += 4;
-               if (private_key.bits < MIN_RSA_MODULUS_BITS ||
-                   private_key.bits > MAX_RSA_MODULUS_BITS ||
-                   dh_public == NULL || peer->dh_public == NULL) {
-                       rval = -1;
-               } else {
-                       R_SignInit(&ctx, DA_MD5);
-                       R_SignUpdate(&ctx, dh_public,
-                           dh_params.primeLen);
-                       R_SignUpdate(&ctx, (u_char *)peer->dh_public,
-                           dh_params.primeLen);
-                       rval = R_SignFinal(&ctx, (u_char *)&xpkt[i + 3],
-                           &temp, &private_key);
-               }
-               if (rval != 0) {
-                       msyslog(LOG_ERR,
-                           "crypto_xmit: signature fails %x", rval);
+       case CRYPTO_NAME | CRYPTO_RESP:
+               vp = (struct value *)&xpkt[i + 2];
+               vp->tstamp = htonl(sys_revoketime.l_ui);
+               vp->vallen = host.vallen;
+               len += 8;
+               temp = ntohl(host.vallen);
+               if (temp == 0)
                        break;
-               }
-               xpkt[i + 2] = htonl(temp);
+               memcpy((u_char *)&vp->val, host.val, temp);
                len += temp;
+               j = i + 4 + temp / 4;
+               temp = public_key.bits / 8;
+               xpkt[j++] = htonl(temp);
+               memcpy((u_char *)&xpkt[j], host.sig, temp);
+               len += temp + 4;
                break;
 
        /*
         * Send public key. We send the public key only if it exists and
-        * is valid. This is used in all modes, primarily for testing.
+        * is valid. This is used primarily for testing.
         */
        case CRYPTO_PUBL | CRYPTO_RESP:
                xpkt[i + 2] = 0;
@@ -714,16 +725,6 @@ crypto_xmit(
                    (u_char *)&public_key.modulus, temp);
                len += temp + 4;
                break;
-
-       /*
-        * Send host name.
-        */
-       case CRYPTO_NAME | CRYPTO_RESP:
-               gethostname((char *)&xpkt[i + 3], MAXFILENAME);
-               temp = strlen((char *)&xpkt[i + 3]);
-               xpkt[i + 2] = htonl(temp);
-               len += temp + 4;
-               break;
 #endif /* PUBKEY */
 
        /*
@@ -746,7 +747,7 @@ crypto_xmit(
 #ifdef DEBUG
                if (debug)
                        printf(
-                           "crypto_xmit: ext field offset %d length %d code %x assoc ID %d\n",
+                           "crypto_xmit: ext offset %d len %d code %x assoc ID %d\n",
                            start, len, code, associd);
 #endif
        }
@@ -755,6 +756,91 @@ crypto_xmit(
 
 
 #ifdef PUBKEY
+/*
+ * crypto_agree - compute public and private Diffie-Hellman values from
+ * given prime and generator, then sign with private key.
+ */
+void
+crypto_agree(void)
+{
+       u_int len, temp;
+       R_RANDOM_STRUCT randomstr;
+       R_SIGNATURE_CTX ctx;    /* signature context */
+       int rval;
+       int i;
+
+       /*
+        * Sign host name and timestamp.
+        */
+       host.tstamp = htonl(sys_revoketime.l_ui);
+       host.vallen = htonl(sys_hostnamelen);
+       host.val = sys_hostname;
+       host.siglen = dh_params.primeLen;
+       if (host.sig == NULL)
+               host.sig = emalloc(dh_params.primeLen);
+       R_SignInit(&ctx, DA_MD5);
+       R_SignUpdate(&ctx, (u_char *)&host, 8);
+       R_SignUpdate(&ctx, host.val, sys_hostnamelen);
+       rval = R_SignFinal(&ctx, host.sig, &temp, &private_key);
+       if (rval != 0) {
+               msyslog(LOG_ERR,
+                   "crypto_agree: host signature fails %x", rval);
+               return;
+       }
+
+       /*
+        * Compute Diffie-Hellman public value. Note that the length of
+        * the private value is set arbitrarily to half the prime
+        * length.
+        */
+       if (dh_params.primeLen == 0) {
+               msyslog(LOG_ERR,
+                   "unavailable d-h parameters");
+               return;
+       }
+       R_RandomInit(&randomstr);
+       R_GetRandomBytesNeeded(&len, &randomstr);
+       for (i = 0; i < len; i++) {
+               temp = random();
+               R_RandomUpdate(&randomstr, (u_char *)&temp, 1);
+       }
+       if (dh_private == NULL)
+               dh_private = (u_char *)emalloc(dh_keyLen);
+       if (dh_public == NULL)
+               dh_public = (u_char *)emalloc(dh_params.primeLen);
+       rval = R_SetupDHAgreement(dh_public, dh_private, dh_keyLen,
+           &dh_params, &randomstr);
+       if (rval != 0) {
+               msyslog(LOG_ERR, "invalid d-h parameters");
+               return;
+       }
+
+       /*
+        * Sigfie-Hellman public value and save for later.
+        */
+       if (dh_sign == NULL)
+               dh_sign = emalloc(dh_params.primeLen);
+       R_SignInit(&ctx, DA_MD5);
+       R_SignUpdate(&ctx, (char *)&host.tstamp, 4);
+       temp = htonl(dh_params.primeLen);
+       R_SignUpdate(&ctx, (char *)&temp, 4);
+       R_SignUpdate(&ctx, dh_public, dh_params.primeLen);
+       rval = R_SignFinal(&ctx, dh_sign, &temp, &private_key);
+       if (rval != 0) {
+               msyslog(LOG_ERR,
+                   "crypto_agree: d-h signature fails %x", rval);
+               return;
+       }
+#ifdef DEBUG
+       if (debug)
+               printf(
+                   "cypto_agree: host %s d-h prime %d gen %d\n",
+                   host.val, dh_params.primeLen,
+                   dh_params.generatorLen);
+#endif
+}
+
+
 /*
  * crypto_read - read RSA key, decode and check for errors
  */
@@ -784,7 +870,8 @@ crypto_read(
        } else if (*cp == '/') {
                strcpy(filename, cp);
        } else {
-               snprintf(filename, sizeof filename, "%s%s", keysdir, cp);
+               snprintf(filename, MAXFILENAME - 1, "%s%s", keysdir,
+                   cp);
        }
        str = fopen(filename, "r");
        if (str == NULL) {
@@ -873,7 +960,7 @@ crypto_public(
        u_int keylen = sizeof(R_RSA_PUBLIC_KEY);
        char filename[MAXFILENAME];
 
-       snprintf(filename, sizeof filename, "ntpkey_%s", cp);
+       snprintf(filename, MAXFILENAME - 1, "ntpkey_%s", cp);
        if (!crypto_read(filename, (u_char *)&keybuf, keylen))
                return (0);
        if (peer->keystr != NULL)
@@ -906,7 +993,7 @@ crypto_line(
 
        /*
         * Read key and length. Bail out if the length word doesn't
-        * match the decoded string length.
+        * match the decoded string length and in other cases.
         */
        *key = NULL;
        *len = 0;
@@ -919,6 +1006,8 @@ crypto_line(
        }
        if (sscanf(buf, "%d %s", &temp, encoded_key) != 2)
                return;
+       if (temp > MAX_DH_LEN)
+               return;
        temp2 = DECODED_CONTENT_LEN(strlen(encoded_key));
        if (R_DecodePEMBlock(buf, &temp1, encoded_key,
            strlen(encoded_key)))
@@ -957,7 +1046,7 @@ crypto_setup(void)
         */
        if (public_key_file == NULL) {
                gethostname(hostname, MAXFILENAME);
-               snprintf(filename, sizeof filename, "ntpkey_%s",
+               snprintf(filename, MAXFILENAME - 1, "ntpkey_%s",
                         hostname);
                public_key_file = emalloc(strlen(filename) + 1);
                strcpy(public_key_file, filename);
@@ -973,7 +1062,7 @@ crypto_setup(void)
        if (*dh_params_file == '/')
                strcpy(filename, dh_params_file);
        else
-               snprintf(filename, sizeof filename, "%s%s", keysdir,
+               snprintf(filename, MAXFILENAME - 1, "%s%s", keysdir,
                         dh_params_file);
 
        str = fopen(filename, "r");
@@ -998,47 +1087,6 @@ crypto_setup(void)
 }
 
 
-/*
- * crypto_agree - compute public and private Diffie-Hellman values from
- * given prime and generator.
- */
-void
-crypto_agree(void)
-{
-       R_RANDOM_STRUCT randomstr;
-       u_int len, temp;
-       int rval, i;
-
-       /*
-        * Note that the length of the private value is set arbitrarily
-        * to half the prime length.
-        */
-       if (dh_params.primeLen == 0)
-               return;
-       R_RandomInit(&randomstr);
-       R_GetRandomBytesNeeded(&len, &randomstr);
-       for (i = 0; i < len; i++) {
-               temp = random();
-               R_RandomUpdate(&randomstr, (u_char *)&temp, 1);
-       }
-       if (dh_private == NULL)
-               dh_private = (u_char *)emalloc(dh_keyLen);
-       if (dh_public == NULL)
-               dh_public = (u_char *)emalloc(dh_params.primeLen);
-       rval = R_SetupDHAgreement(dh_public, dh_private, dh_keyLen,
-           &dh_params, &randomstr);
-       if (rval != 0)
-               msyslog(LOG_ERR, "invalid Diffie-Hellman parameters");
-#ifdef DEBUG
-       if (debug)
-               printf(
-                   "cypto_init: Diffie-Hellman prime %d generator %d key %d\n",
-                   dh_params.primeLen, dh_params.generatorLen,
-                   dh_keyLen);
-#endif
-}
-
-
 /*
  * crypto_config - configure crypto data.
  */
@@ -1103,6 +1151,7 @@ crypto_init(void)
        memset((char *)&private_key, 0, sizeof(private_key));
        memset((char *)&public_key, 0, sizeof(public_key));
        memset((char *)&dh_params, 0, sizeof(dh_params));
+       memset((char *)&host, 0, sizeof(host));
 }
 #endif /* PUBKEY */
 #endif /* AUTOKEY */
index d614d8e4887a0b897e3cf4ca9d9e4e0db3742da1..ad0caca25b330abcc80a6404442b68e7b1103eb0 100644 (file)
@@ -10,9 +10,9 @@
 
 #include "ntpd.h"
 #include "ntp_stdlib.h"
-#ifdef PUBKEY
+#ifdef AUTOKEY
 #include "ntp_crypto.h"
-#endif /* PUBKEY */
+#endif /* AUTOKEY */
 
 /*
  *                  Table of valid association combinations
@@ -366,14 +366,13 @@ findmanycastpeer(
        return manycast_peer;
 }
 
-#ifdef AUTOKEY
+
 /*
- * key_expire - expire all keys and roll a new private value. Note the
- * 32-bit mask is necessary for 64-bit u_ints.
+ * clear_all - flush all time values and refresh Diffie-Hellman public
+ * value.
  */
 void
-key_expire_all(
-       )
+clear_all(void)
 {
        struct peer *peer, *next_peer;
        int n;
@@ -384,18 +383,46 @@ key_expire_all(
                        peer_clear(peer);
                }
        }
+#ifdef DEBUG
+       if (debug)
+               printf("clear_all: at %lu\n", current_time);
+#endif
+}
+
+
+#ifdef AUTOKEY
+/*
+ * expire_all - flush all crypto data and update timestamp
+ */
+void
+expire_all(void)
+{
+       struct peer *peer, *next_peer;
+       int n;
+
+       for (n = 0; n < HASH_SIZE; n++) {
+               for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
+                       next_peer = peer->next;
+                       key_expire(peer);
+                       peer->pcookie.tstamp = 0;
+               }
+       }
        sys_private = (u_int32)RANDOM & 0xffffffff;
+       L_CLR(&sys_revoketime);
+       if (sys_leap != LEAP_NOTINSYNC)
+               get_systime(&sys_revoketime);
 #ifdef PUBKEY
-       crypto_agree();
+       if (crypto_enable)
+               crypto_agree();
 #endif /* PUBKEY */
 #ifdef DEBUG
        if (debug)
-               printf("key_expire_all: at %lu private %08x next %lu\n",
-                   current_time, sys_private, current_time + sys_revoke);
+               printf("expire_all: at %lu\n", current_time);
 #endif
 }
 #endif /* AUTOKEY */
 
+
 /*
  * unpeer - remove peer structure from hash table and free structure
  */
index 31f88029b3edf8e4e0e024430ba71401170581f5..a49495e47c101f0e19aa8c30277f60073437d339 100644 (file)
@@ -54,6 +54,10 @@ static       double sys_maxd;        /* select error (squares) */
 static double sys_epsil;       /* system error (squares) */
 keyid_t        sys_private;            /* private value for session seed */
 int    sys_manycastserver;     /* 1 => respond to manycast client pkts */
+#ifdef AUTOKEY
+char   *sys_hostname;          /* gethostname() name */
+u_int  sys_hostnamelen;        /* name length (round to word) */
+#endif /* AUTOKEY */
 
 /*
  * Statistics counters
@@ -405,23 +409,34 @@ receive(
                         * packets, the cookie was previously obtained
                         * from the server. For symmetric modes, the
                         * cookie was previously constructed using an
-                        * agreement protocol.
+                        * agreement protocol; however, should PKI be
+                        * unavailable, we construct a fake agreement as
+                        * the EXOR of the peer and host cookies.
                         */
-                       if (hismode == MODE_BROADCAST)
+                       if (hismode == MODE_BROADCAST) {
                                pkeyid = 0;
-                       else if (peer == 0)
+                       } else if (peer == 0) {
                                pkeyid = session_key(
                                    &rbufp->recv_srcadr,
                                    &rbufp->dstadr->sin, 0, sys_private,
                                    0);
-                       else if (hismode == MODE_CLIENT)
+                       } else if (hismode == MODE_CLIENT) {
                                pkeyid = peer->hcookie;
-                       else
+                       } else {
 #ifdef PUBKEY
-                               pkeyid = peer->pcookie;
+                               if (crypto_enable)
+                                       pkeyid = peer->pcookie.key;
+                               else
+                                       pkeyid = peer->pcookie.key;
+                                       
 #else
-                               pkeyid = peer->hcookie ^ peer->pcookie;
+                               if (hismode == MODE_SERVER)
+                                       pkeyid = peer->pcookie.key;
+                               else
+                                       pkeyid = peer->hcookie ^
+                                           peer->pcookie.key;
 #endif /* PUBKEY */
+                       }
 
                        /*
                         * The session key includes both the public
@@ -680,10 +695,21 @@ receive(
            (restrict_mask & RES_DONTTRUST))    /* test 9 */
                peer->flash |= TEST9;           /* access denied */
        if (peer->flags & FLAG_AUTHENABLE) {
+
+               /*
+                * Here we have a little bit of nastyness. Should
+                * authentication fail in client mode, it could either
+                * be a hacker attempting to jam the protocol, or it
+                * could be the server has just refreshed its keys. On
+                * the premiss the later is more likely than the former
+                * and that even the former can't do real evil, we
+                * simply ask for the cookie again.
+                */
                if (!(peer->flags & FLAG_AUTHENTIC)) { /* test 5 */
                        peer->flash |= TEST5;   /* auth failed */
 #ifdef AUTOKEY
-                       peer->pcookie = 0;
+                       if (hismode == MODE_SERVER)
+                               peer->pcookie.tstamp = 0;
 #endif /* AUTOKEY */
                } else if (!(oflags & FLAG_AUTHENABLE)) {
                        report_event(EVNT_PEERAUTH, peer);
@@ -723,8 +749,6 @@ receive(
                } else if (hismode == MODE_SERVER) {
                        if (skeyid == peer->keyid)
                                peer->flash &= ~TEST10;
-                       else
-                               peer->hcookie = 0;
                } else {
                        int i = 0;
 
@@ -979,8 +1003,6 @@ clock_update(void)
 {
        u_char oleap;
        u_char ostratum;
-       int i;
-       struct peer *peer;
 
        /*
         * Reset/adjust the system clock. Do this only if there is a
@@ -1001,24 +1023,19 @@ clock_update(void)
        ostratum = sys_stratum;
        switch (local_clock(sys_peer, sys_offset, sys_epsil)) {
 
-               case -1:
-               /*
-                * Clock is too screwed up. Just exit for now.
-                */
+       /*
+        * Clock is too screwed up. Just exit for now.
+        */
+       case -1:
                report_event(EVNT_SYSFAULT, (struct peer *)0);
                exit(1);
                /*NOTREACHED*/
 
-               case 1:
-               /*
-                * Clock was stepped. Clear filter registers
-                * of all peers.
-                */
-               for (i = 0; i < HASH_SIZE; i++) {
-                       for (peer = peer_hash[i]; peer != 0;
-                               peer =peer->next)
-                               peer_clear(peer);
-               }
+       /*
+        * Clock was stepped. Flush all time values of all peers.
+        */
+       case 1:
+               clear_all();
                NLOG(NLOG_SYNCSTATUS)
                        msyslog(LOG_INFO, "synchronisation lost");
                sys_peer = 0;
@@ -1026,13 +1043,13 @@ clock_update(void)
                report_event(EVNT_CLOCKRESET, (struct peer *)0);
                break;
 
-               default:
-               /*
-                * Update the system stratum, leap bits, root delay,
-                * root dispersion, reference ID and reference time. We
-                * also update select dispersion and max frequency
-                * error.
-                */
+       /*
+        * Update the system stratum, leap bits, root delay, root
+        * dispersion, reference ID and reference time. We also update
+        * select dispersion and max frequency error. If the leap
+        * changes, we gotta reroll the keys.
+        */
+       default:
                sys_stratum = sys_peer->stratum + 1;
                if (sys_stratum == 1)
                        sys_refid = sys_peer->refid;
@@ -1042,16 +1059,11 @@ clock_update(void)
                sys_rootdelay = sys_peer->rootdelay +
                    fabs(sys_peer->delay);
                sys_leap = leap_consensus;
-
-               /*
-                * This is cute. If the leap changes, we gotta reroll
-                * the keys.
-                */
-               if (sys_leap != oleap)
-                       key_expire_all();
        }
-       if (oleap != sys_leap)
+       if (oleap != sys_leap) {
                report_event(EVNT_SYNCCHG, (struct peer *)0);
+               expire_all();
+       }
        if (ostratum != sys_stratum)
                report_event(EVNT_PEERSTCHG, (struct peer *)0);
 }
@@ -1148,14 +1160,6 @@ peer_clear(
 #endif
 #ifdef AUTOKEY
        key_expire(peer);
-#ifdef PUBKEY
-       if (peer->sign != NULL)
-               free(peer->sign);
-       if (peer->dh_public != NULL)
-               free(peer->dh_public);
-       if (peer->dh_key != NULL)
-               free(peer->dh_key);
-#endif /* PUBKEY */
 #endif /* AUTOKEY */
 
        /*
@@ -1180,15 +1184,6 @@ peer_clear(
                peer->filter_epoch[i] = current_time;
        }
        poll_update(peer, peer->minpoll);
-
-       /*
-        * Since we have a chance to correct possible funniness in
-        * our selection of interfaces on a multihomed host, do so
-        * by setting us to no particular interface.
-        * WARNING: do so only in non-broadcast mode!
-        */
-       if (peer->hmode != MODE_BROADCAST)
-               peer->dstadr = any_interface;
 }
 
 
@@ -1859,7 +1854,7 @@ peer_xmit(
                 * are contained in extension fields, each including a
                 * 4-octet length/code word followed by a 4-octet
                 * association ID and optional additional data. Optional
-                * data includes a 4-octet data length field followd by
+                * data includes a 4-octet data length field followed by
                 * the data itself. Request messages are sent from a
                 * configured association; response messages can be sent
                 * from a configured association or can take the fast
@@ -1955,8 +1950,7 @@ peer_xmit(
                case MODE_ACTIVE:
                case MODE_PASSIVE:
 #ifdef PUBKEY
-                       if (crypto_enable && peer->cmmd != 0 &&
-                           peer->cmmd >> 16 != CRYPTO_DH) {
+                       if (crypto_enable && peer->cmmd != 0) {
                                sendlen += crypto_xmit((u_int32 *)&xpkt,
                                    sendlen, (peer->cmmd >> 16) |
                                    CRYPTO_RESP, peer->hcookie,
@@ -1968,29 +1962,11 @@ peer_xmit(
                                sendlen += crypto_xmit((u_int32 *)&xpkt,
                                    sendlen, CRYPTO_NAME, peer->hcookie,
                                    peer->assoc);
-                       } else
-#endif /* PUBKEY */
-                       if (peer->recauto.tstamp == 0) {
-                               sendlen += crypto_xmit((u_int32 *)&xpkt,
-                                   sendlen, CRYPTO_AUTO, peer->hcookie,
-                                   peer->assoc);
-                       } else if (peer->keynumber == peer->sndauto.seq)
-                           {
-                               sendlen += crypto_xmit((u_int32 *)&xpkt,
-                                   sendlen, CRYPTO_AUTO | CRYPTO_RESP,
-                                   peer->hcookie, peer->associd);
-#ifdef PUBKEY
-                       } else if (peer->pcookie == 0) {
+                       } else if (peer->pcookie.tstamp == 0) {
                                sendlen += crypto_xmit((u_int32 *)&xpkt,
                                    sendlen, CRYPTO_DH, peer->hcookie,
                                    peer->assoc);
 #else
-                       } else if (peer->pcookie == 0) {
-                               sendlen += crypto_xmit((u_int32 *)&xpkt,
-                                   sendlen, CRYPTO_PRIV, peer->hcookie,
-                                   peer->assoc);
-#endif /* PUBKEY */
-                       }
                        if (peer->cmmd != 0) {
                                sendlen += crypto_xmit((u_int32 *)&xpkt,
                                    sendlen, (peer->cmmd >> 16) |
@@ -1998,6 +1974,21 @@ peer_xmit(
                                    peer->associd);
                                peer->cmmd = 0;
                        }
+                       if (peer->pcookie.tstamp == 0) {
+                               sendlen += crypto_xmit((u_int32 *)&xpkt,
+                                   sendlen, CRYPTO_PRIV, peer->hcookie,
+                                   peer->assoc);
+#endif /* PUBKEY */
+                       } else if (peer->recauto.tstamp == 0) {
+                               sendlen += crypto_xmit((u_int32 *)&xpkt,
+                                   sendlen, CRYPTO_AUTO, peer->hcookie,
+                                   peer->assoc);
+                       } else if (peer->keynumber == peer->sndauto.seq)
+                           {
+                               sendlen += crypto_xmit((u_int32 *)&xpkt,
+                                   sendlen, CRYPTO_AUTO | CRYPTO_RESP,
+                                   peer->hcookie, peer->associd);
+                       }
                        break;
 
                /*
@@ -2007,7 +1998,8 @@ peer_xmit(
                 * client/server exchange to avoid having to wait until
                 * the next key list regeneration. Otherwise, the poor
                 * dude may die a lingering death until becoming
-                * unreachable and attempting rebirth.
+                * unreachable and attempting rebirth. Note that we ask
+                * for the cookie at each key list regeneration anyway.
                 */
                case MODE_CLIENT:
                        if (peer->cmmd != 0) {
@@ -2025,7 +2017,8 @@ peer_xmit(
                                    peer->assoc);
                        } else
 #endif /* PUBKEY */
-                       if (peer->pcookie == 0) {
+                       if (peer->pcookie.tstamp == 0 ||
+                           peer->keynumber == peer->sndauto.seq) {
                                sendlen += crypto_xmit((u_int32 *)&xpkt,
                                    sendlen, CRYPTO_PRIV, peer->hcookie,
                                    peer->assoc);
index 8d0e1281274490c2cb391da74af6bd1b28ce4446..af68c9ef7fb43af6bd03b46ccac94f3b089c78f8 100644 (file)
@@ -10,7 +10,7 @@
 #include <sys/time.h>
 #include <signal.h>
 #include <sys/signal.h>
-
+#include <unistd.h>
 #include "ntp_machine.h"
 #include "ntpd.h"
 #include "ntp_stdlib.h"
 # include "ntp_timer.h"
 #endif
 
+#ifdef PUBKEY
+#include "ntp_crypto.h"
+#endif /* PUBKEY */
+
 /*
  * These routines provide support for the event timer. The timer is
  * implemented by an interrupt routine which sets a flag once every
@@ -44,6 +48,7 @@ static        u_long hourly_timer;            /* hour timer */
 #ifdef AUTOKEY
 static u_long revoke_timer;            /* keys revoke timer */
 u_long sys_revoke = 1 << KEY_REVOKE;   /* keys revoke timeout */
+l_fp   sys_revoketime;                 /* last key revoke time */
 #endif /* AUTOKEY */
 
 /*
@@ -208,7 +213,7 @@ void
 timer(void)
 {
        register struct peer *peer, *next_peer;
-       int n;
+       u_int n;
 
        current_time += (1<<EVENT_TIMEOUT);
 
@@ -251,13 +256,18 @@ timer(void)
                auth_agekeys();
        }
 
+#ifdef AUTOKEY
        /*
         * Garbage collect old keys and generate new private value
         */
-#ifdef AUTOKEY
        if (revoke_timer <= current_time) {
                revoke_timer += sys_revoke;
-               key_expire_all();
+               expire_all();
+#ifdef DEBUG
+               if (debug)
+                       printf("key expire: at %lu  next %lu\n",
+                           current_time, revoke_timer);
+#endif
        }
 #endif /* AUTOKEY */
 
index 30e7f5fcf6639b4ac748a7ff4ea48bb109d2dd90..12168afa3b6af07d4089cc7554f125996bac4a8d 100644 (file)
@@ -339,6 +339,10 @@ ntpdmain(
 {
        l_fp now;
        char *cp;
+       u_int n;
+#ifdef AUTOKEY
+       char hostname[MAXFILENAME];
+#endif /* AUTOKEY */
        struct recvbuf *rbuflist;
        struct recvbuf *rbuf;
 #ifdef _AIX                    /* HMS: ifdef SIGDANGER? */
@@ -734,13 +738,22 @@ service_main(
        /*
         * Get configuration.  This (including argument list parsing) is
         * done in a separate module since this will definitely be different
-        * for the gizmo board.
+        * for the gizmo board. While at it, save the host name for later
+        * along with the length. The crypto needs this.
         */
        getconfig(argc, argv);
+#ifdef AUTOKEY
+       gethostname(hostname, MAXFILENAME);
+       for (n = strlen(hostname); n % 4 != 0; n++)
+               hostname[n] = 0;
+       sys_hostname = emalloc(n);
+       sys_hostnamelen = n;
+       memcpy(sys_hostname, hostname, n);
 #ifdef PUBKEY
        if (crypto_enable)
                crypto_setup();
 #endif /* PUBKEY */
+#endif /* AUTOKEY */
        initializing = 0;
 
 #if defined(SYS_WINNT) && !defined(NODETACH)