FreeBSD/contrib/ntp/ntpd/ntp_crypto.c
/*
 * cert_sign - sign x509 certificate equest and update value structure.
 *
 * The certificate request includes a copy of the host certificate,
 * which includes the version number, subject name and public key of the
 * host. The resulting certificate includes these values plus the
 * serial number, issuer name and valid interval of the server. The
 * valid interval extends from the current time to the same time one
 * year hence. This may extend the life of the signed certificate beyond
 * that of the signer certificate.
 *
 * It is convenient to use the NTP seconds of the current time as the
 * serial number. In the value structure the timestamp is the current
 * time and the filestamp is taken from the extension field. Note this
 * routine is called only when the client clock is synchronized to a
 * proventic source, so timestamp comparisons are valid.
 *
 * The host certificate is valid from the time it was generated for a
 * period of one year. A signed certificate is valid from the time of
 * signature for a period of one year, but only the host certificate (or
 * sign certificate if used) is actually used to encrypt and decrypt
 * signatures. The signature trail is built from the client via the
 * intermediate servers to the trusted server. Each signature on the
 * trail must be valid at the time of signature, but it could happen
 * that a signer certificate expire before the signed certificate, which
 * remains valid until its expiration. 
 *
 * Returns
 * XEVNT_OK	success
 * XEVNT_CRT	bad or missing certificate
 * XEVNT_PER	host certificate expired
 * XEVNT_PUB	bad or missing public key
 * XEVNT_VFY	certificate not verified
 */
sign x509 certificate equest and update value structure.
The certificate request includes a copy of the host certificate,
which includes the version number, subject name and public key of the
host. The resulting certificate includes these values plus the
serial number, issuer name and valid interval of the server. The
valid interval extends from the current time to the same time one
year hence. This may extend the life of the signed certificate beyond
that of the signer certificate.

It is convenient to use the NTP seconds of the current time as the
serial number. In the value structure the timestamp is the current
time and the filestamp is taken from the extension field. Note this
routine is called only when the client clock is synchronized to a
proventic source, so timestamp comparisons are valid.

The host certificate is valid from the time it was generated for a
period of one year. A signed certificate is valid from the time of
signature for a period of one year, but only the host certificate (or
sign certificate if used) is actually used to encrypt and decrypt
signatures. The signature trail is built from the client via the
intermediate servers to the trusted server. Each signature on the
trail must be valid at the time of signature, but it could happen
that a signer certificate expire before the signed certificate, which
remains valid until its expiration.

Returns
XEVNT_OK     success
XEVNT_CRT    bad or missing certificate
XEVNT_PER    host certificate expired
XEVNT_PUB    bad or missing public key
XEVNT_VFY    certificate not verified
sign x509 certificate equest and update value structure . The certificate request includes a copy of the host certificate which includes the version number subject name and public key of the host . The resulting certificate includes these values plus the serial number issuer name and valid interval of the server . The valid interval extends from the current time to the same time one year hence . This may extend the life of the signed certificate beyond that of the signer certificate . It is convenient to use the NTP seconds of the current time as the serial number . In the value structure the timestamp is the current time and the filestamp is taken from the extension field . Note this routine is called only when the client clock is synchronized to a proventic source so timestamp comparisons are valid . The host certificate is valid from the time it was generated for a period of one year . A signed certificate is valid from the time of signature for a period of one year but only the host certificate ( or sign certificate if used ) is actually used to encrypt and decrypt signatures . The signature trail is built from the client via the intermediate servers to the trusted server . Each signature on the trail must be valid at the time of signature but it could happen that a signer certificate expire before the signed certificate which remains valid until its expiration . Returns XEVNT_OK success XEVNT_CRT bad or missing certificate XEVNT_PER host certificate expired XEVNT_PUB bad or missing public key XEVNT_VFY certificate not verified
static int
cert_sign(
	struct exten *ep,	
	struct value *vp	
	)
{
	X509	*req;		
	X509	*cert;		
	X509_EXTENSION *ext;	
	ASN1_INTEGER *serial;	
	X509_NAME *subj;	
	EVP_PKEY *pkey;		
	EVP_MD_CTX *ctx;	
	tstamp_t tstamp;	
	struct calendar tscal;
	u_int	len;
	const u_char *cptr;
	u_char *ptr;
	int	i, temp;
	tstamp = crypto_time();
	if (tstamp == 0)
		return (XEVNT_TSP);
	len = exten_payload_size(ep);
	if (len == 0 || len > MAX_VALLEN)
		return (XEVNT_LEN);
	cptr = (void *)ep->pkt;
	if ((req = d2i_X509(NULL, &cptr, len)) == NULL) {
		msyslog(LOG_ERR, "cert_sign: %s",
		    ERR_error_string(ERR_get_error(), NULL));
		return (XEVNT_CRT);
	}
	if ((pkey = X509_get_pubkey(req)) == NULL) {
		msyslog(LOG_ERR, "cert_sign: %s",
		    ERR_error_string(ERR_get_error(), NULL));
		X509_free(req);
		return (XEVNT_PUB);
	}
	cert = X509_new();
	X509_set_version(cert, X509_get_version(req));
	serial = ASN1_INTEGER_new();
	ASN1_INTEGER_set(serial, tstamp);
	X509_set_serialNumber(cert, serial);
	X509_gmtime_adj(X509_get_notBefore(cert), 0L);
	X509_gmtime_adj(X509_get_notAfter(cert), YEAR);
	subj = X509_get_issuer_name(cert);
	X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC,
	    hostval.ptr, strlen((const char *)hostval.ptr), -1, 0);
	subj = X509_get_subject_name(req);
	X509_set_subject_name(cert, subj);
	X509_set_pubkey(cert, pkey);
	temp = X509_get_ext_count(req);
	for (i = 0; i < temp; i++) {
		ext = X509_get_ext(req, i);
		INSIST(X509_add_ext(cert, ext, -1));
	}
	X509_free(req);
	(void)ntpcal_ntp_to_date(&tscal, tstamp, NULL);
	if ((calcomp(&tscal, &(cert_host->first)) < 0)
	|| (calcomp(&tscal, &(cert_host->last)) > 0)) {
		X509_free(cert);
		return (XEVNT_PER);
	}
	X509_sign(cert, sign_pkey, sign_digest);
	if (X509_verify(cert, sign_pkey) <= 0) {
		msyslog(LOG_ERR, "cert_sign: %s",
		    ERR_error_string(ERR_get_error(), NULL));
		X509_free(cert);
		return (XEVNT_VFY);
	}
	len = i2d_X509(cert, NULL);
	memset(vp, 0, sizeof(struct value));
	vp->tstamp = htonl(tstamp);
	vp->fstamp = ep->fstamp;
	vp->vallen = htonl(len);
	vp->ptr = emalloc(len);
	ptr = vp->ptr;
	i2d_X509(cert, (unsigned char **)(intptr_t)&ptr);
	vp->siglen = 0;
	if (tstamp != 0) {
		vp->sig = emalloc(sign_siglen);
		ctx = EVP_MD_CTX_new();
		EVP_SignInit(ctx, sign_digest);
		EVP_SignUpdate(ctx, (u_char *)vp, 12);
		EVP_SignUpdate(ctx, vp->ptr, len);
		if (EVP_SignFinal(ctx, vp->sig, &len, sign_pkey)) {
			INSIST(len <= sign_siglen);
			vp->siglen = htonl(len);
		}
		EVP_MD_CTX_free(ctx);
	}
#ifdef DEBUG
	if (debug > 1)
		X509_print_fp(stdout, cert);
