1 /****************************************************************************
2 * *
3 * Kernel Message Dispatcher *
4 * Copyright Peter Gutmann 1997-2012 *
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 certificate sign/sig-check messages */
24
25 static const MESSAGE_ACL FAR_BSS messageParamACLTbl[] = {
26 /* Certificates can only be signed by (private-key) PKC contexts */
27 { MESSAGE_CRT_SIGN,
28 { ST_CTX_PKC,
29 ST_NONE, ST_NONE } },
30
31 /* Signatures can be checked with a raw PKC context or a certificate
32 (but specifically not a certificate chain, see the long discussion
33 in certs/certschk.c for details on this). The object being checked
34 can also be checked against a CRL or CRL-equivalent like an RTCS or
35 OCSP response, against revocation data in a certificate store, or
36 against an RTCS or OCSP responder */
37 { MESSAGE_CRT_SIGCHECK,
38 { ST_CTX_PKC | MKTYPE_CERTIFICATES( ST_CERT_CERT ) | \
39 MKTYPE_CERTREV( ST_CERT_CRL ) | MKTYPE_CERTVAL( ST_CERT_RTCS_RESP ) | \
40 MKTYPE_CERTREV( ST_CERT_OCSP_RESP ),
41 MKTYPE_DBMS( ST_KEYSET_DBMS ) | MKTYPE_DBMS( ST_KEYSET_DBMS_STORE ),
42 MKTYPE_RTCS( ST_SESS_RTCS ) | MKTYPE_OCSP( ST_SESS_OCSP ) } },
43
44 /* End-of-ACL marker */
45 { MESSAGE_NONE, { ST_NONE, ST_NONE, ST_NONE } },
46 { MESSAGE_NONE, { ST_NONE, ST_NONE, ST_NONE } }
47 };
48
49 /****************************************************************************
50 * *
51 * Utility Functions *
52 * *
53 ****************************************************************************/
54
55 /* Sometimes a message is explicitly non-routable (i.e. it has to be sent
56 directly to the appropriate target object). The following function checks
57 that the target object is one of the required types */
58
59 CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
checkTargetType(IN_HANDLE const CRYPT_HANDLE originalObjectHandle,OUT_HANDLE_OPT CRYPT_HANDLE * targetObjectHandle,const long targets)60 int checkTargetType( IN_HANDLE const CRYPT_HANDLE originalObjectHandle,
61 OUT_HANDLE_OPT CRYPT_HANDLE *targetObjectHandle,
62 const long targets )
63 {
64 const OBJECT_TYPE target = targets & 0xFF;
65 const OBJECT_TYPE altTarget = targets >> 8;
66 OBJECT_INFO *objectTable = krnlData->objectTable;
67
68 /* Precondition: Source is a valid object, destination(s) are valid
69 target(s) */
70 REQUIRES( isValidObject( originalObjectHandle ) );
71 REQUIRES( isValidType( target ) );
72 REQUIRES( altTarget == OBJECT_TYPE_NONE || isValidType( altTarget ) );
73
74 /* Clear return value */
75 *targetObjectHandle = CRYPT_ERROR;
76
77 /* Check whether the object matches the required type. We don't have to
78 check whether the alternative target has a value or not since the
79 object can never be a OBJECT_TYPE_NONE */
80 if( !isValidObject( originalObjectHandle ) || \
81 ( objectTable[ originalObjectHandle ].type != target && \
82 objectTable[ originalObjectHandle ].type != altTarget ) )
83 return( CRYPT_ERROR );
84
85 /* Postcondition */
86 ENSURES( objectTable[ originalObjectHandle ].type == target || \
87 objectTable[ originalObjectHandle ].type == altTarget );
88
89 *targetObjectHandle = originalObjectHandle;
90 return( CRYPT_OK );
91 }
92
93 /* Find the ACL for a parameter object */
94
95 CHECK_RETVAL_PTR \
findParamACL(IN_MESSAGE const MESSAGE_TYPE message)96 static const MESSAGE_ACL *findParamACL( IN_MESSAGE const MESSAGE_TYPE message )
97 {
98 int i;
99
100 /* Precondition: It's a message that takes an object parameter */
101 REQUIRES_N( isParamMessage( message ) );
102
103 /* Find the ACL entry for this message type. There's no need to
104 explicitly handle the internal-error condition since any loop
105 exit is treated as an error */
106 for( i = 0; messageParamACLTbl[ i ].type != MESSAGE_NONE && \
107 i < FAILSAFE_ARRAYSIZE( messageParamACLTbl, MESSAGE_ACL );
108 i++ )
109 {
110 if( messageParamACLTbl[ i ].type == message )
111 return( &messageParamACLTbl[ i ] );
112 }
113
114 retIntError_Null();
115 }
116
117 /* Wait for an object to become available so that we can use it, with a
118 timeout for blocked objects (dulcis et alta quies placidaeque similima
119 morti). We spin for WAITCOUNT_SLEEP_THRESHOLD turns, then sleep (see
120 the comment in waitForObject() for more on this), and finally bail out
121 once MAX_WAITCOUNT is reached.
122
123 This is an internal function that's used when mapping an object handle to
124 object data, and is never called directly.
125
126 As an aid in identifying objects acting as bottlenecks, we provide a
127 function to warn about excessive waiting, along with information on the
128 object that was waited on, in debug mode. A wait count threshold of
129 100 is generally high enough to avoid false positives caused by (for
130 example) network subsystem delays */
131
132 #define WAITCOUNT_SLEEP_THRESHOLD 100
133 #define WAITCOUNT_WARN_THRESHOLD 100
134 #define MAX_WAITCOUNT 1000
135
136 #if !defined( NDEBUG )
137
138 /* Get a text description of an object associated with a given object
139 handle */
140
getObjectDescription(IN_HANDLE const int objectHandle,OUT char * description)141 static void getObjectDescription( IN_HANDLE const int objectHandle,
142 OUT char *description )
143 {
144 static const char *objectTypeNames[] = {
145 "none", "context", "keyset", "envelope", "certificate", "device",
146 "session", "user", "none", "none"
147 };
148 typedef struct {
149 const OBJECT_SUBTYPE subType;
150 const char *description;
151 } OBJECT_DESCRIPTION_MAP;
152 static const OBJECT_DESCRIPTION_MAP descriptionMap[] = {
153 { SUBTYPE_CTX_CONV, "conventional encryption" },
154 { SUBTYPE_CTX_PKC, "public-key encryption" },
155 { SUBTYPE_CTX_HASH, "hash" },
156 { SUBTYPE_CTX_MAC, "MAC" },
157 { SUBTYPE_CTX_GENERIC, "generic" },
158 { SUBTYPE_CERT_CERT, "certificate" },
159 { SUBTYPE_CERT_CERTREQ, "PKCS #10 cert.request" },
160 { SUBTYPE_CERT_REQ_CERT, "CRMF cert.request" },
161 { SUBTYPE_CERT_REQ_REV, "CRMF rev.request" },
162 { SUBTYPE_CERT_CERTCHAIN, "cert.chain" },
163 { SUBTYPE_CERT_ATTRCERT, "attribute cert." },
164 { SUBTYPE_CERT_CRL, "CRK" },
165 { SUBTYPE_CERT_CMSATTR, "CMS attributes" },
166 { SUBTYPE_CERT_RTCS_REQ, "RTCS request" },
167 { SUBTYPE_CERT_RTCS_RESP, "RTCS response" },
168 { SUBTYPE_CERT_OCSP_REQ, "OCSP request" },
169 { SUBTYPE_CERT_OCSP_RESP, "OCSP response" },
170 { SUBTYPE_CERT_PKIUSER, "PKI user" },
171 { SUBTYPE_ENV_ENV, "PKCS #7/CMS envelope" },
172 { SUBTYPE_ENV_ENV_PGP, "PGP envelope" },
173 { SUBTYPE_ENV_DEENV, "de-envelope" },
174 { SUBTYPE_KEYSET_FILE, "file" },
175 { SUBTYPE_KEYSET_FILE_PARTIAL, "file (partial)" },
176 { SUBTYPE_KEYSET_FILE_READONLY, "file (readonly)" },
177 { SUBTYPE_KEYSET_DBMS, "database" },
178 { SUBTYPE_KEYSET_DBMS_STORE, "database store" },
179 { SUBTYPE_KEYSET_HTTP, "HTTP" },
180 { SUBTYPE_KEYSET_LDAP, "LDAP" },
181 { SUBTYPE_DEV_SYSTEM, "system" },
182 { SUBTYPE_DEV_PKCS11, "PKCS #11" },
183 { SUBTYPE_DEV_CRYPTOAPI, "CryptoAPI" },
184 { SUBTYPE_DEV_HARDWARE, "hardware" },
185 { SUBTYPE_SESSION_SSH, "SSH" },
186 { SUBTYPE_SESSION_SSH_SVR, "SSH server" },
187 { SUBTYPE_SESSION_SSL, "SSL" },
188 { SUBTYPE_SESSION_SSL_SVR, "SSL server" },
189 { SUBTYPE_SESSION_RTCS, "RTCS" },
190 { SUBTYPE_SESSION_RTCS_SVR, "RTCS server" },
191 { SUBTYPE_SESSION_OCSP, "OCSP" },
192 { SUBTYPE_SESSION_OCSP_SVR, "OCSP server" },
193 { SUBTYPE_SESSION_TSP, "TSP" },
194 { SUBTYPE_SESSION_TSP_SVR, "TSP server" },
195 { SUBTYPE_SESSION_CMP, "CMP" },
196 { SUBTYPE_SESSION_CMP_SVR, "CMP server" },
197 { SUBTYPE_SESSION_SCEP, "SCEP" },
198 { SUBTYPE_SESSION_SCEP_SVR, "SCEP server" },
199 { SUBTYPE_SESSION_CERT_SVR, "cerificate store" },
200 { SUBTYPE_USER_SO, "SO user" },
201 { SUBTYPE_USER_NORMAL, "standard user" },
202 { SUBTYPE_USER_CA, "CA user" },
203 { SUBTYPE_NONE, "NONE" }, { SUBTYPE_NONE, "NONE" },
204 };
205 const OBJECT_INFO *objectInfoPtr = &krnlData->objectTable[ objectHandle ];
206 int i;
207
208 assert( isValidObject( objectHandle ) );
209
210 REQUIRES_V( isValidType( objectInfoPtr->type ) );
211
212 if( objectHandle == SYSTEM_OBJECT_HANDLE )
213 {
214 strlcpy_s( description, 128, "system object" );
215 return;
216 }
217 if( objectHandle == DEFAULTUSER_OBJECT_HANDLE )
218 {
219 strlcpy_s( description, 128, "default user object" );
220 return;
221 }
222 for( i = 0; descriptionMap[ i ].subType != objectInfoPtr->subType && \
223 descriptionMap[ i ].subType != SUBTYPE_NONE; i++ );
224 sprintf_s( description, 128, "object %d (%s/%s)", objectHandle,
225 objectTypeNames[ objectInfoPtr->type ],
226 descriptionMap[ i ].description );
227 }
228
229 /* Non thread-safe version of the above that can be used directly in
230 printf() statements. This isn't really that bad, firstly it's mostly
231 only called for diagnostics during startup/shutdown where there's
232 guaranteed to be only one thread active, and secondly it uses TLS
233 where possible which means that it'll only really be non-thread-safe on
234 systems that don't have threading anyway (embedded systems that use
235 the tasking model where there's typically only one task) */
236
237 #if defined( _MSC_VER )
238 #define THREAD_STORAGE_STATIC __declspec( thread ) static
239 #elif defined( __GNUC__ ) || defined( __clang__ ) || \
240 defined( __SUNPRO_C ) || defined( __xlc__ )
241 #define THREAD_STORAGE_STATIC static __thread
242 #else
243 #define THREAD_STORAGE_STATIC static
244 #endif /* Compiler-specific TLS */
245 #if defined( __APPLE__ )
246 #undef THREAD_STORAGE_STATIC
247 #define THREAD_STORAGE_STATIC static
248 #endif /* OS X */
249
getObjectDescriptionNT(IN_HANDLE const int objectHandle)250 const char *getObjectDescriptionNT( IN_HANDLE const int objectHandle )
251 {
252 THREAD_STORAGE_STATIC char buffer[ 128 ];
253
254 getObjectDescription( objectHandle, buffer );
255 return( buffer );
256 }
257
258 /* Warn about an excessive wait for an object to become available */
259
waitWarn(IN_HANDLE const int objectHandle,IN_INT const int waitCount)260 static void waitWarn( IN_HANDLE const int objectHandle,
261 IN_INT const int waitCount )
262 {
263 char description[ 128 + 8 ];
264
265 assert( isValidObject( objectHandle ) );
266 assert( waitCount > WAITCOUNT_WARN_THRESHOLD && \
267 waitCount <= MAX_WAITCOUNT );
268
269 getObjectDescription( objectHandle, description );
270 DEBUG_PRINT(( "\nWarning: Thread %lX waited %d iteration%s for %s.\n",
271 ( unsigned long ) THREAD_SELF(), waitCount,
272 ( waitCount == 1 ) ? "" : "s", description ));
273 }
274 #endif /* Debug mode only */
275
276 CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
waitForObject(IN_HANDLE const int objectHandle,OUT_PTR_COND OBJECT_INFO ** objectInfoPtrPtr)277 int waitForObject( IN_HANDLE const int objectHandle,
278 OUT_PTR_COND OBJECT_INFO **objectInfoPtrPtr )
279 {
280 OBJECT_INFO *objectTable = krnlData->objectTable;
281 const int uniqueID = objectTable[ objectHandle ].uniqueID;
282 int waitCount = 0;
283
284 /* Preconditions: The object is in use by another thread */
285 REQUIRES( isValidObject( objectHandle ) );
286 REQUIRES( isInUse( objectHandle ) && !isObjectOwner( objectHandle ) );
287
288 /* Clear return value */
289 *objectInfoPtrPtr = NULL;
290
291 /* While the object is busy, put the thread to sleep (Pauzele lungi si
292 dese; Cheia marilor succese). This is the only really portable way
293 to wait on the resource, which gives up this thread's timeslice to
294 allow other threads (including the one using the object) to run.
295 Somewhat better methods methods such as mutexes with timers are
296 difficult to manage portably across different platforms.
297
298 Even this can cause problems in some circumstances. The idea behind
299 the mechanism below is that by yielding the CPU, whichever thread
300 currently holds the object gets to finish with it and then the
301 current thread resumes. However if there's a thundering-herd
302 situation where a dozen other threads are waiting on the lock and
303 they've voluntarily yielded the CPU and the scheduler prioritises
304 them above other threads because of this then they'll all fight for
305 the lock and so the thread that holds the object that they're waiting
306 on never gets to run.
307
308 This seems somewhat unlikely, but it's cropped up on multicore
309 hyperthreaded Linux machines running large numbers of threads,
310 probably because of the thread-scheduling pecularities of HT CPUs
311 combined with the thread-scheduling peculiarities of Linux (it
312 doesn't occur on the same systems running Windows or other OSes).
313 The problem seems to be that if a thread yields on a CPU other than
314 the one that holds the resource and no other threads are waiting to
315 run then it's immediately re-scheduled, because the yield only
316 applies to threads on the same CPU.
317
318 To deal with this we turn the basic thread-timeslice-yield into a
319 more aggressive thread-sleep (which really does yield the CPU, even
320 with the thread-scheduling described above) if
321 WAITCOUNT_SLEEP_THRESHOLD yields are exceeded */
322 while( isValidObject( objectHandle ) && \
323 objectTable[ objectHandle ].uniqueID == uniqueID && \
324 isInUse( objectHandle ) && waitCount < MAX_WAITCOUNT && \
325 krnlData->shutdownLevel < SHUTDOWN_LEVEL_MESSAGES )
326 {
327 objectTable = NULL;
328 MUTEX_UNLOCK( objectTable );
329 waitCount++;
330 THREAD_YIELD();
331 if( waitCount > WAITCOUNT_SLEEP_THRESHOLD )
332 {
333 /* We've waited for over WAITCOUNT_SLEEP_THRESHOLD thread
334 timeslices, explicitly put the thread to sleep rather than
335 just yielding its timeslice */
336 THREAD_SLEEP( 1 );
337 }
338 MUTEX_LOCK( objectTable );
339 objectTable = krnlData->objectTable;
340 }
341 #if !defined( NDEBUG ) && !defined( __WIN16__ )
342 if( waitCount > WAITCOUNT_WARN_THRESHOLD )
343 {
344 /* If we waited more than WAITCOUNT_WARN_THRESHOLD iterations for
345 something this could be a sign of a resource usage bottleneck
346 (typically caused by users who don't understand threading), warn
347 the user that there's a potential problem */
348 waitWarn( objectHandle, waitCount );
349 }
350 #endif /* NDEBUG on systems with stdio */
351
352 /* If cryptlib is shutting down, exit */
353 if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MESSAGES )
354 return( CRYPT_ERROR_PERMISSION );
355
356 /* If we timed out waiting for the object, return a timeout error */
357 if( waitCount >= MAX_WAITCOUNT )
358 {
359 DEBUG_DIAG(( "Object wait exceeded %d iterations", MAX_WAITCOUNT ));
360 assert( DEBUG_WARN );
361 return( CRYPT_ERROR_TIMEOUT );
362 }
363
364 /* Make sure that nothing happened to the object while we were waiting
365 on it */
366 if( !isValidObject( objectHandle ) || \
367 objectTable[ objectHandle ].uniqueID != uniqueID )
368 return( CRYPT_ERROR_SIGNALLED );
369
370 /* Update the object info pointer in case the object table was updated
371 while we had yielded control */
372 *objectInfoPtrPtr = &objectTable[ objectHandle ];
373
374 /* Postconditions: The object is available for use */
375 ENSURES( isValidObject( objectHandle ) );
376 ENSURES( !isInUse( objectHandle ) );
377
378 return( CRYPT_OK );
379 }
380
381 /****************************************************************************
382 * *
383 * Message Routing *
384 * *
385 ****************************************************************************/
386
387 /* Find the ultimate target of an object attribute manipulation message by
388 walking down the chain of controlling -> dependent objects. For example
389 a message targeted at a device and sent to a certificate would be routed
390 to the certificate's dependent object (which would typically be a
391 context). The device message targeted at the context would in turn be
392 routed to the context's dependent device, which is its final destination */
393
394 CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
findTargetType(IN_HANDLE const CRYPT_HANDLE originalObjectHandle,OUT_HANDLE_OPT CRYPT_HANDLE * targetObjectHandle,const long targets)395 int findTargetType( IN_HANDLE const CRYPT_HANDLE originalObjectHandle,
396 OUT_HANDLE_OPT CRYPT_HANDLE *targetObjectHandle,
397 const long targets )
398 {
399 const OBJECT_TYPE target = targets & 0xFF;
400 const OBJECT_TYPE altTarget1 = ( targets >> 8 ) & 0xFF;
401 const OBJECT_TYPE altTarget2 = ( targets >> 16 ) & 0xFF;
402 OBJECT_INFO *objectTable = krnlData->objectTable;
403 OBJECT_TYPE type = objectTable[ originalObjectHandle ].type;
404 int objectHandle = originalObjectHandle, iterations;
405
406 /* Preconditions: Source is a valid object, destination(s) are valid
407 target(s) */
408 REQUIRES( isValidObject( objectHandle ) );
409 REQUIRES( isValidType( target ) );
410 REQUIRES( altTarget1 == OBJECT_TYPE_NONE || isValidType( altTarget1 ) );
411 REQUIRES( altTarget2 == OBJECT_TYPE_NONE || isValidType( altTarget2 ) );
412
413 /* Clear return value */
414 *targetObjectHandle = CRYPT_ERROR;
415
416 /* Route the request through any dependent objects as required until we
417 reach the required target object type. "And thou shalt make
418 loops..." -- Exodus 26:4 */
419 for( iterations = 0; \
420 iterations < 3 && isValidObject( objectHandle ) && \
421 !( target == type || \
422 ( altTarget1 != OBJECT_TYPE_NONE && altTarget1 == type ) || \
423 ( altTarget2 != OBJECT_TYPE_NONE && altTarget2 == type ) ); \
424 iterations++ )
425 {
426 /* Loop invariants. "Fifty loops thou shalt make" -- Exodus 26:5
427 (some of the OT verses shouldn't be taken too literally,
428 apparently the 50 used here merely means "many" as in "more than
429 one or two" in the same way that "40 days and nights" is now
430 generally taken as meaning "Lots, but that's as far as we're
431 prepared to count") */
432 ENSURES( isValidObject( objectHandle ) );
433 ENSURES( iterations < 3 );
434
435 /* Find the next potential target object */
436 if( target == OBJECT_TYPE_DEVICE && \
437 objectTable[ objectHandle ].dependentDevice != CRYPT_ERROR )
438 objectHandle = objectTable[ objectHandle ].dependentDevice;
439 else
440 {
441 if( target == OBJECT_TYPE_USER )
442 {
443 /* If we've reached the system object (the parent of all
444 other objects) we can't go any further */
445 objectHandle = ( objectHandle != SYSTEM_OBJECT_HANDLE ) ? \
446 objectTable[ objectHandle ].owner : CRYPT_ERROR;
447 }
448 else
449 objectHandle = objectTable[ objectHandle ].dependentObject;
450 }
451 if( isValidObject( objectHandle ) )
452 type = objectTable[ objectHandle ].type;
453
454 /* If we've got a new object, it has the same owner as the original
455 target candidate */
456 ENSURES( !isValidObject( objectHandle ) || \
457 isSameOwningObject( originalObjectHandle, objectHandle ) || \
458 objectTable[ originalObjectHandle ].owner == objectHandle );
459 }
460 ENSURES( iterations < 3 );
461 if( !isValidObject( objectHandle ) )
462 return( CRYPT_ARGERROR_OBJECT );
463
464 /* Postcondition: We've reached the target object */
465 ENSURES( isValidObject( objectHandle ) && \
466 ( isSameOwningObject( originalObjectHandle, objectHandle ) || \
467 objectTable[ originalObjectHandle ].owner == objectHandle ) && \
468 ( target == type || \
469 ( altTarget1 != OBJECT_TYPE_NONE && altTarget1 == type ) || \
470 ( altTarget2 != OBJECT_TYPE_NONE && altTarget2 == type ) ) );
471
472
473 *targetObjectHandle = objectHandle;
474 return( CRYPT_OK );
475 }
476
477 /* Find the ultimate target of a compare message by walking down the chain
478 of controlling -> dependent objects. For example a message targeted at a
479 device and sent to a certificate would be routed to the certificate's
480 dependent object (which would typically be a context). The device
481 message targeted at the context would be routed to the context's
482 dependent device, which is its final destination */
483
484 CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
routeCompareMessageTarget(IN_HANDLE const CRYPT_HANDLE originalObjectHandle,OUT_HANDLE_OPT CRYPT_HANDLE * targetObjectHandle,IN_ENUM (MESSAGE_COMPARE)const long messageValue)485 static int routeCompareMessageTarget( IN_HANDLE const CRYPT_HANDLE originalObjectHandle,
486 OUT_HANDLE_OPT CRYPT_HANDLE *targetObjectHandle,
487 IN_ENUM( MESSAGE_COMPARE ) \
488 const long messageValue )
489 {
490 OBJECT_TYPE targetType = OBJECT_TYPE_NONE;
491 int status;
492
493 /* Preconditions */
494 REQUIRES( isValidObject( originalObjectHandle ) );
495 REQUIRES( messageValue == MESSAGE_COMPARE_HASH || \
496 messageValue == MESSAGE_COMPARE_ICV || \
497 messageValue == MESSAGE_COMPARE_KEYID || \
498 messageValue == MESSAGE_COMPARE_KEYID_PGP || \
499 messageValue == MESSAGE_COMPARE_KEYID_OPENPGP || \
500 messageValue == MESSAGE_COMPARE_SUBJECT || \
501 messageValue == MESSAGE_COMPARE_ISSUERANDSERIALNUMBER || \
502 messageValue == MESSAGE_COMPARE_SUBJECTKEYIDENTIFIER || \
503 messageValue == MESSAGE_COMPARE_FINGERPRINT_SHA1 || \
504 messageValue == MESSAGE_COMPARE_FINGERPRINT_SHA2 || \
505 messageValue == MESSAGE_COMPARE_FINGERPRINT_SHAng || \
506 messageValue == MESSAGE_COMPARE_CERTOBJ );
507
508 /* Clear return value */
509 *targetObjectHandle = CRYPT_ERROR;
510
511 /* Determine the ultimate target type for the message. We don't check for
512 keysets, envelopes and sessions as dependent objects since this never
513 occurs */
514 switch( messageValue )
515 {
516 case MESSAGE_COMPARE_HASH:
517 case MESSAGE_COMPARE_ICV:
518 case MESSAGE_COMPARE_KEYID:
519 case MESSAGE_COMPARE_KEYID_PGP:
520 case MESSAGE_COMPARE_KEYID_OPENPGP:
521 targetType = OBJECT_TYPE_CONTEXT;
522 break;
523
524 case MESSAGE_COMPARE_SUBJECT:
525 case MESSAGE_COMPARE_ISSUERANDSERIALNUMBER:
526 case MESSAGE_COMPARE_SUBJECTKEYIDENTIFIER:
527 case MESSAGE_COMPARE_FINGERPRINT_SHA1:
528 case MESSAGE_COMPARE_FINGERPRINT_SHA2:
529 case MESSAGE_COMPARE_FINGERPRINT_SHAng:
530 case MESSAGE_COMPARE_CERTOBJ:
531 targetType = OBJECT_TYPE_CERTIFICATE;
532 break;
533
534 default:
535 retIntError();
536 }
537
538 /* Route the message through to the appropriate object */
539 status = findTargetType( originalObjectHandle, targetObjectHandle,
540 targetType );
541 if( cryptStatusError( status ) )
542 return( CRYPT_ARGERROR_OBJECT );
543
544 /* Postcondition: We've found a valid target object */
545 ENSURES( isValidObject( *targetObjectHandle ) && \
546 isSameOwningObject( originalObjectHandle, \
547 *targetObjectHandle ) );
548
549 return( CRYPT_OK );
550 }
551
552 /****************************************************************************
553 * *
554 * Message Dispatch ACL *
555 * *
556 ****************************************************************************/
557
558 /* Each message type has certain properties such as whether it's routable,
559 which object types it applies to, what checks are performed on it, whether
560 it's processed by the kernel or dispatched to an object, etc etc. These
561 are all defined in the following table.
562
563 In addition to the usual checks, we also make various assertions about the
564 parameters we're passed. Note that these don't check user data (that's
565 checked programmatically and an error code returned) but values passed by
566 cryptlib code */
567
568 typedef enum {
569 PARAMTYPE_NONE_NONE, /* Data = 0, value = 0 */
570 PARAMTYPE_NONE = PARAMTYPE_NONE_NONE,/* For code analyser */
571 PARAMTYPE_NONE_ANY, /* Data = 0, value = any */
572 PARAMTYPE_NONE_BOOLEAN, /* Data = 0, value = boolean */
573 PARAMTYPE_NONE_CHECKTYPE,/* Data = 0, value = check type */
574 PARAMTYPE_DATA_NONE, /* Data, value = 0 */
575 PARAMTYPE_DATA_ANY, /* Data, value = any */
576 PARAMTYPE_DATA_ATTRIBUTE,/* Data, value = attribute type */
577 PARAMTYPE_DATA_LENGTH, /* Data, value >= 0 */
578 PARAMTYPE_DATA_OBJTYPE, /* Data, value = object type */
579 PARAMTYPE_DATA_MECHTYPE,/* Data, value = mechanism type */
580 PARAMTYPE_DATA_ITEMTYPE,/* Data, value = keymgmt.item type */
581 PARAMTYPE_DATA_FORMATTYPE,/* Data, value = cert format type */
582 PARAMTYPE_DATA_COMPARETYPE,/* Data, value = compare type */
583 PARAMTYPE_DATA_SETDEPTYPE,/* Data, value = setdep.option type */
584 PARAMTYPE_DATA_CERTMGMTTYPE,/* Data, value = cert.mgmt.type */
585 PARAMTYPE_ANY_USERMGMTTYPE,/* Data = any, value = user mgmt.type */
586 PARAMTYPE_ANY_TRUSTMGMTTYPE,/* Data = any, value = trust mgmt.type */
587 PARAMTYPE_LAST /* Last possible parameter check type */
588 } PARAMCHECK_TYPE;
589
590 /* Symbolic defines for message handling types, used to make it clearer
591 what's going on
592
593 PRE_DISPATCH - Action before message is dispatched
594 POST_DISPATCH - Action after message is dispatched
595 HANDLE_INTERNAL - Message handled by the kernel */
596
597 #define PRE_DISPATCH( function ) preDispatch##function, NULL
598 #define POST_DISPATCH( function ) NULL, postDispatch##function
599 #define PRE_POST_DISPATCH( preFunction, postFunction ) \
600 preDispatch##preFunction, postDispatch##postFunction
601 #define HANDLE_INTERNAL( function ) NULL, NULL, MESSAGE_HANDLING_FLAG_INTERNAL, function
602
603 /* Flags to indicate (potential) special-case handling for a message. These
604 are:
605
606 FLAG_INTERNAL: The message is handled internally by the kernel rather
607 than being sent to an external handler.
608
609 FLAG_MAYUNLOCK: The message handler may unlock the object (via
610 krnlReleaseObject()) to allow other threads access. In this
611 case the first parameter to the handler function should be a
612 MESSAGE_FUNCTION_EXTINFO structure to contain unlocking
613 information */
614
615 #define MESSAGE_HANDLING_FLAG_NONE 0 /* No special handling */
616 #define MESSAGE_HANDLING_FLAG_MAYUNLOCK 1 /* Handler may unlock object */
617 #define MESSAGE_HANDLING_FLAG_INTERNAL 2 /* Message handle by kernel */
618
619 /* The handling information, declared in the order in which it's applied */
620
621 typedef CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
622 int ( *PREDISPATCH_FUNCTION )( IN_HANDLE const int objectHandle,
623 IN_MESSAGE const MESSAGE_TYPE message,
624 const void *messageDataPtr,
625 const int messageValue, const void *auxInfo );
626 typedef CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
627 int ( *POSTDISPATCH_FUNCTION )( IN_HANDLE const int objectHandle,
628 IN_MESSAGE const MESSAGE_TYPE message,
629 const void *messageDataPtr,
630 const int messageValue, const void *auxInfo );
631 typedef CHECK_RETVAL \
632 int ( *INTERNALHANDLER_FUNCTION )( IN_HANDLE const int objectHandle,
633 const int arg1, const void *arg2,
634 const BOOLEAN isInternal );
635
636 typedef struct {
637 /* The message type, used for consistency checking */
638 const MESSAGE_TYPE messageType;
639
640 /* Message routing information if the message is routable. If the target
641 is implicitly determined via the message value, the routing target is
642 OBJECT_TYPE_NONE; if the target is explicitly determined, the routing
643 target is identified in the target. If the routing function is null,
644 the message isn't routed */
645 const long routingTarget; /* Target type if routable */
646 ROUTING_FUNCTION routingFunction;
647
648 /* Object type checking information: Object subtypes for which this
649 message is valid (for object-type-specific message) */
650 const OBJECT_SUBTYPE subTypeA, subTypeB, subTypeC;
651 /* Object subtype for which msg.valid */
652
653 /* Message type checking information used to assertion-check the function
654 preconditions */
655 const PARAMCHECK_TYPE paramCheck; /* Parameter check assertion type */
656
657 /* Pre- and post-message-dispatch handlers. These perform any additional
658 checking and processing that may be necessary before and after a
659 message is dispatched to an object */
660 PREDISPATCH_FUNCTION preDispatchFunction;
661 POSTDISPATCH_FUNCTION postDispatchFunction;
662
663 /* Flags to indicate (potential) special-case handling for this message,
664 and the (optional) internal handler function that's used if the
665 message is handled directly by the kernel */
666 int flags; /* Special-case handling flags */
667 INTERNALHANDLER_FUNCTION internalHandlerFunction;
668 } MESSAGE_HANDLING_INFO;
669
670 static const MESSAGE_HANDLING_INFO FAR_BSS messageHandlingInfo[] = {
671 { MESSAGE_NONE, ROUTE_NONE, 0, 0, 0, PARAMTYPE_NONE_NONE },
672
673 /* Control messages. These messages aren't routed, are valid for all
674 object types and subtypes, take no (or minimal) parameters, and are
675 handled by the kernel */
676 { MESSAGE_DESTROY, /* Destroy the object */
677 ROUTE_NONE, ST_ANY_A, ST_ANY_B, ST_ANY_C,
678 PARAMTYPE_NONE_NONE,
679 PRE_POST_DISPATCH( SignalDependentObjects, SignalDependentDevices ) },
680 { MESSAGE_INCREFCOUNT, /* Increment object ref.count */
681 ROUTE_NONE, ST_ANY_A, ST_ANY_B, ST_ANY_C,
682 PARAMTYPE_NONE_NONE,
683 HANDLE_INTERNAL( incRefCount ) },
684 { MESSAGE_DECREFCOUNT, /* Decrement object ref.count */
685 ROUTE_NONE, ST_ANY_A, ST_ANY_B, ST_ANY_C,
686 PARAMTYPE_NONE_NONE,
687 HANDLE_INTERNAL( decRefCount ) },
688 { MESSAGE_GETDEPENDENT, /* Get dependent object */
689 ROUTE_NONE, ST_ANY_A, ST_ANY_B, ST_ANY_C,
690 PARAMTYPE_DATA_OBJTYPE,
691 HANDLE_INTERNAL( getDependentObject ) },
692 { MESSAGE_SETDEPENDENT, /* Set dependent object (e.g. ctx->dev) */
693 ROUTE_NONE, ST_ANY_A, ST_ANY_B, ST_ANY_C,
694 PARAMTYPE_DATA_SETDEPTYPE,
695 HANDLE_INTERNAL( setDependentObject ) },
696 { MESSAGE_CLONE, /* Clone the object (only valid for ctxs) */
697 ROUTE_FIXED( OBJECT_TYPE_CONTEXT ), ST_CTX_CONV | ST_CTX_HASH, ST_NONE, ST_NONE,
698 PARAMTYPE_NONE_ANY,
699 HANDLE_INTERNAL( cloneObject ) },
700
701 /* Attribute messages. These messages are implicitly routed by attribute
702 type, more specific checking is performed using the attribute ACL's */
703 { MESSAGE_GETATTRIBUTE, /* Get numeric object attribute */
704 ROUTE_IMPLICIT, ST_ANY_A, ST_ANY_B, ST_ANY_C,
705 PARAMTYPE_DATA_ATTRIBUTE,
706 PRE_POST_DISPATCH( CheckAttributeAccess, MakeObjectExternal ) },
707 { MESSAGE_GETATTRIBUTE_S, /* Get string object attribute */
708 ROUTE_IMPLICIT, ST_ANY_A, ST_ANY_B, ST_ANY_C,
709 PARAMTYPE_DATA_ATTRIBUTE,
710 PRE_DISPATCH( CheckAttributeAccess ) },
711 { MESSAGE_SETATTRIBUTE, /* Set numeric object attribute */
712 ROUTE_IMPLICIT, ST_ANY_A, ST_ANY_B, ST_ANY_C,
713 PARAMTYPE_DATA_ATTRIBUTE,
714 PRE_POST_DISPATCH( CheckAttributeAccess, ChangeStateOpt ) },
715 { MESSAGE_SETATTRIBUTE_S, /* Set string object attribute */
716 ROUTE_IMPLICIT, ST_ANY_A, ST_ANY_B, ST_ANY_C,
717 PARAMTYPE_DATA_ATTRIBUTE,
718 PRE_POST_DISPATCH( CheckAttributeAccess, ChangeStateOpt ) },
719 { MESSAGE_DELETEATTRIBUTE, /* Delete object attribute */
720 ROUTE_IMPLICIT, ST_CTX_ANY | ST_CERT_ANY, ST_NONE, ST_SESS_ANY | ST_USER_NORMAL | ST_USER_SO,
721 PARAMTYPE_NONE_ANY,
722 PRE_DISPATCH( CheckAttributeAccess ) },
723
724 /* General messages to objects */
725 { MESSAGE_COMPARE, /* Compare objs.or obj.properties */
726 ROUTE_SPECIAL( CompareMessageTarget ), ST_CTX_ANY | ST_CERT_ANY, ST_NONE, ST_NONE,
727 PARAMTYPE_DATA_COMPARETYPE,
728 PRE_DISPATCH( CheckCompareParam ) },
729 { MESSAGE_CHECK, /* Check object info */
730 ROUTE_NONE, ST_ANY_A, ST_ANY_B, ST_ANY_C,
731 PARAMTYPE_NONE_CHECKTYPE,
732 PRE_POST_DISPATCH( CheckCheckParam, ForwardToDependentObject ) },
733 { MESSAGE_SELFTEST, /* Perform a self-test */
734 ROUTE_FIXED( OBJECT_TYPE_DEVICE ), ST_NONE, ST_DEV_SYSTEM, ST_NONE,
735 PARAMTYPE_NONE_NONE,
736 NULL, NULL,
737 MESSAGE_HANDLING_FLAG_MAYUNLOCK },
738
739 /* Messages sent from the kernel to object message handlers. These
740 messages are sent directly to the object from inside the kernel in
741 response to a control message, so we set the checking to disallow
742 everything to catch any that arrive from outside */
743 { MESSAGE_CHANGENOTIFY, /* Notification of obj.status chge.*/
744 ROUTE_NONE, ST_NONE, ST_NONE, ST_NONE, PARAMTYPE_NONE_NONE },
745
746 /* Object-type-specific messages: Contexts */
747 { MESSAGE_CTX_ENCRYPT, /* Context: Action = encrypt */
748 ROUTE( OBJECT_TYPE_CONTEXT ), ST_CTX_CONV | ST_CTX_PKC, ST_NONE, ST_NONE,
749 PARAMTYPE_DATA_LENGTH,
750 PRE_POST_DISPATCH( CheckActionAccess, UpdateUsageCount ) },
751 { MESSAGE_CTX_DECRYPT, /* Context: Action = decrypt */
752 ROUTE( OBJECT_TYPE_CONTEXT ), ST_CTX_CONV | ST_CTX_PKC, ST_NONE, ST_NONE,
753 PARAMTYPE_DATA_LENGTH,
754 PRE_POST_DISPATCH( CheckActionAccess, UpdateUsageCount ) },
755 { MESSAGE_CTX_SIGN, /* Context: Action = sign */
756 ROUTE( OBJECT_TYPE_CONTEXT ), ST_CTX_PKC, ST_NONE, ST_NONE,
757 PARAMTYPE_DATA_LENGTH,
758 PRE_POST_DISPATCH( CheckActionAccess, UpdateUsageCount ) },
759 { MESSAGE_CTX_SIGCHECK, /* Context: Action = sigcheck */
760 ROUTE( OBJECT_TYPE_CONTEXT ), ST_CTX_PKC, ST_NONE, ST_NONE,
761 PARAMTYPE_DATA_LENGTH,
762 PRE_POST_DISPATCH( CheckActionAccess, UpdateUsageCount ) },
763 { MESSAGE_CTX_HASH, /* Context: Action = hash */
764 ROUTE( OBJECT_TYPE_CONTEXT ), ST_CTX_HASH | ST_CTX_MAC, ST_NONE, ST_NONE,
765 PARAMTYPE_DATA_LENGTH,
766 PRE_POST_DISPATCH( CheckActionAccess, UpdateUsageCount ) },
767 { MESSAGE_CTX_GENKEY, /* Context: Generate a key */
768 ROUTE( OBJECT_TYPE_CONTEXT ),
769 ST_CTX_CONV | ST_CTX_PKC | ST_CTX_MAC | ST_CTX_GENERIC, ST_NONE, ST_NONE,
770 PARAMTYPE_NONE_NONE,
771 PRE_POST_DISPATCH( CheckState, ChangeState ) },
772 { MESSAGE_CTX_GENIV, /* Context: Generate an IV */
773 ROUTE( OBJECT_TYPE_CONTEXT ), ST_CTX_CONV, ST_NONE, ST_NONE,
774 PARAMTYPE_NONE_NONE },
775
776 /* Object-type-specific messages: Certificates */
777 { MESSAGE_CRT_SIGN, /* Cert: Action = sign certificate */
778 ROUTE( OBJECT_TYPE_CERTIFICATE ),
779 ST_CERT_ANY_CERT | ST_CERT_ATTRCERT | ST_CERT_CRL | \
780 ST_CERT_OCSP_REQ | ST_CERT_OCSP_RESP, ST_NONE, ST_NONE,
781 PARAMTYPE_NONE_ANY,
782 PRE_POST_DISPATCH( CheckStateParamHandle, ChangeState ) },
783 { MESSAGE_CRT_SIGCHECK, /* Cert: Action = check/verify certificate */
784 ROUTE( OBJECT_TYPE_CERTIFICATE ),
785 ST_CERT_ANY_CERT | ST_CERT_ATTRCERT | ST_CERT_CRL | \
786 ST_CERT_RTCS_RESP | ST_CERT_OCSP_RESP, ST_NONE, ST_NONE,
787 PARAMTYPE_NONE_ANY,
788 PRE_DISPATCH( CheckParamHandleOpt ) },
789 { MESSAGE_CRT_EXPORT, /* Cert: Export encoded certificate data */
790 ROUTE( OBJECT_TYPE_CERTIFICATE ), ST_CERT_ANY, ST_NONE, ST_NONE,
791 PARAMTYPE_DATA_FORMATTYPE,
792 PRE_DISPATCH( CheckExportAccess ) },
793
794 /* Object-type-specific messages: Devices */
795 { MESSAGE_DEV_QUERYCAPABILITY, /* Device: Query capability */
796 ROUTE_FIXED( OBJECT_TYPE_DEVICE ), ST_NONE, ST_DEV_ANY, ST_NONE,
797 PARAMTYPE_DATA_ANY },
798 { MESSAGE_DEV_EXPORT, /* Device: Action = export key */
799 ROUTE( OBJECT_TYPE_DEVICE ), ST_NONE, ST_DEV_ANY, ST_NONE,
800 PARAMTYPE_DATA_MECHTYPE,
801 PRE_DISPATCH( CheckMechanismWrapAccess ),
802 MESSAGE_HANDLING_FLAG_MAYUNLOCK },
803 { MESSAGE_DEV_IMPORT, /* Device: Action = import key */
804 ROUTE( OBJECT_TYPE_DEVICE ), ST_NONE, ST_DEV_ANY, ST_NONE,
805 PARAMTYPE_DATA_MECHTYPE,
806 PRE_DISPATCH( CheckMechanismWrapAccess ),
807 MESSAGE_HANDLING_FLAG_MAYUNLOCK },
808 { MESSAGE_DEV_SIGN, /* Device: Action = sign */
809 ROUTE( OBJECT_TYPE_DEVICE ), ST_NONE, ST_DEV_ANY, ST_NONE,
810 PARAMTYPE_DATA_MECHTYPE,
811 PRE_DISPATCH( CheckMechanismSignAccess ),
812 MESSAGE_HANDLING_FLAG_MAYUNLOCK },
813 { MESSAGE_DEV_SIGCHECK, /* Device: Action = sig.check */
814 ROUTE( OBJECT_TYPE_DEVICE ), ST_NONE, ST_DEV_ANY, ST_NONE,
815 PARAMTYPE_DATA_MECHTYPE,
816 PRE_DISPATCH( CheckMechanismSignAccess ),
817 MESSAGE_HANDLING_FLAG_MAYUNLOCK },
818 { MESSAGE_DEV_DERIVE, /* Device: Action = derive key */
819 ROUTE( OBJECT_TYPE_DEVICE ), ST_NONE, ST_DEV_ANY, ST_NONE,
820 PARAMTYPE_DATA_MECHTYPE,
821 PRE_DISPATCH( CheckMechanismDeriveAccess ),
822 MESSAGE_HANDLING_FLAG_MAYUNLOCK },
823 { MESSAGE_DEV_KDF, /* Device: Action = KDF key */
824 ROUTE( OBJECT_TYPE_DEVICE ), ST_NONE, ST_DEV_ANY, ST_NONE,
825 PARAMTYPE_DATA_MECHTYPE,
826 PRE_DISPATCH( CheckMechanismKDFAccess ),
827 MESSAGE_HANDLING_FLAG_MAYUNLOCK },
828 { MESSAGE_DEV_CREATEOBJECT, /* Device: Create object */
829 ROUTE_FIXED( OBJECT_TYPE_DEVICE ), ST_NONE, ST_DEV_ANY, ST_NONE,
830 PARAMTYPE_DATA_OBJTYPE,
831 PRE_POST_DISPATCH( CheckCreate, MakeObjectExternal ),
832 MESSAGE_HANDLING_FLAG_MAYUNLOCK },
833 { MESSAGE_DEV_CREATEOBJECT_INDIRECT,/* Device: Create obj.from data */
834 ROUTE_FIXED( OBJECT_TYPE_DEVICE ), ST_NONE, ST_DEV_ANY, ST_NONE,
835 PARAMTYPE_DATA_OBJTYPE,
836 PRE_POST_DISPATCH( CheckCreate, MakeObjectExternal ),
837 MESSAGE_HANDLING_FLAG_MAYUNLOCK },
838
839 /* Object-type-specific messages: Envelopes */
840 { MESSAGE_ENV_PUSHDATA, /* Envelope: Push data */
841 ROUTE_FIXED_ALT( OBJECT_TYPE_ENVELOPE, OBJECT_TYPE_SESSION ),
842 ST_NONE, ST_ENV_ANY, ST_SESS_ANY_DATA,
843 PARAMTYPE_DATA_NONE,
844 PRE_DISPATCH( CheckData ) },
845 { MESSAGE_ENV_POPDATA, /* Envelope: Pop data */
846 ROUTE_FIXED_ALT( OBJECT_TYPE_ENVELOPE, OBJECT_TYPE_SESSION ),
847 ST_NONE, ST_ENV_ANY, ST_SESS_ANY_DATA,
848 PARAMTYPE_DATA_NONE,
849 PRE_DISPATCH( CheckData ) },
850
851 /* Object-type-specific messages: Keysets */
852 { MESSAGE_KEY_GETKEY, /* Keyset: Instantiate ctx/certificate */
853 ROUTE_FIXED_ALT( OBJECT_TYPE_KEYSET, OBJECT_TYPE_DEVICE ),
854 ST_NONE, ST_KEYSET_ANY | ST_DEV_ANY_STD, ST_NONE,
855 PARAMTYPE_DATA_ITEMTYPE,
856 PRE_POST_DISPATCH( CheckKeysetAccess, MakeObjectExternal ) },
857 { MESSAGE_KEY_SETKEY, /* Keyset: Add ctx/certificate */
858 ROUTE_FIXED_ALT( OBJECT_TYPE_KEYSET, OBJECT_TYPE_DEVICE ),
859 ST_NONE, ST_KEYSET_ANY | ST_DEV_ANY_STD, ST_NONE,
860 PARAMTYPE_DATA_ITEMTYPE,
861 PRE_DISPATCH( CheckKeysetAccess ) },
862 { MESSAGE_KEY_DELETEKEY, /* Keyset: Delete key */
863 ROUTE_FIXED_ALT( OBJECT_TYPE_KEYSET, OBJECT_TYPE_DEVICE ),
864 ST_NONE, ST_KEYSET_ANY | ST_DEV_ANY_STD, ST_NONE,
865 PARAMTYPE_DATA_ITEMTYPE,
866 PRE_DISPATCH( CheckKeysetAccess ) },
867 { MESSAGE_KEY_GETFIRSTCERT, /* Keyset: Get first cert in sequence */
868 ROUTE_FIXED_ALT( OBJECT_TYPE_KEYSET, OBJECT_TYPE_DEVICE ),
869 ST_NONE, ST_KEYSET_ANY | ST_DEV_ANY_STD, ST_NONE,
870 PARAMTYPE_DATA_ITEMTYPE,
871 PRE_DISPATCH( CheckKeysetAccess ) },
872 { MESSAGE_KEY_GETNEXTCERT, /* Keyset: Get next cert in sequence */
873 ROUTE_FIXED_ALT( OBJECT_TYPE_KEYSET, OBJECT_TYPE_DEVICE ),
874 ST_NONE, ST_KEYSET_ANY | ST_DEV_ANY_STD, ST_NONE,
875 PARAMTYPE_DATA_ITEMTYPE,
876 PRE_POST_DISPATCH( CheckKeysetAccess, MakeObjectExternal ) },
877 { MESSAGE_KEY_CERTMGMT, /* Keyset: Certificate management */
878 ROUTE_FIXED( OBJECT_TYPE_KEYSET ),
879 ST_NONE, ST_KEYSET_DBMS_STORE, ST_NONE,
880 PARAMTYPE_DATA_CERTMGMTTYPE,
881 PRE_POST_DISPATCH( CheckCertMgmtAccess, MakeObjectExternal ) },
882
883 /* Object-type-specific messages: Users */
884 { MESSAGE_USER_USERMGMT, /* User: User management */
885 ROUTE_FIXED( OBJECT_TYPE_USER ), ST_NONE, ST_NONE, ST_USER_SO,
886 PARAMTYPE_ANY_USERMGMTTYPE,
887 PRE_POST_DISPATCH( CheckUserMgmtAccess, HandleZeroise ) },
888 { MESSAGE_USER_TRUSTMGMT, /* User: Trust management */
889 ROUTE_FIXED( OBJECT_TYPE_USER ), ST_NONE, ST_NONE, ST_USER_SO,
890 PARAMTYPE_ANY_TRUSTMGMTTYPE,
891 PRE_DISPATCH( CheckTrustMgmtAccess ) },
892
893 /* End-of-ACL marker */
894 { MESSAGE_NONE, ROUTE_NONE, 0, PARAMTYPE_NONE_NONE },
895 { MESSAGE_NONE, ROUTE_NONE, 0, PARAMTYPE_NONE_NONE }
896 };
897
898 /* Check the basic validity of message parameters. Note that this only
899 checks for coding errors (krnlSendMessage() having been called
900 correctly), it doesn't perform parameter validation, which is the
901 job of the full ACL checks */
902
903 CHECK_RETVAL_BOOL
checkParams(IN_ENUM (PARAMTYPE)const PARAMCHECK_TYPE paramCheck,const void * messageDataPtr,const int messageValue)904 static BOOLEAN checkParams( IN_ENUM( PARAMTYPE ) \
905 const PARAMCHECK_TYPE paramCheck,
906 const void *messageDataPtr,
907 const int messageValue )
908 {
909 REQUIRES_B( paramCheck >= PARAMTYPE_NONE_NONE && \
910 paramCheck < PARAMTYPE_LAST );
911
912 switch( paramCheck )
913 {
914 case PARAMTYPE_NONE_NONE:
915 return( messageDataPtr == NULL && messageValue == 0 );
916
917 case PARAMTYPE_NONE_ANY:
918 return( messageDataPtr == NULL );
919
920 case PARAMTYPE_NONE_BOOLEAN:
921 return( messageDataPtr == NULL && \
922 ( messageValue == FALSE || messageValue == TRUE ) );
923
924 case PARAMTYPE_NONE_CHECKTYPE:
925 return( messageDataPtr == NULL && \
926 ( messageValue > MESSAGE_CHECK_NONE && \
927 messageValue < MESSAGE_CHECK_LAST ) );
928
929 case PARAMTYPE_DATA_NONE:
930 return( messageDataPtr != NULL && messageValue == 0 );
931
932 case PARAMTYPE_DATA_ANY:
933 return( messageDataPtr != NULL );
934
935 case PARAMTYPE_DATA_ATTRIBUTE:
936 return( messageDataPtr != NULL && \
937 ( ( messageValue > CRYPT_ATTRIBUTE_NONE && \
938 messageValue < CRYPT_ATTRIBUTE_LAST ) || \
939 ( messageValue > CRYPT_IATTRIBUTE_FIRST && \
940 messageValue < CRYPT_IATTRIBUTE_LAST ) ) );
941
942 case PARAMTYPE_DATA_LENGTH:
943 return( messageDataPtr != NULL && messageValue >= 0 );
944
945 case PARAMTYPE_DATA_OBJTYPE:
946 return( messageDataPtr != NULL && \
947 ( messageValue > OBJECT_TYPE_NONE && \
948 messageValue < OBJECT_TYPE_LAST ) );
949
950 case PARAMTYPE_DATA_MECHTYPE:
951 return( messageDataPtr != NULL && \
952 ( messageValue > MECHANISM_NONE && \
953 messageValue < MECHANISM_LAST ) );
954
955 case PARAMTYPE_DATA_ITEMTYPE:
956 return( messageDataPtr != NULL && \
957 ( messageValue > KEYMGMT_ITEM_NONE && \
958 messageValue < KEYMGMT_ITEM_LAST ) );
959
960 case PARAMTYPE_DATA_FORMATTYPE:
961 return( messageDataPtr != NULL && \
962 ( messageValue > CRYPT_CERTFORMAT_NONE && \
963 messageValue < CRYPT_CERTFORMAT_LAST ) );
964
965 case PARAMTYPE_DATA_COMPARETYPE:
966 return( messageDataPtr != NULL && \
967 ( messageValue > MESSAGE_COMPARE_NONE && \
968 messageValue < MESSAGE_COMPARE_LAST ) );
969
970 case PARAMTYPE_DATA_SETDEPTYPE:
971 return( messageDataPtr != NULL && \
972 messageValue > SETDEP_OPTION_NONE && \
973 messageValue < SETDEP_OPTION_LAST );
974
975 case PARAMTYPE_DATA_CERTMGMTTYPE:
976 return( messageDataPtr != NULL && \
977 messageValue > CRYPT_CERTACTION_NONE && \
978 messageValue < CRYPT_CERTACTION_LAST );
979
980 case PARAMTYPE_ANY_USERMGMTTYPE:
981 return( messageValue > MESSAGE_USERMGMT_NONE && \
982 messageValue < MESSAGE_USERMGMT_LAST );
983
984 case PARAMTYPE_ANY_TRUSTMGMTTYPE:
985 return( messageValue > MESSAGE_TRUSTMGMT_NONE && \
986 messageValue < MESSAGE_TRUSTMGMT_LAST );
987
988 default:
989 retIntError_Boolean();
990 }
991
992 retIntError_Boolean();
993 }
994
995 /****************************************************************************
996 * *
997 * Init/Shutdown Functions *
998 * *
999 ****************************************************************************/
1000
1001 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
initSendMessage(INOUT KERNEL_DATA * krnlDataPtr)1002 int initSendMessage( INOUT KERNEL_DATA *krnlDataPtr )
1003 {
1004 int i;
1005
1006 assert( isWritePtr( krnlDataPtr, sizeof( KERNEL_DATA ) ) );
1007
1008 /* If we're running a fuzzing build, skip the lengthy self-checks */
1009 #ifdef CONFIG_FUZZ
1010 krnlData = krnlDataPtr;
1011 return( CRYPT_OK );
1012 #endif /* CONFIG_FUZZ */
1013
1014 /* Perform a consistency check on various things that need to be set
1015 up in a certain way for things to work properly */
1016 static_assert( MESSAGE_CTX_DECRYPT == MESSAGE_CTX_ENCRYPT + 1, \
1017 "Message value" );
1018 static_assert( MESSAGE_CTX_SIGN == MESSAGE_CTX_DECRYPT + 1, \
1019 "Message value" );
1020 static_assert( MESSAGE_CTX_SIGCHECK == MESSAGE_CTX_SIGN + 1, \
1021 "Message value" );
1022 static_assert( MESSAGE_CTX_HASH == MESSAGE_CTX_SIGCHECK + 1, \
1023 "Message value" );
1024 static_assert( MESSAGE_CTX_GENKEY == MESSAGE_CTX_HASH + 1, \
1025 "Message value" );
1026 static_assert( MESSAGE_GETATTRIBUTE_S == MESSAGE_GETATTRIBUTE + 1, \
1027 "Message value" );
1028 static_assert( MESSAGE_SETATTRIBUTE == MESSAGE_GETATTRIBUTE_S + 1, \
1029 "Message value" );
1030 static_assert( MESSAGE_SETATTRIBUTE_S == MESSAGE_SETATTRIBUTE + 1, \
1031 "Message value" );
1032 static_assert( MESSAGE_DELETEATTRIBUTE == MESSAGE_SETATTRIBUTE_S + 1, \
1033 "Message value" );
1034
1035 /* Perform a consistency check on various internal values and constants */
1036 assert( ACTION_PERM_COUNT == 6 );
1037
1038 /* Perform a consistency check on the parameter ACL */
1039 for( i = 0; messageParamACLTbl[ i ].type != MESSAGE_NONE && \
1040 i < FAILSAFE_ARRAYSIZE( messageParamACLTbl, MESSAGE_ACL );
1041 i++ )
1042 {
1043 const MESSAGE_ACL *messageParamACL = &messageParamACLTbl[ i ];
1044
1045 ENSURES( isParamMessage( messageParamACL->type ) && \
1046 !( messageParamACL->objectACL.subTypeA & ( SUBTYPE_CLASS_B | \
1047 SUBTYPE_CLASS_C ) ) && \
1048 !( messageParamACL->objectACL.subTypeB & ( SUBTYPE_CLASS_A | \
1049 SUBTYPE_CLASS_C ) ) && \
1050 !( messageParamACL->objectACL.subTypeC & ( SUBTYPE_CLASS_A | \
1051 SUBTYPE_CLASS_B ) ) );
1052 }
1053 ENSURES( i < FAILSAFE_ARRAYSIZE( messageParamACLTbl, MESSAGE_ACL ) );
1054
1055 /* Perform a consistency check on the message handling information */
1056 for( i = MESSAGE_NONE + 1; i < MESSAGE_LAST; i++ )
1057 {
1058 const MESSAGE_HANDLING_INFO *messageInfo = &messageHandlingInfo[ i ];
1059
1060 ENSURES( messageInfo->messageType == i && \
1061 messageInfo->paramCheck >= PARAMTYPE_NONE_NONE && \
1062 messageInfo->paramCheck < PARAMTYPE_LAST );
1063 ENSURES( ( messageInfo->messageType >= MESSAGE_ENV_PUSHDATA && \
1064 messageInfo->messageType <= MESSAGE_KEY_GETNEXTCERT ) || \
1065 ( messageInfo->routingTarget >= OBJECT_TYPE_NONE && \
1066 messageInfo->routingTarget <= OBJECT_TYPE_LAST ) );
1067 ENSURES( messageInfo->messageType == MESSAGE_CLONE || \
1068 messageInfo->messageType == MESSAGE_COMPARE || \
1069 ( messageInfo->routingTarget == OBJECT_TYPE_NONE && \
1070 messageInfo->routingFunction == NULL ) || \
1071 ( messageInfo->routingTarget != OBJECT_TYPE_NONE && \
1072 messageInfo->routingFunction != NULL ) );
1073 ENSURES( !( messageInfo->subTypeA & ( SUBTYPE_CLASS_B | \
1074 SUBTYPE_CLASS_C ) ) && \
1075 !( messageInfo->subTypeB & ( SUBTYPE_CLASS_A | \
1076 SUBTYPE_CLASS_C ) ) && \
1077 !( messageInfo->subTypeC & ( SUBTYPE_CLASS_A | \
1078 SUBTYPE_CLASS_B ) ) );
1079 ENSURES( ( messageInfo->flags & MESSAGE_HANDLING_FLAG_INTERNAL ) || \
1080 messageInfo->messageType == MESSAGE_SELFTEST || \
1081 messageInfo->messageType == MESSAGE_CHANGENOTIFY || \
1082 messageInfo->messageType == MESSAGE_CTX_GENIV || \
1083 messageInfo->messageType == MESSAGE_DEV_QUERYCAPABILITY || \
1084 messageInfo->preDispatchFunction != NULL );
1085 ENSURES( messageInfo->messageType == MESSAGE_SELFTEST || \
1086 messageInfo->messageType == MESSAGE_CHANGENOTIFY || \
1087 messageInfo->messageType == MESSAGE_CTX_GENIV || \
1088 messageInfo->messageType == MESSAGE_DEV_QUERYCAPABILITY || \
1089 ( messageInfo->preDispatchFunction != NULL || \
1090 messageInfo->postDispatchFunction != NULL || \
1091 messageInfo->internalHandlerFunction != NULL ) );
1092 ENSURES( ( ( messageInfo->flags & MESSAGE_HANDLING_FLAG_INTERNAL ) && \
1093 messageInfo->internalHandlerFunction != NULL ) || \
1094 ( !( messageInfo->flags & MESSAGE_HANDLING_FLAG_INTERNAL ) && \
1095 messageInfo->internalHandlerFunction == NULL ) );
1096 }
1097
1098 /* Set up the reference to the kernel data block */
1099 krnlData = krnlDataPtr;
1100
1101 return( CRYPT_OK );
1102 }
1103
endSendMessage(void)1104 void endSendMessage( void )
1105 {
1106 krnlData = NULL;
1107 }
1108
1109 /****************************************************************************
1110 * *
1111 * Message Queue *
1112 * *
1113 ****************************************************************************/
1114
1115 /* Enqueue a message */
1116
1117 CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
enqueueMessage(IN_HANDLE const int objectHandle,const MESSAGE_HANDLING_INFO * handlingInfoPtr,IN_MESSAGE const MESSAGE_TYPE message,IN_OPT const void * messageDataPtr,const int messageValue)1118 static int enqueueMessage( IN_HANDLE const int objectHandle,
1119 const MESSAGE_HANDLING_INFO *handlingInfoPtr,
1120 IN_MESSAGE const MESSAGE_TYPE message,
1121 IN_OPT const void *messageDataPtr,
1122 const int messageValue )
1123 {
1124 MESSAGE_QUEUE_DATA *messageQueue = krnlData->messageQueue;
1125 int queuePos, i, iterationCount;
1126 ORIGINAL_INT_VAR( queueEnd, krnlData->queueEnd );
1127
1128 assert( isReadPtr( handlingInfoPtr, sizeof( MESSAGE_HANDLING_INFO ) ) );
1129
1130 /* Precondition: It's a valid message being sent to a valid object */
1131 REQUIRES( isValidObject( objectHandle ) );
1132 REQUIRES( isValidMessage( message & MESSAGE_MASK ) );
1133
1134 /* Sanity-check the state/make sure that we don't overflow the queue
1135 (this object is not responding to messages... now all we need is
1136 GPF's). We return a timeout error on overflow to indicate that there
1137 are too many messages queued for this (or other) objects */
1138 if( krnlData->queueEnd < 0 || \
1139 krnlData->queueEnd >= MESSAGE_QUEUE_SIZE - 1 )
1140 {
1141 ENSURES( krnlData->queueEnd >= 0 );
1142 DEBUG_DIAG(( "Invalid kernel message queue state" ));
1143 assert( DEBUG_WARN );
1144 return( CRYPT_ERROR_TIMEOUT );
1145 }
1146
1147 /* Precondition: There's room to enqueue the message */
1148 REQUIRES( krnlData->queueEnd >= 0 && \
1149 krnlData->queueEnd < MESSAGE_QUEUE_SIZE - 1 );
1150
1151 /* Check whether a message to this object is already present in the
1152 queue */
1153 for( queuePos = krnlData->queueEnd - 1, iterationCount = 0;
1154 queuePos >= 0 && iterationCount++ < MESSAGE_QUEUE_SIZE; queuePos-- )
1155 {
1156 if( messageQueue[ queuePos ].objectHandle == objectHandle )
1157 break;
1158 }
1159 ENSURES( iterationCount < MESSAGE_QUEUE_SIZE );
1160
1161 /* Postcondition: queuePos = -1 if not present, position in queue if
1162 present */
1163 ENSURES( queuePos == -1 || \
1164 ( queuePos >= 0 && queuePos < krnlData->queueEnd ) );
1165
1166 /* Sanity-check the queue positioning */
1167 ENSURES( queuePos >= -1 && queuePos < krnlData->queueEnd );
1168
1169 /* Enqueue the message:
1170
1171 +---------------+ +---------------+
1172 |.|.|x|x|y|z| | -> |.|.|x|x|#|y|z| |
1173 +---------------+ +---------------+
1174 ^ ^ ^ ^
1175 qPos qEnd qPos qEnd */
1176 queuePos++; /* Insert after current position */
1177 for( i = krnlData->queueEnd - 1, iterationCount = 0;
1178 i >= queuePos && iterationCount < MESSAGE_QUEUE_SIZE;
1179 i--, iterationCount++ )
1180 messageQueue[ i + 1 ] = messageQueue[ i ];
1181 ENSURES( iterationCount < MESSAGE_QUEUE_SIZE );
1182 memset( &messageQueue[ queuePos ], 0, sizeof( MESSAGE_QUEUE_DATA ) );
1183 messageQueue[ queuePos ].objectHandle = objectHandle;
1184 messageQueue[ queuePos ].handlingInfoPtr = handlingInfoPtr;
1185 messageQueue[ queuePos ].message = message;
1186 messageQueue[ queuePos ].messageDataPtr = messageDataPtr;
1187 messageQueue[ queuePos ].messageValue = messageValue;
1188 krnlData->queueEnd++;
1189
1190 /* Postcondition: The queue is within bounds and has grown by one
1191 element */
1192 ENSURES( krnlData->queueEnd > 0 && \
1193 krnlData->queueEnd <= MESSAGE_QUEUE_SIZE - 1 );
1194 ENSURES( krnlData->queueEnd == ORIGINAL_VALUE( queueEnd ) + 1 );
1195
1196 /* If a message for this object is already present tell the caller to
1197 defer processing */
1198 if( queuePos > 0 )
1199 return( OK_SPECIAL );
1200
1201 return( CRYPT_OK );
1202 }
1203
1204 /* Dequeue a message */
1205
1206 CHECK_RETVAL \
1207 static int dequeueMessage( IN_RANGE( 0, MESSAGE_QUEUE_SIZE ) \
1208 const int messagePosition )
1209 {
1210 MESSAGE_QUEUE_DATA *messageQueue = krnlData->messageQueue;
1211 int i, iterationCount;
1212 ORIGINAL_INT_VAR( queueEnd, krnlData->queueEnd );
1213
1214 /* Precondition: We're deleting a valid queue position */
1215 REQUIRES( messagePosition >= 0 && \
1216 messagePosition < krnlData->queueEnd );
1217 REQUIRES( krnlData->queueEnd > 0 && \
1218 krnlData->queueEnd < MESSAGE_QUEUE_SIZE );
1219
1220 /* Move the remaining messages down and clear the last entry */
1221 for( i = messagePosition, iterationCount = 0;
1222 i < krnlData->queueEnd - 1 && \
1223 iterationCount++ < MESSAGE_QUEUE_SIZE; i++ )
1224 messageQueue[ i ] = messageQueue[ i + 1 ];
1225 ENSURES( iterationCount < MESSAGE_QUEUE_SIZE );
1226 zeroise( &messageQueue[ krnlData->queueEnd - 1 ],
1227 sizeof( MESSAGE_QUEUE_DATA ) );
1228 krnlData->queueEnd--;
1229
1230 /* Postcondition: the queue is one element shorter, all queue entries
1231 are valid, and all non-queue entries are empty */
1232 ENSURES( krnlData->queueEnd == ORIGINAL_VALUE( queueEnd ) - 1 );
1233 ENSURES( krnlData->queueEnd >= 0 && \
1234 krnlData->queueEnd < MESSAGE_QUEUE_SIZE - 1 );
1235 FORALL( i, 0, krnlData->queueEnd,
1236 messageQueue[ i ].handlingInfoPtr != NULL );
1237 FORALL( i, krnlData->queueEnd, MESSAGE_QUEUE_SIZE,
1238 messageQueue[ i ].handlingInfoPtr == NULL );
1239
1240 return( CRYPT_OK );
1241 }
1242
1243 /* Get the next message in the queue */
1244
1245 CHECK_RETVAL_BOOL \
getNextMessage(IN_HANDLE const int objectHandle,OUT_OPT MESSAGE_QUEUE_DATA * messageQueueInfo)1246 static BOOLEAN getNextMessage( IN_HANDLE const int objectHandle,
1247 OUT_OPT MESSAGE_QUEUE_DATA *messageQueueInfo )
1248 {
1249 MESSAGE_QUEUE_DATA *messageQueue = krnlData->messageQueue;
1250 int i;
1251
1252 assert( messageQueueInfo == NULL || \
1253 isWritePtr( messageQueueInfo, sizeof( MESSAGE_QUEUE_DATA ) ) );
1254
1255 /* Preconditions: It's a valid object table entry. It's not necessarily
1256 a valid object since we may be de-queueing messages for it because
1257 it's just been destroyed */
1258 REQUIRES_B( objectHandle == SYSTEM_OBJECT_HANDLE || \
1259 objectHandle == DEFAULTUSER_OBJECT_HANDLE || \
1260 isHandleRangeValid( objectHandle ) );
1261
1262 /* Clear return value */
1263 if( messageQueueInfo != NULL )
1264 memset( messageQueueInfo, 0, sizeof( MESSAGE_QUEUE_DATA ) );
1265
1266 /* Sanity-check the state */
1267 ENSURES_B( krnlData->queueEnd >= 0 && \
1268 krnlData->queueEnd < MESSAGE_QUEUE_SIZE );
1269
1270 /* Find the next message for this object. Since other messages can have
1271 come and gone in the meantime, we have to scan from the start each
1272 time */
1273 for( i = 0; i < krnlData->queueEnd && i < MESSAGE_QUEUE_SIZE; i++ )
1274 {
1275 if( messageQueue[ i ].objectHandle == objectHandle )
1276 {
1277 int status;
1278
1279 if( messageQueueInfo != NULL )
1280 *messageQueueInfo = messageQueue[ i ];
1281 status = dequeueMessage( i );
1282 if( cryptStatusError( status ) )
1283 return( FALSE );
1284
1285 return( TRUE );
1286 }
1287 }
1288 ENSURES_B( i < MESSAGE_QUEUE_SIZE );
1289
1290 /* Postcondition: There are no more messages for this object present in
1291 the queue */
1292 FORALL( i, 0, krnlData->queueEnd,
1293 messageQueue[ i ].objectHandle != objectHandle );
1294
1295 return( FALSE );
1296 }
1297
1298 /* Dequeue all messages for an object in the queue */
1299
dequeueAllMessages(IN_HANDLE const int objectHandle)1300 static void dequeueAllMessages( IN_HANDLE const int objectHandle )
1301 {
1302 int iterationCount;
1303
1304 /* Preconditions: It's a valid object table entry. It's not necessarily
1305 a valid object since we may be de-queueing messages for it because
1306 it's just been destroyed */
1307 REQUIRES_V( objectHandle == SYSTEM_OBJECT_HANDLE || \
1308 objectHandle == DEFAULTUSER_OBJECT_HANDLE || \
1309 isHandleRangeValid( objectHandle ) );
1310
1311 /* Dequeue all messages for a given object */
1312 for( iterationCount = 0;
1313 getNextMessage( objectHandle, NULL ) && \
1314 iterationCount < MESSAGE_QUEUE_SIZE;
1315 iterationCount++ );
1316 ENSURES_V( iterationCount < MESSAGE_QUEUE_SIZE );
1317
1318 /* Postcondition: There are no more messages for this object present in
1319 the queue */
1320 FORALL( i, 0, krnlData->queueEnd,
1321 krnlData->messageQueue[ i ].objectHandle != objectHandle );
1322 }
1323
1324 /****************************************************************************
1325 * *
1326 * Message Dispatcher *
1327 * *
1328 ****************************************************************************/
1329
1330 /* Process a message that's handled internally by the kernel, for example
1331 one that accesses an object's kernel attributes */
1332
1333 CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
processInternalMessage(IN_HANDLE const int localObjectHandle,const MESSAGE_HANDLING_INFO * handlingInfoPtr,IN_MESSAGE const MESSAGE_TYPE message,IN_OPT void * messageDataPtr,const int messageValue,IN_OPT const void * aclPtr)1334 static int processInternalMessage( IN_HANDLE const int localObjectHandle,
1335 const MESSAGE_HANDLING_INFO *handlingInfoPtr,
1336 IN_MESSAGE const MESSAGE_TYPE message,
1337 IN_OPT void *messageDataPtr,
1338 const int messageValue,
1339 IN_OPT const void *aclPtr )
1340 {
1341 int status;
1342
1343 assert( isReadPtr( handlingInfoPtr, sizeof( MESSAGE_HANDLING_INFO ) ) );
1344
1345 /* Precondition: It's a valid message being sent to a valid object */
1346 REQUIRES( isValidObject( localObjectHandle ) );
1347 REQUIRES( isValidMessage( message & MESSAGE_MASK ) );
1348
1349 /* If there's a pre-dispatch handler, invoke it */
1350 if( handlingInfoPtr->preDispatchFunction != NULL )
1351 {
1352 status = handlingInfoPtr->preDispatchFunction( localObjectHandle,
1353 message, messageDataPtr, messageValue,
1354 aclPtr );
1355 if( cryptStatusError( status ) )
1356 return( status );
1357 }
1358
1359 /* Inner precondition: Either the message as a whole is internally
1360 handled or it's a property attribute */
1361 REQUIRES( handlingInfoPtr->internalHandlerFunction != NULL || \
1362 isAttributeMessage( message & MESSAGE_MASK ) );
1363
1364 /* If it's an object property attribute (which is handled by the kernel),
1365 get or set its value */
1366 if( handlingInfoPtr->internalHandlerFunction == NULL )
1367 {
1368 /* Precondition: Object properties are always numeric attributes,
1369 and there's always a message value present */
1370 REQUIRES( handlingInfoPtr->messageType == MESSAGE_GETATTRIBUTE || \
1371 handlingInfoPtr->messageType == MESSAGE_SETATTRIBUTE );
1372 REQUIRES( messageDataPtr != NULL );
1373
1374 if( handlingInfoPtr->messageType == MESSAGE_GETATTRIBUTE )
1375 status = getPropertyAttribute( localObjectHandle, messageValue,
1376 messageDataPtr );
1377 else
1378 status = setPropertyAttribute( localObjectHandle, messageValue,
1379 messageDataPtr );
1380 }
1381 else
1382 {
1383 /* It's a kernel-handled message, process it */
1384 status = handlingInfoPtr->internalHandlerFunction( localObjectHandle,
1385 messageValue, messageDataPtr,
1386 isInternalMessage( message ) );
1387 }
1388 if( cryptStatusError( status ) )
1389 {
1390 /* Postcondition: It's a genuine error, or a special-case condition
1391 such as the object creation being aborted, which produces an
1392 OK_SPECIAL status to tell the caller to convert the message that
1393 triggered this into a MESSAGE_DESTROY */
1394 ENSURES( cryptStatusError( status ) || status == OK_SPECIAL );
1395
1396 return( status );
1397 }
1398
1399 /* If there's a post-dispatch handler, invoke it */
1400 if( handlingInfoPtr->postDispatchFunction != NULL )
1401 {
1402 status = handlingInfoPtr->postDispatchFunction( localObjectHandle,
1403 message, messageDataPtr, messageValue,
1404 aclPtr );
1405 if( cryptStatusError( status ) )
1406 return( status );
1407 }
1408
1409 return( CRYPT_OK );
1410 }
1411
1412 /* Dispatch a message to an object */
1413
1414 CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3 ) ) \
dispatchMessage(IN_HANDLE const int localObjectHandle,const MESSAGE_QUEUE_DATA * messageQueueData,INOUT OBJECT_INFO * objectInfoPtr,IN_OPT const void * aclPtr)1415 static int dispatchMessage( IN_HANDLE const int localObjectHandle,
1416 const MESSAGE_QUEUE_DATA *messageQueueData,
1417 INOUT OBJECT_INFO *objectInfoPtr,
1418 IN_OPT const void *aclPtr )
1419 {
1420 const MESSAGE_HANDLING_INFO *handlingInfoPtr = \
1421 messageQueueData->handlingInfoPtr;
1422 const MESSAGE_FUNCTION messageFunction = \
1423 FNPTR_GET( objectInfoPtr->messageFunction );
1424 const MESSAGE_TYPE localMessage = \
1425 messageQueueData->message & MESSAGE_MASK;
1426 MESSAGE_FUNCTION_EXTINFO messageExtInfo;
1427 void *objectPtr = objectInfoPtr->objectPtr;
1428 BOOLEAN mayUnlock = FALSE;
1429 int status;
1430 ORIGINAL_INT_VAR( lockCount, objectInfoPtr->lockCount );
1431
1432 assert( isReadPtr( messageQueueData, sizeof( MESSAGE_QUEUE_DATA ) ) );
1433 assert( isWritePtr( objectInfoPtr, sizeof( OBJECT_INFO ) ) );
1434
1435 REQUIRES( isValidObject( localObjectHandle ) );
1436 REQUIRES( !isInUse( localObjectHandle ) || \
1437 isObjectOwner( localObjectHandle ) );
1438 ENSURES( messageFunction != NULL );
1439
1440 /* If there's a pre-dispatch handler present, apply it */
1441 if( handlingInfoPtr->preDispatchFunction != NULL )
1442 {
1443 status = handlingInfoPtr->preDispatchFunction( localObjectHandle,
1444 messageQueueData->message,
1445 messageQueueData->messageDataPtr,
1446 messageQueueData->messageValue,
1447 aclPtr );
1448 if( cryptStatusError( status ) )
1449 return( status );
1450 }
1451
1452 /* Some objects (generally the system object and to a lesser extent other
1453 devices and the default user object) may unlock themselves while
1454 processing a message when they forward the message elsewhere or perform
1455 non-object-specific processing. If this may be the case then we pass
1456 in an extended message structure to record this information */
1457 initMessageExtInfo( &messageExtInfo, objectPtr );
1458 if( ( objectInfoPtr->type == OBJECT_TYPE_DEVICE ) || \
1459 ( handlingInfoPtr->flags & MESSAGE_HANDLING_FLAG_MAYUNLOCK ) )
1460 {
1461 mayUnlock = TRUE;
1462 objectPtr = &messageExtInfo;
1463 }
1464
1465 /* Mark the object as busy so that we have it available for our
1466 exclusive use and further messages to it will be enqueued, dispatch
1467 the message with the object table unlocked, and mark the object as
1468 non-busy again */
1469 objectInfoPtr->lockCount++;
1470 #ifdef USE_THREADS
1471 objectInfoPtr->lockOwner = THREAD_SELF();
1472 #endif /* USE_THREADS */
1473 MUTEX_UNLOCK( objectTable );
1474 status = messageFunction( objectPtr, localMessage,
1475 ( MESSAGE_CAST ) messageQueueData->messageDataPtr,
1476 messageQueueData->messageValue );
1477 MUTEX_LOCK( objectTable );
1478 objectInfoPtr = &krnlData->objectTable[ localObjectHandle ];
1479 if( !isValidType( objectInfoPtr->type ) )
1480 retIntError(); /* Something catastrophic happened while unlocked */
1481 if( !( mayUnlock && isMessageObjectUnlocked( &messageExtInfo ) ) )
1482 objectInfoPtr->lockCount--;
1483
1484 /* Postcondition: The lock count is non-negative and, if it's not the
1485 system object, has been reset to its previous value */
1486 ENSURES( objectInfoPtr->lockCount >= 0 && \
1487 ( localObjectHandle == SYSTEM_OBJECT_HANDLE ||
1488 objectInfoPtr->lockCount == ORIGINAL_VALUE( lockCount ) ) );
1489
1490 /* If there's a post-dispatch handler present, apply it. Since a
1491 destroy object message always succeeds but can return an error code
1492 (typically CRYPT_ERROR_INCOMPLETE), we don't treat an error return as
1493 a real error status for the purposes of further processing */
1494 if( ( cryptStatusOK( status ) || localMessage == MESSAGE_DESTROY ) && \
1495 handlingInfoPtr->postDispatchFunction != NULL )
1496 {
1497 const BOOLEAN isIncomplete = ( localMessage == MESSAGE_DESTROY && \
1498 status == CRYPT_ERROR_INCOMPLETE ) ? \
1499 TRUE : FALSE;
1500
1501 status = handlingInfoPtr->postDispatchFunction( localObjectHandle,
1502 messageQueueData->message,
1503 messageQueueData->messageDataPtr,
1504 messageQueueData->messageValue,
1505 aclPtr );
1506 if( isIncomplete )
1507 {
1508 /* Normally we don't call the post-dispatch handler on error,
1509 however if it's a destroy message then we have to call it
1510 in order to handle any additional cleanup operations since
1511 the object is about to be destroyed, so if the destroy
1512 message to the object returned an incomplete error a we
1513 override any post-dispatch status with the original error
1514 status */
1515 status = CRYPT_ERROR_INCOMPLETE;
1516 }
1517 }
1518 return( status );
1519 }
1520
1521 /* Send a message to an object */
1522
1523 RETVAL \
1524 PARAMCHECK_MESSAGE( MESSAGE_DESTROY, PARAM_NULL, PARAM_IS( 0 ) ) \
1525 PARAMCHECK_MESSAGE( MESSAGE_INCREFCOUNT, PARAM_NULL, PARAM_IS( 0 ) ) \
1526 PARAMCHECK_MESSAGE( MESSAGE_DECREFCOUNT, PARAM_NULL, PARAM_IS( 0 ) ) \
PARAMCHECK_MESSAGE(MESSAGE_GETDEPENDENT,OUT,IN_ENUM (OBJECT_TYPE))1527 PARAMCHECK_MESSAGE( MESSAGE_GETDEPENDENT, OUT, IN_ENUM( OBJECT_TYPE ) ) \
1528 PARAMCHECK_MESSAGE( MESSAGE_SETDEPENDENT, IN, IN ) \
1529 PARAMCHECK_MESSAGE( MESSAGE_CLONE, PARAM_NULL, IN_HANDLE ) \
1530 PARAMCHECK_MESSAGE( MESSAGE_GETATTRIBUTE, OUT, IN_ATTRIBUTE ) \
1531 PARAMCHECK_MESSAGE( MESSAGE_GETATTRIBUTE_S, INOUT, IN_ATTRIBUTE ) \
1532 PARAMCHECK_MESSAGE( MESSAGE_SETATTRIBUTE, IN, IN_ATTRIBUTE ) \
1533 PARAMCHECK_MESSAGE( MESSAGE_SETATTRIBUTE_S, IN, IN_ATTRIBUTE ) \
1534 PARAMCHECK_MESSAGE( MESSAGE_DELETEATTRIBUTE, PARAM_NULL, IN_ATTRIBUTE ) \
1535 PARAMCHECK_MESSAGE( MESSAGE_COMPARE, IN, IN_ENUM( MESSAGE_COMPARE ) ) \
1536 PARAMCHECK_MESSAGE( MESSAGE_CHECK, PARAM_NULL, IN_ENUM( MESSAGE_CHECK ) ) \
1537 PARAMCHECK_MESSAGE( MESSAGE_SELFTEST, PARAM_NULL, PARAM_IS( 0 ) ) \
1538 PARAMCHECK_MESSAGE( MESSAGE_CHANGENOTIFY, PARAM_NULL, PARAM_IS( 0 ) ) \
1539 PARAMCHECK_MESSAGE( MESSAGE_CTX_ENCRYPT, INOUT, IN_LENGTH ) \
1540 PARAMCHECK_MESSAGE( MESSAGE_CTX_DECRYPT, INOUT, IN_LENGTH ) \
1541 PARAMCHECK_MESSAGE( MESSAGE_CTX_SIGN, IN, IN_LENGTH ) \
1542 PARAMCHECK_MESSAGE( MESSAGE_CTX_SIGCHECK, IN, IN_LENGTH ) \
1543 PARAMCHECK_MESSAGE( MESSAGE_CTX_HASH, IN, IN_LENGTH_Z ) \
1544 PARAMCHECK_MESSAGE( MESSAGE_CTX_GENKEY, PARAM_NULL, PARAM_IS( 0 ) ) \
1545 PARAMCHECK_MESSAGE( MESSAGE_CTX_GENIV, PARAM_NULL, PARAM_IS( 0 ) ) \
1546 PARAMCHECK_MESSAGE( MESSAGE_CRT_SIGN, PARAM_NULL, IN_HANDLE ) \
1547 PARAMCHECK_MESSAGE( MESSAGE_CRT_SIGCHECK, PARAM_NULL, IN_HANDLE_OPT ) \
1548 PARAMCHECK_MESSAGE( MESSAGE_CRT_EXPORT, INOUT, IN_ENUM( CRYPT_CERTFORMAT ) ) \
1549 PARAMCHECK_MESSAGE( MESSAGE_DEV_QUERYCAPABILITY, OUT, IN_ALGO ) \
1550 PARAMCHECK_MESSAGE( MESSAGE_DEV_EXPORT, INOUT, IN_ENUM( MECHANISM ) ) \
1551 PARAMCHECK_MESSAGE( MESSAGE_DEV_IMPORT, INOUT, IN_ENUM( MECHANISM ) ) \
1552 PARAMCHECK_MESSAGE( MESSAGE_DEV_SIGN, INOUT, IN_ENUM( MECHANISM ) ) \
1553 PARAMCHECK_MESSAGE( MESSAGE_DEV_SIGCHECK, INOUT, IN_ENUM( MECHANISM ) ) \
1554 PARAMCHECK_MESSAGE( MESSAGE_DEV_DERIVE, INOUT, IN_ENUM( MECHANISM ) ) \
1555 PARAMCHECK_MESSAGE( MESSAGE_DEV_KDF, INOUT, IN_ENUM( MECHANISM ) ) \
1556 PARAMCHECK_MESSAGE( MESSAGE_DEV_CREATEOBJECT, INOUT, IN_ENUM( OBJECT_TYPE ) ) \
1557 PARAMCHECK_MESSAGE( MESSAGE_DEV_CREATEOBJECT_INDIRECT, INOUT, IN_ENUM( OBJECT_TYPE ) ) \
1558 PARAMCHECK_MESSAGE( MESSAGE_ENV_PUSHDATA, INOUT, PARAM_IS( 0 ) ) \
1559 PARAMCHECK_MESSAGE( MESSAGE_ENV_POPDATA, INOUT, PARAM_IS( 0 ) ) \
1560 PARAMCHECK_MESSAGE( MESSAGE_KEY_GETKEY, INOUT, IN_ENUM( KEYMGMT_ITEM ) ) \
1561 PARAMCHECK_MESSAGE( MESSAGE_KEY_SETKEY, INOUT, IN_ENUM( KEYMGMT_ITEM ) ) \
1562 PARAMCHECK_MESSAGE( MESSAGE_KEY_DELETEKEY, INOUT, IN_ENUM( KEYMGMT_ITEM ) ) \
1563 PARAMCHECK_MESSAGE( MESSAGE_KEY_GETFIRSTCERT, INOUT, IN_ENUM( KEYMGMT_ITEM ) ) \
1564 PARAMCHECK_MESSAGE( MESSAGE_KEY_GETNEXTCERT, INOUT, IN_ENUM( KEYMGMT_ITEM ) ) \
1565 PARAMCHECK_MESSAGE( MESSAGE_KEY_CERTMGMT, INOUT, IN_ENUM( CRYPT_CERTACTION ) ) \
1566 PARAMCHECK_MESSAGE( MESSAGE_USER_USERMGMT, INOUT, IN_ENUM( MESSAGE_USERMGMT ) ) \
1567 PARAMCHECK_MESSAGE( MESSAGE_USER_TRUSTMGMT, IN, IN_ENUM( MESSAGE_TRUSTMGMT ) ) \
1568 /* Actually INOUT for MESSAGE_TRUSTMGMT_GETISSUER, but too \
1569 complex to annotate */ \
1570 int krnlSendMessage( IN_HANDLE const int objectHandle,
1571 IN_MESSAGE const MESSAGE_TYPE message,
1572 void *messageDataPtr, const int messageValue )
1573 {
1574 const ATTRIBUTE_ACL *attributeACL = NULL;
1575 const MESSAGE_HANDLING_INFO *handlingInfoPtr;
1576 OBJECT_INFO *objectTable, *objectInfoPtr;
1577 MESSAGE_QUEUE_DATA enqueuedMessageData;
1578 const BOOLEAN isInternalMessage = isInternalMessage( message ) ? \
1579 TRUE : FALSE;
1580 const void *aclPtr = NULL;
1581 MESSAGE_TYPE localMessage = message & MESSAGE_MASK;
1582 int localObjectHandle = objectHandle, iterationCount;
1583 int status = CRYPT_OK;
1584
1585 assert( isWritePtr( krnlData, sizeof( KERNEL_DATA ) ) );
1586
1587 /* Preconditions. For external messages we don't provide any assertions
1588 at this point since they're coming straight from the user and could
1589 contain any values, and for internal messages we only trap on
1590 programming errors (thus for example isValidHandle() vs.
1591 isValidObject(), since this would trap if a message is sent to a
1592 destroyed object) */
1593 REQUIRES( isValidMessage( localMessage ) );
1594 REQUIRES( !isInternalMessage || isValidHandle( objectHandle ) );
1595
1596 /* Get the information that we need to handle this message */
1597 handlingInfoPtr = &messageHandlingInfo[ localMessage ];
1598
1599 /* Inner preconditions now that we have the handling information: Message
1600 parameters must be within the allowed range */
1601 REQUIRES( checkParams( handlingInfoPtr->paramCheck, messageDataPtr,
1602 messageValue ) );
1603
1604 /* If it's an object-manipulation message get the attribute's mandatory
1605 ACL; if it's an object-parameter message get the parameter's mandatory
1606 ACL. Since these doesn't require access to any object information, we
1607 can do it before we lock the object table */
1608 if( isAttributeMessage( localMessage ) )
1609 {
1610 attributeACL = findAttributeACL( messageValue, isInternalMessage );
1611 if( attributeACL == NULL )
1612 return( CRYPT_ARGERROR_VALUE );
1613 aclPtr = attributeACL;
1614
1615 /* Because cryptlib can be called through a variety of different
1616 language bindings it's not guaranteed that the values of TRUE and
1617 FALSE (as supplied by the caller) will always be 1 and 0. For
1618 example Visual Basic uses the value -1 for TRUE because of
1619 obscure backwards-compatibility and implementation issues with
1620 16-bit versions of VB. In order to avoid complaints from various
1621 checks at lower levels of cryptlib, we replace any boolean values
1622 with a setting other than FALSE with the explicit boolean value
1623 TRUE. This is a bit of an ugly kludge but it avoids having to
1624 special-case these values at all sorts of other locations in the
1625 code */
1626 if( localMessage == MESSAGE_SETATTRIBUTE && \
1627 attributeACL->valueType == ATTRIBUTE_VALUE_BOOLEAN )
1628 {
1629 REQUIRES( messageDataPtr != NULL );
1630
1631 if( *( ( BOOLEAN * ) messageDataPtr ) )
1632 messageDataPtr = MESSAGE_VALUE_TRUE;
1633 }
1634 }
1635 if( isParamMessage( localMessage ) )
1636 {
1637 aclPtr = findParamACL( localMessage );
1638 ENSURES( aclPtr != NULL );
1639 }
1640
1641 /* Inner precondition: If it's an attribute-manipulation message, we have
1642 a valid ACL for the attribute present */
1643 REQUIRES( !isAttributeMessage( localMessage ) || attributeACL != NULL );
1644
1645 /* If we're in the middle of a shutdown, don't allow any further
1646 messages except ones related to object destruction (the status read
1647 is needed for objects capable of performing async ops, since the
1648 shutdown code needs to determine whether they're currently busy).
1649 The check outside the object-table lock is done in order to have any
1650 remaining active objects exit quickly without tying up the object
1651 table, since we don't want them to block the shutdown. In addition
1652 if the thread is a leftover/long-running thread that's still active
1653 after the shutdown has occurred, we can't access the object table
1654 lock since it'll have been deleted */
1655 if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MESSAGES && \
1656 !( localMessage == MESSAGE_DESTROY || \
1657 localMessage == MESSAGE_DECREFCOUNT || \
1658 ( localMessage == MESSAGE_GETATTRIBUTE && \
1659 messageValue == CRYPT_IATTRIBUTE_STATUS ) ) )
1660 {
1661 /* Exit without even trying to acquire the object table lock */
1662 return( CRYPT_ERROR_PERMISSION );
1663 }
1664
1665 /* Lock the object table to ensure that other threads don't try to
1666 access it */
1667 MUTEX_LOCK( objectTable );
1668 objectTable = krnlData->objectTable;
1669
1670 /* The first line of defence: Make sure that the message is being sent
1671 to a valid object and that the object is externally visible and
1672 accessible to the caller if required by the message. The checks
1673 performed are:
1674
1675 if( handle does not correspond to an object )
1676 error;
1677 if( message is external )
1678 {
1679 if( object is internal )
1680 error;
1681 if( object isn't owned by calling thread )
1682 error;
1683 }
1684
1685 This is equivalent to the shorter form fullObjectCheck() that used
1686 elsewhere. The error condition reported in all of these cases is
1687 that the object handle isn't valid */
1688 if( !isValidObject( objectHandle ) )
1689 status = CRYPT_ARGERROR_OBJECT;
1690 else
1691 {
1692 if( !isInternalMessage && \
1693 ( isInternalObject( objectHandle ) || \
1694 !checkObjectOwnership( objectTable[ objectHandle ] ) ) )
1695 status = CRYPT_ARGERROR_OBJECT;
1696 }
1697 if( cryptStatusError( status ) )
1698 {
1699 MUTEX_UNLOCK( objectTable );
1700 return( status );
1701 }
1702
1703 /* Inner precondition now that the outer check has been passed: It's a
1704 valid, accessible object and not a system object that can never be
1705 explicitly destroyed or have its refCount altered */
1706 REQUIRES_MUTEX( isValidObject( objectHandle ), objectTable );
1707 REQUIRES_MUTEX( isInternalMessage || ( !isInternalObject( objectHandle ) && \
1708 checkObjectOwnership( objectTable[ objectHandle ] ) ), \
1709 objectTable );
1710 REQUIRES_MUTEX( fullObjectCheck( objectHandle, message ), objectTable );
1711 REQUIRES_MUTEX( objectHandle >= NO_SYSTEM_OBJECTS || \
1712 ( localMessage != MESSAGE_DESTROY && \
1713 localMessage != MESSAGE_DECREFCOUNT && \
1714 localMessage != MESSAGE_INCREFCOUNT ), objectTable );
1715
1716 /* If this message is routable, find its target object */
1717 if( handlingInfoPtr->routingFunction != NULL )
1718 {
1719 /* If it's implicitly routed, route it based on the attribute type */
1720 if( isImplicitRouting( handlingInfoPtr->routingTarget ) )
1721 {
1722 REQUIRES_MUTEX( attributeACL != NULL, objectTable );
1723
1724 if( attributeACL->routingFunction != NULL )
1725 {
1726 status = attributeACL->routingFunction( objectHandle,
1727 &localObjectHandle,
1728 attributeACL->routingTarget );
1729 }
1730 }
1731 else
1732 {
1733 /* It's explicitly or directly routed, route it based on the
1734 message type or fixed-target type */
1735 status = handlingInfoPtr->routingFunction( objectHandle,
1736 &localObjectHandle,
1737 isExplicitRouting( handlingInfoPtr->routingTarget ) ? \
1738 messageValue : handlingInfoPtr->routingTarget );
1739 }
1740 if( cryptStatusError( status ) )
1741 {
1742 MUTEX_UNLOCK( objectTable );
1743 return( CRYPT_ARGERROR_OBJECT );
1744 }
1745 }
1746
1747 /* Inner precodition: It's a valid destination object */
1748 REQUIRES_MUTEX( isValidObject( localObjectHandle ), objectTable );
1749
1750 /* Sanity-check the message routing */
1751 if( !isValidObject( localObjectHandle ) )
1752 {
1753 MUTEX_UNLOCK( objectTable );
1754 retIntError();
1755 }
1756
1757 /* It's a valid object, get its info */
1758 objectInfoPtr = &objectTable[ localObjectHandle ];
1759
1760 /* Now that the message has been routed to its intended target, make sure
1761 that it's valid for the target object subtype */
1762 if( !isValidSubtype( handlingInfoPtr->subTypeA, objectInfoPtr->subType ) && \
1763 !isValidSubtype( handlingInfoPtr->subTypeB, objectInfoPtr->subType ) && \
1764 !isValidSubtype( handlingInfoPtr->subTypeC, objectInfoPtr->subType ) )
1765 {
1766 MUTEX_UNLOCK( objectTable );
1767 return( CRYPT_ARGERROR_OBJECT );
1768 }
1769
1770 /* Inner precondition: The message is valid for this object subtype */
1771 REQUIRES_MUTEX( isValidSubtype( handlingInfoPtr->subTypeA, \
1772 objectInfoPtr->subType ) || \
1773 isValidSubtype( handlingInfoPtr->subTypeB, \
1774 objectInfoPtr->subType ) || \
1775 isValidSubtype( handlingInfoPtr->subTypeC, \
1776 objectInfoPtr->subType ), \
1777 objectTable );
1778
1779 /* If this message is processed internally, handle it now. These
1780 messages aren't affected by the object's state so they're always
1781 processed */
1782 if( handlingInfoPtr->internalHandlerFunction != NULL || \
1783 ( attributeACL != NULL && \
1784 attributeACL->flags & ATTRIBUTE_FLAG_PROPERTY ) )
1785 {
1786 status = processInternalMessage( localObjectHandle, handlingInfoPtr,
1787 message, messageDataPtr,
1788 messageValue, aclPtr );
1789 if( status != OK_SPECIAL )
1790 {
1791 /* The message was processed normally, exit */
1792 MUTEX_UNLOCK( objectTable );
1793 return( status );
1794 }
1795
1796 /* The object has entered an invalid state (for example it was
1797 signalled while it was being initialised) and can't be used any
1798 more, destroy it, convert the (local copy of the) message into a
1799 destroy object message */
1800 localMessage = MESSAGE_DESTROY;
1801 status = CRYPT_OK;
1802 }
1803
1804 /* If the object isn't already processing a message and the message isn't
1805 a special type such as MESSAGE_DESTROY, dispatch it immediately rather
1806 than enqueueing it for later dispatch. This scoreboard mechanism
1807 greatly reduces the load on the queue */
1808 if( !isInUse( localObjectHandle ) && localMessage != MESSAGE_DESTROY )
1809 {
1810 CONST_INIT_STRUCT_5( MESSAGE_QUEUE_DATA messageQueueData, \
1811 localObjectHandle, handlingInfoPtr, message, \
1812 messageDataPtr, messageValue );
1813
1814 CONST_SET_STRUCT( messageQueueData.objectHandle = localObjectHandle; \
1815 messageQueueData.handlingInfoPtr = handlingInfoPtr; \
1816 messageQueueData.message = message; \
1817 messageQueueData.messageDataPtr = messageDataPtr; \
1818 messageQueueData.messageValue = messageValue );
1819
1820 /* If the object isn't in a valid state, we can't do anything with it.
1821 There are no messages that can be sent to it at this point, get/
1822 set property messages have already been handled earlier and the
1823 destroy message isn't handled here */
1824 if( isInvalidObjectState( localObjectHandle ) )
1825 {
1826 status = getObjectStatusValue( objectInfoPtr->flags );
1827 MUTEX_UNLOCK( objectTable );
1828 return( status );
1829 }
1830
1831 /* In case a shutdown was signalled while we were performing other
1832 processing, exit now before we try and do anything with the
1833 object. It's safe to perform the check at this point since no
1834 message sent during shutdown will get here */
1835 if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MESSAGES )
1836 {
1837 MUTEX_UNLOCK( objectTable );
1838 return( CRYPT_ERROR_PERMISSION );
1839 }
1840
1841 /* Inner precondition: The object is in a valid state */
1842 REQUIRES_MUTEX( !isInvalidObjectState( localObjectHandle ), \
1843 objectTable );
1844
1845 /* Dispatch the message to the object */
1846 status = dispatchMessage( localObjectHandle, &messageQueueData,
1847 objectInfoPtr, aclPtr );
1848 MUTEX_UNLOCK( objectTable );
1849
1850 /* If it's a zeroise, perform a kernel shutdown. In theory we could
1851 do this from the post-dispatch handler, but we need to make sure
1852 that there are no further kernel actions to be taken before we
1853 perform the shutdown, so we do it at this level instead */
1854 if( cryptStatusOK( status ) && \
1855 ( messageQueueData.message & MESSAGE_MASK ) == MESSAGE_USER_USERMGMT && \
1856 messageQueueData.messageValue == MESSAGE_USERMGMT_ZEROISE )
1857 {
1858 /* Since it's a zeroise we return the status of the overall
1859 zeroise operation rather than any possible non-OK status from
1860 shutting down the kernel at the end of the zeroise */
1861 ( void ) endCryptlib();
1862 }
1863
1864 /* Postcondition: The return status is valid */
1865 ENSURES( cryptStandardError( status ) || \
1866 cryptArgError( status ) || status == OK_SPECIAL );
1867
1868 return( status );
1869 }
1870
1871 /* Inner precondition: The object is in use or it's a destroy object
1872 message, we have to enqueue it */
1873 REQUIRES_MUTEX( isInUse( localObjectHandle ) || \
1874 localMessage == MESSAGE_DESTROY, \
1875 objectTable );
1876
1877 /* If we're stuck in a loop processing recursive messages, bail out.
1878 This would happen automatically anyway once we fill the message queue,
1879 but this early-out mechanism prevents a single object from filling the
1880 queue to the detriment of other objects */
1881 if( objectInfoPtr->lockCount > MESSAGE_QUEUE_SIZE / 2 )
1882 {
1883 MUTEX_UNLOCK( objectTable );
1884 DEBUG_DIAG(( "Invalid kernel message queue state" ));
1885 assert( DEBUG_WARN );
1886 return( CRYPT_ERROR_TIMEOUT );
1887 }
1888
1889 /* If the object is in use by another thread, wait for it to become
1890 available */
1891 if( isInUse( localObjectHandle ) && !isObjectOwner( localObjectHandle ) )
1892 {
1893 status = waitForObject( localObjectHandle, &objectInfoPtr );
1894 #if !defined( NDEBUG ) && defined( USE_THREADS )
1895 if( cryptStatusOK( status ) && isInUse( localObjectHandle ) )
1896 {
1897 /* dispatchMessage() expects us to be the lock owner if the
1898 object is in use, however if the object has been */
1899 objectInfoPtr->lockOwner = THREAD_SELF();
1900 }
1901 #endif /* !NDEBUG && USE_THREADS */
1902 }
1903 if( cryptStatusError( status ) )
1904 {
1905 MUTEX_UNLOCK( objectTable );
1906 return( status );
1907 }
1908 assert( !isInUse( localObjectHandle ) || \
1909 isObjectOwner( localObjectHandle ) );
1910
1911 /* Enqueue the message */
1912 if( ( message & MESSAGE_MASK ) != localMessage )
1913 {
1914 /* The message was converted during processing, this can only happen
1915 when a message sent to an invalid-state object is converted into
1916 a destroy-object message. What we therefore enqueue is a
1917 destroy-object message, but with the messageValue parameter set
1918 to TRUE to indicate that it's a converted destroy message */
1919 REQUIRES_MUTEX( localMessage == MESSAGE_DESTROY, objectTable );
1920
1921 status = enqueueMessage( localObjectHandle,
1922 &messageHandlingInfo[ MESSAGE_DESTROY ],
1923 MESSAGE_DESTROY, messageDataPtr, TRUE );
1924 }
1925 else
1926 {
1927 status = enqueueMessage( localObjectHandle, handlingInfoPtr, message,
1928 messageDataPtr, messageValue );
1929 }
1930 if( cryptStatusError( status ) )
1931 {
1932 /* A message for this object is already present in the queue, defer
1933 processing until later */
1934 MUTEX_UNLOCK( objectTable );
1935 return( ( status == OK_SPECIAL ) ? CRYPT_OK : status );
1936 }
1937 assert( !isInUse( localObjectHandle ) || \
1938 isObjectOwner( localObjectHandle ) );
1939
1940 /* While there are more messages for this object present, dequeue them
1941 and dispatch them. Since messages will only be enqueued if
1942 krnlSendMessage() is called recursively, we only dequeue messages for
1943 the current object in this loop. Queued messages for other objects
1944 will be handled at a different level of recursion.
1945
1946 Bounding this loop is a bit tricky because new messages can arrive as
1947 the existing ones are dequeued, so that in theory the arrival rate
1948 could match the dispatch rate. However in practice a situation like
1949 this would be extremely unusual, so we bound the loop at
1950 FAILSAFE_ITERATIONS_LARGE */
1951 for( iterationCount = 0;
1952 getNextMessage( localObjectHandle, &enqueuedMessageData ) && \
1953 iterationCount < FAILSAFE_ITERATIONS_LARGE;
1954 iterationCount++ )
1955 {
1956 const BOOLEAN isDestroy = \
1957 ( enqueuedMessageData.message & MESSAGE_MASK ) == MESSAGE_DESTROY;
1958 const BOOLEAN isZeroise = \
1959 ( enqueuedMessageData.message & MESSAGE_MASK ) == MESSAGE_USER_USERMGMT && \
1960 enqueuedMessageData.messageValue == MESSAGE_USERMGMT_ZEROISE;
1961
1962 /* If there's a problem with the object, initiate special processing.
1963 The exception to this is a destroy message that started out as a
1964 different type of message (that is, it was converted into a
1965 destroy object message due to the object being in an invalid
1966 state, indicated by the messageValue parameter being set to TRUE
1967 when it's normally zero for a destroy message), which is let
1968 through */
1969 if( isInvalidObjectState( localObjectHandle ) && \
1970 !( isDestroy && ( enqueuedMessageData.messageValue == TRUE ) ) )
1971 {
1972 /* If it's a destroy object message being sent to an object in
1973 the process of being created, set the state to signalled and
1974 continue. The object will be destroyed when the caller
1975 notifies the kernel that the init is complete */
1976 if( isDestroy && ( objectInfoPtr->flags & OBJECT_FLAG_NOTINITED ) )
1977 {
1978 objectInfoPtr->flags |= OBJECT_FLAG_SIGNALLED;
1979 status = CRYPT_OK;
1980 }
1981 else
1982 {
1983 /* Remove all further messages for this object and return
1984 to the caller */
1985 dequeueAllMessages( localObjectHandle );
1986 status = getObjectStatusValue( objectInfoPtr->flags );
1987 }
1988 continue;
1989 }
1990 assert( !isInUse( localObjectHandle ) || \
1991 isObjectOwner( localObjectHandle ) );
1992
1993 /* Inner precondition: The object is in a valid state or it's a
1994 destroy message that was converted from a different message
1995 type */
1996 REQUIRES_MUTEX( !isInvalidObjectState( localObjectHandle ) || \
1997 ( isDestroy && ( enqueuedMessageData.messageValue == TRUE ) ), \
1998 objectTable );
1999
2000 /* Dispatch the message to the object */
2001 status = dispatchMessage( localObjectHandle, &enqueuedMessageData,
2002 objectInfoPtr, aclPtr );
2003
2004 /* If the message is a destroy object message, we have to explicitly
2005 remove it from the object table and dequeue all further messages
2006 for it since the object's message handler can't do this itself.
2007 Since a destroy object message always succeeds but can return an
2008 error code (typically CRYPT_ERROR_INCOMPLETE), we don't treat an
2009 error return as a real error status for the purposes of further
2010 processing */
2011 if( isDestroy )
2012 {
2013 int destroyStatus; /* Preserve original status value */
2014
2015 destroyStatus = destroyObjectData( localObjectHandle );
2016 ENSURES_MUTEX( cryptStatusOK( destroyStatus ), objectTable );
2017 dequeueAllMessages( localObjectHandle );
2018 }
2019 else
2020 {
2021 /* If we ran into a problem or this is a zeroise (i.e. a
2022 localised shutdown), dequeue all further messages for this
2023 object. This causes getNextMessage() to fail and we drop out
2024 of the loop */
2025 if( cryptStatusError( status ) || \
2026 ( cryptStatusOK( status ) && isZeroise ) )
2027 {
2028 dequeueAllMessages( localObjectHandle );
2029 }
2030 }
2031 }
2032 ENSURES_MUTEX( iterationCount < FAILSAFE_ITERATIONS_LARGE, \
2033 objectTable );
2034
2035 /* Unlock the object table to allow access by other threads */
2036 MUTEX_UNLOCK( objectTable );
2037
2038 /* If it's a zeroise, perform a kernel shutdown. In theory we could do
2039 this from the post-dispatch handler, but we need to make sure that
2040 there are no further kernel actions to be taken before we perform the
2041 shutdown, so we do it at this level instead */
2042 if( cryptStatusOK( status ) && localMessage == MESSAGE_USER_USERMGMT && \
2043 messageValue == MESSAGE_USERMGMT_ZEROISE )
2044 {
2045 /* Since it's a zeroise we return the status of the overall zeroise
2046 operation rather than any possible non-OK status from shutting
2047 down the kernel at the end of the zeroise */
2048 ( void ) endCryptlib();
2049 }
2050
2051 /* Postcondition: The return status is valid */
2052 ENSURES( cryptStandardError( status ) || cryptArgError( status ) || \
2053 status == OK_SPECIAL );
2054
2055 return( status );
2056 }
2057