cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
sendmsg.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Kernel Message Dispatcher *
4 * Copyright Peter Gutmann 1997-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "acl.h"
11  #include "kernel.h"
12 #else
13  #include "crypt.h"
14  #include "kernel/acl.h"
15  #include "kernel/kernel.h"
16 #endif /* Compiler-specific includes */
17 
18 /* A pointer to the kernel data block */
19 
20 static KERNEL_DATA *krnlData = NULL;
21 
22 /* The ACL used to check objects passed as message parameters, in this case
23  for cert sign/sig-check messages */
24 
25 static const MESSAGE_ACL FAR_BSS messageParamACLTbl[] = {
26  /* Certs can only be signed by (private-key) PKC contexts */
28  { ST_CTX_PKC,
29  ST_NONE, ST_NONE } },
30 
31  /* Signatures can be checked with a raw PKC context or a cert or cert
32  chain. The object being checked can also be checked against a CRL,
33  against revocation data in a cert store, or against an RTCS or OCSP
34  responder */
39 
40  /* End-of-ACL marker */
41  { MESSAGE_NONE, { ST_NONE, ST_NONE, ST_NONE } },
42  { MESSAGE_NONE, { ST_NONE, ST_NONE, ST_NONE } }
43  };
44 
45 /****************************************************************************
46 * *
47 * Utility Functions *
48 * *
49 ****************************************************************************/
50 
51 /* Sometimes a message is explicitly non-routable (i.e. it has to be sent
52  directly to the appropriate target object). The following function checks
53  that the target object is one of the required types */
54 
55 CHECK_RETVAL \
56 int checkTargetType( IN_HANDLE const int objectHandle, const long targets )
57  {
58  const OBJECT_TYPE target = targets & 0xFF;
59  const OBJECT_TYPE altTarget = targets >> 8;
60  OBJECT_INFO *objectTable = krnlData->objectTable;
61 
62  /* Precondition: Source is a valid object, destination(s) are valid
63  target(s) */
64  REQUIRES( isValidObject( objectHandle ) );
65  REQUIRES( isValidType( target ) );
66  REQUIRES( altTarget == OBJECT_TYPE_NONE || isValidType( altTarget ) );
67 
68  /* Check whether the object matches the required type. We don't have to
69  check whether the alternative target has a value or not since the
70  object can never be a OBJECT_TYPE_NONE */
71  if( !isValidObject( objectHandle ) || \
72  ( objectTable[ objectHandle ].type != target && \
73  objectTable[ objectHandle ].type != altTarget ) )
74  return( CRYPT_ERROR );
75 
76  /* Postcondition */
77  ENSURES( objectTable[ objectHandle ].type == target || \
78  objectTable[ objectHandle ].type == altTarget );
79 
80  return( objectHandle );
81  }
82 
83 /* Find the ACL for a parameter object */
84 
85 CHECK_RETVAL_PTR \
86 static const MESSAGE_ACL *findParamACL( IN_MESSAGE const MESSAGE_TYPE message )
87  {
88  int i;
89 
90  /* Precondition: It's a message that takes an object parameter */
91  REQUIRES_N( isParamMessage( message ) );
92 
93  /* Find the ACL entry for this message type. There's no need to
94  explicitly handle the internal-error condition since any loop
95  exit is treated as an error */
96  for( i = 0; messageParamACLTbl[ i ].type != MESSAGE_NONE && \
97  i < FAILSAFE_ARRAYSIZE( messageParamACLTbl, MESSAGE_ACL );
98  i++ )
99  {
100  if( messageParamACLTbl[ i ].type == message )
101  return( &messageParamACLTbl[ i ] );
102  }
103 
105  }
106 
107 /* Wait for an object to become available so that we can use it, with a
108  timeout for blocked objects (dulcis et alta quies placidaeque similima
109  morti). This is an internal function which is used when mapping an
110  object handle to object data, and is never called directly. As an aid in
111  identifying objects acting as bottlenecks, we provide a function to warn
112  about excessive waiting, along with information on the object that was
113  waited on, in debug mode. A wait count threshold of 100 is generally
114  high enough to avoid false positives caused by (for example) network
115  subsystem delays */
116 
117 #define MAX_WAITCOUNT 10000
118 #define WAITCOUNT_WARN_THRESHOLD 100
119 
120 #if !defined( NDEBUG ) && !defined( __WIN16__ )
121 
122 static void waitWarn( IN_HANDLE const int objectHandle,
123  IN_INT const int waitCount )
124  {
125  static const char *objectTypeNames[] = {
126  "None", "Context", "Keyset", "Envelope", "Certificate", "Device",
127  "Session", "User", "None", "None"
128  };
129  const OBJECT_INFO *objectInfoPtr = &krnlData->objectTable[ objectHandle ];
130  char buffer[ 128 + 8 ];
131 
132  assert( isValidObject( objectHandle ) );
133  assert( waitCount > WAITCOUNT_WARN_THRESHOLD && \
134  waitCount <= MAX_WAITCOUNT );
135 
136  REQUIRES_V( isValidType( objectInfoPtr->type ) );
137 
138  if( objectHandle == SYSTEM_OBJECT_HANDLE )
139  strlcpy_s( buffer, 128, "system object" );
140  else
141  {
142  if( objectHandle == DEFAULTUSER_OBJECT_HANDLE )
143  strlcpy_s( buffer, 128, "default user object" );
144  else
145  {
146  sprintf_s( buffer, 128, "object %d (%s, subtype %X)",
147  objectHandle, objectTypeNames[ objectInfoPtr->type ],
148  objectInfoPtr->subType );
149  }
150  }
151  DEBUG_PRINT(( "\nWarning: Thread %lX waited %d iteration%s for %s.\n",
152  ( unsigned long ) THREAD_SELF(), waitCount,
153  ( waitCount == 1 ) ? "" : "s", buffer ));
154  }
155 #endif /* Debug mode only */
156 
158 int waitForObject( IN_HANDLE const int objectHandle,
160  {
161  OBJECT_INFO *objectTable = krnlData->objectTable;
162  const int uniqueID = objectTable[ objectHandle ].uniqueID;
163  int waitCount = 0;
164 
165  /* Preconditions: The object is in use by another thread */
166  REQUIRES( isValidObject( objectHandle ) );
167  REQUIRES( isInUse( objectHandle ) && !isObjectOwner( objectHandle ) );
168 
169  /* While the object is busy, put the thread to sleep (Pauzele lungi si
170  dese; Cheia marilor succese). This is the only really portable way
171  to wait on the resource, which gives up this thread's timeslice to
172  allow other threads (including the one using the object) to run.
173  Somewhat better methods methods such as mutexes with timers are
174  difficult to manage portably across different platforms */
175  while( isValidObject( objectHandle ) && \
176  objectTable[ objectHandle ].uniqueID == uniqueID && \
177  isInUse( objectHandle ) && waitCount < MAX_WAITCOUNT && \
179  {
180  objectTable = NULL;
181  MUTEX_UNLOCK( objectTable );
182  waitCount++;
183  THREAD_YIELD();
184  MUTEX_LOCK( objectTable );
185  objectTable = krnlData->objectTable;
186  }
187 #if !defined( NDEBUG ) && !defined( __WIN16__ )
188  if( waitCount > WAITCOUNT_WARN_THRESHOLD )
189  {
190  /* If we waited more than WAITCOUNT_WARN_THRESHOLD iterations for
191  something this could be a sign of a resource usage bottleneck
192  (typically caused by users who don't understand threading), warn
193  the user that there's a potential problem */
194  waitWarn( objectHandle, waitCount );
195  }
196 #endif /* NDEBUG on systems with stdio */
197 
198  /* If cryptlib is shutting down, exit */
199  if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MESSAGES )
200  return( CRYPT_ERROR_PERMISSION );
201 
202  /* If we timed out waiting for the object, return a timeout error */
203  if( waitCount >= MAX_WAITCOUNT )
204  {
205  DEBUG_DIAG(( "Object wait exceeded %d iterations", MAX_WAITCOUNT ));
206  assert( DEBUG_WARN );
207  return( CRYPT_ERROR_TIMEOUT );
208  }
209 
210  /* Make sure that nothing happened to the object while we were waiting
211  on it */
212  if( !isValidObject( objectHandle ) || \
213  objectTable[ objectHandle ].uniqueID != uniqueID )
214  return( CRYPT_ERROR_SIGNALLED );
215 
216  /* Update the object info pointer in case the object table was updated
217  while we had yielded control */
218  *objectInfoPtrPtr = &objectTable[ objectHandle ];
219 
220  /* Postconditions: The object is available for use */
221  ENSURES( isValidObject( objectHandle ) );
222  ENSURES( !isInUse( objectHandle ) );
223 
224  return( CRYPT_OK );
225  }
226 
227 /****************************************************************************
228 * *
229 * Message Routing *
230 * *
231 ****************************************************************************/
232 
233 /* Find the ultimate target of an object attribute manipulation message by
234  walking down the chain of controlling -> dependent objects. For example
235  a message targeted at a device and sent to a certificate would be routed
236  to the cert's dependent object (which would typically be a context).
237  The device message targeted at the context would in turn be routed to the
238  context's dependent device, which is its final destination */
239 
240 CHECK_RETVAL \
241 int findTargetType( IN_HANDLE const int originalObjectHandle,
242  const long targets )
243  {
244  const OBJECT_TYPE target = targets & 0xFF;
245  const OBJECT_TYPE altTarget1 = ( targets >> 8 ) & 0xFF;
246  const OBJECT_TYPE altTarget2 = ( targets >> 16 ) & 0xFF;
247  OBJECT_INFO *objectTable = krnlData->objectTable;
248  OBJECT_TYPE type = objectTable[ originalObjectHandle ].type;
249  int objectHandle = originalObjectHandle, iterations;
250 
251  /* Preconditions: Source is a valid object, destination(s) are valid
252  target(s) */
253  REQUIRES( isValidObject( objectHandle ) );
254  REQUIRES( isValidType( target ) );
255  REQUIRES( altTarget1 == OBJECT_TYPE_NONE || isValidType( altTarget1 ) );
256  REQUIRES( altTarget2 == OBJECT_TYPE_NONE || isValidType( altTarget2 ) );
257 
258  /* Route the request through any dependent objects as required until we
259  reach the required target object type. "And thou shalt make
260  loops..." -- Exodus 26:4 */
261  for( iterations = 0; \
262  iterations < 3 && isValidObject( objectHandle ) && \
263  !( target == type || \
264  ( altTarget1 != OBJECT_TYPE_NONE && altTarget1 == type ) || \
265  ( altTarget2 != OBJECT_TYPE_NONE && altTarget2 == type ) ); \
266  iterations++ )
267  {
268  /* Loop invariants. "Fifty loops thou shalt make" -- Exodus 26:5
269  (some of the OT verses shouldn't be taken too literally,
270  apparently the 50 used here merely means "many" as in "more than
271  one or two" in the same way that "40 days and nights" is now
272  generally taken as meaning "Lots, but that's as far as we're
273  prepared to count") */
274  ENSURES( isValidObject( objectHandle ) );
275  ENSURES( iterations < 3 );
276 
277  /* Find the next potential target object */
278  if( target == OBJECT_TYPE_DEVICE && \
279  objectTable[ objectHandle ].dependentDevice != CRYPT_ERROR )
280  objectHandle = objectTable[ objectHandle ].dependentDevice;
281  else
282  {
283  if( target == OBJECT_TYPE_USER )
284  {
285  /* If we've reached the system object (the parent of all
286  other objects) we can't go any further */
287  objectHandle = ( objectHandle != SYSTEM_OBJECT_HANDLE ) ? \
288  objectTable[ objectHandle ].owner : CRYPT_ERROR;
289  }
290  else
291  objectHandle = objectTable[ objectHandle ].dependentObject;
292  }
293  if( isValidObject( objectHandle ) )
294  type = objectTable[ objectHandle ].type;
295 
296  /* If we've got a new object, it has the same owner as the original
297  target candidate */
298  ENSURES( !isValidObject( objectHandle ) || \
299  isSameOwningObject( originalObjectHandle, objectHandle ) || \
300  objectTable[ originalObjectHandle ].owner == objectHandle );
301  }
302  ENSURES( iterations < 3 );
303 
304  /* Postcondition: We ran out of options or we reached the target object */
305  ENSURES( iterations < 3 );
306  ENSURES( objectHandle == CRYPT_ERROR || \
307  ( isValidObject( objectHandle ) && \
308  ( isSameOwningObject( originalObjectHandle, objectHandle ) || \
309  objectTable[ originalObjectHandle ].owner == objectHandle ) && \
310  ( target == type || \
311  ( altTarget1 != OBJECT_TYPE_NONE && altTarget1 == type ) || \
312  ( altTarget2 != OBJECT_TYPE_NONE && altTarget2 == type ) ) ) );
313 
314  return( isValidObject( objectHandle ) ? \
315  objectHandle : CRYPT_ARGERROR_OBJECT );
316  }
317 
318 /* Find the ultimate target of a compare message by walking down the chain
319  of controlling -> dependent objects. For example a message targeted at a
320  device and sent to a certificate would be routed to the cert's dependent
321  object (which would typically be a context). The device message targeted
322  at the context would be routed to the context's dependent device, which
323  is its final destination */
324 
325 CHECK_RETVAL \
326 static int routeCompareMessageTarget( IN_HANDLE const int originalObjectHandle,
328  const long messageValue )
329  {
331  int objectHandle = originalObjectHandle;
332 
333  /* Preconditions */
334  REQUIRES( isValidObject( objectHandle ) );
335  REQUIRES( messageValue == MESSAGE_COMPARE_HASH || \
336  messageValue == MESSAGE_COMPARE_ICV || \
337  messageValue == MESSAGE_COMPARE_KEYID || \
338  messageValue == MESSAGE_COMPARE_KEYID_PGP || \
339  messageValue == MESSAGE_COMPARE_KEYID_OPENPGP || \
340  messageValue == MESSAGE_COMPARE_SUBJECT || \
341  messageValue == MESSAGE_COMPARE_ISSUERANDSERIALNUMBER || \
342  messageValue == MESSAGE_COMPARE_FINGERPRINT_SHA1 || \
343  messageValue == MESSAGE_COMPARE_FINGERPRINT_SHA2 || \
344  messageValue == MESSAGE_COMPARE_FINGERPRINT_SHAng || \
345  messageValue == MESSAGE_COMPARE_CERTOBJ );
346 
347  /* Determine the ultimate target type for the message. We don't check for
348  keysets, envelopes and sessions as dependent objects since this never
349  occurs */
350  switch( messageValue )
351  {
353  case MESSAGE_COMPARE_ICV:
357  targetType = OBJECT_TYPE_CONTEXT;
358  break;
359 
366  targetType = OBJECT_TYPE_CERTIFICATE;
367  break;
368 
369  default:
370  retIntError();
371  }
372 
373  /* Route the message through to the appropriate object */
374  objectHandle = findTargetType( objectHandle, targetType );
375 
376  /* Postcondition */
377  ENSURES( objectHandle == CRYPT_ARGERROR_OBJECT || \
378  ( isValidObject( objectHandle ) && \
379  isSameOwningObject( originalObjectHandle, objectHandle ) ) );
380 
381  return( objectHandle );
382  }
383 
384 /****************************************************************************
385 * *
386 * Message Dispatch ACL *
387 * *
388 ****************************************************************************/
389 
390 /* Each message type has certain properties such as whether it's routable,
391  which object types it applies to, what checks are performed on it, whether
392  it's processed by the kernel or dispatched to an object, etc etc. These
393  are all defined in the following table.
394 
395  In addition to the usual checks, we also make various assertions about the
396  parameters we're passed. Note that these don't check user data (that's
397  checked programmatically and an error code returned) but values passed by
398  cryptlib code */
399 
400 typedef enum {
401  PARAMTYPE_NONE_NONE, /* Data = 0, value = 0 */
402  PARAMTYPE_NONE_ANY, /* Data = 0, value = any */
403  PARAMTYPE_NONE_BOOLEAN, /* Data = 0, value = boolean */
404  PARAMTYPE_NONE_CHECKTYPE,/* Data = 0, value = check type */
405  PARAMTYPE_DATA_NONE, /* Data, value = 0 */
406  PARAMTYPE_DATA_ANY, /* Data, value = any */
407  PARAMTYPE_DATA_LENGTH, /* Data, value >= 0 */
408  PARAMTYPE_DATA_OBJTYPE, /* Data, value = object type */
409  PARAMTYPE_DATA_MECHTYPE,/* Data, value = mechanism type */
410  PARAMTYPE_DATA_ITEMTYPE,/* Data, value = keymgmt.item type */
411  PARAMTYPE_DATA_FORMATTYPE,/* Data, value = cert format type */
412  PARAMTYPE_DATA_COMPARETYPE,/* Data, value = compare type */
413  PARAMTYPE_DATA_SETDEPTYPE,/* Data, value = setdep.option type */
414  PARAMTYPE_DATA_CERTMGMTTYPE,/* Data, value = cert.mgmt.type */
415  PARAMTYPE_ANY_USERMGMTTYPE,/* Data = any, value = user mgmt.type */
416  PARAMTYPE_ANY_TRUSTMGMTTYPE,/* Data = any, value = trust mgmt.type */
417  PARAMTYPE_LAST /* Last possible parameter check type */
418  } PARAMCHECK_TYPE;
419 
420 /* Symbolic defines for message handling types, used to make it clearer
421  what's going on
422 
423  PRE_DISPATCH - Action before message is dispatched
424  POST_DISPATCH - Action after message is dispatched
425  HANDLE_INTERNAL - Message handled by the kernel */
426 
427 #define PRE_DISPATCH( function ) preDispatch##function, NULL
428 #define POST_DISPATCH( function ) NULL, postDispatch##function
429 #define PRE_POST_DISPATCH( preFunction, postFunction ) \
430  preDispatch##preFunction, postDispatch##postFunction
431 #define HANDLE_INTERNAL( function ) NULL, NULL, MESSAGE_HANDLING_FLAG_INTERNAL, function
432 
433 /* Flags to indicate (potential) special-case handling for a message. These
434  are:
435 
436  FLAG_INTERNAL: The message is handled internally by the kernel rather
437  than being sent to an external handler.
438 
439  FLAG_MAYUNLOCK: The message handler may unlock the object (via
440  krnlReleaseObject()) to allow other threads access. In this
441  case the first parameter to the handler function should be a
442  MESSAGE_FUNCTION_EXTINFO structure to contain unlocking
443  information */
444 
445 #define MESSAGE_HANDLING_FLAG_NONE 0 /* No special handling */
446 #define MESSAGE_HANDLING_FLAG_MAYUNLOCK 1 /* Handler may unlock object */
447 #define MESSAGE_HANDLING_FLAG_INTERNAL 2 /* Message handle by kernel */
448 
449 /* The handling information, declared in the order in which it's applied */
450 
451 typedef struct {
452  /* The message type, used for consistency checking */
454 
455  /* Message routing information if the message is routable. If the target
456  is implicitly determined via the message value, the routing target is
457  OBJECT_TYPE_NONE; if the target is explicitly determined, the routing
458  target is identified in the target. If the routing function is null,
459  the message isn't routed */
460  const long routingTarget; /* Target type if routable */
461  int ( *routingFunction )( const int objectHandle, const long arg );
462 
463  /* Object type checking information: Object subtypes for which this
464  message is valid (for object-type-specific message) */
465  const OBJECT_SUBTYPE subTypeA, subTypeB, subTypeC;
466  /* Object subtype for which msg.valid */
467 
468  /* Message type checking information used to assertion-check the function
469  preconditions */
470  const PARAMCHECK_TYPE paramCheck; /* Parameter check assertion type */
471 
472  /* Pre- and post-message-dispatch handlers. These perform any additional
473  checking and processing that may be necessary before and after a
474  message is dispatched to an object */
475  int ( *preDispatchFunction )( const int objectHandle,
476  const MESSAGE_TYPE message,
477  const void *messageDataPtr,
478  const int messageValue, const void *auxInfo );
479  int ( *postDispatchFunction )( const int objectHandle,
480  const MESSAGE_TYPE message,
481  const void *messageDataPtr,
482  const int messageValue, const void *auxInfo );
483 
484  /* Flags to indicate (potential) special-case handling for this message,
485  and the (optional) internal handler function that's used if the
486  message is handled directly by the kernel */
487  int flags; /* Special-case handling flags */
488  int ( *internalHandlerFunction )( const int objectHandle, const int arg1,
489  const void *arg2,
490  const BOOLEAN isInternal );
492 
493 static const MESSAGE_HANDLING_INFO FAR_BSS messageHandlingInfo[] = {
495 
496  /* Control messages. These messages aren't routed, are valid for all
497  object types and subtypes, take no (or minimal) parameters, and are
498  handled by the kernel */
499  { MESSAGE_DESTROY, /* Destroy the object */
502  PRE_DISPATCH( SignalDependentObjects ) },
503  { MESSAGE_INCREFCOUNT, /* Increment object ref.count */
507  { MESSAGE_DECREFCOUNT, /* Decrement object ref.count */
511  { MESSAGE_GETDEPENDENT, /* Get dependent object */
514  HANDLE_INTERNAL( getDependentObject ) },
515  { MESSAGE_SETDEPENDENT, /* Set dependent object (e.g. ctx->dev) */
518  HANDLE_INTERNAL( setDependentObject ) },
519  { MESSAGE_CLONE, /* Clone the object (only valid for ctxs) */
523 
524  /* Attribute messages. These messages are implicitly routed by attribute
525  type, more specific checking is performed using the attribute ACL's */
526  { MESSAGE_GETATTRIBUTE, /* Get numeric object attribute */
529  PRE_POST_DISPATCH( CheckAttributeAccess, MakeObjectExternal ) },
530  { MESSAGE_GETATTRIBUTE_S, /* Get string object attribute */
533  PRE_DISPATCH( CheckAttributeAccess ) },
534  { MESSAGE_SETATTRIBUTE, /* Set numeric object attribute */
537  PRE_POST_DISPATCH( CheckAttributeAccess, ChangeStateOpt ) },
538  { MESSAGE_SETATTRIBUTE_S, /* Set string object attribute */
541  PRE_POST_DISPATCH( CheckAttributeAccess, ChangeStateOpt ) },
542  { MESSAGE_DELETEATTRIBUTE, /* Delete object attribute */
545  PRE_DISPATCH( CheckAttributeAccess ) },
546 
547  /* General messages to objects */
548  { MESSAGE_COMPARE, /* Compare objs.or obj.properties */
549  ROUTE_SPECIAL( CompareMessageTarget ), ST_CTX_ANY | ST_CERT_ANY, ST_NONE, ST_NONE,
551  PRE_DISPATCH( CheckCompareParam ) },
552  { MESSAGE_CHECK, /* Check object info */
555  PRE_POST_DISPATCH( CheckCheckParam, ForwardToDependentObject ) },
556  { MESSAGE_SELFTEST, /* Perform a self-test */
559  NULL, NULL,
561 
562  /* Messages sent from the kernel to object message handlers. These
563  messages are sent directly to the object from inside the kernel in
564  response to a control message, so we set the checking to disallow
565  everything to catch any that arrive from outside */
566  { MESSAGE_CHANGENOTIFY, /* Notification of obj.status chge.*/
568 
569  /* Object-type-specific messages: Contexts */
570  { MESSAGE_CTX_ENCRYPT, /* Context: Action = encrypt */
573  PRE_POST_DISPATCH( CheckActionAccess, UpdateUsageCount ) },
574  { MESSAGE_CTX_DECRYPT, /* Context: Action = decrypt */
577  PRE_POST_DISPATCH( CheckActionAccess, UpdateUsageCount ) },
578  { MESSAGE_CTX_SIGN, /* Context: Action = sign */
581  PRE_POST_DISPATCH( CheckActionAccess, UpdateUsageCount ) },
582  { MESSAGE_CTX_SIGCHECK, /* Context: Action = sigcheck */
585  PRE_POST_DISPATCH( CheckActionAccess, UpdateUsageCount ) },
586  { MESSAGE_CTX_HASH, /* Context: Action = hash */
589  PRE_POST_DISPATCH( CheckActionAccess, UpdateUsageCount ) },
590  { MESSAGE_CTX_GENKEY, /* Context: Generate a key */
594  PRE_POST_DISPATCH( CheckState, ChangeState ) },
595  { MESSAGE_CTX_GENIV, /* Context: Generate an IV */
598 
599  /* Object-type-specific messages: Certificates */
600  { MESSAGE_CRT_SIGN, /* Cert: Action = sign cert */
603  ST_CERT_OCSP_REQ | ST_CERT_OCSP_RESP, ST_NONE, ST_NONE,
605  PRE_POST_DISPATCH( CheckStateParamHandle, ChangeState ) },
606  { MESSAGE_CRT_SIGCHECK, /* Cert: Action = check/verify cert */
609  ST_CERT_RTCS_RESP | ST_CERT_OCSP_RESP, ST_NONE, ST_NONE,
611  PRE_DISPATCH( CheckParamHandleOpt ) },
612  { MESSAGE_CRT_EXPORT, /* Cert: Export encoded cert data */
615  PRE_DISPATCH( CheckExportAccess ) },
616 
617  /* Object-type-specific messages: Devices */
618  { MESSAGE_DEV_QUERYCAPABILITY, /* Device: Query capability */
621  { MESSAGE_DEV_EXPORT, /* Device: Action = export key */
624  PRE_DISPATCH( CheckMechanismWrapAccess ),
626  { MESSAGE_DEV_IMPORT, /* Device: Action = import key */
629  PRE_DISPATCH( CheckMechanismWrapAccess ),
631  { MESSAGE_DEV_SIGN, /* Device: Action = sign */
634  PRE_DISPATCH( CheckMechanismSignAccess ),
636  { MESSAGE_DEV_SIGCHECK, /* Device: Action = sig.check */
639  PRE_DISPATCH( CheckMechanismSignAccess ),
641  { MESSAGE_DEV_DERIVE, /* Device: Action = derive key */
644  PRE_DISPATCH( CheckMechanismDeriveAccess ),
646  { MESSAGE_DEV_KDF, /* Device: Action = KDF key */
649  PRE_DISPATCH( CheckMechanismKDFAccess ),
651  { MESSAGE_DEV_CREATEOBJECT, /* Device: Create object */
654  PRE_POST_DISPATCH( CheckCreate, MakeObjectExternal ),
656  { MESSAGE_DEV_CREATEOBJECT_INDIRECT,/* Device: Create obj.from data */
659  PRE_POST_DISPATCH( CheckCreate, MakeObjectExternal ),
661 
662  /* Object-type-specific messages: Envelopes */
663  { MESSAGE_ENV_PUSHDATA, /* Envelope: Push data */
667  PRE_DISPATCH( CheckData ) },
668  { MESSAGE_ENV_POPDATA, /* Envelope: Pop data */
672  PRE_DISPATCH( CheckData ) },
673 
674  /* Object-type-specific messages: Keysets */
675  { MESSAGE_KEY_GETKEY, /* Keyset: Instantiate ctx/cert */
679  PRE_POST_DISPATCH( CheckKeysetAccess, MakeObjectExternal ) },
680  { MESSAGE_KEY_SETKEY, /* Keyset: Add ctx/cert */
684  PRE_DISPATCH( CheckKeysetAccess ) },
685  { MESSAGE_KEY_DELETEKEY, /* Keyset: Delete key */
689  PRE_DISPATCH( CheckKeysetAccess ) },
690  { MESSAGE_KEY_GETFIRSTCERT, /* Keyset: Get first cert in sequence */
694  PRE_DISPATCH( CheckKeysetAccess ) },
695  { MESSAGE_KEY_GETNEXTCERT, /* Keyset: Get next cert in sequence */
699  PRE_POST_DISPATCH( CheckKeysetAccess, MakeObjectExternal ) },
700  { MESSAGE_KEY_CERTMGMT, /* Keyset: Cert management */
704  PRE_POST_DISPATCH( CheckCertMgmtAccess, MakeObjectExternal ) },
705 
706  /* Object-type-specific messages: Users */
707  { MESSAGE_USER_USERMGMT, /* User: User management */
710  PRE_POST_DISPATCH( CheckUserMgmtAccess, HandleZeroise ) },
711  { MESSAGE_USER_TRUSTMGMT, /* User: Trust management */
714  PRE_DISPATCH( CheckTrustMgmtAccess ) },
715 
716  /* End-of-ACL marker */
719  };
720 
721 /* Check the basic validity of message parameters. Note that this only
722  checks for coding errors (krnlSendMessage() having been called
723  correctly), it doesn't perform parameter validation, which is the
724  job of the full ACL checks */
725 
727 static BOOLEAN checkParams( IN_ENUM( PARAMCHECK ) \
728  const PARAMCHECK_TYPE paramCheck,
729  const void *messageDataPtr,
730  const int messageValue )
731  {
732  REQUIRES_B( paramCheck >= PARAMTYPE_NONE_NONE && \
733  paramCheck < PARAMTYPE_LAST );
734 
735  switch( paramCheck )
736  {
737  case PARAMTYPE_NONE_NONE:
738  return( messageDataPtr == NULL && messageValue == 0 );
739 
740  case PARAMTYPE_NONE_ANY:
741  return( messageDataPtr == NULL );
742 
744  return( messageDataPtr == NULL && \
745  ( messageValue == FALSE || messageValue == TRUE ) );
746 
748  return( messageDataPtr == NULL && \
749  ( messageValue > MESSAGE_CHECK_NONE && \
750  messageValue < MESSAGE_CHECK_LAST ) );
751 
752  case PARAMTYPE_DATA_NONE:
753  return( messageDataPtr != NULL && messageValue == 0 );
754 
755  case PARAMTYPE_DATA_ANY:
756  return( messageDataPtr != NULL );
757 
759  return( messageDataPtr != NULL && messageValue >= 0 );
760 
762  return( messageDataPtr != NULL && \
763  ( messageValue > OBJECT_TYPE_NONE && \
764  messageValue < OBJECT_TYPE_LAST ) );
765 
767  return( messageDataPtr != NULL && \
768  ( messageValue > MECHANISM_NONE && \
769  messageValue < MECHANISM_LAST ) );
770 
772  return( messageDataPtr != NULL && \
773  ( messageValue > KEYMGMT_ITEM_NONE && \
774  messageValue < KEYMGMT_ITEM_LAST ) );
775 
777  return( messageDataPtr != NULL && \
778  ( messageValue > CRYPT_CERTFORMAT_NONE && \
779  messageValue < CRYPT_CERTFORMAT_LAST ) );
780 
782  return( messageDataPtr != NULL && \
783  ( messageValue > MESSAGE_COMPARE_NONE && \
784  messageValue < MESSAGE_COMPARE_LAST ) );
785 
787  return( messageDataPtr != NULL && \
788  messageValue > SETDEP_OPTION_NONE && \
789  messageValue < SETDEP_OPTION_LAST );
790 
792  return( messageDataPtr != NULL && \
793  messageValue > CRYPT_CERTACTION_NONE && \
794  messageValue < CRYPT_CERTACTION_LAST );
795 
797  return( messageValue > MESSAGE_USERMGMT_NONE && \
798  messageValue < MESSAGE_USERMGMT_LAST );
799 
801  return( messageValue > MESSAGE_TRUSTMGMT_NONE && \
802  messageValue < MESSAGE_TRUSTMGMT_LAST );
803 
804  default:
806  }
807 
809  }
810 
811 /****************************************************************************
812 * *
813 * Init/Shutdown Functions *
814 * *
815 ****************************************************************************/
816 
818 int initSendMessage( INOUT KERNEL_DATA *krnlDataPtr )
819  {
820  int i;
821 
822  assert( isWritePtr( krnlDataPtr, sizeof( KERNEL_DATA ) ) );
823 
824  /* Perform a consistency check on various things that need to be set
825  up in a certain way for things to work properly */
827  "Message value" );
829  "Message value" );
831  "Message value" );
833  "Message value" );
835  "Message value" );
837  "Message value" );
839  "Message value" );
841  "Message value" );
843  "Message value" );
844 
845  /* Perform a consistency check on various internal values and constants */
846  assert( ACTION_PERM_COUNT == 6 );
847 
848  /* Perform a consistency check on the parameter ACL */
849  for( i = 0; messageParamACLTbl[ i ].type != MESSAGE_NONE && \
850  i < FAILSAFE_ARRAYSIZE( messageParamACLTbl, MESSAGE_ACL );
851  i++ )
852  {
853  const MESSAGE_ACL *messageParamACL = &messageParamACLTbl[ i ];
854 
855  ENSURES( isParamMessage( messageParamACL->type ) && \
856  !( messageParamACL->objectACL.subTypeA & ( SUBTYPE_CLASS_B | \
857  SUBTYPE_CLASS_C ) ) && \
858  !( messageParamACL->objectACL.subTypeB & ( SUBTYPE_CLASS_A | \
859  SUBTYPE_CLASS_C ) ) && \
860  !( messageParamACL->objectACL.subTypeC & ( SUBTYPE_CLASS_A | \
861  SUBTYPE_CLASS_B ) ) );
862  }
863  ENSURES( i < FAILSAFE_ARRAYSIZE( messageParamACLTbl, MESSAGE_ACL ) );
864 
865  /* Perform a consistency check on the message handling information */
866  for( i = MESSAGE_NONE + 1; i < MESSAGE_LAST; i++ )
867  {
868  const MESSAGE_HANDLING_INFO *messageInfo = &messageHandlingInfo[ i ];
869 
870  ENSURES( messageInfo->messageType == i && \
871  messageInfo->paramCheck >= PARAMTYPE_NONE_NONE && \
872  messageInfo->paramCheck < PARAMTYPE_LAST );
873  ENSURES( ( messageInfo->messageType >= MESSAGE_ENV_PUSHDATA && \
874  messageInfo->messageType <= MESSAGE_KEY_GETNEXTCERT ) || \
875  ( messageInfo->routingTarget >= OBJECT_TYPE_NONE && \
876  messageInfo->routingTarget <= OBJECT_TYPE_LAST ) );
877  ENSURES( messageInfo->messageType == MESSAGE_CLONE || \
878  messageInfo->messageType == MESSAGE_COMPARE || \
879  ( messageInfo->routingTarget == OBJECT_TYPE_NONE && \
880  messageInfo->routingFunction == NULL ) || \
881  ( messageInfo->routingTarget != OBJECT_TYPE_NONE && \
882  messageInfo->routingFunction != NULL ) );
883  ENSURES( !( messageInfo->subTypeA & ( SUBTYPE_CLASS_B | \
884  SUBTYPE_CLASS_C ) ) && \
885  !( messageInfo->subTypeB & ( SUBTYPE_CLASS_A | \
886  SUBTYPE_CLASS_C ) ) && \
887  !( messageInfo->subTypeC & ( SUBTYPE_CLASS_A | \
888  SUBTYPE_CLASS_B ) ) );
889  ENSURES( ( messageInfo->flags & MESSAGE_HANDLING_FLAG_INTERNAL ) || \
890  messageInfo->messageType == MESSAGE_SELFTEST || \
891  messageInfo->messageType == MESSAGE_CHANGENOTIFY || \
892  messageInfo->messageType == MESSAGE_CTX_GENIV || \
893  messageInfo->messageType == MESSAGE_DEV_QUERYCAPABILITY || \
894  messageInfo->preDispatchFunction != NULL );
895  ENSURES( messageInfo->messageType == MESSAGE_SELFTEST || \
896  messageInfo->messageType == MESSAGE_CHANGENOTIFY || \
897  messageInfo->messageType == MESSAGE_CTX_GENIV || \
898  messageInfo->messageType == MESSAGE_DEV_QUERYCAPABILITY || \
899  ( messageInfo->preDispatchFunction != NULL || \
900  messageInfo->postDispatchFunction != NULL || \
901  messageInfo->internalHandlerFunction != NULL ) );
902  ENSURES( ( ( messageInfo->flags & MESSAGE_HANDLING_FLAG_INTERNAL ) && \
903  messageInfo->internalHandlerFunction != NULL ) || \
904  ( !( messageInfo->flags & MESSAGE_HANDLING_FLAG_INTERNAL ) && \
905  messageInfo->internalHandlerFunction == NULL ) );
906  }
907 
908  /* Set up the reference to the kernel data block */
909  krnlData = krnlDataPtr;
910 
911  return( CRYPT_OK );
912  }
913 
914 void endSendMessage( void )
915  {
916  krnlData = NULL;
917  }
918 
919 /****************************************************************************
920 * *
921 * Message Queue *
922 * *
923 ****************************************************************************/
924 
925 /* Enqueue a message */
926 
928 static int enqueueMessage( IN_HANDLE const int objectHandle,
929  const MESSAGE_HANDLING_INFO *handlingInfoPtr,
930  IN_MESSAGE const MESSAGE_TYPE message,
931  IN_OPT const void *messageDataPtr,
932  const int messageValue )
933  {
934  MESSAGE_QUEUE_DATA *messageQueue = krnlData->messageQueue;
935  int queuePos, i, iterationCount;
936  ORIGINAL_INT_VAR( queueEnd, krnlData->queueEnd );
937 
938  assert( isReadPtr( handlingInfoPtr, sizeof( MESSAGE_HANDLING_INFO ) ) );
939 
940  /* Precondition: It's a valid message being sent to a valid object */
941  REQUIRES( isValidObject( objectHandle ) );
942  REQUIRES( isValidMessage( message & MESSAGE_MASK ) );
943 
944  /* Sanity-check the state/make sure that we don't overflow the queue
945  (this object is not responding to messages... now all we need is
946  GPF's). We return a timeout error on overflow to indicate that there
947  are too many messages queued for this (or other) objects */
948  if( krnlData->queueEnd < 0 || \
949  krnlData->queueEnd >= MESSAGE_QUEUE_SIZE - 1 )
950  {
951  ENSURES( krnlData->queueEnd >= 0 );
952  DEBUG_DIAG(( "Invalid kernel message queue state" ));
953  assert( DEBUG_WARN );
954  return( CRYPT_ERROR_TIMEOUT );
955  }
956 
957  /* Precondition: There's room to enqueue the message */
958  REQUIRES( krnlData->queueEnd >= 0 && \
959  krnlData->queueEnd < MESSAGE_QUEUE_SIZE - 1 );
960 
961  /* Check whether a message to this object is already present in the
962  queue */
963  for( queuePos = krnlData->queueEnd - 1, iterationCount = 0;
964  queuePos >= 0 && iterationCount++ < MESSAGE_QUEUE_SIZE; queuePos-- )
965  {
966  if( messageQueue[ queuePos ].objectHandle == objectHandle )
967  break;
968  }
969  ENSURES( iterationCount < MESSAGE_QUEUE_SIZE );
970 
971  /* Postcondition: queuePos = -1 if not present, position in queue if
972  present */
973  ENSURES( queuePos == -1 || \
974  ( queuePos >= 0 && queuePos < krnlData->queueEnd ) );
975 
976  /* Sanity-check the queue positioning */
977  ENSURES( queuePos >= -1 && queuePos < krnlData->queueEnd );
978 
979  /* Enqueue the message:
980 
981  +---------------+ +---------------+
982  |.|.|x|x|y|z| | -> |.|.|x|x|#|y|z| |
983  +---------------+ +---------------+
984  ^ ^ ^ ^
985  qPos qEnd qPos qEnd */
986  queuePos++; /* Insert after current position */
987  for( i = krnlData->queueEnd - 1, iterationCount = 0;
988  i >= queuePos && iterationCount < MESSAGE_QUEUE_SIZE;
989  i--, iterationCount++ )
990  messageQueue[ i + 1 ] = messageQueue[ i ];
991  ENSURES( iterationCount < MESSAGE_QUEUE_SIZE );
992  memset( &messageQueue[ queuePos ], 0, sizeof( MESSAGE_QUEUE_DATA ) );
993  messageQueue[ queuePos ].objectHandle = objectHandle;
994  messageQueue[ queuePos ].handlingInfoPtr = handlingInfoPtr;
995  messageQueue[ queuePos ].message = message;
996  messageQueue[ queuePos ].messageDataPtr = messageDataPtr;
997  messageQueue[ queuePos ].messageValue = messageValue;
998  krnlData->queueEnd++;
999 
1000  /* Postcondition: The queue is within bounds and has grown by one
1001  element */
1002  ENSURES( krnlData->queueEnd > 0 && \
1003  krnlData->queueEnd <= MESSAGE_QUEUE_SIZE - 1 );
1004  ENSURES( krnlData->queueEnd == ORIGINAL_VALUE( queueEnd ) + 1 );
1005 
1006  /* If a message for this object is already present tell the caller to
1007  defer processing */
1008  if( queuePos > 0 )
1009  return( OK_SPECIAL );
1010 
1011  return( CRYPT_OK );
1012  }
1013 
1014 /* Dequeue a message */
1015 
1016 CHECK_RETVAL \
1017 static int dequeueMessage( IN_RANGE( 0, MESSAGE_QUEUE_SIZE ) \
1018  const int messagePosition )
1019  {
1020  MESSAGE_QUEUE_DATA *messageQueue = krnlData->messageQueue;
1021  int i, iterationCount;
1022  ORIGINAL_INT_VAR( queueEnd, krnlData->queueEnd );
1023 
1024  /* Precondition: We're deleting a valid queue position */
1025  REQUIRES( messagePosition >= 0 && \
1026  messagePosition < krnlData->queueEnd );
1027  REQUIRES( krnlData->queueEnd > 0 && \
1028  krnlData->queueEnd < MESSAGE_QUEUE_SIZE );
1029 
1030  /* Move the remaining messages down and clear the last entry */
1031  for( i = messagePosition, iterationCount = 0;
1032  i < krnlData->queueEnd - 1 && \
1033  iterationCount++ < MESSAGE_QUEUE_SIZE; i++ )
1034  messageQueue[ i ] = messageQueue[ i + 1 ];
1035  ENSURES( iterationCount < MESSAGE_QUEUE_SIZE );
1036  zeroise( &messageQueue[ krnlData->queueEnd - 1 ],
1037  sizeof( MESSAGE_QUEUE_DATA ) );
1038  krnlData->queueEnd--;
1039 
1040  /* Postcondition: the queue is one element shorter, all queue entries
1041  are valid, and all non-queue entries are empty */
1042  ENSURES( krnlData->queueEnd == ORIGINAL_VALUE( queueEnd ) - 1 );
1043  ENSURES( krnlData->queueEnd >= 0 && \
1044  krnlData->queueEnd < MESSAGE_QUEUE_SIZE - 1 );
1045  FORALL( i, 0, krnlData->queueEnd,
1046  messageQueue[ i ].handlingInfoPtr != NULL );
1047  FORALL( i, krnlData->queueEnd, MESSAGE_QUEUE_SIZE,
1048  messageQueue[ i ].handlingInfoPtr == NULL );
1049 
1050  return( CRYPT_OK );
1051  }
1052 
1053 /* Get the next message in the queue */
1054 
1055 CHECK_RETVAL \
1056 static BOOLEAN getNextMessage( IN_HANDLE const int objectHandle,
1057  OUT_OPT MESSAGE_QUEUE_DATA *messageQueueInfo )
1058  {
1059  MESSAGE_QUEUE_DATA *messageQueue = krnlData->messageQueue;
1060  int i;
1061 
1062  assert( messageQueueInfo == NULL || \
1063  isWritePtr( messageQueueInfo, sizeof( MESSAGE_QUEUE_DATA ) ) );
1064 
1065  /* Preconditions: It's a valid object table entry. It's not necessarily
1066  a valid object since we may be de-queueing messages for it because
1067  it's just been destroyed */
1068  REQUIRES_B( objectHandle == SYSTEM_OBJECT_HANDLE || \
1069  objectHandle == DEFAULTUSER_OBJECT_HANDLE || \
1070  isHandleRangeValid( objectHandle ) );
1071 
1072  /* Clear return value */
1073  if( messageQueueInfo != NULL )
1074  memset( messageQueueInfo, 0, sizeof( MESSAGE_QUEUE_DATA ) );
1075 
1076  /* Sanity-check the state */
1077  ENSURES_B( krnlData->queueEnd >= 0 && \
1078  krnlData->queueEnd < MESSAGE_QUEUE_SIZE );
1079 
1080  /* Find the next message for this object. Since other messages can have
1081  come and gone in the meantime, we have to scan from the start each
1082  time */
1083  for( i = 0; i < krnlData->queueEnd && i < MESSAGE_QUEUE_SIZE; i++ )
1084  {
1085  if( messageQueue[ i ].objectHandle == objectHandle )
1086  {
1087  int status;
1088 
1089  if( messageQueueInfo != NULL )
1090  *messageQueueInfo = messageQueue[ i ];
1091  status = dequeueMessage( i );
1092  if( cryptStatusError( status ) )
1093  return( FALSE );
1094 
1095  return( TRUE );
1096  }
1097  }
1098  ENSURES_B( i < MESSAGE_QUEUE_SIZE );
1099 
1100  /* Postcondition: There are no more messages for this object present in
1101  the queue */
1102  FORALL( i, 0, krnlData->queueEnd,
1103  messageQueue[ i ].objectHandle != objectHandle );
1104 
1105  return( FALSE );
1106  }
1107 
1108 /* Dequeue all messages for an object in the queue */
1109 
1110 static void dequeueAllMessages( IN_HANDLE const int objectHandle )
1111  {
1112  int iterationCount;
1113 
1114  /* Preconditions: It's a valid object table entry. It's not necessarily
1115  a valid object since we may be de-queueing messages for it because
1116  it's just been destroyed */
1117  REQUIRES_V( objectHandle == SYSTEM_OBJECT_HANDLE || \
1118  objectHandle == DEFAULTUSER_OBJECT_HANDLE || \
1119  isHandleRangeValid( objectHandle ) );
1120 
1121  /* Dequeue all messages for a given object */
1122  for( iterationCount = 0;
1123  getNextMessage( objectHandle, NULL ) && \
1124  iterationCount < MESSAGE_QUEUE_SIZE;
1125  iterationCount++ );
1126  ENSURES_V( iterationCount < MESSAGE_QUEUE_SIZE );
1127 
1128  /* Postcondition: There are no more messages for this object present in
1129  the queue */
1130  FORALL( i, 0, krnlData->queueEnd,
1131  krnlData->messageQueue[ i ].objectHandle != objectHandle );
1132  }
1133 
1134 /****************************************************************************
1135 * *
1136 * Message Dispatcher *
1137 * *
1138 ****************************************************************************/
1139 
1140 /* Process a message that's handled internally by the kernel, for example
1141  one that accesses an object's kernel attributes */
1142 
1143 CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
1144 static int processInternalMessage( IN_HANDLE const int localObjectHandle,
1145  const MESSAGE_HANDLING_INFO *handlingInfoPtr,
1146  IN_MESSAGE const MESSAGE_TYPE message,
1147  IN_OPT void *messageDataPtr,
1148  const int messageValue,
1149  IN_OPT const void *aclPtr )
1150  {
1151  int status;
1152 
1153  assert( isReadPtr( handlingInfoPtr, sizeof( MESSAGE_HANDLING_INFO ) ) );
1154 
1155  /* Precondition: It's a valid message being sent to a valid object */
1156  REQUIRES( isValidObject( localObjectHandle ) );
1157  REQUIRES( isValidMessage( message & MESSAGE_MASK ) );
1158 
1159  /* If there's a pre-dispatch handler, invoke it */
1160  if( handlingInfoPtr->preDispatchFunction != NULL )
1161  {
1162  status = handlingInfoPtr->preDispatchFunction( localObjectHandle,
1163  message, messageDataPtr, messageValue,
1164  aclPtr );
1165  if( cryptStatusError( status ) )
1166  return( status );
1167  }
1168 
1169  /* Inner precondition: Either the message as a whole is internally
1170  handled or it's a property attribute */
1171  REQUIRES( handlingInfoPtr->internalHandlerFunction != NULL || \
1172  isAttributeMessage( message & MESSAGE_MASK ) );
1173 
1174  /* If it's an object property attribute (which is handled by the kernel),
1175  get or set its value */
1176  if( handlingInfoPtr->internalHandlerFunction == NULL )
1177  {
1178  /* Precondition: Object properties are always numeric attributes,
1179  and there's always a message value present */
1180  REQUIRES( handlingInfoPtr->messageType == MESSAGE_GETATTRIBUTE || \
1181  handlingInfoPtr->messageType == MESSAGE_SETATTRIBUTE );
1182  REQUIRES( messageDataPtr != NULL );
1183 
1184  if( handlingInfoPtr->messageType == MESSAGE_GETATTRIBUTE )
1185  status = getPropertyAttribute( localObjectHandle, messageValue,
1186  messageDataPtr );
1187  else
1188  status = setPropertyAttribute( localObjectHandle, messageValue,
1189  messageDataPtr );
1190  }
1191  else
1192  {
1193  /* It's a kernel-handled message, process it */
1194  status = handlingInfoPtr->internalHandlerFunction( localObjectHandle,
1195  messageValue, messageDataPtr,
1196  isInternalMessage( message ) );
1197  }
1198  if( cryptStatusError( status ) )
1199  {
1200  /* Postcondition: It's a genuine error, or a special-case condition
1201  such as the object creation being aborted, which produces an
1202  OK_SPECIAL status to tell the caller to convert the message that
1203  triggered this into a MESSAGE_DESTROY */
1204  ENSURES( cryptStatusError( status ) || status == OK_SPECIAL );
1205 
1206  return( status );
1207  }
1208 
1209  /* If there's a post-dispatch handler, invoke it */
1210  if( handlingInfoPtr->postDispatchFunction != NULL )
1211  {
1212  status = handlingInfoPtr->postDispatchFunction( localObjectHandle,
1213  message, messageDataPtr, messageValue,
1214  aclPtr );
1215  if( cryptStatusError( status ) )
1216  return( status );
1217  }
1218 
1219  return( CRYPT_OK );
1220  }
1221 
1222 /* Dispatch a message to an object */
1223 
1225 static int dispatchMessage( IN_HANDLE const int localObjectHandle,
1226  const MESSAGE_QUEUE_DATA *messageQueueData,
1227  INOUT OBJECT_INFO *objectInfoPtr,
1228  IN_OPT const void *aclPtr )
1229  {
1230  const MESSAGE_HANDLING_INFO *handlingInfoPtr = \
1231  messageQueueData->handlingInfoPtr;
1232  const MESSAGE_FUNCTION messageFunction = objectInfoPtr->messageFunction;
1233  const MESSAGE_TYPE localMessage = messageQueueData->message & MESSAGE_MASK;
1235  void *objectPtr = objectInfoPtr->objectPtr;
1236  BOOLEAN mayUnlock = FALSE;
1237  int status;
1238  ORIGINAL_INT_VAR( lockCount, objectInfoPtr->lockCount );
1239 
1240  assert( isReadPtr( messageQueueData, sizeof( MESSAGE_QUEUE_DATA ) ) );
1241  assert( isWritePtr( objectInfoPtr, sizeof( OBJECT_INFO ) ) );
1242 
1243  REQUIRES( isValidObject( localObjectHandle ) );
1244  REQUIRES( !isInUse( localObjectHandle ) || \
1245  isObjectOwner( localObjectHandle ) );
1246  REQUIRES( messageFunction != NULL );
1247 
1248  /* If there's a pre-dispatch handler present, apply it */
1249  if( handlingInfoPtr->preDispatchFunction != NULL )
1250  {
1251  status = handlingInfoPtr->preDispatchFunction( localObjectHandle,
1252  messageQueueData->message,
1253  messageQueueData->messageDataPtr,
1254  messageQueueData->messageValue,
1255  aclPtr );
1256  if( cryptStatusError( status ) )
1257  return( status );
1258  }
1259 
1260  /* Some objects (generally the system object and to a lesser extent other
1261  devices and the default user object) may unlock themselves while
1262  processing a message when they forward the message elsewhere or perform
1263  non-object-specific processing. If this may be the case then we pass
1264  in an extended message structure to record this information */
1265  initMessageExtInfo( &messageExtInfo, objectPtr );
1266  if( ( objectInfoPtr->type == OBJECT_TYPE_DEVICE ) || \
1267  ( handlingInfoPtr->flags & MESSAGE_HANDLING_FLAG_MAYUNLOCK ) )
1268  {
1269  mayUnlock = TRUE;
1270  objectPtr = &messageExtInfo;
1271  }
1272 
1273  /* Mark the object as busy so that we have it available for our
1274  exclusive use and further messages to it will be enqueued, dispatch
1275  the message with the object table unlocked, and mark the object as
1276  non-busy again */
1277  objectInfoPtr->lockCount++;
1278 #ifdef USE_THREADS
1279  objectInfoPtr->lockOwner = THREAD_SELF();
1280 #endif /* USE_THREADS */
1281  MUTEX_UNLOCK( objectTable );
1282  status = messageFunction( objectPtr, localMessage,
1283  ( MESSAGE_CAST ) messageQueueData->messageDataPtr,
1284  messageQueueData->messageValue );
1285  MUTEX_LOCK( objectTable );
1286  objectInfoPtr = &krnlData->objectTable[ localObjectHandle ];
1287  if( !isValidType( objectInfoPtr->type ) )
1288  retIntError(); /* Something catastrophic happened while unlocked */
1289  if( !( mayUnlock && isMessageObjectUnlocked( &messageExtInfo ) ) )
1290  objectInfoPtr->lockCount--;
1291 
1292  /* Postcondition: The lock count is non-negative and, if it's not the
1293  system object, has been reset to its previous value */
1294  ENSURES( objectInfoPtr->lockCount >= 0 && \
1295  ( localObjectHandle == SYSTEM_OBJECT_HANDLE ||
1296  objectInfoPtr->lockCount == ORIGINAL_VALUE( lockCount ) ) );
1297 
1298  /* If there's a post-dispatch handler present, apply it. Since a
1299  destroy object message always succeeds but can return an error code
1300  (typically CRYPT_ERROR_INCOMPLETE), we don't treat an error return as
1301  a real error status for the purposes of further processing */
1302  if( ( cryptStatusOK( status ) || localMessage == MESSAGE_DESTROY ) && \
1303  handlingInfoPtr->postDispatchFunction != NULL )
1304  {
1305  status = handlingInfoPtr->postDispatchFunction( localObjectHandle,
1306  messageQueueData->message,
1307  messageQueueData->messageDataPtr,
1308  messageQueueData->messageValue,
1309  aclPtr );
1310  }
1311  return( status );
1312  }
1313 
1314 /* Send a message to an object */
1315 
1316 int krnlSendMessage( IN_HANDLE const int objectHandle,
1317  IN_MESSAGE const MESSAGE_TYPE message,
1318  void *messageDataPtr, const int messageValue )
1319  {
1320  const ATTRIBUTE_ACL *attributeACL = NULL;
1321  const MESSAGE_HANDLING_INFO *handlingInfoPtr;
1322  OBJECT_INFO *objectTable, *objectInfoPtr;
1323  MESSAGE_QUEUE_DATA enqueuedMessageData;
1324  const BOOLEAN isInternalMessage = isInternalMessage( message ) ? \
1325  TRUE : FALSE;
1326  const void *aclPtr = NULL;
1327  MESSAGE_TYPE localMessage = message & MESSAGE_MASK;
1328  int localObjectHandle = objectHandle, iterationCount;
1329  int status = CRYPT_OK;
1330 
1331  assert( isWritePtr( krnlData, sizeof( KERNEL_DATA ) ) );
1332 
1333  /* Preconditions. For external messages we don't provide any assertions
1334  at this point since they're coming straight from the user and could
1335  contain any values, and for internal messages we only trap on
1336  programming errors (thus for example isValidHandle() vs.
1337  isValidObject(), since this would trap if a message is sent to a
1338  destroyed object) */
1339  REQUIRES( isValidMessage( localMessage ) );
1340  REQUIRES( !isInternalMessage || isValidHandle( objectHandle ) );
1341 
1342  /* Get the information that we need to handle this message */
1343  handlingInfoPtr = &messageHandlingInfo[ localMessage ];
1344 
1345  /* Inner preconditions now that we have the handling information: Message
1346  parameters must be within the allowed range */
1347  REQUIRES( checkParams( handlingInfoPtr->paramCheck, messageDataPtr,
1348  messageValue ) );
1349 
1350  /* If it's an object-manipulation message get the attribute's mandatory
1351  ACL; if it's an object-parameter message get the parameter's mandatory
1352  ACL. Since these doesn't require access to any object information, we
1353  can do it before we lock the object table */
1354  if( isAttributeMessage( localMessage ) )
1355  {
1356  attributeACL = findAttributeACL( messageValue, isInternalMessage );
1357  if( attributeACL == NULL )
1358  return( CRYPT_ARGERROR_VALUE );
1359  aclPtr = attributeACL;
1360 
1361  /* Because cryptlib can be called through a variety of different
1362  language bindings it's not guaranteed that the values of TRUE and
1363  FALSE (as supplied by the caller) will always be 1 and 0. For
1364  example Visual Basic uses the value -1 for TRUE because of
1365  obscure backwards-compatibility and implementation issues with
1366  16-bit versions of VB. In order to avoid complaints from various
1367  checks at lower levels of cryptlib, we replace any boolean values
1368  with a setting other than FALSE with the explicit boolean value
1369  TRUE. This is a bit of an ugly kludge but it avoids having to
1370  special-case these values at all sorts of other locations in the
1371  code */
1372  if( localMessage == MESSAGE_SETATTRIBUTE && \
1373  attributeACL->valueType == ATTRIBUTE_VALUE_BOOLEAN )
1374  {
1375  REQUIRES( messageDataPtr != NULL );
1376 
1377  if( *( ( BOOLEAN * ) messageDataPtr ) )
1378  messageDataPtr = MESSAGE_VALUE_TRUE;
1379  }
1380  }
1381  if( isParamMessage( localMessage ) )
1382  {
1383  aclPtr = findParamACL( localMessage );
1384  ENSURES( aclPtr != NULL );
1385  }
1386 
1387  /* Inner precondition: If it's an attribute-manipulation message, we have
1388  a valid ACL for the attribute present */
1389  REQUIRES( !isAttributeMessage( localMessage ) || attributeACL != NULL );
1390 
1391  /* If we're in the middle of a shutdown, don't allow any further
1392  messages except ones related to object destruction (the status read
1393  is needed for objects capable of performing async ops, since the
1394  shutdown code needs to determine whether they're currently busy).
1395  The check outside the object-table lock is done in order to have any
1396  remaining active objects exit quickly without tying up the object
1397  table, since we don't want them to block the shutdown. In addition
1398  if the thread is a leftover/long-running thread that's still active
1399  after the shutdown has occurred, we can't access the object table
1400  lock since it'll have been deleted */
1401  if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MESSAGES && \
1402  !( localMessage == MESSAGE_DESTROY || \
1403  localMessage == MESSAGE_DECREFCOUNT || \
1404  ( localMessage == MESSAGE_GETATTRIBUTE && \
1405  messageValue == CRYPT_IATTRIBUTE_STATUS ) ) )
1406  {
1407  /* Exit without even trying to acquire the object table lock */
1408  return( CRYPT_ERROR_PERMISSION );
1409  }
1410 
1411  /* Lock the object table to ensure that other threads don't try to
1412  access it */
1413  MUTEX_LOCK( objectTable );
1414  objectTable = krnlData->objectTable;
1415 
1416  /* The first line of defence: Make sure that the message is being sent
1417  to a valid object and that the object is externally visible and
1418  accessible to the caller if required by the message. The checks
1419  performed are:
1420 
1421  if( handle does not correspond to an object )
1422  error;
1423  if( message is external )
1424  {
1425  if( object is internal )
1426  error;
1427  if( object isn't owned by calling thread )
1428  error;
1429  }
1430 
1431  This is equivalent to the shorter form fullObjectCheck() that used
1432  elsewhere. The error condition reported in all of these cases is
1433  that the object handle isn't valid */
1434  if( !isValidObject( objectHandle ) )
1435  status = CRYPT_ARGERROR_OBJECT;
1436  else
1437  {
1438  if( !isInternalMessage && \
1439  ( isInternalObject( objectHandle ) || \
1440  !checkObjectOwnership( objectTable[ objectHandle ] ) ) )
1441  status = CRYPT_ARGERROR_OBJECT;
1442  }
1443  if( cryptStatusError( status ) )
1444  {
1445  MUTEX_UNLOCK( objectTable );
1446  return( status );
1447  }
1448 
1449  /* Inner precondition now that the outer check has been passed: It's a
1450  valid, accessible object and not a system object that can never be
1451  explicitly destroyed or have its refCount altered */
1452  REQUIRES( isValidObject( objectHandle ) );
1453  REQUIRES( isInternalMessage || ( !isInternalObject( objectHandle ) && \
1454  checkObjectOwnership( objectTable[ objectHandle ] ) ) );
1455  REQUIRES( fullObjectCheck( objectHandle, message ) );
1456  REQUIRES( objectHandle >= NO_SYSTEM_OBJECTS || \
1457  ( localMessage != MESSAGE_DESTROY && \
1458  localMessage != MESSAGE_DECREFCOUNT && \
1459  localMessage != MESSAGE_INCREFCOUNT ) );
1460 
1461  /* If this message is routable, find its target object */
1462  if( handlingInfoPtr->routingFunction != NULL )
1463  {
1464  /* If it's implicitly routed, route it based on the attribute type */
1465  if( isImplicitRouting( handlingInfoPtr->routingTarget ) )
1466  {
1467  REQUIRES( attributeACL != NULL );
1468 
1469  if( attributeACL->routingFunction != NULL )
1470  localObjectHandle = attributeACL->routingFunction( objectHandle,
1471  attributeACL->routingTarget );
1472  }
1473  else
1474  {
1475  /* It's explicitly or directly routed, route it based on the
1476  message type or fixed-target type */
1477  localObjectHandle = handlingInfoPtr->routingFunction( objectHandle,
1478  isExplicitRouting( handlingInfoPtr->routingTarget ) ? \
1479  messageValue : handlingInfoPtr->routingTarget );
1480  }
1481  if( cryptStatusError( localObjectHandle ) )
1482  {
1483  MUTEX_UNLOCK( objectTable );
1484  return( CRYPT_ARGERROR_OBJECT );
1485  }
1486  }
1487 
1488  /* Inner precodition: It's a valid destination object */
1489  REQUIRES( isValidObject( localObjectHandle ) );
1490 
1491  /* Sanity-check the message routing */
1492  if( !isValidObject( localObjectHandle ) )
1493  {
1494  MUTEX_UNLOCK( objectTable );
1495  retIntError();
1496  }
1497 
1498  /* It's a valid object, get its info */
1499  objectInfoPtr = &objectTable[ localObjectHandle ];
1500 
1501  /* Now that the message has been routed to its intended target, make sure
1502  that it's valid for the target object subtype */
1503  if( !isValidSubtype( handlingInfoPtr->subTypeA, objectInfoPtr->subType ) && \
1504  !isValidSubtype( handlingInfoPtr->subTypeB, objectInfoPtr->subType ) && \
1505  !isValidSubtype( handlingInfoPtr->subTypeC, objectInfoPtr->subType ) )
1506  {
1507  MUTEX_UNLOCK( objectTable );
1508  return( CRYPT_ARGERROR_OBJECT );
1509  }
1510 
1511  /* Inner precondition: The message is valid for this object subtype */
1512  REQUIRES( isValidSubtype( handlingInfoPtr->subTypeA, \
1513  objectInfoPtr->subType ) || \
1514  isValidSubtype( handlingInfoPtr->subTypeB, \
1515  objectInfoPtr->subType ) || \
1516  isValidSubtype( handlingInfoPtr->subTypeC, \
1517  objectInfoPtr->subType ) );
1518 
1519  /* If this message is processed internally, handle it now. These
1520  messages aren't affected by the object's state so they're always
1521  processed */
1522  if( handlingInfoPtr->internalHandlerFunction != NULL || \
1523  ( attributeACL != NULL && \
1524  attributeACL->flags & ATTRIBUTE_FLAG_PROPERTY ) )
1525  {
1526  status = processInternalMessage( localObjectHandle, handlingInfoPtr,
1527  message, messageDataPtr,
1528  messageValue, aclPtr );
1529  if( status != OK_SPECIAL )
1530  {
1531  /* The message was processed normally, exit */
1532  MUTEX_UNLOCK( objectTable );
1533  return( status );
1534  }
1535 
1536  /* The object has entered an invalid state (for example it was
1537  signalled while it was being initialised) and can't be used any
1538  more, destroy it, convert the (local copy of the) message into a
1539  destroy object message */
1540  localMessage = MESSAGE_DESTROY;
1541  status = CRYPT_OK;
1542  }
1543 
1544  /* If the object isn't already processing a message and the message isn't
1545  a special type such as MESSAGE_DESTROY, dispatch it immediately rather
1546  than enqueueing it for later dispatch. This scoreboard mechanism
1547  greatly reduces the load on the queue */
1548  if( !isInUse( localObjectHandle ) && localMessage != MESSAGE_DESTROY )
1549  {
1550  CONST_INIT_STRUCT_5( MESSAGE_QUEUE_DATA messageQueueData, \
1551  localObjectHandle, handlingInfoPtr, message, \
1552  messageDataPtr, messageValue );
1553 
1554  CONST_SET_STRUCT( messageQueueData.objectHandle = localObjectHandle; \
1555  messageQueueData.handlingInfoPtr = handlingInfoPtr; \
1556  messageQueueData.message = message; \
1557  messageQueueData.messageDataPtr = messageDataPtr; \
1558  messageQueueData.messageValue = messageValue );
1559 
1560  /* If the object isn't in a valid state, we can't do anything with it.
1561  There are no messages that can be sent to it at this point, get/
1562  set property messages have already been handled earlier and the
1563  destroy message isn't handled here */
1564  if( isInvalidObjectState( localObjectHandle ) )
1565  {
1566  status = getObjectStatusValue( objectInfoPtr->flags );
1567  MUTEX_UNLOCK( objectTable );
1568  return( status );
1569  }
1570 
1571  /* In case a shutdown was signalled while we were performing other
1572  processing, exit now before we try and do anything with the
1573  object. It's safe to perform the check at this point since no
1574  message sent during shutdown will get here */
1575  if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MESSAGES )
1576  {
1577  MUTEX_UNLOCK( objectTable );
1578  return( CRYPT_ERROR_PERMISSION );
1579  }
1580 
1581  /* Inner precondition: The object is in a valid state */
1582  REQUIRES( !isInvalidObjectState( localObjectHandle ) );
1583 
1584  /* Dispatch the message to the object */
1585  status = dispatchMessage( localObjectHandle, &messageQueueData,
1586  objectInfoPtr, aclPtr );
1587  MUTEX_UNLOCK( objectTable );
1588 
1589  /* If it's a zeroise, perform a kernel shutdown. In theory we could
1590  do this from the post-dispatch handler, but we need to make sure
1591  that there are no further kernel actions to be taken before we
1592  perform the shutdown, so we do it at this level instead */
1593  if( cryptStatusOK( status ) && \
1594  ( messageQueueData.message & MESSAGE_MASK ) == MESSAGE_USER_USERMGMT && \
1595  messageQueueData.messageValue == MESSAGE_USERMGMT_ZEROISE )
1596  {
1597  endCryptlib();
1598  }
1599 
1600  /* Postcondition: The return status is valid */
1601  ENSURES( cryptStandardError( status ) || \
1602  cryptArgError( status ) || status == OK_SPECIAL );
1603 
1604  return( status );
1605  }
1606 
1607  /* Inner precondition: The object is in use or it's a destroy object
1608  message, we have to enqueue it */
1609  REQUIRES( isInUse( localObjectHandle ) || \
1610  localMessage == MESSAGE_DESTROY );
1611 
1612  /* If we're stuck in a loop processing recursive messages, bail out.
1613  This would happen automatically anyway once we fill the message queue,
1614  but this early-out mechanism prevents a single object from filling the
1615  queue to the detriment of other objects */
1616  if( objectInfoPtr->lockCount > MESSAGE_QUEUE_SIZE / 2 )
1617  {
1618  MUTEX_UNLOCK( objectTable );
1619  DEBUG_DIAG(( "Invalid kernel message queue state" ));
1620  assert( DEBUG_WARN );
1621  return( CRYPT_ERROR_TIMEOUT );
1622  }
1623 
1624  /* If the object is in use by another thread, wait for it to become
1625  available */
1626  if( isInUse( localObjectHandle ) && !isObjectOwner( localObjectHandle ) )
1627  {
1628  status = waitForObject( localObjectHandle, &objectInfoPtr );
1629 #if !defined( NDEBUG ) && defined( USE_THREADS )
1630  if( cryptStatusOK( status ) && isInUse( localObjectHandle ) )
1631  {
1632  /* dispatchMessage() expects us to be the lock owner if the
1633  object is in use, however if the object has been */
1634  objectInfoPtr->lockOwner = THREAD_SELF();
1635  }
1636 #endif /* !NDEBUG && USE_THREADS */
1637  }
1638  if( cryptStatusError( status ) )
1639  {
1640  MUTEX_UNLOCK( objectTable );
1641  return( status );
1642  }
1643  assert( !isInUse( localObjectHandle ) || \
1644  isObjectOwner( localObjectHandle ) );
1645 
1646  /* Enqueue the message */
1647  if( ( message & MESSAGE_MASK ) != localMessage )
1648  {
1649  /* The message was converted during processing, this can only happen
1650  when a message sent to an invalid-state object is converted into
1651  a destroy-object message. What we therefore enqueue is a
1652  destroy-object message, but with the messageValue parameter set
1653  to TRUE to indicate that it's a converted destroy message */
1654  REQUIRES( localMessage == MESSAGE_DESTROY );
1655 
1656  status = enqueueMessage( localObjectHandle,
1657  &messageHandlingInfo[ MESSAGE_DESTROY ],
1658  MESSAGE_DESTROY, messageDataPtr, TRUE );
1659  }
1660  else
1661  {
1662  status = enqueueMessage( localObjectHandle, handlingInfoPtr, message,
1663  messageDataPtr, messageValue );
1664  }
1665  if( cryptStatusError( status ) )
1666  {
1667  /* A message for this object is already present in the queue, defer
1668  processing until later */
1669  MUTEX_UNLOCK( objectTable );
1670  return( ( status == OK_SPECIAL ) ? CRYPT_OK : status );
1671  }
1672  assert( !isInUse( localObjectHandle ) || \
1673  isObjectOwner( localObjectHandle ) );
1674 
1675  /* While there are more messages for this object present, dequeue them
1676  and dispatch them. Since messages will only be enqueued if
1677  krnlSendMessage() is called recursively, we only dequeue messages for
1678  the current object in this loop. Queued messages for other objects
1679  will be handled at a different level of recursion.
1680 
1681  Bounding this loop is a bit tricky because new messages can arrive as
1682  the existing ones are dequeued, so that in theory the arrival rate
1683  could match the dispatch rate. However in practice a situation like
1684  this would be extremely unusual, so we bound the loop at
1685  FAILSAFE_ITERATIONS_LARGE */
1686  for( iterationCount = 0;
1687  getNextMessage( localObjectHandle, &enqueuedMessageData ) && \
1688  iterationCount < FAILSAFE_ITERATIONS_LARGE;
1689  iterationCount++ )
1690  {
1691  const BOOLEAN isDestroy = \
1692  ( enqueuedMessageData.message & MESSAGE_MASK ) == MESSAGE_DESTROY;
1693  const BOOLEAN isZeroise = \
1694  ( enqueuedMessageData.message & MESSAGE_MASK ) == MESSAGE_USER_USERMGMT && \
1695  enqueuedMessageData.messageValue == MESSAGE_USERMGMT_ZEROISE;
1696 
1697  /* If there's a problem with the object, initiate special processing.
1698  The exception to this is a destroy message that started out as a
1699  different type of message (that is, it was converted into a
1700  destroy object message due to the object being in an invalid
1701  state, indicated by the messageValue parameter being set to TRUE
1702  when it's normally zero for a destroy message), which is let
1703  through */
1704  if( isInvalidObjectState( localObjectHandle ) && \
1705  !( isDestroy && ( enqueuedMessageData.messageValue == TRUE ) ) )
1706  {
1707  /* If it's a destroy object message being sent to an object in
1708  the process of being created, set the state to signalled and
1709  continue. The object will be destroyed when the caller
1710  notifies the kernel that the init is complete */
1711  if( isDestroy && ( objectInfoPtr->flags & OBJECT_FLAG_NOTINITED ) )
1712  {
1713  objectInfoPtr->flags |= OBJECT_FLAG_SIGNALLED;
1714  status = CRYPT_OK;
1715  }
1716  else
1717  {
1718  /* Remove all further messages for this object and return
1719  to the caller */
1720  dequeueAllMessages( localObjectHandle );
1721  status = getObjectStatusValue( objectInfoPtr->flags );
1722  }
1723  continue;
1724  }
1725  assert( !isInUse( localObjectHandle ) || \
1726  isObjectOwner( localObjectHandle ) );
1727 
1728  /* Inner precondition: The object is in a valid state or it's a
1729  destroy message that was converted from a different message
1730  type */
1731  REQUIRES( !isInvalidObjectState( localObjectHandle ) || \
1732  ( isDestroy && ( enqueuedMessageData.messageValue == TRUE ) ) );
1733 
1734  /* Dispatch the message to the object */
1735  status = dispatchMessage( localObjectHandle, &enqueuedMessageData,
1736  objectInfoPtr, aclPtr );
1737 
1738  /* If the message is a destroy object message, we have to explicitly
1739  remove it from the object table and dequeue all further messages
1740  for it since the object's message handler can't do this itself.
1741  Since a destroy object message always succeeds but can return an
1742  error code (typically CRYPT_ERROR_INCOMPLETE), we don't treat an
1743  error return as a real error status for the purposes of further
1744  processing */
1745  if( isDestroy )
1746  {
1747  status = destroyObjectData( localObjectHandle );
1748  ENSURES( cryptStatusOK( status ) );
1749  dequeueAllMessages( localObjectHandle );
1750  }
1751  else
1752  {
1753  /* If we ran into a problem or this is a zeroise (i.e. a
1754  localised shutdown), dequeue all further messages for this
1755  object. This causes getNextMessage() to fail and we drop out
1756  of the loop */
1757  if( cryptStatusError( status ) || \
1758  ( cryptStatusOK( status ) && isZeroise ) )
1759  {
1760  dequeueAllMessages( localObjectHandle );
1761  }
1762  }
1763  }
1764  ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
1765 
1766  /* Unlock the object table to allow access by other threads */
1767  MUTEX_UNLOCK( objectTable );
1768 
1769  /* If it's a zeroise, perform a kernel shutdown. In theory we could do
1770  this from the post-dispatch handler, but we need to make sure that
1771  there are no further kernel actions to be taken before we perform the
1772  shutdown, so we do it at this level instead */
1773  if( cryptStatusOK( status ) && localMessage == MESSAGE_USER_USERMGMT && \
1774  messageValue == MESSAGE_USERMGMT_ZEROISE )
1775  {
1776  endCryptlib();
1777  }
1778 
1779  /* Postcondition: The return status is valid */
1780  ENSURES( cryptStandardError( status ) || cryptArgError( status ) || \
1781  status == OK_SPECIAL );
1782 
1783  return( status );
1784  }