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

📄 cms_env.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 4 页
字号:
		envelopeInfoPtr->preActionList == NULL )
		{
		/* Set the block size mask to all ones if we're not encrypting since 
		   we can begin and end data segments on arbitrary boundaries and 
		   inform the caller that we're done */
		if( envelopeInfoPtr->usage != ACTION_CRYPT )
			envelopeInfoPtr->blockSizeMask = -1;
		envelopeInfoPtr->lastAction = NULL;
		return( OK_SPECIAL );
		}

	/* Start emitting the key exchange actions */
	envelopeInfoPtr->lastAction = findAction( envelopeInfoPtr->preActionList,
											  ACTION_KEYEXCHANGE_PKC );
	if( envelopeInfoPtr->lastAction == NULL )
		envelopeInfoPtr->lastAction = findAction( envelopeInfoPtr->preActionList,
												  ACTION_KEYEXCHANGE );
	ENSURES( envelopeInfoPtr->lastAction != NULL );

	return( CRYPT_OK );
	}

/* Write key exchange actions */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int writeKeyex( INOUT ENVELOPE_INFO *envelopeInfoPtr )
	{
	const CRYPT_CONTEXT iCryptContext = \
							( envelopeInfoPtr->usage == ACTION_CRYPT ) ? \
							envelopeInfoPtr->iCryptContext : \
							envelopeInfoPtr->actionList->iCryptHandle;
	ACTION_LIST *actionListPtr;
	int iterationCount, status = CRYPT_OK;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );

	/* Export the session key/MAC using each of the PKC or conventional 
	   keys.  If it's a conventional key exchange we force the use of the 
	   CMS format since there's no reason to use the cryptlib format */
	for( actionListPtr = envelopeInfoPtr->lastAction, iterationCount = 0;
		 actionListPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
		 actionListPtr = actionListPtr->next, iterationCount++ )
		{
		const CRYPT_FORMAT_TYPE formatType = \
						( actionListPtr->action == ACTION_KEYEXCHANGE ) ? \
						CRYPT_FORMAT_CMS : envelopeInfoPtr->type;
		const int dataLeft = min( envelopeInfoPtr->bufSize - \
								  envelopeInfoPtr->bufPos, 
								  MAX_INTLENGTH_SHORT - 1 );
		int keyexSize;

		ENSURES( dataLeft >= 0 && dataLeft < MAX_INTLENGTH_SHORT );

		/* Make sure that there's enough room to emit this key exchange 
		   action */
		if( actionListPtr->encodedSize + 128 > dataLeft )
			{
			status = CRYPT_ERROR_OVERFLOW;
			break;
			}

		/* Emit the key exchange action */
		status = iCryptExportKey( envelopeInfoPtr->buffer + \
								  envelopeInfoPtr->bufPos, dataLeft, 
								  &keyexSize, formatType, iCryptContext,
								  actionListPtr->iCryptHandle );
		if( cryptStatusError( status ) )
			break;
		envelopeInfoPtr->bufPos += keyexSize;
		}
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
	envelopeInfoPtr->lastAction = actionListPtr;
	if( cryptStatusError( status ) )
		return( status );

	/* If it's an indefinite-length header close off the set of key 
	   exchange actions */
	if( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED )
		return( writeEOCs( envelopeInfoPtr, 1 ) );

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Trailer Processing Routines						*
*																			*
****************************************************************************/

/* Write the signing certificate 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 certificate chain into a dynamically-allocated auxiliary buffer 
   if there isn't enough room to emit it into the main buffer  */

CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1 ) ) \
static int writeCertchainTrailer( INOUT ENVELOPE_INFO *envelopeInfoPtr )
	{
	STREAM stream;
	void *certChainBufPtr;
	const int dataLeft = min( envelopeInfoPtr->bufSize - \
							  envelopeInfoPtr->bufPos, 
							  MAX_INTLENGTH_SHORT - 1 );
	const int eocSize = ( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
						( 3 * 2 ) : 0;
	int certChainBufSize, certChainSize = DUMMY_INIT, status;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );

	ENSURES( dataLeft >= 0 && dataLeft < MAX_INTLENGTH_SHORT );

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

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

	/* 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 certificate 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 ) )
			{
			sMemDisconnect( &stream );
			return( status );
			}
		}
	if( envelopeInfoPtr->dataFlags & ENVDATA_HASINDEFTRAILER )
		status = writeSetIndef( &stream );
	else
		status = writeSet( &stream, envelopeInfoPtr->signActionSize );
	if( cryptStatusOK( status ) )
		certChainSize = stell( &stream );
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		return( status );

	/* If we're copying data via the auxBuffer flush as much as we can into 
	   the main buffer.  If we can't copy it all in, resulting in an overflow
	   error, we use the OK_SPECIAL status to tell the caller that although
	   an overflow occurred it was due to the auxBuffer copy and not the
	   certificate chain write and it's OK to move on to the next state */
	if( envelopeInfoPtr->auxBufSize > 0 )
		{
		envelopeInfoPtr->auxBufPos = certChainSize;
		status = copyFromAuxBuffer( envelopeInfoPtr );
		return( ( status == CRYPT_ERROR_OVERFLOW ) ? OK_SPECIAL : status );
		}

	/* 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->bufPos += certChainSize;
	envelopeInfoPtr->segmentDataEnd = envelopeInfoPtr->bufPos;

	return( CRYPT_OK );
	}

/* Write signatures */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int writeSignatures( INOUT ENVELOPE_INFO *envelopeInfoPtr )
	{
	ACTION_LIST *actionListPtr;
	int iterationCount, status = CRYPT_OK;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );

	/* Sign each hash using the associated signature key */
	for( actionListPtr = envelopeInfoPtr->lastAction, iterationCount = 0;
		 actionListPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED; 
		 actionListPtr = actionListPtr->next, iterationCount++ )
		{
		const int sigBufSize = min( envelopeInfoPtr->bufSize - \
									envelopeInfoPtr->bufPos, \
									MAX_INTLENGTH_SHORT - 1 );
		int sigSize, signingAttributes = actionListPtr->iExtraData;

		REQUIRES( actionListPtr->action == ACTION_SIGN );
		ENSURES( sigBufSize >= 0 && sigBufSize < MAX_INTLENGTH_SHORT );

		/* Check whether there's enough room left in the buffer to emit the
		   signature directly into it.  Since signatures 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( actionListPtr->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) we 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 */
		if( signingAttributes == CRYPT_ERROR )
			{
			/* If it's a raw signature there are no signing attributes */
			if( envelopeInfoPtr->type == CRYPT_FORMAT_CRYPTLIB )
				signingAttributes = CRYPT_UNUSED;
			else
				{
				int useDefaultAttributes;

				/* It's a CMS/SMIME signature, use whatever the default is */
				status = krnlSendMessage( envelopeInfoPtr->ownerHandle,
										  IMESSAGE_GETATTRIBUTE, 
										  &useDefaultAttributes,
										  CRYPT_OPTION_CMS_DEFAULTATTRIBUTES );
				if( cryptStatusError( status ) )
					break;
				signingAttributes = useDefaultAttributes ? \
									CRYPT_USE_DEFAULT : CRYPT_UNUSED;
				}
			}

		/* Sign the data */
		REQUIRES( actionListPtr->associatedAction != NULL );
		status = iCryptCreateSignature( envelopeInfoPtr->buffer + \
										envelopeInfoPtr->bufPos, sigBufSize, 
							&sigSize, envelopeInfoPtr->type,
							actionListPtr->iCryptHandle,
							actionListPtr->associatedAction->iCryptHandle,
							signingAttributes,
							( actionListPtr->iTspSession != CRYPT_ERROR ) ? \
							actionListPtr->iTspSession : CRYPT_UNUSED );
		if( cryptStatusError( status ) )
			break;
		envelopeInfoPtr->bufPos += sigSize;
		}
	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
	envelopeInfoPtr->lastAction = actionListPtr;

	return( status );
	}

/* Write MAC value */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int writeMAC( INOUT ENVELOPE_INFO *envelopeInfoPtr )
	{
	STREAM stream;
	MESSAGE_DATA msgData;
	BYTE hash[ CRYPT_MAX_HASHSIZE + 8 ];
	const int eocSize = ( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
						( 3 * 2 ) : 0;
	const int dataLeft = min( envelopeInfoPtr->bufSize - \
							  envelopeInfoPtr->bufPos, 512 );
	int length = DUMMY_INIT, status;

	/* Make sure that there's room for the MAC data in the buffer */
	if( dataLeft < eocSize + sizeofObject( CRYPT_MAX_HASHSIZE ) )
		return( CRYPT_ERROR_OVERFLOW );

	/* 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 );
		}

	/* Get the MAC value and write it to the buffer */
	setMessageData( &msgData, hash, CRYPT_MAX_HASHSIZE );
	status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
							  IMESSAGE_GETATTRIBUTE_S, &msgData,
							  CRYPT_CTXINFO_HASHVALUE );
	if( cryptStatusError( status ) )
		return( status );
	sMemOpen( &stream, envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos, 
			  dataLeft );
	status = writeOctetString( &stream, hash, msgData.length, DEFAULT_TAG );
	if( cryptStatusOK( status ) )
		length = stell( &stream );
	sMemDisconnect( &stream );
	if( cryptStatusError( status ) )
		return( status );
	envelopeInfoPtr->bufPos += length;

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Emit Envelope Preamble/Postamble				*
*																			*
****************************************************************************/

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

CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int emitPreamble( INOUT ENVELOPE_INFO *envelopeInfoPtr )
	{
	int status = CRYPT_OK;

	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );

	REQUIRES( sanityCheck( envelopeInfoPtr ) );

	/* If we've finished processing the header information, don't do
	   anything */
	if( envelopeInfoPtr->envState == ENVSTATE_DONE )
		return( CRYPT_OK );

	/* If we haven't started doing anything yet perform various final
	   initialisations */
	if( envelopeInfoPtr->envState == ENVSTATE_NONE )
		{
		/* If there's no nested content type set default to plain data */
		if( envelopeInfoPtr->contentType == CRYPT_CONTENT_NONE )
			envelopeInfoPtr->contentType = CRYPT_CONTENT_DATA;

		/* If there's an absolute data length set, remember it for when we
		   copy in data */
		if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
			envelopeInfoPtr->segmentSize = envelopeInfoPtr->payloadSize;

		/* Perform any remaining initialisation.  MAC'd data is a special-

⌨️ 快捷键说明

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