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

📄 env_cms.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 4 页
字号:
			{
			status = writeEOCs( envelopeInfoPtr, 1 );
			if( cryptStatusError( status ) )
				return( status );
			}

		/* Move on to the next state */
		envelopeInfoPtr->envState = ENVSTATE_ENCRINFO;
		}

	/* Handle encrypted content information */
	if( envelopeInfoPtr->envState == ENVSTATE_ENCRINFO )
		{
		STREAM stream;
		const int dataLeft = min( envelopeInfoPtr->bufSize - \
								  envelopeInfoPtr->bufPos, 8192 );
		int length;

		/* Make sure that there's enough room to emit the data header.  The
		   value used is only approximate, if there's not enough room left 
		   the write will also return an overflow error */
		if( dataLeft < 256 )
			return( CRYPT_ERROR_OVERFLOW );

		/* Write the encrypted content header */
		sMemOpen( &stream, envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos, 
				  dataLeft );
		status = writeEncryptedContentHeader( &stream,
							getContentOID( envelopeInfoPtr->contentType ),
							envelopeInfoPtr->iCryptContext, 
							envelopeInfoPtr->payloadSize, 
							envelopeInfoPtr->blockSize );
		length = stell( &stream );
		sMemDisconnect( &stream );
		if( cryptStatusError( status ) )
			return( status );
		envelopeInfoPtr->bufPos += length;

		/* Make sure that we start a new segment if we try to add any data */
		envelopeInfoPtr->dataFlags |= ENVDATA_SEGMENTCOMPLETE;

		/* We're done */
		envelopeInfoPtr->envState = ENVSTATE_DONE;
		}

	return( status );
	}

/* Output as much of the postamble as possible into the envelope buffer */

static int emitPostamble( ENVELOPE_INFO *envelopeInfoPtr )
	{
	ACTION_LIST *lastActionPtr;
	int status;

	/* Before we can emit the trailer we need to flush any remaining data
	   from internal buffers */
	if( envelopeInfoPtr->envState == ENVSTATE_NONE )
		{
		status = envelopeInfoPtr->copyToEnvelopeFunction( envelopeInfoPtr, 
													( BYTE * ) "", 0 );
		if( cryptStatusError( status ) )
			return( status );
		envelopeInfoPtr->envState = ENVSTATE_FLUSHED;
		}

	/* The only message type that has a trailer is signed data, if we're not
	   signing data we can exit now */
	if( envelopeInfoPtr->usage != ACTION_SIGN )
		{
		/* Emit the various end-of-contents octets if necessary */
		if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED || \
			( envelopeInfoPtr->usage == ACTION_CRYPT &&
			  envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED ) )
			{
			/* Write the end-of-contents octets for the encapsulated data if 
			   necessary.  Normally we have two EOC's, however compressed 
			   data requires an extra one due to the explicit tagging */
			if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED && \
				( envelopeInfoPtr->usage == ACTION_CRYPT || \
				  envelopeInfoPtr->usage == ACTION_COMPRESS ) )
				status = writeEOCs( envelopeInfoPtr, 3 + \
									( ( envelopeInfoPtr->usage == \
										ACTION_COMPRESS ) ? \
									  3 : 2 ) );
			else
				/* Write the remaining end-of-contents octets for the OCTET 
				   STRING/SEQUENCE, [0], and SEQUENCE */
				status = writeEOCs( envelopeInfoPtr, 3 );
			if( cryptStatusError( status ) )
				return( status );
			}

		/* Now that we've written the final end-of-contents octets, set the end-
		   of-segment-data pointer to the end of the data in the buffer so that
		   copyFromEnvelope() can copy out the remaining data */
		envelopeInfoPtr->segmentDataEnd = envelopeInfoPtr->bufPos;
		envelopeInfoPtr->envState = ENVSTATE_DONE;

		return( CRYPT_OK );
		}

	/* If there's any signature data left in the auxiliary buffer, try and 
	   empty that first */
	if( envelopeInfoPtr->auxBufPos > 0 )
		{
		status = copyFromAuxBuffer( envelopeInfoPtr );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Handle signing cert chain.  This can grow arbitrarily large, and in
	   particular can become larger than the main envelope buffer if 
	   multiple signatures with long chains and a small envelope buffer are
	   used, so we emit the cert chain into a dynamically-allocated 
	   auxiliary buffer if there isn't enough room to emit it into the main 
	   buffer */
	if( envelopeInfoPtr->envState == ENVSTATE_FLUSHED )
		{
		STREAM stream;
		void *certChainBufPtr;
		const int dataLeft = min( envelopeInfoPtr->bufSize - \
								  envelopeInfoPtr->bufPos, 32767 );
		const int eocSize = \
					( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
					( 3 * 2 ) : 0;
		int certChainBufSize, certChainSize;

		/* Check whether there's enough room left in the buffer to emit the 
		   signing cert chain directly into it */
		if( envelopeInfoPtr->extraDataSize + 64 < dataLeft )
			{
			certChainBufPtr = envelopeInfoPtr->buffer + \
							  envelopeInfoPtr->bufPos + eocSize;
			certChainBufSize = dataLeft - eocSize;
			}
		else
			{
			/* If there's almost no room left in the buffer anyway, tell the 
			   user that they have to pop some data before they can 
			   continue.  Hopefully this will create enough room to emit the 
			   certs directly into the buffer */	
			if( dataLeft < 1024 )
				return( CRYPT_ERROR_OVERFLOW );

			/* We can't emit the certs directly into the envelope buffer, 
			   allocate an auxiliary buffer for it and from there copy it 
			   into the main buffer */
			if( ( envelopeInfoPtr->auxBuffer = \
					clDynAlloc( "emitPostamble", 
								envelopeInfoPtr->extraDataSize + 64 ) ) == NULL )
				return( CRYPT_ERROR_MEMORY );
			certChainBufSize = envelopeInfoPtr->auxBufSize = \
									envelopeInfoPtr->extraDataSize + 64;
			certChainBufPtr = envelopeInfoPtr->auxBuffer;
			}

		/* Write the end-of-contents octets for the Data OCTET STRING, [0], 
		   and SEQUENCE if necessary */
		if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED )
			{
			status = writeEOCs( envelopeInfoPtr, 3 );
			if( cryptStatusError( status ) )
				return( status );
			}
		envelopeInfoPtr->lastAction = envelopeInfoPtr->postActionList;

		/* Write the signing cert chain if it's a CMS signature and they're 
		   not explicitly excluded, followed by the SET OF SignerInfo 
		   header */
		sMemOpen( &stream, certChainBufPtr, certChainBufSize );
		if( ( envelopeInfoPtr->type == CRYPT_FORMAT_CMS || \
			  envelopeInfoPtr->type == CRYPT_FORMAT_SMIME ) && \
			!( envelopeInfoPtr->flags & ENVELOPE_NOSIGNINGCERTS ) )
			{
			status = exportCertToStream( &stream, 
							( envelopeInfoPtr->iExtraCertChain != CRYPT_ERROR ) ? \
							  envelopeInfoPtr->iExtraCertChain : \
							  envelopeInfoPtr->lastAction->iCryptHandle, 
							CRYPT_ICERTFORMAT_CERTSET );
			if( cryptStatusError( status ) )
				return( status );
			}
		if( envelopeInfoPtr->dataFlags & ENVDATA_HASINDEFTRAILER )
			status = writeSetIndef( &stream );
		else
			status = writeSet( &stream, envelopeInfoPtr->signActionSize );
		certChainSize = stell( &stream );
		sMemDisconnect( &stream );
		if( cryptStatusError( status ) )
			return( status );
		if( envelopeInfoPtr->auxBufSize > 0 )
			{
			envelopeInfoPtr->auxBufPos = certChainSize;
			status = copyFromAuxBuffer( envelopeInfoPtr );
			}
		else
			{
			envelopeInfoPtr->bufPos += certChainSize;

			/* Since we're in the post-data state, any necessary payload 
			   data segmentation has been completed.  However, the caller 
			   can't copy out any post-payload data because it's past the 
			   end-of-segment position.  In order to allow the buffer to be 
			   emptied to make room for signature data, we set the end-of-
			   segment position to the end of the new data */
			envelopeInfoPtr->segmentDataEnd = envelopeInfoPtr->bufPos;
			}
		envelopeInfoPtr->envState = ENVSTATE_SIGNATURE;
		if( cryptStatusError( status ) )
			/* If we're copying from the auxBuffer, we'll get an overflow
			   error at this point and have to resume later in the 
			   signature state */
			return( status );
		}

	/* Handle signing actions */
	assert( envelopeInfoPtr->envState == ENVSTATE_SIGNATURE );

	/* Sign each hash using the associated signature key */
	for( lastActionPtr = envelopeInfoPtr->lastAction;
		 lastActionPtr != NULL; lastActionPtr = lastActionPtr->next )
		{
		const int sigBufSize = min( envelopeInfoPtr->bufSize - \
									envelopeInfoPtr->bufPos, 32767 );
		int sigSize, signingAttributes;

		assert( lastActionPtr->action == ACTION_SIGN );

		/* Check whether there's enough room left in the buffer to emit the 
		   signature directly into it.  Since sigs are fairly small (a
		   few hundred bytes), we always require enough room in the buffer 
		   and don't bother with any overflow handling via the auxBuffer */
		if( lastActionPtr->encodedSize + 64 > sigBufSize )
			{
			status = CRYPT_ERROR_OVERFLOW;
			break;
			}

		/* Determine the type of signing attributes to use.  If none are 
		   specified (which can only happen under circumstances controlled 
		   by the pre-envelope-signing code), either get the signing code to 
		   add the default ones for us, or use none at all if the use of 
		   default attributes is disabled */
		signingAttributes = lastActionPtr->iExtraData;
		if( signingAttributes == CRYPT_ERROR )
			{
			int useDefaultAttributes;

			krnlSendMessage( envelopeInfoPtr->ownerHandle, 
							 IMESSAGE_GETATTRIBUTE, &useDefaultAttributes, 
							 CRYPT_OPTION_CMS_DEFAULTATTRIBUTES );
			signingAttributes = useDefaultAttributes ? CRYPT_USE_DEFAULT : \
													   CRYPT_UNUSED;
			}

		/* Sign the data */
		status = iCryptCreateSignatureEx( envelopeInfoPtr->buffer + \
										  envelopeInfoPtr->bufPos, &sigSize, 
							sigBufSize, envelopeInfoPtr->type, 
							lastActionPtr->iCryptHandle,
							lastActionPtr->associatedAction->iCryptHandle,
							signingAttributes, 
							( lastActionPtr->iTspSession != CRYPT_ERROR ) ? \
							lastActionPtr->iTspSession : CRYPT_UNUSED );
		if( cryptStatusError( status ) )
			break;
		envelopeInfoPtr->bufPos += sigSize;
		}
	envelopeInfoPtr->lastAction = lastActionPtr;
	if( cryptStatusError( status ) )
		return( status );

	/* Write the end-of-contents octets for the OCTET STRING/SEQUENCE, [0], 
	   and SEQUENCE if necessary.  If the trailer has an indefinite length 
	   then we need to add an EOC for the trailer as well */
	if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED || \
		( envelopeInfoPtr->dataFlags & ENVDATA_HASINDEFTRAILER ) )
		{
		status = writeEOCs( envelopeInfoPtr, 
							3 + ( ( envelopeInfoPtr->dataFlags & \
									ENVDATA_HASINDEFTRAILER ) ? \
								  1 : 0 ) );
		if( cryptStatusError( status ) )
			return( status );
		}

	/* Now that we've written the final end-of-contents octets, set the end-
	   of-segment-data pointer to the end of the data in the buffer so that
	   copyFromEnvelope() can copy out the remaining data */
	envelopeInfoPtr->segmentDataEnd = envelopeInfoPtr->bufPos;
	envelopeInfoPtr->envState = ENVSTATE_DONE;

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Envelope Access Routines						*
*																			*
****************************************************************************/

void initCMSEnveloping( ENVELOPE_INFO *envelopeInfoPtr )
	{
	/* Set the access method pointers */
	envelopeInfoPtr->processPreambleFunction = emitPreamble;
	envelopeInfoPtr->processPostambleFunction = emitPostamble;
	envelopeInfoPtr->checkCryptAlgo = checkCryptAlgo;
	envelopeInfoPtr->checkHashAlgo = checkHashAlgo;

	/* Set up the processing state information */
	envelopeInfoPtr->envState = ENVSTATE_NONE;

	/* Remember the current default settings for use with the envelope.  
	   We force the use of the CBC encryption mode because this is the 
	   safest and most efficient encryption mode, and the only mode defined 
	   for many CMS algorithms.  Since the CMS algorithms represent only a 
	   subset of what's available, we have to drop back to fixed values if 
	   the caller has selected something exotic */
	krnlSendMessage( envelopeInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE, 
					 &envelopeInfoPtr->defaultHash, CRYPT_OPTION_ENCR_HASH );
	if( !checkAlgoID( envelopeInfoPtr->defaultHash, CRYPT_MODE_NONE ) )
		envelopeInfoPtr->defaultHash = CRYPT_ALGO_SHA;
	krnlSendMessage( envelopeInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE, 
					 &envelopeInfoPtr->defaultAlgo, CRYPT_OPTION_ENCR_ALGO );
	if( !checkAlgoID( envelopeInfoPtr->defaultAlgo,
					  ( envelopeInfoPtr->defaultAlgo == CRYPT_ALGO_RC4 ) ? \
					  CRYPT_MODE_OFB : CRYPT_MODE_CBC ) )
		envelopeInfoPtr->defaultAlgo = CRYPT_ALGO_3DES;
	krnlSendMessage( envelopeInfoPtr->ownerHandle, IMESSAGE_GETATTRIBUTE, 
					 &envelopeInfoPtr->defaultMAC, CRYPT_OPTION_ENCR_MAC );
	if( !checkAlgoID( envelopeInfoPtr->defaultMAC, CRYPT_MODE_NONE ) )
		envelopeInfoPtr->defaultMAC = CRYPT_ALGO_HMAC_SHA;
	}
#endif /* USE_ENVELOPES */

⌨️ 快捷键说明

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