]> git.ipfire.org Git - thirdparty/ntp.git/commitdiff
Changes fro Dave Mills: crypto_recv() improvements, etc.
authorHarlan Stenn <stenn@ntp.org>
Fri, 24 Aug 2001 02:52:15 +0000 (22:52 -0400)
committerHarlan Stenn <stenn@ntp.org>
Fri, 24 Aug 2001 02:52:15 +0000 (22:52 -0400)
bk: 3b85c15f10aj4Ap9VJUaimO2jp2WwQ

include/ntpd.h
ntpd/ntp_crypto.c
ntpd/ntp_proto.c

index b33b6ffab51a942d9873cbdfc2a5451c706664cb..f2c371f6b50a750384d5b4d29ec82fa34dc6c273 100644 (file)
@@ -141,7 +141,7 @@ extern      void    resetmanycast   P((void));
 
 /* ntp_crypto.c */
 #ifdef OPENSSL
-extern void    crypto_recv     P((struct peer *, struct recvbuf *));
+extern void    crypto_recv     P((struct peer *, struct recvbuf *, int));
 extern int     crypto_xmit     P((struct pkt *, int, u_int32 *, keyid_t, u_int));
 extern keyid_t session_key     P((struct sockaddr_in *, struct sockaddr_in *, keyid_t, keyid_t, u_long));
 extern void    make_keylist    P((struct peer *, struct interface *));
index 8db6bd75f4da6126682e40bf04055d9b5887f994..efd28c13ee69591fee798c63bb3c9e1fc1ed281a 100644 (file)
@@ -275,14 +275,16 @@ make_keylist(
        vp->fstamp = cinfo.fstamp;
        vp->vallen = htonl(sizeof(struct autokey));
        vp->siglen = 0;
-       if (vp->sig == NULL)
-               vp->sig = emalloc(sign_siglen);
-       EVP_SignInit(&ctx, digest);
-       EVP_SignUpdate(&ctx, (u_char *)vp, 12);
-       EVP_SignUpdate(&ctx, vp->ptr, sizeof(struct autokey));
-       if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey))
-               vp->siglen = htonl(len);
-       peer->flags |= FLAG_ASSOC;
+       if (vp->tstamp != 0) {
+               if (vp->sig == NULL)
+                       vp->sig = emalloc(sign_siglen);
+               EVP_SignInit(&ctx, digest);
+               EVP_SignUpdate(&ctx, (u_char *)vp, 12);
+               EVP_SignUpdate(&ctx, vp->ptr, sizeof(struct autokey));
+               if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey))
+                       vp->siglen = htonl(len);
+               peer->flags |= FLAG_ASSOC;
+       }
 #if DEBUG
        if (debug)
                printf("make_keys: %d %08x %08x ts %u fs %u poll %d\n",
@@ -306,7 +308,8 @@ make_keylist(
 void
 crypto_recv(
        struct peer *peer,      /* peer structure pointer */
-       struct recvbuf *rbufp   /* packet buffer pointer */
+       struct recvbuf *rbufp,  /* packet buffer pointer */
+       int     is_org          /* timestamps test */
        )
 {
        EVP_MD_CTX ctx;         /* signature context */
@@ -349,11 +352,9 @@ crypto_recv(
        authlen = LEN_PKT_NOMAC;
        while ((has_mac = rbufp->recv_length - authlen) > MAX_MAC_LEN) {
                pkt = (u_int32 *)&rbufp->recv_pkt + authlen / 4;
-               len = ntohl(pkt[0]) & 0x0000ffff;
                code = ntohl(pkt[0]) & 0xffff0000;
+               len = ntohl(pkt[0]) & 0x0000ffff;
                associd = ntohl(pkt[1]);
-               if (associd != 0)
-                       peer->assoc = associd;
 #ifdef DEBUG
                if (debug)
                        printf(
@@ -372,6 +373,8 @@ crypto_recv(
                        peer->flash |= TEST12;
                        return;
                }
+               if (associd != 0)
+                       peer->assoc = associd;
                switch (code) {
 
                /*
@@ -381,9 +384,13 @@ crypto_recv(
                 * defines the signature scheme. This the only message
                 * not validated by signature, but its timestamps are
                 * not used by NTP.
+                *
+                * Discard the message if the status word has already
+                * been received or the response does not match the
+                * request..
                 */
                case CRYPTO_ASSOC | CRYPTO_RESP:
-                       if (peer->crypto)
+                       if (peer->crypto || !is_org)
                                break;
                        vp = (struct value *)&pkt[2];
                        fstamp = ntohl(vp->fstamp);
@@ -430,10 +437,15 @@ crypto_recv(
                 * Decode X509 certificate in ASN.1 format and extract
                 * the data containing, among other things, subject
                 * name and public key.
+                *
+                * Discard the message if the status word has not been
+                * received or the certificate has already been received
+                * or the response does not match the request.
                 */
                case CRYPTO_CERT | CRYPTO_RESP:
-                       if (!peer->crypto)
-                               return;
+                       if (!peer->crypto || peer->crypto &
+                           CRYPTO_FLAG_PROV || !is_org)
+                               break;
                        vp = (struct value *)&pkt[2];
                        tstamp = ntohl(vp->tstamp);
                        fstamp = ntohl(vp->fstamp);
@@ -523,11 +535,16 @@ crypto_recv(
                /*
                 * Roll a random cookie and install in symmetric mode.
                 * Encrypt for the response, which is transmitted later.
+                *
+                * Discard the message if the certificate has not been
+                * received or the cookie has alread been received or
+                * the response does not match the request or another
+                * response has already been queued.
                 */
                case CRYPTO_COOK:
-                       if (!peer->crypto)
-                               return;
-                       if (peer->cmmd != NULL)
+                       if (!(peer->crypto & CRYPTO_FLAG_PROV) ||
+                           peer->crypto & CRYPTO_FLAG_AGREE ||
+                           !is_org || peer->cmmd != NULL)
                                break;
                        if ((vp = crypto_verify(pkt, &peer->cookval,
                            peer)) == NULL)
@@ -571,11 +588,17 @@ crypto_recv(
 
                /*
                 * Decrypt and install session cookie in client and
-                * symmetric modes.
+                * symmetric modes. If the cookie bit is set, the
+                * working cookie is the EXOR of the current and new
+                * values.
+                *
+                * Discard the response if the certificate has not been
+                * received or the response does not match the request.
                 */
                case CRYPTO_COOK | CRYPTO_RESP:
-                       if (!peer->crypto)
-                               return;
+                       if (!(peer->crypto & CRYPTO_FLAG_PROV) ||
+                           !is_org)
+                               break;
                        if ((vp = crypto_verify(pkt, &peer->cookval,
                            peer)) == NULL)
                                break;
@@ -605,7 +628,10 @@ crypto_recv(
                        key_expire(peer);
                        peer->cookval.tstamp = vp->tstamp;
                        peer->cookval.fstamp = vp->fstamp;
-                       peer->pcookie = cookie;
+                       if (peer->crypto & CRYPTO_FLAG_AGREE)
+                               peer->pcookie ^= cookie;
+                       else
+                               peer->pcookie = cookie;
                        if (peer->hmode == MODE_CLIENT &&
                            !(peer->cast_flags & MDF_BCLNT))
                                peer->crypto |= CRYPTO_FLAG_AUTO;
@@ -630,10 +656,14 @@ crypto_recv(
                 * rolled. Ordinarily, this is automatic as this message
                 * is piggybacked on the first NTP packet sent upon
                 * either of these events.
+                *
+                * Discard the response if the certificate has not been
+                * received. A broadcast client or symmetric peer can
+                * receive this response without a matching request.
                 */
                case CRYPTO_AUTO | CRYPTO_RESP:
-                       if (!peer->crypto)
-                               return;
+                       if (!(peer->crypto & CRYPTO_FLAG_PROV))
+                               break;
                        if ((vp = crypto_verify(pkt, &peer->recval,
                            peer)) == NULL)
                                break;
@@ -673,11 +703,18 @@ crypto_recv(
                 * protocol. While the entire table is installed at the
                 * server, presently only the current TAI offset is
                 * provided via the kernel to other applications.
+                *
+                * Discard the request if the certificate has not been
+                * received or the leapseconds table has already been
+                * received or the response does not match the request
+                * or another response has already been queued. Discard
+                * the response if the certificate has not been received
+                * or the response does not match the request.
                 */
                case CRYPTO_TAI:
-                       if (!peer->crypto)
-                               return;
-                       if (peer->cmmd != NULL)
+                       if (!(peer->crypto & CRYPTO_FLAG_PROV) ||
+                           peer->crypto & CRYPTO_FLAG_LEAP ||
+                           !is_org || peer->cmmd != NULL)
                                break;
                        ptr32 = emalloc(len);
                        memcpy(ptr32, pkt, len);
@@ -689,6 +726,9 @@ crypto_recv(
                        /* fall through */
 
                case CRYPTO_TAI | CRYPTO_RESP:
+                       if (!(peer->crypto & CRYPTO_FLAG_PROV) ||
+                           !is_org)
+                               break;
                        if ((vp = crypto_verify(pkt, &peer->tai_leap,
                           peer)) == NULL)
                                break;
index 7948f6620c670880c55956a2a2aca6db997a5729..91c2a6286b86f0d0118a5c36379a0ffd1ff8339a 100644 (file)
@@ -275,11 +275,11 @@ receive(
        struct recvbuf *rbufp
        )
 {
-       register struct peer *peer;
-       register struct pkt *pkt;
-       int     hismode;
-       int     oflags;
-       int     restrict_mask;
+       register struct peer *peer;     /* peer structure pointer */
+       register struct pkt *pkt;       /* receive packet pointer */
+       int     hismode;                /* packet mode */
+       int     oflags;                 /* temp flags */
+       int     restrict_mask;          /* restrict bits */
        int     has_mac;                /* length of MAC field */
        int     authlen;                /* offset of MAC field */
        int     is_authentic;           /* cryptosum ok */
@@ -288,9 +288,9 @@ receive(
 #ifdef OPENSSL
        keyid_t pkeyid, tkeyid;         /* cryptographic keys */
        l_fp    p_org;                  /* originate timestamp */
-       int     is_org;                 /* org matches previous xmt */
-       struct autokey *ap;
-       struct peer *peer2;
+       int     is_org;                 /* loopback ok */
+       struct autokey *ap;             /* autokey structure pointer */
+       struct peer *peer2;             /* aux peer structure pointer */
 #endif /* OPENSSL */
        int retcode = AM_NOMATCH;
 
@@ -692,7 +692,7 @@ receive(
                        return;
 #ifdef OPENSSL
                if (crypto_flags && (peer->flags & FLAG_SKEY)) {
-                       crypto_recv(peer, rbufp);
+                       crypto_recv(peer, rbufp, 1);
                        if (peer->flash)
                                unpeer(peer);
                }
@@ -739,7 +739,7 @@ receive(
        if (!(peer->flags & FLAG_CONFIG) && has_mac) {
                peer->flags |= FLAG_AUTHENABLE;
 #ifdef OPENSSL
-               if (skeyid > NTP_MAXKEY) {
+               if (skeyid > NTP_MAXKEY) {      /* test 5 */
                        if (crypto_flags)
                                peer->flags |= FLAG_SKEY;
                        else
@@ -747,23 +747,26 @@ receive(
                }
 #endif /* OPENSSL */
        }
+       if (peer->hmode == MODE_BROADCAST &&
+           (restrict_mask & RES_DONTTRUST))    /* test 4 */
+               peer->flash |= TEST4;           /* access denied */
+       if (peer->flash) {
+#ifdef DEBUG
+               if (debug)
+                       printf("receive: denied %03x\n",
+                           peer->flash);
+#endif
+               return;
+       }
 
        /*
         * A valid packet must be from an authentic and allowed source.
-        * All packets must pass the authentication allowed tests.
         * Autokey authenticated packets must pass additional tests and
         * public-key authenticated packets must have the credentials
         * verified. If all tests are passed, the packet is forwarded
         * for processing. If not, the packet is discarded and the
         * association demobilized if appropriate.
         */
-       if (peer->hmode == MODE_BROADCAST &&
-           (restrict_mask & RES_DONTTRUST))    /* test 4 */
-               peer->flash |= TEST4;           /* access denied */
-#ifdef OPENSSL
-       NTOHL_FP(&pkt->org, &p_org);
-       is_org = L_ISEQU(&peer->xmt, &p_org);
-#endif /* OPENSSL */
        if (peer->flags & FLAG_AUTHENABLE) {
                if (!(peer->flags & FLAG_AUTHENTIC)) /* test 5 */
                        peer->flash |= TEST5;   /* auth failed */
@@ -781,6 +784,10 @@ receive(
         * is very likely a valid response to one sent earlier. See
         * below for more jitterbug in other error cases.
         */
+#ifdef OPENSSL
+       NTOHL_FP(&pkt->org, &p_org);
+       is_org = L_ISEQU(&peer->xmt, &p_org);
+#endif /* OPENSSL */
        if (peer->flash) {
 #ifdef OPENSSL
                switch (hismode) {
@@ -789,16 +796,13 @@ receive(
                 * In client mode if the packet matches the last one
                 * sent and is a crypto-NAK, the server has either
                 * restarted or refreshed the private value, so we
-                * retrieve the server cookie and continue where we left
+                * start over.
                 * off.
                 */
                case MODE_SERVER:
                        if (is_org && has_mac == 4 && pkt->exten[0] ==
-                           0) {
-                               key_expire(peer);
-                               peer->crypto &= ~(CRYPTO_FLAG_AUTO |
-                                   CRYPTO_FLAG_AGREE);
-                       }
+                           0)
+                               peer_clear(peer);
                        break;
 
                /*
@@ -819,7 +823,8 @@ receive(
 #endif /* OPENSSL */
 #ifdef DEBUG
                if (debug)
-                       printf("receive: bad auth %03x\n", peer->flash);
+                       printf("receive: bad auth %03x\n",
+                           peer->flash);
 #endif
                return;
        }
@@ -830,20 +835,24 @@ receive(
         *
         * 1. If there is no key or the key is not auto, do nothing.
         *
-        * 2. If an extension field contains a verified signature, it is
+        * 2. If this packet is in response to the one just previously
+        *    sent or from a broadcast server, do the extension fields.
+        *    Otherwise, assume bogosity and bail out.
+        *
+        * 3. If an extension field contains a verified signature, it is
         *    self-authenticated and we sit the dance.
         *
-        * 3. If this is a server reply, check only to see that the
+        * 4. If this is a server reply, check only to see that the
         *    transmitted key ID matches the received key ID.
         *
-        * 4. Check to see that one or more hashes of the current key ID
+        * 5. Check to see that one or more hashes of the current key ID
         *    matches the previous key ID or ultimate original key ID
         *    obtained from the broadcaster or symmetric peer. If no
         *    match, sit the dance and wait for timeout.
         */
        if (crypto_flags && (peer->flags & FLAG_SKEY)) {
                peer->flash |= TEST10;
-               crypto_recv(peer, rbufp);
+               crypto_recv(peer, rbufp, is_org);
                if (peer->flash & TEST12) {
                        /* fall through */
 
@@ -872,25 +881,28 @@ receive(
                }
 
                /*
-                * This is delicious. Ordinarily, we kick out all errors
-                * at this point; however, in symmetric mode and just
-                * warming up, an unsynchronized peer must inject the
-                * timestamps, even if it fails further up the road. So,
-                * let the dude by here, but only if the jerk is not yet
-                * reachable. After that, he's on his own.
+                * If errors flash at this point and loopback, clamp the
+                * poll to minimum. If the certificate has been stored,
+                * scratch the association. If the server is not
+                * reachable, assume this is the first symmetric mode
+                * packet that warmed up the association and let it by.
+                * It will die later after leaving the originate and
+                * receive timestamp in the dust for the reply.
                 */
-               if (peer->flash && is_org && (peer->crypto &
-                   CRYPTO_FLAG_PROV)) {
+               if (peer->flash && is_org) {
+                       poll_update(peer, peer->minpoll);
+                       if (peer->crypto & CRYPTO_FLAG_PROV) {
+                               if (peer->flags & FLAG_CONFIG)
+                                       peer_clear(peer);
+                               else
+                                       unpeer(peer);
 #ifdef DEBUG
-                       if (debug)
-                               printf("packet: bad crypto %03x\n",
-                                   peer->flash);
+                               if (debug)
+                                       printf("packet: bad crypto %03x\n",
+                                           peer->flash);
 #endif
-                       if (!(peer->flags & FLAG_CONFIG))
-                               unpeer(peer);
-                       else
-                               peer_clear(peer);
-                       return;
+                               return;
+                       }
                }
                if (!(peer->crypto & CRYPTO_FLAG_PROV))
                        peer->flash |= TEST11;