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

📄 ntp_crypto.c

📁 网络时间协议NTP 源码 版本v4.2.0b 该源码用于linux平台下
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * ntp_crypto.c - NTP version 4 public key routines */#ifdef HAVE_CONFIG_H#include <config.h>#endif#ifdef OPENSSL#include <stdio.h>#include <sys/types.h>#include <sys/param.h>#include <unistd.h>#include <fcntl.h>#include "ntpd.h"#include "ntp_stdlib.h"#include "ntp_unixtime.h"#include "ntp_string.h"#include <ntp_random.h>#include "openssl/asn1_mac.h"#include "openssl/bn.h"#include "openssl/err.h"#include "openssl/evp.h"#include "openssl/pem.h"#include "openssl/rand.h"#include "openssl/x509v3.h"#ifdef KERNEL_PLL#include "ntp_syscall.h"#endif /* KERNEL_PLL *//* * Extension field message format * * These are always signed and saved before sending in network byte * order. They must be converted to and from host byte order for * processing. * * +-------+-------+ * |   op  |  len  | <- extension pointer * +-------+-------+ * |    assocID    | * +---------------+ * |   timestamp   | <- value pointer * +---------------+ * |   filestamp   | * +---------------+ * |   value len   | * +---------------+ * |               | * =     value     = * |               | * +---------------+ * | signature len | * +---------------+ * |               | * =   signature   = * |               | * +---------------+ * * The CRYPTO_RESP bit is set to 0 for requests, 1 for responses. * Requests carry the association ID of the receiver; responses carry * the association ID of the sender. Some messages include only the * operation/length and association ID words and so have length 8 * octets. Ohers include the value structure and associated value and * signature fields. These messages include the timestamp, filestamp, * value and signature words and so have length at least 24 octets. The * signature and/or value fields can be empty, in which case the * respective length words are zero. An empty value with nonempty * signature is syntactically valid, but semantically questionable. * * The filestamp represents the time when a cryptographic data file such * as a public/private key pair is created. It follows every reference * depending on that file and serves as a means to obsolete earlier data * of the same type. The timestamp represents the time when the * cryptographic data of the message were last signed. Creation of a * cryptographic data file or signing a message can occur only when the * creator or signor is synchronized to an authoritative source and * proventicated to a trusted authority. * * Note there are four conditions required for server trust. First, the * public key on the certificate must be verified, which involves a * number of format, content and consistency checks. Next, the server * identity must be confirmed by one of four schemes: private * certificate, IFF scheme, GQ scheme or certificate trail hike to a * self signed trusted certificate. Finally, the server signature must * be verified. *//* * Cryptodefines */#define TAI_1972	10	/* initial TAI offset (s) */#define MAX_LEAP	100	/* max UTC leapseconds (s) */#define VALUE_LEN	(6 * 4) /* min response field length */#define YEAR		(60 * 60 * 24 * 365) /* seconds in year *//* * Global cryptodata in host byte order */u_int32	crypto_flags = 0x0;	/* status word *//* * Global cryptodata in network byte order */struct cert_info *cinfo = NULL;	/* certificate info/value */struct value hostval;		/* host value */struct value pubkey;		/* public key */struct value tai_leap;		/* leapseconds table */EVP_PKEY *iffpar_pkey = NULL;	/* IFF parameters */EVP_PKEY *gqpar_pkey = NULL;	/* GQ parameters */EVP_PKEY *mvpar_pkey = NULL;	/* MV parameters */char	*iffpar_file = NULL; /* IFF parameters file */char	*gqpar_file = NULL;	/* GQ parameters file */char	*mvpar_file = NULL;	/* MV parameters file *//* * Private cryptodata in host byte order */static char *passwd = NULL;	/* private key password */static EVP_PKEY *host_pkey = NULL; /* host key */static EVP_PKEY *sign_pkey = NULL; /* sign key */static const EVP_MD *sign_digest = NULL; /* sign digest */static u_int sign_siglen;	/* sign key length */static char *rand_file = NULL;	/* random seed file */static char *host_file = NULL;	/* host key file */static char *sign_file = NULL;	/* sign key file */static char *cert_file = NULL;	/* certificate file */static char *leap_file = NULL;	/* leapseconds file */static tstamp_t if_fstamp = 0;	/* IFF filestamp */static tstamp_t gq_fstamp = 0;	/* GQ file stamp */static tstamp_t mv_fstamp = 0;	/* MV filestamp */static u_int ident_scheme = 0;	/* server identity scheme *//* * Cryptotypes */static	int	crypto_verify	P((struct exten *, struct value *,				    struct peer *));static	int	crypto_encrypt	P((struct exten *, struct value *,				    keyid_t *));static	int	crypto_alice	P((struct peer *, struct value *));static	int	crypto_alice2	P((struct peer *, struct value *));static	int	crypto_alice3	P((struct peer *, struct value *));static	int	crypto_bob	P((struct exten *, struct value *));static	int	crypto_bob2	P((struct exten *, struct value *));static	int	crypto_bob3	P((struct exten *, struct value *));static	int	crypto_iff	P((struct exten *, struct peer *));static	int	crypto_gq	P((struct exten *, struct peer *));static	int	crypto_mv	P((struct exten *, struct peer *));static	u_int	crypto_send	P((struct exten *, struct value *));static	tstamp_t crypto_time	P((void));static	u_long	asn2ntp		P((ASN1_TIME *));static	struct cert_info *cert_parse P((u_char *, u_int, tstamp_t));static	int	cert_sign	P((struct exten *, struct value *));static	int	cert_valid	P((struct cert_info *, EVP_PKEY *));static	int	cert_install	P((struct exten *, struct peer *));static	void	cert_free	P((struct cert_info *));static	EVP_PKEY *crypto_key	P((char *, tstamp_t *));static	int	bighash		P((BIGNUM *, BIGNUM *));static	struct cert_info *crypto_cert P((char *));static	void	crypto_tai	P((char *));#ifdef SYS_WINNTintreadlink(char * link, char * file, int len) {	return (-1);}#endif/* * session_key - generate session key * * This routine generates a session key from the source address, * destination address, key ID and private value. The value of the * session key is the MD5 hash of these values, while the next key ID is * the first four octets of the hash. * * Returns the next key ID */keyid_tsession_key(	struct sockaddr_storage *srcadr, /* source address */	struct sockaddr_storage *dstadr, /* destination address */	keyid_t	keyno,		/* key ID */	keyid_t	private,	/* private value */	u_long	lifetime 	/* key lifetime */	){	EVP_MD_CTX ctx;		/* message digest context */	u_char dgst[EVP_MAX_MD_SIZE]; /* message digest */	keyid_t	keyid;		/* key identifer */	u_int32	header[10];	/* data in network byte order */	u_int	hdlen, len;	/*	 * Generate the session key and key ID. If the lifetime is	 * greater than zero, install the key and call it trusted.	 */	hdlen = 0;	switch(srcadr->ss_family) {	case AF_INET:		header[0] = ((struct sockaddr_in *)srcadr)->sin_addr.s_addr;		header[1] = ((struct sockaddr_in *)dstadr)->sin_addr.s_addr;		header[2] = htonl(keyno);		header[3] = htonl(private);		hdlen = 4 * sizeof(u_int32);		break;	case AF_INET6:		memcpy(&header[0], &GET_INADDR6(*srcadr),		    sizeof(struct in6_addr));		memcpy(&header[4], &GET_INADDR6(*dstadr),		    sizeof(struct in6_addr));		header[8] = htonl(keyno);		header[9] = htonl(private);		hdlen = 10 * sizeof(u_int32);		break;	}	EVP_DigestInit(&ctx, EVP_md5());	EVP_DigestUpdate(&ctx, (u_char *)header, hdlen);	EVP_DigestFinal(&ctx, dgst, &len);	memcpy(&keyid, dgst, 4);	keyid = ntohl(keyid);	if (lifetime != 0) {		MD5auth_setkey(keyno, dgst, len);		authtrust(keyno, lifetime);	}#ifdef DEBUG	if (debug > 1)		printf(		    "session_key: %s > %s %08x %08x hash %08x life %lu\n",		    stoa(srcadr), stoa(dstadr), keyno,		    private, keyid, lifetime);#endif	return (keyid);}/* * make_keylist - generate key list * * Returns * XEVNT_OK	success * XEVNT_PER	host certificate expired * * This routine constructs a pseudo-random sequence by repeatedly * hashing the session key starting from a given source address, * destination address, private value and the next key ID of the * preceeding session key. The last entry on the list is saved along * with its sequence number and public signature. */intmake_keylist(	struct peer *peer,	/* peer structure pointer */	struct interface *dstadr /* interface */	){	EVP_MD_CTX ctx;		/* signature context */	tstamp_t tstamp;	/* NTP timestamp */	struct autokey *ap;	/* autokey pointer */	struct value *vp;	/* value pointer */	keyid_t	keyid = 0;	/* next key ID */	keyid_t	cookie;		/* private value */	u_long	lifetime;	u_int	len, mpoll;	int	i;	/*	 * Allocate the key list if necessary.	 */	tstamp = crypto_time();	if (peer->keylist == NULL)		peer->keylist = emalloc(sizeof(keyid_t) *		    NTP_MAXSESSION);	/*	 * Generate an initial key ID which is unique and greater than	 * NTP_MAXKEY.	 */	while (1) {		keyid = (ntp_random() + NTP_MAXKEY + 1) & ((1 <<		    sizeof(keyid_t)) - 1);		if (authhavekey(keyid))			continue;		break;	}	/*	 * Generate up to NTP_MAXSESSION session keys. Stop if the	 * next one would not be unique or not a session key ID or if	 * it would expire before the next poll. The private value	 * included in the hash is zero if broadcast mode, the peer	 * cookie if client mode or the host cookie if symmetric modes.	 */	mpoll = 1 << min(peer->ppoll, peer->hpoll);	lifetime = min(sys_automax, NTP_MAXSESSION * mpoll);	if (peer->hmode == MODE_BROADCAST)		cookie = 0;	else		cookie = peer->pcookie;	for (i = 0; i < NTP_MAXSESSION; i++) {		peer->keylist[i] = keyid;		peer->keynumber = i;		keyid = session_key(&dstadr->sin, &peer->srcadr, keyid,		    cookie, lifetime);		lifetime -= mpoll;		if (auth_havekey(keyid) || keyid <= NTP_MAXKEY ||		    lifetime <= mpoll)			break;	}	/*	 * Save the last session key ID, sequence number and timestamp,	 * then sign these values for later retrieval by the clients. Be	 * careful not to use invalid key media. Use the public values	 * timestamp as filestamp. 	 */	vp = &peer->sndval;	if (vp->ptr == NULL)		vp->ptr = emalloc(sizeof(struct autokey));	ap = (struct autokey *)vp->ptr;	ap->seq = htonl(peer->keynumber);	ap->key = htonl(keyid);	vp->tstamp = htonl(tstamp);	vp->fstamp = hostval.tstamp;	vp->vallen = htonl(sizeof(struct autokey));	vp->siglen = 0;	if (tstamp != 0) {		if (tstamp < cinfo->first || tstamp > cinfo->last)			return (XEVNT_PER);		if (vp->sig == NULL)			vp->sig = emalloc(sign_siglen);		EVP_SignInit(&ctx, sign_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);		else			msyslog(LOG_ERR, "make_keys %s\n",			    ERR_error_string(ERR_get_error(), NULL));		peer->flags |= FLAG_ASSOC;	}#ifdef DEBUG	if (debug)		printf("make_keys: %d %08x %08x ts %u fs %u poll %d\n",		    ntohl(ap->seq), ntohl(ap->key), cookie,		    ntohl(vp->tstamp), ntohl(vp->fstamp), peer->hpoll);#endif	return (XEVNT_OK);}/* * crypto_recv - parse extension fields * * This routine is called when the packet has been matched to an * association and passed sanity, format and MAC checks. We believe the * extension field values only if the field has proper format and * length, the timestamp and filestamp are valid and the signature has * valid length and is verified. There are a few cases where some values * are believed even if the signature fails, but only if the proventic * bit is not set. */intcrypto_recv(	struct peer *peer,	/* peer structure pointer */	struct recvbuf *rbufp	/* packet buffer pointer */	){	const EVP_MD *dp;	/* message digest algorithm */	u_int32	*pkt;		/* receive packet pointer */	struct autokey *ap, *bp; /* autokey pointer */	struct exten *ep, *fp;	/* extension pointers */	int	has_mac;	/* length of MAC field */	int	authlen;	/* offset of MAC field */	associd_t associd;	/* association ID */	tstamp_t tstamp = 0;	/* timestamp */	tstamp_t fstamp = 0;	/* filestamp */	u_int	len;		/* extension field length */	u_int	code;		/* extension field opcode */	u_int	vallen = 0;	/* value length */	X509	*cert;		/* X509 certificate */	char	statstr[NTP_MAXSTRLEN]; /* statistics for filegen */	keyid_t	cookie;		/* crumbles */	int	hismode;	/* packet mode */	int	rval = XEVNT_OK;	u_char	*ptr;	u_int32 temp32;	/*	 * Initialize. Note that the packet has already been checked for	 * valid format and extension field lengths. First extract the	 * field length, command code and association ID in host byte	 * order. These are used with all commands and modes. Then check	 * the version number, which must be 2, and length, which must	 * be at least 8 for requests and VALUE_LEN (24) for responses.	 * Packets that fail either test sink without a trace. The	 * association ID is saved only if nonzero.	 */	authlen = LEN_PKT_NOMAC;	hismode = (int)PKT_MODE((&rbufp->recv_pkt)->li_vn_mode);	while ((has_mac = rbufp->recv_length - authlen) > MAX_MAC_LEN) {		pkt = (u_int32 *)&rbufp->recv_pkt + authlen / 4;		ep = (struct exten *)pkt;		code = ntohl(ep->opcode) & 0xffff0000;		len = ntohl(ep->opcode) & 0x0000ffff;		associd = (associd_t) ntohl(pkt[1]);		rval = XEVNT_OK;#ifdef DEBUG		if (debug)			printf(			    "crypto_recv: flags 0x%x ext offset %d len %u code 0x%x assocID %d\n",			    peer->crypto, authlen, len, code >> 16,			    associd);#endif		/*		 * Check version number and field length. If bad,		 * quietly ignore the packet.		 */		if (((code >> 24) & 0x3f) != CRYPTO_VN || len < 8) {			sys_unknownversion++;			code |= CRYPTO_ERROR;		}		/*		 * Little vulnerability bandage here. If a perp tosses a		 * fake association ID over the fence, we better toss it		 * out. Only the first one counts.		 */		if (code & CRYPTO_RESP) {			if (peer->assoc == 0)				peer->assoc = associd;			else if (peer->assoc != associd)				code |= CRYPTO_ERROR;		}		if (len >= VALUE_LEN) {			tstamp = ntohl(ep->tstamp);			fstamp = ntohl(ep->fstamp);			vallen = ntohl(ep->vallen);		}		switch (code) {		/*		 * Install status word, host name, signature scheme and		 * association ID. In OpenSSL the signature algorithm is		 * bound to the digest algorithm, so the NID completely		 * defines the signature scheme. Note the request and		 * response are identical, but neither is validated by		 * signature. The request is processed here only in		 * symmetric modes. The server name field might be		 * useful to implement access controls in future.		 */		case CRYPTO_ASSOC:			/*			 * If the machine is running when this message			 * arrives, the other fellow has reset and so			 * must we. Otherwise, pass the extension field			 * to the transmit side.			 */			if (peer->crypto) {				rval = XEVNT_ERR;				break;			}

⌨️ 快捷键说明

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