⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ntp_crypto.c

📁 网络时间协议NTP 源码 版本v4.2.0b 该源码用于linux平台下
💻 C
📖 第 1 页 / 共 5 页
字号:
		if ((rval = crypto_encrypt(ep, &vtemp, &tcookie)) ==		    XEVNT_OK)			len += crypto_send(fp, &vtemp);		value_free(&vtemp);		break;	/*	 * Find peer and send autokey data and signature in broadcast	 * server and symmetric modes. Use the values in the autokey	 * structure. If no association is found, either the server has	 * restarted with new associations or some perp has replayed an	 * old message, in which case light the error bit.	 */	case CRYPTO_AUTO | CRYPTO_RESP:		if ((peer = findpeerbyassoc(associd)) == NULL) {			rval = XEVNT_ERR;			break;		}		peer->flags &= ~FLAG_ASSOC;		len += crypto_send(fp, &peer->sndval);		break;	/*	 * Send leapseconds table and signature. Use the values from the	 * tai structure. If no table has been loaded, just send an	 * empty request.	 */	case CRYPTO_TAI:	case CRYPTO_TAI | CRYPTO_RESP:		if (crypto_flags & CRYPTO_FLAG_TAI)			len += crypto_send(fp, &tai_leap);		break;	/*	 * Default - Fall through for requests; for unknown responses,	 * flag as error.	 */	default:		if (opcode & CRYPTO_RESP)			rval = XEVNT_ERR;	}	/*	 * In case of error, flame the log. If a request, toss the	 * puppy; if a response, return so the sender can flame, too.	 */	if (rval != XEVNT_OK) {		opcode |= CRYPTO_ERROR;		sprintf(statstr, "error %x opcode %x", rval, opcode);		record_crypto_stats(srcadr_sin, statstr);		report_event(rval, NULL);#ifdef DEBUG		if (debug)			printf("crypto_xmit: %s\n", statstr);#endif		if (!(opcode & CRYPTO_RESP))			return (0);	}	/*	 * Round up the field length to a multiple of 8 bytes and save	 * the request code and length.	 */	len = ((len + 7) / 8) * 8;	fp->opcode = htonl((opcode & 0xffff0000) | len);#ifdef DEBUG	if (debug)		printf(		    "crypto_xmit: flags 0x%x ext offset %d len %u code 0x%x assocID %d\n",		    crypto_flags, start, len, opcode >> 16, associd);#endif	return (len);}/* * crypto_verify - parse and verify the extension field and value * * Returns * XEVNT_OK	success * XEVNT_LEN	bad field format or length * XEVNT_TSP	bad timestamp * XEVNT_FSP	bad filestamp * XEVNT_PUB	bad or missing public key * XEVNT_SGL	bad signature length * XEVNT_SIG	signature not verified * XEVNT_ERR	protocol error */static intcrypto_verify(	struct exten *ep,	/* extension pointer */	struct value *vp,	/* value pointer */	struct peer *peer	/* peer structure pointer */	){	EVP_PKEY *pkey;		/* server public key */	EVP_MD_CTX ctx;		/* signature context */	tstamp_t tstamp, tstamp1 = 0; /* timestamp */	tstamp_t fstamp, fstamp1 = 0; /* filestamp */	u_int	vallen;		/* value length */	u_int	siglen;		/* signature length */	u_int	opcode, len;	int	i;	/*	 * We require valid opcode and field lengths, timestamp,	 * filestamp, public key, digest, signature length and	 * signature, where relevant. Note that preliminary length	 * checks are done in the main loop.	 */	len = ntohl(ep->opcode) & 0x0000ffff;	opcode = ntohl(ep->opcode) & 0xffff0000;	/*	 * Check for valid operation code and protocol. The opcode must	 * not have the error bit set. If a response, it must have a	 * value header. If a request and does not contain a value	 * header, no need for further checking.	 */	if (opcode & CRYPTO_ERROR)		return (XEVNT_ERR); 	if (opcode & CRYPTO_RESP) { 		if (len < VALUE_LEN)			return (XEVNT_LEN);	} else { 		if (len < VALUE_LEN)			return (XEVNT_OK);	}	/*	 * We have a value header. Check for valid field lengths. The	 * field length must be long enough to contain the value header,	 * value and signature. Note both the value and signature fields	 * are rounded up to the next word.	 */	vallen = ntohl(ep->vallen);	i = (vallen + 3) / 4;	siglen = ntohl(ep->pkt[i++]);	if (len < VALUE_LEN + ((vallen + 3) / 4) * 4 + ((siglen + 3) /	    4) * 4)		return (XEVNT_LEN);	/*	 * Punt if this is a response with no data. Punt if this is a	 * request and a previous response is pending. 	 */	if (opcode & CRYPTO_RESP) {		if (vallen == 0)			return (XEVNT_LEN);	} else {		if (peer->cmmd != NULL)			return (XEVNT_LEN);	}	/*	 * Check for valid timestamp and filestamp. If the timestamp is	 * zero, the sender is not synchronized and signatures are	 * disregarded. If not, the timestamp must not precede the	 * filestamp. The timestamp and filestamp must not precede the	 * corresponding values in the value structure, if present. Once	 * the autokey values have been installed, the timestamp must	 * always be later than the corresponding value in the value	 * structure. Duplicate timestamps are illegal once the cookie	 * has been validated.	 */	tstamp = ntohl(ep->tstamp);	fstamp = ntohl(ep->fstamp);	if (tstamp == 0)		return (XEVNT_OK);	if (tstamp < fstamp)		return (XEVNT_TSP);	if (vp != NULL) {		tstamp1 = ntohl(vp->tstamp);		fstamp1 = ntohl(vp->fstamp);		if ((tstamp < tstamp1 || (tstamp == tstamp1 &&		    (peer->crypto & CRYPTO_FLAG_AUTO))))			return (XEVNT_TSP);		if ((tstamp < fstamp1 || fstamp < fstamp1))			return (XEVNT_FSP);	}	/*	 * Check for valid signature length, public key and digest	 * algorithm.	 */	if (crypto_flags & peer->crypto & CRYPTO_FLAG_PRIV)		pkey = sign_pkey;	else		pkey = peer->pkey;	if (siglen == 0 || pkey == NULL || peer->digest == NULL)		return (XEVNT_OK);	if (siglen != (u_int)EVP_PKEY_size(pkey))		return (XEVNT_SGL);	/*	 * Darn, I thought we would never get here. Verify the	 * signature. If the identity exchange is verified, light the	 * proventic bit. If no client identity scheme is specified,	 * avoid doing the sign exchange.	 */	EVP_VerifyInit(&ctx, peer->digest);	EVP_VerifyUpdate(&ctx, (u_char *)&ep->tstamp, vallen + 12);	if (!EVP_VerifyFinal(&ctx, (u_char *)&ep->pkt[i], siglen, pkey))		return (XEVNT_SIG);	if (peer->crypto & CRYPTO_FLAG_VRFY) {		peer->crypto |= CRYPTO_FLAG_PROV;		if (!(crypto_flags & CRYPTO_FLAG_MASK))			peer->crypto |= CRYPTO_FLAG_SIGN;	}	return (XEVNT_OK);}/* * crypto_encrypt - construct encrypted cookie and signature from * extension field and cookie * * Returns * XEVNT_OK	success * XEVNT_PUB	bad or missing public key * XEVNT_CKY	bad or missing cookie * XEVNT_PER	host certificate expired */static intcrypto_encrypt(	struct exten *ep,	/* extension pointer */	struct value *vp,	/* value pointer */	keyid_t	*cookie		/* server cookie */	){	EVP_PKEY *pkey;		/* public key */	EVP_MD_CTX ctx;		/* signature context */	tstamp_t tstamp;	/* NTP timestamp */	u_int32	temp32;	u_int	len;	u_char	*ptr;	/*	 * Extract the public key from the request.	 */	len = ntohl(ep->vallen);	ptr = (u_char *)ep->pkt;	pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &ptr, len);	if (pkey == NULL) {		msyslog(LOG_ERR, "crypto_encrypt %s\n",		    ERR_error_string(ERR_get_error(), NULL));		return (XEVNT_PUB);	}	/*	 * Encrypt the cookie, encode in ASN.1 and sign.	 */	tstamp = crypto_time();	memset(vp, 0, sizeof(struct value));	vp->tstamp = htonl(tstamp);	vp->fstamp = hostval.tstamp;	len = EVP_PKEY_size(pkey);	vp->vallen = htonl(len);	vp->ptr = emalloc(len);	temp32 = htonl(*cookie);	if (!RSA_public_encrypt(4, (u_char *)&temp32, vp->ptr,	    pkey->pkey.rsa, RSA_PKCS1_OAEP_PADDING)) {		msyslog(LOG_ERR, "crypto_encrypt %s\n",		    ERR_error_string(ERR_get_error(), NULL));		EVP_PKEY_free(pkey);		return (XEVNT_CKY);	}	EVP_PKEY_free(pkey);	vp->siglen = 0;	if (tstamp == 0)		return (XEVNT_OK);	if (tstamp < cinfo->first || tstamp > cinfo->last)		return (XEVNT_PER);	vp->sig = emalloc(sign_siglen);	EVP_SignInit(&ctx, sign_digest);	EVP_SignUpdate(&ctx, (u_char *)&vp->tstamp, 12);	EVP_SignUpdate(&ctx, vp->ptr, len);	if (EVP_SignFinal(&ctx, vp->sig, &len, sign_pkey))		vp->siglen = htonl(len);	return (XEVNT_OK);}/* * crypto_ident - construct extension field for identity scheme * * This routine determines which identity scheme is in use and * constructs an extension field for that scheme. */u_intcrypto_ident(	struct peer *peer	/* peer structure pointer */	){	char	filename[MAXFILENAME + 1];	/*	 * If the server identity has already been verified, no further	 * action is necessary. Otherwise, try to load the identity file	 * of the certificate issuer. If the issuer file is not found,	 * try the host file. If nothing found, declare a cryptobust.	 * Note we can't get here unless the trusted certificate has	 * been found and the CRYPTO_FLAG_VALID bit is set, so the	 * certificate issuer is valid.	 */	if (peer->ident_pkey != NULL)		EVP_PKEY_free(peer->ident_pkey);	if (peer->crypto & CRYPTO_FLAG_GQ) {		snprintf(filename, MAXFILENAME, "ntpkey_gq_%s",		    peer->issuer);		peer->ident_pkey = crypto_key(filename, &peer->fstamp);		if (peer->ident_pkey != NULL)			return (CRYPTO_GQ);		snprintf(filename, MAXFILENAME, "ntpkey_gq_%s",		    sys_hostname);		peer->ident_pkey = crypto_key(filename, &peer->fstamp);		if (peer->ident_pkey != NULL)			return (CRYPTO_GQ);	}	if (peer->crypto & CRYPTO_FLAG_IFF) {		snprintf(filename, MAXFILENAME, "ntpkey_iff_%s",		    peer->issuer);		peer->ident_pkey = crypto_key(filename, &peer->fstamp);		if (peer->ident_pkey != NULL)			return (CRYPTO_IFF);		snprintf(filename, MAXFILENAME, "ntpkey_iff_%s",		    sys_hostname);		peer->ident_pkey = crypto_key(filename, &peer->fstamp);		if (peer->ident_pkey != NULL)			return (CRYPTO_IFF);	}	if (peer->crypto & CRYPTO_FLAG_MV) {		snprintf(filename, MAXFILENAME, "ntpkey_mv_%s",		    peer->issuer);		peer->ident_pkey = crypto_key(filename, &peer->fstamp);		if (peer->ident_pkey != NULL)			return (CRYPTO_MV);		snprintf(filename, MAXFILENAME, "ntpkey_mv_%s",		    sys_hostname);		peer->ident_pkey = crypto_key(filename, &peer->fstamp);		if (peer->ident_pkey != NULL)			return (CRYPTO_MV);	}	/*	 * No compatible identity scheme is available. Life is hard.	 */	msyslog(LOG_INFO,	    "crypto_ident: no compatible identity scheme found");	return (0);}/* * crypto_args - construct extension field from arguments * * This routine creates an extension field with current timestamps and * specified opcode, association ID and optional string. Note that the * extension field is created here, but freed after the crypto_xmit() * call in the protocol module. * * Returns extension field pointer (no errors). */struct exten *crypto_args(	struct peer *peer,	/* peer structure pointer */	u_int	opcode,		/* operation code */	char	*str		/* argument string */	){	tstamp_t tstamp;	/* NTP timestamp */	struct exten *ep;	/* extension field pointer */	u_int	len;		/* extension field length */	tstamp = crypto_time();	len = sizeof(struct exten);	if (str != NULL)		len += strlen(str);	ep = emalloc(len);	memset(ep, 0, len);	if (opcode == 0)		return (ep);	ep->opcode = htonl(opcode + len);	/*	 * If a response, send our ID; if a request, send the	 * responder's ID.	 */	if (opcode & CRYPTO_RESP)		ep->associd = htonl(peer->associd);	else		ep->associd = htonl(peer->assoc);	ep->tstamp = htonl(tstamp);	ep->fstamp = hostval.tstamp;	ep->vallen = 0;	if (str != NULL) {		ep->vallen = htonl(strlen(str));		memcpy((char *)ep->pkt, str, strlen(str));	} else {		ep->pkt[0] = peer->associd;	}	return (ep);}/* * crypto_send - construct extension field from value components * * Returns extension field length. Note: it is not polite to send a * nonempty signature with zero timestamp or a nonzero timestamp with * empty signature, but these rules are not enforced here. */u_intcrypto_send(	struct exten *ep,	/* extension field pointer */	struct value *vp	/* value pointer */	){	u_int	len, temp32;	int	i;	/*	 * Copy data. If the data field is empty or zero length, encode	 * an empty value with length zero.	 */	ep->tstamp = vp->tstamp;	ep->fstamp = vp->fstamp;	ep->vallen = vp->vallen;	len = 12;	temp32 = ntohl(vp->vallen);	if (temp32 > 0 && vp->ptr != NULL)		memcpy(ep->pkt, vp->ptr, temp32);	/*	 * Copy signature. If the signature field is empty or zero	 * length, encode an empty signature with length zero.	 */	i = (temp32 + 3) / 4;	len += i * 4 + 4;	ep->pkt[i++] = vp->siglen;	temp32 = ntohl(vp->siglen);	if (temp32 > 0 && vp->sig != NULL)		memcpy(&ep->pkt[i], vp->sig, temp32);	len += temp32;	return (len);}/* * crypto_update - compute new public value and sign extension fields * * This routine runs periodically, like once a day, and when something * changes. It updates the timestamps on three value structures and one * value structure list, then signs all the structures: *

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -