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

📄 certwr.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
*																			*
*							Certificate Write Routines						*
*						Copyright Peter Gutmann 1996-2003					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL ) ||  defined( INC_CHILD )
  #include "cert.h"
  #include "../misc/asn1_rw.h"
  #include "../misc/asn1s_rw.h"
#else
  #include "cert/cert.h"
  #include "misc/asn1_rw.h"
  #include "misc/asn1s_rw.h"
#endif /* Compiler-specific includes */

/* The X.509 version numbers */

enum { X509VERSION_1, X509VERSION_2, X509VERSION_3 };

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Add standard X.509v3 extensions to a cert if they're not already present.
   This function simply adds the required extensions, it doesn't check for
   consistency with existing extensions which is done later by checkCert() */

static int addStandardExtensions( CERT_INFO *certInfoPtr )
	{
	ATTRIBUTE_LIST *attributeListPtr;
	BOOLEAN isCA = FALSE;
	int keyUsage, extKeyUsage, status;

	/* Get various pieces of information about the cert.  We do this before
	   we make any changes so we can safely bail out if necessary.  First we
	   get the implicit key usage flags (based on any extended key usage
	   extensions present) and explicit key usage flags.  Since these are
	   required to be consistent, we extend the keyUsage with extKeyUsage
	   flags further on if necessary */
	extKeyUsage = getKeyUsageFromExtKeyUsage( certInfoPtr,
						&certInfoPtr->errorLocus, &certInfoPtr->errorType );
	if( cryptStatusError( extKeyUsage ) )
		return( extKeyUsage );
	attributeListPtr = findAttributeField( certInfoPtr->attributes,
										   CRYPT_CERTINFO_KEYUSAGE,
										   CRYPT_ATTRIBUTE_NONE );
	keyUsage = ( attributeListPtr != NULL ) ? \
			   attributeListPtr->intValue : 0;

	/* If there's an explicit key usage present, make sure that it's
	   consistent with the implicit key usage flags derived from the extended
	   key usage.  We mask out the nonRepudiation bit for reasons given in
	   certchk.c.

	   This check is also performed by checkCert(), however we need to
	   explicitly perform it here as well since we need to add a key usage
	   to match the extKeyUsage before calling checkCert() if one wasn't
	   explicitly set or checkCert() will reject the cert because of the
	   inconsistent keyUsage */
	if( keyUsage )
		{
		const int effectiveKeyUsage = \
						extKeyUsage & ~CRYPT_KEYUSAGE_NONREPUDIATION;

		if( ( keyUsage & effectiveKeyUsage ) != effectiveKeyUsage )
			{
			setErrorInfo( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
						  CRYPT_ERRTYPE_CONSTRAINT );
			return( CRYPT_ERROR_INVALID );
			}
		}

	/* Check whether this is a CA certificate */
	attributeListPtr = findAttributeField( certInfoPtr->attributes,
										   CRYPT_CERTINFO_CA,
										   CRYPT_ATTRIBUTE_NONE );
	if( attributeListPtr != NULL )
		isCA = attributeListPtr->intValue;

	/* If there's no explicit keyUsage information present, add it based on
	   various implicit information.  We also add key feature information
	   which is used to help automate key management, for example to inhibit
	   speculative reads of keys held in removable tokens, which can result
	   in spurious insert-token dialogs being presented to the user outside
	   the control of cryptlib if the token isn't present */
	if( !keyUsage )
		{
		/* If there's no implicit key usage present, set the key usage flags
		   based on the algorithm type.  Because no-one can figure out what
		   the nonRepudiation flag signifies, we don't set this, if the user
		   wants it they have to specify it explicitly */
		if( !extKeyUsage && !isCA )
			{
			if( isSigAlgo( certInfoPtr->publicKeyAlgo ) )
				keyUsage = CRYPT_KEYUSAGE_DIGITALSIGNATURE;
			if( isCryptAlgo( certInfoPtr->publicKeyAlgo ) )
				keyUsage |= CRYPT_KEYUSAGE_KEYENCIPHERMENT;
			if( isKeyxAlgo( certInfoPtr->publicKeyAlgo ) )
				keyUsage |= CRYPT_KEYUSAGE_KEYAGREEMENT;
			}
		else
			{
			/* Make the usage consistent with the extended usage */
			keyUsage = extKeyUsage;

			/* If it's a CA key, make sure it's a signing key and enable its
			   use for certification-related purposes*/
			if( isCA )
				{
				if( !isSigAlgo( certInfoPtr->publicKeyAlgo ) )
					{
					setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CA,
								  CRYPT_ERRTYPE_CONSTRAINT );
					return( CRYPT_ERROR_INVALID );
					}
				keyUsage |= CRYPT_KEYUSAGE_KEYCERTSIGN | \
							CRYPT_KEYUSAGE_CRLSIGN;
				}
			}
		assert( keyUsage );
		status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
								   &keyUsage, CRYPT_UNUSED );
		if( cryptStatusError( status ) )
			return( status );
		}
	if( certInfoPtr->publicKeyFeatures )
		{
		/* This is a bitstring so we only add it if there are feature flags
		   present to avoid writing zero-length values */
		status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_KEYFEATURES,
								   &certInfoPtr->publicKeyFeatures,
								   CRYPT_UNUSED );
		if( cryptStatusError( status ) && status != CRYPT_ERROR_INITED )
			return( status );
		}

	/* Add the subjectKeyIdentifier */
	return( addCertComponent( certInfoPtr, CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER,
							  certInfoPtr->publicKeyID, KEYID_SIZE ) );
	}

/* Prepare the entries in a cert status list prior to encoding them */

static int prepareCertStatusEntries( REVOCATION_INFO *listPtr,
									 const time_t defaultTime,
									 REVOCATION_INFO **errorEntry,
									 CRYPT_ATTRIBUTE_TYPE *errorLocus,
									 CRYPT_ERRTYPE_TYPE *errorType )
	{
	REVOCATION_INFO *revocationEntry;
	const time_t currentTime = defaultTime ? defaultTime : getApproxTime();

	/* Set the invalidity time if this hasn't already been set.  If there's a
	   default time set we use that, otherwise we use the current time */
	for( revocationEntry = listPtr; revocationEntry != NULL; \
		 revocationEntry = revocationEntry->next )
		if( !revocationEntry->revocationTime )
			revocationEntry->revocationTime = currentTime;

	/* Check the attributes for each entry in a revocation list */
	for( revocationEntry = listPtr; revocationEntry != NULL; \
		 revocationEntry = revocationEntry->next )
		{
		int status;

		status = checkAttributes( ATTRIBUTE_CERTIFICATE,
								  revocationEntry->attributes,
								  errorLocus, errorType );
		if( cryptStatusError( status ) )
			{
			/* Remember the entry that caused the problem */
			*errorEntry = revocationEntry;
			return( status );
			}
		}

	return( CRYPT_OK );
	}

/* Prepare the entries in a revocation list prior to encoding them */

static int prepareRevocationEntries( REVOCATION_INFO *listPtr,
									 const time_t defaultTime,
									 REVOCATION_INFO **errorEntry,
									 CRYPT_ATTRIBUTE_TYPE *errorLocus,
									 CRYPT_ERRTYPE_TYPE *errorType )
	{
	REVOCATION_INFO *revocationEntry;
	const time_t currentTime = defaultTime ? defaultTime : getApproxTime();

	/* Set the revocation time if this hasn't already been set.  If there's a
	   default time set we use that, otherwise we use the current time */
	for( revocationEntry = listPtr; revocationEntry != NULL; \
		 revocationEntry = revocationEntry->next )
		{
		const ATTRIBUTE_LIST *attributeListPtr;

		if( !revocationEntry->revocationTime )
			revocationEntry->revocationTime = currentTime;

		/* Check whether the cert was revoked with a reason of neverValid,
		   which requires special handling of dates because X.509 doesn't
		   formally define a neverValid reason, assuming that all CAs are
		   perfect and never issue certs in error.  The general idea is to
		   set the two to the same value, with the invalidity date (which
		   should be earlier than the revocation date, at least in a sanely-
		   run CA) taking precedence.  A revocation with this reason code will
		   in general only be issued by the cryptlib CA (where it's required
		   to handle problems in the CMP protocol) and this always sets the
		   invalidity date, so in almost all cases we'll be setting the
		   revocation date to the (CA-specified) invalidity date, which is
		   the date of issue of the cert being revoked */
		attributeListPtr = findAttributeField( revocationEntry->attributes,
											   CRYPT_CERTINFO_CRLREASON,
											   CRYPT_ATTRIBUTE_NONE );
		if( attributeListPtr != NULL && \
			attributeListPtr->intValue == CRYPT_CRLREASON_NEVERVALID )
			{
			/* The cert was revoked with the neverValid code, see if there's
			   an invalidity date present */
			attributeListPtr = \
					findAttributeField( revocationEntry->attributes,
										CRYPT_CERTINFO_INVALIDITYDATE,
										CRYPT_ATTRIBUTE_NONE );
			if( attributeListPtr == NULL )
				/* There's no invalidity date present, set it to the same as
				   the revocation date */
				addAttributeField( &revocationEntry->attributes,
								   CRYPT_CERTINFO_INVALIDITYDATE,
								   CRYPT_ATTRIBUTE_NONE,
								   &revocationEntry->revocationTime,
								   sizeof( time_t ), ATTR_FLAG_NONE,
								   NULL, NULL );
			else
				/* There's an invalidity date present, make sure the
				   revocation date is the same as the invalidity date */
				revocationEntry->revocationTime = \
						*( time_t * ) attributeListPtr->value;
			}
		}

	/* Check the attributes for each entry in a revocation list */
	for( revocationEntry = listPtr; revocationEntry != NULL; \
		 revocationEntry = revocationEntry->next )
		{
		int status;

		status = checkAttributes( ATTRIBUTE_CERTIFICATE,
								  revocationEntry->attributes,
								  errorLocus, errorType );
		if( cryptStatusError( status ) )
			{
			/* Remember the entry that caused the problem */
			*errorEntry = revocationEntry;
			return( status );
			}
		}

	return( CRYPT_OK );
	}

/* Prepare to create a certificate object */

static int preEncodeCertificate( CERT_INFO *subjectCertInfoPtr,
								 const CERT_INFO *issuerCertInfoPtr,
								 const CRYPT_CERTTYPE_TYPE type )
	{
	int status;

	/* Make sure everything is in order.  We perform the following checks for
	   the different object types:

		Object			Checks
		-----------------------------------------------
		cert			key		DN		exts	cert
		attr.cert				DN		exts	cert
		cert.req		key		DN		exts
		CRMF cert.req	key		DN(optional)
		CRMF rev.req					exts
		CRL								exts	cert
		RTCS req.						exts
		RTCS resp.						exts
		OCSP req.						exts
		OCSP resp.						exts	cert

	   Since some of the checks depend on data that isn't set up yet, we
	   break the checking up into two phases, the first one which is
	   performed immediately and the second one which is performed after
	   default and issuer-contributed attributes have been added */
	if( ( type == CRYPT_CERTTYPE_CERTIFICATE || \
		  type == CRYPT_CERTTYPE_CERTREQUEST || \
		  type == CRYPT_CERTTYPE_REQUEST_CERT ) && \
		subjectCertInfoPtr->publicKeyInfo == NULL )
		{
		setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO,
					  CRYPT_ERRTYPE_ATTR_ABSENT );
		return( CRYPT_ERROR_NOTINITED );
		}
	if( type == CRYPT_CERTTYPE_CERTIFICATE || \
		type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
		type == CRYPT_CERTTYPE_CERTREQUEST || \
		( type == CRYPT_CERTTYPE_REQUEST_CERT && \
		  subjectCertInfoPtr->subjectName != NULL ) )
		{
		/* If it's a cert request, we allow the country to be optional since
		   some CA's fill this in themselves */
		status = checkDN( subjectCertInfoPtr->subjectName, TRUE,
						  ( type == CRYPT_CERTTYPE_CERTREQUEST || \
							type == CRYPT_CERTTYPE_REQUEST_CERT ) ? TRUE : FALSE,
						  &subjectCertInfoPtr->errorLocus,
						  &subjectCertInfoPtr->errorType );
		if( cryptStatusError( status ) )
			return( status );

		/* If we're creating a non-self-signed cert, check whether the
		   subject's DN is the same as the issuer's DN.  If this is the case,
		   the resulting object would appear to be self-signed so we disallow
		   it */
		if( ( type == CRYPT_CERTTYPE_CERTIFICATE || \
			  type == CRYPT_CERTTYPE_ATTRIBUTE_CERT ) && \
			!( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) && \
			compareDN( issuerCertInfoPtr->subjectName,
					   subjectCertInfoPtr->subjectName, FALSE ) )
			{
			setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_SUBJECTNAME,
						  CRYPT_ERRTYPE_ISSUERCONSTRAINT );
			return( CRYPT_ERROR_NOTINITED );
			}
		}

	/* Handle various default certificate extensions if necessary */
	if( type == CRYPT_CERTTYPE_CERTIFICATE || \
		type == CRYPT_CERTTYPE_ATTRIBUTE_CERT )
		{
		/* Constrain the subject validity period to be within the issuer
		   validity period */
		if( subjectCertInfoPtr->startTime < issuerCertInfoPtr->startTime )
			subjectCertInfoPtr->startTime = issuerCertInfoPtr->startTime;
		if( subjectCertInfoPtr->endTime > issuerCertInfoPtr->endTime )
			subjectCertInfoPtr->endTime = issuerCertInfoPtr->endTime;

		/* If it's a >= v3 cert, add the standard X.509v3 extensions if these
		   aren't already present */
		if( ( type == CRYPT_CERTTYPE_CERTIFICATE ) && \
			( subjectCertInfoPtr->version >= 3 ) )
			{
			status = addStandardExtensions( subjectCertInfoPtr );
			if( cryptStatusError( status ) )
				return( status );
			}
		}
	if( type == CRYPT_CERTTYPE_CERTIFICATE || \
		type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
		( type == CRYPT_CERTTYPE_CRL && issuerCertInfoPtr != NULL ) )
		{
		/* Copy the issuer DN if this isn't already present */
		if( subjectCertInfoPtr->issuerName == NULL )
			{
			status = copyDN( &subjectCertInfoPtr->issuerName,
							 issuerCertInfoPtr->subjectName );
			if( cryptStatusError( status ) )
				return( status );
			}

		/* Copy any required extensions from the issuer to the subject cert
		   if necessary */
		if( !( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
			{
			status = copyIssuerAttributes( &subjectCertInfoPtr->attributes,
										   issuerCertInfoPtr->attributes,
										   &subjectCertInfoPtr->errorLocus,
										   &subjectCertInfoPtr->errorType,
										   subjectCertInfoPtr->type );
			if( cryptStatusError( status ) )
				return( status );
			}
		}
	if( type == CRYPT_CERTTYPE_CRL && issuerCertInfoPtr != NULL )
		{
		/* If it's a CRL, compare the revoked cert issuer DN and signer DN
		   to make sure we're not trying to revoke someone else's certs, and
		   prepare the revocation entries */
		if( !compareDN( subjectCertInfoPtr->issuerName,
						issuerCertInfoPtr->subjectName, FALSE ) )
			{
			setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
						  CRYPT_ERRTYPE_ATTR_VALUE );
			return( CRYPT_ERROR_INVALID );
			}
		}
	if( type == CRYPT_CERTTYPE_RTCS_RESPONSE )
		{

⌨️ 快捷键说明

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