📄 sendmsg.c
字号:
/****************************************************************************
* *
* Kernel Message Dispatcher *
* Copyright Peter Gutmann 1997-2004 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "crypt.h"
#include "acl.h"
#include "kernel.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "acl.h"
#include "kernel.h"
#else
#include "crypt.h"
#include "kernel/acl.h"
#include "kernel/kernel.h"
#endif /* Compiler-specific includes */
/* A pointer to the kernel data block */
static KERNEL_DATA *krnlData = NULL;
/* The ACL used to check objects passed as message parameters, in this case
for cert sign/sig-check messages */
static const FAR_BSS MESSAGE_ACL messageParamACLTbl[] = {
/* Certs can only be signed by (private-key) PKC contexts */
{ MESSAGE_CRT_SIGN,
{ ST_CTX_PKC,
ST_NONE } },
/* Signatures can be checked with a raw PKC context or a cert or cert
chain. The object being checked can also be checked against a CRL,
against revocation data in a cert store, or against an RTCS or OCSP
responder */
{ MESSAGE_CRT_SIGCHECK,
{ ST_CTX_PKC | ST_CERT_CERT | ST_CERT_CERTCHAIN | ST_CERT_CRL | \
ST_KEYSET_DBMS,
ST_SESS_RTCS | ST_SESS_OCSP } },
{ MESSAGE_NONE, ST_NONE, ST_NONE }
};
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Sometimes a message is explicitly non-routable (i.e. it has to be sent
directly to the appropriate target object). The following function checks
that the target object is one of the required types */
int checkTargetType( const int objectHandle, const int targets )
{
const OBJECT_TYPE target = targets & 0xFF;
const OBJECT_TYPE altTarget = targets >> 8;
OBJECT_INFO *objectTable = krnlData->objectTable;
/* Precondition: Source is a valid object, destination(s) are valid
target(s) */
PRE( isValidObject( objectHandle ) );
PRE( isValidType( target ) );
PRE( altTarget == OBJECT_TYPE_NONE || isValidType( altTarget ) );
/* Check whether the object matches the required type. We don't have to
check whether the alternative target has a value or not since the
object can never be a OBJECT_TYPE_NONE */
if( !isValidObject( objectHandle ) || \
( objectTable[ objectHandle ].type != target && \
objectTable[ objectHandle ].type != altTarget ) )
return( CRYPT_ERROR );
/* Postcondition */
POST( objectTable[ objectHandle ].type == target || \
objectTable[ objectHandle ].type == altTarget );
return( objectHandle );
}
/* Find the ACL for a parameter object */
static const MESSAGE_ACL *findParamACL( const MESSAGE_TYPE message )
{
int i;
/* Precondition: It's a message that takes an object parameter */
PRE( isParamMessage( message ) );
/* Find the ACL entry for this message type */
for( i = 0; messageParamACLTbl[ i ].type != MESSAGE_NONE; i++ )
if( messageParamACLTbl[ i ].type == message )
return( &messageParamACLTbl[ i ] );
/* Postcondition: We found a matching ACL entry */
POST( NOTREACHED );
/* Return a no-permission ACL in case of error */
return( &messageParamACLTbl[ i ] );
}
/* Wait for an object to become available so that we can use it, with a
timeout for blocked objects. This is an internal function which is used
when mapping an object handle to object data, and is never called
directly. As an aid in identifying objects acting as bottlenecks, we
provide a function to warn about excessive waiting, along with information
on the object that was waited on, in debug mode. A wait count threshold
of 100 is generally high enough to avoid false positives caused by (for
example) network subsystem delays */
#define MAX_WAITCOUNT 10000
#define WAITCOUNT_WARN_THRESHOLD 100
#ifndef NDEBUG
#include <stdio.h>
static void waitWarn( const int objectHandle, const int waitCount )
{
static const char *objectTypeNames[] = {
"None", "Context", "Keyset", "Envelope", "Certificate", "Device",
"Session", "User", "None", "None"
};
const OBJECT_INFO *objectInfoPtr = &krnlData->objectTable[ objectHandle ];
char buffer[ 128 ];
if( objectHandle == SYSTEM_OBJECT_HANDLE )
strcpy( buffer, "system object" );
else
if( objectHandle == DEFAULTUSER_OBJECT_HANDLE )
strcpy( buffer, "default user object" );
else
sPrintf( buffer, "object %d (%s, subtype %lX)",
objectHandle, objectTypeNames[ objectInfoPtr->type ],
objectInfoPtr->subType );
fprintf( stderr, "\nWarning: Thread %X waited %d iteration%s for %s.\n",
THREAD_SELF(), waitCount, ( waitCount == 1 ) ? "" : "s",
buffer );
}
#endif /* Debug mode only */
int waitForObject( const int objectHandle, OBJECT_INFO **objectInfoPtrPtr )
{
OBJECT_INFO *objectTable = krnlData->objectTable;
const unsigned int uniqueID = objectTable[ objectHandle ].uniqueID;
int waitCount = 0;
/* Preconditions: The object is in use by another thread */
PRE( isValidObject( objectHandle ) );
PRE( isInUse( objectHandle ) && !isObjectOwner( objectHandle ) );
/* While the object is busy, put the thread to sleep. This is the
optimal portable way to wait on the resource, since it gives up this
thread's timeslice to allow other threads (including the one using
the object) to run. Other methods such as mutexes with timers are
difficult to manage portably across different platforms */
while( objectTable[ objectHandle ].uniqueID == uniqueID && \
isInUse( objectHandle ) && waitCount < MAX_WAITCOUNT && \
krnlData->shutdownLevel < SHUTDOWN_LEVEL_MESSAGES )
{
MUTEX_UNLOCK( objectTable );
waitCount++;
THREAD_YIELD();
MUTEX_LOCK( objectTable );
}
#ifndef NDEBUG
if( waitCount > WAITCOUNT_WARN_THRESHOLD )
/* If we waited more than WAITCOUNT_WARN_THRESHOLD iterations for
something this could be a sign of a resource usage bottleneck
(typically caused by users who don't understand threading), warn
the user that there's a potential problem */
waitWarn( objectHandle, waitCount );
#endif /* NDEBUG */
/* If cryptlib is shutting down, exit */
if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MESSAGES )
return( CRYPT_ERROR_PERMISSION );
/* If we timed out waiting for the object, return a timeout error */
if( waitCount >= MAX_WAITCOUNT )
{
assert( NOTREACHED );
return( CRYPT_ERROR_TIMEOUT );
}
/* Make sure that nothing happened to the object while we were waiting
on it */
if( objectTable[ objectHandle ].uniqueID != uniqueID )
return( CRYPT_ERROR_SIGNALLED );
/* Update the object info pointer in case the object table was updated
while we had yielded control */
*objectInfoPtrPtr = &objectTable[ objectHandle ];
/* Postconditions: The object is available for use */
POST( isValidObject( objectHandle ) );
POST( !isInUse( objectHandle ) );
return( CRYPT_OK );
}
#if 0 /* 18/2/04 No need for copy-on-write any more since we can just copy
across the instance data referenced in the object table */
/* Handle an object that has been cloned and is subject to copy-on-write */
static int handleAliasedObject( const int objectHandle,
const MESSAGE_TYPE message,
const void *messageDataPtr,
const int messageValue )
{
OBJECT_INFO *objectTable = krnlData->objectTable;
OBJECT_INFO *objectInfoPtr = &objectTable[ objectHandle ];
CRYPT_CONTEXT originalObject = objectHandle;
CRYPT_CONTEXT clonedObject = objectInfoPtr->clonedObject;
int status;
/* Preconditions */
PRE( isValidObject( objectHandle ) && \
objectHandle >= NO_SYSTEM_OBJECTS );
PRE( isValidObject( clonedObject ) && \
clonedObject >= NO_SYSTEM_OBJECTS );
PRE( objectInfoPtr->type == OBJECT_TYPE_CONTEXT );
PRE( objectTable[ clonedObject ].type == OBJECT_TYPE_CONTEXT );
PRE( objectHandle != clonedObject );
PRE( isAliasedObject( objectHandle ) && isAliasedObject( clonedObject ) );
PRE( isClonedObject( objectHandle ) || isClonedObject( clonedObject ) );
/* If it's a destroy-object message, make sure that the (incomplete)
clone is the one that gets destroyed rather than the original */
if( message == MESSAGE_DESTROY )
{
OBJECT_INFO *originalObjectInfoPtr, *clonedObjectInfoPtr;
OBJECT_INFO tempObjectInfo;
/* If we're destroying the clone, we're done */
if( isClonedObject( objectHandle ) )
return( CRYPT_OK );
/* We're trying to destroy the original, switch it with the clone */
memcpy( &tempObjectInfo, &objectTable[ objectHandle ],
sizeof( OBJECT_INFO ) );
memcpy( &objectTable[ objectHandle ], &objectTable[ clonedObject ],
sizeof( OBJECT_INFO ) );
memcpy( &objectTable[ clonedObject ], &tempObjectInfo,
sizeof( OBJECT_INFO ) );
/* Inner precondition: Now the original is the clone and the clone is
the original */
PRE( isClonedObject( objectHandle ) );
PRE( !isClonedObject( clonedObject ) );
/* We've now swapped the clone and the original, mark them as normal
(non-aliased) objects since we're about to destroy the clone */
originalObjectInfoPtr = &objectTable[ clonedObject ];
clonedObjectInfoPtr = &objectTable[ objectHandle ];
originalObjectInfoPtr->flags &= ~OBJECT_FLAG_ALIASED;
clonedObjectInfoPtr->flags &= ~( OBJECT_FLAG_ALIASED | OBJECT_FLAG_CLONE );
originalObjectInfoPtr->clonedObject = \
clonedObjectInfoPtr->clonedObject = CRYPT_ERROR;
/* Postconditions: The two objects are back to being normal objects */
POST( !isAliasedObject( objectHandle ) && !isClonedObject( objectHandle ) );
POST( !isAliasedObject( clonedObject ) && !isClonedObject( clonedObject ) );
return( CRYPT_OK );
}
/* If it's not a message that modifies the object's state, we're done */
if( !isActionMessage( message ) && \
!( message == MESSAGE_SETATTRIBUTE || \
message == MESSAGE_SETATTRIBUTE_S || \
message == MESSAGE_DELETEATTRIBUTE ) && \
!( message == MESSAGE_CTX_GENIV || message == MESSAGE_CLONE ) )
return( CRYPT_OK );
/* If the object that we've been passed is the clone, get the original
and clone into their correct roles */
if( isClonedObject( objectHandle ) )
{
clonedObject = objectHandle;
originalObject = objectInfoPtr->clonedObject;
objectInfoPtr = &objectTable[ originalObject ];
}
/* Inner precondition: We've sorted out the original vs.the clone, and
the two are distinct */
PRE( isClonedObject( clonedObject ) );
PRE( clonedObject != originalObject );
/* We're about to modify one of the two aliased objects, create distinct
objects to enforce copy-on-write semantics and reset the cloned/
aliased status. We also create two distinct objects if a second
attempt is made to clone the original rather than allowing the
creation of multiple aliased objects. This is done for two reasons,
firstly because handling arbitrarily large collections of cloned
objects, while possible, complicates the kernel since it's no longer
a straighforward message filter that needs to add relatively complex
processing to manage chains of cloned objects. Secondly, having
multiple aliased objects is exceedingly rare (it can only happen if a
user, for some reason, pushes the same session key or hash into
multiple envelopes), so the extra overhead of a forced clone is
negligible */
status = cloneContext( clonedObject, originalObject );
if( cryptStatusOK( status ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -