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

📄 cryptapi.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 5 页
字号:
static const COMMAND_HANDLER commandHandlers[] = {
	NULL, NULL, cmdServerQuery, cmdCreateObject, cmdCreateObjectIndirect,
	cmdExportObject, cmdDestroyObject, cmdQueryCapability, cmdGenKey,
	cmdEncrypt, cmdDecrypt, cmdGetAttribute, cmdSetAttribute,
	cmdDeleteAttribute, cmdGetKey, cmdSetKey, cmdDeleteKey, cmdPushData,
	cmdPopData, cmdFlushData, cmdCertSign, cmdCertCheck, cmdCertMgmt };

static void processCommand( BYTE *buffer )
	{
	COMMAND_INFO cmd = { 0 };
	BYTE header[ COMMAND_FIXED_DATA_SIZE ], *bufPtr;
	long totalLength;
	int i, status;

	/* Read the client's message header */
	memcpy( header, buffer, COMMAND_FIXED_DATA_SIZE );

	/* Process the fixed message header and make sure it's valid */
	getMessageType( header, cmd.type, cmd.flags, cmd.noArgs, cmd.noStrArgs );
	totalLength = getMessageLength( header + COMMAND_WORDSIZE );
	if( !checkCommandInfo( &cmd, totalLength ) || \
		cmd.type == COMMAND_RESULT )
		{
		assert( DEBUG_WARN );

		/* Return an invalid result message */
		putMessageType( buffer, COMMAND_RESULT, 0, 0, 0 );
		putMessageLength( buffer + COMMAND_WORDSIZE, 0 );
		return;
		}

	/* Read the rest of the clients message */
	bufPtr = buffer + COMMAND_FIXED_DATA_SIZE;
	for( i = 0; i < cmd.noArgs; i++ )
		{
		cmd.arg[ i ] = getMessageWord( bufPtr );
		bufPtr += COMMAND_WORDSIZE;
		}
	for( i = 0; i < cmd.noStrArgs; i++ )
		{
		cmd.strArgLen[ i ] = getMessageWord( bufPtr );
		cmd.strArg[ i ] = bufPtr + COMMAND_WORDSIZE;
		bufPtr += COMMAND_WORDSIZE + cmd.strArgLen[ i ];
		}
	if( !checkCommandConsistency( &cmd, totalLength ) )
		{
		assert( DEBUG_WARN );

		/* Return an invalid result message */
		putMessageType( buffer, COMMAND_RESULT, 0, 0, 0 );
		putMessageLength( buffer + COMMAND_WORDSIZE, 0 );
		return;
		}

	/* If it's a command that returns a string value, obtain the returned
	   data in the buffer.  Normally we limit the size to the maximum
	   attribute size, however encoded objects and data popped from
	   envelopes/sessions can be larger than this so we use the entire buffer
	   minus a safety margin */
	if( cmd.type == COMMAND_POPDATA || \
		( cmd.flags != COMMAND_FLAG_RET_LENGTH && \
		  ( cmd.type == COMMAND_EXPORTOBJECT || \
			cmd.type == COMMAND_QUERYCAPABILITY || \
			( cmd.type == COMMAND_GETATTRIBUTE && \
			  cmd.noArgs == 3 ) ) ) )
		{
		cmd.noStrArgs = 1;
		cmd.strArg[ 0 ] = bufPtr;
		if( cmd.type == COMMAND_EXPORTOBJECT || cmd.type == COMMAND_POPDATA )
			{
			cmd.strArgLen[ 0 ] = RPC_IO_BUFSIZE - 16 - ( bufPtr - buffer );
			assert( cmd.type != COMMAND_POPDATA || \
					cmd.strArgLen[ 0 ] >= MAX_FRAGMENT_SIZE );
			}
		else
			cmd.strArgLen[ 0 ] = MAX_ATTRIBUTE_SIZE;
		}

	/* Process the command and copy any return information back to the
	   caller */
	status = commandHandlers[ cmd.type ]( NULL, &cmd );
	bufPtr = buffer;
	if( cryptStatusError( status ) )
		{
		/* The push data command is a special case since an error can occur
		   after some data has been processed, so we still need to copy back
		   a result even if we get an error status */
		if( cmd.type == COMMAND_PUSHDATA )
			{
			putMessageType( bufPtr, COMMAND_RESULT, 0, 2, 0 );
			putMessageLength( bufPtr + COMMAND_WORDSIZE, COMMAND_WORDSIZE * 2 );
			putMessageWord( bufPtr + COMMAND_WORD1_OFFSET, status );
			putMessageWord( bufPtr + COMMAND_WORD2_OFFSET, cmd.arg[ 0 ] );
			return;
			}

		/* The command failed, return a simple status value */
		putMessageType( bufPtr, COMMAND_RESULT, 0, 1, 0 );
		putMessageLength( bufPtr + COMMAND_WORDSIZE, COMMAND_WORDSIZE );
		putMessageWord( bufPtr + COMMAND_WORD1_OFFSET, status );
		return;
		}
	if( cmd.type == COMMAND_CREATEOBJECT || \
		cmd.type == COMMAND_CREATEOBJECT_INDIRECT || \
		cmd.type == COMMAND_GETKEY || \
		cmd.type == COMMAND_PUSHDATA || \
		( ( cmd.type == COMMAND_EXPORTOBJECT || \
			cmd.type == COMMAND_QUERYCAPABILITY ) && \
		  cmd.flags == COMMAND_FLAG_RET_LENGTH ) || \
		( cmd.type == COMMAND_GETATTRIBUTE && \
		  ( cmd.noArgs == 2 || cmd.flags == COMMAND_FLAG_RET_LENGTH ) ) || \
		( cmd.type == COMMAND_CERTMGMT && cmd.flags != COMMAND_FLAG_RET_NONE ) )
		{
		/* Return object handle or numeric value or string length */
		putMessageType( bufPtr, COMMAND_RESULT, 0, 2, 0 );
		putMessageLength( bufPtr + COMMAND_WORDSIZE, COMMAND_WORDSIZE * 2 );
		putMessageWord( bufPtr + COMMAND_WORD1_OFFSET, CRYPT_OK );
		putMessageWord( bufPtr + COMMAND_WORD2_OFFSET, cmd.arg[ 0 ] );
		return;
		}
	if( cmd.type == COMMAND_ENCRYPT || \
		cmd.type == COMMAND_DECRYPT || \
		cmd.type == COMMAND_POPDATA || \
		cmd.type == COMMAND_EXPORTOBJECT || \
		cmd.type == COMMAND_QUERYCAPABILITY || \
		cmd.type == COMMAND_GETATTRIBUTE )
		{
		const long dataLength = cmd.strArgLen[ 0 ];

		/* Return capability info or attribute data and length */
		putMessageType( bufPtr, COMMAND_RESULT, 0, 1, 1 );
		putMessageLength( bufPtr + COMMAND_WORDSIZE,
						  ( COMMAND_WORDSIZE * 2 ) + cmd.strArgLen[ 0 ] );
		putMessageWord( bufPtr + COMMAND_WORD1_OFFSET, CRYPT_OK );
		putMessageWord( bufPtr + COMMAND_WORD2_OFFSET, dataLength );
		if( dataLength )
			memmove( bufPtr + COMMAND_WORD3_OFFSET, cmd.strArg[ 0 ],
					 dataLength );
		return;
		}
	putMessageType( bufPtr, COMMAND_RESULT, 0, 1, 0 );
	putMessageLength( bufPtr + COMMAND_WORDSIZE, COMMAND_WORDSIZE );
	putMessageWord( bufPtr + COMMAND_WORD1_OFFSET, CRYPT_OK );
	}

/* Dummy forwarding procedure to take the place of the comms channel between
   client and server */

static void serverTransact( void *clientBuffer )
	{
#ifdef CONFIG_CONSERVE_MEMORY
	static BYTE *serverBuffer = NULL;
#else
	BYTE serverBuffer[ RPC_IO_BUFSIZE ];
#endif /* Memory-starved systems */
	int length;

	/* On memory-starved systems (typically older ones limited to a maximum
	   of 64K of stack) we have to malloc() this on demand.  Since there's
	   no threading this is OK since there won't be any race conditions.
	   Note that there's no way to free this, but it'll be automatically
	   freed when the OS reclaims the application heap */
#ifdef CONFIG_CONSERVE_MEMORY
	if( serverBuffer == NULL && \
		( serverBuffer = clAlloc( "serverTransact", \
								  RPC_IO_BUFSIZE ) ) == NULL )
		{
		memset( clientBuffer, 0, 16 );
		return;
		}
#endif /* Memory-starved systems */

	/* Copy the command to the server buffer, process it, and copy the result
	   back to the client buffer to emulate the client <-> server
	   transmission */
	length = getMessageLength( ( BYTE * ) clientBuffer + COMMAND_WORDSIZE );
	memcpy( serverBuffer, clientBuffer, length + COMMAND_FIXED_DATA_SIZE );
	processCommand( serverBuffer );
	length = getMessageLength( ( BYTE * ) serverBuffer + COMMAND_WORDSIZE );
	memcpy( clientBuffer, serverBuffer, length + COMMAND_FIXED_DATA_SIZE );
	}

/* Dispatch a command to the server */

static int dispatchCommand( COMMAND_INFO *cmd )
	{
	COMMAND_INFO sentCmd = *cmd;
	BYTE buffer[ RPC_IO_BUFSIZE ], *bufPtr = buffer;
	BYTE header[ COMMAND_FIXED_DATA_SIZE ];
	BYTE *payloadStartPtr, *payloadPtr;
	const BOOLEAN isPushPop = \
		( cmd->type == COMMAND_PUSHDATA || cmd->type == COMMAND_POPDATA ) ? \
		TRUE : FALSE;
	const BOOLEAN isDataCommand = \
		( cmd->type == COMMAND_ENCRYPT || cmd->type == COMMAND_DECRYPT || \
		  isPushPop ) ? TRUE : FALSE;
	const long payloadLength = ( cmd->noArgs * COMMAND_WORDSIZE ) + \
							   ( cmd->noStrArgs * COMMAND_WORDSIZE ) + \
							   cmd->strArgLen[ 0 ] + cmd->strArgLen[ 1 ];
	long dataLength = ( cmd->type == COMMAND_POPDATA ) ? \
					  cmd->arg[ 1 ] : cmd->strArgLen[ 0 ], resultLength;
	int i;

	assert( checkCommandInfo( cmd, 0 ) );

	/* Clear the return value */
	memset( cmd, 0, sizeof( COMMAND_INFO ) );

	/* Make sure the data will fit into the buffer */
	if( !isDataCommand && \
		( COMMAND_FIXED_DATA_SIZE + payloadLength ) > RPC_IO_BUFSIZE )
		{
		long maxLength = dataLength;
		int maxPos = 0;

		/* Find the longest arg (the one that contributes most to the
		   problem) and report it as an error.  We report the problem
		   as being with the numeric rather than the string arg since
		   string args with implicit lengths (e.g.text strings) have
		   their length check in the API function, and all other string
		   args are given as (data, length) pairs  */
		for( i = 0; i < sentCmd.noStrArgs; i++ )
			{
			if( sentCmd.strArgLen[ i ] > maxLength )
				{
				maxLength = sentCmd.strArgLen[ i ];
				maxPos = i;
				}
			}
		return( CRYPT_ARGERROR_NUM1 - maxPos );
		}

	/* If it's a short-datasize command, process it and return immediately */
	if( !isDataCommand || ( dataLength < MAX_FRAGMENT_SIZE ) )
		{
		/* Write the header and message fields to the buffer */
		putMessageType( bufPtr, sentCmd.type, sentCmd.flags,
						sentCmd.noArgs, sentCmd.noStrArgs );
		putMessageLength( bufPtr + COMMAND_WORDSIZE, payloadLength );
		bufPtr += COMMAND_FIXED_DATA_SIZE;
		for( i = 0; i < sentCmd.noArgs; i++ )
			{
			putMessageWord( bufPtr, sentCmd.arg[ i ] );
			bufPtr += COMMAND_WORDSIZE;
			}
		for( i = 0; i < sentCmd.noStrArgs; i++ )
			{
			const int argLength = sentCmd.strArgLen[ i ];

			putMessageWord( bufPtr, argLength );
			if( argLength > 0 )
				memcpy( bufPtr + COMMAND_WORDSIZE, sentCmd.strArg[ i ],
						argLength );
			bufPtr += COMMAND_WORDSIZE + argLength;
			}

		/* Send the command to the server and read the servers message header */
		serverTransact( buffer );
		memcpy( header, buffer, COMMAND_FIXED_DATA_SIZE );

		/* Process the fixed message header and make sure that it's valid */
		getMessageType( header, cmd->type, cmd->flags,
						cmd->noArgs, cmd->noStrArgs );
		resultLength = getMessageLength( header + COMMAND_WORDSIZE );
		if( !checkCommandInfo( cmd, resultLength ) || \
			cmd->type != COMMAND_RESULT )
			{
			assert( DEBUG_WARN );
			return( CRYPT_ERROR );
			}

		/* Read the rest of the server's message */
		bufPtr = buffer + COMMAND_FIXED_DATA_SIZE;
		for( i = 0; i < cmd->noArgs; i++ )
			{
			cmd->arg[ i ] = getMessageWord( bufPtr );
			bufPtr += COMMAND_WORDSIZE;
			}
		for( i = 0; i < cmd->noStrArgs; i++ )
			{
			cmd->strArgLen[ i ] = getMessageWord( bufPtr );
			cmd->strArg[ i ] = bufPtr + COMMAND_WORDSIZE;
			bufPtr += COMMAND_WORDSIZE + cmd->strArgLen[ i ];
			}

		/* The first value returned is the status code, if it's nonzero return
		   it to the caller, otherwise move the other values down */
		if( cryptStatusError( cmd->arg[ 0 ] ) )
			{
			/* The push data command is a special case since it returns a
			   bytes copied value even if an error occurs */
			if( sentCmd.type == COMMAND_PUSHDATA )
				{
				const int status = cmd->arg[ 0 ];

				cmd->arg[ 0 ] = cmd->arg[ 1 ];
				cmd->arg[ 1 ] = 0;
				cmd->noArgs--;
				return( status );
				}
			return( cmd->arg[ 0 ] );
			}
		assert( cryptStatusOK( cmd->arg[ 0 ] ) );
		for( i = 1; i < cmd->noArgs; i++ )
			cmd->arg[ i - 1 ] = cmd->arg[ i ];
		cmd->arg[ i ] = 0;
		cmd->noArgs--;

		/* Copy any string arg data back to the caller */
		if( cmd->noStrArgs && cmd->strArgLen[ 0 ] )
			{
			memcpy( sentCmd.strArg[ 0 ], cmd->strArg[ 0 ],
					cmd->strArgLen[ 0 ] );
			cmd->strArg[ 0 ] = sentCmd.strArg[ 0 ];
			if( cmd->type == COMMAND_PUSHDATA )
				{
				/* A data push returns the actual number of copied bytes
				   (which may be less than the requested number of bytes) as
				   arg 0 */
				cmd->arg[ 0 ] = cmd->strArgLen[ 0 ];
				}
			}

		return( CRYPT_OK );
		}

	/* Remember where the variable-length payload starts in the buffer and
	   where it's to be copied to */
	payloadStartPtr = buffer + COMMAND_FIXED_DATA_SIZE + COMMAND_WORDSIZE;
	payloadPtr = sentCmd.strArg[ 0 ];

	/* It's a long-datasize command, handle fragmentation */
	do
		{
		COMMAND_INFO cmdResult = { 0 };
		const int fragmentLength = min( dataLength, MAX_FRAGMENT_SIZE );
		int status;

		/* Write the fixed and variable-length message fields to the buffer */
		putMessageType( buffer, sentCmd.type, 0, sentCmd.noArgs,
						sentCmd.noStrArgs );
		if( sentCmd.type == COMMAND_POPDATA )
			{
			putMessageLength( buffer + COMMAND_WORDSIZE,
							  ( COMMAND_WORDSIZE * 2 ) );
			}
		else
			{
			putMessageLength( buffer + COMMAND_WORDSIZE,
							  ( COMMAND_WORDSIZE * 2 ) + fragmentLength );
			}
		putMessageWord( buffer + COMMAND_FIXED_DATA_SIZE,
						sentCmd.arg[ 0 ] );
		putMessageWord( payloadStartPtr, fragmentLength );
		if( sentCmd.type != COMMAND_POPDATA )
			{
			memcpy( payloadStartPtr + COMMAND_WORDSIZE, payloadPtr,
					fragmentLength );
			}

		/* Process as much data as we can and read the server's message
		   header */
		serverTransact( buffer );
		memcpy( header, buffer, COMMAND_FIXED_DATA_SIZE );

		/* Process the fixed message header and make sure it's valid */
		getMessageType( header, cmdResult.type, cmdResult.flags,
						cmdResult.noArgs, cmdResult.noStrArgs );
		resultLength = getMessageLength( header + COMMAND_WORDSIZE );
		if( !checkCommandInfo( &cmdResult, resultLength ) || \
			cmdResult.type != COMMAND_RESULT || \
			cmdResult.flags != COMMAND_FLAG_NONE )
			{
			assert( DEBUG_WARN );
			return( CRYPT_ERROR );
			}
		if( cmdResult.noArgs != 1 || cmdResult.noStrArgs )
			{
			/* Make sure the parameters are valid for a non-error return */
			if( sentCmd.type == COMMAND_PUSHDATA )
				{
				if( cmdResult.noArgs != 2 || cmdResult.noStrArgs )
					{
					assert( DEBUG_WARN );
					return( CRYPT_ERROR );
					}

⌨️ 快捷键说明

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