/**************************************************************************** * * * cryptlib External API Interface * * Copyright Peter Gutmann 1997-2005 * * * ****************************************************************************/ /* NSA motto: In God we trust... all others we monitor. -- Stanley Miller */ #include "crypt.h" #if defined( INC_ALL ) #include "rpc.h" #else #include "misc/rpc.h" #endif /* Compiler-specific includes */ /* Handlers for the various commands */ static int cmdAsyncOp( void *stateInfo, COMMAND_INFO *cmd ) { int dummy, status; assert( cmd->type == COMMAND_ASYNCOP ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs == 2); assert( cmd->noStrArgs == 0 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) ) return( CRYPT_ERROR_PARAM1 ); /* This command is a kitchen-sink operation used to manage async ops.on contexts. If the arg is zero, it gets the objects status, otherwise it cancels an async operation. First, since we're about to access an internal attribute (which can only be done through an internal message), we have to explicitly make sure the object is externally visible. We do this by reading its algorithm type, which is a context-only attribute which ensures that what'll be reported is the status of whatever it is that could be busy rather than the status of an associated object (e.g.an envelope, which is never busy, in any case we can't use a universal object attribute like a property because these are handled by the kernel and aren't affected by the object state). Since the context attribute read returns an error value if the object is in a non-normal state, we allow some error types through */ status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE, &dummy, CRYPT_CTXINFO_ALGO ); if( status != CRYPT_OK && status != CRYPT_ERROR_TIMEOUT ) return( status ); /* If we're after the object status or it's in the normal status (ie there's nothing to do), return now */ if( !cmd->arg[ 1 ] || status == CRYPT_OK ) return( status ); /* If the object is busy, reset its status to non-busy. If the object is still busy when the message is received, the abort flag will be set, otherwise the message won't have any effect */ return( krnlSendMessage( cmd->arg[ 0 ], IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_OK, CRYPT_IATTRIBUTE_STATUS ) ); } static int cmdCertCheck( void *stateInfo, COMMAND_INFO *cmd ) { assert( cmd->type == COMMAND_CERTCHECK ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs == 2 ); assert( cmd->noStrArgs == 0 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) ) return( CRYPT_ARGERROR_OBJECT ); if( !isHandleRangeValid( cmd->arg[ 1 ] ) && \ ( cmd->arg[ 1 ] != CRYPT_UNUSED ) ) return( CRYPT_ARGERROR_NUM1 ); return( krnlSendMessage( cmd->arg[ 0 ], MESSAGE_CRT_SIGCHECK, NULL, cmd->arg[ 1 ] ) ); } static int cmdCertMgmt( void *stateInfo, COMMAND_INFO *cmd ) { MESSAGE_CERTMGMT_INFO certMgmtInfo; int status; assert( cmd->type == COMMAND_CERTMGMT ); assert( cmd->flags == COMMAND_FLAG_NONE || \ cmd->flags == COMMAND_FLAG_RET_NONE ); assert( cmd->noArgs == 4 ); assert( cmd->noStrArgs == 0 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) ) return( CRYPT_ARGERROR_OBJECT ); if( cmd->arg[ 1 ] < CRYPT_CERTACTION_FIRST_USER || \ cmd->arg[ 1 ] > CRYPT_CERTACTION_LAST_USER ) return( CRYPT_ARGERROR_VALUE ); if( !isHandleRangeValid( cmd->arg[ 2 ] ) && \ !( ( cmd->arg[ 1 ] == CRYPT_CERTACTION_EXPIRE_CERT || \ cmd->arg[ 1 ] == CRYPT_CERTACTION_CLEANUP ) && \ cmd->arg[ 2 ] == CRYPT_UNUSED ) ) return( CRYPT_ARGERROR_NUM1 ); if( !isHandleRangeValid( cmd->arg[ 3 ] ) && \ !( ( cmd->arg[ 1 ] == CRYPT_CERTACTION_ISSUE_CRL || \ cmd->arg[ 1 ] == CRYPT_CERTACTION_EXPIRE_CERT || \ cmd->arg[ 1 ] == CRYPT_CERTACTION_CLEANUP ) && \ cmd->arg[ 3 ] == CRYPT_UNUSED ) ) return( CRYPT_ARGERROR_NUM2 ); setMessageCertMgmtInfo( &certMgmtInfo, cmd->arg[ 2 ], cmd->arg[ 3 ] ); if( cmd->flags == COMMAND_FLAG_RET_NONE ) /* If we aren't interested in the return value, set the crypt handle to CRYPT_UNUSED to indicate that there's no need to return the created cert object */ certMgmtInfo.cryptCert = CRYPT_UNUSED; status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_KEY_CERTMGMT, &certMgmtInfo, cmd->arg[ 1 ] ); if( cryptStatusOK( status ) && cmd->flags != COMMAND_FLAG_RET_NONE ) cmd->arg[ 0 ] = certMgmtInfo.cryptCert; return( status ); } static int cmdCertSign( void *stateInfo, COMMAND_INFO *cmd ) { assert( cmd->type == COMMAND_CERTSIGN ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs == 2 ); assert( cmd->noStrArgs == 0 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) ) return( CRYPT_ARGERROR_OBJECT ); if( !isHandleRangeValid( cmd->arg[ 1 ] ) ) return( CRYPT_ARGERROR_NUM1 ); return( krnlSendMessage( cmd->arg[ 0 ], MESSAGE_CRT_SIGN, NULL, cmd->arg[ 1 ] ) ); } static int cmdCreateObject( void *stateInfo, COMMAND_INFO *cmd ) { MESSAGE_CREATEOBJECT_INFO createInfo; BOOLEAN bindToOwner = FALSE, hasStrArg = FALSE; int owner, status; assert( cmd->type == COMMAND_CREATEOBJECT ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs >= 2 && cmd->noArgs <= 4 ); assert( cmd->noStrArgs >= 0 && cmd->noStrArgs <= 2 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) && \ cmd->arg[ 0 ] != SYSTEM_OBJECT_HANDLE ) return( CRYPT_ARGERROR_OBJECT ); if( cmd->arg[ 1 ] <= OBJECT_TYPE_NONE || \ cmd->arg[ 1 ] >= OBJECT_TYPE_LAST ) return( CRYPT_ERROR_FAILED ); /* Internal error */ switch( cmd->arg[ 1 ] ) { case OBJECT_TYPE_CONTEXT: assert( cmd->noArgs == 3 ); assert( cmd->noStrArgs == 0 ); if( ( cmd->arg[ 2 ] <= CRYPT_ALGO_NONE || \ cmd->arg[ 2 ] >= CRYPT_ALGO_LAST ) && \ cmd->arg[ 2 ] != CRYPT_USE_DEFAULT ) return( CRYPT_ARGERROR_NUM1 ); break; case OBJECT_TYPE_CERTIFICATE: assert( cmd->noArgs == 3 ); assert( cmd->noStrArgs == 0 ); if( cmd->arg[ 2 ] <= CRYPT_CERTTYPE_NONE || \ cmd->arg[ 2 ] >= CRYPT_CERTTYPE_LAST_EXTERNAL ) return( CRYPT_ARGERROR_NUM1 ); break; case OBJECT_TYPE_DEVICE: assert( cmd->noArgs == 3 ); assert( cmd->noStrArgs == 1 ); if( cmd->arg[ 2 ] <= CRYPT_DEVICE_NONE || \ cmd->arg[ 2 ] >= CRYPT_DEVICE_LAST ) return( CRYPT_ARGERROR_NUM1 ); if( cmd->arg[ 2 ] == CRYPT_DEVICE_PKCS11 || \ cmd->arg[ 2 ] == CRYPT_DEVICE_CRYPTOAPI ) { if( cmd->strArgLen[ 0 ] < MIN_NAME_LENGTH || \ cmd->strArgLen[ 0 ] >= MAX_ATTRIBUTE_SIZE ) return( CRYPT_ARGERROR_STR1 ); hasStrArg = TRUE; } break; case OBJECT_TYPE_KEYSET: assert( cmd->noArgs == 4 ); assert( cmd->noStrArgs >= 0 && cmd->noStrArgs <= 1 ); if( cmd->arg[ 2 ] <= CRYPT_KEYSET_NONE || \ cmd->arg[ 2 ] >= CRYPT_KEYSET_LAST ) return( CRYPT_ARGERROR_NUM1 ); if( cmd->strArgLen[ 0 ] < MIN_NAME_LENGTH || \ cmd->strArgLen[ 0 ] >= MAX_ATTRIBUTE_SIZE ) return( CRYPT_ARGERROR_STR1 ); if( cmd->arg[ 3 ] < CRYPT_KEYOPT_NONE || \ cmd->arg[ 3 ] >= CRYPT_KEYOPT_LAST_EXTERNAL ) /* CRYPT_KEYOPT_NONE is a valid setting for this parameter */ return( CRYPT_ARGERROR_NUM2 ); hasStrArg = TRUE; break; case OBJECT_TYPE_ENVELOPE: assert( cmd->noArgs == 3 ); assert( cmd->noStrArgs == 0 ); if( cmd->arg[ 2 ] <= CRYPT_FORMAT_NONE || \ cmd->arg[ 2 ] >= CRYPT_FORMAT_LAST_EXTERNAL ) return( CRYPT_ARGERROR_NUM1 ); break; case OBJECT_TYPE_SESSION: assert( cmd->noArgs == 3 ); assert( cmd->noStrArgs == 0 ); if( cmd->arg[ 2 ] <= CRYPT_SESSION_NONE || \ cmd->arg[ 2 ] >= CRYPT_SESSION_LAST ) return( CRYPT_ARGERROR_NUM1 ); break; case OBJECT_TYPE_USER: assert( cmd->noArgs == 2 ); assert( cmd->noStrArgs == 2 ); if( cmd->strArgLen[ 0 ] < MIN_NAME_LENGTH || \ cmd->strArgLen[ 0 ] >= CRYPT_MAX_TEXTSIZE ) return( CRYPT_ARGERROR_STR1 ); if( cmd->strArgLen[ 1 ] < MIN_NAME_LENGTH || \ cmd->strArgLen[ 1 ] >= CRYPT_MAX_TEXTSIZE ) return( CRYPT_ARGERROR_STR2 ); hasStrArg = TRUE; break; default: assert( NOTREACHED ); } /* If we're creating the object via a device, we should set the new object owner to the device owner */ if( cmd->arg[ 0 ] != SYSTEM_OBJECT_HANDLE ) { bindToOwner = TRUE; owner = cmd->arg[ 0 ]; } /* Create the object via the device. Since we're usually doing this via the system object which is invisible to the user, we have to use an internal message for this one case */ setMessageCreateObjectInfo( &createInfo, cmd->arg[ 2 ] ); if( cmd->noArgs == 4 ) createInfo.arg2 = cmd->arg[ 3 ]; if( hasStrArg ) { createInfo.strArg1 = cmd->strArg[ 0 ]; createInfo.strArgLen1 = cmd->strArgLen[ 0 ]; if( cmd->noStrArgs > 1 ) { createInfo.strArg2 = cmd->strArg[ 1 ]; createInfo.strArgLen2 = cmd->strArgLen[ 1 ]; } } if( cmd->arg[ 0 ] == SYSTEM_OBJECT_HANDLE ) status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT, &createInfo, cmd->arg[ 1 ] ); else status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_DEV_CREATEOBJECT, &createInfo, cmd->arg[ 1 ] ); if( cryptStatusError( status ) ) return( status ); /* If the device used to create the object is bound to a thread, bind the created object to the thread as well. If this fails, we don't return the object to the caller since it would be returned in a potentially unbound state */ if( bindToOwner ) { int ownerID; status = krnlSendMessage( owner, IMESSAGE_GETATTRIBUTE, &ownerID, CRYPT_PROPERTY_OWNER ); if( cryptStatusOK( status ) ) status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE, &ownerID, CRYPT_PROPERTY_OWNER ); if( cryptStatusError( status ) && status != CRYPT_ERROR_NOTINITED ) { krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT ); return( status ); } } /* Make the newly-created object externally visible if necessary. This is only required when we're creating the object via the system handle, which requires an internal message that leaves the object internal */ if( cmd->arg[ 0 ] == SYSTEM_OBJECT_HANDLE ) krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_INTERNAL ); cmd->arg[ 0 ] = createInfo.cryptHandle; return( CRYPT_OK ); } static int cmdCreateObjectIndirect( void *stateInfo, COMMAND_INFO *cmd ) { MESSAGE_CREATEOBJECT_INFO createInfo; int status; assert( cmd->type == COMMAND_CREATEOBJECT_INDIRECT ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs == 2 ); assert( cmd->noStrArgs == 1 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( cmd->arg[ 0 ] != SYSTEM_OBJECT_HANDLE ) return( CRYPT_ERROR_FAILED ); /* Internal error */ if( cmd->arg[ 1 ] != OBJECT_TYPE_CERTIFICATE ) return( CRYPT_ERROR_FAILED ); /* Internal error */ if( cmd->strArgLen[ 0 ] < MIN_CERTSIZE ) return( CRYPT_ARGERROR_STR1 ); /* Create the object via the device. Since we're usually doing this via the system object which is invisible to the user, we have to use an internal message for this one case */ setMessageCreateObjectIndirectInfo( &createInfo, cmd->strArg[ 0 ], cmd->strArgLen[ 0 ], CRYPT_CERTTYPE_NONE ); if( cmd->arg[ 0 ] == SYSTEM_OBJECT_HANDLE ) status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT_INDIRECT, &createInfo, OBJECT_TYPE_CERTIFICATE ); else status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_DEV_CREATEOBJECT_INDIRECT, &createInfo, OBJECT_TYPE_CERTIFICATE ); if( cryptStatusError( status ) ) return( status ); /* Make the newly-created object externally visible */ krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_INTERNAL ); cmd->arg[ 0 ] = createInfo.cryptHandle; return( status ); } static int cmdDecrypt( void *stateInfo, COMMAND_INFO *cmd ) { CRYPT_ALGO_TYPE cryptAlgo; CRYPT_MODE_TYPE cryptMode = CRYPT_MODE_NONE; int status; assert( cmd->type == COMMAND_DECRYPT ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs == 1 ); assert( cmd->noStrArgs == 1 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE, &cryptAlgo, CRYPT_CTXINFO_ALGO ); if( cryptStatusError( status ) ) return( status ); if( cryptAlgo <= CRYPT_ALGO_LAST_CONVENTIONAL ) { status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE, &cryptMode, CRYPT_CTXINFO_MODE ); if( cryptStatusError( status ) ) return( status ); } else if( cryptAlgo <= CRYPT_ALGO_LAST_PKC ) { int blockSize; status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE, &blockSize, CRYPT_CTXINFO_KEYSIZE ); if( cryptStatusOK( status ) && cmd->strArgLen[ 0 ] != blockSize ) status = CRYPT_ARGERROR_NUM1; if( cryptStatusError( status ) ) return( status ); } if( cmd->strArgLen[ 0 ] < 0 ) return( CRYPT_ARGERROR_NUM1 ); if( cryptMode == CRYPT_MODE_ECB || cryptMode == CRYPT_MODE_CBC ) { int blockSize; status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE, &blockSize, CRYPT_CTXINFO_BLOCKSIZE ); if( cryptStatusOK( status ) && cmd->strArgLen[ 0 ] % blockSize ) status = CRYPT_ARGERROR_NUM1; if( cryptStatusError( status ) ) return( status ); } /* Make sure the IV has been set */ if( needsIV( cryptMode ) && !isStreamCipher( cryptAlgo ) ) { MESSAGE_DATA msgData; setMessageData( &msgData, NULL, 0 ); status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_CTXINFO_IV ); if( cryptStatusError( status ) ) return( status ); } status = krnlSendMessage( cmd->arg[ 0 ], ( cryptAlgo >= CRYPT_ALGO_FIRST_HASH ) ? \ MESSAGE_CTX_HASH : MESSAGE_CTX_DECRYPT, cmd->strArgLen[ 0 ] ? cmd->strArg[ 0 ] : "", cmd->strArgLen[ 0 ] ); if( cryptAlgo >= CRYPT_ALGO_FIRST_HASH ) /* There's no data to return since the hashing doesn't change it */ cmd->strArgLen[ 0 ] = 0; return( status ); } static int cmdDeleteAttribute( void *stateInfo, COMMAND_INFO *cmd ) { assert( cmd->type == COMMAND_DELETEATTRIBUTE ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs == 2 ); assert( cmd->noStrArgs == 0 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) && \ cmd->arg[ 0 ] != DEFAULTUSER_OBJECT_HANDLE ) return( CRYPT_ARGERROR_OBJECT ); if( cmd->arg[ 0 ] == DEFAULTUSER_OBJECT_HANDLE ) { if( cmd->arg[ 1 ] <= CRYPT_OPTION_FIRST || \ cmd->arg[ 1 ] >= CRYPT_OPTION_LAST ) return( CRYPT_ARGERROR_NUM1 ); } else if( cmd->arg[ 1 ] <= CRYPT_ATTRIBUTE_NONE || \ cmd->arg[ 1 ] >= CRYPT_ATTRIBUTE_LAST ) return( CRYPT_ARGERROR_NUM1 ); /* Delete the attribute. Since we're usually doing this via the default user object which is invisible to the user, we have to use an internal message for this one case */ if( cmd->arg[ 0 ] == DEFAULTUSER_OBJECT_HANDLE ) return( krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE, IMESSAGE_DELETEATTRIBUTE, NULL, cmd->arg[ 1 ] ) ); return( krnlSendMessage( cmd->arg[ 0 ], MESSAGE_DELETEATTRIBUTE, NULL, cmd->arg[ 1 ] ) ); } static int cmdDeleteKey( void *stateInfo, COMMAND_INFO *cmd ) { MESSAGE_KEYMGMT_INFO deletekeyInfo; int itemType = KEYMGMT_ITEM_PUBLICKEY; assert( cmd->type == COMMAND_DELETEKEY ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs >= 2 && cmd->noArgs <= 3 ); assert( cmd->noStrArgs == 1 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) ) return( CRYPT_ARGERROR_OBJECT ); if( cmd->arg[ 1 ] <= CRYPT_KEYID_NONE || \ cmd->arg[ 1 ] >= CRYPT_KEYID_LAST_EXTERNAL ) return( CRYPT_ARGERROR_NUM1 ); if( cmd->arg[ 2 ] ) { /* It's a special-case object being fetched from a CA store */ if( cmd->arg[ 2 ] == CRYPT_CERTTYPE_REQUEST_CERT ) itemType = KEYMGMT_ITEM_REQUEST; else if( cmd->arg[ 2 ] == CRYPT_CERTTYPE_PKIUSER ) itemType = KEYMGMT_ITEM_PKIUSER; else return( CRYPT_ARGERROR_NUM2 ); } if( cmd->strArgLen[ 0 ] < MIN_NAME_LENGTH || \ cmd->strArgLen[ 0 ] >= MAX_ATTRIBUTE_SIZE ) return( CRYPT_ARGERROR_STR1 ); /* Delete the key from the keyset. Unless the user has explicitly specified a CA item to delete, we set the item type to delete to public-key since private-key keysets will interpret this correctly to mean they should also delete the associated private key */ setMessageKeymgmtInfo( &deletekeyInfo, cmd->arg[ 1 ], cmd->strArg[ 0 ], cmd->strArgLen[ 0 ], NULL, 0, KEYMGMT_FLAG_NONE ); return( krnlSendMessage( cmd->arg[ 0 ], MESSAGE_KEY_DELETEKEY, &deletekeyInfo, itemType ) ); } static int cmdDestroyObject( void *stateInfo, COMMAND_INFO *cmd ) { assert( cmd->type == COMMAND_DESTROYOBJECT ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs == 1 ); assert( cmd->noStrArgs == 0 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) ) return( CRYPT_ARGERROR_OBJECT ); /* Decrement the object's reference count, which may or may not actually destroy it (the kernel marks it as internal so it appears destroyed to the caller) */ return( krnlSendNotifier( cmd->arg[ 0 ], MESSAGE_DECREFCOUNT ) ); } static int cmdEncrypt( void *stateInfo, COMMAND_INFO *cmd ) { CRYPT_ALGO_TYPE cryptAlgo; CRYPT_MODE_TYPE cryptMode = CRYPT_MODE_NONE; int status; assert( cmd->type == COMMAND_ENCRYPT ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs == 1 ); assert( cmd->noStrArgs == 1 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE, &cryptAlgo, CRYPT_CTXINFO_ALGO ); if( cryptStatusError( status ) ) return( status ); if( cryptAlgo <= CRYPT_ALGO_LAST_CONVENTIONAL ) { status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE, &cryptMode, CRYPT_CTXINFO_MODE ); if( cryptStatusError( status ) ) return( status ); } else if( cryptAlgo <= CRYPT_ALGO_LAST_PKC ) { int blockSize; status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE, &blockSize, CRYPT_CTXINFO_KEYSIZE ); if( cryptStatusOK( status ) && cmd->strArgLen[ 0 ] != blockSize ) status = CRYPT_ARGERROR_NUM1; if( cryptStatusError( status ) ) return( status ); } if( cryptAlgo >= CRYPT_ALGO_FIRST_HASH ) { /* For hash and MAC operations a length of zero is valid since this is an indication to wrap up the hash operation */ if( cmd->strArgLen[ 0 ] < 0 ) return( CRYPT_ARGERROR_NUM1 ); } else if( cmd->strArgLen[ 0 ] <= 0 ) return( CRYPT_ARGERROR_NUM1 ); if( cryptMode == CRYPT_MODE_ECB || cryptMode == CRYPT_MODE_CBC ) { int blockSize; status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE, &blockSize, CRYPT_CTXINFO_BLOCKSIZE ); if( cryptStatusOK( status ) && cmd->strArgLen[ 0 ] % blockSize ) status = CRYPT_ARGERROR_NUM1; if( cryptStatusError( status ) ) return( status ); } /* If there's no IV set, generate one ourselves */ if( needsIV( cryptMode ) && !isStreamCipher( cryptAlgo ) ) { MESSAGE_DATA msgData; setMessageData( &msgData, NULL, 0 ); status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_CTXINFO_IV ); if( cryptStatusError( status ) ) { if( status == CRYPT_ERROR_NOTINITED ) krnlSendNotifier( cmd->arg[ 0 ], MESSAGE_CTX_GENIV ); else return( status ); } } status = krnlSendMessage( cmd->arg[ 0 ], ( cryptAlgo >= CRYPT_ALGO_FIRST_HASH ) ? \ MESSAGE_CTX_HASH : MESSAGE_CTX_ENCRYPT, cmd->strArgLen[ 0 ] ? cmd->strArg[ 0 ] : "", cmd->strArgLen[ 0 ] ); if( cryptAlgo >= CRYPT_ALGO_FIRST_HASH ) /* There's no data to return since the hashing doesn't change it */ cmd->strArgLen[ 0 ] = 0; return( status ); } static int cmdExportObject( void *stateInfo, COMMAND_INFO *cmd ) { MESSAGE_DATA msgData; int status; assert( cmd->type == COMMAND_EXPORTOBJECT ); assert( cmd->flags == COMMAND_FLAG_NONE || \ cmd->flags == COMMAND_FLAG_RET_LENGTH ); assert( cmd->noArgs == 2 ); assert( ( cmd->flags == COMMAND_FLAG_NONE && cmd->noStrArgs == 1 ) || \ ( cmd->flags == COMMAND_FLAG_RET_LENGTH && cmd->noStrArgs == 0 ) ); assert( cmd->flags == COMMAND_FLAG_RET_LENGTH || \ cmd->strArg[ 0 ] != NULL ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) ) return( CRYPT_ARGERROR_OBJECT ); if( cmd->arg[ 1 ] <= CRYPT_CERTFORMAT_NONE || \ cmd->arg[ 1 ] >= CRYPT_CERTFORMAT_LAST_EXTERNAL ) /* At the moment the only object that we can export is a cert, so we make sure that the format type is valid for this */ return( CRYPT_ARGERROR_NUM1 ); /* Export the cert */ if( cmd->flags == COMMAND_FLAG_RET_LENGTH ) { setMessageData( &msgData, NULL, 0 ); status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_CRT_EXPORT, &msgData, cmd->arg[ 1 ] ); if( cryptStatusOK( status ) ) cmd->arg[ 0 ] = msgData.length; } else { setMessageData( &msgData, cmd->strArg[ 0 ], cmd->strArgLen[ 0 ] ); status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_CRT_EXPORT, &msgData, cmd->arg[ 1 ] ); if( cryptStatusOK( status ) ) cmd->strArgLen[ 0 ] = msgData.length; } /* If we try and export using a disallowed format (e.g. a CRYPT_CERTFORMAT_CERTCHAIN from a cert request) we'll get an argument value error that we need to convert into something more sensible. The error type to report is somewhat debatable since either the format type or the object can be regarded as being wrong, for example when exporting a cert request as a cert chain the format is wrong but when exporting a data-only object as anything the object is wrong. To handle this, we report an argument value error as a numeric parameter error for cases where the format is incorrect for the object type, and a permission error for cases where the object can't be exported externally */ if( status == CRYPT_ARGERROR_VALUE ) { int type; status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE, &type, CRYPT_CERTINFO_CERTTYPE ); if( cryptStatusError( status ) ) return( CRYPT_ARGERROR_OBJECT ); status = ( type == CRYPT_CERTTYPE_CERTIFICATE || \ type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \ type == CRYPT_CERTTYPE_CERTCHAIN || \ type == CRYPT_CERTTYPE_CERTREQUEST || \ type == CRYPT_CERTTYPE_CRL ) ? \ CRYPT_ARGERROR_NUM1 : CRYPT_ERROR_PERMISSION; } return( status ); } static int cmdFlushData( void *stateInfo, COMMAND_INFO *cmd ) { MESSAGE_DATA msgData; int status; assert( cmd->type == COMMAND_FLUSHDATA ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs == 1 ); assert( cmd->noStrArgs == 0 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) ) return( CRYPT_ARGERROR_OBJECT ); /* Send the flush data command to the object */ setMessageData( &msgData, NULL, 0 ); status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_ENV_PUSHDATA, &msgData, 0 ); return( status ); } static int cmdGenKey( void *stateInfo, COMMAND_INFO *cmd ) { assert( cmd->type == COMMAND_GENKEY ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs >= 1 && cmd->noArgs <= 2 ); assert( cmd->noStrArgs == 0 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) ) return( CRYPT_ARGERROR_OBJECT ); return( krnlSendMessage( cmd->arg[ 0 ], MESSAGE_CTX_GENKEY, NULL, ( cmd->noArgs > 1 ) ? \ ( cmd->arg[ 1 ] ? TRUE : FALSE ) : FALSE ) ); } static int cmdGetAttribute( void *stateInfo, COMMAND_INFO *cmd ) { MESSAGE_DATA msgData; int status; assert( cmd->type == COMMAND_GETATTRIBUTE ); assert( cmd->flags == COMMAND_FLAG_NONE || \ cmd->flags == COMMAND_FLAG_RET_LENGTH ); assert( cmd->noArgs >= 2 && cmd->noArgs <= 3 ); assert( ( cmd->flags == COMMAND_FLAG_NONE && cmd->noStrArgs == 1 ) || \ ( ( cmd->noArgs == 2 || cmd->flags == COMMAND_FLAG_RET_LENGTH ) && \ cmd->noStrArgs == 0 ) ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) && \ cmd->arg[ 0 ] != DEFAULTUSER_OBJECT_HANDLE ) return( CRYPT_ARGERROR_OBJECT ); if( cmd->arg[ 0 ] == DEFAULTUSER_OBJECT_HANDLE ) { if( cmd->arg[ 1 ] <= CRYPT_OPTION_FIRST || \ cmd->arg[ 1 ] >= CRYPT_OPTION_LAST ) return( CRYPT_ARGERROR_NUM1 ); } else if( cmd->arg[ 1 ] <= CRYPT_ATTRIBUTE_NONE || \ cmd->arg[ 1 ] >= CRYPT_ATTRIBUTE_LAST ) return( CRYPT_ARGERROR_NUM1 ); /* Get the attribute data from the object. If it's a config option, we're usually doing this via the default user object which is invisible to the user, so we have to use an internal message for this one case. This is further complicated by the fact that the kernel checks that the destination memory is writeable and either returns an error (for an external message) or throws an exception (for the internal message required to access the user object) if it isn't. Since the external API doesn't allow the specification of the returned data length, it uses a worst-case estimate which may be much larger than the actual buffer size, which the kernel will refuse to write to. To handle this we first read the actual length and then ask for only that much data, which the caller should have made available for the output */ if( cmd->noArgs == 2 ) { if( cmd->arg[ 0 ] == DEFAULTUSER_OBJECT_HANDLE ) return( krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE, &cmd->arg[ 0 ], cmd->arg[ 1 ] ) ); return( krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE, &cmd->arg[ 0 ], cmd->arg[ 1 ] ) ); } setMessageData( &msgData, NULL, 0 ); if( cmd->arg[ 0 ] == DEFAULTUSER_OBJECT_HANDLE ) status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, &msgData, cmd->arg[ 1 ] ); else status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE_S, &msgData, cmd->arg[ 1 ] ); if( cryptStatusError( status ) ) return( status ); if( cmd->flags == COMMAND_FLAG_RET_LENGTH ) { cmd->arg[ 0 ] = msgData.length; return( CRYPT_OK ); } msgData.data = cmd->strArg[ 0 ]; if( cmd->arg[ 0 ] == DEFAULTUSER_OBJECT_HANDLE ) status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, &msgData, cmd->arg[ 1 ] ); else status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE_S, &msgData, cmd->arg[ 1 ] ); if( cryptStatusOK( status ) ) cmd->strArgLen[ 0 ] = msgData.length; return( status ); } static int cmdGetKey( void *stateInfo, COMMAND_INFO *cmd ) { MESSAGE_KEYMGMT_INFO getkeyInfo; int messageType = ( cmd->arg[ 2 ] == CRYPT_KEYID_NONE ) ? \ MESSAGE_KEY_GETNEXTCERT : MESSAGE_KEY_GETKEY; int owner, status; assert( cmd->type == COMMAND_GETKEY ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs == 3 ); assert( cmd->noStrArgs >= 1 && cmd->noStrArgs <= 2 ); UNUSED( stateInfo ); /* Perform basic server-side error checking. Because of keyset queries we have to accept CRYPT_KEYID_NONE as well as obviously valid key ID's. In addition if we find a missing ID we pass the request in as a keyset query (this is matched to an implicit GetFirstCert performed by setting the query attribute, this isn't really possible using the external API) */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) ) return( CRYPT_ARGERROR_OBJECT ); if( cmd->arg[ 1 ] <= KEYMGMT_ITEM_NONE || \ cmd->arg[ 1 ] >= KEYMGMT_ITEM_REVOCATIONINFO ) /* Item can only be a public key, private key, secret key, CA request, or CA PKI user info */ return( CRYPT_ARGERROR_NUM1 ); if( cmd->arg[ 2 ] < CRYPT_KEYID_NONE || \ cmd->arg[ 2 ] >= CRYPT_KEYID_LAST_EXTERNAL ) return( CRYPT_ARGERROR_NUM2 ); if( cmd->arg[ 2 ] == CRYPT_KEYID_NONE ) { if( cmd->arg[ 1 ] != KEYMGMT_ITEM_PUBLICKEY ) /* If we're doing a keyset query, it has to be for a certificate */ return( CRYPT_ARGERROR_NUM1 ); if( cmd->strArgLen[ 0 ] ) return( CRYPT_ARGERROR_NUM1 ); } else if( cmd->strArgLen[ 0 ] < MIN_NAME_LENGTH || \ cmd->strArgLen[ 0 ] >= MAX_ATTRIBUTE_SIZE ) return( CRYPT_ARGERROR_STR1 ); /* Read the key from the keyset */ setMessageKeymgmtInfo( &getkeyInfo, cmd->arg[ 2 ], cmd->strArgLen[ 0 ] ? cmd->strArg[ 0 ] : NULL, cmd->strArgLen[ 0 ], cmd->strArgLen[ 1 ] ? cmd->strArg[ 1 ] : NULL, cmd->strArgLen[ 1 ], KEYMGMT_FLAG_NONE ); status = krnlSendMessage( cmd->arg[ 0 ], messageType, &getkeyInfo, cmd->arg[ 1 ] ); if( cryptStatusError( status ) ) return( status ); /* If the keyset is bound to a thread, bind the key read from it to the thread as well. If this fails, we don't return the imported key to the caller since it would be returned in a potentially unbound state */ status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_GETATTRIBUTE, &owner, CRYPT_PROPERTY_OWNER ); if( cryptStatusOK( status ) ) status = krnlSendMessage( getkeyInfo.cryptHandle, IMESSAGE_SETATTRIBUTE, &owner, CRYPT_PROPERTY_OWNER ); if( cryptStatusError( status ) && status != CRYPT_ERROR_NOTINITED ) { krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT ); return( status ); } cmd->arg[ 0 ] = getkeyInfo.cryptHandle; return( CRYPT_OK ); } static int cmdPopData( void *stateInfo, COMMAND_INFO *cmd ) { MESSAGE_DATA msgData; int status; assert( cmd->type == COMMAND_POPDATA ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs == 2 ); assert( cmd->noStrArgs == 1 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) ) return( CRYPT_ARGERROR_OBJECT ); if( cmd->arg[ 1 ] < 1 ) return( CRYPT_ARGERROR_NUM1 ); /* Get the data from the object. We always copy out the byte count value because it's valid even if an error occurs */ setMessageData( &msgData, cmd->strArg[ 0 ], cmd->arg[ 1 ] ); status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_ENV_POPDATA, &msgData, 0 ); cmd->strArgLen[ 0 ] = msgData.length; return( status ); } static int cmdPushData( void *stateInfo, COMMAND_INFO *cmd ) { MESSAGE_DATA msgData; int status; assert( cmd->type == COMMAND_PUSHDATA ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs == 1 ); assert( cmd->noStrArgs == 1 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) ) return( CRYPT_ARGERROR_OBJECT ); if( cmd->strArgLen[ 0 ] < 0 ) return( CRYPT_ARGERROR_NUM1 ); /* Send the data to the object. We always copy out the byte count value because it's valid even if an error occurs */ setMessageData( &msgData, cmd->strArgLen[ 0 ] ? cmd->strArg[ 0 ] : NULL, cmd->strArgLen[ 0 ] ); status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_ENV_PUSHDATA, &msgData, 0 ); cmd->arg[ 0 ] = msgData.length; return( status ); } static int cmdQueryCapability( void *stateInfo, COMMAND_INFO *cmd ) { CRYPT_QUERY_INFO queryInfo; int status; assert( cmd->type == COMMAND_QUERYCAPABILITY ); assert( cmd->flags == COMMAND_FLAG_NONE || \ cmd->flags == COMMAND_FLAG_RET_LENGTH ); assert( cmd->noArgs == 2 ); assert( ( cmd->flags == COMMAND_FLAG_NONE && cmd->noStrArgs == 1 ) || \ ( cmd->flags == COMMAND_FLAG_RET_LENGTH && cmd->noStrArgs == 0 ) ); assert( cmd->flags == COMMAND_FLAG_RET_LENGTH || \ cmd->strArg[ 0 ] != NULL ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) && \ cmd->arg[ 0 ] != SYSTEM_OBJECT_HANDLE ) return( CRYPT_ARGERROR_OBJECT ); if( cmd->arg[ 1 ] < CRYPT_ALGO_NONE || cmd->arg[ 1 ] >= CRYPT_ALGO_LAST ) return( CRYPT_ARGERROR_NUM1 ); /* Query the device for information on the given algorithm and mode. Since we're usually doing this via the system object which is invisible to the user, we have to use an internal message for this one case */ if( cmd->arg[ 0 ] == SYSTEM_OBJECT_HANDLE ) status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_QUERYCAPABILITY, &queryInfo, cmd->arg[ 1 ] ); else status = krnlSendMessage( cmd->arg[ 0 ], MESSAGE_DEV_QUERYCAPABILITY, &queryInfo, cmd->arg[ 1 ] ); if( cryptStatusOK( status ) ) { /* Return either the length or the full capability into on what the caller has asked for */ if( cmd->flags == COMMAND_FLAG_RET_LENGTH ) cmd->arg[ 0 ] = sizeof( CRYPT_QUERY_INFO ); else { memcpy( cmd->strArg[ 0 ], &queryInfo, sizeof( CRYPT_QUERY_INFO ) ); cmd->strArgLen[ 0 ] = sizeof( CRYPT_QUERY_INFO ); } } return( status ); } #ifdef USE_RPCAPI static int cmdServerQuery( void *stateInfo, COMMAND_INFO *cmd ) { int value; assert( cmd->type == COMMAND_SERVERQUERY ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs == 0 ); assert( cmd->noStrArgs == 0 ); UNUSED( stateInfo ); /* Return information about the server */ krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE, &value, CRYPT_OPTION_INFO_MAJORVERSION ); krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE, &value, CRYPT_OPTION_INFO_MINORVERSION ); return( CRYPT_OK ); } #endif /* USE_RPCAPI */ static int cmdSetAttribute( void *stateInfo, COMMAND_INFO *cmd ) { MESSAGE_DATA msgData; assert( cmd->type == COMMAND_SETATTRIBUTE ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( ( cmd->noArgs == 3 && cmd->noStrArgs == 0 ) || ( cmd->noArgs == 2 && cmd->noStrArgs == 1 ) ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) && \ cmd->arg[ 0 ] != DEFAULTUSER_OBJECT_HANDLE ) return( CRYPT_ARGERROR_OBJECT ); if( cmd->arg[ 0 ] == DEFAULTUSER_OBJECT_HANDLE ) { if( cmd->arg[ 1 ] <= CRYPT_OPTION_FIRST || \ cmd->arg[ 1 ] >= CRYPT_OPTION_LAST ) return( CRYPT_ARGERROR_NUM1 ); } else if( cmd->arg[ 1 ] <= CRYPT_ATTRIBUTE_NONE || \ cmd->arg[ 1 ] >= CRYPT_ATTRIBUTE_LAST ) return( CRYPT_ARGERROR_NUM1 ); if( cmd->noStrArgs == 1 ) { if( cmd->arg[ 1 ] == CRYPT_CTXINFO_KEY_COMPONENTS ) { /* Public key components constitute a special case since the composite structures used are quite large */ if( cmd->strArgLen[ 0 ] != sizeof( CRYPT_PKCINFO_RSA ) && \ cmd->strArgLen[ 0 ] != sizeof( CRYPT_PKCINFO_DLP ) && \ cmd->strArgLen[ 0 ] != sizeof( CRYPT_PKCINFO_ECC ) ) return( CRYPT_ARGERROR_NUM2 ); } else if( cmd->strArgLen[ 0 ] < 1 || \ cmd->strArgLen[ 0 ] >= MAX_ATTRIBUTE_SIZE ) return( CRYPT_ARGERROR_NUM2 ); } /* Send the attribute data to the object, mapping the return code to the correct value if necessary. If it's a config option, we're usually doing this via the default user object which is invisible to the user, so we have to use an internal message for this one case */ if( cmd->noStrArgs == 0 ) { if( cmd->arg[ 0 ] == DEFAULTUSER_OBJECT_HANDLE ) return( krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE, ( void * ) &cmd->arg[ 2 ], cmd->arg[ 1 ] ) ); return( krnlSendMessage( cmd->arg[ 0 ], MESSAGE_SETATTRIBUTE, ( void * ) &cmd->arg[ 2 ], cmd->arg[ 1 ] ) ); } setMessageData( &msgData, cmd->strArg[ 0 ], cmd->strArgLen[ 0 ] ); if( cmd->arg[ 0 ] == DEFAULTUSER_OBJECT_HANDLE ) return( krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE, IMESSAGE_SETATTRIBUTE_S, &msgData, cmd->arg[ 1 ] ) ); return( krnlSendMessage( cmd->arg[ 0 ], MESSAGE_SETATTRIBUTE_S, &msgData, cmd->arg[ 1 ] ) ); } static int cmdSetKey( void *stateInfo, COMMAND_INFO *cmd ) { MESSAGE_KEYMGMT_INFO setkeyInfo; int itemType = ( cmd->noStrArgs == 1 ) ? \ KEYMGMT_ITEM_PRIVATEKEY : KEYMGMT_ITEM_PUBLICKEY; assert( cmd->type == COMMAND_SETKEY ); assert( cmd->flags == COMMAND_FLAG_NONE ); assert( cmd->noArgs >= 2 && cmd->noArgs <= 3 ); assert( cmd->noStrArgs >= 0 && cmd->noStrArgs <= 1 ); UNUSED( stateInfo ); /* Perform basic server-side error checking */ if( !isHandleRangeValid( cmd->arg[ 0 ] ) ) return( CRYPT_ARGERROR_OBJECT ); if( !isHandleRangeValid( cmd->arg[ 1 ] ) ) return( CRYPT_ARGERROR_NUM1 ); if( cmd->noStrArgs == 1 && \ ( cmd->strArgLen[ 0 ] < MIN_NAME_LENGTH || \ cmd->strArgLen[ 0 ] >= MAX_ATTRIBUTE_SIZE ) ) return( CRYPT_ARGERROR_STR1 ); if( cmd->arg[ 2 ] ) { int value; /* It's a cert management item request being added to a CA store, usually this is a request but it may also be PKI user info */ itemType = KEYMGMT_ITEM_REQUEST; if( cryptStatusOK( krnlSendMessage( cmd->arg[ 1 ], MESSAGE_GETATTRIBUTE, &value, CRYPT_CERTINFO_CERTTYPE ) ) && \ value == CRYPT_CERTTYPE_PKIUSER ) itemType = KEYMGMT_ITEM_PKIUSER; } else { int value; /* If we're adding a CRL, add it as revocation information rather than as a generic public-key object */ if( itemType != KEYMGMT_ITEM_PRIVATEKEY && \ cryptStatusOK( krnlSendMessage( cmd->arg[ 1 ], MESSAGE_GETATTRIBUTE, &value, CRYPT_CERTINFO_CERTTYPE ) ) && \ value == CRYPT_CERTTYPE_CRL ) itemType = KEYMGMT_ITEM_REVOCATIONINFO; } /* Add the key */ setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0, ( cmd->noStrArgs == 1 ) ? cmd->strArg[ 0 ] : NULL, cmd->strArgLen[ 0 ], KEYMGMT_FLAG_NONE ); setkeyInfo.cryptHandle = cmd->arg[ 1 ]; return( krnlSendMessage( cmd->arg[ 0 ], MESSAGE_KEY_SETKEY, &setkeyInfo, itemType ) ); } #ifdef USE_RPCAPI /* Process a command from the client and send it to the appropriate handler */ 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, cmdAsyncOp }; 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( NOTREACHED ); /* 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( NOTREACHED ); /* 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 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( NOTREACHED ); 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( NOTREACHED ); 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( NOTREACHED ); return( CRYPT_ERROR ); } } else if( cmdResult.noArgs != 1 || cmdResult.noStrArgs != 1 ) { assert( NOTREACHED ); return( CRYPT_ERROR ); } } /* Process the fixed message header and make sure it's valid */ bufPtr = buffer + COMMAND_FIXED_DATA_SIZE; status = getMessageWord( bufPtr ); if( cryptStatusError( status ) ) { /* 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 long bytesCopied = \ getMessageWord( bufPtr + COMMAND_WORDSIZE ); if( bytesCopied < 0 ) { assert( NOTREACHED ); return( CRYPT_ERROR ); } cmdResult.arg[ 0 ] = cmd->arg[ 0 ] + bytesCopied; cmdResult.noArgs = 1; } *cmd = cmdResult; return( status ); } assert( cryptStatusOK( status ) ); /* Read the rest of the server's message */ resultLength = getMessageWord( bufPtr + COMMAND_WORDSIZE ); if( isPushPop ) { /* It's a variable-length transformation, we have to return a non-negative number of bytes */ if( resultLength <= 0 ) { if( resultLength == 0 ) /* We've run out of data, return to the caller */ break; assert( NOTREACHED ); return( CRYPT_ERROR ); } if( cmd->type == COMMAND_PUSHDATA ) cmd->arg[ 0 ] += resultLength; else cmd->strArgLen[ 0 ] += resultLength; if( sentCmd.type == COMMAND_POPDATA ) { memcpy( payloadPtr, payloadStartPtr + COMMAND_WORDSIZE, resultLength ); /* If we got less than what we asked for, there's nothing more available, exit */ if( resultLength < fragmentLength ) dataLength = resultLength; } } else { /* It's an encrypt/decrypt, the result must be a 1:1 transformation unless it's a hash, in which case nothing is returned */ if( resultLength ) { if( resultLength != fragmentLength ) { assert( NOTREACHED ); return( CRYPT_ERROR ); } memcpy( payloadPtr, payloadStartPtr + COMMAND_WORDSIZE, resultLength ); } else /* If no data was returned, it was a hash, set a pseudo- result length which is the same size as the amount of data fed in */ resultLength = fragmentLength; } /* Move on to the next fragment */ payloadPtr += resultLength; dataLength -= resultLength; } while( dataLength > 0 ); return( CRYPT_OK ); } #endif /* USE_RPCAPI */ /**************************************************************************** * * * Client-side Translation Handling * * * ****************************************************************************/ /* When the cryptlib client is using a different character set, we need to map from the internal to the external character set. The following function checks for attribute values that contain text strings. In addition the functions cryptGetKey(), cryptGetPrivateKey(), cryptAddPrivateKey(), and cryptLogin() use text strings that need to be mapped to the internal character set */ #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) static BOOLEAN needsTranslation( const CRYPT_ATTRIBUTE_TYPE attribute ) { if( attribute < CRYPT_CTXINFO_LAST ) { if( attribute < CRYPT_OPTION_LAST ) { return( ( attribute == CRYPT_ATTRIBUTE_INT_ERRORMESSAGE || \ attribute == CRYPT_OPTION_INFO_DESCRIPTION || \ attribute == CRYPT_OPTION_INFO_COPYRIGHT || \ attribute == CRYPT_OPTION_KEYS_LDAP_OBJECTCLASS || \ attribute == CRYPT_OPTION_KEYS_LDAP_FILTER || \ attribute == CRYPT_OPTION_KEYS_LDAP_CACERTNAME || \ attribute == CRYPT_OPTION_KEYS_LDAP_CERTNAME || \ attribute == CRYPT_OPTION_KEYS_LDAP_CRLNAME || \ attribute == CRYPT_OPTION_KEYS_LDAP_EMAILNAME ) ? \ TRUE : FALSE ); } return( ( attribute == CRYPT_CTXINFO_NAME_ALGO || \ attribute == CRYPT_CTXINFO_NAME_MODE || \ attribute == CRYPT_CTXINFO_KEYING_VALUE || \ attribute == CRYPT_CTXINFO_LABEL ) ? \ TRUE : FALSE ); } if( attribute <= CRYPT_CERTINFO_LAST_NAME ) { if( attribute < CRYPT_CERTINFO_FIRST_NAME ) { return( ( attribute == CRYPT_CERTINFO_DN || \ attribute == CRYPT_CERTINFO_PKIUSER_ID || \ attribute == CRYPT_CERTINFO_PKIUSER_ISSUEPASSWORD || \ attribute == CRYPT_CERTINFO_PKIUSER_REVPASSWORD ) ? \ TRUE : FALSE ); } return( ( attribute == CRYPT_CERTINFO_COUNTRYNAME || \ attribute == CRYPT_CERTINFO_STATEORPROVINCENAME || \ attribute == CRYPT_CERTINFO_LOCALITYNAME || \ attribute == CRYPT_CERTINFO_ORGANIZATIONNAME || \ attribute == CRYPT_CERTINFO_ORGANIZATIONALUNITNAME || \ attribute == CRYPT_CERTINFO_COMMONNAME || \ attribute == CRYPT_CERTINFO_OTHERNAME_TYPEID || \ attribute == CRYPT_CERTINFO_RFC822NAME || \ attribute == CRYPT_CERTINFO_DNSNAME || \ attribute == CRYPT_CERTINFO_EDIPARTYNAME_NAMEASSIGNER || \ attribute == CRYPT_CERTINFO_EDIPARTYNAME_PARTYNAME || \ attribute == CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER ) ? \ TRUE : FALSE ); } if( attribute <= CRYPT_CERTINFO_LAST_EXTENSION ) { return( ( attribute == CRYPT_CERTINFO_SIGG_PROCURE_COUNTRY || \ attribute == CRYPT_CERTINFO_SIGG_PROCURE_TYPEOFSUBSTITUTION || \ attribute == CRYPT_CERTINFO_SIGG_MONETARY_CURRENCY || \ attribute == CRYPT_CERTINFO_SIGG_RESTRICTION || \ attribute == CRYPT_CERTINFO_SUBJECTDIR_TYPE || \ attribute == CRYPT_CERTINFO_CERTPOLICYID || \ attribute == CRYPT_CERTINFO_CERTPOLICY_CPSURI || \ attribute == CRYPT_CERTINFO_CERTPOLICY_ORGANIZATION || \ attribute == CRYPT_CERTINFO_CERTPOLICY_EXPLICITTEXT || \ attribute == CRYPT_CERTINFO_ISSUERDOMAINPOLICY || \ attribute == CRYPT_CERTINFO_SUBJECTDOMAINPOLICY || \ attribute == CRYPT_CERTINFO_SET_MERID || \ attribute == CRYPT_CERTINFO_SET_MERACQUIRERBIN || \ attribute == CRYPT_CERTINFO_SET_MERCHANTLANGUAGE || \ attribute == CRYPT_CERTINFO_SET_MERCHANTNAME || \ attribute == CRYPT_CERTINFO_SET_MERCHANTCITY || \ attribute == CRYPT_CERTINFO_SET_MERCHANTSTATEPROVINCE || \ attribute == CRYPT_CERTINFO_SET_MERCHANTPOSTALCODE || \ attribute == CRYPT_CERTINFO_SET_MERCHANTCOUNTRYNAME || \ attribute == CRYPT_CERTINFO_SET_MERCOUNTRY || \ attribute == CRYPT_CERTINFO_SET_MERAUTHFLAG ) ? \ TRUE : FALSE ); } if( attribute <= CRYPT_CERTINFO_LAST_CMS ) { return( ( attribute == CRYPT_CERTINFO_CMS_SECLABEL_POLICY || \ attribute == CRYPT_CERTINFO_CMS_SECLABEL_PRIVACYMARK || \ attribute == CRYPT_CERTINFO_CMS_SECLABEL_CATTYPE || \ attribute == CRYPT_CERTINFO_CMS_SECLABEL_CATVALUE || \ attribute == CRYPT_CERTINFO_CMS_CONTENTHINT_DESCRIPTION || \ attribute == CRYPT_CERTINFO_CMS_EQVLABEL_POLICY || \ attribute == CRYPT_CERTINFO_CMS_EQVLABEL_PRIVACYMARK || \ attribute == CRYPT_CERTINFO_CMS_EQVLABEL_CATTYPE || \ attribute == CRYPT_CERTINFO_CMS_EQVLABEL_CATVALUE || \ attribute == CRYPT_CERTINFO_CMS_SIGNINGCERT_POLICIES || \ attribute == CRYPT_CERTINFO_CMS_SPCOPUSINFO_NAME || \ attribute == CRYPT_CERTINFO_CMS_SPCOPUSINFO_URL || \ attribute == CRYPT_CERTINFO_CMS_SPCAGENCYURL ) ? \ TRUE : FALSE ); } if( attribute < CRYPT_KEYINFO_LAST ) return( ( attribute == CRYPT_KEYINFO_QUERY || \ attribute == CRYPT_KEYINFO_QUERY_REQUESTS ) ? \ TRUE : FALSE ); if( attribute < CRYPT_DEVINFO_LAST ) { return( ( attribute == CRYPT_DEVINFO_INITIALISE || \ attribute == CRYPT_DEVINFO_AUTHENT_USER || \ attribute == CRYPT_DEVINFO_AUTHENT_SUPERVISOR || \ attribute == CRYPT_DEVINFO_SET_AUTHENT_USER || \ attribute == CRYPT_DEVINFO_SET_AUTHENT_SUPERVISOR || \ attribute == CRYPT_DEVINFO_ZEROISE || \ attribute == CRYPT_DEVINFO_LABEL ) ? \ TRUE : FALSE ); } if( attribute < CRYPT_ENVINFO_LAST ) { return( ( attribute == CRYPT_ENVINFO_PASSWORD || \ attribute == CRYPT_ENVINFO_RECIPIENT || \ attribute == CRYPT_ENVINFO_PRIVATEKEY_LABEL ) ? \ TRUE : FALSE ); } if( attribute < CRYPT_SESSINFO_LAST ) { return( ( attribute == CRYPT_SESSINFO_USERNAME || \ attribute == CRYPT_SESSINFO_PASSWORD || \ attribute == CRYPT_SESSINFO_SERVER_NAME || \ attribute == CRYPT_SESSINFO_CLIENT_NAME ) ? \ TRUE : FALSE ); } return( ( attribute == CRYPT_USERINFO_PASSWORD ) ? TRUE : FALSE ); } #ifdef EBCDIC_CHARS #define nativeStrlen( string ) strlen( string ) #define nativeToCryptlibString( dest, src, length ) \ ebcdicToAscii( dest, src, length ) #define cryptlibToNativeString( dest, src, length ) \ asciiToEbcdic( dest, src, length ) #else #define nativeStrlen( string ) wcslen( string ) #define nativeToCryptlibString( dest, src, length ) \ unicodeToAscii( dest, src, length ) #define cryptlibToNativeString( dest, src, length ) \ asciiToUnicode( dest, src, length ) #endif /* EBCDIC vs. Unicode translation */ #endif /* EBCDIC_CHARS || UNICODE_CHARS */ /**************************************************************************** * * * Utility Functions * * * ****************************************************************************/ /* Some functions take null-terminated strings as parameters, since these can be ASCII or Unicode strings depending on the environment we need to define a situation-specific get-string-length function to handle them */ #ifdef nativeStrlen #define strParamLen nativeStrlen #else #define strParamLen strlen #endif /* System-specific string parameter length functions */ /* Internal parameter errors are reported in terms of the parameter type (eg invalid object, invalid attribute), but externally they're reported in terms of parameter numbers. Before we return error values to the caller, we have to map them from the internal representation to the position they occur in in the function parameter list. The following function takes a list of parameter types and maps the returned parameter type error to a parameter position error */ typedef enum { ARG_D, /* Dummy placeholder */ ARG_O, /* Object */ ARG_V, /* Value (attribute) */ ARG_N, /* Numeric arg */ ARG_S, /* String arg */ ARG_LAST, } ERRORMAP; static int mapError( const ERRORMAP *errorMap, const int status ) { ERRORMAP type; int count = 0, i; /* If it's not an internal parameter error, let it out */ if( !cryptArgError( status ) ) { assert( status <= 0 && status >= CRYPT_ENVELOPE_RESOURCE ); return( status ); } /* Map the parameter error to a position error */ switch( status ) { case CRYPT_ARGERROR_OBJECT: type = ARG_O; break; case CRYPT_ARGERROR_VALUE: type = ARG_V; break; case CRYPT_ARGERROR_NUM1: case CRYPT_ARGERROR_NUM2: type = ARG_N; count = CRYPT_ARGERROR_NUM1 - status; break; case CRYPT_ARGERROR_STR1: case CRYPT_ARGERROR_STR2: type = ARG_S; count = CRYPT_ARGERROR_STR1 - status; break; default: assert( NOTREACHED ); } for( i = 0; errorMap[ i ] != ARG_LAST && \ i < FAILSAFE_ITERATIONS_SMALL; i++ ) { if( errorMap[ i ] == type && !count-- ) return( CRYPT_ERROR_PARAM1 - i ); } if( i >= FAILSAFE_ITERATIONS_SMALL ) retIntError(); assert( NOTREACHED ); return( CRYPT_ERROR ); /* Get rid of compiler warning */ } /**************************************************************************** * * * Create/Destroy Objects * * * ****************************************************************************/ /* A flag to record whether the external API initialisation function has been called. This merely reflects the current state of the cryptInit()/ cryptEnd() calls at the external API level rather than the internal state of the kernel, and is used to try and catch problems with people who don't call cryptInit() */ static BOOLEAN initCalled = FALSE; /* Initialise and shut down cryptlib. These functions are a type of super- create/destroy in that they create/destroy an instantiation of cryptlib. Unlike the other functions in this module, these can't pass control to the kernel because it hasn't been instantiated yet, so they pass the call down to the internal init/shutodwn functions */ C_RET cryptInit( void ) { int status; status = initCryptlib(); if( cryptStatusOK( status ) ) initCalled = TRUE; return( status ); } C_RET cryptEnd( void ) { initCalled = FALSE; return( endCryptlib() ); } /* Create an encryption context */ C_RET cryptCreateContext( C_OUT CRYPT_CONTEXT C_PTR cryptContext, C_IN CRYPT_USER cryptUser, C_IN CRYPT_ALGO_TYPE cryptAlgo ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_CREATEOBJECT, COMMAND_FLAG_NONE, 3, 0, { SYSTEM_OBJECT_HANDLE, OBJECT_TYPE_CONTEXT } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_D, ARG_O, ARG_N, ARG_N, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isWritePtr( cryptContext, sizeof( CRYPT_CONTEXT ) ) ) return( CRYPT_ERROR_PARAM1 ); *cryptContext = CRYPT_ERROR; if( cryptUser != CRYPT_UNUSED && !isHandleRangeValid( cryptUser ) ) return( CRYPT_ERROR_PARAM2 ); if( ( cryptAlgo <= CRYPT_ALGO_NONE || cryptAlgo >= CRYPT_ALGO_LAST ) && \ cryptAlgo != CRYPT_USE_DEFAULT ) return( CRYPT_ERROR_PARAM3 ); /* Make sure that the user has remembered to initialise cryptlib */ if( !initCalled ) return( CRYPT_ERROR_NOTINITED ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( cryptUser != CRYPT_UNUSED ) cmd.arg[ 0 ] = cryptUser; cmd.arg[ 2 ] = cryptAlgo; status = DISPATCH_COMMAND( cmdCreateObject, cmd ); if( cryptStatusOK( status ) ) { *cryptContext = cmd.arg[ 0 ]; return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } /* Create an encryption context via the device */ C_RET cryptDeviceCreateContext( C_IN CRYPT_DEVICE device, C_OUT CRYPT_CONTEXT C_PTR cryptContext, C_IN CRYPT_ALGO_TYPE cryptAlgo ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_CREATEOBJECT, COMMAND_FLAG_NONE, 3, 0, { 0, OBJECT_TYPE_CONTEXT } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_D, ARG_N, ARG_N, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( device ) ) return( CRYPT_ERROR_PARAM1 ); if( !isWritePtr( cryptContext, sizeof( CRYPT_CONTEXT ) ) ) return( CRYPT_ERROR_PARAM2 ); *cryptContext = CRYPT_ERROR; if( ( cryptAlgo <= CRYPT_ALGO_NONE || cryptAlgo >= CRYPT_ALGO_LAST ) && \ cryptAlgo != CRYPT_USE_DEFAULT ) return( CRYPT_ERROR_PARAM3 ); /* Make sure that the user has remembered to initialise cryptlib */ if( !initCalled ) return( CRYPT_ERROR_NOTINITED ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = device; cmd.arg[ 2 ] = cryptAlgo; status = DISPATCH_COMMAND( cmdCreateObject, cmd ); if( cryptStatusOK( status ) ) { *cryptContext = cmd.arg[ 0 ]; return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } /* Create a certificate */ C_RET cryptCreateCert( C_OUT CRYPT_CERTIFICATE C_PTR certificate, C_IN CRYPT_USER cryptUser, C_IN CRYPT_CERTTYPE_TYPE certType ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_CREATEOBJECT, COMMAND_FLAG_NONE, 3, 0, { SYSTEM_OBJECT_HANDLE, OBJECT_TYPE_CERTIFICATE } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_D, ARG_O, ARG_N, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isWritePtr( certificate, sizeof( CRYPT_CERTIFICATE ) ) ) return( CRYPT_ERROR_PARAM1 ); *certificate = CRYPT_ERROR; if( cryptUser != CRYPT_UNUSED && !isHandleRangeValid( cryptUser ) ) return( CRYPT_ERROR_PARAM2 ); if( certType <= CRYPT_CERTTYPE_NONE || \ certType >= CRYPT_CERTTYPE_LAST_EXTERNAL ) return( CRYPT_ERROR_PARAM3 ); /* Make sure that the user has remembered to initialise cryptlib */ if( !initCalled ) return( CRYPT_ERROR_NOTINITED ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( cryptUser != CRYPT_UNUSED ) cmd.arg[ 0 ] = cryptUser; cmd.arg[ 2 ] = certType; status = DISPATCH_COMMAND( cmdCreateObject, cmd ); if( cryptStatusOK( status ) ) { *certificate = cmd.arg[ 0 ]; return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } /* Open a device */ C_RET cryptDeviceOpen( C_OUT CRYPT_DEVICE C_PTR device, C_IN CRYPT_USER cryptUser, C_IN CRYPT_DEVICE_TYPE deviceType, C_IN C_STR name ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_CREATEOBJECT, COMMAND_FLAG_NONE, 3, 1, { SYSTEM_OBJECT_HANDLE, OBJECT_TYPE_DEVICE } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_D, ARG_O, ARG_N, ARG_S, ARG_LAST }; COMMAND_INFO cmd; #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) BYTE nameBuffer[ MAX_ATTRIBUTE_SIZE + 1 ], *namePtr = NULL; #else const char *namePtr = name; #endif /* EBCDIC_CHARS || UNICODE_CHARS */ int status; /* Perform basic error checking */ if( !isReadPtr( device, sizeof( CRYPT_DEVICE ) ) ) return( CRYPT_ERROR_PARAM1 ); *device = CRYPT_ERROR; if( cryptUser != CRYPT_UNUSED && !isHandleRangeValid( cryptUser ) ) return( CRYPT_ERROR_PARAM2 ); if( deviceType <= CRYPT_DEVICE_NONE || deviceType >= CRYPT_DEVICE_LAST ) return( CRYPT_ERROR_PARAM3 ); if( ( deviceType == CRYPT_DEVICE_PKCS11 || \ deviceType == CRYPT_DEVICE_CRYPTOAPI ) && \ ( !isReadPtr( name, 2 ) || strParamLen( name ) < 2 || \ strParamLen( name ) >= MAX_ATTRIBUTE_SIZE ) ) return( CRYPT_ERROR_PARAM4 ); #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) if( name != NULL ) { status = nativeToCryptlibString( nameBuffer, name, nativeStrlen( name ) + 1 ); if( cryptStatusError( status ) ) return( CRYPT_ERROR_PARAM4 ); namePtr = nameBuffer; } #endif /* EBCDIC_CHARS || UNICODE_CHARS */ /* Make sure that the user has remembered to initialise cryptlib */ if( !initCalled ) return( CRYPT_ERROR_NOTINITED ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( cryptUser != CRYPT_UNUSED ) cmd.arg[ 0 ] = cryptUser; cmd.arg[ 2 ] = deviceType; cmd.strArg[ 0 ] = ( void * ) namePtr; if( namePtr != NULL ) cmd.strArgLen[ 0 ] = strlen( namePtr ); status = DISPATCH_COMMAND( cmdCreateObject, cmd ); if( cryptStatusOK( status ) ) { *device = cmd.arg[ 0 ]; return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } /* Create an envelope */ C_RET cryptCreateEnvelope( C_OUT CRYPT_ENVELOPE C_PTR envelope, C_IN CRYPT_USER cryptUser, C_IN CRYPT_FORMAT_TYPE formatType ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_CREATEOBJECT, COMMAND_FLAG_NONE, 3, 0, { SYSTEM_OBJECT_HANDLE, OBJECT_TYPE_ENVELOPE } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_D, ARG_O, ARG_N, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic error checking */ if( !isWritePtr( envelope, sizeof( CRYPT_ENVELOPE ) ) ) return( CRYPT_ERROR_PARAM1 ); *envelope = CRYPT_ERROR; if( cryptUser != CRYPT_UNUSED && !isHandleRangeValid( cryptUser ) ) return( CRYPT_ERROR_PARAM2 ); if( formatType <= CRYPT_FORMAT_NONE || \ formatType >= CRYPT_FORMAT_LAST_EXTERNAL ) return( CRYPT_ERROR_PARAM3 ); /* Make sure that the user has remembered to initialise cryptlib */ if( !initCalled ) return( CRYPT_ERROR_NOTINITED ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( cryptUser != CRYPT_UNUSED ) cmd.arg[ 0 ] = cryptUser; cmd.arg[ 2 ] = formatType; status = DISPATCH_COMMAND( cmdCreateObject, cmd ); if( cryptStatusOK( status ) ) { *envelope = cmd.arg[ 0 ]; return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } /* Open/create a keyset */ C_RET cryptKeysetOpen( C_OUT CRYPT_KEYSET C_PTR keyset, C_IN CRYPT_USER cryptUser, C_IN CRYPT_KEYSET_TYPE keysetType, C_IN C_STR name, C_IN CRYPT_KEYOPT_TYPE options ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_CREATEOBJECT, COMMAND_FLAG_NONE, 4, 1, { SYSTEM_OBJECT_HANDLE, OBJECT_TYPE_KEYSET } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_D, ARG_O, ARG_N, ARG_S, ARG_N, ARG_LAST }; COMMAND_INFO cmd; #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) BYTE nameBuffer[ MAX_ATTRIBUTE_SIZE + 1 ], *namePtr = nameBuffer; #else const char *namePtr = name; #endif /* EBCDIC_CHARS || UNICODE_CHARS */ int status; /* Perform basic error checking */ if( !isReadPtr( keyset, sizeof( CRYPT_KEYSET ) ) ) return( CRYPT_ERROR_PARAM1 ); *keyset = CRYPT_ERROR; if( cryptUser != CRYPT_UNUSED && !isHandleRangeValid( cryptUser ) ) return( CRYPT_ERROR_PARAM2 ); if( keysetType <= CRYPT_KEYSET_NONE || keysetType >= CRYPT_KEYSET_LAST ) return( CRYPT_ERROR_PARAM3 ); if( !isReadPtr( name, 2 ) || strParamLen( name ) < 2 || \ strParamLen( name ) >= MAX_ATTRIBUTE_SIZE ) return( CRYPT_ERROR_PARAM4 ); if( options < CRYPT_KEYOPT_NONE || \ options >= CRYPT_KEYOPT_LAST_EXTERNAL ) /* CRYPT_KEYOPT_NONE is a valid setting for this parameter */ return( CRYPT_ERROR_PARAM4 ); #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) status = nativeToCryptlibString( nameBuffer, name, nativeStrlen( name ) + 1 ); if( cryptStatusError( status ) ) return( CRYPT_ERROR_PARAM4 ); #endif /* EBCDIC_CHARS || UNICODE_CHARS */ /* Make sure that the user has remembered to initialise cryptlib */ if( !initCalled ) return( CRYPT_ERROR_NOTINITED ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( cryptUser != CRYPT_UNUSED ) cmd.arg[ 0 ] = cryptUser; cmd.arg[ 2 ] = keysetType; cmd.arg[ 3 ] = options; cmd.strArg[ 0 ] = ( void * ) namePtr; cmd.strArgLen[ 0 ] = strlen( namePtr ); status = DISPATCH_COMMAND( cmdCreateObject, cmd ); if( cryptStatusOK( status ) ) { *keyset = cmd.arg[ 0 ]; return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } /* Create a session */ C_RET cryptCreateSession( C_OUT CRYPT_SESSION C_PTR session, C_IN CRYPT_USER cryptUser, C_IN CRYPT_SESSION_TYPE sessionType ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_CREATEOBJECT, COMMAND_FLAG_NONE, 3, 0, { SYSTEM_OBJECT_HANDLE, OBJECT_TYPE_SESSION } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_D, ARG_O, ARG_N, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic error checking */ if( !isWritePtr( session, sizeof( CRYPT_SESSION ) ) ) return( CRYPT_ERROR_PARAM1 ); *session = CRYPT_ERROR; if( cryptUser != CRYPT_UNUSED && !isHandleRangeValid( cryptUser ) ) return( CRYPT_ERROR_PARAM2 ); if( sessionType <= CRYPT_SESSION_NONE || \ sessionType >= CRYPT_SESSION_LAST ) return( CRYPT_ERROR_PARAM3 ); /* Make sure that the user has remembered to initialise cryptlib */ if( !initCalled ) return( CRYPT_ERROR_NOTINITED ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( cryptUser != CRYPT_UNUSED ) cmd.arg[ 0 ] = cryptUser; cmd.arg[ 2 ] = sessionType; status = DISPATCH_COMMAND( cmdCreateObject, cmd ); if( cryptStatusOK( status ) ) { *session = cmd.arg[ 0 ]; return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } /* Log on/create a user object */ C_RET cryptLogin( C_OUT CRYPT_USER C_PTR user, C_IN C_STR name, C_IN C_STR password ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_CREATEOBJECT, COMMAND_FLAG_NONE, 2, 2, { SYSTEM_OBJECT_HANDLE, OBJECT_TYPE_USER } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_D, ARG_S, ARG_S, ARG_LAST }; COMMAND_INFO cmd; #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) BYTE nameBuffer[ CRYPT_MAX_TEXTSIZE + 1 ], *namePtr = nameBuffer; BYTE passwordBuffer[ CRYPT_MAX_TEXTSIZE + 1 ], *passwordPtr = passwordBuffer; #else const char *namePtr = name, *passwordPtr = password; #endif /* EBCDIC_CHARS || UNICODE_CHARS */ int status; /* Perform basic error checking */ if( !isReadPtr( user, sizeof( CRYPT_USER ) ) ) return( CRYPT_ERROR_PARAM1 ); *user = CRYPT_ERROR; if( !isReadPtr( name, MIN_NAME_LENGTH ) || \ strParamLen( name ) < MIN_NAME_LENGTH || \ strParamLen( name ) >= CRYPT_MAX_TEXTSIZE ) return( CRYPT_ERROR_PARAM2 ); if( !isReadPtr( password, MIN_NAME_LENGTH ) || \ strParamLen( password ) < MIN_NAME_LENGTH || \ strParamLen( password ) >= CRYPT_MAX_TEXTSIZE ) return( CRYPT_ERROR_PARAM3 ); #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) status = nativeToCryptlibString( nameBuffer, name, nativeStrlen( name ) + 1 ); if( cryptStatusError( status ) ) return( CRYPT_ERROR_PARAM2 ); status = nativeToCryptlibString( passwordBuffer, password, nativeStrlen( password ) + 1 ); if( cryptStatusError( status ) ) return( CRYPT_ERROR_PARAM3 ); #endif /* EBCDIC_CHARS || UNICODE_CHARS */ /* Make sure that the user has remembered to initialise cryptlib */ if( !initCalled ) return( CRYPT_ERROR_NOTINITED ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.strArg[ 0 ] = ( void * ) namePtr; cmd.strArgLen[ 0 ] = strlen( namePtr ); cmd.strArg[ 1 ] = ( void * ) passwordPtr; cmd.strArgLen[ 1 ] = strlen( passwordPtr ); status = DISPATCH_COMMAND( cmdCreateObject, cmd ); if( cryptStatusOK( status ) ) { *user = cmd.arg[ 0 ]; return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } /* Destroy object functions */ C_RET cryptDestroyObject( C_IN CRYPT_HANDLE cryptHandle ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_DESTROYOBJECT, COMMAND_FLAG_NONE, 1, 0 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( cryptHandle ) ) return( CRYPT_ERROR_PARAM1 ); /* Make sure that the user has remembered to initialise cryptlib */ if( !initCalled ) return( CRYPT_ERROR_NOTINITED ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = cryptHandle; status = DISPATCH_COMMAND( cmdDestroyObject, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } C_RET cryptDestroyCert( C_IN CRYPT_CERTIFICATE certificate ) { return( cryptDestroyObject( certificate ) ); } C_RET cryptDestroyContext( C_IN CRYPT_CONTEXT cryptContext ) { return( cryptDestroyObject( cryptContext ) ); } C_RET cryptDestroyEnvelope( C_IN CRYPT_ENVELOPE cryptEnvelope ) { return( cryptDestroyObject( cryptEnvelope ) ); } C_RET cryptDeviceClose( C_IN CRYPT_DEVICE device ) { return( cryptDestroyObject( device ) ); } C_RET cryptKeysetClose( C_IN CRYPT_KEYSET keyset ) { return( cryptDestroyObject( keyset ) ); } C_RET cryptDestroySession( C_IN CRYPT_SESSION session ) { return( cryptDestroyObject( session ) ); } C_RET cryptLogout( C_IN CRYPT_USER user ) { return( cryptDestroyObject( user ) ); } /**************************************************************************** * * * Attribute Manipulation Functions * * * ****************************************************************************/ /* Get an attribute */ C_RET cryptGetAttribute( C_IN CRYPT_HANDLE cryptHandle, C_IN CRYPT_ATTRIBUTE_TYPE attributeType, C_OUT int C_PTR value ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_GETATTRIBUTE, COMMAND_FLAG_NONE, 2, 0, { DEFAULTUSER_OBJECT_HANDLE } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_V, ARG_S, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( cryptHandle ) && cryptHandle != CRYPT_UNUSED ) return( CRYPT_ERROR_PARAM1 ); if( attributeType <= CRYPT_ATTRIBUTE_NONE || attributeType >= CRYPT_ATTRIBUTE_LAST ) return( CRYPT_ERROR_PARAM2 ); if( !isWritePtr( value, sizeof( int ) ) ) return( CRYPT_ERROR_PARAM3 ); *value = CRYPT_ERROR; /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( cryptHandle != CRYPT_UNUSED ) cmd.arg[ 0 ] = cryptHandle; cmd.arg[ 1 ] = attributeType; status = DISPATCH_COMMAND( cmdGetAttribute, cmd ); if( cryptStatusOK( status ) ) { *value = cmd.arg[ 0 ]; return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } C_RET cryptGetAttributeString( C_IN CRYPT_HANDLE cryptHandle, C_IN CRYPT_ATTRIBUTE_TYPE attributeType, C_OUT void C_PTR value, C_OUT int C_PTR valueLength ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_GETATTRIBUTE, COMMAND_FLAG_NONE, 3, RETURN_VALUE( 1 ), { DEFAULTUSER_OBJECT_HANDLE, 0, TRUE } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_V, ARG_S, ARG_N, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( cryptHandle ) && cryptHandle != CRYPT_UNUSED ) return( CRYPT_ERROR_PARAM1 ); if( attributeType <= CRYPT_ATTRIBUTE_NONE || attributeType >= CRYPT_ATTRIBUTE_LAST ) return( CRYPT_ERROR_PARAM2 ); if( !isWritePtr( valueLength, sizeof( int ) ) ) return( CRYPT_ERROR_PARAM4 ); *valueLength = CRYPT_ERROR; if( value != NULL ) *( ( BYTE * ) value ) = '\0'; /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( value == NULL ) { cmd.flags = COMMAND_FLAG_RET_LENGTH; cmd.noStrArgs = 0; } if( cryptHandle != CRYPT_UNUSED ) cmd.arg[ 0 ] = cryptHandle; cmd.arg[ 1 ] = attributeType; /* arg[ 2 ] = TRUE from template */ cmd.strArg[ 0 ] = value; cmd.strArgLen[ 0 ] = RETURN_VALUE( MAX_ATTRIBUTE_SIZE ); status = DISPATCH_COMMAND( cmdGetAttribute, cmd ); if( cryptStatusOK( status ) ) { *valueLength = ( value == NULL ) ? cmd.arg[ 0 ] : cmd.strArgLen[ 0 ]; #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) if( value != NULL && *valueLength > 0 && \ needsTranslation( attributeType ) ) { BYTE buffer[ MAX_ATTRIBUTE_SIZE ]; if( *valueLength >= MAX_ATTRIBUTE_SIZE ) return( CRYPT_ERROR_OVERFLOW ); memcpy( buffer, value, *valueLength ); cryptlibToNativeString( value, buffer, *valueLength ); #ifdef UNICODE_CHARS *valueLength *= sizeof( wchar_t ); #endif /* UNICODE_CHARS */ } #endif /* EBCDIC_CHARS || UNICODE_CHARS */ return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } /* Set an attribute */ C_RET cryptSetAttribute( C_IN CRYPT_HANDLE cryptHandle, C_IN CRYPT_ATTRIBUTE_TYPE attributeType, C_IN int value ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_SETATTRIBUTE, COMMAND_FLAG_NONE, 3, 0, { DEFAULTUSER_OBJECT_HANDLE } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_V, ARG_N, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( cryptHandle ) && cryptHandle != CRYPT_UNUSED ) return( CRYPT_ERROR_PARAM1 ); if( attributeType <= CRYPT_ATTRIBUTE_NONE || attributeType >= CRYPT_ATTRIBUTE_LAST ) return( CRYPT_ERROR_PARAM2 ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( cryptHandle != CRYPT_UNUSED ) cmd.arg[ 0 ] = cryptHandle; cmd.arg[ 1 ] = attributeType; cmd.arg[ 2 ] = value; status = DISPATCH_COMMAND( cmdSetAttribute, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } C_RET cryptSetAttributeString( C_IN CRYPT_HANDLE cryptHandle, C_IN CRYPT_ATTRIBUTE_TYPE attributeType, C_IN void C_PTR value, C_IN int valueLength ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_SETATTRIBUTE, COMMAND_FLAG_NONE, 2, 1, { DEFAULTUSER_OBJECT_HANDLE } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_V, ARG_S, ARG_N, ARG_LAST }; COMMAND_INFO cmd; #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) BYTE valueBuffer[ MAX_ATTRIBUTE_SIZE ]; #endif /* EBCDIC_CHARS || UNICODE_CHARS */ int length = valueLength, status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( cryptHandle ) && cryptHandle != CRYPT_UNUSED ) return( CRYPT_ERROR_PARAM1 ); if( attributeType <= CRYPT_ATTRIBUTE_NONE || attributeType >= CRYPT_ATTRIBUTE_LAST ) return( CRYPT_ERROR_PARAM2 ); if( !isReadPtr( value, 1 ) ) return( CRYPT_ERROR_PARAM3 ); if( attributeType == CRYPT_CTXINFO_KEY_COMPONENTS ) { /* Public key components constitute a special case since the composite structures used are quite large */ if( valueLength != sizeof( CRYPT_PKCINFO_RSA ) && \ valueLength != sizeof( CRYPT_PKCINFO_DLP ) && \ valueLength != sizeof( CRYPT_PKCINFO_ECC ) ) return( CRYPT_ERROR_PARAM4 ); } else if( valueLength < 1 || valueLength > MAX_ATTRIBUTE_SIZE ) return( CRYPT_ERROR_PARAM4 ); if( !isReadPtr( value, valueLength ) ) return( CRYPT_ERROR_PARAM3 ); #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) if( needsTranslation( attributeType ) ) { status = nativeToCryptlibString( valueBuffer, value, valueLength ); if( cryptStatusError( status ) ) return( CRYPT_ERROR_PARAM3 ); value = valueBuffer; #ifdef UNICODE_CHARS length = status; #endif /* UNICODE_CHARS */ } #endif /* EBCDIC_CHARS || UNICODE_CHARS */ /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( cryptHandle != CRYPT_UNUSED ) cmd.arg[ 0 ] = cryptHandle; cmd.arg[ 1 ] = attributeType; cmd.strArg[ 0 ] = ( void * ) value; cmd.strArgLen[ 0 ] = length; status = DISPATCH_COMMAND( cmdSetAttribute, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } /* Delete an attribute */ C_RET cryptDeleteAttribute( C_IN CRYPT_HANDLE cryptHandle, C_IN CRYPT_ATTRIBUTE_TYPE attributeType ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_DELETEATTRIBUTE, COMMAND_FLAG_NONE, 2, 0, { DEFAULTUSER_OBJECT_HANDLE } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_V, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( cryptHandle ) && cryptHandle != CRYPT_UNUSED ) return( CRYPT_ERROR_PARAM1 ); if( attributeType <= CRYPT_ATTRIBUTE_NONE || attributeType >= CRYPT_ATTRIBUTE_LAST ) return( CRYPT_ERROR_PARAM2 ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( cryptHandle != CRYPT_UNUSED ) cmd.arg[ 0 ] = cryptHandle; cmd.arg[ 1 ] = attributeType; status = DISPATCH_COMMAND( cmdDeleteAttribute, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } /**************************************************************************** * * * Encryption Functions * * * ****************************************************************************/ /* Generate a key into an encryption context */ C_RET cryptGenerateKey( C_IN CRYPT_CONTEXT cryptContext ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_GENKEY, COMMAND_FLAG_NONE, 1, 0 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( cryptContext ) ) return( CRYPT_ERROR_PARAM1 ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = cryptContext; status = DISPATCH_COMMAND( cmdGenKey, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } /* Asynchronous key generate operations */ C_RET cryptGenerateKeyAsync( C_IN CRYPT_CONTEXT cryptContext ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_GENKEY, COMMAND_FLAG_NONE, 2, 0, { 0, TRUE } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( cryptContext ) ) return( CRYPT_ERROR_PARAM1 ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = cryptContext; status = DISPATCH_COMMAND( cmdGenKey, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } /* Query the status of an asynchronous operation. This has more or less the same effect as calling any other operation (both will return CRYPT_ERROR_TIMEOUT if the context is busy), but this is a pure query function with no other side effects */ C_RET cryptAsyncQuery( C_IN CRYPT_CONTEXT cryptContext ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_ASYNCOP, COMMAND_FLAG_NONE, 2, 0, { 0, FALSE } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( cryptContext ) ) return( CRYPT_ERROR_PARAM1 ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = cryptContext; status = DISPATCH_COMMAND( cmdAsyncOp, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } /* Cancel an asynchronous operation on a context */ C_RET cryptAsyncCancel( C_IN CRYPT_CONTEXT cryptContext ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_ASYNCOP, COMMAND_FLAG_NONE, 2, 0, { 0, TRUE } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( cryptContext ) ) return( CRYPT_ERROR_PARAM1 ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = cryptContext; status = DISPATCH_COMMAND( cmdAsyncOp, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } /* Encrypt/decrypt data */ C_RET cryptEncrypt( C_IN CRYPT_CONTEXT cryptContext, C_INOUT void C_PTR buffer, C_IN int length ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_ENCRYPT, COMMAND_FLAG_NONE, 1, 1 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_S, ARG_N, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking. In theory we should also check for writeability since the encryption does an in-place update, however when we're hashing data it's valid for the data to be read- only so we only check for readability. In addition when hashing we could be doing a hash-wrapup call so we allow a zero length and only check the buffer if the length is nonzero */ if( !isHandleRangeValid( cryptContext ) ) return( CRYPT_ERROR_PARAM1 ); if( length < 0 ) return( CRYPT_ERROR_PARAM3 ); if( length > 0 && !isReadPtr( buffer, length ) ) return( CRYPT_ERROR_PARAM2 ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = cryptContext; cmd.strArg[ 0 ] = ( length == 0 ) ? "" : buffer; cmd.strArgLen[ 0 ] = length; status = DISPATCH_COMMAND( cmdEncrypt, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } C_RET cryptDecrypt( C_IN CRYPT_CONTEXT cryptContext, C_INOUT void C_PTR buffer, C_IN int length ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_DECRYPT, COMMAND_FLAG_NONE, 1, 1 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_S, ARG_N, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( cryptContext ) ) return( CRYPT_ERROR_PARAM1 ); if( length < 0 ) return( CRYPT_ERROR_PARAM3 ); if( !isWritePtr( buffer, length ) ) return( CRYPT_ERROR_PARAM2 ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = cryptContext; cmd.strArg[ 0 ] = buffer; cmd.strArgLen[ 0 ] = length; status = DISPATCH_COMMAND( cmdDecrypt, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } /**************************************************************************** * * * Certificate Functions * * * ****************************************************************************/ /* Sign/sig.check a certificate object. The possibilities for signing are as follows: Signer Type | Cert Chain ------+--------------------+--------------- Cert | Cert | Cert | | Chain | Chain, length = 2 | Chain, length = n+1 For sig.checking the cert object is checked against an issuing key/ certificate or against a CRL, either as a raw CRL or a keyset contain revocation information */ C_RET cryptSignCert( C_IN CRYPT_CERTIFICATE certificate, C_IN CRYPT_CONTEXT signContext ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_CERTSIGN, COMMAND_FLAG_NONE, 2, 0 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_V, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( certificate ) ) return( CRYPT_ERROR_PARAM1 ); if( !isHandleRangeValid( signContext ) ) return( CRYPT_ERROR_PARAM2 ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = certificate; cmd.arg[ 1 ] = signContext; status = DISPATCH_COMMAND( cmdCertSign, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } C_RET cryptCheckCert( C_IN CRYPT_HANDLE certificate, C_IN CRYPT_HANDLE sigCheckKey ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_CERTCHECK, COMMAND_FLAG_NONE, 2, 0 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_V, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( certificate ) ) return( CRYPT_ERROR_PARAM1 ); if( !isHandleRangeValid( sigCheckKey ) && ( sigCheckKey != CRYPT_UNUSED ) ) return( CRYPT_ERROR_PARAM2 ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = certificate; cmd.arg[ 1 ] = sigCheckKey; status = DISPATCH_COMMAND( cmdCertCheck, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } /* Import/export a certificate, CRL, certification request, or cert chain. In the export case this just copies the internal encoded object to an external buffer. For cert/cert chain export the possibilities are as follows: Export Type | Cert Chain ------+--------------------+--------------- Cert | Cert | Cert as chain | | Chain | Currently selected | Chain | cert in chain | */ C_RET cryptImportCert( C_IN void C_PTR certObject, C_IN int certObjectLength, C_IN CRYPT_USER cryptUser, C_OUT CRYPT_CERTIFICATE C_PTR certificate ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_CREATEOBJECT_INDIRECT, COMMAND_FLAG_NONE, 2, 1, { SYSTEM_OBJECT_HANDLE, OBJECT_TYPE_CERTIFICATE } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_S, ARG_N, ARG_N, ARG_O, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( certObjectLength < MIN_CERTSIZE ) return( CRYPT_ERROR_PARAM2 ); if( !isReadPtr( certObject, certObjectLength ) ) return( CRYPT_ERROR_PARAM1 ); if( cryptUser != CRYPT_UNUSED && !isHandleRangeValid( cryptUser ) ) return( CRYPT_ERROR_PARAM3 ); if( !isWritePtr( certificate, sizeof( CRYPT_CERTIFICATE ) ) ) return( CRYPT_ERROR_PARAM4 ); *certificate = CRYPT_ERROR; /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( cryptUser != CRYPT_UNUSED ) cmd.arg[ 0 ] = cryptUser; cmd.strArg[ 0 ] = ( void * ) certObject; cmd.strArgLen[ 0 ] = certObjectLength; status = DISPATCH_COMMAND( cmdCreateObjectIndirect, cmd ); if( cryptStatusOK( status ) ) { *certificate = cmd.arg[ 0 ]; return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } C_RET cryptExportCert( C_OUT void C_PTR certObject, C_IN int certObjectMaxLength, C_OUT int C_PTR certObjectLength, C_IN CRYPT_CERTFORMAT_TYPE certFormatType, C_IN CRYPT_HANDLE certificate ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_EXPORTOBJECT, COMMAND_FLAG_NONE, 2, RETURN_VALUE( 1 ) }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_S, ARG_D, ARG_N, ARG_V, ARG_O, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( certObject != NULL ) { if( certObjectMaxLength < MIN_CERTSIZE ) return( CRYPT_ERROR_PARAM2 ); if( !isWritePtr( certObject, certObjectMaxLength ) ) return( CRYPT_ERROR_PARAM1 ); memset( certObject, 0, MIN_CERTSIZE ); } if( !isWritePtr( certObjectLength, sizeof( int ) ) ) return( CRYPT_ERROR_PARAM3 ); *certObjectLength = CRYPT_ERROR; if( certFormatType <= CRYPT_CERTFORMAT_NONE || \ certFormatType >= CRYPT_CERTFORMAT_LAST_EXTERNAL ) return( CRYPT_ERROR_PARAM4 ); if( !isHandleRangeValid( certificate ) ) return( CRYPT_ERROR_PARAM5 ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( certObject == NULL ) { cmd.flags = COMMAND_FLAG_RET_LENGTH; cmd.noStrArgs = 0; } cmd.arg[ 0 ] = certificate; cmd.arg[ 1 ] = certFormatType; cmd.strArg[ 0 ] = certObject; cmd.strArgLen[ 0 ] = certObjectMaxLength; status = DISPATCH_COMMAND( cmdExportObject, cmd ); if( cryptStatusOK( status ) ) { *certObjectLength = ( certObject == NULL ) ? \ cmd.arg[ 0 ] : cmd.strArgLen[ 0 ]; #if defined( EBCDIC_CHARS ) if( ( certFormatType == CRYPT_CERTFORMAT_TEXT_CERTIFICATE || \ certFormatType == CRYPT_CERTFORMAT_TEXT_CERTCHAIN || \ certFormatType == CRYPT_CERTFORMAT_XML_CERTIFICATE || \ certFormatType == CRYPT_CERTFORMAT_XML_CERTCHAIN ) && \ certObject != NULL ) { /* It's text-encoded cert data, convert it to the native text format before we return */ cryptlibToNativeString( certObject, certObject, *certObjectLength ); } #endif /* EBCDIC_CHARS */ return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } /* CA management functions */ C_RET cryptCAAddItem( C_IN CRYPT_KEYSET keyset, C_IN CRYPT_CERTIFICATE certificate ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_SETKEY, COMMAND_FLAG_NONE, 3, 0 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_N, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( keyset ) ) return( CRYPT_ERROR_PARAM1 ); if( !isHandleRangeValid( certificate ) ) return( CRYPT_ERROR_PARAM2 ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = keyset; cmd.arg[ 1 ] = certificate; cmd.arg[ 2 ] = TRUE; status = DISPATCH_COMMAND( cmdSetKey, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } C_RET cryptCAGetItem( C_IN CRYPT_KEYSET keyset, C_OUT CRYPT_CERTIFICATE C_PTR certificate, C_IN CRYPT_CERTTYPE_TYPE certType, C_IN CRYPT_KEYID_TYPE keyIDtype, C_IN C_STR keyID ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_GETKEY, COMMAND_FLAG_NONE, 3, 1 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_D, ARG_N, ARG_N, ARG_S, ARG_LAST }; COMMAND_INFO cmd; #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) BYTE keyIDBuffer[ MAX_ATTRIBUTE_SIZE + 1 ], *keyIDPtr = NULL; #else const char *keyIDPtr = keyID; #endif /* EBCDIC_CHARS || UNICODE_CHARS */ BOOLEAN isCert = FALSE; int status; /* Perform basic client-side error checking. Because of keyset queries we have to accept CRYPT_KEYID_NONE and a null keyID as well as obviously valid key ID's */ if( !isHandleRangeValid( keyset ) ) return( CRYPT_ERROR_PARAM1 ); if( !isWritePtr( certificate, sizeof( CRYPT_HANDLE ) ) ) return( CRYPT_ERROR_PARAM2 ); *certificate = CRYPT_ERROR; if( certType == CRYPT_CERTTYPE_CERTIFICATE || \ certType == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \ certType == CRYPT_CERTTYPE_CERTCHAIN ) isCert = TRUE; else if( certType != CRYPT_CERTTYPE_CERTREQUEST && \ certType != CRYPT_CERTTYPE_REQUEST_CERT && \ certType != CRYPT_CERTTYPE_REQUEST_REVOCATION && \ certType != CRYPT_CERTTYPE_PKIUSER ) return( CRYPT_ERROR_PARAM3 ); if( keyIDtype < CRYPT_KEYID_NONE || \ keyIDtype >= CRYPT_KEYID_LAST_EXTERNAL ) return( CRYPT_ERROR_PARAM4 ); if( keyIDtype == CRYPT_KEYID_NONE ) { if( keyID != NULL ) return( CRYPT_ERROR_PARAM5 ); } else if( !isReadPtr( keyID, MIN_NAME_LENGTH ) || \ strParamLen( keyID ) < MIN_NAME_LENGTH || \ strParamLen( keyID ) >= MAX_ATTRIBUTE_SIZE ) return( CRYPT_ERROR_PARAM5 ); #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) if( keyID != NULL ) { status = nativeToCryptlibString( keyIDBuffer, keyID, nativeStrlen( keyID ) + 1 ); if( cryptStatusError( status ) ) return( CRYPT_ERROR_PARAM4 ); keyIDPtr = keyIDBuffer; } #endif /* EBCDIC_CHARS || UNICODE_CHARS */ /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = keyset; if( isCert ) /* If we're being asked for a standard cert, the caller should really be using cryptGetPublicKey(), however for orthogonality we convert the request into a standard public-key read. Note that this leads to some ambiguity since we can't explicitly specify what we want returned for a cert read (for example we could get a chain if we ask for a single cert or a single cert if we ask for a chain, depending on what's there), but it's less confusing than refusing any request to read a cert */ cmd.arg[ 1 ] = KEYMGMT_ITEM_PUBLICKEY; else cmd.arg[ 1 ] = ( certType == CRYPT_CERTTYPE_PKIUSER ) ? \ KEYMGMT_ITEM_PKIUSER : KEYMGMT_ITEM_REQUEST; cmd.arg[ 2 ] = keyIDtype; cmd.strArg[ 0 ] = ( void * ) keyIDPtr; if( keyIDPtr != NULL ) cmd.strArgLen[ 0 ] = strlen( keyIDPtr ); status = DISPATCH_COMMAND( cmdGetKey, cmd ); if( cryptStatusOK( status ) ) { *certificate = cmd.arg[ 0 ]; return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } C_RET cryptCADeleteItem( C_IN CRYPT_KEYSET keyset, C_IN CRYPT_CERTTYPE_TYPE certType, C_IN CRYPT_KEYID_TYPE keyIDtype, C_IN C_STR keyID ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_DELETEKEY, COMMAND_FLAG_NONE, 3, 1 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_N, ARG_S, ARG_LAST }; COMMAND_INFO cmd; #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) BYTE keyIDBuffer[ MAX_ATTRIBUTE_SIZE + 1 ], *keyIDPtr = keyIDBuffer; #else const char *keyIDPtr = keyID; #endif /* EBCDIC_CHARS || UNICODE_CHARS */ int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( keyset ) ) return( CRYPT_ERROR_PARAM1 ); if( certType != CRYPT_CERTTYPE_CERTIFICATE && \ certType != CRYPT_CERTTYPE_CERTREQUEST && \ certType != CRYPT_CERTTYPE_REQUEST_CERT && \ certType != CRYPT_CERTTYPE_REQUEST_REVOCATION && \ certType != CRYPT_CERTTYPE_PKIUSER ) return( CRYPT_ERROR_PARAM2 ); if( keyIDtype <= CRYPT_KEYID_NONE || \ keyIDtype >= CRYPT_KEYID_LAST_EXTERNAL ) return( CRYPT_ERROR_PARAM3 ); if( !isReadPtr( keyID, MIN_NAME_LENGTH ) || \ strParamLen( keyID ) < MIN_NAME_LENGTH || \ strParamLen( keyID ) > MAX_ATTRIBUTE_SIZE ) return( CRYPT_ERROR_PARAM4 ); #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) status = nativeToCryptlibString( keyIDBuffer, keyID, nativeStrlen( keyID ) + 1 ); if( cryptStatusError( status ) ) return( CRYPT_ERROR_PARAM4 ); #endif /* EBCDIC_CHARS || UNICODE_CHARS */ /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = keyset; cmd.arg[ 1 ] = keyIDtype; if( certType == CRYPT_CERTTYPE_CERTIFICATE ) /* Allow a delete of a cert for the same reason as given above for cryptCAGetItem() */ cmd.noArgs = 2; else cmd.arg[ 2 ] = ( certType == CRYPT_CERTTYPE_PKIUSER ) ? \ CRYPT_CERTTYPE_PKIUSER : CRYPT_CERTTYPE_REQUEST_CERT; cmd.strArg[ 0 ] = ( void * ) keyIDPtr; cmd.strArgLen[ 0 ] = strlen( keyIDPtr ); status = DISPATCH_COMMAND( cmdDeleteKey, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } C_RET cryptCACertManagement( C_OUT CRYPT_CERTIFICATE C_PTR certificate, C_IN CRYPT_CERTACTION_TYPE action, C_IN CRYPT_KEYSET keyset, C_IN CRYPT_CONTEXT caKey, C_IN CRYPT_CERTIFICATE certRequest ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_CERTMGMT, COMMAND_FLAG_NONE, 4, 0 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_D, ARG_V, ARG_O, ARG_N, ARG_N, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( certificate != NULL ) { if( !isWritePtr( certificate, sizeof( CRYPT_HANDLE ) ) ) return( CRYPT_ERROR_PARAM1 ); *certificate = CRYPT_ERROR; } if( action < CRYPT_CERTACTION_FIRST_USER || \ action > CRYPT_CERTACTION_LAST_USER ) return( CRYPT_ERROR_PARAM2 ); if( !isHandleRangeValid( keyset ) ) return( CRYPT_ERROR_PARAM3 ); if( !isHandleRangeValid( caKey ) && \ !( ( action == CRYPT_CERTACTION_EXPIRE_CERT || \ action == CRYPT_CERTACTION_CLEANUP ) && caKey == CRYPT_UNUSED ) ) return( CRYPT_ERROR_PARAM4 ); if( !isHandleRangeValid( certRequest ) && \ !( ( action == CRYPT_CERTACTION_ISSUE_CRL || \ action == CRYPT_CERTACTION_EXPIRE_CERT || \ action == CRYPT_CERTACTION_CLEANUP ) && \ certRequest == CRYPT_UNUSED ) ) return( CRYPT_ERROR_PARAM5 ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( certificate == NULL ) cmd.flags = COMMAND_FLAG_RET_NONE; cmd.arg[ 0 ] = keyset; cmd.arg[ 1 ] = action; cmd.arg[ 2 ] = caKey; cmd.arg[ 3 ] = certRequest; status = DISPATCH_COMMAND( cmdCertMgmt, cmd ); if( cryptStatusOK( status ) && certificate != NULL ) { *certificate = cmd.arg[ 0 ]; return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } /**************************************************************************** * * * Envelope Functions * * * ****************************************************************************/ /* Push data into an envelope/session object */ C_RET cryptPushData( C_IN CRYPT_HANDLE envelope, C_IN void C_PTR buffer, C_IN int length, C_OUT int C_PTR bytesCopied ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_PUSHDATA, COMMAND_FLAG_NONE, 1, 1 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_S, ARG_N, ARG_N, ARG_LAST }; COMMAND_INFO cmd; int dummy, status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( envelope ) ) return( CRYPT_ERROR_PARAM1 ); if( !isReadPtr( buffer, length ) ) return( CRYPT_ERROR_PARAM2 ); if( length <= 0 ) return( CRYPT_ERROR_PARAM3 ); if( bytesCopied == NULL ) /* If the user isn't interested in the bytes copied count, point at a dummy location */ bytesCopied = &dummy; *bytesCopied = 0; /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = envelope; cmd.strArg[ 0 ] = ( void * ) buffer; cmd.strArgLen[ 0 ] = length; status = DISPATCH_COMMAND( cmdPushData, cmd ); *bytesCopied = cmd.arg[ 0 ]; if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } /* Pop data from an envelope/session object */ C_RET cryptPopData( C_IN CRYPT_ENVELOPE envelope, C_OUT void C_PTR buffer, C_IN int length, C_OUT int C_PTR bytesCopied ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_POPDATA, COMMAND_FLAG_NONE, 2, RETURN_VALUE( 1 ) }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_S, ARG_N, ARG_S, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( envelope ) ) return( CRYPT_ERROR_PARAM1 ); if( !isWritePtr( buffer, length ) ) return( CRYPT_ERROR_PARAM2 ); if( length <= 0 ) return( CRYPT_ERROR_PARAM3 ); memset( buffer, 0, min( length, 16 ) ); if( !isWritePtr( bytesCopied, sizeof( int ) ) ) return( CRYPT_ERROR_PARAM4 ); *bytesCopied = 0; /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = envelope; cmd.arg[ 1 ] = length; cmd.strArg[ 0 ] = ( void * ) buffer; cmd.strArgLen[ 0 ] = RETURN_VALUE( length ); status = DISPATCH_COMMAND( cmdPopData, cmd ); *bytesCopied = cmd.strArgLen[ 0 ]; if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } /* Flush data through an envelope/session object */ C_RET cryptFlushData( C_IN CRYPT_HANDLE envelope ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_FLUSHDATA, COMMAND_FLAG_NONE, 1, 0 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( envelope ) ) return( CRYPT_ERROR_PARAM1 ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = envelope; status = DISPATCH_COMMAND( cmdFlushData, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } /**************************************************************************** * * * Keyset Functions * * * ****************************************************************************/ /* Retrieve a key from a keyset or equivalent object */ C_RET cryptGetPublicKey( C_IN CRYPT_KEYSET keyset, C_OUT CRYPT_HANDLE C_PTR cryptKey, C_IN CRYPT_KEYID_TYPE keyIDtype, C_IN C_STR keyID ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_GETKEY, COMMAND_FLAG_NONE, 3, 1 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_D, ARG_N, ARG_S, ARG_LAST }; COMMAND_INFO cmd; #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) BYTE keyIDBuffer[ MAX_ATTRIBUTE_SIZE + 1 ], *keyIDPtr = NULL; #else const char *keyIDPtr = keyID; #endif /* EBCDIC_CHARS || UNICODE_CHARS */ int status; /* Perform basic client-side error checking. Because of keyset queries we have to accept CRYPT_KEYID_NONE and a null keyID as well as obviously valid key ID's */ if( !isHandleRangeValid( keyset ) ) return( CRYPT_ERROR_PARAM1 ); if( !isWritePtr( cryptKey, sizeof( CRYPT_HANDLE ) ) ) return( CRYPT_ERROR_PARAM2 ); *cryptKey = CRYPT_ERROR; if( keyIDtype < CRYPT_KEYID_NONE || \ keyIDtype >= CRYPT_KEYID_LAST_EXTERNAL ) return( CRYPT_ERROR_PARAM3 ); if( keyIDtype == CRYPT_KEYID_NONE ) { if( keyID != NULL ) return( CRYPT_ERROR_PARAM4 ); } else if( !isReadPtr( keyID, MIN_NAME_LENGTH ) || \ strParamLen( keyID ) < MIN_NAME_LENGTH || \ strParamLen( keyID ) >= MAX_ATTRIBUTE_SIZE ) return( CRYPT_ERROR_PARAM4 ); #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) if( keyID != NULL ) { status = nativeToCryptlibString( keyIDBuffer, keyID, nativeStrlen( keyID ) + 1 ); if( cryptStatusError( status ) ) return( CRYPT_ERROR_PARAM4 ); keyIDPtr = keyIDBuffer; } #endif /* EBCDIC_CHARS || UNICODE_CHARS */ /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = keyset; cmd.arg[ 1 ] = KEYMGMT_ITEM_PUBLICKEY; cmd.arg[ 2 ] = keyIDtype; cmd.strArg[ 0 ] = ( void * ) keyIDPtr; if( keyIDPtr != NULL ) cmd.strArgLen[ 0 ] = strlen( keyIDPtr ); status = DISPATCH_COMMAND( cmdGetKey, cmd ); if( cryptStatusOK( status ) ) { *cryptKey = cmd.arg[ 0 ]; return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } C_RET cryptGetPrivateKey( C_IN CRYPT_HANDLE keyset, C_OUT CRYPT_CONTEXT C_PTR cryptContext, C_IN CRYPT_KEYID_TYPE keyIDtype, C_IN C_STR keyID, C_IN C_STR password ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_GETKEY, COMMAND_FLAG_NONE, 3, 2 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_D, ARG_N, ARG_S, ARG_S, ARG_LAST }; COMMAND_INFO cmd; #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) BYTE keyIDBuffer[ MAX_ATTRIBUTE_SIZE + 1 ], *keyIDPtr = keyIDBuffer; BYTE passwordBuffer[ MAX_ATTRIBUTE_SIZE + 1 ], *passwordPtr = NULL; #else const char *keyIDPtr = keyID, *passwordPtr = password; #endif /* EBCDIC_CHARS || UNICODE_CHARS */ int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( keyset ) ) return( CRYPT_ERROR_PARAM1 ); if( !isWritePtr( cryptContext, sizeof( CRYPT_CONTEXT ) ) ) return( CRYPT_ERROR_PARAM2 ); *cryptContext = CRYPT_ERROR; if( keyIDtype <= CRYPT_KEYID_NONE || \ keyIDtype >= CRYPT_KEYID_LAST_EXTERNAL ) return( CRYPT_ERROR_PARAM3 ); if( !isReadPtr( keyID, MIN_NAME_LENGTH ) || \ strParamLen( keyID ) < MIN_NAME_LENGTH || \ strParamLen( keyID ) >= MAX_ATTRIBUTE_SIZE ) return( CRYPT_ERROR_PARAM4 ); if( password != NULL && \ ( !isReadPtr( password, MIN_NAME_LENGTH ) || \ strParamLen( password ) < MIN_NAME_LENGTH || \ strParamLen( password ) >= MAX_ATTRIBUTE_SIZE ) ) return( CRYPT_ERROR_PARAM5 ); #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) status = nativeToCryptlibString( keyIDBuffer, keyID, nativeStrlen( keyID ) + 1 ); if( cryptStatusError( status ) ) return( CRYPT_ERROR_PARAM4 ); if( password != NULL ) { status = nativeToCryptlibString( passwordBuffer, password, nativeStrlen( password ) + 1 ); if( cryptStatusError( status ) ) return( CRYPT_ERROR_PARAM5 ); passwordPtr = passwordBuffer; } #endif /* EBCDIC_CHARS || UNICODE_CHARS */ /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = keyset; cmd.arg[ 1 ] = KEYMGMT_ITEM_PRIVATEKEY; cmd.arg[ 2 ] = keyIDtype; cmd.strArg[ 0 ] = ( void * ) keyIDPtr; cmd.strArgLen[ 0 ] = strlen( keyIDPtr ); cmd.strArg[ 1 ] = ( void * ) passwordPtr; if( passwordPtr != NULL ) cmd.strArgLen[ 1 ] = strlen( passwordPtr ); status = DISPATCH_COMMAND( cmdGetKey, cmd ); #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) zeroise( passwordBuffer, MAX_ATTRIBUTE_SIZE + 1 ); #endif /* EBCDIC_CHARS || UNICODE_CHARS */ if( cryptStatusOK( status ) ) { *cryptContext = cmd.arg[ 0 ]; return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } C_RET cryptGetKey( C_IN CRYPT_HANDLE keyset, C_OUT CRYPT_CONTEXT C_PTR cryptContext, C_IN CRYPT_KEYID_TYPE keyIDtype, C_IN C_STR keyID, C_IN C_STR password ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_GETKEY, COMMAND_FLAG_NONE, 3, 2 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_D, ARG_N, ARG_S, ARG_S, ARG_LAST }; COMMAND_INFO cmd; #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) BYTE keyIDBuffer[ MAX_ATTRIBUTE_SIZE + 1 ], *keyIDPtr = keyIDBuffer; BYTE passwordBuffer[ MAX_ATTRIBUTE_SIZE + 1 ], *passwordPtr = NULL; #else const char *keyIDPtr = keyID, *passwordPtr = password; #endif /* EBCDIC_CHARS || UNICODE_CHARS */ int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( keyset ) ) return( CRYPT_ERROR_PARAM1 ); if( !isWritePtr( cryptContext, sizeof( CRYPT_CONTEXT ) ) ) return( CRYPT_ERROR_PARAM2 ); *cryptContext = CRYPT_ERROR; if( keyIDtype <= CRYPT_KEYID_NONE || \ keyIDtype >= CRYPT_KEYID_LAST_EXTERNAL ) return( CRYPT_ERROR_PARAM3 ); if( !isReadPtr( keyID, MIN_NAME_LENGTH ) || \ strParamLen( keyID ) < MIN_NAME_LENGTH || \ strParamLen( keyID ) >= MAX_ATTRIBUTE_SIZE ) return( CRYPT_ERROR_PARAM4 ); if( password != NULL && \ ( !isReadPtr( password, MIN_NAME_LENGTH ) || \ strParamLen( password ) < MIN_NAME_LENGTH || \ strParamLen( password ) >= MAX_ATTRIBUTE_SIZE ) ) return( CRYPT_ERROR_PARAM5 ); #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) status = nativeToCryptlibString( keyIDBuffer, keyID, nativeStrlen( keyID ) + 1 ); if( cryptStatusError( status ) ) return( CRYPT_ERROR_PARAM4 ); if( password != NULL ) { status = nativeToCryptlibString( passwordBuffer, password, nativeStrlen( password ) + 1 ); if( cryptStatusError( status ) ) return( CRYPT_ERROR_PARAM5 ); passwordPtr = passwordBuffer; } #endif /* EBCDIC_CHARS || UNICODE_CHARS */ /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = keyset; cmd.arg[ 1 ] = KEYMGMT_ITEM_SECRETKEY; cmd.arg[ 2 ] = keyIDtype; cmd.strArg[ 0 ] = ( void * ) keyIDPtr; cmd.strArgLen[ 0 ] = strlen( keyIDPtr ); cmd.strArg[ 1 ] = ( void * ) passwordPtr; if( passwordPtr != NULL ) cmd.strArgLen[ 1 ] = strlen( passwordPtr ); status = DISPATCH_COMMAND( cmdGetKey, cmd ); #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) zeroise( passwordBuffer, MAX_ATTRIBUTE_SIZE + 1 ); #endif /* EBCDIC_CHARS || UNICODE_CHARS */ if( cryptStatusOK( status ) ) { *cryptContext = cmd.arg[ 0 ]; return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } /* Add a key from a keyset or equivalent object */ C_RET cryptAddPublicKey( C_IN CRYPT_KEYSET keyset, C_IN CRYPT_CERTIFICATE certificate ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_SETKEY, COMMAND_FLAG_NONE, 2, 0 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_N, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( keyset ) ) return( CRYPT_ERROR_PARAM1 ); if( !isHandleRangeValid( certificate ) ) return( CRYPT_ERROR_PARAM2 ); /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = keyset; cmd.arg[ 1 ] = certificate; status = DISPATCH_COMMAND( cmdSetKey, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } C_RET cryptAddPrivateKey( C_IN CRYPT_KEYSET keyset, C_IN CRYPT_HANDLE cryptKey, C_IN C_STR password ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_SETKEY, COMMAND_FLAG_NONE, 2, 1 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_N, ARG_S, ARG_LAST }; COMMAND_INFO cmd; #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) BYTE passwordBuffer[ MAX_ATTRIBUTE_SIZE + 1 ], *passwordPtr = NULL; #else const char *passwordPtr = password; #endif /* EBCDIC_CHARS || UNICODE_CHARS */ int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( keyset ) ) return( CRYPT_ERROR_PARAM1 ); if( !isHandleRangeValid( cryptKey ) ) return( CRYPT_ERROR_PARAM2 ); if( password != NULL && \ ( !isReadPtr( password, MIN_NAME_LENGTH ) || \ isBadPassword( password ) || \ strParamLen( password ) < MIN_NAME_LENGTH || \ strParamLen( password ) >= MAX_ATTRIBUTE_SIZE ) ) return( CRYPT_ERROR_PARAM3 ); #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) if( password != NULL ) { status = nativeToCryptlibString( passwordBuffer, password, nativeStrlen( password ) + 1 ); if( cryptStatusError( status ) ) return( CRYPT_ERROR_PARAM3 ); passwordPtr = passwordBuffer; } #endif /* EBCDIC_CHARS || UNICODE_CHARS */ /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = keyset; cmd.arg[ 1 ] = cryptKey; cmd.strArg[ 0 ] = ( void * ) passwordPtr; if( passwordPtr != NULL ) cmd.strArgLen[ 0 ] = strlen( passwordPtr ); status = DISPATCH_COMMAND( cmdSetKey, cmd ); #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) zeroise( passwordBuffer, MAX_ATTRIBUTE_SIZE + 1 ); #endif /* EBCDIC_CHARS || UNICODE_CHARS */ if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } /* Delete a key from a keyset or equivalent object */ C_RET cryptDeleteKey( C_IN CRYPT_KEYSET keyset, C_IN CRYPT_KEYID_TYPE keyIDtype, C_IN C_STR keyID ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_DELETEKEY, COMMAND_FLAG_NONE, 2, 1 }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_N, ARG_S, ARG_LAST }; COMMAND_INFO cmd; #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) BYTE keyIDBuffer[ MAX_ATTRIBUTE_SIZE + 1 ], *keyIDPtr = keyIDBuffer; #else const char *keyIDPtr = keyID; #endif /* EBCDIC_CHARS || UNICODE_CHARS */ int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( keyset ) ) return( CRYPT_ERROR_PARAM1 ); if( keyIDtype <= CRYPT_KEYID_NONE || \ keyIDtype >= CRYPT_KEYID_LAST_EXTERNAL ) return( CRYPT_ERROR_PARAM2 ); if( !isReadPtr( keyID, MIN_NAME_LENGTH ) || \ strParamLen( keyID ) < MIN_NAME_LENGTH || \ strParamLen( keyID ) > MAX_ATTRIBUTE_SIZE ) return( CRYPT_ERROR_PARAM3 ); #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) status = nativeToCryptlibString( keyIDBuffer, keyID, nativeStrlen( keyID ) + 1 ); if( cryptStatusError( status ) ) return( CRYPT_ERROR_PARAM3 ); #endif /* EBCDIC_CHARS || UNICODE_CHARS */ /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); cmd.arg[ 0 ] = keyset; cmd.arg[ 1 ] = keyIDtype; cmd.strArg[ 0 ] = ( void * ) keyIDPtr; cmd.strArgLen[ 0 ] = strlen( keyIDPtr ); status = DISPATCH_COMMAND( cmdDeleteKey, cmd ); if( cryptStatusOK( status ) ) return( CRYPT_OK ); return( mapError( errorMap, status ) ); } /**************************************************************************** * * * User Management Functions * * * ****************************************************************************/ /**************************************************************************** * * * Misc Functions * * * ****************************************************************************/ /* cryptlib/object query functions */ C_RET cryptQueryCapability( C_IN CRYPT_ALGO_TYPE cryptAlgo, C_OUT CRYPT_QUERY_INFO C_PTR cryptQueryInfo ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_QUERYCAPABILITY, COMMAND_FLAG_NONE, 2, RETURN_VALUE( 1 ), { SYSTEM_OBJECT_HANDLE } }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_N, ARG_N, ARG_S, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( cryptAlgo < CRYPT_ALGO_NONE || cryptAlgo >= CRYPT_ALGO_LAST ) return( CRYPT_ERROR_PARAM1 ); if( cryptQueryInfo != NULL ) { if( !isWritePtr( cryptQueryInfo, sizeof( CRYPT_QUERY_INFO ) ) ) return( CRYPT_ERROR_PARAM3 ); memset( cryptQueryInfo, 0, sizeof( CRYPT_QUERY_INFO ) ); } /* Dispatch the command. We need to map parameter errors down one because the system object is invisible to the caller */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( cryptQueryInfo == NULL ) { cmd.flags = COMMAND_FLAG_RET_LENGTH; cmd.noStrArgs = 0; } cmd.arg[ 1 ] = cryptAlgo; cmd.strArg[ 0 ] = cryptQueryInfo; cmd.strArgLen[ 0 ] = RETURN_VALUE( MAX_ATTRIBUTE_SIZE ); status = DISPATCH_COMMAND( cmdQueryCapability, cmd ); if( cryptStatusOK( status ) ) { #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) if( cryptQueryInfo != NULL ) { BYTE buffer[ MAX_ATTRIBUTE_SIZE ]; const int algoNameLength = \ strlen( ( char * ) cryptQueryInfo->algoName ) + 1; memcpy( buffer, cryptQueryInfo->algoName, algoNameLength ); cryptlibToNativeString( cryptQueryInfo->algoName, buffer, algoNameLength ); } #endif /* EBCDIC_CHARS || UNICODE_CHARS */ return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } C_RET cryptDeviceQueryCapability( C_IN CRYPT_DEVICE device, C_IN CRYPT_ALGO_TYPE cryptAlgo, C_OUT CRYPT_QUERY_INFO C_PTR cryptQueryInfo ) { static const COMMAND_INFO FAR_BSS cmdTemplate = \ { COMMAND_QUERYCAPABILITY, COMMAND_FLAG_NONE, 2, RETURN_VALUE( 1 ) }; static const ERRORMAP FAR_BSS errorMap[] = \ { ARG_O, ARG_N, ARG_N, ARG_S, ARG_LAST }; COMMAND_INFO cmd; int status; /* Perform basic client-side error checking */ if( !isHandleRangeValid( device ) ) return( CRYPT_ERROR_PARAM1 ); if( cryptAlgo < CRYPT_ALGO_NONE || cryptAlgo >= CRYPT_ALGO_LAST ) return( CRYPT_ERROR_PARAM2 ); if( cryptQueryInfo != NULL ) { if( !isWritePtr( cryptQueryInfo, sizeof( CRYPT_QUERY_INFO ) ) ) return( CRYPT_ERROR_PARAM4 ); memset( cryptQueryInfo, 0, sizeof( CRYPT_QUERY_INFO ) ); } /* Dispatch the command */ memcpy( &cmd, &cmdTemplate, sizeof( COMMAND_INFO ) ); if( cryptQueryInfo == NULL ) { cmd.flags = COMMAND_FLAG_RET_LENGTH; cmd.noStrArgs = 0; } cmd.arg[ 0 ] = device; cmd.arg[ 1 ] = cryptAlgo; cmd.strArg[ 0 ] = cryptQueryInfo; cmd.strArgLen[ 0 ] = RETURN_VALUE( MAX_ATTRIBUTE_SIZE ); status = DISPATCH_COMMAND( cmdQueryCapability, cmd ); if( cryptStatusOK( status ) ) { #if defined( EBCDIC_CHARS ) || defined( UNICODE_CHARS ) if( cryptQueryInfo != NULL ) { BYTE buffer[ MAX_ATTRIBUTE_SIZE ]; const int algoNameLength = \ strlen( ( char * ) cryptQueryInfo->algoName ) + 1; memcpy( buffer, cryptQueryInfo->algoName, algoNameLength ); cryptlibToNativeString( cryptQueryInfo->algoName, buffer, algoNameLength ); } #endif /* EBCDIC_CHARS || UNICODE_CHARS */ return( CRYPT_OK ); } return( mapError( errorMap, status ) ); } /* If the use of certificates is disabled, we have to provide stub replacements for the legacy blob cert-extension manipulation functions, which aren't handled by the kernel */ #ifndef USE_CERTIFICATES C_RET cryptGetCertExtension( C_IN CRYPT_CERTIFICATE certificate, C_IN char C_PTR oid, C_OUT int C_PTR criticalFlag, C_OUT void C_PTR extension, C_IN int extensionMaxLength, C_OUT int C_PTR extensionLength ) { return( CRYPT_ERROR_NOTAVAIL ); } C_RET cryptAddCertExtension( C_IN CRYPT_CERTIFICATE certificate, C_IN char C_PTR oid, C_IN int criticalFlag, C_IN void C_PTR extension, C_IN int extensionLength ) { return( CRYPT_ERROR_NOTAVAIL ); } C_RET cryptDeleteCertExtension( C_IN CRYPT_CERTIFICATE certificate, C_IN char C_PTR oid ) { return( CRYPT_ERROR_NOTAVAIL ); } #endif /* !USE_CERTIFICATES */ /**************************************************************************** * * * Custom Code Insertion Point * * * ****************************************************************************/ /* This section can be used to insert custom code for application-specific purposes. It's normally not used, and isn't present in the standard distribution */ #if !defined( NDEBUG ) && 0 #include "docs/cryptapi_ext.c" #endif /* Debug-mode only test code */