FreeBSD/contrib/ntp/ntpd/ntp_crypto.c
/*
 * cert_parse - parse x509 certificate and create info/value structures.
 *
 * The server certificate includes the version number, issuer name,
 * subject name, public key and valid date interval. If the issuer name
 * is the same as the subject name, the certificate is self signed and
 * valid only if the server is configured as trustable. If the names are
 * different, another issuer has signed the server certificate and
 * vouched for it. In this case the server certificate is valid if
 * verified by the issuer public key.
 *
 * Returns certificate info/value pointer if valid, NULL if not.
 */
parse x509 certificate and create info/value structures.
The server certificate includes the version number, issuer name,
subject name, public key and valid date interval. If the issuer name
is the same as the subject name, the certificate is self signed and
valid only if the server is configured as trustable. If the names are
different, another issuer has signed the server certificate and
vouched for it. In this case the server certificate is valid if
verified by the issuer public key.

Returns certificate info/value pointer if valid, NULL if not.
parse x509 certificate and create info / value structures . The server certificate includes the version number issuer name subject name public key and valid date interval . If the issuer name is the same as the subject name the certificate is self signed and valid only if the server is configured as trustable . If the names are different another issuer has signed the server certificate and vouched for it . In this case the server certificate is valid if verified by the issuer public key . Returns certificate info / value pointer if valid NULL if not .
struct cert_info *		
cert_parse(
	const u_char *asn1cert,	
	long	len,		
	tstamp_t fstamp		
	)
{
	X509	*cert;		
	struct cert_info *ret;	
	BIO	*bp;
	char	pathbuf[MAXFILENAME];
	const u_char *ptr;
	char	*pch;
	int	cnt, i;
	struct calendar fscal;
	ptr = asn1cert;
	if ((cert = d2i_X509(NULL, &ptr, len)) == NULL) {
		msyslog(LOG_ERR, "cert_parse: %s",
		    ERR_error_string(ERR_get_error(), NULL));
		return (NULL);
	}
#ifdef DEBUG
	if (debug > 1)
		X509_print_fp(stdout, cert);
#endif
	ret = emalloc_zero(sizeof(*ret));
	if ((ret->pkey = X509_get_pubkey(cert)) == NULL) {
		msyslog(LOG_ERR, "cert_parse: %s",
		    ERR_error_string(ERR_get_error(), NULL));
		cert_free(ret);
		X509_free(cert);
		return (NULL);
	}
	ret->version = X509_get_version(cert);
	X509_NAME_oneline(X509_get_subject_name(cert), pathbuf,
	    sizeof(pathbuf));
	pch = strstr(pathbuf, "CN=");
	if (NULL == pch) {
		msyslog(LOG_NOTICE, "cert_parse: invalid subject %s",
		    pathbuf);
		cert_free(ret);
		X509_free(cert);
		return (NULL);
	}
	ret->subject = estrdup(pch + 3);
	ret->nid = X509_get_signature_nid(cert);
	ret->digest = (const EVP_MD *)EVP_get_digestbynid(ret->nid);
	ret->serial =
	    (u_long)ASN1_INTEGER_get(X509_get_serialNumber(cert));
	X509_NAME_oneline(X509_get_issuer_name(cert), pathbuf,
	    sizeof(pathbuf));
	if ((pch = strstr(pathbuf, "CN=")) == NULL) {
		msyslog(LOG_NOTICE, "cert_parse: invalid issuer %s",
		    pathbuf);
		cert_free(ret);
		X509_free(cert);
		return (NULL);
	}
	ret->issuer = estrdup(pch + 3);
	asn_to_calendar(X509_get_notBefore(cert), &(ret->first));
	asn_to_calendar(X509_get_notAfter(cert), &(ret->last));
	cnt = X509_get_ext_count(cert);
	for (i = 0; i < cnt; i++) {
		X509_EXTENSION *ext;
		ASN1_OBJECT *obj;
		int nid;
		ASN1_OCTET_STRING *data;
		ext = X509_get_ext(cert, i);
		obj = X509_EXTENSION_get_object(ext);
		nid = OBJ_obj2nid(obj);
		switch (nid) {
		case NID_ext_key_usage:
			bp = BIO_new(BIO_s_mem());
			X509V3_EXT_print(bp, ext, 0, 0);
			BIO_gets(bp, pathbuf, sizeof(pathbuf));
			BIO_free(bp);
			if (strcmp(pathbuf, "Trust Root") == 0)
				ret->flags |= CERT_TRUST;
			else if (strcmp(pathbuf, "Private") == 0)
				ret->flags |= CERT_PRIV;
			DPRINTF(1, ("cert_parse: %s: %s\n",
				    OBJ_nid2ln(nid), pathbuf));
			break;
		case NID_subject_key_identifier:
			data = X509_EXTENSION_get_data(ext);
			ret->grpkey = BN_bin2bn(&data->data[2],
			    data->length - 2, NULL);
		default:
			DPRINTF(1, ("cert_parse: %s\n",
				    OBJ_nid2ln(nid)));
			break;
		}
	}
	if (strcmp(ret->subject, ret->issuer) == 0) {
		if (X509_verify(cert, ret->pkey) <= 0) {
			msyslog(LOG_NOTICE,
			    "cert_parse: signature not verified %s",
			    ret->subject);
			cert_free(ret);
			X509_free(cert);
			return (NULL);
		}
	} else {
		if (strcmp((const char *)hostval.ptr, ret->issuer) == 0) {
			msyslog(LOG_NOTICE,
			    "cert_parse: certificate trail loop %s",
			    ret->subject);
			cert_free(ret);
			X509_free(cert);
			return (NULL);
		}
	}
	(void)ntpcal_ntp_to_date(&fscal, fstamp, NULL);
	if ((calcomp(&(ret->first), &(ret->last)) > 0)
	|| (calcomp(&(ret->first), &fscal) < 0)) {
		msyslog(LOG_NOTICE,
		    "cert_parse: invalid times %s first %u-%02u-%02uT%02u:%02u:%02u last %u-%02u-%02uT%02u:%02u:%02u fstamp %u-%02u-%02uT%02u:%02u:%02u",
		    ret->subject,
		    ret->first.year, ret->first.month, ret->first.monthday,
		    ret->first.hour, ret->first.minute, ret->first.second,
		    ret->last.year, ret->last.month, ret->last.monthday,
		    ret->last.hour, ret->last.minute, ret->last.second,
		    fscal.year, fscal.month, fscal.monthday,
		    fscal.hour, fscal.minute, fscal.second);
		cert_free(ret);
		X509_free(cert);
		return (NULL);
	}
	ret->cert.fstamp = htonl(fstamp);
	ret->cert.vallen = htonl(len);
	ret->cert.ptr = emalloc(len);
	memcpy(ret->cert.ptr, asn1cert, len);
	X509_free(cert);
	return (ret);
}
struct cert_info * cert_parse ( const u_char * asn1cert , long len , tstamp_t fstamp ) { X509 * cert ; struct cert_info * ret ; BIO * bp ; char pathbuf [ MAXFILENAME ] ; const u_char * ptr ; char * pch ; int cnt , i ; struct calendar fscal ; ptr = asn1cert ; if ( ( cert = d2i_X509 ( NULL , & ptr , len ) ) == NULL ) { msyslog ( LOG_ERR , " " , ERR_error_string ( ERR_get_error ( ) , NULL ) ) ; return ( NULL ) ; } #ifdef DEBUG if ( debug > 1 ) X509_print_fp ( stdout , cert ) ; #endif ret = emalloc_zero ( sizeof ( * ret ) ) ; if ( ( ret -> pkey = X509_get_pubkey ( cert ) ) == NULL ) { msyslog ( LOG_ERR , " " , ERR_error_string ( ERR_get_error ( ) , NULL ) ) ; cert_free ( ret ) ; X509_free ( cert ) ; return ( NULL ) ; } ret -> version = X509_get_version ( cert ) ; X509_NAME_oneline ( X509_get_subject_name ( cert ) , pathbuf , sizeof ( pathbuf ) ) ; pch = strstr ( pathbuf , " " ) ; if ( NULL == pch ) { msyslog ( LOG_NOTICE , " " , pathbuf ) ; cert_free ( ret ) ; X509_free ( cert ) ; return ( NULL ) ; } ret -> subject = estrdup ( pch + 3 ) ; ret -> nid = X509_get_signature_nid ( cert ) ; ret -> digest = ( const EVP_MD * ) EVP_get_digestbynid ( ret -> nid ) ; ret -> serial = ( u_long ) ASN1_INTEGER_get ( X509_get_serialNumber ( cert ) ) ; X509_NAME_oneline ( X509_get_issuer_name ( cert ) , pathbuf , sizeof ( pathbuf ) ) ; if ( ( pch = strstr ( pathbuf , " " ) ) == NULL ) { msyslog ( LOG_NOTICE , " " , pathbuf ) ; cert_free ( ret ) ; X509_free ( cert ) ; return ( NULL ) ; } ret -> issuer = estrdup ( pch + 3 ) ; asn_to_calendar ( X509_get_notBefore ( cert ) , & ( ret -> first ) ) ; asn_to_calendar ( X509_get_notAfter ( cert ) , & ( ret -> last ) ) ; cnt = X509_get_ext_count ( cert ) ; for ( i = 0 ; i < cnt ; i ++ ) { X509_EXTENSION * ext ; ASN1_OBJECT * obj ; int nid ; ASN1_OCTET_STRING * data ; ext = X509_get_ext ( cert , i ) ; obj = X509_EXTENSION_get_object ( ext ) ; nid = OBJ_obj2nid ( obj ) ; switch ( nid ) { case NID_ext_key_usage : bp = BIO_new ( BIO_s_mem ( ) ) ; X509V3_EXT_print ( bp , ext , 0 , 0 ) ; BIO_gets ( bp , pathbuf , sizeof ( pathbuf ) ) ; BIO_free ( bp ) ; if ( strcmp ( pathbuf , " " ) == 0 ) ret -> flags |= CERT_TRUST ; else if ( strcmp ( pathbuf , " " ) == 0 ) ret -> flags |= CERT_PRIV ; DPRINTF ( 1 , ( " \n " , OBJ_nid2ln ( nid ) , pathbuf ) ) ; break ; case NID_subject_key_identifier : data = X509_EXTENSION_get_data ( ext ) ; ret -> grpkey = BN_bin2bn ( & data -> data [ 2 ] , data -> length - 2 , NULL ) ; default : DPRINTF ( 1 , ( " \n " , OBJ_nid2ln ( nid ) ) ) ; break ; } } if ( strcmp ( ret -> subject , ret -> issuer ) == 0 ) { if ( X509_verify ( cert , ret -> pkey ) <= 0 ) { msyslog ( LOG_NOTICE , " " , ret -> subject ) ; cert_free ( ret ) ; X509_free ( cert ) ; return ( NULL ) ; } } else { if ( strcmp ( ( const char * ) hostval . ptr , ret -> issuer ) == 0 ) { msyslog ( LOG_NOTICE , " " , ret -> subject ) ; cert_free ( ret ) ; X509_free ( cert ) ; return ( NULL ) ; } } ( void ) ntpcal_ntp_to_date ( & fscal , fstamp , NULL ) ; if ( ( calcomp ( & ( ret -> first ) , & ( ret -> last ) ) > 0 ) || ( calcomp ( & ( ret -> first ) , & fscal ) < 0 ) ) { msyslog ( LOG_NOTICE , " " , ret -> subject , ret -> first . year , ret -> first . month , ret -> first . monthday , ret -> first . hour , ret -> first . minute , ret -> first . second , ret -> last . year , ret -> last . month , ret -> last . monthday , ret -> last . hour , ret -> last . minute , ret -> last . second , fscal . year , fscal . month , fscal . monthday , fscal . hour , fscal . minute , fscal . second ) ; cert_free ( ret ) ; X509_free ( cert ) ; return ( NULL ) ; } ret -> cert . fstamp = htonl ( fstamp ) ; ret -> cert . vallen = htonl ( len ) ; ret -> cert . ptr = emalloc ( len ) ; memcpy ( ret -> cert . ptr , asn1cert , len ) ; X509_free ( cert ) ; return ( ret ) ; }
cert_parse - parse x509 certificate and create info/value structures.
cert_parse - parse x509 certificate and create info / value structures .
/* certificate information structure */ /* X509 certificate */ /* certificate length */ /* filestamp */ /* X509 certificate */ /* certificate info/value */ /*
	 * Decode ASN.1 objects and construct certificate structure.
	 */ /*
	 * Extract version, subject name and public key.
	 */ /*
	 * Extract remaining objects. Note that the NTP serial number is
	 * the NTP seconds at the time of signing, but this might not be
	 * the case for other authority. We don't bother to check the
	 * objects at this time, since the real crunch can happen only
	 * when the time is valid but not yet certificated.
	 */ /*
	 * Extract extension fields. These are ad hoc ripoffs of
	 * currently assigned functions and will certainly be changed
	 * before prime time.
	 */ /*
		 * If a key_usage field is present, we decode whether
		 * this is a trusted or private certificate. This is
		 * dorky; all we want is to compare NIDs, but OpenSSL
		 * insists on BIO text strings.
		 */ /*
		 * If a NID_subject_key_identifier field is present, it
		 * contains the GQ public key.
		 */ /* fall through */ /*
		 * If certificate is self signed, verify signature.
		 */ /*
		 * Check for a certificate loop.
		 */ /*
	 * Verify certificate valid times. Note that certificates cannot
	 * be retroactive.
	 */ /*
	 * Build the value structure to sign and send later.
	 */