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

📄 certsig.c

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

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

/* Prototypes for functions in lib_sign.c */

int createX509signature( void *signedObject, int *signedObjectLength,
						 const void *object, const int objectLength,
						 CRYPT_CONTEXT signContext,
						 const CRYPT_ALGO hashAlgo );
int checkX509signature( const void *signedObject, const int signedObjectLength,
						void **object, int *objectLength, 
						CRYPT_CONTEXT sigCheckContext );

/****************************************************************************
*																			*
*							Certificate Signing Functions					*
*																			*
****************************************************************************/

/* Sign a certificate object */

int signCert( CERT_INFO *certInfoPtr, const CRYPT_CONTEXT signContext )
	{
	CERT_INFO *issuerCertInfoPtr = NULL;
	STREAM stream;
	BOOLEAN issuerCertPresent = FALSE, isCertificate = FALSE;
	BOOLEAN nonSigningKey = FALSE;
	BYTE certObjectBuffer[ 1024 ], *certObjectPtr = certObjectBuffer;
	int ( *writeCertObjectFunction )( STREAM *stream, CERT_INFO *subjectCertInfoPtr,
									  const CERT_INFO *issuerCertInfoPtr,
									  const CRYPT_CONTEXT iIssuerCryptContext );
	void *signedCertObject;
	const time_t currentTime = time( NULL );
	int certObjectLength, signedCertObjectLength, status;

	/* If it's a non-signing key we have to create a special format of cert
	   request which isn't signed but contains an indication that the private
	   key POP will be performed by out-of-band means.  We have to check for
	   the signContext being absent to handle OCSP requests for which the
	   signature is optional so there may be no signing key present */
	if( signContext == CRYPT_UNUSED || \
		cryptStatusError( krnlSendMessage( signContext, RESOURCE_IMESSAGE_CHECK, 
						  NULL, RESOURCE_MESSAGE_CHECK_PKC_SIGN ) ) )
		nonSigningKey = TRUE;

	/* Set up type and version information as appropriate.  We only handle 
	   certificates at this point, other objects have versions which are 
	   either explicitly determined (OCSP, setting certain attributes forces
	   use of v1 or v2) or implicitly determined when the object is finalised
	   for writing (for example CRLs, where the presence of extensions, 
	   either added directly or copied from the signing cert, creates a v2 
	   CRL).  The remaining object types only have a single version */
	if( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
		certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
		certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
		{
		int createV3cert;

		isCertificate = TRUE;
		krnlSendMessage( certInfoPtr->ownerHandle, 
						 RESOURCE_IMESSAGE_GETATTRIBUTE, &createV3cert, 
						 CRYPT_OPTION_CERT_CREATEV3CERT );
		certInfoPtr->version = \
			( createV3cert || certInfoPtr->attributes != NULL ) ? 3 : 1;
		}

	/* Obtain the issuer certificate from the private key if necessary */
	if( isCertificate || certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
		( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST && \
		  signContext != CRYPT_UNUSED ) || \
		certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
		{
		/* If it's a self-signed cert, the issuer is also the subject */
		if( certInfoPtr->flags & CERT_FLAG_SELFSIGNED )
			issuerCertInfoPtr = certInfoPtr;
		else
			{
			CRYPT_CERTIFICATE dataOnlyCert;

			/* Get the data-only certificate from the context */
			status = krnlSendMessage( signContext, 
								RESOURCE_IMESSAGE_GETDEPENDENT, &dataOnlyCert,
								OBJECT_TYPE_CERTIFICATE );
			if( cryptStatusError( status ) )
				return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
						CRYPT_ARGERROR_VALUE : status );
			getCheckInternalResource( dataOnlyCert, issuerCertInfoPtr,
									  OBJECT_TYPE_CERTIFICATE );
			issuerCertPresent = TRUE;
			}

		/* Make sure the key associated with the issuer cert is valid for
		   cert/CRL signing: We need a key+complete certificate (unless we're
		   creating a self-signed cert), and the cert has to allow the key to
		   be used for cert/CRL signing, unless we're signing an OCSP 
		   response in which case the choose-your-own-signing-semantics in
		   the RFC don't really allow much in the way of checking */
		if( ( issuerCertInfoPtr->type != CRYPT_CERTTYPE_CERTIFICATE && \
			  issuerCertInfoPtr->type != CRYPT_CERTTYPE_CERTCHAIN ) || \
			( issuerCertPresent && issuerCertInfoPtr->certificate == NULL ) )
			status = CRYPT_ARGERROR_VALUE;
		else
			if( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST )
				status = checkCertUsage( issuerCertInfoPtr, 
							CRYPT_KEYUSAGE_DIGITALSIGNATURE | CRYPT_KEYUSAGE_NONREPUDIATION,
							RESOURCE_MESSAGE_CHECK_PKC_SIGN, &certInfoPtr->errorLocus, 
							&certInfoPtr->errorType );
			else
				if( certInfoPtr->type != CRYPT_CERTTYPE_OCSP_RESPONSE )
					{
					status = checkCertUsage( issuerCertInfoPtr, ( isCertificate ) ? \
							CRYPT_KEYUSAGE_KEYCERTSIGN : CRYPT_KEYUSAGE_CRLSIGN,
							RESOURCE_MESSAGE_CHECK_CA, &certInfoPtr->errorLocus, 
							&certInfoPtr->errorType );
					if( cryptStatusError( status ) && \
						certInfoPtr->errorType == CRYPT_ERRTYPE_CONSTRAINT )
						/* If there was a constraint problem, it's something 
						   in the issuer's cert rather than the cert being 
						   signed so we have to change the error type 
						   accordingly.  What's reported isn't striclty 
						   accurate since the locus is in the issuer rather 
						   than subject cert, but it's the best we can do */
						certInfoPtr->errorType = CRYPT_ERRTYPE_ISSUERCONSTRAINT;
					}
		if( cryptStatusError( status ) )
			{
			if( issuerCertPresent )
				unlockResource( issuerCertInfoPtr );
			return( status );
			}
		}

	/* If it's a certificate chain, copy over the signing cert and order the
	   certificates in the chain from the current one up to the root */
	if( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
		{
		/* If there's a chain of certs present (for example from a previous
		   signing attempt which wasn't completed due to an error), free
		   them */
		if( certInfoPtr->certChainEnd )
			{
			int i;

			for( i = 0; i < certInfoPtr->certChainEnd; i++ )
				krnlSendNotifier( certInfoPtr->certChain[ i ],
								  RESOURCE_IMESSAGE_DECREFCOUNT );
			certInfoPtr->certChainEnd = 0;
			}

		/* If it's a self-signed cert, it must be the only cert in the chain
		   (creating a chain like this doesn't make much sense, but we handle
		   it anyway) */
		if( certInfoPtr->flags & CERT_FLAG_SELFSIGNED )
			{
			if( certInfoPtr->certChainEnd )
				{
				setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
							  CRYPT_ERRTYPE_ATTR_PRESENT );
				return( CRYPT_ERROR_INVALID );
				}
			}
		else
			{
			/* Copy the cert chain into the cert to be signed */
			status = copyCertChain( certInfoPtr, signContext );
			if( cryptStatusError( status ) )
				return( status );
			}
		}

	/* If it's some certificate variant or CRL/OCSP response and the various 
	   timestamps haven't been set yet, start them at the current time and 
	   give them the default validity period or next update time if these 
	   haven't been set.  The time used is the local time, this is converted 
	   to GMT when we write it to the certificate.  Issues like validity 
	   period nesting and checking for valid time periods are handled when 
	   the data is encoded */
	if( ( isCertificate || certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
		  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE ) && \
		!certInfoPtr->startTime )
		certInfoPtr->startTime = currentTime;
	if( isCertificate && !certInfoPtr->endTime )
		{
		int validity;

		krnlSendMessage( certInfoPtr->ownerHandle, 
						 RESOURCE_IMESSAGE_GETATTRIBUTE, &validity, 
						 CRYPT_OPTION_CERT_VALIDITY );
		certInfoPtr->endTime = certInfoPtr->startTime + \
							   ( ( time_t ) validity * 86400L );
		}
	if( certInfoPtr->type == CRYPT_CERTTYPE_CRL || \
		certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
		{
		if( !certInfoPtr->endTime )
			if( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
				/* OCSP responses come directly from the certificate store
				   and represent an atomic (and ephemeral) snapshot of the 
				   store state.  Because of this the next-update time is
				   effectively immediately, since the next snapshot could
				   provide a different response */
				certInfoPtr->endTime = currentTime;
			else
				{
				int updateInterval;

				krnlSendMessage( certInfoPtr->ownerHandle, 
								 RESOURCE_IMESSAGE_GETATTRIBUTE, &updateInterval, 
								 CRYPT_OPTION_CERT_UPDATEINTERVAL );

				certInfoPtr->endTime = certInfoPtr->startTime + \
									   ( ( time_t ) updateInterval * 86400L );
				}
		if( !certInfoPtr->revocationTime )
			certInfoPtr->revocationTime = currentTime;
		}

	/* If it's a certificate, set up the certificate serial number.  Ideally
	   we would store this as a static value in the configuration database,
	   but this has three disadvantages: Updating the serial number updates
	   the entire configuration database (including things the user might not
	   want updated), if the config database update fails the serial number
	   never changes, and the predictable serial number allows tracking of
	   the number of certificates which have been signed by the CA.  Because 
	   of this, we just use a 64-bit nonce */
	if( isCertificate )
		{
		BYTE *dataPtr;

		/* Allocate storage for the value and copy it in, clearing the high 
		   bit to provide a constant-length ASN.1 encoded value */
		if( ( dataPtr = malloc( 8 ) ) == NULL )
			{
			if( issuerCertPresent )
				unlockResource( issuerCertInfoPtr );
			return( CRYPT_ERROR_MEMORY );
			}
		if( certInfoPtr->serialNumber != NULL )
			free( certInfoPtr->serialNumber );
		getNonce( dataPtr, 8 );
		dataPtr[ 0 ] &= 0x7F;
		certInfoPtr->serialNumber = dataPtr;
		certInfoPtr->serialNumberLength = 8;
		}

	/* Select the function to use to write the certificate object to be
	   signed */
	switch( certInfoPtr->type )
		{
		case CRYPT_CERTTYPE_CERTIFICATE:
		case CRYPT_CERTTYPE_CERTCHAIN:
			writeCertObjectFunction = writeCertInfo;
			break;

		case CRYPT_CERTTYPE_ATTRIBUTE_CERT:
			writeCertObjectFunction = writeAttributeCertInfo;
			break;

		case CRYPT_CERTTYPE_CERTREQUEST:
			writeCertObjectFunction = writeCertRequestInfo;
			break;

		case CRYPT_CERTTYPE_REQUEST_CERT:
			writeCertObjectFunction = writeCRMFRequestInfo;
			break;

		case CRYPT_CERTTYPE_REQUEST_REVOCATION:
			writeCertObjectFunction = writeRevRequestInfo;
			break;

		case CRYPT_CERTTYPE_CRL:
			writeCertObjectFunction = writeCRLInfo;
			break;

		case CRYPT_CERTTYPE_OCSP_REQUEST:
			writeCertObjectFunction = writeOCSPRequestInfo;
			break;

		case CRYPT_CERTTYPE_OCSP_RESPONSE:
			writeCertObjectFunction = writeOCSPResponseInfo;
			break;

		case CRYPT_CERTTYPE_PKIUSER:
			writeCertObjectFunction = writePKIUserInfo;
			break;

		default:
			assert( NOTREACHED );
		}

	/* Determine how big the encoded certificate information will be,
	   allocate memory for it and the full signed certificate, and write the
	   encoded certificate information */
	sMemOpen( &stream, NULL, 0 );
	status = writeCertObjectFunction( &stream, certInfoPtr, issuerCertInfoPtr,
									  signContext );
	certObjectLength = ( int ) stell( &stream );
	sMemClose( &stream );
	if( cryptStatusError( status ) )
		{
		if( issuerCertPresent )
			unlockResource( issuerCertInfoPtr );
		return( status );
		}
	if( ( certObjectLength > 1024 && \
		  ( certObjectPtr = malloc( certObjectLength ) ) == NULL ) || \
		( signedCertObject = malloc( certObjectLength + 1024 ) ) == NULL )
		{
		if( certObjectPtr != NULL )
			free( certObjectPtr );
		if( issuerCertPresent )
			unlockResource( issuerCertInfoPtr );
		return( CRYPT_ERROR_MEMORY );
		}
	sMemOpen( &stream, certObjectPtr, certObjectLength );
	status = writeCertObjectFunction( &stream, certInfoPtr, issuerCertInfoPtr,
									  signContext );
	assert( certObjectLength == stream.bufPos );

⌨️ 快捷键说明

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