FreeBSD/contrib/ntp/ntpd/ntp_crypto.c
/*
 * crypto_verify - verify the extension field value and signature
 *
 * Returns
 * XEVNT_OK	success
 * XEVNT_ERR	protocol error
 * XEVNT_FSP	bad filestamp
 * XEVNT_LEN	bad field format or length
 * XEVNT_PUB	bad or missing public key
 * XEVNT_SGL	bad signature length
 * XEVNT_SIG	signature not verified
 * XEVNT_TSP	bad timestamp
 */
verify the extension field value and signature
Returns
XEVNT_OK     success
XEVNT_ERR    protocol error
XEVNT_FSP    bad filestamp
XEVNT_LEN    bad field format or length
XEVNT_PUB    bad or missing public key
XEVNT_SGL    bad signature length
XEVNT_SIG    signature not verified
XEVNT_TSP    bad timestamp
verify the extension field value and signature Returns XEVNT_OK success XEVNT_ERR protocol error XEVNT_FSP bad filestamp XEVNT_LEN bad field format or length XEVNT_PUB bad or missing public key XEVNT_SGL bad signature length XEVNT_SIG signature not verified XEVNT_TSP bad timestamp
static int
crypto_verify(
	struct exten *ep,	
	struct value *vp,	
	struct peer *peer	
	)
{
	EVP_PKEY *pkey;		
	EVP_MD_CTX *ctx;	
	tstamp_t tstamp, tstamp1 = 0; 
	tstamp_t fstamp, fstamp1 = 0; 
	u_int	vallen;		
	u_int	siglen;		
	u_int	opcode, len;
	int	i;
	len = ntohl(ep->opcode) & 0x0000ffff;
	opcode = ntohl(ep->opcode) & 0xffff0000;
	if (opcode & CRYPTO_ERROR)
		return (XEVNT_ERR);
 	if (len < VALUE_LEN)
		return (XEVNT_LEN);
	if (opcode == (CRYPTO_AUTO | CRYPTO_RESP) && (peer->pmode ==
	    MODE_BROADCAST || (peer->cast_flags & MDF_BCLNT))) {
		if (ntohl(ep->associd) != peer->assoc)
			return (XEVNT_ERR);
	} else {
		if (ntohl(ep->associd) != peer->associd)
			return (XEVNT_ERR);
	}
	vallen = ntohl(ep->vallen);
	if (   vallen == 0
	    || vallen > MAX_VALLEN)
		return (XEVNT_LEN);
	i = (vallen + 3) / 4;
	siglen = ntohl(ep->pkt[i++]);
	if (   siglen > MAX_VALLEN
	    || len - VALUE_LEN < ((vallen + 3) / 4) * 4
	    || len - VALUE_LEN - ((vallen + 3) / 4) * 4
	      < ((siglen + 3) / 4) * 4)
		return (XEVNT_LEN);
	tstamp = ntohl(ep->tstamp);
	fstamp = ntohl(ep->fstamp);
	if (tstamp == 0)
		return (XEVNT_TSP);
	if (tstamp < fstamp)
		return (XEVNT_TSP);
	if (vp != NULL) {
		tstamp1 = ntohl(vp->tstamp);
		fstamp1 = ntohl(vp->fstamp);
		if (tstamp1 != 0 && fstamp1 != 0) {
			if (tstamp < tstamp1)
				return (XEVNT_TSP);
			if ((tstamp < fstamp1 || fstamp < fstamp1))
				return (XEVNT_FSP);
		}
	}
	if (opcode == (CRYPTO_CERT | CRYPTO_RESP))
		return (XEVNT_OK);
	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_ERR);
	if (siglen != (u_int)EVP_PKEY_size(pkey))
		return (XEVNT_SGL);
	ctx = EVP_MD_CTX_new();
	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) <= 0) {
		EVP_MD_CTX_free(ctx);
		return (XEVNT_SIG);
	}
	EVP_MD_CTX_free(ctx);
	if (peer->crypto & CRYPTO_FLAG_VRFY)
		peer->crypto |= CRYPTO_FLAG_PROV;
	return (XEVNT_OK);
}
static int crypto_verify ( struct exten * ep , struct value * vp , struct peer * peer ) { EVP_PKEY * pkey ; EVP_MD_CTX * ctx ; tstamp_t tstamp , tstamp1 = 0 ; tstamp_t fstamp , fstamp1 = 0 ; u_int vallen ; u_int siglen ; u_int opcode , len ; int i ; len = ntohl ( ep -> opcode ) & 0x0000ffff ; opcode = ntohl ( ep -> opcode ) & 0xffff0000 ; if ( opcode & CRYPTO_ERROR ) return ( XEVNT_ERR ) ; if ( len < VALUE_LEN ) return ( XEVNT_LEN ) ; if ( opcode == ( CRYPTO_AUTO | CRYPTO_RESP ) && ( peer -> pmode == MODE_BROADCAST || ( peer -> cast_flags & MDF_BCLNT ) ) ) { if ( ntohl ( ep -> associd ) != peer -> assoc ) return ( XEVNT_ERR ) ; } else { if ( ntohl ( ep -> associd ) != peer -> associd ) return ( XEVNT_ERR ) ; } vallen = ntohl ( ep -> vallen ) ; if ( vallen == 0 || vallen > MAX_VALLEN ) return ( XEVNT_LEN ) ; i = ( vallen + 3 ) / 4 ; siglen = ntohl ( ep -> pkt [ i ++ ] ) ; if ( siglen > MAX_VALLEN || len - VALUE_LEN < ( ( vallen + 3 ) / 4 ) * 4 || len - VALUE_LEN - ( ( vallen + 3 ) / 4 ) * 4 < ( ( siglen + 3 ) / 4 ) * 4 ) return ( XEVNT_LEN ) ; tstamp = ntohl ( ep -> tstamp ) ; fstamp = ntohl ( ep -> fstamp ) ; if ( tstamp == 0 ) return ( XEVNT_TSP ) ; if ( tstamp < fstamp ) return ( XEVNT_TSP ) ; if ( vp != NULL ) { tstamp1 = ntohl ( vp -> tstamp ) ; fstamp1 = ntohl ( vp -> fstamp ) ; if ( tstamp1 != 0 && fstamp1 != 0 ) { if ( tstamp < tstamp1 ) return ( XEVNT_TSP ) ; if ( ( tstamp < fstamp1 || fstamp < fstamp1 ) ) return ( XEVNT_FSP ) ; } } if ( opcode == ( CRYPTO_CERT | CRYPTO_RESP ) ) return ( XEVNT_OK ) ; 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_ERR ) ; if ( siglen != ( u_int ) EVP_PKEY_size ( pkey ) ) return ( XEVNT_SGL ) ; ctx = EVP_MD_CTX_new ( ) ; 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 ) <= 0 ) { EVP_MD_CTX_free ( ctx ) ; return ( XEVNT_SIG ) ; } EVP_MD_CTX_free ( ctx ) ; if ( peer -> crypto & CRYPTO_FLAG_VRFY ) peer -> crypto |= CRYPTO_FLAG_PROV ; return ( XEVNT_OK ) ; }
crypto_verify - verify the extension field value and signature
 Returns
 XEVNT_OK     success
 XEVNT_ERR    protocol error
 XEVNT_FSP    bad filestamp
 XEVNT_LEN    bad field format or length
 XEVNT_PUB    bad or missing public key
 XEVNT_SGL    bad signature length
 XEVNT_SIG    signature not verified
 XEVNT_TSP    bad timestamp
crypto_verify - verify the extension field value and signature Returns XEVNT_OK success XEVNT_ERR protocol error XEVNT_FSP bad filestamp XEVNT_LEN bad field format or length XEVNT_PUB bad or missing public key XEVNT_SGL bad signature length XEVNT_SIG signature not verified XEVNT_TSP bad timestamp
/* extension pointer */ /* value pointer */ /* peer structure pointer */ /* server public key */ /* signature context */ /* timestamp */ /* filestamp */ /* value length */ /* signature length */ /*
	 * We are extremely parannoyed. We require valid opcode, length,
	 * association ID, timestamp, filestamp, public key, digest,
	 * signature length and signature, where relevant. Note that
	 * preliminary length checks are done in the main loop.
	 */ /*
	 * Check for valid value header, association ID and extension
	 * field length. Remember, it is not an error to receive an
	 * unsolicited response; however, the response ID must match
	 * the association ID.
	 */ /*
	 * We have a valid value header. Check for valid value and
	 * signature field lengths. The extension field length must be
	 * long enough to contain the value header, value and signature.
	 * Note both the value and signature field lengths are rounded
	 * up to the next word (4 octets).
	 */ /*
	 * Check for valid timestamp and filestamp. If the timestamp is
	 * zero, the sender is not synchronized and signatures are
	 * not possible. If nonzero the timestamp must not precede the
	 * filestamp. The timestamp and filestamp must not precede the
	 * corresponding values in the value structure, if present.
 	 */ /*
	 * At the time the certificate message is validated, the public
	 * key in the message is not available. Thus, don't try to
	 * verify the signature.
	 */ /*
	 * Check for valid signature length, public key and digest
	 * algorithm.
	 */ /*
	 * Darn, I thought we would never get here. Verify the
	 * signature. If the identity exchange is verified, light the
	 * proventic bit. What a relief.
	 */ /* XXX: the "+ 12" needs to be at least documented... */