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

📄 octetstr.c

📁 提供了很多种加密算法和CA认证及相关服务如CMP、OCSP等的开发
💻 C
📖 第 1 页 / 共 4 页
字号:
	   the EOC flag is set elsewhere as soon as the entire payload has been
	   copied to the buffer) */
	if( envelopeInfoPtr->endOfContents )
		return( 0 );

	/* If we're using the definite encoding form, there's a single segment
	   equal in length to the entire payload */
	if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
		{
		envelopeInfoPtr->segmentSize = envelopeInfoPtr->payloadSize;
		return( 0 );
		}
	else
		/* If we're using the indefinite form but it's an envelope type which
		   doesn't segment data, the length is implicitly defined as "until
		   we run out of input" */
		if( envelopeInfoPtr->flags & ENVELOPE_NOSEGMENT )
			{
			envelopeInfoPtr->segmentSize = CRYPT_UNUSED;
			return( 0 );
			}

	/* Process each data byte until we've either parsed the entire header or
	   run out of input */
	for( bufPos = 0; bufPos < length && state != SEGHDRSTATE_DONE; bufPos++ )
		{
		SEGHDR_STATE oldState = state;

		switch( state )
			{
			case SEGHDRSTATE_NONE:
				/* Check for OCTET STRING or start or end-of-contents
				   octets */
				if( buffer[ bufPos ] == BER_OCTETSTRING )
					state = SEGHDRSTATE_LEN_OF_LEN;
				if( !buffer[ bufPos ] )
					state = SEGHDRSTATE_END;
				break;

			case SEGHDRSTATE_LEN_OF_LEN:
				/* We've seen the OCTET STRING header, check for the short
				   length or length-of-length */
				count = buffer[ bufPos ];
				if( !( count & 0x80 ) )
					{
					segmentLength = count;
					state = SEGHDRSTATE_DONE;
					}
				else
					{
					/* It's a long segment, get the length-of-length
					   information and reset the first-time flag to make sure
					   we decrypt the length data */
					count &= 0x7F;
					if( count < 1 || count > 4 )
						/* "Nobody will ever need more than 640K" */
						return( CRYPT_ERROR_BADDATA );
					state = SEGHDRSTATE_LEN;
					}
				break;

			case SEGHDRSTATE_LEN:
				/* We're processing a long-format length field, get the next
				   part of the length */
				segmentLength <<= 8;
				segmentLength |= buffer[ bufPos ];
				count--;

				/* If we've got all the data, make sure the segment length is
				   valid and return to the initial state */
				if( !count )
					{
					if( segmentLength < 0x80 )
						return( CRYPT_ERROR_BADDATA );
					state = SEGHDRSTATE_DONE;
					}
				break;

			case SEGHDRSTATE_END:
				/* We've seen the first end-of-contents octet, check for
				   the second one */
				if( !buffer[ bufPos ] )
					{
					int status;

					status = processEOC( envelopeInfoPtr );
					if( cryptStatusError( status ) )
						return( status );
					state = SEGHDRSTATE_DONE;
					}
				break;

			default:
				assert( NOTREACHED );
			}

		/* If the state hasn't changed when it should have, there's a
		   problem */
		if( state == oldState && state != SEGHDRSTATE_LEN )
			return( CRYPT_ERROR_BADDATA );
		}

	/* If we got the final length, update the appropriate segment length
	   value */
	if( state == SEGHDRSTATE_DONE )
		{
		envelopeInfoPtr->segmentSize = segmentLength;
		envelopeInfoPtr->segHdrSegLength = 0L;
		envelopeInfoPtr->segHdrCount = 0;
		envelopeInfoPtr->segHdrState = SEGHDRSTATE_NONE;
		}
	else
		{
		/* Copy the local state information back into the envelope
		   structure */
		envelopeInfoPtr->segHdrSegLength = segmentLength;
		envelopeInfoPtr->segHdrCount = count;
		envelopeInfoPtr->segHdrState = state;
		}

	return( bufPos );
	}

/* Copy possibly encrypted data into the envelope with special handling for
   block encryption modes.  Returns the number of bytes copied */

static int copyData( ENVELOPE_INFO *envelopeInfoPtr, const BYTE *buffer,
					 const int length )
	{
	BYTE *bufPtr = envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos;
	int bytesToCopy;

	/* Figure out how much we can copy across.  First we calculate the
	   minimum of the amount of data passed in and the amount remaining in
	   the current segment.  If it's unknown-length data (which can only
	   happen for compressed data), it ends wherever the caller tells us it 
	   ends and we use it all */
	if( envelopeInfoPtr->segmentSize != CRYPT_UNUSED )
		bytesToCopy = ( int ) min( envelopeInfoPtr->segmentSize, length );
	else
		bytesToCopy = length;

	/* Now we check if this is affected by the total free space remaining in
	   the buffer.  If we're processing data blocks we can have two cases,
	   one in which the limit is the amount of buffer space available and the
	   other in which the limit is the amount of data available.  If the
	   limit is set by the available data, we don't have to worry about
	   flushing extra data out of the block buffer into the main buffer, but
	   if the limit is set by the available buffer space we have to reduce
	   the amount we can copy in based on any extra data which will be
	   flushed out of the block buffer.

	   There are two possible approaches which can be used when the block
	   buffer is involved.  The first one copies as much as we can into the
	   buffer and, if that isn't enough, maxes out the block buffer with as
	   much remaining data as possible.  The second only copies in as much as
	   can fit into the buffer, even if there's room in the block buffer for
	   a few more bytes.  The second approach is preferable because although
	   either will give the impression of a not-quite-full buffer into which
	   no more data can be copied, the second minimizes the amount of data
	   which is moved into and out of the block buffer.

	   The first approach may seem slightly more logical, but will only
	   cause confusion in the long run.  Consider copying (say) 43 bytes to
	   a 43-byte buffer.  The first time this will succeed, after which there
	   will be 40 bytes in the buffer (reported to the caller) and 3 in the
	   block buffer.  If the caller tries to copy in 3 more bytes to "fill"
	   the main buffer, they'll again vanish into the block buffer.  A second
	   call with three more bytes will copy 2 bytes and return with 1
	   uncopied.  In effect this method of using the block buffer extends the
	   blocksize-quantized main buffer by the size of the block buffer, which
	   at a glance seems to make sense but will only cause confusion because
	   data appears to vanish into the buffer */
	bytesToCopy = min( bytesToCopy, \
		( envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos ) - envelopeInfoPtr->blockBufferPos );
	assert( bytesToCopy >= 0 );

	/* If we're given a zero length, return now.  This can happen if all
	   input is consumed in processing the headers (we're passed a zero
	   length) */
	if( bytesToCopy == 0 )
		return( 0 );

	/* If its a block encryption mode we need to provide special handling for
	   odd data lengths which don't match the block size */
	if( envelopeInfoPtr->blockSize > 1 )
		{
		int bytesCopied = 0, quantizedBytesToCopy;

		/* If the new data will fit into the block buffer, copy it in now and
		   return */
		if( envelopeInfoPtr->blockBufferPos + bytesToCopy < \
			envelopeInfoPtr->blockSize )
			{
			memcpy( envelopeInfoPtr->blockBuffer + envelopeInfoPtr->blockBufferPos,
					buffer, bytesToCopy );
			envelopeInfoPtr->blockBufferPos += bytesToCopy;

			/* Adjust the segment size based on what we've consumed */
			envelopeInfoPtr->segmentSize -= bytesToCopy;

			return( bytesToCopy );
			}

		/* If there isn't room in the main buffer for even one more block,
		   exit without doing anything.  This leads to slightly anomalous
		   behaviour where, with no room for a complete block in the main
		   buffer, copying in a data length smaller than the block buffer
		   will lead to the data being absorbed by the block buffer due to
		   the previous section of code, but copying in a length larger than
		   the block buffer will result in no data at all being absorbed,
		   even if there is still room in the block buffer */
		if( envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos < \
			envelopeInfoPtr->blockSize )
			return( 0 );	/* No room for even one more block */

		/* There's room for at least one more block in the buffer.  First,
		   if there are leftover bytes in the block buffer move them into
		   the main buffer */
		if( envelopeInfoPtr->blockBufferPos )
			{
			memcpy( bufPtr, envelopeInfoPtr->blockBuffer,
					envelopeInfoPtr->blockBufferPos );
			bytesCopied = envelopeInfoPtr->blockBufferPos;
			}

		/* Determine how many bytes we can copy into the buffer to fill it
		   to the nearest available block size */
		quantizedBytesToCopy = ( bytesToCopy + bytesCopied ) & \
							   envelopeInfoPtr->blockSizeMask;
		quantizedBytesToCopy -= bytesCopied;
		assert( quantizedBytesToCopy >= 1 );

		/* Now copy across a number of bytes which is a multiple of the block
		   size and decrypt them */
		memcpy( bufPtr + bytesCopied, buffer, quantizedBytesToCopy );
		envelopeInfoPtr->bufPos += bytesCopied + quantizedBytesToCopy;
		envelopeInfoPtr->segmentSize -= bytesToCopy;
		krnlSendMessage( envelopeInfoPtr->iCryptContext,
						 RESOURCE_IMESSAGE_CTX_DECRYPT, bufPtr,
						 bytesCopied + quantizedBytesToCopy );

		/* If the payload has a definite length and we've reached its end,
		   set the EOC flag to make sure we don't go any further */
		if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED && \
			!envelopeInfoPtr->segmentSize )
			{
			int status;

			status = processEOC( envelopeInfoPtr );
			if( cryptStatusError( status ) )
				return( status );
			}
		else
			{
			/* Copy any remainder (the difference between the amount to copy
			   and the blocksize-quantized amount) into the block buffer */
			if( bytesToCopy - quantizedBytesToCopy )
				memcpy( envelopeInfoPtr->blockBuffer, buffer + quantizedBytesToCopy,
						bytesToCopy - quantizedBytesToCopy );
			envelopeInfoPtr->blockBufferPos = bytesToCopy - quantizedBytesToCopy;
			}

		return( bytesToCopy );
		}

	/* It's unencrypted or encrypted with a stream cipher, just copy over as
	   much of the segment as we can and decrypt it if necessary */
	if( bytesToCopy > envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos )
		bytesToCopy = envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos;
	memcpy( envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos, buffer,
			bytesToCopy );
	envelopeInfoPtr->bufPos += bytesToCopy;
	if( envelopeInfoPtr->segmentSize != CRYPT_UNUSED )
		envelopeInfoPtr->segmentSize -= bytesToCopy;
	if( envelopeInfoPtr->iCryptContext != CRYPT_ERROR )
		krnlSendMessage( envelopeInfoPtr->iCryptContext,
						 RESOURCE_IMESSAGE_CTX_DECRYPT, bufPtr, bytesToCopy );

	/* If the payload has a definite length and we've reached its end, set
	   the EOC flag to make sure we don't go any further */
	if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED && \
		!envelopeInfoPtr->segmentSize )
		{
		const int status = processEOC( envelopeInfoPtr );
		if( cryptStatusError( status ) )
			return( status );
		}

	return( bytesToCopy );
	}

/* Copy data into the de-enveloping envelope.  Returns the number of bytes
   copied */

static int copyToDeenvelope( ENVELOPE_INFO *envelopeInfoPtr, 
							 const BYTE *buffer, int length )
	{
	BYTE *bufPtr = ( BYTE * ) buffer;
	int oldLength = length, bytesCopied;

	/* If we're trying to copy into a full buffer, return a count of 0 bytes
	   (the calling routine may convert this to an overflow error if
	   necessary) */
	if( envelopeInfoPtr->bufPos == envelopeInfoPtr->bufSize )
		return( 0 );

	/* If we're verifying a detached signature, just hash the data and exit.
	   We don't have to check for problems with the context at this point
	   since they'll be detected when we try and read the hash value, and we
	   don't have to check whether hashing is active or not since it'll 
	   always be active for detached data, which is hashed and discarded */
	if( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG )
		{
		ACTION_LIST *hashActionPtr;

		assert( envelopeInfoPtr->hashActionsActive );
		for( hashActionPtr = envelopeInfoPtr->actionList;
			 hashActionPtr != NULL; hashActionPtr = hashActionPtr->next )
			krnlSendMessage( hashActionPtr->iCryptHandle,
							 RESOURCE_IMESSAGE_CTX_HASH, ( void * ) buffer,
							 length );
		return( length );
		}

	/* Keep processing data until either we run out of input or we can't copy
	   in any more data.  The code sequence within this loop acts as a simple
	   FSM so that if we exit at any point then the next call to this
	   function will resume where we left off */
	do
		{
		int status;

		/* If there's no segment information currently available, we need to
		   process a segment header before we can handle any data */
		if( !envelopeInfoPtr->segmentSize )

⌨️ 快捷键说明

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