📄 ntp_crypto.c
字号:
fp = emalloc(len); memcpy(fp, ep, len); temp32 = CRYPTO_RESP; fp->opcode |= htonl(temp32); peer->cmmd = fp; /* fall through */ case CRYPTO_ASSOC | CRYPTO_RESP: /* * Discard the message if it has already been * stored or the message has been amputated. */ if (peer->crypto) break; if (vallen == 0 || vallen > MAXHOSTNAME || len < VALUE_LEN + vallen) { rval = XEVNT_LEN; break; } /* * Check the identity schemes are compatible. If * the client has PC, the server must have PC, * in which case the server public key and * identity are presumed valid, so we skip the * certificate and identity exchanges and move * immediately to the cookie exchange which * confirms the server signature. */#ifdef DEBUG if (debug) printf( "crypto_recv: ident host 0x%x server 0x%x\n", crypto_flags, fstamp);#endif temp32 = (crypto_flags | ident_scheme) & fstamp & CRYPTO_FLAG_MASK; if (crypto_flags & CRYPTO_FLAG_PRIV) { if (!(fstamp & CRYPTO_FLAG_PRIV)) { rval = XEVNT_KEY; break; } else { fstamp |= CRYPTO_FLAG_VALID | CRYPTO_FLAG_VRFY | CRYPTO_FLAG_SIGN; } /* * In symmetric modes it is an error if either * peer requests identity and the other peer * does not support it. */ } else if ((hismode == MODE_ACTIVE || hismode == MODE_PASSIVE) && ((crypto_flags | fstamp) & CRYPTO_FLAG_MASK) && !temp32) { rval = XEVNT_KEY; break; /* * It is an error if the client requests * identity and the server does not support it. */ } else if (hismode == MODE_CLIENT && (fstamp & CRYPTO_FLAG_MASK) && !temp32) { rval = XEVNT_KEY; break; } /* * Otherwise, the identity scheme(s) are those * that both client and server support. */ fstamp = temp32 | (fstamp & ~CRYPTO_FLAG_MASK); /* * Discard the message if the signature digest * NID is not supported. */ temp32 = (fstamp >> 16) & 0xffff; dp = (const EVP_MD *)EVP_get_digestbynid(temp32); if (dp == NULL) { rval = XEVNT_MD; break; } /* * Save status word, host name and message * digest/signature type. */ peer->crypto = fstamp; peer->digest = dp; peer->subject = emalloc(vallen + 1); memcpy(peer->subject, ep->pkt, vallen); peer->subject[vallen] = '\0'; peer->issuer = emalloc(vallen + 1); strcpy(peer->issuer, peer->subject); temp32 = (fstamp >> 16) & 0xffff; sprintf(statstr, "flags 0x%x host %s signature %s", fstamp, peer->subject, OBJ_nid2ln(temp32)); record_crypto_stats(&peer->srcadr, statstr);#ifdef DEBUG if (debug) printf("crypto_recv: %s\n", statstr);#endif break; /* * Decode X509 certificate in ASN.1 format and extract * the data containing, among other things, subject * name and public key. In the default identification * scheme, the certificate trail is followed to a self * signed trusted certificate. */ case CRYPTO_CERT | CRYPTO_RESP: /* * Discard the message if invalid. */ 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; /* * If we snatch the certificate before the * server certificate has been signed by its * server, it will be self signed. When it is, * we chase the certificate issuer, which the * server has, and keep going until a self * signed trusted certificate is found. Be sure * to update the issuer field, since it may * change. */ if (peer->issuer != NULL) free(peer->issuer); peer->issuer = emalloc(strlen(cinfo->issuer) + 1); strcpy(peer->issuer, cinfo->issuer); /* * We plug in the public key and lifetime from * the first certificate received. However, note * that this certificate might not be signed by * the server, so we can't check the * signature/digest NID. */ if (peer->pkey == NULL) { ptr = (u_char *)cinfo->cert.ptr; cert = d2i_X509(NULL, &ptr, ntohl(cinfo->cert.vallen)); peer->pkey = X509_get_pubkey(cert); X509_free(cert); } peer->flash &= ~TEST8; temp32 = cinfo->nid; sprintf(statstr, "cert %s 0x%x %s (%u) fs %u", cinfo->subject, 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; /* * Schnorr (IFF)identity scheme. This scheme is designed * for use with shared secret group keys and where the * certificate may be generated by a third party. The * client sends a challenge to the server, which * performs a calculation and returns the result. A * positive result is possible only if both client and * server contain the same secret group key. */ case CRYPTO_IFF | CRYPTO_RESP: /* * Discard the message if invalid or certificate * trail not trusted. */ if (!(peer->crypto & CRYPTO_FLAG_VALID)) { rval = XEVNT_ERR; break; } if ((rval = crypto_verify(ep, NULL, peer)) != XEVNT_OK) break; /* * If the the challenge matches the response, * the certificate public key, as well as the * server public key, signatyre and identity are * all verified at the same time. The server is * declared trusted, so we skip further * certificate stages and move immediately to * the cookie stage. */ if ((rval = crypto_iff(ep, peer)) != XEVNT_OK) break; peer->crypto |= CRYPTO_FLAG_VRFY | CRYPTO_FLAG_PROV; peer->flash &= ~TEST8; sprintf(statstr, "iff fs %u", ntohl(ep->fstamp)); record_crypto_stats(&peer->srcadr, statstr);#ifdef DEBUG if (debug) printf("crypto_recv: %s\n", statstr);#endif break; /* * Guillou-Quisquater (GQ) identity scheme. This scheme * is designed for use with public certificates carrying * the GQ public key in an extension field. The client * sends a challenge to the server, which performs a * calculation and returns the result. A positive result * is possible only if both client and server contain * the same group key and the server has the matching GQ * private key. */ case CRYPTO_GQ | CRYPTO_RESP: /* * Discard the message if invalid or certificate * trail not trusted. */ if (!(peer->crypto & CRYPTO_FLAG_VALID)) { rval = XEVNT_ERR; break; } if ((rval = crypto_verify(ep, NULL, peer)) != XEVNT_OK) break; /* * If the the challenge matches the response, * the certificate public key, as well as the * server public key, signatyre and identity are * all verified at the same time. The server is * declared trusted, so we skip further * certificate stages and move immediately to * the cookie stage. */ if ((rval = crypto_gq(ep, peer)) != XEVNT_OK) break; peer->crypto |= CRYPTO_FLAG_VRFY | CRYPTO_FLAG_PROV; peer->flash &= ~TEST8; sprintf(statstr, "gq fs %u", ntohl(ep->fstamp)); record_crypto_stats(&peer->srcadr, statstr);#ifdef DEBUG if (debug) printf("crypto_recv: %s\n", statstr);#endif break; /* * MV */ case CRYPTO_MV | CRYPTO_RESP: /* * Discard the message if invalid or certificate * trail not trusted. */ if (!(peer->crypto & CRYPTO_FLAG_VALID)) { rval = XEVNT_ERR; break; } if ((rval = crypto_verify(ep, NULL, peer)) != XEVNT_OK) break; /* * If the the challenge matches the response, * the certificate public key, as well as the * server public key, signatyre and identity are * all verified at the same time. The server is * declared trusted, so we skip further * certificate stages and move immediately to * the cookie stage. */ if ((rval = crypto_mv(ep, peer)) != XEVNT_OK) break; peer->crypto |= CRYPTO_FLAG_VRFY | CRYPTO_FLAG_PROV; peer->flash &= ~TEST8; sprintf(statstr, "mv fs %u", ntohl(ep->fstamp)); record_crypto_stats(&peer->srcadr, statstr);#ifdef DEBUG if (debug) printf("crypto_recv: %s\n", statstr);#endif break; /* * Cookie request in symmetric modes. Roll a random * cookie and install in symmetric mode. Encrypt for the * response, which is transmitted later. */ case CRYPTO_COOK: /* * Discard the message if invalid or certificate * trail not trusted. */ if (!(peer->crypto & CRYPTO_FLAG_VALID)) { rval = XEVNT_ERR; break; } if ((rval = crypto_verify(ep, NULL, peer)) != XEVNT_OK) break; /* * Pass the extension field to the transmit * side. If already agreed, walk away. */ fp = emalloc(len); memcpy(fp, ep, len); temp32 = CRYPTO_RESP; fp->opcode |= htonl(temp32); peer->cmmd = fp; if (peer->crypto & CRYPTO_FLAG_AGREE) { peer->flash &= ~TEST8; break; } /* * Install cookie values and light the cookie * bit. The transmit side will pick up and * encrypt it for the response. */ key_expire(peer); peer->cookval.tstamp = ep->tstamp; peer->cookval.fstamp = ep->fstamp; RAND_bytes((u_char *)&peer->pcookie, 4); peer->crypto &= ~CRYPTO_FLAG_AUTO; peer->crypto |= CRYPTO_FLAG_AGREE; peer->flash &= ~TEST8; sprintf(statstr, "cook %x ts %u fs %u", peer->pcookie, ntohl(ep->tstamp), ntohl(ep->fstamp)); record_crypto_stats(&peer->srcadr, statstr);#ifdef DEBUG if (debug) printf("crypto_recv: %s\n", statstr);#endif break; /* * Cookie response in client and symmetric modes. If the * cookie bit is set, the working cookie is the EXOR of * the current and new values. */ case CRYPTO_COOK | CRYPTO_RESP: /* * Discard the message if invalid or identity * not confirmed or signature not verified with * respect to the cookie values. */ if (!(peer->crypto & CRYPTO_FLAG_VRFY)) { rval = XEVNT_ERR; break; } if ((rval = crypto_verify(ep, &peer->cookval, peer)) != XEVNT_OK) break; /* * Decrypt the cookie, hunting all the time for * errors. */ if (vallen == (u_int) EVP_PKEY_size(host_pkey)) { RSA_private_decrypt(vallen, (u_char *)ep->pkt, (u_char *)&temp32, host_pkey->pkey.rsa, RSA_PKCS1_OAEP_PADDING); cookie = ntohl(temp32); } else { rval = XEVNT_CKY; break; } /* * Install cookie values and light the cookie * bit. If this is not broadcast client mode, we * are done here. */ key_expire(peer); peer->cookval.tstamp = ep->tstamp; peer->cookval.fstamp = ep->fstamp; 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; else peer->crypto &= ~CRYPTO_FLAG_AUTO; peer->crypto |= CRYPTO_FLAG_AGREE; peer->flash &= ~TEST8; sprintf(statstr, "cook %x ts %u fs %u", peer->pcookie, ntohl(ep->tstamp), ntohl(ep->fstamp)); record_crypto_stats(&peer->srcadr, statstr);#ifdef DEBUG if (debug) printf("crypto_recv: %s\n", statstr);#endif break; /* * Install autokey values in broadcast client and * symmetric modes. We have to do this every time the * sever/peer cookie changes or a new keylist is * rolled. Ordinarily, this is automatic as this message * is piggybacked on the first NTP packet sent upon * either of these events. Note that a broadcast client * or symmetric peer can receive this response without a * matching request. */ case CRYPTO_AUTO | CRYPTO_RESP: /* * Discard the message if invalid or identity * not confirmed or signature not verified with * respect to the receive autokey values. */ if (!(peer->crypto & CRYPTO_FLAG_VRFY)) { rval = XEVNT_ERR; break; } if ((rval = crypto_verify(ep, &peer->recval, peer)) != XEVNT_OK) break; /* * Install autokey values and light the * autokey bit. This is not hard. */ if (peer->recval.ptr == NULL) peer->recval.ptr = emalloc(sizeof(struct autokey)); bp = (struct autokey *)peer->recval.ptr; peer->recval.tstamp = ep->tstamp; peer->recval.fstamp = ep->fstamp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -