/* 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 *));
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",
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 */
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(
peer->flash |= TEST12;
return;
}
+ if (associd != 0)
+ peer->assoc = associd;
switch (code) {
/*
* 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);
* 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);
/*
* 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)
/*
* 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;
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;
* 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;
* 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);
/* 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;
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 */
#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;
return;
#ifdef OPENSSL
if (crypto_flags && (peer->flags & FLAG_SKEY)) {
- crypto_recv(peer, rbufp);
+ crypto_recv(peer, rbufp, 1);
if (peer->flash)
unpeer(peer);
}
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
}
#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 */
* 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) {
* 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;
/*
#endif /* OPENSSL */
#ifdef DEBUG
if (debug)
- printf("receive: bad auth %03x\n", peer->flash);
+ printf("receive: bad auth %03x\n",
+ peer->flash);
#endif
return;
}
*
* 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 */
}
/*
- * 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;