📄 ntp_crypto.c
字号:
ap = (struct autokey *)ep->pkt; bp->seq = ntohl(ap->seq); bp->key = ntohl(ap->key); peer->pkeyid = bp->key; peer->crypto |= CRYPTO_FLAG_AUTO; peer->flash &= ~TEST8; sprintf(statstr, "auto seq %d key %x ts %u fs %u", bp->seq, bp->key, ntohl(ep->tstamp), ntohl(ep->fstamp)); record_crypto_stats(&peer->srcadr, statstr);#ifdef DEBUG if (debug) printf("crypto_recv: %s\n", statstr);#endif break; /* * X509 certificate sign response. Validate the * certificate signed by the server and install. Later * this can be provided to clients of this server in * lieu of the self signed certificate in order to * validate the public key. */ case CRYPTO_SIGN | CRYPTO_RESP: /* * Discard the message if invalid or not * proventic. */ if (!(peer->crypto & CRYPTO_FLAG_PROV)) { rval = XEVNT_ERR; break; } if ((rval = crypto_verify(ep, NULL, peer)) != XEVNT_OK) break; /* * Scan the certificate list to delete old * versions and link the newest version first on * the list. */ if ((rval = cert_install(ep, peer)) != XEVNT_OK) break; peer->crypto |= CRYPTO_FLAG_SIGN; peer->flash &= ~TEST8; temp32 = cinfo->nid; sprintf(statstr, "sign %s 0x%x %s (%u) fs %u", cinfo->issuer, cinfo->flags, OBJ_nid2ln(temp32), temp32, ntohl(ep->fstamp)); record_crypto_stats(&peer->srcadr, statstr);#ifdef DEBUG if (debug) printf("crypto_recv: %s\n", statstr);#endif break; /* * Install leapseconds table in symmetric modes. This * table is proventicated to the NIST primary servers, * either by copying the file containing the table from * a NIST server to a trusted server or directly using * this protocol. While the entire table is installed at * the server, presently only the current TAI offset is * provided via the kernel to other applications. */ case CRYPTO_TAI: /* * Discard the message if invalid. */ if ((rval = crypto_verify(ep, NULL, peer)) != XEVNT_OK) break; /* * Pass the extension field to the transmit * side. Continue below if a leapseconds table * accompanies the message. */ fp = emalloc(len); memcpy(fp, ep, len); temp32 = CRYPTO_RESP; fp->opcode |= htonl(temp32); peer->cmmd = fp; if (len <= VALUE_LEN) { peer->flash &= ~TEST8; break; } /* fall through */ case CRYPTO_TAI | CRYPTO_RESP: /* * If this is a response, discard the message if * signature not verified with respect to the * leapsecond table values. */ if (peer->cmmd == NULL) { if ((rval = crypto_verify(ep, &peer->tai_leap, peer)) != XEVNT_OK) break; } /* * Initialize peer variables with latest update. */ peer->tai_leap.tstamp = ep->tstamp; peer->tai_leap.fstamp = ep->fstamp; peer->tai_leap.vallen = ep->vallen; /* * Install the new table if there is no stored * table or the new table is more recent than * the stored table. Since a filestamp may have * changed, recompute the signatures. */ if (ntohl(peer->tai_leap.fstamp) > ntohl(tai_leap.fstamp)) { tai_leap.fstamp = ep->fstamp; tai_leap.vallen = ep->vallen; if (tai_leap.ptr != NULL) free(tai_leap.ptr); tai_leap.ptr = emalloc(vallen); memcpy(tai_leap.ptr, ep->pkt, vallen); crypto_update(); } crypto_flags |= CRYPTO_FLAG_TAI; peer->crypto |= CRYPTO_FLAG_LEAP; peer->flash &= ~TEST8; sprintf(statstr, "leap %u ts %u fs %u", vallen, ntohl(ep->tstamp), ntohl(ep->fstamp)); record_crypto_stats(&peer->srcadr, statstr);#ifdef DEBUG if (debug) printf("crypto_recv: %s\n", statstr);#endif break; /* * We come here in symmetric modes for miscellaneous * commands that have value fields but are processed on * the transmit side. All we need do here is check for * valid field length. Remaining checks are below and on * the transmit side. */ case CRYPTO_CERT: case CRYPTO_IFF: case CRYPTO_GQ: case CRYPTO_MV: case CRYPTO_SIGN: if (len < VALUE_LEN) { rval = XEVNT_LEN; break; } /* fall through */ /* * We come here for miscellaneous requests and unknown * requests and responses. If an unknown response or * error, forget it. If a request, save the extension * field for later. Unknown requests will be caught on * the transmit side. */ default: if (code & (CRYPTO_RESP | CRYPTO_ERROR)) { rval = XEVNT_ERR; } else if ((rval = crypto_verify(ep, NULL, peer)) == XEVNT_OK) { fp = emalloc(len); memcpy(fp, ep, len); temp32 = CRYPTO_RESP; fp->opcode |= htonl(temp32); peer->cmmd = fp; } } /* * We don't log length/format/timestamp errors and * duplicates, which are log clogging vulnerabilities. * The first error found terminates the extension field * scan and we return the laundry to the caller. A * length/format/timestamp error on transmit is * cheerfully ignored, as the message is not sent. */ if (rval > XEVNT_TSP) { sprintf(statstr, "error %x opcode %x ts %u fs %u", rval, code, tstamp, fstamp); record_crypto_stats(&peer->srcadr, statstr); report_event(rval, peer);#ifdef DEBUG if (debug) printf("crypto_recv: %s\n", statstr);#endif break; } else if (rval > XEVNT_OK && (code & CRYPTO_RESP)) { rval = XEVNT_OK; } authlen += len; } return (rval);}/* * crypto_xmit - construct extension fields * * This routine is called both when an association is configured and * when one is not. The only case where this matters is to retrieve the * autokey information, in which case the caller has to provide the * association ID to match the association. * * Returns length of extension field. */intcrypto_xmit( struct pkt *xpkt, /* transmit packet pointer */ struct sockaddr_storage *srcadr_sin, /* active runway */ int start, /* offset to extension field */ struct exten *ep, /* extension pointer */ keyid_t cookie /* session cookie */ ){ u_int32 *pkt; /* packet pointer */ struct peer *peer; /* peer structure pointer */ u_int opcode; /* extension field opcode */ struct exten *fp; /* extension pointers */ struct cert_info *cp, *xp; /* certificate info/value pointer */ char certname[MAXHOSTNAME + 1]; /* subject name buffer */ char statstr[NTP_MAXSTRLEN]; /* statistics for filegen */ tstamp_t tstamp; u_int vallen; u_int len; struct value vtemp; associd_t associd; int rval; keyid_t tcookie; /* * Generate the requested extension field request code, length * and association ID. If this is a response and the host is not * synchronized, light the error bit and go home. */ pkt = (u_int32 *)xpkt + start / 4; fp = (struct exten *)pkt; opcode = ntohl(ep->opcode); associd = (associd_t) ntohl(ep->associd); fp->associd = htonl(associd); len = 8; rval = XEVNT_OK; tstamp = crypto_time(); switch (opcode & 0xffff0000) { /* * Send association request and response with status word and * host name. Note, this message is not signed and the filestamp * contains only the status word. */ case CRYPTO_ASSOC | CRYPTO_RESP: len += crypto_send(fp, &hostval); fp->fstamp = htonl(crypto_flags); break; case CRYPTO_ASSOC: len += crypto_send(fp, &hostval); fp->fstamp = htonl(crypto_flags | ident_scheme); break; /* * Send certificate request. Use the values from the extension * field. */ case CRYPTO_CERT: memset(&vtemp, 0, sizeof(vtemp)); vtemp.tstamp = ep->tstamp; vtemp.fstamp = ep->fstamp; vtemp.vallen = ep->vallen; vtemp.ptr = (u_char *)ep->pkt; len += crypto_send(fp, &vtemp); break; /* * Send certificate response or sign request. Use the values * from the certificate cache. If the request contains no * subject name, assume the name of this host. This is for * backwards compatibility. Private certificates are never sent. */ case CRYPTO_SIGN: case CRYPTO_CERT | CRYPTO_RESP: vallen = ntohl(ep->vallen); if (vallen == 8) { strcpy(certname, sys_hostname); } else if (vallen == 0 || vallen > MAXHOSTNAME) { rval = XEVNT_LEN; break; } else { memcpy(certname, ep->pkt, vallen); certname[vallen] = '\0'; } /* * Find all certificates with matching subject. If a * self-signed, trusted certificate is found, use that. * If not, use the first one with matching subject. A * private certificate is never divulged or signed. */ xp = NULL; for (cp = cinfo; cp != NULL; cp = cp->link) { if (cp->flags & CERT_PRIV) continue; if (strcmp(certname, cp->subject) == 0) { if (xp == NULL) xp = cp; if (strcmp(certname, cp->issuer) == 0 && cp->flags & CERT_TRUST) { xp = cp; break; } } } /* * Be careful who you trust. If not yet synchronized, * give back an empty response. If certificate not found * or beyond the lifetime, return an error. This is to * avoid a bad dude trying to get an expired certificate * re-signed. Otherwise, send it. * * Note the timestamp and filestamp are taken from the * certificate value structure. For all certificates the * timestamp is the latest signature update time. For * host and imported certificates the filestamp is the * creation epoch. For signed certificates the filestamp * is the creation epoch of the trusted certificate at * the base of the certificate trail. In principle, this * allows strong checking for signature masquerade. */ if (tstamp == 0) break; if (xp == NULL) rval = XEVNT_CRT; else if (tstamp < xp->first || tstamp > xp->last) rval = XEVNT_SRV; else len += crypto_send(fp, &xp->cert); break; /* * Send challenge in Schnorr (IFF) identity scheme. */ case CRYPTO_IFF: if ((peer = findpeerbyassoc(ep->pkt[0])) == NULL) { rval = XEVNT_ERR; break; } if ((rval = crypto_alice(peer, &vtemp)) == XEVNT_OK) { len += crypto_send(fp, &vtemp); value_free(&vtemp); } break; /* * Send response in Schnorr (IFF) identity scheme. */ case CRYPTO_IFF | CRYPTO_RESP: if ((rval = crypto_bob(ep, &vtemp)) == XEVNT_OK) { len += crypto_send(fp, &vtemp); value_free(&vtemp); } break; /* * Send challenge in Guillou-Quisquater (GQ) identity scheme. */ case CRYPTO_GQ: if ((peer = findpeerbyassoc(ep->pkt[0])) == NULL) { rval = XEVNT_ERR; break; } if ((rval = crypto_alice2(peer, &vtemp)) == XEVNT_OK) { len += crypto_send(fp, &vtemp); value_free(&vtemp); } break; /* * Send response in Guillou-Quisquater (GQ) identity scheme. */ case CRYPTO_GQ | CRYPTO_RESP: if ((rval = crypto_bob2(ep, &vtemp)) == XEVNT_OK) { len += crypto_send(fp, &vtemp); value_free(&vtemp); } break; /* * Send challenge in MV identity scheme. */ case CRYPTO_MV: if ((peer = findpeerbyassoc(ep->pkt[0])) == NULL) { rval = XEVNT_ERR; break; } if ((rval = crypto_alice3(peer, &vtemp)) == XEVNT_OK) { len += crypto_send(fp, &vtemp); value_free(&vtemp); } break; /* * Send response in MV identity scheme. */ case CRYPTO_MV | CRYPTO_RESP: if ((rval = crypto_bob3(ep, &vtemp)) == XEVNT_OK) { len += crypto_send(fp, &vtemp); value_free(&vtemp); } break; /* * Send certificate sign response. The integrity of the request * certificate has already been verified on the receive side. * Sign the response using the local server key. Use the * filestamp from the request and use the timestamp as the * current time. Light the error bit if the certificate is * invalid or contains an unverified signature. */ case CRYPTO_SIGN | CRYPTO_RESP: if ((rval = cert_sign(ep, &vtemp)) == XEVNT_OK) len += crypto_send(fp, &vtemp); value_free(&vtemp); break; /* * Send public key and signature. Use the values from the public * key. */ case CRYPTO_COOK: len += crypto_send(fp, &pubkey); break; /* * Encrypt and send cookie and signature. Light the error bit if * anything goes wrong. */ case CRYPTO_COOK | CRYPTO_RESP: if ((opcode & 0xffff) < VALUE_LEN) { rval = XEVNT_LEN; break; } if (PKT_MODE(xpkt->li_vn_mode) == MODE_SERVER) { tcookie = cookie; } else { if ((peer = findpeerbyassoc(associd)) == NULL) { rval = XEVNT_ERR; break; } tcookie = peer->pcookie; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -