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

📄 certwr.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************
*																			*
*							Certificate Write Routines						*
*						Copyright Peter Gutmann 1996-2001					*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL ) ||  defined( INC_CHILD )
  #include "asn1.h"
  #include "asn1objs.h"
  #include "asn1oid.h"
  #include "cert.h"
#else
  #include "keymgmt/asn1.h"
  #include "keymgmt/asn1objs.h"
  #include "keymgmt/asn1oid.h"
  #include "keymgmt/cert.h"
#endif /* Compiler-specific includes */

/* The X.509 version numbers */

enum { X509VERSION_1, X509VERSION_2, X509VERSION_3 };

/* Context-specific tags for certificates */

enum { CTAG_CE_VERSION, CTAG_CE_ISSUERUNIQUEID, CTAG_CE_SUBJECTUNIQUEID,
	   CTAG_CE_EXTENSIONS };

/* Context-specific tags for attribute certificates */

enum { CTAG_AC_BASECERTIFICATEID, CTAG_AC_ENTITYNAME,
	   CTAG_AC_OBJECTDIGESTINFO };

/* Context-specific tags for certification requests */

enum { CTAG_CR_ATTRIBUTES };

/* Context-specific tags for CRMF certification requests */

enum { CTAG_CF_VERSION, CTAG_CF_SERIALNUMBER, CTAG_CF_SIGNINGALG, 
	   CTAG_CF_ISSUER, CTAG_CF_VALIDITY, CTAG_CF_SUBJECT, CTAG_CF_PUBLICKEY,
	   CTAG_CF_ISSUERUID, CTAG_CF_SUBJECTUID, CTAG_CF_EXTENSIONS };

/* Context-specific tags for OCSP requests */

enum { CTAG_OR_VERSION, CTAG_OR_DUMMY, CTAG_OR_EXTENSIONS };

/* Context-specific tags for OCSP responses */

enum { CTAG_OP_VERSION, CTAG_OP_EXTENSIONS };

/* Context-specific tags for OCSP certificate identifier types */

enum { OCSP_IDTYPE_ISSUERANDSERIALNUMBER, OCSP_IDTYPE_CERTIFICATE, 
	   OCSP_IDTYPE_DUMMY, OCSP_IDTYPE_CERTHASH };

/* Prototypes for functions in certchk.c */

int getKeyUsageFlags( CERT_INFO *certInfoPtr, BOOLEAN *isCA );

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

/* Add standard X.509v3 extensions to a cert/attribute 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,
								  const BOOLEAN isCertificate )
	{
	CRYPT_ALGO cryptAlgo;
	ATTRIBUTE_LIST *attributeListPtr;
	BYTE keyID[ KEYID_SIZE ];
	BOOLEAN isCA;
	int keyUsage;

	/* If it's a standard certificate, get the key usage flags for the cert
	   based on any usage-related cert extensions, and get information on the
	   key in the cert */
	if( isCertificate )
		{
		RESOURCE_DATA msgData;
		int status;

		keyUsage = getKeyUsageFlags( certInfoPtr, &isCA );
		if( cryptStatusError( keyUsage ) )
			return( keyUsage );
		status = krnlSendMessage( certInfoPtr->iCryptContext, 
								  RESOURCE_IMESSAGE_GETATTRIBUTE, &cryptAlgo, 
								  CRYPT_CTXINFO_ALGO );
		if( cryptStatusError( status ) )
			return( status );
		setResourceData( &msgData, keyID, KEYID_SIZE );
		status = krnlSendMessage( certInfoPtr->iCryptContext, 
								  RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData, 
								  CRYPT_IATTRIBUTE_KEYID );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Check whether there's a basicConstraints extension present and whether
	   this is a CA certificate */
	attributeListPtr = findAttributeField( certInfoPtr->attributes,
									CRYPT_CERTINFO_CA, CRYPT_ATTRIBUTE_NONE );
	if( attributeListPtr != NULL )
		isCA = ( BOOLEAN ) attributeListPtr->value;
	else
		{
		int value = isCA;	/* Type kludge for VC++ */
		int status;

		/* There's no basicConstraint extension present, add one and make
		   it the appropriate type of cert */
		status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_CA, &value,
								   CRYPT_UNUSED );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* If it's not a key certificate, we're done */
	if( !isCertificate )
		return( CRYPT_OK );

	/* If there's no keyUsage implied by existing extensions and there's no
	   keyUsage extension present, add one based on the algorithm type */
	if( !keyUsage && \
		findAttributeField( certInfoPtr->attributes,
					CRYPT_CERTINFO_KEYUSAGE, CRYPT_ATTRIBUTE_NONE ) == NULL )
		{
		int status;

		if( isCA )
			{
			/* A non-signature key can never be a CA key */
			if( !isSigAlgo( cryptAlgo ) )
				{
				setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CA,
							  CRYPT_ERRTYPE_CONSTRAINT );
				return( CRYPT_ERROR_INVALID );
				}

			/* We only allow the CA key to be used for certification-
			   related purposes, if they want anything else they have to
			   specify it explicitly */
			keyUsage = CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN;
			}
		else
			{
			/* Set the key usage flags based on the algorithm type.  Because
			   noone 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( isSigAlgo( cryptAlgo ) )
				keyUsage |= CRYPT_KEYUSAGE_DIGITALSIGNATURE;
			if( isCryptAlgo( cryptAlgo ) )
				keyUsage |= CRYPT_KEYUSAGE_KEYENCIPHERMENT;
			if( isKeyxAlgo( cryptAlgo ) )
				keyUsage |= CRYPT_KEYUSAGE_KEYAGREEMENT;
			}

		status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
								   &keyUsage, CRYPT_UNUSED );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Add the subjectKeyIdentifier */
	return( addCertComponent( certInfoPtr, CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER,
							  keyID, KEYID_SIZE ) );
	}

/* 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 : time( NULL );

	/* 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 )
		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 which 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
		OCSP req.						exts.

	   Since some of the checks depend on data which 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->iCryptContext == CRYPT_ERROR )
		{
		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 )
		{
		int encodeValidityNesting;

		/* Enforce validity period nesting if necessary */
		krnlSendMessage( subjectCertInfoPtr->ownerHandle, 
						 RESOURCE_IMESSAGE_GETATTRIBUTE, &encodeValidityNesting, 
						 CRYPT_OPTION_CERT_ENCODE_VALIDITYNESTING );
		if( encodeValidityNesting )
			{
			/* 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;
			}

		/* Add the standard X.509v3 extensions if these aren't already
		   present */
		if( subjectCertInfoPtr->version > 2 )
			{
			status = addStandardExtensions( subjectCertInfoPtr,
					( BOOLEAN )	/* Needed by VC++ */
					( ( type == CRYPT_CERTTYPE_CERTIFICATE ) ? TRUE : FALSE ) );
			if( cryptStatusError( status ) )
				return( status );
			}
		}
	if( type == CRYPT_CERTTYPE_CERTIFICATE || \
		type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
		type == CRYPT_CERTTYPE_CRL )
		{
		/* 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 )
		{
		/* 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->issuerName, FALSE ) )
			{
			setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
						  CRYPT_ERRTYPE_ATTR_VALUE );
			return( CRYPT_ERROR_INVALID );
			}
		}
	if( type == CRYPT_CERTTYPE_CRL || type == CRYPT_CERTTYPE_OCSP_REQUEST )
		{
		/* If it's a CRL or OCSP request, prepare the revocation list entries
		   prior to encoding them */
		status = prepareRevocationEntries( subjectCertInfoPtr->revocations,
										   subjectCertInfoPtr->revocationTime,
										   &subjectCertInfoPtr->currentRevocation,
										   &subjectCertInfoPtr->errorLocus,
										   &subjectCertInfoPtr->errorType );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Now that we've set up the attributes, perform the remainder of the
	   checks */
	status = checkAttributes( ATTRIBUTE_CERTIFICATE,
							  subjectCertInfoPtr->attributes,
							  &subjectCertInfoPtr->errorLocus,
							  &subjectCertInfoPtr->errorType );
	if( cryptStatusError( status ) )
		return( status );
	if( type == CRYPT_CERTTYPE_CERTIFICATE || \
		type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
		type == CRYPT_CERTTYPE_CRL )
		status = checkCert( subjectCertInfoPtr, issuerCertInfoPtr );
	return( status );
	}

/* Write a CRL entry:

	RevokedCert ::= SEQUENCE {
			userCertificate		CertificalSerialNumber,
			revocationDate		UTCTime
			extensions			Extensions OPTIONAL,
			} */

int sizeofCRLentry( REVOCATION_INFO *crlEntry )
	{
	/* Remember the encoded attribute size for later when we write the
	   attributes */
	crlEntry->attributeSize = sizeofAttributes( crlEntry->attributes );

	return( ( int ) sizeofObject( \
						sizeofInteger( crlEntry->data, crlEntry->dataLength ) + \
						sizeofUTCTime() + \
						( ( crlEntry->attributeSize ) ? \
							( int ) sizeofObject( crlEntry->attributeSize ) : 0 ) ) );
	}

int writeCRLentry( STREAM *stream, const REVOCATION_INFO *crlEntry )
	{
	const int revocationLength = \
				sizeofInteger( crlEntry->data, crlEntry->dataLength ) + \
				sizeofUTCTime() + \
				( ( crlEntry->attributeSize ) ? \
					( int ) sizeofObject( crlEntry->attributeSize ) : 0 );

	/* Write the CRL entry */
	writeSequence( stream, revocationLength );
	writeInteger( stream, crlEntry->data, crlEntry->dataLength, DEFAULT_TAG );
	writeUTCTime( stream, crlEntry->revocationTime, DEFAULT_TAG );

	/* Write the per-entry extensions if necessary.  Since these are per-
	   entry extensions we write them as CRYPT_CERTTYPE_NONE rather than
	   CRYPT_CERTTYPE_CRL to make sure they're processed as required  */
	if( crlEntry->attributeSize )
		writeAttributes( stream, crlEntry->attributes, CRYPT_CERTTYPE_NONE,
						 crlEntry->attributeSize );

	return( sGetStatus( stream ) );
	}

/* Write an OCSP entry, either a request or a response:

	Entry ::= SEQUENCE {				-- Request

⌨️ 快捷键说明

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