📄 cryptapi.c
字号:
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 + -