#endif
	X509_free(cert);
	return (XEVNT_OK);
}
static int cert_sign ( struct exten * ep , struct value * vp ) { X509 * req ; X509 * cert ; X509_EXTENSION * ext ; ASN1_INTEGER * serial ; X509_NAME * subj ; EVP_PKEY * pkey ; EVP_MD_CTX * ctx ; tstamp_t tstamp ; struct calendar tscal ; u_int len ; const u_char * cptr ; u_char * ptr ; int i , temp ; tstamp = crypto_time ( ) ; if ( tstamp == 0 ) return ( XEVNT_TSP ) ; len = exten_payload_size ( ep ) ; if ( len == 0 || len > MAX_VALLEN ) return ( XEVNT_LEN ) ; cptr = ( void * ) ep -> pkt ; if ( ( req = d2i_X509 ( NULL , & cptr , len ) ) == NULL ) { msyslog ( LOG_ERR , " " , ERR_error_string ( ERR_get_error ( ) , NULL ) ) ; return ( XEVNT_CRT ) ; } if ( ( pkey = X509_get_pubkey ( req ) ) == NULL ) { msyslog ( LOG_ERR , " " , ERR_error_string ( ERR_get_error ( ) , NULL ) ) ; X509_free ( req ) ; return ( XEVNT_PUB ) ; } cert = X509_new ( ) ; X509_set_version ( cert , X509_get_version ( req ) ) ; serial = ASN1_INTEGER_new ( ) ; ASN1_INTEGER_set ( serial , tstamp ) ; X509_set_serialNumber ( cert , serial ) ; X509_gmtime_adj ( X509_get_notBefore ( cert ) , 0L ) ; X509_gmtime_adj ( X509_get_notAfter ( cert ) , YEAR ) ; subj = X509_get_issuer_name ( cert ) ; X509_NAME_add_entry_by_txt ( subj , " " , MBSTRING_ASC , hostval . ptr , strlen ( ( const char * ) hostval . ptr ) , -1 , 0 ) ; subj = X509_get_subject_name ( req ) ; X509_set_subject_name ( cert , subj ) ; X509_set_pubkey ( cert , pkey ) ; temp = X509_get_ext_count ( req ) ; for ( i = 0 ; i < temp ; i ++ ) { ext = X509_get_ext ( req , i ) ; INSIST ( X509_add_ext ( cert , ext , -1 ) ) ; } X509_free ( req ) ; ( void ) ntpcal_ntp_to_date ( & tscal , tstamp , NULL ) ; if ( ( calcomp ( & tscal , & ( cert_host -> first ) ) < 0 ) || ( calcomp ( & tscal , & ( cert_host -> last ) ) > 0 ) ) { X509_free ( cert ) ; return ( XEVNT_PER ) ; } X509_sign ( cert , sign_pkey , sign_digest ) ; if ( X509_verify ( cert , sign_pkey ) <= 0 ) { msyslog ( LOG_ERR , " " , ERR_error_string ( ERR_get_error ( ) , NULL ) ) ; X509_free ( cert ) ; return ( XEVNT_VFY ) ; } len = i2d_X509 ( cert , NULL ) ; memset ( vp , 0 , sizeof ( struct value ) ) ; vp -> tstamp = htonl ( tstamp ) ; vp -> fstamp = ep -> fstamp ; vp -> vallen = htonl ( len ) ; vp -> ptr = emalloc ( len ) ; ptr = vp -> ptr ; i2d_X509 ( cert , ( unsigned char * * ) ( intptr_t ) & ptr ) ; vp -> siglen = 0 ; if ( tstamp != 0 ) { vp -> sig = emalloc ( sign_siglen ) ; ctx = EVP_MD_CTX_new ( ) ; EVP_SignInit ( ctx , sign_digest ) ; EVP_SignUpdate ( ctx , ( u_char * ) vp , 12 ) ; EVP_SignUpdate ( ctx , vp -> ptr , len ) ; if ( EVP_SignFinal ( ctx , vp -> sig , & len , sign_pkey ) ) { INSIST ( len <= sign_siglen ) ; vp -> siglen = htonl ( len ) ; } EVP_MD_CTX_free ( ctx ) ; } #ifdef DEBUG if ( debug > 1 ) X509_print_fp ( stdout , cert ) ; #endif X509_free ( cert ) ; return ( XEVNT_OK ) ; }
cert_sign - sign x509 certificate equest and update value structure.
cert_sign - sign x509 certificate equest and update value structure .
/* extension field pointer */ /* value pointer */ /* X509 certificate request */ /* X509 certificate */ /* certificate extension */ /* serial number */ /* distinguished (common) name */ /* public key */ /* message digest context */ /* NTP timestamp */ /*
	 * Decode ASN.1 objects and construct certificate structure.
	 * Make sure the system clock is synchronized to a proventic
	 * source.
	 */ /*
	 * Extract public key and check for errors.
	 */ /*
	 * Generate X509 certificate signed by this server. If this is a
	 * trusted host, the issuer name is the group name; otherwise,
	 * it is the host name. Also copy any extensions that might be
	 * present.
	 */ /*
	 * Sign and verify the client certificate, but only if the host
	 * certificate has not expired.
	 */ /*
	 * Build and sign the value structure. We have to sign it here,
	 * since the response has to be returned right away. This is a
	 * clogging hazard.
	 */